1 /************************************************************************/
2 /* */
3 /* Editor functionality. */
4 /* */
5 /************************************************************************/
6
7 # include "tedConfig.h"
8
9 # include <stddef.h>
10 # include <stdio.h>
11 # include <ctype.h>
12
13 # include <uniUtf8.h>
14 # include <ucdGeneralCategory.h>
15
16 # include "tedEdit.h"
17 # include "tedDocument.h"
18 # include "tedApp.h"
19 # include "tedSelect.h"
20 # include "tedToolFront.h"
21 # include <docRtfTrace.h>
22 # include <docTreeType.h>
23 # include <docField.h>
24 # include <docTextParticule.h>
25 # include <docTreeNode.h>
26 # include <docEditCommand.h>
27
28 # include <appDebugon.h>
29
30 /************************************************************************/
31 /* */
32 /* Replace the selection in the document with new text. */
33 /* */
34 /* b) Replace the tail of the beginning paragraph with the new text. */
35 /* c) Merge the two paragraphs. */
36 /* d) Erase all paragraphs after the beginning of the selection */
37 /* to, including the end. */
38 /* e) Update the paragraph buffer and the particule administration. */
39 /* */
40 /* B) The first particule of the line was split, also reformat the */
41 /* previous line. */
42 /* If paragraphs were merged, redraw the whole neighbourhood. */
43 /* C) - Recalculate the geometry from the start of the selection to */
44 /* the end of the paragraph. */
45 /* - Redraw the affected part of the paragraph. */
46 /* 6) Update the notion of current particule and current line. */
47 /* 7) Redraw the I-Bar. */
48 /* */
49 /************************************************************************/
50
tedEditReplaceSelection(TedEditOperation * teo,const char * addedText,int addedLength,int textAttributeNr)51 int tedEditReplaceSelection( TedEditOperation * teo,
52 const char * addedText,
53 int addedLength,
54 int textAttributeNr )
55 {
56 EditOperation * eo= &(teo->teoEo);
57
58 /* b,c,d,e */
59 if ( docReplaceSelection( eo, addedText, addedLength, textAttributeNr ) )
60 { LDEB(addedLength); return -1; }
61
62 return 0;
63 }
64
tedEditDeleteSelection(TedEditOperation * teo)65 int tedEditDeleteSelection( TedEditOperation * teo )
66 {
67 EditOperation * eo= &(teo->teoEo);
68
69 /* b,c,d,e */
70 if ( docDeleteSelection( eo ) )
71 { LDEB(1); return -1; }
72
73 return 0;
74 }
75
76 /************************************************************************/
77 /* */
78 /* Merge the selection into one paragraph. */
79 /* */
80 /************************************************************************/
81
tedMergeParagraphsInSelection(EditDocument * ed,int traced)82 int tedMergeParagraphsInSelection( EditDocument * ed,
83 int traced )
84 {
85 int rval= 0;
86 int beforeEnd;
87
88 TedEditOperation teo;
89 EditOperation * eo= &(teo.teoEo);
90 SelectionGeometry sg;
91 SelectionDescription sd;
92
93 DocumentSelection dsTraced;
94
95 const int fullWidth= 1;
96
97 tedStartEditOperation( &teo, &sg, &sd, ed, fullWidth, traced );
98
99 if ( tedEditStartReplace( &dsTraced, &teo,
100 EDITcmdMERGE_PARAS, DOClevSPAN, 0 ) )
101 { LDEB(1); rval= -1; goto ready; }
102
103 beforeEnd= docParaStrlen( eo->eoTailDp.dpNode )-
104 eo->eoSelectedRange.erTail.epStroff;
105
106 if ( docMergeParagraphsInSelection( eo ) )
107 { LDEB(1); rval= -1; goto ready; }
108
109 eo->eoSelectedRange.erTail.epParaNr= eo->eoSelectedRange.erHead.epParaNr;
110 eo->eoSelectedRange.erTail.epStroff=
111 docParaStrlen( eo->eoHeadDp.dpNode )- beforeEnd;
112 eo->eoAffectedRange= eo->eoSelectedRange;
113
114 if ( tedEditFinishOldSelection( &teo ) )
115 { LDEB(1); }
116
117 if ( teo.teoEditTrace )
118 {
119 if ( docRtfTraceNewContents( eo, SELposALL ) )
120 { LDEB(1); rval= -1; goto ready; }
121 }
122
123 tedFinishEditOperation( &teo );
124
125 ready:
126
127 tedCleanEditOperation( &teo );
128
129 return rval;
130 }
131
132 /************************************************************************/
133 /* */
134 /* Implementation of replace functionality. */
135 /* */
136 /************************************************************************/
137
tedReplaceSelectionImpl(TedEditOperation * teo,const char * word,int len,int typing,int textAttrNr)138 static int tedReplaceSelectionImpl( TedEditOperation * teo,
139 const char * word,
140 int len,
141 int typing,
142 int textAttrNr )
143 {
144 EditOperation * eo= &(teo->teoEo);
145
146 if ( tedEditReplaceSelection( teo, word, len, textAttrNr ) )
147 { LDEB(1); return -1; }
148
149 if ( typing == TYPING_BLANK || typing == TYPING_NONBLANK )
150 {
151 EditDocument * ed= teo->teoEditDocument;
152 TedDocument * td= (TedDocument *)ed->edPrivateData;
153 EditTrace * et= &(td->tdEditTrace);
154
155 eo->eoAffectedRange.erHead= et->etTypingOldRange.erHead;
156 }
157
158 /* 6,7 */
159 tedEditFinishSelectionTail( teo );
160
161 if ( teo->teoEditTrace )
162 {
163 if ( docRtfTraceNewContents( eo, SELposTAIL ) )
164 { LDEB(1); return -1; }
165 }
166
167 tedFinishEditOperation( teo );
168
169 return 0;
170 }
171
tedDeleteSelectionImpl(TedEditOperation * teo)172 int tedDeleteSelectionImpl( TedEditOperation * teo )
173 {
174 EditDocument * ed= teo->teoEditDocument;
175 TedDocument * td= (TedDocument *)ed->edPrivateData;
176
177 return tedReplaceSelectionImpl( teo, (const char *)0, 0, TYPING_NO,
178 td->tdSelectionDescription.sdTextAttributeNumber );
179 }
180
181 /************************************************************************/
182
tedDetermineTypingClass(int * pHeadClass,const EditTrace * et,const char * str,int length)183 static int tedDetermineTypingClass( int * pHeadClass,
184 const EditTrace * et,
185 const char * str,
186 int length )
187 {
188 int headClass= TYPING_NO;
189 int tailClass= TYPING_NO;
190
191 int done= 0;
192
193 while( done < length )
194 {
195 unsigned short uni;
196 int step;
197
198 step= uniGetUtf8( &uni, str+ done );
199 if ( step < 1 )
200 { LDEB(step); return -1; }
201
202 if ( ucdIsZ( uni ) )
203 { tailClass= TYPING_BLANK; }
204 else{ tailClass= TYPING_NONBLANK; }
205
206 if ( done == 0 )
207 { headClass= tailClass; }
208
209 done += step;
210 }
211
212 if ( et->etTyping == TYPING_NO ||
213 ( et->etTyping == TYPING_BLANK && headClass == TYPING_NONBLANK ) )
214 { *pHeadClass= TYPING_START; }
215 else{ *pHeadClass= et->etTyping; }
216
217 return tailClass;
218 }
219
220 /************************************************************************/
221 /* */
222 /* Refuse to scribble in the 'bullet' of a note. */
223 /* */
224 /************************************************************************/
225
tedEditHoldsNoteHead(const SelectionDescription * sd,const EditOperation * eo)226 static int tedEditHoldsNoteHead( const SelectionDescription * sd,
227 const EditOperation * eo )
228 {
229 if ( sd->sdInTreeType == DOCinFOOTNOTE ||
230 sd->sdInTreeType == DOCinENDNOTE )
231 {
232 DocumentPosition dp= eo->eoHeadDp;
233
234 if ( docPrevPosition( &dp ) )
235 { return 1; }
236 }
237
238 return 0;
239 }
240
241 /************************************************************************/
242 /* */
243 /* Replace the selection with something new. */
244 /* */
245 /* 1) No selection... Just refuse. */
246 /* 2) Replace nothing with nothing: Do nothing. */
247 /* (Saves a lot of work, and avoids some combinations of special */
248 /* cases) */
249 /* 3) Refuse to scribble in the 'bullet' of a note. */
250 /* */
251 /************************************************************************/
252
tedDocReplaceSelection(EditDocument * ed,int command,const char * str,int length,int traced)253 int tedDocReplaceSelection( EditDocument * ed,
254 int command,
255 const char * str,
256 int length,
257 int traced )
258 {
259 int rval =0;
260 TedDocument * td= (TedDocument *)ed->edPrivateData;
261 EditTrace * et= &(td->tdEditTrace);
262
263 TedEditOperation teo;
264 SelectionGeometry sg;
265 SelectionDescription sd;
266
267 const int fullWidth= 0;
268
269 /* 1 */
270 if ( ! tedHasSelection( ed ) )
271 { LDEB(1); rval= -1; goto ready; }
272
273 tedStartEditOperation( &teo, &sg, &sd, ed, fullWidth, traced );
274
275 /* 2 */
276 if ( teo.teoEo.eoIBarSelectionOld && length == 0 )
277 { goto ready; }
278
279 /* 3 */
280 if ( tedEditHoldsNoteHead( &sd, &(teo.teoEo) ) )
281 { goto ready; }
282
283 if ( traced )
284 {
285 DocumentSelection dsTraced;
286
287 if ( tedEditStartReplace( &dsTraced, &teo, command, DOClevSPAN, 0 ) )
288 { LDEB(1); rval= -1; goto ready; }
289 }
290
291 if ( tedReplaceSelectionImpl( &teo, str, length, TYPING_NO,
292 td->tdSelectionDescription.sdTextAttributeNumber ) )
293 { LDEB(length); rval= -1; goto ready; }
294
295 et->etTyping= TYPING_NO;
296
297 ready:
298
299 tedCleanEditOperation( &teo );
300
301 return rval;
302 }
303
tedDocDeleteSelection(EditDocument * ed,int command,int traced)304 int tedDocDeleteSelection( EditDocument * ed,
305 int command,
306 int traced )
307 {
308 return tedDocReplaceSelection( ed, command, (const char *)0, 0, traced );
309 }
310
tedDocReplaceSelectionTyping(EditDocument * ed,const char * str,int length)311 int tedDocReplaceSelectionTyping( EditDocument * ed,
312 const char * str,
313 int length )
314 {
315 int rval =0;
316 TedDocument * td= (TedDocument *)ed->edPrivateData;
317 EditTrace * et= &(td->tdEditTrace);
318
319 TedEditOperation teo;
320 SelectionGeometry sg;
321 SelectionDescription sd;
322
323 const int fullWidth= 0;
324
325 int headClass= et->etTyping;
326 int tailClass= TYPING_NO;
327
328 /* 1 */
329 if ( ! tedHasSelection( ed ) )
330 { LDEB(1); rval= -1; goto ready; }
331
332 tedStartEditOperation( &teo, &sg, &sd, ed, fullWidth, td->tdTraced );
333
334 /* 3 */
335 if ( tedEditHoldsNoteHead( &sd, &(teo.teoEo) ) )
336 { goto ready; }
337
338 if ( td->tdTraced )
339 {
340 tailClass= tedDetermineTypingClass( &headClass, et, str, length );
341
342 if ( tailClass < 0 )
343 { LDEB(tailClass); rval= -1; goto ready; }
344 }
345 else{
346 if ( et->etTyping != TYPING_NO )
347 { CDEB(et->etTyping); }
348 }
349
350 if ( td->tdTraced )
351 {
352 if ( headClass == TYPING_BLANK ||
353 headClass == TYPING_NONBLANK )
354 {
355 if ( teo.teoEditTrace &&
356 docTraceExtendReplace( &(teo.teoEo), teo.teoEditTrace,
357 EDITcmdEXTEND_REPLACE, DOClevSPAN, 0 ) )
358 { LDEB(1); rval= -1; goto ready; }
359 }
360 else{
361 DocumentSelection dsTraced;
362
363 if ( tedEditStartReplace( &dsTraced, &teo,
364 EDITcmdREPLACE, DOClevSPAN, 0 ) )
365 { LDEB(1); rval= -1; goto ready; }
366
367 if ( headClass == TYPING_START )
368 { docSetEditRange( &(et->etTypingOldRange), &dsTraced ); }
369 }
370 }
371
372 if ( tedReplaceSelectionImpl( &teo, str, length, headClass,
373 td->tdSelectionDescription.sdTextAttributeNumber ) )
374 { LDEB(length); rval= -1; goto ready; }
375
376 et->etTyping= tailClass;
377
378 ready:
379
380 tedCleanEditOperation( &teo );
381
382 return rval;
383 }
384
385 /************************************************************************/
386 /* */
387 /* Insert a string with known attributes (font) */
388 /* */
389 /************************************************************************/
390
tedDocInsertStringWithAttribute(EditDocument * ed,const char * word,int len,const TextAttribute * taSet,const PropertyMask * taSetMask,int traced)391 void tedDocInsertStringWithAttribute( EditDocument * ed,
392 const char * word,
393 int len,
394 const TextAttribute * taSet,
395 const PropertyMask * taSetMask,
396 int traced )
397 {
398 TedDocument * td= (TedDocument *)ed->edPrivateData;
399 BufferDocument * bd= td->tdDocument;
400
401 TedEditOperation teo;
402 SelectionGeometry sg;
403 SelectionDescription sd;
404
405 PropertyMask taDoneMask;
406
407 TextAttribute ta= td->tdSelectionDescription.sdTextAttribute;
408 int textAttrNr= td->tdSelectionDescription.sdTextAttributeNumber;
409
410 DocumentSelection dsTraced;
411
412 const int fullWidth= 0;
413
414 /* 1 */
415 if ( ! tedHasSelection( ed ) )
416 { LDEB(1); goto ready; }
417
418 utilUpdateTextAttribute( &taDoneMask, &ta, taSetMask, taSet );
419 textAttrNr= docTextAttributeNumber( bd, &ta );
420
421 tedStartEditOperation( &teo, &sg, &sd, ed, fullWidth, traced );
422
423 if ( tedEditStartReplace( &dsTraced, &teo,
424 EDITcmdREPLACE, DOClevSPAN, 0 ) )
425 { LDEB(1); goto ready; }
426
427 if ( tedReplaceSelectionImpl( &teo, word, len, TYPING_NO, textAttrNr ) )
428 { LDEB(len); goto ready; }
429
430 ready:
431
432 tedCleanEditOperation( &teo );
433
434 return;
435 }
436
437 /************************************************************************/
438 /* */
439 /* Insert a (line/page) break particule in the document. */
440 /* */
441 /* Against flashing, a more subtle approach is used for TABs. */
442 /* (redoLayout=0). */
443 /* */
444 /************************************************************************/
445
tedEditInsertSpecialParticule(EditDocument * ed,int kind,int command,int redoLayout,int traced)446 void tedEditInsertSpecialParticule( EditDocument * ed,
447 int kind,
448 int command,
449 int redoLayout,
450 int traced )
451 {
452 TextParticule * tp;
453
454 TedEditOperation teo;
455 EditOperation * eo= &(teo.teoEo);
456 SelectionGeometry sg;
457 SelectionDescription sd;
458
459 DocumentSelection dsTraced;
460
461 const int fullWidth= 0;
462
463 tedStartEditOperation( &teo, &sg, &sd, ed, fullWidth, traced );
464
465 if ( tedEditStartReplace( &dsTraced, &teo, command, DOClevSPAN, 0 ) )
466 { LDEB(1); goto ready; }
467
468 if ( tedEditDeleteSelection( &teo ) )
469 { goto ready; }
470
471 tp= docEditParaSpecialParticule( eo, kind );
472 if ( ! tp )
473 { XDEB(tp); goto ready; }
474
475 if ( docCheckNoBreakAsLast( eo, eo->eoTailDp.dpNode ) )
476 { LDEB(1); }
477
478 /* 3,4,5 */
479 if ( redoLayout )
480 { docEditIncludeNodeInReformatRange( eo, eo->eoTailDp.dpNode ); }
481
482 /* 6,7 */
483 tedEditFinishSelectionTail( &teo );
484
485 if ( teo.teoEditTrace )
486 {
487 if ( docRtfTraceNewContents( eo, SELposTAIL ) )
488 { LDEB(1); goto ready; }
489 }
490
491 tedFinishEditOperation( &teo );
492
493 ready:
494 tedCleanEditOperation( &teo );
495
496 return;
497 }
498
tedDocUpdField(TedEditOperation * teo,DocumentField * dfTo,const FieldInstructions * fi)499 int tedDocUpdField( TedEditOperation * teo,
500 DocumentField * dfTo,
501 const FieldInstructions * fi )
502 {
503 int rval= 0;
504 EditDocument * ed= teo->teoEditDocument;
505 EditOperation * eo= &(teo->teoEo);
506
507 DocumentSelection dsAround;
508
509 if ( tedEditStartTypedStep( teo, EDITcmdUPD_FIELD, dfTo->dfKind ) )
510 { LDEB(1); rval= -1; goto ready; }
511
512 if ( teo->teoEditTrace )
513 {
514 if ( docRtfTraceOldField( eo, dfTo ) )
515 { LDEB(1); rval= -1; goto ready; }
516 }
517
518 if ( docCopyFieldInstructions( &(dfTo->dfInstructions), fi ) )
519 { LDEB(1); rval= -1; goto ready; }
520
521 tedFormatFieldListChanged( ed->edApplication );
522
523 if ( dfTo->dfKind == DOCfkTOC &&
524 tedRefreshTocField( &dsAround, teo, dfTo ) )
525 { LDEB(1); rval= -1; goto ready; }
526
527 tedEditFinishOldSelection( teo );
528
529 if ( teo->teoEditTrace )
530 {
531 if ( docRtfTraceNewField( eo, dfTo ) )
532 { LDEB(1); rval= -1; goto ready; }
533
534 docRtfTraceNewPosition( eo, (const SelectionScope *)0, SELposALL );
535 }
536
537 tedFinishEditOperation( teo );
538
539 ready:
540
541 return rval;
542 }
543
544 /************************************************************************/
545 /* */
546 /* Surround the current selection with a field. */
547 /* */
548 /* This is a special case for Hyperlinks and Bookmarks that hold */
549 /* editable text that is part of the document rather than content that */
550 /* is calculated by the field itself. */
551 /* */
552 /************************************************************************/
553
tedDocSetField(TedEditOperation * teo,const DocumentSelection * ds,int command,int fieldKind,const FieldInstructions * fi,const PropertyMask * taSetMask,const TextAttribute * taSet)554 int tedDocSetField( TedEditOperation * teo,
555 const DocumentSelection * ds,
556 int command,
557 int fieldKind,
558 const FieldInstructions * fi,
559 const PropertyMask * taSetMask,
560 const TextAttribute * taSet )
561 {
562 int rval= 0;
563
564 EditDocument * ed= teo->teoEditDocument;
565 EditOperation * eo= &(teo->teoEo);
566
567 DocumentField * df;
568 DocumentSelection dsField;
569
570 DocumentSelection dsInside;
571 DocumentSelection dsAround;
572 int headPart;
573 int tailPart;
574
575 if ( taSetMask && utilPropMaskIsEmpty( taSetMask ) )
576 { taSetMask= (const PropertyMask *)0; }
577
578 dsField= *ds;
579
580 if ( DOC_FieldKinds[fieldKind].fkiSingleParagraph )
581 {
582 int beginMoved;
583 int endMoved;
584
585 docConstrainSelectionToOneParagraph( &beginMoved, &endMoved,
586 &dsField );
587 eo->eoHeadDp= dsField.dsHead;
588 eo->eoTailDp= dsField.dsTail;
589 eo->eoLastDp= eo->eoTailDp;
590 }
591
592 if ( tedEditStartStep( teo, command ) )
593 { LDEB(1); rval= -1; goto ready; }
594
595 if ( teo->teoEditTrace && taSetMask )
596 {
597 DocumentSelection dsTraced;
598
599 if ( docRtfTraceNewProperties( eo,
600 taSetMask, taSet,
601 (const PropertyMask *)0, (const ParagraphProperties *)0,
602 (const PropertyMask *)0, (const CellProperties *)0,
603 (const PropertyMask *)0, (const RowProperties *)0,
604 (const PropertyMask *)0, (const SectionProperties *)0,
605 (const PropertyMask *)0, (const DocumentProperties *)0 ) )
606 { LDEB(1); rval= -1; goto ready; }
607
608 if ( docRtfTraceOldContents( &dsTraced, eo, DOClevSPAN, 0 ) )
609 { LDEB(1); goto ready; }
610 }
611
612 /* 4 */
613 if ( docEditSurroundTextSelectionByField( eo, &df,
614 &dsInside, &dsAround, &headPart, &tailPart,
615 taSetMask, taSet, fieldKind, fi ) )
616 { LDEB(1); rval= -1; goto ready; }
617
618 /* 5 */
619 if ( tedLayoutNodeOfField( teo, &dsAround, FIELDdoNOTHING ) )
620 { LDEB(1); rval= -1; goto ready; }
621
622 tedFormatFieldListChanged( ed->edApplication );
623
624 tedEditFinishSelection( teo, &dsInside );
625
626 if ( teo->teoEditTrace )
627 {
628 if ( docRtfTraceNewField( eo, df ) )
629 { LDEB(1); rval= -1; goto ready; }
630
631 docRtfTraceNewPosition( eo, (const SelectionScope *)0, SELposALL );
632 }
633
634 tedFinishEditOperation( teo );
635
636 ready:
637
638 return rval;
639 }
640
641 /************************************************************************/
642 /* */
643 /* Roll the rows in a table. */
644 /* */
645 /************************************************************************/
646
tedEditShiftRowsInTable(EditDocument * ed,int direction,int traced)647 int tedEditShiftRowsInTable( EditDocument * ed,
648 int direction,
649 int traced )
650 {
651 int rval= 0;
652 TedEditOperation teo;
653 EditOperation * eo= &(teo.teoEo);
654 SelectionGeometry sg;
655 SelectionDescription sd;
656
657 const int move= 1;
658 int rowsdown= 0;
659 int command= -1;
660
661 const int fullWidth= 1;
662
663 if ( direction > 0 )
664 {
665 rowsdown= 1;
666 command= EDITcmdSHIFT_ROWS_DOWN;
667 }
668
669 if ( direction < 0 )
670 {
671 rowsdown= -1;
672 command= EDITcmdSHIFT_ROWS_UP;
673 }
674
675 tedStartEditOperation( &teo, &sg, &sd, ed, fullWidth, traced );
676
677 if ( tedEditStartStep( &teo, command ) )
678 { LDEB(1); rval= -1; goto ready; }
679
680 if ( tedDocRollRowsInTableImpl( &teo, &(sd.sdTableRectangle),
681 move, rowsdown ) )
682 { LDEB(1); rval= -1; goto ready; }
683
684 tedEditFinishOldSelection( &teo );
685
686 if ( teo.teoEditTrace )
687 {
688 docRtfTraceNewPosition( eo, (const SelectionScope *)0, SELposALL );
689 }
690
691 tedFinishEditOperation( &teo );
692
693 ready:
694
695 tedCleanEditOperation( &teo );
696
697 return rval;
698 }
699
700