LibreOffice Module sw (master)  1
docnum.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  */
19 
20 #include <hintids.hxx>
21 #include <ftninfo.hxx>
22 #include <ftnidx.hxx>
23 #include <doc.hxx>
24 #include <IDocumentUndoRedo.hxx>
25 #include <IDocumentListsAccess.hxx>
28 #include <IDocumentState.hxx>
30 #include <pam.hxx>
31 #include <ndtxt.hxx>
32 #include <poolfmt.hxx>
33 #include <UndoCore.hxx>
34 #include <UndoRedline.hxx>
35 #include <UndoNumbering.hxx>
36 #include <swundo.hxx>
37 #include <SwUndoFmt.hxx>
38 #include <rolbck.hxx>
39 #include <paratr.hxx>
40 #include <docary.hxx>
41 #include <mvsave.hxx>
42 #include <txtfrm.hxx>
43 #include <rootfrm.hxx>
44 #include <redline.hxx>
45 #include <strings.hrc>
46 #include <SwNodeNum.hxx>
47 #include <list.hxx>
48 #include <calbck.hxx>
49 #include <comphelper/string.hxx>
50 #include <comphelper/random.hxx>
51 #include <o3tl/safeint.hxx>
52 #include <o3tl/string_view.hxx>
53 #include <osl/diagnose.h>
54 #include <tools/datetimeutils.hxx>
55 
56 #include <map>
57 #include <stdlib.h>
58 
59 #include <wrtsh.hxx>
60 
61 namespace {
62  void lcl_ResetIndentAttrs(SwDoc *pDoc, const SwPaM &rPam, sal_uInt16 marker,
63  SwRootFrame const*const pLayout)
64  {
65  const o3tl::sorted_vector<sal_uInt16> aResetAttrsArray{ marker };
66  // #i114929#
67  // On a selection setup a corresponding Point-and-Mark in order to get
68  // the indentation attribute reset on all paragraphs touched by the selection
69  if ( rPam.HasMark() &&
70  rPam.End()->nNode.GetNode().GetTextNode() )
71  {
72  SwPaM aPam( rPam.Start()->nNode,
73  rPam.End()->nNode );
74  aPam.Start()->nContent = 0;
75  aPam.End()->nContent = rPam.End()->nNode.GetNode().GetTextNode()->Len();
76  pDoc->ResetAttrs( aPam, false, aResetAttrsArray, true, pLayout );
77  }
78  else
79  {
80  pDoc->ResetAttrs( rPam, false, aResetAttrsArray, true, pLayout );
81  }
82  }
83 
84  void ExpandPamForParaPropsNodes(SwPaM& rPam, SwRootFrame const*const pLayout)
85  {
86  if (!pLayout)
87  return;
88 
89  // ensure that selection from the Shell includes the para-props node
90  // to which the attributes should be applied
91  if (rPam.GetPoint()->nNode.GetNode().IsTextNode())
92  {
93  rPam.GetPoint()->nNode = *sw::GetParaPropsNode(*pLayout, rPam.GetPoint()->nNode);
95  }
96  if (rPam.GetMark()->nNode.GetNode().IsTextNode())
97  {
98  rPam.GetMark()->nNode = *sw::GetParaPropsNode(*pLayout, rPam.GetMark()->nNode);
99  rPam.GetMark()->nContent.Assign(rPam.GetMark()->nNode.GetNode().GetContentNode(), 0);
100  }
101  }
102 }
103 
104 static sal_uInt8 GetUpperLvlChg( sal_uInt8 nCurLvl, sal_uInt8 nLevel, sal_uInt16 nMask )
105 {
106  if( 1 < nLevel )
107  {
108  if( nCurLvl + 1 >= nLevel )
109  nCurLvl -= nLevel - 1;
110  else
111  nCurLvl = 0;
112  }
113  return static_cast<sal_uInt8>((nMask - 1) & ~(( 1 << nCurLvl ) - 1));
114 }
115 
117 {
118  if (GetIDocumentUndoRedo().DoesUndo())
119  {
121  if (mpOutlineRule)
122  {
124  std::make_unique<SwUndoOutlineEdit>(*mpOutlineRule, rRule, *this));
125  }
126  }
127 
128  if( mpOutlineRule )
129  (*mpOutlineRule) = rRule;
130  else
131  {
132  mpOutlineRule = new SwNumRule( rRule );
133 
134  AddNumRule(mpOutlineRule); // #i36749#
135  }
136 
139 
140  // assure that the outline numbering rule is an automatic rule
141  mpOutlineRule->SetAutoRule( true );
142 
143  // test whether the optional CharFormats are defined in this Document
145 
146  // notify text nodes, which are registered at the outline style, about the
147  // changed outline style
148  SwNumRule::tTextNodeList aTextNodeList;
149  mpOutlineRule->GetTextNodeList( aTextNodeList );
150  for ( SwTextNode* pTextNd : aTextNodeList )
151  {
152  pTextNd->NumRuleChgd();
153 
154  // assure that list level corresponds to outline level
155  if ( pTextNd->GetTextColl()->IsAssignedToListLevelOfOutlineStyle() &&
156  pTextNd->GetAttrListLevel() != pTextNd->GetTextColl()->GetAssignedOutlineStyleLevel() )
157  {
158  pTextNd->SetAttrListLevel( pTextNd->GetTextColl()->GetAssignedOutlineStyleLevel() );
159  }
160  }
161 
164  UpdateNumRule();
165 
166  // update if we have foot notes && numbering by chapter
167  if( !GetFootnoteIdxs().empty() && FTNNUM_CHAPTER == GetFootnoteInfo().m_eNum )
169 
170  getIDocumentFieldsAccess().UpdateExpFields(nullptr, true);
171 
172  if (GetIDocumentUndoRedo().DoesUndo())
173  {
175  }
176 
178 }
179 
181 {
182  SwNumRule* pMyOutlineRule = GetOutlineNumRule();
183  if (!pMyOutlineRule)
184  return;
185 
186  for (auto pColl : *mpTextFormatCollTable)
187  {
188  if(pColl->IsAssignedToListLevelOfOutlineStyle())
189  {
190  // Check only the list style, which is set at the paragraph style
191  const SwNumRuleItem & rCollRuleItem = pColl->GetNumRule( false );
192 
193  if ( rCollRuleItem.GetValue().isEmpty() )
194  {
195  SwNumRuleItem aNumItem( pMyOutlineRule->GetName() );
196  pColl->SetFormatAttr(aNumItem);
197  }
198  }
199  }
200 }
201 
202 // Increase/Decrease
203 bool SwDoc::OutlineUpDown(const SwPaM& rPam, short nOffset,
204  SwRootFrame const*const pLayout)
205 {
206  if( GetNodes().GetOutLineNds().empty() || !nOffset )
207  return false;
208 
209  // calculate the range
210  SwPaM aPam(rPam, nullptr);
211  ExpandPamForParaPropsNodes(aPam, pLayout);
212  const SwOutlineNodes& rOutlNds = GetNodes().GetOutLineNds();
213  SwNode* const pSttNd = &aPam.Start()->nNode.GetNode();
214  SwNode* const pEndNd = &aPam.End()->nNode.GetNode();
215  SwOutlineNodes::size_type nSttPos, nEndPos;
216 
217  if( !rOutlNds.Seek_Entry( pSttNd, &nSttPos ) &&
218  !nSttPos-- )
219  // we're not in an "Outline section"
220  return false;
221 
222  if( rOutlNds.Seek_Entry( pEndNd, &nEndPos ) )
223  ++nEndPos;
224 
225  // We now have the wanted range in the OutlineNodes array,
226  // so check now if we're not invalidating sublevels
227  // (stepping over the limits)
228 
229  // Here we go:
230  // 1. Create the style array:
231  SwTextFormatColl* aCollArr[ MAXLEVEL ];
232  memset( aCollArr, 0, sizeof( SwTextFormatColl* ) * MAXLEVEL );
233 
234  for( auto pTextFormatColl : *mpTextFormatCollTable )
235  {
236  if (pTextFormatColl->IsAssignedToListLevelOfOutlineStyle())
237  {
238  const int nLevel = pTextFormatColl->GetAssignedOutlineStyleLevel();
239  aCollArr[ nLevel ] = pTextFormatColl;
240  }
241  }
242 
243  int n;
244 
245  /* Find the last occupied level (backward). */
246  for (n = MAXLEVEL - 1; n > 0; n--)
247  {
248  if (aCollArr[n] != nullptr)
249  break;
250  }
251 
252  /* If an occupied level is found, choose next level (which IS
253  unoccupied) until a valid level is found. If no occupied level
254  was found n is 0 and aCollArr[0] is 0. In this case no demoting
255  is possible. */
256  if (aCollArr[n] != nullptr)
257  {
258  while (n < MAXLEVEL - 1)
259  {
260  n++;
261 
262  SwTextFormatColl *aTmpColl =
263  getIDocumentStylePoolAccess().GetTextCollFromPool(o3tl::narrowing<sal_uInt16>(RES_POOLCOLL_HEADLINE1 + n));
264 
265  if( aTmpColl->IsAssignedToListLevelOfOutlineStyle() &&
266  aTmpColl->GetAssignedOutlineStyleLevel() == n )
267  {
268  aCollArr[n] = aTmpColl;
269  break;
270  }
271  }
272  }
273 
274  /* Find the first occupied level (forward). */
275  for (n = 0; n < MAXLEVEL - 1; n++)
276  {
277  if (aCollArr[n] != nullptr)
278  break;
279  }
280 
281  /* If an occupied level is found, choose previous level (which IS
282  unoccupied) until a valid level is found. If no occupied level
283  was found n is MAXLEVEL - 1 and aCollArr[MAXLEVEL - 1] is 0. In
284  this case no demoting is possible. */
285  if (aCollArr[n] != nullptr)
286  {
287  while (n > 0)
288  {
289  n--;
290 
291  SwTextFormatColl *aTmpColl =
292  getIDocumentStylePoolAccess().GetTextCollFromPool(o3tl::narrowing<sal_uInt16>(RES_POOLCOLL_HEADLINE1 + n));
293 
294  if( aTmpColl->IsAssignedToListLevelOfOutlineStyle() &&
295  aTmpColl->GetAssignedOutlineStyleLevel() == n )
296  {
297  aCollArr[n] = aTmpColl;
298  break;
299  }
300  }
301  }
302 
303  /* --> #i13747#
304 
305  Build a move table that states from which level to which other level
306  an outline will be moved.
307 
308  the move table:
309  aMoveArr[n] = m: replace aCollArr[n] with aCollArr[m]
310  */
311  int aMoveArr[MAXLEVEL];
312  int nStep; // step size for searching in aCollArr: -1 or 1
313  int nNum; // amount of steps for stepping in aCollArr
314 
315  if (nOffset < 0)
316  {
317  nStep = -1;
318  nNum = -nOffset;
319  }
320  else
321  {
322  nStep = 1;
323  nNum = nOffset;
324  }
325 
326  /* traverse aCollArr */
327  for (n = 0; n < MAXLEVEL; n++)
328  {
329  /* If outline level n has an assigned paragraph style step
330  nNum steps forwards (nStep == 1) or backwards (nStep ==
331  -1). One step is to go to the next non-null entry in
332  aCollArr in the selected direction. If nNum steps were
333  possible write the index of the entry found to aCollArr[n],
334  i.e. outline level n will be replaced by outline level
335  aCollArr[n].
336 
337  If outline level n has no assigned paragraph style
338  aMoveArr[n] is set to -1.
339  */
340  if (aCollArr[n] != nullptr)
341  {
342  int m = n;
343  int nCount = nNum;
344 
345  while (nCount > 0 && m + nStep >= 0 && m + nStep < MAXLEVEL)
346  {
347  m += nStep;
348 
349  if (aCollArr[m] != nullptr)
350  nCount--;
351  }
352 
353  if (nCount == 0)
354  aMoveArr[n] = m;
355  else
356  aMoveArr[n] = -1;
357  }
358  else
359  aMoveArr[n] = -1;
360  }
361 
362  /* If moving of the outline levels is applicable, i.e. for all
363  outline levels occurring in the document there has to be a valid
364  target outline level implied by aMoveArr. */
365  bool bMoveApplicable = true;
366  for (auto i = nSttPos; i < nEndPos; ++i)
367  {
368  SwTextNode* pTextNd = rOutlNds[ i ]->GetTextNode();
369  if (pLayout && !sw::IsParaPropsNode(*pLayout, *pTextNd))
370  {
371  continue;
372  }
373  SwTextFormatColl* pColl = pTextNd->GetTextColl();
374 
376  {
377  const int nLevel = pColl->GetAssignedOutlineStyleLevel();
378  if (aMoveArr[nLevel] == -1)
379  bMoveApplicable = false;
380  }
381 
382  // Check on outline level attribute of text node, if text node is
383  // not an outline via a to outline style assigned paragraph style.
384  else
385  {
386  const int nNewOutlineLevel = pTextNd->GetAttrOutlineLevel() + nOffset;
387  if ( nNewOutlineLevel < 1 || nNewOutlineLevel > MAXLEVEL )
388  {
389  bMoveApplicable = false;
390  }
391  }
392  }
393 
394  if (! bMoveApplicable )
395  return false;
396 
397  if (GetIDocumentUndoRedo().DoesUndo())
398  {
401  std::make_unique<SwUndoOutlineLeftRight>(aPam, nOffset) );
402  }
403 
404  // 2. Apply the new style to all Nodes
405  for (auto i = nSttPos; i < nEndPos; ++i)
406  {
407  SwTextNode* pTextNd = rOutlNds[ i ]->GetTextNode();
408  if (pLayout && !sw::IsParaPropsNode(*pLayout, *pTextNd))
409  {
410  continue;
411  }
412  SwTextFormatColl* pColl = pTextNd->GetTextColl();
413 
415  {
416  const int nLevel = pColl->GetAssignedOutlineStyleLevel();
417 
418  OSL_ENSURE(aMoveArr[nLevel] >= 0,
419  "move table: current TextColl not found when building table!");
420 
421  if (nLevel < MAXLEVEL && aMoveArr[nLevel] >= 0)
422  {
423  pColl = aCollArr[ aMoveArr[nLevel] ];
424 
425  if (pColl != nullptr)
426  pTextNd->ChgFormatColl( pColl );
427  }
428 
429  }
430  else if( pTextNd->GetAttrOutlineLevel() > 0)
431  {
432  int nLevel = pTextNd->GetAttrOutlineLevel() + nOffset;
433  if( 0 <= nLevel && nLevel <= MAXLEVEL)
434  pTextNd->SetAttrOutlineLevel( nLevel );
435 
436  }
437  // Undo ???
438  }
439  if (GetIDocumentUndoRedo().DoesUndo())
440  {
442  }
443 
444  ChkCondColls();
446 
447  return true;
448 }
449 
450 // Move up/down
452 {
453  // Do not move to special sections in the nodes array
454  const SwPosition& rStt = *rPam.Start(),
455  & rEnd = *rPam.End();
456  if( GetNodes().GetOutLineNds().empty() || !nOffset ||
457  (rStt.nNode.GetIndex() < GetNodes().GetEndOfExtras().GetIndex()) ||
458  (rEnd.nNode.GetIndex() < GetNodes().GetEndOfExtras().GetIndex()))
459  {
460  return false;
461  }
462 
463  SwOutlineNodes::size_type nCurrentPos = 0;
464  SwNodeIndex aSttRg( rStt.nNode ), aEndRg( rEnd.nNode );
465 
466  int nOutLineLevel = MAXLEVEL;
467  SwNode* pSrch = &aSttRg.GetNode();
468 
469  if( pSrch->IsTextNode())
470  nOutLineLevel = static_cast<sal_uInt8>(pSrch->GetTextNode()->GetAttrOutlineLevel()-1);
471  SwNode* pEndSrch = &aEndRg.GetNode();
472  if( !GetNodes().GetOutLineNds().Seek_Entry( pSrch, &nCurrentPos ) )
473  {
474  if( !nCurrentPos )
475  return false; // Promoting or demoting before the first outline => no.
476  if( --nCurrentPos )
477  aSttRg = *GetNodes().GetOutLineNds()[ nCurrentPos ];
478  else if( 0 > nOffset )
479  return false; // Promoting at the top of document?!
480  else
482  }
483  SwOutlineNodes::size_type nTmpPos = 0;
484  // If the given range ends at an outlined text node we have to decide if it has to be a part of
485  // the moving range or not. Normally it will be a sub outline of our chapter
486  // and has to be moved, too. But if the chapter ends with a table(or a section end),
487  // the next text node will be chosen and this could be the next outline of the same level.
488  // The criteria has to be the outline level: sub level => incorporate, same/higher level => no.
489  if( GetNodes().GetOutLineNds().Seek_Entry( pEndSrch, &nTmpPos ) )
490  {
491  if( !pEndSrch->IsTextNode() || pEndSrch == pSrch ||
492  nOutLineLevel < pEndSrch->GetTextNode()->GetAttrOutlineLevel()-1 )
493  ++nTmpPos; // For sub outlines only!
494  }
495 
496  aEndRg = nTmpPos < GetNodes().GetOutLineNds().size()
497  ? *GetNodes().GetOutLineNds()[ nTmpPos ]
499  if( nOffset >= 0 )
500  nCurrentPos = nTmpPos;
501  if( aEndRg == aSttRg )
502  {
503  OSL_FAIL( "Moving outlines: Surprising selection" );
504  ++aEndRg;
505  }
506 
507  const SwNode* pNd;
508  // The following code corrects the range to handle sections (start/end nodes)
509  // The range will be extended if the least node before the range is a start node
510  // which ends inside the range => The complete section will be moved.
511  // The range will be shrunk if the last position is a start node.
512  // The range will be shrunk if the last node is an end node which starts before the range.
513  --aSttRg;
514  while( aSttRg.GetNode().IsStartNode() )
515  {
516  pNd = aSttRg.GetNode().EndOfSectionNode();
517  if( pNd->GetIndex() >= aEndRg.GetIndex() )
518  break;
519  --aSttRg;
520  }
521  ++aSttRg;
522 
523  --aEndRg;
524  while( aEndRg.GetNode().IsStartNode() )
525  --aEndRg;
526 
527  while( aEndRg.GetNode().IsEndNode() )
528  {
529  pNd = aEndRg.GetNode().StartOfSectionNode();
530  if( pNd->GetIndex() >= aSttRg.GetIndex() )
531  break;
532  --aEndRg;
533  }
534  ++aEndRg;
535 
536  // calculation of the new position
537  if( nOffset < 0 && nCurrentPos < o3tl::make_unsigned(-nOffset) )
539  else if( nCurrentPos + nOffset >= GetNodes().GetOutLineNds().size() )
540  pNd = &GetNodes().GetEndOfContent();
541  else
542  pNd = GetNodes().GetOutLineNds()[ nCurrentPos + nOffset ];
543 
544  SwNodeOffset nNewPos = pNd->GetIndex();
545 
546  // And now a correction of the insert position if necessary...
547  SwNodeIndex aInsertPos( *pNd, -1 );
548  while( aInsertPos.GetNode().IsStartNode() )
549  {
550  // Just before the insert position starts a section:
551  // when I'm moving forward I do not want to enter the section,
552  // when I'm moving backward I want to stay in the section if I'm already a part of,
553  // I want to stay outside if I was outside before.
554  if( nOffset < 0 )
555  {
556  pNd = aInsertPos.GetNode().EndOfSectionNode();
557  if( pNd->GetIndex() >= aEndRg.GetIndex() )
558  break;
559  }
560  --aInsertPos;
561  --nNewPos;
562  }
563 
564  if( nOffset >= 0 )
565  {
566  // When just before the insert position a section ends, it is okay when I'm moving backward
567  // because I want to stay outside the section.
568  // When moving forward I've to check if I started inside or outside the section
569  // because I don't want to enter of leave such a section
570  while( aInsertPos.GetNode().IsEndNode() )
571  {
572  pNd = aInsertPos.GetNode().StartOfSectionNode();
573  if( pNd->GetIndex() >= aSttRg.GetIndex() )
574  break;
575  --aInsertPos;
576  --nNewPos;
577  }
578  }
579  // We do not want to move into tables (at the moment)
580  ++aInsertPos;
581  pNd = &aInsertPos.GetNode();
582  if( pNd->IsTableNode() )
583  pNd = pNd->StartOfSectionNode();
584  if( pNd->FindTableNode() )
585  return false;
586 
587  OSL_ENSURE( aSttRg.GetIndex() > nNewPos || nNewPos >= aEndRg.GetIndex(),
588  "Position lies within Move range" );
589 
590  // If a Position inside the special nodes array sections was calculated,
591  // set it to document start instead.
592  // Sections or Tables at the document start will be pushed backwards.
593  nNewPos = std::max( nNewPos, GetNodes().GetEndOfExtras().GetIndex() + SwNodeOffset(2) );
594 
595  SwNodeOffset nOffs = nNewPos - ( 0 < nOffset ? aEndRg.GetIndex() : aSttRg.GetIndex());
596  SwPaM aPam( aSttRg, aEndRg, SwNodeOffset(0), SwNodeOffset(-1) );
597  return MoveParagraph( aPam, nOffs, true );
598 }
599 
601  SwRootFrame const*const pLayout, const OUString& rName, bool const bExact)
602 {
603  SwTextNode * pExactButDeleted(nullptr);
604  SwTextNode* pSavedNode = nullptr;
605  for( auto pOutlNd : rOutlNds )
606  {
607  SwTextNode* pTextNd = pOutlNd->GetTextNode();
608  const OUString sText( pTextNd->GetExpandText(pLayout) );
609  if (sText.startsWith(rName))
610  {
611  if (sText.getLength() == rName.getLength())
612  {
613  if (pLayout && !sw::IsParaPropsNode(*pLayout, *pTextNd))
614  {
615  pExactButDeleted = pTextNd;
616  }
617  else
618  {
619  // Found "exact", set Pos to the Node
620  return pTextNd;
621  }
622  }
623  if (!bExact && !pSavedNode
624  && (!pLayout || sw::IsParaPropsNode(*pLayout, *pTextNd)))
625  {
626  // maybe we just found the text's first part
627  pSavedNode = pTextNd;
628  }
629  }
630  }
631 
632  return bExact ? pExactButDeleted : pSavedNode;
633 }
634 
636  OUString& rName, SwRootFrame const*const pLayout)
637 {
638  // Valid numbers are (always just offsets!):
639  // ([Number]+\.)+ (as a regular expression!)
640  // (Number followed by a period, with 5 repetitions)
641  // i.e.: "1.1.", "1.", "1.1.1."
642  sal_Int32 nPos = 0;
643  std::u16string_view sNum = o3tl::getToken(rName, 0, '.', nPos );
644  if( -1 == nPos )
645  return nullptr; // invalid number!
646 
647  sal_uInt16 nLevelVal[ MAXLEVEL ]; // numbers of all levels
648  memset( nLevelVal, 0, MAXLEVEL * sizeof( nLevelVal[0] ));
649  int nLevel = 0;
650  std::u16string_view sName( rName );
651 
652  while( -1 != nPos )
653  {
654  sal_uInt16 nVal = 0;
655  for( size_t n = 0; n < sNum.size(); ++n )
656  {
657  const sal_Unicode c {sNum[ n ]};
658  if( '0' <= c && c <= '9' )
659  {
660  nVal *= 10;
661  nVal += c - '0';
662  }
663  else if( nLevel )
664  break; // "almost" valid number
665  else
666  return nullptr; // invalid number!
667  }
668 
669  if( MAXLEVEL > nLevel )
670  nLevelVal[ nLevel++ ] = nVal;
671 
672  sName = sName.substr( nPos );
673  nPos = 0;
674  sNum = o3tl::getToken(sName, 0, '.', nPos );
675  // #i4533# without this check all parts delimited by a dot are treated as outline numbers
677  break;
678  }
679  rName = sName; // that's the follow-up text
680 
681  // read all levels, so search the document for this outline
682 
683  // Without OutlineNodes searching doesn't pay off
684  // and we save a crash
685  if( rOutlNds.empty() )
686  return nullptr;
687 
688  // search in the existing outline nodes for the required outline num array
689  for( auto pOutlNd : rOutlNds )
690  {
691  SwTextNode* pNd = pOutlNd->GetTextNode();
692  if ( pNd->GetAttrOutlineLevel() == nLevel )
693  {
694  // #i51089#, #i68289#
695  // Assure, that text node has the correct numbering level. Otherwise,
696  // its number vector will not fit to the searched level.
697  if (pNd->GetNum(pLayout) && pNd->GetActualListLevel() == nLevel - 1)
698  {
699  const SwNodeNum & rNdNum = *(pNd->GetNum(pLayout));
700  SwNumberTree::tNumberVector aLevelVal = rNdNum.GetNumberVector();
701  // now compare with the one searched for
702  bool bEqual = true;
703  nLevel = std::min<int>(nLevel, MAXLEVEL);
704  for( int n = 0; n < nLevel; ++n )
705  {
706  if ( aLevelVal[n] != nLevelVal[n] )
707  {
708  bEqual = false;
709  break;
710  }
711  }
712  if (bEqual)
713  return pNd;
714  }
715  else
716  {
717  // A text node, which has an outline paragraph style applied and
718  // has as hard attribute 'no numbering' set, has an outline level,
719  // but no numbering tree node. Thus, consider this situation in
720  // the assertion condition.
721  OSL_ENSURE( !pNd->GetNumRule(),
722  "<lcl_FindOutlineNum(..)> - text node with outline level and numbering rule, but without numbering tree node. This is a serious defect" );
723  }
724  }
725  }
726 
727  return nullptr;
728 }
729 
730 // rName can contain a Number and/or the Text.
731 // First, we try to find the correct Entry via the Number.
732 // If it exists, we compare the Text to see if it's the right one.
733 // If that's not the case, we search again via the Text. If it is
734 // found, we got the right entry. Or else we use the one found by
735 // searching for the Number.
736 // If we don't have a Number, we search via the Text only.
737 bool SwDoc::GotoOutline(SwPosition& rPos, const OUString& rName, SwRootFrame const*const pLayout) const
738 {
739  if( !rName.isEmpty() )
740  {
741  const SwOutlineNodes& rOutlNds = GetNodes().GetOutLineNds();
742 
743  // 1. step: via the Number:
744  OUString sName( rName );
745  SwTextNode* pNd = ::lcl_FindOutlineNum(rOutlNds, sName, pLayout);
746  if ( pNd )
747  {
748  OUString sExpandedText = pNd->GetExpandText(pLayout);
749  //#i4533# leading numbers followed by a dot have been remove while
750  //searching for the outline position
751  //to compensate this they must be removed from the paragraphs text content, too
752  while(!sExpandedText.isEmpty())
753  {
754  sal_Int32 nPos = 0;
755  std::u16string_view sTempNum = o3tl::getToken(sExpandedText, 0, '.', nPos);
756  if( sTempNum.empty() || -1 == nPos ||
758  break;
759  sExpandedText = sExpandedText.copy(nPos);
760  }
761 
762  if( sExpandedText != sName )
763  {
764  SwTextNode *pTmpNd = ::lcl_FindOutlineName(rOutlNds, pLayout, sName, true);
765  if ( pTmpNd ) // found via the Name
766  {
767  if (pLayout && !sw::IsParaPropsNode(*pLayout, *pTmpNd))
768  { // found the correct node but it's deleted!
769  return false; // avoid fallback to inexact search
770  }
771  pNd = pTmpNd;
772  }
773  }
774  rPos.nNode = *pNd;
775  rPos.nContent.Assign( pNd, 0 );
776  return true;
777  }
778 
779  pNd = ::lcl_FindOutlineName(rOutlNds, pLayout, rName, false);
780  if ( pNd )
781  {
782  rPos.nNode = *pNd;
783  rPos.nContent.Assign( pNd, 0 );
784  return true;
785  }
786 
787  // #i68289# additional search on hyperlink URL without its outline numbering part
788  if ( sName != rName )
789  {
790  pNd = ::lcl_FindOutlineName(rOutlNds, pLayout, sName, false);
791  if ( pNd )
792  {
793  rPos.nNode = *pNd;
794  rPos.nContent.Assign( pNd, 0 );
795  return true;
796  }
797  }
798  }
799  return false;
800 }
801 
802 static void lcl_ChgNumRule( SwDoc& rDoc, const SwNumRule& rRule )
803 {
804  SwNumRule* pOld = rDoc.FindNumRulePtr( rRule.GetName() );
805  if (!pOld) //we cannot proceed without the old NumRule
806  return;
807 
808  sal_uInt16 nChgFormatLevel = 0;
809  sal_uInt16 nMask = 1;
810 
811  for ( sal_uInt8 n = 0; n < MAXLEVEL; ++n, nMask <<= 1 )
812  {
813  const SwNumFormat& rOldFormat = pOld->Get( n ), &rNewFormat = rRule.Get( n );
814 
815  if ( rOldFormat != rNewFormat )
816  {
817  nChgFormatLevel |= nMask;
818  }
819  else if ( SVX_NUM_NUMBER_NONE > rNewFormat.GetNumberingType()
820  && 1 < rNewFormat.GetIncludeUpperLevels()
821  && 0 != ( nChgFormatLevel & GetUpperLvlChg( n, rNewFormat.GetIncludeUpperLevels(), nMask ) ) )
822  {
823  nChgFormatLevel |= nMask;
824  }
825  }
826 
827  if( !nChgFormatLevel ) // Nothing has been changed?
828  {
829  const bool bInvalidateNumRule( pOld->IsContinusNum() != rRule.IsContinusNum() );
830  pOld->CheckCharFormats( rDoc );
831  pOld->SetContinusNum( rRule.IsContinusNum() );
832 
833  if ( bInvalidateNumRule )
834  {
835  pOld->SetInvalidRule(true);
836  }
837 
838  return ;
839  }
840 
841  SwNumRule::tTextNodeList aTextNodeList;
842  pOld->GetTextNodeList( aTextNodeList );
843  sal_uInt8 nLvl( 0 );
844  for ( SwTextNode* pTextNd : aTextNodeList )
845  {
846  nLvl = static_cast<sal_uInt8>(pTextNd->GetActualListLevel());
847 
848  if( nLvl < MAXLEVEL )
849  {
850  if( nChgFormatLevel & ( 1 << nLvl ))
851  {
852  pTextNd->NumRuleChgd();
853  }
854  }
855  }
856 
857  for ( sal_uInt8 n = 0; n < MAXLEVEL; ++n )
858  if ( nChgFormatLevel & ( 1 << n ) )
859  pOld->Set( n, rRule.GetNumFormat( n ) );
860 
861  pOld->CheckCharFormats( rDoc );
862  pOld->SetInvalidRule( true );
863  pOld->SetContinusNum( rRule.IsContinusNum() );
864 
865  rDoc.UpdateNumRule();
866 }
867 
868 OUString SwDoc::SetNumRule( const SwPaM& rPam,
869  const SwNumRule& rRule,
870  const bool bCreateNewList,
871  SwRootFrame const*const pLayout,
872  const OUString& sContinuedListId,
873  bool bSetItem,
874  const bool bResetIndentAttrs )
875 {
876  OUString sListId;
877 
878  SwPaM aPam(rPam, nullptr);
879  ExpandPamForParaPropsNodes(aPam, pLayout);
880 
881  SwUndoInsNum * pUndo = nullptr;
882  if (GetIDocumentUndoRedo().DoesUndo())
883  {
884  // Start/End for attributes!
886  pUndo = new SwUndoInsNum( aPam, rRule );
887  GetIDocumentUndoRedo().AppendUndo(std::unique_ptr<SwUndo>(pUndo));
888  }
889 
890  SwNumRule* pNewOrChangedNumRule = FindNumRulePtr( rRule.GetName() );
891  bool bNewNumRuleCreated = false;
892  if ( pNewOrChangedNumRule == nullptr )
893  {
894  // create new numbering rule based on given one
895  pNewOrChangedNumRule = ( *mpNumRuleTable )[MakeNumRule( rRule.GetName(), &rRule )];
896  bNewNumRuleCreated = true;
897  }
898  else if ( rRule != *pNewOrChangedNumRule )
899  {
900  // change existing numbering rule
901  if (pUndo)
902  {
903  pUndo->SaveOldNumRule( *pNewOrChangedNumRule );
904  }
905  ::lcl_ChgNumRule( *this, rRule );
906  if (pUndo)
907  {
908  pUndo->SetLRSpaceEndPos();
909  }
910  }
911 
912  if ( bSetItem )
913  {
914  if ( bCreateNewList )
915  {
916  if ( bNewNumRuleCreated )
917  {
918  // apply list id of list, which has been created for the new list style
919  sListId = pNewOrChangedNumRule->GetDefaultListId();
920  }
921  else
922  {
923  // create new list and apply its list id
924  const SwList* pNewList = getIDocumentListsAccess().createList( OUString(), pNewOrChangedNumRule->GetName() );
925  OSL_ENSURE( pNewList,
926  "<SwDoc::SetNumRule(..)> - could not create new list. Serious defect." );
927  sListId = pNewList->GetListId();
928  }
929  }
930  else if ( !sContinuedListId.isEmpty() )
931  {
932  // apply given list id
933  sListId = sContinuedListId;
934  }
935  if (!sListId.isEmpty())
936  {
939  SetAttrMode::DEFAULT, pLayout);
940  }
941  }
942 
943  if (!aPam.HasMark())
944  {
945  SwTextNode * pTextNd = aPam.GetPoint()->nNode.GetNode().GetTextNode();
946  // robust code: consider case that the PaM doesn't denote a text node - e.g. it denotes a graphic node
947  if ( pTextNd != nullptr )
948  {
949  assert(!pLayout || sw::IsParaPropsNode(*pLayout, *pTextNd));
950  SwNumRule * pRule = pTextNd->GetNumRule();
951 
952  if (pRule && pRule->GetName() == pNewOrChangedNumRule->GetName())
953  {
954  bSetItem = false;
955  if ( !pTextNd->IsInList() )
956  {
957  pTextNd->AddToList();
958  }
959  }
960  // Only clear numbering attribute at text node, if at paragraph
961  // style the new numbering rule is found.
962  else if ( !pRule )
963  {
964  SwTextFormatColl* pColl = pTextNd->GetTextColl();
965  if ( pColl )
966  {
967  SwNumRule* pCollRule = FindNumRulePtr(pColl->GetNumRule().GetValue());
968  if ( pCollRule && pCollRule->GetName() == pNewOrChangedNumRule->GetName() )
969  {
970  pTextNd->ResetAttr( RES_PARATR_NUMRULE );
971  bSetItem = false;
972  }
973  }
974  }
975  }
976  }
977 
978  if ( bSetItem )
979  {
981  SwNumRuleItem(pNewOrChangedNumRule->GetName()),
982  SetAttrMode::DEFAULT, pLayout);
983  }
984 
985  if ( bResetIndentAttrs
986  && pNewOrChangedNumRule->Get( 0 ).GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
987  {
988  ::lcl_ResetIndentAttrs(this, aPam, RES_LR_SPACE, pLayout);
989  }
990 
991  if (GetIDocumentUndoRedo().DoesUndo())
992  {
994  }
995 
997 
998  return sListId;
999 }
1000 
1001 void SwDoc::SetCounted(const SwPaM & rPam, bool bCounted,
1002  SwRootFrame const*const pLayout)
1003 {
1004  if ( bCounted )
1005  {
1006  ::lcl_ResetIndentAttrs(this, rPam, RES_PARATR_LIST_ISCOUNTED, pLayout);
1007  }
1008  else
1009  {
1012  SetAttrMode::DEFAULT, pLayout);
1013  }
1014 }
1015 
1016 void SwDoc::SetNumRuleStart( const SwPosition& rPos, bool bFlag )
1017 {
1018  SwTextNode* pTextNd = rPos.nNode.GetNode().GetTextNode();
1019 
1020  if (!pTextNd)
1021  return;
1022 
1023  const SwNumRule* pRule = pTextNd->GetNumRule();
1024  if( pRule && !bFlag != !pTextNd->IsListRestart())
1025  {
1027  {
1029  std::make_unique<SwUndoNumRuleStart>(rPos, bFlag) );
1030  }
1031 
1032  pTextNd->SetListRestart(bFlag);
1033 
1035  }
1036 }
1037 
1038 void SwDoc::SetNodeNumStart( const SwPosition& rPos, sal_uInt16 nStt )
1039 {
1040  SwTextNode* pTextNd = rPos.nNode.GetNode().GetTextNode();
1041 
1042  if (!pTextNd)
1043  return;
1044 
1045  if ( !pTextNd->HasAttrListRestartValue() ||
1046  pTextNd->GetAttrListRestartValue() != nStt )
1047  {
1049  {
1051  std::make_unique<SwUndoNumRuleStart>(rPos, nStt) );
1052  }
1053  pTextNd->SetAttrListRestartValue( nStt );
1054 
1056  }
1057 }
1058 
1059 // We can only delete if the Rule is unused!
1060 bool SwDoc::DelNumRule( const OUString& rName, bool bBroadcast )
1061 {
1062  sal_uInt16 nPos = FindNumRule( rName );
1063 
1064  if (nPos == USHRT_MAX)
1065  return false;
1066 
1067  if ( (*mpNumRuleTable)[ nPos ] == GetOutlineNumRule() )
1068  {
1069  OSL_FAIL( "<SwDoc::DelNumRule(..)> - No deletion of outline list style. This is serious defect" );
1070  return false;
1071  }
1072 
1073  if( !IsUsed( *(*mpNumRuleTable)[ nPos ] ))
1074  {
1075  if (GetIDocumentUndoRedo().DoesUndo())
1076  {
1078  std::make_unique<SwUndoNumruleDelete>(*(*mpNumRuleTable)[nPos], *this));
1079  }
1080 
1081  if (bBroadcast)
1082  BroadcastStyleOperation(rName, SfxStyleFamily::Pseudo,
1083  SfxHintId::StyleSheetErased);
1084 
1087  // #i34097# DeleteAndDestroy deletes rName if
1088  // rName is directly taken from the numrule.
1089  const OUString aTmpName( rName );
1090  delete (*mpNumRuleTable)[ nPos ];
1091  mpNumRuleTable->erase( mpNumRuleTable->begin() + nPos );
1092  maNumRuleMap.erase(aTmpName);
1093 
1095  return true;
1096  }
1097  return false;
1098 }
1099 
1101 {
1102  SwNumRule* pRule = FindNumRulePtr( rRule.GetName() );
1103  if( !pRule )
1104  return;
1105 
1106  SwUndoInsNum* pUndo = nullptr;
1108  {
1109  pUndo = new SwUndoInsNum( *pRule, rRule, *this );
1110  pUndo->GetHistory();
1111  GetIDocumentUndoRedo().AppendUndo( std::unique_ptr<SwUndo>(pUndo) );
1112  }
1113  ::lcl_ChgNumRule( *this, rRule );
1114  if (pUndo)
1115  {
1116  pUndo->SetLRSpaceEndPos();
1117  }
1118 
1120 }
1121 
1122 bool SwDoc::RenameNumRule(const OUString & rOldName, const OUString & rNewName,
1123  bool bBroadcast)
1124 {
1125  assert(!FindNumRulePtr(rNewName));
1126 
1127  bool bResult = false;
1128  SwNumRule * pNumRule = FindNumRulePtr(rOldName);
1129 
1130  if (pNumRule)
1131  {
1132  if (GetIDocumentUndoRedo().DoesUndo())
1133  {
1135  std::make_unique<SwUndoNumruleRename>(rOldName, rNewName, *this));
1136  }
1137 
1138  SwNumRule::tTextNodeList aTextNodeList;
1139  pNumRule->GetTextNodeList( aTextNodeList );
1140 
1141  pNumRule->SetName( rNewName, getIDocumentListsAccess() );
1142 
1143  SwNumRuleItem aItem(rNewName);
1144 
1145  for ( SwTextNode* pTextNd : aTextNodeList )
1146  {
1147  pTextNd->SetAttr(aItem);
1148  }
1149 
1150  bResult = true;
1151 
1152  if (bBroadcast)
1153  BroadcastStyleOperation(rOldName, SfxStyleFamily::Pseudo,
1154  SfxHintId::StyleSheetModified);
1155  }
1156 
1157  return bResult;
1158 }
1159 
1161 {
1162  for( sal_uInt16 n = GetNumRuleTable().size(); n; )
1163  {
1164  SwNumRule::tTextNodeList aTextNodeList;
1165  GetNumRuleTable()[ --n ]->GetTextNodeList( aTextNodeList );
1166  for ( SwTextNode* pTNd : aTextNodeList )
1167  {
1169  for(SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next() )
1170  if (pFrame->HasAnimation() &&
1171  (!pFrame->GetMergedPara() || pFrame->GetMergedPara()->pParaPropsNode == pTNd))
1172  {
1173  pFrame->StopAnimation( pOut );
1174  }
1175  }
1176  }
1177 }
1178 
1180  const OUString& rOldRule, const OUString& rNewRule )
1181 {
1182  SwNumRule *pOldRule = FindNumRulePtr( rOldRule ),
1183  *pNewRule = FindNumRulePtr( rNewRule );
1184  if( !pOldRule || !pNewRule || pOldRule == pNewRule )
1185  return;
1186 
1187  SwUndoInsNum* pUndo = nullptr;
1188  if (GetIDocumentUndoRedo().DoesUndo())
1189  {
1190  // Start/End for attributes!
1192  pUndo = new SwUndoInsNum( rPos, *pNewRule, rOldRule );
1193  GetIDocumentUndoRedo().AppendUndo(std::unique_ptr<SwUndo>(pUndo));
1194  }
1195 
1196  SwNumRule::tTextNodeList aTextNodeList;
1197  pOldRule->GetTextNodeList( aTextNodeList );
1198  if ( !aTextNodeList.empty() )
1199  {
1200  SwRegHistory aRegH( pUndo ? pUndo->GetHistory() : nullptr );
1201 
1202  const SwTextNode* pGivenTextNode = rPos.nNode.GetNode().GetTextNode();
1203  SwNumRuleItem aRule( rNewRule );
1204  for ( SwTextNode* pTextNd : aTextNodeList )
1205  {
1206  if ( pGivenTextNode &&
1207  pGivenTextNode->GetListId() == pTextNd->GetListId() )
1208  {
1209  aRegH.RegisterInModify( pTextNd, *pTextNd );
1210 
1211  pTextNd->SetAttr( aRule );
1212  pTextNd->NumRuleChgd();
1213  }
1214  }
1217  }
1218 }
1219 
1220 namespace
1221 {
1222  struct ListStyleData
1223  {
1224  SwNumRule* pReplaceNumRule;
1225  bool bCreateNewList;
1226  OUString sListId;
1227 
1228  ListStyleData()
1229  : pReplaceNumRule( nullptr ),
1230  bCreateNewList( false )
1231  {}
1232  };
1233 }
1234 
1236 {
1237  OSL_ENSURE( &rPaM.GetDoc() == this, "need same doc" );
1238 
1239  std::map<SwNumRule *, ListStyleData> aMyNumRuleMap;
1240 
1241  bool bFirst = true;
1242 
1243  const SwNodeOffset nStt = rPaM.Start()->nNode.GetIndex();
1244  const SwNodeOffset nEnd = rPaM.End()->nNode.GetIndex();
1245  for (SwNodeOffset n = nStt; n <= nEnd; n++)
1246  {
1247  SwTextNode * pCNd = GetNodes()[n]->GetTextNode();
1248 
1249  if (pCNd)
1250  {
1251  SwNumRule * pRule = pCNd->GetNumRule();
1252 
1253  if (pRule && pRule->IsAutoRule() && ! pRule->IsOutlineRule())
1254  {
1255  ListStyleData aListStyleData = aMyNumRuleMap[pRule];
1256 
1257  if ( aListStyleData.pReplaceNumRule == nullptr )
1258  {
1259  if (bFirst)
1260  {
1261  SwPosition aPos(*pCNd);
1262  aListStyleData.pReplaceNumRule =
1263  const_cast<SwNumRule *>
1264  (SearchNumRule( aPos, false, pCNd->HasNumber(),
1265  false, 0,
1266  aListStyleData.sListId, nullptr, true ));
1267  }
1268 
1269  if ( aListStyleData.pReplaceNumRule == nullptr )
1270  {
1271  aListStyleData.pReplaceNumRule = new SwNumRule(*pRule);
1272  aListStyleData.pReplaceNumRule->SetName( GetUniqueNumRuleName(), getIDocumentListsAccess() );
1273  aListStyleData.bCreateNewList = true;
1274  }
1275 
1276  aMyNumRuleMap[pRule] = aListStyleData;
1277  }
1278 
1279  SwPaM aPam(*pCNd);
1280 
1281  SetNumRule( aPam,
1282  *aListStyleData.pReplaceNumRule,
1283  aListStyleData.bCreateNewList,
1284  nullptr,
1285  aListStyleData.sListId );
1286  if ( aListStyleData.bCreateNewList )
1287  {
1288  aListStyleData.bCreateNewList = false;
1289  aListStyleData.sListId = pCNd->GetListId();
1290  aMyNumRuleMap[pRule] = aListStyleData;
1291  }
1292 
1293  bFirst = false;
1294  }
1295  }
1296  }
1297 }
1298 
1299 bool SwDoc::NoNum( const SwPaM& rPam )
1300 {
1301 
1302  bool bRet = getIDocumentContentOperations().SplitNode( *rPam.GetPoint(), false );
1303  // Do we actually use Numbering at all?
1304  if( bRet )
1305  {
1306  // Set NoNum and Update
1307  const SwNodeIndex& rIdx = rPam.GetPoint()->nNode;
1308  SwTextNode* pNd = rIdx.GetNode().GetTextNode();
1309  const SwNumRule* pRule = pNd->GetNumRule();
1310  if( pRule )
1311  {
1312  pNd->SetCountedInList(false);
1313 
1315  }
1316  else
1317  bRet = false; // no Numbering or just always true?
1318  }
1319  return bRet;
1320 }
1321 
1322 void SwDoc::DelNumRules(const SwPaM& rPam, SwRootFrame const*const pLayout)
1323 {
1324  SwPaM aPam(rPam, nullptr);
1325  ExpandPamForParaPropsNodes(aPam, pLayout);
1326  SwNodeOffset nStt = aPam.Start()->nNode.GetIndex();
1327  SwNodeOffset const nEnd = aPam.End()->nNode.GetIndex();
1328 
1329  SwUndoDelNum* pUndo;
1330  if (GetIDocumentUndoRedo().DoesUndo())
1331  {
1332  pUndo = new SwUndoDelNum( aPam );
1333  GetIDocumentUndoRedo().AppendUndo(std::unique_ptr<SwUndo>(pUndo));
1334  }
1335  else
1336  pUndo = nullptr;
1337 
1338  SwRegHistory aRegH( pUndo ? pUndo->GetHistory() : nullptr );
1339 
1340  SwNumRuleItem aEmptyRule;
1341  const SwNode* pOutlNd = nullptr;
1342  for( ; nStt <= nEnd; ++nStt )
1343  {
1344  SwTextNode* pTNd = GetNodes()[ nStt ]->GetTextNode();
1345  if (pLayout && pTNd)
1346  {
1347  pTNd = sw::GetParaPropsNode(*pLayout, *pTNd);
1348  }
1349  SwNumRule* pNumRuleOfTextNode = pTNd ? pTNd->GetNumRule() : nullptr;
1350  if ( pTNd && pNumRuleOfTextNode )
1351  {
1352  // recognize changes of attribute for undo
1353  aRegH.RegisterInModify( pTNd, *pTNd );
1354 
1355  if( pUndo )
1356  pUndo->AddNode( *pTNd );
1357 
1358  // directly set list style attribute is reset, otherwise empty
1359  // list style is applied
1360  const SfxItemSet* pAttrSet = pTNd->GetpSwAttrSet();
1361  if ( pAttrSet &&
1362  pAttrSet->GetItemState( RES_PARATR_NUMRULE, false ) == SfxItemState::SET )
1363  pTNd->ResetAttr( RES_PARATR_NUMRULE );
1364  else
1365  pTNd->SetAttr( aEmptyRule );
1366 
1367  pTNd->ResetAttr( RES_PARATR_LIST_ID );
1372 
1373  if( RES_CONDTXTFMTCOLL == pTNd->GetFormatColl()->Which() )
1374  {
1375  pTNd->ChkCondColl();
1376  }
1377  else if( !pOutlNd &&
1378  static_cast<SwTextFormatColl*>(pTNd->GetFormatColl())->IsAssignedToListLevelOfOutlineStyle() )
1379  {
1380  pOutlNd = pTNd;
1381  }
1382  }
1383  }
1384 
1385  // Finally, update all
1386  UpdateNumRule();
1387 
1388  if( pOutlNd )
1389  GetNodes().UpdateOutlineIdx( *pOutlNd );
1390 }
1391 
1393 {
1394  for (size_t n = 0; n < mpNumRuleTable->size(); ++n)
1395  (*mpNumRuleTable)[n]->SetInvalidRule(true);
1396 }
1397 
1398 // To the next/preceding Bullet at the same Level
1399 static bool lcl_IsNumOk( sal_uInt8 nSrchNum, sal_uInt8& rLower, sal_uInt8& rUpper,
1400  bool bOverUpper, sal_uInt8 nNumber )
1401 {
1402  OSL_ENSURE( nNumber < MAXLEVEL,
1403  "<lcl_IsNumOk(..)> - misusage of method" );
1404 
1405  bool bRet = false;
1406  {
1407  if( bOverUpper ? nSrchNum == nNumber : nSrchNum >= nNumber )
1408  bRet = true;
1409  else if( nNumber > rLower )
1410  rLower = nNumber;
1411  else if( nNumber < rUpper )
1412  rUpper = nNumber;
1413  }
1414  return bRet;
1415 }
1416 
1417 static bool lcl_IsValidPrevNextNumNode( const SwNodeIndex& rIdx )
1418 {
1419  bool bRet = false;
1420  const SwNode& rNd = rIdx.GetNode();
1421  switch( rNd.GetNodeType() )
1422  {
1423  case SwNodeType::End:
1426  break;
1427 
1428  case SwNodeType::Start:
1429  bRet = SwTableBoxStartNode == static_cast<const SwStartNode&>(rNd).GetStartNodeType();
1430  break;
1431 
1432  case SwNodeType::Section: // that one's valid, so proceed
1433  bRet = true;
1434  break;
1435 
1436  default: break;
1437  }
1438  return bRet;
1439 }
1440 
1441 namespace sw {
1442 
1443 void
1444 GotoPrevLayoutTextFrame(SwNodeIndex & rIndex, SwRootFrame const*const pLayout)
1445 {
1446  if (pLayout && pLayout->HasMergedParas())
1447  {
1448  if (rIndex.GetNode().IsTextNode())
1449  {
1450  if (rIndex.GetNode().GetRedlineMergeFlag() != SwNode::Merge::None &&
1451  // not a tracked row deletion in Hide Changes mode
1452  rIndex.GetNode().GetTextNode()->getLayoutFrame(pLayout) )
1453  {
1454  rIndex = *static_cast<SwTextFrame*>(rIndex.GetNode().GetTextNode()->getLayoutFrame(pLayout))->GetMergedPara()->pFirstNode;
1455  }
1456  }
1457  else if (rIndex.GetNode().IsEndNode())
1458  {
1460  {
1461  rIndex = *rIndex.GetNode().StartOfSectionNode();
1462  assert(rIndex.GetNode().IsTableNode());
1463  }
1464  }
1465  }
1466  --rIndex;
1467  if (pLayout && rIndex.GetNode().IsTextNode())
1468  {
1469  rIndex = *sw::GetParaPropsNode(*pLayout, *rIndex.GetNode().GetTextNode());
1470  }
1471 }
1472 
1473 void
1474 GotoNextLayoutTextFrame(SwNodeIndex & rIndex, SwRootFrame const*const pLayout)
1475 {
1476  if (pLayout && pLayout->HasMergedParas())
1477  {
1478  if (rIndex.GetNode().IsTextNode())
1479  {
1481  {
1482  rIndex = *static_cast<SwTextFrame*>(rIndex.GetNode().GetTextNode()->getLayoutFrame(pLayout))->GetMergedPara()->pLastNode;
1483  }
1484  }
1485  else if (rIndex.GetNode().IsTableNode())
1486  {
1488  {
1489  rIndex = *rIndex.GetNode().EndOfSectionNode();
1490  }
1491  }
1492  }
1493  ++rIndex;
1494  if (pLayout && rIndex.GetNode().IsTextNode())
1495  {
1496  rIndex = *sw::GetParaPropsNode(*pLayout, *rIndex.GetNode().GetTextNode());
1497  }
1498 }
1499 
1500 } // namespace sw
1501 
1502 static bool lcl_GotoNextPrevNum( SwPosition& rPos, bool bNext,
1503  bool bOverUpper, sal_uInt8* pUpper, sal_uInt8* pLower,
1504  SwRootFrame const*const pLayout)
1505 {
1506  const SwTextNode* pNd = rPos.nNode.GetNode().GetTextNode();
1507  if (pNd && pLayout)
1508  {
1509  pNd = sw::GetParaPropsNode(*pLayout, *pNd);
1510  }
1511  if( !pNd || nullptr == pNd->GetNumRule() )
1512  return false;
1513 
1514  sal_uInt8 nSrchNum = static_cast<sal_uInt8>(pNd->GetActualListLevel());
1515 
1516  SwNodeIndex aIdx( rPos.nNode );
1517  if( ! pNd->IsCountedInList() )
1518  {
1519  bool bError = false;
1520  do {
1521  sw::GotoPrevLayoutTextFrame(aIdx, pLayout);
1522  if( aIdx.GetNode().IsTextNode() )
1523  {
1524  pNd = aIdx.GetNode().GetTextNode();
1525  const SwNumRule* pRule = pNd->GetNumRule();
1526 
1527  if( pRule )
1528  {
1529  sal_uInt8 nTmpNum = static_cast<sal_uInt8>(pNd->GetActualListLevel());
1530  if( pNd->IsCountedInList() || (nTmpNum < nSrchNum ) )
1531  break; // found it!
1532  }
1533  else
1534  bError = true;
1535  }
1536  else
1537  bError = !lcl_IsValidPrevNextNumNode( aIdx );
1538 
1539  } while( !bError );
1540  if( bError )
1541  return false;
1542  }
1543 
1544  sal_uInt8 nLower = nSrchNum, nUpper = nSrchNum;
1545  bool bRet = false;
1546 
1547  const SwTextNode* pLast;
1548  if( bNext )
1549  {
1550  sw::GotoNextLayoutTextFrame(aIdx, pLayout);
1551  pLast = pNd;
1552  }
1553  else
1554  {
1555  sw::GotoPrevLayoutTextFrame(aIdx, pLayout);
1556  pLast = nullptr;
1557  }
1558 
1559  while( bNext ? ( aIdx.GetIndex() < aIdx.GetNodes().Count() - 1 )
1560  : aIdx.GetIndex() != SwNodeOffset(0) )
1561  {
1562  if( aIdx.GetNode().IsTextNode() )
1563  {
1564  pNd = aIdx.GetNode().GetTextNode();
1565  const SwNumRule* pRule = pNd->GetNumRule();
1566  if( pRule )
1567  {
1568  if( ::lcl_IsNumOk( nSrchNum, nLower, nUpper, bOverUpper,
1569  static_cast<sal_uInt8>(pNd->GetActualListLevel()) ))
1570  {
1571  rPos.nNode = aIdx;
1572  rPos.nContent.Assign( const_cast<SwTextNode*>(pNd), 0 );
1573  bRet = true;
1574  break;
1575  }
1576  else
1577  pLast = pNd;
1578  }
1579  else
1580  break;
1581  }
1582  else if( !lcl_IsValidPrevNextNumNode( aIdx ))
1583  break;
1584 
1585  if( bNext )
1586  sw::GotoNextLayoutTextFrame(aIdx, pLayout);
1587  else
1588  sw::GotoPrevLayoutTextFrame(aIdx, pLayout);
1589  }
1590 
1591  if( !bRet && !bOverUpper && pLast ) // do not iterate over higher numbers, but still to the end
1592  {
1593  if( bNext )
1594  {
1595  rPos.nNode = aIdx;
1596  if( aIdx.GetNode().IsContentNode() )
1597  rPos.nContent.Assign( aIdx.GetNode().GetContentNode(), 0 );
1598  }
1599  else
1600  {
1601  rPos.nNode.Assign( *pLast );
1602  rPos.nContent.Assign( const_cast<SwTextNode*>(pLast), 0 );
1603  }
1604  bRet = true;
1605  }
1606 
1607  if( bRet )
1608  {
1609  if( pUpper )
1610  *pUpper = nUpper;
1611  if( pLower )
1612  *pLower = nLower;
1613  }
1614  return bRet;
1615 }
1616 
1617 bool SwDoc::GotoNextNum(SwPosition& rPos, SwRootFrame const*const pLayout,
1618  bool bOverUpper, sal_uInt8* pUpper, sal_uInt8* pLower)
1619 {
1620  return ::lcl_GotoNextPrevNum(rPos, true, bOverUpper, pUpper, pLower, pLayout);
1621 }
1622 
1624  const bool bForward,
1625  const bool bNum,
1626  const bool bOutline,
1627  int nNonEmptyAllowed,
1628  OUString& sListId,
1629  SwRootFrame const* pLayout,
1630  const bool bInvestigateStartNode)
1631 {
1632  const SwNumRule * pResult = nullptr;
1633  SwTextNode * pTextNd = rPos.nNode.GetNode().GetTextNode();
1634  if (pLayout)
1635  {
1636  pTextNd = sw::GetParaPropsNode(*pLayout, rPos.nNode);
1637  }
1638  SwNode * pStartFromNode = pTextNd;
1639 
1640  if (pTextNd)
1641  {
1642  SwNodeIndex aIdx(rPos.nNode);
1643 
1644  // - the start node has also been investigated, if requested.
1645  const SwNode * pNode = nullptr;
1646  do
1647  {
1648  if ( !bInvestigateStartNode )
1649  {
1650  if (bForward)
1651  sw::GotoNextLayoutTextFrame(aIdx, pLayout);
1652  else
1653  sw::GotoPrevLayoutTextFrame(aIdx, pLayout);
1654  }
1655 
1656  if (aIdx.GetNode().IsTextNode())
1657  {
1658  pTextNd = aIdx.GetNode().GetTextNode();
1659 
1660  const SwNumRule * pNumRule = pTextNd->GetNumRule();
1661  if (pNumRule)
1662  {
1663  if ( ( pNumRule->IsOutlineRule() == bOutline ) &&
1664  ( ( bNum && pNumRule->Get(0).IsEnumeration()) ||
1665  ( !bNum && pNumRule->Get(0).IsItemize() ) ) ) // #i22362#, #i29560#
1666  {
1667  pResult = pTextNd->GetNumRule();
1668  // provide also the list id, to which the text node belongs.
1669  sListId = pTextNd->GetListId();
1670  }
1671 
1672  break;
1673  }
1674  else if (pTextNd->Len() > 0 || nullptr != pTextNd->GetNumRule())
1675  {
1676  if (nNonEmptyAllowed == 0)
1677  break;
1678 
1679  nNonEmptyAllowed--;
1680 
1681  if (nNonEmptyAllowed < 0)
1682  nNonEmptyAllowed = -1;
1683  }
1684  }
1685 
1686  if ( bInvestigateStartNode )
1687  {
1688  if (bForward)
1689  sw::GotoNextLayoutTextFrame(aIdx, pLayout);
1690  else
1691  sw::GotoPrevLayoutTextFrame(aIdx, pLayout);
1692  }
1693 
1694  pNode = &aIdx.GetNode();
1695  }
1696  while (pNode != GetNodes().DocumentSectionStartNode(pStartFromNode) &&
1697  pNode != GetNodes().DocumentSectionEndNode(pStartFromNode));
1698  }
1699 
1700  return pResult;
1701 }
1702 
1703 bool SwDoc::GotoPrevNum(SwPosition& rPos, SwRootFrame const*const pLayout,
1704  bool bOverUpper)
1705 {
1706  return ::lcl_GotoNextPrevNum(rPos, false, bOverUpper, nullptr, nullptr, pLayout);
1707 }
1708 
1709 bool SwDoc::NumUpDown(const SwPaM& rPam, bool bDown, SwRootFrame const*const pLayout)
1710 {
1711  SwPaM aPam(rPam, nullptr);
1712  ExpandPamForParaPropsNodes(aPam, pLayout);
1713  SwNodeOffset nStt = aPam.Start()->nNode.GetIndex();
1714  SwNodeOffset const nEnd = aPam.End()->nNode.GetIndex();
1715 
1716  // -> outline nodes are promoted or demoted differently
1717  bool bOnlyOutline = true;
1718  bool bOnlyNonOutline = true;
1719  for (SwNodeOffset n = nStt; n <= nEnd; n++)
1720  {
1721  SwTextNode * pTextNd = GetNodes()[n]->GetTextNode();
1722 
1723  if (pTextNd)
1724  {
1725  if (pLayout)
1726  {
1727  pTextNd = sw::GetParaPropsNode(*pLayout, *pTextNd);
1728  }
1729  SwNumRule * pRule = pTextNd->GetNumRule();
1730 
1731  if (pRule)
1732  {
1733  if (pRule->IsOutlineRule())
1734  bOnlyNonOutline = false;
1735  else
1736  bOnlyOutline = false;
1737  }
1738  }
1739  }
1740 
1741  bool bRet = true;
1742  sal_Int8 nDiff = bDown ? 1 : -1;
1743 
1744  if (bOnlyOutline)
1745  bRet = OutlineUpDown(rPam, nDiff, pLayout);
1746  else if (bOnlyNonOutline)
1747  {
1748  /* #i24560#
1749  Only promote or demote if all selected paragraphs are
1750  promotable resp. demotable.
1751  */
1752  for (SwNodeOffset nTmp = nStt; nTmp <= nEnd; ++nTmp)
1753  {
1754  SwTextNode* pTNd = GetNodes()[ nTmp ]->GetTextNode();
1755 
1756  // Make code robust: consider case that the node doesn't denote a
1757  // text node.
1758  if ( pTNd )
1759  {
1760  if (pLayout)
1761  {
1762  pTNd = sw::GetParaPropsNode(*pLayout, *pTNd);
1763  }
1764 
1765  SwNumRule * pRule = pTNd->GetNumRule();
1766 
1767  if (pRule)
1768  {
1769  sal_uInt8 nLevel = static_cast<sal_uInt8>(pTNd->GetActualListLevel());
1770  if( (-1 == nDiff && 0 >= nLevel) ||
1771  (1 == nDiff && MAXLEVEL - 1 <= nLevel))
1772  bRet = false;
1773  }
1774  }
1775  }
1776 
1777  if( bRet )
1778  {
1780  {
1782  std::make_unique<SwUndoNumUpDown>(aPam, nDiff) );
1783  }
1784 
1785  SwTextNode* pPrev = nullptr;
1786  for(SwNodeOffset nTmp = nStt; nTmp <= nEnd; ++nTmp )
1787  {
1788  SwTextNode* pTNd = GetNodes()[ nTmp ]->GetTextNode();
1789 
1790  if( pTNd)
1791  {
1792  if (pLayout)
1793  {
1794  pTNd = sw::GetParaPropsNode(*pLayout, *pTNd);
1795  if (pTNd == pPrev)
1796  {
1797  continue;
1798  }
1799  pPrev = pTNd;
1800  }
1801 
1802  SwNumRule * pRule = pTNd->GetNumRule();
1803 
1804  if (pRule)
1805  {
1806  sal_uInt8 nLevel = static_cast<sal_uInt8>(pTNd->GetActualListLevel());
1807  nLevel = nLevel + nDiff;
1808 
1809  pTNd->SetAttrListLevel(nLevel);
1810  }
1811  }
1812  }
1813 
1814  ChkCondColls();
1816  }
1817  }
1818 
1819  return bRet;
1820 }
1821 
1822 // this function doesn't contain any numbering-related code, but it is
1823 // primarily called to move numbering-relevant paragraphs around, hence
1824 // it will expand its selection to include full SwTextFrames.
1825 bool SwDoc::MoveParagraph(SwPaM& rPam, SwNodeOffset nOffset, bool const bIsOutlMv)
1826 {
1828 
1829  // sw_redlinehide: as long as a layout with Hide mode exists, only
1830  // move nodes that have merged frames *completely*
1831  SwRootFrame const* pLayout(nullptr);
1832  for (SwRootFrame const*const pLay : GetAllLayouts())
1833  {
1834  if (pLay->HasMergedParas())
1835  {
1836  pLayout = pLay;
1837  }
1838  }
1839  if (pLayout)
1840  {
1841  std::pair<SwTextNode *, SwTextNode *> nodes(
1842  sw::GetFirstAndLastNode(*pLayout, rPam.Start()->nNode));
1843  if (nodes.first && nodes.first != &rPam.Start()->nNode.GetNode())
1844  {
1845  assert(nodes.second);
1846  if (nOffset < SwNodeOffset(0))
1847  {
1848  nOffset += rPam.Start()->nNode.GetIndex() - nodes.first->GetIndex();
1849  if (SwNodeOffset(0) <= nOffset) // hack: there are callers that know what
1850  { // node they want; those should never need
1851  nOffset = SwNodeOffset(-1); // this; other callers just pass in -1
1852  } // and those should still move
1853  }
1854  if (!rPam.HasMark())
1855  {
1856  rPam.SetMark();
1857  }
1858  assert(nodes.first->GetIndex() < rPam.Start()->nNode.GetIndex());
1859  rPam.Start()->nNode = *nodes.first;
1860  rPam.Start()->nContent.Assign(nodes.first, 0);
1861  }
1862  nodes = sw::GetFirstAndLastNode(*pLayout, rPam.End()->nNode);
1863  if (nodes.second && nodes.second != &rPam.End()->nNode.GetNode())
1864  {
1865  assert(nodes.first);
1866  if (SwNodeOffset(0) < nOffset)
1867  {
1868  nOffset -= nodes.second->GetIndex() - rPam.End()->nNode.GetIndex();
1869  if (nOffset <= SwNodeOffset(0)) // hack: there are callers that know what
1870  { // node they want; those should never need
1871  nOffset = SwNodeOffset(+1); // this; other callers just pass in +1
1872  } // and those should still move
1873  }
1874  if (!rPam.HasMark())
1875  {
1876  rPam.SetMark();
1877  }
1878  assert(rPam.End()->nNode.GetIndex() < nodes.second->GetIndex());
1879  rPam.End()->nNode = *nodes.second;
1880  // until end, otherwise Impl will detect overlapping redline
1881  rPam.End()->nContent.Assign(nodes.second, nodes.second->GetTextNode()->Len());
1882  }
1883 
1884  if (nOffset > SwNodeOffset(0))
1885  { // sw_redlinehide: avoid moving into delete redline, skip forward
1886  if (GetNodes().GetEndOfContent().GetIndex() <= rPam.End()->nNode.GetIndex() + nOffset)
1887  {
1888  return false; // can't move
1889  }
1890  SwNode const* pNode(GetNodes()[rPam.End()->nNode.GetIndex() + nOffset + 1]);
1891  if ( pNode->GetRedlineMergeFlag() != SwNode::Merge::None
1892  && pNode->GetRedlineMergeFlag() != SwNode::Merge::First)
1893  {
1894  for ( ; ; ++nOffset)
1895  {
1896  pNode = GetNodes()[rPam.End()->nNode.GetIndex() + nOffset];
1897  if (pNode->IsTextNode())
1898  {
1899  nodes = GetFirstAndLastNode(*pLayout, *pNode->GetTextNode());
1900  assert(nodes.first && nodes.second);
1901  nOffset += nodes.second->GetIndex() - pNode->GetIndex();
1902  // on last; will be incremented below to behind-last
1903  break;
1904  }
1905  }
1906  }
1907  }
1908  else
1909  { // sw_redlinehide: avoid moving into delete redline, skip backward
1910  if (rPam.Start()->nNode.GetIndex() + nOffset < SwNodeOffset(1))
1911  {
1912  return false; // can't move
1913  }
1914  SwNode const* pNode(GetNodes()[rPam.Start()->nNode.GetIndex() + nOffset]);
1915  if ( pNode->GetRedlineMergeFlag() != SwNode::Merge::None
1916  && pNode->GetRedlineMergeFlag() != SwNode::Merge::First)
1917  {
1918  for ( ; ; --nOffset)
1919  {
1920  pNode = GetNodes()[rPam.Start()->nNode.GetIndex() + nOffset];
1921  if (pNode->IsTextNode())
1922  {
1923  nodes = GetFirstAndLastNode(*pLayout, *pNode->GetTextNode());
1924  assert(nodes.first && nodes.second);
1925  nOffset -= pNode->GetIndex() - nodes.first->GetIndex();
1926  // on first
1927  break;
1928  }
1929  }
1930  }
1931  }
1932  }
1933  return MoveParagraphImpl(rPam, nOffset, bIsOutlMv, pLayout);
1934 }
1935 
1936 bool SwDoc::MoveParagraphImpl(SwPaM& rPam, SwNodeOffset const nOffset,
1937  bool const bIsOutlMv, SwRootFrame const*const pLayout)
1938 {
1939  const SwPosition *pStt = rPam.Start(), *pEnd = rPam.End();
1940 
1941  SwNodeOffset nStIdx = pStt->nNode.GetIndex();
1942  SwNodeOffset nEndIdx = pEnd->nNode.GetIndex();
1943 
1944  // Here are some sophisticated checks whether the wished PaM will be moved or not.
1945  // For moving outlines (bIsOutlMv) I've already done some checks, so here are two different
1946  // checks...
1947  SwNode *pTmp1;
1948  SwNode *pTmp2;
1949  if( bIsOutlMv )
1950  {
1951  // For moving chapters (outline) the following reason will deny the move:
1952  // if a start node is inside the moved range and its end node outside or vice versa.
1953  // If a start node is the first moved paragraph, its end node has to be within the moved
1954  // range, too (e.g. as last node).
1955  // If an end node is the last node of the moved range, its start node has to be a part of
1956  // the moved section, too.
1957  pTmp1 = GetNodes()[ nStIdx ];
1958  if( pTmp1->IsStartNode() )
1959  {
1960  // coverity[copy_paste_error : FALSE] - First is a start node
1961  pTmp2 = pTmp1->EndOfSectionNode();
1962  if( pTmp2->GetIndex() > nEndIdx )
1963  return false; // Its end node is behind the moved range
1964  }
1965  pTmp1 = pTmp1->StartOfSectionNode()->EndOfSectionNode();
1966  if( pTmp1->GetIndex() <= nEndIdx )
1967  return false; // End node inside but start node before moved range => no.
1968  pTmp1 = GetNodes()[ nEndIdx ];
1969  if( pTmp1->IsEndNode() )
1970  { // The last one is an end node
1971  pTmp1 = pTmp1->StartOfSectionNode();
1972  if( pTmp1->GetIndex() < nStIdx )
1973  return false; // Its start node is before the moved range.
1974  }
1975  pTmp1 = pTmp1->StartOfSectionNode();
1976  if( pTmp1->GetIndex() >= nStIdx )
1977  return false; // A start node which ends behind the moved range => no.
1978  }
1979 
1980  SwNodeOffset nInStIdx, nInEndIdx;
1981  SwNodeOffset nOffs = nOffset;
1982  if( nOffset > SwNodeOffset(0) )
1983  {
1984  nInEndIdx = nEndIdx;
1985  nEndIdx += nOffset;
1986  ++nOffs;
1987  }
1988  else
1989  {
1990  // Impossible to move to negative index
1991  if( abs( nOffset ) > nStIdx)
1992  return false;
1993 
1994  nInEndIdx = nStIdx - 1;
1995  nStIdx += nOffset;
1996  }
1997  nInStIdx = nInEndIdx + 1;
1998  // The following paragraphs shall be swapped:
1999  // Swap [ nStIdx, nInEndIdx ] with [ nInStIdx, nEndIdx ]
2000 
2001  if( nEndIdx >= GetNodes().GetEndOfContent().GetIndex() )
2002  return false;
2003 
2004  if( !bIsOutlMv )
2005  { // And here the restrictions for moving paragraphs other than chapters (outlines)
2006  // The plan is to exchange [nStIdx,nInEndIdx] and [nStartIdx,nEndIdx]
2007  // It will checked if the both "start" nodes as well as the both "end" notes belongs to
2008  // the same start-end-section. This is more restrictive than the conditions checked above.
2009  // E.g. a paragraph will not escape from a section or be inserted to another section.
2010  pTmp1 = GetNodes()[ nStIdx ]->StartOfSectionNode();
2011  pTmp2 = GetNodes()[ nInStIdx ]->StartOfSectionNode();
2012  if( pTmp1 != pTmp2 )
2013  return false; // "start" nodes in different sections
2014  pTmp1 = GetNodes()[ nEndIdx ];
2015  bool bIsEndNode = pTmp1->IsEndNode();
2016  if( !pTmp1->IsStartNode() )
2017  {
2018  pTmp1 = pTmp1->StartOfSectionNode();
2019  if( bIsEndNode ) // For end nodes the first start node is of course inside the range,
2020  pTmp1 = pTmp1->StartOfSectionNode(); // I've to check the start node of the start node.
2021  }
2022  pTmp1 = pTmp1->EndOfSectionNode();
2023  pTmp2 = GetNodes()[ nInEndIdx ];
2024  if( !pTmp2->IsStartNode() )
2025  {
2026  bIsEndNode = pTmp2->IsEndNode();
2027  pTmp2 = pTmp2->StartOfSectionNode();
2028  if( bIsEndNode )
2029  pTmp2 = pTmp2->StartOfSectionNode();
2030  }
2031  pTmp2 = pTmp2->EndOfSectionNode();
2032  if( pTmp1 != pTmp2 )
2033  return false; // The "end" notes are in different sections
2034  }
2035 
2036  // Test for Redlining - Can the Selection be moved at all, actually?
2037  if( !getIDocumentRedlineAccess().IsIgnoreRedline() )
2038  {
2039  SwRedlineTable::size_type nRedlPos = getIDocumentRedlineAccess().GetRedlinePos( pStt->nNode.GetNode(), RedlineType::Delete );
2040  if( SwRedlineTable::npos != nRedlPos )
2041  {
2042  SwPosition aStPos( *pStt ), aEndPos( *pEnd );
2043  aStPos.nContent = 0;
2044  SwContentNode* pCNd = pEnd->nNode.GetNode().GetContentNode();
2045  aEndPos.nContent = pCNd ? pCNd->Len() : 1;
2046  bool bCheckDel = true;
2047 
2048  // There is a some Redline Delete Object for the range
2049  for( ; nRedlPos < getIDocumentRedlineAccess().GetRedlineTable().size(); ++nRedlPos )
2050  {
2051  const SwRangeRedline* pTmp = getIDocumentRedlineAccess().GetRedlineTable()[ nRedlPos ];
2052  if( !bCheckDel || RedlineType::Delete == pTmp->GetType() )
2053  {
2054  const SwPosition *pRStt = pTmp->Start(), *pREnd = pTmp->End();
2055  switch( ComparePosition( *pRStt, *pREnd, aStPos, aEndPos ))
2056  {
2058  case SwComparePosition::Behind: // Pos1 comes after Pos2
2060  break;
2061 
2063  case SwComparePosition::Before: // Pos1 comes before Pos2
2064  break;
2065  case SwComparePosition::Inside: // Pos1 is completely inside Pos2
2066  // that's valid, but check all following for overlapping
2067  bCheckDel = false;
2068  break;
2069 
2070  case SwComparePosition::Outside: // Pos2 is completely inside Pos1
2071  case SwComparePosition::Equal: // Pos1 is equal to Pos2
2072  case SwComparePosition::OverlapBefore: // Pos1 overlaps Pos2 in the beginning
2073  case SwComparePosition::OverlapBehind: // Pos1 overlaps Pos2 at the end
2074  return false;
2075  }
2076  }
2077  }
2078  }
2079  }
2080 
2081  {
2082  // Send DataChanged before moving. We then can detect
2083  // which objects are still in the range.
2084  // After the move they could come before/after the
2085  // Position.
2086  SwDataChanged aTmp( rPam );
2087  }
2088 
2089  SwNodeIndex aIdx( nOffset > SwNodeOffset(0) ? pEnd->nNode : pStt->nNode, nOffs );
2090  SwNodeRange aMvRg( pStt->nNode, SwNodeOffset(0), pEnd->nNode, SwNodeOffset(+1) );
2091 
2092  SwRangeRedline* pOwnRedl = nullptr;
2093  if( getIDocumentRedlineAccess().IsRedlineOn() )
2094  {
2095  // If the range is completely in the own Redline, we can move it!
2096  SwRedlineTable::size_type nRedlPos = getIDocumentRedlineAccess().GetRedlinePos( pStt->nNode.GetNode(), RedlineType::Insert );
2097  if( SwRedlineTable::npos != nRedlPos )
2098  {
2100  const SwPosition *pRStt = pTmp->Start(), *pREnd = pTmp->End();
2101  SwRangeRedline aTmpRedl( RedlineType::Insert, rPam );
2102  const SwContentNode* pCEndNd = pEnd->nNode.GetNode().GetContentNode();
2103  // Is completely in the range and is the own Redline too?
2104  if( aTmpRedl.IsOwnRedline( *pTmp ) &&
2105  (pRStt->nNode < pStt->nNode ||
2106  (pRStt->nNode == pStt->nNode && !pRStt->nContent.GetIndex()) ) &&
2107  (pEnd->nNode < pREnd->nNode ||
2108  (pEnd->nNode == pREnd->nNode &&
2109  pCEndNd ? pREnd->nContent.GetIndex() == pCEndNd->Len()
2110  : !pREnd->nContent.GetIndex() )) )
2111  {
2112  pOwnRedl = pTmp;
2113  if( nRedlPos + 1 < getIDocumentRedlineAccess().GetRedlineTable().size() )
2114  {
2115  pTmp = getIDocumentRedlineAccess().GetRedlineTable()[ nRedlPos+1 ];
2116  if( *pTmp->Start() == *pREnd )
2117  // then don't!
2118  pOwnRedl = nullptr;
2119  }
2120 
2121  if( pOwnRedl &&
2122  ( pRStt->nNode > aIdx || aIdx > pREnd->nNode ||
2123  // pOwnRedl doesn't start at the beginning of a node, so it's not
2124  // possible to resize it to contain the line moved before it
2125  ( pRStt->nNode == aIdx && pRStt->nContent.GetIndex() > 0 ) ) )
2126  {
2127  // it's not in itself, so don't move it
2128  pOwnRedl = nullptr;
2129  }
2130  }
2131  }
2132 
2133  if( !pOwnRedl )
2134  {
2136 
2137  // First the Insert, then the Delete
2138  SwPosition aInsPos( aIdx );
2139  aInsPos.nContent.Assign( aIdx.GetNode().GetContentNode(), 0 );
2140 
2141  SwPaM aPam( pStt->nNode, 0, aMvRg.aEnd, 0 );
2142 
2143  SwPaM& rOrigPam(rPam);
2144  rOrigPam.DeleteMark();
2145  rOrigPam.GetPoint()->nNode = aIdx.GetIndex() - 1;
2146  rOrigPam.GetPoint()->nContent.Assign( rOrigPam.GetContentNode(), 0 );
2147 
2148  bool bDelLastPara = !aInsPos.nNode.GetNode().IsContentNode();
2149  SwNodeOffset nOrigIdx = aIdx.GetIndex();
2150 
2151  /* When copying to a non-content node Copy will
2152  insert a paragraph before that node and insert before
2153  that inserted node. Copy creates an SwUndoInserts that
2154  does not cover the extra paragraph. Thus we insert the
2155  extra paragraph ourselves, _with_ correct undo
2156  information. */
2157  if (bDelLastPara)
2158  {
2159  /* aInsPos points to the non-content node. Move it to
2160  the previous content node. */
2161  SwPaM aInsPam(aInsPos);
2162  const bool bMoved = aInsPam.Move(fnMoveBackward);
2163  OSL_ENSURE(bMoved, "No content node found!");
2164 
2165  if (bMoved)
2166  {
2167  /* Append the new node after the content node
2168  found. The new position to insert the moved
2169  paragraph at is before the inserted
2170  paragraph. */
2172  aInsPos = *aInsPam.GetPoint();
2173  }
2174  }
2175 
2176  --aIdx; // move before insertion
2177 
2178  // adjust empty nodes later
2179  SwTextNode const*const pIsEmptyNode(nOffset < SwNodeOffset(0)
2180  ? aInsPos.nNode.GetNode().GetTextNode()
2181  : aIdx.GetNode().GetTextNode());
2182  bool bIsEmptyNode = pIsEmptyNode && pIsEmptyNode->Len() == 0;
2183 
2185 
2186  // now delete all the delete redlines that were copied
2187 #ifndef NDEBUG
2188  size_t nRedlines(getIDocumentRedlineAccess().GetRedlineTable().size());
2189 #endif
2190  if (nOffset > SwNodeOffset(0))
2191  assert(aPam.End()->nNode.GetIndex() - aPam.Start()->nNode.GetIndex() + nOffset == aInsPos.nNode.GetIndex() - aPam.End()->nNode.GetIndex());
2192  else
2193  assert(aPam.Start()->nNode.GetIndex() - aPam.End()->nNode.GetIndex() + nOffset == aInsPos.nNode.GetIndex() - aPam.End()->nNode.GetIndex());
2195  getIDocumentRedlineAccess().GetRedline(*aPam.End(), &i);
2196  for ( ; 0 < i; --i)
2197  { // iterate backwards and offset via the start nodes difference
2198  SwRangeRedline const*const pRedline = getIDocumentRedlineAccess().GetRedlineTable()[i - 1];
2199  if (*pRedline->End() < *aPam.Start())
2200  {
2201  break;
2202  }
2203  if (pRedline->GetType() == RedlineType::Delete &&
2204  // tdf#145066 skip full-paragraph deletion which was jumped over
2205  // in Show Changes mode to avoid of deleting an extra row
2206  *aPam.Start() <= *pRedline->Start())
2207  {
2208  SwRangeRedline* pNewRedline;
2209  {
2210  SwPaM pam(*pRedline, nullptr);
2211  SwNodeOffset const nCurrentOffset(
2212  nOrigIdx - aPam.Start()->nNode.GetIndex());
2213  pam.GetPoint()->nNode += nCurrentOffset;
2215  pam.GetMark()->nNode += nCurrentOffset;
2217 
2218  pNewRedline = new SwRangeRedline( RedlineType::Delete, pam );
2219  }
2220  // note: effectively this will DeleteAndJoin the pam!
2221  getIDocumentRedlineAccess().AppendRedline(pNewRedline, true);
2222  assert(getIDocumentRedlineAccess().GetRedlineTable().size() <= nRedlines);
2223  }
2224  }
2225 
2226  if( bDelLastPara )
2227  {
2228  // We need to remove the last empty Node again
2229  aIdx = aInsPos.nNode;
2230  SwContentNode* pCNd = SwNodes::GoPrevious( &aInsPos.nNode );
2231  aInsPos.nContent.Assign( pCNd, pCNd ? pCNd->Len() : 0 );
2232 
2233  // All, that are in the to-be-deleted Node, need to be
2234  // moved to the next Node
2236  {
2237  SwPosition* pPos = &pTmp->GetBound();
2238  if( pPos->nNode == aIdx )
2239  {
2240  ++pPos->nNode;
2241  pPos->nContent.Assign( pPos->nNode.GetNode().GetContentNode(),0);
2242  }
2243  pPos = &pTmp->GetBound(false);
2244  if( pPos->nNode == aIdx )
2245  {
2246  ++pPos->nNode;
2247  pPos->nContent.Assign( pPos->nNode.GetNode().GetContentNode(),0);
2248  }
2249  }
2250  CorrRel( aIdx, aInsPos );
2251 
2252  if (pCNd)
2253  pCNd->JoinNext();
2254  }
2255 
2256  ++rOrigPam.GetPoint()->nNode;
2257  rOrigPam.GetPoint()->nContent.Assign( rOrigPam.GetContentNode(), 0 );
2258  assert(*aPam.GetMark() < *aPam.GetPoint());
2259  if (aPam.GetPoint()->nNode.GetNode().IsEndNode())
2260  { // ensure redline ends on content node
2261  --aPam.GetPoint()->nNode;
2262  assert(aPam.GetPoint()->nNode.GetNode().IsTextNode());
2263  SwTextNode *const pNode(aPam.GetPoint()->nNode.GetNode().GetTextNode());
2264  aPam.GetPoint()->nContent.Assign(pNode, pNode->Len());
2265  }
2266 
2268  if (GetIDocumentUndoRedo().DoesUndo())
2269  {
2270  // this should no longer happen in calls from the UI but maybe via API
2271  SAL_WARN_IF((eOld & RedlineFlags::ShowMask) != RedlineFlags::ShowMask,
2272  "sw.core", "redlines will be moved in DeleteAndJoin");
2273 
2277  std::make_unique<SwUndoRedlineDelete>(aPam, SwUndoId::DELETE));
2278  }
2279 
2280  SwRangeRedline* pNewRedline = new SwRangeRedline( RedlineType::Delete, aPam );
2281 
2282  // prevent assertion from aPam's target being deleted
2283  // (Alternatively, one could just let aPam go out of scope, but
2284  // that requires touching a lot of code.)
2285  aPam.GetBound().nContent.Assign( nullptr, 0 );
2286  aPam.GetBound(false).nContent.Assign( nullptr, 0 );
2287 
2288  getIDocumentRedlineAccess().AppendRedline( pNewRedline, true );
2289 
2291  aPam.GetBound(false).nContent.Assign(aPam.GetBound(false).nNode.GetNode().GetContentNode(), 0);
2293 
2294  // avoid setting empty nodes to tracked insertion
2295  if ( bIsEmptyNode )
2296  {
2298  SwRedlineTable::size_type nRedlPosWithEmpty =
2299  getIDocumentRedlineAccess().GetRedlinePos( pStt->nNode.GetNode(), RedlineType::Insert );
2300  if ( SwRedlineTable::npos != nRedlPosWithEmpty )
2301  {
2302  pOwnRedl = rTable[nRedlPosWithEmpty];
2303  SwPosition *pRPos = nOffset < SwNodeOffset(0) ? pOwnRedl->End() : pOwnRedl->Start();
2304  SwNodeIndex aIdx2 ( pRPos->nNode );
2305  SwTextNode const*const pEmptyNode0(aIdx2.GetNode().GetTextNode());
2306  if ( nOffset < SwNodeOffset(0) )
2307  {
2308  // move up
2309  --aIdx2;
2310  SwTextNode const*const pEmptyNode(aIdx2.GetNode().GetTextNode());
2311  if ( pEmptyNode && pEmptyNode->Len() == 0 )
2312  {
2313  --(pRPos->nNode);
2314  pRPos->nContent.Assign( aIdx2.GetNode().GetContentNode(), 0 );
2315  }
2316  }
2317  else if ( pEmptyNode0 && pEmptyNode0->Len() == 0 )
2318  {
2319  // move down
2320  ++aIdx2;
2321  SwTextNode const*const pEmptyNode(aIdx2.GetNode().GetTextNode());
2322  if (pEmptyNode)
2323  {
2324  ++(pRPos->nNode);
2325  pRPos->nContent.Assign( aIdx2.GetNode().GetContentNode(), 0 );
2326  }
2327  }
2328 
2329  // sort redlines, when the trimmed range results bad redline order
2330  if ( nRedlPosWithEmpty + 1 < rTable.size() &&
2331  *rTable[nRedlPosWithEmpty + 1] < *rTable[nRedlPosWithEmpty] )
2332  {
2333  rTable.Remove(nRedlPosWithEmpty);
2334  rTable.Insert(pOwnRedl);
2335  }
2336  }
2337  }
2338 
2342 
2343  return true;
2344  }
2345  }
2346 
2347  if( !pOwnRedl && !getIDocumentRedlineAccess().IsIgnoreRedline() && !getIDocumentRedlineAccess().GetRedlineTable().empty() )
2348  {
2349  SwPaM aTemp(aIdx);
2351  }
2352 
2353  SwNodeOffset nRedlSttNd(0), nRedlEndNd(0);
2354  if( pOwnRedl )
2355  {
2356  const SwPosition *pRStt = pOwnRedl->Start(), *pREnd = pOwnRedl->End();
2357  nRedlSttNd = pRStt->nNode.GetIndex();
2358  nRedlEndNd = pREnd->nNode.GetIndex();
2359  }
2360 
2361  std::unique_ptr<SwUndoMoveNum> pUndo;
2362  SwNodeOffset nMoved(0);
2363  if (GetIDocumentUndoRedo().DoesUndo())
2364  {
2365  pUndo.reset(new SwUndoMoveNum( rPam, nOffset, bIsOutlMv ));
2366  nMoved = rPam.End()->nNode.GetIndex() - rPam.Start()->nNode.GetIndex() + 1;
2367  }
2368 
2369  (void) pLayout; // note: move will insert between aIdx-1 and aIdx
2370  assert(!pLayout // check not moving *into* delete redline (caller's fault)
2374 
2375  if( pUndo )
2376  {
2377  // i57907: Under circumstances (sections at the end of a chapter)
2378  // the rPam.Start() is not moved to the new position.
2379  // But aIdx should be at the new end position and as long as the
2380  // number of moved paragraphs is nMoved, I know, where the new
2381  // position is.
2382  pUndo->SetStartNode( aIdx.GetIndex() - nMoved );
2383  GetIDocumentUndoRedo().AppendUndo(std::move(pUndo));
2384  }
2385 
2386  if( pOwnRedl )
2387  {
2388  SwPosition *pRStt = pOwnRedl->Start(), *pREnd = pOwnRedl->End();
2389  if( pRStt->nNode.GetIndex() != nRedlSttNd )
2390  {
2391  pRStt->nNode = nRedlSttNd;
2392  pRStt->nContent.Assign( pRStt->nNode.GetNode().GetContentNode(),0);
2393  }
2394  if( pREnd->nNode.GetIndex() != nRedlEndNd )
2395  {
2396  pREnd->nNode = nRedlEndNd;
2397  SwContentNode* pCNd = pREnd->nNode.GetNode().GetContentNode();
2398  pREnd->nContent.Assign( pCNd, pCNd ? pCNd->Len() : 0 );
2399  }
2400  }
2401 
2403  return true;
2404 }
2405 
2406 bool SwDoc::NumOrNoNum( const SwNodeIndex& rIdx, bool bDel )
2407 {
2408  bool bResult = false;
2409  SwTextNode * pTextNd = rIdx.GetNode().GetTextNode();
2410 
2411  if (pTextNd && pTextNd->GetNumRule() != nullptr &&
2412  (pTextNd->HasNumber() || pTextNd->HasBullet()))
2413  {
2414  if ( !pTextNd->IsCountedInList() == !bDel)
2415  {
2416  bool bOldNum = bDel;
2417  bool bNewNum = !bDel;
2418  pTextNd->SetCountedInList(bNewNum);
2419 
2421 
2422  bResult = true;
2423 
2424  if (GetIDocumentUndoRedo().DoesUndo())
2425  {
2427  std::make_unique<SwUndoNumOrNoNum>(rIdx, bOldNum, bNewNum));
2428  }
2429  }
2430  else if (bDel && pTextNd->GetNumRule(false) &&
2431  pTextNd->GetActualListLevel() >= 0 &&
2432  pTextNd->GetActualListLevel() < MAXLEVEL)
2433  {
2434  SwPaM aPam(*pTextNd);
2435  DelNumRules(aPam);
2436 
2437  bResult = true;
2438  }
2439  }
2440 
2441  return bResult;
2442 }
2443 
2445  SwRootFrame const*const pLayout)
2446 {
2447  SwNumRule* pRet = nullptr;
2448  SwTextNode* pTNd = rPos.nNode.GetNode().GetTextNode();
2449 
2450  if ( pTNd != nullptr )
2451  {
2452  if (pLayout && !sw::IsParaPropsNode(*pLayout, *pTNd))
2453  {
2454  pTNd = static_cast<SwTextFrame*>(pTNd->getLayoutFrame(pLayout))->GetMergedPara()->pParaPropsNode;
2455  rPos.nNode = *pTNd;
2456  rPos.nContent.Assign(pTNd, 0);
2457  }
2458  pRet = pTNd->GetNumRule();
2459  }
2460 
2461  return pRet;
2462 }
2463 
2464 sal_uInt16 SwDoc::FindNumRule( std::u16string_view rName ) const
2465 {
2466  for( sal_uInt16 n = mpNumRuleTable->size(); n; )
2467  if( (*mpNumRuleTable)[ --n ]->GetName() == rName )
2468  return n;
2469 
2470  return USHRT_MAX;
2471 }
2472 
2473 SwNumRule* SwDoc::FindNumRulePtr( const OUString& rName ) const
2474 {
2475  SwNumRule * pResult = maNumRuleMap[rName];
2476 
2477  if ( !pResult )
2478  {
2479  for (size_t n = 0; n < mpNumRuleTable->size(); ++n)
2480  {
2481  if ((*mpNumRuleTable)[n]->GetName() == rName)
2482  {
2483  pResult = (*mpNumRuleTable)[n];
2484 
2485  break;
2486  }
2487  }
2488  }
2489 
2490  return pResult;
2491 }
2492 
2494 {
2495  if ((SAL_MAX_UINT16 - 1) <= mpNumRuleTable->size())
2496  {
2497  OSL_ENSURE(false, "SwDoc::AddNumRule: table full.");
2498  abort(); // this should never happen on real documents
2499  }
2500  mpNumRuleTable->push_back(pRule);
2501  maNumRuleMap[pRule->GetName()] = pRule;
2502  pRule->SetNumRuleMap(&maNumRuleMap);
2503 
2505 }
2506 
2507 sal_uInt16 SwDoc::MakeNumRule( const OUString &rName,
2508  const SwNumRule* pCpy,
2509  bool bBroadcast,
2510  const SvxNumberFormat::SvxNumPositionAndSpaceMode eDefaultNumberFormatPositionAndSpaceMode )
2511 {
2512  SwNumRule* pNew;
2513  if( pCpy )
2514  {
2515  pNew = new SwNumRule( *pCpy );
2516 
2518 
2519  if( pNew->GetName() != rName )
2520  {
2521  pNew->SetPoolFormatId( USHRT_MAX );
2522  pNew->SetPoolHelpId( USHRT_MAX );
2523  pNew->SetPoolHlpFileId( UCHAR_MAX );
2524  pNew->SetDefaultListId( OUString() );
2525  }
2526  pNew->CheckCharFormats( *this );
2527  }
2528  else
2529  {
2530  pNew = new SwNumRule( GetUniqueNumRuleName( &rName ),
2531  eDefaultNumberFormatPositionAndSpaceMode );
2532  }
2533 
2534  sal_uInt16 nRet = mpNumRuleTable->size();
2535 
2536  AddNumRule(pNew);
2537 
2538  if (GetIDocumentUndoRedo().DoesUndo())
2539  {
2541  std::make_unique<SwUndoNumruleCreate>(pNew, *this));
2542  }
2543 
2544  if (bBroadcast)
2545  BroadcastStyleOperation(pNew->GetName(), SfxStyleFamily::Pseudo,
2546  SfxHintId::StyleSheetCreated);
2547 
2548  return nRet;
2549 }
2550 
2551 OUString SwDoc::GetUniqueNumRuleName( const OUString* pChkStr, bool bAutoNum ) const
2552 {
2553  // If we got pChkStr, then the caller expects that in case it's not yet
2554  // used, it'll be returned.
2555  if( IsInMailMerge() && !pChkStr )
2556  {
2557  OUString newName = "MailMergeNumRule"
2558  + OStringToOUString( DateTimeToOString( DateTime( DateTime::SYSTEM )), RTL_TEXTENCODING_ASCII_US )
2559  + OUString::number( mpNumRuleTable->size() + 1 );
2560  return newName;
2561  }
2562 
2563  OUString aName;
2564  if( bAutoNum )
2565  {
2566  static bool bHack = (getenv("LIBO_ONEWAY_STABLE_ODF_EXPORT") != nullptr);
2567 
2568  if (bHack)
2569  {
2570  static sal_Int64 nIdCounter = SAL_CONST_INT64(8000000000);
2571  aName = OUString::number(nIdCounter++);
2572  }
2573  else
2574  {
2575  unsigned int const n(comphelper::rng::uniform_uint_distribution(0,
2576  std::numeric_limits<unsigned int>::max()));
2577  aName = OUString::number(n);
2578  }
2579  if( pChkStr && pChkStr->isEmpty() )
2580  pChkStr = nullptr;
2581  }
2582  else if( pChkStr && !pChkStr->isEmpty() )
2583  aName = *pChkStr;
2584  else
2585  {
2586  pChkStr = nullptr;
2587  aName = SwResId( STR_NUMRULE_DEFNAME );
2588  }
2589 
2590  sal_uInt16 nNum(0), nTmp, nFlagSize = ( mpNumRuleTable->size() / 8 ) +2;
2591  std::unique_ptr<sal_uInt8[]> pSetFlags(new sal_uInt8[ nFlagSize ]);
2592  memset( pSetFlags.get(), 0, nFlagSize );
2593 
2594  sal_Int32 nNmLen = aName.getLength();
2595  if( !bAutoNum && pChkStr )
2596  {
2597  while( nNmLen-- && '0' <= aName[nNmLen] && aName[nNmLen] <= '9' )
2598  ; //nop
2599 
2600  if( ++nNmLen < aName.getLength() )
2601  {
2602  aName = aName.copy(0, nNmLen );
2603  pChkStr = nullptr;
2604  }
2605  }
2606 
2607  for( auto const & pNumRule: *mpNumRuleTable )
2608  if( nullptr != pNumRule )
2609  {
2610  const OUString sNm = pNumRule->GetName();
2611  if( sNm.startsWith( aName ) )
2612  {
2613  // Determine Number and set the Flag
2614  nNum = o3tl::narrowing<sal_uInt16>(o3tl::toInt32(sNm.subView( nNmLen )));
2615  if( nNum-- && nNum < mpNumRuleTable->size() )
2616  pSetFlags[ nNum / 8 ] |= (0x01 << ( nNum & 0x07 ));
2617  }
2618  if( pChkStr && *pChkStr==sNm )
2619  pChkStr = nullptr;
2620  }
2621 
2622  if( !pChkStr )
2623  {
2624  // All Numbers have been flagged accordingly, so identify the right Number
2625  nNum = mpNumRuleTable->size();
2626  for( sal_uInt16 n = 0; n < nFlagSize; ++n )
2627  {
2628  nTmp = pSetFlags[ n ];
2629  if( 0xff != nTmp )
2630  {
2631  // identify the Number
2632  nNum = n * 8;
2633  while( nTmp & 1 )
2634  {
2635  ++nNum;
2636  nTmp >>= 1;
2637  }
2638  break;
2639  }
2640  }
2641  }
2642  if( pChkStr && !pChkStr->isEmpty() )
2643  return *pChkStr;
2644  return aName + OUString::number( ++nNum );
2645 }
2646 
2648 {
2649  const SwNumRuleTable& rNmTable = GetNumRuleTable();
2650  for( size_t n = 0; n < rNmTable.size(); ++n )
2651  if( rNmTable[ n ]->IsInvalidRule() )
2652  rNmTable[ n ]->Validate(*this);
2653 }
2654 
2655 void SwDoc::MarkListLevel( const OUString& sListId,
2656  const int nListLevel,
2657  const bool bValue )
2658 {
2659  SwList* pList = getIDocumentListsAccess().getListByName( sListId );
2660 
2661  if ( pList )
2662  {
2663  // Set new marked list level and notify all affected nodes of the changed mark.
2664  pList->MarkListLevel( nListLevel, bValue );
2665  }
2666 }
2667 
2669  SwRootFrame const& rLayout)
2670 {
2671  bool bResult = false;
2672 
2673  const SwTextNode *const pTextNode = sw::GetParaPropsNode(rLayout, rPos.nNode);
2674  if ( pTextNode != nullptr )
2675  {
2676  bResult = pTextNode->IsFirstOfNumRule(rLayout);
2677  }
2678 
2679  return bResult;
2680 }
2681 
2682 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const SwEndNode * EndOfSectionNode() const
Definition: node.hxx:692
Starts a section of nodes in the document model.
Definition: node.hxx:313
Represents the visualization of a paragraph.
Definition: txtfrm.hxx:159
virtual sal_Int32 Len() const
Definition: node.cxx:1243
SwHistory * GetHistory()
void DeleteMark()
Definition: pam.hxx:178
void SetListRestart(bool bRestart)
Definition: ndtxt.cxx:4146
bool IsInMailMerge() const
Definition: doc.hxx:959
bool IsUsed(const sw::BroadcastingModify &) const
Definition: poolfmt.cxx:86
int GetAssignedOutlineStyleLevel() const
Definition: fmtcol.cxx:604
bool HasBullet() const
Returns if this text node has a bullet.
Definition: ndtxt.cxx:3142
Represents the style of a paragraph.
Definition: fmtcol.hxx:56
void SaveOldNumRule(const SwNumRule &rOld)
Definition: unnum.cxx:149
Marks a position in the document model.
Definition: pam.hxx:36
void UpdateFramesForAddDeleteRedline(SwDoc &rDoc, SwPaM const &rPam)
void ChkCondColls()
Definition: doc.cxx:1787
bool IsSectionNode() const
Definition: node.hxx:654
const SwNodeNum * GetNum(SwRootFrame const *pLayout=nullptr) const
Definition: ndtxt.cxx:3994
SwComparePosition ComparePosition(const T &rStt1, const T &rEnd1, const T &rStt2, const T &rEnd2)
Definition: pam.hxx:78
virtual void deleteListsByDefaultListStyle(const OUString &rListStyleName)=0
void SetAutoRule(bool bFlag)
Definition: numrule.hxx:230
virtual bool SetAttr(const SfxPoolItem &) override
overriding to handle change of certain paragraph attributes
Definition: ndtxt.cxx:4885
virtual void createListForListStyle(const OUString &rListStyleName)=0
virtual AppendResult AppendRedline(SwRangeRedline *pNewRedl, bool bCallDelete)=0
Append a new redline.
signed char sal_Int8
const SwNumFormat * GetNumFormat(sal_uInt16 i) const
Definition: number.cxx:96
SwNodeIndex nNode
Definition: pam.hxx:38
static bool lcl_IsValidPrevNextNumNode(const SwNodeIndex &rIdx)
Definition: docnum.cxx:1417
void AddToList()
Definition: ndtxt.cxx:4306
bool isdigitAsciiString(std::string_view rString)
std::vector< SwNode * >::difference_type difference_type
void SetPoolHlpFileId(sal_uInt8 nId)
Definition: numrule.hxx:257
SVX_NUM_NUMBER_NONE
virtual sal_Int32 Len() const override
Definition: ndtxt.cxx:277
virtual void SetModified()=0
Must be called manually at changes of format.
virtual SwList * createList(const OUString &rListId, const OUString &rDefaultListStyleName)=0
constexpr TypedWhichId< SwNumRuleItem > RES_PARATR_NUMRULE(72)
Pos1 is as large as Pos2.
const SwPosition * GetMark() const
Definition: pam.hxx:210
const OUString & GetDefaultListId() const
Definition: numrule.hxx:194
constexpr TypedWhichId< SfxInt16Item > RES_PARATR_LIST_RESTARTVALUE(85)
Definition: list.hxx:32
bool IsAutoRule() const
Definition: numrule.hxx:229
bool NumOrNoNum(const SwNodeIndex &rIdx, bool bDel=false)
Definition: docnum.cxx:2406
Pos1 completely contained in Pos2.
SwContentFrame * getLayoutFrame(const SwRootFrame *, const SwPosition *pPos=nullptr, std::pair< Point, bool > const *pViewPosAndCalcFrame=nullptr) const
Definition: node.cxx:1210
bool MoveOutlinePara(const SwPaM &rPam, SwOutlineNodes::difference_type nOffset)
Outline - move up / move down.
Definition: docnum.cxx:451
sal_Int64 n
void Remove(size_type nPos)
Definition: docredln.cxx:643
virtual SwUndoId EndUndo(SwUndoId const eUndoId, SwRewriter const *const pRewriter)=0
Closes undo block.
OUString GetListId() const
Definition: ndtxt.cxx:4413
Definition: doc.hxx:187
TElementType * Next()
Definition: calbck.hxx:364
constexpr sal_uInt8 MAXLEVEL
Definition: swtypes.hxx:92
void SetContinusNum(bool bFlag)
Definition: numrule.hxx:236
SwSectionNode is derived from SwStartNode.
std::basic_string_view< charT, traits > getToken(std::basic_string_view< charT, traits > sv, charT delimiter, std::size_t &position)
static SwContentNode * GoPrevious(SwNodeIndex *)
Definition: nodes.cxx:1317
static SwTextNode * lcl_FindOutlineName(const SwOutlineNodes &rOutlNds, SwRootFrame const *const pLayout, const OUString &rName, bool const bExact)
Definition: docnum.cxx:600
SwNode & GetNode() const
Definition: ndindex.hxx:119
void SetNumRuleStart(const SwPosition &rPos, bool bFlag=true)
Definition: docnum.cxx:1016
OUString newName(std::u16string_view aNewPrefix, const OUString &aOldPrefix, std::u16string_view old_Name)
const OUString & GetName() const
Definition: numrule.hxx:224
OUString GetUniqueNumRuleName(const OUString *pChkStr=nullptr, bool bAutoNum=true) const
Definition: docnum.cxx:2551
SwNumberTree::tNumberVector GetNumberVector() const
Returns level numbers of this node.
constexpr TypedWhichId< SwConditionTextFormatColl > RES_CONDTXTFMTCOLL(160)
SwPosition & GetBound(bool bOne=true)
Definition: pam.hxx:246
Dialog to specify the properties of date form field.
IDocumentUndoRedo & GetIDocumentUndoRedo()
Definition: doc.cxx:144
virtual bool InsertPoolItem(const SwPaM &rRg, const SfxPoolItem &, const SetAttrMode nFlags=SetAttrMode::DEFAULT, SwRootFrame const *pLayout=nullptr, SwTextAttr **ppNewTextAttr=nullptr)=0
Insert an attribute.
bool NumUpDown(const SwPaM &, bool bDown, SwRootFrame const *pLayout=nullptr)
Definition: docnum.cxx:1709
std::unordered_map< OUString, SwNumRule * > maNumRuleMap
Definition: doc.hxx:272
SwNodeOffset abs(const SwNodeOffset &a)
Definition: nodeoffset.hxx:34
void UpdateOutlineIdx(const SwNode &)
Update all OutlineNodes starting from Node.
Definition: ndnum.cxx:77
IDocumentContentOperations const & getIDocumentContentOperations() const
Definition: doc.cxx:315
bool HasNumber(SwRootFrame const *pLayout=nullptr) const
Returns if this text node has a number.
Definition: ndtxt.cxx:3126
bool IsListRestart() const
Definition: ndtxt.cxx:4162
The root element of a Writer document layout.
Definition: rootfrm.hxx:81
int GetActualListLevel() const
Returns the actual list level of this text node, when it is a list item.
Definition: ndtxt.cxx:4139
int GetAttrOutlineLevel() const
Returns outline level of this text node.
Definition: ndtxt.cxx:4059
constexpr TypedWhichId< SfxBoolItem > RES_PARATR_LIST_ISRESTART(84)
unsigned int uniform_uint_distribution(unsigned int a, unsigned int b)
show all inserts
size_type size() const
Definition: docary.hxx:267
const OUString & GetListId() const
Definition: list.hxx:40
SwContentNode * GetContentNode(bool bPoint=true) const
Definition: pam.hxx:230
virtual void UpdateExpFields(SwTextField *pField, bool bUpdateRefFields)=0
OUString SwResId(TranslateId aId)
Definition: swmodule.cxx:164
Pos1 end touches at Pos2 start.
IDocumentFieldsAccess const & getIDocumentFieldsAccess() const
Definition: doc.cxx:357
bool IsOwnRedline(const SwRangeRedline &rRedl) const
Definition: redline.hxx:247
sal_uInt16 sal_Unicode
bool IsAssignedToListLevelOfOutlineStyle() const
Definition: fmtcol.hxx:120
SwNodeType GetNodeType() const
Definition: node.hxx:146
SwIndex nContent
Definition: pam.hxx:39
constexpr TypedWhichId< SfxInt16Item > RES_PARATR_LIST_LEVEL(83)
#define SAL_MAX_UINT16
static SwNumRule * GetNumRuleAtPos(SwPosition &rPos, SwRootFrame const *pLayout=nullptr)
Definition: docnum.cxx:2444
void ResetAttrs(const SwPaM &rRg, bool bTextAttr=true, const o3tl::sorted_vector< sal_uInt16 > &rAttrs=o3tl::sorted_vector< sal_uInt16 >(), const bool bSendDataChangedEvents=true, SwRootFrame const *pLayout=nullptr)
Reset attributes.
Definition: docfmt.cxx:242
bool NoNum(const SwPaM &)
Definition: docnum.cxx:1299
IDocumentStylePoolAccess const & getIDocumentStylePoolAccess() const
Definition: doc.cxx:426
check if target position is in fly anchored at source range
std::unique_ptr< SwNumRuleTable > mpNumRuleTable
Definition: doc.hxx:269
int nCount
static sal_uInt8 GetUpperLvlChg(sal_uInt8 nCurLvl, sal_uInt8 nLevel, sal_uInt16 nMask)
Definition: docnum.cxx:104
void PropagateOutlineRule()
Definition: docnum.cxx:180
bool IsStartNode() const
Definition: node.hxx:634
Pos2 completely contained in Pos1.
void MarkListLevel(const int nListLevel, const bool bValue)
Definition: list.cxx:123
o3tl::sorted_vector< SwRootFrame * > GetAllLayouts()
Definition: doclay.cxx:1668
SwNodeOffset GetIndex() const
Definition: ndindex.hxx:152
void SetCountedInList(bool bCounted)
Definition: ndtxt.cxx:4261
void GotoNextLayoutTextFrame(SwNodeIndex &rIndex, SwRootFrame const *const pLayout)
Definition: docnum.cxx:1474
Pos1 before Pos2.
void ChkCondColl(const SwTextFormatColl *pColl=nullptr)
Definition: node.cxx:1978
SwHistory * GetHistory()
Definition: unnum.cxx:142
RedlineFlags on.
bool RenameNumRule(const OUString &aOldName, const OUString &aNewName, bool bBroadcast=false)
Definition: docnum.cxx:1122
void SetNumRuleMap(std::unordered_map< OUString, SwNumRule * > *pNumRuleMap)
Register this rule in a "name->numrule" map.
Definition: number.cxx:162
bool MoveParagraph(SwPaM &, SwNodeOffset nOffset, bool bIsOutlMv=false)
Move selected paragraphs (not only numberings) according to offsets.
Definition: docnum.cxx:1825
size_type size() const
virtual bool DoesUndo() const =0
Is Undo enabled?
void SetPoolFormatId(sal_uInt16 nId)
Definition: numrule.hxx:251
const char * sName
SwNode & GetEndOfContent() const
Regular ContentSection (i.e. the BodyText).
Definition: ndarr.hxx:162
bool IsContinusNum() const
Definition: numrule.hxx:235
static SwTextNode * lcl_FindOutlineNum(const SwOutlineNodes &rOutlNds, OUString &rName, SwRootFrame const *const pLayout)
Definition: docnum.cxx:635
void SetCounted(const SwPaM &, bool bCounted, SwRootFrame const *pLayout)
Definition: docnum.cxx:1001
void DelNumRules(const SwPaM &, SwRootFrame const *pLayout=nullptr)
Definition: docnum.cxx:1322
void SetNodeNumStart(const SwPosition &rPos, sal_uInt16 nStt)
Definition: docnum.cxx:1038
bool IsContentNode() const
Definition: node.hxx:638
PaM is Point and Mark: a selection of the document model.
Definition: pam.hxx:137
const SwAttrSet * GetpSwAttrSet() const
Definition: node.hxx:457
bool Move(SwMoveFnCollection const &fnMove=fnMoveForward, SwGoInDoc fnGo=GoInContent)
Movement of cursor.
Definition: pam.cxx:502
virtual SwRedlineTable::size_type GetRedlinePos(const SwNode &rNode, RedlineType nType) const =0
sal_uInt16 FindNumRule(std::u16string_view rName) const
Definition: docnum.cxx:2464
std::unique_ptr< SwTextFormatColls > mpTextFormatCollTable
Definition: doc.hxx:244
SwNumRule * FindNumRulePtr(const OUString &rName) const
Definition: docnum.cxx:2473
virtual SwList * getListByName(const OUString &rListId) const =0
virtual void AppendUndo(std::unique_ptr< SwUndo > pUndo)=0
Add new Undo action.
void AddNumRule(SwNumRule *pRule)
Add numbering rule to document.
Definition: docnum.cxx:2493
SwNodeIndex & Assign(SwNodes const &rNds, SwNodeOffset)
Definition: ndindex.hxx:272
virtual SwUndoId StartUndo(SwUndoId const eUndoId, SwRewriter const *const pRewriter)=0
Opens undo block.
void MakeUniqueNumRules(const SwPaM &rPaM)
Definition: docnum.cxx:1235
void CheckCharFormats(SwDoc &rDoc)
Tests whether the CharFormats are from the given doc and copies them if appropriate.
Definition: number.cxx:526
SfxItemState GetItemState(sal_uInt16 nWhich, bool bSrchInParent=true, const SfxPoolItem **ppItem=nullptr) const
int i
uno_Any a
static bool lcl_IsNumOk(sal_uInt8 nSrchNum, sal_uInt8 &rLower, sal_uInt8 &rUpper, bool bOverUpper, sal_uInt8 nNumber)
Definition: docnum.cxx:1399
const SwStartNode * StartOfSectionNode() const
Definition: node.hxx:133
const SwPosition * GetPoint() const
Definition: pam.hxx:208
virtual bool CopyRange(SwPaM &rPam, SwPosition &rPos, SwCopyFlags flags) const =0
Copy a selected content range to a position.
Pos1 start touches at Pos2 end.
SwIndex & Assign(SwIndexReg *, sal_Int32)
Definition: index.cxx:206
void SetAttrOutlineLevel(int nLevel)
Sets the out line level at a text node.
Definition: ndtxt.cxx:4064
TElementType * First()
Definition: calbck.hxx:356
SwContentNode * GetContentNode()
Definition: node.hxx:625
SwNodeOffset GetIndex() const
Definition: node.hxx:292
vector_type::size_type size_type
Definition: docary.hxx:222
const OUString & GetValue() const
bool HasMark() const
A PaM marks a selection if Point and Mark are distinct positions.
Definition: pam.hxx:206
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
void UpdateNumRule()
Definition: docnum.cxx:2647
bool IsEnumeration() const
Definition: number.cxx:236
static bool lcl_GotoNextPrevNum(SwPosition &rPos, bool bNext, bool bOverUpper, sal_uInt8 *pUpper, sal_uInt8 *pLower, SwRootFrame const *const pLayout)
Definition: docnum.cxx:1502
size_t size() const
Definition: docary.hxx:87
virtual SwFormatColl * ChgFormatColl(SwFormatColl *) override
Definition: ndtxt.cxx:3959
static OUString GetOutlineRuleName()
Definition: number.cxx:81
void SetRuleType(SwNumRuleType eNew)
Definition: numrule.hxx:212
SwNumRule * GetNumRule(bool bInParent=true) const
Returns numbering rule of this text node.
Definition: ndtxt.cxx:2833
IDocumentState const & getIDocumentState() const
Definition: doc.cxx:394
virtual void deleteListForListStyle(const OUString &rListStyleName)=0
bool IsItemize() const
Definition: number.cxx:244
size
SwNumRule * mpOutlineRule
Definition: doc.hxx:253
void SetPoolHelpId(sal_uInt16 nId)
Definition: numrule.hxx:255
Marks a node in the document model.
Definition: ndindex.hxx:30
bool IsEndNode() const
Definition: node.hxx:642
const SwOutlineNodes & GetOutLineNds() const
Array of all OutlineNodes.
Definition: ndarr.hxx:230
void GetTextNodeList(SwNumRule::tTextNodeList &rTextNodeList) const
Definition: number.cxx:130
sal_Int32 toInt32(std::u16string_view str, sal_Int16 radix=10)
SwStartNodeType GetStartNodeType() const
Definition: node.hxx:330
bool empty() const
SvxNumPositionAndSpaceMode GetPositionAndSpaceMode() const
virtual bool MoveNodeRange(SwNodeRange &, SwNodeIndex &, SwMoveFlags)=0
show all deletes
const SwPosition * Start() const
Definition: pam.hxx:213
const SwNumRuleItem & GetNumRule(bool=true) const
Definition: paratr.hxx:232
void SetOutlineNumRule(const SwNumRule &rRule)
Definition: docnum.cxx:116
SwTextNode * GetParaPropsNode(SwRootFrame const &rLayout, SwNodeIndex const &rNode)
Definition: txtfrm.cxx:330
virtual const SwRangeRedline * GetRedline(const SwPosition &rPos, SwRedlineTable::size_type *pFndPos) const =0
std::vector< tSwNumTreeNumber > tNumberVector
sal_uInt16 Which() const
for Querying of Writer-functions.
Definition: format.hxx:82
void CorrRel(const SwNodeIndex &rOldNode, const SwPosition &rNewPos, const sal_Int32 nOffset=0, bool bMoveCursor=false)
Definition: doccorr.cxx:305
const SwNumFormat & Get(sal_uInt16 i) const
Definition: number.cxx:86
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:79
virtual bool SplitRedline(const SwPaM &rPam)=0
void SetAttrListLevel(int nLevel)
Sets the list level of this text node.
Definition: ndtxt.cxx:4109
IDocumentRedlineAccess const & getIDocumentRedlineAccess() const
Definition: doc.cxx:335
void Set(sal_uInt16 i, const SwNumFormat *)
Definition: number.cxx:617
void SetInvalidRule(bool bFlag)
Definition: number.cxx:957
OUString GetExpandText(SwRootFrame const *pLayout, const sal_Int32 nIdx=0, const sal_Int32 nLen=-1, const bool bWithNum=false, const bool bAddSpaceAfterListLabelStr=false, const bool bWithSpacesForLevel=false, const ExpandMode eAdditionalMode=ExpandMode::ExpandFootnote) const
add 4th optional parameter indicating, when that a spa...
Definition: ndtxt.cxx:3412
bool GotoOutline(SwPosition &rPos, const OUString &rName, SwRootFrame const *=nullptr) const
Definition: docnum.cxx:737
void StopNumRuleAnimations(const OutputDevice *)
Definition: docnum.cxx:1160
#define SAL_WARN_IF(condition, area, stream)
static void lcl_ChgNumRule(SwDoc &rDoc, const SwNumRule &rRule)
Definition: docnum.cxx:802
SwNumberTree::tSwNumTreeNumber GetAttrListRestartValue() const
Definition: ndtxt.cxx:4215
void SetDefaultListId(const OUString &sDefaultListId)
Definition: numrule.hxx:190
Pos1 overlaps Pos2 at the end.
unsigned char sal_uInt8
const SwNodes & GetNodes() const
Definition: ndindex.hxx:156
void MarkListLevel(const OUString &sListId, const int nListLevel, const bool bValue)
Marks/Unmarks a list level of a certain list.
Definition: docnum.cxx:2655
void ReplaceNumRule(const SwPosition &rPos, const OUString &rOldRule, const OUString &rNewRule)
Definition: docnum.cxx:1179
const SwNumRuleTable & GetNumRuleTable() const
Definition: doc.hxx:1065
virtual void SetRedlineFlags(RedlineFlags eMode)=0
Set a new redline mode.
OUString aName
sal_Int32 GetIndex() const
Definition: index.hxx:91
OString DateTimeToOString(const DateTime &rDateTime)
bool IsCountedInList() const
Definition: ndtxt.cxx:4276
constexpr TypedWhichId< SfxBoolItem > RES_PARATR_LIST_ISCOUNTED(86)
SwNodes & GetNodes()
Definition: doc.hxx:408
virtual SwTextFormatColl * GetTextCollFromPool(sal_uInt16 nId, bool bRegardLanguage=true)=0
Return "Auto-Collection with ID.
const SwPosition * End() const
Definition: pam.hxx:218
SwNodeIndex aEnd
Definition: ndindex.hxx:133
RedlineType GetType(sal_uInt16 nPos=0) const
Definition: docredln.cxx:1929
static bool GotoNextNum(SwPosition &, SwRootFrame const *pLayout, bool bOverUpper=true, sal_uInt8 *pUpper=nullptr, sal_uInt8 *pLower=nullptr)
Definition: docnum.cxx:1617
sal_uInt16 MakeNumRule(const OUString &rName, const SwNumRule *pCpy=nullptr, bool bBroadcast=false, const SvxNumberFormat::SvxNumPositionAndSpaceMode eDefaultNumberFormatPositionAndSpaceMode=SvxNumberFormat::LABEL_WIDTH_AND_POSITION)
Definition: docnum.cxx:2507
constexpr TypedWhichId< SvxLRSpaceItem > RES_LR_SPACE(91)
bool IsFirstOfNumRule(SwRootFrame const &rLayout) const
Definition: ndtxt.cxx:4384
o3tl::strong_int< sal_Int32, struct Tag_SwNodeOffset > SwNodeOffset
Definition: nodeoffset.hxx:16
bool IsParaPropsNode(SwRootFrame const &rLayout, SwTextNode const &rNode)
Definition: txtfrm.cxx:313
virtual SwContentNode * JoinNext()
Definition: node.cxx:1532
static bool IsFirstOfNumRuleAtPos(const SwPosition &rPos, SwRootFrame const &rLayout)
Definition: docnum.cxx:2668
static bool GotoPrevNum(SwPosition &, SwRootFrame const *pLayout, bool bOverUpper=true)
Definition: docnum.cxx:1703
std::vector< SwTextNode * > tTextNodeList
Definition: numrule.hxx:97
virtual bool AppendTextNode(SwPosition &rPos)=0
SwMoveFnCollection const & fnMoveBackward
Definition: paminit.cxx:58
SwTableNode * FindTableNode()
Search table node, in which it is.
Definition: node.cxx:358
SwNodeOffset Count() const
Definition: ndarr.hxx:141
void GotoPrevLayoutTextFrame(SwNodeIndex &rIndex, SwRootFrame const *const pLayout)
Definition: docnum.cxx:1444
virtual bool SplitNode(const SwPosition &rPos, bool bChkTableStart)=0
Split a node at rPos (implemented only for TextNode).
SwFootnoteIdxs & GetFootnoteIdxs()
Definition: doc.hxx:633
virtual RedlineFlags GetRedlineFlags() const =0
Query the currently set redline mode.
bool IsTableNode() const
Definition: node.hxx:650
SwFormatColl * GetFormatColl() const
Definition: node.hxx:461
bool IsInList() const
Definition: ndtxt.cxx:4379
SwDoc & GetDoc() const
Definition: pam.hxx:244
bool HasMergedParas() const
Definition: rootfrm.hxx:425
virtual void SetMark()
Unless this is called, the getter method of Mark will return Point.
Definition: pam.cxx:476
Pos1 behind Pos2.
bool DelNumRule(const OUString &rName, bool bBroadCast=false)
Definition: docnum.cxx:1060
bool Seek_Entry(SwNode *rP, size_type *pnPos) const
Definition: ndnum.cxx:32
tuple m
void InvalidateNumRules()
Definition: docnum.cxx:1392
void SetName(const OUString &rNm, IDocumentListsAccess &rDocListAccess)
Definition: number.cxx:110
virtual const SwRedlineTable & GetRedlineTable() const =0
bool Insert(SwRangeRedline *&p)
Definition: docredln.cxx:417
virtual bool ResetAttr(sal_uInt16 nWhich1, sal_uInt16 nWhich2=0) override
Definition: ndtxt.cxx:5119
std::vector< SwNode * >::size_type size_type
const SwNumRule * SearchNumRule(const SwPosition &rPos, const bool bForward, const bool bNum, const bool bOutline, int nNonEmptyAllowed, OUString &sListId, SwRootFrame const *pLayout, const bool bInvestigateStartNode=false)
Searches for a text node with a numbering rule.
Definition: docnum.cxx:1623
OUString SetNumRule(const SwPaM &, const SwNumRule &, bool bCreateNewList, SwRootFrame const *pLayout=nullptr, const OUString &sContinuedListId=OUString(), bool bSetItem=true, const bool bResetIndentAttrs=false)
Accept changes of outline styles for OutlineRule.
Definition: docnum.cxx:868
void UpdateAllFootnote()
Definition: ftnidx.cxx:267
void AddNode(const SwTextNode &rNd)
Definition: unnum.cxx:198
SwNode & GetEndOfExtras() const
This is the last EndNode of a special section.
Definition: ndarr.hxx:160
bool HasAttrListRestartValue() const
Definition: ndtxt.cxx:4210
IDocumentListsAccess const & getIDocumentListsAccess() const
Definition: doc.cxx:293
bool IsTextNode() const
Definition: node.hxx:646
static constexpr size_type npos
Definition: docary.hxx:223
bool MoveParagraphImpl(SwPaM &, SwNodeOffset nOffset, bool bIsOutlMv, SwRootFrame const *)
Definition: docnum.cxx:1936
Merge GetRedlineMergeFlag() const
Definition: node.hxx:99
bool OutlineUpDown(const SwPaM &rPam, short nOffset, SwRootFrame const *pLayout=nullptr)
Definition: docnum.cxx:203
const SwFootnoteInfo & GetFootnoteInfo() const
Definition: doc.hxx:629
void SetAttrListRestartValue(SwNumberTree::tSwNumTreeNumber nNum)
Definition: ndtxt.cxx:4189
Pos1 overlaps Pos2 at the beginning.
bool IsOutlineRule() const
Definition: numrule.hxx:241
void BroadcastStyleOperation(const OUString &rName, SfxStyleFamily eFamily, SfxHintId nOp)
Definition: docdesc.cxx:717
constexpr TypedWhichId< SfxStringItem > RES_PARATR_LIST_ID(RES_PARATR_LIST_BEGIN)
void SetLRSpaceEndPos()
Definition: unnum.cxx:119
sal_uInt16 nPos
std::pair< SwTextNode *, SwTextNode * > GetFirstAndLastNode(SwRootFrame const &rLayout, SwNodeIndex const &rPos)
Definition: txtfrm.cxx:357
SwTextNode * GetTextNode()
Inline methods from Node.hxx.
Definition: ndtxt.hxx:864
SwNumRule * GetOutlineNumRule() const
Definition: doc.hxx:1023
void ChgNumRuleFormats(const SwNumRule &rRule)
Definition: docnum.cxx:1100
bool m_bDetectedRangeSegmentation false
Base class of the Writer document model elements.
Definition: node.hxx:81
SwTextFormatColl * GetTextColl() const
Definition: ndtxt.hxx:858
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo