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