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