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