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