xref: /aoo41x/main/sw/source/core/txtnode/ndtxt.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sw.hxx"
30 #include <hintids.hxx>
31 #include <hints.hxx>
32 
33 #include <editeng/fontitem.hxx>
34 #include <editeng/brkitem.hxx>
35 #include <editeng/escpitem.hxx>
36 #include <editeng/lrspitem.hxx>
37 #include <editeng/tstpitem.hxx>
38 #include <svl/urihelper.hxx>
39 #ifndef _SVSTDARR_HXX
40 #define _SVSTDARR_ULONGS
41 #include <svl/svstdarr.hxx>
42 #endif
43 #include <svl/ctloptions.hxx>
44 #include <swmodule.hxx>
45 #include <txtfld.hxx>
46 #include <txtinet.hxx>
47 #include <fmtinfmt.hxx>
48 #include <fmtpdsc.hxx>
49 #include <txtatr.hxx>
50 #include <fmtrfmrk.hxx>
51 #include <txttxmrk.hxx>
52 #include <fchrfmt.hxx>
53 #include <txtftn.hxx>
54 #include <fmtflcnt.hxx>
55 #include <fmtfld.hxx>
56 #include <frmatr.hxx>
57 #include <charatr.hxx>
58 #include <ftnidx.hxx>
59 #include <ftninfo.hxx>
60 #include <fmtftn.hxx>
61 #include <fmtmeta.hxx>
62 #include <charfmt.hxx>
63 #include <ndtxt.hxx>
64 #include <doc.hxx>
65 #include <IDocumentUndoRedo.hxx>
66 #include <docary.hxx>
67 #include <pam.hxx>					// fuer SwPosition
68 #include <fldbas.hxx>
69 #include <errhdl.hxx>
70 #include <paratr.hxx>
71 #include <txtfrm.hxx>
72 #include <ftnfrm.hxx>
73 #include <ftnboss.hxx>
74 #include <rootfrm.hxx>
75 #include <pagedesc.hxx>				// fuer SwPageDesc
76 #include <expfld.hxx>				// fuer SwTblField
77 #include <section.hxx>				// fuer SwSection
78 #include <mvsave.hxx>
79 #include <swcache.hxx>
80 #include <SwGrammarMarkUp.hxx>
81 #include <dcontact.hxx>
82 #include <redline.hxx>
83 #include <doctxm.hxx>
84 #include <IMark.hxx>
85 #include <scriptinfo.hxx>
86 #include <istyleaccess.hxx>
87 #include <SwStyleNameMapper.hxx>
88 #include <numrule.hxx>
89 #include <svl/intitem.hxx>
90 #include <swtable.hxx>
91 #include <docsh.hxx>
92 #include <SwNodeNum.hxx>
93 #include <svl/intitem.hxx>
94 #include <list.hxx>
95 #include <switerator.hxx>
96 #include <attrhint.hxx>
97 
98 
99 using namespace ::com::sun::star;
100 
101 
102 SV_DECL_PTRARR( TmpHints, SwTxtAttr*, 0, 4 )
103 
104 TYPEINIT1( SwTxtNode, SwCntntNode )
105 
106 SV_DECL_PTRARR(SwpHts,SwTxtAttr*,1,1)
107 
108 // Leider ist das SwpHints nicht ganz wasserdicht:
109 // Jeder darf an den Hints rumfummeln, ohne die Sortierreihenfolge
110 // und Verkettung sicherstellen zu muessen.
111 #ifdef DBG_UTIL
112 #define CHECK_SWPHINTS(pNd)  { if( pNd->GetpSwpHints() && \
113                                    !pNd->GetDoc()->IsInReading() ) \
114 								  pNd->GetpSwpHints()->Check(); }
115 #else
116 #define CHECK_SWPHINTS(pNd)
117 #endif
118 
119 SwTxtNode *SwNodes::MakeTxtNode( const SwNodeIndex & rWhere,
120 								 SwTxtFmtColl *pColl,
121 								 SwAttrSet* pAutoAttr )
122 {
123 	ASSERT( pColl, "Collectionpointer ist 0." );
124 
125 	SwTxtNode *pNode = new SwTxtNode( rWhere, pColl, pAutoAttr );
126 
127 	SwNodeIndex aIdx( *pNode );
128 
129     // --> OD 2005-11-03 #125329#
130     // call method <UpdateOutlineNode(..)> only for the document nodes array
131     if ( IsDocNodes() )
132         UpdateOutlineNode(*pNode);
133 
134 	//Wenn es noch kein Layout gibt oder in einer versteckten Section
135 	// stehen, brauchen wir uns um das MakeFrms nicht bemuehen.
136 	const SwSectionNode* pSectNd;
137 	if( !GetDoc()->GetCurrentViewShell() ||	//swmod 071108//swmod 071225
138 		( 0 != (pSectNd = pNode->FindSectionNode()) &&
139 			pSectNd->GetSection().IsHiddenFlag() ))
140 		return pNode;
141 
142 	SwNodeIndex aTmp( rWhere );
143 	do {
144 		// max. 2 Durchlaeufe:
145 		// 1. den Nachfolger nehmen
146 		// 2. den Vorgaenger
147 
148         SwNode * pNd = & aTmp.GetNode();
149         switch (pNd->GetNodeType())
150 		{
151 		case ND_TABLENODE:
152 			((SwTableNode*)pNd)->MakeFrms( aIdx );
153 			return pNode;
154 
155 		case ND_SECTIONNODE:
156 			if( ((SwSectionNode*)pNd)->GetSection().IsHidden() ||
157 				((SwSectionNode*)pNd)->IsCntntHidden() )
158 			{
159 				SwNodeIndex aTmpIdx( *pNode );
160 				pNd = FindPrvNxtFrmNode( aTmpIdx, pNode );
161 				if( !pNd )
162 					return pNode;
163 				aTmp = *pNd;
164 				break;
165 			}
166 			((SwSectionNode*)pNd)->MakeFrms( aIdx );
167 			return pNode;
168 
169 		case ND_TEXTNODE:
170 		case ND_GRFNODE:
171 		case ND_OLENODE:
172 			((SwCntntNode*)pNd)->MakeFrms( *pNode );
173 			return pNode;
174 
175 		case ND_ENDNODE:
176             if( pNd->StartOfSectionNode()->IsSectionNode() &&
177 				aTmp.GetIndex() < rWhere.GetIndex() )
178 			{
179                 if( pNd->StartOfSectionNode()->GetSectionNode()->GetSection().IsHiddenFlag())
180 				{
181 					if( !GoPrevSection( &aTmp, sal_True, sal_False ) ||
182 						aTmp.GetNode().FindTableNode() !=
183 							pNode->FindTableNode() )
184 						return pNode;		// schade, das wars
185 				}
186 				else
187                     aTmp = *pNd->StartOfSectionNode();
188 				break;
189 			}
190             else if( pNd->StartOfSectionNode()->IsTableNode() &&
191 					aTmp.GetIndex() < rWhere.GetIndex() )
192 			{
193 				// wir stehen hinter einem TabellenNode
194                 aTmp = *pNd->StartOfSectionNode();
195 				break;
196 			}
197 			// kein break !!!
198 		default:
199 			if( rWhere == aTmp )
200 				aTmp -= 2;
201 			else
202 				return pNode;
203 			break;
204 		}
205 	} while( sal_True );
206 }
207 
208 // --------------------
209 // SwTxtNode
210 // --------------------
211 
212 SwTxtNode::SwTxtNode( const SwNodeIndex &rWhere,
213                       SwTxtFmtColl *pTxtColl,
214                       const SfxItemSet* pAutoAttr )
215 	: SwCntntNode( rWhere, ND_TEXTNODE, pTxtColl ),
216       m_pSwpHints( 0 ),
217       mpNodeNum( 0 ),
218       m_bLastOutlineState( false ),
219       m_bNotifiable( false ),
220       // --> OD 2008-11-19 #i70748#
221       mbEmptyListStyleSetDueToSetOutlineLevelAttr( false ),
222       // <--
223       // --> OD 2008-05-06 #refactorlists#
224       mbInSetOrResetAttr( false ),
225       mpList( 0 )
226       // <--
227 {
228     InitSwParaStatistics( true );
229 
230 	// soll eine Harte-Attributierung gesetzt werden?
231     if( pAutoAttr )
232         SetAttr( *pAutoAttr );
233 
234     // --> OD 2008-03-13 #refactorlists# - no longed needed
235 //    SyncNumberAndNumRule();
236     if ( !IsInList() && GetNumRule() && GetListId().Len() > 0 )
237     {
238         // --> OD 2009-08-27 #i101516#
239         // apply paragraph style's assigned outline style list level as
240         // list level of the paragraph, if it has none set already.
241         if ( !HasAttrListLevel() &&
242              pTxtColl && pTxtColl->IsAssignedToListLevelOfOutlineStyle() )
243         {
244             SetAttrListLevel( pTxtColl->GetAssignedOutlineStyleLevel() );
245         }
246         // <--
247         AddToList();
248     }
249     // <--
250     GetNodes().UpdateOutlineNode(*this);
251 
252     m_bNotifiable = true;
253 
254     m_bContainsHiddenChars = m_bHiddenCharsHidePara = false;
255     m_bRecalcHiddenCharFlags = true;
256 }
257 
258 SwTxtNode::~SwTxtNode()
259 {
260 	// delete loescht nur die Pointer, nicht die Arrayelemente!
261     if ( m_pSwpHints )
262 	{
263 		// damit Attribute die ihren Inhalt entfernen nicht doppelt
264 		// geloescht werden.
265         SwpHints* pTmpHints = m_pSwpHints;
266         m_pSwpHints = 0;
267 
268 		for( sal_uInt16 j = pTmpHints->Count(); j; )
269 			// erst muss das Attribut aus dem Array entfernt werden,
270 			// denn sonst wuerde es sich selbst loeschen (Felder) !!!!
271             DestroyAttr( pTmpHints->GetTextHint( --j ) );
272 
273 		delete pTmpHints;
274 	}
275 
276     // --> OD 2008-03-13 #refactorlists#
277 //    if ( mpNodeNum )
278 //    {
279 //        mpNodeNum->RemoveMe();
280 //        delete mpNodeNum;
281 //        mpNodeNum = 0L;
282 //    }
283     RemoveFromList();
284     // <--
285 
286     InitSwParaStatistics( false );
287 }
288 
289 SwCntntFrm *SwTxtNode::MakeFrm( SwFrm* pSib )
290 {
291 	SwCntntFrm *pFrm = new SwTxtFrm( this, pSib );
292 	return pFrm;
293 }
294 
295 xub_StrLen SwTxtNode::Len() const
296 {
297     return m_Text.Len();
298 }
299 
300 /*---------------------------------------------------------------------------
301  * lcl_ChangeFtnRef
302  * 	After a split node, it's necessary to actualize the ref-pointer of the
303  *  ftnfrms.
304  * --------------------------------------------------------------------------*/
305 
306 void lcl_ChangeFtnRef( SwTxtNode &rNode )
307 {
308 	SwpHints *pSwpHints = rNode.GetpSwpHints();
309 	if( pSwpHints && rNode.GetDoc()->GetCurrentViewShell() )	//swmod 071108//swmod 071225
310 	{
311 		SwTxtAttr* pHt;
312 		SwCntntFrm* pFrm = NULL;
313         // OD 07.11.2002 #104840# - local variable to remember first footnote
314         // of node <rNode> in order to invalidate position of its first content.
315         // Thus, in its <MakeAll()> it will checked its position relative to its reference.
316         SwFtnFrm* pFirstFtnOfNode = 0;
317 		for( sal_uInt16 j = pSwpHints->Count(); j; )
318         {
319             pHt = pSwpHints->GetTextHint(--j);
320             if (RES_TXTATR_FTN == pHt->Which())
321             {
322 				if( !pFrm )
323 				{
324 					pFrm = SwIterator<SwCntntFrm,SwTxtNode>::FirstElement( rNode );
325 					if( !pFrm )
326 						return;
327 				}
328 				SwTxtFtn *pAttr = (SwTxtFtn*)pHt;
329 				ASSERT( pAttr->GetStartNode(), "FtnAtr ohne StartNode." );
330 				SwNodeIndex aIdx( *pAttr->GetStartNode(), 1 );
331 				SwCntntNode *pNd = aIdx.GetNode().GetCntntNode();
332 				if ( !pNd )
333 					pNd = pFrm->GetAttrSet()->GetDoc()->
334 			  			  GetNodes().GoNextSection( &aIdx, sal_True, sal_False );
335 				if ( !pNd )
336 					continue;
337 
338             	SwIterator<SwCntntFrm,SwCntntNode> aIter( *pNd );
339 				SwCntntFrm* pCntnt = aIter.First();
340 				if( pCntnt )
341 				{
342 					ASSERT( pCntnt->getRootFrm() == pFrm->getRootFrm(),
343 							"lcl_ChangeFtnRef: Layout double?" );
344 					SwFtnFrm *pFtn = pCntnt->FindFtnFrm();
345 					if( pFtn && pFtn->GetAttr() == pAttr )
346 					{
347 						while( pFtn->GetMaster() )
348 							pFtn = pFtn->GetMaster();
349                         // OD 07.11.2002 #104840# - remember footnote frame
350                         pFirstFtnOfNode = pFtn;
351                         while ( pFtn )
352 						{
353 							pFtn->SetRef( pFrm );
354 							pFtn = pFtn->GetFollow();
355 							((SwTxtFrm*)pFrm)->SetFtn( sal_True );
356 						}
357 					}
358 #ifdef DBG_UTIL
359 					while( 0 != (pCntnt = aIter.Next()) )
360 					{
361 						SwFtnFrm *pDbgFtn = pCntnt->FindFtnFrm();
362 						ASSERT( !pDbgFtn || pDbgFtn->GetRef() == pFrm,
363 								"lcl_ChangeFtnRef: Who's that guy?" );
364 					}
365 #endif
366 				}
367 			}
368         } // end of for-loop on <SwpHints>
369         // OD 08.11.2002 #104840# - invalidate
370         if ( pFirstFtnOfNode )
371         {
372             SwCntntFrm* pCntnt = pFirstFtnOfNode->ContainsCntnt();
373             if ( pCntnt )
374             {
375                 pCntnt->_InvalidatePos();
376             }
377         }
378 	}
379 }
380 
381 SwCntntNode *SwTxtNode::SplitCntntNode( const SwPosition &rPos )
382 {
383 	// lege den Node "vor" mir an
384     const xub_StrLen nSplitPos = rPos.nContent.GetIndex();
385     const xub_StrLen nTxtLen = m_Text.Len();
386     SwTxtNode* const pNode =
387         _MakeNewTxtNode( rPos.nNode, sal_False, nSplitPos==nTxtLen );
388 
389     // the first paragraph gets the XmlId,
390     // _except_ if it is empty and the second is not empty
391     if (nSplitPos != 0) {
392         pNode->RegisterAsCopyOf(*this, true);
393         if (nSplitPos == nTxtLen)
394         {
395             this->RemoveMetadataReference();
396             // NB: SwUndoSplitNode will call pNode->JoinNext,
397             // which is sufficient even in this case!
398         }
399     }
400 
401     // --> OD 2008-03-27 #refactorlists#
402 //    // --> OD 2007-07-09 #i77372#
403 //    // reset numbering attribute at current node, only if it is numbered.
404 //    if ( GetNumRule() != NULL )
405 //    {
406 //        SetRestart(false);
407 //        SetStart(1);
408 //        SetCounted(true);
409 //    }
410     ResetAttr( RES_PARATR_LIST_ISRESTART );
411     ResetAttr( RES_PARATR_LIST_RESTARTVALUE );
412     ResetAttr( RES_PARATR_LIST_ISCOUNTED );
413     if ( GetNumRule() == 0 )
414     {
415         ResetAttr( RES_PARATR_LIST_ID );
416         ResetAttr( RES_PARATR_LIST_LEVEL );
417     }
418     // <--
419 
420     if ( GetDepends() && m_Text.Len() && (nTxtLen / 2) < nSplitPos )
421     {
422 // JP 25.04.95: Optimierung fuer SplitNode:
423 //				Wird am Ende vom Node gesplittet, dann verschiebe die
424 //				Frames vom akt. auf den neuen und erzeuge fuer den akt.
425 //				neue. Dadurch entfaellt das neu aufbauen vom Layout.
426 
427 		LockModify();	// Benachrichtigungen abschalten
428 
429 		// werden FlyFrames mit verschoben, so muessen diese nicht ihre
430 		// Frames zerstoeren. Im SwTxtFly::SetAnchor wird es abgefragt!
431         if ( HasHints() )
432         {
433             pNode->GetOrCreateSwpHints().SetInSplitNode(true);
434         }
435 
436 		//Ersten Teil des Inhalts in den neuen Node uebertragen und
437 		//im alten Node loeschen.
438 		SwIndex aIdx( this );
439         CutText( pNode, aIdx, nSplitPos );
440 
441 		if( GetWrong() )
442         {
443             pNode->SetWrong( GetWrong()->SplitList( nSplitPos ) );
444         }
445         SetWrongDirty( true );
446 
447         if( GetGrammarCheck() )
448         {
449             pNode->SetGrammarCheck( GetGrammarCheck()->SplitGrammarList( nSplitPos ) );
450         }
451         SetGrammarCheckDirty( true );
452 
453         SetWordCountDirty( true );
454 
455         // SMARTTAGS
456         if( GetSmartTags() )
457         {
458             pNode->SetSmartTags( GetSmartTags()->SplitList( nSplitPos ) );
459         }
460         SetSmartTagDirty( true );
461 
462         if ( pNode->HasHints() )
463         {
464             if ( pNode->m_pSwpHints->CanBeDeleted() )
465             {
466                 delete pNode->m_pSwpHints;
467                 pNode->m_pSwpHints = 0;
468             }
469             else
470             {
471                 pNode->m_pSwpHints->SetInSplitNode(false);
472             }
473 
474 			// alle zeichengebundenen Rahmen, die im neuen Absatz laden
475 			// muessen aus den alten Frame entfernt werden:
476 			// JP 01.10.96: alle leeren und nicht zu expandierenden
477 			//				Attribute loeschen
478             if ( HasHints() )
479 			{
480                 for ( sal_uInt16 j = m_pSwpHints->Count(); j; )
481                 {
482                     SwTxtAttr* const pHt = m_pSwpHints->GetTextHint( --j );
483                     if ( RES_TXTATR_FLYCNT == pHt ->Which() )
484                     {
485                         pHt->GetFlyCnt().GetFrmFmt()->DelFrms();
486                     }
487                     else if ( pHt->DontExpand() )
488                     {
489                         const xub_StrLen* const pEnd = pHt->GetEnd();
490                         if (pEnd && *pHt->GetStart() == *pEnd )
491                         {
492                             // delete it!
493                             m_pSwpHints->DeleteAtPos( j );
494                             DestroyAttr( pHt );
495                         }
496                     }
497                 }
498 			}
499 
500 		}
501 
502 		SwIterator<SwCntntFrm,SwTxtNode> aIter( *this );
503         for( SwCntntFrm* pFrm = aIter.First(); pFrm; pFrm = aIter.Next() )
504 		{
505             pFrm->RegisterToNode( *pNode );
506 	        if( pFrm->IsTxtFrm() && !pFrm->IsFollow() && ((SwTxtFrm*)pFrm)->GetOfst() )
507 				((SwTxtFrm*)pFrm)->SetOfst( 0 );
508         }
509 
510 		if ( IsInCache() )
511 		{
512 			SwFrm::GetCache().Delete( this );
513 			SetInCache( sal_False );
514 		}
515 
516 		UnlockModify();	// Benachrichtigungen wieder freischalten
517 
518 		// If there is an accessible layout we must call modify even
519 		// with length zero, because we have to notify about the changed
520 		// text node.
521 		const SwRootFrm *pRootFrm;
522         if ( (nTxtLen != nSplitPos) ||
523 			( (pRootFrm = pNode->GetDoc()->GetCurrentLayout()) != 0 &&
524               pRootFrm->IsAnyShellAccessible() ) )	//swmod 080218
525 		{
526 			// dann sage den Frames noch, das am Ende etwas "geloescht" wurde
527 			if( 1 == nTxtLen - nSplitPos )
528 			{
529 				SwDelChr aHint( nSplitPos );
530 				pNode->NotifyClients( 0, &aHint );
531 			}
532 			else
533 			{
534 				SwDelTxt aHint( nSplitPos, nTxtLen - nSplitPos );
535 				pNode->NotifyClients( 0, &aHint );
536 			}
537 		}
538         if ( HasHints() )
539         {
540 			MoveTxtAttr_To_AttrSet();
541         }
542 		pNode->MakeFrms( *this );		// neue Frames anlegen.
543 		lcl_ChangeFtnRef( *this );
544 	}
545 	else
546 	{
547         SwWrongList *pList = GetWrong();
548         SetWrong( 0, false );
549         SetWrongDirty( true );
550 
551         SwGrammarMarkUp *pList3 = GetGrammarCheck();
552         SetGrammarCheck( 0, false );
553         SetGrammarCheckDirty( true );
554 
555         SetWordCountDirty( true );
556 
557         // SMARTTAGS
558         SwWrongList *pList2 = GetSmartTags();
559         SetSmartTags( 0, false );
560         SetSmartTagDirty( true );
561 
562 		SwIndex aIdx( this );
563         CutText( pNode, aIdx, nSplitPos );
564 
565 		// JP 01.10.96: alle leeren und nicht zu expandierenden
566 		//				Attribute loeschen
567         if ( HasHints() )
568 		{
569             for ( sal_uInt16 j = m_pSwpHints->Count(); j; )
570             {
571                 SwTxtAttr* const pHt = m_pSwpHints->GetTextHint( --j );
572                 const xub_StrLen* const pEnd = pHt->GetEnd();
573                 if ( pHt->DontExpand() && pEnd && (*pHt->GetStart() == *pEnd) )
574                 {
575                     // delete it!
576                     m_pSwpHints->DeleteAtPos( j );
577 					DestroyAttr( pHt );
578 				}
579             }
580 			MoveTxtAttr_To_AttrSet();
581 		}
582 
583         if( pList )
584         {
585             pNode->SetWrong( pList->SplitList( nSplitPos ) );
586             SetWrong( pList, false );
587         }
588 
589         if( pList3 )
590         {
591             pNode->SetGrammarCheck( pList3->SplitGrammarList( nSplitPos ) );
592             SetGrammarCheck( pList3, false );
593         }
594 
595         // SMARTTAGS
596         if( pList2 )
597         {
598             pNode->SetSmartTags( pList2->SplitList( nSplitPos ) );
599             SetSmartTags( pList2, false );
600         }
601 
602 		if ( GetDepends() )
603         {
604 			MakeFrms( *pNode );		// neue Frames anlegen.
605         }
606 		lcl_ChangeFtnRef( *pNode );
607 	}
608 
609 	{
610 		//Hint fuer Pagedesc versenden. Das mueste eigntlich das Layout im
611 		//Paste der Frames selbst erledigen, aber das fuehrt dann wiederum
612 		//zu weiteren Folgefehlern, die mit Laufzeitkosten geloest werden
613 		//muesten. #56977# #55001# #56135#
614 		const SfxPoolItem *pItem;
615 		if( GetDepends() && SFX_ITEM_SET == pNode->GetSwAttrSet().
616 			GetItemState( RES_PAGEDESC, sal_True, &pItem ) )
617         {
618 			pNode->ModifyNotification( (SfxPoolItem*)pItem, (SfxPoolItem*)pItem );
619         }
620 	}
621 	return pNode;
622 }
623 
624 void SwTxtNode::MoveTxtAttr_To_AttrSet()
625 {
626     ASSERT( m_pSwpHints, "MoveTxtAttr_To_AttrSet without SwpHints?" );
627     for ( sal_uInt16 i = 0; m_pSwpHints && i < m_pSwpHints->Count(); ++i )
628     {
629         SwTxtAttr *pHt = m_pSwpHints->GetTextHint(i);
630 
631 		if( *pHt->GetStart() )
632 			break;
633 
634 		const xub_StrLen* pHtEndIdx = pHt->GetEnd();
635 
636 		if( !pHtEndIdx )
637 			continue;
638 
639         if ( *pHtEndIdx < m_Text.Len() || pHt->IsCharFmtAttr() )
640 			break;
641 
642 		if( !pHt->IsDontMoveAttr() &&
643             SetAttr( pHt->GetAttr() ) )
644 		{
645             m_pSwpHints->DeleteAtPos(i);
646 			DestroyAttr( pHt );
647 			--i;
648 		}
649 	}
650 
651 }
652 
653 SwCntntNode *SwTxtNode::JoinNext()
654 {
655 	SwNodes& rNds = GetNodes();
656 	SwNodeIndex aIdx( *this );
657 	if( SwCntntNode::CanJoinNext( &aIdx ) )
658 	{
659 		SwDoc* pDoc = rNds.GetDoc();
660 		SvULongs aBkmkArr( 15, 15 );
661 		_SaveCntntIdx( pDoc, aIdx.GetIndex(), USHRT_MAX, aBkmkArr, SAVEFLY );
662 		SwTxtNode *pTxtNode = aIdx.GetNode().GetTxtNode();
663         xub_StrLen nOldLen = m_Text.Len();
664 
665         // METADATA: merge
666         this->JoinMetadatable(*pTxtNode, !this->Len(), !pTxtNode->Len());
667 
668         SwWrongList *pList = GetWrong();
669         if( pList )
670         {
671             pList->JoinList( pTxtNode->GetWrong(), nOldLen );
672             SetWrongDirty( true );
673             SetWrong( 0, false );
674         }
675         else
676         {
677             pList = pTxtNode->GetWrong();
678             if( pList )
679             {
680                 pList->Move( 0, nOldLen );
681                 SetWrongDirty( true );
682                 pTxtNode->SetWrong( 0, false );
683             }
684         }
685 
686         SwGrammarMarkUp *pList3 = GetGrammarCheck();
687         if( pList3 )
688         {
689             pList3->JoinGrammarList( pTxtNode->GetGrammarCheck(), nOldLen );
690             SetGrammarCheckDirty( true );
691             SetGrammarCheck( 0, false );
692         }
693         else
694         {
695             pList3 = pTxtNode->GetGrammarCheck();
696             if( pList3 )
697             {
698                 pList3->MoveGrammar( 0, nOldLen );
699                 SetGrammarCheckDirty( true );
700                 pTxtNode->SetGrammarCheck( 0, false );
701             }
702         }
703 
704         // SMARTTAGS
705         SwWrongList *pList2 = GetSmartTags();
706         if( pList2 )
707         {
708             pList2->JoinList( pTxtNode->GetSmartTags(), nOldLen );
709             SetSmartTagDirty( true );
710             SetSmartTags( 0, false );
711         }
712         else
713         {
714             pList2 = pTxtNode->GetSmartTags();
715             if( pList2 )
716             {
717                 pList2->Move( 0, nOldLen );
718                 SetSmartTagDirty( true );
719                 pTxtNode->SetSmartTags( 0, false );
720             }
721         }
722 
723         { // wg. SwIndex
724             pTxtNode->CutText( this, SwIndex(pTxtNode), pTxtNode->Len() );
725         }
726 		// verschiebe noch alle Bookmarks/TOXMarks
727 		if( aBkmkArr.Count() )
728 			_RestoreCntntIdx( pDoc, aBkmkArr, GetIndex(), nOldLen );
729 
730 		if( pTxtNode->HasAnyIndex() )
731 		{
732 			// alle Crsr/StkCrsr/UnoCrsr aus dem Loeschbereich verschieben
733 			pDoc->CorrAbs( aIdx, SwPosition( *this ), nOldLen, sal_True );
734 		}
735 		rNds.Delete(aIdx);
736         SetWrong( pList, false );
737         SetGrammarCheck( pList3, false );
738         SetSmartTags( pList2, false ); // SMARTTAGS
739 		InvalidateNumRule();
740 	}
741 	else {
742 		ASSERT( sal_False, "kein TxtNode." );
743     }
744 
745 	return this;
746 }
747 
748 SwCntntNode *SwTxtNode::JoinPrev()
749 {
750 	SwNodes& rNds = GetNodes();
751 	SwNodeIndex aIdx( *this );
752 	if( SwCntntNode::CanJoinPrev( &aIdx ) )
753 	{
754 		SwDoc* pDoc = rNds.GetDoc();
755 		SvULongs aBkmkArr( 15, 15 );
756 		_SaveCntntIdx( pDoc, aIdx.GetIndex(), USHRT_MAX, aBkmkArr, SAVEFLY );
757 		SwTxtNode *pTxtNode = aIdx.GetNode().GetTxtNode();
758 		xub_StrLen nLen = pTxtNode->Len();
759 
760         SwWrongList *pList = pTxtNode->GetWrong();
761         if( pList )
762         {
763             pList->JoinList( GetWrong(), Len() );
764             SetWrongDirty( true );
765             pTxtNode->SetWrong( 0, false );
766             SetWrong( NULL );
767         }
768         else
769         {
770             pList = GetWrong();
771             if( pList )
772             {
773                 pList->Move( 0, nLen );
774                 SetWrongDirty( true );
775                 SetWrong( 0, false );
776             }
777         }
778 
779         SwGrammarMarkUp *pList3 = pTxtNode->GetGrammarCheck();
780         if( pList3 )
781         {
782             pList3->JoinGrammarList( GetGrammarCheck(), Len() );
783             SetGrammarCheckDirty( true );
784             pTxtNode->SetGrammarCheck( 0, false );
785             SetGrammarCheck( NULL );
786         }
787         else
788         {
789             pList3 = GetGrammarCheck();
790             if( pList3 )
791             {
792                 pList3->MoveGrammar( 0, nLen );
793                 SetGrammarCheckDirty( true );
794                 SetGrammarCheck( 0, false );
795             }
796         }
797 
798         // SMARTTAGS
799         SwWrongList *pList2 = pTxtNode->GetSmartTags();
800         if( pList2 )
801         {
802             pList2->JoinList( GetSmartTags(), Len() );
803             SetSmartTagDirty( true );
804             pTxtNode->SetSmartTags( 0, false );
805             SetSmartTags( NULL );
806         }
807         else
808         {
809             pList2 = GetSmartTags();
810             if( pList2 )
811             {
812                 pList2->Move( 0, nLen );
813                 SetSmartTagDirty( true );
814                 SetSmartTags( 0, false );
815             }
816         }
817 
818 		{ // wg. SwIndex
819             pTxtNode->CutText( this, SwIndex(this), SwIndex(pTxtNode), nLen );
820         }
821 		// verschiebe noch alle Bookmarks/TOXMarks
822 		if( aBkmkArr.Count() )
823 			_RestoreCntntIdx( pDoc, aBkmkArr, GetIndex() );
824 
825 		if( pTxtNode->HasAnyIndex() )
826 		{
827 			// alle Crsr/StkCrsr/UnoCrsr aus dem Loeschbereich verschieben
828 			pDoc->CorrAbs( aIdx, SwPosition( *this ), nLen, sal_True );
829 		}
830 		rNds.Delete(aIdx);
831         SetWrong( pList, false );
832         SetGrammarCheck( pList3, false );
833         SetSmartTags( pList2, false );
834 		InvalidateNumRule();
835 	}
836 	else {
837 		ASSERT( sal_False, "kein TxtNode." );
838     }
839 
840 	return this;
841 }
842 
843 // erzeugt einen AttrSet mit Bereichen fuer Frame-/Para/Char-Attributen
844 void SwTxtNode::NewAttrSet( SwAttrPool& rPool )
845 {
846     ASSERT( !mpAttrSet.get(), "AttrSet ist doch gesetzt" );
847     SwAttrSet aNewAttrSet( rPool, aTxtNodeSetRange );
848 
849     // put names of parent style and conditional style:
850     const SwFmtColl* pAnyFmtColl = &GetAnyFmtColl();
851     const SwFmtColl* pFmtColl = GetFmtColl();
852     String sVal;
853 	SwStyleNameMapper::FillProgName( pAnyFmtColl->GetName(), sVal, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL, sal_True );
854     SfxStringItem aAnyFmtColl( RES_FRMATR_STYLE_NAME, sVal );
855     if ( pFmtColl != pAnyFmtColl )
856     	SwStyleNameMapper::FillProgName( pFmtColl->GetName(), sVal, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL, sal_True );
857     SfxStringItem aFmtColl( RES_FRMATR_CONDITIONAL_STYLE_NAME, sVal );
858     aNewAttrSet.Put( aAnyFmtColl );
859     aNewAttrSet.Put( aFmtColl );
860 
861     aNewAttrSet.SetParent( &pAnyFmtColl->GetAttrSet() );
862     mpAttrSet = GetDoc()->GetIStyleAccess().getAutomaticStyle( aNewAttrSet, IStyleAccess::AUTO_STYLE_PARA );
863 }
864 
865 
866 // override SwIndexReg::Update => text hints do not need SwIndex for start/end!
867 void SwTxtNode::Update( SwIndex const & rPos, const xub_StrLen nChangeLen,
868                         const bool bNegative, const bool bDelete )
869 {
870 	SetAutoCompleteWordDirty( sal_True );
871 
872     ::std::auto_ptr<TmpHints> pCollector;
873     const xub_StrLen nChangePos = rPos.GetIndex();
874 
875     if ( HasHints() )
876     {
877         if ( bNegative )
878         {
879             const xub_StrLen nChangeEnd = nChangePos + nChangeLen;
880             for ( sal_uInt16 n = 0; n < m_pSwpHints->Count(); ++n )
881             {
882                 SwTxtAttr * const pHint = m_pSwpHints->GetTextHint(n);
883                 xub_StrLen * const pStart = pHint->GetStart();
884                 if ( *pStart > nChangePos )
885                 {
886                     if ( *pStart > nChangeEnd )
887                     {
888                          *pStart = *pStart - nChangeLen;
889                     }
890                     else
891                     {
892                          *pStart = nChangePos;
893                     }
894                 }
895 
896                 xub_StrLen * const pEnd = pHint->GetEnd();
897                 if (pEnd)
898                 {
899                     if ( *pEnd > nChangePos )
900                     {
901                         if( *pEnd > nChangeEnd )
902                         {
903                             *pEnd = *pEnd - nChangeLen;
904                         }
905                         else
906                         {
907                             *pEnd = nChangePos;
908                         }
909                     }
910                 }
911             }
912 
913             m_pSwpHints->MergePortions( *this );
914         }
915         else
916         {
917             bool bNoExp = false;
918             bool bResort = false;
919 			const sal_uInt16 coArrSz = static_cast<sal_uInt16>(RES_TXTATR_WITHEND_END) -
920                                    static_cast<sal_uInt16>(RES_CHRATR_BEGIN);
921 
922 			sal_Bool aDontExp[ coArrSz ];
923 			memset( &aDontExp, 0, coArrSz * sizeof(sal_Bool) );
924 
925             for ( sal_uInt16 n = 0; n < m_pSwpHints->Count(); ++n )
926             {
927                 SwTxtAttr * const pHint = m_pSwpHints->GetTextHint(n);
928                 xub_StrLen * const pStart = pHint->GetStart();
929                 xub_StrLen * const pEnd = pHint->GetEnd();
930                 if ( *pStart >= nChangePos )
931                 {
932                     *pStart = *pStart + nChangeLen;
933                     if ( pEnd )
934                     {
935                         *pEnd = *pEnd + nChangeLen;
936                     }
937                 }
938                 else if ( pEnd && (*pEnd >= nChangePos) )
939                 {
940                     if ( (*pEnd > nChangePos) || IsIgnoreDontExpand() )
941                     {
942                         *pEnd = *pEnd + nChangeLen;
943                     }
944                     else // *pEnd == nChangePos
945                     {
946                         sal_uInt16 nWhPos;
947                         const sal_uInt16 nWhich = pHint->Which();
948 
949                         ASSERT(!isCHRATR(nWhich), "Update: char attr hint?");
950                         if (isCHRATR(nWhich) || isTXTATR_WITHEND(nWhich))
951                         {
952                             nWhPos = static_cast<sal_uInt16>(nWhich -
953                                         RES_CHRATR_BEGIN);
954                         }
955 						else
956 							continue;
957 
958 						if( aDontExp[ nWhPos ] )
959 							continue;
960 
961                         if ( pHint->DontExpand() )
962                         {
963                             pHint->SetDontExpand( false );
964                             bResort = true;
965                             if ( pHint->IsCharFmtAttr() )
966                             {
967                                 bNoExp = true;
968 								aDontExp[ static_cast<sal_uInt16>(RES_TXTATR_CHARFMT) - static_cast<sal_uInt16>(RES_CHRATR_BEGIN) ]
969 									= sal_True;
970 								aDontExp[ static_cast<sal_uInt16>(RES_TXTATR_INETFMT) - static_cast<sal_uInt16>(RES_CHRATR_BEGIN) ]
971 									= sal_True;
972 							}
973 							else
974 								aDontExp[ nWhPos ] = sal_True;
975 						}
976 						else if( bNoExp )
977 						{
978                              if ( !pCollector.get() )
979                              {
980                                 pCollector.reset( new TmpHints );
981                              }
982 							 sal_uInt16 nCollCnt = pCollector->Count();
983 							 for( sal_uInt16 i = 0; i < nCollCnt; ++i )
984 							 {
985 								SwTxtAttr *pTmp = (*pCollector)[ i ];
986 								if( nWhich == pTmp->Which() )
987 								{
988 									pCollector->Remove( i );
989                                     SwTxtAttr::Destroy( pTmp,
990                                         GetDoc()->GetAttrPool() );
991 									break;
992 								}
993 							 }
994                              SwTxtAttr * const pTmp = MakeTxtAttr( *GetDoc(),
995                                  pHint->GetAttr(),
996                                  nChangePos, nChangePos + nChangeLen);
997 							 pCollector->C40_INSERT( SwTxtAttr, pTmp, pCollector->Count() );
998                         }
999                         else
1000                         {
1001                             *pEnd = *pEnd + nChangeLen;
1002                         }
1003                     }
1004                 }
1005             }
1006             if ( bResort )
1007             {
1008                 m_pSwpHints->Resort();
1009             }
1010         }
1011     }
1012 
1013 	SwIndexReg aTmpIdxReg;
1014     if ( !bNegative && !bDelete )
1015     {
1016 		const SwRedlineTbl& rTbl = GetDoc()->GetRedlineTbl();
1017         for ( sal_uInt16 i = 0; i < rTbl.Count(); ++i )
1018         {
1019             SwRedline *const pRedl = rTbl[ i ];
1020             if ( pRedl->HasMark() )
1021             {
1022                 SwPosition* const pEnd = pRedl->End();
1023                 if ( this == &pEnd->nNode.GetNode() &&
1024                      *pRedl->GetPoint() != *pRedl->GetMark() )
1025                 {
1026                     SwIndex & rIdx = pEnd->nContent;
1027                     if (nChangePos == rIdx.GetIndex())
1028                     {
1029                         rIdx.Assign( &aTmpIdxReg, rIdx.GetIndex() );
1030                     }
1031                 }
1032             }
1033             else if ( this == &pRedl->GetPoint()->nNode.GetNode() )
1034             {
1035                 SwIndex & rIdx = pRedl->GetPoint()->nContent;
1036                 if (nChangePos == rIdx.GetIndex())
1037                 {
1038                     rIdx.Assign( &aTmpIdxReg, rIdx.GetIndex() );
1039                     // mst: FIXME: why does this adjust the unused position???
1040                     SwIndex * pIdx;
1041                     if ( &pRedl->GetBound( true ) == pRedl->GetPoint() )
1042                     {
1043                         pRedl->GetBound( false ) = pRedl->GetBound( true );
1044                         pIdx = &pRedl->GetBound( false ).nContent;
1045                     }
1046                     else
1047                     {
1048                         pRedl->GetBound( true ) = pRedl->GetBound( false );
1049                         pIdx = &pRedl->GetBound( true ).nContent;
1050                     }
1051                     pIdx->Assign( &aTmpIdxReg, pIdx->GetIndex() );
1052                 }
1053             }
1054         }
1055 
1056         const IDocumentMarkAccess* const pMarkAccess = getIDocumentMarkAccess();
1057         for(IDocumentMarkAccess::const_iterator_t ppMark =
1058                 pMarkAccess->getMarksBegin();
1059             ppMark != pMarkAccess->getMarksEnd();
1060             ppMark++)
1061         {
1062             // Bookmarks must never grow to either side, when
1063             // editing (directly) to the left or right (#i29942#)!
1064             // And a bookmark with same start and end must remain
1065             // to the left of the inserted text (used in XML import).
1066             const ::sw::mark::IMark* const pMark = ppMark->get();
1067             const SwPosition* pEnd = &pMark->GetMarkEnd();
1068             SwIndex & rIdx = const_cast<SwIndex&>(pEnd->nContent);
1069             if( this == &pEnd->nNode.GetNode() &&
1070                 rPos.GetIndex() == rIdx.GetIndex() )
1071             {
1072                 rIdx.Assign( &aTmpIdxReg, rIdx.GetIndex() );
1073             }
1074         }
1075     }
1076 
1077     // base class
1078     SwIndexReg::Update( rPos, nChangeLen, bNegative, bDelete );
1079 
1080     if ( pCollector.get() )
1081     {
1082         const sal_uInt16 nCount = pCollector->Count();
1083         for ( sal_uInt16 i = 0; i < nCount; ++i )
1084         {
1085             m_pSwpHints->TryInsertHint( (*pCollector)[ i ], *this );
1086         }
1087     }
1088 
1089 	aTmpIdxReg.MoveTo( *this );
1090 }
1091 
1092 void SwTxtNode::_ChgTxtCollUpdateNum( const SwTxtFmtColl *pOldColl,
1093 										const SwTxtFmtColl *pNewColl)
1094 {
1095 	SwDoc* pDoc = GetDoc();
1096 	ASSERT( pDoc, "Kein Doc?" );
1097 	// erfrage die OutlineLevel und update gegebenenfalls das Nodes-Array,
1098 	// falls sich die Level geaendert haben !
1099 	//const sal_uInt8 nOldLevel = pOldColl ? pOldColl->GetOutlineLevel():NO_NUMBERING;//#outline level,removed by zhaojianwei
1100 	//const sal_uInt8 nNewLevel = pNewColl ? pNewColl->GetOutlineLevel():NO_NUMBERING;//<-end,zhaojianwei
1101 	const int nOldLevel = pOldColl && pOldColl->IsAssignedToListLevelOfOutlineStyle() ?
1102 	                 pOldColl->GetAssignedOutlineStyleLevel() : MAXLEVEL;
1103     const int nNewLevel = pNewColl && pNewColl->IsAssignedToListLevelOfOutlineStyle() ?
1104 					 pNewColl->GetAssignedOutlineStyleLevel() : MAXLEVEL;
1105 
1106 //	if ( NO_NUMBERING != nNewLevel )	//#outline level,zhaojianwei
1107 	if ( MAXLEVEL != nNewLevel )	//<-end,zhaojianwei
1108     {
1109         SetAttrListLevel(nNewLevel);
1110     }
1111 
1112 	{
1113         if (pDoc)
1114             pDoc->GetNodes().UpdateOutlineNode(*this);
1115     }
1116 
1117 
1118 	SwNodes& rNds = GetNodes();
1119 	// Update beim Level 0 noch die Fussnoten !!
1120 	if( ( !nNewLevel || !nOldLevel) && pDoc->GetFtnIdxs().Count() &&
1121 		FTNNUM_CHAPTER == pDoc->GetFtnInfo().eNum &&
1122 		rNds.IsDocNodes() )
1123 	{
1124 		SwNodeIndex aTmpIndex( rNds, GetIndex());
1125 
1126 		pDoc->GetFtnIdxs().UpdateFtn( aTmpIndex);
1127 	}
1128 
1129 //FEATURE::CONDCOLL
1130 	if( /*pOldColl != pNewColl && pNewColl && */
1131 		RES_CONDTXTFMTCOLL == pNewColl->Which() )
1132 	{
1133 		// Erfrage die akt. Condition des TextNodes:
1134 		ChkCondColl();
1135 	}
1136 //FEATURE::CONDCOLL
1137 }
1138 
1139 // Wenn man sich genau am Ende einer Text- bzw. INetvorlage befindet,
1140 // bekommt diese das DontExpand-Flag verpasst
1141 
1142 sal_Bool SwTxtNode::DontExpandFmt( const SwIndex& rIdx, bool bFlag,
1143 								sal_Bool bFmtToTxtAttributes )
1144 {
1145 	const xub_StrLen nIdx = rIdx.GetIndex();
1146     if ( bFmtToTxtAttributes && nIdx == m_Text.Len() )
1147     {
1148         FmtToTxtAttr( this );
1149     }
1150 
1151 	sal_Bool bRet = sal_False;
1152     if ( HasHints() )
1153     {
1154         const sal_uInt16 nEndCnt = m_pSwpHints->GetEndCount();
1155 		sal_uInt16 nPos = nEndCnt;
1156 		while( nPos )
1157         {
1158             SwTxtAttr *pTmp = m_pSwpHints->GetEnd( --nPos );
1159 			xub_StrLen *pEnd = pTmp->GetEnd();
1160 			if( !pEnd || *pEnd > nIdx )
1161 				continue;
1162 			if( nIdx != *pEnd )
1163 				nPos = 0;
1164 			else if( bFlag != pTmp->DontExpand() && !pTmp->IsLockExpandFlag()
1165 					 && *pEnd > *pTmp->GetStart())
1166 			{
1167 				bRet = sal_True;
1168                 m_pSwpHints->NoteInHistory( pTmp );
1169 				pTmp->SetDontExpand( bFlag );
1170 			}
1171 		}
1172 	}
1173 	return bRet;
1174 }
1175 
1176 static bool lcl_GetTxtAttrDefault(xub_StrLen const nIndex,
1177     xub_StrLen const nHintStart, xub_StrLen const nHintEnd)
1178 {
1179     return ((nHintStart <= nIndex) && (nIndex <  nHintEnd));
1180 }
1181 static bool lcl_GetTxtAttrExpand(xub_StrLen const nIndex,
1182     xub_StrLen const nHintStart, xub_StrLen const nHintEnd)
1183 {
1184     return ((nHintStart <  nIndex) && (nIndex <= nHintEnd));
1185 }
1186 static bool lcl_GetTxtAttrParent(xub_StrLen const nIndex,
1187     xub_StrLen const nHintStart, xub_StrLen const nHintEnd)
1188 {
1189     return ((nHintStart <  nIndex) && (nIndex <  nHintEnd));
1190 }
1191 
1192 static void
1193 lcl_GetTxtAttrs(
1194     ::std::vector<SwTxtAttr *> *const pVector, SwTxtAttr **const ppTxtAttr,
1195     SwpHints *const pSwpHints,
1196     xub_StrLen const nIndex, RES_TXTATR const nWhich,
1197     enum SwTxtNode::GetTxtAttrMode const eMode)
1198 {
1199     sal_uInt16 const nSize = (pSwpHints) ? pSwpHints->Count() : 0;
1200     xub_StrLen nPreviousIndex(0); // index of last hint with nWhich
1201     bool (*pMatchFunc)(xub_StrLen const, xub_StrLen const, xub_StrLen const)=0;
1202     switch (eMode)
1203     {
1204         case SwTxtNode::DEFAULT:   pMatchFunc = &lcl_GetTxtAttrDefault; break;
1205         case SwTxtNode::EXPAND:    pMatchFunc = &lcl_GetTxtAttrExpand;  break;
1206         case SwTxtNode::PARENT:    pMatchFunc = &lcl_GetTxtAttrParent;  break;
1207         default: OSL_ASSERT(false);
1208     }
1209 
1210 	for( sal_uInt16 i = 0; i < nSize; ++i )
1211     {
1212         SwTxtAttr *const pHint = pSwpHints->GetTextHint(i);
1213         xub_StrLen const nHintStart( *(pHint->GetStart()) );
1214         if (nIndex < nHintStart)
1215         {
1216             return; // hints are sorted by start, so we are done...
1217         }
1218 
1219         if (pHint->Which() != nWhich)
1220         {
1221             continue;
1222         }
1223 
1224         xub_StrLen const*const pEndIdx = pHint->GetEnd();
1225         ASSERT(pEndIdx || pHint->HasDummyChar(),
1226                 "hint with no end and no dummy char?");
1227 			// Wenn bExpand gesetzt ist, wird das Verhalten bei Eingabe
1228 			// simuliert, d.h. der Start wuede verschoben, das Ende expandiert,
1229         bool const bContained( (pEndIdx)
1230             ? (*pMatchFunc)(nIndex, nHintStart, *pEndIdx)
1231             : (nHintStart == nIndex) );
1232         if (bContained)
1233         {
1234             if (pVector)
1235             {
1236                 if (nPreviousIndex < nHintStart)
1237                 {
1238                     pVector->clear(); // clear hints that are outside pHint
1239                     nPreviousIndex = nHintStart;
1240                 }
1241                 pVector->push_back(pHint);
1242             }
1243             else
1244             {
1245                 *ppTxtAttr = pHint; // and possibly overwrite outer hint
1246             }
1247             if (!pEndIdx)
1248             {
1249                 break;
1250             }
1251         }
1252     }
1253 }
1254 
1255 ::std::vector<SwTxtAttr *>
1256 SwTxtNode::GetTxtAttrsAt(xub_StrLen const nIndex, RES_TXTATR const nWhich,
1257                         enum GetTxtAttrMode const eMode) const
1258 {
1259     ::std::vector<SwTxtAttr *> ret;
1260     lcl_GetTxtAttrs(& ret, 0, m_pSwpHints, nIndex, nWhich, eMode);
1261     return ret;
1262 }
1263 
1264 SwTxtAttr *
1265 SwTxtNode::GetTxtAttrAt(xub_StrLen const nIndex, RES_TXTATR const nWhich,
1266                         enum GetTxtAttrMode const eMode) const
1267 {
1268     ASSERT(    (nWhich == RES_TXTATR_META)
1269             || (nWhich == RES_TXTATR_METAFIELD)
1270             || (nWhich == RES_TXTATR_AUTOFMT)
1271             || (nWhich == RES_TXTATR_INETFMT)
1272             || (nWhich == RES_TXTATR_CJK_RUBY)
1273             || (nWhich == RES_TXTATR_UNKNOWN_CONTAINER),
1274         "GetTxtAttrAt() will give wrong result for this hint!");
1275 
1276     SwTxtAttr * pRet(0);
1277     lcl_GetTxtAttrs(0, & pRet, m_pSwpHints, nIndex, nWhich, eMode);
1278     return pRet;
1279 }
1280 
1281 /*************************************************************************
1282  *							CopyHint()
1283  *************************************************************************/
1284 
1285 SwCharFmt* lcl_FindCharFmt( const SwCharFmts* pCharFmts, const XubString& rName )
1286 {
1287 	if( rName.Len() )
1288 	{
1289 		SwCharFmt* pFmt;
1290 		sal_uInt16 nArrLen = pCharFmts->Count();
1291 		for( sal_uInt16 i = 1; i < nArrLen; i++ )
1292 		{
1293 			pFmt = (*pCharFmts)[ i ];
1294 			if( pFmt->GetName().CompareTo( rName ) == COMPARE_EQUAL )
1295 				return pFmt;
1296 		}
1297 	}
1298 	return NULL;
1299 }
1300 
1301 void lcl_CopyHint( const sal_uInt16 nWhich, const SwTxtAttr * const pHt,
1302     SwTxtAttr *const pNewHt, SwDoc *const pOtherDoc, SwTxtNode *const pDest )
1303 {
1304 	ASSERT( nWhich == pHt->Which(), "Falsche Hint-Id" );
1305 	switch( nWhich )
1306 	{
1307         // copy nodesarray section with footnote content
1308 		case RES_TXTATR_FTN :
1309             ASSERT(pDest, "lcl_CopyHint: no destination text node?");
1310             static_cast<const SwTxtFtn*>(pHt)->CopyFtn(
1311                 *static_cast<SwTxtFtn*>(pNewHt), *pDest);
1312 			break;
1313 
1314 		// Beim Kopieren von Feldern in andere Dokumente
1315 		// muessen die Felder bei ihren neuen Feldtypen angemeldet werden.
1316 
1317 		// TabellenFormel muessen relativ kopiert werden.
1318 		case RES_TXTATR_FIELD :
1319 			{
1320 				const SwFmtFld& rFld = pHt->GetFld();
1321 				if( pOtherDoc )
1322                 {
1323                     static_cast<const SwTxtFld*>(pHt)->CopyFld(
1324                         static_cast<SwTxtFld*>(pNewHt) );
1325                 }
1326 
1327 				// Tabellenformel ??
1328 				if( RES_TABLEFLD == rFld.GetFld()->GetTyp()->Which()
1329                     && static_cast<const SwTblField*>(rFld.GetFld())->IsIntrnlName())
1330 				{
1331 					// wandel die interne in eine externe Formel um
1332                     const SwTableNode* const pDstTblNd =
1333                         static_cast<const SwTxtFld*>(pHt)->
1334 											GetTxtNode().FindTableNode();
1335 					if( pDstTblNd )
1336 					{
1337                         SwTblField* const pTblFld = const_cast<SwTblField*>(
1338                             static_cast<const SwTblField*>(
1339                                 pNewHt->GetFld().GetFld()));
1340 						pTblFld->PtrToBoxNm( &pDstTblNd->GetTable() );
1341 					}
1342 				}
1343 			}
1344 			break;
1345 
1346 		case RES_TXTATR_TOXMARK :
1347 			if( pOtherDoc && pDest && pDest->GetpSwpHints()
1348 				&& USHRT_MAX != pDest->GetpSwpHints()->GetPos( pNewHt ) )
1349             {
1350 				// Beim Kopieren von TOXMarks(Client) in andere Dokumente
1351 				// muss der Verzeichnis (Modify) ausgetauscht werden
1352                 static_cast<SwTxtTOXMark*>(pNewHt)->CopyTOXMark( pOtherDoc );
1353             }
1354 			break;
1355 
1356 		case RES_TXTATR_CHARFMT :
1357 			// Wenn wir es mit einer Zeichenvorlage zu tun haben,
1358 			// muessen wir natuerlich auch die Formate kopieren.
1359 			if( pDest && pDest->GetpSwpHints()
1360 				&& USHRT_MAX != pDest->GetpSwpHints()->GetPos( pNewHt ) )
1361 			{
1362                 SwCharFmt* pFmt =
1363                     static_cast<SwCharFmt*>(pHt->GetCharFmt().GetCharFmt());
1364 
1365 				if( pFmt && pOtherDoc )
1366                 {
1367 					pFmt = pOtherDoc->CopyCharFmt( *pFmt );
1368                 }
1369                 const_cast<SwFmtCharFmt&>( static_cast<const SwFmtCharFmt&>(
1370                     pNewHt->GetCharFmt() ) ).SetCharFmt( pFmt );
1371 			}
1372 			break;
1373 		case RES_TXTATR_INETFMT :
1374         {
1375 			// Wenn wir es mit benutzerdefinierten INet-Zeichenvorlagen
1376 			// zu tun haben, muessen wir natuerlich auch die Formate kopieren.
1377 			if( pOtherDoc && pDest && pDest->GetpSwpHints()
1378 				&& USHRT_MAX != pDest->GetpSwpHints()->GetPos( pNewHt ) )
1379 			{
1380                 const SwDoc* const pDoc = static_cast<const SwTxtINetFmt*>(pHt)
1381                                             ->GetTxtNode().GetDoc();
1382                 if ( pDoc )
1383 				{
1384 					const SwCharFmts* pCharFmts = pDoc->GetCharFmts();
1385 					const SwFmtINetFmt& rFmt = pHt->GetINetFmt();
1386 					SwCharFmt* pFmt;
1387 					pFmt = lcl_FindCharFmt( pCharFmts, rFmt.GetINetFmt() );
1388 					if( pFmt )
1389 						pOtherDoc->CopyCharFmt( *pFmt );
1390 					pFmt = lcl_FindCharFmt( pCharFmts, rFmt.GetVisitedFmt() );
1391 					if( pFmt )
1392 						pOtherDoc->CopyCharFmt( *pFmt );
1393 				}
1394 			}
1395 			//JP 24.04.98: Bug 49753 - ein TextNode muss am Attribut
1396 			//				gesetzt sein, damit die Vorlagen erzeugt
1397 			//				werden koenne
1398             SwTxtINetFmt* const pINetHt = static_cast<SwTxtINetFmt*>(pNewHt);
1399             if ( !pINetHt->GetpTxtNode() )
1400             {
1401                 pINetHt->ChgTxtNode( pDest );
1402             }
1403 
1404 			//JP 22.10.97: Bug 44875 - Verbindung zum Format herstellen
1405             pINetHt->GetCharFmt();
1406 			break;
1407         }
1408         case RES_TXTATR_META:
1409         case RES_TXTATR_METAFIELD:
1410             OSL_ENSURE(pNewHt, "copying Meta should not fail!");
1411             OSL_ENSURE(pDest && (CH_TXTATR_INWORD ==
1412                                 pDest->GetTxt().GetChar(*pNewHt->GetStart())),
1413                    "missing CH_TXTATR?");
1414             break;
1415     }
1416 }
1417 
1418 /*************************************************************************
1419 |*	SwTxtNode::CopyAttr()
1420 |*	Beschreibung	kopiert Attribute an der Position nStart in pDest.
1421 |*	BP 7.6.93:		Es werden mit Absicht nur die Attribute _mit_ EndIdx
1422 |*					kopiert! CopyAttr wird vornehmlich dann gerufen,
1423 |*					wenn Attribute fuer einen Node mit leerem String
1424 |*					gesetzt werden sollen.
1425 *************************************************************************/
1426 
1427 void SwTxtNode::CopyAttr( SwTxtNode *pDest, const xub_StrLen nTxtStartIdx,
1428 						  const xub_StrLen nOldPos )
1429 {
1430     if ( HasHints() )    // keine Attribute, keine Kekse
1431     {
1432         SwDoc* const pOtherDoc = (pDest->GetDoc() != GetDoc()) ?
1433                 pDest->GetDoc() : 0;
1434 
1435         for ( sal_uInt16 i = 0; i < m_pSwpHints->Count(); i++ )
1436         {
1437             SwTxtAttr *const pHt = m_pSwpHints->GetTextHint(i);
1438             xub_StrLen const nAttrStartIdx = *pHt->GetStart();
1439             if ( nTxtStartIdx < nAttrStartIdx )
1440 				break;		// ueber das Textende, da nLen == 0
1441 
1442             const xub_StrLen *const pEndIdx = pHt->GetEnd();
1443             if ( pEndIdx && !pHt->HasDummyChar() )
1444 			{
1445 				if( ( *pEndIdx > nTxtStartIdx ||
1446 					  ( *pEndIdx == nTxtStartIdx &&
1447 						nAttrStartIdx == nTxtStartIdx ) ) )
1448 				{
1449                     sal_uInt16 const nWhich = pHt->Which();
1450                     if ( RES_TXTATR_REFMARK != nWhich )
1451                     {
1452                         // attribute in the area => copy
1453                         SwTxtAttr *const pNewHt = pDest->InsertItem(
1454                                 pHt->GetAttr(), nOldPos, nOldPos,
1455                                 nsSetAttrMode::SETATTR_IS_COPY);
1456                         if ( pNewHt )
1457                         {
1458                             lcl_CopyHint( nWhich, pHt, pNewHt,
1459                                     pOtherDoc, pDest );
1460                         }
1461                     }
1462 					else if( !pOtherDoc ? GetDoc()->IsCopyIsMove()
1463 										: 0 == pOtherDoc->GetRefMark(
1464 										pHt->GetRefMark().GetRefName() ) )
1465                     {
1466                         pDest->InsertItem( pHt->GetAttr(), nOldPos, nOldPos,
1467                                 nsSetAttrMode::SETATTR_IS_COPY);
1468                     }
1469 				}
1470 			}
1471 		}
1472 	}
1473 
1474 	if( this != pDest )
1475 	{
1476 		// Frames benachrichtigen, sonst verschwinden die Ftn-Nummern
1477 		SwUpdateAttr aHint( nOldPos, nOldPos, 0 );
1478 		pDest->ModifyNotification( 0, &aHint );
1479 	}
1480 }
1481 
1482 /*************************************************************************
1483 |*	SwTxtNode::Copy()
1484 |*	Beschreibung		kopiert Zeichen und Attibute in pDest,
1485 |*						wird angehaengt
1486 *************************************************************************/
1487 
1488 // --> OD 2008-11-18 #i96213#
1489 // introduction of new optional parameter to control, if all attributes have to be copied.
1490 void SwTxtNode::CopyText( SwTxtNode *const pDest,
1491                       const SwIndex &rStart,
1492                       const xub_StrLen nLen,
1493                       const bool bForceCopyOfAllAttrs )
1494 {
1495     SwIndex aIdx( pDest, pDest->m_Text.Len() );
1496     CopyText( pDest, aIdx, rStart, nLen, bForceCopyOfAllAttrs );
1497 }
1498 // <--
1499 
1500 // --> OD 2008-11-18 #i96213#
1501 // introduction of new optional parameter to control, if all attributes have to be copied.
1502 void SwTxtNode::CopyText( SwTxtNode *const pDest,
1503                       const SwIndex &rDestStart,
1504                       const SwIndex &rStart,
1505                       xub_StrLen nLen,
1506                       const bool bForceCopyOfAllAttrs )
1507 // <--
1508 {
1509 	xub_StrLen nTxtStartIdx = rStart.GetIndex();
1510 	xub_StrLen nDestStart = rDestStart.GetIndex();		// alte Pos merken
1511 
1512     if (pDest->GetDoc()->IsClipBoard() && this->GetNum())
1513     {
1514         // #i111677# cache expansion of source (for clipboard)
1515         pDest->m_pNumStringCache.reset(
1516             new ::rtl::OUString(this->GetNumString()));
1517     }
1518 
1519 	if( !nLen )
1520 	{
1521 		// wurde keine Laenge angegeben, dann Kopiere die Attribute
1522 		// an der Position rStart.
1523 		CopyAttr( pDest, nTxtStartIdx, nDestStart );
1524 
1525 		// harte Absatz umspannende Attribute kopieren
1526         if( HasSwAttrSet() )
1527 		{
1528 			// alle, oder nur die CharAttribute ?
1529             // --> OD 2008-11-18 #i96213#
1530             if ( !bForceCopyOfAllAttrs &&
1531                  ( nDestStart ||
1532                    pDest->HasSwAttrSet() ||
1533                    nLen != pDest->GetTxt().Len() ) )
1534             // <--
1535 			{
1536 				SfxItemSet aCharSet( pDest->GetDoc()->GetAttrPool(),
1537 									RES_CHRATR_BEGIN, RES_CHRATR_END-1,
1538                                     RES_TXTATR_INETFMT, RES_TXTATR_INETFMT,
1539                                     RES_TXTATR_CHARFMT, RES_TXTATR_CHARFMT,
1540 									RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1,
1541 									0 );
1542 				aCharSet.Put( *GetpSwAttrSet() );
1543 				if( aCharSet.Count() )
1544                 {
1545                     pDest->SetAttr( aCharSet, nDestStart, nDestStart );
1546                 }
1547 			}
1548 			else
1549             {
1550 				GetpSwAttrSet()->CopyToModify( *pDest );
1551             }
1552 		}
1553 		return;
1554 	}
1555 
1556 	// 1. Text kopieren
1557     const xub_StrLen oldLen = pDest->m_Text.Len();
1558 	//JP 15.02.96: Bug 25537 - Attributbehandlung am Ende fehlt! Darum
1559 	//				ueber die InsertMethode den Text einfuegen und nicht
1560 	//				selbst direkt
1561     pDest->InsertText( m_Text.Copy( nTxtStartIdx, nLen ), rDestStart,
1562                    IDocumentContentOperations::INS_EMPTYEXPAND );
1563 
1564 	// um reale Groesse Updaten !
1565     nLen = pDest->m_Text.Len() - oldLen;
1566     if ( !nLen ) // string not longer?
1567         return;
1568 
1569     SwDoc* const pOtherDoc = (pDest->GetDoc() != GetDoc()) ?
1570             pDest->GetDoc() : 0;
1571 
1572 	// harte Absatz umspannende Attribute kopieren
1573     if( HasSwAttrSet() )
1574 	{
1575 		// alle, oder nur die CharAttribute ?
1576         // --> OD 2008-11-18 #i96213#
1577         if ( !bForceCopyOfAllAttrs &&
1578              ( nDestStart ||
1579                pDest->HasSwAttrSet() ||
1580                nLen != pDest->GetTxt().Len() ) )
1581         // <--
1582 		{
1583 			SfxItemSet aCharSet( pDest->GetDoc()->GetAttrPool(),
1584 								RES_CHRATR_BEGIN, RES_CHRATR_END-1,
1585                                 RES_TXTATR_INETFMT, RES_TXTATR_INETFMT,
1586                                 RES_TXTATR_CHARFMT, RES_TXTATR_CHARFMT,
1587 								RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1,
1588 								0 );
1589 			aCharSet.Put( *GetpSwAttrSet() );
1590 			if( aCharSet.Count() )
1591             {
1592                 pDest->SetAttr( aCharSet, nDestStart, nDestStart + nLen );
1593             }
1594 		}
1595 		else
1596         {
1597 			GetpSwAttrSet()->CopyToModify( *pDest );
1598         }
1599 	}
1600 
1601     bool const bUndoNodes = !pOtherDoc
1602         && GetDoc()->GetIDocumentUndoRedo().IsUndoNodes(GetNodes());
1603 
1604 	// Ende erst jetzt holen, weil beim Kopieren in sich selbst der
1605 	// Start-Index und alle Attribute vorher aktualisiert werden.
1606 	nTxtStartIdx = rStart.GetIndex();
1607     const xub_StrLen nEnd = nTxtStartIdx + nLen;
1608 
1609 	// 2. Attribute kopieren
1610 	// durch das Attribute-Array, bis der Anfang des Geltungsbereiches
1611 	// des Attributs hinter dem zu kopierenden Bereich liegt
1612     const sal_uInt16 nSize = m_pSwpHints ? m_pSwpHints->Count() : 0;
1613 
1614 	// wird in sich selbst kopiert, dann kann beim Einfuegen ein
1615 	// Attribut geloescht werden. Darum erst ins Tmp-Array kopieren und
1616 	// dann erst ins eigene uebertragen.
1617 	SwpHts aArr( 5 );
1618 
1619 	// Del-Array fuer alle RefMarks ohne Ausdehnung
1620 	SwpHts aRefMrkArr;
1621 
1622     sal_uInt16 nDeletedDummyChars(0);
1623 		//Achtung: kann ungueltig sein!!
1624     for (sal_uInt16 n = 0; ( n < nSize ); ++n)
1625     {
1626         const xub_StrLen nAttrStartIdx = *(*m_pSwpHints)[n]->GetStart();
1627         if (!( nAttrStartIdx < nEnd))
1628             break;
1629 
1630         SwTxtAttr * const pHt = m_pSwpHints->GetTextHint(n);
1631         const xub_StrLen * const pEndIdx = pHt->GetEnd();
1632         const sal_uInt16 nWhich = pHt->Which();
1633 
1634 		// JP 26.04.94: REFMARK's werden nie kopiert. Hat das Refmark aber
1635 		//				keinen Bereich umspannt, so steht im Text ein 255
1636 		//				dieses muss entfernt werden. Trick: erst kopieren,
1637 		//				erkennen und sammeln, nach dem kopieren Loeschen.
1638 		//				Nimmt sein Zeichen mit ins Grab !!
1639 		// JP 14.08.95:	Duerfen RefMarks gemovt werden?
1640 		int bCopyRefMark = RES_TXTATR_REFMARK == nWhich && ( bUndoNodes ||
1641 						   (!pOtherDoc ? GetDoc()->IsCopyIsMove()
1642 									  : 0 == pOtherDoc->GetRefMark(
1643 										pHt->GetRefMark().GetRefName() )));
1644 
1645 		if( pEndIdx && RES_TXTATR_REFMARK == nWhich && !bCopyRefMark )
1646 		{
1647 			continue;
1648 		}
1649 
1650         xub_StrLen nAttrStt;
1651         xub_StrLen nAttrEnd;
1652 
1653 		if( nAttrStartIdx < nTxtStartIdx )
1654 		{
1655             // start is before selection
1656             // copy hints with end and CH_TXTATR only if dummy char is copied
1657             if ( pEndIdx && (*pEndIdx > nTxtStartIdx) && !pHt->HasDummyChar() )
1658             {
1659                 // attribute with extent and the end is in the selection
1660 				nAttrStt = nDestStart;
1661                 nAttrEnd = (*pEndIdx > nEnd)
1662 							? rDestStart.GetIndex()
1663                             : nDestStart + (*pEndIdx) - nTxtStartIdx;
1664 			}
1665 			else
1666 			{
1667 				continue;
1668 			}
1669 		}
1670 		else
1671 		{
1672             // start is in the selection
1673 			nAttrStt = nDestStart + ( nAttrStartIdx - nTxtStartIdx );
1674 			if( pEndIdx )
1675             {
1676 				nAttrEnd = *pEndIdx > nEnd
1677 							? rDestStart.GetIndex()
1678 							: nDestStart + ( *pEndIdx - nTxtStartIdx );
1679             }
1680 			else
1681             {
1682 				nAttrEnd = nAttrStt;
1683             }
1684 		}
1685 
1686         SwTxtAttr * pNewHt = 0;
1687 
1688 		if( pDest == this )
1689         {
1690             // copy the hint here, but insert it later
1691             pNewHt = MakeTxtAttr( *GetDoc(), pHt->GetAttr(),
1692                     nAttrStt, nAttrEnd, COPY, pDest );
1693 
1694             lcl_CopyHint(nWhich, pHt, pNewHt, 0, pDest);
1695 			aArr.C40_INSERT( SwTxtAttr, pNewHt, aArr.Count() );
1696 		}
1697 		else
1698 		{
1699             pNewHt = pDest->InsertItem( pHt->GetAttr(), nAttrStt - nDeletedDummyChars,
1700                 nAttrEnd - nDeletedDummyChars,
1701                       nsSetAttrMode::SETATTR_NOTXTATRCHR
1702                     | nsSetAttrMode::SETATTR_IS_COPY);
1703             if (pNewHt)
1704             {
1705                 lcl_CopyHint( nWhich, pHt, pNewHt, pOtherDoc, pDest );
1706             }
1707             else if (pHt->HasDummyChar())
1708             {
1709                 // The attribute that has failed to be copied would insert
1710                 // dummy char, so positions of the following attributes have
1711                 // to be shifted by one to compensate for that missing char.
1712                 ++nDeletedDummyChars;
1713             }
1714         }
1715 
1716 		if( RES_TXTATR_REFMARK == nWhich && !pEndIdx && !bCopyRefMark )
1717 		{
1718 			aRefMrkArr.C40_INSERT( SwTxtAttr, pNewHt, aRefMrkArr.Count() );
1719 		}
1720 	}
1721 
1722 	// nur falls im Array Attribute stehen (kann nur beim Kopieren
1723 	// sich selbst passieren!!)
1724     for ( sal_uInt16 i = 0; i < aArr.Count(); ++i )
1725     {
1726         InsertHint( aArr[ i ], nsSetAttrMode::SETATTR_NOTXTATRCHR );
1727     }
1728 
1729 	if( pDest->GetpSwpHints() )
1730     {
1731         for ( sal_uInt16 i = 0; i < aRefMrkArr.Count(); ++i )
1732 		{
1733             SwTxtAttr * const pNewHt = aRefMrkArr[i];
1734 			if( pNewHt->GetEnd() )
1735 			{
1736 				pDest->GetpSwpHints()->Delete( pNewHt );
1737 				pDest->DestroyAttr( pNewHt );
1738 			}
1739 			else
1740 			{
1741 				const SwIndex aIdx( pDest, *pNewHt->GetStart() );
1742                 pDest->EraseText( aIdx, 1 );
1743             }
1744         }
1745     }
1746 
1747 	CHECK_SWPHINTS(this);
1748 }
1749 
1750 
1751 void SwTxtNode::InsertText( const XubString & rStr, const SwIndex & rIdx,
1752         const IDocumentContentOperations::InsertFlags nMode )
1753 {
1754     ASSERT( rIdx <= m_Text.Len(), "SwTxtNode::InsertText: invalid index." );
1755     ASSERT( (sal_uLong)m_Text.Len() + (sal_uLong)rStr.Len() <= STRING_LEN,
1756             "SwTxtNode::InsertText: node text with insertion > STRING_LEN." );
1757 
1758 	xub_StrLen aPos = rIdx.GetIndex();
1759     xub_StrLen nLen = m_Text.Len() - aPos;
1760     m_Text.Insert( rStr, aPos );
1761     nLen = m_Text.Len() - aPos - nLen;
1762 
1763     if ( !nLen ) return;
1764 
1765     sal_Bool bOldExpFlg = IsIgnoreDontExpand();
1766     if (nMode & IDocumentContentOperations::INS_FORCEHINTEXPAND)
1767     {
1768         SetIgnoreDontExpand( sal_True );
1769     }
1770 
1771     Update( rIdx, nLen ); // text content changed!
1772 
1773     if (nMode & IDocumentContentOperations::INS_FORCEHINTEXPAND)
1774     {
1775         SetIgnoreDontExpand( bOldExpFlg );
1776     }
1777 
1778 	// analog zu Insert(char) in txtedt.cxx:
1779 	// 1) bei bHintExp leere Hints an rIdx.GetIndex suchen und aufspannen
1780 	// 2) bei bHintExp == sal_False mitgezogene Feldattribute zuruecksetzen
1781 
1782     if ( HasHints() )
1783     {
1784         for ( sal_uInt16 i = 0; i < m_pSwpHints->Count() &&
1785                 rIdx >= *(*m_pSwpHints)[i]->GetStart(); ++i )
1786         {
1787             SwTxtAttr * const pHt = m_pSwpHints->GetTextHint( i );
1788             xub_StrLen * const pEndIdx = pHt->GetEnd();
1789 			if( !pEndIdx )
1790 				continue;
1791 
1792 			if( rIdx == *pEndIdx )
1793 			{
1794                 if (  (nMode & IDocumentContentOperations::INS_NOHINTEXPAND) ||
1795                     (!(nMode & IDocumentContentOperations::INS_FORCEHINTEXPAND)
1796                      && pHt->DontExpand()) )
1797 				{
1798 					// bei leeren Attributen auch Start veraendern
1799 					if( rIdx == *pHt->GetStart() )
1800 						*pHt->GetStart() = *pHt->GetStart() - nLen;
1801 					*pEndIdx = *pEndIdx - nLen;
1802                     m_pSwpHints->DeleteAtPos(i);
1803                     InsertHint( pHt, nsSetAttrMode::SETATTR_NOHINTADJUST );
1804                 }
1805                 // empty hints at insert position?
1806                 else if ( (nMode & IDocumentContentOperations::INS_EMPTYEXPAND)
1807                         && (*pEndIdx == *pHt->GetStart()) )
1808 				{
1809 					*pHt->GetStart() = *pHt->GetStart() - nLen;
1810                     const sal_uInt16 nAktLen = m_pSwpHints->Count();
1811                     m_pSwpHints->DeleteAtPos(i);
1812                     InsertHint( pHt/* AUTOSTYLES:, nsSetAttrMode::SETATTR_NOHINTADJUST*/ );
1813                     if ( nAktLen > m_pSwpHints->Count() && i )
1814                     {
1815 						--i;
1816                     }
1817 					continue;
1818 				}
1819 				else
1820                 {
1821 					continue;
1822                 }
1823 			}
1824             if ( !(nMode & IDocumentContentOperations::INS_NOHINTEXPAND) &&
1825 				 rIdx == nLen && *pHt->GetStart() == rIdx.GetIndex() &&
1826 				 !pHt->IsDontExpandStartAttr() )
1827 			{
1828 				// Kein Feld, am Absatzanfang, HintExpand
1829                 m_pSwpHints->DeleteAtPos(i);
1830 				*pHt->GetStart() = *pHt->GetStart() - nLen;
1831                 InsertHint( pHt, nsSetAttrMode::SETATTR_NOHINTADJUST );
1832             }
1833         }
1834         TryDeleteSwpHints();
1835     }
1836 
1837 	if ( GetDepends() )
1838 	{
1839 		SwInsTxt aHint( aPos, nLen );
1840 		NotifyClients( 0, &aHint );
1841 	}
1842 
1843     // By inserting a character, the hidden flags
1844     // at the TxtNode can become invalid:
1845     SetCalcHiddenCharFlags();
1846 
1847 	CHECK_SWPHINTS(this);
1848 }
1849 
1850 /*************************************************************************
1851 |*
1852 |*	SwTxtNode::Cut()
1853 |*
1854 |*	Beschreibung		text.doc
1855 |*	Ersterstellung		VB 20.03.91
1856 |*	Letzte Aenderung	JP 11.08.94
1857 |*
1858 *************************************************************************/
1859 
1860 void SwTxtNode::CutText( SwTxtNode * const pDest,
1861             const SwIndex & rStart, const xub_StrLen nLen )
1862 {
1863 	if(pDest)
1864 	{
1865 		SwIndex aDestStt( pDest, pDest->GetTxt().Len() );
1866         CutImpl( pDest, aDestStt, rStart, nLen, false );
1867     }
1868     else
1869     {
1870         ASSERT(false,
1871             "mst: entering dead and bitrotted code; fasten your seatbelts!");
1872         EraseText( rStart, nLen );
1873     }
1874 }
1875 
1876 
1877 void SwTxtNode::CutImpl( SwTxtNode * const pDest, const SwIndex & rDestStart,
1878          const SwIndex & rStart, /*const*/ xub_StrLen nLen, const bool bUpdate )
1879 {
1880 	if(!pDest)
1881     {
1882         ASSERT(false,
1883             "mst: entering dead and bitrotted code; fasten your seatbelts!");
1884         EraseText( rStart, nLen );
1885 		return;
1886 	}
1887 
1888 	// nicht im Dokument verschieben ?
1889 	if( GetDoc() != pDest->GetDoc() )
1890 	{
1891         ASSERT(false,
1892             "mst: entering dead and bitrotted code; fasten your seatbelts!");
1893         CopyText( pDest, rDestStart, rStart, nLen);
1894         EraseText(rStart, nLen);
1895 		return;
1896 	}
1897 
1898 	if( !nLen )
1899 	{
1900 		// wurde keine Laenge angegeben, dann Kopiere die Attribute
1901 		// an der Position rStart.
1902 		CopyAttr( pDest, rStart.GetIndex(), rDestStart.GetIndex() );
1903 		return;
1904 	}
1905 
1906 	xub_StrLen nTxtStartIdx = rStart.GetIndex();
1907 	xub_StrLen nDestStart = rDestStart.GetIndex();		// alte Pos merken
1908     const xub_StrLen nInitSize = pDest->m_Text.Len();
1909 
1910 	// wird in sich selbst verschoben, muss es gesondert behandelt werden !!
1911 	if( pDest == this )
1912 	{
1913         ASSERT(false,
1914             "mst: entering dead and bitrotted code; fasten your seatbelts!");
1915         m_Text.Insert( m_Text, nTxtStartIdx, nLen, nDestStart );
1916         m_Text.Erase( nTxtStartIdx + (nDestStart<nTxtStartIdx ? nLen : 0), nLen );
1917 
1918         const xub_StrLen nEnd = rStart.GetIndex() + nLen;
1919 
1920 		// dann suche mal alle Attribute zusammen, die im verschobenen
1921 		// Bereich liegen. Diese werden in das extra Array verschoben,
1922 		// damit sich die Indizies beim Updaten nicht veraendern !!!
1923 		SwpHts aArr( 5 );
1924 
1925 		// 2. Attribute verschieben
1926 		// durch das Attribute-Array, bis der Anfang des Geltungsbereiches
1927 		// des Attributs hinter dem zu verschiebenden Bereich liegt
1928         sal_uInt16 nAttrCnt = 0;
1929         while ( m_pSwpHints && nAttrCnt < m_pSwpHints->Count() )
1930         {
1931             SwTxtAttr * const pHt = m_pSwpHints->GetTextHint(nAttrCnt);
1932             const xub_StrLen nAttrStartIdx = *pHt->GetStart();
1933             if (!( nAttrStartIdx < nEnd ))
1934                 break;
1935             const xub_StrLen * const pEndIdx = pHt->GetEnd();
1936             const sal_uInt16 nWhich = pHt->Which();
1937             SwTxtAttr *pNewHt = 0;
1938 
1939 			if(nAttrStartIdx < nTxtStartIdx)
1940 			{
1941 				// Anfang liegt vor dem Bereich
1942                 if ( RES_TXTATR_REFMARK != nWhich && !pHt->HasDummyChar() &&
1943 					pEndIdx && *pEndIdx > nTxtStartIdx )
1944 				{
1945 					// Attribut mit einem Bereich
1946 					// und das Ende des Attribut liegt im Bereich
1947                     pNewHt = MakeTxtAttr( *GetDoc(), pHt->GetAttr(), 0,
1948 										*pEndIdx > nEnd
1949 											? nLen
1950 											: *pEndIdx - nTxtStartIdx );
1951 				}
1952 			}
1953 			else
1954 			{
1955 				// der Anfang liegt vollstaendig im Bereich
1956 				if( !pEndIdx || *pEndIdx < nEnd )
1957 				{
1958 					// Attribut verschieben
1959                     m_pSwpHints->Delete( pHt );
1960 					// die Start/End Indicies neu setzen
1961 					*pHt->GetStart() = nAttrStartIdx - nTxtStartIdx;
1962 					if( pEndIdx )
1963 						*pHt->GetEnd() = *pEndIdx - nTxtStartIdx;
1964 					aArr.C40_INSERT( SwTxtAttr, pHt, aArr.Count() );
1965 					continue;			// while-Schleife weiter, ohne ++ !
1966 				}
1967 					// das Ende liegt dahinter
1968                 else if (RES_TXTATR_REFMARK != nWhich && !pHt->HasDummyChar())
1969 				{
1970                     pNewHt = MakeTxtAttr( *GetDoc(), pHt->GetAttr(),
1971 							nAttrStartIdx - nTxtStartIdx,
1972 							!pEndIdx ? 0
1973 									 : ( *pEndIdx > nEnd
1974 											? nLen
1975 											: *pEndIdx - nTxtStartIdx ));
1976 				}
1977 			}
1978 			if( pNewHt )
1979 			{
1980 				// die Daten kopieren
1981 				lcl_CopyHint( nWhich, pHt, pNewHt, 0, this );
1982 				aArr.C40_INSERT( SwTxtAttr, pNewHt, aArr.Count() );
1983 			}
1984 			++nAttrCnt;
1985 		}
1986 
1987 		if( bUpdate )
1988         {
1989 			// Update aller Indizies
1990 			Update( rDestStart, nLen, sal_False, sal_True );
1991         }
1992 #ifdef CUTNOEXPAND
1993 		else
1994 			// wird am Ende eingefuegt, nur die Attribut-Indizies verschieben
1995             if ( 0 < nLen && 0 < nInitSize && m_pSwpHints )
1996             {
1997                 // check if there was the end of an attribute at the insertion
1998                 // position: if it is not a field, it must be expanded
1999                 for ( sal_uInt16 n = 0; n < m_pSwpHints->Count(); n++ )
2000                 {
2001                     SwTxtAttr * const pHt = m_pSwpHints->GetTextHint(n);
2002                     const xub_StrLen * const pEndIdx = pHt->GetEnd();
2003                     if ( pEndIdx  && (*pEndIdx == nInitSize) )
2004                     {
2005                         *pEndIdx = *pEndIdx + nLen;
2006                     }
2007                 }
2008             }
2009 #endif
2010 		CHECK_SWPHINTS(this);
2011 
2012 		Update( rStart, nLen, sal_True, sal_True );
2013 
2014 		CHECK_SWPHINTS(this);
2015 
2016 		// dann setze die kopierten/geloeschten Attribute in den Node
2017 		if( nDestStart <= nTxtStartIdx )
2018         {
2019 			nTxtStartIdx = nTxtStartIdx + nLen;
2020         }
2021 		else
2022         {
2023 			nDestStart = nDestStart - nLen;
2024         }
2025 
2026         for ( sal_uInt16 n = 0; n < aArr.Count(); ++n )
2027         {
2028             SwTxtAttr *const pNewHt = aArr[n];
2029 			*pNewHt->GetStart() = nDestStart + *pNewHt->GetStart();
2030             xub_StrLen * const pEndIdx = pNewHt->GetEnd();
2031             if ( pEndIdx )
2032             {
2033                 *pEndIdx = nDestStart + *pEndIdx;
2034             }
2035             InsertHint( pNewHt, nsSetAttrMode::SETATTR_NOTXTATRCHR );
2036         }
2037     }
2038     else
2039     {
2040         pDest->m_Text.Insert( m_Text, nTxtStartIdx, nLen, nDestStart );
2041         m_Text.Erase( nTxtStartIdx, nLen );
2042         nLen = pDest->m_Text.Len() - nInitSize; // update w/ current size!
2043 		if( !nLen )					// String nicht gewachsen ??
2044 			return;
2045 
2046 		if( bUpdate )
2047         {
2048 			// Update aller Indizies
2049 			pDest->Update( rDestStart, nLen, sal_False, sal_True);
2050         }
2051 #ifdef CUTNOEXPAND
2052 		else
2053 			// wird am Ende eingefuegt, nur die Attribut-Indizies verschieben
2054             if ( 0 < nLen && 0 < nInitSize && pDest->m_pSwpHints )
2055             {
2056                 // check if there was the end of an attribute at the insertion
2057                 // position: if it is not a field, it must be expanded
2058                 for ( sal_uInt16 n = 0; n < pDest->m_pSwpHints->Count(); n++ )
2059                 {
2060                     SwTxtAttr * const pHt = pDest->m_pSwpHints->GetTextHint(n);
2061                     const xub_StrLen * const pEndIdx = pHt->GetEnd();
2062                     if ( pEndIdx  && (*pEndIdx == nInitSize) )
2063                     {
2064                         *pEndIdx = *pEndIdx + nLen;
2065                     }
2066                 }
2067             }
2068 #endif
2069 		CHECK_SWPHINTS(pDest);
2070 
2071         const xub_StrLen nEnd = rStart.GetIndex() + nLen;
2072         SwDoc* const pOtherDoc = (pDest->GetDoc() != GetDoc())
2073             ? pDest->GetDoc() : 0;
2074         bool const bUndoNodes = !pOtherDoc
2075             && GetDoc()->GetIDocumentUndoRedo().IsUndoNodes(GetNodes());
2076 
2077         ASSERT(!pOtherDoc,
2078             "mst: entering dead and bitrotted code; fasten your seatbelts!");
2079 
2080 		// harte Absatz umspannende Attribute kopieren
2081         if( HasSwAttrSet() )
2082 		{
2083 			// alle, oder nur die CharAttribute ?
2084             if( nInitSize || pDest->HasSwAttrSet() ||
2085 				nLen != pDest->GetTxt().Len() )
2086 			{
2087 				SfxItemSet aCharSet( pDest->GetDoc()->GetAttrPool(),
2088 									RES_CHRATR_BEGIN, RES_CHRATR_END-1,
2089                                     RES_TXTATR_INETFMT, RES_TXTATR_INETFMT,
2090                                     RES_TXTATR_CHARFMT, RES_TXTATR_CHARFMT,
2091 									RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1,
2092 									0 );
2093 				aCharSet.Put( *GetpSwAttrSet() );
2094 				if( aCharSet.Count() )
2095                     pDest->SetAttr( aCharSet, nDestStart, nDestStart + nLen );
2096 			}
2097 			else
2098             {
2099 				GetpSwAttrSet()->CopyToModify( *pDest );
2100             }
2101 		}
2102 
2103 		// 2. Attribute verschieben
2104 		// durch das Attribute-Array, bis der Anfang des Geltungsbereiches
2105 		// des Attributs hinter dem zu verschiebenden Bereich liegt
2106         sal_uInt16 nAttrCnt = 0;
2107         while ( m_pSwpHints && (nAttrCnt < m_pSwpHints->Count()) )
2108         {
2109             SwTxtAttr * const pHt = m_pSwpHints->GetTextHint(nAttrCnt);
2110             const xub_StrLen nAttrStartIdx = *pHt->GetStart();
2111             if (!( nAttrStartIdx < nEnd ))
2112                 break;
2113             const xub_StrLen * const pEndIdx = pHt->GetEnd();
2114             const sal_uInt16 nWhich = pHt->Which();
2115             SwTxtAttr *pNewHt = 0;
2116 
2117             // if the hint has a dummy character, then it must not be split!
2118 			if(nAttrStartIdx < nTxtStartIdx)
2119 			{
2120 				// Anfang liegt vor dem Bereich
2121                 if( !pHt->HasDummyChar() && ( RES_TXTATR_REFMARK != nWhich
2122 					|| bUndoNodes ) && pEndIdx && *pEndIdx > nTxtStartIdx )
2123 				{
2124 					// Attribut mit einem Bereich
2125 					// und das Ende des Attribut liegt im Bereich
2126                     pNewHt = MakeTxtAttr( *pDest->GetDoc(), pHt->GetAttr(),
2127                                     nDestStart,
2128                                     nDestStart + (
2129 										*pEndIdx > nEnd
2130 											? nLen
2131 											: *pEndIdx - nTxtStartIdx ) );
2132 				}
2133 			}
2134 			else
2135 			{
2136 				// der Anfang liegt vollstaendig im Bereich
2137 				if( !pEndIdx || *pEndIdx < nEnd ||
2138 					(!pOtherDoc && !bUndoNodes && RES_TXTATR_REFMARK == nWhich)
2139                     || pHt->HasDummyChar() )
2140 				{
2141 					// do not delete note and later add it -> sidebar flickering
2142 					if ( GetDoc()->GetDocShell() )
2143                     {
2144 						GetDoc()->GetDocShell()->Broadcast( SfxSimpleHint(SFX_HINT_USER04));
2145                     }
2146 					// Attribut verschieben
2147                     m_pSwpHints->Delete( pHt );
2148 					// die Start/End Indicies neu setzen
2149 					*pHt->GetStart() =
2150 							nDestStart + (nAttrStartIdx - nTxtStartIdx);
2151 					if( pEndIdx )
2152                     {
2153 						*pHt->GetEnd() = nDestStart + (
2154 										*pEndIdx > nEnd
2155 											? nLen
2156 											: *pEndIdx - nTxtStartIdx );
2157                     }
2158                     pDest->InsertHint( pHt,
2159                               nsSetAttrMode::SETATTR_NOTXTATRCHR
2160                             | nsSetAttrMode::SETATTR_DONTREPLACE );
2161 					if ( GetDoc()->GetDocShell() )
2162                     {
2163 						GetDoc()->GetDocShell()->Broadcast( SfxSimpleHint(SFX_HINT_USER04));
2164                     }
2165 					continue;			// while-Schleife weiter, ohne ++ !
2166 				}
2167 					// das Ende liegt dahinter
2168 				else if( RES_TXTATR_REFMARK != nWhich || bUndoNodes )
2169 				{
2170                     pNewHt = MakeTxtAttr( *GetDoc(), pHt->GetAttr(),
2171 							nDestStart + (nAttrStartIdx - nTxtStartIdx),
2172 							!pEndIdx ? 0
2173 									 : nDestStart + ( *pEndIdx > nEnd
2174 											? nLen
2175 											: *pEndIdx - nTxtStartIdx ));
2176 				}
2177 			}
2178 			if ( pNewHt )
2179             {
2180                 const bool bSuccess( pDest->InsertHint( pNewHt,
2181                               nsSetAttrMode::SETATTR_NOTXTATRCHR
2182                             | nsSetAttrMode::SETATTR_DONTREPLACE
2183                             | nsSetAttrMode::SETATTR_IS_COPY) );
2184                 if (bSuccess)
2185                 {
2186                     lcl_CopyHint( nWhich, pHt, pNewHt, pOtherDoc, pDest );
2187                 }
2188             }
2189 			++nAttrCnt;
2190 		}
2191 		// sollten jetzt noch leere Attribute rumstehen, dann haben diese
2192 		// eine hoehere Praezedenz. Also herausholen und das Array updaten.
2193 		// Die dabei entstehenden leeren Hints werden von den gesicherten
2194 		// "uebergeplaettet".	(Bug: 6977)
2195         if( m_pSwpHints && nAttrCnt < m_pSwpHints->Count() )
2196         {
2197             SwpHts aArr( 5 );
2198             while ( nAttrCnt < m_pSwpHints->Count() )
2199             {
2200                 SwTxtAttr * const pHt = m_pSwpHints->GetTextHint(nAttrCnt);
2201                 if ( nEnd != *pHt->GetStart() )
2202                     break;
2203                 const xub_StrLen * const pEndIdx = pHt->GetEnd();
2204                 if ( pEndIdx && *pEndIdx == nEnd )
2205                 {
2206 					aArr.C40_INSERT( SwTxtAttr, pHt, aArr.Count() );
2207                     m_pSwpHints->Delete( pHt );
2208                 }
2209                 else
2210                 {
2211                     ++nAttrCnt;
2212                 }
2213 			}
2214 			Update( rStart, nLen, sal_True, sal_True );
2215 
2216             for ( sal_uInt16 n = 0; n < aArr.Count(); ++n )
2217 			{
2218                 SwTxtAttr * const pHt = aArr[ n ];
2219 				*pHt->GetStart() = *pHt->GetEnd() = rStart.GetIndex();
2220                 InsertHint( pHt );
2221             }
2222         }
2223 		else
2224         {
2225 			Update( rStart, nLen, sal_True, sal_True );
2226         }
2227 
2228 		CHECK_SWPHINTS(this);
2229 	}
2230 
2231     TryDeleteSwpHints();
2232 
2233 	// Frames benachrichtigen;
2234 	SwInsTxt aInsHint( nDestStart, nLen );
2235     pDest->ModifyNotification( 0, &aInsHint );
2236 	SwDelTxt aDelHint( nTxtStartIdx, nLen );
2237     ModifyNotification( 0, &aDelHint );
2238 }
2239 
2240 
2241 void SwTxtNode::EraseText(const SwIndex &rIdx, const xub_StrLen nCount,
2242         const IDocumentContentOperations::InsertFlags nMode )
2243 {
2244     ASSERT( rIdx <= m_Text.Len(), "SwTxtNode::EraseText: invalid index." );
2245 
2246     const xub_StrLen nStartIdx = rIdx.GetIndex();
2247     const xub_StrLen nCnt = (STRING_LEN == nCount)
2248                       ? m_Text.Len() - nStartIdx : nCount;
2249     const xub_StrLen nEndIdx = nStartIdx + nCnt;
2250     m_Text.Erase( nStartIdx, nCnt );
2251 
2252 	/* GCAttr(); alle leeren weggwerfen ist zu brutal.
2253 	 * Es duerfen nur die wegggeworfen werden,
2254 	 * die im Bereich liegen und nicht am Ende des Bereiches liegen
2255 	 */
2256 
2257     for ( sal_uInt16 i = 0; m_pSwpHints && i < m_pSwpHints->Count(); ++i )
2258     {
2259         SwTxtAttr *pHt = m_pSwpHints->GetTextHint(i);
2260 
2261         const xub_StrLen nHintStart = *pHt->GetStart();
2262 
2263         if ( nHintStart < nStartIdx )
2264 			continue;
2265 
2266         if ( nHintStart > nEndIdx )
2267             break; // hints are sorted by end, so break here
2268 
2269 		const xub_StrLen* pHtEndIdx = pHt->GetEnd();
2270 		const sal_uInt16 nWhich = pHt->Which();
2271 
2272 		if( !pHtEndIdx )
2273         {
2274             ASSERT(pHt->HasDummyChar(),
2275                     "attribute with neither end nor CH_TXTATR?");
2276             if (isTXTATR(nWhich) &&
2277                 (nHintStart >= nStartIdx) && (nHintStart < nEndIdx))
2278             {
2279                 m_pSwpHints->DeleteAtPos(i);
2280 				DestroyAttr( pHt );
2281 				--i;
2282 			}
2283 			continue;
2284 		}
2285 
2286         ASSERT (!( (nHintStart < nEndIdx) && (*pHtEndIdx > nEndIdx)
2287                     && pHt->HasDummyChar() )
2288                 // next line: deleting exactly dummy char: DeleteAttributes
2289                 || ((nHintStart == nStartIdx) && (nHintStart + 1 == nEndIdx)),
2290                 "ERROR: deleting left-overlapped attribute with CH_TXTATR");
2291 
2292         // Delete the hint if:
2293         // 1. The hint ends before the deletion end position or
2294         // 2. The hint ends at the deletion end position and
2295         //    we are not in empty expand mode and
2296         //    the hint is a [toxmark|refmark|ruby] text attribute
2297         // 3. deleting exactly the dummy char of an hint with end and dummy
2298         //    char deletes the hint
2299         if (   (*pHtEndIdx < nEndIdx)
2300             || ( (*pHtEndIdx == nEndIdx)     &&
2301                  !(IDocumentContentOperations::INS_EMPTYEXPAND & nMode)  &&
2302                  (  (RES_TXTATR_TOXMARK == nWhich)  ||
2303                     (RES_TXTATR_REFMARK == nWhich)  ||
2304                  // --> FME 2006-03-03 #i62668# Ruby text attribute must be
2305                  // treated just like toxmark and refmarks
2306                     (RES_TXTATR_CJK_RUBY == nWhich) ) )
2307                  // <--
2308 #if 0
2309             || ( (nHintStart == nStartIdx)  &&
2310                  (nHintStart + 1 == nEndIdx)&&
2311 #else // generalize this to left-overlapped dummy char hints (see ASSERT)
2312             || ( (nHintStart < nEndIdx)     &&
2313 #endif
2314                  pHt->HasDummyChar()        )
2315            )
2316         {
2317             m_pSwpHints->DeleteAtPos(i);
2318             DestroyAttr( pHt );
2319             --i;
2320         }
2321     }
2322 
2323     ASSERT(rIdx.GetIndex() == nStartIdx, "huh? start index has changed?");
2324 
2325     TryDeleteSwpHints();
2326 
2327 	Update( rIdx, nCnt, sal_True );
2328 
2329 	if( 1 == nCnt )
2330 	{
2331         SwDelChr aHint( nStartIdx );
2332 		NotifyClients( 0, &aHint );
2333     }
2334     else
2335     {
2336         SwDelTxt aHint( nStartIdx, nCnt );
2337 		NotifyClients( 0, &aHint );
2338 	}
2339 
2340     ASSERT(rIdx.GetIndex() == nStartIdx, "huh? start index has changed?");
2341 
2342     // By deleting a character, the hidden flags
2343     // at the TxtNode can become invalid:
2344     SetCalcHiddenCharFlags();
2345 
2346 	CHECK_SWPHINTS(this);
2347 }
2348 
2349 /***********************************************************************
2350 #*	Class		:	SwTxtNode
2351 #*	Methode 	:	GCAttr
2352 #*
2353 #*	Beschreibung
2354 #*					text.doc
2355 #*
2356 #*	Datum		:	MS 28.11.90
2357 #*	Update		:	VB 24.07.91
2358 #***********************************************************************/
2359 
2360 void SwTxtNode::GCAttr()
2361 {
2362     if ( !HasHints() )
2363         return;
2364 
2365     bool   bChanged = false;
2366     sal_uInt16 nMin = m_Text.Len(),
2367 		   nMax = 0;
2368 	sal_Bool bAll = nMin != 0; // Bei leeren Absaetzen werden nur die
2369 						   // INet-Formate entfernt.
2370 
2371     for ( sal_uInt16 i = 0; m_pSwpHints && i < m_pSwpHints->Count(); ++i )
2372     {
2373         SwTxtAttr * const pHt = m_pSwpHints->GetTextHint(i);
2374 
2375 		// wenn Ende und Start gleich sind --> loeschen
2376         const xub_StrLen * const pEndIdx = pHt->GetEnd();
2377         if (pEndIdx && !pHt->HasDummyChar() && (*pEndIdx == *pHt->GetStart())
2378 			&& ( bAll || pHt->Which() == RES_TXTATR_INETFMT ) )
2379         {
2380             bChanged = true;
2381 			nMin = Min( nMin, *pHt->GetStart() );
2382 			nMax = Max( nMax, *pHt->GetEnd() );
2383             DestroyAttr( m_pSwpHints->Cut(i) );
2384 			--i;
2385         }
2386         else
2387         {
2388             pHt->SetDontExpand( false );
2389         }
2390     }
2391     TryDeleteSwpHints();
2392 
2393 	if(bChanged)
2394 	{
2395 		//TxtFrm's reagieren auf aHint, andere auf aNew
2396 		SwUpdateAttr aHint( nMin, nMax, 0 );
2397 		NotifyClients( 0, &aHint );
2398 		SwFmtChg aNew( GetTxtColl() );
2399 		NotifyClients( 0, &aNew );
2400 	}
2401 }
2402 
2403 // #i23726#
2404 SwNumRule* SwTxtNode::_GetNumRule(sal_Bool bInParent) const
2405 {
2406     SwNumRule* pRet = 0;
2407 
2408     const SfxPoolItem* pItem = GetNoCondAttr( RES_PARATR_NUMRULE, bInParent );
2409     bool bNoNumRule = false;
2410     if ( pItem )
2411     {
2412         String sNumRuleName = static_cast<const SwNumRuleItem *>(pItem)->GetValue();
2413         if (sNumRuleName.Len() > 0)
2414         {
2415             pRet = GetDoc()->FindNumRulePtr( sNumRuleName );
2416         }
2417         else // numbering is turned off
2418             bNoNumRule = true;
2419     }
2420 
2421     if ( !bNoNumRule )
2422     {
2423         if ( pRet && pRet == GetDoc()->GetOutlineNumRule() &&
2424              ( !HasSwAttrSet() ||
2425                SFX_ITEM_SET !=
2426                 GetpSwAttrSet()->GetItemState( RES_PARATR_NUMRULE, sal_False ) ) )
2427         {
2428             SwTxtFmtColl* pColl = GetTxtColl();
2429             if ( pColl )
2430             {
2431                 const SwNumRuleItem& rDirectItem = pColl->GetNumRule( sal_False );
2432                 if ( rDirectItem.GetValue().Len() == 0 )
2433                 {
2434                     pRet = 0L;
2435                 }
2436             }
2437         }
2438 
2439         // --> OD 2006-11-20 #i71764#
2440         // Document setting OUTLINE_LEVEL_YIELDS_OUTLINE_RULE has no influence
2441         // any more.
2442 //        if ( !pRet &&
2443 //             GetDoc()->get(IDocumentSettingAccess::OUTLINE_LEVEL_YIELDS_OUTLINE_RULE) &&
2444 //             GetOutlineLevel() != NO_NUMBERING )
2445 //        {
2446 //            pRet = GetDoc()->GetOutlineNumRule();
2447 //        }
2448         // <--
2449     }
2450     // old code before tuning
2451 //    // --> OD 2005-10-25 #126347#
2452 //    // determine of numbering/bullet rule, which is set as a hard attribute
2453 //    // at the text node
2454 //    const SfxPoolItem* pItem( 0L );
2455 //    if ( HasSwAttrSet() ) // does text node has hard attributes ?
2456 //    {
2457 //        if ( SFX_ITEM_SET !=
2458 //                GetpSwAttrSet()->GetItemState( RES_PARATR_NUMRULE, sal_False, &pItem ) )
2459 //        {
2460 //            pItem = 0L;
2461 //        }
2462 //        // else: <pItem> contains the numbering/bullet attribute, which is
2463 //        //       hard set at the paragraph.
2464 
2465 //    }
2466 //    // <--
2467 //    bool bNoNumRule = false;
2468 //    if (pItem)
2469 //    {
2470 //        String sNumRuleName = static_cast<const SwNumRuleItem *>(pItem)->GetValue();
2471 //        if (sNumRuleName.Len() > 0)
2472 //        {
2473 //            pRet = GetDoc()->FindNumRulePtr(sNumRuleName);
2474 //        }
2475 //        else // numbering is turned off by hard attribute
2476 //            bNoNumRule = true;
2477 //    }
2478 
2479 //    if (! bNoNumRule)
2480 //    {
2481 //        if (! pRet && bInParent)
2482 //        {
2483 //            SwTxtFmtColl * pColl = GetTxtColl();
2484 
2485 //            if (pColl)
2486 //            {
2487 //                const SwNumRuleItem & rItem = pColl->GetNumRule(sal_True);
2488 
2489 //                pRet = const_cast<SwDoc *>(GetDoc())->
2490 //                    FindNumRulePtrWithPool(rItem.GetValue());
2491 //                // --> OD 2005-10-13 #125993# - The outline numbering rule
2492 //                // isn't allowed to be derived from a parent paragraph style
2493 //                // to a derived one.
2494 //                // Thus check, if the found outline numbering rule is directly
2495 //                // set at the paragraph style <pColl>. If not, don't return
2496 //                // the outline numbering rule.
2497 //                if ( pRet && pRet == GetDoc()->GetOutlineNumRule() )
2498 //                {
2499 //                    const SwNumRuleItem& rDirectItem = pColl->GetNumRule(sal_False);
2500 //                    SwNumRule* pNumRuleAtParaStyle = const_cast<SwDoc*>(GetDoc())->
2501 //                        FindNumRulePtrWithPool(rDirectItem.GetValue());
2502 //                    if ( !pNumRuleAtParaStyle )
2503 //                    {
2504 //                        pRet = 0L;
2505 //                    }
2506 //                }
2507 //                // <--
2508 //            }
2509 //        }
2510 
2511 //        if (!pRet && GetDoc()->IsOutlineLevelYieldsOutlineRule() &&
2512 //            GetOutlineLevel() != NO_NUMBERING)
2513 //            pRet = GetDoc()->GetOutlineNumRule();
2514 //    }
2515     // <--
2516 
2517 	return pRet;
2518 }
2519 
2520 SwNumRule* SwTxtNode::GetNumRule(sal_Bool bInParent) const
2521 {
2522     SwNumRule * pRet = _GetNumRule(bInParent);
2523 
2524     return pRet;
2525 }
2526 
2527 void SwTxtNode::NumRuleChgd()
2528 {
2529     // --> OD 2008-04-04 #refactorlists#
2530     if ( IsInList() )
2531     {
2532         SwNumRule* pNumRule = GetNumRule();
2533         if ( pNumRule && pNumRule != GetNum()->GetNumRule() )
2534         {
2535             mpNodeNum->ChangeNumRule( *pNumRule );
2536         }
2537     }
2538     // <--
2539 
2540     if( IsInCache() )
2541 	{
2542 		SwFrm::GetCache().Delete( this );
2543 		SetInCache( sal_False );
2544 	}
2545 	SetInSwFntCache( sal_False );
2546 
2547     // Sending "noop" modify in order to cause invalidations of registered
2548     // <SwTxtFrm> instances to get the list style change respectively the change
2549     // in the list tree reflected in the layout.
2550     // Important note:
2551     {
2552         SvxLRSpaceItem& rLR = (SvxLRSpaceItem&)GetSwAttrSet().GetLRSpace();
2553         NotifyClients( &rLR, &rLR );
2554     }
2555 }
2556 
2557 // -> #i27615#
2558 sal_Bool SwTxtNode::IsNumbered() const
2559 {
2560     sal_Bool bResult = sal_False;
2561 
2562     SwNumRule* pRule = GetNum() ? GetNum()->GetNumRule() : 0L;
2563     if ( pRule && IsCountedInList() )
2564         bResult = sal_True;
2565 
2566     return bResult;
2567 }
2568 
2569 // --> OD 2008-04-02 #refactorlists#
2570 bool SwTxtNode::HasMarkedLabel() const
2571 {
2572     bool bResult = false;
2573 
2574     if ( IsInList() )
2575     {
2576         bResult =
2577             GetDoc()->getListByName( GetListId() )->IsListLevelMarked( GetActualListLevel() );
2578     }
2579 
2580     return bResult;
2581 }
2582 // <--
2583 // <- #i27615#
2584 
2585 SwTxtNode* SwTxtNode::_MakeNewTxtNode( const SwNodeIndex& rPos, sal_Bool bNext,
2586 										sal_Bool bChgFollow )
2587 {
2588 	/* hartes PageBreak/PageDesc/ColumnBreak aus AUTO-Set ignorieren */
2589 	SwAttrSet* pNewAttrSet = 0;
2590     // --> OD 2007-07-10 #i75353#
2591     bool bClearHardSetNumRuleWhenFmtCollChanges( false );
2592     // <--
2593     if( HasSwAttrSet() )
2594 	{
2595 		pNewAttrSet = new SwAttrSet( *GetpSwAttrSet() );
2596         const SfxItemSet* pTmpSet = GetpSwAttrSet();
2597 
2598 		if( bNext )		// der naechste erbt keine Breaks!
2599 			pTmpSet = pNewAttrSet;
2600 
2601 		// PageBreaks/PageDesc/ColBreak rausschmeissen.
2602         sal_Bool bRemoveFromCache = sal_False;
2603         std::vector<sal_uInt16> aClearWhichIds;
2604         if ( bNext )
2605             bRemoveFromCache = ( 0 != pNewAttrSet->ClearItem( RES_PAGEDESC ) );
2606         else
2607             aClearWhichIds.push_back( RES_PAGEDESC );
2608 
2609 		if( SFX_ITEM_SET == pTmpSet->GetItemState( RES_BREAK, sal_False ) )
2610 		{
2611             if ( bNext )
2612                 pNewAttrSet->ClearItem( RES_BREAK );
2613             else
2614                 aClearWhichIds.push_back( RES_BREAK );
2615             bRemoveFromCache = sal_True;
2616 		}
2617 		if( SFX_ITEM_SET == pTmpSet->GetItemState( RES_KEEP, sal_False ) )
2618 		{
2619             if ( bNext )
2620                 pNewAttrSet->ClearItem( RES_KEEP );
2621             else
2622                 aClearWhichIds.push_back( RES_KEEP );
2623             bRemoveFromCache = sal_True;
2624 		}
2625 		if( SFX_ITEM_SET == pTmpSet->GetItemState( RES_PARATR_SPLIT, sal_False ) )
2626 		{
2627             if ( bNext )
2628                 pNewAttrSet->ClearItem( RES_PARATR_SPLIT );
2629             else
2630                 aClearWhichIds.push_back( RES_PARATR_SPLIT );
2631             bRemoveFromCache = sal_True;
2632 		}
2633 		if(SFX_ITEM_SET == pTmpSet->GetItemState(RES_PARATR_NUMRULE, sal_False))
2634         {
2635             SwNumRule * pRule = GetNumRule();
2636 
2637             if (pRule && IsOutline())
2638             {
2639                 if ( bNext )
2640                     pNewAttrSet->ClearItem(RES_PARATR_NUMRULE);
2641                 else
2642                 {
2643                     // --> OD 2007-07-10 #i75353#
2644                     // No clear of hard set numbering rule at an outline paragraph at this point.
2645                     // Only if the paragraph style changes - see below.
2646 //                    aClearWhichIds.push_back( RES_PARATR_NUMRULE );
2647                     bClearHardSetNumRuleWhenFmtCollChanges = true;
2648                     // <--
2649                 }
2650                 bRemoveFromCache = sal_True;
2651             }
2652         }
2653 
2654         if ( 0 != aClearWhichIds.size() )
2655             bRemoveFromCache = 0 != ClearItemsFromAttrSet( aClearWhichIds );
2656 
2657 		if( !bNext && bRemoveFromCache && IsInCache() )
2658 		{
2659 			SwFrm::GetCache().Delete( this );
2660 			SetInCache( sal_False );
2661 		}
2662 	}
2663 	SwNodes& rNds = GetNodes();
2664 
2665 	SwTxtFmtColl* pColl = GetTxtColl();
2666 
2667 	SwTxtNode *pNode = new SwTxtNode( rPos, pColl, pNewAttrSet );
2668 
2669 	if( pNewAttrSet )
2670 		delete pNewAttrSet;
2671 
2672 	const SwNumRule* pRule = GetNumRule();
2673 	if( pRule && pRule == pNode->GetNumRule() && rNds.IsDocNodes() ) // #115901#
2674 	{
2675         // --> OD 2005-10-18 #i55459#
2676         // - correction: parameter <bNext> has to be checked, as it was in the
2677         //   previous implementation.
2678         if ( !bNext && !IsCountedInList() )
2679             SetCountedInList(true);
2680         // <--
2681 	}
2682 
2683 	// jetzt kann es sein, das durch die Nummerierung dem neuen Node eine
2684 	// Vorlage aus dem Pool zugewiesen wurde. Dann darf diese nicht
2685 	// nochmal uebergeplaettet werden !!
2686 	if( pColl != pNode->GetTxtColl() ||
2687 		( bChgFollow && pColl != GetTxtColl() ))
2688 		return pNode;		// mehr duerfte nicht gemacht werden oder ????
2689 
2690 	pNode->_ChgTxtCollUpdateNum( 0, pColl ); // fuer Nummerierung/Gliederung
2691 	if( bNext || !bChgFollow )
2692 		return pNode;
2693 
2694 	SwTxtFmtColl *pNextColl = &pColl->GetNextTxtFmtColl();
2695     // --> OD 2009-08-12 #i101870#
2696     // perform action on different paragraph styles before applying the new paragraph style
2697     if (pNextColl != pColl)
2698     {
2699         // --> OD 2007-07-10 #i75353#
2700         if ( bClearHardSetNumRuleWhenFmtCollChanges )
2701         {
2702             std::vector<sal_uInt16> aClearWhichIds;
2703             aClearWhichIds.push_back( RES_PARATR_NUMRULE );
2704             if ( ClearItemsFromAttrSet( aClearWhichIds ) != 0 && IsInCache() )
2705             {
2706                 SwFrm::GetCache().Delete( this );
2707                 SetInCache( sal_False );
2708             }
2709         }
2710         // <--
2711     }
2712     // <--
2713 	ChgFmtColl( pNextColl );
2714 
2715 	return pNode;
2716 }
2717 
2718 SwCntntNode* SwTxtNode::AppendNode( const SwPosition & rPos )
2719 {
2720 	// Position hinter dem eingefuegt wird
2721 	SwNodeIndex aIdx( rPos.nNode, 1 );
2722 	SwTxtNode* pNew = _MakeNewTxtNode( aIdx, sal_True );
2723 
2724     // --> OD 2008-05-14 #refactorlists#
2725     // reset list attributes at appended text node
2726     pNew->ResetAttr( RES_PARATR_LIST_ISRESTART );
2727     pNew->ResetAttr( RES_PARATR_LIST_RESTARTVALUE );
2728     pNew->ResetAttr( RES_PARATR_LIST_ISCOUNTED );
2729     if ( pNew->GetNumRule() == 0 )
2730     {
2731         pNew->ResetAttr( RES_PARATR_LIST_ID );
2732         pNew->ResetAttr( RES_PARATR_LIST_LEVEL );
2733     }
2734     // <--
2735     // --> OD 2008-03-13 #refactorlists#
2736 //    SyncNumberAndNumRule();
2737     if ( !IsInList() && GetNumRule() && GetListId().Len() > 0 )
2738     {
2739         AddToList();
2740     }
2741     // <--
2742 
2743 	if( GetDepends() )
2744 		MakeFrms( *pNew );
2745 	return pNew;
2746 }
2747 
2748 /*************************************************************************
2749  *						SwTxtNode::GetTxtAttr
2750  *************************************************************************/
2751 
2752 SwTxtAttr * SwTxtNode::GetTxtAttrForCharAt( const xub_StrLen nIndex,
2753     const RES_TXTATR nWhich ) const
2754 {
2755     if ( HasHints() )
2756     {
2757         for ( sal_uInt16 i = 0; i < m_pSwpHints->Count(); ++i )
2758         {
2759             SwTxtAttr * const pHint = m_pSwpHints->GetTextHint(i);
2760             const xub_StrLen nStartPos = *pHint->GetStart();
2761             if ( nIndex < nStartPos )
2762             {
2763                 return 0;
2764             }
2765             if ( (nIndex == nStartPos) && pHint->HasDummyChar() )
2766             {
2767                 return ( RES_TXTATR_END == nWhich || nWhich == pHint->Which() )
2768                     ? pHint : 0;
2769             }
2770         }
2771     }
2772     return 0;
2773 }
2774 
2775 // -> #i29560#
2776 sal_Bool SwTxtNode::HasNumber() const
2777 {
2778     sal_Bool bResult = sal_False;
2779 
2780     const SwNumRule* pRule = GetNum() ? GetNum()->GetNumRule() : 0L;
2781     if ( pRule )
2782     {
2783         SwNumFmt aFmt(pRule->Get( static_cast<sal_uInt16>(GetActualListLevel())));
2784 
2785         // #i40041#
2786         bResult = aFmt.IsEnumeration() &&
2787             SVX_NUM_NUMBER_NONE != aFmt.GetNumberingType();
2788     }
2789 
2790     return bResult;
2791 }
2792 
2793 sal_Bool SwTxtNode::HasBullet() const
2794 {
2795     sal_Bool bResult = sal_False;
2796 
2797     const SwNumRule* pRule = GetNum() ? GetNum()->GetNumRule() : 0L;
2798     if ( pRule )
2799     {
2800         SwNumFmt aFmt(pRule->Get( static_cast<sal_uInt16>(GetActualListLevel())));
2801 
2802         bResult = aFmt.IsItemize();
2803     }
2804 
2805     return bResult;
2806 }
2807 // <- #i29560#
2808 
2809 // --> OD 2005-11-17 #128041# - introduce parameter <_bInclPrefixAndSuffixStrings>
2810 //i53420 added max outline parameter
2811 XubString SwTxtNode::GetNumString( const bool _bInclPrefixAndSuffixStrings, const unsigned int _nRestrictToThisLevel ) const
2812 {
2813     if (GetDoc()->IsClipBoard() && m_pNumStringCache.get())
2814     {
2815         // #i111677# do not expand number strings in clipboard documents
2816         return *m_pNumStringCache;
2817     }
2818     const SwNumRule* pRule = GetNum() ? GetNum()->GetNumRule() : 0L;
2819     if ( pRule &&
2820          IsCountedInList() )
2821     {
2822         SvxNumberType const& rNumberType(
2823                 pRule->Get( static_cast<sal_uInt16>(GetActualListLevel()) ) );
2824         if (rNumberType.IsTxtFmt() ||
2825         // #b6432095#
2826             (style::NumberingType::NUMBER_NONE == rNumberType.GetNumberingType()))
2827         {
2828             return pRule->MakeNumString( GetNum()->GetNumberVector(),
2829                                      _bInclPrefixAndSuffixStrings ? sal_True : sal_False,
2830                                      sal_False,
2831                                      _nRestrictToThisLevel );
2832         }
2833     }
2834 
2835     return aEmptyStr;
2836 }
2837 
2838 long SwTxtNode::GetLeftMarginWithNum( sal_Bool bTxtLeft ) const
2839 {
2840     long nRet = 0;
2841     const SwNumRule* pRule = GetNum() ? GetNum()->GetNumRule() : 0L;
2842 	if( pRule )
2843 	{
2844         const SwNumFmt& rFmt = pRule->Get(static_cast<sal_uInt16>(GetActualListLevel()));
2845         // --> OD 2008-01-16 #newlistlevelattrs#
2846         if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
2847         {
2848             nRet = rFmt.GetAbsLSpace();
2849 
2850             if( !bTxtLeft )
2851             {
2852                 if( 0 > rFmt.GetFirstLineOffset() &&
2853                     nRet > -rFmt.GetFirstLineOffset() )
2854                     nRet = nRet + rFmt.GetFirstLineOffset();
2855                 else
2856                     nRet = 0;
2857             }
2858 
2859             if( pRule->IsAbsSpaces() )
2860                 nRet = nRet - GetSwAttrSet().GetLRSpace().GetLeft();
2861         }
2862         else if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
2863         {
2864             if ( AreListLevelIndentsApplicable() )
2865             {
2866                 nRet = rFmt.GetIndentAt();
2867                 // --> OD 2008-06-06 #i90401#
2868                 // Only negative first line indents have consider for the left margin
2869                 if ( !bTxtLeft &&
2870                      rFmt.GetFirstLineIndent() < 0 )
2871                 {
2872                     nRet = nRet + rFmt.GetFirstLineIndent();
2873                 }
2874                 // <--
2875             }
2876         }
2877         // <--
2878 	}
2879 
2880     return nRet;
2881 }
2882 
2883 sal_Bool SwTxtNode::GetFirstLineOfsWithNum( short& rFLOffset ) const
2884 {
2885     sal_Bool bRet( sal_False );
2886     // --> OD 2009-09-08 #i95907#, #b6879723#
2887     rFLOffset = 0;
2888     // <--
2889 
2890     // --> OD 2005-11-02 #i51089 - TUNING#
2891     const SwNumRule* pRule = GetNum() ? GetNum()->GetNumRule() : 0L;
2892     if ( pRule )
2893 	{
2894         if ( IsCountedInList() )
2895         {
2896             // --> OD 2008-01-16 #newlistlevelattrs#
2897             const SwNumFmt& rFmt = pRule->Get(static_cast<sal_uInt16>(GetActualListLevel()));
2898             if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
2899             {
2900                 rFLOffset = pRule->Get( static_cast<sal_uInt16>(GetActualListLevel() )).GetFirstLineOffset();
2901 
2902                 if (!getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING))
2903                 {
2904                     SvxLRSpaceItem aItem = GetSwAttrSet().GetLRSpace();
2905                     rFLOffset = rFLOffset + aItem.GetTxtFirstLineOfst();
2906                 }
2907             }
2908             else if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
2909             {
2910                 if ( AreListLevelIndentsApplicable() )
2911                 {
2912                     rFLOffset = static_cast<sal_uInt16>(rFmt.GetFirstLineIndent());
2913                 }
2914                 else if (!getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING))
2915                 {
2916                     SvxLRSpaceItem aItem = GetSwAttrSet().GetLRSpace();
2917                     rFLOffset = aItem.GetTxtFirstLineOfst();
2918                 }
2919             }
2920             // <--
2921         }
2922 
2923         bRet = sal_True;
2924 	}
2925     else
2926     {
2927         rFLOffset = GetSwAttrSet().GetLRSpace().GetTxtFirstLineOfst();
2928     }
2929 
2930     return bRet;
2931 }
2932 
2933 // --> OD 2010-01-05 #b6884103#
2934 SwTwips SwTxtNode::GetAdditionalIndentForStartingNewList() const
2935 {
2936     SwTwips nAdditionalIndent = 0;
2937 
2938     const SwNumRule* pRule = GetNum() ? GetNum()->GetNumRule() : 0L;
2939     if ( pRule )
2940     {
2941         const SwNumFmt& rFmt = pRule->Get(static_cast<sal_uInt16>(GetActualListLevel()));
2942         if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
2943         {
2944             nAdditionalIndent = GetSwAttrSet().GetLRSpace().GetLeft();
2945 
2946             if (getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING))
2947             {
2948                 nAdditionalIndent = nAdditionalIndent -
2949                                     GetSwAttrSet().GetLRSpace().GetTxtFirstLineOfst();
2950             }
2951         }
2952         else if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
2953         {
2954             if ( AreListLevelIndentsApplicable() )
2955             {
2956                 nAdditionalIndent = rFmt.GetIndentAt() + rFmt.GetFirstLineIndent();
2957             }
2958             else
2959             {
2960                 nAdditionalIndent = GetSwAttrSet().GetLRSpace().GetLeft();
2961                 if (getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING))
2962                 {
2963                     nAdditionalIndent = nAdditionalIndent -
2964                                         GetSwAttrSet().GetLRSpace().GetTxtFirstLineOfst();
2965                 }
2966             }
2967         }
2968     }
2969     else
2970     {
2971         nAdditionalIndent = GetSwAttrSet().GetLRSpace().GetLeft();
2972     }
2973 
2974     return nAdditionalIndent;
2975 }
2976 // <--
2977 
2978 // --> OD 2008-12-02 #i96772#
2979 void SwTxtNode::ClearLRSpaceItemDueToListLevelIndents( SvxLRSpaceItem& o_rLRSpaceItem ) const
2980 {
2981     if ( AreListLevelIndentsApplicable() )
2982     {
2983         const SwNumRule* pRule = GetNumRule();
2984         if ( pRule && GetActualListLevel() >= 0 )
2985         {
2986             const SwNumFmt& rFmt = pRule->Get(static_cast<sal_uInt16>(GetActualListLevel()));
2987             if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
2988             {
2989                 SvxLRSpaceItem aLR( RES_LR_SPACE );
2990                 o_rLRSpaceItem = aLR;
2991             }
2992         }
2993     }
2994 }
2995 // <--
2996 
2997 // --> OD 2008-07-01 #i91133#
2998 long SwTxtNode::GetLeftMarginForTabCalculation() const
2999 {
3000     long nLeftMarginForTabCalc = 0;
3001 
3002     bool bLeftMarginForTabCalcSetToListLevelIndent( false );
3003     const SwNumRule* pRule = GetNum() ? GetNum()->GetNumRule() : 0;
3004     if( pRule )
3005     {
3006         const SwNumFmt& rFmt = pRule->Get(static_cast<sal_uInt16>(GetActualListLevel()));
3007         if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
3008         {
3009             if ( AreListLevelIndentsApplicable() )
3010             {
3011                 nLeftMarginForTabCalc = rFmt.GetIndentAt();
3012                 bLeftMarginForTabCalcSetToListLevelIndent = true;
3013             }
3014         }
3015     }
3016     if ( !bLeftMarginForTabCalcSetToListLevelIndent )
3017     {
3018         nLeftMarginForTabCalc = GetSwAttrSet().GetLRSpace().GetTxtLeft();
3019     }
3020 
3021     return nLeftMarginForTabCalc;
3022 }
3023 // <--
3024 
3025 void SwTxtNode::Replace0xFF( XubString& rTxt, xub_StrLen& rTxtStt,
3026 							xub_StrLen nEndPos, sal_Bool bExpandFlds ) const
3027 {
3028 	if( GetpSwpHints() )
3029 	{
3030 		sal_Unicode cSrchChr = CH_TXTATR_BREAKWORD;
3031 		for( int nSrchIter = 0; 2 > nSrchIter; ++nSrchIter,
3032 								cSrchChr = CH_TXTATR_INWORD )
3033 		{
3034 			xub_StrLen nPos = rTxt.Search( cSrchChr );
3035 			while( STRING_NOTFOUND != nPos && nPos < nEndPos )
3036             {
3037                 const SwTxtAttr* const pAttr =
3038                     GetTxtAttrForCharAt( rTxtStt + nPos );
3039 				if( pAttr )
3040 				{
3041 					switch( pAttr->Which() )
3042 					{
3043 					case RES_TXTATR_FIELD:
3044 						rTxt.Erase( nPos, 1 );
3045 						if( bExpandFlds )
3046 						{
3047                             const XubString aExpand(
3048                                 static_cast<SwTxtFld const*>(pAttr)->GetFld()
3049                                     .GetFld()->ExpandField(true));
3050 							rTxt.Insert( aExpand, nPos );
3051 							nPos = nPos + aExpand.Len();
3052 							nEndPos = nEndPos + aExpand.Len();
3053 							rTxtStt = rTxtStt - aExpand.Len();
3054 						}
3055 						++rTxtStt;
3056 						break;
3057 					case RES_TXTATR_FTN:
3058 						rTxt.Erase( nPos, 1 );
3059 						if( bExpandFlds )
3060 						{
3061 							const SwFmtFtn& rFtn = pAttr->GetFtn();
3062 							XubString sExpand;
3063 							if( rFtn.GetNumStr().Len() )
3064 								sExpand = rFtn.GetNumStr();
3065 							else if( rFtn.IsEndNote() )
3066 								sExpand = GetDoc()->GetEndNoteInfo().aFmt.
3067 												GetNumStr( rFtn.GetNumber() );
3068 							else
3069 								sExpand = GetDoc()->GetFtnInfo().aFmt.
3070 												GetNumStr( rFtn.GetNumber() );
3071 							rTxt.Insert( sExpand, nPos );
3072 							nPos = nPos + sExpand.Len();
3073 							nEndPos = nEndPos + sExpand.Len();
3074 							rTxtStt = rTxtStt - sExpand.Len();
3075 						}
3076 						++rTxtStt;
3077 						break;
3078 					default:
3079 						rTxt.Erase( nPos, 1 );
3080 						++rTxtStt;
3081 					}
3082 				}
3083 				else
3084 					++nPos, ++nEndPos;
3085 				nPos = rTxt.Search( cSrchChr, nPos );
3086 			}
3087 		}
3088 	}
3089 }
3090 
3091 /*************************************************************************
3092  *                      SwTxtNode::GetExpandTxt
3093  * Expand fields
3094  *************************************************************************/
3095 // --> OD 2007-11-15 #i83479# - handling of new parameters
3096 XubString SwTxtNode::GetExpandTxt( const xub_StrLen nIdx,
3097                                    const xub_StrLen nLen,
3098                                    const bool bWithNum,
3099                                    const bool bAddSpaceAfterListLabelStr,
3100                                    const bool bWithSpacesForLevel ) const
3101 {
3102 	XubString aTxt( GetTxt().Copy( nIdx, nLen ) );
3103 	xub_StrLen nTxtStt = nIdx;
3104 	Replace0xFF( aTxt, nTxtStt, aTxt.Len(), sal_True );
3105 	if( bWithNum )
3106     {
3107         XubString aListLabelStr = GetNumString();
3108         if ( aListLabelStr.Len() > 0 )
3109         {
3110             if ( bAddSpaceAfterListLabelStr )
3111             {
3112                 const sal_Unicode aSpace = ' ';
3113                 aTxt.Insert( aSpace, 0 );
3114             }
3115             aTxt.Insert( GetNumString(), 0 );
3116         }
3117     }
3118 
3119     if ( bWithSpacesForLevel && GetActualListLevel() > 0 )
3120     {
3121         int nLevel( GetActualListLevel() );
3122         while ( nLevel > 0 )
3123         {
3124             const sal_Unicode aSpace = ' ';
3125             aTxt.Insert( aSpace , 0 );
3126             aTxt.Insert( aSpace , 0 );
3127             --nLevel;
3128         }
3129     }
3130 
3131 	return aTxt;
3132 }
3133 // <--
3134 
3135 sal_Bool SwTxtNode::GetExpandTxt( SwTxtNode& rDestNd, const SwIndex* pDestIdx,
3136                         xub_StrLen nIdx, xub_StrLen nLen, sal_Bool bWithNum,
3137                         sal_Bool bWithFtn, sal_Bool bReplaceTabsWithSpaces ) const
3138 {
3139 	if( &rDestNd == this )
3140 		return sal_False;
3141 
3142 	SwIndex aDestIdx( &rDestNd, rDestNd.GetTxt().Len() );
3143 	if( pDestIdx )
3144 		aDestIdx = *pDestIdx;
3145 	xub_StrLen nDestStt = aDestIdx.GetIndex();
3146 
3147 	// Text einfuegen
3148     String sTmpText = GetTxt();
3149     if( bReplaceTabsWithSpaces )
3150         sTmpText.SearchAndReplaceAll('\t', ' ');
3151 
3152     // mask hidden characters
3153     const xub_Unicode cChar = CH_TXTATR_BREAKWORD;
3154     sal_uInt16 nHiddenChrs =
3155         SwScriptInfo::MaskHiddenRanges( *this, sTmpText, 0, sTmpText.Len(), cChar );
3156 
3157     sTmpText = sTmpText.Copy( nIdx, nLen );
3158     rDestNd.InsertText( sTmpText, aDestIdx );
3159 	nLen = aDestIdx.GetIndex() - nDestStt;
3160 
3161 	// alle FontAttribute mit CHARSET Symbol in dem Bereich setzen
3162     if ( HasHints() )
3163     {
3164 		xub_StrLen nInsPos = nDestStt - nIdx;
3165         for ( sal_uInt16 i = 0; i < m_pSwpHints->Count(); i++ )
3166         {
3167             const SwTxtAttr* pHt = (*m_pSwpHints)[i];
3168             const xub_StrLen nAttrStartIdx = *pHt->GetStart();
3169             const sal_uInt16 nWhich = pHt->Which();
3170             if (nIdx + nLen <= nAttrStartIdx)
3171 				break;		// ueber das Textende
3172 
3173 			const xub_StrLen *pEndIdx = pHt->GetEnd();
3174 			if( pEndIdx && *pEndIdx > nIdx &&
3175 				( RES_CHRATR_FONT == nWhich ||
3176                   RES_TXTATR_CHARFMT == nWhich ||
3177                   RES_TXTATR_AUTOFMT == nWhich ))
3178             {
3179                 const SvxFontItem* const pFont =
3180                     static_cast<const SvxFontItem*>(
3181                         CharFmt::GetItem( *pHt, RES_CHRATR_FONT ));
3182                 if ( pFont && RTL_TEXTENCODING_SYMBOL == pFont->GetCharSet() )
3183                 {
3184                     // attribute in area => copy
3185                     rDestNd.InsertItem( *const_cast<SvxFontItem*>(pFont),
3186                             nInsPos + nAttrStartIdx, nInsPos + *pEndIdx );
3187                 }
3188             }
3189             else if ( pHt->HasDummyChar() && (nAttrStartIdx >= nIdx) )
3190 			{
3191 				aDestIdx = nInsPos + nAttrStartIdx;
3192 				switch( nWhich )
3193 				{
3194 				case RES_TXTATR_FIELD:
3195 					{
3196                         XubString const aExpand(
3197                             static_cast<SwTxtFld const*>(pHt)->GetFld().GetFld()
3198                                 ->ExpandField(true));
3199 						if( aExpand.Len() )
3200 						{
3201 							aDestIdx++;		// dahinter einfuegen;
3202                             rDestNd.InsertText( aExpand, aDestIdx );
3203 							aDestIdx = nInsPos + nAttrStartIdx;
3204 							nInsPos = nInsPos + aExpand.Len();
3205                         }
3206                         rDestNd.EraseText( aDestIdx, 1 );
3207 						--nInsPos;
3208 					}
3209 					break;
3210 
3211 				case RES_TXTATR_FTN:
3212 					{
3213                         if ( bWithFtn )
3214                         {
3215                             const SwFmtFtn& rFtn = pHt->GetFtn();
3216                             XubString sExpand;
3217                             if( rFtn.GetNumStr().Len() )
3218                                 sExpand = rFtn.GetNumStr();
3219                             else if( rFtn.IsEndNote() )
3220                                 sExpand = GetDoc()->GetEndNoteInfo().aFmt.
3221                                                 GetNumStr( rFtn.GetNumber() );
3222                             else
3223                                 sExpand = GetDoc()->GetFtnInfo().aFmt.
3224                                                 GetNumStr( rFtn.GetNumber() );
3225                             if( sExpand.Len() )
3226                             {
3227                                 aDestIdx++;     // insert behind
3228                                 SvxEscapementItem aItem(
3229                                         SVX_ESCAPEMENT_SUPERSCRIPT );
3230                                 rDestNd.InsertItem(aItem,
3231                                         aDestIdx.GetIndex(),
3232                                         aDestIdx.GetIndex() );
3233                                 rDestNd.InsertText( sExpand, aDestIdx,
3234                                   IDocumentContentOperations::INS_EMPTYEXPAND);
3235                                 aDestIdx = nInsPos + nAttrStartIdx;
3236                                 nInsPos = nInsPos + sExpand.Len();
3237                             }
3238                         }
3239                         rDestNd.EraseText( aDestIdx, 1 );
3240 						--nInsPos;
3241 					}
3242 					break;
3243 
3244 				default:
3245                     rDestNd.EraseText( aDestIdx, 1 );
3246 					--nInsPos;
3247 				}
3248 			}
3249 		}
3250 	}
3251 
3252 	if( bWithNum )
3253 	{
3254 		aDestIdx = nDestStt;
3255         rDestNd.InsertText( GetNumString(), aDestIdx );
3256 	}
3257 
3258     if ( nHiddenChrs > 0 )
3259     {
3260         aDestIdx = 0;
3261         while ( aDestIdx < rDestNd.GetTxt().Len() )
3262         {
3263             if ( cChar == rDestNd.GetTxt().GetChar( aDestIdx.GetIndex() ) )
3264             {
3265                 xub_StrLen nIndex = aDestIdx.GetIndex();
3266                 while ( nIndex < rDestNd.GetTxt().Len() &&
3267                         cChar == rDestNd.GetTxt().GetChar( ++nIndex ) )
3268                     ;
3269                 rDestNd.EraseText( aDestIdx, nIndex - aDestIdx.GetIndex() );
3270             }
3271             else
3272                 ++aDestIdx;
3273         }
3274     }
3275 
3276 	return sal_True;
3277 }
3278 
3279 const ModelToViewHelper::ConversionMap*
3280         SwTxtNode::BuildConversionMap( rtl::OUString& rRetText ) const
3281 {
3282     const rtl::OUString& rNodeText = GetTxt();
3283     rRetText = rNodeText;
3284     ModelToViewHelper::ConversionMap* pConversionMap = 0;
3285 
3286     const SwpHints* pSwpHints2 = GetpSwpHints();
3287     xub_StrLen nPos = 0;
3288 
3289     for ( sal_uInt16 i = 0; pSwpHints2 && i < pSwpHints2->Count(); ++i )
3290     {
3291         const SwTxtAttr* pAttr = (*pSwpHints2)[i];
3292         if ( RES_TXTATR_FIELD == pAttr->Which() )
3293         {
3294             const XubString aExpand(
3295                 static_cast<SwTxtFld const*>(pAttr)->GetFld().GetFld()
3296                     ->ExpandField(true));
3297             if ( aExpand.Len() > 0 )
3298             {
3299                 const xub_StrLen nFieldPos = *pAttr->GetStart();
3300                 rRetText = rRetText.replaceAt( nPos + nFieldPos, 1, aExpand );
3301                 if ( !pConversionMap )
3302                     pConversionMap = new ModelToViewHelper::ConversionMap;
3303                 pConversionMap->push_back(
3304                         ModelToViewHelper::ConversionMapEntry(
3305                             nFieldPos, nPos + nFieldPos ) );
3306                 nPos += ( aExpand.Len() - 1 );
3307             }
3308         }
3309     }
3310 
3311     if ( pConversionMap && pConversionMap->size() )
3312         pConversionMap->push_back(
3313             ModelToViewHelper::ConversionMapEntry(
3314                 rNodeText.getLength()+1, rRetText.getLength()+1 ) );
3315 
3316     return pConversionMap;
3317 }
3318 
3319 XubString SwTxtNode::GetRedlineTxt( xub_StrLen nIdx, xub_StrLen nLen,
3320 								sal_Bool bExpandFlds, sal_Bool bWithNum ) const
3321 {
3322 	SvUShorts aRedlArr;
3323 	const SwDoc* pDoc = GetDoc();
3324 	sal_uInt16 nRedlPos = pDoc->GetRedlinePos( *this, nsRedlineType_t::REDLINE_DELETE );
3325 	if( USHRT_MAX != nRedlPos )
3326 	{
3327 		// es existiert fuer den Node irgendein Redline-Delete-Object
3328 		const sal_uLong nNdIdx = GetIndex();
3329 		for( ; nRedlPos < pDoc->GetRedlineTbl().Count() ; ++nRedlPos )
3330 		{
3331 			const SwRedline* pTmp = pDoc->GetRedlineTbl()[ nRedlPos ];
3332 			if( nsRedlineType_t::REDLINE_DELETE == pTmp->GetType() )
3333 			{
3334 				const SwPosition *pRStt = pTmp->Start(), *pREnd = pTmp->End();
3335 				if( pRStt->nNode < nNdIdx )
3336 				{
3337 					if( pREnd->nNode > nNdIdx )
3338 						// Absatz ist komplett geloescht
3339 						return aEmptyStr;
3340 					else if( pREnd->nNode == nNdIdx )
3341 					{
3342 						// von 0 bis nContent ist alles geloescht
3343 						aRedlArr.Insert( xub_StrLen(0), aRedlArr.Count() );
3344 						aRedlArr.Insert( pREnd->nContent.GetIndex(), aRedlArr.Count() );
3345 					}
3346 				}
3347 				else if( pRStt->nNode == nNdIdx )
3348 				{
3349 					aRedlArr.Insert( pRStt->nContent.GetIndex(), aRedlArr.Count() );
3350 					if( pREnd->nNode == nNdIdx )
3351 						aRedlArr.Insert( pREnd->nContent.GetIndex(), aRedlArr.Count() );
3352 					else
3353 					{
3354 						aRedlArr.Insert( GetTxt().Len(), aRedlArr.Count() );
3355 						break; 		// mehr kann nicht kommen
3356 					}
3357 				}
3358 				else
3359 					break; 		// mehr kann nicht kommen
3360 			}
3361 		}
3362 	}
3363 
3364 	XubString aTxt( GetTxt().Copy( nIdx, nLen ) );
3365 
3366 	xub_StrLen nTxtStt = nIdx, nIdxEnd = nIdx + aTxt.Len();
3367 	for( sal_uInt16 n = 0; n < aRedlArr.Count(); n += 2 )
3368 	{
3369 		xub_StrLen nStt = aRedlArr[ n ], nEnd = aRedlArr[ n+1 ];
3370 		if( ( nIdx <= nStt && nStt <= nIdxEnd ) ||
3371 			( nIdx <= nEnd && nEnd <= nIdxEnd ))
3372 		{
3373 			if( nStt < nIdx ) nStt = nIdx;
3374 			if( nIdxEnd < nEnd ) nEnd = nIdxEnd;
3375 			xub_StrLen nDelCnt = nEnd - nStt;
3376 			aTxt.Erase( nStt - nTxtStt, nDelCnt );
3377 			Replace0xFF( aTxt, nTxtStt, nStt - nTxtStt, bExpandFlds );
3378 			nTxtStt = nTxtStt + nDelCnt;
3379 		}
3380 		else if( nStt >= nIdxEnd )
3381 			break;
3382 	}
3383 	Replace0xFF( aTxt, nTxtStt, aTxt.Len(), bExpandFlds );
3384 
3385 	if( bWithNum )
3386 		aTxt.Insert( GetNumString(), 0 );
3387 	return aTxt;
3388 }
3389 
3390 /*************************************************************************
3391  *                        SwTxtNode::ReplaceText
3392  *************************************************************************/
3393 
3394 void SwTxtNode::ReplaceText( const SwIndex& rStart, const xub_StrLen nDelLen,
3395                              const XubString& rText )
3396 {
3397     ASSERT( rStart.GetIndex() < m_Text.Len() &&
3398             rStart.GetIndex() + nDelLen <= m_Text.Len(),
3399             "SwTxtNode::ReplaceText: index out of bounds" );
3400     const xub_StrLen nStartPos = rStart.GetIndex();
3401     xub_StrLen nEndPos = nStartPos + nDelLen;
3402     xub_StrLen nLen = nDelLen;
3403     for ( xub_StrLen nPos = nStartPos; nPos < nEndPos; ++nPos )
3404     {
3405         if ( ( CH_TXTATR_BREAKWORD == m_Text.GetChar( nPos ) ) ||
3406              ( CH_TXTATR_INWORD    == m_Text.GetChar( nPos ) ) )
3407         {
3408             SwTxtAttr *const pHint = GetTxtAttrForCharAt( nPos );
3409             if (pHint)
3410             {
3411                 ASSERT (!( pHint->GetEnd() && pHint->HasDummyChar()
3412                             && (*pHint->GetStart() < nEndPos)
3413                             && (*pHint->GetEnd()   > nEndPos) ),
3414                     "ReplaceText: ERROR: "
3415                     "deleting left-overlapped attribute with CH_TXTATR");
3416                 DeleteAttribute( pHint );
3417                 --nEndPos;
3418                 --nLen;
3419             }
3420         }
3421     }
3422 
3423 	sal_Bool bOldExpFlg = IsIgnoreDontExpand();
3424 	SetIgnoreDontExpand( sal_True );
3425 
3426 	if( nLen && rText.Len() )
3427 	{
3428 		// dann das 1. Zeichen ersetzen den Rest loschen und einfuegen
3429 		// Dadurch wird die Attributierung des 1. Zeichen expandiert!
3430         m_Text.SetChar( nStartPos, rText.GetChar( 0 ) );
3431 
3432 		((SwIndex&)rStart)++;
3433         m_Text.Erase( rStart.GetIndex(), nLen - 1 );
3434         Update( rStart, nLen - 1, true );
3435 
3436 		XubString aTmpTxt( rText ); aTmpTxt.Erase( 0, 1 );
3437         m_Text.Insert( aTmpTxt, rStart.GetIndex() );
3438         Update( rStart, aTmpTxt.Len(), false );
3439     }
3440     else
3441     {
3442         m_Text.Erase( nStartPos, nLen );
3443         Update( rStart, nLen, true );
3444 
3445         m_Text.Insert( rText, nStartPos );
3446         Update( rStart, rText.Len(), false );
3447     }
3448 
3449 	SetIgnoreDontExpand( bOldExpFlg );
3450     SwDelTxt aDelHint( nStartPos, nDelLen );
3451 	NotifyClients( 0, &aDelHint );
3452 
3453     SwInsTxt aHint( nStartPos, rText.Len() );
3454 	NotifyClients( 0, &aHint );
3455 }
3456 
3457 // --> OD 2008-03-27 #refactorlists#
3458 namespace {
3459     // Helper method for special handling of modified attributes at text node.
3460     // The following is handled:
3461     // (1) on changing the paragraph style - RES_FMT_CHG:
3462     // Check, if list style of the text node is changed. If yes, add respectively
3463     // remove the text node to the corresponding list.
3464     // (2) on changing the attributes - RES_ATTRSET_CHG:
3465     // Same as (1).
3466     // (3) on changing the list style - RES_PARATR_NUMRULE:
3467     // Same as (1).
3468     void HandleModifyAtTxtNode( SwTxtNode& rTxtNode,
3469                                 const SfxPoolItem* pOldValue,
3470                                 const SfxPoolItem* pNewValue )
3471     {
3472         const sal_uInt16 nWhich = pOldValue ? pOldValue->Which() :
3473                               pNewValue ? pNewValue->Which() : 0 ;
3474         bool bNumRuleSet = false;
3475         bool bParagraphStyleChanged = false;
3476         String sNumRule;
3477         String sOldNumRule;
3478         switch ( nWhich )
3479         {
3480             case RES_FMT_CHG:
3481             {
3482                 bParagraphStyleChanged = true;
3483                 if( rTxtNode.GetNodes().IsDocNodes() )
3484                 {
3485                     // --> OD 2008-12-17 #i70748#
3486                     // The former list style set at the paragraph can not be
3487                     // retrieved from the change set.
3488 //                    sOldNumRule =
3489 //                        dynamic_cast<const SwFmtChg*>(pOldValue)->pChangedFmt->GetNumRule().GetValue();
3490                     const SwNumRule* pFormerNumRuleAtTxtNode =
3491                         rTxtNode.GetNum() ? rTxtNode.GetNum()->GetNumRule() : 0;
3492                     if ( pFormerNumRuleAtTxtNode )
3493                     {
3494                         sOldNumRule = pFormerNumRuleAtTxtNode->GetName();
3495                     }
3496                     // <--
3497                     // --> OD 2008-11-19 #i70748#
3498                     if ( rTxtNode.IsEmptyListStyleDueToSetOutlineLevelAttr() )
3499                     {
3500                         const SwNumRuleItem& rNumRuleItem = rTxtNode.GetTxtColl()->GetNumRule();
3501                         if ( rNumRuleItem.GetValue().Len() > 0 )
3502                         {
3503                             rTxtNode.ResetEmptyListStyleDueToResetOutlineLevelAttr();
3504                         }
3505                     }
3506                     // <--
3507                     const SwNumRule* pNumRuleAtTxtNode = rTxtNode.GetNumRule();
3508                     if ( pNumRuleAtTxtNode )
3509                     {
3510                         bNumRuleSet = true;
3511                         sNumRule = pNumRuleAtTxtNode->GetName();
3512                     }
3513                 }
3514                 break;
3515             }
3516             case RES_ATTRSET_CHG:
3517             {
3518                 const SfxPoolItem* pItem = 0;
3519                 // --> OD 2008-12-19 #i70748#
3520                 // The former list style set at the paragraph can not be
3521                 // retrieved from the change set.
3522 //                if ( dynamic_cast<const SwAttrSetChg*>(pOldValue)->GetChgSet()->GetItemState( RES_PARATR_NUMRULE, sal_False, &pItem ) ==
3523 //                        SFX_ITEM_SET )
3524 //                {
3525 //                    sOldNumRule = dynamic_cast<const SwNumRuleItem*>(pItem)->GetValue();
3526 //                }
3527                 const SwNumRule* pFormerNumRuleAtTxtNode =
3528                     rTxtNode.GetNum() ? rTxtNode.GetNum()->GetNumRule() : 0;
3529                 if ( pFormerNumRuleAtTxtNode )
3530                 {
3531                     sOldNumRule = pFormerNumRuleAtTxtNode->GetName();
3532                 }
3533                 // <--
3534                 if ( dynamic_cast<const SwAttrSetChg*>(pNewValue)->GetChgSet()->GetItemState( RES_PARATR_NUMRULE, sal_False, &pItem ) ==
3535                         SFX_ITEM_SET )
3536                 {
3537                     // --> OD 2008-11-19 #i70748#
3538                     rTxtNode.ResetEmptyListStyleDueToResetOutlineLevelAttr();
3539                     // <--
3540                     bNumRuleSet = true;
3541                     // The new list style set at the paragraph can not be
3542                     // retrieved from the change set.
3543 //                    sNumRule = dynamic_cast<const SwNumRuleItem*>(pItem)->GetValue();
3544                     // <--
3545                 }
3546                 // --> OD 2008-12-17 #i70748#
3547                 // The new list style set at the paragraph.
3548                 const SwNumRule* pNumRuleAtTxtNode = rTxtNode.GetNumRule();
3549                 if ( pNumRuleAtTxtNode )
3550                 {
3551                     sNumRule = pNumRuleAtTxtNode->GetName();
3552                 }
3553                 // <--
3554                 break;
3555             }
3556             case RES_PARATR_NUMRULE:
3557             {
3558                 if ( rTxtNode.GetNodes().IsDocNodes() )
3559                 {
3560                     // The former list style set at the paragraph can not be
3561                     // retrieved from the change set.
3562 //                    if ( pOldValue )
3563 //                    {
3564 //                        sOldNumRule = dynamic_cast<const SwNumRuleItem*>(pOldValue)->GetValue();
3565 //                    }
3566                     const SwNumRule* pFormerNumRuleAtTxtNode =
3567                         rTxtNode.GetNum() ? rTxtNode.GetNum()->GetNumRule() : 0;
3568                     if ( pFormerNumRuleAtTxtNode )
3569                     {
3570                         sOldNumRule = pFormerNumRuleAtTxtNode->GetName();
3571                     }
3572                     // <--
3573                     if ( pNewValue )
3574                     {
3575                         // --> OD 2008-11-19 #i70748#
3576                         rTxtNode.ResetEmptyListStyleDueToResetOutlineLevelAttr();
3577                         // <--
3578                         bNumRuleSet = true;
3579                         // --> OD 2008-12-17 #i70748#
3580                         // The new list style set at the paragraph can not be
3581                         // retrieved from the change set.
3582 //                        sNumRule = dynamic_cast<const SwNumRuleItem*>(pNewValue)->GetValue();
3583                         // <--
3584                     }
3585                     // --> OD 2008-12-17 #i70748#
3586                     // The new list style set at the paragraph.
3587                     const SwNumRule* pNumRuleAtTxtNode = rTxtNode.GetNumRule();
3588                     if ( pNumRuleAtTxtNode )
3589                     {
3590                         sNumRule = pNumRuleAtTxtNode->GetName();
3591                     }
3592                     // <--
3593                 }
3594                 break;
3595             }
3596         }
3597         if ( sNumRule != sOldNumRule )
3598         {
3599             if ( bNumRuleSet )
3600             {
3601                 if ( sNumRule.Len() == 0 )
3602                 {
3603                     rTxtNode.RemoveFromList();
3604                     if ( bParagraphStyleChanged )
3605                     {
3606                         SvUShortsSort aResetAttrsArray;
3607                         aResetAttrsArray.Insert( RES_PARATR_LIST_ID );
3608                         aResetAttrsArray.Insert( RES_PARATR_LIST_LEVEL );
3609                         aResetAttrsArray.Insert( RES_PARATR_LIST_ISRESTART );
3610                         aResetAttrsArray.Insert( RES_PARATR_LIST_RESTARTVALUE );
3611                         aResetAttrsArray.Insert( RES_PARATR_LIST_ISCOUNTED );
3612                         SwPaM aPam( rTxtNode );
3613                         // --> OD 2008-11-28 #i96644#
3614                         // suppress side effect "send data changed events"
3615                         rTxtNode.GetDoc()->ResetAttrs( aPam, sal_False,
3616                                                        &aResetAttrsArray,
3617                                                        false );
3618                         // <--
3619                     }
3620                 }
3621                 else
3622                 {
3623                     rTxtNode.RemoveFromList();
3624                     // If new list style is the outline style, apply outline
3625                     // level as the list level.
3626                     if ( sNumRule ==
3627                             String::CreateFromAscii( SwNumRule::GetOutlineRuleName() ) )
3628                     {
3629                         // --> OD 2008-09-10 #i70748#
3630                         ASSERT( rTxtNode.GetTxtColl()->IsAssignedToListLevelOfOutlineStyle(),
3631                                 "<HandleModifyAtTxtNode()> - text node with outline style, but its paragraph style is not assigned to outline style." );
3632                         int nNewListLevel =
3633                             rTxtNode.GetTxtColl()->GetAssignedOutlineStyleLevel();
3634                         // <--
3635                         if ( 0 <= nNewListLevel && nNewListLevel < MAXLEVEL )
3636                         {
3637                             rTxtNode.SetAttrListLevel( nNewListLevel );
3638                         }
3639                     }
3640                     rTxtNode.AddToList();
3641                 }
3642             }
3643             else // <sNumRule.Len() == 0 && sOldNumRule.Len() != 0>
3644             {
3645                 rTxtNode.RemoveFromList();
3646                 if ( bParagraphStyleChanged )
3647                 {
3648                     SvUShortsSort aResetAttrsArray;
3649                     aResetAttrsArray.Insert( RES_PARATR_LIST_ID );
3650                     aResetAttrsArray.Insert( RES_PARATR_LIST_LEVEL );
3651                     aResetAttrsArray.Insert( RES_PARATR_LIST_ISRESTART );
3652                     aResetAttrsArray.Insert( RES_PARATR_LIST_RESTARTVALUE );
3653                     aResetAttrsArray.Insert( RES_PARATR_LIST_ISCOUNTED );
3654                     SwPaM aPam( rTxtNode );
3655                     // --> OD 2008-11-28 #i96644#
3656                     // suppress side effect "send data changed events"
3657                     rTxtNode.GetDoc()->ResetAttrs( aPam, sal_False,
3658                                                    &aResetAttrsArray,
3659                                                    false );
3660                     // <--
3661                     // --> OD 2008-11-19 #i70748#
3662                     if ( dynamic_cast<const SfxUInt16Item &>(rTxtNode.GetAttr( RES_PARATR_OUTLINELEVEL, sal_False )).GetValue() > 0 )
3663                     {
3664                         rTxtNode.SetEmptyListStyleDueToSetOutlineLevelAttr();
3665                     }
3666                     // <--
3667                 }
3668             }
3669         }
3670         else if ( sNumRule.Len() > 0 && !rTxtNode.IsInList() )
3671         {
3672             rTxtNode.AddToList();
3673         }
3674         // <--
3675     }
3676     // End of method <HandleModifyAtTxtNode>
3677 }
3678 // <--
3679 
3680 void SwTxtNode::Modify( const SfxPoolItem* pOldValue, const SfxPoolItem* pNewValue )
3681 {
3682     bool bWasNotifiable = m_bNotifiable;
3683     m_bNotifiable = false;
3684 
3685 	// Bug 24616/24617:
3686 	// 		Modify ueberladen, damit beim Loeschen von Vorlagen diese
3687 	// 		wieder richtig verwaltet werden (Outline-Numerierung!!)
3688 	// 	Bug25481:
3689 	//		bei Nodes im Undo nie _ChgTxtCollUpdateNum rufen.
3690 	if( pOldValue && pNewValue && RES_FMT_CHG == pOldValue->Which() &&
3691 		GetRegisteredIn() == ((SwFmtChg*)pNewValue)->pChangedFmt &&
3692 		GetNodes().IsDocNodes() )
3693     {
3694 		_ChgTxtCollUpdateNum(
3695 						(SwTxtFmtColl*)((SwFmtChg*)pOldValue)->pChangedFmt,
3696 						(SwTxtFmtColl*)((SwFmtChg*)pNewValue)->pChangedFmt );
3697     }
3698 
3699     // --> OD 2008-03-27 #refactorlists#
3700     if ( !mbInSetOrResetAttr )
3701     {
3702         HandleModifyAtTxtNode( *this, pOldValue, pNewValue );
3703     }
3704     // <--
3705 
3706 	SwCntntNode::Modify( pOldValue, pNewValue );
3707 
3708     SwDoc * pDoc = GetDoc();
3709     // --> OD 2005-11-02 #125329# - assure that text node is in document nodes array
3710     if ( pDoc && !pDoc->IsInDtor() && &pDoc->GetNodes() == &GetNodes() )
3711     // <--
3712     {
3713         pDoc->GetNodes().UpdateOutlineNode(*this);
3714     }
3715 
3716     m_bNotifiable = bWasNotifiable;
3717 
3718     if (pOldValue && (RES_REMOVE_UNO_OBJECT == pOldValue->Which()))
3719     {   // invalidate cached uno object
3720         SetXParagraph(::com::sun::star::uno::Reference<
3721                 ::com::sun::star::text::XTextContent>(0));
3722     }
3723 }
3724 
3725 SwFmtColl* SwTxtNode::ChgFmtColl( SwFmtColl *pNewColl )
3726 {
3727     ASSERT( pNewColl,"ChgFmtColl: Collectionpointer ist 0." );
3728     ASSERT( HAS_BASE( SwTxtFmtColl, pNewColl ),
3729                 "ChgFmtColl: ist kein Text-Collectionpointer." );
3730 
3731     SwTxtFmtColl *pOldColl = GetTxtColl();
3732     if( pNewColl != pOldColl )
3733     {
3734         SetCalcHiddenCharFlags();
3735         SwCntntNode::ChgFmtColl( pNewColl );
3736         // --> OD 2008-03-27 #refactorlists#
3737 //        NumRuleChgd();
3738 #if OSL_DEBUG_LEVEL > 1
3739         ASSERT( !mbInSetOrResetAttr,
3740                 "DEBUG ASSERTION - <SwTxtNode::ChgFmtColl(..)> called during <Set/ResetAttr(..)>" )
3741 #endif
3742         if ( !mbInSetOrResetAttr )
3743         {
3744             SwFmtChg aTmp1( pOldColl );
3745             SwFmtChg aTmp2( pNewColl );
3746             HandleModifyAtTxtNode( *this, &aTmp1, &aTmp2  );
3747         }
3748         // <--
3749     }
3750 
3751     // nur wenn im normalen Nodes-Array
3752     if( GetNodes().IsDocNodes() )
3753     {
3754         _ChgTxtCollUpdateNum( pOldColl, static_cast<SwTxtFmtColl *>(pNewColl) );
3755     }
3756 
3757     GetNodes().UpdateOutlineNode(*this);
3758 
3759     return pOldColl;
3760 }
3761 
3762 SwNodeNum* SwTxtNode::CreateNum() const
3763 {
3764     if ( !mpNodeNum )
3765     {
3766         // --> OD 2008-02-19 #refactorlists#
3767         mpNodeNum = new SwNodeNum( const_cast<SwTxtNode*>(this) );
3768         // <--
3769     }
3770     return mpNodeNum;
3771 }
3772 
3773 SwNumberTree::tNumberVector SwTxtNode::GetNumberVector() const
3774 {
3775     if ( GetNum() )
3776     {
3777         return GetNum()->GetNumberVector();
3778     }
3779     else
3780     {
3781         SwNumberTree::tNumberVector aResult;
3782         return aResult;
3783     }
3784 }
3785 
3786 bool SwTxtNode::IsOutline() const
3787 {
3788     bool bResult = false;
3789 
3790     //if ( GetOutlineLevel() != NO_NUMBERING )//#outline level,removed by zhaojianwei
3791     if ( GetAttrOutlineLevel() > 0 )            //<-end,zhaojianwei
3792     {
3793         bResult = !IsInRedlines();
3794     }
3795     else
3796     {
3797         const SwNumRule* pRule( GetNum() ? GetNum()->GetNumRule() : 0L );
3798         if ( pRule && pRule->IsOutlineRule() )
3799         {
3800             bResult = !IsInRedlines();
3801         }
3802     }
3803 
3804     return bResult;
3805 }
3806 
3807 bool SwTxtNode::IsOutlineStateChanged() const
3808 {
3809     return IsOutline() != m_bLastOutlineState;
3810 }
3811 
3812 void SwTxtNode::UpdateOutlineState()
3813 {
3814     m_bLastOutlineState = IsOutline();
3815 }
3816 
3817 //#outline level, zhaojianwei
3818 int SwTxtNode::GetAttrOutlineLevel() const
3819 {
3820 	return ((const SfxUInt16Item &)GetAttr(RES_PARATR_OUTLINELEVEL)).GetValue();
3821 }
3822 void SwTxtNode::SetAttrOutlineLevel(int nLevel)
3823 {
3824     ASSERT( 0 <= nLevel && nLevel <= MAXLEVEL ,"SwTxtNode: Level Out Of Range" );//#outline level,zhaojianwei
3825     if ( 0 <= nLevel && nLevel <= MAXLEVEL )
3826     {
3827         SetAttr( SfxUInt16Item( RES_PARATR_OUTLINELEVEL,
3828                                 static_cast<sal_uInt16>(nLevel) ) );
3829     }
3830 }
3831 //<-end
3832 
3833 // --> OD 2008-11-19 #i70748#
3834 bool SwTxtNode::IsEmptyListStyleDueToSetOutlineLevelAttr()
3835 {
3836     return mbEmptyListStyleSetDueToSetOutlineLevelAttr;
3837 }
3838 
3839 void SwTxtNode::SetEmptyListStyleDueToSetOutlineLevelAttr()
3840 {
3841     if ( !mbEmptyListStyleSetDueToSetOutlineLevelAttr )
3842     {
3843         SetAttr( SwNumRuleItem() );
3844         mbEmptyListStyleSetDueToSetOutlineLevelAttr = true;
3845     }
3846 }
3847 
3848 void SwTxtNode::ResetEmptyListStyleDueToResetOutlineLevelAttr()
3849 {
3850     if ( mbEmptyListStyleSetDueToSetOutlineLevelAttr )
3851     {
3852         ResetAttr( RES_PARATR_NUMRULE );
3853         mbEmptyListStyleSetDueToSetOutlineLevelAttr = false;
3854     }
3855 }
3856 // <--
3857 
3858 
3859 // --> OD 2008-02-27 #refactorlists#
3860 void SwTxtNode::SetAttrListLevel( int nLevel )
3861 {
3862     if ( nLevel < 0 || nLevel >= MAXLEVEL )
3863     {
3864         ASSERT( false,
3865                 "<SwTxtNode::SetAttrListLevel()> - value of parameter <nLevel> is out of valid range" );
3866         return;
3867     }
3868 
3869     SfxInt16Item aNewListLevelItem( RES_PARATR_LIST_LEVEL,
3870                                     static_cast<sal_Int16>(nLevel) );
3871     SetAttr( aNewListLevelItem );
3872 }
3873 // <--
3874 // --> OD 2008-02-27 #refactorlists#
3875 bool SwTxtNode::HasAttrListLevel() const
3876 {
3877     return GetpSwAttrSet() &&
3878            GetpSwAttrSet()->GetItemState( RES_PARATR_LIST_LEVEL, sal_False ) == SFX_ITEM_SET;
3879 }
3880 // <--
3881 // --> OD 2008-02-27 #refactorlists#
3882 int SwTxtNode::GetAttrListLevel() const
3883 {
3884     int nAttrListLevel = 0;
3885 
3886     const SfxInt16Item& aListLevelItem =
3887         dynamic_cast<const SfxInt16Item&>(GetAttr( RES_PARATR_LIST_LEVEL ));
3888     nAttrListLevel = static_cast<int>(aListLevelItem.GetValue());
3889 
3890     return nAttrListLevel;
3891 }
3892 // <--
3893 
3894 int SwTxtNode::GetActualListLevel() const
3895 {
3896     return GetNum() ? GetNum()->GetLevelInListTree() : -1;
3897 }
3898 
3899 // --> OD 2008-02-25 #refactorlists#
3900 void SwTxtNode::SetListRestart( bool bRestart )
3901 {
3902 //    CreateNum()->SetRestart(bRestart);
3903     if ( !bRestart )
3904     {
3905         // attribute not contained in paragraph style's attribute set. Thus,
3906         // it can be reset to the attribute pool default by resetting the attribute.
3907         ResetAttr( RES_PARATR_LIST_ISRESTART );
3908     }
3909     else
3910     {
3911         SfxBoolItem aNewIsRestartItem( RES_PARATR_LIST_ISRESTART,
3912                                        sal_True );
3913         SetAttr( aNewIsRestartItem );
3914     }
3915 }
3916 
3917 // --> OD 2008-02-25 #refactorlists#
3918 bool SwTxtNode::IsListRestart() const
3919 {
3920 //    return GetNum() ? GetNum()->IsRestart() : false;
3921     const SfxBoolItem& aIsRestartItem =
3922         dynamic_cast<const SfxBoolItem&>(GetAttr( RES_PARATR_LIST_ISRESTART ));
3923 
3924     return aIsRestartItem.GetValue() ? true : false;
3925 }
3926 // <--
3927 
3928 /** Returns if the paragraph has a visible numbering or bullet.
3929     This includes all kinds of numbering/bullet/outlines.
3930     OD 2008-02-28 #newlistlevelattrs#
3931     The concrete list label string has to be checked, too.
3932  */
3933 bool SwTxtNode::HasVisibleNumberingOrBullet() const
3934 {
3935     bool bRet = false;
3936 
3937     const SwNumRule* pRule = GetNum() ? GetNum()->GetNumRule() : 0L;
3938     if ( pRule && IsCountedInList())
3939     {
3940         // --> OD 2008-03-19 #i87154#
3941         // Correction of #newlistlevelattrs#:
3942         // The numbering type has to be checked for bullet lists.
3943         const SwNumFmt& rFmt = pRule->Get( static_cast<sal_uInt16>(GetActualListLevel() ));
3944         if ( SVX_NUM_NUMBER_NONE != rFmt.GetNumberingType() ||
3945              pRule->MakeNumString( *(GetNum()) ).Len() > 0 )
3946         {
3947             bRet = true;
3948         }
3949         // <--
3950     }
3951 
3952     return bRet;
3953 }
3954 
3955 // --> OD 2008-02-25 #refactorlists#
3956 void SwTxtNode::SetAttrListRestartValue( SwNumberTree::tSwNumTreeNumber nNumber )
3957 {
3958 //    CreateNum()->SetStart(nNumber);
3959     const bool bChanged( HasAttrListRestartValue()
3960                          ? GetAttrListRestartValue() != nNumber
3961                          : nNumber != USHRT_MAX );
3962 
3963     if ( bChanged || !HasAttrListRestartValue() )
3964     {
3965         if ( nNumber == USHRT_MAX )
3966         {
3967             ResetAttr( RES_PARATR_LIST_RESTARTVALUE );
3968         }
3969         else
3970         {
3971             SfxInt16Item aNewListRestartValueItem( RES_PARATR_LIST_RESTARTVALUE,
3972                                                    static_cast<sal_Int16>(nNumber) );
3973             SetAttr( aNewListRestartValueItem );
3974         }
3975     }
3976 }
3977 // <--
3978 
3979 // --> OD 2008-02-27 #refactorlists#
3980 bool SwTxtNode::HasAttrListRestartValue() const
3981 {
3982     return GetpSwAttrSet() &&
3983            GetpSwAttrSet()->GetItemState( RES_PARATR_LIST_RESTARTVALUE, sal_False ) == SFX_ITEM_SET;
3984 }
3985 // <--
3986 SwNumberTree::tSwNumTreeNumber SwTxtNode::GetAttrListRestartValue() const
3987 {
3988     ASSERT( HasAttrListRestartValue(),
3989             "<SwTxtNode::GetAttrListRestartValue()> - only ask for list restart value, if attribute is set at text node." );
3990 
3991     const SfxInt16Item& aListRestartValueItem =
3992         dynamic_cast<const SfxInt16Item&>(GetAttr( RES_PARATR_LIST_RESTARTVALUE ));
3993     return static_cast<SwNumberTree::tSwNumTreeNumber>(aListRestartValueItem.GetValue());
3994 }
3995 
3996 // --> OD 2008-02-25 #refactorlists#
3997 SwNumberTree::tSwNumTreeNumber SwTxtNode::GetActualListStartValue() const
3998 {
3999 //    return GetNum() ? GetNum()->GetStart() : 1;
4000     SwNumberTree::tSwNumTreeNumber nListRestartValue = 1;
4001 
4002     if ( IsListRestart() && HasAttrListRestartValue() )
4003     {
4004         nListRestartValue = GetAttrListRestartValue();
4005     }
4006     else
4007     {
4008         SwNumRule* pRule = GetNumRule();
4009         if ( pRule )
4010         {
4011             const SwNumFmt* pFmt =
4012                     pRule->GetNumFmt( static_cast<sal_uInt16>(GetAttrListLevel()) );
4013             if ( pFmt )
4014             {
4015                 nListRestartValue = pFmt->GetStart();
4016             }
4017         }
4018     }
4019 
4020     return nListRestartValue;
4021 }
4022 // <--
4023 
4024 bool SwTxtNode::IsNotifiable() const
4025 {
4026     return m_bNotifiable && IsNotificationEnabled();
4027 }
4028 
4029 bool SwTxtNode::IsNotificationEnabled() const
4030 {
4031     bool bResult = false;
4032     const SwDoc * pDoc = GetDoc();
4033     if( pDoc )
4034     {
4035         bResult = pDoc->IsInReading() || pDoc->IsInDtor() ? false : true;
4036     }
4037     return bResult;
4038 }
4039 
4040 // --> OD 2008-02-27 #refactorlists#
4041 void SwTxtNode::SetCountedInList( bool bCounted )
4042 {
4043     if ( bCounted )
4044     {
4045         // attribute not contained in paragraph style's attribute set. Thus,
4046         // it can be reset to the attribute pool default by resetting the attribute.
4047         ResetAttr( RES_PARATR_LIST_ISCOUNTED );
4048     }
4049     else
4050     {
4051         SfxBoolItem aIsCountedInListItem( RES_PARATR_LIST_ISCOUNTED, sal_False );
4052         SetAttr( aIsCountedInListItem );
4053     }
4054 }
4055 // <--
4056 
4057 bool SwTxtNode::IsCountedInList() const
4058 {
4059     const SfxBoolItem& aIsCountedInListItem =
4060         dynamic_cast<const SfxBoolItem&>(GetAttr( RES_PARATR_LIST_ISCOUNTED ));
4061 
4062     return aIsCountedInListItem.GetValue() ? true : false;
4063 }
4064 
4065 // --> OD 2008-03-13 #refactorlists#
4066 void SwTxtNode::AddToList()
4067 {
4068     if ( IsInList() )
4069     {
4070         ASSERT( false,
4071                 "<SwTxtNode::AddToList()> - the text node is already added to a list. Serious defect -> please inform OD" );
4072         return;
4073     }
4074 
4075     const String sListId = GetListId();
4076     if ( sListId.Len() > 0 )
4077     {
4078         SwList* pList = GetDoc()->getListByName( sListId );
4079         if ( pList == 0 )
4080         {
4081             // Create corresponding list.
4082             SwNumRule* pNumRule = GetNumRule();
4083             if ( pNumRule )
4084             {
4085                 pList = GetDoc()->createList( sListId, GetNumRule()->GetName() );
4086             }
4087         }
4088         ASSERT( pList != 0,
4089                 "<SwTxtNode::AddToList()> - no list for given list id. Serious defect -> please inform OD" );
4090         if ( pList )
4091         {
4092             pList->InsertListItem( *CreateNum(), GetAttrListLevel() );
4093             mpList = pList;
4094         }
4095     }
4096 }
4097 
4098 void SwTxtNode::RemoveFromList()
4099 {
4100     if ( IsInList() )
4101     {
4102         mpList->RemoveListItem( *mpNodeNum );
4103         mpList = 0;
4104         delete mpNodeNum;
4105         mpNodeNum = 0L;
4106     }
4107 }
4108 
4109 bool SwTxtNode::IsInList() const
4110 {
4111     return GetNum() != 0 && GetNum()->GetParent() != 0;
4112 }
4113 // <--
4114 
4115 bool SwTxtNode::IsFirstOfNumRule() const
4116 {
4117     bool bResult = false;
4118 
4119     if ( GetNum() && GetNum()->GetNumRule())
4120         bResult = GetNum()->IsFirst();
4121 
4122     return bResult;
4123 }
4124 
4125 // --> OD 2008-02-20 #refactorlists#
4126 void SwTxtNode::SetListId( const String sListId )
4127 {
4128     const SfxStringItem& rListIdItem =
4129             dynamic_cast<const SfxStringItem&>(GetAttr( RES_PARATR_LIST_ID ));
4130     if ( rListIdItem.GetValue() != sListId )
4131     {
4132         if ( sListId.Len() == 0 )
4133         {
4134             ResetAttr( RES_PARATR_LIST_ID );
4135         }
4136         else
4137         {
4138             SfxStringItem aNewListIdItem( RES_PARATR_LIST_ID, sListId );
4139             SetAttr( aNewListIdItem );
4140         }
4141     }
4142 }
4143 
4144 String SwTxtNode::GetListId() const
4145 {
4146     String sListId;
4147 
4148     const SfxStringItem& rListIdItem =
4149                 dynamic_cast<const SfxStringItem&>(GetAttr( RES_PARATR_LIST_ID ));
4150     sListId = rListIdItem.GetValue();
4151 
4152     // As long as no explicit list id attribute is set, use the list id of
4153     // the list, which has been created for the applied list style.
4154     if ( sListId.Len() == 0 )
4155     {
4156         SwNumRule* pRule = GetNumRule();
4157         if ( pRule )
4158         {
4159             sListId = pRule->GetDefaultListId();
4160 //#if OSL_DEBUG_LEVEL > 1
4161 //            ASSERT( false,
4162 //                    "DEBUG ASSERTION: default list id of list style is applied." );
4163 //#endif
4164 //            // setting list id directly using <SwCntntNode::SetAttr(..)>,
4165 //            // because no handling of this attribute set is needed and to avoid
4166 //            // recursive calls of <SwTxtNode::SetAttr(..)>
4167 //            SfxStringItem aNewListIdItem( RES_PARATR_LIST_ID, sListId );
4168 //            const_cast<SwTxtNode*>(this)->SwCntntNode::SetAttr( aNewListIdItem );
4169         }
4170     }
4171 
4172     return sListId;
4173 }
4174 // <--
4175 
4176 /** Determines, if the list level indent attributes can be applied to the
4177     paragraph.
4178 
4179     OD 2008-01-17 #newlistlevelattrs#
4180     The list level indents can be applied to the paragraph under the one
4181     of following conditions:
4182     - the list style is directly applied to the paragraph and the paragraph
4183       has no own indent attributes.
4184     - the list style is applied to the paragraph through one of its paragraph
4185       styles, the paragraph has no own indent attributes and on the paragraph
4186       style hierarchy from the paragraph to the paragraph style with the
4187       list style no indent attributes are found.
4188 
4189     @author OD
4190 
4191     @return boolean
4192 */
4193 bool SwTxtNode::AreListLevelIndentsApplicable() const
4194 {
4195     bool bAreListLevelIndentsApplicable( true );
4196 
4197     if ( !GetNum() || !GetNum()->GetNumRule() )
4198     {
4199         // no list style applied to paragraph
4200         bAreListLevelIndentsApplicable = false;
4201     }
4202     else if ( HasSwAttrSet() &&
4203               GetpSwAttrSet()->GetItemState( RES_LR_SPACE, sal_False ) == SFX_ITEM_SET )
4204     {
4205         // paragraph has hard-set indent attributes
4206         bAreListLevelIndentsApplicable = false;
4207     }
4208     else if ( HasSwAttrSet() &&
4209               GetpSwAttrSet()->GetItemState( RES_PARATR_NUMRULE, sal_False ) == SFX_ITEM_SET )
4210     {
4211         // list style is directly applied to paragraph and paragraph has no
4212         // hard-set indent attributes
4213         bAreListLevelIndentsApplicable = true;
4214     }
4215     else
4216     {
4217         // list style is applied through one of the paragraph styles and
4218         // paragraph has no hard-set indent attributes
4219 
4220         // check, paragraph's
4221         const SwTxtFmtColl* pColl = GetTxtColl();
4222         while ( pColl )
4223         {
4224             if ( pColl->GetAttrSet().GetItemState( RES_LR_SPACE, sal_False ) == SFX_ITEM_SET )
4225             {
4226                 // indent attributes found in the paragraph style hierarchy.
4227                 bAreListLevelIndentsApplicable = false;
4228                 break;
4229             }
4230 
4231             if ( pColl->GetAttrSet().GetItemState( RES_PARATR_NUMRULE, sal_False ) == SFX_ITEM_SET )
4232             {
4233                 // paragraph style with the list style found and until now no
4234                 // indent attributes are found in the paragraph style hierarchy.
4235                 bAreListLevelIndentsApplicable = true;
4236                 break;
4237             }
4238 
4239             pColl = dynamic_cast<const SwTxtFmtColl*>(pColl->DerivedFrom());
4240             ASSERT( pColl,
4241                     "<SwTxtNode::AreListLevelIndentsApplicable()> - something wrong in paragraph's style hierarchy. The applied list style is not found." );
4242         }
4243     }
4244 
4245     return bAreListLevelIndentsApplicable;
4246 }
4247 
4248 /** Retrieves the list tab stop position, if the paragraph's list level defines
4249     one and this list tab stop has to merged into the tap stops of the paragraph
4250 
4251     OD 2008-01-17 #newlistlevelattrs#
4252 
4253     @author OD
4254 
4255     @param nListTabStopPosition
4256     output parameter - containing the list tab stop position
4257 
4258     @return boolean - indicating, if a list tab stop position is provided
4259 */
4260 bool SwTxtNode::GetListTabStopPosition( long& nListTabStopPosition ) const
4261 {
4262     bool bListTanStopPositionProvided( false );
4263 
4264     const SwNumRule* pNumRule = GetNum() ? GetNum()->GetNumRule() : 0;
4265     if ( pNumRule && HasVisibleNumberingOrBullet() && GetActualListLevel() >= 0 )
4266     {
4267         const SwNumFmt& rFmt = pNumRule->Get( static_cast<sal_uInt16>(GetActualListLevel()) );
4268         if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT &&
4269              rFmt.GetLabelFollowedBy() == SvxNumberFormat::LISTTAB )
4270         {
4271             bListTanStopPositionProvided = true;
4272             nListTabStopPosition = rFmt.GetListtabPos();
4273 
4274             if ( getIDocumentSettingAccess()->get(IDocumentSettingAccess::TABS_RELATIVE_TO_INDENT) )
4275             {
4276                 // tab stop position are treated to be relative to the "before text"
4277                 // indent value of the paragraph. Thus, adjust <nListTabStopPos>.
4278                 if ( AreListLevelIndentsApplicable() )
4279                 {
4280                     nListTabStopPosition -= rFmt.GetIndentAt();
4281                 }
4282                 else if (!getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING))
4283                 {
4284                     SvxLRSpaceItem aItem = GetSwAttrSet().GetLRSpace();
4285                     nListTabStopPosition -= aItem.GetTxtLeft();
4286                 }
4287             }
4288         }
4289     }
4290 
4291     return bListTanStopPositionProvided;
4292 }
4293 
4294 /** Retrieves the character following the list label, if the paragraph's
4295     list level defines one.
4296 
4297     OD 2008-01-17 #newlistlevelattrs#
4298 
4299     @author OD
4300 
4301     @return XubString - the list tab stop position
4302 */
4303 XubString SwTxtNode::GetLabelFollowedBy() const
4304 {
4305     XubString aLabelFollowedBy;
4306 
4307     const SwNumRule* pNumRule = GetNum() ? GetNum()->GetNumRule() : 0;
4308     if ( pNumRule && HasVisibleNumberingOrBullet() && GetActualListLevel() >= 0 )
4309     {
4310         const SwNumFmt& rFmt = pNumRule->Get( static_cast<sal_uInt16>(GetActualListLevel()) );
4311         if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
4312         {
4313             switch ( rFmt.GetLabelFollowedBy() )
4314             {
4315                 case SvxNumberFormat::LISTTAB:
4316                 {
4317                     const sal_Unicode aTab = '\t';
4318                     aLabelFollowedBy.Insert( aTab, 0 );
4319                 }
4320                 break;
4321                 case SvxNumberFormat::SPACE:
4322                 {
4323                     const sal_Unicode aSpace = ' ';
4324                     aLabelFollowedBy.Insert( aSpace, 0 );
4325                 }
4326                 break;
4327                 case SvxNumberFormat::NOTHING:
4328                 {
4329                     // intentionally left blank.
4330                 }
4331                 break;
4332                 default:
4333                 {
4334                     ASSERT( false,
4335                             "<SwTxtNode::GetLabelFollowedBy()> - unknown SvxNumberFormat::GetLabelFollowedBy() return value" );
4336                 }
4337             }
4338         }
4339     }
4340 
4341     return aLabelFollowedBy;
4342 }
4343 
4344 void SwTxtNode::CalcHiddenCharFlags() const
4345 {
4346     xub_StrLen nStartPos;
4347     xub_StrLen nEndPos;
4348     // Update of the flags is done inside GetBoundsOfHiddenRange()
4349     SwScriptInfo::GetBoundsOfHiddenRange( *this, 0, nStartPos, nEndPos );
4350 }
4351 
4352 // --> FME 2004-06-08 #i12836# enhanced pdf export
4353 bool SwTxtNode::IsHidden() const
4354 {
4355     if ( HasHiddenParaField() || HasHiddenCharAttribute( true ) )
4356         return true;
4357 
4358     const SwSectionNode* pSectNd = FindSectionNode();
4359     if ( pSectNd && pSectNd->GetSection().IsHiddenFlag() )
4360         return true;
4361 
4362     return false;
4363 }
4364 // <--
4365 
4366 // --> OD 2008-03-13 #refactorlists#
4367 namespace {
4368     // Helper class for special handling of setting attributes at text node:
4369     // In constructor an instance of the helper class recognize whose attributes
4370     // are set and perform corresponding actions before the intrinsic set of
4371     // attributes has been taken place.
4372     // In the destructor - after the attributes have been set at the text
4373     // node - corresponding actions are performed.
4374     // The following is handled:
4375     // (1) When the list style attribute - RES_PARATR_NUMRULE - is set,
4376     //     (A) list style attribute is empty -> the text node is removed from
4377     //         its list.
4378     //     (B) list style attribute is not empty
4379     //         (a) text node has no list style -> add text node to its list after
4380     //             the attributes have been set.
4381     //         (b) text node has list style -> change of list style is notified
4382     //             after the attributes have been set.
4383     // (2) When the list id attribute - RES_PARATR_LIST_ID - is set and changed,
4384     //     the text node is removed from its current list before the attributes
4385     //     are set and added to its new list after the attributes have been set.
4386     // (3) Notify list tree, if list level - RES_PARATR_LIST_LEVEL - is set
4387     //     and changed after the attributes have been set
4388     // (4) Notify list tree, if list restart - RES_PARATR_LIST_ISRESTART - is set
4389     //     and changed after the attributes have been set
4390     // (5) Notify list tree, if list restart value - RES_PARATR_LIST_RESTARTVALUE -
4391     //     is set and changed after the attributes have been set
4392     // (6) Notify list tree, if count in list - RES_PARATR_LIST_ISCOUNTED - is set
4393     //     and changed after the attributes have been set
4394     // (7) Set or Reset emtpy list style due to changed outline level - RES_PARATR_OUTLINELEVEL.
4395     class HandleSetAttrAtTxtNode
4396     {
4397         public:
4398             HandleSetAttrAtTxtNode( SwTxtNode& rTxtNode,
4399                                     const SfxPoolItem& pItem );
4400             HandleSetAttrAtTxtNode( SwTxtNode& rTxtNode,
4401                                     const SfxItemSet& rItemSet );
4402             ~HandleSetAttrAtTxtNode();
4403 
4404         private:
4405             SwTxtNode& mrTxtNode;
4406             bool mbAddTxtNodeToList;
4407             bool mbUpdateListLevel;
4408             bool mbUpdateListRestart;
4409             bool mbUpdateListCount;
4410             // --> OD 2008-11-19 #i70748#
4411             bool mbOutlineLevelSet;
4412             // <--
4413     };
4414 
4415     HandleSetAttrAtTxtNode::HandleSetAttrAtTxtNode( SwTxtNode& rTxtNode,
4416                                                     const SfxPoolItem& pItem )
4417         : mrTxtNode( rTxtNode ),
4418           mbAddTxtNodeToList( false ),
4419           mbUpdateListLevel( false ),
4420           mbUpdateListRestart( false ),
4421           mbUpdateListCount( false ),
4422           // --> OD 2008-11-19 #i70748#
4423           mbOutlineLevelSet( false )
4424           // <--
4425     {
4426         switch ( pItem.Which() )
4427         {
4428             // handle RES_PARATR_NUMRULE
4429             case RES_PARATR_NUMRULE:
4430             {
4431                 mrTxtNode.RemoveFromList();
4432 
4433                 const SwNumRuleItem& pNumRuleItem =
4434                                 dynamic_cast<const SwNumRuleItem&>(pItem);
4435                 if ( pNumRuleItem.GetValue().Len() > 0 )
4436                 {
4437                     mbAddTxtNodeToList = true;
4438                     // --> OD 2010-05-12 #i105562#
4439                     //
4440                     mrTxtNode.ResetEmptyListStyleDueToResetOutlineLevelAttr();
4441                     // <--
4442                 }
4443             }
4444             break;
4445 
4446             // handle RES_PARATR_LIST_ID
4447             case RES_PARATR_LIST_ID:
4448             {
4449                 const SfxStringItem& pListIdItem =
4450                                         dynamic_cast<const SfxStringItem&>(pItem);
4451                 ASSERT( pListIdItem.GetValue().Len() > 0,
4452                         "<HandleSetAttrAtTxtNode(..)> - empty list id attribute not excepted. Serious defect -> please inform OD." );
4453                 const String sListIdOfTxtNode = rTxtNode.GetListId();
4454                 if ( pListIdItem.GetValue() != sListIdOfTxtNode )
4455                 {
4456                     mbAddTxtNodeToList = true;
4457                     if ( mrTxtNode.IsInList() )
4458                     {
4459                         mrTxtNode.RemoveFromList();
4460                     }
4461                 }
4462             }
4463             break;
4464 
4465             // handle RES_PARATR_LIST_LEVEL
4466             case RES_PARATR_LIST_LEVEL:
4467             {
4468                 const SfxInt16Item& aListLevelItem =
4469                                     dynamic_cast<const SfxInt16Item&>(pItem);
4470                 if ( aListLevelItem.GetValue() != mrTxtNode.GetAttrListLevel() )
4471                 {
4472                     mbUpdateListLevel = true;
4473                 }
4474             }
4475             break;
4476 
4477             // handle RES_PARATR_LIST_ISRESTART
4478             case RES_PARATR_LIST_ISRESTART:
4479             {
4480                 const SfxBoolItem& aListIsRestartItem =
4481                                     dynamic_cast<const SfxBoolItem&>(pItem);
4482                 if ( aListIsRestartItem.GetValue() !=
4483                                     (mrTxtNode.IsListRestart() ? sal_True : sal_False) )
4484                 {
4485                     mbUpdateListRestart = true;
4486                 }
4487             }
4488             break;
4489 
4490             // handle RES_PARATR_LIST_RESTARTVALUE
4491             case RES_PARATR_LIST_RESTARTVALUE:
4492             {
4493                 const SfxInt16Item& aListRestartValueItem =
4494                                     dynamic_cast<const SfxInt16Item&>(pItem);
4495                 if ( !mrTxtNode.HasAttrListRestartValue() ||
4496                      aListRestartValueItem.GetValue() != mrTxtNode.GetAttrListRestartValue() )
4497                 {
4498                     mbUpdateListRestart = true;
4499                 }
4500             }
4501             break;
4502 
4503             // handle RES_PARATR_LIST_ISCOUNTED
4504             case RES_PARATR_LIST_ISCOUNTED:
4505             {
4506                 const SfxBoolItem& aIsCountedInListItem =
4507                                     dynamic_cast<const SfxBoolItem&>(pItem);
4508                 if ( aIsCountedInListItem.GetValue() !=
4509                                     (mrTxtNode.IsCountedInList() ? sal_True : sal_False) )
4510                 {
4511                     mbUpdateListCount = true;
4512                 }
4513             }
4514             break;
4515 
4516             // --> OD 2008-11-19 #i70748#
4517             // handle RES_PARATR_OUTLINELEVEL
4518             case RES_PARATR_OUTLINELEVEL:
4519             {
4520                 const SfxUInt16Item& aOutlineLevelItem =
4521                                     dynamic_cast<const SfxUInt16Item&>(pItem);
4522                 if ( aOutlineLevelItem.GetValue() != mrTxtNode.GetAttrOutlineLevel() )
4523                 {
4524                     mbOutlineLevelSet = true;
4525                 }
4526             }
4527             break;
4528             // <--
4529         }
4530 
4531     }
4532 
4533     HandleSetAttrAtTxtNode::HandleSetAttrAtTxtNode( SwTxtNode& rTxtNode,
4534                                                     const SfxItemSet& rItemSet )
4535         : mrTxtNode( rTxtNode ),
4536           mbAddTxtNodeToList( false ),
4537           mbUpdateListLevel( false ),
4538           mbUpdateListRestart( false ),
4539           mbUpdateListCount( false ),
4540           // --> OD 2008-11-19 #i70748#
4541           mbOutlineLevelSet( false )
4542           // <--
4543     {
4544         const SfxPoolItem* pItem = 0;
4545         // handle RES_PARATR_NUMRULE
4546         if ( rItemSet.GetItemState( RES_PARATR_NUMRULE, sal_False, &pItem ) == SFX_ITEM_SET )
4547         {
4548             mrTxtNode.RemoveFromList();
4549 
4550             const SwNumRuleItem* pNumRuleItem =
4551                             dynamic_cast<const SwNumRuleItem*>(pItem);
4552             if ( pNumRuleItem->GetValue().Len() > 0 )
4553             {
4554                 mbAddTxtNodeToList = true;
4555                 // --> OD 2008-11-19 #i70748#
4556                 mrTxtNode.ResetEmptyListStyleDueToResetOutlineLevelAttr();
4557                 // <--
4558             }
4559         }
4560 
4561         // handle RES_PARATR_LIST_ID
4562         if ( rItemSet.GetItemState( RES_PARATR_LIST_ID, sal_False, &pItem ) == SFX_ITEM_SET )
4563         {
4564             const SfxStringItem* pListIdItem =
4565                                     dynamic_cast<const SfxStringItem*>(pItem);
4566             const String sListIdOfTxtNode = mrTxtNode.GetListId();
4567             if ( pListIdItem &&
4568                  pListIdItem->GetValue() != sListIdOfTxtNode )
4569             {
4570                 mbAddTxtNodeToList = true;
4571                 if ( mrTxtNode.IsInList() )
4572                 {
4573                     mrTxtNode.RemoveFromList();
4574                 }
4575             }
4576         }
4577 
4578         // handle RES_PARATR_LIST_LEVEL
4579         if ( rItemSet.GetItemState( RES_PARATR_LIST_LEVEL, sal_False, &pItem ) == SFX_ITEM_SET )
4580         {
4581             const SfxInt16Item* pListLevelItem =
4582                                 dynamic_cast<const SfxInt16Item*>(pItem);
4583             if ( pListLevelItem->GetValue() != mrTxtNode.GetAttrListLevel() )
4584             {
4585                 mbUpdateListLevel = true;
4586             }
4587         }
4588 
4589         // handle RES_PARATR_LIST_ISRESTART
4590         if ( rItemSet.GetItemState( RES_PARATR_LIST_ISRESTART, sal_False, &pItem ) == SFX_ITEM_SET )
4591         {
4592             const SfxBoolItem* pListIsRestartItem =
4593                                 dynamic_cast<const SfxBoolItem*>(pItem);
4594             if ( pListIsRestartItem->GetValue() !=
4595                                     (mrTxtNode.IsListRestart() ? sal_True : sal_False) )
4596             {
4597                 mbUpdateListRestart = true;
4598             }
4599         }
4600 
4601         // handle RES_PARATR_LIST_RESTARTVALUE
4602         if ( rItemSet.GetItemState( RES_PARATR_LIST_RESTARTVALUE, sal_False, &pItem ) == SFX_ITEM_SET )
4603         {
4604             const SfxInt16Item* pListRestartValueItem =
4605                                 dynamic_cast<const SfxInt16Item*>(pItem);
4606             if ( !mrTxtNode.HasAttrListRestartValue() ||
4607                  pListRestartValueItem->GetValue() != mrTxtNode.GetAttrListRestartValue() )
4608             {
4609                 mbUpdateListRestart = true;
4610             }
4611         }
4612 
4613         // handle RES_PARATR_LIST_ISCOUNTED
4614         if ( rItemSet.GetItemState( RES_PARATR_LIST_ISCOUNTED, sal_False, &pItem ) == SFX_ITEM_SET )
4615         {
4616             const SfxBoolItem* pIsCountedInListItem =
4617                                 dynamic_cast<const SfxBoolItem*>(pItem);
4618             if ( pIsCountedInListItem->GetValue() !=
4619                                 (mrTxtNode.IsCountedInList() ? sal_True : sal_False) )
4620             {
4621                 mbUpdateListCount = true;
4622             }
4623         }
4624 
4625         // --> OD 2008-11-19 #i70748#
4626         // handle RES_PARATR_OUTLINELEVEL
4627         if ( rItemSet.GetItemState( RES_PARATR_OUTLINELEVEL, sal_False, &pItem ) == SFX_ITEM_SET )
4628         {
4629             const SfxUInt16Item* pOutlineLevelItem =
4630                                 dynamic_cast<const SfxUInt16Item*>(pItem);
4631             if ( pOutlineLevelItem->GetValue() != mrTxtNode.GetAttrOutlineLevel() )
4632             {
4633                 mbOutlineLevelSet = true;
4634             }
4635         }
4636         // <--
4637     }
4638 
4639     HandleSetAttrAtTxtNode::~HandleSetAttrAtTxtNode()
4640     {
4641         if ( mbAddTxtNodeToList )
4642         {
4643             SwNumRule* pNumRuleAtTxtNode = mrTxtNode.GetNumRule();
4644             if ( pNumRuleAtTxtNode )
4645             {
4646                 mrTxtNode.AddToList();
4647             }
4648         }
4649         else
4650         {
4651             if ( mbUpdateListLevel && mrTxtNode.IsInList() )
4652             {
4653                 const_cast<SwNodeNum*>(mrTxtNode.GetNum())->SetLevelInListTree(
4654                                                     mrTxtNode.GetAttrListLevel() );
4655             }
4656 
4657             if ( mbUpdateListRestart && mrTxtNode.IsInList() )
4658             {
4659                 SwNodeNum* pNodeNum = const_cast<SwNodeNum*>(mrTxtNode.GetNum());
4660                 pNodeNum->InvalidateMe();
4661                 pNodeNum->NotifyInvalidSiblings();
4662             }
4663 
4664             if ( mbUpdateListCount && mrTxtNode.IsInList() )
4665             {
4666                 const_cast<SwNodeNum*>(mrTxtNode.GetNum())->InvalidateAndNotifyTree();
4667             }
4668         }
4669 
4670         // --> OD 2008-11-19 #i70748#
4671         if ( mbOutlineLevelSet )
4672         {
4673             if ( mrTxtNode.GetAttrOutlineLevel() == 0 )
4674             {
4675                 mrTxtNode.ResetEmptyListStyleDueToResetOutlineLevelAttr();
4676             }
4677             else
4678             {
4679                 const SfxPoolItem* pItem = 0;
4680                 if ( mrTxtNode.GetSwAttrSet().GetItemState( RES_PARATR_NUMRULE,
4681                                                             sal_True, &pItem )
4682                                                                 != SFX_ITEM_SET )
4683                 {
4684                     mrTxtNode.SetEmptyListStyleDueToSetOutlineLevelAttr();
4685                 }
4686             }
4687         }
4688         // <--
4689     }
4690     // End of class <HandleSetAttrAtTxtNode>
4691 }
4692 
4693 sal_Bool SwTxtNode::SetAttr( const SfxPoolItem& pItem )
4694 {
4695     const bool bOldIsSetOrResetAttr( mbInSetOrResetAttr );
4696     mbInSetOrResetAttr = true;
4697 
4698     HandleSetAttrAtTxtNode aHandleSetAttr( *this, pItem );
4699 
4700     sal_Bool bRet = SwCntntNode::SetAttr( pItem );
4701 
4702     mbInSetOrResetAttr = bOldIsSetOrResetAttr;
4703 
4704     return bRet;
4705 }
4706 
4707 sal_Bool SwTxtNode::SetAttr( const SfxItemSet& rSet )
4708 {
4709     const bool bOldIsSetOrResetAttr( mbInSetOrResetAttr );
4710     mbInSetOrResetAttr = true;
4711 
4712     HandleSetAttrAtTxtNode aHandleSetAttr( *this, rSet );
4713 
4714     sal_Bool bRet = SwCntntNode::SetAttr( rSet );
4715 
4716     mbInSetOrResetAttr = bOldIsSetOrResetAttr;
4717 
4718     return bRet;
4719 }
4720 
4721 namespace {
4722     // Helper class for special handling of resetting attributes at text node:
4723     // In constructor an instance of the helper class recognize whose attributes
4724     // are reset and perform corresponding actions before the intrinsic reset of
4725     // attributes has been taken place.
4726     // In the destructor - after the attributes have been reset at the text
4727     // node - corresponding actions are performed.
4728     // The following is handled:
4729     // (1) When the list style attribute - RES_PARATR_NUMRULE - is reset,
4730     //     the text is removed from its list before the attributes have been reset.
4731     // (2) When the list id attribute - RES_PARATR_LIST_ID - is reset,
4732     //     the text is removed from its list before the attributes have been reset.
4733     // (3) Notify list tree, if list level - RES_PARATR_LIST_LEVEL - is reset.
4734     // (4) Notify list tree, if list restart - RES_PARATR_LIST_ISRESTART - is reset.
4735     // (5) Notify list tree, if list restart value - RES_PARATR_LIST_RESTARTVALUE - is reset.
4736     // (6) Notify list tree, if count in list - RES_PARATR_LIST_ISCOUNTED - is reset.
4737     // (7) Reset empty list style, if outline level attribute - RES_PARATR_OUTLINELEVEL - is reset.
4738     class HandleResetAttrAtTxtNode
4739     {
4740         public:
4741             HandleResetAttrAtTxtNode( SwTxtNode& rTxtNode,
4742                                       const sal_uInt16 nWhich1,
4743                                       const sal_uInt16 nWhich2 );
4744             HandleResetAttrAtTxtNode( SwTxtNode& rTxtNode,
4745                                       const SvUShorts& rWhichArr );
4746             HandleResetAttrAtTxtNode( SwTxtNode& rTxtNode );
4747 
4748             ~HandleResetAttrAtTxtNode();
4749 
4750         private:
4751             SwTxtNode& mrTxtNode;
4752             bool mbListStyleOrIdReset;
4753             bool mbUpdateListLevel;
4754             bool mbUpdateListRestart;
4755             bool mbUpdateListCount;
4756     };
4757 
4758     HandleResetAttrAtTxtNode::HandleResetAttrAtTxtNode( SwTxtNode& rTxtNode,
4759                                                         const sal_uInt16 nWhich1,
4760                                                         const sal_uInt16 nWhich2 )
4761         : mrTxtNode( rTxtNode ),
4762           mbListStyleOrIdReset( false ),
4763           mbUpdateListLevel( false ),
4764           mbUpdateListRestart( false ),
4765           mbUpdateListCount( false )
4766     {
4767         bool bRemoveFromList( false );
4768         if ( nWhich2 != 0 && nWhich2 > nWhich1 )
4769         {
4770             // RES_PARATR_NUMRULE and RES_PARATR_LIST_ID
4771             if ( nWhich1 <= RES_PARATR_NUMRULE && RES_PARATR_NUMRULE <= nWhich2 )
4772             {
4773                 bRemoveFromList = mrTxtNode.GetNumRule() != 0;
4774                 mbListStyleOrIdReset = true;
4775             }
4776             else if ( nWhich1 <= RES_PARATR_LIST_ID && RES_PARATR_LIST_ID <= nWhich2 )
4777             {
4778                 bRemoveFromList = mrTxtNode.GetpSwAttrSet() &&
4779                     mrTxtNode.GetpSwAttrSet()->GetItemState( RES_PARATR_LIST_ID, sal_False ) == SFX_ITEM_SET;
4780                 // --> OD 2008-10-20 #i92898#
4781                 mbListStyleOrIdReset = true;
4782                 // <--
4783             }
4784 
4785             if ( !bRemoveFromList )
4786             {
4787                 // RES_PARATR_LIST_LEVEL
4788                 mbUpdateListLevel = ( nWhich1 <= RES_PARATR_LIST_LEVEL &&
4789                                       RES_PARATR_LIST_LEVEL <= nWhich2 &&
4790                                       mrTxtNode.HasAttrListLevel() );
4791 
4792                 // RES_PARATR_LIST_ISRESTART and RES_PARATR_LIST_RESTARTVALUE
4793                 mbUpdateListRestart =
4794                     ( nWhich1 <= RES_PARATR_LIST_ISRESTART && RES_PARATR_LIST_ISRESTART <= nWhich2 &&
4795                       mrTxtNode.IsListRestart() ) ||
4796                     ( nWhich1 <= RES_PARATR_LIST_RESTARTVALUE && RES_PARATR_LIST_RESTARTVALUE <= nWhich2 &&
4797                       mrTxtNode.HasAttrListRestartValue() );
4798 
4799                 // RES_PARATR_LIST_ISCOUNTED
4800                 mbUpdateListCount =
4801                     ( nWhich1 <= RES_PARATR_LIST_ISCOUNTED && RES_PARATR_LIST_ISCOUNTED <= nWhich2 &&
4802                       !mrTxtNode.IsCountedInList() );
4803             }
4804 
4805             // --> OD 2008-11-19 #i70748#
4806             // RES_PARATR_OUTLINELEVEL
4807             if ( nWhich1 <= RES_PARATR_OUTLINELEVEL && RES_PARATR_OUTLINELEVEL <= nWhich2 )
4808             {
4809                 mrTxtNode.ResetEmptyListStyleDueToResetOutlineLevelAttr();
4810             }
4811             // <--
4812         }
4813         else
4814         {
4815             // RES_PARATR_NUMRULE and RES_PARATR_LIST_ID
4816             if ( nWhich1 == RES_PARATR_NUMRULE )
4817             {
4818                 bRemoveFromList = mrTxtNode.GetNumRule() != 0;
4819                 mbListStyleOrIdReset = true;
4820             }
4821             else if ( nWhich1 == RES_PARATR_LIST_ID )
4822             {
4823                 bRemoveFromList = mrTxtNode.GetpSwAttrSet() &&
4824                     mrTxtNode.GetpSwAttrSet()->GetItemState( RES_PARATR_LIST_ID, sal_False ) == SFX_ITEM_SET;
4825                 // --> OD 2008-10-20 #i92898#
4826                 mbListStyleOrIdReset = true;
4827                 // <--
4828             }
4829             // --> OD 2008-11-19 #i70748#
4830             // RES_PARATR_OUTLINELEVEL
4831             else if ( nWhich1 == RES_PARATR_OUTLINELEVEL )
4832             {
4833                 mrTxtNode.ResetEmptyListStyleDueToResetOutlineLevelAttr();
4834             }
4835             // <--
4836 
4837             if ( !bRemoveFromList )
4838             {
4839                 // RES_PARATR_LIST_LEVEL
4840                 mbUpdateListLevel = nWhich1 == RES_PARATR_LIST_LEVEL &&
4841                                     mrTxtNode.HasAttrListLevel();
4842 
4843                 // RES_PARATR_LIST_ISRESTART and RES_PARATR_LIST_RESTARTVALUE
4844                 mbUpdateListRestart = ( nWhich1 == RES_PARATR_LIST_ISRESTART &&
4845                                         mrTxtNode.IsListRestart() ) ||
4846                                       ( nWhich1 == RES_PARATR_LIST_RESTARTVALUE &&
4847                                         mrTxtNode.HasAttrListRestartValue() );
4848 
4849                 // RES_PARATR_LIST_ISCOUNTED
4850                 mbUpdateListCount = nWhich1 == RES_PARATR_LIST_ISCOUNTED &&
4851                                     !mrTxtNode.IsCountedInList();
4852             }
4853         }
4854 
4855         if ( bRemoveFromList && mrTxtNode.IsInList() )
4856         {
4857             mrTxtNode.RemoveFromList();
4858         }
4859     }
4860 
4861     HandleResetAttrAtTxtNode::HandleResetAttrAtTxtNode( SwTxtNode& rTxtNode,
4862                                                         const SvUShorts& rWhichArr )
4863         : mrTxtNode( rTxtNode ),
4864           mbListStyleOrIdReset( false ),
4865           mbUpdateListLevel( false ),
4866           mbUpdateListRestart( false ),
4867           mbUpdateListCount( false )
4868     {
4869         bool bRemoveFromList( false );
4870         {
4871             const sal_uInt16 nEnd = rWhichArr.Count();
4872             for ( sal_uInt16 n = 0; n < nEnd; ++n )
4873             {
4874                 // RES_PARATR_NUMRULE and RES_PARATR_LIST_ID
4875                 if ( rWhichArr[ n ] == RES_PARATR_NUMRULE )
4876                 {
4877                     bRemoveFromList = bRemoveFromList ||
4878                                       mrTxtNode.GetNumRule() != 0;
4879                     mbListStyleOrIdReset = true;
4880                 }
4881                 else if ( rWhichArr[ n ] == RES_PARATR_LIST_ID )
4882                 {
4883                     bRemoveFromList = bRemoveFromList ||
4884                         ( mrTxtNode.GetpSwAttrSet() &&
4885                           mrTxtNode.GetpSwAttrSet()->GetItemState( RES_PARATR_LIST_ID, sal_False ) == SFX_ITEM_SET );
4886                     // --> OD 2008-10-20 #i92898#
4887                     mbListStyleOrIdReset = true;
4888                     // <--
4889                 }
4890                 // --> OD 2008-11-19 #i70748#
4891                 // RES_PARATR_OUTLINELEVEL
4892                 else if ( rWhichArr[ n ] == RES_PARATR_OUTLINELEVEL )
4893                 {
4894                     mrTxtNode.ResetEmptyListStyleDueToResetOutlineLevelAttr();
4895                 }
4896                 // <--
4897 
4898                 if ( !bRemoveFromList )
4899                 {
4900                     // RES_PARATR_LIST_LEVEL
4901                     mbUpdateListLevel = mbUpdateListLevel ||
4902                                         ( rWhichArr[ n ] == RES_PARATR_LIST_LEVEL &&
4903                                           mrTxtNode.HasAttrListLevel() );
4904 
4905                     // RES_PARATR_LIST_ISRESTART and RES_PARATR_LIST_RESTARTVALUE
4906                     mbUpdateListRestart = mbUpdateListRestart ||
4907                                           ( rWhichArr[ n ] == RES_PARATR_LIST_ISRESTART &&
4908                                             mrTxtNode.IsListRestart() ) ||
4909                                           ( rWhichArr[ n ] == RES_PARATR_LIST_RESTARTVALUE &&
4910                                             mrTxtNode.HasAttrListRestartValue() );
4911 
4912                     // RES_PARATR_LIST_ISCOUNTED
4913                     mbUpdateListCount = mbUpdateListCount ||
4914                                         ( rWhichArr[ n ] == RES_PARATR_LIST_ISCOUNTED &&
4915                                           !mrTxtNode.IsCountedInList() );
4916                 }
4917             }
4918         }
4919 
4920         if ( bRemoveFromList && mrTxtNode.IsInList() )
4921         {
4922             mrTxtNode.RemoveFromList();
4923         }
4924     }
4925 
4926     HandleResetAttrAtTxtNode::HandleResetAttrAtTxtNode( SwTxtNode& rTxtNode )
4927         : mrTxtNode( rTxtNode ),
4928           mbListStyleOrIdReset( false ),
4929           mbUpdateListLevel( false ),
4930           mbUpdateListRestart( false ),
4931           mbUpdateListCount( false )
4932     {
4933         mbListStyleOrIdReset = true;
4934         if ( rTxtNode.IsInList() )
4935         {
4936             rTxtNode.RemoveFromList();
4937         }
4938         // --> OD 2008-11-19 #i70748#
4939         mrTxtNode.ResetEmptyListStyleDueToResetOutlineLevelAttr();
4940         // <--
4941     }
4942 
4943     HandleResetAttrAtTxtNode::~HandleResetAttrAtTxtNode()
4944     {
4945         if ( mbListStyleOrIdReset && !mrTxtNode.IsInList() )
4946         {
4947             // check, if in spite of the reset of the list style or the list id
4948             // the paragraph still has to be added to a list.
4949             if ( mrTxtNode.GetNumRule() &&
4950                  mrTxtNode.GetListId().Len() > 0 )
4951             {
4952                 // --> OD 2009-01-14 #i96062#
4953                 // If paragraph has no list level attribute set and list style
4954                 // is the outline style, apply outline level as the list level.
4955                 if ( !mrTxtNode.HasAttrListLevel() &&
4956                      mrTxtNode.GetNumRule()->GetName() ==
4957                         String::CreateFromAscii( SwNumRule::GetOutlineRuleName() ) &&
4958                      mrTxtNode.GetTxtColl()->IsAssignedToListLevelOfOutlineStyle() )
4959                 {
4960                     int nNewListLevel = mrTxtNode.GetTxtColl()->GetAssignedOutlineStyleLevel();
4961                     if ( 0 <= nNewListLevel && nNewListLevel < MAXLEVEL )
4962                     {
4963                         mrTxtNode.SetAttrListLevel( nNewListLevel );
4964                     }
4965                 }
4966                 // <--
4967                 mrTxtNode.AddToList();
4968             }
4969             // --> OD 2008-11-19 #i70748#
4970             // --> OD 2010-05-12 #i105562#
4971             else if ( mrTxtNode.GetpSwAttrSet() &&
4972                       dynamic_cast<const SfxUInt16Item &>(mrTxtNode.GetAttr( RES_PARATR_OUTLINELEVEL, sal_False )).GetValue() > 0 )
4973             {
4974                 mrTxtNode.SetEmptyListStyleDueToSetOutlineLevelAttr();
4975             }
4976             // <--
4977         }
4978 
4979         if ( mrTxtNode.IsInList() )
4980         {
4981             if ( mbUpdateListLevel )
4982             {
4983                 SwNodeNum* pNodeNum = const_cast<SwNodeNum*>(mrTxtNode.GetNum());
4984                 pNodeNum->SetLevelInListTree( mrTxtNode.GetAttrListLevel() );
4985             }
4986 
4987             if ( mbUpdateListRestart )
4988             {
4989                 SwNodeNum* pNodeNum = const_cast<SwNodeNum*>(mrTxtNode.GetNum());
4990                 pNodeNum->InvalidateMe();
4991                 pNodeNum->NotifyInvalidSiblings();
4992             }
4993 
4994             if ( mbUpdateListCount )
4995             {
4996                 SwNodeNum* pNodeNum = const_cast<SwNodeNum*>(mrTxtNode.GetNum());
4997                 pNodeNum->InvalidateAndNotifyTree();
4998             }
4999         }
5000     }
5001     // End of class <HandleResetAttrAtTxtNode>
5002 }
5003 
5004 sal_Bool SwTxtNode::ResetAttr( sal_uInt16 nWhich1, sal_uInt16 nWhich2 )
5005 {
5006     const bool bOldIsSetOrResetAttr( mbInSetOrResetAttr );
5007     mbInSetOrResetAttr = true;
5008 
5009     HandleResetAttrAtTxtNode aHandleResetAttr( *this, nWhich1, nWhich2 );
5010 
5011     sal_Bool bRet = SwCntntNode::ResetAttr( nWhich1, nWhich2 );
5012 
5013     mbInSetOrResetAttr = bOldIsSetOrResetAttr;
5014 
5015     return bRet;
5016 }
5017 
5018 sal_Bool SwTxtNode::ResetAttr( const SvUShorts& rWhichArr )
5019 {
5020     const bool bOldIsSetOrResetAttr( mbInSetOrResetAttr );
5021     mbInSetOrResetAttr = true;
5022 
5023     HandleResetAttrAtTxtNode aHandleResetAttr( *this, rWhichArr );
5024 
5025     sal_Bool bRet = SwCntntNode::ResetAttr( rWhichArr );
5026 
5027     mbInSetOrResetAttr = bOldIsSetOrResetAttr;
5028 
5029     return bRet;
5030 }
5031 
5032 sal_uInt16 SwTxtNode::ResetAllAttr()
5033 {
5034     const bool bOldIsSetOrResetAttr( mbInSetOrResetAttr );
5035     mbInSetOrResetAttr = true;
5036 
5037     HandleResetAttrAtTxtNode aHandleResetAttr( *this );
5038 
5039     sal_uInt16 nRet = SwCntntNode::ResetAllAttr();
5040 
5041     mbInSetOrResetAttr = bOldIsSetOrResetAttr;
5042 
5043     return nRet;
5044 }
5045 // <--
5046 
5047 // sw::Metadatable
5048 ::sfx2::IXmlIdRegistry& SwTxtNode::GetRegistry()
5049 {
5050     return GetDoc()->GetXmlIdRegistry();
5051 }
5052 
5053 bool SwTxtNode::IsInClipboard() const
5054 {
5055     return GetDoc()->IsClipBoard();
5056 }
5057 
5058 bool SwTxtNode::IsInUndo() const
5059 {
5060     return GetDoc()->GetIDocumentUndoRedo().IsUndoNodes(GetNodes());
5061 }
5062 
5063 bool SwTxtNode::IsInContent() const
5064 {
5065     return !GetDoc()->IsInHeaderFooter( SwNodeIndex(*this) );
5066 }
5067 
5068 void SwTxtNode::SwClientNotify( const SwModify& rModify, const SfxHint& rHint )
5069 {
5070     const SwAttrHint* pHint = dynamic_cast<const SwAttrHint*>(&rHint);
5071     if ( pHint && pHint->GetId() == RES_CONDTXTFMTCOLL && &rModify == GetRegisteredIn() )
5072         ChkCondColl();
5073 }
5074 
5075 #include <unoparagraph.hxx>
5076 
5077 uno::Reference< rdf::XMetadatable >
5078 SwTxtNode::MakeUnoObject()
5079 {
5080     const uno::Reference<rdf::XMetadatable> xMeta(
5081             SwXParagraph::CreateXParagraph(*GetDoc(), *this), uno::UNO_QUERY);
5082     return xMeta;
5083 }
5084 
5085