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