Bug Summary

File:home/maarten/src/libreoffice/core/sw/source/core/docnode/ndtbl.cxx
Warning:line 4625, column 12
Moved-from object 'pReleasedFormat' is moved

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name ndtbl.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -isystem /usr/include/libxml2 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D SW_DLLIMPLEMENTATION -D SWUI_DLL_NAME="libswuilo.so" -D SYSTEM_LIBXML -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/sw/source/core/inc -I /home/maarten/src/libreoffice/core/sw/source/filter/inc -I /home/maarten/src/libreoffice/core/sw/source/uibase/inc -I /home/maarten/src/libreoffice/core/sw/inc -I /home/maarten/src/libreoffice/core/workdir/SdiTarget/sw/sdi -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/sw/generated -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/oovbaapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/sw/source/core/docnode/ndtbl.cxx

/home/maarten/src/libreoffice/core/sw/source/core/docnode/ndtbl.cxx

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

/usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/bits/unique_ptr.h

1// unique_ptr implementation -*- C++ -*-
2
3// Copyright (C) 2008-2020 Free Software Foundation, Inc.
4//
5// This file is part of the GNU ISO C++ Library. This library is free
6// software; you can redistribute it and/or modify it under the
7// terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 3, or (at your option)
9// any later version.
10
11// This library is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// Under Section 7 of GPL version 3, you are granted additional
17// permissions described in the GCC Runtime Library Exception, version
18// 3.1, as published by the Free Software Foundation.
19
20// You should have received a copy of the GNU General Public License and
21// a copy of the GCC Runtime Library Exception along with this program;
22// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23// <http://www.gnu.org/licenses/>.
24
25/** @file bits/unique_ptr.h
26 * This is an internal header file, included by other library headers.
27 * Do not attempt to use it directly. @headername{memory}
28 */
29
30#ifndef _UNIQUE_PTR_H1
31#define _UNIQUE_PTR_H1 1
32
33#include <bits/c++config.h>
34#include <debug/assertions.h>
35#include <type_traits>
36#include <utility>
37#include <tuple>
38#include <bits/stl_function.h>
39#include <bits/functional_hash.h>
40#if __cplusplus201703L > 201703L
41# include <compare>
42# include <ostream>
43#endif
44
45namespace std _GLIBCXX_VISIBILITY(default)__attribute__ ((__visibility__ ("default")))
46{
47_GLIBCXX_BEGIN_NAMESPACE_VERSION
48
49 /**
50 * @addtogroup pointer_abstractions
51 * @{
52 */
53
54#if _GLIBCXX_USE_DEPRECATED1
55#pragma GCC diagnostic push
56#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
57 template<typename> class auto_ptr;
58#pragma GCC diagnostic pop
59#endif
60
61 /// Primary template of default_delete, used by unique_ptr for single objects
62 template<typename _Tp>
63 struct default_delete
64 {
65 /// Default constructor
66 constexpr default_delete() noexcept = default;
67
68 /** @brief Converting constructor.
69 *
70 * Allows conversion from a deleter for objects of another type, `_Up`,
71 * only if `_Up*` is convertible to `_Tp*`.
72 */
73 template<typename _Up,
74 typename = _Require<is_convertible<_Up*, _Tp*>>>
75 default_delete(const default_delete<_Up>&) noexcept { }
76
77 /// Calls `delete __ptr`
78 void
79 operator()(_Tp* __ptr) const
80 {
81 static_assert(!is_void<_Tp>::value,
82 "can't delete pointer to incomplete type");
83 static_assert(sizeof(_Tp)>0,
84 "can't delete pointer to incomplete type");
85 delete __ptr;
86 }
87 };
88
89 // _GLIBCXX_RESOLVE_LIB_DEFECTS
90 // DR 740 - omit specialization for array objects with a compile time length
91
92 /// Specialization of default_delete for arrays, used by `unique_ptr<T[]>`
93 template<typename _Tp>
94 struct default_delete<_Tp[]>
95 {
96 public:
97 /// Default constructor
98 constexpr default_delete() noexcept = default;
99
100 /** @brief Converting constructor.
101 *
102 * Allows conversion from a deleter for arrays of another type, such as
103 * a const-qualified version of `_Tp`.
104 *
105 * Conversions from types derived from `_Tp` are not allowed because
106 * it is undefined to `delete[]` an array of derived types through a
107 * pointer to the base type.
108 */
109 template<typename _Up,
110 typename = _Require<is_convertible<_Up(*)[], _Tp(*)[]>>>
111 default_delete(const default_delete<_Up[]>&) noexcept { }
112
113 /// Calls `delete[] __ptr`
114 template<typename _Up>
115 typename enable_if<is_convertible<_Up(*)[], _Tp(*)[]>::value>::type
116 operator()(_Up* __ptr) const
117 {
118 static_assert(sizeof(_Tp)>0,
119 "can't delete pointer to incomplete type");
120 delete [] __ptr;
121 }
122 };
123
124 /// @cond undocumented
125
126 // Manages the pointer and deleter of a unique_ptr
127 template <typename _Tp, typename _Dp>
128 class __uniq_ptr_impl
129 {
130 template <typename _Up, typename _Ep, typename = void>
131 struct _Ptr
132 {
133 using type = _Up*;
134 };
135
136 template <typename _Up, typename _Ep>
137 struct
138 _Ptr<_Up, _Ep, __void_t<typename remove_reference<_Ep>::type::pointer>>
139 {
140 using type = typename remove_reference<_Ep>::type::pointer;
141 };
142
143 public:
144 using _DeleterConstraint = enable_if<
145 __and_<__not_<is_pointer<_Dp>>,
146 is_default_constructible<_Dp>>::value>;
147
148 using pointer = typename _Ptr<_Tp, _Dp>::type;
149
150 static_assert( !is_rvalue_reference<_Dp>::value,
151 "unique_ptr's deleter type must be a function object type"
152 " or an lvalue reference type" );
153
154 __uniq_ptr_impl() = default;
155 __uniq_ptr_impl(pointer __p) : _M_t() { _M_ptr() = __p; }
156
157 template<typename _Del>
158 __uniq_ptr_impl(pointer __p, _Del&& __d)
159 : _M_t(__p, std::forward<_Del>(__d)) { }
160
161 __uniq_ptr_impl(__uniq_ptr_impl&& __u) noexcept
162 : _M_t(std::move(__u._M_t))
163 { __u._M_ptr() = nullptr; }
164
165 __uniq_ptr_impl& operator=(__uniq_ptr_impl&& __u) noexcept
166 {
167 reset(__u.release());
168 _M_deleter() = std::forward<_Dp>(__u._M_deleter());
169 return *this;
170 }
171
172 pointer& _M_ptr() { return std::get<0>(_M_t); }
173 pointer _M_ptr() const { return std::get<0>(_M_t); }
174 _Dp& _M_deleter() { return std::get<1>(_M_t); }
175 const _Dp& _M_deleter() const { return std::get<1>(_M_t); }
176
177 void reset(pointer __p) noexcept
178 {
179 const pointer __old_p = _M_ptr();
180 _M_ptr() = __p;
181 if (__old_p)
182 _M_deleter()(__old_p);
183 }
184
185 pointer release() noexcept
186 {
187 pointer __p = _M_ptr();
188 _M_ptr() = nullptr;
189 return __p;
190 }
191
192 void
193 swap(__uniq_ptr_impl& __rhs) noexcept
194 {
195 using std::swap;
196 swap(this->_M_ptr(), __rhs._M_ptr());
197 swap(this->_M_deleter(), __rhs._M_deleter());
198 }
199
200 private:
201 tuple<pointer, _Dp> _M_t;
202 };
203
204 // Defines move construction + assignment as either defaulted or deleted.
205 template <typename _Tp, typename _Dp,
206 bool = is_move_constructible<_Dp>::value,
207 bool = is_move_assignable<_Dp>::value>
208 struct __uniq_ptr_data : __uniq_ptr_impl<_Tp, _Dp>
209 {
210 using __uniq_ptr_impl<_Tp, _Dp>::__uniq_ptr_impl;
211 __uniq_ptr_data(__uniq_ptr_data&&) = default;
212 __uniq_ptr_data& operator=(__uniq_ptr_data&&) = default;
213 };
214
215 template <typename _Tp, typename _Dp>
216 struct __uniq_ptr_data<_Tp, _Dp, true, false> : __uniq_ptr_impl<_Tp, _Dp>
217 {
218 using __uniq_ptr_impl<_Tp, _Dp>::__uniq_ptr_impl;
219 __uniq_ptr_data(__uniq_ptr_data&&) = default;
220 __uniq_ptr_data& operator=(__uniq_ptr_data&&) = delete;
221 };
222
223 template <typename _Tp, typename _Dp>
224 struct __uniq_ptr_data<_Tp, _Dp, false, true> : __uniq_ptr_impl<_Tp, _Dp>
225 {
226 using __uniq_ptr_impl<_Tp, _Dp>::__uniq_ptr_impl;
227 __uniq_ptr_data(__uniq_ptr_data&&) = delete;
228 __uniq_ptr_data& operator=(__uniq_ptr_data&&) = default;
229 };
230
231 template <typename _Tp, typename _Dp>
232 struct __uniq_ptr_data<_Tp, _Dp, false, false> : __uniq_ptr_impl<_Tp, _Dp>
233 {
234 using __uniq_ptr_impl<_Tp, _Dp>::__uniq_ptr_impl;
235 __uniq_ptr_data(__uniq_ptr_data&&) = delete;
236 __uniq_ptr_data& operator=(__uniq_ptr_data&&) = delete;
237 };
238 /// @endcond
239
240 /// 20.7.1.2 unique_ptr for single objects.
241 template <typename _Tp, typename _Dp = default_delete<_Tp>>
242 class unique_ptr
243 {
244 template <typename _Up>
245 using _DeleterConstraint =
246 typename __uniq_ptr_impl<_Tp, _Up>::_DeleterConstraint::type;
247
248 __uniq_ptr_data<_Tp, _Dp> _M_t;
249
250 public:
251 using pointer = typename __uniq_ptr_impl<_Tp, _Dp>::pointer;
252 using element_type = _Tp;
253 using deleter_type = _Dp;
254
255 private:
256 // helper template for detecting a safe conversion from another
257 // unique_ptr
258 template<typename _Up, typename _Ep>
259 using __safe_conversion_up = __and_<
260 is_convertible<typename unique_ptr<_Up, _Ep>::pointer, pointer>,
261 __not_<is_array<_Up>>
262 >;
263
264 public:
265 // Constructors.
266
267 /// Default constructor, creates a unique_ptr that owns nothing.
268 template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>>
269 constexpr unique_ptr() noexcept
270 : _M_t()
271 { }
272
273 /** Takes ownership of a pointer.
274 *
275 * @param __p A pointer to an object of @c element_type
276 *
277 * The deleter will be value-initialized.
278 */
279 template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>>
280 explicit
281 unique_ptr(pointer __p) noexcept
282 : _M_t(__p)
283 { }
284
285 /** Takes ownership of a pointer.
286 *
287 * @param __p A pointer to an object of @c element_type
288 * @param __d A reference to a deleter.
289 *
290 * The deleter will be initialized with @p __d
291 */
292 template<typename _Del = deleter_type,
293 typename = _Require<is_copy_constructible<_Del>>>
294 unique_ptr(pointer __p, const deleter_type& __d) noexcept
295 : _M_t(__p, __d) { }
296
297 /** Takes ownership of a pointer.
298 *
299 * @param __p A pointer to an object of @c element_type
300 * @param __d An rvalue reference to a (non-reference) deleter.
301 *
302 * The deleter will be initialized with @p std::move(__d)
303 */
304 template<typename _Del = deleter_type,
305 typename = _Require<is_move_constructible<_Del>>>
306 unique_ptr(pointer __p,
307 __enable_if_t<!is_lvalue_reference<_Del>::value,
308 _Del&&> __d) noexcept
309 : _M_t(__p, std::move(__d))
310 { }
311
312 template<typename _Del = deleter_type,
313 typename _DelUnref = typename remove_reference<_Del>::type>
314 unique_ptr(pointer,
315 __enable_if_t<is_lvalue_reference<_Del>::value,
316 _DelUnref&&>) = delete;
317
318 /// Creates a unique_ptr that owns nothing.
319 template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>>
320 constexpr unique_ptr(nullptr_t) noexcept
321 : _M_t()
322 { }
323
324 // Move constructors.
325
326 /// Move constructor.
327 unique_ptr(unique_ptr&&) = default;
328
329 /** @brief Converting constructor from another type
330 *
331 * Requires that the pointer owned by @p __u is convertible to the
332 * type of pointer owned by this object, @p __u does not own an array,
333 * and @p __u has a compatible deleter type.
334 */
335 template<typename _Up, typename _Ep, typename = _Require<
336 __safe_conversion_up<_Up, _Ep>,
337 typename conditional<is_reference<_Dp>::value,
338 is_same<_Ep, _Dp>,
339 is_convertible<_Ep, _Dp>>::type>>
340 unique_ptr(unique_ptr<_Up, _Ep>&& __u) noexcept
341 : _M_t(__u.release(), std::forward<_Ep>(__u.get_deleter()))
342 { }
343
344#if _GLIBCXX_USE_DEPRECATED1
345#pragma GCC diagnostic push
346#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
347 /// Converting constructor from @c auto_ptr
348 template<typename _Up, typename = _Require<
349 is_convertible<_Up*, _Tp*>, is_same<_Dp, default_delete<_Tp>>>>
350 unique_ptr(auto_ptr<_Up>&& __u) noexcept;
351#pragma GCC diagnostic pop
352#endif
353
354 /// Destructor, invokes the deleter if the stored pointer is not null.
355 ~unique_ptr() noexcept
356 {
357 static_assert(__is_invocable<deleter_type&, pointer>::value,
358 "unique_ptr's deleter must be invocable with a pointer");
359 auto& __ptr = _M_t._M_ptr();
360 if (__ptr != nullptr)
361 get_deleter()(std::move(__ptr));
362 __ptr = pointer();
363 }
364
365 // Assignment.
366
367 /** @brief Move assignment operator.
368 *
369 * Invokes the deleter if this object owns a pointer.
370 */
371 unique_ptr& operator=(unique_ptr&&) = default;
372
373 /** @brief Assignment from another type.
374 *
375 * @param __u The object to transfer ownership from, which owns a
376 * convertible pointer to a non-array object.
377 *
378 * Invokes the deleter if this object owns a pointer.
379 */
380 template<typename _Up, typename _Ep>
381 typename enable_if< __and_<
382 __safe_conversion_up<_Up, _Ep>,
383 is_assignable<deleter_type&, _Ep&&>
384 >::value,
385 unique_ptr&>::type
386 operator=(unique_ptr<_Up, _Ep>&& __u) noexcept
387 {
388 reset(__u.release());
389 get_deleter() = std::forward<_Ep>(__u.get_deleter());
390 return *this;
391 }
392
393 /// Reset the %unique_ptr to empty, invoking the deleter if necessary.
394 unique_ptr&
395 operator=(nullptr_t) noexcept
396 {
397 reset();
398 return *this;
399 }
400
401 // Observers.
402
403 /// Dereference the stored pointer.
404 typename add_lvalue_reference<element_type>::type
405 operator*() const
406 {
407 __glibcxx_assert(get() != pointer());
408 return *get();
409 }
410
411 /// Return the stored pointer.
412 pointer
413 operator->() const noexcept
414 {
415 _GLIBCXX_DEBUG_PEDASSERT(get() != pointer());
416 return get();
417 }
418
419 /// Return the stored pointer.
420 pointer
421 get() const noexcept
422 { return _M_t._M_ptr(); }
423
424 /// Return a reference to the stored deleter.
425 deleter_type&
426 get_deleter() noexcept
427 { return _M_t._M_deleter(); }
428
429 /// Return a reference to the stored deleter.
430 const deleter_type&
431 get_deleter() const noexcept
432 { return _M_t._M_deleter(); }
433
434 /// Return @c true if the stored pointer is not null.
435 explicit operator bool() const noexcept
436 { return get() == pointer() ? false : true; }
437
438 // Modifiers.
439
440 /// Release ownership of any stored pointer.
441 pointer
442 release() noexcept
443 { return _M_t.release(); }
444
445 /** @brief Replace the stored pointer.
446 *
447 * @param __p The new pointer to store.
448 *
449 * The deleter will be invoked if a pointer is already owned.
450 */
451 void
452 reset(pointer __p = pointer()) noexcept
453 {
454 static_assert(__is_invocable<deleter_type&, pointer>::value,
455 "unique_ptr's deleter must be invocable with a pointer");
456 _M_t.reset(std::move(__p));
457 }
458
459 /// Exchange the pointer and deleter with another object.
460 void
461 swap(unique_ptr& __u) noexcept
462 {
463 static_assert(__is_swappable<_Dp>::value, "deleter must be swappable");
464 _M_t.swap(__u._M_t);
465 }
466
467 // Disable copy from lvalue.
468 unique_ptr(const unique_ptr&) = delete;
469 unique_ptr& operator=(const unique_ptr&) = delete;
470 };
471
472 /// 20.7.1.3 unique_ptr for array objects with a runtime length
473 // [unique.ptr.runtime]
474 // _GLIBCXX_RESOLVE_LIB_DEFECTS
475 // DR 740 - omit specialization for array objects with a compile time length
476 template<typename _Tp, typename _Dp>
477 class unique_ptr<_Tp[], _Dp>
478 {
479 template <typename _Up>
480 using _DeleterConstraint =
481 typename __uniq_ptr_impl<_Tp, _Up>::_DeleterConstraint::type;
482
483 __uniq_ptr_data<_Tp, _Dp> _M_t;
484
485 template<typename _Up>
486 using __remove_cv = typename remove_cv<_Up>::type;
487
488 // like is_base_of<_Tp, _Up> but false if unqualified types are the same
489 template<typename _Up>
490 using __is_derived_Tp
491 = __and_< is_base_of<_Tp, _Up>,
492 __not_<is_same<__remove_cv<_Tp>, __remove_cv<_Up>>> >;
493
494 public:
495 using pointer = typename __uniq_ptr_impl<_Tp, _Dp>::pointer;
496 using element_type = _Tp;
497 using deleter_type = _Dp;
498
499 // helper template for detecting a safe conversion from another
500 // unique_ptr
501 template<typename _Up, typename _Ep,
502 typename _UPtr = unique_ptr<_Up, _Ep>,
503 typename _UP_pointer = typename _UPtr::pointer,
504 typename _UP_element_type = typename _UPtr::element_type>
505 using __safe_conversion_up = __and_<
506 is_array<_Up>,
507 is_same<pointer, element_type*>,
508 is_same<_UP_pointer, _UP_element_type*>,
509 is_convertible<_UP_element_type(*)[], element_type(*)[]>
510 >;
511
512 // helper template for detecting a safe conversion from a raw pointer
513 template<typename _Up>
514 using __safe_conversion_raw = __and_<
515 __or_<__or_<is_same<_Up, pointer>,
516 is_same<_Up, nullptr_t>>,
517 __and_<is_pointer<_Up>,
518 is_same<pointer, element_type*>,
519 is_convertible<
520 typename remove_pointer<_Up>::type(*)[],
521 element_type(*)[]>
522 >
523 >
524 >;
525
526 // Constructors.
527
528 /// Default constructor, creates a unique_ptr that owns nothing.
529 template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>>
530 constexpr unique_ptr() noexcept
531 : _M_t()
532 { }
533
534 /** Takes ownership of a pointer.
535 *
536 * @param __p A pointer to an array of a type safely convertible
537 * to an array of @c element_type
538 *
539 * The deleter will be value-initialized.
540 */
541 template<typename _Up,
542 typename _Vp = _Dp,
543 typename = _DeleterConstraint<_Vp>,
544 typename = typename enable_if<
545 __safe_conversion_raw<_Up>::value, bool>::type>
546 explicit
547 unique_ptr(_Up __p) noexcept
548 : _M_t(__p)
549 { }
550
551 /** Takes ownership of a pointer.
552 *
553 * @param __p A pointer to an array of a type safely convertible
554 * to an array of @c element_type
555 * @param __d A reference to a deleter.
556 *
557 * The deleter will be initialized with @p __d
558 */
559 template<typename _Up, typename _Del = deleter_type,
560 typename = _Require<__safe_conversion_raw<_Up>,
561 is_copy_constructible<_Del>>>
562 unique_ptr(_Up __p, const deleter_type& __d) noexcept
563 : _M_t(__p, __d) { }
564
565 /** Takes ownership of a pointer.
566 *
567 * @param __p A pointer to an array of a type safely convertible
568 * to an array of @c element_type
569 * @param __d A reference to a deleter.
570 *
571 * The deleter will be initialized with @p std::move(__d)
572 */
573 template<typename _Up, typename _Del = deleter_type,
574 typename = _Require<__safe_conversion_raw<_Up>,
575 is_move_constructible<_Del>>>
576 unique_ptr(_Up __p,
577 __enable_if_t<!is_lvalue_reference<_Del>::value,
578 _Del&&> __d) noexcept
579 : _M_t(std::move(__p), std::move(__d))
580 { }
581
582 template<typename _Up, typename _Del = deleter_type,
583 typename _DelUnref = typename remove_reference<_Del>::type,
584 typename = _Require<__safe_conversion_raw<_Up>>>
585 unique_ptr(_Up,
586 __enable_if_t<is_lvalue_reference<_Del>::value,
587 _DelUnref&&>) = delete;
588
589 /// Move constructor.
590 unique_ptr(unique_ptr&&) = default;
591
592 /// Creates a unique_ptr that owns nothing.
593 template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>>
594 constexpr unique_ptr(nullptr_t) noexcept
595 : _M_t()
596 { }
597
598 template<typename _Up, typename _Ep, typename = _Require<
599 __safe_conversion_up<_Up, _Ep>,
600 typename conditional<is_reference<_Dp>::value,
601 is_same<_Ep, _Dp>,
602 is_convertible<_Ep, _Dp>>::type>>
603 unique_ptr(unique_ptr<_Up, _Ep>&& __u) noexcept
604 : _M_t(__u.release(), std::forward<_Ep>(__u.get_deleter()))
605 { }
606
607 /// Destructor, invokes the deleter if the stored pointer is not null.
608 ~unique_ptr()
609 {
610 auto& __ptr = _M_t._M_ptr();
611 if (__ptr != nullptr)
612 get_deleter()(__ptr);
613 __ptr = pointer();
614 }
615
616 // Assignment.
617
618 /** @brief Move assignment operator.
619 *
620 * Invokes the deleter if this object owns a pointer.
621 */
622 unique_ptr&
623 operator=(unique_ptr&&) = default;
624
625 /** @brief Assignment from another type.
626 *
627 * @param __u The object to transfer ownership from, which owns a
628 * convertible pointer to an array object.
629 *
630 * Invokes the deleter if this object owns a pointer.
631 */
632 template<typename _Up, typename _Ep>
633 typename
634 enable_if<__and_<__safe_conversion_up<_Up, _Ep>,
635 is_assignable<deleter_type&, _Ep&&>
636 >::value,
637 unique_ptr&>::type
638 operator=(unique_ptr<_Up, _Ep>&& __u) noexcept
639 {
640 reset(__u.release());
641 get_deleter() = std::forward<_Ep>(__u.get_deleter());
642 return *this;
643 }
644
645 /// Reset the %unique_ptr to empty, invoking the deleter if necessary.
646 unique_ptr&
647 operator=(nullptr_t) noexcept
648 {
649 reset();
650 return *this;
651 }
652
653 // Observers.
654
655 /// Access an element of owned array.
656 typename std::add_lvalue_reference<element_type>::type
657 operator[](size_t __i) const
658 {
659 __glibcxx_assert(get() != pointer());
660 return get()[__i];
661 }
662
663 /// Return the stored pointer.
664 pointer
665 get() const noexcept
666 { return _M_t._M_ptr(); }
667
668 /// Return a reference to the stored deleter.
669 deleter_type&
670 get_deleter() noexcept
671 { return _M_t._M_deleter(); }
672
673 /// Return a reference to the stored deleter.
674 const deleter_type&
675 get_deleter() const noexcept
676 { return _M_t._M_deleter(); }
677
678 /// Return @c true if the stored pointer is not null.
679 explicit operator bool() const noexcept
680 { return get() == pointer() ? false : true; }
681
682 // Modifiers.
683
684 /// Release ownership of any stored pointer.
685 pointer
686 release() noexcept
687 { return _M_t.release(); }
688
689 /** @brief Replace the stored pointer.
690 *
691 * @param __p The new pointer to store.
692 *
693 * The deleter will be invoked if a pointer is already owned.
694 */
695 template <typename _Up,
696 typename = _Require<
697 __or_<is_same<_Up, pointer>,
698 __and_<is_same<pointer, element_type*>,
699 is_pointer<_Up>,
700 is_convertible<
701 typename remove_pointer<_Up>::type(*)[],
702 element_type(*)[]
703 >
704 >
705 >
706 >>
707 void
708 reset(_Up __p) noexcept
709 { _M_t.reset(std::move(__p)); }
710
711 void reset(nullptr_t = nullptr) noexcept
712 { reset(pointer()); }
713
714 /// Exchange the pointer and deleter with another object.
715 void
716 swap(unique_ptr& __u) noexcept
717 {
718 static_assert(__is_swappable<_Dp>::value, "deleter must be swappable");
719 _M_t.swap(__u._M_t);
720 }
721
722 // Disable copy from lvalue.
723 unique_ptr(const unique_ptr&) = delete;
724 unique_ptr& operator=(const unique_ptr&) = delete;
725 };
726
727 /// @relates unique_ptr @{
728
729 /// Swap overload for unique_ptr
730 template<typename _Tp, typename _Dp>
731 inline
732#if __cplusplus201703L > 201402L || !defined(__STRICT_ANSI__1) // c++1z or gnu++11
733 // Constrained free swap overload, see p0185r1
734 typename enable_if<__is_swappable<_Dp>::value>::type
735#else
736 void
737#endif
738 swap(unique_ptr<_Tp, _Dp>& __x,
739 unique_ptr<_Tp, _Dp>& __y) noexcept
740 { __x.swap(__y); }
741
742#if __cplusplus201703L > 201402L || !defined(__STRICT_ANSI__1) // c++1z or gnu++11
743 template<typename _Tp, typename _Dp>
744 typename enable_if<!__is_swappable<_Dp>::value>::type
745 swap(unique_ptr<_Tp, _Dp>&,
746 unique_ptr<_Tp, _Dp>&) = delete;
747#endif
748
749 /// Equality operator for unique_ptr objects, compares the owned pointers
750 template<typename _Tp, typename _Dp,
751 typename _Up, typename _Ep>
752 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
753 operator==(const unique_ptr<_Tp, _Dp>& __x,
754 const unique_ptr<_Up, _Ep>& __y)
755 { return __x.get() == __y.get(); }
756
757 /// unique_ptr comparison with nullptr
758 template<typename _Tp, typename _Dp>
759 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
760 operator==(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) noexcept
761 { return !__x; }
762
763#ifndef __cpp_lib_three_way_comparison
764 /// unique_ptr comparison with nullptr
765 template<typename _Tp, typename _Dp>
766 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
767 operator==(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) noexcept
768 { return !__x; }
769
770 /// Inequality operator for unique_ptr objects, compares the owned pointers
771 template<typename _Tp, typename _Dp,
772 typename _Up, typename _Ep>
773 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
774 operator!=(const unique_ptr<_Tp, _Dp>& __x,
775 const unique_ptr<_Up, _Ep>& __y)
776 { return __x.get() != __y.get(); }
777
778 /// unique_ptr comparison with nullptr
779 template<typename _Tp, typename _Dp>
780 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
781 operator!=(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) noexcept
782 { return (bool)__x; }
783
784 /// unique_ptr comparison with nullptr
785 template<typename _Tp, typename _Dp>
786 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
787 operator!=(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) noexcept
788 { return (bool)__x; }
789#endif // three way comparison
790
791 /// Relational operator for unique_ptr objects, compares the owned pointers
792 template<typename _Tp, typename _Dp,
793 typename _Up, typename _Ep>
794 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
795 operator<(const unique_ptr<_Tp, _Dp>& __x,
796 const unique_ptr<_Up, _Ep>& __y)
797 {
798 typedef typename
799 std::common_type<typename unique_ptr<_Tp, _Dp>::pointer,
800 typename unique_ptr<_Up, _Ep>::pointer>::type _CT;
801 return std::less<_CT>()(__x.get(), __y.get());
802 }
803
804 /// unique_ptr comparison with nullptr
805 template<typename _Tp, typename _Dp>
806 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
807 operator<(const unique_ptr<_Tp, _Dp>& __x, nullptr_t)
808 {
809 return std::less<typename unique_ptr<_Tp, _Dp>::pointer>()(__x.get(),
810 nullptr);
811 }
812
813 /// unique_ptr comparison with nullptr
814 template<typename _Tp, typename _Dp>
815 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
816 operator<(nullptr_t, const unique_ptr<_Tp, _Dp>& __x)
817 {
818 return std::less<typename unique_ptr<_Tp, _Dp>::pointer>()(nullptr,
819 __x.get());
820 }
821
822 /// Relational operator for unique_ptr objects, compares the owned pointers
823 template<typename _Tp, typename _Dp,
824 typename _Up, typename _Ep>
825 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
826 operator<=(const unique_ptr<_Tp, _Dp>& __x,
827 const unique_ptr<_Up, _Ep>& __y)
828 { return !(__y < __x); }
829
830 /// unique_ptr comparison with nullptr
831 template<typename _Tp, typename _Dp>
832 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
833 operator<=(const unique_ptr<_Tp, _Dp>& __x, nullptr_t)
834 { return !(nullptr < __x); }
835
836 /// unique_ptr comparison with nullptr
837 template<typename _Tp, typename _Dp>
838 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
839 operator<=(nullptr_t, const unique_ptr<_Tp, _Dp>& __x)
840 { return !(__x < nullptr); }
841
842 /// Relational operator for unique_ptr objects, compares the owned pointers
843 template<typename _Tp, typename _Dp,
844 typename _Up, typename _Ep>
845 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
846 operator>(const unique_ptr<_Tp, _Dp>& __x,
847 const unique_ptr<_Up, _Ep>& __y)
848 { return (__y < __x); }
849
850 /// unique_ptr comparison with nullptr
851 template<typename _Tp, typename _Dp>
852 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
853 operator>(const unique_ptr<_Tp, _Dp>& __x, nullptr_t)
854 {
855 return std::less<typename unique_ptr<_Tp, _Dp>::pointer>()(nullptr,
856 __x.get());
857 }
858
859 /// unique_ptr comparison with nullptr
860 template<typename _Tp, typename _Dp>
861 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
862 operator>(nullptr_t, const unique_ptr<_Tp, _Dp>& __x)
863 {
864 return std::less<typename unique_ptr<_Tp, _Dp>::pointer>()(__x.get(),
865 nullptr);
866 }
867
868 /// Relational operator for unique_ptr objects, compares the owned pointers
869 template<typename _Tp, typename _Dp,
870 typename _Up, typename _Ep>
871 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
872 operator>=(const unique_ptr<_Tp, _Dp>& __x,
873 const unique_ptr<_Up, _Ep>& __y)
874 { return !(__x < __y); }
875
876 /// unique_ptr comparison with nullptr
877 template<typename _Tp, typename _Dp>
878 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
879 operator>=(const unique_ptr<_Tp, _Dp>& __x, nullptr_t)
880 { return !(__x < nullptr); }
881
882 /// unique_ptr comparison with nullptr
883 template<typename _Tp, typename _Dp>
884 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
885 operator>=(nullptr_t, const unique_ptr<_Tp, _Dp>& __x)
886 { return !(nullptr < __x); }
887
888#ifdef __cpp_lib_three_way_comparison
889 template<typename _Tp, typename _Dp, typename _Up, typename _Ep>
890 requires three_way_comparable_with<typename unique_ptr<_Tp, _Dp>::pointer,
891 typename unique_ptr<_Up, _Ep>::pointer>
892 inline
893 compare_three_way_result_t<typename unique_ptr<_Tp, _Dp>::pointer,
894 typename unique_ptr<_Up, _Ep>::pointer>
895 operator<=>(const unique_ptr<_Tp, _Dp>& __x,
896 const unique_ptr<_Up, _Ep>& __y)
897 { return compare_three_way()(__x.get(), __y.get()); }
898
899 template<typename _Tp, typename _Dp>
900 requires three_way_comparable<typename unique_ptr<_Tp, _Dp>::pointer>
901 inline
902 compare_three_way_result_t<typename unique_ptr<_Tp, _Dp>::pointer>
903 operator<=>(const unique_ptr<_Tp, _Dp>& __x, nullptr_t)
904 {
905 using pointer = typename unique_ptr<_Tp, _Dp>::pointer;
906 return compare_three_way()(__x.get(), static_cast<pointer>(nullptr));
907 }
908#endif
909 // @} relates unique_ptr
910
911 /// @cond undocumented
912 template<typename _Up, typename _Ptr = typename _Up::pointer,
913 bool = __poison_hash<_Ptr>::__enable_hash_call>
914 struct __uniq_ptr_hash
915#if ! _GLIBCXX_INLINE_VERSION0
916 : private __poison_hash<_Ptr>
917#endif
918 {
919 size_t
920 operator()(const _Up& __u) const
921 noexcept(noexcept(std::declval<hash<_Ptr>>()(std::declval<_Ptr>())))
922 { return hash<_Ptr>()(__u.get()); }
923 };
924
925 template<typename _Up, typename _Ptr>
926 struct __uniq_ptr_hash<_Up, _Ptr, false>
927 : private __poison_hash<_Ptr>
928 { };
929 /// @endcond
930
931 /// std::hash specialization for unique_ptr.
932 template<typename _Tp, typename _Dp>
933 struct hash<unique_ptr<_Tp, _Dp>>
934 : public __hash_base<size_t, unique_ptr<_Tp, _Dp>>,
935 public __uniq_ptr_hash<unique_ptr<_Tp, _Dp>>
936 { };
937
938#if __cplusplus201703L >= 201402L
939 /// @relates unique_ptr @{
940#define __cpp_lib_make_unique201304 201304
941
942 /// @cond undocumented
943
944 template<typename _Tp>
945 struct _MakeUniq
946 { typedef unique_ptr<_Tp> __single_object; };
947
948 template<typename _Tp>
949 struct _MakeUniq<_Tp[]>
950 { typedef unique_ptr<_Tp[]> __array; };
951
952 template<typename _Tp, size_t _Bound>
953 struct _MakeUniq<_Tp[_Bound]>
954 { struct __invalid_type { }; };
955
956 /// @endcond
957
958 /// std::make_unique for single objects
959 template<typename _Tp, typename... _Args>
960 inline typename _MakeUniq<_Tp>::__single_object
961 make_unique(_Args&&... __args)
962 { return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); }
9
Object 'pReleasedFormat' is moved
963
964 /// std::make_unique for arrays of unknown bound
965 template<typename _Tp>
966 inline typename _MakeUniq<_Tp>::__array
967 make_unique(size_t __num)
968 { return unique_ptr<_Tp>(new remove_extent_t<_Tp>[__num]()); }
969
970 /// Disable std::make_unique for arrays of known bound
971 template<typename _Tp, typename... _Args>
972 inline typename _MakeUniq<_Tp>::__invalid_type
973 make_unique(_Args&&...) = delete;
974 // @} relates unique_ptr
975#endif // C++14
976
977#if __cplusplus201703L > 201703L && __cpp_concepts
978 // _GLIBCXX_RESOLVE_LIB_DEFECTS
979 // 2948. unique_ptr does not define operator<< for stream output
980 /// Stream output operator for unique_ptr
981 template<typename _CharT, typename _Traits, typename _Tp, typename _Dp>
982 inline basic_ostream<_CharT, _Traits>&
983 operator<<(basic_ostream<_CharT, _Traits>& __os,
984 const unique_ptr<_Tp, _Dp>& __p)
985 requires requires { __os << __p.get(); }
986 {
987 __os << __p.get();
988 return __os;
989 }
990#endif // C++20
991
992 // @} group pointer_abstractions
993
994#if __cplusplus201703L >= 201703L
995 namespace __detail::__variant
996 {
997 template<typename> struct _Never_valueless_alt; // see <variant>
998
999 // Provide the strong exception-safety guarantee when emplacing a
1000 // unique_ptr into a variant.
1001 template<typename _Tp, typename _Del>
1002 struct _Never_valueless_alt<std::unique_ptr<_Tp, _Del>>
1003 : std::true_type
1004 { };
1005 } // namespace __detail::__variant
1006#endif // C++17
1007
1008_GLIBCXX_END_NAMESPACE_VERSION
1009} // namespace
1010
1011#endif /* _UNIQUE_PTR_H */