Bug Summary

File:home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx
Warning:line 5156, column 9
Called C++ object pointer is null

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 DocumentContentOperationsManager.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/doc/DocumentContentOperationsManager.cxx

/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.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#include <DocumentContentOperationsManager.hxx>
20#include <doc.hxx>
21#include <IDocumentUndoRedo.hxx>
22#include <IDocumentMarkAccess.hxx>
23#include <IDocumentState.hxx>
24#include <IDocumentLayoutAccess.hxx>
25#include <IDocumentStylePoolAccess.hxx>
26#include <IDocumentSettingAccess.hxx>
27#include <UndoManager.hxx>
28#include <docary.hxx>
29#include <textboxhelper.hxx>
30#include <dcontact.hxx>
31#include <grfatr.hxx>
32#include <numrule.hxx>
33#include <charfmt.hxx>
34#include <ndgrf.hxx>
35#include <ndnotxt.hxx>
36#include <ndole.hxx>
37#include <breakit.hxx>
38#include <frmfmt.hxx>
39#include <fmtanchr.hxx>
40#include <fmtcntnt.hxx>
41#include <fmtinfmt.hxx>
42#include <fmtpdsc.hxx>
43#include <fmtcnct.hxx>
44#include <SwStyleNameMapper.hxx>
45#include <redline.hxx>
46#include <txtfrm.hxx>
47#include <rootfrm.hxx>
48#include <frmtool.hxx>
49#include <unocrsr.hxx>
50#include <mvsave.hxx>
51#include <ndtxt.hxx>
52#include <poolfmt.hxx>
53#include <paratr.hxx>
54#include <txatbase.hxx>
55#include <UndoRedline.hxx>
56#include <undobj.hxx>
57#include <UndoBookmark.hxx>
58#include <UndoDelete.hxx>
59#include <UndoSplitMove.hxx>
60#include <UndoOverwrite.hxx>
61#include <UndoInsert.hxx>
62#include <UndoAttribute.hxx>
63#include <rolbck.hxx>
64#include <acorrect.hxx>
65#include <bookmrk.hxx>
66#include <ftnidx.hxx>
67#include <txtftn.hxx>
68#include <hints.hxx>
69#include <fmtflcnt.hxx>
70#include <docedt.hxx>
71#include <frameformats.hxx>
72#include <o3tl/safeint.hxx>
73#include <sal/log.hxx>
74#include <unotools/charclass.hxx>
75#include <unotools/configmgr.hxx>
76#include <sfx2/Metadatable.hxx>
77#include <sot/exchange.hxx>
78#include <svl/stritem.hxx>
79#include <svl/itemiter.hxx>
80#include <svx/svdobj.hxx>
81#include <svx/svdouno.hxx>
82#include <tools/globname.hxx>
83#include <editeng/formatbreakitem.hxx>
84#include <com/sun/star/i18n/Boundary.hpp>
85#include <com/sun/star/i18n/WordType.hpp>
86#include <com/sun/star/i18n/XBreakIterator.hpp>
87#include <com/sun/star/embed/XEmbeddedObject.hpp>
88
89#include <tuple>
90#include <memory>
91
92#include <editsh.hxx>
93#include <viewopt.hxx>
94#include <wrtsh.hxx>
95
96using namespace ::com::sun::star::i18n;
97
98namespace
99{
100 // Copy method from SwDoc
101 // Prevent copying into Flys that are anchored in the range
102 bool lcl_ChkFlyFly( SwDoc& rDoc, sal_uLong nSttNd, sal_uLong nEndNd,
103 sal_uLong nInsNd )
104 {
105 const SwFrameFormats& rFrameFormatTable = *rDoc.GetSpzFrameFormats();
106
107 for( size_t n = 0; n < rFrameFormatTable.size(); ++n )
108 {
109 SwFrameFormat const*const pFormat = rFrameFormatTable[n];
110 SwFormatAnchor const*const pAnchor = &pFormat->GetAnchor();
111 SwPosition const*const pAPos = pAnchor->GetContentAnchor();
112 if (pAPos &&
113 ((RndStdIds::FLY_AS_CHAR == pAnchor->GetAnchorId()) ||
114 (RndStdIds::FLY_AT_CHAR == pAnchor->GetAnchorId()) ||
115 (RndStdIds::FLY_AT_FLY == pAnchor->GetAnchorId()) ||
116 (RndStdIds::FLY_AT_PARA == pAnchor->GetAnchorId())) &&
117 nSttNd <= pAPos->nNode.GetIndex() &&
118 pAPos->nNode.GetIndex() < nEndNd )
119 {
120 const SwFormatContent& rContent = pFormat->GetContent();
121 SwStartNode* pSNd;
122 if( !rContent.GetContentIdx() ||
123 nullptr == ( pSNd = rContent.GetContentIdx()->GetNode().GetStartNode() ))
124 continue;
125
126 if( pSNd->GetIndex() < nInsNd &&
127 nInsNd < pSNd->EndOfSectionIndex() )
128 // Do not copy !
129 return true;
130
131 if( lcl_ChkFlyFly( rDoc, pSNd->GetIndex(),
132 pSNd->EndOfSectionIndex(), nInsNd ) )
133 // Do not copy !
134 return true;
135 }
136 }
137
138 return false;
139 }
140
141 SwNodeIndex InitDelCount(SwPaM const& rSourcePaM, sal_uLong & rDelCount)
142 {
143 SwNodeIndex const& rStart(rSourcePaM.Start()->nNode);
144 // Special handling for SwDoc::AppendDoc
145 if (rSourcePaM.GetDoc().GetNodes().GetEndOfExtras().GetIndex() + 1
146 == rStart.GetIndex())
147 {
148 rDelCount = 1;
149 return SwNodeIndex(rStart, +1);
150 }
151 else
152 {
153 rDelCount = 0;
154 return rStart;
155 }
156 }
157
158 /*
159 The CopyBookmarks function has to copy bookmarks from the source to the destination nodes
160 array. It is called after a call of the CopyNodes(..) function. But this function does not copy
161 every node (at least at the moment: 2/08/2006 ), section start and end nodes will not be copied
162 if the corresponding end/start node is outside the copied pam.
163 The lcl_NonCopyCount function counts the number of these nodes, given the copied pam and a node
164 index inside the pam.
165 rPam is the original source pam, rLastIdx is the last calculated position, rDelCount the number
166 of "non-copy" nodes between rPam.Start() and rLastIdx.
167 nNewIdx is the new position of interest.
168 */
169 void lcl_NonCopyCount( const SwPaM& rPam, SwNodeIndex& rLastIdx, const sal_uLong nNewIdx, sal_uLong& rDelCount )
170 {
171 sal_uLong nStart = rPam.Start()->nNode.GetIndex();
172 sal_uLong nEnd = rPam.End()->nNode.GetIndex();
173 if( rLastIdx.GetIndex() < nNewIdx ) // Moving forward?
174 {
175 // We never copy the StartOfContent node
176 do // count "non-copy" nodes
177 {
178 SwNode& rNode = rLastIdx.GetNode();
179 if( ( rNode.IsSectionNode() && rNode.EndOfSectionIndex() >= nEnd )
180 || ( rNode.IsEndNode() && rNode.StartOfSectionNode()->GetIndex() < nStart ) )
181 {
182 ++rDelCount;
183 }
184 ++rLastIdx;
185 }
186 while( rLastIdx.GetIndex() < nNewIdx );
187 }
188 else if( rDelCount ) // optimization: if there are no "non-copy" nodes until now,
189 // no move backward needed
190 {
191 while( rLastIdx.GetIndex() > nNewIdx )
192 {
193 SwNode& rNode = rLastIdx.GetNode();
194 if( ( rNode.IsSectionNode() && rNode.EndOfSectionIndex() >= nEnd )
195 || ( rNode.IsEndNode() && rNode.StartOfSectionNode()->GetIndex() < nStart ) )
196 {
197 --rDelCount;
198 }
199 rLastIdx--;
200 }
201 }
202 }
203
204 void lcl_SetCpyPos( const SwPosition& rOrigPos,
205 const SwPosition& rOrigStt,
206 const SwPosition& rCpyStt,
207 SwPosition& rChgPos,
208 sal_uLong nDelCount )
209 {
210 sal_uLong nNdOff = rOrigPos.nNode.GetIndex();
211 nNdOff -= rOrigStt.nNode.GetIndex();
212 nNdOff -= nDelCount;
213 sal_Int32 nContentPos = rOrigPos.nContent.GetIndex();
214
215 // Always adjust <nNode> at to be changed <SwPosition> instance <rChgPos>
216 rChgPos.nNode = nNdOff + rCpyStt.nNode.GetIndex();
217 if( !nNdOff )
218 {
219 // just adapt the content index
220 if( nContentPos > rOrigStt.nContent.GetIndex() )
221 nContentPos -= rOrigStt.nContent.GetIndex();
222 else
223 nContentPos = 0;
224 nContentPos += rCpyStt.nContent.GetIndex();
225 }
226 rChgPos.nContent.Assign( rChgPos.nNode.GetNode().GetContentNode(), nContentPos );
227 }
228
229}
230
231namespace sw
232{
233 // TODO: use SaveBookmark (from DelBookmarks)
234 void CopyBookmarks(const SwPaM& rPam, SwPosition& rCpyPam)
235 {
236 const SwDoc& rSrcDoc = rPam.GetDoc();
237 SwDoc& rDestDoc = rCpyPam.GetDoc();
238 const IDocumentMarkAccess* const pSrcMarkAccess = rSrcDoc.getIDocumentMarkAccess();
239 ::sw::UndoGuard const undoGuard(rDestDoc.GetIDocumentUndoRedo());
240
241 const SwPosition &rStt = *rPam.Start(), &rEnd = *rPam.End();
242 SwPosition const*const pCpyStt = &rCpyPam;
243
244 std::vector< const ::sw::mark::IMark* > vMarksToCopy;
245 for ( IDocumentMarkAccess::const_iterator_t ppMark = pSrcMarkAccess->getAllMarksBegin();
246 ppMark != pSrcMarkAccess->getAllMarksEnd();
247 ++ppMark )
248 {
249 const ::sw::mark::IMark* const pMark = *ppMark;
250
251 const SwPosition& rMarkStart = pMark->GetMarkStart();
252 const SwPosition& rMarkEnd = pMark->GetMarkEnd();
253 // only include marks that are in the range and not touching both start and end
254 // - not for annotation or checkbox marks.
255 const bool bIsNotOnBoundary =
256 pMark->IsExpanded()
257 ? (rMarkStart != rStt || rMarkEnd != rEnd) // rMarkStart != rMarkEnd
258 : (rMarkStart != rStt && rMarkEnd != rEnd); // rMarkStart == rMarkEnd
259 const IDocumentMarkAccess::MarkType aMarkType = IDocumentMarkAccess::GetType(*pMark);
260 if ( rMarkStart >= rStt && rMarkEnd <= rEnd
261 && ( bIsNotOnBoundary
262 || aMarkType == IDocumentMarkAccess::MarkType::ANNOTATIONMARK
263 || aMarkType == IDocumentMarkAccess::MarkType::TEXT_FIELDMARK
264 || aMarkType == IDocumentMarkAccess::MarkType::CHECKBOX_FIELDMARK
265 || aMarkType == IDocumentMarkAccess::MarkType::DROPDOWN_FIELDMARK
266 || aMarkType == IDocumentMarkAccess::MarkType::DATE_FIELDMARK))
267 {
268 vMarksToCopy.push_back(pMark);
269 }
270 }
271 // We have to count the "non-copied" nodes...
272 sal_uLong nDelCount;
273 SwNodeIndex aCorrIdx(InitDelCount(rPam, nDelCount));
274 for(const sw::mark::IMark* const pMark : vMarksToCopy)
275 {
276 SwPaM aTmpPam(*pCpyStt);
277 lcl_NonCopyCount(rPam, aCorrIdx, pMark->GetMarkPos().nNode.GetIndex(), nDelCount);
278 lcl_SetCpyPos( pMark->GetMarkPos(), rStt, *pCpyStt, *aTmpPam.GetPoint(), nDelCount);
279 if(pMark->IsExpanded())
280 {
281 aTmpPam.SetMark();
282 lcl_NonCopyCount(rPam, aCorrIdx, pMark->GetOtherMarkPos().nNode.GetIndex(), nDelCount);
283 lcl_SetCpyPos(pMark->GetOtherMarkPos(), rStt, *pCpyStt, *aTmpPam.GetMark(), nDelCount);
284 }
285
286 ::sw::mark::IMark* const pNewMark = rDestDoc.getIDocumentMarkAccess()->makeMark(
287 aTmpPam,
288 pMark->GetName(),
289 IDocumentMarkAccess::GetType(*pMark),
290 ::sw::mark::InsertMode::CopyText);
291 // Explicitly try to get exactly the same name as in the source
292 // because NavigatorReminders, DdeBookmarks etc. ignore the proposed name
293 rDestDoc.getIDocumentMarkAccess()->renameMark(pNewMark, pMark->GetName());
294
295 // copying additional attributes for bookmarks or fieldmarks
296 ::sw::mark::IBookmark* const pNewBookmark =
297 dynamic_cast< ::sw::mark::IBookmark* const >(pNewMark);
298 const ::sw::mark::IBookmark* const pOldBookmark =
299 dynamic_cast< const ::sw::mark::IBookmark* >(pMark);
300 if (pNewBookmark && pOldBookmark)
301 {
302 pNewBookmark->SetKeyCode(pOldBookmark->GetKeyCode());
303 pNewBookmark->SetShortName(pOldBookmark->GetShortName());
304 pNewBookmark->Hide(pOldBookmark->IsHidden());
305 pNewBookmark->SetHideCondition(pOldBookmark->GetHideCondition());
306 }
307 ::sw::mark::IFieldmark* const pNewFieldmark =
308 dynamic_cast< ::sw::mark::IFieldmark* const >(pNewMark);
309 const ::sw::mark::IFieldmark* const pOldFieldmark =
310 dynamic_cast< const ::sw::mark::IFieldmark* >(pMark);
311 if (pNewFieldmark && pOldFieldmark)
312 {
313 pNewFieldmark->SetFieldname(pOldFieldmark->GetFieldname());
314 pNewFieldmark->SetFieldHelptext(pOldFieldmark->GetFieldHelptext());
315 ::sw::mark::IFieldmark::parameter_map_t* pNewParams = pNewFieldmark->GetParameters();
316 const ::sw::mark::IFieldmark::parameter_map_t* pOldParams = pOldFieldmark->GetParameters();
317 for (const auto& rEntry : *pOldParams )
318 {
319 pNewParams->insert( rEntry );
320 }
321 }
322
323 ::sfx2::Metadatable const*const pMetadatable(
324 dynamic_cast< ::sfx2::Metadatable const* >(pMark));
325 ::sfx2::Metadatable *const pNewMetadatable(
326 dynamic_cast< ::sfx2::Metadatable * >(pNewMark));
327 if (pMetadatable && pNewMetadatable)
328 {
329 pNewMetadatable->RegisterAsCopyOf(*pMetadatable);
330 }
331 }
332 }
333} // namespace sw
334
335namespace
336{
337 void lcl_DeleteRedlines( const SwPaM& rPam, SwPaM& rCpyPam )
338 {
339 const SwDoc& rSrcDoc = rPam.GetDoc();
340 const SwRedlineTable& rTable = rSrcDoc.getIDocumentRedlineAccess().GetRedlineTable();
341 if( rTable.empty() )
342 return;
343
344 SwDoc& rDestDoc = rCpyPam.GetDoc();
345 SwPosition* pCpyStt = rCpyPam.Start(), *pCpyEnd = rCpyPam.End();
346 std::unique_ptr<SwPaM> pDelPam;
347 const SwPosition *pStt = rPam.Start(), *pEnd = rPam.End();
348 // We have to count the "non-copied" nodes
349 sal_uLong nDelCount;
350 SwNodeIndex aCorrIdx(InitDelCount(rPam, nDelCount));
351
352 SwRedlineTable::size_type n = 0;
353 rSrcDoc.getIDocumentRedlineAccess().GetRedline( *pStt, &n );
354 for( ; n < rTable.size(); ++n )
355 {
356 const SwRangeRedline* pRedl = rTable[ n ];
357 if( RedlineType::Delete == pRedl->GetType() && pRedl->IsVisible() )
358 {
359 const SwPosition *pRStt = pRedl->Start(), *pREnd = pRedl->End();
360
361 SwComparePosition eCmpPos = ComparePosition( *pStt, *pEnd, *pRStt, *pREnd );
362 switch( eCmpPos )
363 {
364 case SwComparePosition::CollideEnd:
365 case SwComparePosition::Before:
366 // Pos1 is before Pos2
367 break;
368
369 case SwComparePosition::CollideStart:
370 case SwComparePosition::Behind:
371 // Pos1 is after Pos2
372 n = rTable.size();
373 break;
374
375 default:
376 {
377 pDelPam.reset(new SwPaM( *pCpyStt, pDelPam.release() ));
378 if( *pStt < *pRStt )
379 {
380 lcl_NonCopyCount( rPam, aCorrIdx, pRStt->nNode.GetIndex(), nDelCount );
381 lcl_SetCpyPos( *pRStt, *pStt, *pCpyStt,
382 *pDelPam->GetPoint(), nDelCount );
383 }
384 pDelPam->SetMark();
385
386 if( *pEnd < *pREnd )
387 *pDelPam->GetPoint() = *pCpyEnd;
388 else
389 {
390 lcl_NonCopyCount( rPam, aCorrIdx, pREnd->nNode.GetIndex(), nDelCount );
391 lcl_SetCpyPos( *pREnd, *pStt, *pCpyStt,
392 *pDelPam->GetPoint(), nDelCount );
393 }
394
395 if (pDelPam->GetNext() && *pDelPam->GetNext()->End() == *pDelPam->Start())
396 {
397 *pDelPam->GetNext()->End() = *pDelPam->End();
398 pDelPam.reset(pDelPam->GetNext());
399 }
400 }
401 }
402 }
403 }
404
405 if( !pDelPam )
406 return;
407
408 RedlineFlags eOld = rDestDoc.getIDocumentRedlineAccess().GetRedlineFlags();
409 rDestDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld | RedlineFlags::Ignore );
410
411 ::sw::UndoGuard const undoGuard(rDestDoc.GetIDocumentUndoRedo());
412
413 do {
414 rDestDoc.getIDocumentContentOperations().DeleteAndJoin( *pDelPam->GetNext() );
415 if( !pDelPam->IsMultiSelection() )
416 break;
417 delete pDelPam->GetNext();
418 } while( true );
419
420 rDestDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld );
421 }
422
423 void lcl_DeleteRedlines( const SwNodeRange& rRg, SwNodeRange const & rCpyRg )
424 {
425 SwDoc& rSrcDoc = rRg.aStart.GetNode().GetDoc();
426 if( !rSrcDoc.getIDocumentRedlineAccess().GetRedlineTable().empty() )
427 {
428 SwPaM aRgTmp( rRg.aStart, rRg.aEnd );
429 SwPaM aCpyTmp( rCpyRg.aStart, rCpyRg.aEnd );
430 lcl_DeleteRedlines( aRgTmp, aCpyTmp );
431 }
432 }
433
434 void lcl_ChainFormats( SwFlyFrameFormat *pSrc, SwFlyFrameFormat *pDest )
435 {
436 SwFormatChain aSrc( pSrc->GetChain() );
437 if ( !aSrc.GetNext() )
438 {
439 aSrc.SetNext( pDest );
440 pSrc->SetFormatAttr( aSrc );
441 }
442 SwFormatChain aDest( pDest->GetChain() );
443 if ( !aDest.GetPrev() )
444 {
445 aDest.SetPrev( pSrc );
446 pDest->SetFormatAttr( aDest );
447 }
448 }
449
450 // #i86492#
451 bool lcl_ContainsOnlyParagraphsInList( const SwPaM& rPam )
452 {
453 bool bRet = false;
454
455 const SwTextNode* pTextNd = rPam.Start()->nNode.GetNode().GetTextNode();
456 const SwTextNode* pEndTextNd = rPam.End()->nNode.GetNode().GetTextNode();
457 if ( pTextNd && pTextNd->IsInList() &&
458 pEndTextNd && pEndTextNd->IsInList() )
459 {
460 bRet = true;
461 SwNodeIndex aIdx(rPam.Start()->nNode);
462
463 do
464 {
465 ++aIdx;
466 pTextNd = aIdx.GetNode().GetTextNode();
467
468 if ( !pTextNd || !pTextNd->IsInList() )
469 {
470 bRet = false;
471 break;
472 }
473 } while (pTextNd != pEndTextNd);
474 }
475
476 return bRet;
477 }
478
479 bool lcl_MarksWholeNode(const SwPaM & rPam)
480 {
481 bool bResult = false;
482 const SwPosition* pStt = rPam.Start();
483 const SwPosition* pEnd = rPam.End();
484
485 if (nullptr != pStt && nullptr != pEnd)
486 {
487 const SwTextNode* pSttNd = pStt->nNode.GetNode().GetTextNode();
488 const SwTextNode* pEndNd = pEnd->nNode.GetNode().GetTextNode();
489
490 if (nullptr != pSttNd && nullptr != pEndNd &&
491 pStt->nContent.GetIndex() == 0 &&
492 pEnd->nContent.GetIndex() == pEndNd->Len())
493 {
494 bResult = true;
495 }
496 }
497
498 return bResult;
499 }
500}
501
502//local functions originally from sw/source/core/doc/docedt.cxx
503namespace sw
504{
505 void CalcBreaks(std::vector<std::pair<sal_uLong, sal_Int32>> & rBreaks,
506 SwPaM const & rPam, bool const isOnlyFieldmarks)
507 {
508 sal_uLong const nStartNode(rPam.Start()->nNode.GetIndex());
509 sal_uLong const nEndNode(rPam.End()->nNode.GetIndex());
510 SwNodes const& rNodes(rPam.GetPoint()->nNode.GetNodes());
511 IDocumentMarkAccess const& rIDMA(*rPam.GetDoc().getIDocumentMarkAccess());
512
513 std::stack<std::tuple<sw::mark::IFieldmark const*, bool, sal_uLong, sal_Int32>> startedFields;
514
515 for (sal_uLong n = nStartNode; n <= nEndNode; ++n)
516 {
517 SwNode *const pNode(rNodes[n]);
518 if (pNode->IsTextNode())
519 {
520 SwTextNode & rTextNode(*pNode->GetTextNode());
521 sal_Int32 const nStart(n == nStartNode
522 ? rPam.Start()->nContent.GetIndex()
523 : 0);
524 sal_Int32 const nEnd(n == nEndNode
525 ? rPam.End()->nContent.GetIndex()
526 : rTextNode.Len());
527 for (sal_Int32 i = nStart; i < nEnd; ++i)
528 {
529 const sal_Unicode c(rTextNode.GetText()[i]);
530 switch (c)
531 {
532 // note: CH_TXT_ATR_FORMELEMENT does not need handling
533 // not sure how CH_TXT_ATR_INPUTFIELDSTART/END are currently handled
534 case CH_TXTATR_INWORDu'\xFFF9':
535 case CH_TXTATR_BREAKWORDu'\x0001':
536 {
537 // META hints only have dummy char at the start, not
538 // at the end, so no need to check in nStartNode
539 if (n == nEndNode && !isOnlyFieldmarks)
540 {
541 SwTextAttr const*const pAttr(rTextNode.GetTextAttrForCharAt(i));
542 if (pAttr && pAttr->End() && (nEnd < *pAttr->End()))
543 {
544 assert(pAttr->HasDummyChar())(static_cast <bool> (pAttr->HasDummyChar()) ? void (
0) : __assert_fail ("pAttr->HasDummyChar()", "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 544, __extension__ __PRETTY_FUNCTION__))
;
545 rBreaks.emplace_back(n, i);
546 }
547 }
548 break;
549 }
550 case CH_TXT_ATR_FIELDSTARTu'\x0007':
551 {
552 auto const pFieldMark(rIDMA.getFieldmarkAt(SwPosition(rTextNode, i)));
553 startedFields.emplace(pFieldMark, false, 0, 0);
554 break;
555 }
556 case CH_TXT_ATR_FIELDSEPu'\x0003':
557 {
558 if (startedFields.empty())
559 {
560 rBreaks.emplace_back(n, i);
561 }
562 else
563 { // no way to find the field via MarkManager...
564 assert(std::get<0>(startedFields.top())->IsCoveringPosition(SwPosition(rTextNode, i)))(static_cast <bool> (std::get<0>(startedFields.top
())->IsCoveringPosition(SwPosition(rTextNode, i))) ? void (
0) : __assert_fail ("std::get<0>(startedFields.top())->IsCoveringPosition(SwPosition(rTextNode, i))"
, "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 564, __extension__ __PRETTY_FUNCTION__))
;
565 std::get<1>(startedFields.top()) = true;
566 std::get<2>(startedFields.top()) = n;
567 std::get<3>(startedFields.top()) = i;
568 }
569 break;
570 }
571 case CH_TXT_ATR_FIELDENDu'\x0008':
572 {
573 if (startedFields.empty())
574 {
575 rBreaks.emplace_back(n, i);
576 }
577 else
578 { // fieldmarks must not overlap => stack
579 assert(std::get<0>(startedFields.top()) == rIDMA.getFieldmarkAt(SwPosition(rTextNode, i)))(static_cast <bool> (std::get<0>(startedFields.top
()) == rIDMA.getFieldmarkAt(SwPosition(rTextNode, i))) ? void
(0) : __assert_fail ("std::get<0>(startedFields.top()) == rIDMA.getFieldmarkAt(SwPosition(rTextNode, i))"
, "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 579, __extension__ __PRETTY_FUNCTION__))
;
580 startedFields.pop();
581 }
582 break;
583 }
584 }
585 }
586 }
587 else if (pNode->IsStartNode())
588 {
589 if (pNode->EndOfSectionIndex() <= nEndNode)
590 { // fieldmark cannot overlap node section
591 n = pNode->EndOfSectionIndex();
592 }
593 }
594 else
595 { // EndNode can actually happen with sections :(
596 assert(pNode->IsEndNode() || pNode->IsNoTextNode())(static_cast <bool> (pNode->IsEndNode() || pNode->
IsNoTextNode()) ? void (0) : __assert_fail ("pNode->IsEndNode() || pNode->IsNoTextNode()"
, "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 596, __extension__ __PRETTY_FUNCTION__))
;
597 }
598 }
599 while (!startedFields.empty())
600 {
601 SwPosition const& rStart(std::get<0>(startedFields.top())->GetMarkStart());
602 std::pair<sal_uLong, sal_Int32> const pos(
603 rStart.nNode.GetIndex(), rStart.nContent.GetIndex());
604 auto it = std::lower_bound(rBreaks.begin(), rBreaks.end(), pos);
605 assert(it == rBreaks.end() || *it != pos)(static_cast <bool> (it == rBreaks.end() || *it != pos)
? void (0) : __assert_fail ("it == rBreaks.end() || *it != pos"
, "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 605, __extension__ __PRETTY_FUNCTION__))
;
606 rBreaks.insert(it, pos);
607 if (std::get<1>(startedFields.top()))
608 {
609 std::pair<sal_uLong, sal_Int32> const posSep(
610 std::get<2>(startedFields.top()),
611 std::get<3>(startedFields.top()));
612 it = std::lower_bound(rBreaks.begin(), rBreaks.end(), posSep);
613 assert(it == rBreaks.end() || *it != posSep)(static_cast <bool> (it == rBreaks.end() || *it != posSep
) ? void (0) : __assert_fail ("it == rBreaks.end() || *it != posSep"
, "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 613, __extension__ __PRETTY_FUNCTION__))
;
614 rBreaks.insert(it, posSep);
615 }
616 startedFields.pop();
617 }
618 }
619}
620
621namespace
622{
623
624 bool lcl_DoWithBreaks(::sw::DocumentContentOperationsManager & rDocumentContentOperations, SwPaM & rPam,
625 bool (::sw::DocumentContentOperationsManager::*pFunc)(SwPaM&, bool), const bool bForceJoinNext = false)
626 {
627 std::vector<std::pair<sal_uLong, sal_Int32>> Breaks;
628
629 sw::CalcBreaks(Breaks, rPam);
630
631 if (Breaks.empty())
632 {
633 return (rDocumentContentOperations.*pFunc)(rPam, bForceJoinNext);
634 }
635
636 // Deletion must be split into several parts if the text node
637 // contains a text attribute with end and with dummy character
638 // and the selection does not contain the text attribute completely,
639 // but overlaps its start (left), where the dummy character is.
640
641 SwPosition const & rSelectionEnd( *rPam.End() );
642
643 bool bRet( true );
644 // iterate from end to start, to avoid invalidating the offsets!
645 auto iter( Breaks.rbegin() );
646 sal_uLong nOffset(0);
647 SwNodes const& rNodes(rPam.GetPoint()->nNode.GetNodes());
648 SwPaM aPam( rSelectionEnd, rSelectionEnd ); // end node!
649 SwPosition & rEnd( *aPam.End() );
650 SwPosition & rStart( *aPam.Start() );
651
652 while (iter != Breaks.rend())
653 {
654 rStart = SwPosition(*rNodes[iter->first - nOffset]->GetTextNode(), iter->second + 1);
655 if (rStart < rEnd) // check if part is empty
656 {
657 bRet &= (rDocumentContentOperations.*pFunc)(aPam, bForceJoinNext);
658 nOffset = iter->first - rStart.nNode.GetIndex(); // deleted fly nodes...
659 }
660 rEnd = SwPosition(*rNodes[iter->first - nOffset]->GetTextNode(), iter->second);
661 ++iter;
662 }
663
664 rStart = *rPam.Start(); // set to original start
665 if (rStart < rEnd) // check if part is empty
666 {
667 bRet &= (rDocumentContentOperations.*pFunc)(aPam, bForceJoinNext);
668 }
669
670 return bRet;
671 }
672
673 bool lcl_StrLenOverflow( const SwPaM& rPam )
674 {
675 // If we try to merge two paragraphs we have to test if afterwards
676 // the string doesn't exceed the allowed string length
677 if( rPam.GetPoint()->nNode != rPam.GetMark()->nNode )
678 {
679 const SwPosition* pStt = rPam.Start(), *pEnd = rPam.End();
680 const SwTextNode* pEndNd = pEnd->nNode.GetNode().GetTextNode();
681 if( (nullptr != pEndNd) && pStt->nNode.GetNode().IsTextNode() )
682 {
683 const sal_uInt64 nSum = pStt->nContent.GetIndex() +
684 pEndNd->GetText().getLength() - pEnd->nContent.GetIndex();
685 return nSum > o3tl::make_unsigned(SAL_MAX_INT32((sal_Int32) 0x7FFFFFFF));
686 }
687 }
688 return false;
689 }
690
691 struct SaveRedline
692 {
693 SwRangeRedline* pRedl;
694 sal_uInt32 nStt, nEnd;
695 sal_Int32 nSttCnt;
696 sal_Int32 nEndCnt;
697
698 SaveRedline( SwRangeRedline* pR, const SwNodeIndex& rSttIdx )
699 : pRedl(pR)
700 , nEnd(0)
701 , nEndCnt(0)
702 {
703 const SwPosition* pStt = pR->Start(),
704 * pEnd = pR->GetMark() == pStt ? pR->GetPoint() : pR->GetMark();
705 sal_uInt32 nSttIdx = rSttIdx.GetIndex();
706 nStt = pStt->nNode.GetIndex() - nSttIdx;
707 nSttCnt = pStt->nContent.GetIndex();
708 if( pR->HasMark() )
709 {
710 nEnd = pEnd->nNode.GetIndex() - nSttIdx;
711 nEndCnt = pEnd->nContent.GetIndex();
712 }
713
714 pRedl->GetPoint()->nNode = 0;
715 pRedl->GetPoint()->nContent.Assign( nullptr, 0 );
716 pRedl->GetMark()->nNode = 0;
717 pRedl->GetMark()->nContent.Assign( nullptr, 0 );
718 }
719
720 SaveRedline( SwRangeRedline* pR, const SwPosition& rPos )
721 : pRedl(pR)
722 , nEnd(0)
723 , nEndCnt(0)
724 {
725 const SwPosition* pStt = pR->Start(),
726 * pEnd = pR->GetMark() == pStt ? pR->GetPoint() : pR->GetMark();
727 sal_uInt32 nSttIdx = rPos.nNode.GetIndex();
728 nStt = pStt->nNode.GetIndex() - nSttIdx;
729 nSttCnt = pStt->nContent.GetIndex();
730 if( nStt == 0 )
731 nSttCnt = nSttCnt - rPos.nContent.GetIndex();
732 if( pR->HasMark() )
733 {
734 nEnd = pEnd->nNode.GetIndex() - nSttIdx;
735 nEndCnt = pEnd->nContent.GetIndex();
736 if( nEnd == 0 )
737 nEndCnt = nEndCnt - rPos.nContent.GetIndex();
738 }
739
740 pRedl->GetPoint()->nNode = 0;
741 pRedl->GetPoint()->nContent.Assign( nullptr, 0 );
742 pRedl->GetMark()->nNode = 0;
743 pRedl->GetMark()->nContent.Assign( nullptr, 0 );
744 }
745
746 void SetPos( sal_uInt32 nInsPos )
747 {
748 pRedl->GetPoint()->nNode = nInsPos + nStt;
749 pRedl->GetPoint()->nContent.Assign( pRedl->GetContentNode(), nSttCnt );
750 if( pRedl->HasMark() )
751 {
752 pRedl->GetMark()->nNode = nInsPos + nEnd;
753 pRedl->GetMark()->nContent.Assign( pRedl->GetContentNode(false), nEndCnt );
754 }
755 }
756
757 void SetPos( const SwPosition& aPos )
758 {
759 pRedl->GetPoint()->nNode = aPos.nNode.GetIndex() + nStt;
760 pRedl->GetPoint()->nContent.Assign( pRedl->GetContentNode(), nSttCnt + ( nStt == 0 ? aPos.nContent.GetIndex() : 0 ) );
761 if( pRedl->HasMark() )
762 {
763 pRedl->GetMark()->nNode = aPos.nNode.GetIndex() + nEnd;
764 pRedl->GetMark()->nContent.Assign( pRedl->GetContentNode(false), nEndCnt + ( nEnd == 0 ? aPos.nContent.GetIndex() : 0 ) );
765 }
766 }
767 };
768
769 typedef std::vector< SaveRedline > SaveRedlines_t;
770
771 void lcl_SaveRedlines(const SwPaM& aPam, SaveRedlines_t& rArr)
772 {
773 SwDoc& rDoc = aPam.GetNode().GetDoc();
774
775 const SwPosition* pStart = aPam.Start();
776 const SwPosition* pEnd = aPam.End();
777
778 // get first relevant redline
779 SwRedlineTable::size_type nCurrentRedline;
780 rDoc.getIDocumentRedlineAccess().GetRedline( *pStart, &nCurrentRedline );
781 if( nCurrentRedline > 0)
782 nCurrentRedline--;
783
784 // redline mode RedlineFlags::Ignore|RedlineFlags::On; save old mode
785 RedlineFlags eOld = rDoc.getIDocumentRedlineAccess().GetRedlineFlags();
786 rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( ( eOld & ~RedlineFlags::Ignore) | RedlineFlags::On );
787
788 // iterate over relevant redlines and decide for each whether it should
789 // be saved, or split + saved
790 SwRedlineTable& rRedlineTable = rDoc.getIDocumentRedlineAccess().GetRedlineTable();
791 for( ; nCurrentRedline < rRedlineTable.size(); nCurrentRedline++ )
792 {
793 SwRangeRedline* pCurrent = rRedlineTable[ nCurrentRedline ];
794 SwComparePosition eCompare =
795 ComparePosition( *pCurrent->Start(), *pCurrent->End(),
796 *pStart, *pEnd);
797
798 // we must save this redline if it overlaps aPam
799 // (we may have to split it, too)
800 if( eCompare == SwComparePosition::OverlapBehind ||
801 eCompare == SwComparePosition::OverlapBefore ||
802 eCompare == SwComparePosition::Outside ||
803 eCompare == SwComparePosition::Inside ||
804 eCompare == SwComparePosition::Equal )
805 {
806 rRedlineTable.Remove( nCurrentRedline-- );
807
808 // split beginning, if necessary
809 if( eCompare == SwComparePosition::OverlapBefore ||
810 eCompare == SwComparePosition::Outside )
811 {
812 SwRangeRedline* pNewRedline = new SwRangeRedline( *pCurrent );
813 *pNewRedline->End() = *pStart;
814 *pCurrent->Start() = *pStart;
815 rDoc.getIDocumentRedlineAccess().AppendRedline( pNewRedline, true );
816 }
817
818 // split end, if necessary
819 if( eCompare == SwComparePosition::OverlapBehind ||
820 eCompare == SwComparePosition::Outside )
821 {
822 SwRangeRedline* pNewRedline = new SwRangeRedline( *pCurrent );
823 *pNewRedline->Start() = *pEnd;
824 *pCurrent->End() = *pEnd;
825 rDoc.getIDocumentRedlineAccess().AppendRedline( pNewRedline, true );
826 }
827
828 // save the current redline
829 rArr.emplace_back( pCurrent, *pStart );
830 }
831 }
832
833 // restore old redline mode
834 rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld );
835 }
836
837 void lcl_RestoreRedlines(SwDoc& rDoc, const SwPosition& rPos, SaveRedlines_t& rArr)
838 {
839 RedlineFlags eOld = rDoc.getIDocumentRedlineAccess().GetRedlineFlags();
840 rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( ( eOld & ~RedlineFlags::Ignore) | RedlineFlags::On );
841
842 for(SaveRedline & rSvRedLine : rArr)
843 {
844 rSvRedLine.SetPos( rPos );
845 rDoc.getIDocumentRedlineAccess().AppendRedline( rSvRedLine.pRedl, true );
846 }
847
848 rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld );
849 }
850
851 void lcl_SaveRedlines(const SwNodeRange& rRg, SaveRedlines_t& rArr)
852 {
853 SwDoc& rDoc = rRg.aStart.GetNode().GetDoc();
854 SwRedlineTable::size_type nRedlPos;
855 SwPosition aSrchPos( rRg.aStart ); aSrchPos.nNode--;
856 aSrchPos.nContent.Assign( aSrchPos.nNode.GetNode().GetContentNode(), 0 );
857 if( rDoc.getIDocumentRedlineAccess().GetRedline( aSrchPos, &nRedlPos ) && nRedlPos )
858 --nRedlPos;
859 else if( nRedlPos >= rDoc.getIDocumentRedlineAccess().GetRedlineTable().size() )
860 return ;
861
862 RedlineFlags eOld = rDoc.getIDocumentRedlineAccess().GetRedlineFlags();
863 rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( ( eOld & ~RedlineFlags::Ignore) | RedlineFlags::On );
864 SwRedlineTable& rRedlTable = rDoc.getIDocumentRedlineAccess().GetRedlineTable();
865
866 do {
867 SwRangeRedline* pTmp = rRedlTable[ nRedlPos ];
868
869 const SwPosition* pRStt = pTmp->Start(),
870 * pREnd = pTmp->GetMark() == pRStt
871 ? pTmp->GetPoint() : pTmp->GetMark();
872
873 if( pRStt->nNode < rRg.aStart )
874 {
875 if( pREnd->nNode > rRg.aStart && pREnd->nNode < rRg.aEnd )
876 {
877 // Create a copy and set the end of the original to the end of the MoveArea.
878 // The copy is moved too.
879 SwRangeRedline* pNewRedl = new SwRangeRedline( *pTmp );
880 SwPosition* pTmpPos = pNewRedl->Start();
881 pTmpPos->nNode = rRg.aStart;
882 pTmpPos->nContent.Assign(
883 pTmpPos->nNode.GetNode().GetContentNode(), 0 );
884
885 rArr.emplace_back(pNewRedl, rRg.aStart);
886
887 pTmpPos = pTmp->End();
888 pTmpPos->nNode = rRg.aEnd;
889 pTmpPos->nContent.Assign(
890 pTmpPos->nNode.GetNode().GetContentNode(), 0 );
891 }
892 else if( pREnd->nNode == rRg.aStart )
893 {
894 SwPosition* pTmpPos = pTmp->End();
895 pTmpPos->nNode = rRg.aEnd;
896 pTmpPos->nContent.Assign(
897 pTmpPos->nNode.GetNode().GetContentNode(), 0 );
898 }
899 }
900 else if( pRStt->nNode < rRg.aEnd )
901 {
902 rRedlTable.Remove( nRedlPos-- );
903 if( pREnd->nNode < rRg.aEnd ||
904 ( pREnd->nNode == rRg.aEnd && !pREnd->nContent.GetIndex()) )
905 {
906 // move everything
907 rArr.emplace_back( pTmp, rRg.aStart );
908 }
909 else
910 {
911 // split
912 SwRangeRedline* pNewRedl = new SwRangeRedline( *pTmp );
913 SwPosition* pTmpPos = pNewRedl->End();
914 pTmpPos->nNode = rRg.aEnd;
915 pTmpPos->nContent.Assign(
916 pTmpPos->nNode.GetNode().GetContentNode(), 0 );
917
918 rArr.emplace_back( pNewRedl, rRg.aStart );
919
920 pTmpPos = pTmp->Start();
921 pTmpPos->nNode = rRg.aEnd;
922 pTmpPos->nContent.Assign(
923 pTmpPos->nNode.GetNode().GetContentNode(), 0 );
924 rDoc.getIDocumentRedlineAccess().AppendRedline( pTmp, true );
925 }
926 }
927 else
928 break;
929
930 } while( ++nRedlPos < rDoc.getIDocumentRedlineAccess().GetRedlineTable().size() );
931 rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld );
932 }
933
934 void lcl_RestoreRedlines(SwDoc& rDoc, sal_uInt32 const nInsPos, SaveRedlines_t& rArr)
935 {
936 RedlineFlags eOld = rDoc.getIDocumentRedlineAccess().GetRedlineFlags();
937 rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( ( eOld & ~RedlineFlags::Ignore) | RedlineFlags::On );
938
939 for(SaveRedline & rSvRedLine : rArr)
940 {
941 rSvRedLine.SetPos( nInsPos );
942 rDoc.getIDocumentRedlineAccess().AppendRedline( rSvRedLine.pRedl, true );
943 if (rSvRedLine.pRedl->GetType() == RedlineType::Delete)
944 {
945 UpdateFramesForAddDeleteRedline(rDoc, *rSvRedLine.pRedl);
946 }
947 }
948
949 rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld );
950 }
951
952 bool lcl_SaveFootnote( const SwNodeIndex& rSttNd, const SwNodeIndex& rEndNd,
953 const SwNodeIndex& rInsPos,
954 SwFootnoteIdxs& rFootnoteArr, SwFootnoteIdxs& rSaveArr,
955 const SwIndex* pSttCnt = nullptr, const SwIndex* pEndCnt = nullptr )
956 {
957 bool bUpdateFootnote = false;
958 const SwNodes& rNds = rInsPos.GetNodes();
959 const bool bDelFootnote = rInsPos.GetIndex() < rNds.GetEndOfAutotext().GetIndex() &&
960 rSttNd.GetIndex() >= rNds.GetEndOfAutotext().GetIndex();
961 const bool bSaveFootnote = !bDelFootnote &&
962 rInsPos.GetIndex() >= rNds.GetEndOfExtras().GetIndex();
963 if( !rFootnoteArr.empty() )
964 {
965
966 size_t nPos = 0;
967 rFootnoteArr.SeekEntry( rSttNd, &nPos );
968 SwTextFootnote* pSrch;
969 const SwNode* pFootnoteNd;
970
971 // Delete/save all that come after it
972 while( nPos < rFootnoteArr.size() && ( pFootnoteNd =
973 &( pSrch = rFootnoteArr[ nPos ] )->GetTextNode())->GetIndex()
974 <= rEndNd.GetIndex() )
975 {
976 const sal_Int32 nFootnoteSttIdx = pSrch->GetStart();
977 if( ( pEndCnt && pSttCnt )
978 ? (( &rSttNd.GetNode() == pFootnoteNd &&
979 pSttCnt->GetIndex() > nFootnoteSttIdx) ||
980 ( &rEndNd.GetNode() == pFootnoteNd &&
981 nFootnoteSttIdx >= pEndCnt->GetIndex() ))
982 : ( &rEndNd.GetNode() == pFootnoteNd ))
983 {
984 ++nPos; // continue searching
985 }
986 else
987 {
988 // delete it
989 if( bDelFootnote )
990 {
991 SwTextNode& rTextNd = const_cast<SwTextNode&>(pSrch->GetTextNode());
992 SwIndex aIdx( &rTextNd, nFootnoteSttIdx );
993 rTextNd.EraseText( aIdx, 1 );
994 }
995 else
996 {
997 pSrch->DelFrames(nullptr);
998 rFootnoteArr.erase( rFootnoteArr.begin() + nPos );
999 if( bSaveFootnote )
1000 rSaveArr.insert( pSrch );
1001 }
1002 bUpdateFootnote = true;
1003 }
1004 }
1005
1006 while( nPos-- && ( pFootnoteNd = &( pSrch = rFootnoteArr[ nPos ] )->
1007 GetTextNode())->GetIndex() >= rSttNd.GetIndex() )
1008 {
1009 const sal_Int32 nFootnoteSttIdx = pSrch->GetStart();
1010 if( !pEndCnt || !pSttCnt ||
1011 ! (( &rSttNd.GetNode() == pFootnoteNd &&
1012 pSttCnt->GetIndex() > nFootnoteSttIdx ) ||
1013 ( &rEndNd.GetNode() == pFootnoteNd &&
1014 nFootnoteSttIdx >= pEndCnt->GetIndex() )) )
1015 {
1016 if( bDelFootnote )
1017 {
1018 // delete it
1019 SwTextNode& rTextNd = const_cast<SwTextNode&>(pSrch->GetTextNode());
1020 SwIndex aIdx( &rTextNd, nFootnoteSttIdx );
1021 rTextNd.EraseText( aIdx, 1 );
1022 }
1023 else
1024 {
1025 pSrch->DelFrames(nullptr);
1026 rFootnoteArr.erase( rFootnoteArr.begin() + nPos );
1027 if( bSaveFootnote )
1028 rSaveArr.insert( pSrch );
1029 }
1030 bUpdateFootnote = true;
1031 }
1032 }
1033 }
1034 // When moving from redline section into document content section, e.g.
1035 // after loading a document with (delete-)redlines, the footnote array
1036 // has to be adjusted... (#i70572)
1037 if( bSaveFootnote )
1038 {
1039 SwNodeIndex aIdx( rSttNd );
1040 while( aIdx < rEndNd ) // Check the moved section
1041 {
1042 SwNode* pNode = &aIdx.GetNode();
1043 if( pNode->IsTextNode() ) // Looking for text nodes...
1044 {
1045 SwpHints *pHints = pNode->GetTextNode()->GetpSwpHints();
1046 if( pHints && pHints->HasFootnote() ) //...with footnotes
1047 {
1048 bUpdateFootnote = true; // Heureka
1049 const size_t nCount = pHints->Count();
1050 for( size_t i = 0; i < nCount; ++i )
1051 {
1052 SwTextAttr *pAttr = pHints->Get( i );
1053 if ( pAttr->Which() == RES_TXTATR_FTN )
1054 {
1055 rSaveArr.insert( static_cast<SwTextFootnote*>(pAttr) );
1056 }
1057 }
1058 }
1059 }
1060 ++aIdx;
1061 }
1062 }
1063 return bUpdateFootnote;
1064 }
1065
1066 bool lcl_MayOverwrite( const SwTextNode *pNode, const sal_Int32 nPos )
1067 {
1068 sal_Unicode const cChr = pNode->GetText()[nPos];
1069 switch (cChr)
1070 {
1071 case CH_TXTATR_BREAKWORDu'\x0001':
1072 case CH_TXTATR_INWORDu'\xFFF9':
1073 return !pNode->GetTextAttrForCharAt(nPos);// how could there be none?
1074 case CH_TXT_ATR_INPUTFIELDSTARTu'\x0004':
1075 case CH_TXT_ATR_INPUTFIELDENDu'\x0005':
1076 case CH_TXT_ATR_FIELDSTARTu'\x0007':
1077 case CH_TXT_ATR_FIELDSEPu'\x0003':
1078 case CH_TXT_ATR_FIELDENDu'\x0008':
1079 case CH_TXT_ATR_FORMELEMENTu'\x0006':
1080 return false;
1081 default:
1082 return true;
1083 }
1084 }
1085
1086 void lcl_SkipAttr( const SwTextNode *pNode, SwIndex &rIdx, sal_Int32 &rStart )
1087 {
1088 if( !lcl_MayOverwrite( pNode, rStart ) )
1089 {
1090 // skip all special attributes
1091 do {
1092 ++rIdx;
1093 rStart = rIdx.GetIndex();
1094 } while (rStart < pNode->GetText().getLength()
1095 && !lcl_MayOverwrite(pNode, rStart) );
1096 }
1097 }
1098
1099 bool lcl_GetTokenToParaBreak( OUString& rStr, OUString& rRet, bool bRegExpRplc )
1100 {
1101 if( bRegExpRplc )
1102 {
1103 sal_Int32 nPos = 0;
1104 const OUString sPara("\\n");
1105 for (;;)
1106 {
1107 nPos = rStr.indexOf( sPara, nPos );
1108 if (nPos<0)
1109 {
1110 break;
1111 }
1112 // Has this been escaped?
1113 if( nPos && '\\' == rStr[nPos-1])
1114 {
1115 ++nPos;
1116 if( nPos >= rStr.getLength() )
1117 {
1118 break;
1119 }
1120 }
1121 else
1122 {
1123 rRet = rStr.copy( 0, nPos );
1124 rStr = rStr.copy( nPos + sPara.getLength() );
1125 return true;
1126 }
1127 }
1128 }
1129 rRet = rStr;
1130 rStr.clear();
1131 return false;
1132 }
1133}
1134
1135namespace //local functions originally from docfmt.cxx
1136{
1137
1138 bool lcl_ApplyOtherSet(
1139 SwContentNode & rNode,
1140 SwHistory *const pHistory,
1141 SfxItemSet const& rOtherSet,
1142 SfxItemSet const& rFirstSet,
1143 SfxItemSet const& rPropsSet,
1144 SwRootFrame const*const pLayout,
1145 SwNodeIndex *const o_pIndex = nullptr)
1146 {
1147 assert(rOtherSet.Count())(static_cast <bool> (rOtherSet.Count()) ? void (0) : __assert_fail
("rOtherSet.Count()", "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 1147, __extension__ __PRETTY_FUNCTION__))
;
1148
1149 bool ret(false);
1150 SwTextNode *const pTNd = rNode.GetTextNode();
1151 sw::MergedPara const* pMerged(nullptr);
1152 if (pLayout && pLayout->IsHideRedlines() && pTNd)
1153 {
1154 SwTextFrame const*const pTextFrame(static_cast<SwTextFrame const*>(
1155 pTNd->getLayoutFrame(pLayout)));
1156 if (pTextFrame)
1157 {
1158 pMerged = pTextFrame->GetMergedPara();
1159 }
1160 if (pMerged)
1161 {
1162 if (rFirstSet.Count())
1163 {
1164 if (pHistory)
1165 {
1166 SwRegHistory aRegH(pMerged->pFirstNode, *pMerged->pFirstNode, pHistory);
1167 ret = pMerged->pFirstNode->SetAttr(rFirstSet);
1168 }
1169 else
1170 {
1171 ret = pMerged->pFirstNode->SetAttr(rFirstSet);
1172 }
1173 }
1174 if (rPropsSet.Count())
1175 {
1176 if (pHistory)
1177 {
1178 SwRegHistory aRegH(pMerged->pParaPropsNode, *pMerged->pParaPropsNode, pHistory);
1179 ret = pMerged->pParaPropsNode->SetAttr(rPropsSet) || ret;
1180 }
1181 else
1182 {
1183 ret = pMerged->pParaPropsNode->SetAttr(rPropsSet) || ret;
1184 }
1185 }
1186 if (o_pIndex)
1187 {
1188 *o_pIndex = *pMerged->pLastNode; // skip hidden
1189 }
1190 }
1191 }
1192
1193 // input cursor can't be on hidden node, and iteration skips them
1194 assert(!pLayout || !pLayout->IsHideRedlines()(static_cast <bool> (!pLayout || !pLayout->IsHideRedlines
() || rNode.GetRedlineMergeFlag() != SwNode::Merge::Hidden) ?
void (0) : __assert_fail ("!pLayout || !pLayout->IsHideRedlines() || rNode.GetRedlineMergeFlag() != SwNode::Merge::Hidden"
, "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 1195, __extension__ __PRETTY_FUNCTION__))
1195 || rNode.GetRedlineMergeFlag() != SwNode::Merge::Hidden)(static_cast <bool> (!pLayout || !pLayout->IsHideRedlines
() || rNode.GetRedlineMergeFlag() != SwNode::Merge::Hidden) ?
void (0) : __assert_fail ("!pLayout || !pLayout->IsHideRedlines() || rNode.GetRedlineMergeFlag() != SwNode::Merge::Hidden"
, "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 1195, __extension__ __PRETTY_FUNCTION__))
;
1196
1197 if (!pMerged)
1198 {
1199 if (pHistory)
1200 {
1201 SwRegHistory aRegH(&rNode, rNode, pHistory);
1202 ret = rNode.SetAttr( rOtherSet );
1203 }
1204 else
1205 {
1206 ret = rNode.SetAttr( rOtherSet );
1207 }
1208 }
1209 return ret;
1210 }
1211
1212 #define DELETECHARSETSif ( bDelete ) { delete pCharSet; delete pOtherSet; } if ( bDelete ) { delete pCharSet; delete pOtherSet; }
1213
1214 /// Insert Hints according to content types;
1215 // Is used in SwDoc::Insert(..., SwFormatHint &rHt)
1216
1217 bool lcl_InsAttr(
1218 SwDoc& rDoc,
1219 const SwPaM &rRg,
1220 const SfxItemSet& rChgSet,
1221 const SetAttrMode nFlags,
1222 SwUndoAttr *const pUndo,
1223 SwRootFrame const*const pLayout,
1224 const bool bExpandCharToPara,
1225 SwTextAttr **ppNewTextAttr)
1226 {
1227 // Divide the Sets (for selections in Nodes)
1228 const SfxItemSet* pCharSet = nullptr;
1229 const SfxItemSet* pOtherSet = nullptr;
1230 bool bDelete = false;
1231 bool bCharAttr = false;
1232 bool bOtherAttr = false;
1233
1234 // Check, if we can work with rChgSet or if we have to create additional SfxItemSets
1235 if ( 1 == rChgSet.Count() )
1236 {
1237 SfxItemIter aIter( rChgSet );
1238 const SfxPoolItem* pItem = aIter.GetCurItem();
1239 if (pItem && !IsInvalidItem(pItem))
1240 {
1241 const sal_uInt16 nWhich = pItem->Which();
1242
1243 if ( isCHRATR(nWhich) ||
1244 (RES_TXTATR_CHARFMT == nWhich) ||
1245 (RES_TXTATR_INETFMT == nWhich) ||
1246 (RES_TXTATR_AUTOFMT == nWhich) ||
1247 (RES_TXTATR_UNKNOWN_CONTAINER == nWhich) )
1248 {
1249 pCharSet = &rChgSet;
1250 bCharAttr = true;
1251 }
1252
1253 if ( isPARATR(nWhich)
1254 || isPARATR_LIST(nWhich)
1255 || isFRMATR(nWhich)
1256 || isGRFATR(nWhich)
1257 || isUNKNOWNATR(nWhich)
1258 || isDrawingLayerAttribute(nWhich) )
1259 {
1260 pOtherSet = &rChgSet;
1261 bOtherAttr = true;
1262 }
1263 }
1264 }
1265
1266 // Build new itemset if either
1267 // - rChgSet.Count() > 1 or
1268 // - The attribute in rChgSet does not belong to one of the above categories
1269 if ( !bCharAttr && !bOtherAttr )
1270 {
1271 SfxItemSet* pTmpCharItemSet = new SfxItemSet(
1272 rDoc.GetAttrPool(),
1273 svl::Items<
1274 RES_CHRATR_BEGIN, RES_CHRATR_END - 1,
1275 RES_TXTATR_AUTOFMT, RES_TXTATR_CHARFMT,
1276 RES_TXTATR_UNKNOWN_CONTAINER,
1277 RES_TXTATR_UNKNOWN_CONTAINER>{});
1278
1279 SfxItemSet* pTmpOtherItemSet = new SfxItemSet(
1280 rDoc.GetAttrPool(),
1281 svl::Items<
1282 RES_PARATR_BEGIN, RES_GRFATR_END - 1,
1283 RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END - 1,
1284 // FillAttribute support:
1285 XATTR_FILL_FIRST, XATTR_FILL_LAST>{});
1286
1287 pTmpCharItemSet->Put( rChgSet );
1288 pTmpOtherItemSet->Put( rChgSet );
1289
1290 pCharSet = pTmpCharItemSet;
1291 pOtherSet = pTmpOtherItemSet;
1292
1293 bDelete = true;
1294 }
1295
1296 SwHistory* pHistory = pUndo ? &pUndo->GetHistory() : nullptr;
1297 bool bRet = false;
1298 const SwPosition *pStt = rRg.Start(), *pEnd = rRg.End();
1299 SwContentNode* pNode = pStt->nNode.GetNode().GetContentNode();
1300
1301 if( pNode && pNode->IsTextNode() )
1302 {
1303 // tdf#127606 at editing, remove different formatting of DOCX-like numbering symbol
1304 if (pLayout && pNode->GetTextNode()->getIDocumentSettingAccess()->
1305 get(DocumentSettingId::APPLY_PARAGRAPH_MARK_FORMAT_TO_NUMBERING ))
1306 {
1307 SwContentNode* pEndNode = pEnd->nNode.GetNode().GetContentNode();
1308 SwContentNode* pCurrentNode = pEndNode;
1309 auto nStartIndex = pNode->GetIndex();
1310 auto nEndIndex = pEndNode->GetIndex();
1311 SwNodeIndex aIdx( pEnd->nNode.GetNode() );
1312 while ( pCurrentNode != nullptr && nStartIndex <= pCurrentNode->GetIndex() )
1313 {
1314 if (pCurrentNode->GetSwAttrSet().HasItem(RES_PARATR_LIST_AUTOFMT) &&
1315 // remove character formatting only on wholly selected paragraphs
1316 (nStartIndex < pCurrentNode->GetIndex() || pStt->nContent.GetIndex() == 0) &&
1317 (pCurrentNode->GetIndex() < nEndIndex || pEnd->nContent.GetIndex() == pEndNode->Len()))
1318 {
1319 pCurrentNode->ResetAttr(RES_PARATR_LIST_AUTOFMT);
1320 // reset also paragraph marker
1321 SwIndex nIdx( pCurrentNode, pCurrentNode->Len() );
1322 pCurrentNode->GetTextNode()->RstTextAttr(nIdx, 1);
1323 }
1324 pCurrentNode = SwNodes::GoPrevious( &aIdx );
1325 }
1326 }
1327 // #i27615#
1328 if (rRg.IsInFrontOfLabel())
1329 {
1330 SwTextNode * pTextNd = pNode->GetTextNode();
1331 if (pLayout)
1332 {
1333 pTextNd = sw::GetParaPropsNode(*pLayout, *pTextNd);
1334 }
1335 SwNumRule * pNumRule = pTextNd->GetNumRule();
1336
1337 if ( !pNumRule )
1338 {
1339 OSL_FAIL( "<InsAttr(..)> - PaM in front of label, but text node has no numbering rule set. This is a serious defect." )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
":" "1339" ": "), "%s", "<InsAttr(..)> - PaM in front of label, but text node has no numbering rule set. This is a serious defect."
); } } while (false)
;
1340 DELETECHARSETSif ( bDelete ) { delete pCharSet; delete pOtherSet; }
1341 return false;
1342 }
1343
1344 int nLevel = pTextNd->GetActualListLevel();
1345
1346 if (nLevel < 0)
1347 nLevel = 0;
1348
1349 if (nLevel >= MAXLEVEL)
1350 nLevel = MAXLEVEL - 1;
1351
1352 SwNumFormat aNumFormat = pNumRule->Get(static_cast<sal_uInt16>(nLevel));
1353 SwCharFormat * pCharFormat =
1354 rDoc.FindCharFormatByName(aNumFormat.GetCharFormatName());
1355
1356 if (pCharFormat)
1357 {
1358 if (pHistory)
1359 pHistory->Add(pCharFormat->GetAttrSet(), *pCharFormat);
1360
1361 if ( pCharSet )
1362 pCharFormat->SetFormatAttr(*pCharSet);
1363 }
1364
1365 DELETECHARSETSif ( bDelete ) { delete pCharSet; delete pOtherSet; }
1366 return true;
1367 }
1368
1369 const SwIndex& rSt = pStt->nContent;
1370
1371 // Attributes without an end do not have a range
1372 if ( !bCharAttr && !bOtherAttr )
1373 {
1374 SfxItemSet aTextSet( rDoc.GetAttrPool(),
1375 svl::Items<RES_TXTATR_NOEND_BEGIN, RES_TXTATR_NOEND_END-1>{} );
1376 aTextSet.Put( rChgSet );
1377 if( aTextSet.Count() )
1378 {
1379 SwRegHistory history( pNode, *pNode, pHistory );
1380 bRet = history.InsertItems(
1381 aTextSet, rSt.GetIndex(), rSt.GetIndex(), nFlags, /*ppNewTextAttr*/nullptr ) || bRet;
1382
1383 if (bRet && (rDoc.getIDocumentRedlineAccess().IsRedlineOn() || (!rDoc.getIDocumentRedlineAccess().IsIgnoreRedline()
1384 && !rDoc.getIDocumentRedlineAccess().GetRedlineTable().empty())))
1385 {
1386 SwPaM aPam( pStt->nNode, pStt->nContent.GetIndex()-1,
1387 pStt->nNode, pStt->nContent.GetIndex() );
1388
1389 if( pUndo )
1390 pUndo->SaveRedlineData( aPam, true );
1391
1392 if( rDoc.getIDocumentRedlineAccess().IsRedlineOn() )
1393 rDoc.getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline( RedlineType::Insert, aPam ), true);
1394 else
1395 rDoc.getIDocumentRedlineAccess().SplitRedline( aPam );
1396 }
1397 }
1398 }
1399
1400 // TextAttributes with an end never expand their range
1401 if ( !bCharAttr && !bOtherAttr )
1402 {
1403 // CharFormat and URL attributes are treated separately!
1404 // TEST_TEMP ToDo: AutoFormat!
1405 SfxItemSet aTextSet(
1406 rDoc.GetAttrPool(),
1407 svl::Items<
1408 RES_TXTATR_REFMARK, RES_TXTATR_METAFIELD,
1409 RES_TXTATR_CJK_RUBY, RES_TXTATR_CJK_RUBY,
1410 RES_TXTATR_INPUTFIELD, RES_TXTATR_INPUTFIELD>{});
1411
1412 aTextSet.Put( rChgSet );
1413 if( aTextSet.Count() )
1414 {
1415 const sal_Int32 nInsCnt = rSt.GetIndex();
1416 const sal_Int32 nEnd = pStt->nNode == pEnd->nNode
1417 ? pEnd->nContent.GetIndex()
1418 : pNode->Len();
1419 SwRegHistory history( pNode, *pNode, pHistory );
1420 bRet = history.InsertItems( aTextSet, nInsCnt, nEnd, nFlags, ppNewTextAttr )
1421 || bRet;
1422
1423 if (bRet && (rDoc.getIDocumentRedlineAccess().IsRedlineOn() || (!rDoc.getIDocumentRedlineAccess().IsIgnoreRedline()
1424 && !rDoc.getIDocumentRedlineAccess().GetRedlineTable().empty())))
1425 {
1426 // Was text content inserted? (RefMark/TOXMarks without an end)
1427 bool bTextIns = nInsCnt != rSt.GetIndex();
1428 // Was content inserted or set over the selection?
1429 SwPaM aPam( pStt->nNode, bTextIns ? nInsCnt + 1 : nEnd,
1430 pStt->nNode, nInsCnt );
1431 if( pUndo )
1432 pUndo->SaveRedlineData( aPam, bTextIns );
1433
1434 if( rDoc.getIDocumentRedlineAccess().IsRedlineOn() )
1435 rDoc.getIDocumentRedlineAccess().AppendRedline(
1436 new SwRangeRedline(
1437 bTextIns ? RedlineType::Insert : RedlineType::Format, aPam ),
1438 true);
1439 else if( bTextIns )
1440 rDoc.getIDocumentRedlineAccess().SplitRedline( aPam );
1441 }
1442 }
1443 }
1444 }
1445
1446 // We always have to set the auto flag for PageDescs that are set at the Node!
1447 if( pOtherSet && pOtherSet->Count() )
1448 {
1449 SwTableNode* pTableNd;
1450 const SwFormatPageDesc* pDesc;
1451 if( SfxItemState::SET == pOtherSet->GetItemState( RES_PAGEDESC,
1452 false, reinterpret_cast<const SfxPoolItem**>(&pDesc) ))
1453 {
1454 if( pNode )
1455 {
1456 // Set auto flag. Only in the template it's without auto!
1457 SwFormatPageDesc aNew( *pDesc );
1458
1459 // Tables now also know line breaks
1460 if( !(nFlags & SetAttrMode::APICALL) &&
1461 nullptr != ( pTableNd = pNode->FindTableNode() ) )
1462 {
1463 SwTableNode* pCurTableNd = pTableNd;
1464 while ( nullptr != ( pCurTableNd = pCurTableNd->StartOfSectionNode()->FindTableNode() ) )
1465 pTableNd = pCurTableNd;
1466
1467 // set the table format
1468 SwFrameFormat* pFormat = pTableNd->GetTable().GetFrameFormat();
1469 SwRegHistory aRegH( pFormat, *pTableNd, pHistory );
1470 pFormat->SetFormatAttr( aNew );
1471 bRet = true;
1472 }
1473 else
1474 {
1475 SwContentNode * pFirstNode(pNode);
1476 if (pLayout && pLayout->IsHideRedlines())
1477 {
1478 pFirstNode = sw::GetFirstAndLastNode(*pLayout, pStt->nNode).first;
1479 }
1480 SwRegHistory aRegH( pFirstNode, *pFirstNode, pHistory );
1481 bRet = pFirstNode->SetAttr( aNew ) || bRet;
1482 }
1483 }
1484
1485 // bOtherAttr = true means that pOtherSet == rChgSet. In this case
1486 // we know, that there is only one attribute in pOtherSet. We cannot
1487 // perform the following operations, instead we return:
1488 if ( bOtherAttr )
1489 return bRet;
1490
1491 const_cast<SfxItemSet*>(pOtherSet)->ClearItem( RES_PAGEDESC );
1492 if( !pOtherSet->Count() )
1493 {
1494 DELETECHARSETSif ( bDelete ) { delete pCharSet; delete pOtherSet; }
1495 return bRet;
1496 }
1497 }
1498
1499 // Tables now also know line breaks
1500 const SvxFormatBreakItem* pBreak;
1501 if( pNode && !(nFlags & SetAttrMode::APICALL) &&
1502 nullptr != (pTableNd = pNode->FindTableNode() ) &&
1503 SfxItemState::SET == pOtherSet->GetItemState( RES_BREAK,
1504 false, reinterpret_cast<const SfxPoolItem**>(&pBreak) ) )
1505 {
1506 SwTableNode* pCurTableNd = pTableNd;
1507 while ( nullptr != ( pCurTableNd = pCurTableNd->StartOfSectionNode()->FindTableNode() ) )
1508 pTableNd = pCurTableNd;
1509
1510 // set the table format
1511 SwFrameFormat* pFormat = pTableNd->GetTable().GetFrameFormat();
1512 SwRegHistory aRegH( pFormat, *pTableNd, pHistory );
1513 pFormat->SetFormatAttr( *pBreak );
1514 bRet = true;
1515
1516 // bOtherAttr = true means that pOtherSet == rChgSet. In this case
1517 // we know, that there is only one attribute in pOtherSet. We cannot
1518 // perform the following operations, instead we return:
1519 if ( bOtherAttr )
1520 return bRet;
1521
1522 const_cast<SfxItemSet*>(pOtherSet)->ClearItem( RES_BREAK );
1523 if( !pOtherSet->Count() )
1524 {
1525 DELETECHARSETSif ( bDelete ) { delete pCharSet; delete pOtherSet; }
1526 return bRet;
1527 }
1528 }
1529
1530 {
1531 // If we have a PoolNumRule, create it if needed
1532 const SwNumRuleItem* pRule;
1533 sal_uInt16 nPoolId=0;
1534 if( SfxItemState::SET == pOtherSet->GetItemState( RES_PARATR_NUMRULE,
1535 false, reinterpret_cast<const SfxPoolItem**>(&pRule) ) &&
1536 !rDoc.FindNumRulePtr( pRule->GetValue() ) &&
1537 USHRT_MAX(32767 *2 +1) != (nPoolId = SwStyleNameMapper::GetPoolIdFromUIName ( pRule->GetValue(),
1538 SwGetPoolIdFromName::NumRule )) )
1539 rDoc.getIDocumentStylePoolAccess().GetNumRuleFromPool( nPoolId );
1540 }
1541 }
1542
1543 SfxItemSet firstSet(rDoc.GetAttrPool(),
1544 svl::Items<RES_PAGEDESC, RES_BREAK>{});
1545 if (pOtherSet && pOtherSet->Count())
1546 { // actually only RES_BREAK is possible here...
1547 firstSet.Put(*pOtherSet);
1548 }
1549 SfxItemSet propsSet(rDoc.GetAttrPool(),
1550 svl::Items<RES_PARATR_BEGIN, RES_PAGEDESC,
1551 RES_BREAK+1, RES_FRMATR_END,
1552 XATTR_FILL_FIRST, XATTR_FILL_LAST+1>{});
1553 if (pOtherSet && pOtherSet->Count())
1554 {
1555 propsSet.Put(*pOtherSet);
1556 }
1557
1558 if( !rRg.HasMark() ) // no range
1559 {
1560 if( !pNode )
1561 {
1562 DELETECHARSETSif ( bDelete ) { delete pCharSet; delete pOtherSet; }
1563 return bRet;
1564 }
1565
1566 if( pNode->IsTextNode() && pCharSet && pCharSet->Count() )
1567 {
1568 SwTextNode* pTextNd = pNode->GetTextNode();
1569 const SwIndex& rSt = pStt->nContent;
1570 sal_Int32 nMkPos, nPtPos = rSt.GetIndex();
1571 const OUString& rStr = pTextNd->GetText();
1572
1573 // Special case: if the Cursor is located within a URL attribute, we take over it's area
1574 SwTextAttr const*const pURLAttr(
1575 pTextNd->GetTextAttrAt(rSt.GetIndex(), RES_TXTATR_INETFMT));
1576 if (pURLAttr && !pURLAttr->GetINetFormat().GetValue().isEmpty())
1577 {
1578 nMkPos = pURLAttr->GetStart();
1579 nPtPos = *pURLAttr->End();
1580 }
1581 else
1582 {
1583 assert(g_pBreakIt && g_pBreakIt->GetBreakIter().is())(static_cast <bool> (g_pBreakIt && g_pBreakIt->
GetBreakIter().is()) ? void (0) : __assert_fail ("g_pBreakIt && g_pBreakIt->GetBreakIter().is()"
, "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 1583, __extension__ __PRETTY_FUNCTION__))
;
1584 Boundary aBndry = g_pBreakIt->GetBreakIter()->getWordBoundary(
1585 pTextNd->GetText(), nPtPos,
1586 g_pBreakIt->GetLocale( pTextNd->GetLang( nPtPos ) ),
1587 WordType::ANY_WORD /*ANYWORD_IGNOREWHITESPACES*/,
1588 true);
1589
1590 if( aBndry.startPos < nPtPos && nPtPos < aBndry.endPos )
1591 {
1592 nMkPos = aBndry.startPos;
1593 nPtPos = aBndry.endPos;
1594 }
1595 else
1596 nPtPos = nMkPos = rSt.GetIndex();
1597 }
1598
1599 // Remove the overriding attributes from the SwpHintsArray,
1600 // if the selection spans across the whole paragraph.
1601 // These attributes are inserted as FormatAttributes and
1602 // never override the TextAttributes!
1603 if( !(nFlags & SetAttrMode::DONTREPLACE ) &&
1604 pTextNd->HasHints() && !nMkPos && nPtPos == rStr.getLength())
1605 {
1606 SwIndex aSt( pTextNd );
1607 if( pHistory )
1608 {
1609 // Save all attributes for the Undo.
1610 SwRegHistory aRHst( *pTextNd, pHistory );
1611 pTextNd->GetpSwpHints()->Register( &aRHst );
1612 pTextNd->RstTextAttr( aSt, nPtPos, 0, pCharSet );
1613 if( pTextNd->GetpSwpHints() )
1614 pTextNd->GetpSwpHints()->DeRegister();
1615 }
1616 else
1617 pTextNd->RstTextAttr( aSt, nPtPos, 0, pCharSet );
1618 }
1619
1620 // the SwRegHistory inserts the attribute into the TextNode!
1621 SwRegHistory history( pNode, *pNode, pHistory );
1622 bRet = history.InsertItems( *pCharSet, nMkPos, nPtPos, nFlags, /*ppNewTextAttr*/nullptr )
1623 || bRet;
1624
1625 if( rDoc.getIDocumentRedlineAccess().IsRedlineOn() )
1626 {
1627 SwPaM aPam( *pNode, nMkPos, *pNode, nPtPos );
1628
1629 if( pUndo )
1630 pUndo->SaveRedlineData( aPam, false );
1631 rDoc.getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline( RedlineType::Format, aPam ), true);
1632 }
1633 }
1634 if( pOtherSet && pOtherSet->Count() )
1635 {
1636 // Need to check for unique item for DrawingLayer items of type NameOrIndex
1637 // and evtl. correct that item to ensure unique names for that type. This call may
1638 // modify/correct entries inside of the given SfxItemSet
1639 SfxItemSet aTempLocalCopy(*pOtherSet);
1640
1641 rDoc.CheckForUniqueItemForLineFillNameOrIndex(aTempLocalCopy);
1642 bRet = lcl_ApplyOtherSet(*pNode, pHistory, aTempLocalCopy, firstSet, propsSet, pLayout) || bRet;
1643 }
1644
1645 DELETECHARSETSif ( bDelete ) { delete pCharSet; delete pOtherSet; }
1646 return bRet;
1647 }
1648
1649 if( rDoc.getIDocumentRedlineAccess().IsRedlineOn() && pCharSet && pCharSet->Count() )
1650 {
1651 if( pUndo )
1652 pUndo->SaveRedlineData( rRg, false );
1653 rDoc.getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline( RedlineType::Format, rRg ), true);
1654 }
1655
1656 /* now if range */
1657 sal_uLong nNodes = 0;
1658
1659 SwNodeIndex aSt( rDoc.GetNodes() );
1660 SwNodeIndex aEnd( rDoc.GetNodes() );
1661 SwIndex aCntEnd( pEnd->nContent );
1662
1663 if( pNode )
1664 {
1665 const sal_Int32 nLen = pNode->Len();
1666 if( pStt->nNode != pEnd->nNode )
1667 aCntEnd.Assign( pNode, nLen );
1668
1669 if( pStt->nContent.GetIndex() != 0 || aCntEnd.GetIndex() != nLen )
1670 {
1671 // the SwRegHistory inserts the attribute into the TextNode!
1672 if( pNode->IsTextNode() && pCharSet && pCharSet->Count() )
1673 {
1674 SwRegHistory history( pNode, *pNode, pHistory );
1675 bRet = history.InsertItems(*pCharSet,
1676 pStt->nContent.GetIndex(), aCntEnd.GetIndex(), nFlags, /*ppNewTextAttr*/nullptr)
1677 || bRet;
1678 }
1679
1680 if( pOtherSet && pOtherSet->Count() )
1681 {
1682 bRet = lcl_ApplyOtherSet(*pNode, pHistory, *pOtherSet, firstSet, propsSet, pLayout) || bRet;
1683 }
1684
1685 // Only selection in a Node.
1686 if( pStt->nNode == pEnd->nNode )
1687 {
1688 //The data parameter flag: bExpandCharToPara, comes from the data member of SwDoc,
1689 //which is set in SW MS Word Binary filter WW8ImplRreader. With this flag on, means that
1690 //current setting attribute set is a character range properties set and comes from a MS Word
1691 //binary file, and the setting range include a paragraph end position (0X0D);
1692 //more specifications, as such property inside the character range properties set recorded in
1693 //MS Word binary file are dealt and inserted into data model (SwDoc) one by one, so we
1694 //only dealing the scenario that the char properties set with 1 item inside;
1695
1696 if (bExpandCharToPara && pCharSet && pCharSet->Count() ==1 )
1697 {
1698 SwTextNode* pCurrentNd = pStt->nNode.GetNode().GetTextNode();
1699
1700 if (pCurrentNd)
1701 {
1702 pCurrentNd->TryCharSetExpandToNum(*pCharSet);
1703
1704 }
1705 }
1706 DELETECHARSETSif ( bDelete ) { delete pCharSet; delete pOtherSet; }
1707 return bRet;
1708 }
1709 ++nNodes;
1710 aSt.Assign( pStt->nNode.GetNode(), +1 );
1711 }
1712 else
1713 aSt = pStt->nNode;
1714 aCntEnd = pEnd->nContent; // aEnd was changed!
1715 }
1716 else
1717 aSt.Assign( pStt->nNode.GetNode(), +1 );
1718
1719 // aSt points to the first full Node now
1720
1721 /*
1722 * The selection spans more than one Node.
1723 */
1724 if( pStt->nNode < pEnd->nNode )
1725 {
1726 pNode = pEnd->nNode.GetNode().GetContentNode();
1727 if(pNode)
1728 {
1729 if( aCntEnd.GetIndex() != pNode->Len() )
1730 {
1731 // the SwRegHistory inserts the attribute into the TextNode!
1732 if( pNode->IsTextNode() && pCharSet && pCharSet->Count() )
1733 {
1734 SwRegHistory history( pNode, *pNode, pHistory );
1735 (void)history.InsertItems(*pCharSet,
1736 0, aCntEnd.GetIndex(), nFlags, /*ppNewTextAttr*/nullptr);
1737 }
1738
1739 if( pOtherSet && pOtherSet->Count() )
1740 {
1741 lcl_ApplyOtherSet(*pNode, pHistory, *pOtherSet, firstSet, propsSet, pLayout);
1742 }
1743
1744 ++nNodes;
1745 aEnd = pEnd->nNode;
1746 }
1747 else
1748 aEnd.Assign( pEnd->nNode.GetNode(), +1 );
1749 }
1750 else
1751 aEnd = pEnd->nNode;
1752 }
1753 else
1754 aEnd.Assign( pEnd->nNode.GetNode(), +1 );
1755
1756 // aEnd points BEHIND the last full node now
1757
1758 /* Edit the fully selected Nodes. */
1759 // Reset all attributes from the set!
1760 if( pCharSet && pCharSet->Count() && !( SetAttrMode::DONTREPLACE & nFlags ) )
1761 {
1762 ::sw::DocumentContentOperationsManager::ParaRstFormat aPara(
1763 pStt, pEnd, pHistory, pCharSet, pLayout);
1764 rDoc.GetNodes().ForEach( aSt, aEnd, ::sw::DocumentContentOperationsManager::lcl_RstTextAttr, &aPara );
1765 }
1766
1767 bool bCreateSwpHints = pCharSet && (
1768 SfxItemState::SET == pCharSet->GetItemState( RES_TXTATR_CHARFMT, false ) ||
1769 SfxItemState::SET == pCharSet->GetItemState( RES_TXTATR_INETFMT, false ) );
1770
1771 for (SwNodeIndex current = aSt; current < aEnd; ++current)
1772 {
1773 SwTextNode *const pTNd = current.GetNode().GetTextNode();
1774 if (!pTNd)
1775 continue;
1776
1777 if (pLayout && pLayout->IsHideRedlines()
1778 && pTNd->GetRedlineMergeFlag() == SwNode::Merge::Hidden)
1779 { // not really sure what to do here, but applying to hidden
1780 continue; // nodes doesn't make sense...
1781 }
1782
1783 if( pHistory )
1784 {
1785 SwRegHistory aRegH( pTNd, *pTNd, pHistory );
1786
1787 if (pCharSet && pCharSet->Count())
1788 {
1789 SwpHints *pSwpHints = bCreateSwpHints ? &pTNd->GetOrCreateSwpHints()
1790 : pTNd->GetpSwpHints();
1791 if( pSwpHints )
1792 pSwpHints->Register( &aRegH );
1793
1794 pTNd->SetAttr(*pCharSet, 0, pTNd->GetText().getLength(), nFlags);
1795 if( pSwpHints )
1796 pSwpHints->DeRegister();
1797 }
1798 }
1799 else
1800 {
1801 if (pCharSet && pCharSet->Count())
1802 pTNd->SetAttr(*pCharSet, 0, pTNd->GetText().getLength(), nFlags);
1803 }
1804 ++nNodes;
1805 }
1806
1807 if (pOtherSet && pOtherSet->Count())
1808 {
1809 for (; aSt < aEnd; ++aSt)
1810 {
1811 pNode = aSt.GetNode().GetContentNode();
1812 if (!pNode)
1813 continue;
1814
1815 lcl_ApplyOtherSet(*pNode, pHistory, *pOtherSet, firstSet, propsSet, pLayout, &aSt);
1816 ++nNodes;
1817 }
1818 }
1819
1820 //The data parameter flag: bExpandCharToPara, comes from the data member of SwDoc,
1821 //which is set in SW MS Word Binary filter WW8ImplRreader. With this flag on, means that
1822 //current setting attribute set is a character range properties set and comes from a MS Word
1823 //binary file, and the setting range include a paragraph end position (0X0D);
1824 //more specifications, as such property inside the character range properties set recorded in
1825 //MS Word binary file are dealt and inserted into data model (SwDoc) one by one, so we
1826 //only dealing the scenario that the char properties set with 1 item inside;
1827 if (bExpandCharToPara && pCharSet && pCharSet->Count() ==1)
1828 {
1829 SwPosition aStartPos (*rRg.Start());
1830 SwPosition aEndPos (*rRg.End());
1831
1832 if (aEndPos.nNode.GetNode().GetTextNode() && aEndPos.nContent != aEndPos.nNode.GetNode().GetTextNode()->Len())
1833 aEndPos.nNode--;
1834
1835 sal_uLong nStart = aStartPos.nNode.GetIndex();
1836 sal_uLong nEnd = aEndPos.nNode.GetIndex();
1837 for(; nStart <= nEnd; ++nStart)
1838 {
1839 SwNode* pNd = rDoc.GetNodes()[ nStart ];
1840 if (!pNd || !pNd->IsTextNode())
1841 continue;
1842 SwTextNode *pCurrentNd = pNd->GetTextNode();
1843 pCurrentNd->TryCharSetExpandToNum(*pCharSet);
1844 }
1845 }
1846
1847 DELETECHARSETSif ( bDelete ) { delete pCharSet; delete pOtherSet; }
1848 return (nNodes != 0) || bRet;
1849 }
1850}
1851
1852namespace sw
1853{
1854
1855namespace mark
1856{
1857 bool IsFieldmarkOverlap(SwPaM const& rPaM)
1858 {
1859 std::vector<std::pair<sal_uLong, sal_Int32>> Breaks;
1860 sw::CalcBreaks(Breaks, rPaM);
1861 return !Breaks.empty();
1862 }
1863}
1864
1865DocumentContentOperationsManager::DocumentContentOperationsManager( SwDoc& i_rSwdoc ) : m_rDoc( i_rSwdoc )
1866{
1867}
1868
1869/**
1870 * Checks if rStart..rEnd mark a range that makes sense to copy.
1871 *
1872 * IsMoveToFly means the copy is a move to create a fly
1873 * and so existing flys at the edge must not be copied.
1874 */
1875static bool IsEmptyRange(const SwPosition& rStart, const SwPosition& rEnd,
1876 SwCopyFlags const flags)
1877{
1878 if (rStart == rEnd)
7
Assuming the condition is false
8
Taking false branch
1879 { // check if a fly anchored there would be copied - then copy...
1880 return !IsDestroyFrameAnchoredAtChar(rStart, rStart, rEnd,
1881 (flags & SwCopyFlags::IsMoveToFly)
1882 ? DelContentType::WriterfilterHack|DelContentType::AllMask
1883 : DelContentType::AllMask);
1884 }
1885 else
1886 {
1887 return rEnd < rStart;
9
Returning value, which participates in a condition later
1888 }
1889}
1890
1891// Copy an area into this document or into another document
1892bool
1893DocumentContentOperationsManager::CopyRange( SwPaM& rPam, SwPosition& rPos,
1894 SwCopyFlags const flags) const
1895{
1896 const SwPosition *pStt = rPam.Start(), *pEnd = rPam.End();
1897
1898 SwDoc& rDoc = rPos.nNode.GetNode().GetDoc();
1899 bool bColumnSel = rDoc.IsClipBoard() && rDoc.IsColumnSelection();
1900
1901 // Catch if there's no copy to do
1902 if (!rPam.HasMark() || (IsEmptyRange(*pStt, *pEnd, flags) && !bColumnSel))
1903 return false;
1904
1905 // Prevent copying into Flys that are anchored in the source range
1906 if (&rDoc == &m_rDoc && (flags & SwCopyFlags::CheckPosInFly))
1907 {
1908 // Correct the Start-/EndNode
1909 sal_uLong nStt = pStt->nNode.GetIndex(),
1910 nEnd = pEnd->nNode.GetIndex(),
1911 nDiff = nEnd - nStt +1;
1912 SwNode* pNd = m_rDoc.GetNodes()[ nStt ];
1913 if( pNd->IsContentNode() && pStt->nContent.GetIndex() )
1914 {
1915 ++nStt;
1916 --nDiff;
1917 }
1918 if( (pNd = m_rDoc.GetNodes()[ nEnd ])->IsContentNode() &&
1919 static_cast<SwContentNode*>(pNd)->Len() != pEnd->nContent.GetIndex() )
1920 {
1921 --nEnd;
1922 --nDiff;
1923 }
1924 if( nDiff &&
1925 lcl_ChkFlyFly( rDoc, nStt, nEnd, rPos.nNode.GetIndex() ) )
1926 {
1927 return false;
1928 }
1929 }
1930
1931 SwPaM* pRedlineRange = nullptr;
1932 if( rDoc.getIDocumentRedlineAccess().IsRedlineOn() ||
1933 (!rDoc.getIDocumentRedlineAccess().IsIgnoreRedline() && !rDoc.getIDocumentRedlineAccess().GetRedlineTable().empty() ) )
1934 pRedlineRange = new SwPaM( rPos );
1935
1936 RedlineFlags eOld = rDoc.getIDocumentRedlineAccess().GetRedlineFlags();
1937
1938 bool bRet = false;
1939
1940 if( &rDoc != &m_rDoc )
1941 { // ordinary copy
1942 bRet = CopyImpl(rPam, rPos, flags & ~SwCopyFlags::CheckPosInFly, pRedlineRange);
1943 }
1944 else if( ! ( *pStt <= rPos && rPos < *pEnd &&
1945 ( pStt->nNode != pEnd->nNode ||
1946 !pStt->nNode.GetNode().IsTextNode() )) )
1947 {
1948 // Copy to a position outside of the area, or copy a single TextNode
1949 // Do an ordinary copy
1950 bRet = CopyImpl(rPam, rPos, flags & ~SwCopyFlags::CheckPosInFly, pRedlineRange);
1951 }
1952 else
1953 {
1954 // Copy the range in itself
1955 assert(!"mst: this is assumed to be dead code")(static_cast <bool> (!"mst: this is assumed to be dead code"
) ? void (0) : __assert_fail ("!\"mst: this is assumed to be dead code\""
, "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 1955, __extension__ __PRETTY_FUNCTION__))
;
1956 }
1957
1958 rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld );
1959 if( pRedlineRange )
1960 {
1961 if( rDoc.getIDocumentRedlineAccess().IsRedlineOn() )
1962 rDoc.getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline( RedlineType::Insert, *pRedlineRange ), true);
1963 else
1964 rDoc.getIDocumentRedlineAccess().SplitRedline( *pRedlineRange );
1965 delete pRedlineRange;
1966 }
1967
1968 return bRet;
1969}
1970
1971/// Delete a full Section of the NodeArray.
1972/// The passed Node is located somewhere in the designated Section.
1973void DocumentContentOperationsManager::DeleteSection( SwNode *pNode )
1974{
1975 assert(pNode && "Didn't pass a Node.")(static_cast <bool> (pNode && "Didn't pass a Node."
) ? void (0) : __assert_fail ("pNode && \"Didn't pass a Node.\""
, "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 1975, __extension__ __PRETTY_FUNCTION__))
;
1976
1977 SwStartNode* pSttNd = pNode->IsStartNode() ? static_cast<SwStartNode*>(pNode)
1978 : pNode->StartOfSectionNode();
1979 SwNodeIndex aSttIdx( *pSttNd ), aEndIdx( *pNode->EndOfSectionNode() );
1980
1981 // delete all Flys, Bookmarks, ...
1982 DelFlyInRange( aSttIdx, aEndIdx );
1983 m_rDoc.getIDocumentRedlineAccess().DeleteRedline( *pSttNd, true, RedlineType::Any );
1984 DelBookmarks(aSttIdx, aEndIdx);
1985
1986 {
1987 // move all Cursor/StackCursor/UnoCursor out of the to-be-deleted area
1988 SwNodeIndex aMvStt( aSttIdx, 1 );
1989 SwDoc::CorrAbs( aMvStt, aEndIdx, SwPosition( aSttIdx ), true );
1990 }
1991
1992 m_rDoc.GetNodes().DelNodes( aSttIdx, aEndIdx.GetIndex() - aSttIdx.GetIndex() + 1 );
1993}
1994
1995void DocumentContentOperationsManager::DeleteDummyChar(
1996 SwPosition const& rPos, sal_Unicode const cDummy)
1997{
1998 SwPaM aPam(rPos, rPos);
1999 ++aPam.GetPoint()->nContent;
2000 assert(aPam.GetText().getLength() == 1 && aPam.GetText()[0] == cDummy)(static_cast <bool> (aPam.GetText().getLength() == 1 &&
aPam.GetText()[0] == cDummy) ? void (0) : __assert_fail ("aPam.GetText().getLength() == 1 && aPam.GetText()[0] == cDummy"
, "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 2000, __extension__ __PRETTY_FUNCTION__))
;
2001 (void) cDummy;
2002
2003 DeleteRangeImpl(aPam);
2004
2005 if (!m_rDoc.getIDocumentRedlineAccess().IsIgnoreRedline()
2006 && !m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().empty())
2007 {
2008 m_rDoc.getIDocumentRedlineAccess().CompressRedlines();
2009 }
2010}
2011
2012void DocumentContentOperationsManager::DeleteRange( SwPaM & rPam )
2013{
2014 lcl_DoWithBreaks( *this, rPam, &DocumentContentOperationsManager::DeleteRangeImpl );
2015
2016 if (m_rDoc.getIDocumentRedlineAccess().IsRedlineOn())
2017 {
2018 rPam.Normalize(false); // tdf#127635 put point at the end of deletion
2019 }
2020
2021 if (!m_rDoc.getIDocumentRedlineAccess().IsIgnoreRedline()
2022 && !m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().empty())
2023 {
2024 m_rDoc.getIDocumentRedlineAccess().CompressRedlines();
2025 }
2026}
2027
2028bool DocumentContentOperationsManager::DelFullPara( SwPaM& rPam )
2029{
2030 const SwPosition &rStt = *rPam.Start(), &rEnd = *rPam.End();
2031 const SwNode* pNd = &rStt.nNode.GetNode();
2032 sal_uInt32 nSectDiff = pNd->StartOfSectionNode()->EndOfSectionIndex() -
2033 pNd->StartOfSectionIndex();
2034 sal_uInt32 nNodeDiff = rEnd.nNode.GetIndex() - rStt.nNode.GetIndex();
2035
2036 if ( nSectDiff-2 <= nNodeDiff || m_rDoc.getIDocumentRedlineAccess().IsRedlineOn() ||
2037 /* #i9185# Prevent getting the node after the end node (see below) */
2038 rEnd.nNode.GetIndex() + 1 == m_rDoc.GetNodes().Count() )
2039 {
2040 return false;
2041 }
2042
2043 {
2044 SwPaM temp(rPam, nullptr);
2045 if (!temp.HasMark())
2046 {
2047 temp.SetMark();
2048 }
2049 if (SwTextNode *const pNode = temp.Start()->nNode.GetNode().GetTextNode())
2050 { // rPam may not have nContent set but IsFieldmarkOverlap requires it
2051 pNode->MakeStartIndex(&temp.Start()->nContent);
2052 }
2053 if (SwTextNode *const pNode = temp.End()->nNode.GetNode().GetTextNode())
2054 {
2055 pNode->MakeEndIndex(&temp.End()->nContent);
2056 }
2057 if (sw::mark::IsFieldmarkOverlap(temp))
2058 { // a bit of a problem: we want to completely remove the nodes
2059 // but then how can the CH_TXT_ATR survive?
2060 return false;
2061 }
2062 }
2063
2064 // Move hard page brakes to the following Node.
2065 bool bSavePageBreak = false, bSavePageDesc = false;
2066
2067 /* #i9185# This would lead to a segmentation fault if not caught above. */
2068 sal_uLong nNextNd = rEnd.nNode.GetIndex() + 1;
2069 SwTableNode *const pTableNd = m_rDoc.GetNodes()[ nNextNd ]->GetTableNode();
2070
2071 if( pTableNd && pNd->IsContentNode() )
2072 {
2073 SwFrameFormat* pTableFormat = pTableNd->GetTable().GetFrameFormat();
2074
2075 {
2076 const SfxPoolItem *pItem;
2077 const SfxItemSet* pSet = static_cast<const SwContentNode*>(pNd)->GetpSwAttrSet();
2078 if( pSet && SfxItemState::SET == pSet->GetItemState( RES_PAGEDESC,
2079 false, &pItem ) )
2080 {
2081 pTableFormat->SetFormatAttr( *pItem );
2082 bSavePageDesc = true;
2083 }
2084
2085 if( pSet && SfxItemState::SET == pSet->GetItemState( RES_BREAK,
2086 false, &pItem ) )
2087 {
2088 pTableFormat->SetFormatAttr( *pItem );
2089 bSavePageBreak = true;
2090 }
2091 }
2092 }
2093
2094 bool const bDoesUndo = m_rDoc.GetIDocumentUndoRedo().DoesUndo();
2095 if( bDoesUndo )
2096 {
2097 if( !rPam.HasMark() )
2098 rPam.SetMark();
2099 else if( rPam.GetPoint() == &rStt )
2100 rPam.Exchange();
2101 rPam.GetPoint()->nNode++;
2102
2103 SwContentNode *pTmpNode = rPam.GetPoint()->nNode.GetNode().GetContentNode();
2104 rPam.GetPoint()->nContent.Assign( pTmpNode, 0 );
2105 bool bGoNext = (nullptr == pTmpNode);
2106 pTmpNode = rPam.GetMark()->nNode.GetNode().GetContentNode();
2107 rPam.GetMark()->nContent.Assign( pTmpNode, 0 );
2108
2109 m_rDoc.GetIDocumentUndoRedo().ClearRedo();
2110
2111 SwPaM aDelPam( *rPam.GetMark(), *rPam.GetPoint() );
2112 {
2113 SwPosition aTmpPos( *aDelPam.GetPoint() );
2114 if( bGoNext )
2115 {
2116 pTmpNode = m_rDoc.GetNodes().GoNext( &aTmpPos.nNode );
2117 aTmpPos.nContent.Assign( pTmpNode, 0 );
2118 }
2119 ::PaMCorrAbs( aDelPam, aTmpPos );
2120 }
2121
2122 std::unique_ptr<SwUndoDelete> pUndo(new SwUndoDelete( aDelPam, true ));
2123
2124 *rPam.GetPoint() = *aDelPam.GetPoint();
2125 pUndo->SetPgBrkFlags( bSavePageBreak, bSavePageDesc );
2126 m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::move(pUndo));
2127 rPam.DeleteMark();
2128 }
2129 else
2130 {
2131 SwNodeRange aRg( rStt.nNode, rEnd.nNode );
2132 rPam.Normalize(false);
2133
2134 // Try to move past the End
2135 if( !rPam.Move( fnMoveForward, GoInNode ) )
2136 {
2137 // Fair enough, at the Beginning then
2138 rPam.Exchange();
2139 if( !rPam.Move( fnMoveBackward, GoInNode ))
2140 {
2141 SAL_WARN("sw.core", "DelFullPara: no more Nodes")do { if (true) { 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() << "DelFullPara: no more Nodes"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"
), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
":" "2141" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "DelFullPara: no more Nodes"), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "DelFullPara: no more Nodes"; ::sal::detail::log( (
::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
":" "2141" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "DelFullPara: no more Nodes") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
":" "2141" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "DelFullPara: no more Nodes"), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "DelFullPara: no more Nodes"; ::sal::detail::log( (
::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
":" "2141" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
2142 return false;
2143 }
2144 }
2145 // move bookmarks, redlines etc.
2146 if (aRg.aStart == aRg.aEnd) // only first CorrAbs variant handles this
2147 {
2148 m_rDoc.CorrAbs( aRg.aStart, *rPam.GetPoint(), 0, true );
2149 }
2150 else
2151 {
2152 SwDoc::CorrAbs( aRg.aStart, aRg.aEnd, *rPam.GetPoint(), true );
2153 }
2154
2155 // What's with Flys?
2156 {
2157 // If there are FlyFrames left, delete these too
2158 for( size_t n = 0; n < m_rDoc.GetSpzFrameFormats()->size(); ++n )
2159 {
2160 SwFrameFormat* pFly = (*m_rDoc.GetSpzFrameFormats())[n];
2161 const SwFormatAnchor* pAnchor = &pFly->GetAnchor();
2162 SwPosition const*const pAPos = pAnchor->GetContentAnchor();
2163 if (pAPos &&
2164 ((RndStdIds::FLY_AT_PARA == pAnchor->GetAnchorId()) ||
2165 (RndStdIds::FLY_AT_CHAR == pAnchor->GetAnchorId())) &&
2166 // note: here use <= not < like in
2167 // IsDestroyFrameAnchoredAtChar() because of the increment
2168 // of rPam in the bDoesUndo path above!
2169 aRg.aStart <= pAPos->nNode && pAPos->nNode <= aRg.aEnd )
2170 {
2171 m_rDoc.getIDocumentLayoutAccess().DelLayoutFormat( pFly );
2172 --n;
2173 }
2174 }
2175 }
2176
2177 rPam.DeleteMark();
2178 m_rDoc.GetNodes().Delete( aRg.aStart, nNodeDiff+1 );
2179 }
2180 m_rDoc.getIDocumentState().SetModified();
2181
2182 return true;
2183}
2184
2185// #i100466# Add handling of new optional parameter <bForceJoinNext>
2186bool DocumentContentOperationsManager::DeleteAndJoin( SwPaM & rPam,
2187 const bool bForceJoinNext )
2188{
2189 if ( lcl_StrLenOverflow( rPam ) )
2190 return false;
2191
2192 bool const ret = lcl_DoWithBreaks( *this, rPam, (m_rDoc.getIDocumentRedlineAccess().IsRedlineOn())
2193 ? &DocumentContentOperationsManager::DeleteAndJoinWithRedlineImpl
2194 : &DocumentContentOperationsManager::DeleteAndJoinImpl,
2195 bForceJoinNext );
2196
2197 if (m_rDoc.getIDocumentRedlineAccess().IsRedlineOn())
2198 {
2199 rPam.Normalize(false); // tdf#127635 put point at the end of deletion
2200 }
2201
2202 return ret;
2203}
2204
2205// It seems that this is mostly used by SwDoc internals; the only
2206// way to call this from the outside seems to be the special case in
2207// SwDoc::CopyRange (but I have not managed to actually hit that case).
2208bool DocumentContentOperationsManager::MoveRange( SwPaM& rPaM, SwPosition& rPos, SwMoveFlags eMvFlags )
2209{
2210 // nothing moved: return
2211 const SwPosition *pStt = rPaM.Start(), *pEnd = rPaM.End();
2212 if( !rPaM.HasMark() || *pStt >= *pEnd || (*pStt <= rPos && rPos < *pEnd))
2213 return false;
2214
2215 assert(!sw::mark::IsFieldmarkOverlap(rPaM))(static_cast <bool> (!sw::mark::IsFieldmarkOverlap(rPaM
)) ? void (0) : __assert_fail ("!sw::mark::IsFieldmarkOverlap(rPaM)"
, "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 2215, __extension__ __PRETTY_FUNCTION__))
; // probably an invalid redline was created?
2216
2217 // Save the paragraph anchored Flys, so that they can be moved.
2218 SaveFlyArr aSaveFlyArr;
2219 SaveFlyInRange( rPaM, rPos, aSaveFlyArr, bool( SwMoveFlags::ALLFLYS & eMvFlags ) );
2220
2221 // save redlines (if DOC_MOVEREDLINES is used)
2222 SaveRedlines_t aSaveRedl;
2223 if( SwMoveFlags::REDLINES & eMvFlags && !m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().empty() )
2224 {
2225 lcl_SaveRedlines( rPaM, aSaveRedl );
2226
2227 // #i17764# unfortunately, code below relies on undos being
2228 // in a particular order, and presence of bookmarks
2229 // will change this order. Hence, we delete bookmarks
2230 // here without undo.
2231 ::sw::UndoGuard const undoGuard(m_rDoc.GetIDocumentUndoRedo());
2232 DelBookmarks(
2233 pStt->nNode,
2234 pEnd->nNode,
2235 nullptr,
2236 &pStt->nContent,
2237 &pEnd->nContent);
2238 }
2239
2240 bool bUpdateFootnote = false;
2241 SwFootnoteIdxs aTmpFntIdx;
2242
2243 std::unique_ptr<SwUndoMove> pUndoMove;
2244 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
2245 {
2246 m_rDoc.GetIDocumentUndoRedo().ClearRedo();
2247 pUndoMove.reset(new SwUndoMove( rPaM, rPos ));
2248 pUndoMove->SetMoveRedlines( eMvFlags == SwMoveFlags::REDLINES );
2249 }
2250 else
2251 {
2252 bUpdateFootnote = lcl_SaveFootnote( pStt->nNode, pEnd->nNode, rPos.nNode,
2253 m_rDoc.GetFootnoteIdxs(), aTmpFntIdx,
2254 &pStt->nContent, &pEnd->nContent );
2255 }
2256
2257 bool bSplit = false;
2258 SwPaM aSavePam( rPos, rPos );
2259
2260 // Move the SPoint to the beginning of the range
2261 if( rPaM.GetPoint() == pEnd )
2262 rPaM.Exchange();
2263
2264 // If there is a TextNode before and after the Move, create a JoinNext in the EditShell.
2265 SwTextNode* pSrcNd = rPaM.GetPoint()->nNode.GetNode().GetTextNode();
2266 bool bCorrSavePam = pSrcNd && pStt->nNode != pEnd->nNode;
2267
2268 // If one ore more TextNodes are moved, SwNodes::Move will do a SplitNode.
2269 // However, this does not update the cursor. So we create a TextNode to keep
2270 // updating the indices. After the Move the Node is optionally deleted.
2271 SwTextNode * pTNd = rPos.nNode.GetNode().GetTextNode();
2272 if( pTNd && rPaM.GetPoint()->nNode != rPaM.GetMark()->nNode &&
2273 ( rPos.nContent.GetIndex() || ( pTNd->Len() && bCorrSavePam )) )
2274 {
2275 bSplit = true;
2276 const sal_Int32 nMkContent = rPaM.GetMark()->nContent.GetIndex();
2277
2278 const std::shared_ptr<sw::mark::ContentIdxStore> pContentStore(sw::mark::ContentIdxStore::Create());
2279 pContentStore->Save( m_rDoc, rPos.nNode.GetIndex(), rPos.nContent.GetIndex(), true );
2280
2281 SwTextNode * pOrigNode = pTNd;
2282 assert(*aSavePam.GetPoint() == *aSavePam.GetMark() &&(static_cast <bool> (*aSavePam.GetPoint() == *aSavePam.
GetMark() && *aSavePam.GetPoint() == rPos) ? void (0)
: __assert_fail ("*aSavePam.GetPoint() == *aSavePam.GetMark() && *aSavePam.GetPoint() == rPos"
, "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 2283, __extension__ __PRETTY_FUNCTION__))
2283 *aSavePam.GetPoint() == rPos)(static_cast <bool> (*aSavePam.GetPoint() == *aSavePam.
GetMark() && *aSavePam.GetPoint() == rPos) ? void (0)
: __assert_fail ("*aSavePam.GetPoint() == *aSavePam.GetMark() && *aSavePam.GetPoint() == rPos"
, "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 2283, __extension__ __PRETTY_FUNCTION__))
;
2284 assert(aSavePam.GetPoint()->nContent.GetIdxReg() == pOrigNode)(static_cast <bool> (aSavePam.GetPoint()->nContent.GetIdxReg
() == pOrigNode) ? void (0) : __assert_fail ("aSavePam.GetPoint()->nContent.GetIdxReg() == pOrigNode"
, "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 2284, __extension__ __PRETTY_FUNCTION__))
;
2285 assert(aSavePam.GetPoint()->nNode == rPos.nNode.GetIndex())(static_cast <bool> (aSavePam.GetPoint()->nNode == rPos
.nNode.GetIndex()) ? void (0) : __assert_fail ("aSavePam.GetPoint()->nNode == rPos.nNode.GetIndex()"
, "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 2285, __extension__ __PRETTY_FUNCTION__))
;
2286 assert(rPos.nNode.GetIndex() == pOrigNode->GetIndex())(static_cast <bool> (rPos.nNode.GetIndex() == pOrigNode
->GetIndex()) ? void (0) : __assert_fail ("rPos.nNode.GetIndex() == pOrigNode->GetIndex()"
, "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 2286, __extension__ __PRETTY_FUNCTION__))
;
2287
2288 std::function<void (SwTextNode *, sw::mark::RestoreMode)> restoreFunc(
2289 [&](SwTextNode *const, sw::mark::RestoreMode const eMode)
2290 {
2291 if (!pContentStore->Empty())
2292 {
2293 pContentStore->Restore(m_rDoc, pOrigNode->GetIndex()-1, 0, true, eMode);
2294 }
2295 });
2296 pTNd = pTNd->SplitContentNode(rPos, &restoreFunc)->GetTextNode();
2297
2298 //A new node was inserted before the orig pTNd and the content up to
2299 //rPos moved into it. The old node is returned with the remainder
2300 //of the content in it.
2301 //
2302 //aSavePam was created with rPos, it continues to point to the
2303 //old node, but with the *original* content index into the node.
2304 //Seeing as all the orignode content before that index has
2305 //been removed, the new index into the original node should now be set
2306 //to 0 and the content index of rPos should also be adapted to the
2307 //truncated node
2308 assert(*aSavePam.GetPoint() == *aSavePam.GetMark() &&(static_cast <bool> (*aSavePam.GetPoint() == *aSavePam.
GetMark() && *aSavePam.GetPoint() == rPos) ? void (0)
: __assert_fail ("*aSavePam.GetPoint() == *aSavePam.GetMark() && *aSavePam.GetPoint() == rPos"
, "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 2309, __extension__ __PRETTY_FUNCTION__))
2309 *aSavePam.GetPoint() == rPos)(static_cast <bool> (*aSavePam.GetPoint() == *aSavePam.
GetMark() && *aSavePam.GetPoint() == rPos) ? void (0)
: __assert_fail ("*aSavePam.GetPoint() == *aSavePam.GetMark() && *aSavePam.GetPoint() == rPos"
, "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 2309, __extension__ __PRETTY_FUNCTION__))
;
2310 assert(aSavePam.GetPoint()->nContent.GetIdxReg() == pOrigNode)(static_cast <bool> (aSavePam.GetPoint()->nContent.GetIdxReg
() == pOrigNode) ? void (0) : __assert_fail ("aSavePam.GetPoint()->nContent.GetIdxReg() == pOrigNode"
, "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 2310, __extension__ __PRETTY_FUNCTION__))
;
2311 assert(aSavePam.GetPoint()->nNode == rPos.nNode.GetIndex())(static_cast <bool> (aSavePam.GetPoint()->nNode == rPos
.nNode.GetIndex()) ? void (0) : __assert_fail ("aSavePam.GetPoint()->nNode == rPos.nNode.GetIndex()"
, "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 2311, __extension__ __PRETTY_FUNCTION__))
;
2312 assert(rPos.nNode.GetIndex() == pOrigNode->GetIndex())(static_cast <bool> (rPos.nNode.GetIndex() == pOrigNode
->GetIndex()) ? void (0) : __assert_fail ("rPos.nNode.GetIndex() == pOrigNode->GetIndex()"
, "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 2312, __extension__ __PRETTY_FUNCTION__))
;
2313 aSavePam.GetPoint()->nContent.Assign(pOrigNode, 0);
2314 rPos = *aSavePam.GetMark() = *aSavePam.GetPoint();
2315
2316 // correct the PaM!
2317 if( rPos.nNode == rPaM.GetMark()->nNode )
2318 {
2319 rPaM.GetMark()->nNode = rPos.nNode.GetIndex()-1;
2320 rPaM.GetMark()->nContent.Assign( pTNd, nMkContent );
2321 }
2322 }
2323
2324 // Put back the Pam by one "content"; so that it's always outside of
2325 // the manipulated range.
2326 // tdf#99692 don't Move() back if that would end up in another node
2327 // because moving backward is not necessarily the inverse of forward then.
2328 // (but do Move() back if we have split the node)
2329 const bool bNullContent = !bSplit && aSavePam.GetPoint()->nContent == 0;
2330 if( bNullContent )
2331 {
2332 aSavePam.GetPoint()->nNode--;
2333 aSavePam.GetPoint()->nContent.Assign(aSavePam.GetContentNode(), 0);
2334 }
2335 else
2336 {
2337 bool const success(aSavePam.Move(fnMoveBackward, GoInContent));
2338 assert(success)(static_cast <bool> (success) ? void (0) : __assert_fail
("success", "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 2338, __extension__ __PRETTY_FUNCTION__))
;
2339 (void) success;
2340 }
2341
2342 // Copy all Bookmarks that are within the Move range into an array,
2343 // that saves the position as an offset.
2344 std::vector< ::sw::mark::SaveBookmark> aSaveBkmks;
2345 DelBookmarks(
2346 pStt->nNode,
2347 pEnd->nNode,
2348 &aSaveBkmks,
2349 &pStt->nContent,
2350 &pEnd->nContent);
2351
2352 // If there is no range anymore due to the above deletions (e.g. the
2353 // footnotes got deleted), it's still a valid Move!
2354 if( *rPaM.GetPoint() != *rPaM.GetMark() )
2355 {
2356 // now do the actual move
2357 m_rDoc.GetNodes().MoveRange( rPaM, rPos, m_rDoc.GetNodes() );
2358
2359 // after a MoveRange() the Mark is deleted
2360 if ( rPaM.HasMark() ) // => no Move occurred!
2361 {
2362 return false;
2363 }
2364 }
2365 else
2366 rPaM.DeleteMark();
2367
2368 OSL_ENSURE( *aSavePam.GetMark() == rPos ||do { if (true && (!(*aSavePam.GetMark() == rPos || ( aSavePam
.GetMark()->nNode.GetNode().GetContentNode() == nullptr ))
)) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
":" "2370" ": "), "%s", "PaM was not moved. Aren't there ContentNodes at the beginning/end?"
); } } while (false)
2369 ( aSavePam.GetMark()->nNode.GetNode().GetContentNode() == nullptr ),do { if (true && (!(*aSavePam.GetMark() == rPos || ( aSavePam
.GetMark()->nNode.GetNode().GetContentNode() == nullptr ))
)) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
":" "2370" ": "), "%s", "PaM was not moved. Aren't there ContentNodes at the beginning/end?"
); } } while (false)
2370 "PaM was not moved. Aren't there ContentNodes at the beginning/end?" )do { if (true && (!(*aSavePam.GetMark() == rPos || ( aSavePam
.GetMark()->nNode.GetNode().GetContentNode() == nullptr ))
)) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
":" "2370" ": "), "%s", "PaM was not moved. Aren't there ContentNodes at the beginning/end?"
); } } while (false)
;
2371 *aSavePam.GetMark() = rPos;
2372
2373 rPaM.SetMark(); // create a Sel. around the new range
2374 pTNd = aSavePam.GetNode().GetTextNode();
2375 assert(!m_rDoc.GetIDocumentUndoRedo().DoesUndo())(static_cast <bool> (!m_rDoc.GetIDocumentUndoRedo().DoesUndo
()) ? void (0) : __assert_fail ("!m_rDoc.GetIDocumentUndoRedo().DoesUndo()"
, "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 2375, __extension__ __PRETTY_FUNCTION__))
;
2376 bool bRemove = true;
2377 // Do two Nodes have to be joined at the SavePam?
2378 if (bSplit && pTNd)
2379 {
2380 if (pTNd->CanJoinNext())
2381 {
2382 // Always join next, because <pTNd> has to stay as it is.
2383 // A join previous from its next would more or less delete <pTNd>
2384 pTNd->JoinNext();
2385 bRemove = false;
2386 }
2387 }
2388 if (bNullContent)
2389 {
2390 aSavePam.GetPoint()->nNode++;
2391 aSavePam.GetPoint()->nContent.Assign( aSavePam.GetContentNode(), 0 );
2392 }
2393 else if (bRemove) // No move forward after joining with next paragraph
2394 {
2395 aSavePam.Move( fnMoveForward, GoInContent );
2396 }
2397
2398 // Insert the Bookmarks back into the Document.
2399 *rPaM.GetMark() = *aSavePam.Start();
2400 for(auto& rBkmk : aSaveBkmks)
2401 rBkmk.SetInDoc(
2402 &m_rDoc,
2403 rPaM.GetMark()->nNode,
2404 &rPaM.GetMark()->nContent);
2405 *rPaM.GetPoint() = *aSavePam.End();
2406
2407 // Move the Flys to the new position.
2408 // note: rPos is at the end here; can't really tell flys that used to be
2409 // at the start of rPam from flys that used to be at the end of rPam
2410 // unfortunately, so some of them are going to end up with wrong anchor...
2411 RestFlyInRange( aSaveFlyArr, *rPaM.Start(), &(rPos.nNode) );
2412
2413 // restore redlines (if DOC_MOVEREDLINES is used)
2414 if( !aSaveRedl.empty() )
2415 {
2416 lcl_RestoreRedlines( m_rDoc, *aSavePam.Start(), aSaveRedl );
2417 }
2418
2419 if( bUpdateFootnote )
2420 {
2421 if( !aTmpFntIdx.empty() )
2422 {
2423 m_rDoc.GetFootnoteIdxs().insert( aTmpFntIdx );
2424 aTmpFntIdx.clear();
2425 }
2426
2427 m_rDoc.GetFootnoteIdxs().UpdateAllFootnote();
2428 }
2429
2430 m_rDoc.getIDocumentState().SetModified();
2431 return true;
2432}
2433
2434bool DocumentContentOperationsManager::MoveNodeRange( SwNodeRange& rRange, SwNodeIndex& rPos,
2435 SwMoveFlags eMvFlags )
2436{
2437 std::vector<SwNode*> aFoldedOutlineNdsArray;
2438 SwWrtShell* pWrtShell = dynamic_cast<SwWrtShell*>(m_rDoc.GetEditShell());
2439 if (pWrtShell && pWrtShell->GetViewOptions() && pWrtShell->GetViewOptions()->IsShowOutlineContentVisibilityButton())
2440 {
2441 // unfold all folded outline content
2442 SwOutlineNodes rOutlineNds = m_rDoc.GetNodes().GetOutLineNds();
2443 for (SwOutlineNodes::size_type nPos = 0; nPos < rOutlineNds.size(); ++nPos)
2444 {
2445 SwNode* pNd = rOutlineNds[nPos];
2446 if (pNd->IsTextNode()) // should always be true
2447 {
2448 bool bOutlineContentVisibleAttr = true;
2449 pNd->GetTextNode()->GetAttrOutlineContentVisible(bOutlineContentVisibleAttr);
2450 if (!bOutlineContentVisibleAttr)
2451 {
2452 aFoldedOutlineNdsArray.push_back(pNd);
2453 pWrtShell->ToggleOutlineContentVisibility(nPos);
2454 }
2455 }
2456 }
2457 }
2458 // Moves all Nodes to the new position.
2459 // Bookmarks are moved too (currently without Undo support).
2460
2461 // If footnotes are being moved to the special section, remove them now.
2462
2463 // Or else delete the Frames for all footnotes that are being moved
2464 // and have it rebuild after the Move (footnotes can change pages).
2465 // Additionally we have to correct the FootnoteIdx array's sorting.
2466 bool bUpdateFootnote = false;
2467 SwFootnoteIdxs aTmpFntIdx;
2468
2469 std::unique_ptr<SwUndoMove> pUndo;
2470 if ((SwMoveFlags::CREATEUNDOOBJ & eMvFlags ) && m_rDoc.GetIDocumentUndoRedo().DoesUndo())
2471 {
2472 pUndo.reset(new SwUndoMove( m_rDoc, rRange, rPos ));
2473 }
2474 else
2475 {
2476 bUpdateFootnote = lcl_SaveFootnote( rRange.aStart, rRange.aEnd, rPos,
2477 m_rDoc.GetFootnoteIdxs(), aTmpFntIdx );
2478 }
2479
2480 SaveRedlines_t aSaveRedl;
2481 std::vector<SwRangeRedline*> aSavRedlInsPosArr;
2482 if( SwMoveFlags::REDLINES & eMvFlags && !m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().empty() )
2483 {
2484 lcl_SaveRedlines( rRange, aSaveRedl );
2485
2486 // Find all RedLines that end at the InsPos.
2487 // These have to be moved back to the "old" position after the Move.
2488 SwRedlineTable::size_type nRedlPos = m_rDoc.getIDocumentRedlineAccess().GetRedlinePos( rPos.GetNode(), RedlineType::Any );
2489 if( SwRedlineTable::npos != nRedlPos )
2490 {
2491 const SwPosition *pRStt, *pREnd;
2492 do {
2493 SwRangeRedline* pTmp = m_rDoc.getIDocumentRedlineAccess().GetRedlineTable()[ nRedlPos ];
2494 pRStt = pTmp->Start();
2495 pREnd = pTmp->End();
2496 if( pREnd->nNode == rPos && pRStt->nNode < rPos )
2497 {
2498 aSavRedlInsPosArr.push_back( pTmp );
2499 }
2500 } while( pRStt->nNode < rPos && ++nRedlPos < m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().size());
2501 }
2502 }
2503
2504 // Copy all Bookmarks that are within the Move range into an array
2505 // that stores all references to positions as an offset.
2506 // The final mapping happens after the Move.
2507 std::vector< ::sw::mark::SaveBookmark> aSaveBkmks;
2508 DelBookmarks(rRange.aStart, rRange.aEnd, &aSaveBkmks);
2509
2510 // Save the paragraph-bound Flys, so that they can be moved.
2511 SaveFlyArr aSaveFlyArr;
2512 if( !m_rDoc.GetSpzFrameFormats()->empty() )
2513 SaveFlyInRange( rRange, aSaveFlyArr );
2514
2515 // Set it to before the Position, so that it cannot be moved further.
2516 SwNodeIndex aIdx( rPos, -1 );
2517
2518 std::unique_ptr<SwNodeIndex> pSaveInsPos;
2519 if( pUndo )
2520 pSaveInsPos.reset(new SwNodeIndex( rRange.aStart, -1 ));
2521
2522 // move the Nodes
2523 bool bNoDelFrames = bool(SwMoveFlags::NO_DELFRMS & eMvFlags);
2524 if( m_rDoc.GetNodes().MoveNodes( rRange, m_rDoc.GetNodes(), rPos, !bNoDelFrames ) )
2525 {
2526 ++aIdx; // again back to old position
2527 if( pSaveInsPos )
2528 ++(*pSaveInsPos);
2529 }
2530 else
2531 {
2532 aIdx = rRange.aStart;
2533 pUndo.reset();
2534 }
2535
2536 // move the Flys to the new position
2537 if( !aSaveFlyArr.empty() )
2538 {
2539 SwPosition const tmp(aIdx);
2540 RestFlyInRange(aSaveFlyArr, tmp, nullptr);
2541 }
2542
2543 // Add the Bookmarks back to the Document
2544 for(auto& rBkmk : aSaveBkmks)
2545 rBkmk.SetInDoc(&m_rDoc, aIdx);
2546
2547 if( !aSavRedlInsPosArr.empty() )
2548 {
2549 SwNode* pNewNd = &aIdx.GetNode();
2550 for(SwRangeRedline* pTmp : aSavRedlInsPosArr)
2551 {
2552 if( m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().Contains( pTmp ) )
2553 {
2554 SwPosition* pEnd = pTmp->End();
2555 pEnd->nNode = aIdx;
2556 pEnd->nContent.Assign( pNewNd->GetContentNode(), 0 );
2557 }
2558 }
2559 }
2560
2561 if( !aSaveRedl.empty() )
2562 lcl_RestoreRedlines( m_rDoc, aIdx.GetIndex(), aSaveRedl );
2563
2564 if( pUndo )
2565 {
2566 pUndo->SetDestRange( aIdx, rPos, *pSaveInsPos );
2567 m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::move(pUndo));
2568 }
2569
2570 pSaveInsPos.reset();
2571
2572 if( bUpdateFootnote )
2573 {
2574 if( !aTmpFntIdx.empty() )
2575 {
2576 m_rDoc.GetFootnoteIdxs().insert( aTmpFntIdx );
2577 aTmpFntIdx.clear();
2578 }
2579
2580 m_rDoc.GetFootnoteIdxs().UpdateAllFootnote();
2581 }
2582
2583 if (pWrtShell && pWrtShell->GetViewOptions() && pWrtShell->GetViewOptions()->IsShowOutlineContentVisibilityButton())
2584 {
2585 // fold all outlines that were folded before move
2586 for (SwNode* pNd : aFoldedOutlineNdsArray)
2587 pWrtShell->ToggleOutlineContentVisibility(pNd, true);
2588 }
2589
2590 m_rDoc.getIDocumentState().SetModified();
2591 return true;
2592}
2593
2594bool DocumentContentOperationsManager::MoveAndJoin( SwPaM& rPaM, SwPosition& rPos )
2595{
2596 SwNodeIndex aIdx( rPaM.Start()->nNode );
2597 bool bJoinText = aIdx.GetNode().IsTextNode();
2598 bool bOneNode = rPaM.GetPoint()->nNode == rPaM.GetMark()->nNode;
2599 aIdx--; // in front of the move area!
2600
2601 bool bRet = MoveRange( rPaM, rPos, SwMoveFlags::DEFAULT );
2602 if( bRet && !bOneNode )
2603 {
2604 if( bJoinText )
2605 ++aIdx;
2606 SwTextNode * pTextNd = aIdx.GetNode().GetTextNode();
2607 SwNodeIndex aNxtIdx( aIdx );
2608 if( pTextNd && pTextNd->CanJoinNext( &aNxtIdx ) )
2609 {
2610 { // Block so SwIndex into node is deleted before Join
2611 m_rDoc.CorrRel( aNxtIdx, SwPosition( aIdx, SwIndex(pTextNd,
2612 pTextNd->GetText().getLength()) ), 0, true );
2613 }
2614 pTextNd->JoinNext();
2615 }
2616 }
2617 return bRet;
2618}
2619
2620// Overwrite only uses the point of the PaM, the mark is ignored; characters
2621// are replaced from point until the end of the node; at the end of the node,
2622// characters are inserted.
2623bool DocumentContentOperationsManager::Overwrite( const SwPaM &rRg, const OUString &rStr )
2624{
2625 assert(rStr.getLength())(static_cast <bool> (rStr.getLength()) ? void (0) : __assert_fail
("rStr.getLength()", "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 2625, __extension__ __PRETTY_FUNCTION__))
;
2626 SwPosition& rPt = *const_cast<SwPosition*>(rRg.GetPoint());
2627 if( m_rDoc.GetAutoCorrExceptWord() ) // Add to AutoCorrect
2628 {
2629 if( 1 == rStr.getLength() )
2630 m_rDoc.GetAutoCorrExceptWord()->CheckChar( rPt, rStr[ 0 ] );
2631 m_rDoc.DeleteAutoCorrExceptWord();
2632 }
2633
2634 SwTextNode *pNode = rPt.nNode.GetNode().GetTextNode();
2635 if (!pNode || rStr.getLength() > pNode->GetSpaceLeft()) // worst case: no erase
2636 {
2637 return false;
2638 }
2639
2640 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
2641 {
2642 m_rDoc.GetIDocumentUndoRedo().ClearRedo(); // AppendUndo not always called
2643 }
2644
2645 const size_t nOldAttrCnt = pNode->GetpSwpHints()
2646 ? pNode->GetpSwpHints()->Count() : 0;
2647 SwDataChanged aTmp( rRg );
2648 SwIndex& rIdx = rPt.nContent;
2649 sal_Int32 const nActualStart(rIdx.GetIndex());
2650 sal_Int32 nStart = 0;
2651
2652 bool bOldExpFlg = pNode->IsIgnoreDontExpand();
2653 pNode->SetIgnoreDontExpand( true );
2654
2655 for( sal_Int32 nCnt = 0; nCnt < rStr.getLength(); ++nCnt )
2656 {
2657 // start behind the characters (to fix the attributes!)
2658 nStart = rIdx.GetIndex();
2659 if (nStart < pNode->GetText().getLength())
2660 {
2661 lcl_SkipAttr( pNode, rIdx, nStart );
2662 }
2663 sal_Unicode c = rStr[ nCnt ];
2664 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
2665 {
2666 bool bMerged(false);
2667 if (m_rDoc.GetIDocumentUndoRedo().DoesGroupUndo())
2668 {
2669 SwUndo *const pUndo = m_rDoc.GetUndoManager().GetLastUndo();
2670 SwUndoOverwrite *const pUndoOW(
2671 dynamic_cast<SwUndoOverwrite *>(pUndo) );
2672 if (pUndoOW)
2673 {
2674 // if CanGrouping() returns true it's already merged
2675 bMerged = pUndoOW->CanGrouping(m_rDoc, rPt, c);
2676 }
2677 }
2678 if (!bMerged)
2679 {
2680 m_rDoc.GetIDocumentUndoRedo().AppendUndo(
2681 std::make_unique<SwUndoOverwrite>(m_rDoc, rPt, c) );
2682 }
2683 }
2684 else
2685 {
2686 // start behind the characters (to fix the attributes!)
2687 if (nStart < pNode->GetText().getLength())
2688 ++rIdx;
2689 pNode->InsertText( OUString(c), rIdx, SwInsertFlags::EMPTYEXPAND );
2690 if( nStart+1 < rIdx.GetIndex() )
2691 {
2692 rIdx = nStart;
2693 pNode->EraseText( rIdx, 1 );
2694 ++rIdx;
2695 }
2696 }
2697 }
2698 pNode->SetIgnoreDontExpand( bOldExpFlg );
2699
2700 const size_t nNewAttrCnt = pNode->GetpSwpHints()
2701 ? pNode->GetpSwpHints()->Count() : 0;
2702 if( nOldAttrCnt != nNewAttrCnt )
2703 {
2704 SwUpdateAttr aHint(0,0,0);
2705 pNode->ModifyBroadcast(nullptr, &aHint);
2706 }
2707
2708 if (!m_rDoc.GetIDocumentUndoRedo().DoesUndo() &&
2709 !m_rDoc.getIDocumentRedlineAccess().IsIgnoreRedline() && !m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().empty())
2710 {
2711 SwPaM aPam(rPt.nNode, nActualStart, rPt.nNode, rPt.nContent.GetIndex());
2712 m_rDoc.getIDocumentRedlineAccess().DeleteRedline( aPam, true, RedlineType::Any );
2713 }
2714 else if( m_rDoc.getIDocumentRedlineAccess().IsRedlineOn() )
2715 {
2716 // FIXME: this redline is WRONG: there is no DELETE, and the skipped
2717 // characters are also included in aPam
2718 SwPaM aPam(rPt.nNode, nActualStart, rPt.nNode, rPt.nContent.GetIndex());
2719 m_rDoc.getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline( RedlineType::Insert, aPam ), true);
2720 }
2721
2722 m_rDoc.getIDocumentState().SetModified();
2723 return true;
2724}
2725
2726bool DocumentContentOperationsManager::InsertString( const SwPaM &rRg, const OUString &rStr,
2727 const SwInsertFlags nInsertMode )
2728{
2729 // tdf#119019 accept tracked paragraph formatting to do not hide new insertions
2730 if( m_rDoc.getIDocumentRedlineAccess().IsRedlineOn() )
2731 {
2732 RedlineFlags eOld = m_rDoc.getIDocumentRedlineAccess().GetRedlineFlags();
2733 m_rDoc.getIDocumentRedlineAccess().AcceptRedlineParagraphFormatting( rRg );
2734 if (eOld != m_rDoc.getIDocumentRedlineAccess().GetRedlineFlags())
2735 m_rDoc.getIDocumentRedlineAccess().SetRedlineFlags( eOld );
2736 }
2737
2738 // fetching DoesUndo is surprisingly expensive
2739 bool bDoesUndo = m_rDoc.GetIDocumentUndoRedo().DoesUndo();
2740 if (bDoesUndo)
2741 m_rDoc.GetIDocumentUndoRedo().ClearRedo(); // AppendUndo not always called!
2742
2743 const SwPosition& rPos = *rRg.GetPoint();
2744
2745 if( m_rDoc.GetAutoCorrExceptWord() ) // add to auto correction
2746 {
2747 if( 1 == rStr.getLength() && m_rDoc.GetAutoCorrExceptWord()->IsDeleted() )
2748 {
2749 m_rDoc.GetAutoCorrExceptWord()->CheckChar( rPos, rStr[ 0 ] );
2750 }
2751 m_rDoc.DeleteAutoCorrExceptWord();
2752 }
2753
2754 SwTextNode *const pNode = rPos.nNode.GetNode().GetTextNode();
2755 if(!pNode)
2756 return false;
2757
2758 SwDataChanged aTmp( rRg );
2759
2760 if (!bDoesUndo || !m_rDoc.GetIDocumentUndoRedo().DoesGroupUndo())
2761 {
2762 OUString const ins(pNode->InsertText(rStr, rPos.nContent, nInsertMode));
2763 if (bDoesUndo)
2764 {
2765 m_rDoc.GetIDocumentUndoRedo().AppendUndo(
2766 std::make_unique<SwUndoInsert>(rPos.nNode,
2767 rPos.nContent.GetIndex(), ins.getLength(), nInsertMode));
2768 }
2769 }
2770 else
2771 { // if Undo and grouping is enabled, everything changes!
2772 SwUndoInsert * pUndo = nullptr;
2773
2774 // don't group the start if hints at the start should be expanded
2775 if (!(nInsertMode & SwInsertFlags::FORCEHINTEXPAND))
2776 {
2777 SwUndo *const pLastUndo = m_rDoc.GetUndoManager().GetLastUndo();
2778 SwUndoInsert *const pUndoInsert(
2779 dynamic_cast<SwUndoInsert *>(pLastUndo) );
2780 if (pUndoInsert && pUndoInsert->CanGrouping(rPos))
2781 {
2782 pUndo = pUndoInsert;
2783 }
2784 }
2785
2786 CharClass const& rCC = GetAppCharClass();
2787 sal_Int32 nInsPos = rPos.nContent.GetIndex();
2788
2789 if (!pUndo)
2790 {
2791 pUndo = new SwUndoInsert( rPos.nNode, nInsPos, 0, nInsertMode,
2792 !rCC.isLetterNumeric( rStr, 0 ) );
2793 m_rDoc.GetIDocumentUndoRedo().AppendUndo( std::unique_ptr<SwUndo>(pUndo) );
2794 }
2795
2796 OUString const ins(pNode->InsertText(rStr, rPos.nContent, nInsertMode));
2797
2798 for (sal_Int32 i = 0; i < ins.getLength(); ++i)
2799 {
2800 nInsPos++;
2801 // if CanGrouping() returns true, everything has already been done
2802 if (!pUndo->CanGrouping(ins[i]))
2803 {
2804 pUndo = new SwUndoInsert(rPos.nNode, nInsPos, 1, nInsertMode,
2805 !rCC.isLetterNumeric(ins, i));
2806 m_rDoc.GetIDocumentUndoRedo().AppendUndo( std::unique_ptr<SwUndo>(pUndo) );
2807 }
2808 }
2809 }
2810
2811 // To-Do - add 'SwExtraRedlineTable' also ?
2812 if( m_rDoc.getIDocumentRedlineAccess().IsRedlineOn() || (!m_rDoc.getIDocumentRedlineAccess().IsIgnoreRedline() && !m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().empty() ))
2813 {
2814 SwPaM aPam( rPos.nNode, aTmp.GetContent(),
2815 rPos.nNode, rPos.nContent.GetIndex());
2816 if( m_rDoc.getIDocumentRedlineAccess().IsRedlineOn() )
2817 {
2818 m_rDoc.getIDocumentRedlineAccess().AppendRedline(
2819 new SwRangeRedline( RedlineType::Insert, aPam ), true);
2820 }
2821 else
2822 {
2823 m_rDoc.getIDocumentRedlineAccess().SplitRedline( aPam );
2824 }
2825 }
2826
2827 m_rDoc.getIDocumentState().SetModified();
2828 return true;
2829}
2830
2831void DocumentContentOperationsManager::TransliterateText(
2832 const SwPaM& rPaM,
2833 utl::TransliterationWrapper& rTrans )
2834{
2835 std::unique_ptr<SwUndoTransliterate> pUndo;
2836 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
2837 pUndo.reset(new SwUndoTransliterate( rPaM, rTrans ));
2838
2839 const SwPosition* pStt = rPaM.Start(),
2840 * pEnd = rPaM.End();
2841 sal_uLong nSttNd = pStt->nNode.GetIndex(),
2842 nEndNd = pEnd->nNode.GetIndex();
2843 sal_Int32 nSttCnt = pStt->nContent.GetIndex();
2844 sal_Int32 nEndCnt = pEnd->nContent.GetIndex();
2845
2846 SwTextNode* pTNd = pStt->nNode.GetNode().GetTextNode();
2847 if( pStt == pEnd && pTNd ) // no selection?
2848 {
2849 // set current word as 'area of effect'
2850
2851 assert(g_pBreakIt && g_pBreakIt->GetBreakIter().is())(static_cast <bool> (g_pBreakIt && g_pBreakIt->
GetBreakIter().is()) ? void (0) : __assert_fail ("g_pBreakIt && g_pBreakIt->GetBreakIter().is()"
, "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 2851, __extension__ __PRETTY_FUNCTION__))
;
2852 Boundary aBndry = g_pBreakIt->GetBreakIter()->getWordBoundary(
2853 pTNd->GetText(), nSttCnt,
2854 g_pBreakIt->GetLocale( pTNd->GetLang( nSttCnt ) ),
2855 WordType::ANY_WORD /*ANYWORD_IGNOREWHITESPACES*/,
2856 true);
2857
2858 if( aBndry.startPos < nSttCnt && nSttCnt < aBndry.endPos )
2859 {
2860 nSttCnt = aBndry.startPos;
2861 nEndCnt = aBndry.endPos;
2862 }
2863 }
2864
2865 if( nSttNd != nEndNd ) // is more than one text node involved?
2866 {
2867 // iterate over all effected text nodes, the first and the last one
2868 // may be incomplete because the selection starts and/or ends there
2869
2870 SwNodeIndex aIdx( pStt->nNode );
2871 if( nSttCnt )
2872 {
2873 ++aIdx;
2874 if( pTNd )
2875 pTNd->TransliterateText(
2876 rTrans, nSttCnt, pTNd->GetText().getLength(), pUndo.get());
2877 }
2878
2879 for( ; aIdx.GetIndex() < nEndNd; ++aIdx )
2880 {
2881 pTNd = aIdx.GetNode().GetTextNode();
2882 if (pTNd)
2883 {
2884 pTNd->TransliterateText(
2885 rTrans, 0, pTNd->GetText().getLength(), pUndo.get());
2886 }
2887 }
2888
2889 if( nEndCnt && nullptr != ( pTNd = pEnd->nNode.GetNode().GetTextNode() ))
2890 pTNd->TransliterateText( rTrans, 0, nEndCnt, pUndo.get() );
2891 }
2892 else if( pTNd && nSttCnt < nEndCnt )
2893 pTNd->TransliterateText( rTrans, nSttCnt, nEndCnt, pUndo.get() );
2894
2895 if( pUndo && pUndo->HasData() )
2896 {
2897 m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::move(pUndo));
2898 }
2899 m_rDoc.getIDocumentState().SetModified();
2900}
2901
2902SwFlyFrameFormat* DocumentContentOperationsManager::InsertGraphic(
2903 const SwPaM &rRg,
2904 const OUString& rGrfName,
2905 const OUString& rFltName,
2906 const Graphic* pGraphic,
2907 const SfxItemSet* pFlyAttrSet,
2908 const SfxItemSet* pGrfAttrSet,
2909 SwFrameFormat* pFrameFormat )
2910{
2911 if( !pFrameFormat )
2912 pFrameFormat = m_rDoc.getIDocumentStylePoolAccess().GetFrameFormatFromPool( RES_POOLFRM_GRAPHIC );
2913 SwGrfNode* pSwGrfNode = SwNodes::MakeGrfNode(
2914 SwNodeIndex( m_rDoc.GetNodes().GetEndOfAutotext() ),
2915 rGrfName, rFltName, pGraphic,
2916 m_rDoc.GetDfltGrfFormatColl() );
2917 SwFlyFrameFormat* pSwFlyFrameFormat = InsNoTextNode( *rRg.GetPoint(), pSwGrfNode,
2918 pFlyAttrSet, pGrfAttrSet, pFrameFormat );
2919 return pSwFlyFrameFormat;
2920}
2921
2922SwFlyFrameFormat* DocumentContentOperationsManager::InsertGraphicObject(
2923 const SwPaM &rRg, const GraphicObject& rGrfObj,
2924 const SfxItemSet* pFlyAttrSet,
2925 const SfxItemSet* pGrfAttrSet )
2926{
2927 SwFrameFormat* pFrameFormat = m_rDoc.getIDocumentStylePoolAccess().GetFrameFormatFromPool( RES_POOLFRM_GRAPHIC );
2928 SwGrfNode* pSwGrfNode = SwNodes::MakeGrfNode(
2929 SwNodeIndex( m_rDoc.GetNodes().GetEndOfAutotext() ),
2930 rGrfObj, m_rDoc.GetDfltGrfFormatColl() );
2931 SwFlyFrameFormat* pSwFlyFrameFormat = InsNoTextNode( *rRg.GetPoint(), pSwGrfNode,
2932 pFlyAttrSet, pGrfAttrSet, pFrameFormat );
2933 return pSwFlyFrameFormat;
2934}
2935
2936SwFlyFrameFormat* DocumentContentOperationsManager::InsertEmbObject(
2937 const SwPaM &rRg, const svt::EmbeddedObjectRef& xObj,
2938 SfxItemSet* pFlyAttrSet)
2939{
2940 sal_uInt16 nId = RES_POOLFRM_OLE;
2941 if (xObj.is())
2942 {
2943 SvGlobalName aClassName( xObj->getClassID() );
2944 if (SotExchange::IsMath(aClassName))
2945 {
2946 nId = RES_POOLFRM_FORMEL;
2947 }
2948 }
2949
2950 SwFrameFormat* pFrameFormat = m_rDoc.getIDocumentStylePoolAccess().GetFrameFormatFromPool( nId );
2951
2952 return InsNoTextNode( *rRg.GetPoint(), m_rDoc.GetNodes().MakeOLENode(
2953 SwNodeIndex( m_rDoc.GetNodes().GetEndOfAutotext() ),
2954 xObj,
2955 m_rDoc.GetDfltGrfFormatColl() ),
2956 pFlyAttrSet, nullptr,
2957 pFrameFormat );
2958}
2959
2960SwFlyFrameFormat* DocumentContentOperationsManager::InsertOLE(const SwPaM &rRg, const OUString& rObjName,
2961 sal_Int64 nAspect,
2962 const SfxItemSet* pFlyAttrSet,
2963 const SfxItemSet* pGrfAttrSet)
2964{
2965 SwFrameFormat* pFrameFormat = m_rDoc.getIDocumentStylePoolAccess().GetFrameFormatFromPool( RES_POOLFRM_OLE );
2966
2967 return InsNoTextNode( *rRg.GetPoint(),
2968 m_rDoc.GetNodes().MakeOLENode(
2969 SwNodeIndex( m_rDoc.GetNodes().GetEndOfAutotext() ),
2970 rObjName,
2971 nAspect,
2972 m_rDoc.GetDfltGrfFormatColl(),
2973 nullptr ),
2974 pFlyAttrSet, pGrfAttrSet,
2975 pFrameFormat );
2976}
2977
2978void DocumentContentOperationsManager::ReRead( SwPaM& rPam, const OUString& rGrfName,
2979 const OUString& rFltName, const Graphic* pGraphic )
2980{
2981 SwGrfNode *pGrfNd;
2982 if( !(( !rPam.HasMark()
2983 || rPam.GetPoint()->nNode.GetIndex() == rPam.GetMark()->nNode.GetIndex() )
2984 && nullptr != ( pGrfNd = rPam.GetPoint()->nNode.GetNode().GetGrfNode() )) )
2985 return;
2986
2987 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
2988 {
2989 m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoReRead>(rPam, *pGrfNd));
2990 }
2991
2992 // Because we don't know if we can mirror the graphic, the mirror attribute is always reset
2993 if( MirrorGraph::Dont != pGrfNd->GetSwAttrSet().
2994 GetMirrorGrf().GetValue() )
2995 pGrfNd->SetAttr( SwMirrorGrf() );
2996
2997 pGrfNd->ReRead( rGrfName, rFltName, pGraphic );
2998 m_rDoc.getIDocumentState().SetModified();
2999}
3000
3001// Insert drawing object, which has to be already inserted in the DrawModel
3002SwDrawFrameFormat* DocumentContentOperationsManager::InsertDrawObj(
3003 const SwPaM &rRg,
3004 SdrObject& rDrawObj,
3005 const SfxItemSet& rFlyAttrSet )
3006{
3007 SwDrawFrameFormat* pFormat = m_rDoc.MakeDrawFrameFormat( OUString(), m_rDoc.GetDfltFrameFormat() );
3008
3009 const SwFormatAnchor* pAnchor = nullptr;
3010 rFlyAttrSet.GetItemState( RES_ANCHOR, false, reinterpret_cast<const SfxPoolItem**>(&pAnchor) );
3011 pFormat->SetFormatAttr( rFlyAttrSet );
3012
3013 // Didn't set the Anchor yet?
3014 // DrawObjecte must never end up in the Header/Footer!
3015 RndStdIds eAnchorId = pAnchor != nullptr ? pAnchor->GetAnchorId() : pFormat->GetAnchor().GetAnchorId();
3016 const bool bIsAtContent = (RndStdIds::FLY_AT_PAGE != eAnchorId);
3017
3018 const SwNodeIndex* pChkIdx = nullptr;
3019 if ( pAnchor == nullptr )
3020 {
3021 pChkIdx = &rRg.GetPoint()->nNode;
3022 }
3023 else if ( bIsAtContent )
3024 {
3025 pChkIdx =
3026 pAnchor->GetContentAnchor() ? &pAnchor->GetContentAnchor()->nNode : &rRg.GetPoint()->nNode;
3027 }
3028
3029 // allow drawing objects in header/footer, but control objects aren't allowed in header/footer.
3030 if( pChkIdx != nullptr
3031 && ::CheckControlLayer( &rDrawObj )
3032 && m_rDoc.IsInHeaderFooter( *pChkIdx ) )
3033 {
3034 // apply at-page anchor format
3035 eAnchorId = RndStdIds::FLY_AT_PAGE;
3036 pFormat->SetFormatAttr( SwFormatAnchor( eAnchorId ) );
3037 }
3038 else if( pAnchor == nullptr
3039 || ( bIsAtContent
3040 && pAnchor->GetContentAnchor() == nullptr ) )
3041 {
3042 // apply anchor format
3043 SwFormatAnchor aAnch( pAnchor != nullptr ? *pAnchor : pFormat->GetAnchor() );
3044 eAnchorId = aAnch.GetAnchorId();
3045 if ( eAnchorId == RndStdIds::FLY_AT_FLY )
3046 {
3047 const SwStartNode* pStartNode = rRg.GetNode().FindFlyStartNode();
3048 assert(pStartNode)(static_cast <bool> (pStartNode) ? void (0) : __assert_fail
("pStartNode", "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 3048, __extension__ __PRETTY_FUNCTION__))
;
3049 SwPosition aPos(*pStartNode);
3050 aAnch.SetAnchor( &aPos );
3051 }
3052 else
3053 {
3054 aAnch.SetAnchor( rRg.GetPoint() );
3055 if ( eAnchorId == RndStdIds::FLY_AT_PAGE )
3056 {
3057 eAnchorId = dynamic_cast<const SdrUnoObj*>( &rDrawObj) != nullptr ? RndStdIds::FLY_AS_CHAR : RndStdIds::FLY_AT_PARA;
3058 aAnch.SetType( eAnchorId );
3059 }
3060 }
3061 pFormat->SetFormatAttr( aAnch );
3062 }
3063
3064 // insert text attribute for as-character anchored drawing object
3065 if ( eAnchorId == RndStdIds::FLY_AS_CHAR )
3066 {
3067 bool bAnchorAtPageAsFallback = true;
3068 const SwFormatAnchor& rDrawObjAnchorFormat = pFormat->GetAnchor();
3069 if ( rDrawObjAnchorFormat.GetContentAnchor() != nullptr )
3070 {
3071 SwTextNode* pAnchorTextNode =
3072 rDrawObjAnchorFormat.GetContentAnchor()->nNode.GetNode().GetTextNode();
3073 if ( pAnchorTextNode != nullptr )
3074 {
3075 const sal_Int32 nStt = rDrawObjAnchorFormat.GetContentAnchor()->nContent.GetIndex();
3076 SwFormatFlyCnt aFormat( pFormat );
3077 pAnchorTextNode->InsertItem( aFormat, nStt, nStt );
3078 bAnchorAtPageAsFallback = false;
3079 }
3080 }
3081
3082 if ( bAnchorAtPageAsFallback )
3083 {
3084 OSL_ENSURE( false, "DocumentContentOperationsManager::InsertDrawObj(..) - missing content anchor for as-character anchored drawing object --> anchor at-page" )do { if (true && (!(false))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
":" "3084" ": "), "%s", "DocumentContentOperationsManager::InsertDrawObj(..) - missing content anchor for as-character anchored drawing object --> anchor at-page"
); } } while (false)
;
3085 pFormat->SetFormatAttr( SwFormatAnchor( RndStdIds::FLY_AT_PAGE ) );
3086 }
3087 }
3088
3089 SwDrawContact* pContact = new SwDrawContact( pFormat, &rDrawObj );
3090
3091 // Create Frames if necessary
3092 if( m_rDoc.getIDocumentLayoutAccess().GetCurrentViewShell() )
3093 {
3094 // create layout representation
3095 pFormat->MakeFrames();
3096 // #i42319# - follow-up of #i35635#
3097 // move object to visible layer
3098 // #i79391#
3099 if ( pContact->GetAnchorFrame() )
3100 {
3101 pContact->MoveObjToVisibleLayer( &rDrawObj );
3102 }
3103 }
3104
3105 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
3106 {
3107 m_rDoc.GetIDocumentUndoRedo().AppendUndo( std::make_unique<SwUndoInsLayFormat>(pFormat, 0, 0) );
3108 }
3109
3110 m_rDoc.getIDocumentState().SetModified();
3111 return pFormat;
3112}
3113
3114bool DocumentContentOperationsManager::SplitNode( const SwPosition &rPos, bool bChkTableStart )
3115{
3116 SwContentNode *pNode = rPos.nNode.GetNode().GetContentNode();
3117 if(nullptr == pNode)
3118 return false;
3119
3120 {
3121 // BUG 26675: Send DataChanged before deleting, so that we notice which objects are in scope.
3122 // After that they can be before/after the position.
3123 SwDataChanged aTmp( m_rDoc, rPos );
3124 }
3125
3126 SwUndoSplitNode* pUndo = nullptr;
3127 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
3128 {
3129 m_rDoc.GetIDocumentUndoRedo().ClearRedo();
3130 // insert the Undo object (currently only for TextNode)
3131 if( pNode->IsTextNode() )
3132 {
3133 pUndo = new SwUndoSplitNode( m_rDoc, rPos, bChkTableStart );
3134 m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::unique_ptr<SwUndo>(pUndo));
3135 }
3136 }
3137
3138 // Update the rsid of the old and the new node unless
3139 // the old node is split at the beginning or at the end
3140 SwTextNode *pTextNode = rPos.nNode.GetNode().GetTextNode();
3141 const sal_Int32 nPos = rPos.nContent.GetIndex();
3142 if( pTextNode && nPos && nPos != pTextNode->Len() )
3143 {
3144 m_rDoc.UpdateParRsid( pTextNode );
3145 }
3146
3147 //JP 28.01.97: Special case for SplitNode at table start:
3148 // If it is at the beginning of a Doc/Fly/Footer/... or right at after a table
3149 // then insert a paragraph before it.
3150 if( bChkTableStart && !rPos.nContent.GetIndex() && pNode->IsTextNode() )
3151 {
3152 sal_uLong nPrevPos = rPos.nNode.GetIndex() - 1;
3153 const SwTableNode* pTableNd;
3154 const SwNode* pNd = m_rDoc.GetNodes()[ nPrevPos ];
3155 if( pNd->IsStartNode() &&
3156 SwTableBoxStartNode == static_cast<const SwStartNode*>(pNd)->GetStartNodeType() &&
3157 nullptr != ( pTableNd = m_rDoc.GetNodes()[ --nPrevPos ]->GetTableNode() ) &&
3158 ((( pNd = m_rDoc.GetNodes()[ --nPrevPos ])->IsStartNode() &&
3159 SwTableBoxStartNode != static_cast<const SwStartNode*>(pNd)->GetStartNodeType() )
3160 || ( pNd->IsEndNode() && pNd->StartOfSectionNode()->IsTableNode() )
3161 || pNd->IsContentNode() ))
3162 {
3163 if( pNd->IsContentNode() )
3164 {
3165 //JP 30.04.99 Bug 65660:
3166 // There are no page breaks outside of the normal body area,
3167 // so this is not a valid condition to insert a paragraph.
3168 if( nPrevPos < m_rDoc.GetNodes().GetEndOfExtras().GetIndex() )
3169 pNd = nullptr;
3170 else
3171 {
3172 // Only if the table has page breaks!
3173 const SwFrameFormat* pFrameFormat = pTableNd->GetTable().GetFrameFormat();
3174 if( SfxItemState::SET != pFrameFormat->GetItemState(RES_PAGEDESC, false) &&
3175 SfxItemState::SET != pFrameFormat->GetItemState( RES_BREAK, false ) )
3176 pNd = nullptr;
3177 }
3178 }
3179
3180 if( pNd )
3181 {
3182 SwTextNode* pTextNd = m_rDoc.GetNodes().MakeTextNode(
3183 SwNodeIndex( *pTableNd ),
3184 m_rDoc.getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_TEXT ));
3185 if( pTextNd )
3186 {
3187 const_cast<SwPosition&>(rPos).nNode = pTableNd->GetIndex()-1;
3188 const_cast<SwPosition&>(rPos).nContent.Assign( pTextNd, 0 );
3189
3190 // only add page breaks/styles to the body area
3191 if( nPrevPos > m_rDoc.GetNodes().GetEndOfExtras().GetIndex() )
3192 {
3193 SwFrameFormat* pFrameFormat = pTableNd->GetTable().GetFrameFormat();
3194 const SfxPoolItem *pItem;
3195 if( SfxItemState::SET == pFrameFormat->GetItemState( RES_PAGEDESC,
3196 false, &pItem ) )
3197 {
3198 pTextNd->SetAttr( *pItem );
3199 pFrameFormat->ResetFormatAttr( RES_PAGEDESC );
3200 }
3201 if( SfxItemState::SET == pFrameFormat->GetItemState( RES_BREAK,
3202 false, &pItem ) )
3203 {
3204 pTextNd->SetAttr( *pItem );
3205 pFrameFormat->ResetFormatAttr( RES_BREAK );
3206 }
3207 }
3208
3209 if( pUndo )
3210 pUndo->SetTableFlag();
3211 m_rDoc.getIDocumentState().SetModified();
3212 return true;
3213 }
3214 }
3215 }
3216 }
3217
3218 const std::shared_ptr<sw::mark::ContentIdxStore> pContentStore(sw::mark::ContentIdxStore::Create());
3219 pContentStore->Save( m_rDoc, rPos.nNode.GetIndex(), rPos.nContent.GetIndex(), true );
3220 assert(pNode->IsTextNode())(static_cast <bool> (pNode->IsTextNode()) ? void (0)
: __assert_fail ("pNode->IsTextNode()", "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 3220, __extension__ __PRETTY_FUNCTION__))
;
3221 std::function<void (SwTextNode *, sw::mark::RestoreMode)> restoreFunc(
3222 [&](SwTextNode *const, sw::mark::RestoreMode const eMode)
3223 {
3224 if (!pContentStore->Empty())
3225 { // move all bookmarks, TOXMarks, FlyAtCnt
3226 pContentStore->Restore(m_rDoc, rPos.nNode.GetIndex()-1, 0, true, eMode);
3227 }
3228 if (eMode & sw::mark::RestoreMode::NonFlys)
3229 {
3230 // To-Do - add 'SwExtraRedlineTable' also ?
3231 if (m_rDoc.getIDocumentRedlineAccess().IsRedlineOn() ||
3232 (!m_rDoc.getIDocumentRedlineAccess().IsIgnoreRedline() &&
3233 !m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().empty()))
3234 {
3235 SwPaM aPam( rPos );
3236 aPam.SetMark();
3237 aPam.Move( fnMoveBackward );
3238 if (m_rDoc.getIDocumentRedlineAccess().IsRedlineOn())
3239 {
3240 m_rDoc.getIDocumentRedlineAccess().AppendRedline(
3241 new SwRangeRedline(RedlineType::Insert, aPam), true);
3242 }
3243 else
3244 {
3245 m_rDoc.getIDocumentRedlineAccess().SplitRedline(aPam);
3246 }
3247 }
3248 }
3249 });
3250 pNode->GetTextNode()->SplitContentNode(rPos, &restoreFunc);
3251
3252 m_rDoc.getIDocumentState().SetModified();
3253 return true;
3254}
3255
3256bool DocumentContentOperationsManager::AppendTextNode( SwPosition& rPos )
3257{
3258 // create new node before EndOfContent
3259 SwTextNode * pCurNode = rPos.nNode.GetNode().GetTextNode();
3260 if( !pCurNode )
3261 {
3262 // so then one can be created!
3263 SwNodeIndex aIdx( rPos.nNode, 1 );
3264 pCurNode = m_rDoc.GetNodes().MakeTextNode( aIdx,
3265 m_rDoc.getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_STANDARD ));
3266 }
3267 else
3268 pCurNode = pCurNode->AppendNode( rPos )->GetTextNode();
3269
3270 rPos.nNode++;
3271 rPos.nContent.Assign( pCurNode, 0 );
3272
3273 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
3274 {
3275 m_rDoc.GetIDocumentUndoRedo().AppendUndo( std::make_unique<SwUndoInsert>( rPos.nNode ) );
3276 }
3277
3278 // To-Do - add 'SwExtraRedlineTable' also ?
3279 if( m_rDoc.getIDocumentRedlineAccess().IsRedlineOn() || (!m_rDoc.getIDocumentRedlineAccess().IsIgnoreRedline() && !m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().empty() ))
3280 {
3281 SwPaM aPam( rPos );
3282 aPam.SetMark();
3283 aPam.Move( fnMoveBackward );
3284 if( m_rDoc.getIDocumentRedlineAccess().IsRedlineOn() )
3285 m_rDoc.getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline( RedlineType::Insert, aPam ), true);
3286 else
3287 m_rDoc.getIDocumentRedlineAccess().SplitRedline( aPam );
3288 }
3289
3290 m_rDoc.getIDocumentState().SetModified();
3291 return true;
3292}
3293
3294bool DocumentContentOperationsManager::ReplaceRange( SwPaM& rPam, const OUString& rStr,
3295 const bool bRegExReplace )
3296{
3297 // unfortunately replace works slightly differently from delete,
3298 // so we cannot use lcl_DoWithBreaks here...
3299
3300 std::vector<std::pair<sal_uLong, sal_Int32>> Breaks;
3301
3302 SwPaM aPam( *rPam.GetMark(), *rPam.GetPoint() );
3303 aPam.Normalize(false);
3304 if (aPam.GetPoint()->nNode != aPam.GetMark()->nNode)
3305 {
3306 aPam.Move(fnMoveBackward);
3307 }
3308 OSL_ENSURE((aPam.GetPoint()->nNode == aPam.GetMark()->nNode), "invalid pam?")do { if (true && (!((aPam.GetPoint()->nNode == aPam
.GetMark()->nNode)))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
":" "3308" ": "), "%s", "invalid pam?"); } } while (false)
;
3309
3310 sw::CalcBreaks(Breaks, aPam);
3311
3312 while (!Breaks.empty() // skip over prefix of dummy chars
3313 && (aPam.GetMark()->nNode.GetIndex() == Breaks.begin()->first)
3314 && (aPam.GetMark()->nContent.GetIndex() == Breaks.begin()->second))
3315 {
3316 // skip!
3317 ++aPam.GetMark()->nContent; // always in bounds if Breaks valid
3318 Breaks.erase(Breaks.begin());
3319 }
3320 *rPam.Start() = *aPam.GetMark(); // update start of original pam w/ prefix
3321
3322 if (Breaks.empty())
3323 {
3324 // park aPam somewhere so it does not point to node that is deleted
3325 aPam.DeleteMark();
3326 *aPam.GetPoint() = SwPosition(m_rDoc.GetNodes().GetEndOfContent());
3327 return ReplaceRangeImpl(rPam, rStr, bRegExReplace); // original pam!
3328 }
3329
3330 // Deletion must be split into several parts if the text node
3331 // contains a text attribute with end and with dummy character
3332 // and the selection does not contain the text attribute completely,
3333 // but overlaps its start (left), where the dummy character is.
3334
3335 bool bRet( true );
3336 // iterate from end to start, to avoid invalidating the offsets!
3337 auto iter( Breaks.rbegin() );
3338 sal_uLong nOffset(0);
3339 SwNodes const& rNodes(rPam.GetPoint()->nNode.GetNodes());
3340 OSL_ENSURE(aPam.GetPoint() == aPam.End(), "wrong!")do { if (true && (!(aPam.GetPoint() == aPam.End()))) {
sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
":" "3340" ": "), "%s", "wrong!"); } } while (false)
;
3341 SwPosition & rEnd( *aPam.End() );
3342 SwPosition & rStart( *aPam.Start() );
3343
3344 // set end of temp pam to original end (undo Move backward above)
3345 rEnd = *rPam.End();
3346 // after first deletion, rEnd will point into the original text node again!
3347
3348 while (iter != Breaks.rend())
3349 {
3350 rStart = SwPosition(*rNodes[iter->first - nOffset]->GetTextNode(), iter->second + 1);
3351 if (rStart < rEnd) // check if part is empty
3352 {
3353 bRet &= (m_rDoc.getIDocumentRedlineAccess().IsRedlineOn())
3354 ? DeleteAndJoinWithRedlineImpl(aPam)
3355 : DeleteAndJoinImpl(aPam, false);
3356 nOffset = iter->first - rStart.nNode.GetIndex(); // deleted fly nodes...
3357 }
3358 rEnd = SwPosition(*rNodes[iter->first - nOffset]->GetTextNode(), iter->second);
3359 ++iter;
3360 }
3361
3362 rStart = *rPam.Start(); // set to original start
3363 assert(rStart < rEnd && "replace part empty!")(static_cast <bool> (rStart < rEnd && "replace part empty!"
) ? void (0) : __assert_fail ("rStart < rEnd && \"replace part empty!\""
, "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 3363, __extension__ __PRETTY_FUNCTION__))
;
3364 if (rStart < rEnd) // check if part is empty
3365 {
3366 bRet &= ReplaceRangeImpl(aPam, rStr, bRegExReplace);
3367 }
3368
3369 rPam = aPam; // update original pam (is this required?)
3370
3371 return bRet;
3372}
3373
3374///Add a para for the char attribute exp...
3375bool DocumentContentOperationsManager::InsertPoolItem(
3376 const SwPaM &rRg,
3377 const SfxPoolItem &rHt,
3378 const SetAttrMode nFlags,
3379 SwRootFrame const*const pLayout,
3380 const bool bExpandCharToPara,
3381 SwTextAttr **ppNewTextAttr)
3382{
3383 if (utl::ConfigManager::IsFuzzing())
3384 return false;
3385
3386 SwDataChanged aTmp( rRg );
3387 std::unique_ptr<SwUndoAttr> pUndoAttr;
3388 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
3389 {
3390 m_rDoc.GetIDocumentUndoRedo().ClearRedo();
3391 pUndoAttr.reset(new SwUndoAttr( rRg, rHt, nFlags ));
3392 }
3393
3394 SfxItemSet aSet( m_rDoc.GetAttrPool(), {{rHt.Which(), rHt.Which()}} );
3395 aSet.Put( rHt );
3396 const bool bRet = lcl_InsAttr(m_rDoc, rRg, aSet, nFlags, pUndoAttr.get(), pLayout, bExpandCharToPara, ppNewTextAttr);
3397
3398 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
3399 {
3400 m_rDoc.GetIDocumentUndoRedo().AppendUndo( std::move(pUndoAttr) );
3401 }
3402
3403 if( bRet )
3404 {
3405 m_rDoc.getIDocumentState().SetModified();
3406 }
3407 return bRet;
3408}
3409
3410void DocumentContentOperationsManager::InsertItemSet ( const SwPaM &rRg, const SfxItemSet &rSet,
3411 const SetAttrMode nFlags, SwRootFrame const*const pLayout)
3412{
3413 SwDataChanged aTmp( rRg );
3414 std::unique_ptr<SwUndoAttr> pUndoAttr;
3415 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
3416 {
3417 m_rDoc.GetIDocumentUndoRedo().ClearRedo();
3418 pUndoAttr.reset(new SwUndoAttr( rRg, rSet, nFlags ));
3419 }
3420
3421 bool bRet = lcl_InsAttr(m_rDoc, rRg, rSet, nFlags, pUndoAttr.get(), pLayout, /*bExpandCharToPara*/false, /*ppNewTextAttr*/nullptr );
3422
3423 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
3424 {
3425 m_rDoc.GetIDocumentUndoRedo().AppendUndo( std::move(pUndoAttr) );
3426 }
3427
3428 if( bRet )
3429 m_rDoc.getIDocumentState().SetModified();
3430}
3431
3432void DocumentContentOperationsManager::RemoveLeadingWhiteSpace(const SwPosition & rPos )
3433{
3434 const SwTextNode* pTNd = rPos.nNode.GetNode().GetTextNode();
3435 if ( !pTNd )
3436 return;
3437
3438 const OUString& rText = pTNd->GetText();
3439 sal_Int32 nIdx = 0;
3440 while (nIdx < rText.getLength())
3441 {
3442 sal_Unicode const cCh = rText[nIdx];
3443 if (('\t' != cCh) && (' ' != cCh))
3444 {
3445 break;
3446 }
3447 ++nIdx;
3448 }
3449
3450 if ( nIdx > 0 )
3451 {
3452 SwPaM aPam(rPos);
3453 aPam.GetPoint()->nContent = 0;
3454 aPam.SetMark();
3455 aPam.GetMark()->nContent = nIdx;
3456 DeleteRange( aPam );
3457 }
3458}
3459
3460// Copy method from SwDoc - "copy Flys in Flys"
3461/// note: rRg/rInsPos *exclude* a partially selected start text node;
3462/// pCopiedPaM *includes* a partially selected start text node
3463void DocumentContentOperationsManager::CopyWithFlyInFly(
3464 const SwNodeRange& rRg,
3465 const SwNodeIndex& rInsPos,
3466 const std::pair<const SwPaM&, const SwPosition&>* pCopiedPaM /*and real insert pos*/,
3467 const bool bMakeNewFrames,
3468 const bool bDelRedlines,
3469 const bool bCopyFlyAtFly,
3470 SwCopyFlags const flags) const
3471{
3472 assert(!pCopiedPaM || pCopiedPaM->first.End()->nNode == rRg.aEnd)(static_cast <bool> (!pCopiedPaM || pCopiedPaM->first
.End()->nNode == rRg.aEnd) ? void (0) : __assert_fail ("!pCopiedPaM || pCopiedPaM->first.End()->nNode == rRg.aEnd"
, "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 3472, __extension__ __PRETTY_FUNCTION__))
;
3473 assert(!pCopiedPaM || pCopiedPaM->second.nNode <= rInsPos)(static_cast <bool> (!pCopiedPaM || pCopiedPaM->second
.nNode <= rInsPos) ? void (0) : __assert_fail ("!pCopiedPaM || pCopiedPaM->second.nNode <= rInsPos"
, "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 3473, __extension__ __PRETTY_FUNCTION__))
;
3474
3475 SwDoc& rDest = rInsPos.GetNode().GetDoc();
3476 SwNodeIndex aSavePos( rInsPos );
3477
3478 if (rRg.aStart != rRg.aEnd)
3479 {
3480 bool bEndIsEqualEndPos = rInsPos == rRg.aEnd;
3481 bool isRecreateEndNode(false);
3482 --aSavePos;
3483 SaveRedlEndPosForRestore aRedlRest( rInsPos, 0 );
3484
3485 // insert behind the already copied start node
3486 m_rDoc.GetNodes().CopyNodes( rRg, rInsPos, false, true );
3487 aRedlRest.Restore();
3488 if (bMakeNewFrames) // tdf#130685 only after aRedlRest
3489 { // recreate from previous node (could be merged now)
3490 if (SwTextNode *const pNode = aSavePos.GetNode().GetTextNode())
3491 {
3492 o3tl::sorted_vector<SwTextFrame*> frames;
3493 SwTextNode *const pEndNode = rInsPos.GetNode().GetTextNode();
3494 if (pEndNode)
3495 {
3496 SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(*pEndNode);
3497 for (SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
3498 {
3499 if (pFrame->getRootFrame()->IsHideRedlines())
3500 {
3501 frames.insert(pFrame);
3502 }
3503 }
3504 }
3505 sw::RecreateStartTextFrames(*pNode);
3506 if (!frames.empty())
3507 { // tdf#132187 check if the end node needs new frames
3508 SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(*pEndNode);
3509 for (SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
3510 {
3511 if (pFrame->getRootFrame()->IsHideRedlines())
3512 {
3513 auto const it = frames.find(pFrame);
3514 if (it != frames.end())
3515 {
3516 frames.erase(it);
3517 }
3518 }
3519 }
3520 if (!frames.empty()) // existing frame was deleted
3521 { // all layouts because MakeFrames recreates all layouts
3522 pEndNode->DelFrames(nullptr);
3523 isRecreateEndNode = true;
3524 }
3525 }
3526 }
3527 }
3528 bool const isAtStartOfSection(aSavePos.GetNode().IsStartNode());
3529 ++aSavePos;
3530 if (bMakeNewFrames)
3531 {
3532 // it's possible that CheckParaRedlineMerge() deleted frames
3533 // on rInsPos so have to include it, but it must not be included
3534 // if it was the first node in the document so that MakeFrames()
3535 // will find the existing (wasn't deleted) frame on it
3536 SwNodeIndex const end(rInsPos,
3537 (!isRecreateEndNode || isAtStartOfSection)
3538 ? 0 : +1);
3539 ::MakeFrames(&rDest, aSavePos, end);
3540 }
3541 if (bEndIsEqualEndPos)
3542 {
3543 const_cast<SwNodeIndex&>(rRg.aEnd) = aSavePos;
3544 }
3545 }
3546
3547#if OSL_DEBUG_LEVEL1 > 0
3548 {
3549 //JP 17.06.99: Bug 66973 - check count only if the selection is in
3550 // the same section or there's no section, because sections that are
3551 // not fully selected are not copied.
3552 const SwSectionNode* pSSectNd = rRg.aStart.GetNode().FindSectionNode();
3553 SwNodeIndex aTmpI( rRg.aEnd, -1 );
3554 const SwSectionNode* pESectNd = aTmpI.GetNode().FindSectionNode();
3555 if( pSSectNd == pESectNd &&
3556 !rRg.aStart.GetNode().IsSectionNode() &&
3557 !aTmpI.GetNode().IsEndNode() )
3558 {
3559 // If the range starts with a SwStartNode, it isn't copied
3560 sal_uInt16 offset = (rRg.aStart.GetNode().GetNodeType() != SwNodeType::Start) ? 1 : 0;
3561 OSL_ENSURE( rInsPos.GetIndex() - aSavePos.GetIndex() ==do { if (true && (!(rInsPos.GetIndex() - aSavePos.GetIndex
() == rRg.aEnd.GetIndex() - rRg.aStart.GetIndex() - 1 + offset
))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
":" "3563" ": "), "%s", "An insufficient number of nodes were copied!"
); } } while (false)
3562 rRg.aEnd.GetIndex() - rRg.aStart.GetIndex() - 1 + offset,do { if (true && (!(rInsPos.GetIndex() - aSavePos.GetIndex
() == rRg.aEnd.GetIndex() - rRg.aStart.GetIndex() - 1 + offset
))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
":" "3563" ": "), "%s", "An insufficient number of nodes were copied!"
); } } while (false)
3563 "An insufficient number of nodes were copied!" )do { if (true && (!(rInsPos.GetIndex() - aSavePos.GetIndex
() == rRg.aEnd.GetIndex() - rRg.aStart.GetIndex() - 1 + offset
))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
":" "3563" ": "), "%s", "An insufficient number of nodes were copied!"
); } } while (false)
;
3564 }
3565 }
3566#endif
3567
3568 {
3569 ::sw::UndoGuard const undoGuard(rDest.GetIDocumentUndoRedo());
3570 CopyFlyInFlyImpl(rRg, pCopiedPaM ? &pCopiedPaM->first : nullptr,
3571 // see comment below regarding use of pCopiedPaM->second
3572 (pCopiedPaM && rRg.aStart != pCopiedPaM->first.Start()->nNode)
3573 ? pCopiedPaM->second.nNode
3574 : aSavePos,
3575 bCopyFlyAtFly,
3576 flags);
3577 }
3578
3579 SwNodeRange aCpyRange( aSavePos, rInsPos );
3580
3581 // Also copy all bookmarks
3582 // guess this must be done before the DelDummyNodes below as that
3583 // deletes nodes so would mess up the index arithmetic
3584 if( m_rDoc.getIDocumentMarkAccess()->getAllMarksCount() )
3585 {
3586 SwPaM aRgTmp( rRg.aStart, rRg.aEnd );
3587 SwPaM aCpyPaM(aCpyRange.aStart, aCpyRange.aEnd);
3588 if (pCopiedPaM && rRg.aStart != pCopiedPaM->first.Start()->nNode)
3589 {
3590 // there is 1 (partially selected, maybe) paragraph before
3591 assert(SwNodeIndex(rRg.aStart, -1) == pCopiedPaM->first.Start()->nNode)(static_cast <bool> (SwNodeIndex(rRg.aStart, -1) == pCopiedPaM
->first.Start()->nNode) ? void (0) : __assert_fail ("SwNodeIndex(rRg.aStart, -1) == pCopiedPaM->first.Start()->nNode"
, "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 3591, __extension__ __PRETTY_FUNCTION__))
;
3592 // only use the passed in target SwPosition if the source PaM point
3593 // is on a different node; if it was the same node then the target
3594 // position was likely moved along by the copy operation and now
3595 // points to the end of the range!
3596 *aCpyPaM.GetPoint() = pCopiedPaM->second;
3597 }
3598
3599 sw::CopyBookmarks(pCopiedPaM ? pCopiedPaM->first : aRgTmp, *aCpyPaM.Start());
3600 }
3601
3602 if( bDelRedlines && ( RedlineFlags::DeleteRedlines & rDest.getIDocumentRedlineAccess().GetRedlineFlags() ))
3603 lcl_DeleteRedlines( rRg, aCpyRange );
3604
3605 rDest.GetNodes().DelDummyNodes( aCpyRange );
3606}
3607
3608// note: for the redline Show/Hide this must be in sync with
3609// SwRangeRedline::CopyToSection()/DelCopyOfSection()/MoveFromSection()
3610void DocumentContentOperationsManager::CopyFlyInFlyImpl(
3611 const SwNodeRange& rRg,
3612 SwPaM const*const pCopiedPaM,
3613 const SwNodeIndex& rStartIdx,
3614 const bool bCopyFlyAtFly,
3615 SwCopyFlags const flags) const
3616{
3617 assert(!pCopiedPaM || pCopiedPaM->End()->nNode == rRg.aEnd)(static_cast <bool> (!pCopiedPaM || pCopiedPaM->End(
)->nNode == rRg.aEnd) ? void (0) : __assert_fail ("!pCopiedPaM || pCopiedPaM->End()->nNode == rRg.aEnd"
, "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 3617, __extension__ __PRETTY_FUNCTION__))
;
3618
3619 // First collect all Flys, sort them according to their ordering number,
3620 // and then only copy them. This maintains the ordering numbers (which are only
3621 // managed in the DrawModel).
3622 SwDoc& rDest = rStartIdx.GetNode().GetDoc();
3623 std::set< ZSortFly > aSet;
3624 const size_t nArrLen = m_rDoc.GetSpzFrameFormats()->size();
3625
3626 SwTextBoxHelper::SavedLink aOldTextBoxes;
3627 SwTextBoxHelper::saveLinks(*m_rDoc.GetSpzFrameFormats(), aOldTextBoxes);
3628
3629 for ( size_t n = 0; n < nArrLen; ++n )
3630 {
3631 SwFrameFormat* pFormat = (*m_rDoc.GetSpzFrameFormats())[n];
3632 SwFormatAnchor const*const pAnchor = &pFormat->GetAnchor();
3633 SwPosition const*const pAPos = pAnchor->GetContentAnchor();
3634 if ( !pAPos )
3635 continue;
3636 bool bAdd = false;
3637 sal_uLong nSkipAfter = pAPos->nNode.GetIndex();
3638 sal_uLong nStart = rRg.aStart.GetIndex();
3639 switch ( pAnchor->GetAnchorId() )
3640 {
3641 case RndStdIds::FLY_AT_FLY:
3642 if(bCopyFlyAtFly)
3643 ++nSkipAfter;
3644 else if(m_rDoc.getIDocumentRedlineAccess().IsRedlineMove())
3645 ++nStart;
3646 break;
3647 case RndStdIds::FLY_AT_PARA:
3648 {
3649 bAdd = IsSelectFrameAnchoredAtPara(*pAPos,
3650 pCopiedPaM ? *pCopiedPaM->Start() : SwPosition(rRg.aStart),
3651 pCopiedPaM ? *pCopiedPaM->End() : SwPosition(rRg.aEnd),
3652 (flags & SwCopyFlags::IsMoveToFly)
3653 ? DelContentType::AllMask|DelContentType::WriterfilterHack
3654 : DelContentType::AllMask);
3655 }
3656 break;
3657 case RndStdIds::FLY_AT_CHAR:
3658 {
3659 bAdd = IsDestroyFrameAnchoredAtChar(*pAPos,
3660 pCopiedPaM ? *pCopiedPaM->Start() : SwPosition(rRg.aStart),
3661 pCopiedPaM ? *pCopiedPaM->End() : SwPosition(rRg.aEnd),
3662 (flags & SwCopyFlags::IsMoveToFly)
3663 ? DelContentType::AllMask|DelContentType::WriterfilterHack
3664 : DelContentType::AllMask);
3665 }
3666 break;
3667 default:
3668 continue;
3669 }
3670 if (RndStdIds::FLY_AT_FLY == pAnchor->GetAnchorId())
3671 {
3672 if (nStart > nSkipAfter)
3673 continue;
3674 if (pAPos->nNode > rRg.aEnd)
3675 continue;
3676 //frames at the last source node are not always copied:
3677 //- if the node is empty and is the last node of the document or a table cell
3678 // or a text frame then they have to be copied
3679 //- if the content index in this node is > 0 then paragraph and frame bound objects are copied
3680 //- to-character bound objects are copied if their index is <= nEndContentIndex
3681 if (pAPos->nNode < rRg.aEnd)
3682 bAdd = true;
3683 if (!bAdd && !m_rDoc.getIDocumentRedlineAccess().IsRedlineMove()) // fdo#40599: not for redline move
3684 {
3685 if (!bAdd)
3686 {
3687 // technically old code checked nContent of AT_FLY which is pointless
3688 bAdd = pCopiedPaM && 0 < pCopiedPaM->End()->nContent.GetIndex();
3689 }
3690 }
3691 }
3692 if( bAdd )
3693 {
3694 aSet.insert( ZSortFly( pFormat, pAnchor, nArrLen + aSet.size() ));
3695 }
3696 }
3697
3698 // Store all copied (and also the newly created) frames in another array.
3699 // They are stored as matching the originals, so that we will be later
3700 // able to build the chains accordingly.
3701 std::vector< SwFrameFormat* > aVecSwFrameFormat;
3702 std::set< ZSortFly >::const_iterator it=aSet.begin();
3703
3704 while (it != aSet.end())
3705 {
3706 // #i59964#
3707 // correct determination of new anchor position
3708 SwFormatAnchor aAnchor( *(*it).GetAnchor() );
3709 assert( aAnchor.GetContentAnchor() != nullptr )(static_cast <bool> (aAnchor.GetContentAnchor() != nullptr
) ? void (0) : __assert_fail ("aAnchor.GetContentAnchor() != nullptr"
, "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 3709, __extension__ __PRETTY_FUNCTION__))
;
3710 SwPosition newPos = *aAnchor.GetContentAnchor();
3711 // for at-paragraph and at-character anchored objects the new anchor
3712 // position can *not* be determined by the difference of the current
3713 // anchor position to the start of the copied range, because not
3714 // complete selected sections in the copied range aren't copied - see
3715 // method <SwNodes::CopyNodes(..)>.
3716 // Thus, the new anchor position in the destination document is found
3717 // by counting the text nodes.
3718 if ((aAnchor.GetAnchorId() == RndStdIds::FLY_AT_PARA) ||
3719 (aAnchor.GetAnchorId() == RndStdIds::FLY_AT_CHAR) )
3720 {
3721 // First, determine number of anchor text node in the copied range.
3722 // Note: The anchor text node *have* to be inside the copied range.
3723 sal_uLong nAnchorTextNdNumInRange( 0 );
3724 bool bAnchorTextNdFound( false );
3725 // start at the first node for which flys are copied
3726 SwNodeIndex aIdx(pCopiedPaM ? pCopiedPaM->Start()->nNode : rRg.aStart);
3727 while ( !bAnchorTextNdFound && aIdx <= rRg.aEnd )
3728 {
3729 if ( aIdx.GetNode().IsTextNode() )
3730 {
3731 ++nAnchorTextNdNumInRange;
3732 bAnchorTextNdFound = aAnchor.GetContentAnchor()->nNode == aIdx;
3733 }
3734
3735 ++aIdx;
3736 }
3737
3738 if ( !bAnchorTextNdFound )
3739 {
3740 // This case can *not* happen, but to be robust take the first
3741 // text node in the destination document.
3742 OSL_FAIL( "<SwDoc::_CopyFlyInFly(..)> - anchor text node in copied range not found" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
":" "3742" ": "), "%s", "<SwDoc::_CopyFlyInFly(..)> - anchor text node in copied range not found"
); } } while (false)
;
3743 nAnchorTextNdNumInRange = 1;
3744 }
3745 // Second, search corresponding text node in destination document
3746 // by counting forward from start insert position <rStartIdx> the
3747 // determined number of text nodes.
3748 aIdx = rStartIdx;
3749 SwNodeIndex aAnchorNdIdx( rStartIdx );
3750 const SwNode& aEndOfContentNd =
3751 aIdx.GetNode().GetNodes().GetEndOfContent();
3752 while ( nAnchorTextNdNumInRange > 0 &&
3753 &(aIdx.GetNode()) != &aEndOfContentNd )
3754 {
3755 if ( aIdx.GetNode().IsTextNode() )
3756 {
3757 --nAnchorTextNdNumInRange;
3758 aAnchorNdIdx = aIdx;
3759 }
3760
3761 ++aIdx;
3762 }
3763 if ( !aAnchorNdIdx.GetNode().IsTextNode() )
3764 {
3765 // This case can *not* happen, but to be robust take the first
3766 // text node in the destination document.
3767 OSL_FAIL( "<SwDoc::_CopyFlyInFly(..)> - found anchor node index isn't a text node" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
":" "3767" ": "), "%s", "<SwDoc::_CopyFlyInFly(..)> - found anchor node index isn't a text node"
); } } while (false)
;
3768 aAnchorNdIdx = rStartIdx;
3769 while ( !aAnchorNdIdx.GetNode().IsTextNode() )
3770 {
3771 ++aAnchorNdIdx;
3772 }
3773 }
3774 // apply found anchor text node as new anchor position
3775 newPos.nNode = aAnchorNdIdx;
3776 }
3777 else
3778 {
3779 long nOffset = newPos.nNode.GetIndex() - rRg.aStart.GetIndex();
3780 SwNodeIndex aIdx( rStartIdx, nOffset );
3781 newPos.nNode = aIdx;
3782 }
3783 // Set the character bound Flys back at the original character
3784 if ((RndStdIds::FLY_AT_CHAR == aAnchor.GetAnchorId()) &&
3785 newPos.nNode.GetNode().IsTextNode() )
3786 {
3787 // only if pCopiedPaM: care about partially selected start node
3788 sal_Int32 const nContent = pCopiedPaM && pCopiedPaM->Start()->nNode == aAnchor.GetContentAnchor()->nNode
3789 ? newPos.nContent.GetIndex() - pCopiedPaM->Start()->nContent.GetIndex()
3790 : newPos.nContent.GetIndex();
3791 newPos.nContent.Assign(newPos.nNode.GetNode().GetTextNode(), nContent);
3792 }
3793 else
3794 {
3795 newPos.nContent.Assign( nullptr, 0 );
3796 }
3797 aAnchor.SetAnchor( &newPos );
3798
3799 // Check recursion: if copying content inside the same frame, then don't copy the format.
3800 if( &rDest == &m_rDoc )
3801 {
3802 const SwFormatContent& rContent = (*it).GetFormat()->GetContent();
3803 const SwStartNode* pSNd;
3804 if( rContent.GetContentIdx() &&
3805 nullptr != ( pSNd = rContent.GetContentIdx()->GetNode().GetStartNode() ) &&
3806 pSNd->GetIndex() < rStartIdx.GetIndex() &&
3807 rStartIdx.GetIndex() < pSNd->EndOfSectionIndex() )
3808 {
3809 it = aSet.erase(it);
3810 continue;
3811 }
3812 }
3813
3814 // Ignore TextBoxes, they are already handled in
3815 // sw::DocumentLayoutManager::CopyLayoutFormat().
3816 if (SwTextBoxHelper::isTextBox(it->GetFormat(), RES_FLYFRMFMT))
3817 {
3818 it = aSet.erase(it);
3819 continue;
3820 }
3821
3822 // Copy the format and set the new anchor
3823 aVecSwFrameFormat.push_back( rDest.getIDocumentLayoutAccess().CopyLayoutFormat( *(*it).GetFormat(),
3824 aAnchor, false, true ) );
3825 ++it;
3826 }
3827
3828 // Rebuild as much as possible of all chains that are available in the original,
3829 OSL_ENSURE( aSet.size() == aVecSwFrameFormat.size(), "Missing new Flys" )do { if (true && (!(aSet.size() == aVecSwFrameFormat.
size()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN),
("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
":" "3829" ": "), "%s", "Missing new Flys"); } } while (false
)
;
3830 if ( aSet.size() != aVecSwFrameFormat.size() )
3831 return;
3832
3833 size_t n = 0;
3834 for (const auto& rFlyN : aSet)
3835 {
3836 const SwFrameFormat *pFormatN = rFlyN.GetFormat();
3837 const SwFormatChain &rChain = pFormatN->GetChain();
3838 int nCnt = int(nullptr != rChain.GetPrev());
3839 nCnt += rChain.GetNext() ? 1: 0;
3840 size_t k = 0;
3841 for (const auto& rFlyK : aSet)
3842 {
3843 const SwFrameFormat *pFormatK = rFlyK.GetFormat();
3844 if ( rChain.GetPrev() == pFormatK )
3845 {
3846 ::lcl_ChainFormats( static_cast< SwFlyFrameFormat* >(aVecSwFrameFormat[k]),
3847 static_cast< SwFlyFrameFormat* >(aVecSwFrameFormat[n]) );
3848 --nCnt;
3849 }
3850 else if ( rChain.GetNext() == pFormatK )
3851 {
3852 ::lcl_ChainFormats( static_cast< SwFlyFrameFormat* >(aVecSwFrameFormat[n]),
3853 static_cast< SwFlyFrameFormat* >(aVecSwFrameFormat[k]) );
3854 --nCnt;
3855 }
3856 ++k;
3857 }
3858 ++n;
3859 }
3860
3861 // Re-create content property of draw formats, knowing how old shapes
3862 // were paired with old fly formats (aOldTextBoxes) and that aSet is
3863 // parallel with aVecSwFrameFormat.
3864 SwTextBoxHelper::restoreLinks(aSet, aVecSwFrameFormat, aOldTextBoxes);
3865}
3866
3867/*
3868 * Reset the text's hard formatting
3869 */
3870/** @params pArgs contains the document's ChrFormatTable
3871 * Is need for selections at the beginning/end and with no SSelection.
3872 */
3873bool DocumentContentOperationsManager::lcl_RstTextAttr( const SwNodePtr& rpNd, void* pArgs )
3874{
3875 ParaRstFormat* pPara = static_cast<ParaRstFormat*>(pArgs);
3876 if (pPara->pLayout && pPara->pLayout->IsHideRedlines()
3877 && rpNd->GetRedlineMergeFlag() == SwNode::Merge::Hidden)
3878 {
3879 return true; // skip hidden, since new items aren't applied
3880 }
3881 SwTextNode * pTextNode = rpNd->GetTextNode();
3882 if( pTextNode && pTextNode->GetpSwpHints() )
3883 {
3884 SwIndex aSt( pTextNode, 0 );
3885 sal_Int32 nEnd = pTextNode->Len();
3886
3887 if( &pPara->pSttNd->nNode.GetNode() == pTextNode &&
3888 pPara->pSttNd->nContent.GetIndex() )
3889 aSt = pPara->pSttNd->nContent.GetIndex();
3890
3891 if( &pPara->pEndNd->nNode.GetNode() == rpNd )
3892 nEnd = pPara->pEndNd->nContent.GetIndex();
3893
3894 if( pPara->pHistory )
3895 {
3896 // Save all attributes for the Undo.
3897 SwRegHistory aRHst( *pTextNode, pPara->pHistory );
3898 pTextNode->GetpSwpHints()->Register( &aRHst );
3899 pTextNode->RstTextAttr( aSt, nEnd - aSt.GetIndex(), pPara->nWhich,
3900 pPara->pDelSet, pPara->bInclRefToxMark, pPara->bExactRange );
3901 if( pTextNode->GetpSwpHints() )
3902 pTextNode->GetpSwpHints()->DeRegister();
3903 }
3904 else
3905 pTextNode->RstTextAttr( aSt, nEnd - aSt.GetIndex(), pPara->nWhich,
3906 pPara->pDelSet, pPara->bInclRefToxMark, pPara->bExactRange );
3907 }
3908 return true;
3909}
3910
3911DocumentContentOperationsManager::~DocumentContentOperationsManager()
3912{
3913}
3914//Private methods
3915
3916bool DocumentContentOperationsManager::DeleteAndJoinWithRedlineImpl( SwPaM & rPam, const bool )
3917{
3918 assert(m_rDoc.getIDocumentRedlineAccess().IsRedlineOn())(static_cast <bool> (m_rDoc.getIDocumentRedlineAccess()
.IsRedlineOn()) ? void (0) : __assert_fail ("m_rDoc.getIDocumentRedlineAccess().IsRedlineOn()"
, "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 3918, __extension__ __PRETTY_FUNCTION__))
;
3919
3920 RedlineFlags eOld = m_rDoc.getIDocumentRedlineAccess().GetRedlineFlags();
3921
3922 if (*rPam.GetPoint() == *rPam.GetMark())
3923 {
3924 return false; // do not add empty redlines
3925 }
3926
3927 std::vector<SwRangeRedline*> redlines;
3928 {
3929 auto pRedline(std::make_unique<SwRangeRedline>(RedlineType::Delete, rPam));
3930 if (pRedline->HasValidRange())
3931 {
3932 redlines.push_back(pRedline.release());
3933 }
3934 else // sigh ... why is such a selection even possible...
3935 { // split it up so we get one SwUndoRedlineDelete per inserted RL
3936 redlines = GetAllValidRanges(std::move(pRedline));
3937 }
3938 }
3939
3940 if (redlines.empty())
3941 {
3942 return false;
3943 }
3944
3945 // tdf#54819 current redlining needs also modification of paragraph style and
3946 // attributes added to the same grouped Undo
3947 if (m_rDoc.GetIDocumentUndoRedo().DoesGroupUndo())
3948 m_rDoc.GetIDocumentUndoRedo().StartUndo(SwUndoId::EMPTY, nullptr);
3949
3950 auto & rDMA(*m_rDoc.getIDocumentMarkAccess());
3951 std::vector<std::unique_ptr<SwUndo>> MarkUndos;
3952 for (auto iter = rDMA.getAnnotationMarksBegin();
3953 iter != rDMA.getAnnotationMarksEnd(); )
3954 {
3955 // tdf#111524 remove annotation marks that have their field
3956 // characters deleted
3957 SwPosition const& rEndPos((**iter).GetMarkEnd());
3958 if (*rPam.Start() < rEndPos && rEndPos <= *rPam.End())
3959 {
3960 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
3961 {
3962 MarkUndos.emplace_back(std::make_unique<SwUndoDeleteBookmark>(**iter));
3963 }
3964 // iter is into annotation mark vector so must be dereferenced!
3965 rDMA.deleteMark(&**iter);
3966 // this invalidates iter, have to start over...
3967 iter = rDMA.getAnnotationMarksBegin();
3968 }
3969 else
3970 { // marks are sorted by start
3971 if (*rPam.End() < (**iter).GetMarkStart())
3972 {
3973 break;
3974 }
3975 ++iter;
3976 }
3977 }
3978
3979 // tdf#119019 accept tracked paragraph formatting to do not hide new deletions
3980 if (*rPam.GetPoint() != *rPam.GetMark())
3981 m_rDoc.getIDocumentRedlineAccess().AcceptRedlineParagraphFormatting(rPam);
3982
3983 std::vector<std::unique_ptr<SwUndoRedlineDelete>> undos;
3984 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
3985 {
3986 // this should no longer happen in calls from the UI but maybe via API
3987 // (randomTest and testTdf54819 triggers it)
3988 SAL_WARN_IF((eOld & RedlineFlags::ShowMask) != RedlineFlags::ShowMask,do { if (true && ((eOld & RedlineFlags::ShowMask)
!= RedlineFlags::ShowMask)) { 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() << "redlines will be moved in DeleteAndJoin"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"
), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
":" "3989" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "redlines will be moved in DeleteAndJoin"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "redlines will be moved in DeleteAndJoin"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
":" "3989" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "redlines will be moved in DeleteAndJoin") == 1) {
::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core")
, ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
":" "3989" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "redlines will be moved in DeleteAndJoin"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "redlines will be moved in DeleteAndJoin"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
":" "3989" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
3989 "sw.core", "redlines will be moved in DeleteAndJoin")do { if (true && ((eOld & RedlineFlags::ShowMask)
!= RedlineFlags::ShowMask)) { 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() << "redlines will be moved in DeleteAndJoin"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"
), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
":" "3989" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "redlines will be moved in DeleteAndJoin"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "redlines will be moved in DeleteAndJoin"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
":" "3989" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "redlines will be moved in DeleteAndJoin") == 1) {
::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core")
, ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
":" "3989" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "redlines will be moved in DeleteAndJoin"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "redlines will be moved in DeleteAndJoin"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
":" "3989" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
3990 m_rDoc.getIDocumentRedlineAccess().SetRedlineFlags(
3991 RedlineFlags::On | RedlineFlags::ShowInsert | RedlineFlags::ShowDelete);
3992 for (SwRangeRedline * pRedline : redlines)
3993 {
3994 assert(pRedline->HasValidRange())(static_cast <bool> (pRedline->HasValidRange()) ? void
(0) : __assert_fail ("pRedline->HasValidRange()", "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 3994, __extension__ __PRETTY_FUNCTION__))
;
3995 undos.emplace_back(std::make_unique<SwUndoRedlineDelete>(
3996 *pRedline, SwUndoId::DELETE));
3997 }
3998 const SwRewriter aRewriter = undos.front()->GetRewriter();
3999 // can only group a single undo action
4000 if (MarkUndos.empty() && undos.size() == 1
4001 && m_rDoc.GetIDocumentUndoRedo().DoesGroupUndo())
4002 {
4003 SwUndo * const pLastUndo( m_rDoc.GetUndoManager().GetLastUndo() );
4004 SwUndoRedlineDelete *const pUndoRedlineDel(dynamic_cast<SwUndoRedlineDelete*>(pLastUndo));
4005 bool const bMerged = pUndoRedlineDel
4006 && pUndoRedlineDel->CanGrouping(*undos.front());
4007 if (!bMerged)
4008 {
4009 m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::move(undos.front()));
4010 }
4011 undos.clear(); // prevent unmatched EndUndo
4012 }
4013 else
4014 {
4015 m_rDoc.GetIDocumentUndoRedo().StartUndo(SwUndoId::DELETE, &aRewriter);
4016 for (auto& it : MarkUndos)
4017 {
4018 m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::move(it));
4019 }
4020 for (auto & it : undos)
4021 {
4022 m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::move(it));
4023 }
4024 }
4025 }
4026
4027 for (SwRangeRedline *const pRedline : redlines)
4028 {
4029 // note: 1. the pRedline can still be merged & deleted
4030 // 2. the impl. can even DeleteAndJoin the range => no plain PaM
4031 std::shared_ptr<SwUnoCursor> const pCursor(m_rDoc.CreateUnoCursor(*pRedline->GetMark()));
4032 pCursor->SetMark();
4033 *pCursor->GetPoint() = *pRedline->GetPoint();
4034 m_rDoc.getIDocumentRedlineAccess().AppendRedline(pRedline, true);
4035 // sw_redlinehide: 2 reasons why this is needed:
4036 // 1. it's the first redline in node => RedlineDelText was sent but ignored
4037 // 2. redline spans multiple nodes => must merge text frames
4038 sw::UpdateFramesForAddDeleteRedline(m_rDoc, *pCursor);
4039 }
4040 m_rDoc.getIDocumentState().SetModified();
4041
4042 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
4043 {
4044 if (!undos.empty())
4045 {
4046 m_rDoc.GetIDocumentUndoRedo().EndUndo(SwUndoId::EMPTY, nullptr);
4047 }
4048 m_rDoc.getIDocumentRedlineAccess().SetRedlineFlags( eOld );
4049 }
4050
4051 if (m_rDoc.GetIDocumentUndoRedo().DoesGroupUndo())
4052 m_rDoc.GetIDocumentUndoRedo().EndUndo(SwUndoId::EMPTY, nullptr);
4053
4054 return true;
4055}
4056
4057bool DocumentContentOperationsManager::DeleteAndJoinImpl( SwPaM & rPam,
4058 const bool bForceJoinNext )
4059{
4060 bool bJoinText, bJoinPrev;
4061 ::sw_GetJoinFlags( rPam, bJoinText, bJoinPrev );
4062 // #i100466#
4063 if ( bForceJoinNext )
4064 {
4065 bJoinPrev = false;
4066 }
4067
4068 {
4069 bool const bSuccess( DeleteRangeImpl( rPam ) );
4070 if (!bSuccess)
4071 return false;
4072 }
4073
4074 if( bJoinText )
4075 {
4076 ::sw_JoinText( rPam, bJoinPrev );
4077 }
4078
4079 if (!m_rDoc.getIDocumentRedlineAccess().IsIgnoreRedline()
4080 && !m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().empty())
4081 {
4082 m_rDoc.getIDocumentRedlineAccess().CompressRedlines();
4083 }
4084
4085 return true;
4086}
4087
4088bool DocumentContentOperationsManager::DeleteRangeImpl(SwPaM & rPam, const bool)
4089{
4090 // Move all cursors out of the deleted range, but first copy the
4091 // passed PaM, because it could be a cursor that would be moved!
4092 SwPaM aDelPam( *rPam.GetMark(), *rPam.GetPoint() );
4093 ::PaMCorrAbs( aDelPam, *aDelPam.GetPoint() );
4094
4095 bool const bSuccess( DeleteRangeImplImpl( aDelPam ) );
4096 if (bSuccess)
4097 { // now copy position from temp copy to given PaM
4098 *rPam.GetPoint() = *aDelPam.GetPoint();
4099 }
4100
4101 return bSuccess;
4102}
4103
4104bool DocumentContentOperationsManager::DeleteRangeImplImpl(SwPaM & rPam)
4105{
4106 SwPosition *pStt = rPam.Start(), *pEnd = rPam.End();
4107
4108 if (!rPam.HasMark()
4109 || (*pStt == *pEnd && !IsFlySelectedByCursor(m_rDoc, *pStt, *pEnd)))
4110 {
4111 return false;
4112 }
4113
4114 if( m_rDoc.GetAutoCorrExceptWord() )
4115 {
4116 // if necessary the saved Word for the exception
4117 if( m_rDoc.GetAutoCorrExceptWord()->IsDeleted() || pStt->nNode != pEnd->nNode ||
4118 pStt->nContent.GetIndex() + 1 != pEnd->nContent.GetIndex() ||
4119 !m_rDoc.GetAutoCorrExceptWord()->CheckDelChar( *pStt ))
4120 { m_rDoc.DeleteAutoCorrExceptWord(); }
4121 }
4122
4123 {
4124 // Delete all empty TextHints at the Mark's position
4125 SwTextNode* pTextNd = rPam.GetMark()->nNode.GetNode().GetTextNode();
4126 SwpHints* pHts;
4127 if( pTextNd && nullptr != ( pHts = pTextNd->GetpSwpHints()) && pHts->Count() )
4128 {
4129 const sal_Int32 nMkCntPos = rPam.GetMark()->nContent.GetIndex();
4130 for( size_t n = pHts->Count(); n; )
4131 {
4132 const SwTextAttr* pAttr = pHts->Get( --n );
4133 if( nMkCntPos > pAttr->GetStart() )
4134 break;
4135
4136 const sal_Int32 *pEndIdx;
4137 if( nMkCntPos == pAttr->GetStart() &&
4138 nullptr != (pEndIdx = pAttr->End()) &&
4139 *pEndIdx == pAttr->GetStart() )
4140 pTextNd->DestroyAttr( pHts->Cut( n ) );
4141 }
4142 }
4143 }
4144
4145 {
4146 // Send DataChanged before deletion, so that we still know
4147 // which objects are in the range.
4148 // Afterwards they could be before/after the Position.
4149 SwDataChanged aTmp( rPam );
4150 }
4151
4152 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
4153 {
4154 m_rDoc.GetIDocumentUndoRedo().ClearRedo();
4155 bool bMerged(false);
4156 if (m_rDoc.GetIDocumentUndoRedo().DoesGroupUndo())
4157 {
4158 SwUndo *const pLastUndo( m_rDoc.GetUndoManager().GetLastUndo() );
4159 SwUndoDelete *const pUndoDelete(
4160 dynamic_cast<SwUndoDelete *>(pLastUndo) );
4161 if (pUndoDelete)
4162 {
4163 bMerged = pUndoDelete->CanGrouping(m_rDoc, rPam);
4164 // if CanGrouping() returns true it's already merged
4165 }
4166 }
4167 if (!bMerged)
4168 {
4169 m_rDoc.GetIDocumentUndoRedo().AppendUndo( std::make_unique<SwUndoDelete>( rPam ) );
4170 }
4171
4172 m_rDoc.getIDocumentState().SetModified();
4173
4174 return true;
4175 }
4176
4177 if( !m_rDoc.getIDocumentRedlineAccess().IsIgnoreRedline() && !m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().empty() )
4178 m_rDoc.getIDocumentRedlineAccess().DeleteRedline( rPam, true, RedlineType::Any );
4179
4180 // Delete and move all "Flys at the paragraph", which are within the Selection
4181 DelFlyInRange(rPam.GetMark()->nNode, rPam.GetPoint()->nNode,
4182 &rPam.GetMark()->nContent, &rPam.GetPoint()->nContent);
4183 DelBookmarks(
4184 pStt->nNode,
4185 pEnd->nNode,
4186 nullptr,
4187 &pStt->nContent,
4188 &pEnd->nContent);
4189
4190 SwNodeIndex aSttIdx( pStt->nNode );
4191 SwContentNode * pCNd = aSttIdx.GetNode().GetContentNode();
4192
4193 do { // middle checked loop!
4194 if( pCNd )
4195 {
4196 SwTextNode * pStartTextNode( pCNd->GetTextNode() );
4197 if ( pStartTextNode )
4198 {
4199 // now move the Content to the new Node
4200 bool bOneNd = pStt->nNode == pEnd->nNode;
4201 const sal_Int32 nLen = ( bOneNd ? pEnd->nContent.GetIndex()
4202 : pCNd->Len() )
4203 - pStt->nContent.GetIndex();
4204
4205 // Don't call again, if already empty
4206 if( nLen )
4207 {
4208 pStartTextNode->EraseText( pStt->nContent, nLen );
4209
4210 if( !pStartTextNode->Len() )
4211 {
4212 // METADATA: remove reference if empty (consider node deleted)
4213 pStartTextNode->RemoveMetadataReference();
4214 }
4215 }
4216
4217 if( bOneNd ) // that's it
4218 break;
4219
4220 ++aSttIdx;
4221 }
4222 else
4223 {
4224 // So that there are no indices left registered when deleted,
4225 // we remove a SwPaM from the Content here.
4226 pStt->nContent.Assign( nullptr, 0 );
4227 }
4228 }
4229
4230 pCNd = pEnd->nNode.GetNode().GetContentNode();
4231 if( pCNd )
4232 {
4233 SwTextNode * pEndTextNode( pCNd->GetTextNode() );
4234 if( pEndTextNode )
4235 {
4236 // if already empty, don't call again
4237 if( pEnd->nContent.GetIndex() )
4238 {
4239 SwIndex aIdx( pCNd, 0 );
4240 pEndTextNode->EraseText( aIdx, pEnd->nContent.GetIndex() );
4241
4242 if( !pEndTextNode->Len() )
4243 {
4244 // METADATA: remove reference if empty (consider node deleted)
4245 pEndTextNode->RemoveMetadataReference();
4246 }
4247 }
4248 }
4249 else
4250 {
4251 // So that there are no indices left registered when deleted,
4252 // we remove a SwPaM from the Content here.
4253 pEnd->nContent.Assign( nullptr, 0 );
4254 }
4255 }
4256
4257 // if the end is not a content node, delete it as well
4258 sal_uInt32 nEnd = pEnd->nNode.GetIndex();
4259 if( pCNd == nullptr )
4260 nEnd++;
4261
4262 if( aSttIdx != nEnd )
4263 {
4264 // tdf#134436 delete section nodes like SwUndoDelete::SwUndoDelete
4265 SwNode *pTmpNd;
4266 while (pEnd == rPam.GetPoint()
4267 && nEnd + 2 < m_rDoc.GetNodes().Count()
4268 && (pTmpNd = m_rDoc.GetNodes()[nEnd + 1])->IsEndNode()
4269 && pTmpNd->StartOfSectionNode()->IsSectionNode()
4270 && aSttIdx <= pTmpNd->StartOfSectionNode()->GetIndex())
4271 {
4272 SwNodeRange range(*pTmpNd->StartOfSectionNode(), *pTmpNd);
4273 m_rDoc.GetNodes().SectionUp(&range);
4274 --nEnd; // account for deleted start node
4275 }
4276
4277 // delete the Nodes from the NodesArray
4278 m_rDoc.GetNodes().Delete( aSttIdx, nEnd - aSttIdx.GetIndex() );
4279 }
4280
4281 // If the Node that contained the Cursor has been deleted,
4282 // the Content has to be assigned to the current Content.
4283 pStt->nContent.Assign( pStt->nNode.GetNode().GetContentNode(),
4284 pStt->nContent.GetIndex() );
4285
4286 // If we deleted across Node boundaries we have to correct the PaM,
4287 // because they are in different Nodes now.
4288 // Also, the Selection is revoked.
4289 *pEnd = *pStt;
4290 rPam.DeleteMark();
4291
4292 } while( false );
4293
4294 m_rDoc.getIDocumentState().SetModified();
4295
4296 return true;
4297}
4298
4299// It's possible to call Replace with a PaM that spans 2 paragraphs:
4300// search with regex for "$", then replace _all_
4301bool DocumentContentOperationsManager::ReplaceRangeImpl( SwPaM& rPam, const OUString& rStr,
4302 const bool bRegExReplace )
4303{
4304 if( !rPam.HasMark() || *rPam.GetPoint() == *rPam.GetMark() )
4305 return false;
4306
4307 bool bJoinText, bJoinPrev;
4308 ::sw_GetJoinFlags( rPam, bJoinText, bJoinPrev );
4309
4310 {
4311 // Create a copy of the Cursor in order to move all Pams from
4312 // the other views out of the deletion range.
4313 // Except for itself!
4314 SwPaM aDelPam( *rPam.GetMark(), *rPam.GetPoint() );
4315 ::PaMCorrAbs( aDelPam, *aDelPam.GetPoint() );
4316
4317 SwPosition *pStt = aDelPam.Start(),
4318 *pEnd = aDelPam.End();
4319 bool bOneNode = pStt->nNode == pEnd->nNode;
4320
4321 // Own Undo?
4322 OUString sRepl( rStr );
4323 SwTextNode* pTextNd = pStt->nNode.GetNode().GetTextNode();
4324 sal_Int32 nStt = pStt->nContent.GetIndex();
4325 sal_Int32 nEnd;
4326
4327 SwDataChanged aTmp( aDelPam );
4328
4329 if( m_rDoc.getIDocumentRedlineAccess().IsRedlineOn() )
4330 {
4331 RedlineFlags eOld = m_rDoc.getIDocumentRedlineAccess().GetRedlineFlags();
4332 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
4333 {
4334 // this should no longer happen in calls from the UI but maybe via API
4335 SAL_WARN_IF((eOld & RedlineFlags::ShowMask) != RedlineFlags::ShowMask,do { if (true && ((eOld & RedlineFlags::ShowMask)
!= RedlineFlags::ShowMask)) { 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() << "redlines will be moved in ReplaceRange"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"
), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
":" "4336" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "redlines will be moved in ReplaceRange"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "redlines will be moved in ReplaceRange"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
":" "4336" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "redlines will be moved in ReplaceRange") == 1) {
::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core")
, ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
":" "4336" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "redlines will be moved in ReplaceRange"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "redlines will be moved in ReplaceRange"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
":" "4336" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
4336 "sw.core", "redlines will be moved in ReplaceRange")do { if (true && ((eOld & RedlineFlags::ShowMask)
!= RedlineFlags::ShowMask)) { 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() << "redlines will be moved in ReplaceRange"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"
), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
":" "4336" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "redlines will be moved in ReplaceRange"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "redlines will be moved in ReplaceRange"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
":" "4336" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "redlines will be moved in ReplaceRange") == 1) {
::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core")
, ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
":" "4336" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "redlines will be moved in ReplaceRange"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "redlines will be moved in ReplaceRange"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"), ("/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
":" "4336" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
4337
4338 m_rDoc.GetIDocumentUndoRedo().StartUndo(SwUndoId::EMPTY, nullptr);
4339
4340 // If any Redline will change (split!) the node
4341 const ::sw::mark::IMark* pBkmk =
4342 m_rDoc.getIDocumentMarkAccess()->makeMark( aDelPam,
4343 OUString(), IDocumentMarkAccess::MarkType::UNO_BOOKMARK,
4344 ::sw::mark::InsertMode::New);
4345
4346 m_rDoc.getIDocumentRedlineAccess().SetRedlineFlags(
4347 RedlineFlags::On | RedlineFlags::ShowInsert | RedlineFlags::ShowDelete );
4348
4349 *aDelPam.GetPoint() = pBkmk->GetMarkPos();
4350 if(pBkmk->IsExpanded())
4351 *aDelPam.GetMark() = pBkmk->GetOtherMarkPos();
4352 m_rDoc.getIDocumentMarkAccess()->deleteMark(pBkmk);
4353 pStt = aDelPam.Start();
4354 pTextNd = pStt->nNode.GetNode().GetTextNode();
4355 nStt = pStt->nContent.GetIndex();
4356 }
4357
4358 if( !sRepl.isEmpty() )
4359 {
4360 // Apply the first character's attributes to the ReplaceText
4361 SfxItemSet aSet( m_rDoc.GetAttrPool(),
4362 svl::Items<RES_CHRATR_BEGIN, RES_TXTATR_WITHEND_END - 1,
4363 RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1>{} );
4364 pTextNd->GetParaAttr( aSet, nStt+1, nStt+1 );
4365
4366 aSet.ClearItem( RES_TXTATR_REFMARK );
4367 aSet.ClearItem( RES_TXTATR_TOXMARK );
4368 aSet.ClearItem( RES_TXTATR_CJK_RUBY );
4369 aSet.ClearItem( RES_TXTATR_INETFMT );
4370 aSet.ClearItem( RES_TXTATR_META );
4371 aSet.ClearItem( RES_TXTATR_METAFIELD );
4372
4373 if( aDelPam.GetPoint() != aDelPam.End() )
4374 aDelPam.Exchange();
4375
4376 // Remember the End
4377 SwNodeIndex aPtNd( aDelPam.GetPoint()->nNode, -1 );
4378 const sal_Int32 nPtCnt = aDelPam.GetPoint()->nContent.GetIndex();
4379
4380 bool bFirst = true;
4381 OUString sIns;
4382 while ( lcl_GetTokenToParaBreak( sRepl, sIns, bRegExReplace ) )
4383 {
4384 InsertString( aDelPam, sIns );
4385 if( bFirst )
4386 {
4387 SwNodeIndex aMkNd( aDelPam.GetMark()->nNode, -1 );
4388 const sal_Int32 nMkCnt = aDelPam.GetMark()->nContent.GetIndex();
4389
4390 SplitNode( *aDelPam.GetPoint(), false );
4391
4392 ++aMkNd;
4393 aDelPam.GetMark()->nNode = aMkNd;
4394 aDelPam.GetMark()->nContent.Assign(
4395 aMkNd.GetNode().GetContentNode(), nMkCnt );
4396 bFirst = false;
4397 }
4398 else
4399 SplitNode( *aDelPam.GetPoint(), false );
4400 }
4401 if( !sIns.isEmpty() )
4402 {
4403 InsertString( aDelPam, sIns );
4404 }
4405
4406 SwPaM aTmpRange( *aDelPam.GetPoint() );
4407 aTmpRange.SetMark();
4408
4409 ++aPtNd;
4410 aDelPam.GetPoint()->nNode = aPtNd;
4411 aDelPam.GetPoint()->nContent.Assign( aPtNd.GetNode().GetContentNode(),
4412 nPtCnt);
4413 *aTmpRange.GetMark() = *aDelPam.GetPoint();
4414
4415 m_rDoc.RstTextAttrs( aTmpRange );
4416 InsertItemSet( aTmpRange, aSet );
4417 }
4418
4419 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
4420 {
4421 m_rDoc.GetIDocumentUndoRedo().AppendUndo(
4422 std::make_unique<SwUndoRedlineDelete>( aDelPam, SwUndoId::REPLACE ));
4423 }
4424 m_rDoc.getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline( RedlineType::Delete, aDelPam ), true);
4425
4426 *rPam.GetMark() = *aDelPam.GetMark();
4427 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
4428 {
4429 *aDelPam.GetPoint() = *rPam.GetPoint();
4430 m_rDoc.GetIDocumentUndoRedo().EndUndo(SwUndoId::EMPTY, nullptr);
4431
4432 // If any Redline will change (split!) the node
4433 const ::sw::mark::IMark* pBkmk =
4434 m_rDoc.getIDocumentMarkAccess()->makeMark( aDelPam,
4435 OUString(), IDocumentMarkAccess::MarkType::UNO_BOOKMARK,
4436 ::sw::mark::InsertMode::New);
4437
4438 SwIndex& rIdx = aDelPam.GetPoint()->nContent;
4439 rIdx.Assign( nullptr, 0 );
4440 aDelPam.GetMark()->nContent = rIdx;
4441 rPam.GetPoint()->nNode = 0;
4442 rPam.GetPoint()->nContent = rIdx;
4443 *rPam.GetMark() = *rPam.GetPoint();
4444 m_rDoc.getIDocumentRedlineAccess().SetRedlineFlags( eOld );
4445
4446 *rPam.GetPoint() = pBkmk->GetMarkPos();
4447 if(pBkmk->IsExpanded())
4448 *rPam.GetMark() = pBkmk->GetOtherMarkPos();
4449 m_rDoc.getIDocumentMarkAccess()->deleteMark(pBkmk);
4450 }
4451 bJoinText = false;
4452 }
4453 else
4454 {
4455 assert((pStt->nNode == pEnd->nNode ||(static_cast <bool> ((pStt->nNode == pEnd->nNode ||
( pStt->nNode.GetIndex() + 1 == pEnd->nNode.GetIndex()
&& !pEnd->nContent.GetIndex() )) && "invalid range: Point and Mark on different nodes"
) ? void (0) : __assert_fail ("(pStt->nNode == pEnd->nNode || ( pStt->nNode.GetIndex() + 1 == pEnd->nNode.GetIndex() && !pEnd->nContent.GetIndex() )) && \"invalid range: Point and Mark on different nodes\""
, "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 4458, __extension__ __PRETTY_FUNCTION__))
4456 ( pStt->nNode.GetIndex() + 1 == pEnd->nNode.GetIndex() &&(static_cast <bool> ((pStt->nNode == pEnd->nNode ||
( pStt->nNode.GetIndex() + 1 == pEnd->nNode.GetIndex()
&& !pEnd->nContent.GetIndex() )) && "invalid range: Point and Mark on different nodes"
) ? void (0) : __assert_fail ("(pStt->nNode == pEnd->nNode || ( pStt->nNode.GetIndex() + 1 == pEnd->nNode.GetIndex() && !pEnd->nContent.GetIndex() )) && \"invalid range: Point and Mark on different nodes\""
, "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 4458, __extension__ __PRETTY_FUNCTION__))
4457 !pEnd->nContent.GetIndex() )) &&(static_cast <bool> ((pStt->nNode == pEnd->nNode ||
( pStt->nNode.GetIndex() + 1 == pEnd->nNode.GetIndex()
&& !pEnd->nContent.GetIndex() )) && "invalid range: Point and Mark on different nodes"
) ? void (0) : __assert_fail ("(pStt->nNode == pEnd->nNode || ( pStt->nNode.GetIndex() + 1 == pEnd->nNode.GetIndex() && !pEnd->nContent.GetIndex() )) && \"invalid range: Point and Mark on different nodes\""
, "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 4458, __extension__ __PRETTY_FUNCTION__))
4458 "invalid range: Point and Mark on different nodes" )(static_cast <bool> ((pStt->nNode == pEnd->nNode ||
( pStt->nNode.GetIndex() + 1 == pEnd->nNode.GetIndex()
&& !pEnd->nContent.GetIndex() )) && "invalid range: Point and Mark on different nodes"
) ? void (0) : __assert_fail ("(pStt->nNode == pEnd->nNode || ( pStt->nNode.GetIndex() + 1 == pEnd->nNode.GetIndex() && !pEnd->nContent.GetIndex() )) && \"invalid range: Point and Mark on different nodes\""
, "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 4458, __extension__ __PRETTY_FUNCTION__))
;
4459
4460 if( !m_rDoc.getIDocumentRedlineAccess().IsIgnoreRedline() && !m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().empty() )
4461 m_rDoc.getIDocumentRedlineAccess().DeleteRedline( aDelPam, true, RedlineType::Any );
4462
4463 SwUndoReplace* pUndoRpl = nullptr;
4464 bool const bDoesUndo = m_rDoc.GetIDocumentUndoRedo().DoesUndo();
4465 if (bDoesUndo)
4466 {
4467 pUndoRpl = new SwUndoReplace(aDelPam, sRepl, bRegExReplace);
4468 m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::unique_ptr<SwUndo>(pUndoRpl));
4469 }
4470 ::sw::UndoGuard const undoGuard(m_rDoc.GetIDocumentUndoRedo());
4471
4472 if( aDelPam.GetPoint() != pStt )
4473 aDelPam.Exchange();
4474
4475 SwNodeIndex aPtNd( pStt->nNode, -1 );
4476 const sal_Int32 nPtCnt = pStt->nContent.GetIndex();
4477
4478 // Set the values again, if Frames or footnotes on the Text have been removed.
4479 nStt = nPtCnt;
4480 nEnd = bOneNode ? pEnd->nContent.GetIndex()
4481 : pTextNd->GetText().getLength();
4482
4483 bool bFirst = true;
4484 OUString sIns;
4485 while ( lcl_GetTokenToParaBreak( sRepl, sIns, bRegExReplace ) )
4486 {
4487 if (!bFirst || nStt == pTextNd->GetText().getLength())
4488 {
4489 InsertString( aDelPam, sIns );
4490 }
4491 else if( nStt < nEnd || !sIns.isEmpty() )
4492 {
4493 pTextNd->ReplaceText( pStt->nContent, nEnd - nStt, sIns );
4494 }
4495 SplitNode( *pStt, false);
4496 bFirst = false;
4497 }
4498
4499 if( bFirst || !sIns.isEmpty() )
4500 {
4501 if (!bFirst || nStt == pTextNd->GetText().getLength())
4502 {
4503 InsertString( aDelPam, sIns );
4504 }
4505 else if( nStt < nEnd || !sIns.isEmpty() )
4506 {
4507 pTextNd->ReplaceText( pStt->nContent, nEnd - nStt, sIns );
4508 }
4509 }
4510
4511 *rPam.GetPoint() = *aDelPam.GetMark();
4512 ++aPtNd;
4513 rPam.GetMark()->nNode = aPtNd;
4514 rPam.GetMark()->nContent.Assign( aPtNd.GetNode().GetContentNode(),
4515 nPtCnt );
4516
4517 if (bJoinText)
4518 {
4519 assert(rPam.GetPoint() == rPam.End())(static_cast <bool> (rPam.GetPoint() == rPam.End()) ? void
(0) : __assert_fail ("rPam.GetPoint() == rPam.End()", "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 4519, __extension__ __PRETTY_FUNCTION__))
;
4520 // move so that SetEnd remembers position after sw_JoinText
4521 rPam.Move(fnMoveBackward);
4522 }
4523 else if (aDelPam.GetPoint() == pStt) // backward selection?
4524 {
4525 assert(*rPam.GetMark() <= *rPam.GetPoint())(static_cast <bool> (*rPam.GetMark() <= *rPam.GetPoint
()) ? void (0) : __assert_fail ("*rPam.GetMark() <= *rPam.GetPoint()"
, "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 4525, __extension__ __PRETTY_FUNCTION__))
;
4526 rPam.Exchange(); // swap so that rPam is backwards
4527 }
4528
4529 if( pUndoRpl )
4530 {
4531 pUndoRpl->SetEnd(rPam);
4532 }
4533 }
4534 }
4535
4536 bool bRet(true);
4537 if (bJoinText)
4538 {
4539 bRet = ::sw_JoinText(rPam, bJoinPrev);
4540 }
4541
4542 m_rDoc.getIDocumentState().SetModified();
4543 return bRet;
4544}
4545
4546SwFlyFrameFormat* DocumentContentOperationsManager::InsNoTextNode( const SwPosition& rPos, SwNoTextNode* pNode,
4547 const SfxItemSet* pFlyAttrSet,
4548 const SfxItemSet* pGrfAttrSet,
4549 SwFrameFormat* pFrameFormat)
4550{
4551 SwFlyFrameFormat *pFormat = nullptr;
4552 if( pNode )
4553 {
4554 pFormat = m_rDoc.MakeFlySection_( rPos, *pNode, RndStdIds::FLY_AT_PARA,
4555 pFlyAttrSet, pFrameFormat );
4556 if( pGrfAttrSet )
4557 pNode->SetAttr( *pGrfAttrSet );
4558 }
4559 return pFormat;
4560}
4561
4562#define NUMRULE_STATESfxItemState aNumRuleState = SfxItemState::UNKNOWN; std::shared_ptr
<SwNumRuleItem> aNumRuleItem; SfxItemState aListIdState
= SfxItemState::UNKNOWN; std::shared_ptr<SfxStringItem>
aListIdItem;
\
4563 SfxItemState aNumRuleState = SfxItemState::UNKNOWN; \
4564 std::shared_ptr<SwNumRuleItem> aNumRuleItem; \
4565 SfxItemState aListIdState = SfxItemState::UNKNOWN; \
4566 std::shared_ptr<SfxStringItem> aListIdItem; \
4567
4568#define PUSH_NUMRULE_STATElcl_PushNumruleState( aNumRuleState, aNumRuleItem, aListIdState
, aListIdItem, pDestTextNd );
\
4569 lcl_PushNumruleState( aNumRuleState, aNumRuleItem, aListIdState, aListIdItem, pDestTextNd );
4570
4571#define POP_NUMRULE_STATElcl_PopNumruleState( aNumRuleState, aNumRuleItem, aListIdState
, aListIdItem, pDestTextNd, rPam );
\
4572 lcl_PopNumruleState( aNumRuleState, aNumRuleItem, aListIdState, aListIdItem, pDestTextNd, rPam );
4573
4574static void lcl_PushNumruleState(
4575 SfxItemState &aNumRuleState, std::shared_ptr<SwNumRuleItem>& aNumRuleItem,
4576 SfxItemState &aListIdState, std::shared_ptr<SfxStringItem>& aListIdItem,
4577 const SwTextNode *pDestTextNd )
4578{
4579 // Safe numrule item at destination.
4580 // #i86492# - Safe also <ListId> item of destination.
4581 const SfxItemSet * pAttrSet = pDestTextNd->GetpSwAttrSet();
4582 if (pAttrSet == nullptr)
4583 return;
4584
4585 const SfxPoolItem * pItem = nullptr;
4586 aNumRuleState = pAttrSet->GetItemState(RES_PARATR_NUMRULE, false, &pItem);
4587 if (SfxItemState::SET == aNumRuleState)
4588 {
4589 aNumRuleItem.reset(static_cast<SwNumRuleItem*>(pItem->Clone()));
4590 }
4591
4592 aListIdState = pAttrSet->GetItemState(RES_PARATR_LIST_ID, false, &pItem);
4593 if (SfxItemState::SET == aListIdState)
4594 {
4595 aListIdItem.reset(static_cast<SfxStringItem*>(pItem->Clone()));
4596 }
4597}
4598
4599static void lcl_PopNumruleState(
4600 SfxItemState aNumRuleState, const std::shared_ptr<SwNumRuleItem>& aNumRuleItem,
4601 SfxItemState aListIdState, const std::shared_ptr<SfxStringItem>& aListIdItem,
4602 SwTextNode *pDestTextNd, const SwPaM& rPam )
4603{
4604 /* If only a part of one paragraph is copied
4605 restore the numrule at the destination. */
4606 // #i86492# - restore also <ListId> item
4607 if ( lcl_MarksWholeNode(rPam) )
4608 return;
4609
4610 if (SfxItemState::SET == aNumRuleState)
4611 {
4612 pDestTextNd->SetAttr(*aNumRuleItem);
4613 }
4614 else
4615 {
4616 pDestTextNd->ResetAttr(RES_PARATR_NUMRULE);
4617 }
4618 if (SfxItemState::SET == aListIdState)
4619 {
4620 pDestTextNd->SetAttr(*aListIdItem);
4621 }
4622 else
4623 {
4624 pDestTextNd->ResetAttr(RES_PARATR_LIST_ID);
4625 }
4626}
4627
4628bool DocumentContentOperationsManager::CopyImpl(SwPaM& rPam, SwPosition& rPos,
4629 SwCopyFlags const flags,
4630 SwPaM *const pCopyRange) const
4631{
4632 std::vector<std::pair<sal_uLong, sal_Int32>> Breaks;
4633
4634 sw::CalcBreaks(Breaks, rPam, true);
4635
4636 if (Breaks.empty())
4637 {
4638 return CopyImplImpl(rPam, rPos, flags, pCopyRange);
4639 }
4640
4641 SwPosition const & rSelectionEnd( *rPam.End() );
4642
4643 bool bRet(true);
4644 bool bFirst(true);
4645 // iterate from end to start, ... don't think it's necessary here?
4646 auto iter( Breaks.rbegin() );
4647 sal_uLong nOffset(0);
4648 SwNodes const& rNodes(rPam.GetPoint()->nNode.GetNodes());
4649 SwPaM aPam( rSelectionEnd, rSelectionEnd ); // end node!
4650 SwPosition & rEnd( *aPam.End() );
4651 SwPosition & rStart( *aPam.Start() );
4652 SwPaM copyRange(rPos, rPos);
4653
4654 while (iter != Breaks.rend())
4655 {
4656 rStart = SwPosition(*rNodes[iter->first - nOffset]->GetTextNode(), iter->second + 1);
4657 if (rStart < rEnd) // check if part is empty
4658 {
4659 // pass in copyRange member as rPos; should work ...
4660 bRet &= CopyImplImpl(aPam, *copyRange.Start(), flags & ~SwCopyFlags::IsMoveToFly, &copyRange);
4661 nOffset = iter->first - rStart.nNode.GetIndex(); // fly nodes...
4662 if (pCopyRange)
4663 {
4664 if (bFirst)
4665 {
4666 pCopyRange->SetMark();
4667 *pCopyRange->GetMark() = *copyRange.End();
4668 }
4669 *pCopyRange->GetPoint() = *copyRange.Start();
4670 }
4671 bFirst = false;
4672 }
4673 rEnd = SwPosition(*rNodes[iter->first - nOffset]->GetTextNode(), iter->second);
4674 ++iter;
4675 }
4676
4677 rStart = *rPam.Start(); // set to original start
4678 if (rStart < rEnd) // check if part is empty
4679 {
4680 bRet &= CopyImplImpl(aPam, *copyRange.Start(), flags & ~SwCopyFlags::IsMoveToFly, &copyRange);
4681 if (pCopyRange)
4682 {
4683 if (bFirst)
4684 {
4685 pCopyRange->SetMark();
4686 *pCopyRange->GetMark() = *copyRange.End();
4687 }
4688 *pCopyRange->GetPoint() = *copyRange.Start();
4689 }
4690 }
4691
4692 return bRet;
4693}
4694
4695bool DocumentContentOperationsManager::CopyImplImpl(SwPaM& rPam, SwPosition& rPos,
4696 SwCopyFlags const flags,
4697 SwPaM *const pCpyRange) const
4698{
4699 SwDoc& rDoc = rPos.nNode.GetNode().GetDoc();
4700 const bool bColumnSel = rDoc.IsClipBoard() && rDoc.IsColumnSelection();
1
Assuming the condition is false
4701
4702 SwPosition const*const pStt = rPam.Start();
4703 SwPosition *const pEnd = rPam.End();
4704
4705 // Catch when there's no copy to do.
4706 if (!rPam.HasMark() || (IsEmptyRange(*pStt, *pEnd, flags) && !bColumnSel) ||
2
Calling 'SwPaM::HasMark'
5
Returning from 'SwPaM::HasMark'
6
Calling 'IsEmptyRange'
10
Returning from 'IsEmptyRange'
11
Assuming the condition is false
4707 //JP 29.6.2001: 88963 - don't copy if inspos is in region of start to end
4708 //JP 15.11.2001: don't test inclusive the end, ever exclusive
4709 ( &rDoc == &m_rDoc && *pStt <= rPos && rPos < *pEnd ))
12
Assuming the condition is false
4710 {
4711 return false;
4712 }
4713
4714 const bool bEndEqualIns = &rDoc == &m_rDoc && rPos == *pEnd;
4715
4716 // If Undo is enabled, create the UndoCopy object
4717 SwUndoCpyDoc* pUndo = nullptr;
13
'pUndo' initialized to a null pointer value
4718 // lcl_DeleteRedlines may delete the start or end node of the cursor when
4719 // removing the redlines so use cursor that is corrected by PaMCorrAbs
4720 std::shared_ptr<SwUnoCursor> const pCopyPam(rDoc.CreateUnoCursor(rPos));
4721
4722 SwTableNumFormatMerge aTNFM( m_rDoc, rDoc );
4723 std::unique_ptr<std::vector<SwFrameFormat*>> pFlys;
4724 std::vector<SwFrameFormat*> const* pFlysAtInsPos;
4725
4726 if (rDoc.GetIDocumentUndoRedo().DoesUndo())
14
Assuming the condition is false
15
Taking false branch
4727 {
4728 pUndo = new SwUndoCpyDoc(*pCopyPam);
4729 rDoc.GetIDocumentUndoRedo().AppendUndo( std::unique_ptr<SwUndo>(pUndo) );
4730 pFlysAtInsPos = pUndo->GetFlysAnchoredAt();
4731 }
4732 else
4733 {
4734 pFlys = sw::GetFlysAnchoredAt(rDoc, rPos.nNode.GetIndex());
16
Calling defaulted move assignment operator for 'unique_ptr<std::vector<SwFrameFormat *, std::allocator<SwFrameFormat *>>, std::default_delete<std::vector<SwFrameFormat *, std::allocator<SwFrameFormat *>>>>'
44
Returning from move assignment operator for 'unique_ptr<std::vector<SwFrameFormat *, std::allocator<SwFrameFormat *>>, std::default_delete<std::vector<SwFrameFormat *, std::allocator<SwFrameFormat *>>>>'
4735 pFlysAtInsPos = pFlys.get();
4736 }
4737
4738 RedlineFlags eOld = rDoc.getIDocumentRedlineAccess().GetRedlineFlags();
4739 rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern(eOld | RedlineFlags::Ignore);
4740
4741 // Move the PaM one node back from the insert position, so that
4742 // the position doesn't get moved
4743 pCopyPam->SetMark();
4744 bool bCanMoveBack = pCopyPam->Move(fnMoveBackward, GoInContent);
4745 // If the position was shifted from more than one node, an end node has been skipped
4746 bool bAfterTable = false;
4747 if ((rPos.nNode.GetIndex() - pCopyPam->GetPoint()->nNode.GetIndex()) > 1)
45
Assuming the condition is false
46
Taking false branch
4748 {
4749 // First go back to the original place
4750 pCopyPam->GetPoint()->nNode = rPos.nNode;
4751 pCopyPam->GetPoint()->nContent = rPos.nContent;
4752
4753 bCanMoveBack = false;
4754 bAfterTable = true;
4755 }
4756 if( !bCanMoveBack )
47
Assuming 'bCanMoveBack' is true
48
Taking false branch
4757 {
4758 pCopyPam->GetPoint()->nNode--;
4759 assert(pCopyPam->GetPoint()->nContent.GetIndex() == 0)(static_cast <bool> (pCopyPam->GetPoint()->nContent
.GetIndex() == 0) ? void (0) : __assert_fail ("pCopyPam->GetPoint()->nContent.GetIndex() == 0"
, "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 4759, __extension__ __PRETTY_FUNCTION__))
;
4760 }
4761
4762 SwNodeRange aRg( pStt->nNode, pEnd->nNode );
4763 SwNodeIndex aInsPos( rPos.nNode );
4764 const bool bOneNode = pStt->nNode == pEnd->nNode;
4765 SwTextNode* pSttTextNd = pStt->nNode.GetNode().GetTextNode();
49
Calling 'SwNode::GetTextNode'
53
Returning from 'SwNode::GetTextNode'
4766 SwTextNode* pEndTextNd = pEnd->nNode.GetNode().GetTextNode();
4767 SwTextNode* pDestTextNd = aInsPos.GetNode().GetTextNode();
4768 bool bCopyCollFormat = !rDoc.IsInsOnlyTextGlossary() &&
54
Assuming the condition is false
4769 ( (pDestTextNd && !pDestTextNd->GetText().getLength()) ||
4770 ( !bOneNode && !rPos.nContent.GetIndex() ) );
4771 bool bCopyBookmarks = true;
4772 bool bCopyPageSource = false;
4773 int nDeleteTextNodes = 0;
4774
4775 // #i104585# copy outline num rule to clipboard (for ASCII filter)
4776 if (rDoc.IsClipBoard() && m_rDoc.GetOutlineNumRule())
55
Assuming the condition is false
4777 {
4778 rDoc.SetOutlineNumRule(*m_rDoc.GetOutlineNumRule());
4779 }
4780
4781 // #i86492#
4782 // Correct the search for a previous list:
4783 // First search for non-outline numbering list. Then search for non-outline
4784 // bullet list.
4785 // Keep also the <ListId> value for possible propagation.
4786 OUString aListIdToPropagate;
4787 const SwNumRule* pNumRuleToPropagate =
4788 rDoc.SearchNumRule( rPos, false, true, false, 0, aListIdToPropagate, nullptr, true );
4789 if ( !pNumRuleToPropagate )
56
Assuming 'pNumRuleToPropagate' is non-null
57
Taking false branch
4790 {
4791 pNumRuleToPropagate =
4792 rDoc.SearchNumRule( rPos, false, false, false, 0, aListIdToPropagate, nullptr, true );
4793 }
4794 // #i86492#
4795 // Do not propagate previous found list, if
4796 // - destination is an empty paragraph which is not in a list and
4797 // - source contains at least one paragraph which is not in a list
4798 if ( pNumRuleToPropagate
57.1
'pNumRuleToPropagate' is non-null
57.1
'pNumRuleToPropagate' is non-null
57.1
'pNumRuleToPropagate' is non-null
57.1
'pNumRuleToPropagate' is non-null
57.1
'pNumRuleToPropagate' is non-null
57.1
'pNumRuleToPropagate' is non-null
57.1
'pNumRuleToPropagate' is non-null
&&
4799 pDestTextNd
57.2
'pDestTextNd' is null
57.2
'pDestTextNd' is null
57.2
'pDestTextNd' is null
57.2
'pDestTextNd' is null
57.2
'pDestTextNd' is null
57.2
'pDestTextNd' is null
57.2
'pDestTextNd' is null
&& !pDestTextNd->GetText().getLength() &&
4800 !pDestTextNd->IsInList() &&
4801 !lcl_ContainsOnlyParagraphsInList( rPam ) )
4802 {
4803 pNumRuleToPropagate = nullptr;
4804 }
4805
4806 // This do/while block is only there so that we can break out of it!
4807 do {
72
Loop condition is false. Exiting loop
4808 if( pSttTextNd
57.3
'pSttTextNd' is null
57.3
'pSttTextNd' is null
57.3
'pSttTextNd' is null
57.3
'pSttTextNd' is null
57.3
'pSttTextNd' is null
57.3
'pSttTextNd' is null
57.3
'pSttTextNd' is null
)
58
Taking false branch
4809 {
4810 ++nDeleteTextNodes; // must be joined in Undo
4811 // Don't copy the beginning completely?
4812 if( !bCopyCollFormat || bColumnSel || pStt->nContent.GetIndex() )
4813 {
4814 SwIndex aDestIdx( rPos.nContent );
4815 bool bCopyOk = false;
4816 if( !pDestTextNd )
4817 {
4818 if( pStt->nContent.GetIndex() || bOneNode )
4819 pDestTextNd = rDoc.GetNodes().MakeTextNode( aInsPos,
4820 rDoc.getIDocumentStylePoolAccess().GetTextCollFromPool(RES_POOLCOLL_STANDARD));
4821 else
4822 {
4823 pDestTextNd = pSttTextNd->MakeCopy(rDoc, aInsPos, true)->GetTextNode();
4824 bCopyOk = true;
4825 }
4826 aDestIdx.Assign( pDestTextNd, 0 );
4827 bCopyCollFormat = true;
4828 }
4829 else if( !bOneNode || bColumnSel )
4830 {
4831 const sal_Int32 nContentEnd = pEnd->nContent.GetIndex();
4832 {
4833 ::sw::UndoGuard const ug(rDoc.GetIDocumentUndoRedo());
4834 rDoc.getIDocumentContentOperations().SplitNode( rPos, false );
4835 }
4836
4837 if (bCanMoveBack && rPos == *pCopyPam->GetPoint())
4838 {
4839 // after the SplitNode, span the CpyPam correctly again
4840 pCopyPam->Move( fnMoveBackward, GoInContent );
4841 pCopyPam->Move( fnMoveBackward, GoInContent );
4842 }
4843
4844 pDestTextNd = rDoc.GetNodes()[ aInsPos.GetIndex()-1 ]->GetTextNode();
4845 aDestIdx.Assign(
4846 pDestTextNd, pDestTextNd->GetText().getLength());
4847
4848 // Correct the area again
4849 if( bEndEqualIns )
4850 {
4851 bool bChg = pEnd != rPam.GetPoint();
4852 if( bChg )
4853 rPam.Exchange();
4854 rPam.Move( fnMoveBackward, GoInContent );
4855 if( bChg )
4856 rPam.Exchange();
4857 }
4858 else if( rPos == *pEnd )
4859 {
4860 // The end was also moved
4861 pEnd->nNode--;
4862 pEnd->nContent.Assign( pDestTextNd, nContentEnd );
4863 }
4864 // tdf#63022 always reset pEndTextNd after SplitNode
4865 aRg.aEnd = pEnd->nNode;
4866 pEndTextNd = pEnd->nNode.GetNode().GetTextNode();
4867 }
4868
4869 NUMRULE_STATESfxItemState aNumRuleState = SfxItemState::UNKNOWN; std::shared_ptr
<SwNumRuleItem> aNumRuleItem; SfxItemState aListIdState
= SfxItemState::UNKNOWN; std::shared_ptr<SfxStringItem>
aListIdItem;
4870 if( bCopyCollFormat && bOneNode )
4871 {
4872 PUSH_NUMRULE_STATElcl_PushNumruleState( aNumRuleState, aNumRuleItem, aListIdState
, aListIdItem, pDestTextNd );
4873 }
4874
4875 if( !bCopyOk )
4876 {
4877 const sal_Int32 nCpyLen = ( bOneNode
4878 ? pEnd->nContent.GetIndex()
4879 : pSttTextNd->GetText().getLength())
4880 - pStt->nContent.GetIndex();
4881 pSttTextNd->CopyText( pDestTextNd, aDestIdx,
4882 pStt->nContent, nCpyLen );
4883 if( bEndEqualIns )
4884 pEnd->nContent -= nCpyLen;
4885 }
4886
4887 aRg.aStart++;
4888
4889 if( bOneNode )
4890 {
4891 if (bCopyCollFormat)
4892 {
4893 pSttTextNd->CopyCollFormat( *pDestTextNd );
4894 POP_NUMRULE_STATElcl_PopNumruleState( aNumRuleState, aNumRuleItem, aListIdState
, aListIdItem, pDestTextNd, rPam );
4895 }
4896
4897 // copy at-char flys in rPam
4898 SwNodeIndex temp(*pDestTextNd); // update to new (start) node for flys
4899 // tdf#126626 prevent duplicate Undos
4900 ::sw::UndoGuard const ug(rDoc.GetIDocumentUndoRedo());
4901 CopyFlyInFlyImpl(aRg, &rPam, temp, false);
4902
4903 break;
4904 }
4905 }
4906 }
4907 else if( pDestTextNd
58.1
'pDestTextNd' is null
58.1
'pDestTextNd' is null
58.1
'pDestTextNd' is null
58.1
'pDestTextNd' is null
58.1
'pDestTextNd' is null
58.1
'pDestTextNd' is null
58.1
'pDestTextNd' is null
)
59
Taking false branch
4908 {
4909 // Problems with insertion of table selections into "normal" text solved.
4910 // We have to set the correct PaM for Undo, if this PaM starts in a textnode,
4911 // the undo operation will try to merge this node after removing the table.
4912 // If we didn't split a textnode, the PaM should start at the inserted table node
4913 if( rPos.nContent.GetIndex() == pDestTextNd->Len() )
4914 { // Insertion at the last position of a textnode (empty or not)
4915 ++aInsPos; // The table will be inserted behind the text node
4916 }
4917 else if( rPos.nContent.GetIndex() )
4918 { // Insertion in the middle of a text node, it has to be split
4919 // (and joined from undo)
4920 ++nDeleteTextNodes;
4921
4922 const sal_Int32 nContentEnd = pEnd->nContent.GetIndex();
4923 {
4924 ::sw::UndoGuard const ug(rDoc.GetIDocumentUndoRedo());
4925 rDoc.getIDocumentContentOperations().SplitNode( rPos, false );
4926 }
4927
4928 if (bCanMoveBack && rPos == *pCopyPam->GetPoint())
4929 {
4930 // after the SplitNode, span the CpyPam correctly again
4931 pCopyPam->Move( fnMoveBackward, GoInContent );
4932 pCopyPam->Move( fnMoveBackward, GoInContent );
4933 }
4934
4935 // Correct the area again
4936 if( bEndEqualIns )
4937 aRg.aEnd--;
4938 // The end would also be moved
4939 else if( rPos == *pEnd )
4940 {
4941 rPos.nNode-=2;
4942 rPos.nContent.Assign( rPos.nNode.GetNode().GetContentNode(),
4943 nContentEnd );
4944 rPos.nNode++;
4945 aRg.aEnd--;
4946 }
4947 }
4948 else if( bCanMoveBack )
4949 { // Insertion at the first position of a text node. It will not be split, the table
4950 // will be inserted before the text node.
4951 // See below, before the SetInsertRange function of the undo object will be called,
4952 // the CpyPam would be moved to the next content position. This has to be avoided
4953 // We want to be moved to the table node itself thus we have to set bCanMoveBack
4954 // and to manipulate pCopyPam.
4955 bCanMoveBack = false;
4956 pCopyPam->GetPoint()->nNode--;
4957 }
4958 }
4959
4960 pDestTextNd = aInsPos.GetNode().GetTextNode();
4961 if (pEndTextNd
59.1
'pEndTextNd' is null
59.1
'pEndTextNd' is null
59.1
'pEndTextNd' is null
59.1
'pEndTextNd' is null
59.1
'pEndTextNd' is null
59.1
'pEndTextNd' is null
59.1
'pEndTextNd' is null
)
60
Taking false branch
4962 {
4963 SwIndex aDestIdx( rPos.nContent );
4964 if( !pDestTextNd )
4965 {
4966 pDestTextNd = rDoc.GetNodes().MakeTextNode( aInsPos,
4967 rDoc.getIDocumentStylePoolAccess().GetTextCollFromPool(RES_POOLCOLL_STANDARD));
4968 aDestIdx.Assign( pDestTextNd, 0 );
4969 aInsPos--;
4970
4971 // if we have to insert an extra text node
4972 // at the destination, this node will be our new destination
4973 // (text) node, and thus we increment nDeleteTextNodes. This
4974 // will ensure that this node will be deleted during Undo.
4975 ++nDeleteTextNodes; // must be deleted
4976 }
4977
4978 const bool bEmptyDestNd = pDestTextNd->GetText().isEmpty();
4979
4980 NUMRULE_STATESfxItemState aNumRuleState = SfxItemState::UNKNOWN; std::shared_ptr
<SwNumRuleItem> aNumRuleItem; SfxItemState aListIdState
= SfxItemState::UNKNOWN; std::shared_ptr<SfxStringItem>
aListIdItem;
4981 if( bCopyCollFormat && ( bOneNode || bEmptyDestNd ))
4982 {
4983 PUSH_NUMRULE_STATElcl_PushNumruleState( aNumRuleState, aNumRuleItem, aListIdState
, aListIdItem, pDestTextNd );
4984 }
4985
4986 pEndTextNd->CopyText( pDestTextNd, aDestIdx, SwIndex( pEndTextNd ),
4987 pEnd->nContent.GetIndex() );
4988
4989 // Also copy all format templates
4990 if( bCopyCollFormat && ( bOneNode || bEmptyDestNd ))
4991 {
4992 pEndTextNd->CopyCollFormat( *pDestTextNd );
4993 if ( bOneNode )
4994 {
4995 POP_NUMRULE_STATElcl_PopNumruleState( aNumRuleState, aNumRuleItem, aListIdState
, aListIdItem, pDestTextNd, rPam );
4996 }
4997 }
4998 }
4999
5000 SfxItemSet aBrkSet( rDoc.GetAttrPool(), aBreakSetRange );
5001 if ((flags & SwCopyFlags::CopyAll) || aRg.aStart != aRg.aEnd)
61
Taking false branch
5002 {
5003 if (pSttTextNd && bCopyCollFormat && pDestTextNd->HasSwAttrSet())
5004 {
5005 aBrkSet.Put( *pDestTextNd->GetpSwAttrSet() );
5006 if( SfxItemState::SET == aBrkSet.GetItemState( RES_BREAK, false ) )
5007 pDestTextNd->ResetAttr( RES_BREAK );
5008 if( SfxItemState::SET == aBrkSet.GetItemState( RES_PAGEDESC, false ) )
5009 pDestTextNd->ResetAttr( RES_PAGEDESC );
5010 }
5011 }
5012
5013 {
5014 SwPosition startPos(SwNodeIndex(pCopyPam->GetPoint()->nNode, +1),
5015 SwIndex(SwNodeIndex(pCopyPam->GetPoint()->nNode, +1).GetNode().GetContentNode()));
5016 if (bCanMoveBack
61.1
'bCanMoveBack' is true
61.1
'bCanMoveBack' is true
61.1
'bCanMoveBack' is true
61.1
'bCanMoveBack' is true
61.1
'bCanMoveBack' is true
61.1
'bCanMoveBack' is true
61.1
'bCanMoveBack' is true
)
62
Taking true branch
5017 { // pCopyPam is actually 1 before the copy range so move it fwd
5018 SwPaM temp(*pCopyPam->GetPoint());
5019 temp.Move(fnMoveForward, GoInContent);
5020 startPos = *temp.GetPoint();
5021 }
5022 assert(startPos.nNode.GetNode().IsContentNode())(static_cast <bool> (startPos.nNode.GetNode().IsContentNode
()) ? void (0) : __assert_fail ("startPos.nNode.GetNode().IsContentNode()"
, "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 5022, __extension__ __PRETTY_FUNCTION__))
;
63
'?' condition is true
5023 std::pair<SwPaM const&, SwPosition const&> tmp(rPam, startPos);
5024 if( aInsPos == pEnd->nNode )
64
Calling 'SwNodeIndex::operator=='
67
Returning from 'SwNodeIndex::operator=='
68
Taking false branch
5025 {
5026 SwNodeIndex aSaveIdx( aInsPos, -1 );
5027 assert(pStt->nNode != pEnd->nNode)(static_cast <bool> (pStt->nNode != pEnd->nNode) ?
void (0) : __assert_fail ("pStt->nNode != pEnd->nNode"
, "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 5027, __extension__ __PRETTY_FUNCTION__))
;
5028 pEnd->nContent = 0; // TODO why this?
5029 CopyWithFlyInFly(aRg, aInsPos, &tmp, /*bMakeNewFrames*/true, false, /*bCopyFlyAtFly=*/false, flags);
5030 ++aSaveIdx;
5031 pEnd->nNode = aSaveIdx;
5032 pEnd->nContent.Assign( aSaveIdx.GetNode().GetTextNode(), 0 );
5033 }
5034 else
5035 CopyWithFlyInFly(aRg, aInsPos, &tmp, /*bMakeNewFrames*/true, false, /*bCopyFlyAtFly=*/false, flags);
5036
5037 bCopyBookmarks = false;
5038 }
5039
5040 // at-char anchors post SplitNode are on index 0 of 2nd node and will
5041 // remain there - move them back to the start (end would also work?)
5042 // ... also for at-para anchors; here start is preferable because
5043 // it's consistent with SplitNode from SwUndoInserts::RedoImpl()
5044 if (pFlysAtInsPos)
69
Assuming 'pFlysAtInsPos' is null
70
Taking false branch
5045 {
5046 // init *again* - because CopyWithFlyInFly moved startPos
5047 SwPosition startPos(SwNodeIndex(pCopyPam->GetPoint()->nNode, +1),
5048 SwIndex(SwNodeIndex(pCopyPam->GetPoint()->nNode, +1).GetNode().GetContentNode()));
5049 if (bCanMoveBack)
5050 { // pCopyPam is actually 1 before the copy range so move it fwd
5051 SwPaM temp(*pCopyPam->GetPoint());
5052 temp.Move(fnMoveForward, GoInContent);
5053 startPos = *temp.GetPoint();
5054 }
5055 assert(startPos.nNode.GetNode().IsContentNode())(static_cast <bool> (startPos.nNode.GetNode().IsContentNode
()) ? void (0) : __assert_fail ("startPos.nNode.GetNode().IsContentNode()"
, "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 5055, __extension__ __PRETTY_FUNCTION__))
;
5056 SwPosition startPosAtPara(startPos);
5057 startPosAtPara.nContent.Assign(nullptr, 0);
5058
5059 for (SwFrameFormat * pFly : *pFlysAtInsPos)
5060 {
5061 SwFormatAnchor const*const pAnchor = &pFly->GetAnchor();
5062 if (pAnchor->GetAnchorId() == RndStdIds::FLY_AT_CHAR)
5063 {
5064 SwFormatAnchor anchor(*pAnchor);
5065 anchor.SetAnchor( &startPos );
5066 pFly->SetFormatAttr(anchor);
5067 }
5068 else if (pAnchor->GetAnchorId() == RndStdIds::FLY_AT_PARA)
5069 {
5070 SwFormatAnchor anchor(*pAnchor);
5071 anchor.SetAnchor( &startPosAtPara );
5072 pFly->SetFormatAttr(anchor);
5073 }
5074 }
5075 }
5076
5077 if ((flags & SwCopyFlags::CopyAll) || aRg.aStart != aRg.aEnd)
71
Taking false branch
5078 {
5079 // Put the breaks back into the first node
5080 if( aBrkSet.Count() && nullptr != ( pDestTextNd = rDoc.GetNodes()[
5081 pCopyPam->GetPoint()->nNode.GetIndex()+1 ]->GetTextNode()))
5082 {
5083 pDestTextNd->SetAttr( aBrkSet );
5084 bCopyPageSource = true;
5085 }
5086 }
5087 } while( false );
5088
5089
5090 // it is not possible to make this test when copy from the clipBoard to document
5091 // in this case the PageNum not exist anymore
5092 // tdf#39400 and tdf#97526
5093 // when copy from document to ClipBoard, and it is from the first page
5094 // and not the source has the page break
5095 if (rDoc.IsClipBoard() && (rPam.GetPageNum(pStt == rPam.GetPoint()) == 1) && !bCopyPageSource)
73
Assuming the condition is false
5096 {
5097 pDestTextNd->ResetAttr(RES_BREAK); // remove the page-break
5098 pDestTextNd->ResetAttr(RES_PAGEDESC);
5099 }
5100
5101
5102 // Adjust position (in case it was moved / in another node)
5103 rPos.nContent.Assign( rPos.nNode.GetNode().GetContentNode(),
5104 rPos.nContent.GetIndex() );
5105
5106 if( rPos.nNode != aInsPos )
74
Taking false branch
5107 {
5108 pCopyPam->GetMark()->nNode = aInsPos;
5109 if (aInsPos < rPos.nNode)
5110 { // tdf#134250 decremented in (pEndTextNd && !pDestTextNd) above
5111 pCopyPam->GetContentNode(false)->MakeEndIndex(&pCopyPam->GetMark()->nContent);
5112 }
5113 else // incremented in (!pSttTextNd && pDestTextNd) above
5114 {
5115 pCopyPam->GetMark()->nContent.Assign(pCopyPam->GetContentNode(false), 0);
5116 }
5117 rPos = *pCopyPam->GetMark();
5118 }
5119 else
5120 *pCopyPam->GetMark() = rPos;
5121
5122 if ( !bAfterTable
74.1
'bAfterTable' is false
74.1
'bAfterTable' is false
74.1
'bAfterTable' is false
74.1
'bAfterTable' is false
74.1
'bAfterTable' is false
74.1
'bAfterTable' is false
74.1
'bAfterTable' is false
)
75
Taking true branch
5123 pCopyPam->Move( fnMoveForward, bCanMoveBack
75.1
'bCanMoveBack' is true
75.1
'bCanMoveBack' is true
75.1
'bCanMoveBack' is true
75.1
'bCanMoveBack' is true
75.1
'bCanMoveBack' is true
75.1
'bCanMoveBack' is true
75.1
'bCanMoveBack' is true
? GoInContent : GoInNode );
76
'?' condition is true
5124 else
5125 {
5126 pCopyPam->GetPoint()->nNode++;
5127
5128 // Reset the offset to 0 as it was before the insertion
5129 pCopyPam->GetPoint()->nContent.Assign(pCopyPam->GetPoint()->nNode.GetNode().GetContentNode(), 0);
5130 // If the next node is a start node, then step back: the start node
5131 // has been copied and needs to be in the selection for the undo
5132 if (pCopyPam->GetPoint()->nNode.GetNode().IsStartNode())
5133 pCopyPam->GetPoint()->nNode--;
5134
5135 }
5136 pCopyPam->Exchange();
5137
5138 // Also copy all bookmarks
5139 if( bCopyBookmarks
76.1
'bCopyBookmarks' is false
76.1
'bCopyBookmarks' is false
76.1
'bCopyBookmarks' is false
76.1
'bCopyBookmarks' is false
76.1
'bCopyBookmarks' is false
76.1
'bCopyBookmarks' is false
76.1
'bCopyBookmarks' is false
&& m_rDoc.getIDocumentMarkAccess()->getAllMarksCount() )
5140 {
5141 sw::CopyBookmarks(rPam, *pCopyPam->Start());
5142 }
5143
5144 if( RedlineFlags::DeleteRedlines & eOld )
77
Calling 'Wrap::operator bool'
80
Returning from 'Wrap::operator bool'
81
Taking false branch
5145 {
5146 assert(*pCopyPam->GetPoint() == rPos)(static_cast <bool> (*pCopyPam->GetPoint() == rPos) ?
void (0) : __assert_fail ("*pCopyPam->GetPoint() == rPos"
, "/home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx"
, 5146, __extension__ __PRETTY_FUNCTION__))
;
5147 // the Node rPos points to may be deleted so unregister ...
5148 rPos.nContent.Assign(nullptr, 0);
5149 lcl_DeleteRedlines(rPam, *pCopyPam);
5150 rPos = *pCopyPam->GetPoint(); // ... and restore.
5151 }
5152
5153 // If Undo is enabled, store the inserted area
5154 if (rDoc.GetIDocumentUndoRedo().DoesUndo())
82
Assuming the condition is true
83
Taking true branch
5155 {
5156 pUndo->SetInsertRange(*pCopyPam, true, nDeleteTextNodes);
84
Called C++ object pointer is null
5157 }
5158
5159 if( pCpyRange )
5160 {
5161 pCpyRange->SetMark();
5162 *pCpyRange->GetPoint() = *pCopyPam->GetPoint();
5163 *pCpyRange->GetMark() = *pCopyPam->GetMark();
5164 }
5165
5166 if ( pNumRuleToPropagate != nullptr )
5167 {
5168 // #i86492# - use <SwDoc::SetNumRule(..)>, because it also handles the <ListId>
5169 // Don't reset indent attributes, that would mean loss of direct
5170 // formatting.
5171 rDoc.SetNumRule( *pCopyPam, *pNumRuleToPropagate, false, nullptr,
5172 aListIdToPropagate, true, /*bResetIndentAttrs=*/false );
5173 }
5174
5175 rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld );
5176 rDoc.getIDocumentState().SetModified();
5177
5178 return true;
5179}
5180
5181
5182}
5183/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/sw/inc/pam.hxx

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#ifndef INCLUDED_SW_INC_PAM_HXX
20#define INCLUDED_SW_INC_PAM_HXX
21
22#include <sal/types.h>
23#include "ring.hxx"
24#include "index.hxx"
25#include "ndindex.hxx"
26#include "swdllapi.h"
27
28#include <iostream>
29
30class SwDoc;
31class SwPaM;
32class Point;
33
34/// Marks a position in the document model.
35struct SAL_WARN_UNUSED__attribute__((warn_unused)) SW_DLLPUBLIC__attribute__ ((visibility("default"))) SwPosition
36{
37 SwNodeIndex nNode;
38 SwIndex nContent;
39
40 SwPosition( const SwNodeIndex &rNode, const SwIndex &rContent );
41 explicit SwPosition( const SwNodeIndex &rNode );
42 explicit SwPosition( const SwNode& rNode );
43 explicit SwPosition( SwContentNode& rNode, const sal_Int32 nOffset = 0 );
44
45 /**
46 Returns the document this position is in.
47
48 @return the document this position is in.
49 */
50 SwDoc& GetDoc() const;
51
52 bool operator < (const SwPosition &) const;
53 bool operator > (const SwPosition &) const;
54 bool operator <=(const SwPosition &) const;
55 bool operator >=(const SwPosition &) const;
56 bool operator ==(const SwPosition &) const;
57 bool operator !=(const SwPosition &) const;
58 void dumpAsXml(xmlTextWriterPtr pWriter) const;
59};
60
61SW_DLLPUBLIC__attribute__ ((visibility("default"))) std::ostream &operator <<(std::ostream& s, const SwPosition& position);
62
63// Result of comparing positions.
64enum class SwComparePosition {
65 Before, ///< Pos1 before Pos2.
66 Behind, ///< Pos1 behind Pos2.
67 Inside, ///< Pos1 completely contained in Pos2.
68 Outside, ///< Pos2 completely contained in Pos1.
69 Equal, ///< Pos1 is as large as Pos2.
70 OverlapBefore, ///< Pos1 overlaps Pos2 at the beginning.
71 OverlapBehind, ///< Pos1 overlaps Pos2 at the end.
72 CollideStart, ///< Pos1 start touches at Pos2 end.
73 CollideEnd ///< Pos1 end touches at Pos2 start.
74};
75
76template<typename T>
77SwComparePosition ComparePosition(
78 const T& rStt1, const T& rEnd1,
79 const T& rStt2, const T& rEnd2 )
80{
81 SwComparePosition nRet;
82 if( rStt1 < rStt2 )
83 {
84 if( rEnd1 > rStt2 )
85 {
86 if( rEnd1 >= rEnd2 )
87 nRet = SwComparePosition::Outside;
88 else
89 nRet = SwComparePosition::OverlapBefore;
90
91 }
92 else if( rEnd1 == rStt2 )
93 nRet = SwComparePosition::CollideEnd;
94 else
95 nRet = SwComparePosition::Before;
96 }
97 else if( rEnd2 > rStt1 )
98 {
99 if( rEnd2 >= rEnd1 )
100 {
101 if( rEnd2 == rEnd1 && rStt2 == rStt1 )
102 nRet = SwComparePosition::Equal;
103 else
104 nRet = SwComparePosition::Inside;
105 }
106 else
107 {
108 if (rStt1 == rStt2)
109 nRet = SwComparePosition::Outside;
110 else
111 nRet = SwComparePosition::OverlapBehind;
112 }
113 }
114 else if( rEnd2 == rStt1 )
115 nRet = SwComparePosition::CollideStart;
116 else
117 nRet = SwComparePosition::Behind;
118 return nRet;
119}
120
121/// SwPointAndMark / SwPaM
122struct SwMoveFnCollection;
123SW_DLLPUBLIC__attribute__ ((visibility("default"))) extern SwMoveFnCollection const & fnMoveForward; ///< SwPam::Move()/Find() default argument.
124SW_DLLPUBLIC__attribute__ ((visibility("default"))) extern SwMoveFnCollection const & fnMoveBackward;
125
126using SwGoInDoc = auto (*)(SwPaM& rPam, SwMoveFnCollection const & fnMove) -> bool;
127SW_DLLPUBLIC__attribute__ ((visibility("default"))) bool GoInDoc( SwPaM&, SwMoveFnCollection const &);
128bool GoInSection( SwPaM&, SwMoveFnCollection const &);
129SW_DLLPUBLIC__attribute__ ((visibility("default"))) bool GoInNode( SwPaM&, SwMoveFnCollection const &);
130SW_DLLPUBLIC__attribute__ ((visibility("default"))) bool GoInContent( SwPaM&, SwMoveFnCollection const &);
131bool GoInContentCells( SwPaM&, SwMoveFnCollection const &);
132bool GoInContentSkipHidden( SwPaM&, SwMoveFnCollection const &);
133bool GoInContentCellsSkipHidden( SwPaM&, SwMoveFnCollection const &);
134
135/// PaM is Point and Mark: a selection of the document model.
136class SAL_WARN_UNUSED__attribute__((warn_unused)) SW_DLLPUBLIC__attribute__ ((visibility("default"))) SwPaM : public sw::Ring<SwPaM>
137{
138 SwPosition m_Bound1;
139 SwPosition m_Bound2;
140 SwPosition * m_pPoint; ///< points at either m_Bound1 or m_Bound2
141 SwPosition * m_pMark; ///< points at either m_Bound1 or m_Bound2
142 bool m_bIsInFrontOfLabel;
143
144 SwPaM(SwPaM const& rPaM) = delete;
145
146public:
147 explicit SwPaM( const SwPosition& rPos, SwPaM* pRing = nullptr );
148 SwPaM( const SwPosition& rMk, const SwPosition& rPt, SwPaM* pRing = nullptr );
149 SwPaM( const SwNodeIndex& rMk, const SwNodeIndex& rPt,
150 long nMkOffset = 0, long nPtOffset = 0, SwPaM* pRing = nullptr );
151 SwPaM( const SwNode& rMk, const SwNode& rPt,
152 long nMkOffset = 0, long nPtOffset = 0, SwPaM* pRing = nullptr );
153 SwPaM( const SwNodeIndex& rMk, sal_Int32 nMkContent,
154 const SwNodeIndex& rPt, sal_Int32 nPtContent, SwPaM* pRing = nullptr );
155 SwPaM( const SwNode& rMk, sal_Int32 nMkContent,
156 const SwNode& rPt, sal_Int32 nPtContent, SwPaM* pRing = nullptr );
157 SwPaM( const SwNode& rNd, sal_Int32 nContent = 0, SwPaM* pRing = nullptr );
158 SwPaM( const SwNodeIndex& rNd, sal_Int32 nContent = 0, SwPaM* pRing = nullptr );
159 virtual ~SwPaM() override;
160
161 /// this takes a second parameter, which indicates the Ring that
162 /// the new PaM should be part of (may be null)
163 SwPaM(SwPaM const& rPaM, SwPaM * pRing);
164 /// @@@ semantic: no copy assignment for super class Ring.
165 SwPaM& operator=( const SwPaM & );
166
167 /// Movement of cursor.
168 bool Move( SwMoveFnCollection const & fnMove = fnMoveForward,
169 SwGoInDoc fnGo = GoInContent );
170
171 bool IsInFrontOfLabel() const { return m_bIsInFrontOfLabel; }
172 void SetInFrontOfLabel_( bool bNew ) { m_bIsInFrontOfLabel = bNew; }
173
174 /// Unless this is called, the getter method of Mark will return Point.
175 virtual void SetMark();
176
177 void DeleteMark()
178 {
179 if (m_pMark != m_pPoint)
180 {
181 /** clear the mark position; this helps if mark's SwIndex is
182 registered at some node, and that node is then deleted */
183 *m_pMark = SwPosition( SwNodeIndex( GetNode().GetNodes() ) );
184 m_pMark = m_pPoint;
185 }
186 }
187#ifdef DBG_UTIL
188 void Exchange();
189
190#else
191 void Exchange()
192 {
193 if (m_pPoint != m_pMark)
194 {
195 SwPosition *pTmp = m_pPoint;
196 m_pPoint = m_pMark;
197 m_pMark = pTmp;
198 }
199 }
200#endif
201
202 /** A PaM marks a selection if Point and Mark are distinct positions.
203 @return true if the PaM spans a selection
204 */
205 bool HasMark() const { return m_pPoint != m_pMark; }
3
Assuming field 'm_pPoint' is not equal to field 'm_pMark'
4
Returning the value 1, which participates in a condition later
206
207 const SwPosition *GetPoint() const { return m_pPoint; }
208 SwPosition *GetPoint() { return m_pPoint; }
209 const SwPosition *GetMark() const { return m_pMark; }
210 SwPosition *GetMark() { return m_pMark; }
211
212 const SwPosition *Start() const
213 { return (*m_pPoint) <= (*m_pMark) ? m_pPoint : m_pMark; }
214 SwPosition *Start()
215 { return (*m_pPoint) <= (*m_pMark) ? m_pPoint : m_pMark; }
216
217 const SwPosition *End() const
218 { return (*m_pPoint) > (*m_pMark) ? m_pPoint : m_pMark; }
219 SwPosition *End()
220 { return (*m_pPoint) > (*m_pMark) ? m_pPoint : m_pMark; }
221
222 /// @return current Node at Point/Mark
223 SwNode & GetNode ( bool bPoint = true ) const
224 {
225 return ( bPoint ? m_pPoint->nNode : m_pMark->nNode ).GetNode();
226 }
227
228 /// @return current ContentNode at Point/Mark
229 SwContentNode* GetContentNode( bool bPoint = true ) const
230 {
231 return GetNode(bPoint).GetContentNode();
232 }
233
234 /**
235 Normalizes PaM, i.e. sort point and mark.
236
237 @param bPointFirst true: If the point is behind the mark then swap.
238 false: If the mark is behind the point then swap.
239 */
240 void Normalize(bool bPointFirst = true);
241
242 /// @return the document (SwDoc) at which the PaM is registered
243 SwDoc& GetDoc() const { return m_pPoint->nNode.GetNode().GetDoc(); }
244
245 SwPosition& GetBound( bool bOne = true )
246 { return bOne ? m_Bound1 : m_Bound2; }
247 const SwPosition& GetBound( bool bOne = true ) const
248 { return bOne ? m_Bound1 : m_Bound2; }
249
250 /// Get number of page which contains cursor.
251 sal_uInt16 GetPageNum( bool bAtPoint = true, const Point* pLayPos = nullptr );
252
253 /** Is in something protected (readonly) or selection contains
254 something protected. */
255 bool HasReadonlySel( bool bFormView ) const;
256
257 bool ContainsPosition(const SwPosition & rPos) const
258 {
259 return *Start() <= rPos && rPos <= *End();
260 }
261
262 OUString GetText() const;
263 void InvalidatePaM();
264 SwPaM* GetNext()
265 { return GetNextInRing(); }
266 const SwPaM* GetNext() const
267 { return GetNextInRing(); }
268 SwPaM* GetPrev()
269 { return GetPrevInRing(); }
270 const SwPaM* GetPrev() const
271 { return GetPrevInRing(); }
272 bool IsMultiSelection() const
273 { return !unique(); }
274
275 void dumpAsXml(xmlTextWriterPtr pWriter) const;
276};
277
278SW_DLLPUBLIC__attribute__ ((visibility("default"))) std::ostream &operator <<(std::ostream& s, const SwPaM& pam);
279
280bool CheckNodesRange(const SwNodeIndex&, const SwNodeIndex&, bool bChkSection);
281
282#endif // INCLUDED_SW_INC_PAM_HXX
283
284/* 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());
19
Calling '__uniq_ptr_impl::reset'
41
Returning from '__uniq_ptr_impl::reset'
168 _M_deleter() = std::forward<_Dp>(__u._M_deleter());
169 return *this;
170 }
171
172 pointer& _M_ptr() { return std::get<0>(_M_t); }
21
Calling 'get<0, std::vector<SwFrameFormat *, std::allocator<SwFrameFormat *>> *, std::default_delete<std::vector<SwFrameFormat *, std::allocator<SwFrameFormat *>>>>'
28
Returning from 'get<0, std::vector<SwFrameFormat *, std::allocator<SwFrameFormat *>> *, std::default_delete<std::vector<SwFrameFormat *, std::allocator<SwFrameFormat *>>>>'
31
Calling 'get<0, std::vector<SwFrameFormat *, std::allocator<SwFrameFormat *>> *, std::default_delete<std::vector<SwFrameFormat *, std::allocator<SwFrameFormat *>>>>'
38
Returning from 'get<0, std::vector<SwFrameFormat *, std::allocator<SwFrameFormat *>> *, std::default_delete<std::vector<SwFrameFormat *, std::allocator<SwFrameFormat *>>>>'
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();
20
Calling '__uniq_ptr_impl::_M_ptr'
29
Returning from '__uniq_ptr_impl::_M_ptr'
180 _M_ptr() = __p;
30
Calling '__uniq_ptr_impl::_M_ptr'
39
Returning from '__uniq_ptr_impl::_M_ptr'
181 if (__old_p
39.1
'__old_p' is null
39.1
'__old_p' is null
39.1
'__old_p' is null
39.1
'__old_p' is null
39.1
'__old_p' is null
39.1
'__old_p' is null
39.1
'__old_p' is null
)
40
Taking false branch
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;
18
Calling move assignment operator for '__uniq_ptr_impl<std::vector<SwFrameFormat *, std::allocator<SwFrameFormat *>>, std::default_delete<std::vector<SwFrameFormat *, std::allocator<SwFrameFormat *>>>>'
42
Returning from move assignment operator for '__uniq_ptr_impl<std::vector<SwFrameFormat *, std::allocator<SwFrameFormat *>>, std::default_delete<std::vector<SwFrameFormat *, std::allocator<SwFrameFormat *>>>>'
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;
17
Calling defaulted move assignment operator for '__uniq_ptr_data<std::vector<SwFrameFormat *, std::allocator<SwFrameFormat *>>, std::default_delete<std::vector<SwFrameFormat *, std::allocator<SwFrameFormat *>>>, true, true>'
43
Returning from move assignment operator for '__uniq_ptr_data<std::vector<SwFrameFormat *, std::allocator<SwFrameFormat *>>, std::default_delete<std::vector<SwFrameFormat *, std::allocator<SwFrameFormat *>>>, true, true>'
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)...)); }
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 */

/usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/tuple

1// <tuple> -*- C++ -*-
2
3// Copyright (C) 2007-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 include/tuple
26 * This is a Standard C++ Library header.
27 */
28
29#ifndef _GLIBCXX_TUPLE1
30#define _GLIBCXX_TUPLE1 1
31
32#pragma GCC system_header
33
34#if __cplusplus201703L < 201103L
35# include <bits/c++0x_warning.h>
36#else
37
38#include <utility>
39#include <array>
40#include <bits/uses_allocator.h>
41#include <bits/invoke.h>
42#if __cplusplus201703L > 201703L
43# include <compare>
44# define __cpp_lib_constexpr_tuple 201811L
45#endif
46
47namespace std _GLIBCXX_VISIBILITY(default)__attribute__ ((__visibility__ ("default")))
48{
49_GLIBCXX_BEGIN_NAMESPACE_VERSION
50
51 /**
52 * @addtogroup utilities
53 * @{
54 */
55
56 template<typename... _Elements>
57 class tuple;
58
59 template<typename _Tp>
60 struct __is_empty_non_tuple : is_empty<_Tp> { };
61
62 // Using EBO for elements that are tuples causes ambiguous base errors.
63 template<typename _El0, typename... _El>
64 struct __is_empty_non_tuple<tuple<_El0, _El...>> : false_type { };
65
66 // Use the Empty Base-class Optimization for empty, non-final types.
67 template<typename _Tp>
68 using __empty_not_final
69 = typename conditional<__is_final(_Tp), false_type,
70 __is_empty_non_tuple<_Tp>>::type;
71
72 template<std::size_t _Idx, typename _Head,
73 bool = __empty_not_final<_Head>::value>
74 struct _Head_base;
75
76 template<std::size_t _Idx, typename _Head>
77 struct _Head_base<_Idx, _Head, true>
78 : public _Head
79 {
80 constexpr _Head_base()
81 : _Head() { }
82
83 constexpr _Head_base(const _Head& __h)
84 : _Head(__h) { }
85
86 constexpr _Head_base(const _Head_base&) = default;
87 constexpr _Head_base(_Head_base&&) = default;
88
89 template<typename _UHead>
90 constexpr _Head_base(_UHead&& __h)
91 : _Head(std::forward<_UHead>(__h)) { }
92
93 _Head_base(allocator_arg_t, __uses_alloc0)
94 : _Head() { }
95
96 template<typename _Alloc>
97 _Head_base(allocator_arg_t, __uses_alloc1<_Alloc> __a)
98 : _Head(allocator_arg, *__a._M_a) { }
99
100 template<typename _Alloc>
101 _Head_base(allocator_arg_t, __uses_alloc2<_Alloc> __a)
102 : _Head(*__a._M_a) { }
103
104 template<typename _UHead>
105 _Head_base(__uses_alloc0, _UHead&& __uhead)
106 : _Head(std::forward<_UHead>(__uhead)) { }
107
108 template<typename _Alloc, typename _UHead>
109 _Head_base(__uses_alloc1<_Alloc> __a, _UHead&& __uhead)
110 : _Head(allocator_arg, *__a._M_a, std::forward<_UHead>(__uhead)) { }
111
112 template<typename _Alloc, typename _UHead>
113 _Head_base(__uses_alloc2<_Alloc> __a, _UHead&& __uhead)
114 : _Head(std::forward<_UHead>(__uhead), *__a._M_a) { }
115
116 static constexpr _Head&
117 _M_head(_Head_base& __b) noexcept { return __b; }
118
119 static constexpr const _Head&
120 _M_head(const _Head_base& __b) noexcept { return __b; }
121 };
122
123 template<std::size_t _Idx, typename _Head>
124 struct _Head_base<_Idx, _Head, false>
125 {
126 constexpr _Head_base()
127 : _M_head_impl() { }
128
129 constexpr _Head_base(const _Head& __h)
130 : _M_head_impl(__h) { }
131
132 constexpr _Head_base(const _Head_base&) = default;
133 constexpr _Head_base(_Head_base&&) = default;
134
135 template<typename _UHead>
136 constexpr _Head_base(_UHead&& __h)
137 : _M_head_impl(std::forward<_UHead>(__h)) { }
138
139 _GLIBCXX20_CONSTEXPR
140 _Head_base(allocator_arg_t, __uses_alloc0)
141 : _M_head_impl() { }
142
143 template<typename _Alloc>
144 _Head_base(allocator_arg_t, __uses_alloc1<_Alloc> __a)
145 : _M_head_impl(allocator_arg, *__a._M_a) { }
146
147 template<typename _Alloc>
148 _Head_base(allocator_arg_t, __uses_alloc2<_Alloc> __a)
149 : _M_head_impl(*__a._M_a) { }
150
151 template<typename _UHead>
152 _GLIBCXX20_CONSTEXPR
153 _Head_base(__uses_alloc0, _UHead&& __uhead)
154 : _M_head_impl(std::forward<_UHead>(__uhead)) { }
155
156 template<typename _Alloc, typename _UHead>
157 _Head_base(__uses_alloc1<_Alloc> __a, _UHead&& __uhead)
158 : _M_head_impl(allocator_arg, *__a._M_a, std::forward<_UHead>(__uhead))
159 { }
160
161 template<typename _Alloc, typename _UHead>
162 _Head_base(__uses_alloc2<_Alloc> __a, _UHead&& __uhead)
163 : _M_head_impl(std::forward<_UHead>(__uhead), *__a._M_a) { }
164
165 static constexpr _Head&
166 _M_head(_Head_base& __b) noexcept { return __b._M_head_impl; }
167
168 static constexpr const _Head&
169 _M_head(const _Head_base& __b) noexcept { return __b._M_head_impl; }
170
171 _Head _M_head_impl;
172 };
173
174 /**
175 * Contains the actual implementation of the @c tuple template, stored
176 * as a recursive inheritance hierarchy from the first element (most
177 * derived class) to the last (least derived class). The @c Idx
178 * parameter gives the 0-based index of the element stored at this
179 * point in the hierarchy; we use it to implement a constant-time
180 * get() operation.
181 */
182 template<std::size_t _Idx, typename... _Elements>
183 struct _Tuple_impl;
184
185 /**
186 * Recursive tuple implementation. Here we store the @c Head element
187 * and derive from a @c Tuple_impl containing the remaining elements
188 * (which contains the @c Tail).
189 */
190 template<std::size_t _Idx, typename _Head, typename... _Tail>
191 struct _Tuple_impl<_Idx, _Head, _Tail...>
192 : public _Tuple_impl<_Idx + 1, _Tail...>,
193 private _Head_base<_Idx, _Head>
194 {
195 template<std::size_t, typename...> friend class _Tuple_impl;
196
197 typedef _Tuple_impl<_Idx + 1, _Tail...> _Inherited;
198 typedef _Head_base<_Idx, _Head> _Base;
199
200 static constexpr _Head&
201 _M_head(_Tuple_impl& __t) noexcept { return _Base::_M_head(__t); }
24
Calling '_Head_base::_M_head'
25
Returning from '_Head_base::_M_head'
34
Calling '_Head_base::_M_head'
35
Returning from '_Head_base::_M_head'
202
203 static constexpr const _Head&
204 _M_head(const _Tuple_impl& __t) noexcept { return _Base::_M_head(__t); }
205
206 static constexpr _Inherited&
207 _M_tail(_Tuple_impl& __t) noexcept { return __t; }
208
209 static constexpr const _Inherited&
210 _M_tail(const _Tuple_impl& __t) noexcept { return __t; }
211
212 constexpr _Tuple_impl()
213 : _Inherited(), _Base() { }
214
215 explicit
216 constexpr _Tuple_impl(const _Head& __head, const _Tail&... __tail)
217 : _Inherited(__tail...), _Base(__head) { }
218
219 template<typename _UHead, typename... _UTail, typename = typename
220 enable_if<sizeof...(_Tail) == sizeof...(_UTail)>::type>
221 explicit
222 constexpr _Tuple_impl(_UHead&& __head, _UTail&&... __tail)
223 : _Inherited(std::forward<_UTail>(__tail)...),
224 _Base(std::forward<_UHead>(__head)) { }
225
226 constexpr _Tuple_impl(const _Tuple_impl&) = default;
227
228 // _GLIBCXX_RESOLVE_LIB_DEFECTS
229 // 2729. Missing SFINAE on std::pair::operator=
230 _Tuple_impl& operator=(const _Tuple_impl&) = delete;
231
232 constexpr
233 _Tuple_impl(_Tuple_impl&& __in)
234 noexcept(__and_<is_nothrow_move_constructible<_Head>,
235 is_nothrow_move_constructible<_Inherited>>::value)
236 : _Inherited(std::move(_M_tail(__in))),
237 _Base(std::forward<_Head>(_M_head(__in))) { }
238
239 template<typename... _UElements>
240 constexpr _Tuple_impl(const _Tuple_impl<_Idx, _UElements...>& __in)
241 : _Inherited(_Tuple_impl<_Idx, _UElements...>::_M_tail(__in)),
242 _Base(_Tuple_impl<_Idx, _UElements...>::_M_head(__in)) { }
243
244 template<typename _UHead, typename... _UTails>
245 constexpr _Tuple_impl(_Tuple_impl<_Idx, _UHead, _UTails...>&& __in)
246 : _Inherited(std::move
247 (_Tuple_impl<_Idx, _UHead, _UTails...>::_M_tail(__in))),
248 _Base(std::forward<_UHead>
249 (_Tuple_impl<_Idx, _UHead, _UTails...>::_M_head(__in))) { }
250
251 template<typename _Alloc>
252 _GLIBCXX20_CONSTEXPR
253 _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a)
254 : _Inherited(__tag, __a),
255 _Base(__tag, __use_alloc<_Head>(__a)) { }
256
257 template<typename _Alloc>
258 _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a,
259 const _Head& __head, const _Tail&... __tail)
260 : _Inherited(__tag, __a, __tail...),
261 _Base(__use_alloc<_Head, _Alloc, _Head>(__a), __head) { }
262
263 template<typename _Alloc, typename _UHead, typename... _UTail,
264 typename = typename enable_if<sizeof...(_Tail)
265 == sizeof...(_UTail)>::type>
266 _GLIBCXX20_CONSTEXPR
267 _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a,
268 _UHead&& __head, _UTail&&... __tail)
269 : _Inherited(__tag, __a, std::forward<_UTail>(__tail)...),
270 _Base(__use_alloc<_Head, _Alloc, _UHead>(__a),
271 std::forward<_UHead>(__head)) { }
272
273 template<typename _Alloc>
274 _GLIBCXX20_CONSTEXPR
275 _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a,
276 const _Tuple_impl& __in)
277 : _Inherited(__tag, __a, _M_tail(__in)),
278 _Base(__use_alloc<_Head, _Alloc, _Head>(__a), _M_head(__in)) { }
279
280 template<typename _Alloc>
281 _GLIBCXX20_CONSTEXPR
282 _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a,
283 _Tuple_impl&& __in)
284 : _Inherited(__tag, __a, std::move(_M_tail(__in))),
285 _Base(__use_alloc<_Head, _Alloc, _Head>(__a),
286 std::forward<_Head>(_M_head(__in))) { }
287
288 template<typename _Alloc, typename... _UElements>
289 _GLIBCXX20_CONSTEXPR
290 _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a,
291 const _Tuple_impl<_Idx, _UElements...>& __in)
292 : _Inherited(__tag, __a,
293 _Tuple_impl<_Idx, _UElements...>::_M_tail(__in)),
294 _Base(__use_alloc<_Head, _Alloc, _Head>(__a),
295 _Tuple_impl<_Idx, _UElements...>::_M_head(__in)) { }
296
297 template<typename _Alloc, typename _UHead, typename... _UTails>
298 _GLIBCXX20_CONSTEXPR
299 _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a,
300 _Tuple_impl<_Idx, _UHead, _UTails...>&& __in)
301 : _Inherited(__tag, __a, std::move
302 (_Tuple_impl<_Idx, _UHead, _UTails...>::_M_tail(__in))),
303 _Base(__use_alloc<_Head, _Alloc, _UHead>(__a),
304 std::forward<_UHead>
305 (_Tuple_impl<_Idx, _UHead, _UTails...>::_M_head(__in))) { }
306
307 template<typename... _UElements>
308 _GLIBCXX20_CONSTEXPR
309 void
310 _M_assign(const _Tuple_impl<_Idx, _UElements...>& __in)
311 {
312 _M_head(*this) = _Tuple_impl<_Idx, _UElements...>::_M_head(__in);
313 _M_tail(*this)._M_assign(
314 _Tuple_impl<_Idx, _UElements...>::_M_tail(__in));
315 }
316
317 template<typename _UHead, typename... _UTails>
318 _GLIBCXX20_CONSTEXPR
319 void
320 _M_assign(_Tuple_impl<_Idx, _UHead, _UTails...>&& __in)
321 {
322 _M_head(*this) = std::forward<_UHead>
323 (_Tuple_impl<_Idx, _UHead, _UTails...>::_M_head(__in));
324 _M_tail(*this)._M_assign(
325 std::move(_Tuple_impl<_Idx, _UHead, _UTails...>::_M_tail(__in)));
326 }
327
328 protected:
329 _GLIBCXX20_CONSTEXPR
330 void
331 _M_swap(_Tuple_impl& __in)
332 {
333 using std::swap;
334 swap(_M_head(*this), _M_head(__in));
335 _Inherited::_M_swap(_M_tail(__in));
336 }
337 };
338
339 // Basis case of inheritance recursion.
340 template<std::size_t _Idx, typename _Head>
341 struct _Tuple_impl<_Idx, _Head>
342 : private _Head_base<_Idx, _Head>
343 {
344 template<std::size_t, typename...> friend class _Tuple_impl;
345
346 typedef _Head_base<_Idx, _Head> _Base;
347
348 static constexpr _Head&
349 _M_head(_Tuple_impl& __t) noexcept { return _Base::_M_head(__t); }
350
351 static constexpr const _Head&
352 _M_head(const _Tuple_impl& __t) noexcept { return _Base::_M_head(__t); }
353
354 constexpr _Tuple_impl()
355 : _Base() { }
356
357 explicit
358 constexpr _Tuple_impl(const _Head& __head)
359 : _Base(__head) { }
360
361 template<typename _UHead>
362 explicit
363 constexpr _Tuple_impl(_UHead&& __head)
364 : _Base(std::forward<_UHead>(__head)) { }
365
366 constexpr _Tuple_impl(const _Tuple_impl&) = default;
367
368 // _GLIBCXX_RESOLVE_LIB_DEFECTS
369 // 2729. Missing SFINAE on std::pair::operator=
370 _Tuple_impl& operator=(const _Tuple_impl&) = delete;
371
372 constexpr
373 _Tuple_impl(_Tuple_impl&& __in)
374 noexcept(is_nothrow_move_constructible<_Head>::value)
375 : _Base(std::forward<_Head>(_M_head(__in))) { }
376
377 template<typename _UHead>
378 constexpr _Tuple_impl(const _Tuple_impl<_Idx, _UHead>& __in)
379 : _Base(_Tuple_impl<_Idx, _UHead>::_M_head(__in)) { }
380
381 template<typename _UHead>
382 constexpr _Tuple_impl(_Tuple_impl<_Idx, _UHead>&& __in)
383 : _Base(std::forward<_UHead>(_Tuple_impl<_Idx, _UHead>::_M_head(__in)))
384 { }
385
386 template<typename _Alloc>
387 _GLIBCXX20_CONSTEXPR
388 _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a)
389 : _Base(__tag, __use_alloc<_Head>(__a)) { }
390
391 template<typename _Alloc>
392 _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a,
393 const _Head& __head)
394 : _Base(__use_alloc<_Head, _Alloc, _Head>(__a), __head) { }
395
396 template<typename _Alloc, typename _UHead>
397 _GLIBCXX20_CONSTEXPR
398 _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a,
399 _UHead&& __head)
400 : _Base(__use_alloc<_Head, _Alloc, _UHead>(__a),
401 std::forward<_UHead>(__head)) { }
402
403 template<typename _Alloc>
404 _GLIBCXX20_CONSTEXPR
405 _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a,
406 const _Tuple_impl& __in)
407 : _Base(__use_alloc<_Head, _Alloc, _Head>(__a), _M_head(__in)) { }
408
409 template<typename _Alloc>
410 _GLIBCXX20_CONSTEXPR
411 _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a,
412 _Tuple_impl&& __in)
413 : _Base(__use_alloc<_Head, _Alloc, _Head>(__a),
414 std::forward<_Head>(_M_head(__in))) { }
415
416 template<typename _Alloc, typename _UHead>
417 _GLIBCXX20_CONSTEXPR
418 _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a,
419 const _Tuple_impl<_Idx, _UHead>& __in)
420 : _Base(__use_alloc<_Head, _Alloc, _Head>(__a),
421 _Tuple_impl<_Idx, _UHead>::_M_head(__in)) { }
422
423 template<typename _Alloc, typename _UHead>
424 _GLIBCXX20_CONSTEXPR
425 _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a,
426 _Tuple_impl<_Idx, _UHead>&& __in)
427 : _Base(__use_alloc<_Head, _Alloc, _UHead>(__a),
428 std::forward<_UHead>(_Tuple_impl<_Idx, _UHead>::_M_head(__in)))
429 { }
430
431 template<typename _UHead>
432 _GLIBCXX20_CONSTEXPR
433 void
434 _M_assign(const _Tuple_impl<_Idx, _UHead>& __in)
435 {
436 _M_head(*this) = _Tuple_impl<_Idx, _UHead>::_M_head(__in);
437 }
438
439 template<typename _UHead>
440 _GLIBCXX20_CONSTEXPR
441 void
442 _M_assign(_Tuple_impl<_Idx, _UHead>&& __in)
443 {
444 _M_head(*this)
445 = std::forward<_UHead>(_Tuple_impl<_Idx, _UHead>::_M_head(__in));
446 }
447
448 protected:
449 _GLIBCXX20_CONSTEXPR
450 void
451 _M_swap(_Tuple_impl& __in)
452 {
453 using std::swap;
454 swap(_M_head(*this), _M_head(__in));
455 }
456 };
457
458 // Concept utility functions, reused in conditionally-explicit
459 // constructors.
460 template<bool, typename... _Types>
461 struct _TupleConstraints
462 {
463 // Constraint for a non-explicit constructor.
464 // True iff each Ti in _Types... can be constructed from Ui in _UTypes...
465 // and every Ui is implicitly convertible to Ti.
466 template<typename... _UTypes>
467 static constexpr bool __is_implicitly_constructible()
468 {
469 return __and_<is_constructible<_Types, _UTypes>...,
470 is_convertible<_UTypes, _Types>...
471 >::value;
472 }
473
474 // Constraint for a non-explicit constructor.
475 // True iff each Ti in _Types... can be constructed from Ui in _UTypes...
476 // but not every Ui is implicitly convertible to Ti.
477 template<typename... _UTypes>
478 static constexpr bool __is_explicitly_constructible()
479 {
480 return __and_<is_constructible<_Types, _UTypes>...,
481 __not_<__and_<is_convertible<_UTypes, _Types>...>>
482 >::value;
483 }
484
485 static constexpr bool __is_implicitly_default_constructible()
486 {
487 return __and_<std::__is_implicitly_default_constructible<_Types>...
488 >::value;
489 }
490
491 static constexpr bool __is_explicitly_default_constructible()
492 {
493 return __and_<is_default_constructible<_Types>...,
494 __not_<__and_<
495 std::__is_implicitly_default_constructible<_Types>...>
496 >>::value;
497 }
498 };
499
500 // Partial specialization used when a required precondition isn't met,
501 // e.g. when sizeof...(_Types) != sizeof...(_UTypes).
502 template<typename... _Types>
503 struct _TupleConstraints<false, _Types...>
504 {
505 template<typename... _UTypes>
506 static constexpr bool __is_implicitly_constructible()
507 { return false; }
508
509 template<typename... _UTypes>
510 static constexpr bool __is_explicitly_constructible()
511 { return false; }
512 };
513
514 /// Primary class template, tuple
515 template<typename... _Elements>
516 class tuple : public _Tuple_impl<0, _Elements...>
517 {
518 typedef _Tuple_impl<0, _Elements...> _Inherited;
519
520 template<bool _Cond>
521 using _TCC = _TupleConstraints<_Cond, _Elements...>;
522
523 // Constraint for non-explicit default constructor
524 template<bool _Dummy>
525 using _ImplicitDefaultCtor = __enable_if_t<
526 _TCC<_Dummy>::__is_implicitly_default_constructible(),
527 bool>;
528
529 // Constraint for explicit default constructor
530 template<bool _Dummy>
531 using _ExplicitDefaultCtor = __enable_if_t<
532 _TCC<_Dummy>::__is_explicitly_default_constructible(),
533 bool>;
534
535 // Constraint for non-explicit constructors
536 template<bool _Cond, typename... _Args>
537 using _ImplicitCtor = __enable_if_t<
538 _TCC<_Cond>::template __is_implicitly_constructible<_Args...>(),
539 bool>;
540
541 // Constraint for non-explicit constructors
542 template<bool _Cond, typename... _Args>
543 using _ExplicitCtor = __enable_if_t<
544 _TCC<_Cond>::template __is_explicitly_constructible<_Args...>(),
545 bool>;
546
547 template<typename... _UElements>
548 static constexpr
549 __enable_if_t<sizeof...(_UElements) == sizeof...(_Elements), bool>
550 __assignable()
551 { return __and_<is_assignable<_Elements&, _UElements>...>::value; }
552
553 // Condition for noexcept-specifier of an assignment operator.
554 template<typename... _UElements>
555 static constexpr bool __nothrow_assignable()
556 {
557 return
558 __and_<is_nothrow_assignable<_Elements&, _UElements>...>::value;
559 }
560
561 // Condition for noexcept-specifier of a constructor.
562 template<typename... _UElements>
563 static constexpr bool __nothrow_constructible()
564 {
565 return
566 __and_<is_nothrow_constructible<_Elements, _UElements>...>::value;
567 }
568
569 // Constraint for tuple(_UTypes&&...) where sizeof...(_UTypes) == 1.
570 template<typename _Up>
571 static constexpr bool __valid_args()
572 {
573 return sizeof...(_Elements) == 1
574 && !is_same<tuple, __remove_cvref_t<_Up>>::value;
575 }
576
577 // Constraint for tuple(_UTypes&&...) where sizeof...(_UTypes) > 1.
578 template<typename, typename, typename... _Tail>
579 static constexpr bool __valid_args()
580 { return (sizeof...(_Tail) + 2) == sizeof...(_Elements); }
581
582 /* Constraint for constructors with a tuple<UTypes...> parameter ensures
583 * that the constructor is only viable when it would not interfere with
584 * tuple(UTypes&&...) or tuple(const tuple&) or tuple(tuple&&).
585 * Such constructors are only viable if:
586 * either sizeof...(Types) != 1,
587 * or (when Types... expands to T and UTypes... expands to U)
588 * is_convertible_v<TUPLE, T>, is_constructible_v<T, TUPLE>,
589 * and is_same_v<T, U> are all false.
590 */
591 template<typename _Tuple, typename = tuple,
592 typename = __remove_cvref_t<_Tuple>>
593 struct _UseOtherCtor
594 : false_type
595 { };
596 // If TUPLE is convertible to the single element in *this,
597 // then TUPLE should match tuple(UTypes&&...) instead.
598 template<typename _Tuple, typename _Tp, typename _Up>
599 struct _UseOtherCtor<_Tuple, tuple<_Tp>, tuple<_Up>>
600 : __or_<is_convertible<_Tuple, _Tp>, is_constructible<_Tp, _Tuple>>
601 { };
602 // If TUPLE and *this each have a single element of the same type,
603 // then TUPLE should match a copy/move constructor instead.
604 template<typename _Tuple, typename _Tp>
605 struct _UseOtherCtor<_Tuple, tuple<_Tp>, tuple<_Tp>>
606 : true_type
607 { };
608
609 // Return true iff sizeof...(Types) == 1 && tuple_size_v<TUPLE> == 1
610 // and the single element in Types can be initialized from TUPLE,
611 // or is the same type as tuple_element_t<0, TUPLE>.
612 template<typename _Tuple>
613 static constexpr bool __use_other_ctor()
614 { return _UseOtherCtor<_Tuple>::value; }
615
616 public:
617 template<typename _Dummy = void,
618 _ImplicitDefaultCtor<is_void<_Dummy>::value> = true>
619 constexpr
620 tuple()
621 noexcept(__and_<is_nothrow_default_constructible<_Elements>...>::value)
622 : _Inherited() { }
623
624 template<typename _Dummy = void,
625 _ExplicitDefaultCtor<is_void<_Dummy>::value> = false>
626 explicit constexpr
627 tuple()
628 noexcept(__and_<is_nothrow_default_constructible<_Elements>...>::value)
629 : _Inherited() { }
630
631 template<bool _NotEmpty = (sizeof...(_Elements) >= 1),
632 _ImplicitCtor<_NotEmpty, const _Elements&...> = true>
633 constexpr
634 tuple(const _Elements&... __elements)
635 noexcept(__nothrow_constructible<const _Elements&...>())
636 : _Inherited(__elements...) { }
637
638 template<bool _NotEmpty = (sizeof...(_Elements) >= 1),
639 _ExplicitCtor<_NotEmpty, const _Elements&...> = false>
640 explicit constexpr
641 tuple(const _Elements&... __elements)
642 noexcept(__nothrow_constructible<const _Elements&...>())
643 : _Inherited(__elements...) { }
644
645 template<typename... _UElements,
646 bool _Valid = __valid_args<_UElements...>(),
647 _ImplicitCtor<_Valid, _UElements...> = true>
648 constexpr
649 tuple(_UElements&&... __elements)
650 noexcept(__nothrow_constructible<_UElements...>())
651 : _Inherited(std::forward<_UElements>(__elements)...) { }
652
653 template<typename... _UElements,
654 bool _Valid = __valid_args<_UElements...>(),
655 _ExplicitCtor<_Valid, _UElements...> = false>
656 explicit constexpr
657 tuple(_UElements&&... __elements)
658 noexcept(__nothrow_constructible<_UElements...>())
659 : _Inherited(std::forward<_UElements>(__elements)...) { }
660
661 constexpr tuple(const tuple&) = default;
662
663 constexpr tuple(tuple&&) = default;
664
665 template<typename... _UElements,
666 bool _Valid = (sizeof...(_Elements) == sizeof...(_UElements))
667 && !__use_other_ctor<const tuple<_UElements...>&>(),
668 _ImplicitCtor<_Valid, const _UElements&...> = true>
669 constexpr
670 tuple(const tuple<_UElements...>& __in)
671 noexcept(__nothrow_constructible<const _UElements&...>())
672 : _Inherited(static_cast<const _Tuple_impl<0, _UElements...>&>(__in))
673 { }
674
675 template<typename... _UElements,
676 bool _Valid = (sizeof...(_Elements) == sizeof...(_UElements))
677 && !__use_other_ctor<const tuple<_UElements...>&>(),
678 _ExplicitCtor<_Valid, const _UElements&...> = false>
679 explicit constexpr
680 tuple(const tuple<_UElements...>& __in)
681 noexcept(__nothrow_constructible<const _UElements&...>())
682 : _Inherited(static_cast<const _Tuple_impl<0, _UElements...>&>(__in))
683 { }
684
685 template<typename... _UElements,
686 bool _Valid = (sizeof...(_Elements) == sizeof...(_UElements))
687 && !__use_other_ctor<tuple<_UElements...>&&>(),
688 _ImplicitCtor<_Valid, _UElements...> = true>
689 constexpr
690 tuple(tuple<_UElements...>&& __in)
691 noexcept(__nothrow_constructible<_UElements...>())
692 : _Inherited(static_cast<_Tuple_impl<0, _UElements...>&&>(__in)) { }
693
694 template<typename... _UElements,
695 bool _Valid = (sizeof...(_Elements) == sizeof...(_UElements))
696 && !__use_other_ctor<tuple<_UElements...>&&>(),
697 _ExplicitCtor<_Valid, _UElements...> = false>
698 explicit constexpr
699 tuple(tuple<_UElements...>&& __in)
700 noexcept(__nothrow_constructible<_UElements...>())
701 : _Inherited(static_cast<_Tuple_impl<0, _UElements...>&&>(__in)) { }
702
703 // Allocator-extended constructors.
704
705 template<typename _Alloc,
706 _ImplicitDefaultCtor<is_object<_Alloc>::value> = true>
707 _GLIBCXX20_CONSTEXPR
708 tuple(allocator_arg_t __tag, const _Alloc& __a)
709 : _Inherited(__tag, __a) { }
710
711 template<typename _Alloc, bool _NotEmpty = (sizeof...(_Elements) >= 1),
712 _ImplicitCtor<_NotEmpty, const _Elements&...> = true>
713 _GLIBCXX20_CONSTEXPR
714 tuple(allocator_arg_t __tag, const _Alloc& __a,
715 const _Elements&... __elements)
716 : _Inherited(__tag, __a, __elements...) { }
717
718 template<typename _Alloc, bool _NotEmpty = (sizeof...(_Elements) >= 1),
719 _ExplicitCtor<_NotEmpty, const _Elements&...> = false>
720 _GLIBCXX20_CONSTEXPR
721 explicit
722 tuple(allocator_arg_t __tag, const _Alloc& __a,
723 const _Elements&... __elements)
724 : _Inherited(__tag, __a, __elements...) { }
725
726 template<typename _Alloc, typename... _UElements,
727 bool _Valid = __valid_args<_UElements...>(),
728 _ImplicitCtor<_Valid, _UElements...> = true>
729 _GLIBCXX20_CONSTEXPR
730 tuple(allocator_arg_t __tag, const _Alloc& __a,
731 _UElements&&... __elements)
732 : _Inherited(__tag, __a, std::forward<_UElements>(__elements)...)
733 { }
734
735 template<typename _Alloc, typename... _UElements,
736 bool _Valid = __valid_args<_UElements...>(),
737 _ExplicitCtor<_Valid, _UElements...> = false>
738 _GLIBCXX20_CONSTEXPR
739 explicit
740 tuple(allocator_arg_t __tag, const _Alloc& __a,
741 _UElements&&... __elements)
742 : _Inherited(__tag, __a, std::forward<_UElements>(__elements)...)
743 { }
744
745 template<typename _Alloc>
746 _GLIBCXX20_CONSTEXPR
747 tuple(allocator_arg_t __tag, const _Alloc& __a, const tuple& __in)
748 : _Inherited(__tag, __a, static_cast<const _Inherited&>(__in)) { }
749
750 template<typename _Alloc>
751 _GLIBCXX20_CONSTEXPR
752 tuple(allocator_arg_t __tag, const _Alloc& __a, tuple&& __in)
753 : _Inherited(__tag, __a, static_cast<_Inherited&&>(__in)) { }
754
755 template<typename _Alloc, typename... _UElements,
756 bool _Valid = (sizeof...(_Elements) == sizeof...(_UElements))
757 && !__use_other_ctor<const tuple<_UElements...>&>(),
758 _ImplicitCtor<_Valid, const _UElements&...> = true>
759 _GLIBCXX20_CONSTEXPR
760 tuple(allocator_arg_t __tag, const _Alloc& __a,
761 const tuple<_UElements...>& __in)
762 : _Inherited(__tag, __a,
763 static_cast<const _Tuple_impl<0, _UElements...>&>(__in))
764 { }
765
766 template<typename _Alloc, typename... _UElements,
767 bool _Valid = (sizeof...(_Elements) == sizeof...(_UElements))
768 && !__use_other_ctor<const tuple<_UElements...>&>(),
769 _ExplicitCtor<_Valid, const _UElements&...> = false>
770 _GLIBCXX20_CONSTEXPR
771 explicit
772 tuple(allocator_arg_t __tag, const _Alloc& __a,
773 const tuple<_UElements...>& __in)
774 : _Inherited(__tag, __a,
775 static_cast<const _Tuple_impl<0, _UElements...>&>(__in))
776 { }
777
778 template<typename _Alloc, typename... _UElements,
779 bool _Valid = (sizeof...(_Elements) == sizeof...(_UElements))
780 && !__use_other_ctor<tuple<_UElements...>&&>(),
781 _ImplicitCtor<_Valid, _UElements...> = true>
782 _GLIBCXX20_CONSTEXPR
783 tuple(allocator_arg_t __tag, const _Alloc& __a,
784 tuple<_UElements...>&& __in)
785 : _Inherited(__tag, __a,
786 static_cast<_Tuple_impl<0, _UElements...>&&>(__in))
787 { }
788
789 template<typename _Alloc, typename... _UElements,
790 bool _Valid = (sizeof...(_Elements) == sizeof...(_UElements))
791 && !__use_other_ctor<tuple<_UElements...>&&>(),
792 _ExplicitCtor<_Valid, _UElements...> = false>
793 _GLIBCXX20_CONSTEXPR
794 explicit
795 tuple(allocator_arg_t __tag, const _Alloc& __a,
796 tuple<_UElements...>&& __in)
797 : _Inherited(__tag, __a,
798 static_cast<_Tuple_impl<0, _UElements...>&&>(__in))
799 { }
800
801 // tuple assignment
802
803 _GLIBCXX20_CONSTEXPR
804 tuple&
805 operator=(typename conditional<__assignable<const _Elements&...>(),
806 const tuple&,
807 const __nonesuch&>::type __in)
808 noexcept(__nothrow_assignable<const _Elements&...>())
809 {
810 this->_M_assign(__in);
811 return *this;
812 }
813
814 _GLIBCXX20_CONSTEXPR
815 tuple&
816 operator=(typename conditional<__assignable<_Elements...>(),
817 tuple&&,
818 __nonesuch&&>::type __in)
819 noexcept(__nothrow_assignable<_Elements...>())
820 {
821 this->_M_assign(std::move(__in));
822 return *this;
823 }
824
825 template<typename... _UElements>
826 _GLIBCXX20_CONSTEXPR
827 __enable_if_t<__assignable<const _UElements&...>(), tuple&>
828 operator=(const tuple<_UElements...>& __in)
829 noexcept(__nothrow_assignable<const _UElements&...>())
830 {
831 this->_M_assign(__in);
832 return *this;
833 }
834
835 template<typename... _UElements>
836 _GLIBCXX20_CONSTEXPR
837 __enable_if_t<__assignable<_UElements...>(), tuple&>
838 operator=(tuple<_UElements...>&& __in)
839 noexcept(__nothrow_assignable<_UElements...>())
840 {
841 this->_M_assign(std::move(__in));
842 return *this;
843 }
844
845 // tuple swap
846 _GLIBCXX20_CONSTEXPR
847 void
848 swap(tuple& __in)
849 noexcept(__and_<__is_nothrow_swappable<_Elements>...>::value)
850 { _Inherited::_M_swap(__in); }
851 };
852
853#if __cpp_deduction_guides201703L >= 201606
854 template<typename... _UTypes>
855 tuple(_UTypes...) -> tuple<_UTypes...>;
856 template<typename _T1, typename _T2>
857 tuple(pair<_T1, _T2>) -> tuple<_T1, _T2>;
858 template<typename _Alloc, typename... _UTypes>
859 tuple(allocator_arg_t, _Alloc, _UTypes...) -> tuple<_UTypes...>;
860 template<typename _Alloc, typename _T1, typename _T2>
861 tuple(allocator_arg_t, _Alloc, pair<_T1, _T2>) -> tuple<_T1, _T2>;
862 template<typename _Alloc, typename... _UTypes>
863 tuple(allocator_arg_t, _Alloc, tuple<_UTypes...>) -> tuple<_UTypes...>;
864#endif
865
866 // Explicit specialization, zero-element tuple.
867 template<>
868 class tuple<>
869 {
870 public:
871 void swap(tuple&) noexcept { /* no-op */ }
872 // We need the default since we're going to define no-op
873 // allocator constructors.
874 tuple() = default;
875 // No-op allocator constructors.
876 template<typename _Alloc>
877 _GLIBCXX20_CONSTEXPR
878 tuple(allocator_arg_t, const _Alloc&) noexcept { }
879 template<typename _Alloc>
880 _GLIBCXX20_CONSTEXPR
881 tuple(allocator_arg_t, const _Alloc&, const tuple&) noexcept { }
882 };
883
884 /// Partial specialization, 2-element tuple.
885 /// Includes construction and assignment from a pair.
886 template<typename _T1, typename _T2>
887 class tuple<_T1, _T2> : public _Tuple_impl<0, _T1, _T2>
888 {
889 typedef _Tuple_impl<0, _T1, _T2> _Inherited;
890
891 // Constraint for non-explicit default constructor
892 template<bool _Dummy, typename _U1, typename _U2>
893 using _ImplicitDefaultCtor = __enable_if_t<
894 _TupleConstraints<_Dummy, _U1, _U2>::
895 __is_implicitly_default_constructible(),
896 bool>;
897
898 // Constraint for explicit default constructor
899 template<bool _Dummy, typename _U1, typename _U2>
900 using _ExplicitDefaultCtor = __enable_if_t<
901 _TupleConstraints<_Dummy, _U1, _U2>::
902 __is_explicitly_default_constructible(),
903 bool>;
904
905 template<bool _Dummy>
906 using _TCC = _TupleConstraints<_Dummy, _T1, _T2>;
907
908 // Constraint for non-explicit constructors
909 template<bool _Cond, typename _U1, typename _U2>
910 using _ImplicitCtor = __enable_if_t<
911 _TCC<_Cond>::template __is_implicitly_constructible<_U1, _U2>(),
912 bool>;
913
914 // Constraint for non-explicit constructors
915 template<bool _Cond, typename _U1, typename _U2>
916 using _ExplicitCtor = __enable_if_t<
917 _TCC<_Cond>::template __is_explicitly_constructible<_U1, _U2>(),
918 bool>;
919
920 template<typename _U1, typename _U2>
921 static constexpr bool __assignable()
922 {
923 return __and_<is_assignable<_T1&, _U1>,
924 is_assignable<_T2&, _U2>>::value;
925 }
926
927 template<typename _U1, typename _U2>
928 static constexpr bool __nothrow_assignable()
929 {
930 return __and_<is_nothrow_assignable<_T1&, _U1>,
931 is_nothrow_assignable<_T2&, _U2>>::value;
932 }
933
934 template<typename _U1, typename _U2>
935 static constexpr bool __nothrow_constructible()
936 {
937 return __and_<is_nothrow_constructible<_T1, _U1>,
938 is_nothrow_constructible<_T2, _U2>>::value;
939 }
940
941 static constexpr bool __nothrow_default_constructible()
942 {
943 return __and_<is_nothrow_default_constructible<_T1>,
944 is_nothrow_default_constructible<_T2>>::value;
945 }
946
947 template<typename _U1>
948 static constexpr bool __is_alloc_arg()
949 { return is_same<__remove_cvref_t<_U1>, allocator_arg_t>::value; }
950
951 public:
952 template<bool _Dummy = true,
953 _ImplicitDefaultCtor<_Dummy, _T1, _T2> = true>
954 constexpr
955 tuple()
956 noexcept(__nothrow_default_constructible())
957 : _Inherited() { }
958
959 template<bool _Dummy = true,
960 _ExplicitDefaultCtor<_Dummy, _T1, _T2> = false>
961 explicit constexpr
962 tuple()
963 noexcept(__nothrow_default_constructible())
964 : _Inherited() { }
965
966 template<bool _Dummy = true,
967 _ImplicitCtor<_Dummy, const _T1&, const _T2&> = true>
968 constexpr
969 tuple(const _T1& __a1, const _T2& __a2)
970 noexcept(__nothrow_constructible<const _T1&, const _T2&>())
971 : _Inherited(__a1, __a2) { }
972
973 template<bool _Dummy = true,
974 _ExplicitCtor<_Dummy, const _T1&, const _T2&> = false>
975 explicit constexpr
976 tuple(const _T1& __a1, const _T2& __a2)
977 noexcept(__nothrow_constructible<const _T1&, const _T2&>())
978 : _Inherited(__a1, __a2) { }
979
980 template<typename _U1, typename _U2,
981 _ImplicitCtor<!__is_alloc_arg<_U1>(), _U1, _U2> = true>
982 constexpr
983 tuple(_U1&& __a1, _U2&& __a2)
984 noexcept(__nothrow_constructible<_U1, _U2>())
985 : _Inherited(std::forward<_U1>(__a1), std::forward<_U2>(__a2)) { }
986
987 template<typename _U1, typename _U2,
988 _ExplicitCtor<!__is_alloc_arg<_U1>(), _U1, _U2> = false>
989 explicit constexpr
990 tuple(_U1&& __a1, _U2&& __a2)
991 noexcept(__nothrow_constructible<_U1, _U2>())
992 : _Inherited(std::forward<_U1>(__a1), std::forward<_U2>(__a2)) { }
993
994 constexpr tuple(const tuple&) = default;
995
996 constexpr tuple(tuple&&) = default;
997
998 template<typename _U1, typename _U2,
999 _ImplicitCtor<true, const _U1&, const _U2&> = true>
1000 constexpr
1001 tuple(const tuple<_U1, _U2>& __in)
1002 noexcept(__nothrow_constructible<const _U1&, const _U2&>())
1003 : _Inherited(static_cast<const _Tuple_impl<0, _U1, _U2>&>(__in)) { }
1004
1005 template<typename _U1, typename _U2,
1006 _ExplicitCtor<true, const _U1&, const _U2&> = false>
1007 explicit constexpr
1008 tuple(const tuple<_U1, _U2>& __in)
1009 noexcept(__nothrow_constructible<const _U1&, const _U2&>())
1010 : _Inherited(static_cast<const _Tuple_impl<0, _U1, _U2>&>(__in)) { }
1011
1012 template<typename _U1, typename _U2,
1013 _ImplicitCtor<true, _U1, _U2> = true>
1014 constexpr
1015 tuple(tuple<_U1, _U2>&& __in)
1016 noexcept(__nothrow_constructible<_U1, _U2>())
1017 : _Inherited(static_cast<_Tuple_impl<0, _U1, _U2>&&>(__in)) { }
1018
1019 template<typename _U1, typename _U2,
1020 _ExplicitCtor<true, _U1, _U2> = false>
1021 explicit constexpr
1022 tuple(tuple<_U1, _U2>&& __in)
1023 noexcept(__nothrow_constructible<_U1, _U2>())
1024 : _Inherited(static_cast<_Tuple_impl<0, _U1, _U2>&&>(__in)) { }
1025
1026 template<typename _U1, typename _U2,
1027 _ImplicitCtor<true, const _U1&, const _U2&> = true>
1028 constexpr
1029 tuple(const pair<_U1, _U2>& __in)
1030 noexcept(__nothrow_constructible<const _U1&, const _U2&>())
1031 : _Inherited(__in.first, __in.second) { }
1032
1033 template<typename _U1, typename _U2,
1034 _ExplicitCtor<true, const _U1&, const _U2&> = false>
1035 explicit constexpr
1036 tuple(const pair<_U1, _U2>& __in)
1037 noexcept(__nothrow_constructible<const _U1&, const _U2&>())
1038 : _Inherited(__in.first, __in.second) { }
1039
1040 template<typename _U1, typename _U2,
1041 _ImplicitCtor<true, _U1, _U2> = true>
1042 constexpr
1043 tuple(pair<_U1, _U2>&& __in)
1044 noexcept(__nothrow_constructible<_U1, _U2>())
1045 : _Inherited(std::forward<_U1>(__in.first),
1046 std::forward<_U2>(__in.second)) { }
1047
1048 template<typename _U1, typename _U2,
1049 _ExplicitCtor<true, _U1, _U2> = false>
1050 explicit constexpr
1051 tuple(pair<_U1, _U2>&& __in)
1052 noexcept(__nothrow_constructible<_U1, _U2>())
1053 : _Inherited(std::forward<_U1>(__in.first),
1054 std::forward<_U2>(__in.second)) { }
1055
1056 // Allocator-extended constructors.
1057
1058 template<typename _Alloc,
1059 _ImplicitDefaultCtor<is_object<_Alloc>::value, _T1, _T2> = true>
1060 _GLIBCXX20_CONSTEXPR
1061 tuple(allocator_arg_t __tag, const _Alloc& __a)
1062 : _Inherited(__tag, __a) { }
1063
1064 template<typename _Alloc, bool _Dummy = true,
1065 _ImplicitCtor<_Dummy, const _T1&, const _T2&> = true>
1066 _GLIBCXX20_CONSTEXPR
1067 tuple(allocator_arg_t __tag, const _Alloc& __a,
1068 const _T1& __a1, const _T2& __a2)
1069 : _Inherited(__tag, __a, __a1, __a2) { }
1070
1071 template<typename _Alloc, bool _Dummy = true,
1072 _ExplicitCtor<_Dummy, const _T1&, const _T2&> = false>
1073 explicit
1074 _GLIBCXX20_CONSTEXPR
1075 tuple(allocator_arg_t __tag, const _Alloc& __a,
1076 const _T1& __a1, const _T2& __a2)
1077 : _Inherited(__tag, __a, __a1, __a2) { }
1078
1079 template<typename _Alloc, typename _U1, typename _U2,
1080 _ImplicitCtor<true, _U1, _U2> = true>
1081 _GLIBCXX20_CONSTEXPR
1082 tuple(allocator_arg_t __tag, const _Alloc& __a, _U1&& __a1, _U2&& __a2)
1083 : _Inherited(__tag, __a, std::forward<_U1>(__a1),
1084 std::forward<_U2>(__a2)) { }
1085
1086 template<typename _Alloc, typename _U1, typename _U2,
1087 _ExplicitCtor<true, _U1, _U2> = false>
1088 explicit
1089 _GLIBCXX20_CONSTEXPR
1090 tuple(allocator_arg_t __tag, const _Alloc& __a,
1091 _U1&& __a1, _U2&& __a2)
1092 : _Inherited(__tag, __a, std::forward<_U1>(__a1),
1093 std::forward<_U2>(__a2)) { }
1094
1095 template<typename _Alloc>
1096 _GLIBCXX20_CONSTEXPR
1097 tuple(allocator_arg_t __tag, const _Alloc& __a, const tuple& __in)
1098 : _Inherited(__tag, __a, static_cast<const _Inherited&>(__in)) { }
1099
1100 template<typename _Alloc>
1101 _GLIBCXX20_CONSTEXPR
1102 tuple(allocator_arg_t __tag, const _Alloc& __a, tuple&& __in)
1103 : _Inherited(__tag, __a, static_cast<_Inherited&&>(__in)) { }
1104
1105 template<typename _Alloc, typename _U1, typename _U2,
1106 _ImplicitCtor<true, const _U1&, const _U2&> = true>
1107 _GLIBCXX20_CONSTEXPR
1108 tuple(allocator_arg_t __tag, const _Alloc& __a,
1109 const tuple<_U1, _U2>& __in)
1110 : _Inherited(__tag, __a,
1111 static_cast<const _Tuple_impl<0, _U1, _U2>&>(__in))
1112 { }
1113
1114 template<typename _Alloc, typename _U1, typename _U2,
1115 _ExplicitCtor<true, const _U1&, const _U2&> = false>
1116 explicit
1117 _GLIBCXX20_CONSTEXPR
1118 tuple(allocator_arg_t __tag, const _Alloc& __a,
1119 const tuple<_U1, _U2>& __in)
1120 : _Inherited(__tag, __a,
1121 static_cast<const _Tuple_impl<0, _U1, _U2>&>(__in))
1122 { }
1123
1124 template<typename _Alloc, typename _U1, typename _U2,
1125 _ImplicitCtor<true, _U1, _U2> = true>
1126 _GLIBCXX20_CONSTEXPR
1127 tuple(allocator_arg_t __tag, const _Alloc& __a, tuple<_U1, _U2>&& __in)
1128 : _Inherited(__tag, __a, static_cast<_Tuple_impl<0, _U1, _U2>&&>(__in))
1129 { }
1130
1131 template<typename _Alloc, typename _U1, typename _U2,
1132 _ExplicitCtor<true, _U1, _U2> = false>
1133 explicit
1134 _GLIBCXX20_CONSTEXPR
1135 tuple(allocator_arg_t __tag, const _Alloc& __a, tuple<_U1, _U2>&& __in)
1136 : _Inherited(__tag, __a, static_cast<_Tuple_impl<0, _U1, _U2>&&>(__in))
1137 { }
1138
1139 template<typename _Alloc, typename _U1, typename _U2,
1140 _ImplicitCtor<true, const _U1&, const _U2&> = true>
1141 _GLIBCXX20_CONSTEXPR
1142 tuple(allocator_arg_t __tag, const _Alloc& __a,
1143 const pair<_U1, _U2>& __in)
1144 : _Inherited(__tag, __a, __in.first, __in.second) { }
1145
1146 template<typename _Alloc, typename _U1, typename _U2,
1147 _ExplicitCtor<true, const _U1&, const _U2&> = false>
1148 explicit
1149 _GLIBCXX20_CONSTEXPR
1150 tuple(allocator_arg_t __tag, const _Alloc& __a,
1151 const pair<_U1, _U2>& __in)
1152 : _Inherited(__tag, __a, __in.first, __in.second) { }
1153
1154 template<typename _Alloc, typename _U1, typename _U2,
1155 _ImplicitCtor<true, _U1, _U2> = true>
1156 _GLIBCXX20_CONSTEXPR
1157 tuple(allocator_arg_t __tag, const _Alloc& __a, pair<_U1, _U2>&& __in)
1158 : _Inherited(__tag, __a, std::forward<_U1>(__in.first),
1159 std::forward<_U2>(__in.second)) { }
1160
1161 template<typename _Alloc, typename _U1, typename _U2,
1162 _ExplicitCtor<true, _U1, _U2> = false>
1163 explicit
1164 _GLIBCXX20_CONSTEXPR
1165 tuple(allocator_arg_t __tag, const _Alloc& __a, pair<_U1, _U2>&& __in)
1166 : _Inherited(__tag, __a, std::forward<_U1>(__in.first),
1167 std::forward<_U2>(__in.second)) { }
1168
1169 // Tuple assignment.
1170
1171 _GLIBCXX20_CONSTEXPR
1172 tuple&
1173 operator=(typename conditional<__assignable<const _T1&, const _T2&>(),
1174 const tuple&,
1175 const __nonesuch&>::type __in)
1176 noexcept(__nothrow_assignable<const _T1&, const _T2&>())
1177 {
1178 this->_M_assign(__in);
1179 return *this;
1180 }
1181
1182 _GLIBCXX20_CONSTEXPR
1183 tuple&
1184 operator=(typename conditional<__assignable<_T1, _T2>(),
1185 tuple&&,
1186 __nonesuch&&>::type __in)
1187 noexcept(__nothrow_assignable<_T1, _T2>())
1188 {
1189 this->_M_assign(std::move(__in));
1190 return *this;
1191 }
1192
1193 template<typename _U1, typename _U2>
1194 _GLIBCXX20_CONSTEXPR
1195 __enable_if_t<__assignable<const _U1&, const _U2&>(), tuple&>
1196 operator=(const tuple<_U1, _U2>& __in)
1197 noexcept(__nothrow_assignable<const _U1&, const _U2&>())
1198 {
1199 this->_M_assign(__in);
1200 return *this;
1201 }
1202
1203 template<typename _U1, typename _U2>
1204 _GLIBCXX20_CONSTEXPR
1205 __enable_if_t<__assignable<_U1, _U2>(), tuple&>
1206 operator=(tuple<_U1, _U2>&& __in)
1207 noexcept(__nothrow_assignable<_U1, _U2>())
1208 {
1209 this->_M_assign(std::move(__in));
1210 return *this;
1211 }
1212
1213 template<typename _U1, typename _U2>
1214 _GLIBCXX20_CONSTEXPR
1215 __enable_if_t<__assignable<const _U1&, const _U2&>(), tuple&>
1216 operator=(const pair<_U1, _U2>& __in)
1217 noexcept(__nothrow_assignable<const _U1&, const _U2&>())
1218 {
1219 this->_M_head(*this) = __in.first;
1220 this->_M_tail(*this)._M_head(*this) = __in.second;
1221 return *this;
1222 }
1223
1224 template<typename _U1, typename _U2>
1225 _GLIBCXX20_CONSTEXPR
1226 __enable_if_t<__assignable<_U1, _U2>(), tuple&>
1227 operator=(pair<_U1, _U2>&& __in)
1228 noexcept(__nothrow_assignable<_U1, _U2>())
1229 {
1230 this->_M_head(*this) = std::forward<_U1>(__in.first);
1231 this->_M_tail(*this)._M_head(*this) = std::forward<_U2>(__in.second);
1232 return *this;
1233 }
1234
1235 _GLIBCXX20_CONSTEXPR
1236 void
1237 swap(tuple& __in)
1238 noexcept(__and_<__is_nothrow_swappable<_T1>,
1239 __is_nothrow_swappable<_T2>>::value)
1240 { _Inherited::_M_swap(__in); }
1241 };
1242
1243
1244 /// class tuple_size
1245 template<typename... _Elements>
1246 struct tuple_size<tuple<_Elements...>>
1247 : public integral_constant<std::size_t, sizeof...(_Elements)> { };
1248
1249#if __cplusplus201703L > 201402L
1250 template <typename _Tp>
1251 inline constexpr size_t tuple_size_v = tuple_size<_Tp>::value;
1252#endif
1253
1254 /**
1255 * Recursive case for tuple_element: strip off the first element in
1256 * the tuple and retrieve the (i-1)th element of the remaining tuple.
1257 */
1258 template<std::size_t __i, typename _Head, typename... _Tail>
1259 struct tuple_element<__i, tuple<_Head, _Tail...> >
1260 : tuple_element<__i - 1, tuple<_Tail...> > { };
1261
1262 /**
1263 * Basis case for tuple_element: The first element is the one we're seeking.
1264 */
1265 template<typename _Head, typename... _Tail>
1266 struct tuple_element<0, tuple<_Head, _Tail...> >
1267 {
1268 typedef _Head type;
1269 };
1270
1271 /**
1272 * Error case for tuple_element: invalid index.
1273 */
1274 template<size_t __i>
1275 struct tuple_element<__i, tuple<>>
1276 {
1277 static_assert(__i < tuple_size<tuple<>>::value,
1278 "tuple index is in range");
1279 };
1280
1281 template<std::size_t __i, typename _Head, typename... _Tail>
1282 constexpr _Head&
1283 __get_helper(_Tuple_impl<__i, _Head, _Tail...>& __t) noexcept
1284 { return _Tuple_impl<__i, _Head, _Tail...>::_M_head(__t); }
23
Calling '_Tuple_impl::_M_head'
26
Returning from '_Tuple_impl::_M_head'
33
Calling '_Tuple_impl::_M_head'
36
Returning from '_Tuple_impl::_M_head'
1285
1286 template<std::size_t __i, typename _Head, typename... _Tail>
1287 constexpr const _Head&
1288 __get_helper(const _Tuple_impl<__i, _Head, _Tail...>& __t) noexcept
1289 { return _Tuple_impl<__i, _Head, _Tail...>::_M_head(__t); }
1290
1291 /// Return a reference to the ith element of a tuple.
1292 template<std::size_t __i, typename... _Elements>
1293 constexpr __tuple_element_t<__i, tuple<_Elements...>>&
1294 get(tuple<_Elements...>& __t) noexcept
1295 { return std::__get_helper<__i>(__t); }
22
Calling '__get_helper<0, std::vector<SwFrameFormat *, std::allocator<SwFrameFormat *>> *, std::default_delete<std::vector<SwFrameFormat *, std::allocator<SwFrameFormat *>>>>'
27
Returning from '__get_helper<0, std::vector<SwFrameFormat *, std::allocator<SwFrameFormat *>> *, std::default_delete<std::vector<SwFrameFormat *, std::allocator<SwFrameFormat *>>>>'
32
Calling '__get_helper<0, std::vector<SwFrameFormat *, std::allocator<SwFrameFormat *>> *, std::default_delete<std::vector<SwFrameFormat *, std::allocator<SwFrameFormat *>>>>'
37
Returning from '__get_helper<0, std::vector<SwFrameFormat *, std::allocator<SwFrameFormat *>> *, std::default_delete<std::vector<SwFrameFormat *, std::allocator<SwFrameFormat *>>>>'
1296
1297 /// Return a const reference to the ith element of a const tuple.
1298 template<std::size_t __i, typename... _Elements>
1299 constexpr const __tuple_element_t<__i, tuple<_Elements...>>&
1300 get(const tuple<_Elements...>& __t) noexcept
1301 { return std::__get_helper<__i>(__t); }
1302
1303 /// Return an rvalue reference to the ith element of a tuple rvalue.
1304 template<std::size_t __i, typename... _Elements>
1305 constexpr __tuple_element_t<__i, tuple<_Elements...>>&&
1306 get(tuple<_Elements...>&& __t) noexcept
1307 {
1308 typedef __tuple_element_t<__i, tuple<_Elements...>> __element_type;
1309 return std::forward<__element_type&&>(std::get<__i>(__t));
1310 }
1311
1312 /// Return a const rvalue reference to the ith element of a const tuple rvalue.
1313 template<std::size_t __i, typename... _Elements>
1314 constexpr const __tuple_element_t<__i, tuple<_Elements...>>&&
1315 get(const tuple<_Elements...>&& __t) noexcept
1316 {
1317 typedef __tuple_element_t<__i, tuple<_Elements...>> __element_type;
1318 return std::forward<const __element_type&&>(std::get<__i>(__t));
1319 }
1320
1321#if __cplusplus201703L >= 201402L
1322
1323#define __cpp_lib_tuples_by_type201304 201304
1324
1325 template<typename _Head, size_t __i, typename... _Tail>
1326 constexpr _Head&
1327 __get_helper2(_Tuple_impl<__i, _Head, _Tail...>& __t) noexcept
1328 { return _Tuple_impl<__i, _Head, _Tail...>::_M_head(__t); }
1329
1330 template<typename _Head, size_t __i, typename... _Tail>
1331 constexpr const _Head&
1332 __get_helper2(const _Tuple_impl<__i, _Head, _Tail...>& __t) noexcept
1333 { return _Tuple_impl<__i, _Head, _Tail...>::_M_head(__t); }
1334
1335 /// Return a reference to the unique element of type _Tp of a tuple.
1336 template <typename _Tp, typename... _Types>
1337 constexpr _Tp&
1338 get(tuple<_Types...>& __t) noexcept
1339 { return std::__get_helper2<_Tp>(__t); }
1340
1341 /// Return a reference to the unique element of type _Tp of a tuple rvalue.
1342 template <typename _Tp, typename... _Types>
1343 constexpr _Tp&&
1344 get(tuple<_Types...>&& __t) noexcept
1345 { return std::forward<_Tp&&>(std::__get_helper2<_Tp>(__t)); }
1346
1347 /// Return a const reference to the unique element of type _Tp of a tuple.
1348 template <typename _Tp, typename... _Types>
1349 constexpr const _Tp&
1350 get(const tuple<_Types...>& __t) noexcept
1351 { return std::__get_helper2<_Tp>(__t); }
1352
1353 /// Return a const reference to the unique element of type _Tp of
1354 /// a const tuple rvalue.
1355 template <typename _Tp, typename... _Types>
1356 constexpr const _Tp&&
1357 get(const tuple<_Types...>&& __t) noexcept
1358 { return std::forward<const _Tp&&>(std::__get_helper2<_Tp>(__t)); }
1359#endif
1360
1361 // This class performs the comparison operations on tuples
1362 template<typename _Tp, typename _Up, size_t __i, size_t __size>
1363 struct __tuple_compare
1364 {
1365 static constexpr bool
1366 __eq(const _Tp& __t, const _Up& __u)
1367 {
1368 return bool(std::get<__i>(__t) == std::get<__i>(__u))
1369 && __tuple_compare<_Tp, _Up, __i + 1, __size>::__eq(__t, __u);
1370 }
1371
1372 static constexpr bool
1373 __less(const _Tp& __t, const _Up& __u)
1374 {
1375 return bool(std::get<__i>(__t) < std::get<__i>(__u))
1376 || (!bool(std::get<__i>(__u) < std::get<__i>(__t))
1377 && __tuple_compare<_Tp, _Up, __i + 1, __size>::__less(__t, __u));
1378 }
1379 };
1380
1381 template<typename _Tp, typename _Up, size_t __size>
1382 struct __tuple_compare<_Tp, _Up, __size, __size>
1383 {
1384 static constexpr bool
1385 __eq(const _Tp&, const _Up&) { return true; }
1386
1387 static constexpr bool
1388 __less(const _Tp&, const _Up&) { return false; }
1389 };
1390
1391 template<typename... _TElements, typename... _UElements>
1392 constexpr bool
1393 operator==(const tuple<_TElements...>& __t,
1394 const tuple<_UElements...>& __u)
1395 {
1396 static_assert(sizeof...(_TElements) == sizeof...(_UElements),
1397 "tuple objects can only be compared if they have equal sizes.");
1398 using __compare = __tuple_compare<tuple<_TElements...>,
1399 tuple<_UElements...>,
1400 0, sizeof...(_TElements)>;
1401 return __compare::__eq(__t, __u);
1402 }
1403
1404#if __cpp_lib_three_way_comparison
1405 template<typename _Cat, typename _Tp, typename _Up>
1406 constexpr _Cat
1407 __tuple_cmp(const _Tp&, const _Up&, index_sequence<>)
1408 { return _Cat::equivalent; }
1409
1410 template<typename _Cat, typename _Tp, typename _Up,
1411 size_t _Idx0, size_t... _Idxs>
1412 constexpr _Cat
1413 __tuple_cmp(const _Tp& __t, const _Up& __u,
1414 index_sequence<_Idx0, _Idxs...>)
1415 {
1416 auto __c
1417 = __detail::__synth3way(std::get<_Idx0>(__t), std::get<_Idx0>(__u));
1418 if (__c != 0)
1419 return __c;
1420 return std::__tuple_cmp<_Cat>(__t, __u, index_sequence<_Idxs...>());
1421 }
1422
1423 template<typename... _Tps, typename... _Ups>
1424 constexpr
1425 common_comparison_category_t<__detail::__synth3way_t<_Tps, _Ups>...>
1426 operator<=>(const tuple<_Tps...>& __t, const tuple<_Ups...>& __u)
1427 {
1428 using _Cat
1429 = common_comparison_category_t<__detail::__synth3way_t<_Tps, _Ups>...>;
1430 return std::__tuple_cmp<_Cat>(__t, __u, index_sequence_for<_Tps...>());
1431 }
1432#else
1433 template<typename... _TElements, typename... _UElements>
1434 constexpr bool
1435 operator<(const tuple<_TElements...>& __t,
1436 const tuple<_UElements...>& __u)
1437 {
1438 static_assert(sizeof...(_TElements) == sizeof...(_UElements),
1439 "tuple objects can only be compared if they have equal sizes.");
1440 using __compare = __tuple_compare<tuple<_TElements...>,
1441 tuple<_UElements...>,
1442 0, sizeof...(_TElements)>;
1443 return __compare::__less(__t, __u);
1444 }
1445
1446 template<typename... _TElements, typename... _UElements>
1447 constexpr bool
1448 operator!=(const tuple<_TElements...>& __t,
1449 const tuple<_UElements...>& __u)
1450 { return !(__t == __u); }
1451
1452 template<typename... _TElements, typename... _UElements>
1453 constexpr bool
1454 operator>(const tuple<_TElements...>& __t,
1455 const tuple<_UElements...>& __u)
1456 { return __u < __t; }
1457
1458 template<typename... _TElements, typename... _UElements>
1459 constexpr bool
1460 operator<=(const tuple<_TElements...>& __t,
1461 const tuple<_UElements...>& __u)
1462 { return !(__u < __t); }
1463
1464 template<typename... _TElements, typename... _UElements>
1465 constexpr bool
1466 operator>=(const tuple<_TElements...>& __t,
1467 const tuple<_UElements...>& __u)
1468 { return !(__t < __u); }
1469#endif // three_way_comparison
1470
1471 // NB: DR 705.
1472 template<typename... _Elements>
1473 constexpr tuple<typename __decay_and_strip<_Elements>::__type...>
1474 make_tuple(_Elements&&... __args)
1475 {
1476 typedef tuple<typename __decay_and_strip<_Elements>::__type...>
1477 __result_type;
1478 return __result_type(std::forward<_Elements>(__args)...);
1479 }
1480
1481 // _GLIBCXX_RESOLVE_LIB_DEFECTS
1482 // 2275. Why is forward_as_tuple not constexpr?
1483 /// std::forward_as_tuple
1484 template<typename... _Elements>
1485 constexpr tuple<_Elements&&...>
1486 forward_as_tuple(_Elements&&... __args) noexcept
1487 { return tuple<_Elements&&...>(std::forward<_Elements>(__args)...); }
1488
1489 template<size_t, typename, typename, size_t>
1490 struct __make_tuple_impl;
1491
1492 template<size_t _Idx, typename _Tuple, typename... _Tp, size_t _Nm>
1493 struct __make_tuple_impl<_Idx, tuple<_Tp...>, _Tuple, _Nm>
1494 : __make_tuple_impl<_Idx + 1,
1495 tuple<_Tp..., __tuple_element_t<_Idx, _Tuple>>,
1496 _Tuple, _Nm>
1497 { };
1498
1499 template<std::size_t _Nm, typename _Tuple, typename... _Tp>
1500 struct __make_tuple_impl<_Nm, tuple<_Tp...>, _Tuple, _Nm>
1501 {
1502 typedef tuple<_Tp...> __type;
1503 };
1504
1505 template<typename _Tuple>
1506 struct __do_make_tuple
1507 : __make_tuple_impl<0, tuple<>, _Tuple, std::tuple_size<_Tuple>::value>
1508 { };
1509
1510 // Returns the std::tuple equivalent of a tuple-like type.
1511 template<typename _Tuple>
1512 struct __make_tuple
1513 : public __do_make_tuple<__remove_cvref_t<_Tuple>>
1514 { };
1515
1516 // Combines several std::tuple's into a single one.
1517 template<typename...>
1518 struct __combine_tuples;
1519
1520 template<>
1521 struct __combine_tuples<>
1522 {
1523 typedef tuple<> __type;
1524 };
1525
1526 template<typename... _Ts>
1527 struct __combine_tuples<tuple<_Ts...>>
1528 {
1529 typedef tuple<_Ts...> __type;
1530 };
1531
1532 template<typename... _T1s, typename... _T2s, typename... _Rem>
1533 struct __combine_tuples<tuple<_T1s...>, tuple<_T2s...>, _Rem...>
1534 {
1535 typedef typename __combine_tuples<tuple<_T1s..., _T2s...>,
1536 _Rem...>::__type __type;
1537 };
1538
1539 // Computes the result type of tuple_cat given a set of tuple-like types.
1540 template<typename... _Tpls>
1541 struct __tuple_cat_result
1542 {
1543 typedef typename __combine_tuples
1544 <typename __make_tuple<_Tpls>::__type...>::__type __type;
1545 };
1546
1547 // Helper to determine the index set for the first tuple-like
1548 // type of a given set.
1549 template<typename...>
1550 struct __make_1st_indices;
1551
1552 template<>
1553 struct __make_1st_indices<>
1554 {
1555 typedef std::_Index_tuple<> __type;
1556 };
1557
1558 template<typename _Tp, typename... _Tpls>
1559 struct __make_1st_indices<_Tp, _Tpls...>
1560 {
1561 typedef typename std::_Build_index_tuple<std::tuple_size<
1562 typename std::remove_reference<_Tp>::type>::value>::__type __type;
1563 };
1564
1565 // Performs the actual concatenation by step-wise expanding tuple-like
1566 // objects into the elements, which are finally forwarded into the
1567 // result tuple.
1568 template<typename _Ret, typename _Indices, typename... _Tpls>
1569 struct __tuple_concater;
1570
1571 template<typename _Ret, std::size_t... _Is, typename _Tp, typename... _Tpls>
1572 struct __tuple_concater<_Ret, std::_Index_tuple<_Is...>, _Tp, _Tpls...>
1573 {
1574 template<typename... _Us>
1575 static constexpr _Ret
1576 _S_do(_Tp&& __tp, _Tpls&&... __tps, _Us&&... __us)
1577 {
1578 typedef typename __make_1st_indices<_Tpls...>::__type __idx;
1579 typedef __tuple_concater<_Ret, __idx, _Tpls...> __next;
1580 return __next::_S_do(std::forward<_Tpls>(__tps)...,
1581 std::forward<_Us>(__us)...,
1582 std::get<_Is>(std::forward<_Tp>(__tp))...);
1583 }
1584 };
1585
1586 template<typename _Ret>
1587 struct __tuple_concater<_Ret, std::_Index_tuple<>>
1588 {
1589 template<typename... _Us>
1590 static constexpr _Ret
1591 _S_do(_Us&&... __us)
1592 {
1593 return _Ret(std::forward<_Us>(__us)...);
1594 }
1595 };
1596
1597 /// tuple_cat
1598 template<typename... _Tpls, typename = typename
1599 enable_if<__and_<__is_tuple_like<_Tpls>...>::value>::type>
1600 constexpr auto
1601 tuple_cat(_Tpls&&... __tpls)
1602 -> typename __tuple_cat_result<_Tpls...>::__type
1603 {
1604 typedef typename __tuple_cat_result<_Tpls...>::__type __ret;
1605 typedef typename __make_1st_indices<_Tpls...>::__type __idx;
1606 typedef __tuple_concater<__ret, __idx, _Tpls...> __concater;
1607 return __concater::_S_do(std::forward<_Tpls>(__tpls)...);
1608 }
1609
1610 // _GLIBCXX_RESOLVE_LIB_DEFECTS
1611 // 2301. Why is tie not constexpr?
1612 /// tie
1613 template<typename... _Elements>
1614 constexpr tuple<_Elements&...>
1615 tie(_Elements&... __args) noexcept
1616 { return tuple<_Elements&...>(__args...); }
1617
1618 /// swap
1619 template<typename... _Elements>
1620 _GLIBCXX20_CONSTEXPR
1621 inline
1622#if __cplusplus201703L > 201402L || !defined(__STRICT_ANSI__1) // c++1z or gnu++11
1623 // Constrained free swap overload, see p0185r1
1624 typename enable_if<__and_<__is_swappable<_Elements>...>::value
1625 >::type
1626#else
1627 void
1628#endif
1629 swap(tuple<_Elements...>& __x, tuple<_Elements...>& __y)
1630 noexcept(noexcept(__x.swap(__y)))
1631 { __x.swap(__y); }
1632
1633#if __cplusplus201703L > 201402L || !defined(__STRICT_ANSI__1) // c++1z or gnu++11
1634 template<typename... _Elements>
1635 _GLIBCXX20_CONSTEXPR
1636 typename enable_if<!__and_<__is_swappable<_Elements>...>::value>::type
1637 swap(tuple<_Elements...>&, tuple<_Elements...>&) = delete;
1638#endif
1639
1640 // A class (and instance) which can be used in 'tie' when an element
1641 // of a tuple is not required.
1642 // _GLIBCXX14_CONSTEXPR
1643 // 2933. PR for LWG 2773 could be clearer
1644 struct _Swallow_assign
1645 {
1646 template<class _Tp>
1647 _GLIBCXX14_CONSTEXPRconstexpr const _Swallow_assign&
1648 operator=(const _Tp&) const
1649 { return *this; }
1650 };
1651
1652 // _GLIBCXX_RESOLVE_LIB_DEFECTS
1653 // 2773. Making std::ignore constexpr
1654 _GLIBCXX17_INLINEinline constexpr _Swallow_assign ignore{};
1655
1656 /// Partial specialization for tuples
1657 template<typename... _Types, typename _Alloc>
1658 struct uses_allocator<tuple<_Types...>, _Alloc> : true_type { };
1659
1660 // See stl_pair.h...
1661 /** "piecewise construction" using a tuple of arguments for each member.
1662 *
1663 * @param __first Arguments for the first member of the pair.
1664 * @param __second Arguments for the second member of the pair.
1665 *
1666 * The elements of each tuple will be used as the constructor arguments
1667 * for the data members of the pair.
1668 */
1669 template<class _T1, class _T2>
1670 template<typename... _Args1, typename... _Args2>
1671 _GLIBCXX20_CONSTEXPR
1672 inline
1673 pair<_T1, _T2>::
1674 pair(piecewise_construct_t,
1675 tuple<_Args1...> __first, tuple<_Args2...> __second)
1676 : pair(__first, __second,
1677 typename _Build_index_tuple<sizeof...(_Args1)>::__type(),
1678 typename _Build_index_tuple<sizeof...(_Args2)>::__type())
1679 { }
1680
1681 template<class _T1, class _T2>
1682 template<typename... _Args1, std::size_t... _Indexes1,
1683 typename... _Args2, std::size_t... _Indexes2>
1684 _GLIBCXX20_CONSTEXPR inline
1685 pair<_T1, _T2>::
1686 pair(tuple<_Args1...>& __tuple1, tuple<_Args2...>& __tuple2,
1687 _Index_tuple<_Indexes1...>, _Index_tuple<_Indexes2...>)
1688 : first(std::forward<_Args1>(std::get<_Indexes1>(__tuple1))...),
1689 second(std::forward<_Args2>(std::get<_Indexes2>(__tuple2))...)
1690 { }
1691
1692#if __cplusplus201703L >= 201703L
1693
1694 // Unpack a std::tuple into a type trait and use its value.
1695 // For cv std::tuple<_Up> the result is _Trait<_Tp, cv _Up...>::value.
1696 // For cv std::tuple<_Up>& the result is _Trait<_Tp, cv _Up&...>::value.
1697 // Otherwise the result is false (because we don't know if std::get throws).
1698 template<template<typename...> class _Trait, typename _Tp, typename _Tuple>
1699 inline constexpr bool __unpack_std_tuple = false;
1700
1701 template<template<typename...> class _Trait, typename _Tp, typename... _Up>
1702 inline constexpr bool __unpack_std_tuple<_Trait, _Tp, tuple<_Up...>>
1703 = _Trait<_Tp, _Up...>::value;
1704
1705 template<template<typename...> class _Trait, typename _Tp, typename... _Up>
1706 inline constexpr bool __unpack_std_tuple<_Trait, _Tp, tuple<_Up...>&>
1707 = _Trait<_Tp, _Up&...>::value;
1708
1709 template<template<typename...> class _Trait, typename _Tp, typename... _Up>
1710 inline constexpr bool __unpack_std_tuple<_Trait, _Tp, const tuple<_Up...>>
1711 = _Trait<_Tp, const _Up...>::value;
1712
1713 template<template<typename...> class _Trait, typename _Tp, typename... _Up>
1714 inline constexpr bool __unpack_std_tuple<_Trait, _Tp, const tuple<_Up...>&>
1715 = _Trait<_Tp, const _Up&...>::value;
1716
1717# define __cpp_lib_apply201603 201603
1718
1719 template <typename _Fn, typename _Tuple, size_t... _Idx>
1720 constexpr decltype(auto)
1721 __apply_impl(_Fn&& __f, _Tuple&& __t, index_sequence<_Idx...>)
1722 {
1723 return std::__invoke(std::forward<_Fn>(__f),
1724 std::get<_Idx>(std::forward<_Tuple>(__t))...);
1725 }
1726
1727 template <typename _Fn, typename _Tuple>
1728 constexpr decltype(auto)
1729 apply(_Fn&& __f, _Tuple&& __t)
1730 noexcept(__unpack_std_tuple<is_nothrow_invocable, _Fn, _Tuple>)
1731 {
1732 using _Indices
1733 = make_index_sequence<tuple_size_v<remove_reference_t<_Tuple>>>;
1734 return std::__apply_impl(std::forward<_Fn>(__f),
1735 std::forward<_Tuple>(__t),
1736 _Indices{});
1737 }
1738
1739#define __cpp_lib_make_from_tuple201606 201606
1740
1741 template <typename _Tp, typename _Tuple, size_t... _Idx>
1742 constexpr _Tp
1743 __make_from_tuple_impl(_Tuple&& __t, index_sequence<_Idx...>)
1744 { return _Tp(std::get<_Idx>(std::forward<_Tuple>(__t))...); }
1745
1746 template <typename _Tp, typename _Tuple>
1747 constexpr _Tp
1748 make_from_tuple(_Tuple&& __t)
1749 noexcept(__unpack_std_tuple<is_nothrow_constructible, _Tp, _Tuple>)
1750 {
1751 return __make_from_tuple_impl<_Tp>(
1752 std::forward<_Tuple>(__t),
1753 make_index_sequence<tuple_size_v<remove_reference_t<_Tuple>>>{});
1754 }
1755#endif // C++17
1756
1757 /// @}
1758
1759_GLIBCXX_END_NAMESPACE_VERSION
1760} // namespace std
1761
1762#endif // C++11
1763
1764#endif // _GLIBCXX_TUPLE

/home/maarten/src/libreoffice/core/sw/inc/ndtxt.hxx

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#ifndef INCLUDED_SW_INC_NDTXT_HXX
20#define INCLUDED_SW_INC_NDTXT_HXX
21
22#include <cppuhelper/weakref.hxx>
23
24#include "swdllapi.h"
25#include "node.hxx"
26#include "hintids.hxx"
27#include "ndhints.hxx"
28#include "SwNumberTreeTypes.hxx"
29#include "IDocumentContentOperations.hxx"
30#include "modeltoviewhelper.hxx"
31
32#include <sfx2/Metadatable.hxx>
33
34#include <memory>
35#include <vector>
36#include <set>
37#include <functional>
38
39class SfxHint;
40class SwNumRule;
41class SwNodeNum;
42class SvxLRSpaceItem;
43
44namespace utl {
45 class TransliterationWrapper;
46}
47namespace vcl
48{
49class Font;
50}
51
52class SwContentFrame;
53class SwTextField;
54class SwTextInputField;
55class SfxItemSet;
56class SwUndoTransliterate;
57struct SwSpellArgs;
58struct SwConversionArgs;
59class SwInterHyphInfo;
60class SwWrongList;
61class SwGrammarMarkUp;
62struct SwDocStat;
63struct SwParaIdleData_Impl;
64enum class ExpandMode;
65enum class SwFieldIds : sal_uInt16;
66class SwField;
67
68namespace sw::mark { enum class RestoreMode; }
69
70namespace com::sun::star {
71 namespace uno {
72 template < class > class Sequence;
73 }
74 namespace text { class XTextContent; }
75}
76
77typedef std::set< sal_Int32 > SwSoftPageBreakList;
78
79/// SwTextNode is a paragraph in the document model.
80class SW_DLLPUBLIC__attribute__ ((visibility("default"))) SwTextNode
81 : public SwContentNode
82 , public ::sfx2::Metadatable
83{
84 friend class SwContentNode;
85 /// For creating the first TextNode.
86 friend class SwDoc; ///< CTOR and AppendTextNode()
87 friend class SwNodes;
88 friend class SwTextFrame;
89 friend class SwScriptInfo;
90
91 /** May be 0. It is only then not 0 if it contains hard attributes.
92 Therefore: never access directly! */
93 std::unique_ptr<SwpHints> m_pSwpHints;
94
95 mutable std::unique_ptr<SwNodeNum> mpNodeNum; ///< Numbering for this paragraph.
96 mutable std::unique_ptr<SwNodeNum> mpNodeNumRLHidden; ///< Numbering for this paragraph (hidden redlines)
97
98 OUString m_Text;
99
100 SwParaIdleData_Impl* m_pParaIdleData_Impl;
101
102 /** Some of the chars this para are hidden. Paragraph has to be reformatted
103 on changing the view to print preview. */
104 mutable bool m_bContainsHiddenChars : 1;
105 /// The whole paragraph is hidden because of the hidden text attribute
106 mutable bool m_bHiddenCharsHidePara : 1;
107 /// The last two flags have to be recalculated if this flag is set:
108 mutable bool m_bRecalcHiddenCharFlags : 1;
109
110 mutable bool m_bLastOutlineState : 1;
111 bool m_bNotifiable;
112
113 bool mbEmptyListStyleSetDueToSetOutlineLevelAttr;
114
115 /** boolean, indicating that a <SetAttr(..)> or <ResetAttr(..)> or
116 <ResetAllAttr(..)> method is running.
117 Needed to avoid duplicate handling of attribute change actions. */
118 bool mbInSetOrResetAttr;
119
120 std::unique_ptr< OUString > m_pNumStringCache;
121
122 css::uno::WeakReference<css::text::XTextContent> m_wXParagraph;
123
124 // DrawingLayer FillAttributes in a preprocessed form for primitive usage
125 drawinglayer::attribute::SdrAllFillAttributesHelperPtr maFillAttributes;
126
127 SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) SwTextNode( const SwNodeIndex &rWhere, SwTextFormatColl *pTextColl,
128 const SfxItemSet* pAutoAttr = nullptr );
129
130 /// Copies the attributes at nStart to pDest.
131 SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) void CopyAttr( SwTextNode *pDest, const sal_Int32 nStart, const sal_Int32 nOldPos);
132
133 SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) SwTextNode* MakeNewTextNode( const SwNodeIndex&, bool bNext = true,
134 bool bChgFollow = true );
135
136 SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) void CutImpl(
137 SwTextNode * const pDest, const SwIndex & rDestStart,
138 const SwIndex & rStart, /*const*/ sal_Int32 nLen,
139 const bool bUpdate = true );
140
141 /// Move all comprising hard attributes to the AttrSet of the paragraph.
142 SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) void MoveTextAttr_To_AttrSet(); // Called by SplitNode.
143
144 /// Create the specific AttrSet.
145 SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) virtual void NewAttrSet( SwAttrPool& ) override;
146
147 /// Optimization: Asking for information about hidden characters at SwScriptInfo
148 /// updates these flags.
149 bool IsCalcHiddenCharFlags() const
150 { return m_bRecalcHiddenCharFlags; }
151 void SetHiddenCharAttribute( bool bNewHiddenCharsHidePara, bool bNewContainsHiddenChars ) const
152 {
153 m_bHiddenCharsHidePara = bNewHiddenCharsHidePara;
154 m_bContainsHiddenChars = bNewContainsHiddenChars;
155 m_bRecalcHiddenCharFlags = false;
156 }
157
158 SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) void CalcHiddenCharFlags() const;
159
160 SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) void SetLanguageAndFont( const SwPaM &rPaM,
161 LanguageType nLang, sal_uInt16 nLangWhichId,
162 const vcl::Font *pFont, sal_uInt16 nFontWhichId );
163
164 /// Start: Data collected during idle time
165
166 SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) void InitSwParaStatistics( bool bNew );
167
168 inline void TryDeleteSwpHints();
169
170 SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) void impl_FormatToTextAttr(const SfxItemSet& i_rAttrSet);
171
172 const SwTextInputField* GetOverlappingInputField( const SwTextAttr& rTextAttr ) const;
173
174 void DelFrames_TextNodePart();
175
176public:
177 enum class WrongState { TODO, PENDING, DONE };
178
179 bool IsWordCountDirty() const;
180 WrongState GetWrongDirty() const;
181 bool IsWrongDirty() const;
182 bool IsGrammarCheckDirty() const;
183 bool IsSmartTagDirty() const;
184 bool IsAutoCompleteWordDirty() const;
185 void SetWordCountDirty( bool bNew ) const;
186 void SetWrongDirty(WrongState eNew) const;
187 void SetGrammarCheckDirty( bool bNew ) const;
188 void SetSmartTagDirty( bool bNew ) const;
189 void SetAutoCompleteWordDirty( bool bNew ) const;
190 void SetWrong( SwWrongList* pNew, bool bDelete = true );
191 SwWrongList* GetWrong();
192 const SwWrongList* GetWrong() const;
193 void SetGrammarCheck( SwGrammarMarkUp* pNew, bool bDelete = true );
194 SwGrammarMarkUp* GetGrammarCheck();
195 // return SwWrongList because *function pointer* return values aren't covariant
196 SwWrongList const* GetGrammarCheck() const;
197 void SetSmartTags( SwWrongList* pNew, bool bDelete = true );
198 SwWrongList* GetSmartTags();
199 SwWrongList const* GetSmartTags() const;
200 void TryCharSetExpandToNum(const SfxItemSet& pCharSet);
201
202 /// End: Data collected during idle time
203
204protected:
205 /// for hanging TextFormatCollections somewhere else (Outline-Numbering!)
206 virtual void SwClientNotify( const SwModify&, const SfxHint& ) override;
207
208public:
209 using SwContentNode::GetAttr;
210
211 const OUString& GetText() const { return m_Text; }
212
213 // returns the maximum number of characters that can still be added to the node
214 inline sal_Int32 GetSpaceLeft() const;
215
216 /// getters for SwpHints
217 inline SwpHints &GetSwpHints();
218 inline const SwpHints &GetSwpHints() const;
219 SwpHints *GetpSwpHints() { return m_pSwpHints.get(); }
220 const SwpHints *GetpSwpHints() const { return m_pSwpHints.get(); }
221 bool HasHints() const { return m_pSwpHints != nullptr; }
222 inline SwpHints &GetOrCreateSwpHints();
223
224 virtual ~SwTextNode() override;
225
226 virtual sal_Int32 Len() const override;
227
228 /// Is in itratr.
229 void GetMinMaxSize( sal_uLong nIndex, sal_uLong& rMin, sal_uLong &rMax, sal_uLong &rAbs ) const;
230
231 /// overriding to handle change of certain paragraph attributes
232 virtual bool SetAttr( const SfxPoolItem& ) override;
233 virtual bool SetAttr( const SfxItemSet& rSet ) override;
234 virtual bool ResetAttr( sal_uInt16 nWhich1, sal_uInt16 nWhich2 = 0 ) override;
235 virtual bool ResetAttr( const std::vector<sal_uInt16>& rWhichArr ) override;
236 virtual sal_uInt16 ResetAllAttr() override;
237
238 /// insert text content
239 /// @param rStr text to insert; in case it does not fit into the capacity
240 /// of the node, the longest prefix that fits is inserted
241 /// @return the prefix of rStr that was actually inserted
242 OUString InsertText( const OUString & rStr, const SwIndex & rIdx,
243 const SwInsertFlags nMode
244 = SwInsertFlags::DEFAULT );
245
246 /** delete text content
247 ATTENTION: must not be called with a range that overlaps the start of
248 an attribute with both extent and dummy char
249 */
250 void EraseText ( const SwIndex &rIdx, const sal_Int32 nCount = SAL_MAX_INT32((sal_Int32) 0x7FFFFFFF),
251 const SwInsertFlags nMode = SwInsertFlags::DEFAULT );
252
253 /** delete all attributes.
254 If neither pSet nor nWhich is given, delete all attributes (except
255 refmarks, toxmarks, meta) in range.
256 @param rIdx start position
257 @param nLen range in which attributes will be deleted
258 @param pSet if not 0, delete only attributes contained in pSet
259 @param nWhich if not 0, delete only attributes with matching which
260 @param bInclRefToxMark
261 refmarks, toxmarks, and metas will be ignored unless this is true
262 ATTENTION: setting bInclRefToxMark is only allowed from UNDO!
263 @param bExactRange From the attributes included in the range, delete
264 only the ones which have exactly same range. Don't delete the ones
265 which are simply included in the range.
266 */
267 void RstTextAttr(
268 const SwIndex &rIdx,
269 const sal_Int32 nLen,
270 const sal_uInt16 nWhich = 0,
271 const SfxItemSet* pSet = nullptr,
272 const bool bInclRefToxMark = false,
273 const bool bExactRange = false );
274 void GCAttr();
275
276 // Delete text attribute (needs to be deregistered at Pool!)
277 void DestroyAttr( SwTextAttr* pAttr );
278
279 // delete all attributes from SwpHintsArray.
280 void ClearSwpHintsArr( bool bDelFields );
281
282 /// initialize the hints after file loading (which takes shortcuts)
283 void FileLoadedInitHints();
284
285 /// Insert pAttr into hints array. @return true iff inserted successfully
286 bool InsertHint( SwTextAttr * const pAttr,
287 const SetAttrMode nMode = SetAttrMode::DEFAULT );
288 /// create new text attribute from rAttr and insert it
289 /// @return inserted hint; 0 if not sure the hint is inserted
290 SwTextAttr* InsertItem( SfxPoolItem& rAttr,
291 const sal_Int32 nStart, const sal_Int32 nEnd,
292 const SetAttrMode nMode = SetAttrMode::DEFAULT );
293
294 /** Set these attributes at TextNode. If the whole range is comprised
295 set them only in AutoAttrSet (SwContentNode::SetAttr). */
296 bool SetAttr( const SfxItemSet& rSet,
297 sal_Int32 nStt, sal_Int32 nEnd,
298 const SetAttrMode nMode = SetAttrMode::DEFAULT,
299 SwTextAttr **ppNewTextAttr = nullptr);
300 /** Query the attributes of textnode over the range.
301 Introduce 4th optional parameter <bMergeIndentValuesOfNumRule>.
302 If <bMergeIndentValuesOfNumRule> == true, the indent attributes of
303 the corresponding list level of an applied list style is merged into
304 the requested item set as a LR-SPACE item, if <bOnlyTextAttr> == false,
305 corresponding node has not its own indent attributes and the
306 position-and-space mode of the list level is SvxNumberFormat::LABEL_ALIGNMENT. */
307 bool GetParaAttr( SfxItemSet& rSet, sal_Int32 nStt, sal_Int32 nEnd,
308 const bool bOnlyTextAttr = false,
309 const bool bGetFromChrFormat = true,
310 const bool bMergeIndentValuesOfNumRule = false,
311 SwRootFrame const* pLayout = nullptr) const;
312
313 /// Convey attributes of an AttrSet (AutoFormat) to SwpHintsArray.
314 void FormatToTextAttr( SwTextNode* pNd );
315
316 /// delete all attributes of type nWhich at nStart (opt. end nEnd)
317 void DeleteAttributes( const sal_uInt16 nWhich,
318 const sal_Int32 nStart, const sal_Int32 nEnd = 0 );
319 /// delete the attribute pTextAttr
320 void DeleteAttribute ( SwTextAttr * const pTextAttr );
321
322 /** Actions on text and attributes.
323 introduce optional parameter to control, if all attributes have to be copied. */
324 void CopyText( SwTextNode * const pDest,
325 const SwIndex &rStart,
326 const sal_Int32 nLen,
327 const bool bForceCopyOfAllAttrs );
328 void CopyText( SwTextNode * const pDest,
329 const SwIndex &rDestStart,
330 const SwIndex &rStart,
331 sal_Int32 nLen,
332 const bool bForceCopyOfAllAttrs = false );
333
334 void CutText(SwTextNode * const pDest,
335 const SwIndex & rStart, const sal_Int32 nLen);
336 inline void CutText(SwTextNode * const pDest, const SwIndex &rDestStart,
337 const SwIndex & rStart, const sal_Int32 nLen);
338
339 /// replace nDelLen characters at rStart with rText
340 /// in case the replacement does not fit, it is partially inserted up to
341 /// the capacity of the node
342 void ReplaceText( const SwIndex& rStart, const sal_Int32 nDelLen,
343 const OUString & rText );
344 void ReplaceTextOnly( sal_Int32 nPos, sal_Int32 nLen,
345 const OUString& rText,
346 const css::uno::Sequence<sal_Int32>& rOffsets );
347
348 /// Virtual methods from ContentNode.
349 virtual SwContentFrame *MakeFrame( SwFrame* ) override;
350 SwTextNode * SplitContentNode(const SwPosition &,
351 std::function<void (SwTextNode *, sw::mark::RestoreMode)> const* pContentIndexRestore);
352 virtual SwContentNode *JoinNext() override;
353 void JoinPrev();
354
355 SwContentNode *AppendNode( const SwPosition & );
356
357 /// When appropriate set DontExpand-flag at INet or character styles respectively.
358 bool DontExpandFormat( const SwIndex& rIdx, bool bFlag = true,
359 bool bFormatToTextAttributes = true );
360
361 enum GetTextAttrMode {
362 DEFAULT, /// DEFAULT: (Start <= nIndex < End)
363 EXPAND, /// EXPAND : (Start < nIndex <= End)
364 PARENT, /// PARENT : (Start < nIndex < End)
365 };
366
367 /** get the innermost text attribute covering position nIndex.
368 @param nWhich only attribute with this id is returned.
369 @param eMode the predicate for matching (@see GetTextAttrMode).
370
371 ATTENTION: this function is not well-defined for those
372 hints of which several may cover a single position, like
373 RES_TXTATR_CHARFMT, RES_TXTATR_REFMARK, RES_TXTATR_TOXMARK
374 */
375 SwTextAttr *GetTextAttrAt(
376 sal_Int32 const nIndex,
377 sal_uInt16 const nWhich,
378 enum GetTextAttrMode const eMode = DEFAULT ) const;
379
380 /** get the innermost text attributes covering position nIndex.
381 @param nWhich only attributes with this id are returned.
382 @param eMode the predicate for matching (@see GetTextAttrMode).
383 */
384 std::vector<SwTextAttr *> GetTextAttrsAt(
385 sal_Int32 const nIndex,
386 sal_uInt16 const nWhich ) const;
387
388 /** get the text attribute at position nIndex which owns
389 the dummy character CH_TXTATR_* at that position, if one exists.
390 @param nIndex the position in the text
391 @param nWhich if different from RES_TXTATR_END, return only
392 attribute with given which id
393 @return the text attribute at nIndex of type nWhich, if it exists
394 */
395 SwTextAttr *GetTextAttrForCharAt(
396 const sal_Int32 nIndex,
397 const sal_uInt16 nWhich = RES_TXTATR_END ) const;
398
399 SwTextField* GetFieldTextAttrAt(
400 const sal_Int32 nIndex,
401 const bool bIncludeInputFieldAtStart = false ) const;
402
403 bool Spell(SwSpellArgs*);
404 bool Convert( SwConversionArgs & );
405
406 inline SwTextFormatColl *GetTextColl() const;
407 virtual SwFormatColl *ChgFormatColl( SwFormatColl* ) override;
408 void ChgTextCollUpdateNum( const SwTextFormatColl* pOld,
409 const SwTextFormatColl* pNew );
410
411 /** Copy collection with all auto formats to dest-node.
412 The latter might be in another document!
413 (Method in ndcopy.cxx!!). */
414 void CopyCollFormat( SwTextNode& rDestNd );
415
416 // BEGIN OF BULLET/NUMBERING/OUTLINE STUFF:
417
418 /**
419 Returns numbering rule of this text node.
420
421 @param bInParent search in parent attributes, too
422
423 @return numbering rule of this text node or NULL if none is set
424 */
425 SwNumRule *GetNumRule(bool bInParent = true) const;
426
427 const SwNodeNum* GetNum(SwRootFrame const* pLayout = nullptr) const;
428 void DoNum(std::function<void (SwNodeNum &)> const&);
429
430 SwNumberTree::tNumberVector GetNumberVector(SwRootFrame const* pLayout = nullptr) const;
431
432 /**
433 Returns if this text node is an outline.
434
435 @retval true this text node is an outline
436 @retval false else
437 */
438 bool IsOutline() const;
439
440 bool IsOutlineStateChanged() const;
441
442 void UpdateOutlineState();
443
444 /**
445 Notify this textnode that its numbering rule has changed.
446 */
447 void NumRuleChgd();
448
449 /** Returns outline of numbering string
450
451 Introduce parameter <_bInclPrefixAndSuffixStrings> in order to control,
452 if the prefix and the suffix strings have to been included or not.
453
454 @param _bInclPrefixAndSuffixStrings
455 optional input parameter - boolean indicating, if the prefix and the
456 suffix strings have to been included or not. default value = <true>
457
458 @param _nRestrictToThisLevel
459 optional input parameter - unsigned integer indicating the maximum outline
460 level to which the output string must be restricted to. Default value is
461 MAXLEVEL
462 */
463 OUString GetNumString( const bool _bInclPrefixAndSuffixStrings = true,
464 const unsigned int _nRestrictToThisLevel = MAXLEVEL,
465 SwRootFrame const* pLayout = nullptr) const;
466
467 /**
468 Returns the additional indents of this text node and its numbering.
469
470 @param bTextLeft ???
471
472 @return additional indents
473 */
474 long GetLeftMarginWithNum( bool bTextLeft = false ) const;
475
476 /**
477 Returns the combined first line indent of this text node and
478 its numbering.
479
480 @param the first line indent of this text node taking the
481 numbering into account (return parameter)
482
483 @retval true this node has SwNodeNum and has numbering rule
484 @retval false else
485 */
486 bool GetFirstLineOfsWithNum( short& rFirstOffset ) const;
487
488 SwTwips GetAdditionalIndentForStartingNewList() const;
489
490 void ClearLRSpaceItemDueToListLevelIndents( std::shared_ptr<SvxLRSpaceItem>& o_rLRSpaceItem ) const;
491
492 /** return left margin for tab stop position calculation
493
494 Needed for text formatting
495 Method considers new list level attributes, which also can provide a left margin value
496 */
497 long GetLeftMarginForTabCalculation() const;
498
499 /** Returns if this text node has a number.
500
501 This text node has a number if it has a SwNodeNum and a
502 numbering rule and the numbering format specified for the
503 level of the SwNodeNum is of an enumeration type.
504
505 @retval true This text node has a number.
506 @retval false else
507 */
508 bool HasNumber() const;
509
510 /** Returns if this text node has a bullet.
511
512 This text node has a bullet if it has a SwNodeNum and a
513 numbering rule and the numbering format specified for the
514 level of the SwNodeNum is of a bullet type.
515
516 @retval true This text node has a bullet.
517 @retval false else
518 */
519 bool HasBullet() const;
520
521 /** Returns is this text node is numbered.
522
523 This node is numbered if it has a SwNodeNum and it has a
524 numbering rule and has not a hidden SwNodeNum.
525
526 ATTENTION: Returns true even if the SwNumFormat has type
527 SVX_NUM_NUMBER_NONE.
528
529 @retval true This node is numbered.
530 @retval false else
531 */
532 bool IsNumbered(SwRootFrame const* pLayout = nullptr) const;
533
534 /** Returns if this text node has a marked label.
535
536 @retval true This text node has a marked label.
537 @retval false else
538 */
539 bool HasMarkedLabel() const;
540
541 /** Sets the list level of this text node.
542
543 Side effect, when the text node is a list item:
544 The text node's representation in the list tree (<SwNodeNum> instance)
545 is updated.
546
547 @param nLevel level to set
548 */
549 void SetAttrListLevel(int nLevel);
550
551 bool HasAttrListLevel() const;
552
553 int GetAttrListLevel() const;
554
555 /** Returns the actual list level of this text node, when it is a list item
556
557 @return the actual list level of this text node, if it is a list item,
558 -1 otherwise
559 */
560 int GetActualListLevel() const;
561
562 /**
563 Returns outline level of this text node.
564
565 If a text node has an outline number (i.e. it has an SwNodeNum
566 and an outline numbering rule) the outline level is the level of
567 this SwNodeNum.
568
569 If a text node has no outline number and has a paragraph style
570 attached the outline level is the outline level of the
571 paragraph style.
572
573 Otherwise the text node has no outline level (NO_NUMBERING).
574
575 NOTE: The outline level of text nodes is subject to change. The
576 plan is to have an SwTextNode::nOutlineLevel member that is
577 updated from a paragraph style upon appliance of that paragraph
578 style.
579
580 @return outline level or NO_NUMBERING if there is no outline level
581 */
582 int GetAttrOutlineLevel() const;
583
584 /**
585 Sets the out line level *at* a text node.
586
587 @param nLevel the level to be set
588
589 If the text node has an outline number the level is set at the
590 outline number.
591
592 If the text node has no outline number but has a paragraph
593 style applied the outline level is set at the paragraph style.
594
595 NOTE: This is subject to change, see GetOutlineLevel.
596 */
597 void SetAttrOutlineLevel(int nLevel);
598
599 /**
600 * @brief GetAttrOutlineContentVisible
601 * @param bOutlineContentVisibleAttr the value stored in RES_PARATR_GRABBAG for 'OutlineContentVisibleAttr'
602 * @return true if 'OutlineContentVisibleAttr' is found in RES_PARATR_GRABBAG
603 */
604 bool GetAttrOutlineContentVisible(bool& bOutlineContentVisibleAttr);
605 void SetAttrOutlineContentVisible(bool bVisible);
606
607 bool IsEmptyListStyleDueToSetOutlineLevelAttr() const { return mbEmptyListStyleSetDueToSetOutlineLevelAttr;}
608 void SetEmptyListStyleDueToSetOutlineLevelAttr();
609 void ResetEmptyListStyleDueToResetOutlineLevelAttr();
610
611 /**
612 Returns the width of leading tabs/blanks in this paragraph.
613 This space will be converted into numbering indent if the paragraph
614 is set to be numbered.
615
616 @return the width of the leading whitespace
617 */
618 SwTwips GetWidthOfLeadingTabs() const;
619
620 /**
621 Returns if the paragraph has a visible numbering or bullet.
622 This includes all kinds of numbering/bullet/outlines.
623 Note: This function returns false, if the numbering format is
624 SVX_NUM_NUMBER_NONE or if the numbering/bullet has been deleted.
625
626 @return true if the paragraph has a visible numbering/bullet/outline
627 */
628 bool HasVisibleNumberingOrBullet() const;
629
630 void SetListId(OUString const& rListId);
631 OUString GetListId() const;
632
633 /** Determines, if the list level indent attributes can be applied to the
634 paragraph.
635
636 The list level indents can be applied to the paragraph under the one
637 of following conditions:
638 - the list style is directly applied to the paragraph and the paragraph
639 has no own indent attributes.
640 - the list style is applied to the paragraph through one of its paragraph
641 styles, the paragraph has no own indent attributes and on the paragraph
642 style hierarchy from the paragraph to the paragraph style with the
643 list style no indent attributes are found.
644
645 @return boolean
646 */
647 bool AreListLevelIndentsApplicable() const;
648
649 /** Retrieves the list tab stop position, if the paragraph's list level defines
650 one and this list tab stop has to merged into the tap stops of the paragraph
651
652 @param nListTabStopPosition
653 output parameter - containing the list tab stop position
654
655 @return boolean - indicating, if a list tab stop position is provided
656 */
657 bool GetListTabStopPosition( long& nListTabStopPosition ) const;
658
659 /** Retrieves the character following the list label, if the paragraph's
660 list level defines one.
661
662 @return the list tab stop position as string
663 */
664 OUString GetLabelFollowedBy() const;
665
666 // END OF BULLET/NUMBERING/OUTLINE STUFF:
667
668 void fillSoftPageBreakList( SwSoftPageBreakList& rBreak ) const;
669
670 LanguageType GetLang( const sal_Int32 nBegin, const sal_Int32 nLen = 0,
671 sal_uInt16 nScript = 0 ) const;
672
673 /// in ndcopy.cxx
674 bool IsSymbolAt(sal_Int32 nBegin) const; // In itratr.cxx.
675 virtual SwContentNode* MakeCopy(SwDoc&, const SwNodeIndex&, bool bNewFrames) const override;
676
677 /// Interactive hyphenation: we find TextFrame and call its CalcHyph.
678 bool Hyphenate( SwInterHyphInfo &rHyphInf );
679 void DelSoftHyph( const sal_Int32 nStart, const sal_Int32 nEnd );
680
681 /** add 4th optional parameter <bAddSpaceAfterListLabelStr> indicating,
682 when <bWithNum = true> that a space is inserted after the string for
683 the list label.
684 add 5th optional parameter <bWithSpacesForLevel> indicating, if additional
685 spaces are inserted in front of the expanded text string depending on
686 the list level. */
687 OUString GetExpandText( SwRootFrame const* pLayout,
688 const sal_Int32 nIdx = 0,
689 const sal_Int32 nLen = -1,
690 const bool bWithNum = false,
691 const bool bAddSpaceAfterListLabelStr = false,
692 const bool bWithSpacesForLevel = false,
693 const ExpandMode eAdditionalMode = ExpandMode::ExpandFootnote) const;
694 bool CopyExpandText( SwTextNode& rDestNd, const SwIndex* pDestIdx,
695 sal_Int32 nIdx, sal_Int32 nLen,
696 SwRootFrame const* pLayout,
697 bool bWithNum = false, bool bWithFootnote = true,
698 bool bReplaceTabsWithSpaces = false ) const;
699
700 OUString GetRedlineText() const;
701
702 /** @return actual count of initial chars for initial-function.
703 If nWishLen == 0 that of first word. */
704 sal_Int32 GetDropLen(sal_Int32 nWishLen) const;
705
706 /// Passes back info needed on the dropcap dimensions
707 bool GetDropSize(int& rFontHeight, int& rDropHeight, int& rDropDescent) const;
708
709 /// Hidden Paragraph Field:
710 bool CalcHiddenParaField()
711 { return m_pSwpHints && m_pSwpHints->CalcHiddenParaField(); }
712 /// set CalcVisible flags
713 void SetCalcHiddenParaField()
714 { if (m_pSwpHints) m_pSwpHints->SetCalcHiddenParaField(); }
715
716 /// is the paragraph visible?
717 bool IsHiddenByParaField() const
718 { return m_pSwpHints && m_pSwpHints->IsHiddenByParaField(); }
719
720 /// Hidden Paragraph Field:
721
722 bool HasHiddenCharAttribute( bool bWholePara ) const
723 {
724 if ( m_bRecalcHiddenCharFlags )
725 CalcHiddenCharFlags();
726 return bWholePara ? m_bHiddenCharsHidePara : m_bContainsHiddenChars;
727 }
728
729 void SetCalcHiddenCharFlags() const
730 { m_bRecalcHiddenCharFlags = true; }
731
732 /** @return if the node is hidden due to
733 1. HiddenParaField
734 2. HiddenCharAttribute
735 3. HiddenSection */
736
737 bool IsHidden() const;
738
739
740 /// override SwIndexReg
741 virtual void Update(
742 SwIndex const & rPos,
743 const sal_Int32 nChangeLen,
744 const bool bNegative = false,
745 const bool bDelete = false ) override;
746
747 /// change text to Upper/Lower/Hiragana/Katakana/...
748 void TransliterateText( utl::TransliterationWrapper& rTrans,
749 sal_Int32 nStart, sal_Int32 nEnd,
750 SwUndoTransliterate* pUndo );
751
752 /// count words in given range - returns true if we refreshed out count
753 bool CountWords( SwDocStat& rStat, sal_Int32 nStart, sal_Int32 nEnd ) const;
754
755 /** Checks some global conditions like loading or destruction of document
756 to economize notifications */
757 bool IsNotificationEnabled() const;
758
759 /// Checks a temporary notification blocker and the global conditions of IsNotificationEnabled()
760 bool IsNotifiable() const;
761
762 void SetListRestart( bool bRestart );
763 bool IsListRestart() const;
764
765 void SetAttrListRestartValue( SwNumberTree::tSwNumTreeNumber nNum );
766 bool HasAttrListRestartValue() const;
767 SwNumberTree::tSwNumTreeNumber GetAttrListRestartValue() const;
768 SwNumberTree::tSwNumTreeNumber GetActualListStartValue() const;
769
770 void SetCountedInList( bool bCounted );
771 bool IsCountedInList() const;
772
773 void AddToList();
774 void AddToListRLHidden();
775 void RemoveFromList();
776 void RemoveFromListRLHidden();
777 bool IsInList() const;
778
779 bool IsFirstOfNumRule(SwRootFrame const& rLayout) const;
780
781 SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) css::uno::WeakReference<css::text::XTextContent> const& GetXParagraph() const
782 { return m_wXParagraph; }
783 SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) void SetXParagraph(css::uno::Reference<css::text::XTextContent> const& xParagraph)
784 { m_wXParagraph = xParagraph; }
785
786 /// sfx2::Metadatable
787 virtual ::sfx2::IXmlIdRegistry& GetRegistry() override;
788 virtual bool IsInClipboard() const override;
789 virtual bool IsInUndo() const override;
790 virtual bool IsInContent() const override;
791 virtual css::uno::Reference< css::rdf::XMetadatable > MakeUnoObject() override;
792
793 bool IsCollapse() const;
794
795 virtual void dumpAsXml(xmlTextWriterPtr pWriter) const override;
796
797 sal_uInt32 GetRsid( sal_Int32 nStt, sal_Int32 nEnd ) const;
798 sal_uInt32 GetParRsid() const;
799
800 bool CompareRsid( const SwTextNode &rTextNode, sal_Int32 nStt1, sal_Int32 nStt2 ) const;
801 bool CompareParRsid( const SwTextNode &rTextNode ) const;
802
803 // Access to DrawingLayer FillAttributes in a preprocessed form for primitive usage
804 virtual drawinglayer::attribute::SdrAllFillAttributesHelperPtr getSdrAllFillAttributesHelper() const override;
805
806 /// In MS Word, the font underline setting of the paragraph end position won't affect the formatting of numbering, so we ignore it
807 static bool IsIgnoredCharFormatForNumbering(const sal_uInt16 nWhich);
808};
809
810inline SwpHints & SwTextNode::GetSwpHints()
811{
812 assert( m_pSwpHints )(static_cast <bool> (m_pSwpHints) ? void (0) : __assert_fail
("m_pSwpHints", "/home/maarten/src/libreoffice/core/sw/inc/ndtxt.hxx"
, 812, __extension__ __PRETTY_FUNCTION__))
;
813 return *m_pSwpHints;
814}
815inline const SwpHints &SwTextNode::GetSwpHints() const
816{
817 assert( m_pSwpHints )(static_cast <bool> (m_pSwpHints) ? void (0) : __assert_fail
("m_pSwpHints", "/home/maarten/src/libreoffice/core/sw/inc/ndtxt.hxx"
, 817, __extension__ __PRETTY_FUNCTION__))
;
818 return *m_pSwpHints;
819}
820
821inline SwpHints& SwTextNode::GetOrCreateSwpHints()
822{
823 if ( !m_pSwpHints )
824 {
825 m_pSwpHints.reset(new SwpHints(*this));
826 }
827 return *m_pSwpHints;
828}
829
830inline void SwTextNode::TryDeleteSwpHints()
831{
832 if ( m_pSwpHints && m_pSwpHints->CanBeDeleted() )
833 {
834 m_pSwpHints.reset();
835 }
836}
837
838inline SwTextFormatColl* SwTextNode::GetTextColl() const
839{
840 return static_cast<SwTextFormatColl*>(const_cast<SwModify*>(GetRegisteredIn()));
841}
842
843/// Inline methods from Node.hxx
844inline SwTextNode *SwNode::GetTextNode()
845{
846 return SwNodeType::Text == m_nNodeType ? static_cast<SwTextNode*>(this) : nullptr;
50
Assuming Text is not equal to field 'm_nNodeType'
51
'?' condition is false
52
Returning null pointer, which participates in a condition later
847}
848
849inline const SwTextNode *SwNode::GetTextNode() const
850{
851 return SwNodeType::Text == m_nNodeType ? static_cast<const SwTextNode*>(this) : nullptr;
852}
853
854inline void
855SwTextNode::CutText(SwTextNode * const pDest, const SwIndex & rDestStart,
856 const SwIndex & rStart, const sal_Int32 nLen)
857{
858 CutImpl( pDest, rDestStart, rStart, nLen );
859}
860
861inline sal_Int32 SwTextNode::GetSpaceLeft() const
862{
863 // do not fill the String up to the max - need to be able to have a
864 // SwPosition "behind" the last character, i.e., at index TXTNODE_MAX + 1
865 const sal_Int32 TXTNODE_MAX = SAL_MAX_INT32((sal_Int32) 0x7FFFFFFF) - 2;
866 return TXTNODE_MAX-m_Text.getLength();
867}
868
869#endif
870
871/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/sw/inc/ndindex.hxx

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#ifndef INCLUDED_SW_INC_NDINDEX_HXX
20#define INCLUDED_SW_INC_NDINDEX_HXX
21
22#include <iostream>
23
24#include <tools/solar.h>
25
26#include "node.hxx"
27#include "ring.hxx"
28#include "ndarr.hxx"
29
30/// Marks a node in the document model.
31class SW_DLLPUBLIC__attribute__ ((visibility("default"))) SwNodeIndex final : public sw::Ring<SwNodeIndex>
32{
33 SwNode * m_pNode;
34
35 // These are not allowed!
36 SwNodeIndex( SwNodes& rNds, sal_uInt16 nIdx ) = delete;
37 SwNodeIndex( SwNodes& rNds, int nIdx ) = delete;
38 void RegisterIndex( SwNodes& rNodes )
39 {
40 if(!rNodes.m_vIndices)
41 rNodes.m_vIndices = this;
42 MoveTo(rNodes.m_vIndices);
43 }
44 void DeRegisterIndex( SwNodes& rNodes )
45 {
46 if(rNodes.m_vIndices == this)
47 rNodes.m_vIndices = GetNextInRing();
48 MoveTo(nullptr);
49 if(rNodes.m_vIndices == this)
50 rNodes.m_vIndices = nullptr;
51 }
52
53public:
54 SwNodeIndex( SwNodes& rNds, sal_uLong nIdx = 0 )
55 : m_pNode( rNds[ nIdx ] )
56 {
57 RegisterIndex( rNds );
58 };
59 SwNodeIndex( const SwNodeIndex& rIdx, long nDiff = 0 )
60 : sw::Ring<SwNodeIndex>()
61 {
62 if( nDiff )
63 m_pNode = rIdx.GetNodes()[ rIdx.GetIndex() + nDiff ];
64 else
65 m_pNode = rIdx.m_pNode;
66 RegisterIndex( m_pNode->GetNodes() );
67 }
68
69 SwNodeIndex( const SwNode& rNd, long nDiff = 0 )
70 {
71 if( nDiff )
72 m_pNode = rNd.GetNodes()[ rNd.GetIndex() + nDiff ];
73 else
74 m_pNode = const_cast<SwNode*>(&rNd);
75 RegisterIndex( m_pNode->GetNodes() );
76 }
77
78 virtual ~SwNodeIndex() override
79 { DeRegisterIndex( m_pNode->GetNodes() ); }
80
81 inline sal_uLong operator++();
82 inline sal_uLong operator--();
83 inline sal_uLong operator++(int);
84 inline sal_uLong operator--(int);
85
86 inline sal_uLong operator+=( sal_uLong );
87 inline sal_uLong operator-=( sal_uLong );
88
89 inline bool operator< ( const SwNodeIndex& ) const;
90 inline bool operator<=( const SwNodeIndex& ) const;
91 inline bool operator> ( const SwNodeIndex& ) const;
92 inline bool operator>=( const SwNodeIndex& ) const;
93 inline bool operator==( const SwNodeIndex& ) const;
94 inline bool operator!=( const SwNodeIndex& ) const;
95
96 inline bool operator< ( sal_uLong ) const;
97 inline bool operator<=( sal_uLong ) const;
98 inline bool operator> ( sal_uLong ) const;
99 inline bool operator>=( sal_uLong ) const;
100 inline bool operator==( sal_uLong ) const;
101 inline bool operator!=( sal_uLong ) const;
102
103 inline SwNodeIndex& operator=( sal_uLong );
104 inline SwNodeIndex& operator=( const SwNodeIndex& );
105 inline SwNodeIndex& operator=( const SwNode& );
106
107 // Return value of index as sal_uLong.
108 inline sal_uLong GetIndex() const;
109
110 // Enables assignments without creation of a temporary object.
111 inline SwNodeIndex& Assign( SwNodes const & rNds, sal_uLong );
112 inline SwNodeIndex& Assign( const SwNode& rNd, long nOffset = 0 );
113
114 // Gets pointer on NodesArray.
115 inline const SwNodes& GetNodes() const;
116 inline SwNodes& GetNodes();
117
118 SwNodeIndex* GetNext() { return GetNextInRing(); }
119 SwNode& GetNode() const { return *m_pNode; }
120};
121
122inline std::ostream &operator <<(std::ostream& s, const SwNodeIndex& index)
123{
124 return s << "SwNodeIndex (node " << index.GetIndex() << ")";
125};
126
127// SwRange
128
129class SW_DLLPUBLIC__attribute__ ((visibility("default"))) SwNodeRange
130{
131public:
132 SwNodeIndex aStart;
133 SwNodeIndex aEnd;
134
135 SwNodeRange( const SwNodeIndex &rS, const SwNodeIndex &rE )
136 : aStart( rS ), aEnd( rE ) {};
137 SwNodeRange( const SwNodeRange &rRange )
138 : aStart( rRange.aStart ), aEnd( rRange.aEnd ) {};
139
140 SwNodeRange( SwNodes& rNds, sal_uLong nSttIdx, sal_uLong nEndIdx = 0 )
141 : aStart( rNds, nSttIdx ), aEnd( rNds, nEndIdx ) {};
142
143 SwNodeRange( const SwNodeIndex& rS, long nSttDiff, const SwNodeIndex& rE, long nEndDiff = 0 )
144 : aStart( rS, nSttDiff ), aEnd( rE, nEndDiff ) {};
145 SwNodeRange( const SwNode& rS, long nSttDiff, const SwNode& rE, long nEndDiff = 0 )
146 : aStart( rS, nSttDiff ), aEnd( rE, nEndDiff ) {};
147};
148
149// For inlines node.hxx is needed which in turn needs this one.
150// Therefore all inlines accessing m_pNode are implemented here.
151
152inline sal_uLong SwNodeIndex::GetIndex() const
153{
154 return m_pNode->GetIndex();
155}
156inline const SwNodes& SwNodeIndex::GetNodes() const
157{
158 return m_pNode->GetNodes();
159}
160inline SwNodes& SwNodeIndex::GetNodes()
161{
162 return m_pNode->GetNodes();
163}
164inline bool SwNodeIndex::operator< ( sal_uLong const nOther ) const
165{
166 return m_pNode->GetIndex() < nOther;
167}
168inline bool SwNodeIndex::operator<=( sal_uLong const nOther ) const
169{
170 return m_pNode->GetIndex() <= nOther;
171}
172inline bool SwNodeIndex::operator> ( sal_uLong const nOther ) const
173{
174 return m_pNode->GetIndex() > nOther;
175}
176inline bool SwNodeIndex::operator>=( sal_uLong const nOther ) const
177{
178 return m_pNode->GetIndex() >= nOther;
179}
180inline bool SwNodeIndex::operator==( sal_uLong const nOther ) const
181{
182 return m_pNode->GetIndex() == nOther;
183}
184inline bool SwNodeIndex::operator!=( sal_uLong const nOther ) const
185{
186 return m_pNode->GetIndex() != nOther;
187}
188inline bool SwNodeIndex::operator<( const SwNodeIndex& rIndex ) const
189{
190 return m_pNode->GetIndex() < rIndex.GetIndex();
191}
192inline bool SwNodeIndex::operator<=( const SwNodeIndex& rIndex ) const
193{
194 return m_pNode->GetIndex() <= rIndex.GetIndex();
195}
196inline bool SwNodeIndex::operator>( const SwNodeIndex& rIndex ) const
197{
198 return m_pNode->GetIndex() > rIndex.GetIndex();
199}
200inline bool SwNodeIndex::operator>=( const SwNodeIndex& rIndex ) const
201{
202 return m_pNode->GetIndex() >= rIndex.GetIndex();
203}
204inline bool SwNodeIndex::operator==( const SwNodeIndex& rIdx ) const
205{
206 return m_pNode == rIdx.m_pNode;
65
Assuming 'm_pNode' is not equal to 'rIdx.m_pNode'
66
Returning zero, which participates in a condition later
207}
208inline bool SwNodeIndex::operator!=( const SwNodeIndex& rIdx ) const
209{
210 return m_pNode != rIdx.m_pNode;
211}
212
213inline sal_uLong SwNodeIndex::operator++()
214{
215 m_pNode = GetNodes()[ m_pNode->GetIndex()+1 ];
216 return m_pNode->GetIndex();
217}
218inline sal_uLong SwNodeIndex::operator--()
219{
220 m_pNode = GetNodes()[ m_pNode->GetIndex()-1 ];
221 return m_pNode->GetIndex();
222}
223inline sal_uLong SwNodeIndex::operator++(int)
224{
225 sal_uLong nOldIndex = m_pNode->GetIndex();
226 m_pNode = GetNodes()[ nOldIndex + 1 ];
227 return nOldIndex;
228}
229inline sal_uLong SwNodeIndex::operator--(int)
230{
231 sal_uLong nOldIndex = m_pNode->GetIndex();
232 m_pNode = GetNodes()[ nOldIndex - 1 ];
233 return nOldIndex;
234}
235
236inline sal_uLong SwNodeIndex::operator+=( sal_uLong const nOffset )
237{
238 m_pNode = GetNodes()[ m_pNode->GetIndex() + nOffset ];
239 return m_pNode->GetIndex();
240}
241inline sal_uLong SwNodeIndex::operator-=( sal_uLong const nOffset )
242{
243 m_pNode = GetNodes()[ m_pNode->GetIndex() - nOffset ];
244 return m_pNode->GetIndex();
245}
246
247inline SwNodeIndex& SwNodeIndex::operator=( sal_uLong const nNew )
248{
249 m_pNode = GetNodes()[ nNew ];
250 return *this;
251}
252
253SwNodeIndex& SwNodeIndex::operator=( const SwNodeIndex& rIdx )
254{
255 *this = *(rIdx.m_pNode);
256 return *this;
257}
258
259SwNodeIndex& SwNodeIndex::operator=( const SwNode& rNd )
260{
261 if (&m_pNode->GetNodes() != &rNd.GetNodes())
262 {
263 DeRegisterIndex( m_pNode->GetNodes() );
264 m_pNode = const_cast<SwNode*>(&rNd);
265 RegisterIndex( m_pNode->GetNodes() );
266 }
267 else
268 m_pNode = const_cast<SwNode*>(&rNd);
269 return *this;
270}
271
272SwNodeIndex& SwNodeIndex::Assign( SwNodes const & rNds, sal_uLong nIdx )
273{
274 *this = *rNds[ nIdx ];
275 return *this;
276}
277
278SwNodeIndex& SwNodeIndex::Assign( const SwNode& rNd, long nOffset )
279{
280 *this = rNd;
281
282 if( nOffset )
283 m_pNode = m_pNode->GetNodes()[ m_pNode->GetIndex() + nOffset ];
284
285 return *this;
286}
287
288#endif
289
290/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx

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#ifndef INCLUDED_O3TL_TYPED_FLAGS_SET_HXX
21#define INCLUDED_O3TL_TYPED_FLAGS_SET_HXX
22
23#include <sal/config.h>
24
25#include <cassert>
26#include <type_traits>
27
28#include <o3tl/underlyingenumvalue.hxx>
29#include <sal/types.h>
30
31namespace o3tl {
32
33namespace detail {
34
35template<typename T> constexpr
36typename std::enable_if<std::is_signed<T>::value, bool>::type isNonNegative(
37 T value)
38{
39 return value >= 0;
40}
41
42template<typename T> constexpr
43typename std::enable_if<std::is_unsigned<T>::value, bool>::type isNonNegative(T)
44{
45 return true;
46}
47
48}
49
50template<typename T> struct typed_flags {};
51
52/// Mark a (scoped) enumeration as a set of bit flags, with accompanying
53/// operations.
54///
55/// template<>
56/// struct o3tl::typed_flags<TheE>: o3tl::is_typed_flags<TheE, TheM> {};
57///
58/// All relevant values must be non-negative. (Typically, the enumeration's
59/// underlying type will either be fixed and unsigned, or it will be unfixed---
60/// and can thus default to a signed type---and all enumerators will have non-
61/// negative values.)
62///
63/// \param E the enumeration type.
64/// \param M the all-bits-set value for the bit flags.
65template<typename E, typename std::underlying_type<E>::type M>
66struct is_typed_flags {
67 static_assert(
68 M >= 0, "is_typed_flags expects only non-negative bit values");
69
70 typedef E Self;
71
72 class Wrap {
73 public:
74 typedef is_typed_flags Unwrapped;
75
76 explicit constexpr Wrap(typename std::underlying_type<E>::type value):
77 value_(value)
78 {
79 assert(detail::isNonNegative(value))(static_cast <bool> (detail::isNonNegative(value)) ? void
(0) : __assert_fail ("detail::isNonNegative(value)", "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 79, __extension__ __PRETTY_FUNCTION__))
;
80 assert((static_cast <bool> (static_cast<typename std::underlying_type
<E>::type>(~0) == M || (value & ~M) == 0) ? void
(0) : __assert_fail ("static_cast<typename std::underlying_type<E>::type>(~0) == M || (value & ~M) == 0"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 84, __extension__ __PRETTY_FUNCTION__))
81 static_cast<typename std::underlying_type<E>::type>(~0) == M(static_cast <bool> (static_cast<typename std::underlying_type
<E>::type>(~0) == M || (value & ~M) == 0) ? void
(0) : __assert_fail ("static_cast<typename std::underlying_type<E>::type>(~0) == M || (value & ~M) == 0"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 84, __extension__ __PRETTY_FUNCTION__))
82 // avoid "operands don't affect result" warnings when M(static_cast <bool> (static_cast<typename std::underlying_type
<E>::type>(~0) == M || (value & ~M) == 0) ? void
(0) : __assert_fail ("static_cast<typename std::underlying_type<E>::type>(~0) == M || (value & ~M) == 0"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 84, __extension__ __PRETTY_FUNCTION__))
83 // covers all bits of the underlying type(static_cast <bool> (static_cast<typename std::underlying_type
<E>::type>(~0) == M || (value & ~M) == 0) ? void
(0) : __assert_fail ("static_cast<typename std::underlying_type<E>::type>(~0) == M || (value & ~M) == 0"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 84, __extension__ __PRETTY_FUNCTION__))
84 || (value & ~M) == 0)(static_cast <bool> (static_cast<typename std::underlying_type
<E>::type>(~0) == M || (value & ~M) == 0) ? void
(0) : __assert_fail ("static_cast<typename std::underlying_type<E>::type>(~0) == M || (value & ~M) == 0"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 84, __extension__ __PRETTY_FUNCTION__))
;
85 }
86
87 constexpr operator E() const { return static_cast<E>(value_); }
88
89 explicit constexpr operator typename std::underlying_type<E>::type()
90 const
91 { return value_; }
92
93 explicit constexpr operator bool() const { return value_ != 0; }
78
Assuming field 'value_' is equal to 0
79
Returning zero, which participates in a condition later
94
95 private:
96 typename std::underlying_type<E>::type value_;
97 };
98
99 static typename std::underlying_type<E>::type const mask = M;
100};
101
102}
103
104template<typename E>
105constexpr typename o3tl::typed_flags<E>::Wrap operator ~(E rhs) {
106 assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 108, __extension__ __PRETTY_FUNCTION__))
107 o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 108, __extension__ __PRETTY_FUNCTION__))
108 o3tl::underlyingEnumValue(rhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 108, __extension__ __PRETTY_FUNCTION__))
;
109 return static_cast<typename o3tl::typed_flags<E>::Wrap>(
110 o3tl::typed_flags<E>::mask
111 & ~o3tl::underlyingEnumValue(rhs));
112}
113
114template<typename E> constexpr typename o3tl::typed_flags<E>::Wrap operator ~(
115 typename o3tl::typed_flags<E>::Wrap rhs)
116{
117 return static_cast<typename o3tl::typed_flags<E>::Wrap>(
118 o3tl::typed_flags<E>::mask
119 & ~o3tl::underlyingEnumValue<E>(rhs));
120}
121
122template<typename E> constexpr typename o3tl::typed_flags<E>::Wrap operator ^(
123 E lhs, E rhs)
124{
125 assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 127, __extension__ __PRETTY_FUNCTION__))
126 o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 127, __extension__ __PRETTY_FUNCTION__))
127 o3tl::underlyingEnumValue(lhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 127, __extension__ __PRETTY_FUNCTION__))
;
128 assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 130, __extension__ __PRETTY_FUNCTION__))
129 o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 130, __extension__ __PRETTY_FUNCTION__))
130 o3tl::underlyingEnumValue(rhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 130, __extension__ __PRETTY_FUNCTION__))
;
131 return static_cast<typename o3tl::typed_flags<E>::Wrap>(
132 o3tl::underlyingEnumValue(lhs)
133 ^ o3tl::underlyingEnumValue(rhs));
134}
135
136template<typename E> constexpr typename o3tl::typed_flags<E>::Wrap operator ^(
137 E lhs, typename o3tl::typed_flags<E>::Wrap rhs)
138{
139 assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 141, __extension__ __PRETTY_FUNCTION__))
140 o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 141, __extension__ __PRETTY_FUNCTION__))
141 o3tl::underlyingEnumValue(lhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 141, __extension__ __PRETTY_FUNCTION__))
;
142 return static_cast<typename o3tl::typed_flags<E>::Wrap>(
143 o3tl::underlyingEnumValue(lhs)
144 ^ o3tl::underlyingEnumValue<E>(rhs));
145}
146
147template<typename E> constexpr typename o3tl::typed_flags<E>::Wrap operator ^(
148 typename o3tl::typed_flags<E>::Wrap lhs, E rhs)
149{
150 assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 152, __extension__ __PRETTY_FUNCTION__))
151 o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 152, __extension__ __PRETTY_FUNCTION__))
152 o3tl::underlyingEnumValue(rhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 152, __extension__ __PRETTY_FUNCTION__))
;
153 return static_cast<typename o3tl::typed_flags<E>::Wrap>(
154 o3tl::underlyingEnumValue<E>(lhs)
155 ^ o3tl::underlyingEnumValue(rhs));
156}
157
158template<typename W> constexpr
159typename o3tl::typed_flags<typename W::Unwrapped::Self>::Wrap operator ^(
160 W lhs, W rhs)
161{
162 return static_cast<W>(
163 o3tl::underlyingEnumValue<typename W::Unwrapped::Self>(lhs)
164 ^ o3tl::underlyingEnumValue<typename W::Unwrapped::Self>(rhs));
165}
166
167template<typename E>
168constexpr typename o3tl::typed_flags<E>::Wrap operator &(E lhs, E rhs) {
169 assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 171, __extension__ __PRETTY_FUNCTION__))
170 o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 171, __extension__ __PRETTY_FUNCTION__))
171 o3tl::underlyingEnumValue(lhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 171, __extension__ __PRETTY_FUNCTION__))
;
172 assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 174, __extension__ __PRETTY_FUNCTION__))
173 o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 174, __extension__ __PRETTY_FUNCTION__))
174 o3tl::underlyingEnumValue(rhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 174, __extension__ __PRETTY_FUNCTION__))
;
175 return static_cast<typename o3tl::typed_flags<E>::Wrap>(
176 o3tl::underlyingEnumValue(lhs)
177 & o3tl::underlyingEnumValue(rhs));
178}
179
180template<typename E> constexpr typename o3tl::typed_flags<E>::Wrap operator &(
181 E lhs, typename o3tl::typed_flags<E>::Wrap rhs)
182{
183 assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 185, __extension__ __PRETTY_FUNCTION__))
184 o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 185, __extension__ __PRETTY_FUNCTION__))
185 o3tl::underlyingEnumValue(lhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 185, __extension__ __PRETTY_FUNCTION__))
;
186 return static_cast<typename o3tl::typed_flags<E>::Wrap>(
187 o3tl::underlyingEnumValue(lhs)
188 & o3tl::underlyingEnumValue<E>(rhs));
189}
190
191template<typename E> constexpr typename o3tl::typed_flags<E>::Wrap operator &(
192 typename o3tl::typed_flags<E>::Wrap lhs, E rhs)
193{
194 assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 196, __extension__ __PRETTY_FUNCTION__))
195 o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 196, __extension__ __PRETTY_FUNCTION__))
196 o3tl::underlyingEnumValue(rhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 196, __extension__ __PRETTY_FUNCTION__))
;
197 return static_cast<typename o3tl::typed_flags<E>::Wrap>(
198 o3tl::underlyingEnumValue<E>(lhs)
199 & o3tl::underlyingEnumValue(rhs));
200}
201
202template<typename W> constexpr
203typename o3tl::typed_flags<typename W::Unwrapped::Self>::Wrap operator &(
204 W lhs, W rhs)
205{
206 return static_cast<W>(
207 o3tl::underlyingEnumValue<typename W::Unwrapped::Self>(lhs)
208 & o3tl::underlyingEnumValue<typename W::Unwrapped::Self>(rhs));
209}
210
211template<typename E>
212constexpr typename o3tl::typed_flags<E>::Wrap operator |(E lhs, E rhs) {
213 assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 215, __extension__ __PRETTY_FUNCTION__))
214 o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 215, __extension__ __PRETTY_FUNCTION__))
215 o3tl::underlyingEnumValue(lhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 215, __extension__ __PRETTY_FUNCTION__))
;
216 assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 218, __extension__ __PRETTY_FUNCTION__))
217 o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 218, __extension__ __PRETTY_FUNCTION__))
218 o3tl::underlyingEnumValue(rhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 218, __extension__ __PRETTY_FUNCTION__))
;
219 return static_cast<typename o3tl::typed_flags<E>::Wrap>(
220 o3tl::underlyingEnumValue(lhs)
221 | o3tl::underlyingEnumValue(rhs));
222}
223
224template<typename E> constexpr typename o3tl::typed_flags<E>::Wrap operator |(
225 E lhs, typename o3tl::typed_flags<E>::Wrap rhs)
226{
227 assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 229, __extension__ __PRETTY_FUNCTION__))
228 o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 229, __extension__ __PRETTY_FUNCTION__))
229 o3tl::underlyingEnumValue(lhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 229, __extension__ __PRETTY_FUNCTION__))
;
230 return static_cast<typename o3tl::typed_flags<E>::Wrap>(
231 o3tl::underlyingEnumValue(lhs)
232 | o3tl::underlyingEnumValue<E>(rhs));
233}
234
235template<typename E> constexpr typename o3tl::typed_flags<E>::Wrap operator |(
236 typename o3tl::typed_flags<E>::Wrap lhs, E rhs)
237{
238 assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 240, __extension__ __PRETTY_FUNCTION__))
239 o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 240, __extension__ __PRETTY_FUNCTION__))
240 o3tl::underlyingEnumValue(rhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 240, __extension__ __PRETTY_FUNCTION__))
;
241 return static_cast<typename o3tl::typed_flags<E>::Wrap>(
242 o3tl::underlyingEnumValue<E>(lhs)
243 | o3tl::underlyingEnumValue(rhs));
244}
245
246template<typename W> constexpr
247typename o3tl::typed_flags<typename W::Unwrapped::Self>::Wrap operator |(
248 W lhs, W rhs)
249{
250 return static_cast<W>(
251 o3tl::underlyingEnumValue<typename W::Unwrapped::Self>(lhs)
252 | o3tl::underlyingEnumValue<typename W::Unwrapped::Self>(rhs));
253}
254
255template<typename E>
256inline typename o3tl::typed_flags<E>::Self operator &=(E & lhs, E rhs) {
257 assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 259, __extension__ __PRETTY_FUNCTION__))
258 o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 259, __extension__ __PRETTY_FUNCTION__))
259 o3tl::underlyingEnumValue(lhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 259, __extension__ __PRETTY_FUNCTION__))
;
260 assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 262, __extension__ __PRETTY_FUNCTION__))
261 o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 262, __extension__ __PRETTY_FUNCTION__))
262 o3tl::underlyingEnumValue(rhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 262, __extension__ __PRETTY_FUNCTION__))
;
263 lhs = lhs & rhs;
264 return lhs;
265}
266
267template<typename E>
268inline typename o3tl::typed_flags<E>::Self operator &=(
269 E & lhs, typename o3tl::typed_flags<E>::Wrap rhs)
270{
271 assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 273, __extension__ __PRETTY_FUNCTION__))
272 o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 273, __extension__ __PRETTY_FUNCTION__))
273 o3tl::underlyingEnumValue(lhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 273, __extension__ __PRETTY_FUNCTION__))
;
274 lhs = lhs & rhs;
275 return lhs;
276}
277
278template<typename E>
279inline typename o3tl::typed_flags<E>::Self operator |=(E & lhs, E rhs) {
280 assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 282, __extension__ __PRETTY_FUNCTION__))
281 o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 282, __extension__ __PRETTY_FUNCTION__))
282 o3tl::underlyingEnumValue(lhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 282, __extension__ __PRETTY_FUNCTION__))
;
283 assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 285, __extension__ __PRETTY_FUNCTION__))
284 o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 285, __extension__ __PRETTY_FUNCTION__))
285 o3tl::underlyingEnumValue(rhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 285, __extension__ __PRETTY_FUNCTION__))
;
286 lhs = lhs | rhs;
287 return lhs;
288}
289
290template<typename E>
291inline typename o3tl::typed_flags<E>::Self operator |=(
292 E & lhs, typename o3tl::typed_flags<E>::Wrap rhs)
293{
294 assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 296, __extension__ __PRETTY_FUNCTION__))
295 o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 296, __extension__ __PRETTY_FUNCTION__))
296 o3tl::underlyingEnumValue(lhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 296, __extension__ __PRETTY_FUNCTION__))
;
297 lhs = lhs | rhs;
298 return lhs;
299}
300
301template<typename E>
302inline typename o3tl::typed_flags<E>::Self operator ^=(E & lhs, E rhs) {
303 assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 305, __extension__ __PRETTY_FUNCTION__))
304 o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 305, __extension__ __PRETTY_FUNCTION__))
305 o3tl::underlyingEnumValue(lhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 305, __extension__ __PRETTY_FUNCTION__))
;
306 assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 308, __extension__ __PRETTY_FUNCTION__))
307 o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 308, __extension__ __PRETTY_FUNCTION__))
308 o3tl::underlyingEnumValue(rhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(rhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(rhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 308, __extension__ __PRETTY_FUNCTION__))
;
309 lhs = lhs ^ rhs;
310 return lhs;
311}
312
313template<typename E>
314inline typename o3tl::typed_flags<E>::Self operator ^=(
315 E & lhs, typename o3tl::typed_flags<E>::Wrap rhs)
316{
317 assert((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 319, __extension__ __PRETTY_FUNCTION__))
318 o3tl::detail::isNonNegative((static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 319, __extension__ __PRETTY_FUNCTION__))
319 o3tl::underlyingEnumValue(lhs)))(static_cast <bool> (o3tl::detail::isNonNegative( o3tl::
underlyingEnumValue(lhs))) ? void (0) : __assert_fail ("o3tl::detail::isNonNegative( o3tl::underlyingEnumValue(lhs))"
, "/home/maarten/src/libreoffice/core/include/o3tl/typed_flags_set.hxx"
, 319, __extension__ __PRETTY_FUNCTION__))
;
320 lhs = lhs ^ rhs;
321 return lhs;
322}
323
324#endif /* INCLUDED_O3TL_TYPED_FLAGS_SET_HXX */
325
326/* vim:set shiftwidth=4 softtabstop=4 expandtab: */