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