1 /************************************************************************/
2 /*									*/
3 /*  Delimit tables and table rectangles.				*/
4 /*									*/
5 /************************************************************************/
6 
7 #   include	"docBufConfig.h"
8 
9 #   include	<appDebugon.h>
10 
11 #   include	"docBuf.h"
12 #   include	"docTreeNode.h"
13 #   include	"docNodeTree.h"
14 
15 /************************************************************************/
16 /*									*/
17 /*  Find the range of rows for a 'table'				*/
18 /*									*/
19 /************************************************************************/
20 
docDelimitTable(const BufferItem * paraNode,BufferItem ** pParentNode,int * pCol,int * pRow0,int * pRow,int * pRow1)21 int docDelimitTable(	const BufferItem *	paraNode,
22 			BufferItem **		pParentNode,
23 			int *			pCol,
24 			int *			pRow0,
25 			int *			pRow,
26 			int *			pRow1 )
27     {
28     BufferItem *	rowNode;
29     BufferItem *	parentNode;
30     int			col;
31 
32     if  ( paraNode->biLevel != DOClevPARA	||
33 	  paraNode->biParaTableNesting == 0	)
34 	{ /* LLDEB(paraNode->biLevel,paraNode->biParaInTable); */ return -1; }
35 
36     rowNode= paraNode->biParent->biParent;
37     parentNode= rowNode->biParent;
38     col= paraNode->biParent->biNumberInParent;
39 
40     if  ( pParentNode )
41 	{ *pParentNode= parentNode;		}
42     if  ( pCol )
43 	{ *pCol= col;				}
44     if  ( pRow0 )
45 	{ *pRow0= rowNode->biRowTableFirst;	}
46     if  ( pRow )
47 	{ *pRow= rowNode->biNumberInParent;	}
48     if  ( pRow1 )
49 	{ *pRow1= rowNode->biRowTablePast- 1;	}
50 
51     return 0;
52     }
53 
54 /************************************************************************/
55 /*									*/
56 /*  Determine the spans of a table cell.				*/
57 /*									*/
58 /************************************************************************/
59 
docGetCellBottom(LayoutPosition * lpBottom,const BufferItem * cellNode)60 int docGetCellBottom(		LayoutPosition *	lpBottom,
61 				const BufferItem *	cellNode )
62     {
63     const BufferItem *		rowNode= cellNode->biParent;
64     int				col= cellNode->biNumberInParent;
65     const BufferItem *		parentNode= rowNode->biParent;
66 
67     int				row0= rowNode->biNumberInParent;
68     int				rowp= rowNode->biRowTablePast;
69     const CellProperties *	cp= &(rowNode->biRowCells[col]);
70 
71     const LayoutPosition *	lpBelow= &(rowNode->biBelowPosition);
72 
73     int				rowspan= 1;
74 
75     if  ( cp->cpVerticalMerge == CELLmergeFOLLOW )
76 	{ rowspan= 0;	}
77     else{
78 	if  ( cp->cpVerticalMerge == CELLmergeHEAD )
79 	    {
80 	    int		nRow;
81 	    int		csp= 1;
82 	    int		l, r;
83 
84 	    if  ( col == 0 )
85 		{ l= rowNode->biRowLeftIndentTwips;	}
86 	    else{ l= cp[-1].cpRightBoundaryTwips;	}
87 	    r= docGetCellRight( &csp, cellNode );
88 
89 	    for ( nRow= row0+ 1; nRow < rowp; nRow++ )
90 		{
91 		int			ncsp= 1;
92 		const BufferItem *	nRowBi= parentNode->biChildren[nRow];
93 		int			nCol;
94 
95 		nCol= docGetMatchingCell( &ncsp, nRowBi, l, r );
96 		if  ( nCol < 0 )
97 		    { break;	}
98 
99 		if  ( nRowBi->biRowCells[nCol].cpVerticalMerge !=
100 							    CELLmergeFOLLOW )
101 		    { break;	}
102 
103 		lpBelow= &(nRowBi->biBelowPosition);
104 		rowspan++;
105 		}
106 	    }
107 	}
108 
109     if  ( lpBottom )
110 	{ *lpBottom= *lpBelow;	}
111 
112     return rowspan;
113     }
114 
docTableDetermineCellspans(int * pRowspan,int * pColspan,const BufferItem * cellNode)115 void docTableDetermineCellspans(	int *			pRowspan,
116 					int *			pColspan,
117 					const BufferItem *	cellNode )
118     {
119     const BufferItem *		rowNode= cellNode->biParent;
120     int				col= cellNode->biNumberInParent;
121 
122     const CellProperties *	cp= &(rowNode->biRowCells[col]);
123 
124     int				colspan= 1;
125     int				rowspan= 1;
126 
127     if  ( cp->cpHorizontalMerge == CELLmergeFOLLOW )
128 	{ colspan= 0;	}
129     else{
130 	if  ( cp->cpHorizontalMerge == CELLmergeHEAD )
131 	    { /* right= */ docGetCellRight( &colspan, cellNode );	}
132 	}
133 
134     rowspan= docGetCellBottom( (LayoutPosition *)0, cellNode );
135 
136     if  ( pRowspan )
137 	{ *pRowspan= rowspan;	}
138     if  ( pColspan )
139 	{ *pColspan= colspan;	}
140 
141     return;
142     }
143 
144 /************************************************************************/
145 /*									*/
146 /*  Determine the rectangular area as it is selected in a table.	*/
147 /*									*/
148 /*  This funtion fails if the whole selection is not inside ONE table.	*/
149 /*									*/
150 /*  1)  Find the table environment of the beginning of the selection.	*/
151 /*  2)  Find the table environment of the end of the selection.		*/
152 /*  3)  Different section -> Different table.				*/
153 /*  4)  Different begin or different end -> Different table.		*/
154 /*  5)  Paranoia checks.						*/
155 /*  6)  Delimit rectangle.						*/
156 /*  7)  If the selection is inside one cell determine its		*/
157 /*	colspan/rowspan.						*/
158 /*									*/
159 /************************************************************************/
160 
docGetTableRectangle(TableRectangle * tr,const DocumentSelection * ds)161 int docGetTableRectangle(	TableRectangle *		tr,
162 				const DocumentSelection *	ds )
163     {
164     BufferItem *	parentNode0;
165     BufferItem *	parentNode1;
166 
167     TableRectangle	trHead;
168     TableRectangle	trTail;
169 
170     /*  1  */
171     if  ( docDelimitTable( ds->dsHead.dpNode, &parentNode0,
172 						&(trHead.trCol0),
173 						&(trHead.trRow00),
174 						&(trHead.trRow0),
175 						&(trHead.trRow11) ) )
176 	{ /* LDEB(1); */ return 1;	}
177 
178     /*  2  */
179     if  ( docDelimitTable( ds->dsTail.dpNode, &parentNode1,
180 						&(trTail.trCol0),
181 						&(trTail.trRow00),
182 						&(trTail.trRow0),
183 						&(trTail.trRow11) ) )
184 	{ /* LDEB(1); */ return 1;	}
185 
186     /*  3  */
187     if  ( parentNode0 != parentNode1 )
188 	{ /* XXDEB(parentNode0,parentNode1); */ return 1;	}
189 
190     /*  4  */
191     if  ( trHead.trRow00 != trTail.trRow00	||
192 	  trHead.trRow11 != trTail.trRow11	)
193 	{ return 1;	}
194 
195     /*  5  */
196     if  ( trHead.trCol0 > trTail.trCol0 )
197 	{ return 1;	}
198     if  ( trHead.trRow0 > trTail.trRow0 )
199 	{ return 1;	}
200 
201     /*  6  */
202     tr->trCol0= trHead.trCol0;
203     tr->trCol1= trTail.trCol0;
204     tr->trCol11= parentNode0->biChildren[trHead.trRow0]->biChildCount- 1;
205 
206     tr->trRow00= trHead.trRow00;
207     tr->trRow0= trHead.trRow0;
208     tr->trRow1= trTail.trRow0;
209     tr->trRow11= trHead.trRow11;
210 
211     tr->trCellColspan= 0;
212     tr->trCellRowspan= 0;
213 
214     tr->trIsSingleCell= (	tr->trRow0 == tr->trRow1	&&
215 				tr->trCol0 == tr->trCol1	);
216 
217     tr->trIsColSlice= (		tr->trRow0 == tr->trRow00	&&
218     				tr->trRow1 == tr->trRow11	);
219 
220     tr->trIsRowSlice= (		tr->trCol0 == 0			&&
221 				tr->trCol1 == tr->trCol11	);
222 
223     tr->trIsTableSlice= tr->trIsColSlice || tr->trIsRowSlice;
224     tr->trIsWholeTable= tr->trIsColSlice && tr->trIsRowSlice;
225 
226     /*  7  */
227     if  ( tr->trIsSingleCell )
228 	{
229 	const BufferItem *	rowNode0= parentNode0->biChildren[trHead.trRow0];
230 	const BufferItem *	cellNode0= rowNode0->biChildren[tr->trCol0];
231 
232 	docTableDetermineCellspans(
233 			&(tr->trCellRowspan), &(tr->trCellColspan), cellNode0 );
234 	}
235 
236     tr->trInTableHeader=
237 		parentNode0->biChildren[trHead.trRow0]->biRowIsTableHeader;
238 
239     return 0;
240     }
241 
242 /************************************************************************/
243 /*									*/
244 /*  Delimit the tables in a section.					*/
245 /*									*/
246 /************************************************************************/
247 
docDelimitTables(BufferItem * parentNode,int recursively)248 void docDelimitTables(	BufferItem *		parentNode,
249 			int			recursively )
250     {
251     int		n;
252     int		headerRow= -1;
253 
254     n= 0;
255     while( n < parentNode->biChildCount )
256 	{
257 	BufferItem *	rowNodeFirst;
258 	BufferItem *	rowNode;
259 
260 	int		first;
261 	int		past;
262 
263 	rowNodeFirst= parentNode->biChildren[n];
264 	if  ( ! docIsRowNode( rowNodeFirst ) )
265 	    {
266 	    if  ( recursively && rowNodeFirst->biLevel != DOClevPARA )
267 		{ docDelimitTables( rowNodeFirst, recursively );	}
268 
269 	    if  ( rowNodeFirst->biLevel == DOClevROW )
270 		{
271 		rowNodeFirst->biRowTableHeaderRow= -1;
272 		rowNodeFirst->biRowTableFirst= -1;
273 		rowNodeFirst->biRowTablePast= -1;
274 		}
275 
276 	    headerRow= -1;
277 	    n++; continue;
278 	    }
279 
280 	first= n;
281 	past= n+ 1;
282 
283 	while( past < parentNode->biChildCount )
284 	    {
285 	    rowNode= parentNode->biChildren[past];
286 
287 	    if  ( ! docIsRowNode( rowNode ) )
288 		{ break;	}
289 
290 	    /*
291 	    if  ( ! docApproximatelyAlignedColumns(
292 					&(rowNodeFirst->biRowProperties),
293 					&(rowNode->biRowProperties) )	)
294 		{ break;	}
295 	    */
296 
297 	    past++;
298 	    }
299 
300 	while( n < past )
301 	    {
302 	    rowNode= parentNode->biChildren[n];
303 
304 	    if  ( recursively && rowNode->biLevel != DOClevPARA )
305 		{ docDelimitTables( rowNode, recursively );	}
306 
307 	    if  ( rowNode->biRowIsTableHeader )
308 		{ headerRow= n;	}
309 
310 	    rowNode->biRowTableHeaderRow= headerRow;
311 	    rowNode->biRowTableFirst= first;
312 	    rowNode->biRowTablePast= past;
313 
314 	    n++;
315 	    }
316 	}
317 
318     return;
319     }
320 
321 /************************************************************************/
322 /*									*/
323 /*  Get colspan and right border of a cell.				*/
324 /*									*/
325 /************************************************************************/
326 
docGetCellRight(int * pColspan,const BufferItem * cellNode)327 int docGetCellRight(	int *			pColspan,
328 			const BufferItem *	cellNode )
329     {
330     const BufferItem *	rowNode= cellNode->biParent;
331     int			col= cellNode->biNumberInParent;
332 
333     return docCellRight( pColspan, &(rowNode->biRowProperties), col );
334     }
335 
336 /************************************************************************/
337 /*									*/
338 /*  Find the cell with left and right borders as given.			*/
339 /*									*/
340 /************************************************************************/
341 
docGetMatchingCell(int * pColspan,const BufferItem * rowNode,int l,int r)342 int docGetMatchingCell(		int *			pColspan,
343 				const BufferItem *	rowNode,
344 				int			l,
345 				int			r )
346     {
347     int				col;
348     int				ll, rr;
349     const CellProperties *	cp;
350 
351     if  ( rowNode->biLevel != DOClevROW )
352 	{ SDEB(docLevelStr(rowNode->biLevel)); return -1;	}
353 
354     /*  2  */
355     rr= rowNode->biRowLeftIndentTwips;
356     cp= rowNode->biRowCells;
357     for ( col= 0; col < rowNode->biChildCount; cp++, col++ )
358 	{
359 	int		colspan= 1;
360 
361 	if  ( cp->cpHorizontalMerge == CELLmergeFOLLOW )
362 	    { continue;	}
363 
364 	ll= rr; rr= cp->cpRightBoundaryTwips;
365 	if  ( cp->cpHorizontalMerge == CELLmergeHEAD )
366 	    { rr= docGetCellRight( &colspan, rowNode->biChildren[col] ); }
367 
368 	if  ( ll == l && rr == r )
369 	    { *pColspan= colspan; return col;	}
370 	}
371 
372     return -1;
373     }
374 
375 /************************************************************************/
376 /*									*/
377 /*  Get the cell and row properties for a node.				*/
378 /*									*/
379 /************************************************************************/
380 
docGetCellProperties(const RowProperties ** pRp,const BufferItem * cellNode)381 const CellProperties *	docGetCellProperties(
382 					const RowProperties **	pRp,
383 					const BufferItem *	cellNode )
384     {
385     const BufferItem *		rowNode= cellNode->biParent;
386     const RowProperties *	rp= &(rowNode->biRowProperties);
387     int				col= cellNode->biNumberInParent;
388     const CellProperties *	cp= &(rp->rpCells[col]);
389 
390     if  ( ! docIsRowNode( rowNode ) )
391 	{
392 	SSDEB(docLevelStr(rowNode->biLevel),docLevelStr(cellNode->biLevel));
393 	return (const CellProperties *)0;
394 	}
395 
396     if  ( pRp )
397 	{ *pRp= rp;	}
398 
399     return cp;
400     }
401 
docAvoidMergedTail(DocumentSelection * dsNew,EditRange * er)402 void docAvoidMergedTail(	DocumentSelection *	dsNew,
403 				EditRange *		er )
404     {
405     BufferItem *	cellNode= docGetCellNode( dsNew->dsTail.dpNode );
406 
407     if  ( cellNode )
408 	{
409 	const RowProperties *	rp;
410 	const CellProperties *	cp;
411 
412 	cp= docGetCellProperties( &rp, cellNode );
413 	if  ( cp && CELL_MERGED( cp ) )
414 	    {
415 	    cellNode= docGetCellNode( dsNew->dsHead.dpNode );
416 
417 	    if  ( docSetNodeSelection( dsNew, cellNode ) )
418 		{ LDEB(1);				}
419 	    else{ docSetEditRange( er, dsNew );	}
420 	    }
421 	}
422 
423     return;
424     }
425 
426 /************************************************************************/
427 /*									*/
428 /*  Save cell properties that are representative for the cells in a	*/
429 /*  table rectangle. Typically, that is the properties of the		*/
430 /*  upper-left cell. For a bigger rectangle, the borders are adapted	*/
431 /*  to those on the outside of the rectangle.				*/
432 /*									*/
433 /************************************************************************/
434 
docSetCellRectangleProperties(CellProperties * cpSet,const BufferItem * rowNode,const TableRectangle * tr,const DocumentAttributeMap * dam)435 void docSetCellRectangleProperties(	CellProperties *		cpSet,
436 					const BufferItem *		rowNode,
437 					const TableRectangle *		tr,
438 					const DocumentAttributeMap *	dam )
439     {
440     const RowProperties *	rp= &(rowNode->biRowProperties);
441 
442     if  ( docCopyCellProperties( cpSet, &(rp->rpCells[tr->trCol0]), dam ) )
443 	{ LDEB(1); return;	}
444 
445     if  ( tr->trCol1 > tr->trCol0 )
446 	{
447 	int	fromNumber= rp->rpCells[tr->trCol1].cpRightBorderNumber;
448 
449 	if  ( fromNumber >= 0 && dam && dam->damBorderMap )
450 	    { fromNumber= dam->damBorderMap[fromNumber];	}
451 
452 	cpSet->cpRightBorderNumber= fromNumber;
453 	}
454 
455     if  ( tr->trRow1 > tr->trRow0 )
456 	{
457 	const RowProperties *	rp1;
458 	int 			fromNumber;
459 
460 	rp1= &(rowNode->biParent->biChildren[tr->trRow1]->biRowProperties);
461 
462 	fromNumber= rp1->rpCells[tr->trCol0].cpBottomBorderNumber;
463 	if  ( fromNumber >= 0 && dam && dam->damBorderMap )
464 	    { fromNumber= dam->damBorderMap[fromNumber];	}
465 
466 	cpSet->cpBottomBorderNumber= fromNumber;
467 	}
468 
469     return;
470     }
471 
472