xref: /core/sw/source/core/undo/untblk.cxx (revision fcd4222d)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <libxml/xmlwriter.h>
21 
22 #include <fmtanchr.hxx>
23 #include <frmfmt.hxx>
24 #include <doc.hxx>
25 #include <IDocumentRedlineAccess.hxx>
26 #include <IShellCursorSupplier.hxx>
27 #include <docary.hxx>
28 #include <swcrsr.hxx>
29 #include <swundo.hxx>
30 #include <pam.hxx>
31 #include <mvsave.hxx>
32 #include <ndtxt.hxx>
33 #include <UndoCore.hxx>
34 #include <rolbck.hxx>
35 #include <redline.hxx>
36 #include <frameformats.hxx>
37 
38 namespace sw {
39 
40 std::optional<std::vector<SwFrameFormat*>>
GetFlysAnchoredAt(SwDoc & rDoc,SwNodeOffset const nSttNode,bool const isAtPageIncluded)41 GetFlysAnchoredAt(SwDoc & rDoc, SwNodeOffset const nSttNode, bool const isAtPageIncluded)
42 {
43     std::optional<std::vector<SwFrameFormat*>> pFrameFormats;
44     const size_t nArrLen = rDoc.GetSpzFrameFormats()->size();
45     for (size_t n = 0; n < nArrLen; ++n)
46     {
47         SwFrameFormat *const pFormat = (*rDoc.GetSpzFrameFormats())[n];
48         SwFormatAnchor const*const pAnchor = &pFormat->GetAnchor();
49         SwNode const*const pAnchorNode = pAnchor->GetAnchorNode();
50         if ((pAnchorNode
51                 && nSttNode == pAnchorNode->GetIndex()
52                 && ((pAnchor->GetAnchorId() == RndStdIds::FLY_AT_PARA)
53                     || (pAnchor->GetAnchorId() == RndStdIds::FLY_AT_CHAR)))
54             || (isAtPageIncluded && pAnchor->GetAnchorId() == RndStdIds::FLY_AT_PAGE))
55         {
56             if (!pFrameFormats)
57                 pFrameFormats.emplace();
58             pFrameFormats->push_back( pFormat );
59         }
60     }
61     return pFrameFormats;
62 }
63 
64 } // namespace sw
65 
66 //note: parameter is SwPam just so we can init SwUndRng, the End is ignored!
SwUndoInserts(SwUndoId nUndoId,const SwPaM & rPam)67 SwUndoInserts::SwUndoInserts( SwUndoId nUndoId, const SwPaM& rPam )
68     : SwUndo( nUndoId, &rPam.GetDoc() )
69     , SwUndRng( rPam )
70     , m_pTextFormatColl(nullptr)
71     , m_pLastNodeColl(nullptr)
72     , m_nDeleteTextNodes(1)
73     , m_nNodeDiff(0)
74     , m_nSetPos(0)
75 {
76     m_pHistory.reset( new SwHistory );
77     SwDoc& rDoc = rPam.GetDoc();
78 
79     SwTextNode* pTextNd = rPam.GetPoint()->GetNode().GetTextNode();
80     if( pTextNd )
81     {
82         m_pTextFormatColl = pTextNd->GetTextColl();
83         assert(m_pTextFormatColl);
84         m_pHistory->CopyAttr( pTextNd->GetpSwpHints(), m_nSttNode,
85                             0, pTextNd->GetText().getLength(), false );
86         if( pTextNd->HasSwAttrSet() )
87             m_pHistory->CopyFormatAttr( *pTextNd->GetpSwAttrSet(), m_nSttNode );
88 
89         // We may have some flys anchored to paragraph where we inserting.
90         // These flys will be saved in pFrameFormats array (only flys which exist BEFORE insertion!)
91         // Then in SwUndoInserts::SetInsertRange the flys saved in pFrameFormats will NOT create Undos.
92         // m_FlyUndos will only be filled with newly inserted flys.
93         m_pFrameFormats = sw::GetFlysAnchoredAt(rDoc, m_nSttNode, true);
94     }
95     // consider Redline
96     if( rDoc.getIDocumentRedlineAccess().IsRedlineOn() )
97     {
98         m_pRedlineData.reset( new SwRedlineData( RedlineType::Insert, rDoc.getIDocumentRedlineAccess().GetRedlineAuthor() ) );
99         SetRedlineFlags( rDoc.getIDocumentRedlineAccess().GetRedlineFlags() );
100     }
101 }
102 
103 // This method does two things:
104 // 1. Adjusts SwUndoRng members, required for Undo.
105 //  Members are:
106 //  SwUndoRng::nSttNode - all nodes starting from this node will be deleted during Undo (in SwUndoInserts::UndoImpl)
107 //  SwUndoRng::nSttContent - corresponding content index in SwUndoRng::nSttNode
108 //  SwUndoRng::nEndNode - end node for deletion
109 //  SwUndoRng::nEndContent - end content index
110 // All these members are filled in during construction of SwUndoInserts instance, and can be adjusted using this method
111 //
112 // 2. Fills in m_FlyUndos array with flys anchored ONLY to first and last paragraphs (first == rPam.Start(), last == rPam.End())
113 //  Flys, anchored to any paragraph, but not first and last, are handled by DelContentIndex (see SwUndoInserts::UndoImpl) and are not stored in m_FlyUndos.
114 
SetInsertRange(const SwPaM & rPam,bool bScanFlys,SwNodeOffset const nDeleteTextNodes)115 void SwUndoInserts::SetInsertRange( const SwPaM& rPam, bool bScanFlys,
116                                     SwNodeOffset const nDeleteTextNodes)
117 {
118     const SwPosition* pTmpPos = rPam.End();
119     m_nEndNode = pTmpPos->GetNodeIndex();
120     m_nEndContent = pTmpPos->GetContentIndex();
121     if( rPam.HasMark() )
122     {
123         if( pTmpPos == rPam.GetPoint() )
124             pTmpPos = rPam.GetMark();
125         else
126             pTmpPos = rPam.GetPoint();
127 
128         m_nSttNode = pTmpPos->GetNodeIndex();
129         m_nSttContent = pTmpPos->GetContentIndex();
130 
131         m_nDeleteTextNodes = nDeleteTextNodes;
132         if (m_nDeleteTextNodes == SwNodeOffset(0)) // if a table selection is added...
133         {
134             ++m_nSttNode;         // ... then the CopyPam is not fully correct
135         }
136     }
137 
138     // Fill m_FlyUndos with flys anchored to first and last paragraphs
139 
140     if( !bScanFlys)
141         return;
142 
143     // than collect all new Flys
144     SwDoc& rDoc = rPam.GetDoc();
145     const size_t nArrLen = rDoc.GetSpzFrameFormats()->size();
146     for( size_t n = 0; n < nArrLen; ++n )
147     {
148         SwFrameFormat* pFormat = (*rDoc.GetSpzFrameFormats())[n];
149         SwFormatAnchor const*const pAnchor = &pFormat->GetAnchor();
150         if (IsCreateUndoForNewFly(*pAnchor, m_nSttNode, m_nEndNode))
151         {
152             std::vector<SwFrameFormat*>::iterator it;
153             if( !m_pFrameFormats ||
154                 m_pFrameFormats->end() == ( it = std::find( m_pFrameFormats->begin(), m_pFrameFormats->end(), pFormat ) ) )
155             {
156                 std::shared_ptr<SwUndoInsLayFormat> const pFlyUndo =
157                     std::make_shared<SwUndoInsLayFormat>(pFormat, SwNodeOffset(0), 0);
158                 m_FlyUndos.push_back(pFlyUndo);
159             }
160             else
161                 m_pFrameFormats->erase( it );
162         }
163     }
164     m_pFrameFormats.reset();
165 }
166 
167 /** This is not the same as IsDestroyFrameAnchoredAtChar()
168     and intentionally so: because the SwUndoInserts::UndoImpl() must remove
169     the flys at the start/end position that were inserted but not the ones
170     at the start/insert position that were already there;
171     handle all at-char flys at start/end node like this, even if they're
172     not *on* the start/end position, because it makes it easier to ensure
173     that the Undo/Redo run in inverse order.
174  */
IsCreateUndoForNewFly(SwFormatAnchor const & rAnchor,SwNodeOffset const nStartNode,SwNodeOffset const nEndNode)175 bool SwUndoInserts::IsCreateUndoForNewFly(SwFormatAnchor const& rAnchor,
176     SwNodeOffset const nStartNode, SwNodeOffset const nEndNode)
177 {
178     assert(nStartNode <= nEndNode);
179 
180     if (rAnchor.GetAnchorId() == RndStdIds::FLY_AT_PAGE)
181     {
182         return true; // needed for SwUndoInserts/SwReader::Read()
183     }
184 
185     // check all at-char flys at the start/end nodes:
186     // ExcludeFlyAtStartEnd will exclude them!
187     SwNode const*const pAnchorNode = rAnchor.GetAnchorNode();
188     return pAnchorNode != nullptr
189         && (   rAnchor.GetAnchorId() == RndStdIds::FLY_AT_PARA
190             || rAnchor.GetAnchorId() == RndStdIds::FLY_AT_CHAR)
191         && (   nStartNode == pAnchorNode->GetIndex()
192             || nEndNode == pAnchorNode->GetIndex());
193 }
194 
dumpAsXml(xmlTextWriterPtr pWriter) const195 void SwUndoInserts::dumpAsXml(xmlTextWriterPtr pWriter) const
196 {
197     (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwUndoInserts"));
198     (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
199     (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("symbol"), "%s",
200                                       BAD_CAST(typeid(*this).name()));
201 
202     SwUndo::dumpAsXml(pWriter);
203     SwUndoSaveContent::dumpAsXml(pWriter);
204 
205     if (m_pFrameFormats)
206     {
207         (void)xmlTextWriterStartElement(pWriter, BAD_CAST("m_pFrameFormats"));
208         for (const auto& pFormat : *m_pFrameFormats)
209         {
210             pFormat->dumpAsXml(pWriter);
211         }
212         (void)xmlTextWriterEndElement(pWriter);
213     }
214 
215     if (!m_FlyUndos.empty())
216     {
217         (void)xmlTextWriterStartElement(pWriter, BAD_CAST("m_FlyUndos"));
218         for (const auto& pFly : m_FlyUndos)
219         {
220             pFly->dumpAsXml(pWriter);
221         }
222         (void)xmlTextWriterEndElement(pWriter);
223     }
224 
225     (void)xmlTextWriterEndElement(pWriter);
226 }
227 
~SwUndoInserts()228 SwUndoInserts::~SwUndoInserts()
229 {
230     if (m_oUndoNodeIndex) // delete also the section from UndoNodes array
231     {
232         // Insert saves content in IconSection
233         SwNodes& rUNds = m_oUndoNodeIndex->GetNodes();
234         rUNds.Delete(*m_oUndoNodeIndex,
235             rUNds.GetEndOfExtras().GetIndex() - m_oUndoNodeIndex->GetIndex());
236         m_oUndoNodeIndex.reset();
237     }
238     m_pFrameFormats.reset();
239     m_pRedlineData.reset();
240 }
241 
242 // Undo Insert operation
243 //  It's important to note that Undo stores absolute node indexes. I.e. if during insertion, you insert nodes 31 to 33,
244 //  during Undo nodes with indices from 31 to 33 will be deleted. Undo doesn't check that nodes 31 to 33 are the same nodes which were inserted.
245 //  It just deletes them.
246 //  This may seem as bad programming practice, but Undo actions are strongly ordered. If you change your document in some way, a new Undo action is added.
247 //  During Undo most recent actions will be executed first. So during execution of particular Undo action indices will be correct.
248 //  But storing absolute indices leads to crashes if some action in Undo fails to roll back some modifications.
249 
250 //  Has following main steps:
251 //  1. m_FlyUndos removes flys anchored to first and last paragraph in Undo range.
252 //     This array may be empty.
253 //  2. DelContentIndex to delete footnotes, flys, bookmarks (see comment for this function)
254 //     Deleted flys are stored in pHistory array.
255 //     First and last paragraphs flys are not deleted by DelContentIndex!
256 //     For flys anchored to last paragraph, DelContentIndex re-anchors them to
257 //     the last paragraph that will remain after Undo.
258 //  3. MoveToUndoNds moves nodes to Undo nodes array and removes them from document.
259 //  4. Lastly (starting from if(pTextNode)), text from last paragraph is joined to last remaining paragraph and FormatColl for last paragraph is restored.
260 //     Format coll for last paragraph is removed during execution of UndoImpl
261 
UndoImpl(::sw::UndoRedoContext & rContext)262 void SwUndoInserts::UndoImpl(::sw::UndoRedoContext & rContext)
263 {
264     SwDoc& rDoc = rContext.GetDoc();
265     SwPaM& rPam = AddUndoRedoPaM(rContext);
266 
267     m_nNodeDiff = SwNodeOffset(0);
268 
269     if( IDocumentRedlineAccess::IsRedlineOn( GetRedlineFlags() ))
270         rDoc.getIDocumentRedlineAccess().DeleteRedline(rPam, true, RedlineType::Any);
271 
272     // if Point and Mark are different text nodes so a JoinNext has to be done
273     bool bJoinNext = m_nSttNode != m_nEndNode &&
274                 rPam.GetMark()->GetNode().GetTextNode() &&
275                 rPam.GetPoint()->GetNode().GetTextNode();
276 
277     // Is there any content? (loading from template does not have content)
278     if( m_nSttNode != m_nEndNode || m_nSttContent != m_nEndContent )
279     {
280         if( m_nSttNode != m_nEndNode )
281         {
282             SwTextNode* pTextNd = rDoc.GetNodes()[ m_nEndNode ]->GetTextNode();
283             if (pTextNd && pTextNd->GetText().getLength() == m_nEndContent)
284                 m_pLastNodeColl = pTextNd->GetTextColl();
285         }
286 
287         // tdf#128739 correct cursors but do not delete bookmarks yet
288         ::PaMCorrAbs(rPam, *rPam.End());
289 
290         SetPaM(rPam);
291     }
292 
293     // ... for consistency with the Insert File code in shellio.cxx, which
294     // creates separate SwUndoInsLayFormat for mysterious reasons, do this
295     // *before* anything else:
296     // after SetPaM but before MoveToUndoNds and DelContentIndex.
297     // note: there isn't an order dep wrt. initial Copy action because Undo
298     // overwrites the indexes but there is wrt. Redo because that uses the
299     // indexes
300     if (!m_FlyUndos.empty())
301     {
302         SwNodeOffset nTmp = rPam.GetPoint()->GetNodeIndex();
303         for (size_t n = m_FlyUndos.size(); 0 < n; --n)
304         {
305             m_FlyUndos[ n-1 ]->UndoImpl(rContext);
306         }
307         m_nNodeDiff += nTmp - rPam.GetPoint()->GetNodeIndex();
308     }
309 
310     if (m_nSttNode != m_nEndNode || m_nSttContent != m_nEndContent)
311     {
312         // are there Footnotes or ContentFlyFrames in text?
313         m_nSetPos = m_pHistory->Count();
314         SwNodeOffset nTmp = rPam.GetMark()->GetNodeIndex();
315         DelContentIndex(*rPam.GetMark(), *rPam.GetPoint(),
316             DelContentType::AllMask|DelContentType::ExcludeFlyAtStartEnd);
317         m_nNodeDiff += nTmp - rPam.GetMark()->GetNodeIndex();
318         if( *rPam.GetPoint() != *rPam.GetMark() )
319         {
320             m_oUndoNodeIndex.emplace(rDoc.GetNodes().GetEndOfContent());
321             MoveToUndoNds(rPam, &*m_oUndoNodeIndex);
322 
323             if (m_nDeleteTextNodes == SwNodeOffset(0))
324             {
325                 rPam.Move( fnMoveBackward, GoInContent );
326             }
327         }
328     }
329 
330     SwTextNode* pTextNode = rPam.GetPoint()->GetNode().GetTextNode();
331     if( !pTextNode )
332         return;
333 
334     if( !m_pTextFormatColl ) // if 0 than it's no TextNode -> delete
335     {
336         SwNodeIndex aDelIdx( *pTextNode );
337         assert(SwNodeOffset(0) < m_nDeleteTextNodes && m_nDeleteTextNodes < SwNodeOffset(3));
338         for (SwNodeOffset i(0); i < m_nDeleteTextNodes; ++i)
339         {
340             rPam.Move(fnMoveForward, GoInNode);
341         }
342         rPam.DeleteMark();
343 
344         for (SwNodeOffset i(0); i < m_nDeleteTextNodes; ++i)
345         {
346             RemoveIdxRel(aDelIdx.GetIndex() + i, *rPam.GetPoint());
347         }
348 
349         rDoc.GetNodes().Delete( aDelIdx, m_nDeleteTextNodes );
350     }
351     else
352     {
353         if( bJoinNext && pTextNode->CanJoinNext())
354         {
355             {
356                 RemoveIdxRel( pTextNode->GetIndex()+1,
357                     SwPosition( *pTextNode, pTextNode, pTextNode->GetText().getLength() ) );
358             }
359             pTextNode->JoinNext();
360         }
361         // reset all text attributes in the paragraph!
362         pTextNode->RstTextAttr( 0, pTextNode->Len(), 0, nullptr, true );
363 
364         pTextNode->ResetAllAttr();
365 
366         if (rDoc.GetTextFormatColls()->IsAlive(m_pTextFormatColl))
367             m_pTextFormatColl = static_cast<SwTextFormatColl*>(pTextNode->ChgFormatColl( m_pTextFormatColl )) ;
368 
369         m_pHistory->SetTmpEnd( m_nSetPos );
370         m_pHistory->TmpRollback(&rDoc, 0, false);
371     }
372 }
373 
374 // See SwUndoInserts::UndoImpl comments
375 // All actions here should be done in reverse order to what is done in SwUndoInserts::UndoImpl!
376 
RedoImpl(::sw::UndoRedoContext & rContext)377 void SwUndoInserts::RedoImpl(::sw::UndoRedoContext & rContext)
378 {
379     // position cursor onto REDO section
380     SwCursor& rPam(rContext.GetCursorSupplier().CreateNewShellCursor());
381     SwDoc& rDoc = rPam.GetDoc();
382     rPam.DeleteMark();
383     rPam.GetPoint()->Assign( m_nSttNode - m_nNodeDiff, m_nSttContent );
384     SwContentNode* pCNd = rPam.GetPointContentNode();
385 
386     SwTextFormatColl* pSavTextFormatColl = m_pTextFormatColl;
387     if( m_pTextFormatColl && pCNd && pCNd->IsTextNode() )
388         pSavTextFormatColl = static_cast<SwTextNode*>(pCNd)->GetTextColl();
389 
390     m_pHistory->SetTmpEnd( m_nSetPos );
391 
392     // retrieve start position for rollback
393     if( ( m_nSttNode != m_nEndNode || m_nSttContent != m_nEndContent ) && m_oUndoNodeIndex)
394     {
395         auto const pFlysAtInsPos(sw::GetFlysAnchoredAt(rDoc,
396             rPam.GetPoint()->GetNodeIndex(), false));
397 
398         ::std::optional<SwNodeIndex> oMvBkwrd = MovePtBackward(rPam);
399         bool const isMoveFlyAnchors(!oMvBkwrd // equivalent to bCanMoveBack
400             || m_oUndoNodeIndex->GetNode().IsTextNode()
401             || (oMvBkwrd->GetNode().IsStartNode()
402                 && m_oUndoNodeIndex->GetNode().IsSectionNode()));
403 
404         // re-insert content again (first detach m_oUndoNodeIndex!)
405         SwNodeOffset const nMvNd = m_oUndoNodeIndex->GetIndex();
406         m_oUndoNodeIndex.reset();
407         MoveFromUndoNds(rDoc, nMvNd, *rPam.GetMark());
408         if (m_nDeleteTextNodes != SwNodeOffset(0) || oMvBkwrd)
409         {
410             MovePtForward(rPam, ::std::move(oMvBkwrd));
411         }
412         rPam.Exchange();
413 
414         // at-char anchors post SplitNode are on index 0 of 2nd node and will
415         // remain there - move them back to the start (end would also work?)
416         if (pFlysAtInsPos && isMoveFlyAnchors)
417         {
418             for (SwFrameFormat * pFly : *pFlysAtInsPos)
419             {
420                 SwFormatAnchor const*const pAnchor = &pFly->GetAnchor();
421                 if (pAnchor->GetAnchorId() == RndStdIds::FLY_AT_CHAR)
422                 {
423                     SwFormatAnchor anchor(*pAnchor);
424                     anchor.SetAnchor( rPam.GetMark() );
425                     pFly->SetFormatAttr(anchor);
426                 }
427             }
428         }
429     }
430 
431     if (m_pTextFormatColl && rDoc.GetTextFormatColls()->IsAlive(m_pTextFormatColl))
432     {
433         SwTextNode* pTextNd = rPam.GetMark()->GetNode().GetTextNode();
434         if( pTextNd )
435             pTextNd->ChgFormatColl( m_pTextFormatColl );
436     }
437     m_pTextFormatColl = pSavTextFormatColl;
438 
439     if (m_pLastNodeColl && rDoc.GetTextFormatColls()->IsAlive(m_pLastNodeColl)
440         && rPam.GetPoint()->GetNode() != rPam.GetMark()->GetNode())
441     {
442         SwTextNode* pTextNd = rPam.GetPoint()->GetNode().GetTextNode();
443         if( pTextNd )
444             pTextNd->ChgFormatColl( m_pLastNodeColl );
445     }
446 
447     // tdf#108124 the SwHistoryChangeFlyAnchor/SwHistoryFlyCnt must run before
448     // m_FlyUndos as they were created by DelContentIndex()
449     m_pHistory->Rollback( &rDoc, m_nSetPos );
450 
451     // tdf#108124 (10/25/2017)
452     // During UNDO we call SwUndoInsLayFormat::UndoImpl in reverse order,
453     //  firstly for m_FlyUndos[ m_FlyUndos.size()-1 ], etc.
454     // As absolute node index of fly stored in SwUndoFlyBase::nNdPgPos we
455     //  should recover from Undo in direct order (last should be recovered first)
456     // During REDO we should recover Flys (Images) in direct order,
457     //  firstly m_FlyUndos[0], then with m_FlyUndos[1] index, etc.
458 
459     for (size_t n = 0; m_FlyUndos.size() > n; ++n)
460     {
461         m_FlyUndos[n]->RedoImpl(rContext);
462     }
463 
464     if( m_pRedlineData && IDocumentRedlineAccess::IsRedlineOn( GetRedlineFlags() ))
465     {
466         RedlineFlags eOld = rDoc.getIDocumentRedlineAccess().GetRedlineFlags();
467         rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld & ~RedlineFlags::Ignore );
468         rDoc.getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline( *m_pRedlineData, rPam ), true);
469         rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld );
470     }
471     else if( !( RedlineFlags::Ignore & GetRedlineFlags() ) &&
472             !rDoc.getIDocumentRedlineAccess().GetRedlineTable().empty() )
473         rDoc.getIDocumentRedlineAccess().SplitRedline(rPam);
474 }
475 
RepeatImpl(::sw::RepeatContext & rContext)476 void SwUndoInserts::RepeatImpl(::sw::RepeatContext & rContext)
477 {
478     SwPaM aPam( rContext.GetDoc().GetNodes().GetEndOfContent() );
479     SetPaM( aPam );
480     SwPaM & rRepeatPaM( rContext.GetRepeatPaM() );
481     aPam.GetDoc().getIDocumentContentOperations().CopyRange( aPam, *rRepeatPaM.GetPoint(), SwCopyFlags::CheckPosInFly);
482 }
483 
SwUndoInsDoc(const SwPaM & rPam)484 SwUndoInsDoc::SwUndoInsDoc( const SwPaM& rPam )
485     : SwUndoInserts( SwUndoId::INSDOKUMENT, rPam )
486 {
487 }
488 
SwUndoCpyDoc(const SwPaM & rPam)489 SwUndoCpyDoc::SwUndoCpyDoc( const SwPaM& rPam )
490     : SwUndoInserts( SwUndoId::COPY, rPam )
491 {
492 }
493 
494 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
495