LibreOffice Module svx (master)  1
tablelayouter.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 
21 #include <com/sun/star/table/XMergeableCell.hpp>
22 
23 #include <tools/debug.hxx>
24 #include <tools/gen.hxx>
25 #include <libxml/xmlwriter.h>
26 
27 #include <cell.hxx>
28 #include "cellrange.hxx"
29 #include <o3tl/safeint.hxx>
30 #include <tablemodel.hxx>
31 #include "tablerow.hxx"
32 #include "tablerows.hxx"
33 #include "tablecolumn.hxx"
34 #include "tablecolumns.hxx"
35 #include "tablelayouter.hxx"
36 #include <svx/svdotable.hxx>
37 #include <editeng/borderline.hxx>
38 #include <editeng/boxitem.hxx>
39 #include <svx/svdmodel.hxx>
40 
41 using ::editeng::SvxBorderLine;
42 using namespace ::com::sun::star::uno;
43 using namespace ::com::sun::star::lang;
44 using namespace ::com::sun::star::container;
45 using namespace ::com::sun::star::beans;
46 using namespace ::com::sun::star::table;
47 using namespace ::com::sun::star::text;
48 
49 
50 namespace sdr { namespace table {
51 
52 
53 static SvxBorderLine gEmptyBorder;
54 
55 static const OUStringLiteral gsSize( "Size" );
56 
58 : mxTable( xTableModel )
59 {
60 }
61 
62 
64 {
66 }
67 
68 
69 basegfx::B2ITuple TableLayouter::getCellSize( const CellRef& xCell, const CellPos& rPos ) const
70 {
71  sal_Int32 width = 0;
72  sal_Int32 height = 0;
73 
74  try
75  {
76  if( xCell.is() && !xCell->isMerged() )
77  {
78  CellPos aPos( rPos );
79 
80  sal_Int32 nRowCount = getRowCount();
81  sal_Int32 nRowSpan = std::max( xCell->getRowSpan(), sal_Int32(1) );
82  while( nRowSpan && (aPos.mnRow < nRowCount) )
83  {
84  if( static_cast<sal_Int32>(maRows.size()) <= aPos.mnRow )
85  break;
86 
87  height = o3tl::saturating_add(height, maRows[aPos.mnRow++].mnSize);
88  nRowSpan--;
89  }
90 
91  sal_Int32 nColCount = getColumnCount();
92  sal_Int32 nColSpan = std::max( xCell->getColumnSpan(), sal_Int32(1) );
93  while( nColSpan && (aPos.mnCol < nColCount ) )
94  {
95  if( static_cast<sal_Int32>(maColumns.size()) <= aPos.mnCol )
96  break;
97 
98  width = o3tl::saturating_add(width, maColumns[aPos.mnCol++].mnSize);
99  nColSpan--;
100  }
101  }
102  }
103  catch( Exception& )
104  {
105  OSL_FAIL( "TableLayouter::getCellSize(), exception caught!" );
106  }
107 
108  return basegfx::B2ITuple( width, height );
109 }
110 
111 
112 bool TableLayouter::getCellArea( const CellRef& xCell, const CellPos& rPos, basegfx::B2IRectangle& rArea ) const
113 {
114  try
115  {
116  if( xCell.is() && !xCell->isMerged() && isValid(rPos) )
117  {
118  const basegfx::B2ITuple aCellSize( getCellSize( xCell, rPos ) );
119  const bool bRTL = (mxTable->getSdrTableObj()->GetWritingMode() == WritingMode_RL_TB);
120 
121  if( (rPos.mnCol < static_cast<sal_Int32>(maColumns.size())) && (rPos.mnRow < static_cast<sal_Int32>(maRows.size()) ) )
122  {
123  const sal_Int32 y = maRows[rPos.mnRow].mnPos;
124 
125  sal_Int32 endy;
126  if (o3tl::checked_add(y, aCellSize.getY(), endy))
127  return false;
128 
129  if(bRTL)
130  {
132  const sal_Int32 x = maColumns[rPos.mnCol].mnPos + maColumns[rPos.mnCol].mnSize;
133  sal_Int32 startx;
134  if (o3tl::checked_sub(x, aCellSize.getX(), startx))
135  return false;
136  rArea = basegfx::B2IRectangle(startx, y, x, endy);
137  }
138  else
139  {
140  const sal_Int32 x = maColumns[rPos.mnCol].mnPos;
141  sal_Int32 endx;
142  if (o3tl::checked_add(x, aCellSize.getX(), endx))
143  return false;
144  rArea = basegfx::B2IRectangle(x, y, endx, endy);
145  }
146  return true;
147  }
148  }
149  }
150  catch( Exception& )
151  {
152  OSL_FAIL( "TableLayouter::getCellSize(), exception caught!" );
153  }
154  return false;
155 }
156 
157 
158 sal_Int32 TableLayouter::getRowHeight( sal_Int32 nRow ) const
159 {
160  if( isValidRow(nRow) )
161  return maRows[nRow].mnSize;
162  else
163  return 0;
164 }
165 
166 
167 sal_Int32 TableLayouter::getColumnWidth( sal_Int32 nColumn ) const
168 {
169  if( isValidColumn(nColumn) )
170  return maColumns[nColumn].mnSize;
171  else
172  return 0;
173 }
174 
175 sal_Int32 TableLayouter::calcPreferredColumnWidth( sal_Int32 nColumn, Size aSize ) const
176 {
177  sal_Int32 nRet = 0;
178  for ( sal_uInt32 nRow = 0; nRow < static_cast<sal_uInt32>(maRows.size()); ++nRow )
179  {
180  // Account for the space desired by spanned columns.
181  // Only the last spanned cell will try to ensure sufficient space,
182  // by looping through the previous columns, subtracting their portion.
183  sal_Int32 nWish = 0;
184  sal_Int32 nSpannedColumn = nColumn;
185  bool bFindSpan = true;
186  while ( bFindSpan && isValidColumn(nSpannedColumn) )
187  {
188  // recursive function call gets earlier portion of spanned column.
189  if ( nSpannedColumn < nColumn )
190  nWish -= calcPreferredColumnWidth( nSpannedColumn, aSize );
191 
192  CellRef xCell( getCell( CellPos( nSpannedColumn, nRow ) ) );
193  if ( xCell.is() && !xCell->isMerged()
194  && (xCell->getColumnSpan() == 1 || nSpannedColumn < nColumn) )
195  {
196  nWish += xCell->calcPreferredWidth(aSize);
197  bFindSpan = false;
198  }
199  else if ( xCell.is() && xCell->isMerged()
200  && nColumn == nSpannedColumn
201  && isValidColumn(nColumn + 1) )
202  {
203  xCell = getCell( CellPos( nColumn + 1, nRow ) );
204  bFindSpan = xCell.is() && !xCell->isMerged();
205  }
206  nSpannedColumn--;
207  }
208  nRet = std::max( nRet, nWish );
209  }
210  return nRet;
211 }
212 
213 
214 bool TableLayouter::isEdgeVisible( sal_Int32 nEdgeX, sal_Int32 nEdgeY, bool bHorizontal ) const
215 {
216  const BorderLineMap& rMap = bHorizontal ? maHorizontalBorders : maVerticalBorders;
217 
218  if( (nEdgeX >= 0) && (nEdgeX < sal::static_int_cast<sal_Int32>(rMap.size())) &&
219  (nEdgeY >= 0) && (nEdgeY < sal::static_int_cast<sal_Int32>(rMap[nEdgeX].size())) )
220  {
221  return rMap[nEdgeX][nEdgeY] != nullptr;
222  }
223  else
224  {
225  OSL_FAIL( "sdr::table::TableLayouter::getBorderLine(), invalid edge!" );
226  }
227 
228  return false;
229 }
230 
231 
233 SvxBorderLine* TableLayouter::getBorderLine( sal_Int32 nEdgeX, sal_Int32 nEdgeY, bool bHorizontal )const
234 {
235  SvxBorderLine* pLine = nullptr;
236 
237  const BorderLineMap& rMap = bHorizontal ? maHorizontalBorders : maVerticalBorders;
238 
239  if( (nEdgeX >= 0) && (nEdgeX < sal::static_int_cast<sal_Int32>(rMap.size())) &&
240  (nEdgeY >= 0) && (nEdgeY < sal::static_int_cast<sal_Int32>(rMap[nEdgeX].size())) )
241  {
242  pLine = rMap[nEdgeX][nEdgeY];
243  if( pLine == &gEmptyBorder )
244  pLine = nullptr;
245  }
246  else
247  {
248  OSL_FAIL( "sdr::table::TableLayouter::getBorderLine(), invalid edge!" );
249  }
250 
251  return pLine;
252 }
253 
254 std::vector<EdgeInfo> TableLayouter::getHorizontalEdges()
255 {
256  std::vector<EdgeInfo> aReturn;
257  sal_Int32 nRowSize = sal_Int32(maRows.size());
258  for (sal_Int32 i = 0; i <= nRowSize; i++)
259  {
260  sal_Int32 nEdgeMin = 0;
261  sal_Int32 nEdgeMax = 0;
262  sal_Int32 nEdge = getHorizontalEdge(i, &nEdgeMin, &nEdgeMax);
263  nEdgeMin -= nEdge;
264  nEdgeMax -= nEdge;
265  aReturn.emplace_back(i, nEdge, nEdgeMin, nEdgeMax);
266  }
267  return aReturn;
268 }
269 
270 std::vector<EdgeInfo> TableLayouter::getVerticalEdges()
271 {
272  std::vector<EdgeInfo> aReturn;
273  sal_Int32 nColumnSize = sal_Int32(maColumns.size());
274  for (sal_Int32 i = 0; i <= nColumnSize; i++)
275  {
276  sal_Int32 nEdgeMin = 0;
277  sal_Int32 nEdgeMax = 0;
278  sal_Int32 nEdge = getVerticalEdge(i, &nEdgeMin, &nEdgeMax);
279  nEdgeMin -= nEdge;
280  nEdgeMax -= nEdge;
281  aReturn.emplace_back(i, nEdge, nEdgeMin, nEdgeMax);
282  }
283  return aReturn;
284 }
285 
286 sal_Int32 TableLayouter::getHorizontalEdge( int nEdgeY, sal_Int32* pnMin /*= 0*/, sal_Int32* pnMax /*= 0*/ )
287 {
288  sal_Int32 nRet = 0;
289  const sal_Int32 nRowCount = getRowCount();
290  if( (nEdgeY >= 0) && (nEdgeY <= nRowCount ) )
291  nRet = maRows[std::min(static_cast<sal_Int32>(nEdgeY),nRowCount-1)].mnPos;
292 
293  if( nEdgeY == nRowCount )
294  nRet += maRows[nEdgeY - 1].mnSize;
295 
296  if( pnMin )
297  {
298  if( (nEdgeY > 0) && (nEdgeY <= nRowCount ) )
299  {
300  *pnMin = maRows[nEdgeY-1].mnPos + 600; // todo
301  }
302  else
303  {
304  *pnMin = nRet;
305  }
306  }
307 
308  if( pnMax )
309  {
310  *pnMax = 0x0fffffff;
311  }
312  return nRet;
313 }
314 
315 
316 sal_Int32 TableLayouter::getVerticalEdge( int nEdgeX, sal_Int32* pnMin /*= 0*/, sal_Int32* pnMax /*= 0*/ )
317 {
318  sal_Int32 nRet = 0;
319 
320  const sal_Int32 nColCount = getColumnCount();
321  if( (nEdgeX >= 0) && (nEdgeX <= nColCount ) )
322  nRet = maColumns[std::min(static_cast<sal_Int32>(nEdgeX),nColCount-1)].mnPos;
323 
324  const bool bRTL = (mxTable->getSdrTableObj()->GetWritingMode() == WritingMode_RL_TB);
325  if( bRTL )
326  {
327  if( (nEdgeX >= 0) && (nEdgeX < nColCount) )
328  nRet += maColumns[nEdgeX].mnSize;
329  }
330  else
331  {
332  if( nEdgeX == nColCount )
333  nRet += maColumns[nEdgeX - 1].mnSize;
334  }
335 
336  if( pnMin )
337  {
338  *pnMin = nRet;
339  if( bRTL )
340  {
341  if( nEdgeX < nColCount )
342  *pnMin = nRet - maColumns[nEdgeX].mnSize + getMinimumColumnWidth(nEdgeX);
343  }
344  else
345  {
346  if( (nEdgeX > 0) && (nEdgeX <= nColCount ) )
347  *pnMin = maColumns[nEdgeX-1].mnPos + getMinimumColumnWidth( nEdgeX-1 );
348  }
349  }
350 
351  if( pnMax )
352  {
353  *pnMax = 0x0fffffff; // todo
354  if( bRTL )
355  {
356  if( nEdgeX > 0 )
357  *pnMax = nRet + maColumns[nEdgeX-1].mnSize - getMinimumColumnWidth( nEdgeX-1 );
358  }
359  else
360  {
361  if( (nEdgeX >= 0) && (nEdgeX < nColCount ) )
362  *pnMax = maColumns[nEdgeX].mnPos + maColumns[nEdgeX].mnSize - getMinimumColumnWidth( nEdgeX );
363  }
364  }
365 
366  return nRet;
367 }
368 
369 
370 static bool checkMergeOrigin( const TableModelRef& xTable, sal_Int32 nMergedX, sal_Int32 nMergedY, sal_Int32 nCellX, sal_Int32 nCellY, bool& bRunning )
371 {
372  Reference< XMergeableCell > xCell( xTable->getCellByPosition( nCellX, nCellY ), UNO_QUERY );
373  if( xCell.is() && !xCell->isMerged() )
374  {
375  const sal_Int32 nRight = xCell->getColumnSpan() + nCellX;
376  const sal_Int32 nBottom = xCell->getRowSpan() + nCellY;
377  if( (nMergedX < nRight) && (nMergedY < nBottom) )
378  return true;
379 
380  bRunning = false;
381  }
382  return false;
383 }
384 
388 bool findMergeOrigin( const TableModelRef& xTable, sal_Int32 nMergedX, sal_Int32 nMergedY, sal_Int32& rOriginX, sal_Int32& rOriginY )
389 {
390  rOriginX = nMergedX;
391  rOriginY = nMergedY;
392 
393  if( xTable.is() ) try
394  {
395  // check if this cell already the origin or not merged at all
396  Reference< XMergeableCell > xCell( xTable->getCellByPosition( nMergedX, nMergedY ), UNO_QUERY_THROW );
397  if( !xCell->isMerged() )
398  return true;
399 
400  bool bCheckVert = true;
401  bool bCheckHorz = true;
402 
403  sal_Int32 nMinCol = 0;
404  sal_Int32 nMinRow = 0;
405 
406  sal_Int32 nStep = 1, i;
407 
408  sal_Int32 nRow, nCol;
409  do
410  {
411  if( bCheckVert )
412  {
413  nRow = nMergedY - nStep;
414  if( nRow >= nMinRow )
415  {
416  nCol = nMergedX;
417  for( i = 0; (i <= nStep) && (nCol >= nMinCol); i++, nCol-- )
418  {
419  if( checkMergeOrigin( xTable, nMergedX, nMergedY, nCol, nRow, bCheckVert ) )
420  {
421  rOriginX = nCol; rOriginY = nRow;
422  return true;
423  }
424 
425  if( !bCheckVert )
426  {
427  if( nCol == nMergedX )
428  {
429  nMinRow = nRow+1;
430  }
431  else
432  {
433  bCheckVert = true;
434  }
435  break;
436  }
437  }
438  }
439  else
440  {
441  bCheckVert = false;
442  }
443  }
444 
445  if( bCheckHorz )
446  {
447  nCol = nMergedX - nStep;
448  if( nCol >= nMinCol )
449  {
450  nRow = nMergedY;
451  for( i = 0; (i < nStep) && (nRow >= nMinRow); i++, nRow-- )
452  {
453  if( checkMergeOrigin( xTable, nMergedX, nMergedY, nCol, nRow, bCheckHorz ) )
454  {
455  rOriginX = nCol; rOriginY = nRow;
456  return true;
457  }
458 
459  if( !bCheckHorz )
460  {
461  if( nRow == nMergedY )
462  {
463  nMinCol = nCol+1;
464  }
465  else
466  {
467  bCheckHorz = true;
468  }
469  break;
470  }
471  }
472  }
473  else
474  {
475  bCheckHorz = false;
476  }
477  }
478  nStep++;
479  }
480  while( bCheckVert || bCheckHorz );
481  }
482  catch( Exception& )
483  {
484  OSL_FAIL("sdr::table::TableLayouter::findMergeOrigin(), exception caught!");
485  }
486  return false;
487 }
488 
489 
490 sal_Int32 TableLayouter::getMinimumColumnWidth( sal_Int32 nColumn )
491 {
492  if( isValidColumn( nColumn ) )
493  {
494  return maColumns[nColumn].mnMinSize;
495  }
496  else
497  {
498  OSL_FAIL( "TableLayouter::getMinimumColumnWidth(), column out of range!" );
499  return 0;
500  }
501 }
502 
503 
504 sal_Int32 TableLayouter::distribute( LayoutVector& rLayouts, sal_Int32 nDistribute )
505 {
506  // break loops after 100 runs to avoid freezing office due to developer error
507  sal_Int32 nSafe = 100;
508 
509  const std::size_t nCount = rLayouts.size();
510  std::size_t nIndex;
511 
512  bool bConstrainsBroken = false;
513 
514  do
515  {
516  bConstrainsBroken = false;
517 
518  // first enforce minimum size constrains on all entities
519  for( nIndex = 0; nIndex < nCount; ++nIndex )
520  {
521  Layout& rLayout = rLayouts[nIndex];
522  if( rLayout.mnSize < rLayout.mnMinSize )
523  {
524  sal_Int32 nDiff(0);
525  bConstrainsBroken |= o3tl::checked_sub(rLayout.mnMinSize, rLayout.mnSize, nDiff);
526  bConstrainsBroken |= o3tl::checked_sub(nDistribute, nDiff, nDistribute);
527  rLayout.mnSize = rLayout.mnMinSize;
528  }
529  }
530 
531  // calculate current width
532  // if nDistribute is < 0 (shrinking), entities that are already
533  // at minimum width are not counted
534  sal_Int32 nCurrentWidth = 0;
535  for( nIndex = 0; nIndex < nCount; ++nIndex )
536  {
537  Layout& rLayout = rLayouts[nIndex];
538  if( (nDistribute > 0) || (rLayout.mnSize > rLayout.mnMinSize) )
539  nCurrentWidth = o3tl::saturating_add(nCurrentWidth, rLayout.mnSize);
540  }
541 
542  // now distribute over entities
543  if( (nCurrentWidth != 0) && (nDistribute != 0) )
544  {
545  sal_Int32 nDistributed = nDistribute;
546  for( nIndex = 0; nIndex < nCount; ++nIndex )
547  {
548  Layout& rLayout = rLayouts[nIndex];
549  if( (nDistribute > 0) || (rLayout.mnSize > rLayout.mnMinSize) )
550  {
551  sal_Int32 n(nDistributed); // for last entity use up rest
552  if (nIndex != (nCount-1))
553  {
554  bConstrainsBroken |= o3tl::checked_multiply(nDistribute, rLayout.mnSize, n);
555  n /= nCurrentWidth;
556  }
557 
558  bConstrainsBroken |= o3tl::checked_add(rLayout.mnSize, n, rLayout.mnSize);
559  nDistributed -= n;
560 
561  if( rLayout.mnSize < rLayout.mnMinSize )
562  bConstrainsBroken = true;
563  }
564  }
565  }
566  } while( bConstrainsBroken && --nSafe );
567 
568  sal_Int32 nSize = 0;
569  for( nIndex = 0; nIndex < nCount; ++nIndex )
570  nSize = o3tl::saturating_add(nSize, rLayouts[nIndex].mnSize);
571 
572  return nSize;
573 }
574 
575 
576 typedef std::vector< CellRef > MergeableCellVector;
577 typedef std::vector< MergeableCellVector > MergeVector;
578 
579 
581 {
582  const sal_Int32 nColCount = getColumnCount();
583  const sal_Int32 nRowCount = getRowCount();
584  if( nColCount == 0 )
585  return;
586 
587  MergeVector aMergedCells( nColCount );
588  std::vector<sal_Int32> aOptimalColumns;
589 
590  const OUString sOptimalSize("OptimalSize");
591 
592  if( sal::static_int_cast< sal_Int32 >( maColumns.size() ) != nColCount )
593  maColumns.resize( nColCount );
594 
595  Reference< XTableColumns > xCols( mxTable->getColumns(), UNO_SET_THROW );
596 
597  // first calculate current width and initial minimum width per column,
598  // merged cells will be counted later
599  sal_Int32 nCurrentWidth = 0;
600  sal_Int32 nCol = 0, nRow = 0;
601  for( nCol = 0; nCol < nColCount; nCol++ )
602  {
603  sal_Int32 nMinWidth = 0;
604 
605  bool bIsEmpty = true; // check if all cells in this column are merged
606 
607  for( nRow = 0; nRow < nRowCount; ++nRow )
608  {
609  CellRef xCell( getCell( CellPos( nCol, nRow ) ) );
610  if( xCell.is() && !xCell->isMerged() )
611  {
612  bIsEmpty = false;
613 
614  sal_Int32 nColSpan = xCell->getColumnSpan();
615  if( nColSpan > 1 )
616  {
617  // merged cells will be evaluated later
618  aMergedCells[nCol+nColSpan-1].push_back( xCell );
619  }
620  else
621  {
622  nMinWidth = std::max( nMinWidth, xCell->getMinimumWidth() );
623  }
624  }
625  }
626 
627  maColumns[nCol].mnMinSize = nMinWidth;
628 
629  if( bIsEmpty )
630  {
631  maColumns[nCol].mnSize = 0;
632  }
633  else
634  {
635  sal_Int32 nColWidth = 0;
636  Reference< XPropertySet > xColSet( xCols->getByIndex( nCol ), UNO_QUERY_THROW );
637  bool bOptimal = false;
638  xColSet->getPropertyValue( sOptimalSize ) >>= bOptimal;
639  if( bOptimal )
640  {
641  aOptimalColumns.push_back(nCol);
642  }
643  else
644  {
645  xColSet->getPropertyValue( gsSize ) >>= nColWidth;
646  }
647 
648  maColumns[nCol].mnSize = std::max( nColWidth, nMinWidth);
649 
650  nCurrentWidth = o3tl::saturating_add(nCurrentWidth, maColumns[nCol].mnSize);
651  }
652  }
653 
654  // if we have optimal sized rows, distribute what is given (left)
655  if( !bFit && !aOptimalColumns.empty() && (nCurrentWidth < rArea.getWidth()) )
656  {
657  sal_Int32 nLeft = rArea.getWidth() - nCurrentWidth;
658  sal_Int32 nDistribute = nLeft / aOptimalColumns.size();
659 
660  auto iter( aOptimalColumns.begin() );
661  while( iter != aOptimalColumns.end() )
662  {
663  sal_Int32 nOptCol = *iter++;
664  if( iter == aOptimalColumns.end() )
665  nDistribute = nLeft;
666 
667  maColumns[nOptCol].mnSize += nDistribute;
668  nLeft -= nDistribute;
669  }
670 
671  DBG_ASSERT( nLeft == 0, "svx::TableLayouter::LayoutTableWidtht(), layouting failed!" );
672  }
673 
674  // now check if merged cells fit
675  for( nCol = 1; nCol < nColCount; ++nCol )
676  {
677  bool bChanges = false;
678 
679  const sal_Int32 nOldSize = maColumns[nCol].mnSize;
680 
681  for( const CellRef& xCell : aMergedCells[nCol] )
682  {
683  sal_Int32 nMinWidth = xCell->getMinimumWidth();
684 
685  for( sal_Int32 nMCol = nCol - xCell->getColumnSpan() + 1; (nMCol > 0) && (nMCol < nCol); ++nMCol )
686  nMinWidth -= maColumns[nMCol].mnSize;
687 
688  if( nMinWidth > maColumns[nCol].mnMinSize )
689  maColumns[nCol].mnMinSize = nMinWidth;
690 
691  if( nMinWidth > maColumns[nCol].mnSize )
692  {
693  maColumns[nCol].mnSize = nMinWidth;
694  bChanges = true;
695  }
696  }
697 
698  if( bChanges )
699  {
700  nCurrentWidth = o3tl::saturating_add(nCurrentWidth, maColumns[nCol].mnSize - nOldSize);
701  }
702  }
703 
704  // now scale if wanted and needed
705  if( bFit && (nCurrentWidth != rArea.getWidth()) )
706  distribute( maColumns, rArea.getWidth() - nCurrentWidth );
707 
708  // last step, update left edges
709  sal_Int32 nNewWidth = 0;
710 
711  const bool bRTL = (mxTable->getSdrTableObj()->GetWritingMode() == WritingMode_RL_TB);
712  RangeIterator<sal_Int32> coliter( 0, nColCount, !bRTL );
713  while( coliter.next(nCol ) )
714  {
715  maColumns[nCol].mnPos = nNewWidth;
716  nNewWidth = o3tl::saturating_add(nNewWidth, maColumns[nCol].mnSize);
717  if( bFit )
718  {
719  Reference< XPropertySet > xColSet( xCols->getByIndex(nCol), UNO_QUERY_THROW );
720  xColSet->setPropertyValue( gsSize, Any( maColumns[nCol].mnSize ) );
721  }
722  }
723 
724  rArea.SetSize( Size( nNewWidth, rArea.GetHeight() ) );
725  updateCells( rArea );
726 }
727 
728 
730 {
731  const sal_Int32 nColCount = getColumnCount();
732  const sal_Int32 nRowCount = getRowCount();
733  if( nRowCount == 0 )
734  return;
735 
736  Reference< XTableRows > xRows( mxTable->getRows() );
737 
738  MergeVector aMergedCells( nRowCount );
739  std::vector<sal_Int32> aOptimalRows;
740 
741  const OUString sOptimalSize("OptimalSize");
742 
743  // first calculate current height and initial minimum size per column,
744  // merged cells will be counted later
745  sal_Int32 nCurrentHeight = 0;
746  sal_Int32 nCol, nRow;
747  for( nRow = 0; nRow < nRowCount; ++nRow )
748  {
749  sal_Int32 nMinHeight = 0;
750 
751  bool bIsEmpty = true; // check if all cells in this row are merged
752  bool bRowHasText = false;
753 
754  for( nCol = 0; nCol < nColCount; ++nCol )
755  {
756  CellRef xCell( getCell( CellPos( nCol, nRow ) ) );
757  if( xCell.is() && !xCell->isMerged() )
758  {
759  bIsEmpty = false;
760 
761  sal_Int32 nRowSpan = xCell->getRowSpan();
762  if( nRowSpan > 1 )
763  {
764  // merged cells will be evaluated later
765  aMergedCells[nRow+nRowSpan-1].push_back( xCell );
766  }
767  else
768  {
769  bool bCellHasText = xCell->hasText();
770  if (bRowHasText == bCellHasText)
771  {
772  nMinHeight = std::max( nMinHeight, xCell->getMinimumHeight() );
773  }
774  else if ( !bRowHasText && bCellHasText )
775  {
776  bRowHasText = true;
777  nMinHeight = xCell->getMinimumHeight();
778  }
779  }
780  }
781  }
782 
783  maRows[nRow].mnMinSize = nMinHeight;
784 
785  if( bIsEmpty )
786  {
787  maRows[nRow].mnSize = 0;
788  }
789  else
790  {
791  sal_Int32 nRowHeight = 0;
792  Reference< XPropertySet > xRowSet( xRows->getByIndex(nRow), UNO_QUERY_THROW );
793 
794  bool bOptimal = false;
795  xRowSet->getPropertyValue( sOptimalSize ) >>= bOptimal;
796  if( bOptimal )
797  {
798  aOptimalRows.push_back( nRow );
799  }
800  else
801  {
802  xRowSet->getPropertyValue( gsSize ) >>= nRowHeight;
803  }
804 
805  maRows[nRow].mnSize = nRowHeight;
806 
807  if( maRows[nRow].mnSize < nMinHeight )
808  maRows[nRow].mnSize = nMinHeight;
809 
810  nCurrentHeight = o3tl::saturating_add(nCurrentHeight, maRows[nRow].mnSize);
811  }
812  }
813 
814  // if we have optimal sized rows, distribute what is given (left)
815  if( !bFit && !aOptimalRows.empty() && (nCurrentHeight < rArea.getHeight()) )
816  {
817  sal_Int32 nLeft = rArea.getHeight() - nCurrentHeight;
818  sal_Int32 nDistribute = nLeft / aOptimalRows.size();
819 
820  auto iter( aOptimalRows.begin() );
821  while( iter != aOptimalRows.end() )
822  {
823  sal_Int32 nOptRow = *iter++;
824  if( iter == aOptimalRows.end() )
825  nDistribute = nLeft;
826 
827  maRows[nOptRow].mnSize += nDistribute;
828  nLeft -= nDistribute;
829 
830  }
831 
832  DBG_ASSERT( nLeft == 0, "svx::TableLayouter::LayoutTableHeight(), layouting failed!" );
833  }
834 
835  // now check if merged cells fit
836  for( nRow = 1; nRow < nRowCount; ++nRow )
837  {
838  bool bChanges = false;
839  sal_Int32 nOldSize = maRows[nRow].mnSize;
840 
841  for( const CellRef& xCell : aMergedCells[nRow] )
842  {
843  sal_Int32 nMinHeight = xCell->getMinimumHeight();
844 
845  for( sal_Int32 nMRow = nRow - xCell->getRowSpan() + 1; (nMRow > 0) && (nMRow < nRow); ++nMRow )
846  nMinHeight -= maRows[nMRow].mnSize;
847 
848  if( nMinHeight > maRows[nRow].mnMinSize )
849  maRows[nRow].mnMinSize = nMinHeight;
850 
851  if( nMinHeight > maRows[nRow].mnSize )
852  {
853  maRows[nRow].mnSize = nMinHeight;
854  bChanges = true;
855  }
856  }
857  if( bChanges )
858  nCurrentHeight = o3tl::saturating_add(nCurrentHeight, maRows[nRow].mnSize - nOldSize);
859  }
860 
861  // now scale if wanted and needed
862  if( bFit && nCurrentHeight != rArea.getHeight() )
863  distribute(maRows, o3tl::saturating_sub<sal_Int32>(rArea.getHeight(), nCurrentHeight));
864 
865  // last step, update left edges
866  sal_Int32 nNewHeight = 0;
867  for( nRow = 0; nRow < nRowCount; ++nRow )
868  {
869  maRows[nRow].mnPos = nNewHeight;
870  nNewHeight = o3tl::saturating_add(nNewHeight, maRows[nRow].mnSize);
871 
872  if( bFit )
873  {
874  Reference< XPropertySet > xRowSet( xRows->getByIndex(nRow), UNO_QUERY_THROW );
875  xRowSet->setPropertyValue( gsSize, Any( maRows[nRow].mnSize ) );
876  }
877  }
878 
879  rArea.SetSize( Size( rArea.GetWidth(), nNewHeight ) );
880  updateCells( rArea );
881 }
882 
883 
886 void TableLayouter::LayoutTable( tools::Rectangle& rRectangle, bool bFitWidth, bool bFitHeight )
887 {
888  if( !mxTable.is() )
889  return;
890 
891  const sal_Int32 nRowCount = mxTable->getRowCount();
892  const sal_Int32 nColCount = mxTable->getColumnCount();
893 
894  if( (nRowCount != getRowCount()) || (nColCount != getColumnCount()) )
895  {
896  if( static_cast< sal_Int32 >( maRows.size() ) != nRowCount )
897  maRows.resize( nRowCount );
898 
899  for( sal_Int32 nRow = 0; nRow < nRowCount; nRow++ )
900  maRows[nRow].clear();
901 
902  if( static_cast< sal_Int32 >( maColumns.size() ) != nColCount )
903  maColumns.resize( nColCount );
904 
905  for( sal_Int32 nCol = 0; nCol < nColCount; nCol++ )
906  maColumns[nCol].clear();
907  }
908 
909  LayoutTableWidth( rRectangle, bFitWidth );
910  LayoutTableHeight( rRectangle, bFitHeight );
912 }
913 
914 
916 {
917  const sal_Int32 nColCount = getColumnCount();
918  const sal_Int32 nRowCount = getRowCount();
919 
920  CellPos aPos;
921  for( aPos.mnRow = 0; aPos.mnRow < nRowCount; aPos.mnRow++ )
922  {
923  for( aPos.mnCol = 0; aPos.mnCol < nColCount; aPos.mnCol++ )
924  {
925  CellRef xCell( getCell( aPos ) );
926  if( xCell.is() )
927  {
928  basegfx::B2IRectangle aCellArea;
929  if( getCellArea( xCell, aPos, aCellArea ) )
930  {
931  tools::Rectangle aCellRect;
932  aCellRect.SetLeft( aCellArea.getMinX() );
933  aCellRect.SetRight( aCellArea.getMaxX() );
934  aCellRect.SetTop( aCellArea.getMinY() );
935  aCellRect.SetBottom( aCellArea.getMaxY() );
936  aCellRect.Move( rRectangle.Left(), rRectangle.Top() );
937  xCell->setCellRect( aCellRect );
938  }
939  }
940  }
941  }
942 }
943 
944 
946 {
947  CellRef xCell;
948  if( mxTable.is() ) try
949  {
950  xCell.set( dynamic_cast< Cell* >( mxTable->getCellByPosition( rPos.mnCol, rPos.mnRow ).get() ) );
951  }
952  catch( Exception& )
953  {
954  OSL_FAIL( "sdr::table::TableLayouter::getCell(), exception caught!" );
955  }
956  return xCell;
957 }
958 
959 
960 bool TableLayouter::HasPriority( const SvxBorderLine* pThis, const SvxBorderLine* pOther )
961 {
962  if (!pThis || ((pThis == &gEmptyBorder) && (pOther != nullptr)))
963  return false;
964  if (!pOther || (pOther == &gEmptyBorder))
965  return true;
966 
967  sal_uInt16 nThisSize = pThis->GetScaledWidth();
968  sal_uInt16 nOtherSize = pOther->GetScaledWidth();
969 
970  if (nThisSize > nOtherSize)
971  return true;
972 
973  else if (nThisSize < nOtherSize)
974  {
975  return false;
976  }
977  else
978  {
979  if ( pOther->GetInWidth() && !pThis->GetInWidth() )
980  {
981  return true;
982  }
983  else if ( pThis->GetInWidth() && !pOther->GetInWidth() )
984  {
985  return false;
986  }
987  else
988  {
989  return true;
990  }
991  }
992 }
993 
994 void TableLayouter::SetBorder( sal_Int32 nCol, sal_Int32 nRow, bool bHorizontal, const SvxBorderLine* pLine )
995 {
996  if (!pLine)
997  pLine = &gEmptyBorder;
998 
999  BorderLineMap& rMap = bHorizontal ? maHorizontalBorders : maVerticalBorders;
1000 
1001  if( (nCol >= 0) && (nCol < sal::static_int_cast<sal_Int32>(rMap.size())) &&
1002  (nRow >= 0) && (nRow < sal::static_int_cast<sal_Int32>(rMap[nCol].size())) )
1003  {
1004  SvxBorderLine *pOld = rMap[nCol][nRow];
1005 
1006  if (HasPriority(pLine, pOld))
1007  {
1008  if (pOld && pOld != &gEmptyBorder)
1009  delete pOld;
1010 
1011  SvxBorderLine* pNew = (pLine != &gEmptyBorder) ? new SvxBorderLine(*pLine) : &gEmptyBorder;
1012 
1013  rMap[nCol][nRow] = pNew;
1014  }
1015  }
1016  else
1017  {
1018  OSL_FAIL( "sdr::table::TableLayouter::SetBorder(), invalid border!" );
1019  }
1020 }
1021 
1023 {
1026 }
1027 
1029 {
1030  const sal_Int32 nColCount = rMap.size();
1031 
1032  for( sal_Int32 nCol = 0; nCol < nColCount; nCol++ )
1033  {
1034  const sal_Int32 nRowCount = rMap[nCol].size();
1035  for( sal_Int32 nRow = 0; nRow < nRowCount; nRow++ )
1036  {
1037  SvxBorderLine* pLine = rMap[nCol][nRow];
1038  if( pLine )
1039  {
1040  if( pLine != &gEmptyBorder )
1041  delete pLine;
1042 
1043  rMap[nCol][nRow] = nullptr;
1044  }
1045  }
1046  }
1047 }
1048 
1050 {
1054 }
1055 
1056 
1058 {
1059  const sal_Int32 nColCount = getColumnCount() + 1;
1060  const sal_Int32 nRowCount = getRowCount() + 1;
1061 
1062  if( sal::static_int_cast<sal_Int32>(rMap.size()) != nColCount )
1063  rMap.resize( nColCount );
1064 
1065  for( sal_Int32 nCol = 0; nCol < nColCount; nCol++ )
1066  {
1067  if( sal::static_int_cast<sal_Int32>(rMap[nCol].size()) != nRowCount )
1068  rMap[nCol].resize( nRowCount );
1069  }
1070 }
1071 
1072 
1074 {
1075  // make sure old border layout is cleared and border maps have correct size
1077 
1078  const sal_Int32 nColCount = getColumnCount();
1079  const sal_Int32 nRowCount = getRowCount();
1080 
1081  CellPos aPos;
1082  for( aPos.mnRow = 0; aPos.mnRow < nRowCount; aPos.mnRow++ )
1083  {
1084  for( aPos.mnCol = 0; aPos.mnCol < nColCount; aPos.mnCol++ )
1085  {
1086  CellRef xCell( getCell( aPos ) );
1087  if( !xCell.is() )
1088  continue;
1089 
1090  const SvxBoxItem* pThisAttr = xCell->GetItemSet().GetItem<SvxBoxItem>( SDRATTR_TABLE_BORDER );
1091  OSL_ENSURE(pThisAttr,"sdr::table::TableLayouter::UpdateBorderLayout(), no border attribute?");
1092 
1093  if( !pThisAttr )
1094  continue;
1095 
1096  const sal_Int32 nLastRow = xCell->getRowSpan() + aPos.mnRow;
1097  const sal_Int32 nLastCol = xCell->getColumnSpan() + aPos.mnCol;
1098 
1099  for( sal_Int32 nRow = aPos.mnRow; nRow < nLastRow; nRow++ )
1100  {
1101  SetBorder( aPos.mnCol, nRow, false, pThisAttr->GetLeft() );
1102  SetBorder( nLastCol, nRow, false, pThisAttr->GetRight() );
1103  }
1104 
1105  for( sal_Int32 nCol = aPos.mnCol; nCol < nLastCol; nCol++ )
1106  {
1107  SetBorder( nCol, aPos.mnRow, true, pThisAttr->GetTop() );
1108  SetBorder( nCol, nLastRow, true, pThisAttr->GetBottom() );
1109  }
1110  }
1111  }
1112 }
1113 
1114 
1116  sal_Int32 nFirstCol,
1117  sal_Int32 nLastCol,
1118  const bool bOptimize,
1119  const bool bMinimize )
1120 {
1121  if( mxTable.is() ) try
1122  {
1123  const sal_Int32 nColCount = getColumnCount();
1124  Reference< XTableColumns > xCols( mxTable->getColumns(), UNO_SET_THROW );
1125  const Size aSize(0xffffff, 0xffffff);
1126 
1127  //special case - optimize a single column
1128  if ( (bOptimize || bMinimize) && nFirstCol == nLastCol )
1129  {
1130  const sal_Int32 nWish = calcPreferredColumnWidth(nFirstCol, aSize);
1131  if ( nWish < getColumnWidth(nFirstCol) )
1132  {
1133  Reference< XPropertySet > xColSet( xCols->getByIndex(nFirstCol), UNO_QUERY_THROW );
1134  xColSet->setPropertyValue( gsSize, Any( nWish ) );
1135 
1136  //FitWidth automatically distributes the new excess space
1137  LayoutTable( rArea, /*bFitWidth=*/!bMinimize, /*bFitHeight=*/false );
1138  }
1139  }
1140 
1141  if( (nFirstCol < 0) || (nFirstCol>= nLastCol) || (nLastCol >= nColCount) )
1142  return;
1143 
1144  sal_Int32 nAllWidth = 0;
1145  float fAllWish = 0;
1146  sal_Int32 nUnused = 0;
1147  std::vector<sal_Int32> aWish(nColCount);
1148 
1149  for( sal_Int32 nCol = nFirstCol; nCol <= nLastCol; ++nCol )
1150  nAllWidth += getColumnWidth(nCol);
1151 
1152  const sal_Int32 nEqualWidth = nAllWidth / (nLastCol-nFirstCol+1);
1153 
1154  //pass 1 - collect unneeded space (from an equal width perspective)
1155  if ( bMinimize || bOptimize )
1156  {
1157  for( sal_Int32 nCol = nFirstCol; nCol <= nLastCol; ++nCol )
1158  {
1159  const sal_Int32 nIndex = nCol - nFirstCol;
1160  aWish[nIndex] = calcPreferredColumnWidth(nCol, aSize);
1161  fAllWish += aWish[nIndex];
1162  if ( aWish[nIndex] < nEqualWidth )
1163  nUnused += nEqualWidth - aWish[nIndex];
1164  }
1165  }
1166  const sal_Int32 nDistributeExcess = nAllWidth - fAllWish;
1167 
1168  sal_Int32 nWidth = nEqualWidth;
1169  for( sal_Int32 nCol = nFirstCol; nCol <= nLastCol; ++nCol )
1170  {
1171  if ( !bMinimize && nCol == nLastCol )
1172  nWidth = nAllWidth; // last column gets rounding/logic errors
1173  else if ( (bMinimize || bOptimize) && fAllWish )
1174  {
1175  //pass 2 - first come, first served when requesting from the
1176  // unneeded pool, or proportionally allocate excess.
1177  const sal_Int32 nIndex = nCol - nFirstCol;
1178  if ( aWish[nIndex] > nEqualWidth + nUnused )
1179  {
1180  nWidth = nEqualWidth + nUnused;
1181  nUnused = 0;
1182  }
1183  else
1184  {
1185  nWidth = aWish[nIndex];
1186  if ( aWish[nIndex] > nEqualWidth )
1187  nUnused -= aWish[nIndex] - nEqualWidth;
1188 
1189  if ( !bMinimize && nDistributeExcess > 0 )
1190  nWidth += nWidth / fAllWish * nDistributeExcess;
1191  }
1192  }
1193 
1194  Reference< XPropertySet > xColSet( xCols->getByIndex( nCol ), UNO_QUERY_THROW );
1195  xColSet->setPropertyValue( gsSize, Any( nWidth ) );
1196 
1197  nAllWidth -= nWidth;
1198  }
1199 
1200  LayoutTable( rArea, !bMinimize, false );
1201  }
1202  catch( Exception& )
1203  {
1204  OSL_FAIL("sdr::table::TableLayouter::DistributeColumns(), exception caught!");
1205  }
1206 }
1207 
1208 
1210  sal_Int32 nFirstRow,
1211  sal_Int32 nLastRow,
1212  const bool bOptimize,
1213  const bool bMinimize )
1214 {
1215  if( mxTable.is() ) try
1216  {
1217  const sal_Int32 nRowCount = mxTable->getRowCount();
1218  Reference< XTableRows > xRows( mxTable->getRows(), UNO_SET_THROW );
1219  sal_Int32 nMinHeight = 0;
1220 
1221  //special case - minimize a single row
1222  if ( bMinimize && nFirstRow == nLastRow )
1223  {
1224  const sal_Int32 nWish = std::max( maRows[nFirstRow].mnMinSize, nMinHeight );
1225  if ( nWish < getRowHeight(nFirstRow) )
1226  {
1227  Reference< XPropertySet > xRowSet( xRows->getByIndex( nFirstRow ), UNO_QUERY_THROW );
1228  xRowSet->setPropertyValue( gsSize, Any( nWish ) );
1229 
1230  LayoutTable( rArea, /*bFitWidth=*/false, /*bFitHeight=*/!bMinimize );
1231  }
1232  }
1233 
1234  if( (nFirstRow < 0) || (nFirstRow>= nLastRow) || (nLastRow >= nRowCount) )
1235  return;
1236 
1237  sal_Int32 nAllHeight = 0;
1238  sal_Int32 nMaxHeight = 0;
1239 
1240  for( sal_Int32 nRow = nFirstRow; nRow <= nLastRow; ++nRow )
1241  {
1242  nMinHeight = std::max( maRows[nRow].mnMinSize, nMinHeight );
1243  nMaxHeight = std::max( maRows[nRow].mnSize, nMaxHeight );
1244  nAllHeight += maRows[nRow].mnSize;
1245  }
1246 
1247  const sal_Int32 nRows = nLastRow-nFirstRow+1;
1248  sal_Int32 nHeight = nAllHeight / nRows;
1249 
1250  if ( !bMinimize && nHeight < nMaxHeight )
1251  {
1252  if ( !bOptimize )
1253  {
1254  sal_Int32 nNeededHeight = nRows * nMaxHeight;
1255  rArea.AdjustBottom(nNeededHeight - nAllHeight );
1256  nHeight = nMaxHeight;
1257  nAllHeight = nRows * nMaxHeight;
1258  }
1259  else if ( nHeight < nMinHeight )
1260  {
1261  sal_Int32 nNeededHeight = nRows * nMinHeight;
1262  rArea.AdjustBottom(nNeededHeight - nAllHeight );
1263  nHeight = nMinHeight;
1264  nAllHeight = nRows * nMinHeight;
1265  }
1266  }
1267 
1268  for( sal_Int32 nRow = nFirstRow; nRow <= nLastRow; ++nRow )
1269  {
1270  if ( bMinimize )
1271  nHeight = maRows[nRow].mnMinSize;
1272  else if ( nRow == nLastRow )
1273  nHeight = nAllHeight; // last row get round errors
1274 
1275  Reference< XPropertySet > xRowSet( xRows->getByIndex( nRow ), UNO_QUERY_THROW );
1276  xRowSet->setPropertyValue( gsSize, Any( nHeight ) );
1277 
1278  nAllHeight -= nHeight;
1279  }
1280 
1281  LayoutTable( rArea, false, !bMinimize );
1282  }
1283  catch( Exception& )
1284  {
1285  OSL_FAIL("sdr::table::TableLayouter::DistributeRows(), exception caught!");
1286  }
1287 }
1288 
1290 {
1291  xmlTextWriterStartElement(pWriter, BAD_CAST("TableLayouter"));
1292 
1293  xmlTextWriterStartElement(pWriter, BAD_CAST("columns"));
1294  for (const auto& rColumn : maColumns)
1295  rColumn.dumpAsXml(pWriter);
1296  xmlTextWriterEndElement(pWriter);
1297 
1298  xmlTextWriterStartElement(pWriter, BAD_CAST("rows"));
1299  for (const auto& rRow : maRows)
1300  rRow.dumpAsXml(pWriter);
1301  xmlTextWriterEndElement(pWriter);
1302 
1303  xmlTextWriterEndElement(pWriter);
1304 }
1305 
1307 {
1308  xmlTextWriterStartElement(pWriter, BAD_CAST("TableLayouter_Layout"));
1309 
1310  xmlTextWriterWriteAttribute(pWriter, BAD_CAST("pos"), BAD_CAST(OString::number(mnPos).getStr()));
1311  xmlTextWriterWriteAttribute(pWriter, BAD_CAST("size"), BAD_CAST(OString::number(mnSize).getStr()));
1312  xmlTextWriterWriteAttribute(pWriter, BAD_CAST("minSize"), BAD_CAST(OString::number(mnMinSize).getStr()));
1313 
1314  xmlTextWriterEndElement(pWriter);
1315 }
1316 
1317 } }
1318 
1319 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool findMergeOrigin(const TableModelRef &xTable, sal_Int32 nMergedX, sal_Int32 nMergedY, sal_Int32 &rOriginX, sal_Int32 &rOriginY)
returns true if the cell(nMergedX,nMergedY) is merged with other cells.
long getHeight() const
const int nColCount
std::enable_if< std::is_signed< T >::value, bool >::type checked_sub(T a, T b, T &result)
::sal_Int32 getColumnCount() const
long GetWidth() const
void DistributeColumns(::tools::Rectangle &rArea, sal_Int32 nFirstCol, sal_Int32 nLastCol, const bool bOptimize, const bool bMinimize)
sal_Int32 nIndex
void dumpAsXml(xmlTextWriterPtr pWriter) const
long GetHeight() const
#define SDRATTR_TABLE_BORDER
Definition: svddef.hxx:399
basegfx::B2ITuple getCellSize(const CellRef &xCell, const CellPos &rPos) const
std::vector< Layout > LayoutVector
static bool checkMergeOrigin(const TableModelRef &xTable, sal_Int32 nMergedX, sal_Int32 nMergedY, sal_Int32 nCellX, sal_Int32 nCellY, bool &bRunning)
long getWidth() const
::sal_Int32 getRowCount() const
std::vector< EdgeInfo > getHorizontalEdges()
sal_Int64 n
static SvxBorderLine gEmptyBorder
sal_Int32 getMinY() const
static sal_Int32 distribute(LayoutVector &rLayouts, sal_Int32 nDistribute)
const editeng::SvxBorderLine * GetRight() const
sal_Int32 getMinimumColumnWidth(sal_Int32 nColumn)
float x
bool isValidColumn(sal_Int32 nColumn) const
struct _xmlTextWriter * xmlTextWriterPtr
sal_Int32 getHorizontalEdge(int nEdgeY, sal_Int32 *pnMin, sal_Int32 *pnMax)
long AdjustBottom(long nVertMoveDelta)
void SetBorder(sal_Int32 nCol, sal_Int32 nRow, bool bHorizontal, const editeng::SvxBorderLine *pLine)
void Move(long nHorzMoveDelta, long nVertMoveDelta)
editeng::SvxBorderLine * getBorderLine(sal_Int32 nEdgeX, sal_Int32 nEdgeY, bool bHorizontal) const
returns the requested borderline in rpBorderLine or a null pointer if there is no border at this edge...
bool next(T &rValue)
Definition: celltypes.hxx:75
sal_Int32 getMaxX() const
int nCount
long Top() const
float y
const editeng::SvxBorderLine * GetTop() const
void SetTop(long v)
const editeng::SvxBorderLine * GetLeft() const
#define DBG_ASSERT(sCon, aError)
sal_Int32 getX() const
void dumpAsXml(xmlTextWriterPtr pWriter) const
void SetSize(const Size &rSize)
int i
std::enable_if< std::is_signed< T >::value, T >::type saturating_add(T a, T b)
void updateCells(::tools::Rectangle const &rRectangle)
sal_Int32 getColumnWidth(sal_Int32 nColumn) const
BorderLineMap maHorizontalBorders
void SetRight(long v)
bool getCellArea(const CellRef &xCell, const CellPos &rPos, basegfx::B2IRectangle &rArea) const
std::enable_if< std::is_signed< T >::value, bool >::type checked_add(T a, T b, T &result)
std::enable_if< std::is_signed< T >::value, bool >::type checked_multiply(T a, T b, T &result)
CellRef getCell(const CellPos &rPos) const
size
sal_Int32 getMinX() const
static const OUStringLiteral gsSize("Size")
sal_uInt32 const mnSize
bool isValid(const CellPos &rPos) const
std::vector< CellRef > MergeableCellVector
static bool HasPriority(const editeng::SvxBorderLine *pThis, const editeng::SvxBorderLine *pOther)
std::vector< MergeableCellVector > MergeVector
bool isEdgeVisible(sal_Int32 nEdgeX, sal_Int32 nEdgeY, bool bHorizontal) const
checks if the given edge is visible.
void LayoutTableHeight(::tools::Rectangle &rArea, bool bFit)
bool isValidRow(sal_Int32 nRow) const
TableLayouter(const TableModelRef &xTableModel)
void SetBottom(long v)
sal_Int32 getY() const
sal_Int32 getRowHeight(sal_Int32 nRow) const
long Left() const
sal_Int32 calcPreferredColumnWidth(sal_Int32 nColumn, Size aSize) const
B2IRange B2IRectangle
std::vector< BorderLineVector > BorderLineMap
void LayoutTableWidth(::tools::Rectangle &rArea, bool bFit)
void LayoutTable(::tools::Rectangle &rRectangle, bool bFitWidth, bool bFitHeight)
try to fit the table into the given rectangle.
sal_Int32 getMaxY() const
void SetLeft(long v)
void DistributeRows(::tools::Rectangle &rArea, sal_Int32 nFirstRow, sal_Int32 nLastRow, const bool bOptimize, const bool bMinimize)
const editeng::SvxBorderLine * GetBottom() const
std::vector< EdgeInfo > getVerticalEdges()
sal_Int32 getVerticalEdge(int nEdgeX, sal_Int32 *pnMin, sal_Int32 *pnMax)