1 /************************************************************************/
2 /* */
3 /* Buffer administration routines. Functionality related to the node */
4 /* tree. */
5 /* */
6 /************************************************************************/
7
8 # include "docBufConfig.h"
9
10 # include <stdlib.h>
11
12 # include <appDebugon.h>
13
14 # include "docBuf.h"
15 # include "docNodeTree.h"
16 # include "docParaParticules.h"
17
18 # define VALIDATE_TREE 0
19
20 #if 0
21
22 Schema to illustrate the numbering of paragraphs and the
23 administration that is kept for that purpose
24 =========================================================
25
26 node->biLeftParagraphs is the number of paragraphs to the left
27 of this node in its immediate parent plus the number of paragraph
28 descendants. I.E: For nodes with children, the number of paragraphs
29 in the children is included in node->biLeftParagraphs. A paragraph
30 includes itself in its node->biLeftParagraphs.
31
32 Numbers of the paragraphs and the value of node->biLeftParagraphs:
33
34 1 2 3 4 5 6 7 8 9 10 11 12
35 + + + + + + + + + + + +
36 1 2 3 4 1 2 3 4 5 1 2 3
37 | | | | | | | | | | | |
38 4-----+-----+-----+ 9-----+-----+-----+-----+ 12----+-----+
39 | | |
40 12----------------------+-----------------------------+
41 |
42 *
43
44 Deleting 8 yields:
45
46 1 2 3 4 5 6 7 8 9 10 11
47 + + + + + + + + + + +
48 1 2 3 4 1 2 3 4 1 2 3
49 | | | | | | | | | | |
50 4-----+-----+-----+ 8-----+-----+-----+-----+ 11----+-----+
51 | | |
52 11----------------------+-----------------------------+
53 |
54 *
55
56 So after deleting/inserting paragraphs: Descend to the root of the
57 tree. In every parent adapt node->biLeftParagraphs of all direct
58 children to the right of the child that we come from. Set
59 node->biLeftParagraphs of the parent to the value in its right most
60 child. Continue with the parent of the parent until we have reached
61 the root.
62
63 NOTE: I am educated as a biologist. My trees have their root at the
64 bottom, not at the top like those of computer scientists that
65 turn the world upside down. (I must admit that the metaphor
66 of parents and descendants has the computer science orientation.)
67
68 #endif
69
70 /************************************************************************/
71 /* */
72 /* Free a BufferItem. */
73 /* */
74 /************************************************************************/
75
docCleanNode(BufferDocument * bd,DocumentTree * dt,BufferItem * node)76 static void docCleanNode( BufferDocument * bd,
77 DocumentTree * dt,
78 BufferItem * node )
79 {
80 int i;
81
82 for ( i= node->biChildCount- 1; i >= 0; i-- )
83 { docFreeNode( bd, dt, node->biChildren[i] ); }
84 if ( node->biChildren )
85 { free( node->biChildren ); }
86
87 switch( node->biLevel )
88 {
89 case DOClevBODY:
90 break;
91
92 case DOClevSECT:
93 {
94 SectHeadersFooters * shf= node->biSectHeadersFooters;
95
96 if ( shf )
97 {
98 docCleanSectHeadersFooters( bd, shf );
99 free( shf );
100 }
101
102 docCleanSectionProperties( &(node->biSectProperties) );
103 }
104 break;
105
106 case DOClevCELL:
107 break;
108
109 case DOClevROW:
110 docCleanRowProperties( &(node->biRowProperties) );
111 break;
112
113 case DOClevPARA:
114 docCleanParaNode( bd, dt, node );
115 break;
116
117 default:
118 /*FALLTHROUGH*/
119 case DOClevOUT:
120 LDEB(node->biLevel);
121 break;
122 }
123
124 node->biLevel= DOClevOUT;
125 }
126
docFreeNode(BufferDocument * bd,DocumentTree * dt,BufferItem * node)127 void docFreeNode( BufferDocument * bd,
128 DocumentTree * dt,
129 BufferItem * node )
130 {
131 docCleanNode( bd, dt, node );
132 free( node );
133 }
134
docMakeNode(void)135 BufferItem * docMakeNode( void )
136 {
137 return (BufferItem *)malloc(sizeof(BufferItem));
138 }
139
140 /************************************************************************/
141 /* */
142 /* Initialise a BufferItem. */
143 /* */
144 /************************************************************************/
145
docInitNode(BufferItem * node,BufferItem * parent,const BufferDocument * bd,int numberInParent,int level,int treeType)146 void docInitNode( BufferItem * node,
147 BufferItem * parent,
148 const BufferDocument * bd,
149 int numberInParent,
150 int level,
151 int treeType )
152 {
153 node->biChildren= (BufferItem **)0;
154 node->biChildCount= 0;
155 node->biLeftParagraphs= 0;
156
157 switch( level )
158 {
159 case DOClevBODY:
160 break;
161
162 case DOClevSECT:
163 node->biSectHeadersFooters= (SectHeadersFooters *)malloc(
164 sizeof(SectHeadersFooters) );
165 if ( ! node->biSectHeadersFooters )
166 { XDEB(node->biSectHeadersFooters); }
167 else{ docInitSectHeadersFooters( node->biSectHeadersFooters ); }
168
169 docInitSectionProperties( &(node->biSectProperties) );
170
171 if ( bd )
172 { node->biSectDocumentGeometry= bd->bdProperties.dpGeometry; }
173
174 docInitSelectionScope( &(node->biSectSelectionScope) );
175
176 node->biSectSelectionScope.ssTreeType= treeType;
177 node->biSectSelectionScope.ssSectNr= numberInParent;
178
179 break;
180
181 case DOClevCELL:
182 node->biCellTopInset= 0;
183 node->biCellRowspan= 1;
184 node->biCellMergedCellTopRow= -1;
185 node->biCellMergedCellTopCol= -1;
186 break;
187
188 case DOClevROW:
189 node->biRowTableHeaderRow= -1;
190 node->biRowTableFirst= -1;
191 node->biRowTablePast= -1;
192 node->biRowPrecededByHeader= 0;
193 node->biRowForTable= 0;
194
195 node->biRowTopInset= 0;
196
197 docInitRowProperties( &(node->biRowProperties) );
198
199 docInitLayoutPosition( &(node->biRowBelowAllCellsPosition) );
200 docInitLayoutPosition( &(node->biRowAboveHeaderPosition) );
201 break;
202
203 case DOClevPARA:
204 docInitParaNode( node );
205 break;
206
207 default:
208 node->biLevel= DOClevOUT;
209 node->biParent= (BufferItem *)0;
210 LDEB(level); return;
211 }
212
213 node->biLevel= level;
214 node->biTreeType= treeType;
215 node->biParent= parent;
216 node->biNumberInParent= numberInParent;
217
218 docInitLayoutPosition( &(node->biTopPosition) );
219 docInitLayoutPosition( &(node->biBelowPosition) );
220
221 return;
222 }
223
224 /************************************************************************/
225 /* */
226 /* 1) Delete a series of nodes. */
227 /* 2) Delete a node from its parent. */
228 /* */
229 /************************************************************************/
230
docSectSetSelectionScopes(BufferItem * sectBi)231 static void docSectSetSelectionScopes( BufferItem * sectBi )
232 {
233 int n= sectBi->biNumberInParent;
234 SectHeadersFooters * shf= sectBi->biSectHeadersFooters;
235
236 sectBi->biSectSelectionScope.ssSectNr= n;
237
238 if ( shf )
239 {
240 if ( shf->shfFirstPageHeader.dtRoot )
241 {
242 shf->shfFirstPageHeader.dtRoot->
243 biSectSelectionScope.ssOwnerSectNr= n;
244 }
245 if ( shf->shfLeftPageHeader.dtRoot )
246 {
247 shf->shfLeftPageHeader.dtRoot->
248 biSectSelectionScope.ssOwnerSectNr= n;
249 }
250 if ( shf->shfRightPageHeader.dtRoot )
251 {
252 shf->shfRightPageHeader.dtRoot->
253 biSectSelectionScope.ssOwnerSectNr= n;
254 }
255
256 if ( shf->shfFirstPageFooter.dtRoot )
257 {
258 shf->shfFirstPageFooter.dtRoot->
259 biSectSelectionScope.ssOwnerSectNr= n;
260 }
261 if ( shf->shfLeftPageFooter.dtRoot )
262 {
263 shf->shfLeftPageFooter.dtRoot->
264 biSectSelectionScope.ssOwnerSectNr= n;
265 }
266 if ( shf->shfRightPageFooter.dtRoot )
267 {
268 shf->shfRightPageFooter.dtRoot->
269 biSectSelectionScope.ssOwnerSectNr= n;
270 }
271 }
272
273 return;
274 }
275
276 /************************************************************************/
277 /* */
278 /* Paragraphs have been deleted from a group node. */
279 /* Administration in the child array has been done. Fix */
280 /* biLeftParagraphs in the node itself and its parents. */
281 /* */
282 /************************************************************************/
283
docParagraphsDeleted(BufferItem * node,int paragraphsDeleted)284 static void docParagraphsDeleted( BufferItem * node,
285 int paragraphsDeleted )
286 {
287 while( node->biParent )
288 {
289 int first;
290 int f;
291
292 first= node->biNumberInParent;
293 node= node->biParent;
294
295 for ( f= first; f < node->biChildCount; f++ )
296 { node->biChildren[f]->biLeftParagraphs -= paragraphsDeleted; }
297 }
298
299 node->biLeftParagraphs -= paragraphsDeleted;
300
301 return;
302 }
303
304 /* 1 */
docDeleteNodes(BufferDocument * bd,DocumentTree * dt,BufferItem * node,int first,int count)305 void docDeleteNodes( BufferDocument * bd,
306 DocumentTree * dt,
307 BufferItem * node,
308 int first,
309 int count )
310 {
311 int n;
312 int f;
313 int c;
314 int paragraphsDeleted= 0;
315
316 # if VALIDATE_TREE
317 if ( docCheckNode( bd->bdBody.dtRoot ) )
318 { LDEB(2); docListNode( 0, bd->bdBody.dtRoot ); abort(); }
319 # endif
320
321 if ( first > node->biChildCount )
322 {
323 LLDEB(first,node->biChildCount);
324 first= node->biChildCount;
325 }
326
327 if ( first+ count > node->biChildCount )
328 {
329 LLDEB(first+count,node->biChildCount);
330 count= node->biChildCount- first;
331 }
332
333 if ( count <= 0 )
334 { LDEB(count); return; }
335 else{
336 f= 0;
337 if ( first > 0 )
338 { f= node->biChildren[first- 1]->biLeftParagraphs; }
339
340 c= node->biChildren[first+ count- 1]->biLeftParagraphs;
341
342 paragraphsDeleted= c- f;
343 }
344
345 n= first+ count- 1;
346 while( n >= first )
347 { docFreeNode( bd, dt, node->biChildren[n] ); n--; }
348
349 node->biChildCount -= count;
350
351 f= first;
352 while( f < node->biChildCount )
353 {
354 node->biChildren[f]= node->biChildren[f+ count];
355 node->biChildren[f]->biNumberInParent= f;
356 node->biChildren[f]->biLeftParagraphs -= paragraphsDeleted;
357
358 if ( node->biChildren[f]->biLevel == DOClevSECT )
359 { docSectSetSelectionScopes( node->biChildren[f] ); }
360
361 f++;
362 }
363
364 docParagraphsDeleted( node, paragraphsDeleted );
365
366 # if VALIDATE_TREE
367 if ( docCheckNode( bd->bdBody.dtRoot ) )
368 { LDEB(2); docListNode( 0, bd->bdBody.dtRoot ); abort(); }
369 # endif
370
371 return;
372 }
373
374 /* 2 */
docDeleteNode(BufferDocument * bd,DocumentTree * dt,BufferItem * node)375 void docDeleteNode( BufferDocument * bd,
376 DocumentTree * dt,
377 BufferItem * node )
378 {
379 if ( node->biParent )
380 {
381 docDeleteNodes( bd, dt, node->biParent, node->biNumberInParent, 1 );
382 }
383 else{ docFreeNode( bd, dt, node ); }
384 }
385
386 /************************************************************************/
387 /* */
388 /* Delete the Document Tree Node that is the root of a document Tree */
389 /* This is NOT the way to delete a document tree. Use */
390 /* docEraseDocumentTree() to do so. */
391 /* */
392 /************************************************************************/
393
docDeleteDocumentTree(BufferDocument * bd,DocumentTree * dt)394 void docDeleteDocumentTree( BufferDocument * bd,
395 DocumentTree * dt )
396 {
397 docFreeNode( bd, dt, dt->dtRoot );
398 dt->dtRoot= (BufferItem *)0;
399 }
400
401 /************************************************************************/
402 /* */
403 /* Paragraphs have been inserted into a group node. */
404 /* Administration in the child array has been done. Fix */
405 /* biLeftParagraphs in the node itself and its parents. */
406 /* */
407 /************************************************************************/
408
docParagraphsInserted(BufferItem * node,int paragraphsInserted)409 static void docParagraphsInserted( BufferItem * node,
410 int paragraphsInserted )
411 {
412 while( node->biParent )
413 {
414 int first;
415 int f;
416
417 first= node->biNumberInParent;
418 node= node->biParent;
419
420 for ( f= first; f < node->biChildCount; f++ )
421 { node->biChildren[f]->biLeftParagraphs += paragraphsInserted; }
422 }
423
424 node->biLeftParagraphs += paragraphsInserted;
425
426 return;
427 }
428
429 /************************************************************************/
430
docValidChildLevel(int parentLevel,int childLevel)431 int docValidChildLevel( int parentLevel,
432 int childLevel )
433 {
434 switch( parentLevel )
435 {
436 case DOClevBODY:
437 if ( childLevel != DOClevSECT )
438 { return 0; }
439 break;
440
441 case DOClevSECT:
442 if ( childLevel != DOClevROW )
443 { return 0; }
444 break;
445
446 case DOClevROW:
447 if ( childLevel != DOClevCELL )
448 { return 0; }
449 break;
450
451 case DOClevCELL:
452 if ( childLevel != DOClevPARA && childLevel != DOClevROW )
453 { return 0; }
454 break;
455
456 default:
457 LLDEB(parentLevel,childLevel); return 0;
458 }
459
460 return 1;
461 }
462
463 /************************************************************************/
464 /* */
465 /* Add a new child to a parent. */
466 /* */
467 /************************************************************************/
468
docInsertNode(const BufferDocument * bd,BufferItem * parent,int n,int level)469 BufferItem * docInsertNode( const BufferDocument * bd,
470 BufferItem * parent,
471 int n,
472 int level )
473 {
474 BufferItem * rval= (BufferItem *)0;
475 BufferItem * newBi= (BufferItem *)0;
476
477 int i;
478
479 int newSize;
480
481 BufferItem ** freshChildren;
482
483 int paragraphsInserted;
484
485 # if VALIDATE_TREE
486 if ( docCheckNode( bd->bdBody.dtRoot ) )
487 { LDEB(2); docListNode( 0, bd->bdBody.dtRoot ); abort(); }
488 # endif
489
490 if ( ! docValidChildLevel( parent->biLevel, level ) )
491 { SSDEB(docLevelStr(parent->biLevel),docLevelStr(level)); goto ready; }
492
493 if ( n == -1 )
494 { n= parent->biChildCount; }
495
496 newSize= parent->biChildCount;
497
498 if ( newSize % 10 )
499 { newSize ++; }
500 else{ newSize += 10; }
501
502 newSize *= sizeof(BufferItem *);
503
504 freshChildren= (BufferItem **)realloc( parent->biChildren, newSize );
505 if ( ! freshChildren )
506 { LLXDEB(parent->biChildCount,newSize,freshChildren); goto ready; }
507 parent->biChildren= freshChildren;
508
509 newBi= (BufferItem *)malloc( sizeof(BufferItem) );
510 if ( ! newBi )
511 { XDEB(newBi); goto ready; }
512
513 docInitNode( newBi, parent, bd, n, level, parent->biTreeType );
514
515 if ( n == 0 )
516 { newBi->biTopPosition= parent->biTopPosition; }
517 else{ newBi->biTopPosition= freshChildren[n-1]->biBelowPosition; }
518
519 for ( i= parent->biChildCount; i > n; i-- )
520 {
521 freshChildren[i]= freshChildren[i-1];
522
523 freshChildren[i]->biNumberInParent= i;
524
525 if ( freshChildren[i]->biLevel == DOClevSECT )
526 { docSectSetSelectionScopes( freshChildren[i] ); }
527 }
528
529 freshChildren[n]= newBi;
530 parent->biChildCount++;
531
532 rval= newBi; newBi= (BufferItem *)0; /* steal */
533
534 if ( level == DOClevPARA )
535 {
536 paragraphsInserted= 1;
537
538 docSetParaTableNesting( rval );
539
540 if ( n > 0 )
541 { rval->biLeftParagraphs= freshChildren[n-1]->biLeftParagraphs; }
542
543 for ( i= n; i < parent->biChildCount; i++ )
544 { parent->biChildren[i]->biLeftParagraphs += paragraphsInserted; }
545
546 docParagraphsInserted( parent, paragraphsInserted );
547 }
548 else{
549 if ( n > 0 )
550 { rval->biLeftParagraphs= freshChildren[n-1]->biLeftParagraphs; }
551 }
552
553 # if VALIDATE_TREE
554 if ( docCheckNode( bd->bdBody.dtRoot ) )
555 { LDEB(2); docListNode( 0, bd->bdBody.dtRoot ); abort(); }
556 # endif
557
558 ready:
559
560 if ( newBi )
561 { free( newBi ); }
562
563 return rval;
564 }
565
566 /************************************************************************/
567 /* */
568 /* Make an empty paragraph: Needed at several locations. */
569 /* */
570 /************************************************************************/
571
docInsertEmptyParagraph(BufferDocument * bd,BufferItem * node,int textAttributeNumber)572 BufferItem * docInsertEmptyParagraph(
573 BufferDocument * bd,
574 BufferItem * node,
575 int textAttributeNumber )
576 {
577 if ( node->biLevel < DOClevSECT )
578 { LDEB(node->biLevel); return (BufferItem *)0; }
579
580 if ( node->biLevel < DOClevROW )
581 {
582 node= docInsertNode( bd, node, -1, DOClevROW );
583 if ( ! node )
584 { XDEB(node); return (BufferItem *)0; }
585 }
586
587 if ( node->biLevel < DOClevCELL )
588 {
589 node= docInsertNode( bd, node, -1, DOClevCELL );
590 if ( ! node )
591 { XDEB(node); return (BufferItem *)0; }
592 }
593
594 if ( node->biLevel < DOClevPARA )
595 {
596 node= docInsertNode( bd, node, -1, DOClevPARA );
597 if ( ! node )
598 { XDEB(node); return (BufferItem *)0; }
599 }
600 else{
601 node= docInsertNode( bd, node->biParent, -1, DOClevPARA );
602 if ( ! node )
603 { XDEB(node); return (BufferItem *)0; }
604 }
605
606 if ( ! docInsertTextParticule( node, 0, 0, 0,
607 DOCkindSPAN, textAttributeNumber ) )
608 { LDEB(1); return (BufferItem *)0; }
609
610 return node;
611 }
612
613 /************************************************************************/
614 /* */
615 /* Insert a new row in a table. */
616 /* */
617 /************************************************************************/
618
docInsertRowNode(BufferDocument * bd,BufferItem * sectBi,int n,const RowProperties * rp,int textAttributeNumber)619 BufferItem * docInsertRowNode( BufferDocument * bd,
620 BufferItem * sectBi,
621 int n,
622 const RowProperties * rp,
623 int textAttributeNumber )
624 {
625 int col;
626
627 BufferItem * rval= (BufferItem *)0;
628 BufferItem * rowBi= (BufferItem *)0;
629
630 rowBi= docInsertNode( bd, sectBi, n, DOClevROW );
631 if ( ! rowBi )
632 { XDEB(rowBi); goto ready; }
633
634 if ( docCopyRowProperties( &(rowBi->biRowProperties), rp,
635 (const DocumentAttributeMap *)0 ) )
636 { LDEB(1); goto ready; }
637
638 for ( col= 0; col < rp->rpCellCount; col++ )
639 {
640 BufferItem * paraBi;
641
642 paraBi= docInsertEmptyParagraph( bd, rowBi, textAttributeNumber );
643 if ( ! paraBi )
644 { XDEB(paraBi); goto ready; }
645
646 docSetParaTableNesting( paraBi );
647 }
648
649 rval= rowBi; rowBi= (BufferItem *)0; /* steal */
650
651 ready:
652
653 if ( rowBi )
654 { docDeleteNode( bd, (DocumentTree *)0, rowBi ); }
655
656 return rval;
657 }
658
659 /************************************************************************/
660 /* */
661 /* Split a node with childen. */
662 /* */
663 /* 1) Insert a fresh node at the position of the node to be split. */
664 /* 2) Copy various properties to the fresh node. */
665 /* 3) Move the first n children to the fresh node. */
666 /* 4) Paragraph number administration. */
667 /* 5) Shift the children in the old node. */
668 /* */
669 /************************************************************************/
670
docSplitGroupNode(BufferDocument * bd,BufferItem ** pNewBi,BufferItem * oldBi,int n)671 int docSplitGroupNode( BufferDocument * bd,
672 BufferItem ** pNewBi,
673 BufferItem * oldBi,
674 int n )
675 {
676 BufferItem * newBi;
677 int i;
678 int prev;
679
680 /* 1 */
681 newBi= docInsertNode( bd, oldBi->biParent,
682 oldBi->biNumberInParent, oldBi->biLevel );
683 if ( ! newBi )
684 { XDEB(newBi); return -1; }
685
686 /* 2 */
687 switch( oldBi->biLevel )
688 {
689 case DOClevSECT:
690 if ( docCopySectDescription( newBi, bd, oldBi, bd ) )
691 { LDEB(1); return -1; }
692 break;
693
694 case DOClevCELL:
695 break;
696
697 case DOClevROW:
698 if ( docCopyRowProperties( &(newBi->biRowProperties),
699 &(oldBi->biRowProperties),
700 (const DocumentAttributeMap *)0 ) )
701 { LDEB(1); return -1; }
702 break;
703
704 default:
705 LDEB(oldBi->biLevel); return -1;
706 }
707
708 newBi->biChildren= (BufferItem **)malloc( n* sizeof(BufferItem *) );
709 if ( ! newBi->biChildren )
710 { XDEB(newBi->biChildren); return -1; }
711
712 /* 3 */
713 for ( i= 0; i < n; i++ )
714 {
715 newBi->biChildren[i]= oldBi->biChildren[i];
716 newBi->biChildren[i]->biParent= newBi;
717 }
718
719 /* 4 */
720 prev= 0;
721 if ( newBi->biNumberInParent > 0 )
722 {
723 prev= newBi->biParent->biChildren[newBi->biNumberInParent-1]->
724 biLeftParagraphs;
725 }
726
727 if ( n == 0 )
728 { newBi->biLeftParagraphs= prev; }
729 else{
730 newBi->biLeftParagraphs= prev+ newBi->biChildren[n-1]->biLeftParagraphs;
731 }
732
733 /* 4,5 */
734 newBi->biChildCount= n;
735 oldBi->biChildCount -= n;
736
737 prev= 0;
738 for ( i= 0; i < oldBi->biChildCount; i++ )
739 {
740 BufferItem * child= oldBi->biChildren[i+ n];
741
742 /* 5 */
743 oldBi->biChildren[i]= child;
744 child->biNumberInParent -= n;
745
746 if ( oldBi->biChildren[i]->biLevel == DOClevPARA )
747 { prev++; }
748 else{
749 if ( child->biChildCount > 0 )
750 {
751 prev += child->biChildren[child->biChildCount-1]->
752 biLeftParagraphs;
753 }
754 }
755
756 oldBi->biChildren[i]->biLeftParagraphs= prev;
757 }
758
759 *pNewBi= newBi; return 0;
760 }
761
762 /************************************************************************/
763 /* */
764 /* Split a 'group node' I.E. a node that has children rather than */
765 /* its own text. */
766 /* */
767 /* The goal is to make sure that the split before position n in */
768 /* splitNode is between two nodes with level level. */
769 /* */
770 /************************************************************************/
771
docSplitGroupNodeAtLevel(BufferDocument * bd,BufferItem ** pBeforeNode,BufferItem ** pAfterNode,BufferItem * splitNode,int n,int level)772 int docSplitGroupNodeAtLevel( BufferDocument * bd,
773 BufferItem ** pBeforeNode,
774 BufferItem ** pAfterNode,
775 BufferItem * splitNode,
776 int n,
777 int level )
778 {
779 BufferItem * beforeNode= (BufferItem *)0;
780 BufferItem * afterNode= splitNode;
781 BufferItem * node;
782
783 # if VALIDATE_TREE
784 SDEB(docLevelStr(parentBi->biLevel));
785 if ( docCheckNode( bd->bdBody.dtRoot ) )
786 { LDEB(2); docListNode( 0, bd->bdBody.dtRoot ); abort(); }
787 # endif
788
789 if ( ! splitNode )
790 { XDEB(splitNode); return -1; }
791
792 node= splitNode;
793 while( node && node->biLevel != level- 1 )
794 { node= node->biParent; }
795 if ( ! node )
796 {
797 SSXDEB(docLevelStr(splitNode->biLevel),docLevelStr(level),node);
798 return -1;
799 }
800
801 if ( n < 0 || n >= splitNode->biChildCount )
802 { LLDEB(n,splitNode->biChildCount); return -1; }
803
804 afterNode= splitNode;
805 for (;;)
806 {
807 if ( n > 0 || afterNode->biLevel == level )
808 {
809 if ( docSplitGroupNode( bd, &beforeNode, afterNode, n ) )
810 { LDEB(n); return -1; }
811
812 if ( afterNode->biLevel == level )
813 { break; }
814 }
815
816 n= afterNode->biNumberInParent;
817 afterNode= afterNode->biParent;
818 }
819
820 # if VALIDATE_TREE
821 SDEB(docLevelStr(afterNode->biLevel));
822 if ( docCheckNode( bd->bdBody.dtRoot ) )
823 { LDEB(2); docListNode( 0, bd->bdBody.dtRoot ); abort(); }
824 # endif
825
826 if ( pBeforeNode )
827 { *pBeforeNode= beforeNode; }
828 if ( pAfterNode )
829 { *pAfterNode= afterNode; }
830
831 return 0;
832 }
833
834 /************************************************************************/
835 /* */
836 /* Merge the children of two nodes into the first one. */
837 /* */
838 /************************************************************************/
839
docMergeGroupNodes(BufferItem * to,BufferItem * from)840 int docMergeGroupNodes( BufferItem * to,
841 BufferItem * from )
842 {
843 BufferItem ** freshChildren;
844 int f;
845 int t;
846 int left;
847 int prev;
848 int paragraphsMoved;
849
850 if ( to == from )
851 { XXDEB(to,from); return -1; }
852 if ( to->biLevel != from->biLevel )
853 { LLDEB(to->biLevel,from->biLevel); return -1; }
854
855 if ( from->biChildCount == 0 )
856 { return 0; }
857
858 # if VALIDATE_TREE
859 SSDEB(docLevelStr(to->biLevel),docLevelStr(from->biLevel));
860 if ( docCheckRootNode( to ) )
861 { LDEB(2); docListRootNode( 0, to ); abort(); }
862 if ( docCheckRootNode( from ) )
863 { LDEB(2); docListRootNode( 0, from ); abort(); }
864 # endif
865
866 freshChildren= (BufferItem **)realloc( to->biChildren,
867 ( to->biChildCount+ from->biChildCount )* sizeof(BufferItem *) );
868 if ( ! freshChildren )
869 {
870 LLXDEB(to->biChildCount,from->biChildCount,freshChildren);
871 return -1;
872 }
873 to->biChildren= freshChildren;
874
875 if ( from->biParent && from->biNumberInParent > 0 )
876 {
877 BufferItem * prevBi;
878
879 prevBi= from->biParent->biChildren[from->biNumberInParent- 1];
880 paragraphsMoved= from->biLeftParagraphs- prevBi->biLeftParagraphs;
881 }
882 else{
883 paragraphsMoved= from->biLeftParagraphs;
884 }
885
886 left= 0; prev= 0;
887 t= to->biChildCount;
888 if ( t > 0 )
889 { left= to->biChildren[t- 1]->biLeftParagraphs; }
890 for ( f= 0; f < from->biChildCount; t++, f++ )
891 {
892 int count;
893
894 freshChildren[t]= from->biChildren[f];
895 freshChildren[t]->biParent= to;
896 freshChildren[t]->biNumberInParent= t;
897
898 count= freshChildren[t]->biLeftParagraphs- prev;
899 prev= freshChildren[t]->biLeftParagraphs;
900 left += count;
901 freshChildren[t]->biLeftParagraphs= left;
902
903 if ( freshChildren[t]->biLevel == DOClevSECT )
904 { docSectSetSelectionScopes( freshChildren[t] ); }
905 }
906
907 to->biChildCount += from->biChildCount;
908 from->biChildCount= 0;
909
910 docParagraphsInserted( to, paragraphsMoved );
911 docParagraphsDeleted( from, paragraphsMoved );
912
913 # if VALIDATE_TREE
914 SSDEB(docLevelStr(to->biLevel),docLevelStr(from->biLevel));
915 if ( docCheckRootNode( to ) )
916 { LDEB(2); docListRootNode( 0, to ); abort(); }
917 if ( docCheckRootNode( from ) )
918 { LDEB(2); docListRootNode( 0, from ); abort(); }
919 # endif
920
921 return 0;
922 }
923
924 /************************************************************************/
925 /* */
926 /* Return the number of a paragraph. */
927 /* */
928 /************************************************************************/
929
docNumberOfParagraph(const BufferItem * node)930 int docNumberOfParagraph( const BufferItem * node )
931 {
932 int n= 0;
933
934 if ( node->biLevel != DOClevPARA )
935 { SDEB(docLevelStr(node->biLevel)); return -1; }
936
937 n= node->biLeftParagraphs;
938
939 while( node->biParent )
940 {
941 node= node->biParent;
942
943 if ( node->biParent && node->biNumberInParent > 0 )
944 {
945 if ( node->biNumberInParent >= node->biParent->biChildCount )
946 { LLDEB(node->biNumberInParent,node->biParent->biChildCount); }
947
948 n += node->biParent->biChildren[
949 node->biNumberInParent- 1]->biLeftParagraphs;
950 }
951 }
952
953 return n;
954 }
955
docGetParagraphByNumber(const DocumentTree * dt,int paraNr)956 BufferItem * docGetParagraphByNumber( const DocumentTree * dt,
957 int paraNr )
958 {
959 BufferItem * node= dt->dtRoot;
960
961 if ( paraNr < 1 )
962 { LDEB(paraNr); return (BufferItem *)0; }
963
964 while( node->biChildCount > 0 )
965 {
966 int i;
967
968 for ( i= 0; i < node->biChildCount; i++ )
969 {
970 if ( node->biChildren[i]->biLeftParagraphs >= paraNr )
971 { break; }
972 }
973
974 if ( i >= node->biChildCount )
975 {
976 /* LLSDEB(paraNr,node->biChildCount,docLevelStr(node->biLevel)); */
977 return (BufferItem *)0;
978 }
979
980 if ( i > 0 )
981 { paraNr -= node->biChildren[i-1]->biLeftParagraphs; }
982
983 node= node->biChildren[i];
984 }
985
986 if ( node->biLevel != DOClevPARA )
987 { SDEB(docLevelStr(node->biLevel)); return (BufferItem *)0; }
988
989 if ( paraNr != 1 )
990 { LDEB(paraNr); return (BufferItem *)0; }
991
992 return node;
993 }
994
docGetCommonParent(BufferItem * paraNode1,BufferItem * paraNode2)995 BufferItem * docGetCommonParent( BufferItem * paraNode1,
996 BufferItem * paraNode2 )
997 {
998 int paraNr1= docNumberOfParagraph( paraNode1 );
999 int paraNr2= docNumberOfParagraph( paraNode2 );
1000
1001 BufferItem * bi1= paraNode1;
1002 BufferItem * bi2= paraNode2;
1003
1004 if ( paraNr1 < 1 || paraNr2 < paraNr1 )
1005 { LLDEB(paraNr1,paraNr2); return (BufferItem *)0; }
1006
1007 while( bi1->biParent )
1008 { bi1= bi1->biParent; }
1009 while( bi2->biParent )
1010 { bi2= bi2->biParent; }
1011 if ( bi1 != bi2 )
1012 { XXDEB(bi1,bi2); return (BufferItem *)0; }
1013
1014 while( bi1->biChildCount > 0 )
1015 {
1016 int i;
1017
1018 for ( i= 0; i < bi1->biChildCount; i++ )
1019 {
1020 if ( bi1->biChildren[i]->biLeftParagraphs >= paraNr1 )
1021 { break; }
1022 }
1023
1024 if ( bi1->biChildren[i]->biLeftParagraphs < paraNr2 )
1025 { return bi1; }
1026
1027 if ( i >= bi1->biChildCount )
1028 {
1029 /* LLSDEB(paraNr,bi1->biChildCount,docLevelStr(bi1->biLevel)); */
1030 return (BufferItem *)0;
1031 }
1032
1033 if ( i > 0 )
1034 {
1035 paraNr1 -= bi1->biChildren[i-1]->biLeftParagraphs;
1036 paraNr2 -= bi1->biChildren[i-1]->biLeftParagraphs;
1037 }
1038
1039 bi1= bi1->biChildren[i];
1040 }
1041
1042 if ( bi1->biLevel != DOClevPARA )
1043 { SDEB(docLevelStr(bi1->biLevel)); return (BufferItem *)0; }
1044
1045 if ( paraNr1 != 1 || paraNr2 != 1 )
1046 { LLDEB(paraNr1,paraNr2); return (BufferItem *)0; }
1047
1048 return bi1;
1049 }
1050
1051 /************************************************************************/
1052 /* */
1053 /* Return the nearest parent of a BufferItem that is a real row. */
1054 /* candidate row, cell. */
1055 /* */
1056 /************************************************************************/
1057
docGetRowNode(BufferItem * node)1058 BufferItem * docGetRowNode( BufferItem * node )
1059 {
1060 while( node && ! docIsRowNode( node ) )
1061 { node= node->biParent; }
1062
1063 return node;
1064 }
1065
docGetRowLevelNode(BufferItem * node)1066 BufferItem * docGetRowLevelNode( BufferItem * node )
1067 {
1068 while( node &&
1069 node->biLevel != DOClevROW )
1070 { node= node->biParent; }
1071
1072 return node;
1073 }
1074
docGetCellNode(BufferItem * node)1075 BufferItem * docGetCellNode( BufferItem * node )
1076 {
1077 while( node &&
1078 node->biLevel != DOClevCELL )
1079 { node= node->biParent; }
1080
1081 return node;
1082 }
1083
1084 /************************************************************************/
1085 /* */
1086 /* Return the nearest parent of a BufferItem that is a section. */
1087 /* */
1088 /************************************************************************/
1089
docGetSectNode(BufferItem * node)1090 BufferItem * docGetSectNode( BufferItem * node )
1091 {
1092 while( node &&
1093 node->biLevel != DOClevSECT )
1094 { node= node->biParent; }
1095
1096 return node;
1097 }
1098
1099 /************************************************************************/
1100 /* */
1101 /* Calculate table nesting: Follow the path to the root and count */
1102 /* the number of (table) rows that we traverse. */
1103 /* */
1104 /************************************************************************/
1105
docTableNesting(const BufferItem * node)1106 int docTableNesting( const BufferItem * node )
1107 {
1108 int tableNesting= 0;
1109
1110 while( node )
1111 {
1112 if ( docIsRowNode( node ) )
1113 { tableNesting++; }
1114
1115 node= node->biParent;
1116 }
1117
1118 return tableNesting;
1119 }
1120
docRowNesting(const BufferItem * node)1121 int docRowNesting( const BufferItem * node )
1122 {
1123 int rowNesting= 0;
1124
1125 while( node )
1126 {
1127 if ( node->biLevel == DOClevROW )
1128 { rowNesting++; }
1129
1130 node= node->biParent;
1131 }
1132
1133 return rowNesting;
1134 }
1135
docSetParaTableNesting(BufferItem * paraBi)1136 void docSetParaTableNesting( BufferItem * paraBi )
1137 {
1138 if ( paraBi->biLevel != DOClevPARA )
1139 { SDEB(docLevelStr(paraBi->biLevel)); return; }
1140
1141 paraBi->biParaTableNesting= docTableNesting( paraBi );
1142 }
1143
1144 /************************************************************************/
1145 /* */
1146 /* Change the kind of tree for a node and all its children. */
1147 /* */
1148 /************************************************************************/
1149
docSetTreeTypeOfNode(BufferItem * node,int treeType)1150 void docSetTreeTypeOfNode( BufferItem * node,
1151 int treeType )
1152 {
1153 int i;
1154
1155 node->biTreeType= treeType;
1156
1157 if ( node->biLevel == DOClevSECT )
1158 { node->biSectSelectionScope.ssTreeType= treeType; }
1159
1160 for ( i= 0; i < node->biChildCount; i++ )
1161 { docSetTreeTypeOfNode( node->biChildren[i], treeType ); }
1162
1163 return;
1164 }
1165
1166 /************************************************************************/
1167 /* */
1168 /* Is a node at the extremity of a parent node. */
1169 /* */
1170 /************************************************************************/
1171
docNodeAtExtremity(int * pAtExtremity,const BufferItem * parentNode,const BufferItem * paraNode,int after)1172 int docNodeAtExtremity( int * pAtExtremity,
1173 const BufferItem * parentNode,
1174 const BufferItem * paraNode,
1175 int after )
1176 {
1177 if ( after )
1178 {
1179 DocumentPosition dpTail;
1180
1181 if ( docTailPosition( &dpTail, (BufferItem *)parentNode ) )
1182 { LDEB(1); return -1; }
1183
1184 *pAtExtremity= ( paraNode == dpTail.dpNode );
1185 }
1186 else{
1187 DocumentPosition dpHead;
1188
1189 if ( docHeadPosition( &dpHead, (BufferItem *)parentNode ) )
1190 { LDEB(1); return -1; }
1191
1192 *pAtExtremity= ( paraNode == dpHead.dpNode );
1193 }
1194
1195 return 0;
1196 }
1197
1198