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 .
20 #include <libxml/xmlwriter.h>
22 #include <hintids.hxx>
24 #include <editeng/lrspitem.hxx>
25 #include <editeng/shaditem.hxx>
26 #include <editeng/adjustitem.hxx>
27 #include <editeng/colritem.hxx>
28 #include <osl/diagnose.h>
29 #include <sfx2/linkmgr.hxx>
30 #include <fmtfsize.hxx>
31 #include <fmtornt.hxx>
32 #include <fmtpdsc.hxx>
37 #include <IDocumentLinksAdministration.hxx>
38 #include <IDocumentRedlineAccess.hxx>
39 #include <IDocumentFieldsAccess.hxx>
42 #include <swtable.hxx>
46 #include <cellfrm.hxx>
51 #include <cellatr.hxx>
52 #include <txatbase.hxx>
53 #include <htmltbl.hxx>
54 #include <swtblfmt.hxx>
55 #include <ndindex.hxx>
56 #include <tblrwcl.hxx>
57 #include <shellres.hxx>
59 #include <redline.hxx>
62 #include <o3tl/string_view.hxx>
63 #include <svl/numformat.hxx>
68 #define CHECK_TABLE(t) (t).CheckConsistency();
70 #define CHECK_TABLE(t)
73 using namespace com::sun::star
;
78 static void ChgTextToNum( SwTableBox
& rBox
, const OUString
& rText
, const Color
* pCol
,
79 bool bChgAlign
, SwNodeOffset nNdPos
);
81 void SwTableBox::setRowSpan( sal_Int32 nNewRowSpan
)
83 mnRowSpan
= nNewRowSpan
;
86 bool SwTableBox::getDummyFlag() const
91 void SwTableBox::setDummyFlag( bool bDummy
)
96 //JP 15.09.98: Bug 55741 - Keep tabs (front and rear)
97 static void lcl_TabToBlankAtSttEnd( OUString
& rText
)
102 for( n
= 0; n
< rText
.getLength() && ' ' >= ( c
= rText
[n
] ); ++n
)
104 rText
= rText
.replaceAt( n
, 1, u
" " );
105 for( n
= rText
.getLength(); n
&& ' ' >= ( c
= rText
[--n
] ); )
107 rText
= rText
.replaceAt( n
, 1, u
" " );
110 static void lcl_DelTabsAtSttEnd( OUString
& rText
)
114 OUStringBuffer
sBuff(rText
);
116 for( n
= 0; n
< sBuff
.getLength() && ' ' >= ( c
= sBuff
[ n
]); ++n
)
119 sBuff
.remove( n
--, 1 );
121 for( n
= sBuff
.getLength(); n
&& ' ' >= ( c
= sBuff
[ --n
]); )
124 sBuff
.remove( n
, 1 );
126 rText
= sBuff
.makeStringAndClear();
129 void InsTableBox( SwDoc
& rDoc
, SwTableNode
* pTableNd
,
130 SwTableLine
* pLine
, SwTableBoxFormat
* pBoxFrameFormat
,
132 sal_uInt16 nInsPos
, sal_uInt16 nCnt
)
134 OSL_ENSURE( pBox
->GetSttNd(), "Box with no start node" );
135 SwNodeIndex
aIdx( *pBox
->GetSttNd(), +1 );
136 SwContentNode
* pCNd
= aIdx
.GetNode().GetContentNode();
138 pCNd
= SwNodes::GoNext(&aIdx
);
139 assert(pCNd
&& "Box with no content node");
141 if( pCNd
->IsTextNode() )
143 if( pCNd
->GetpSwAttrSet() )
145 SwAttrSet
aAttrSet( *pCNd
->GetpSwAttrSet() );
146 if(pCNd
->GetSwAttrSet().HasItem(RES_PARATR_LIST_AUTOFMT
))
148 SwFormatAutoFormat format
= aAttrSet
.Get(RES_PARATR_LIST_AUTOFMT
);
149 const std::shared_ptr
<SfxItemSet
>& handle
= format
.GetStyleHandle();
150 aAttrSet
.Put(*handle
);
152 if( pBox
->GetSaveNumFormatColor() )
154 if( pBox
->GetSaveUserColor() )
155 aAttrSet
.Put( SvxColorItem( *pBox
->GetSaveUserColor(), RES_CHRATR_COLOR
));
157 aAttrSet
.ClearItem( RES_CHRATR_COLOR
);
159 rDoc
.GetNodes().InsBoxen( pTableNd
, pLine
, pBoxFrameFormat
,
160 static_cast<SwTextNode
*>(pCNd
)->GetTextColl(),
161 &aAttrSet
, nInsPos
, nCnt
);
164 rDoc
.GetNodes().InsBoxen( pTableNd
, pLine
, pBoxFrameFormat
,
165 static_cast<SwTextNode
*>(pCNd
)->GetTextColl(),
166 pCNd
->GetpSwAttrSet(), nInsPos
, nCnt
);
169 rDoc
.GetNodes().InsBoxen( pTableNd
, pLine
, pBoxFrameFormat
,
170 rDoc
.GetDfltTextFormatColl(), nullptr,
173 sal_Int32 nRowSpan
= pBox
->getRowSpan();
176 SwTableBoxes
& rTableBoxes
= pLine
->GetTabBoxes();
177 for( sal_uInt16 i
= 0; i
< nCnt
; ++i
)
179 pBox
= rTableBoxes
[ i
+ nInsPos
];
180 pBox
->setRowSpan( nRowSpan
);
186 : SwClient( nullptr ),
187 m_pTableNode( nullptr ),
188 m_nGraphicsThatResize( 0 ),
189 m_nRowsToRepeat( 1 ),
190 m_bModifyLocked( false ),
193 // default value set in the options
194 m_eTableChgMode
= GetTableChgDefaultMode();
197 SwTable::SwTable( const SwTable
& rTable
)
198 : SwClient( rTable
.GetFrameFormat() ),
199 m_pTableNode( nullptr ),
200 m_eTableChgMode( rTable
.m_eTableChgMode
),
201 m_nGraphicsThatResize( 0 ),
202 m_nRowsToRepeat( rTable
.GetRowsToRepeat() ),
203 maTableStyleName(rTable
.maTableStyleName
),
204 m_bModifyLocked( false ),
205 m_bNewModel( rTable
.m_bNewModel
)
209 void DelBoxNode( SwTableSortBoxes
const & rSortCntBoxes
)
211 for (size_t n
= 0; n
< rSortCntBoxes
.size(); ++n
)
213 rSortCntBoxes
[ n
]->m_pStartNode
= nullptr;
221 SwDoc
* pDoc
= GetFrameFormat()->GetDoc();
222 if( !pDoc
->IsInDtor() ) // then remove from the list
223 pDoc
->getIDocumentLinksAdministration().GetLinkManager().RemoveServer( m_xRefObj
.get() );
228 // the table can be deleted if it's the last client of the FrameFormat
229 SwTableFormat
* pFormat
= GetFrameFormat();
230 pFormat
->Remove(*this); // remove
232 if( !pFormat
->HasWriterListeners() )
233 pFormat
->GetDoc()->DelTableFrameFormat( pFormat
); // and delete
235 // Delete the pointers from the SortArray of the boxes. The objects
236 // are preserved and are deleted by the lines/boxes arrays dtor.
237 // Note: unfortunately not enough, pointers to the StartNode of the
238 // section need deletion.
239 DelBoxNode(m_TabSortContentBoxes
);
240 m_TabSortContentBoxes
.clear();
247 T
lcl_MulDiv64(sal_uInt64 nA
, sal_uInt64 nM
, sal_uInt64 nD
)
250 return nD
== 0 ? static_cast<T
>(nA
*nM
) : static_cast<T
>((nA
*nM
)/nD
);
255 static void FormatInArr( std::vector
<SwFormat
*>& rFormatArr
, SwFormat
* pBoxFormat
)
257 std::vector
<SwFormat
*>::const_iterator it
= std::find( rFormatArr
.begin(), rFormatArr
.end(), pBoxFormat
);
258 if ( it
== rFormatArr
.end() )
259 rFormatArr
.push_back( pBoxFormat
);
262 static void lcl_ModifyBoxes( SwTableBoxes
&rBoxes
, const tools::Long nOld
,
263 const tools::Long nNew
, std::vector
<SwFormat
*>& rFormatArr
);
265 static void lcl_ModifyLines( SwTableLines
&rLines
, const tools::Long nOld
,
266 const tools::Long nNew
, std::vector
<SwFormat
*>& rFormatArr
, const bool bCheckSum
)
268 for ( auto &rLine
: rLines
)
269 ::lcl_ModifyBoxes( rLine
->GetTabBoxes(), nOld
, nNew
, rFormatArr
);
272 for(SwFormat
* pFormat
: rFormatArr
)
274 const SwTwips nBox
= lcl_MulDiv64
<SwTwips
>(pFormat
->GetFrameSize().GetWidth(), nNew
, nOld
);
275 SwFormatFrameSize
aNewBox( SwFrameSize::Variable
, nBox
, 0 );
276 pFormat
->LockModify();
277 pFormat
->SetFormatAttr( aNewBox
);
278 pFormat
->UnlockModify();
283 static void lcl_ModifyBoxes( SwTableBoxes
&rBoxes
, const tools::Long nOld
,
284 const tools::Long nNew
, std::vector
<SwFormat
*>& rFormatArr
)
286 sal_uInt64 nSum
= 0; // To avoid rounding errors we summarize all box widths
287 sal_uInt64 nOriginalSum
= 0; // Sum of original widths
288 for ( size_t i
= 0; i
< rBoxes
.size(); ++i
)
290 SwTableBox
&rBox
= *rBoxes
[i
];
291 if ( !rBox
.GetTabLines().empty() )
293 // For SubTables the rounding problem will not be solved :-(
294 ::lcl_ModifyLines( rBox
.GetTabLines(), nOld
, nNew
, rFormatArr
, false );
297 SwFrameFormat
*pFormat
= rBox
.GetFrameFormat();
298 sal_uInt64 nBox
= pFormat
->GetFrameSize().GetWidth();
299 nOriginalSum
+= nBox
;
300 nBox
= lcl_MulDiv64
<sal_uInt64
>(nBox
, nNew
, nOld
);
301 const sal_uInt64 nWishedSum
= lcl_MulDiv64
<sal_uInt64
>(nOriginalSum
, nNew
, nOld
) - nSum
;
304 if( nBox
== nWishedSum
)
305 FormatInArr( rFormatArr
, pFormat
);
309 pFormat
= rBox
.ClaimFrameFormat();
310 SwFormatFrameSize
aNewBox( SwFrameSize::Variable
, static_cast< SwTwips
>(nBox
), 0 );
311 pFormat
->LockModify();
312 pFormat
->SetFormatAttr( aNewBox
);
313 pFormat
->UnlockModify();
317 OSL_FAIL( "Rounding error" );
323 void SwTable::SwClientNotify(const SwModify
&, const SfxHint
& rHint
)
325 if(rHint
.GetId() == SfxHintId::SwAutoFormatUsedHint
)
327 auto& rAutoFormatUsedHint
= static_cast<const sw::AutoFormatUsedHint
&>(rHint
);
328 rAutoFormatUsedHint
.CheckNode(GetTableNode());
330 else if (rHint
.GetId() == SfxHintId::SwAttrSetChange
)
332 auto pChangeHint
= static_cast<const sw::AttrSetChangeHint
*>(&rHint
);
333 // catch SSize changes, to adjust the lines/boxes
334 const SwFormatFrameSize
* pNewSize
= nullptr, *pOldSize
= nullptr;
335 if (pChangeHint
->m_pOld
&& pChangeHint
->m_pNew
336 && (pNewSize
= pChangeHint
->m_pNew
->GetChgSet()->GetItemIfSet(
340 pOldSize
= &pChangeHint
->m_pOld
->GetChgSet()->GetFrameSize();
342 if (pOldSize
&& pNewSize
&& !m_bModifyLocked
)
343 AdjustWidths(pOldSize
->GetWidth(), pNewSize
->GetWidth());
345 else if (rHint
.GetId() == SfxHintId::SwObjectDying
)
347 auto pDyingHint
= static_cast<const sw::ObjectDyingHint
*>(&rHint
);
348 CheckRegistration( *pDyingHint
);
350 else if (rHint
.GetId() == SfxHintId::SwLegacyModify
)
352 auto pLegacy
= static_cast<const sw::LegacyModifyHint
*>(&rHint
);
353 // catch SSize changes, to adjust the lines/boxes
354 const sal_uInt16 nWhich
= pLegacy
->GetWhich();
355 if (nWhich
== RES_FRM_SIZE
)
357 const SwFormatFrameSize
* pNewSize
= nullptr, *pOldSize
= nullptr;
358 pOldSize
= static_cast<const SwFormatFrameSize
*>(pLegacy
->m_pOld
);
359 pNewSize
= static_cast<const SwFormatFrameSize
*>(pLegacy
->m_pNew
);
360 if (pOldSize
&& pNewSize
&& !m_bModifyLocked
)
361 AdjustWidths(pOldSize
->GetWidth(), pNewSize
->GetWidth());
366 void SwTable::AdjustWidths( const tools::Long nOld
, const tools::Long nNew
)
368 std::vector
<SwFormat
*> aFormatArr
;
369 aFormatArr
.reserve( m_aLines
[0]->GetTabBoxes().size() );
370 ::lcl_ModifyLines( m_aLines
, nOld
, nNew
, aFormatArr
, true );
373 static void lcl_RefreshHidden( SwTabCols
&rToFill
, size_t nPos
)
375 for ( size_t i
= 0; i
< rToFill
.Count(); ++i
)
377 if ( std::abs(static_cast<tools::Long
>(nPos
) - rToFill
[i
]) <= COLFUZZY
)
379 rToFill
.SetHidden( i
, false );
385 static void lcl_SortedTabColInsert( SwTabCols
&rToFill
, const SwTableBox
*pBox
,
386 const SwFrameFormat
*pTabFormat
, const bool bHidden
,
387 const bool bRefreshHidden
)
389 const tools::Long nWish
= pTabFormat
->GetFrameSize().GetWidth();
390 OSL_ENSURE(nWish
, "weird <= 0 width frmfrm");
392 // The value for the left edge of the box is calculated from the
393 // widths of the previous boxes.
394 tools::Long nPos
= 0;
395 tools::Long nLeftMin
= 0;
396 tools::Long nRightMax
= 0;
397 if (nWish
!= 0) //fdo#33012 0 width frmfmt
400 const SwTableBox
*pCur
= pBox
;
401 const SwTableLine
*pLine
= pBox
->GetUpper();
402 const tools::Long nAct
= rToFill
.GetRight() - rToFill
.GetLeft(); // +1 why?
406 const SwTableBoxes
&rBoxes
= pLine
->GetTabBoxes();
407 for ( size_t i
= 0; i
< rBoxes
.size(); ++i
)
409 const SwTwips nWidth
= rBoxes
[i
]->GetFrameFormat()->GetFrameSize().GetWidth();
411 const tools::Long nTmp
= lcl_MulDiv64
<tools::Long
>(nSum
, nAct
, nWish
);
413 if (rBoxes
[i
] != pCur
)
415 if ( pLine
== pBox
->GetUpper() || 0 == nLeftMin
)
416 nLeftMin
= nTmp
- nPos
;
422 if ( 0 == nRightMax
)
423 nRightMax
= nTmp
- nPos
;
427 pCur
= pLine
->GetUpper();
428 pLine
= pCur
? pCur
->GetUpper() : nullptr;
432 bool bInsert
= !bRefreshHidden
;
433 for ( size_t j
= 0; bInsert
&& (j
< rToFill
.Count()); ++j
)
435 tools::Long nCmp
= rToFill
[j
];
436 if ( (nPos
>= ((nCmp
>= COLFUZZY
) ? nCmp
- COLFUZZY
: nCmp
)) &&
437 (nPos
<= (nCmp
+ COLFUZZY
)) )
439 bInsert
= false; // Already has it.
441 else if ( nPos
< nCmp
)
444 rToFill
.Insert( nPos
, bHidden
, j
);
448 rToFill
.Insert( nPos
, bHidden
, rToFill
.Count() );
449 else if ( bRefreshHidden
)
450 ::lcl_RefreshHidden( rToFill
, nPos
);
452 if ( !bHidden
|| bRefreshHidden
)
455 // calculate minimum/maximum values for the existing entries:
456 nLeftMin
= nPos
- nLeftMin
;
457 nRightMax
= nPos
+ nRightMax
;
459 // check if nPos is entry:
460 bool bFoundPos
= false;
461 bool bFoundMax
= false;
462 for ( size_t j
= 0; !(bFoundPos
&& bFoundMax
) && j
< rToFill
.Count(); ++j
)
464 SwTabColsEntry
& rEntry
= rToFill
.GetEntry( j
);
465 tools::Long nCmp
= rToFill
[j
];
467 if ( (nPos
>= ((nCmp
>= COLFUZZY
) ? nCmp
- COLFUZZY
: nCmp
)) &&
468 (nPos
<= (nCmp
+ COLFUZZY
)) )
470 // check if nLeftMin is > old minimum for entry nPos:
471 const tools::Long nOldMin
= rEntry
.nMin
;
472 if ( nLeftMin
> nOldMin
)
473 rEntry
.nMin
= nLeftMin
;
474 // check if nRightMin is < old maximum for entry nPos:
475 const tools::Long nOldMax
= rEntry
.nMax
;
476 if ( nRightMax
< nOldMax
)
477 rEntry
.nMax
= nRightMax
;
481 else if ( (nRightMax
>= ((nCmp
>= COLFUZZY
) ? nCmp
- COLFUZZY
: nCmp
)) &&
482 (nRightMax
<= (nCmp
+ COLFUZZY
)) )
484 // check if nPos is > old minimum for entry nRightMax:
485 const tools::Long nOldMin
= rEntry
.nMin
;
486 if ( nPos
> nOldMin
)
494 static void lcl_ProcessBoxGet( const SwTableBox
*pBox
, SwTabCols
&rToFill
,
495 const SwFrameFormat
*pTabFormat
, bool bRefreshHidden
)
497 if ( !pBox
->GetTabLines().empty() )
499 const SwTableLines
&rLines
= pBox
->GetTabLines();
500 for ( size_t i
= 0; i
< rLines
.size(); ++i
)
502 const SwTableBoxes
&rBoxes
= rLines
[i
]->GetTabBoxes();
503 for ( size_t j
= 0; j
< rBoxes
.size(); ++j
)
504 ::lcl_ProcessBoxGet( rBoxes
[j
], rToFill
, pTabFormat
, bRefreshHidden
);
508 ::lcl_SortedTabColInsert( rToFill
, pBox
, pTabFormat
, false, bRefreshHidden
);
511 static void lcl_ProcessLineGet( const SwTableLine
*pLine
, SwTabCols
&rToFill
,
512 const SwFrameFormat
*pTabFormat
)
514 for ( size_t i
= 0; i
< pLine
->GetTabBoxes().size(); ++i
)
516 const SwTableBox
*pBox
= pLine
->GetTabBoxes()[i
];
517 if ( pBox
->GetSttNd() )
518 ::lcl_SortedTabColInsert( rToFill
, pBox
, pTabFormat
, true, false );
520 for ( size_t j
= 0; j
< pBox
->GetTabLines().size(); ++j
)
521 ::lcl_ProcessLineGet( pBox
->GetTabLines()[j
], rToFill
, pTabFormat
);
525 void SwTable::GetTabCols( SwTabCols
&rToFill
, const SwTableBox
*pStart
,
526 bool bRefreshHidden
, bool bCurRowOnly
) const
528 // Optimization: if bHidden is set, we only update the Hidden Array.
529 if ( bRefreshHidden
)
531 // remove corrections
532 for ( size_t i
= 0; i
< rToFill
.Count(); ++i
)
534 SwTabColsEntry
& rEntry
= rToFill
.GetEntry( i
);
535 rEntry
.nPos
-= rToFill
.GetLeft();
536 rEntry
.nMin
-= rToFill
.GetLeft();
537 rEntry
.nMax
-= rToFill
.GetLeft();
540 // All are hidden, so add the visible ones.
541 for ( size_t i
= 0; i
< rToFill
.Count(); ++i
)
542 rToFill
.SetHidden( i
, true );
546 rToFill
.Remove( 0, rToFill
.Count() );
550 // 1. All boxes which are inferior to Line which is superior to the Start,
551 // as well as their inferior boxes if present.
552 // 2. Starting from the Line, the superior box plus its neighbours; but no inferiors.
553 // 3. Apply 2. to the Line superior to the chain of boxes,
554 // until the Line's superior is not a box but the table.
555 // Only those boxes are inserted that don't contain further rows. The insertion
556 // function takes care to avoid duplicates. In order to achieve this, we work
557 // with some degree of fuzzyness (to avoid rounding errors).
558 // Only the left edge of the boxes are inserted.
559 // Finally, the first entry is removed again, because it's already
560 // covered by the border.
561 // 4. Scan the table again and insert _all_ boxes, this time as hidden.
563 const SwFrameFormat
*pTabFormat
= GetFrameFormat();
566 const SwTableBoxes
&rBoxes
= pStart
->GetUpper()->GetTabBoxes();
568 for ( size_t i
= 0; i
< rBoxes
.size(); ++i
)
569 ::lcl_ProcessBoxGet( rBoxes
[i
], rToFill
, pTabFormat
, bRefreshHidden
);
572 const SwTableLine
*pLine
= pStart
->GetUpper()->GetUpper() ?
573 pStart
->GetUpper()->GetUpper()->GetUpper() : nullptr;
576 const SwTableBoxes
&rBoxes2
= pLine
->GetTabBoxes();
577 for ( size_t k
= 0; k
< rBoxes2
.size(); ++k
)
578 ::lcl_SortedTabColInsert( rToFill
, rBoxes2
[k
],
579 pTabFormat
, false, bRefreshHidden
);
580 pLine
= pLine
->GetUpper() ? pLine
->GetUpper()->GetUpper() : nullptr;
583 if ( !bRefreshHidden
)
588 for ( size_t i
= 0; i
< m_aLines
.size(); ++i
)
589 ::lcl_ProcessLineGet( m_aLines
[i
], rToFill
, pTabFormat
);
595 // Now the coordinates are relative to the left table border - i.e.
596 // relative to SwTabCols.nLeft. However, they are expected
597 // relative to the left document border, i.e. SwTabCols.nLeftMin.
598 // So all values need to be extended by nLeft.
599 for ( size_t i
= 0; i
< rToFill
.Count(); ++i
)
601 SwTabColsEntry
& rEntry
= rToFill
.GetEntry( i
);
602 rEntry
.nPos
+= rToFill
.GetLeft();
603 rEntry
.nMin
+= rToFill
.GetLeft();
604 rEntry
.nMax
+= rToFill
.GetLeft();
608 // Structure for parameter passing
611 const SwTabCols
&rNew
;
612 const SwTabCols
&rOld
;
613 tools::Long nNewWish
,
615 std::deque
<SwTableBox
*> aBoxArr
;
616 SwShareBoxFormats aShareFormats
;
618 Parm( const SwTabCols
&rN
, const SwTabCols
&rO
)
619 : rNew( rN
), rOld( rO
), nNewWish(0), nOldWish(0)
623 static void lcl_ProcessBoxSet( SwTableBox
*pBox
, Parm
&rParm
);
625 static void lcl_ProcessLine( SwTableLine
*pLine
, Parm
&rParm
)
627 SwTableBoxes
&rBoxes
= pLine
->GetTabBoxes();
628 for ( size_t i
= rBoxes
.size(); i
> 0; )
631 ::lcl_ProcessBoxSet( rBoxes
[i
], rParm
);
635 static void lcl_ProcessBoxSet( SwTableBox
*pBox
, Parm
&rParm
)
637 if ( !pBox
->GetTabLines().empty() )
639 SwTableLines
&rLines
= pBox
->GetTabLines();
640 for ( size_t i
= rLines
.size(); i
> 0; )
643 lcl_ProcessLine( rLines
[i
], rParm
);
648 // Search the old TabCols for the current position (calculate from
649 // left and right edge). Adjust the box if the values differ from
650 // the new TabCols. If the adjusted edge has no neighbour we also
651 // adjust all superior boxes.
653 const tools::Long nOldAct
= rParm
.rOld
.GetRight() -
654 rParm
.rOld
.GetLeft(); // +1 why?
656 // The value for the left edge of the box is calculated from the
657 // widths of the previous boxes plus the left edge.
658 tools::Long nLeft
= rParm
.rOld
.GetLeft();
659 const SwTableBox
*pCur
= pBox
;
660 const SwTableLine
*pLine
= pBox
->GetUpper();
664 const SwTableBoxes
&rBoxes
= pLine
->GetTabBoxes();
665 for ( size_t i
= 0; (i
< rBoxes
.size()) && (rBoxes
[i
] != pCur
); ++i
)
667 nLeft
+= lcl_MulDiv64
<tools::Long
>(
668 rBoxes
[i
]->GetFrameFormat()->GetFrameSize().GetWidth(),
669 nOldAct
, rParm
.nOldWish
);
671 pCur
= pLine
->GetUpper();
672 pLine
= pCur
? pCur
->GetUpper() : nullptr;
674 tools::Long nLeftDiff
= 0;
675 tools::Long nRightDiff
= 0;
676 if ( nLeft
!= rParm
.rOld
.GetLeft() ) // There are still boxes before this.
678 // Right edge is left edge plus width.
679 const tools::Long nWidth
= lcl_MulDiv64
<tools::Long
>(
680 pBox
->GetFrameFormat()->GetFrameSize().GetWidth(),
681 nOldAct
, rParm
.nOldWish
);
682 const tools::Long nRight
= nLeft
+ nWidth
;
684 size_t nRightPos
= 0;
685 bool bFoundLeftPos
= false;
686 bool bFoundRightPos
= false;
687 for ( size_t i
= 0; i
< rParm
.rOld
.Count(); ++i
)
689 if ( nLeft
>= (rParm
.rOld
[i
] - COLFUZZY
) &&
690 nLeft
<= (rParm
.rOld
[i
] + COLFUZZY
) )
693 bFoundLeftPos
= true;
695 else if ( nRight
>= (rParm
.rOld
[i
] - COLFUZZY
) &&
696 nRight
<= (rParm
.rOld
[i
] + COLFUZZY
) )
699 bFoundRightPos
= true;
702 nLeftDiff
= bFoundLeftPos
?
703 rParm
.rOld
[nLeftPos
] - rParm
.rNew
[nLeftPos
] : 0;
704 nRightDiff
= bFoundRightPos
?
705 rParm
.rNew
[nRightPos
] - rParm
.rOld
[nRightPos
] : 0;
707 else // The first box.
709 nLeftDiff
= rParm
.rOld
.GetLeft() - rParm
.rNew
.GetLeft();
710 if ( rParm
.rOld
.Count() )
712 // Calculate the difference to the edge touching the first box.
713 const tools::Long nWidth
= lcl_MulDiv64
<tools::Long
>(
714 pBox
->GetFrameFormat()->GetFrameSize().GetWidth(),
715 nOldAct
, rParm
.nOldWish
);
716 const tools::Long nTmp
= nWidth
+ rParm
.rOld
.GetLeft();
717 for ( size_t i
= 0; i
< rParm
.rOld
.Count(); ++i
)
719 if ( nTmp
>= (rParm
.rOld
[i
] - COLFUZZY
) &&
720 nTmp
<= (rParm
.rOld
[i
] + COLFUZZY
) )
722 nRightDiff
= rParm
.rNew
[i
] - rParm
.rOld
[i
];
729 if( pBox
->getRowSpan() == 1 )
731 const sal_uInt16 nPos
= pBox
->GetUpper()->GetBoxPos( pBox
);
732 SwTableBoxes
& rTableBoxes
= pBox
->GetUpper()->GetTabBoxes();
733 if( nPos
&& rTableBoxes
[ nPos
- 1 ]->getRowSpan() != 1 )
735 if( nPos
+ 1 < o3tl::narrowing
<sal_uInt16
>(rTableBoxes
.size()) &&
736 rTableBoxes
[ nPos
+ 1 ]->getRowSpan() != 1 )
740 nLeftDiff
= nRightDiff
= 0;
742 if ( nLeftDiff
|| nRightDiff
)
744 // The difference is the actual difference amount. For stretched
745 // tables, it does not make sense to adjust the attributes of the
746 // boxes by this amount. The difference amount needs to be converted
748 tools::Long nTmp
= rParm
.rNew
.GetRight() - rParm
.rNew
.GetLeft(); // +1 why?
749 nLeftDiff
*= rParm
.nNewWish
;
751 nRightDiff
*= rParm
.nNewWish
;
753 tools::Long nDiff
= nLeftDiff
+ nRightDiff
;
755 // Adjust the box and all superiors by the difference amount.
758 SwFormatFrameSize
aFormatFrameSize( pBox
->GetFrameFormat()->GetFrameSize() );
759 aFormatFrameSize
.SetWidth( aFormatFrameSize
.GetWidth() + nDiff
);
760 if ( aFormatFrameSize
.GetWidth() < 0 )
761 aFormatFrameSize
.SetWidth( -aFormatFrameSize
.GetWidth() );
762 rParm
.aShareFormats
.SetSize( *pBox
, aFormatFrameSize
);
764 // The outer cells of the last row are responsible to adjust a surrounding cell.
766 if ( pBox
->GetUpper()->GetUpper() &&
767 pBox
->GetUpper() != pBox
->GetUpper()->GetUpper()->GetTabLines().back())
773 // Middle cell check:
774 if ( pBox
!= pBox
->GetUpper()->GetTabBoxes().front() )
777 if ( pBox
!= pBox
->GetUpper()->GetTabBoxes().back() )
780 pBox
= nDiff
? pBox
->GetUpper()->GetUpper() : nullptr;
787 static void lcl_ProcessBoxPtr( SwTableBox
*pBox
, std::deque
<SwTableBox
*> &rBoxArr
,
790 if ( !pBox
->GetTabLines().empty() )
792 const SwTableLines
&rLines
= pBox
->GetTabLines();
793 for ( size_t i
= 0; i
< rLines
.size(); ++i
)
795 const SwTableBoxes
&rBoxes
= rLines
[i
]->GetTabBoxes();
796 for ( size_t j
= 0; j
< rBoxes
.size(); ++j
)
797 ::lcl_ProcessBoxPtr( rBoxes
[j
], rBoxArr
, bBefore
);
801 rBoxArr
.push_front( pBox
);
803 rBoxArr
.push_back( pBox
);
806 static void lcl_AdjustBox( SwTableBox
*pBox
, const tools::Long nDiff
, Parm
&rParm
);
808 static void lcl_AdjustLines( SwTableLines
&rLines
, const tools::Long nDiff
, Parm
&rParm
)
810 for ( size_t i
= 0; i
< rLines
.size(); ++i
)
812 SwTableBox
*pBox
= rLines
[i
]->GetTabBoxes()
813 [rLines
[i
]->GetTabBoxes().size()-1];
814 lcl_AdjustBox( pBox
, nDiff
, rParm
);
818 static void lcl_AdjustBox( SwTableBox
*pBox
, const tools::Long nDiff
, Parm
&rParm
)
820 if ( !pBox
->GetTabLines().empty() )
821 ::lcl_AdjustLines( pBox
->GetTabLines(), nDiff
, rParm
);
823 // Adjust the size of the box.
824 SwFormatFrameSize
aFormatFrameSize( pBox
->GetFrameFormat()->GetFrameSize() );
825 aFormatFrameSize
.SetWidth( aFormatFrameSize
.GetWidth() + nDiff
);
827 rParm
.aShareFormats
.SetSize( *pBox
, aFormatFrameSize
);
830 void SwTable::SetTabCols( const SwTabCols
&rNew
, const SwTabCols
&rOld
,
831 const SwTableBox
*pStart
, bool bCurRowOnly
)
835 SetHTMLTableLayout(std::shared_ptr
<SwHTMLTableLayout
>()); // delete HTML-Layout
837 // FME: Made rOld const. The caller is responsible for passing correct
838 // values of rOld. Therefore we do not have to call GetTabCols anymore:
839 //GetTabCols( rOld, pStart );
841 Parm
aParm( rNew
, rOld
);
843 OSL_ENSURE( rOld
.Count() == rNew
.Count(), "Number of columns changed.");
845 // Convert the edges. We need to adjust the size of the table and some boxes.
846 // For the size adjustment, we must not make use of the Modify, since that'd
847 // adjust all boxes, which we really don't want.
848 SwFrameFormat
*pFormat
= GetFrameFormat();
849 aParm
.nOldWish
= aParm
.nNewWish
= pFormat
->GetFrameSize().GetWidth();
850 if ( (rOld
.GetLeft() != rNew
.GetLeft()) ||
851 (rOld
.GetRight()!= rNew
.GetRight()) )
855 SvxLRSpaceItem
aLR( pFormat
->GetLRSpace() );
856 SvxShadowItem
aSh( pFormat
->GetShadow() );
858 SwTwips nShRight
= aSh
.CalcShadowSpace( SvxShadowItemSide::RIGHT
);
859 SwTwips nShLeft
= aSh
.CalcShadowSpace( SvxShadowItemSide::LEFT
);
861 aLR
.SetLeft(SvxIndentValue::twips(rNew
.GetLeft() - nShLeft
));
862 aLR
.SetRight(SvxIndentValue::twips(rNew
.GetRightMax() - rNew
.GetRight() - nShRight
));
863 pFormat
->SetFormatAttr( aLR
);
865 // The alignment of the table needs to be adjusted accordingly.
866 // This is done by preserving the exact positions that have been
868 SwFormatHoriOrient
aOri( pFormat
->GetHoriOrient() );
869 if( text::HoriOrientation::NONE
!= aOri
.GetHoriOrient() &&
870 text::HoriOrientation::CENTER
!= aOri
.GetHoriOrient() )
872 const bool bLeftDist
= rNew
.GetLeft() != nShLeft
;
873 const bool bRightDist
= rNew
.GetRight() + nShRight
!= rNew
.GetRightMax();
874 if(!bLeftDist
&& !bRightDist
)
875 aOri
.SetHoriOrient( text::HoriOrientation::FULL
);
876 else if(!bRightDist
&& rNew
.GetLeft() > nShLeft
)
877 aOri
.SetHoriOrient( text::HoriOrientation::RIGHT
);
878 else if(!bLeftDist
&& rNew
.GetRight() + nShRight
< rNew
.GetRightMax())
879 aOri
.SetHoriOrient( text::HoriOrientation::LEFT
);
882 // if an automatic table hasn't (really) changed size, then leave it as auto.
883 const tools::Long nOldWidth
= rOld
.GetRight() - rOld
.GetLeft();
884 const tools::Long nNewWidth
= rNew
.GetRight() - rNew
.GetLeft();
885 if (aOri
.GetHoriOrient() != text::HoriOrientation::FULL
886 || std::abs(nOldWidth
- nNewWidth
) > COLFUZZY
)
888 aOri
.SetHoriOrient(text::HoriOrientation::LEFT_AND_WIDTH
);
892 pFormat
->SetFormatAttr( aOri
);
894 const tools::Long nAct
= rOld
.GetRight() - rOld
.GetLeft(); // +1 why?
895 tools::Long nTabDiff
= 0;
897 if ( rOld
.GetLeft() != rNew
.GetLeft() )
899 nTabDiff
= rOld
.GetLeft() - rNew
.GetLeft();
900 nTabDiff
*= aParm
.nOldWish
;
903 if ( rOld
.GetRight() != rNew
.GetRight() )
905 tools::Long nDiff
= rNew
.GetRight() - rOld
.GetRight();
906 nDiff
*= aParm
.nOldWish
;
910 ::lcl_AdjustLines( GetTabLines(), nDiff
, aParm
);
913 // Adjust the size of the table, watch out for stretched tables.
916 aParm
.nNewWish
+= nTabDiff
;
917 if ( aParm
.nNewWish
< 0 )
918 aParm
.nNewWish
= USHRT_MAX
; // Oops! Have to roll back.
919 SwFormatFrameSize
aSz( pFormat
->GetFrameSize() );
920 if ( aSz
.GetWidth() != aParm
.nNewWish
)
922 aSz
.SetWidth( aParm
.nNewWish
);
923 aSz
.SetWidthPercent( 0 );
924 pFormat
->SetFormatAttr( aSz
);
931 NewSetTabCols( aParm
, rNew
, rOld
, pStart
, bCurRowOnly
);
936 // To adjust the current row, we need to process all its boxes,
937 // similar to the filling of the TabCols (see GetTabCols()).
938 // Unfortunately we again have to take care to adjust the boxes
939 // from back to front, respectively from outer to inner.
940 // The best way to achieve this is probably to track the boxes
942 const SwTableBoxes
&rBoxes
= pStart
->GetUpper()->GetTabBoxes();
943 for ( size_t i
= 0; i
< rBoxes
.size(); ++i
)
944 ::lcl_ProcessBoxPtr( rBoxes
[i
], aParm
.aBoxArr
, false );
946 const SwTableLine
*pLine
= pStart
->GetUpper()->GetUpper() ?
947 pStart
->GetUpper()->GetUpper()->GetUpper() : nullptr;
948 const SwTableBox
*pExcl
= pStart
->GetUpper()->GetUpper();
951 const SwTableBoxes
&rBoxes2
= pLine
->GetTabBoxes();
953 for ( size_t i
= 0; i
< rBoxes2
.size(); ++i
)
955 if ( rBoxes2
[i
] != pExcl
)
956 ::lcl_ProcessBoxPtr( rBoxes2
[i
], aParm
.aBoxArr
, bBefore
);
960 pExcl
= pLine
->GetUpper();
961 pLine
= pLine
->GetUpper() ? pLine
->GetUpper()->GetUpper() : nullptr;
963 // After we've inserted a bunch of boxes (hopefully all and in
964 // correct order), we just need to process them in reverse order.
965 for ( int j
= aParm
.aBoxArr
.size()-1; j
>= 0; --j
)
967 SwTableBox
*pBox
= aParm
.aBoxArr
[j
];
968 ::lcl_ProcessBoxSet( pBox
, aParm
);
973 // Adjusting the entire table is 'easy'. All boxes without lines are
974 // adjusted, as are their superiors. Of course we need to process
975 // in reverse order to prevent fooling ourselves!
976 SwTableLines
&rLines
= GetTabLines();
977 for ( size_t i
= rLines
.size(); i
> 0; )
980 ::lcl_ProcessLine( rLines
[i
], aParm
);
986 CheckBoxWidth(GetTabLines(), *GetFrameFormat());
990 typedef std::pair
<sal_uInt16
, sal_uInt16
> ColChange
;
991 typedef std::list
< ColChange
> ChangeList
;
993 static void lcl_AdjustWidthsInLine( SwTableLine
* pLine
, ChangeList
& rOldNew
,
994 Parm
& rParm
, sal_uInt16 nColFuzzy
)
996 ChangeList::iterator pCurr
= rOldNew
.begin();
997 if( pCurr
== rOldNew
.end() )
999 const size_t nCount
= pLine
->GetTabBoxes().size();
1000 SwTwips nBorder
= 0;
1002 for( size_t i
= 0; i
< nCount
; ++i
)
1004 SwTableBox
* pBox
= pLine
->GetTabBoxes()[i
];
1005 SwTwips nWidth
= pBox
->GetFrameFormat()->GetFrameSize().GetWidth();
1006 SwTwips nNewWidth
= nWidth
- nRest
;
1009 if( pCurr
!= rOldNew
.end() && nBorder
+ nColFuzzy
>= pCurr
->first
)
1011 nBorder
-= nColFuzzy
;
1012 while( pCurr
!= rOldNew
.end() && nBorder
> pCurr
->first
)
1014 if( pCurr
!= rOldNew
.end() )
1016 nBorder
+= nColFuzzy
;
1017 if( nBorder
+ nColFuzzy
>= pCurr
->first
)
1019 if( pCurr
->second
== pCurr
->first
)
1022 nRest
= pCurr
->second
- nBorder
;
1028 if( nNewWidth
!= nWidth
)
1032 nRest
+= 1 - nNewWidth
;
1035 SwFormatFrameSize
aFormatFrameSize( pBox
->GetFrameFormat()->GetFrameSize() );
1036 aFormatFrameSize
.SetWidth( nNewWidth
);
1037 rParm
.aShareFormats
.SetSize( *pBox
, aFormatFrameSize
);
1042 static void lcl_CalcNewWidths( std::vector
<sal_uInt16
> &rSpanPos
, ChangeList
& rChanges
,
1043 SwTableLine
* pLine
, tools::Long nWish
, tools::Long nWidth
, bool bTop
)
1045 if( rChanges
.empty() )
1050 if( rSpanPos
.empty() )
1055 std::vector
<sal_uInt16
> aNewSpanPos
;
1056 ChangeList::iterator pCurr
= rChanges
.begin();
1057 ChangeList aNewChanges
{ *pCurr
}; // Nullposition
1058 std::vector
<sal_uInt16
>::iterator pSpan
= rSpanPos
.begin();
1059 sal_uInt16 nCurr
= 0;
1060 SwTwips nOrgSum
= 0;
1061 bool bRowSpan
= false;
1062 sal_uInt16 nRowSpanCount
= 0;
1063 const size_t nCount
= pLine
->GetTabBoxes().size();
1064 for( size_t nCurrBox
= 0; nCurrBox
< nCount
; ++nCurrBox
)
1066 SwTableBox
* pBox
= pLine
->GetTabBoxes()[nCurrBox
];
1067 SwTwips nCurrWidth
= pBox
->GetFrameFormat()->GetFrameSize().GetWidth();
1068 const sal_Int32 nRowSpan
= pBox
->getRowSpan();
1069 const bool bCurrRowSpan
= bTop
? nRowSpan
< 0 :
1070 ( nRowSpan
> 1 || nRowSpan
< -1 );
1071 if( bRowSpan
|| bCurrRowSpan
)
1072 aNewSpanPos
.push_back( nRowSpanCount
);
1073 bRowSpan
= bCurrRowSpan
;
1074 nOrgSum
+= nCurrWidth
;
1075 const sal_uInt16 nPos
= lcl_MulDiv64
<sal_uInt16
>(
1076 lcl_MulDiv64
<sal_uInt64
>(nOrgSum
, nWidth
, nWish
),
1078 while( pCurr
!= rChanges
.end() && pCurr
->first
< nPos
)
1084 if( pCurr
!= rChanges
.end() && pCurr
->first
<= nPos
&&
1085 pCurr
->first
!= pCurr
->second
)
1087 pSpan
= std::find_if(pSpan
, rSpanPos
.end(),
1088 [nCurr
](const sal_uInt16 nSpan
) { return nSpan
>= nCurr
; });
1089 if( pSpan
!= rSpanPos
.end() && *pSpan
== nCurr
)
1091 aNewChanges
.push_back( *pCurr
);
1098 ColChange
aTmp( nPos
, nPos
);
1099 aNewChanges
.push_back( aTmp
);
1104 pCurr
= aNewChanges
.begin();
1105 ChangeList::iterator pLast
= pCurr
;
1106 ChangeList::iterator pLeftMove
= pCurr
;
1107 while( pCurr
!= aNewChanges
.end() )
1109 if( pLeftMove
== pCurr
)
1111 while( ++pLeftMove
!= aNewChanges
.end() && pLeftMove
->first
<= pLeftMove
->second
)
1114 if( pCurr
->second
== pCurr
->first
)
1116 if( pLeftMove
!= aNewChanges
.end() && pCurr
->second
> pLeftMove
->second
)
1118 if( pLeftMove
->first
== pLast
->first
)
1119 pCurr
->second
= pLeftMove
->second
;
1122 pCurr
->second
= lcl_MulDiv64
<sal_uInt16
>(
1123 pCurr
->first
- pLast
->first
,
1124 pLeftMove
->second
- pLast
->second
,
1125 pLeftMove
->first
- pLast
->first
) + pLast
->second
;
1131 else if( pCurr
->second
> pCurr
->first
)
1135 ChangeList::iterator pNext
= pCurr
;
1136 while( pNext
!= pLeftMove
&& pNext
->second
== pNext
->first
&&
1137 pNext
->second
< pLast
->second
)
1139 while( pCurr
!= pNext
)
1141 if( pNext
== aNewChanges
.end() || pNext
->first
== pLast
->first
)
1142 pCurr
->second
= pLast
->second
;
1145 pCurr
->second
= lcl_MulDiv64
<sal_uInt16
>(
1146 pCurr
->first
- pLast
->first
,
1147 pNext
->second
- pLast
->second
,
1148 pNext
->first
- pLast
->first
) + pLast
->second
;
1161 rChanges
.swap(aNewChanges
);
1162 rSpanPos
.swap(aNewSpanPos
);
1165 void SwTable::NewSetTabCols( Parm
&rParm
, const SwTabCols
&rNew
,
1166 const SwTabCols
&rOld
, const SwTableBox
*pStart
, bool bCurRowOnly
)
1168 #if OSL_DEBUG_LEVEL > 1
1169 static int nCallCount
= 0;
1172 // First step: evaluate which lines have been moved/which widths changed
1174 const tools::Long nNewWidth
= rParm
.rNew
.GetRight() - rParm
.rNew
.GetLeft();
1175 const tools::Long nOldWidth
= rParm
.rOld
.GetRight() - rParm
.rOld
.GetLeft();
1176 if( nNewWidth
< 1 || nOldWidth
< 1 )
1178 for( size_t i
= 0; i
<= rOld
.Count(); ++i
)
1180 tools::Long nNewPos
;
1181 tools::Long nOldPos
;
1182 if( i
== rOld
.Count() )
1184 nOldPos
= rParm
.rOld
.GetRight() - rParm
.rOld
.GetLeft();
1185 nNewPos
= rParm
.rNew
.GetRight() - rParm
.rNew
.GetLeft();
1189 nOldPos
= rOld
[i
] - rParm
.rOld
.GetLeft();
1190 nNewPos
= rNew
[i
] - rParm
.rNew
.GetLeft();
1192 nNewPos
= lcl_MulDiv64
<tools::Long
>(nNewPos
, rParm
.nNewWish
, nNewWidth
);
1193 nOldPos
= lcl_MulDiv64
<tools::Long
>(nOldPos
, rParm
.nOldWish
, nOldWidth
);
1194 if( nOldPos
!= nNewPos
&& nNewPos
> 0 && nOldPos
> 0 )
1196 ColChange
aChg( o3tl::narrowing
<sal_uInt16
>(nOldPos
), o3tl::narrowing
<sal_uInt16
>(nNewPos
) );
1197 aOldNew
.push_back( aChg
);
1200 // Finished first step
1201 int nCount
= aOldNew
.size();
1203 return; // no change, nothing to do
1204 SwTableLines
&rLines
= GetTabLines();
1207 const SwTableLine
* pCurrLine
= pStart
->GetUpper();
1208 sal_uInt16 nCurr
= rLines
.GetPos( pCurrLine
);
1209 if( nCurr
>= USHRT_MAX
)
1212 ColChange
aChg( 0, 0 );
1213 aOldNew
.push_front( aChg
);
1214 std::vector
<sal_uInt16
> aRowSpanPos
;
1218 sal_uInt16 nPos
= 0;
1219 for( const auto& rCop
: aOldNew
)
1221 aCopy
.push_back( rCop
);
1222 aRowSpanPos
.push_back( nPos
++ );
1224 lcl_CalcNewWidths( aRowSpanPos
, aCopy
, rLines
[nCurr
],
1225 rParm
.nOldWish
, nOldWidth
, true );
1226 sal_uInt16 j
= nCurr
;
1227 while (!aRowSpanPos
.empty() && j
> 0)
1229 j
= o3tl::sanitizing_dec(j
);
1230 lcl_CalcNewWidths( aRowSpanPos
, aCopy
, rLines
[j
],
1231 rParm
.nOldWish
, nOldWidth
, true );
1232 lcl_AdjustWidthsInLine( rLines
[j
], aCopy
, rParm
, 0 );
1234 aRowSpanPos
.clear();
1236 if( nCurr
+1 < o3tl::narrowing
<sal_uInt16
>(rLines
.size()) )
1239 sal_uInt16 nPos
= 0;
1240 for( const auto& rCop
: aOldNew
)
1242 aCopy
.push_back( rCop
);
1243 aRowSpanPos
.push_back( nPos
++ );
1245 lcl_CalcNewWidths( aRowSpanPos
, aCopy
, rLines
[nCurr
],
1246 rParm
.nOldWish
, nOldWidth
, false );
1247 bool bGoOn
= !aRowSpanPos
.empty();
1248 sal_uInt16 j
= nCurr
;
1251 lcl_CalcNewWidths( aRowSpanPos
, aCopy
, rLines
[++j
],
1252 rParm
.nOldWish
, nOldWidth
, false );
1253 lcl_AdjustWidthsInLine( rLines
[j
], aCopy
, rParm
, 0 );
1254 bGoOn
= !aRowSpanPos
.empty() && j
+1 < o3tl::narrowing
<sal_uInt16
>(rLines
.size());
1257 ::lcl_AdjustWidthsInLine( rLines
[nCurr
], aOldNew
, rParm
, COLFUZZY
);
1261 for( size_t i
= 0; i
< rLines
.size(); ++i
)
1262 ::lcl_AdjustWidthsInLine( rLines
[i
], aOldNew
, rParm
, COLFUZZY
);
1264 CHECK_TABLE( *this )
1267 // return the pointer of the box specified.
1268 static bool lcl_IsValidRowName( std::u16string_view rStr
)
1270 bool bIsValid
= true;
1271 size_t nLen
= rStr
.size();
1272 for( size_t i
= 0; i
< nLen
&& bIsValid
; ++i
)
1274 const sal_Unicode cChar
= rStr
[i
];
1275 if (cChar
< '0' || cChar
> '9')
1282 // add 3rd parameter and its handling
1283 sal_uInt16
SwTable::GetBoxNum( OUString
& rStr
, bool bFirstPart
,
1284 const bool bPerformValidCheck
)
1286 sal_uInt16 nRet
= 0;
1287 if( bFirstPart
) // true == column; false == row
1290 // the first one uses letters for addressing!
1293 bool overflow
= false;
1294 while (nPos
<rStr
.getLength())
1296 sal_Unicode cChar
= rStr
[nPos
];
1297 if ((cChar
<'A' || cChar
>'Z') && (cChar
<'a' || cChar
>'z'))
1306 num
= num
* 52 + cChar
;
1307 if (num
> SAL_MAX_UINT16
) {
1312 nRet
= overflow
? SAL_MAX_UINT16
: num
;
1313 rStr
= rStr
.copy( nPos
); // Remove char from String
1317 const sal_Int32 nPos
= rStr
.indexOf( "." );
1321 if ( !bPerformValidCheck
|| lcl_IsValidRowName( rStr
) )
1323 nRet
= o3tl::narrowing
<sal_uInt16
>(rStr
.toInt32());
1330 const std::u16string_view
aText( rStr
.subView( 0, nPos
) );
1331 if ( !bPerformValidCheck
|| lcl_IsValidRowName( aText
) )
1333 nRet
= o3tl::narrowing
<sal_uInt16
>(o3tl::toInt32(aText
));
1335 rStr
= rStr
.copy( nPos
+1 );
1342 // add 2nd parameter and its handling
1343 const SwTableBox
* SwTable::GetTableBox( const OUString
& rName
,
1344 const bool bPerformValidCheck
) const
1346 const SwTableBox
* pBox
= nullptr;
1347 const SwTableLine
* pLine
;
1348 const SwTableLines
* pLines
;
1350 sal_uInt16 nLine
, nBox
;
1351 OUString
aNm( rName
);
1352 while( !aNm
.isEmpty() )
1354 nBox
= SwTable::GetBoxNum( aNm
, nullptr == pBox
, bPerformValidCheck
);
1357 pLines
= &GetTabLines();
1360 pLines
= &pBox
->GetTabLines();
1365 nLine
= SwTable::GetBoxNum( aNm
, false, bPerformValidCheck
);
1368 if( !nLine
|| nLine
> pLines
->size() )
1370 pLine
= (*pLines
)[ nLine
-1 ];
1373 const SwTableBoxes
* pBoxes
= &pLine
->GetTabBoxes();
1374 if( nBox
>= pBoxes
->size() )
1376 pBox
= (*pBoxes
)[ nBox
];
1379 // check if the box found has any contents
1380 if( pBox
&& !pBox
->GetSttNd() )
1382 OSL_FAIL( "Box without content, looking for the next one!" );
1383 // "drop this" until the first box
1384 while( !pBox
->GetTabLines().empty() )
1385 pBox
= pBox
->GetTabLines().front()->GetTabBoxes().front();
1390 SwTableBox
* SwTable::GetTableBox( SwNodeOffset nSttIdx
)
1392 // For optimizations, don't always process the entire SortArray.
1393 // Converting text to table, tries certain conditions
1394 // to ask for a table box of a table that is not yet having a format
1395 if(!GetFrameFormat())
1397 SwTableBox
* pRet
= nullptr;
1398 SwNodes
& rNds
= GetFrameFormat()->GetDoc()->GetNodes();
1399 SwNodeOffset nIndex
= nSttIdx
+ 1;
1400 SwContentNode
* pCNd
= nullptr;
1401 SwTableNode
* pTableNd
= nullptr;
1403 while ( nIndex
< rNds
.Count() )
1405 pTableNd
= rNds
[ nIndex
]->GetTableNode();
1409 pCNd
= rNds
[ nIndex
]->GetContentNode();
1416 if ( pCNd
|| pTableNd
)
1418 sw::BroadcastingModify
* pModify
= pCNd
;
1419 // #144862# Better handling of table in table
1420 if ( pTableNd
&& pTableNd
->GetTable().GetFrameFormat() )
1421 pModify
= pTableNd
->GetTable().GetFrameFormat();
1423 SwFrame
* pFrame
= pModify
? SwIterator
<SwFrame
,sw::BroadcastingModify
>(*pModify
).First() : nullptr;
1424 while ( pFrame
&& !pFrame
->IsCellFrame() )
1425 pFrame
= pFrame
->GetUpper();
1427 pRet
= const_cast<SwTableBox
*>(static_cast<SwCellFrame
*>(pFrame
)->GetTabBox());
1430 // In case the layout doesn't exist yet or anything else goes wrong.
1433 for (size_t n
= m_TabSortContentBoxes
.size(); n
; )
1435 if (m_TabSortContentBoxes
[ --n
]->GetSttIdx() == nSttIdx
)
1437 return m_TabSortContentBoxes
[ n
];
1444 bool SwTable::IsTableComplex() const
1446 // Returns true for complex tables, i.e. tables that contain nestings,
1447 // like containing boxes not part of the first line, e.g. results of
1448 // splits/merges which lead to more complex structures.
1449 for (size_t n
= 0; n
< m_TabSortContentBoxes
.size(); ++n
)
1451 if (m_TabSortContentBoxes
[ n
]->GetUpper()->GetUpper())
1459 SwTableLine::SwTableLine( SwTableLineFormat
*pFormat
, sal_uInt16 nBoxes
,
1461 : SwClient( pFormat
)
1463 , m_eRedlineType( RedlineType::None
)
1465 m_aBoxes
.reserve( nBoxes
);
1468 SwTableLine::~SwTableLine()
1470 for (size_t i
= 0; i
< m_aBoxes
.size(); ++i
)
1474 // the TabelleLine can be deleted if it's the last client of the FrameFormat
1475 sw::BroadcastingModify
* pMod
= GetFrameFormat();
1476 pMod
->Remove(*this); // remove,
1477 if( !pMod
->HasWriterListeners() )
1478 delete pMod
; // and delete
1481 SwTableLineFormat
* SwTableLine::ClaimFrameFormat()
1483 // This method makes sure that this object is an exclusive SwTableLine client
1484 // of an SwTableLineFormat object
1485 // If other SwTableLine objects currently listen to the same SwTableLineFormat as
1486 // this one, something needs to be done
1487 SwTableLineFormat
*pRet
= GetFrameFormat();
1488 SwIterator
<SwTableLine
,SwFormat
> aIter( *pRet
);
1489 for( SwTableLine
* pLast
= aIter
.First(); pLast
; pLast
= aIter
.Next() )
1491 if ( pLast
!= this )
1493 // found another SwTableLine that is a client of the current Format
1494 // create a new Format as a copy and use it for this object
1495 SwTableLineFormat
*pNewFormat
= pRet
->GetDoc()->MakeTableLineFormat();
1496 *pNewFormat
= *pRet
;
1498 // register SwRowFrames that know me as clients at the new Format
1499 SwIterator
<SwRowFrame
,SwFormat
> aFrameIter( *pRet
);
1500 for( SwRowFrame
* pFrame
= aFrameIter
.First(); pFrame
; pFrame
= aFrameIter
.Next() )
1501 if( pFrame
->GetTabLine() == this )
1502 pFrame
->RegisterToFormat( *pNewFormat
);
1505 pNewFormat
->Add(*this);
1514 void SwTableLine::ChgFrameFormat(SwTableLineFormat
* pNewFormat
)
1516 auto pOld
= GetFrameFormat();
1517 pOld
->CallSwClientNotify(sw::TableLineFormatChanged(*pNewFormat
, *this));
1518 // Now, re-register self.
1519 pNewFormat
->Add(*this);
1520 if(!pOld
->HasWriterListeners())
1524 SwTwips
SwTableLine::GetTableLineHeight( bool& bLayoutAvailable
) const
1527 bLayoutAvailable
= false;
1528 SwIterator
<SwRowFrame
,SwFormat
> aIter( *GetFrameFormat() );
1529 // A row could appear several times in headers/footers so only one chain of master/follow tables
1530 // will be accepted...
1531 const SwTabFrame
* pChain
= nullptr; // My chain
1532 for( SwRowFrame
* pLast
= aIter
.First(); pLast
; pLast
= aIter
.Next() )
1534 if (pLast
->GetTabLine() != this)
1537 const SwTabFrame
* pTab
= pLast
->FindTabFrame();
1541 bLayoutAvailable
= ( pTab
->IsVertical() ) ?
1542 ( 0 < pTab
->getFrameArea().Height() ) :
1543 ( 0 < pTab
->getFrameArea().Width() );
1545 // The first one defines the chain, if a chain is defined, only members of the chain
1547 if (!pChain
|| pChain
->IsAnFollow( pTab
) || pTab
->IsAnFollow(pChain
))
1549 pChain
= pTab
; // defines my chain (even it is already)
1550 if( pTab
->IsVertical() )
1551 nRet
+= pLast
->getFrameArea().Width();
1553 nRet
+= pLast
->getFrameArea().Height();
1554 // Optimization, if there are no master/follows in my chain, nothing more to add
1555 if( !pTab
->HasFollow() && !pTab
->IsFollow() )
1557 // This is not an optimization, this is necessary to avoid double additions of
1559 if( pTab
->IsInHeadline(*pLast
) )
1566 bool SwTableLine::IsEmpty() const
1568 for (size_t i
= 0; i
< m_aBoxes
.size(); ++i
)
1570 if ( !m_aBoxes
[i
]->IsEmpty() )
1576 bool SwTable::IsEmpty() const
1578 for (size_t i
= 0; i
< m_aLines
.size(); ++i
)
1580 if ( !m_aLines
[i
]->IsEmpty() )
1586 bool SwTable::HasDeletedRowOrCell() const
1588 const SwRedlineTable
& aRedlineTable
= GetFrameFormat()->GetDoc()->getIDocumentRedlineAccess().GetRedlineTable();
1589 if ( aRedlineTable
.empty() )
1592 SwRedlineTable::size_type nRedlinePos
= 0;
1593 for (size_t i
= 0; i
< m_aLines
.size(); ++i
)
1595 // has a deleted row
1596 if ( m_aLines
[i
]->IsDeleted(nRedlinePos
) )
1599 // has a deleted cell in the not deleted row
1600 SwTableBoxes
& rBoxes
= m_aLines
[i
]->GetTabBoxes();
1601 for( size_t j
= 0; j
< rBoxes
.size(); ++j
)
1603 if ( RedlineType::Delete
== rBoxes
[j
]->GetRedlineType() )
1610 bool SwTable::IsDeleted() const
1612 const SwRedlineTable
& aRedlineTable
= GetFrameFormat()->GetDoc()->getIDocumentRedlineAccess().GetRedlineTable();
1613 if ( aRedlineTable
.empty() )
1616 SwRedlineTable::size_type nRedlinePos
= 0;
1617 for (size_t i
= 0; i
< m_aLines
.size(); ++i
)
1619 if ( !m_aLines
[i
]->IsDeleted(nRedlinePos
) )
1625 void SwTable::GatherFormulas(std::vector
<SwTableBoxFormula
*>& rvFormulas
)
1627 GatherFormulas(*GetFrameFormat()->GetDoc(), rvFormulas
);
1630 void SwTable::GatherFormulas(SwDoc
& rDoc
, std::vector
<SwTableBoxFormula
*>& rvFormulas
)
1633 sw::TableFrameFormats
* pTableFrameFormats
= rDoc
.GetTableFrameFormats();
1634 for(SwTableFormat
* pFormat
: *pTableFrameFormats
)
1636 SwTable
* pTable
= FindTable(pFormat
);
1639 SwTableLines
& rTableLines
= pTable
->GetTabLines();
1640 for (SwTableLine
* pTableLine
: rTableLines
)
1642 SwTableBoxes
& rTableBoxes
= pTableLine
->GetTabBoxes();
1643 for (SwTableBox
* pTableBox
: rTableBoxes
)
1645 SwTableBoxFormat
* pTableBoxFormat
= pTableBox
->GetFrameFormat();
1646 if (const SwTableBoxFormula
* pBoxFormula
= pTableBoxFormat
->GetItemIfSet( RES_BOXATR_FORMULA
, false ))
1648 const SwNode
* pNd
= pBoxFormula
->GetNodeOfFormula();
1649 if(!pNd
|| &pNd
->GetNodes() != &pNd
->GetDoc().GetNodes()) // is this ever valid or should we assert here?
1651 rvFormulas
.push_back(const_cast<SwTableBoxFormula
*>(pBoxFormula
));
1658 void SwTable::Split(const OUString
& sNewTableName
, sal_uInt16 nSplitLine
, SwHistory
* pHistory
)
1660 SwTableFormulaUpdate
aHint(this);
1661 aHint
.m_eFlags
= TBL_SPLITTBL
;
1662 aHint
.m_aData
.pNewTableNm
= &sNewTableName
;
1663 aHint
.m_nSplitLine
= nSplitLine
;
1665 std::vector
<SwTableBoxFormula
*> vFormulas
;
1666 GatherFormulas(vFormulas
);
1667 for(auto pBoxFormula
: vFormulas
)
1669 const SwNode
* pNd
= pBoxFormula
->GetNodeOfFormula();
1670 const SwTableNode
* pTableNd
= pNd
->FindTableNode();
1671 if(pTableNd
== nullptr)
1673 if(&pTableNd
->GetTable() == this)
1675 sal_uInt16 nLnPos
= SwTableFormula::GetLnPosInTable(*this, pBoxFormula
->GetTableBox());
1676 aHint
.m_bBehindSplitLine
= USHRT_MAX
!= nLnPos
&& aHint
.m_nSplitLine
<= nLnPos
;
1679 aHint
.m_bBehindSplitLine
= false;
1680 pBoxFormula
->ToSplitMergeBoxNmWithHistory(aHint
, pHistory
);
1684 void SwTable::Merge(SwTable
& rTable
, SwHistory
* pHistory
)
1686 SwTableFormulaUpdate
aHint(this);
1687 aHint
.m_eFlags
= TBL_MERGETBL
;
1688 aHint
.m_aData
.pDelTable
= &rTable
;
1689 std::vector
<SwTableBoxFormula
*> vFormulas
;
1690 GatherFormulas(vFormulas
);
1691 for(auto pBoxFormula
: vFormulas
)
1692 pBoxFormula
->ToSplitMergeBoxNmWithHistory(aHint
, pHistory
);
1695 void SwTable::UpdateFields(TableFormulaUpdateFlags eFlags
)
1697 auto pDoc
= GetFrameFormat()->GetDoc();
1698 auto pFieldType
= pDoc
->getIDocumentFieldsAccess().GetFieldType(SwFieldIds::Table
, OUString(), false);
1701 std::vector
<SwFormatField
*> vFields
;
1702 pFieldType
->GatherFields(vFields
);
1703 for(auto pFormatField
: vFields
)
1705 SwTableField
* pField
= static_cast<SwTableField
*>(pFormatField
->GetField());
1706 // table where this field is located
1707 const SwTableNode
* pTableNd
;
1708 const SwTextNode
& rTextNd
= pFormatField
->GetTextField()->GetTextNode();
1709 pTableNd
= rTextNd
.FindTableNode();
1710 if(pTableNd
== nullptr || &pTableNd
->GetTable() != this)
1716 // to the external representation
1717 pField
->PtrToBoxNm(this);
1719 case TBL_RELBOXNAME
:
1720 // to the relative representation
1721 pField
->ToRelBoxNm(this);
1724 // to the internal representation
1725 // JP 17.06.96: internal representation on all formulas
1726 // (reference to other table!!!)
1727 pField
->BoxNmToPtr( &pTableNd
->GetTable() );
1730 assert(false); // Only TBL_BOXNAME, TBL_RELBOXNAME and TBL_BOXPTR are supported
1735 // process all table box formulas
1736 SwTableLines
& rTableLines
= GetTabLines();
1737 for (SwTableLine
* pTableLine
: rTableLines
)
1739 SwTableBoxes
& rTableBoxes
= pTableLine
->GetTabBoxes();
1740 for (SwTableBox
* pTableBox
: rTableBoxes
)
1742 SwTableBoxFormat
* pTableBoxFormat
= pTableBox
->GetFrameFormat();
1743 if (const SwTableBoxFormula
* pItem
= pTableBoxFormat
->GetItemIfSet( RES_BOXATR_FORMULA
, false ))
1745 // SwTableBoxFormula is non-shareable, so const_cast is somewhat OK
1746 auto & rBoxFormula
= const_cast<SwTableBoxFormula
&>(*pItem
);
1747 if(eFlags
== TBL_BOXPTR
)
1748 rBoxFormula
.TryBoxNmToPtr();
1749 else if(eFlags
== TBL_RELBOXNAME
)
1750 rBoxFormula
.TryRelBoxNm();
1752 rBoxFormula
.ChangeState();
1758 void SwTable::dumpAsXml(xmlTextWriterPtr pWriter
) const
1760 (void)xmlTextWriterStartElement(pWriter
, BAD_CAST("SwTable"));
1761 (void)xmlTextWriterWriteFormatAttribute(pWriter
, BAD_CAST("ptr"), "%p", this);
1762 (void)xmlTextWriterWriteFormatAttribute(pWriter
, BAD_CAST("table-format"), "%p", GetFrameFormat());
1763 (void)xmlTextWriterStartElement(pWriter
, BAD_CAST("lines"));
1764 for (const auto& pLine
: m_aLines
)
1766 pLine
->dumpAsXml(pWriter
);
1768 (void)xmlTextWriterEndElement(pWriter
);
1769 (void)xmlTextWriterEndElement(pWriter
);
1772 // TODO Set HasTextChangesOnly=true, if needed based on the redlines in the cells.
1773 // At tracked row deletion, return with the newest deletion of the row or
1774 // at tracked row insertion, return with the oldest insertion in the row, which
1775 // contain the change data of the row change.
1776 // If the return value is SwRedlineTable::npos, there is no tracked row change.
1777 SwRedlineTable::size_type
SwTableLine::UpdateTextChangesOnly(
1778 SwRedlineTable::size_type
& rRedlinePos
, bool bUpdateProperty
) const
1780 SwRedlineTable::size_type nRet
= SwRedlineTable::npos
;
1781 const SwRedlineTable
& aRedlineTable
= GetFrameFormat()->GetDoc()->getIDocumentRedlineAccess().GetRedlineTable();
1783 // check table row property "HasTextChangesOnly", if it's defined and its
1784 // value is false, and all text content is in delete redlines, the row is deleted
1785 const SvxPrintItem
*pHasTextChangesOnlyProp
=
1786 GetFrameFormat()->GetAttrSet().GetItem
<SvxPrintItem
>(RES_PRINT
);
1787 if ( pHasTextChangesOnlyProp
&& !pHasTextChangesOnlyProp
->GetValue() )
1789 const SwTableBoxes
& rBoxes
= GetTabBoxes();
1790 size_t nBoxes
= rBoxes
.size();
1791 bool bInsertion
= false;
1792 bool bPlainTextInLine
= false;
1793 SwRedlineTable::size_type nOldestRedline
= SwRedlineTable::npos
;
1794 SwRedlineTable::size_type nNewestRedline
= SwRedlineTable::npos
;
1795 for (size_t nBoxIndex
= 0; nBoxIndex
< nBoxes
&& rRedlinePos
< aRedlineTable
.size(); ++nBoxIndex
)
1797 auto pBox
= rBoxes
[nBoxIndex
];
1798 if ( pBox
->IsEmpty( /*bWithRemainingNestedTable =*/ false ) )
1800 // no text content, check the next cells
1804 bool bHasRedlineInBox
= false;
1805 SwPosition
aCellStart( *pBox
->GetSttNd(), SwNodeOffset(0) );
1806 SwPosition
aCellEnd( *pBox
->GetSttNd()->EndOfSectionNode(), SwNodeOffset(-1) );
1807 SwNodeIndex
pEndNodeIndex(aCellEnd
.GetNode());
1808 SwRangeRedline
* pPreviousDeleteRedline
= nullptr;
1809 for( ; rRedlinePos
< aRedlineTable
.size(); ++rRedlinePos
)
1811 const SwRangeRedline
* pRedline
= aRedlineTable
[ rRedlinePos
];
1813 if ( pRedline
->Start()->GetNodeIndex() > pEndNodeIndex
.GetIndex() )
1815 // no more redlines in the actual cell,
1816 // check the next ones
1820 // redline in the cell
1821 if ( aCellStart
<= *pRedline
->Start() )
1823 if ( !bHasRedlineInBox
)
1825 bHasRedlineInBox
= true;
1826 // plain text before the first redline in the text
1827 if ( pRedline
->Start()->GetContentIndex() > 0 )
1828 bPlainTextInLine
= true;
1831 RedlineType nType
= pRedline
->GetType();
1833 // first insert redline
1836 if ( RedlineType::Insert
== nType
)
1842 // plain text between the delete redlines
1843 if ( pPreviousDeleteRedline
&&
1844 *pPreviousDeleteRedline
->End() < *pRedline
->Start() &&
1845 // in the same section, i.e. not in a nested table
1846 pPreviousDeleteRedline
->End()->nNode
.GetNode().StartOfSectionNode() ==
1847 pRedline
->Start()->nNode
.GetNode().StartOfSectionNode() )
1849 bPlainTextInLine
= true;
1851 pPreviousDeleteRedline
= const_cast<SwRangeRedline
*>(pRedline
);
1855 // search newest and oldest redlines
1856 if ( nNewestRedline
== SwRedlineTable::npos
||
1857 aRedlineTable
[nNewestRedline
]->GetRedlineData().GetTimeStamp() <
1858 pRedline
->GetRedlineData().GetTimeStamp() )
1860 nNewestRedline
= rRedlinePos
;
1862 if ( nOldestRedline
== SwRedlineTable::npos
||
1863 aRedlineTable
[nOldestRedline
]->GetRedlineData().GetTimeStamp() >
1864 pRedline
->GetRedlineData().GetTimeStamp() )
1866 nOldestRedline
= rRedlinePos
;
1871 // there is text content outside of redlines: not a deletion
1872 if ( !bInsertion
&& ( !bHasRedlineInBox
|| ( pPreviousDeleteRedline
&&
1873 // in the same cell, i.e. not in a nested table
1874 pPreviousDeleteRedline
->End()->nNode
.GetNode().StartOfSectionNode() ==
1875 aCellEnd
.GetNode().StartOfSectionNode() &&
1876 ( pPreviousDeleteRedline
->End()->GetNode() < aCellEnd
.GetNode() ||
1877 pPreviousDeleteRedline
->End()->GetContentIndex() <
1878 aCellEnd
.GetNode().GetContentNode()->Len() ) ) ) )
1880 bPlainTextInLine
= true;
1881 // not deleted cell content: the row is not empty
1882 // maybe insertion of a row, try to search it
1887 // choose return redline, if it exists or remove changed row attribute
1888 if ( bInsertion
&& SwRedlineTable::npos
!= nOldestRedline
&&
1889 RedlineType::Insert
== aRedlineTable
[ nOldestRedline
]->GetType() )
1891 // there is an insert redline, which is the oldest redline in the row
1892 nRet
= nOldestRedline
;
1894 else if ( !bInsertion
&& !bPlainTextInLine
&& SwRedlineTable::npos
!= nNewestRedline
&&
1895 RedlineType::Delete
== aRedlineTable
[ nNewestRedline
]->GetType() )
1897 // there is a delete redline, which is the newest redline in the row,
1898 // and no text outside of redlines, and no insert redline in the row,
1899 // i.e. whole text content is deleted
1900 nRet
= nNewestRedline
;
1904 // no longer tracked row insertion or deletion
1905 nRet
= SwRedlineTable::npos
;
1906 // set TextChangesOnly = true to remove the tracked deletion
1907 // FIXME Undo is not supported here (this is only a fallback,
1908 // because using SetRowNotTracked() is not recommended here)
1909 if ( bUpdateProperty
)
1911 SvxPrintItem
aUnsetTracking(RES_PRINT
, true);
1912 SwFrameFormat
*pFormat
= const_cast<SwTableLine
*>(this)->ClaimFrameFormat();
1913 pFormat
->LockModify();
1914 pFormat
->SetFormatAttr( aUnsetTracking
);
1915 pFormat
->UnlockModify();
1921 const_cast<SwTableLine
*>(this)->SetRedlineType( SwRedlineTable::npos
== nRet
1923 : aRedlineTable
[ nRet
]->GetType());
1928 SwRedlineTable::size_type
SwTableLine::GetTableRedline() const
1930 const SwRedlineTable
& aRedlineTable
= GetFrameFormat()->GetDoc()->getIDocumentRedlineAccess().GetRedlineTable();
1931 const SwStartNode
* pFirstBox
= GetTabBoxes().front()->GetSttNd();
1932 const SwStartNode
* pLastBox
= GetTabBoxes().back()->GetSttNd();
1934 // Box with no start node
1935 if ( !pFirstBox
|| !pLastBox
)
1936 return SwRedlineTable::npos
;
1938 const SwPosition
aLineStart(*pFirstBox
);
1939 const SwPosition
aLineEnd(*pLastBox
);
1940 SwRedlineTable::size_type n
= 0;
1942 const SwRangeRedline
* pFnd
= aRedlineTable
.FindAtPosition( aLineStart
, n
, /*next=*/false );
1943 if( pFnd
&& *pFnd
->Start() < aLineStart
&& *pFnd
->End() > aLineEnd
)
1946 return SwRedlineTable::npos
;
1949 bool SwTableLine::IsTracked(SwRedlineTable::size_type
& rRedlinePos
, bool bOnlyDeleted
) const
1951 SwRedlineTable::size_type nPos
= UpdateTextChangesOnly(rRedlinePos
);
1952 if ( nPos
!= SwRedlineTable::npos
)
1954 const SwRedlineTable
& aRedlineTable
=
1955 GetFrameFormat()->GetDoc()->getIDocumentRedlineAccess().GetRedlineTable();
1956 if ( RedlineType::Delete
== aRedlineTable
[nPos
]->GetType() ||
1957 ( !bOnlyDeleted
&& RedlineType::Insert
== aRedlineTable
[nPos
]->GetType() ) )
1963 bool SwTableLine::IsDeleted(SwRedlineTable::size_type
& rRedlinePos
) const
1965 // if not a deleted row, check the deleted columns
1966 if ( !IsTracked(rRedlinePos
, /*bOnlyDeleted=*/true) )
1968 const SwTableBoxes
& rBoxes
= GetTabBoxes();
1969 for( size_t i
= 0; i
< rBoxes
.size(); ++i
)
1971 // there is a not deleted column
1972 if ( rBoxes
[i
]->GetRedlineType() != RedlineType::Delete
)
1980 RedlineType
SwTableLine::GetRedlineType() const
1982 const SwRedlineTable
& aRedlineTable
= GetFrameFormat()->GetDoc()->getIDocumentRedlineAccess().GetRedlineTable();
1983 if ( aRedlineTable
.empty() )
1984 return RedlineType::None
;
1986 // check table row property "HasTextChangesOnly", if it's defined and its value is
1987 // false, return with the cached redline type, if it exists, otherwise calculate it
1988 const SvxPrintItem
*pHasTextChangesOnlyProp
=
1989 GetFrameFormat()->GetAttrSet().GetItem
<SvxPrintItem
>(RES_PRINT
);
1990 if ( pHasTextChangesOnlyProp
&& !pHasTextChangesOnlyProp
->GetValue() )
1992 if ( RedlineType::None
!= m_eRedlineType
)
1993 return m_eRedlineType
;
1995 SwRedlineTable::size_type nPos
= 0;
1996 nPos
= UpdateTextChangesOnly(nPos
);
1997 if ( nPos
!= SwRedlineTable::npos
)
1998 return aRedlineTable
[nPos
]->GetType();
2000 else if ( RedlineType::None
!= m_eRedlineType
)
2002 const_cast<SwTableLine
*>(this)->SetRedlineType( RedlineType::None
);
2004 // is the whole table part of a changed text
2005 SwRedlineTable::size_type nTableRedline
= GetTableRedline();
2006 if ( nTableRedline
!= SwRedlineTable::npos
)
2007 return aRedlineTable
[nTableRedline
]->GetType();
2009 return RedlineType::None
;
2012 void SwTableLine::dumpAsXml(xmlTextWriterPtr pWriter
) const
2014 (void)xmlTextWriterStartElement(pWriter
, BAD_CAST("SwTableLine"));
2015 (void)xmlTextWriterWriteFormatAttribute(pWriter
, BAD_CAST("ptr"), "%p", this);
2017 GetFrameFormat()->dumpAsXml(pWriter
);
2019 (void)xmlTextWriterStartElement(pWriter
, BAD_CAST("boxes"));
2020 for (const auto& pBox
: m_aBoxes
)
2022 pBox
->dumpAsXml(pWriter
);
2024 (void)xmlTextWriterEndElement(pWriter
);
2026 (void)xmlTextWriterEndElement(pWriter
);
2029 SwTableBox::SwTableBox( SwTableBoxFormat
* pFormat
, sal_uInt16 nLines
, SwTableLine
*pUp
)
2032 , m_pStartNode(nullptr)
2035 , mbDummyFlag(false)
2036 , mbDirectFormatting(false)
2038 m_aLines
.reserve( nLines
);
2039 CheckBoxFormat( pFormat
)->Add(*this);
2042 SwTableBox::SwTableBox( SwTableBoxFormat
* pFormat
, const SwNodeIndex
&rIdx
,
2048 , mbDummyFlag(false)
2049 , mbDirectFormatting(false)
2051 CheckBoxFormat( pFormat
)->Add(*this);
2053 m_pStartNode
= rIdx
.GetNode().GetStartNode();
2055 // insert into the table
2056 const SwTableNode
* pTableNd
= m_pStartNode
->FindTableNode();
2057 assert(pTableNd
&& "In which table is that box?");
2058 SwTableSortBoxes
& rSrtArr
= const_cast<SwTableSortBoxes
&>(pTableNd
->GetTable().
2060 SwTableBox
* p
= this; // error: &this
2061 rSrtArr
.insert( p
); // insert
2064 SwTableBox::SwTableBox( SwTableBoxFormat
* pFormat
, const SwStartNode
& rSttNd
, SwTableLine
*pUp
)
2067 , m_pStartNode(&rSttNd
)
2070 , mbDummyFlag(false)
2071 , mbDirectFormatting(false)
2073 CheckBoxFormat( pFormat
)->Add(*this);
2075 // insert into the table
2076 const SwTableNode
* pTableNd
= m_pStartNode
->FindTableNode();
2077 assert(pTableNd
&& "In which table is the box?");
2078 SwTableSortBoxes
& rSrtArr
= const_cast<SwTableSortBoxes
&>(pTableNd
->GetTable().
2080 SwTableBox
* p
= this; // error: &this
2081 rSrtArr
.insert( p
); // insert
2084 void SwTableBox::RemoveFromTable()
2086 if (m_pStartNode
) // box containing contents?
2088 // remove from table
2089 const SwTableNode
* pTableNd
= m_pStartNode
->FindTableNode();
2090 assert(pTableNd
&& "In which table is that box?");
2091 SwTableSortBoxes
& rSrtArr
= const_cast<SwTableSortBoxes
&>(pTableNd
->GetTable().
2093 SwTableBox
*p
= this; // error: &this
2094 rSrtArr
.erase( p
); // remove
2095 m_pStartNode
= nullptr; // clear it so this is only run once
2099 SwTableBox::~SwTableBox()
2101 if (!GetFrameFormat()->GetDoc()->IsInDtor())
2106 // the TabelleBox can be deleted if it's the last client of the FrameFormat
2107 sw::BroadcastingModify
* pMod
= GetFrameFormat();
2108 pMod
->Remove(*this); // remove,
2109 if( !pMod
->HasWriterListeners() )
2110 delete pMod
; // and delete
2113 SwTableBoxFormat
* SwTableBox::CheckBoxFormat( SwTableBoxFormat
* pFormat
)
2115 // We might need to create a new format here, because the box must be
2116 // added to the format solely if pFormat has a value or form.
2117 if( SfxItemState::SET
== pFormat
->GetItemState( RES_BOXATR_VALUE
, false ) ||
2118 SfxItemState::SET
== pFormat
->GetItemState( RES_BOXATR_FORMULA
, false ) )
2120 SwTableBox
* pOther
= SwIterator
<SwTableBox
,SwFormat
>( *pFormat
).First();
2123 SwTableBoxFormat
* pNewFormat
= pFormat
->GetDoc()->MakeTableBoxFormat();
2124 pNewFormat
->LockModify();
2125 *pNewFormat
= *pFormat
;
2127 // Remove values and formulas
2128 pNewFormat
->ResetFormatAttr( RES_BOXATR_FORMULA
, RES_BOXATR_VALUE
);
2129 pNewFormat
->UnlockModify();
2131 pFormat
= pNewFormat
;
2137 SwTableBoxFormat
* SwTableBox::ClaimFrameFormat()
2139 // This method makes sure that this object is an exclusive SwTableBox client
2140 // of an SwTableBoxFormat object
2141 // If other SwTableBox objects currently listen to the same SwTableBoxFormat as
2142 // this one, something needs to be done
2143 SwTableBoxFormat
*pRet
= GetFrameFormat();
2144 SwIterator
<SwTableBox
,SwFormat
> aIter( *pRet
);
2145 for( SwTableBox
* pLast
= aIter
.First(); pLast
; pLast
= aIter
.Next() )
2147 if ( pLast
!= this )
2149 // Found another SwTableBox object
2150 // create a new Format as a copy and assign me to it
2151 // don't copy values and formulas
2152 SwTableBoxFormat
* pNewFormat
= pRet
->GetDoc()->MakeTableBoxFormat();
2153 pNewFormat
->LockModify();
2154 *pNewFormat
= *pRet
;
2155 pNewFormat
->ResetFormatAttr( RES_BOXATR_FORMULA
, RES_BOXATR_VALUE
);
2156 pNewFormat
->UnlockModify();
2158 // re-register SwCellFrame objects that know me
2159 SwIterator
<SwCellFrame
,SwFormat
> aFrameIter( *pRet
);
2160 for( SwCellFrame
* pCell
= aFrameIter
.First(); pCell
; pCell
= aFrameIter
.Next() )
2161 if( pCell
->GetTabBox() == this )
2162 pCell
->RegisterToFormat( *pNewFormat
);
2164 // re-register myself
2165 pNewFormat
->Add(*this);
2173 void SwTableBox::ChgFrameFormat(SwTableBoxFormat
* pNewFormat
, bool bNeedToReregister
)
2175 SwFrameFormat
* pOld
= GetFrameFormat();
2176 // tdf#84635 We set bNeedToReregister=false to avoid a quadratic slowdown on loading large tables,
2177 // and since we are creating the table for the first time, no re-registration is necessary.
2178 // First, re-register the Frames.
2179 if(bNeedToReregister
)
2180 pOld
->CallSwClientNotify(sw::TableBoxFormatChanged(*pNewFormat
, *this));
2181 // Now, re-register self.
2182 pNewFormat
->Add(*this);
2183 if(!pOld
->HasWriterListeners())
2187 // Return the name of this box. This is determined dynamically
2188 // resulting from the position in the lines/boxes/tables.
2189 void sw_GetTableBoxColStr( sal_uInt16 nCol
, OUString
& rNm
)
2191 const sal_uInt16 coDiff
= 52; // 'A'-'Z' 'a' - 'z'
2194 const sal_uInt16 nCalc
= nCol
% coDiff
;
2196 rNm
= OUStringChar( sal_Unicode('a' - 26 + nCalc
) ) + rNm
;
2198 rNm
= OUStringChar( sal_Unicode('A' + nCalc
) ) + rNm
;
2200 nCol
= nCol
- nCalc
;
2208 Point
SwTableBox::GetCoordinates() const
2210 if( !m_pStartNode
) // box without content?
2212 // search for the next first box?
2213 return Point( 0, 0 );
2216 const SwTable
& rTable
= m_pStartNode
->FindTableNode()->GetTable();
2218 const SwTableBox
* pBox
= this;
2220 const SwTableLine
* pLine
= pBox
->GetUpper();
2221 // at the first level?
2222 const SwTableLines
* pLines
= pLine
->GetUpper()
2223 ? &pLine
->GetUpper()->GetTabLines() : &rTable
.GetTabLines();
2225 nY
= pLines
->GetPos( pLine
) + 1 ;
2226 nX
= pBox
->GetUpper()->GetBoxPos( pBox
) + 1;
2227 pBox
= pLine
->GetUpper();
2229 return Point( nX
, nY
);
2232 OUString
SwTableBox::GetName() const
2234 if( !m_pStartNode
) // box without content?
2236 // search for the next first box?
2240 const SwTable
& rTable
= m_pStartNode
->FindTableNode()->GetTable();
2243 const SwTableBox
* pBox
= this;
2245 const SwTableLine
* pLine
= pBox
->GetUpper();
2246 // at the first level?
2247 const SwTableLines
* pLines
= pLine
->GetUpper()
2248 ? &pLine
->GetUpper()->GetTabLines() : &rTable
.GetTabLines();
2250 nPos
= pLines
->GetPos( pLine
) + 1;
2251 sTmp
= OUString::number( nPos
);
2252 if( !sNm
.isEmpty() )
2253 sNm
= sTmp
+ "." + sNm
;
2257 nPos
= pBox
->GetUpper()->GetBoxPos( pBox
);
2258 sTmp
= OUString::number(nPos
+ 1);
2259 pBox
= pLine
->GetUpper();
2260 if( nullptr != pBox
)
2261 sNm
= sTmp
+ "." + sNm
;
2263 sw_GetTableBoxColStr( nPos
, sNm
);
2269 bool SwTableBox::IsInHeadline( const SwTable
* pTable
) const
2271 if( !GetUpper() ) // should only happen upon merge.
2275 pTable
= &m_pStartNode
->FindTableNode()->GetTable();
2277 const SwTableLine
* pLine
= GetUpper();
2278 while( pLine
->GetUpper() )
2279 pLine
= pLine
->GetUpper()->GetUpper();
2282 return pTable
->GetTabLines()[ 0 ] == pLine
;
2285 SwNodeOffset
SwTableBox::GetSttIdx() const
2287 return m_pStartNode
? m_pStartNode
->GetIndex() : SwNodeOffset(0);
2290 bool SwTableBox::IsEmpty( bool bWithRemainingNestedTable
) const
2292 const SwStartNode
*pSttNd
= GetSttNd();
2297 const SwNode
* pFirstNode
= pSttNd
->GetNodes()[pSttNd
->GetIndex() + 1];
2299 if ( pSttNd
->GetIndex() + 2 == pSttNd
->EndOfSectionIndex() )
2301 // single empty node in the box
2302 const SwContentNode
*pCNd
= pFirstNode
->GetContentNode();
2303 if ( pCNd
&& !pCNd
->Len() )
2306 // tdf#157011 OOXML w:std cell content is imported with terminating 0x01 characters,
2307 // i.e. an empty box can contain double 0x01: handle it to avoid losing change tracking
2308 // FIXME regression since commit b5c616d10bff3213840d4893d13b4493de71fa56
2309 if ( pCNd
&& pCNd
->Len() == 2 && pCNd
->GetTextNode() )
2311 const OUString
&rText
= pCNd
->GetTextNode()->GetText();
2312 if ( rText
[0] == 0x01 && rText
[1] == 0x01 )
2316 else if ( bWithRemainingNestedTable
)
2318 if ( const SwTableNode
* pTableNode
= pFirstNode
->GetTableNode() )
2320 // empty nested table in the box and
2321 // no text content after it
2322 if ( pTableNode
->EndOfSectionIndex() + 2 == pSttNd
->EndOfSectionIndex() )
2323 return pTableNode
->GetTable().IsEmpty();
2330 // retrieve information from the client
2331 bool SwTable::GetInfo( SwFindNearestNode
& rInfo
) const
2333 if( GetFrameFormat() &&
2334 GetFrameFormat()->GetFormatAttr( RES_PAGEDESC
).GetPageDesc() &&
2335 !m_TabSortContentBoxes
.empty() &&
2336 m_TabSortContentBoxes
[0]->GetSttNd()->GetNodes().IsDocNodes() )
2337 rInfo
.CheckNode( *m_TabSortContentBoxes
[0]->GetSttNd()->FindTableNode() );
2341 SwTable
* SwTable::FindTable( SwFrameFormat
const*const pFormat
)
2344 ? SwIterator
<SwTable
,SwFormat
>(*pFormat
).First()
2348 SwTableNode
* SwTable::GetTableNode() const
2350 return !GetTabSortBoxes().empty() ?
2351 const_cast<SwTableNode
*>(GetTabSortBoxes()[ 0 ]->GetSttNd()->FindTableNode()) :
2355 void SwTable::SetRefObject( SwServerObject
* pObj
)
2357 if( m_xRefObj
.is() )
2358 m_xRefObj
->Closed();
2363 void SwTable::SetHTMLTableLayout(std::shared_ptr
<SwHTMLTableLayout
> const& r
)
2368 static void ChgTextToNum( SwTableBox
& rBox
, const OUString
& rText
, const Color
* pCol
,
2371 SwNodeOffset nNdPos
= rBox
.IsValidNumTextNd();
2372 ChgTextToNum( rBox
,rText
,pCol
,bChgAlign
,nNdPos
);
2374 void ChgTextToNum( SwTableBox
& rBox
, const OUString
& rText
, const Color
* pCol
,
2375 bool bChgAlign
, SwNodeOffset nNdPos
)
2378 if( NODE_OFFSET_MAX
== nNdPos
)
2381 SwDoc
* pDoc
= rBox
.GetFrameFormat()->GetDoc();
2382 SwTextNode
* pTNd
= pDoc
->GetNodes()[ nNdPos
]->GetTextNode();
2384 // assign adjustment
2387 const SfxPoolItem
* pItem
;
2388 pItem
= &pTNd
->SwContentNode::GetAttr( RES_PARATR_ADJUST
);
2389 SvxAdjust eAdjust
= static_cast<const SvxAdjustItem
*>(pItem
)->GetAdjust();
2390 if( SvxAdjust::Left
== eAdjust
|| SvxAdjust::Block
== eAdjust
)
2392 SvxAdjustItem
aAdjust( *static_cast<const SvxAdjustItem
*>(pItem
) );
2393 aAdjust
.SetAdjust( SvxAdjust::Right
);
2394 pTNd
->SetAttr( aAdjust
);
2398 // assign color or save "user color"
2399 const SvxColorItem
* pColorItem
= nullptr;
2400 if( pTNd
->GetpSwAttrSet() )
2401 pColorItem
= pTNd
->GetpSwAttrSet()->GetItemIfSet( RES_CHRATR_COLOR
, false );
2403 const std::optional
<Color
>& pOldNumFormatColor
= rBox
.GetSaveNumFormatColor();
2404 std::optional
<Color
> pNewUserColor
;
2406 pNewUserColor
= pColorItem
->GetValue();
2408 if( ( pNewUserColor
&& pOldNumFormatColor
&&
2409 *pNewUserColor
== *pOldNumFormatColor
) ||
2410 ( !pNewUserColor
&& !pOldNumFormatColor
))
2412 // Keep the user color, set updated values, delete old NumFormatColor if needed
2414 // if needed, set the color
2415 pTNd
->SetAttr( SvxColorItem( *pCol
, RES_CHRATR_COLOR
));
2416 else if( pColorItem
)
2418 pNewUserColor
= rBox
.GetSaveUserColor();
2420 pTNd
->SetAttr( SvxColorItem( *pNewUserColor
, RES_CHRATR_COLOR
));
2422 pTNd
->ResetAttr( RES_CHRATR_COLOR
);
2427 // Save user color, set NumFormat color if needed, but never reset the color
2428 rBox
.SetSaveUserColor( pNewUserColor
? *pNewUserColor
: std::optional
<Color
>() );
2431 // if needed, set the color
2432 pTNd
->SetAttr( SvxColorItem( *pCol
, RES_CHRATR_COLOR
));
2435 rBox
.SetSaveNumFormatColor( pCol
? *pCol
: std::optional
<Color
>() );
2437 if( pTNd
->GetText() != rText
)
2439 // Exchange text. Bugfix to keep Tabs (front and back!) and annotations (inword comment anchors)
2440 const OUString
& rOrig
= pTNd
->GetText();
2443 for( n
= 0; n
< rOrig
.getLength() && ('\x9' == rOrig
[n
] || CH_TXTATR_INWORD
== rOrig
[n
]); ++n
)
2445 for( ; n
< rOrig
.getLength() && '\x01' == rOrig
[n
]; ++n
)
2447 SwContentIndex
aIdx( pTNd
, n
);
2448 for( n
= rOrig
.getLength(); n
&& ('\x9' == rOrig
[--n
] || CH_TXTATR_INWORD
== rOrig
[n
]); )
2450 sal_Int32 nEndPos
= n
;
2451 n
-= aIdx
.GetIndex() - 1;
2453 // Reset DontExpand-Flags before exchange, to retrigger expansion
2455 SwContentIndex
aResetIdx( aIdx
, n
);
2456 pTNd
->DontExpandFormat( aResetIdx
.GetIndex(), false, false );
2459 if( !pDoc
->getIDocumentRedlineAccess().IsIgnoreRedline() && !pDoc
->getIDocumentRedlineAccess().GetRedlineTable().empty() )
2461 SwPaM
aTemp(*pTNd
, 0, *pTNd
, rOrig
.getLength());
2462 pDoc
->getIDocumentRedlineAccess().DeleteRedline(aTemp
, true, RedlineType::Any
);
2465 // preserve comments inside of the number by deleting number portions starting from the back
2466 sal_Int32 nCommentPos
= pTNd
->GetText().lastIndexOf( CH_TXTATR_INWORD
, nEndPos
);
2467 while( nCommentPos
> aIdx
.GetIndex() )
2469 pTNd
->EraseText( SwContentIndex(pTNd
, nCommentPos
+1), nEndPos
- nCommentPos
, SwInsertFlags::EMPTYEXPAND
);
2470 // find the next non-sequential comment anchor
2473 nEndPos
= nCommentPos
;
2474 n
= nEndPos
- aIdx
.GetIndex();
2475 nCommentPos
= pTNd
->GetText().lastIndexOf( CH_TXTATR_INWORD
, nEndPos
);
2478 while( nCommentPos
> aIdx
.GetIndex() && nCommentPos
== nEndPos
);
2481 pTNd
->EraseText( aIdx
, n
, SwInsertFlags::EMPTYEXPAND
);
2482 pTNd
->InsertText( rText
, aIdx
, SwInsertFlags::EMPTYEXPAND
);
2484 if( pDoc
->getIDocumentRedlineAccess().IsRedlineOn() )
2486 SwPaM
aTemp(*pTNd
, 0, *pTNd
, rText
.getLength());
2487 pDoc
->getIDocumentRedlineAccess().AppendRedline(new SwRangeRedline(RedlineType::Insert
, aTemp
), true);
2491 // assign vertical orientation
2492 const SwFormatVertOrient
* pVertOrientItem
;
2494 ( !(pVertOrientItem
= rBox
.GetFrameFormat()->GetItemIfSet( RES_VERT_ORIENT
)) ||
2495 text::VertOrientation::TOP
== pVertOrientItem
->GetVertOrient() ))
2497 rBox
.GetFrameFormat()->SetFormatAttr( SwFormatVertOrient( 0, text::VertOrientation::BOTTOM
));
2502 static void ChgNumToText( SwTableBox
& rBox
, sal_uLong nFormat
)
2504 SwNodeOffset nNdPos
= rBox
.IsValidNumTextNd( false );
2505 if( NODE_OFFSET_MAX
== nNdPos
)
2508 SwDoc
* pDoc
= rBox
.GetFrameFormat()->GetDoc();
2509 SwTextNode
* pTNd
= pDoc
->GetNodes()[ nNdPos
]->GetTextNode();
2510 bool bChgAlign
= pDoc
->IsInsTableAlignNum();
2512 const Color
* pCol
= nullptr;
2513 if( getSwDefaultTextFormat() != nFormat
)
2515 // special text format:
2517 const OUString
sText( pTNd
->GetText() );
2518 pDoc
->GetNumberFormatter()->GetOutputString( sText
, nFormat
, sTmp
, &pCol
);
2522 // Reset DontExpand-Flags before exchange, to retrigger expansion
2523 pTNd
->DontExpandFormat( sText
.getLength(), false, false );
2524 SwContentIndex
aIdx( pTNd
, 0 );
2525 pTNd
->EraseText( aIdx
, SAL_MAX_INT32
, SwInsertFlags::EMPTYEXPAND
);
2526 pTNd
->InsertText( sTmp
, aIdx
, SwInsertFlags::EMPTYEXPAND
);
2530 const SfxItemSet
* pAttrSet
= pTNd
->GetpSwAttrSet();
2532 // assign adjustment
2533 const SvxAdjustItem
* pAdjustItem
;
2534 if( bChgAlign
&& pAttrSet
&&
2535 (pAdjustItem
= pAttrSet
->GetItemIfSet( RES_PARATR_ADJUST
, false )) &&
2536 SvxAdjust::Right
== pAdjustItem
->GetAdjust() )
2538 pTNd
->SetAttr( SvxAdjustItem( SvxAdjust::Left
, RES_PARATR_ADJUST
) );
2541 // assign color or save "user color"
2542 const SvxColorItem
* pColorItem
= nullptr;
2544 pColorItem
= pAttrSet
->GetItemIfSet( RES_CHRATR_COLOR
, false );
2546 const std::optional
<Color
>& pOldNumFormatColor
= rBox
.GetSaveNumFormatColor();
2547 std::optional
<Color
> pNewUserColor
;
2549 pNewUserColor
= pColorItem
->GetValue();
2551 if( ( pNewUserColor
&& pOldNumFormatColor
&&
2552 *pNewUserColor
== *pOldNumFormatColor
) ||
2553 ( !pNewUserColor
&& !pOldNumFormatColor
))
2555 // Keep the user color, set updated values, delete old NumFormatColor if needed
2557 // if needed, set the color
2558 pTNd
->SetAttr( SvxColorItem( *pCol
, RES_CHRATR_COLOR
));
2559 else if( pColorItem
)
2561 pNewUserColor
= rBox
.GetSaveUserColor();
2563 pTNd
->SetAttr( SvxColorItem( *pNewUserColor
, RES_CHRATR_COLOR
));
2565 pTNd
->ResetAttr( RES_CHRATR_COLOR
);
2570 // Save user color, set NumFormat color if needed, but never reset the color
2571 rBox
.SetSaveUserColor( pNewUserColor
);
2574 // if needed, set the color
2575 pTNd
->SetAttr( SvxColorItem( *pCol
, RES_CHRATR_COLOR
));
2578 rBox
.SetSaveNumFormatColor( pCol
? *pCol
: std::optional
<Color
>() );
2580 // assign vertical orientation
2581 const SwFormatVertOrient
* pVertOrientItem
;
2583 (pVertOrientItem
= rBox
.GetFrameFormat()->GetItemIfSet( RES_VERT_ORIENT
, false )) &&
2584 text::VertOrientation::BOTTOM
== pVertOrientItem
->GetVertOrient() )
2586 rBox
.GetFrameFormat()->SetFormatAttr( SwFormatVertOrient( 0, text::VertOrientation::TOP
));
2590 void SwTableBoxFormat::BoxAttributeChanged(SwTableBox
& rBox
, const SwTableBoxNumFormat
* pNewFormat
, const SwTableBoxFormula
* pNewFormula
, const SwTableBoxValue
* pNewValue
, sal_uLong nOldFormat
)
2592 sal_uLong nNewFormat
;
2595 nNewFormat
= pNewFormat
->GetValue();
2597 // is it newer or has the current been removed?
2598 if( SfxItemState::SET
!= GetItemState(RES_BOXATR_VALUE
, false))
2599 pNewFormat
= nullptr;
2603 // fetch the current Item
2604 pNewFormat
= GetItemIfSet(RES_BOXATR_FORMAT
, false);
2605 nOldFormat
= GetTableBoxNumFormat().GetValue();
2606 nNewFormat
= pNewFormat
? pNewFormat
->GetValue() : nOldFormat
;
2609 // is it newer or has the current been removed?
2612 if(GetDoc()->GetNumberFormatter()->IsTextFormat(nNewFormat
))
2616 if(SfxItemState::SET
== GetItemState(RES_BOXATR_VALUE
, false))
2617 nOldFormat
= getSwDefaultTextFormat();
2619 nNewFormat
= getSwDefaultTextFormat();
2624 // Value change: -> "simulate" a format change!
2626 // Text -> !Text or format change:
2627 // - align right for horizontal alignment, if LEFT or JUSTIFIED
2628 // - align bottom for vertical alignment, if TOP is set, or default
2629 // - replace text (color? negative numbers RED?)
2631 // - align left for horizontal alignment, if RIGHT
2632 // - align top for vertical alignment, if BOTTOM is set
2633 SvNumberFormatter
* pNumFormatr
= GetDoc()->GetNumberFormatter();
2634 bool bNewIsTextFormat
= pNumFormatr
->IsTextFormat(nNewFormat
);
2636 if((!bNewIsTextFormat
&& nOldFormat
!= nNewFormat
) || pNewFormula
)
2638 bool bIsNumFormat
= false;
2640 bool bChgText
= true;
2643 pNewValue
= GetItemIfSet(RES_BOXATR_VALUE
, false);
2646 // so far, no value has been set, so try to evaluate the content
2647 SwNodeOffset nNdPos
= rBox
.IsValidNumTextNd();
2648 if(NODE_OFFSET_MAX
!= nNdPos
)
2650 sal_uInt32 nTmpFormatIdx
= nNewFormat
;
2651 OUString
aText(GetDoc()->GetNodes()[nNdPos
] ->GetTextNode()->GetRedlineText());
2658 lcl_TabToBlankAtSttEnd(aText
);
2660 // JP 22.04.98: Bug 49659 -
2661 // Special casing for percent
2662 if(SvNumFormatType::PERCENT
== pNumFormatr
->GetType(nNewFormat
))
2664 sal_uInt32 nTmpFormat
= 0;
2665 if(GetDoc()->IsNumberFormat(aText
, nTmpFormat
, fVal
))
2667 if(SvNumFormatType::NUMBER
== pNumFormatr
->GetType( nTmpFormat
))
2670 bIsNumFormat
= GetDoc()->IsNumberFormat(aText
, nTmpFormatIdx
, fVal
);
2674 bIsNumFormat
= GetDoc()->IsNumberFormat(aText
, nTmpFormatIdx
, fVal
);
2678 // directly assign value - without Modify
2679 bool bIsLockMod
= IsModifyLocked();
2681 SetFormatAttr(SwTableBoxValue(fVal
));
2690 fVal
= pNewValue
->GetValue();
2691 bIsNumFormat
= true;
2694 // format contents with the new value assigned and write to paragraph
2695 const Color
* pCol
= nullptr;
2697 bool bChangeFormat
= true;
2700 sNewText
= SwViewShell::GetShellRes()->aCalc_Error
;
2705 pNumFormatr
->GetOutputString(fVal
, nNewFormat
, sNewText
, &pCol
);
2708 // Original text could not be parsed as
2709 // number/date/time/..., so keep the text.
2711 // Actually the text should be formatted
2712 // according to the format, which may include
2713 // additional text from the format, for example
2714 // in {0;-0;"BAD: "@}. But other places when
2715 // entering a new value or changing text or
2716 // changing to a different format of type Text
2717 // don't do this (yet?).
2718 pNumFormatr
->GetOutputString(aOrigText
, nNewFormat
, sNewText
, &pCol
);
2720 sNewText
= aOrigText
;
2722 // Remove the newly assigned numbering format as well if text actually exists.
2723 // Exception: assume user-defined formats are always intentional.
2724 if (bChgText
&& pNumFormatr
->IsTextFormat(nOldFormat
)
2725 && !pNumFormatr
->IsUserDefined(nNewFormat
))
2727 rBox
.GetFrameFormat()->ResetFormatAttr(RES_BOXATR_FORMAT
);
2728 bChangeFormat
= false;
2738 ChgTextToNum(rBox
, sNewText
, pCol
, GetDoc()->IsInsTableAlignNum());
2741 else if(bNewIsTextFormat
&& nOldFormat
!= nNewFormat
)
2742 ChgNumToText(rBox
, nNewFormat
);
2745 SwTableBox
* SwTableBoxFormat::SwTableBoxFormat::GetTableBox()
2747 SwIterator
<SwTableBox
,SwFormat
> aIter(*this);
2748 auto pBox
= aIter
.First();
2749 SAL_INFO_IF(!pBox
, "sw.core", "no box found at format");
2750 SAL_WARN_IF(pBox
&& aIter
.Next(), "sw.core", "more than one box found at format");
2754 // for detection of modifications (mainly TableBoxAttribute)
2755 void SwTableBoxFormat::SwClientNotify(const SwModify
& rMod
, const SfxHint
& rHint
)
2757 if(rHint
.GetId() == SfxHintId::SwFormatChange
2758 || rHint
.GetId() == SfxHintId::SwObjectDying
2759 || rHint
.GetId() == SfxHintId::SwUpdateAttr
)
2761 SwFrameFormat::SwClientNotify(rMod
, rHint
);
2764 if(rHint
.GetId() != SfxHintId::SwLegacyModify
&& rHint
.GetId() != SfxHintId::SwAttrSetChange
)
2766 if(IsModifyLocked() || !GetDoc() || GetDoc()->IsInDtor())
2768 SwFrameFormat::SwClientNotify(rMod
, rHint
);
2771 const SwTableBoxNumFormat
* pNewFormat
= nullptr;
2772 const SwTableBoxFormula
* pNewFormula
= nullptr;
2773 const SwTableBoxValue
* pNewVal
= nullptr;
2774 sal_uLong nOldFormat
= getSwDefaultTextFormat();
2776 if(rHint
.GetId() == SfxHintId::SwLegacyModify
)
2778 auto pLegacy
= static_cast<const sw::LegacyModifyHint
*>(&rHint
);
2779 switch(pLegacy
->m_pNew
? pLegacy
->m_pNew
->Which() : 0)
2781 case RES_BOXATR_FORMAT
:
2782 pNewFormat
= static_cast<const SwTableBoxNumFormat
*>(pLegacy
->m_pNew
);
2783 nOldFormat
= static_cast<const SwTableBoxNumFormat
*>(pLegacy
->m_pOld
)->GetValue();
2785 case RES_BOXATR_FORMULA
:
2786 pNewFormula
= static_cast<const SwTableBoxFormula
*>(pLegacy
->m_pNew
);
2788 case RES_BOXATR_VALUE
:
2789 pNewVal
= static_cast<const SwTableBoxValue
*>(pLegacy
->m_pNew
);
2793 else // rHint.GetId() == SfxHintId::SwAttrSetChange
2795 auto pChangeHint
= static_cast<const sw::AttrSetChangeHint
*>(&rHint
);
2796 const SfxItemSet
& rSet
= *pChangeHint
->m_pNew
->GetChgSet();
2797 pNewFormat
= rSet
.GetItemIfSet( RES_BOXATR_FORMAT
, false);
2799 nOldFormat
= pChangeHint
->m_pOld
->GetChgSet()->Get(RES_BOXATR_FORMAT
).GetValue();
2800 pNewFormula
= rSet
.GetItemIfSet(RES_BOXATR_FORMULA
, false);
2801 pNewVal
= rSet
.GetItemIfSet(RES_BOXATR_VALUE
, false);
2804 // something changed and some BoxAttribute remained in the set!
2805 if( pNewFormat
|| pNewFormula
|| pNewVal
)
2807 GetDoc()->getIDocumentFieldsAccess().SetFieldsDirty(true, nullptr, SwNodeOffset(0));
2809 if(SfxItemState::SET
== GetItemState(RES_BOXATR_FORMAT
, false) ||
2810 SfxItemState::SET
== GetItemState(RES_BOXATR_VALUE
, false) ||
2811 SfxItemState::SET
== GetItemState(RES_BOXATR_FORMULA
, false) )
2813 if(auto pBox
= GetTableBox())
2814 BoxAttributeChanged(*pBox
, pNewFormat
, pNewFormula
, pNewVal
, nOldFormat
);
2818 SwFrameFormat::SwClientNotify(rMod
, rHint
);
2821 bool SwTableBoxFormat::supportsFullDrawingLayerFillAttributeSet() const
2826 bool SwTableFormat::supportsFullDrawingLayerFillAttributeSet() const
2831 bool SwTableLineFormat::supportsFullDrawingLayerFillAttributeSet() const
2836 bool SwTableBox::HasNumContent( double& rNum
, sal_uInt32
& rFormatIndex
,
2837 bool& rIsEmptyTextNd
) const
2840 SwNodeOffset nNdPos
= IsValidNumTextNd();
2841 if( NODE_OFFSET_MAX
!= nNdPos
)
2843 OUString
aText( m_pStartNode
->GetNodes()[ nNdPos
]->GetTextNode()->GetRedlineText() );
2845 lcl_TabToBlankAtSttEnd( aText
);
2846 rIsEmptyTextNd
= aText
.isEmpty();
2847 SvNumberFormatter
* pNumFormatr
= GetFrameFormat()->GetDoc()->GetNumberFormatter();
2849 if( const SwTableBoxNumFormat
* pItem
= GetFrameFormat()->GetItemIfSet( RES_BOXATR_FORMAT
, false) )
2851 rFormatIndex
= pItem
->GetValue();
2852 // Special casing for percent
2853 if( !rIsEmptyTextNd
&& SvNumFormatType::PERCENT
== pNumFormatr
->GetType( rFormatIndex
))
2855 sal_uInt32 nTmpFormat
= 0;
2856 if( GetFrameFormat()->GetDoc()->IsNumberFormat( aText
, nTmpFormat
, rNum
) &&
2857 SvNumFormatType::NUMBER
== pNumFormatr
->GetType( nTmpFormat
))
2864 bRet
= GetFrameFormat()->GetDoc()->IsNumberFormat( aText
, rFormatIndex
, rNum
);
2867 rIsEmptyTextNd
= false;
2871 bool SwTableBox::IsNumberChanged() const
2875 if( SfxItemState::SET
== GetFrameFormat()->GetItemState( RES_BOXATR_FORMULA
, false ))
2877 const SwTableBoxNumFormat
*pNumFormat
= GetFrameFormat()->GetItemIfSet( RES_BOXATR_FORMAT
, false );
2878 const SwTableBoxValue
*pValue
= GetFrameFormat()->GetItemIfSet( RES_BOXATR_VALUE
, false );
2880 SwNodeOffset nNdPos
;
2881 if( pNumFormat
&& pValue
&& NODE_OFFSET_MAX
!= ( nNdPos
= IsValidNumTextNd() ) )
2883 OUString sNewText
, sOldText( m_pStartNode
->GetNodes()[ nNdPos
]->
2884 GetTextNode()->GetRedlineText() );
2885 lcl_DelTabsAtSttEnd( sOldText
);
2887 const Color
* pCol
= nullptr;
2888 GetFrameFormat()->GetDoc()->GetNumberFormatter()->GetOutputString(
2889 pValue
->GetValue(), pNumFormat
->GetValue(), sNewText
, &pCol
);
2891 bRet
= sNewText
!= sOldText
||
2892 !( ( !pCol
&& !GetSaveNumFormatColor() ) ||
2893 ( pCol
&& GetSaveNumFormatColor() &&
2894 *pCol
== *GetSaveNumFormatColor() ));
2900 SwNodeOffset
SwTableBox::IsValidNumTextNd( bool bCheckAttr
) const
2902 SwNodeOffset nPos
= NODE_OFFSET_MAX
;
2905 SwNodeIndex
aIdx( *m_pStartNode
);
2906 SwNodeOffset nIndex
= aIdx
.GetIndex();
2907 const SwNodeOffset nIndexEnd
= m_pStartNode
->GetNodes()[ nIndex
]->EndOfSectionIndex();
2908 const SwTextNode
*pTextNode
= nullptr;
2909 while( ++nIndex
< nIndexEnd
)
2911 const SwNode
* pNode
= m_pStartNode
->GetNodes()[nIndex
];
2912 if( pNode
->IsTableNode() )
2914 pTextNode
= nullptr;
2917 if( pNode
->IsTextNode() )
2921 pTextNode
= nullptr;
2926 pTextNode
= pNode
->GetTextNode();
2935 const SwpHints
* pHts
= pTextNode
->GetpSwpHints();
2936 // do some tests if there's only text in the node!
2940 sal_Int32 nNextSetField
= 0;
2941 for( size_t n
= 0; n
< pHts
->Count(); ++n
)
2943 const SwTextAttr
* pAttr
= pHts
->Get(n
);
2944 if( RES_TXTATR_NOEND_BEGIN
<= pAttr
->Which() )
2946 if ( (pAttr
->GetStart() == nNextSetField
)
2947 && (pAttr
->Which() == RES_TXTATR_FIELD
))
2949 // #i104949# hideous hack for report builder:
2950 // it inserts hidden variable-set fields at
2951 // the beginning of para in cell, but they
2952 // should not turn cell into text cell
2953 const SwField
* pField
= pAttr
->GetFormatField().GetField();
2955 (pField
->GetTypeId() == SwFieldTypesEnum::Set
) &&
2956 (0 != (static_cast<SwSetExpField
const*>
2957 (pField
)->GetSubType() &
2958 nsSwExtendedSubType::SUB_INVISIBLE
)))
2960 nNextSetField
= pAttr
->GetStart() + 1;
2964 else if( RES_TXTATR_ANNOTATION
== pAttr
->Which() ||
2965 RES_TXTATR_FTN
== pAttr
->Which() )
2969 nPos
= NODE_OFFSET_MAX
;
2977 nPos
= NODE_OFFSET_MAX
;
2982 // is this a Formula box or one with numeric content (AutoSum)
2983 sal_uInt16
SwTableBox::IsFormulaOrValueBox() const
2985 sal_uInt16 nWhich
= 0;
2986 const SwTextNode
* pTNd
;
2987 SwFrameFormat
* pFormat
= GetFrameFormat();
2988 if( SfxItemState::SET
== pFormat
->GetItemState( RES_BOXATR_FORMULA
, false ))
2989 nWhich
= RES_BOXATR_FORMULA
;
2990 else if( SfxItemState::SET
== pFormat
->GetItemState( RES_BOXATR_VALUE
, false ) &&
2991 !pFormat
->GetDoc()->GetNumberFormatter()->IsTextFormat(
2992 pFormat
->GetTableBoxNumFormat().GetValue() ))
2993 nWhich
= RES_BOXATR_VALUE
;
2994 else if( m_pStartNode
&& m_pStartNode
->GetIndex() + 2 == m_pStartNode
->EndOfSectionIndex()
2995 && nullptr != ( pTNd
= m_pStartNode
->GetNodes()[ m_pStartNode
->GetIndex() + 1 ]
2996 ->GetTextNode() ) && pTNd
->GetText().isEmpty())
3002 void SwTableBox::ActualiseValueBox()
3004 SwFrameFormat
* pFormat
= GetFrameFormat();
3005 const SwTableBoxNumFormat
*pFormatItem
= pFormat
->GetItemIfSet( RES_BOXATR_FORMAT
, true );
3008 const SwTableBoxValue
*pValItem
= pFormat
->GetItemIfSet( RES_BOXATR_VALUE
);
3012 const sal_uLong nFormatId
= pFormatItem
->GetValue();
3013 SwNodeOffset nNdPos
= NODE_OFFSET_MAX
;
3014 SvNumberFormatter
* pNumFormatr
= pFormat
->GetDoc()->GetNumberFormatter();
3016 if( !pNumFormatr
->IsTextFormat( nFormatId
) &&
3017 NODE_OFFSET_MAX
!= (nNdPos
= IsValidNumTextNd()) )
3019 double fVal
= pValItem
->GetValue();
3020 const Color
* pCol
= nullptr;
3022 pNumFormatr
->GetOutputString( fVal
, nFormatId
, sNewText
, &pCol
);
3024 const OUString
& rText
= m_pStartNode
->GetNodes()[ nNdPos
]->GetTextNode()->GetText();
3025 if( rText
!= sNewText
)
3026 ChgTextToNum( *this, sNewText
, pCol
, false ,nNdPos
);
3030 SwRedlineTable::size_type
SwTableBox::GetRedline() const
3032 const SwRedlineTable
& aRedlineTable
= GetFrameFormat()->GetDoc()->getIDocumentRedlineAccess().GetRedlineTable();
3033 const SwStartNode
*pSttNd
= GetSttNd();
3035 if ( aRedlineTable
.empty() || !pSttNd
)
3036 return SwRedlineTable::npos
;
3038 // check table row property "HasTextChangesOnly", if it's defined and its value is
3039 // false, return with the first redline of the cell
3040 const SvxPrintItem
*pHasTextChangesOnlyProp
=
3041 GetFrameFormat()->GetAttrSet().GetItem
<SvxPrintItem
>(RES_PRINT
);
3042 if ( !pHasTextChangesOnlyProp
|| pHasTextChangesOnlyProp
->GetValue() )
3043 return SwRedlineTable::npos
;
3045 SwPosition
aCellStart( *GetSttNd(), SwNodeOffset(0) );
3046 SwPosition
aCellEnd( *GetSttNd()->EndOfSectionNode(), SwNodeOffset(-1) );
3047 SwNodeIndex
pEndNodeIndex(aCellEnd
.GetNode());
3048 SwRedlineTable::size_type nRedlinePos
= 0;
3049 for( ; nRedlinePos
< aRedlineTable
.size(); ++nRedlinePos
)
3051 const SwRangeRedline
* pRedline
= aRedlineTable
[ nRedlinePos
];
3053 if ( pRedline
->Start()->GetNodeIndex() > pEndNodeIndex
.GetIndex() )
3055 // no more redlines in the actual cell,
3056 // check the next ones
3060 // redline in the cell
3061 if ( aCellStart
<= *pRedline
->Start() )
3065 return SwRedlineTable::npos
;
3068 RedlineType
SwTableBox::GetRedlineType() const
3070 SwRedlineTable::size_type nPos
= GetRedline();
3071 if ( nPos
!= SwRedlineTable::npos
)
3073 const SwRedlineTable
& aRedlineTable
= GetFrameFormat()->GetDoc()->getIDocumentRedlineAccess().GetRedlineTable();
3074 const SwRangeRedline
* pRedline
= aRedlineTable
[ nPos
];
3075 if ( RedlineType::Delete
== pRedline
->GetType() ||
3076 RedlineType::Insert
== pRedline
->GetType() )
3078 return pRedline
->GetType();
3081 return RedlineType::None
;
3084 void SwTableBox::dumpAsXml(xmlTextWriterPtr pWriter
) const
3086 (void)xmlTextWriterStartElement(pWriter
, BAD_CAST("SwTableBox"));
3087 (void)xmlTextWriterWriteFormatAttribute(pWriter
, BAD_CAST("ptr"), "%p", this);
3088 (void)xmlTextWriterWriteAttribute(pWriter
, BAD_CAST("start-node"), BAD_CAST(OString::number(static_cast<sal_Int32
>(m_pStartNode
->GetIndex())).getStr()));
3089 (void)xmlTextWriterWriteAttribute(pWriter
, BAD_CAST("rowspan"), BAD_CAST(OString::number(mnRowSpan
).getStr()));
3090 GetFrameFormat()->dumpAsXml(pWriter
);
3091 (void)xmlTextWriterEndElement(pWriter
);
3094 struct SwTableCellInfo::Impl
3096 const SwTable
* m_pTable
;
3097 const SwCellFrame
* m_pCellFrame
;
3098 const SwTabFrame
* m_pTabFrame
;
3099 typedef o3tl::sorted_vector
<const SwTableBox
*> TableBoxes_t
;
3100 TableBoxes_t m_HandledTableBoxes
;
3104 : m_pTable(nullptr), m_pCellFrame(nullptr), m_pTabFrame(nullptr)
3108 void setTable(const SwTable
* pTable
)
3111 SwFrameFormat
* pFrameFormat
= m_pTable
->GetFrameFormat();
3112 m_pTabFrame
= SwIterator
<SwTabFrame
,SwFormat
>(*pFrameFormat
).First();
3113 if (m_pTabFrame
&& m_pTabFrame
->IsFollow())
3114 m_pTabFrame
= m_pTabFrame
->FindMaster(true);
3117 const SwCellFrame
* getCellFrame() const { return m_pCellFrame
; }
3119 const SwFrame
* getNextFrameInTable(const SwFrame
* pFrame
);
3120 const SwCellFrame
* getNextCellFrame(const SwFrame
* pFrame
);
3121 const SwCellFrame
* getNextTableBoxsCellFrame(const SwFrame
* pFrame
);
3125 const SwFrame
* SwTableCellInfo::Impl::getNextFrameInTable(const SwFrame
* pFrame
)
3127 const SwFrame
* pResult
= nullptr;
3129 if (((! pFrame
->IsTabFrame()) || pFrame
== m_pTabFrame
) && pFrame
->GetLower())
3130 pResult
= pFrame
->GetLower();
3131 else if (pFrame
->GetNext())
3132 pResult
= pFrame
->GetNext();
3135 while (pFrame
->GetUpper() != nullptr)
3137 pFrame
= pFrame
->GetUpper();
3139 if (pFrame
->IsTabFrame())
3141 m_pTabFrame
= static_cast<const SwTabFrame
*>(pFrame
)->GetFollow();
3142 pResult
= m_pTabFrame
;
3145 else if (pFrame
->GetNext())
3147 pResult
= pFrame
->GetNext();
3156 const SwCellFrame
* SwTableCellInfo::Impl::getNextCellFrame(const SwFrame
* pFrame
)
3158 const SwCellFrame
* pResult
= nullptr;
3160 while ((pFrame
= getNextFrameInTable(pFrame
)) != nullptr)
3162 if (pFrame
->IsCellFrame())
3164 pResult
= static_cast<const SwCellFrame
*>(pFrame
);
3172 const SwCellFrame
* SwTableCellInfo::Impl::getNextTableBoxsCellFrame(const SwFrame
* pFrame
)
3174 const SwCellFrame
* pResult
= nullptr;
3176 while ((pFrame
= getNextCellFrame(pFrame
)) != nullptr)
3178 const SwCellFrame
* pCellFrame
= static_cast<const SwCellFrame
*>(pFrame
);
3179 const SwTableBox
* pTabBox
= pCellFrame
->GetTabBox();
3180 auto aIt
= m_HandledTableBoxes
.insert(pTabBox
);
3183 pResult
= pCellFrame
;
3191 const SwCellFrame
* SwTableCellInfo::getCellFrame() const
3193 return m_pImpl
->getCellFrame();
3196 bool SwTableCellInfo::Impl::getNext()
3198 if (m_pCellFrame
== nullptr)
3200 if (m_pTabFrame
!= nullptr)
3201 m_pCellFrame
= Impl::getNextTableBoxsCellFrame(m_pTabFrame
);
3204 m_pCellFrame
= Impl::getNextTableBoxsCellFrame(m_pCellFrame
);
3206 return m_pCellFrame
!= nullptr;
3209 SwTableCellInfo::SwTableCellInfo(const SwTable
* pTable
)
3210 : m_pImpl(std::make_unique
<Impl
>())
3212 m_pImpl
->setTable(pTable
);
3215 SwTableCellInfo::~SwTableCellInfo()
3219 bool SwTableCellInfo::getNext()
3221 return m_pImpl
->getNext();
3224 SwRect
SwTableCellInfo::getRect() const
3228 if (getCellFrame() != nullptr)
3229 aRet
= getCellFrame()->getFrameArea();
3234 const SwTableBox
* SwTableCellInfo::getTableBox() const
3236 const SwTableBox
* pRet
= nullptr;
3238 if (getCellFrame() != nullptr)
3239 pRet
= getCellFrame()->GetTabBox();
3244 void SwTable::RegisterToFormat( SwFormat
& rFormat
)
3249 bool SwTable::HasLayout() const
3251 const SwFrameFormat
* pFrameFormat
= GetFrameFormat();
3252 //a table in a clipboard document doesn't have any layout information
3253 return pFrameFormat
&& SwIterator
<SwTabFrame
,SwFormat
>(*pFrameFormat
).First();
3256 void SwTableBox::RegisterToFormat( SwFormat
& rFormat
)
3261 // free's any remaining child objects
3262 SwTableLines::~SwTableLines()
3264 for ( const_iterator it
= begin(); it
!= end(); ++it
)
3268 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */