Bug Summary

File:home/maarten/src/libreoffice/core/sw/source/core/doc/DocumentContentOperationsManager.cxx
Warning:line 3105, column 9
Potential leak of memory pointed to by 'pContact'

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
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)
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;
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();
1
Assuming the condition is true
2
'?' condition is true
3016 const bool bIsAtContent = (RndStdIds::FLY_AT_PAGE != eAnchorId);
3
Assuming 'eAnchorId' is equal to FLY_AT_PAGE
3017
3018 const SwNodeIndex* pChkIdx = nullptr;
3019 if ( pAnchor == nullptr )
4
Taking false branch
3020 {
3021 pChkIdx = &rRg.GetPoint()->nNode;
3022 }
3023 else if ( bIsAtContent
4.1
'bIsAtContent' is false
)
5
Taking false branch
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
5.1
'bIsAtContent' is false
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
5.2
'eAnchorId' is not equal to FLY_AS_CHAR
== RndStdIds::FLY_AS_CHAR )
6
Taking false branch
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 );
7
Memory is allocated
3090 3091 // Create Frames if necessary 3092 if( m_rDoc.getIDocumentLayoutAccess().GetCurrentViewShell() )
8
Assuming the condition is false
9
Taking false branch
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())
10
Potential leak of memory pointed to by 'pContact'
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(); 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) || 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 )) 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; 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()) 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()); 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) 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 ) 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(); 4766 SwTextNode* pEndTextNd = pEnd->nNode.GetNode().GetTextNode(); 4767 SwTextNode* pDestTextNd = aInsPos.GetNode().GetTextNode(); 4768 bool bCopyCollFormat = !rDoc.IsInsOnlyTextGlossary() && 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()) 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 ) 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 && 4799 pDestTextNd && !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 { 4808 if( pSttTextNd ) 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 ) 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) 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) 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) 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__))
; 5023 std::pair<SwPaM const&, SwPosition const&> tmp(rPam, startPos); 5024 if( aInsPos == pEnd->nNode ) 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) 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) 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) 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 ) 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 ) 5123 pCopyPam->Move( fnMoveForward, bCanMoveBack ? GoInContent : GoInNode ); 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 && m_rDoc.getIDocumentMarkAccess()->getAllMarksCount() ) 5140 { 5141 sw::CopyBookmarks(rPam, *pCopyPam->Start()); 5142 } 5143 5144 if( RedlineFlags::DeleteRedlines & eOld ) 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()) 5155 { 5156 pUndo->SetInsertRange(*pCopyPam, true, nDeleteTextNodes); 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: */