LibreOffice Module sw (master)  1
ndtbl.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 <memory>
21 #include <fesh.hxx>
22 #include <hintids.hxx>
23 #include <editeng/lrspitem.hxx>
24 #include <editeng/protitem.hxx>
25 #include <editeng/boxitem.hxx>
26 #include <svl/stritem.hxx>
27 #include <editeng/shaditem.hxx>
28 #include <fmtfsize.hxx>
29 #include <fmtornt.hxx>
30 #include <fmtfordr.hxx>
31 #include <fmtpdsc.hxx>
32 #include <fmtanchr.hxx>
33 #include <fmtlsplt.hxx>
34 #include <frmatr.hxx>
35 #include <cellfrm.hxx>
36 #include <pagefrm.hxx>
37 #include <tabcol.hxx>
38 #include <doc.hxx>
39 #include <IDocumentUndoRedo.hxx>
40 #include <UndoManager.hxx>
47 #include <IDocumentState.hxx>
48 #include <cntfrm.hxx>
49 #include <pam.hxx>
50 #include <swcrsr.hxx>
51 #include <swtable.hxx>
52 #include <swundo.hxx>
53 #include <tblsel.hxx>
54 #include <poolfmt.hxx>
55 #include <tabfrm.hxx>
56 #include <UndoCore.hxx>
57 #include <UndoRedline.hxx>
58 #include <UndoDelete.hxx>
59 #include <UndoNumbering.hxx>
60 #include <UndoTable.hxx>
61 #include <hints.hxx>
62 #include <tblafmt.hxx>
63 #include <frminf.hxx>
64 #include <cellatr.hxx>
65 #include <swtblfmt.hxx>
66 #include <swddetbl.hxx>
67 #include <mvsave.hxx>
68 #include <docary.hxx>
69 #include <redline.hxx>
70 #include <rolbck.hxx>
71 #include <tblrwcl.hxx>
72 #include <editsh.hxx>
73 #include <txtfrm.hxx>
74 #include <section.hxx>
75 #include <frmtool.hxx>
76 #include <node2lay.hxx>
77 #include <strings.hrc>
78 #include <docsh.hxx>
79 #include <unochart.hxx>
80 #include <node.hxx>
81 #include <ndtxt.hxx>
82 #include <cstdlib>
83 #include <map>
84 #include <algorithm>
85 #include <rootfrm.hxx>
86 #include <fldupde.hxx>
87 #include <calbck.hxx>
88 #include <fntcache.hxx>
89 #include <frameformats.hxx>
90 #include <o3tl/numeric.hxx>
91 #include <tools/datetimeutils.hxx>
92 #include <sal/log.hxx>
93 
94 #ifdef DBG_UTIL
95 #define CHECK_TABLE(t) (t).CheckConsistency();
96 #else
97 #define CHECK_TABLE(t)
98 #endif
99 
100 using ::editeng::SvxBorderLine;
101 using namespace ::com::sun::star;
102 
103 const sal_Unicode T2T_PARA = 0x0a;
104 
105 static void lcl_SetDfltBoxAttr( SwFrameFormat& rFormat, sal_uInt8 nId )
106 {
107  bool bTop = false, bBottom = false, bLeft = false, bRight = false;
108  switch ( nId )
109  {
110  case 0: bTop = bBottom = bLeft = true; break;
111  case 1: bTop = bBottom = bLeft = bRight = true; break;
112  case 2: bBottom = bLeft = true; break;
113  case 3: bBottom = bLeft = bRight = true; break;
114  }
115 
116  const bool bHTML = rFormat.getIDocumentSettingAccess().get(DocumentSettingId::HTML_MODE);
117  Color aCol( bHTML ? COL_GRAY : COL_BLACK );
118  SvxBorderLine aLine( &aCol, DEF_LINE_WIDTH_0 );
119  if ( bHTML )
120  {
121  aLine.SetBorderLineStyle(SvxBorderLineStyle::DOUBLE);
122  aLine.SetWidth( DEF_LINE_WIDTH_0 );
123  }
124  SvxBoxItem aBox(RES_BOX);
125  aBox.SetAllDistances(55);
126  if ( bTop )
127  aBox.SetLine( &aLine, SvxBoxItemLine::TOP );
128  if ( bBottom )
129  aBox.SetLine( &aLine, SvxBoxItemLine::BOTTOM );
130  if ( bLeft )
131  aBox.SetLine( &aLine, SvxBoxItemLine::LEFT );
132  if ( bRight )
133  aBox.SetLine( &aLine, SvxBoxItemLine::RIGHT );
134  rFormat.SetFormatAttr( aBox );
135 }
136 
137 typedef std::map<SwFrameFormat *, SwTableBoxFormat *> DfltBoxAttrMap_t;
138 typedef std::vector<DfltBoxAttrMap_t *> DfltBoxAttrList_t;
139 
140 static void
142  sal_uInt8 const nId, SwTableAutoFormat const*const pAutoFormat = nullptr)
143 {
144  DfltBoxAttrMap_t * pMap = rBoxFormatArr[ nId ];
145  if (!pMap)
146  {
147  pMap = new DfltBoxAttrMap_t;
148  rBoxFormatArr[ nId ] = pMap;
149  }
150 
151  SwTableBoxFormat* pNewTableBoxFormat = nullptr;
152  SwFrameFormat* pBoxFrameFormat = rBox.GetFrameFormat();
153  DfltBoxAttrMap_t::iterator const iter(pMap->find(pBoxFrameFormat));
154  if (pMap->end() != iter)
155  {
156  pNewTableBoxFormat = iter->second;
157  }
158  else
159  {
160  SwDoc* pDoc = pBoxFrameFormat->GetDoc();
161  // format does not exist, so create it
162  pNewTableBoxFormat = pDoc->MakeTableBoxFormat();
163  pNewTableBoxFormat->SetFormatAttr( pBoxFrameFormat->GetAttrSet().Get( RES_FRM_SIZE ) );
164 
165  if( pAutoFormat )
166  pAutoFormat->UpdateToSet( nId, false, false,
167  const_cast<SfxItemSet&>(static_cast<SfxItemSet const &>(pNewTableBoxFormat->GetAttrSet())),
169  pDoc->GetNumberFormatter() );
170  else
171  ::lcl_SetDfltBoxAttr( *pNewTableBoxFormat, nId );
172 
173  (*pMap)[pBoxFrameFormat] = pNewTableBoxFormat;
174  }
175  rBox.ChgFrameFormat( pNewTableBoxFormat );
176 }
177 
178 static SwTableBoxFormat *lcl_CreateDfltBoxFormat( SwDoc &rDoc, std::vector<SwTableBoxFormat*> &rBoxFormatArr,
179  sal_uInt16 nCols, sal_uInt8 nId )
180 {
181  if ( !rBoxFormatArr[nId] )
182  {
183  SwTableBoxFormat* pBoxFormat = rDoc.MakeTableBoxFormat();
184  if( USHRT_MAX != nCols )
186  USHRT_MAX / nCols, 0 ));
187  ::lcl_SetDfltBoxAttr( *pBoxFormat, nId );
188  rBoxFormatArr[ nId ] = pBoxFormat;
189  }
190  return rBoxFormatArr[nId];
191 }
192 
193 static SwTableBoxFormat *lcl_CreateAFormatBoxFormat( SwDoc &rDoc, std::vector<SwTableBoxFormat*> &rBoxFormatArr,
194  const SwTableAutoFormat& rAutoFormat,
195  const sal_uInt16 nRows, const sal_uInt16 nCols, sal_uInt8 nId )
196 {
197  if( !rBoxFormatArr[nId] )
198  {
199  SwTableBoxFormat* pBoxFormat = rDoc.MakeTableBoxFormat();
200  rAutoFormat.UpdateToSet( nId, nRows==1, nCols==1,
201  const_cast<SfxItemSet&>(static_cast<SfxItemSet const &>(pBoxFormat->GetAttrSet())),
203  rDoc.GetNumberFormatter( ) );
204  if( USHRT_MAX != nCols )
206  USHRT_MAX / nCols, 0 ));
207  rBoxFormatArr[ nId ] = pBoxFormat;
208  }
209  return rBoxFormatArr[nId];
210 }
211 
213 {
214  SwTableNode* pTableNd = nullptr;
215  sal_uLong nIndex = rIdx.GetIndex();
216  do {
217  SwNode* pNd = GetNodes()[ nIndex ]->StartOfSectionNode();
218  pTableNd = pNd->GetTableNode();
219  if( nullptr != pTableNd )
220  break;
221 
222  nIndex = pNd->GetIndex();
223  } while ( nIndex );
224  return pTableNd;
225 }
226 
231  SwTableLine* pLine,
232  SwTableBoxFormat* pBoxFormat,
233  SwTextFormatColl* pTextColl,
234  const SfxItemSet* pAutoAttr,
235  sal_uInt16 nInsPos,
236  sal_uInt16 nCnt )
237 {
238  if( !nCnt )
239  return false;
240  OSL_ENSURE( pLine, "No valid Line" );
241 
242  // Move Index after the Line's last Box
243  sal_uLong nIdxPos = 0;
244  SwTableBox *pPrvBox = nullptr, *pNxtBox = nullptr;
245  if( !pLine->GetTabBoxes().empty() )
246  {
247  if( nInsPos < pLine->GetTabBoxes().size() )
248  {
249  pPrvBox = pLine->FindPreviousBox( pTableNd->GetTable(),
250  pLine->GetTabBoxes()[ nInsPos ] );
251  if( nullptr == pPrvBox )
252  pPrvBox = pLine->FindPreviousBox( pTableNd->GetTable() );
253  }
254  else
255  {
256  pNxtBox = pLine->FindNextBox( pTableNd->GetTable(),
257  pLine->GetTabBoxes().back() );
258  if( nullptr == pNxtBox )
259  pNxtBox = pLine->FindNextBox( pTableNd->GetTable() );
260  }
261  }
262  else
263  {
264  pNxtBox = pLine->FindNextBox( pTableNd->GetTable() );
265  if( nullptr == pNxtBox )
266  pPrvBox = pLine->FindPreviousBox( pTableNd->GetTable() );
267  }
268 
269  if( !pPrvBox && !pNxtBox )
270  {
271  bool bSetIdxPos = true;
272  if( !pTableNd->GetTable().GetTabLines().empty() && !nInsPos )
273  {
274  const SwTableLine* pTableLn = pLine;
275  while( pTableLn->GetUpper() )
276  pTableLn = pTableLn->GetUpper()->GetUpper();
277 
278  if( pTableNd->GetTable().GetTabLines()[ 0 ] == pTableLn )
279  {
280  // Before the Table's first Box
281  while( !( pNxtBox = pLine->GetTabBoxes()[0])->GetTabLines().empty() )
282  pLine = pNxtBox->GetTabLines()[0];
283  nIdxPos = pNxtBox->GetSttIdx();
284  bSetIdxPos = false;
285  }
286  }
287  if( bSetIdxPos )
288  // Tables without content or at the end; move before the End
289  nIdxPos = pTableNd->EndOfSectionIndex();
290  }
291  else if( pNxtBox ) // There is a successor
292  nIdxPos = pNxtBox->GetSttIdx();
293  else // There is a predecessor
294  nIdxPos = pPrvBox->GetSttNd()->EndOfSectionIndex() + 1;
295 
296  SwNodeIndex aEndIdx( *this, nIdxPos );
297  for( sal_uInt16 n = 0; n < nCnt; ++n )
298  {
299  SwStartNode* pSttNd = new SwStartNode( aEndIdx, SwNodeType::Start,
301  pSttNd->m_pStartOfSection = pTableNd;
302  new SwEndNode( aEndIdx, *pSttNd );
303 
304  pPrvBox = new SwTableBox( pBoxFormat, *pSttNd, pLine );
305 
306  SwTableBoxes & rTabBoxes = pLine->GetTabBoxes();
307  sal_uInt16 nRealInsPos = nInsPos + n;
308  if (nRealInsPos > rTabBoxes.size())
309  nRealInsPos = rTabBoxes.size();
310 
311  rTabBoxes.insert( rTabBoxes.begin() + nRealInsPos, pPrvBox );
312 
313  if( ! pTextColl->IsAssignedToListLevelOfOutlineStyle()
314 //FEATURE::CONDCOLL
315  && RES_CONDTXTFMTCOLL != pTextColl->Which()
316 //FEATURE::CONDCOLL
317  )
318  new SwTextNode( SwNodeIndex( *pSttNd->EndOfSectionNode() ),
319  pTextColl, pAutoAttr );
320  else
321  {
322  // Handle Outline numbering correctly!
323  SwTextNode* pTNd = new SwTextNode(
324  SwNodeIndex( *pSttNd->EndOfSectionNode() ),
326  pAutoAttr );
327  pTNd->ChgFormatColl( pTextColl );
328  }
329  }
330  return true;
331 }
332 
336 const SwTable* SwDoc::InsertTable( const SwInsertTableOptions& rInsTableOpts,
337  const SwPosition& rPos, sal_uInt16 nRows,
338  sal_uInt16 nCols, sal_Int16 eAdjust,
339  const SwTableAutoFormat* pTAFormat,
340  const std::vector<sal_uInt16> *pColArr,
341  bool bCalledFromShell,
342  bool bNewModel )
343 {
344  assert(nRows && "Table without line?");
345  assert(nCols && "Table without rows?");
346 
347  {
348  // Do not copy into Footnotes!
349  if( rPos.nNode < GetNodes().GetEndOfInserts().GetIndex() &&
350  rPos.nNode >= GetNodes().GetEndOfInserts().StartOfSectionIndex() )
351  return nullptr;
352 
353  // If the ColumnArray has a wrong count, ignore it!
354  if( pColArr &&
355  static_cast<size_t>(nCols + ( text::HoriOrientation::NONE == eAdjust ? 2 : 1 )) != pColArr->size() )
356  pColArr = nullptr;
357  }
358 
359  OUString aTableName = GetUniqueTableName();
360 
361  if( GetIDocumentUndoRedo().DoesUndo() )
362  {
364  std::make_unique<SwUndoInsTable>( rPos, nCols, nRows, static_cast<sal_uInt16>(eAdjust),
365  rInsTableOpts, pTAFormat, pColArr,
366  aTableName));
367  }
368 
369  // Start with inserting the Nodes and get the AutoFormat for the Table
371  *pHeadColl = pBodyColl;
372 
373  bool bDfltBorders( rInsTableOpts.mnInsMode & SwInsertTableFlags::DefaultBorder );
374 
375  if( (rInsTableOpts.mnInsMode & SwInsertTableFlags::Headline) && (1 != nRows || !bDfltBorders) )
377 
378  const sal_uInt16 nRowsToRepeat =
380  rInsTableOpts.mnRowsToRepeat :
381  0;
382 
383  /* Save content node to extract FRAMEDIR from. */
384  const SwContentNode * pContentNd = rPos.nNode.GetNode().GetContentNode();
385 
386  /* If we are called from a shell pass the attrset from
387  pContentNd (aka the node the table is inserted at) thus causing
388  SwNodes::InsertTable to propagate an adjust item if
389  necessary. */
390  SwTableNode *pTableNd = SwNodes::InsertTable(
391  rPos.nNode,
392  nCols,
393  pBodyColl,
394  nRows,
395  nRowsToRepeat,
396  pHeadColl,
397  bCalledFromShell ? &pContentNd->GetSwAttrSet() : nullptr );
398 
399  // Create the Box/Line/Table construct
400  SwTableLineFormat* pLineFormat = MakeTableLineFormat();
401  SwTableFormat* pTableFormat = MakeTableFrameFormat( aTableName, GetDfltFrameFormat() );
402 
403  /* If the node to insert the table at is a context node and has a
404  non-default FRAMEDIR propagate it to the table. */
405  if (pContentNd)
406  {
407  const SwAttrSet & aNdSet = pContentNd->GetSwAttrSet();
408  const SfxPoolItem *pItem = nullptr;
409 
410  if (SfxItemState::SET == aNdSet.GetItemState( RES_FRAMEDIR, true, &pItem )
411  && pItem != nullptr)
412  {
413  pTableFormat->SetFormatAttr( *pItem );
414  }
415  }
416 
417  // Set Orientation at the Table's Format
418  pTableFormat->SetFormatAttr( SwFormatHoriOrient( 0, eAdjust ) );
419  // All lines use the left-to-right Fill-Order!
420  pLineFormat->SetFormatAttr( SwFormatFillOrder( ATT_LEFT_TO_RIGHT ));
421 
422  // Set USHRT_MAX as the Table's default SSize
423  SwTwips nWidth = USHRT_MAX;
424  if( pColArr )
425  {
426  sal_uInt16 nSttPos = pColArr->front();
427  sal_uInt16 nLastPos = pColArr->back();
428  if( text::HoriOrientation::NONE == eAdjust )
429  {
430  sal_uInt16 nFrameWidth = nLastPos;
431  nLastPos = (*pColArr)[ pColArr->size()-2 ];
432  pTableFormat->SetFormatAttr( SvxLRSpaceItem( nSttPos, nFrameWidth - nLastPos, 0, 0, RES_LR_SPACE ) );
433  }
434  nWidth = nLastPos - nSttPos;
435  }
436  else
437  {
438  nWidth /= nCols;
439  nWidth *= nCols; // to avoid rounding problems
440  }
441  pTableFormat->SetFormatAttr( SwFormatFrameSize( SwFrameSize::Variable, nWidth ));
442  if( !(rInsTableOpts.mnInsMode & SwInsertTableFlags::SplitLayout) )
443  pTableFormat->SetFormatAttr( SwFormatLayoutSplit( false ));
444 
445  // Move the hard PageDesc/PageBreak Attributes if needed
446  SwContentNode* pNextNd = GetNodes()[ pTableNd->EndOfSectionIndex()+1 ]
447  ->GetContentNode();
448  if( pNextNd && pNextNd->HasSwAttrSet() )
449  {
450  const SfxItemSet* pNdSet = pNextNd->GetpSwAttrSet();
451  const SfxPoolItem *pItem;
452  if( SfxItemState::SET == pNdSet->GetItemState( RES_PAGEDESC, false,
453  &pItem ) )
454  {
455  pTableFormat->SetFormatAttr( *pItem );
456  pNextNd->ResetAttr( RES_PAGEDESC );
457  pNdSet = pNextNd->GetpSwAttrSet();
458  }
459  if( pNdSet && SfxItemState::SET == pNdSet->GetItemState( RES_BREAK, false,
460  &pItem ) )
461  {
462  pTableFormat->SetFormatAttr( *pItem );
463  pNextNd->ResetAttr( RES_BREAK );
464  }
465  }
466 
467  SwTable& rNdTable = pTableNd->GetTable();
468  rNdTable.RegisterToFormat( *pTableFormat );
469 
470  rNdTable.SetRowsToRepeat( nRowsToRepeat );
471  rNdTable.SetTableModel( bNewModel );
472 
473  std::vector<SwTableBoxFormat*> aBoxFormatArr;
474  SwTableBoxFormat* pBoxFormat = nullptr;
475  if( !bDfltBorders && !pTAFormat )
476  {
477  pBoxFormat = MakeTableBoxFormat();
478  pBoxFormat->SetFormatAttr( SwFormatFrameSize( SwFrameSize::Variable, USHRT_MAX / nCols, 0 ));
479  }
480  else
481  {
482  const sal_uInt16 nBoxArrLen = pTAFormat ? 16 : 4;
483  aBoxFormatArr.resize( nBoxArrLen, nullptr );
484  }
486 
487  SwNodeIndex aNdIdx( *pTableNd, 1 ); // Set to StartNode of first Box
488  SwTableLines& rLines = rNdTable.GetTabLines();
489  for( sal_uInt16 n = 0; n < nRows; ++n )
490  {
491  SwTableLine* pLine = new SwTableLine( pLineFormat, nCols, nullptr );
492  rLines.insert( rLines.begin() + n, pLine );
493  SwTableBoxes& rBoxes = pLine->GetTabBoxes();
494  for( sal_uInt16 i = 0; i < nCols; ++i )
495  {
496  SwTableBoxFormat *pBoxF;
497  if( pTAFormat )
498  {
499  sal_uInt8 nId = SwTableAutoFormat::CountPos(i, nCols, n, nRows);
500  pBoxF = ::lcl_CreateAFormatBoxFormat( *this, aBoxFormatArr, *pTAFormat,
501  nRows, nCols, nId );
502 
503  // Set the Paragraph/Character Attributes if needed
504  if( pTAFormat->IsFont() || pTAFormat->IsJustify() )
505  {
506  aCharSet.ClearItem();
507  pTAFormat->UpdateToSet( nId, nRows==1, nCols==1, aCharSet,
509  if( aCharSet.Count() )
510  GetNodes()[ aNdIdx.GetIndex()+1 ]->GetContentNode()->
511  SetAttr( aCharSet );
512  }
513  }
514  else if( bDfltBorders )
515  {
516  sal_uInt8 nBoxId = (i < nCols - 1 ? 0 : 1) + (n ? 2 : 0 );
517  pBoxF = ::lcl_CreateDfltBoxFormat( *this, aBoxFormatArr, nCols, nBoxId);
518  }
519  else
520  pBoxF = pBoxFormat;
521 
522  // For AutoFormat on input: the columns are set when inserting the Table
523  // The Array contains the columns positions and not their widths!
524  if( pColArr )
525  {
526  nWidth = (*pColArr)[ i + 1 ] - (*pColArr)[ i ];
527  if( pBoxF->GetFrameSize().GetWidth() != nWidth )
528  {
529  if( pBoxF->HasWriterListeners() ) // Create new Format
530  {
531  SwTableBoxFormat *pNewFormat = MakeTableBoxFormat();
532  *pNewFormat = *pBoxF;
533  pBoxF = pNewFormat;
534  }
536  }
537  }
538 
539  SwTableBox *pBox = new SwTableBox( pBoxF, aNdIdx, pLine);
540  rBoxes.insert( rBoxes.begin() + i, pBox );
541  aNdIdx += 3; // StartNode, TextNode, EndNode == 3 Nodes
542  }
543  }
544  // Insert Frames
545  GetNodes().GoNext( &aNdIdx ); // Go to the next ContentNode
546  pTableNd->MakeOwnFrames( &aNdIdx );
547 
548  // To-Do - add 'SwExtraRedlineTable' also ?
549  if( getIDocumentRedlineAccess().IsRedlineOn() || (!getIDocumentRedlineAccess().IsIgnoreRedline() && !getIDocumentRedlineAccess().GetRedlineTable().empty() ))
550  {
551  SwPaM aPam( *pTableNd->EndOfSectionNode(), *pTableNd, 1 );
553  getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline( RedlineType::Insert, aPam ), true);
554  else
556  }
557 
559  CHECK_TABLE(rNdTable);
560  return &rNdTable;
561 }
562 
564  sal_uInt16 nBoxes,
565  SwTextFormatColl* pContentTextColl,
566  sal_uInt16 nLines,
567  sal_uInt16 nRepeat,
568  SwTextFormatColl* pHeadlineTextColl,
569  const SwAttrSet * pAttrSet)
570 {
571  if( !nBoxes )
572  return nullptr;
573 
574  // If Lines is given, create the Matrix from Lines and Boxes
575  if( !pHeadlineTextColl || !nLines )
576  pHeadlineTextColl = pContentTextColl;
577 
578  SwTableNode * pTableNd = new SwTableNode( rNdIdx );
579  SwEndNode* pEndNd = new SwEndNode( rNdIdx, *pTableNd );
580 
581  if( !nLines ) // For the for loop
582  ++nLines;
583 
584  SwNodeIndex aIdx( *pEndNd );
585  SwTextFormatColl* pTextColl = pHeadlineTextColl;
586  for( sal_uInt16 nL = 0; nL < nLines; ++nL )
587  {
588  for( sal_uInt16 nB = 0; nB < nBoxes; ++nB )
589  {
590  SwStartNode* pSttNd = new SwStartNode( aIdx, SwNodeType::Start,
592  pSttNd->m_pStartOfSection = pTableNd;
593 
594  SwTextNode * pTmpNd = new SwTextNode( aIdx, pTextColl );
595 
596  // #i60422# Propagate some more attributes.
597  const SfxPoolItem* pItem = nullptr;
598  if ( nullptr != pAttrSet )
599  {
600  static const sal_uInt16 aPropagateItems[] = {
605 
606  const sal_uInt16* pIdx = aPropagateItems;
607  while ( *pIdx != 0 )
608  {
609  if ( SfxItemState::SET != pTmpNd->GetSwAttrSet().GetItemState( *pIdx ) &&
610  SfxItemState::SET == pAttrSet->GetItemState( *pIdx, true, &pItem ) )
611  static_cast<SwContentNode *>(pTmpNd)->SetAttr(*pItem);
612  ++pIdx;
613  }
614  }
615 
616  new SwEndNode( aIdx, *pSttNd );
617  }
618  if ( nL + 1 >= nRepeat )
619  pTextColl = pContentTextColl;
620  }
621  return pTableNd;
622 }
623 
627 const SwTable* SwDoc::TextToTable( const SwInsertTableOptions& rInsTableOpts,
628  const SwPaM& rRange, sal_Unicode cCh,
629  sal_Int16 eAdjust,
630  const SwTableAutoFormat* pTAFormat )
631 {
632  // See if the selection contains a Table
633  const SwPosition *pStt = rRange.Start(), *pEnd = rRange.End();
634  {
635  sal_uLong nCnt = pStt->nNode.GetIndex();
636  for( ; nCnt <= pEnd->nNode.GetIndex(); ++nCnt )
637  if( !GetNodes()[ nCnt ]->IsTextNode() )
638  return nullptr;
639  }
640 
641  // Save first node in the selection if it is a context node
642  SwContentNode * pSttContentNd = pStt->nNode.GetNode().GetContentNode();
643 
644  SwPaM aOriginal( *pStt, *pEnd );
645  pStt = aOriginal.GetMark();
646  pEnd = aOriginal.GetPoint();
647 
648  SwUndoTextToTable* pUndo = nullptr;
649  if( GetIDocumentUndoRedo().DoesUndo() )
650  {
652  pUndo = new SwUndoTextToTable( aOriginal, rInsTableOpts, cCh,
653  static_cast<sal_uInt16>(eAdjust), pTAFormat );
654  GetIDocumentUndoRedo().AppendUndo( std::unique_ptr<SwUndo>(pUndo) );
655 
656  // Do not add splitting the TextNode to the Undo history
657  GetIDocumentUndoRedo().DoUndo( false );
658  }
659 
660  ::PaMCorrAbs( aOriginal, *pEnd );
661 
662  // Make sure that the range is on Node Edges
663  SwNodeRange aRg( pStt->nNode, pEnd->nNode );
664  if( pStt->nContent.GetIndex() )
665  getIDocumentContentOperations().SplitNode( *pStt, false );
666 
667  bool bEndContent = 0 != pEnd->nContent.GetIndex();
668 
669  // Do not split at the End of a Line (except at the End of the Doc)
670  if( bEndContent )
671  {
672  if( pEnd->nNode.GetNode().GetContentNode()->Len() != pEnd->nContent.GetIndex()
673  || pEnd->nNode.GetIndex() >= GetNodes().GetEndOfContent().GetIndex()-1 )
674  {
675  getIDocumentContentOperations().SplitNode( *pEnd, false );
676  --const_cast<SwNodeIndex&>(pEnd->nNode);
677  const_cast<SwIndex&>(pEnd->nContent).Assign(
678  pEnd->nNode.GetNode().GetContentNode(), 0 );
679  // A Node and at the End?
680  if( pStt->nNode.GetIndex() >= pEnd->nNode.GetIndex() )
681  --aRg.aStart;
682  }
683  else
684  ++aRg.aEnd;
685  }
686 
687  if( aRg.aEnd.GetIndex() == aRg.aStart.GetIndex() )
688  {
689  OSL_FAIL( "empty range" );
690  ++aRg.aEnd;
691  }
692 
693  // We always use Upper to insert the Table
694  SwNode2LayoutSaveUpperFrames aNode2Layout( aRg.aStart.GetNode() );
695 
696  GetIDocumentUndoRedo().DoUndo( nullptr != pUndo );
697 
698  // Create the Box/Line/Table construct
699  SwTableBoxFormat* pBoxFormat = MakeTableBoxFormat();
700  SwTableLineFormat* pLineFormat = MakeTableLineFormat();
702 
703  // All Lines have a left-to-right Fill Order
705  // The Table's SSize is USHRT_MAX
707  if( !(rInsTableOpts.mnInsMode & SwInsertTableFlags::SplitLayout) )
708  pTableFormat->SetFormatAttr( SwFormatLayoutSplit( false ));
709 
710  /* If the first node in the selection is a context node and if it
711  has an item FRAMEDIR set (no default) propagate the item to the
712  replacing table. */
713  if (pSttContentNd)
714  {
715  const SwAttrSet & aNdSet = pSttContentNd->GetSwAttrSet();
716  const SfxPoolItem *pItem = nullptr;
717 
718  if (SfxItemState::SET == aNdSet.GetItemState( RES_FRAMEDIR, true, &pItem )
719  && pItem != nullptr)
720  {
721  pTableFormat->SetFormatAttr( *pItem );
722  }
723  }
724 
725  //Resolves: tdf#87977, tdf#78599, disable broadcasting modifications
726  //until after RegisterToFormat is completed
727  bool bEnableSetModified = getIDocumentState().IsEnableSetModified();
729 
730  SwTableNode* pTableNd = GetNodes().TextToTable(
731  aRg, cCh, pTableFormat, pLineFormat, pBoxFormat,
732  getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_STANDARD ), pUndo );
733 
734  SwTable& rNdTable = pTableNd->GetTable();
735 
736  const sal_uInt16 nRowsToRepeat =
738  rInsTableOpts.mnRowsToRepeat :
739  0;
740  rNdTable.SetRowsToRepeat(nRowsToRepeat);
741 
742  bool bUseBoxFormat = false;
743  if( !pBoxFormat->HasWriterListeners() )
744  {
745  // The Box's Formats already have the right size, we must only set
746  // the right Border/AutoFormat.
747  bUseBoxFormat = true;
748  pTableFormat->SetFormatAttr( pBoxFormat->GetFrameSize() );
749  delete pBoxFormat;
750  eAdjust = text::HoriOrientation::NONE;
751  }
752 
753  // Set Orientation in the Table's Format
754  pTableFormat->SetFormatAttr( SwFormatHoriOrient( 0, eAdjust ) );
755  rNdTable.RegisterToFormat(*pTableFormat);
756 
757  if( pTAFormat || ( rInsTableOpts.mnInsMode & SwInsertTableFlags::DefaultBorder) )
758  {
759  sal_uInt8 nBoxArrLen = pTAFormat ? 16 : 4;
760  std::unique_ptr< DfltBoxAttrList_t > aBoxFormatArr1;
761  std::unique_ptr< std::vector<SwTableBoxFormat*> > aBoxFormatArr2;
762  if( bUseBoxFormat )
763  {
764  aBoxFormatArr1.reset(new DfltBoxAttrList_t( nBoxArrLen, nullptr ));
765  }
766  else
767  {
768  aBoxFormatArr2.reset(new std::vector<SwTableBoxFormat*>( nBoxArrLen, nullptr ));
769  }
770 
772 
773  SwHistory* pHistory = pUndo ? &pUndo->GetHistory() : nullptr;
774 
775  SwTableBoxFormat *pBoxF = nullptr;
776  SwTableLines& rLines = rNdTable.GetTabLines();
777  const SwTableLines::size_type nRows = rLines.size();
778  for( SwTableLines::size_type n = 0; n < nRows; ++n )
779  {
780  SwTableBoxes& rBoxes = rLines[ n ]->GetTabBoxes();
781  const SwTableBoxes::size_type nCols = rBoxes.size();
782  for( SwTableBoxes::size_type i = 0; i < nCols; ++i )
783  {
784  SwTableBox* pBox = rBoxes[ i ];
785  bool bChgSz = false;
786 
787  if( pTAFormat )
788  {
789  sal_uInt8 nId = static_cast<sal_uInt8>(!n ? 0 : (( n+1 == nRows )
790  ? 12 : (4 * (1 + ((n-1) & 1 )))));
791  nId = nId + static_cast<sal_uInt8>(!i ? 0 :
792  ( i+1 == nCols ? 3 : (1 + ((i-1) & 1))));
793  if( bUseBoxFormat )
794  ::lcl_SetDfltBoxAttr( *pBox, *aBoxFormatArr1, nId, pTAFormat );
795  else
796  {
797  bChgSz = nullptr == (*aBoxFormatArr2)[ nId ];
798  pBoxF = ::lcl_CreateAFormatBoxFormat( *this, *aBoxFormatArr2,
799  *pTAFormat, USHRT_MAX, USHRT_MAX, nId );
800  }
801 
802  // Set Paragraph/Character Attributes if needed
803  if( pTAFormat->IsFont() || pTAFormat->IsJustify() )
804  {
805  aCharSet.ClearItem();
806  pTAFormat->UpdateToSet( nId, nRows==1, nCols==1, aCharSet,
808  if( aCharSet.Count() )
809  {
810  sal_uLong nSttNd = pBox->GetSttIdx()+1;
811  sal_uLong nEndNd = pBox->GetSttNd()->EndOfSectionIndex();
812  for( ; nSttNd < nEndNd; ++nSttNd )
813  {
814  SwContentNode* pNd = GetNodes()[ nSttNd ]->GetContentNode();
815  if( pNd )
816  {
817  if( pHistory )
818  {
819  SwRegHistory aReg( pNd, *pNd, pHistory );
820  pNd->SetAttr( aCharSet );
821  }
822  else
823  pNd->SetAttr( aCharSet );
824  }
825  }
826  }
827  }
828  }
829  else
830  {
831  sal_uInt8 nId = (i < nCols - 1 ? 0 : 1) + (n ? 2 : 0 );
832  if( bUseBoxFormat )
833  ::lcl_SetDfltBoxAttr( *pBox, *aBoxFormatArr1, nId );
834  else
835  {
836  bChgSz = nullptr == (*aBoxFormatArr2)[ nId ];
837  pBoxF = ::lcl_CreateDfltBoxFormat( *this, *aBoxFormatArr2,
838  USHRT_MAX, nId );
839  }
840  }
841 
842  if( !bUseBoxFormat )
843  {
844  if( bChgSz )
845  pBoxF->SetFormatAttr( pBox->GetFrameFormat()->GetFrameSize() );
846  pBox->ChgFrameFormat( pBoxF );
847  }
848  }
849  }
850 
851  if( bUseBoxFormat )
852  {
853  for( sal_uInt8 i = 0; i < nBoxArrLen; ++i )
854  {
855  delete (*aBoxFormatArr1)[ i ];
856  }
857  }
858  }
859 
860  // Check the boxes for numbers
861  if( IsInsTableFormatNum() )
862  {
863  for (size_t nBoxes = rNdTable.GetTabSortBoxes().size(); nBoxes; )
864  {
865  ChkBoxNumFormat(*rNdTable.GetTabSortBoxes()[ --nBoxes ], false);
866  }
867  }
868 
869  sal_uLong nIdx = pTableNd->GetIndex();
870  aNode2Layout.RestoreUpperFrames( GetNodes(), nIdx, nIdx + 1 );
871 
872  {
873  SwPaM& rTmp = const_cast<SwPaM&>(rRange); // Point always at the Start
874  rTmp.DeleteMark();
875  rTmp.GetPoint()->nNode = *pTableNd;
876  SwContentNode* pCNd = GetNodes().GoNext( &rTmp.GetPoint()->nNode );
877  rTmp.GetPoint()->nContent.Assign( pCNd, 0 );
878  }
879 
880  if( pUndo )
881  {
883  }
884 
885  getIDocumentState().SetEnableSetModified(bEnableSetModified);
887  getIDocumentFieldsAccess().SetFieldsDirty(true, nullptr, 0);
888  return &rNdTable;
889 }
890 
891 static void lcl_RemoveBreaks(SwContentNode & rNode, SwTableFormat *const pTableFormat)
892 {
893  // delete old layout frames, new ones need to be created...
894  rNode.DelFrames(nullptr);
895 
896  if (!rNode.IsTextNode())
897  {
898  return;
899  }
900 
901  SwTextNode & rTextNode = *rNode.GetTextNode();
902  // remove PageBreaks/PageDesc/ColBreak
903  SfxItemSet const* pSet = rTextNode.GetpSwAttrSet();
904  if (!pSet)
905  return;
906 
907  const SfxPoolItem* pItem;
908  if (SfxItemState::SET == pSet->GetItemState(RES_BREAK, false, &pItem))
909  {
910  if (pTableFormat)
911  {
912  pTableFormat->SetFormatAttr(*pItem);
913  }
914  rTextNode.ResetAttr(RES_BREAK);
915  pSet = rTextNode.GetpSwAttrSet();
916  }
917 
918  if (pSet
919  && (SfxItemState::SET == pSet->GetItemState(RES_PAGEDESC, false, &pItem))
920  && static_cast<SwFormatPageDesc const*>(pItem)->GetPageDesc())
921  {
922  if (pTableFormat)
923  {
924  pTableFormat->SetFormatAttr(*pItem);
925  }
926  rTextNode.ResetAttr(RES_PAGEDESC);
927  }
928 }
929 
933 static void
934 lcl_BalanceTable(SwTable & rTable, size_t const nMaxBoxes,
935  SwTableNode & rTableNd, SwTableBoxFormat & rBoxFormat, SwTextFormatColl & rTextColl,
936  SwUndoTextToTable *const pUndo, std::vector<sal_uInt16> *const pPositions)
937 {
938  for (size_t n = 0; n < rTable.GetTabLines().size(); ++n)
939  {
940  SwTableLine *const pCurrLine = rTable.GetTabLines()[ n ];
941  size_t const nBoxes = pCurrLine->GetTabBoxes().size();
942  if (nMaxBoxes != nBoxes)
943  {
944  rTableNd.GetNodes().InsBoxen(&rTableNd, pCurrLine, &rBoxFormat, &rTextColl,
945  nullptr, nBoxes, nMaxBoxes - nBoxes);
946 
947  if (pUndo)
948  {
949  for (size_t i = nBoxes; i < nMaxBoxes; ++i)
950  {
951  pUndo->AddFillBox( *pCurrLine->GetTabBoxes()[i] );
952  }
953  }
954 
955  // if the first line is missing boxes, the width array is useless!
956  if (!n && pPositions)
957  {
958  pPositions->clear();
959  }
960  }
961  }
962 }
963 
964 static void
965 lcl_SetTableBoxWidths(SwTable & rTable, size_t const nMaxBoxes,
966  SwTableBoxFormat & rBoxFormat, SwDoc & rDoc,
967  std::vector<sal_uInt16> *const pPositions)
968 {
969  if (pPositions && !pPositions->empty())
970  {
971  SwTableLines& rLns = rTable.GetTabLines();
972  sal_uInt16 nLastPos = 0;
973  for (size_t n = 0; n < pPositions->size(); ++n)
974  {
975  SwTableBoxFormat *pNewFormat = rDoc.MakeTableBoxFormat();
976  pNewFormat->SetFormatAttr(
977  SwFormatFrameSize(SwFrameSize::Variable, (*pPositions)[n] - nLastPos));
978  for (size_t nTmpLine = 0; nTmpLine < rLns.size(); ++nTmpLine)
979  {
980  // Have to do an Add here, because the BoxFormat
981  // is still needed by the caller
982  pNewFormat->Add( rLns[ nTmpLine ]->GetTabBoxes()[ n ] );
983  }
984 
985  nLastPos = (*pPositions)[ n ];
986  }
987 
988  // propagate size upwards from format, so the table gets the right size
989  SAL_WARN_IF(rBoxFormat.HasWriterListeners(), "sw.core",
990  "who is still registered in the format?");
991  rBoxFormat.SetFormatAttr( SwFormatFrameSize( SwFrameSize::Variable, nLastPos ));
992  }
993  else
994  {
995  size_t nWidth = nMaxBoxes ? USHRT_MAX / nMaxBoxes : USHRT_MAX;
997  }
998 }
999 
1001  SwTableFormat* pTableFormat,
1002  SwTableLineFormat* pLineFormat,
1003  SwTableBoxFormat* pBoxFormat,
1004  SwTextFormatColl* pTextColl,
1005  SwUndoTextToTable* pUndo )
1006 {
1007  if( rRange.aStart >= rRange.aEnd )
1008  return nullptr;
1009 
1010  SwTableNode * pTableNd = new SwTableNode( rRange.aStart );
1011  new SwEndNode( rRange.aEnd, *pTableNd );
1012 
1013  SwDoc& rDoc = GetDoc();
1014  std::vector<sal_uInt16> aPosArr;
1015  SwTable& rTable = pTableNd->GetTable();
1016  SwTableBox* pBox;
1017  sal_uInt16 nBoxes, nLines, nMaxBoxes = 0;
1018 
1019  SwNodeIndex aSttIdx( *pTableNd, 1 );
1020  SwNodeIndex aEndIdx( rRange.aEnd, -1 );
1021  for( nLines = 0, nBoxes = 0;
1022  aSttIdx.GetIndex() < aEndIdx.GetIndex();
1023  aSttIdx += 2, nLines++, nBoxes = 0 )
1024  {
1025  SwTextNode* pTextNd = aSttIdx.GetNode().GetTextNode();
1026  OSL_ENSURE( pTextNd, "Only add TextNodes to the Table" );
1027 
1028  if( !nLines && 0x0b == cCh )
1029  {
1030  cCh = 0x09;
1031 
1032  // Get the separator's position from the first Node, in order for the Boxes to be set accordingly
1033  SwTextFrameInfo aFInfo( static_cast<SwTextFrame*>(pTextNd->getLayoutFrame( pTextNd->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout() )) );
1034  if( aFInfo.IsOneLine() ) // only makes sense in this case
1035  {
1036  OUString const& rText(pTextNd->GetText());
1037  for (sal_Int32 nChPos = 0; nChPos < rText.getLength(); ++nChPos)
1038  {
1039  if (rText[nChPos] == cCh)
1040  {
1041  // sw_redlinehide: no idea if this makes any sense...
1042  TextFrameIndex const nPos(aFInfo.GetFrame()->MapModelToView(pTextNd, nChPos));
1043  aPosArr.push_back( static_cast<sal_uInt16>(
1044  aFInfo.GetCharPos(nPos+TextFrameIndex(1), false)) );
1045  }
1046  }
1047 
1048  aPosArr.push_back(
1049  static_cast<sal_uInt16>(aFInfo.GetFrame()->IsVertical() ?
1050  aFInfo.GetFrame()->getFramePrintArea().Bottom() :
1051  aFInfo.GetFrame()->getFramePrintArea().Right()) );
1052 
1053  }
1054  }
1055 
1056  lcl_RemoveBreaks(*pTextNd, (0 == nLines) ? pTableFormat : nullptr);
1057 
1058  // Set the TableNode as StartNode for all TextNodes in the Table
1059  pTextNd->m_pStartOfSection = pTableNd;
1060 
1061  SwTableLine* pLine = new SwTableLine( pLineFormat, 1, nullptr );
1062  rTable.GetTabLines().insert(rTable.GetTabLines().begin() + nLines, pLine);
1063 
1064  SwStartNode* pSttNd;
1065  SwPosition aCntPos( aSttIdx, SwIndex( pTextNd ));
1066 
1067  const std::shared_ptr< sw::mark::ContentIdxStore> pContentStore(sw::mark::ContentIdxStore::Create());
1068  pContentStore->Save(rDoc, aSttIdx.GetIndex(), SAL_MAX_INT32);
1069 
1070  if( T2T_PARA != cCh )
1071  {
1072  for (sal_Int32 nChPos = 0; nChPos < pTextNd->GetText().getLength();)
1073  {
1074  if (pTextNd->GetText()[nChPos] == cCh)
1075  {
1076  aCntPos.nContent = nChPos;
1077  std::function<void (SwTextNode *, sw::mark::RestoreMode)> restoreFunc(
1078  [&](SwTextNode *const pNewNode, sw::mark::RestoreMode const eMode)
1079  {
1080  if (!pContentStore->Empty())
1081  {
1082  pContentStore->Restore(*pNewNode, nChPos, nChPos + 1, eMode);
1083  }
1084  });
1085  SwContentNode *const pNewNd =
1086  pTextNd->SplitContentNode(aCntPos, &restoreFunc);
1087 
1088  // Delete separator and correct search string
1089  pTextNd->EraseText( aCntPos.nContent, 1 );
1090  nChPos = 0;
1091 
1092  // Set the TableNode as StartNode for all TextNodes in the Table
1093  const SwNodeIndex aTmpIdx( aCntPos.nNode, -1 );
1094  pSttNd = new SwStartNode( aTmpIdx, SwNodeType::Start,
1096  new SwEndNode( aCntPos.nNode, *pSttNd );
1097  pNewNd->m_pStartOfSection = pSttNd;
1098 
1099  // Assign Section to the Box
1100  pBox = new SwTableBox( pBoxFormat, *pSttNd, pLine );
1101  pLine->GetTabBoxes().insert( pLine->GetTabBoxes().begin() + nBoxes++, pBox );
1102  }
1103  else
1104  {
1105  ++nChPos;
1106  }
1107  }
1108  }
1109 
1110  // Now for the last substring
1111  if( !pContentStore->Empty())
1112  pContentStore->Restore( *pTextNd, pTextNd->GetText().getLength(), pTextNd->GetText().getLength()+1 );
1113 
1114  pSttNd = new SwStartNode( aCntPos.nNode, SwNodeType::Start, SwTableBoxStartNode );
1115  const SwNodeIndex aTmpIdx( aCntPos.nNode, 1 );
1116  new SwEndNode( aTmpIdx, *pSttNd );
1117  pTextNd->m_pStartOfSection = pSttNd;
1118 
1119  pBox = new SwTableBox( pBoxFormat, *pSttNd, pLine );
1120  pLine->GetTabBoxes().insert( pLine->GetTabBoxes().begin() + nBoxes++, pBox );
1121  if( nMaxBoxes < nBoxes )
1122  nMaxBoxes = nBoxes;
1123  }
1124 
1125  lcl_BalanceTable(rTable, nMaxBoxes, *pTableNd, *pBoxFormat, *pTextColl,
1126  pUndo, &aPosArr);
1127  lcl_SetTableBoxWidths(rTable, nMaxBoxes, *pBoxFormat, rDoc, &aPosArr);
1128 
1129  return pTableNd;
1130 }
1131 
1132 const SwTable* SwDoc::TextToTable( const std::vector< std::vector<SwNodeRange> >& rTableNodes )
1133 {
1134  if (rTableNodes.empty())
1135  return nullptr;
1136 
1137  const std::vector<SwNodeRange>& rFirstRange = *rTableNodes.begin();
1138 
1139  if (rFirstRange.empty())
1140  return nullptr;
1141 
1142  const std::vector<SwNodeRange>& rLastRange = *rTableNodes.rbegin();
1143 
1144  if (rLastRange.empty())
1145  return nullptr;
1146 
1147  /* Save first node in the selection if it is a content node. */
1148  SwContentNode * pSttContentNd = rFirstRange.begin()->aStart.GetNode().GetContentNode();
1149 
1150  const SwNodeRange& rStartRange = *rFirstRange.begin();
1151  const SwNodeRange& rEndRange = *rLastRange.rbegin();
1152 
1154  SwPaM aOriginal( rStartRange.aStart, rEndRange.aEnd );
1155  const SwPosition *pStt = aOriginal.GetMark();
1156  const SwPosition *pEnd = aOriginal.GetPoint();
1157 
1158  bool const bUndo(GetIDocumentUndoRedo().DoesUndo());
1159  if (bUndo)
1160  {
1161  // Do not add splitting the TextNode to the Undo history
1162  GetIDocumentUndoRedo().DoUndo(false);
1163  }
1164 
1165  ::PaMCorrAbs( aOriginal, *pEnd );
1166 
1167  // make sure that the range is on Node Edges
1168  SwNodeRange aRg( pStt->nNode, pEnd->nNode );
1169  if( pStt->nContent.GetIndex() )
1170  getIDocumentContentOperations().SplitNode( *pStt, false );
1171 
1172  bool bEndContent = 0 != pEnd->nContent.GetIndex();
1173 
1174  // Do not split at the End of a Line (except at the End of the Doc)
1175  if( bEndContent )
1176  {
1177  if( pEnd->nNode.GetNode().GetContentNode()->Len() != pEnd->nContent.GetIndex()
1178  || pEnd->nNode.GetIndex() >= GetNodes().GetEndOfContent().GetIndex()-1 )
1179  {
1180  getIDocumentContentOperations().SplitNode( *pEnd, false );
1181  --const_cast<SwNodeIndex&>(pEnd->nNode);
1182  const_cast<SwIndex&>(pEnd->nContent).Assign(
1183  pEnd->nNode.GetNode().GetContentNode(), 0 );
1184  // A Node and at the End?
1185  if( pStt->nNode.GetIndex() >= pEnd->nNode.GetIndex() )
1186  --aRg.aStart;
1187  }
1188  else
1189  ++aRg.aEnd;
1190  }
1191 
1192  assert(aRg.aEnd == pEnd->nNode);
1193  assert(aRg.aStart == pStt->nNode);
1194  if( aRg.aEnd.GetIndex() == aRg.aStart.GetIndex() )
1195  {
1196  OSL_FAIL( "empty range" );
1197  ++aRg.aEnd;
1198  }
1199 
1200 
1201  {
1202  // TODO: this is not Undo-able - only good enough for file import
1204  SwNodeIndex const prev(rTableNodes.begin()->begin()->aStart, -1);
1205  SwNodeIndex const* pPrev(&prev);
1206  // pPrev could point to non-textnode now
1207  for (const auto& rRow : rTableNodes)
1208  {
1209  for (const auto& rCell : rRow)
1210  {
1211  assert(SwNodeIndex(*pPrev, +1) == rCell.aStart);
1212  SwPaM pam(rCell.aStart, 0, *pPrev,
1213  (pPrev->GetNode().IsContentNode())
1214  ? pPrev->GetNode().GetContentNode()->Len() : 0);
1215  rIDRA.SplitRedline(pam);
1216  pPrev = &rCell.aEnd;
1217  }
1218  }
1219  // another one to break between last cell and node after table
1220  SwPaM pam(SwNodeIndex(*pPrev, +1), 0, *pPrev,
1221  (pPrev->GetNode().IsContentNode())
1222  ? pPrev->GetNode().GetContentNode()->Len() : 0);
1223  rIDRA.SplitRedline(pam);
1224  }
1225 
1226  // We always use Upper to insert the Table
1227  SwNode2LayoutSaveUpperFrames aNode2Layout( aRg.aStart.GetNode() );
1228 
1229  GetIDocumentUndoRedo().DoUndo(bUndo);
1230 
1231  // Create the Box/Line/Table construct
1232  SwTableBoxFormat* pBoxFormat = MakeTableBoxFormat();
1233  SwTableLineFormat* pLineFormat = MakeTableLineFormat();
1235 
1236  // All Lines have a left-to-right Fill Order
1238  // The Table's SSize is USHRT_MAX
1240 
1241  /* If the first node in the selection is a context node and if it
1242  has an item FRAMEDIR set (no default) propagate the item to the
1243  replacing table. */
1244  if (pSttContentNd)
1245  {
1246  const SwAttrSet & aNdSet = pSttContentNd->GetSwAttrSet();
1247  const SfxPoolItem *pItem = nullptr;
1248 
1249  if (SfxItemState::SET == aNdSet.GetItemState( RES_FRAMEDIR, true, &pItem )
1250  && pItem != nullptr)
1251  {
1252  pTableFormat->SetFormatAttr( *pItem );
1253  }
1254  }
1255 
1256  //Resolves: tdf#87977, tdf#78599, disable broadcasting modifications
1257  //until after RegisterToFormat is completed
1258  bool bEnableSetModified = getIDocumentState().IsEnableSetModified();
1260 
1261  SwTableNode* pTableNd = GetNodes().TextToTable(
1262  rTableNodes, pTableFormat, pLineFormat, pBoxFormat );
1263 
1264  SwTable& rNdTable = pTableNd->GetTable();
1265  rNdTable.RegisterToFormat(*pTableFormat);
1266 
1267  if( !pBoxFormat->HasWriterListeners() )
1268  {
1269  // The Box's Formats already have the right size, we must only set
1270  // the right Border/AutoFormat.
1271  pTableFormat->SetFormatAttr( pBoxFormat->GetFrameSize() );
1272  delete pBoxFormat;
1273  }
1274 
1275  sal_uLong nIdx = pTableNd->GetIndex();
1276  aNode2Layout.RestoreUpperFrames( GetNodes(), nIdx, nIdx + 1 );
1277 
1278  getIDocumentState().SetEnableSetModified(bEnableSetModified);
1280  getIDocumentFieldsAccess().SetFieldsDirty( true, nullptr, 0 );
1281  return &rNdTable;
1282 }
1283 
1284 std::unique_ptr<SwNodeRange> SwNodes::ExpandRangeForTableBox(const SwNodeRange & rRange)
1285 {
1286  bool bChanged = false;
1287 
1288  SwNodeIndex aNewStart = rRange.aStart;
1289  SwNodeIndex aNewEnd = rRange.aEnd;
1290 
1291  SwNodeIndex aEndIndex = rRange.aEnd;
1292  SwNodeIndex aIndex = rRange.aStart;
1293 
1294  while (aIndex < aEndIndex)
1295  {
1296  SwNode& rNode = aIndex.GetNode();
1297 
1298  if (rNode.IsStartNode())
1299  {
1300  // advance aIndex to the end node of this start node
1301  SwNode * pEndNode = rNode.EndOfSectionNode();
1302  aIndex = *pEndNode;
1303 
1304  if (aIndex > aNewEnd)
1305  {
1306  aNewEnd = aIndex;
1307  bChanged = true;
1308  }
1309  }
1310  else if (rNode.IsEndNode())
1311  {
1312  SwNode * pStartNode = rNode.StartOfSectionNode();
1313  SwNodeIndex aStartIndex = *pStartNode;
1314 
1315  if (aStartIndex < aNewStart)
1316  {
1317  aNewStart = aStartIndex;
1318  bChanged = true;
1319  }
1320  }
1321 
1322  if (aIndex < aEndIndex)
1323  ++aIndex;
1324  }
1325 
1326  SwNode * pNode = &aIndex.GetNode();
1327  while (pNode->IsEndNode() && aIndex < Count() - 1)
1328  {
1329  SwNode * pStartNode = pNode->StartOfSectionNode();
1330  SwNodeIndex aStartIndex(*pStartNode);
1331  aNewStart = aStartIndex;
1332  aNewEnd = aIndex;
1333  bChanged = true;
1334 
1335  ++aIndex;
1336  pNode = &aIndex.GetNode();
1337  }
1338 
1339  std::unique_ptr<SwNodeRange> pResult;
1340  if (bChanged)
1341  pResult.reset(new SwNodeRange(aNewStart, aNewEnd));
1342  return pResult;
1343 }
1344 
1345 static void
1346 lcl_SetTableBoxWidths2(SwTable & rTable, size_t const nMaxBoxes,
1347  SwTableBoxFormat & rBoxFormat, SwDoc & rDoc)
1348 {
1349  // rhbz#820283, fdo#55462: set default box widths so table width is covered
1350  SwTableLines & rLines = rTable.GetTabLines();
1351  for (size_t nTmpLine = 0; nTmpLine < rLines.size(); ++nTmpLine)
1352  {
1353  SwTableBoxes & rBoxes = rLines[nTmpLine]->GetTabBoxes();
1354  assert(!rBoxes.empty()); // ensured by convertToTable
1355  size_t const nMissing = nMaxBoxes - rBoxes.size();
1356  if (nMissing)
1357  {
1358  // default width for box at the end of an incomplete line
1359  SwTableBoxFormat *const pNewFormat = rDoc.MakeTableBoxFormat();
1360  size_t nWidth = nMaxBoxes ? USHRT_MAX / nMaxBoxes : USHRT_MAX;
1362  nWidth * (nMissing + 1)) );
1363  pNewFormat->Add(rBoxes.back());
1364  }
1365  }
1366  size_t nWidth = nMaxBoxes ? USHRT_MAX / nMaxBoxes : USHRT_MAX;
1367  // default width for all boxes not at the end of an incomplete line
1369 }
1370 
1372  SwTableFormat* pTableFormat,
1373  SwTableLineFormat* pLineFormat,
1374  SwTableBoxFormat* pBoxFormat )
1375 {
1376  if( rTableNodes.empty() )
1377  return nullptr;
1378 
1379  SwTableNode * pTableNd = new SwTableNode( rTableNodes.begin()->begin()->aStart );
1380  //insert the end node after the last text node
1381  SwNodeIndex aInsertIndex( rTableNodes.rbegin()->rbegin()->aEnd );
1382  ++aInsertIndex;
1383 
1386  new SwEndNode( aInsertIndex, *pTableNd );
1387 
1388  SwDoc& rDoc = GetDoc();
1389  SwTable& rTable = pTableNd->GetTable();
1390  SwTableBox* pBox;
1391  sal_uInt16 nLines, nMaxBoxes = 0;
1392 
1393  SwNodeIndex aNodeIndex = rTableNodes.begin()->begin()->aStart;
1394  // delete frames of all contained content nodes
1395  for( nLines = 0; aNodeIndex <= rTableNodes.rbegin()->rbegin()->aEnd; ++aNodeIndex,++nLines )
1396  {
1397  SwNode& rNode = aNodeIndex.GetNode();
1398  if( rNode.IsContentNode() )
1399  {
1400  lcl_RemoveBreaks(static_cast<SwContentNode&>(rNode),
1401  (0 == nLines) ? pTableFormat : nullptr);
1402  }
1403  }
1404 
1405  nLines = 0;
1406  for( const auto& rRow : rTableNodes )
1407  {
1408  sal_uInt16 nBoxes = 0;
1409  SwTableLine* pLine = new SwTableLine( pLineFormat, 1, nullptr );
1410  rTable.GetTabLines().insert(rTable.GetTabLines().begin() + nLines, pLine);
1411 
1412  for( const auto& rCell : rRow )
1413  {
1414  const SwNodeIndex aTmpIdx( rCell.aStart, 0 );
1415 
1416  SwNodeIndex aCellEndIdx(rCell.aEnd);
1417  ++aCellEndIdx;
1418  SwStartNode* pSttNd = new SwStartNode( aTmpIdx, SwNodeType::Start,
1420 
1421  // Quotation of http://nabble.documentfoundation.org/Some-strange-lines-by-taking-a-look-at-the-bt-of-fdo-51916-tp3994561p3994639.html
1422  // SwNode's constructor adds itself to the same SwNodes array as the other node (pSttNd).
1423  // So this statement is only executed for the side-effect.
1424  new SwEndNode( aCellEndIdx, *pSttNd );
1425 
1426  //set the start node on all node of the current cell
1427  SwNodeIndex aCellNodeIdx = rCell.aStart;
1428  for(;aCellNodeIdx <= rCell.aEnd; ++aCellNodeIdx )
1429  {
1430  aCellNodeIdx.GetNode().m_pStartOfSection = pSttNd;
1431  //skip start/end node pairs
1432  if( aCellNodeIdx.GetNode().IsStartNode() )
1433  aCellNodeIdx.Assign(*aCellNodeIdx.GetNode().EndOfSectionNode());
1434  }
1435 
1436  // assign Section to the Box
1437  pBox = new SwTableBox( pBoxFormat, *pSttNd, pLine );
1438  pLine->GetTabBoxes().insert( pLine->GetTabBoxes().begin() + nBoxes++, pBox );
1439  }
1440  if( nMaxBoxes < nBoxes )
1441  nMaxBoxes = nBoxes;
1442 
1443  nLines++;
1444  }
1445 
1446  lcl_SetTableBoxWidths2(rTable, nMaxBoxes, *pBoxFormat, rDoc);
1447 
1448  return pTableNd;
1449 }
1450 
1454 bool SwDoc::TableToText( const SwTableNode* pTableNd, sal_Unicode cCh )
1455 {
1456  if( !pTableNd )
1457  return false;
1458 
1459  // #i34471#
1460  // If this is triggered by SwUndoTableToText::Repeat() nobody ever deleted
1461  // the table cursor.
1462  SwEditShell* pESh = GetEditShell();
1463  if( pESh && pESh->IsTableMode() )
1464  pESh->ClearMark();
1465 
1466  SwNodeRange aRg( *pTableNd, 0, *pTableNd->EndOfSectionNode() );
1467  std::unique_ptr<SwUndoTableToText> pUndo;
1468  SwNodeRange* pUndoRg = nullptr;
1470  {
1472  pUndoRg = new SwNodeRange( aRg.aStart, -1, aRg.aEnd, +1 );
1473  pUndo.reset(new SwUndoTableToText( pTableNd->GetTable(), cCh ));
1474  }
1475 
1476  SwTableFormulaUpdate aMsgHint( &pTableNd->GetTable() );
1477  aMsgHint.m_eFlags = TBL_BOXNAME;
1479 
1480  bool bRet = GetNodes().TableToText( aRg, cCh, pUndo.get() );
1481  if( pUndoRg )
1482  {
1483  ++pUndoRg->aStart;
1484  --pUndoRg->aEnd;
1485  pUndo->SetRange( *pUndoRg );
1486  GetIDocumentUndoRedo().AppendUndo(std::move(pUndo));
1487  delete pUndoRg;
1488  }
1489 
1490  if( bRet )
1492 
1493  return bRet;
1494 }
1495 
1496 namespace {
1497 
1502 struct DelTabPara
1503 {
1504  SwTextNode* pLastNd;
1505  SwNodes& rNds;
1506  SwUndoTableToText* pUndo;
1507  sal_Unicode cCh;
1508 
1509  DelTabPara( SwNodes& rNodes, sal_Unicode cChar, SwUndoTableToText* pU ) :
1510  pLastNd(nullptr), rNds( rNodes ), pUndo( pU ), cCh( cChar ) {}
1511 };
1512 
1513 }
1514 
1515 // Forward declare so that the Lines and Boxes can use recursion
1516 static void lcl_DelBox( SwTableBox* pBox, DelTabPara* pDelPara );
1517 
1518 static void lcl_DelLine( SwTableLine* pLine, DelTabPara* pPara )
1519 {
1520  assert(pPara && "The parameters are missing!");
1521  DelTabPara aPara( *pPara );
1522  for( auto& rpBox : pLine->GetTabBoxes() )
1523  lcl_DelBox(rpBox, &aPara );
1524  if( pLine->GetUpper() ) // Is there a parent Box?
1525  // Return the last TextNode
1526  pPara->pLastNd = aPara.pLastNd;
1527 }
1528 
1529 static void lcl_DelBox( SwTableBox* pBox, DelTabPara* pDelPara )
1530 {
1531  assert(pDelPara && "The parameters are missing");
1532 
1533  // Delete the Box's Lines
1534  if( !pBox->GetTabLines().empty() )
1535  {
1536  for( SwTableLine* pLine : pBox->GetTabLines() )
1537  lcl_DelLine( pLine, pDelPara );
1538  }
1539  else
1540  {
1541  SwDoc& rDoc = pDelPara->rNds.GetDoc();
1542  SwNodeRange aDelRg( *pBox->GetSttNd(), 0,
1543  *pBox->GetSttNd()->EndOfSectionNode() );
1544  // Delete the Section
1545  pDelPara->rNds.SectionUp( &aDelRg );
1546  const SwTextNode* pCurTextNd = nullptr;
1547  if (T2T_PARA != pDelPara->cCh && pDelPara->pLastNd)
1548  pCurTextNd = aDelRg.aStart.GetNode().GetTextNode();
1549  if (nullptr != pCurTextNd)
1550  {
1551  // Join the current text node with the last from the previous box if possible
1552  sal_uLong nNdIdx = aDelRg.aStart.GetIndex();
1553  --aDelRg.aStart;
1554  if( pDelPara->pLastNd == &aDelRg.aStart.GetNode() )
1555  {
1556  // Inserting the separator
1557  SwIndex aCntIdx( pDelPara->pLastNd,
1558  pDelPara->pLastNd->GetText().getLength());
1559  pDelPara->pLastNd->InsertText( OUString(pDelPara->cCh), aCntIdx,
1561  if( pDelPara->pUndo )
1562  pDelPara->pUndo->AddBoxPos( rDoc, nNdIdx, aDelRg.aEnd.GetIndex(),
1563  aCntIdx.GetIndex() );
1564 
1565  const std::shared_ptr<sw::mark::ContentIdxStore> pContentStore(sw::mark::ContentIdxStore::Create());
1566  const sal_Int32 nOldTextLen = aCntIdx.GetIndex();
1567  pContentStore->Save(rDoc, nNdIdx, SAL_MAX_INT32);
1568 
1569  pDelPara->pLastNd->JoinNext();
1570 
1571  if( !pContentStore->Empty() )
1572  pContentStore->Restore( rDoc, pDelPara->pLastNd->GetIndex(), nOldTextLen );
1573  }
1574  else if( pDelPara->pUndo )
1575  {
1576  ++aDelRg.aStart;
1577  pDelPara->pUndo->AddBoxPos( rDoc, nNdIdx, aDelRg.aEnd.GetIndex() );
1578  }
1579  }
1580  else if( pDelPara->pUndo )
1581  pDelPara->pUndo->AddBoxPos( rDoc, aDelRg.aStart.GetIndex(), aDelRg.aEnd.GetIndex() );
1582  --aDelRg.aEnd;
1583  pDelPara->pLastNd = aDelRg.aEnd.GetNode().GetTextNode();
1584 
1585  // Do not take over the NumberFormatting's adjustment
1586  if( pDelPara->pLastNd && pDelPara->pLastNd->HasSwAttrSet() )
1587  pDelPara->pLastNd->ResetAttr( RES_PARATR_ADJUST );
1588  }
1589 }
1590 
1592  SwUndoTableToText* pUndo )
1593 {
1594  // Is a Table selected?
1595  if (rRange.aStart.GetIndex() >= rRange.aEnd.GetIndex())
1596  return false;
1597  SwTableNode *const pTableNd(rRange.aStart.GetNode().GetTableNode());
1598  if (nullptr == pTableNd ||
1599  &rRange.aEnd.GetNode() != pTableNd->EndOfSectionNode() )
1600  return false;
1601 
1602  // If the Table was alone in a Section, create the Frames via the Table's Upper
1603  SwNode2LayoutSaveUpperFrames * pNode2Layout = nullptr;
1604  SwNodeIndex aFrameIdx( rRange.aStart );
1605  SwNode* pFrameNd = FindPrvNxtFrameNode( aFrameIdx, &rRange.aEnd.GetNode() );
1606  if( !pFrameNd )
1607  // Collect all Uppers
1608  pNode2Layout = new SwNode2LayoutSaveUpperFrames(*pTableNd);
1609 
1610  // Delete the Frames
1611  pTableNd->DelFrames();
1612 
1613  // "Delete" the Table and merge all Lines/Boxes
1614  DelTabPara aDelPara( *this, cCh, pUndo );
1615  for( SwTableLine *pLine : pTableNd->m_pTable->GetTabLines() )
1616  lcl_DelLine( pLine, &aDelPara );
1617 
1618  // We just created a TextNode with fitting separator for every TableLine.
1619  // Now we only need to delete the TableSection and create the Frames for the
1620  // new TextNode.
1621  SwNodeRange aDelRg( rRange.aStart, rRange.aEnd );
1622 
1623  // If the Table has PageDesc/Break Attributes, carry them over to the
1624  // first Text Node
1625  {
1626  // What about UNDO?
1627  const SfxItemSet& rTableSet = pTableNd->m_pTable->GetFrameFormat()->GetAttrSet();
1628  const SfxPoolItem *pBreak, *pDesc;
1629  if( SfxItemState::SET != rTableSet.GetItemState( RES_PAGEDESC, false, &pDesc ))
1630  pDesc = nullptr;
1631  if( SfxItemState::SET != rTableSet.GetItemState( RES_BREAK, false, &pBreak ))
1632  pBreak = nullptr;
1633 
1634  if( pBreak || pDesc )
1635  {
1636  SwNodeIndex aIdx( *pTableNd );
1637  SwContentNode* pCNd = GoNext( &aIdx );
1638  if( pBreak )
1639  pCNd->SetAttr( *pBreak );
1640  if( pDesc )
1641  pCNd->SetAttr( *pDesc );
1642  }
1643  }
1644 
1645  SectionUp( &aDelRg ); // Delete this Section and by that the Table
1646  // #i28006#
1647  sal_uLong nStt = aDelRg.aStart.GetIndex(), nEnd = aDelRg.aEnd.GetIndex();
1648  if( !pFrameNd )
1649  {
1650  pNode2Layout->RestoreUpperFrames( *this,
1651  aDelRg.aStart.GetIndex(), aDelRg.aEnd.GetIndex() );
1652  delete pNode2Layout;
1653  }
1654  else
1655  {
1656  SwContentNode *pCNd;
1657  SwSectionNode *pSNd;
1658  while( aDelRg.aStart.GetIndex() < nEnd )
1659  {
1660  pCNd = aDelRg.aStart.GetNode().GetContentNode();
1661  if( nullptr != pCNd )
1662  {
1663  if( pFrameNd->IsContentNode() )
1664  static_cast<SwContentNode*>(pFrameNd)->MakeFramesForAdjacentContentNode(*pCNd);
1665  else if( pFrameNd->IsTableNode() )
1666  static_cast<SwTableNode*>(pFrameNd)->MakeFramesForAdjacentContentNode(aDelRg.aStart);
1667  else if( pFrameNd->IsSectionNode() )
1668  static_cast<SwSectionNode*>(pFrameNd)->MakeFramesForAdjacentContentNode(aDelRg.aStart);
1669  pFrameNd = pCNd;
1670  }
1671  else
1672  {
1673  pSNd = aDelRg.aStart.GetNode().GetSectionNode();
1674  if( pSNd )
1675  {
1676  if( !pSNd->GetSection().IsHidden() && !pSNd->IsContentHidden() )
1677  {
1678  pSNd->MakeOwnFrames(&aFrameIdx, &aDelRg.aEnd);
1679  break;
1680  }
1681  aDelRg.aStart = *pSNd->EndOfSectionNode();
1682  }
1683  }
1684  ++aDelRg.aStart;
1685  }
1686  }
1687 
1688  // #i28006# Fly frames have to be restored even if the table was
1689  // #alone in the section
1690  const SwFrameFormats& rFlyArr = *GetDoc().GetSpzFrameFormats();
1691  for( auto pFly : rFlyArr )
1692  {
1693  SwFrameFormat *const pFormat = pFly;
1694  const SwFormatAnchor& rAnchor = pFormat->GetAnchor();
1695  SwPosition const*const pAPos = rAnchor.GetContentAnchor();
1696  if (pAPos &&
1697  ((RndStdIds::FLY_AT_PARA == rAnchor.GetAnchorId()) ||
1698  (RndStdIds::FLY_AT_CHAR == rAnchor.GetAnchorId())) &&
1699  nStt <= pAPos->nNode.GetIndex() &&
1700  pAPos->nNode.GetIndex() < nEnd )
1701  {
1702  pFormat->MakeFrames();
1703  }
1704  }
1705 
1706  return true;
1707 }
1708 
1712 void SwDoc::InsertCol( const SwCursor& rCursor, sal_uInt16 nCnt, bool bBehind )
1713 {
1714  if( !::CheckSplitCells( rCursor, nCnt + 1, SwTableSearchType::Col ) )
1715  return;
1716 
1717  // Find the Boxes via the Layout
1718  SwSelBoxes aBoxes;
1719  ::GetTableSel( rCursor, aBoxes, SwTableSearchType::Col );
1720 
1721  if( !aBoxes.empty() )
1722  InsertCol( aBoxes, nCnt, bBehind );
1723 }
1724 
1725 bool SwDoc::InsertCol( const SwSelBoxes& rBoxes, sal_uInt16 nCnt, bool bBehind )
1726 {
1727  OSL_ENSURE( !rBoxes.empty(), "No valid Box list" );
1728  SwTableNode* pTableNd = const_cast<SwTableNode*>(rBoxes[0]->GetSttNd()->FindTableNode());
1729  if( !pTableNd )
1730  return false;
1731 
1732  SwTable& rTable = pTableNd->GetTable();
1733  if( dynamic_cast<const SwDDETable*>( &rTable) != nullptr)
1734  return false;
1735 
1736  SwTableSortBoxes aTmpLst;
1737  std::unique_ptr<SwUndoTableNdsChg> pUndo;
1738  if (GetIDocumentUndoRedo().DoesUndo())
1739  {
1740  pUndo.reset(new SwUndoTableNdsChg( SwUndoId::TABLE_INSCOL, rBoxes, *pTableNd,
1741  0, 0, nCnt, bBehind, false ));
1742  aTmpLst.insert( rTable.GetTabSortBoxes() );
1743  }
1744 
1745  bool bRet(false);
1746  {
1747  ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
1748 
1749  SwTableFormulaUpdate aMsgHint( &rTable );
1750  aMsgHint.m_eFlags = TBL_BOXPTR;
1752 
1753  bRet = rTable.InsertCol(*this, rBoxes, nCnt, bBehind);
1754  if (bRet)
1755  {
1757  ::ClearFEShellTabCols(*this, nullptr);
1758  getIDocumentFieldsAccess().SetFieldsDirty( true, nullptr, 0 );
1759  }
1760  }
1761 
1762  if( pUndo && bRet )
1763  {
1764  pUndo->SaveNewBoxes( *pTableNd, aTmpLst );
1765  GetIDocumentUndoRedo().AppendUndo( std::move(pUndo) );
1766  }
1767  return bRet;
1768 }
1769 
1770 void SwDoc::InsertRow( const SwCursor& rCursor, sal_uInt16 nCnt, bool bBehind )
1771 {
1772  // Find the Boxes via the Layout
1773  SwSelBoxes aBoxes;
1774  GetTableSel( rCursor, aBoxes, SwTableSearchType::Row );
1775 
1776  if( !aBoxes.empty() )
1777  InsertRow( aBoxes, nCnt, bBehind );
1778 }
1779 
1780 bool SwDoc::InsertRow( const SwSelBoxes& rBoxes, sal_uInt16 nCnt, bool bBehind )
1781 {
1782  OSL_ENSURE( !rBoxes.empty(), "No valid Box list" );
1783  SwTableNode* pTableNd = const_cast<SwTableNode*>(rBoxes[0]->GetSttNd()->FindTableNode());
1784  if( !pTableNd )
1785  return false;
1786 
1787  SwTable& rTable = pTableNd->GetTable();
1788  if( dynamic_cast<const SwDDETable*>( &rTable) != nullptr)
1789  return false;
1790 
1791  SwTableSortBoxes aTmpLst;
1792  std::unique_ptr<SwUndoTableNdsChg> pUndo;
1793  if (GetIDocumentUndoRedo().DoesUndo())
1794  {
1795  pUndo.reset(new SwUndoTableNdsChg( SwUndoId::TABLE_INSROW,rBoxes, *pTableNd,
1796  0, 0, nCnt, bBehind, false ));
1797  aTmpLst.insert( rTable.GetTabSortBoxes() );
1798  }
1799 
1800  bool bRet(false);
1801  {
1802  ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
1803 
1804  SwTableFormulaUpdate aMsgHint( &rTable );
1805  aMsgHint.m_eFlags = TBL_BOXPTR;
1807 
1808  bRet = rTable.InsertRow( this, rBoxes, nCnt, bBehind );
1809  if (bRet)
1810  {
1812  ::ClearFEShellTabCols(*this, nullptr);
1813  getIDocumentFieldsAccess().SetFieldsDirty( true, nullptr, 0 );
1814  }
1815  }
1816 
1817  if( pUndo && bRet )
1818  {
1819  pUndo->SaveNewBoxes( *pTableNd, aTmpLst );
1820  GetIDocumentUndoRedo().AppendUndo( std::move(pUndo) );
1821  }
1822  return bRet;
1823 
1824 }
1825 
1829 void SwDoc::DeleteRow( const SwCursor& rCursor )
1830 {
1831  // Find the Boxes via the Layout
1832  SwSelBoxes aBoxes;
1833  GetTableSel( rCursor, aBoxes, SwTableSearchType::Row );
1834  if( ::HasProtectedCells( aBoxes ))
1835  return;
1836 
1837  // Remove the Cursor from the to-be-deleted Section.
1838  // The Cursor is placed after the table, except for
1839  // - when there's another Line, we place it in that one
1840  // - when a Line precedes it, we place it in that one
1841  {
1842  SwTableNode* pTableNd = rCursor.GetNode().FindTableNode();
1843 
1844  if(dynamic_cast<const SwDDETable*>( & pTableNd->GetTable()) != nullptr)
1845  return;
1846 
1847  // Find all Boxes/Lines
1848  FndBox_ aFndBox( nullptr, nullptr );
1849  {
1850  FndPara aPara( aBoxes, &aFndBox );
1851  ForEach_FndLineCopyCol( pTableNd->GetTable().GetTabLines(), &aPara );
1852  }
1853 
1854  if( aFndBox.GetLines().empty() )
1855  return;
1856 
1857  SwEditShell* pESh = GetEditShell();
1858  if( pESh )
1859  {
1860  pESh->KillPams();
1861  // FIXME: actually we should be iterating over all Shells!
1862  }
1863 
1864  FndBox_* pFndBox = &aFndBox;
1865  while( 1 == pFndBox->GetLines().size() &&
1866  1 == pFndBox->GetLines().front()->GetBoxes().size() )
1867  {
1868  FndBox_ *const pTmp = pFndBox->GetLines().front()->GetBoxes()[0].get();
1869  if( pTmp->GetBox()->GetSttNd() )
1870  break; // Else it gets too far
1871  pFndBox = pTmp;
1872  }
1873 
1874  SwTableLine* pDelLine = pFndBox->GetLines().back()->GetLine();
1875  SwTableBox* pDelBox = pDelLine->GetTabBoxes().back();
1876  while( !pDelBox->GetSttNd() )
1877  {
1878  SwTableLine* pLn = pDelBox->GetTabLines()[
1879  pDelBox->GetTabLines().size()-1 ];
1880  pDelBox = pLn->GetTabBoxes().back();
1881  }
1882  SwTableBox* pNextBox = pDelLine->FindNextBox( pTableNd->GetTable(),
1883  pDelBox );
1884  while( pNextBox &&
1885  pNextBox->GetFrameFormat()->GetProtect().IsContentProtected() )
1886  pNextBox = pNextBox->FindNextBox( pTableNd->GetTable(), pNextBox );
1887 
1888  if( !pNextBox ) // No succeeding Boxes? Then take the preceding one
1889  {
1890  pDelLine = pFndBox->GetLines().front()->GetLine();
1891  pDelBox = pDelLine->GetTabBoxes()[ 0 ];
1892  while( !pDelBox->GetSttNd() )
1893  pDelBox = pDelBox->GetTabLines()[0]->GetTabBoxes()[0];
1894  pNextBox = pDelLine->FindPreviousBox( pTableNd->GetTable(),
1895  pDelBox );
1896  while( pNextBox &&
1897  pNextBox->GetFrameFormat()->GetProtect().IsContentProtected() )
1898  pNextBox = pNextBox->FindPreviousBox( pTableNd->GetTable(), pNextBox );
1899  }
1900 
1901  sal_uLong nIdx;
1902  if( pNextBox ) // Place the Cursor here
1903  nIdx = pNextBox->GetSttIdx() + 1;
1904  else // Else after the Table
1905  nIdx = pTableNd->EndOfSectionIndex() + 1;
1906 
1907  SwNodeIndex aIdx( GetNodes(), nIdx );
1908  SwContentNode* pCNd = aIdx.GetNode().GetContentNode();
1909  if( !pCNd )
1910  pCNd = GetNodes().GoNext( &aIdx );
1911 
1912  if( pCNd )
1913  {
1914  // Change the Shell's Cursor or the one passed?
1915  SwPaM* pPam = const_cast<SwPaM*>(static_cast<SwPaM const *>(&rCursor));
1916  pPam->GetPoint()->nNode = aIdx;
1917  pPam->GetPoint()->nContent.Assign( pCNd, 0 );
1918  pPam->SetMark(); // Both want a part of it
1919  pPam->DeleteMark();
1920  }
1921  }
1922 
1923  // Thus delete the Rows
1925  DeleteRowCol( aBoxes );
1927 }
1928 
1929 void SwDoc::DeleteCol( const SwCursor& rCursor )
1930 {
1931  // Find the Boxes via the Layout
1932  SwSelBoxes aBoxes;
1933  GetTableSel( rCursor, aBoxes, SwTableSearchType::Col );
1934  if( ::HasProtectedCells( aBoxes ))
1935  return;
1936 
1937  // The Cursors need to be removed from the to-be-deleted range.
1938  // Always place them after/on top of the Table; they are always set
1939  // to the old position via the document position.
1940  SwEditShell* pESh = GetEditShell();
1941  if( pESh )
1942  {
1943  const SwNode* pNd = rCursor.GetNode().FindTableBoxStartNode();
1944  pESh->ParkCursor( SwNodeIndex( *pNd ) );
1945  }
1946 
1947  // Thus delete the Columns
1951 }
1952 
1953 bool SwDoc::DeleteRowCol(const SwSelBoxes& rBoxes, RowColMode const eMode)
1954 {
1955  if (!(eMode & SwDoc::RowColMode::DeleteProtected)
1956  && ::HasProtectedCells(rBoxes))
1957  {
1958  return false;
1959  }
1960 
1961  OSL_ENSURE( !rBoxes.empty(), "No valid Box list" );
1962  SwTableNode* pTableNd = const_cast<SwTableNode*>(rBoxes[0]->GetSttNd()->FindTableNode());
1963  if( !pTableNd )
1964  return false;
1965 
1966  if (!(eMode & SwDoc::RowColMode::DeleteProtected)
1967  && dynamic_cast<const SwDDETable*>(&pTableNd->GetTable()) != nullptr)
1968  {
1969  return false;
1970  }
1971 
1972  ::ClearFEShellTabCols(*this, nullptr);
1973  SwSelBoxes aSelBoxes( rBoxes );
1974  SwTable &rTable = pTableNd->GetTable();
1975  tools::Long nMin = 0;
1976  tools::Long nMax = 0;
1977  if( rTable.IsNewModel() )
1978  {
1979  if (eMode & SwDoc::RowColMode::DeleteColumn)
1980  rTable.ExpandColumnSelection( aSelBoxes, nMin, nMax );
1981  else
1982  rTable.FindSuperfluousRows( aSelBoxes );
1983  }
1984 
1985  // Are we deleting the whole Table?
1986  const sal_uLong nTmpIdx1 = pTableNd->GetIndex();
1987  const sal_uLong nTmpIdx2 = aSelBoxes.back()->GetSttNd()->EndOfSectionIndex() + 1;
1988  if( pTableNd->GetTable().GetTabSortBoxes().size() == aSelBoxes.size() &&
1989  aSelBoxes[0]->GetSttIdx()-1 == nTmpIdx1 &&
1990  nTmpIdx2 == pTableNd->EndOfSectionIndex() )
1991  {
1992  bool bNewTextNd = false;
1993  // Is it alone in a FlyFrame?
1994  SwNodeIndex aIdx( *pTableNd, -1 );
1995  const SwStartNode* pSttNd = aIdx.GetNode().GetStartNode();
1996  if( pSttNd )
1997  {
1998  const sal_uLong nTableEnd = pTableNd->EndOfSectionIndex() + 1;
1999  const sal_uLong nSectEnd = pSttNd->EndOfSectionIndex();
2000  if( nTableEnd == nSectEnd )
2001  {
2002  if( SwFlyStartNode == pSttNd->GetStartNodeType() )
2003  {
2004  SwFrameFormat* pFormat = pSttNd->GetFlyFormat();
2005  if( pFormat )
2006  {
2007  // That's the FlyFormat we're looking for
2009  return true;
2010  }
2011  }
2012  // No Fly? Thus Header or Footer: always leave a TextNode
2013  // We can forget about Undo then!
2014  bNewTextNd = true;
2015  }
2016  }
2017 
2018  // No Fly? Then it is a Header or Footer, so keep always a TextNode
2019  ++aIdx;
2020  if (GetIDocumentUndoRedo().DoesUndo())
2021  {
2023  SwPaM aPaM( *pTableNd->EndOfSectionNode(), aIdx.GetNode() );
2024 
2025  if( bNewTextNd )
2026  {
2027  const SwNodeIndex aTmpIdx( *pTableNd->EndOfSectionNode(), 1 );
2028  GetNodes().MakeTextNode( aTmpIdx,
2029  getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_STANDARD ) );
2030  }
2031 
2032  // Save the cursors (UNO and otherwise)
2033  SwPaM aSavePaM( SwNodeIndex( *pTableNd->EndOfSectionNode() ) );
2034  if( ! aSavePaM.Move( fnMoveForward, GoInNode ) )
2035  {
2036  *aSavePaM.GetMark() = SwPosition( *pTableNd );
2037  aSavePaM.Move( fnMoveBackward, GoInNode );
2038  }
2039  {
2040  SwPaM const tmpPaM(*pTableNd, *pTableNd->EndOfSectionNode());
2041  ::PaMCorrAbs(tmpPaM, *aSavePaM.GetMark());
2042  }
2043 
2044  // Move hard PageBreaks to the succeeding Node
2045  bool bSavePageBreak = false, bSavePageDesc = false;
2046  sal_uLong nNextNd = pTableNd->EndOfSectionIndex()+1;
2047  SwContentNode* pNextNd = GetNodes()[ nNextNd ]->GetContentNode();
2048  if( pNextNd )
2049  {
2050  SwFrameFormat* pTableFormat = pTableNd->GetTable().GetFrameFormat();
2051  const SfxPoolItem *pItem;
2052  if( SfxItemState::SET == pTableFormat->GetItemState( RES_PAGEDESC,
2053  false, &pItem ) )
2054  {
2055  pNextNd->SetAttr( *pItem );
2056  bSavePageDesc = true;
2057  }
2058 
2059  if( SfxItemState::SET == pTableFormat->GetItemState( RES_BREAK,
2060  false, &pItem ) )
2061  {
2062  pNextNd->SetAttr( *pItem );
2063  bSavePageBreak = true;
2064  }
2065  }
2066  std::unique_ptr<SwUndoDelete> pUndo(new SwUndoDelete( aPaM ));
2067  if( bNewTextNd )
2068  pUndo->SetTableDelLastNd();
2069  pUndo->SetPgBrkFlags( bSavePageBreak, bSavePageDesc );
2070  pUndo->SetTableName(pTableNd->GetTable().GetFrameFormat()->GetName());
2071  GetIDocumentUndoRedo().AppendUndo( std::move(pUndo) );
2072  }
2073  else
2074  {
2075  if( bNewTextNd )
2076  {
2077  const SwNodeIndex aTmpIdx( *pTableNd->EndOfSectionNode(), 1 );
2078  GetNodes().MakeTextNode( aTmpIdx,
2079  getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_STANDARD ) );
2080  }
2081 
2082  // Save the cursors (UNO and otherwise)
2083  SwPaM aSavePaM( SwNodeIndex( *pTableNd->EndOfSectionNode() ) );
2084  if( ! aSavePaM.Move( fnMoveForward, GoInNode ) )
2085  {
2086  *aSavePaM.GetMark() = SwPosition( *pTableNd );
2087  aSavePaM.Move( fnMoveBackward, GoInNode );
2088  }
2089  {
2090  SwPaM const tmpPaM(*pTableNd, *pTableNd->EndOfSectionNode());
2091  ::PaMCorrAbs(tmpPaM, *aSavePaM.GetMark());
2092  }
2093 
2094  // Move hard PageBreaks to the succeeding Node
2095  SwContentNode* pNextNd = GetNodes()[ pTableNd->EndOfSectionIndex()+1 ]->GetContentNode();
2096  if( pNextNd )
2097  {
2098  SwFrameFormat* pTableFormat = pTableNd->GetTable().GetFrameFormat();
2099  const SfxPoolItem *pItem;
2100  if( SfxItemState::SET == pTableFormat->GetItemState( RES_PAGEDESC,
2101  false, &pItem ) )
2102  pNextNd->SetAttr( *pItem );
2103 
2104  if( SfxItemState::SET == pTableFormat->GetItemState( RES_BREAK,
2105  false, &pItem ) )
2106  pNextNd->SetAttr( *pItem );
2107  }
2108 
2109  pTableNd->DelFrames();
2111  }
2112 
2114 
2116  getIDocumentFieldsAccess().SetFieldsDirty( true, nullptr, 0 );
2117 
2118  return true;
2119  }
2120 
2121  std::unique_ptr<SwUndoTableNdsChg> pUndo;
2122  if (GetIDocumentUndoRedo().DoesUndo())
2123  {
2124  pUndo.reset(new SwUndoTableNdsChg( SwUndoId::TABLE_DELBOX, aSelBoxes, *pTableNd,
2125  nMin, nMax, 0, false, false ));
2126  }
2127 
2128  bool bRet(false);
2129  {
2130  ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
2131 
2132  SwTableFormulaUpdate aMsgHint( &pTableNd->GetTable() );
2133  aMsgHint.m_eFlags = TBL_BOXPTR;
2135 
2136  if (rTable.IsNewModel())
2137  {
2138  if (eMode & SwDoc::RowColMode::DeleteColumn)
2139  rTable.PrepareDeleteCol( nMin, nMax );
2140  rTable.FindSuperfluousRows( aSelBoxes );
2141  if (pUndo)
2142  pUndo->ReNewBoxes( aSelBoxes );
2143  }
2144  bRet = rTable.DeleteSel( this, aSelBoxes, nullptr, pUndo.get(), true, true );
2145  if (bRet)
2146  {
2148 
2150  getIDocumentFieldsAccess().SetFieldsDirty( true, nullptr, 0 );
2151  }
2152  }
2153 
2154  if( pUndo && bRet )
2155  {
2156  GetIDocumentUndoRedo().AppendUndo( std::move(pUndo) );
2157  }
2158 
2159  return bRet;
2160 }
2161 
2165 bool SwDoc::SplitTable( const SwSelBoxes& rBoxes, bool bVert, sal_uInt16 nCnt,
2166  bool bSameHeight )
2167 {
2168  OSL_ENSURE( !rBoxes.empty() && nCnt, "No valid Box list" );
2169  SwTableNode* pTableNd = const_cast<SwTableNode*>(rBoxes[0]->GetSttNd()->FindTableNode());
2170  if( !pTableNd )
2171  return false;
2172 
2173  SwTable& rTable = pTableNd->GetTable();
2174  if( dynamic_cast<const SwDDETable*>( &rTable) != nullptr)
2175  return false;
2176 
2177  std::vector<sal_uLong> aNdsCnts;
2178  SwTableSortBoxes aTmpLst;
2179  std::unique_ptr<SwUndoTableNdsChg> pUndo;
2180  if (GetIDocumentUndoRedo().DoesUndo())
2181  {
2182  pUndo.reset(new SwUndoTableNdsChg( SwUndoId::TABLE_SPLIT, rBoxes, *pTableNd, 0, 0,
2183  nCnt, bVert, bSameHeight ));
2184 
2185  aTmpLst.insert( rTable.GetTabSortBoxes() );
2186  if( !bVert )
2187  {
2188  for (size_t n = 0; n < rBoxes.size(); ++n)
2189  {
2190  const SwStartNode* pSttNd = rBoxes[ n ]->GetSttNd();
2191  aNdsCnts.push_back( pSttNd->EndOfSectionIndex() -
2192  pSttNd->GetIndex() );
2193  }
2194  }
2195  }
2196 
2197  bool bRet(false);
2198  {
2199  ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
2200 
2201  SwTableFormulaUpdate aMsgHint( &rTable );
2202  aMsgHint.m_eFlags = TBL_BOXPTR;
2204 
2205  if (bVert)
2206  bRet = rTable.SplitCol(*this, rBoxes, nCnt);
2207  else
2208  bRet = rTable.SplitRow(*this, rBoxes, nCnt, bSameHeight);
2209 
2210  if (bRet)
2211  {
2213 
2215  getIDocumentFieldsAccess().SetFieldsDirty( true, nullptr, 0 );
2216  }
2217  }
2218 
2219  if( pUndo && bRet )
2220  {
2221  if( bVert )
2222  pUndo->SaveNewBoxes( *pTableNd, aTmpLst );
2223  else
2224  pUndo->SaveNewBoxes( *pTableNd, aTmpLst, rBoxes, aNdsCnts );
2225  GetIDocumentUndoRedo().AppendUndo( std::move(pUndo) );
2226  }
2227 
2228  return bRet;
2229 }
2230 
2232 {
2233  // Check if the current cursor's Point/Mark are inside a Table
2234  SwTableNode* pTableNd = rPam.GetNode().FindTableNode();
2235  if( !pTableNd )
2237  SwTable& rTable = pTableNd->GetTable();
2238  if( dynamic_cast<const SwDDETable*>( &rTable) != nullptr )
2241  if( !rTable.IsNewModel() )
2242  {
2243  nRet =::CheckMergeSel( rPam );
2244  if( TableMergeErr::Ok != nRet )
2245  return nRet;
2247  }
2248 
2249  // #i33394#
2251 
2254 
2255  std::unique_ptr<SwUndoTableMerge> pUndo;
2256  if (GetIDocumentUndoRedo().DoesUndo())
2257  pUndo.reset(new SwUndoTableMerge( rPam ));
2258 
2259  // Find the Boxes via the Layout
2260  SwSelBoxes aBoxes;
2261  SwSelBoxes aMerged;
2262  SwTableBox* pMergeBox;
2263 
2264  if( !rTable.PrepareMerge( rPam, aBoxes, aMerged, &pMergeBox, pUndo.get() ) )
2265  { // No cells found to merge
2267  if( pUndo )
2268  {
2269  pUndo.reset();
2270  SwUndoId nLastUndoId(SwUndoId::EMPTY);
2271  if (GetIDocumentUndoRedo().GetLastUndoInfo(nullptr, & nLastUndoId)
2272  && (SwUndoId::REDLINE == nLastUndoId))
2273  {
2274  // FIXME: why is this horrible cleanup necessary?
2275  SwUndoRedline *const pU = dynamic_cast<SwUndoRedline*>(
2277  if (pU && pU->GetRedlSaveCount())
2278  {
2279  SwEditShell *const pEditShell(GetEditShell());
2280  assert(pEditShell);
2281  ::sw::UndoRedoContext context(*this, *pEditShell);
2282  static_cast<SfxUndoAction *>(pU)->UndoWithContext(context);
2283  }
2284  delete pU;
2285  }
2286  }
2287  }
2288  else
2289  {
2290  // The PaMs need to be removed from the to-be-deleted range. Thus always place
2291  // them at the end of/on top of the Table; it's always set to the old position via
2292  // the Document Position.
2293  // For a start remember an index for the temporary position, because we cannot
2294  // access it after GetMergeSel
2295  {
2296  rPam.DeleteMark();
2297  rPam.GetPoint()->nNode = *pMergeBox->GetSttNd();
2298  rPam.GetPoint()->nContent.Assign( nullptr, 0 );
2299  rPam.SetMark();
2300  rPam.DeleteMark();
2301 
2302  SwPaM* pTmp = &rPam;
2303  while( &rPam != ( pTmp = pTmp->GetNext() ))
2304  for( int i = 0; i < 2; ++i )
2305  pTmp->GetBound( static_cast<bool>(i) ) = *rPam.GetPoint();
2306 
2307  if (SwTableCursor* pTableCursor = dynamic_cast<SwTableCursor*>(&rPam))
2308  {
2309  // tdf#135098 update selection so rPam's m_SelectedBoxes is updated
2310  // to not contain the soon to-be-deleted SwTableBox so if the rPam
2311  // is queried via a11y it doesn't claim the deleted cell still
2312  // exists
2313  pTableCursor->NewTableSelection();
2314  }
2315  }
2316 
2317  // Merge them
2318  SwTableFormulaUpdate aMsgHint( &pTableNd->GetTable() );
2319  aMsgHint.m_eFlags = TBL_BOXPTR;
2321 
2322  if( pTableNd->GetTable().Merge( this, aBoxes, aMerged, pMergeBox, pUndo.get() ))
2323  {
2324  nRet = TableMergeErr::Ok;
2325 
2327  getIDocumentFieldsAccess().SetFieldsDirty( true, nullptr, 0 );
2328  if( pUndo )
2329  {
2330  GetIDocumentUndoRedo().AppendUndo( std::move(pUndo) );
2331  }
2332  }
2333 
2334  rPam.GetPoint()->nNode = *pMergeBox->GetSttNd();
2335  rPam.Move();
2336 
2337  ::ClearFEShellTabCols(*this, nullptr);
2339  }
2341  return nRet;
2342 }
2343 
2345  : SwStartNode( rIdx, SwNodeType::Table )
2346 {
2347  m_pTable.reset(new SwTable);
2348 }
2349 
2351 {
2352  // Notify UNO wrappers
2353  GetTable().GetFrameFormat()->GetNotifier().Broadcast(SfxHint(SfxHintId::Dying));
2354  DelFrames();
2355  m_pTable->SetTableNode(this); // set this so that ~SwDDETable can read it!
2356  m_pTable.reset();
2357 }
2358 
2360 {
2361  return new SwTabFrame( *m_pTable, pSib );
2362 }
2363 
2369 {
2370  if( !GetTable().GetFrameFormat()->HasWriterListeners()) // Do we actually have Frame?
2371  return;
2372 
2373  SwFrame *pFrame;
2374  SwContentNode * pNode = rIdx.GetNode().GetContentNode();
2375 
2376  OSL_ENSURE( pNode, "No ContentNode or CopyNode and new Node is identical");
2377 
2378  bool bBefore = rIdx < GetIndex();
2379 
2380  SwNode2Layout aNode2Layout( *this, rIdx.GetIndex() );
2381 
2382  while( nullptr != (pFrame = aNode2Layout.NextFrame()) )
2383  {
2384  if (pFrame->getRootFrame()->HasMergedParas()
2385  && !pNode->IsCreateFrameWhenHidingRedlines())
2386  {
2387  continue;
2388  }
2389  SwFrame *pNew = pNode->MakeFrame( pFrame );
2390  // Will the Node receive Frames before or after?
2391  if ( bBefore )
2392  // The new one precedes me
2393  pNew->Paste( pFrame->GetUpper(), pFrame );
2394  else
2395  // The new one succeeds me
2396  pNew->Paste( pFrame->GetUpper(), pFrame->GetNext() );
2397  }
2398 }
2399 
2404 {
2405  OSL_ENSURE( pIdxBehind, "No Index" );
2406  *pIdxBehind = *this;
2407  SwNode *pNd = GetNodes().FindPrvNxtFrameNode( *pIdxBehind, EndOfSectionNode() );
2408  if( !pNd )
2409  return ;
2410 
2411  SwFrame *pFrame( nullptr );
2412  SwLayoutFrame *pUpper( nullptr );
2413  SwNode2Layout aNode2Layout( *pNd, GetIndex() );
2414  while( nullptr != (pUpper = aNode2Layout.UpperFrame( pFrame, *this )) )
2415  {
2416  if (pUpper->getRootFrame()->HasMergedParas()
2418  {
2419  continue;
2420  }
2421  SwTabFrame* pNew = MakeFrame( pUpper );
2422  pNew->Paste( pUpper, pFrame );
2423  // #i27138#
2424  // notify accessibility paragraphs objects about changed
2425  // CONTENT_FLOWS_FROM/_TO relation.
2426  // Relation CONTENT_FLOWS_FROM for next paragraph will change
2427  // and relation CONTENT_FLOWS_TO for previous paragraph will change.
2428  {
2429  SwViewShell* pViewShell( pNew->getRootFrame()->GetCurrShell() );
2430  if ( pViewShell && pViewShell->GetLayout() &&
2431  pViewShell->GetLayout()->IsAnyShellAccessible() )
2432  {
2434  dynamic_cast<SwTextFrame*>(pNew->FindNextCnt( true )),
2435  dynamic_cast<SwTextFrame*>(pNew->FindPrevCnt()) );
2436  }
2437  }
2438  pNew->RegistFlys();
2439  }
2440 }
2441 
2442 void SwTableNode::DelFrames(SwRootFrame const*const pLayout)
2443 {
2444  /* For a start, cut out and delete the TabFrames (which will also delete the Columns and Rows)
2445  The TabFrames are attached to the FrameFormat of the SwTable.
2446  We need to delete them in a more cumbersome way, for the Master to also delete the Follows. */
2447 
2448  SwIterator<SwTabFrame,SwFormat> aIter( *(m_pTable->GetFrameFormat()) );
2449  SwTabFrame *pFrame = aIter.First();
2450  while ( pFrame )
2451  {
2452  bool bAgain = false;
2453  {
2454  if (!pFrame->IsFollow() && (!pLayout || pLayout == pFrame->getRootFrame()))
2455  {
2456  while ( pFrame->HasFollow() )
2457  pFrame->JoinAndDelFollows();
2458  // #i27138#
2459  // notify accessibility paragraphs objects about changed
2460  // CONTENT_FLOWS_FROM/_TO relation.
2461  // Relation CONTENT_FLOWS_FROM for current next paragraph will change
2462  // and relation CONTENT_FLOWS_TO for current previous paragraph will change.
2463  {
2464  SwViewShell* pViewShell( pFrame->getRootFrame()->GetCurrShell() );
2465  if ( pViewShell && pViewShell->GetLayout() &&
2466  pViewShell->GetLayout()->IsAnyShellAccessible() )
2467  {
2469  dynamic_cast<SwTextFrame*>(pFrame->FindNextCnt( true )),
2470  dynamic_cast<SwTextFrame*>(pFrame->FindPrevCnt()) );
2471  }
2472  }
2473  pFrame->Cut();
2474  SwFrame::DestroyFrame(pFrame);
2475  bAgain = true;
2476  }
2477  }
2478  pFrame = bAgain ? aIter.First() : aIter.Next();
2479  }
2480 }
2481 
2482 void SwTableNode::SetNewTable( std::unique_ptr<SwTable> pNewTable, bool bNewFrames )
2483 {
2484  DelFrames();
2485  m_pTable->SetTableNode(this);
2486  m_pTable = std::move(pNewTable);
2487  if( bNewFrames )
2488  {
2489  SwNodeIndex aIdx( *EndOfSectionNode());
2490  GetNodes().GoNext( &aIdx );
2491  MakeOwnFrames(&aIdx);
2492  }
2493 }
2494 
2496 {
2497  SwDoc& rDoc = GetDoc();
2498  SwTable& rTable = GetTable();
2500  rDoc.getIDocumentRedlineAccess().GetExtraRedlineTable().DeleteAllTableRedlines(rDoc, rTable, true, RedlineType::Any);
2501 }
2502 
2503 void SwDoc::GetTabCols( SwTabCols &rFill, const SwCellFrame* pBoxFrame )
2504 {
2505  OSL_ENSURE( pBoxFrame, "pBoxFrame needs to be specified!" );
2506  if( !pBoxFrame )
2507  return;
2508 
2509  SwTabFrame *pTab = const_cast<SwFrame*>(static_cast<SwFrame const *>(pBoxFrame))->ImplFindTabFrame();
2510  const SwTableBox* pBox = pBoxFrame->GetTabBox();
2511 
2512  // Set fixed points, LeftMin in Document coordinates, all others relative
2513  SwRectFnSet aRectFnSet(pTab);
2514  const SwPageFrame* pPage = pTab->FindPageFrame();
2515  const sal_uLong nLeftMin = aRectFnSet.GetLeft(pTab->getFrameArea()) -
2516  aRectFnSet.GetLeft(pPage->getFrameArea());
2517  const sal_uLong nRightMax = aRectFnSet.GetRight(pTab->getFrameArea()) -
2518  aRectFnSet.GetLeft(pPage->getFrameArea());
2519 
2520  rFill.SetLeftMin ( nLeftMin );
2521  rFill.SetLeft ( aRectFnSet.GetLeft(pTab->getFramePrintArea()) );
2522  rFill.SetRight ( aRectFnSet.GetRight(pTab->getFramePrintArea()));
2523  rFill.SetRightMax( nRightMax - nLeftMin );
2524 
2525  pTab->GetTable()->GetTabCols( rFill, pBox );
2526 }
2527 
2528 // Here are some little helpers used in SwDoc::GetTabRows
2529 
2530 #define ROWFUZZY 25
2531 
2532 namespace {
2533 
2534 struct FuzzyCompare
2535 {
2536  bool operator() ( tools::Long s1, tools::Long s2 ) const;
2537 };
2538 
2539 }
2540 
2541 bool FuzzyCompare::operator() ( tools::Long s1, tools::Long s2 ) const
2542 {
2543  return ( s1 < s2 && std::abs( s1 - s2 ) > ROWFUZZY );
2544 }
2545 
2546 static bool lcl_IsFrameInColumn( const SwCellFrame& rFrame, SwSelBoxes const & rBoxes )
2547 {
2548  for (size_t i = 0; i < rBoxes.size(); ++i)
2549  {
2550  if ( rFrame.GetTabBox() == rBoxes[ i ] )
2551  return true;
2552  }
2553 
2554  return false;
2555 }
2556 
2557 void SwDoc::GetTabRows( SwTabCols &rFill, const SwCellFrame* pBoxFrame )
2558 {
2559  OSL_ENSURE( pBoxFrame, "GetTabRows called without pBoxFrame" );
2560 
2561  // Make code robust:
2562  if ( !pBoxFrame )
2563  return;
2564 
2565  // #i39552# Collection of the boxes of the current
2566  // column has to be done at the beginning of this function, because
2567  // the table may be formatted in ::GetTableSel.
2568  SwDeletionChecker aDelCheck( pBoxFrame );
2569 
2570  SwSelBoxes aBoxes;
2571  const SwContentFrame* pContent = ::GetCellContent( *pBoxFrame );
2572  if ( pContent && pContent->IsTextFrame() )
2573  {
2574  const SwPosition aPos(*static_cast<const SwTextFrame*>(pContent)->GetTextNodeFirst());
2575  const SwCursor aTmpCursor( aPos, nullptr );
2576  ::GetTableSel( aTmpCursor, aBoxes, SwTableSearchType::Col );
2577  }
2578 
2579  // Make code robust:
2580  if ( aDelCheck.HasBeenDeleted() )
2581  {
2582  OSL_FAIL( "Current box has been deleted during GetTabRows()" );
2583  return;
2584  }
2585 
2586  // Make code robust:
2587  const SwTabFrame* pTab = pBoxFrame->FindTabFrame();
2588  OSL_ENSURE( pTab, "GetTabRows called without a table" );
2589  if ( !pTab )
2590  return;
2591 
2592  const SwFrame* pFrame = pTab->GetNextLayoutLeaf();
2593 
2594  // Set fixed points, LeftMin in Document coordinates, all others relative
2595  SwRectFnSet aRectFnSet(pTab);
2596  const SwPageFrame* pPage = pTab->FindPageFrame();
2597  const tools::Long nLeftMin = ( aRectFnSet.IsVert() ?
2598  pTab->GetPrtLeft() - pPage->getFrameArea().Left() :
2599  pTab->GetPrtTop() - pPage->getFrameArea().Top() );
2600  const tools::Long nLeft = aRectFnSet.IsVert() ? LONG_MAX : 0;
2601  const tools::Long nRight = aRectFnSet.GetHeight(pTab->getFramePrintArea());
2602  const tools::Long nRightMax = aRectFnSet.IsVert() ? nRight : LONG_MAX;
2603 
2604  rFill.SetLeftMin( nLeftMin );
2605  rFill.SetLeft( nLeft );
2606  rFill.SetRight( nRight );
2607  rFill.SetRightMax( nRightMax );
2608 
2609  typedef std::map< tools::Long, std::pair< tools::Long, long >, FuzzyCompare > BoundaryMap;
2610  BoundaryMap aBoundaries;
2611  BoundaryMap::iterator aIter;
2612  std::pair< tools::Long, long > aPair;
2613 
2614  typedef std::map< tools::Long, bool > HiddenMap;
2615  HiddenMap aHidden;
2616  HiddenMap::iterator aHiddenIter;
2617 
2618  while ( pFrame && pTab->IsAnLower( pFrame ) )
2619  {
2620  if ( pFrame->IsCellFrame() && pFrame->FindTabFrame() == pTab )
2621  {
2622  // upper and lower borders of current cell frame:
2623  tools::Long nUpperBorder = aRectFnSet.GetTop(pFrame->getFrameArea());
2624  tools::Long nLowerBorder = aRectFnSet.GetBottom(pFrame->getFrameArea());
2625 
2626  // get boundaries for nUpperBorder:
2627  aIter = aBoundaries.find( nUpperBorder );
2628  if ( aIter == aBoundaries.end() )
2629  {
2630  aPair.first = nUpperBorder; aPair.second = LONG_MAX;
2631  aBoundaries[ nUpperBorder ] = aPair;
2632  }
2633 
2634  // get boundaries for nLowerBorder:
2635  aIter = aBoundaries.find( nLowerBorder );
2636  if ( aIter == aBoundaries.end() )
2637  {
2638  aPair.first = nUpperBorder; aPair.second = LONG_MAX;
2639  }
2640  else
2641  {
2642  nLowerBorder = (*aIter).first;
2643  tools::Long nNewLowerBorderUpperBoundary = std::max( (*aIter).second.first, nUpperBorder );
2644  aPair.first = nNewLowerBorderUpperBoundary; aPair.second = LONG_MAX;
2645  }
2646  aBoundaries[ nLowerBorder ] = aPair;
2647 
2648  // calculate hidden flags for entry nUpperBorder/nLowerBorder:
2649  tools::Long nTmpVal = nUpperBorder;
2650  for ( sal_uInt8 i = 0; i < 2; ++i )
2651  {
2652  aHiddenIter = aHidden.find( nTmpVal );
2653  if ( aHiddenIter == aHidden.end() )
2654  aHidden[ nTmpVal ] = !lcl_IsFrameInColumn( *static_cast<const SwCellFrame*>(pFrame), aBoxes );
2655  else
2656  {
2657  if ( aHidden[ nTmpVal ] &&
2658  lcl_IsFrameInColumn( *static_cast<const SwCellFrame*>(pFrame), aBoxes ) )
2659  aHidden[ nTmpVal ] = false;
2660  }
2661  nTmpVal = nLowerBorder;
2662  }
2663  }
2664 
2665  pFrame = pFrame->GetNextLayoutLeaf();
2666  }
2667 
2668  // transfer calculated values from BoundaryMap and HiddenMap into rFill:
2669  size_t nIdx = 0;
2670  for ( const auto& rEntry : aBoundaries )
2671  {
2672  const tools::Long nTabTop = aRectFnSet.GetPrtTop(*pTab);
2673  const tools::Long nKey = aRectFnSet.YDiff( rEntry.first, nTabTop );
2674  const std::pair< tools::Long, long > aTmpPair = rEntry.second;
2675  const tools::Long nFirst = aRectFnSet.YDiff( aTmpPair.first, nTabTop );
2676  const tools::Long nSecond = aTmpPair.second;
2677 
2678  aHiddenIter = aHidden.find( rEntry.first );
2679  const bool bHidden = aHiddenIter != aHidden.end() && (*aHiddenIter).second;
2680  rFill.Insert( nKey, nFirst, nSecond, bHidden, nIdx++ );
2681  }
2682 
2683  // delete first and last entry
2684  OSL_ENSURE( rFill.Count(), "Deleting from empty vector. Fasten your seatbelts!" );
2685  // #i60818# There may be only one entry in rFill. Make
2686  // code robust by checking count of rFill.
2687  if ( rFill.Count() ) rFill.Remove( 0 );
2688  if ( rFill.Count() ) rFill.Remove( rFill.Count() - 1 );
2689  rFill.SetLastRowAllowedToChange( !pTab->HasFollowFlowLine() );
2690 }
2691 
2692 void SwDoc::SetTabCols( const SwTabCols &rNew, bool bCurRowOnly,
2693  const SwCellFrame* pBoxFrame )
2694 {
2695  const SwTableBox* pBox = nullptr;
2696  SwTabFrame *pTab = nullptr;
2697 
2698  if( pBoxFrame )
2699  {
2700  pTab = const_cast<SwFrame*>(static_cast<SwFrame const *>(pBoxFrame))->ImplFindTabFrame();
2701  pBox = pBoxFrame->GetTabBox();
2702  }
2703  else
2704  {
2705  OSL_ENSURE( false, "must specify pBoxFrame" );
2706  return ;
2707  }
2708 
2709  // If the Table is still using relative values (USHRT_MAX)
2710  // we need to switch to absolute ones.
2711  SwTable& rTab = *pTab->GetTable();
2712  const SwFormatFrameSize& rTableFrameSz = rTab.GetFrameFormat()->GetFrameSize();
2713  SwRectFnSet aRectFnSet(pTab);
2714  // #i17174# - With fix for #i9040# the shadow size is taken
2715  // from the table width. Thus, add its left and right size to current table
2716  // printing area width in order to get the correct table size attribute.
2717  SwTwips nPrtWidth = aRectFnSet.GetWidth(pTab->getFramePrintArea());
2718  {
2719  SvxShadowItem aShadow( rTab.GetFrameFormat()->GetShadow() );
2720  nPrtWidth += aShadow.CalcShadowSpace( SvxShadowItemSide::LEFT ) +
2721  aShadow.CalcShadowSpace( SvxShadowItemSide::RIGHT );
2722  }
2723  if( nPrtWidth != rTableFrameSz.GetWidth() )
2724  {
2725  SwFormatFrameSize aSz( rTableFrameSz );
2726  aSz.SetWidth( nPrtWidth );
2727  rTab.GetFrameFormat()->SetFormatAttr( aSz );
2728  }
2729 
2730  SwTabCols aOld( rNew.Count() );
2731 
2732  const SwPageFrame* pPage = pTab->FindPageFrame();
2733  const sal_uLong nLeftMin = aRectFnSet.GetLeft(pTab->getFrameArea()) -
2734  aRectFnSet.GetLeft(pPage->getFrameArea());
2735  const sal_uLong nRightMax = aRectFnSet.GetRight(pTab->getFrameArea()) -
2736  aRectFnSet.GetLeft(pPage->getFrameArea());
2737 
2738  // Set fixed points, LeftMin in Document coordinates, all others relative
2739  aOld.SetLeftMin ( nLeftMin );
2740  aOld.SetLeft ( aRectFnSet.GetLeft(pTab->getFramePrintArea()) );
2741  aOld.SetRight ( aRectFnSet.GetRight(pTab->getFramePrintArea()));
2742  aOld.SetRightMax( nRightMax - nLeftMin );
2743 
2744  rTab.GetTabCols( aOld, pBox );
2745  SetTabCols(rTab, rNew, aOld, pBox, bCurRowOnly );
2746 }
2747 
2748 void SwDoc::SetTabRows( const SwTabCols &rNew, bool bCurColOnly,
2749  const SwCellFrame* pBoxFrame )
2750 {
2751  SwTabFrame *pTab = nullptr;
2752 
2753  if( pBoxFrame )
2754  {
2755  pTab = const_cast<SwFrame*>(static_cast<SwFrame const *>(pBoxFrame))->ImplFindTabFrame();
2756  }
2757  else
2758  {
2759  OSL_ENSURE( false, "must specify pBoxFrame" );
2760  return ;
2761  }
2762 
2763  // If the Table is still using relative values (USHRT_MAX)
2764  // we need to switch to absolute ones.
2765  SwRectFnSet aRectFnSet(pTab);
2766  SwTabCols aOld( rNew.Count() );
2767 
2768  // Set fixed points, LeftMin in Document coordinates, all others relative
2769  const SwPageFrame* pPage = pTab->FindPageFrame();
2770 
2771  aOld.SetRight( aRectFnSet.GetHeight(pTab->getFramePrintArea()) );
2772  tools::Long nLeftMin;
2773  if ( aRectFnSet.IsVert() )
2774  {
2775  nLeftMin = pTab->GetPrtLeft() - pPage->getFrameArea().Left();
2776  aOld.SetLeft ( LONG_MAX );
2777  aOld.SetRightMax( aOld.GetRight() );
2778 
2779  }
2780  else
2781  {
2782  nLeftMin = pTab->GetPrtTop() - pPage->getFrameArea().Top();
2783  aOld.SetLeft ( 0 );
2784  aOld.SetRightMax( LONG_MAX );
2785  }
2786  aOld.SetLeftMin ( nLeftMin );
2787 
2788  GetTabRows( aOld, pBoxFrame );
2789 
2791 
2792  // check for differences between aOld and rNew:
2793  const size_t nCount = rNew.Count();
2794  const SwTable* pTable = pTab->GetTable();
2795  OSL_ENSURE( pTable, "My colleague told me, this couldn't happen" );
2796 
2797  for ( size_t i = 0; i <= nCount; ++i )
2798  {
2799  const size_t nIdxStt = aRectFnSet.IsVert() ? nCount - i : i - 1;
2800  const size_t nIdxEnd = aRectFnSet.IsVert() ? nCount - i - 1 : i;
2801 
2802  const tools::Long nOldRowStart = i == 0 ? 0 : aOld[ nIdxStt ];
2803  const tools::Long nOldRowEnd = i == nCount ? aOld.GetRight() : aOld[ nIdxEnd ];
2804  const tools::Long nOldRowHeight = nOldRowEnd - nOldRowStart;
2805 
2806  const tools::Long nNewRowStart = i == 0 ? 0 : rNew[ nIdxStt ];
2807  const tools::Long nNewRowEnd = i == nCount ? rNew.GetRight() : rNew[ nIdxEnd ];
2808  const tools::Long nNewRowHeight = nNewRowEnd - nNewRowStart;
2809 
2810  const tools::Long nDiff = nNewRowHeight - nOldRowHeight;
2811  if ( std::abs( nDiff ) >= ROWFUZZY )
2812  {
2813  // For the old table model pTextFrame and pLine will be set for every box.
2814  // For the new table model pTextFrame will be set if the box is not covered,
2815  // but the pLine will be set if the box is not an overlapping box
2816  // In the new table model the row height can be adjusted,
2817  // when both variables are set.
2818  const SwTextFrame* pTextFrame = nullptr;
2819  const SwTableLine* pLine = nullptr;
2820 
2821  // Iterate over all SwCellFrames with Bottom = nOldPos
2822  const SwFrame* pFrame = pTab->GetNextLayoutLeaf();
2823  while ( pFrame && pTab->IsAnLower( pFrame ) )
2824  {
2825  if ( pFrame->IsCellFrame() && pFrame->FindTabFrame() == pTab )
2826  {
2827  const tools::Long nLowerBorder = aRectFnSet.GetBottom(pFrame->getFrameArea());
2828  const sal_uLong nTabTop = aRectFnSet.GetPrtTop(*pTab);
2829  if ( std::abs( aRectFnSet.YInc( nTabTop, nOldRowEnd ) - nLowerBorder ) <= ROWFUZZY )
2830  {
2831  if ( !bCurColOnly || pFrame == pBoxFrame )
2832  {
2833  const SwFrame* pContent = ::GetCellContent( static_cast<const SwCellFrame&>(*pFrame) );
2834 
2835  if ( pContent && pContent->IsTextFrame() )
2836  {
2837  const SwTableBox* pBox = static_cast<const SwCellFrame*>(pFrame)->GetTabBox();
2838  const sal_Int32 nRowSpan = pBox->getRowSpan();
2839  if( nRowSpan > 0 ) // Not overlapped
2840  pTextFrame = static_cast<const SwTextFrame*>(pContent);
2841  if( nRowSpan < 2 ) // Not overlapping for row height
2842  pLine = pBox->GetUpper();
2843  if( pLine && pTextFrame ) // always for old table model
2844  {
2845  // The new row height must not to be calculated from an overlapping box
2846  SwFormatFrameSize aNew( pLine->GetFrameFormat()->GetFrameSize() );
2847  const tools::Long nNewSize = aRectFnSet.GetHeight(pFrame->getFrameArea()) + nDiff;
2848  if( nNewSize != aNew.GetHeight() )
2849  {
2850  aNew.SetHeight( nNewSize );
2851  if ( SwFrameSize::Variable == aNew.GetHeightSizeType() )
2852  aNew.SetHeightSizeType( SwFrameSize::Minimum );
2853  // This position must not be in an overlapped box
2854  const SwPosition aPos(*static_cast<const SwTextFrame*>(pContent)->GetTextNodeFirst());
2855  const SwCursor aTmpCursor( aPos, nullptr );
2856  SetRowHeight( aTmpCursor, aNew );
2857  // For the new table model we're done, for the old one
2858  // there might be another (sub)row to adjust...
2859  if( pTable->IsNewModel() )
2860  break;
2861  }
2862  pLine = nullptr;
2863  }
2864  }
2865  }
2866  }
2867  }
2868  pFrame = pFrame->GetNextLayoutLeaf();
2869  }
2870  }
2871  }
2872 
2874 
2875  ::ClearFEShellTabCols(*this, nullptr);
2876 }
2877 
2881 void SwDoc::SetTabCols(SwTable& rTab, const SwTabCols &rNew, const SwTabCols &rOld,
2882  const SwTableBox *pStart, bool bCurRowOnly )
2883 {
2884  if (GetIDocumentUndoRedo().DoesUndo())
2885  {
2887  std::make_unique<SwUndoAttrTable>( *rTab.GetTableNode(), true ));
2888  }
2889  rTab.SetTabCols( rNew, rOld, pStart, bCurRowOnly );
2890  ::ClearFEShellTabCols(*this, nullptr);
2893 }
2894 
2895 void SwDoc::SetRowsToRepeat( SwTable &rTable, sal_uInt16 nSet )
2896 {
2897  if( nSet == rTable.GetRowsToRepeat() )
2898  return;
2899 
2901  {
2903  std::make_unique<SwUndoTableHeadline>(rTable, rTable.GetRowsToRepeat(), nSet) );
2904  }
2905 
2906  const SwMsgPoolItem aChg(RES_TBLHEADLINECHG);
2907  rTable.SetRowsToRepeat( nSet );
2908  rTable.GetFrameFormat()->GetNotifier().Broadcast(sw::LegacyModifyHint(&aChg, &aChg));
2910 }
2911 
2913 {
2914  if( m_pHistory )
2916 }
2917 
2919 {
2920  m_aPositionArr.push_back(m_nWidth);
2921  SwTableBox* p = const_cast<SwTableBox*>(&rBox);
2922  m_Boxes.push_back(p);
2923  m_nWidth = m_nWidth + static_cast<sal_uInt16>(rBox.GetFrameFormat()->GetFrameSize().GetWidth());
2924 }
2925 
2927 {
2928  const SwTableBox* pRet = nullptr;
2929 
2930  if( !m_aPositionArr.empty() )
2931  {
2932  std::vector<sal_uInt16>::size_type n;
2933  for( n = 0; n < m_aPositionArr.size(); ++n )
2934  if( m_aPositionArr[ n ] == m_nWidth )
2935  break;
2936  else if( m_aPositionArr[ n ] > m_nWidth )
2937  {
2938  if( n )
2939  --n;
2940  break;
2941  }
2942 
2943  if( n >= m_aPositionArr.size() )
2944  --n;
2945 
2946  m_nWidth = m_nWidth + static_cast<sal_uInt16>(rBox.GetFrameFormat()->GetFrameSize().GetWidth());
2947  pRet = m_Boxes[ n ];
2948  }
2949  return pRet;
2950 }
2951 
2952 bool SwCollectTableLineBoxes::Resize( sal_uInt16 nOffset, sal_uInt16 nOldWidth )
2953 {
2954  if( !m_aPositionArr.empty() )
2955  {
2956  std::vector<sal_uInt16>::size_type n;
2957  for( n = 0; n < m_aPositionArr.size(); ++n )
2958  {
2959  if( m_aPositionArr[ n ] == nOffset )
2960  break;
2961  else if( m_aPositionArr[ n ] > nOffset )
2962  {
2963  if( n )
2964  --n;
2965  break;
2966  }
2967  }
2968 
2969  m_aPositionArr.erase( m_aPositionArr.begin(), m_aPositionArr.begin() + n );
2970  m_Boxes.erase(m_Boxes.begin(), m_Boxes.begin() + n);
2971 
2972  size_t nArrSize = m_aPositionArr.size();
2973  if (nArrSize)
2974  {
2975  if (nOldWidth == 0)
2976  throw o3tl::divide_by_zero();
2977 
2978  // Adapt the positions to the new Size
2979  for( n = 0; n < nArrSize; ++n )
2980  {
2981  sal_uLong nSize = m_nWidth;
2982  nSize *= ( m_aPositionArr[ n ] - nOffset );
2983  nSize /= nOldWidth;
2984  m_aPositionArr[ n ] = sal_uInt16( nSize );
2985  }
2986  }
2987  }
2988  return !m_aPositionArr.empty();
2989 }
2990 
2991 bool sw_Line_CollectBox( const SwTableLine*& rpLine, void* pPara )
2992 {
2993  SwCollectTableLineBoxes* pSplPara = static_cast<SwCollectTableLineBoxes*>(pPara);
2994  if( pSplPara->IsGetValues() )
2995  for( const auto& rpBox : const_cast<SwTableLine*>(rpLine)->GetTabBoxes() )
2996  sw_Box_CollectBox(rpBox, pSplPara );
2997  else
2998  for( auto& rpBox : const_cast<SwTableLine*>(rpLine)->GetTabBoxes() )
2999  sw_BoxSetSplitBoxFormats(rpBox, pSplPara );
3000  return true;
3001 }
3002 
3004 {
3005  auto nLen = pBox->GetTabLines().size();
3006  if( nLen )
3007  {
3008  // Continue with the actual Line
3009  if( pSplPara->IsGetFromTop() )
3010  nLen = 0;
3011  else
3012  --nLen;
3013 
3014  const SwTableLine* pLn = pBox->GetTabLines()[ nLen ];
3015  sw_Line_CollectBox( pLn, pSplPara );
3016  }
3017  else
3018  pSplPara->AddBox( *pBox );
3019 }
3020 
3022 {
3023  auto nLen = pBox->GetTabLines().size();
3024  if( nLen )
3025  {
3026  // Continue with the actual Line
3027  if( pSplPara->IsGetFromTop() )
3028  nLen = 0;
3029  else
3030  --nLen;
3031 
3032  const SwTableLine* pLn = pBox->GetTabLines()[ nLen ];
3033  sw_Line_CollectBox( pLn, pSplPara );
3034  }
3035  else
3036  {
3037  const SwTableBox* pSrcBox = pSplPara->GetBoxOfPos( *pBox );
3038  SwFrameFormat* pFormat = pSrcBox->GetFrameFormat();
3039 
3040  if( SplitTable_HeadlineOption::BorderCopy == pSplPara->GetMode() )
3041  {
3042  const SvxBoxItem& rBoxItem = pBox->GetFrameFormat()->GetBox();
3043  if( !rBoxItem.GetTop() )
3044  {
3045  SvxBoxItem aNew( rBoxItem );
3046  aNew.SetLine( pFormat->GetBox().GetBottom(), SvxBoxItemLine::TOP );
3047  if( aNew != rBoxItem )
3048  pBox->ClaimFrameFormat()->SetFormatAttr( aNew );
3049  }
3050  }
3051  else
3052  {
3053  sal_uInt16 const aTableSplitBoxSetRange[] {
3058  0 };
3059 
3060  SfxItemSet aTmpSet( pFormat->GetDoc()->GetAttrPool(),
3061  aTableSplitBoxSetRange );
3062  aTmpSet.Put( pFormat->GetAttrSet() );
3063  if( aTmpSet.Count() )
3064  pBox->ClaimFrameFormat()->SetFormatAttr( aTmpSet );
3065 
3067  {
3068  SwNodeIndex aIdx( *pSrcBox->GetSttNd(), 1 );
3069  SwContentNode* pCNd = aIdx.GetNode().GetContentNode();
3070  if( !pCNd )
3071  pCNd = aIdx.GetNodes().GoNext( &aIdx );
3072  aIdx = *pBox->GetSttNd();
3073  SwContentNode* pDNd = aIdx.GetNodes().GoNext( &aIdx );
3074 
3075  // If the Node is alone in the Section
3076  if( 2 == pDNd->EndOfSectionIndex() -
3077  pDNd->StartOfSectionIndex() )
3078  {
3079  pSplPara->AddToUndoHistory( *pDNd );
3080  pDNd->ChgFormatColl( pCNd->GetFormatColl() );
3081  }
3082  }
3083 
3084  // note conditional template
3085  pBox->GetSttNd()->CheckSectionCondColl();
3086  }
3087  }
3088 }
3089 
3100  bool bCalcNewSize )
3101 {
3102  SwNode* pNd = &rPos.nNode.GetNode();
3103  SwTableNode* pTNd = pNd->FindTableNode();
3104  if( !pTNd || pNd->IsTableNode() )
3105  return false;
3106 
3107  if( dynamic_cast<const SwDDETable*>( &pTNd->GetTable() ) != nullptr)
3108  return false;
3109 
3110  SwTable& rTable = pTNd->GetTable();
3111  rTable.SetHTMLTableLayout(std::shared_ptr<SwHTMLTableLayout>()); // Delete HTML Layout
3112 
3113  SwTableFormulaUpdate aMsgHint( &rTable );
3114 
3115  SwHistory aHistory;
3116  if (GetIDocumentUndoRedo().DoesUndo())
3117  {
3118  aMsgHint.m_pHistory = &aHistory;
3119  }
3120 
3121  {
3122  sal_uLong nSttIdx = pNd->FindTableBoxStartNode()->GetIndex();
3123 
3124  // Find top-level Line
3125  SwTableBox* pBox = rTable.GetTableBox( nSttIdx );
3126  if( pBox )
3127  {
3128  SwTableLine* pLine = pBox->GetUpper();
3129  while( pLine->GetUpper() )
3130  pLine = pLine->GetUpper()->GetUpper();
3131 
3132  // pLine contains the top-level Line now
3133  aMsgHint.m_nSplitLine = rTable.GetTabLines().GetPos( pLine );
3134  }
3135 
3136  OUString sNewTableNm( GetUniqueTableName() );
3137  aMsgHint.m_aData.pNewTableNm = &sNewTableNm;
3138  aMsgHint.m_eFlags = TBL_SPLITTBL;
3140  }
3141 
3142  // Find Lines for the Layout update
3143  FndBox_ aFndBox( nullptr, nullptr );
3144  aFndBox.SetTableLines( rTable );
3145  aFndBox.DelFrames( rTable );
3146 
3147  SwTableNode* pNew = GetNodes().SplitTable( rPos.nNode, false, bCalcNewSize );
3148 
3149  if( pNew )
3150  {
3151  std::unique_ptr<SwSaveRowSpan> pSaveRowSp = pNew->GetTable().CleanUpTopRowSpan( rTable.GetTabLines().size() );
3152  SwUndoSplitTable* pUndo = nullptr;
3154  {
3155  pUndo = new SwUndoSplitTable(
3156  *pNew, std::move(pSaveRowSp), eHdlnMode, bCalcNewSize);
3157  GetIDocumentUndoRedo().AppendUndo(std::unique_ptr<SwUndo>(pUndo));
3158  if( aHistory.Count() )
3159  pUndo->SaveFormula( aHistory );
3160  }
3161 
3162  switch( eHdlnMode )
3163  {
3164  // Set the lower Border of the preceding Line to
3165  // the upper Border of the current one
3167  {
3168  SwCollectTableLineBoxes aPara( false, eHdlnMode );
3169  SwTableLine* pLn = rTable.GetTabLines()[
3170  rTable.GetTabLines().size() - 1 ];
3171  for( const auto& rpBox : pLn->GetTabBoxes() )
3172  sw_Box_CollectBox(rpBox, &aPara );
3173 
3174  aPara.SetValues( true );
3175  pLn = pNew->GetTable().GetTabLines()[ 0 ];
3176  for( auto& rpBox : pLn->GetTabBoxes() )
3177  sw_BoxSetSplitBoxFormats(rpBox, &aPara );
3178 
3179  // Switch off repeating Header
3180  pNew->GetTable().SetRowsToRepeat( 0 );
3181  }
3182  break;
3183 
3184  // Take over the Attributes of the first Line to the new one
3187  {
3188  SwHistory* pHst = nullptr;
3189  if( SplitTable_HeadlineOption::BoxAttrAllCopy == eHdlnMode && pUndo )
3190  pHst = pUndo->GetHistory();
3191 
3192  SwCollectTableLineBoxes aPara( true, eHdlnMode, pHst );
3193  SwTableLine* pLn = rTable.GetTabLines()[ 0 ];
3194  for( const auto& rpBox : pLn->GetTabBoxes() )
3195  sw_Box_CollectBox(rpBox, &aPara );
3196 
3197  aPara.SetValues( true );
3198  pLn = pNew->GetTable().GetTabLines()[ 0 ];
3199  for( auto& rpBox : pLn->GetTabBoxes() )
3200  sw_BoxSetSplitBoxFormats(rpBox, &aPara );
3201  }
3202  break;
3203 
3205  rTable.CopyHeadlineIntoTable( *pNew );
3206  if( pUndo )
3207  pUndo->SetTableNodeOffset( pNew->GetIndex() );
3208  break;
3209 
3211  // Switch off repeating the Header
3212  pNew->GetTable().SetRowsToRepeat( 0 );
3213  break;
3214  }
3215 
3216  // And insert Frames
3217  SwNodeIndex aNdIdx( *pNew->EndOfSectionNode() );
3218  GetNodes().GoNext( &aNdIdx ); // To the next ContentNode
3219  pNew->MakeOwnFrames( &aNdIdx );
3220 
3221  // Insert a paragraph between the Table
3222  GetNodes().MakeTextNode( SwNodeIndex( *pNew ),
3223  getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_TEXT ) );
3224  }
3225 
3226  // Update Layout
3227  aFndBox.MakeFrames( rTable );
3228 
3229  // TL_CHART2: need to inform chart of probably changed cell names
3230  UpdateCharts( rTable.GetFrameFormat()->GetName() );
3231 
3232  // update table style formatting of both the tables
3235 
3236  getIDocumentFieldsAccess().SetFieldsDirty( true, nullptr, 0 );
3237 
3238  return nullptr != pNew;
3239 }
3240 
3241 static bool lcl_ChgTableSize( SwTable& rTable )
3242 {
3243  // The Attribute must not be set via the Modify or else all Boxes are
3244  // set back to 0.
3245  // So lock the Format.
3246  SwFrameFormat* pFormat = rTable.GetFrameFormat();
3247  SwFormatFrameSize aTableMaxSz( pFormat->GetFrameSize() );
3248 
3249  if( USHRT_MAX == aTableMaxSz.GetWidth() )
3250  return false;
3251 
3252  bool bLocked = pFormat->IsModifyLocked();
3253  pFormat->LockModify();
3254 
3255  aTableMaxSz.SetWidth( 0 );
3256 
3257  SwTableLines& rLns = rTable.GetTabLines();
3258  for( auto pLn : rLns )
3259  {
3260  SwTwips nMaxLnWidth = 0;
3261  SwTableBoxes& rBoxes = pLn->GetTabBoxes();
3262  for( auto pBox : rBoxes )
3263  nMaxLnWidth += pBox->GetFrameFormat()->GetFrameSize().GetWidth();
3264 
3265  if( nMaxLnWidth > aTableMaxSz.GetWidth() )
3266  aTableMaxSz.SetWidth( nMaxLnWidth );
3267  }
3268  pFormat->SetFormatAttr( aTableMaxSz );
3269  if( !bLocked ) // Release the Lock if appropriate
3270  pFormat->UnlockModify();
3271 
3272  return true;
3273 }
3274 
3275 namespace {
3276 
3277 class SplitTable_Para
3278 {
3279  std::map<SwFrameFormat const*, SwFrameFormat*> m_aSrcDestMap;
3280  SwTableNode* m_pNewTableNode;
3281  SwTable& m_rOldTable;
3282 
3283 public:
3284  SplitTable_Para(SwTableNode* pNew, SwTable& rOld)
3285  : m_aSrcDestMap()
3286  , m_pNewTableNode(pNew)
3287  , m_rOldTable(rOld)
3288  {}
3289  SwFrameFormat* GetDestFormat( SwFrameFormat* pSrcFormat ) const
3290  {
3291  auto it = m_aSrcDestMap.find(pSrcFormat);
3292  return it == m_aSrcDestMap.end() ? nullptr : it->second;
3293  }
3294 
3295  void InsertSrcDest( SwFrameFormat const * pSrcFormat, SwFrameFormat* pDestFormat )
3296  {
3297  m_aSrcDestMap[pSrcFormat] = pDestFormat;
3298  }
3299 
3300  void ChgBox( SwTableBox* pBox )
3301  {
3302  m_rOldTable.GetTabSortBoxes().erase(pBox);
3303  m_pNewTableNode->GetTable().GetTabSortBoxes().insert(pBox);
3304  }
3305 };
3306 
3307 }
3308 
3309 static void lcl_SplitTable_CpyBox( SwTableBox* pBox, SplitTable_Para* pPara );
3310 
3311 static void lcl_SplitTable_CpyLine( SwTableLine* pLn, SplitTable_Para* pPara )
3312 {
3313  SwFrameFormat *pSrcFormat = pLn->GetFrameFormat();
3314  SwTableLineFormat* pDestFormat = static_cast<SwTableLineFormat*>( pPara->GetDestFormat( pSrcFormat ) );
3315  if( pDestFormat == nullptr )
3316  {
3317  pPara->InsertSrcDest( pSrcFormat, pLn->ClaimFrameFormat() );
3318  }
3319  else
3320  pLn->ChgFrameFormat( pDestFormat );
3321 
3322  for( auto& rpBox : pLn->GetTabBoxes() )
3323  lcl_SplitTable_CpyBox(rpBox, pPara );
3324 }
3325 
3326 static void lcl_SplitTable_CpyBox( SwTableBox* pBox, SplitTable_Para* pPara )
3327 {
3328  SwFrameFormat *pSrcFormat = pBox->GetFrameFormat();
3329  SwTableBoxFormat* pDestFormat = static_cast<SwTableBoxFormat*>(pPara->GetDestFormat( pSrcFormat ));
3330  if( pDestFormat == nullptr )
3331  {
3332  pPara->InsertSrcDest( pSrcFormat, pBox->ClaimFrameFormat() );
3333  }
3334  else
3335  pBox->ChgFrameFormat( pDestFormat );
3336 
3337  if( pBox->GetSttNd() )
3338  pPara->ChgBox( pBox );
3339  else
3340  for( SwTableLine* pLine : pBox->GetTabLines() )
3341  lcl_SplitTable_CpyLine( pLine, pPara );
3342 }
3343 
3344 SwTableNode* SwNodes::SplitTable( const SwNodeIndex& rPos, bool bAfter,
3345  bool bCalcNewSize )
3346 {
3347  SwNode* pNd = &rPos.GetNode();
3348  SwTableNode* pTNd = pNd->FindTableNode();
3349  if( !pTNd || pNd->IsTableNode() )
3350  return nullptr;
3351 
3352  sal_uLong nSttIdx = pNd->FindTableBoxStartNode()->GetIndex();
3353 
3354  // Find this Box/top-level line
3355  SwTable& rTable = pTNd->GetTable();
3356  SwTableBox* pBox = rTable.GetTableBox( nSttIdx );
3357  if( !pBox )
3358  return nullptr;
3359 
3360  SwTableLine* pLine = pBox->GetUpper();
3361  while( pLine->GetUpper() )
3362  pLine = pLine->GetUpper()->GetUpper();
3363 
3364  // pLine now contains the top-level line
3365  sal_uInt16 nLinePos = rTable.GetTabLines().GetPos( pLine );
3366  if( USHRT_MAX == nLinePos ||
3367  ( bAfter ? ++nLinePos >= rTable.GetTabLines().size() : !nLinePos ))
3368  return nullptr; // Not found or last Line!
3369 
3370  // Find the first Box of the succeeding Line
3371  SwTableLine* pNextLine = rTable.GetTabLines()[ nLinePos ];
3372  pBox = pNextLine->GetTabBoxes()[0];
3373  while( !pBox->GetSttNd() )
3374  pBox = pBox->GetTabLines()[0]->GetTabBoxes()[0];
3375 
3376  // Insert an EndNode and TableNode into the Nodes Array
3377  SwTableNode * pNewTableNd;
3378  {
3379  SwEndNode* pOldTableEndNd = pTNd->EndOfSectionNode()->GetEndNode();
3380  assert(pOldTableEndNd && "Where is the EndNode?");
3381 
3382  SwNodeIndex aIdx( *pBox->GetSttNd() );
3383  new SwEndNode( aIdx, *pTNd );
3384  pNewTableNd = new SwTableNode( aIdx );
3385  pNewTableNd->GetTable().SetTableModel( rTable.IsNewModel() );
3386 
3387  pOldTableEndNd->m_pStartOfSection = pNewTableNd;
3388  pNewTableNd->m_pEndOfSection = pOldTableEndNd;
3389 
3390  SwNode* pBoxNd = aIdx.GetNode().GetStartNode();
3391  do {
3392  OSL_ENSURE( pBoxNd->IsStartNode(), "This needs to be a StartNode!" );
3393  pBoxNd->m_pStartOfSection = pNewTableNd;
3394  pBoxNd = (*this)[ pBoxNd->EndOfSectionIndex() + 1 ];
3395  } while( pBoxNd != pOldTableEndNd );
3396  }
3397 
3398  {
3399  // Move the Lines
3400  SwTable& rNewTable = pNewTableNd->GetTable();
3401  rNewTable.GetTabLines().insert( rNewTable.GetTabLines().begin(),
3402  rTable.GetTabLines().begin() + nLinePos, rTable.GetTabLines().end() );
3403 
3404  /* From the back (bottom right) to the front (top left) deregister all Boxes from the
3405  Chart Data Provider. The Modify event is triggered in the calling function.
3406  TL_CHART2: */
3408  if( pPCD )
3409  {
3410  for (SwTableLines::size_type k = nLinePos; k < rTable.GetTabLines().size(); ++k)
3411  {
3412  const SwTableLines::size_type nLineIdx = (rTable.GetTabLines().size() - 1) - k + nLinePos;
3413  const SwTableBoxes::size_type nBoxCnt = rTable.GetTabLines()[ nLineIdx ]->GetTabBoxes().size();
3414  for (SwTableBoxes::size_type j = 0; j < nBoxCnt; ++j)
3415  {
3416  const SwTableBoxes::size_type nIdx = nBoxCnt - 1 - j;
3417  pPCD->DeleteBox( &rTable, *rTable.GetTabLines()[ nLineIdx ]->GetTabBoxes()[nIdx] );
3418  }
3419  }
3420  }
3421 
3422  // Delete
3423  sal_uInt16 nDeleted = rTable.GetTabLines().size() - nLinePos;
3424  rTable.GetTabLines().erase( rTable.GetTabLines().begin() + nLinePos, rTable.GetTabLines().end() );
3425 
3426  // Move the affected Boxes. Make the Formats unique and correct the StartNodes
3427  SplitTable_Para aPara( pNewTableNd, rTable );
3428  for( SwTableLine* pNewLine : rNewTable.GetTabLines() )
3429  lcl_SplitTable_CpyLine( pNewLine, &aPara );
3430  rTable.CleanUpBottomRowSpan( nDeleted );
3431  }
3432 
3433  {
3434  // Copy the Table FrameFormat
3435  SwFrameFormat* pOldTableFormat = rTable.GetFrameFormat();
3436  SwFrameFormat* pNewTableFormat = pOldTableFormat->GetDoc()->MakeTableFrameFormat(
3437  pOldTableFormat->GetDoc()->GetUniqueTableName(),
3438  pOldTableFormat->GetDoc()->GetDfltFrameFormat() );
3439 
3440  *pNewTableFormat = *pOldTableFormat;
3441  pNewTableNd->GetTable().RegisterToFormat( *pNewTableFormat );
3442 
3443  pNewTableNd->GetTable().SetTableStyleName(rTable.GetTableStyleName());
3444 
3445  // Calculate a new Size?
3446  // lcl_ChgTableSize: Only execute the second call if the first call was
3447  // successful, thus has an absolute Size
3448  if( bCalcNewSize && lcl_ChgTableSize( rTable ) )
3449  lcl_ChgTableSize( pNewTableNd->GetTable() );
3450  }
3451 
3452  // TL_CHART2: need to inform chart of probably changed cell names
3453  rTable.UpdateCharts();
3454 
3455  return pNewTableNd; // That's it!
3456 }
3457 
3464 bool SwDoc::MergeTable( const SwPosition& rPos, bool bWithPrev, sal_uInt16 nMode )
3465 {
3466  SwTableNode* pTableNd = rPos.nNode.GetNode().FindTableNode(), *pDelTableNd;
3467  if( !pTableNd )
3468  return false;
3469 
3470  SwNodes& rNds = GetNodes();
3471  if( bWithPrev )
3472  pDelTableNd = rNds[ pTableNd->GetIndex() - 1 ]->FindTableNode();
3473  else
3474  pDelTableNd = rNds[ pTableNd->EndOfSectionIndex() + 1 ]->GetTableNode();
3475  if( !pDelTableNd )
3476  return false;
3477 
3478  if( dynamic_cast<const SwDDETable*>( &pTableNd->GetTable() ) != nullptr ||
3479  dynamic_cast<const SwDDETable*>( &pDelTableNd->GetTable() ) != nullptr)
3480  return false;
3481 
3482  // Delete HTML Layout
3483  pTableNd->GetTable().SetHTMLTableLayout(std::shared_ptr<SwHTMLTableLayout>());
3484  pDelTableNd->GetTable().SetHTMLTableLayout(std::shared_ptr<SwHTMLTableLayout>());
3485 
3486  // Both Tables are present; we can start
3487  SwUndoMergeTable* pUndo = nullptr;
3488  std::unique_ptr<SwHistory> pHistory;
3489  if (GetIDocumentUndoRedo().DoesUndo())
3490  {
3491  pUndo = new SwUndoMergeTable( *pTableNd, *pDelTableNd, bWithPrev, nMode );
3492  GetIDocumentUndoRedo().AppendUndo(std::unique_ptr<SwUndo>(pUndo));
3493  pHistory.reset(new SwHistory);
3494  }
3495 
3496  // Adapt all "TableFormulas"
3497  SwTableFormulaUpdate aMsgHint( &pTableNd->GetTable() );
3498  aMsgHint.m_aData.pDelTable = &pDelTableNd->GetTable();
3499  aMsgHint.m_eFlags = TBL_MERGETBL;
3500  aMsgHint.m_pHistory = pHistory.get();
3502 
3503  // The actual merge
3504  SwNodeIndex aIdx( bWithPrev ? *pTableNd : *pDelTableNd );
3505  bool bRet = rNds.MergeTable( aIdx, !bWithPrev, nMode );
3506 
3507  if( pHistory )
3508  {
3509  if( pHistory->Count() )
3510  pUndo->SaveFormula( *pHistory );
3511  pHistory.reset();
3512  }
3513  if( bRet )
3514  {
3516 
3518  getIDocumentFieldsAccess().SetFieldsDirty( true, nullptr, 0 );
3519  }
3520  return bRet;
3521 }
3522 
3523 bool SwNodes::MergeTable( const SwNodeIndex& rPos, bool bWithPrev,
3524  sal_uInt16 nMode )
3525 {
3526  SwTableNode* pDelTableNd = rPos.GetNode().GetTableNode();
3527  OSL_ENSURE( pDelTableNd, "Where did the TableNode go?" );
3528 
3529  SwTableNode* pTableNd = (*this)[ rPos.GetIndex() - 1]->FindTableNode();
3530  OSL_ENSURE( pTableNd, "Where did the TableNode go?" );
3531 
3532  if( !pDelTableNd || !pTableNd )
3533  return false;
3534 
3535  pDelTableNd->DelFrames();
3536 
3537  SwTable& rDelTable = pDelTableNd->GetTable();
3538  SwTable& rTable = pTableNd->GetTable();
3539 
3540  // Find Lines for the Layout update
3541  FndBox_ aFndBox( nullptr, nullptr );
3542  aFndBox.SetTableLines( rTable );
3543  aFndBox.DelFrames( rTable );
3544 
3545  // TL_CHART2:
3546  // tell the charts about the table to be deleted and have them use their own data
3548 
3549  // Sync the TableFormat's Width
3550  {
3551  const SwFormatFrameSize& rTableSz = rTable.GetFrameFormat()->GetFrameSize();
3552  const SwFormatFrameSize& rDelTableSz = rDelTable.GetFrameFormat()->GetFrameSize();
3553  if( rTableSz != rDelTableSz )
3554  {
3555  // The needs correction
3556  if( bWithPrev )
3557  rDelTable.GetFrameFormat()->SetFormatAttr( rTableSz );
3558  else
3559  rTable.GetFrameFormat()->SetFormatAttr( rDelTableSz );
3560  }
3561  }
3562 
3563  if( !bWithPrev )
3564  {
3565  // Transfer all Attributes of the succeeding Table to the preceding one
3566  // We do this, because the succeeding one is deleted when deleting the Node
3567  rTable.SetRowsToRepeat( rDelTable.GetRowsToRepeat() );
3568  rTable.SetTableChgMode( rDelTable.GetTableChgMode() );
3569 
3570  rTable.GetFrameFormat()->LockModify();
3571  *rTable.GetFrameFormat() = *rDelTable.GetFrameFormat();
3572  // Also switch the Name
3573  rTable.GetFrameFormat()->SetName( rDelTable.GetFrameFormat()->GetName() );
3574  rTable.GetFrameFormat()->UnlockModify();
3575  }
3576 
3577  // Move the Lines and Boxes
3578  SwTableLines::size_type nOldSize = rTable.GetTabLines().size();
3579  rTable.GetTabLines().insert( rTable.GetTabLines().begin() + nOldSize,
3580  rDelTable.GetTabLines().begin(), rDelTable.GetTabLines().end() );
3581  rDelTable.GetTabLines().clear();
3582 
3583  rTable.GetTabSortBoxes().insert( rDelTable.GetTabSortBoxes() );
3584  rDelTable.GetTabSortBoxes().clear();
3585 
3586  // The preceding Table always remains, while the succeeding one is deleted
3587  SwEndNode* pTableEndNd = pDelTableNd->EndOfSectionNode();
3588  pTableNd->m_pEndOfSection = pTableEndNd;
3589 
3590  SwNodeIndex aIdx( *pDelTableNd, 1 );
3591 
3592  SwNode* pBoxNd = aIdx.GetNode().GetStartNode();
3593  do {
3594  OSL_ENSURE( pBoxNd->IsStartNode(), "This needs to be a StartNode!" );
3595  pBoxNd->m_pStartOfSection = pTableNd;
3596  pBoxNd = (*this)[ pBoxNd->EndOfSectionIndex() + 1 ];
3597  } while( pBoxNd != pTableEndNd );
3598  pBoxNd->m_pStartOfSection = pTableNd;
3599 
3600  aIdx -= 2;
3601  DelNodes( aIdx, 2 );
3602 
3603  // tweak the conditional styles at the first inserted Line
3604  const SwTableLine* pFirstLn = rTable.GetTabLines()[ nOldSize ];
3605  if( 1 == nMode )
3606  {
3607  // Set Header Template in the Line and save in the History
3608  // if needed for Undo!
3609  }
3610  sw_LineSetHeadCondColl( pFirstLn );
3611 
3612  // Clean up the Borders
3613  if( nOldSize )
3614  {
3615  SwGCLineBorder aPara( rTable );
3616  aPara.nLinePos = --nOldSize;
3617  pFirstLn = rTable.GetTabLines()[ nOldSize ];
3618  sw_GC_Line_Border( pFirstLn, &aPara );
3619  }
3620 
3621  // Update Layout
3622  aFndBox.MakeFrames( rTable );
3623 
3624  return true;
3625 }
3626 
3627 namespace {
3628 
3629 // Use the PtrArray's ForEach method
3630 struct SetAFormatTabPara
3631 {
3632  SwTableAutoFormat& rTableFormat;
3633  SwUndoTableAutoFormat* pUndo;
3634  sal_uInt16 nEndBox, nCurBox;
3635  sal_uInt8 nAFormatLine, nAFormatBox;
3636  bool bSingleRowTable;
3637 
3638  explicit SetAFormatTabPara( const SwTableAutoFormat& rNew )
3639  : rTableFormat( const_cast<SwTableAutoFormat&>(rNew) ), pUndo( nullptr ),
3640  nEndBox( 0 ), nCurBox( 0 ), nAFormatLine( 0 ), nAFormatBox( 0 ), bSingleRowTable(false)
3641  {}
3642 };
3643 
3644 }
3645 
3646 // Forward declare so that the Lines and Boxes can use recursion
3647 static bool lcl_SetAFormatBox(FndBox_ &, SetAFormatTabPara *pSetPara, bool bResetDirect);
3648 static bool lcl_SetAFormatLine(FndLine_ &, SetAFormatTabPara *pPara, bool bResetDirect);
3649 
3650 static bool lcl_SetAFormatLine(FndLine_ & rLine, SetAFormatTabPara *pPara, bool bResetDirect)
3651 {
3652  for (auto const& it : rLine.GetBoxes())
3653  {
3654  lcl_SetAFormatBox(*it, pPara, bResetDirect);
3655  }
3656  return true;
3657 }
3658 
3659 static bool lcl_SetAFormatBox(FndBox_ & rBox, SetAFormatTabPara *pSetPara, bool bResetDirect)
3660 {
3661  if (!rBox.GetUpper()->GetUpper()) // Box on first level?
3662  {
3663  if( !pSetPara->nCurBox )
3664  pSetPara->nAFormatBox = 0;
3665  else if( pSetPara->nCurBox == pSetPara->nEndBox )
3666  pSetPara->nAFormatBox = 3;
3667  else //Even column(1) or Odd column(2)
3668  pSetPara->nAFormatBox = static_cast<sal_uInt8>(1 + ((pSetPara->nCurBox-1) & 1));
3669  }
3670 
3671  if (rBox.GetBox()->GetSttNd())
3672  {
3673  SwTableBox* pSetBox = rBox.GetBox();
3674  if (!pSetBox->HasDirectFormatting() || bResetDirect)
3675  {
3676  if (bResetDirect)
3677  pSetBox->SetDirectFormatting(false);
3678 
3679  SwDoc* pDoc = pSetBox->GetFrameFormat()->GetDoc();
3681  SfxItemSet aBoxSet(pDoc->GetAttrPool(), aTableBoxSetRange);
3682  sal_uInt8 nPos = pSetPara->nAFormatLine * 4 + pSetPara->nAFormatBox;
3683  const bool bSingleRowTable = pSetPara->bSingleRowTable;
3684  const bool bSingleColTable = pSetPara->nEndBox == 0;
3685  pSetPara->rTableFormat.UpdateToSet(nPos, bSingleRowTable, bSingleColTable, aCharSet, SwTableAutoFormatUpdateFlags::Char, nullptr);
3686  pSetPara->rTableFormat.UpdateToSet(nPos, bSingleRowTable, bSingleColTable, aBoxSet, SwTableAutoFormatUpdateFlags::Box, pDoc->GetNumberFormatter());
3687 
3688  if (aCharSet.Count())
3689  {
3690  sal_uLong nSttNd = pSetBox->GetSttIdx()+1;
3691  sal_uLong nEndNd = pSetBox->GetSttNd()->EndOfSectionIndex();
3692  for (; nSttNd < nEndNd; ++nSttNd)
3693  {
3694  SwContentNode* pNd = pDoc->GetNodes()[ nSttNd ]->GetContentNode();
3695  if (pNd)
3696  pNd->SetAttr(aCharSet);
3697  }
3698  }
3699 
3700  if (aBoxSet.Count())
3701  {
3702  if (pSetPara->pUndo && SfxItemState::SET == aBoxSet.GetItemState(RES_BOXATR_FORMAT))
3703  pSetPara->pUndo->SaveBoxContent( *pSetBox );
3704 
3705  pSetBox->ClaimFrameFormat()->SetFormatAttr(aBoxSet);
3706  }
3707  }
3708  }
3709  else
3710  {
3711  // Not sure how this situation can occur, but apparently we have some kind of table in table.
3712  // I am guessing at how to best handle singlerow in this situation.
3713  const bool bOrigSingleRowTable = pSetPara->bSingleRowTable;
3714  pSetPara->bSingleRowTable = rBox.GetLines().size() == 1;
3715  for (auto const& rpFndLine : rBox.GetLines())
3716  {
3717  lcl_SetAFormatLine(*rpFndLine, pSetPara, bResetDirect);
3718  }
3719  pSetPara->bSingleRowTable = bOrigSingleRowTable;
3720  }
3721 
3722  if (!rBox.GetUpper()->GetUpper()) // a BaseLine
3723  ++pSetPara->nCurBox;
3724  return true;
3725 }
3726 
3727 bool SwDoc::SetTableAutoFormat(const SwSelBoxes& rBoxes, const SwTableAutoFormat& rNew, bool bResetDirect, bool const isSetStyleName)
3728 {
3729  OSL_ENSURE( !rBoxes.empty(), "No valid Box list" );
3730  SwTableNode* pTableNd = const_cast<SwTableNode*>(rBoxes[0]->GetSttNd()->FindTableNode());
3731  if( !pTableNd )
3732  return false;
3733 
3734  // Find all Boxes/Lines
3735  FndBox_ aFndBox( nullptr, nullptr );
3736  {
3737  FndPara aPara( rBoxes, &aFndBox );
3738  ForEach_FndLineCopyCol( pTableNd->GetTable().GetTabLines(), &aPara );
3739  }
3740  if( aFndBox.GetLines().empty() )
3741  return false;
3742 
3743  SwTable &table = pTableNd->GetTable();
3744  table.SetHTMLTableLayout(std::shared_ptr<SwHTMLTableLayout>());
3745 
3746  FndBox_* pFndBox = &aFndBox;
3747  while( 1 == pFndBox->GetLines().size() &&
3748  1 == pFndBox->GetLines().front()->GetBoxes().size())
3749  {
3750  pFndBox = pFndBox->GetLines().front()->GetBoxes()[0].get();
3751  }
3752 
3753  if( pFndBox->GetLines().empty() ) // One too far? (only one sel. Box)
3754  pFndBox = pFndBox->GetUpper()->GetUpper();
3755 
3756  // Disable Undo, but first store parameters
3757  SwUndoTableAutoFormat* pUndo = nullptr;
3758  bool const bUndo(GetIDocumentUndoRedo().DoesUndo());
3759  if (bUndo)
3760  {
3761  pUndo = new SwUndoTableAutoFormat( *pTableNd, rNew );
3762  GetIDocumentUndoRedo().AppendUndo(std::unique_ptr<SwUndo>(pUndo));
3763  GetIDocumentUndoRedo().DoUndo(false);
3764  }
3765 
3766  if (isSetStyleName)
3767  { // tdf#98226 do this here where undo can record it
3768  pTableNd->GetTable().SetTableStyleName(rNew.GetName());
3769  }
3770 
3771  rNew.RestoreTableProperties(table);
3772 
3773  SetAFormatTabPara aPara( rNew );
3774  FndLines_t& rFLns = pFndBox->GetLines();
3775  aPara.bSingleRowTable = rFLns.size() == 1;
3776 
3777  for (FndLines_t::size_type n = 0; n < rFLns.size(); ++n)
3778  {
3779  FndLine_* pLine = rFLns[n].get();
3780 
3781  // Set Upper to 0 (thus simulate BaseLine)
3782  FndBox_* pSaveBox = pLine->GetUpper();
3783  pLine->SetUpper( nullptr );
3784 
3785  if( !n )
3786  aPara.nAFormatLine = 0;
3787  else if (static_cast<size_t>(n+1) == rFLns.size())
3788  aPara.nAFormatLine = 3;
3789  else
3790  aPara.nAFormatLine = static_cast<sal_uInt8>(1 + ((n-1) & 1 ));
3791 
3792  aPara.nAFormatBox = 0;
3793  aPara.nCurBox = 0;
3794  aPara.nEndBox = pLine->GetBoxes().size()-1;
3795  aPara.pUndo = pUndo;
3796  for (auto const& it : pLine->GetBoxes())
3797  {
3798  lcl_SetAFormatBox(*it, &aPara, bResetDirect);
3799  }
3800 
3801  pLine->SetUpper( pSaveBox );
3802  }
3803 
3804  if( pUndo )
3805  {
3806  GetIDocumentUndoRedo().DoUndo(bUndo);
3807  }
3808 
3810  getIDocumentFieldsAccess().SetFieldsDirty( true, nullptr, 0 );
3811 
3812  return true;
3813 }
3814 
3819 {
3820  OSL_ENSURE( !rBoxes.empty(), "No valid Box list" );
3821  SwTableNode* pTableNd = const_cast<SwTableNode*>(rBoxes[0]->GetSttNd()->FindTableNode());
3822  if( !pTableNd )
3823  return false;
3824 
3825  // Find all Boxes/Lines
3826  FndBox_ aFndBox( nullptr, nullptr );
3827  {
3828  FndPara aPara( rBoxes, &aFndBox );
3829  ForEach_FndLineCopyCol( pTableNd->GetTable().GetTabLines(), &aPara );
3830  }
3831  if( aFndBox.GetLines().empty() )
3832  return false;
3833 
3834  // Store table properties
3835  SwTable &table = pTableNd->GetTable();
3836  rGet.StoreTableProperties(table);
3837 
3838  FndBox_* pFndBox = &aFndBox;
3839  while( 1 == pFndBox->GetLines().size() &&
3840  1 == pFndBox->GetLines().front()->GetBoxes().size())
3841  {
3842  pFndBox = pFndBox->GetLines().front()->GetBoxes()[0].get();
3843  }
3844 
3845  if( pFndBox->GetLines().empty() ) // One too far? (only one sel. Box)
3846  pFndBox = pFndBox->GetUpper()->GetUpper();
3847 
3848  FndLines_t& rFLns = pFndBox->GetLines();
3849 
3850  sal_uInt16 aLnArr[4];
3851  aLnArr[0] = 0;
3852  aLnArr[1] = 1 < rFLns.size() ? 1 : 0;
3853  aLnArr[2] = 2 < rFLns.size() ? 2 : aLnArr[1];
3854  aLnArr[3] = rFLns.size() - 1;
3855 
3856  for( sal_uInt8 nLine = 0; nLine < 4; ++nLine )
3857  {
3858  FndLine_& rLine = *rFLns[ aLnArr[ nLine ] ];
3859 
3860  sal_uInt16 aBoxArr[4];
3861  aBoxArr[0] = 0;
3862  aBoxArr[1] = 1 < rLine.GetBoxes().size() ? 1 : 0;
3863  aBoxArr[2] = 2 < rLine.GetBoxes().size() ? 2 : aBoxArr[1];
3864  aBoxArr[3] = rLine.GetBoxes().size() - 1;
3865 
3866  for( sal_uInt8 nBox = 0; nBox < 4; ++nBox )
3867  {
3868  SwTableBox* pFBox = rLine.GetBoxes()[ aBoxArr[ nBox ] ]->GetBox();
3869  // Always apply to the first ones
3870  while( !pFBox->GetSttNd() )
3871  pFBox = pFBox->GetTabLines()[0]->GetTabBoxes()[0];
3872 
3873  sal_uInt8 nPos = nLine * 4 + nBox;
3874  SwNodeIndex aIdx( *pFBox->GetSttNd(), 1 );
3875  SwContentNode* pCNd = aIdx.GetNode().GetContentNode();
3876  if( !pCNd )
3877  pCNd = GetNodes().GoNext( &aIdx );
3878 
3879  if( pCNd )
3880  rGet.UpdateFromSet( nPos, pCNd->GetSwAttrSet(),
3882  rGet.UpdateFromSet( nPos, pFBox->GetFrameFormat()->GetAttrSet(),
3884  GetNumberFormatter() );
3885  }
3886  }
3887 
3888  return true;
3889 }
3890 
3892 {
3893  if (!m_pTableStyles)
3894  {
3896  m_pTableStyles->Load();
3897  }
3898  return *m_pTableStyles;
3899 }
3900 
3902 {
3903  if( IsInMailMerge())
3904  {
3905  OUString newName = "MailMergeTable"
3906  + OStringToOUString( DateTimeToOString( DateTime( DateTime::SYSTEM )), RTL_TEXTENCODING_ASCII_US )
3907  + OUString::number( mpTableFrameFormatTable->size() + 1 );
3908  return newName;
3909  }
3910 
3911  const OUString aName(SwResId(STR_TABLE_DEFNAME));
3912 
3913  const size_t nFlagSize = ( mpTableFrameFormatTable->size() / 8 ) + 2;
3914 
3915  std::unique_ptr<sal_uInt8[]> pSetFlags( new sal_uInt8[ nFlagSize ] );
3916  memset( pSetFlags.get(), 0, nFlagSize );
3917 
3918  for( size_t n = 0; n < mpTableFrameFormatTable->size(); ++n )
3919  {
3920  const SwFrameFormat* pFormat = (*mpTableFrameFormatTable)[ n ];
3921  if( !pFormat->IsDefault() && IsUsed( *pFormat ) &&
3922  pFormat->GetName().startsWith( aName ) )
3923  {
3924  // Get number and set the Flag
3925  const sal_Int32 nNmLen = aName.getLength();
3926  size_t nNum = pFormat->GetName().copy( nNmLen ).toInt32();
3927  if( nNum-- && nNum < mpTableFrameFormatTable->size() )
3928  pSetFlags[ nNum / 8 ] |= (0x01 << ( nNum & 0x07 ));
3929  }
3930  }
3931 
3932  // All numbers are flagged properly, thus calculate the right number
3933  size_t nNum = mpTableFrameFormatTable->size();
3934  for( size_t n = 0; n < nFlagSize; ++n )
3935  {
3936  auto nTmp = pSetFlags[ n ];
3937  if( nTmp != 0xFF )
3938  {
3939  // Calculate the number
3940  nNum = n * 8;
3941  while( nTmp & 1 )
3942  {
3943  ++nNum;
3944  nTmp >>= 1;
3945  }
3946  break;
3947  }
3948  }
3949 
3950  return aName + OUString::number( ++nNum );
3951 }
3952 
3953 SwTableFormat* SwDoc::FindTableFormatByName( std::u16string_view rName, bool bAll ) const
3954 {
3955  const SwFormat* pRet = nullptr;
3956  if( bAll )
3957  pRet = FindFormatByName( *mpTableFrameFormatTable, rName );
3958  else
3959  {
3960  // Only the ones set in the Doc
3961  for( size_t n = 0; n < mpTableFrameFormatTable->size(); ++n )
3962  {
3963  const SwFrameFormat* pFormat = (*mpTableFrameFormatTable)[ n ];
3964  if( !pFormat->IsDefault() && IsUsed( *pFormat ) &&
3965  pFormat->GetName() == rName )
3966  {
3967  pRet = pFormat;
3968  break;
3969  }
3970  }
3971  }
3972  return const_cast<SwTableFormat*>(static_cast<const SwTableFormat*>(pRet));
3973 }
3974 
3976  SwTwips nAbsDiff, SwTwips nRelDiff )
3977 {
3978  SwTableNode* pTableNd = const_cast<SwTableNode*>(rCurrentBox.GetSttNd()->FindTableNode());
3979  std::unique_ptr<SwUndo> pUndo;
3980 
3981  SwTableFormulaUpdate aMsgHint( &pTableNd->GetTable() );
3982  aMsgHint.m_eFlags = TBL_BOXPTR;
3984 
3985  bool const bUndo(GetIDocumentUndoRedo().DoesUndo());
3986  bool bRet = false;
3987  switch( extractPosition(eType) )
3988  {
3993  {
3994  bRet = pTableNd->GetTable().SetColWidth( rCurrentBox,
3995  eType, nAbsDiff, nRelDiff,
3996  bUndo ? &pUndo : nullptr );
3997  }
3998  break;
4002  bRet = pTableNd->GetTable().SetRowHeight( rCurrentBox,
4003  eType, nAbsDiff, nRelDiff,
4004  bUndo ? &pUndo : nullptr );
4005  break;
4006  default: break;
4007  }
4008 
4009  GetIDocumentUndoRedo().DoUndo(bUndo); // SetColWidth can turn it off
4010  if( pUndo )
4011  {
4012  GetIDocumentUndoRedo().AppendUndo( std::move(pUndo) );
4013  }
4014 
4015  if( bRet )
4016  {
4018  }
4019  return bRet;
4020 }
4021 
4022 bool SwDoc::IsNumberFormat( const OUString& rString, sal_uInt32& F_Index, double& fOutNumber )
4023 {
4024  if( rString.getLength() > 308 ) // optimization matches svl:IsNumberFormat arbitrary value
4025  return false;
4026 
4027  // remove any comment anchor marks
4028  OUStringBuffer sStringBuffer(rString);
4029  sal_Int32 nCommentPosition = sStringBuffer.indexOf( CH_TXTATR_INWORD );
4030  while( nCommentPosition != -1 )
4031  {
4032  sStringBuffer.remove( nCommentPosition, 1 );
4033  nCommentPosition = sStringBuffer.indexOf( CH_TXTATR_INWORD, nCommentPosition );
4034  }
4035 
4036  return GetNumberFormatter()->IsNumberFormat( sStringBuffer.makeStringAndClear(), F_Index, fOutNumber );
4037 }
4038 
4039 void SwDoc::ChkBoxNumFormat( SwTableBox& rBox, bool bCallUpdate )
4040 {
4041  // Optimization: If the Box says it's Text, it remains Text
4042  const SfxPoolItem* pNumFormatItem = nullptr;
4043  if( SfxItemState::SET == rBox.GetFrameFormat()->GetItemState( RES_BOXATR_FORMAT,
4044  false, &pNumFormatItem ) && GetNumberFormatter()->IsTextFormat(
4045  static_cast<const SwTableBoxNumFormat*>(pNumFormatItem)->GetValue() ))
4046  return ;
4047 
4048  std::unique_ptr<SwUndoTableNumFormat> pUndo;
4049 
4050  bool bIsEmptyTextNd;
4051  bool bChgd = true;
4052  sal_uInt32 nFormatIdx;
4053  double fNumber;
4054  if( rBox.HasNumContent( fNumber, nFormatIdx, bIsEmptyTextNd ) )
4055  {
4056  if( !rBox.IsNumberChanged() )
4057  bChgd = false;
4058  else
4059  {
4061  {
4063  pUndo.reset(new SwUndoTableNumFormat( rBox ));
4064  pUndo->SetNumFormat( nFormatIdx, fNumber );
4065  }
4066 
4067  SwTableBoxFormat* pBoxFormat = static_cast<SwTableBoxFormat*>(rBox.GetFrameFormat());
4069 
4070  bool bLockModify = true;
4071  bool bSetNumberFormat = IsInsTableFormatNum();
4072  const bool bForceNumberFormat = IsInsTableFormatNum() && IsInsTableChangeNumFormat();
4073 
4074  // if the user forced a number format in this cell previously,
4075  // keep it, unless the user set that she wants the full number
4076  // format recognition
4077  if( pNumFormatItem && !bForceNumberFormat )
4078  {
4079  sal_uLong nOldNumFormat = static_cast<const SwTableBoxNumFormat*>(pNumFormatItem)->GetValue();
4080  SvNumberFormatter* pNumFormatr = GetNumberFormatter();
4081 
4082  SvNumFormatType nFormatType = pNumFormatr->GetType( nFormatIdx );
4083  if( nFormatType == pNumFormatr->GetType( nOldNumFormat ) || SvNumFormatType::NUMBER == nFormatType )
4084  {
4085  // Current and specified NumFormat match
4086  // -> keep old Format
4087  nFormatIdx = nOldNumFormat;
4088  bSetNumberFormat = true;
4089  }
4090  else
4091  {
4092  // Current and specified NumFormat do not match
4093  // -> insert as Text
4094  bLockModify = bSetNumberFormat = false;
4095  }
4096  }
4097 
4098  if( bSetNumberFormat || bForceNumberFormat )
4099  {
4100  pBoxFormat = static_cast<SwTableBoxFormat*>(rBox.ClaimFrameFormat());
4101 
4102  aBoxSet.Put( SwTableBoxValue( fNumber ));
4103  aBoxSet.Put( SwTableBoxNumFormat( nFormatIdx ));
4104  }
4105 
4106  // It's not enough to only reset the Formula.
4107  // Make sure that the Text is formatted accordingly
4108  if( !bSetNumberFormat && !bIsEmptyTextNd && pNumFormatItem )
4109  {
4110  // Just resetting Attributes is not enough
4111  // Make sure that the Text is formatted accordingly
4112  pBoxFormat->SetFormatAttr( *GetDfltAttr( RES_BOXATR_FORMAT ));
4113  }
4114 
4115  if( bLockModify ) pBoxFormat->LockModify();
4117  if( bLockModify ) pBoxFormat->UnlockModify();
4118 
4119  if( bSetNumberFormat )
4120  pBoxFormat->SetFormatAttr( aBoxSet );
4121  }
4122  }
4123  else
4124  {
4125  // It's not a number
4126  const SfxPoolItem* pValueItem = nullptr, *pFormatItem = nullptr;
4127  SwTableBoxFormat* pBoxFormat = static_cast<SwTableBoxFormat*>(rBox.GetFrameFormat());
4128  if( SfxItemState::SET == pBoxFormat->GetItemState( RES_BOXATR_FORMAT,
4129  false, &pFormatItem ) ||
4130  SfxItemState::SET == pBoxFormat->GetItemState( RES_BOXATR_VALUE,
4131  false, &pValueItem ))
4132  {
4134  {
4136  pUndo.reset(new SwUndoTableNumFormat( rBox ));
4137  }
4138 
4139  pBoxFormat = static_cast<SwTableBoxFormat*>(rBox.ClaimFrameFormat());
4140 
4141  // Remove all number formats
4142  sal_uInt16 nWhich1 = RES_BOXATR_FORMULA;
4143  if( !bIsEmptyTextNd )
4144  {
4145  nWhich1 = RES_BOXATR_FORMAT;
4146 
4147  // Just resetting Attributes is not enough
4148  // Make sure that the Text is formatted accordingly
4149  pBoxFormat->SetFormatAttr( *GetDfltAttr( nWhich1 ));
4150  }
4151  pBoxFormat->ResetFormatAttr( nWhich1, RES_BOXATR_VALUE );
4152  }
4153  else
4154  bChgd = false;
4155  }
4156 
4157  if( !bChgd )
4158  return;
4159 
4160  if( pUndo )
4161  {
4162  pUndo->SetBox( rBox );
4163  GetIDocumentUndoRedo().AppendUndo(std::move(pUndo));
4165  }
4166 
4167  const SwTableNode* pTableNd = rBox.GetSttNd()->FindTableNode();
4168  if( bCallUpdate )
4169  {
4170  SwTableFormulaUpdate aTableUpdate( &pTableNd->GetTable() );
4171  getIDocumentFieldsAccess().UpdateTableFields( &aTableUpdate );
4172 
4173  // TL_CHART2: update charts (when cursor leaves cell and
4174  // automatic update is enabled)
4175  if (AUTOUPD_FIELD_AND_CHARTS == GetDocumentSettingManager().getFieldUpdateFlags(true))
4176  pTableNd->GetTable().UpdateCharts();
4177  }
4179 }
4180 
4182 {
4183  if (GetIDocumentUndoRedo().DoesUndo())
4184  {
4185  GetIDocumentUndoRedo().AppendUndo( std::make_unique<SwUndoTableNumFormat>(rBox, &rSet) );
4186  }
4187 
4188  SwFrameFormat* pBoxFormat = rBox.ClaimFrameFormat();
4189  if( SfxItemState::SET == rSet.GetItemState( RES_BOXATR_FORMULA ))
4190  {
4191  pBoxFormat->LockModify();
4192  pBoxFormat->ResetFormatAttr( RES_BOXATR_VALUE );
4193  pBoxFormat->UnlockModify();
4194  }
4195  else if( SfxItemState::SET == rSet.GetItemState( RES_BOXATR_VALUE ))
4196  {
4197  pBoxFormat->LockModify();
4198  pBoxFormat->ResetFormatAttr( RES_BOXATR_FORMULA );
4199  pBoxFormat->UnlockModify();
4200  }
4201  pBoxFormat->SetFormatAttr( rSet );
4203 }
4204 
4206 {
4207  SwPaM aPam(rPos);
4208  aPam.Move(fnMoveBackward);
4209  SwContentNode *pNode = aPam.GetContentNode();
4210  if ( nullptr == pNode )
4211  return ;
4212  if( !pNode->IsTextNode() )
4213  return;
4214 
4215  SwTextNode * pTextNode = pNode->GetTextNode();
4216  if (!(pTextNode && pTextNode->IsNumbered()
4217  && pTextNode->GetText().isEmpty()))
4218  return;
4219 
4220  const SfxPoolItem* pFormatItem = nullptr;
4221  SfxItemSet rSet( pTextNode->GetDoc().GetAttrPool(),
4223  pTextNode->SwContentNode::GetAttr( rSet );
4224  if ( SfxItemState::SET != rSet.GetItemState( RES_PARATR_NUMRULE , false , &pFormatItem ) )
4225  return;
4226 
4227  SwUndoDelNum * pUndo;
4228  if( GetIDocumentUndoRedo().DoesUndo() )
4229  {
4231  pUndo = new SwUndoDelNum( aPam );
4232  GetIDocumentUndoRedo().AppendUndo( std::unique_ptr<SwUndo>(pUndo) );
4233  }
4234  else
4235  pUndo = nullptr;
4236  SwRegHistory aRegH( pUndo ? pUndo->GetHistory() : nullptr );
4237  aRegH.RegisterInModify( pTextNode , *pTextNode );
4238  if ( pUndo )
4239  pUndo->AddNode( *pTextNode );
4240  std::unique_ptr<SfxStringItem> pNewItem(static_cast<SfxStringItem*>(pFormatItem->Clone()));
4241  pNewItem->SetValue(OUString());
4242  rSet.Put( std::move(pNewItem) );
4243  pTextNode->SetAttr( rSet );
4244 }
4245 
4247 {
4249  if( nullptr == pSttNd ||
4250  2 != pSttNd->EndOfSectionIndex() - pSttNd->GetIndex())
4251  return;
4252 
4253  SwTableBox* pBox = pSttNd->FindTableNode()->GetTable().
4254  GetTableBox( pSttNd->GetIndex() );
4255 
4256  const SfxPoolItem* pFormatItem = nullptr;
4257  const SfxItemSet& rSet = pBox->GetFrameFormat()->GetAttrSet();
4258  if( !(SfxItemState::SET == rSet.GetItemState( RES_BOXATR_FORMAT, false, &pFormatItem ) ||
4259  SfxItemState::SET == rSet.GetItemState( RES_BOXATR_FORMULA, false ) ||
4260  SfxItemState::SET == rSet.GetItemState( RES_BOXATR_VALUE, false )))
4261  return;
4262 
4264  {
4265  GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoTableNumFormat>(*pBox));
4266  }
4267 
4268  SwFrameFormat* pBoxFormat = pBox->ClaimFrameFormat();
4269 
4270  // Keep TextFormats!
4271  sal_uInt16 nWhich1 = RES_BOXATR_FORMAT;
4272  if( pFormatItem && GetNumberFormatter()->IsTextFormat(
4273  static_cast<const SwTableBoxNumFormat*>(pFormatItem)->GetValue() ))
4274  nWhich1 = RES_BOXATR_FORMULA;
4275  else
4276  // Just resetting Attributes is not enough
4277  // Make sure that the Text is formatted accordingly
4278  pBoxFormat->SetFormatAttr( *GetDfltAttr( RES_BOXATR_FORMAT ));
4279 
4280  pBoxFormat->ResetFormatAttr( nWhich1, RES_BOXATR_VALUE );
4282 }
4283 
4291 bool SwDoc::InsCopyOfTable( SwPosition& rInsPos, const SwSelBoxes& rBoxes,
4292  const SwTable* pCpyTable, bool bCpyName, bool bCorrPos )
4293 {
4294  bool bRet;
4295 
4296  const SwTableNode* pSrcTableNd = pCpyTable
4297  ? pCpyTable->GetTableNode()
4298  : rBoxes[ 0 ]->GetSttNd()->FindTableNode();
4299 
4300  SwTableNode * pInsTableNd = rInsPos.nNode.GetNode().FindTableNode();
4301 
4302  bool const bUndo( GetIDocumentUndoRedo().DoesUndo() );
4303  if( !pCpyTable && !pInsTableNd )
4304  {
4305  std::unique_ptr<SwUndoCpyTable> pUndo;
4306  if (bUndo)
4307  {
4309  pUndo.reset(new SwUndoCpyTable(*this));
4310  }
4311 
4312  {
4313  ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
4314  bRet = pSrcTableNd->GetTable().MakeCopy( *this, rInsPos, rBoxes,
4315  bCpyName );
4316  }
4317 
4318  if( pUndo && bRet )
4319  {
4320  pInsTableNd = GetNodes()[ rInsPos.nNode.GetIndex() - 1 ]->FindTableNode();
4321 
4322  pUndo->SetTableSttIdx( pInsTableNd->GetIndex() );
4323  GetIDocumentUndoRedo().AppendUndo( std::move(pUndo) );
4324  }
4325  }
4326  else
4327  {
4329  if( getIDocumentRedlineAccess().IsRedlineOn() )
4333 
4334  std::unique_ptr<SwUndoTableCpyTable> pUndo;
4335  if (bUndo)
4336  {
4338  pUndo.reset(new SwUndoTableCpyTable(*this));
4339  GetIDocumentUndoRedo().DoUndo(false);
4340  }
4341 
4342  rtl::Reference<SwDoc> xCpyDoc(&const_cast<SwDoc&>(pSrcTableNd->GetDoc()));
4343  bool bDelCpyDoc = xCpyDoc == this;
4344 
4345  if( bDelCpyDoc )
4346  {
4347  // Copy the Table into a temporary Doc
4348  xCpyDoc = new SwDoc;
4349 
4350  SwPosition aPos( SwNodeIndex( xCpyDoc->GetNodes().GetEndOfContent() ));
4351  if( !pSrcTableNd->GetTable().MakeCopy( *xCpyDoc, aPos, rBoxes, true ))
4352  {
4353  xCpyDoc.clear();
4354 
4355  if( pUndo )
4356  {
4357  GetIDocumentUndoRedo().DoUndo(bUndo);
4358  }
4359  return false;
4360  }
4361  aPos.nNode -= 1; // Set to the Table's EndNode
4362  pSrcTableNd = aPos.nNode.GetNode().FindTableNode();
4363  }
4364 
4365  const SwStartNode* pSttNd = rInsPos.nNode.GetNode().FindTableBoxStartNode();
4366 
4367  rInsPos.nContent.Assign( nullptr, 0 );
4368 
4369  // no complex into complex, but copy into or from new model is welcome
4370  if( ( !pSrcTableNd->GetTable().IsTableComplex() || pInsTableNd->GetTable().IsNewModel() )
4371  && ( bDelCpyDoc || !rBoxes.empty() ) )
4372  {
4373  // Copy the Table "relatively"
4374  const SwSelBoxes* pBoxes;
4375  SwSelBoxes aBoxes;
4376 
4377  if( bDelCpyDoc )
4378  {
4379  SwTableBox* pBox = pInsTableNd->GetTable().GetTableBox(
4380  pSttNd->GetIndex() );
4381  OSL_ENSURE( pBox, "Box is not in this Table" );
4382  aBoxes.insert( pBox );
4383  pBoxes = &aBoxes;
4384  }
4385  else
4386  pBoxes = &rBoxes;
4387 
4388  // Copy Table to the selected Lines
4389  bRet = pInsTableNd->GetTable().InsTable( pSrcTableNd->GetTable(),
4390  *pBoxes, pUndo.get() );
4391  }
4392  else
4393  {
4394  SwNodeIndex aNdIdx( *pSttNd, 1 );
4395  bRet = pInsTableNd->GetTable().InsTable( pSrcTableNd->GetTable(),
4396  aNdIdx, pUndo.get() );
4397  }
4398 
4399  xCpyDoc.clear();
4400 
4401  if( pUndo )
4402  {
4403  // If the Table could not be copied, delete the Undo object
4404  GetIDocumentUndoRedo().DoUndo(bUndo);
4405  if( bRet || !pUndo->IsEmpty() )
4406  {
4407  GetIDocumentUndoRedo().AppendUndo(std::move(pUndo));
4408  }
4409  }
4410 
4411  if( bCorrPos )
4412  {
4413  rInsPos.nNode = *pSttNd;
4414  rInsPos.nContent.Assign( GetNodes().GoNext( &rInsPos.nNode ), 0 );
4415  }
4417  }
4418 
4419  if( bRet )
4420  {
4422  getIDocumentFieldsAccess().SetFieldsDirty( true, nullptr, 0 );
4423  }
4424  return bRet;
4425 }
4426 
4428 {
4429  bool bChgd = false;
4430  std::unique_ptr<SwUndoAttrTable> pUndo;
4431  if (GetIDocumentUndoRedo().DoesUndo())
4432  pUndo.reset(new SwUndoAttrTable( *rTable.GetTableNode() ));
4433 
4434  SwTableSortBoxes& rSrtBox = rTable.GetTabSortBoxes();
4435  for (size_t i = rSrtBox.size(); i; )
4436  {
4437  SwFrameFormat *pBoxFormat = rSrtBox[ --i ]->GetFrameFormat();
4438  if( pBoxFormat->GetProtect().IsContentProtected() )
4439  {
4440  pBoxFormat->ResetFormatAttr( RES_PROTECT );
4441  bChgd = true;
4442  }
4443  }
4444 
4445  if( pUndo && bChgd )
4446  GetIDocumentUndoRedo().AppendUndo( std::move(pUndo) );
4447  return bChgd;
4448 }
4449 
4450 void SwDoc::UnProtectCells( std::u16string_view rName )
4451 {
4452  SwTableFormat* pFormat = FindTableFormatByName( rName );
4453  if( pFormat )
4454  {
4455  bool bChgd = UnProtectTableCells( *SwTable::FindTable( pFormat ) );
4456  if( bChgd )
4458  }
4459 }
4460 
4461 bool SwDoc::UnProtectCells( const SwSelBoxes& rBoxes )
4462 {
4463  bool bChgd = false;
4464  if( !rBoxes.empty() )
4465  {
4466  std::unique_ptr<SwUndoAttrTable> pUndo;
4468  pUndo.reset(new SwUndoAttrTable( *rBoxes[0]->GetSttNd()->FindTableNode() ));
4469 
4470  std::map<SwFrameFormat*, SwTableBoxFormat*> aFormatsMap;
4471  for (size_t i = rBoxes.size(); i; )
4472  {
4473  SwTableBox* pBox = rBoxes[ --i ];
4474  SwFrameFormat* pBoxFormat = pBox->GetFrameFormat();
4475  if( pBoxFormat->GetProtect().IsContentProtected() )
4476  {
4477  std::map<SwFrameFormat*, SwTableBoxFormat*>::const_iterator const it =
4478  aFormatsMap.find(pBoxFormat);
4479  if (aFormatsMap.end() != it)
4480  pBox->ChgFrameFormat(it->second);
4481  else
4482  {
4483  SwTableBoxFormat *const pNewBoxFormat(
4484  static_cast<SwTableBoxFormat*>(pBox->ClaimFrameFormat()));
4485  pNewBoxFormat->ResetFormatAttr( RES_PROTECT );
4486  aFormatsMap.insert(std::make_pair(pBoxFormat, pNewBoxFormat));
4487  }
4488  bChgd = true;
4489  }
4490  }
4491 
4492  if( pUndo && bChgd )
4493  GetIDocumentUndoRedo().AppendUndo( std::move(pUndo) );
4494  }
4495  return bChgd;
4496 }
4497 
4498 void SwDoc::UnProtectTables( const SwPaM& rPam )
4499 {
4501 
4502  bool bChgd = false, bHasSel = rPam.HasMark() ||
4503  rPam.GetNext() != &rPam;
4504  SwFrameFormats& rFormats = *GetTableFrameFormats();
4505  SwTable* pTable;
4506  const SwTableNode* pTableNd;
4507  for( auto n = rFormats.size(); n ; )
4508  if( nullptr != (pTable = SwTable::FindTable( rFormats[ --n ] )) &&
4509  nullptr != (pTableNd = pTable->GetTableNode() ) &&
4510  pTableNd->GetNodes().IsDocNodes() )
4511  {
4512  sal_uLong nTableIdx = pTableNd->GetIndex();
4513 
4514  // Check whether the Table is within the Selection
4515  if( bHasSel )
4516  {
4517  bool bFound = false;
4518  SwPaM* pTmp = const_cast<SwPaM*>(&rPam);
4519  do {
4520  const SwPosition *pStt = pTmp->Start(),
4521  *pEnd = pTmp->End();
4522  bFound = pStt->nNode.GetIndex() < nTableIdx &&
4523  nTableIdx < pEnd->nNode.GetIndex();
4524 
4525  } while( !bFound && &rPam != ( pTmp = pTmp->GetNext() ) );
4526  if( !bFound )
4527  continue; // Continue searching
4528  }
4529 
4530  // Lift the protection
4531  bChgd |= UnProtectTableCells( *pTable );
4532  }
4533 
4535  if( bChgd )
4537 }
4538 
4540  const OUString* pTableName,
4541  bool* pFullTableProtection )
4542 {
4543  bool bHasProtection = false;
4544  SwTable* pTable = nullptr;
4545  if( pTableName )
4546  pTable = SwTable::FindTable( FindTableFormatByName( *pTableName ) );
4547  else if( pPos )
4548  {
4549  SwTableNode* pTableNd = pPos->nNode.GetNode().FindTableNode();
4550  if( pTableNd )
4551  pTable = &pTableNd->GetTable();
4552  }
4553 
4554  if( pTable )
4555  {
4556  SwTableSortBoxes& rSrtBox = pTable->GetTabSortBoxes();
4557  for (size_t i = rSrtBox.size(); i; )
4558  {
4559  SwFrameFormat *pBoxFormat = rSrtBox[ --i ]->GetFrameFormat();
4560  if( pBoxFormat->GetProtect().IsContentProtected() )
4561  {
4562  if( !bHasProtection )
4563  {
4564  bHasProtection = true;
4565  if( !pFullTableProtection )
4566  break;
4567  *pFullTableProtection = true;
4568  }
4569  }
4570  else if( bHasProtection && pFullTableProtection )
4571  {
4572  *pFullTableProtection = false;
4573  break;
4574  }
4575  }
4576  }
4577  return bHasProtection;
4578 }
4579 
4580 SwTableAutoFormat* SwDoc::MakeTableStyle(const OUString& rName, bool bBroadcast)
4581 {
4582  SwTableAutoFormat aTableFormat(rName);
4583  GetTableStyles().AddAutoFormat(aTableFormat);
4584  SwTableAutoFormat* pTableFormat = GetTableStyles().FindAutoFormat(rName);
4585 
4587 
4588  if (GetIDocumentUndoRedo().DoesUndo())
4589  {
4591  std::make_unique<SwUndoTableStyleMake>(rName, *this));
4592  }
4593 
4594  if (bBroadcast)
4595  BroadcastStyleOperation(rName, SfxStyleFamily::Table, SfxHintId::StyleSheetCreated);
4596 
4597  return pTableFormat;
4598 }
4599 
4600 std::unique_ptr<SwTableAutoFormat> SwDoc::DelTableStyle(const OUString& rName, bool bBroadcast)
4601 {
4602  if (bBroadcast)
4603  BroadcastStyleOperation(rName, SfxStyleFamily::Table, SfxHintId::StyleSheetErased);
4604 
4605  std::unique_ptr<SwTableAutoFormat> pReleasedFormat = GetTableStyles().ReleaseAutoFormat(rName);
4606 
4607  std::vector<SwTable*> vAffectedTables;
4608  if (pReleasedFormat)
4609  {
4610  size_t nTableCount = GetTableFrameFormatCount(true);
4611  for (size_t i=0; i < nTableCount; ++i)
4612  {
4613  SwFrameFormat* pFrameFormat = &GetTableFrameFormat(i, true);
4614  SwTable* pTable = SwTable::FindTable(pFrameFormat);
4615  if (pTable->GetTableStyleName() == pReleasedFormat->GetName())
4616  {
4617  pTable->SetTableStyleName("");
4618  vAffectedTables.push_back(pTable);
4619  }
4620  }
4621 
4623 
4624  if (GetIDocumentUndoRedo().DoesUndo())
4625  {
4627  std::make_unique<SwUndoTableStyleDelete>(std::move(pReleasedFormat), vAffectedTables, *this));
4628  }
4629  }
4630 
4631  return pReleasedFormat;
4632 }
4633 
4634 void SwDoc::ChgTableStyle(const OUString& rName, const SwTableAutoFormat& rNewFormat)
4635 {
4636  SwTableAutoFormat* pFormat = GetTableStyles().FindAutoFormat(rName);
4637  if (!pFormat)
4638  return;
4639 
4640  SwTableAutoFormat aOldFormat = *pFormat;
4641  *pFormat = rNewFormat;
4642  pFormat->SetName(rName);
4643 
4644  size_t nTableCount = GetTableFrameFormatCount(true);
4645  for (size_t i=0; i < nTableCount; ++i)
4646  {
4647  SwFrameFormat* pFrameFormat = &GetTableFrameFormat(i, true);
4648  SwTable* pTable = SwTable::FindTable(pFrameFormat);
4649  if (pTable->GetTableStyleName() == rName)
4651  }
4652 
4654 
4655  if (GetIDocumentUndoRedo().DoesUndo())
4656  {
4658  std::make_unique<SwUndoTableStyleUpdate>(*pFormat, aOldFormat, *this));
4659  }
4660 }
4661 
4662 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
SwStartNode * FindSttNodeByType(SwStartNodeType eTyp)
Definition: node.cxx:764
bool IsInsTableChangeNumFormat() const
Definition: doc.cxx:1684
sal_uInt16 GetRedlSaveCount() const
Definition: unredln.cxx:84
bool IsAnLower(const SwFrame *) const
Definition: findfrm.cxx:207
SwTableFormat * MakeTableFrameFormat(const OUString &rFormatName, SwFrameFormat *pDerivedFrom)
Definition: docfmt.cxx:799
void SetTableBoxFormulaAttrs(SwTableBox &rBox, const SfxItemSet &rSet)
Definition: ndtbl.cxx:4181
bool IsTableComplex() const
Definition: swtable.cxx:1429
static SwTableBoxFormat * lcl_CreateAFormatBoxFormat(SwDoc &rDoc, std::vector< SwTableBoxFormat * > &rBoxFormatArr, const SwTableAutoFormat &rAutoFormat, const sal_uInt16 nRows, const sal_uInt16 nCols, sal_uInt8 nId)
Definition: ndtbl.cxx:193
const SwEndNode * EndOfSectionNode() const
Definition: node.hxx:686
Starts a section of nodes in the document model.
Definition: node.hxx:312
constexpr TypedWhichId< SvxProtectItem > RES_PROTECT(100)
std::vector< SwTableLine * >::size_type size_type
Definition: swtable.hxx:67
Base class of the Writer layout elements.
Definition: frame.hxx:298
void SetName(const OUString &rNew)
Definition: tblafmt.hxx:207
Represents the visualization of a paragraph.
Definition: txtfrm.hxx:157
const FndLines_t & GetLines() const
Definition: tblsel.hxx:173
constexpr TypedWhichId< SvxFrameDirectionItem > RES_FRAMEDIR(120)
virtual sal_Int32 Len() const
Definition: node.cxx:1245
tools::Long GetWidth() const
SwHistory * GetHistory()
constexpr TypedWhichId< SwFormatPageDesc > RES_PAGEDESC(93)
void SwClearFntCacheTextGlyphs()
Clears the pre-calculated text glyphs in all SwFntObj instances.
Definition: fntcache.cxx:2713
void DeleteMark()
Definition: pam.hxx:177
tools::Long GetRight(const SwRect &rRect) const
Definition: frame.hxx:1361
virtual void Cut() override
Definition: tabfrm.cxx:3637
void KillPams()
Definition: crsrsh.cxx:1025
bool IsInMailMerge() const
Definition: doc.hxx:962
static SwTableBoxFormat * lcl_CreateDfltBoxFormat(SwDoc &rDoc, std::vector< SwTableBoxFormat * > &rBoxFormatArr, sal_uInt16 nCols, sal_uInt8 nId)
Definition: ndtbl.cxx:178
sal_uLong GetIndex() const
Definition: node.hxx:291
bool IsUsed(const sw::BroadcastingModify &) const
Definition: poolfmt.cxx:86
SwNode & GetNode(bool bPoint=true) const
Definition: pam.hxx:223
const Value & back() const
SwTableLineFormat * MakeTableLineFormat()
Definition: docfmt.cxx:1712
SwStartNode * m_pStartOfSection
Definition: node.hxx:113
sal_Int32 nIndex
void Add(SwClient *pDepend)
Definition: calbck.cxx:171
static SwFormat * FindFormatByName(const SwFormatsBase &rFormatArr, std::u16string_view rName)
Definition: docfmt.cxx:1609
bool IsFollow() const
Definition: flowfrm.hxx:166
sal_uLong Count() const
Definition: ndarr.hxx:142
void SetRowsToRepeat(sal_uInt16 nNumOfRows)
Definition: swtable.hxx:196
Represents the style of a paragraph.
Definition: fmtcol.hxx:56
void RegisterToFormat(SwFormat &rFormat)
Definition: swtable.cxx:2734
Marks a position in the document model.
Definition: pam.hxx:35
bool IsSectionNode() const
Definition: node.hxx:648
constexpr TypedWhichId< SvxFontItem > RES_CHRATR_CTL_FONT(27)
void SetLeft(tools::Long nNew)
Definition: tabcol.hxx:83
const SwTableBox * GetTableBox(const OUString &rName, const bool bPerformValidCheck=false) const
Definition: swtable.cxx:1328
static bool lcl_ChgTableSize(SwTable &rTable)
Definition: ndtbl.cxx:3241
bool SplitRow(SwDoc &rDoc, const SwSelBoxes &rBoxes, sal_uInt16 nCnt, bool bSameHeight)
Definition: swtable.hxx:237
std::vector< SwTableBox * > m_Boxes
Definition: tblrwcl.hxx:64
bool IsDefault() const
Definition: format.hxx:113
union SwTableFormulaUpdate::@26 m_aData
sal_uLong StartOfSectionIndex() const
Definition: node.hxx:677
void DelFrames(SwRootFrame const *pLayout=nullptr)
Method deletes all views of document for the node.
Definition: ndtbl.cxx:2442
constexpr TypedWhichId< SwTableBoxNumFormat > RES_BOXATR_FORMAT(RES_BOXATR_BEGIN)
void FindSuperfluousRows(SwSelBoxes &rBoxes)
Definition: swtable.hxx:257
bool IsInsTableFormatNum() const
Definition: doc.cxx:1679
bool TableToText(const SwTableNode *pTableNd, sal_Unicode cCh)
Table to Text.
Definition: ndtbl.cxx:1454
const OUString & GetText() const
Definition: ndtxt.hxx:211
void UpdateCharts() const
Definition: docchart.cxx:34
static void lcl_SetTableBoxWidths2(SwTable &rTable, size_t const nMaxBoxes, SwTableBoxFormat &rBoxFormat, SwDoc &rDoc)
Definition: ndtbl.cxx:1346
virtual const SwRootFrame * GetCurrentLayout() const =0
virtual void Paste(SwFrame *pParent, SwFrame *pSibling=nullptr) override
Definition: tabfrm.cxx:3742
sal_uLong GetSttIdx() const
Definition: swtable.cxx:1866
SwUndoId
Definition: swundo.hxx:29
SwDocShell * GetDocShell()
Definition: doc.hxx:1354
virtual bool SetAttr(const SfxPoolItem &) override
overriding to handle change of certain paragraph attributes
Definition: ndtxt.cxx:4897
std::string GetValue
SvNumberFormatter * GetNumberFormatter(bool bCreate=true)
Definition: doc.hxx:1413
constexpr TypedWhichId< SwTableBoxValue > RES_BOXATR_VALUE(150)
void UpdateToSet(const sal_uInt8 nPos, const bool bSingleRowTable, const bool bSingleColTable, SfxItemSet &rSet, SwTableAutoFormatUpdateFlags eFlags, SvNumberFormatter *) const
Definition: tblafmt.cxx:560
SwHistory * m_pHistory
Definition: hints.hxx:248
virtual AppendResult AppendRedline(SwRangeRedline *pNewRedl, bool bCallDelete)=0
Append a new redline.
const SwFrameFormats * GetTableFrameFormats() const
Definition: doc.hxx:813
virtual void SetRedlineFlags_intern(RedlineFlags eMode)=0
Set a new redline mode.
void RegistFlys()
Definition: tabfrm.cxx:157
virtual SfxPoolItem * Clone(SfxItemPool *pPool=nullptr) const =0
void DeleteRow(const SwCursor &rCursor)
Deleting Columns/Rows.
Definition: ndtbl.cxx:1829
const SwTable * GetTable() const
Definition: tabfrm.hxx:143
void Left(const tools::Long nLeft)
Definition: swrect.hxx:195
SwNodeIndex nNode
Definition: pam.hxx:37
bool IsTableMode() const
Definition: crsrsh.hxx:643
void SetRight(tools::Long nNew)
Definition: tabcol.hxx:84
constexpr TypedWhichId< SwFormatFrameSize > RES_FRM_SIZE(89)
SwDoc & GetDoc()
Which Doc contains the nodes-array?
Definition: ndarr.hxx:302
sal_uInt16 char char * pDesc
static void GetTabCols(SwTabCols &rFill, const SwCellFrame *pBoxFrame)
Definition: ndtbl.cxx:2503
static bool lcl_SetAFormatBox(FndBox_ &, SetAFormatTabPara *pSetPara, bool bResetDirect)
Definition: ndtbl.cxx:3659
virtual void SetModified()=0
Must be called manually at changes of format.
sal_uIntPtr sal_uLong
void StoreTableProperties(const SwTable &table)
Definition: tblafmt.cxx:703
long Long
constexpr TypedWhichId< SwNumRuleItem > RES_PARATR_NUMRULE(72)
OUString GetUniqueTableName() const
Definition: ndtbl.cxx:3901
const SwRect & getFramePrintArea() const
Definition: frame.hxx:179
constexpr TypedWhichId< SvxFontHeightItem > RES_CHRATR_FONTSIZE(8)
const SwPosition * GetMark() const
Definition: pam.hxx:209
SwTabFrame is one table in the document layout, containing rows (which contain cells).
Definition: tabfrm.hxx:30
SwInsertTableFlags mnInsMode
Definition: itabenum.hxx:40
virtual void CreateChartInternalDataProviders(const SwTable *pTable)=0
calls createInternalDataProvider for all charts using the specified table
bool IsContentHidden() const
Check for not hidden areas whether there is content that is not in a hidden sub-area.
Definition: ndsect.cxx:1296
SwContentFrame * getLayoutFrame(const SwRootFrame *, const SwPosition *pPos=nullptr, std::pair< Point, bool > const *pViewPosAndCalcFrame=nullptr) const
Definition: node.cxx:1212
virtual SwContentFrame * MakeFrame(SwFrame *pSib)=0
MakeFrame will be called for a certain layout pSib is another SwFrame of the same layout (e...
sal_Int64 n
virtual SwUndoId EndUndo(SwUndoId const eUndoId, SwRewriter const *const pRewriter)=0
Closes undo block.
Definition: doc.hxx:187
SwFrameFormat * ClaimFrameFormat()
Definition: swtable.cxx:1466
TElementType * Next()
Definition: calbck.hxx:333
bool HasFollow() const
Definition: flowfrm.hxx:165
SvNumFormatType GetType(sal_uInt32 nFIndex) const
void DelFrames(SwTable &rTable)
Definition: tblsel.cxx:2172
sal_Int16 nId
exports com.sun.star. table
TableChgWidthHeightType
Definition: tblenum.hxx:25
bool IsGetFromTop() const
Definition: tblrwcl.hxx:93
constexpr TypedWhichId< SvxFormatBreakItem > RES_BREAK(94)
virtual bool HasExtraRedlineTable() const =0
SwTableLine is one table row in the document model.
Definition: swtable.hxx:351
sal_uInt16 nLinePos
Definition: tblrwcl.hxx:122
void SetTabRows(const SwTabCols &rNew, bool bCurColOnly, const SwCellFrame *pBoxFrame)
Definition: ndtbl.cxx:2748
void PrepareDeleteCol(tools::Long nMin, tools::Long nMax)
SwTable::PrepareDeleteCol(..) adjusts the widths of the neighbour cells of a cell selection for an up...
SwNode & GetNode() const
Definition: ndindex.hxx:119
OUString newName(std::u16string_view aNewPrefix, const OUString &aOldPrefix, std::u16string_view old_Name)
bool HasProtectedCells(const SwSelBoxes &rBoxes)
Definition: tblsel.cxx:856
void RemoveRedlines()
Definition: ndtbl.cxx:2495
bool IsVert() const
Definition: frame.hxx:1348
sal_uInt16 GetRowsToRepeat() const
Definition: swtable.hxx:195
static void DestroyFrame(SwFrame *const pFrame)
this is the only way to delete a SwFrame instance
Definition: ssfrm.cxx:383
SwTextNode * SplitContentNode(const SwPosition &, std::function< void(SwTextNode *, sw::mark::RestoreMode)> const *pContentIndexRestore)
Definition: ndtxt.cxx:412
SwPosition & GetBound(bool bOne=true)
Definition: pam.hxx:245
IDocumentUndoRedo & GetIDocumentUndoRedo()
Definition: doc.cxx:144
bool IsCellFrame() const
Definition: frame.hxx:1207
iterator begin()
Definition: swtable.hxx:76
void CheckSectionCondColl() const
Call ChkCondcoll to all ContentNodes of section.
Definition: node.cxx:975
IDocumentChartDataProviderAccess & getIDocumentChartDataProviderAccess()
Gives access to the chart data-provider.
Definition: format.cxx:716
tools::Long GetWidth(const SwRect &rRect) const
Definition: frame.hxx:1362
bool InsertRow(SwDoc *, const SwSelBoxes &rBoxes, sal_uInt16 nCnt, bool bBehind)
SwTable::InsertRow(..) inserts one or more rows before or behind the selected boxes.
void AddAutoFormat(const SwTableAutoFormat &rFormat)
Append table style to the existing styles.
Definition: tblafmt.cxx:943
IDocumentContentOperations const & getIDocumentContentOperations() const
Definition: doc.cxx:315
bool HasWriterListeners() const
Definition: calbck.hxx:197
The root element of a Writer document layout.
Definition: rootfrm.hxx:82
static void GetTabRows(SwTabCols &rFill, const SwCellFrame *pBoxFrame)
Definition: ndtbl.cxx:2557
sal_uInt16 mnRowsToRepeat
Definition: itabenum.hxx:41
constexpr TypedWhichId< SvxFontItem > RES_CHRATR_FONT(7)
SwTableFormat * GetFrameFormat()
Definition: swtable.hxx:203
void SetValues(bool bFlag)
Definition: tblrwcl.hxx:97
const SwFrameFormats * GetSpzFrameFormats() const
Definition: doc.hxx:744
void ClearBoxNumAttrs(const SwNodeIndex &rNode)
Definition: ndtbl.cxx:4246
Value in Var-direction gives minimum (can be exceeded but not be less).
bool PrepareMerge(const SwPaM &rPam, SwSelBoxes &rBoxes, SwSelBoxes &rMerged, SwTableBox **ppMergeBox, SwUndoTableMerge *pUndo)
SwTable::PrepareMerge(..) some preparation for the coming Merge(..)
Definition: swnewtable.cxx:809
void UnProtectTables(const SwPaM &rPam)
Definition: ndtbl.cxx:4498
size_type size() const
Definition: swtable.hxx:75
static void lcl_SplitTable_CpyBox(SwTableBox *pBox, SplitTable_Para *pPara)
Definition: ndtbl.cxx:3326
void UpdateCharts(std::u16string_view rName) const
Definition: docchart.cxx:120
SwTableNode * TextToTable(const SwNodeRange &rRange, sal_Unicode cCh, SwTableFormat *pTableFormat, SwTableLineFormat *pLineFormat, SwTableBoxFormat *pBoxFormat, SwTextFormatColl *pTextColl, SwUndoTextToTable *pUndo)
Create balanced table from selected range.
Definition: ndtbl.cxx:1000
void ForEach_FndLineCopyCol(SwTableLines &rLines, FndPara *pFndPara)
This creates a structure mirroring the SwTable structure that contains all rows and non-leaf boxes (a...
Definition: tblsel.cxx:2104
bool TableToText(const SwNodeRange &rRange, sal_Unicode cCh, SwUndoTableToText *)
Create regular text from what was table.
Definition: ndtbl.cxx:1591
std::unique_ptr< SwTable > m_pTable
Definition: node.hxx:494
show all inserts
const SvxBoxItem & GetBox(bool=true) const
Definition: frmatr.hxx:84
static void lcl_SetTableBoxWidths(SwTable &rTable, size_t const nMaxBoxes, SwTableBoxFormat &rBoxFormat, SwDoc &rDoc, std::vector< sal_uInt16 > *const pPositions)
Definition: ndtbl.cxx:965
sal_Int32 getRowSpan() const
Definition: swtable.cxx:75
const SwSection & GetSection() const
Definition: node.hxx:545
SwContentNode * GetContentNode(bool bPoint=true) const
Definition: pam.hxx:229
void SetRightMax(tools::Long nNew)
Definition: tabcol.hxx:85
SwTableBox * FindNextBox(const SwTable &, const SwTableBox *=nullptr, bool bOvrTableLns=true) const
Definition: tblrwcl.cxx:2194
tools::Long GetTop(const SwRect &rRect) const
Definition: frame.hxx:1358
void UnProtectCells(std::u16string_view rTableName)
Definition: ndtbl.cxx:4450
void MakeFramesForAdjacentContentNode(SwContentNode &rNode)
Method creates all views of document for given node.
Definition: node.cxx:1359
IDocumentFieldsAccess const & getIDocumentFieldsAccess() const
Definition: doc.cxx:357
constexpr TypedWhichId< SwFormatVertOrient > RES_VERT_ORIENT(102)
bool IsFont() const
Definition: tblafmt.hxx:219
TableMergeErr
Definition: tblenum.hxx:62
void ChgFrameFormat(SwTableLineFormat *pNewFormat)
Definition: swtable.cxx:1499
sal_uInt16 sal_Unicode
bool IsAssignedToListLevelOfOutlineStyle() const
Definition: fmtcol.hxx:114
void MakeFramesForAdjacentContentNode(const SwNodeIndex &rIdx)
Method creates all views of the document for the previous node.
Definition: ndtbl.cxx:2368
void SetUpper(FndBox_ *pUp)
Definition: tblsel.hxx:210
void GetTabCols(SwTabCols &rToFill, const SwTableBox *pStart, bool bHidden=false, bool bCurRowOnly=false) const
Definition: swtable.cxx:510
#define CH_TXTATR_INWORD
Definition: hintids.hxx:170
SwTableNode * GetTableNode()
Definition: node.hxx:603
void JoinAndDelFollows()
Definition: tabfrm.cxx:147
constexpr sal_uInt16 RES_PARATR_BEGIN(RES_TXTATR_END)
static void lcl_SplitTable_CpyLine(SwTableLine *pLn, SplitTable_Para *pPara)
Definition: ndtbl.cxx:3311
std::unique_ptr< SwFrameFormats > mpTableFrameFormatTable
Definition: doc.hxx:243
bool UpdateTableStyleFormatting(SwTableNode *pTableNode=nullptr, bool bResetDirect=false, OUString const *pStyleName=nullptr)
Update the direct formatting according to the current table style.
Definition: fetab.cxx:1200
const SwTableBox * GetTabBox() const
Definition: cellfrm.hxx:52
void RegisterInModify(sw::BroadcastingModify *pRegIn, const SwNode &rNd)
Definition: rolbck.cxx:1496
SwIndex nContent
Definition: pam.hxx:38
bool IsJustify() const
Definition: tblafmt.hxx:220
const SwRect & getFrameArea() const
Definition: frame.hxx:178
SwTableNode * SplitTable(const SwNodeIndex &rPos, bool bAfter=true, bool bCalcNewSize=false)
Splits a table at the base-line which contains the index.
Definition: ndtbl.cxx:3344
friend class SwStartNode
Definition: ndarr.hxx:93
SwNodeIndex aStart
Definition: ndindex.hxx:132
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
void sw_LineSetHeadCondColl(const SwTableLine *pLine)
Definition: tblrwcl.cxx:2331
IDocumentStylePoolAccess const & getIDocumentStylePoolAccess() const
Definition: doc.cxx:426
const SwTextFormatColl * GetDfltTextFormatColl() const
Definition: doc.hxx:778
void SetAttr(const SfxPoolItem &, SwFormat &)
Set attribute in given format.1y If Undo is enabled, the old values is added to the Undo history...
Definition: docfmt.cxx:451
void MakeOwnFrames(SwNodeIndex *pIdxBehind, SwNodeIndex *pEnd=nullptr)
Creates the frms for the SectionNode (i.e.
Definition: ndsect.cxx:1163
static bool IsRedlineOn(const RedlineFlags eM)
std::vector< NodeRanges_t > TableRanges_t
Definition: ndarr.hxx:138
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:230
const OUString & GetName() const
Definition: format.hxx:115
void SetTableModel(bool bNew)
Definition: swtable.hxx:186
int nCount
sal_uLong GetIndex() const
Definition: ndindex.hxx:152
virtual void UpdateTableFields(SfxPoolItem *pHt)=0
virtual void DelLayoutFormat(SwFrameFormat *pFormat)=0
virtual void SetName(const OUString &rNewName, bool bBroadcast=false) override
Definition: atrfrm.cxx:2470
bool IsTextFrame() const
Definition: frame.hxx:1215
virtual void DoUndo(bool const bDoUndo)=0
Enable/Disable Undo.
bool IsStartNode() const
Definition: node.hxx:628
virtual ~SwTableNode() override
Definition: ndtbl.cxx:2350
void SetTabCols(const SwTabCols &rNew, const SwTabCols &rOld, const SwTableBox *pStart, bool bCurRowOnly)
Definition: swtable.cxx:815
const FndBoxes_t & GetBoxes() const
Definition: tblsel.hxx:203
virtual bool SetFieldsDirty(bool b, const SwNode *pChk, sal_uLong nLen)=0
static void lcl_RemoveBreaks(SwContentNode &rNode, SwTableFormat *const pTableFormat)
Definition: ndtbl.cxx:891
Mode eMode
iterator insert(iterator aIt, SwTableLine *pLine)
Definition: swtable.hxx:85
void SetHTMLTableLayout(std::shared_ptr< SwHTMLTableLayout > const &r)
Definition: swtable.cxx:1928
void CopyHeadlineIntoTable(SwTableNode &rTableNd)
Definition: tblrwcl.cxx:2000
const SwTable & GetTable() const
Definition: node.hxx:501
virtual void DeleteSection(SwNode *pNode)=0
Delete section containing the node.
RowColMode
Definition: doc.hxx:1200
void DelNodes(const SwNodeIndex &rStart, sal_uLong nCnt=1)
Delete a number of nodes.
Definition: nodes.cxx:1332
const SfxPoolItem * GetDfltAttr(sal_uInt16 nWhich)
Get the default attribute from corresponding default attribute table.
Definition: hints.cxx:153
const OUString & GetTableStyleName() const
Return the table style name of this table.
Definition: swtable.hxx:190
static sal_uInt8 CountPos(sal_uInt32 nCol, sal_uInt32 nCols, sal_uInt32 nRow, sal_uInt32 nRows)
Calculates the relevant position in the table autoformat for a given cell in a given table...
Definition: tblafmt.cxx:914
void SetAllDistances(sal_uInt16 nNew)
SwTableBox * FindPreviousBox(const SwTable &, const SwTableBox *) const
Definition: tblrwcl.cxx:2312
RedlineFlags on.
tools::Long GetLeft(const SwRect &rRect) const
Definition: frame.hxx:1360
bool InsTable(const SwTable &rCpyTable, const SwNodeIndex &, SwUndoTableCpyTable *pUndo)
Copy Table into this Box.
Definition: tblcpy.cxx:704
virtual bool IsEnableSetModified() const =0
bool SplitCol(SwDoc &rDoc, const SwSelBoxes &rBoxes, sal_uInt16 nCnt)
Definition: tblrwcl.cxx:1151
tools::Long GetPrtLeft() const
Definition: ssfrm.cxx:48
size_type size() const
virtual bool DoesUndo() const =0
Is Undo enabled?
void SetRowHeight(const SwCursor &rCursor, const SwFormatFrameSize &rNew)
Definition: ndtbl1.cxx:385
void sw_BoxSetSplitBoxFormats(SwTableBox *pBox, SwCollectTableLineBoxes *pSplPara)
Definition: ndtbl.cxx:3021
const FndBox_ * GetUpper() const
Definition: tblsel.hxx:207
bool IsGetValues() const
Definition: tblrwcl.hxx:94
SwPaM * GetNext()
Definition: pam.hxx:264
helper class to check if a frame has been deleted during an operation WARNING! This should only be us...
Definition: frmtool.hxx:595
void ClearLineNumAttrs(SwPosition const &rPos)
Definition: ndtbl.cxx:4205
void InsertRow(const SwCursor &rCursor, sal_uInt16 nCnt=1, bool bBehind=true)
Definition: ndtbl.cxx:1770
void DeleteCol(const SwCursor &rCursor)
Definition: ndtbl.cxx:1929
Specific frame formats (frames, DrawObjects).
void MakeFrames(SwTable &rTable)
Definition: tblsel.cxx:2333
Base class for various Writer styles.
Definition: format.hxx:46
void SetTableNodeOffset(sal_uLong nIdx)
Definition: UndoTable.hxx:330
virtual void Paste(SwFrame *pParent, SwFrame *pSibling=nullptr)=0
SwNode & GetEndOfContent() const
Regular ContentSection (i.e. the BodyText).
Definition: ndarr.hxx:163
Class for SplitTable Collects the uppermost or lowermost Lines of a Box from a Line in an array...
Definition: tblrwcl.hxx:61
virtual bool ResetAttr(sal_uInt16 nWhich1, sal_uInt16 nWhich2=0)
Definition: node.cxx:1653
SwTableSortBoxes & GetTabSortBoxes()
Definition: swtable.hxx:261
Table of Contents - heading.
Definition: poolfmt.hxx:341
bool IsContentNode() const
Definition: node.hxx:632
PaM is Point and Mark: a selection of the document model.
Definition: pam.hxx:136
std::unique_ptr< SwTableAutoFormatTable > m_pTableStyles
Table styles (autoformats that are applied with table changes).
Definition: doc.hxx:287
const SwAttrSet * GetpSwAttrSet() const
Definition: node.hxx:452
bool Move(SwMoveFnCollection const &fnMove=fnMoveForward, SwGoInDoc fnGo=GoInContent)
Movement of cursor.
Definition: pam.cxx:504
const editeng::SvxBorderLine * GetTop() const
static SwTable * FindTable(SwFrameFormat const *const pFormat)
Definition: swtable.cxx:1906
virtual void AppendUndo(std::unique_ptr< SwUndo > pUndo)=0
Add new Undo action.
SwTabFrame * ImplFindTabFrame()
Definition: findfrm.cxx:469
virtual void ClearRedo()=0
Delete all Redo actions.
bool SetColWidth(SwTableBox &rCurrentBox, TableChgWidthHeightType eType, SwTwips nAbsDiff, SwTwips nRelDiff, std::unique_ptr< SwUndo > *ppUndo)
Definition: tblrwcl.cxx:2592
Style of a layout element.
Definition: frmfmt.hxx:58
::sw::UndoManager & GetUndoManager()
Definition: doc.cxx:133
bool GoNext(SwNode *pNd, SwIndex *pIdx, sal_uInt16 nMode)
Definition: pam.cxx:291
virtual SwUndoId StartUndo(SwUndoId const eUndoId, SwRewriter const *const pRewriter)=0
Opens undo block.
SwNodeType
Definition: ndtyp.hxx:28
#define SAL_MAX_INT32
virtual const SwExtraRedlineTable & GetExtraRedlineTable() const =0
void Broadcast(const SfxHint &rHint)
SfxItemState GetItemState(sal_uInt16 nWhich, bool bSrchInParent=true, const SfxPoolItem **ppItem=nullptr) const
void SetTableLines(const SwSelBoxes &rBoxes, const SwTable &rTable)
Definition: tblsel.cxx:2110
const SwFormatAnchor & GetAnchor(bool=true) const
Definition: fmtanchr.hxx:81
int i
static void lcl_DelLine(SwTableLine *pLine, DelTabPara *pPara)
Definition: ndtbl.cxx:1518