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