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