LibreOffice Module sw (master)  1
tblrwcl.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 #include <memory>
21 #include <com/sun/star/text/HoriOrientation.hpp>
22 #include <hintids.hxx>
23 
24 #include <editeng/lrspitem.hxx>
25 #include <editeng/boxitem.hxx>
26 #include <tools/fract.hxx>
27 #include <fmtfsize.hxx>
28 #include <fmtornt.hxx>
29 #include <doc.hxx>
36 #include <docsh.hxx>
37 #include <fesh.hxx>
38 #include <tabfrm.hxx>
39 #include <frmatr.hxx>
40 #include <frmtool.hxx>
41 #include <pam.hxx>
42 #include <swtable.hxx>
43 #include <tblsel.hxx>
44 #include <fldbas.hxx>
45 #include <rowfrm.hxx>
46 #include <ddefld.hxx>
47 #include <hints.hxx>
48 #include <UndoTable.hxx>
49 #include <cellatr.hxx>
50 #include <mvsave.hxx>
51 #include <swtblfmt.hxx>
52 #include <swddetbl.hxx>
53 #include <poolfmt.hxx>
54 #include <tblrwcl.hxx>
55 #include <unochart.hxx>
56 #include <o3tl/numeric.hxx>
57 #include <calbck.hxx>
58 #include <docary.hxx>
59 
60 using namespace com::sun::star;
61 using namespace com::sun::star::uno;
62 
63 #define COLFUZZY 20
64 #define ROWFUZZY 10
65 
66 #ifdef DBG_UTIL
67 #define CHECK_TABLE(t) (t).CheckConsistency();
68 #else
69 #define CHECK_TABLE(t)
70 #endif
71 
72 namespace {
73 
74 // In order to set the Frame Formats for the Boxes, it's enough to look
75 // up the current one in the array. If it's already there return the new one.
76 struct CpyTabFrame
77 {
78  SwFrameFormat* pFrameFormat;
79  SwTableBoxFormat *pNewFrameFormat;
80 
81  explicit CpyTabFrame(SwFrameFormat* pCurrentFrameFormat) : pNewFrameFormat( nullptr )
82  { pFrameFormat = pCurrentFrameFormat; }
83 
84  bool operator==( const CpyTabFrame& rCpyTabFrame ) const
85  { return pFrameFormat == rCpyTabFrame.pFrameFormat; }
86  bool operator<( const CpyTabFrame& rCpyTabFrame ) const
87  { return pFrameFormat < rCpyTabFrame.pFrameFormat; }
88 };
89 
90 struct CR_SetBoxWidth
91 {
92  SwShareBoxFormats aShareFormats;
93  SwTableNode* pTableNd;
94  SwTwips nDiff, nSide, nMaxSize, nLowerDiff;
95  TableChgMode nMode;
96  bool bBigger, bLeft;
97 
98  CR_SetBoxWidth( TableChgWidthHeightType eType, SwTwips nDif, SwTwips nSid,
99  SwTwips nMax, SwTableNode* pTNd )
100  : pTableNd( pTNd ),
101  nDiff( nDif ), nSide( nSid ), nMaxSize( nMax ), nLowerDiff( 0 )
102  {
105  bBigger = bool(eType & TableChgWidthHeightType::BiggerMode );
106  nMode = pTableNd->GetTable().GetTableChgMode();
107  }
108  CR_SetBoxWidth( const CR_SetBoxWidth& rCpy )
109  : pTableNd( rCpy.pTableNd ),
110  nDiff( rCpy.nDiff ), nSide( rCpy.nSide ),
111  nMaxSize( rCpy.nMaxSize ), nLowerDiff( 0 ),
112  nMode( rCpy.nMode ),
113  bBigger( rCpy.bBigger ), bLeft( rCpy.bLeft )
114  {
115  }
116 
117  void LoopClear()
118  {
119  nLowerDiff = 0;
120  }
121 };
122 
123 }
124 
125 static bool lcl_SetSelBoxWidth( SwTableLine* pLine, CR_SetBoxWidth& rParam,
126  SwTwips nDist, bool bCheck );
127 static bool lcl_SetOtherBoxWidth( SwTableLine* pLine, CR_SetBoxWidth& rParam,
128  SwTwips nDist, bool bCheck );
129 
130 typedef bool (*FN_lcl_SetBoxWidth)(SwTableLine*, CR_SetBoxWidth&, SwTwips, bool );
131 
132 #ifdef DBG_UTIL
133 
134 #define CHECKBOXWIDTH \
135  { \
136  SwTwips nSize = GetFrameFormat()->GetFrameSize().GetWidth(); \
137  for (size_t nTmp = 0; nTmp < m_aLines.size(); ++nTmp) \
138  ::CheckBoxWidth( *m_aLines[ nTmp ], nSize ); \
139  }
140 
141 #define CHECKTABLELAYOUT \
142  { \
143  for ( size_t i = 0; i < GetTabLines().size(); ++i ) \
144  { \
145  SwFrameFormat* pFormat = GetTabLines()[i]->GetFrameFormat(); \
146  SwIterator<SwRowFrame,SwFormat> aIter( *pFormat ); \
147  for (SwRowFrame* pFrame=aIter.First(); pFrame; pFrame=aIter.Next())\
148  { \
149  if ( pFrame->GetTabLine() == GetTabLines()[i] ) \
150  { \
151  OSL_ENSURE( pFrame->GetUpper()->IsTabFrame(), \
152  "Table layout does not match table structure" ); \
153  } \
154  } \
155  } \
156  }
157 
158 #else
159 
160 #define CHECKBOXWIDTH
161 #define CHECKTABLELAYOUT
162 
163 #endif // DBG_UTIL
164 
165 namespace {
166 
167 struct CR_SetLineHeight
168 {
169  SwTableNode* pTableNd;
170  SwTwips nMaxSpace, nMaxHeight;
171  TableChgMode nMode;
172  bool bBigger;
173 
174  CR_SetLineHeight( TableChgWidthHeightType eType, SwTableNode* pTNd )
175  : pTableNd( pTNd ),
176  nMaxSpace( 0 ), nMaxHeight( 0 )
177  {
178  bBigger = bool(eType & TableChgWidthHeightType::BiggerMode );
179  nMode = pTableNd->GetTable().GetTableChgMode();
180  }
181  CR_SetLineHeight( const CR_SetLineHeight& rCpy )
182  : pTableNd( rCpy.pTableNd ),
183  nMaxSpace( rCpy.nMaxSpace ), nMaxHeight( rCpy.nMaxHeight ),
184  nMode( rCpy.nMode ),
185  bBigger( rCpy.bBigger )
186  {}
187 };
188 
189 }
190 
191 static bool lcl_SetSelLineHeight( SwTableLine* pLine, const CR_SetLineHeight& rParam,
192  SwTwips nDist, bool bCheck );
193 static bool lcl_SetOtherLineHeight( SwTableLine* pLine, const CR_SetLineHeight& rParam,
194  SwTwips nDist, bool bCheck );
195 
196 typedef bool (*FN_lcl_SetLineHeight)(SwTableLine*, CR_SetLineHeight&, SwTwips, bool );
197 
199 
200 namespace {
201 
202 struct CpyPara
203 {
204  std::shared_ptr< std::vector< std::vector< sal_uLong > > > pWidths;
205  SwDoc& rDoc;
206  SwTableNode* pTableNd;
207  CpyTabFrames& rTabFrameArr;
208  SwTableLine* pInsLine;
209  SwTableBox* pInsBox;
210  sal_uLong nOldSize, nNewSize; // in order to correct the size attributes
211  sal_uLong nMinLeft, nMaxRight;
212  sal_uInt16 nCpyCnt, nInsPos;
213  sal_uInt16 nLnIdx, nBoxIdx;
214  sal_uInt8 nDelBorderFlag;
215  bool bCpyContent;
216 
217  CpyPara( SwTableNode* pNd, sal_uInt16 nCopies, CpyTabFrames& rFrameArr )
218  : rDoc( pNd->GetDoc() ), pTableNd( pNd ), rTabFrameArr(rFrameArr),
219  pInsLine(nullptr), pInsBox(nullptr), nOldSize(0), nNewSize(0),
220  nMinLeft(ULONG_MAX), nMaxRight(0),
221  nCpyCnt(nCopies), nInsPos(0),
222  nLnIdx(0), nBoxIdx(0),
223  nDelBorderFlag(0), bCpyContent( true )
224  {}
225  CpyPara( const CpyPara& rPara, SwTableLine* pLine )
226  : pWidths( rPara.pWidths ), rDoc(rPara.rDoc), pTableNd(rPara.pTableNd),
227  rTabFrameArr(rPara.rTabFrameArr), pInsLine(pLine), pInsBox(rPara.pInsBox),
228  nOldSize(0), nNewSize(rPara.nNewSize), nMinLeft( rPara.nMinLeft ),
229  nMaxRight( rPara.nMaxRight ), nCpyCnt(rPara.nCpyCnt), nInsPos(0),
230  nLnIdx( rPara.nLnIdx), nBoxIdx( rPara.nBoxIdx ),
231  nDelBorderFlag( rPara.nDelBorderFlag ), bCpyContent( rPara.bCpyContent )
232  {}
233  CpyPara( const CpyPara& rPara, SwTableBox* pBox )
234  : pWidths( rPara.pWidths ), rDoc(rPara.rDoc), pTableNd(rPara.pTableNd),
235  rTabFrameArr(rPara.rTabFrameArr), pInsLine(rPara.pInsLine), pInsBox(pBox),
236  nOldSize(rPara.nOldSize), nNewSize(rPara.nNewSize),
237  nMinLeft( rPara.nMinLeft ), nMaxRight( rPara.nMaxRight ),
238  nCpyCnt(rPara.nCpyCnt), nInsPos(0), nLnIdx(rPara.nLnIdx), nBoxIdx(rPara.nBoxIdx),
239  nDelBorderFlag( rPara.nDelBorderFlag ), bCpyContent( rPara.bCpyContent )
240  {}
241 };
242 
243 }
244 
245 static void lcl_CopyRow(FndLine_ & rFndLine, CpyPara *const pCpyPara);
246 
247 static void lcl_CopyCol( FndBox_ & rFndBox, CpyPara *const pCpyPara)
248 {
249  // Look up the Frame Format in the Frame Format Array
250  SwTableBox* pBox = rFndBox.GetBox();
251  CpyTabFrame aFindFrame(pBox->GetFrameFormat());
252 
253  if( pCpyPara->nCpyCnt )
254  {
255  sal_uInt16 nFndPos;
256  CpyTabFrames::const_iterator itFind = pCpyPara->rTabFrameArr.lower_bound( aFindFrame );
257  nFndPos = itFind - pCpyPara->rTabFrameArr.begin();
258  if( itFind == pCpyPara->rTabFrameArr.end() || !(*itFind == aFindFrame) )
259  {
260  // For nested copying, also save the new Format as an old one.
261  SwTableBoxFormat* pNewFormat = static_cast<SwTableBoxFormat*>(pBox->ClaimFrameFormat());
262 
263  // Find the selected Boxes in the Line:
264  FndLine_ const* pCmpLine = nullptr;
265  SwFormatFrameSize aFrameSz( pNewFormat->GetFrameSize() );
266 
267  bool bDiffCount = false;
268  if( !pBox->GetTabLines().empty() )
269  {
270  pCmpLine = rFndBox.GetLines().front().get();
271  if ( pCmpLine->GetBoxes().size() != pCmpLine->GetLine()->GetTabBoxes().size() )
272  bDiffCount = true;
273  }
274 
275  if( bDiffCount )
276  {
277  // The first Line should be enough
278  FndBoxes_t const& rFndBoxes = pCmpLine->GetBoxes();
279  tools::Long nSz = 0;
280  for( auto n = rFndBoxes.size(); n; )
281  {
282  nSz += rFndBoxes[--n]->GetBox()->
283  GetFrameFormat()->GetFrameSize().GetWidth();
284  }
285  aFrameSz.SetWidth( aFrameSz.GetWidth() -
286  nSz / ( pCpyPara->nCpyCnt + 1 ) );
287  pNewFormat->SetFormatAttr( aFrameSz );
288  aFrameSz.SetWidth( nSz / ( pCpyPara->nCpyCnt + 1 ) );
289 
290  // Create a new Format for the new Box, specifying its size.
291  aFindFrame.pNewFrameFormat = reinterpret_cast<SwTableBoxFormat*>(pNewFormat->GetDoc()->
292  MakeTableLineFormat());
293  *aFindFrame.pNewFrameFormat = *pNewFormat;
294  aFindFrame.pNewFrameFormat->SetFormatAttr( aFrameSz );
295  }
296  else
297  {
298  aFrameSz.SetWidth( aFrameSz.GetWidth() / ( pCpyPara->nCpyCnt + 1 ) );
299  pNewFormat->SetFormatAttr( aFrameSz );
300 
301  aFindFrame.pNewFrameFormat = pNewFormat;
302  pCpyPara->rTabFrameArr.insert( aFindFrame );
303  aFindFrame.pFrameFormat = pNewFormat;
304  pCpyPara->rTabFrameArr.insert( aFindFrame );
305  }
306  }
307  else
308  {
309  aFindFrame = pCpyPara->rTabFrameArr[ nFndPos ];
310  pBox->ChgFrameFormat( aFindFrame.pNewFrameFormat );
311  }
312  }
313  else
314  {
315  CpyTabFrames::const_iterator itFind = pCpyPara->rTabFrameArr.find( aFindFrame );
316  if( pCpyPara->nDelBorderFlag &&
317  itFind != pCpyPara->rTabFrameArr.end() )
318  aFindFrame = *itFind;
319  else
320  aFindFrame.pNewFrameFormat = static_cast<SwTableBoxFormat*>(pBox->GetFrameFormat());
321  }
322 
323  if (!rFndBox.GetLines().empty())
324  {
325  pBox = new SwTableBox( aFindFrame.pNewFrameFormat,
326  rFndBox.GetLines().size(), pCpyPara->pInsLine );
327  pCpyPara->pInsLine->GetTabBoxes().insert( pCpyPara->pInsLine->GetTabBoxes().begin() + pCpyPara->nInsPos++, pBox );
328  CpyPara aPara( *pCpyPara, pBox );
329  aPara.nDelBorderFlag &= 7;
330 
331  for (auto const& pFndLine : rFndBox.GetLines())
332  {
333  lcl_CopyRow(*pFndLine, &aPara);
334  }
335  }
336  else
337  {
338  ::InsTableBox( pCpyPara->rDoc, pCpyPara->pTableNd, pCpyPara->pInsLine,
339  aFindFrame.pNewFrameFormat, pBox, pCpyPara->nInsPos++ );
340 
341  const FndBoxes_t& rFndBxs = rFndBox.GetUpper()->GetBoxes();
342  if( 8 > pCpyPara->nDelBorderFlag
343  ? pCpyPara->nDelBorderFlag != 0
344  : &rFndBox == rFndBxs[rFndBxs.size() - 1].get())
345  {
346  const SvxBoxItem& rBoxItem = pBox->GetFrameFormat()->GetBox();
347  if( 8 > pCpyPara->nDelBorderFlag
348  ? rBoxItem.GetTop()
349  : rBoxItem.GetRight() )
350  {
351  aFindFrame.pFrameFormat = pBox->GetFrameFormat();
352 
353  SvxBoxItem aNew( rBoxItem );
354  if( 8 > pCpyPara->nDelBorderFlag )
355  aNew.SetLine( nullptr, SvxBoxItemLine::TOP );
356  else
357  aNew.SetLine( nullptr, SvxBoxItemLine::RIGHT );
358 
359  if( 1 == pCpyPara->nDelBorderFlag ||
360  8 == pCpyPara->nDelBorderFlag )
361  {
362  // For all Boxes that delete TopBorderLine, we copy after that
363  pBox = pCpyPara->pInsLine->GetTabBoxes()[
364  pCpyPara->nInsPos - 1 ];
365  }
366 
367  aFindFrame.pNewFrameFormat = static_cast<SwTableBoxFormat*>(pBox->GetFrameFormat());
368 
369  // Else we copy before that and the first Line keeps the TopLine
370  // and we remove it at the original
371  pBox->ClaimFrameFormat()->SetFormatAttr( aNew );
372 
373  if( !pCpyPara->nCpyCnt )
374  pCpyPara->rTabFrameArr.insert( aFindFrame );
375  }
376  }
377  }
378 }
379 
380 static void lcl_CopyRow(FndLine_& rFndLine, CpyPara *const pCpyPara)
381 {
382  SwTableLine* pNewLine = new SwTableLine(
383  static_cast<SwTableLineFormat*>(rFndLine.GetLine()->GetFrameFormat()),
384  rFndLine.GetBoxes().size(), pCpyPara->pInsBox );
385  if( pCpyPara->pInsBox )
386  {
387  SwTableLines& rLines = pCpyPara->pInsBox->GetTabLines();
388  rLines.insert( rLines.begin() + pCpyPara->nInsPos++, pNewLine );
389  }
390  else
391  {
392  SwTableLines& rLines = pCpyPara->pTableNd->GetTable().GetTabLines();
393  rLines.insert( rLines.begin() + pCpyPara->nInsPos++, pNewLine );
394  }
395 
396  CpyPara aPara( *pCpyPara, pNewLine );
397  for (auto const& it : rFndLine.GetBoxes())
398  {
399  lcl_CopyCol(*it, &aPara);
400  }
401 
402  pCpyPara->nDelBorderFlag &= 0xf8;
403 }
404 
405 static void lcl_InsCol( FndLine_* pFndLn, CpyPara& rCpyPara, sal_uInt16 nCpyCnt,
406  bool bBehind )
407 {
408  // Bug 29124: Not only copy in the BaseLines. If possible, we go down as far as possible
409  FndBox_* pFBox;
410  if( 1 == pFndLn->GetBoxes().size() &&
411  !( pFBox = pFndLn->GetBoxes()[0].get() )->GetBox()->GetSttNd() )
412  {
413  // A Box with multiple Lines, so insert into these Lines
414  for (auto &rpLine : pFBox->GetLines())
415  {
416  lcl_InsCol( rpLine.get(), rCpyPara, nCpyCnt, bBehind );
417  }
418  }
419  else
420  {
421  rCpyPara.pInsLine = pFndLn->GetLine();
422  SwTableBox* pBox = pFndLn->GetBoxes()[ bBehind ?
423  pFndLn->GetBoxes().size()-1 : 0 ]->GetBox();
424  rCpyPara.nInsPos = pFndLn->GetLine()->GetBoxPos( pBox );
425  if( bBehind )
426  ++rCpyPara.nInsPos;
427 
428  for( sal_uInt16 n = 0; n < nCpyCnt; ++n )
429  {
430  if( n + 1 == nCpyCnt && bBehind )
431  rCpyPara.nDelBorderFlag = 9;
432  else
433  rCpyPara.nDelBorderFlag = 8;
434  for (auto const& it : pFndLn->GetBoxes())
435  {
436  lcl_CopyCol(*it, &rCpyPara);
437  }
438  }
439  }
440 }
441 
443 {
445  for( SwRowFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next() )
446  if( pFrame->GetTabLine() == &rLine )
447  return pFrame;
448  return nullptr;
449 }
450 
451 bool SwTable::InsertCol( SwDoc& rDoc, const SwSelBoxes& rBoxes, sal_uInt16 nCnt, bool bBehind )
452 {
453  OSL_ENSURE( !rBoxes.empty() && nCnt, "No valid Box List" );
454  SwTableNode* pTableNd = const_cast<SwTableNode*>(rBoxes[0]->GetSttNd()->FindTableNode());
455  if( !pTableNd )
456  return false;
457 
458  bool bRes = true;
459  if( IsNewModel() )
460  bRes = NewInsertCol( rDoc, rBoxes, nCnt, bBehind );
461  else
462  {
463  // Find all Boxes/Lines
464  FndBox_ aFndBox( nullptr, nullptr );
465  {
466  FndPara aPara( rBoxes, &aFndBox );
467  ForEach_FndLineCopyCol( GetTabLines(), &aPara );
468  }
469  if( aFndBox.GetLines().empty() )
470  return false;
471 
472  SetHTMLTableLayout(std::shared_ptr<SwHTMLTableLayout>()); // Delete HTML Layout
473 
474  // Find Lines for the layout update
475  aFndBox.SetTableLines( *this );
476  aFndBox.DelFrames( *this );
477 
478  // TL_CHART2: nothing to be done since chart2 currently does not want to
479  // get notified about new rows/cols.
480 
481  CpyTabFrames aTabFrameArr;
482  CpyPara aCpyPara( pTableNd, nCnt, aTabFrameArr );
483 
484  for (auto & rpLine : aFndBox.GetLines())
485  {
486  lcl_InsCol( rpLine.get(), aCpyPara, nCnt, bBehind );
487  }
488 
489  // clean up this Line's structure once again, generally all of them
490  GCLines();
491 
492  // Update Layout
493  aFndBox.MakeFrames( *this );
494 
497  bRes = true;
498  }
499 
501  if (pPCD && nCnt)
502  pPCD->AddRowCols( *this, rBoxes, nCnt, bBehind );
503  rDoc.UpdateCharts( GetFrameFormat()->GetName() );
504 
506 
507  return bRes;
508 }
509 
510 bool SwTable::InsertRow_( SwDoc* pDoc, const SwSelBoxes& rBoxes,
511  sal_uInt16 nCnt, bool bBehind )
512 {
513  OSL_ENSURE( pDoc && !rBoxes.empty() && nCnt, "No valid Box List" );
514  SwTableNode* pTableNd = const_cast<SwTableNode*>(rBoxes[0]->GetSttNd()->FindTableNode());
515  if( !pTableNd )
516  return false;
517 
518  // Find all Boxes/Lines
519  FndBox_ aFndBox( nullptr, nullptr );
520  {
521  FndPara aPara( rBoxes, &aFndBox );
522  ForEach_FndLineCopyCol( GetTabLines(), &aPara );
523  }
524  if( aFndBox.GetLines().empty() )
525  return false;
526 
527  SetHTMLTableLayout(std::shared_ptr<SwHTMLTableLayout>()); // Delete HTML Layout
528 
529  FndBox_* pFndBox = &aFndBox;
530  {
531  FndLine_* pFndLine;
532  while( 1 == pFndBox->GetLines().size() )
533  {
534  pFndLine = pFndBox->GetLines()[0].get();
535  if( 1 != pFndLine->GetBoxes().size() )
536  break;
537  // Don't go down too far! One Line with Box needs to remain!
538  FndBox_ *const pTmpBox = pFndLine->GetBoxes().front().get();
539  if( !pTmpBox->GetLines().empty() )
540  pFndBox = pTmpBox;
541  else
542  break;
543  }
544  }
545 
546  // Find Lines for the layout update
547  const bool bLayout = !IsNewModel() &&
548  nullptr != SwIterator<SwTabFrame,SwFormat>( *GetFrameFormat() ).First();
549 
550  if ( bLayout )
551  {
552  aFndBox.SetTableLines( *this );
553  if( pFndBox != &aFndBox )
554  aFndBox.DelFrames( *this );
555  // TL_CHART2: nothing to be done since chart2 currently does not want to
556  // get notified about new rows/cols.
557  }
558 
559  CpyTabFrames aTabFrameArr;
560  CpyPara aCpyPara( pTableNd, 0, aTabFrameArr );
561 
562  SwTableLine* pLine = pFndBox->GetLines()[ bBehind ?
563  pFndBox->GetLines().size()-1 : 0 ]->GetLine();
564  if( &aFndBox == pFndBox )
565  aCpyPara.nInsPos = GetTabLines().GetPos( pLine );
566  else
567  {
568  aCpyPara.pInsBox = pFndBox->GetBox();
569  aCpyPara.nInsPos = pFndBox->GetBox()->GetTabLines().GetPos( pLine );
570  }
571 
572  if( bBehind )
573  {
574  ++aCpyPara.nInsPos;
575  aCpyPara.nDelBorderFlag = 1;
576  }
577  else
578  aCpyPara.nDelBorderFlag = 2;
579 
580  for( sal_uInt16 nCpyCnt = 0; nCpyCnt < nCnt; ++nCpyCnt )
581  {
582  if( bBehind )
583  aCpyPara.nDelBorderFlag = 1;
584  for (auto & rpFndLine : pFndBox->GetLines())
585  lcl_CopyRow( *rpFndLine, &aCpyPara );
586  }
587 
588  // clean up this Line's structure once again, generally all of them
589  if( !pDoc->IsInReading() )
590  GCLines();
591 
592  // Update Layout
593  if ( bLayout )
594  {
595  if( pFndBox != &aFndBox )
596  aFndBox.MakeFrames( *this );
597  else
598  aFndBox.MakeNewFrames( *this, nCnt, bBehind );
599  }
600 
603 
605  if (pPCD && nCnt)
606  pPCD->AddRowCols( *this, rBoxes, nCnt, bBehind );
607  pDoc->UpdateCharts( GetFrameFormat()->GetName() );
608 
610 
611  return true;
612 }
613 
614 static void lcl_LastBoxSetWidth( SwTableBoxes &rBoxes, const tools::Long nOffset,
615  bool bFirst, SwShareBoxFormats& rShareFormats );
616 
617 static void lcl_LastBoxSetWidthLine( SwTableLines &rLines, const tools::Long nOffset,
618  bool bFirst, SwShareBoxFormats& rShareFormats )
619 {
620  for ( auto pLine : rLines )
621  ::lcl_LastBoxSetWidth( pLine->GetTabBoxes(), nOffset, bFirst, rShareFormats );
622 }
623 
624 static void lcl_LastBoxSetWidth( SwTableBoxes &rBoxes, const tools::Long nOffset,
625  bool bFirst, SwShareBoxFormats& rShareFormats )
626 {
627  SwTableBox& rBox = *(bFirst ? rBoxes.front() : rBoxes.back());
628  if( !rBox.GetSttNd() )
629  ::lcl_LastBoxSetWidthLine( rBox.GetTabLines(), nOffset,
630  bFirst, rShareFormats );
631 
632  // Adapt the Box
633  const SwFrameFormat *pBoxFormat = rBox.GetFrameFormat();
634  SwFormatFrameSize aNew( pBoxFormat->GetFrameSize() );
635  aNew.SetWidth( aNew.GetWidth() + nOffset );
636  SwFrameFormat *pFormat = rShareFormats.GetFormat( *pBoxFormat, aNew );
637  if( pFormat )
638  rBox.ChgFrameFormat( static_cast<SwTableBoxFormat*>(pFormat) );
639  else
640  {
641  pFormat = rBox.ClaimFrameFormat();
642 
643  pFormat->LockModify();
644  pFormat->SetFormatAttr( aNew );
645  pFormat->UnlockModify();
646 
647  rShareFormats.AddFormat( *pBoxFormat, *pFormat );
648  }
649 }
650 
651 void DeleteBox_( SwTable& rTable, SwTableBox* pBox, SwUndo* pUndo,
652  bool bCalcNewSize, const bool bCorrBorder,
653  SwShareBoxFormats* pShareFormats )
654 {
655  do {
656  SwTwips nBoxSz = bCalcNewSize ?
657  pBox->GetFrameFormat()->GetFrameSize().GetWidth() : 0;
658  SwTableLine* pLine = pBox->GetUpper();
659  SwTableBoxes& rTableBoxes = pLine->GetTabBoxes();
660  sal_uInt16 nDelPos = pLine->GetBoxPos( pBox );
661  SwTableBox* pUpperBox = pBox->GetUpper()->GetUpper();
662 
663  // Special treatment for the border:
664  if( bCorrBorder && 1 < rTableBoxes.size() )
665  {
666  const SvxBoxItem& rBoxItem = pBox->GetFrameFormat()->GetBox();
667 
668  if( rBoxItem.GetLeft() || rBoxItem.GetRight() )
669  {
670  bool bChgd = false;
671 
672  // JP 02.04.97: 1st part for Bug 36271
673  // First the left/right edges
674  if( nDelPos + 1 < static_cast<sal_uInt16>(rTableBoxes.size()) )
675  {
676  SwTableBox* pNxtBox = rTableBoxes[ nDelPos + 1 ];
677  const SvxBoxItem& rNxtBoxItem = pNxtBox->GetFrameFormat()->GetBox();
678 
679  SwTableBox* pPrvBox = nDelPos ? rTableBoxes[ nDelPos - 1 ] : nullptr;
680 
681  if( pNxtBox->GetSttNd() && !rNxtBoxItem.GetLeft() &&
682  ( !pPrvBox || !pPrvBox->GetFrameFormat()->GetBox().GetRight()) )
683  {
684  SvxBoxItem aTmp( rNxtBoxItem );
685  aTmp.SetLine( rBoxItem.GetLeft() ? rBoxItem.GetLeft()
686  : rBoxItem.GetRight(),
687  SvxBoxItemLine::LEFT );
688  if( pShareFormats )
689  pShareFormats->SetAttr( *pNxtBox, aTmp );
690  else
691  pNxtBox->ClaimFrameFormat()->SetFormatAttr( aTmp );
692  bChgd = true;
693  }
694  }
695  if( !bChgd && nDelPos )
696  {
697  SwTableBox* pPrvBox = rTableBoxes[ nDelPos - 1 ];
698  const SvxBoxItem& rPrvBoxItem = pPrvBox->GetFrameFormat()->GetBox();
699 
700  SwTableBox* pNxtBox = nDelPos + 1 < static_cast<sal_uInt16>(rTableBoxes.size())
701  ? rTableBoxes[ nDelPos + 1 ] : nullptr;
702 
703  if( pPrvBox->GetSttNd() && !rPrvBoxItem.GetRight() &&
704  ( !pNxtBox || !pNxtBox->GetFrameFormat()->GetBox().GetLeft()) )
705  {
706  SvxBoxItem aTmp( rPrvBoxItem );
707  aTmp.SetLine( rBoxItem.GetLeft() ? rBoxItem.GetLeft()
708  : rBoxItem.GetRight(),
709  SvxBoxItemLine::RIGHT );
710  if( pShareFormats )
711  pShareFormats->SetAttr( *pPrvBox, aTmp );
712  else
713  pPrvBox->ClaimFrameFormat()->SetFormatAttr( aTmp );
714  }
715  }
716  }
717  }
718 
719  // Delete the Box first, then the Nodes!
720  SwStartNode* pSttNd = const_cast<SwStartNode*>(pBox->GetSttNd());
721  if( pShareFormats )
722  pShareFormats->RemoveFormat( *rTableBoxes[ nDelPos ]->GetFrameFormat() );
723 
724  // Before deleting the 'Table Box' from memory - delete any redlines attached to it
726  rTable.GetFrameFormat()->GetDoc()->getIDocumentRedlineAccess().GetExtraRedlineTable().DeleteTableCellRedline( rTable.GetFrameFormat()->GetDoc(), *(rTableBoxes[nDelPos]), true, RedlineType::Any );
727  delete rTableBoxes[nDelPos];
728  rTableBoxes.erase( rTableBoxes.begin() + nDelPos );
729 
730  if( pSttNd )
731  {
732  // Has the UndoObject been prepared to save the Section?
733  if( pUndo && pUndo->IsDelBox() )
734  static_cast<SwUndoTableNdsChg*>(pUndo)->SaveSection( pSttNd );
735  else
736  pSttNd->GetDoc().getIDocumentContentOperations().DeleteSection( pSttNd );
737  }
738 
739  // Also delete the Line?
740  if( !rTableBoxes.empty() )
741  {
742  // Then adapt the Frame-SSize
743  bool bLastBox = nDelPos == rTableBoxes.size();
744  if( bLastBox )
745  --nDelPos;
746  pBox = rTableBoxes[nDelPos];
747  if( bCalcNewSize )
748  {
749  SwFormatFrameSize aNew( pBox->GetFrameFormat()->GetFrameSize() );
750  aNew.SetWidth( aNew.GetWidth() + nBoxSz );
751  if( pShareFormats )
752  pShareFormats->SetSize( *pBox, aNew );
753  else
754  pBox->ClaimFrameFormat()->SetFormatAttr( aNew );
755 
756  if( !pBox->GetSttNd() )
757  {
758  // We need to this recursively in all Lines in all Cells!
759  SwShareBoxFormats aShareFormats;
760  ::lcl_LastBoxSetWidthLine( pBox->GetTabLines(), nBoxSz,
761  !bLastBox,
762  pShareFormats ? *pShareFormats
763  : aShareFormats );
764  }
765  }
766  break; // Stop deleting
767  }
768  // Delete the Line from the Table/Box
769  if( !pUpperBox )
770  {
771  // Also delete the Line from the Table
772  nDelPos = rTable.GetTabLines().GetPos( pLine );
773  if( pShareFormats )
774  pShareFormats->RemoveFormat( *rTable.GetTabLines()[ nDelPos ]->GetFrameFormat() );
775 
776  SwTableLine* pTabLineToDelete = rTable.GetTabLines()[ nDelPos ];
777  // Before deleting the 'Table Line' from memory - delete any redlines attached to it
779  rTable.GetFrameFormat()->GetDoc()->getIDocumentRedlineAccess().GetExtraRedlineTable().DeleteTableRowRedline( rTable.GetFrameFormat()->GetDoc(), *pTabLineToDelete, true, RedlineType::Any );
780  delete pTabLineToDelete;
781  rTable.GetTabLines().erase( rTable.GetTabLines().begin() + nDelPos );
782  break; // we cannot delete more
783  }
784 
785  // finally also delete the Line
786  pBox = pUpperBox;
787  nDelPos = pBox->GetTabLines().GetPos( pLine );
788  if( pShareFormats )
789  pShareFormats->RemoveFormat( *pBox->GetTabLines()[ nDelPos ]->GetFrameFormat() );
790 
791  SwTableLine* pTabLineToDelete = pBox->GetTabLines()[ nDelPos ];
792  // Before deleting the 'Table Line' from memory - delete any redlines attached to it
794  rTable.GetFrameFormat()->GetDoc()->getIDocumentRedlineAccess().GetExtraRedlineTable().DeleteTableRowRedline( rTable.GetFrameFormat()->GetDoc(), *pTabLineToDelete, true, RedlineType::Any );
795  delete pTabLineToDelete;
796  pBox->GetTabLines().erase( pBox->GetTabLines().begin() + nDelPos );
797  } while( pBox->GetTabLines().empty() );
798 }
799 
800 static SwTableBox*
802  SwTwips nBoxStt, SwTwips nBoxWidth,
803  sal_uInt16 nLinePos, bool bNxt,
804  SwSelBoxes* pAllDelBoxes, size_t *const pCurPos)
805 {
806  SwTableBox* pFndBox = nullptr;
807  do {
808  if( bNxt )
809  ++nLinePos;
810  else
811  --nLinePos;
812  SwTableLine* pLine = rTableLns[ nLinePos ];
813  SwTwips nFndBoxWidth = 0;
814  SwTwips nFndWidth = nBoxStt + nBoxWidth;
815 
816  pFndBox = pLine->GetTabBoxes()[ 0 ];
817  for( auto pBox : pLine->GetTabBoxes() )
818  {
819  if ( nFndWidth <= 0 )
820  {
821  break;
822  }
823  pFndBox = pBox;
824  nFndBoxWidth = pFndBox->GetFrameFormat()->GetFrameSize().GetWidth();
825  nFndWidth -= nFndBoxWidth;
826  }
827 
828  // Find the first ContentBox
829  while( !pFndBox->GetSttNd() )
830  {
831  const SwTableLines& rLowLns = pFndBox->GetTabLines();
832  if( bNxt )
833  pFndBox = rLowLns.front()->GetTabBoxes().front();
834  else
835  pFndBox = rLowLns.back()->GetTabBoxes().front();
836  }
837 
838  if( std::abs( nFndWidth ) > COLFUZZY ||
839  std::abs( nBoxWidth - nFndBoxWidth ) > COLFUZZY )
840  pFndBox = nullptr;
841  else if( pAllDelBoxes )
842  {
843  // If the predecessor will also be deleted, there's nothing to do
844  SwSelBoxes::const_iterator aFndIt = pAllDelBoxes->find( pFndBox);
845  if( aFndIt == pAllDelBoxes->end() )
846  break;
847  size_t const nFndPos = aFndIt - pAllDelBoxes->begin() ;
848 
849  // else, we keep on searching.
850  // We do not need to recheck the Box, however
851  pFndBox = nullptr;
852  if( nFndPos <= *pCurPos )
853  --*pCurPos;
854  pAllDelBoxes->erase( pAllDelBoxes->begin() + nFndPos );
855  }
856  } while( bNxt ? ( nLinePos + 1 < static_cast<sal_uInt16>(rTableLns.size()) ) : nLinePos != 0 );
857  return pFndBox;
858 }
859 
860 static void
862  SwShareBoxFormats& rShareFormats,
863  SwSelBoxes* pAllDelBoxes = nullptr,
864  size_t *const pCurPos = nullptr )
865 {
866 //JP 16.04.97: 2. part for Bug 36271
867  const SwTableLine* pLine = rBox.GetUpper();
868  const SwTableBoxes& rTableBoxes = pLine->GetTabBoxes();
869  const SwTableBox* pUpperBox = &rBox;
870  sal_uInt16 nDelPos = pLine->GetBoxPos( pUpperBox );
871  pUpperBox = rBox.GetUpper()->GetUpper();
872  const SvxBoxItem& rBoxItem = rBox.GetFrameFormat()->GetBox();
873 
874  // then the top/bottom edges
875  if( !rBoxItem.GetTop() && !rBoxItem.GetBottom() )
876  return;
877 
878  bool bChgd = false;
879  const SwTableLines* pTableLns;
880  if( pUpperBox )
881  pTableLns = &pUpperBox->GetTabLines();
882  else
883  pTableLns = &rTable.GetTabLines();
884 
885  sal_uInt16 nLnPos = pTableLns->GetPos( pLine );
886 
887  // Calculate the attribute position of the top-be-deleted Box and then
888  // search in the top/bottom Line of the respective counterparts.
889  SwTwips nBoxStt = 0;
890  for( sal_uInt16 n = 0; n < nDelPos; ++n )
891  nBoxStt += rTableBoxes[ n ]->GetFrameFormat()->GetFrameSize().GetWidth();
892  SwTwips nBoxWidth = rBox.GetFrameFormat()->GetFrameSize().GetWidth();
893 
894  SwTableBox *pPrvBox = nullptr, *pNxtBox = nullptr;
895  if( nLnPos ) // Predecessor?
896  pPrvBox = ::lcl_FndNxtPrvDelBox( *pTableLns, nBoxStt, nBoxWidth,
897  nLnPos, false, pAllDelBoxes, pCurPos );
898 
899  if( nLnPos + 1 < static_cast<sal_uInt16>(pTableLns->size()) ) // Successor?
900  pNxtBox = ::lcl_FndNxtPrvDelBox( *pTableLns, nBoxStt, nBoxWidth,
901  nLnPos, true, pAllDelBoxes, pCurPos );
902 
903  if( pNxtBox && pNxtBox->GetSttNd() )
904  {
905  const SvxBoxItem& rNxtBoxItem = pNxtBox->GetFrameFormat()->GetBox();
906  if( !rNxtBoxItem.GetTop() && ( !pPrvBox ||
907  !pPrvBox->GetFrameFormat()->GetBox().GetBottom()) )
908  {
909  SvxBoxItem aTmp( rNxtBoxItem );
910  aTmp.SetLine( rBoxItem.GetTop() ? rBoxItem.GetTop()
911  : rBoxItem.GetBottom(),
912  SvxBoxItemLine::TOP );
913  rShareFormats.SetAttr( *pNxtBox, aTmp );
914  bChgd = true;
915  }
916  }
917  if( !(!bChgd && pPrvBox && pPrvBox->GetSttNd()) )
918  return;
919 
920  const SvxBoxItem& rPrvBoxItem = pPrvBox->GetFrameFormat()->GetBox();
921  if( !rPrvBoxItem.GetTop() && ( !pNxtBox ||
922  !pNxtBox->GetFrameFormat()->GetBox().GetTop()) )
923  {
924  SvxBoxItem aTmp( rPrvBoxItem );
925  aTmp.SetLine( rBoxItem.GetTop() ? rBoxItem.GetTop()
926  : rBoxItem.GetBottom(),
927  SvxBoxItemLine::BOTTOM );
928  rShareFormats.SetAttr( *pPrvBox, aTmp );
929  }
930 
931 }
932 
934  SwDoc* pDoc
935  ,
936  const SwSelBoxes& rBoxes,
937  const SwSelBoxes* pMerged, SwUndo* pUndo,
938  const bool bDelMakeFrames, const bool bCorrBorder )
939 {
940  OSL_ENSURE( pDoc, "No doc?" );
941  SwTableNode* pTableNd = nullptr;
942  if( !rBoxes.empty() )
943  {
944  pTableNd = const_cast<SwTableNode*>(rBoxes[0]->GetSttNd()->FindTableNode());
945  if( !pTableNd )
946  return false;
947  }
948 
949  SetHTMLTableLayout(std::shared_ptr<SwHTMLTableLayout>()); // Delete HTML Layout
950 
951  // Find Lines for the Layout update
952  FndBox_ aFndBox( nullptr, nullptr );
953  if ( bDelMakeFrames )
954  {
955  if( pMerged && !pMerged->empty() )
956  aFndBox.SetTableLines( *pMerged, *this );
957  else if( !rBoxes.empty() )
958  aFndBox.SetTableLines( rBoxes, *this );
959  aFndBox.DelFrames( *this );
960  }
961 
962  SwShareBoxFormats aShareFormats;
963 
964  // First switch the Border, then delete
965  if( bCorrBorder )
966  {
967  SwSelBoxes aBoxes( rBoxes );
968  for (size_t n = 0; n < aBoxes.size(); ++n)
969  {
970  ::lcl_SaveUpperLowerBorder( *this, *rBoxes[ n ], aShareFormats,
971  &aBoxes, &n );
972  }
973  }
974 
975  PrepareDelBoxes( rBoxes );
976 
978  // Delete boxes from last to first
979  for (size_t n = 0; n < rBoxes.size(); ++n)
980  {
981  size_t const nIdx = rBoxes.size() - 1 - n;
982 
983  // First adapt the data-sequence for chart if necessary
984  // (needed to move the implementation cursor properly to its new
985  // position which can't be done properly if the cell is already gone)
986  if (pPCD && pTableNd)
987  pPCD->DeleteBox( &pTableNd->GetTable(), *rBoxes[nIdx] );
988 
989  // ... then delete the boxes
990  DeleteBox_( *this, rBoxes[nIdx], pUndo, true, bCorrBorder, &aShareFormats );
991  }
992 
993  // then clean up the structure of all Lines
994  GCLines();
995 
996  if( bDelMakeFrames && aFndBox.AreLinesToRestore( *this ) )
997  aFndBox.MakeFrames( *this );
998 
999  // TL_CHART2: now inform chart that sth has changed
1000  pDoc->UpdateCharts( GetFrameFormat()->GetName() );
1001 
1003  CHECK_TABLE( *this );
1004 
1005  return true;
1006 }
1007 
1008 bool SwTable::OldSplitRow( SwDoc& rDoc, const SwSelBoxes& rBoxes, sal_uInt16 nCnt,
1009  bool bSameHeight )
1010 {
1011  OSL_ENSURE( !rBoxes.empty() && nCnt, "No valid values" );
1012  SwTableNode* pTableNd = const_cast<SwTableNode*>(rBoxes[0]->GetSttNd()->FindTableNode());
1013  if( !pTableNd )
1014  return false;
1015 
1016  // TL_CHART2: splitting/merging of a number of cells or rows will usually make
1017  // the table too complex to be handled with chart.
1018  // Thus we tell the charts to use their own data provider and forget about this table
1020 
1021  SetHTMLTableLayout(std::shared_ptr<SwHTMLTableLayout>()); // Delete HTML Layout
1022 
1023  // If the rows should get the same (min) height, we first have
1024  // to store the old row heights before deleting the frames
1025  std::unique_ptr<tools::Long[]> pRowHeights;
1026  if ( bSameHeight )
1027  {
1028  pRowHeights.reset(new tools::Long[ rBoxes.size() ]);
1029  for (size_t n = 0; n < rBoxes.size(); ++n)
1030  {
1031  SwTableBox* pSelBox = rBoxes[n];
1032  const SwRowFrame* pRow = GetRowFrame( *pSelBox->GetUpper() );
1033  OSL_ENSURE( pRow, "Where is the SwTableLine's Frame?" );
1034  SwRectFnSet aRectFnSet(pRow);
1035  pRowHeights[ n ] = aRectFnSet.GetHeight(pRow->getFrameArea());
1036  }
1037  }
1038 
1039  // Find Lines for the Layout update
1040  FndBox_ aFndBox( nullptr, nullptr );
1041  aFndBox.SetTableLines( rBoxes, *this );
1042  aFndBox.DelFrames( *this );
1043 
1044  for (size_t n = 0; n < rBoxes.size(); ++n)
1045  {
1046  SwTableBox* pSelBox = rBoxes[n];
1047  OSL_ENSURE( pSelBox, "Box is not within the Table" );
1048 
1049  // Insert nCnt new Lines into the Box
1050  SwTableLine* pInsLine = pSelBox->GetUpper();
1051  SwTableBoxFormat* pFrameFormat = static_cast<SwTableBoxFormat*>(pSelBox->GetFrameFormat());
1052 
1053  // Respect the Line's height, reset if needed
1054  SwFormatFrameSize aFSz( pInsLine->GetFrameFormat()->GetFrameSize() );
1055  if ( bSameHeight && SwFrameSize::Variable == aFSz.GetHeightSizeType() )
1057 
1058  bool bChgLineSz = 0 != aFSz.GetHeight() || bSameHeight;
1059  if ( bChgLineSz )
1060  aFSz.SetHeight( ( bSameHeight ? pRowHeights[ n ] : aFSz.GetHeight() ) /
1061  (nCnt + 1) );
1062 
1063  SwTableBox* pNewBox = new SwTableBox( pFrameFormat, nCnt, pInsLine );
1064  sal_uInt16 nBoxPos = pInsLine->GetBoxPos( pSelBox );
1065  pInsLine->GetTabBoxes()[nBoxPos] = pNewBox; // overwrite old one
1066 
1067  // Delete background/border attribute
1068  SwTableBox* pLastBox = pSelBox; // To distribute the TextNodes!
1069  // If Areas are contained in the Box, it stays as is
1070  // !! If this is changed we need to adapt the Undo, too !!!
1071  bool bMoveNodes = true;
1072  {
1073  sal_uLong nSttNd = pLastBox->GetSttIdx() + 1,
1074  nEndNd = pLastBox->GetSttNd()->EndOfSectionIndex();
1075  while( nSttNd < nEndNd )
1076  if( !rDoc.GetNodes()[ nSttNd++ ]->IsTextNode() )
1077  {
1078  bMoveNodes = false;
1079  break;
1080  }
1081  }
1082 
1083  SwTableBoxFormat* pCpyBoxFrameFormat = static_cast<SwTableBoxFormat*>(pSelBox->GetFrameFormat());
1084  bool bChkBorder = nullptr != pCpyBoxFrameFormat->GetBox().GetTop();
1085  if( bChkBorder )
1086  pCpyBoxFrameFormat = static_cast<SwTableBoxFormat*>(pSelBox->ClaimFrameFormat());
1087 
1088  for( sal_uInt16 i = 0; i <= nCnt; ++i )
1089  {
1090  // Create a new Line in the new Box
1091  SwTableLine* pNewLine = new SwTableLine(
1092  static_cast<SwTableLineFormat*>(pInsLine->GetFrameFormat()), 1, pNewBox );
1093  if( bChgLineSz )
1094  {
1095  pNewLine->ClaimFrameFormat()->SetFormatAttr( aFSz );
1096  }
1097 
1098  pNewBox->GetTabLines().insert( pNewBox->GetTabLines().begin() + i, pNewLine );
1099  // then a new Box in the Line
1100  if( !i ) // hang up the original Box
1101  {
1102  pSelBox->SetUpper( pNewLine );
1103  pNewLine->GetTabBoxes().insert( pNewLine->GetTabBoxes().begin(), pSelBox );
1104  }
1105  else
1106  {
1107  ::InsTableBox( rDoc, pTableNd, pNewLine, pCpyBoxFrameFormat,
1108  pLastBox, 0 );
1109 
1110  if( bChkBorder )
1111  {
1112  pCpyBoxFrameFormat = static_cast<SwTableBoxFormat*>(pNewLine->GetTabBoxes()[ 0 ]->ClaimFrameFormat());
1113  SvxBoxItem aTmp( pCpyBoxFrameFormat->GetBox() );
1114  aTmp.SetLine( nullptr, SvxBoxItemLine::TOP );
1115  pCpyBoxFrameFormat->SetFormatAttr( aTmp );
1116  bChkBorder = false;
1117  }
1118 
1119  if( bMoveNodes )
1120  {
1121  const SwNode* pEndNd = pLastBox->GetSttNd()->EndOfSectionNode();
1122  if( pLastBox->GetSttIdx()+2 != pEndNd->GetIndex() )
1123  {
1124  // Move TextNodes
1125  SwNodeRange aRg( *pLastBox->GetSttNd(), +2, *pEndNd );
1126  pLastBox = pNewLine->GetTabBoxes()[0]; // reset
1127  SwNodeIndex aInsPos( *pLastBox->GetSttNd(), 1 );
1128  rDoc.GetNodes().MoveNodes(aRg, rDoc.GetNodes(), aInsPos, false);
1129  rDoc.GetNodes().Delete( aInsPos ); // delete the empty one
1130  }
1131  }
1132  }
1133  }
1134  // In Boxes with Lines, we can only have Size/Fillorder
1135  pFrameFormat = static_cast<SwTableBoxFormat*>(pNewBox->ClaimFrameFormat());
1136  pFrameFormat->ResetFormatAttr( RES_LR_SPACE, RES_FRMATR_END - 1 );
1137  pFrameFormat->ResetFormatAttr( RES_BOXATR_BEGIN, RES_BOXATR_END - 1 );
1138  }
1139 
1140  pRowHeights.reset();
1141 
1142  GCLines();
1143 
1144  aFndBox.MakeFrames( *this );
1145 
1148  return true;
1149 }
1150 
1151 bool SwTable::SplitCol(SwDoc& rDoc, const SwSelBoxes& rBoxes, sal_uInt16 nCnt)
1152 {
1153  OSL_ENSURE( !rBoxes.empty() && nCnt, "No valid values" );
1154  SwTableNode* pTableNd = const_cast<SwTableNode*>(rBoxes[0]->GetSttNd()->FindTableNode());
1155  if( !pTableNd )
1156  return false;
1157 
1158  // TL_CHART2: splitting/merging of a number of cells or rows will usually make
1159  // the table too complex to be handled with chart.
1160  // Thus we tell the charts to use their own data provider and forget about this table
1162 
1163  SetHTMLTableLayout(std::shared_ptr<SwHTMLTableLayout>()); // Delete HTML Layout
1164  SwSelBoxes aSelBoxes(rBoxes);
1165  ExpandSelection( aSelBoxes );
1166 
1167  // Find Lines for the Layout update
1168  FndBox_ aFndBox( nullptr, nullptr );
1169  aFndBox.SetTableLines( aSelBoxes, *this );
1170  aFndBox.DelFrames( *this );
1171 
1172  CpyTabFrames aFrameArr;
1173  std::vector<SwTableBoxFormat*> aLastBoxArr;
1174  for (size_t n = 0; n < aSelBoxes.size(); ++n)
1175  {
1176  SwTableBox* pSelBox = aSelBoxes[n];
1177  OSL_ENSURE( pSelBox, "Box is not in the table" );
1178 
1179  // We don't want to split small table cells into very very small cells
1180  if( pSelBox->GetFrameFormat()->GetFrameSize().GetWidth()/( nCnt + 1 ) < 10 )
1181  continue;
1182 
1183  // Then split the nCnt Box up into nCnt Boxes
1184  SwTableLine* pInsLine = pSelBox->GetUpper();
1185  sal_uInt16 nBoxPos = pInsLine->GetBoxPos( pSelBox );
1186 
1187  // Find the Frame Format in the Frame Format Array
1188  SwTableBoxFormat* pLastBoxFormat;
1189  CpyTabFrame aFindFrame( static_cast<SwTableBoxFormat*>(pSelBox->GetFrameFormat()) );
1190  CpyTabFrames::const_iterator itFind = aFrameArr.lower_bound( aFindFrame );
1191  const size_t nFndPos = itFind - aFrameArr.begin();
1192  if( itFind == aFrameArr.end() || !(*itFind == aFindFrame) )
1193  {
1194  // Change the FrameFormat
1195  aFindFrame.pNewFrameFormat = static_cast<SwTableBoxFormat*>(pSelBox->ClaimFrameFormat());
1196  SwTwips nBoxSz = aFindFrame.pNewFrameFormat->GetFrameSize().GetWidth();
1197  SwTwips nNewBoxSz = nBoxSz / ( nCnt + 1 );
1198  aFindFrame.pNewFrameFormat->SetFormatAttr( SwFormatFrameSize( SwFrameSize::Variable,
1199  nNewBoxSz, 0 ) );
1200  aFrameArr.insert( aFindFrame );
1201 
1202  pLastBoxFormat = aFindFrame.pNewFrameFormat;
1203  if( nBoxSz != ( nNewBoxSz * (nCnt + 1)))
1204  {
1205  // We have a remainder, so we need to define an own Format
1206  // for the last Box.
1207  pLastBoxFormat = new SwTableBoxFormat( *aFindFrame.pNewFrameFormat );
1209  nBoxSz - ( nNewBoxSz * nCnt ), 0 ) );
1210  }
1211  aLastBoxArr.insert( aLastBoxArr.begin() + nFndPos, pLastBoxFormat );
1212  }
1213  else
1214  {
1215  aFindFrame = aFrameArr[ nFndPos ];
1216  pSelBox->ChgFrameFormat( aFindFrame.pNewFrameFormat );
1217  pLastBoxFormat = aLastBoxArr[ nFndPos ];
1218  }
1219 
1220  // Insert the Boxes at the Position
1221  for( sal_uInt16 i = 1; i < nCnt; ++i )
1222  ::InsTableBox( rDoc, pTableNd, pInsLine, aFindFrame.pNewFrameFormat,
1223  pSelBox, nBoxPos + i ); // insert after
1224 
1225  ::InsTableBox( rDoc, pTableNd, pInsLine, pLastBoxFormat,
1226  pSelBox, nBoxPos + nCnt ); // insert after
1227 
1228  // Special treatment for the Border:
1229  const SvxBoxItem& aSelBoxItem = aFindFrame.pNewFrameFormat->GetBox();
1230  if( aSelBoxItem.GetRight() )
1231  {
1232  pInsLine->GetTabBoxes()[ nBoxPos + nCnt ]->ClaimFrameFormat();
1233 
1234  SvxBoxItem aTmp( aSelBoxItem );
1235  aTmp.SetLine( nullptr, SvxBoxItemLine::RIGHT );
1236  aFindFrame.pNewFrameFormat->SetFormatAttr( aTmp );
1237 
1238  // Remove the Format from the "cache"
1239  for( auto i = aFrameArr.size(); i; )
1240  {
1241  const CpyTabFrame& rCTF = aFrameArr[ --i ];
1242  if( rCTF.pNewFrameFormat == aFindFrame.pNewFrameFormat ||
1243  rCTF.pFrameFormat == aFindFrame.pNewFrameFormat )
1244  {
1245  aFrameArr.erase( aFrameArr.begin() + i );
1246  aLastBoxArr.erase( aLastBoxArr.begin() + i );
1247  }
1248  }
1249  }
1250  }
1251 
1252  // Update Layout
1253  aFndBox.MakeFrames( *this );
1254 
1257  return true;
1258 }
1259 
1260 /*
1261  * >> MERGE <<
1262  * Algorithm:
1263  * If we only have one Line in the FndBox_, take this Line and test
1264  * the Box count:
1265  * If we have more than one Box, we merge on Box level, meaning
1266  * the new Box will be as wide as the old ones.
1267  * All Lines that are above/under the Area, are inserted into
1268  * the Box as Line + Box.
1269  * All Lines that come before/after the Area, are inserted into
1270  * the Boxes Left/Right.
1271  *
1272  * >> MERGE <<
1273  */
1274 static void lcl_CpyLines( sal_uInt16 nStt, sal_uInt16 nEnd,
1275  SwTableLines& rLines,
1276  SwTableBox* pInsBox,
1277  sal_uInt16 nPos = USHRT_MAX )
1278 {
1279  for( sal_uInt16 n = nStt; n < nEnd; ++n )
1280  rLines[n]->SetUpper( pInsBox );
1281  if( USHRT_MAX == nPos )
1282  nPos = pInsBox->GetTabLines().size();
1283  pInsBox->GetTabLines().insert( pInsBox->GetTabLines().begin() + nPos,
1284  rLines.begin() + nStt, rLines.begin() + nEnd );
1285  rLines.erase( rLines.begin() + nStt, rLines.begin() + nEnd );
1286 }
1287 
1288 static void lcl_CpyBoxes( sal_uInt16 nStt, sal_uInt16 nEnd,
1289  SwTableBoxes& rBoxes,
1290  SwTableLine* pInsLine )
1291 {
1292  for( sal_uInt16 n = nStt; n < nEnd; ++n )
1293  rBoxes[n]->SetUpper( pInsLine );
1294  sal_uInt16 nPos = pInsLine->GetTabBoxes().size();
1295  pInsLine->GetTabBoxes().insert( pInsLine->GetTabBoxes().begin() + nPos,
1296  rBoxes.begin() + nStt, rBoxes.begin() + nEnd );
1297  rBoxes.erase( rBoxes.begin() + nStt, rBoxes.begin() + nEnd );
1298 }
1299 
1300 static void lcl_CalcWidth( SwTableBox* pBox )
1301 {
1302  // Assertion: Every Line in the Box is as large
1303  SwFrameFormat* pFormat = pBox->ClaimFrameFormat();
1304  OSL_ENSURE( pBox->GetTabLines().size(), "Box does not have any Lines" );
1305 
1306  SwTableLine* pLine = pBox->GetTabLines()[0];
1307  OSL_ENSURE( pLine, "Box is not within a Line" );
1308 
1309  tools::Long nWidth = 0;
1310  for( auto pTabBox : pLine->GetTabBoxes() )
1311  nWidth += pTabBox->GetFrameFormat()->GetFrameSize().GetWidth();
1312 
1313  pFormat->SetFormatAttr( SwFormatFrameSize( SwFrameSize::Variable, nWidth, 0 ));
1314 
1315  // Boxes with Lines can only have Size/Fillorder
1316  pFormat->ResetFormatAttr( RES_LR_SPACE, RES_FRMATR_END - 1 );
1318 }
1319 
1320 namespace {
1321 
1322 struct InsULPara
1323 {
1324  SwTableNode* pTableNd;
1325  SwTableLine* pInsLine;
1326  SwTableBox* pInsBox;
1327  bool bUL_LR : 1; // Upper-Lower(true) or Left-Right(false) ?
1328  bool bUL : 1; // Upper-Left(true) or Lower-Right(false) ?
1329 
1330  SwTableBox* pLeftBox;
1331 
1332  InsULPara( SwTableNode* pTNd,
1333  SwTableBox* pLeft,
1334  SwTableLine* pLine )
1335  : pTableNd( pTNd ), pInsLine( pLine ), pInsBox( nullptr ),
1336  pLeftBox( pLeft )
1337  { bUL_LR = true; bUL = true; }
1338 
1339  void SetLeft( SwTableBox* pBox )
1340  { bUL_LR = false; bUL = true; if( pBox ) pInsBox = pBox; }
1341  void SetRight( SwTableBox* pBox )
1342  { bUL_LR = false; bUL = false; if( pBox ) pInsBox = pBox; }
1343  void SetLower( SwTableLine* pLine )
1344  { bUL_LR = true; bUL = false; if( pLine ) pInsLine = pLine; }
1345 };
1346 
1347 }
1348 
1349 static void lcl_Merge_MoveLine(FndLine_ & rFndLine, InsULPara *const pULPara);
1350 
1351 static void lcl_Merge_MoveBox(FndBox_ & rFndBox, InsULPara *const pULPara)
1352 {
1353  SwTableBoxes* pBoxes;
1354 
1355  sal_uInt16 nStt = 0, nEnd = rFndBox.GetLines().size();
1356  sal_uInt16 nInsPos = USHRT_MAX;
1357  if( !pULPara->bUL_LR ) // Left/Right
1358  {
1359  sal_uInt16 nPos;
1360  SwTableBox* pFndTableBox = rFndBox.GetBox();
1361  pBoxes = &pFndTableBox->GetUpper()->GetTabBoxes();
1362  if( pULPara->bUL ) // Left ?
1363  {
1364  // if there are Boxes before it, move them
1365  nPos = pFndTableBox->GetUpper()->GetBoxPos( pFndTableBox );
1366  if( 0 != nPos )
1367  lcl_CpyBoxes( 0, nPos, *pBoxes, pULPara->pInsLine );
1368  }
1369  else // Right
1370  {
1371  // if there are Boxes behind it, move them
1372  nPos = pFndTableBox->GetUpper()->GetBoxPos( pFndTableBox );
1373  if( nPos +1 < static_cast<sal_uInt16>(pBoxes->size()) )
1374  {
1375  nInsPos = pULPara->pInsLine->GetTabBoxes().size();
1376  lcl_CpyBoxes( nPos+1, pBoxes->size(),
1377  *pBoxes, pULPara->pInsLine );
1378  }
1379  }
1380  }
1381  // Upper/Lower and still deeper?
1382  else if (!rFndBox.GetLines().empty())
1383  {
1384  // Only search the Line from which we need to move
1385  nStt = pULPara->bUL ? 0 : rFndBox.GetLines().size()-1;
1386  nEnd = nStt+1;
1387  }
1388 
1389  pBoxes = &pULPara->pInsLine->GetTabBoxes();
1390 
1391  // Is there still a level to step down to?
1392  if (rFndBox.GetBox()->GetTabLines().empty())
1393  return;
1394 
1395  SwTableBox* pBox = new SwTableBox(
1396  static_cast<SwTableBoxFormat*>(rFndBox.GetBox()->GetFrameFormat()),
1397  0, pULPara->pInsLine );
1398  InsULPara aPara( *pULPara );
1399  aPara.pInsBox = pBox;
1400  for (FndLines_t::iterator it = rFndBox.GetLines().begin() + nStt;
1401  it != rFndBox.GetLines().begin() + nEnd; ++it )
1402  {
1403  lcl_Merge_MoveLine(**it, &aPara);
1404  }
1405  if( !pBox->GetTabLines().empty() )
1406  {
1407  if( USHRT_MAX == nInsPos )
1408  nInsPos = pBoxes->size();
1409  pBoxes->insert( pBoxes->begin() + nInsPos, pBox );
1410  lcl_CalcWidth( pBox ); // calculate the Box's width
1411  }
1412  else
1413  delete pBox;
1414 }
1415 
1416 static void lcl_Merge_MoveLine(FndLine_& rFndLine, InsULPara *const pULPara)
1417 {
1418  SwTableLines* pLines;
1419 
1420  sal_uInt16 nStt = 0, nEnd = rFndLine.GetBoxes().size();
1421  sal_uInt16 nInsPos = USHRT_MAX;
1422  if( pULPara->bUL_LR ) // UpperLower ?
1423  {
1424  sal_uInt16 nPos;
1425  SwTableLine* pFndLn = rFndLine.GetLine();
1426  pLines = pFndLn->GetUpper() ?
1427  &pFndLn->GetUpper()->GetTabLines() :
1428  &pULPara->pTableNd->GetTable().GetTabLines();
1429 
1430  SwTableBox* pLBx = rFndLine.GetBoxes().front()->GetBox();
1431  SwTableBox* pRBx = rFndLine.GetBoxes().back()->GetBox();
1432  sal_uInt16 nLeft = pFndLn->GetBoxPos( pLBx );
1433  sal_uInt16 nRight = pFndLn->GetBoxPos( pRBx );
1434 
1435  if( !nLeft || nRight == pFndLn->GetTabBoxes().size() )
1436  {
1437  if( pULPara->bUL ) // Upper ?
1438  {
1439  // If there are Lines before it, move them
1440  nPos = pLines->GetPos( pFndLn );
1441  if( 0 != nPos )
1442  lcl_CpyLines( 0, nPos, *pLines, pULPara->pInsBox );
1443  }
1444  else
1445  // If there are Lines after it, move them
1446  if( (nPos = pLines->GetPos( pFndLn )) + 1 < static_cast<sal_uInt16>(pLines->size()) )
1447  {
1448  nInsPos = pULPara->pInsBox->GetTabLines().size();
1449  lcl_CpyLines( nPos+1, pLines->size(), *pLines,
1450  pULPara->pInsBox );
1451  }
1452  }
1453  else
1454  {
1455  // There are still Boxes on the left side, so put the Left-
1456  // and Merge-Box into one Box and Line, insert before/after
1457  // a Line with a Box, into which the upper/lower Lines are
1458  // inserted
1459  SwTableLine* pInsLine = pULPara->pLeftBox->GetUpper();
1460  SwTableBox* pLMBox = new SwTableBox(
1461  static_cast<SwTableBoxFormat*>(pULPara->pLeftBox->GetFrameFormat()), 0, pInsLine );
1462  SwTableLine* pLMLn = new SwTableLine(
1463  static_cast<SwTableLineFormat*>(pInsLine->GetFrameFormat()), 2, pLMBox );
1465 
1466  pLMBox->GetTabLines().insert( pLMBox->GetTabLines().begin(), pLMLn );
1467 
1468  lcl_CpyBoxes( 0, 2, pInsLine->GetTabBoxes(), pLMLn );
1469 
1470  pInsLine->GetTabBoxes().insert( pInsLine->GetTabBoxes().begin(), pLMBox );
1471 
1472  if( pULPara->bUL ) // Upper ?
1473  {
1474  // If there are Lines before it, move them
1475  nPos = pLines->GetPos( pFndLn );
1476  if( 0 != nPos )
1477  lcl_CpyLines( 0, nPos, *pLines, pLMBox, 0 );
1478  }
1479  else
1480  // If there are Lines after it, move them
1481  if( (nPos = pLines->GetPos( pFndLn )) + 1 < static_cast<sal_uInt16>(pLines->size()) )
1482  lcl_CpyLines( nPos+1, pLines->size(), *pLines,
1483  pLMBox );
1484  lcl_CalcWidth( pLMBox ); // calculate the Box's width
1485  }
1486  }
1487  // Left/Right
1488  else
1489  {
1490  // Find only the Line from which we need to move
1491  nStt = pULPara->bUL ? 0 : rFndLine.GetBoxes().size()-1;
1492  nEnd = nStt+1;
1493  }
1494  pLines = &pULPara->pInsBox->GetTabLines();
1495 
1496  SwTableLine* pNewLine = new SwTableLine(
1497  static_cast<SwTableLineFormat*>(rFndLine.GetLine()->GetFrameFormat()), 0, pULPara->pInsBox );
1498  InsULPara aPara( *pULPara ); // copying
1499  aPara.pInsLine = pNewLine;
1500  FndBoxes_t & rLineBoxes = rFndLine.GetBoxes();
1501  for (FndBoxes_t::iterator it = rLineBoxes.begin() + nStt;
1502  it != rLineBoxes.begin() + nEnd; ++it)
1503  {
1504  lcl_Merge_MoveBox(**it, &aPara);
1505  }
1506 
1507  if( !pNewLine->GetTabBoxes().empty() )
1508  {
1509  if( USHRT_MAX == nInsPos )
1510  nInsPos = pLines->size();
1511  pLines->insert( pLines->begin() + nInsPos, pNewLine );
1512  }
1513  else
1514  delete pNewLine;
1515 }
1516 
1517 static void lcl_BoxSetHeadCondColl( const SwTableBox* pBox );
1518 
1519 bool SwTable::OldMerge( SwDoc* pDoc, const SwSelBoxes& rBoxes,
1520  SwTableBox* pMergeBox, SwUndoTableMerge* pUndo )
1521 {
1522  OSL_ENSURE( !rBoxes.empty() && pMergeBox, "no valid values" );
1523  SwTableNode* pTableNd = const_cast<SwTableNode*>(rBoxes[0]->GetSttNd()->FindTableNode());
1524  if( !pTableNd )
1525  return false;
1526 
1527  // Find all Boxes/Lines
1528  FndBox_ aFndBox( nullptr, nullptr );
1529  {
1530  FndPara aPara( rBoxes, &aFndBox );
1531  ForEach_FndLineCopyCol( GetTabLines(), &aPara );
1532  }
1533  if( aFndBox.GetLines().empty() )
1534  return false;
1535 
1536  // TL_CHART2: splitting/merging of a number of cells or rows will usually make
1537  // the table too complex to be handled with chart.
1538  // Thus we tell the charts to use their own data provider and forget about this table
1540 
1541  SetHTMLTableLayout(std::shared_ptr<SwHTMLTableLayout>()); // Delete HTML Layout
1542 
1543  if( pUndo )
1544  pUndo->SetSelBoxes( rBoxes );
1545 
1546  // Find Lines for the Layout update
1547  aFndBox.SetTableLines( *this );
1548  aFndBox.DelFrames( *this );
1549 
1550  FndBox_* pFndBox = &aFndBox;
1551  while( 1 == pFndBox->GetLines().size() &&
1552  1 == pFndBox->GetLines().front()->GetBoxes().size() )
1553  {
1554  pFndBox = pFndBox->GetLines().front()->GetBoxes().front().get();
1555  }
1556 
1557  SwTableLine* pInsLine = new SwTableLine(
1558  static_cast<SwTableLineFormat*>(pFndBox->GetLines().front()->GetLine()->GetFrameFormat()), 0,
1559  !pFndBox->GetUpper() ? nullptr : pFndBox->GetBox() );
1561 
1562  // Add the new Line
1563  SwTableLines* pLines = pFndBox->GetUpper() ?
1564  &pFndBox->GetBox()->GetTabLines() : &GetTabLines();
1565 
1566  SwTableLine* pNewLine = pFndBox->GetLines().front()->GetLine();
1567  sal_uInt16 nInsPos = pLines->GetPos( pNewLine );
1568  pLines->insert( pLines->begin() + nInsPos, pInsLine );
1569 
1570  SwTableBox* pLeftBox = new SwTableBox( static_cast<SwTableBoxFormat*>(pMergeBox->GetFrameFormat()), 0, pInsLine );
1571  SwTableBox* pRightBox = new SwTableBox( static_cast<SwTableBoxFormat*>(pMergeBox->GetFrameFormat()), 0, pInsLine );
1572  pMergeBox->SetUpper( pInsLine );
1573  pInsLine->GetTabBoxes().insert( pInsLine->GetTabBoxes().begin(), pLeftBox );
1574  pLeftBox->ClaimFrameFormat();
1575  pInsLine->GetTabBoxes().insert( pInsLine->GetTabBoxes().begin() + 1, pMergeBox);
1576  pInsLine->GetTabBoxes().insert( pInsLine->GetTabBoxes().begin() + 2, pRightBox );
1577  pRightBox->ClaimFrameFormat();
1578 
1579  // This contains all Lines that are above the selected Area,
1580  // thus they form a Upper/Lower Line
1581  InsULPara aPara( pTableNd, pLeftBox, pInsLine );
1582 
1583  // Move the overlapping upper/lower Lines of the selected Area
1584  for (auto & it : pFndBox->GetLines().front()->GetBoxes())
1585  {
1586  lcl_Merge_MoveBox(*it, &aPara);
1587  }
1588  aPara.SetLower( pInsLine );
1589  const auto nEnd = pFndBox->GetLines().size()-1;
1590  for (auto & it : pFndBox->GetLines()[nEnd]->GetBoxes())
1591  {
1592  lcl_Merge_MoveBox(*it, &aPara);
1593  }
1594 
1595  // Move the Boxes extending into the selected Area from left/right
1596  aPara.SetLeft( pLeftBox );
1597  for (auto & rpFndLine : pFndBox->GetLines())
1598  {
1599  lcl_Merge_MoveLine( *rpFndLine, &aPara );
1600  }
1601 
1602  aPara.SetRight( pRightBox );
1603  for (auto & rpFndLine : pFndBox->GetLines())
1604  {
1605  lcl_Merge_MoveLine( *rpFndLine, &aPara );
1606  }
1607 
1608  if( pLeftBox->GetTabLines().empty() )
1609  DeleteBox_( *this, pLeftBox, nullptr, false, false );
1610  else
1611  {
1612  lcl_CalcWidth( pLeftBox ); // calculate the Box's width
1613  if( pUndo && pLeftBox->GetSttNd() )
1614  pUndo->AddNewBox( pLeftBox->GetSttIdx() );
1615  }
1616  if( pRightBox->GetTabLines().empty() )
1617  DeleteBox_( *this, pRightBox, nullptr, false, false );
1618  else
1619  {
1620  lcl_CalcWidth( pRightBox ); // calculate the Box's width
1621  if( pUndo && pRightBox->GetSttNd() )
1622  pUndo->AddNewBox( pRightBox->GetSttIdx() );
1623  }
1624 
1625  DeleteSel( pDoc, rBoxes, nullptr, nullptr, false, false );
1626 
1627  // Clean up this Line's structure once again, generally all of them
1628  GCLines();
1629 
1630  for( const auto& rpBox : GetTabLines()[0]->GetTabBoxes() )
1631  lcl_BoxSetHeadCondColl(rpBox);
1632 
1633  aFndBox.MakeFrames( *this );
1634 
1637 
1638  return true;
1639 }
1640 
1641 static void lcl_CheckRowSpan( SwTable &rTable )
1642 {
1643  const tools::Long nLineCount = static_cast<tools::Long>(rTable.GetTabLines().size());
1644  tools::Long nMaxSpan = nLineCount;
1645  tools::Long nMinSpan = 1;
1646  while( nMaxSpan )
1647  {
1648  SwTableLine* pLine = rTable.GetTabLines()[ nLineCount - nMaxSpan ];
1649  for( auto pBox : pLine->GetTabBoxes() )
1650  {
1651  sal_Int32 nRowSpan = pBox->getRowSpan();
1652  if( nRowSpan > nMaxSpan )
1653  pBox->setRowSpan( nMaxSpan );
1654  else if( nRowSpan < nMinSpan )
1655  pBox->setRowSpan( nMinSpan > 0 ? nMaxSpan : nMinSpan );
1656  }
1657  --nMaxSpan;
1658  nMinSpan = -nMaxSpan;
1659  }
1660 }
1661 
1662 static sal_uInt16 lcl_GetBoxOffset( const FndBox_& rBox )
1663 {
1664  // Find the first Box
1665  const FndBox_* pFirstBox = &rBox;
1666  while (!pFirstBox->GetLines().empty())
1667  {
1668  pFirstBox = pFirstBox->GetLines().front()->GetBoxes().front().get();
1669  }
1670 
1671  sal_uInt16 nRet = 0;
1672  // Calculate the position relative to above via the Lines
1673  const SwTableBox* pBox = pFirstBox->GetBox();
1674  do {
1675  const SwTableBoxes& rBoxes = pBox->GetUpper()->GetTabBoxes();
1676  for( auto pCmp : rBoxes )
1677  {
1678  if (pBox==pCmp)
1679  break;
1680  nRet = nRet + static_cast<sal_uInt16>(pCmp->GetFrameFormat()->GetFrameSize().GetWidth());
1681  }
1682  pBox = pBox->GetUpper()->GetUpper();
1683  } while( pBox );
1684  return nRet;
1685 }
1686 
1687 static sal_uInt16 lcl_GetLineWidth( const FndLine_& rLine )
1688 {
1689  sal_uInt16 nRet = 0;
1690  for( auto n = rLine.GetBoxes().size(); n; )
1691  {
1692  nRet = nRet + static_cast<sal_uInt16>(rLine.GetBoxes()[--n]->GetBox()
1693  ->GetFrameFormat()->GetFrameSize().GetWidth());
1694  }
1695  return nRet;
1696 }
1697 
1698 static void lcl_CalcNewWidths(const FndLines_t& rFndLines, CpyPara& rPara)
1699 {
1700  rPara.pWidths.reset();
1701  const size_t nLineCount = rFndLines.size();
1702  if( nLineCount )
1703  {
1704  rPara.pWidths = std::make_shared< std::vector< std::vector< sal_uLong > > >
1705  ( nLineCount );
1706  // First we collect information about the left/right borders of all
1707  // selected cells
1708  for( size_t nLine = 0; nLine < nLineCount; ++nLine )
1709  {
1710  std::vector< sal_uLong > &rWidth = (*rPara.pWidths)[ nLine ];
1711  const FndLine_ *pFndLine = rFndLines[ nLine ].get();
1712  if( pFndLine && !pFndLine->GetBoxes().empty() )
1713  {
1714  const SwTableLine *pLine = pFndLine->GetLine();
1715  if( pLine && !pLine->GetTabBoxes().empty() )
1716  {
1717  size_t nBoxCount = pLine->GetTabBoxes().size();
1718  sal_uLong nPos = 0;
1719  // The first selected box...
1720  const SwTableBox *const pSel =
1721  pFndLine->GetBoxes().front()->GetBox();
1722  size_t nBox = 0;
1723  // Sum up the width of all boxes before the first selected box
1724  while( nBox < nBoxCount )
1725  {
1726  SwTableBox* pBox = pLine->GetTabBoxes()[nBox++];
1727  if( pBox != pSel )
1728  nPos += pBox->GetFrameFormat()->GetFrameSize().GetWidth();
1729  else
1730  break;
1731  }
1732  // nPos is now the left border of the first selected box
1733  if( rPara.nMinLeft > nPos )
1734  rPara.nMinLeft = nPos;
1735  nBoxCount = pFndLine->GetBoxes().size();
1736  rWidth = std::vector< sal_uLong >( nBoxCount+2 );
1737  rWidth[ 0 ] = nPos;
1738  // Add now the widths of all selected boxes and store
1739  // the positions in the vector
1740  for( nBox = 0; nBox < nBoxCount; )
1741  {
1742  nPos += pFndLine->GetBoxes()[nBox]
1743  ->GetBox()->GetFrameFormat()->GetFrameSize().GetWidth();
1744  rWidth[ ++nBox ] = nPos;
1745  }
1746  // nPos: The right border of the last selected box
1747  if( rPara.nMaxRight < nPos )
1748  rPara.nMaxRight = nPos;
1749  if( nPos <= rWidth[ 0 ] )
1750  rWidth.clear();
1751  }
1752  }
1753  }
1754  }
1755  // Second step: calculate the new widths for the copied cells
1756  sal_uLong nSelSize = rPara.nMaxRight - rPara.nMinLeft;
1757  if( !nSelSize )
1758  return;
1759 
1760  for( size_t nLine = 0; nLine < nLineCount; ++nLine )
1761  {
1762  std::vector< sal_uLong > &rWidth = (*rPara.pWidths)[ nLine ];
1763  const size_t nCount = rWidth.size();
1764  if( nCount > 2 )
1765  {
1766  rWidth[ nCount - 1 ] = rPara.nMaxRight;
1767  sal_uLong nLastPos = 0;
1768  for( size_t nBox = 0; nBox < nCount; ++nBox )
1769  {
1770  sal_uInt64 nNextPos = rWidth[ nBox ];
1771  nNextPos -= rPara.nMinLeft;
1772  nNextPos *= rPara.nNewSize;
1773  nNextPos /= nSelSize;
1774  rWidth[ nBox ] = static_cast<sal_uLong>(nNextPos - nLastPos);
1775  nLastPos = static_cast<sal_uLong>(nNextPos);
1776  }
1777  }
1778  }
1779 }
1780 
1781 static void
1782 lcl_CopyLineToDoc(FndLine_ const& rpFndLn, CpyPara *const pCpyPara);
1783 
1784 static void lcl_CopyBoxToDoc(FndBox_ const& rFndBox, CpyPara *const pCpyPara)
1785 {
1786  // Calculation of new size
1787  sal_uLong nRealSize;
1788  sal_uLong nDummy1 = 0;
1789  sal_uLong nDummy2 = 0;
1790  if( pCpyPara->pTableNd->GetTable().IsNewModel() )
1791  {
1792  if( pCpyPara->nBoxIdx == 1 )
1793  nDummy1 = (*pCpyPara->pWidths)[pCpyPara->nLnIdx][0];
1794  nRealSize = (*pCpyPara->pWidths)[pCpyPara->nLnIdx][pCpyPara->nBoxIdx++];
1795  if( pCpyPara->nBoxIdx == (*pCpyPara->pWidths)[pCpyPara->nLnIdx].size()-1 )
1796  nDummy2 = (*pCpyPara->pWidths)[pCpyPara->nLnIdx][pCpyPara->nBoxIdx];
1797  }
1798  else
1799  {
1800  nRealSize = pCpyPara->nNewSize;
1801  nRealSize *= rFndBox.GetBox()->GetFrameFormat()->GetFrameSize().GetWidth();
1802  if (pCpyPara->nOldSize == 0)
1803  throw o3tl::divide_by_zero();
1804  nRealSize /= pCpyPara->nOldSize;
1805  }
1806 
1807  sal_uLong nSize;
1808  bool bDummy = nDummy1 > 0;
1809  if( bDummy )
1810  nSize = nDummy1;
1811  else
1812  {
1813  nSize = nRealSize;
1814  nRealSize = 0;
1815  }
1816  do
1817  {
1818  // Find the Frame Format in the list of all Frame Formats
1819  CpyTabFrame aFindFrame(static_cast<SwTableBoxFormat*>(rFndBox.GetBox()->GetFrameFormat()));
1820 
1821  std::shared_ptr<SwFormatFrameSize> aFrameSz(std::make_shared<SwFormatFrameSize>());
1822  CpyTabFrames::const_iterator itFind = pCpyPara->rTabFrameArr.lower_bound( aFindFrame );
1823  const CpyTabFrames::size_type nFndPos = itFind - pCpyPara->rTabFrameArr.begin();
1824 
1825  // It *is* sometimes cool to have multiple tests/if's and assignments
1826  // in a single statement, and it is technically possible. But it is definitely
1827  // not simply readable - where from my POV reading code is done 1000 times
1828  // more often than writing it. Thus I dismantled the expression in smaller
1829  // chunks to keep it handy/understandable/changeable (hopefully without error)
1830  // The original for reference:
1831  // if( itFind == pCpyPara->rTabFrameArr.end() || !(*itFind == aFindFrame) ||
1832  // ( aFrameSz = ( aFindFrame = pCpyPara->rTabFrameArr[ nFndPos ]).pNewFrameFormat->
1833  // GetFrameSize()).GetWidth() != static_cast<SwTwips>(nSize) )
1834 
1835  bool DoCopyIt(itFind == pCpyPara->rTabFrameArr.end());
1836 
1837  if(!DoCopyIt)
1838  {
1839  DoCopyIt = !(*itFind == aFindFrame);
1840  }
1841 
1842  if(!DoCopyIt)
1843  {
1844  aFindFrame = pCpyPara->rTabFrameArr[ nFndPos ];
1845  aFrameSz.reset(aFindFrame.pNewFrameFormat->GetFrameSize().Clone());
1846  DoCopyIt = aFrameSz->GetWidth() != static_cast<SwTwips>(nSize);
1847  }
1848 
1849  if(DoCopyIt)
1850  {
1851  // It doesn't exist yet, so copy it
1852  aFindFrame.pNewFrameFormat = pCpyPara->rDoc.MakeTableBoxFormat();
1853  aFindFrame.pNewFrameFormat->CopyAttrs( *rFndBox.GetBox()->GetFrameFormat() );
1854  if( !pCpyPara->bCpyContent )
1855  aFindFrame.pNewFrameFormat->ResetFormatAttr( RES_BOXATR_FORMULA, RES_BOXATR_VALUE );
1856  aFrameSz->SetWidth( nSize );
1857  aFindFrame.pNewFrameFormat->SetFormatAttr( *aFrameSz );
1858  pCpyPara->rTabFrameArr.insert( aFindFrame );
1859  }
1860 
1861  SwTableBox* pBox;
1862  if (!rFndBox.GetLines().empty())
1863  {
1864  pBox = new SwTableBox( aFindFrame.pNewFrameFormat,
1865  rFndBox.GetLines().size(), pCpyPara->pInsLine );
1866  pCpyPara->pInsLine->GetTabBoxes().insert( pCpyPara->pInsLine->GetTabBoxes().begin() + pCpyPara->nInsPos++, pBox );
1867  CpyPara aPara( *pCpyPara, pBox );
1868  aPara.nNewSize = nSize; // get the size
1869  for (auto const& rpFndLine : rFndBox.GetLines())
1870  {
1871  lcl_CopyLineToDoc( *rpFndLine, &aPara );
1872  }
1873  }
1874  else
1875  {
1876  // Create an empty Box
1877  pCpyPara->rDoc.GetNodes().InsBoxen( pCpyPara->pTableNd, pCpyPara->pInsLine,
1878  aFindFrame.pNewFrameFormat,
1879  pCpyPara->rDoc.GetDfltTextFormatColl(),
1880  nullptr, pCpyPara->nInsPos );
1881  pBox = pCpyPara->pInsLine->GetTabBoxes()[ pCpyPara->nInsPos ];
1882  if( bDummy )
1883  pBox->setDummyFlag( true );
1884  else if( pCpyPara->bCpyContent )
1885  {
1886  // Copy the content into this empty Box
1887  pBox->setRowSpan(rFndBox.GetBox()->getRowSpan());
1888 
1889  // We can also copy formulas and values, if we copy the content
1890  {
1891  SfxItemSet aBoxAttrSet( pCpyPara->rDoc.GetAttrPool(),
1893  aBoxAttrSet.Put(rFndBox.GetBox()->GetFrameFormat()->GetAttrSet());
1894  if( aBoxAttrSet.Count() )
1895  {
1896  const SfxPoolItem* pItem;
1897  SvNumberFormatter* pN = pCpyPara->rDoc.GetNumberFormatter( false );
1898  if( pN && pN->HasMergeFormatTable() && SfxItemState::SET == aBoxAttrSet.
1899  GetItemState( RES_BOXATR_FORMAT, false, &pItem ) )
1900  {
1901  sal_uLong nOldIdx = static_cast<const SwTableBoxNumFormat*>(pItem)->GetValue();
1902  sal_uLong nNewIdx = pN->GetMergeFormatIndex( nOldIdx );
1903  if( nNewIdx != nOldIdx )
1904  aBoxAttrSet.Put( SwTableBoxNumFormat( nNewIdx ));
1905  }
1906  pBox->ClaimFrameFormat()->SetFormatAttr( aBoxAttrSet );
1907  }
1908  }
1909  SwDoc* pFromDoc = rFndBox.GetBox()->GetFrameFormat()->GetDoc();
1910  SwNodeRange aCpyRg( *rFndBox.GetBox()->GetSttNd(), 1,
1911  *rFndBox.GetBox()->GetSttNd()->EndOfSectionNode() );
1912  SwNodeIndex aInsIdx( *pBox->GetSttNd(), 1 );
1913 
1914  pFromDoc->GetDocumentContentOperationsManager().CopyWithFlyInFly(aCpyRg, aInsIdx, nullptr, false);
1915  // Delete the initial TextNode
1916  pCpyPara->rDoc.GetNodes().Delete( aInsIdx );
1917  }
1918  ++pCpyPara->nInsPos;
1919  }
1920  if( nRealSize )
1921  {
1922  bDummy = false;
1923  nSize = nRealSize;
1924  nRealSize = 0;
1925  }
1926  else
1927  {
1928  bDummy = true;
1929  nSize = nDummy2;
1930  nDummy2 = 0;
1931  }
1932  }
1933  while( nSize );
1934 }
1935 
1936 static void
1937 lcl_CopyLineToDoc(const FndLine_& rFndLine, CpyPara *const pCpyPara)
1938 {
1939  // Find the Frame Format in the list of all Frame Formats
1940  CpyTabFrame aFindFrame( rFndLine.GetLine()->GetFrameFormat() );
1941  CpyTabFrames::const_iterator itFind = pCpyPara->rTabFrameArr.find( aFindFrame );
1942  if( itFind == pCpyPara->rTabFrameArr.end() )
1943  {
1944  // It doesn't exist yet, so copy it
1945  aFindFrame.pNewFrameFormat = reinterpret_cast<SwTableBoxFormat*>(pCpyPara->rDoc.MakeTableLineFormat());
1946  aFindFrame.pNewFrameFormat->CopyAttrs( *rFndLine.GetLine()->GetFrameFormat() );
1947  pCpyPara->rTabFrameArr.insert( aFindFrame );
1948  }
1949  else
1950  aFindFrame = *itFind;
1951 
1952  SwTableLine* pNewLine = new SwTableLine( reinterpret_cast<SwTableLineFormat*>(aFindFrame.pNewFrameFormat),
1953  rFndLine.GetBoxes().size(), pCpyPara->pInsBox );
1954  if( pCpyPara->pInsBox )
1955  {
1956  SwTableLines& rLines = pCpyPara->pInsBox->GetTabLines();
1957  rLines.insert( rLines.begin() + pCpyPara->nInsPos++, pNewLine );
1958  }
1959  else
1960  {
1961  SwTableLines& rLines = pCpyPara->pTableNd->GetTable().GetTabLines();
1962  rLines.insert( rLines.begin() + pCpyPara->nInsPos++, pNewLine);
1963  }
1964 
1965  CpyPara aPara( *pCpyPara, pNewLine );
1966 
1967  if( pCpyPara->pTableNd->GetTable().IsNewModel() )
1968  {
1969  aPara.nOldSize = 0; // will not be used
1970  aPara.nBoxIdx = 1;
1971  }
1972  else if( rFndLine.GetBoxes().size() ==
1973  rFndLine.GetLine()->GetTabBoxes().size() )
1974  {
1975  // Get the Parent's size
1976  const SwFrameFormat* pFormat;
1977 
1978  if( rFndLine.GetLine()->GetUpper() )
1979  pFormat = rFndLine.GetLine()->GetUpper()->GetFrameFormat();
1980  else
1981  pFormat = pCpyPara->pTableNd->GetTable().GetFrameFormat();
1982  aPara.nOldSize = pFormat->GetFrameSize().GetWidth();
1983  }
1984  else
1985  // Calculate it
1986  for (auto &rpBox : rFndLine.GetBoxes())
1987  {
1988  aPara.nOldSize += rpBox->GetBox()->GetFrameFormat()->GetFrameSize().GetWidth();
1989  }
1990 
1991  const FndBoxes_t& rBoxes = rFndLine.GetBoxes();
1992  for (auto const& it : rBoxes)
1993  {
1994  lcl_CopyBoxToDoc(*it, &aPara);
1995  }
1996  if( pCpyPara->pTableNd->GetTable().IsNewModel() )
1997  ++pCpyPara->nLnIdx;
1998 }
1999 
2001 {
2002  // Find all Boxes/Lines
2003  SwSelBoxes aSelBoxes;
2004  SwTableBox* pBox = GetTabSortBoxes()[ 0 ];
2005  pBox = GetTableBox( pBox->GetSttNd()->StartOfSectionNode()->GetIndex() + 1 );
2006  SelLineFromBox( pBox, aSelBoxes );
2007 
2008  FndBox_ aFndBox( nullptr, nullptr );
2009  {
2010  FndPara aPara( aSelBoxes, &aFndBox );
2011  ForEach_FndLineCopyCol( GetTabLines(), &aPara );
2012  }
2013  if( aFndBox.GetLines().empty() )
2014  return;
2015 
2016  {
2017  // Convert Table formulas to their relative representation
2018  SwTableFormulaUpdate aMsgHint( this );
2019  aMsgHint.m_eFlags = TBL_RELBOXNAME;
2020  GetFrameFormat()->GetDoc()->getIDocumentFieldsAccess().UpdateTableFields( &aMsgHint );
2021  }
2022 
2023  CpyTabFrames aCpyFormat;
2024  CpyPara aPara( &rTableNd, 1, aCpyFormat );
2025  aPara.nNewSize = aPara.nOldSize = rTableNd.GetTable().GetFrameFormat()->GetFrameSize().GetWidth();
2026  // Copy
2027  if( IsNewModel() )
2028  lcl_CalcNewWidths( aFndBox.GetLines(), aPara );
2029  for (const auto & rpFndLine : aFndBox.GetLines())
2030  {
2031  lcl_CopyLineToDoc( *rpFndLine, &aPara );
2032  }
2033  if( rTableNd.GetTable().IsNewModel() )
2034  { // The copied line must not contain any row span attributes > 1
2035  SwTableLine* pLine = rTableNd.GetTable().GetTabLines()[0];
2036  OSL_ENSURE( !pLine->GetTabBoxes().empty(), "Empty Table Line" );
2037  for( auto pTableBox : pLine->GetTabBoxes() )
2038  {
2039  OSL_ENSURE( pTableBox, "Missing Table Box" );
2040  pTableBox->setRowSpan( 1 );
2041  }
2042  }
2043 }
2044 
2045 bool SwTable::MakeCopy( SwDoc& rInsDoc, const SwPosition& rPos,
2046  const SwSelBoxes& rSelBoxes,
2047  bool bCpyName ) const
2048 {
2049  // Find all Boxes/Lines
2050  FndBox_ aFndBox( nullptr, nullptr );
2051  {
2052  FndPara aPara( rSelBoxes, &aFndBox );
2053  ForEach_FndLineCopyCol( const_cast<SwTableLines&>(GetTabLines()), &aPara );
2054  }
2055  if( aFndBox.GetLines().empty() )
2056  return false;
2057 
2058  // First copy the PoolTemplates for the Table, so that the Tables are
2059  // actually copied and have valid values.
2060  SwDoc* pSrcDoc = GetFrameFormat()->GetDoc();
2061  if( pSrcDoc != &rInsDoc )
2062  {
2065  }
2066 
2067  SwTable* pNewTable = const_cast<SwTable*>(rInsDoc.InsertTable(
2069  rPos, 1, 1, GetFrameFormat()->GetHoriOrient().GetHoriOrient(),
2070  nullptr, nullptr, false, IsNewModel() ));
2071  if( !pNewTable )
2072  return false;
2073 
2074  SwNodeIndex aIdx( rPos.nNode, -1 );
2075  SwTableNode* pTableNd = aIdx.GetNode().FindTableNode();
2076  ++aIdx;
2077  OSL_ENSURE( pTableNd, "Where is the TableNode now?" );
2078 
2079  pTableNd->GetTable().SetRowsToRepeat( GetRowsToRepeat() );
2080 
2081  pNewTable->SetTableStyleName(pTableNd->GetTable().GetTableStyleName());
2082 
2083  if( auto pSwDDETable = dynamic_cast<const SwDDETable*>(this) )
2084  {
2085  // A DDE-Table is being copied
2086  // Does the new Document actually have it's FieldType?
2087  SwFieldType* pFieldType = rInsDoc.getIDocumentFieldsAccess().InsertFieldType(
2088  *pSwDDETable->GetDDEFieldType() );
2089  OSL_ENSURE( pFieldType, "unknown FieldType" );
2090 
2091  // Change the Table Pointer at the Node
2092  pNewTable = new SwDDETable( *pNewTable,
2093  static_cast<SwDDEFieldType*>(pFieldType) );
2094  pTableNd->SetNewTable( std::unique_ptr<SwTable>(pNewTable), false );
2095  }
2096 
2097  pNewTable->GetFrameFormat()->CopyAttrs( *GetFrameFormat() );
2098  pNewTable->SetTableChgMode( GetTableChgMode() );
2099 
2100  // Destroy the already created Frames
2101  pTableNd->DelFrames();
2102 
2103  {
2104  // Convert the Table formulas to their relative representation
2105  SwTableFormulaUpdate aMsgHint( this );
2106  aMsgHint.m_eFlags = TBL_RELBOXNAME;
2107  pSrcDoc->getIDocumentFieldsAccess().UpdateTableFields( &aMsgHint );
2108  }
2109 
2110  SwTableNumFormatMerge aTNFM(*pSrcDoc, rInsDoc);
2111 
2112  // Also copy Names or enforce a new unique one
2113  if( bCpyName )
2114  pNewTable->GetFrameFormat()->SetName( GetFrameFormat()->GetName() );
2115 
2116  CpyTabFrames aCpyFormat;
2117  CpyPara aPara( pTableNd, 1, aCpyFormat );
2118  aPara.nNewSize = aPara.nOldSize = GetFrameFormat()->GetFrameSize().GetWidth();
2119 
2120  if( IsNewModel() )
2121  lcl_CalcNewWidths( aFndBox.GetLines(), aPara );
2122  // Copy
2123  for (const auto & rpFndLine : aFndBox.GetLines())
2124  {
2125  lcl_CopyLineToDoc( *rpFndLine, &aPara );
2126  }
2127 
2128  // Set the "right" margin above/below
2129  {
2130  FndLine_* pFndLn = aFndBox.GetLines().front().get();
2131  SwTableLine* pLn = pFndLn->GetLine();
2132  const SwTableLine* pTmp = pLn;
2133  sal_uInt16 nLnPos = GetTabLines().GetPos( pTmp );
2134  if( USHRT_MAX != nLnPos && nLnPos )
2135  {
2136  // There is a Line before it
2138 
2139  pLn = GetTabLines()[ nLnPos - 1 ];
2140  for( const auto& rpBox : pLn->GetTabBoxes() )
2141  sw_Box_CollectBox( rpBox, &aLnPara );
2142 
2143  if( aLnPara.Resize( lcl_GetBoxOffset( aFndBox ),
2144  lcl_GetLineWidth( *pFndLn )) )
2145  {
2146  aLnPara.SetValues( true );
2147  pLn = pNewTable->GetTabLines()[ 0 ];
2148  for( const auto& rpBox : pLn->GetTabBoxes() )
2149  sw_BoxSetSplitBoxFormats(rpBox, &aLnPara );
2150  }
2151  }
2152 
2153  pFndLn = aFndBox.GetLines().back().get();
2154  pLn = pFndLn->GetLine();
2155  pTmp = pLn;
2156  nLnPos = GetTabLines().GetPos( pTmp );
2157  if( nLnPos < GetTabLines().size() - 1 )
2158  {
2159  // There is a Line following it
2161 
2162  pLn = GetTabLines()[ nLnPos + 1 ];
2163  for( const auto& rpBox : pLn->GetTabBoxes() )
2164  sw_Box_CollectBox( rpBox, &aLnPara );
2165 
2166  if( aLnPara.Resize( lcl_GetBoxOffset( aFndBox ),
2167  lcl_GetLineWidth( *pFndLn )) )
2168  {
2169  aLnPara.SetValues( false );
2170  pLn = pNewTable->GetTabLines().back();
2171  for( const auto& rpBox : pLn->GetTabBoxes() )
2172  sw_BoxSetSplitBoxFormats(rpBox, &aLnPara );
2173  }
2174  }
2175  }
2176 
2177  // We need to delete the initial Box
2178  DeleteBox_( *pNewTable, pNewTable->GetTabLines().back()->GetTabBoxes()[0],
2179  nullptr, false, false );
2180 
2181  if( pNewTable->IsNewModel() )
2182  lcl_CheckRowSpan( *pNewTable );
2183  // Clean up
2184  pNewTable->GCLines();
2185 
2186  pTableNd->MakeOwnFrames( &aIdx ); // re-generate the Frames
2187 
2189 
2190  return true;
2191 }
2192 
2193 // Find the next Box with content from this Line
2195  const SwTableBox* pSrchBox, bool bOvrTableLns ) const
2196 {
2197  const SwTableLine* pLine = this; // for M800
2198  SwTableBox* pBox;
2199  sal_uInt16 nFndPos;
2200  if( !GetTabBoxes().empty() && pSrchBox )
2201  {
2202  nFndPos = GetBoxPos( pSrchBox );
2203  if( USHRT_MAX != nFndPos &&
2204  nFndPos + 1 != static_cast<sal_uInt16>(GetTabBoxes().size()) )
2205  {
2206  pBox = GetTabBoxes()[ nFndPos + 1 ];
2207  while( !pBox->GetTabLines().empty() )
2208  pBox = pBox->GetTabLines().front()->GetTabBoxes()[0];
2209  return pBox;
2210  }
2211  }
2212 
2213  if( GetUpper() )
2214  {
2215  nFndPos = GetUpper()->GetTabLines().GetPos( pLine );
2216  OSL_ENSURE( USHRT_MAX != nFndPos, "Line is not in the Table" );
2217  // Is there another Line?
2218  if( nFndPos+1 >= static_cast<sal_uInt16>(GetUpper()->GetTabLines().size()) )
2219  return GetUpper()->GetUpper()->FindNextBox( rTable, GetUpper(), bOvrTableLns );
2220  pLine = GetUpper()->GetTabLines()[nFndPos+1];
2221  }
2222  else if( bOvrTableLns ) // Over a Table's the "BaseLines"??
2223  {
2224  // Search for the next Line in the Table
2225  nFndPos = rTable.GetTabLines().GetPos( pLine );
2226  if( nFndPos + 1 >= static_cast<sal_uInt16>(rTable.GetTabLines().size()) )
2227  return nullptr; // there are no more Boxes
2228 
2229  pLine = rTable.GetTabLines()[ nFndPos+1 ];
2230  }
2231  else
2232  return nullptr;
2233 
2234  if( !pLine->GetTabBoxes().empty() )
2235  {
2236  pBox = pLine->GetTabBoxes().front();
2237  while( !pBox->GetTabLines().empty() )
2238  pBox = pBox->GetTabLines().front()->GetTabBoxes().front();
2239  return pBox;
2240  }
2241  return pLine->FindNextBox( rTable, nullptr, bOvrTableLns );
2242 }
2243 
2244 // Find the previous Box from this Line
2246  const SwTableBox* pSrchBox, bool bOvrTableLns ) const
2247 {
2248  const SwTableLine* pLine = this; // for M800
2249  SwTableBox* pBox;
2250  sal_uInt16 nFndPos;
2251  if( !GetTabBoxes().empty() && pSrchBox )
2252  {
2253  nFndPos = GetBoxPos( pSrchBox );
2254  if( USHRT_MAX != nFndPos && nFndPos )
2255  {
2256  pBox = GetTabBoxes()[ nFndPos - 1 ];
2257  while( !pBox->GetTabLines().empty() )
2258  {
2259  pLine = pBox->GetTabLines().back();
2260  pBox = pLine->GetTabBoxes().back();
2261  }
2262  return pBox;
2263  }
2264  }
2265 
2266  if( GetUpper() )
2267  {
2268  nFndPos = GetUpper()->GetTabLines().GetPos( pLine );
2269  OSL_ENSURE( USHRT_MAX != nFndPos, "Line is not in the Table" );
2270  // Is there another Line?
2271  if( !nFndPos )
2272  return GetUpper()->GetUpper()->FindPreviousBox( rTable, GetUpper(), bOvrTableLns );
2273  pLine = GetUpper()->GetTabLines()[nFndPos-1];
2274  }
2275  else if( bOvrTableLns ) // Over a Table's the "BaseLines"??
2276  {
2277  // Search for the next Line in the Table
2278  nFndPos = rTable.GetTabLines().GetPos( pLine );
2279  if( !nFndPos )
2280  return nullptr; // there are no more Boxes
2281 
2282  pLine = rTable.GetTabLines()[ nFndPos-1 ];
2283  }
2284  else
2285  return nullptr;
2286 
2287  if( !pLine->GetTabBoxes().empty() )
2288  {
2289  pBox = pLine->GetTabBoxes().back();
2290  while( !pBox->GetTabLines().empty() )
2291  {
2292  pLine = pBox->GetTabLines().back();
2293  pBox = pLine->GetTabBoxes().back();
2294  }
2295  return pBox;
2296  }
2297  return pLine->FindPreviousBox( rTable, nullptr, bOvrTableLns );
2298 }
2299 
2300 // Find the next Box with content from this Line
2302  const SwTableBox* pSrchBox, bool bOvrTableLns ) const
2303 {
2304  if( !pSrchBox && GetTabLines().empty() )
2305  return const_cast<SwTableBox*>(this);
2306  return GetUpper()->FindNextBox( rTable, pSrchBox ? pSrchBox : this,
2307  bOvrTableLns );
2308 
2309 }
2310 
2311 // Find the next Box with content from this Line
2313  const SwTableBox* pSrchBox ) const
2314 {
2315  if( !pSrchBox && GetTabLines().empty() )
2316  return const_cast<SwTableBox*>(this);
2317  return GetUpper()->FindPreviousBox( rTable, pSrchBox ? pSrchBox : this );
2318 }
2319 
2320 static void lcl_BoxSetHeadCondColl( const SwTableBox* pBox )
2321 {
2322  // We need to adapt the paragraphs with conditional templates in the HeadLine
2323  const SwStartNode* pSttNd = pBox->GetSttNd();
2324  if( pSttNd )
2325  pSttNd->CheckSectionCondColl();
2326  else
2327  for( const SwTableLine* pLine : pBox->GetTabLines() )
2328  sw_LineSetHeadCondColl( pLine );
2329 }
2330 
2332 {
2333  for( const SwTableBox* pBox : pLine->GetTabBoxes() )
2334  lcl_BoxSetHeadCondColl(pBox);
2335 }
2336 
2337 static SwTwips lcl_GetDistance( SwTableBox* pBox, bool bLeft )
2338 {
2339  bool bFirst = true;
2340  SwTwips nRet = 0;
2341  SwTableLine* pLine;
2342  while( pBox )
2343  {
2344  pLine = pBox->GetUpper();
2345  if( !pLine )
2346  break;
2347  sal_uInt16 nStt = 0, nPos = pLine->GetBoxPos( pBox );
2348 
2349  if( bFirst && !bLeft )
2350  ++nPos;
2351  bFirst = false;
2352 
2353  while( nStt < nPos )
2354  nRet += pLine->GetTabBoxes()[ nStt++ ]->GetFrameFormat()
2355  ->GetFrameSize().GetWidth();
2356  pBox = pLine->GetUpper();
2357  }
2358  return nRet;
2359 }
2360 
2361 static bool lcl_SetSelBoxWidth( SwTableLine* pLine, CR_SetBoxWidth& rParam,
2362  SwTwips nDist, bool bCheck )
2363 {
2364  SwTableBoxes& rBoxes = pLine->GetTabBoxes();
2365  for( auto pBox : rBoxes )
2366  {
2367  SwFrameFormat* pFormat = pBox->GetFrameFormat();
2368  const SwFormatFrameSize& rSz = pFormat->GetFrameSize();
2369  SwTwips nWidth = rSz.GetWidth();
2370  bool bGreaterBox = false;
2371 
2372  if( bCheck )
2373  {
2374  for( auto pLn : pBox->GetTabLines() )
2375  if( !::lcl_SetSelBoxWidth( pLn, rParam, nDist, true ))
2376  return false;
2377 
2378  // Collect all "ContentBoxes"
2379  bGreaterBox = (TableChgMode::FixedWidthChangeAbs != rParam.nMode)
2380  && ((nDist + (rParam.bLeft ? 0 : nWidth)) >= rParam.nSide);
2381  if (bGreaterBox
2382  || (!rParam.bBigger
2383  && (std::abs(nDist + ((rParam.nMode != TableChgMode::FixedWidthChangeAbs && rParam.bLeft) ? 0 : nWidth) - rParam.nSide) < COLFUZZY)))
2384  {
2385  SwTwips nLowerDiff;
2386  if( bGreaterBox && TableChgMode::FixedWidthChangeProp == rParam.nMode )
2387  {
2388  // The "other Boxes" have been adapted, so change by this value
2389  nLowerDiff = (nDist + ( rParam.bLeft ? 0 : nWidth ) ) - rParam.nSide;
2390  nLowerDiff *= rParam.nDiff;
2391  nLowerDiff /= rParam.nMaxSize;
2392  nLowerDiff = rParam.nDiff - nLowerDiff;
2393  }
2394  else
2395  nLowerDiff = rParam.nDiff;
2396 
2397  if( nWidth < nLowerDiff || nWidth - nLowerDiff < MINLAY )
2398  return false;
2399  }
2400  }
2401  else
2402  {
2403  SwTwips nLowerDiff = 0, nOldLower = rParam.nLowerDiff;
2404  for( auto pLn : pBox->GetTabLines() )
2405  {
2406  rParam.nLowerDiff = 0;
2407  lcl_SetSelBoxWidth( pLn, rParam, nDist, false );
2408 
2409  if( nLowerDiff < rParam.nLowerDiff )
2410  nLowerDiff = rParam.nLowerDiff;
2411  }
2412  rParam.nLowerDiff = nOldLower;
2413 
2414  if( nLowerDiff ||
2415  (bGreaterBox = !nOldLower && TableChgMode::FixedWidthChangeAbs != rParam.nMode &&
2416  ( nDist + ( rParam.bLeft ? 0 : nWidth ) ) >= rParam.nSide) ||
2417  ( std::abs( nDist + ( (rParam.nMode != TableChgMode::FixedWidthChangeAbs && rParam.bLeft) ? 0 : nWidth )
2418  - rParam.nSide ) < COLFUZZY ))
2419  {
2420  // This column contains the Cursor - so decrease/increase
2421  SwFormatFrameSize aNew( rSz );
2422 
2423  if( !nLowerDiff )
2424  {
2425  if( bGreaterBox && TableChgMode::FixedWidthChangeProp == rParam.nMode )
2426  {
2427  // The "other Boxes" have been adapted, so change by this value
2428  nLowerDiff = (nDist + ( rParam.bLeft ? 0 : nWidth ) ) - rParam.nSide;
2429  nLowerDiff *= rParam.nDiff;
2430  nLowerDiff /= rParam.nMaxSize;
2431  nLowerDiff = rParam.nDiff - nLowerDiff;
2432  }
2433  else
2434  nLowerDiff = rParam.nDiff;
2435  }
2436 
2437  rParam.nLowerDiff += nLowerDiff;
2438 
2439  if( rParam.bBigger )
2440  aNew.SetWidth( nWidth + nLowerDiff );
2441  else
2442  aNew.SetWidth( nWidth - nLowerDiff );
2443  rParam.aShareFormats.SetSize( *pBox, aNew );
2444  break;
2445  }
2446  }
2447 
2448  if( rParam.bLeft && rParam.nMode != TableChgMode::FixedWidthChangeAbs && nDist >= rParam.nSide )
2449  break;
2450 
2451  nDist += nWidth;
2452 
2453  // If it gets bigger, then that's it
2454  if( ( TableChgMode::FixedWidthChangeAbs == rParam.nMode || !rParam.bLeft ) &&
2455  nDist >= rParam.nSide )
2456  break;
2457  }
2458  return true;
2459 }
2460 
2461 static bool lcl_SetOtherBoxWidth( SwTableLine* pLine, CR_SetBoxWidth& rParam,
2462  SwTwips nDist, bool bCheck )
2463 {
2464  SwTableBoxes& rBoxes = pLine->GetTabBoxes();
2465  for( auto pBox : rBoxes )
2466  {
2467  SwFrameFormat* pFormat = pBox->GetFrameFormat();
2468  const SwFormatFrameSize& rSz = pFormat->GetFrameSize();
2469  SwTwips nWidth = rSz.GetWidth();
2470 
2471  if( bCheck )
2472  {
2473  for( auto pLn : pBox->GetTabLines() )
2474  if( !::lcl_SetOtherBoxWidth( pLn, rParam, nDist, true ))
2475  return false;
2476 
2477  if( rParam.bBigger && ( TableChgMode::FixedWidthChangeAbs == rParam.nMode
2478  ? std::abs( nDist - rParam.nSide ) < COLFUZZY
2479  : ( rParam.bLeft ? nDist < rParam.nSide - COLFUZZY
2480  : nDist >= rParam.nSide - COLFUZZY )) )
2481  {
2482  SwTwips nDiff;
2483  if( TableChgMode::FixedWidthChangeProp == rParam.nMode ) // Table fixed, proportional
2484  {
2485  // calculate relative
2486  nDiff = nWidth;
2487  nDiff *= rParam.nDiff;
2488  nDiff /= rParam.nMaxSize;
2489  }
2490  else
2491  nDiff = rParam.nDiff;
2492 
2493  if( nWidth < nDiff || nWidth - nDiff < MINLAY )
2494  return false;
2495  }
2496  }
2497  else
2498  {
2499  SwTwips nLowerDiff = 0, nOldLower = rParam.nLowerDiff;
2500  for( auto pLn : pBox->GetTabLines() )
2501  {
2502  rParam.nLowerDiff = 0;
2503  lcl_SetOtherBoxWidth( pLn, rParam, nDist, false );
2504 
2505  if( nLowerDiff < rParam.nLowerDiff )
2506  nLowerDiff = rParam.nLowerDiff;
2507  }
2508  rParam.nLowerDiff = nOldLower;
2509 
2510  if( nLowerDiff ||
2511  ( TableChgMode::FixedWidthChangeAbs == rParam.nMode
2512  ? std::abs( nDist - rParam.nSide ) < COLFUZZY
2513  : ( rParam.bLeft ? nDist < rParam.nSide - COLFUZZY
2514  : nDist >= rParam.nSide - COLFUZZY)
2515  ) )
2516  {
2517  SwFormatFrameSize aNew( rSz );
2518 
2519  if( !nLowerDiff )
2520  {
2521  if( TableChgMode::FixedWidthChangeProp == rParam.nMode ) // Table fixed, proportional
2522  {
2523  // calculate relative
2524  nLowerDiff = nWidth;
2525  nLowerDiff *= rParam.nDiff;
2526  nLowerDiff /= rParam.nMaxSize;
2527  }
2528  else
2529  nLowerDiff = rParam.nDiff;
2530  }
2531 
2532  rParam.nLowerDiff += nLowerDiff;
2533 
2534  if( rParam.bBigger )
2535  aNew.SetWidth( nWidth - nLowerDiff );
2536  else
2537  aNew.SetWidth( nWidth + nLowerDiff );
2538 
2539  rParam.aShareFormats.SetSize( *pBox, aNew );
2540  }
2541  }
2542 
2543  nDist += nWidth;
2544  if( ( TableChgMode::FixedWidthChangeAbs == rParam.nMode || rParam.bLeft ) &&
2545  nDist > rParam.nSide )
2546  break;
2547  }
2548  return true;
2549 }
2550 
2551 static void lcl_AjustLines( SwTableLine* pLine, CR_SetBoxWidth& rParam )
2552 {
2553  SwTableBoxes& rBoxes = pLine->GetTabBoxes();
2554  for( auto pBox : rBoxes )
2555  {
2556  SwFormatFrameSize aSz( pBox->GetFrameFormat()->GetFrameSize() );
2557  SwTwips nWidth = aSz.GetWidth();
2558  nWidth *= rParam.nDiff;
2559  nWidth /= rParam.nMaxSize;
2560  aSz.SetWidth( nWidth );
2561  rParam.aShareFormats.SetSize( *pBox, aSz );
2562 
2563  for( auto pLn : pBox->GetTabLines() )
2564  ::lcl_AjustLines( pLn, rParam );
2565  }
2566 }
2567 
2568 #ifdef DBG_UTIL
2569 void CheckBoxWidth( const SwTableLine& rLine, SwTwips nSize )
2570 {
2571  const SwTableBoxes& rBoxes = rLine.GetTabBoxes();
2572 
2573  SwTwips nCurrentSize = 0;
2574  // See if the tables have a correct width
2575  for (const SwTableBox* pBox : rBoxes)
2576  {
2577  const SwTwips nBoxW = pBox->GetFrameFormat()->GetFrameSize().GetWidth();
2578  nCurrentSize += nBoxW;
2579 
2580  for( auto pLn : pBox->GetTabLines() )
2581  CheckBoxWidth( *pLn, nBoxW );
2582  }
2583 
2584  if (sal::static_int_cast< tools::ULong >(std::abs(nCurrentSize - nSize)) >
2585  (COLFUZZY * rBoxes.size()))
2586  {
2587  OSL_FAIL( "Line's Boxes are too small or too large" );
2588  }
2589 }
2590 #endif
2591 
2593  SwTwips nAbsDiff, SwTwips nRelDiff, std::unique_ptr<SwUndo>* ppUndo )
2594 {
2595  SetHTMLTableLayout(std::shared_ptr<SwHTMLTableLayout>()); // Delete HTML Layout
2596 
2597  const SwFormatFrameSize& rSz = GetFrameFormat()->GetFrameSize();
2598  const SvxLRSpaceItem& rLR = GetFrameFormat()->GetLRSpace();
2599 
2600  std::unique_ptr<FndBox_> xFndBox; // for insertion/deletion
2601  bool bBigger,
2602  bRet = false,
2603  bLeft = TableChgWidthHeightType::ColLeft == extractPosition( eType ) ||
2605 
2606  // Get the current Box's edge
2607  // Only needed for manipulating the width
2608  const SwTwips nDist = ::lcl_GetDistance( &rCurrentBox, bLeft );
2609  SwTwips nDistStt = 0;
2610  CR_SetBoxWidth aParam( eType, nRelDiff, nDist,
2611  bLeft ? nDist : rSz.GetWidth() - nDist,
2612  const_cast<SwTableNode*>(rCurrentBox.GetSttNd()->FindTableNode()) );
2613  bBigger = aParam.bBigger;
2614 
2615  FN_lcl_SetBoxWidth fnSelBox, fnOtherBox;
2616  fnSelBox = lcl_SetSelBoxWidth;
2617  fnOtherBox = lcl_SetOtherBoxWidth;
2618 
2619  switch( extractPosition(eType) )
2620  {
2623  if( TableChgMode::VarWidthChangeAbs == m_eTableChgMode )
2624  {
2625  // First test if we have room at all
2626  bool bChgLRSpace = true;
2627  if( bBigger )
2628  {
2629  if( GetFrameFormat()->getIDocumentSettingAccess().get(DocumentSettingId::BROWSE_MODE) &&
2630  !rSz.GetWidthPercent() )
2631  {
2632  // silence -Wsign-compare on Android with the static cast
2633  bRet = rSz.GetWidth() < static_cast<unsigned short>(USHRT_MAX) - nRelDiff;
2634  bChgLRSpace = bLeft ? rLR.GetLeft() >= nAbsDiff
2635  : rLR.GetRight() >= nAbsDiff;
2636  }
2637  else
2638  bRet = bLeft ? rLR.GetLeft() >= nAbsDiff
2639  : rLR.GetRight() >= nAbsDiff;
2640 
2641  if( !bRet )
2642  {
2643  // Then call itself recursively; only with another mode (proportional)
2644  TableChgMode eOld = m_eTableChgMode;
2645  m_eTableChgMode = TableChgMode::FixedWidthChangeProp;
2646 
2647  bRet = SetColWidth( rCurrentBox, eType, nAbsDiff, nRelDiff,
2648  ppUndo );
2649  m_eTableChgMode = eOld;
2650  return bRet;
2651  }
2652  }
2653  else
2654  {
2655  bRet = true;
2656  for( auto const & n: m_aLines )
2657  {
2658  aParam.LoopClear();
2659  if( !(*fnSelBox)( n, aParam, nDistStt, true ))
2660  {
2661  bRet = false;
2662  break;
2663  }
2664  }
2665  }
2666 
2667  if( bRet )
2668  {
2669  if( ppUndo )
2670  ppUndo->reset(new SwUndoAttrTable( *aParam.pTableNd, true ));
2671 
2672  tools::Long nFrameWidth = LONG_MAX;
2673  LockModify();
2674  SwFormatFrameSize aSz( rSz );
2675  SvxLRSpaceItem aLR( rLR );
2676  if( bBigger )
2677  {
2678  // If the Table does not have any room to grow, we need to create some!
2679  // silence -Wsign-compare on Android with the static cast
2680  if( aSz.GetWidth() + nRelDiff > static_cast<unsigned short>(USHRT_MAX) )
2681  {
2682  // Break down to USHRT_MAX / 2
2683  CR_SetBoxWidth aTmpPara( TableChgWidthHeightType::ColLeft, aSz.GetWidth() / 2,
2684  0, aSz.GetWidth(), aParam.pTableNd );
2685  for( size_t nLn = 0; nLn < m_aLines.size(); ++nLn )
2686  ::lcl_AjustLines( m_aLines[ nLn ], aTmpPara );
2687  aSz.SetWidth( aSz.GetWidth() / 2 );
2688  aParam.nDiff = nRelDiff /= 2;
2689  aParam.nSide /= 2;
2690  aParam.nMaxSize /= 2;
2691  }
2692 
2693  if( bLeft )
2694  aLR.SetLeft( sal_uInt16( aLR.GetLeft() - nAbsDiff ) );
2695  else
2696  aLR.SetRight( sal_uInt16( aLR.GetRight() - nAbsDiff ) );
2697  }
2698  else if( bLeft )
2699  aLR.SetLeft( sal_uInt16( aLR.GetLeft() + nAbsDiff ) );
2700  else
2701  aLR.SetRight( sal_uInt16( aLR.GetRight() + nAbsDiff ) );
2702 
2703  if( bChgLRSpace )
2704  GetFrameFormat()->SetFormatAttr( aLR );
2705  const SwFormatHoriOrient& rHOri = GetFrameFormat()->GetHoriOrient();
2706  if( text::HoriOrientation::FULL == rHOri.GetHoriOrient() ||
2707  (text::HoriOrientation::LEFT == rHOri.GetHoriOrient() && aLR.GetLeft()) ||
2708  (text::HoriOrientation::RIGHT == rHOri.GetHoriOrient() && aLR.GetRight()))
2709  {
2710  SwFormatHoriOrient aHOri( rHOri );
2712  GetFrameFormat()->SetFormatAttr( aHOri );
2713 
2714  // If the Table happens to contain relative values (USHORT_MAX),
2715  // we need to convert them to absolute ones now.
2716  // Bug 61494
2717  if( GetFrameFormat()->getIDocumentSettingAccess().get(DocumentSettingId::BROWSE_MODE) &&
2718  !rSz.GetWidthPercent() )
2719  {
2720  SwTabFrame* pTabFrame = SwIterator<SwTabFrame,SwFormat>( *GetFrameFormat() ).First();
2721  if( pTabFrame &&
2722  pTabFrame->getFramePrintArea().Width() != rSz.GetWidth() )
2723  {
2724  nFrameWidth = pTabFrame->getFramePrintArea().Width();
2725  if( bBigger )
2726  nFrameWidth += nAbsDiff;
2727  else
2728  nFrameWidth -= nAbsDiff;
2729  }
2730  }
2731  }
2732 
2733  if( bBigger )
2734  aSz.SetWidth( aSz.GetWidth() + nRelDiff );
2735  else
2736  aSz.SetWidth( aSz.GetWidth() - nRelDiff );
2737 
2738  if( rSz.GetWidthPercent() )
2739  aSz.SetWidthPercent( static_cast<sal_uInt8>(( aSz.GetWidth() * 100 ) /
2740  ( aSz.GetWidth() + aLR.GetRight() + aLR.GetLeft())));
2741 
2742  GetFrameFormat()->SetFormatAttr( aSz );
2743 
2744  UnlockModify();
2745 
2746  for( sal_uInt16 n = m_aLines.size(); n; )
2747  {
2748  --n;
2749  aParam.LoopClear();
2750  (*fnSelBox)( m_aLines[ n ], aParam, nDistStt, false );
2751  }
2752 
2753  // If the Table happens to contain relative values (USHORT_MAX),
2754  // we need to convert them to absolute ones now.
2755  // Bug 61494
2756  if( LONG_MAX != nFrameWidth )
2757  {
2758  SwFormatFrameSize aAbsSz( aSz );
2759  aAbsSz.SetWidth( nFrameWidth );
2760  GetFrameFormat()->SetFormatAttr( aAbsSz );
2761  }
2762  }
2763  }
2764  else if( bLeft ? nDist != 0 : std::abs( rSz.GetWidth() - nDist ) > COLFUZZY )
2765  {
2766  bRet = true;
2767  if( bLeft && TableChgMode::FixedWidthChangeAbs == m_eTableChgMode )
2768  aParam.bBigger = !bBigger;
2769 
2770  // First test if we have room at all
2771  if( aParam.bBigger )
2772  {
2773  for( auto const & n: m_aLines )
2774  {
2775  aParam.LoopClear();
2776  if( !(*fnOtherBox)( n, aParam, 0, true ))
2777  {
2778  bRet = false;
2779  break;
2780  }
2781  }
2782  }
2783  else
2784  {
2785  for( auto const & n: m_aLines )
2786  {
2787  aParam.LoopClear();
2788  if( !(*fnSelBox)( n, aParam, nDistStt, true ))
2789  {
2790  bRet = false;
2791  break;
2792  }
2793  }
2794  }
2795 
2796  // If true, set it
2797  if( bRet )
2798  {
2799  CR_SetBoxWidth aParam1( aParam );
2800  if( ppUndo )
2801  ppUndo->reset(new SwUndoAttrTable( *aParam.pTableNd, true ));
2802 
2803  if( TableChgMode::FixedWidthChangeAbs != m_eTableChgMode && bLeft )
2804  {
2805  for( sal_uInt16 n = m_aLines.size(); n; )
2806  {
2807  --n;
2808  aParam.LoopClear();
2809  aParam1.LoopClear();
2810  (*fnSelBox)( m_aLines[ n ], aParam, nDistStt, false );
2811  (*fnOtherBox)( m_aLines[ n ], aParam1, nDistStt, false );
2812  }
2813  }
2814  else
2815  {
2816  for( sal_uInt16 n = m_aLines.size(); n; )
2817  {
2818  --n;
2819  aParam.LoopClear();
2820  aParam1.LoopClear();
2821  (*fnOtherBox)( m_aLines[ n ], aParam1, nDistStt, false );
2822  (*fnSelBox)( m_aLines[ n ], aParam, nDistStt, false );
2823  }
2824  }
2825  }
2826  }
2827  break;
2828 
2831  if( TableChgMode::VarWidthChangeAbs == m_eTableChgMode )
2832  {
2833  // Then call itself recursively; only with another mode (proportional)
2834  TableChgMode eOld = m_eTableChgMode;
2835  m_eTableChgMode = TableChgMode::FixedWidthChangeAbs;
2836 
2837  bRet = SetColWidth( rCurrentBox, eType, nAbsDiff, nRelDiff,
2838  ppUndo );
2839  m_eTableChgMode = eOld;
2840  return bRet;
2841  }
2842  else if( bLeft ? nDist != 0 : (rSz.GetWidth() - nDist) > COLFUZZY )
2843  {
2844  if( bLeft && TableChgMode::FixedWidthChangeAbs == m_eTableChgMode )
2845  aParam.bBigger = !bBigger;
2846 
2847  // First, see if there is enough room at all
2848  SwTableBox* pBox = &rCurrentBox;
2849  SwTableLine* pLine = rCurrentBox.GetUpper();
2850  while( pLine->GetUpper() )
2851  {
2852  const SwTableBoxes::size_type nPos = pLine->GetBoxPos( pBox );
2853  if( bLeft ? nPos != 0 : nPos + 1 != pLine->GetTabBoxes().size() )
2854  break;
2855 
2856  pBox = pLine->GetUpper();
2857  pLine = pBox->GetUpper();
2858  }
2859 
2860  if( pLine->GetUpper() )
2861  {
2862  // We need to correct the distance once again!
2863  aParam.nSide -= ::lcl_GetDistance( pLine->GetUpper(), true );
2864 
2865  if( bLeft )
2866  aParam.nMaxSize = aParam.nSide;
2867  else
2868  aParam.nMaxSize = pLine->GetUpper()->GetFrameFormat()->
2869  GetFrameSize().GetWidth() - aParam.nSide;
2870  }
2871 
2872  // First, see if there is enough room at all
2873  FN_lcl_SetBoxWidth fnTmp = aParam.bBigger ? fnOtherBox : fnSelBox;
2874  bRet = (*fnTmp)( pLine, aParam, nDistStt, true );
2875 
2876  // If true, set it
2877  if( bRet )
2878  {
2879  CR_SetBoxWidth aParam1( aParam );
2880  if( ppUndo )
2881  ppUndo->reset(new SwUndoAttrTable( *aParam.pTableNd, true ));
2882 
2883  if( TableChgMode::FixedWidthChangeAbs != m_eTableChgMode && bLeft )
2884  {
2885  (*fnSelBox)( pLine, aParam, nDistStt, false );
2886  (*fnOtherBox)( pLine, aParam1, nDistStt, false );
2887  }
2888  else
2889  {
2890  (*fnOtherBox)( pLine, aParam1, nDistStt, false );
2891  (*fnSelBox)( pLine, aParam, nDistStt, false );
2892  }
2893  }
2894  }
2895  break;
2896  default: break;
2897  }
2898 
2899  if( xFndBox )
2900  {
2901  // Clean up the structure of all Lines
2902  GCLines();
2903 
2904  // Update Layout
2905  if( !bBigger || xFndBox->AreLinesToRestore( *this ) )
2906  xFndBox->MakeFrames( *this );
2907 
2908  // TL_CHART2: it is currently unclear if sth has to be done here.
2909  // The function name hints that nothing needs to be done, on the other
2910  // hand there is a case where sth gets deleted. :-(
2911 
2912  xFndBox.reset();
2913  }
2914 
2915 #if defined DBG_UTIL
2916  if( bRet )
2917  {
2920  }
2921 #endif
2922 
2923  return bRet;
2924 }
2925 
2926 static void SetLineHeight( SwTableLine& rLine, SwTwips nOldHeight, SwTwips nNewHeight,
2927  bool bMinSize )
2928 {
2929  SwLayoutFrame* pLineFrame = GetRowFrame( rLine );
2930  OSL_ENSURE( pLineFrame, "Where is the Frame from the SwTableLine?" );
2931 
2932  SwFrameFormat* pFormat = rLine.ClaimFrameFormat();
2933 
2934  SwTwips nMyNewH, nMyOldH = pLineFrame->getFrameArea().Height();
2935  if( !nOldHeight ) // the BaseLine and absolute
2936  nMyNewH = nMyOldH + nNewHeight;
2937  else
2938  {
2939  // Calculate as exactly as possible
2940  Fraction aTmp( nMyOldH );
2941  aTmp *= Fraction( nNewHeight, nOldHeight );
2942  aTmp += Fraction( 1, 2 ); // round up if needed
2943  nMyNewH = tools::Long(aTmp);
2944  }
2945 
2947  if( !bMinSize &&
2948  ( nMyOldH - nMyNewH ) > ( CalcRowRstHeight( pLineFrame ) + ROWFUZZY ))
2949  eSize = SwFrameSize::Fixed;
2950 
2951  pFormat->SetFormatAttr( SwFormatFrameSize( eSize, 0, nMyNewH ) );
2952 
2953  // First adapt all internal ones
2954  for( auto pBox : rLine.GetTabBoxes() )
2955  {
2956  for( auto pLine : pBox->GetTabLines() )
2957  SetLineHeight( *pLine, nMyOldH, nMyNewH, bMinSize );
2958  }
2959 }
2960 
2961 static bool lcl_SetSelLineHeight( SwTableLine* pLine, const CR_SetLineHeight& rParam,
2962  SwTwips nDist, bool bCheck )
2963 {
2964  bool bRet = true;
2965  if( !bCheck )
2966  {
2967  // Set line height
2968  SetLineHeight( *pLine, 0, rParam.bBigger ? nDist : -nDist,
2969  rParam.bBigger );
2970  }
2971  else if( !rParam.bBigger )
2972  {
2973  // Calculate the new relative size by means of the old one
2974  SwLayoutFrame* pLineFrame = GetRowFrame( *pLine );
2975  OSL_ENSURE( pLineFrame, "Where is the Frame from the SwTableLine?" );
2976  SwTwips nRstHeight = CalcRowRstHeight( pLineFrame );
2977  if( (nRstHeight + ROWFUZZY) < nDist )
2978  bRet = false;
2979  }
2980  return bRet;
2981 }
2982 
2983 static bool lcl_SetOtherLineHeight( SwTableLine* pLine, const CR_SetLineHeight& rParam,
2984  SwTwips nDist, bool bCheck )
2985 {
2986  bool bRet = true;
2987  if( bCheck )
2988  {
2989  if( rParam.bBigger )
2990  {
2991  // Calculate the new relative size by means of the old one
2992  SwLayoutFrame* pLineFrame = GetRowFrame( *pLine );
2993  OSL_ENSURE( pLineFrame, "Where is the Frame from the SwTableLine?" );
2994 
2995  if( TableChgMode::FixedWidthChangeProp == rParam.nMode )
2996  {
2997  nDist *= pLineFrame->getFrameArea().Height();
2998  nDist /= rParam.nMaxHeight;
2999  }
3000  bRet = nDist <= CalcRowRstHeight( pLineFrame );
3001  }
3002  }
3003  else
3004  {
3005  // Set line height
3006  // pLine is the following/preceding, thus adjust it
3007  if( TableChgMode::FixedWidthChangeProp == rParam.nMode )
3008  {
3009  SwLayoutFrame* pLineFrame = GetRowFrame( *pLine );
3010  OSL_ENSURE( pLineFrame, "Where is the Frame from the SwTableLine??" );
3011 
3012  // Calculate the new relative size by means of the old one
3013  // If the selected Box get bigger, adjust via the max space else
3014  // via the max height.
3015  if( (true) )
3016  {
3017  nDist *= pLineFrame->getFrameArea().Height();
3018  nDist /= rParam.nMaxHeight;
3019  }
3020  else
3021  {
3022  // Calculate the new relative size by means of the old one
3023  nDist *= CalcRowRstHeight( pLineFrame );
3024  nDist /= rParam.nMaxSpace;
3025  }
3026  }
3027  SetLineHeight( *pLine, 0, rParam.bBigger ? -nDist : nDist,
3028  !rParam.bBigger );
3029  }
3030  return bRet;
3031 }
3032 
3034  SwTwips nAbsDiff, SwTwips nRelDiff, std::unique_ptr<SwUndo>* ppUndo )
3035 {
3036  SwTableLine* pLine = rCurrentBox.GetUpper();
3037 
3038  SwTableLine* pBaseLine = pLine;
3039  while( pBaseLine->GetUpper() )
3040  pBaseLine = pBaseLine->GetUpper()->GetUpper();
3041 
3042  std::unique_ptr<FndBox_> xFndBox; // for insertion/deletion
3043  bool bBigger,
3044  bRet = false,
3046  sal_uInt16 nBaseLinePos = GetTabLines().GetPos( pBaseLine );
3047 
3048  CR_SetLineHeight aParam( eType,
3049  const_cast<SwTableNode*>(rCurrentBox.GetSttNd()->FindTableNode()) );
3050  bBigger = aParam.bBigger;
3051 
3052  SwTableLines* pLines = &m_aLines;
3053 
3054  // How do we get to the height?
3055  switch( extractPosition(eType) )
3056  {
3059  if( pLine == pBaseLine )
3060  break; // it doesn't work then!
3061 
3062  // Is a nested Line (Box!)
3063  pLines = &pLine->GetUpper()->GetTabLines();
3064  nBaseLinePos = pLines->GetPos( pLine );
3065  [[fallthrough]];
3066 
3068  {
3069  if( TableChgMode::VarWidthChangeAbs == m_eTableChgMode )
3070  {
3071  // First test if we have room at all
3072  if( bBigger )
3073  bRet = true;
3074  else
3075  bRet = lcl_SetSelLineHeight( (*pLines)[ nBaseLinePos ], aParam,
3076  nAbsDiff, true );
3077 
3078  if( bRet )
3079  {
3080  if( ppUndo )
3081  ppUndo->reset(new SwUndoAttrTable( *aParam.pTableNd, true ));
3082 
3083  lcl_SetSelLineHeight( (*pLines)[ nBaseLinePos ], aParam,
3084  nAbsDiff, false );
3085  }
3086  }
3087  else
3088  {
3089  bRet = true;
3092  if( bTop )
3093  {
3094  nStt = 0;
3095  nEnd = nBaseLinePos;
3096  }
3097  else
3098  {
3099  nStt = nBaseLinePos + 1;
3100  nEnd = pLines->size();
3101  }
3102 
3103  // Get the current Lines' height
3104  if( TableChgMode::FixedWidthChangeProp == m_eTableChgMode )
3105  {
3106  for( auto n = nStt; n < nEnd; ++n )
3107  {
3108  SwLayoutFrame* pLineFrame = GetRowFrame( *(*pLines)[ n ] );
3109  OSL_ENSURE( pLineFrame, "Where is the Frame from the SwTableLine??" );
3110  aParam.nMaxSpace += CalcRowRstHeight( pLineFrame );
3111  aParam.nMaxHeight += pLineFrame->getFrameArea().Height();
3112  }
3113  if( bBigger && aParam.nMaxSpace < nAbsDiff )
3114  bRet = false;
3115  }
3116  else
3117  {
3118  if( bTop ? nEnd != 0 : nStt < nEnd )
3119  {
3120  if( bTop )
3121  nStt = nEnd - 1;
3122  else
3123  nEnd = nStt + 1;
3124  }
3125  else
3126  bRet = false;
3127  }
3128 
3129  if( bRet )
3130  {
3131  if( bBigger )
3132  {
3133  for( auto n = nStt; n < nEnd; ++n )
3134  {
3135  if( !lcl_SetOtherLineHeight( (*pLines)[ n ], aParam,
3136  nAbsDiff, true ))
3137  {
3138  bRet = false;
3139  break;
3140  }
3141  }
3142  }
3143  else
3144  bRet = lcl_SetSelLineHeight( (*pLines)[ nBaseLinePos ], aParam,
3145  nAbsDiff, true );
3146  }
3147 
3148  if( bRet )
3149  {
3150  // Adjust
3151  if( ppUndo )
3152  ppUndo->reset(new SwUndoAttrTable( *aParam.pTableNd, true ));
3153 
3154  CR_SetLineHeight aParam1( aParam );
3155 
3156  if( bTop )
3157  {
3158  lcl_SetSelLineHeight( (*pLines)[ nBaseLinePos ], aParam,
3159  nAbsDiff, false );
3160  for( auto n = nStt; n < nEnd; ++n )
3161  lcl_SetOtherLineHeight( (*pLines)[ n ], aParam1,
3162  nAbsDiff, false );
3163  }
3164  else
3165  {
3166  for( auto n = nStt; n < nEnd; ++n )
3167  lcl_SetOtherLineHeight( (*pLines)[ n ], aParam1,
3168  nAbsDiff, false );
3169  lcl_SetSelLineHeight( (*pLines)[ nBaseLinePos ], aParam,
3170  nAbsDiff, false );
3171  }
3172  }
3173  else
3174  {
3175  // Then call itself recursively; only with another mode (proportional)
3176  TableChgMode eOld = m_eTableChgMode;
3177  m_eTableChgMode = TableChgMode::VarWidthChangeAbs;
3178 
3179  bRet = SetRowHeight( rCurrentBox, eType, nAbsDiff,
3180  nRelDiff, ppUndo );
3181 
3182  m_eTableChgMode = eOld;
3183  xFndBox.reset();
3184  }
3185  }
3186  }
3187  break;
3188  default: break;
3189  }
3190 
3191  if( xFndBox )
3192  {
3193  // then clean up the structure of all Lines
3194  GCLines();
3195 
3196  // Update Layout
3197  if( bBigger || xFndBox->AreLinesToRestore( *this ) )
3198  xFndBox->MakeFrames( *this );
3199 
3200  // TL_CHART2: it is currently unclear if sth has to be done here.
3201 
3202  xFndBox.reset();
3203  }
3204 
3206 
3207  return bRet;
3208 }
3209 
3211 {
3212  SwFrameFormat *pRet = nullptr, *pTmp;
3213  for( auto n = m_aNewFormats.size(); n; )
3214  if( ( pTmp = m_aNewFormats[ --n ])->GetFrameSize().GetWidth()
3215  == nWidth )
3216  {
3217  pRet = pTmp;
3218  break;
3219  }
3220  return pRet;
3221 }
3222 
3224 {
3225  const SfxPoolItem* pItem;
3226  sal_uInt16 nWhich = rItem.Which();
3227  SwFrameFormat *pRet = nullptr, *pTmp;
3228  const SfxPoolItem& rFrameSz = m_pOldFormat->GetFormatAttr( RES_FRM_SIZE, false );
3229  for( auto n = m_aNewFormats.size(); n; )
3230  if( SfxItemState::SET == ( pTmp = m_aNewFormats[ --n ])->
3231  GetItemState( nWhich, false, &pItem ) && *pItem == rItem &&
3232  pTmp->GetFormatAttr( RES_FRM_SIZE, false ) == rFrameSz )
3233  {
3234  pRet = pTmp;
3235  break;
3236  }
3237  return pRet;
3238 }
3239 
3241 {
3242  m_aNewFormats.push_back( &rNew );
3243 }
3244 
3246 {
3247  // returns true, if we can delete
3248  if( m_pOldFormat == &rFormat )
3249  return true;
3250 
3251  std::vector<SwFrameFormat*>::iterator it = std::find( m_aNewFormats.begin(), m_aNewFormats.end(), &rFormat );
3252  if( m_aNewFormats.end() != it )
3253  m_aNewFormats.erase( it );
3254  return m_aNewFormats.empty();
3255 }
3256 
3258 {
3259 }
3260 
3262 {
3263  sal_uInt16 nPos;
3264  return Seek_Entry( rFormat, &nPos )
3265  ? m_ShareArr[ nPos ]->GetFormat(nWidth)
3266  : nullptr;
3267 }
3269  const SfxPoolItem& rItem ) const
3270 {
3271  sal_uInt16 nPos;
3272  return Seek_Entry( rFormat, &nPos )
3273  ? m_ShareArr[ nPos ]->GetFormat(rItem)
3274  : nullptr;
3275 }
3276 
3278 {
3279  sal_uInt16 nPos;
3280  SwShareBoxFormat* pEntry;
3281  if( !Seek_Entry( rOld, &nPos ))
3282  {
3283  pEntry = new SwShareBoxFormat( rOld );
3284  m_ShareArr.insert(m_ShareArr.begin() + nPos, std::unique_ptr<SwShareBoxFormat>(pEntry));
3285  }
3286  else
3287  pEntry = m_ShareArr[ nPos ].get();
3288 
3289  pEntry->AddFormat( rNew );
3290 }
3291 
3293  SwFrameFormat& rFormat )
3294 {
3295  SwClient aCl;
3296  SwFrameFormat* pOld = nullptr;
3297  if( pBox )
3298  {
3299  pOld = pBox->GetFrameFormat();
3300  pOld->Add( &aCl );
3301  pBox->ChgFrameFormat( static_cast<SwTableBoxFormat*>(&rFormat) );
3302  }
3303  else if( pLn )
3304  {
3305  pOld = pLn->GetFrameFormat();
3306  pOld->Add( &aCl );
3307  pLn->ChgFrameFormat( static_cast<SwTableLineFormat*>(&rFormat) );
3308  }
3309  if( pOld && pOld->HasOnlyOneListener() )
3310  {
3311  RemoveFormat( *pOld );
3312  delete pOld;
3313  }
3314 }
3315 
3317 {
3318  SwFrameFormat *pBoxFormat = rBox.GetFrameFormat(),
3319  *pRet = GetFormat( *pBoxFormat, rSz.GetWidth() );
3320  if( pRet )
3321  ChangeFrameFormat( &rBox, nullptr, *pRet );
3322  else
3323  {
3324  pRet = rBox.ClaimFrameFormat();
3325  pRet->SetFormatAttr( rSz );
3326  AddFormat( *pBoxFormat, *pRet );
3327  }
3328 }
3329 
3331 {
3332  SwFrameFormat *pBoxFormat = rBox.GetFrameFormat(),
3333  *pRet = GetFormat( *pBoxFormat, rItem );
3334  if( pRet )
3335  ChangeFrameFormat( &rBox, nullptr, *pRet );
3336  else
3337  {
3338  pRet = rBox.ClaimFrameFormat();
3339  pRet->SetFormatAttr( rItem );
3340  AddFormat( *pBoxFormat, *pRet );
3341  }
3342 }
3343 
3345 {
3346  SwFrameFormat *pLineFormat = rLine.GetFrameFormat(),
3347  *pRet = GetFormat( *pLineFormat, rItem );
3348  if( pRet )
3349  ChangeFrameFormat( nullptr, &rLine, *pRet );
3350  else
3351  {
3352  pRet = rLine.ClaimFrameFormat();
3353  pRet->SetFormatAttr( rItem );
3354  AddFormat( *pLineFormat, *pRet );
3355  }
3356 }
3357 
3359 {
3360  for (auto i = m_ShareArr.size(); i; )
3361  {
3362  if (m_ShareArr[ --i ]->RemoveFormat(rFormat))
3363  {
3364  m_ShareArr.erase( m_ShareArr.begin() + i );
3365  }
3366  }
3367 }
3368 
3369 bool SwShareBoxFormats::Seek_Entry( const SwFrameFormat& rFormat, sal_uInt16* pPos ) const
3370 {
3371  sal_uIntPtr nIdx = reinterpret_cast<sal_uIntPtr>(&rFormat);
3372  auto nO = m_ShareArr.size();
3373  decltype(nO) nU = 0;
3374  if( nO > 0 )
3375  {
3376  nO--;
3377  while( nU <= nO )
3378  {
3379  const auto nM = nU + ( nO - nU ) / 2;
3380  sal_uIntPtr nFormat = reinterpret_cast<sal_uIntPtr>(&m_ShareArr[ nM ]->GetOldFormat());
3381  if( nFormat == nIdx )
3382  {
3383  if( pPos )
3384  *pPos = nM;
3385  return true;
3386  }
3387  else if( nFormat < nIdx )
3388  nU = nM + 1;
3389  else if( nM == 0 )
3390  {
3391  if( pPos )
3392  *pPos = nU;
3393  return false;
3394  }
3395  else
3396  nO = nM - 1;
3397  }
3398  }
3399  if( pPos )
3400  *pPos = nU;
3401  return false;
3402 }
3403 
3404 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
void AddRowCols(const SwTable &rTable, const SwSelBoxes &rBoxes, sal_uInt16 nLines, bool bBehind)
SwChartDataProvider::AddRowCols tries to notify charts of added columns or rows and extends the value...
Definition: unochart.cxx:1547
Instances of SwFields and those derived from it occur 0 to n times.
Definition: fldbas.hxx:240
const SwEndNode * EndOfSectionNode() const
Definition: node.hxx:685
Starts a section of nodes in the document model.
Definition: node.hxx:311
std::vector< SwTableLine * >::size_type size_type
Definition: swtable.hxx:67
const FndLines_t & GetLines() const
Definition: tblsel.hxx:173
tools::Long GetWidth() const
const SwTableLine * GetLine() const
Definition: tblsel.hxx:205
const_iterator lower_bound(const Value &x) const
sal_uLong GetIndex() const
Definition: node.hxx:290
void Add(SwClient *pDepend)
Definition: calbck.cxx:199
void SetRight(const tools::Long nR, const sal_uInt16 nProp=100)
void SetRowsToRepeat(sal_uInt16 nNumOfRows)
Definition: swtable.hxx:196
Marks a position in the document model.
Definition: pam.hxx:35
static SwTwips lcl_GetDistance(SwTableBox *pBox, bool bLeft)
Definition: tblrwcl.cxx:2337
void DelFrames(SwRootFrame const *pLayout=nullptr)
Method deletes all views of document for the node.
Definition: ndtbl.cxx:2436
static void lcl_CopyLineToDoc(FndLine_ const &rpFndLn, CpyPara *const pCpyPara)
constexpr TypedWhichId< SwTableBoxNumFormat > RES_BOXATR_FORMAT(RES_BOXATR_BEGIN)
sal_uLong GetSttIdx() const
Definition: swtable.cxx:1865
SwDocShell * GetDocShell()
Definition: doc.hxx:1350
std::string GetValue
constexpr TypedWhichId< SwTableBoxValue > RES_BOXATR_VALUE(150)
static void lcl_CopyCol(FndBox_ &rFndBox, CpyPara *const pCpyPara)
Definition: tblrwcl.cxx:247
static void lcl_CpyLines(sal_uInt16 nStt, sal_uInt16 nEnd, SwTableLines &rLines, SwTableBox *pInsBox, sal_uInt16 nPos=USHRT_MAX)
Definition: tblrwcl.cxx:1274
static void lcl_LastBoxSetWidth(SwTableBoxes &rBoxes, const tools::Long nOffset, bool bFirst, SwShareBoxFormats &rShareFormats)
Definition: tblrwcl.cxx:624
SwNodeIndex nNode
Definition: pam.hxx:37
constexpr TypedWhichId< SwFormatFrameSize > RES_FRM_SIZE(89)
sal_uIntPtr sal_uLong
#define ROWFUZZY
Definition: tblrwcl.cxx:64
long Long
tools::Long GetRight() const
const SwRect & getFramePrintArea() const
Definition: frame.hxx:179
#define MINLAY
Definition: swtypes.hxx:66
bool AreLinesToRestore(const SwTable &rTable) const
Definition: tblsel.cxx:2546
SwTabFrame is one table in the document layout, containing rows (which contain cells).
Definition: tabfrm.hxx:30
virtual void CreateChartInternalDataProviders(const SwTable *pTable)=0
calls createInternalDataProvider for all charts using the specified table
SwFrameFormat * GetFormat(tools::Long nWidth) const
Definition: tblrwcl.cxx:3210
sal_Int64 n
Definition: doc.hxx:186
SwFrameFormat * ClaimFrameFormat()
Definition: swtable.cxx:1465
void setDummyFlag(bool bDummy)
Definition: swtable.cxx:89
void DelFrames(SwTable &rTable)
Definition: tblsel.cxx:2172
bool OldSplitRow(SwDoc &, const SwSelBoxes &, sal_uInt16, bool)
Definition: tblrwcl.cxx:1008
TableChgWidthHeightType
Definition: tblenum.hxx:25
const_iterator find(const Value &x) const
virtual bool HasExtraRedlineTable() const =0
SwTableLine is one table row in the document model.
Definition: swtable.hxx:351
SwNode & GetNode() const
Definition: ndindex.hxx:119
SwFrameFormat * GetFormat(const SwFrameFormat &rFormat, tools::Long nWidth) const
Definition: tblrwcl.cxx:3261
static sal_uInt16 lcl_GetLineWidth(const FndLine_ &rLine)
Definition: tblrwcl.cxx:1687
iterator begin()
Definition: swtable.hxx:76
void CheckSectionCondColl() const
Call ChkCondcoll to all ContentNodes of section.
Definition: node.cxx:973
const editeng::SvxBorderLine * GetRight() const
SwTableLine * front() const
Definition: swtable.hxx:80
IDocumentContentOperations const & getIDocumentContentOperations() const
Definition: doc.cxx:315
bool OldMerge(SwDoc *, const SwSelBoxes &, SwTableBox *, SwUndoTableMerge *)
Definition: tblrwcl.cxx:1519
SwTableFormat * GetFrameFormat()
Definition: swtable.hxx:203
void SetValues(bool bFlag)
Definition: tblrwcl.hxx:97
Value in Var-direction gives minimum (can be exceeded but not be less).
static bool lcl_SetOtherLineHeight(SwTableLine *pLine, const CR_SetLineHeight &rParam, SwTwips nDist, bool bCheck)
Definition: tblrwcl.cxx:2983
size_type size() const
Definition: swtable.hxx:75
void ForEach_FndLineCopyCol(SwTableLines &rLines, FndPara *pFndPara)
This creates a structure mirroring the SwTable structure that contains all rows and non-leaf boxes (a...
Definition: tblsel.cxx:2104
const SvxBoxItem & GetBox(bool=true) const
Definition: frmatr.hxx:84
sal_Int32 getRowSpan() const
Definition: swtable.cxx:74
SwTableBox * FindNextBox(const SwTable &, const SwTableBox *=nullptr, bool bOvrTableLns=true) const
Definition: tblrwcl.cxx:2194
SwTableLine * back() const
Definition: swtable.hxx:81
IDocumentFieldsAccess const & getIDocumentFieldsAccess() const
Definition: doc.cxx:357
void Delete(const SwNodeIndex &rPos, sal_uLong nNodes=1)
delete nodes
Definition: nodes.cxx:1072
void ChgFrameFormat(SwTableLineFormat *pNewFormat)
Definition: swtable.cxx:1498
void SetHoriOrient(sal_Int16 eNew)
Definition: fmtornt.hxx:89
bool UpdateTableStyleFormatting(SwTableNode *pTableNode=nullptr, bool bResetDirect=false, OUString const *pStyleName=nullptr)
Update the direct formatting according to the current table style.
Definition: fetab.cxx:1201
const SwRect & getFrameArea() const
Definition: frame.hxx:178
void AddFormat(SwFrameFormat &rFormat)
Definition: tblrwcl.cxx:3240
static void lcl_CheckRowSpan(SwTable &rTable)
Definition: tblrwcl.cxx:1641
void sw_LineSetHeadCondColl(const SwTableLine *pLine)
Definition: tblrwcl.cxx:2331
IDocumentStylePoolAccess const & getIDocumentStylePoolAccess() const
Definition: doc.cxx:426
static void SetLineHeight(SwTableLine &rLine, SwTwips nOldHeight, SwTwips nNewHeight, bool bMinSize)
Definition: tblrwcl.cxx:2926
int nCount
virtual void UpdateTableFields(SfxPoolItem *pHt)=0
static void lcl_Merge_MoveBox(FndBox_ &rFndBox, InsULPara *const pULPara)
Definition: tblrwcl.cxx:1351
virtual void SetName(const OUString &rNewName, bool bBroadcast=false) override
Definition: atrfrm.cxx:2493
void Width(tools::Long nNew)
Definition: swrect.hxx:187
const FndBoxes_t & GetBoxes() const
Definition: tblsel.hxx:203
iterator insert(iterator aIt, SwTableLine *pLine)
Definition: swtable.hxx:85
SwTextFormatColl * CopyTextColl(const SwTextFormatColl &rColl)
copy TextNodes
Definition: docfmt.cxx:1164
void CopyHeadlineIntoTable(SwTableNode &rTableNd)
Definition: tblrwcl.cxx:2000
const SwTable & GetTable() const
Definition: node.hxx:500
virtual void DeleteSection(SwNode *pNode)=0
Delete section containing the node.
static void lcl_Merge_MoveLine(FndLine_ &rFndLine, InsULPara *const pULPara)
Definition: tblrwcl.cxx:1416
o3tl::sorted_vector< CpyTabFrame > CpyTabFrames
Definition: tblrwcl.cxx:198
const OUString & GetTableStyleName() const
Return the table style name of this table.
Definition: swtable.hxx:190
bool Seek_Entry(const SwFrameFormat &rFormat, sal_uInt16 *pPos) const
Definition: tblrwcl.cxx:3369
SwTableBox * FindPreviousBox(const SwTable &, const SwTableBox *) const
Definition: tblrwcl.cxx:2312
static void lcl_CalcWidth(SwTableBox *pBox)
Definition: tblrwcl.cxx:1300
void UpdateCharts(const OUString &rName) const
Definition: docchart.cxx:120
bool HasOnlyOneListener() const
Definition: calbck.hxx:224
bool SplitCol(SwDoc &rDoc, const SwSelBoxes &rBoxes, sal_uInt16 nCnt)
Definition: tblrwcl.cxx:1151
size_type size() const
void sw_BoxSetSplitBoxFormats(SwTableBox *pBox, SwCollectTableLineBoxes *pSplPara)
Definition: ndtbl.cxx:3015
void MakeFrames(SwTable &rTable)
Definition: tblsel.cxx:2333
static void lcl_CpyBoxes(sal_uInt16 nStt, sal_uInt16 nEnd, SwTableBoxes &rBoxes, SwTableLine *pInsLine)
Definition: tblrwcl.cxx:1288
static void lcl_LastBoxSetWidthLine(SwTableLines &rLines, const tools::Long nOffset, bool bFirst, SwShareBoxFormats &rShareFormats)
Definition: tblrwcl.cxx:617
DocumentType eType
Class for SplitTable Collects the uppermost or lowermost Lines of a Box from a Line in an array...
Definition: tblrwcl.hxx:61
void InsTableBox(SwDoc &rDoc, SwTableNode *pTableNd, SwTableLine *pLine, SwTableBoxFormat *pBoxFrameFormat, SwTableBox *pBox, sal_uInt16 nInsPos, sal_uInt16 nCnt=1)
Definition: swtable.cxx:129
#define CHECKTABLELAYOUT
Definition: tblrwcl.cxx:141
Table of Contents - heading.
Definition: poolfmt.hxx:341
const editeng::SvxBorderLine * GetTop() const
void SetSize(SwTableBox &rBox, const SwFormatFrameSize &rSz)
Definition: tblrwcl.cxx:3316
bool SetColWidth(SwTableBox &rCurrentBox, TableChgWidthHeightType eType, SwTwips nAbsDiff, SwTwips nRelDiff, std::unique_ptr< SwUndo > *ppUndo)
Definition: tblrwcl.cxx:2592
Style of a layout element.
Definition: frmfmt.hxx:58
bool(* FN_lcl_SetBoxWidth)(SwTableLine *, CR_SetBoxWidth &, SwTwips, bool)
Definition: tblrwcl.cxx:130
virtual const SwExtraRedlineTable & GetExtraRedlineTable() const =0
const editeng::SvxBorderLine * GetLeft() const
static SwRowFrame * GetRowFrame(SwTableLine &rLine)
Definition: tblrwcl.cxx:442
void SetTableLines(const SwSelBoxes &rBoxes, const SwTable &rTable)
Definition: tblsel.cxx:2110
int i
void RemoveFormat(const SwFrameFormat &rFormat)
Definition: tblrwcl.cxx:3358
const SwStartNode * StartOfSectionNode() const
Definition: node.hxx:131
SwDoc & GetDoc()
Definition: node.hxx:211
bool empty() const
Definition: swtable.hxx:74
bool DeleteSel(SwDoc *, const SwSelBoxes &rBoxes, const SwSelBoxes *pMerged, SwUndo *pUndo, const bool bDelMakeFrames, const bool bCorrBorder)
Definition: tblrwcl.cxx:933
void CheckBoxWidth(const SwTableLine &rLine, SwTwips nSize)
Definition: tblrwcl.cxx:2569
virtual SwChartDataProvider * GetChartDataProvider(bool bCreate=false) const =0
returns or creates the data-provider for chart
::sw::DocumentContentOperationsManager const & GetDocumentContentOperationsManager() const
Definition: doc.cxx:325
void AddFormat(const SwFrameFormat &rOld, SwFrameFormat &rNew)
Definition: tblrwcl.cxx:3277
static void lcl_BoxSetHeadCondColl(const SwTableBox *pBox)
Definition: tblrwcl.cxx:2320
tools::Long GetHeight(const SwRect &rRect) const
Definition: frame.hxx:1363
void SetSelBoxes(const SwSelBoxes &rBoxes)
Definition: untbl.cxx:2002
tools::Long GetLeft() const
bool DeleteTableRowRedline(SwDoc *pDoc, const SwTableLine &rTableLine, bool bSaveInUndo, RedlineType nRedlineTypeToDelete)
Definition: docredln.cxx:208
constexpr sal_uInt16 RES_BOXATR_END(151)
static bool lcl_SetSelLineHeight(SwTableLine *pLine, const CR_SetLineHeight &rParam, SwTwips nDist, bool bCheck)
Definition: tblrwcl.cxx:2961
static SwTableBox * lcl_FndNxtPrvDelBox(const SwTableLines &rTableLns, SwTwips nBoxStt, SwTwips nBoxWidth, sal_uInt16 nLinePos, bool bNxt, SwSelBoxes *pAllDelBoxes, size_t *const pCurPos)
Definition: tblrwcl.cxx:801
void UnlockModify()
Definition: calbck.hxx:215
sal_Int16 GetHoriOrient() const
Definition: fmtornt.hxx:87
void LockModify()
Definition: calbck.hxx:214
SwFrameFormat * GetFrameFormat()
Definition: swtable.hxx:373
bool SetRowHeight(SwTableBox &rCurrentBox, TableChgWidthHeightType eType, SwTwips nAbsDiff, SwTwips nRelDiff, std::unique_ptr< SwUndo > *ppUndo)
Definition: tblrwcl.cxx:3033
size
void MakeOwnFrames(SwNodeIndex *pIdxBehind)
Creates the frms for the table node (i.e. the TabFrames).
Definition: ndtbl.cxx:2397
constexpr sal_uInt16 RES_BOXATR_BEGIN(RES_GRFATR_END)
SwFrameSize
Definition: fmtfsize.hxx:35
Marks a node in the document model.
Definition: ndindex.hxx:31
SwFrameFormat * GetFrameFormat()
Definition: swtable.hxx:432
const_iterator end() const
bool HasMergeFormatTable() const
bool empty() const
static bool lcl_SetSelBoxWidth(SwTableLine *pLine, CR_SetBoxWidth &rParam, SwTwips nDist, bool bCheck)
Definition: tblrwcl.cxx:2361
#define CHECK_TABLE(t)
Definition: tblrwcl.cxx:67
const SwDoc * GetDoc() const
The document is set in SwAttrPool now, therefore you always can access it.
Definition: format.hxx:119
sal_uInt8 GetWidthPercent() const
Definition: fmtfsize.hxx:91
IDocumentChartDataProviderAccess const & getIDocumentChartDataProviderAccess() const
Definition: doc.cxx:227
SwTableBox * FindPreviousBox(const SwTable &, const SwTableBox *=nullptr, bool bOvrTableLns=true) const
Definition: tblrwcl.cxx:2245
sal_uInt16 GetBoxPos(const SwTableBox *pBox) const
Definition: swtable.hxx:363
bool IsInReading() const
Definition: doc.hxx:953
Frame cannot be moved in Var-direction.
SwTableLines & GetTabLines()
Definition: swtable.hxx:200
tools::Long SwTwips
Definition: swtypes.hxx:49
static void lcl_AjustLines(SwTableLine *pLine, CR_SetBoxWidth &rParam)
Definition: tblrwcl.cxx:2551
const long LONG_MAX
SwTable is one table in the document model, containing rows (which contain cells).
Definition: swtable.hxx:111
void SetWidth(tools::Long n)
SwTableLines & GetTabLines()
Definition: swtable.hxx:425
static sal_uInt16 lcl_GetBoxOffset(const FndBox_ &rBox)
Definition: tblrwcl.cxx:1662
const_iterator begin() const
#define COLFUZZY
Definition: tblrwcl.cxx:63
virtual bool SetFormatAttr(const SfxPoolItem &rAttr)
Definition: format.cxx:461
void SetTableChgMode(TableChgMode eMode)
Definition: swtable.hxx:333
constexpr sal_uInt16 RES_FRMATR_END(131)
sal_uLong EndOfSectionIndex() const
Definition: node.hxx:680
void MakeNewFrames(SwTable &rTable, const sal_uInt16 nNumber, const bool bBehind)
Definition: tblsel.cxx:2406
SwTableBoxes & GetTabBoxes()
Definition: swtable.hxx:361
static void lcl_InsCol(FndLine_ *pFndLn, CpyPara &rCpyPara, sal_uInt16 nCpyCnt, bool bBehind)
Definition: tblrwcl.cxx:405
virtual bool ResetFormatAttr(sal_uInt16 nWhich1, sal_uInt16 nWhich2=0)
Definition: format.cxx:641
IDocumentRedlineAccess const & getIDocumentRedlineAccess() const
Definition: doc.cxx:335
std::vector< SwTableBox * > SwTableBoxes
Definition: swtable.hxx:104
static void lcl_SaveUpperLowerBorder(SwTable &rTable, const SwTableBox &rBox, SwShareBoxFormats &rShareFormats, SwSelBoxes *pAllDelBoxes=nullptr, size_t *const pCurPos=nullptr)
Definition: tblrwcl.cxx:861
constexpr TypedWhichId< SwTableBoxFormula > RES_BOXATR_FORMULA(149)
std::vector< std::unique_ptr< FndBox_ > > FndBoxes_t
Definition: tblsel.hxx:152
void sw_Box_CollectBox(const SwTableBox *pBox, SwCollectTableLineBoxes *pSplPara)
Definition: ndtbl.cxx:2997
const SwStartNode * GetSttNd() const
Definition: swtable.hxx:446
static void lcl_CopyBoxToDoc(FndBox_ const &rFndBox, CpyPara *const pCpyPara)
Definition: tblrwcl.cxx:1784
bool operator<(TypeDescription const &left, TypeDescription const &right)
void ChgFrameFormat(SwTableBoxFormat *pNewFormat, bool bNeedToReregister=true)
Definition: swtable.cxx:1725
void GCLines()
Definition: gctable.cxx:454
bool(* FN_lcl_SetLineHeight)(SwTableLine *, CR_SetLineHeight &, SwTwips, bool)
Definition: tblrwcl.cxx:196
void SetLeft(const tools::Long nL, const sal_uInt16 nProp=100)
void CopyAttrs(const SwFormat &)
Copy attributes even among documents.
Definition: format.cxx:177
void ChangeFrameFormat(SwTableBox *pBox, SwTableLine *pLn, SwFrameFormat &rFormat)
Definition: tblrwcl.cxx:3292
unsigned char sal_uInt8
void CopyWithFlyInFly(const SwNodeRange &rRg, const SwNodeIndex &rInsPos, const std::pair< const SwPaM &, const SwPosition & > *pCopiedPaM=nullptr, bool bMakeNewFrames=true, bool bDelRedlines=true, bool bCopyFlyAtFly=false, SwCopyFlags flags=SwCopyFlags::Default) const
note: rRg/rInsPos exclude a partially selected start text node; pCopiedPaM includes a partially selec...
sal_uInt32 GetMergeFormatIndex(sal_uInt32 nOldFmt) const
virtual SwFieldType * InsertFieldType(const SwFieldType &)=0
void SetWidthPercent(sal_uInt8 n)
Definition: fmtfsize.hxx:95
const o3tl::enumarray< SvxAdjust, unsigned short > aSvxToUnoAdjust USHRT_MAX
Definition: unosett.cxx:254
void SetTableStyleName(const OUString &rName)
Set the new table style name for this table.
Definition: swtable.hxx:193
const SwTableBox * GetBox() const
Definition: tblsel.hxx:175
bool InsertCol(SwDoc &, const SwSelBoxes &rBoxes, sal_uInt16 nCnt, bool bBehind)
Definition: tblrwcl.cxx:451
SwNodes & GetNodes()
Definition: doc.hxx:405
virtual SwTextFormatColl * GetTextCollFromPool(sal_uInt16 nId, bool bRegardLanguage=true)=0
Return "Auto-Collection with ID.
static bool lcl_SetOtherBoxWidth(SwTableLine *pLine, CR_SetBoxWidth &rParam, SwTwips nDist, bool bCheck)
Definition: tblrwcl.cxx:2461
bool MakeCopy(SwDoc &, const SwPosition &, const SwSelBoxes &, bool bCpyName=false) const
Definition: tblrwcl.cxx:2045
SwTableBox is one table cell in the document model.
Definition: swtable.hxx:393
void SetAttr(SwTableBox &rBox, const SfxPoolItem &rItem)
Definition: tblrwcl.cxx:3330
static void lcl_CopyRow(FndLine_ &rFndLine, CpyPara *const pCpyPara)
Definition: tblrwcl.cxx:380
constexpr TableChgWidthHeightType extractPosition(TableChgWidthHeightType e)
Definition: tblenum.hxx:42
constexpr TypedWhichId< SvxLRSpaceItem > RES_LR_SPACE(91)
bool Resize(sal_uInt16 nOffset, sal_uInt16 nWidth)
Definition: ndtbl.cxx:2946
SwFrameFormat * ClaimFrameFormat()
Definition: swtable.cxx:1689
SvxBoxItem & rBoxItem
#define CHECKBOXWIDTH
Definition: tblrwcl.cxx:134
const SwFormatFrameSize & GetFrameSize(bool=true) const
Definition: fmtfsize.hxx:104
SwFEShell * GetFEShell()
For Core - it knows the DocShell but not the WrtShell!
Definition: docsh.cxx:1210
std::vector< std::unique_ptr< FndLine_ > > FndLines_t
Definition: tblsel.hxx:155
SwTableNode * FindTableNode()
Search table node, in which it is.
Definition: node.cxx:355
SwTableBox * GetUpper()
Definition: swtable.hxx:369
bool RemoveFormat(const SwFrameFormat &rFormat)
Definition: tblrwcl.cxx:3245
void DeleteBox_(SwTable &rTable, SwTableBox *pBox, SwUndo *pUndo, bool bCalcNewSize, const bool bCorrBorder, SwShareBoxFormats *pShareFormats)
Definition: tblrwcl.cxx:651
void SetUpper(SwTableLine *pNew)
Definition: swtable.hxx:430
SwTableBox * FindNextBox(const SwTable &, const SwTableBox *, bool bOvrTableLns=true) const
Definition: tblrwcl.cxx:2301
static void lcl_CalcNewWidths(const FndLines_t &rFndLines, CpyPara &rPara)
Definition: tblrwcl.cxx:1698
void setRowSpan(sal_Int32 nNewRowSpan)
Definition: swtable.cxx:79
sal_uInt16 GetPos(const SwTableLine *pBox) const
Definition: swtable.hxx:97
TableChgMode
Definition: tblenum.hxx:46
A layout frame is a frame that contains other frames (m_pLower), e.g. SwPageFrame or SwTabFrame...
Definition: layfrm.hxx:35
void AddNewBox(sal_uLong nSttNdIdx)
Definition: UndoTable.hxx:232
bool DeleteTableCellRedline(SwDoc *pDoc, const SwTableBox &rTableBox, bool bSaveInUndo, RedlineType nRedlineTypeToDelete)
Definition: docredln.cxx:252
const SwAttrSet & GetAttrSet() const
For querying the attribute array.
Definition: format.hxx:116
TableFormulaUpdateFlags m_eFlags
Definition: hints.hxx:246
Frame is variable in Var-direction.
const FndLine_ * GetUpper() const
Definition: tblsel.hxx:177
void SetNewTable(std::unique_ptr< SwTable >, bool bNewFrames=true)
Definition: ndtbl.cxx:2476
std::pair< const_iterator, bool > insert(Value &&x)
void DeleteBox(const SwTable *pTable, const SwTableBox &rBox)
Definition: unochart.cxx:1446
std::vector< Value >::size_type size_type
Subgroup table.
Definition: poolfmt.hxx:340
bool IsNewModel() const
Definition: swtable.hxx:187
const int nLineCount
SwTableLine * GetUpper()
Definition: swtable.hxx:428
const SwTable * InsertTable(const SwInsertTableOptions &rInsTableOpts, const SwPosition &rPos, sal_uInt16 nRows, sal_uInt16 nCols, sal_Int16 eAdjust, const SwTableAutoFormat *pTAFormat=nullptr, const std::vector< sal_uInt16 > *pColArr=nullptr, bool bCalledFromShell=false, bool bNewModel=true)
Insert new table at position.
Definition: ndtbl.cxx:336
void SetHeightSizeType(SwFrameSize eSize)
Definition: fmtfsize.hxx:81
void Height(tools::Long nNew)
Definition: swrect.hxx:191
bool operator==(const ScCsvLayoutData &rData1, const ScCsvLayoutData &rData2)
bool InsertRow_(SwDoc *, const SwSelBoxes &, sal_uInt16 nCnt, bool bBehind)
Definition: tblrwcl.cxx:510
const editeng::SvxBorderLine * GetBottom() const
bool IsDelBox() const
Definition: undobj.cxx:182
TableChgMode GetTableChgMode() const
Definition: swtable.hxx:332
sal_uInt16 Which() const
sal_uInt16 nPos
iterator erase(iterator aIt)
Definition: swtable.hxx:83
std::vector< Value >::const_iterator const_iterator
size_type erase(const Value &x)
SwRowFrame is one table row in the document layout.
Definition: rowfrm.hxx:28
bool MoveNodes(const SwNodeRange &, SwNodes &rNodes, const SwNodeIndex &, bool bNewFrames=true)
move the node pointer
Definition: nodes.cxx:394
void SetLine(const editeng::SvxBorderLine *pNew, SvxBoxItemLine nLine)
SwTwips CalcRowRstHeight(SwLayoutFrame *pRow)
Definition: frmtool.cxx:3591
Base class of the Writer document model elements.
Definition: node.hxx:79