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