nss: upgrade to release 3.73
[LibreOffice.git] / sw / source / core / edit / ednumber.cxx
blob354e2782e20cebfa3c2798b9e274e83f1b93a39d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <editsh.hxx>
21 #include <edimp.hxx>
22 #include <doc.hxx>
23 #include <IDocumentUndoRedo.hxx>
24 #include <IDocumentState.hxx>
25 #include <ndtxt.hxx>
26 #include <txtfrm.hxx>
27 #include <swundo.hxx>
28 #include <numrule.hxx>
30 SwPamRanges::SwPamRanges( const SwPaM& rRing )
32 for(SwPaM& rTmp : const_cast<SwPaM*>(&rRing)->GetRingContainer())
33 Insert( rTmp.GetMark()->nNode, rTmp.GetPoint()->nNode );
36 void SwPamRanges::Insert( const SwNodeIndex& rIdx1, const SwNodeIndex& rIdx2 )
38 SwPamRange aRg( rIdx1.GetIndex(), rIdx2.GetIndex() );
39 if( aRg.nEnd < aRg.nStart )
40 { aRg.nStart = aRg.nEnd; aRg.nEnd = rIdx1.GetIndex(); }
42 o3tl::sorted_vector<SwPamRange>::const_iterator it = maVector.lower_bound(aRg); //search Insert Position
43 size_t nPos = it - maVector.begin();
44 if (!maVector.empty() && (it != maVector.end()) && (*it) == aRg)
46 // is the one in the Array smaller?
47 SwPamRange const& rTmp = maVector[nPos];
48 if( rTmp.nEnd < aRg.nEnd )
50 aRg.nEnd = rTmp.nEnd;
51 maVector.erase(maVector.begin() + nPos); // combine
53 else
54 return; // done, because by precondition everything is combined
57 bool bEnd;
58 do {
59 bEnd = true;
61 // combine with predecessor?
62 if( nPos > 0 )
64 SwPamRange const& rTmp = maVector[nPos-1];
65 if( rTmp.nEnd == aRg.nStart
66 || rTmp.nEnd+1 == aRg.nStart )
68 aRg.nStart = rTmp.nStart;
69 bEnd = false;
70 maVector.erase( maVector.begin() + --nPos ); // combine
72 // range contained in rTmp?
73 else if( rTmp.nStart <= aRg.nStart && aRg.nEnd <= rTmp.nEnd )
74 return;
76 // combine with successor?
77 if( nPos < maVector.size() )
79 SwPamRange const& rTmp = maVector[nPos];
80 if( rTmp.nStart == aRg.nEnd ||
81 rTmp.nStart == aRg.nEnd+1 )
83 aRg.nEnd = rTmp.nEnd;
84 bEnd = false;
85 maVector.erase( maVector.begin() + nPos ); // combine
88 // range contained in rTmp?
89 else if( rTmp.nStart <= aRg.nStart && aRg.nEnd <= rTmp.nEnd )
90 return;
92 } while( !bEnd );
94 maVector.insert( aRg );
97 SwPaM& SwPamRanges::SetPam( size_t nArrPos, SwPaM& rPam )
99 assert( nArrPos < Count() );
100 const SwPamRange& rTmp = maVector[ nArrPos ];
101 rPam.GetPoint()->nNode = rTmp.nStart;
102 rPam.GetPoint()->nContent.Assign( rPam.GetContentNode(), 0 );
103 rPam.SetMark();
104 rPam.GetPoint()->nNode = rTmp.nEnd;
105 rPam.GetPoint()->nContent.Assign( rPam.GetContentNode(), 0 );
106 return rPam;
109 // Rule book for outline numbering
111 void SwEditShell::SetOutlineNumRule(const SwNumRule& rRule)
113 StartAllAction(); // bracketing for updating!
114 GetDoc()->SetOutlineNumRule(rRule);
115 EndAllAction();
118 const SwNumRule* SwEditShell::GetOutlineNumRule() const
120 return GetDoc()->GetOutlineNumRule();
123 // Set if there is no numbering yet, else update.
124 // Works with old and new rules. Update only differences.
126 // paragraphs without numbering, with indentations
127 void SwEditShell::NoNum()
129 StartAllAction();
131 SwPaM* pCursor = GetCursor();
132 if( pCursor->GetNext() != pCursor ) // Multiple selection?
134 GetDoc()->GetIDocumentUndoRedo().StartUndo( SwUndoId::START, nullptr );
135 SwPamRanges aRangeArr( *pCursor );
136 SwPaM aPam( *pCursor->GetPoint() );
137 for( size_t n = 0; n < aRangeArr.Count(); ++n )
138 GetDoc()->NoNum( aRangeArr.SetPam( n, aPam ));
139 GetDoc()->GetIDocumentUndoRedo().EndUndo( SwUndoId::END, nullptr );
141 else
142 // sw_redlinehide: leave cursor as is, will be split at Point & apply to new node
143 GetDoc()->NoNum( *pCursor );
145 EndAllAction();
148 bool SwEditShell::SelectionHasNumber() const
150 bool bResult = HasNumber();
151 const SwTextNode * pTextNd = sw::GetParaPropsNode(*GetLayout(), GetCursor()->GetPoint()->nNode);
152 if (!bResult && pTextNd && pTextNd->Len()==0 && !pTextNd->GetNumRule()) {
153 SwPamRanges aRangeArr( *GetCursor() );
154 SwPaM aPam( *GetCursor()->GetPoint() );
155 for( size_t n = 0; n < aRangeArr.Count(); ++n )
157 aRangeArr.SetPam( n, aPam );
159 sal_uInt32 nStt = aPam.GetPoint()->nNode.GetIndex(),
160 nEnd = aPam.GetMark()->nNode.GetIndex();
161 if( nStt > nEnd )
163 sal_uInt32 nTmp = nStt; nStt = nEnd; nEnd = nTmp;
165 for (sal_uInt32 nPos = nStt; nPos<=nEnd; nPos++)
167 pTextNd = mxDoc->GetNodes()[nPos]->GetTextNode();
168 if (pTextNd)
170 pTextNd = sw::GetParaPropsNode(*GetLayout(), SwNodeIndex(*pTextNd));
172 if (pTextNd && pTextNd->Len()!=0)
174 bResult = pTextNd->HasNumber();
176 // #b6340308# special case: outline numbered, not counted paragraph
177 if ( bResult &&
178 pTextNd->GetNumRule() == GetDoc()->GetOutlineNumRule() &&
179 !pTextNd->IsCountedInList() )
181 bResult = false;
183 if (!bResult) {
184 break;
193 return bResult;
196 // add a new function to determine number on/off status
197 bool SwEditShell::SelectionHasBullet() const
199 bool bResult = HasBullet();
200 const SwTextNode * pTextNd = sw::GetParaPropsNode(*GetLayout(), GetCursor()->GetPoint()->nNode);
201 if (!bResult && pTextNd && pTextNd->Len()==0 && !pTextNd->GetNumRule()) {
202 SwPamRanges aRangeArr( *GetCursor() );
203 SwPaM aPam( *GetCursor()->GetPoint() );
204 for( size_t n = 0; n < aRangeArr.Count(); ++n )
206 aRangeArr.SetPam( n, aPam );
208 sal_uInt32 nStt = aPam.GetPoint()->nNode.GetIndex(),
209 nEnd = aPam.GetMark()->nNode.GetIndex();
210 if( nStt > nEnd )
212 sal_uInt32 nTmp = nStt; nStt = nEnd; nEnd = nTmp;
214 for (sal_uInt32 nPos = nStt; nPos<=nEnd; nPos++)
216 pTextNd = mxDoc->GetNodes()[nPos]->GetTextNode();
217 if (pTextNd)
219 pTextNd = sw::GetParaPropsNode(*GetLayout(), SwNodeIndex(*pTextNd));
221 if (pTextNd && pTextNd->Len()!=0)
223 bResult = pTextNd->HasBullet();
225 if (!bResult) {
226 break;
234 return bResult;
237 // -> #i29560#
238 bool SwEditShell::HasNumber() const
240 bool bResult = false;
242 const SwTextNode *const pTextNd = sw::GetParaPropsNode(*GetLayout(), GetCursor()->GetPoint()->nNode);
244 if (pTextNd)
246 bResult = pTextNd->HasNumber();
248 // special case: outline numbered, not counted paragraph
249 if ( bResult &&
250 pTextNd->GetNumRule() == GetDoc()->GetOutlineNumRule() &&
251 !pTextNd->IsCountedInList() )
253 bResult = false;
257 return bResult;
260 bool SwEditShell::HasBullet() const
262 bool bResult = false;
264 const SwTextNode *const pTextNd = sw::GetParaPropsNode(*GetLayout(), GetCursor()->GetPoint()->nNode);
266 if (pTextNd)
268 bResult = pTextNd->HasBullet();
271 return bResult;
273 // <- #i29560#
275 // delete, split list
276 void SwEditShell::DelNumRules()
278 StartAllAction();
280 SwPaM* pCursor = GetCursor();
281 if( pCursor->IsMultiSelection() )
283 GetDoc()->GetIDocumentUndoRedo().StartUndo( SwUndoId::START, nullptr );
284 SwPamRanges aRangeArr( *pCursor );
285 SwPaM aPam( *pCursor->GetPoint() );
286 for( size_t n = 0; n < aRangeArr.Count(); ++n )
288 GetDoc()->DelNumRules(aRangeArr.SetPam( n, aPam ), GetLayout());
290 GetDoc()->GetIDocumentUndoRedo().EndUndo( SwUndoId::END, nullptr );
292 else
293 GetDoc()->DelNumRules(*pCursor, GetLayout());
295 // Call AttrChangeNotify on the UI-side. Should actually be redundant but there was a bug once.
296 CallChgLnk();
298 // Cursor cannot be in front of a label anymore, because numbering/bullet is deleted.
299 SetInFrontOfLabel( false );
301 GetDoc()->getIDocumentState().SetModified();
302 EndAllAction();
305 // up- & downgrading
306 void SwEditShell::NumUpDown( bool bDown )
308 StartAllAction();
310 SwPaM* pCursor = GetCursor();
311 if( !pCursor->IsMultiSelection() )
312 GetDoc()->NumUpDown(*pCursor, bDown, GetLayout());
313 else
315 GetDoc()->GetIDocumentUndoRedo().StartUndo( SwUndoId::START, nullptr );
316 SwPamRanges aRangeArr( *pCursor );
317 SwPaM aPam( *pCursor->GetPoint() );
318 for( size_t n = 0; n < aRangeArr.Count(); ++n )
319 GetDoc()->NumUpDown(aRangeArr.SetPam( n, aPam ), bDown, GetLayout());
320 GetDoc()->GetIDocumentUndoRedo().EndUndo( SwUndoId::END, nullptr );
322 GetDoc()->getIDocumentState().SetModified();
324 // #i54693# Update marked numbering levels
325 if ( IsInFrontOfLabel() )
326 UpdateMarkedListLevel();
328 CallChgLnk();
330 EndAllAction();
333 bool SwEditShell::IsFirstOfNumRuleAtCursorPos() const
335 return SwDoc::IsFirstOfNumRuleAtPos(*GetCursor()->GetPoint(), *GetLayout());
338 // -> #i23725#, #i90078#
339 void SwEditShell::ChangeIndentOfAllListLevels( const sal_Int32 nDiff )
341 StartAllAction();
343 const SwNumRule *pCurNumRule = GetNumRuleAtCurrCursorPos();
344 if ( pCurNumRule != nullptr )
346 SwNumRule aRule(*pCurNumRule);
347 const SwNumFormat& aRootNumFormat(aRule.Get(0));
348 if( nDiff > 0 || aRootNumFormat.GetIndentAt() + nDiff > 0) // fdo#42708
350 // #i90078#
351 aRule.ChangeIndent( nDiff );
353 // no start of new list
354 SetCurNumRule( aRule, false );
357 EndAllAction();
360 // #i90078#
361 void SwEditShell::SetIndent(short nIndent, const SwPosition & rPos)
363 StartAllAction();
365 SwPosition pos(rPos);
366 SwNumRule *pCurNumRule = SwDoc::GetNumRuleAtPos(pos, GetLayout());
368 if (pCurNumRule)
370 SwNumRule aRule(*pCurNumRule);
371 if ( !IsMultiSelection() && IsFirstOfNumRuleAtCursorPos() )
373 aRule.SetIndentOfFirstListLevelAndChangeOthers( nIndent );
375 else
377 const SwTextNode* pTextNode = pos.nNode.GetNode().GetTextNode();
378 if ( pTextNode != nullptr
379 && pTextNode->GetActualListLevel() >= 0 )
381 aRule.SetIndent( nIndent, static_cast< sal_uInt16 >( pTextNode->GetActualListLevel() ) );
385 // change numbering rule - changed numbering rule is not applied at <aPaM>
386 SwPaM aPaM(pos);
387 GetDoc()->SetNumRule(aPaM, aRule, false, GetLayout(), OUString(), false);
390 EndAllAction();
393 bool SwEditShell::MoveParagraph( tools::Long nOffset )
395 StartAllAction();
397 SwPaM *pCursor = GetCursor();
399 bool bRet = GetDoc()->MoveParagraph( *pCursor, nOffset );
401 GetDoc()->getIDocumentState().SetModified();
402 EndAllAction();
403 return bRet;
406 int SwEditShell::GetCurrentParaOutlineLevel( ) const
408 int nLevel = 0;
410 SwPaM* pCursor = GetCursor();
411 const SwTextNode *const pTextNd = sw::GetParaPropsNode(*GetLayout(), pCursor->GetPoint()->nNode);
412 if (pTextNd)
413 nLevel = pTextNd->GetAttrOutlineLevel();
414 return nLevel;
417 void SwEditShell::GetCurrentOutlineLevels( sal_uInt8& rUpper, sal_uInt8& rLower )
419 SwPaM* pCursor = GetCursor();
420 SwPaM aCursor( *pCursor->Start() );
421 aCursor.SetMark();
422 if( pCursor->HasMark() )
423 *aCursor.GetPoint() = *pCursor->End();
424 SwDoc::GotoNextNum(*aCursor.GetPoint(), GetLayout(), false, &rUpper, &rLower);
427 bool SwEditShell::MoveNumParas( bool bUpperLower, bool bUpperLeft )
429 StartAllAction();
431 // On all selections?
432 SwPaM* pCursor = GetCursor();
433 SwPaM aCursor( *pCursor->Start() );
434 aCursor.SetMark();
436 if( pCursor->HasMark() )
437 *aCursor.GetPoint() = *pCursor->End();
439 bool bRet = false;
440 sal_uInt8 nUpperLevel, nLowerLevel;
441 if (SwDoc::GotoNextNum( *aCursor.GetPoint(), GetLayout(), false,
442 &nUpperLevel, &nLowerLevel ))
444 if( bUpperLower )
446 // on top of the next numbering
447 tools::Long nOffset = 0;
448 const SwNode* pNd;
450 if( bUpperLeft ) // move up
452 SwPosition aPos( *aCursor.GetMark() );
453 if (SwDoc::GotoPrevNum( aPos, GetLayout(), false ))
454 nOffset = aPos.nNode.GetIndex() -
455 aCursor.GetMark()->nNode.GetIndex();
456 else
458 sal_uLong nStt = aPos.nNode.GetIndex(), nIdx = nStt - 1;
460 if (SwTextNode const*const pStt = aPos.nNode.GetNode().GetTextNode())
462 std::pair<SwTextNode *, SwTextNode *> nodes(
463 sw::GetFirstAndLastNode(*GetLayout(), *pStt));
464 nIdx = nodes.first->GetIndex() - 1;
466 while( nIdx && (
467 ( pNd = GetDoc()->GetNodes()[ nIdx ])->IsSectionNode() ||
468 ( pNd->IsEndNode() && pNd->StartOfSectionNode()->IsSectionNode())))
469 --nIdx;
470 if( GetDoc()->GetNodes()[ nIdx ]->IsTextNode() )
471 nOffset = nIdx - nStt;
474 else // move down
476 assert(!aCursor.GetNode().IsTextNode()
477 || sw::IsParaPropsNode(*GetLayout(), *aCursor.GetNode().GetTextNode()));
478 const SwNumRule* pOrig = sw::GetParaPropsNode(*GetLayout(), *aCursor.GetNode(false).GetTextNode())->GetNumRule();
479 if( aCursor.GetNode().IsTextNode() &&
480 pOrig == aCursor.GetNode().GetTextNode()->GetNumRule() )
482 sal_uLong nStt = aCursor.GetPoint()->nNode.GetIndex(), nIdx = nStt+1;
483 if (SwTextNode const*const pStt = aCursor.GetPoint()->nNode.GetNode().GetTextNode())
485 std::pair<SwTextNode *, SwTextNode *> nodes(
486 sw::GetFirstAndLastNode(*GetLayout(), *pStt));
487 nIdx = nodes.second->GetIndex() + 1;
490 while (nIdx < GetDoc()->GetNodes().Count()-1)
492 pNd = GetDoc()->GetNodes()[ nIdx ];
494 if (pNd->IsSectionNode() ||
495 (pNd->IsEndNode() && pNd->StartOfSectionNode()->IsSectionNode()))
497 ++nIdx;
499 else if (pNd->IsTextNode())
501 SwTextNode const*const pTextNode =
502 sw::GetParaPropsNode(*GetLayout(), SwNodeIndex(*pNd));
503 if (pOrig == pTextNode->GetNumRule()
504 && pTextNode->GetActualListLevel() > nUpperLevel)
506 std::pair<SwTextNode *, SwTextNode *> nodes(
507 sw::GetFirstAndLastNode(*GetLayout(), *pTextNode));
508 nIdx = nodes.second->GetIndex() + 1;
510 else
512 break;
515 // #i57856#
516 else
518 break;
522 if( nStt == nIdx || !GetDoc()->GetNodes()[ nIdx ]->IsTextNode() )
523 nOffset = 1;
524 else
525 nOffset = nIdx - nStt;
527 else
528 nOffset = 1;
531 if( nOffset )
533 aCursor.Move( fnMoveBackward, GoInNode );
534 bRet = GetDoc()->MoveParagraph( aCursor, nOffset );
537 else if( (bUpperLeft ? nUpperLevel : nLowerLevel+1) < MAXLEVEL )
539 aCursor.Move( fnMoveBackward, GoInNode );
540 bRet = GetDoc()->NumUpDown(aCursor, !bUpperLeft, GetLayout());
544 GetDoc()->getIDocumentState().SetModified();
545 EndAllAction();
546 return bRet;
549 bool SwEditShell::OutlineUpDown( short nOffset )
551 StartAllAction();
553 bool bRet = true;
554 SwPaM* pCursor = GetCursor();
555 if( !pCursor->IsMultiSelection() )
556 bRet = GetDoc()->OutlineUpDown(*pCursor, nOffset, GetLayout());
557 else
559 GetDoc()->GetIDocumentUndoRedo().StartUndo( SwUndoId::START, nullptr );
560 SwPamRanges aRangeArr( *pCursor );
561 SwPaM aPam( *pCursor->GetPoint() );
562 for( size_t n = 0; n < aRangeArr.Count(); ++n )
563 bRet = bRet && GetDoc()->OutlineUpDown(
564 aRangeArr.SetPam(n, aPam), nOffset, GetLayout());
565 GetDoc()->GetIDocumentUndoRedo().EndUndo( SwUndoId::END, nullptr );
567 GetDoc()->getIDocumentState().SetModified();
568 EndAllAction();
569 return bRet;
572 bool SwEditShell::MoveOutlinePara( SwOutlineNodes::difference_type nOffset )
574 StartAllAction();
575 bool bRet = GetDoc()->MoveOutlinePara( *GetCursor(), nOffset );
576 EndAllAction();
577 return bRet;
580 // Outlines and SubOutline are ReadOnly?
581 bool SwEditShell::IsProtectedOutlinePara() const
583 bool bRet = false;
584 const SwNode& rNd = GetCursor()->Start()->nNode.GetNode();
585 if( rNd.IsTextNode() )
587 const SwOutlineNodes& rOutlNd = GetDoc()->GetNodes().GetOutLineNds();
588 SwNodePtr pNd = const_cast<SwNodePtr>(&rNd);
589 bool bFirst = true;
590 SwOutlineNodes::size_type nPos;
591 int nLvl(0);
592 if( !rOutlNd.Seek_Entry( pNd, &nPos ) && nPos )
593 --nPos;
595 for( ; nPos < rOutlNd.size(); ++nPos )
597 SwNodePtr pTmpNd = rOutlNd[ nPos ];
599 if (!sw::IsParaPropsNode(*GetLayout(), *pTmpNd->GetTextNode()))
601 continue;
604 int nTmpLvl = pTmpNd->GetTextNode()->GetAttrOutlineLevel();
606 OSL_ENSURE( nTmpLvl >= 0 && nTmpLvl <= MAXLEVEL,
607 "<SwEditShell::IsProtectedOutlinePara()>" );
609 if( bFirst )
611 nLvl = nTmpLvl;
612 bFirst = false;
614 else if( nLvl >= nTmpLvl )
615 break;
617 if( pTmpNd->IsProtect() )
619 bRet = true;
620 break;
624 #if OSL_DEBUG_LEVEL > 0
625 else
627 OSL_FAIL("Cursor not on an outline node");
629 #endif
630 return bRet;
633 /** Test whether outline may be moved (bCopy == false)
634 * or copied (bCopy == true)
635 * Verify these conditions:
636 * 1) outline must be within main body (and not in redline)
637 * 2) outline must not be within table
638 * 3) if bCopy is set, outline must not be write protected
640 static bool lcl_IsOutlineMoveAndCopyable(SwEditShell const& rShell,
641 SwOutlineNodes::size_type const nIdx, bool const bCopy)
643 const SwNodes& rNds = rShell.GetDoc()->GetNodes();
644 const SwNode* pNd = rNds.GetOutLineNds()[ nIdx ];
645 return pNd->GetIndex() >= rNds.GetEndOfExtras().GetIndex() && // 1) body
646 !pNd->FindTableNode() && // 2) table
647 sw::IsParaPropsNode(*rShell.GetLayout(), *pNd->GetTextNode()) &&
648 ( bCopy || !pNd->IsProtect() ); // 3) write
651 bool SwEditShell::IsOutlineMovable( SwOutlineNodes::size_type nIdx ) const
653 return lcl_IsOutlineMoveAndCopyable( *this, nIdx, false );
656 bool SwEditShell::IsOutlineCopyable( SwOutlineNodes::size_type nIdx ) const
658 return lcl_IsOutlineMoveAndCopyable( *this, nIdx, true );
661 bool SwEditShell::NumOrNoNum(
662 bool bNumOn,
663 bool bChkStart )
665 bool bRet = false;
667 if ( !IsMultiSelection()
668 && !HasSelection()
669 && ( !bChkStart || IsSttPara() ) )
671 StartAllAction();
672 SwPosition const pos(sw::GetParaPropsPos(*GetLayout(), *GetCursor()->GetPoint()));
673 bRet = GetDoc()->NumOrNoNum(pos.nNode, !bNumOn);
674 EndAllAction();
676 return bRet;
679 bool SwEditShell::IsNoNum( bool bChkStart ) const
681 // a Backspace in the paragraph without number becomes a Delete
682 bool bResult = false;
684 if ( !IsMultiSelection()
685 && !HasSelection()
686 && ( !bChkStart || IsSttPara() ) )
688 const SwTextNode* pTextNd = sw::GetParaPropsNode(*GetLayout(), GetCursor()->GetPoint()->nNode);
689 if ( pTextNd != nullptr )
691 bResult = !pTextNd->IsCountedInList();
695 return bResult;
698 sal_uInt8 SwEditShell::GetNumLevel() const
700 // return current level where the point of the cursor is
701 sal_uInt8 nLevel = MAXLEVEL;
703 SwPaM* pCursor = GetCursor();
704 const SwTextNode *const pTextNd = sw::GetParaPropsNode(*GetLayout(), pCursor->GetPoint()->nNode);
706 OSL_ENSURE( pTextNd, "GetNumLevel() without text node" );
707 if ( pTextNd == nullptr )
708 return nLevel;
710 const SwNumRule* pRule = pTextNd->GetNumRule();
711 if ( pRule != nullptr )
713 const int nListLevelOfTextNode( pTextNd->GetActualListLevel() );
714 if ( nListLevelOfTextNode >= 0 )
716 nLevel = static_cast<sal_uInt8>( nListLevelOfTextNode );
720 return nLevel;
723 const SwNumRule* SwEditShell::GetNumRuleAtCurrCursorPos() const
725 SwPosition pos(*GetCursor()->GetPoint());
726 return SwDoc::GetNumRuleAtPos( pos, GetLayout() );
729 const SwNumRule* SwEditShell::GetNumRuleAtCurrentSelection() const
731 const SwNumRule* pNumRuleAtCurrentSelection = nullptr;
733 bool bDifferentNumRuleFound = false;
734 for(const SwPaM& rCurrentCursor : GetCursor()->GetRingContainer())
736 const SwNodeIndex aEndNode = rCurrentCursor.End()->nNode;
738 for ( SwNodeIndex aNode = rCurrentCursor.Start()->nNode; aNode <= aEndNode; ++aNode )
740 SwPosition pos(aNode);
741 const SwNumRule* pNumRule = SwDoc::GetNumRuleAtPos(pos, GetLayout());
742 if ( pNumRule == nullptr )
744 continue;
746 else if ( pNumRule != pNumRuleAtCurrentSelection )
748 if ( pNumRuleAtCurrentSelection == nullptr )
750 pNumRuleAtCurrentSelection = pNumRule;
752 else
754 pNumRuleAtCurrentSelection = nullptr;
755 bDifferentNumRuleFound = true;
756 break;
760 if(bDifferentNumRuleFound)
761 break;
764 return pNumRuleAtCurrentSelection;
767 void SwEditShell::SetCurNumRule( const SwNumRule& rRule,
768 bool bCreateNewList,
769 const OUString& rContinuedListId,
770 const bool bResetIndentAttrs )
772 StartAllAction();
774 GetDoc()->GetIDocumentUndoRedo().StartUndo( SwUndoId::START, nullptr );
776 SwPaM* pCursor = GetCursor();
777 if( IsMultiSelection() )
779 SwPamRanges aRangeArr( *pCursor );
780 SwPaM aPam( *pCursor->GetPoint() );
781 OUString sContinuedListId(rContinuedListId);
782 for( size_t n = 0; n < aRangeArr.Count(); ++n )
784 aRangeArr.SetPam( n, aPam );
785 OUString sListId = GetDoc()->SetNumRule( aPam, rRule,
786 bCreateNewList, GetLayout(), sContinuedListId,
787 true, bResetIndentAttrs );
789 //tdf#87548 On creating a new list for a multi-selection only
790 //create a single new list for the multi-selection, not one per selection
791 if (bCreateNewList)
793 sContinuedListId = sListId;
794 bCreateNewList = false;
797 GetDoc()->SetCounted(aPam, true, GetLayout());
800 else
802 GetDoc()->SetNumRule( *pCursor, rRule,
803 bCreateNewList, GetLayout(), rContinuedListId,
804 true, bResetIndentAttrs );
805 GetDoc()->SetCounted( *pCursor, true, GetLayout() );
807 GetDoc()->GetIDocumentUndoRedo().EndUndo( SwUndoId::END, nullptr );
809 EndAllAction();
812 OUString SwEditShell::GetUniqueNumRuleName() const
814 return GetDoc()->GetUniqueNumRuleName();
817 void SwEditShell::ChgNumRuleFormats( const SwNumRule& rRule )
819 StartAllAction();
820 GetDoc()->ChgNumRuleFormats( rRule );
821 EndAllAction();
824 void SwEditShell::ReplaceNumRule( const OUString& rOldRule, const OUString& rNewRule )
826 StartAllAction();
827 SwPosition const pos(sw::GetParaPropsPos(*GetLayout(), *GetCursor()->GetPoint()));
828 GetDoc()->ReplaceNumRule( pos, rOldRule, rNewRule );
829 EndAllAction();
832 void SwEditShell::SetNumRuleStart( bool bFlag, SwPaM* pPaM )
834 StartAllAction();
835 SwPaM* pCursor = pPaM ? pPaM : GetCursor();
836 if( pCursor->IsMultiSelection() ) // multiple selection ?
838 GetDoc()->GetIDocumentUndoRedo().StartUndo( SwUndoId::START, nullptr );
839 SwPamRanges aRangeArr( *pCursor );
840 SwPaM aPam( *pCursor->GetPoint() );
841 for( size_t n = 0; n < aRangeArr.Count(); ++n )
843 SwPosition const pos(sw::GetParaPropsPos(*GetLayout(), *aRangeArr.SetPam( n, aPam ).GetPoint()));
844 GetDoc()->SetNumRuleStart( pos, bFlag );
846 GetDoc()->GetIDocumentUndoRedo().EndUndo( SwUndoId::END, nullptr );
848 else
850 SwPosition const pos(sw::GetParaPropsPos(*GetLayout(), *GetCursor()->GetPoint()));
851 GetDoc()->SetNumRuleStart(pos, bFlag);
854 EndAllAction();
857 bool SwEditShell::IsNumRuleStart( SwPaM* pPaM ) const
859 SwPaM* pCursor = pPaM ? pPaM : GetCursor( );
860 const SwTextNode *const pTextNd = sw::GetParaPropsNode(*GetLayout(), pCursor->GetPoint()->nNode);
861 return pTextNd && pTextNd->IsListRestart();
864 void SwEditShell::SetNodeNumStart( sal_uInt16 nStt )
866 StartAllAction();
868 SwPaM* pCursor = GetCursor();
869 if( pCursor->IsMultiSelection() ) // multiple selection ?
871 GetDoc()->GetIDocumentUndoRedo().StartUndo( SwUndoId::START, nullptr );
872 SwPamRanges aRangeArr( *pCursor );
873 SwPaM aPam( *pCursor->GetPoint() );
874 for( size_t n = 0; n < aRangeArr.Count(); ++n )
876 SwPosition const pos(sw::GetParaPropsPos(*GetLayout(), *aRangeArr.SetPam( n, aPam ).GetPoint()));
877 GetDoc()->SetNodeNumStart( pos, nStt );
879 GetDoc()->GetIDocumentUndoRedo().EndUndo( SwUndoId::END, nullptr );
881 else
883 SwPosition const pos(sw::GetParaPropsPos(*GetLayout(), *pCursor->GetPoint()));
884 GetDoc()->SetNodeNumStart( pos, nStt );
887 EndAllAction();
890 sal_uInt16 SwEditShell::GetNodeNumStart( SwPaM* pPaM ) const
892 SwPaM* pCursor = pPaM ? pPaM : GetCursor();
893 const SwTextNode *const pTextNd = sw::GetParaPropsNode(*GetLayout(), pCursor->GetPoint()->nNode);
894 // correction: check, if list restart value is set at text node and
895 // use new method <SwTextNode::GetAttrListRestartValue()>.
896 // return USHRT_MAX, if no list restart value is found.
897 if ( pTextNd && pTextNd->HasAttrListRestartValue() )
899 return static_cast<sal_uInt16>(pTextNd->GetAttrListRestartValue());
901 return USHRT_MAX;
904 const SwNumRule * SwEditShell::SearchNumRule( const bool bNum,
905 OUString& sListId )
907 return GetDoc()->SearchNumRule( *(GetCursor()->Start()),
908 false/*bForward*/, bNum, false/*bOutline*/, -1/*nNonEmptyAllowe*/,
909 sListId, GetLayout() );
912 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */