android: Update app-specific/MIME type icons
[LibreOffice.git] / sw / source / core / doc / tblrwcl.cxx
blob2b519280485644f312b801d569d507ca0de0e63d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <memory>
21 #include <com/sun/star/text/HoriOrientation.hpp>
22 #include <osl/diagnose.h>
23 #include <svl/numformat.hxx>
24 #include <hintids.hxx>
26 #include <editeng/lrspitem.hxx>
27 #include <editeng/boxitem.hxx>
28 #include <tools/fract.hxx>
29 #include <fmtfsize.hxx>
30 #include <fmtornt.hxx>
31 #include <doc.hxx>
32 #include <IDocumentSettingAccess.hxx>
33 #include <IDocumentChartDataProviderAccess.hxx>
34 #include <DocumentContentOperationsManager.hxx>
35 #include <IDocumentRedlineAccess.hxx>
36 #include <IDocumentStylePoolAccess.hxx>
37 #include <IDocumentFieldsAccess.hxx>
38 #include <docsh.hxx>
39 #include <fesh.hxx>
40 #include <tabfrm.hxx>
41 #include <frmatr.hxx>
42 #include <frmtool.hxx>
43 #include <pam.hxx>
44 #include <swtable.hxx>
45 #include <tblsel.hxx>
46 #include <fldbas.hxx>
47 #include <rowfrm.hxx>
48 #include <ddefld.hxx>
49 #include <hints.hxx>
50 #include <UndoTable.hxx>
51 #include <cellatr.hxx>
52 #include <mvsave.hxx>
53 #include <swtblfmt.hxx>
54 #include <swddetbl.hxx>
55 #include <poolfmt.hxx>
56 #include <tblrwcl.hxx>
57 #include <unochart.hxx>
58 #include <o3tl/numeric.hxx>
59 #include <calbck.hxx>
60 #include <docary.hxx>
62 using namespace com::sun::star;
63 using namespace com::sun::star::uno;
65 #define COLFUZZY 20
66 #define ROWFUZZY 10
68 #ifdef DBG_UTIL
69 #define CHECK_TABLE(t) (t).CheckConsistency();
70 #else
71 #define CHECK_TABLE(t)
72 #endif
74 namespace {
76 // In order to set the Frame Formats for the Boxes, it's enough to look
77 // up the current one in the array. If it's already there return the new one.
78 struct CpyTabFrame
80 SwFrameFormat* pFrameFormat;
81 SwTableBoxFormat *pNewFrameFormat;
83 explicit CpyTabFrame(SwFrameFormat* pCurrentFrameFormat) : pNewFrameFormat( nullptr )
84 { pFrameFormat = pCurrentFrameFormat; }
86 bool operator==( const CpyTabFrame& rCpyTabFrame ) const
87 { return pFrameFormat == rCpyTabFrame.pFrameFormat; }
88 bool operator<( const CpyTabFrame& rCpyTabFrame ) const
89 { return pFrameFormat < rCpyTabFrame.pFrameFormat; }
92 struct CR_SetBoxWidth
94 SwShareBoxFormats aShareFormats;
95 SwTableNode* pTableNd;
96 SwTwips nDiff, nSide, nMaxSize, nLowerDiff;
97 TableChgMode nMode;
98 bool bBigger, bLeft;
100 CR_SetBoxWidth( TableChgWidthHeightType eType, SwTwips nDif, SwTwips nSid,
101 SwTwips nMax, SwTableNode* pTNd )
102 : pTableNd( pTNd ),
103 nDiff( nDif ), nSide( nSid ), nMaxSize( nMax ), nLowerDiff( 0 )
105 bLeft = TableChgWidthHeightType::ColLeft == extractPosition( eType ) ||
106 TableChgWidthHeightType::CellLeft == extractPosition( eType );
107 bBigger = bool(eType & TableChgWidthHeightType::BiggerMode );
108 nMode = pTableNd->GetTable().GetTableChgMode();
110 CR_SetBoxWidth( const CR_SetBoxWidth& rCpy )
111 : pTableNd( rCpy.pTableNd ),
112 nDiff( rCpy.nDiff ), nSide( rCpy.nSide ),
113 nMaxSize( rCpy.nMaxSize ), nLowerDiff( 0 ),
114 nMode( rCpy.nMode ),
115 bBigger( rCpy.bBigger ), bLeft( rCpy.bLeft )
119 void LoopClear()
121 nLowerDiff = 0;
127 static bool lcl_SetSelBoxWidth( SwTableLine* pLine, CR_SetBoxWidth& rParam,
128 SwTwips nDist, bool bCheck );
129 static bool lcl_SetOtherBoxWidth( SwTableLine* pLine, CR_SetBoxWidth& rParam,
130 SwTwips nDist, bool bCheck );
132 typedef bool (*FN_lcl_SetBoxWidth)(SwTableLine*, CR_SetBoxWidth&, SwTwips, bool );
134 #ifdef DBG_UTIL
136 #define CHECKBOXWIDTH \
138 SwTwips nSize = GetFrameFormat()->GetFrameSize().GetWidth(); \
139 for (size_t nTmp = 0; nTmp < m_aLines.size(); ++nTmp) \
140 ::CheckBoxWidth( *m_aLines[ nTmp ], nSize ); \
143 #define CHECKTABLELAYOUT \
145 for ( size_t i = 0; i < GetTabLines().size(); ++i ) \
147 SwFrameFormat* pFormat = GetTabLines()[i]->GetFrameFormat(); \
148 SwIterator<SwRowFrame,SwFormat> aIter( *pFormat ); \
149 for (SwRowFrame* pFrame=aIter.First(); pFrame; pFrame=aIter.Next())\
151 if ( pFrame->GetTabLine() == GetTabLines()[i] ) \
153 OSL_ENSURE( pFrame->GetUpper()->IsTabFrame(), \
154 "Table layout does not match table structure" ); \
160 #else
162 #define CHECKBOXWIDTH
163 #define CHECKTABLELAYOUT
165 #endif // DBG_UTIL
167 namespace {
169 struct CR_SetLineHeight
171 SwTableNode* pTableNd;
172 SwTwips nMaxSpace, nMaxHeight;
173 TableChgMode nMode;
174 bool bBigger;
176 CR_SetLineHeight( TableChgWidthHeightType eType, SwTableNode* pTNd )
177 : pTableNd( pTNd ),
178 nMaxSpace( 0 ), nMaxHeight( 0 )
180 bBigger = bool(eType & TableChgWidthHeightType::BiggerMode );
181 nMode = pTableNd->GetTable().GetTableChgMode();
183 CR_SetLineHeight( const CR_SetLineHeight& rCpy )
184 : pTableNd( rCpy.pTableNd ),
185 nMaxSpace( rCpy.nMaxSpace ), nMaxHeight( rCpy.nMaxHeight ),
186 nMode( rCpy.nMode ),
187 bBigger( rCpy.bBigger )
193 static bool lcl_SetSelLineHeight( SwTableLine* pLine, const CR_SetLineHeight& rParam,
194 SwTwips nDist, bool bCheck );
195 static bool lcl_SetOtherLineHeight( SwTableLine* pLine, const CR_SetLineHeight& rParam,
196 SwTwips nDist, bool bCheck );
198 typedef bool (*FN_lcl_SetLineHeight)(SwTableLine*, CR_SetLineHeight&, SwTwips, bool );
200 typedef o3tl::sorted_vector<CpyTabFrame> CpyTabFrames;
202 namespace {
204 struct CpyPara
206 std::shared_ptr< std::vector< std::vector< sal_uLong > > > pWidths;
207 SwDoc& rDoc;
208 SwTableNode* pTableNd;
209 CpyTabFrames& rTabFrameArr;
210 SwTableLine* pInsLine;
211 SwTableBox* pInsBox;
212 sal_uLong nOldSize, nNewSize; // in order to correct the size attributes
213 sal_uLong nMinLeft, nMaxRight;
214 sal_uInt16 nCpyCnt, nInsPos;
215 sal_uInt16 nLnIdx, nBoxIdx;
216 sal_uInt8 nDelBorderFlag;
217 bool bCpyContent;
219 CpyPara( SwTableNode* pNd, sal_uInt16 nCopies, CpyTabFrames& rFrameArr )
220 : rDoc( pNd->GetDoc() ), pTableNd( pNd ), rTabFrameArr(rFrameArr),
221 pInsLine(nullptr), pInsBox(nullptr), nOldSize(0), nNewSize(0),
222 nMinLeft(ULONG_MAX), nMaxRight(0),
223 nCpyCnt(nCopies), nInsPos(0),
224 nLnIdx(0), nBoxIdx(0),
225 nDelBorderFlag(0), bCpyContent( true )
227 CpyPara( const CpyPara& rPara, SwTableLine* pLine )
228 : pWidths( rPara.pWidths ), rDoc(rPara.rDoc), pTableNd(rPara.pTableNd),
229 rTabFrameArr(rPara.rTabFrameArr), pInsLine(pLine), pInsBox(rPara.pInsBox),
230 nOldSize(0), nNewSize(rPara.nNewSize), nMinLeft( rPara.nMinLeft ),
231 nMaxRight( rPara.nMaxRight ), nCpyCnt(rPara.nCpyCnt), nInsPos(0),
232 nLnIdx( rPara.nLnIdx), nBoxIdx( rPara.nBoxIdx ),
233 nDelBorderFlag( rPara.nDelBorderFlag ), bCpyContent( rPara.bCpyContent )
235 CpyPara( const CpyPara& rPara, SwTableBox* pBox )
236 : pWidths( rPara.pWidths ), rDoc(rPara.rDoc), pTableNd(rPara.pTableNd),
237 rTabFrameArr(rPara.rTabFrameArr), pInsLine(rPara.pInsLine), pInsBox(pBox),
238 nOldSize(rPara.nOldSize), nNewSize(rPara.nNewSize),
239 nMinLeft( rPara.nMinLeft ), nMaxRight( rPara.nMaxRight ),
240 nCpyCnt(rPara.nCpyCnt), nInsPos(0), nLnIdx(rPara.nLnIdx), nBoxIdx(rPara.nBoxIdx),
241 nDelBorderFlag( rPara.nDelBorderFlag ), bCpyContent( rPara.bCpyContent )
247 static SwTableLine* lcl_CopyRow(FndLine_ & rFndLine, CpyPara *const pCpyPara);
249 static void lcl_CopyCol( FndBox_ & rFndBox, CpyPara *const pCpyPara)
251 // Look up the Frame Format in the Frame Format Array
252 SwTableBox* pBox = rFndBox.GetBox();
253 CpyTabFrame aFindFrame(pBox->GetFrameFormat());
255 if( pCpyPara->nCpyCnt )
257 sal_uInt16 nFndPos;
258 CpyTabFrames::const_iterator itFind = pCpyPara->rTabFrameArr.lower_bound( aFindFrame );
259 nFndPos = itFind - pCpyPara->rTabFrameArr.begin();
260 if( itFind == pCpyPara->rTabFrameArr.end() || !(*itFind == aFindFrame) )
262 // For nested copying, also save the new Format as an old one.
263 SwTableBoxFormat* pNewFormat = static_cast<SwTableBoxFormat*>(pBox->ClaimFrameFormat());
265 // Find the selected Boxes in the Line:
266 FndLine_ const* pCmpLine = nullptr;
267 SwFormatFrameSize aFrameSz( pNewFormat->GetFrameSize() );
269 bool bDiffCount = false;
270 if( !pBox->GetTabLines().empty() )
272 pCmpLine = rFndBox.GetLines().front().get();
273 if ( pCmpLine->GetBoxes().size() != pCmpLine->GetLine()->GetTabBoxes().size() )
274 bDiffCount = true;
277 if( bDiffCount )
279 // The first Line should be enough
280 FndBoxes_t const& rFndBoxes = pCmpLine->GetBoxes();
281 tools::Long nSz = 0;
282 for( auto n = rFndBoxes.size(); n; )
284 nSz += rFndBoxes[--n]->GetBox()->
285 GetFrameFormat()->GetFrameSize().GetWidth();
287 aFrameSz.SetWidth( aFrameSz.GetWidth() -
288 nSz / ( pCpyPara->nCpyCnt + 1 ) );
289 pNewFormat->SetFormatAttr( aFrameSz );
290 aFrameSz.SetWidth( nSz / ( pCpyPara->nCpyCnt + 1 ) );
292 // Create a new Format for the new Box, specifying its size.
293 aFindFrame.pNewFrameFormat = reinterpret_cast<SwTableBoxFormat*>(pNewFormat->GetDoc()->
294 MakeTableLineFormat());
295 *aFindFrame.pNewFrameFormat = *pNewFormat;
296 aFindFrame.pNewFrameFormat->SetFormatAttr( aFrameSz );
298 else
300 aFrameSz.SetWidth( aFrameSz.GetWidth() / ( pCpyPara->nCpyCnt + 1 ) );
301 pNewFormat->SetFormatAttr( aFrameSz );
303 aFindFrame.pNewFrameFormat = pNewFormat;
304 pCpyPara->rTabFrameArr.insert( aFindFrame );
305 aFindFrame.pFrameFormat = pNewFormat;
306 pCpyPara->rTabFrameArr.insert( aFindFrame );
309 else
311 aFindFrame = pCpyPara->rTabFrameArr[ nFndPos ];
312 pBox->ChgFrameFormat( aFindFrame.pNewFrameFormat );
315 else
317 CpyTabFrames::const_iterator itFind = pCpyPara->rTabFrameArr.find( aFindFrame );
318 if( pCpyPara->nDelBorderFlag &&
319 itFind != pCpyPara->rTabFrameArr.end() )
320 aFindFrame = *itFind;
321 else
322 aFindFrame.pNewFrameFormat = static_cast<SwTableBoxFormat*>(pBox->GetFrameFormat());
325 if (!rFndBox.GetLines().empty())
327 pBox = new SwTableBox( aFindFrame.pNewFrameFormat,
328 rFndBox.GetLines().size(), pCpyPara->pInsLine );
329 pCpyPara->pInsLine->GetTabBoxes().insert( pCpyPara->pInsLine->GetTabBoxes().begin() + pCpyPara->nInsPos++, pBox );
330 CpyPara aPara( *pCpyPara, pBox );
331 aPara.nDelBorderFlag &= 7;
333 for (auto const& pFndLine : rFndBox.GetLines())
335 lcl_CopyRow(*pFndLine, &aPara);
338 else
340 ::InsTableBox( pCpyPara->rDoc, pCpyPara->pTableNd, pCpyPara->pInsLine,
341 aFindFrame.pNewFrameFormat, pBox, pCpyPara->nInsPos++ );
343 const FndBoxes_t& rFndBxs = rFndBox.GetUpper()->GetBoxes();
344 if( 8 > pCpyPara->nDelBorderFlag
345 ? pCpyPara->nDelBorderFlag != 0
346 : &rFndBox == rFndBxs[rFndBxs.size() - 1].get())
348 const SvxBoxItem& rBoxItem = pBox->GetFrameFormat()->GetBox();
349 if( 8 > pCpyPara->nDelBorderFlag
350 ? rBoxItem.GetTop()
351 : rBoxItem.GetRight() )
353 aFindFrame.pFrameFormat = pBox->GetFrameFormat();
355 SvxBoxItem aNew( rBoxItem );
356 if( 8 > pCpyPara->nDelBorderFlag )
357 aNew.SetLine( nullptr, SvxBoxItemLine::TOP );
358 else
359 aNew.SetLine( nullptr, SvxBoxItemLine::RIGHT );
361 if( 1 == pCpyPara->nDelBorderFlag ||
362 8 == pCpyPara->nDelBorderFlag )
364 // For all Boxes that delete TopBorderLine, we copy after that
365 pBox = pCpyPara->pInsLine->GetTabBoxes()[
366 pCpyPara->nInsPos - 1 ];
369 aFindFrame.pNewFrameFormat = static_cast<SwTableBoxFormat*>(pBox->GetFrameFormat());
371 // Else we copy before that and the first Line keeps the TopLine
372 // and we remove it at the original
373 pBox->ClaimFrameFormat()->SetFormatAttr( aNew );
375 if( !pCpyPara->nCpyCnt )
376 pCpyPara->rTabFrameArr.insert( aFindFrame );
382 static SwTableLine* lcl_CopyRow(FndLine_& rFndLine, CpyPara *const pCpyPara)
384 SwTableLine* pNewLine = new SwTableLine(
385 static_cast<SwTableLineFormat*>(rFndLine.GetLine()->GetFrameFormat()),
386 rFndLine.GetBoxes().size(), pCpyPara->pInsBox );
387 if( pCpyPara->pInsBox )
389 SwTableLines& rLines = pCpyPara->pInsBox->GetTabLines();
390 rLines.insert( rLines.begin() + pCpyPara->nInsPos++, pNewLine );
392 else
394 SwTableLines& rLines = pCpyPara->pTableNd->GetTable().GetTabLines();
395 rLines.insert( rLines.begin() + pCpyPara->nInsPos++, pNewLine );
398 CpyPara aPara( *pCpyPara, pNewLine );
399 for (auto const& it : rFndLine.GetBoxes())
401 lcl_CopyCol(*it, &aPara);
404 pCpyPara->nDelBorderFlag &= 0xf8;
406 return pNewLine;
409 static void lcl_InsCol( FndLine_* pFndLn, CpyPara& rCpyPara, sal_uInt16 nCpyCnt,
410 bool bBehind )
412 // Bug 29124: Not only copy in the BaseLines. If possible, we go down as far as possible
413 FndBox_* pFBox;
414 if( 1 == pFndLn->GetBoxes().size() &&
415 !( pFBox = pFndLn->GetBoxes()[0].get() )->GetBox()->GetSttNd() )
417 // A Box with multiple Lines, so insert into these Lines
418 for (auto &rpLine : pFBox->GetLines())
420 lcl_InsCol( rpLine.get(), rCpyPara, nCpyCnt, bBehind );
423 else
425 rCpyPara.pInsLine = pFndLn->GetLine();
426 SwTableBox* pBox = pFndLn->GetBoxes()[ bBehind ?
427 pFndLn->GetBoxes().size()-1 : 0 ]->GetBox();
428 rCpyPara.nInsPos = pFndLn->GetLine()->GetBoxPos( pBox );
429 if( bBehind )
430 ++rCpyPara.nInsPos;
432 for( sal_uInt16 n = 0; n < nCpyCnt; ++n )
434 if( n + 1 == nCpyCnt && bBehind )
435 rCpyPara.nDelBorderFlag = 9;
436 else
437 rCpyPara.nDelBorderFlag = 8;
438 for (auto const& it : pFndLn->GetBoxes())
440 lcl_CopyCol(*it, &rCpyPara);
446 static SwRowFrame* GetRowFrame( SwTableLine& rLine )
448 SwIterator<SwRowFrame,SwFormat> aIter( *rLine.GetFrameFormat() );
449 for( SwRowFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next() )
450 if( pFrame->GetTabLine() == &rLine )
451 return pFrame;
452 return nullptr;
455 bool SwTable::InsertCol( SwDoc& rDoc, const SwSelBoxes& rBoxes, sal_uInt16 nCnt,
456 bool bBehind, bool bInsertDummy )
458 OSL_ENSURE( !rBoxes.empty() && nCnt, "No valid Box List" );
459 SwTableNode* pTableNd = const_cast<SwTableNode*>(rBoxes[0]->GetSttNd()->FindTableNode());
460 if( !pTableNd )
461 return false;
463 bool bRes = true;
464 if( IsNewModel() )
465 bRes = NewInsertCol( rDoc, rBoxes, nCnt, bBehind, bInsertDummy );
466 else
468 // Find all Boxes/Lines
469 FndBox_ aFndBox( nullptr, nullptr );
471 FndPara aPara( rBoxes, &aFndBox );
472 ForEach_FndLineCopyCol( GetTabLines(), &aPara );
474 if( aFndBox.GetLines().empty() )
475 return false;
477 SetHTMLTableLayout(std::shared_ptr<SwHTMLTableLayout>()); // Delete HTML Layout
479 // Find Lines for the layout update
480 aFndBox.SetTableLines( *this );
481 aFndBox.DelFrames( *this );
483 // TL_CHART2: nothing to be done since chart2 currently does not want to
484 // get notified about new rows/cols.
486 CpyTabFrames aTabFrameArr;
487 CpyPara aCpyPara( pTableNd, nCnt, aTabFrameArr );
489 for (auto & rpLine : aFndBox.GetLines())
491 lcl_InsCol( rpLine.get(), aCpyPara, nCnt, bBehind );
494 // clean up this Line's structure once again, generally all of them
495 GCLines();
497 // Update Layout
498 aFndBox.MakeFrames( *this );
500 CHECKBOXWIDTH;
501 CHECKTABLELAYOUT;
502 bRes = true;
505 SwChartDataProvider *pPCD = rDoc.getIDocumentChartDataProviderAccess().GetChartDataProvider();
506 if (pPCD && nCnt)
507 pPCD->AddRowCols( *this, rBoxes, nCnt, bBehind );
508 rDoc.UpdateCharts( GetFrameFormat()->GetName() );
510 if (SwFEShell* pFEShell = rDoc.GetDocShell()->GetFEShell())
511 pFEShell->UpdateTableStyleFormatting();
513 return bRes;
516 bool SwTable::InsertRow_( SwDoc* pDoc, const SwSelBoxes& rBoxes,
517 sal_uInt16 nCnt, bool bBehind, bool bInsertDummy )
519 OSL_ENSURE( pDoc && !rBoxes.empty() && nCnt, "No valid Box List" );
520 SwTableNode* pTableNd = const_cast<SwTableNode*>(rBoxes[0]->GetSttNd()->FindTableNode());
521 if( !pTableNd )
522 return false;
524 // Find all Boxes/Lines
525 FndBox_ aFndBox( nullptr, nullptr );
527 FndPara aPara( rBoxes, &aFndBox );
528 ForEach_FndLineCopyCol( GetTabLines(), &aPara );
530 if( aFndBox.GetLines().empty() )
531 return false;
533 SetHTMLTableLayout(std::shared_ptr<SwHTMLTableLayout>()); // Delete HTML Layout
535 FndBox_* pFndBox = &aFndBox;
537 FndLine_* pFndLine;
538 while( 1 == pFndBox->GetLines().size() )
540 pFndLine = pFndBox->GetLines()[0].get();
541 if( 1 != pFndLine->GetBoxes().size() )
542 break;
543 // Don't go down too far! One Line with Box needs to remain!
544 FndBox_ *const pTmpBox = pFndLine->GetBoxes().front().get();
545 if( !pTmpBox->GetLines().empty() )
546 pFndBox = pTmpBox;
547 else
548 break;
552 // Find Lines for the layout update
553 const bool bLayout = !IsNewModel() &&
554 nullptr != SwIterator<SwTabFrame,SwFormat>( *GetFrameFormat() ).First();
556 if ( bLayout )
558 aFndBox.SetTableLines( *this );
559 if( pFndBox != &aFndBox )
560 aFndBox.DelFrames( *this );
561 // TL_CHART2: nothing to be done since chart2 currently does not want to
562 // get notified about new rows/cols.
565 CpyTabFrames aTabFrameArr;
566 CpyPara aCpyPara( pTableNd, 0, aTabFrameArr );
568 SwTableLine* pLine = pFndBox->GetLines()[ bBehind ?
569 pFndBox->GetLines().size()-1 : 0 ]->GetLine();
570 if( &aFndBox == pFndBox )
571 aCpyPara.nInsPos = GetTabLines().GetPos( pLine );
572 else
574 aCpyPara.pInsBox = pFndBox->GetBox();
575 aCpyPara.nInsPos = pFndBox->GetBox()->GetTabLines().GetPos( pLine );
578 if( bBehind )
580 ++aCpyPara.nInsPos;
581 aCpyPara.nDelBorderFlag = 1;
583 else
584 aCpyPara.nDelBorderFlag = 2;
586 for( sal_uInt16 nCpyCnt = 0; nCpyCnt < nCnt; ++nCpyCnt )
588 if( bBehind )
589 aCpyPara.nDelBorderFlag = 1;
590 for (auto & rpFndLine : pFndBox->GetLines())
592 SwTableLine* pNewTableLine = lcl_CopyRow( *rpFndLine, &aCpyPara );
594 // tracked insertion of empty table line
595 if ( pDoc->getIDocumentRedlineAccess().IsRedlineOn() )
597 SvxPrintItem aSetTracking(RES_PRINT, false);
598 SwPosition aPos(*pNewTableLine->GetTabBoxes()[0]->GetSttNd());
599 SwCursor aCursor( aPos, nullptr );
600 if ( bInsertDummy )
602 SwPaM aPaM(*pNewTableLine->GetTabBoxes()[0]->GetSttNd(), SwNodeOffset(1));
603 pDoc->getIDocumentContentOperations().InsertString( aPaM,
604 OUStringChar(CH_TXT_TRACKED_DUMMY_CHAR) );
606 pDoc->SetRowNotTracked( aCursor, aSetTracking, /*bAll=*/false, /*bIns=*/true );
611 // clean up this Line's structure once again, generally all of them
612 if( !pDoc->IsInReading() )
613 GCLines();
615 // Update Layout
616 if ( bLayout )
618 if( pFndBox != &aFndBox )
619 aFndBox.MakeFrames( *this );
620 else
621 aFndBox.MakeNewFrames( *this, nCnt, bBehind );
624 CHECKBOXWIDTH;
625 CHECKTABLELAYOUT;
627 SwChartDataProvider *pPCD = pDoc->getIDocumentChartDataProviderAccess().GetChartDataProvider();
628 if (pPCD && nCnt)
629 pPCD->AddRowCols( *this, rBoxes, nCnt, bBehind );
630 pDoc->UpdateCharts( GetFrameFormat()->GetName() );
632 if (SwFEShell* pFEShell = pDoc->GetDocShell()->GetFEShell())
633 pFEShell->UpdateTableStyleFormatting(pTableNd);
635 return true;
638 static void lcl_LastBoxSetWidth( SwTableBoxes &rBoxes, const tools::Long nOffset,
639 bool bFirst, SwShareBoxFormats& rShareFormats );
641 static void lcl_LastBoxSetWidthLine( SwTableLines &rLines, const tools::Long nOffset,
642 bool bFirst, SwShareBoxFormats& rShareFormats )
644 for ( auto pLine : rLines )
645 ::lcl_LastBoxSetWidth( pLine->GetTabBoxes(), nOffset, bFirst, rShareFormats );
648 static void lcl_LastBoxSetWidth( SwTableBoxes &rBoxes, const tools::Long nOffset,
649 bool bFirst, SwShareBoxFormats& rShareFormats )
651 SwTableBox& rBox = *(bFirst ? rBoxes.front() : rBoxes.back());
652 if( !rBox.GetSttNd() )
653 ::lcl_LastBoxSetWidthLine( rBox.GetTabLines(), nOffset,
654 bFirst, rShareFormats );
656 // Adapt the Box
657 const SwFrameFormat *pBoxFormat = rBox.GetFrameFormat();
658 SwFormatFrameSize aNew( pBoxFormat->GetFrameSize() );
659 aNew.SetWidth( aNew.GetWidth() + nOffset );
660 SwFrameFormat *pFormat = rShareFormats.GetFormat( *pBoxFormat, aNew );
661 if( pFormat )
662 rBox.ChgFrameFormat( static_cast<SwTableBoxFormat*>(pFormat) );
663 else
665 pFormat = rBox.ClaimFrameFormat();
667 pFormat->LockModify();
668 pFormat->SetFormatAttr( aNew );
669 pFormat->UnlockModify();
671 rShareFormats.AddFormat( *pBoxFormat, *pFormat );
675 void DeleteBox_( SwTable& rTable, SwTableBox* pBox, SwUndo* pUndo,
676 bool bCalcNewSize, const bool bCorrBorder,
677 SwShareBoxFormats* pShareFormats )
679 do {
680 SwTwips nBoxSz = bCalcNewSize ?
681 pBox->GetFrameFormat()->GetFrameSize().GetWidth() : 0;
682 SwTableLine* pLine = pBox->GetUpper();
683 SwTableBoxes& rTableBoxes = pLine->GetTabBoxes();
684 sal_uInt16 nDelPos = pLine->GetBoxPos( pBox );
685 SwTableBox* pUpperBox = pBox->GetUpper()->GetUpper();
687 // Special treatment for the border:
688 if( bCorrBorder && 1 < rTableBoxes.size() )
690 const SvxBoxItem& rBoxItem = pBox->GetFrameFormat()->GetBox();
692 if( rBoxItem.GetLeft() || rBoxItem.GetRight() )
694 bool bChgd = false;
696 // JP 02.04.97: 1st part for Bug 36271
697 // First the left/right edges
698 if( nDelPos + 1 < o3tl::narrowing<sal_uInt16>(rTableBoxes.size()) )
700 SwTableBox* pNxtBox = rTableBoxes[ nDelPos + 1 ];
701 const SvxBoxItem& rNxtBoxItem = pNxtBox->GetFrameFormat()->GetBox();
703 SwTableBox* pPrvBox = nDelPos ? rTableBoxes[ nDelPos - 1 ] : nullptr;
705 if( pNxtBox->GetSttNd() && !rNxtBoxItem.GetLeft() &&
706 ( !pPrvBox || !pPrvBox->GetFrameFormat()->GetBox().GetRight()) )
708 SvxBoxItem aTmp( rNxtBoxItem );
709 aTmp.SetLine( rBoxItem.GetLeft() ? rBoxItem.GetLeft()
710 : rBoxItem.GetRight(),
711 SvxBoxItemLine::LEFT );
712 if( pShareFormats )
713 pShareFormats->SetAttr( *pNxtBox, aTmp );
714 else
715 pNxtBox->ClaimFrameFormat()->SetFormatAttr( aTmp );
716 bChgd = true;
719 if( !bChgd && nDelPos )
721 SwTableBox* pPrvBox = rTableBoxes[ nDelPos - 1 ];
722 const SvxBoxItem& rPrvBoxItem = pPrvBox->GetFrameFormat()->GetBox();
724 SwTableBox* pNxtBox = nDelPos + 1 < o3tl::narrowing<sal_uInt16>(rTableBoxes.size())
725 ? rTableBoxes[ nDelPos + 1 ] : nullptr;
727 if( pPrvBox->GetSttNd() && !rPrvBoxItem.GetRight() &&
728 ( !pNxtBox || !pNxtBox->GetFrameFormat()->GetBox().GetLeft()) )
730 SvxBoxItem aTmp( rPrvBoxItem );
731 aTmp.SetLine( rBoxItem.GetLeft() ? rBoxItem.GetLeft()
732 : rBoxItem.GetRight(),
733 SvxBoxItemLine::RIGHT );
734 if( pShareFormats )
735 pShareFormats->SetAttr( *pPrvBox, aTmp );
736 else
737 pPrvBox->ClaimFrameFormat()->SetFormatAttr( aTmp );
743 // Delete the Box first, then the Nodes!
744 SwStartNode* pSttNd = const_cast<SwStartNode*>(pBox->GetSttNd());
745 if( pShareFormats )
746 pShareFormats->RemoveFormat( *rTableBoxes[ nDelPos ]->GetFrameFormat() );
748 // Before deleting the 'Table Box' from memory - delete any redlines attached to it
749 rTable.GetFrameFormat()->GetDoc()->getIDocumentRedlineAccess().GetExtraRedlineTable().DeleteTableCellRedline( rTable.GetFrameFormat()->GetDoc(), *(rTableBoxes[nDelPos]), true, RedlineType::Any );
750 delete rTableBoxes[nDelPos];
751 rTableBoxes.erase( rTableBoxes.begin() + nDelPos );
753 if( pSttNd )
755 // Has the UndoObject been prepared to save the Section?
756 if( pUndo && pUndo->IsDelBox() )
757 static_cast<SwUndoTableNdsChg*>(pUndo)->SaveSection( pSttNd );
758 else
759 pSttNd->GetDoc().getIDocumentContentOperations().DeleteSection( pSttNd );
762 // Also delete the Line?
763 if( !rTableBoxes.empty() )
765 // Then adapt the Frame-SSize
766 bool bLastBox = nDelPos == rTableBoxes.size();
767 if( bLastBox )
768 --nDelPos;
769 pBox = rTableBoxes[nDelPos];
770 if( bCalcNewSize )
772 SwFormatFrameSize aNew( pBox->GetFrameFormat()->GetFrameSize() );
773 aNew.SetWidth( aNew.GetWidth() + nBoxSz );
774 if( pShareFormats )
775 pShareFormats->SetSize( *pBox, aNew );
776 else
777 pBox->ClaimFrameFormat()->SetFormatAttr( aNew );
779 if( !pBox->GetSttNd() )
781 // We need to this recursively in all Lines in all Cells!
782 SwShareBoxFormats aShareFormats;
783 ::lcl_LastBoxSetWidthLine( pBox->GetTabLines(), nBoxSz,
784 !bLastBox,
785 pShareFormats ? *pShareFormats
786 : aShareFormats );
789 break; // Stop deleting
791 // Delete the Line from the Table/Box
792 if( !pUpperBox )
794 // Also delete the Line from the Table
795 nDelPos = rTable.GetTabLines().GetPos( pLine );
796 if( pShareFormats )
797 pShareFormats->RemoveFormat( *rTable.GetTabLines()[ nDelPos ]->GetFrameFormat() );
799 SwTableLine* pTabLineToDelete = rTable.GetTabLines()[ nDelPos ];
800 // Before deleting the 'Table Line' from memory - delete any redlines attached to it
801 rTable.GetFrameFormat()->GetDoc()->getIDocumentRedlineAccess().GetExtraRedlineTable().DeleteTableRowRedline( rTable.GetFrameFormat()->GetDoc(), *pTabLineToDelete, true, RedlineType::Any );
802 delete pTabLineToDelete;
803 rTable.GetTabLines().erase( rTable.GetTabLines().begin() + nDelPos );
804 break; // we cannot delete more
807 // finally also delete the Line
808 pBox = pUpperBox;
809 nDelPos = pBox->GetTabLines().GetPos( pLine );
810 if( pShareFormats )
811 pShareFormats->RemoveFormat( *pBox->GetTabLines()[ nDelPos ]->GetFrameFormat() );
813 SwTableLine* pTabLineToDelete = pBox->GetTabLines()[ nDelPos ];
814 // Before deleting the 'Table Line' from memory - delete any redlines attached to it
815 rTable.GetFrameFormat()->GetDoc()->getIDocumentRedlineAccess().GetExtraRedlineTable().DeleteTableRowRedline( rTable.GetFrameFormat()->GetDoc(), *pTabLineToDelete, true, RedlineType::Any );
816 delete pTabLineToDelete;
817 pBox->GetTabLines().erase( pBox->GetTabLines().begin() + nDelPos );
818 } while( pBox->GetTabLines().empty() );
821 static SwTableBox*
822 lcl_FndNxtPrvDelBox( const SwTableLines& rTableLns,
823 SwTwips nBoxStt, SwTwips nBoxWidth,
824 sal_uInt16 nLinePos, bool bNxt,
825 SwSelBoxes* pAllDelBoxes, size_t *const pCurPos)
827 SwTableBox* pFndBox = nullptr;
828 do {
829 if( bNxt )
830 ++nLinePos;
831 else
832 --nLinePos;
833 SwTableLine* pLine = rTableLns[ nLinePos ];
834 SwTwips nFndBoxWidth = 0;
835 SwTwips nFndWidth = nBoxStt + nBoxWidth;
837 pFndBox = pLine->GetTabBoxes()[ 0 ];
838 for( auto pBox : pLine->GetTabBoxes() )
840 if ( nFndWidth <= 0 )
842 break;
844 pFndBox = pBox;
845 nFndBoxWidth = pFndBox->GetFrameFormat()->GetFrameSize().GetWidth();
846 nFndWidth -= nFndBoxWidth;
849 // Find the first ContentBox
850 while( !pFndBox->GetSttNd() )
852 const SwTableLines& rLowLns = pFndBox->GetTabLines();
853 if( bNxt )
854 pFndBox = rLowLns.front()->GetTabBoxes().front();
855 else
856 pFndBox = rLowLns.back()->GetTabBoxes().front();
859 if( std::abs( nFndWidth ) > COLFUZZY ||
860 std::abs( nBoxWidth - nFndBoxWidth ) > COLFUZZY )
861 pFndBox = nullptr;
862 else if( pAllDelBoxes )
864 // If the predecessor will also be deleted, there's nothing to do
865 SwSelBoxes::const_iterator aFndIt = pAllDelBoxes->find( pFndBox);
866 if( aFndIt == pAllDelBoxes->end() )
867 break;
868 size_t const nFndPos = aFndIt - pAllDelBoxes->begin() ;
870 // else, we keep on searching.
871 // We do not need to recheck the Box, however
872 pFndBox = nullptr;
873 if( nFndPos <= *pCurPos )
874 --*pCurPos;
875 pAllDelBoxes->erase( pAllDelBoxes->begin() + nFndPos );
877 } while( bNxt ? ( nLinePos + 1 < o3tl::narrowing<sal_uInt16>(rTableLns.size()) ) : nLinePos != 0 );
878 return pFndBox;
881 static void
882 lcl_SaveUpperLowerBorder( SwTable& rTable, const SwTableBox& rBox,
883 SwShareBoxFormats& rShareFormats,
884 SwSelBoxes* pAllDelBoxes = nullptr,
885 size_t *const pCurPos = nullptr )
887 //JP 16.04.97: 2. part for Bug 36271
888 const SwTableLine* pLine = rBox.GetUpper();
889 const SwTableBoxes& rTableBoxes = pLine->GetTabBoxes();
890 const SwTableBox* pUpperBox = &rBox;
891 sal_uInt16 nDelPos = pLine->GetBoxPos( pUpperBox );
892 pUpperBox = rBox.GetUpper()->GetUpper();
893 const SvxBoxItem& rBoxItem = rBox.GetFrameFormat()->GetBox();
895 // then the top/bottom edges
896 if( !rBoxItem.GetTop() && !rBoxItem.GetBottom() )
897 return;
899 bool bChgd = false;
900 const SwTableLines* pTableLns;
901 if( pUpperBox )
902 pTableLns = &pUpperBox->GetTabLines();
903 else
904 pTableLns = &rTable.GetTabLines();
906 sal_uInt16 nLnPos = pTableLns->GetPos( pLine );
908 // Calculate the attribute position of the top-be-deleted Box and then
909 // search in the top/bottom Line of the respective counterparts.
910 SwTwips nBoxStt = 0;
911 for( sal_uInt16 n = 0; n < nDelPos; ++n )
912 nBoxStt += rTableBoxes[ n ]->GetFrameFormat()->GetFrameSize().GetWidth();
913 SwTwips nBoxWidth = rBox.GetFrameFormat()->GetFrameSize().GetWidth();
915 SwTableBox *pPrvBox = nullptr, *pNxtBox = nullptr;
916 if( nLnPos ) // Predecessor?
917 pPrvBox = ::lcl_FndNxtPrvDelBox( *pTableLns, nBoxStt, nBoxWidth,
918 nLnPos, false, pAllDelBoxes, pCurPos );
920 if( nLnPos + 1 < o3tl::narrowing<sal_uInt16>(pTableLns->size()) ) // Successor?
921 pNxtBox = ::lcl_FndNxtPrvDelBox( *pTableLns, nBoxStt, nBoxWidth,
922 nLnPos, true, pAllDelBoxes, pCurPos );
924 if( pNxtBox && pNxtBox->GetSttNd() )
926 const SvxBoxItem& rNxtBoxItem = pNxtBox->GetFrameFormat()->GetBox();
927 if( !rNxtBoxItem.GetTop() && ( !pPrvBox ||
928 !pPrvBox->GetFrameFormat()->GetBox().GetBottom()) )
930 SvxBoxItem aTmp( rNxtBoxItem );
931 aTmp.SetLine( rBoxItem.GetTop() ? rBoxItem.GetTop()
932 : rBoxItem.GetBottom(),
933 SvxBoxItemLine::TOP );
934 rShareFormats.SetAttr( *pNxtBox, aTmp );
935 bChgd = true;
938 if( !(!bChgd && pPrvBox && pPrvBox->GetSttNd()) )
939 return;
941 const SvxBoxItem& rPrvBoxItem = pPrvBox->GetFrameFormat()->GetBox();
942 if( !rPrvBoxItem.GetTop() && ( !pNxtBox ||
943 !pNxtBox->GetFrameFormat()->GetBox().GetTop()) )
945 SvxBoxItem aTmp( rPrvBoxItem );
946 aTmp.SetLine( rBoxItem.GetTop() ? rBoxItem.GetTop()
947 : rBoxItem.GetBottom(),
948 SvxBoxItemLine::BOTTOM );
949 rShareFormats.SetAttr( *pPrvBox, aTmp );
954 bool SwTable::DeleteSel(
955 SwDoc* pDoc
957 const SwSelBoxes& rBoxes,
958 const SwSelBoxes* pMerged, SwUndo* pUndo,
959 const bool bDelMakeFrames, const bool bCorrBorder )
961 OSL_ENSURE( pDoc, "No doc?" );
962 SwTableNode* pTableNd = nullptr;
963 if( !rBoxes.empty() )
965 pTableNd = const_cast<SwTableNode*>(rBoxes[0]->GetSttNd()->FindTableNode());
966 if( !pTableNd )
967 return false;
970 SetHTMLTableLayout(std::shared_ptr<SwHTMLTableLayout>()); // Delete HTML Layout
972 // Find Lines for the Layout update
973 FndBox_ aFndBox( nullptr, nullptr );
974 if ( bDelMakeFrames )
976 if( pMerged && !pMerged->empty() )
977 aFndBox.SetTableLines( *pMerged, *this );
978 else if( !rBoxes.empty() )
979 aFndBox.SetTableLines( rBoxes, *this );
980 aFndBox.DelFrames( *this );
983 SwShareBoxFormats aShareFormats;
985 // First switch the Border, then delete
986 if( bCorrBorder )
988 SwSelBoxes aBoxes( rBoxes );
989 for (size_t n = 0; n < aBoxes.size(); ++n)
991 ::lcl_SaveUpperLowerBorder( *this, *rBoxes[ n ], aShareFormats,
992 &aBoxes, &n );
996 PrepareDelBoxes( rBoxes );
998 SwChartDataProvider *pPCD = pDoc->getIDocumentChartDataProviderAccess().GetChartDataProvider();
999 // Delete boxes from last to first
1000 for (size_t n = 0; n < rBoxes.size(); ++n)
1002 size_t const nIdx = rBoxes.size() - 1 - n;
1004 // First adapt the data-sequence for chart if necessary
1005 // (needed to move the implementation cursor properly to its new
1006 // position which can't be done properly if the cell is already gone)
1007 if (pPCD && pTableNd)
1008 pPCD->DeleteBox( &pTableNd->GetTable(), *rBoxes[nIdx] );
1010 // ... then delete the boxes
1011 DeleteBox_( *this, rBoxes[nIdx], pUndo, true, bCorrBorder, &aShareFormats );
1014 // then clean up the structure of all Lines
1015 GCLines();
1017 if( bDelMakeFrames && aFndBox.AreLinesToRestore( *this ) )
1018 aFndBox.MakeFrames( *this );
1020 // TL_CHART2: now inform chart that sth has changed
1021 pDoc->UpdateCharts( GetFrameFormat()->GetName() );
1023 CHECKTABLELAYOUT;
1024 CHECK_TABLE( *this );
1026 return true;
1029 bool SwTable::OldSplitRow( SwDoc& rDoc, const SwSelBoxes& rBoxes, sal_uInt16 nCnt,
1030 bool bSameHeight )
1032 OSL_ENSURE( !rBoxes.empty() && nCnt, "No valid values" );
1033 SwTableNode* pTableNd = const_cast<SwTableNode*>(rBoxes[0]->GetSttNd()->FindTableNode());
1034 if( !pTableNd )
1035 return false;
1037 // TL_CHART2: splitting/merging of a number of cells or rows will usually make
1038 // the table too complex to be handled with chart.
1039 // Thus we tell the charts to use their own data provider and forget about this table
1040 rDoc.getIDocumentChartDataProviderAccess().CreateChartInternalDataProviders( this );
1042 SetHTMLTableLayout(std::shared_ptr<SwHTMLTableLayout>()); // Delete HTML Layout
1044 // If the rows should get the same (min) height, we first have
1045 // to store the old row heights before deleting the frames
1046 std::unique_ptr<tools::Long[]> pRowHeights;
1047 if ( bSameHeight )
1049 pRowHeights.reset(new tools::Long[ rBoxes.size() ]);
1050 for (size_t n = 0; n < rBoxes.size(); ++n)
1052 SwTableBox* pSelBox = rBoxes[n];
1053 const SwRowFrame* pRow = GetRowFrame( *pSelBox->GetUpper() );
1054 OSL_ENSURE( pRow, "Where is the SwTableLine's Frame?" );
1055 SwRectFnSet aRectFnSet(pRow);
1056 pRowHeights[ n ] = aRectFnSet.GetHeight(pRow->getFrameArea());
1060 // Find Lines for the Layout update
1061 FndBox_ aFndBox( nullptr, nullptr );
1062 aFndBox.SetTableLines( rBoxes, *this );
1063 aFndBox.DelFrames( *this );
1065 for (size_t n = 0; n < rBoxes.size(); ++n)
1067 SwTableBox* pSelBox = rBoxes[n];
1068 OSL_ENSURE( pSelBox, "Box is not within the Table" );
1070 // Insert nCnt new Lines into the Box
1071 SwTableLine* pInsLine = pSelBox->GetUpper();
1072 SwTableBoxFormat* pFrameFormat = static_cast<SwTableBoxFormat*>(pSelBox->GetFrameFormat());
1074 // Respect the Line's height, reset if needed
1075 SwFormatFrameSize aFSz( pInsLine->GetFrameFormat()->GetFrameSize() );
1076 if ( bSameHeight && SwFrameSize::Variable == aFSz.GetHeightSizeType() )
1077 aFSz.SetHeightSizeType( SwFrameSize::Minimum );
1079 bool bChgLineSz = 0 != aFSz.GetHeight() || bSameHeight;
1080 if ( bChgLineSz )
1081 aFSz.SetHeight( ( bSameHeight ? pRowHeights[ n ] : aFSz.GetHeight() ) /
1082 (nCnt + 1) );
1084 SwTableBox* pNewBox = new SwTableBox( pFrameFormat, nCnt, pInsLine );
1085 sal_uInt16 nBoxPos = pInsLine->GetBoxPos( pSelBox );
1086 pInsLine->GetTabBoxes()[nBoxPos] = pNewBox; // overwrite old one
1088 // Delete background/border attribute
1089 SwTableBox* pLastBox = pSelBox; // To distribute the TextNodes!
1090 // If Areas are contained in the Box, it stays as is
1091 // !! If this is changed we need to adapt the Undo, too !!!
1092 bool bMoveNodes = true;
1094 SwNodeOffset nSttNd = pLastBox->GetSttIdx() + 1,
1095 nEndNd = pLastBox->GetSttNd()->EndOfSectionIndex();
1096 while( nSttNd < nEndNd )
1097 if( !rDoc.GetNodes()[ nSttNd++ ]->IsTextNode() )
1099 bMoveNodes = false;
1100 break;
1104 SwTableBoxFormat* pCpyBoxFrameFormat = static_cast<SwTableBoxFormat*>(pSelBox->GetFrameFormat());
1105 bool bChkBorder = nullptr != pCpyBoxFrameFormat->GetBox().GetTop();
1106 if( bChkBorder )
1107 pCpyBoxFrameFormat = static_cast<SwTableBoxFormat*>(pSelBox->ClaimFrameFormat());
1109 for( sal_uInt16 i = 0; i <= nCnt; ++i )
1111 // Create a new Line in the new Box
1112 SwTableLine* pNewLine = new SwTableLine(
1113 static_cast<SwTableLineFormat*>(pInsLine->GetFrameFormat()), 1, pNewBox );
1114 if( bChgLineSz )
1116 pNewLine->ClaimFrameFormat()->SetFormatAttr( aFSz );
1119 pNewBox->GetTabLines().insert( pNewBox->GetTabLines().begin() + i, pNewLine );
1120 // then a new Box in the Line
1121 if( !i ) // hang up the original Box
1123 pSelBox->SetUpper( pNewLine );
1124 pNewLine->GetTabBoxes().insert( pNewLine->GetTabBoxes().begin(), pSelBox );
1126 else
1128 ::InsTableBox( rDoc, pTableNd, pNewLine, pCpyBoxFrameFormat,
1129 pLastBox, 0 );
1131 if( bChkBorder )
1133 pCpyBoxFrameFormat = static_cast<SwTableBoxFormat*>(pNewLine->GetTabBoxes()[ 0 ]->ClaimFrameFormat());
1134 SvxBoxItem aTmp( pCpyBoxFrameFormat->GetBox() );
1135 aTmp.SetLine( nullptr, SvxBoxItemLine::TOP );
1136 pCpyBoxFrameFormat->SetFormatAttr( aTmp );
1137 bChkBorder = false;
1140 if( bMoveNodes )
1142 const SwNode* pEndNd = pLastBox->GetSttNd()->EndOfSectionNode();
1143 if( pLastBox->GetSttIdx()+SwNodeOffset(2) != pEndNd->GetIndex() )
1145 // Move TextNodes
1146 SwNodeRange aRg( *pLastBox->GetSttNd(), SwNodeOffset(+2), *pEndNd );
1147 pLastBox = pNewLine->GetTabBoxes()[0]; // reset
1148 SwNodeIndex aInsPos( *pLastBox->GetSttNd(), 1 );
1149 rDoc.GetNodes().MoveNodes(aRg, rDoc.GetNodes(), aInsPos.GetNode(), false);
1150 rDoc.GetNodes().Delete( aInsPos ); // delete the empty one
1155 // In Boxes with Lines, we can only have Size/Fillorder
1156 pFrameFormat = static_cast<SwTableBoxFormat*>(pNewBox->ClaimFrameFormat());
1157 pFrameFormat->ResetFormatAttr( RES_LR_SPACE, RES_FRMATR_END - 1 );
1158 pFrameFormat->ResetFormatAttr( RES_BOXATR_BEGIN, RES_BOXATR_END - 1 );
1161 pRowHeights.reset();
1163 GCLines();
1165 aFndBox.MakeFrames( *this );
1167 CHECKBOXWIDTH
1168 CHECKTABLELAYOUT
1169 return true;
1172 bool SwTable::SplitCol(SwDoc& rDoc, const SwSelBoxes& rBoxes, sal_uInt16 nCnt)
1174 OSL_ENSURE( !rBoxes.empty() && nCnt, "No valid values" );
1175 SwTableNode* pTableNd = const_cast<SwTableNode*>(rBoxes[0]->GetSttNd()->FindTableNode());
1176 if( !pTableNd )
1177 return false;
1179 // TL_CHART2: splitting/merging of a number of cells or rows will usually make
1180 // the table too complex to be handled with chart.
1181 // Thus we tell the charts to use their own data provider and forget about this table
1182 rDoc.getIDocumentChartDataProviderAccess().CreateChartInternalDataProviders( this );
1184 SetHTMLTableLayout(std::shared_ptr<SwHTMLTableLayout>()); // Delete HTML Layout
1185 SwSelBoxes aSelBoxes(rBoxes);
1186 ExpandSelection( aSelBoxes );
1188 // Find Lines for the Layout update
1189 FndBox_ aFndBox( nullptr, nullptr );
1190 aFndBox.SetTableLines( aSelBoxes, *this );
1191 aFndBox.DelFrames( *this );
1193 CpyTabFrames aFrameArr;
1194 std::vector<SwTableBoxFormat*> aLastBoxArr;
1195 for (size_t n = 0; n < aSelBoxes.size(); ++n)
1197 SwTableBox* pSelBox = aSelBoxes[n];
1198 OSL_ENSURE( pSelBox, "Box is not in the table" );
1200 // We don't want to split small table cells into very very small cells
1201 if( pSelBox->GetFrameFormat()->GetFrameSize().GetWidth()/( nCnt + 1 ) < 10 )
1202 continue;
1204 // Then split the nCnt Box up into nCnt Boxes
1205 SwTableLine* pInsLine = pSelBox->GetUpper();
1206 sal_uInt16 nBoxPos = pInsLine->GetBoxPos( pSelBox );
1208 // Find the Frame Format in the Frame Format Array
1209 SwTableBoxFormat* pLastBoxFormat;
1210 CpyTabFrame aFindFrame( static_cast<SwTableBoxFormat*>(pSelBox->GetFrameFormat()) );
1211 CpyTabFrames::const_iterator itFind = aFrameArr.lower_bound( aFindFrame );
1212 const size_t nFndPos = itFind - aFrameArr.begin();
1213 if( itFind == aFrameArr.end() || !(*itFind == aFindFrame) )
1215 // Change the FrameFormat
1216 aFindFrame.pNewFrameFormat = static_cast<SwTableBoxFormat*>(pSelBox->ClaimFrameFormat());
1217 SwTwips nBoxSz = aFindFrame.pNewFrameFormat->GetFrameSize().GetWidth();
1218 SwTwips nNewBoxSz = nBoxSz / ( nCnt + 1 );
1219 aFindFrame.pNewFrameFormat->SetFormatAttr( SwFormatFrameSize( SwFrameSize::Variable,
1220 nNewBoxSz, 0 ) );
1221 aFrameArr.insert( aFindFrame );
1223 pLastBoxFormat = aFindFrame.pNewFrameFormat;
1224 if( nBoxSz != ( nNewBoxSz * (nCnt + 1)))
1226 // We have a remainder, so we need to define an own Format
1227 // for the last Box.
1228 pLastBoxFormat = new SwTableBoxFormat( *aFindFrame.pNewFrameFormat );
1229 pLastBoxFormat->SetFormatAttr( SwFormatFrameSize( SwFrameSize::Variable,
1230 nBoxSz - ( nNewBoxSz * nCnt ), 0 ) );
1232 aLastBoxArr.insert( aLastBoxArr.begin() + nFndPos, pLastBoxFormat );
1234 else
1236 aFindFrame = aFrameArr[ nFndPos ];
1237 pSelBox->ChgFrameFormat( aFindFrame.pNewFrameFormat );
1238 pLastBoxFormat = aLastBoxArr[ nFndPos ];
1241 // Insert the Boxes at the Position
1242 for( sal_uInt16 i = 1; i < nCnt; ++i )
1243 ::InsTableBox( rDoc, pTableNd, pInsLine, aFindFrame.pNewFrameFormat,
1244 pSelBox, nBoxPos + i ); // insert after
1246 ::InsTableBox( rDoc, pTableNd, pInsLine, pLastBoxFormat,
1247 pSelBox, nBoxPos + nCnt ); // insert after
1249 // Special treatment for the Border:
1250 const SvxBoxItem& aSelBoxItem = aFindFrame.pNewFrameFormat->GetBox();
1251 if( aSelBoxItem.GetRight() )
1253 pInsLine->GetTabBoxes()[ nBoxPos + nCnt ]->ClaimFrameFormat();
1255 SvxBoxItem aTmp( aSelBoxItem );
1256 aTmp.SetLine( nullptr, SvxBoxItemLine::RIGHT );
1257 aFindFrame.pNewFrameFormat->SetFormatAttr( aTmp );
1259 // Remove the Format from the "cache"
1260 for( auto i = aFrameArr.size(); i; )
1262 const CpyTabFrame& rCTF = aFrameArr[ --i ];
1263 if( rCTF.pNewFrameFormat == aFindFrame.pNewFrameFormat ||
1264 rCTF.pFrameFormat == aFindFrame.pNewFrameFormat )
1266 aFrameArr.erase( aFrameArr.begin() + i );
1267 aLastBoxArr.erase( aLastBoxArr.begin() + i );
1273 // Update Layout
1274 aFndBox.MakeFrames( *this );
1276 CHECKBOXWIDTH
1277 CHECKTABLELAYOUT
1278 return true;
1282 * >> MERGE <<
1283 * Algorithm:
1284 * If we only have one Line in the FndBox_, take this Line and test
1285 * the Box count:
1286 * If we have more than one Box, we merge on Box level, meaning
1287 * the new Box will be as wide as the old ones.
1288 * All Lines that are above/under the Area, are inserted into
1289 * the Box as Line + Box.
1290 * All Lines that come before/after the Area, are inserted into
1291 * the Boxes Left/Right.
1293 * >> MERGE <<
1295 static void lcl_CpyLines( sal_uInt16 nStt, sal_uInt16 nEnd,
1296 SwTableLines& rLines,
1297 SwTableBox* pInsBox,
1298 sal_uInt16 nPos = USHRT_MAX )
1300 for( sal_uInt16 n = nStt; n < nEnd; ++n )
1301 rLines[n]->SetUpper( pInsBox );
1302 if( USHRT_MAX == nPos )
1303 nPos = pInsBox->GetTabLines().size();
1304 pInsBox->GetTabLines().insert( pInsBox->GetTabLines().begin() + nPos,
1305 rLines.begin() + nStt, rLines.begin() + nEnd );
1306 rLines.erase( rLines.begin() + nStt, rLines.begin() + nEnd );
1309 static void lcl_CpyBoxes( sal_uInt16 nStt, sal_uInt16 nEnd,
1310 SwTableBoxes& rBoxes,
1311 SwTableLine* pInsLine )
1313 for( sal_uInt16 n = nStt; n < nEnd; ++n )
1314 rBoxes[n]->SetUpper( pInsLine );
1315 sal_uInt16 nPos = pInsLine->GetTabBoxes().size();
1316 pInsLine->GetTabBoxes().insert( pInsLine->GetTabBoxes().begin() + nPos,
1317 rBoxes.begin() + nStt, rBoxes.begin() + nEnd );
1318 rBoxes.erase( rBoxes.begin() + nStt, rBoxes.begin() + nEnd );
1321 static void lcl_CalcWidth( SwTableBox* pBox )
1323 // Assertion: Every Line in the Box is as large
1324 SwFrameFormat* pFormat = pBox->ClaimFrameFormat();
1325 OSL_ENSURE( pBox->GetTabLines().size(), "Box does not have any Lines" );
1327 SwTableLine* pLine = pBox->GetTabLines()[0];
1328 OSL_ENSURE( pLine, "Box is not within a Line" );
1330 tools::Long nWidth = 0;
1331 for( auto pTabBox : pLine->GetTabBoxes() )
1332 nWidth += pTabBox->GetFrameFormat()->GetFrameSize().GetWidth();
1334 pFormat->SetFormatAttr( SwFormatFrameSize( SwFrameSize::Variable, nWidth, 0 ));
1336 // Boxes with Lines can only have Size/Fillorder
1337 pFormat->ResetFormatAttr( RES_LR_SPACE, RES_FRMATR_END - 1 );
1338 pFormat->ResetFormatAttr( RES_BOXATR_BEGIN, RES_BOXATR_END - 1 );
1341 namespace {
1343 struct InsULPara
1345 SwTableNode* pTableNd;
1346 SwTableLine* pInsLine;
1347 SwTableBox* pInsBox;
1348 bool bUL_LR : 1; // Upper-Lower(true) or Left-Right(false) ?
1349 bool bUL : 1; // Upper-Left(true) or Lower-Right(false) ?
1351 SwTableBox* pLeftBox;
1353 InsULPara( SwTableNode* pTNd,
1354 SwTableBox* pLeft,
1355 SwTableLine* pLine )
1356 : pTableNd( pTNd ), pInsLine( pLine ), pInsBox( nullptr ),
1357 pLeftBox( pLeft )
1358 { bUL_LR = true; bUL = true; }
1360 void SetLeft( SwTableBox* pBox )
1361 { bUL_LR = false; bUL = true; if( pBox ) pInsBox = pBox; }
1362 void SetRight( SwTableBox* pBox )
1363 { bUL_LR = false; bUL = false; if( pBox ) pInsBox = pBox; }
1364 void SetLower( SwTableLine* pLine )
1365 { bUL_LR = true; bUL = false; if( pLine ) pInsLine = pLine; }
1370 static void lcl_Merge_MoveLine(FndLine_ & rFndLine, InsULPara *const pULPara);
1372 static void lcl_Merge_MoveBox(FndBox_ & rFndBox, InsULPara *const pULPara)
1374 SwTableBoxes* pBoxes;
1376 sal_uInt16 nStt = 0, nEnd = rFndBox.GetLines().size();
1377 sal_uInt16 nInsPos = USHRT_MAX;
1378 if( !pULPara->bUL_LR ) // Left/Right
1380 sal_uInt16 nPos;
1381 SwTableBox* pFndTableBox = rFndBox.GetBox();
1382 pBoxes = &pFndTableBox->GetUpper()->GetTabBoxes();
1383 if( pULPara->bUL ) // Left ?
1385 // if there are Boxes before it, move them
1386 nPos = pFndTableBox->GetUpper()->GetBoxPos( pFndTableBox );
1387 if( 0 != nPos )
1388 lcl_CpyBoxes( 0, nPos, *pBoxes, pULPara->pInsLine );
1390 else // Right
1392 // if there are Boxes behind it, move them
1393 nPos = pFndTableBox->GetUpper()->GetBoxPos( pFndTableBox );
1394 if( nPos +1 < o3tl::narrowing<sal_uInt16>(pBoxes->size()) )
1396 nInsPos = pULPara->pInsLine->GetTabBoxes().size();
1397 lcl_CpyBoxes( nPos+1, pBoxes->size(),
1398 *pBoxes, pULPara->pInsLine );
1402 // Upper/Lower and still deeper?
1403 else if (!rFndBox.GetLines().empty())
1405 // Only search the Line from which we need to move
1406 nStt = pULPara->bUL ? 0 : rFndBox.GetLines().size()-1;
1407 nEnd = nStt+1;
1410 pBoxes = &pULPara->pInsLine->GetTabBoxes();
1412 // Is there still a level to step down to?
1413 if (rFndBox.GetBox()->GetTabLines().empty())
1414 return;
1416 SwTableBox* pBox = new SwTableBox(
1417 static_cast<SwTableBoxFormat*>(rFndBox.GetBox()->GetFrameFormat()),
1418 0, pULPara->pInsLine );
1419 InsULPara aPara( *pULPara );
1420 aPara.pInsBox = pBox;
1421 for (FndLines_t::iterator it = rFndBox.GetLines().begin() + nStt;
1422 it != rFndBox.GetLines().begin() + nEnd; ++it )
1424 lcl_Merge_MoveLine(**it, &aPara);
1426 if( !pBox->GetTabLines().empty() )
1428 if( USHRT_MAX == nInsPos )
1429 nInsPos = pBoxes->size();
1430 pBoxes->insert( pBoxes->begin() + nInsPos, pBox );
1431 lcl_CalcWidth( pBox ); // calculate the Box's width
1433 else
1434 delete pBox;
1437 static void lcl_Merge_MoveLine(FndLine_& rFndLine, InsULPara *const pULPara)
1439 SwTableLines* pLines;
1441 sal_uInt16 nStt = 0, nEnd = rFndLine.GetBoxes().size();
1442 sal_uInt16 nInsPos = USHRT_MAX;
1443 if( pULPara->bUL_LR ) // UpperLower ?
1445 sal_uInt16 nPos;
1446 SwTableLine* pFndLn = rFndLine.GetLine();
1447 pLines = pFndLn->GetUpper() ?
1448 &pFndLn->GetUpper()->GetTabLines() :
1449 &pULPara->pTableNd->GetTable().GetTabLines();
1451 SwTableBox* pLBx = rFndLine.GetBoxes().front()->GetBox();
1452 SwTableBox* pRBx = rFndLine.GetBoxes().back()->GetBox();
1453 sal_uInt16 nLeft = pFndLn->GetBoxPos( pLBx );
1454 sal_uInt16 nRight = pFndLn->GetBoxPos( pRBx );
1456 if( !nLeft || nRight == pFndLn->GetTabBoxes().size() )
1458 if( pULPara->bUL ) // Upper ?
1460 // If there are Lines before it, move them
1461 nPos = pLines->GetPos( pFndLn );
1462 if( 0 != nPos )
1463 lcl_CpyLines( 0, nPos, *pLines, pULPara->pInsBox );
1465 else
1466 // If there are Lines after it, move them
1467 if( (nPos = pLines->GetPos( pFndLn )) + 1 < o3tl::narrowing<sal_uInt16>(pLines->size()) )
1469 nInsPos = pULPara->pInsBox->GetTabLines().size();
1470 lcl_CpyLines( nPos+1, pLines->size(), *pLines,
1471 pULPara->pInsBox );
1474 else
1476 // There are still Boxes on the left side, so put the Left-
1477 // and Merge-Box into one Box and Line, insert before/after
1478 // a Line with a Box, into which the upper/lower Lines are
1479 // inserted
1480 SwTableLine* pInsLine = pULPara->pLeftBox->GetUpper();
1481 SwTableBox* pLMBox = new SwTableBox(
1482 static_cast<SwTableBoxFormat*>(pULPara->pLeftBox->GetFrameFormat()), 0, pInsLine );
1483 SwTableLine* pLMLn = new SwTableLine(
1484 static_cast<SwTableLineFormat*>(pInsLine->GetFrameFormat()), 2, pLMBox );
1485 pLMLn->ClaimFrameFormat()->ResetFormatAttr( RES_FRM_SIZE );
1487 pLMBox->GetTabLines().insert( pLMBox->GetTabLines().begin(), pLMLn );
1489 lcl_CpyBoxes( 0, 2, pInsLine->GetTabBoxes(), pLMLn );
1491 pInsLine->GetTabBoxes().insert( pInsLine->GetTabBoxes().begin(), pLMBox );
1493 if( pULPara->bUL ) // Upper ?
1495 // If there are Lines before it, move them
1496 nPos = pLines->GetPos( pFndLn );
1497 if( 0 != nPos )
1498 lcl_CpyLines( 0, nPos, *pLines, pLMBox, 0 );
1500 else
1501 // If there are Lines after it, move them
1502 if( (nPos = pLines->GetPos( pFndLn )) + 1 < o3tl::narrowing<sal_uInt16>(pLines->size()) )
1503 lcl_CpyLines( nPos+1, pLines->size(), *pLines,
1504 pLMBox );
1505 lcl_CalcWidth( pLMBox ); // calculate the Box's width
1508 // Left/Right
1509 else
1511 // Find only the Line from which we need to move
1512 nStt = pULPara->bUL ? 0 : rFndLine.GetBoxes().size()-1;
1513 nEnd = nStt+1;
1515 pLines = &pULPara->pInsBox->GetTabLines();
1517 SwTableLine* pNewLine = new SwTableLine(
1518 static_cast<SwTableLineFormat*>(rFndLine.GetLine()->GetFrameFormat()), 0, pULPara->pInsBox );
1519 InsULPara aPara( *pULPara ); // copying
1520 aPara.pInsLine = pNewLine;
1521 FndBoxes_t & rLineBoxes = rFndLine.GetBoxes();
1522 for (FndBoxes_t::iterator it = rLineBoxes.begin() + nStt;
1523 it != rLineBoxes.begin() + nEnd; ++it)
1525 lcl_Merge_MoveBox(**it, &aPara);
1528 if( !pNewLine->GetTabBoxes().empty() )
1530 if( USHRT_MAX == nInsPos )
1531 nInsPos = pLines->size();
1532 pLines->insert( pLines->begin() + nInsPos, pNewLine );
1534 else
1535 delete pNewLine;
1538 static void lcl_BoxSetHeadCondColl( const SwTableBox* pBox );
1540 bool SwTable::OldMerge( SwDoc* pDoc, const SwSelBoxes& rBoxes,
1541 SwTableBox* pMergeBox, SwUndoTableMerge* pUndo )
1543 OSL_ENSURE( !rBoxes.empty() && pMergeBox, "no valid values" );
1544 SwTableNode* pTableNd = const_cast<SwTableNode*>(rBoxes[0]->GetSttNd()->FindTableNode());
1545 if( !pTableNd )
1546 return false;
1548 // Find all Boxes/Lines
1549 FndBox_ aFndBox( nullptr, nullptr );
1551 FndPara aPara( rBoxes, &aFndBox );
1552 ForEach_FndLineCopyCol( GetTabLines(), &aPara );
1554 if( aFndBox.GetLines().empty() )
1555 return false;
1557 // TL_CHART2: splitting/merging of a number of cells or rows will usually make
1558 // the table too complex to be handled with chart.
1559 // Thus we tell the charts to use their own data provider and forget about this table
1560 pDoc->getIDocumentChartDataProviderAccess().CreateChartInternalDataProviders( this );
1562 SetHTMLTableLayout(std::shared_ptr<SwHTMLTableLayout>()); // Delete HTML Layout
1564 if( pUndo )
1565 pUndo->SetSelBoxes( rBoxes );
1567 // Find Lines for the Layout update
1568 aFndBox.SetTableLines( *this );
1569 aFndBox.DelFrames( *this );
1571 FndBox_* pFndBox = &aFndBox;
1572 while( 1 == pFndBox->GetLines().size() &&
1573 1 == pFndBox->GetLines().front()->GetBoxes().size() )
1575 pFndBox = pFndBox->GetLines().front()->GetBoxes().front().get();
1578 SwTableLine* pInsLine = new SwTableLine(
1579 static_cast<SwTableLineFormat*>(pFndBox->GetLines().front()->GetLine()->GetFrameFormat()), 0,
1580 !pFndBox->GetUpper() ? nullptr : pFndBox->GetBox() );
1581 pInsLine->ClaimFrameFormat()->ResetFormatAttr( RES_FRM_SIZE );
1583 // Add the new Line
1584 SwTableLines* pLines = pFndBox->GetUpper() ?
1585 &pFndBox->GetBox()->GetTabLines() : &GetTabLines();
1587 SwTableLine* pNewLine = pFndBox->GetLines().front()->GetLine();
1588 sal_uInt16 nInsPos = pLines->GetPos( pNewLine );
1589 pLines->insert( pLines->begin() + nInsPos, pInsLine );
1591 SwTableBox* pLeftBox = new SwTableBox( static_cast<SwTableBoxFormat*>(pMergeBox->GetFrameFormat()), 0, pInsLine );
1592 SwTableBox* pRightBox = new SwTableBox( static_cast<SwTableBoxFormat*>(pMergeBox->GetFrameFormat()), 0, pInsLine );
1593 pMergeBox->SetUpper( pInsLine );
1594 pInsLine->GetTabBoxes().insert( pInsLine->GetTabBoxes().begin(), pLeftBox );
1595 pLeftBox->ClaimFrameFormat();
1596 pInsLine->GetTabBoxes().insert( pInsLine->GetTabBoxes().begin() + 1, pMergeBox);
1597 pInsLine->GetTabBoxes().insert( pInsLine->GetTabBoxes().begin() + 2, pRightBox );
1598 pRightBox->ClaimFrameFormat();
1600 // This contains all Lines that are above the selected Area,
1601 // thus they form a Upper/Lower Line
1602 InsULPara aPara( pTableNd, pLeftBox, pInsLine );
1604 // Move the overlapping upper/lower Lines of the selected Area
1605 for (auto & it : pFndBox->GetLines().front()->GetBoxes())
1607 lcl_Merge_MoveBox(*it, &aPara);
1609 aPara.SetLower( pInsLine );
1610 const auto nEnd = pFndBox->GetLines().size()-1;
1611 for (auto & it : pFndBox->GetLines()[nEnd]->GetBoxes())
1613 lcl_Merge_MoveBox(*it, &aPara);
1616 // Move the Boxes extending into the selected Area from left/right
1617 aPara.SetLeft( pLeftBox );
1618 for (auto & rpFndLine : pFndBox->GetLines())
1620 lcl_Merge_MoveLine( *rpFndLine, &aPara );
1623 aPara.SetRight( pRightBox );
1624 for (auto & rpFndLine : pFndBox->GetLines())
1626 lcl_Merge_MoveLine( *rpFndLine, &aPara );
1629 if( pLeftBox->GetTabLines().empty() )
1630 DeleteBox_( *this, pLeftBox, nullptr, false, false );
1631 else
1633 lcl_CalcWidth( pLeftBox ); // calculate the Box's width
1634 if( pUndo && pLeftBox->GetSttNd() )
1635 pUndo->AddNewBox( pLeftBox->GetSttIdx() );
1637 if( pRightBox->GetTabLines().empty() )
1638 DeleteBox_( *this, pRightBox, nullptr, false, false );
1639 else
1641 lcl_CalcWidth( pRightBox ); // calculate the Box's width
1642 if( pUndo && pRightBox->GetSttNd() )
1643 pUndo->AddNewBox( pRightBox->GetSttIdx() );
1646 DeleteSel( pDoc, rBoxes, nullptr, nullptr, false, false );
1648 // Clean up this Line's structure once again, generally all of them
1649 GCLines();
1651 for( const auto& rpBox : GetTabLines()[0]->GetTabBoxes() )
1652 lcl_BoxSetHeadCondColl(rpBox);
1654 aFndBox.MakeFrames( *this );
1656 CHECKBOXWIDTH
1657 CHECKTABLELAYOUT
1659 return true;
1662 static void lcl_CheckRowSpan( SwTable &rTable )
1664 const tools::Long nLineCount = static_cast<tools::Long>(rTable.GetTabLines().size());
1665 tools::Long nMaxSpan = nLineCount;
1666 tools::Long nMinSpan = 1;
1667 while( nMaxSpan )
1669 SwTableLine* pLine = rTable.GetTabLines()[ nLineCount - nMaxSpan ];
1670 for( auto pBox : pLine->GetTabBoxes() )
1672 sal_Int32 nRowSpan = pBox->getRowSpan();
1673 if( nRowSpan > nMaxSpan )
1674 pBox->setRowSpan( nMaxSpan );
1675 else if( nRowSpan < nMinSpan )
1676 pBox->setRowSpan( nMinSpan > 0 ? nMaxSpan : nMinSpan );
1678 --nMaxSpan;
1679 nMinSpan = -nMaxSpan;
1683 static sal_uInt16 lcl_GetBoxOffset( const FndBox_& rBox )
1685 // Find the first Box
1686 const FndBox_* pFirstBox = &rBox;
1687 while (!pFirstBox->GetLines().empty())
1689 pFirstBox = pFirstBox->GetLines().front()->GetBoxes().front().get();
1692 sal_uInt16 nRet = 0;
1693 // Calculate the position relative to above via the Lines
1694 const SwTableBox* pBox = pFirstBox->GetBox();
1695 do {
1696 const SwTableBoxes& rBoxes = pBox->GetUpper()->GetTabBoxes();
1697 for( auto pCmp : rBoxes )
1699 if (pBox==pCmp)
1700 break;
1701 nRet = nRet + o3tl::narrowing<sal_uInt16>(pCmp->GetFrameFormat()->GetFrameSize().GetWidth());
1703 pBox = pBox->GetUpper()->GetUpper();
1704 } while( pBox );
1705 return nRet;
1708 static sal_uInt16 lcl_GetLineWidth( const FndLine_& rLine )
1710 sal_uInt16 nRet = 0;
1711 for( auto n = rLine.GetBoxes().size(); n; )
1713 nRet = nRet + o3tl::narrowing<sal_uInt16>(rLine.GetBoxes()[--n]->GetBox()
1714 ->GetFrameFormat()->GetFrameSize().GetWidth());
1716 return nRet;
1719 static void lcl_CalcNewWidths(const FndLines_t& rFndLines, CpyPara& rPara)
1721 rPara.pWidths.reset();
1722 const size_t nLineCount = rFndLines.size();
1723 if( nLineCount )
1725 rPara.pWidths = std::make_shared< std::vector< std::vector< sal_uLong > > >
1726 ( nLineCount );
1727 // First we collect information about the left/right borders of all
1728 // selected cells
1729 for( size_t nLine = 0; nLine < nLineCount; ++nLine )
1731 std::vector< sal_uLong > &rWidth = (*rPara.pWidths)[ nLine ];
1732 const FndLine_ *pFndLine = rFndLines[ nLine ].get();
1733 if( pFndLine && !pFndLine->GetBoxes().empty() )
1735 const SwTableLine *pLine = pFndLine->GetLine();
1736 if( pLine && !pLine->GetTabBoxes().empty() )
1738 size_t nBoxCount = pLine->GetTabBoxes().size();
1739 sal_uLong nPos = 0;
1740 // The first selected box...
1741 const SwTableBox *const pSel =
1742 pFndLine->GetBoxes().front()->GetBox();
1743 size_t nBox = 0;
1744 // Sum up the width of all boxes before the first selected box
1745 while( nBox < nBoxCount )
1747 SwTableBox* pBox = pLine->GetTabBoxes()[nBox++];
1748 if( pBox != pSel )
1749 nPos += pBox->GetFrameFormat()->GetFrameSize().GetWidth();
1750 else
1751 break;
1753 // nPos is now the left border of the first selected box
1754 if( rPara.nMinLeft > nPos )
1755 rPara.nMinLeft = nPos;
1756 nBoxCount = pFndLine->GetBoxes().size();
1757 rWidth = std::vector< sal_uLong >( nBoxCount+2 );
1758 rWidth[ 0 ] = nPos;
1759 // Add now the widths of all selected boxes and store
1760 // the positions in the vector
1761 for( nBox = 0; nBox < nBoxCount; )
1763 nPos += pFndLine->GetBoxes()[nBox]
1764 ->GetBox()->GetFrameFormat()->GetFrameSize().GetWidth();
1765 rWidth[ ++nBox ] = nPos;
1767 // nPos: The right border of the last selected box
1768 if( rPara.nMaxRight < nPos )
1769 rPara.nMaxRight = nPos;
1770 if( nPos <= rWidth[ 0 ] )
1771 rWidth.clear();
1776 // Second step: calculate the new widths for the copied cells
1777 sal_uLong nSelSize = rPara.nMaxRight - rPara.nMinLeft;
1778 if( !nSelSize )
1779 return;
1781 for( size_t nLine = 0; nLine < nLineCount; ++nLine )
1783 std::vector< sal_uLong > &rWidth = (*rPara.pWidths)[ nLine ];
1784 const size_t nCount = rWidth.size();
1785 if( nCount > 2 )
1787 rWidth[ nCount - 1 ] = rPara.nMaxRight;
1788 sal_uLong nLastPos = 0;
1789 for( size_t nBox = 0; nBox < nCount; ++nBox )
1791 sal_uInt64 nNextPos = rWidth[ nBox ];
1792 nNextPos -= rPara.nMinLeft;
1793 nNextPos *= rPara.nNewSize;
1794 nNextPos /= nSelSize;
1795 rWidth[ nBox ] = static_cast<sal_uLong>(nNextPos - nLastPos);
1796 nLastPos = static_cast<sal_uLong>(nNextPos);
1802 static void
1803 lcl_CopyLineToDoc(FndLine_ const& rpFndLn, CpyPara *const pCpyPara);
1805 static void lcl_CopyBoxToDoc(FndBox_ const& rFndBox, CpyPara *const pCpyPara)
1807 // Calculation of new size
1808 sal_uLong nRealSize;
1809 sal_uLong nDummy1 = 0;
1810 sal_uLong nDummy2 = 0;
1811 if( pCpyPara->pTableNd->GetTable().IsNewModel() )
1813 if( pCpyPara->nBoxIdx == 1 )
1814 nDummy1 = (*pCpyPara->pWidths)[pCpyPara->nLnIdx][0];
1815 nRealSize = (*pCpyPara->pWidths)[pCpyPara->nLnIdx][pCpyPara->nBoxIdx++];
1816 if( pCpyPara->nBoxIdx == (*pCpyPara->pWidths)[pCpyPara->nLnIdx].size()-1 )
1817 nDummy2 = (*pCpyPara->pWidths)[pCpyPara->nLnIdx][pCpyPara->nBoxIdx];
1819 else
1821 nRealSize = pCpyPara->nNewSize;
1822 nRealSize *= rFndBox.GetBox()->GetFrameFormat()->GetFrameSize().GetWidth();
1823 if (pCpyPara->nOldSize == 0)
1824 throw o3tl::divide_by_zero();
1825 nRealSize /= pCpyPara->nOldSize;
1828 sal_uLong nSize;
1829 bool bDummy = nDummy1 > 0;
1830 if( bDummy )
1831 nSize = nDummy1;
1832 else
1834 nSize = nRealSize;
1835 nRealSize = 0;
1839 // Find the Frame Format in the list of all Frame Formats
1840 CpyTabFrame aFindFrame(static_cast<SwTableBoxFormat*>(rFndBox.GetBox()->GetFrameFormat()));
1842 std::shared_ptr<SwFormatFrameSize> aFrameSz(std::make_shared<SwFormatFrameSize>());
1843 CpyTabFrames::const_iterator itFind = pCpyPara->rTabFrameArr.lower_bound( aFindFrame );
1844 const CpyTabFrames::size_type nFndPos = itFind - pCpyPara->rTabFrameArr.begin();
1846 // It *is* sometimes cool to have multiple tests/if's and assignments
1847 // in a single statement, and it is technically possible. But it is definitely
1848 // not simply readable - where from my POV reading code is done 1000 times
1849 // more often than writing it. Thus I dismantled the expression in smaller
1850 // chunks to keep it handy/understandable/changeable (hopefully without error)
1851 // The original for reference:
1852 // if( itFind == pCpyPara->rTabFrameArr.end() || !(*itFind == aFindFrame) ||
1853 // ( aFrameSz = ( aFindFrame = pCpyPara->rTabFrameArr[ nFndPos ]).pNewFrameFormat->
1854 // GetFrameSize()).GetWidth() != static_cast<SwTwips>(nSize) )
1856 bool DoCopyIt(itFind == pCpyPara->rTabFrameArr.end());
1858 if(!DoCopyIt)
1860 DoCopyIt = !(*itFind == aFindFrame);
1863 if(!DoCopyIt)
1865 aFindFrame = pCpyPara->rTabFrameArr[ nFndPos ];
1866 aFrameSz.reset(aFindFrame.pNewFrameFormat->GetFrameSize().Clone());
1867 DoCopyIt = aFrameSz->GetWidth() != static_cast<SwTwips>(nSize);
1870 if(DoCopyIt)
1872 // It doesn't exist yet, so copy it
1873 aFindFrame.pNewFrameFormat = pCpyPara->rDoc.MakeTableBoxFormat();
1874 aFindFrame.pNewFrameFormat->CopyAttrs( *rFndBox.GetBox()->GetFrameFormat() );
1875 if( !pCpyPara->bCpyContent )
1876 aFindFrame.pNewFrameFormat->ResetFormatAttr( RES_BOXATR_FORMULA, RES_BOXATR_VALUE );
1877 aFrameSz->SetWidth( nSize );
1878 aFindFrame.pNewFrameFormat->SetFormatAttr( *aFrameSz );
1879 pCpyPara->rTabFrameArr.insert( aFindFrame );
1882 SwTableBox* pBox;
1883 if (!rFndBox.GetLines().empty())
1885 pBox = new SwTableBox( aFindFrame.pNewFrameFormat,
1886 rFndBox.GetLines().size(), pCpyPara->pInsLine );
1887 pCpyPara->pInsLine->GetTabBoxes().insert( pCpyPara->pInsLine->GetTabBoxes().begin() + pCpyPara->nInsPos++, pBox );
1888 CpyPara aPara( *pCpyPara, pBox );
1889 aPara.nNewSize = nSize; // get the size
1890 for (auto const& rpFndLine : rFndBox.GetLines())
1892 lcl_CopyLineToDoc( *rpFndLine, &aPara );
1895 else
1897 // Create an empty Box
1898 pCpyPara->rDoc.GetNodes().InsBoxen( pCpyPara->pTableNd, pCpyPara->pInsLine,
1899 aFindFrame.pNewFrameFormat,
1900 pCpyPara->rDoc.GetDfltTextFormatColl(),
1901 nullptr, pCpyPara->nInsPos );
1902 pBox = pCpyPara->pInsLine->GetTabBoxes()[ pCpyPara->nInsPos ];
1903 if( bDummy )
1904 pBox->setDummyFlag( true );
1905 else if( pCpyPara->bCpyContent )
1907 // Copy the content into this empty Box
1908 pBox->setRowSpan(rFndBox.GetBox()->getRowSpan());
1910 // We can also copy formulas and values, if we copy the content
1912 SfxItemSetFixed<RES_BOXATR_FORMAT, RES_BOXATR_VALUE> aBoxAttrSet( pCpyPara->rDoc.GetAttrPool() );
1913 aBoxAttrSet.Put(rFndBox.GetBox()->GetFrameFormat()->GetAttrSet());
1914 if( aBoxAttrSet.Count() )
1916 const SwTableBoxNumFormat* pItem;
1917 SvNumberFormatter* pN = pCpyPara->rDoc.GetNumberFormatter( false );
1918 if( pN && pN->HasMergeFormatTable() && (pItem = aBoxAttrSet.
1919 GetItemIfSet( RES_BOXATR_FORMAT, false )) )
1921 sal_uLong nOldIdx = pItem->GetValue();
1922 sal_uLong nNewIdx = pN->GetMergeFormatIndex( nOldIdx );
1923 if( nNewIdx != nOldIdx )
1924 aBoxAttrSet.Put( SwTableBoxNumFormat( nNewIdx ));
1926 pBox->ClaimFrameFormat()->SetFormatAttr( aBoxAttrSet );
1929 SwDoc* pFromDoc = rFndBox.GetBox()->GetFrameFormat()->GetDoc();
1930 SwNodeRange aCpyRg( *rFndBox.GetBox()->GetSttNd(), SwNodeOffset(1),
1931 *rFndBox.GetBox()->GetSttNd()->EndOfSectionNode() );
1932 SwNodeIndex aInsIdx( *pBox->GetSttNd(), 1 );
1934 pFromDoc->GetDocumentContentOperationsManager().CopyWithFlyInFly(aCpyRg, aInsIdx.GetNode(), nullptr, false);
1935 // Delete the initial TextNode
1936 pCpyPara->rDoc.GetNodes().Delete( aInsIdx );
1938 ++pCpyPara->nInsPos;
1940 if( nRealSize )
1942 bDummy = false;
1943 nSize = nRealSize;
1944 nRealSize = 0;
1946 else
1948 bDummy = true;
1949 nSize = nDummy2;
1950 nDummy2 = 0;
1953 while( nSize );
1956 static void
1957 lcl_CopyLineToDoc(const FndLine_& rFndLine, CpyPara *const pCpyPara)
1959 // Find the Frame Format in the list of all Frame Formats
1960 CpyTabFrame aFindFrame( rFndLine.GetLine()->GetFrameFormat() );
1961 CpyTabFrames::const_iterator itFind = pCpyPara->rTabFrameArr.find( aFindFrame );
1962 if( itFind == pCpyPara->rTabFrameArr.end() )
1964 // It doesn't exist yet, so copy it
1965 aFindFrame.pNewFrameFormat = reinterpret_cast<SwTableBoxFormat*>(pCpyPara->rDoc.MakeTableLineFormat());
1966 aFindFrame.pNewFrameFormat->CopyAttrs( *rFndLine.GetLine()->GetFrameFormat() );
1967 pCpyPara->rTabFrameArr.insert( aFindFrame );
1969 else
1970 aFindFrame = *itFind;
1972 SwTableLine* pNewLine = new SwTableLine( reinterpret_cast<SwTableLineFormat*>(aFindFrame.pNewFrameFormat),
1973 rFndLine.GetBoxes().size(), pCpyPara->pInsBox );
1974 if( pCpyPara->pInsBox )
1976 SwTableLines& rLines = pCpyPara->pInsBox->GetTabLines();
1977 rLines.insert( rLines.begin() + pCpyPara->nInsPos++, pNewLine );
1979 else
1981 SwTableLines& rLines = pCpyPara->pTableNd->GetTable().GetTabLines();
1982 rLines.insert( rLines.begin() + pCpyPara->nInsPos++, pNewLine);
1985 CpyPara aPara( *pCpyPara, pNewLine );
1987 if( pCpyPara->pTableNd->GetTable().IsNewModel() )
1989 aPara.nOldSize = 0; // will not be used
1990 aPara.nBoxIdx = 1;
1992 else if( rFndLine.GetBoxes().size() ==
1993 rFndLine.GetLine()->GetTabBoxes().size() )
1995 // Get the Parent's size
1996 const SwFrameFormat* pFormat;
1998 if( rFndLine.GetLine()->GetUpper() )
1999 pFormat = rFndLine.GetLine()->GetUpper()->GetFrameFormat();
2000 else
2001 pFormat = pCpyPara->pTableNd->GetTable().GetFrameFormat();
2002 aPara.nOldSize = pFormat->GetFrameSize().GetWidth();
2004 else
2005 // Calculate it
2006 for (auto &rpBox : rFndLine.GetBoxes())
2008 aPara.nOldSize += rpBox->GetBox()->GetFrameFormat()->GetFrameSize().GetWidth();
2011 const FndBoxes_t& rBoxes = rFndLine.GetBoxes();
2012 for (auto const& it : rBoxes)
2014 lcl_CopyBoxToDoc(*it, &aPara);
2016 if( pCpyPara->pTableNd->GetTable().IsNewModel() )
2017 ++pCpyPara->nLnIdx;
2020 void SwTable::CopyHeadlineIntoTable( SwTableNode& rTableNd )
2022 // Find all Boxes/Lines
2023 SwSelBoxes aSelBoxes;
2024 SwTableBox* pBox = GetTabSortBoxes()[ 0 ];
2025 pBox = GetTableBox( pBox->GetSttNd()->StartOfSectionNode()->GetIndex() + 1 );
2026 SelLineFromBox( pBox, aSelBoxes );
2028 FndBox_ aFndBox( nullptr, nullptr );
2030 FndPara aPara( aSelBoxes, &aFndBox );
2031 ForEach_FndLineCopyCol( GetTabLines(), &aPara );
2033 if( aFndBox.GetLines().empty() )
2034 return;
2036 SwitchFormulasToRelativeRepresentation();
2038 CpyTabFrames aCpyFormat;
2039 CpyPara aPara( &rTableNd, 1, aCpyFormat );
2040 aPara.nNewSize = aPara.nOldSize = rTableNd.GetTable().GetFrameFormat()->GetFrameSize().GetWidth();
2041 // Copy
2042 if( IsNewModel() )
2043 lcl_CalcNewWidths( aFndBox.GetLines(), aPara );
2044 for (const auto & rpFndLine : aFndBox.GetLines())
2046 lcl_CopyLineToDoc( *rpFndLine, &aPara );
2048 if( rTableNd.GetTable().IsNewModel() )
2049 { // The copied line must not contain any row span attributes > 1
2050 SwTableLine* pLine = rTableNd.GetTable().GetTabLines()[0];
2051 OSL_ENSURE( !pLine->GetTabBoxes().empty(), "Empty Table Line" );
2052 for( auto pTableBox : pLine->GetTabBoxes() )
2054 OSL_ENSURE( pTableBox, "Missing Table Box" );
2055 pTableBox->setRowSpan( 1 );
2060 bool SwTable::MakeCopy( SwDoc& rInsDoc, const SwPosition& rPos,
2061 const SwSelBoxes& rSelBoxes,
2062 bool bCpyName, const OUString& rStyleName ) const
2064 // Find all Boxes/Lines
2065 FndBox_ aFndBox( nullptr, nullptr );
2067 FndPara aPara( rSelBoxes, &aFndBox );
2068 ForEach_FndLineCopyCol( const_cast<SwTableLines&>(GetTabLines()), &aPara );
2070 if( aFndBox.GetLines().empty() )
2071 return false;
2073 // First copy the PoolTemplates for the Table, so that the Tables are
2074 // actually copied and have valid values.
2075 SwDoc* pSrcDoc = GetFrameFormat()->GetDoc();
2076 if( pSrcDoc != &rInsDoc )
2078 rInsDoc.CopyTextColl( *pSrcDoc->getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_TABLE ) );
2079 rInsDoc.CopyTextColl( *pSrcDoc->getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_TABLE_HDLN ) );
2082 SwTable* pNewTable = const_cast<SwTable*>(rInsDoc.InsertTable(
2083 SwInsertTableOptions( SwInsertTableFlags::HeadlineNoBorder, 1 ),
2084 rPos, 1, 1, GetFrameFormat()->GetHoriOrient().GetHoriOrient(),
2085 nullptr, nullptr, false, IsNewModel() ));
2086 if( !pNewTable )
2087 return false;
2089 SwNodeIndex aIdx( rPos.GetNode(), -1 );
2090 SwTableNode* pTableNd = aIdx.GetNode().FindTableNode();
2091 ++aIdx;
2092 OSL_ENSURE( pTableNd, "Where is the TableNode now?" );
2094 pTableNd->GetTable().SetRowsToRepeat( GetRowsToRepeat() );
2096 pNewTable->SetTableStyleName(pTableNd->GetTable().GetTableStyleName());
2098 pTableNd->GetTable().SetTableStyleName(rStyleName);
2099 if( auto pSwDDETable = dynamic_cast<const SwDDETable*>(this) )
2101 // A DDE-Table is being copied
2102 // Does the new Document actually have it's FieldType?
2103 SwFieldType* pFieldType = rInsDoc.getIDocumentFieldsAccess().InsertFieldType(
2104 *pSwDDETable->GetDDEFieldType() );
2105 OSL_ENSURE( pFieldType, "unknown FieldType" );
2107 // Change the Table Pointer at the Node
2108 pNewTable = new SwDDETable( *pNewTable,
2109 static_cast<SwDDEFieldType*>(pFieldType) );
2110 pTableNd->SetNewTable( std::unique_ptr<SwTable>(pNewTable), false );
2113 pNewTable->GetFrameFormat()->CopyAttrs( *GetFrameFormat() );
2114 pNewTable->SetTableChgMode( GetTableChgMode() );
2116 // Destroy the already created Frames
2117 pTableNd->DelFrames();
2119 const_cast<SwTable*>(this)->SwitchFormulasToRelativeRepresentation();
2121 SwTableNumFormatMerge aTNFM(*pSrcDoc, rInsDoc);
2123 // Also copy Names or enforce a new unique one
2124 if( bCpyName )
2125 pNewTable->GetFrameFormat()->SetFormatName( GetFrameFormat()->GetName() );
2127 CpyTabFrames aCpyFormat;
2128 CpyPara aPara( pTableNd, 1, aCpyFormat );
2129 aPara.nNewSize = aPara.nOldSize = GetFrameFormat()->GetFrameSize().GetWidth();
2131 if( IsNewModel() )
2132 lcl_CalcNewWidths( aFndBox.GetLines(), aPara );
2133 // Copy
2134 for (const auto & rpFndLine : aFndBox.GetLines())
2136 lcl_CopyLineToDoc( *rpFndLine, &aPara );
2139 // Set the "right" margin above/below
2141 FndLine_* pFndLn = aFndBox.GetLines().front().get();
2142 SwTableLine* pLn = pFndLn->GetLine();
2143 const SwTableLine* pTmp = pLn;
2144 sal_uInt16 nLnPos = GetTabLines().GetPos( pTmp );
2145 if( USHRT_MAX != nLnPos && nLnPos )
2147 // There is a Line before it
2148 SwCollectTableLineBoxes aLnPara( false, SplitTable_HeadlineOption::BorderCopy );
2150 pLn = GetTabLines()[ nLnPos - 1 ];
2151 for( const auto& rpBox : pLn->GetTabBoxes() )
2152 sw_Box_CollectBox( rpBox, &aLnPara );
2154 if( aLnPara.Resize( lcl_GetBoxOffset( aFndBox ),
2155 lcl_GetLineWidth( *pFndLn )) )
2157 aLnPara.SetValues( true );
2158 pLn = pNewTable->GetTabLines()[ 0 ];
2159 for( const auto& rpBox : pLn->GetTabBoxes() )
2160 sw_BoxSetSplitBoxFormats(rpBox, &aLnPara );
2164 pFndLn = aFndBox.GetLines().back().get();
2165 pLn = pFndLn->GetLine();
2166 pTmp = pLn;
2167 nLnPos = GetTabLines().GetPos( pTmp );
2168 if( nLnPos < GetTabLines().size() - 1 )
2170 // There is a Line following it
2171 SwCollectTableLineBoxes aLnPara( true, SplitTable_HeadlineOption::BorderCopy );
2173 pLn = GetTabLines()[ nLnPos + 1 ];
2174 for( const auto& rpBox : pLn->GetTabBoxes() )
2175 sw_Box_CollectBox( rpBox, &aLnPara );
2177 if( aLnPara.Resize( lcl_GetBoxOffset( aFndBox ),
2178 lcl_GetLineWidth( *pFndLn )) )
2180 aLnPara.SetValues( false );
2181 pLn = pNewTable->GetTabLines().back();
2182 for( const auto& rpBox : pLn->GetTabBoxes() )
2183 sw_BoxSetSplitBoxFormats(rpBox, &aLnPara );
2188 // We need to delete the initial Box
2189 DeleteBox_( *pNewTable, pNewTable->GetTabLines().back()->GetTabBoxes()[0],
2190 nullptr, false, false );
2192 if( pNewTable->IsNewModel() )
2193 lcl_CheckRowSpan( *pNewTable );
2194 // Clean up
2195 pNewTable->GCLines();
2197 pTableNd->MakeOwnFrames(); // re-generate the Frames
2199 CHECKTABLELAYOUT
2201 return true;
2204 // Find the next Box with content from this Line
2205 SwTableBox* SwTableLine::FindNextBox( const SwTable& rTable,
2206 const SwTableBox* pSrchBox, bool bOvrTableLns ) const
2208 const SwTableLine* pLine = this; // for M800
2209 SwTableBox* pBox;
2210 sal_uInt16 nFndPos;
2211 if( !GetTabBoxes().empty() && pSrchBox )
2213 nFndPos = GetBoxPos( pSrchBox );
2214 if( USHRT_MAX != nFndPos &&
2215 nFndPos + 1 != o3tl::narrowing<sal_uInt16>(GetTabBoxes().size()) )
2217 pBox = GetTabBoxes()[ nFndPos + 1 ];
2218 while( !pBox->GetTabLines().empty() )
2219 pBox = pBox->GetTabLines().front()->GetTabBoxes()[0];
2220 return pBox;
2224 if( GetUpper() )
2226 nFndPos = GetUpper()->GetTabLines().GetPos( pLine );
2227 OSL_ENSURE( USHRT_MAX != nFndPos, "Line is not in the Table" );
2228 // Is there another Line?
2229 if( nFndPos+1 >= o3tl::narrowing<sal_uInt16>(GetUpper()->GetTabLines().size()) )
2230 return GetUpper()->GetUpper()->FindNextBox( rTable, GetUpper(), bOvrTableLns );
2231 pLine = GetUpper()->GetTabLines()[nFndPos+1];
2233 else if( bOvrTableLns ) // Over a Table's the "BaseLines"??
2235 // Search for the next Line in the Table
2236 nFndPos = rTable.GetTabLines().GetPos( pLine );
2237 if( nFndPos + 1 >= o3tl::narrowing<sal_uInt16>(rTable.GetTabLines().size()) )
2238 return nullptr; // there are no more Boxes
2240 pLine = rTable.GetTabLines()[ nFndPos+1 ];
2242 else
2243 return nullptr;
2245 if( !pLine->GetTabBoxes().empty() )
2247 pBox = pLine->GetTabBoxes().front();
2248 while( !pBox->GetTabLines().empty() )
2249 pBox = pBox->GetTabLines().front()->GetTabBoxes().front();
2250 return pBox;
2252 return pLine->FindNextBox( rTable, nullptr, bOvrTableLns );
2255 // Find the previous Box from this Line
2256 SwTableBox* SwTableLine::FindPreviousBox( const SwTable& rTable,
2257 const SwTableBox* pSrchBox, bool bOvrTableLns ) const
2259 const SwTableLine* pLine = this; // for M800
2260 SwTableBox* pBox;
2261 sal_uInt16 nFndPos;
2262 if( !GetTabBoxes().empty() && pSrchBox )
2264 nFndPos = GetBoxPos( pSrchBox );
2265 if( USHRT_MAX != nFndPos && nFndPos )
2267 pBox = GetTabBoxes()[ nFndPos - 1 ];
2268 while( !pBox->GetTabLines().empty() )
2270 pLine = pBox->GetTabLines().back();
2271 pBox = pLine->GetTabBoxes().back();
2273 return pBox;
2277 if( GetUpper() )
2279 nFndPos = GetUpper()->GetTabLines().GetPos( pLine );
2280 OSL_ENSURE( USHRT_MAX != nFndPos, "Line is not in the Table" );
2281 // Is there another Line?
2282 if( !nFndPos )
2283 return GetUpper()->GetUpper()->FindPreviousBox( rTable, GetUpper(), bOvrTableLns );
2284 pLine = GetUpper()->GetTabLines()[nFndPos-1];
2286 else if( bOvrTableLns ) // Over a Table's the "BaseLines"??
2288 // Search for the next Line in the Table
2289 nFndPos = rTable.GetTabLines().GetPos( pLine );
2290 if( !nFndPos )
2291 return nullptr; // there are no more Boxes
2293 pLine = rTable.GetTabLines()[ nFndPos-1 ];
2295 else
2296 return nullptr;
2298 if( !pLine->GetTabBoxes().empty() )
2300 pBox = pLine->GetTabBoxes().back();
2301 while( !pBox->GetTabLines().empty() )
2303 pLine = pBox->GetTabLines().back();
2304 pBox = pLine->GetTabBoxes().back();
2306 return pBox;
2308 return pLine->FindPreviousBox( rTable, nullptr, bOvrTableLns );
2311 // Find the next Box with content from this Line
2312 SwTableBox* SwTableBox::FindNextBox( const SwTable& rTable,
2313 const SwTableBox* pSrchBox, bool bOvrTableLns ) const
2315 if( !pSrchBox && GetTabLines().empty() )
2316 return const_cast<SwTableBox*>(this);
2317 return GetUpper()->FindNextBox( rTable, pSrchBox ? pSrchBox : this,
2318 bOvrTableLns );
2322 // Find the next Box with content from this Line
2323 SwTableBox* SwTableBox::FindPreviousBox( const SwTable& rTable,
2324 const SwTableBox* pSrchBox ) const
2326 if( !pSrchBox && GetTabLines().empty() )
2327 return const_cast<SwTableBox*>(this);
2328 return GetUpper()->FindPreviousBox( rTable, pSrchBox ? pSrchBox : this );
2331 static void lcl_BoxSetHeadCondColl( const SwTableBox* pBox )
2333 // We need to adapt the paragraphs with conditional templates in the HeadLine
2334 const SwStartNode* pSttNd = pBox->GetSttNd();
2335 if( pSttNd )
2336 pSttNd->CheckSectionCondColl();
2337 else
2338 for( const SwTableLine* pLine : pBox->GetTabLines() )
2339 sw_LineSetHeadCondColl( pLine );
2342 void sw_LineSetHeadCondColl( const SwTableLine* pLine )
2344 for( const SwTableBox* pBox : pLine->GetTabBoxes() )
2345 lcl_BoxSetHeadCondColl(pBox);
2348 static SwTwips lcl_GetDistance( SwTableBox* pBox, bool bLeft )
2350 bool bFirst = true;
2351 SwTwips nRet = 0;
2352 SwTableLine* pLine;
2353 while( pBox )
2355 pLine = pBox->GetUpper();
2356 if( !pLine )
2357 break;
2358 sal_uInt16 nStt = 0, nPos = pLine->GetBoxPos( pBox );
2360 if( bFirst && !bLeft )
2361 ++nPos;
2362 bFirst = false;
2364 while( nStt < nPos )
2365 nRet += pLine->GetTabBoxes()[ nStt++ ]->GetFrameFormat()
2366 ->GetFrameSize().GetWidth();
2367 pBox = pLine->GetUpper();
2369 return nRet;
2372 static bool lcl_SetSelBoxWidth( SwTableLine* pLine, CR_SetBoxWidth& rParam,
2373 SwTwips nDist, bool bCheck )
2375 SwTableBoxes& rBoxes = pLine->GetTabBoxes();
2376 for( auto pBox : rBoxes )
2378 SwFrameFormat* pFormat = pBox->GetFrameFormat();
2379 const SwFormatFrameSize& rSz = pFormat->GetFrameSize();
2380 SwTwips nWidth = rSz.GetWidth();
2381 bool bGreaterBox = false;
2383 if( bCheck )
2385 for( auto pLn : pBox->GetTabLines() )
2386 if( !::lcl_SetSelBoxWidth( pLn, rParam, nDist, true ))
2387 return false;
2389 // Collect all "ContentBoxes"
2390 bGreaterBox = (TableChgMode::FixedWidthChangeAbs != rParam.nMode)
2391 && ((nDist + (rParam.bLeft ? 0 : nWidth)) >= rParam.nSide);
2392 if (bGreaterBox
2393 || (!rParam.bBigger
2394 && (std::abs(nDist + ((rParam.nMode != TableChgMode::FixedWidthChangeAbs && rParam.bLeft) ? 0 : nWidth) - rParam.nSide) < COLFUZZY)))
2396 SwTwips nLowerDiff;
2397 if( bGreaterBox && TableChgMode::FixedWidthChangeProp == rParam.nMode )
2399 // The "other Boxes" have been adapted, so change by this value
2400 nLowerDiff = (nDist + ( rParam.bLeft ? 0 : nWidth ) ) - rParam.nSide;
2401 nLowerDiff *= rParam.nDiff;
2402 nLowerDiff /= rParam.nMaxSize;
2403 nLowerDiff = rParam.nDiff - nLowerDiff;
2405 else
2406 nLowerDiff = rParam.nDiff;
2408 if( nWidth < nLowerDiff || nWidth - nLowerDiff < MINLAY )
2409 return false;
2412 else
2414 SwTwips nLowerDiff = 0, nOldLower = rParam.nLowerDiff;
2415 for( auto pLn : pBox->GetTabLines() )
2417 rParam.nLowerDiff = 0;
2418 lcl_SetSelBoxWidth( pLn, rParam, nDist, false );
2420 if( nLowerDiff < rParam.nLowerDiff )
2421 nLowerDiff = rParam.nLowerDiff;
2423 rParam.nLowerDiff = nOldLower;
2425 if( nLowerDiff ||
2426 (bGreaterBox = !nOldLower && TableChgMode::FixedWidthChangeAbs != rParam.nMode &&
2427 ( nDist + ( rParam.bLeft ? 0 : nWidth ) ) >= rParam.nSide) ||
2428 ( std::abs( nDist + ( (rParam.nMode != TableChgMode::FixedWidthChangeAbs && rParam.bLeft) ? 0 : nWidth )
2429 - rParam.nSide ) < COLFUZZY ))
2431 // This column contains the Cursor - so decrease/increase
2432 SwFormatFrameSize aNew( rSz );
2434 if( !nLowerDiff )
2436 if( bGreaterBox && TableChgMode::FixedWidthChangeProp == rParam.nMode )
2438 // The "other Boxes" have been adapted, so change by this value
2439 nLowerDiff = (nDist + ( rParam.bLeft ? 0 : nWidth ) ) - rParam.nSide;
2440 nLowerDiff *= rParam.nDiff;
2441 nLowerDiff /= rParam.nMaxSize;
2442 nLowerDiff = rParam.nDiff - nLowerDiff;
2444 else
2445 nLowerDiff = rParam.nDiff;
2448 rParam.nLowerDiff += nLowerDiff;
2450 if( rParam.bBigger )
2451 aNew.SetWidth( nWidth + nLowerDiff );
2452 else
2453 aNew.SetWidth( nWidth - nLowerDiff );
2454 rParam.aShareFormats.SetSize( *pBox, aNew );
2455 break;
2459 if( rParam.bLeft && rParam.nMode != TableChgMode::FixedWidthChangeAbs && nDist >= rParam.nSide )
2460 break;
2462 nDist += nWidth;
2464 // If it gets bigger, then that's it
2465 if( ( TableChgMode::FixedWidthChangeAbs == rParam.nMode || !rParam.bLeft ) &&
2466 nDist >= rParam.nSide )
2467 break;
2469 return true;
2472 static bool lcl_SetOtherBoxWidth( SwTableLine* pLine, CR_SetBoxWidth& rParam,
2473 SwTwips nDist, bool bCheck )
2475 SwTableBoxes& rBoxes = pLine->GetTabBoxes();
2476 for( auto pBox : rBoxes )
2478 SwFrameFormat* pFormat = pBox->GetFrameFormat();
2479 const SwFormatFrameSize& rSz = pFormat->GetFrameSize();
2480 SwTwips nWidth = rSz.GetWidth();
2482 if( bCheck )
2484 for( auto pLn : pBox->GetTabLines() )
2485 if( !::lcl_SetOtherBoxWidth( pLn, rParam, nDist, true ))
2486 return false;
2488 if( rParam.bBigger && ( TableChgMode::FixedWidthChangeAbs == rParam.nMode
2489 ? std::abs( nDist - rParam.nSide ) < COLFUZZY
2490 : ( rParam.bLeft ? nDist < rParam.nSide - COLFUZZY
2491 : nDist >= rParam.nSide - COLFUZZY )) )
2493 SwTwips nDiff;
2494 if( TableChgMode::FixedWidthChangeProp == rParam.nMode ) // Table fixed, proportional
2496 // calculate relative
2497 nDiff = nWidth;
2498 nDiff *= rParam.nDiff;
2499 nDiff /= rParam.nMaxSize;
2501 else
2502 nDiff = rParam.nDiff;
2504 if( nWidth < nDiff || nWidth - nDiff < MINLAY )
2505 return false;
2508 else
2510 SwTwips nLowerDiff = 0, nOldLower = rParam.nLowerDiff;
2511 for( auto pLn : pBox->GetTabLines() )
2513 rParam.nLowerDiff = 0;
2514 lcl_SetOtherBoxWidth( pLn, rParam, nDist, false );
2516 if( nLowerDiff < rParam.nLowerDiff )
2517 nLowerDiff = rParam.nLowerDiff;
2519 rParam.nLowerDiff = nOldLower;
2521 if( nLowerDiff ||
2522 ( TableChgMode::FixedWidthChangeAbs == rParam.nMode
2523 ? std::abs( nDist - rParam.nSide ) < COLFUZZY
2524 : ( rParam.bLeft ? nDist < rParam.nSide - COLFUZZY
2525 : nDist >= rParam.nSide - COLFUZZY)
2528 SwFormatFrameSize aNew( rSz );
2530 if( !nLowerDiff )
2532 if( TableChgMode::FixedWidthChangeProp == rParam.nMode ) // Table fixed, proportional
2534 // calculate relative
2535 nLowerDiff = nWidth;
2536 nLowerDiff *= rParam.nDiff;
2537 nLowerDiff /= rParam.nMaxSize;
2539 else
2540 nLowerDiff = rParam.nDiff;
2543 rParam.nLowerDiff += nLowerDiff;
2545 if( rParam.bBigger )
2546 aNew.SetWidth( nWidth - nLowerDiff );
2547 else
2548 aNew.SetWidth( nWidth + nLowerDiff );
2550 rParam.aShareFormats.SetSize( *pBox, aNew );
2554 nDist += nWidth;
2555 if( ( TableChgMode::FixedWidthChangeAbs == rParam.nMode || rParam.bLeft ) &&
2556 nDist > rParam.nSide )
2557 break;
2559 return true;
2562 static void lcl_AjustLines( SwTableLine* pLine, CR_SetBoxWidth& rParam )
2564 SwTableBoxes& rBoxes = pLine->GetTabBoxes();
2565 for( auto pBox : rBoxes )
2567 SwFormatFrameSize aSz( pBox->GetFrameFormat()->GetFrameSize() );
2568 SwTwips nWidth = aSz.GetWidth();
2569 nWidth *= rParam.nDiff;
2570 nWidth /= rParam.nMaxSize;
2571 aSz.SetWidth( nWidth );
2572 rParam.aShareFormats.SetSize( *pBox, aSz );
2574 for( auto pLn : pBox->GetTabLines() )
2575 ::lcl_AjustLines( pLn, rParam );
2579 #ifdef DBG_UTIL
2580 void CheckBoxWidth( const SwTableLine& rLine, SwTwips nSize )
2582 const SwTableBoxes& rBoxes = rLine.GetTabBoxes();
2584 SwTwips nCurrentSize = 0;
2585 // See if the tables have a correct width
2586 for (const SwTableBox* pBox : rBoxes)
2588 const SwTwips nBoxW = pBox->GetFrameFormat()->GetFrameSize().GetWidth();
2589 nCurrentSize += nBoxW;
2591 for( auto pLn : pBox->GetTabLines() )
2592 CheckBoxWidth( *pLn, nBoxW );
2595 if (sal::static_int_cast< tools::ULong >(std::abs(nCurrentSize - nSize)) >
2596 (COLFUZZY * rBoxes.size()))
2598 OSL_FAIL( "Line's Boxes are too small or too large" );
2601 #endif
2603 bool SwTable::SetColWidth( SwTableBox& rCurrentBox, TableChgWidthHeightType eType,
2604 SwTwips nAbsDiff, SwTwips nRelDiff, std::unique_ptr<SwUndo>* ppUndo )
2606 SetHTMLTableLayout(std::shared_ptr<SwHTMLTableLayout>()); // Delete HTML Layout
2608 const SwFormatFrameSize& rSz = GetFrameFormat()->GetFrameSize();
2609 const SvxLRSpaceItem& rLR = GetFrameFormat()->GetLRSpace();
2611 bool bBigger,
2612 bRet = false,
2613 bLeft = TableChgWidthHeightType::ColLeft == extractPosition( eType ) ||
2614 TableChgWidthHeightType::CellLeft == extractPosition( eType );
2616 // Get the current Box's edge
2617 // Only needed for manipulating the width
2618 const SwTwips nDist = ::lcl_GetDistance( &rCurrentBox, bLeft );
2619 SwTwips nDistStt = 0;
2620 CR_SetBoxWidth aParam( eType, nRelDiff, nDist,
2621 bLeft ? nDist : rSz.GetWidth() - nDist,
2622 const_cast<SwTableNode*>(rCurrentBox.GetSttNd()->FindTableNode()) );
2623 bBigger = aParam.bBigger;
2625 FN_lcl_SetBoxWidth fnSelBox, fnOtherBox;
2626 fnSelBox = lcl_SetSelBoxWidth;
2627 fnOtherBox = lcl_SetOtherBoxWidth;
2629 switch( extractPosition(eType) )
2631 case TableChgWidthHeightType::ColRight:
2632 case TableChgWidthHeightType::ColLeft:
2633 if( TableChgMode::VarWidthChangeAbs == m_eTableChgMode )
2635 // First test if we have room at all
2636 bool bChgLRSpace = true;
2637 if( bBigger )
2639 if( GetFrameFormat()->getIDocumentSettingAccess().get(DocumentSettingId::BROWSE_MODE) &&
2640 !rSz.GetWidthPercent() )
2642 // silence -Wsign-compare on Android with the static cast
2643 bRet = rSz.GetWidth() < static_cast<unsigned short>(USHRT_MAX) - nRelDiff;
2644 bChgLRSpace = bLeft ? rLR.GetLeft() >= nAbsDiff
2645 : rLR.GetRight() >= nAbsDiff;
2647 else
2648 bRet = bLeft ? rLR.GetLeft() >= nAbsDiff
2649 : rLR.GetRight() >= nAbsDiff;
2651 if( !bRet )
2653 // Then call itself recursively; only with another mode (proportional)
2654 TableChgMode eOld = m_eTableChgMode;
2655 m_eTableChgMode = TableChgMode::FixedWidthChangeProp;
2657 bRet = SetColWidth( rCurrentBox, eType, nAbsDiff, nRelDiff,
2658 ppUndo );
2659 m_eTableChgMode = eOld;
2660 return bRet;
2663 else
2665 bRet = true;
2666 for( auto const & n: m_aLines )
2668 aParam.LoopClear();
2669 if( !(*fnSelBox)( n, aParam, nDistStt, true ))
2671 bRet = false;
2672 break;
2677 if( bRet )
2679 if( ppUndo )
2680 ppUndo->reset(new SwUndoAttrTable( *aParam.pTableNd, true ));
2682 tools::Long nFrameWidth = LONG_MAX;
2683 LockModify();
2684 SwFormatFrameSize aSz( rSz );
2685 SvxLRSpaceItem aLR( rLR );
2686 if( bBigger )
2688 // If the Table does not have any room to grow, we need to create some!
2689 // silence -Wsign-compare on Android with the static cast
2690 if( aSz.GetWidth() + nRelDiff > static_cast<unsigned short>(USHRT_MAX) )
2692 // Break down to USHRT_MAX / 2
2693 CR_SetBoxWidth aTmpPara( TableChgWidthHeightType::ColLeft, aSz.GetWidth() / 2,
2694 0, aSz.GetWidth(), aParam.pTableNd );
2695 for( size_t nLn = 0; nLn < m_aLines.size(); ++nLn )
2696 ::lcl_AjustLines( m_aLines[ nLn ], aTmpPara );
2697 aSz.SetWidth( aSz.GetWidth() / 2 );
2698 aParam.nDiff = nRelDiff /= 2;
2699 aParam.nSide /= 2;
2700 aParam.nMaxSize /= 2;
2703 if( bLeft )
2704 aLR.SetLeft( sal_uInt16( aLR.GetLeft() - nAbsDiff ) );
2705 else
2706 aLR.SetRight( sal_uInt16( aLR.GetRight() - nAbsDiff ) );
2708 else if( bLeft )
2709 aLR.SetLeft( sal_uInt16( aLR.GetLeft() + nAbsDiff ) );
2710 else
2711 aLR.SetRight( sal_uInt16( aLR.GetRight() + nAbsDiff ) );
2713 if( bChgLRSpace )
2714 GetFrameFormat()->SetFormatAttr( aLR );
2715 const SwFormatHoriOrient& rHOri = GetFrameFormat()->GetHoriOrient();
2716 if( text::HoriOrientation::FULL == rHOri.GetHoriOrient() ||
2717 (text::HoriOrientation::LEFT == rHOri.GetHoriOrient() && aLR.GetLeft()) ||
2718 (text::HoriOrientation::RIGHT == rHOri.GetHoriOrient() && aLR.GetRight()))
2720 SwFormatHoriOrient aHOri( rHOri );
2721 aHOri.SetHoriOrient( text::HoriOrientation::NONE );
2722 GetFrameFormat()->SetFormatAttr( aHOri );
2724 // If the Table happens to contain relative values (USHORT_MAX),
2725 // we need to convert them to absolute ones now.
2726 // Bug 61494
2727 if( GetFrameFormat()->getIDocumentSettingAccess().get(DocumentSettingId::BROWSE_MODE) &&
2728 !rSz.GetWidthPercent() )
2730 SwTabFrame* pTabFrame = SwIterator<SwTabFrame,SwFormat>( *GetFrameFormat() ).First();
2731 if( pTabFrame &&
2732 pTabFrame->getFramePrintArea().Width() != rSz.GetWidth() )
2734 nFrameWidth = pTabFrame->getFramePrintArea().Width();
2735 if( bBigger )
2736 nFrameWidth += nAbsDiff;
2737 else
2738 nFrameWidth -= nAbsDiff;
2743 if( bBigger )
2744 aSz.SetWidth( aSz.GetWidth() + nRelDiff );
2745 else
2746 aSz.SetWidth( aSz.GetWidth() - nRelDiff );
2748 if( rSz.GetWidthPercent() )
2749 aSz.SetWidthPercent( static_cast<sal_uInt8>(( aSz.GetWidth() * 100 ) /
2750 ( aSz.GetWidth() + aLR.GetRight() + aLR.GetLeft())));
2752 GetFrameFormat()->SetFormatAttr( aSz );
2754 UnlockModify();
2756 for( sal_uInt16 n = m_aLines.size(); n; )
2758 --n;
2759 aParam.LoopClear();
2760 (*fnSelBox)( m_aLines[ n ], aParam, nDistStt, false );
2763 // If the Table happens to contain relative values (USHORT_MAX),
2764 // we need to convert them to absolute ones now.
2765 // Bug 61494
2766 if( LONG_MAX != nFrameWidth )
2768 SwFormatFrameSize aAbsSz( aSz );
2769 aAbsSz.SetWidth( nFrameWidth );
2770 GetFrameFormat()->SetFormatAttr( aAbsSz );
2774 else if( bLeft ? nDist != 0 : std::abs( rSz.GetWidth() - nDist ) > COLFUZZY )
2776 bRet = true;
2777 if( bLeft && TableChgMode::FixedWidthChangeAbs == m_eTableChgMode )
2778 aParam.bBigger = !bBigger;
2780 // First test if we have room at all
2781 if( aParam.bBigger )
2783 for( auto const & n: m_aLines )
2785 aParam.LoopClear();
2786 if( !(*fnOtherBox)( n, aParam, 0, true ))
2788 bRet = false;
2789 break;
2793 else
2795 for( auto const & n: m_aLines )
2797 aParam.LoopClear();
2798 if( !(*fnSelBox)( n, aParam, nDistStt, true ))
2800 bRet = false;
2801 break;
2806 // If true, set it
2807 if( bRet )
2809 CR_SetBoxWidth aParam1( aParam );
2810 if( ppUndo )
2811 ppUndo->reset(new SwUndoAttrTable( *aParam.pTableNd, true ));
2813 if( TableChgMode::FixedWidthChangeAbs != m_eTableChgMode && bLeft )
2815 for( sal_uInt16 n = m_aLines.size(); n; )
2817 --n;
2818 aParam.LoopClear();
2819 aParam1.LoopClear();
2820 (*fnSelBox)( m_aLines[ n ], aParam, nDistStt, false );
2821 (*fnOtherBox)( m_aLines[ n ], aParam1, nDistStt, false );
2824 else
2826 for( sal_uInt16 n = m_aLines.size(); n; )
2828 --n;
2829 aParam.LoopClear();
2830 aParam1.LoopClear();
2831 (*fnOtherBox)( m_aLines[ n ], aParam1, nDistStt, false );
2832 (*fnSelBox)( m_aLines[ n ], aParam, nDistStt, false );
2837 break;
2839 case TableChgWidthHeightType::CellRight:
2840 case TableChgWidthHeightType::CellLeft:
2841 if( TableChgMode::VarWidthChangeAbs == m_eTableChgMode )
2843 // Then call itself recursively; only with another mode (proportional)
2844 TableChgMode eOld = m_eTableChgMode;
2845 m_eTableChgMode = TableChgMode::FixedWidthChangeAbs;
2847 bRet = SetColWidth( rCurrentBox, eType, nAbsDiff, nRelDiff,
2848 ppUndo );
2849 m_eTableChgMode = eOld;
2850 return bRet;
2852 else if( bLeft ? nDist != 0 : (rSz.GetWidth() - nDist) > COLFUZZY )
2854 if( bLeft && TableChgMode::FixedWidthChangeAbs == m_eTableChgMode )
2855 aParam.bBigger = !bBigger;
2857 // First, see if there is enough room at all
2858 SwTableBox* pBox = &rCurrentBox;
2859 SwTableLine* pLine = rCurrentBox.GetUpper();
2860 while( pLine->GetUpper() )
2862 const SwTableBoxes::size_type nPos = pLine->GetBoxPos( pBox );
2863 if( bLeft ? nPos != 0 : nPos + 1 != pLine->GetTabBoxes().size() )
2864 break;
2866 pBox = pLine->GetUpper();
2867 pLine = pBox->GetUpper();
2870 if( pLine->GetUpper() )
2872 // We need to correct the distance once again!
2873 aParam.nSide -= ::lcl_GetDistance( pLine->GetUpper(), true );
2875 if( bLeft )
2876 aParam.nMaxSize = aParam.nSide;
2877 else
2878 aParam.nMaxSize = pLine->GetUpper()->GetFrameFormat()->
2879 GetFrameSize().GetWidth() - aParam.nSide;
2882 // First, see if there is enough room at all
2883 FN_lcl_SetBoxWidth fnTmp = aParam.bBigger ? fnOtherBox : fnSelBox;
2884 bRet = (*fnTmp)( pLine, aParam, nDistStt, true );
2886 // If true, set it
2887 if( bRet )
2889 CR_SetBoxWidth aParam1( aParam );
2890 if( ppUndo )
2891 ppUndo->reset(new SwUndoAttrTable( *aParam.pTableNd, true ));
2893 if( TableChgMode::FixedWidthChangeAbs != m_eTableChgMode && bLeft )
2895 (*fnSelBox)( pLine, aParam, nDistStt, false );
2896 (*fnOtherBox)( pLine, aParam1, nDistStt, false );
2898 else
2900 (*fnOtherBox)( pLine, aParam1, nDistStt, false );
2901 (*fnSelBox)( pLine, aParam, nDistStt, false );
2905 break;
2906 default: break;
2909 #if defined DBG_UTIL
2910 if( bRet )
2912 CHECKBOXWIDTH
2913 CHECKTABLELAYOUT
2915 #endif
2917 return bRet;
2920 static void SetLineHeight( SwTableLine& rLine, SwTwips nOldHeight, SwTwips nNewHeight,
2921 bool bMinSize )
2923 SwLayoutFrame* pLineFrame = GetRowFrame( rLine );
2924 OSL_ENSURE( pLineFrame, "Where is the Frame from the SwTableLine?" );
2926 SwFrameFormat* pFormat = rLine.ClaimFrameFormat();
2928 SwTwips nMyNewH, nMyOldH = pLineFrame->getFrameArea().Height();
2929 if( !nOldHeight ) // the BaseLine and absolute
2930 nMyNewH = nMyOldH + nNewHeight;
2931 else
2933 // Calculate as exactly as possible
2934 Fraction aTmp( nMyOldH );
2935 aTmp *= Fraction( nNewHeight, nOldHeight );
2936 aTmp += Fraction( 1, 2 ); // round up if needed
2937 nMyNewH = tools::Long(aTmp);
2940 SwFrameSize eSize = SwFrameSize::Minimum;
2941 if( !bMinSize &&
2942 ( nMyOldH - nMyNewH ) > ( CalcRowRstHeight( pLineFrame ) + ROWFUZZY ))
2943 eSize = SwFrameSize::Fixed;
2945 pFormat->SetFormatAttr( SwFormatFrameSize( eSize, 0, nMyNewH ) );
2947 // First adapt all internal ones
2948 for( auto pBox : rLine.GetTabBoxes() )
2950 for( auto pLine : pBox->GetTabLines() )
2951 SetLineHeight( *pLine, nMyOldH, nMyNewH, bMinSize );
2955 static bool lcl_SetSelLineHeight( SwTableLine* pLine, const CR_SetLineHeight& rParam,
2956 SwTwips nDist, bool bCheck )
2958 bool bRet = true;
2959 if( !bCheck )
2961 // Set line height
2962 SetLineHeight( *pLine, 0, rParam.bBigger ? nDist : -nDist,
2963 rParam.bBigger );
2965 else if( !rParam.bBigger )
2967 // Calculate the new relative size by means of the old one
2968 SwLayoutFrame* pLineFrame = GetRowFrame( *pLine );
2969 OSL_ENSURE( pLineFrame, "Where is the Frame from the SwTableLine?" );
2970 SwTwips nRstHeight = CalcRowRstHeight( pLineFrame );
2971 if( (nRstHeight + ROWFUZZY) < nDist )
2972 bRet = false;
2974 return bRet;
2977 static bool lcl_SetOtherLineHeight( SwTableLine* pLine, const CR_SetLineHeight& rParam,
2978 SwTwips nDist, bool bCheck )
2980 bool bRet = true;
2981 if( bCheck )
2983 if( rParam.bBigger )
2985 // Calculate the new relative size by means of the old one
2986 SwLayoutFrame* pLineFrame = GetRowFrame( *pLine );
2987 OSL_ENSURE( pLineFrame, "Where is the Frame from the SwTableLine?" );
2989 if( TableChgMode::FixedWidthChangeProp == rParam.nMode )
2991 nDist *= pLineFrame->getFrameArea().Height();
2992 nDist /= rParam.nMaxHeight;
2994 bRet = nDist <= CalcRowRstHeight( pLineFrame );
2997 else
2999 // Set line height
3000 // pLine is the following/preceding, thus adjust it
3001 if( TableChgMode::FixedWidthChangeProp == rParam.nMode )
3003 SwLayoutFrame* pLineFrame = GetRowFrame( *pLine );
3004 OSL_ENSURE( pLineFrame, "Where is the Frame from the SwTableLine??" );
3006 // Calculate the new relative size by means of the old one
3007 // If the selected Box get bigger, adjust via the max space else
3008 // via the max height.
3009 if( (true) /*!rParam.bBigger*/ )
3011 nDist *= pLineFrame->getFrameArea().Height();
3012 nDist /= rParam.nMaxHeight;
3014 else
3016 // Calculate the new relative size by means of the old one
3017 nDist *= CalcRowRstHeight( pLineFrame );
3018 nDist /= rParam.nMaxSpace;
3021 SetLineHeight( *pLine, 0, rParam.bBigger ? -nDist : nDist,
3022 !rParam.bBigger );
3024 return bRet;
3027 bool SwTable::SetRowHeight( SwTableBox& rCurrentBox, TableChgWidthHeightType eType,
3028 SwTwips nAbsDiff, SwTwips nRelDiff, std::unique_ptr<SwUndo>* ppUndo )
3030 SwTableLine* pLine = rCurrentBox.GetUpper();
3032 SwTableLine* pBaseLine = pLine;
3033 while( pBaseLine->GetUpper() )
3034 pBaseLine = pBaseLine->GetUpper()->GetUpper();
3036 bool bBigger,
3037 bRet = false,
3038 bTop = TableChgWidthHeightType::CellTop == extractPosition( eType );
3039 sal_uInt16 nBaseLinePos = GetTabLines().GetPos( pBaseLine );
3041 CR_SetLineHeight aParam( eType,
3042 const_cast<SwTableNode*>(rCurrentBox.GetSttNd()->FindTableNode()) );
3043 bBigger = aParam.bBigger;
3045 SwTableLines* pLines = &m_aLines;
3047 // How do we get to the height?
3048 switch( extractPosition(eType) )
3050 case TableChgWidthHeightType::CellTop:
3051 case TableChgWidthHeightType::CellBottom:
3052 if( pLine == pBaseLine )
3053 break; // it doesn't work then!
3055 // Is a nested Line (Box!)
3056 pLines = &pLine->GetUpper()->GetTabLines();
3057 nBaseLinePos = pLines->GetPos( pLine );
3058 [[fallthrough]];
3060 case TableChgWidthHeightType::RowBottom:
3062 if( TableChgMode::VarWidthChangeAbs == m_eTableChgMode )
3064 // First test if we have room at all
3065 if( bBigger )
3066 bRet = true;
3067 else
3068 bRet = lcl_SetSelLineHeight( (*pLines)[ nBaseLinePos ], aParam,
3069 nAbsDiff, true );
3071 if( bRet )
3073 if( ppUndo )
3074 ppUndo->reset(new SwUndoAttrTable( *aParam.pTableNd, true ));
3076 lcl_SetSelLineHeight( (*pLines)[ nBaseLinePos ], aParam,
3077 nAbsDiff, false );
3080 else
3082 bRet = true;
3083 SwTableLines::size_type nStt;
3084 SwTableLines::size_type nEnd;
3085 if( bTop )
3087 nStt = 0;
3088 nEnd = nBaseLinePos;
3090 else
3092 nStt = nBaseLinePos + 1;
3093 nEnd = pLines->size();
3096 // Get the current Lines' height
3097 if( TableChgMode::FixedWidthChangeProp == m_eTableChgMode )
3099 for( auto n = nStt; n < nEnd; ++n )
3101 SwLayoutFrame* pLineFrame = GetRowFrame( *(*pLines)[ n ] );
3102 OSL_ENSURE( pLineFrame, "Where is the Frame from the SwTableLine??" );
3103 aParam.nMaxSpace += CalcRowRstHeight( pLineFrame );
3104 aParam.nMaxHeight += pLineFrame->getFrameArea().Height();
3106 if( bBigger && aParam.nMaxSpace < nAbsDiff )
3107 bRet = false;
3109 else
3111 if( bTop ? nEnd != 0 : nStt < nEnd )
3113 if( bTop )
3114 nStt = nEnd - 1;
3115 else
3116 nEnd = nStt + 1;
3118 else
3119 bRet = false;
3122 if( bRet )
3124 if( bBigger )
3126 for( auto n = nStt; n < nEnd; ++n )
3128 if( !lcl_SetOtherLineHeight( (*pLines)[ n ], aParam,
3129 nAbsDiff, true ))
3131 bRet = false;
3132 break;
3136 else
3137 bRet = lcl_SetSelLineHeight( (*pLines)[ nBaseLinePos ], aParam,
3138 nAbsDiff, true );
3141 if( bRet )
3143 // Adjust
3144 if( ppUndo )
3145 ppUndo->reset(new SwUndoAttrTable( *aParam.pTableNd, true ));
3147 CR_SetLineHeight aParam1( aParam );
3149 if( bTop )
3151 lcl_SetSelLineHeight( (*pLines)[ nBaseLinePos ], aParam,
3152 nAbsDiff, false );
3153 for( auto n = nStt; n < nEnd; ++n )
3154 lcl_SetOtherLineHeight( (*pLines)[ n ], aParam1,
3155 nAbsDiff, false );
3157 else
3159 for( auto n = nStt; n < nEnd; ++n )
3160 lcl_SetOtherLineHeight( (*pLines)[ n ], aParam1,
3161 nAbsDiff, false );
3162 lcl_SetSelLineHeight( (*pLines)[ nBaseLinePos ], aParam,
3163 nAbsDiff, false );
3166 else
3168 // Then call itself recursively; only with another mode (proportional)
3169 TableChgMode eOld = m_eTableChgMode;
3170 m_eTableChgMode = TableChgMode::VarWidthChangeAbs;
3172 bRet = SetRowHeight( rCurrentBox, eType, nAbsDiff,
3173 nRelDiff, ppUndo );
3175 m_eTableChgMode = eOld;
3179 break;
3180 default: break;
3183 CHECKTABLELAYOUT
3185 return bRet;
3188 SwFrameFormat* SwShareBoxFormat::GetFormat( tools::Long nWidth ) const
3190 SwFrameFormat *pRet = nullptr, *pTmp;
3191 for( auto n = m_aNewFormats.size(); n; )
3192 if( ( pTmp = m_aNewFormats[ --n ])->GetFrameSize().GetWidth()
3193 == nWidth )
3195 pRet = pTmp;
3196 break;
3198 return pRet;
3201 SwFrameFormat* SwShareBoxFormat::GetFormat( const SfxPoolItem& rItem ) const
3203 const SfxPoolItem* pItem;
3204 sal_uInt16 nWhich = rItem.Which();
3205 SwFrameFormat *pRet = nullptr, *pTmp;
3206 const SfxPoolItem& rFrameSz = m_pOldFormat->GetFormatAttr( RES_FRM_SIZE, false );
3207 for( auto n = m_aNewFormats.size(); n; )
3208 if( SfxItemState::SET == ( pTmp = m_aNewFormats[ --n ])->
3209 GetItemState( nWhich, false, &pItem ) && *pItem == rItem &&
3210 pTmp->GetFormatAttr( RES_FRM_SIZE, false ) == rFrameSz )
3212 pRet = pTmp;
3213 break;
3215 return pRet;
3218 void SwShareBoxFormat::AddFormat( SwFrameFormat& rNew )
3220 m_aNewFormats.push_back( &rNew );
3223 bool SwShareBoxFormat::RemoveFormat( const SwFrameFormat& rFormat )
3225 // returns true, if we can delete
3226 if( m_pOldFormat == &rFormat )
3227 return true;
3229 std::vector<SwFrameFormat*>::iterator it = std::find( m_aNewFormats.begin(), m_aNewFormats.end(), &rFormat );
3230 if( m_aNewFormats.end() != it )
3231 m_aNewFormats.erase( it );
3232 return m_aNewFormats.empty();
3235 SwShareBoxFormats::~SwShareBoxFormats()
3239 SwFrameFormat* SwShareBoxFormats::GetFormat( const SwFrameFormat& rFormat, tools::Long nWidth ) const
3241 sal_uInt16 nPos;
3242 return Seek_Entry( rFormat, &nPos )
3243 ? m_ShareArr[ nPos ].GetFormat(nWidth)
3244 : nullptr;
3246 SwFrameFormat* SwShareBoxFormats::GetFormat( const SwFrameFormat& rFormat,
3247 const SfxPoolItem& rItem ) const
3249 sal_uInt16 nPos;
3250 return Seek_Entry( rFormat, &nPos )
3251 ? m_ShareArr[ nPos ].GetFormat(rItem)
3252 : nullptr;
3255 void SwShareBoxFormats::AddFormat( const SwFrameFormat& rOld, SwFrameFormat& rNew )
3257 sal_uInt16 nPos;
3258 if( !Seek_Entry( rOld, &nPos ))
3260 SwShareBoxFormat aEntry(rOld);
3261 aEntry.AddFormat( rNew );
3262 m_ShareArr.insert(m_ShareArr.begin() + nPos, aEntry);
3264 else
3265 m_ShareArr[ nPos ].AddFormat(rNew);
3268 void SwShareBoxFormats::ChangeFrameFormat( SwTableBox* pBox, SwTableLine* pLn,
3269 SwFrameFormat& rFormat )
3271 SwClient aCl;
3272 SwFrameFormat* pOld = nullptr;
3273 if( pBox )
3275 pOld = pBox->GetFrameFormat();
3276 pOld->Add( &aCl );
3277 pBox->ChgFrameFormat( static_cast<SwTableBoxFormat*>(&rFormat) );
3279 else if( pLn )
3281 pOld = pLn->GetFrameFormat();
3282 pOld->Add( &aCl );
3283 pLn->ChgFrameFormat( static_cast<SwTableLineFormat*>(&rFormat) );
3285 if( pOld && pOld->HasOnlyOneListener() )
3287 RemoveFormat( *pOld );
3288 delete pOld;
3292 void SwShareBoxFormats::SetSize( SwTableBox& rBox, const SwFormatFrameSize& rSz )
3294 SwFrameFormat *pBoxFormat = rBox.GetFrameFormat(),
3295 *pRet = GetFormat( *pBoxFormat, rSz.GetWidth() );
3296 if( pRet )
3297 ChangeFrameFormat( &rBox, nullptr, *pRet );
3298 else
3300 pRet = rBox.ClaimFrameFormat();
3301 pRet->SetFormatAttr( rSz );
3302 AddFormat( *pBoxFormat, *pRet );
3306 void SwShareBoxFormats::SetAttr( SwTableBox& rBox, const SfxPoolItem& rItem )
3308 SwFrameFormat *pBoxFormat = rBox.GetFrameFormat(),
3309 *pRet = GetFormat( *pBoxFormat, rItem );
3310 if( pRet )
3311 ChangeFrameFormat( &rBox, nullptr, *pRet );
3312 else
3314 pRet = rBox.ClaimFrameFormat();
3315 pRet->SetFormatAttr( rItem );
3316 AddFormat( *pBoxFormat, *pRet );
3320 void SwShareBoxFormats::SetAttr( SwTableLine& rLine, const SfxPoolItem& rItem )
3322 SwFrameFormat *pLineFormat = rLine.GetFrameFormat(),
3323 *pRet = GetFormat( *pLineFormat, rItem );
3324 if( pRet )
3325 ChangeFrameFormat( nullptr, &rLine, *pRet );
3326 else
3328 pRet = rLine.ClaimFrameFormat();
3329 pRet->SetFormatAttr( rItem );
3330 AddFormat( *pLineFormat, *pRet );
3334 void SwShareBoxFormats::RemoveFormat( const SwFrameFormat& rFormat )
3336 for (auto i = m_ShareArr.size(); i; )
3338 if (m_ShareArr[ --i ].RemoveFormat(rFormat))
3340 m_ShareArr.erase( m_ShareArr.begin() + i );
3345 bool SwShareBoxFormats::Seek_Entry( const SwFrameFormat& rFormat, sal_uInt16* pPos ) const
3347 sal_uIntPtr nIdx = reinterpret_cast<sal_uIntPtr>(&rFormat);
3348 auto nO = m_ShareArr.size();
3349 decltype(nO) nU = 0;
3350 if( nO > 0 )
3352 nO--;
3353 while( nU <= nO )
3355 const auto nM = nU + ( nO - nU ) / 2;
3356 sal_uIntPtr nFormat = reinterpret_cast<sal_uIntPtr>(&m_ShareArr[ nM ].GetOldFormat());
3357 if( nFormat == nIdx )
3359 if( pPos )
3360 *pPos = nM;
3361 return true;
3363 else if( nFormat < nIdx )
3364 nU = nM + 1;
3365 else if( nM == 0 )
3367 if( pPos )
3368 *pPos = nU;
3369 return false;
3371 else
3372 nO = nM - 1;
3375 if( pPos )
3376 *pPos = nU;
3377 return false;
3380 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */