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