1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
19 #include <DocumentContentOperationsManager.hxx>
21 #include <IDocumentUndoRedo.hxx>
22 #include <IDocumentMarkAccess.hxx>
23 #include <DocumentRedlineManager.hxx>
24 #include <IDocumentState.hxx>
25 #include <IDocumentLayoutAccess.hxx>
26 #include <IDocumentStylePoolAccess.hxx>
27 #include <UndoManager.hxx>
29 #include <textboxhelper.hxx>
30 #include <dcontact.hxx>
32 #include <numrule.hxx>
33 #include <charfmt.hxx>
35 #include <ndnotxt.hxx>
38 #include <breakit.hxx>
40 #include <fmtanchr.hxx>
41 #include <fmtcntnt.hxx>
42 #include <fmtinfmt.hxx>
43 #include <fmtpdsc.hxx>
44 #include <fmtcnct.hxx>
45 #include <SwStyleNameMapper.hxx>
46 #include <redline.hxx>
47 #include <unocrsr.hxx>
50 #include <poolfmt.hxx>
52 #include <txatbase.hxx>
53 #include <UndoRedline.hxx>
55 #include <UndoBookmark.hxx>
56 #include <UndoDelete.hxx>
57 #include <UndoSplitMove.hxx>
58 #include <UndoOverwrite.hxx>
59 #include <UndoInsert.hxx>
60 #include <UndoAttribute.hxx>
62 #include <acorrect.hxx>
67 #include <fmtflcnt.hxx>
69 #include <unotools/charclass.hxx>
70 #include <unotools/configmgr.hxx>
71 #include <sfx2/Metadatable.hxx>
72 #include <svl/stritem.hxx>
73 #include <svl/itemiter.hxx>
74 #include <svx/svdobj.hxx>
75 #include <svx/svdouno.hxx>
76 #include <tools/globname.hxx>
77 #include <editeng/formatbreakitem.hxx>
78 #include <o3tl/make_unique.hxx>
79 #include <com/sun/star/i18n/Boundary.hpp>
83 using namespace ::com::sun::star::i18n
;
87 // Copy method from SwDoc
88 // Prevent copying in Flys that are anchored in the area
89 bool lcl_ChkFlyFly( SwDoc
* pDoc
, sal_uLong nSttNd
, sal_uLong nEndNd
,
92 const SwFrameFormats
& rFrameFormatTable
= *pDoc
->GetSpzFrameFormats();
94 for( size_t n
= 0; n
< rFrameFormatTable
.size(); ++n
)
96 SwFrameFormat
const*const pFormat
= rFrameFormatTable
[n
];
97 SwFormatAnchor
const*const pAnchor
= &pFormat
->GetAnchor();
98 SwPosition
const*const pAPos
= pAnchor
->GetContentAnchor();
100 ((RndStdIds::FLY_AS_CHAR
== pAnchor
->GetAnchorId()) ||
101 (RndStdIds::FLY_AT_CHAR
== pAnchor
->GetAnchorId()) ||
102 (RndStdIds::FLY_AT_FLY
== pAnchor
->GetAnchorId()) ||
103 (RndStdIds::FLY_AT_PARA
== pAnchor
->GetAnchorId())) &&
104 nSttNd
<= pAPos
->nNode
.GetIndex() &&
105 pAPos
->nNode
.GetIndex() < nEndNd
)
107 const SwFormatContent
& rContent
= pFormat
->GetContent();
109 if( !rContent
.GetContentIdx() ||
110 nullptr == ( pSNd
= rContent
.GetContentIdx()->GetNode().GetStartNode() ))
113 if( pSNd
->GetIndex() < nInsNd
&&
114 nInsNd
< pSNd
->EndOfSectionIndex() )
118 if( lcl_ChkFlyFly( pDoc
, pSNd
->GetIndex(),
119 pSNd
->EndOfSectionIndex(), nInsNd
) )
128 SwNodeIndex
InitDelCount(SwPaM
const& rSourcePaM
, sal_uLong
& rDelCount
)
130 SwNodeIndex
const& rStart(rSourcePaM
.Start()->nNode
);
131 // Special handling for SwDoc::AppendDoc
132 if (rSourcePaM
.GetDoc()->GetNodes().GetEndOfExtras().GetIndex() + 1
133 == rStart
.GetIndex())
136 return SwNodeIndex(rStart
, +1);
146 The lcl_CopyBookmarks function has to copy bookmarks from the source to the destination nodes
147 array. It is called after a call of the CopyNodes(..) function. But this function does not copy
148 every node (at least at the moment: 2/08/2006 ), section start and end nodes will not be copied
149 if the corresponding end/start node is outside the copied pam.
150 The lcl_NonCopyCount function counts the number of these nodes, given the copied pam and a node
151 index inside the pam.
152 rPam is the original source pam, rLastIdx is the last calculated position, rDelCount the number
153 of "non-copy" nodes between rPam.Start() and rLastIdx.
154 nNewIdx is the new position of interest.
156 void lcl_NonCopyCount( const SwPaM
& rPam
, SwNodeIndex
& rLastIdx
, const sal_uLong nNewIdx
, sal_uLong
& rDelCount
)
158 sal_uLong nStart
= rPam
.Start()->nNode
.GetIndex();
159 sal_uLong nEnd
= rPam
.End()->nNode
.GetIndex();
160 if( rLastIdx
.GetIndex() < nNewIdx
) // Moving forward?
162 // We never copy the StartOfContent node
163 do // count "non-copy" nodes
165 SwNode
& rNode
= rLastIdx
.GetNode();
166 if( ( rNode
.IsSectionNode() && rNode
.EndOfSectionIndex() >= nEnd
)
167 || ( rNode
.IsEndNode() && rNode
.StartOfSectionNode()->GetIndex() < nStart
) )
173 while( rLastIdx
.GetIndex() < nNewIdx
);
175 else if( rDelCount
) // optimization: if there are no "non-copy" nodes until now,
176 // no move backward needed
178 while( rLastIdx
.GetIndex() > nNewIdx
)
180 SwNode
& rNode
= rLastIdx
.GetNode();
181 if( ( rNode
.IsSectionNode() && rNode
.EndOfSectionIndex() >= nEnd
)
182 || ( rNode
.IsEndNode() && rNode
.StartOfSectionNode()->GetIndex() < nStart
) )
191 void lcl_SetCpyPos( const SwPosition
& rOrigPos
,
192 const SwPosition
& rOrigStt
,
193 const SwPosition
& rCpyStt
,
195 sal_uLong nDelCount
)
197 sal_uLong nNdOff
= rOrigPos
.nNode
.GetIndex();
198 nNdOff
-= rOrigStt
.nNode
.GetIndex();
200 sal_Int32 nContentPos
= rOrigPos
.nContent
.GetIndex();
202 // Always adjust <nNode> at to be changed <SwPosition> instance <rChgPos>
203 rChgPos
.nNode
= nNdOff
+ rCpyStt
.nNode
.GetIndex();
206 // just adapt the content index
207 if( nContentPos
> rOrigStt
.nContent
.GetIndex() )
208 nContentPos
-= rOrigStt
.nContent
.GetIndex();
211 nContentPos
+= rCpyStt
.nContent
.GetIndex();
213 rChgPos
.nContent
.Assign( rChgPos
.nNode
.GetNode().GetContentNode(), nContentPos
);
216 // TODO: use SaveBookmark (from DelBookmarks)
217 void lcl_CopyBookmarks(
221 const SwDoc
* pSrcDoc
= rPam
.GetDoc();
222 SwDoc
* pDestDoc
= rCpyPam
.GetDoc();
223 const IDocumentMarkAccess
* const pSrcMarkAccess
= pSrcDoc
->getIDocumentMarkAccess();
224 ::sw::UndoGuard
const undoGuard(pDestDoc
->GetIDocumentUndoRedo());
226 const SwPosition
&rStt
= *rPam
.Start(), &rEnd
= *rPam
.End();
227 SwPosition
* pCpyStt
= rCpyPam
.Start();
229 typedef std::vector
< const ::sw::mark::IMark
* > mark_vector_t
;
230 mark_vector_t vMarksToCopy
;
231 for ( IDocumentMarkAccess::const_iterator_t ppMark
= pSrcMarkAccess
->getAllMarksBegin();
232 ppMark
!= pSrcMarkAccess
->getAllMarksEnd();
235 const ::sw::mark::IMark
* const pMark
= ppMark
->get();
237 const SwPosition
& rMarkStart
= pMark
->GetMarkStart();
238 const SwPosition
& rMarkEnd
= pMark
->GetMarkEnd();
239 // only include marks that are in the range and not touching both start and end
240 // - not for annotation or checkbox marks.
241 const bool bIsNotOnBoundary
=
243 ? (rMarkStart
!= rStt
|| rMarkEnd
!= rEnd
) // rMarkStart != rMarkEnd
244 : (rMarkStart
!= rStt
&& rMarkEnd
!= rEnd
); // rMarkStart == rMarkEnd
245 const IDocumentMarkAccess::MarkType aMarkType
= IDocumentMarkAccess::GetType(*pMark
);
246 if ( rMarkStart
>= rStt
&& rMarkEnd
<= rEnd
247 && ( bIsNotOnBoundary
248 || aMarkType
== IDocumentMarkAccess::MarkType::ANNOTATIONMARK
249 || aMarkType
== IDocumentMarkAccess::MarkType::CHECKBOX_FIELDMARK
) )
251 vMarksToCopy
.push_back(pMark
);
254 // We have to count the "non-copied" nodes..
256 SwNodeIndex
aCorrIdx(InitDelCount(rPam
, nDelCount
));
257 for(mark_vector_t::const_iterator ppMark
= vMarksToCopy
.begin();
258 ppMark
!= vMarksToCopy
.end();
261 const ::sw::mark::IMark
* const pMark
= *ppMark
;
262 SwPaM
aTmpPam(*pCpyStt
);
263 lcl_NonCopyCount(rPam
, aCorrIdx
, pMark
->GetMarkPos().nNode
.GetIndex(), nDelCount
);
264 lcl_SetCpyPos( pMark
->GetMarkPos(), rStt
, *pCpyStt
, *aTmpPam
.GetPoint(), nDelCount
);
265 if(pMark
->IsExpanded())
268 lcl_NonCopyCount(rPam
, aCorrIdx
, pMark
->GetOtherMarkPos().nNode
.GetIndex(), nDelCount
);
269 lcl_SetCpyPos(pMark
->GetOtherMarkPos(), rStt
, *pCpyStt
, *aTmpPam
.GetMark(), nDelCount
);
272 ::sw::mark::IMark
* const pNewMark
= pDestDoc
->getIDocumentMarkAccess()->makeMark(
275 IDocumentMarkAccess::GetType(*pMark
),
276 ::sw::mark::InsertMode::CopyText
);
277 // Explicitly try to get exactly the same name as in the source
278 // because NavigatorReminders, DdeBookmarks etc. ignore the proposed name
279 pDestDoc
->getIDocumentMarkAccess()->renameMark(pNewMark
, pMark
->GetName());
281 // copying additional attributes for bookmarks or fieldmarks
282 ::sw::mark::IBookmark
* const pNewBookmark
=
283 dynamic_cast< ::sw::mark::IBookmark
* const >(pNewMark
);
284 const ::sw::mark::IBookmark
* const pOldBookmark
=
285 dynamic_cast< const ::sw::mark::IBookmark
* >(pMark
);
286 if (pNewBookmark
&& pOldBookmark
)
288 pNewBookmark
->SetKeyCode(pOldBookmark
->GetKeyCode());
289 pNewBookmark
->SetShortName(pOldBookmark
->GetShortName());
291 ::sw::mark::IFieldmark
* const pNewFieldmark
=
292 dynamic_cast< ::sw::mark::IFieldmark
* const >(pNewMark
);
293 const ::sw::mark::IFieldmark
* const pOldFieldmark
=
294 dynamic_cast< const ::sw::mark::IFieldmark
* >(pMark
);
295 if (pNewFieldmark
&& pOldFieldmark
)
297 pNewFieldmark
->SetFieldname(pOldFieldmark
->GetFieldname());
298 pNewFieldmark
->SetFieldHelptext(pOldFieldmark
->GetFieldHelptext());
299 ::sw::mark::IFieldmark::parameter_map_t
* pNewParams
= pNewFieldmark
->GetParameters();
300 const ::sw::mark::IFieldmark::parameter_map_t
* pOldParams
= pOldFieldmark
->GetParameters();
301 ::sw::mark::IFieldmark::parameter_map_t::const_iterator pIt
= pOldParams
->begin();
302 for (; pIt
!= pOldParams
->end(); ++pIt
)
304 pNewParams
->insert( *pIt
);
308 ::sfx2::Metadatable
const*const pMetadatable(
309 dynamic_cast< ::sfx2::Metadatable
const* >(pMark
));
310 ::sfx2::Metadatable
*const pNewMetadatable(
311 dynamic_cast< ::sfx2::Metadatable
* >(pNewMark
));
312 if (pMetadatable
&& pNewMetadatable
)
314 pNewMetadatable
->RegisterAsCopyOf(*pMetadatable
);
319 void lcl_DeleteRedlines( const SwPaM
& rPam
, SwPaM
& rCpyPam
)
321 const SwDoc
* pSrcDoc
= rPam
.GetDoc();
322 const SwRedlineTable
& rTable
= pSrcDoc
->getIDocumentRedlineAccess().GetRedlineTable();
323 if( !rTable
.empty() )
325 SwDoc
* pDestDoc
= rCpyPam
.GetDoc();
326 SwPosition
* pCpyStt
= rCpyPam
.Start(), *pCpyEnd
= rCpyPam
.End();
327 std::unique_ptr
<SwPaM
> pDelPam
;
328 const SwPosition
*pStt
= rPam
.Start(), *pEnd
= rPam
.End();
329 // We have to count the "non-copied" nodes
331 SwNodeIndex
aCorrIdx(InitDelCount(rPam
, nDelCount
));
333 SwRedlineTable::size_type n
= 0;
334 pSrcDoc
->getIDocumentRedlineAccess().GetRedline( *pStt
, &n
);
335 for( ; n
< rTable
.size(); ++n
)
337 const SwRangeRedline
* pRedl
= rTable
[ n
];
338 if( nsRedlineType_t::REDLINE_DELETE
== pRedl
->GetType() && pRedl
->IsVisible() )
340 const SwPosition
*pRStt
= pRedl
->Start(), *pREnd
= pRedl
->End();
342 SwComparePosition eCmpPos
= ComparePosition( *pStt
, *pEnd
, *pRStt
, *pREnd
);
345 case SwComparePosition::CollideEnd
:
346 case SwComparePosition::Before
:
347 // Pos1 is before Pos2
350 case SwComparePosition::CollideStart
:
351 case SwComparePosition::Behind
:
352 // Pos1 is after Pos2
358 pDelPam
.reset(new SwPaM( *pCpyStt
, pDelPam
.release() ));
361 lcl_NonCopyCount( rPam
, aCorrIdx
, pRStt
->nNode
.GetIndex(), nDelCount
);
362 lcl_SetCpyPos( *pRStt
, *pStt
, *pCpyStt
,
363 *pDelPam
->GetPoint(), nDelCount
);
368 *pDelPam
->GetPoint() = *pCpyEnd
;
371 lcl_NonCopyCount( rPam
, aCorrIdx
, pREnd
->nNode
.GetIndex(), nDelCount
);
372 lcl_SetCpyPos( *pREnd
, *pStt
, *pCpyStt
,
373 *pDelPam
->GetPoint(), nDelCount
);
382 RedlineFlags eOld
= pDestDoc
->getIDocumentRedlineAccess().GetRedlineFlags();
383 pDestDoc
->getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld
| RedlineFlags::Ignore
);
385 ::sw::UndoGuard
const undoGuard(pDestDoc
->GetIDocumentUndoRedo());
388 pDestDoc
->getIDocumentContentOperations().DeleteAndJoin( *pDelPam
->GetNext() );
389 if( !pDelPam
->IsMultiSelection() )
391 delete pDelPam
->GetNext();
394 pDestDoc
->getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld
);
399 void lcl_DeleteRedlines( const SwNodeRange
& rRg
, SwNodeRange
const & rCpyRg
)
401 SwDoc
* pSrcDoc
= rRg
.aStart
.GetNode().GetDoc();
402 if( !pSrcDoc
->getIDocumentRedlineAccess().GetRedlineTable().empty() )
404 SwPaM
aRgTmp( rRg
.aStart
, rRg
.aEnd
);
405 SwPaM
aCpyTmp( rCpyRg
.aStart
, rCpyRg
.aEnd
);
406 lcl_DeleteRedlines( aRgTmp
, aCpyTmp
);
410 void lcl_ChainFormats( SwFlyFrameFormat
*pSrc
, SwFlyFrameFormat
*pDest
)
412 SwFormatChain
aSrc( pSrc
->GetChain() );
413 if ( !aSrc
.GetNext() )
415 aSrc
.SetNext( pDest
);
416 pSrc
->SetFormatAttr( aSrc
);
418 SwFormatChain
aDest( pDest
->GetChain() );
419 if ( !aDest
.GetPrev() )
421 aDest
.SetPrev( pSrc
);
422 pDest
->SetFormatAttr( aDest
);
427 bool lcl_ContainsOnlyParagraphsInList( const SwPaM
& rPam
)
431 const SwTextNode
* pTextNd
= rPam
.Start()->nNode
.GetNode().GetTextNode();
432 const SwTextNode
* pEndTextNd
= rPam
.End()->nNode
.GetNode().GetTextNode();
433 if ( pTextNd
&& pTextNd
->IsInList() &&
434 pEndTextNd
&& pEndTextNd
->IsInList() )
437 SwNodeIndex
aIdx(rPam
.Start()->nNode
);
442 pTextNd
= aIdx
.GetNode().GetTextNode();
444 if ( !pTextNd
|| !pTextNd
->IsInList() )
449 } while ( pTextNd
&& pTextNd
!= pEndTextNd
);
455 bool lcl_MarksWholeNode(const SwPaM
& rPam
)
457 bool bResult
= false;
458 const SwPosition
* pStt
= rPam
.Start();
459 const SwPosition
* pEnd
= rPam
.End();
461 if (nullptr != pStt
&& nullptr != pEnd
)
463 const SwTextNode
* pSttNd
= pStt
->nNode
.GetNode().GetTextNode();
464 const SwTextNode
* pEndNd
= pEnd
->nNode
.GetNode().GetTextNode();
466 if (nullptr != pSttNd
&& nullptr != pEndNd
&&
467 pStt
->nContent
.GetIndex() == 0 &&
468 pEnd
->nContent
.GetIndex() == pEndNd
->Len())
478 //local functions originally from sw/source/core/doc/docedt.cxx
482 lcl_CalcBreaks( std::vector
<sal_Int32
> & rBreaks
, SwPaM
const & rPam
)
484 SwTextNode
const * const pTextNode(
485 rPam
.End()->nNode
.GetNode().GetTextNode() );
487 return; // left-overlap only possible at end of selection...
489 const sal_Int32
nStart(rPam
.Start()->nContent
.GetIndex());
490 const sal_Int32
nEnd (rPam
.End ()->nContent
.GetIndex());
491 if (nEnd
== pTextNode
->Len())
492 return; // paragraph selected until the end
494 for (sal_Int32 i
= nStart
; i
< nEnd
; ++i
)
496 const sal_Unicode
c(pTextNode
->GetText()[i
]);
497 if ((CH_TXTATR_INWORD
== c
) || (CH_TXTATR_BREAKWORD
== c
))
499 SwTextAttr
const * const pAttr( pTextNode
->GetTextAttrForCharAt(i
) );
500 if (pAttr
&& pAttr
->End() && (*pAttr
->End() > nEnd
))
502 OSL_ENSURE(pAttr
->HasDummyChar(), "GetTextAttrForCharAt broken?");
503 rBreaks
.push_back(i
);
509 bool lcl_DoWithBreaks(::sw::DocumentContentOperationsManager
& rDocumentContentOperations
, SwPaM
& rPam
,
510 bool (::sw::DocumentContentOperationsManager::*pFunc
)(SwPaM
&, bool), const bool bForceJoinNext
= false)
512 std::vector
<sal_Int32
> Breaks
;
514 lcl_CalcBreaks(Breaks
, rPam
);
518 return (rDocumentContentOperations
.*pFunc
)(rPam
, bForceJoinNext
);
521 // Deletion must be split into several parts if the text node
522 // contains a text attribute with end and with dummy character
523 // and the selection does not contain the text attribute completely,
524 // but overlaps its start (left), where the dummy character is.
526 SwPosition
const & rSelectionEnd( *rPam
.End() );
529 // iterate from end to start, to avoid invalidating the offsets!
530 std::vector
<sal_Int32
>::reverse_iterator
iter( Breaks
.rbegin() );
531 SwPaM
aPam( rSelectionEnd
, rSelectionEnd
); // end node!
532 SwPosition
& rEnd( *aPam
.End() );
533 SwPosition
& rStart( *aPam
.Start() );
535 while (iter
!= Breaks
.rend())
537 rStart
.nContent
= *iter
+ 1;
538 if (rEnd
.nContent
> rStart
.nContent
) // check if part is empty
540 bRet
&= (rDocumentContentOperations
.*pFunc
)(aPam
, bForceJoinNext
);
542 rEnd
.nContent
= *iter
;
546 rStart
= *rPam
.Start(); // set to original start
547 if (rEnd
.nContent
> rStart
.nContent
) // check if part is empty
549 bRet
&= (rDocumentContentOperations
.*pFunc
)(aPam
, bForceJoinNext
);
555 bool lcl_StrLenOverflow( const SwPaM
& rPam
)
557 // If we try to merge two paragraphs we have to test if afterwards
558 // the string doesn't exceed the allowed string length
559 if( rPam
.GetPoint()->nNode
!= rPam
.GetMark()->nNode
)
561 const SwPosition
* pStt
= rPam
.Start(), *pEnd
= rPam
.End();
562 const SwTextNode
* pEndNd
= pEnd
->nNode
.GetNode().GetTextNode();
563 if( (nullptr != pEndNd
) && pStt
->nNode
.GetNode().IsTextNode() )
565 const sal_uInt64 nSum
= pStt
->nContent
.GetIndex() +
566 pEndNd
->GetText().getLength() - pEnd
->nContent
.GetIndex();
567 return nSum
> static_cast<sal_uInt64
>(SAL_MAX_INT32
);
575 SwRangeRedline
* pRedl
;
576 sal_uInt32 nStt
, nEnd
;
580 SaveRedline( SwRangeRedline
* pR
, const SwNodeIndex
& rSttIdx
)
585 const SwPosition
* pStt
= pR
->Start(),
586 * pEnd
= pR
->GetMark() == pStt
? pR
->GetPoint() : pR
->GetMark();
587 sal_uInt32 nSttIdx
= rSttIdx
.GetIndex();
588 nStt
= pStt
->nNode
.GetIndex() - nSttIdx
;
589 nSttCnt
= pStt
->nContent
.GetIndex();
592 nEnd
= pEnd
->nNode
.GetIndex() - nSttIdx
;
593 nEndCnt
= pEnd
->nContent
.GetIndex();
596 pRedl
->GetPoint()->nNode
= 0;
597 pRedl
->GetPoint()->nContent
.Assign( nullptr, 0 );
598 pRedl
->GetMark()->nNode
= 0;
599 pRedl
->GetMark()->nContent
.Assign( nullptr, 0 );
602 SaveRedline( SwRangeRedline
* pR
, const SwPosition
& rPos
)
607 const SwPosition
* pStt
= pR
->Start(),
608 * pEnd
= pR
->GetMark() == pStt
? pR
->GetPoint() : pR
->GetMark();
609 sal_uInt32 nSttIdx
= rPos
.nNode
.GetIndex();
610 nStt
= pStt
->nNode
.GetIndex() - nSttIdx
;
611 nSttCnt
= pStt
->nContent
.GetIndex();
613 nSttCnt
= nSttCnt
- rPos
.nContent
.GetIndex();
616 nEnd
= pEnd
->nNode
.GetIndex() - nSttIdx
;
617 nEndCnt
= pEnd
->nContent
.GetIndex();
619 nEndCnt
= nEndCnt
- rPos
.nContent
.GetIndex();
622 pRedl
->GetPoint()->nNode
= 0;
623 pRedl
->GetPoint()->nContent
.Assign( nullptr, 0 );
624 pRedl
->GetMark()->nNode
= 0;
625 pRedl
->GetMark()->nContent
.Assign( nullptr, 0 );
628 void SetPos( sal_uInt32 nInsPos
)
630 pRedl
->GetPoint()->nNode
= nInsPos
+ nStt
;
631 pRedl
->GetPoint()->nContent
.Assign( pRedl
->GetContentNode(), nSttCnt
);
632 if( pRedl
->HasMark() )
634 pRedl
->GetMark()->nNode
= nInsPos
+ nEnd
;
635 pRedl
->GetMark()->nContent
.Assign( pRedl
->GetContentNode(false), nEndCnt
);
639 void SetPos( const SwPosition
& aPos
)
641 pRedl
->GetPoint()->nNode
= aPos
.nNode
.GetIndex() + nStt
;
642 pRedl
->GetPoint()->nContent
.Assign( pRedl
->GetContentNode(), nSttCnt
+ ( nStt
== 0 ? aPos
.nContent
.GetIndex() : 0 ) );
643 if( pRedl
->HasMark() )
645 pRedl
->GetMark()->nNode
= aPos
.nNode
.GetIndex() + nEnd
;
646 pRedl
->GetMark()->nContent
.Assign( pRedl
->GetContentNode(false), nEndCnt
+ ( nEnd
== 0 ? aPos
.nContent
.GetIndex() : 0 ) );
651 typedef std::vector
< SaveRedline
> SaveRedlines_t
;
653 void lcl_SaveRedlines(const SwPaM
& aPam
, SaveRedlines_t
& rArr
)
655 SwDoc
* pDoc
= aPam
.GetNode().GetDoc();
657 const SwPosition
* pStart
= aPam
.Start();
658 const SwPosition
* pEnd
= aPam
.End();
660 // get first relevant redline
661 SwRedlineTable::size_type nCurrentRedline
;
662 pDoc
->getIDocumentRedlineAccess().GetRedline( *pStart
, &nCurrentRedline
);
663 if( nCurrentRedline
> 0)
666 // redline mode RedlineFlags::Ignore|RedlineFlags::On; save old mode
667 RedlineFlags eOld
= pDoc
->getIDocumentRedlineAccess().GetRedlineFlags();
668 pDoc
->getIDocumentRedlineAccess().SetRedlineFlags_intern( ( eOld
& ~RedlineFlags::Ignore
) | RedlineFlags::On
);
670 // iterate over relevant redlines and decide for each whether it should
671 // be saved, or split + saved
672 SwRedlineTable
& rRedlineTable
= pDoc
->getIDocumentRedlineAccess().GetRedlineTable();
673 for( ; nCurrentRedline
< rRedlineTable
.size(); nCurrentRedline
++ )
675 SwRangeRedline
* pCurrent
= rRedlineTable
[ nCurrentRedline
];
676 SwComparePosition eCompare
=
677 ComparePosition( *pCurrent
->Start(), *pCurrent
->End(),
680 // we must save this redline if it overlaps aPam
681 // (we may have to split it, too)
682 if( eCompare
== SwComparePosition::OverlapBehind
||
683 eCompare
== SwComparePosition::OverlapBefore
||
684 eCompare
== SwComparePosition::Outside
||
685 eCompare
== SwComparePosition::Inside
||
686 eCompare
== SwComparePosition::Equal
)
688 rRedlineTable
.Remove( nCurrentRedline
-- );
690 // split beginning, if necessary
691 if( eCompare
== SwComparePosition::OverlapBefore
||
692 eCompare
== SwComparePosition::Outside
)
694 SwRangeRedline
* pNewRedline
= new SwRangeRedline( *pCurrent
);
695 *pNewRedline
->End() = *pStart
;
696 *pCurrent
->Start() = *pStart
;
697 pDoc
->getIDocumentRedlineAccess().AppendRedline( pNewRedline
, true );
700 // split end, if necessary
701 if( eCompare
== SwComparePosition::OverlapBehind
||
702 eCompare
== SwComparePosition::Outside
)
704 SwRangeRedline
* pNewRedline
= new SwRangeRedline( *pCurrent
);
705 *pNewRedline
->Start() = *pEnd
;
706 *pCurrent
->End() = *pEnd
;
707 pDoc
->getIDocumentRedlineAccess().AppendRedline( pNewRedline
, true );
710 // save the current redline
711 rArr
.emplace_back( pCurrent
, *pStart
);
715 // restore old redline mode
716 pDoc
->getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld
);
719 void lcl_RestoreRedlines(SwDoc
* pDoc
, const SwPosition
& rPos
, SaveRedlines_t
& rArr
)
721 RedlineFlags eOld
= pDoc
->getIDocumentRedlineAccess().GetRedlineFlags();
722 pDoc
->getIDocumentRedlineAccess().SetRedlineFlags_intern( ( eOld
& ~RedlineFlags::Ignore
) | RedlineFlags::On
);
724 for(SaveRedline
& rSvRedLine
: rArr
)
726 rSvRedLine
.SetPos( rPos
);
727 pDoc
->getIDocumentRedlineAccess().AppendRedline( rSvRedLine
.pRedl
, true );
730 pDoc
->getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld
);
733 void lcl_SaveRedlines(const SwNodeRange
& rRg
, SaveRedlines_t
& rArr
)
735 SwDoc
* pDoc
= rRg
.aStart
.GetNode().GetDoc();
736 SwRedlineTable::size_type nRedlPos
;
737 SwPosition
aSrchPos( rRg
.aStart
); aSrchPos
.nNode
--;
738 aSrchPos
.nContent
.Assign( aSrchPos
.nNode
.GetNode().GetContentNode(), 0 );
739 if( pDoc
->getIDocumentRedlineAccess().GetRedline( aSrchPos
, &nRedlPos
) && nRedlPos
)
741 else if( nRedlPos
>= pDoc
->getIDocumentRedlineAccess().GetRedlineTable().size() )
744 RedlineFlags eOld
= pDoc
->getIDocumentRedlineAccess().GetRedlineFlags();
745 pDoc
->getIDocumentRedlineAccess().SetRedlineFlags_intern( ( eOld
& ~RedlineFlags::Ignore
) | RedlineFlags::On
);
746 SwRedlineTable
& rRedlTable
= pDoc
->getIDocumentRedlineAccess().GetRedlineTable();
749 SwRangeRedline
* pTmp
= rRedlTable
[ nRedlPos
];
751 const SwPosition
* pRStt
= pTmp
->Start(),
752 * pREnd
= pTmp
->GetMark() == pRStt
753 ? pTmp
->GetPoint() : pTmp
->GetMark();
755 if( pRStt
->nNode
< rRg
.aStart
)
757 if( pREnd
->nNode
> rRg
.aStart
&& pREnd
->nNode
< rRg
.aEnd
)
759 // Create a copy and set the end of the original to the end of the MoveArea.
760 // The copy is moved too.
761 SwRangeRedline
* pNewRedl
= new SwRangeRedline( *pTmp
);
762 SwPosition
* pTmpPos
= pNewRedl
->Start();
763 pTmpPos
->nNode
= rRg
.aStart
;
764 pTmpPos
->nContent
.Assign(
765 pTmpPos
->nNode
.GetNode().GetContentNode(), 0 );
767 rArr
.emplace_back(pNewRedl
, rRg
.aStart
);
769 pTmpPos
= pTmp
->End();
770 pTmpPos
->nNode
= rRg
.aEnd
;
771 pTmpPos
->nContent
.Assign(
772 pTmpPos
->nNode
.GetNode().GetContentNode(), 0 );
774 else if( pREnd
->nNode
== rRg
.aStart
)
776 SwPosition
* pTmpPos
= pTmp
->End();
777 pTmpPos
->nNode
= rRg
.aEnd
;
778 pTmpPos
->nContent
.Assign(
779 pTmpPos
->nNode
.GetNode().GetContentNode(), 0 );
782 else if( pRStt
->nNode
< rRg
.aEnd
)
784 rRedlTable
.Remove( nRedlPos
-- );
785 if( pREnd
->nNode
< rRg
.aEnd
||
786 ( pREnd
->nNode
== rRg
.aEnd
&& !pREnd
->nContent
.GetIndex()) )
789 rArr
.emplace_back( pTmp
, rRg
.aStart
);
794 SwRangeRedline
* pNewRedl
= new SwRangeRedline( *pTmp
);
795 SwPosition
* pTmpPos
= pNewRedl
->End();
796 pTmpPos
->nNode
= rRg
.aEnd
;
797 pTmpPos
->nContent
.Assign(
798 pTmpPos
->nNode
.GetNode().GetContentNode(), 0 );
800 rArr
.emplace_back( pNewRedl
, rRg
.aStart
);
802 pTmpPos
= pTmp
->Start();
803 pTmpPos
->nNode
= rRg
.aEnd
;
804 pTmpPos
->nContent
.Assign(
805 pTmpPos
->nNode
.GetNode().GetContentNode(), 0 );
806 pDoc
->getIDocumentRedlineAccess().AppendRedline( pTmp
, true );
812 } while( ++nRedlPos
< pDoc
->getIDocumentRedlineAccess().GetRedlineTable().size() );
813 pDoc
->getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld
);
816 void lcl_RestoreRedlines(SwDoc
*const pDoc
, sal_uInt32
const nInsPos
, SaveRedlines_t
& rArr
)
818 RedlineFlags eOld
= pDoc
->getIDocumentRedlineAccess().GetRedlineFlags();
819 pDoc
->getIDocumentRedlineAccess().SetRedlineFlags_intern( ( eOld
& ~RedlineFlags::Ignore
) | RedlineFlags::On
);
821 for(SaveRedline
& rSvRedLine
: rArr
)
823 rSvRedLine
.SetPos( nInsPos
);
824 pDoc
->getIDocumentRedlineAccess().AppendRedline( rSvRedLine
.pRedl
, true );
827 pDoc
->getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld
);
830 bool lcl_SaveFootnote( const SwNodeIndex
& rSttNd
, const SwNodeIndex
& rEndNd
,
831 const SwNodeIndex
& rInsPos
,
832 SwFootnoteIdxs
& rFootnoteArr
, SwFootnoteIdxs
& rSaveArr
,
833 const SwIndex
* pSttCnt
= nullptr, const SwIndex
* pEndCnt
= nullptr )
835 bool bUpdateFootnote
= false;
836 const SwNodes
& rNds
= rInsPos
.GetNodes();
837 const bool bDelFootnote
= rInsPos
.GetIndex() < rNds
.GetEndOfAutotext().GetIndex() &&
838 rSttNd
.GetIndex() >= rNds
.GetEndOfAutotext().GetIndex();
839 const bool bSaveFootnote
= !bDelFootnote
&&
840 rInsPos
.GetIndex() >= rNds
.GetEndOfExtras().GetIndex();
841 if( !rFootnoteArr
.empty() )
845 rFootnoteArr
.SeekEntry( rSttNd
, &nPos
);
846 SwTextFootnote
* pSrch
;
847 const SwNode
* pFootnoteNd
;
849 // Delete/save all that come after it
850 while( nPos
< rFootnoteArr
.size() && ( pFootnoteNd
=
851 &( pSrch
= rFootnoteArr
[ nPos
] )->GetTextNode())->GetIndex()
852 <= rEndNd
.GetIndex() )
854 const sal_Int32 nFootnoteSttIdx
= pSrch
->GetStart();
855 if( ( pEndCnt
&& pSttCnt
)
856 ? (( &rSttNd
.GetNode() == pFootnoteNd
&&
857 pSttCnt
->GetIndex() > nFootnoteSttIdx
) ||
858 ( &rEndNd
.GetNode() == pFootnoteNd
&&
859 nFootnoteSttIdx
>= pEndCnt
->GetIndex() ))
860 : ( &rEndNd
.GetNode() == pFootnoteNd
))
862 ++nPos
; // continue searching
869 SwTextNode
& rTextNd
= const_cast<SwTextNode
&>(pSrch
->GetTextNode());
870 SwIndex
aIdx( &rTextNd
, nFootnoteSttIdx
);
871 rTextNd
.EraseText( aIdx
, 1 );
875 pSrch
->DelFrames(nullptr);
876 rFootnoteArr
.erase( rFootnoteArr
.begin() + nPos
);
878 rSaveArr
.insert( pSrch
);
880 bUpdateFootnote
= true;
884 while( nPos
-- && ( pFootnoteNd
= &( pSrch
= rFootnoteArr
[ nPos
] )->
885 GetTextNode())->GetIndex() >= rSttNd
.GetIndex() )
887 const sal_Int32 nFootnoteSttIdx
= pSrch
->GetStart();
888 if( !pEndCnt
|| !pSttCnt
||
889 ! (( &rSttNd
.GetNode() == pFootnoteNd
&&
890 pSttCnt
->GetIndex() > nFootnoteSttIdx
) ||
891 ( &rEndNd
.GetNode() == pFootnoteNd
&&
892 nFootnoteSttIdx
>= pEndCnt
->GetIndex() )) )
897 SwTextNode
& rTextNd
= const_cast<SwTextNode
&>(pSrch
->GetTextNode());
898 SwIndex
aIdx( &rTextNd
, nFootnoteSttIdx
);
899 rTextNd
.EraseText( aIdx
, 1 );
903 pSrch
->DelFrames(nullptr);
904 rFootnoteArr
.erase( rFootnoteArr
.begin() + nPos
);
906 rSaveArr
.insert( pSrch
);
908 bUpdateFootnote
= true;
912 // When moving from redline section into document content section, e.g.
913 // after loading a document with (delete-)redlines, the footnote array
914 // has to be adjusted... (#i70572)
917 SwNodeIndex
aIdx( rSttNd
);
918 while( aIdx
< rEndNd
) // Check the moved section
920 SwNode
* pNode
= &aIdx
.GetNode();
921 if( pNode
->IsTextNode() ) // Looking for text nodes...
923 SwpHints
*pHints
= pNode
->GetTextNode()->GetpSwpHints();
924 if( pHints
&& pHints
->HasFootnote() ) //...with footnotes
926 bUpdateFootnote
= true; // Heureka
927 const size_t nCount
= pHints
->Count();
928 for( size_t i
= 0; i
< nCount
; ++i
)
930 SwTextAttr
*pAttr
= pHints
->Get( i
);
931 if ( pAttr
->Which() == RES_TXTATR_FTN
)
933 rSaveArr
.insert( static_cast<SwTextFootnote
*>(pAttr
) );
941 return bUpdateFootnote
;
944 bool lcl_MayOverwrite( const SwTextNode
*pNode
, const sal_Int32 nPos
)
946 sal_Unicode
const cChr
= pNode
->GetText()[nPos
];
949 case CH_TXTATR_BREAKWORD
:
950 case CH_TXTATR_INWORD
:
951 return !pNode
->GetTextAttrForCharAt(nPos
);// how could there be none?
952 case CH_TXT_ATR_FIELDSTART
:
953 case CH_TXT_ATR_FIELDEND
:
954 case CH_TXT_ATR_FORMELEMENT
:
961 void lcl_SkipAttr( const SwTextNode
*pNode
, SwIndex
&rIdx
, sal_Int32
&rStart
)
963 if( !lcl_MayOverwrite( pNode
, rStart
) )
965 // skip all special attributes
968 rStart
= rIdx
.GetIndex();
969 } while (rStart
< pNode
->GetText().getLength()
970 && !lcl_MayOverwrite(pNode
, rStart
) );
974 bool lcl_GetTokenToParaBreak( OUString
& rStr
, OUString
& rRet
, bool bRegExpRplc
)
979 const OUString
sPara("\\n");
982 nPos
= rStr
.indexOf( sPara
, nPos
);
987 // Has this been escaped?
988 if( nPos
&& '\\' == rStr
[nPos
-1])
991 if( nPos
>= rStr
.getLength() )
998 rRet
= rStr
.copy( 0, nPos
);
999 rStr
= rStr
.copy( nPos
+ sPara
.getLength() );
1010 namespace //local functions originally from docfmt.cxx
1012 #define DELETECHARSETS if ( bDelete ) { delete pCharSet; delete pOtherSet; }
1014 /// Insert Hints according to content types;
1015 // Is used in SwDoc::Insert(..., SwFormatHint &rHt)
1020 const SfxItemSet
& rChgSet
,
1021 const SetAttrMode nFlags
,
1022 SwUndoAttr
*const pUndo
,
1023 const bool bExpandCharToPara
=false)
1025 // Divide the Sets (for selections in Nodes)
1026 const SfxItemSet
* pCharSet
= nullptr;
1027 const SfxItemSet
* pOtherSet
= nullptr;
1028 bool bDelete
= false;
1029 bool bCharAttr
= false;
1030 bool bOtherAttr
= false;
1032 // Check, if we can work with rChgSet or if we have to create additional SfxItemSets
1033 if ( 1 == rChgSet
.Count() )
1035 SfxItemIter
aIter( rChgSet
);
1036 const SfxPoolItem
* pItem
= aIter
.FirstItem();
1037 if (pItem
&& !IsInvalidItem(pItem
))
1039 const sal_uInt16 nWhich
= pItem
->Which();
1041 if ( isCHRATR(nWhich
) ||
1042 (RES_TXTATR_CHARFMT
== nWhich
) ||
1043 (RES_TXTATR_INETFMT
== nWhich
) ||
1044 (RES_TXTATR_AUTOFMT
== nWhich
) ||
1045 (RES_TXTATR_UNKNOWN_CONTAINER
== nWhich
) )
1047 pCharSet
= &rChgSet
;
1051 if ( isPARATR(nWhich
)
1052 || isPARATR_LIST(nWhich
)
1055 || isUNKNOWNATR(nWhich
)
1056 || isDrawingLayerAttribute(nWhich
) )
1058 pOtherSet
= &rChgSet
;
1064 // Build new itemset if either
1065 // - rChgSet.Count() > 1 or
1066 // - The attribute in rChgSet does not belong to one of the above categories
1067 if ( !bCharAttr
&& !bOtherAttr
)
1069 SfxItemSet
* pTmpCharItemSet
= new SfxItemSet(
1070 pDoc
->GetAttrPool(),
1072 RES_CHRATR_BEGIN
, RES_CHRATR_END
- 1,
1073 RES_TXTATR_AUTOFMT
, RES_TXTATR_CHARFMT
,
1074 RES_TXTATR_UNKNOWN_CONTAINER
,
1075 RES_TXTATR_UNKNOWN_CONTAINER
>{});
1077 SfxItemSet
* pTmpOtherItemSet
= new SfxItemSet(
1078 pDoc
->GetAttrPool(),
1080 RES_PARATR_BEGIN
, RES_GRFATR_END
- 1,
1081 RES_UNKNOWNATR_BEGIN
, RES_UNKNOWNATR_END
- 1,
1082 // FillAttribute support:
1083 XATTR_FILL_FIRST
, XATTR_FILL_LAST
>{});
1085 pTmpCharItemSet
->Put( rChgSet
);
1086 pTmpOtherItemSet
->Put( rChgSet
);
1088 pCharSet
= pTmpCharItemSet
;
1089 pOtherSet
= pTmpOtherItemSet
;
1094 SwHistory
* pHistory
= pUndo
? &pUndo
->GetHistory() : nullptr;
1096 const SwPosition
*pStt
= rRg
.Start(), *pEnd
= rRg
.End();
1097 SwContentNode
* pNode
= pStt
->nNode
.GetNode().GetContentNode();
1099 if( pNode
&& pNode
->IsTextNode() )
1102 if (rRg
.IsInFrontOfLabel())
1104 SwTextNode
* pTextNd
= pNode
->GetTextNode();
1105 SwNumRule
* pNumRule
= pTextNd
->GetNumRule();
1109 OSL_FAIL( "<InsAttr(..)> - PaM in front of label, but text node has no numbering rule set. This is a serious defect." );
1114 int nLevel
= pTextNd
->GetActualListLevel();
1119 if (nLevel
>= MAXLEVEL
)
1120 nLevel
= MAXLEVEL
- 1;
1122 SwNumFormat aNumFormat
= pNumRule
->Get(static_cast<sal_uInt16
>(nLevel
));
1123 SwCharFormat
* pCharFormat
=
1124 pDoc
->FindCharFormatByName(aNumFormat
.GetCharFormatName());
1129 pHistory
->Add(pCharFormat
->GetAttrSet(), *pCharFormat
);
1132 pCharFormat
->SetFormatAttr(*pCharSet
);
1139 const SwIndex
& rSt
= pStt
->nContent
;
1141 // Attributes without an end do not have a range
1142 if ( !bCharAttr
&& !bOtherAttr
)
1144 SfxItemSet
aTextSet( pDoc
->GetAttrPool(),
1145 svl::Items
<RES_TXTATR_NOEND_BEGIN
, RES_TXTATR_NOEND_END
-1>{} );
1146 aTextSet
.Put( rChgSet
);
1147 if( aTextSet
.Count() )
1149 SwRegHistory
history( pNode
, *pNode
, pHistory
);
1150 bRet
= history
.InsertItems(
1151 aTextSet
, rSt
.GetIndex(), rSt
.GetIndex(), nFlags
) || bRet
;
1153 if (bRet
&& (pDoc
->getIDocumentRedlineAccess().IsRedlineOn() || (!pDoc
->getIDocumentRedlineAccess().IsIgnoreRedline()
1154 && !pDoc
->getIDocumentRedlineAccess().GetRedlineTable().empty())))
1156 SwPaM
aPam( pStt
->nNode
, pStt
->nContent
.GetIndex()-1,
1157 pStt
->nNode
, pStt
->nContent
.GetIndex() );
1160 pUndo
->SaveRedlineData( aPam
, true );
1162 if( pDoc
->getIDocumentRedlineAccess().IsRedlineOn() )
1163 pDoc
->getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline( nsRedlineType_t::REDLINE_INSERT
, aPam
), true);
1165 pDoc
->getIDocumentRedlineAccess().SplitRedline( aPam
);
1170 // TextAttributes with an end never expand their range
1171 if ( !bCharAttr
&& !bOtherAttr
)
1173 // CharFormat and URL attributes are treated separately!
1174 // TEST_TEMP ToDo: AutoFormat!
1175 SfxItemSet
aTextSet(
1176 pDoc
->GetAttrPool(),
1178 RES_TXTATR_REFMARK
, RES_TXTATR_METAFIELD
,
1179 RES_TXTATR_CJK_RUBY
, RES_TXTATR_CJK_RUBY
,
1180 RES_TXTATR_INPUTFIELD
, RES_TXTATR_INPUTFIELD
>{});
1182 aTextSet
.Put( rChgSet
);
1183 if( aTextSet
.Count() )
1185 const sal_Int32 nInsCnt
= rSt
.GetIndex();
1186 const sal_Int32 nEnd
= pStt
->nNode
== pEnd
->nNode
1187 ? pEnd
->nContent
.GetIndex()
1189 SwRegHistory
history( pNode
, *pNode
, pHistory
);
1190 bRet
= history
.InsertItems( aTextSet
, nInsCnt
, nEnd
, nFlags
)
1193 if (bRet
&& (pDoc
->getIDocumentRedlineAccess().IsRedlineOn() || (!pDoc
->getIDocumentRedlineAccess().IsIgnoreRedline()
1194 && !pDoc
->getIDocumentRedlineAccess().GetRedlineTable().empty())))
1196 // Was text content inserted? (RefMark/TOXMarks without an end)
1197 bool bTextIns
= nInsCnt
!= rSt
.GetIndex();
1198 // Was content inserted or set over the selection?
1199 SwPaM
aPam( pStt
->nNode
, bTextIns
? nInsCnt
+ 1 : nEnd
,
1200 pStt
->nNode
, nInsCnt
);
1202 pUndo
->SaveRedlineData( aPam
, bTextIns
);
1204 if( pDoc
->getIDocumentRedlineAccess().IsRedlineOn() )
1205 pDoc
->getIDocumentRedlineAccess().AppendRedline(
1207 bTextIns
? nsRedlineType_t::REDLINE_INSERT
: nsRedlineType_t::REDLINE_FORMAT
, aPam
),
1210 pDoc
->getIDocumentRedlineAccess().SplitRedline( aPam
);
1216 // We always have to set the auto flag for PageDescs that are set at the Node!
1217 if( pOtherSet
&& pOtherSet
->Count() )
1219 SwTableNode
* pTableNd
;
1220 const SwFormatPageDesc
* pDesc
;
1221 if( SfxItemState::SET
== pOtherSet
->GetItemState( RES_PAGEDESC
,
1222 false, reinterpret_cast<const SfxPoolItem
**>(&pDesc
) ))
1226 // Set auto flag. Only in the template it's without auto!
1227 SwFormatPageDesc
aNew( *pDesc
);
1229 // Tables now also know line breaks
1230 if( !(nFlags
& SetAttrMode::APICALL
) &&
1231 nullptr != ( pTableNd
= pNode
->FindTableNode() ) )
1233 SwTableNode
* pCurTableNd
= pTableNd
;
1234 while ( nullptr != ( pCurTableNd
= pCurTableNd
->StartOfSectionNode()->FindTableNode() ) )
1235 pTableNd
= pCurTableNd
;
1237 // set the table format
1238 SwFrameFormat
* pFormat
= pTableNd
->GetTable().GetFrameFormat();
1239 SwRegHistory
aRegH( pFormat
, *pTableNd
, pHistory
);
1240 pFormat
->SetFormatAttr( aNew
);
1245 SwRegHistory
aRegH( pNode
, *pNode
, pHistory
);
1246 bRet
= pNode
->SetAttr( aNew
) || bRet
;
1250 // bOtherAttr = true means that pOtherSet == rChgSet. In this case
1251 // we know, that there is only one attribute in pOtherSet. We cannot
1252 // perform the following operations, instead we return:
1256 const_cast<SfxItemSet
*>(pOtherSet
)->ClearItem( RES_PAGEDESC
);
1257 if( !pOtherSet
->Count() )
1264 // Tables now also know line breaks
1265 const SvxFormatBreakItem
* pBreak
;
1266 if( pNode
&& !(nFlags
& SetAttrMode::APICALL
) &&
1267 nullptr != (pTableNd
= pNode
->FindTableNode() ) &&
1268 SfxItemState::SET
== pOtherSet
->GetItemState( RES_BREAK
,
1269 false, reinterpret_cast<const SfxPoolItem
**>(&pBreak
) ) )
1271 SwTableNode
* pCurTableNd
= pTableNd
;
1272 while ( nullptr != ( pCurTableNd
= pCurTableNd
->StartOfSectionNode()->FindTableNode() ) )
1273 pTableNd
= pCurTableNd
;
1275 // set the table format
1276 SwFrameFormat
* pFormat
= pTableNd
->GetTable().GetFrameFormat();
1277 SwRegHistory
aRegH( pFormat
, *pTableNd
, pHistory
);
1278 pFormat
->SetFormatAttr( *pBreak
);
1281 // bOtherAttr = true means that pOtherSet == rChgSet. In this case
1282 // we know, that there is only one attribute in pOtherSet. We cannot
1283 // perform the following operations, instead we return:
1287 const_cast<SfxItemSet
*>(pOtherSet
)->ClearItem( RES_BREAK
);
1288 if( !pOtherSet
->Count() )
1296 // If we have a PoolNumRule, create it if needed
1297 const SwNumRuleItem
* pRule
;
1298 sal_uInt16 nPoolId
=0;
1299 if( SfxItemState::SET
== pOtherSet
->GetItemState( RES_PARATR_NUMRULE
,
1300 false, reinterpret_cast<const SfxPoolItem
**>(&pRule
) ) &&
1301 !pDoc
->FindNumRulePtr( pRule
->GetValue() ) &&
1302 USHRT_MAX
!= (nPoolId
= SwStyleNameMapper::GetPoolIdFromUIName ( pRule
->GetValue(),
1303 SwGetPoolIdFromName::NumRule
)) )
1304 pDoc
->getIDocumentStylePoolAccess().GetNumRuleFromPool( nPoolId
);
1308 if( !rRg
.HasMark() ) // no range
1316 if( pNode
->IsTextNode() && pCharSet
&& pCharSet
->Count() )
1318 SwTextNode
* pTextNd
= pNode
->GetTextNode();
1319 const SwIndex
& rSt
= pStt
->nContent
;
1320 sal_Int32 nMkPos
, nPtPos
= rSt
.GetIndex();
1321 const OUString
& rStr
= pTextNd
->GetText();
1323 // Special case: if the Cursor is located within a URL attribute, we take over it's area
1324 SwTextAttr
const*const pURLAttr(
1325 pTextNd
->GetTextAttrAt(rSt
.GetIndex(), RES_TXTATR_INETFMT
));
1326 if (pURLAttr
&& !pURLAttr
->GetINetFormat().GetValue().isEmpty())
1328 nMkPos
= pURLAttr
->GetStart();
1329 nPtPos
= *pURLAttr
->End();
1333 assert(g_pBreakIt
&& g_pBreakIt
->GetBreakIter().is());
1334 Boundary aBndry
= g_pBreakIt
->GetBreakIter()->getWordBoundary(
1335 pTextNd
->GetText(), nPtPos
,
1336 g_pBreakIt
->GetLocale( pTextNd
->GetLang( nPtPos
) ),
1337 WordType::ANY_WORD
/*ANYWORD_IGNOREWHITESPACES*/,
1340 if( aBndry
.startPos
< nPtPos
&& nPtPos
< aBndry
.endPos
)
1342 nMkPos
= aBndry
.startPos
;
1343 nPtPos
= aBndry
.endPos
;
1346 nPtPos
= nMkPos
= rSt
.GetIndex();
1349 // Remove the overriding attributes from the SwpHintsArray,
1350 // if the selection spans across the whole paragraph.
1351 // These attributes are inserted as FormatAttributes and
1352 // never override the TextAttributes!
1353 if( !(nFlags
& SetAttrMode::DONTREPLACE
) &&
1354 pTextNd
->HasHints() && !nMkPos
&& nPtPos
== rStr
.getLength())
1356 SwIndex
aSt( pTextNd
);
1359 // Save all attributes for the Undo.
1360 SwRegHistory
aRHst( *pTextNd
, pHistory
);
1361 pTextNd
->GetpSwpHints()->Register( &aRHst
);
1362 pTextNd
->RstTextAttr( aSt
, nPtPos
, 0, pCharSet
);
1363 if( pTextNd
->GetpSwpHints() )
1364 pTextNd
->GetpSwpHints()->DeRegister();
1367 pTextNd
->RstTextAttr( aSt
, nPtPos
, 0, pCharSet
);
1370 // the SwRegHistory inserts the attribute into the TextNode!
1371 SwRegHistory
history( pNode
, *pNode
, pHistory
);
1372 bRet
= history
.InsertItems( *pCharSet
, nMkPos
, nPtPos
, nFlags
)
1375 if( pDoc
->getIDocumentRedlineAccess().IsRedlineOn() )
1377 SwPaM
aPam( *pNode
, nMkPos
, *pNode
, nPtPos
);
1380 pUndo
->SaveRedlineData( aPam
, false );
1381 pDoc
->getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline( nsRedlineType_t::REDLINE_FORMAT
, aPam
), true);
1384 if( pOtherSet
&& pOtherSet
->Count() )
1386 SwRegHistory
aRegH( pNode
, *pNode
, pHistory
);
1388 // Need to check for unique item for DrawingLayer items of type NameOrIndex
1389 // and evtl. correct that item to ensure unique names for that type. This call may
1390 // modify/correct entries inside of the given SfxItemSet
1391 SfxItemSet
aTempLocalCopy(*pOtherSet
);
1393 pDoc
->CheckForUniqueItemForLineFillNameOrIndex(aTempLocalCopy
);
1394 bRet
= pNode
->SetAttr(aTempLocalCopy
) || bRet
;
1401 if( pDoc
->getIDocumentRedlineAccess().IsRedlineOn() && pCharSet
&& pCharSet
->Count() )
1404 pUndo
->SaveRedlineData( rRg
, false );
1405 pDoc
->getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline( nsRedlineType_t::REDLINE_FORMAT
, rRg
), true);
1409 sal_uLong nNodes
= 0;
1411 SwNodeIndex
aSt( pDoc
->GetNodes() );
1412 SwNodeIndex
aEnd( pDoc
->GetNodes() );
1413 SwIndex
aCntEnd( pEnd
->nContent
);
1417 const sal_Int32 nLen
= pNode
->Len();
1418 if( pStt
->nNode
!= pEnd
->nNode
)
1419 aCntEnd
.Assign( pNode
, nLen
);
1421 if( pStt
->nContent
.GetIndex() != 0 || aCntEnd
.GetIndex() != nLen
)
1423 // the SwRegHistory inserts the attribute into the TextNode!
1424 if( pNode
->IsTextNode() && pCharSet
&& pCharSet
->Count() )
1426 SwRegHistory
history( pNode
, *pNode
, pHistory
);
1427 bRet
= history
.InsertItems(*pCharSet
,
1428 pStt
->nContent
.GetIndex(), aCntEnd
.GetIndex(), nFlags
)
1432 if( pOtherSet
&& pOtherSet
->Count() )
1434 SwRegHistory
aRegH( pNode
, *pNode
, pHistory
);
1435 bRet
= pNode
->SetAttr( *pOtherSet
) || bRet
;
1438 // Only selection in a Node.
1439 if( pStt
->nNode
== pEnd
->nNode
)
1441 //The data parameter flag: bExpandCharToPara, comes from the data member of SwDoc,
1442 //which is set in SW MS Word Binary filter WW8ImplRreader. With this flag on, means that
1443 //current setting attribute set is a character range properties set and comes from a MS Word
1444 //binary file, and the setting range include a paragraph end position (0X0D);
1445 //more specifications, as such property inside the character range properties set recorded in
1446 //MS Word binary file are dealed and inserted into data model (SwDoc) one by one, so we
1447 //only dealing the scenario that the char properties set with 1 item inside;
1449 if (bExpandCharToPara
&& pCharSet
&& pCharSet
->Count() ==1 )
1451 SwTextNode
* pCurrentNd
= pStt
->nNode
.GetNode().GetTextNode();
1455 pCurrentNd
->TryCharSetExpandToNum(*pCharSet
);
1463 aSt
.Assign( pStt
->nNode
.GetNode(), +1 );
1467 aCntEnd
= pEnd
->nContent
; // aEnd was changed!
1470 aSt
.Assign( pStt
->nNode
.GetNode(), +1 );
1472 // aSt points to the first full Node now
1475 * The selection spans more than one Node.
1477 if( pStt
->nNode
< pEnd
->nNode
)
1479 pNode
= pEnd
->nNode
.GetNode().GetContentNode();
1482 if( aCntEnd
.GetIndex() != pNode
->Len() )
1484 // the SwRegHistory inserts the attribute into the TextNode!
1485 if( pNode
->IsTextNode() && pCharSet
&& pCharSet
->Count() )
1487 SwRegHistory
history( pNode
, *pNode
, pHistory
);
1488 (void)history
.InsertItems(*pCharSet
,
1489 0, aCntEnd
.GetIndex(), nFlags
);
1492 if( pOtherSet
&& pOtherSet
->Count() )
1494 SwRegHistory
aRegH( pNode
, *pNode
, pHistory
);
1495 pNode
->SetAttr( *pOtherSet
);
1502 aEnd
.Assign( pEnd
->nNode
.GetNode(), +1 );
1508 aEnd
.Assign( pEnd
->nNode
.GetNode(), +1 );
1510 // aEnd points BEHIND the last full node now
1512 /* Edit the fully selected Nodes. */
1513 // Reset all attributes from the set!
1514 if( pCharSet
&& pCharSet
->Count() && !( SetAttrMode::DONTREPLACE
& nFlags
) )
1516 ::sw::DocumentContentOperationsManager::ParaRstFormat
aPara( pStt
, pEnd
, pHistory
, pCharSet
);
1517 pDoc
->GetNodes().ForEach( aSt
, aEnd
, ::sw::DocumentContentOperationsManager::lcl_RstTextAttr
, &aPara
);
1520 bool bCreateSwpHints
= pCharSet
&& (
1521 SfxItemState::SET
== pCharSet
->GetItemState( RES_TXTATR_CHARFMT
, false ) ||
1522 SfxItemState::SET
== pCharSet
->GetItemState( RES_TXTATR_INETFMT
, false ) );
1524 for(; aSt
< aEnd
; ++aSt
)
1526 pNode
= aSt
.GetNode().GetContentNode();
1530 SwTextNode
* pTNd
= pNode
->GetTextNode();
1533 SwRegHistory
aRegH( pNode
, *pNode
, pHistory
);
1535 if( pTNd
&& pCharSet
&& pCharSet
->Count() )
1537 SwpHints
*pSwpHints
= bCreateSwpHints
? &pTNd
->GetOrCreateSwpHints()
1538 : pTNd
->GetpSwpHints();
1540 pSwpHints
->Register( &aRegH
);
1542 pTNd
->SetAttr(*pCharSet
, 0, pTNd
->GetText().getLength(), nFlags
);
1544 pSwpHints
->DeRegister();
1546 if( pOtherSet
&& pOtherSet
->Count() )
1547 pNode
->SetAttr( *pOtherSet
);
1551 if( pTNd
&& pCharSet
&& pCharSet
->Count() )
1552 pTNd
->SetAttr(*pCharSet
, 0, pTNd
->GetText().getLength(), nFlags
);
1553 if( pOtherSet
&& pOtherSet
->Count() )
1554 pNode
->SetAttr( *pOtherSet
);
1559 //The data parameter flag: bExpandCharToPara, comes from the data member of SwDoc,
1560 //which is set in SW MS Word Binary filter WW8ImplRreader. With this flag on, means that
1561 //current setting attribute set is a character range properties set and comes from a MS Word
1562 //binary file, and the setting range include a paragraph end position (0X0D);
1563 //more specifications, as such property inside the character range properties set recorded in
1564 //MS Word binary file are dealed and inserted into data model (SwDoc) one by one, so we
1565 //only dealing the scenario that the char properties set with 1 item inside;
1566 if (bExpandCharToPara
&& pCharSet
&& pCharSet
->Count() ==1)
1568 SwPosition
aStartPos (*rRg
.Start());
1569 SwPosition
aEndPos (*rRg
.End());
1571 if (aEndPos
.nNode
.GetNode().GetTextNode() && aEndPos
.nContent
!= aEndPos
.nNode
.GetNode().GetTextNode()->Len())
1574 sal_uLong nStart
= aStartPos
.nNode
.GetIndex();
1575 sal_uLong nEnd
= aEndPos
.nNode
.GetIndex();
1576 for(; nStart
<= nEnd
; ++nStart
)
1578 SwNode
* pNd
= pDoc
->GetNodes()[ nStart
];
1579 if (!pNd
|| !pNd
->IsTextNode())
1581 SwTextNode
*pCurrentNd
= pNd
->GetTextNode();
1582 pCurrentNd
->TryCharSetExpandToNum(*pCharSet
);
1587 return (nNodes
!= 0) || bRet
;
1594 DocumentContentOperationsManager::DocumentContentOperationsManager( SwDoc
& i_rSwdoc
) : m_rDoc( i_rSwdoc
)
1598 // Copy an area into this document or into another document
1600 DocumentContentOperationsManager::CopyRange( SwPaM
& rPam
, SwPosition
& rPos
, const bool bCopyAll
, bool bCheckPos
) const
1602 const SwPosition
*pStt
= rPam
.Start(), *pEnd
= rPam
.End();
1604 SwDoc
* pDoc
= rPos
.nNode
.GetNode().GetDoc();
1605 bool bColumnSel
= pDoc
->IsClipBoard() && pDoc
->IsColumnSelection();
1607 // Catch if there's no copy to do
1608 if( !rPam
.HasMark() || ( *pStt
>= *pEnd
&& !bColumnSel
) )
1611 // Prevent copying in Flys that are anchored in the area
1612 if( pDoc
== &m_rDoc
&& bCheckPos
)
1614 // Correct the Start-/EndNode
1615 sal_uLong nStt
= pStt
->nNode
.GetIndex(),
1616 nEnd
= pEnd
->nNode
.GetIndex(),
1617 nDiff
= nEnd
- nStt
+1;
1618 SwNode
* pNd
= m_rDoc
.GetNodes()[ nStt
];
1619 if( pNd
->IsContentNode() && pStt
->nContent
.GetIndex() )
1624 if( (pNd
= m_rDoc
.GetNodes()[ nEnd
])->IsContentNode() &&
1625 static_cast<SwContentNode
*>(pNd
)->Len() != pEnd
->nContent
.GetIndex() )
1631 lcl_ChkFlyFly( pDoc
, nStt
, nEnd
, rPos
.nNode
.GetIndex() ) )
1637 SwPaM
* pRedlineRange
= nullptr;
1638 if( pDoc
->getIDocumentRedlineAccess().IsRedlineOn() ||
1639 (!pDoc
->getIDocumentRedlineAccess().IsIgnoreRedline() && !pDoc
->getIDocumentRedlineAccess().GetRedlineTable().empty() ) )
1640 pRedlineRange
= new SwPaM( rPos
);
1642 RedlineFlags eOld
= pDoc
->getIDocumentRedlineAccess().GetRedlineFlags();
1646 if( pDoc
!= &m_rDoc
)
1648 bRet
= CopyImpl( rPam
, rPos
, true, bCopyAll
, pRedlineRange
);
1650 else if( ! ( *pStt
<= rPos
&& rPos
< *pEnd
&&
1651 ( pStt
->nNode
!= pEnd
->nNode
||
1652 !pStt
->nNode
.GetNode().IsTextNode() )) )
1654 // Copy to a position outside of the area, or copy a single TextNode
1655 // Do an ordinary copy
1656 bRet
= CopyImpl( rPam
, rPos
, true, bCopyAll
, pRedlineRange
);
1660 // Copy the area in itself
1661 // Special case for handling an area with several nodes,
1662 // or a single node that is not a TextNode
1663 OSL_ENSURE( &m_rDoc
== pDoc
, " invalid copy branch!" );
1664 assert(!"mst: this is assumed to be dead code");
1665 pDoc
->getIDocumentRedlineAccess().SetRedlineFlags_intern(eOld
| RedlineFlags::Ignore
);
1667 // Then copy the area to the underlying document area
1668 // (with start/end nodes clamped) and move them to
1669 // the desired position.
1671 SwUndoCpyDoc
* pUndo
= nullptr;
1672 // Save the Undo area
1674 if (pDoc
->GetIDocumentUndoRedo().DoesUndo())
1676 pDoc
->GetIDocumentUndoRedo().ClearRedo();
1677 pUndo
= new SwUndoCpyDoc( aPam
);
1681 ::sw::UndoGuard
const undoGuard(pDoc
->GetIDocumentUndoRedo());
1682 SwStartNode
* pSttNd
= SwNodes::MakeEmptySection(
1683 SwNodeIndex( m_rDoc
.GetNodes().GetEndOfAutotext() ));
1684 aPam
.GetPoint()->nNode
= *pSttNd
->EndOfSectionNode();
1685 // copy without Frames
1686 pDoc
->GetDocumentContentOperationsManager().CopyImpl( rPam
, *aPam
.GetPoint(), false, bCopyAll
, nullptr );
1688 aPam
.GetPoint()->nNode
= pDoc
->GetNodes().GetEndOfAutotext();
1690 SwContentNode
* pNode
= SwNodes::GoPrevious( &aPam
.GetMark()->nNode
);
1691 pNode
->MakeEndIndex( &aPam
.GetMark()->nContent
);
1693 aPam
.GetPoint()->nNode
= *aPam
.GetNode().StartOfSectionNode();
1694 pNode
= pDoc
->GetNodes().GoNext( &aPam
.GetPoint()->nNode
);
1695 pNode
->MakeStartIndex( &aPam
.GetPoint()->nContent
);
1696 // move to desired position
1697 pDoc
->getIDocumentContentOperations().MoveRange( aPam
, rPos
, SwMoveFlags::DEFAULT
);
1699 pNode
= aPam
.GetContentNode();
1700 *aPam
.GetPoint() = rPos
; // Move the cursor for Undo
1701 aPam
.SetMark(); // also move the Mark
1702 aPam
.DeleteMark(); // But don't mark any area
1703 pDoc
->getIDocumentContentOperations().DeleteSection( pNode
); // Delete the area again
1706 // if Undo is enabled, store the insertion range
1707 if (pDoc
->GetIDocumentUndoRedo().DoesUndo())
1709 pUndo
->SetInsertRange( aPam
);
1710 pDoc
->GetIDocumentUndoRedo().AppendUndo(pUndo
);
1715 pRedlineRange
->SetMark();
1716 *pRedlineRange
->GetPoint() = *aPam
.GetPoint();
1717 *pRedlineRange
->GetMark() = *aPam
.GetMark();
1720 pDoc
->getIDocumentState().SetModified();
1724 pDoc
->getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld
);
1727 if( pDoc
->getIDocumentRedlineAccess().IsRedlineOn() )
1728 pDoc
->getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline( nsRedlineType_t::REDLINE_INSERT
, *pRedlineRange
), true);
1730 pDoc
->getIDocumentRedlineAccess().SplitRedline( *pRedlineRange
);
1731 delete pRedlineRange
;
1737 /// Delete a full Section of the NodeArray.
1738 /// The passed Node is located somewhere in the designated Section.
1739 void DocumentContentOperationsManager::DeleteSection( SwNode
*pNode
)
1741 assert(pNode
&& "Didn't pass a Node.");
1743 SwStartNode
* pSttNd
= pNode
->IsStartNode() ? static_cast<SwStartNode
*>(pNode
)
1744 : pNode
->StartOfSectionNode();
1745 SwNodeIndex
aSttIdx( *pSttNd
), aEndIdx( *pNode
->EndOfSectionNode() );
1747 // delete all Flys, Bookmarks, ...
1748 DelFlyInRange( aSttIdx
, aEndIdx
);
1749 m_rDoc
.getIDocumentRedlineAccess().DeleteRedline( *pSttNd
, true, USHRT_MAX
);
1750 DelBookmarks(aSttIdx
, aEndIdx
);
1753 // move all Cursor/StackCursor/UnoCursor out of the to-be-deleted area
1754 SwNodeIndex
aMvStt( aSttIdx
, 1 );
1755 SwDoc::CorrAbs( aMvStt
, aEndIdx
, SwPosition( aSttIdx
), true );
1758 m_rDoc
.GetNodes().DelNodes( aSttIdx
, aEndIdx
.GetIndex() - aSttIdx
.GetIndex() + 1 );
1761 void DocumentContentOperationsManager::DeleteRange( SwPaM
& rPam
)
1763 lcl_DoWithBreaks( *this, rPam
, &DocumentContentOperationsManager::DeleteRangeImpl
);
1766 bool DocumentContentOperationsManager::DelFullPara( SwPaM
& rPam
)
1768 const SwPosition
&rStt
= *rPam
.Start(), &rEnd
= *rPam
.End();
1769 const SwNode
* pNd
= &rStt
.nNode
.GetNode();
1770 sal_uInt32 nSectDiff
= pNd
->StartOfSectionNode()->EndOfSectionIndex() -
1771 pNd
->StartOfSectionIndex();
1772 sal_uInt32 nNodeDiff
= rEnd
.nNode
.GetIndex() - rStt
.nNode
.GetIndex();
1774 if ( nSectDiff
-2 <= nNodeDiff
|| m_rDoc
.getIDocumentRedlineAccess().IsRedlineOn() ||
1775 /* #i9185# Prevent getting the node after the end node (see below) */
1776 rEnd
.nNode
.GetIndex() + 1 == m_rDoc
.GetNodes().Count() )
1781 // Move hard page brakes to the following Node.
1782 bool bSavePageBreak
= false, bSavePageDesc
= false;
1784 /* #i9185# This whould lead to a segmentation fault if not caught above. */
1785 sal_uLong nNextNd
= rEnd
.nNode
.GetIndex() + 1;
1786 SwTableNode
*const pTableNd
= m_rDoc
.GetNodes()[ nNextNd
]->GetTableNode();
1788 if( pTableNd
&& pNd
->IsContentNode() )
1790 SwFrameFormat
* pTableFormat
= pTableNd
->GetTable().GetFrameFormat();
1793 const SfxPoolItem
*pItem
;
1794 const SfxItemSet
* pSet
= static_cast<const SwContentNode
*>(pNd
)->GetpSwAttrSet();
1795 if( pSet
&& SfxItemState::SET
== pSet
->GetItemState( RES_PAGEDESC
,
1798 pTableFormat
->SetFormatAttr( *pItem
);
1799 bSavePageDesc
= true;
1802 if( pSet
&& SfxItemState::SET
== pSet
->GetItemState( RES_BREAK
,
1805 pTableFormat
->SetFormatAttr( *pItem
);
1806 bSavePageBreak
= true;
1811 bool const bDoesUndo
= m_rDoc
.GetIDocumentUndoRedo().DoesUndo();
1814 if( !rPam
.HasMark() )
1816 else if( rPam
.GetPoint() == &rStt
)
1818 rPam
.GetPoint()->nNode
++;
1820 SwContentNode
*pTmpNode
= rPam
.GetPoint()->nNode
.GetNode().GetContentNode();
1821 rPam
.GetPoint()->nContent
.Assign( pTmpNode
, 0 );
1822 bool bGoNext
= (nullptr == pTmpNode
);
1823 pTmpNode
= rPam
.GetMark()->nNode
.GetNode().GetContentNode();
1824 rPam
.GetMark()->nContent
.Assign( pTmpNode
, 0 );
1826 m_rDoc
.GetIDocumentUndoRedo().ClearRedo();
1828 SwPaM
aDelPam( *rPam
.GetMark(), *rPam
.GetPoint() );
1830 SwPosition
aTmpPos( *aDelPam
.GetPoint() );
1833 pTmpNode
= m_rDoc
.GetNodes().GoNext( &aTmpPos
.nNode
);
1834 aTmpPos
.nContent
.Assign( pTmpNode
, 0 );
1836 ::PaMCorrAbs( aDelPam
, aTmpPos
);
1839 SwUndoDelete
* pUndo
= new SwUndoDelete( aDelPam
, true );
1841 *rPam
.GetPoint() = *aDelPam
.GetPoint();
1842 pUndo
->SetPgBrkFlags( bSavePageBreak
, bSavePageDesc
);
1843 m_rDoc
.GetIDocumentUndoRedo().AppendUndo(pUndo
);
1848 SwNodeRange
aRg( rStt
.nNode
, rEnd
.nNode
);
1849 rPam
.Normalize(false);
1851 // Try to move past the End
1852 if( !rPam
.Move( fnMoveForward
, GoInNode
) )
1854 // Fair enough, at the Beginning then
1856 if( !rPam
.Move( fnMoveBackward
, GoInNode
))
1858 SAL_WARN("sw.core", "DelFullPara: no more Nodes");
1862 // move bookmarks, redlines etc.
1863 if (aRg
.aStart
== aRg
.aEnd
) // only first CorrAbs variant handles this
1865 m_rDoc
.CorrAbs( aRg
.aStart
, *rPam
.GetPoint(), 0, true );
1869 SwDoc::CorrAbs( aRg
.aStart
, aRg
.aEnd
, *rPam
.GetPoint(), true );
1872 // What's with Flys?
1874 // If there are FlyFrames left, delete these too
1875 for( size_t n
= 0; n
< m_rDoc
.GetSpzFrameFormats()->size(); ++n
)
1877 SwFrameFormat
* pFly
= (*m_rDoc
.GetSpzFrameFormats())[n
];
1878 const SwFormatAnchor
* pAnchor
= &pFly
->GetAnchor();
1879 SwPosition
const*const pAPos
= pAnchor
->GetContentAnchor();
1881 ((RndStdIds::FLY_AT_PARA
== pAnchor
->GetAnchorId()) ||
1882 (RndStdIds::FLY_AT_CHAR
== pAnchor
->GetAnchorId())) &&
1883 aRg
.aStart
<= pAPos
->nNode
&& pAPos
->nNode
<= aRg
.aEnd
)
1885 m_rDoc
.getIDocumentLayoutAccess().DelLayoutFormat( pFly
);
1892 m_rDoc
.GetNodes().Delete( aRg
.aStart
, nNodeDiff
+1 );
1894 m_rDoc
.getIDocumentState().SetModified();
1899 // #i100466# Add handling of new optional parameter <bForceJoinNext>
1900 bool DocumentContentOperationsManager::DeleteAndJoin( SwPaM
& rPam
,
1901 const bool bForceJoinNext
)
1903 if ( lcl_StrLenOverflow( rPam
) )
1906 return lcl_DoWithBreaks( *this, rPam
, (m_rDoc
.getIDocumentRedlineAccess().IsRedlineOn())
1907 ? &DocumentContentOperationsManager::DeleteAndJoinWithRedlineImpl
1908 : &DocumentContentOperationsManager::DeleteAndJoinImpl
,
1912 // It seems that this is mostly used by SwDoc internals; the only
1913 // way to call this from the outside seems to be the special case in
1914 // SwDoc::CopyRange (but I have not managed to actually hit that case).
1915 bool DocumentContentOperationsManager::MoveRange( SwPaM
& rPaM
, SwPosition
& rPos
, SwMoveFlags eMvFlags
)
1917 // nothing moved: return
1918 const SwPosition
*pStt
= rPaM
.Start(), *pEnd
= rPaM
.End();
1919 if( !rPaM
.HasMark() || *pStt
>= *pEnd
|| (*pStt
<= rPos
&& rPos
< *pEnd
))
1922 // Save the paragraph anchored Flys, so that they can be moved.
1923 SaveFlyArr aSaveFlyArr
;
1924 SaveFlyInRange( rPaM
, rPos
.nNode
, aSaveFlyArr
, bool( SwMoveFlags::ALLFLYS
& eMvFlags
) );
1926 // save redlines (if DOC_MOVEREDLINES is used)
1927 SaveRedlines_t aSaveRedl
;
1928 if( SwMoveFlags::REDLINES
& eMvFlags
&& !m_rDoc
.getIDocumentRedlineAccess().GetRedlineTable().empty() )
1930 lcl_SaveRedlines( rPaM
, aSaveRedl
);
1932 // #i17764# unfortunately, code below relies on undos being
1933 // in a particular order, and presence of bookmarks
1934 // will change this order. Hence, we delete bookmarks
1935 // here without undo.
1936 ::sw::UndoGuard
const undoGuard(m_rDoc
.GetIDocumentUndoRedo());
1945 bool bUpdateFootnote
= false;
1946 SwFootnoteIdxs aTmpFntIdx
;
1948 SwUndoMove
* pUndoMove
= nullptr;
1949 if (m_rDoc
.GetIDocumentUndoRedo().DoesUndo())
1951 m_rDoc
.GetIDocumentUndoRedo().ClearRedo();
1952 pUndoMove
= new SwUndoMove( rPaM
, rPos
);
1953 pUndoMove
->SetMoveRedlines( eMvFlags
== SwMoveFlags::REDLINES
);
1957 bUpdateFootnote
= lcl_SaveFootnote( pStt
->nNode
, pEnd
->nNode
, rPos
.nNode
,
1958 m_rDoc
.GetFootnoteIdxs(), aTmpFntIdx
,
1959 &pStt
->nContent
, &pEnd
->nContent
);
1962 bool bSplit
= false;
1963 SwPaM
aSavePam( rPos
, rPos
);
1965 // Move the SPoint to the beginning of the range
1966 if( rPaM
.GetPoint() == pEnd
)
1969 // If there is a TextNode before and after the Move, create a JoinNext in the EditShell.
1970 SwTextNode
* pSrcNd
= rPaM
.GetPoint()->nNode
.GetNode().GetTextNode();
1971 bool bCorrSavePam
= pSrcNd
&& pStt
->nNode
!= pEnd
->nNode
;
1973 // If one ore more TextNodes are moved, SwNodes::Move will do a SplitNode.
1974 // However, this does not update the cursor. So we create a TextNode to keep
1975 // updating the indices. After the Move the Node is optionally deleted.
1976 SwTextNode
* pTNd
= rPos
.nNode
.GetNode().GetTextNode();
1977 if( pTNd
&& rPaM
.GetPoint()->nNode
!= rPaM
.GetMark()->nNode
&&
1978 ( rPos
.nContent
.GetIndex() || ( pTNd
->Len() && bCorrSavePam
)) )
1981 const sal_Int32 nMkContent
= rPaM
.GetMark()->nContent
.GetIndex();
1983 const std::shared_ptr
<sw::mark::ContentIdxStore
> pContentStore(sw::mark::ContentIdxStore::Create());
1984 pContentStore
->Save( &m_rDoc
, rPos
.nNode
.GetIndex(), rPos
.nContent
.GetIndex(), true );
1986 SwTextNode
* pOrigNode
= pTNd
;
1987 assert(*aSavePam
.GetPoint() == *aSavePam
.GetMark() &&
1988 *aSavePam
.GetPoint() == rPos
);
1989 assert(aSavePam
.GetPoint()->nContent
.GetIdxReg() == pOrigNode
);
1990 assert(aSavePam
.GetPoint()->nNode
== rPos
.nNode
.GetIndex());
1991 assert(rPos
.nNode
.GetIndex() == pOrigNode
->GetIndex());
1993 pTNd
= pTNd
->SplitContentNode( rPos
)->GetTextNode();
1995 //A new node was inserted before the orig pTNd and the content up to
1996 //rPos moved into it. The old node is returned with the remainder
1997 //of the content in it.
1999 //aSavePam was created with rPos, it continues to point to the
2000 //old node, but with the *original* content index into the node.
2001 //Seeing as all the orignode content before that index has
2002 //been removed, the new index into the original node should now be set
2003 //to 0 and the content index of rPos should also be adapted to the
2005 assert(*aSavePam
.GetPoint() == *aSavePam
.GetMark() &&
2006 *aSavePam
.GetPoint() == rPos
);
2007 assert(aSavePam
.GetPoint()->nContent
.GetIdxReg() == pOrigNode
);
2008 assert(aSavePam
.GetPoint()->nNode
== rPos
.nNode
.GetIndex());
2009 assert(rPos
.nNode
.GetIndex() == pOrigNode
->GetIndex());
2010 aSavePam
.GetPoint()->nContent
.Assign(pOrigNode
, 0);
2011 rPos
= *aSavePam
.GetMark() = *aSavePam
.GetPoint();
2013 if( !pContentStore
->Empty() )
2014 pContentStore
->Restore( &m_rDoc
, rPos
.nNode
.GetIndex()-1, 0, true );
2017 if( rPos
.nNode
== rPaM
.GetMark()->nNode
)
2019 rPaM
.GetMark()->nNode
= rPos
.nNode
.GetIndex()-1;
2020 rPaM
.GetMark()->nContent
.Assign( pTNd
, nMkContent
);
2024 // Put back the Pam by one "content"; so that it's always outside of
2025 // the manipulated range.
2026 // tdf#99692 don't Move() back if that would end up in another node
2027 // because moving backward is not necessarily the inverse of forward then.
2028 // (but do Move() back if we have split the node)
2029 const bool bNullContent
= !bSplit
&& aSavePam
.GetPoint()->nContent
== 0;
2032 aSavePam
.GetPoint()->nNode
--;
2033 aSavePam
.GetPoint()->nContent
.Assign(aSavePam
.GetContentNode(), 0);
2037 bool const success(aSavePam
.Move(fnMoveBackward
, GoInContent
));
2042 // Copy all Bookmarks that are within the Move range into an array,
2043 // that saves the position as an offset.
2044 std::vector
< ::sw::mark::SaveBookmark
> aSaveBkmks
;
2052 // If there is no range anymore due to the above deletions (e.g. the
2053 // footnotes got deleted), it's still a valid Move!
2054 if( *rPaM
.GetPoint() != *rPaM
.GetMark() )
2056 // now do the actual move
2057 m_rDoc
.GetNodes().MoveRange( rPaM
, rPos
, m_rDoc
.GetNodes() );
2059 // after a MoveRange() the Mark is deleted
2060 if ( rPaM
.HasMark() ) // => no Move occurred!
2069 OSL_ENSURE( *aSavePam
.GetMark() == rPos
||
2070 ( aSavePam
.GetMark()->nNode
.GetNode().GetContentNode() == nullptr ),
2071 "PaM was not moved. Aren't there ContentNodes at the beginning/end?" );
2072 *aSavePam
.GetMark() = rPos
;
2074 rPaM
.SetMark(); // create a Sel. around the new range
2075 pTNd
= aSavePam
.GetNode().GetTextNode();
2076 if (m_rDoc
.GetIDocumentUndoRedo().DoesUndo())
2078 assert(!"mst: this is assumed to be dead code");
2080 // correct the SavePam's Content first
2083 aSavePam
.GetPoint()->nContent
= 0;
2086 // The method SwEditShell::Move() merges the TextNode after the Move,
2087 // where the rPaM is located.
2088 // If the Content was moved to the back and the SavePam's SPoint is
2089 // in the next Node, we have to deal with this when saving the Undo object!
2090 SwTextNode
* pPamTextNd
= nullptr;
2092 // Is passed to SwUndoMove, which happens when subsequently calling Undo JoinNext.
2093 // If it's not possible to call Undo JoinNext here.
2094 bool bJoin
= bSplit
&& pTNd
;
2097 pPamTextNd
= rPaM
.GetNode().GetTextNode();
2098 bCorrSavePam
= (pPamTextNd
!= nullptr)
2099 && pPamTextNd
->CanJoinNext()
2100 && (*rPaM
.GetPoint() <= *aSavePam
.GetPoint());
2103 // Do two Nodes have to be joined at the SavePam?
2104 if( bJoin
&& pTNd
->CanJoinNext() )
2107 // No temporary Index when using &&.
2108 // We probably only want to compare the indices.
2109 if( bCorrSavePam
&& rPaM
.GetPoint()->nNode
.GetIndex()+1 ==
2110 aSavePam
.GetPoint()->nNode
.GetIndex() )
2112 aSavePam
.GetPoint()->nContent
+= pPamTextNd
->Len();
2116 else if ( !aSavePam
.Move( fnMoveForward
, GoInContent
) )
2118 aSavePam
.GetPoint()->nNode
++;
2121 // The newly inserted range is now inbetween SPoint and GetMark.
2122 pUndoMove
->SetDestRange( aSavePam
, *rPaM
.GetPoint(),
2123 bJoin
, bCorrSavePam
);
2124 m_rDoc
.GetIDocumentUndoRedo().AppendUndo( pUndoMove
);
2128 bool bRemove
= true;
2129 // Do two Nodes have to be joined at the SavePam?
2130 if( bSplit
&& pTNd
)
2132 if( pTNd
->CanJoinNext())
2134 // Always join next, because <pTNd> has to stay as it is.
2135 // A join previous from its next would more or less delete <pTNd>
2142 aSavePam
.GetPoint()->nNode
++;
2143 aSavePam
.GetPoint()->nContent
.Assign( aSavePam
.GetContentNode(), 0 );
2145 else if( bRemove
) // No move forward after joining with next paragraph
2147 aSavePam
.Move( fnMoveForward
, GoInContent
);
2151 // Insert the Bookmarks back into the Document.
2152 *rPaM
.GetMark() = *aSavePam
.Start();
2154 std::vector
< ::sw::mark::SaveBookmark
>::iterator pBkmk
= aSaveBkmks
.begin();
2155 pBkmk
!= aSaveBkmks
.end();
2159 rPaM
.GetMark()->nNode
,
2160 &rPaM
.GetMark()->nContent
);
2161 *rPaM
.GetPoint() = *aSavePam
.End();
2163 // Move the Flys to the new position.
2164 RestFlyInRange( aSaveFlyArr
, rPaM
.Start()->nNode
, &(rPos
.nNode
) );
2166 // restore redlines (if DOC_MOVEREDLINES is used)
2167 if( !aSaveRedl
.empty() )
2169 lcl_RestoreRedlines( &m_rDoc
, *aSavePam
.Start(), aSaveRedl
);
2172 if( bUpdateFootnote
)
2174 if( !aTmpFntIdx
.empty() )
2176 m_rDoc
.GetFootnoteIdxs().insert( aTmpFntIdx
);
2180 m_rDoc
.GetFootnoteIdxs().UpdateAllFootnote();
2183 m_rDoc
.getIDocumentState().SetModified();
2187 bool DocumentContentOperationsManager::MoveNodeRange( SwNodeRange
& rRange
, SwNodeIndex
& rPos
,
2188 SwMoveFlags eMvFlags
)
2190 // Moves all Nodes to the new position.
2191 // Bookmarks are moved too (currently without Undo support).
2193 // If footnotes are being moved to the special section, remove them now.
2195 // Or else delete the Frames for all footnotes that are being moved
2196 // and have it rebuild after the Move (footnotes can change pages).
2197 // Additionally we have to correct the FootnoteIdx array's sorting.
2198 bool bUpdateFootnote
= false;
2199 SwFootnoteIdxs aTmpFntIdx
;
2201 SwUndoMove
* pUndo
= nullptr;
2202 if ((SwMoveFlags::CREATEUNDOOBJ
& eMvFlags
) && m_rDoc
.GetIDocumentUndoRedo().DoesUndo())
2204 pUndo
= new SwUndoMove( &m_rDoc
, rRange
, rPos
);
2208 bUpdateFootnote
= lcl_SaveFootnote( rRange
.aStart
, rRange
.aEnd
, rPos
,
2209 m_rDoc
.GetFootnoteIdxs(), aTmpFntIdx
);
2212 SaveRedlines_t aSaveRedl
;
2213 std::vector
<SwRangeRedline
*> aSavRedlInsPosArr
;
2214 if( SwMoveFlags::REDLINES
& eMvFlags
&& !m_rDoc
.getIDocumentRedlineAccess().GetRedlineTable().empty() )
2216 lcl_SaveRedlines( rRange
, aSaveRedl
);
2218 // Find all RedLines that end at the InsPos.
2219 // These have to be moved back to the "old" position after the Move.
2220 SwRedlineTable::size_type nRedlPos
= m_rDoc
.getIDocumentRedlineAccess().GetRedlinePos( rPos
.GetNode(), USHRT_MAX
);
2221 if( SwRedlineTable::npos
!= nRedlPos
)
2223 const SwPosition
*pRStt
, *pREnd
;
2225 SwRangeRedline
* pTmp
= m_rDoc
.getIDocumentRedlineAccess().GetRedlineTable()[ nRedlPos
];
2226 pRStt
= pTmp
->Start();
2227 pREnd
= pTmp
->End();
2228 if( pREnd
->nNode
== rPos
&& pRStt
->nNode
< rPos
)
2230 aSavRedlInsPosArr
.push_back( pTmp
);
2232 } while( pRStt
->nNode
< rPos
&& ++nRedlPos
< m_rDoc
.getIDocumentRedlineAccess().GetRedlineTable().size());
2236 // Copy all Bookmarks that are within the Move range into an array
2237 // that stores all references to positions as an offset.
2238 // The final mapping happens after the Move.
2239 std::vector
< ::sw::mark::SaveBookmark
> aSaveBkmks
;
2240 DelBookmarks(rRange
.aStart
, rRange
.aEnd
, &aSaveBkmks
);
2242 // Save the paragraph-bound Flys, so that they can be moved.
2243 SaveFlyArr aSaveFlyArr
;
2244 if( !m_rDoc
.GetSpzFrameFormats()->empty() )
2245 SaveFlyInRange( rRange
, aSaveFlyArr
);
2247 // Set it to before the Position, so that it cannot be moved further.
2248 SwNodeIndex
aIdx( rPos
, -1 );
2250 SwNodeIndex
* pSaveInsPos
= nullptr;
2252 pSaveInsPos
= new SwNodeIndex( rRange
.aStart
, -1 );
2255 bool bNoDelFrames
= bool(SwMoveFlags::NO_DELFRMS
& eMvFlags
);
2256 if( m_rDoc
.GetNodes().MoveNodes( rRange
, m_rDoc
.GetNodes(), rPos
, !bNoDelFrames
) )
2258 ++aIdx
; // again back to old position
2264 aIdx
= rRange
.aStart
;
2269 // move the Flys to the new position
2270 if( !aSaveFlyArr
.empty() )
2271 RestFlyInRange( aSaveFlyArr
, aIdx
, nullptr );
2273 // Add the Bookmarks back to the Document
2275 std::vector
< ::sw::mark::SaveBookmark
>::iterator pBkmk
= aSaveBkmks
.begin();
2276 pBkmk
!= aSaveBkmks
.end();
2278 pBkmk
->SetInDoc(&m_rDoc
, aIdx
);
2280 if( !aSavRedlInsPosArr
.empty() )
2282 SwNode
* pNewNd
= &aIdx
.GetNode();
2283 for(SwRangeRedline
* pTmp
: aSavRedlInsPosArr
)
2285 if( m_rDoc
.getIDocumentRedlineAccess().GetRedlineTable().Contains( pTmp
) )
2287 SwPosition
* pEnd
= pTmp
->End();
2289 pEnd
->nContent
.Assign( pNewNd
->GetContentNode(), 0 );
2294 if( !aSaveRedl
.empty() )
2295 lcl_RestoreRedlines( &m_rDoc
, aIdx
.GetIndex(), aSaveRedl
);
2299 pUndo
->SetDestRange( aIdx
, rPos
, *pSaveInsPos
);
2300 m_rDoc
.GetIDocumentUndoRedo().AppendUndo(pUndo
);
2305 if( bUpdateFootnote
)
2307 if( !aTmpFntIdx
.empty() )
2309 m_rDoc
.GetFootnoteIdxs().insert( aTmpFntIdx
);
2313 m_rDoc
.GetFootnoteIdxs().UpdateAllFootnote();
2316 m_rDoc
.getIDocumentState().SetModified();
2320 bool DocumentContentOperationsManager::MoveAndJoin( SwPaM
& rPaM
, SwPosition
& rPos
)
2322 SwNodeIndex
aIdx( rPaM
.Start()->nNode
);
2323 bool bJoinText
= aIdx
.GetNode().IsTextNode();
2324 bool bOneNode
= rPaM
.GetPoint()->nNode
== rPaM
.GetMark()->nNode
;
2325 aIdx
--; // in front of the move area!
2327 bool bRet
= MoveRange( rPaM
, rPos
, SwMoveFlags::DEFAULT
);
2328 if( bRet
&& !bOneNode
)
2332 SwTextNode
* pTextNd
= aIdx
.GetNode().GetTextNode();
2333 SwNodeIndex
aNxtIdx( aIdx
);
2334 if( pTextNd
&& pTextNd
->CanJoinNext( &aNxtIdx
) )
2336 { // Block so SwIndex into node is deleted before Join
2337 m_rDoc
.CorrRel( aNxtIdx
, SwPosition( aIdx
, SwIndex(pTextNd
,
2338 pTextNd
->GetText().getLength()) ), 0, true );
2340 pTextNd
->JoinNext();
2346 bool DocumentContentOperationsManager::Overwrite( const SwPaM
&rRg
, const OUString
&rStr
)
2348 SwPosition
& rPt
= *const_cast<SwPosition
*>(rRg
.GetPoint());
2349 if( m_rDoc
.GetAutoCorrExceptWord() ) // Add to AutoCorrect
2351 if( 1 == rStr
.getLength() )
2352 m_rDoc
.GetAutoCorrExceptWord()->CheckChar( rPt
, rStr
[ 0 ] );
2353 m_rDoc
.DeleteAutoCorrExceptWord();
2356 SwTextNode
*pNode
= rPt
.nNode
.GetNode().GetTextNode();
2357 if (!pNode
|| rStr
.getLength() > pNode
->GetSpaceLeft()) // worst case: no erase
2362 if (m_rDoc
.GetIDocumentUndoRedo().DoesUndo())
2364 m_rDoc
.GetIDocumentUndoRedo().ClearRedo(); // AppendUndo not always called
2367 const size_t nOldAttrCnt
= pNode
->GetpSwpHints()
2368 ? pNode
->GetpSwpHints()->Count() : 0;
2369 SwDataChanged
aTmp( rRg
);
2370 SwIndex
& rIdx
= rPt
.nContent
;
2371 sal_Int32 nStart
= 0;
2373 bool bOldExpFlg
= pNode
->IsIgnoreDontExpand();
2374 pNode
->SetIgnoreDontExpand( true );
2376 for( sal_Int32 nCnt
= 0; nCnt
< rStr
.getLength(); ++nCnt
)
2378 // start behind the characters (to fix the attributes!)
2379 nStart
= rIdx
.GetIndex();
2380 if (nStart
< pNode
->GetText().getLength())
2382 lcl_SkipAttr( pNode
, rIdx
, nStart
);
2384 sal_Unicode c
= rStr
[ nCnt
];
2385 if (m_rDoc
.GetIDocumentUndoRedo().DoesUndo())
2387 bool bMerged(false);
2388 if (m_rDoc
.GetIDocumentUndoRedo().DoesGroupUndo())
2390 SwUndo
*const pUndo
= m_rDoc
.GetUndoManager().GetLastUndo();
2391 SwUndoOverwrite
*const pUndoOW(
2392 dynamic_cast<SwUndoOverwrite
*>(pUndo
) );
2395 // if CanGrouping() returns true it's already merged
2396 bMerged
= pUndoOW
->CanGrouping( &m_rDoc
, rPt
, c
);
2401 SwUndo
*const pUndoOW( new SwUndoOverwrite(&m_rDoc
, rPt
, c
) );
2402 m_rDoc
.GetIDocumentUndoRedo().AppendUndo(pUndoOW
);
2407 // start behind the characters (to fix the attributes!)
2408 if (nStart
< pNode
->GetText().getLength())
2410 pNode
->InsertText( OUString(c
), rIdx
, SwInsertFlags::EMPTYEXPAND
);
2411 if( nStart
+1 < rIdx
.GetIndex() )
2414 pNode
->EraseText( rIdx
, 1 );
2419 pNode
->SetIgnoreDontExpand( bOldExpFlg
);
2421 const size_t nNewAttrCnt
= pNode
->GetpSwpHints()
2422 ? pNode
->GetpSwpHints()->Count() : 0;
2423 if( nOldAttrCnt
!= nNewAttrCnt
)
2425 SwUpdateAttr
aHint(0,0,0);
2426 pNode
->ModifyBroadcast(nullptr, &aHint
);
2429 if (!m_rDoc
.GetIDocumentUndoRedo().DoesUndo() &&
2430 !m_rDoc
.getIDocumentRedlineAccess().IsIgnoreRedline() && !m_rDoc
.getIDocumentRedlineAccess().GetRedlineTable().empty())
2432 SwPaM
aPam( rPt
.nNode
, nStart
, rPt
.nNode
, rPt
.nContent
.GetIndex() );
2433 m_rDoc
.getIDocumentRedlineAccess().DeleteRedline( aPam
, true, USHRT_MAX
);
2435 else if( m_rDoc
.getIDocumentRedlineAccess().IsRedlineOn() )
2437 // FIXME: this redline is WRONG: there is no DELETE, and the skipped
2438 // characters are also included in aPam
2439 SwPaM
aPam( rPt
.nNode
, nStart
, rPt
.nNode
, rPt
.nContent
.GetIndex() );
2440 m_rDoc
.getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline( nsRedlineType_t::REDLINE_INSERT
, aPam
), true);
2443 m_rDoc
.getIDocumentState().SetModified();
2447 bool DocumentContentOperationsManager::InsertString( const SwPaM
&rRg
, const OUString
&rStr
,
2448 const SwInsertFlags nInsertMode
)
2450 // fetching DoesUndo is surprisingly expensive
2451 bool bDoesUndo
= m_rDoc
.GetIDocumentUndoRedo().DoesUndo();
2453 m_rDoc
.GetIDocumentUndoRedo().ClearRedo(); // AppendUndo not always called!
2455 const SwPosition
& rPos
= *rRg
.GetPoint();
2457 if( m_rDoc
.GetAutoCorrExceptWord() ) // add to auto correction
2459 if( 1 == rStr
.getLength() && m_rDoc
.GetAutoCorrExceptWord()->IsDeleted() )
2461 m_rDoc
.GetAutoCorrExceptWord()->CheckChar( rPos
, rStr
[ 0 ] );
2463 m_rDoc
.DeleteAutoCorrExceptWord();
2466 SwTextNode
*const pNode
= rPos
.nNode
.GetNode().GetTextNode();
2470 SwDataChanged
aTmp( rRg
);
2472 if (!bDoesUndo
|| !m_rDoc
.GetIDocumentUndoRedo().DoesGroupUndo())
2474 OUString
const ins(pNode
->InsertText(rStr
, rPos
.nContent
, nInsertMode
));
2477 SwUndoInsert
* const pUndo( new SwUndoInsert(rPos
.nNode
,
2478 rPos
.nContent
.GetIndex(), ins
.getLength(), nInsertMode
));
2479 m_rDoc
.GetIDocumentUndoRedo().AppendUndo(pUndo
);
2483 { // if Undo and grouping is enabled, everything changes!
2484 SwUndoInsert
* pUndo
= nullptr;
2486 // don't group the start if hints at the start should be expanded
2487 if (!(nInsertMode
& SwInsertFlags::FORCEHINTEXPAND
))
2489 SwUndo
*const pLastUndo
= m_rDoc
.GetUndoManager().GetLastUndo();
2490 SwUndoInsert
*const pUndoInsert(
2491 dynamic_cast<SwUndoInsert
*>(pLastUndo
) );
2492 if (pUndoInsert
&& pUndoInsert
->CanGrouping(rPos
))
2494 pUndo
= pUndoInsert
;
2498 CharClass
const& rCC
= GetAppCharClass();
2499 sal_Int32 nInsPos
= rPos
.nContent
.GetIndex();
2503 pUndo
= new SwUndoInsert( rPos
.nNode
, nInsPos
, 0, nInsertMode
,
2504 !rCC
.isLetterNumeric( rStr
, 0 ) );
2505 m_rDoc
.GetIDocumentUndoRedo().AppendUndo( pUndo
);
2508 OUString
const ins(pNode
->InsertText(rStr
, rPos
.nContent
, nInsertMode
));
2510 for (sal_Int32 i
= 0; i
< ins
.getLength(); ++i
)
2513 // if CanGrouping() returns true, everything has already been done
2514 if (!pUndo
->CanGrouping(ins
[i
]))
2516 pUndo
= new SwUndoInsert(rPos
.nNode
, nInsPos
, 1, nInsertMode
,
2517 !rCC
.isLetterNumeric(ins
, i
));
2518 m_rDoc
.GetIDocumentUndoRedo().AppendUndo( pUndo
);
2523 // To-Do - add 'SwExtraRedlineTable' also ?
2524 if( m_rDoc
.getIDocumentRedlineAccess().IsRedlineOn() || (!m_rDoc
.getIDocumentRedlineAccess().IsIgnoreRedline() && !m_rDoc
.getIDocumentRedlineAccess().GetRedlineTable().empty() ))
2526 SwPaM
aPam( rPos
.nNode
, aTmp
.GetContent(),
2527 rPos
.nNode
, rPos
.nContent
.GetIndex());
2528 if( m_rDoc
.getIDocumentRedlineAccess().IsRedlineOn() )
2530 m_rDoc
.getIDocumentRedlineAccess().AppendRedline(
2531 new SwRangeRedline( nsRedlineType_t::REDLINE_INSERT
, aPam
), true);
2535 m_rDoc
.getIDocumentRedlineAccess().SplitRedline( aPam
);
2539 m_rDoc
.getIDocumentState().SetModified();
2543 void DocumentContentOperationsManager::TransliterateText(
2545 utl::TransliterationWrapper
& rTrans
)
2547 SwUndoTransliterate
*const pUndo
= (m_rDoc
.GetIDocumentUndoRedo().DoesUndo())
2548 ? new SwUndoTransliterate( rPaM
, rTrans
)
2551 const SwPosition
* pStt
= rPaM
.Start(),
2552 * pEnd
= rPaM
.End();
2553 sal_uLong nSttNd
= pStt
->nNode
.GetIndex(),
2554 nEndNd
= pEnd
->nNode
.GetIndex();
2555 sal_Int32 nSttCnt
= pStt
->nContent
.GetIndex();
2556 sal_Int32 nEndCnt
= pEnd
->nContent
.GetIndex();
2558 SwTextNode
* pTNd
= pStt
->nNode
.GetNode().GetTextNode();
2559 if( pStt
== pEnd
&& pTNd
) // no selection?
2561 // set current word as 'area of effect'
2563 assert(g_pBreakIt
&& g_pBreakIt
->GetBreakIter().is());
2564 Boundary aBndry
= g_pBreakIt
->GetBreakIter()->getWordBoundary(
2565 pTNd
->GetText(), nSttCnt
,
2566 g_pBreakIt
->GetLocale( pTNd
->GetLang( nSttCnt
) ),
2567 WordType::ANY_WORD
/*ANYWORD_IGNOREWHITESPACES*/,
2570 if( aBndry
.startPos
< nSttCnt
&& nSttCnt
< aBndry
.endPos
)
2572 nSttCnt
= aBndry
.startPos
;
2573 nEndCnt
= aBndry
.endPos
;
2577 if( nSttNd
!= nEndNd
) // is more than one text node involved?
2579 // iterate over all effected text nodes, the first and the last one
2580 // may be incomplete because the selection starts and/or ends there
2582 SwNodeIndex
aIdx( pStt
->nNode
);
2587 pTNd
->TransliterateText(
2588 rTrans
, nSttCnt
, pTNd
->GetText().getLength(), pUndo
);
2591 for( ; aIdx
.GetIndex() < nEndNd
; ++aIdx
)
2593 pTNd
= aIdx
.GetNode().GetTextNode();
2596 pTNd
->TransliterateText(
2597 rTrans
, 0, pTNd
->GetText().getLength(), pUndo
);
2601 if( nEndCnt
&& nullptr != ( pTNd
= pEnd
->nNode
.GetNode().GetTextNode() ))
2602 pTNd
->TransliterateText( rTrans
, 0, nEndCnt
, pUndo
);
2604 else if( pTNd
&& nSttCnt
< nEndCnt
)
2605 pTNd
->TransliterateText( rTrans
, nSttCnt
, nEndCnt
, pUndo
);
2609 if( pUndo
->HasData() )
2611 m_rDoc
.GetIDocumentUndoRedo().AppendUndo(pUndo
);
2616 m_rDoc
.getIDocumentState().SetModified();
2619 SwFlyFrameFormat
* DocumentContentOperationsManager::InsertGraphic(
2621 const OUString
& rGrfName
,
2622 const OUString
& rFltName
,
2623 const Graphic
* pGraphic
,
2624 const SfxItemSet
* pFlyAttrSet
,
2625 const SfxItemSet
* pGrfAttrSet
,
2626 SwFrameFormat
* pFrameFormat
)
2629 pFrameFormat
= m_rDoc
.getIDocumentStylePoolAccess().GetFrameFormatFromPool( RES_POOLFRM_GRAPHIC
);
2630 SwGrfNode
* pSwGrfNode
= SwNodes::MakeGrfNode(
2631 SwNodeIndex( m_rDoc
.GetNodes().GetEndOfAutotext() ),
2632 rGrfName
, rFltName
, pGraphic
,
2633 m_rDoc
.GetDfltGrfFormatColl() );
2634 SwFlyFrameFormat
* pSwFlyFrameFormat
= InsNoTextNode( *rRg
.GetPoint(), pSwGrfNode
,
2635 pFlyAttrSet
, pGrfAttrSet
, pFrameFormat
);
2636 return pSwFlyFrameFormat
;
2639 SwFlyFrameFormat
* DocumentContentOperationsManager::InsertGraphicObject(
2640 const SwPaM
&rRg
, const GraphicObject
& rGrfObj
,
2641 const SfxItemSet
* pFlyAttrSet
,
2642 const SfxItemSet
* pGrfAttrSet
,
2643 SwFrameFormat
* pFrameFormat
)
2646 pFrameFormat
= m_rDoc
.getIDocumentStylePoolAccess().GetFrameFormatFromPool( RES_POOLFRM_GRAPHIC
);
2647 SwGrfNode
* pSwGrfNode
= SwNodes::MakeGrfNode(
2648 SwNodeIndex( m_rDoc
.GetNodes().GetEndOfAutotext() ),
2649 rGrfObj
, m_rDoc
.GetDfltGrfFormatColl() );
2650 SwFlyFrameFormat
* pSwFlyFrameFormat
= InsNoTextNode( *rRg
.GetPoint(), pSwGrfNode
,
2651 pFlyAttrSet
, pGrfAttrSet
, pFrameFormat
);
2652 return pSwFlyFrameFormat
;
2655 SwFlyFrameFormat
* DocumentContentOperationsManager::InsertEmbObject(
2656 const SwPaM
&rRg
, const svt::EmbeddedObjectRef
& xObj
,
2657 const SfxItemSet
* pFlyAttrSet
)
2659 sal_uInt16 nId
= RES_POOLFRM_OLE
;
2662 SvGlobalName
aClassName( xObj
->getClassID() );
2663 if (SotExchange::IsMath(aClassName
))
2664 nId
= RES_POOLFRM_FORMEL
;
2667 SwFrameFormat
* pFrameFormat
= m_rDoc
.getIDocumentStylePoolAccess().GetFrameFormatFromPool( nId
);
2669 return InsNoTextNode( *rRg
.GetPoint(), m_rDoc
.GetNodes().MakeOLENode(
2670 SwNodeIndex( m_rDoc
.GetNodes().GetEndOfAutotext() ),
2672 m_rDoc
.GetDfltGrfFormatColl() ),
2673 pFlyAttrSet
, nullptr,
2677 SwFlyFrameFormat
* DocumentContentOperationsManager::InsertOLE(const SwPaM
&rRg
, const OUString
& rObjName
,
2679 const SfxItemSet
* pFlyAttrSet
,
2680 const SfxItemSet
* pGrfAttrSet
)
2682 SwFrameFormat
* pFrameFormat
= m_rDoc
.getIDocumentStylePoolAccess().GetFrameFormatFromPool( RES_POOLFRM_OLE
);
2684 return InsNoTextNode( *rRg
.GetPoint(),
2685 m_rDoc
.GetNodes().MakeOLENode(
2686 SwNodeIndex( m_rDoc
.GetNodes().GetEndOfAutotext() ),
2689 m_rDoc
.GetDfltGrfFormatColl(),
2691 pFlyAttrSet
, pGrfAttrSet
,
2695 void DocumentContentOperationsManager::ReRead( SwPaM
& rPam
, const OUString
& rGrfName
,
2696 const OUString
& rFltName
, const Graphic
* pGraphic
,
2697 const GraphicObject
* pGrafObj
)
2700 if( ( !rPam
.HasMark()
2701 || rPam
.GetPoint()->nNode
.GetIndex() == rPam
.GetMark()->nNode
.GetIndex() )
2702 && nullptr != ( pGrfNd
= rPam
.GetPoint()->nNode
.GetNode().GetGrfNode() ) )
2704 if (m_rDoc
.GetIDocumentUndoRedo().DoesUndo())
2706 m_rDoc
.GetIDocumentUndoRedo().AppendUndo(new SwUndoReRead(rPam
, *pGrfNd
));
2709 // Because we don't know if we can mirror the graphic, the mirror attribute is always reset
2710 if( MirrorGraph::Dont
!= pGrfNd
->GetSwAttrSet().
2711 GetMirrorGrf().GetValue() )
2712 pGrfNd
->SetAttr( SwMirrorGrf() );
2714 pGrfNd
->ReRead( rGrfName
, rFltName
, pGraphic
, pGrafObj
);
2715 m_rDoc
.getIDocumentState().SetModified();
2719 // Insert drawing object, which has to be already inserted in the DrawModel
2720 SwDrawFrameFormat
* DocumentContentOperationsManager::InsertDrawObj(
2722 SdrObject
& rDrawObj
,
2723 const SfxItemSet
& rFlyAttrSet
)
2725 SwDrawFrameFormat
* pFormat
= m_rDoc
.MakeDrawFrameFormat( OUString(), m_rDoc
.GetDfltFrameFormat() );
2727 const SwFormatAnchor
* pAnchor
= nullptr;
2728 rFlyAttrSet
.GetItemState( RES_ANCHOR
, false, reinterpret_cast<const SfxPoolItem
**>(&pAnchor
) );
2729 pFormat
->SetFormatAttr( rFlyAttrSet
);
2731 // Didn't set the Anchor yet?
2732 // DrawObjecte must never end up in the Header/Footer!
2733 RndStdIds eAnchorId
= pAnchor
!= nullptr ? pAnchor
->GetAnchorId() : pFormat
->GetAnchor().GetAnchorId();
2734 const bool bIsAtContent
= (RndStdIds::FLY_AT_PAGE
!= eAnchorId
);
2736 const SwNodeIndex
* pChkIdx
= nullptr;
2737 if ( pAnchor
== nullptr )
2739 pChkIdx
= &rRg
.GetPoint()->nNode
;
2741 else if ( bIsAtContent
)
2744 pAnchor
->GetContentAnchor() ? &pAnchor
->GetContentAnchor()->nNode
: &rRg
.GetPoint()->nNode
;
2747 // allow drawing objects in header/footer, but control objects aren't allowed in header/footer.
2748 if( pChkIdx
!= nullptr
2749 && ::CheckControlLayer( &rDrawObj
)
2750 && m_rDoc
.IsInHeaderFooter( *pChkIdx
) )
2752 // apply at-page anchor format
2753 eAnchorId
= RndStdIds::FLY_AT_PAGE
;
2754 pFormat
->SetFormatAttr( SwFormatAnchor( eAnchorId
) );
2756 else if( pAnchor
== nullptr
2758 && pAnchor
->GetContentAnchor() == nullptr ) )
2760 // apply anchor format
2761 SwFormatAnchor
aAnch( pAnchor
!= nullptr ? *pAnchor
: pFormat
->GetAnchor() );
2762 eAnchorId
= aAnch
.GetAnchorId();
2763 if ( eAnchorId
== RndStdIds::FLY_AT_FLY
)
2765 SwPosition
aPos( *rRg
.GetNode().FindFlyStartNode() );
2766 aAnch
.SetAnchor( &aPos
);
2770 aAnch
.SetAnchor( rRg
.GetPoint() );
2771 if ( eAnchorId
== RndStdIds::FLY_AT_PAGE
)
2773 eAnchorId
= dynamic_cast<const SdrUnoObj
*>( &rDrawObj
) != nullptr ? RndStdIds::FLY_AS_CHAR
: RndStdIds::FLY_AT_PARA
;
2774 aAnch
.SetType( eAnchorId
);
2777 pFormat
->SetFormatAttr( aAnch
);
2780 // insert text attribute for as-character anchored drawing object
2781 if ( eAnchorId
== RndStdIds::FLY_AS_CHAR
)
2783 bool bAnchorAtPageAsFallback
= true;
2784 const SwFormatAnchor
& rDrawObjAnchorFormat
= pFormat
->GetAnchor();
2785 if ( rDrawObjAnchorFormat
.GetContentAnchor() != nullptr )
2787 SwTextNode
* pAnchorTextNode
=
2788 rDrawObjAnchorFormat
.GetContentAnchor()->nNode
.GetNode().GetTextNode();
2789 if ( pAnchorTextNode
!= nullptr )
2791 const sal_Int32 nStt
= rDrawObjAnchorFormat
.GetContentAnchor()->nContent
.GetIndex();
2792 SwFormatFlyCnt
aFormat( pFormat
);
2793 pAnchorTextNode
->InsertItem( aFormat
, nStt
, nStt
);
2794 bAnchorAtPageAsFallback
= false;
2798 if ( bAnchorAtPageAsFallback
)
2800 OSL_ENSURE( false, "DocumentContentOperationsManager::InsertDrawObj(..) - missing content anchor for as-character anchored drawing object --> anchor at-page" );
2801 pFormat
->SetFormatAttr( SwFormatAnchor( RndStdIds::FLY_AT_PAGE
) );
2805 SwDrawContact
* pContact
= new SwDrawContact( pFormat
, &rDrawObj
);
2807 // Create Frames if necessary
2808 if( m_rDoc
.getIDocumentLayoutAccess().GetCurrentViewShell() )
2810 // create layout representation
2811 pFormat
->MakeFrames();
2812 // #i42319# - follow-up of #i35635#
2813 // move object to visible layer
2815 if ( pContact
->GetAnchorFrame() )
2817 pContact
->MoveObjToVisibleLayer( &rDrawObj
);
2821 if (m_rDoc
.GetIDocumentUndoRedo().DoesUndo())
2823 m_rDoc
.GetIDocumentUndoRedo().AppendUndo( new SwUndoInsLayFormat(pFormat
, 0, 0) );
2826 m_rDoc
.getIDocumentState().SetModified();
2830 bool DocumentContentOperationsManager::SplitNode( const SwPosition
&rPos
, bool bChkTableStart
)
2832 SwContentNode
*pNode
= rPos
.nNode
.GetNode().GetContentNode();
2833 if(nullptr == pNode
)
2837 // BUG 26675: Send DataChanged before deleting, so that we notice which objects are in scope.
2838 // After that they can be before/after the position.
2839 SwDataChanged
aTmp( &m_rDoc
, rPos
);
2842 SwUndoSplitNode
* pUndo
= nullptr;
2843 if (m_rDoc
.GetIDocumentUndoRedo().DoesUndo())
2845 m_rDoc
.GetIDocumentUndoRedo().ClearRedo();
2846 // insert the Undo object (currently only for TextNode)
2847 if( pNode
->IsTextNode() )
2849 pUndo
= new SwUndoSplitNode( &m_rDoc
, rPos
, bChkTableStart
);
2850 m_rDoc
.GetIDocumentUndoRedo().AppendUndo(pUndo
);
2854 // Update the rsid of the old and the new node unless
2855 // the old node is split at the beginning or at the end
2856 SwTextNode
*pTextNode
= rPos
.nNode
.GetNode().GetTextNode();
2857 const sal_Int32 nPos
= rPos
.nContent
.GetIndex();
2858 if( pTextNode
&& nPos
&& nPos
!= pTextNode
->Len() )
2860 m_rDoc
.UpdateParRsid( pTextNode
);
2863 //JP 28.01.97: Special case for SplitNode at table start:
2864 // If it is at the beginning of a Doc/Fly/Footer/... or right at after a table
2865 // then insert a paragraph before it.
2866 if( bChkTableStart
&& !rPos
.nContent
.GetIndex() && pNode
->IsTextNode() )
2868 sal_uLong nPrevPos
= rPos
.nNode
.GetIndex() - 1;
2869 const SwTableNode
* pTableNd
;
2870 const SwNode
* pNd
= m_rDoc
.GetNodes()[ nPrevPos
];
2871 if( pNd
->IsStartNode() &&
2872 SwTableBoxStartNode
== static_cast<const SwStartNode
*>(pNd
)->GetStartNodeType() &&
2873 nullptr != ( pTableNd
= m_rDoc
.GetNodes()[ --nPrevPos
]->GetTableNode() ) &&
2874 ((( pNd
= m_rDoc
.GetNodes()[ --nPrevPos
])->IsStartNode() &&
2875 SwTableBoxStartNode
!= static_cast<const SwStartNode
*>(pNd
)->GetStartNodeType() )
2876 || ( pNd
->IsEndNode() && pNd
->StartOfSectionNode()->IsTableNode() )
2877 || pNd
->IsContentNode() ))
2879 if( pNd
->IsContentNode() )
2881 //JP 30.04.99 Bug 65660:
2882 // There are no page breaks outside of the normal body area,
2883 // so this is not a valid condition to insert a paragraph.
2884 if( nPrevPos
< m_rDoc
.GetNodes().GetEndOfExtras().GetIndex() )
2888 // Only if the table has page breaks!
2889 const SwFrameFormat
* pFrameFormat
= pTableNd
->GetTable().GetFrameFormat();
2890 if( SfxItemState::SET
!= pFrameFormat
->GetItemState(RES_PAGEDESC
, false) &&
2891 SfxItemState::SET
!= pFrameFormat
->GetItemState( RES_BREAK
, false ) )
2898 SwTextNode
* pTextNd
= m_rDoc
.GetNodes().MakeTextNode(
2899 SwNodeIndex( *pTableNd
),
2900 m_rDoc
.getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_TEXT
));
2903 const_cast<SwPosition
&>(rPos
).nNode
= pTableNd
->GetIndex()-1;
2904 const_cast<SwPosition
&>(rPos
).nContent
.Assign( pTextNd
, 0 );
2906 // only add page breaks/styles to the body area
2907 if( nPrevPos
> m_rDoc
.GetNodes().GetEndOfExtras().GetIndex() )
2909 SwFrameFormat
* pFrameFormat
= pTableNd
->GetTable().GetFrameFormat();
2910 const SfxPoolItem
*pItem
;
2911 if( SfxItemState::SET
== pFrameFormat
->GetItemState( RES_PAGEDESC
,
2914 pTextNd
->SetAttr( *pItem
);
2915 pFrameFormat
->ResetFormatAttr( RES_PAGEDESC
);
2917 if( SfxItemState::SET
== pFrameFormat
->GetItemState( RES_BREAK
,
2920 pTextNd
->SetAttr( *pItem
);
2921 pFrameFormat
->ResetFormatAttr( RES_BREAK
);
2926 pUndo
->SetTableFlag();
2927 m_rDoc
.getIDocumentState().SetModified();
2934 const std::shared_ptr
<sw::mark::ContentIdxStore
> pContentStore(sw::mark::ContentIdxStore::Create());
2935 pContentStore
->Save( &m_rDoc
, rPos
.nNode
.GetIndex(), rPos
.nContent
.GetIndex(), true );
2936 // FIXME: only SwTextNode has a valid implementation of SplitContentNode!
2937 OSL_ENSURE(pNode
->IsTextNode(), "splitting non-text node?");
2938 pNode
= pNode
->SplitContentNode( rPos
);
2941 // move all bookmarks, TOXMarks, FlyAtCnt
2942 if( !pContentStore
->Empty() )
2943 pContentStore
->Restore( &m_rDoc
, rPos
.nNode
.GetIndex()-1, 0, true );
2945 // To-Do - add 'SwExtraRedlineTable' also ?
2946 if( m_rDoc
.getIDocumentRedlineAccess().IsRedlineOn() || (!m_rDoc
.getIDocumentRedlineAccess().IsIgnoreRedline() && !m_rDoc
.getIDocumentRedlineAccess().GetRedlineTable().empty() ))
2950 aPam
.Move( fnMoveBackward
);
2951 if( m_rDoc
.getIDocumentRedlineAccess().IsRedlineOn() )
2952 m_rDoc
.getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline( nsRedlineType_t::REDLINE_INSERT
, aPam
), true);
2954 m_rDoc
.getIDocumentRedlineAccess().SplitRedline( aPam
);
2958 m_rDoc
.getIDocumentState().SetModified();
2962 bool DocumentContentOperationsManager::AppendTextNode( SwPosition
& rPos
)
2964 // create new node before EndOfContent
2965 SwTextNode
* pCurNode
= rPos
.nNode
.GetNode().GetTextNode();
2968 // so then one can be created!
2969 SwNodeIndex
aIdx( rPos
.nNode
, 1 );
2970 pCurNode
= m_rDoc
.GetNodes().MakeTextNode( aIdx
,
2971 m_rDoc
.getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_STANDARD
));
2974 pCurNode
= pCurNode
->AppendNode( rPos
)->GetTextNode();
2977 rPos
.nContent
.Assign( pCurNode
, 0 );
2979 if (m_rDoc
.GetIDocumentUndoRedo().DoesUndo())
2981 m_rDoc
.GetIDocumentUndoRedo().AppendUndo( new SwUndoInsert( rPos
.nNode
) );
2984 // To-Do - add 'SwExtraRedlineTable' also ?
2985 if( m_rDoc
.getIDocumentRedlineAccess().IsRedlineOn() || (!m_rDoc
.getIDocumentRedlineAccess().IsIgnoreRedline() && !m_rDoc
.getIDocumentRedlineAccess().GetRedlineTable().empty() ))
2989 aPam
.Move( fnMoveBackward
);
2990 if( m_rDoc
.getIDocumentRedlineAccess().IsRedlineOn() )
2991 m_rDoc
.getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline( nsRedlineType_t::REDLINE_INSERT
, aPam
), true);
2993 m_rDoc
.getIDocumentRedlineAccess().SplitRedline( aPam
);
2996 m_rDoc
.getIDocumentState().SetModified();
3000 bool DocumentContentOperationsManager::ReplaceRange( SwPaM
& rPam
, const OUString
& rStr
,
3001 const bool bRegExReplace
)
3003 // unfortunately replace works slightly differently from delete,
3004 // so we cannot use lcl_DoWithBreaks here...
3006 std::vector
<sal_Int32
> Breaks
;
3008 SwPaM
aPam( *rPam
.GetMark(), *rPam
.GetPoint() );
3009 aPam
.Normalize(false);
3010 if (aPam
.GetPoint()->nNode
!= aPam
.GetMark()->nNode
)
3012 aPam
.Move(fnMoveBackward
);
3014 OSL_ENSURE((aPam
.GetPoint()->nNode
== aPam
.GetMark()->nNode
), "invalid pam?");
3016 lcl_CalcBreaks(Breaks
, aPam
);
3018 while (!Breaks
.empty() // skip over prefix of dummy chars
3019 && (aPam
.GetMark()->nContent
.GetIndex() == *Breaks
.begin()) )
3022 ++aPam
.GetMark()->nContent
; // always in bounds if Breaks valid
3023 Breaks
.erase(Breaks
.begin());
3025 *rPam
.Start() = *aPam
.GetMark(); // update start of original pam w/ prefix
3029 // park aPam somewhere so it does not point to node that is deleted
3031 *aPam
.GetPoint() = SwPosition(m_rDoc
.GetNodes().GetEndOfContent());
3032 return ReplaceRangeImpl(rPam
, rStr
, bRegExReplace
); // original pam!
3035 // Deletion must be split into several parts if the text node
3036 // contains a text attribute with end and with dummy character
3037 // and the selection does not contain the text attribute completely,
3038 // but overlaps its start (left), where the dummy character is.
3041 // iterate from end to start, to avoid invalidating the offsets!
3042 std::vector
<sal_Int32
>::reverse_iterator
iter( Breaks
.rbegin() );
3043 OSL_ENSURE(aPam
.GetPoint() == aPam
.End(), "wrong!");
3044 SwPosition
& rEnd( *aPam
.End() );
3045 SwPosition
& rStart( *aPam
.Start() );
3047 // set end of temp pam to original end (undo Move backward above)
3049 // after first deletion, rEnd will point into the original text node again!
3051 while (iter
!= Breaks
.rend())
3053 rStart
.nContent
= *iter
+ 1;
3054 if (rEnd
.nContent
!= rStart
.nContent
) // check if part is empty
3056 bRet
&= (m_rDoc
.getIDocumentRedlineAccess().IsRedlineOn())
3057 ? DeleteAndJoinWithRedlineImpl(aPam
)
3058 : DeleteAndJoinImpl(aPam
, false);
3060 rEnd
.nContent
= *iter
;
3064 rStart
= *rPam
.Start(); // set to original start
3065 OSL_ENSURE(rEnd
.nContent
> rStart
.nContent
, "replace part empty!");
3066 if (rEnd
.nContent
> rStart
.nContent
) // check if part is empty
3068 bRet
&= ReplaceRangeImpl(aPam
, rStr
, bRegExReplace
);
3071 rPam
= aPam
; // update original pam (is this required?)
3076 ///Add a para for the char attribute exp...
3077 bool DocumentContentOperationsManager::InsertPoolItem(
3079 const SfxPoolItem
&rHt
,
3080 const SetAttrMode nFlags
,
3081 const bool bExpandCharToPara
)
3083 if (utl::ConfigManager::IsFuzzing())
3086 SwDataChanged
aTmp( rRg
);
3087 SwUndoAttr
* pUndoAttr
= nullptr;
3088 if (m_rDoc
.GetIDocumentUndoRedo().DoesUndo())
3090 m_rDoc
.GetIDocumentUndoRedo().ClearRedo();
3091 pUndoAttr
= new SwUndoAttr( rRg
, rHt
, nFlags
);
3094 SfxItemSet
aSet( m_rDoc
.GetAttrPool(), {{rHt
.Which(), rHt
.Which()}} );
3096 const bool bRet
= lcl_InsAttr( &m_rDoc
, rRg
, aSet
, nFlags
, pUndoAttr
, bExpandCharToPara
);
3098 if (m_rDoc
.GetIDocumentUndoRedo().DoesUndo())
3100 m_rDoc
.GetIDocumentUndoRedo().AppendUndo( pUndoAttr
);
3105 m_rDoc
.getIDocumentState().SetModified();
3110 void DocumentContentOperationsManager::InsertItemSet ( const SwPaM
&rRg
, const SfxItemSet
&rSet
,
3111 const SetAttrMode nFlags
)
3113 SwDataChanged
aTmp( rRg
);
3114 SwUndoAttr
* pUndoAttr
= nullptr;
3115 if (m_rDoc
.GetIDocumentUndoRedo().DoesUndo())
3117 m_rDoc
.GetIDocumentUndoRedo().ClearRedo();
3118 pUndoAttr
= new SwUndoAttr( rRg
, rSet
, nFlags
);
3121 bool bRet
= lcl_InsAttr( &m_rDoc
, rRg
, rSet
, nFlags
, pUndoAttr
);
3123 if (m_rDoc
.GetIDocumentUndoRedo().DoesUndo())
3125 m_rDoc
.GetIDocumentUndoRedo().AppendUndo( pUndoAttr
);
3129 m_rDoc
.getIDocumentState().SetModified();
3132 void DocumentContentOperationsManager::RemoveLeadingWhiteSpace(const SwPosition
& rPos
)
3134 const SwTextNode
* pTNd
= rPos
.nNode
.GetNode().GetTextNode();
3137 const OUString
& rText
= pTNd
->GetText();
3139 while (nIdx
< rText
.getLength())
3141 sal_Unicode
const cCh
= rText
[nIdx
];
3142 if (('\t' != cCh
) && (' ' != cCh
))
3152 aPam
.GetPoint()->nContent
= 0;
3154 aPam
.GetMark()->nContent
= nIdx
;
3155 DeleteRange( aPam
);
3160 // Copy method from SwDoc - "copy Flys in Flys"
3161 void DocumentContentOperationsManager::CopyWithFlyInFly(
3162 const SwNodeRange
& rRg
,
3163 const sal_Int32 nEndContentIndex
,
3164 const SwNodeIndex
& rInsPos
,
3165 const std::pair
<const SwPaM
&, const SwPosition
&>* pCopiedPaM
/*and real insert pos*/,
3166 const bool bMakeNewFrames
,
3167 const bool bDelRedlines
,
3168 const bool bCopyFlyAtFly
) const
3170 assert(!pCopiedPaM
|| pCopiedPaM
->first
.End()->nContent
== nEndContentIndex
);
3171 assert(!pCopiedPaM
|| pCopiedPaM
->first
.End()->nNode
== rRg
.aEnd
);
3173 SwDoc
* pDest
= rInsPos
.GetNode().GetDoc();
3175 SaveRedlEndPosForRestore
aRedlRest( rInsPos
, 0 );
3177 SwNodeIndex
aSavePos( rInsPos
, -1 );
3178 bool bEndIsEqualEndPos
= rInsPos
== rRg
.aEnd
;
3179 m_rDoc
.GetNodes().CopyNodes( rRg
, rInsPos
, bMakeNewFrames
, true );
3181 if( bEndIsEqualEndPos
)
3182 const_cast<SwNodeIndex
&>(rRg
.aEnd
) = aSavePos
;
3184 aRedlRest
.Restore();
3186 #if OSL_DEBUG_LEVEL > 0
3188 //JP 17.06.99: Bug 66973 - check count only if the selection is in
3189 // the same section or there's no section, because sections that are
3190 // not fully selected are not copied.
3191 const SwSectionNode
* pSSectNd
= rRg
.aStart
.GetNode().FindSectionNode();
3192 SwNodeIndex
aTmpI( rRg
.aEnd
, -1 );
3193 const SwSectionNode
* pESectNd
= aTmpI
.GetNode().FindSectionNode();
3194 if( pSSectNd
== pESectNd
&&
3195 !rRg
.aStart
.GetNode().IsSectionNode() &&
3196 !aTmpI
.GetNode().IsEndNode() )
3198 // If the range starts with a SwStartNode, it isn't copied
3199 sal_uInt16 offset
= (rRg
.aStart
.GetNode().GetNodeType() != SwNodeType::Start
) ? 1 : 0;
3200 OSL_ENSURE( rInsPos
.GetIndex() - aSavePos
.GetIndex() ==
3201 rRg
.aEnd
.GetIndex() - rRg
.aStart
.GetIndex() - 1 + offset
,
3202 "An insufficient number of nodes were copied!" );
3208 ::sw::UndoGuard
const undoGuard(pDest
->GetIDocumentUndoRedo());
3209 CopyFlyInFlyImpl( rRg
, nEndContentIndex
, aSavePos
, bCopyFlyAtFly
);
3212 SwNodeRange
aCpyRange( aSavePos
, rInsPos
);
3214 // Also copy all bookmarks
3215 // guess this must be done before the DelDummyNodes below as that
3216 // deletes nodes so would mess up the index arithmetic
3217 if( m_rDoc
.getIDocumentMarkAccess()->getAllMarksCount() )
3219 SwPaM
aRgTmp( rRg
.aStart
, rRg
.aEnd
);
3220 SwPaM
aCpyPaM(aCpyRange
.aStart
, aCpyRange
.aEnd
);
3221 if (pCopiedPaM
&& rRg
.aStart
!= pCopiedPaM
->first
.Start()->nNode
)
3223 // there is 1 (partially selected, maybe) paragraph before
3224 assert(SwNodeIndex(rRg
.aStart
, -1) == pCopiedPaM
->first
.Start()->nNode
);
3225 // only use the passed in target SwPosition if the source PaM point
3226 // is on a different node; if it was the same node then the target
3227 // position was likely moved along by the copy operation and now
3228 // points to the end of the range!
3229 *aCpyPaM
.GetPoint() = pCopiedPaM
->second
;
3232 lcl_CopyBookmarks(pCopiedPaM
? pCopiedPaM
->first
: aRgTmp
, aCpyPaM
);
3235 if( bDelRedlines
&& ( RedlineFlags::DeleteRedlines
& pDest
->getIDocumentRedlineAccess().GetRedlineFlags() ))
3236 lcl_DeleteRedlines( rRg
, aCpyRange
);
3238 pDest
->GetNodes().DelDummyNodes( aCpyRange
);
3241 // TODO: there is a limitation here in that it's not possible to pass a start
3242 // content index - which means that at-character anchored frames inside
3243 // partial 1st paragraph of redline is not copied.
3244 // But the DelFlyInRange() that is called from DelCopyOfSection() does not
3245 // delete it either, and it also does not delete those on partial last para of
3246 // redline, so copying those is suppressed here too ...
3247 void DocumentContentOperationsManager::CopyFlyInFlyImpl(
3248 const SwNodeRange
& rRg
,
3249 const sal_Int32 nEndContentIndex
,
3250 const SwNodeIndex
& rStartIdx
,
3251 const bool bCopyFlyAtFly
) const
3253 // First collect all Flys, sort them according to their ordering number,
3254 // and then only copy them. This maintains the ordering numbers (which are only
3255 // managed in the DrawModel).
3256 SwDoc
*const pDest
= rStartIdx
.GetNode().GetDoc();
3257 std::set
< ZSortFly
> aSet
;
3258 const size_t nArrLen
= m_rDoc
.GetSpzFrameFormats()->size();
3260 SwTextBoxHelper::SavedLink aOldTextBoxes
;
3261 SwTextBoxHelper::saveLinks(*m_rDoc
.GetSpzFrameFormats(), aOldTextBoxes
);
3262 SwTextBoxHelper::SavedContent aOldContent
;
3264 for ( size_t n
= 0; n
< nArrLen
; ++n
)
3266 SwFrameFormat
* pFormat
= (*m_rDoc
.GetSpzFrameFormats())[n
];
3267 SwFormatAnchor
const*const pAnchor
= &pFormat
->GetAnchor();
3268 SwPosition
const*const pAPos
= pAnchor
->GetContentAnchor();
3269 bool bAtContent
= (pAnchor
->GetAnchorId() == RndStdIds::FLY_AT_PARA
);
3272 sal_uLong nSkipAfter
= pAPos
->nNode
.GetIndex();
3273 sal_uLong nStart
= rRg
.aStart
.GetIndex();
3274 switch ( pAnchor
->GetAnchorId() )
3276 case RndStdIds::FLY_AT_FLY
:
3279 else if(m_rDoc
.getIDocumentRedlineAccess().IsRedlineMove())
3282 case RndStdIds::FLY_AT_CHAR
:
3283 case RndStdIds::FLY_AT_PARA
:
3284 if(m_rDoc
.getIDocumentRedlineAccess().IsRedlineMove())
3290 if ( nStart
> nSkipAfter
)
3292 if ( pAPos
->nNode
> rRg
.aEnd
)
3294 //frames at the last source node are not always copied:
3295 //- if the node is empty and is the last node of the document or a table cell
3296 // or a text frame then they have to be copied
3297 //- if the content index in this node is > 0 then paragraph and frame bound objects are copied
3298 //- to-character bound objects are copied if their index is <= nEndContentIndex
3300 if( pAPos
->nNode
< rRg
.aEnd
)
3302 if (!bAdd
&& !m_rDoc
.getIDocumentRedlineAccess().IsRedlineMove()) // fdo#40599: not for redline move
3304 bool bEmptyNode
= false;
3305 bool bLastNode
= false;
3306 // is the node empty?
3307 const SwNodes
& rNodes
= pAPos
->nNode
.GetNodes();
3308 SwTextNode
* pTextNode
;
3309 if( nullptr != ( pTextNode
= pAPos
->nNode
.GetNode().GetTextNode() ))
3311 bEmptyNode
= pTextNode
->GetText().isEmpty();
3314 //last node information is only necessary to know for the last TextNode
3315 SwNodeIndex
aTmp( pAPos
->nNode
);
3316 ++aTmp
;//goto next node
3317 while (aTmp
.GetNode().IsEndNode())
3319 if( aTmp
== rNodes
.GetEndOfContent().GetIndex() )
3328 bAdd
= bLastNode
&& bEmptyNode
;
3332 bAdd
= nEndContentIndex
> 0;
3334 bAdd
= pAPos
->nContent
<= nEndContentIndex
;
3339 // Make sure draw formats don't refer to content, so that such
3340 // content can be removed without problems.
3341 SwTextBoxHelper::resetLink(pFormat
, aOldContent
);
3342 aSet
.insert( ZSortFly( pFormat
, pAnchor
, nArrLen
+ aSet
.size() ));
3346 // Store all copied (and also the newly created) frames in another array.
3347 // They are stored as matching the originals, so that we will be later
3348 // able to build the chains accordingly.
3349 std::vector
< SwFrameFormat
* > aVecSwFrameFormat
;
3350 std::set
< ZSortFly
>::const_iterator it
=aSet
.begin();
3352 while (it
!= aSet
.end())
3355 // correct determination of new anchor position
3356 SwFormatAnchor
aAnchor( *(*it
).GetAnchor() );
3357 assert( aAnchor
.GetContentAnchor() != nullptr );
3358 SwPosition newPos
= *aAnchor
.GetContentAnchor();
3359 // for at-paragraph and at-character anchored objects the new anchor
3360 // position can *not* be determined by the difference of the current
3361 // anchor position to the start of the copied range, because not
3362 // complete selected sections in the copied range aren't copied - see
3363 // method <SwNodes::CopyNodes(..)>.
3364 // Thus, the new anchor position in the destination document is found
3365 // by counting the text nodes.
3366 if ((aAnchor
.GetAnchorId() == RndStdIds::FLY_AT_PARA
) ||
3367 (aAnchor
.GetAnchorId() == RndStdIds::FLY_AT_CHAR
) )
3369 // First, determine number of anchor text node in the copied range.
3370 // Note: The anchor text node *have* to be inside the copied range.
3371 sal_uLong
nAnchorTextNdNumInRange( 0 );
3372 bool bAnchorTextNdFound( false );
3373 SwNodeIndex
aIdx( rRg
.aStart
);
3374 while ( !bAnchorTextNdFound
&& aIdx
<= rRg
.aEnd
)
3376 if ( aIdx
.GetNode().IsTextNode() )
3378 ++nAnchorTextNdNumInRange
;
3379 bAnchorTextNdFound
= aAnchor
.GetContentAnchor()->nNode
== aIdx
;
3385 if ( !bAnchorTextNdFound
)
3387 // This case can *not* happen, but to be robust take the first
3388 // text node in the destination document.
3389 OSL_FAIL( "<SwDoc::_CopyFlyInFly(..)> - anchor text node in copied range not found" );
3390 nAnchorTextNdNumInRange
= 1;
3392 // Second, search corresponding text node in destination document
3393 // by counting forward from start insert position <rStartIdx> the
3394 // determined number of text nodes.
3396 SwNodeIndex
aAnchorNdIdx( rStartIdx
);
3397 const SwNode
& aEndOfContentNd
=
3398 aIdx
.GetNode().GetNodes().GetEndOfContent();
3399 while ( nAnchorTextNdNumInRange
> 0 &&
3400 &(aIdx
.GetNode()) != &aEndOfContentNd
)
3402 if ( aIdx
.GetNode().IsTextNode() )
3404 --nAnchorTextNdNumInRange
;
3405 aAnchorNdIdx
= aIdx
;
3410 if ( !aAnchorNdIdx
.GetNode().IsTextNode() )
3412 // This case can *not* happen, but to be robust take the first
3413 // text node in the destination document.
3414 OSL_FAIL( "<SwDoc::_CopyFlyInFly(..)> - found anchor node index isn't a text node" );
3415 aAnchorNdIdx
= rStartIdx
;
3416 while ( !aAnchorNdIdx
.GetNode().IsTextNode() )
3421 // apply found anchor text node as new anchor position
3422 newPos
.nNode
= aAnchorNdIdx
;
3426 long nOffset
= newPos
.nNode
.GetIndex() - rRg
.aStart
.GetIndex();
3427 SwNodeIndex
aIdx( rStartIdx
, nOffset
);
3428 newPos
.nNode
= aIdx
;
3430 // Set the character bound Flys back at the original character
3431 if ((RndStdIds::FLY_AT_CHAR
== aAnchor
.GetAnchorId()) &&
3432 newPos
.nNode
.GetNode().IsTextNode() )
3434 newPos
.nContent
.Assign( newPos
.nNode
.GetNode().GetTextNode(), newPos
.nContent
.GetIndex() );
3438 newPos
.nContent
.Assign( nullptr, 0 );
3440 aAnchor
.SetAnchor( &newPos
);
3442 // Check recursion: copy content in its own frame, then don't copy it.
3443 if( pDest
== &m_rDoc
)
3445 const SwFormatContent
& rContent
= (*it
).GetFormat()->GetContent();
3446 const SwStartNode
* pSNd
;
3447 if( rContent
.GetContentIdx() &&
3448 nullptr != ( pSNd
= rContent
.GetContentIdx()->GetNode().GetStartNode() ) &&
3449 pSNd
->GetIndex() < rStartIdx
.GetIndex() &&
3450 rStartIdx
.GetIndex() < pSNd
->EndOfSectionIndex() )
3452 it
= aSet
.erase(it
);
3457 // Copy the format and set the new anchor
3458 aVecSwFrameFormat
.push_back( pDest
->getIDocumentLayoutAccess().CopyLayoutFormat( *(*it
).GetFormat(),
3459 aAnchor
, false, true ) );
3463 // Rebuild as much as possible of all chains that are available in the original,
3464 OSL_ENSURE( aSet
.size() == aVecSwFrameFormat
.size(), "Missing new Flys" );
3465 if ( aSet
.size() == aVecSwFrameFormat
.size() )
3468 for (std::set
< ZSortFly
>::const_iterator nIt
=aSet
.begin() ; nIt
!= aSet
.end(); ++nIt
, ++n
)
3470 const SwFrameFormat
*pFormatN
= (*nIt
).GetFormat();
3471 const SwFormatChain
&rChain
= pFormatN
->GetChain();
3472 int nCnt
= int(nullptr != rChain
.GetPrev());
3473 nCnt
+= rChain
.GetNext() ? 1: 0;
3475 for (std::set
< ZSortFly
>::const_iterator kIt
=aSet
.begin() ; kIt
!= aSet
.end(); ++kIt
, ++k
)
3477 const SwFrameFormat
*pFormatK
= (*kIt
).GetFormat();
3478 if ( rChain
.GetPrev() == pFormatK
)
3480 ::lcl_ChainFormats( static_cast< SwFlyFrameFormat
* >(aVecSwFrameFormat
[k
]),
3481 static_cast< SwFlyFrameFormat
* >(aVecSwFrameFormat
[n
]) );
3484 else if ( rChain
.GetNext() == pFormatK
)
3486 ::lcl_ChainFormats( static_cast< SwFlyFrameFormat
* >(aVecSwFrameFormat
[n
]),
3487 static_cast< SwFlyFrameFormat
* >(aVecSwFrameFormat
[k
]) );
3493 // Re-create content property of draw formats, knowing how old shapes
3494 // were paired with old fly formats (aOldTextBoxes) and that aSet is
3495 // parallel with aVecSwFrameFormat.
3496 SwTextBoxHelper::restoreLinks(aSet
, aVecSwFrameFormat
, aOldTextBoxes
, aOldContent
);
3501 * Reset the text's hard formatting
3503 /** @params pArgs contains the document's ChrFormatTable
3504 * Is need for selections at the beginning/end and with no SSelection.
3506 bool DocumentContentOperationsManager::lcl_RstTextAttr( const SwNodePtr
& rpNd
, void* pArgs
)
3508 ParaRstFormat
* pPara
= static_cast<ParaRstFormat
*>(pArgs
);
3509 SwTextNode
* pTextNode
= rpNd
->GetTextNode();
3510 if( pTextNode
&& pTextNode
->GetpSwpHints() )
3512 SwIndex
aSt( pTextNode
, 0 );
3513 sal_Int32 nEnd
= pTextNode
->Len();
3515 if( &pPara
->pSttNd
->nNode
.GetNode() == pTextNode
&&
3516 pPara
->pSttNd
->nContent
.GetIndex() )
3517 aSt
= pPara
->pSttNd
->nContent
.GetIndex();
3519 if( &pPara
->pEndNd
->nNode
.GetNode() == rpNd
)
3520 nEnd
= pPara
->pEndNd
->nContent
.GetIndex();
3522 if( pPara
->pHistory
)
3524 // Save all attributes for the Undo.
3525 SwRegHistory
aRHst( *pTextNode
, pPara
->pHistory
);
3526 pTextNode
->GetpSwpHints()->Register( &aRHst
);
3527 pTextNode
->RstTextAttr( aSt
, nEnd
- aSt
.GetIndex(), pPara
->nWhich
,
3528 pPara
->pDelSet
, pPara
->bInclRefToxMark
, pPara
->bExactRange
);
3529 if( pTextNode
->GetpSwpHints() )
3530 pTextNode
->GetpSwpHints()->DeRegister();
3533 pTextNode
->RstTextAttr( aSt
, nEnd
- aSt
.GetIndex(), pPara
->nWhich
,
3534 pPara
->pDelSet
, pPara
->bInclRefToxMark
, pPara
->bExactRange
);
3539 DocumentContentOperationsManager::~DocumentContentOperationsManager()
3544 bool DocumentContentOperationsManager::DeleteAndJoinWithRedlineImpl( SwPaM
& rPam
, const bool )
3546 OSL_ENSURE( m_rDoc
.getIDocumentRedlineAccess().IsRedlineOn(), "DeleteAndJoinWithRedline: redline off" );
3549 SwUndoRedlineDelete
* pUndo
= nullptr;
3550 RedlineFlags eOld
= m_rDoc
.getIDocumentRedlineAccess().GetRedlineFlags();
3551 m_rDoc
.GetDocumentRedlineManager().checkRedlining( eOld
);
3553 auto & rDMA(*m_rDoc
.getIDocumentMarkAccess());
3554 std::vector
<std::unique_ptr
<SwUndo
>> MarkUndos
;
3555 for (auto iter
= rDMA
.getAnnotationMarksBegin();
3556 iter
!= rDMA
.getAnnotationMarksEnd(); )
3558 // tdf#111524 remove annotation marks that have their field
3559 // characters deleted
3560 SwPosition
const& rEndPos((**iter
).GetMarkEnd());
3561 if (*rPam
.Start() < rEndPos
&& rEndPos
<= *rPam
.End())
3563 if (m_rDoc
.GetIDocumentUndoRedo().DoesUndo())
3565 MarkUndos
.emplace_back(o3tl::make_unique
<SwUndoDeleteBookmark
>(**iter
));
3567 // iter is into annotation mark vector so must be dereferenced!
3568 rDMA
.deleteMark(&**iter
);
3569 // this invalidates iter, have to start over...
3570 iter
= rDMA
.getAnnotationMarksBegin();
3573 { // marks are sorted by start
3574 if (*rPam
.End() < (**iter
).GetMarkStart())
3582 if (m_rDoc
.GetIDocumentUndoRedo().DoesUndo())
3585 /* please don't translate -- for cultural reasons this comment is protected
3586 until the redline implementation is finally fixed some day */
3587 //JP 06.01.98: MUSS noch optimiert werden!!!
3588 m_rDoc
.getIDocumentRedlineAccess().SetRedlineFlags(
3589 RedlineFlags::On
| RedlineFlags::ShowInsert
| RedlineFlags::ShowDelete
);
3590 pUndo
= new SwUndoRedlineDelete( rPam
, SwUndoId::DELETE
);
3591 const SwRewriter aRewriter
= pUndo
->GetRewriter();
3592 m_rDoc
.GetIDocumentUndoRedo().StartUndo( SwUndoId::DELETE
, &aRewriter
);
3593 for (auto& it
: MarkUndos
)
3595 m_rDoc
.GetIDocumentUndoRedo().AppendUndo(it
.release());
3597 m_rDoc
.GetIDocumentUndoRedo().AppendUndo( pUndo
);
3600 if ( *rPam
.GetPoint() != *rPam
.GetMark() )
3601 m_rDoc
.getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline( nsRedlineType_t::REDLINE_DELETE
, rPam
), true );
3602 m_rDoc
.getIDocumentState().SetModified();
3606 m_rDoc
.GetIDocumentUndoRedo().EndUndo( SwUndoId::EMPTY
, nullptr );
3607 // ??? why the hell is the AppendUndo not below the
3608 // CanGrouping, so this hideous cleanup wouldn't be necessary?
3609 // bah, this is redlining, probably changing this would break it...
3610 if ( m_rDoc
.GetIDocumentUndoRedo().DoesGroupUndo() )
3612 SwUndo
* const pLastUndo( m_rDoc
.GetUndoManager().GetLastUndo() );
3613 SwUndoRedlineDelete
* const pUndoRedlineDel( dynamic_cast< SwUndoRedlineDelete
* >( pLastUndo
) );
3614 if ( pUndoRedlineDel
)
3616 bool const bMerged
= pUndoRedlineDel
->CanGrouping( *pUndo
);
3619 ::sw::UndoGuard
const undoGuard( m_rDoc
.GetIDocumentUndoRedo() );
3620 SwUndo
const* const pDeleted
= m_rDoc
.GetUndoManager().RemoveLastUndo();
3621 OSL_ENSURE( pDeleted
== pUndo
, "DeleteAndJoinWithRedlineImpl: "
3622 "undo removed is not undo inserted?" );
3627 //JP 06.01.98: MUSS noch optimiert werden!!!
3628 m_rDoc
.getIDocumentRedlineAccess().SetRedlineFlags( eOld
);
3634 bool DocumentContentOperationsManager::DeleteAndJoinImpl( SwPaM
& rPam
,
3635 const bool bForceJoinNext
)
3637 bool bJoinText
, bJoinPrev
;
3638 ::sw_GetJoinFlags( rPam
, bJoinText
, bJoinPrev
);
3640 if ( bForceJoinNext
)
3646 bool const bSuccess( DeleteRangeImpl( rPam
) );
3653 ::sw_JoinText( rPam
, bJoinPrev
);
3659 bool DocumentContentOperationsManager::DeleteRangeImpl(SwPaM
& rPam
, const bool)
3661 // Move all cursors out of the deleted range, but first copy the
3662 // passed PaM, because it could be a cursor that would be moved!
3663 SwPaM
aDelPam( *rPam
.GetMark(), *rPam
.GetPoint() );
3664 ::PaMCorrAbs( aDelPam
, *aDelPam
.GetPoint() );
3666 bool const bSuccess( DeleteRangeImplImpl( aDelPam
) );
3668 { // now copy position from temp copy to given PaM
3669 *rPam
.GetPoint() = *aDelPam
.GetPoint();
3675 bool DocumentContentOperationsManager::DeleteRangeImplImpl(SwPaM
& rPam
)
3677 SwPosition
*pStt
= rPam
.Start(), *pEnd
= rPam
.End();
3679 if( !rPam
.HasMark() || *pStt
>= *pEnd
)
3682 if( m_rDoc
.GetAutoCorrExceptWord() )
3684 // if necessary the saved Word for the exception
3685 if( m_rDoc
.GetAutoCorrExceptWord()->IsDeleted() || pStt
->nNode
!= pEnd
->nNode
||
3686 pStt
->nContent
.GetIndex() + 1 != pEnd
->nContent
.GetIndex() ||
3687 !m_rDoc
.GetAutoCorrExceptWord()->CheckDelChar( *pStt
))
3688 { m_rDoc
.DeleteAutoCorrExceptWord(); }
3692 // Delete all empty TextHints at the Mark's position
3693 SwTextNode
* pTextNd
= rPam
.GetMark()->nNode
.GetNode().GetTextNode();
3695 if( pTextNd
&& nullptr != ( pHts
= pTextNd
->GetpSwpHints()) && pHts
->Count() )
3697 const sal_Int32 nMkCntPos
= rPam
.GetMark()->nContent
.GetIndex();
3698 for( size_t n
= pHts
->Count(); n
; )
3700 const SwTextAttr
* pAttr
= pHts
->Get( --n
);
3701 if( nMkCntPos
> pAttr
->GetStart() )
3704 const sal_Int32
*pEndIdx
;
3705 if( nMkCntPos
== pAttr
->GetStart() &&
3706 nullptr != (pEndIdx
= pAttr
->End()) &&
3707 *pEndIdx
== pAttr
->GetStart() )
3708 pTextNd
->DestroyAttr( pHts
->Cut( n
) );
3714 // Send DataChanged before deletion, so that we still know
3715 // which objects are in the range.
3716 // Afterwards they could be before/after the Position.
3717 SwDataChanged
aTmp( rPam
);
3720 if (m_rDoc
.GetIDocumentUndoRedo().DoesUndo())
3722 m_rDoc
.GetIDocumentUndoRedo().ClearRedo();
3723 bool bMerged(false);
3724 if (m_rDoc
.GetIDocumentUndoRedo().DoesGroupUndo())
3726 SwUndo
*const pLastUndo( m_rDoc
.GetUndoManager().GetLastUndo() );
3727 SwUndoDelete
*const pUndoDelete(
3728 dynamic_cast<SwUndoDelete
*>(pLastUndo
) );
3731 bMerged
= pUndoDelete
->CanGrouping( &m_rDoc
, rPam
);
3732 // if CanGrouping() returns true it's already merged
3737 m_rDoc
.GetIDocumentUndoRedo().AppendUndo( new SwUndoDelete( rPam
) );
3740 m_rDoc
.getIDocumentState().SetModified();
3745 if( !m_rDoc
.getIDocumentRedlineAccess().IsIgnoreRedline() && !m_rDoc
.getIDocumentRedlineAccess().GetRedlineTable().empty() )
3746 m_rDoc
.getIDocumentRedlineAccess().DeleteRedline( rPam
, true, USHRT_MAX
);
3748 // Delete and move all "Flys at the paragraph", which are within the Selection
3749 DelFlyInRange(rPam
.GetMark()->nNode
, rPam
.GetPoint()->nNode
);
3757 SwNodeIndex
aSttIdx( pStt
->nNode
);
3758 SwContentNode
* pCNd
= aSttIdx
.GetNode().GetContentNode();
3760 do { // middle checked loop!
3763 SwTextNode
* pStartTextNode( pCNd
->GetTextNode() );
3764 if ( pStartTextNode
)
3766 // now move the Content to the new Node
3767 bool bOneNd
= pStt
->nNode
== pEnd
->nNode
;
3768 const sal_Int32 nLen
= ( bOneNd
? pEnd
->nContent
.GetIndex()
3770 - pStt
->nContent
.GetIndex();
3772 // Don't call again, if already empty
3775 pStartTextNode
->EraseText( pStt
->nContent
, nLen
);
3777 if( !pStartTextNode
->Len() )
3779 // METADATA: remove reference if empty (consider node deleted)
3780 pStartTextNode
->RemoveMetadataReference();
3784 if( bOneNd
) // that's it
3791 // So that there are no indices left registered when deleted,
3792 // we remove a SwPaM from the Content here.
3793 pStt
->nContent
.Assign( nullptr, 0 );
3797 pCNd
= pEnd
->nNode
.GetNode().GetContentNode();
3800 SwTextNode
* pEndTextNode( pCNd
->GetTextNode() );
3803 // if already empty, don't call again
3804 if( pEnd
->nContent
.GetIndex() )
3806 SwIndex
aIdx( pCNd
, 0 );
3807 pEndTextNode
->EraseText( aIdx
, pEnd
->nContent
.GetIndex() );
3809 if( !pEndTextNode
->Len() )
3811 // METADATA: remove reference if empty (consider node deleted)
3812 pEndTextNode
->RemoveMetadataReference();
3818 // So that there are no indices left registered when deleted,
3819 // we remove a SwPaM from the Content here.
3820 pEnd
->nContent
.Assign( nullptr, 0 );
3824 // if the end is not a content node, delete it as well
3825 sal_uInt32 nEnde
= pEnd
->nNode
.GetIndex();
3826 if( pCNd
== nullptr )
3829 if( aSttIdx
!= nEnde
)
3831 // delete the Nodes into the NodesArary
3832 m_rDoc
.GetNodes().Delete( aSttIdx
, nEnde
- aSttIdx
.GetIndex() );
3835 // If the Node that contained the Cursor has been deleted,
3836 // the Content has to be assigned to the current Content.
3837 pStt
->nContent
.Assign( pStt
->nNode
.GetNode().GetContentNode(),
3838 pStt
->nContent
.GetIndex() );
3840 // If we deleted across Node boundaries we have to correct the PaM,
3841 // because they are in different Nodes now.
3842 // Also, the Selection is revoked.
3848 if( !m_rDoc
.getIDocumentRedlineAccess().IsIgnoreRedline() && !m_rDoc
.getIDocumentRedlineAccess().GetRedlineTable().empty() )
3849 m_rDoc
.getIDocumentRedlineAccess().CompressRedlines();
3850 m_rDoc
.getIDocumentState().SetModified();
3855 // It's possible to call Replace with a PaM that spans 2 paragraphs:
3856 // search with regex for "$", then replace _all_
3857 bool DocumentContentOperationsManager::ReplaceRangeImpl( SwPaM
& rPam
, const OUString
& rStr
,
3858 const bool bRegExReplace
)
3860 if( !rPam
.HasMark() || *rPam
.GetPoint() == *rPam
.GetMark() )
3863 bool bJoinText
, bJoinPrev
;
3864 ::sw_GetJoinFlags( rPam
, bJoinText
, bJoinPrev
);
3867 // Create a copy of the Cursor in order to move all Pams from
3868 // the other views out of the deletion range.
3869 // Except for itself!
3870 SwPaM
aDelPam( *rPam
.GetMark(), *rPam
.GetPoint() );
3871 ::PaMCorrAbs( aDelPam
, *aDelPam
.GetPoint() );
3873 SwPosition
*pStt
= aDelPam
.Start(),
3874 *pEnd
= aDelPam
.End();
3875 OSL_ENSURE( pStt
->nNode
== pEnd
->nNode
||
3876 ( pStt
->nNode
.GetIndex() + 1 == pEnd
->nNode
.GetIndex() &&
3877 !pEnd
->nContent
.GetIndex() ),
3878 "invalid range: Point and Mark on different nodes" );
3879 bool bOneNode
= pStt
->nNode
== pEnd
->nNode
;
3882 OUString
sRepl( rStr
);
3883 SwTextNode
* pTextNd
= pStt
->nNode
.GetNode().GetTextNode();
3884 sal_Int32 nStt
= pStt
->nContent
.GetIndex();
3887 SwDataChanged
aTmp( aDelPam
);
3889 if( m_rDoc
.getIDocumentRedlineAccess().IsRedlineOn() )
3891 RedlineFlags eOld
= m_rDoc
.getIDocumentRedlineAccess().GetRedlineFlags();
3892 m_rDoc
.GetDocumentRedlineManager().checkRedlining(eOld
);
3893 if (m_rDoc
.GetIDocumentUndoRedo().DoesUndo())
3895 m_rDoc
.GetIDocumentUndoRedo().StartUndo(SwUndoId::EMPTY
, nullptr);
3897 // If any Redline will change (split!) the node
3898 const ::sw::mark::IMark
* pBkmk
=
3899 m_rDoc
.getIDocumentMarkAccess()->makeMark( aDelPam
,
3900 OUString(), IDocumentMarkAccess::MarkType::UNO_BOOKMARK
,
3901 ::sw::mark::InsertMode::New
);
3903 //JP 06.01.98: MUSS noch optimiert werden!!!
3904 m_rDoc
.getIDocumentRedlineAccess().SetRedlineFlags(
3905 RedlineFlags::On
| RedlineFlags::ShowInsert
| RedlineFlags::ShowDelete
);
3907 *aDelPam
.GetPoint() = pBkmk
->GetMarkPos();
3908 if(pBkmk
->IsExpanded())
3909 *aDelPam
.GetMark() = pBkmk
->GetOtherMarkPos();
3910 m_rDoc
.getIDocumentMarkAccess()->deleteMark(pBkmk
);
3911 pStt
= aDelPam
.Start();
3912 pTextNd
= pStt
->nNode
.GetNode().GetTextNode();
3913 nStt
= pStt
->nContent
.GetIndex();
3916 if( !sRepl
.isEmpty() )
3918 // Apply the first character's attributes to the ReplaceText
3919 SfxItemSet
aSet( m_rDoc
.GetAttrPool(),
3920 svl::Items
<RES_CHRATR_BEGIN
, RES_TXTATR_WITHEND_END
- 1,
3921 RES_UNKNOWNATR_BEGIN
, RES_UNKNOWNATR_END
-1>{} );
3922 pTextNd
->GetAttr( aSet
, nStt
+1, nStt
+1 );
3924 aSet
.ClearItem( RES_TXTATR_REFMARK
);
3925 aSet
.ClearItem( RES_TXTATR_TOXMARK
);
3926 aSet
.ClearItem( RES_TXTATR_CJK_RUBY
);
3927 aSet
.ClearItem( RES_TXTATR_INETFMT
);
3928 aSet
.ClearItem( RES_TXTATR_META
);
3929 aSet
.ClearItem( RES_TXTATR_METAFIELD
);
3931 if( aDelPam
.GetPoint() != aDelPam
.End() )
3935 SwNodeIndex
aPtNd( aDelPam
.GetPoint()->nNode
, -1 );
3936 const sal_Int32 nPtCnt
= aDelPam
.GetPoint()->nContent
.GetIndex();
3940 while ( lcl_GetTokenToParaBreak( sRepl
, sIns
, bRegExReplace
) )
3942 InsertString( aDelPam
, sIns
);
3945 SwNodeIndex
aMkNd( aDelPam
.GetMark()->nNode
, -1 );
3946 const sal_Int32 nMkCnt
= aDelPam
.GetMark()->nContent
.GetIndex();
3948 SplitNode( *aDelPam
.GetPoint(), false );
3951 aDelPam
.GetMark()->nNode
= aMkNd
;
3952 aDelPam
.GetMark()->nContent
.Assign(
3953 aMkNd
.GetNode().GetContentNode(), nMkCnt
);
3957 SplitNode( *aDelPam
.GetPoint(), false );
3959 if( !sIns
.isEmpty() )
3961 InsertString( aDelPam
, sIns
);
3964 SwPaM
aTmpRange( *aDelPam
.GetPoint() );
3965 aTmpRange
.SetMark();
3968 aDelPam
.GetPoint()->nNode
= aPtNd
;
3969 aDelPam
.GetPoint()->nContent
.Assign( aPtNd
.GetNode().GetContentNode(),
3971 *aTmpRange
.GetMark() = *aDelPam
.GetPoint();
3973 m_rDoc
.RstTextAttrs( aTmpRange
);
3974 InsertItemSet( aTmpRange
, aSet
);
3977 if (m_rDoc
.GetIDocumentUndoRedo().DoesUndo())
3979 SwUndo
*const pUndoRD
=
3980 new SwUndoRedlineDelete( aDelPam
, SwUndoId::REPLACE
);
3981 m_rDoc
.GetIDocumentUndoRedo().AppendUndo(pUndoRD
);
3983 m_rDoc
.getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline( nsRedlineType_t::REDLINE_DELETE
, aDelPam
), true);
3985 *rPam
.GetMark() = *aDelPam
.GetMark();
3986 if (m_rDoc
.GetIDocumentUndoRedo().DoesUndo())
3988 *aDelPam
.GetPoint() = *rPam
.GetPoint();
3989 m_rDoc
.GetIDocumentUndoRedo().EndUndo(SwUndoId::EMPTY
, nullptr);
3991 // If any Redline will change (split!) the node
3992 const ::sw::mark::IMark
* pBkmk
=
3993 m_rDoc
.getIDocumentMarkAccess()->makeMark( aDelPam
,
3994 OUString(), IDocumentMarkAccess::MarkType::UNO_BOOKMARK
,
3995 ::sw::mark::InsertMode::New
);
3997 SwIndex
& rIdx
= aDelPam
.GetPoint()->nContent
;
3998 rIdx
.Assign( nullptr, 0 );
3999 aDelPam
.GetMark()->nContent
= rIdx
;
4000 rPam
.GetPoint()->nNode
= 0;
4001 rPam
.GetPoint()->nContent
= rIdx
;
4002 *rPam
.GetMark() = *rPam
.GetPoint();
4003 //JP 06.01.98: MUSS noch optimiert werden!!!
4004 m_rDoc
.getIDocumentRedlineAccess().SetRedlineFlags( eOld
);
4006 *rPam
.GetPoint() = pBkmk
->GetMarkPos();
4007 if(pBkmk
->IsExpanded())
4008 *rPam
.GetMark() = pBkmk
->GetOtherMarkPos();
4009 m_rDoc
.getIDocumentMarkAccess()->deleteMark(pBkmk
);
4015 if( !m_rDoc
.getIDocumentRedlineAccess().IsIgnoreRedline() && m_rDoc
.getIDocumentRedlineAccess().GetRedlineTable().size() )
4016 m_rDoc
.getIDocumentRedlineAccess().DeleteRedline( aDelPam
, true, USHRT_MAX
);
4018 SwUndoReplace
* pUndoRpl
= nullptr;
4019 bool const bDoesUndo
= m_rDoc
.GetIDocumentUndoRedo().DoesUndo();
4022 pUndoRpl
= new SwUndoReplace(aDelPam
, sRepl
, bRegExReplace
);
4023 m_rDoc
.GetIDocumentUndoRedo().AppendUndo(pUndoRpl
);
4025 ::sw::UndoGuard
const undoGuard(m_rDoc
.GetIDocumentUndoRedo());
4027 if( aDelPam
.GetPoint() != pStt
)
4030 SwNodeIndex
aPtNd( pStt
->nNode
, -1 );
4031 const sal_Int32 nPtCnt
= pStt
->nContent
.GetIndex();
4033 // Set the values again, if Frames or footnotes on the Text have been removed.
4035 nEnd
= bOneNode
? pEnd
->nContent
.GetIndex()
4036 : pTextNd
->GetText().getLength();
4040 while ( lcl_GetTokenToParaBreak( sRepl
, sIns
, bRegExReplace
) )
4042 if (!bFirst
|| nStt
== pTextNd
->GetText().getLength())
4044 InsertString( aDelPam
, sIns
);
4046 else if( nStt
< nEnd
|| !sIns
.isEmpty() )
4048 pTextNd
->ReplaceText( pStt
->nContent
, nEnd
- nStt
, sIns
);
4050 SplitNode( *pStt
, false);
4054 if( bFirst
|| !sIns
.isEmpty() )
4056 if (!bFirst
|| nStt
== pTextNd
->GetText().getLength())
4058 InsertString( aDelPam
, sIns
);
4060 else if( nStt
< nEnd
|| !sIns
.isEmpty() )
4062 pTextNd
->ReplaceText( pStt
->nContent
, nEnd
- nStt
, sIns
);
4066 *rPam
.GetPoint() = *aDelPam
.GetMark();
4068 rPam
.GetMark()->nNode
= aPtNd
;
4069 rPam
.GetMark()->nContent
.Assign( aPtNd
.GetNode().GetContentNode(),
4074 assert(rPam
.GetPoint() == rPam
.End());
4075 // move so that SetEnd remembers position after sw_JoinText
4076 rPam
.Move(fnMoveBackward
);
4078 else if (aDelPam
.GetPoint() == pStt
) // backward selection?
4080 assert(*rPam
.GetMark() <= *rPam
.GetPoint());
4081 rPam
.Exchange(); // swap so that rPam is backwards
4086 pUndoRpl
->SetEnd(rPam
);
4094 bRet
= ::sw_JoinText(rPam
, bJoinPrev
);
4097 m_rDoc
.getIDocumentState().SetModified();
4101 SwFlyFrameFormat
* DocumentContentOperationsManager::InsNoTextNode( const SwPosition
& rPos
, SwNoTextNode
* pNode
,
4102 const SfxItemSet
* pFlyAttrSet
,
4103 const SfxItemSet
* pGrfAttrSet
,
4104 SwFrameFormat
* pFrameFormat
)
4106 SwFlyFrameFormat
*pFormat
= nullptr;
4109 pFormat
= m_rDoc
.MakeFlySection_( rPos
, *pNode
, RndStdIds::FLY_AT_PARA
,
4110 pFlyAttrSet
, pFrameFormat
);
4112 pNode
->SetAttr( *pGrfAttrSet
);
4117 #define NUMRULE_STATE \
4118 SfxItemState aNumRuleState = SfxItemState::UNKNOWN; \
4119 SwNumRuleItem aNumRuleItem; \
4120 SfxItemState aListIdState = SfxItemState::UNKNOWN; \
4121 SfxStringItem aListIdItem( RES_PARATR_LIST_ID, OUString() ); \
4123 #define PUSH_NUMRULE_STATE \
4124 lcl_PushNumruleState( aNumRuleState, aNumRuleItem, aListIdState, aListIdItem, pDestTextNd );
4126 #define POP_NUMRULE_STATE \
4127 lcl_PopNumruleState( aNumRuleState, aNumRuleItem, aListIdState, aListIdItem, pDestTextNd, rPam );
4129 static void lcl_PushNumruleState( SfxItemState
&aNumRuleState
, SwNumRuleItem
&aNumRuleItem
,
4130 SfxItemState
&aListIdState
, SfxStringItem
&aListIdItem
,
4131 const SwTextNode
*pDestTextNd
)
4133 // Safe numrule item at destination.
4134 // #i86492# - Safe also <ListId> item of destination.
4135 const SfxItemSet
* pAttrSet
= pDestTextNd
->GetpSwAttrSet();
4136 if (pAttrSet
!= nullptr)
4138 const SfxPoolItem
* pItem
= nullptr;
4139 aNumRuleState
= pAttrSet
->GetItemState(RES_PARATR_NUMRULE
, false, &pItem
);
4140 if (SfxItemState::SET
== aNumRuleState
)
4141 aNumRuleItem
= *static_cast<const SwNumRuleItem
*>( pItem
);
4144 pAttrSet
->GetItemState(RES_PARATR_LIST_ID
, false, &pItem
);
4145 if (SfxItemState::SET
== aListIdState
)
4147 aListIdItem
.SetValue( static_cast<const SfxStringItem
*>(pItem
)->GetValue() );
4152 static void lcl_PopNumruleState( SfxItemState aNumRuleState
, const SwNumRuleItem
&aNumRuleItem
,
4153 SfxItemState aListIdState
, const SfxStringItem
&aListIdItem
,
4154 SwTextNode
*pDestTextNd
, const SwPaM
& rPam
)
4156 /* If only a part of one paragraph is copied
4157 restore the numrule at the destination. */
4158 // #i86492# - restore also <ListId> item
4159 if ( !lcl_MarksWholeNode(rPam
) )
4161 if (SfxItemState::SET
== aNumRuleState
)
4163 pDestTextNd
->SetAttr(aNumRuleItem
);
4167 pDestTextNd
->ResetAttr(RES_PARATR_NUMRULE
);
4169 if (SfxItemState::SET
== aListIdState
)
4171 pDestTextNd
->SetAttr(aListIdItem
);
4175 pDestTextNd
->ResetAttr(RES_PARATR_LIST_ID
);
4180 bool DocumentContentOperationsManager::CopyImpl( SwPaM
& rPam
, SwPosition
& rPos
,
4181 const bool bMakeNewFrames
, const bool bCopyAll
,
4182 SwPaM
*const pCpyRange
) const
4184 SwDoc
* pDoc
= rPos
.nNode
.GetNode().GetDoc();
4185 const bool bColumnSel
= pDoc
->IsClipBoard() && pDoc
->IsColumnSelection();
4187 SwPosition
* pStt
= rPam
.Start();
4188 SwPosition
* pEnd
= rPam
.End();
4190 // Catch when there's no copy to do.
4191 if( !rPam
.HasMark() || ( *pStt
>= *pEnd
&& !bColumnSel
) ||
4192 //JP 29.6.2001: 88963 - don't copy if inspos is in region of start to end
4193 //JP 15.11.2001: don't test inclusive the end, ever exclusive
4194 ( pDoc
== &m_rDoc
&& *pStt
<= rPos
&& rPos
< *pEnd
))
4199 const bool bEndEqualIns
= pDoc
== &m_rDoc
&& rPos
== *pEnd
;
4201 // If Undo is enabled, create the UndoCopy object
4202 SwUndoCpyDoc
* pUndo
= nullptr;
4203 // lcl_DeleteRedlines may delete the start or end node of the cursor when
4204 // removing the redlines so use cursor that is corrected by PaMCorrAbs
4205 std::shared_ptr
<SwUnoCursor
> const pCopyPam(pDoc
->CreateUnoCursor(rPos
));
4207 SwTableNumFormatMerge
aTNFM( m_rDoc
, *pDoc
);
4209 if (pDoc
->GetIDocumentUndoRedo().DoesUndo())
4211 pUndo
= new SwUndoCpyDoc(*pCopyPam
);
4212 pDoc
->GetIDocumentUndoRedo().AppendUndo( pUndo
);
4215 RedlineFlags eOld
= pDoc
->getIDocumentRedlineAccess().GetRedlineFlags();
4216 pDoc
->getIDocumentRedlineAccess().SetRedlineFlags_intern(eOld
| RedlineFlags::Ignore
);
4218 // Move the PaM one node back from the insert position, so that
4219 // the position doesn't get moved
4220 pCopyPam
->SetMark();
4221 bool bCanMoveBack
= pCopyPam
->Move(fnMoveBackward
, GoInContent
);
4222 // If the position was shifted from more than one node, an end node has been skipped
4223 bool bAfterTable
= false;
4224 if ((rPos
.nNode
.GetIndex() - pCopyPam
->GetPoint()->nNode
.GetIndex()) > 1)
4226 // First go back to the original place
4227 pCopyPam
->GetPoint()->nNode
= rPos
.nNode
;
4228 pCopyPam
->GetPoint()->nContent
= rPos
.nContent
;
4230 bCanMoveBack
= false;
4234 pCopyPam
->GetPoint()->nNode
--;
4236 SwNodeRange
aRg( pStt
->nNode
, pEnd
->nNode
);
4237 SwNodeIndex
aInsPos( rPos
.nNode
);
4238 const bool bOneNode
= pStt
->nNode
== pEnd
->nNode
;
4239 SwTextNode
* pSttTextNd
= pStt
->nNode
.GetNode().GetTextNode();
4240 SwTextNode
* pEndTextNd
= pEnd
->nNode
.GetNode().GetTextNode();
4241 SwTextNode
* pDestTextNd
= aInsPos
.GetNode().GetTextNode();
4242 bool bCopyCollFormat
= !pDoc
->IsInsOnlyTextGlossary() &&
4243 ( (pDestTextNd
&& !pDestTextNd
->GetText().getLength()) ||
4244 ( !bOneNode
&& !rPos
.nContent
.GetIndex() ) );
4245 bool bCopyBookmarks
= true;
4246 bool bCopyPageSource
= false;
4247 bool bStartIsTextNode
= nullptr != pSttTextNd
;
4249 // #i104585# copy outline num rule to clipboard (for ASCII filter)
4250 if (pDoc
->IsClipBoard() && m_rDoc
.GetOutlineNumRule())
4252 pDoc
->SetOutlineNumRule(*m_rDoc
.GetOutlineNumRule());
4256 // Correct the search for a previous list:
4257 // First search for non-outline numbering list. Then search for non-outline
4259 // Keep also the <ListId> value for possible propagation.
4260 OUString aListIdToPropagate
;
4261 const SwNumRule
* pNumRuleToPropagate
=
4262 pDoc
->SearchNumRule( rPos
, false, true, false, 0, aListIdToPropagate
, true );
4263 if ( !pNumRuleToPropagate
)
4265 pNumRuleToPropagate
=
4266 pDoc
->SearchNumRule( rPos
, false, false, false, 0, aListIdToPropagate
, true );
4269 // Do not propagate previous found list, if
4270 // - destination is an empty paragraph which is not in a list and
4271 // - source contains at least one paragraph which is not in a list
4272 if ( pNumRuleToPropagate
&&
4273 pDestTextNd
&& !pDestTextNd
->GetText().getLength() &&
4274 !pDestTextNd
->IsInList() &&
4275 !lcl_ContainsOnlyParagraphsInList( rPam
) )
4277 pNumRuleToPropagate
= nullptr;
4280 // This do/while block is only there so that we can break out of it!
4284 // Don't copy the beginning completely?
4285 if( !bCopyCollFormat
|| bColumnSel
|| pStt
->nContent
.GetIndex() )
4287 SwIndex
aDestIdx( rPos
.nContent
);
4288 bool bCopyOk
= false;
4291 if( pStt
->nContent
.GetIndex() || bOneNode
)
4292 pDestTextNd
= pDoc
->GetNodes().MakeTextNode( aInsPos
,
4293 pDoc
->getIDocumentStylePoolAccess().GetTextCollFromPool(RES_POOLCOLL_STANDARD
));
4296 pDestTextNd
= pSttTextNd
->MakeCopy( pDoc
, aInsPos
)->GetTextNode();
4299 aDestIdx
.Assign( pDestTextNd
, 0 );
4300 bCopyCollFormat
= true;
4302 else if( !bOneNode
|| bColumnSel
)
4304 const sal_Int32 nContentEnd
= pEnd
->nContent
.GetIndex();
4306 ::sw::UndoGuard
const ug(pDoc
->GetIDocumentUndoRedo());
4307 pDoc
->getIDocumentContentOperations().SplitNode( rPos
, false );
4310 if (bCanMoveBack
&& rPos
== *pCopyPam
->GetPoint())
4312 // after the SplitNode, span the CpyPam correctly again
4313 pCopyPam
->Move( fnMoveBackward
, GoInContent
);
4314 pCopyPam
->Move( fnMoveBackward
, GoInContent
);
4317 pDestTextNd
= pDoc
->GetNodes()[ aInsPos
.GetIndex()-1 ]->GetTextNode();
4319 pDestTextNd
, pDestTextNd
->GetText().getLength());
4321 // Correct the area again
4324 bool bChg
= pEnd
!= rPam
.GetPoint();
4327 rPam
.Move( fnMoveBackward
, GoInContent
);
4331 else if( rPos
== *pEnd
)
4333 // The end was also moved
4335 pEnd
->nContent
.Assign( pDestTextNd
, nContentEnd
);
4337 // tdf#63022 always reset pEndTextNd after SplitNode
4338 aRg
.aEnd
= pEnd
->nNode
;
4339 pEndTextNd
= pEnd
->nNode
.GetNode().GetTextNode();
4343 if( bCopyCollFormat
&& bOneNode
)
4350 const sal_Int32 nCpyLen
= ( bOneNode
4351 ? pEnd
->nContent
.GetIndex()
4352 : pSttTextNd
->GetText().getLength())
4353 - pStt
->nContent
.GetIndex();
4354 pSttTextNd
->CopyText( pDestTextNd
, aDestIdx
,
4355 pStt
->nContent
, nCpyLen
);
4357 pEnd
->nContent
-= nCpyLen
;
4362 if (bCopyCollFormat
)
4364 pSttTextNd
->CopyCollFormat( *pDestTextNd
);
4374 else if( pDestTextNd
)
4376 // Problems with insertion of table selections into "normal" text solved.
4377 // We have to set the correct PaM for Undo, if this PaM starts in a textnode,
4378 // the undo operation will try to merge this node after removing the table.
4379 // If we didn't split a textnode, the PaM should start at the inserted table node
4380 if( rPos
.nContent
.GetIndex() == pDestTextNd
->Len() )
4381 { // Insertion at the last position of a textnode (empty or not)
4382 ++aInsPos
; // The table will be inserted behind the text node
4384 else if( rPos
.nContent
.GetIndex() )
4385 { // Insertion in the middle of a text node, it has to be split
4386 // (and joined from undo)
4387 bStartIsTextNode
= true;
4389 const sal_Int32 nContentEnd
= pEnd
->nContent
.GetIndex();
4391 ::sw::UndoGuard
const ug(pDoc
->GetIDocumentUndoRedo());
4392 pDoc
->getIDocumentContentOperations().SplitNode( rPos
, false );
4395 if (bCanMoveBack
&& rPos
== *pCopyPam
->GetPoint())
4397 // after the SplitNode, span the CpyPam correctly again
4398 pCopyPam
->Move( fnMoveBackward
, GoInContent
);
4399 pCopyPam
->Move( fnMoveBackward
, GoInContent
);
4402 // Correct the area again
4405 // The end would also be moved
4406 else if( rPos
== *pEnd
)
4409 rPos
.nContent
.Assign( rPos
.nNode
.GetNode().GetContentNode(),
4415 else if( bCanMoveBack
)
4416 { //Insertion at the first position of a text node. It will not be splitted, the table
4417 // will be inserted before the text node.
4418 // See below, before the SetInsertRange function of the undo object will be called,
4419 // the CpyPam would be moved to the next content position. This has to be avoided
4420 // We want to be moved to the table node itself thus we have to set bCanMoveBack
4421 // and to manipulate pCopyPam.
4422 bCanMoveBack
= false;
4423 pCopyPam
->GetPoint()->nNode
--;
4427 pDestTextNd
= aInsPos
.GetNode().GetTextNode();
4430 SwIndex
aDestIdx( rPos
.nContent
);
4433 pDestTextNd
= pDoc
->GetNodes().MakeTextNode( aInsPos
,
4434 pDoc
->getIDocumentStylePoolAccess().GetTextCollFromPool(RES_POOLCOLL_STANDARD
));
4435 aDestIdx
.Assign( pDestTextNd
, 0 );
4438 // if we have to insert an extra text node
4439 // at the destination, this node will be our new destination
4440 // (text) node, and thus we set bStartisTextNode to true. This
4441 // will ensure that this node will be deleted during Undo
4443 OSL_ENSURE( !bStartIsTextNode
, "Oops, undo may be instable now." );
4444 bStartIsTextNode
= true;
4447 const bool bEmptyDestNd
= pDestTextNd
->GetText().isEmpty();
4450 if( bCopyCollFormat
&& ( bOneNode
|| bEmptyDestNd
))
4455 pEndTextNd
->CopyText( pDestTextNd
, aDestIdx
, SwIndex( pEndTextNd
),
4456 pEnd
->nContent
.GetIndex() );
4458 // Also copy all format templates
4459 if( bCopyCollFormat
&& ( bOneNode
|| bEmptyDestNd
))
4461 pEndTextNd
->CopyCollFormat( *pDestTextNd
);
4469 if( bCopyAll
|| aRg
.aStart
!= aRg
.aEnd
)
4471 SfxItemSet
aBrkSet( pDoc
->GetAttrPool(), aBreakSetRange
);
4472 if (pSttTextNd
&& bCopyCollFormat
&& pDestTextNd
->HasSwAttrSet())
4474 aBrkSet
.Put( *pDestTextNd
->GetpSwAttrSet() );
4475 if( SfxItemState::SET
== aBrkSet
.GetItemState( RES_BREAK
, false ) )
4476 pDestTextNd
->ResetAttr( RES_BREAK
);
4477 if( SfxItemState::SET
== aBrkSet
.GetItemState( RES_PAGEDESC
, false ) )
4478 pDestTextNd
->ResetAttr( RES_PAGEDESC
);
4481 SwPosition
startPos(SwNodeIndex(pCopyPam
->GetPoint()->nNode
, +1),
4482 SwIndex(SwNodeIndex(pCopyPam
->GetPoint()->nNode
, +1).GetNode().GetContentNode()));
4484 { // pCopyPam is actually 1 before the copy range so move it fwd
4485 SwPaM
temp(*pCopyPam
->GetPoint());
4486 temp
.Move(fnMoveForward
, GoInContent
);
4487 startPos
= *temp
.GetPoint();
4489 assert(startPos
.nNode
.GetNode().IsContentNode());
4490 std::pair
<SwPaM
const&, SwPosition
const&> tmp(rPam
, startPos
);
4491 if( aInsPos
== pEnd
->nNode
)
4493 SwNodeIndex
aSaveIdx( aInsPos
, -1 );
4494 CopyWithFlyInFly( aRg
, 0, aInsPos
, &tmp
, bMakeNewFrames
, false );
4496 pEnd
->nNode
= aSaveIdx
;
4497 pEnd
->nContent
.Assign( aSaveIdx
.GetNode().GetTextNode(), 0 );
4500 CopyWithFlyInFly( aRg
, pEnd
->nContent
.GetIndex(), aInsPos
, &tmp
, bMakeNewFrames
, false );
4502 bCopyBookmarks
= false;
4504 // Put the breaks back into the first node
4505 if( aBrkSet
.Count() && nullptr != ( pDestTextNd
= pDoc
->GetNodes()[
4506 pCopyPam
->GetPoint()->nNode
.GetIndex()+1 ]->GetTextNode()))
4508 pDestTextNd
->SetAttr( aBrkSet
);
4509 bCopyPageSource
= true;
4515 // it is not possible to make this test when copy from the clipBoard to document
4516 // in this case the PageNum not exist anymore
4517 // tdf#39400 and tdf#97526
4518 // when copy from document to ClipBoard, and it is from the first page
4519 // and not the source has the page break
4520 if (pDoc
->IsClipBoard() && (rPam
.GetPageNum(pStt
== rPam
.GetPoint()) == 1) && !bCopyPageSource
)
4522 pDestTextNd
->ResetAttr(RES_BREAK
); // remove the page-break
4523 pDestTextNd
->ResetAttr(RES_PAGEDESC
);
4527 // Adjust position (in case it was moved / in another node)
4528 rPos
.nContent
.Assign( rPos
.nNode
.GetNode().GetContentNode(),
4529 rPos
.nContent
.GetIndex() );
4531 if( rPos
.nNode
!= aInsPos
)
4533 pCopyPam
->GetMark()->nNode
= aInsPos
;
4534 pCopyPam
->GetMark()->nContent
.Assign(pCopyPam
->GetContentNode(false), 0);
4535 rPos
= *pCopyPam
->GetMark();
4538 *pCopyPam
->GetMark() = rPos
;
4541 pCopyPam
->Move( fnMoveForward
, bCanMoveBack
? GoInContent
: GoInNode
);
4544 // Reset the offset to 0 as it was before the insertion
4545 pCopyPam
->GetPoint()->nContent
= 0;
4547 pCopyPam
->GetPoint()->nNode
++;
4548 // If the next node is a start node, then step back: the start node
4549 // has been copied and needs to be in the selection for the undo
4550 if (pCopyPam
->GetPoint()->nNode
.GetNode().IsStartNode())
4551 pCopyPam
->GetPoint()->nNode
--;
4554 pCopyPam
->Exchange();
4556 // Also copy all bookmarks
4557 if( bCopyBookmarks
&& m_rDoc
.getIDocumentMarkAccess()->getAllMarksCount() )
4558 lcl_CopyBookmarks( rPam
, *pCopyPam
);
4560 if( RedlineFlags::DeleteRedlines
& eOld
)
4562 assert(*pCopyPam
->GetPoint() == rPos
);
4563 // the Node rPos points to may be deleted so unregister ...
4564 rPos
.nContent
.Assign(nullptr, 0);
4565 lcl_DeleteRedlines(rPam
, *pCopyPam
);
4566 rPos
= *pCopyPam
->GetPoint(); // ... and restore.
4569 // If Undo is enabled, store the inserted area
4570 if (pDoc
->GetIDocumentUndoRedo().DoesUndo())
4572 pUndo
->SetInsertRange( *pCopyPam
, true, bStartIsTextNode
);
4577 pCpyRange
->SetMark();
4578 *pCpyRange
->GetPoint() = *pCopyPam
->GetPoint();
4579 *pCpyRange
->GetMark() = *pCopyPam
->GetMark();
4582 if ( pNumRuleToPropagate
!= nullptr )
4584 // #i86492# - use <SwDoc::SetNumRule(..)>, because it also handles the <ListId>
4585 pDoc
->SetNumRule( *pCopyPam
, *pNumRuleToPropagate
, false,
4586 aListIdToPropagate
, true, true );
4589 pDoc
->getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld
);
4590 pDoc
->getIDocumentState().SetModified();
4597 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */