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