1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
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>
32 #include <IDocumentSettingAccess.hxx>
33 #include <IDocumentChartDataProviderAccess.hxx>
34 #include <DocumentContentOperationsManager.hxx>
35 #include <IDocumentRedlineAccess.hxx>
36 #include <IDocumentStylePoolAccess.hxx>
37 #include <IDocumentFieldsAccess.hxx>
42 #include <frmtool.hxx>
44 #include <swtable.hxx>
50 #include <UndoTable.hxx>
51 #include <cellatr.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>
62 using namespace com::sun::star
;
63 using namespace com::sun::star::uno
;
69 #define CHECK_TABLE(t) (t).CheckConsistency();
71 #define CHECK_TABLE(t)
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.
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
; }
94 SwShareBoxFormats aShareFormats
;
95 SwTableNode
* pTableNd
;
96 SwTwips nDiff
, nSide
, nMaxSize
, nLowerDiff
;
100 CR_SetBoxWidth( TableChgWidthHeightType eType
, SwTwips nDif
, SwTwips nSid
,
101 SwTwips nMax
, SwTableNode
* 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 ),
115 bBigger( rCpy
.bBigger
), bLeft( rCpy
.bLeft
)
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 );
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" ); \
162 #define CHECKBOXWIDTH
163 #define CHECKTABLELAYOUT
169 struct CR_SetLineHeight
171 SwTableNode
* pTableNd
;
172 SwTwips nMaxSpace
, nMaxHeight
;
176 CR_SetLineHeight( TableChgWidthHeightType eType
, SwTableNode
* 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
),
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
;
206 std::shared_ptr
< std::vector
< std::vector
< sal_uLong
> > > pWidths
;
208 SwTableNode
* pTableNd
;
209 CpyTabFrames
& rTabFrameArr
;
210 SwTableLine
* pInsLine
;
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
;
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
)
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() )
279 // The first Line should be enough
280 FndBoxes_t
const& rFndBoxes
= pCmpLine
->GetBoxes();
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
);
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
);
311 aFindFrame
= pCpyPara
->rTabFrameArr
[ nFndPos
];
312 pBox
->ChgFrameFormat( aFindFrame
.pNewFrameFormat
);
317 CpyTabFrames::const_iterator itFind
= pCpyPara
->rTabFrameArr
.find( aFindFrame
);
318 if( pCpyPara
->nDelBorderFlag
&&
319 itFind
!= pCpyPara
->rTabFrameArr
.end() )
320 aFindFrame
= *itFind
;
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
);
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
351 : rBoxItem
.GetRight() )
353 aFindFrame
.pFrameFormat
= pBox
->GetFrameFormat();
355 SvxBoxItem
aNew( rBoxItem
);
356 if( 8 > pCpyPara
->nDelBorderFlag
)
357 aNew
.SetLine( nullptr, SvxBoxItemLine::TOP
);
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
);
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;
409 static void lcl_InsCol( FndLine_
* pFndLn
, CpyPara
& rCpyPara
, sal_uInt16 nCpyCnt
,
412 // Bug 29124: Not only copy in the BaseLines. If possible, we go down as far as possible
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
);
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
);
432 for( sal_uInt16 n
= 0; n
< nCpyCnt
; ++n
)
434 if( n
+ 1 == nCpyCnt
&& bBehind
)
435 rCpyPara
.nDelBorderFlag
= 9;
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
)
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());
465 bRes
= NewInsertCol( rDoc
, rBoxes
, nCnt
, bBehind
, bInsertDummy
);
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() )
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
498 aFndBox
.MakeFrames( *this );
505 SwChartDataProvider
*pPCD
= rDoc
.getIDocumentChartDataProviderAccess().GetChartDataProvider();
507 pPCD
->AddRowCols( *this, rBoxes
, nCnt
, bBehind
);
508 rDoc
.UpdateCharts( GetFrameFormat()->GetName() );
510 if (SwFEShell
* pFEShell
= rDoc
.GetDocShell()->GetFEShell())
511 pFEShell
->UpdateTableStyleFormatting();
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());
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() )
533 SetHTMLTableLayout(std::shared_ptr
<SwHTMLTableLayout
>()); // Delete HTML Layout
535 FndBox_
* pFndBox
= &aFndBox
;
538 while( 1 == pFndBox
->GetLines().size() )
540 pFndLine
= pFndBox
->GetLines()[0].get();
541 if( 1 != pFndLine
->GetBoxes().size() )
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() )
552 // Find Lines for the layout update
553 const bool bLayout
= !IsNewModel() &&
554 nullptr != SwIterator
<SwTabFrame
,SwFormat
>( *GetFrameFormat() ).First();
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
);
574 aCpyPara
.pInsBox
= pFndBox
->GetBox();
575 aCpyPara
.nInsPos
= pFndBox
->GetBox()->GetTabLines().GetPos( pLine
);
581 aCpyPara
.nDelBorderFlag
= 1;
584 aCpyPara
.nDelBorderFlag
= 2;
586 for( sal_uInt16 nCpyCnt
= 0; nCpyCnt
< nCnt
; ++nCpyCnt
)
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 );
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() )
618 if( pFndBox
!= &aFndBox
)
619 aFndBox
.MakeFrames( *this );
621 aFndBox
.MakeNewFrames( *this, nCnt
, bBehind
);
627 SwChartDataProvider
*pPCD
= pDoc
->getIDocumentChartDataProviderAccess().GetChartDataProvider();
629 pPCD
->AddRowCols( *this, rBoxes
, nCnt
, bBehind
);
630 pDoc
->UpdateCharts( GetFrameFormat()->GetName() );
632 if (SwFEShell
* pFEShell
= pDoc
->GetDocShell()->GetFEShell())
633 pFEShell
->UpdateTableStyleFormatting(pTableNd
);
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
);
657 const SwFrameFormat
*pBoxFormat
= rBox
.GetFrameFormat();
658 SwFormatFrameSize
aNew( pBoxFormat
->GetFrameSize() );
659 aNew
.SetWidth( aNew
.GetWidth() + nOffset
);
660 SwFrameFormat
*pFormat
= rShareFormats
.GetFormat( *pBoxFormat
, aNew
);
662 rBox
.ChgFrameFormat( static_cast<SwTableBoxFormat
*>(pFormat
) );
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
)
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() )
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
);
713 pShareFormats
->SetAttr( *pNxtBox
, aTmp
);
715 pNxtBox
->ClaimFrameFormat()->SetFormatAttr( aTmp
);
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
);
735 pShareFormats
->SetAttr( *pPrvBox
, aTmp
);
737 pPrvBox
->ClaimFrameFormat()->SetFormatAttr( aTmp
);
743 // Delete the Box first, then the Nodes!
744 SwStartNode
* pSttNd
= const_cast<SwStartNode
*>(pBox
->GetSttNd());
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
);
755 // Has the UndoObject been prepared to save the Section?
756 if( pUndo
&& pUndo
->IsDelBox() )
757 static_cast<SwUndoTableNdsChg
*>(pUndo
)->SaveSection( pSttNd
);
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();
769 pBox
= rTableBoxes
[nDelPos
];
772 SwFormatFrameSize
aNew( pBox
->GetFrameFormat()->GetFrameSize() );
773 aNew
.SetWidth( aNew
.GetWidth() + nBoxSz
);
775 pShareFormats
->SetSize( *pBox
, aNew
);
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
,
785 pShareFormats
? *pShareFormats
789 break; // Stop deleting
791 // Delete the Line from the Table/Box
794 // Also delete the Line from the Table
795 nDelPos
= rTable
.GetTabLines().GetPos( pLine
);
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
809 nDelPos
= pBox
->GetTabLines().GetPos( pLine
);
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() );
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;
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 )
845 nFndBoxWidth
= pFndBox
->GetFrameFormat()->GetFrameSize().GetWidth();
846 nFndWidth
-= nFndBoxWidth
;
849 // Find the first ContentBox
850 while( !pFndBox
->GetSttNd() )
852 const SwTableLines
& rLowLns
= pFndBox
->GetTabLines();
854 pFndBox
= rLowLns
.front()->GetTabBoxes().front();
856 pFndBox
= rLowLns
.back()->GetTabBoxes().front();
859 if( std::abs( nFndWidth
) > COLFUZZY
||
860 std::abs( nBoxWidth
- nFndBoxWidth
) > COLFUZZY
)
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() )
868 size_t const nFndPos
= aFndIt
- pAllDelBoxes
->begin() ;
870 // else, we keep on searching.
871 // We do not need to recheck the Box, however
873 if( nFndPos
<= *pCurPos
)
875 pAllDelBoxes
->erase( pAllDelBoxes
->begin() + nFndPos
);
877 } while( bNxt
? ( nLinePos
+ 1 < o3tl::narrowing
<sal_uInt16
>(rTableLns
.size()) ) : nLinePos
!= 0 );
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() )
900 const SwTableLines
* pTableLns
;
902 pTableLns
= &pUpperBox
->GetTabLines();
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.
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
);
938 if( !(!bChgd
&& pPrvBox
&& pPrvBox
->GetSttNd()) )
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(
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());
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
988 SwSelBoxes
aBoxes( rBoxes
);
989 for (size_t n
= 0; n
< aBoxes
.size(); ++n
)
991 ::lcl_SaveUpperLowerBorder( *this, *rBoxes
[ n
], aShareFormats
,
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
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() );
1024 CHECK_TABLE( *this );
1029 bool SwTable::OldSplitRow( SwDoc
& rDoc
, const SwSelBoxes
& rBoxes
, sal_uInt16 nCnt
,
1032 OSL_ENSURE( !rBoxes
.empty() && nCnt
, "No valid values" );
1033 SwTableNode
* pTableNd
= const_cast<SwTableNode
*>(rBoxes
[0]->GetSttNd()->FindTableNode());
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
;
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
;
1081 aFSz
.SetHeight( ( bSameHeight
? pRowHeights
[ n
] : aFSz
.GetHeight() ) /
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() )
1104 SwTableBoxFormat
* pCpyBoxFrameFormat
= static_cast<SwTableBoxFormat
*>(pSelBox
->GetFrameFormat());
1105 bool bChkBorder
= nullptr != pCpyBoxFrameFormat
->GetBox().GetTop();
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
);
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
);
1128 ::InsTableBox( rDoc
, pTableNd
, pNewLine
, pCpyBoxFrameFormat
,
1133 pCpyBoxFrameFormat
= static_cast<SwTableBoxFormat
*>(pNewLine
->GetTabBoxes()[ 0 ]->ClaimFrameFormat());
1134 SvxBoxItem
aTmp( pCpyBoxFrameFormat
->GetBox() );
1135 aTmp
.SetLine( nullptr, SvxBoxItemLine::TOP
);
1136 pCpyBoxFrameFormat
->SetFormatAttr( aTmp
);
1142 const SwNode
* pEndNd
= pLastBox
->GetSttNd()->EndOfSectionNode();
1143 if( pLastBox
->GetSttIdx()+SwNodeOffset(2) != pEndNd
->GetIndex() )
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();
1165 aFndBox
.MakeFrames( *this );
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());
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 )
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
,
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
);
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
);
1274 aFndBox
.MakeFrames( *this );
1284 * If we only have one Line in the FndBox_, take this Line and test
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.
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 );
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
,
1355 SwTableLine
* pLine
)
1356 : pTableNd( pTNd
), pInsLine( pLine
), pInsBox( nullptr ),
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
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
);
1388 lcl_CpyBoxes( 0, nPos
, *pBoxes
, pULPara
->pInsLine
);
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;
1410 pBoxes
= &pULPara
->pInsLine
->GetTabBoxes();
1412 // Is there still a level to step down to?
1413 if (rFndBox
.GetBox()->GetTabLines().empty())
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
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 ?
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
);
1463 lcl_CpyLines( 0, nPos
, *pLines
, pULPara
->pInsBox
);
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
,
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
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
);
1498 lcl_CpyLines( 0, nPos
, *pLines
, pLMBox
, 0 );
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
,
1505 lcl_CalcWidth( pLMBox
); // calculate the Box's width
1511 // Find only the Line from which we need to move
1512 nStt
= pULPara
->bUL
? 0 : rFndLine
.GetBoxes().size()-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
);
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());
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() )
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
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
);
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 );
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 );
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
1651 for( const auto& rpBox
: GetTabLines()[0]->GetTabBoxes() )
1652 lcl_BoxSetHeadCondColl(rpBox
);
1654 aFndBox
.MakeFrames( *this );
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;
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
);
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();
1696 const SwTableBoxes
& rBoxes
= pBox
->GetUpper()->GetTabBoxes();
1697 for( auto pCmp
: rBoxes
)
1701 nRet
= nRet
+ o3tl::narrowing
<sal_uInt16
>(pCmp
->GetFrameFormat()->GetFrameSize().GetWidth());
1703 pBox
= pBox
->GetUpper()->GetUpper();
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());
1719 static void lcl_CalcNewWidths(const FndLines_t
& rFndLines
, CpyPara
& rPara
)
1721 rPara
.pWidths
.reset();
1722 const size_t nLineCount
= rFndLines
.size();
1725 rPara
.pWidths
= std::make_shared
< std::vector
< std::vector
< sal_uLong
> > >
1727 // First we collect information about the left/right borders of all
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();
1740 // The first selected box...
1741 const SwTableBox
*const pSel
=
1742 pFndLine
->GetBoxes().front()->GetBox();
1744 // Sum up the width of all boxes before the first selected box
1745 while( nBox
< nBoxCount
)
1747 SwTableBox
* pBox
= pLine
->GetTabBoxes()[nBox
++];
1749 nPos
+= pBox
->GetFrameFormat()->GetFrameSize().GetWidth();
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 );
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 ] )
1776 // Second step: calculate the new widths for the copied cells
1777 sal_uLong nSelSize
= rPara
.nMaxRight
- rPara
.nMinLeft
;
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();
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
);
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
];
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
;
1829 bool bDummy
= nDummy1
> 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());
1860 DoCopyIt
= !(*itFind
== aFindFrame
);
1865 aFindFrame
= pCpyPara
->rTabFrameArr
[ nFndPos
];
1866 aFrameSz
.reset(aFindFrame
.pNewFrameFormat
->GetFrameSize().Clone());
1867 DoCopyIt
= aFrameSz
->GetWidth() != static_cast<SwTwips
>(nSize
);
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
);
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
);
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
];
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
;
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
);
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
);
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
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();
2001 pFormat
= pCpyPara
->pTableNd
->GetTable().GetFrameFormat();
2002 aPara
.nOldSize
= pFormat
->GetFrameSize().GetWidth();
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() )
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() )
2036 SwitchFormulasToRelativeRepresentation();
2038 CpyTabFrames aCpyFormat
;
2039 CpyPara
aPara( &rTableNd
, 1, aCpyFormat
);
2040 aPara
.nNewSize
= aPara
.nOldSize
= rTableNd
.GetTable().GetFrameFormat()->GetFrameSize().GetWidth();
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() )
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() ));
2089 SwNodeIndex
aIdx( rPos
.GetNode(), -1 );
2090 SwTableNode
* pTableNd
= aIdx
.GetNode().FindTableNode();
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
2125 pNewTable
->GetFrameFormat()->SetFormatName( GetFrameFormat()->GetName() );
2127 CpyTabFrames aCpyFormat
;
2128 CpyPara
aPara( pTableNd
, 1, aCpyFormat
);
2129 aPara
.nNewSize
= aPara
.nOldSize
= GetFrameFormat()->GetFrameSize().GetWidth();
2132 lcl_CalcNewWidths( aFndBox
.GetLines(), aPara
);
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();
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
);
2195 pNewTable
->GCLines();
2197 pTableNd
->MakeOwnFrames(); // re-generate the Frames
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
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];
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 ];
2245 if( !pLine
->GetTabBoxes().empty() )
2247 pBox
= pLine
->GetTabBoxes().front();
2248 while( !pBox
->GetTabLines().empty() )
2249 pBox
= pBox
->GetTabLines().front()->GetTabBoxes().front();
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
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();
2279 nFndPos
= GetUpper()->GetTabLines().GetPos( pLine
);
2280 OSL_ENSURE( USHRT_MAX
!= nFndPos
, "Line is not in the Table" );
2281 // Is there another Line?
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
);
2291 return nullptr; // there are no more Boxes
2293 pLine
= rTable
.GetTabLines()[ nFndPos
-1 ];
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();
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,
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();
2336 pSttNd
->CheckSectionCondColl();
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
)
2355 pLine
= pBox
->GetUpper();
2358 sal_uInt16 nStt
= 0, nPos
= pLine
->GetBoxPos( pBox
);
2360 if( bFirst
&& !bLeft
)
2364 while( nStt
< nPos
)
2365 nRet
+= pLine
->GetTabBoxes()[ nStt
++ ]->GetFrameFormat()
2366 ->GetFrameSize().GetWidth();
2367 pBox
= pLine
->GetUpper();
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;
2385 for( auto pLn
: pBox
->GetTabLines() )
2386 if( !::lcl_SetSelBoxWidth( pLn
, rParam
, nDist
, true ))
2389 // Collect all "ContentBoxes"
2390 bGreaterBox
= (TableChgMode::FixedWidthChangeAbs
!= rParam
.nMode
)
2391 && ((nDist
+ (rParam
.bLeft
? 0 : nWidth
)) >= rParam
.nSide
);
2394 && (std::abs(nDist
+ ((rParam
.nMode
!= TableChgMode::FixedWidthChangeAbs
&& rParam
.bLeft
) ? 0 : nWidth
) - rParam
.nSide
) < COLFUZZY
)))
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
;
2406 nLowerDiff
= rParam
.nDiff
;
2408 if( nWidth
< nLowerDiff
|| nWidth
- nLowerDiff
< MINLAY
)
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
;
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
);
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
;
2445 nLowerDiff
= rParam
.nDiff
;
2448 rParam
.nLowerDiff
+= nLowerDiff
;
2450 if( rParam
.bBigger
)
2451 aNew
.SetWidth( nWidth
+ nLowerDiff
);
2453 aNew
.SetWidth( nWidth
- nLowerDiff
);
2454 rParam
.aShareFormats
.SetSize( *pBox
, aNew
);
2459 if( rParam
.bLeft
&& rParam
.nMode
!= TableChgMode::FixedWidthChangeAbs
&& nDist
>= rParam
.nSide
)
2464 // If it gets bigger, then that's it
2465 if( ( TableChgMode::FixedWidthChangeAbs
== rParam
.nMode
|| !rParam
.bLeft
) &&
2466 nDist
>= rParam
.nSide
)
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();
2484 for( auto pLn
: pBox
->GetTabLines() )
2485 if( !::lcl_SetOtherBoxWidth( pLn
, rParam
, nDist
, true ))
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
)) )
2494 if( TableChgMode::FixedWidthChangeProp
== rParam
.nMode
) // Table fixed, proportional
2496 // calculate relative
2498 nDiff
*= rParam
.nDiff
;
2499 nDiff
/= rParam
.nMaxSize
;
2502 nDiff
= rParam
.nDiff
;
2504 if( nWidth
< nDiff
|| nWidth
- nDiff
< MINLAY
)
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
;
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
);
2532 if( TableChgMode::FixedWidthChangeProp
== rParam
.nMode
) // Table fixed, proportional
2534 // calculate relative
2535 nLowerDiff
= nWidth
;
2536 nLowerDiff
*= rParam
.nDiff
;
2537 nLowerDiff
/= rParam
.nMaxSize
;
2540 nLowerDiff
= rParam
.nDiff
;
2543 rParam
.nLowerDiff
+= nLowerDiff
;
2545 if( rParam
.bBigger
)
2546 aNew
.SetWidth( nWidth
- nLowerDiff
);
2548 aNew
.SetWidth( nWidth
+ nLowerDiff
);
2550 rParam
.aShareFormats
.SetSize( *pBox
, aNew
);
2555 if( ( TableChgMode::FixedWidthChangeAbs
== rParam
.nMode
|| rParam
.bLeft
) &&
2556 nDist
> rParam
.nSide
)
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
);
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" );
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();
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;
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
;
2648 bRet
= bLeft
? rLR
.GetLeft() >= nAbsDiff
2649 : rLR
.GetRight() >= nAbsDiff
;
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
,
2659 m_eTableChgMode
= eOld
;
2666 for( auto const & n
: m_aLines
)
2669 if( !(*fnSelBox
)( n
, aParam
, nDistStt
, true ))
2680 ppUndo
->reset(new SwUndoAttrTable( *aParam
.pTableNd
, true ));
2682 tools::Long nFrameWidth
= LONG_MAX
;
2684 SwFormatFrameSize
aSz( rSz
);
2685 SvxLRSpaceItem
aLR( rLR
);
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;
2700 aParam
.nMaxSize
/= 2;
2704 aLR
.SetLeft( sal_uInt16( aLR
.GetLeft() - nAbsDiff
) );
2706 aLR
.SetRight( sal_uInt16( aLR
.GetRight() - nAbsDiff
) );
2709 aLR
.SetLeft( sal_uInt16( aLR
.GetLeft() + nAbsDiff
) );
2711 aLR
.SetRight( sal_uInt16( aLR
.GetRight() + nAbsDiff
) );
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.
2727 if( GetFrameFormat()->getIDocumentSettingAccess().get(DocumentSettingId::BROWSE_MODE
) &&
2728 !rSz
.GetWidthPercent() )
2730 SwTabFrame
* pTabFrame
= SwIterator
<SwTabFrame
,SwFormat
>( *GetFrameFormat() ).First();
2732 pTabFrame
->getFramePrintArea().Width() != rSz
.GetWidth() )
2734 nFrameWidth
= pTabFrame
->getFramePrintArea().Width();
2736 nFrameWidth
+= nAbsDiff
;
2738 nFrameWidth
-= nAbsDiff
;
2744 aSz
.SetWidth( aSz
.GetWidth() + nRelDiff
);
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
);
2756 for( sal_uInt16 n
= m_aLines
.size(); n
; )
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.
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
)
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
)
2786 if( !(*fnOtherBox
)( n
, aParam
, 0, true ))
2795 for( auto const & n
: m_aLines
)
2798 if( !(*fnSelBox
)( n
, aParam
, nDistStt
, true ))
2809 CR_SetBoxWidth
aParam1( aParam
);
2811 ppUndo
->reset(new SwUndoAttrTable( *aParam
.pTableNd
, true ));
2813 if( TableChgMode::FixedWidthChangeAbs
!= m_eTableChgMode
&& bLeft
)
2815 for( sal_uInt16 n
= m_aLines
.size(); n
; )
2819 aParam1
.LoopClear();
2820 (*fnSelBox
)( m_aLines
[ n
], aParam
, nDistStt
, false );
2821 (*fnOtherBox
)( m_aLines
[ n
], aParam1
, nDistStt
, false );
2826 for( sal_uInt16 n
= m_aLines
.size(); n
; )
2830 aParam1
.LoopClear();
2831 (*fnOtherBox
)( m_aLines
[ n
], aParam1
, nDistStt
, false );
2832 (*fnSelBox
)( m_aLines
[ n
], aParam
, nDistStt
, false );
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
,
2849 m_eTableChgMode
= eOld
;
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() )
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 );
2876 aParam
.nMaxSize
= aParam
.nSide
;
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 );
2889 CR_SetBoxWidth
aParam1( aParam
);
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 );
2900 (*fnOtherBox
)( pLine
, aParam1
, nDistStt
, false );
2901 (*fnSelBox
)( pLine
, aParam
, nDistStt
, false );
2909 #if defined DBG_UTIL
2920 static void SetLineHeight( SwTableLine
& rLine
, SwTwips nOldHeight
, SwTwips nNewHeight
,
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
;
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
;
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
)
2962 SetLineHeight( *pLine
, 0, rParam
.bBigger
? nDist
: -nDist
,
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
)
2977 static bool lcl_SetOtherLineHeight( SwTableLine
* pLine
, const CR_SetLineHeight
& rParam
,
2978 SwTwips nDist
, bool 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
);
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
;
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
,
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();
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
);
3060 case TableChgWidthHeightType::RowBottom
:
3062 if( TableChgMode::VarWidthChangeAbs
== m_eTableChgMode
)
3064 // First test if we have room at all
3068 bRet
= lcl_SetSelLineHeight( (*pLines
)[ nBaseLinePos
], aParam
,
3074 ppUndo
->reset(new SwUndoAttrTable( *aParam
.pTableNd
, true ));
3076 lcl_SetSelLineHeight( (*pLines
)[ nBaseLinePos
], aParam
,
3083 SwTableLines::size_type nStt
;
3084 SwTableLines::size_type nEnd
;
3088 nEnd
= nBaseLinePos
;
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
)
3111 if( bTop
? nEnd
!= 0 : nStt
< nEnd
)
3126 for( auto n
= nStt
; n
< nEnd
; ++n
)
3128 if( !lcl_SetOtherLineHeight( (*pLines
)[ n
], aParam
,
3137 bRet
= lcl_SetSelLineHeight( (*pLines
)[ nBaseLinePos
], aParam
,
3145 ppUndo
->reset(new SwUndoAttrTable( *aParam
.pTableNd
, true ));
3147 CR_SetLineHeight
aParam1( aParam
);
3151 lcl_SetSelLineHeight( (*pLines
)[ nBaseLinePos
], aParam
,
3153 for( auto n
= nStt
; n
< nEnd
; ++n
)
3154 lcl_SetOtherLineHeight( (*pLines
)[ n
], aParam1
,
3159 for( auto n
= nStt
; n
< nEnd
; ++n
)
3160 lcl_SetOtherLineHeight( (*pLines
)[ n
], aParam1
,
3162 lcl_SetSelLineHeight( (*pLines
)[ nBaseLinePos
], aParam
,
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
,
3175 m_eTableChgMode
= eOld
;
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()
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
)
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
)
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
3242 return Seek_Entry( rFormat
, &nPos
)
3243 ? m_ShareArr
[ nPos
].GetFormat(nWidth
)
3246 SwFrameFormat
* SwShareBoxFormats::GetFormat( const SwFrameFormat
& rFormat
,
3247 const SfxPoolItem
& rItem
) const
3250 return Seek_Entry( rFormat
, &nPos
)
3251 ? m_ShareArr
[ nPos
].GetFormat(rItem
)
3255 void SwShareBoxFormats::AddFormat( const SwFrameFormat
& rOld
, SwFrameFormat
& rNew
)
3258 if( !Seek_Entry( rOld
, &nPos
))
3260 SwShareBoxFormat
aEntry(rOld
);
3261 aEntry
.AddFormat( rNew
);
3262 m_ShareArr
.insert(m_ShareArr
.begin() + nPos
, aEntry
);
3265 m_ShareArr
[ nPos
].AddFormat(rNew
);
3268 void SwShareBoxFormats::ChangeFrameFormat( SwTableBox
* pBox
, SwTableLine
* pLn
,
3269 SwFrameFormat
& rFormat
)
3272 SwFrameFormat
* pOld
= nullptr;
3275 pOld
= pBox
->GetFrameFormat();
3277 pBox
->ChgFrameFormat( static_cast<SwTableBoxFormat
*>(&rFormat
) );
3281 pOld
= pLn
->GetFrameFormat();
3283 pLn
->ChgFrameFormat( static_cast<SwTableLineFormat
*>(&rFormat
) );
3285 if( pOld
&& pOld
->HasOnlyOneListener() )
3287 RemoveFormat( *pOld
);
3292 void SwShareBoxFormats::SetSize( SwTableBox
& rBox
, const SwFormatFrameSize
& rSz
)
3294 SwFrameFormat
*pBoxFormat
= rBox
.GetFrameFormat(),
3295 *pRet
= GetFormat( *pBoxFormat
, rSz
.GetWidth() );
3297 ChangeFrameFormat( &rBox
, nullptr, *pRet
);
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
);
3311 ChangeFrameFormat( &rBox
, nullptr, *pRet
);
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
);
3325 ChangeFrameFormat( nullptr, &rLine
, *pRet
);
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;
3355 const auto nM
= nU
+ ( nO
- nU
) / 2;
3356 sal_uIntPtr nFormat
= reinterpret_cast<sal_uIntPtr
>(&m_ShareArr
[ nM
].GetOldFormat());
3357 if( nFormat
== nIdx
)
3363 else if( nFormat
< nIdx
)
3380 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */