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