1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
21 #include <hintids.hxx>
22 #include <rtl/random.h>
23 #include <tools/resid.hxx>
24 #include <editeng/lrspitem.hxx>
25 #include <ftninfo.hxx>
28 #include <IDocumentUndoRedo.hxx>
31 #include <doctxm.hxx> // pTOXBaseRing
32 #include <poolfmt.hxx>
33 #include <UndoCore.hxx>
34 #include <UndoRedline.hxx>
35 #include <UndoNumbering.hxx>
37 #include <SwUndoFmt.hxx>
44 #include <redline.hxx>
45 #include <comcore.hrc>
46 #include <editeng/adjustitem.hxx>
47 #include <editeng/frmdiritem.hxx>
49 #include <SwStyleNameMapper.hxx>
50 #include <SwNodeNum.hxx>
52 #include <listfunc.hxx>
53 #include <switerator.hxx>
54 #include <comphelper/string.hxx>
59 static void lcl_ResetIndentAttrs(SwDoc
*pDoc
, const SwPaM
&rPam
, sal_uInt16 marker
)
61 std::set
<sal_uInt16
> aResetAttrsArray
;
62 aResetAttrsArray
.insert( marker
);
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().GetTxtNode() )
69 SwPaM
aPam( rPam
.Start()->nNode
,
71 aPam
.Start()->nContent
= 0;
72 aPam
.End()->nContent
= rPam
.End()->nNode
.GetNode().GetTxtNode()->Len();
73 pDoc
->ResetAttrs( aPam
, false, aResetAttrsArray
);
77 pDoc
->ResetAttrs( rPam
, false, aResetAttrsArray
);
85 inline sal_uInt8
GetUpperLvlChg( sal_uInt8 nCurLvl
, sal_uInt8 nLevel
, sal_uInt16 nMask
)
89 if( nCurLvl
+ 1 >= nLevel
)
90 nCurLvl
-= nLevel
- 1;
94 return static_cast<sal_uInt8
>((nMask
- 1) & ~(( 1 << nCurLvl
) - 1));
97 void SwDoc::SetOutlineNumRule( const SwNumRule
& rRule
)
100 (*mpOutlineRule
) = rRule
;
103 mpOutlineRule
= new SwNumRule( rRule
);
105 AddNumRule(mpOutlineRule
); // #i36749#
108 mpOutlineRule
->SetRuleType( OUTLINE_RULE
);
109 mpOutlineRule
->SetName( OUString::createFromAscii(
110 SwNumRule::GetOutlineRuleName() ),
113 // assure that the outline numbering rule is an automatic rule
114 mpOutlineRule
->SetAutoRule( sal_True
);
116 // test whether the optional CharFormats are defined in this Document
117 mpOutlineRule
->CheckCharFmts( this );
119 // notify text nodes, which are registered at the outline style, about the
120 // changed outline style
121 SwNumRule::tTxtNodeList aTxtNodeList
;
122 mpOutlineRule
->GetTxtNodeList( aTxtNodeList
);
123 for ( SwNumRule::tTxtNodeList::iterator aIter
= aTxtNodeList
.begin();
124 aIter
!= aTxtNodeList
.end(); ++aIter
)
126 SwTxtNode
* pTxtNd
= *aIter
;
127 pTxtNd
->NumRuleChgd();
129 // assure that list level corresponds to outline level
130 if ( pTxtNd
->GetTxtColl()->IsAssignedToListLevelOfOutlineStyle() &&
131 pTxtNd
->GetAttrListLevel() != pTxtNd
->GetTxtColl()->GetAssignedOutlineStyleLevel() )
133 pTxtNd
->SetAttrListLevel( pTxtNd
->GetTxtColl()->GetAssignedOutlineStyleLevel() );
137 PropagateOutlineRule();
138 mpOutlineRule
->SetInvalidRule(sal_True
);
141 // update if we have foot notes && numbering by chapter
142 if( !GetFtnIdxs().empty() && FTNNUM_CHAPTER
== GetFtnInfo().eNum
)
143 GetFtnIdxs().UpdateAllFtn();
145 UpdateExpFlds(NULL
, true);
150 void SwDoc::PropagateOutlineRule()
152 for (sal_uInt16 n
= 0; n
< mpTxtFmtCollTbl
->size(); n
++)
154 SwTxtFmtColl
*pColl
= (*mpTxtFmtCollTbl
)[n
];
156 if(pColl
->IsAssignedToListLevelOfOutlineStyle())//<-end,zhaojianwei
158 // Check only the list style, which is set at the paragraph style
159 const SwNumRuleItem
& rCollRuleItem
= pColl
->GetNumRule( sal_False
);
161 // Check on document setting OUTLINE_LEVEL_YIELDS_OUTLINE_RULE no longer needed.
162 if ( rCollRuleItem
.GetValue().isEmpty() )
164 SwNumRule
* pMyOutlineRule
= GetOutlineNumRule();
168 SwNumRuleItem
aNumItem( pMyOutlineRule
->GetName() );
170 pColl
->SetFmtAttr(aNumItem
);
178 bool SwDoc::OutlineUpDown( const SwPaM
& rPam
, short nOffset
)
180 if( GetNodes().GetOutLineNds().empty() || !nOffset
)
183 // calculate the range
184 const SwOutlineNodes
& rOutlNds
= GetNodes().GetOutLineNds();
185 const SwNodePtr pSttNd
= (SwNodePtr
)&rPam
.Start()->nNode
.GetNode();
186 const SwNodePtr pEndNd
= (SwNodePtr
)&rPam
.End()->nNode
.GetNode();
187 sal_uInt16 nSttPos
, nEndPos
;
189 if( !rOutlNds
.Seek_Entry( pSttNd
, &nSttPos
) &&
191 // we're not in an "Outline section"
194 if( rOutlNds
.Seek_Entry( pEndNd
, &nEndPos
) )
197 // We now have the wanted range in the OutlineNodes array,
198 // so check now if we're not invalidating sublevels
199 // (stepping over the limits)
203 // 1. Create the style array:
204 SwTxtFmtColl
* aCollArr
[ MAXLEVEL
];
205 memset( aCollArr
, 0, sizeof( SwTxtFmtColl
* ) * MAXLEVEL
);
207 for( n
= 0; n
< mpTxtFmtCollTbl
->size(); ++n
)
209 if((*mpTxtFmtCollTbl
)[ n
]->IsAssignedToListLevelOfOutlineStyle())
211 const int nLevel
= (*mpTxtFmtCollTbl
)[ n
]->GetAssignedOutlineStyleLevel();
212 aCollArr
[ nLevel
] = (*mpTxtFmtCollTbl
)[ n
];
216 /* Find the last occupied level (backward). */
217 for (n
= MAXLEVEL
- 1; n
> 0; n
--)
219 if (aCollArr
[n
] != 0)
223 /* If an occupied level is found, choose next level (which IS
224 unoccupied) until a valid level is found. If no occupied level
225 was found n is 0 and aCollArr[0] is 0. In this case no demoting
227 if (aCollArr
[n
] != 0)
229 while (n
< MAXLEVEL
- 1)
233 SwTxtFmtColl
*aTmpColl
=
234 GetTxtCollFromPool(static_cast<sal_uInt16
>(RES_POOLCOLL_HEADLINE1
+ n
));
236 if( aTmpColl
->IsAssignedToListLevelOfOutlineStyle() &&
237 aTmpColl
->GetAssignedOutlineStyleLevel() == n
)//<-end,zhaojianwei
239 aCollArr
[n
] = aTmpColl
;
245 /* Find the first occupied level (forward). */
246 for (n
= 0; n
< MAXLEVEL
- 1; n
++)
248 if (aCollArr
[n
] != 0)
252 /* If an occupied level is found, choose previous level (which IS
253 unoccupied) until a valid level is found. If no occupied level
254 was found n is MAXLEVEL - 1 and aCollArr[MAXLEVEL - 1] is 0. In
255 this case no demoting is possible. */
256 if (aCollArr
[n
] != 0)
262 SwTxtFmtColl
*aTmpColl
=
263 GetTxtCollFromPool(static_cast<sal_uInt16
>(RES_POOLCOLL_HEADLINE1
+ n
));
265 //if (aTmpColl->GetOutlineLevel() == n)//#outline level,zhaojianwei
266 if( aTmpColl
->IsAssignedToListLevelOfOutlineStyle() &&
267 aTmpColl
->GetAssignedOutlineStyleLevel() == n
)//<-end,zhaojianwei
269 aCollArr
[n
] = aTmpColl
;
277 Build a move table that states from which level to which other level
278 an outline will be moved.
281 aMoveArr[n] = m: replace aCollArr[n] with aCollArr[m]
283 int aMoveArr
[MAXLEVEL
];
284 int nStep
; // step size for searching in aCollArr: -1 or 1
285 int nNum
; // amount of steps for stepping in aCollArr
298 /* traverse aCollArr */
299 for (n
= 0; n
< MAXLEVEL
; n
++)
301 /* If outline level n has an assigned paragraph style step
302 nNum steps forwards (nStep == 1) or backwards (nStep ==
303 -1). One step is to go to the next non-null entry in
304 aCollArr in the selected direction. If nNum steps were
305 possible write the index of the entry found to aCollArr[n],
306 i.e. outline level n will be replaced by outline level
309 If outline level n has no assigned paragraph style
310 aMoveArr[n] is set to -1.
312 if (aCollArr
[n
] != NULL
)
317 while (nCount
> 0 && m
+ nStep
>= 0 && m
+ nStep
< MAXLEVEL
)
319 m
= static_cast<sal_uInt16
>(m
+ nStep
);
321 if (aCollArr
[m
] != NULL
)
335 /* If moving of the outline levels is applicable, i.e. for all
336 outline levels occuring in the document there has to be a valid
337 target outline level implied by aMoveArr. */
338 bool bMoveApplicable
= true;
339 for (n
= nSttPos
; n
< nEndPos
; n
++)
341 SwTxtNode
* pTxtNd
= rOutlNds
[ n
]->GetTxtNode();
342 SwTxtFmtColl
* pColl
= pTxtNd
->GetTxtColl();
344 if( pColl
->IsAssignedToListLevelOfOutlineStyle() )
346 const int nLevel
= pColl
->GetAssignedOutlineStyleLevel();
347 if (aMoveArr
[nLevel
] == -1)
348 bMoveApplicable
= false;
351 // Check on outline level attribute of text node, if text node is
352 // not an outline via a to outline style assigned paragraph style.
355 const int nNewOutlineLevel
= pTxtNd
->GetAttrOutlineLevel() + nOffset
;
356 if ( nNewOutlineLevel
< 1 || nNewOutlineLevel
> MAXLEVEL
)
358 bMoveApplicable
= false;
363 if (! bMoveApplicable
)
366 if (GetIDocumentUndoRedo().DoesUndo())
368 GetIDocumentUndoRedo().StartUndo(UNDO_OUTLINE_LR
, NULL
);
369 SwUndo
*const pUndoOLR( new SwUndoOutlineLeftRight( rPam
, nOffset
) );
370 GetIDocumentUndoRedo().AppendUndo(pUndoOLR
);
373 // 2. Apply the new style to all Nodes
378 SwTxtNode
* pTxtNd
= rOutlNds
[ n
]->GetTxtNode();
379 SwTxtFmtColl
* pColl
= pTxtNd
->GetTxtColl();
381 if( pColl
->IsAssignedToListLevelOfOutlineStyle() )
383 const int nLevel
= pColl
->GetAssignedOutlineStyleLevel();//#outline level,add by zhaojianwei
385 OSL_ENSURE(aMoveArr
[nLevel
] >= 0,
386 "move table: current TxtColl not found when building table!");
389 if (nLevel
< MAXLEVEL
&& aMoveArr
[nLevel
] >= 0)
391 pColl
= aCollArr
[ aMoveArr
[nLevel
] ];
394 pColl
= (SwTxtFmtColl
*)pTxtNd
->ChgFmtColl( pColl
);
398 else if( pTxtNd
->GetAttrOutlineLevel() > 0) //#outline level,add by zhaojianwei
400 int nLevel
= pTxtNd
->GetAttrOutlineLevel() + nOffset
;
401 if( 0 <= nLevel
&& nLevel
<= MAXLEVEL
)
402 pTxtNd
->SetAttrOutlineLevel( nLevel
);
409 if (GetIDocumentUndoRedo().DoesUndo())
411 GetIDocumentUndoRedo().EndUndo(UNDO_OUTLINE_LR
, NULL
);
421 bool SwDoc::MoveOutlinePara( const SwPaM
& rPam
, short nOffset
)
423 // Do not move to special sections in the nodes array
424 const SwPosition
& rStt
= *rPam
.Start(),
425 & rEnd
= &rStt
== rPam
.GetPoint() ? *rPam
.GetMark()
427 if( GetNodes().GetOutLineNds().empty() || !nOffset
||
428 (rStt
.nNode
.GetIndex() < GetNodes().GetEndOfExtras().GetIndex()) ||
429 (rEnd
.nNode
.GetIndex() < GetNodes().GetEndOfExtras().GetIndex()))
434 sal_uInt16 nAktPos
= 0;
435 SwNodeIndex
aSttRg( rStt
.nNode
), aEndRg( rEnd
.nNode
);
437 int nOutLineLevel
= MAXLEVEL
; //<-end,zhaojianwei
438 SwNode
* pSrch
= &aSttRg
.GetNode();
440 if( pSrch
->IsTxtNode())
441 nOutLineLevel
= static_cast<sal_uInt8
>(((SwTxtNode
*)pSrch
)->GetAttrOutlineLevel()-1);//<-end,zhaojianwei
442 SwNode
* pEndSrch
= &aEndRg
.GetNode();
443 if( !GetNodes().GetOutLineNds().Seek_Entry( pSrch
, &nAktPos
) )
446 return false; // Promoting or demoting before the first outline => no.
448 aSttRg
= *GetNodes().GetOutLineNds()[ nAktPos
];
449 else if( 0 > nOffset
)
450 return false; // Promoting at the top of document?!
452 aSttRg
= *GetNodes().GetEndOfContent().StartOfSectionNode();
454 sal_uInt16 nTmpPos
= 0;
455 // If the given range ends at an outlined text node we have to decide if it has to be a part of
456 // the moving range or not. Normally it will be a sub outline of our chapter
457 // and has to be moved, too. But if the chapter ends with a table(or a section end),
458 // the next text node will be choosen and this could be the next outline of the same level.
459 // The criteria has to be the outline level: sub level => incorporate, same/higher level => no.
460 if( GetNodes().GetOutLineNds().Seek_Entry( pEndSrch
, &nTmpPos
) )
462 if( !pEndSrch
->IsTxtNode() || pEndSrch
== pSrch
||
463 nOutLineLevel
< ((SwTxtNode
*)pEndSrch
)->GetAttrOutlineLevel()-1 )//<-end,zhaojianwei
464 ++nTmpPos
; // For sub outlines only!
467 aEndRg
= nTmpPos
< GetNodes().GetOutLineNds().size()
468 ? *GetNodes().GetOutLineNds()[ nTmpPos
]
469 : GetNodes().GetEndOfContent();
472 if( aEndRg
== aSttRg
)
474 OSL_FAIL( "Moving outlines: Surprising selection" );
479 // The following code corrects the range to handle sections (start/end nodes)
480 // The range will be extended if the least node before the range is a start node
481 // which ends inside the range => The complete section will be moved.
482 // The range will be shrinked if the last position is a start node.
483 // The range will be shrinked if the last node is an end node which starts before the range.
485 while( aSttRg
.GetNode().IsStartNode() )
487 pNd
= aSttRg
.GetNode().EndOfSectionNode();
488 if( pNd
->GetIndex() >= aEndRg
.GetIndex() )
495 while( aEndRg
.GetNode().IsStartNode() )
497 while( aEndRg
.GetNode().IsEndNode() )
499 pNd
= aEndRg
.GetNode().StartOfSectionNode();
500 if( pNd
->GetIndex() >= aSttRg
.GetIndex() )
506 // calculation of the new position
507 if( nOffset
< 0 && nAktPos
< sal_uInt16(-nOffset
) )
508 pNd
= GetNodes().GetEndOfContent().StartOfSectionNode();
509 else if( nAktPos
+ nOffset
>= (sal_uInt16
)GetNodes().GetOutLineNds().size() )
510 pNd
= &GetNodes().GetEndOfContent();
512 pNd
= GetNodes().GetOutLineNds()[ nAktPos
+ nOffset
];
514 sal_uLong nNewPos
= pNd
->GetIndex();
516 // And now a correction of the insert position if necessary...
517 SwNodeIndex
aInsertPos( *pNd
, -1 );
518 while( aInsertPos
.GetNode().IsStartNode() )
520 // Just before the insert position starts a section:
521 // when I'm moving forward I do not want to enter the section,
522 // when I'm moving backward I want to stay in the section if I'm already a part of,
523 // I want to stay outside if I was outside before.
526 pNd
= aInsertPos
.GetNode().EndOfSectionNode();
527 if( pNd
->GetIndex() >= aEndRg
.GetIndex() )
535 // When just before the insert position a section ends, it is okay when I'm moving backward
536 // because I want to stay outside the section.
537 // When moving forward I've to check if I started inside or outside the section
538 // because I don't want to enter of leave such a section
539 while( aInsertPos
.GetNode().IsEndNode() )
541 pNd
= aInsertPos
.GetNode().StartOfSectionNode();
542 if( pNd
->GetIndex() >= aSttRg
.GetIndex() )
548 // We do not want to move into tables (at the moment)
550 pNd
= &aInsertPos
.GetNode();
551 if( pNd
->IsTableNode() )
552 pNd
= pNd
->StartOfSectionNode();
553 if( pNd
->FindTableNode() )
556 OSL_ENSURE( aSttRg
.GetIndex() > nNewPos
|| nNewPos
>= aEndRg
.GetIndex(),
557 "Position lies within Move range" );
559 // If a Position inside the special nodes array sections was calculated,
560 // set it to document start instead.
561 // Sections or Tables at the document start will be pushed backwards.
562 nNewPos
= std::max( nNewPos
, GetNodes().GetEndOfExtras().GetIndex() + 2 );
564 long nOffs
= nNewPos
- ( 0 < nOffset
? aEndRg
.GetIndex() : aSttRg
.GetIndex());
565 SwPaM
aPam( aSttRg
, aEndRg
, 0, -1 );
566 return MoveParagraph( aPam
, nOffs
, true );
569 static sal_uInt16
lcl_FindOutlineName( const SwNodes
& rNds
, const String
& rName
,
572 sal_uInt16 nSavePos
= USHRT_MAX
;
573 const SwOutlineNodes
& rOutlNds
= rNds
.GetOutLineNds();
574 for( sal_uInt16 n
= 0; n
< rOutlNds
.size(); ++n
)
576 SwTxtNode
* pTxtNd
= rOutlNds
[ n
]->GetTxtNode();
577 String
sTxt( pTxtNd
->GetExpandTxt() );
578 if( sTxt
.Equals( rName
) )
580 // Found "exact", set Pos to the Node
584 else if( !bExact
&& USHRT_MAX
== nSavePos
&&
585 COMPARE_EQUAL
== sTxt
.CompareTo( rName
, rName
.Len()) )
587 // maybe we just found the text's first part
595 static sal_uInt16
lcl_FindOutlineNum( const SwNodes
& rNds
, String
& rName
)
597 // Valid numbers are (always just offsets!):
598 // ([Number]+\.)+ (as a regular expression!)
599 // (Number follwed by a period, with 5 repetitions)
600 // i.e.: "1.1.", "1.", "1.1.1."
602 String sNum
= rName
.GetToken( 0, '.', nPos
);
604 return USHRT_MAX
; // invalid number!
606 sal_uInt16 nLevelVal
[ MAXLEVEL
]; // numbers of all levels
607 memset( nLevelVal
, 0, MAXLEVEL
* sizeof( nLevelVal
[0] ));
608 sal_uInt8 nLevel
= 0;
609 String
sName( rName
);
615 for( sal_uInt16 n
= 0; n
< sNum
.Len(); ++n
)
616 if( '0' <= ( c
= sNum
.GetChar( n
)) && c
<= '9' )
618 nVal
*= 10; nVal
+= c
- '0';
621 break; // "almost" valid number
623 return USHRT_MAX
; // invalid number!
625 if( MAXLEVEL
> nLevel
)
626 nLevelVal
[ nLevel
++ ] = nVal
;
628 sName
.Erase( 0, nPos
);
630 sNum
= sName
.GetToken( 0, '.', nPos
);
631 // #i4533# without this check all parts delimited by a dot are treated as outline numbers
632 if(!comphelper::string::isdigitAsciiString(sNum
))
635 rName
= sName
; // that's the follow-up text
637 // read all levels, so search the document for this outline
638 const SwOutlineNodes
& rOutlNds
= rNds
.GetOutLineNds();
639 // Without OutlineNodes searching doesn't pay off
640 // and we save a crash
641 if( rOutlNds
.empty() )
645 // search in the existing outline nodes for the required outline num array
646 for( ; nPos
< (sal_Int32
) rOutlNds
.size(); ++nPos
)
648 pNd
= rOutlNds
[ nPos
]->GetTxtNode();
649 const int nLvl
= pNd
->GetAttrOutlineLevel()-1; //<-end,zhaojianwei
650 if( nLvl
== nLevel
- 1)
652 // #i51089#, #i68289#
653 // Assure, that text node has the correct numbering level. Otherwise,
654 // its number vector will not fit to the searched level.
655 if ( pNd
->GetNum() &&
656 pNd
->GetActualListLevel() == ( nLevel
- 1 ) )
658 const SwNodeNum
& rNdNum
= *(pNd
->GetNum());
659 SwNumberTree::tNumberVector aLevelVal
= rNdNum
.GetNumberVector();
660 // now compare with the one searched for
662 for( sal_uInt8 n
= 0; (n
< nLevel
) && bEqual
; ++n
)
664 bEqual
= aLevelVal
[n
] == nLevelVal
[n
];
673 // A text node, which has an outline paragraph style applied and
674 // has as hard attribute 'no numbering' set, has an outline level,
675 // but no numbering tree node. Thus, consider this situation in
676 // the assertion condition.
677 OSL_ENSURE( !pNd
->GetNumRule(),
678 "<lcl_FindOutlineNum(..)> - text node with outline level and numbering rule, but without numbering tree node. This is a serious defect -> inform OD" );
682 if( nPos
>= (sal_Int32
) rOutlNds
.size() )
687 // Add this bullet point:
689 // A Name can contain a Number and/or the Text.
691 // First, we try to find the correct Entry via the Number.
692 // If it exists, we compare the Text, to see if it's the right one.
693 // If that's not the case, we search again via the Text. If it is
694 // found, we got the right entry. Or else we use the one found by
695 // searching for the Number.
696 // If we don't have a Number, we search via the Text only.
697 bool SwDoc::GotoOutline( SwPosition
& rPos
, const String
& rName
) const
701 const SwOutlineNodes
& rOutlNds
= GetNodes().GetOutLineNds();
703 // 1. step: via the Number:
704 String
sName( rName
);
705 sal_uInt16 nFndPos
= ::lcl_FindOutlineNum( GetNodes(), sName
);
706 if( USHRT_MAX
!= nFndPos
)
708 SwTxtNode
* pNd
= rOutlNds
[ nFndPos
]->GetTxtNode();
709 String sExpandedText
= pNd
->GetExpandTxt();
710 //#i4533# leading numbers followed by a dot have been remove while
711 //searching for the outline position
712 //to compensate this they must be removed from the paragraphs text content, too
715 while(sExpandedText
.Len() && (sTempNum
= sExpandedText
.GetToken(0, '.', nPos
)).Len() &&
717 comphelper::string::isdigitAsciiString(sTempNum
))
719 sExpandedText
.Erase(0, nPos
);
723 if( !sExpandedText
.Equals( sName
) )
725 sal_uInt16 nTmp
= ::lcl_FindOutlineName( GetNodes(), sName
, true );
726 if( USHRT_MAX
!= nTmp
) // found via the Name
729 pNd
= rOutlNds
[ nFndPos
]->GetTxtNode();
733 rPos
.nContent
.Assign( pNd
, 0 );
737 nFndPos
= ::lcl_FindOutlineName( GetNodes(), rName
, false );
738 if( USHRT_MAX
!= nFndPos
)
740 SwTxtNode
* pNd
= rOutlNds
[ nFndPos
]->GetTxtNode();
742 rPos
.nContent
.Assign( pNd
, 0 );
746 // #i68289# additional search on hyperlink URL without its outline numbering part
747 if ( !sName
.Equals( rName
) )
749 nFndPos
= ::lcl_FindOutlineName( GetNodes(), sName
, false );
750 if( USHRT_MAX
!= nFndPos
)
752 SwTxtNode
* pNd
= rOutlNds
[ nFndPos
]->GetTxtNode();
754 rPos
.nContent
.Assign( pNd
, 0 );
762 static void lcl_ChgNumRule( SwDoc
& rDoc
, const SwNumRule
& rRule
)
764 SwNumRule
* pOld
= rDoc
.FindNumRulePtr( rRule
.GetName() );
765 OSL_ENSURE( pOld
, "we cannot proceed without the old NumRule" );
767 sal_uInt16 nChgFmtLevel
= 0, nMask
= 1;
770 for( n
= 0; n
< MAXLEVEL
; ++n
, nMask
<<= 1 )
772 const SwNumFmt
& rOldFmt
= pOld
->Get( n
),
773 & rNewFmt
= rRule
.Get( n
);
775 if( rOldFmt
!= rNewFmt
)
777 nChgFmtLevel
|= nMask
;
779 else if( SVX_NUM_NUMBER_NONE
> rNewFmt
.GetNumberingType() && 1 < rNewFmt
.GetIncludeUpperLevels() &&
780 0 != (nChgFmtLevel
& GetUpperLvlChg( n
, rNewFmt
.GetIncludeUpperLevels(),nMask
)) )
781 nChgFmtLevel
|= nMask
;
784 if( !nChgFmtLevel
) // Nothing has been changed?
786 const bool bInvalidateNumRule( pOld
->IsContinusNum() != rRule
.IsContinusNum() );
787 pOld
->CheckCharFmts( &rDoc
);
788 pOld
->SetContinusNum( rRule
.IsContinusNum() );
790 if ( bInvalidateNumRule
)
792 pOld
->SetInvalidRule(sal_True
);
798 SwNumRule::tTxtNodeList aTxtNodeList
;
799 pOld
->GetTxtNodeList( aTxtNodeList
);
801 for ( SwNumRule::tTxtNodeList::iterator aIter
= aTxtNodeList
.begin();
802 aIter
!= aTxtNodeList
.end(); ++aIter
)
804 SwTxtNode
* pTxtNd
= *aIter
;
805 nLvl
= static_cast<sal_uInt8
>(pTxtNd
->GetActualListLevel());
807 if( nLvl
< MAXLEVEL
)
809 if( nChgFmtLevel
& ( 1 << nLvl
))
811 pTxtNd
->NumRuleChgd();
816 for( n
= 0; n
< MAXLEVEL
; ++n
)
817 if( nChgFmtLevel
& ( 1 << n
))
818 pOld
->Set( n
, rRule
.GetNumFmt( n
));
820 pOld
->CheckCharFmts( &rDoc
);
821 pOld
->SetInvalidRule(sal_True
);
822 pOld
->SetContinusNum( rRule
.IsContinusNum() );
824 rDoc
.UpdateNumRule();
827 void SwDoc::SetNumRule( const SwPaM
& rPam
,
828 const SwNumRule
& rRule
,
829 const bool bCreateNewList
,
830 const String sContinuedListId
,
832 const bool bResetIndentAttrs
)
834 SwUndoInsNum
* pUndo
= NULL
;
835 if (GetIDocumentUndoRedo().DoesUndo())
837 // Start/End for attributes!
838 GetIDocumentUndoRedo().StartUndo( UNDO_INSNUM
, NULL
);
839 pUndo
= new SwUndoInsNum( rPam
, rRule
);
840 GetIDocumentUndoRedo().AppendUndo(pUndo
);
843 SwNumRule
* pNew
= FindNumRulePtr( rRule
.GetName() );
844 bool bUpdateRule
= false;
848 pNew
= (*mpNumRuleTbl
)[ MakeNumRule( rRule
.GetName(), &rRule
) ];
850 else if (rRule
!= *pNew
)
859 pUndo
->SaveOldNumRule( *pNew
);
860 ::lcl_ChgNumRule( *this, rRule
);
861 pUndo
->SetLRSpaceEndPos();
865 ::lcl_ChgNumRule( *this, rRule
);
871 if ( bCreateNewList
)
876 // apply list id of list, which has been created for the new list style
877 sListId
= pNew
->GetDefaultListId();
881 // create new list and apply its list id
882 SwList
* pNewList
= createList( String(), pNew
->GetName() );
883 OSL_ENSURE( pNewList
,
884 "<SwDoc::SetNumRule(..)> - could not create new list. Serious defect -> please inform OD." );
885 sListId
= pNewList
->GetListId();
887 InsertPoolItem( rPam
,
888 SfxStringItem( RES_PARATR_LIST_ID
, sListId
), 0 );
890 else if ( sContinuedListId
.Len() > 0 )
892 // apply given list id
893 InsertPoolItem( rPam
,
894 SfxStringItem( RES_PARATR_LIST_ID
, sContinuedListId
), 0 );
898 if ( ! rPam
.HasMark())
900 SwTxtNode
* pTxtNd
= rPam
.GetPoint()->nNode
.GetNode().GetTxtNode();
901 // consider case that the PaM doesn't denote a text node - e.g. it denotes a graphic node
904 SwNumRule
* pRule
= pTxtNd
->GetNumRule();
906 if (pRule
&& pRule
->GetName() == pNew
->GetName())
910 if ( !pTxtNd
->IsInList() )
915 // Only clear numbering attribute at text node, if at paragraph
916 // style the new numbering rule is found.
919 SwTxtFmtColl
* pColl
= pTxtNd
->GetTxtColl();
922 SwNumRule
* pCollRule
= FindNumRulePtr(pColl
->GetNumRule().GetValue());
923 if ( pCollRule
&& pCollRule
->GetName() == pNew
->GetName() )
925 pTxtNd
->ResetAttr( RES_PARATR_NUMRULE
);
935 InsertPoolItem( rPam
, SwNumRuleItem( pNew
->GetName() ), 0 );
938 if ( bResetIndentAttrs
&&
939 pNew
&& pNew
->Get( 0 ).GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT
)
941 ::lcl_ResetIndentAttrs(this, rPam
, RES_LR_SPACE
);
944 if (GetIDocumentUndoRedo().DoesUndo())
946 GetIDocumentUndoRedo().EndUndo( UNDO_INSNUM
, NULL
);
952 void SwDoc::SetCounted(const SwPaM
& rPam
, bool bCounted
)
956 ::lcl_ResetIndentAttrs(this, rPam
, RES_PARATR_LIST_ISCOUNTED
);
960 InsertPoolItem( rPam
,
961 SfxBoolItem( RES_PARATR_LIST_ISCOUNTED
, sal_False
), 0 );
965 void SwDoc::SetNumRuleStart( const SwPosition
& rPos
, sal_Bool bFlag
)
967 SwTxtNode
* pTxtNd
= rPos
.nNode
.GetNode().GetTxtNode();
971 const SwNumRule
* pRule
= pTxtNd
->GetNumRule();
972 if( pRule
&& !bFlag
!= !pTxtNd
->IsListRestart())
974 if (GetIDocumentUndoRedo().DoesUndo())
976 SwUndo
*const pUndo( new SwUndoNumRuleStart(rPos
, bFlag
) );
977 GetIDocumentUndoRedo().AppendUndo(pUndo
);
980 pTxtNd
->SetListRestart(bFlag
? true : false);
987 void SwDoc::SetNodeNumStart( const SwPosition
& rPos
, sal_uInt16 nStt
)
989 SwTxtNode
* pTxtNd
= rPos
.nNode
.GetNode().GetTxtNode();
993 if ( !pTxtNd
->HasAttrListRestartValue() ||
994 pTxtNd
->GetAttrListRestartValue() != nStt
)
996 if (GetIDocumentUndoRedo().DoesUndo())
998 SwUndo
*const pUndo( new SwUndoNumRuleStart(rPos
, nStt
) );
999 GetIDocumentUndoRedo().AppendUndo(pUndo
);
1001 pTxtNd
->SetAttrListRestartValue( nStt
);
1008 // We can only delete if the Rule is unused!
1009 bool SwDoc::DelNumRule( const String
& rName
, bool bBroadcast
)
1011 sal_uInt16 nPos
= FindNumRule( rName
);
1013 if ( (*mpNumRuleTbl
)[ nPos
] == GetOutlineNumRule() )
1015 OSL_FAIL( "<SwDoc::DelNumRule(..)> - No deletion of outline list style. This is serious defect - please inform OD" );
1019 if( USHRT_MAX
!= nPos
&& !IsUsed( *(*mpNumRuleTbl
)[ nPos
] ))
1021 if (GetIDocumentUndoRedo().DoesUndo())
1024 new SwUndoNumruleDelete(*(*mpNumRuleTbl
)[nPos
], this);
1025 GetIDocumentUndoRedo().AppendUndo(pUndo
);
1029 BroadcastStyleOperation(rName
, SFX_STYLE_FAMILY_PSEUDO
,
1030 SFX_STYLESHEET_ERASED
);
1032 deleteListForListStyle( rName
);
1034 // delete further list, which have the deleted list style as default list style
1035 std::vector
< SwList
* > aListsForDeletion
;
1036 tHashMapForLists::iterator aListIter
= maLists
.begin();
1037 while ( aListIter
!= maLists
.end() )
1039 SwList
* pList
= (*aListIter
).second
;
1040 if ( pList
->GetDefaultListStyleName() == rName
)
1042 aListsForDeletion
.push_back( pList
);
1047 while ( !aListsForDeletion
.empty() )
1049 SwList
* pList
= aListsForDeletion
.back();
1050 aListsForDeletion
.pop_back();
1051 deleteList( pList
->GetListId() );
1054 // #i34097# DeleteAndDestroy deletes rName if
1055 // rName is directly taken from the numrule.
1056 const String
aTmpName( rName
);
1057 delete (*mpNumRuleTbl
)[ nPos
];
1058 mpNumRuleTbl
->erase( mpNumRuleTbl
->begin() + nPos
);
1059 maNumRuleMap
.erase(aTmpName
);
1067 void SwDoc::ChgNumRuleFmts( const SwNumRule
& rRule
, const String
* pName
)
1069 SwNumRule
* pRule
= FindNumRulePtr( pName
? *pName
: rRule
.GetName() );
1072 SwUndoInsNum
* pUndo
= 0;
1073 if (GetIDocumentUndoRedo().DoesUndo())
1075 pUndo
= new SwUndoInsNum( *pRule
, rRule
);
1076 pUndo
->GetHistory();
1077 GetIDocumentUndoRedo().AppendUndo( pUndo
);
1079 ::lcl_ChgNumRule( *this, rRule
);
1082 pUndo
->SetLRSpaceEndPos();
1088 bool SwDoc::RenameNumRule(const String
& rOldName
, const String
& rNewName
,
1091 bool bResult
= false;
1092 SwNumRule
* pNumRule
= FindNumRulePtr(rOldName
);
1096 if (GetIDocumentUndoRedo().DoesUndo())
1098 SwUndo
* pUndo
= new SwUndoNumruleRename(rOldName
, rNewName
, this);
1099 GetIDocumentUndoRedo().AppendUndo(pUndo
);
1102 SwNumRule::tTxtNodeList aTxtNodeList
;
1103 pNumRule
->GetTxtNodeList( aTxtNodeList
);
1105 pNumRule
->SetName( rNewName
, *this );
1107 SwNumRuleItem
aItem(rNewName
);
1109 for ( SwNumRule::tTxtNodeList::iterator aIter
= aTxtNodeList
.begin();
1110 aIter
!= aTxtNodeList
.end(); ++aIter
)
1112 SwTxtNode
* pTxtNd
= *aIter
;
1113 pTxtNd
->SetAttr(aItem
);
1119 BroadcastStyleOperation(rOldName
, SFX_STYLE_FAMILY_PSEUDO
,
1120 SFX_STYLESHEET_MODIFIED
);
1126 void SwDoc::StopNumRuleAnimations( OutputDevice
* pOut
)
1128 for( sal_uInt16 n
= GetNumRuleTbl().size(); n
; )
1130 SwNumRule::tTxtNodeList aTxtNodeList
;
1131 GetNumRuleTbl()[ --n
]->GetTxtNodeList( aTxtNodeList
);
1132 for ( SwNumRule::tTxtNodeList::iterator aTxtNodeIter
= aTxtNodeList
.begin();
1133 aTxtNodeIter
!= aTxtNodeList
.end(); ++aTxtNodeIter
)
1135 SwTxtNode
* pTNd
= *aTxtNodeIter
;
1136 SwIterator
<SwTxtFrm
,SwTxtNode
> aIter(*pTNd
);
1137 for(SwTxtFrm
* pFrm
= aIter
.First(); pFrm
; pFrm
= aIter
.Next() )
1138 if( pFrm
->HasAnimation() )
1139 pFrm
->StopAnimation( pOut
);
1144 bool SwDoc::ReplaceNumRule( const SwPosition
& rPos
,
1145 const String
& rOldRule
, const String
& rNewRule
)
1148 SwNumRule
*pOldRule
= FindNumRulePtr( rOldRule
),
1149 *pNewRule
= FindNumRulePtr( rNewRule
);
1150 if( pOldRule
&& pNewRule
&& pOldRule
!= pNewRule
)
1152 SwUndoInsNum
* pUndo
= 0;
1153 if (GetIDocumentUndoRedo().DoesUndo())
1155 // Start/End for attributes!
1156 GetIDocumentUndoRedo().StartUndo( UNDO_START
, NULL
);
1157 pUndo
= new SwUndoInsNum( rPos
, *pNewRule
, rOldRule
);
1158 GetIDocumentUndoRedo().AppendUndo(pUndo
);
1161 SwNumRule::tTxtNodeList aTxtNodeList
;
1162 pOldRule
->GetTxtNodeList( aTxtNodeList
);
1163 if ( aTxtNodeList
.size() > 0 )
1166 SwRegHistory
aRegH( pUndo
? pUndo
->GetHistory() : 0 );
1167 sal_uInt16 nChgFmtLevel
= 0;
1168 for( sal_uInt8 n
= 0; n
< MAXLEVEL
; ++n
)
1170 const SwNumFmt
& rOldFmt
= pOldRule
->Get( n
),
1171 & rNewFmt
= pNewRule
->Get( n
);
1173 if( rOldFmt
.GetAbsLSpace() != rNewFmt
.GetAbsLSpace() ||
1174 rOldFmt
.GetFirstLineOffset() != rNewFmt
.GetFirstLineOffset() )
1175 nChgFmtLevel
|= ( 1 << n
);
1178 const SwTxtNode
* pGivenTxtNode
= rPos
.nNode
.GetNode().GetTxtNode();
1179 SwNumRuleItem
aRule( rNewRule
);
1181 for ( SwNumRule::tTxtNodeList::iterator aIter
= aTxtNodeList
.begin();
1182 aIter
!= aTxtNodeList
.end(); ++aIter
)
1184 SwTxtNode
* pTxtNd
= *aIter
;
1186 if ( pGivenTxtNode
&&
1187 pGivenTxtNode
->GetListId() == pTxtNd
->GetListId() )
1189 aRegH
.RegisterInModify( pTxtNd
, *pTxtNd
);
1191 pTxtNd
->SetAttr( aRule
);
1192 pTxtNd
->NumRuleChgd();
1195 GetIDocumentUndoRedo().EndUndo( UNDO_END
, NULL
);
1207 struct ListStyleData
1209 SwNumRule
* pReplaceNumRule
;
1210 bool bCreateNewList
;
1214 : pReplaceNumRule( 0 ),
1215 bCreateNewList( false ),
1221 void SwDoc::MakeUniqueNumRules(const SwPaM
& rPaM
)
1223 OSL_ENSURE( rPaM
.GetDoc() == this, "need same doc" );
1225 ::std::map
<SwNumRule
*, ListStyleData
> aMyNumRuleMap
;
1227 sal_uLong nStt
= rPaM
.Start()->nNode
.GetIndex();
1228 sal_uLong nEnd
= rPaM
.End()->nNode
.GetIndex();
1232 for (sal_uLong n
= nStt
; n
<= nEnd
; n
++)
1234 SwTxtNode
* pCNd
= GetNodes()[n
]->GetTxtNode();
1238 SwNumRule
* pRule
= pCNd
->GetNumRule();
1240 if (pRule
&& pRule
->IsAutoRule() && ! pRule
->IsOutlineRule())
1242 ListStyleData aListStyleData
= aMyNumRuleMap
[pRule
];
1244 if ( aListStyleData
.pReplaceNumRule
== 0 )
1248 SwPosition
aPos(*pCNd
);
1249 aListStyleData
.pReplaceNumRule
=
1250 const_cast<SwNumRule
*>
1251 (SearchNumRule( aPos
, false, pCNd
->HasNumber(),
1253 aListStyleData
.sListId
, true ));
1256 if ( aListStyleData
.pReplaceNumRule
== 0 )
1258 aListStyleData
.pReplaceNumRule
= new SwNumRule(*pRule
);
1260 aListStyleData
.pReplaceNumRule
->SetName(
1261 GetUniqueNumRuleName(), *this );
1263 aListStyleData
.bCreateNewList
= true;
1266 aMyNumRuleMap
[pRule
] = aListStyleData
;
1271 SetNumRule( aPam
, *aListStyleData
.pReplaceNumRule
,
1272 aListStyleData
.bCreateNewList
,
1273 aListStyleData
.sListId
);
1274 if ( aListStyleData
.bCreateNewList
)
1276 aListStyleData
.bCreateNewList
= false;
1277 aListStyleData
.sListId
= pCNd
->GetListId();
1278 aMyNumRuleMap
[pRule
] = aListStyleData
;
1287 bool SwDoc::NoNum( const SwPaM
& rPam
)
1290 bool bRet
= SplitNode( *rPam
.GetPoint(), false );
1291 // Do we actually use Numbering at all?
1294 // Set NoNum and Upate
1295 const SwNodeIndex
& rIdx
= rPam
.GetPoint()->nNode
;
1296 SwTxtNode
* pNd
= rIdx
.GetNode().GetTxtNode();
1297 const SwNumRule
* pRule
= pNd
->GetNumRule();
1300 pNd
->SetCountedInList(false);
1305 bRet
= false; // no Numbering or just always sal_True?
1310 void SwDoc::DelNumRules( const SwPaM
& rPam
)
1312 sal_uLong nStt
= rPam
.GetPoint()->nNode
.GetIndex(),
1313 nEnd
= rPam
.GetMark()->nNode
.GetIndex();
1316 sal_uLong nTmp
= nStt
; nStt
= nEnd
; nEnd
= nTmp
;
1319 SwUndoDelNum
* pUndo
;
1320 if (GetIDocumentUndoRedo().DoesUndo())
1322 pUndo
= new SwUndoDelNum( rPam
);
1323 GetIDocumentUndoRedo().AppendUndo(pUndo
);
1328 SwRegHistory
aRegH( pUndo
? pUndo
->GetHistory() : 0 );
1330 SwNumRuleItem
aEmptyRule( aEmptyStr
);
1331 const SwNode
* pOutlNd
= 0;
1332 for( ; nStt
<= nEnd
; ++nStt
)
1334 SwTxtNode
* pTNd
= GetNodes()[ nStt
]->GetTxtNode();
1335 SwNumRule
* pNumRuleOfTxtNode
= pTNd
? pTNd
->GetNumRule() : 0;
1336 if ( pTNd
&& pNumRuleOfTxtNode
)
1338 // recognize changes of attribute for undo
1339 aRegH
.RegisterInModify( pTNd
, *pTNd
);
1342 pUndo
->AddNode( *pTNd
, sal_False
);
1344 // directly set list style attribute is reset, otherwise empty
1345 // list style is applied
1346 const SfxItemSet
* pAttrSet
= pTNd
->GetpSwAttrSet();
1348 pAttrSet
->GetItemState( RES_PARATR_NUMRULE
, sal_False
) == SFX_ITEM_SET
)
1349 pTNd
->ResetAttr( RES_PARATR_NUMRULE
);
1351 pTNd
->SetAttr( aEmptyRule
);
1353 pTNd
->ResetAttr( RES_PARATR_LIST_ID
);
1354 pTNd
->ResetAttr( RES_PARATR_LIST_LEVEL
);
1355 pTNd
->ResetAttr( RES_PARATR_LIST_ISRESTART
);
1356 pTNd
->ResetAttr( RES_PARATR_LIST_RESTARTVALUE
);
1357 pTNd
->ResetAttr( RES_PARATR_LIST_ISCOUNTED
);
1359 if( RES_CONDTXTFMTCOLL
== pTNd
->GetFmtColl()->Which() )
1361 pTNd
->ChkCondColl();
1363 else if( !pOutlNd
&&
1364 static_cast<SwTxtFmtColl
*>(pTNd
->GetFmtColl())->IsAssignedToListLevelOfOutlineStyle() )//<-end,zhaojianwei
1371 // Finally, update all
1375 GetNodes().UpdtOutlineIdx( *pOutlNd
);
1378 void SwDoc::InvalidateNumRules()
1380 for (sal_uInt16 n
= 0; n
< mpNumRuleTbl
->size(); ++n
)
1381 (*mpNumRuleTbl
)[n
]->SetInvalidRule(sal_True
);
1384 // To the next/preceding Bullet at the same Level
1385 static bool lcl_IsNumOk( sal_uInt8 nSrchNum
, sal_uInt8
& rLower
, sal_uInt8
& rUpper
,
1386 bool bOverUpper
, sal_uInt8 nNumber
)
1388 OSL_ENSURE( nNumber
< MAXLEVEL
,
1389 "<lcl_IsNumOk(..)> - misusage of method" );
1393 if( bOverUpper
? nSrchNum
== nNumber
: nSrchNum
>= nNumber
)
1395 else if( nNumber
> rLower
)
1397 else if( nNumber
< rUpper
)
1403 static bool lcl_IsValidPrevNextNumNode( const SwNodeIndex
& rIdx
)
1406 const SwNode
& rNd
= rIdx
.GetNode();
1407 switch( rNd
.GetNodeType() )
1410 bRet
= SwTableBoxStartNode
== rNd
.StartOfSectionNode()->GetStartNodeType() ||
1411 rNd
.StartOfSectionNode()->IsSectionNode();
1415 bRet
= SwTableBoxStartNode
== ((SwStartNode
&)rNd
).GetStartNodeType();
1418 case ND_SECTIONNODE
: // that one's valid, so proceed
1425 static bool lcl_GotoNextPrevNum( SwPosition
& rPos
, bool bNext
,
1426 bool bOverUpper
, sal_uInt8
* pUpper
, sal_uInt8
* pLower
)
1428 const SwTxtNode
* pNd
= rPos
.nNode
.GetNode().GetTxtNode();
1429 const SwNumRule
* pRule
;
1430 if( !pNd
|| 0 == ( pRule
= pNd
->GetNumRule()))
1433 sal_uInt8 nSrchNum
= static_cast<sal_uInt8
>(pNd
->GetActualListLevel());
1435 SwNodeIndex
aIdx( rPos
.nNode
);
1436 if( ! pNd
->IsCountedInList() )
1438 // If NO_NUMLEVEL is switched on, we search the preceding Node with Numbering
1439 bool bError
= false;
1442 if( aIdx
.GetNode().IsTxtNode() )
1444 pNd
= aIdx
.GetNode().GetTxtNode();
1445 pRule
= pNd
->GetNumRule();
1451 nTmpNum
= static_cast<sal_uInt8
>(pNd
->GetActualListLevel());
1452 if( !( ! pNd
->IsCountedInList() &&
1453 (nTmpNum
>= nSrchNum
)) )
1460 bError
= !lcl_IsValidPrevNextNumNode( aIdx
);
1467 sal_uInt8 nLower
= nSrchNum
, nUpper
= nSrchNum
;
1470 const SwTxtNode
* pLast
;
1472 aIdx
++, pLast
= pNd
;
1476 while( bNext
? ( aIdx
.GetIndex() < aIdx
.GetNodes().Count() - 1 )
1479 if( aIdx
.GetNode().IsTxtNode() )
1481 pNd
= aIdx
.GetNode().GetTxtNode();
1482 pRule
= pNd
->GetNumRule();
1485 if( ::lcl_IsNumOk( nSrchNum
, nLower
, nUpper
, bOverUpper
,
1486 static_cast<sal_uInt8
>(pNd
->GetActualListLevel()) ))
1489 rPos
.nContent
.Assign( (SwTxtNode
*)pNd
, 0 );
1499 else if( !lcl_IsValidPrevNextNumNode( aIdx
))
1508 if( !bRet
&& !bOverUpper
&& pLast
) // do not iterate over higher numbers, but still to the end
1513 if( aIdx
.GetNode().IsCntntNode() )
1514 rPos
.nContent
.Assign( aIdx
.GetNode().GetCntntNode(), 0 );
1518 rPos
.nNode
.Assign( *pLast
);
1519 rPos
.nContent
.Assign( (SwTxtNode
*)pLast
, 0 );
1534 bool SwDoc::GotoNextNum( SwPosition
& rPos
, bool bOverUpper
,
1535 sal_uInt8
* pUpper
, sal_uInt8
* pLower
)
1537 return ::lcl_GotoNextPrevNum( rPos
, true, bOverUpper
, pUpper
, pLower
);
1540 const SwNumRule
* SwDoc::SearchNumRule(const SwPosition
& rPos
,
1541 const bool bForward
,
1543 const bool bOutline
,
1544 int nNonEmptyAllowed
,
1546 const bool bInvestigateStartNode
)
1548 const SwNumRule
* pResult
= NULL
;
1549 SwTxtNode
* pTxtNd
= rPos
.nNode
.GetNode().GetTxtNode();
1550 SwNode
* pStartFromNode
= pTxtNd
;
1554 SwNodeIndex
aIdx(rPos
.nNode
);
1556 // - the start node has also been investigated, if requested.
1557 const SwNode
* pNode
= NULL
;
1560 if ( !bInvestigateStartNode
)
1568 if (aIdx
.GetNode().IsTxtNode())
1570 pTxtNd
= aIdx
.GetNode().GetTxtNode();
1572 const SwNumRule
* pNumRule
= pTxtNd
->GetNumRule();
1575 if ( ( pNumRule
->IsOutlineRule() == ( bOutline
? sal_True
: sal_False
) ) &&
1576 ( ( bNum
&& pNumRule
->Get(0).IsEnumeration()) ||
1577 ( !bNum
&& pNumRule
->Get(0).IsItemize() ) ) ) // #i22362#, #i29560#
1579 pResult
= pTxtNd
->GetNumRule();
1580 // provide also the list id, to which the text node belongs.
1581 sListId
= pTxtNd
->GetListId();
1586 else if (pTxtNd
->Len() > 0 || NULL
!= pTxtNd
->GetNumRule())
1588 if (nNonEmptyAllowed
== 0)
1593 if (nNonEmptyAllowed
< 0)
1594 nNonEmptyAllowed
= -1;
1598 if ( bInvestigateStartNode
)
1606 pNode
= &aIdx
.GetNode();
1608 while (!(pNode
== GetNodes().DocumentSectionStartNode(pStartFromNode
) ||
1609 pNode
== GetNodes().DocumentSectionEndNode(pStartFromNode
)));
1616 bool SwDoc::GotoPrevNum( SwPosition
& rPos
, bool bOverUpper
,
1617 sal_uInt8
* pUpper
, sal_uInt8
* pLower
)
1619 return ::lcl_GotoNextPrevNum( rPos
, false, bOverUpper
, pUpper
, pLower
);
1622 bool SwDoc::NumUpDown( const SwPaM
& rPam
, bool bDown
)
1624 sal_uLong nStt
= rPam
.GetPoint()->nNode
.GetIndex(),
1625 nEnd
= rPam
.GetMark()->nNode
.GetIndex();
1628 sal_uLong nTmp
= nStt
; nStt
= nEnd
; nEnd
= nTmp
;
1631 // -> outline nodes are promoted or demoted differently
1632 bool bOnlyOutline
= true;
1633 bool bOnlyNonOutline
= true;
1634 for (sal_uLong n
= nStt
; n
<= nEnd
; n
++)
1636 SwTxtNode
* pTxtNd
= GetNodes()[n
]->GetTxtNode();
1640 SwNumRule
* pRule
= pTxtNd
->GetNumRule();
1644 if (pRule
->IsOutlineRule())
1645 bOnlyNonOutline
= false;
1647 bOnlyOutline
= false;
1653 sal_Int8 nDiff
= bDown
? 1 : -1;
1656 bRet
= OutlineUpDown(rPam
, nDiff
);
1657 else if (bOnlyNonOutline
)
1661 Only promote or demote if all selected paragraphs are
1662 promotable resp. demotable.
1665 for (sal_uLong nTmp
= nStt
; nTmp
<= nEnd
; ++nTmp
)
1667 SwTxtNode
* pTNd
= GetNodes()[ nTmp
]->GetTxtNode();
1669 // Make code robust: consider case that the node doesn't denote a
1673 SwNumRule
* pRule
= pTNd
->GetNumRule();
1677 sal_uInt8 nLevel
= static_cast<sal_uInt8
>(pTNd
->GetActualListLevel());
1678 if( (-1 == nDiff
&& 0 >= nLevel
) ||
1679 (1 == nDiff
&& MAXLEVEL
- 1 <= nLevel
))
1687 if (GetIDocumentUndoRedo().DoesUndo())
1689 SwUndo
*const pUndo( new SwUndoNumUpDown(rPam
, nDiff
) );
1690 GetIDocumentUndoRedo().AppendUndo(pUndo
);
1693 for(sal_uLong nTmp
= nStt
; nTmp
<= nEnd
; ++nTmp
)
1695 SwTxtNode
* pTNd
= GetNodes()[ nTmp
]->GetTxtNode();
1699 SwNumRule
* pRule
= pTNd
->GetNumRule();
1703 sal_uInt8 nLevel
= static_cast<sal_uInt8
>(pTNd
->GetActualListLevel());
1704 nLevel
= nLevel
+ nDiff
;
1706 pTNd
->SetAttrListLevel(nLevel
);
1719 bool SwDoc::MoveParagraph( const SwPaM
& rPam
, long nOffset
, bool bIsOutlMv
)
1721 const SwPosition
*pStt
= rPam
.Start(), *pEnd
= rPam
.End();
1723 sal_uLong nStIdx
= pStt
->nNode
.GetIndex();
1724 sal_uLong nEndIdx
= pEnd
->nNode
.GetIndex();
1726 // Here are some sophisticated checks whether the wished PaM will be moved or not.
1727 // For moving outlines (bIsOutlMv) I've already done some checks, so here are two different
1733 // For moving chapters (outline) the following reason will deny the move:
1734 // if a start node is inside the moved range and its end node outside or vice versa.
1735 // If a start node is the first moved paragraph, its end node has to be within the moved
1736 // range, too (e.g. as last node).
1737 // If an end node is the last node of the moved range, its start node has to be a part of
1738 // the moved section, too.
1739 pTmp1
= GetNodes()[ nStIdx
];
1740 if( pTmp1
->IsStartNode() )
1741 { // First is a start node
1742 pTmp2
= pTmp1
->EndOfSectionNode();
1743 if( pTmp2
->GetIndex() > nEndIdx
)
1744 return false; // Its end node is behind the moved range
1746 pTmp1
= pTmp1
->StartOfSectionNode()->EndOfSectionNode();
1747 if( pTmp1
->GetIndex() <= nEndIdx
)
1748 return false; // End node inside but start node before moved range => no.
1749 pTmp1
= GetNodes()[ nEndIdx
];
1750 if( pTmp1
->IsEndNode() )
1751 { // The last one is an end node
1752 pTmp1
= pTmp1
->StartOfSectionNode();
1753 if( pTmp1
->GetIndex() < nStIdx
)
1754 return false; // Its start node is before the moved range.
1756 pTmp1
= pTmp1
->StartOfSectionNode();
1757 if( pTmp1
->GetIndex() >= nStIdx
)
1758 return false; // A start node which ends behind the moved range => no.
1761 sal_uLong nInStIdx
, nInEndIdx
;
1762 long nOffs
= nOffset
;
1765 nInEndIdx
= nEndIdx
;
1771 // Impossible to move to negative index
1772 if( sal_uLong(abs( nOffset
)) > nStIdx
)
1775 nInEndIdx
= nStIdx
- 1;
1778 nInStIdx
= nInEndIdx
+ 1;
1779 // The following paragraphs shall be swapped:
1780 // Swap [ nStIdx, nInEndIdx ] with [ nInStIdx, nEndIdx ]
1782 if( nEndIdx
>= GetNodes().GetEndOfContent().GetIndex() )
1786 { // And here the restrictions for moving paragraphs other than chapters (outlines)
1787 // The plan is to exchange [nStIdx,nInEndIdx] and [nStartIdx,nEndIdx]
1788 // It will checked if the both "start" nodes as well as the both "end" notes belongs to
1789 // the same start-end-section. This is more restrictive than the conditions checked above.
1790 // E.g. a paragraph will not escape from a section or be inserted to another section.
1791 pTmp1
= GetNodes()[ nStIdx
]->StartOfSectionNode();
1792 pTmp2
= GetNodes()[ nInStIdx
]->StartOfSectionNode();
1793 if( pTmp1
!= pTmp2
)
1794 return false; // "start" nodes in different sections
1795 pTmp1
= GetNodes()[ nEndIdx
];
1796 bool bIsEndNode
= pTmp1
->IsEndNode();
1797 if( !pTmp1
->IsStartNode() )
1799 pTmp1
= pTmp1
->StartOfSectionNode();
1800 if( bIsEndNode
) // For end nodes the first start node is of course inside the range,
1801 pTmp1
= pTmp1
->StartOfSectionNode(); // I've to check the start node of the start node.
1803 pTmp1
= pTmp1
->EndOfSectionNode();
1804 pTmp2
= GetNodes()[ nInEndIdx
];
1805 if( !pTmp2
->IsStartNode() )
1807 bIsEndNode
= pTmp2
->IsEndNode();
1808 pTmp2
= pTmp2
->StartOfSectionNode();
1810 pTmp2
= pTmp2
->StartOfSectionNode();
1812 pTmp2
= pTmp2
->EndOfSectionNode();
1813 if( pTmp1
!= pTmp2
)
1814 return false; // The "end" notes are in different sections
1817 // Test for Redlining - Can the Selection be moved at all, actually?
1818 if( !IsIgnoreRedline() )
1820 sal_uInt16 nRedlPos
= GetRedlinePos( pStt
->nNode
.GetNode(), nsRedlineType_t::REDLINE_DELETE
);
1821 if( USHRT_MAX
!= nRedlPos
)
1823 SwPosition
aStPos( *pStt
), aEndPos( *pEnd
);
1824 aStPos
.nContent
= 0;
1825 SwCntntNode
* pCNd
= pEnd
->nNode
.GetNode().GetCntntNode();
1826 aEndPos
.nContent
= pCNd
? pCNd
->Len() : 1;
1827 bool bCheckDel
= true;
1829 // There is a some Redline Delete Object for the range
1830 for( ; nRedlPos
< GetRedlineTbl().size(); ++nRedlPos
)
1832 const SwRedline
* pTmp
= GetRedlineTbl()[ nRedlPos
];
1833 if( !bCheckDel
|| nsRedlineType_t::REDLINE_DELETE
== pTmp
->GetType() )
1835 const SwPosition
*pRStt
= pTmp
->Start(), *pREnd
= pTmp
->End();
1836 switch( ComparePosition( *pRStt
, *pREnd
, aStPos
, aEndPos
))
1838 case POS_COLLIDE_START
:
1839 case POS_BEHIND
: // Pos1 comes after Pos2
1840 nRedlPos
= GetRedlineTbl().size();
1843 case POS_COLLIDE_END
:
1844 case POS_BEFORE
: // Pos1 comes before Pos2
1846 case POS_INSIDE
: // Pos1 is completely inside Pos2
1847 // that's valid, but check all following for overlapping
1851 case POS_OUTSIDE
: // Pos2 is completely inside Pos1
1852 case POS_EQUAL
: // Pos1 is equal to Pos2
1853 case POS_OVERLAP_BEFORE
: // Pos1 overlaps Pos2 in the beginning
1854 case POS_OVERLAP_BEHIND
: // Pos1 overlaps Pos2 at the end
1863 // Send DataChanged before moving. We then can detect
1864 // which objects are still in the range.
1865 // After the move they could come before/after the
1867 SwDataChanged
aTmp( rPam
);
1870 SwNodeIndex
aIdx( nOffset
> 0 ? pEnd
->nNode
: pStt
->nNode
, nOffs
);
1871 SwNodeRange
aMvRg( pStt
->nNode
, 0, pEnd
->nNode
, +1 );
1873 SwRedline
* pOwnRedl
= 0;
1876 // If the range is completely in the own Redline, we can move it!
1877 sal_uInt16 nRedlPos
= GetRedlinePos( pStt
->nNode
.GetNode(), nsRedlineType_t::REDLINE_INSERT
);
1878 if( USHRT_MAX
!= nRedlPos
)
1880 SwRedline
* pTmp
= GetRedlineTbl()[ nRedlPos
];
1881 const SwPosition
*pRStt
= pTmp
->Start(), *pREnd
= pTmp
->End();
1882 SwRedline
aTmpRedl( nsRedlineType_t::REDLINE_INSERT
, rPam
);
1883 const SwCntntNode
* pCEndNd
= pEnd
->nNode
.GetNode().GetCntntNode();
1884 // Is completely in the range and is the own Redline too?
1885 if( aTmpRedl
.IsOwnRedline( *pTmp
) &&
1886 (pRStt
->nNode
< pStt
->nNode
||
1887 (pRStt
->nNode
== pStt
->nNode
&& !pRStt
->nContent
.GetIndex()) ) &&
1888 (pEnd
->nNode
< pREnd
->nNode
||
1889 (pEnd
->nNode
== pREnd
->nNode
&&
1890 pCEndNd
? pREnd
->nContent
.GetIndex() == pCEndNd
->Len()
1891 : !pREnd
->nContent
.GetIndex() )) )
1894 if( nRedlPos
+ 1 < (sal_uInt16
)GetRedlineTbl().size() )
1896 pTmp
= GetRedlineTbl()[ nRedlPos
+1 ];
1897 if( *pTmp
->Start() == *pREnd
)
1903 !( pRStt
->nNode
<= aIdx
&& aIdx
<= pREnd
->nNode
))
1905 // it's not in itself, so don't move it
1913 GetIDocumentUndoRedo().StartUndo( UNDO_START
, NULL
);
1915 // First the Insert, then the Delete
1916 SwPosition
aInsPos( aIdx
);
1917 aInsPos
.nContent
.Assign( aIdx
.GetNode().GetCntntNode(), 0 );
1919 SwPaM
aPam( pStt
->nNode
, aMvRg
.aEnd
);
1921 SwPaM
& rOrigPam
= (SwPaM
&)rPam
;
1922 rOrigPam
.DeleteMark();
1923 rOrigPam
.GetPoint()->nNode
= aIdx
.GetIndex() - 1;
1925 bool bDelLastPara
= !aInsPos
.nNode
.GetNode().IsCntntNode();
1927 /* When copying to a non-content node Copy will
1928 insert a paragraph before that node and insert before
1929 that inserted node. Copy creates an SwUndoInserts that
1930 does not cover the extra paragraph. Thus we insert the
1931 extra paragraph ourselves, _with_ correct undo
1935 /* aInsPos points to the non-content node. Move it to
1936 the previous content node. */
1937 SwPaM
aInsPam(aInsPos
);
1938 sal_Bool bMoved
= aInsPam
.Move(fnMoveBackward
);
1939 OSL_ENSURE(bMoved
, "No content node found!");
1943 /* Append the new node after the content node
1944 found. The new position to insert the moved
1945 paragraph at is before the inserted
1947 AppendTxtNode(*aInsPam
.GetPoint());
1948 aInsPos
= *aInsPam
.GetPoint();
1952 CopyRange( aPam
, aInsPos
, false );
1955 // We need to remove the last empty Node again
1956 aIdx
= aInsPos
.nNode
;
1957 SwCntntNode
* pCNd
= GetNodes().GoPrevious( &aInsPos
.nNode
);
1958 xub_StrLen nCLen
= 0; if( pCNd
) nCLen
= pCNd
->Len();
1959 aInsPos
.nContent
.Assign( pCNd
, nCLen
);
1961 // All, that are in the to-be-deleted Node, need to be
1962 // moved to the next Node
1964 for( sal_uInt16 n
= 0; n
< GetRedlineTbl().size(); ++n
)
1966 SwRedline
* pTmp
= GetRedlineTbl()[ n
];
1967 if( ( pPos
= &pTmp
->GetBound(sal_True
))->nNode
== aIdx
)
1970 pPos
->nContent
.Assign( pPos
->nNode
.GetNode().GetCntntNode(),0);
1972 if( ( pPos
= &pTmp
->GetBound(sal_False
))->nNode
== aIdx
)
1975 pPos
->nContent
.Assign( pPos
->nNode
.GetNode().GetCntntNode(),0);
1978 CorrRel( aIdx
, aInsPos
, 0, sal_False
);
1983 rOrigPam
.GetPoint()->nNode
++;
1984 rOrigPam
.GetPoint()->nContent
.Assign( rOrigPam
.GetCntntNode(), 0 );
1986 RedlineMode_t eOld
= GetRedlineMode();
1987 checkRedlining(eOld
);
1988 if (GetIDocumentUndoRedo().DoesUndo())
1990 // Still NEEDS to be optimized (even after 14 years)
1992 (RedlineMode_t
)(nsRedlineMode_t::REDLINE_ON
| nsRedlineMode_t::REDLINE_SHOW_INSERT
| nsRedlineMode_t::REDLINE_SHOW_DELETE
));
1993 SwUndo
*const pUndo(new SwUndoRedlineDelete(aPam
, UNDO_DELETE
));
1994 GetIDocumentUndoRedo().AppendUndo(pUndo
);
1997 SwRedline
* pNewRedline
= new SwRedline( nsRedlineType_t::REDLINE_DELETE
, aPam
);
1999 // prevent assertion from aPam's target being deleted
2000 // (Alternatively, one could just let aPam go out of scope, but
2001 // that requires touching a lot of code.)
2002 aPam
.GetBound(sal_True
).nContent
.Assign( NULL
, 0 );
2003 aPam
.GetBound(sal_False
).nContent
.Assign( NULL
, 0 );
2005 AppendRedline( pNewRedline
, true );
2007 // Still NEEDS to be optimized!
2008 SetRedlineMode( eOld
);
2009 GetIDocumentUndoRedo().EndUndo( UNDO_END
, NULL
);
2016 if( !pOwnRedl
&& !IsIgnoreRedline() && !GetRedlineTbl().empty() )
2019 SplitRedline(aTemp
);
2022 sal_uLong
nRedlSttNd(0), nRedlEndNd(0);
2025 const SwPosition
*pRStt
= pOwnRedl
->Start(), *pREnd
= pOwnRedl
->End();
2026 nRedlSttNd
= pRStt
->nNode
.GetIndex();
2027 nRedlEndNd
= pREnd
->nNode
.GetIndex();
2030 SwUndoMoveNum
* pUndo
= 0;
2031 sal_uLong nMoved
= 0;
2032 if (GetIDocumentUndoRedo().DoesUndo())
2034 pUndo
= new SwUndoMoveNum( rPam
, nOffset
, bIsOutlMv
);
2035 nMoved
= rPam
.End()->nNode
.GetIndex() - rPam
.Start()->nNode
.GetIndex() + 1;
2039 MoveNodeRange( aMvRg
, aIdx
, DOC_MOVEREDLINES
);
2043 // i57907: Under circumstances (sections at the end of a chapter)
2044 // the rPam.Start() is not moved to the new position.
2045 // But aIdx should be at the new end position and as long as the
2046 // number of moved paragraphs is nMoved, I know, where the new
2048 pUndo
->SetStartNode( aIdx
.GetIndex() - nMoved
);
2049 GetIDocumentUndoRedo().AppendUndo(pUndo
);
2054 SwPosition
*pRStt
= pOwnRedl
->Start(), *pREnd
= pOwnRedl
->End();
2055 if( pRStt
->nNode
.GetIndex() != nRedlSttNd
)
2057 pRStt
->nNode
= nRedlSttNd
;
2058 pRStt
->nContent
.Assign( pRStt
->nNode
.GetNode().GetCntntNode(),0);
2060 if( pREnd
->nNode
.GetIndex() != nRedlEndNd
)
2062 pREnd
->nNode
= nRedlEndNd
;
2063 SwCntntNode
* pCNd
= pREnd
->nNode
.GetNode().GetCntntNode();
2064 xub_StrLen nL
= 0; if( pCNd
) nL
= pCNd
->Len();
2065 pREnd
->nContent
.Assign( pCNd
, nL
);
2073 bool SwDoc::NumOrNoNum( const SwNodeIndex
& rIdx
, sal_Bool bDel
)
2075 bool bResult
= false;
2076 SwTxtNode
* pTxtNd
= rIdx
.GetNode().GetTxtNode();
2078 if (pTxtNd
&& pTxtNd
->GetNumRule() != NULL
&&
2079 (pTxtNd
->HasNumber() || pTxtNd
->HasBullet()))
2081 if ( !pTxtNd
->IsCountedInList() == !bDel
)
2083 sal_Bool bOldNum
= bDel
; // == pTxtNd->IsCounted();
2084 sal_Bool bNewNum
= bDel
? sal_False
: sal_True
;
2085 pTxtNd
->SetCountedInList(bNewNum
? true : false);
2091 if (GetIDocumentUndoRedo().DoesUndo())
2093 SwUndoNumOrNoNum
* pUndo
=
2094 new SwUndoNumOrNoNum(rIdx
, bOldNum
, bNewNum
);
2096 GetIDocumentUndoRedo().AppendUndo(pUndo
);
2099 else if (bDel
&& pTxtNd
->GetNumRule(sal_False
) &&
2100 pTxtNd
->GetActualListLevel() >= 0 &&
2101 pTxtNd
->GetActualListLevel() < MAXLEVEL
)
2103 SwPaM
aPam(*pTxtNd
);
2114 SwNumRule
* SwDoc::GetCurrNumRule( const SwPosition
& rPos
) const
2116 SwNumRule
* pRet
= 0;
2117 SwTxtNode
* pTNd
= rPos
.nNode
.GetNode().GetTxtNode();
2121 pRet
= pTNd
->GetNumRule();
2127 sal_uInt16
SwDoc::FindNumRule( const String
& rName
) const
2129 for( sal_uInt16 n
= mpNumRuleTbl
->size(); n
; )
2130 if( (*mpNumRuleTbl
)[ --n
]->GetName() == rName
)
2136 SwNumRule
* SwDoc::FindNumRulePtr( const String
& rName
) const
2138 SwNumRule
* pResult
= 0;
2140 pResult
= maNumRuleMap
[rName
];
2144 for (sal_uInt16 n
= 0; n
< mpNumRuleTbl
->size(); ++n
)
2146 if ((*mpNumRuleTbl
)[n
]->GetName() == rName
)
2148 pResult
= (*mpNumRuleTbl
)[n
];
2158 void SwDoc::AddNumRule(SwNumRule
* pRule
)
2160 if ((SAL_MAX_UINT16
- 1) <= mpNumRuleTbl
->size())
2162 OSL_ENSURE(false, "SwDoc::AddNumRule: table full.");
2163 abort(); // this should never happen on real documents
2165 mpNumRuleTbl
->push_back(pRule
);
2166 maNumRuleMap
[pRule
->GetName()] = pRule
;
2167 pRule
->SetNumRuleMap(&maNumRuleMap
);
2169 createListForListStyle( pRule
->GetName() );
2172 sal_uInt16
SwDoc::MakeNumRule( const String
&rName
,
2173 const SwNumRule
* pCpy
,
2175 const SvxNumberFormat::SvxNumPositionAndSpaceMode eDefaultNumberFormatPositionAndSpaceMode
)
2180 pNew
= new SwNumRule( *pCpy
);
2182 pNew
->SetName( GetUniqueNumRuleName( &rName
), *this );
2184 if( pNew
->GetName() != rName
)
2186 pNew
->SetPoolFmtId( USHRT_MAX
);
2187 pNew
->SetPoolHelpId( USHRT_MAX
);
2188 pNew
->SetPoolHlpFileId( UCHAR_MAX
);
2189 pNew
->SetDefaultListId( String() );
2191 pNew
->CheckCharFmts( this );
2195 pNew
= new SwNumRule( GetUniqueNumRuleName( &rName
),
2196 eDefaultNumberFormatPositionAndSpaceMode
);
2199 sal_uInt16 nRet
= mpNumRuleTbl
->size();
2203 if (GetIDocumentUndoRedo().DoesUndo())
2205 SwUndo
* pUndo
= new SwUndoNumruleCreate(pNew
, this);
2206 GetIDocumentUndoRedo().AppendUndo(pUndo
);
2210 BroadcastStyleOperation(pNew
->GetName(), SFX_STYLE_FAMILY_PSEUDO
,
2211 SFX_STYLESHEET_CREATED
);
2216 String
SwDoc::GetUniqueNumRuleName( const String
* pChkStr
, bool bAutoNum
) const
2221 static rtlRandomPool
s_RandomPool( rtl_random_createPool() );
2223 rtl_random_getBytes( s_RandomPool
, &n
, sizeof(n
) );
2224 aName
= OUString::valueOf( (n
< 0 ? -n
: n
) );
2225 if( pChkStr
&& !pChkStr
->Len() )
2228 else if( pChkStr
&& pChkStr
->Len() )
2233 aName
= SW_RESSTR( STR_NUMRULE_DEFNAME
);
2236 sal_uInt16
nNum(0), nTmp
, nFlagSize
= ( mpNumRuleTbl
->size() / 8 ) +2;
2237 sal_uInt8
* pSetFlags
= new sal_uInt8
[ nFlagSize
];
2238 memset( pSetFlags
, 0, nFlagSize
);
2240 xub_StrLen nNmLen
= aName
.Len();
2241 if( !bAutoNum
&& pChkStr
)
2243 while( nNmLen
-- && '0' <= aName
.GetChar( nNmLen
) &&
2244 '9' >= aName
.GetChar( nNmLen
) )
2247 if( ++nNmLen
< aName
.Len() )
2249 aName
.Erase( nNmLen
);
2254 const SwNumRule
* pNumRule
;
2257 for( n
= 0; n
< mpNumRuleTbl
->size(); ++n
)
2258 if( 0 != ( pNumRule
= (*mpNumRuleTbl
)[ n
] ) )
2260 const String
& rNm
= pNumRule
->GetName();
2261 if( rNm
.Match( aName
) == nNmLen
)
2263 // Determine Number and set the Flag
2264 nNum
= (sal_uInt16
)rNm
.Copy( nNmLen
).ToInt32();
2265 if( nNum
-- && nNum
< mpNumRuleTbl
->size() )
2266 pSetFlags
[ nNum
/ 8 ] |= (0x01 << ( nNum
& 0x07 ));
2268 if( pChkStr
&& pChkStr
->Equals( rNm
) )
2274 // All Numbers have been flagged accordingly, so identify the right Number
2275 nNum
= mpNumRuleTbl
->size();
2276 for( n
= 0; n
< nFlagSize
; ++n
)
2277 if( 0xff != ( nTmp
= pSetFlags
[ n
] ))
2279 // identify the Number
2287 delete [] pSetFlags
;
2288 if( pChkStr
&& pChkStr
->Len() )
2290 return aName
+= OUString::number( ++nNum
);
2293 void SwDoc::UpdateNumRule()
2295 const SwNumRuleTbl
& rNmTbl
= GetNumRuleTbl();
2296 for( sal_uInt16 n
= 0; n
< rNmTbl
.size(); ++n
)
2297 if( rNmTbl
[ n
]->IsInvalidRule() )
2298 rNmTbl
[ n
]->Validate();
2301 void SwDoc::MarkListLevel( const String
& sListId
,
2302 const int nListLevel
,
2305 SwList
* pList
= getListByName( sListId
);
2309 MarkListLevel( *pList
, nListLevel
, bValue
);
2313 void SwDoc::MarkListLevel( SwList
& rList
,
2314 const int nListLevel
,
2317 // Set new marked list level and notify all affected nodes of the changed mark.
2318 rList
.MarkListLevel( nListLevel
, bValue
);
2321 bool SwDoc::IsFirstOfNumRule(SwPosition
& rPos
)
2323 bool bResult
= false;
2324 SwTxtNode
* pTxtNode
= rPos
.nNode
.GetNode().GetTxtNode();
2328 SwNumRule
* pNumRule
= pTxtNode
->GetNumRule();
2331 bResult
= pTxtNode
->IsFirstOfNumRule();
2337 // implementation for interface <IDocumentListItems>
2338 bool SwDoc::lessThanNodeNum::operator()( const SwNodeNum
* pNodeNumOne
,
2339 const SwNodeNum
* pNodeNumTwo
) const
2341 return pNodeNumOne
->LessThan( *pNodeNumTwo
);
2344 void SwDoc::addListItem( const SwNodeNum
& rNodeNum
)
2346 if ( mpListItemsList
== 0 )
2351 const bool bAlreadyInserted(
2352 mpListItemsList
->find( &rNodeNum
) != mpListItemsList
->end() );
2353 OSL_ENSURE( !bAlreadyInserted
,
2354 "<SwDoc::InsertListItem(..)> - <SwNodeNum> instance already registered as numbered item!" );
2355 if ( !bAlreadyInserted
)
2357 mpListItemsList
->insert( &rNodeNum
);
2361 void SwDoc::removeListItem( const SwNodeNum
& rNodeNum
)
2363 if ( mpListItemsList
== 0 )
2368 const tImplSortedNodeNumList::size_type nDeleted
= mpListItemsList
->erase( &rNodeNum
);
2371 OSL_FAIL( "<SwDoc::RemoveListItem(..)> - <SwNodeNum> was registered more than once as numbered item!" );
2375 String
SwDoc::getListItemText( const SwNodeNum
& rNodeNum
,
2376 const bool bWithNumber
,
2377 const bool bWithSpacesForLevel
) const
2379 return rNodeNum
.GetTxtNode()
2380 ? rNodeNum
.GetTxtNode()->GetExpandTxt( 0, STRING_LEN
, bWithNumber
,
2381 bWithNumber
, bWithSpacesForLevel
)
2385 void SwDoc::getListItems( tSortedNodeNumList
& orNodeNumList
) const
2387 orNodeNumList
.clear();
2388 orNodeNumList
.reserve( mpListItemsList
->size() );
2390 tImplSortedNodeNumList::iterator aIter
;
2391 tImplSortedNodeNumList::iterator aEndIter
= mpListItemsList
->end();
2392 for ( aIter
= mpListItemsList
->begin(); aIter
!= aEndIter
; ++aIter
)
2394 orNodeNumList
.push_back( (*aIter
) );
2398 void SwDoc::getNumItems( tSortedNodeNumList
& orNodeNumList
) const
2400 orNodeNumList
.clear();
2401 orNodeNumList
.reserve( mpListItemsList
->size() );
2403 tImplSortedNodeNumList::iterator aIter
;
2404 tImplSortedNodeNumList::iterator aEndIter
= mpListItemsList
->end();
2405 for ( aIter
= mpListItemsList
->begin(); aIter
!= aEndIter
; ++aIter
)
2407 const SwNodeNum
* pNodeNum
= (*aIter
);
2408 if ( pNodeNum
->IsCounted() &&
2409 pNodeNum
->GetTxtNode() && pNodeNum
->GetTxtNode()->HasNumber() )
2411 orNodeNumList
.push_back( pNodeNum
);
2416 // implementation for interface <IDocumentOutlineNodes>
2417 sal_Int32
SwDoc::getOutlineNodesCount() const
2419 return GetNodes().GetOutLineNds().size();
2422 int SwDoc::getOutlineLevel( const sal_Int32 nIdx
) const
2424 return GetNodes().GetOutLineNds()[ static_cast<sal_uInt16
>(nIdx
) ]->
2425 // GetTxtNode()->GetOutlineLevel(); //#outline level,zhaojianwei
2426 GetTxtNode()->GetAttrOutlineLevel()-1; //<-end,zhaojianwei
2429 String
SwDoc::getOutlineText( const sal_Int32 nIdx
,
2430 const bool bWithNumber
,
2431 const bool bWithSpacesForLevel
) const
2433 return GetNodes().GetOutLineNds()[ static_cast<sal_uInt16
>(nIdx
) ]->
2434 GetTxtNode()->GetExpandTxt( 0, STRING_LEN
, bWithNumber
,
2435 bWithNumber
, bWithSpacesForLevel
);
2438 SwTxtNode
* SwDoc::getOutlineNode( const sal_Int32 nIdx
) const
2440 return GetNodes().GetOutLineNds()[ static_cast<sal_uInt16
>(nIdx
) ]->GetTxtNode();
2443 void SwDoc::getOutlineNodes( IDocumentOutlineNodes::tSortedOutlineNodeList
& orOutlineNodeList
) const
2445 orOutlineNodeList
.clear();
2446 orOutlineNodeList
.reserve( getOutlineNodesCount() );
2448 const sal_uInt16
nOutlCount( static_cast<sal_uInt16
>(getOutlineNodesCount()) );
2449 for ( sal_uInt16 i
= 0; i
< nOutlCount
; ++i
)
2451 orOutlineNodeList
.push_back(
2452 GetNodes().GetOutLineNds()[i
]->GetTxtNode() );
2456 // implementation of interface IDocumentListsAccess
2457 SwList
* SwDoc::createList( String sListId
,
2458 const String sDefaultListStyleName
)
2460 if ( sListId
.Len() == 0 )
2462 sListId
= listfunc::CreateUniqueListId( *this );
2465 if ( getListByName( sListId
) )
2467 OSL_FAIL( "<SwDoc::createList(..)> - provided list id already used. Serious defect -> please inform OD." );
2471 SwNumRule
* pDefaultNumRuleForNewList
= FindNumRulePtr( sDefaultListStyleName
);
2472 if ( !pDefaultNumRuleForNewList
)
2474 OSL_FAIL( "<SwDoc::createList(..)> - for provided default list style name no list style is found. Serious defect -> please inform OD." );
2478 SwList
* pNewList
= new SwList( sListId
, *pDefaultNumRuleForNewList
, GetNodes() );
2479 maLists
[sListId
] = pNewList
;
2484 void SwDoc::deleteList( const String sListId
)
2486 SwList
* pList
= getListByName( sListId
);
2489 maLists
.erase( sListId
);
2494 SwList
* SwDoc::getListByName( const String sListId
) const
2498 boost::unordered_map
< String
, SwList
*, StringHash
>::const_iterator
2499 aListIter
= maLists
.find( sListId
);
2500 if ( aListIter
!= maLists
.end() )
2502 pList
= (*aListIter
).second
;
2508 SwList
* SwDoc::createListForListStyle( const String sListStyleName
)
2510 if ( sListStyleName
.Len() == 0 )
2512 OSL_FAIL( "<SwDoc::createListForListStyle(..)> - no list style name provided. Serious defect -> please inform OD." );
2516 if ( getListForListStyle( sListStyleName
) )
2518 OSL_FAIL( "<SwDoc::createListForListStyle(..)> - a list for the provided list style name already exists. Serious defect -> please inform OD." );
2522 SwNumRule
* pNumRule
= FindNumRulePtr( sListStyleName
);
2525 OSL_FAIL( "<SwDoc::createListForListStyle(..)> - for provided list style name no list style is found. Serious defect -> please inform OD." );
2529 String
sListId( pNumRule
->GetDefaultListId() ); // can be empty String
2530 if ( getListByName( sListId
) )
2534 SwList
* pNewList
= createList( sListId
, sListStyleName
);
2535 maListStyleLists
[sListStyleName
] = pNewList
;
2536 pNumRule
->SetDefaultListId( pNewList
->GetListId() );
2541 SwList
* SwDoc::getListForListStyle( const String sListStyleName
) const
2545 boost::unordered_map
< String
, SwList
*, StringHash
>::const_iterator
2546 aListIter
= maListStyleLists
.find( sListStyleName
);
2547 if ( aListIter
!= maListStyleLists
.end() )
2549 pList
= (*aListIter
).second
;
2555 void SwDoc::deleteListForListStyle( const String sListStyleName
)
2559 SwList
* pList
= getListForListStyle( sListStyleName
);
2561 "<SwDoc::deleteListForListStyle(..)> - misusage of method: no list found for given list style name" );
2564 sListId
= pList
->GetListId();
2567 if ( sListId
.Len() > 0 )
2569 maListStyleLists
.erase( sListStyleName
);
2570 deleteList( sListId
);
2574 void SwDoc::trackChangeOfListStyleName( const String sListStyleName
,
2575 const String sNewListStyleName
)
2577 SwList
* pList
= getListForListStyle( sListStyleName
);
2579 "<SwDoc::changeOfListStyleName(..)> - misusage of method: no list found for given list style name" );
2583 maListStyleLists
.erase( sListStyleName
);
2584 maListStyleLists
[sNewListStyleName
] = pList
;
2590 const String
MakeListIdUnique( const SwDoc
& rDoc
,
2591 const String aSuggestedUniqueListId
)
2594 String aTmpStr
= aSuggestedUniqueListId
;
2595 while ( rDoc
.getListByName( aTmpStr
) )
2598 aTmpStr
= aSuggestedUniqueListId
;
2599 aTmpStr
+= OUString::number( nHitCount
);
2604 const String
CreateUniqueListId( const SwDoc
& rDoc
)
2607 OUString
aNewListId( "list" );
2609 static rtlRandomPool
s_RandomPool( rtl_random_createPool() );
2611 rtl_random_getBytes( s_RandomPool
, &n
, sizeof(n
) );
2612 aNewListId
+= OUString::valueOf( (n
< 0 ? -n
: n
) );
2614 return MakeListIdUnique( rDoc
, aNewListId
);
2618 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */