LibreOffice Module sw (master) 1
swtable.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <hintids.hxx>
21#include <hints.hxx>
22#include <editeng/lrspitem.hxx>
23#include <editeng/shaditem.hxx>
25#include <editeng/colritem.hxx>
26#include <osl/diagnose.h>
27#include <sfx2/linkmgr.hxx>
28#include <fmtfsize.hxx>
29#include <fmtornt.hxx>
30#include <fmtpdsc.hxx>
31#include <fldbas.hxx>
32#include <fmtfld.hxx>
33#include <frmatr.hxx>
34#include <doc.hxx>
38#include <docary.hxx>
39#include <frame.hxx>
40#include <swtable.hxx>
41#include <ndtxt.hxx>
42#include <tabcol.hxx>
43#include <tabfrm.hxx>
44#include <cellfrm.hxx>
45#include <rowfrm.hxx>
46#include <swserv.hxx>
47#include <expfld.hxx>
48#include <mdiexp.hxx>
49#include <cellatr.hxx>
50#include <txatbase.hxx>
51#include <htmltbl.hxx>
52#include <swtblfmt.hxx>
53#include <ndindex.hxx>
54#include <tblrwcl.hxx>
55#include <shellres.hxx>
56#include <viewsh.hxx>
57#include <redline.hxx>
58#include <vector>
59#include <calbck.hxx>
60#include <o3tl/string_view.hxx>
61#include <svl/numformat.hxx>
62
63#ifdef DBG_UTIL
64#define CHECK_TABLE(t) (t).CheckConsistency();
65#else
66#define CHECK_TABLE(t)
67#endif
68
69using namespace com::sun::star;
70
71
72#define COLFUZZY 20
73
74static void ChgTextToNum( SwTableBox& rBox, const OUString& rText, const Color* pCol,
75 bool bChgAlign, SwNodeOffset nNdPos );
76
77void SwTableBox::setRowSpan( sal_Int32 nNewRowSpan )
78{
79 mnRowSpan = nNewRowSpan;
80}
81
83{
84 return mbDummyFlag;
85}
86
87void SwTableBox::setDummyFlag( bool bDummy )
88{
89 mbDummyFlag = bDummy;
90}
91
92//JP 15.09.98: Bug 55741 - Keep tabs (front and rear)
93static OUString& lcl_TabToBlankAtSttEnd( OUString& rText )
94{
96 sal_Int32 n;
97
98 for( n = 0; n < rText.getLength() && ' ' >= ( c = rText[n] ); ++n )
99 if( '\x9' == c )
100 rText = rText.replaceAt( n, 1, u" " );
101 for( n = rText.getLength(); n && ' ' >= ( c = rText[--n] ); )
102 if( '\x9' == c )
103 rText = rText.replaceAt( n, 1, u" " );
104 return rText;
105}
106
107static OUString& lcl_DelTabsAtSttEnd( OUString& rText )
108{
109 sal_Unicode c;
110 sal_Int32 n;
111 OUStringBuffer sBuff(rText);
112
113 for( n = 0; n < sBuff.getLength() && ' ' >= ( c = sBuff[ n ]); ++n )
114 {
115 if( '\x9' == c )
116 sBuff.remove( n--, 1 );
117 }
118 for( n = sBuff.getLength(); n && ' ' >= ( c = sBuff[ --n ]); )
119 {
120 if( '\x9' == c )
121 sBuff.remove( n, 1 );
122 }
123 rText = sBuff.makeStringAndClear();
124 return rText;
125}
126
127void InsTableBox( SwDoc& rDoc, SwTableNode* pTableNd,
128 SwTableLine* pLine, SwTableBoxFormat* pBoxFrameFormat,
129 SwTableBox* pBox,
130 sal_uInt16 nInsPos, sal_uInt16 nCnt )
131{
132 OSL_ENSURE( pBox->GetSttNd(), "Box with no start node" );
133 SwNodeIndex aIdx( *pBox->GetSttNd(), +1 );
134 SwContentNode* pCNd = aIdx.GetNode().GetContentNode();
135 if( !pCNd )
136 pCNd = rDoc.GetNodes().GoNext( &aIdx );
137 OSL_ENSURE( pCNd, "Box with no content node" );
138
139 if( pCNd->IsTextNode() )
140 {
141 if( pCNd->GetpSwAttrSet() )
142 {
143 SwAttrSet aAttrSet( *pCNd->GetpSwAttrSet() );
145 {
147 const std::shared_ptr<SfxItemSet>& handle = format.GetStyleHandle();
148 aAttrSet.Put(*handle);
149 }
150 if( pBox->GetSaveNumFormatColor() )
151 {
152 if( pBox->GetSaveUserColor() )
153 aAttrSet.Put( SvxColorItem( *pBox->GetSaveUserColor(), RES_CHRATR_COLOR ));
154 else
155 aAttrSet.ClearItem( RES_CHRATR_COLOR );
156 }
157 rDoc.GetNodes().InsBoxen( pTableNd, pLine, pBoxFrameFormat,
158 static_cast<SwTextNode*>(pCNd)->GetTextColl(),
159 &aAttrSet, nInsPos, nCnt );
160 }
161 else
162 rDoc.GetNodes().InsBoxen( pTableNd, pLine, pBoxFrameFormat,
163 static_cast<SwTextNode*>(pCNd)->GetTextColl(),
164 pCNd->GetpSwAttrSet(), nInsPos, nCnt );
165 }
166 else
167 rDoc.GetNodes().InsBoxen( pTableNd, pLine, pBoxFrameFormat,
168 rDoc.GetDfltTextFormatColl(), nullptr,
169 nInsPos, nCnt );
170
171 sal_Int32 nRowSpan = pBox->getRowSpan();
172 if( nRowSpan != 1 )
173 {
174 SwTableBoxes& rTableBoxes = pLine->GetTabBoxes();
175 for( sal_uInt16 i = 0; i < nCnt; ++i )
176 {
177 pBox = rTableBoxes[ i + nInsPos ];
178 pBox->setRowSpan( nRowSpan );
179 }
180 }
181}
182
184 : SwClient( nullptr ),
185 m_pTableNode( nullptr ),
186 m_nGraphicsThatResize( 0 ),
187 m_nRowsToRepeat( 1 ),
188 m_bModifyLocked( false ),
189 m_bNewModel( true )
190{
191 // default value set in the options
193}
194
195SwTable::SwTable( const SwTable& rTable )
196 : SwClient( rTable.GetFrameFormat() ),
197 m_pTableNode( nullptr ),
198 m_eTableChgMode( rTable.m_eTableChgMode ),
199 m_nGraphicsThatResize( 0 ),
200 m_nRowsToRepeat( rTable.GetRowsToRepeat() ),
201 maTableStyleName(rTable.maTableStyleName),
202 m_bModifyLocked( false ),
203 m_bNewModel( rTable.m_bNewModel )
204{
205}
206
207void DelBoxNode( SwTableSortBoxes const & rSortCntBoxes )
208{
209 for (size_t n = 0; n < rSortCntBoxes.size(); ++n)
210 {
211 rSortCntBoxes[ n ]->m_pStartNode = nullptr;
212 }
213}
214
216{
217 if( m_xRefObj.is() )
218 {
219 SwDoc* pDoc = GetFrameFormat()->GetDoc();
220 if( !pDoc->IsInDtor() ) // then remove from the list
222
223 m_xRefObj->Closed();
224 }
225
226 // the table can be deleted if it's the last client of the FrameFormat
227 SwTableFormat* pFormat = GetFrameFormat();
228 pFormat->Remove( this ); // remove
229
230 if( !pFormat->HasWriterListeners() )
231 pFormat->GetDoc()->DelTableFrameFormat( pFormat ); // and delete
232
233 // Delete the pointers from the SortArray of the boxes. The objects
234 // are preserved and are deleted by the lines/boxes arrays dtor.
235 // Note: unfortunately not enough, pointers to the StartNode of the
236 // section need deletion.
239}
240
241namespace
242{
243
244template<class T>
245T lcl_MulDiv64(sal_uInt64 nA, sal_uInt64 nM, sal_uInt64 nD)
246{
247 assert(nD != 0);
248 return nD == 0 ? static_cast<T>(nA*nM) : static_cast<T>((nA*nM)/nD);
249}
250
251}
252
253static void FormatInArr( std::vector<SwFormat*>& rFormatArr, SwFormat* pBoxFormat )
254{
255 std::vector<SwFormat*>::const_iterator it = std::find( rFormatArr.begin(), rFormatArr.end(), pBoxFormat );
256 if ( it == rFormatArr.end() )
257 rFormatArr.push_back( pBoxFormat );
258}
259
260static void lcl_ModifyBoxes( SwTableBoxes &rBoxes, const tools::Long nOld,
261 const tools::Long nNew, std::vector<SwFormat*>& rFormatArr );
262
263static void lcl_ModifyLines( SwTableLines &rLines, const tools::Long nOld,
264 const tools::Long nNew, std::vector<SwFormat*>& rFormatArr, const bool bCheckSum )
265{
266 for ( size_t i = 0; i < rLines.size(); ++i )
267 ::lcl_ModifyBoxes( rLines[i]->GetTabBoxes(), nOld, nNew, rFormatArr );
268 if( bCheckSum )
269 {
270 for(SwFormat* pFormat : rFormatArr)
271 {
272 const SwTwips nBox = lcl_MulDiv64<SwTwips>(pFormat->GetFrameSize().GetWidth(), nNew, nOld);
273 SwFormatFrameSize aNewBox( SwFrameSize::Variable, nBox, 0 );
274 pFormat->LockModify();
275 pFormat->SetFormatAttr( aNewBox );
276 pFormat->UnlockModify();
277 }
278 }
279}
280
281static void lcl_ModifyBoxes( SwTableBoxes &rBoxes, const tools::Long nOld,
282 const tools::Long nNew, std::vector<SwFormat*>& rFormatArr )
283{
284 sal_uInt64 nSum = 0; // To avoid rounding errors we summarize all box widths
285 sal_uInt64 nOriginalSum = 0; // Sum of original widths
286 for ( size_t i = 0; i < rBoxes.size(); ++i )
287 {
288 SwTableBox &rBox = *rBoxes[i];
289 if ( !rBox.GetTabLines().empty() )
290 {
291 // For SubTables the rounding problem will not be solved :-(
292 ::lcl_ModifyLines( rBox.GetTabLines(), nOld, nNew, rFormatArr, false );
293 }
294 // Adjust the box
295 SwFrameFormat *pFormat = rBox.GetFrameFormat();
296 sal_uInt64 nBox = pFormat->GetFrameSize().GetWidth();
297 nOriginalSum += nBox;
298 nBox = lcl_MulDiv64<sal_uInt64>(nBox, nNew, nOld);
299 const sal_uInt64 nWishedSum = lcl_MulDiv64<sal_uInt64>(nOriginalSum, nNew, nOld) - nSum;
300 if( nWishedSum > 0 )
301 {
302 if( nBox == nWishedSum )
303 FormatInArr( rFormatArr, pFormat );
304 else
305 {
306 nBox = nWishedSum;
307 pFormat = rBox.ClaimFrameFormat();
308 SwFormatFrameSize aNewBox( SwFrameSize::Variable, static_cast< SwTwips >(nBox), 0 );
309 pFormat->LockModify();
310 pFormat->SetFormatAttr( aNewBox );
311 pFormat->UnlockModify();
312 }
313 }
314 else {
315 OSL_FAIL( "Rounding error" );
316 }
317 nSum += nBox;
318 }
319}
320
321void SwTable::SwClientNotify(const SwModify&, const SfxHint& rHint)
322{
323 if (rHint.GetId() != SfxHintId::SwLegacyModify)
324 return;
325 auto pLegacy = static_cast<const sw::LegacyModifyHint*>(&rHint);
326 // catch SSize changes, to adjust the lines/boxes
327 const sal_uInt16 nWhich = pLegacy->GetWhich();
328 const SwFormatFrameSize* pNewSize = nullptr, *pOldSize = nullptr;
329 switch(nWhich)
330 {
331 case RES_ATTRSET_CHG:
332 {
333 if (pLegacy->m_pOld && pLegacy->m_pNew
334 && (pNewSize = static_cast<const SwAttrSetChg*>(pLegacy->m_pNew)->GetChgSet()->GetItemIfSet(
336 false)))
337 {
338 pOldSize = &static_cast<const SwAttrSetChg*>(pLegacy->m_pOld)->GetChgSet()->GetFrameSize();
339 }
340 }
341 break;
342 case RES_FRM_SIZE:
343 {
344 pOldSize = static_cast<const SwFormatFrameSize*>(pLegacy->m_pOld);
345 pNewSize = static_cast<const SwFormatFrameSize*>(pLegacy->m_pNew);
346 }
347 break;
348 default:
349 CheckRegistration(pLegacy->m_pOld);
350 }
351 if (pOldSize && pNewSize && !m_bModifyLocked)
352 AdjustWidths(pOldSize->GetWidth(), pNewSize->GetWidth());
353}
354
355void SwTable::AdjustWidths( const tools::Long nOld, const tools::Long nNew )
356{
357 std::vector<SwFormat*> aFormatArr;
358 aFormatArr.reserve( m_aLines[0]->GetTabBoxes().size() );
359 ::lcl_ModifyLines( m_aLines, nOld, nNew, aFormatArr, true );
360}
361
362static void lcl_RefreshHidden( SwTabCols &rToFill, size_t nPos )
363{
364 for ( size_t i = 0; i < rToFill.Count(); ++i )
365 {
366 if ( std::abs(static_cast<tools::Long>(nPos) - rToFill[i]) <= COLFUZZY )
367 {
368 rToFill.SetHidden( i, false );
369 break;
370 }
371 }
372}
373
374static void lcl_SortedTabColInsert( SwTabCols &rToFill, const SwTableBox *pBox,
375 const SwFrameFormat *pTabFormat, const bool bHidden,
376 const bool bRefreshHidden )
377{
378 const tools::Long nWish = pTabFormat->GetFrameSize().GetWidth();
379 OSL_ENSURE(nWish, "weird <= 0 width frmfrm");
380
381 // The value for the left edge of the box is calculated from the
382 // widths of the previous boxes.
383 tools::Long nPos = 0;
384 tools::Long nLeftMin = 0;
385 tools::Long nRightMax = 0;
386 if (nWish != 0) //fdo#33012 0 width frmfmt
387 {
388 SwTwips nSum = 0;
389 const SwTableBox *pCur = pBox;
390 const SwTableLine *pLine = pBox->GetUpper();
391 const tools::Long nAct = rToFill.GetRight() - rToFill.GetLeft(); // +1 why?
392
393 while ( pLine )
394 {
395 const SwTableBoxes &rBoxes = pLine->GetTabBoxes();
396 for ( size_t i = 0; i < rBoxes.size(); ++i )
397 {
398 const SwTwips nWidth = rBoxes[i]->GetFrameFormat()->GetFrameSize().GetWidth();
399 nSum += nWidth;
400 const tools::Long nTmp = lcl_MulDiv64<tools::Long>(nSum, nAct, nWish);
401
402 if (rBoxes[i] != pCur)
403 {
404 if ( pLine == pBox->GetUpper() || 0 == nLeftMin )
405 nLeftMin = nTmp - nPos;
406 nPos = nTmp;
407 }
408 else
409 {
410 nSum -= nWidth;
411 if ( 0 == nRightMax )
412 nRightMax = nTmp - nPos;
413 break;
414 }
415 }
416 pCur = pLine->GetUpper();
417 pLine = pCur ? pCur->GetUpper() : nullptr;
418 }
419 }
420
421 bool bInsert = !bRefreshHidden;
422 for ( size_t j = 0; bInsert && (j < rToFill.Count()); ++j )
423 {
424 tools::Long nCmp = rToFill[j];
425 if ( (nPos >= ((nCmp >= COLFUZZY) ? nCmp - COLFUZZY : nCmp)) &&
426 (nPos <= (nCmp + COLFUZZY)) )
427 {
428 bInsert = false; // Already has it.
429 }
430 else if ( nPos < nCmp )
431 {
432 bInsert = false;
433 rToFill.Insert( nPos, bHidden, j );
434 }
435 }
436 if ( bInsert )
437 rToFill.Insert( nPos, bHidden, rToFill.Count() );
438 else if ( bRefreshHidden )
439 ::lcl_RefreshHidden( rToFill, nPos );
440
441 if ( !bHidden || bRefreshHidden )
442 return;
443
444 // calculate minimum/maximum values for the existing entries:
445 nLeftMin = nPos - nLeftMin;
446 nRightMax = nPos + nRightMax;
447
448 // check if nPos is entry:
449 bool bFoundPos = false;
450 bool bFoundMax = false;
451 for ( size_t j = 0; !(bFoundPos && bFoundMax ) && j < rToFill.Count(); ++j )
452 {
453 SwTabColsEntry& rEntry = rToFill.GetEntry( j );
454 tools::Long nCmp = rToFill[j];
455
456 if ( (nPos >= ((nCmp >= COLFUZZY) ? nCmp - COLFUZZY : nCmp)) &&
457 (nPos <= (nCmp + COLFUZZY)) )
458 {
459 // check if nLeftMin is > old minimum for entry nPos:
460 const tools::Long nOldMin = rEntry.nMin;
461 if ( nLeftMin > nOldMin )
462 rEntry.nMin = nLeftMin;
463 // check if nRightMin is < old maximum for entry nPos:
464 const tools::Long nOldMax = rEntry.nMax;
465 if ( nRightMax < nOldMax )
466 rEntry.nMax = nRightMax;
467
468 bFoundPos = true;
469 }
470 else if ( (nRightMax >= ((nCmp >= COLFUZZY) ? nCmp - COLFUZZY : nCmp)) &&
471 (nRightMax <= (nCmp + COLFUZZY)) )
472 {
473 // check if nPos is > old minimum for entry nRightMax:
474 const tools::Long nOldMin = rEntry.nMin;
475 if ( nPos > nOldMin )
476 rEntry.nMin = nPos;
477
478 bFoundMax = true;
479 }
480 }
481}
482
483static void lcl_ProcessBoxGet( const SwTableBox *pBox, SwTabCols &rToFill,
484 const SwFrameFormat *pTabFormat, bool bRefreshHidden )
485{
486 if ( !pBox->GetTabLines().empty() )
487 {
488 const SwTableLines &rLines = pBox->GetTabLines();
489 for ( size_t i = 0; i < rLines.size(); ++i )
490 {
491 const SwTableBoxes &rBoxes = rLines[i]->GetTabBoxes();
492 for ( size_t j = 0; j < rBoxes.size(); ++j )
493 ::lcl_ProcessBoxGet( rBoxes[j], rToFill, pTabFormat, bRefreshHidden);
494 }
495 }
496 else
497 ::lcl_SortedTabColInsert( rToFill, pBox, pTabFormat, false, bRefreshHidden );
498}
499
500static void lcl_ProcessLineGet( const SwTableLine *pLine, SwTabCols &rToFill,
501 const SwFrameFormat *pTabFormat )
502{
503 for ( size_t i = 0; i < pLine->GetTabBoxes().size(); ++i )
504 {
505 const SwTableBox *pBox = pLine->GetTabBoxes()[i];
506 if ( pBox->GetSttNd() )
507 ::lcl_SortedTabColInsert( rToFill, pBox, pTabFormat, true, false );
508 else
509 for ( size_t j = 0; j < pBox->GetTabLines().size(); ++j )
510 ::lcl_ProcessLineGet( pBox->GetTabLines()[j], rToFill, pTabFormat );
511 }
512}
513
514void SwTable::GetTabCols( SwTabCols &rToFill, const SwTableBox *pStart,
515 bool bRefreshHidden, bool bCurRowOnly ) const
516{
517 // Optimization: if bHidden is set, we only update the Hidden Array.
518 if ( bRefreshHidden )
519 {
520 // remove corrections
521 for ( size_t i = 0; i < rToFill.Count(); ++i )
522 {
523 SwTabColsEntry& rEntry = rToFill.GetEntry( i );
524 rEntry.nPos -= rToFill.GetLeft();
525 rEntry.nMin -= rToFill.GetLeft();
526 rEntry.nMax -= rToFill.GetLeft();
527 }
528
529 // All are hidden, so add the visible ones.
530 for ( size_t i = 0; i < rToFill.Count(); ++i )
531 rToFill.SetHidden( i, true );
532 }
533 else
534 {
535 rToFill.Remove( 0, rToFill.Count() );
536 }
537
538 // Insertion cases:
539 // 1. All boxes which are inferior to Line which is superior to the Start,
540 // as well as their inferior boxes if present.
541 // 2. Starting from the Line, the superior box plus its neighbours; but no inferiors.
542 // 3. Apply 2. to the Line superior to the chain of boxes,
543 // until the Line's superior is not a box but the table.
544 // Only those boxes are inserted that don't contain further rows. The insertion
545 // function takes care to avoid duplicates. In order to achieve this, we work
546 // with some degree of fuzzyness (to avoid rounding errors).
547 // Only the left edge of the boxes are inserted.
548 // Finally, the first entry is removed again, because it's already
549 // covered by the border.
550 // 4. Scan the table again and insert _all_ boxes, this time as hidden.
551
552 const SwFrameFormat *pTabFormat = GetFrameFormat();
553
554 // 1.
555 const SwTableBoxes &rBoxes = pStart->GetUpper()->GetTabBoxes();
556
557 for ( size_t i = 0; i < rBoxes.size(); ++i )
558 ::lcl_ProcessBoxGet( rBoxes[i], rToFill, pTabFormat, bRefreshHidden );
559
560 // 2. and 3.
561 const SwTableLine *pLine = pStart->GetUpper()->GetUpper() ?
562 pStart->GetUpper()->GetUpper()->GetUpper() : nullptr;
563 while ( pLine )
564 {
565 const SwTableBoxes &rBoxes2 = pLine->GetTabBoxes();
566 for ( size_t k = 0; k < rBoxes2.size(); ++k )
567 ::lcl_SortedTabColInsert( rToFill, rBoxes2[k],
568 pTabFormat, false, bRefreshHidden );
569 pLine = pLine->GetUpper() ? pLine->GetUpper()->GetUpper() : nullptr;
570 }
571
572 if ( !bRefreshHidden )
573 {
574 // 4.
575 if ( !bCurRowOnly )
576 {
577 for ( size_t i = 0; i < m_aLines.size(); ++i )
578 ::lcl_ProcessLineGet( m_aLines[i], rToFill, pTabFormat );
579 }
580
581 rToFill.Remove( 0 );
582 }
583
584 // Now the coordinates are relative to the left table border - i.e.
585 // relative to SwTabCols.nLeft. However, they are expected
586 // relative to the left document border, i.e. SwTabCols.nLeftMin.
587 // So all values need to be extended by nLeft.
588 for ( size_t i = 0; i < rToFill.Count(); ++i )
589 {
590 SwTabColsEntry& rEntry = rToFill.GetEntry( i );
591 rEntry.nPos += rToFill.GetLeft();
592 rEntry.nMin += rToFill.GetLeft();
593 rEntry.nMax += rToFill.GetLeft();
594 }
595}
596
597// Structure for parameter passing
598struct Parm
599{
604 std::deque<SwTableBox*> aBoxArr;
606
607 Parm( const SwTabCols &rN, const SwTabCols &rO )
608 : rNew( rN ), rOld( rO ), nNewWish(0), nOldWish(0)
609 {}
610};
611
612static void lcl_ProcessBoxSet( SwTableBox *pBox, Parm &rParm );
613
614static void lcl_ProcessLine( SwTableLine *pLine, Parm &rParm )
615{
616 SwTableBoxes &rBoxes = pLine->GetTabBoxes();
617 for ( size_t i = rBoxes.size(); i > 0; )
618 {
619 --i;
620 ::lcl_ProcessBoxSet( rBoxes[i], rParm );
621 }
622}
623
624static void lcl_ProcessBoxSet( SwTableBox *pBox, Parm &rParm )
625{
626 if ( !pBox->GetTabLines().empty() )
627 {
628 SwTableLines &rLines = pBox->GetTabLines();
629 for ( size_t i = rLines.size(); i > 0; )
630 {
631 --i;
632 lcl_ProcessLine( rLines[i], rParm );
633 }
634 }
635 else
636 {
637 // Search the old TabCols for the current position (calculate from
638 // left and right edge). Adjust the box if the values differ from
639 // the new TabCols. If the adjusted edge has no neighbour we also
640 // adjust all superior boxes.
641
642 const tools::Long nOldAct = rParm.rOld.GetRight() -
643 rParm.rOld.GetLeft(); // +1 why?
644
645 // The value for the left edge of the box is calculated from the
646 // widths of the previous boxes plus the left edge.
647 tools::Long nLeft = rParm.rOld.GetLeft();
648 const SwTableBox *pCur = pBox;
649 const SwTableLine *pLine = pBox->GetUpper();
650
651 while ( pLine )
652 {
653 const SwTableBoxes &rBoxes = pLine->GetTabBoxes();
654 for ( size_t i = 0; (i < rBoxes.size()) && (rBoxes[i] != pCur); ++i)
655 {
656 nLeft += lcl_MulDiv64<tools::Long>(
657 rBoxes[i]->GetFrameFormat()->GetFrameSize().GetWidth(),
658 nOldAct, rParm.nOldWish);
659 }
660 pCur = pLine->GetUpper();
661 pLine = pCur ? pCur->GetUpper() : nullptr;
662 }
663 tools::Long nLeftDiff = 0;
664 tools::Long nRightDiff = 0;
665 if ( nLeft != rParm.rOld.GetLeft() ) // There are still boxes before this.
666 {
667 // Right edge is left edge plus width.
668 const tools::Long nWidth = lcl_MulDiv64<tools::Long>(
670 nOldAct, rParm.nOldWish);
671 const tools::Long nRight = nLeft + nWidth;
672 size_t nLeftPos = 0;
673 size_t nRightPos = 0;
674 bool bFoundLeftPos = false;
675 bool bFoundRightPos = false;
676 for ( size_t i = 0; i < rParm.rOld.Count(); ++i )
677 {
678 if ( nLeft >= (rParm.rOld[i] - COLFUZZY) &&
679 nLeft <= (rParm.rOld[i] + COLFUZZY) )
680 {
681 nLeftPos = i;
682 bFoundLeftPos = true;
683 }
684 else if ( nRight >= (rParm.rOld[i] - COLFUZZY) &&
685 nRight <= (rParm.rOld[i] + COLFUZZY) )
686 {
687 nRightPos = i;
688 bFoundRightPos = true;
689 }
690 }
691 nLeftDiff = bFoundLeftPos ?
692 rParm.rOld[nLeftPos] - rParm.rNew[nLeftPos] : 0;
693 nRightDiff= bFoundRightPos ?
694 rParm.rNew[nRightPos] - rParm.rOld[nRightPos] : 0;
695 }
696 else // The first box.
697 {
698 nLeftDiff = rParm.rOld.GetLeft() - rParm.rNew.GetLeft();
699 if ( rParm.rOld.Count() )
700 {
701 // Calculate the difference to the edge touching the first box.
702 const tools::Long nWidth = lcl_MulDiv64<tools::Long>(
704 nOldAct, rParm.nOldWish);
705 const tools::Long nTmp = nWidth + rParm.rOld.GetLeft();
706 for ( size_t i = 0; i < rParm.rOld.Count(); ++i )
707 {
708 if ( nTmp >= (rParm.rOld[i] - COLFUZZY) &&
709 nTmp <= (rParm.rOld[i] + COLFUZZY) )
710 {
711 nRightDiff = rParm.rNew[i] - rParm.rOld[i];
712 break;
713 }
714 }
715 }
716 }
717
718 if( pBox->getRowSpan() == 1 )
719 {
720 const sal_uInt16 nPos = pBox->GetUpper()->GetBoxPos( pBox );
721 SwTableBoxes& rTableBoxes = pBox->GetUpper()->GetTabBoxes();
722 if( nPos && rTableBoxes[ nPos - 1 ]->getRowSpan() != 1 )
723 nLeftDiff = 0;
724 if( nPos + 1 < o3tl::narrowing<sal_uInt16>(rTableBoxes.size()) &&
725 rTableBoxes[ nPos + 1 ]->getRowSpan() != 1 )
726 nRightDiff = 0;
727 }
728 else
729 nLeftDiff = nRightDiff = 0;
730
731 if ( nLeftDiff || nRightDiff )
732 {
733 // The difference is the actual difference amount. For stretched
734 // tables, it does not make sense to adjust the attributes of the
735 // boxes by this amount. The difference amount needs to be converted
736 // accordingly.
737 tools::Long nTmp = rParm.rNew.GetRight() - rParm.rNew.GetLeft(); // +1 why?
738 nLeftDiff *= rParm.nNewWish;
739 nLeftDiff /= nTmp;
740 nRightDiff *= rParm.nNewWish;
741 nRightDiff /= nTmp;
742 tools::Long nDiff = nLeftDiff + nRightDiff;
743
744 // Adjust the box and all superiors by the difference amount.
745 while ( pBox )
746 {
747 SwFormatFrameSize aFormatFrameSize( pBox->GetFrameFormat()->GetFrameSize() );
748 aFormatFrameSize.SetWidth( aFormatFrameSize.GetWidth() + nDiff );
749 if ( aFormatFrameSize.GetWidth() < 0 )
750 aFormatFrameSize.SetWidth( -aFormatFrameSize.GetWidth() );
751 rParm.aShareFormats.SetSize( *pBox, aFormatFrameSize );
752
753 // The outer cells of the last row are responsible to adjust a surrounding cell.
754 // Last line check:
755 if ( pBox->GetUpper()->GetUpper() &&
756 pBox->GetUpper() != pBox->GetUpper()->GetUpper()->GetTabLines().back())
757 {
758 pBox = nullptr;
759 }
760 else
761 {
762 // Middle cell check:
763 if ( pBox != pBox->GetUpper()->GetTabBoxes().front() )
764 nDiff = nRightDiff;
765
766 if ( pBox != pBox->GetUpper()->GetTabBoxes().back() )
767 nDiff -= nRightDiff;
768
769 pBox = nDiff ? pBox->GetUpper()->GetUpper() : nullptr;
770 }
771 }
772 }
773 }
774}
775
776static void lcl_ProcessBoxPtr( SwTableBox *pBox, std::deque<SwTableBox*> &rBoxArr,
777 bool bBefore )
778{
779 if ( !pBox->GetTabLines().empty() )
780 {
781 const SwTableLines &rLines = pBox->GetTabLines();
782 for ( size_t i = 0; i < rLines.size(); ++i )
783 {
784 const SwTableBoxes &rBoxes = rLines[i]->GetTabBoxes();
785 for ( size_t j = 0; j < rBoxes.size(); ++j )
786 ::lcl_ProcessBoxPtr( rBoxes[j], rBoxArr, bBefore );
787 }
788 }
789 else if ( bBefore )
790 rBoxArr.push_front( pBox );
791 else
792 rBoxArr.push_back( pBox );
793}
794
795static void lcl_AdjustBox( SwTableBox *pBox, const tools::Long nDiff, Parm &rParm );
796
797static void lcl_AdjustLines( SwTableLines &rLines, const tools::Long nDiff, Parm &rParm )
798{
799 for ( size_t i = 0; i < rLines.size(); ++i )
800 {
801 SwTableBox *pBox = rLines[i]->GetTabBoxes()
802 [rLines[i]->GetTabBoxes().size()-1];
803 lcl_AdjustBox( pBox, nDiff, rParm );
804 }
805}
806
807static void lcl_AdjustBox( SwTableBox *pBox, const tools::Long nDiff, Parm &rParm )
808{
809 if ( !pBox->GetTabLines().empty() )
810 ::lcl_AdjustLines( pBox->GetTabLines(), nDiff, rParm );
811
812 // Adjust the size of the box.
813 SwFormatFrameSize aFormatFrameSize( pBox->GetFrameFormat()->GetFrameSize() );
814 aFormatFrameSize.SetWidth( aFormatFrameSize.GetWidth() + nDiff );
815
816 rParm.aShareFormats.SetSize( *pBox, aFormatFrameSize );
817}
818
819void SwTable::SetTabCols( const SwTabCols &rNew, const SwTabCols &rOld,
820 const SwTableBox *pStart, bool bCurRowOnly )
821{
822 CHECK_TABLE( *this )
823
824 SetHTMLTableLayout(std::shared_ptr<SwHTMLTableLayout>()); // delete HTML-Layout
825
826 // FME: Made rOld const. The caller is responsible for passing correct
827 // values of rOld. Therefore we do not have to call GetTabCols anymore:
828 //GetTabCols( rOld, pStart );
829
830 Parm aParm( rNew, rOld );
831
832 OSL_ENSURE( rOld.Count() == rNew.Count(), "Number of columns changed.");
833
834 // Convert the edges. We need to adjust the size of the table and some boxes.
835 // For the size adjustment, we must not make use of the Modify, since that'd
836 // adjust all boxes, which we really don't want.
837 SwFrameFormat *pFormat = GetFrameFormat();
838 aParm.nOldWish = aParm.nNewWish = pFormat->GetFrameSize().GetWidth();
839 if ( (rOld.GetLeft() != rNew.GetLeft()) ||
840 (rOld.GetRight()!= rNew.GetRight()) )
841 {
842 LockModify();
843 {
844 SvxLRSpaceItem aLR( pFormat->GetLRSpace() );
845 SvxShadowItem aSh( pFormat->GetShadow() );
846
847 SwTwips nShRight = aSh.CalcShadowSpace( SvxShadowItemSide::RIGHT );
848 SwTwips nShLeft = aSh.CalcShadowSpace( SvxShadowItemSide::LEFT );
849
850 aLR.SetLeft ( rNew.GetLeft() - nShLeft );
851 aLR.SetRight( rNew.GetRightMax() - rNew.GetRight() - nShRight );
852 pFormat->SetFormatAttr( aLR );
853
854 // The alignment of the table needs to be adjusted accordingly.
855 // This is done by preserving the exact positions that have been
856 // set by the user.
857 SwFormatHoriOrient aOri( pFormat->GetHoriOrient() );
859 text::HoriOrientation::CENTER != aOri.GetHoriOrient() )
860 {
861 const bool bLeftDist = rNew.GetLeft() != nShLeft;
862 const bool bRightDist = rNew.GetRight() + nShRight != rNew.GetRightMax();
863 if(!bLeftDist && !bRightDist)
864 aOri.SetHoriOrient( text::HoriOrientation::FULL );
865 else if(!bRightDist && rNew.GetLeft() > nShLeft )
866 aOri.SetHoriOrient( text::HoriOrientation::RIGHT );
867 else if(!bLeftDist && rNew.GetRight() + nShRight < rNew.GetRightMax())
868 aOri.SetHoriOrient( text::HoriOrientation::LEFT );
869 else
870 {
871 // if an automatic table hasn't (really) changed size, then leave it as auto.
872 const tools::Long nOldWidth = rOld.GetRight() - rOld.GetLeft();
873 const tools::Long nNewWidth = rNew.GetRight() - rNew.GetLeft();
874 if (aOri.GetHoriOrient() != text::HoriOrientation::FULL
875 || std::abs(nOldWidth - nNewWidth) > COLFUZZY)
876 {
877 aOri.SetHoriOrient(text::HoriOrientation::LEFT_AND_WIDTH);
878 }
879 }
880 }
881 pFormat->SetFormatAttr( aOri );
882 }
883 const tools::Long nAct = rOld.GetRight() - rOld.GetLeft(); // +1 why?
884 tools::Long nTabDiff = 0;
885
886 if ( rOld.GetLeft() != rNew.GetLeft() )
887 {
888 nTabDiff = rOld.GetLeft() - rNew.GetLeft();
889 nTabDiff *= aParm.nOldWish;
890 nTabDiff /= nAct;
891 }
892 if ( rOld.GetRight() != rNew.GetRight() )
893 {
894 tools::Long nDiff = rNew.GetRight() - rOld.GetRight();
895 nDiff *= aParm.nOldWish;
896 nDiff /= nAct;
897 nTabDiff += nDiff;
898 if( !IsNewModel() )
899 ::lcl_AdjustLines( GetTabLines(), nDiff, aParm );
900 }
901
902 // Adjust the size of the table, watch out for stretched tables.
903 if ( nTabDiff )
904 {
905 aParm.nNewWish += nTabDiff;
906 if ( aParm.nNewWish < 0 )
907 aParm.nNewWish = USHRT_MAX; // Oops! Have to roll back.
908 SwFormatFrameSize aSz( pFormat->GetFrameSize() );
909 if ( aSz.GetWidth() != aParm.nNewWish )
910 {
911 aSz.SetWidth( aParm.nNewWish );
912 aSz.SetWidthPercent( 0 );
913 pFormat->SetFormatAttr( aSz );
914 }
915 }
916 UnlockModify();
917 }
918
919 if( IsNewModel() )
920 NewSetTabCols( aParm, rNew, rOld, pStart, bCurRowOnly );
921 else
922 {
923 if ( bCurRowOnly )
924 {
925 // To adjust the current row, we need to process all its boxes,
926 // similar to the filling of the TabCols (see GetTabCols()).
927 // Unfortunately we again have to take care to adjust the boxes
928 // from back to front, respectively from outer to inner.
929 // The best way to achieve this is probably to track the boxes
930 // in a PtrArray.
931 const SwTableBoxes &rBoxes = pStart->GetUpper()->GetTabBoxes();
932 for ( size_t i = 0; i < rBoxes.size(); ++i )
933 ::lcl_ProcessBoxPtr( rBoxes[i], aParm.aBoxArr, false );
934
935 const SwTableLine *pLine = pStart->GetUpper()->GetUpper() ?
936 pStart->GetUpper()->GetUpper()->GetUpper() : nullptr;
937 const SwTableBox *pExcl = pStart->GetUpper()->GetUpper();
938 while ( pLine )
939 {
940 const SwTableBoxes &rBoxes2 = pLine->GetTabBoxes();
941 bool bBefore = true;
942 for ( size_t i = 0; i < rBoxes2.size(); ++i )
943 {
944 if ( rBoxes2[i] != pExcl )
945 ::lcl_ProcessBoxPtr( rBoxes2[i], aParm.aBoxArr, bBefore );
946 else
947 bBefore = false;
948 }
949 pExcl = pLine->GetUpper();
950 pLine = pLine->GetUpper() ? pLine->GetUpper()->GetUpper() : nullptr;
951 }
952 // After we've inserted a bunch of boxes (hopefully all and in
953 // correct order), we just need to process them in reverse order.
954 for ( int j = aParm.aBoxArr.size()-1; j >= 0; --j )
955 {
956 SwTableBox *pBox = aParm.aBoxArr[j];
957 ::lcl_ProcessBoxSet( pBox, aParm );
958 }
959 }
960 else
961 {
962 // Adjusting the entire table is 'easy'. All boxes without lines are
963 // adjusted, as are their superiors. Of course we need to process
964 // in reverse order to prevent fooling ourselves!
965 SwTableLines &rLines = GetTabLines();
966 for ( size_t i = rLines.size(); i > 0; )
967 {
968 --i;
969 ::lcl_ProcessLine( rLines[i], aParm );
970 }
971 }
972 }
973
974#ifdef DBG_UTIL
975 {
976 // do some checking for correct table widths
978 for (size_t n = 0; n < m_aLines.size(); ++n)
979 {
980 CheckBoxWidth( *m_aLines[ n ], nSize );
981 }
982 }
983#endif
984}
985
986typedef std::pair<sal_uInt16, sal_uInt16> ColChange;
987typedef std::list< ColChange > ChangeList;
988
989static void lcl_AdjustWidthsInLine( SwTableLine* pLine, ChangeList& rOldNew,
990 Parm& rParm, sal_uInt16 nColFuzzy )
991{
992 ChangeList::iterator pCurr = rOldNew.begin();
993 if( pCurr == rOldNew.end() )
994 return;
995 const size_t nCount = pLine->GetTabBoxes().size();
996 SwTwips nBorder = 0;
997 SwTwips nRest = 0;
998 for( size_t i = 0; i < nCount; ++i )
999 {
1000 SwTableBox* pBox = pLine->GetTabBoxes()[i];
1001 SwTwips nWidth = pBox->GetFrameFormat()->GetFrameSize().GetWidth();
1002 SwTwips nNewWidth = nWidth - nRest;
1003 nRest = 0;
1004 nBorder += nWidth;
1005 if( pCurr != rOldNew.end() && nBorder + nColFuzzy >= pCurr->first )
1006 {
1007 nBorder -= nColFuzzy;
1008 while( pCurr != rOldNew.end() && nBorder > pCurr->first )
1009 ++pCurr;
1010 if( pCurr != rOldNew.end() )
1011 {
1012 nBorder += nColFuzzy;
1013 if( nBorder + nColFuzzy >= pCurr->first )
1014 {
1015 if( pCurr->second == pCurr->first )
1016 nRest = 0;
1017 else
1018 nRest = pCurr->second - nBorder;
1019 nNewWidth += nRest;
1020 ++pCurr;
1021 }
1022 }
1023 }
1024 if( nNewWidth != nWidth )
1025 {
1026 if( nNewWidth < 0 )
1027 {
1028 nRest += 1 - nNewWidth;
1029 nNewWidth = 1;
1030 }
1031 SwFormatFrameSize aFormatFrameSize( pBox->GetFrameFormat()->GetFrameSize() );
1032 aFormatFrameSize.SetWidth( nNewWidth );
1033 rParm.aShareFormats.SetSize( *pBox, aFormatFrameSize );
1034 }
1035 }
1036}
1037
1038static void lcl_CalcNewWidths( std::vector<sal_uInt16> &rSpanPos, ChangeList& rChanges,
1039 SwTableLine* pLine, tools::Long nWish, tools::Long nWidth, bool bTop )
1040{
1041 if( rChanges.empty() )
1042 {
1043 rSpanPos.clear();
1044 return;
1045 }
1046 if( rSpanPos.empty() )
1047 {
1048 rChanges.clear();
1049 return;
1050 }
1051 std::vector<sal_uInt16> aNewSpanPos;
1052 ChangeList::iterator pCurr = rChanges.begin();
1053 ChangeList aNewChanges { *pCurr }; // Nullposition
1054 std::vector<sal_uInt16>::iterator pSpan = rSpanPos.begin();
1055 sal_uInt16 nCurr = 0;
1056 SwTwips nOrgSum = 0;
1057 bool bRowSpan = false;
1058 sal_uInt16 nRowSpanCount = 0;
1059 const size_t nCount = pLine->GetTabBoxes().size();
1060 for( size_t nCurrBox = 0; nCurrBox < nCount; ++nCurrBox )
1061 {
1062 SwTableBox* pBox = pLine->GetTabBoxes()[nCurrBox];
1063 SwTwips nCurrWidth = pBox->GetFrameFormat()->GetFrameSize().GetWidth();
1064 const sal_Int32 nRowSpan = pBox->getRowSpan();
1065 const bool bCurrRowSpan = bTop ? nRowSpan < 0 :
1066 ( nRowSpan > 1 || nRowSpan < -1 );
1067 if( bRowSpan || bCurrRowSpan )
1068 aNewSpanPos.push_back( nRowSpanCount );
1069 bRowSpan = bCurrRowSpan;
1070 nOrgSum += nCurrWidth;
1071 const sal_uInt16 nPos = lcl_MulDiv64<sal_uInt16>(
1072 lcl_MulDiv64<sal_uInt64>(nOrgSum, nWidth, nWish),
1073 nWish, nWidth);
1074 while( pCurr != rChanges.end() && pCurr->first < nPos )
1075 {
1076 ++nCurr;
1077 ++pCurr;
1078 }
1079 bool bNew = true;
1080 if( pCurr != rChanges.end() && pCurr->first <= nPos &&
1081 pCurr->first != pCurr->second )
1082 {
1083 pSpan = std::find_if(pSpan, rSpanPos.end(),
1084 [nCurr](const sal_uInt16 nSpan) { return nSpan >= nCurr; });
1085 if( pSpan != rSpanPos.end() && *pSpan == nCurr )
1086 {
1087 aNewChanges.push_back( *pCurr );
1088 ++nRowSpanCount;
1089 bNew = false;
1090 }
1091 }
1092 if( bNew )
1093 {
1094 ColChange aTmp( nPos, nPos );
1095 aNewChanges.push_back( aTmp );
1096 ++nRowSpanCount;
1097 }
1098 }
1099
1100 pCurr = aNewChanges.begin();
1101 ChangeList::iterator pLast = pCurr;
1102 ChangeList::iterator pLeftMove = pCurr;
1103 while( pCurr != aNewChanges.end() )
1104 {
1105 if( pLeftMove == pCurr )
1106 {
1107 while( ++pLeftMove != aNewChanges.end() && pLeftMove->first <= pLeftMove->second )
1108 ;
1109 }
1110 if( pCurr->second == pCurr->first )
1111 {
1112 if( pLeftMove != aNewChanges.end() && pCurr->second > pLeftMove->second )
1113 {
1114 if( pLeftMove->first == pLast->first )
1115 pCurr->second = pLeftMove->second;
1116 else
1117 {
1118 pCurr->second = lcl_MulDiv64<sal_uInt16>(
1119 pCurr->first - pLast->first,
1120 pLeftMove->second - pLast->second,
1121 pLeftMove->first - pLast->first) + pLast->second;
1122 }
1123 }
1124 pLast = pCurr;
1125 ++pCurr;
1126 }
1127 else if( pCurr->second > pCurr->first )
1128 {
1129 pLast = pCurr;
1130 ++pCurr;
1131 ChangeList::iterator pNext = pCurr;
1132 while( pNext != pLeftMove && pNext->second == pNext->first &&
1133 pNext->second < pLast->second )
1134 ++pNext;
1135 while( pCurr != pNext )
1136 {
1137 if( pNext == aNewChanges.end() || pNext->first == pLast->first )
1138 pCurr->second = pLast->second;
1139 else
1140 {
1141 pCurr->second = lcl_MulDiv64<sal_uInt16>(
1142 pCurr->first - pLast->first,
1143 pNext->second - pLast->second,
1144 pNext->first - pLast->first) + pLast->second;
1145 }
1146 ++pCurr;
1147 }
1148 pLast = pCurr;
1149 }
1150 else
1151 {
1152 pLast = pCurr;
1153 ++pCurr;
1154 }
1155 }
1156
1157 rChanges.swap(aNewChanges);
1158 rSpanPos.swap(aNewSpanPos);
1159}
1160
1161void SwTable::NewSetTabCols( Parm &rParm, const SwTabCols &rNew,
1162 const SwTabCols &rOld, const SwTableBox *pStart, bool bCurRowOnly )
1163{
1164#if OSL_DEBUG_LEVEL > 1
1165 static int nCallCount = 0;
1166 ++nCallCount;
1167#endif
1168 // First step: evaluate which lines have been moved/which widths changed
1169 ChangeList aOldNew;
1170 const tools::Long nNewWidth = rParm.rNew.GetRight() - rParm.rNew.GetLeft();
1171 const tools::Long nOldWidth = rParm.rOld.GetRight() - rParm.rOld.GetLeft();
1172 if( nNewWidth < 1 || nOldWidth < 1 )
1173 return;
1174 for( size_t i = 0; i <= rOld.Count(); ++i )
1175 {
1176 tools::Long nNewPos;
1177 tools::Long nOldPos;
1178 if( i == rOld.Count() )
1179 {
1180 nOldPos = rParm.rOld.GetRight() - rParm.rOld.GetLeft();
1181 nNewPos = rParm.rNew.GetRight() - rParm.rNew.GetLeft();
1182 }
1183 else
1184 {
1185 nOldPos = rOld[i] - rParm.rOld.GetLeft();
1186 nNewPos = rNew[i] - rParm.rNew.GetLeft();
1187 }
1188 nNewPos = lcl_MulDiv64<tools::Long>(nNewPos, rParm.nNewWish, nNewWidth);
1189 nOldPos = lcl_MulDiv64<tools::Long>(nOldPos, rParm.nOldWish, nOldWidth);
1190 if( nOldPos != nNewPos && nNewPos > 0 && nOldPos > 0 )
1191 {
1192 ColChange aChg( o3tl::narrowing<sal_uInt16>(nOldPos), o3tl::narrowing<sal_uInt16>(nNewPos) );
1193 aOldNew.push_back( aChg );
1194 }
1195 }
1196 // Finished first step
1197 int nCount = aOldNew.size();
1198 if( !nCount )
1199 return; // no change, nothing to do
1200 SwTableLines &rLines = GetTabLines();
1201 if( bCurRowOnly )
1202 {
1203 const SwTableLine* pCurrLine = pStart->GetUpper();
1204 sal_uInt16 nCurr = rLines.GetPos( pCurrLine );
1205 if( nCurr >= USHRT_MAX )
1206 return;
1207
1208 ColChange aChg( 0, 0 );
1209 aOldNew.push_front( aChg );
1210 std::vector<sal_uInt16> aRowSpanPos;
1211 if( nCurr )
1212 {
1213 ChangeList aCopy;
1214 sal_uInt16 nPos = 0;
1215 for( const auto& rCop : aOldNew )
1216 {
1217 aCopy.push_back( rCop );
1218 aRowSpanPos.push_back( nPos++ );
1219 }
1220 lcl_CalcNewWidths( aRowSpanPos, aCopy, rLines[nCurr],
1221 rParm.nOldWish, nOldWidth, true );
1222 bool bGoOn = !aRowSpanPos.empty();
1223 sal_uInt16 j = nCurr;
1224 while( bGoOn )
1225 {
1226 lcl_CalcNewWidths( aRowSpanPos, aCopy, rLines[--j],
1227 rParm.nOldWish, nOldWidth, true );
1228 lcl_AdjustWidthsInLine( rLines[j], aCopy, rParm, 0 );
1229 bGoOn = !aRowSpanPos.empty() && j > 0;
1230 }
1231 aRowSpanPos.clear();
1232 }
1233 if( nCurr+1 < o3tl::narrowing<sal_uInt16>(rLines.size()) )
1234 {
1235 ChangeList aCopy;
1236 sal_uInt16 nPos = 0;
1237 for( const auto& rCop : aOldNew )
1238 {
1239 aCopy.push_back( rCop );
1240 aRowSpanPos.push_back( nPos++ );
1241 }
1242 lcl_CalcNewWidths( aRowSpanPos, aCopy, rLines[nCurr],
1243 rParm.nOldWish, nOldWidth, false );
1244 bool bGoOn = !aRowSpanPos.empty();
1245 sal_uInt16 j = nCurr;
1246 while( bGoOn )
1247 {
1248 lcl_CalcNewWidths( aRowSpanPos, aCopy, rLines[++j],
1249 rParm.nOldWish, nOldWidth, false );
1250 lcl_AdjustWidthsInLine( rLines[j], aCopy, rParm, 0 );
1251 bGoOn = !aRowSpanPos.empty() && j+1 < o3tl::narrowing<sal_uInt16>(rLines.size());
1252 }
1253 }
1254 ::lcl_AdjustWidthsInLine( rLines[nCurr], aOldNew, rParm, COLFUZZY );
1255 }
1256 else
1257 {
1258 for( size_t i = 0; i < rLines.size(); ++i )
1259 ::lcl_AdjustWidthsInLine( rLines[i], aOldNew, rParm, COLFUZZY );
1260 }
1261 CHECK_TABLE( *this )
1262}
1263
1264// return the pointer of the box specified.
1265static bool lcl_IsValidRowName( std::u16string_view rStr )
1266{
1267 bool bIsValid = true;
1268 size_t nLen = rStr.size();
1269 for( size_t i = 0; i < nLen && bIsValid; ++i )
1270 {
1271 const sal_Unicode cChar = rStr[i];
1272 if (cChar < '0' || cChar > '9')
1273 bIsValid = false;
1274 }
1275 return bIsValid;
1276}
1277
1278// #i80314#
1279// add 3rd parameter and its handling
1280sal_uInt16 SwTable::GetBoxNum( OUString& rStr, bool bFirstPart,
1281 const bool bPerformValidCheck )
1282{
1283 sal_uInt16 nRet = 0;
1284 if( bFirstPart ) // true == column; false == row
1285 {
1286 sal_Int32 nPos = 0;
1287 // the first one uses letters for addressing!
1288 bool bFirst = true;
1289 sal_uInt32 num = 0;
1290 bool overflow = false;
1291 while (nPos<rStr.getLength())
1292 {
1293 sal_Unicode cChar = rStr[nPos];
1294 if ((cChar<'A' || cChar>'Z') && (cChar<'a' || cChar>'z'))
1295 break;
1296 cChar -= 'A';
1297 if( cChar >= 26 )
1298 cChar -= 'a' - '[';
1299 if( bFirst )
1300 bFirst = false;
1301 else
1302 ++num;
1303 num = num * 52 + cChar;
1304 if (num > SAL_MAX_UINT16) {
1305 overflow = true;
1306 }
1307 ++nPos;
1308 }
1309 nRet = overflow ? SAL_MAX_UINT16 : num;
1310 rStr = rStr.copy( nPos ); // Remove char from String
1311 }
1312 else
1313 {
1314 const sal_Int32 nPos = rStr.indexOf( "." );
1315 if ( nPos<0 )
1316 {
1317 nRet = 0;
1318 if ( !bPerformValidCheck || lcl_IsValidRowName( rStr ) )
1319 {
1320 nRet = o3tl::narrowing<sal_uInt16>(rStr.toInt32());
1321 }
1322 rStr.clear();
1323 }
1324 else
1325 {
1326 nRet = 0;
1327 const std::u16string_view aText( rStr.subView( 0, nPos ) );
1328 if ( !bPerformValidCheck || lcl_IsValidRowName( aText ) )
1329 {
1330 nRet = o3tl::narrowing<sal_uInt16>(o3tl::toInt32(aText));
1331 }
1332 rStr = rStr.copy( nPos+1 );
1333 }
1334 }
1335 return nRet;
1336}
1337
1338// #i80314#
1339// add 2nd parameter and its handling
1340const SwTableBox* SwTable::GetTableBox( const OUString& rName,
1341 const bool bPerformValidCheck ) const
1342{
1343 const SwTableBox* pBox = nullptr;
1344 const SwTableLine* pLine;
1345 const SwTableLines* pLines;
1346
1347 sal_uInt16 nLine, nBox;
1348 OUString aNm( rName );
1349 while( !aNm.isEmpty() )
1350 {
1351 nBox = SwTable::GetBoxNum( aNm, nullptr == pBox, bPerformValidCheck );
1352 // first box ?
1353 if( !pBox )
1354 pLines = &GetTabLines();
1355 else
1356 {
1357 pLines = &pBox->GetTabLines();
1358 if( nBox )
1359 --nBox;
1360 }
1361
1362 nLine = SwTable::GetBoxNum( aNm, false, bPerformValidCheck );
1363
1364 // determine line
1365 if( !nLine || nLine > pLines->size() )
1366 return nullptr;
1367 pLine = (*pLines)[ nLine-1 ];
1368
1369 // determine box
1370 const SwTableBoxes* pBoxes = &pLine->GetTabBoxes();
1371 if( nBox >= pBoxes->size() )
1372 return nullptr;
1373 pBox = (*pBoxes)[ nBox ];
1374 }
1375
1376 // check if the box found has any contents
1377 if( pBox && !pBox->GetSttNd() )
1378 {
1379 OSL_FAIL( "Box without content, looking for the next one!" );
1380 // "drop this" until the first box
1381 while( !pBox->GetTabLines().empty() )
1382 pBox = pBox->GetTabLines().front()->GetTabBoxes().front();
1383 }
1384 return pBox;
1385}
1386
1388{
1389 // For optimizations, don't always process the entire SortArray.
1390 // Converting text to table, tries certain conditions
1391 // to ask for a table box of a table that is not yet having a format
1392 if(!GetFrameFormat())
1393 return nullptr;
1394 SwTableBox* pRet = nullptr;
1395 SwNodes& rNds = GetFrameFormat()->GetDoc()->GetNodes();
1396 SwNodeOffset nIndex = nSttIdx + 1;
1397 SwContentNode* pCNd = nullptr;
1398 SwTableNode* pTableNd = nullptr;
1399
1400 while ( nIndex < rNds.Count() )
1401 {
1402 pTableNd = rNds[ nIndex ]->GetTableNode();
1403 if ( pTableNd )
1404 break;
1405
1406 pCNd = rNds[ nIndex ]->GetContentNode();
1407 if ( pCNd )
1408 break;
1409
1410 ++nIndex;
1411 }
1412
1413 if ( pCNd || pTableNd )
1414 {
1415 sw::BroadcastingModify* pModify = pCNd;
1416 // #144862# Better handling of table in table
1417 if ( pTableNd && pTableNd->GetTable().GetFrameFormat() )
1418 pModify = pTableNd->GetTable().GetFrameFormat();
1419
1420 SwFrame* pFrame = pModify ? SwIterator<SwFrame,sw::BroadcastingModify>(*pModify).First() : nullptr;
1421 while ( pFrame && !pFrame->IsCellFrame() )
1422 pFrame = pFrame->GetUpper();
1423 if ( pFrame )
1424 pRet = const_cast<SwTableBox*>(static_cast<SwCellFrame*>(pFrame)->GetTabBox());
1425 }
1426
1427 // In case the layout doesn't exist yet or anything else goes wrong.
1428 if ( !pRet )
1429 {
1430 for (size_t n = m_TabSortContentBoxes.size(); n; )
1431 {
1432 if (m_TabSortContentBoxes[ --n ]->GetSttIdx() == nSttIdx)
1433 {
1434 return m_TabSortContentBoxes[ n ];
1435 }
1436 }
1437 }
1438 return pRet;
1439}
1440
1442{
1443 // Returns true for complex tables, i.e. tables that contain nestings,
1444 // like containing boxes not part of the first line, e.g. results of
1445 // splits/merges which lead to more complex structures.
1446 for (size_t n = 0; n < m_TabSortContentBoxes.size(); ++n)
1447 {
1448 if (m_TabSortContentBoxes[ n ]->GetUpper()->GetUpper())
1449 {
1450 return true;
1451 }
1452 }
1453 return false;
1454}
1455
1456SwTableLine::SwTableLine( SwTableLineFormat *pFormat, sal_uInt16 nBoxes,
1457 SwTableBox *pUp )
1458 : SwClient( pFormat )
1459 , m_pUpper( pUp )
1460 , m_eRedlineType( RedlineType::None )
1461{
1462 m_aBoxes.reserve( nBoxes );
1463}
1464
1466{
1467 for (size_t i = 0; i < m_aBoxes.size(); ++i)
1468 {
1469 delete m_aBoxes[i];
1470 }
1471 // the TabelleLine can be deleted if it's the last client of the FrameFormat
1472 sw::BroadcastingModify* pMod = GetFrameFormat();
1473 pMod->Remove( this ); // remove,
1474 if( !pMod->HasWriterListeners() )
1475 delete pMod; // and delete
1476}
1477
1479{
1480 // This method makes sure that this object is an exclusive SwTableLine client
1481 // of an SwTableLineFormat object
1482 // If other SwTableLine objects currently listen to the same SwTableLineFormat as
1483 // this one, something needs to be done
1484 SwTableLineFormat *pRet = static_cast<SwTableLineFormat*>(GetFrameFormat());
1485 SwIterator<SwTableLine,SwFormat> aIter( *pRet );
1486 for( SwTableLine* pLast = aIter.First(); pLast; pLast = aIter.Next() )
1487 {
1488 if ( pLast != this )
1489 {
1490 // found another SwTableLine that is a client of the current Format
1491 // create a new Format as a copy and use it for this object
1492 SwTableLineFormat *pNewFormat = pRet->GetDoc()->MakeTableLineFormat();
1493 *pNewFormat = *pRet;
1494
1495 // register SwRowFrames that know me as clients at the new Format
1496 SwIterator<SwRowFrame,SwFormat> aFrameIter( *pRet );
1497 for( SwRowFrame* pFrame = aFrameIter.First(); pFrame; pFrame = aFrameIter.Next() )
1498 if( pFrame->GetTabLine() == this )
1499 pFrame->RegisterToFormat( *pNewFormat );
1500
1501 // register myself
1502 pNewFormat->Add( this );
1503 pRet = pNewFormat;
1504 break;
1505 }
1506 }
1507
1508 return pRet;
1509}
1510
1512{
1513 auto pOld = GetFrameFormat();
1514 pOld->CallSwClientNotify(sw::TableLineFormatChanged(*pNewFormat, *this));
1515 // Now, re-register self.
1516 pNewFormat->Add(this);
1517 if(!pOld->HasWriterListeners())
1518 delete pOld;
1519}
1520
1521SwTwips SwTableLine::GetTableLineHeight( bool& bLayoutAvailable ) const
1522{
1523 SwTwips nRet = 0;
1524 bLayoutAvailable = false;
1526 // A row could appear several times in headers/footers so only one chain of master/follow tables
1527 // will be accepted...
1528 const SwTabFrame* pChain = nullptr; // My chain
1529 for( SwRowFrame* pLast = aIter.First(); pLast; pLast = aIter.Next() )
1530 {
1531 if (pLast->GetTabLine() != this)
1532 continue;
1533
1534 const SwTabFrame* pTab = pLast->FindTabFrame();
1535 if (!pTab)
1536 continue;
1537
1538 bLayoutAvailable = ( pTab->IsVertical() ) ?
1539 ( 0 < pTab->getFrameArea().Height() ) :
1540 ( 0 < pTab->getFrameArea().Width() );
1541
1542 // The first one defines the chain, if a chain is defined, only members of the chain
1543 // will be added.
1544 if (!pChain || pChain->IsAnFollow( pTab ) || pTab->IsAnFollow(pChain))
1545 {
1546 pChain = pTab; // defines my chain (even it is already)
1547 if( pTab->IsVertical() )
1548 nRet += pLast->getFrameArea().Width();
1549 else
1550 nRet += pLast->getFrameArea().Height();
1551 // Optimization, if there are no master/follows in my chain, nothing more to add
1552 if( !pTab->HasFollow() && !pTab->IsFollow() )
1553 break;
1554 // This is not an optimization, this is necessary to avoid double additions of
1555 // repeating rows
1556 if( pTab->IsInHeadline(*pLast) )
1557 break;
1558 }
1559 }
1560 return nRet;
1561}
1562
1564{
1565 for (size_t i = 0; i < m_aBoxes.size(); ++i)
1566 {
1567 if ( !m_aBoxes[i]->IsEmpty() )
1568 return false;
1569 }
1570 return true;
1571}
1572
1574{
1575 for (size_t i = 0; i < m_aLines.size(); ++i)
1576 {
1577 if ( !m_aLines[i]->IsEmpty() )
1578 return false;
1579 }
1580 return true;
1581}
1582
1584{
1586 if ( aRedlineTable.empty() )
1587 return false;
1588
1589 SwRedlineTable::size_type nRedlinePos = 0;
1590 for (size_t i = 0; i < m_aLines.size(); ++i)
1591 {
1592 if ( m_aLines[i]->IsDeleted(nRedlinePos) )
1593 return true;
1594 }
1595 return false;
1596}
1597
1599{
1601 if ( aRedlineTable.empty() )
1602 return false;
1603
1604 SwRedlineTable::size_type nRedlinePos = 0;
1605 for (size_t i = 0; i < m_aLines.size(); ++i)
1606 {
1607 if ( !m_aLines[i]->IsDeleted(nRedlinePos) )
1608 return false;
1609 }
1610 return true;
1611}
1612
1613// TODO Set HasTextChangesOnly=true, if needed based on the redlines in the cells.
1614// At tracked row deletion, return with the newest deletion of the row or
1615// at tracked row insertion, return with the oldest insertion in the row, which
1616// contain the change data of the row change.
1617// If the return value is SwRedlineTable::npos, there is no tracked row change.
1619 SwRedlineTable::size_type& rRedlinePos, bool bUpdateProperty ) const
1620{
1623
1624 // check table row property "HasTextChangesOnly", if it's defined and its
1625 // value is false, and all text content is in delete redlines, the row is deleted
1626 const SvxPrintItem *pHasTextChangesOnlyProp =
1628 if ( pHasTextChangesOnlyProp && !pHasTextChangesOnlyProp->GetValue() )
1629 {
1630 const SwTableBoxes & rBoxes = GetTabBoxes();
1631 size_t nBoxes = rBoxes.size();
1632 bool bInsertion = false;
1633 bool bPlainTextInLine = false;
1636 for (size_t nBoxIndex = 0; nBoxIndex < nBoxes && rRedlinePos < aRedlineTable.size(); ++nBoxIndex)
1637 {
1638 auto pBox = rBoxes[nBoxIndex];
1639 if ( pBox->IsEmpty( /*bWithRemainingNestedTable =*/ false ) )
1640 {
1641 // no text content, check the next cells
1642 continue;
1643 }
1644
1645 bool bHasRedlineInBox = false;
1646 SwPosition aCellStart( *pBox->GetSttNd(), SwNodeOffset(0) );
1647 SwPosition aCellEnd( *pBox->GetSttNd()->EndOfSectionNode(), SwNodeOffset(-1) );
1648 SwNodeIndex pEndNodeIndex(aCellEnd.GetNode());
1649 SwRangeRedline* pPreviousDeleteRedline = nullptr;
1650 for( ; rRedlinePos < aRedlineTable.size(); ++rRedlinePos )
1651 {
1652 const SwRangeRedline* pRedline = aRedlineTable[ rRedlinePos ];
1653
1654 if ( pRedline->Start()->GetNodeIndex() > pEndNodeIndex.GetIndex() )
1655 {
1656 // no more redlines in the actual cell,
1657 // check the next ones
1658 break;
1659 }
1660
1661 // redline in the cell
1662 if ( aCellStart <= *pRedline->Start() )
1663 {
1664 if ( !bHasRedlineInBox )
1665 {
1666 bHasRedlineInBox = true;
1667 // plain text before the first redline in the text
1668 if ( pRedline->Start()->GetContentIndex() > 0 )
1669 bPlainTextInLine = true;
1670 }
1671
1672 RedlineType nType = pRedline->GetType();
1673
1674 // first insert redline
1675 if ( !bInsertion )
1676 {
1677 if ( RedlineType::Insert == nType )
1678 {
1679 bInsertion = true;
1680 }
1681 else
1682 {
1683 // plain text between the delete redlines
1684 if ( pPreviousDeleteRedline &&
1685 *pPreviousDeleteRedline->End() < *pRedline->Start() &&
1686 // in the same section, i.e. not in a nested table
1687 pPreviousDeleteRedline->End()->nNode.GetNode().StartOfSectionNode() ==
1688 pRedline->Start()->nNode.GetNode().StartOfSectionNode() )
1689 {
1690 bPlainTextInLine = true;
1691 }
1692 pPreviousDeleteRedline = const_cast<SwRangeRedline*>(pRedline);
1693 }
1694 }
1695
1696 // search newest and oldest redlines
1697 if ( nNewestRedline == SwRedlineTable::npos ||
1698 aRedlineTable[nNewestRedline]->GetRedlineData().GetTimeStamp() <
1699 pRedline->GetRedlineData().GetTimeStamp() )
1700 {
1701 nNewestRedline = rRedlinePos;
1702 }
1703 if ( nOldestRedline == SwRedlineTable::npos ||
1704 aRedlineTable[nOldestRedline]->GetRedlineData().GetTimeStamp() >
1705 pRedline->GetRedlineData().GetTimeStamp() )
1706 {
1707 nOldestRedline = rRedlinePos;
1708 }
1709 }
1710 }
1711
1712 // there is text content outside of redlines: not a deletion
1713 if ( !bInsertion && ( !bHasRedlineInBox || ( pPreviousDeleteRedline &&
1714 // in the same cell, i.e. not in a nested table
1715 pPreviousDeleteRedline->End()->nNode.GetNode().StartOfSectionNode() ==
1716 aCellEnd.GetNode().StartOfSectionNode() &&
1717 ( pPreviousDeleteRedline->End()->GetNode() < aCellEnd.GetNode() ||
1718 pPreviousDeleteRedline->End()->GetContentIndex() <
1719 aCellEnd.GetNode().GetContentNode()->Len() ) ) ) )
1720 {
1721 bPlainTextInLine = true;
1722 // not deleted cell content: the row is not empty
1723 // maybe insertion of a row, try to search it
1724 bInsertion = true;
1725 }
1726 }
1727
1728 // choose return redline, if it exists or remove changed row attribute
1729 if ( bInsertion && SwRedlineTable::npos != nOldestRedline &&
1730 RedlineType::Insert == aRedlineTable[ nOldestRedline ]->GetType() )
1731 {
1732 // there is an insert redline, which is the oldest redline in the row
1733 nRet = nOldestRedline;
1734 }
1735 else if ( !bInsertion && !bPlainTextInLine && SwRedlineTable::npos != nNewestRedline &&
1736 RedlineType::Delete == aRedlineTable[ nNewestRedline ]->GetType() )
1737 {
1738 // there is a delete redline, which is the newest redline in the row,
1739 // and no text outside of redlines, and no insert redline in the row,
1740 // i.e. whole text content is deleted
1741 nRet = nNewestRedline;
1742 }
1743 else
1744 {
1745 // no longer tracked row insertion or deletion
1746 nRet = SwRedlineTable::npos;
1747 // set TextChangesOnly = true to remove the tracked deletion
1748 // FIXME Undo is not supported here (this is only a fallback,
1749 // because using SetRowNotTracked() is not recommended here)
1750 if ( bUpdateProperty )
1751 {
1752 SvxPrintItem aUnsetTracking(RES_PRINT, true);
1753 SwFrameFormat *pFormat = const_cast<SwTableLine*>(this)->ClaimFrameFormat();
1754 pFormat->LockModify();
1755 pFormat->SetFormatAttr( aUnsetTracking );
1756 pFormat->UnlockModify();
1757 }
1758 }
1759 }
1760
1761 // cache the result
1762 const_cast<SwTableLine*>(this)->SetRedlineType( SwRedlineTable::npos == nRet
1763 ? RedlineType::None
1764 : aRedlineTable[ nRet ]->GetType());
1765
1766 return nRet;
1767}
1768
1770{
1772 if ( nPos != SwRedlineTable::npos )
1773 {
1774 const SwRedlineTable& aRedlineTable =
1776 if ( RedlineType::Delete == aRedlineTable[nPos]->GetType() )
1777 return true;
1778 }
1779 return false;
1780}
1781
1783{
1785 if ( aRedlineTable.empty() )
1786 return RedlineType::None;
1787
1788 // check table row property "HasTextChangesOnly", if it's defined and its value is
1789 // false, return with the cached redline type, if it exists, otherwise calculate it
1790 const SvxPrintItem *pHasTextChangesOnlyProp =
1792 if ( pHasTextChangesOnlyProp && !pHasTextChangesOnlyProp->GetValue() )
1793 {
1794 if ( RedlineType::None != m_eRedlineType )
1795 return m_eRedlineType;
1796
1799 if ( nPos != SwRedlineTable::npos )
1800 return aRedlineTable[nPos]->GetType();
1801 }
1802 else if ( RedlineType::None != m_eRedlineType )
1803 // empty the cache
1804 const_cast<SwTableLine*>(this)->SetRedlineType( RedlineType::None );
1805
1806 return RedlineType::None;
1807}
1808
1809SwTableBox::SwTableBox( SwTableBoxFormat* pFormat, sal_uInt16 nLines, SwTableLine *pUp )
1810 : SwClient(nullptr)
1811 , m_aLines()
1812 , m_pStartNode(nullptr)
1813 , m_pUpper(pUp)
1814 , mnRowSpan(1)
1815 , mbDummyFlag(false)
1816 , mbDirectFormatting(false)
1817{
1818 m_aLines.reserve( nLines );
1819 CheckBoxFormat( pFormat )->Add( this );
1820}
1821
1823 SwTableLine *pUp )
1824 : SwClient(nullptr)
1825 , m_aLines()
1826 , m_pUpper(pUp)
1827 , mnRowSpan(1)
1828 , mbDummyFlag(false)
1829 , mbDirectFormatting(false)
1830{
1831 CheckBoxFormat( pFormat )->Add( this );
1832
1834
1835 // insert into the table
1836 const SwTableNode* pTableNd = m_pStartNode->FindTableNode();
1837 assert(pTableNd && "In which table is that box?");
1838 SwTableSortBoxes& rSrtArr = const_cast<SwTableSortBoxes&>(pTableNd->GetTable().
1839 GetTabSortBoxes());
1840 SwTableBox* p = this; // error: &this
1841 rSrtArr.insert( p ); // insert
1842}
1843
1845 : SwClient(nullptr)
1846 , m_aLines()
1847 , m_pStartNode(&rSttNd)
1848 , m_pUpper(pUp)
1849 , mnRowSpan(1)
1850 , mbDummyFlag(false)
1851 , mbDirectFormatting(false)
1852{
1853 CheckBoxFormat( pFormat )->Add( this );
1854
1855 // insert into the table
1856 const SwTableNode* pTableNd = m_pStartNode->FindTableNode();
1857 OSL_ENSURE( pTableNd, "In which table is the box?" );
1858 SwTableSortBoxes& rSrtArr = const_cast<SwTableSortBoxes&>(pTableNd->GetTable().
1859 GetTabSortBoxes());
1860 SwTableBox* p = this; // error: &this
1861 rSrtArr.insert( p ); // insert
1862}
1863
1865{
1866 if (m_pStartNode) // box containing contents?
1867 {
1868 // remove from table
1869 const SwTableNode* pTableNd = m_pStartNode->FindTableNode();
1870 assert(pTableNd && "In which table is that box?");
1871 SwTableSortBoxes& rSrtArr = const_cast<SwTableSortBoxes&>(pTableNd->GetTable().
1872 GetTabSortBoxes());
1873 SwTableBox *p = this; // error: &this
1874 rSrtArr.erase( p ); // remove
1875 m_pStartNode = nullptr; // clear it so this is only run once
1876 }
1877}
1878
1880{
1881 if (!GetFrameFormat()->GetDoc()->IsInDtor())
1882 {
1884 }
1885
1886 // the TabelleBox can be deleted if it's the last client of the FrameFormat
1887 sw::BroadcastingModify* pMod = GetFrameFormat();
1888 pMod->Remove( this ); // remove,
1889 if( !pMod->HasWriterListeners() )
1890 delete pMod; // and delete
1891}
1892
1894{
1895 // We might need to create a new format here, because the box must be
1896 // added to the format solely if pFormat has a value or form.
1897 if( SfxItemState::SET == pFormat->GetItemState( RES_BOXATR_VALUE, false ) ||
1898 SfxItemState::SET == pFormat->GetItemState( RES_BOXATR_FORMULA, false ) )
1899 {
1900 SwTableBox* pOther = SwIterator<SwTableBox,SwFormat>( *pFormat ).First();
1901 if( pOther )
1902 {
1903 SwTableBoxFormat* pNewFormat = pFormat->GetDoc()->MakeTableBoxFormat();
1904 pNewFormat->LockModify();
1905 *pNewFormat = *pFormat;
1906
1907 // Remove values and formulas
1909 pNewFormat->UnlockModify();
1910
1911 pFormat = pNewFormat;
1912 }
1913 }
1914 return pFormat;
1915}
1916
1918{
1919 // This method makes sure that this object is an exclusive SwTableBox client
1920 // of an SwTableBoxFormat object
1921 // If other SwTableBox objects currently listen to the same SwTableBoxFormat as
1922 // this one, something needs to be done
1923 SwTableBoxFormat *pRet = static_cast<SwTableBoxFormat*>(GetFrameFormat());
1924 SwIterator<SwTableBox,SwFormat> aIter( *pRet );
1925 for( SwTableBox* pLast = aIter.First(); pLast; pLast = aIter.Next() )
1926 {
1927 if ( pLast != this )
1928 {
1929 // Found another SwTableBox object
1930 // create a new Format as a copy and assign me to it
1931 // don't copy values and formulas
1932 SwTableBoxFormat* pNewFormat = pRet->GetDoc()->MakeTableBoxFormat();
1933 pNewFormat->LockModify();
1934 *pNewFormat = *pRet;
1936 pNewFormat->UnlockModify();
1937
1938 // re-register SwCellFrame objects that know me
1939 SwIterator<SwCellFrame,SwFormat> aFrameIter( *pRet );
1940 for( SwCellFrame* pCell = aFrameIter.First(); pCell; pCell = aFrameIter.Next() )
1941 if( pCell->GetTabBox() == this )
1942 pCell->RegisterToFormat( *pNewFormat );
1943
1944 // re-register myself
1945 pNewFormat->Add( this );
1946 pRet = pNewFormat;
1947 break;
1948 }
1949 }
1950 return pRet;
1951}
1952
1953void SwTableBox::ChgFrameFormat(SwTableBoxFormat* pNewFormat, bool bNeedToReregister)
1954{
1955 SwFrameFormat* pOld = GetFrameFormat();
1956 // tdf#84635 We set bNeedToReregister=false to avoid a quadratic slowdown on loading large tables,
1957 // and since we are creating the table for the first time, no re-registration is necessary.
1958 // First, re-register the Frames.
1959 if(bNeedToReregister)
1960 pOld->CallSwClientNotify(sw::TableBoxFormatChanged(*pNewFormat, *this));
1961 // Now, re-register self.
1962 pNewFormat->Add(this);
1963 if(!pOld->HasWriterListeners())
1964 delete pOld;
1965}
1966
1967// Return the name of this box. This is determined dynamically
1968// resulting from the position in the lines/boxes/tables.
1969void sw_GetTableBoxColStr( sal_uInt16 nCol, OUString& rNm )
1970{
1971 const sal_uInt16 coDiff = 52; // 'A'-'Z' 'a' - 'z'
1972
1973 do {
1974 const sal_uInt16 nCalc = nCol % coDiff;
1975 if( nCalc >= 26 )
1976 rNm = OUStringChar( sal_Unicode('a' - 26 + nCalc) ) + rNm;
1977 else
1978 rNm = OUStringChar( sal_Unicode('A' + nCalc) ) + rNm;
1979
1980 nCol = nCol - nCalc;
1981 if( 0 == nCol )
1982 break;
1983 nCol /= coDiff;
1984 --nCol;
1985 } while( true );
1986}
1987
1989{
1990 if( !m_pStartNode ) // box without content?
1991 {
1992 // search for the next first box?
1993 return Point( 0, 0 );
1994 }
1995
1996 const SwTable& rTable = m_pStartNode->FindTableNode()->GetTable();
1997 sal_uInt16 nX, nY;
1998 const SwTableBox* pBox = this;
1999 do {
2000 const SwTableLine* pLine = pBox->GetUpper();
2001 // at the first level?
2002 const SwTableLines* pLines = pLine->GetUpper()
2003 ? &pLine->GetUpper()->GetTabLines() : &rTable.GetTabLines();
2004
2005 nY = pLines->GetPos( pLine ) + 1 ;
2006 nX = pBox->GetUpper()->GetBoxPos( pBox ) + 1;
2007 pBox = pLine->GetUpper();
2008 } while( pBox );
2009 return Point( nX, nY );
2010}
2011
2012OUString SwTableBox::GetName() const
2013{
2014 if( !m_pStartNode ) // box without content?
2015 {
2016 // search for the next first box?
2017 return OUString();
2018 }
2019
2020 const SwTable& rTable = m_pStartNode->FindTableNode()->GetTable();
2021 sal_uInt16 nPos;
2022 OUString sNm, sTmp;
2023 const SwTableBox* pBox = this;
2024 do {
2025 const SwTableLine* pLine = pBox->GetUpper();
2026 // at the first level?
2027 const SwTableLines* pLines = pLine->GetUpper()
2028 ? &pLine->GetUpper()->GetTabLines() : &rTable.GetTabLines();
2029
2030 nPos = pLines->GetPos( pLine ) + 1;
2031 sTmp = OUString::number( nPos );
2032 if( !sNm.isEmpty() )
2033 sNm = sTmp + "." + sNm;
2034 else
2035 sNm = sTmp;
2036
2037 nPos = pBox->GetUpper()->GetBoxPos( pBox );
2038 sTmp = OUString::number(nPos + 1);
2039 pBox = pLine->GetUpper();
2040 if( nullptr != pBox )
2041 sNm = sTmp + "." + sNm;
2042 else
2043 sw_GetTableBoxColStr( nPos, sNm );
2044
2045 } while( pBox );
2046 return sNm;
2047}
2048
2049bool SwTableBox::IsInHeadline( const SwTable* pTable ) const
2050{
2051 if( !GetUpper() ) // should only happen upon merge.
2052 return false;
2053
2054 if( !pTable )
2055 pTable = &m_pStartNode->FindTableNode()->GetTable();
2056
2057 const SwTableLine* pLine = GetUpper();
2058 while( pLine->GetUpper() )
2059 pLine = pLine->GetUpper()->GetUpper();
2060
2061 // Headerline?
2062 return pTable->GetTabLines()[ 0 ] == pLine;
2063}
2064
2066{
2068}
2069
2070bool SwTableBox::IsEmpty( bool bWithRemainingNestedTable ) const
2071{
2072 const SwStartNode *pSttNd = GetSttNd();
2073
2074 if ( !pSttNd )
2075 return false;
2076
2077 const SwNode * pFirstNode = pSttNd->GetNodes()[pSttNd->GetIndex() + 1];
2078
2079 if ( pSttNd->GetIndex() + 2 == pSttNd->EndOfSectionIndex() )
2080 {
2081 // single empty node in the box
2082 const SwContentNode *pCNd = pFirstNode->GetContentNode();
2083 if ( pCNd && !pCNd->Len() )
2084 return true;
2085 }
2086 else if ( bWithRemainingNestedTable )
2087 {
2088 if ( const SwTableNode * pTableNode = pFirstNode->GetTableNode() )
2089 {
2090 // empty nested table in the box and
2091 // no text content after it
2092 if ( pTableNode->EndOfSectionIndex() + 2 == pSttNd->EndOfSectionIndex() )
2093 return pTableNode->GetTable().IsEmpty();
2094 }
2095 }
2096
2097 return false;
2098}
2099
2100 // retrieve information from the client
2101bool SwTable::GetInfo( SfxPoolItem& rInfo ) const
2102{
2103 switch( rInfo.Which() )
2104 {
2106 {
2107 const SwTableNode* pNode = GetTableNode();
2108 if (pNode && &pNode->GetNodes() == static_cast<SwAutoFormatGetDocNode&>(rInfo).pNodes)
2109 {
2111 {
2112 SwNodeIndex aIdx( *m_TabSortContentBoxes[0]->GetSttNd() );
2113 GetFrameFormat()->GetDoc()->GetNodes().GoNext( &aIdx );
2114 }
2115 return false;
2116 }
2117 break;
2118 }
2120 if( GetFrameFormat() &&
2121 GetFrameFormat()->GetFormatAttr( RES_PAGEDESC ).GetPageDesc() &&
2123 m_TabSortContentBoxes[0]->GetSttNd()->GetNodes().IsDocNodes() )
2124 static_cast<SwFindNearestNode&>(rInfo).CheckNode( *
2125 m_TabSortContentBoxes[0]->GetSttNd()->FindTableNode() );
2126 break;
2127
2130 return false;
2131 }
2132 return true;
2133}
2134
2136{
2137 return pFormat
2139 : nullptr;
2140}
2141
2143{
2144 return !GetTabSortBoxes().empty() ?
2145 const_cast<SwTableNode*>(GetTabSortBoxes()[ 0 ]->GetSttNd()->FindTableNode()) :
2147}
2148
2150{
2151 if( m_xRefObj.is() )
2152 m_xRefObj->Closed();
2153
2154 m_xRefObj = pObj;
2155}
2156
2157void SwTable::SetHTMLTableLayout(std::shared_ptr<SwHTMLTableLayout> const& r)
2158{
2159 m_xHTMLLayout = r;
2160}
2161
2162static void ChgTextToNum( SwTableBox& rBox, const OUString& rText, const Color* pCol,
2163 bool bChgAlign )
2164{
2165 SwNodeOffset nNdPos = rBox.IsValidNumTextNd();
2166 ChgTextToNum( rBox,rText,pCol,bChgAlign,nNdPos);
2167}
2168void ChgTextToNum( SwTableBox& rBox, const OUString& rText, const Color* pCol,
2169 bool bChgAlign, SwNodeOffset nNdPos )
2170{
2171
2172 if( NODE_OFFSET_MAX == nNdPos )
2173 return;
2174
2175 SwDoc* pDoc = rBox.GetFrameFormat()->GetDoc();
2176 SwTextNode* pTNd = pDoc->GetNodes()[ nNdPos ]->GetTextNode();
2177
2178 // assign adjustment
2179 if( bChgAlign )
2180 {
2181 const SfxPoolItem* pItem;
2182 pItem = &pTNd->SwContentNode::GetAttr( RES_PARATR_ADJUST );
2183 SvxAdjust eAdjust = static_cast<const SvxAdjustItem*>(pItem)->GetAdjust();
2184 if( SvxAdjust::Left == eAdjust || SvxAdjust::Block == eAdjust )
2185 {
2186 SvxAdjustItem aAdjust( *static_cast<const SvxAdjustItem*>(pItem) );
2187 aAdjust.SetAdjust( SvxAdjust::Right );
2188 pTNd->SetAttr( aAdjust );
2189 }
2190 }
2191
2192 // assign color or save "user color"
2193 const SvxColorItem* pColorItem = nullptr;
2194 if( pTNd->GetpSwAttrSet() )
2195 pColorItem = pTNd->GetpSwAttrSet()->GetItemIfSet( RES_CHRATR_COLOR, false );
2196
2197 const std::optional<Color>& pOldNumFormatColor = rBox.GetSaveNumFormatColor();
2198 std::optional<Color> pNewUserColor;
2199 if (pColorItem)
2200 pNewUserColor = pColorItem->GetValue();
2201
2202 if( ( pNewUserColor && pOldNumFormatColor &&
2203 *pNewUserColor == *pOldNumFormatColor ) ||
2204 ( !pNewUserColor && !pOldNumFormatColor ))
2205 {
2206 // Keep the user color, set updated values, delete old NumFormatColor if needed
2207 if( pCol )
2208 // if needed, set the color
2209 pTNd->SetAttr( SvxColorItem( *pCol, RES_CHRATR_COLOR ));
2210 else if( pColorItem )
2211 {
2212 pNewUserColor = rBox.GetSaveUserColor();
2213 if( pNewUserColor )
2214 pTNd->SetAttr( SvxColorItem( *pNewUserColor, RES_CHRATR_COLOR ));
2215 else
2216 pTNd->ResetAttr( RES_CHRATR_COLOR );
2217 }
2218 }
2219 else
2220 {
2221 // Save user color, set NumFormat color if needed, but never reset the color
2222 rBox.SetSaveUserColor( pNewUserColor ? *pNewUserColor : std::optional<Color>() );
2223
2224 if( pCol )
2225 // if needed, set the color
2226 pTNd->SetAttr( SvxColorItem( *pCol, RES_CHRATR_COLOR ));
2227
2228 }
2229 rBox.SetSaveNumFormatColor( pCol ? *pCol : std::optional<Color>() );
2230
2231 if( pTNd->GetText() != rText )
2232 {
2233 // Exchange text. Bugfix to keep Tabs (front and back!) and annotations (inword comment anchors)
2234 const OUString& rOrig = pTNd->GetText();
2235 sal_Int32 n;
2236
2237 for( n = 0; n < rOrig.getLength() && ('\x9' == rOrig[n] || CH_TXTATR_INWORD == rOrig[n]); ++n )
2238 ;
2239 for( ; n < rOrig.getLength() && '\x01' == rOrig[n]; ++n )
2240 ;
2241 SwContentIndex aIdx( pTNd, n );
2242 for( n = rOrig.getLength(); n && ('\x9' == rOrig[--n] || CH_TXTATR_INWORD == rOrig[n]); )
2243 ;
2244 sal_Int32 nEndPos = n;
2245 n -= aIdx.GetIndex() - 1;
2246
2247 // Reset DontExpand-Flags before exchange, to retrigger expansion
2248 {
2249 SwContentIndex aResetIdx( aIdx, n );
2250 pTNd->DontExpandFormat( aResetIdx.GetIndex(), false, false );
2251 }
2252
2254 {
2255 SwPaM aTemp(*pTNd, 0, *pTNd, rOrig.getLength());
2256 pDoc->getIDocumentRedlineAccess().DeleteRedline(aTemp, true, RedlineType::Any);
2257 }
2258
2259 // preserve comments inside of the number by deleting number portions starting from the back
2260 sal_Int32 nCommentPos = pTNd->GetText().lastIndexOf( CH_TXTATR_INWORD, nEndPos );
2261 while( nCommentPos > aIdx.GetIndex() )
2262 {
2263 pTNd->EraseText( SwContentIndex(pTNd, nCommentPos+1), nEndPos - nCommentPos, SwInsertFlags::EMPTYEXPAND );
2264 // find the next non-sequential comment anchor
2265 do
2266 {
2267 nEndPos = nCommentPos;
2268 n = nEndPos - aIdx.GetIndex();
2269 nCommentPos = pTNd->GetText().lastIndexOf( CH_TXTATR_INWORD, nEndPos );
2270 --nEndPos;
2271 }
2272 while( nCommentPos > aIdx.GetIndex() && nCommentPos == nEndPos );
2273 }
2274
2275 pTNd->EraseText( aIdx, n, SwInsertFlags::EMPTYEXPAND );
2276 pTNd->InsertText( rText, aIdx, SwInsertFlags::EMPTYEXPAND );
2277
2279 {
2280 SwPaM aTemp(*pTNd, 0, *pTNd, rText.getLength());
2281 pDoc->getIDocumentRedlineAccess().AppendRedline(new SwRangeRedline(RedlineType::Insert, aTemp), true);
2282 }
2283 }
2284
2285 // assign vertical orientation
2286 const SwFormatVertOrient* pVertOrientItem;
2287 if( bChgAlign &&
2288 ( !(pVertOrientItem = rBox.GetFrameFormat()->GetItemIfSet( RES_VERT_ORIENT )) ||
2289 text::VertOrientation::TOP == pVertOrientItem->GetVertOrient() ))
2290 {
2291 rBox.GetFrameFormat()->SetFormatAttr( SwFormatVertOrient( 0, text::VertOrientation::BOTTOM ));
2292 }
2293
2294}
2295
2296static void ChgNumToText( SwTableBox& rBox, sal_uLong nFormat )
2297{
2298 SwNodeOffset nNdPos = rBox.IsValidNumTextNd( false );
2299 if( NODE_OFFSET_MAX == nNdPos )
2300 return;
2301
2302 SwDoc* pDoc = rBox.GetFrameFormat()->GetDoc();
2303 SwTextNode* pTNd = pDoc->GetNodes()[ nNdPos ]->GetTextNode();
2304 bool bChgAlign = pDoc->IsInsTableAlignNum();
2305
2306 const Color * pCol = nullptr;
2307 if( getSwDefaultTextFormat() != nFormat )
2308 {
2309 // special text format:
2310 OUString sTmp;
2311 const OUString sText( pTNd->GetText() );
2312 pDoc->GetNumberFormatter()->GetOutputString( sText, nFormat, sTmp, &pCol );
2313 if( sText != sTmp )
2314 {
2315 // exchange text
2316 // Reset DontExpand-Flags before exchange, to retrigger expansion
2317 pTNd->DontExpandFormat( sText.getLength(), false, false );
2318 SwContentIndex aIdx( pTNd, 0 );
2320 pTNd->InsertText( sTmp, aIdx, SwInsertFlags::EMPTYEXPAND );
2321 }
2322 }
2323
2324 const SfxItemSet* pAttrSet = pTNd->GetpSwAttrSet();
2325
2326 // assign adjustment
2327 const SvxAdjustItem* pAdjustItem;
2328 if( bChgAlign && pAttrSet &&
2329 (pAdjustItem = pAttrSet->GetItemIfSet( RES_PARATR_ADJUST, false )) &&
2330 SvxAdjust::Right == pAdjustItem->GetAdjust() )
2331 {
2332 pTNd->SetAttr( SvxAdjustItem( SvxAdjust::Left, RES_PARATR_ADJUST ) );
2333 }
2334
2335 // assign color or save "user color"
2336 const SvxColorItem* pColorItem = nullptr;
2337 if( pAttrSet )
2338 pColorItem = pAttrSet->GetItemIfSet( RES_CHRATR_COLOR, false );
2339
2340 const std::optional<Color>& pOldNumFormatColor = rBox.GetSaveNumFormatColor();
2341 std::optional<Color> pNewUserColor;
2342 if (pColorItem)
2343 pNewUserColor = pColorItem->GetValue();
2344
2345 if( ( pNewUserColor && pOldNumFormatColor &&
2346 *pNewUserColor == *pOldNumFormatColor ) ||
2347 ( !pNewUserColor && !pOldNumFormatColor ))
2348 {
2349 // Keep the user color, set updated values, delete old NumFormatColor if needed
2350 if( pCol )
2351 // if needed, set the color
2352 pTNd->SetAttr( SvxColorItem( *pCol, RES_CHRATR_COLOR ));
2353 else if( pColorItem )
2354 {
2355 pNewUserColor = rBox.GetSaveUserColor();
2356 if( pNewUserColor )
2357 pTNd->SetAttr( SvxColorItem( *pNewUserColor, RES_CHRATR_COLOR ));
2358 else
2359 pTNd->ResetAttr( RES_CHRATR_COLOR );
2360 }
2361 }
2362 else
2363 {
2364 // Save user color, set NumFormat color if needed, but never reset the color
2365 rBox.SetSaveUserColor( pNewUserColor );
2366
2367 if( pCol )
2368 // if needed, set the color
2369 pTNd->SetAttr( SvxColorItem( *pCol, RES_CHRATR_COLOR ));
2370
2371 }
2372 rBox.SetSaveNumFormatColor( pCol ? *pCol : std::optional<Color>() );
2373
2374 // assign vertical orientation
2375 const SwFormatVertOrient* pVertOrientItem;
2376 if( bChgAlign &&
2377 (pVertOrientItem = rBox.GetFrameFormat()->GetItemIfSet( RES_VERT_ORIENT, false )) &&
2378 text::VertOrientation::BOTTOM == pVertOrientItem->GetVertOrient() )
2379 {
2380 rBox.GetFrameFormat()->SetFormatAttr( SwFormatVertOrient( 0, text::VertOrientation::TOP ));
2381 }
2382
2383}
2384void SwTableBoxFormat::BoxAttributeChanged(SwTableBox& rBox, const SwTableBoxNumFormat* pNewFormat, const SwTableBoxFormula* pNewFormula, const SwTableBoxValue* pNewValue, sal_uLong nOldFormat)
2385{
2386 sal_uLong nNewFormat;
2387 if(pNewFormat)
2388 {
2389 nNewFormat = pNewFormat->GetValue();
2390 // new formatting
2391 // is it newer or has the current been removed?
2392 if( SfxItemState::SET != GetItemState(RES_BOXATR_VALUE, false))
2393 pNewFormat = nullptr;
2394 }
2395 else
2396 {
2397 // fetch the current Item
2398 pNewFormat = GetItemIfSet(RES_BOXATR_FORMAT, false);
2399 nOldFormat = GetTableBoxNumFormat().GetValue();
2400 nNewFormat = pNewFormat ? pNewFormat->GetValue() : nOldFormat;
2401 }
2402
2403 // is it newer or has the current been removed?
2404 if(pNewValue)
2405 {
2406 if(GetDoc()->GetNumberFormatter()->IsTextFormat(nNewFormat))
2407 nOldFormat = 0;
2408 else
2409 {
2410 if(SfxItemState::SET == GetItemState(RES_BOXATR_VALUE, false))
2411 nOldFormat = getSwDefaultTextFormat();
2412 else
2413 nNewFormat = getSwDefaultTextFormat();
2414 }
2415 }
2416
2417 // Logic:
2418 // Value change: -> "simulate" a format change!
2419 // Format change:
2420 // Text -> !Text or format change:
2421 // - align right for horizontal alignment, if LEFT or JUSTIFIED
2422 // - align bottom for vertical alignment, if TOP is set, or default
2423 // - replace text (color? negative numbers RED?)
2424 // !Text -> Text:
2425 // - align left for horizontal alignment, if RIGHT
2426 // - align top for vertical alignment, if BOTTOM is set
2427 SvNumberFormatter* pNumFormatr = GetDoc()->GetNumberFormatter();
2428 bool bNewIsTextFormat = pNumFormatr->IsTextFormat(nNewFormat);
2429
2430 if((!bNewIsTextFormat && nOldFormat != nNewFormat) || pNewFormula)
2431 {
2432 bool bIsNumFormat = false;
2433 OUString aOrigText;
2434 bool bChgText = true;
2435 double fVal = 0;
2436 if(!pNewValue)
2437 pNewValue = GetItemIfSet(RES_BOXATR_VALUE, false);
2438 if(!pNewValue)
2439 {
2440 // so far, no value has been set, so try to evaluate the content
2441 SwNodeOffset nNdPos = rBox.IsValidNumTextNd();
2442 if(NODE_OFFSET_MAX != nNdPos)
2443 {
2444 sal_uInt32 nTmpFormatIdx = nNewFormat;
2445 OUString aText(GetDoc()->GetNodes()[nNdPos] ->GetTextNode()->GetRedlineText());
2446 aOrigText = aText;
2447 if(aText.isEmpty())
2448 bChgText = false;
2449 else
2450 {
2451 // Keep Tabs
2453
2454 // JP 22.04.98: Bug 49659 -
2455 // Special casing for percent
2456 if(SvNumFormatType::PERCENT == pNumFormatr->GetType(nNewFormat))
2457 {
2458 sal_uInt32 nTmpFormat = 0;
2459 if(GetDoc()->IsNumberFormat(aText, nTmpFormat, fVal))
2460 {
2461 if(SvNumFormatType::NUMBER == pNumFormatr->GetType( nTmpFormat))
2462 aText += "%";
2463
2464 bIsNumFormat = GetDoc()->IsNumberFormat(aText, nTmpFormatIdx, fVal);
2465 }
2466 }
2467 else
2468 bIsNumFormat = GetDoc()->IsNumberFormat(aText, nTmpFormatIdx, fVal);
2469
2470 if(bIsNumFormat)
2471 {
2472 // directly assign value - without Modify
2473 bool bIsLockMod = IsModifyLocked();
2474 LockModify();
2476 if(!bIsLockMod)
2477 UnlockModify();
2478 }
2479 }
2480 }
2481 }
2482 else
2483 {
2484 fVal = pNewValue->GetValue();
2485 bIsNumFormat = true;
2486 }
2487
2488 // format contents with the new value assigned and write to paragraph
2489 const Color* pCol = nullptr;
2490 OUString sNewText;
2491 bool bChangeFormat = true;
2492 if(DBL_MAX == fVal)
2493 {
2495 }
2496 else
2497 {
2498 if(bIsNumFormat)
2499 pNumFormatr->GetOutputString(fVal, nNewFormat, sNewText, &pCol);
2500 else
2501 {
2502 // Original text could not be parsed as
2503 // number/date/time/..., so keep the text.
2504#if 0
2505 // Actually the text should be formatted
2506 // according to the format, which may include
2507 // additional text from the format, for example
2508 // in {0;-0;"BAD: "@}. But other places when
2509 // entering a new value or changing text or
2510 // changing to a different format of type Text
2511 // don't do this (yet?).
2512 pNumFormatr->GetOutputString(aOrigText, nNewFormat, sNewText, &pCol);
2513#else
2514 sNewText = aOrigText;
2515#endif
2516 // Remove the newly assigned numbering format as well if text actually exists.
2517 // Exception: assume user-defined formats are always intentional.
2518 if (bChgText && pNumFormatr->IsTextFormat(nOldFormat)
2519 && !pNumFormatr->IsUserDefined(nNewFormat))
2520 {
2522 bChangeFormat = false;
2523 }
2524 }
2525
2526 if(!bChgText)
2527 sNewText.clear();
2528 }
2529
2530 // across all boxes
2531 if (bChangeFormat)
2532 ChgTextToNum(rBox, sNewText, pCol, GetDoc()->IsInsTableAlignNum());
2533
2534 }
2535 else if(bNewIsTextFormat && nOldFormat != nNewFormat)
2536 ChgNumToText(rBox, nNewFormat);
2537}
2538
2539SwTableBox* SwTableBoxFormat::SwTableBoxFormat::GetTableBox()
2540{
2542 auto pBox = aIter.First();
2543 SAL_INFO_IF(!pBox, "sw.core", "no box found at format");
2544 SAL_WARN_IF(pBox && aIter.Next(), "sw.core", "more than one box found at format");
2545 return pBox;
2546}
2547
2548// for detection of modifications (mainly TableBoxAttribute)
2550{
2551 if(rHint.GetId() != SfxHintId::SwLegacyModify)
2552 return;
2553 auto pLegacy = static_cast<const sw::LegacyModifyHint*>(&rHint);
2554 if(IsModifyLocked() || !GetDoc() || GetDoc()->IsInDtor())
2555 {
2556 SwFrameFormat::SwClientNotify(rMod, rHint);
2557 return;
2558 }
2559 const SwTableBoxNumFormat* pNewFormat = nullptr;
2560 const SwTableBoxFormula* pNewFormula = nullptr;
2561 const SwTableBoxValue* pNewVal = nullptr;
2562 sal_uLong nOldFormat = getSwDefaultTextFormat();
2563
2564 switch(pLegacy->m_pNew ? pLegacy->m_pNew->Which() : 0)
2565 {
2566 case RES_ATTRSET_CHG:
2567 {
2568 const SfxItemSet& rSet = *static_cast<const SwAttrSetChg*>(pLegacy->m_pNew)->GetChgSet();
2569 pNewFormat = rSet.GetItemIfSet( RES_BOXATR_FORMAT, false);
2570 if(pNewFormat)
2571 nOldFormat = static_cast<const SwAttrSetChg*>(pLegacy->m_pOld)->GetChgSet()->Get(RES_BOXATR_FORMAT).GetValue();
2572 pNewFormula = rSet.GetItemIfSet(RES_BOXATR_FORMULA, false);
2573 pNewVal = rSet.GetItemIfSet(RES_BOXATR_VALUE, false);
2574 break;
2575 }
2576 case RES_BOXATR_FORMAT:
2577 pNewFormat = static_cast<const SwTableBoxNumFormat*>(pLegacy->m_pNew);
2578 nOldFormat = static_cast<const SwTableBoxNumFormat*>(pLegacy->m_pOld)->GetValue();
2579 break;
2580 case RES_BOXATR_FORMULA:
2581 pNewFormula = static_cast<const SwTableBoxFormula*>(pLegacy->m_pNew);
2582 break;
2583 case RES_BOXATR_VALUE:
2584 pNewVal = static_cast<const SwTableBoxValue*>(pLegacy->m_pNew);
2585 break;
2586 }
2587
2588 // something changed and some BoxAttribut remained in the set!
2589 if( pNewFormat || pNewFormula || pNewVal )
2590 {
2592
2593 if(SfxItemState::SET == GetItemState(RES_BOXATR_FORMAT, false) ||
2594 SfxItemState::SET == GetItemState(RES_BOXATR_VALUE, false) ||
2595 SfxItemState::SET == GetItemState(RES_BOXATR_FORMULA, false) )
2596 {
2597 if(auto pBox = GetTableBox())
2598 BoxAttributeChanged(*pBox, pNewFormat, pNewFormula, pNewVal, nOldFormat);
2599 }
2600 }
2601 // call base class
2602 SwFrameFormat::SwClientNotify(rMod, rHint);
2603}
2604
2606{
2607 return false;
2608}
2609
2611{
2612 return false;
2613}
2614
2616{
2617 return false;
2618}
2619
2620bool SwTableBox::HasNumContent( double& rNum, sal_uInt32& rFormatIndex,
2621 bool& rIsEmptyTextNd ) const
2622{
2623 bool bRet = false;
2624 SwNodeOffset nNdPos = IsValidNumTextNd();
2625 if( NODE_OFFSET_MAX != nNdPos )
2626 {
2627 OUString aText( m_pStartNode->GetNodes()[ nNdPos ]->GetTextNode()->GetRedlineText() );
2628 // Keep Tabs
2629 lcl_TabToBlankAtSttEnd( aText );
2630 rIsEmptyTextNd = aText.isEmpty();
2632
2633 if( const SwTableBoxNumFormat* pItem = GetFrameFormat()->GetItemIfSet( RES_BOXATR_FORMAT, false) )
2634 {
2635 rFormatIndex = pItem->GetValue();
2636 // Special casing for percent
2637 if( !rIsEmptyTextNd && SvNumFormatType::PERCENT == pNumFormatr->GetType( rFormatIndex ))
2638 {
2639 sal_uInt32 nTmpFormat = 0;
2640 if( GetFrameFormat()->GetDoc()->IsNumberFormat( aText, nTmpFormat, rNum ) &&
2641 SvNumFormatType::NUMBER == pNumFormatr->GetType( nTmpFormat ))
2642 aText += "%";
2643 }
2644 }
2645 else
2646 rFormatIndex = 0;
2647
2648 bRet = GetFrameFormat()->GetDoc()->IsNumberFormat( aText, rFormatIndex, rNum );
2649 }
2650 else
2651 rIsEmptyTextNd = false;
2652 return bRet;
2653}
2654
2656{
2657 bool bRet = true;
2658
2659 if( SfxItemState::SET == GetFrameFormat()->GetItemState( RES_BOXATR_FORMULA, false ))
2660 {
2661 const SwTableBoxNumFormat *pNumFormat = GetFrameFormat()->GetItemIfSet( RES_BOXATR_FORMAT, false );
2662 const SwTableBoxValue *pValue = GetFrameFormat()->GetItemIfSet( RES_BOXATR_VALUE, false );
2663
2664 SwNodeOffset nNdPos;
2665 if( pNumFormat && pValue && NODE_OFFSET_MAX != ( nNdPos = IsValidNumTextNd() ) )
2666 {
2667 OUString sNewText, sOldText( m_pStartNode->GetNodes()[ nNdPos ]->
2668 GetTextNode()->GetRedlineText() );
2669 lcl_DelTabsAtSttEnd( sOldText );
2670
2671 const Color* pCol = nullptr;
2673 pValue->GetValue(), pNumFormat->GetValue(), sNewText, &pCol );
2674
2675 bRet = sNewText != sOldText ||
2676 !( ( !pCol && !GetSaveNumFormatColor() ) ||
2677 ( pCol && GetSaveNumFormatColor() &&
2678 *pCol == *GetSaveNumFormatColor() ));
2679 }
2680 }
2681 return bRet;
2682}
2683
2685{
2687 if( m_pStartNode )
2688 {
2689 SwNodeIndex aIdx( *m_pStartNode );
2690 SwNodeOffset nIndex = aIdx.GetIndex();
2691 const SwNodeOffset nIndexEnd = m_pStartNode->GetNodes()[ nIndex ]->EndOfSectionIndex();
2692 const SwTextNode *pTextNode = nullptr;
2693 while( ++nIndex < nIndexEnd )
2694 {
2695 const SwNode* pNode = m_pStartNode->GetNodes()[nIndex];
2696 if( pNode->IsTableNode() )
2697 {
2698 pTextNode = nullptr;
2699 break;
2700 }
2701 if( pNode->IsTextNode() )
2702 {
2703 if( pTextNode )
2704 {
2705 pTextNode = nullptr;
2706 break;
2707 }
2708 else
2709 {
2710 pTextNode = pNode->GetTextNode();
2711 nPos = nIndex;
2712 }
2713 }
2714 }
2715 if( pTextNode )
2716 {
2717 if( bCheckAttr )
2718 {
2719 const SwpHints* pHts = pTextNode->GetpSwpHints();
2720 // do some tests if there's only text in the node!
2721 // Flys/fields/...
2722 if( pHts )
2723 {
2724 sal_Int32 nNextSetField = 0;
2725 for( size_t n = 0; n < pHts->Count(); ++n )
2726 {
2727 const SwTextAttr* pAttr = pHts->Get(n);
2728 if( RES_TXTATR_NOEND_BEGIN <= pAttr->Which() )
2729 {
2730 if ( (pAttr->GetStart() == nNextSetField)
2731 && (pAttr->Which() == RES_TXTATR_FIELD))
2732 {
2733 // #i104949# hideous hack for report builder:
2734 // it inserts hidden variable-set fields at
2735 // the beginning of para in cell, but they
2736 // should not turn cell into text cell
2737 const SwField* pField = pAttr->GetFormatField().GetField();
2738 if (pField &&
2739 (pField->GetTypeId() == SwFieldTypesEnum::Set) &&
2740 (0 != (static_cast<SwSetExpField const*>
2741 (pField)->GetSubType() &
2743 {
2744 nNextSetField = pAttr->GetStart() + 1;
2745 continue;
2746 }
2747 }
2748 else if( RES_TXTATR_ANNOTATION == pAttr->Which() ||
2749 RES_TXTATR_FTN == pAttr->Which() )
2750 {
2751 continue;
2752 }
2754 break;
2755 }
2756 }
2757 }
2758 }
2759 }
2760 else
2762 }
2763 return nPos;
2764}
2765
2766// is this a Formula box or one with numeric content (AutoSum)
2768{
2769 sal_uInt16 nWhich = 0;
2770 const SwTextNode* pTNd;
2771 SwFrameFormat* pFormat = GetFrameFormat();
2772 if( SfxItemState::SET == pFormat->GetItemState( RES_BOXATR_FORMULA, false ))
2773 nWhich = RES_BOXATR_FORMULA;
2774 else if( SfxItemState::SET == pFormat->GetItemState( RES_BOXATR_VALUE, false ) &&
2775 !pFormat->GetDoc()->GetNumberFormatter()->IsTextFormat(
2776 pFormat->GetTableBoxNumFormat().GetValue() ))
2777 nWhich = RES_BOXATR_VALUE;
2779 && nullptr != ( pTNd = m_pStartNode->GetNodes()[ m_pStartNode->GetIndex() + 1 ]
2780 ->GetTextNode() ) && pTNd->GetText().isEmpty())
2781 nWhich = USHRT_MAX;
2782
2783 return nWhich;
2784}
2785
2787{
2788 SwFrameFormat* pFormat = GetFrameFormat();
2789 const SwTableBoxNumFormat *pFormatItem = pFormat->GetItemIfSet( RES_BOXATR_FORMAT, true );
2790 if (!pFormatItem)
2791 return;
2792 const SwTableBoxValue *pValItem = pFormat->GetItemIfSet( RES_BOXATR_VALUE );
2793 if (!pValItem)
2794 return;
2795
2796 const sal_uLong nFormatId = pFormatItem->GetValue();
2798 SvNumberFormatter* pNumFormatr = pFormat->GetDoc()->GetNumberFormatter();
2799
2800 if( !pNumFormatr->IsTextFormat( nFormatId ) &&
2801 NODE_OFFSET_MAX != (nNdPos = IsValidNumTextNd()) )
2802 {
2803 double fVal = pValItem->GetValue();
2804 const Color* pCol = nullptr;
2805 OUString sNewText;
2806 pNumFormatr->GetOutputString( fVal, nFormatId, sNewText, &pCol );
2807
2808 const OUString& rText = m_pStartNode->GetNodes()[ nNdPos ]->GetTextNode()->GetText();
2809 if( rText != sNewText )
2810 ChgTextToNum( *this, sNewText, pCol, false ,nNdPos);
2811 }
2812}
2813
2815{
2821
2822public:
2824 : m_pTable(nullptr), m_pCellFrame(nullptr), m_pTabFrame(nullptr)
2825 {
2826 }
2827
2828 void setTable(const SwTable * pTable)
2829 {
2830 m_pTable = pTable;
2831 SwFrameFormat * pFrameFormat = m_pTable->GetFrameFormat();
2833 if (m_pTabFrame && m_pTabFrame->IsFollow())
2835 }
2836
2837 const SwCellFrame * getCellFrame() const { return m_pCellFrame; }
2838
2839 const SwFrame * getNextFrameInTable(const SwFrame * pFrame);
2840 const SwCellFrame * getNextCellFrame(const SwFrame * pFrame);
2841 const SwCellFrame * getNextTableBoxsCellFrame(const SwFrame * pFrame);
2842 bool getNext();
2843};
2844
2846{
2847 const SwFrame * pResult = nullptr;
2848
2849 if (((! pFrame->IsTabFrame()) || pFrame == m_pTabFrame) && pFrame->GetLower())
2850 pResult = pFrame->GetLower();
2851 else if (pFrame->GetNext())
2852 pResult = pFrame->GetNext();
2853 else
2854 {
2855 while (pFrame->GetUpper() != nullptr)
2856 {
2857 pFrame = pFrame->GetUpper();
2858
2859 if (pFrame->IsTabFrame())
2860 {
2861 m_pTabFrame = static_cast<const SwTabFrame *>(pFrame)->GetFollow();
2862 pResult = m_pTabFrame;
2863 break;
2864 }
2865 else if (pFrame->GetNext())
2866 {
2867 pResult = pFrame->GetNext();
2868 break;
2869 }
2870 }
2871 }
2872
2873 return pResult;
2874}
2875
2877{
2878 const SwCellFrame * pResult = nullptr;
2879
2880 while ((pFrame = getNextFrameInTable(pFrame)) != nullptr)
2881 {
2882 if (pFrame->IsCellFrame())
2883 {
2884 pResult = static_cast<const SwCellFrame *>(pFrame);
2885 break;
2886 }
2887 }
2888
2889 return pResult;
2890}
2891
2893{
2894 const SwCellFrame * pResult = nullptr;
2895
2896 while ((pFrame = getNextCellFrame(pFrame)) != nullptr)
2897 {
2898 const SwCellFrame * pCellFrame = static_cast<const SwCellFrame *>(pFrame);
2899 const SwTableBox * pTabBox = pCellFrame->GetTabBox();
2900 auto aIt = m_HandledTableBoxes.insert(pTabBox);
2901 if (aIt.second)
2902 {
2903 pResult = pCellFrame;
2904 break;
2905 }
2906 }
2907
2908 return pResult;
2909}
2910
2912{
2913 return m_pImpl->getCellFrame();
2914}
2915
2917{
2918 if (m_pCellFrame == nullptr)
2919 {
2920 if (m_pTabFrame != nullptr)
2921 m_pCellFrame = Impl::getNextTableBoxsCellFrame(m_pTabFrame);
2922 }
2923 else
2924 m_pCellFrame = Impl::getNextTableBoxsCellFrame(m_pCellFrame);
2925
2926 return m_pCellFrame != nullptr;
2927}
2928
2930 : m_pImpl(std::make_unique<Impl>())
2931{
2932 m_pImpl->setTable(pTable);
2933}
2934
2936{
2937}
2938
2940{
2941 return m_pImpl->getNext();
2942}
2943
2945{
2946 SwRect aRet;
2947
2948 if (getCellFrame() != nullptr)
2949 aRet = getCellFrame()->getFrameArea();
2950
2951 return aRet;
2952}
2953
2955{
2956 const SwTableBox * pRet = nullptr;
2957
2958 if (getCellFrame() != nullptr)
2959 pRet = getCellFrame()->GetTabBox();
2960
2961 return pRet;
2962}
2963
2965{
2966 rFormat.Add( this );
2967}
2968
2970{
2971 const SwFrameFormat* pFrameFormat = GetFrameFormat();
2972 //a table in a clipboard document doesn't have any layout information
2973 return pFrameFormat && SwIterator<SwTabFrame,SwFormat>(*pFrameFormat).First();
2974}
2975
2977{
2978 rFormat.Add( this );
2979}
2980
2981// free's any remaining child objects
2983{
2984 for ( const_iterator it = begin(); it != end(); ++it )
2985 delete *it;
2986}
2987
2988/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
constexpr sal_uInt32 getSwDefaultTextFormat()
The number formatter's default locale's @ Text format.
Definition: cellatr.hxx:34
sal_uInt32 GetValue() const
virtual bool SetFieldsDirty(bool b, const SwNode *pChk, SwNodeOffset nLen)=0
virtual sfx2::LinkManager & GetLinkManager()=0
virtual bool IsIgnoreRedline() const =0
virtual bool DeleteRedline(const SwPaM &rPam, bool bSaveInUndo, RedlineType nDelType)=0
static bool IsRedlineOn(const RedlineFlags eM)
virtual const SwRedlineTable & GetRedlineTable() const =0
virtual AppendResult AppendRedline(SwRangeRedline *pNewRedl, bool bCallDelete)=0
Append a new redline.
SfxHintId GetId() const
const T * GetItemIfSet(TypedWhichId< T > nWhich, bool bSrchInParent=true) const
sal_uInt16 ClearItem(sal_uInt16 nWhich=0)
bool HasItem(sal_uInt16 nWhich, const SfxPoolItem **ppItem=nullptr) const
const SfxPoolItem * GetItem(sal_uInt16 nWhich, bool bSearchInParent=true) const
const SfxPoolItem * Put(const SfxPoolItem &rItem, sal_uInt16 nWhich)
const SfxPoolItem & Get(sal_uInt16 nWhich, bool bSrchInParent=true) const
sal_uInt16 Which() const
void GetOutputString(const double &fOutNumber, sal_uInt32 nFIndex, OUString &sOutString, const Color **ppColor, bool bUseStarFormat=false)
bool IsTextFormat(sal_uInt32 nFIndex) const
SvNumFormatType GetType(sal_uInt32 nFIndex) const
bool IsUserDefined(sal_uInt32 F_Index) const
SvxAdjust GetAdjust() const
void SetAdjust(const SvxAdjust eType)
const Color & GetValue() const
void SetRight(const tools::Long nR, const sal_uInt16 nProp=100)
void SetLeft(const tools::Long nL, const sal_uInt16 nProp=100)
sal_uInt16 CalcShadowSpace(SvxShadowItemSide nShadow) const
tools::Long GetWidth() const
void SetWidth(tools::Long n)
const SwAttrSet * GetChgSet() const
What has changed.
Definition: hints.hxx:317
const SwNodes * pNodes
Definition: hints.hxx:297
SwCellFrame is one table cell in the document layout.
Definition: cellfrm.hxx:31
const SwTableBox * GetTabBox() const
Definition: cellfrm.hxx:52
std::optional< sw::ModifyChangedHint > CheckRegistration(const SfxPoolItem *pOldValue)
Definition: calbck.cxx:77
Marks a character position inside a document model content node (SwContentNode)
sal_Int32 GetIndex() const
const SwAttrSet & GetSwAttrSet() const
Does node has already its own auto-attributes? Access to SwAttrSet.
Definition: node.hxx:763
virtual sal_Int32 Len() const
Definition: node.cxx:1263
const SwAttrSet * GetpSwAttrSet() const
Definition: node.hxx:493
Definition: doc.hxx:194
bool IsNumberFormat(std::u16string_view aString, sal_uInt32 &F_Index, double &fOutNumber)
Definition: ndtbl.cxx:4010
SwTableBoxFormat * MakeTableBoxFormat()
Definition: docfmt.cxx:1709
bool IsInDtor() const
Definition: doc.hxx:412
SwTableLineFormat * MakeTableLineFormat()
Definition: docfmt.cxx:1717
IDocumentLinksAdministration const & getIDocumentLinksAdministration() const
Definition: doc.cxx:266
SwNodes & GetNodes()
Definition: doc.hxx:417
IDocumentFieldsAccess const & getIDocumentFieldsAccess() const
Definition: doc.cxx:363
IDocumentRedlineAccess const & getIDocumentRedlineAccess() const
Definition: doc.cxx:341
const SwTextFormatColl * GetDfltTextFormatColl() const
Definition: doc.hxx:784
void DelTableFrameFormat(SwTableFormat *pFormat)
Definition: docfmt.cxx:737
SvNumberFormatter * GetNumberFormatter(bool bCreate=true)
Definition: doc.hxx:1418
bool IsInsTableAlignNum() const
Definition: doc.cxx:1689
Base class of all fields.
Definition: fldbas.hxx:292
SwFieldTypesEnum GetTypeId() const
Definition: fldbas.cxx:257
const std::shared_ptr< SfxItemSet > & GetStyleHandle() const
Definition: fmtautofmt.hxx:49
const SwField * GetField() const
Definition: fmtfld.hxx:130
void SetWidthPercent(sal_uInt8 n)
Definition: fmtfsize.hxx:95
Defines the horizontal position of a fly frame.
Definition: fmtornt.hxx:73
void SetHoriOrient(sal_Int16 eNew)
Definition: fmtornt.hxx:96
sal_Int16 GetHoriOrient() const
Definition: fmtornt.hxx:94
Defines the vertical position of a fly frame.
Definition: fmtornt.hxx:37
sal_Int16 GetVertOrient() const
Definition: fmtornt.hxx:57
Base class for various Writer styles.
Definition: format.hxx:47
const SwTableBoxNumFormat & GetTableBoxNumFormat(bool=true) const
TableBox attributes - implemented in cellatr.hxx.
Definition: cellatr.hxx:105
const SwDoc * GetDoc() const
The document is set in SwAttrPool now, therefore you always can access it.
Definition: format.hxx:139
const SwFormatFrameSize & GetFrameSize(bool=true) const
Definition: fmtfsize.hxx:104
const SvxLRSpaceItem & GetLRSpace(bool=true) const
Definition: frmatr.hxx:74
virtual bool ResetFormatAttr(sal_uInt16 nWhich1, sal_uInt16 nWhich2=0)
Definition: format.cxx:618
const SvxShadowItem & GetShadow(bool=true) const
Definition: frmatr.hxx:88
SfxItemState GetItemState(sal_uInt16 nWhich, bool bSrchInParent=true, const SfxPoolItem **ppItem=nullptr) const
Definition: format.cxx:385
const SwAttrSet & GetAttrSet() const
For querying the attribute array.
Definition: format.hxx:136
const SwFormatHoriOrient & GetHoriOrient(bool=true) const
Definition: fmtornt.hxx:115
virtual bool SetFormatAttr(const SfxPoolItem &rAttr)
Definition: format.cxx:447
const T * GetItemIfSet(TypedWhichId< T > nWhich, bool bSrchInParent=true) const
Templatized version of GetItemState() to directly return the correct type.
Definition: format.hxx:111
const SwRect & getFrameArea() const
Definition: frame.hxx:179
Style of a layout element.
Definition: frmfmt.hxx:62
virtual void SwClientNotify(const SwModify &, const SfxHint &) override
Definition: atrfrm.cxx:2620
Base class of the Writer layout elements.
Definition: frame.hxx:315
bool IsCellFrame() const
Definition: frame.hxx:1226
SwTabFrame * FindTabFrame()
Definition: frame.hxx:1099
SwFrame * GetNext()
Definition: frame.hxx:676
bool IsTabFrame() const
Definition: frame.hxx:1218
SwFrame * GetLower()
Definition: findfrm.cxx:194
SwLayoutFrame * GetUpper()
Definition: frame.hxx:678
bool IsVertical() const
Definition: frame.hxx:973
TElementType * Next()
Definition: calbck.hxx:373
TElementType * First()
Definition: calbck.hxx:365
Marks a node in the document model.
Definition: ndindex.hxx:31
SwNode & GetNode() const
Definition: ndindex.hxx:136
SwNodeOffset GetIndex() const
Definition: ndindex.hxx:171
Base class of the Writer document model elements.
Definition: node.hxx:98
SwStartNode * GetStartNode()
Definition: node.hxx:640
SwTextNode * GetTextNode()
Inline methods from Node.hxx.
Definition: ndtxt.hxx:897
SwNodeOffset GetIndex() const
Definition: node.hxx:312
SwNodes & GetNodes()
Node is in which nodes-array/doc?
Definition: node.hxx:742
bool IsTableNode() const
Definition: node.hxx:689
bool IsTextNode() const
Definition: node.hxx:685
SwTableNode * FindTableNode()
Search table node, in which it is.
Definition: node.cxx:380
const SwStartNode * StartOfSectionNode() const
Definition: node.hxx:153
SwNodeOffset EndOfSectionIndex() const
Definition: node.hxx:726
SwContentNode * GetContentNode()
Definition: node.hxx:664
SwTableNode * GetTableNode()
Definition: node.hxx:648
bool InsBoxen(SwTableNode *, SwTableLine *, SwTableBoxFormat *, SwTextFormatColl *, const SfxItemSet *pAutoAttr, sal_uInt16 nInsPos, sal_uInt16 nCnt=1)
Insert a new box in the line before InsPos.
Definition: ndtbl.cxx:234
SwContentNode * GoNext(SwNodeIndex *) const
Definition: nodes.cxx:1294
SwNodeOffset Count() const
Definition: ndarr.hxx:142
PaM is Point and Mark: a selection of the document model.
Definition: pam.hxx:187
const SwPosition * End() const
Definition: pam.hxx:271
const SwPosition * Start() const
Definition: pam.hxx:266
RedlineType GetType(sal_uInt16 nPos=0) const
Definition: docredln.cxx:1940
const SwRedlineData & GetRedlineData(sal_uInt16 nPos=0) const
Definition: docredln.cxx:1963
Of course Writer needs its own rectangles.
Definition: swrect.hxx:35
void Height(tools::Long nNew)
Definition: swrect.hxx:193
void Width(tools::Long nNew)
Definition: swrect.hxx:189
const DateTime & GetTimeStamp() const
Definition: redline.hxx:130
bool empty() const
Definition: docary.hxx:266
static constexpr size_type npos
Definition: docary.hxx:223
size_type size() const
Definition: docary.hxx:267
vector_type::size_type size_type
Definition: docary.hxx:222
SwRowFrame is one table row in the document layout.
Definition: rowfrm.hxx:29
virtual sal_uInt16 GetSubType() const override
Definition: expfld.cxx:896
void SetSize(SwTableBox &rBox, const SwFormatFrameSize &rSz)
Definition: tblrwcl.cxx:3296
Starts a section of nodes in the document model.
Definition: node.hxx:348
const SwTabColsEntry & GetEntry(size_t nPos) const
Definition: tabcol.hxx:74
size_t Count() const
Definition: tabcol.hxx:65
void Remove(size_t nPos, size_t nCount=1)
Definition: tabcol.cxx:79
tools::Long GetLeft() const
Definition: tabcol.hxx:78
tools::Long GetRight() const
Definition: tabcol.hxx:79
tools::Long GetRightMax() const
Definition: tabcol.hxx:80
void SetHidden(size_t nPos, bool bValue)
Definition: tabcol.hxx:68
void Insert(tools::Long nValue, bool bValue, size_t nPos)
Definition: tabcol.cxx:69
SwTabFrame is one table in the document layout, containing rows (which contain cells).
Definition: tabfrm.hxx:47
SwTabFrame * FindMaster(bool bFirstMaster=false) const
Definition: flowfrm.cxx:773
bool IsInHeadline(const SwFrame &rFrame) const
Definition: tabfrm.cxx:5771
SwTableBox * GetTableBox()
void BoxAttributeChanged(SwTableBox &rBox, const SwTableBoxNumFormat *pNewFormat, const SwTableBoxFormula *pNewFormula, const SwTableBoxValue *pNewValue, const sal_uLong nOldFormat)
Definition: swtable.cxx:2384
virtual bool supportsFullDrawingLayerFillAttributeSet() const override
Definition: swtable.cxx:2605
virtual void SwClientNotify(const SwModify &, const SfxHint &) override
Definition: swtable.cxx:2549
double GetValue() const
Definition: cellatr.hxx:95
SwTableBox is one table cell in the document model.
Definition: swtable.hxx:426
SwTableLine * GetUpper()
Definition: swtable.hxx:460
void RemoveFromTable()
Definition: swtable.cxx:1864
SwNodeOffset IsValidNumTextNd(bool bCheckAttr=true) const
Definition: swtable.cxx:2684
void SetSaveUserColor(std::optional< Color > p)
Definition: swtable.hxx:520
bool IsEmpty(bool bWithRemainingNestedTable=true) const
Definition: swtable.cxx:2070
sal_uInt16 IsFormulaOrValueBox() const
Definition: swtable.cxx:2767
bool IsNumberChanged() const
Definition: swtable.cxx:2655
sal_Int32 getRowSpan() const
Definition: swtable.hxx:523
void ActualiseValueBox()
Definition: swtable.cxx:2786
SwNodeOffset GetSttIdx() const
Definition: swtable.cxx:2065
const std::optional< Color > & GetSaveUserColor() const
Definition: swtable.hxx:518
void setRowSpan(sal_Int32 nNewRowSpan)
Definition: swtable.cxx:77
OUString GetName() const
Definition: swtable.cxx:2012
const SwStartNode * m_pStartNode
Definition: swtable.hxx:435
static SwTableBoxFormat * CheckBoxFormat(SwTableBoxFormat *)
Definition: swtable.cxx:1893
void SetSaveNumFormatColor(std::optional< Color > p)
Definition: swtable.hxx:521
SwFrameFormat * GetFrameFormat()
Definition: swtable.hxx:464
SwTableLines & GetTabLines()
Definition: swtable.hxx:457
bool getDummyFlag() const
Definition: swtable.cxx:82
void setDummyFlag(bool bDummy)
Definition: swtable.cxx:87
bool HasNumContent(double &rNum, sal_uInt32 &rFormatIndex, bool &rIsEmptyTextNd) const
Definition: swtable.cxx:2620
Point GetCoordinates() const
Definition: swtable.cxx:1988
bool IsInHeadline(const SwTable *pTable) const
Definition: swtable.cxx:2049
virtual ~SwTableBox() override
Definition: swtable.cxx:1879
bool mbDummyFlag
Definition: swtable.hxx:441
const std::optional< Color > & GetSaveNumFormatColor() const
Definition: swtable.hxx:519
sal_Int32 mnRowSpan
Definition: swtable.hxx:440
const SwStartNode * GetSttNd() const
Definition: swtable.hxx:478
void RegisterToFormat(SwFormat &rFormat)
Definition: swtable.cxx:2976
SwTableLines m_aLines
Definition: swtable.hxx:434
void ChgFrameFormat(SwTableBoxFormat *pNewFormat, bool bNeedToReregister=true)
Definition: swtable.cxx:1953
SwTableBox(const SwTableBox &)=delete
SwFrameFormat * ClaimFrameFormat()
Definition: swtable.cxx:1917
const SwCellFrame * getCellFrame() const
Definition: swtable.cxx:2911
std::unique_ptr< Impl > m_pImpl
Definition: swtable.hxx:543
SwTableCellInfo(SwTableCellInfo const &)=delete
SwRect getRect() const
Definition: swtable.cxx:2944
const SwTableBox * getTableBox() const
Definition: swtable.cxx:2954
virtual bool supportsFullDrawingLayerFillAttributeSet() const override
Definition: swtable.cxx:2610
virtual bool supportsFullDrawingLayerFillAttributeSet() const override
Definition: swtable.cxx:2615
SwTableLine is one table row in the document model.
Definition: swtable.hxx:364
SwTableBoxes m_aBoxes
Definition: swtable.hxx:365
SwFrameFormat * GetFrameFormat()
Definition: swtable.hxx:386
SwTableLine(SwTableLineFormat *, sal_uInt16 nBoxes, SwTableBox *pUp)
Definition: swtable.cxx:1456
SwRedlineTable::size_type UpdateTextChangesOnly(SwRedlineTable::size_type &rRedlinePos, bool bUpdateProperty=true) const
Definition: swtable.cxx:1618
void ChgFrameFormat(SwTableLineFormat *pNewFormat)
Definition: swtable.cxx:1511
SwTwips GetTableLineHeight(bool &bLayoutAvailable) const
Definition: swtable.cxx:1521
SwFrameFormat * ClaimFrameFormat()
Definition: swtable.cxx:1478
void SetRedlineType(RedlineType eType)
Definition: swtable.hxx:421
SwTableBoxes & GetTabBoxes()
Definition: swtable.hxx:374
RedlineType GetRedlineType() const
Definition: swtable.cxx:1782
bool IsDeleted(SwRedlineTable::size_type &rRedlinePos) const
Definition: swtable.cxx:1769
RedlineType m_eRedlineType
Definition: swtable.hxx:367
bool IsEmpty() const
Definition: swtable.cxx:1563
sal_uInt16 GetBoxPos(const SwTableBox *pBox) const
Definition: swtable.hxx:376
virtual ~SwTableLine() override
Definition: swtable.cxx:1465
SwTableBox * GetUpper()
Definition: swtable.hxx:382
std::vector< SwTableLine * >::const_iterator const_iterator
Definition: swtable.hxx:70
size_type size() const
Definition: swtable.hxx:76
SwTableLine * back() const
Definition: swtable.hxx:82
iterator end()
Definition: swtable.hxx:79
SwTableLine * front() const
Definition: swtable.hxx:81
void reserve(size_type nSize)
Definition: swtable.hxx:93
iterator begin()
Definition: swtable.hxx:77
sal_uInt16 GetPos(const SwTableLine *pBox) const
Definition: swtable.hxx:98
bool empty() const
Definition: swtable.hxx:75
const SwTable & GetTable() const
Definition: node.hxx:542
SwTable is one table in the document model, containing rows (which contain cells).
Definition: swtable.hxx:113
void SetTabCols(const SwTabCols &rNew, const SwTabCols &rOld, const SwTableBox *pStart, bool bCurRowOnly)
Definition: swtable.cxx:819
bool IsEmpty() const
Definition: swtable.cxx:1573
virtual ~SwTable() override
Definition: swtable.cxx:215
SwTableNode * GetTableNode() const
Definition: swtable.cxx:2142
void SetHTMLTableLayout(std::shared_ptr< SwHTMLTableLayout > const &r)
Definition: swtable.cxx:2157
std::shared_ptr< SwHTMLTableLayout > m_xHTMLLayout
Definition: swtable.hxx:120
void LockModify()
Definition: swtable.hxx:187
SwTableSortBoxes m_TabSortContentBoxes
Definition: swtable.hxx:117
bool IsDeleted() const
Definition: swtable.cxx:1598
void AdjustWidths(const tools::Long nOld, const tools::Long nNew)
Definition: swtable.cxx:355
SwTableNode * m_pTableNode
Definition: swtable.hxx:126
SwTableLines & GetTabLines()
Definition: swtable.hxx:204
SwTableFormat * GetFrameFormat()
Definition: swtable.hxx:207
SwTableLines m_aLines
Definition: swtable.hxx:116
bool IsTableComplex() const
Definition: swtable.cxx:1441
void RegisterToFormat(SwFormat &rFormat)
Definition: swtable.cxx:2964
TableChgMode m_eTableChgMode
Definition: swtable.hxx:129
SwTable()
Definition: swtable.cxx:183
const SwTableBox * GetTableBox(const OUString &rName, const bool bPerformValidCheck=false) const
Definition: swtable.cxx:1340
bool HasDeletedRow() const
Definition: swtable.cxx:1583
virtual void SwClientNotify(const SwModify &, const SfxHint &) override
Definition: swtable.cxx:321
virtual bool GetInfo(SfxPoolItem &) const override
Definition: swtable.cxx:2101
static SwTable * FindTable(SwFrameFormat const *const pFormat)
Definition: swtable.cxx:2135
static sal_uInt16 GetBoxNum(OUString &rStr, bool bFirst=false, const bool bPerformValidCheck=false)
Definition: swtable.cxx:1280
void UnlockModify()
Definition: swtable.hxx:188
SwTableSortBoxes & GetTabSortBoxes()
Definition: swtable.hxx:265
bool m_bModifyLocked
Definition: swtable.hxx:138
void GetTabCols(SwTabCols &rToFill, const SwTableBox *pStart, bool bHidden=false, bool bCurRowOnly=false) const
Definition: swtable.cxx:514
tools::SvRef< SwServerObject > m_xRefObj
Definition: swtable.hxx:118
bool IsNewModel() const
Definition: swtable.hxx:191
void NewSetTabCols(Parm &rP, const SwTabCols &rNew, const SwTabCols &rOld, const SwTableBox *pStart, bool bCurRowOnly)
Definition: swtable.cxx:1161
void SetRefObject(SwServerObject *)
Definition: swtable.cxx:2149
bool HasLayout() const
Definition: swtable.cxx:2969
A wrapper around SfxPoolItem to store the start position of (usually) a text portion,...
Definition: txatbase.hxx:44
sal_Int32 GetStart() const
Definition: txatbase.hxx:88
sal_uInt16 Which() const
Definition: txatbase.hxx:116
const SwFormatField & GetFormatField() const
Definition: txatbase.hxx:199
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:111
virtual bool SetAttr(const SfxPoolItem &) override
overriding to handle change of certain paragraph attributes
Definition: ndtxt.cxx:5032
void EraseText(const SwContentIndex &rIdx, const sal_Int32 nCount=SAL_MAX_INT32, const SwInsertFlags nMode=SwInsertFlags::DEFAULT)
delete text content ATTENTION: must not be called with a range that overlaps the start of an attribut...
Definition: ndtxt.cxx:2763
OUString InsertText(const OUString &rStr, const SwContentIndex &rIdx, const SwInsertFlags nMode=SwInsertFlags::DEFAULT)
insert text content
Definition: ndtxt.cxx:2358
SwpHints * GetpSwpHints()
Definition: ndtxt.hxx:250
const OUString & GetText() const
Definition: ndtxt.hxx:242
bool DontExpandFormat(sal_Int32 nContentIdx, bool bFlag=true, bool bFormatToTextAttributes=true)
When appropriate set DontExpand-flag at INet or character styles respectively.
Definition: ndtxt.cxx:1667
virtual bool ResetAttr(sal_uInt16 nWhich1, sal_uInt16 nWhich2=0) override
Definition: ndtxt.cxx:5259
static ShellResource * GetShellRes()
Definition: viewsh.cxx:2650
An SwTextAttr container, stores all directly formatted text portions for a text node.
Definition: ndhints.hxx:68
SwTextAttr * Get(size_t nPos) const
Definition: ndhints.hxx:144
size_t Count() const
Definition: ndhints.hxx:142
size_type erase(const Value &x)
bool empty() const
size_type size() const
std::pair< const_iterator, bool > insert(Value &&x)
void RemoveServer(SvLinkSource *rObj)
T * get() const
bool is() const
RedlineType
int nCount
float u
TableChgMode GetTableChgDefaultMode()
Definition: edtwin3.cxx:103
EmbeddedObjectRef * pObject
@ Variable
Frame is variable in Var-direction.
constexpr TypedWhichId< SwFormatFootnote > RES_TXTATR_FTN(59)
constexpr TypedWhichId< SwFindNearestNode > RES_FINDNEARESTNODE(184)
constexpr TypedWhichId< SwTableBoxValue > RES_BOXATR_VALUE(152)
constexpr TypedWhichId< SwFormatFrameSize > RES_FRM_SIZE(89)
constexpr TypedWhichId< SwFormatPageDesc > RES_PAGEDESC(93)
constexpr TypedWhichId< SvxAdjustItem > RES_PARATR_ADJUST(64)
constexpr TypedWhichId< SwTableBoxFormula > RES_BOXATR_FORMULA(151)
constexpr TypedWhichId< SwFormatField > RES_TXTATR_ANNOTATION(60)
constexpr TypedWhichId< SwFormatField > RES_TXTATR_FIELD(RES_TXTATR_NOEND_BEGIN)
constexpr TypedWhichId< SwAttrSetChg > RES_ATTRSET_CHG(163)
constexpr TypedWhichId< SwTableBoxNumFormat > RES_BOXATR_FORMAT(RES_BOXATR_BEGIN)
constexpr TypedWhichId< SwAutoFormatGetDocNode > RES_AUTOFMT_DOCNODE(173)
constexpr TypedWhichId< SwFormatAutoFormat > RES_PARATR_LIST_AUTOFMT(87)
constexpr TypedWhichId< SvxPrintItem > RES_PRINT(98)
#define CH_TXTATR_INWORD
Definition: hintids.hxx:171
constexpr TypedWhichId< SwPtrMsgPoolItem > RES_CONTENT_VISIBLE(185)
constexpr TypedWhichId< SwFormatVertOrient > RES_VERT_ORIENT(102)
constexpr TypedWhichId< SvxColorItem > RES_CHRATR_COLOR(3)
sal_Int32 nIndex
void * p
sal_Int64 n
sal_uInt16 nPos
#define SAL_INFO_IF(condition, area, stream)
#define SAL_WARN_IF(condition, area, stream)
tools::Long const nBorder
size
int i
const SwExtendedSubType SUB_INVISIBLE
Invisible.
Definition: fldbas.hxx:213
sal_Int32 toInt32(std::u16string_view str, sal_Int16 radix=10)
None
long Long
o3tl::strong_int< sal_Int32, struct Tag_SwNodeOffset > SwNodeOffset
Definition: nodeoffset.hxx:16
constexpr SwNodeOffset NODE_OFFSET_MAX(SAL_MAX_INT32)
SwNodeOffset abs(const SwNodeOffset &a)
Definition: nodeoffset.hxx:34
const char GetValue[]
QPRO_FUNC_TYPE nType
static SfxItemSet & rSet
sal_uIntPtr sal_uLong
SwShareBoxFormats aShareFormats
Definition: swtable.cxx:605
const SwTabCols & rNew
Definition: swtable.cxx:600
tools::Long nOldWish
Definition: swtable.cxx:603
std::deque< SwTableBox * > aBoxArr
Definition: swtable.cxx:604
const SwTabCols & rOld
Definition: swtable.cxx:601
Parm(const SwTabCols &rN, const SwTabCols &rO)
Definition: swtable.cxx:607
tools::Long nNewWish
Definition: swtable.cxx:602
OUString aCalc_Error
Definition: shellres.hxx:41
Marks a position in the document model.
Definition: pam.hxx:37
SwNode & GetNode() const
Definition: pam.hxx:80
SwNodeIndex nNode
Definition: pam.hxx:38
SwNodeOffset GetNodeIndex() const
Definition: pam.hxx:77
sal_Int32 GetContentIndex() const
Definition: pam.hxx:84
tools::Long nPos
Definition: tabcol.hxx:30
tools::Long nMax
Definition: tabcol.hxx:32
tools::Long nMin
Definition: tabcol.hxx:31
const SwTable * m_pTable
Definition: swtable.cxx:2816
TableBoxes_t m_HandledTableBoxes
Definition: swtable.cxx:2820
const SwTabFrame * m_pTabFrame
Definition: swtable.cxx:2818
const SwCellFrame * m_pCellFrame
Definition: swtable.cxx:2817
const SwCellFrame * getNextCellFrame(const SwFrame *pFrame)
Definition: swtable.cxx:2876
void setTable(const SwTable *pTable)
Definition: swtable.cxx:2828
const SwCellFrame * getNextTableBoxsCellFrame(const SwFrame *pFrame)
Definition: swtable.cxx:2892
const SwCellFrame * getCellFrame() const
Definition: swtable.cxx:2837
o3tl::sorted_vector< const SwTableBox * > TableBoxes_t
Definition: swtable.cxx:2819
const SwFrame * getNextFrameInTable(const SwFrame *pFrame)
Definition: swtable.cxx:2845
sal_uInt16 GetWhich() const
Definition: calbck.hxx:75
SvxAdjust
std::list< ColChange > ChangeList
Definition: swtable.cxx:987
#define COLFUZZY
Definition: swtable.cxx:72
static void lcl_AdjustWidthsInLine(SwTableLine *pLine, ChangeList &rOldNew, Parm &rParm, sal_uInt16 nColFuzzy)
Definition: swtable.cxx:989
static void lcl_ProcessBoxPtr(SwTableBox *pBox, std::deque< SwTableBox * > &rBoxArr, bool bBefore)
Definition: swtable.cxx:776
std::pair< sal_uInt16, sal_uInt16 > ColChange
Definition: swtable.cxx:986
static void lcl_ProcessLine(SwTableLine *pLine, Parm &rParm)
Definition: swtable.cxx:614
static OUString & lcl_TabToBlankAtSttEnd(OUString &rText)
Definition: swtable.cxx:93
static void lcl_ProcessLineGet(const SwTableLine *pLine, SwTabCols &rToFill, const SwFrameFormat *pTabFormat)
Definition: swtable.cxx:500
static void ChgNumToText(SwTableBox &rBox, sal_uLong nFormat)
Definition: swtable.cxx:2296
static void lcl_ProcessBoxSet(SwTableBox *pBox, Parm &rParm)
Definition: swtable.cxx:624
static void lcl_ModifyLines(SwTableLines &rLines, const tools::Long nOld, const tools::Long nNew, std::vector< SwFormat * > &rFormatArr, const bool bCheckSum)
Definition: swtable.cxx:263
static void lcl_ModifyBoxes(SwTableBoxes &rBoxes, const tools::Long nOld, const tools::Long nNew, std::vector< SwFormat * > &rFormatArr)
Definition: swtable.cxx:281
static void lcl_ProcessBoxGet(const SwTableBox *pBox, SwTabCols &rToFill, const SwFrameFormat *pTabFormat, bool bRefreshHidden)
Definition: swtable.cxx:483
static void lcl_AdjustBox(SwTableBox *pBox, const tools::Long nDiff, Parm &rParm)
Definition: swtable.cxx:807
static void lcl_AdjustLines(SwTableLines &rLines, const tools::Long nDiff, Parm &rParm)
Definition: swtable.cxx:797
static void FormatInArr(std::vector< SwFormat * > &rFormatArr, SwFormat *pBoxFormat)
Definition: swtable.cxx:253
#define CHECK_TABLE(t)
Definition: swtable.cxx:64
static void lcl_CalcNewWidths(std::vector< sal_uInt16 > &rSpanPos, ChangeList &rChanges, SwTableLine *pLine, tools::Long nWish, tools::Long nWidth, bool bTop)
Definition: swtable.cxx:1038
static bool lcl_IsValidRowName(std::u16string_view rStr)
Definition: swtable.cxx:1265
static void ChgTextToNum(SwTableBox &rBox, const OUString &rText, const Color *pCol, bool bChgAlign, SwNodeOffset nNdPos)
Definition: swtable.cxx:2168
static void lcl_RefreshHidden(SwTabCols &rToFill, size_t nPos)
Definition: swtable.cxx:362
void DelBoxNode(SwTableSortBoxes const &rSortCntBoxes)
Definition: swtable.cxx:207
static void lcl_SortedTabColInsert(SwTabCols &rToFill, const SwTableBox *pBox, const SwFrameFormat *pTabFormat, const bool bHidden, const bool bRefreshHidden)
Definition: swtable.cxx:374
static OUString & lcl_DelTabsAtSttEnd(OUString &rText)
Definition: swtable.cxx:107
void sw_GetTableBoxColStr(sal_uInt16 nCol, OUString &rNm)
Definition: swtable.cxx:1969
void InsTableBox(SwDoc &rDoc, SwTableNode *pTableNd, SwTableLine *pLine, SwTableBoxFormat *pBoxFrameFormat, SwTableBox *pBox, sal_uInt16 nInsPos, sal_uInt16 nCnt)
Definition: swtable.cxx:127
std::vector< SwTableBox * > SwTableBoxes
Definition: swtable.hxx:105
tools::Long SwTwips
Definition: swtypes.hxx:51
sal_Int32 mnRowSpan
void CheckBoxWidth(const SwTableLine &rLine, SwTwips nSize)
Definition: tblrwcl.cxx:2584
#define SAL_MAX_UINT16
#define SAL_MAX_INT32
sal_uInt16 sal_Unicode