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->get();
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=false)
1105  {
1106  // Divide the Sets (for selections in Nodes)
1107  const SfxItemSet* pCharSet = nullptr;
1108  const SfxItemSet* pOtherSet = nullptr;
1109  bool bDelete = false;
1110  bool bCharAttr = false;
1111  bool bOtherAttr = false;
1112 
1113  // Check, if we can work with rChgSet or if we have to create additional SfxItemSets
1114  if ( 1 == rChgSet.Count() )
1115  {
1116  SfxItemIter aIter( rChgSet );
1117  const SfxPoolItem* pItem = aIter.FirstItem();
1118  if (pItem && !IsInvalidItem(pItem))
1119  {
1120  const sal_uInt16 nWhich = pItem->Which();
1121 
1122  if ( isCHRATR(nWhich) ||
1123  (RES_TXTATR_CHARFMT == nWhich) ||
1124  (RES_TXTATR_INETFMT == nWhich) ||
1125  (RES_TXTATR_AUTOFMT == nWhich) ||
1126  (RES_TXTATR_UNKNOWN_CONTAINER == nWhich) )
1127  {
1128  pCharSet = &rChgSet;
1129  bCharAttr = true;
1130  }
1131 
1132  if ( isPARATR(nWhich)
1133  || isPARATR_LIST(nWhich)
1134  || isFRMATR(nWhich)
1135  || isGRFATR(nWhich)
1136  || isUNKNOWNATR(nWhich)
1137  || isDrawingLayerAttribute(nWhich) )
1138  {
1139  pOtherSet = &rChgSet;
1140  bOtherAttr = true;
1141  }
1142  }
1143  }
1144 
1145  // Build new itemset if either
1146  // - rChgSet.Count() > 1 or
1147  // - The attribute in rChgSet does not belong to one of the above categories
1148  if ( !bCharAttr && !bOtherAttr )
1149  {
1150  SfxItemSet* pTmpCharItemSet = new SfxItemSet(
1151  pDoc->GetAttrPool(),
1152  svl::Items<
1156  RES_TXTATR_UNKNOWN_CONTAINER>{});
1157 
1158  SfxItemSet* pTmpOtherItemSet = new SfxItemSet(
1159  pDoc->GetAttrPool(),
1160  svl::Items<
1163  // FillAttribute support:
1165 
1166  pTmpCharItemSet->Put( rChgSet );
1167  pTmpOtherItemSet->Put( rChgSet );
1168 
1169  pCharSet = pTmpCharItemSet;
1170  pOtherSet = pTmpOtherItemSet;
1171 
1172  bDelete = true;
1173  }
1174 
1175  SwHistory* pHistory = pUndo ? &pUndo->GetHistory() : nullptr;
1176  bool bRet = false;
1177  const SwPosition *pStt = rRg.Start(), *pEnd = rRg.End();
1178  SwContentNode* pNode = pStt->nNode.GetNode().GetContentNode();
1179 
1180  if( pNode && pNode->IsTextNode() )
1181  {
1182  // #i27615#
1183  if (rRg.IsInFrontOfLabel())
1184  {
1185  SwTextNode * pTextNd = pNode->GetTextNode();
1186  if (pLayout)
1187  {
1188  pTextNd = sw::GetParaPropsNode(*pLayout, *pTextNd);
1189  }
1190  SwNumRule * pNumRule = pTextNd->GetNumRule();
1191 
1192  if ( !pNumRule )
1193  {
1194  OSL_FAIL( "<InsAttr(..)> - PaM in front of label, but text node has no numbering rule set. This is a serious defect." );
1196  return false;
1197  }
1198 
1199  int nLevel = pTextNd->GetActualListLevel();
1200 
1201  if (nLevel < 0)
1202  nLevel = 0;
1203 
1204  if (nLevel >= MAXLEVEL)
1205  nLevel = MAXLEVEL - 1;
1206 
1207  SwNumFormat aNumFormat = pNumRule->Get(static_cast<sal_uInt16>(nLevel));
1208  SwCharFormat * pCharFormat =
1209  pDoc->FindCharFormatByName(aNumFormat.GetCharFormatName());
1210 
1211  if (pCharFormat)
1212  {
1213  if (pHistory)
1214  pHistory->Add(pCharFormat->GetAttrSet(), *pCharFormat);
1215 
1216  if ( pCharSet )
1217  pCharFormat->SetFormatAttr(*pCharSet);
1218  }
1219 
1221  return true;
1222  }
1223 
1224  const SwIndex& rSt = pStt->nContent;
1225 
1226  // Attributes without an end do not have a range
1227  if ( !bCharAttr && !bOtherAttr )
1228  {
1229  SfxItemSet aTextSet( pDoc->GetAttrPool(),
1231  aTextSet.Put( rChgSet );
1232  if( aTextSet.Count() )
1233  {
1234  SwRegHistory history( pNode, *pNode, pHistory );
1235  bRet = history.InsertItems(
1236  aTextSet, rSt.GetIndex(), rSt.GetIndex(), nFlags ) || bRet;
1237 
1240  {
1241  SwPaM aPam( pStt->nNode, pStt->nContent.GetIndex()-1,
1242  pStt->nNode, pStt->nContent.GetIndex() );
1243 
1244  if( pUndo )
1245  pUndo->SaveRedlineData( aPam, true );
1246 
1247  if( pDoc->getIDocumentRedlineAccess().IsRedlineOn() )
1249  else
1250  pDoc->getIDocumentRedlineAccess().SplitRedline( aPam );
1251  }
1252  }
1253  }
1254 
1255  // TextAttributes with an end never expand their range
1256  if ( !bCharAttr && !bOtherAttr )
1257  {
1258  // CharFormat and URL attributes are treated separately!
1259  // TEST_TEMP ToDo: AutoFormat!
1260  SfxItemSet aTextSet(
1261  pDoc->GetAttrPool(),
1262  svl::Items<
1265  RES_TXTATR_INPUTFIELD, RES_TXTATR_INPUTFIELD>{});
1266 
1267  aTextSet.Put( rChgSet );
1268  if( aTextSet.Count() )
1269  {
1270  const sal_Int32 nInsCnt = rSt.GetIndex();
1271  const sal_Int32 nEnd = pStt->nNode == pEnd->nNode
1272  ? pEnd->nContent.GetIndex()
1273  : pNode->Len();
1274  SwRegHistory history( pNode, *pNode, pHistory );
1275  bRet = history.InsertItems( aTextSet, nInsCnt, nEnd, nFlags )
1276  || bRet;
1277 
1280  {
1281  // Was text content inserted? (RefMark/TOXMarks without an end)
1282  bool bTextIns = nInsCnt != rSt.GetIndex();
1283  // Was content inserted or set over the selection?
1284  SwPaM aPam( pStt->nNode, bTextIns ? nInsCnt + 1 : nEnd,
1285  pStt->nNode, nInsCnt );
1286  if( pUndo )
1287  pUndo->SaveRedlineData( aPam, bTextIns );
1288 
1289  if( pDoc->getIDocumentRedlineAccess().IsRedlineOn() )
1291  new SwRangeRedline(
1292  bTextIns ? RedlineType::Insert : RedlineType::Format, aPam ),
1293  true);
1294  else if( bTextIns )
1295  pDoc->getIDocumentRedlineAccess().SplitRedline( aPam );
1296  }
1297  }
1298  }
1299  }
1300 
1301  // We always have to set the auto flag for PageDescs that are set at the Node!
1302  if( pOtherSet && pOtherSet->Count() )
1303  {
1304  SwTableNode* pTableNd;
1305  const SwFormatPageDesc* pDesc;
1306  if( SfxItemState::SET == pOtherSet->GetItemState( RES_PAGEDESC,
1307  false, reinterpret_cast<const SfxPoolItem**>(&pDesc) ))
1308  {
1309  if( pNode )
1310  {
1311  // Set auto flag. Only in the template it's without auto!
1312  SwFormatPageDesc aNew( *pDesc );
1313 
1314  // Tables now also know line breaks
1315  if( !(nFlags & SetAttrMode::APICALL) &&
1316  nullptr != ( pTableNd = pNode->FindTableNode() ) )
1317  {
1318  SwTableNode* pCurTableNd = pTableNd;
1319  while ( nullptr != ( pCurTableNd = pCurTableNd->StartOfSectionNode()->FindTableNode() ) )
1320  pTableNd = pCurTableNd;
1321 
1322  // set the table format
1323  SwFrameFormat* pFormat = pTableNd->GetTable().GetFrameFormat();
1324  SwRegHistory aRegH( pFormat, *pTableNd, pHistory );
1325  pFormat->SetFormatAttr( aNew );
1326  bRet = true;
1327  }
1328  else
1329  {
1330  SwContentNode * pFirstNode(pNode);
1331  if (pLayout && pLayout->IsHideRedlines())
1332  {
1333  pFirstNode = sw::GetFirstAndLastNode(*pLayout, pStt->nNode).first;
1334  }
1335  SwRegHistory aRegH( pFirstNode, *pFirstNode, pHistory );
1336  bRet = pFirstNode->SetAttr( aNew ) || bRet;
1337  }
1338  }
1339 
1340  // bOtherAttr = true means that pOtherSet == rChgSet. In this case
1341  // we know, that there is only one attribute in pOtherSet. We cannot
1342  // perform the following operations, instead we return:
1343  if ( bOtherAttr )
1344  return bRet;
1345 
1346  const_cast<SfxItemSet*>(pOtherSet)->ClearItem( RES_PAGEDESC );
1347  if( !pOtherSet->Count() )
1348  {
1350  return bRet;
1351  }
1352  }
1353 
1354  // Tables now also know line breaks
1355  const SvxFormatBreakItem* pBreak;
1356  if( pNode && !(nFlags & SetAttrMode::APICALL) &&
1357  nullptr != (pTableNd = pNode->FindTableNode() ) &&
1358  SfxItemState::SET == pOtherSet->GetItemState( RES_BREAK,
1359  false, reinterpret_cast<const SfxPoolItem**>(&pBreak) ) )
1360  {
1361  SwTableNode* pCurTableNd = pTableNd;
1362  while ( nullptr != ( pCurTableNd = pCurTableNd->StartOfSectionNode()->FindTableNode() ) )
1363  pTableNd = pCurTableNd;
1364 
1365  // set the table format
1366  SwFrameFormat* pFormat = pTableNd->GetTable().GetFrameFormat();
1367  SwRegHistory aRegH( pFormat, *pTableNd, pHistory );
1368  pFormat->SetFormatAttr( *pBreak );
1369  bRet = true;
1370 
1371  // bOtherAttr = true means that pOtherSet == rChgSet. In this case
1372  // we know, that there is only one attribute in pOtherSet. We cannot
1373  // perform the following operations, instead we return:
1374  if ( bOtherAttr )
1375  return bRet;
1376 
1377  const_cast<SfxItemSet*>(pOtherSet)->ClearItem( RES_BREAK );
1378  if( !pOtherSet->Count() )
1379  {
1381  return bRet;
1382  }
1383  }
1384 
1385  {
1386  // If we have a PoolNumRule, create it if needed
1387  const SwNumRuleItem* pRule;
1388  sal_uInt16 nPoolId=0;
1389  if( SfxItemState::SET == pOtherSet->GetItemState( RES_PARATR_NUMRULE,
1390  false, reinterpret_cast<const SfxPoolItem**>(&pRule) ) &&
1391  !pDoc->FindNumRulePtr( pRule->GetValue() ) &&
1395  }
1396  }
1397 
1398  SfxItemSet firstSet(pDoc->GetAttrPool(),
1400  if (pOtherSet && pOtherSet->Count())
1401  { // actually only RES_BREAK is possible here...
1402  firstSet.Put(*pOtherSet);
1403  }
1404  SfxItemSet propsSet(pDoc->GetAttrPool(),
1408  if (pOtherSet && pOtherSet->Count())
1409  {
1410  propsSet.Put(*pOtherSet);
1411  }
1412 
1413  if( !rRg.HasMark() ) // no range
1414  {
1415  if( !pNode )
1416  {
1418  return bRet;
1419  }
1420 
1421  if( pNode->IsTextNode() && pCharSet && pCharSet->Count() )
1422  {
1423  SwTextNode* pTextNd = pNode->GetTextNode();
1424  const SwIndex& rSt = pStt->nContent;
1425  sal_Int32 nMkPos, nPtPos = rSt.GetIndex();
1426  const OUString& rStr = pTextNd->GetText();
1427 
1428  // Special case: if the Cursor is located within a URL attribute, we take over it's area
1429  SwTextAttr const*const pURLAttr(
1430  pTextNd->GetTextAttrAt(rSt.GetIndex(), RES_TXTATR_INETFMT));
1431  if (pURLAttr && !pURLAttr->GetINetFormat().GetValue().isEmpty())
1432  {
1433  nMkPos = pURLAttr->GetStart();
1434  nPtPos = *pURLAttr->End();
1435  }
1436  else
1437  {
1438  assert(g_pBreakIt && g_pBreakIt->GetBreakIter().is());
1439  Boundary aBndry = g_pBreakIt->GetBreakIter()->getWordBoundary(
1440  pTextNd->GetText(), nPtPos,
1441  g_pBreakIt->GetLocale( pTextNd->GetLang( nPtPos ) ),
1442  WordType::ANY_WORD /*ANYWORD_IGNOREWHITESPACES*/,
1443  true);
1444 
1445  if( aBndry.startPos < nPtPos && nPtPos < aBndry.endPos )
1446  {
1447  nMkPos = aBndry.startPos;
1448  nPtPos = aBndry.endPos;
1449  }
1450  else
1451  nPtPos = nMkPos = rSt.GetIndex();
1452  }
1453 
1454  // Remove the overriding attributes from the SwpHintsArray,
1455  // if the selection spans across the whole paragraph.
1456  // These attributes are inserted as FormatAttributes and
1457  // never override the TextAttributes!
1458  if( !(nFlags & SetAttrMode::DONTREPLACE ) &&
1459  pTextNd->HasHints() && !nMkPos && nPtPos == rStr.getLength())
1460  {
1461  SwIndex aSt( pTextNd );
1462  if( pHistory )
1463  {
1464  // Save all attributes for the Undo.
1465  SwRegHistory aRHst( *pTextNd, pHistory );
1466  pTextNd->GetpSwpHints()->Register( &aRHst );
1467  pTextNd->RstTextAttr( aSt, nPtPos, 0, pCharSet );
1468  if( pTextNd->GetpSwpHints() )
1469  pTextNd->GetpSwpHints()->DeRegister();
1470  }
1471  else
1472  pTextNd->RstTextAttr( aSt, nPtPos, 0, pCharSet );
1473  }
1474 
1475  // the SwRegHistory inserts the attribute into the TextNode!
1476  SwRegHistory history( pNode, *pNode, pHistory );
1477  bRet = history.InsertItems( *pCharSet, nMkPos, nPtPos, nFlags )
1478  || bRet;
1479 
1480  if( pDoc->getIDocumentRedlineAccess().IsRedlineOn() )
1481  {
1482  SwPaM aPam( *pNode, nMkPos, *pNode, nPtPos );
1483 
1484  if( pUndo )
1485  pUndo->SaveRedlineData( aPam, false );
1487  }
1488  }
1489  if( pOtherSet && pOtherSet->Count() )
1490  {
1491  // Need to check for unique item for DrawingLayer items of type NameOrIndex
1492  // and evtl. correct that item to ensure unique names for that type. This call may
1493  // modify/correct entries inside of the given SfxItemSet
1494  SfxItemSet aTempLocalCopy(*pOtherSet);
1495 
1496  pDoc->CheckForUniqueItemForLineFillNameOrIndex(aTempLocalCopy);
1497  bRet = lcl_ApplyOtherSet(*pNode, pHistory, aTempLocalCopy, firstSet, propsSet, pLayout) || bRet;
1498  }
1499 
1501  return bRet;
1502  }
1503 
1504  if( pDoc->getIDocumentRedlineAccess().IsRedlineOn() && pCharSet && pCharSet->Count() )
1505  {
1506  if( pUndo )
1507  pUndo->SaveRedlineData( rRg, false );
1509  }
1510 
1511  /* now if range */
1512  sal_uLong nNodes = 0;
1513 
1514  SwNodeIndex aSt( pDoc->GetNodes() );
1515  SwNodeIndex aEnd( pDoc->GetNodes() );
1516  SwIndex aCntEnd( pEnd->nContent );
1517 
1518  if( pNode )
1519  {
1520  const sal_Int32 nLen = pNode->Len();
1521  if( pStt->nNode != pEnd->nNode )
1522  aCntEnd.Assign( pNode, nLen );
1523 
1524  if( pStt->nContent.GetIndex() != 0 || aCntEnd.GetIndex() != nLen )
1525  {
1526  // the SwRegHistory inserts the attribute into the TextNode!
1527  if( pNode->IsTextNode() && pCharSet && pCharSet->Count() )
1528  {
1529  SwRegHistory history( pNode, *pNode, pHistory );
1530  bRet = history.InsertItems(*pCharSet,
1531  pStt->nContent.GetIndex(), aCntEnd.GetIndex(), nFlags)
1532  || bRet;
1533  }
1534 
1535  if( pOtherSet && pOtherSet->Count() )
1536  {
1537  bRet = lcl_ApplyOtherSet(*pNode, pHistory, *pOtherSet, firstSet, propsSet, pLayout) || bRet;
1538  }
1539 
1540  // Only selection in a Node.
1541  if( pStt->nNode == pEnd->nNode )
1542  {
1543  //The data parameter flag: bExpandCharToPara, comes from the data member of SwDoc,
1544  //which is set in SW MS Word Binary filter WW8ImplRreader. With this flag on, means that
1545  //current setting attribute set is a character range properties set and comes from a MS Word
1546  //binary file, and the setting range include a paragraph end position (0X0D);
1547  //more specifications, as such property inside the character range properties set recorded in
1548  //MS Word binary file are dealed and inserted into data model (SwDoc) one by one, so we
1549  //only dealing the scenario that the char properties set with 1 item inside;
1550 
1551  if (bExpandCharToPara && pCharSet && pCharSet->Count() ==1 )
1552  {
1553  SwTextNode* pCurrentNd = pStt->nNode.GetNode().GetTextNode();
1554 
1555  if (pCurrentNd)
1556  {
1557  pCurrentNd->TryCharSetExpandToNum(*pCharSet);
1558 
1559  }
1560  }
1562  return bRet;
1563  }
1564  ++nNodes;
1565  aSt.Assign( pStt->nNode.GetNode(), +1 );
1566  }
1567  else
1568  aSt = pStt->nNode;
1569  aCntEnd = pEnd->nContent; // aEnd was changed!
1570  }
1571  else
1572  aSt.Assign( pStt->nNode.GetNode(), +1 );
1573 
1574  // aSt points to the first full Node now
1575 
1576  /*
1577  * The selection spans more than one Node.
1578  */
1579  if( pStt->nNode < pEnd->nNode )
1580  {
1581  pNode = pEnd->nNode.GetNode().GetContentNode();
1582  if(pNode)
1583  {
1584  if( aCntEnd.GetIndex() != pNode->Len() )
1585  {
1586  // the SwRegHistory inserts the attribute into the TextNode!
1587  if( pNode->IsTextNode() && pCharSet && pCharSet->Count() )
1588  {
1589  SwRegHistory history( pNode, *pNode, pHistory );
1590  (void)history.InsertItems(*pCharSet,
1591  0, aCntEnd.GetIndex(), nFlags);
1592  }
1593 
1594  if( pOtherSet && pOtherSet->Count() )
1595  {
1596  lcl_ApplyOtherSet(*pNode, pHistory, *pOtherSet, firstSet, propsSet, pLayout);
1597  }
1598 
1599  ++nNodes;
1600  aEnd = pEnd->nNode;
1601  }
1602  else
1603  aEnd.Assign( pEnd->nNode.GetNode(), +1 );
1604  }
1605  else
1606  aEnd = pEnd->nNode;
1607  }
1608  else
1609  aEnd.Assign( pEnd->nNode.GetNode(), +1 );
1610 
1611  // aEnd points BEHIND the last full node now
1612 
1613  /* Edit the fully selected Nodes. */
1614  // Reset all attributes from the set!
1615  if( pCharSet && pCharSet->Count() && !( SetAttrMode::DONTREPLACE & nFlags ) )
1616  {
1618  pStt, pEnd, pHistory, pCharSet, pLayout);
1620  }
1621 
1622  bool bCreateSwpHints = pCharSet && (
1623  SfxItemState::SET == pCharSet->GetItemState( RES_TXTATR_CHARFMT, false ) ||
1624  SfxItemState::SET == pCharSet->GetItemState( RES_TXTATR_INETFMT, false ) );
1625 
1626  for (SwNodeIndex current = aSt; current < aEnd; ++current)
1627  {
1628  SwTextNode *const pTNd = current.GetNode().GetTextNode();
1629  if (!pTNd)
1630  continue;
1631 
1632  if (pLayout && pLayout->IsHideRedlines()
1634  { // not really sure what to do here, but applying to hidden
1635  continue; // nodes doesn't make sense...
1636  }
1637 
1638  if( pHistory )
1639  {
1640  SwRegHistory aRegH( pTNd, *pTNd, pHistory );
1641 
1642  if (pCharSet && pCharSet->Count())
1643  {
1644  SwpHints *pSwpHints = bCreateSwpHints ? &pTNd->GetOrCreateSwpHints()
1645  : pTNd->GetpSwpHints();
1646  if( pSwpHints )
1647  pSwpHints->Register( &aRegH );
1648 
1649  pTNd->SetAttr(*pCharSet, 0, pTNd->GetText().getLength(), nFlags);
1650  if( pSwpHints )
1651  pSwpHints->DeRegister();
1652  }
1653  }
1654  else
1655  {
1656  if (pCharSet && pCharSet->Count())
1657  pTNd->SetAttr(*pCharSet, 0, pTNd->GetText().getLength(), nFlags);
1658  }
1659  ++nNodes;
1660  }
1661 
1662  if (pOtherSet && pOtherSet->Count())
1663  {
1664  for (; aSt < aEnd; ++aSt)
1665  {
1666  pNode = aSt.GetNode().GetContentNode();
1667  if (!pNode)
1668  continue;
1669 
1670  lcl_ApplyOtherSet(*pNode, pHistory, *pOtherSet, firstSet, propsSet, pLayout, &aSt);
1671  ++nNodes;
1672  }
1673  }
1674 
1675  //The data parameter flag: bExpandCharToPara, comes from the data member of SwDoc,
1676  //which is set in SW MS Word Binary filter WW8ImplRreader. With this flag on, means that
1677  //current setting attribute set is a character range properties set and comes from a MS Word
1678  //binary file, and the setting range include a paragraph end position (0X0D);
1679  //more specifications, as such property inside the character range properties set recorded in
1680  //MS Word binary file are dealed and inserted into data model (SwDoc) one by one, so we
1681  //only dealing the scenario that the char properties set with 1 item inside;
1682  if (bExpandCharToPara && pCharSet && pCharSet->Count() ==1)
1683  {
1684  SwPosition aStartPos (*rRg.Start());
1685  SwPosition aEndPos (*rRg.End());
1686 
1687  if (aEndPos.nNode.GetNode().GetTextNode() && aEndPos.nContent != aEndPos.nNode.GetNode().GetTextNode()->Len())
1688  aEndPos.nNode--;
1689 
1690  sal_uLong nStart = aStartPos.nNode.GetIndex();
1691  sal_uLong nEnd = aEndPos.nNode.GetIndex();
1692  for(; nStart <= nEnd; ++nStart)
1693  {
1694  SwNode* pNd = pDoc->GetNodes()[ nStart ];
1695  if (!pNd || !pNd->IsTextNode())
1696  continue;
1697  SwTextNode *pCurrentNd = pNd->GetTextNode();
1698  pCurrentNd->TryCharSetExpandToNum(*pCharSet);
1699  }
1700  }
1701 
1703  return (nNodes != 0) || bRet;
1704  }
1705 }
1706 
1707 namespace sw
1708 {
1709 
1711 {
1712 }
1713 
1714 // Copy an area into this document or into another document
1715 bool
1716 DocumentContentOperationsManager::CopyRange( SwPaM& rPam, SwPosition& rPos, const bool bCopyAll, bool bCheckPos ) const
1717 {
1718  const SwPosition *pStt = rPam.Start(), *pEnd = rPam.End();
1719 
1720  SwDoc* pDoc = rPos.nNode.GetNode().GetDoc();
1721  bool bColumnSel = pDoc->IsClipBoard() && pDoc->IsColumnSelection();
1722 
1723  // Catch if there's no copy to do
1724  if( !rPam.HasMark() || ( *pStt >= *pEnd && !bColumnSel ) )
1725  return false;
1726 
1727  // Prevent copying in Flys that are anchored in the area
1728  if( pDoc == &m_rDoc && bCheckPos )
1729  {
1730  // Correct the Start-/EndNode
1731  sal_uLong nStt = pStt->nNode.GetIndex(),
1732  nEnd = pEnd->nNode.GetIndex(),
1733  nDiff = nEnd - nStt +1;
1734  SwNode* pNd = m_rDoc.GetNodes()[ nStt ];
1735  if( pNd->IsContentNode() && pStt->nContent.GetIndex() )
1736  {
1737  ++nStt;
1738  --nDiff;
1739  }
1740  if( (pNd = m_rDoc.GetNodes()[ nEnd ])->IsContentNode() &&
1741  static_cast<SwContentNode*>(pNd)->Len() != pEnd->nContent.GetIndex() )
1742  {
1743  --nEnd;
1744  --nDiff;
1745  }
1746  if( nDiff &&
1747  lcl_ChkFlyFly( pDoc, nStt, nEnd, rPos.nNode.GetIndex() ) )
1748  {
1749  return false;
1750  }
1751  }
1752 
1753  SwPaM* pRedlineRange = nullptr;
1754  if( pDoc->getIDocumentRedlineAccess().IsRedlineOn() ||
1756  pRedlineRange = new SwPaM( rPos );
1757 
1759 
1760  bool bRet = false;
1761 
1762  if( pDoc != &m_rDoc )
1763  { // ordinary copy
1764  bRet = CopyImpl( rPam, rPos, true, bCopyAll, pRedlineRange );
1765  }
1766  else if( ! ( *pStt <= rPos && rPos < *pEnd &&
1767  ( pStt->nNode != pEnd->nNode ||
1768  !pStt->nNode.GetNode().IsTextNode() )) )
1769  {
1770  // Copy to a position outside of the area, or copy a single TextNode
1771  // Do an ordinary copy
1772  bRet = CopyImpl( rPam, rPos, true, bCopyAll, pRedlineRange );
1773  }
1774  else
1775  {
1776  // Copy the area in itself
1777  // Special case for handling an area with several nodes,
1778  // or a single node that is not a TextNode
1779  OSL_ENSURE( &m_rDoc == pDoc, " invalid copy branch!" );
1780  assert(!"mst: this is assumed to be dead code");
1782 
1783  // Then copy the area to the underlying document area
1784  // (with start/end nodes clamped) and move them to
1785  // the desired position.
1786 
1787  std::unique_ptr<SwUndoCpyDoc> pUndo;
1788  // Save the Undo area
1789  SwPaM aPam( rPos );
1790  if (pDoc->GetIDocumentUndoRedo().DoesUndo())
1791  {
1792  pDoc->GetIDocumentUndoRedo().ClearRedo();
1793  pUndo.reset(new SwUndoCpyDoc( aPam ));
1794  }
1795 
1796  {
1797  ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo());
1800  aPam.GetPoint()->nNode = *pSttNd->EndOfSectionNode();
1801  // copy without Frames
1802  pDoc->GetDocumentContentOperationsManager().CopyImpl( rPam, *aPam.GetPoint(), false, bCopyAll, nullptr );
1803 
1804  aPam.GetPoint()->nNode = pDoc->GetNodes().GetEndOfAutotext();
1805  aPam.SetMark();
1806  SwContentNode* pNode = SwNodes::GoPrevious( &aPam.GetMark()->nNode );
1807  pNode->MakeEndIndex( &aPam.GetMark()->nContent );
1808 
1809  aPam.GetPoint()->nNode = *aPam.GetNode().StartOfSectionNode();
1810  pNode = pDoc->GetNodes().GoNext( &aPam.GetPoint()->nNode );
1811  pNode->MakeStartIndex( &aPam.GetPoint()->nContent );
1812  // move to desired position
1814 
1815  pNode = aPam.GetContentNode();
1816  *aPam.GetPoint() = rPos; // Move the cursor for Undo
1817  aPam.SetMark(); // also move the Mark
1818  aPam.DeleteMark(); // But don't mark any area
1819  pDoc->getIDocumentContentOperations().DeleteSection( pNode ); // Delete the area again
1820  }
1821 
1822  // if Undo is enabled, store the insertion range
1823  if (pDoc->GetIDocumentUndoRedo().DoesUndo())
1824  {
1825  pUndo->SetInsertRange( aPam );
1826  pDoc->GetIDocumentUndoRedo().AppendUndo(std::move(pUndo));
1827  }
1828 
1829  if( pRedlineRange )
1830  {
1831  pRedlineRange->SetMark();
1832  *pRedlineRange->GetPoint() = *aPam.GetPoint();
1833  *pRedlineRange->GetMark() = *aPam.GetMark();
1834  }
1835 
1836  pDoc->getIDocumentState().SetModified();
1837  bRet = true;
1838  }
1839 
1841  if( pRedlineRange )
1842  {
1843  if( pDoc->getIDocumentRedlineAccess().IsRedlineOn() )
1844  pDoc->getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline( RedlineType::Insert, *pRedlineRange ), true);
1845  else
1846  pDoc->getIDocumentRedlineAccess().SplitRedline( *pRedlineRange );
1847  delete pRedlineRange;
1848  }
1849 
1850  return bRet;
1851 }
1852 
1856 {
1857  assert(pNode && "Didn't pass a Node.");
1858 
1859  SwStartNode* pSttNd = pNode->IsStartNode() ? static_cast<SwStartNode*>(pNode)
1860  : pNode->StartOfSectionNode();
1861  SwNodeIndex aSttIdx( *pSttNd ), aEndIdx( *pNode->EndOfSectionNode() );
1862 
1863  // delete all Flys, Bookmarks, ...
1864  DelFlyInRange( aSttIdx, aEndIdx );
1866  DelBookmarks(aSttIdx, aEndIdx);
1867 
1868  {
1869  // move all Cursor/StackCursor/UnoCursor out of the to-be-deleted area
1870  SwNodeIndex aMvStt( aSttIdx, 1 );
1871  SwDoc::CorrAbs( aMvStt, aEndIdx, SwPosition( aSttIdx ), true );
1872  }
1873 
1874  m_rDoc.GetNodes().DelNodes( aSttIdx, aEndIdx.GetIndex() - aSttIdx.GetIndex() + 1 );
1875 }
1876 
1878 {
1879  lcl_DoWithBreaks( *this, rPam, &DocumentContentOperationsManager::DeleteRangeImpl );
1880 
1883  {
1885  }
1886 }
1887 
1889 {
1890  const SwPosition &rStt = *rPam.Start(), &rEnd = *rPam.End();
1891  const SwNode* pNd = &rStt.nNode.GetNode();
1892  sal_uInt32 nSectDiff = pNd->StartOfSectionNode()->EndOfSectionIndex() -
1893  pNd->StartOfSectionIndex();
1894  sal_uInt32 nNodeDiff = rEnd.nNode.GetIndex() - rStt.nNode.GetIndex();
1895 
1896  if ( nSectDiff-2 <= nNodeDiff || m_rDoc.getIDocumentRedlineAccess().IsRedlineOn() ||
1897  /* #i9185# Prevent getting the node after the end node (see below) */
1898  rEnd.nNode.GetIndex() + 1 == m_rDoc.GetNodes().Count() )
1899  {
1900  return false;
1901  }
1902 
1903  // Move hard page brakes to the following Node.
1904  bool bSavePageBreak = false, bSavePageDesc = false;
1905 
1906  /* #i9185# This whould lead to a segmentation fault if not caught above. */
1907  sal_uLong nNextNd = rEnd.nNode.GetIndex() + 1;
1908  SwTableNode *const pTableNd = m_rDoc.GetNodes()[ nNextNd ]->GetTableNode();
1909 
1910  if( pTableNd && pNd->IsContentNode() )
1911  {
1912  SwFrameFormat* pTableFormat = pTableNd->GetTable().GetFrameFormat();
1913 
1914  {
1915  const SfxPoolItem *pItem;
1916  const SfxItemSet* pSet = static_cast<const SwContentNode*>(pNd)->GetpSwAttrSet();
1917  if( pSet && SfxItemState::SET == pSet->GetItemState( RES_PAGEDESC,
1918  false, &pItem ) )
1919  {
1920  pTableFormat->SetFormatAttr( *pItem );
1921  bSavePageDesc = true;
1922  }
1923 
1924  if( pSet && SfxItemState::SET == pSet->GetItemState( RES_BREAK,
1925  false, &pItem ) )
1926  {
1927  pTableFormat->SetFormatAttr( *pItem );
1928  bSavePageBreak = true;
1929  }
1930  }
1931  }
1932 
1933  bool const bDoesUndo = m_rDoc.GetIDocumentUndoRedo().DoesUndo();
1934  if( bDoesUndo )
1935  {
1936  if( !rPam.HasMark() )
1937  rPam.SetMark();
1938  else if( rPam.GetPoint() == &rStt )
1939  rPam.Exchange();
1940  rPam.GetPoint()->nNode++;
1941 
1942  SwContentNode *pTmpNode = rPam.GetPoint()->nNode.GetNode().GetContentNode();
1943  rPam.GetPoint()->nContent.Assign( pTmpNode, 0 );
1944  bool bGoNext = (nullptr == pTmpNode);
1945  pTmpNode = rPam.GetMark()->nNode.GetNode().GetContentNode();
1946  rPam.GetMark()->nContent.Assign( pTmpNode, 0 );
1947 
1949 
1950  SwPaM aDelPam( *rPam.GetMark(), *rPam.GetPoint() );
1951  {
1952  SwPosition aTmpPos( *aDelPam.GetPoint() );
1953  if( bGoNext )
1954  {
1955  pTmpNode = m_rDoc.GetNodes().GoNext( &aTmpPos.nNode );
1956  aTmpPos.nContent.Assign( pTmpNode, 0 );
1957  }
1958  ::PaMCorrAbs( aDelPam, aTmpPos );
1959  }
1960 
1961  std::unique_ptr<SwUndoDelete> pUndo(new SwUndoDelete( aDelPam, true ));
1962 
1963  *rPam.GetPoint() = *aDelPam.GetPoint();
1964  pUndo->SetPgBrkFlags( bSavePageBreak, bSavePageDesc );
1965  m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::move(pUndo));
1966  rPam.DeleteMark();
1967  }
1968  else
1969  {
1970  SwNodeRange aRg( rStt.nNode, rEnd.nNode );
1971  rPam.Normalize(false);
1972 
1973  // Try to move past the End
1974  if( !rPam.Move( fnMoveForward, GoInNode ) )
1975  {
1976  // Fair enough, at the Beginning then
1977  rPam.Exchange();
1978  if( !rPam.Move( fnMoveBackward, GoInNode ))
1979  {
1980  SAL_WARN("sw.core", "DelFullPara: no more Nodes");
1981  return false;
1982  }
1983  }
1984  // move bookmarks, redlines etc.
1985  if (aRg.aStart == aRg.aEnd) // only first CorrAbs variant handles this
1986  {
1987  m_rDoc.CorrAbs( aRg.aStart, *rPam.GetPoint(), 0, true );
1988  }
1989  else
1990  {
1991  SwDoc::CorrAbs( aRg.aStart, aRg.aEnd, *rPam.GetPoint(), true );
1992  }
1993 
1994  // What's with Flys?
1995  {
1996  // If there are FlyFrames left, delete these too
1997  for( size_t n = 0; n < m_rDoc.GetSpzFrameFormats()->size(); ++n )
1998  {
1999  SwFrameFormat* pFly = (*m_rDoc.GetSpzFrameFormats())[n];
2000  const SwFormatAnchor* pAnchor = &pFly->GetAnchor();
2001  SwPosition const*const pAPos = pAnchor->GetContentAnchor();
2002  if (pAPos &&
2003  ((RndStdIds::FLY_AT_PARA == pAnchor->GetAnchorId()) ||
2004  (RndStdIds::FLY_AT_CHAR == pAnchor->GetAnchorId())) &&
2005  aRg.aStart <= pAPos->nNode && pAPos->nNode <= aRg.aEnd )
2006  {
2008  --n;
2009  }
2010  }
2011  }
2012 
2013  rPam.DeleteMark();
2014  m_rDoc.GetNodes().Delete( aRg.aStart, nNodeDiff+1 );
2015  }
2017 
2018  return true;
2019 }
2020 
2021 // #i100466# Add handling of new optional parameter <bForceJoinNext>
2023  const bool bForceJoinNext )
2024 {
2025  if ( lcl_StrLenOverflow( rPam ) )
2026  return false;
2027 
2028  return lcl_DoWithBreaks( *this, rPam, (m_rDoc.getIDocumentRedlineAccess().IsRedlineOn())
2031  bForceJoinNext );
2032 }
2033 
2034 // It seems that this is mostly used by SwDoc internals; the only
2035 // way to call this from the outside seems to be the special case in
2036 // SwDoc::CopyRange (but I have not managed to actually hit that case).
2038 {
2039  // nothing moved: return
2040  const SwPosition *pStt = rPaM.Start(), *pEnd = rPaM.End();
2041  if( !rPaM.HasMark() || *pStt >= *pEnd || (*pStt <= rPos && rPos < *pEnd))
2042  return false;
2043 
2044  // Save the paragraph anchored Flys, so that they can be moved.
2045  SaveFlyArr aSaveFlyArr;
2046  SaveFlyInRange( rPaM, rPos.nNode, aSaveFlyArr, bool( SwMoveFlags::ALLFLYS & eMvFlags ) );
2047 
2048  // save redlines (if DOC_MOVEREDLINES is used)
2049  SaveRedlines_t aSaveRedl;
2051  {
2052  lcl_SaveRedlines( rPaM, aSaveRedl );
2053 
2054  // #i17764# unfortunately, code below relies on undos being
2055  // in a particular order, and presence of bookmarks
2056  // will change this order. Hence, we delete bookmarks
2057  // here without undo.
2058  ::sw::UndoGuard const undoGuard(m_rDoc.GetIDocumentUndoRedo());
2059  DelBookmarks(
2060  pStt->nNode,
2061  pEnd->nNode,
2062  nullptr,
2063  &pStt->nContent,
2064  &pEnd->nContent);
2065  }
2066 
2067  bool bUpdateFootnote = false;
2068  SwFootnoteIdxs aTmpFntIdx;
2069 
2070  std::unique_ptr<SwUndoMove> pUndoMove;
2072  {
2074  pUndoMove.reset(new SwUndoMove( rPaM, rPos ));
2075  pUndoMove->SetMoveRedlines( eMvFlags == SwMoveFlags::REDLINES );
2076  }
2077  else
2078  {
2079  bUpdateFootnote = lcl_SaveFootnote( pStt->nNode, pEnd->nNode, rPos.nNode,
2080  m_rDoc.GetFootnoteIdxs(), aTmpFntIdx,
2081  &pStt->nContent, &pEnd->nContent );
2082  }
2083 
2084  bool bSplit = false;
2085  SwPaM aSavePam( rPos, rPos );
2086 
2087  // Move the SPoint to the beginning of the range
2088  if( rPaM.GetPoint() == pEnd )
2089  rPaM.Exchange();
2090 
2091  // If there is a TextNode before and after the Move, create a JoinNext in the EditShell.
2092  SwTextNode* pSrcNd = rPaM.GetPoint()->nNode.GetNode().GetTextNode();
2093  bool bCorrSavePam = pSrcNd && pStt->nNode != pEnd->nNode;
2094 
2095  // If one ore more TextNodes are moved, SwNodes::Move will do a SplitNode.
2096  // However, this does not update the cursor. So we create a TextNode to keep
2097  // updating the indices. After the Move the Node is optionally deleted.
2098  SwTextNode * pTNd = rPos.nNode.GetNode().GetTextNode();
2099  if( pTNd && rPaM.GetPoint()->nNode != rPaM.GetMark()->nNode &&
2100  ( rPos.nContent.GetIndex() || ( pTNd->Len() && bCorrSavePam )) )
2101  {
2102  bSplit = true;
2103  const sal_Int32 nMkContent = rPaM.GetMark()->nContent.GetIndex();
2104 
2105  const std::shared_ptr<sw::mark::ContentIdxStore> pContentStore(sw::mark::ContentIdxStore::Create());
2106  pContentStore->Save( &m_rDoc, rPos.nNode.GetIndex(), rPos.nContent.GetIndex(), true );
2107 
2108  SwTextNode * pOrigNode = pTNd;
2109  assert(*aSavePam.GetPoint() == *aSavePam.GetMark() &&
2110  *aSavePam.GetPoint() == rPos);
2111  assert(aSavePam.GetPoint()->nContent.GetIdxReg() == pOrigNode);
2112  assert(aSavePam.GetPoint()->nNode == rPos.nNode.GetIndex());
2113  assert(rPos.nNode.GetIndex() == pOrigNode->GetIndex());
2114 
2115  std::function<void (SwTextNode *, sw::mark::RestoreMode)> restoreFunc(
2116  [&](SwTextNode *const, sw::mark::RestoreMode const eMode)
2117  {
2118  if (!pContentStore->Empty())
2119  {
2120  pContentStore->Restore(&m_rDoc, pOrigNode->GetIndex()-1, 0, true, eMode);
2121  }
2122  });
2123  pTNd = pTNd->SplitContentNode(rPos, &restoreFunc)->GetTextNode();
2124 
2125  //A new node was inserted before the orig pTNd and the content up to
2126  //rPos moved into it. The old node is returned with the remainder
2127  //of the content in it.
2128  //
2129  //aSavePam was created with rPos, it continues to point to the
2130  //old node, but with the *original* content index into the node.
2131  //Seeing as all the orignode content before that index has
2132  //been removed, the new index into the original node should now be set
2133  //to 0 and the content index of rPos should also be adapted to the
2134  //truncated node
2135  assert(*aSavePam.GetPoint() == *aSavePam.GetMark() &&
2136  *aSavePam.GetPoint() == rPos);
2137  assert(aSavePam.GetPoint()->nContent.GetIdxReg() == pOrigNode);
2138  assert(aSavePam.GetPoint()->nNode == rPos.nNode.GetIndex());
2139  assert(rPos.nNode.GetIndex() == pOrigNode->GetIndex());
2140  aSavePam.GetPoint()->nContent.Assign(pOrigNode, 0);
2141  rPos = *aSavePam.GetMark() = *aSavePam.GetPoint();
2142 
2143  // correct the PaM!
2144  if( rPos.nNode == rPaM.GetMark()->nNode )
2145  {
2146  rPaM.GetMark()->nNode = rPos.nNode.GetIndex()-1;
2147  rPaM.GetMark()->nContent.Assign( pTNd, nMkContent );
2148  }
2149  }
2150 
2151  // Put back the Pam by one "content"; so that it's always outside of
2152  // the manipulated range.
2153  // tdf#99692 don't Move() back if that would end up in another node
2154  // because moving backward is not necessarily the inverse of forward then.
2155  // (but do Move() back if we have split the node)
2156  const bool bNullContent = !bSplit && aSavePam.GetPoint()->nContent == 0;
2157  if( bNullContent )
2158  {
2159  aSavePam.GetPoint()->nNode--;
2160  aSavePam.GetPoint()->nContent.Assign(aSavePam.GetContentNode(), 0);
2161  }
2162  else
2163  {
2164  bool const success(aSavePam.Move(fnMoveBackward, GoInContent));
2165  assert(success);
2166  (void) success;
2167  }
2168 
2169  // Copy all Bookmarks that are within the Move range into an array,
2170  // that saves the position as an offset.
2171  std::vector< ::sw::mark::SaveBookmark> aSaveBkmks;
2172  DelBookmarks(
2173  pStt->nNode,
2174  pEnd->nNode,
2175  &aSaveBkmks,
2176  &pStt->nContent,
2177  &pEnd->nContent);
2178 
2179  // If there is no range anymore due to the above deletions (e.g. the
2180  // footnotes got deleted), it's still a valid Move!
2181  if( *rPaM.GetPoint() != *rPaM.GetMark() )
2182  {
2183  // now do the actual move
2184  m_rDoc.GetNodes().MoveRange( rPaM, rPos, m_rDoc.GetNodes() );
2185 
2186  // after a MoveRange() the Mark is deleted
2187  if ( rPaM.HasMark() ) // => no Move occurred!
2188  {
2189  return false;
2190  }
2191  }
2192  else
2193  rPaM.DeleteMark();
2194 
2195  OSL_ENSURE( *aSavePam.GetMark() == rPos ||
2196  ( aSavePam.GetMark()->nNode.GetNode().GetContentNode() == nullptr ),
2197  "PaM was not moved. Aren't there ContentNodes at the beginning/end?" );
2198  *aSavePam.GetMark() = rPos;
2199 
2200  rPaM.SetMark(); // create a Sel. around the new range
2201  pTNd = aSavePam.GetNode().GetTextNode();
2203  {
2204  assert(!"mst: this is assumed to be dead code");
2205 
2206  // correct the SavePam's Content first
2207  if( bNullContent )
2208  {
2209  aSavePam.GetPoint()->nContent = 0;
2210  }
2211 
2212  // The method SwEditShell::Move() merges the TextNode after the Move,
2213  // where the rPaM is located.
2214  // If the Content was moved to the back and the SavePam's SPoint is
2215  // in the next Node, we have to deal with this when saving the Undo object!
2216  SwTextNode * pPamTextNd = nullptr;
2217 
2218  // Is passed to SwUndoMove, which happens when subsequently calling Undo JoinNext.
2219  // If it's not possible to call Undo JoinNext here.
2220  bool bJoin = bSplit && pTNd;
2221  if( bCorrSavePam )
2222  {
2223  pPamTextNd = rPaM.GetNode().GetTextNode();
2224  bCorrSavePam = (pPamTextNd != nullptr)
2225  && pPamTextNd->CanJoinNext()
2226  && (*rPaM.GetPoint() <= *aSavePam.GetPoint());
2227  }
2228 
2229  // Do two Nodes have to be joined at the SavePam?
2230  if( bJoin && pTNd->CanJoinNext() )
2231  {
2232  pTNd->JoinNext();
2233  // No temporary Index when using &&.
2234  // We probably only want to compare the indices.
2235  if( bCorrSavePam && rPaM.GetPoint()->nNode.GetIndex()+1 ==
2236  aSavePam.GetPoint()->nNode.GetIndex() )
2237  {
2238  aSavePam.GetPoint()->nContent += pPamTextNd->Len();
2239  }
2240  bJoin = false;
2241  }
2242  else if ( !aSavePam.Move( fnMoveForward, GoInContent ) )
2243  {
2244  aSavePam.GetPoint()->nNode++;
2245  }
2246 
2247  // The newly inserted range is now inbetween SPoint and GetMark.
2248  pUndoMove->SetDestRange( aSavePam, *rPaM.GetPoint(),
2249  bJoin, bCorrSavePam );
2250  m_rDoc.GetIDocumentUndoRedo().AppendUndo( std::move(pUndoMove) );
2251  }
2252  else
2253  {
2254  bool bRemove = true;
2255  // Do two Nodes have to be joined at the SavePam?
2256  if( bSplit && pTNd )
2257  {
2258  if( pTNd->CanJoinNext())
2259  {
2260  // Always join next, because <pTNd> has to stay as it is.
2261  // A join previous from its next would more or less delete <pTNd>
2262  pTNd->JoinNext();
2263  bRemove = false;
2264  }
2265  }
2266  if( bNullContent )
2267  {
2268  aSavePam.GetPoint()->nNode++;
2269  aSavePam.GetPoint()->nContent.Assign( aSavePam.GetContentNode(), 0 );
2270  }
2271  else if( bRemove ) // No move forward after joining with next paragraph
2272  {
2273  aSavePam.Move( fnMoveForward, GoInContent );
2274  }
2275  }
2276 
2277  // Insert the Bookmarks back into the Document.
2278  *rPaM.GetMark() = *aSavePam.Start();
2279  for(auto& rBkmk : aSaveBkmks)
2280  rBkmk.SetInDoc(
2281  &m_rDoc,
2282  rPaM.GetMark()->nNode,
2283  &rPaM.GetMark()->nContent);
2284  *rPaM.GetPoint() = *aSavePam.End();
2285 
2286  // Move the Flys to the new position.
2287  RestFlyInRange( aSaveFlyArr, rPaM.Start()->nNode, &(rPos.nNode) );
2288 
2289  // restore redlines (if DOC_MOVEREDLINES is used)
2290  if( !aSaveRedl.empty() )
2291  {
2292  lcl_RestoreRedlines( &m_rDoc, *aSavePam.Start(), aSaveRedl );
2293  }
2294 
2295  if( bUpdateFootnote )
2296  {
2297  if( !aTmpFntIdx.empty() )
2298  {
2299  m_rDoc.GetFootnoteIdxs().insert( aTmpFntIdx );
2300  aTmpFntIdx.clear();
2301  }
2302 
2304  }
2305 
2307  return true;
2308 }
2309 
2311  SwMoveFlags eMvFlags )
2312 {
2313  // Moves all Nodes to the new position.
2314  // Bookmarks are moved too (currently without Undo support).
2315 
2316  // If footnotes are being moved to the special section, remove them now.
2317 
2318  // Or else delete the Frames for all footnotes that are being moved
2319  // and have it rebuild after the Move (footnotes can change pages).
2320  // Additionally we have to correct the FootnoteIdx array's sorting.
2321  bool bUpdateFootnote = false;
2322  SwFootnoteIdxs aTmpFntIdx;
2323 
2324  std::unique_ptr<SwUndoMove> pUndo;
2326  {
2327  pUndo.reset(new SwUndoMove( &m_rDoc, rRange, rPos ));
2328  }
2329  else
2330  {
2331  bUpdateFootnote = lcl_SaveFootnote( rRange.aStart, rRange.aEnd, rPos,
2332  m_rDoc.GetFootnoteIdxs(), aTmpFntIdx );
2333  }
2334 
2335  SaveRedlines_t aSaveRedl;
2336  std::vector<SwRangeRedline*> aSavRedlInsPosArr;
2338  {
2339  lcl_SaveRedlines( rRange, aSaveRedl );
2340 
2341  // Find all RedLines that end at the InsPos.
2342  // These have to be moved back to the "old" position after the Move.
2344  if( SwRedlineTable::npos != nRedlPos )
2345  {
2346  const SwPosition *pRStt, *pREnd;
2347  do {
2349  pRStt = pTmp->Start();
2350  pREnd = pTmp->End();
2351  if( pREnd->nNode == rPos && pRStt->nNode < rPos )
2352  {
2353  aSavRedlInsPosArr.push_back( pTmp );
2354  }
2355  } while( pRStt->nNode < rPos && ++nRedlPos < m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().size());
2356  }
2357  }
2358 
2359  // Copy all Bookmarks that are within the Move range into an array
2360  // that stores all references to positions as an offset.
2361  // The final mapping happens after the Move.
2362  std::vector< ::sw::mark::SaveBookmark> aSaveBkmks;
2363  DelBookmarks(rRange.aStart, rRange.aEnd, &aSaveBkmks);
2364 
2365  // Save the paragraph-bound Flys, so that they can be moved.
2366  SaveFlyArr aSaveFlyArr;
2367  if( !m_rDoc.GetSpzFrameFormats()->empty() )
2368  SaveFlyInRange( rRange, aSaveFlyArr );
2369 
2370  // Set it to before the Position, so that it cannot be moved further.
2371  SwNodeIndex aIdx( rPos, -1 );
2372 
2373  std::unique_ptr<SwNodeIndex> pSaveInsPos;
2374  if( pUndo )
2375  pSaveInsPos.reset(new SwNodeIndex( rRange.aStart, -1 ));
2376 
2377  // move the Nodes
2378  bool bNoDelFrames = bool(SwMoveFlags::NO_DELFRMS & eMvFlags);
2379  if( m_rDoc.GetNodes().MoveNodes( rRange, m_rDoc.GetNodes(), rPos, !bNoDelFrames ) )
2380  {
2381  ++aIdx; // again back to old position
2382  if( pSaveInsPos )
2383  ++(*pSaveInsPos);
2384  }
2385  else
2386  {
2387  aIdx = rRange.aStart;
2388  pUndo.reset();
2389  }
2390 
2391  // move the Flys to the new position
2392  if( !aSaveFlyArr.empty() )
2393  RestFlyInRange( aSaveFlyArr, aIdx, nullptr );
2394 
2395  // Add the Bookmarks back to the Document
2396  for(auto& rBkmk : aSaveBkmks)
2397  rBkmk.SetInDoc(&m_rDoc, aIdx);
2398 
2399  if( !aSavRedlInsPosArr.empty() )
2400  {
2401  SwNode* pNewNd = &aIdx.GetNode();
2402  for(SwRangeRedline* pTmp : aSavRedlInsPosArr)
2403  {
2405  {
2406  SwPosition* pEnd = pTmp->End();
2407  pEnd->nNode = aIdx;
2408  pEnd->nContent.Assign( pNewNd->GetContentNode(), 0 );
2409  }
2410  }
2411  }
2412 
2413  if( !aSaveRedl.empty() )
2414  lcl_RestoreRedlines( &m_rDoc, aIdx.GetIndex(), aSaveRedl );
2415 
2416  if( pUndo )
2417  {
2418  pUndo->SetDestRange( aIdx, rPos, *pSaveInsPos );
2419  m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::move(pUndo));
2420  }
2421 
2422  pSaveInsPos.reset();
2423 
2424  if( bUpdateFootnote )
2425  {
2426  if( !aTmpFntIdx.empty() )
2427  {
2428  m_rDoc.GetFootnoteIdxs().insert( aTmpFntIdx );
2429  aTmpFntIdx.clear();
2430  }
2431 
2433  }
2434 
2436  return true;
2437 }
2438 
2440 {
2441  SwNodeIndex aIdx( rPaM.Start()->nNode );
2442  bool bJoinText = aIdx.GetNode().IsTextNode();
2443  bool bOneNode = rPaM.GetPoint()->nNode == rPaM.GetMark()->nNode;
2444  aIdx--; // in front of the move area!
2445 
2446  bool bRet = MoveRange( rPaM, rPos, SwMoveFlags::DEFAULT );
2447  if( bRet && !bOneNode )
2448  {
2449  if( bJoinText )
2450  ++aIdx;
2451  SwTextNode * pTextNd = aIdx.GetNode().GetTextNode();
2452  SwNodeIndex aNxtIdx( aIdx );
2453  if( pTextNd && pTextNd->CanJoinNext( &aNxtIdx ) )
2454  {
2455  { // Block so SwIndex into node is deleted before Join
2456  m_rDoc.CorrRel( aNxtIdx, SwPosition( aIdx, SwIndex(pTextNd,
2457  pTextNd->GetText().getLength()) ), 0, true );
2458  }
2459  pTextNd->JoinNext();
2460  }
2461  }
2462  return bRet;
2463 }
2464 
2465 // Overwrite only uses the point of the PaM, the mark is ignored; characters
2466 // are replaced from point until the end of the node; at the end of the node,
2467 // characters are inserted.
2468 bool DocumentContentOperationsManager::Overwrite( const SwPaM &rRg, const OUString &rStr )
2469 {
2470  assert(rStr.getLength());
2471  SwPosition& rPt = *const_cast<SwPosition*>(rRg.GetPoint());
2472  if( m_rDoc.GetAutoCorrExceptWord() ) // Add to AutoCorrect
2473  {
2474  if( 1 == rStr.getLength() )
2475  m_rDoc.GetAutoCorrExceptWord()->CheckChar( rPt, rStr[ 0 ] );
2477  }
2478 
2479  SwTextNode *pNode = rPt.nNode.GetNode().GetTextNode();
2480  if (!pNode || rStr.getLength() > pNode->GetSpaceLeft()) // worst case: no erase
2481  {
2482  return false;
2483  }
2484 
2486  {
2487  m_rDoc.GetIDocumentUndoRedo().ClearRedo(); // AppendUndo not always called
2488  }
2489 
2490  const size_t nOldAttrCnt = pNode->GetpSwpHints()
2491  ? pNode->GetpSwpHints()->Count() : 0;
2492  SwDataChanged aTmp( rRg );
2493  SwIndex& rIdx = rPt.nContent;
2494  sal_Int32 const nActualStart(rIdx.GetIndex());
2495  sal_Int32 nStart = 0;
2496 
2497  bool bOldExpFlg = pNode->IsIgnoreDontExpand();
2498  pNode->SetIgnoreDontExpand( true );
2499 
2500  for( sal_Int32 nCnt = 0; nCnt < rStr.getLength(); ++nCnt )
2501  {
2502  // start behind the characters (to fix the attributes!)
2503  nStart = rIdx.GetIndex();
2504  if (nStart < pNode->GetText().getLength())
2505  {
2506  lcl_SkipAttr( pNode, rIdx, nStart );
2507  }
2508  sal_Unicode c = rStr[ nCnt ];
2510  {
2511  bool bMerged(false);
2513  {
2514  SwUndo *const pUndo = m_rDoc.GetUndoManager().GetLastUndo();
2515  SwUndoOverwrite *const pUndoOW(
2516  dynamic_cast<SwUndoOverwrite *>(pUndo) );
2517  if (pUndoOW)
2518  {
2519  // if CanGrouping() returns true it's already merged
2520  bMerged = pUndoOW->CanGrouping( &m_rDoc, rPt, c );
2521  }
2522  }
2523  if (!bMerged)
2524  {
2526  std::make_unique<SwUndoOverwrite>(&m_rDoc, rPt, c) );
2527  }
2528  }
2529  else
2530  {
2531  // start behind the characters (to fix the attributes!)
2532  if (nStart < pNode->GetText().getLength())
2533  ++rIdx;
2534  pNode->InsertText( OUString(c), rIdx, SwInsertFlags::EMPTYEXPAND );
2535  if( nStart+1 < rIdx.GetIndex() )
2536  {
2537  rIdx = nStart;
2538  pNode->EraseText( rIdx, 1 );
2539  ++rIdx;
2540  }
2541  }
2542  }
2543  pNode->SetIgnoreDontExpand( bOldExpFlg );
2544 
2545  const size_t nNewAttrCnt = pNode->GetpSwpHints()
2546  ? pNode->GetpSwpHints()->Count() : 0;
2547  if( nOldAttrCnt != nNewAttrCnt )
2548  {
2549  SwUpdateAttr aHint(0,0,0);
2550  pNode->ModifyBroadcast(nullptr, &aHint);
2551  }
2552 
2555  {
2556  SwPaM aPam(rPt.nNode, nActualStart, rPt.nNode, rPt.nContent.GetIndex());
2558  }
2560  {
2561  // FIXME: this redline is WRONG: there is no DELETE, and the skipped
2562  // characters are also included in aPam
2563  SwPaM aPam(rPt.nNode, nActualStart, rPt.nNode, rPt.nContent.GetIndex());
2565  }
2566 
2568  return true;
2569 }
2570 
2571 bool DocumentContentOperationsManager::InsertString( const SwPaM &rRg, const OUString &rStr,
2572  const SwInsertFlags nInsertMode )
2573 {
2574  // tdf#119019 accept tracked paragraph formatting to do not hide new insertions
2576  {
2581  }
2582 
2583  // fetching DoesUndo is surprisingly expensive
2584  bool bDoesUndo = m_rDoc.GetIDocumentUndoRedo().DoesUndo();
2585  if (bDoesUndo)
2586  m_rDoc.GetIDocumentUndoRedo().ClearRedo(); // AppendUndo not always called!
2587 
2588  const SwPosition& rPos = *rRg.GetPoint();
2589 
2590  if( m_rDoc.GetAutoCorrExceptWord() ) // add to auto correction
2591  {
2592  if( 1 == rStr.getLength() && m_rDoc.GetAutoCorrExceptWord()->IsDeleted() )
2593  {
2594  m_rDoc.GetAutoCorrExceptWord()->CheckChar( rPos, rStr[ 0 ] );
2595  }
2597  }
2598 
2599  SwTextNode *const pNode = rPos.nNode.GetNode().GetTextNode();
2600  if(!pNode)
2601  return false;
2602 
2603  SwDataChanged aTmp( rRg );
2604 
2605  if (!bDoesUndo || !m_rDoc.GetIDocumentUndoRedo().DoesGroupUndo())
2606  {
2607  OUString const ins(pNode->InsertText(rStr, rPos.nContent, nInsertMode));
2608  if (bDoesUndo)
2609  {
2611  std::make_unique<SwUndoInsert>(rPos.nNode,
2612  rPos.nContent.GetIndex(), ins.getLength(), nInsertMode));
2613  }
2614  }
2615  else
2616  { // if Undo and grouping is enabled, everything changes!
2617  SwUndoInsert * pUndo = nullptr;
2618 
2619  // don't group the start if hints at the start should be expanded
2620  if (!(nInsertMode & SwInsertFlags::FORCEHINTEXPAND))
2621  {
2622  SwUndo *const pLastUndo = m_rDoc.GetUndoManager().GetLastUndo();
2623  SwUndoInsert *const pUndoInsert(
2624  dynamic_cast<SwUndoInsert *>(pLastUndo) );
2625  if (pUndoInsert && pUndoInsert->CanGrouping(rPos))
2626  {
2627  pUndo = pUndoInsert;
2628  }
2629  }
2630 
2631  CharClass const& rCC = GetAppCharClass();
2632  sal_Int32 nInsPos = rPos.nContent.GetIndex();
2633 
2634  if (!pUndo)
2635  {
2636  pUndo = new SwUndoInsert( rPos.nNode, nInsPos, 0, nInsertMode,
2637  !rCC.isLetterNumeric( rStr, 0 ) );
2638  m_rDoc.GetIDocumentUndoRedo().AppendUndo( std::unique_ptr<SwUndo>(pUndo) );
2639  }
2640 
2641  OUString const ins(pNode->InsertText(rStr, rPos.nContent, nInsertMode));
2642 
2643  for (sal_Int32 i = 0; i < ins.getLength(); ++i)
2644  {
2645  nInsPos++;
2646  // if CanGrouping() returns true, everything has already been done
2647  if (!pUndo->CanGrouping(ins[i]))
2648  {
2649  pUndo = new SwUndoInsert(rPos.nNode, nInsPos, 1, nInsertMode,
2650  !rCC.isLetterNumeric(ins, i));
2651  m_rDoc.GetIDocumentUndoRedo().AppendUndo( std::unique_ptr<SwUndo>(pUndo) );
2652  }
2653  }
2654  }
2655 
2656  // To-Do - add 'SwExtraRedlineTable' also ?
2658  {
2659  SwPaM aPam( rPos.nNode, aTmp.GetContent(),
2660  rPos.nNode, rPos.nContent.GetIndex());
2662  {
2664  new SwRangeRedline( RedlineType::Insert, aPam ), true);
2665  }
2666  else
2667  {
2669  }
2670  }
2671 
2673  return true;
2674 }
2675 
2677  const SwPaM& rPaM,
2678  utl::TransliterationWrapper& rTrans )
2679 {
2680  std::unique_ptr<SwUndoTransliterate> pUndo;
2682  pUndo.reset(new SwUndoTransliterate( rPaM, rTrans ));
2683 
2684  const SwPosition* pStt = rPaM.Start(),
2685  * pEnd = rPaM.End();
2686  sal_uLong nSttNd = pStt->nNode.GetIndex(),
2687  nEndNd = pEnd->nNode.GetIndex();
2688  sal_Int32 nSttCnt = pStt->nContent.GetIndex();
2689  sal_Int32 nEndCnt = pEnd->nContent.GetIndex();
2690 
2691  SwTextNode* pTNd = pStt->nNode.GetNode().GetTextNode();
2692  if( pStt == pEnd && pTNd ) // no selection?
2693  {
2694  // set current word as 'area of effect'
2695 
2696  assert(g_pBreakIt && g_pBreakIt->GetBreakIter().is());
2697  Boundary aBndry = g_pBreakIt->GetBreakIter()->getWordBoundary(
2698  pTNd->GetText(), nSttCnt,
2699  g_pBreakIt->GetLocale( pTNd->GetLang( nSttCnt ) ),
2700  WordType::ANY_WORD /*ANYWORD_IGNOREWHITESPACES*/,
2701  true);
2702 
2703  if( aBndry.startPos < nSttCnt && nSttCnt < aBndry.endPos )
2704  {
2705  nSttCnt = aBndry.startPos;
2706  nEndCnt = aBndry.endPos;
2707  }
2708  }
2709 
2710  if( nSttNd != nEndNd ) // is more than one text node involved?
2711  {
2712  // iterate over all effected text nodes, the first and the last one
2713  // may be incomplete because the selection starts and/or ends there
2714 
2715  SwNodeIndex aIdx( pStt->nNode );
2716  if( nSttCnt )
2717  {
2718  ++aIdx;
2719  if( pTNd )
2720  pTNd->TransliterateText(
2721  rTrans, nSttCnt, pTNd->GetText().getLength(), pUndo.get());
2722  }
2723 
2724  for( ; aIdx.GetIndex() < nEndNd; ++aIdx )
2725  {
2726  pTNd = aIdx.GetNode().GetTextNode();
2727  if (pTNd)
2728  {
2729  pTNd->TransliterateText(
2730  rTrans, 0, pTNd->GetText().getLength(), pUndo.get());
2731  }
2732  }
2733 
2734  if( nEndCnt && nullptr != ( pTNd = pEnd->nNode.GetNode().GetTextNode() ))
2735  pTNd->TransliterateText( rTrans, 0, nEndCnt, pUndo.get() );
2736  }
2737  else if( pTNd && nSttCnt < nEndCnt )
2738  pTNd->TransliterateText( rTrans, nSttCnt, nEndCnt, pUndo.get() );
2739 
2740  if( pUndo && pUndo->HasData() )
2741  {
2742  m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::move(pUndo));
2743  }
2745 }
2746 
2748  const SwPaM &rRg,
2749  const OUString& rGrfName,
2750  const OUString& rFltName,
2751  const Graphic* pGraphic,
2752  const SfxItemSet* pFlyAttrSet,
2753  const SfxItemSet* pGrfAttrSet,
2754  SwFrameFormat* pFrameFormat )
2755 {
2756  if( !pFrameFormat )
2758  SwGrfNode* pSwGrfNode = SwNodes::MakeGrfNode(
2760  rGrfName, rFltName, pGraphic,
2762  SwFlyFrameFormat* pSwFlyFrameFormat = InsNoTextNode( *rRg.GetPoint(), pSwGrfNode,
2763  pFlyAttrSet, pGrfAttrSet, pFrameFormat );
2764  return pSwFlyFrameFormat;
2765 }
2766 
2768  const SwPaM &rRg, const GraphicObject& rGrfObj,
2769  const SfxItemSet* pFlyAttrSet,
2770  const SfxItemSet* pGrfAttrSet )
2771 {
2773  SwGrfNode* pSwGrfNode = SwNodes::MakeGrfNode(
2775  rGrfObj, m_rDoc.GetDfltGrfFormatColl() );
2776  SwFlyFrameFormat* pSwFlyFrameFormat = InsNoTextNode( *rRg.GetPoint(), pSwGrfNode,
2777  pFlyAttrSet, pGrfAttrSet, pFrameFormat );
2778  return pSwFlyFrameFormat;
2779 }
2780 
2782  const SwPaM &rRg, const svt::EmbeddedObjectRef& xObj,
2783  const SfxItemSet* pFlyAttrSet)
2784 {
2785  sal_uInt16 nId = RES_POOLFRM_OLE;
2786  if (xObj.is())
2787  {
2788  SvGlobalName aClassName( xObj->getClassID() );
2789  if (SotExchange::IsMath(aClassName))
2790  nId = RES_POOLFRM_FORMEL;
2791  }
2792 
2794 
2795  return InsNoTextNode( *rRg.GetPoint(), m_rDoc.GetNodes().MakeOLENode(
2797  xObj,
2799  pFlyAttrSet, nullptr,
2800  pFrameFormat );
2801 }
2802 
2804  sal_Int64 nAspect,
2805  const SfxItemSet* pFlyAttrSet,
2806  const SfxItemSet* pGrfAttrSet)
2807 {
2809 
2810  return InsNoTextNode( *rRg.GetPoint(),
2813  rObjName,
2814  nAspect,
2816  nullptr ),
2817  pFlyAttrSet, pGrfAttrSet,
2818  pFrameFormat );
2819 }
2820 
2821 void DocumentContentOperationsManager::ReRead( SwPaM& rPam, const OUString& rGrfName,
2822  const OUString& rFltName, const Graphic* pGraphic )
2823 {
2824  SwGrfNode *pGrfNd;
2825  if( ( !rPam.HasMark()
2826  || rPam.GetPoint()->nNode.GetIndex() == rPam.GetMark()->nNode.GetIndex() )
2827  && nullptr != ( pGrfNd = rPam.GetPoint()->nNode.GetNode().GetGrfNode() ) )
2828  {
2830  {
2831  m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoReRead>(rPam, *pGrfNd));
2832  }
2833 
2834  // Because we don't know if we can mirror the graphic, the mirror attribute is always reset
2835  if( MirrorGraph::Dont != pGrfNd->GetSwAttrSet().
2836  GetMirrorGrf().GetValue() )
2837  pGrfNd->SetAttr( SwMirrorGrf() );
2838 
2839  pGrfNd->ReRead( rGrfName, rFltName, pGraphic );
2841  }
2842 }
2843 
2844 // Insert drawing object, which has to be already inserted in the DrawModel
2846  const SwPaM &rRg,
2847  SdrObject& rDrawObj,
2848  const SfxItemSet& rFlyAttrSet )
2849 {
2851 
2852  const SwFormatAnchor* pAnchor = nullptr;
2853  rFlyAttrSet.GetItemState( RES_ANCHOR, false, reinterpret_cast<const SfxPoolItem**>(&pAnchor) );
2854  pFormat->SetFormatAttr( rFlyAttrSet );
2855 
2856  // Didn't set the Anchor yet?
2857  // DrawObjecte must never end up in the Header/Footer!
2858  RndStdIds eAnchorId = pAnchor != nullptr ? pAnchor->GetAnchorId() : pFormat->GetAnchor().GetAnchorId();
2859  const bool bIsAtContent = (RndStdIds::FLY_AT_PAGE != eAnchorId);
2860 
2861  const SwNodeIndex* pChkIdx = nullptr;
2862  if ( pAnchor == nullptr )
2863  {
2864  pChkIdx = &rRg.GetPoint()->nNode;
2865  }
2866  else if ( bIsAtContent )
2867  {
2868  pChkIdx =
2869  pAnchor->GetContentAnchor() ? &pAnchor->GetContentAnchor()->nNode : &rRg.GetPoint()->nNode;
2870  }
2871 
2872  // allow drawing objects in header/footer, but control objects aren't allowed in header/footer.
2873  if( pChkIdx != nullptr
2874  && ::CheckControlLayer( &rDrawObj )
2875  && m_rDoc.IsInHeaderFooter( *pChkIdx ) )
2876  {
2877  // apply at-page anchor format
2878  eAnchorId = RndStdIds::FLY_AT_PAGE;
2879  pFormat->SetFormatAttr( SwFormatAnchor( eAnchorId ) );
2880  }
2881  else if( pAnchor == nullptr
2882  || ( bIsAtContent
2883  && pAnchor->GetContentAnchor() == nullptr ) )
2884  {
2885  // apply anchor format
2886  SwFormatAnchor aAnch( pAnchor != nullptr ? *pAnchor : pFormat->GetAnchor() );
2887  eAnchorId = aAnch.GetAnchorId();
2888  if ( eAnchorId == RndStdIds::FLY_AT_FLY )
2889  {
2890  SwPosition aPos( *rRg.GetNode().FindFlyStartNode() );
2891  aAnch.SetAnchor( &aPos );
2892  }
2893  else
2894  {
2895  aAnch.SetAnchor( rRg.GetPoint() );
2896  if ( eAnchorId == RndStdIds::FLY_AT_PAGE )
2897  {
2898  eAnchorId = dynamic_cast<const SdrUnoObj*>( &rDrawObj) != nullptr ? RndStdIds::FLY_AS_CHAR : RndStdIds::FLY_AT_PARA;
2899  aAnch.SetType( eAnchorId );
2900  }
2901  }
2902  pFormat->SetFormatAttr( aAnch );
2903  }
2904 
2905  // insert text attribute for as-character anchored drawing object
2906  if ( eAnchorId == RndStdIds::FLY_AS_CHAR )
2907  {
2908  bool bAnchorAtPageAsFallback = true;
2909  const SwFormatAnchor& rDrawObjAnchorFormat = pFormat->GetAnchor();
2910  if ( rDrawObjAnchorFormat.GetContentAnchor() != nullptr )
2911  {
2912  SwTextNode* pAnchorTextNode =
2913  rDrawObjAnchorFormat.GetContentAnchor()->nNode.GetNode().GetTextNode();
2914  if ( pAnchorTextNode != nullptr )
2915  {
2916  const sal_Int32 nStt = rDrawObjAnchorFormat.GetContentAnchor()->nContent.GetIndex();
2917  SwFormatFlyCnt aFormat( pFormat );
2918  pAnchorTextNode->InsertItem( aFormat, nStt, nStt );
2919  bAnchorAtPageAsFallback = false;
2920  }
2921  }
2922 
2923  if ( bAnchorAtPageAsFallback )
2924  {
2925  OSL_ENSURE( false, "DocumentContentOperationsManager::InsertDrawObj(..) - missing content anchor for as-character anchored drawing object --> anchor at-page" );
2926  pFormat->SetFormatAttr( SwFormatAnchor( RndStdIds::FLY_AT_PAGE ) );
2927  }
2928  }
2929 
2930  SwDrawContact* pContact = new SwDrawContact( pFormat, &rDrawObj );
2931 
2932  // Create Frames if necessary
2934  {
2935  // create layout representation
2936  pFormat->MakeFrames();
2937  // #i42319# - follow-up of #i35635#
2938  // move object to visible layer
2939  // #i79391#
2940  if ( pContact->GetAnchorFrame() )
2941  {
2942  pContact->MoveObjToVisibleLayer( &rDrawObj );
2943  }
2944  }
2945 
2947  {
2948  m_rDoc.GetIDocumentUndoRedo().AppendUndo( std::make_unique<SwUndoInsLayFormat>(pFormat, 0, 0) );
2949  }
2950 
2952  return pFormat;
2953 }
2954 
2955 bool DocumentContentOperationsManager::SplitNode( const SwPosition &rPos, bool bChkTableStart )
2956 {
2957  SwContentNode *pNode = rPos.nNode.GetNode().GetContentNode();
2958  if(nullptr == pNode)
2959  return false;
2960 
2961  {
2962  // BUG 26675: Send DataChanged before deleting, so that we notice which objects are in scope.
2963  // After that they can be before/after the position.
2964  SwDataChanged aTmp( &m_rDoc, rPos );
2965  }
2966 
2967  SwUndoSplitNode* pUndo = nullptr;
2969  {
2971  // insert the Undo object (currently only for TextNode)
2972  if( pNode->IsTextNode() )
2973  {
2974  pUndo = new SwUndoSplitNode( &m_rDoc, rPos, bChkTableStart );
2975  m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::unique_ptr<SwUndo>(pUndo));
2976  }
2977  }
2978 
2979  // Update the rsid of the old and the new node unless
2980  // the old node is split at the beginning or at the end
2981  SwTextNode *pTextNode = rPos.nNode.GetNode().GetTextNode();
2982  const sal_Int32 nPos = rPos.nContent.GetIndex();
2983  if( pTextNode && nPos && nPos != pTextNode->Len() )
2984  {
2985  m_rDoc.UpdateParRsid( pTextNode );
2986  }
2987 
2988  //JP 28.01.97: Special case for SplitNode at table start:
2989  // If it is at the beginning of a Doc/Fly/Footer/... or right at after a table
2990  // then insert a paragraph before it.
2991  if( bChkTableStart && !rPos.nContent.GetIndex() && pNode->IsTextNode() )
2992  {
2993  sal_uLong nPrevPos = rPos.nNode.GetIndex() - 1;
2994  const SwTableNode* pTableNd;
2995  const SwNode* pNd = m_rDoc.GetNodes()[ nPrevPos ];
2996  if( pNd->IsStartNode() &&
2997  SwTableBoxStartNode == static_cast<const SwStartNode*>(pNd)->GetStartNodeType() &&
2998  nullptr != ( pTableNd = m_rDoc.GetNodes()[ --nPrevPos ]->GetTableNode() ) &&
2999  ((( pNd = m_rDoc.GetNodes()[ --nPrevPos ])->IsStartNode() &&
3000  SwTableBoxStartNode != static_cast<const SwStartNode*>(pNd)->GetStartNodeType() )
3001  || ( pNd->IsEndNode() && pNd->StartOfSectionNode()->IsTableNode() )
3002  || pNd->IsContentNode() ))
3003  {
3004  if( pNd->IsContentNode() )
3005  {
3006  //JP 30.04.99 Bug 65660:
3007  // There are no page breaks outside of the normal body area,
3008  // so this is not a valid condition to insert a paragraph.
3009  if( nPrevPos < m_rDoc.GetNodes().GetEndOfExtras().GetIndex() )
3010  pNd = nullptr;
3011  else
3012  {
3013  // Only if the table has page breaks!
3014  const SwFrameFormat* pFrameFormat = pTableNd->GetTable().GetFrameFormat();
3015  if( SfxItemState::SET != pFrameFormat->GetItemState(RES_PAGEDESC, false) &&
3016  SfxItemState::SET != pFrameFormat->GetItemState( RES_BREAK, false ) )
3017  pNd = nullptr;
3018  }
3019  }
3020 
3021  if( pNd )
3022  {
3023  SwTextNode* pTextNd = m_rDoc.GetNodes().MakeTextNode(
3024  SwNodeIndex( *pTableNd ),
3026  if( pTextNd )
3027  {
3028  const_cast<SwPosition&>(rPos).nNode = pTableNd->GetIndex()-1;
3029  const_cast<SwPosition&>(rPos).nContent.Assign( pTextNd, 0 );
3030 
3031  // only add page breaks/styles to the body area
3032  if( nPrevPos > m_rDoc.GetNodes().GetEndOfExtras().GetIndex() )
3033  {
3034  SwFrameFormat* pFrameFormat = pTableNd->GetTable().GetFrameFormat();
3035  const SfxPoolItem *pItem;
3036  if( SfxItemState::SET == pFrameFormat->GetItemState( RES_PAGEDESC,
3037  false, &pItem ) )
3038  {
3039  pTextNd->SetAttr( *pItem );
3040  pFrameFormat->ResetFormatAttr( RES_PAGEDESC );
3041  }
3042  if( SfxItemState::SET == pFrameFormat->GetItemState( RES_BREAK,
3043  false, &pItem ) )
3044  {
3045  pTextNd->SetAttr( *pItem );
3046  pFrameFormat->ResetFormatAttr( RES_BREAK );
3047  }
3048  }
3049 
3050  if( pUndo )
3051  pUndo->SetTableFlag();
3053  return true;
3054  }
3055  }
3056  }
3057  }
3058 
3059  const std::shared_ptr<sw::mark::ContentIdxStore> pContentStore(sw::mark::ContentIdxStore::Create());
3060  pContentStore->Save( &m_rDoc, rPos.nNode.GetIndex(), rPos.nContent.GetIndex(), true );
3061  assert(pNode->IsTextNode());
3062  std::function<void (SwTextNode *, sw::mark::RestoreMode)> restoreFunc(
3063  [&](SwTextNode *const, sw::mark::RestoreMode const eMode)
3064  {
3065  if (!pContentStore->Empty())
3066  { // move all bookmarks, TOXMarks, FlyAtCnt
3067  pContentStore->Restore(&m_rDoc, rPos.nNode.GetIndex()-1, 0, true, eMode);
3068  }
3069  if (eMode & sw::mark::RestoreMode::NonFlys)
3070  {
3071  // To-Do - add 'SwExtraRedlineTable' also ?
3075  {
3076  SwPaM aPam( rPos );
3077  aPam.SetMark();
3078  aPam.Move( fnMoveBackward );
3080  {
3082  new SwRangeRedline(RedlineType::Insert, aPam), true);
3083  }
3084  else
3085  {
3087  }
3088  }
3089  }
3090  });
3091  pNode->GetTextNode()->SplitContentNode(rPos, &restoreFunc);
3092 
3094  return true;
3095 }
3096 
3098 {
3099  // create new node before EndOfContent
3100  SwTextNode * pCurNode = rPos.nNode.GetNode().GetTextNode();
3101  if( !pCurNode )
3102  {
3103  // so then one can be created!
3104  SwNodeIndex aIdx( rPos.nNode, 1 );
3105  pCurNode = m_rDoc.GetNodes().MakeTextNode( aIdx,
3107  }
3108  else
3109  pCurNode = pCurNode->AppendNode( rPos )->GetTextNode();
3110 
3111  rPos.nNode++;
3112  rPos.nContent.Assign( pCurNode, 0 );
3113 
3115  {
3116  m_rDoc.GetIDocumentUndoRedo().AppendUndo( std::make_unique<SwUndoInsert>( rPos.nNode ) );
3117  }
3118 
3119  // To-Do - add 'SwExtraRedlineTable' also ?
3121  {
3122  SwPaM aPam( rPos );
3123  aPam.SetMark();
3124  aPam.Move( fnMoveBackward );
3127  else
3129  }
3130 
3132  return true;
3133 }
3134 
3135 bool DocumentContentOperationsManager::ReplaceRange( SwPaM& rPam, const OUString& rStr,
3136  const bool bRegExReplace )
3137 {
3138  // unfortunately replace works slightly differently from delete,
3139  // so we cannot use lcl_DoWithBreaks here...
3140 
3141  std::vector<sal_Int32> Breaks;
3142 
3143  SwPaM aPam( *rPam.GetMark(), *rPam.GetPoint() );
3144  aPam.Normalize(false);
3145  if (aPam.GetPoint()->nNode != aPam.GetMark()->nNode)
3146  {
3147  aPam.Move(fnMoveBackward);
3148  }
3149  OSL_ENSURE((aPam.GetPoint()->nNode == aPam.GetMark()->nNode), "invalid pam?");
3150 
3151  lcl_CalcBreaks(Breaks, aPam);
3152 
3153  while (!Breaks.empty() // skip over prefix of dummy chars
3154  && (aPam.GetMark()->nContent.GetIndex() == *Breaks.begin()) )
3155  {
3156  // skip!
3157  ++aPam.GetMark()->nContent; // always in bounds if Breaks valid
3158  Breaks.erase(Breaks.begin());
3159  }
3160  *rPam.Start() = *aPam.GetMark(); // update start of original pam w/ prefix
3161 
3162  if (Breaks.empty())
3163  {
3164  // park aPam somewhere so it does not point to node that is deleted
3165  aPam.DeleteMark();
3167  return ReplaceRangeImpl(rPam, rStr, bRegExReplace); // original pam!
3168  }
3169 
3170  // Deletion must be split into several parts if the text node
3171  // contains a text attribute with end and with dummy character
3172  // and the selection does not contain the text attribute completely,
3173  // but overlaps its start (left), where the dummy character is.
3174 
3175  bool bRet( true );
3176  // iterate from end to start, to avoid invalidating the offsets!
3177  std::vector<sal_Int32>::reverse_iterator iter( Breaks.rbegin() );
3178  OSL_ENSURE(aPam.GetPoint() == aPam.End(), "wrong!");
3179  SwPosition & rEnd( *aPam.End() );
3180  SwPosition & rStart( *aPam.Start() );
3181 
3182  // set end of temp pam to original end (undo Move backward above)
3183  rEnd = *rPam.End();
3184  // after first deletion, rEnd will point into the original text node again!
3185 
3186  while (iter != Breaks.rend())
3187  {
3188  rStart.nContent = *iter + 1;
3189  if (rEnd.nContent != rStart.nContent) // check if part is empty
3190  {
3193  : DeleteAndJoinImpl(aPam, false);
3194  }
3195  rEnd.nContent = *iter;
3196  ++iter;
3197  }
3198 
3199  rStart = *rPam.Start(); // set to original start
3200  OSL_ENSURE(rEnd.nContent > rStart.nContent, "replace part empty!");
3201  if (rEnd.nContent > rStart.nContent) // check if part is empty
3202  {
3203  bRet &= ReplaceRangeImpl(aPam, rStr, bRegExReplace);
3204  }
3205 
3206  rPam = aPam; // update original pam (is this required?)
3207 
3208  return bRet;
3209 }
3210 
3213  const SwPaM &rRg,
3214  const SfxPoolItem &rHt,
3215  const SetAttrMode nFlags,
3216  SwRootFrame const*const pLayout,
3217  const bool bExpandCharToPara)
3218 {
3220  return false;
3221 
3222  SwDataChanged aTmp( rRg );
3223  std::unique_ptr<SwUndoAttr> pUndoAttr;
3225  {
3227  pUndoAttr.reset(new SwUndoAttr( rRg, rHt, nFlags ));
3228  }
3229 
3230  SfxItemSet aSet( m_rDoc.GetAttrPool(), {{rHt.Which(), rHt.Which()}} );
3231  aSet.Put( rHt );
3232  const bool bRet = lcl_InsAttr(&m_rDoc, rRg, aSet, nFlags, pUndoAttr.get(), pLayout, bExpandCharToPara);
3233 
3235  {
3236  m_rDoc.GetIDocumentUndoRedo().AppendUndo( std::move(pUndoAttr) );
3237  }
3238 
3239  if( bRet )
3240  {
3242  }
3243  return bRet;
3244 }
3245 
3247  const SetAttrMode nFlags, SwRootFrame const*const pLayout)
3248 {
3249  SwDataChanged aTmp( rRg );
3250  std::unique_ptr<SwUndoAttr> pUndoAttr;
3252  {
3254  pUndoAttr.reset(new SwUndoAttr( rRg, rSet, nFlags ));
3255  }
3256 
3257  bool bRet = lcl_InsAttr(&m_rDoc, rRg, rSet, nFlags, pUndoAttr.get(), pLayout);
3258 
3260  {
3261  m_rDoc.GetIDocumentUndoRedo().AppendUndo( std::move(pUndoAttr) );
3262  }
3263 
3264  if( bRet )
3266 }
3267 
3269 {
3270  const SwTextNode* pTNd = rPos.nNode.GetNode().GetTextNode();
3271  if ( pTNd )
3272  {
3273  const OUString& rText = pTNd->GetText();
3274  sal_Int32 nIdx = 0;
3275  while (nIdx < rText.getLength())
3276  {
3277  sal_Unicode const cCh = rText[nIdx];
3278  if (('\t' != cCh) && (' ' != cCh))
3279  {
3280  break;
3281  }
3282  ++nIdx;
3283  }
3284 
3285  if ( nIdx > 0 )
3286  {
3287  SwPaM aPam(rPos);
3288  aPam.GetPoint()->nContent = 0;
3289  aPam.SetMark();
3290  aPam.GetMark()->nContent = nIdx;
3291  DeleteRange( aPam );
3292  }
3293  }
3294 }
3295 
3296 // Copy method from SwDoc - "copy Flys in Flys"
3298  const SwNodeRange& rRg,
3299  const sal_Int32 nEndContentIndex,
3300  const SwNodeIndex& rInsPos,
3301  const std::pair<const SwPaM&, const SwPosition&>* pCopiedPaM /*and real insert pos*/,
3302  const bool bMakeNewFrames,
3303  const bool bDelRedlines,
3304  const bool bCopyFlyAtFly ) const
3305 {
3306  assert(!pCopiedPaM || pCopiedPaM->first.End()->nContent == nEndContentIndex);
3307  assert(!pCopiedPaM || pCopiedPaM->first.End()->nNode == rRg.aEnd);
3308 
3309  SwDoc* pDest = rInsPos.GetNode().GetDoc();
3310 
3311  SaveRedlEndPosForRestore aRedlRest( rInsPos, 0 );
3312 
3313  SwNodeIndex aSavePos( rInsPos, -1 );
3314  bool bEndIsEqualEndPos = rInsPos == rRg.aEnd;
3315  m_rDoc.GetNodes().CopyNodes( rRg, rInsPos, bMakeNewFrames, true );
3316  ++aSavePos;
3317  if( bEndIsEqualEndPos )
3318  const_cast<SwNodeIndex&>(rRg.aEnd) = aSavePos;
3319 
3320  aRedlRest.Restore();
3321 
3322 #if OSL_DEBUG_LEVEL > 0
3323  {
3324  //JP 17.06.99: Bug 66973 - check count only if the selection is in
3325  // the same section or there's no section, because sections that are
3326  // not fully selected are not copied.
3327  const SwSectionNode* pSSectNd = rRg.aStart.GetNode().FindSectionNode();
3328  SwNodeIndex aTmpI( rRg.aEnd, -1 );
3329  const SwSectionNode* pESectNd = aTmpI.GetNode().FindSectionNode();
3330  if( pSSectNd == pESectNd &&
3331  !rRg.aStart.GetNode().IsSectionNode() &&
3332  !aTmpI.GetNode().IsEndNode() )
3333  {
3334  // If the range starts with a SwStartNode, it isn't copied
3335  sal_uInt16 offset = (rRg.aStart.GetNode().GetNodeType() != SwNodeType::Start) ? 1 : 0;
3336  OSL_ENSURE( rInsPos.GetIndex() - aSavePos.GetIndex() ==
3337  rRg.aEnd.GetIndex() - rRg.aStart.GetIndex() - 1 + offset,
3338  "An insufficient number of nodes were copied!" );
3339  }
3340  }
3341 #endif
3342 
3343  {
3344  ::sw::UndoGuard const undoGuard(pDest->GetIDocumentUndoRedo());
3345  CopyFlyInFlyImpl( rRg, nEndContentIndex, aSavePos, bCopyFlyAtFly );
3346  }
3347 
3348  SwNodeRange aCpyRange( aSavePos, rInsPos );
3349 
3350  // Also copy all bookmarks
3351  // guess this must be done before the DelDummyNodes below as that
3352  // deletes nodes so would mess up the index arithmetic
3354  {
3355  SwPaM aRgTmp( rRg.aStart, rRg.aEnd );
3356  SwPaM aCpyPaM(aCpyRange.aStart, aCpyRange.aEnd);
3357  if (pCopiedPaM && rRg.aStart != pCopiedPaM->first.Start()->nNode)
3358  {
3359  // there is 1 (partially selected, maybe) paragraph before
3360  assert(SwNodeIndex(rRg.aStart, -1) == pCopiedPaM->first.Start()->nNode);
3361  // only use the passed in target SwPosition if the source PaM point
3362  // is on a different node; if it was the same node then the target
3363  // position was likely moved along by the copy operation and now
3364  // points to the end of the range!
3365  *aCpyPaM.GetPoint() = pCopiedPaM->second;
3366  }
3367 
3368  lcl_CopyBookmarks(pCopiedPaM ? pCopiedPaM->first : aRgTmp, aCpyPaM);
3369  }
3370 
3371  if( bDelRedlines && ( RedlineFlags::DeleteRedlines & pDest->getIDocumentRedlineAccess().GetRedlineFlags() ))
3372  lcl_DeleteRedlines( rRg, aCpyRange );
3373 
3374  pDest->GetNodes().DelDummyNodes( aCpyRange );
3375 }
3376 
3377 // TODO: there is a limitation here in that it's not possible to pass a start
3378 // content index - which means that at-character anchored frames inside
3379 // partial 1st paragraph of redline is not copied.
3380 // But the DelFlyInRange() that is called from DelCopyOfSection() does not
3381 // delete it either, and it also does not delete those on partial last para of
3382 // redline, so copying those is suppressed here too ...
3384  const SwNodeRange& rRg,
3385  const sal_Int32 nEndContentIndex,
3386  const SwNodeIndex& rStartIdx,
3387  const bool bCopyFlyAtFly ) const
3388 {
3389  // First collect all Flys, sort them according to their ordering number,
3390  // and then only copy them. This maintains the ordering numbers (which are only
3391  // managed in the DrawModel).
3392  SwDoc *const pDest = rStartIdx.GetNode().GetDoc();
3393  std::set< ZSortFly > aSet;
3394  const size_t nArrLen = m_rDoc.GetSpzFrameFormats()->size();
3395 
3396  SwTextBoxHelper::SavedLink aOldTextBoxes;
3398  SwTextBoxHelper::SavedContent aOldContent;
3399 
3400  for ( size_t n = 0; n < nArrLen; ++n )
3401  {
3402  SwFrameFormat* pFormat = (*m_rDoc.GetSpzFrameFormats())[n];
3403  SwFormatAnchor const*const pAnchor = &pFormat->GetAnchor();
3404  SwPosition const*const pAPos = pAnchor->GetContentAnchor();
3405  bool bAtContent = (pAnchor->GetAnchorId() == RndStdIds::FLY_AT_PARA);
3406  if ( !pAPos )
3407  continue;
3408  sal_uLong nSkipAfter = pAPos->nNode.GetIndex();
3409  sal_uLong nStart = rRg.aStart.GetIndex();
3410  switch ( pAnchor->GetAnchorId() )
3411  {
3412  case RndStdIds::FLY_AT_FLY:
3413  if(bCopyFlyAtFly)
3414  ++nSkipAfter;
3416  ++nStart;
3417  break;
3418  case RndStdIds::FLY_AT_CHAR:
3419  case RndStdIds::FLY_AT_PARA:
3421  ++nStart;
3422  break;
3423  default:
3424  continue;
3425  }
3426  if ( nStart > nSkipAfter )
3427  continue;
3428  if ( pAPos->nNode > rRg.aEnd )
3429  continue;
3430  //frames at the last source node are not always copied:
3431  //- if the node is empty and is the last node of the document or a table cell
3432  // or a text frame then they have to be copied
3433  //- if the content index in this node is > 0 then paragraph and frame bound objects are copied
3434  //- to-character bound objects are copied if their index is <= nEndContentIndex
3435  bool bAdd = false;
3436  if( pAPos->nNode < rRg.aEnd )
3437  bAdd = true;
3438  if (!bAdd && !m_rDoc.getIDocumentRedlineAccess().IsRedlineMove()) // fdo#40599: not for redline move
3439  {
3440  bool bEmptyNode = false;
3441  bool bLastNode = false;
3442  // is the node empty?
3443  const SwNodes& rNodes = pAPos->nNode.GetNodes();
3444  SwTextNode* pTextNode;
3445  if( nullptr != ( pTextNode = pAPos->nNode.GetNode().GetTextNode() ))
3446  {
3447  bEmptyNode = pTextNode->GetText().isEmpty();
3448  if( bEmptyNode )
3449  {
3450  //last node information is only necessary to know for the last TextNode
3451  SwNodeIndex aTmp( pAPos->nNode );
3452  ++aTmp;//goto next node
3453  while (aTmp.GetNode().IsEndNode())
3454  {
3455  if( aTmp == rNodes.GetEndOfContent().GetIndex() )
3456  {
3457  bLastNode = true;
3458  break;
3459  }
3460  ++aTmp;
3461  }
3462  }
3463  }
3464  bAdd = bLastNode && bEmptyNode;
3465  if( !bAdd )
3466  {
3467  if( bAtContent )
3468  bAdd = nEndContentIndex > 0;
3469  else
3470  bAdd = pAPos->nContent <= nEndContentIndex;
3471  }
3472  }
3473  if( bAdd )
3474  {
3475  // Make sure draw formats don't refer to content, so that such
3476  // content can be removed without problems.
3477  SwTextBoxHelper::resetLink(pFormat, aOldContent);
3478  aSet.insert( ZSortFly( pFormat, pAnchor, nArrLen + aSet.size() ));
3479  }
3480  }
3481 
3482  // Store all copied (and also the newly created) frames in another array.
3483  // They are stored as matching the originals, so that we will be later
3484  // able to build the chains accordingly.
3485  std::vector< SwFrameFormat* > aVecSwFrameFormat;
3486  std::set< ZSortFly >::const_iterator it=aSet.begin();
3487 
3488  while (it != aSet.end())
3489  {
3490  // #i59964#
3491  // correct determination of new anchor position
3492  SwFormatAnchor aAnchor( *(*it).GetAnchor() );
3493  assert( aAnchor.GetContentAnchor() != nullptr );
3494  SwPosition newPos = *aAnchor.GetContentAnchor();
3495  // for at-paragraph and at-character anchored objects the new anchor
3496  // position can *not* be determined by the difference of the current
3497  // anchor position to the start of the copied range, because not
3498  // complete selected sections in the copied range aren't copied - see
3499  // method <SwNodes::CopyNodes(..)>.
3500  // Thus, the new anchor position in the destination document is found
3501  // by counting the text nodes.
3502  if ((aAnchor.GetAnchorId() == RndStdIds::FLY_AT_PARA) ||
3503  (aAnchor.GetAnchorId() == RndStdIds::FLY_AT_CHAR) )
3504  {
3505  // First, determine number of anchor text node in the copied range.
3506  // Note: The anchor text node *have* to be inside the copied range.
3507  sal_uLong nAnchorTextNdNumInRange( 0 );
3508  bool bAnchorTextNdFound( false );
3509  SwNodeIndex aIdx( rRg.aStart );
3510  while ( !bAnchorTextNdFound && aIdx <= rRg.aEnd )
3511  {
3512  if ( aIdx.GetNode().IsTextNode() )
3513  {
3514  ++nAnchorTextNdNumInRange;
3515  bAnchorTextNdFound = aAnchor.GetContentAnchor()->nNode == aIdx;
3516  }
3517 
3518  ++aIdx;
3519  }
3520 
3521  if ( !bAnchorTextNdFound )
3522  {
3523  // This case can *not* happen, but to be robust take the first
3524  // text node in the destination document.
3525  OSL_FAIL( "<SwDoc::_CopyFlyInFly(..)> - anchor text node in copied range not found" );
3526  nAnchorTextNdNumInRange = 1;
3527  }
3528  // Second, search corresponding text node in destination document
3529  // by counting forward from start insert position <rStartIdx> the
3530  // determined number of text nodes.
3531  aIdx = rStartIdx;
3532  SwNodeIndex aAnchorNdIdx( rStartIdx );
3533  const SwNode& aEndOfContentNd =
3534  aIdx.GetNode().GetNodes().GetEndOfContent();
3535  while ( nAnchorTextNdNumInRange > 0 &&
3536  &(aIdx.GetNode()) != &aEndOfContentNd )
3537  {
3538  if ( aIdx.GetNode().IsTextNode() )
3539  {
3540  --nAnchorTextNdNumInRange;
3541  aAnchorNdIdx = aIdx;
3542  }
3543 
3544  ++aIdx;
3545  }
3546  if ( !aAnchorNdIdx.GetNode().IsTextNode() )
3547  {
3548  // This case can *not* happen, but to be robust take the first
3549  // text node in the destination document.
3550  OSL_FAIL( "<SwDoc::_CopyFlyInFly(..)> - found anchor node index isn't a text node" );
3551  aAnchorNdIdx = rStartIdx;
3552  while ( !aAnchorNdIdx.GetNode().IsTextNode() )
3553  {
3554  ++aAnchorNdIdx;
3555  }
3556  }
3557  // apply found anchor text node as new anchor position
3558  newPos.nNode = aAnchorNdIdx;
3559  }
3560  else
3561  {
3562  long nOffset = newPos.nNode.GetIndex() - rRg.aStart.GetIndex();
3563  SwNodeIndex aIdx( rStartIdx, nOffset );
3564  newPos.nNode = aIdx;
3565  }
3566  // Set the character bound Flys back at the original character
3567  if ((RndStdIds::FLY_AT_CHAR == aAnchor.GetAnchorId()) &&
3568  newPos.nNode.GetNode().IsTextNode() )
3569  {
3570  newPos.nContent.Assign( newPos.nNode.GetNode().GetTextNode(), newPos.nContent.GetIndex() );
3571  }
3572  else
3573  {
3574  newPos.nContent.Assign( nullptr, 0 );
3575  }
3576  aAnchor.SetAnchor( &newPos );
3577 
3578  // Check recursion: copy content in its own frame, then don't copy it.
3579  if( pDest == &m_rDoc )
3580  {
3581  const SwFormatContent& rContent = (*it).GetFormat()->GetContent();
3582  const SwStartNode* pSNd;
3583  if( rContent.GetContentIdx() &&
3584  nullptr != ( pSNd = rContent.GetContentIdx()->GetNode().GetStartNode() ) &&
3585  pSNd->GetIndex() < rStartIdx.GetIndex() &&
3586  rStartIdx.GetIndex() < pSNd->EndOfSectionIndex() )
3587  {
3588  it = aSet.erase(it);
3589  continue;
3590  }
3591  }
3592 
3593  // Copy the format and set the new anchor
3594  aVecSwFrameFormat.push_back( pDest->getIDocumentLayoutAccess().CopyLayoutFormat( *(*it).GetFormat(),
3595  aAnchor, false, true ) );
3596  ++it;
3597  }
3598 
3599  // Rebuild as much as possible of all chains that are available in the original,
3600  OSL_ENSURE( aSet.size() == aVecSwFrameFormat.size(), "Missing new Flys" );
3601  if ( aSet.size() == aVecSwFrameFormat.size() )
3602  {
3603  size_t n = 0;
3604  for (const auto& rFlyN : aSet)
3605  {
3606  const SwFrameFormat *pFormatN = rFlyN.GetFormat();
3607  const SwFormatChain &rChain = pFormatN->GetChain();
3608  int nCnt = int(nullptr != rChain.GetPrev());
3609  nCnt += rChain.GetNext() ? 1: 0;
3610  size_t k = 0;
3611  for (const auto& rFlyK : aSet)
3612  {
3613  const SwFrameFormat *pFormatK = rFlyK.GetFormat();
3614  if ( rChain.GetPrev() == pFormatK )
3615  {
3616  ::lcl_ChainFormats( static_cast< SwFlyFrameFormat* >(aVecSwFrameFormat[k]),
3617  static_cast< SwFlyFrameFormat* >(aVecSwFrameFormat[n]) );
3618  --nCnt;
3619  }
3620  else if ( rChain.GetNext() == pFormatK )
3621  {
3622  ::lcl_ChainFormats( static_cast< SwFlyFrameFormat* >(aVecSwFrameFormat[n]),
3623  static_cast< SwFlyFrameFormat* >(aVecSwFrameFormat[k]) );
3624  --nCnt;
3625  }
3626  ++k;
3627  }
3628  ++n;
3629  }
3630 
3631  // Re-create content property of draw formats, knowing how old shapes
3632  // were paired with old fly formats (aOldTextBoxes) and that aSet is
3633  // parallel with aVecSwFrameFormat.
3634  SwTextBoxHelper::restoreLinks(aSet, aVecSwFrameFormat, aOldTextBoxes, aOldContent);
3635  }
3636 }
3637 
3638 /*
3639  * Reset the text's hard formatting
3640  */
3645 {
3646  ParaRstFormat* pPara = static_cast<ParaRstFormat*>(pArgs);
3647  if (pPara->pLayout && pPara->pLayout->IsHideRedlines()
3649  {
3650  return true; // skip hidden, since new items aren't applied
3651  }
3652  SwTextNode * pTextNode = rpNd->GetTextNode();
3653  if( pTextNode && pTextNode->GetpSwpHints() )
3654  {
3655  SwIndex aSt( pTextNode, 0 );
3656  sal_Int32 nEnd = pTextNode->Len();
3657 
3658  if( &pPara->pSttNd->nNode.GetNode() == pTextNode &&
3659  pPara->pSttNd->nContent.GetIndex() )
3660  aSt = pPara->pSttNd->nContent.GetIndex();
3661 
3662  if( &pPara->pEndNd->nNode.GetNode() == rpNd )
3663  nEnd = pPara->pEndNd->nContent.GetIndex();
3664 
3665  if( pPara->pHistory )
3666  {
3667  // Save all attributes for the Undo.
3668  SwRegHistory aRHst( *pTextNode, pPara->pHistory );
3669  pTextNode->GetpSwpHints()->Register( &aRHst );
3670  pTextNode->RstTextAttr( aSt, nEnd - aSt.GetIndex(), pPara->nWhich,
3671  pPara->pDelSet, pPara->bInclRefToxMark, pPara->bExactRange );
3672  if( pTextNode->GetpSwpHints() )
3673  pTextNode->GetpSwpHints()->DeRegister();
3674  }
3675  else
3676  pTextNode->RstTextAttr( aSt, nEnd - aSt.GetIndex(), pPara->nWhich,
3677  pPara->pDelSet, pPara->bInclRefToxMark, pPara->bExactRange );
3678  }
3679  return true;
3680 }
3681 
3683 {
3684 }
3685 //Private methods
3686 
3688 {
3690 
3692 
3693  if (*rPam.GetPoint() == *rPam.GetMark())
3694  {
3695  return false; // do not add empty redlines
3696  }
3697 
3698  std::vector<SwRangeRedline*> redlines;
3699  {
3700  auto pRedline(std::make_unique<SwRangeRedline>(RedlineType::Delete, rPam));
3701  if (pRedline->HasValidRange())
3702  {
3703  redlines.push_back(pRedline.release());
3704  }
3705  else // sigh ... why is such a selection even possible...
3706  { // split it up so we get one SwUndoRedlineDelete per inserted RL
3707  redlines = GetAllValidRanges(std::move(pRedline));
3708  }
3709  }
3710 
3711  if (redlines.empty())
3712  {
3713  return false;
3714  }
3715 
3716  auto & rDMA(*m_rDoc.getIDocumentMarkAccess());
3717  std::vector<std::unique_ptr<SwUndo>> MarkUndos;
3718  for (auto iter = rDMA.getAnnotationMarksBegin();
3719  iter != rDMA.getAnnotationMarksEnd(); )
3720  {
3721  // tdf#111524 remove annotation marks that have their field
3722  // characters deleted
3723  SwPosition const& rEndPos((**iter).GetMarkEnd());
3724  if (*rPam.Start() < rEndPos && rEndPos <= *rPam.End())
3725  {
3727  {
3728  MarkUndos.emplace_back(std::make_unique<SwUndoDeleteBookmark>(**iter));
3729  }
3730  // iter is into annotation mark vector so must be dereferenced!
3731  rDMA.deleteMark(&**iter);
3732  // this invalidates iter, have to start over...
3733  iter = rDMA.getAnnotationMarksBegin();
3734  }
3735  else
3736  { // marks are sorted by start
3737  if (*rPam.End() < (**iter).GetMarkStart())
3738  {
3739  break;
3740  }
3741  ++iter;
3742  }
3743  }
3744 
3745  // tdf#119019 accept tracked paragraph formatting to do not hide new deletions
3746  if (*rPam.GetPoint() != *rPam.GetMark())
3748 
3749  std::vector<std::unique_ptr<SwUndoRedlineDelete>> undos;
3751  {
3752  // this should no longer happen in calls from the UI but maybe via API
3753  // (randomTest and testTdf54819 triggers it)
3754  SAL_WARN_IF((eOld & RedlineFlags::ShowMask) != RedlineFlags::ShowMask,
3755  "sw.core", "redlines will be moved in DeleteAndJoin");
3758  for (SwRangeRedline * pRedline : redlines)
3759  {
3760  assert(pRedline->HasValidRange());
3761  undos.emplace_back(std::make_unique<SwUndoRedlineDelete>(
3762  *pRedline, SwUndoId::DELETE));
3763  }
3764  const SwRewriter aRewriter = undos.front()->GetRewriter();
3765  // can only group a single undo action
3766  if (MarkUndos.empty() && undos.size() == 1
3768  {
3769  SwUndo * const pLastUndo( m_rDoc.GetUndoManager().GetLastUndo() );
3770  SwUndoRedlineDelete *const pUndoRedlineDel(dynamic_cast<SwUndoRedlineDelete*>(pLastUndo));
3771  bool const bMerged = pUndoRedlineDel
3772  && pUndoRedlineDel->CanGrouping(*undos.front());
3773  if (!bMerged)
3774  {
3775  m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::move(undos.front()));
3776  }
3777  undos.clear(); // prevent unmatched EndUndo
3778  }
3779  else
3780  {
3782  for (auto& it : MarkUndos)
3783  {
3784  m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::move(it));
3785  }
3786  for (auto & it : undos)
3787  {
3788  m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::move(it));
3789  }
3790  }
3791  }
3792 
3793  for (SwRangeRedline *const pRedline : redlines)
3794  {
3795  // note: 1. the pRedline can still be merged & deleted
3796  // 2. the impl. can even DeleteAndJoin the range => no plain PaM
3797  std::shared_ptr<SwUnoCursor> const pCursor(m_rDoc.CreateUnoCursor(*pRedline->GetMark()));
3798  pCursor->SetMark();
3799  *pCursor->GetPoint() = *pRedline->GetPoint();
3801  // sw_redlinehide: 2 reasons why this is needed:
3802  // 1. it's the first redline in node => RedlineDelText was sent but ignored
3803  // 2. redline spans multiple nodes => must merge text frames
3805  }
3807 
3809  {
3810  if (!undos.empty())
3811  {
3813  }
3815  }
3816  return true;
3817 }
3818 
3820  const bool bForceJoinNext )
3821 {
3822  bool bJoinText, bJoinPrev;
3823  ::sw_GetJoinFlags( rPam, bJoinText, bJoinPrev );
3824  // #i100466#
3825  if ( bForceJoinNext )
3826  {
3827  bJoinPrev = false;
3828  }
3829 
3830  {
3831  bool const bSuccess( DeleteRangeImpl( rPam ) );
3832  if (!bSuccess)
3833  return false;
3834  }
3835 
3836  if( bJoinText )
3837  {
3838  ::sw_JoinText( rPam, bJoinPrev );
3839  }
3840 
3843  {
3845  }
3846 
3847  return true;
3848 }
3849 
3851 {
3852  // Move all cursors out of the deleted range, but first copy the
3853  // passed PaM, because it could be a cursor that would be moved!
3854  SwPaM aDelPam( *rPam.GetMark(), *rPam.GetPoint() );
3855  ::PaMCorrAbs( aDelPam, *aDelPam.GetPoint() );
3856 
3857  bool const bSuccess( DeleteRangeImplImpl( aDelPam ) );
3858  if (bSuccess)
3859  { // now copy position from temp copy to given PaM
3860  *rPam.GetPoint() = *aDelPam.GetPoint();
3861  }
3862 
3863  return bSuccess;
3864 }
3865 
3867 {
3868  SwPosition *pStt = rPam.Start(), *pEnd = rPam.End();
3869 
3870  if( !rPam.HasMark() || *pStt >= *pEnd )
3871  return false;
3872 
3874  {
3875  // if necessary the saved Word for the exception
3876  if( m_rDoc.GetAutoCorrExceptWord()->IsDeleted() || pStt->nNode != pEnd->nNode ||
3877  pStt->nContent.GetIndex() + 1 != pEnd->nContent.GetIndex() ||
3880  }
3881 
3882  {
3883  // Delete all empty TextHints at the Mark's position
3884  SwTextNode* pTextNd = rPam.GetMark()->nNode.GetNode().GetTextNode();
3885  SwpHints* pHts;
3886  if( pTextNd && nullptr != ( pHts = pTextNd->GetpSwpHints()) && pHts->Count() )
3887  {
3888  const sal_Int32 nMkCntPos = rPam.GetMark()->nContent.GetIndex();
3889  for( size_t n = pHts->Count(); n; )
3890  {
3891  const SwTextAttr* pAttr = pHts->Get( --n );
3892  if( nMkCntPos > pAttr->GetStart() )
3893  break;
3894 
3895  const sal_Int32 *pEndIdx;
3896  if( nMkCntPos == pAttr->GetStart() &&
3897  nullptr != (pEndIdx = pAttr->End()) &&
3898  *pEndIdx == pAttr->GetStart() )
3899  pTextNd->DestroyAttr( pHts->Cut( n ) );
3900  }
3901  }
3902  }
3903 
3904  {
3905  // Send DataChanged before deletion, so that we still know
3906  // which objects are in the range.
3907  // Afterwards they could be before/after the Position.
3908  SwDataChanged aTmp( rPam );
3909  }
3910 
3912  {
3914  bool bMerged(false);
3916  {
3917  SwUndo *const pLastUndo( m_rDoc.GetUndoManager().GetLastUndo() );
3918  SwUndoDelete *const pUndoDelete(
3919  dynamic_cast<SwUndoDelete *>(pLastUndo) );
3920  if (pUndoDelete)
3921  {
3922  bMerged = pUndoDelete->CanGrouping( &m_rDoc, rPam );
3923  // if CanGrouping() returns true it's already merged
3924  }
3925  }
3926  if (!bMerged)
3927  {
3928  m_rDoc.GetIDocumentUndoRedo().AppendUndo( std::make_unique<SwUndoDelete>( rPam ) );
3929  }
3930 
3932 
3933  return true;
3934  }
3935 
3938 
3939  // Delete and move all "Flys at the paragraph", which are within the Selection
3940  DelFlyInRange(rPam.GetMark()->nNode, rPam.GetPoint()->nNode);
3941  DelBookmarks(
3942  pStt->nNode,
3943  pEnd->nNode,
3944  nullptr,
3945  &pStt->nContent,
3946  &pEnd->nContent);
3947 
3948  SwNodeIndex aSttIdx( pStt->nNode );
3949  SwContentNode * pCNd = aSttIdx.GetNode().GetContentNode();
3950 
3951  do { // middle checked loop!
3952  if( pCNd )
3953  {
3954  SwTextNode * pStartTextNode( pCNd->GetTextNode() );
3955  if ( pStartTextNode )
3956  {
3957  // now move the Content to the new Node
3958  bool bOneNd = pStt->nNode == pEnd->nNode;
3959  const sal_Int32 nLen = ( bOneNd ? pEnd->nContent.GetIndex()
3960  : pCNd->Len() )
3961  - pStt->nContent.GetIndex();
3962 
3963  // Don't call again, if already empty
3964  if( nLen )
3965  {
3966  pStartTextNode->EraseText( pStt->nContent, nLen );
3967 
3968  if( !pStartTextNode->Len() )
3969  {
3970  // METADATA: remove reference if empty (consider node deleted)
3971  pStartTextNode->RemoveMetadataReference();
3972  }
3973  }
3974 
3975  if( bOneNd ) // that's it
3976  break;
3977 
3978  ++aSttIdx;
3979  }
3980  else
3981  {
3982  // So that there are no indices left registered when deleted,
3983  // we remove a SwPaM from the Content here.
3984  pStt->nContent.Assign( nullptr, 0 );
3985  }
3986  }
3987 
3988  pCNd = pEnd->nNode.GetNode().GetContentNode();
3989  if( pCNd )
3990  {
3991  SwTextNode * pEndTextNode( pCNd->GetTextNode() );
3992  if( pEndTextNode )
3993  {
3994  // if already empty, don't call again
3995  if( pEnd->nContent.GetIndex() )
3996  {
3997  SwIndex aIdx( pCNd, 0 );
3998  pEndTextNode->EraseText( aIdx, pEnd->nContent.GetIndex() );
3999 
4000  if( !pEndTextNode->Len() )
4001  {
4002  // METADATA: remove reference if empty (consider node deleted)
4003  pEndTextNode->RemoveMetadataReference();
4004  }
4005  }
4006  }
4007  else
4008  {
4009  // So that there are no indices left registered when deleted,
4010  // we remove a SwPaM from the Content here.
4011  pEnd->nContent.Assign( nullptr, 0 );
4012  }
4013  }
4014 
4015  // if the end is not a content node, delete it as well
4016  sal_uInt32 nEnde = pEnd->nNode.GetIndex();
4017  if( pCNd == nullptr )
4018  nEnde++;
4019 
4020  if( aSttIdx != nEnde )
4021  {
4022  // delete the Nodes into the NodesArary
4023  m_rDoc.GetNodes().Delete( aSttIdx, nEnde - aSttIdx.GetIndex() );
4024  }
4025 
4026  // If the Node that contained the Cursor has been deleted,
4027  // the Content has to be assigned to the current Content.
4028  pStt->nContent.Assign( pStt->nNode.GetNode().GetContentNode(),
4029  pStt->nContent.GetIndex() );
4030 
4031  // If we deleted across Node boundaries we have to correct the PaM,
4032  // because they are in different Nodes now.
4033  // Also, the Selection is revoked.
4034  *pEnd = *pStt;
4035  rPam.DeleteMark();
4036 
4037  } while( false );
4038 
4040 
4041  return true;
4042 }
4043 
4044 // It's possible to call Replace with a PaM that spans 2 paragraphs:
4045 // search with regex for "$", then replace _all_
4047  const bool bRegExReplace )
4048 {
4049  if( !rPam.HasMark() || *rPam.GetPoint() == *rPam.GetMark() )
4050  return false;
4051 
4052  bool bJoinText, bJoinPrev;
4053  ::sw_GetJoinFlags( rPam, bJoinText, bJoinPrev );
4054 
4055  {
4056  // Create a copy of the Cursor in order to move all Pams from
4057  // the other views out of the deletion range.
4058  // Except for itself!
4059  SwPaM aDelPam( *rPam.GetMark(), *rPam.GetPoint() );
4060  ::PaMCorrAbs( aDelPam, *aDelPam.GetPoint() );
4061 
4062  SwPosition *pStt = aDelPam.Start(),
4063  *pEnd = aDelPam.End();
4064  bool bOneNode = pStt->nNode == pEnd->nNode;
4065 
4066  // Own Undo?
4067  OUString sRepl( rStr );
4068  SwTextNode* pTextNd = pStt->nNode.GetNode().GetTextNode();
4069  sal_Int32 nStt = pStt->nContent.GetIndex();
4070  sal_Int32 nEnd;
4071 
4072  SwDataChanged aTmp( aDelPam );
4073 
4075  {
4078  {
4079  // this should no longer happen in calls from the UI but maybe via API
4080  SAL_WARN_IF((eOld & RedlineFlags::ShowMask) != RedlineFlags::ShowMask,
4081  "sw.core", "redlines will be moved in ReplaceRange");
4082 
4084 
4085  // If any Redline will change (split!) the node
4086  const ::sw::mark::IMark* pBkmk =
4090 
4093 
4094  *aDelPam.GetPoint() = pBkmk->GetMarkPos();
4095  if(pBkmk->IsExpanded())
4096  *aDelPam.GetMark() = pBkmk->GetOtherMarkPos();
4098  pStt = aDelPam.Start();
4099  pTextNd = pStt->nNode.GetNode().GetTextNode();
4100  nStt = pStt->nContent.GetIndex();
4101  }
4102 
4103  if( !sRepl.isEmpty() )
4104  {
4105  // Apply the first character's attributes to the ReplaceText
4106  SfxItemSet aSet( m_rDoc.GetAttrPool(),
4109  pTextNd->GetParaAttr( aSet, nStt+1, nStt+1 );
4110 
4111  aSet.ClearItem( RES_TXTATR_REFMARK );
4112  aSet.ClearItem( RES_TXTATR_TOXMARK );
4113  aSet.ClearItem( RES_TXTATR_CJK_RUBY );
4114  aSet.ClearItem( RES_TXTATR_INETFMT );
4115  aSet.ClearItem( RES_TXTATR_META );
4116  aSet.ClearItem( RES_TXTATR_METAFIELD );
4117 
4118  if( aDelPam.GetPoint() != aDelPam.End() )
4119  aDelPam.Exchange();
4120 
4121  // Remember the End
4122  SwNodeIndex aPtNd( aDelPam.GetPoint()->nNode, -1 );
4123  const sal_Int32 nPtCnt = aDelPam.GetPoint()->nContent.GetIndex();
4124 
4125  bool bFirst = true;
4126  OUString sIns;
4127  while ( lcl_GetTokenToParaBreak( sRepl, sIns, bRegExReplace ) )
4128  {
4129  InsertString( aDelPam, sIns );
4130  if( bFirst )
4131  {
4132  SwNodeIndex aMkNd( aDelPam.GetMark()->nNode, -1 );
4133  const sal_Int32 nMkCnt = aDelPam.GetMark()->nContent.GetIndex();
4134 
4135  SplitNode( *aDelPam.GetPoint(), false );
4136 
4137  ++aMkNd;
4138  aDelPam.GetMark()->nNode = aMkNd;
4139  aDelPam.GetMark()->nContent.Assign(
4140  aMkNd.GetNode().GetContentNode(), nMkCnt );
4141  bFirst = false;
4142  }
4143  else
4144  SplitNode( *aDelPam.GetPoint(), false );
4145  }
4146  if( !sIns.isEmpty() )
4147  {
4148  InsertString( aDelPam, sIns );
4149  }
4150 
4151  SwPaM aTmpRange( *aDelPam.GetPoint() );
4152  aTmpRange.SetMark();
4153 
4154  ++aPtNd;
4155  aDelPam.GetPoint()->nNode = aPtNd;
4156  aDelPam.GetPoint()->nContent.Assign( aPtNd.GetNode().GetContentNode(),
4157  nPtCnt);
4158  *aTmpRange.GetMark() = *aDelPam.GetPoint();
4159 
4160  m_rDoc.RstTextAttrs( aTmpRange );
4161  InsertItemSet( aTmpRange, aSet );
4162  }
4163 
4165  {
4167  std::make_unique<SwUndoRedlineDelete>( aDelPam, SwUndoId::REPLACE ));
4168  }
4170 
4171  *rPam.GetMark() = *aDelPam.GetMark();
4173  {
4174  *aDelPam.GetPoint() = *rPam.GetPoint();
4176 
4177  // If any Redline will change (split!) the node
4178  const ::sw::mark::IMark* pBkmk =
4182 
4183  SwIndex& rIdx = aDelPam.GetPoint()->nContent;
4184  rIdx.Assign( nullptr, 0 );
4185  aDelPam.GetMark()->nContent = rIdx;
4186  rPam.GetPoint()->nNode = 0;
4187  rPam.GetPoint()->nContent = rIdx;
4188  *rPam.GetMark() = *rPam.GetPoint();
4190 
4191  *rPam.GetPoint() = pBkmk->GetMarkPos();
4192  if(pBkmk->IsExpanded())
4193  *rPam.GetMark() = pBkmk->GetOtherMarkPos();
4195  }
4196  bJoinText = false;
4197  }
4198  else
4199  {
4200  assert((pStt->nNode == pEnd->nNode ||
4201  ( pStt->nNode.GetIndex() + 1 == pEnd->nNode.GetIndex() &&
4202  !pEnd->nContent.GetIndex() )) &&
4203  "invalid range: Point and Mark on different nodes" );
4204 
4207 
4208  SwUndoReplace* pUndoRpl = nullptr;
4209  bool const bDoesUndo = m_rDoc.GetIDocumentUndoRedo().DoesUndo();
4210  if (bDoesUndo)
4211  {
4212  pUndoRpl = new SwUndoReplace(aDelPam, sRepl, bRegExReplace);
4213  m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::unique_ptr<SwUndo>(pUndoRpl));
4214  }
4215  ::sw::UndoGuard const undoGuard(m_rDoc.GetIDocumentUndoRedo());
4216 
4217  if( aDelPam.GetPoint() != pStt )
4218  aDelPam.Exchange();
4219 
4220  SwNodeIndex aPtNd( pStt->nNode, -1 );
4221  const sal_Int32 nPtCnt = pStt->nContent.GetIndex();
4222 
4223  // Set the values again, if Frames or footnotes on the Text have been removed.
4224  nStt = nPtCnt;
4225  nEnd = bOneNode ? pEnd->nContent.GetIndex()
4226  : pTextNd->GetText().getLength();
4227 
4228  bool bFirst = true;
4229  OUString sIns;
4230  while ( lcl_GetTokenToParaBreak( sRepl, sIns, bRegExReplace ) )
4231  {
4232  if (!bFirst || nStt == pTextNd->GetText().getLength())
4233  {
4234  InsertString( aDelPam, sIns );
4235  }
4236  else if( nStt < nEnd || !sIns.isEmpty() )
4237  {
4238  pTextNd->ReplaceText( pStt->nContent, nEnd - nStt, sIns );
4239  }
4240  SplitNode( *pStt, false);
4241  bFirst = false;
4242  }
4243 
4244  if( bFirst || !sIns.isEmpty() )
4245  {
4246  if (!bFirst || nStt == pTextNd->GetText().getLength())
4247  {
4248  InsertString( aDelPam, sIns );
4249  }
4250  else if( nStt < nEnd || !sIns.isEmpty() )
4251  {
4252  pTextNd->ReplaceText( pStt->nContent, nEnd - nStt, sIns );
4253  }
4254  }
4255 
4256  *rPam.GetPoint() = *aDelPam.GetMark();
4257  ++aPtNd;
4258  rPam.GetMark()->nNode = aPtNd;
4259  rPam.GetMark()->nContent.Assign( aPtNd.GetNode().GetContentNode(),
4260  nPtCnt );
4261 
4262  if (bJoinText)
4263  {
4264  assert(rPam.GetPoint() == rPam.End());
4265  // move so that SetEnd remembers position after sw_JoinText
4266  rPam.Move(fnMoveBackward);
4267  }
4268  else if (aDelPam.GetPoint() == pStt) // backward selection?
4269  {
4270  assert(*rPam.GetMark() <= *rPam.GetPoint());
4271  rPam.Exchange(); // swap so that rPam is backwards
4272  }
4273 
4274  if( pUndoRpl )
4275  {
4276  pUndoRpl->SetEnd(rPam);
4277  }
4278  }
4279  }
4280 
4281  bool bRet(true);
4282  if (bJoinText)
4283  {
4284  bRet = ::sw_JoinText(rPam, bJoinPrev);
4285  }
4286 
4288  return bRet;
4289 }
4290 
4292  const SfxItemSet* pFlyAttrSet,
4293  const SfxItemSet* pGrfAttrSet,
4294  SwFrameFormat* pFrameFormat)
4295 {
4296  SwFlyFrameFormat *pFormat = nullptr;
4297  if( pNode )
4298  {
4299  pFormat = m_rDoc.MakeFlySection_( rPos, *pNode, RndStdIds::FLY_AT_PARA,
4300  pFlyAttrSet, pFrameFormat );
4301  if( pGrfAttrSet )
4302  pNode->SetAttr( *pGrfAttrSet );
4303  }
4304  return pFormat;
4305 }
4306 
4307 #define NUMRULE_STATE \
4308  SfxItemState aNumRuleState = SfxItemState::UNKNOWN; \
4309  std::shared_ptr<SwNumRuleItem> aNumRuleItem; \
4310  SfxItemState aListIdState = SfxItemState::UNKNOWN; \
4311  std::shared_ptr<SfxStringItem> aListIdItem; \
4312 
4313 #define PUSH_NUMRULE_STATE \
4314  lcl_PushNumruleState( aNumRuleState, aNumRuleItem, aListIdState, aListIdItem, pDestTextNd );
4315 
4316 #define POP_NUMRULE_STATE \
4317  lcl_PopNumruleState( aNumRuleState, aNumRuleItem, aListIdState, aListIdItem, pDestTextNd, rPam );
4318 
4320  SfxItemState &aNumRuleState, std::shared_ptr<SwNumRuleItem>& aNumRuleItem,
4321  SfxItemState &aListIdState, std::shared_ptr<SfxStringItem>& aListIdItem,
4322  const SwTextNode *pDestTextNd )
4323 {
4324  // Safe numrule item at destination.
4325  // #i86492# - Safe also <ListId> item of destination.
4326  const SfxItemSet * pAttrSet = pDestTextNd->GetpSwAttrSet();
4327  if (pAttrSet != nullptr)
4328  {
4329  const SfxPoolItem * pItem = nullptr;
4330  aNumRuleState = pAttrSet->GetItemState(RES_PARATR_NUMRULE, false, &pItem);
4331  if (SfxItemState::SET == aNumRuleState)
4332  {
4333  aNumRuleItem.reset(static_cast<SwNumRuleItem*>(pItem->Clone()));
4334  }
4335 
4336  aListIdState = pAttrSet->GetItemState(RES_PARATR_LIST_ID, false, &pItem);
4337  if (SfxItemState::SET == aListIdState)
4338  {
4339  aListIdItem.reset(static_cast<SfxStringItem*>(pItem->Clone()));
4340  }
4341  }
4342 }
4343 
4345  SfxItemState aNumRuleState, const std::shared_ptr<SwNumRuleItem>& aNumRuleItem,
4346  SfxItemState aListIdState, const std::shared_ptr<SfxStringItem>& aListIdItem,
4347  SwTextNode *pDestTextNd, const SwPaM& rPam )
4348 {
4349  /* If only a part of one paragraph is copied
4350  restore the numrule at the destination. */
4351  // #i86492# - restore also <ListId> item
4352  if ( !lcl_MarksWholeNode(rPam) )
4353  {
4354  if (SfxItemState::SET == aNumRuleState)
4355  {
4356  pDestTextNd->SetAttr(*aNumRuleItem);
4357  }
4358  else
4359  {
4360  pDestTextNd->ResetAttr(RES_PARATR_NUMRULE);
4361  }
4362  if (SfxItemState::SET == aListIdState)
4363  {
4364  pDestTextNd->SetAttr(*aListIdItem);
4365  }
4366  else
4367  {
4368  pDestTextNd->ResetAttr(RES_PARATR_LIST_ID);
4369  }
4370  }
4371 }
4372 
4374  const bool bMakeNewFrames, const bool bCopyAll,
4375  SwPaM *const pCpyRange ) const
4376 {
4377  SwDoc* pDoc = rPos.nNode.GetNode().GetDoc();
4378  const bool bColumnSel = pDoc->IsClipBoard() && pDoc->IsColumnSelection();
4379 
4380  SwPosition* pStt = rPam.Start();
4381  SwPosition* pEnd = rPam.End();
4382 
4383  // Catch when there's no copy to do.
4384  if( !rPam.HasMark() || ( *pStt >= *pEnd && !bColumnSel ) ||
4385  //JP 29.6.2001: 88963 - don't copy if inspos is in region of start to end
4386  //JP 15.11.2001: don't test inclusive the end, ever exclusive
4387  ( pDoc == &m_rDoc && *pStt <= rPos && rPos < *pEnd ))
4388  {
4389  return false;
4390  }
4391 
4392  const bool bEndEqualIns = pDoc == &m_rDoc && rPos == *pEnd;
4393 
4394  // If Undo is enabled, create the UndoCopy object
4395  SwUndoCpyDoc* pUndo = nullptr;
4396  // lcl_DeleteRedlines may delete the start or end node of the cursor when
4397  // removing the redlines so use cursor that is corrected by PaMCorrAbs
4398  std::shared_ptr<SwUnoCursor> const pCopyPam(pDoc->CreateUnoCursor(rPos));
4399 
4400  SwTableNumFormatMerge aTNFM( m_rDoc, *pDoc );
4401 
4402  if (pDoc->GetIDocumentUndoRedo().DoesUndo())
4403  {
4404  pUndo = new SwUndoCpyDoc(*pCopyPam);
4405  pDoc->GetIDocumentUndoRedo().AppendUndo( std::unique_ptr<SwUndo>(pUndo) );
4406  }
4407 
4410 
4411  // Move the PaM one node back from the insert position, so that
4412  // the position doesn't get moved
4413  pCopyPam->SetMark();
4414  bool bCanMoveBack = pCopyPam->Move(fnMoveBackward, GoInContent);
4415  // If the position was shifted from more than one node, an end node has been skipped
4416  bool bAfterTable = false;
4417  if ((rPos.nNode.GetIndex() - pCopyPam->GetPoint()->nNode.GetIndex()) > 1)
4418  {
4419  // First go back to the original place
4420  pCopyPam->GetPoint()->nNode = rPos.nNode;
4421  pCopyPam->GetPoint()->nContent = rPos.nContent;
4422 
4423  bCanMoveBack = false;
4424  bAfterTable = true;
4425  }
4426  if( !bCanMoveBack )
4427  pCopyPam->GetPoint()->nNode--;
4428 
4429  SwNodeRange aRg( pStt->nNode, pEnd->nNode );
4430  SwNodeIndex aInsPos( rPos.nNode );
4431  const bool bOneNode = pStt->nNode == pEnd->nNode;
4432  SwTextNode* pSttTextNd = pStt->nNode.GetNode().GetTextNode();
4433  SwTextNode* pEndTextNd = pEnd->nNode.GetNode().GetTextNode();
4434  SwTextNode* pDestTextNd = aInsPos.GetNode().GetTextNode();
4435  bool bCopyCollFormat = !pDoc->IsInsOnlyTextGlossary() &&
4436  ( (pDestTextNd && !pDestTextNd->GetText().getLength()) ||
4437  ( !bOneNode && !rPos.nContent.GetIndex() ) );
4438  bool bCopyBookmarks = true;
4439  bool bCopyPageSource = false;
4440  bool bStartIsTextNode = nullptr != pSttTextNd;
4441 
4442  // #i104585# copy outline num rule to clipboard (for ASCII filter)
4443  if (pDoc->IsClipBoard() && m_rDoc.GetOutlineNumRule())
4444  {
4446  }
4447 
4448  // #i86492#
4449  // Correct the search for a previous list:
4450  // First search for non-outline numbering list. Then search for non-outline
4451  // bullet list.
4452  // Keep also the <ListId> value for possible propagation.
4453  OUString aListIdToPropagate;
4454  const SwNumRule* pNumRuleToPropagate =
4455  pDoc->SearchNumRule( rPos, false, true, false, 0, aListIdToPropagate, nullptr, true );
4456  if ( !pNumRuleToPropagate )
4457  {
4458  pNumRuleToPropagate =
4459  pDoc->SearchNumRule( rPos, false, false, false, 0, aListIdToPropagate, nullptr, true );
4460  }
4461  // #i86492#
4462  // Do not propagate previous found list, if
4463  // - destination is an empty paragraph which is not in a list and
4464  // - source contains at least one paragraph which is not in a list
4465  if ( pNumRuleToPropagate &&
4466  pDestTextNd && !pDestTextNd->GetText().getLength() &&
4467  !pDestTextNd->IsInList() &&
4468  !lcl_ContainsOnlyParagraphsInList( rPam ) )
4469  {
4470  pNumRuleToPropagate = nullptr;
4471  }
4472 
4473  // This do/while block is only there so that we can break out of it!
4474  do {
4475  if( pSttTextNd )
4476  {
4477  // Don't copy the beginning completely?
4478  if( !bCopyCollFormat || bColumnSel || pStt->nContent.GetIndex() )
4479  {
4480  SwIndex aDestIdx( rPos.nContent );
4481  bool bCopyOk = false;
4482  if( !pDestTextNd )
4483  {
4484  if( pStt->nContent.GetIndex() || bOneNode )
4485  pDestTextNd = pDoc->GetNodes().MakeTextNode( aInsPos,
4487  else
4488  {
4489  pDestTextNd = pSttTextNd->MakeCopy(pDoc, aInsPos, true)->GetTextNode();
4490  bCopyOk = true;
4491  }
4492  aDestIdx.Assign( pDestTextNd, 0 );
4493  bCopyCollFormat = true;
4494  }
4495  else if( !bOneNode || bColumnSel )
4496  {
4497  const sal_Int32 nContentEnd = pEnd->nContent.GetIndex();
4498  {
4499  ::sw::UndoGuard const ug(pDoc->GetIDocumentUndoRedo());
4500  pDoc->getIDocumentContentOperations().SplitNode( rPos, false );
4501  }
4502 
4503  if (bCanMoveBack && rPos == *pCopyPam->GetPoint())
4504  {
4505  // after the SplitNode, span the CpyPam correctly again
4506  pCopyPam->Move( fnMoveBackward, GoInContent );
4507  pCopyPam->Move( fnMoveBackward, GoInContent );
4508  }
4509 
4510  pDestTextNd = pDoc->GetNodes()[ aInsPos.GetIndex()-1 ]->GetTextNode();
4511  aDestIdx.Assign(
4512  pDestTextNd, pDestTextNd->GetText().getLength());
4513 
4514  // Correct the area again
4515  if( bEndEqualIns )
4516  {
4517  bool bChg = pEnd != rPam.GetPoint();
4518  if( bChg )
4519  rPam.Exchange();
4520  rPam.Move( fnMoveBackward, GoInContent );
4521  if( bChg )
4522  rPam.Exchange();
4523  }
4524  else if( rPos == *pEnd )
4525  {
4526  // The end was also moved
4527  pEnd->nNode--;
4528  pEnd->nContent.Assign( pDestTextNd, nContentEnd );
4529  }
4530  // tdf#63022 always reset pEndTextNd after SplitNode
4531  aRg.aEnd = pEnd->nNode;
4532  pEndTextNd = pEnd->nNode.GetNode().GetTextNode();
4533  }
4534 
4536  if( bCopyCollFormat && bOneNode )
4537  {
4539  }
4540 
4541  if( !bCopyOk )
4542  {
4543  const sal_Int32 nCpyLen = ( bOneNode
4544  ? pEnd->nContent.GetIndex()
4545  : pSttTextNd->GetText().getLength())
4546  - pStt->nContent.GetIndex();
4547  pSttTextNd->CopyText( pDestTextNd, aDestIdx,
4548  pStt->nContent, nCpyLen );
4549  if( bEndEqualIns )
4550  pEnd->nContent -= nCpyLen;
4551  }
4552 
4553  if( bOneNode )
4554  {
4555  if (bCopyCollFormat)
4556  {
4557  pSttTextNd->CopyCollFormat( *pDestTextNd );
4559  }
4560 
4561  break;
4562  }
4563 
4564  aRg.aStart++;
4565  }
4566  }
4567  else if( pDestTextNd )
4568  {
4569  // Problems with insertion of table selections into "normal" text solved.
4570  // We have to set the correct PaM for Undo, if this PaM starts in a textnode,
4571  // the undo operation will try to merge this node after removing the table.
4572  // If we didn't split a textnode, the PaM should start at the inserted table node
4573  if( rPos.nContent.GetIndex() == pDestTextNd->Len() )
4574  { // Insertion at the last position of a textnode (empty or not)
4575  ++aInsPos; // The table will be inserted behind the text node
4576  }
4577  else if( rPos.nContent.GetIndex() )
4578  { // Insertion in the middle of a text node, it has to be split
4579  // (and joined from undo)
4580  bStartIsTextNode = true;
4581 
4582  const sal_Int32 nContentEnd = pEnd->nContent.GetIndex();
4583  {
4584  ::sw::UndoGuard const ug(pDoc->GetIDocumentUndoRedo());
4585  pDoc->getIDocumentContentOperations().SplitNode( rPos, false );
4586  }
4587 
4588  if (bCanMoveBack && rPos == *pCopyPam->GetPoint())
4589  {
4590  // after the SplitNode, span the CpyPam correctly again
4591  pCopyPam->Move( fnMoveBackward, GoInContent );
4592  pCopyPam->Move( fnMoveBackward, GoInContent );
4593  }
4594 
4595  // Correct the area again
4596  if( bEndEqualIns )
4597  aRg.aEnd--;
4598  // The end would also be moved
4599  else if( rPos == *pEnd )
4600  {
4601  rPos.nNode-=2;
4602  rPos.nContent.Assign( rPos.nNode.GetNode().GetContentNode(),
4603  nContentEnd );
4604  rPos.nNode++;
4605  aRg.aEnd--;
4606  }
4607  }
4608  else if( bCanMoveBack )
4609  { //Insertion at the first position of a text node. It will not be splitted, the table
4610  // will be inserted before the text node.
4611  // See below, before the SetInsertRange function of the undo object will be called,
4612  // the CpyPam would be moved to the next content position. This has to be avoided
4613  // We want to be moved to the table node itself thus we have to set bCanMoveBack
4614  // and to manipulate pCopyPam.
4615  bCanMoveBack = false;
4616  pCopyPam->GetPoint()->nNode--;
4617  }
4618  }
4619 
4620  pDestTextNd = aInsPos.GetNode().GetTextNode();
4621  if (pEndTextNd)
4622  {
4623  SwIndex aDestIdx( rPos.nContent );
4624  if( !pDestTextNd )
4625  {
4626  pDestTextNd = pDoc->GetNodes().MakeTextNode( aInsPos,
4628  aDestIdx.Assign( pDestTextNd, 0 );
4629  aInsPos--;
4630 
4631  // if we have to insert an extra text node
4632  // at the destination, this node will be our new destination
4633  // (text) node, and thus we set bStartisTextNode to true. This
4634  // will ensure that this node will be deleted during Undo
4635  // using JoinNext.
4636  OSL_ENSURE( !bStartIsTextNode, "Oops, undo may be instable now." );
4637  bStartIsTextNode = true;
4638  }
4639 
4640  const bool bEmptyDestNd = pDestTextNd->GetText().isEmpty();
4641 
4643  if( bCopyCollFormat && ( bOneNode || bEmptyDestNd ))
4644  {
4646  }
4647 
4648  pEndTextNd->CopyText( pDestTextNd, aDestIdx, SwIndex( pEndTextNd ),
4649  pEnd->nContent.GetIndex() );
4650 
4651  // Also copy all format templates
4652  if( bCopyCollFormat && ( bOneNode || bEmptyDestNd ))
4653  {
4654  pEndTextNd->CopyCollFormat( *pDestTextNd );
4655  if ( bOneNode )
4656  {
4658  }
4659  }
4660  }
4661 
4662  if( bCopyAll || aRg.aStart != aRg.aEnd )
4663  {
4664  SfxItemSet aBrkSet( pDoc->GetAttrPool(), aBreakSetRange );
4665  if (pSttTextNd && bCopyCollFormat && pDestTextNd->HasSwAttrSet())
4666  {
4667  aBrkSet.Put( *pDestTextNd->GetpSwAttrSet() );
4668  if( SfxItemState::SET == aBrkSet.GetItemState( RES_BREAK, false ) )
4669  pDestTextNd->ResetAttr( RES_BREAK );
4670  if( SfxItemState::SET == aBrkSet.GetItemState( RES_PAGEDESC, false ) )
4671  pDestTextNd->ResetAttr( RES_PAGEDESC );
4672  }
4673 
4674  SwPosition startPos(SwNodeIndex(pCopyPam->GetPoint()->nNode, +1),
4675  SwIndex(SwNodeIndex(pCopyPam->GetPoint()->nNode, +1).GetNode().GetContentNode()));
4676  if (bCanMoveBack)
4677  { // pCopyPam is actually 1 before the copy range so move it fwd
4678  SwPaM temp(*pCopyPam->GetPoint());
4680  startPos = *temp.GetPoint();
4681  }
4682  assert(startPos.nNode.GetNode().IsContentNode());
4683  std::pair<SwPaM const&, SwPosition const&> tmp(rPam, startPos);
4684  if( aInsPos == pEnd->nNode )
4685  {
4686  SwNodeIndex aSaveIdx( aInsPos, -1 );
4687  CopyWithFlyInFly( aRg, 0, aInsPos, &tmp, bMakeNewFrames, false );
4688  ++aSaveIdx;
4689  pEnd->nNode = aSaveIdx;
4690  pEnd->nContent.Assign( aSaveIdx.GetNode().GetTextNode(), 0 );
4691  }
4692  else
4693  CopyWithFlyInFly( aRg, pEnd->nContent.GetIndex(), aInsPos, &tmp, bMakeNewFrames, false );
4694 
4695  bCopyBookmarks = false;
4696 
4697  // Put the breaks back into the first node
4698  if( aBrkSet.Count() && nullptr != ( pDestTextNd = pDoc->GetNodes()[
4699  pCopyPam->GetPoint()->nNode.GetIndex()+1 ]->GetTextNode()))
4700  {
4701  pDestTextNd->SetAttr( aBrkSet );
4702  bCopyPageSource = true;
4703  }
4704  }
4705  } while( false );
4706 
4707 
4708  // it is not possible to make this test when copy from the clipBoard to document
4709  // in this case the PageNum not exist anymore
4710  // tdf#39400 and tdf#97526
4711  // when copy from document to ClipBoard, and it is from the first page
4712  // and not the source has the page break
4713  if (pDoc->IsClipBoard() && (rPam.GetPageNum(pStt == rPam.GetPoint()) == 1) && !bCopyPageSource)
4714  {
4715  pDestTextNd->ResetAttr(RES_BREAK); // remove the page-break
4716  pDestTextNd->ResetAttr(RES_PAGEDESC);
4717  }
4718 
4719 
4720  // Adjust position (in case it was moved / in another node)
4721  rPos.nContent.Assign( rPos.nNode.GetNode().GetContentNode(),
4722  rPos.nContent.GetIndex() );
4723 
4724  if( rPos.nNode != aInsPos )
4725  {
4726  pCopyPam->GetMark()->nNode = aInsPos;
4727  pCopyPam->GetMark()->nContent.Assign(pCopyPam->GetContentNode(false), 0);
4728  rPos = *pCopyPam->GetMark();
4729  }
4730  else
4731  *pCopyPam->GetMark() = rPos;
4732 
4733  if ( !bAfterTable )
4734  pCopyPam->Move( fnMoveForward, bCanMoveBack ? GoInContent : GoInNode );
4735  else
4736  {
4737  // Reset the offset to 0 as it was before the insertion
4738  pCopyPam->GetPoint()->nContent = 0;
4739 
4740  pCopyPam->GetPoint()->nNode++;
4741  // If the next node is a start node, then step back: the start node
4742  // has been copied and needs to be in the selection for the undo
4743  if (pCopyPam->GetPoint()->nNode.GetNode().IsStartNode())
4744  pCopyPam->GetPoint()->nNode--;
4745 
4746  }
4747  pCopyPam->Exchange();
4748 
4749  // Also copy all bookmarks
4750  if( bCopyBookmarks && m_rDoc.getIDocumentMarkAccess()->getAllMarksCount() )
4751  lcl_CopyBookmarks( rPam, *pCopyPam );
4752 
4753  if( RedlineFlags::DeleteRedlines & eOld )
4754  {
4755  assert(*pCopyPam->GetPoint() == rPos);
4756  // the Node rPos points to may be deleted so unregister ...
4757  rPos.nContent.Assign(nullptr, 0);
4758  lcl_DeleteRedlines(rPam, *pCopyPam);
4759  rPos = *pCopyPam->GetPoint(); // ... and restore.
4760  }
4761 
4762  // If Undo is enabled, store the inserted area
4763  if (pDoc->GetIDocumentUndoRedo().DoesUndo())
4764  {
4765  pUndo->SetInsertRange( *pCopyPam, true, bStartIsTextNode );
4766  }
4767 
4768  if( pCpyRange )
4769  {
4770  pCpyRange->SetMark();
4771  *pCpyRange->GetPoint() = *pCopyPam->GetPoint();
4772  *pCpyRange->GetMark() = *pCopyPam->GetMark();
4773  }
4774 
4775  if ( pNumRuleToPropagate != nullptr )
4776  {
4777  // #i86492# - use <SwDoc::SetNumRule(..)>, because it also handles the <ListId>
4778  // Don't reset indent attributes, that would mean loss of direct
4779  // formatting.
4780  pDoc->SetNumRule( *pCopyPam, *pNumRuleToPropagate, false, nullptr,
4781  aListIdToPropagate, true, /*bResetIndentAttrs=*/false );
4782  }
4783 
4785  pDoc->getIDocumentState().SetModified();
4786 
4787  return true;
4788 }
4789 
4790 
4791 }
4792 /* 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/...
sal_Int32 & GetStart()
start position
Definition: txatbase.hxx:77
Represents the visualization of a paragraph.
Definition: txtfrm.hxx:149
std::shared_ptr< SwUnoCursor > CreateUnoCursor(const SwPosition &rPos, bool bTableCursor=false)
Definition: doc.cxx:1785
virtual sal_Int32 Len() const
Definition: node.cxx:1183
void DeleteMark()
Definition: pam.hxx:177
sal_uLong GetIndex() const
Definition: node.hxx:282
#define RES_GRFATR_END
Definition: hintids.hxx:258
SwNode & GetNode(bool bPoint=true) const
Definition: pam.hxx:223
SwAutoCorrExceptWord * GetAutoCorrExceptWord()
Definition: doc.hxx:1380
SwNode & GetEndOfAutotext() const
Section for all Flys/Header/Footers.
Definition: ndarr.hxx:157
bool GoInContent(SwPaM &rPam, SwMoveFnCollection const &fnMove)
Definition: pam.cxx:903
std::map< OUString, css::uno::Any > parameter_map_t
Definition: IMark.hxx:108
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:1452
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:756
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:4892
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
sal_Int32 GetSpaceLeft() const
Definition: ndtxt.hxx:859
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:322
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:1150
Pos1 completely contained in Pos2.
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
virtual SwFrameFormat * CopyLayoutFormat(const SwFrameFormat &rSrc, const SwFormatAnchor &rNewAnchor, bool bSetTextFlyAtt, bool bMakeFrames)=0
#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:958
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:1348
Dialog to specify the properties of drop-down form field.
Definition: accfrmobj.cxx:40
IDocumentUndoRedo & GetIDocumentUndoRedo()
Definition: doc.cxx:176
void CopyFlyInFlyImpl(const SwNodeRange &rRg, const sal_Int32 nEndContentIndex, const SwNodeIndex &rStartIdx, const bool bCopyFlyAtFly=false) const
#define RES_TXTATR_CHARFMT
Definition: hintids.hxx:142
sal_uInt16 Which() const
Definition: txatbase.hxx:105
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:1729
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
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:1775
#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:651
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:4097
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:738
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:3060
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
#define XATTR_FILL_FIRST
void DestroyAttr(SwTextAttr *pAttr)
Definition: thints.cxx:1111
IDocumentStylePoolAccess const & getIDocumentStylePoolAccess() const
Definition: doc.cxx:458
static bool IsRedlineOn(const RedlineFlags eM)
static void restoreLinks(std::set< ZSortFly > &rOld, std::vector< SwFrameFormat * > &rNew, SavedLink &rSavedLinks, SavedContent &rResetContent)
Undo the effect of saveLinks() + individual resetLink() calls.
SwBreakIt * g_pBreakIt
Definition: breakit.cxx:34
static bool IsFuzzing()
sal_uLong GetIndex() const
Definition: ndindex.hxx:151
bool SplitNode(const SwPosition &rPos, bool bChkTableStart) override
Split a node at rPos (implemented only for TextNode).
virtual void DelLayoutFormat(SwFrameFormat *pFormat)=0
bool DeleteAndJoin(SwPaM &, const bool bForceJoinNext=false) override
complete delete of a given PaM
static SwGrfNode * MakeGrfNode(const SwNodeIndex &rWhere, const OUString &rGrfName, const OUString &rFltName, const Graphic *pGraphic, SwGrfFormatColl *pColl, SwAttrSet const *pAutoAttr=nullptr)
in ndgrf.cxx
Definition: ndgrf.cxx:401
const sal_uInt8 MAXLEVEL
Definition: swtypes.hxx:95
static SW_DLLPUBLIC sal_uInt16 GetPoolIdFromUIName(const OUString &rName, SwGetPoolIdFromName)
bool IsStartNode() const
Definition: node.hxx:624
Pos2 completely contained in Pos1.
SwTextAttr * InsertItem(SfxPoolItem &rAttr, const sal_Int32 nStart, const sal_Int32 nEnd, const SetAttrMode nMode=SetAttrMode::DEFAULT)
create new text attribute from rAttr and insert it
Definition: thints.cxx:1219
#define RES_TXTATR_WITHEND_END
Definition: hintids.hxx:146
const SwTable & GetTable() const
Definition: node.hxx:497
virtual void DeleteSection(SwNode *pNode)=0
Delete section containing the node.
virtual parameter_map_t * GetParameters()=0
void DelNodes(const SwNodeIndex &rStart, sal_uLong nCnt=1)
Delete a number of nodes.
Definition: nodes.cxx:1343
virtual bool IsRedlineMove() const =0
bool empty() const
Definition: docary.hxx:224
#define RES_PARATR_NUMRULE
Definition: hintids.hxx:170
Describes parts of multiple text nodes, which will form a text frame, even when redlines are hidden a...
Definition: txtfrm.hxx:952
#define RES_PARATR_BEGIN
Definition: hintids.hxx:160
Pos1 before Pos2.
RedlineFlags on.
static sal_uInt16 IsMath(const SvGlobalName &rName)
SwContentNode * AppendNode(const SwPosition &)
Definition: ndtxt.cxx:3034
size_type size() const
virtual bool DoesUndo() const =0
Is Undo enabled?
virtual void MoveObjToVisibleLayer(SdrObject *_pDrawObj)
method to move drawing object to corresponding visible layer
Definition: dcontact.cxx:213
void CopyText(SwTextNode *const pDest, const SwIndex &rStart, const sal_Int32 nLen, const bool bForceCopyOfAllAttrs)
Actions on text and attributes.
Definition: ndtxt.cxx:1996
virtual void SetKeyCode(const vcl::KeyCode &)=0
bool sw_JoinText(SwPaM &rPam, bool bJoinPrev)
Definition: docedt.cxx:339
void Normalize(bool bPointFirst=true)
Normalizes PaM, i.e.
Definition: pam.cxx:520