1 /************************************************************************/
2 /* */
3 /* Get/Move/Set Selections. */
4 /* */
5 /************************************************************************/
6
7 # include "docBufConfig.h"
8
9 # include <appDebugon.h>
10
11 # include "docBuf.h"
12 # include "docNodeTree.h"
13 # include "docDebug.h"
14 # include "docParaString.h"
15 # include "docParaParticules.h"
16
17 /************************************************************************/
18 /* */
19 /* Move to the first/last position. */
20 /* */
21 /************************************************************************/
22
docGotoFirstPosition(DocumentPosition * dp,BufferItem * node)23 int docGotoFirstPosition( DocumentPosition * dp,
24 BufferItem * node )
25 {
26 while( node )
27 {
28 if ( node->biLevel == DOClevPARA )
29 {
30 docSetDocumentPosition( dp, node, docParaFirstStroff( node ) );
31 return 0;
32 }
33
34 if ( node->biChildCount == 0 )
35 { /*LDEB(node->biChildCount);*/ return -1; }
36
37 node= node->biChildren[0];
38 }
39
40 /*XDEB(node);*/ return -1;
41 }
42
docHeadPosition(DocumentPosition * dp,BufferItem * node)43 int docHeadPosition( DocumentPosition * dp,
44 BufferItem * node )
45 {
46 while( node )
47 {
48 if ( node->biLevel == DOClevPARA )
49 {
50 docSetDocumentPosition( dp, node, 0 );
51 return 0;
52 }
53
54 if ( node->biChildCount == 0 )
55 { /*LDEB(node->biChildCount);*/ return -1; }
56
57 node= node->biChildren[0];
58 }
59
60 /*XDEB(node);*/ return -1;
61 }
62
docGotoLastPosition(DocumentPosition * dp,BufferItem * node)63 int docGotoLastPosition( DocumentPosition * dp,
64 BufferItem * node )
65 {
66 while( node )
67 {
68 if ( node->biLevel == DOClevPARA )
69 {
70 docSetDocumentPosition( dp, node, docParaLastStroff( node ) );
71 return 0;
72 }
73
74 if ( node->biChildCount == 0 )
75 { /*LDEB(node->biChildCount);*/ return -1; }
76
77 node= node->biChildren[node->biChildCount- 1];
78 }
79
80 /*XDEB(node);*/ return -1;
81 }
82
docTailPosition(DocumentPosition * dp,BufferItem * node)83 int docTailPosition( DocumentPosition * dp,
84 BufferItem * node )
85 {
86 while( node )
87 {
88 if ( node->biLevel == DOClevPARA )
89 {
90 docSetDocumentPosition( dp, node, docParaStrlen( node ) );
91 return 0;
92 }
93
94 if ( node->biChildCount == 0 )
95 { /*LDEB(node->biChildCount);*/ return -1; }
96
97 node= node->biChildren[node->biChildCount- 1];
98 }
99
100 /*XDEB(node);*/ return -1;
101 }
102
docDocumentHead(DocumentPosition * dp,BufferDocument * bd)103 int docDocumentHead( DocumentPosition * dp,
104 BufferDocument * bd )
105 {
106 if ( docHeadPosition( dp, bd->bdBody.dtRoot ) )
107 { return -1; }
108
109 return 0;
110 }
111
docDocumentTail(DocumentPosition * dp,BufferDocument * bd)112 int docDocumentTail( DocumentPosition * dp,
113 BufferDocument * bd )
114 {
115 if ( docTailPosition( dp, bd->bdBody.dtRoot ) )
116 { return -1; }
117
118 return 0;
119 }
120
121 /************************************************************************/
122 /* */
123 /* Keep out the read-only field at the Head of certain kinds of */
124 /* paragraphs. */
125 /* */
126 /************************************************************************/
127
docAvoidParaHeadField(DocumentPosition * dp,int * pPart,const BufferDocument * bd)128 void docAvoidParaHeadField( DocumentPosition * dp,
129 int * pPart,
130 const BufferDocument * bd )
131 {
132 DocumentField * dfHead= (DocumentField *)0;
133 DocumentSelection dsInsideHead;
134 DocumentSelection dsAroundHead;
135 int partBegin= -1;
136 int partEnd= -1;
137
138 int fieldKind= docParaHeadFieldKind( dp->dpNode, bd );
139 if ( fieldKind < 0 )
140 { return; }
141
142 if ( docDelimitParaHeadField( &dfHead, &dsInsideHead, &dsAroundHead,
143 &partBegin, &partEnd, dp->dpNode, bd ) )
144 { LDEB(1); }
145 else{
146 if ( dp->dpStroff < dsAroundHead.dsTail.dpStroff )
147 { dp->dpStroff= dsAroundHead.dsTail.dpStroff; }
148
149 if ( pPart && *pPart <= partBegin )
150 { *pPart= partBegin+ 1; }
151 }
152
153 return;
154 }
155
156 /************************************************************************/
157 /* */
158 /* Move to the next/previous position. */
159 /* */
160 /************************************************************************/
161
162 # define docIsMergedCell( node ) ( \
163 (node)->biParent && \
164 docIsRowNode( (node)->biParent ) && \
165 (node)->biNumberInParent < (node)->biParent->biRowCellCount && \
166 CELL_MERGED( &( (node)->biParent->biRowCells[(node)->biNumberInParent] ) ) )
167
docNextNode(BufferItem * node,int level)168 static BufferItem * docNextNode( BufferItem * node,
169 int level )
170 {
171 for (;;)
172 {
173 if ( ! node->biParent )
174 { return (BufferItem *)0; }
175
176 if ( node->biNumberInParent < node->biParent->biChildCount- 1 )
177 {
178 node= node->biParent->biChildren[node->biNumberInParent+ 1];
179
180 if ( docIsMergedCell( node ) )
181 { continue; }
182
183 while( node->biLevel < level &&
184 node->biChildCount > 0 )
185 {
186 node= node->biChildren[0];
187
188 if ( docIsMergedCell( node ) )
189 { break; }
190 }
191
192 if ( docIsMergedCell( node ) )
193 { continue; }
194
195 if ( node->biLevel == level )
196 { return node; }
197 }
198 else{ node= node->biParent; }
199 }
200 }
201
docNextParagraph(BufferItem * node)202 BufferItem * docNextParagraph( BufferItem * node )
203 { return docNextNode( node, DOClevPARA ); }
204
docNextSection(BufferItem * node)205 BufferItem * docNextSection( BufferItem * node )
206 { return docNextNode( node, DOClevSECT ); }
207
docPrevNode(BufferItem * node,int level)208 static BufferItem * docPrevNode( BufferItem * node,
209 int level )
210 {
211 for (;;)
212 {
213 if ( ! node->biParent )
214 { return (BufferItem *)0; }
215
216 if ( node->biNumberInParent > 0 )
217 {
218 node= node->biParent->biChildren[node->biNumberInParent- 1];
219
220 if ( docIsMergedCell( node ) )
221 { continue; }
222
223 while( node->biLevel < level &&
224 node->biChildCount > 0 )
225 {
226 node= node->biChildren[node->biChildCount- 1];
227
228 if ( docIsMergedCell( node ) )
229 { break; }
230 }
231
232 if ( docIsMergedCell( node ) )
233 { continue; }
234
235 if ( node->biLevel == level )
236 { return node; }
237 }
238 else{ node= node->biParent; }
239 }
240 }
241
docPrevParagraph(BufferItem * node)242 BufferItem * docPrevParagraph( BufferItem * node )
243 { return docPrevNode( node, DOClevPARA ); }
244
docPrevSection(BufferItem * node)245 BufferItem * docPrevSection( BufferItem * node )
246 { return docPrevNode( node, DOClevSECT ); }
247
248 /************************************************************************/
249 /* */
250 /* Move to the Next/Previous word. */
251 /* */
252 /* 1) Words start after a particule ending in a space or at the */
253 /* beginning of a paragraph. */
254 /* */
255 /************************************************************************/
256
docNextWord(DocumentPosition * dp)257 int docNextWord( DocumentPosition * dp )
258 {
259 BufferItem * paraBi= dp->dpNode;
260 int stroff= dp->dpStroff;
261
262 if ( stroff == docParaStrlen( paraBi ) )
263 {
264 paraBi= docNextParagraph( paraBi );
265 if ( ! paraBi )
266 { return 1; }
267
268 stroff= 0;
269 }
270
271 stroff= docParaNextWord( paraBi, stroff );
272 docSetDocumentPosition( dp, paraBi, stroff );
273
274 return 0;
275 }
276
docPrevWord(DocumentPosition * dp)277 int docPrevWord( DocumentPosition * dp )
278 {
279 BufferItem * paraBi= dp->dpNode;
280 int stroff= dp->dpStroff;
281
282 if ( stroff == 0 )
283 {
284 paraBi= docPrevParagraph( paraBi );
285 if ( ! paraBi )
286 { return 1; }
287
288 stroff= docParaStrlen( paraBi );
289 }
290
291 stroff= docParaPrevWord( paraBi, stroff );
292 docSetDocumentPosition( dp, paraBi, stroff );
293
294 return 0;
295 }
296
297 /************************************************************************/
298 /* */
299 /* Move one line up. */
300 /* */
301 /* 1) Go to previous line of the paragraph or to the last line of the */
302 /* last paragraph before this one that has any lines. */
303 /* 2) In a clumsy attempt to implement vertical movement in tables, */
304 /* try to stay in the same column of a table. */
305 /* */
306 /************************************************************************/
307
docLineUp(int * pLine,DocumentPosition * dp,int line)308 int docLineUp( int * pLine,
309 DocumentPosition * dp,
310 int line )
311 {
312 TextLine * tl;
313 BufferItem * node= dp->dpNode;
314
315 line--;
316
317 /* 1 */
318 while( node )
319 {
320 if ( node->biParaLineCount == 0 )
321 { LLDEB(docNumberOfParagraph(node),node->biParaLineCount); }
322
323 if ( node->biLevel == DOClevPARA &&
324 line < node->biParaLineCount && /* against crashes */
325 line >= 0 )
326 {
327 tl= node->biParaLines+ line;
328
329 dp->dpNode= node;
330 dp->dpStroff= tl->tlStroff;
331
332 if ( pLine )
333 { *pLine= line; }
334 return 0;
335 }
336
337 /* 2 */
338 if ( node->biLevel == DOClevPARA &&
339 node->biParaTableNesting > 0 &&
340 node->biNumberInParent == 0 )
341 {
342 int col;
343 int row0;
344 int row;
345 int row1;
346
347 BufferItem * parentNode;
348
349 if ( docDelimitTable( node, &parentNode, &col, &row0, &row, &row1 ) )
350 { LDEB(1); return -1; }
351
352 if ( row > row0 )
353 {
354 BufferItem * rowNode= parentNode->biChildren[row-1];
355
356 if ( col < rowNode->biChildCount )
357 {
358 BufferItem * cellNode= rowNode->biChildren[col];
359
360 node= cellNode->biChildren[cellNode->biChildCount-1];
361 line= node->biParaLineCount- 1;
362 continue;
363 }
364 }
365 }
366
367 node= docPrevParagraph( node );
368 if ( ! node )
369 { break; }
370 line= node->biParaLineCount- 1;
371 }
372
373 return -1;
374 }
375
376 /************************************************************************/
377 /* */
378 /* Move one line down. */
379 /* */
380 /* 1) Go to the next line of the paragraph or to the first line of */
381 /* the first paragraph after this one that has any lines. */
382 /* 2) In a clumsy attempt to implement vertical movement in tables, */
383 /* try to stay in the same column of a table. */
384 /* */
385 /************************************************************************/
386
docLineDown(int * pLine,DocumentPosition * dp,int line)387 int docLineDown( int * pLine,
388 DocumentPosition * dp,
389 int line )
390 {
391 TextLine * tl;
392 BufferItem * node= dp->dpNode;
393
394 line++;
395
396 /* 1 */
397 while( node )
398 {
399 if ( node->biLevel == DOClevPARA &&
400 line < node->biParaLineCount &&
401 line >= 0 ) /* against crashes */
402 {
403 tl= node->biParaLines+ line;
404
405 dp->dpNode= node;
406 dp->dpStroff= tl->tlStroff;
407
408 if ( pLine )
409 { *pLine= line; }
410 return 0;
411 }
412
413 /* 2 */
414 if ( node->biLevel == DOClevPARA &&
415 node->biParaTableNesting > 0 &&
416 node->biNumberInParent == node->biParent->biChildCount- 1 )
417 {
418 int col;
419 int row0;
420 int row;
421 int row1;
422
423 BufferItem * parentNode;
424
425 if ( docDelimitTable( node, &parentNode, &col, &row0, &row, &row1 ) )
426 { LDEB(1); return -1; }
427
428 if ( row < row1 )
429 {
430 BufferItem * rowNode= parentNode->biChildren[row+1];
431
432 if ( col < rowNode->biChildCount )
433 {
434 BufferItem * cellNode= rowNode->biChildren[col];
435
436 node= cellNode->biChildren[0];
437 line= 0;
438 continue;
439 }
440 }
441 }
442
443 node= docNextParagraph( node );
444 line= 0;
445 }
446
447 return -1;
448 }
449
450 /************************************************************************/
451 /* */
452 /* Move to the beginning/end of a line */
453 /* */
454 /************************************************************************/
455
docLineHead(DocumentPosition * dp,int positionFlags)456 int docLineHead( DocumentPosition * dp,
457 int positionFlags )
458 {
459 int line;
460 int flags= 0;
461 const int lastOne= PARAfindFIRST;
462
463 if ( positionFlags & POSflagLINE_HEAD )
464 { return 0; }
465
466 if ( docFindLineOfPosition( &line, &flags, dp, lastOne ) )
467 { LDEB(dp->dpStroff); return -1; }
468
469 dp->dpStroff= dp->dpNode->biParaLines[line].tlStroff;
470
471 return 0;
472 }
473
docLineTail(DocumentPosition * dp,int positionFlags)474 int docLineTail( DocumentPosition * dp,
475 int positionFlags )
476 {
477 int line;
478 int flags= 0;
479 const int lastOne= PARAfindLAST;
480 const TextLine * tl;
481
482 if ( positionFlags & POSflagLINE_TAIL )
483 { return 0; }
484
485 if ( docFindLineOfPosition( &line, &flags, dp, lastOne ) )
486 { LDEB(dp->dpStroff); return -1; }
487
488 tl= &(dp->dpNode->biParaLines[line]);
489 dp->dpStroff= tl->tlStroff+ tl->tlStrlen;
490
491 return 0;
492 }
493
494 /************************************************************************/
495 /* */
496 /* Get buffer positions for a text line. */
497 /* */
498 /************************************************************************/
499
docLineSelection(DocumentSelection * dsLine,int * pPartLineBegin,int * pPartLineEnd,const BufferItem * node,int line)500 void docLineSelection( DocumentSelection * dsLine,
501 int * pPartLineBegin,
502 int * pPartLineEnd,
503 const BufferItem * node,
504 int line )
505 {
506 const TextLine * tl= node->biParaLines+ line;
507
508 if ( node->biLevel != DOClevPARA )
509 { LLDEB(node->biLevel,DOClevPARA); return; }
510 if ( line < 0 || line >= node->biParaLineCount )
511 { LLDEB(line,node->biParaLineCount); return; }
512
513 docInitDocumentSelection( dsLine );
514
515 dsLine->dsHead.dpNode= (BufferItem *)node;
516 dsLine->dsHead.dpStroff= tl->tlStroff;
517
518 dsLine->dsTail.dpNode= (BufferItem *)node;
519 dsLine->dsTail.dpStroff= tl->tlStroff+ tl->tlStrlen;
520
521 dsLine->dsAnchor= dsLine->dsHead;
522 dsLine->dsDirection= 1;
523
524 dsLine->dsCol0= dsLine->dsCol1= -1;
525
526 docSetSelectionScope( dsLine );
527
528 *pPartLineBegin= tl->tlFirstParticule;
529 *pPartLineEnd= tl->tlFirstParticule+ tl->tlParticuleCount- 1;
530
531 return;
532 }
533
534 /************************************************************************/
535 /* */
536 /* Delimit a 'Word' in the document. */
537 /* */
538 /* A 'Word' is one of the following: */
539 /* 1) A continguous stretch of text. It is not interrupted by either */
540 /* white space or control particules. Any white space after the */
541 /* word is included in the word. */
542 /* 2) An object or an image. */
543 /* */
544 /************************************************************************/
545
docWordSelection(DocumentSelection * dsWord,int * pIsObject,const DocumentPosition * dpAround)546 void docWordSelection( DocumentSelection * dsWord,
547 int * pIsObject,
548 const DocumentPosition * dpAround )
549 {
550 TextParticule * tp;
551
552 BufferItem * paraBi= dpAround->dpNode;
553 int part;
554
555 if ( paraBi->biLevel != DOClevPARA )
556 { LLDEB(paraBi->biLevel,DOClevPARA); return; }
557
558 if ( docFindParticuleOfPosition( &part, (int *)0,
559 dpAround, PARAfindLAST ) )
560 { LDEB(dpAround->dpStroff); return; }
561
562 tp= paraBi->biParaParticules+ part;
563 while( part < paraBi->biParaParticuleCount- 1 &&
564 tp->tpStroff+ tp->tpStrlen <= dpAround->dpStroff )
565 { tp++; part++; }
566
567 if ( tp->tpStroff == dpAround->dpStroff &&
568 part > 0 &&
569 tp[-1].tpKind == DOCkindOBJECT )
570 {
571 docSetParaSelection( dsWord, paraBi, 1,
572 tp[-1].tpStroff, tp[-1].tpStrlen );
573 *pIsObject= 1;
574 return;
575 }
576
577 if ( tp->tpKind == DOCkindOBJECT )
578 {
579 docSetParaSelection( dsWord, paraBi, 1, tp->tpStroff, tp->tpStrlen );
580 *pIsObject= 1;
581 return;
582 }
583 else{
584 int stroffHead;
585 int stroffTail;
586
587 docParaHeadOfWord( &stroffHead, paraBi, part );
588 docParaTailOfWord( &stroffTail, paraBi, part );
589
590 docSetParaSelection( dsWord, paraBi, 1,
591 stroffHead, stroffTail- stroffHead );
592 }
593
594 return;
595 }
596
597 /************************************************************************/
598 /* */
599 /* Translate a TableRectangle to a DocumentSelection. */
600 /* */
601 /************************************************************************/
602
docTableRectangleSelection(DocumentSelection * ds,BufferItem ** pSelParentBi,BufferDocument * bd,const TableRectangle * tr)603 int docTableRectangleSelection( DocumentSelection * ds,
604 BufferItem ** pSelParentBi,
605 BufferDocument * bd,
606 const TableRectangle * tr )
607 {
608 DocumentSelection dsNew;
609
610 BufferItem * selSectBi;
611 BufferItem * selParentBi;
612 BufferItem * rowNode;
613 BufferItem * cellNode;
614
615 docInitDocumentSelection( &dsNew );
616
617 /*******/
618
619 selParentBi= docGetSelectionRoot( (DocumentTree **)0, (BufferItem **)0,
620 bd, ds );
621 if ( ! selParentBi )
622 { XDEB(selParentBi); return -1; }
623
624 if ( selParentBi->biLevel == DOClevPARA )
625 { selParentBi= selParentBi->biParent; }
626 if ( selParentBi->biLevel == DOClevCELL )
627 { selParentBi= selParentBi->biParent; }
628 if ( selParentBi->biLevel == DOClevROW )
629 { selParentBi= selParentBi->biParent; }
630
631 selSectBi= docGetSectNode( selParentBi );
632 if ( ! selSectBi )
633 { XDEB(selSectBi); return -1; }
634
635 /*******/
636
637 if ( tr->trRow0 < 0 ||
638 tr->trRow0 >= selParentBi->biChildCount )
639 { LLDEB(tr->trRow0,selParentBi->biChildCount); return -1; }
640 rowNode= selParentBi->biChildren[tr->trRow0];
641
642 if ( tr->trCol0 < 0 ||
643 tr->trCol0 >= rowNode->biChildCount )
644 { LLDEB(tr->trCol0,rowNode->biChildCount); return -1; }
645 cellNode= rowNode->biChildren[tr->trCol0];
646
647 if ( docHeadPosition( &dsNew.dsHead, cellNode ) )
648 { LDEB(0); return -1; }
649
650 /*******/
651
652 if ( tr->trRow1 < 0 ||
653 tr->trRow1 >= selParentBi->biChildCount )
654 { LLDEB(tr->trRow0,selParentBi->biChildCount); return -1; }
655 rowNode= selParentBi->biChildren[tr->trRow1];
656
657 if ( tr->trCol1 < 0 ||
658 tr->trCol1 >= rowNode->biChildCount )
659 { LLDEB(tr->trCol1,rowNode->biChildCount); return -1; }
660 cellNode= rowNode->biChildren[tr->trCol1];
661
662 if ( docTailPosition( &dsNew.dsTail, cellNode ) )
663 { LDEB(0); return -1; }
664
665 /*******/
666
667 dsNew.dsCol0= tr->trCol0;
668 dsNew.dsCol1= tr->trCol1;
669 dsNew.dsDirection= 1;
670 dsNew.dsAnchor= dsNew.dsHead;
671
672 if ( tr->trRow1 < tr->trRow0 ||
673 ( tr->trRow1 == tr->trRow0 && tr->trCol1 < tr->trCol0 ) )
674 {
675 dsNew.dsDirection= -1;
676 dsNew.dsAnchor= dsNew.dsTail;
677 }
678
679 docSetSelectionScope( &dsNew );
680
681 *ds= dsNew;
682 *pSelParentBi= selParentBi;
683
684 return 0;
685 }
686
687 /************************************************************************/
688 /* */
689 /* Is the selection exactly an object? */
690 /* */
691 /************************************************************************/
692
docGetObjectSelection(const DocumentSelection * ds,const BufferDocument * bd,int * pPart,DocumentPosition * dpObject,InsertedObject ** pIo)693 int docGetObjectSelection( const DocumentSelection * ds,
694 const BufferDocument * bd,
695 int * pPart,
696 DocumentPosition * dpObject,
697 InsertedObject ** pIo )
698 {
699 if ( ds->dsHead.dpNode &&
700 ds->dsTail.dpNode == ds->dsHead.dpNode )
701 {
702 BufferItem * paraBi= ds->dsHead.dpNode;
703 int part;
704 TextParticule * tp;
705
706 if ( docFindParticuleOfPosition( &part, (int *)0,
707 &(ds->dsHead), PARAfindLAST ) )
708 { LDEB(ds->dsHead.dpStroff); return -1; }
709
710 tp= paraBi->biParaParticules+ part;
711
712 if ( tp->tpKind == DOCkindOBJECT &&
713 ds->dsHead.dpStroff == tp->tpStroff &&
714 ds->dsTail.dpStroff == tp->tpStroff+ tp->tpStrlen )
715 {
716 *pPart= part;
717 *dpObject= ds->dsHead;
718 *pIo= docGetObject( bd, tp->tpObjectNumber );
719
720 return 0;
721 }
722 }
723
724 return 1;
725 }
726
727 /************************************************************************/
728 /* */
729 /* Select the whole frame around a position. Make no difficulties if */
730 /* the position is not in a frame: simply select the neghbourhood that */
731 /* is not a frame. (Usually the whole cell.) */
732 /* */
733 /************************************************************************/
734
docSelectFrameOfPosition(DocumentSelection * ds,const DocumentPosition * dp)735 int docSelectFrameOfPosition( DocumentSelection * ds,
736 const DocumentPosition * dp )
737 {
738 BufferItem * cellNode;
739 int para0;
740 int para1;
741 int frameNumber;
742
743 DocumentPosition dpHead;
744 DocumentPosition dpTail;
745
746 const int direction= 1;
747
748 docInitDocumentPosition( &dpHead );
749 docInitDocumentPosition( &dpTail );
750
751 if ( ! dp->dpNode )
752 { XDEB(dp->dpNode); return 1; }
753
754 frameNumber= dp->dpNode->biParaFrameNumber;
755 cellNode= dp->dpNode->biParent;
756 para0= para1= dp->dpNode->biNumberInParent;
757
758 while( para0 > 0 )
759 {
760 if ( cellNode->biChildren[para0- 1]->biParaFrameNumber != frameNumber )
761 { break; }
762 para0--;
763 }
764
765 while( para1 < cellNode->biChildCount- 1 )
766 {
767 if ( cellNode->biChildren[para1+ 1]->biParaFrameNumber != frameNumber )
768 { break; }
769 para1++;
770 }
771
772 if ( docHeadPosition( &dpHead, cellNode->biChildren[para0] ) )
773 { LDEB(1); return 1; }
774 if ( docTailPosition( &dpTail, cellNode->biChildren[para1] ) )
775 { LDEB(1); return 1; }
776
777 docSetRangeSelection( ds, &dpHead, &dpTail, direction );
778
779 return 0;
780 }
781
782