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