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