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