1 /************************************************************************/
2 /* */
3 /* Buffer administration routines relating to the text particules in a */
4 /* text paragraph. */
5 /* */
6 /************************************************************************/
7
8 # include "docEditConfig.h"
9
10 # include <stdlib.h>
11 # include <stdio.h>
12
13 # include <appDebugon.h>
14
15 # include <docBuf.h>
16 # include <docField.h>
17 # include <docNodeTree.h>
18 # include "docCopyNode.h"
19 # include "docEdit.h"
20 # include <docParaString.h>
21 # include <docParaParticules.h>
22 # include "docDocumentCopyJob.h"
23 # include <docHyperlinkField.h>
24 # include <docBookmarkField.h>
25 # include <docObjectProperties.h>
26
27 /*
28 # define DEB_PARTICULES
29 */
30
31 /************************************************************************/
32 /* */
33 /* Enter a field while copying. This assumes that copying is done in */
34 /* document order. */
35 /* */
36 /************************************************************************/
37
docStartFieldCopy(DocumentCopyJob * dcj,const EditPosition * epStart,int obnrFrom)38 static DocumentField * docStartFieldCopy(
39 DocumentCopyJob * dcj,
40 const EditPosition * epStart,
41 int obnrFrom )
42 {
43 EditOperation * eo= dcj->dcjEditOperation;
44 BufferDocument * bdTo= eo->eoDocument;
45 const DocumentFieldList * dflFrom= &(dcj->dcjSourceDocument->bdFieldList);
46 const int fieldCount= dflFrom->dflPagedList.plItemCount;
47
48 DocumentField * dfFrom;
49 DocumentField * dfTo;
50
51 dfFrom= docGetFieldByNumber( dflFrom, obnrFrom );
52
53 dfTo= docClaimFieldCopy( &(bdTo->bdFieldList), dfFrom,
54 &(dcj->dcjTargetSelectionScope), epStart );
55 if ( ! dfTo )
56 { XDEB(dfTo); return (DocumentField *)0; }
57
58 if ( obnrFrom < 0 || obnrFrom >= fieldCount )
59 { LDEB(obnrFrom); }
60 else{
61 dcj->dcjFieldMap[obnrFrom]= dfTo->dfFieldNumber;
62 }
63
64 if ( docPushFieldOnCopyStack( dcj, dfTo ) )
65 { LDEB(1); return (DocumentField *)0; }
66
67 if ( dfTo->dfKind >= DOC_FieldKindCount )
68 { LDEB(dfTo->dfKind); }
69 else{
70 eo->eoFieldUpdate |=
71 DOC_FieldKinds[dfTo->dfKind].fkiCalculateWhen;
72 }
73
74 if ( dfTo->dfKind == DOCfkHYPERLINK &&
75 ! utilMemoryBufferIsEmpty( &(dcj->dcjRefFileName) ) )
76 {
77 docMakeHyperlinkRelative( dfTo, &(dcj->dcjRefFileName) );
78 }
79
80 if ( dfTo->dfKind == DOCfkBOOKMARK )
81 {
82 const MemoryBuffer * mbFrom;
83 MemoryBuffer mbTo;
84
85 utilInitMemoryBuffer( &mbTo );
86
87 if ( docFieldGetBookmark( &mbFrom, dfFrom ) )
88 { utilMemoryBufferSetString( &mbTo, "x" ); }
89 else{ utilCopyMemoryBuffer( &mbTo, mbFrom ); }
90
91 if ( docMakeBookmarkUnique( bdTo, &mbTo ) )
92 { LDEB(1); return (DocumentField *)0; }
93
94 if ( docSetBookmarkField( &(dfTo->dfInstructions), &mbTo ) )
95 { LDEB(1); return (DocumentField *)0; }
96
97 utilCleanMemoryBuffer( &mbTo );
98 }
99
100 if ( docFieldHasNote( dfFrom->dfKind ) && dfFrom->dfNoteIndex >= 0 )
101 {
102 if ( docCopyNote( dcj, dfTo, dfFrom ) )
103 { LDEB(1); return (DocumentField *)0; }
104
105 utilIndexSetAdd( &(dcj->dcjNoteFieldsCopied), dfTo->dfFieldNumber );
106 }
107
108 return dfTo;
109 }
110
111 /************************************************************************/
112 /* */
113 /* Leave a field while copying. This assumes that copying is done in */
114 /* document order. */
115 /* */
116 /************************************************************************/
117
docFinishFieldCopy(DocumentCopyJob * dcj,const EditPosition * epTail,int obnrFrom)118 static int docFinishFieldCopy( DocumentCopyJob * dcj,
119 const EditPosition * epTail,
120 int obnrFrom )
121 {
122 EditOperation * eo= dcj->dcjEditOperation;
123 BufferDocument * bdTo= eo->eoDocument;
124 const DocumentFieldList * dflFrom= &(dcj->dcjSourceDocument->bdFieldList);
125 const int fieldCount= dflFrom->dflPagedList.plItemCount;
126
127 DocumentField * dfTo;
128 int obnrTo;
129
130 FieldCopyStackLevel * fcsl= dcj->dcjFieldStack;
131
132 if ( obnrFrom < 0 ||
133 obnrFrom >= fieldCount )
134 { LLDEB(obnrFrom,fieldCount); return -1; }
135
136 if ( dcj->dcjFieldMap[obnrFrom] < 0 )
137 {
138 LLDEB(obnrFrom,fieldCount);
139 SDEB(docFieldKindStr(docGetFieldKindByNumber(dflFrom,obnrFrom)));
140 return -1;
141 }
142
143 obnrTo= dcj->dcjFieldMap[obnrFrom];
144 dfTo= docGetFieldByNumber( &(bdTo->bdFieldList), obnrTo );
145 docSetFieldTail( dfTo, epTail );
146
147 if ( ! fcsl )
148 { XDEB(fcsl); }
149 else{
150 if ( fcsl->fcslPrev )
151 {
152 if ( docAddChildToField( fcsl->fcslField,
153 fcsl->fcslPrev->fcslField ) )
154 { LDEB(1); return -1; }
155 }
156 else{
157 if ( docAddRootFieldToTree( dcj->dcjTargetTree,
158 fcsl->fcslField ) )
159 { LDEB(1); return -1; }
160 }
161
162 dcj->dcjFieldStack= fcsl->fcslPrev;
163 free( fcsl );
164 }
165
166 return obnrTo;
167 }
168
169 /************************************************************************/
170 /* */
171 /* Copy particule data from one paragraph to another. */
172 /* */
173 /* 9) Not needed, the document is marked as changed, so this can wait */
174 /* until it is saved. */
175 /* */
176 /************************************************************************/
177
docCopyParticuleData(DocumentCopyJob * dcj,BufferItem * biTo,const BufferItem * biFrom,TextParticule * tpTo,const TextParticule * tpFrom)178 static int docCopyParticuleData( DocumentCopyJob * dcj,
179 BufferItem * biTo,
180 const BufferItem * biFrom,
181 TextParticule * tpTo,
182 const TextParticule * tpFrom )
183 {
184 EditOperation * eo= dcj->dcjEditOperation;
185 BufferDocument * bdTo= eo->eoDocument;
186 int paraNr= docNumberOfParagraph( biTo );
187
188 switch( tpFrom->tpKind )
189 {
190 case DOCkindSPAN:
191 case DOCkindTAB:
192 case DOCkindLINEBREAK:
193 case DOCkindPAGEBREAK:
194 case DOCkindCOLUMNBREAK:
195 break;
196
197 case DOCkindOBJECT:
198 {
199 const InsertedObject * ioFrom;
200 InsertedObject * ioTo;
201 int nr;
202
203 ioFrom= docGetObject( dcj->dcjSourceDocument,
204 tpFrom->tpObjectNumber );
205 if ( ! ioFrom )
206 { LPDEB(tpFrom->tpObjectNumber,ioFrom); return -1; }
207
208 ioTo= docClaimObjectCopy( bdTo, &nr, ioFrom );
209 if ( ! ioTo )
210 { XDEB(ioTo); return -1; }
211 tpTo->tpObjectNumber= nr;
212
213 ioFrom= docGetObject( dcj->dcjSourceDocument,
214 tpFrom->tpObjectNumber );
215 if ( ! ioFrom )
216 { LPDEB(tpFrom->tpObjectNumber,ioFrom); return -1; }
217
218 if ( ioFrom->ioKind == DOCokDRAWING_SHAPE )
219 {
220 if ( ! ioFrom->ioDrawingShape )
221 { XDEB(ioFrom->ioDrawingShape); }
222 else{
223 ioTo->ioDrawingShape= docCopyDrawingShape( dcj,
224 ioFrom->ioDrawingShape );
225 if ( ! ioTo->ioDrawingShape )
226 { XDEB(ioTo->ioDrawingShape); }
227 }
228 }
229
230 /* 9
231 if ( ioTo->ioBliptag == 0 )
232 { ioTo->ioBliptag= appGetTimestamp(); }
233 */
234 }
235 break;
236
237 case DOCkindFIELDTAIL:
238 {
239 EditPosition ep;
240
241 ep.epParaNr= paraNr;
242 ep.epStroff= tpTo->tpStroff;
243
244 if ( dcj->dcjCopyFields )
245 {
246 tpTo->tpObjectNumber= docFinishFieldCopy( dcj, &ep,
247 tpFrom->tpObjectNumber );
248 }
249 else{ tpTo->tpObjectNumber= tpFrom->tpObjectNumber; }
250 if ( tpTo->tpObjectNumber < 0 )
251 { LDEB(tpTo->tpObjectNumber); }
252 }
253 break;
254
255 case DOCkindFIELDHEAD:
256 if ( dcj->dcjCopyFields )
257 {
258 EditPosition ep;
259 DocumentField * dfTo;
260
261 ep.epParaNr= paraNr;
262 ep.epStroff= tpTo->tpStroff;
263
264 dfTo= docStartFieldCopy( dcj, &ep, tpFrom->tpObjectNumber );
265 if ( ! dfTo )
266 { XDEB(dfTo); return -1; }
267 tpTo->tpObjectNumber= dfTo->dfFieldNumber;
268 }
269 else{ tpTo->tpObjectNumber= tpFrom->tpObjectNumber; }
270 break;
271
272 default:
273 LDEB(tpFrom->tpKind); return -1;
274 }
275
276 return 0;
277 }
278
279 /************************************************************************/
280 /* */
281 /* Copy particules plus contents from one paragraph to another. */
282 /* */
283 /* This might be a copy to a different document, so font numbers and */
284 /* attribute numbers need to be recalculated. */
285 /* */
286 /* 1) Find out where to insert. */
287 /* (At the end of the paragraph or before particule[partTo]. */
288 /* 2) Find position and length of the source string. */
289 /* 3) Find out whether to replace the empty particule that we use to */
290 /* have at least one particule in a paragraph. */
291 /* 4) Insert the desired number of particules in the correct */
292 /* position. Note that that is one less in a paragraph that was */
293 /* originally empty. */
294 /* 5) Insert the new text into the paragraph string. */
295 /* 6) Shift the particules in the tail of the target paragraph to */
296 /* make place for the new text string bytes. The possible */
297 /* overwritten 'empty' particule should not be shifted. */
298 /* 7) Patch the particules in the hole created above to correct */
299 /* values derived from the source particules. */
300 /* */
301 /************************************************************************/
302
docCopyParticules(DocumentCopyJob * dcj,BufferItem * biTo,const BufferItem * biFrom,int partTo,int partFrom,int countFrom,int * pParticulesInserted,int * pCharactersCopied)303 int docCopyParticules( DocumentCopyJob * dcj,
304 BufferItem * biTo,
305 const BufferItem * biFrom,
306 int partTo,
307 int partFrom,
308 int countFrom,
309 int * pParticulesInserted,
310 int * pCharactersCopied )
311 {
312 EditOperation * eo= dcj->dcjEditOperation;
313
314 TextParticule * tpTo;
315 const TextParticule * tpFrom;
316
317 int stroffTo;
318 int stroffShift;
319
320 int i;
321
322 int replaceEmpty= 0;
323
324 int stroffFrom;
325 int strlenFrom;
326
327 int paraNrTo= docNumberOfParagraph( biTo );
328
329 /* 1 */
330 if ( partTo > biTo->biParaParticuleCount )
331 {
332 LLDEB(partTo,biTo->biParaParticuleCount);
333 partTo= biTo->biParaParticuleCount;
334 }
335
336 if ( partTo == biTo->biParaParticuleCount )
337 { stroffTo= docParaStrlen( biTo ); }
338 else{ stroffTo= biTo->biParaParticules[partTo].tpStroff; }
339
340 /* 2 */
341 tpFrom= biFrom->biParaParticules+ partFrom;
342 stroffFrom= tpFrom->tpStroff;
343 strlenFrom= tpFrom[countFrom- 1].tpStroff+ tpFrom[countFrom- 1].tpStrlen-
344 tpFrom->tpStroff;
345
346 /* 3 */
347 if ( docParaStrlen( biTo ) == 0 && biTo->biParaParticuleCount == 1 )
348 {
349 if ( partTo < 0 || partTo > 1 )
350 { LDEB(partTo); }
351 if ( partTo != 0 )
352 { partTo= 0; }
353
354 replaceEmpty= 1;
355 }
356
357 /* 4 */
358 tpTo= docInsertParticules( biTo, partTo, countFrom- replaceEmpty );
359 if ( ! tpTo )
360 { XDEB(tpTo); return -1; }
361
362 /* 5 */
363 if ( docParaStringReplace( &stroffShift, biTo, stroffTo, stroffTo,
364 (char *)docParaString( biFrom, stroffFrom ), strlenFrom ) )
365 {
366 LDEB(strlenFrom);
367 docDeleteParticules( biTo, partTo, countFrom- replaceEmpty );
368 return -1;
369 }
370
371 /* 6 */
372 if ( docEditShiftParticuleOffsets( eo, biTo, paraNrTo,
373 partTo+ countFrom,
374 biTo->biParaParticuleCount,
375 stroffTo, stroffShift ) )
376 { LDEB(stroffShift); }
377
378 /* 7 */
379 tpTo= biTo->biParaParticules+ partTo;
380 for ( i= 0; i < countFrom; tpTo++, tpFrom++, i++ )
381 {
382 int textAttributeNumberTo;
383
384 textAttributeNumberTo= docMapTextAttributeNumber( dcj,
385 tpFrom->tpTextAttrNr );
386 if ( textAttributeNumberTo < 0 )
387 { LDEB(textAttributeNumberTo); return -1; }
388
389 tpTo->tpStroff= stroffTo;
390 tpTo->tpStrlen= tpFrom->tpStrlen;
391 tpTo->tpKind= tpFrom->tpKind;
392 tpTo->tpTextAttrNr= textAttributeNumberTo;
393
394 if ( docCopyParticuleData( dcj, biTo, biFrom, tpTo, tpFrom ) )
395 { LLDEB(partTo,i); return -1; }
396
397 stroffTo += tpTo->tpStrlen;
398 }
399
400 *pParticulesInserted += countFrom- replaceEmpty;
401 *pCharactersCopied += stroffShift;
402
403 return 0;
404 }
405
docCopyParticuleAndData(TextParticule ** pTpTo,DocumentCopyJob * dcj,BufferItem * paraBiTo,int partTo,int stroffTo,int strlenTo,const BufferItem * paraBiFrom,const TextParticule * tpFrom)406 int docCopyParticuleAndData( TextParticule ** pTpTo,
407 DocumentCopyJob * dcj,
408 BufferItem * paraBiTo,
409 int partTo,
410 int stroffTo,
411 int strlenTo,
412 const BufferItem * paraBiFrom,
413 const TextParticule * tpFrom )
414 {
415 TextParticule tpSaved;
416 int textAttributeNumberTo;
417
418 TextParticule * tpTo;
419
420 tpSaved= *tpFrom;
421
422 textAttributeNumberTo= docMapTextAttributeNumber( dcj,
423 tpSaved.tpTextAttrNr );
424
425 if ( textAttributeNumberTo < 0 )
426 { LDEB(textAttributeNumberTo); return -1; }
427
428 if ( partTo < 0 )
429 { partTo= paraBiTo->biParaParticuleCount; }
430
431 tpTo= docInsertTextParticule( paraBiTo, partTo,
432 stroffTo, strlenTo,
433 tpSaved.tpKind,
434 textAttributeNumberTo );
435 if ( ! tpTo )
436 { LXDEB(partTo,tpTo); return -1; }
437
438 if ( docCopyParticuleData( dcj, paraBiTo, paraBiFrom, tpTo, &tpSaved ) )
439 {
440 docDeleteParticules( paraBiTo, partTo, 1 );
441 LDEB(partTo); return -1;
442 }
443
444 *pTpTo= tpTo;
445 return 0;
446 }
447
448 /************************************************************************/
449 /* */
450 /* Make sure the a paragraph does not end in an explicit break. */
451 /* */
452 /************************************************************************/
453
docCheckNoBreakAsLast(EditOperation * eo,BufferItem * paraBi)454 int docCheckNoBreakAsLast( EditOperation * eo,
455 BufferItem * paraBi )
456 {
457 const int part= paraBi->biParaParticuleCount;
458 const int stroff= docParaStrlen( paraBi );
459 const int len= 0;
460
461 const TextParticule * tp= paraBi->biParaParticules+ part- 1;
462
463 if ( tp->tpKind != DOCkindLINEBREAK &&
464 tp->tpKind != DOCkindPAGEBREAK &&
465 tp->tpKind != DOCkindCOLUMNBREAK )
466 { return 0; }
467
468 tp= docInsertTextParticule( paraBi, part, stroff, len,
469 DOCkindSPAN, tp->tpTextAttrNr );
470 if ( ! tp )
471 { XDEB(tp); return -1; }
472
473 docEditIncludeNodeInReformatRange( eo, paraBi );
474
475 return 0;
476 }
477
478 /************************************************************************/
479 /* */
480 /* Copy a paragraph to make a new one. */
481 /* */
482 /* 1) Copy paragraph item. */
483 /* 2) Open a hole in references to the item to possibly receive some */
484 /* to the fresh item. */
485 /* 3) Do not copy a possible list text field from the original. */
486 /* 4) Copy the contents of the original or insert a dummy particule. */
487 /* 5) Finally adapt the properties of the target paragraph to those */
488 /* of the original. */
489 /* */
490 /************************************************************************/
491
docCopyParaNode(DocumentCopyJob * dcj,const SelectionScope * ssRoot,BufferItem * biCellTo,int n,const BufferItem * biParaFrom)492 BufferItem * docCopyParaNode( DocumentCopyJob * dcj,
493 const SelectionScope * ssRoot,
494 BufferItem * biCellTo,
495 int n,
496 const BufferItem * biParaFrom )
497 {
498 EditOperation * eo= dcj->dcjEditOperation;
499 BufferDocument * bdTo= eo->eoDocument;
500 BufferItem * biParaTo;
501
502 const int partTo= 0;
503 int partFrom= 0;
504
505 PropertyMask ppChgMask;
506 PropertyMask ppUpdMask;
507
508 /* 1 */
509 biParaTo= docInsertNode( bdTo, biCellTo, n, DOClevPARA );
510 if ( ! biParaTo )
511 { XDEB(biParaTo); return biParaTo; }
512
513 docSetParaTableNesting( biParaTo );
514
515 /* 2 */
516 {
517 int paraNr;
518 const int stroff= 0;
519 const int sectShift= 0;
520 const int paraShift= 1;
521
522 paraNr= docNumberOfParagraph( biParaTo );
523
524 docEditShiftReferences( eo, ssRoot, paraNr, stroff,
525 sectShift, paraShift, -stroff );
526 }
527
528 /* 3 */
529 if ( biParaFrom->biParaListOverride > 0 )
530 {
531 DocumentField * dfHead= (DocumentField *)0;
532 DocumentSelection dsInsideHead;
533 DocumentSelection dsAroundHead;
534 int bulletPartBegin= -1;
535 int bulletPartEnd= -1;
536
537 if ( docDelimitParaHeadField( &dfHead, &dsInsideHead, &dsAroundHead,
538 &bulletPartBegin, &bulletPartEnd,
539 biParaFrom, dcj->dcjSourceDocument ) )
540 { LDEB(1); }
541
542 if ( partFrom <= bulletPartEnd )
543 { partFrom= bulletPartEnd+ 1; }
544 }
545
546 /* 4 */
547 if ( partFrom < biParaFrom->biParaParticuleCount )
548 {
549 int particulesInserted= 0;
550 int charactersCopied= 0;
551
552 if ( docCopyParticules( dcj, biParaTo, biParaFrom, partTo,
553 partFrom, biParaFrom->biParaParticuleCount- partFrom,
554 &particulesInserted, &charactersCopied ) )
555 {
556 LDEB(biParaFrom->biParaParticuleCount);
557 docDeleteNode( eo->eoDocument, eo->eoTree, biParaTo );
558 return (BufferItem *)0;
559 }
560 }
561 else{
562 int textAttributeNumberTo;
563 const TextParticule * tpFrom;
564
565 tpFrom= biParaFrom->biParaParticules+
566 biParaFrom->biParaParticuleCount- 1;
567
568 textAttributeNumberTo= docMapTextAttributeNumber( dcj,
569 tpFrom->tpTextAttrNr );
570 if ( textAttributeNumberTo < 0 )
571 { LDEB(textAttributeNumberTo); return (BufferItem *)0; }
572
573 if ( ! docInsertTextParticule( biParaTo, 0, 0, 0,
574 DOCkindSPAN, textAttributeNumberTo ) )
575 { LDEB(1); return (BufferItem *)0; }
576 }
577
578 /* 5 */
579 utilPropMaskClear( &ppChgMask );
580
581 utilPropMaskClear( &ppUpdMask );
582 utilPropMaskFill( &ppUpdMask, PPprop_FULL_COUNT );
583 PROPmaskUNSET( &ppUpdMask, PPpropTABLE_NESTING );
584
585 if ( docEditUpdParaProperties( eo, &ppChgMask, biParaTo, &ppUpdMask,
586 &(biParaFrom->biParaProperties),
587 &(dcj->dcjAttributeMap) ) )
588 { LDEB(1); return (BufferItem *)0; }
589
590 eo->eoParagraphsInserted++;
591 if ( biParaTo->biParaListOverride > 0 )
592 { dcj->dcjBulletsCopied++; }
593
594 return biParaTo;
595 }
596
597