xref: /trunk/main/sw/source/core/edit/autofmt.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sw.hxx"
30 
31 
32 #define _SVSTDARR_LONGS
33 #define _SVSTDARR_USHORTS
34 
35 #include <ctype.h>
36 #include <hintids.hxx>
37 
38 #include <svl/svstdarr.hxx>
39 
40 #include <unotools/charclass.hxx>
41 
42 #include <vcl/msgbox.hxx>
43 
44 #include <editeng/boxitem.hxx>
45 #include <editeng/lrspitem.hxx>
46 #include <editeng/brkitem.hxx>
47 #include <editeng/adjitem.hxx>
48 #include <editeng/tstpitem.hxx>
49 #include <editeng/fontitem.hxx>
50 #include <editeng/langitem.hxx>
51 #include <editeng/cscoitem.hxx>
52 #include <editeng/unolingu.hxx>
53 #include <editeng/acorrcfg.hxx>
54 
55 #include <swwait.hxx>
56 #include <fmtpdsc.hxx>
57 #include <fmtanchr.hxx>
58 #include <doc.hxx>
59 #include <IDocumentUndoRedo.hxx>
60 #include <docary.hxx>
61 #include <editsh.hxx>
62 #include <index.hxx>
63 #include <pam.hxx>
64 #include <edimp.hxx>
65 #include <fesh.hxx>
66 #include <swundo.hxx>       // fuer die UndoIds
67 #include <poolfmt.hxx>
68 #include <ndtxt.hxx>
69 #include <txtfrm.hxx>
70 #include <frminf.hxx>
71 #include <pagedesc.hxx>
72 #include <paratr.hxx>
73 #include <swtable.hxx>
74 #include <acorrect.hxx>
75 #include <shellres.hxx>
76 #include <section.hxx>
77 #include <frmatr.hxx>
78 #include <charatr.hxx>
79 #include <mdiexp.hxx>
80 #include <statstr.hrc>
81 #include <comcore.hrc>
82 #include <numrule.hxx>
83 
84 using namespace ::com::sun::star;
85 
86 //-------------------------------------------------------------------
87 
88 //JP 16.12.99: definition:
89 //      from pos cPosEnDash to cPosEmDash all chars changed to endashes,
90 //      from pos cPosEmDash to cPosEnd    all chars changed to emdashes
91 //      all other chars are changed to the user configuration
92 
93 const sal_Unicode pBulletChar[6] = { '+', '*', '-', 0x2013, 0x2014, 0 };
94 const int cnPosEnDash = 2, cnPosEmDash = 4, cnPosEnd = 5;
95 
96 const sal_Unicode cStarSymbolEnDash = 0x2013;
97 const sal_Unicode cStarSymbolEmDash = 0x2014;
98 
99 
100 SvxSwAutoFmtFlags* SwEditShell::pAutoFmtFlags = 0;
101 
102 // Anzahl von Num-/Bullet-Absatzvorlagen. MAXLEVEL wird demnaechst auf
103 // x erhoeht, die Anzahl Vorlagen aber nicht (Ueberbleibsel aus <= 4.0)
104 const sal_uInt16 cnNumBullColls = 4;
105 
106 class SwAutoFormat
107 {
108     SvxSwAutoFmtFlags aFlags;
109     SwPaM aDelPam;              // ein Pam der benutzt werden kann
110     SwNodeIndex aNdIdx;         // der Index auf den akt. TextNode
111     SwNodeIndex aEndNdIdx;      // Index auf das Ende vom Bereich
112 
113     SwEditShell* pEditShell;
114     SwDoc* pDoc;
115     SwTxtNode* pAktTxtNd;       // der akt. TextNode
116     SwTxtFrm* pAktTxtFrm;       // Frame vom akt. TextNode
117     CharClass* pCharClass;      // Character classification
118     sal_uLong nEndNdIdx;            // fuer die Prozent-Anzeige
119     LanguageType eCharClassLang;
120 
121     sal_uInt16 nLastHeadLvl, nLastCalcHeadLvl;
122     sal_uInt16 nLastEnumLvl, nLastCalcEnumLvl;
123     sal_uInt16 nRedlAutoFmtSeqId;
124 
125     enum
126     {
127         NONE = 0,
128         DELIM = 1,
129         DIGIT = 2,
130         CHG = 4,
131         LOWER_ALPHA = 8,
132         UPPER_ALPHA = 16,
133         LOWER_ROMAN = 32,
134         UPPER_ROMAN = 64,
135         NO_DELIM = (DIGIT|LOWER_ALPHA|UPPER_ALPHA|LOWER_ROMAN|UPPER_ROMAN)
136     };
137 
138     enum Format_Status
139     {
140         READ_NEXT_PARA,
141         TST_EMPTY_LINE,
142         TST_ALPHA_LINE,
143         GET_ALL_INFO,
144         IS_ONE_LINE,
145         TST_ENUMERIC,
146         TST_IDENT,
147         TST_NEG_IDENT,
148         TST_TXT_BODY,
149         HAS_FMTCOLL,
150         IS_ENDE
151     } eStat;
152 
153     sal_Bool bEnde : 1;
154     sal_Bool bEmptyLine : 1;
155     sal_Bool bMoreLines : 1;
156 
157     static sal_Bool  m_bAskForCancelUndoWhileBufferOverflow;
158     static short m_nActionWhileAutoformatUndoBufferOverflow;
159 
160 
161     // ------------- private methods -----------------------------
162     void _GetCharClass( LanguageType eLang );
163     CharClass& GetCharClass( LanguageType eLang ) const
164     {
165         if( !pCharClass || eLang != eCharClassLang )
166         {
167             SwAutoFormat* pThis = (SwAutoFormat*)this;
168             pThis->_GetCharClass( eLang );
169         }
170         return *pCharClass;
171     }
172 
173 
174     sal_Bool IsSpace( const sal_Unicode c ) const
175         { return (' ' == c || '\t' == c || 0x0a == c|| 0x3000 == c /* Jap. space */) ? sal_True : sal_False; }
176 
177     void SetColl( sal_uInt16 nId, sal_Bool bHdLineOrText = sal_False );
178     String GoNextPara();
179     sal_Bool HasObjects( const SwNode& rNd );
180 
181     // TxtNode Methoden
182     const SwTxtNode* GetNextNode() const;
183     sal_Bool IsEmptyLine( const SwTxtNode& rNd ) const
184         {   return 0 == rNd.GetTxt().Len() ||
185                 rNd.GetTxt().Len() == GetLeadingBlanks( rNd.GetTxt() ); }
186 
187     sal_Bool IsOneLine( const SwTxtNode& ) const;
188     sal_Bool IsFastFullLine( const SwTxtNode& ) const;
189     sal_Bool IsNoAlphaLine( const SwTxtNode&) const;
190     sal_Bool IsEnumericChar( const SwTxtNode&) const;
191     sal_Bool IsBlanksInString( const SwTxtNode&) const;
192     sal_uInt16 CalcLevel( const SwTxtNode&, sal_uInt16 *pDigitLvl = 0 ) const;
193     xub_StrLen GetBigIndent( xub_StrLen& rAktSpacePos ) const;
194 
195     String& DelLeadingBlanks( String& rStr ) const;
196     String& DelTrailingBlanks( String& rStr ) const;
197     xub_StrLen GetLeadingBlanks( const String& rStr ) const;
198     xub_StrLen GetTrailingBlanks( const String& rStr ) const;
199 
200     sal_Bool IsFirstCharCapital( const SwTxtNode& rNd ) const;
201     sal_uInt16 GetDigitLevel( const SwTxtNode& rTxtNd, xub_StrLen& rPos,
202                             String* pPreFix = 0, String* pPostFix = 0,
203                             String* pNumTypes = 0 ) const;
204         // hole den FORMATIERTEN TextFrame
205     SwTxtFrm* GetFrm( const SwTxtNode& rTxtNd ) const;
206 
207     void BuildIndent();
208     void BuildText();
209     void BuildTextIndent();
210     void BuildEnum( sal_uInt16 nLvl, sal_uInt16 nDigitLevel );
211     void BuildNegIndent( SwTwips nSpaces );
212     void BuildHeadLine( sal_uInt16 nLvl );
213 
214     sal_Bool HasSelBlanks( SwPaM& rPam ) const;
215     sal_Bool HasBreakAttr( const SwTxtNode& ) const;
216     void DeleteSel( SwPaM& rPam );
217     sal_Bool DeleteAktNxtPara( const String& rNxtPara );
218     // loesche im Node Anfang oder/und Ende
219     void DeleteAktPara( sal_Bool bStart = sal_True, sal_Bool nEnd = sal_True );
220     void DelEmptyLine( sal_Bool bTstNextPara = sal_True );
221         // loesche bei mehrzeiligen Absaetzen die "linken" und/oder
222         // "rechten" Raender
223     void DelMoreLinesBlanks( sal_Bool bWithLineBreaks = sal_False );
224         // loesche den vorherigen Absatz
225     void DelPrevPara();
226         // dann lasse doch mal das AutoCorrect auf den akt. TextNode los
227     void AutoCorrect( xub_StrLen nSttPos = 0 );
228 
229     sal_Bool CanJoin( const SwTxtNode* pTxtNd ) const
230     {
231         return !bEnde && pTxtNd &&
232              !IsEmptyLine( *pTxtNd ) &&
233              !IsNoAlphaLine( *pTxtNd) &&
234              !IsEnumericChar( *pTxtNd ) &&
235              ((STRING_MAXLEN - 50 - pTxtNd->GetTxt().Len()) >
236                     pAktTxtNd->GetTxt().Len()) &&
237              !HasBreakAttr( *pTxtNd );
238     }
239 
240     // ist ein Punkt am Ende ??
241     sal_Bool IsSentenceAtEnd( const SwTxtNode& rTxtNd ) const;
242 
243     sal_Bool DoUnderline();
244     sal_Bool DoTable();
245 
246     void _SetRedlineTxt( sal_uInt16 nId );
247     sal_Bool SetRedlineTxt( sal_uInt16 nId )
248         { if( aFlags.bWithRedlining )   _SetRedlineTxt( nId );  return sal_True; }
249     sal_Bool ClearRedlineTxt()
250         { if( aFlags.bWithRedlining )   pDoc->SetAutoFmtRedlineComment(0);  return sal_True; }
251 
252 public:
253     SwAutoFormat( SwEditShell* pEdShell, SvxSwAutoFmtFlags& rFlags,
254                 SwNodeIndex* pSttNd = 0, SwNodeIndex* pEndNd = 0 );
255     ~SwAutoFormat() {
256         delete pCharClass;
257     }
258 };
259 
260 sal_Bool  SwAutoFormat::m_bAskForCancelUndoWhileBufferOverflow     = sal_True;
261 short SwAutoFormat::m_nActionWhileAutoformatUndoBufferOverflow = RET_YES;
262 
263 const sal_Unicode* StrChr( const sal_Unicode* pSrc, sal_Unicode c )
264 {
265     while( *pSrc && *pSrc != c )
266         ++pSrc;
267     return *pSrc ? pSrc : 0;
268 }
269 
270 SwTxtFrm* SwAutoFormat::GetFrm( const SwTxtNode& rTxtNd ) const
271 {
272     // besorge mal den Frame
273     const SwCntntFrm *pFrm = rTxtNd.getLayoutFrm( pEditShell->GetLayout() );
274     ASSERT( pFrm, "zum Autoformat muss das Layout vorhanden sein" );
275     if( aFlags.bAFmtByInput && !pFrm->IsValid() )
276     {
277         SwRect aTmpFrm( pFrm->Frm() );
278         SwRect aTmpPrt( pFrm->Prt() );
279         pFrm->Calc();
280         if( pFrm->Frm() != aTmpFrm || pFrm->Prt() != aTmpPrt ||
281             ( pFrm->IsTxtFrm() && !((SwTxtFrm*)pFrm)->Paint().IsEmpty() ) )
282             pFrm->SetCompletePaint();
283     }
284     return ((SwTxtFrm*)pFrm)->GetFormatted();
285 }
286 
287 void SwAutoFormat::_GetCharClass( LanguageType eLang )
288 {
289     delete pCharClass;
290     pCharClass = new CharClass( SvxCreateLocale( eLang ));
291     eCharClassLang = eLang;
292 }
293 
294 void SwAutoFormat::_SetRedlineTxt( sal_uInt16 nActionId )
295 {
296     String sTxt;
297     sal_uInt16 nSeqNo = 0;
298     if( STR_AUTOFMTREDL_END > nActionId )
299     {
300         sTxt = *ViewShell::GetShellRes()->GetAutoFmtNameLst()[ nActionId ];
301         switch( nActionId )
302         {
303         case STR_AUTOFMTREDL_SET_NUMBULET:
304         case STR_AUTOFMTREDL_DEL_MORELINES:
305 
306         // AutoCorrect-Actions
307         case STR_AUTOFMTREDL_USE_REPLACE:
308         case STR_AUTOFMTREDL_CPTL_STT_WORD:
309         case STR_AUTOFMTREDL_CPTL_STT_SENT:
310         case STR_AUTOFMTREDL_TYPO:
311         case STR_AUTOFMTREDL_UNDER:
312         case STR_AUTOFMTREDL_BOLD:
313         case STR_AUTOFMTREDL_FRACTION:
314         case STR_AUTOFMTREDL_DASH:
315         case STR_AUTOFMTREDL_ORDINAL:
316         case STR_AUTOFMTREDL_NON_BREAK_SPACE:
317             nSeqNo = ++nRedlAutoFmtSeqId;
318             break;
319         }
320     }
321 #if OSL_DEBUG_LEVEL > 1
322     else
323         sTxt = String::CreateFromAscii(
324                             RTL_CONSTASCII_STRINGPARAM( "Action-Text fehlt" ));
325 #endif
326 
327     pDoc->SetAutoFmtRedlineComment( &sTxt, nSeqNo );
328 }
329 
330 String SwAutoFormat::GoNextPara()
331 {
332     SwNode* pNewNd = 0;
333     do {
334         //has to be checed twice before and after incrementation
335         if( aNdIdx.GetIndex() >= aEndNdIdx.GetIndex() )
336         {
337             bEnde = sal_True;
338             return aEmptyStr;
339         }
340 
341         aNdIdx++;
342         if( aNdIdx.GetIndex() >= aEndNdIdx.GetIndex() )
343         {
344             bEnde = sal_True;
345             return aEmptyStr;
346         }
347         else
348             pNewNd = &aNdIdx.GetNode();
349 
350         // kein TextNode ->
351         //      TableNode   : Tabelle ueberspringen
352         //      NoTxtNode   : Nodes ueberspringen
353         //      EndNode     : Ende erreicht, beenden
354         if( pNewNd->IsEndNode() )
355         {
356             bEnde = sal_True;
357             return aEmptyStr;
358         }
359         else if( pNewNd->IsTableNode() )
360             aNdIdx = *pNewNd->EndOfSectionNode();
361         else if( pNewNd->IsSectionNode() )
362         {
363             const SwSection& rSect = pNewNd->GetSectionNode()->GetSection();
364             if( rSect.IsHiddenFlag() || rSect.IsProtectFlag() )
365                 aNdIdx = *pNewNd->EndOfSectionNode();
366         }
367     } while( !pNewNd->IsTxtNode() );
368 
369     if( !aFlags.bAFmtByInput )
370         ::SetProgressState( aNdIdx.GetIndex() + nEndNdIdx - aEndNdIdx.GetIndex(),
371                             pDoc->GetDocShell() );
372 
373     pAktTxtNd = (SwTxtNode*)pNewNd;
374     pAktTxtFrm = GetFrm( *pAktTxtNd );
375     return pAktTxtNd->GetTxt();
376 }
377 
378 sal_Bool SwAutoFormat::HasObjects( const SwNode& rNd )
379 {
380     // haengt irgend etwas absatzgebundenes am Absatz?
381     // z.B. Rahmen, DrawObjecte, ..
382     sal_Bool bRet = sal_False;
383     const SwSpzFrmFmts& rFmts = *pDoc->GetSpzFrmFmts();
384     for( sal_uInt16 n = 0; n < rFmts.Count(); ++n )
385     {
386         const SwFmtAnchor& rAnchor = rFmts[ n ]->GetAnchor();
387         if ((FLY_AT_PAGE != rAnchor.GetAnchorId()) &&
388             rAnchor.GetCntntAnchor() &&
389             &rAnchor.GetCntntAnchor()->nNode.GetNode() == &rNd )
390         {
391             bRet = sal_True;
392             break;
393         }
394     }
395     return bRet;
396 }
397 
398 const SwTxtNode* SwAutoFormat::GetNextNode() const
399 {
400     if( aNdIdx.GetIndex()+1 >= aEndNdIdx.GetIndex() )
401         return 0;
402     return pDoc->GetNodes()[ aNdIdx.GetIndex() + 1 ]->GetTxtNode();
403 }
404 
405 
406 sal_Bool SwAutoFormat::IsOneLine( const SwTxtNode& rNd ) const
407 {
408     SwTxtFrmInfo aFInfo( GetFrm( rNd ) );
409     return aFInfo.IsOneLine();
410 }
411 
412 
413 sal_Bool SwAutoFormat::IsFastFullLine( const SwTxtNode& rNd ) const
414 {
415     sal_Bool bRet = aFlags.bRightMargin;
416     if( bRet )
417     {
418         SwTxtFrmInfo aFInfo( GetFrm( rNd ) );
419         bRet = aFInfo.IsFilled( aFlags.nRightMargin );
420     }
421     return bRet;
422 }
423 
424 
425 sal_Bool SwAutoFormat::IsEnumericChar( const SwTxtNode& rNd ) const
426 {
427     const String& rTxt = rNd.GetTxt();
428     String sTmp( rTxt );
429     xub_StrLen nBlnks = GetLeadingBlanks( sTmp );
430     xub_StrLen nLen = rTxt.Len() - nBlnks;
431     if( !nLen )
432         return sal_False;
433 
434     // -, +, * getrennt durch Blank ??
435     if( 2 < nLen && IsSpace( rTxt.GetChar( nBlnks + 1 ) ) )
436     {
437         if( StrChr( pBulletChar, rTxt.GetChar( nBlnks ) ) )
438             return sal_True;
439         // sollte an der Position ein Symbolfont existieren ?
440         SwTxtFrmInfo aFInfo( GetFrm( rNd ) );
441         if( aFInfo.IsBullet( nBlnks ))
442             return sal_True;
443     }
444 
445     // 1.) / 1. / 1.1.1 / (1). / (1) / ....
446     return USHRT_MAX != GetDigitLevel( rNd, nBlnks );
447 }
448 
449 
450 sal_Bool SwAutoFormat::IsBlanksInString( const SwTxtNode& rNd ) const
451 {
452     // suche im String mehr als 5 Blanks/Tabs
453     String sTmp( rNd.GetTxt() );
454     DelTrailingBlanks( DelLeadingBlanks( sTmp ));
455     const sal_Unicode* pTmp = sTmp.GetBuffer();
456     while( *pTmp )
457     {
458         if( IsSpace( *pTmp ) )
459         {
460             if( IsSpace( *++pTmp ))     // 2 Space nach einander
461             {
462                 const sal_Unicode* pStt = pTmp;
463                 while( *pTmp && IsSpace( *++pTmp ))
464                     ;
465                 if( 5 <= pTmp - pStt )
466                     return sal_True;
467             }
468             else
469                 ++pTmp;
470         }
471         else
472             ++pTmp;
473     }
474     return sal_False;
475 }
476 
477 
478 sal_uInt16 SwAutoFormat::CalcLevel( const SwTxtNode& rNd, sal_uInt16 *pDigitLvl ) const
479 {
480     sal_uInt16 nLvl = 0, nBlnk = 0;
481     const String& rTxt = rNd.GetTxt();
482     if( pDigitLvl )
483         *pDigitLvl = USHRT_MAX;
484 
485     if( RES_POOLCOLL_TEXT_MOVE == rNd.GetTxtColl()->GetPoolFmtId() )
486     {
487         if( aFlags.bAFmtByInput )
488         {
489             nLvl = rNd.GetAutoFmtLvl();
490             ((SwTxtNode&)rNd).SetAutoFmtLvl( 0 );
491             if( nLvl )
492                 return nLvl;
493         }
494         ++nLvl;
495     }
496 
497 
498     for( xub_StrLen n = 0, nEnd = rTxt.Len(); n < nEnd; ++n )
499     {
500         switch( rTxt.GetChar( n ) )
501         {
502         case ' ':   if( 3 == ++nBlnk )
503                         ++nLvl, nBlnk = 0;
504                     break;
505         case '\t':  ++nLvl, nBlnk = 0;
506                     break;
507         default:
508             if( pDigitLvl )
509                 // Teste auf 1.) / 1. / 1.1.1 / (1). / (1) / ....
510                 *pDigitLvl = GetDigitLevel( rNd, n );
511             return nLvl;
512         }
513     }
514     return nLvl;
515 }
516 
517 
518 
519 xub_StrLen SwAutoFormat::GetBigIndent( xub_StrLen& rAktSpacePos ) const
520 {
521     SwTxtFrmInfo aFInfo( GetFrm( *pAktTxtNd ) );
522     const SwTxtFrm* pNxtFrm = 0;
523 
524     if( !bMoreLines )
525     {
526         const SwTxtNode* pNxtNd = GetNextNode();
527         if( !CanJoin( pNxtNd ) || !IsOneLine( *pNxtNd ) )
528             return 0;
529 
530         pNxtFrm = GetFrm( *pNxtNd );
531     }
532 
533     return aFInfo.GetBigIndent( rAktSpacePos, pNxtFrm );
534 }
535 
536 
537 sal_Bool SwAutoFormat::IsNoAlphaLine( const SwTxtNode& rNd ) const
538 {
539     const String& rStr = rNd.GetTxt();
540     if( !rStr.Len() )
541         return sal_False;
542     // oder besser: ueber die Anzahl von Alpha/Num- und !AN-Zeichen
543     //              bestimmen.
544     xub_StrLen nANChar = 0, nBlnk = 0;
545 
546     CharClass& rCC = GetCharClass( rNd.GetSwAttrSet().GetLanguage().GetLanguage() );
547     for( xub_StrLen n = 0, nEnd = rStr.Len(); n < nEnd; ++n )
548         if( IsSpace( rStr.GetChar( n ) ) )
549             ++nBlnk;
550         else if( rCC.isLetterNumeric( rStr, n ))
551             ++nANChar;
552 
553     // sind zu 75% keine Alpha-Nummerische-Zeichen, dann sal_True
554     sal_uLong nLen = rStr.Len() - nBlnk;
555     nLen = ( nLen * 3 ) / 4;            // long overflow, if the strlen > sal_uInt16
556     return xub_StrLen(nLen) < (rStr.Len() - nANChar - nBlnk);
557 }
558 
559 
560 
561 sal_Bool SwAutoFormat::DoUnderline()
562 {
563     if( !aFlags.bSetBorder )
564         return sal_False;
565 
566     const sal_Unicode* pStr = pAktTxtNd->GetTxt().GetBuffer();
567     int eState = 0;
568     xub_StrLen nCnt = 0;
569     while( *pStr )
570     {
571 //JP 29.03.96: Spaces unterbrechen die Umrandung!
572 //      if( !IsSpace( *pStr ) )
573         {
574             int eTmp = 0;
575             switch( *pStr )
576             {
577             case '-': eTmp = 1; break;
578             case '_': eTmp = 2; break;
579             case '=': eTmp = 3; break;
580             case '*': eTmp = 4; break;
581             case '~': eTmp = 5; break;
582             case '#': eTmp = 6; break;
583             default:
584                 return sal_False;
585             }
586             if( 0 == eState )
587                 eState = eTmp;
588             else if( eState != eTmp )
589                 return sal_False;
590             ++nCnt;
591         }
592         ++pStr;
593     }
594 
595     if( 2 < nCnt )
596     {
597         // dann unterstreiche mal den vorherigen Absatz, wenn es diesen gibt!
598         DelEmptyLine( sal_False );
599         aDelPam.SetMark();
600         aDelPam.GetMark()->nContent = 0;
601 //JP 19.03.96: kein Underline sondern eine Umrandung setzen!
602 //      pDoc->Insert( aDelPam, SvxUnderlineItem( eState ) );
603 
604         SvxBorderLine aLine;
605         switch( eState )
606         {
607         case 1:         // einfach, 0,05 pt
608             aLine.SetOutWidth( DEF_LINE_WIDTH_0 );
609             break;
610         case 2:         // einfach, 1,0 pt
611             aLine.SetOutWidth( DEF_LINE_WIDTH_1 );
612             break;
613         case 3:         // doppelt, 1,1 pt
614             aLine.SetOutWidth( DEF_DOUBLE_LINE0_OUT );
615             aLine.SetInWidth( DEF_DOUBLE_LINE0_IN );
616             aLine.SetDistance( DEF_DOUBLE_LINE0_DIST );
617             break;
618         case 4:         // doppelt, 4,5 pt
619             aLine.SetOutWidth( DEF_DOUBLE_LINE4_OUT );
620             aLine.SetInWidth( DEF_DOUBLE_LINE4_IN );
621             aLine.SetDistance( DEF_DOUBLE_LINE4_DIST );
622             break;
623         case 5:         // doppelt, 6,0 pt
624             aLine.SetOutWidth( DEF_DOUBLE_LINE5_OUT );
625             aLine.SetInWidth( DEF_DOUBLE_LINE5_IN );
626             aLine.SetDistance( DEF_DOUBLE_LINE5_DIST );
627             break;
628         case 6:         // doppelt, 9,0 pt
629             aLine.SetOutWidth( DEF_DOUBLE_LINE6_OUT );
630             aLine.SetInWidth( DEF_DOUBLE_LINE6_IN );
631             aLine.SetDistance( DEF_DOUBLE_LINE6_DIST );
632             break;
633         }
634         SfxItemSet aSet(pDoc->GetAttrPool(),
635                     RES_PARATR_CONNECT_BORDER, RES_PARATR_CONNECT_BORDER,
636                     RES_BOX, RES_BOX,
637                     0);
638         aSet.Put( SwParaConnectBorderItem( sal_False ) );
639         SvxBoxItem aBox( RES_BOX );
640         aBox.SetLine( &aLine, BOX_LINE_BOTTOM );
641         aBox.SetDistance( 42 );     // ~0,75 mm
642         aSet.Put(aBox);
643         pDoc->InsertItemSet( aDelPam, aSet, 0 );
644 
645         aDelPam.DeleteMark();
646     }
647     return 2 < nCnt;
648 }
649 
650 
651 sal_Bool SwAutoFormat::DoTable()
652 {
653     if( !aFlags.bCreateTable || !aFlags.bAFmtByInput ||
654         pAktTxtNd->FindTableNode() )
655         return sal_False;
656 
657     const String& rTmp = pAktTxtNd->GetTxt();
658     xub_StrLen nSttPlus = GetLeadingBlanks( rTmp );
659     xub_StrLen nEndPlus = GetTrailingBlanks( rTmp );
660     sal_Unicode cChar;
661 
662     if( 2 > nEndPlus - nSttPlus ||
663         ( '+' != ( cChar = rTmp.GetChar( nSttPlus )) && '|' != cChar ) ||
664         ( '+' != ( cChar = rTmp.GetChar( nEndPlus - 1)) && '|' != cChar ))
665         return sal_False;
666 
667     SwTxtFrmInfo aInfo( pAktTxtFrm );
668 
669     xub_StrLen n = nSttPlus;
670     const sal_Unicode* pStr = rTmp.GetBuffer() + n;
671     SvUShorts aPosArr( 5, 5 );
672 
673     while( *pStr )
674     {
675         switch( *pStr )
676         {
677         case '-':
678         case '_':
679         case '=':
680         case ' ':
681         case '\t':
682             break;
683 
684         case '+':
685         case '|':
686             aPosArr.Insert( static_cast<sal_uInt16>(aInfo.GetCharPos(n)), aPosArr.Count() );
687             break;
688 
689         default:
690             return sal_False;
691         }
692         if( ++n == nEndPlus )
693             break;
694 
695         ++pStr;
696     }
697 
698     if( 1 < aPosArr.Count() )
699     {
700         // Ausrichtung vom Textnode besorgen:
701         sal_uInt16 nColCnt = aPosArr.Count() - 1;
702         SwTwips nSttPos = aPosArr[ 0 ];
703         sal_Int16 eHori;
704         switch( pAktTxtNd->GetSwAttrSet().GetAdjust().GetAdjust() )
705         {
706         case SVX_ADJUST_CENTER:     eHori = text::HoriOrientation::CENTER;    break;
707         case SVX_ADJUST_RIGHT:      eHori = text::HoriOrientation::RIGHT;     break;
708 
709         default:
710             if( nSttPos )
711             {
712                 eHori = text::HoriOrientation::NONE;
713                 // dann muss als letztes noch die akt. FrameBreite
714                 // ins Array
715                 aPosArr.Insert( static_cast<sal_uInt16>(pAktTxtFrm->Frm().Width()), aPosArr.Count() );
716             }
717             else
718                 eHori = text::HoriOrientation::LEFT;
719             break;
720         }
721 
722         // dann erzeuge eine Tabelle, die den Zeichen entspricht
723         DelEmptyLine();
724         SwNodeIndex aIdx( aDelPam.GetPoint()->nNode );
725         aDelPam.Move( fnMoveForward );
726         pDoc->InsertTable( SwInsertTableOptions( tabopts::ALL_TBL_INS_ATTR , 1 ),
727                            *aDelPam.GetPoint(), 1, nColCnt, eHori,
728                            0, &aPosArr );
729         aDelPam.GetPoint()->nNode = aIdx;
730     }
731     return 1 < aPosArr.Count();
732 }
733 
734 
735 String& SwAutoFormat::DelLeadingBlanks( String& rStr ) const
736 {
737     xub_StrLen nL;
738     xub_StrLen n;
739 
740     for( nL = rStr.Len(), n = 0; n < nL && IsSpace( rStr.GetChar(n) ); ++n )
741         ;
742     if( n )     // keine Spaces
743         rStr.Erase( 0, n );
744     return rStr;
745 }
746 
747 
748 String& SwAutoFormat::DelTrailingBlanks( String& rStr ) const
749 {
750     xub_StrLen nL = rStr.Len(), n = nL;
751     if( !nL )
752         return rStr;
753 
754     while( --n && IsSpace( rStr.GetChar( n ) )  )
755         ;
756     if( n+1 != nL )     // keine Spaces
757         rStr.Erase( n+1 );
758     return rStr;
759 }
760 
761 
762 xub_StrLen SwAutoFormat::GetLeadingBlanks( const String& rStr ) const
763 {
764     xub_StrLen nL;
765     xub_StrLen n;
766 
767     for( nL = rStr.Len(), n = 0; n < nL && IsSpace( rStr.GetChar( n ) ); ++n )
768         ;
769     return n;
770 }
771 
772 
773 xub_StrLen SwAutoFormat::GetTrailingBlanks( const String& rStr ) const
774 {
775     xub_StrLen nL = rStr.Len(), n = nL;
776     if( !nL )
777         return 0;
778 
779     while( --n && IsSpace( rStr.GetChar( n ) )  )
780         ;
781     return ++n;
782 }
783 
784 
785 sal_Bool SwAutoFormat::IsFirstCharCapital( const SwTxtNode& rNd ) const
786 {
787     const String& rTxt = rNd.GetTxt();
788     for( xub_StrLen n = 0, nEnd = rTxt.Len(); n < nEnd; ++n )
789         if( !IsSpace( rTxt.GetChar( n ) ) )
790         {
791             CharClass& rCC = GetCharClass( rNd.GetSwAttrSet().
792                                         GetLanguage().GetLanguage() );
793             sal_Int32 nCharType = rCC.getCharacterType( rTxt, n );
794             return CharClass::isLetterType( nCharType ) &&
795                    0 != ( i18n::KCharacterType::UPPER &
796                                                     nCharType );
797         }
798     return sal_False;
799 }
800 
801 
802 sal_uInt16 SwAutoFormat::GetDigitLevel( const SwTxtNode& rNd, xub_StrLen& rPos,
803         String* pPreFix, String* pPostFix, String* pNumTypes ) const
804 {
805     // Teste auf 1.) / 1. / 1.1.1 / (1). / (1) / ....
806     const String& rTxt = rNd.GetTxt();
807     xub_StrLen nPos = rPos;
808     int eScan = NONE;
809 
810     sal_uInt16 nStart = 0;
811     sal_uInt8 nDigitLvl = 0, nDigitCnt = 0;
812     //count number of parenthesis to assure a sensible order is found
813     sal_uInt16 nOpeningParentheses = 0;
814     sal_uInt16 nClosingParentheses = 0;
815 
816     CharClass& rCC = GetCharClass( rNd.GetSwAttrSet().GetLanguage().GetLanguage() );
817 
818     while( nPos < rTxt.Len() && nDigitLvl < MAXLEVEL - 1)
819     {
820         const sal_Unicode cCurrentChar = rTxt.GetChar( nPos );
821         if( ('0' <= cCurrentChar &&  '9' >= cCurrentChar) ||
822             (0xff10 <= cCurrentChar &&  0xff19 >= cCurrentChar) )
823         {
824             if( eScan & DELIM )
825             {
826                 if( eScan & CHG )       // nicht wenns mit einer Zahl beginnt
827                 {
828                     ++nDigitLvl;
829                     if( pPostFix )
830                         *pPostFix += (sal_Unicode)1;
831                 }
832 
833                 if( pNumTypes )
834                     *pNumTypes += (sal_Unicode)('0' + SVX_NUM_ARABIC);
835 
836                 eScan = eScan | CHG;
837             }
838             else if( pNumTypes && !(eScan & DIGIT) )
839                 *pNumTypes += (sal_Unicode)('0' + SVX_NUM_ARABIC);
840 
841             eScan &= ~DELIM;        // Delim raus
842             if( 0 != (eScan & ~CHG) && DIGIT != (eScan & ~CHG))
843                 return USHRT_MAX;
844 
845             eScan |= DIGIT;         // Digit rein
846             if( 3 == ++nDigitCnt )  // mehr als 2 Nummern sind kein Enum mehr
847                 return USHRT_MAX;
848 
849             nStart *= 10;
850             nStart += cCurrentChar <= '9' ? cCurrentChar - '0' : cCurrentChar - 0xff10;
851         }
852         else if( rCC.isAlpha( rTxt, nPos ) )
853         {
854             sal_Bool bIsUpper =
855                 0 != ( i18n::KCharacterType::UPPER &
856                                         rCC.getCharacterType( rTxt, nPos ));
857             sal_Unicode cLow = rCC.toLower( rTxt, nPos, 1 ).GetChar(0), cNumTyp;
858             int eTmpScan;
859 
860             // roemische Zeichen sind "mdclxvi". Da man aber eher mal eine
861             // Numerierung mit c oder d anfangen will, werden diese erstmal
862             // zu chars und spaeter ggfs. zu romischen Zeichen!
863 //          if( strchr( "mdclxvi", cLow ))
864 #ifdef WITH_ALPHANUM_AS_NUMFMT
865             //detection of 'c' and 'd' a ROMAN numbering should not be done here
866             if( 256 > cLow  &&( (eScan & (LOWER_ROMAN|UPPER_ROMAN))
867                                     ? strchr( "mdclxvi", cLow )
868                                     : strchr( "mlxvi", cLow ) ))
869 #else
870             if( 256 > cLow  && ( strchr( "mdclxvi", cLow ) ))
871 #endif
872             {
873                 if( bIsUpper )
874                     cNumTyp = '0' + SVX_NUM_ROMAN_UPPER, eTmpScan = UPPER_ROMAN;
875                 else
876                     cNumTyp = '0' + SVX_NUM_ROMAN_LOWER, eTmpScan = LOWER_ROMAN;
877             }
878             else if( bIsUpper )
879                 cNumTyp = '0' + SVX_NUM_CHARS_UPPER_LETTER, eTmpScan = UPPER_ALPHA;
880             else
881                 cNumTyp = '0' + SVX_NUM_CHARS_LOWER_LETTER, eTmpScan = LOWER_ALPHA;
882 
883 
884             //ggfs. auf roemische Zeichen umschalten (nur bei c/d!)?
885             if( 1 == nDigitCnt && ( eScan & (UPPER_ALPHA|LOWER_ALPHA) ) &&
886                 ( 3 == nStart || 4 == nStart) && 256 > cLow &&
887                 strchr( "mdclxvi", cLow ) &&
888                 (( eScan & UPPER_ALPHA ) ? (eTmpScan & (UPPER_ALPHA|UPPER_ROMAN))
889                                          : (eTmpScan & (LOWER_ALPHA|LOWER_ROMAN))) )
890             {
891                 sal_Unicode c = '0';
892                 nStart = 3 == nStart ? 100 : 500;
893                 if( UPPER_ALPHA == eTmpScan )
894                     eTmpScan = UPPER_ROMAN, c += SVX_NUM_ROMAN_UPPER;
895                 else
896                     eTmpScan = LOWER_ROMAN, c += SVX_NUM_ROMAN_LOWER;
897 
898                 ( eScan &= ~(UPPER_ALPHA|LOWER_ALPHA)) |= eTmpScan;
899                 if( pNumTypes )
900                     pNumTypes->SetChar( pNumTypes->Len() - 1, c );
901             }
902 
903             if( eScan & DELIM )
904             {
905                 if( eScan & CHG )       // nicht wenns mit einer Zahl beginnt
906                 {
907                     ++nDigitLvl;
908                     if( pPostFix )
909                         *pPostFix += (sal_Unicode)1;
910                 }
911 
912                 if( pNumTypes )
913                     *pNumTypes += cNumTyp;
914                 eScan = eScan | CHG;
915             }
916             else if( pNumTypes && !(eScan & eTmpScan) )
917                 *pNumTypes += cNumTyp;
918 
919             eScan &= ~DELIM;        // Delim raus
920 
921             // falls ein andere Type gesetzt ist, brechen wir ab
922             if( 0 != ( eScan & ~CHG ) && eTmpScan != ( eScan & ~CHG ))
923                 return USHRT_MAX;
924 
925             if( eTmpScan & (UPPER_ALPHA | LOWER_ALPHA) )
926             {
927                 // Buchstaben nur zulassen, wenn sie einmalig vorkommen
928                 return USHRT_MAX;
929             }
930             else
931             {
932                 // roemische Zahlen: checke ob das gueltige Zeichen sind
933                 sal_uInt16 nVal;
934                 sal_Bool bError = sal_False;
935                 switch( cLow )
936                 {
937                 case 'm':   nVal = 1000; goto CHECK_ROMAN_1;
938                 case 'd':   nVal =  500; goto CHECK_ROMAN_5;
939                 case 'c':   nVal =  100; goto CHECK_ROMAN_1;
940                 case 'l':   nVal =   50; goto CHECK_ROMAN_5;
941                 case 'x':   nVal =   10; goto CHECK_ROMAN_1;
942                 case 'v':   nVal =    5; goto CHECK_ROMAN_5;
943 
944 CHECK_ROMAN_1:
945                     {
946                         int nMod5 = nStart % (nVal * 5);
947                         int nLast = nStart % nVal;
948                         int n10 = nVal / 10;
949 
950                         if( nMod5 == ((3 * nVal) + n10 ) ||
951                             nMod5 == ((4 * nVal) + n10 ) ||
952                             nLast == n10 )
953                             nStart = static_cast<sal_uInt16>(nStart + (n10 * 8));
954                         else if( nMod5 == 0 ||
955                                  nMod5 == (1 * nVal) ||
956                                  nMod5 == (2 * nVal) )
957                             nStart = nStart + nVal;
958                         else
959                             bError = sal_True;
960                     }
961                     break;
962 
963 CHECK_ROMAN_5:
964                     {
965                         if( ( nStart / nVal ) & 1 )
966                             bError = sal_True;
967                         else
968                         {
969                             int nMod = nStart % nVal;
970                             int n10 = nVal / 5;
971                             if( n10 == nMod )
972                                 nStart = static_cast<sal_uInt16>(nStart + (3 * n10));
973                             else if( 0 == nMod )
974                                 nStart = nStart + nVal;
975                             else
976                                 bError = sal_True;
977                         }
978                     }
979                     break;
980 
981                 case 'i':
982                         if( nStart % 5 >= 3 )
983                             bError = sal_True;
984                         else
985                             nStart += 1;
986                         break;
987 
988                 default:
989                     bError = sal_True;
990                 }
991 
992                 if( bError )
993                     return USHRT_MAX;
994             }
995             eScan |= eTmpScan;          // Digit rein
996             ++nDigitCnt;
997         }
998         else if( (256 > cCurrentChar &&
999                  strchr( ".)(", cCurrentChar )) ||
1000                  0x3002 == cCurrentChar /* Chinese trad. dot */||
1001                  0xff0e == cCurrentChar /* Japanese dot */||
1002                  0xFF08 == cCurrentChar /* opening bracket Chin./Jap.*/||
1003                  0xFF09 == cCurrentChar )/* closing bracket Chin./Jap. */
1004         {
1005             if(cCurrentChar == '(' || cCurrentChar == 0xFF09)
1006                 nOpeningParentheses++;
1007             else if(cCurrentChar == ')'|| cCurrentChar == 0xFF08)
1008                 nClosingParentheses++;
1009             // nur wenn noch keine Zahlen gelesen wurden!
1010             if( pPreFix && !( eScan & ( NO_DELIM | CHG )) )
1011                 *pPreFix += rTxt.GetChar( nPos );
1012             else if( pPostFix )
1013                 *pPostFix += rTxt.GetChar( nPos );
1014 
1015             if( NO_DELIM & eScan )
1016             {
1017                 eScan |= CHG;
1018                 if( pPreFix )
1019                     (*pPreFix += (sal_Unicode)1)
1020                               += String::CreateFromInt32( nStart );
1021             }
1022             eScan &= ~NO_DELIM;     // Delim raus
1023             eScan |= DELIM;         // Digit rein
1024             nDigitCnt = 0;
1025             nStart = 0;
1026         }
1027         else
1028             break;
1029         ++nPos;
1030     }
1031     if( !( CHG & eScan ) || rPos == nPos ||
1032         nPos == rTxt.Len() || !IsSpace( rTxt.GetChar( nPos ) ) ||
1033         (nOpeningParentheses > nClosingParentheses))
1034         return USHRT_MAX;
1035 
1036     if( (NO_DELIM & eScan) && pPreFix )     // den letzen nicht vergessen
1037         (*pPreFix += (sal_Unicode)1) += String::CreateFromInt32( nStart );
1038 
1039     rPos = nPos;
1040     return nDigitLvl;       // 0 .. 9 (MAXLEVEL - 1)
1041 }
1042 
1043 
1044 void SwAutoFormat::SetColl( sal_uInt16 nId, sal_Bool bHdLineOrText )
1045 {
1046     aDelPam.DeleteMark();
1047     aDelPam.GetPoint()->nNode = aNdIdx;
1048     aDelPam.GetPoint()->nContent.Assign( pAktTxtNd, 0 );
1049 
1050     // behalte harte Tabs, Ausrichtung, Sprache, Silbentrennung,
1051     // DropCaps und fast alle Frame-Attribute
1052     SfxItemSet aSet( pDoc->GetAttrPool(),
1053                         RES_PARATR_ADJUST, RES_PARATR_ADJUST,
1054                         RES_PARATR_TABSTOP, RES_PARATR_DROP,
1055                         RES_CHRATR_LANGUAGE, RES_CHRATR_LANGUAGE,
1056                         RES_BACKGROUND, RES_SHADOW,
1057                         0 );
1058 
1059     if( pAktTxtNd->HasSwAttrSet() )
1060     {
1061         aSet.Put( *pAktTxtNd->GetpSwAttrSet() );
1062         // einige Sonderbedingungen:
1063         // HeaderLine/Textkoerper: nur zentriert oder rechts mitnehmem
1064         // sonst nur den Blocksatz
1065         SvxAdjustItem* pAdj;
1066         if( SFX_ITEM_SET == aSet.GetItemState( RES_PARATR_ADJUST,
1067                         sal_False, (const SfxPoolItem**)&pAdj ))
1068         {
1069             SvxAdjust eAdj = pAdj->GetAdjust();
1070             if( bHdLineOrText ? (SVX_ADJUST_RIGHT != eAdj &&
1071                                  SVX_ADJUST_CENTER != eAdj)
1072                               : SVX_ADJUST_BLOCK != eAdj )
1073                 aSet.ClearItem( RES_PARATR_ADJUST );
1074         }
1075     }
1076 
1077     pDoc->SetTxtFmtCollByAutoFmt( *aDelPam.GetPoint(), nId, &aSet );
1078 }
1079 
1080 
1081 sal_Bool SwAutoFormat::HasSelBlanks( SwPaM& rPam ) const
1082 {
1083     // noch ein Blank am Anfang oder Ende ?
1084     // nicht loeschen, wird wieder eingefuegt.
1085     SwPosition * pPos = rPam.End();
1086     xub_StrLen nBlnkPos = pPos->nContent.GetIndex();
1087     SwTxtNode* pTxtNd = pPos->nNode.GetNode().GetTxtNode();
1088     if( nBlnkPos && nBlnkPos-- < pTxtNd->GetTxt().Len() &&
1089         ( ' ' == pTxtNd->GetTxt().GetChar( nBlnkPos ) ))
1090 // JP 23.08.95: keine Tabs stehen lassen, diese in Blanks wandeln
1091 //        ( ' ' == ( cCh = pTxtNd->GetTxt()[ nBlnkPos ] ) || '\t' == cCh ))
1092         pPos->nContent--;
1093     else
1094     {
1095         pPos = rPam.GetPoint() == pPos ? rPam.GetMark() : rPam.GetPoint();
1096         nBlnkPos = pPos->nContent.GetIndex();
1097         pTxtNd = pPos->nNode.GetNode().GetTxtNode();
1098         if( nBlnkPos < pTxtNd->GetTxt().Len() &&
1099             ( ' ' == pTxtNd->GetTxt().GetChar( nBlnkPos )))
1100 // JP 23.08.95: keine Tabs stehen lassen, diese in Blanks wandeln
1101 //            ( ' ' == ( cCh = pTxtNd->GetTxt()[ nBlnkPos ] ) || '\t' == cCh ))
1102             pPos->nContent++;
1103         else
1104             return sal_False;
1105     }
1106     return sal_True;
1107 }
1108 
1109 
1110 sal_Bool SwAutoFormat::HasBreakAttr( const SwTxtNode& rTxtNd ) const
1111 {
1112     const SfxItemSet* pSet = rTxtNd.GetpSwAttrSet();
1113     if( !pSet )
1114         return sal_False;
1115 
1116     const SfxPoolItem* pItem;
1117     if( SFX_ITEM_SET == pSet->GetItemState( RES_BREAK, sal_False, &pItem )
1118         && SVX_BREAK_NONE != ((SvxFmtBreakItem*)pItem)->GetBreak() )
1119         return sal_True;
1120 
1121     if( SFX_ITEM_SET == pSet->GetItemState( RES_PAGEDESC, sal_False, &pItem )
1122         && ((SwFmtPageDesc*)pItem)->GetPageDesc()
1123         && nsUseOnPage::PD_NONE != ((SwFmtPageDesc*)pItem)->GetPageDesc()->GetUseOn() )
1124         return sal_True;
1125     return sal_False;
1126 }
1127 
1128 
1129 // ist ein Punkt am Ende ??
1130 sal_Bool SwAutoFormat::IsSentenceAtEnd( const SwTxtNode& rTxtNd ) const
1131 {
1132     const String& rStr = rTxtNd.GetTxt();
1133     xub_StrLen n = rStr.Len();
1134     if( !n )
1135         return sal_True;
1136 
1137     while( --n && IsSpace( rStr.GetChar( n  ) ) )
1138         ;
1139     return '.' == rStr.GetChar( n );
1140 }
1141 
1142 
1143 // loesche im Node Anfang oder/und Ende
1144 void SwAutoFormat::DeleteAktPara( sal_Bool bStart, sal_Bool bEnd )
1145 {
1146     if( aFlags.bAFmtByInput
1147         ? aFlags.bAFmtByInpDelSpacesAtSttEnd
1148         : aFlags.bAFmtDelSpacesAtSttEnd )
1149     {
1150         // Loesche Blanks am Ende vom akt. und am Anfang vom naechsten
1151         aDelPam.DeleteMark();
1152         aDelPam.GetPoint()->nNode = aNdIdx;
1153         xub_StrLen nPos;
1154         if( bStart && 0 != ( nPos = GetLeadingBlanks( pAktTxtNd->GetTxt() )))
1155         {
1156             aDelPam.GetPoint()->nContent.Assign( pAktTxtNd, 0 );
1157             aDelPam.SetMark();
1158             aDelPam.GetPoint()->nContent = nPos;
1159             DeleteSel( aDelPam );
1160             aDelPam.DeleteMark();
1161         }
1162         if( bEnd && pAktTxtNd->GetTxt().Len() !=
1163                     ( nPos = GetTrailingBlanks( pAktTxtNd->GetTxt() )) )
1164         {
1165             aDelPam.GetPoint()->nContent.Assign( pAktTxtNd, pAktTxtNd->GetTxt().Len() );
1166             aDelPam.SetMark();
1167             aDelPam.GetPoint()->nContent = nPos;
1168             DeleteSel( aDelPam );
1169             aDelPam.DeleteMark();
1170         }
1171     }
1172 }
1173 
1174 void SwAutoFormat::DeleteSel( SwPaM& rDelPam )
1175 {
1176     if( aFlags.bWithRedlining )
1177     {
1178         // damit der DelPam auch verschoben wird, in den Shell-Cursr-Ring
1179         // mit aufnehmen !!
1180         SwPaM* pShCrsr = pEditShell->_GetCrsr();
1181         SwPaM aTmp( *pAktTxtNd, 0, pShCrsr );
1182 
1183         Ring *pPrev = rDelPam.GetPrev();
1184         rDelPam.MoveRingTo( pShCrsr );
1185 
1186         pEditShell->DeleteSel( rDelPam );
1187 
1188         // und den Pam wieder herausnehmen:
1189         Ring *p, *pNext = (Ring*)&rDelPam;
1190         do {
1191             p = pNext;
1192             pNext = p->GetNext();
1193             p->MoveTo( &rDelPam );
1194         } while( p != pPrev );
1195 
1196         aNdIdx = aTmp.GetPoint()->nNode;
1197         pAktTxtNd = aNdIdx.GetNode().GetTxtNode();
1198     }
1199     else
1200         pEditShell->DeleteSel( rDelPam );
1201 }
1202 
1203 sal_Bool SwAutoFormat::DeleteAktNxtPara( const String& rNxtPara )
1204 {
1205     // Loesche Blanks am Ende vom akt. und am Anfang vom naechsten
1206     aDelPam.DeleteMark();
1207     aDelPam.GetPoint()->nNode = aNdIdx;
1208     aDelPam.GetPoint()->nContent.Assign( pAktTxtNd,
1209                     GetTrailingBlanks( pAktTxtNd->GetTxt() ) );
1210     aDelPam.SetMark();
1211 
1212     aDelPam.GetPoint()->nNode++;
1213     SwTxtNode* pTNd = aDelPam.GetNode()->GetTxtNode();
1214     if( !pTNd )
1215     {
1216         // dann nur bis zum Ende von Absatz loeschen
1217         aDelPam.GetPoint()->nNode--;
1218         aDelPam.GetPoint()->nContent = pAktTxtNd->GetTxt().Len();
1219     }
1220     else
1221         aDelPam.GetPoint()->nContent.Assign( pTNd,
1222                             GetLeadingBlanks( rNxtPara ));
1223 
1224     // noch ein Blank am Anfang oder Ende ?
1225     // nicht loeschen, wird wieder eingefuegt.
1226     sal_Bool bHasBlnks = HasSelBlanks( aDelPam );
1227 
1228     if( *aDelPam.GetPoint() != *aDelPam.GetMark() )
1229         DeleteSel( aDelPam );
1230     aDelPam.DeleteMark();
1231 
1232     return !bHasBlnks;
1233 }
1234 
1235 
1236 void SwAutoFormat::DelEmptyLine( sal_Bool bTstNextPara )
1237 {
1238     SetRedlineTxt( STR_AUTOFMTREDL_DEL_EMPTY_PARA );
1239     // Loesche Blanks den leeren Absatz
1240     aDelPam.DeleteMark();
1241     aDelPam.GetPoint()->nNode = aNdIdx;
1242     aDelPam.GetPoint()->nContent.Assign( pAktTxtNd, pAktTxtNd->GetTxt().Len() );
1243     aDelPam.SetMark();
1244 
1245     aDelPam.GetMark()->nNode--;
1246     SwTxtNode* pTNd = aDelPam.GetNode( sal_False )->GetTxtNode();
1247     if( pTNd )
1248         // erstmal den vorherigen Textnode benutzen.
1249         aDelPam.GetMark()->nContent.Assign( pTNd, pTNd->GetTxt().Len() );
1250     else if( bTstNextPara )
1251     {
1252         // dann versuche den naechsten (am Anfang vom Dok, Tabellen-Zellen,
1253         // Rahmen, ...
1254         aDelPam.GetMark()->nNode += 2;
1255         pTNd = aDelPam.GetNode( sal_False )->GetTxtNode();
1256         if( pTNd )
1257         {
1258             aDelPam.GetMark()->nContent.Assign( pTNd, 0 );
1259             aDelPam.GetPoint()->nContent = 0;
1260         }
1261     }
1262     else
1263     {
1264         aDelPam.GetMark()->nNode = aNdIdx;
1265         aDelPam.GetMark()->nContent = 0;
1266         pTNd = pAktTxtNd;
1267     }
1268     if( pTNd )
1269         DeleteSel( aDelPam );
1270 
1271     aDelPam.DeleteMark();
1272     ClearRedlineTxt();
1273 }
1274 
1275 
1276 void SwAutoFormat::DelMoreLinesBlanks( sal_Bool bWithLineBreaks )
1277 {
1278     if( aFlags.bAFmtByInput
1279         ? aFlags.bAFmtByInpDelSpacesBetweenLines
1280         : aFlags.bAFmtDelSpacesBetweenLines )
1281     {
1282         // loesche alle "Blanks" Links und Rechts vom Einzug
1283         aDelPam.DeleteMark();
1284         aDelPam.GetPoint()->nNode = aNdIdx;
1285         aDelPam.GetPoint()->nContent.Assign( pAktTxtNd, 0 );
1286 
1287         SwTxtFrmInfo aFInfo( pAktTxtFrm );
1288         aFInfo.GetSpaces( aDelPam, !aFlags.bAFmtByInput || bWithLineBreaks );
1289 
1290         SwPaM* pNxt;
1291         do {
1292             pNxt = (SwPaM*)aDelPam.GetNext();
1293             if( pNxt->HasMark() && *pNxt->GetPoint() != *pNxt->GetMark() )
1294             {
1295                 sal_Bool bHasBlnks = HasSelBlanks( *pNxt );
1296                 DeleteSel( *pNxt );
1297                 if( !bHasBlnks )
1298                 {
1299                     pDoc->InsertString( *pNxt, sal_Unicode(' ') );
1300                 }
1301             }
1302 
1303             if( pNxt == &aDelPam )
1304                 break;
1305             delete pNxt;
1306         } while( sal_True );
1307 
1308         aDelPam.DeleteMark();
1309     }
1310 }
1311 
1312 
1313         // loesche den vorherigen Absatz
1314 void SwAutoFormat::DelPrevPara()
1315 {
1316     aDelPam.DeleteMark();
1317     aDelPam.GetPoint()->nNode = aNdIdx;
1318     aDelPam.GetPoint()->nContent.Assign( pAktTxtNd, 0 );
1319     aDelPam.SetMark();
1320 
1321     aDelPam.GetPoint()->nNode--;
1322     SwTxtNode* pTNd = aDelPam.GetNode()->GetTxtNode();
1323     if( pTNd )
1324     {
1325         // erstmal den vorherigen Textnode benutzen.
1326         aDelPam.GetPoint()->nContent.Assign( pTNd, pTNd->GetTxt().Len() );
1327         DeleteSel( aDelPam );
1328     }
1329     aDelPam.DeleteMark();
1330 }
1331 
1332 
1333 void SwAutoFormat::BuildIndent()
1334 {
1335     SetRedlineTxt( STR_AUTOFMTREDL_SET_TMPL_INDENT );
1336 
1337     // lese alle nachfolgenden Absaetze die zu diesem Einzug gehoeren
1338     sal_Bool bBreak = sal_True;
1339     if( bMoreLines )
1340         DelMoreLinesBlanks( sal_True );
1341     else
1342         bBreak = !IsFastFullLine( *pAktTxtNd ) ||
1343                 IsBlanksInString( *pAktTxtNd ) ||
1344                 IsSentenceAtEnd( *pAktTxtNd );
1345     SetColl( RES_POOLCOLL_TEXT_IDENT );
1346     if( !bBreak )
1347     {
1348         SetRedlineTxt( STR_AUTOFMTREDL_DEL_MORELINES );
1349         const SwTxtNode* pNxtNd = GetNextNode();
1350         if( pNxtNd && !bEnde )
1351         {
1352             do {
1353                 bBreak = !IsFastFullLine( *pNxtNd ) ||
1354                         IsBlanksInString( *pNxtNd ) ||
1355                         IsSentenceAtEnd( *pNxtNd );
1356                 if( DeleteAktNxtPara( pNxtNd->GetTxt() ))
1357                 {
1358                     pDoc->InsertString( aDelPam, sal_Unicode(' ') );
1359                 }
1360                 if( bBreak )
1361                     break;
1362                 pNxtNd = GetNextNode();
1363             } while( CanJoin( pNxtNd ) &&
1364                     !CalcLevel( *pNxtNd ) );
1365         }
1366     }
1367     DeleteAktPara( sal_True, sal_True );
1368     AutoCorrect();
1369 }
1370 
1371 
1372 void SwAutoFormat::BuildTextIndent()
1373 {
1374     SetRedlineTxt( STR_AUTOFMTREDL_SET_TMPL_TEXT_INDENT);
1375     // lese alle nachfolgenden Absaetze die zu diesem Einzug gehoeren
1376     sal_Bool bBreak = sal_True;
1377     if( bMoreLines )
1378         DelMoreLinesBlanks( sal_True );
1379     else
1380         bBreak = !IsFastFullLine( *pAktTxtNd ) ||
1381                     IsBlanksInString( *pAktTxtNd ) ||
1382                     IsSentenceAtEnd( *pAktTxtNd );
1383 
1384     if( aFlags.bAFmtByInput )
1385         pAktTxtNd->SetAutoFmtLvl( (sal_uInt8)CalcLevel( *pAktTxtNd ) );
1386 
1387     SetColl( RES_POOLCOLL_TEXT_MOVE );
1388     if( !bBreak )
1389     {
1390         SetRedlineTxt( STR_AUTOFMTREDL_DEL_MORELINES );
1391         const SwTxtNode* pNxtNd = GetNextNode();
1392         while(  CanJoin( pNxtNd ) &&
1393                 CalcLevel( *pNxtNd ) )
1394         {
1395             bBreak = !IsFastFullLine( *pNxtNd ) || IsBlanksInString( *pNxtNd ) ||
1396                     IsSentenceAtEnd( *pNxtNd );
1397             if( DeleteAktNxtPara( pNxtNd->GetTxt() ) )
1398             {
1399                 pDoc->InsertString( aDelPam, sal_Unicode(' ') );
1400             }
1401             if( bBreak )
1402                 break;
1403             pNxtNd = GetNextNode();
1404         }
1405     }
1406     DeleteAktPara( sal_True, sal_True );
1407     AutoCorrect();
1408 }
1409 
1410 
1411 void SwAutoFormat::BuildText()
1412 {
1413     SetRedlineTxt( STR_AUTOFMTREDL_SET_TMPL_TEXT );
1414     // lese alle nachfolgenden Absaetze die zu diesem Text
1415     // ohne Einzug gehoeren
1416     sal_Bool bBreak = sal_True;
1417     if( bMoreLines )
1418         DelMoreLinesBlanks();
1419     else
1420         bBreak = !IsFastFullLine( *pAktTxtNd ) ||
1421                     IsBlanksInString( *pAktTxtNd ) ||
1422                     IsSentenceAtEnd( *pAktTxtNd );
1423     SetColl( RES_POOLCOLL_TEXT, sal_True );
1424     if( !bBreak )
1425     {
1426         SetRedlineTxt( STR_AUTOFMTREDL_DEL_MORELINES );
1427         const SwTxtNode* pNxtNd = GetNextNode();
1428         while(  CanJoin( pNxtNd ) &&
1429                 !CalcLevel( *pNxtNd ) )
1430         {
1431             bBreak = !IsFastFullLine( *pNxtNd ) || IsBlanksInString( *pNxtNd ) ||
1432                     IsSentenceAtEnd( *pNxtNd );
1433             if( DeleteAktNxtPara( pNxtNd->GetTxt() ) )
1434             {
1435                 pDoc->InsertString( aDelPam, sal_Unicode(' ') );
1436             }
1437             if( bBreak )
1438                 break;
1439             const SwTxtNode* pCurrNode = pNxtNd;
1440             pNxtNd = GetNextNode();
1441             if(!pNxtNd || pCurrNode == pNxtNd)
1442                 break;
1443         }
1444     }
1445     DeleteAktPara( sal_True, sal_True );
1446     AutoCorrect();
1447 }
1448 
1449 
1450 void SwAutoFormat::BuildEnum( sal_uInt16 nLvl, sal_uInt16 nDigitLevel )
1451 {
1452     SetRedlineTxt( STR_AUTOFMTREDL_SET_NUMBULET );
1453 
1454     sal_Bool bBreak = sal_True;
1455 
1456     // als erstes den akt. Einzug bestimmen und die Framebreite bestimmen
1457     SwTwips nFrmWidth = pAktTxtFrm->Prt().Width();;
1458     SwTwips nLeftTxtPos;
1459     {
1460         const sal_Unicode* pTxt = pAktTxtNd->GetTxt().GetBuffer(), *pSav = pTxt;
1461         while( IsSpace( *pTxt ) )
1462             ++pTxt;
1463 
1464         SwTxtFrmInfo aInfo( pAktTxtFrm );
1465         nLeftTxtPos = aInfo.GetCharPos( static_cast<xub_StrLen>(pTxt - pSav) );
1466         nLeftTxtPos -= pAktTxtNd->GetSwAttrSet().GetLRSpace().GetLeft();
1467     }
1468 
1469     if( bMoreLines )
1470         DelMoreLinesBlanks();
1471     else
1472         bBreak = !IsFastFullLine( *pAktTxtNd ) ||
1473                     IsBlanksInString( *pAktTxtNd ) ||
1474                     IsSentenceAtEnd( *pAktTxtNd );
1475     sal_Bool bRTL = pEditShell->IsInRightToLeftText();
1476 //  SetColl( RES_POOLCOLL_NUM_LEVEL1 + ( nLvl * 4 ) );
1477     DeleteAktPara( sal_True, sal_True );
1478 
1479     sal_Bool bChgBullet = sal_False, bChgEnum = sal_False;
1480     xub_StrLen nAutoCorrPos = 0;
1481 
1482     // falls die Numerierung gesetzt werden, die akt. besorgen
1483     // --> OD 2008-02-11 #newlistlevelattrs#
1484     SwNumRule aRule( pDoc->GetUniqueNumRuleName(),
1485                      // --> OD 2008-06-06 #i89178#
1486                      numfunc::GetDefaultPositionAndSpaceMode() );
1487                      // <--
1488     // <--
1489     const SwNumRule* pCur = 0;
1490     if( aFlags.bSetNumRule && 0 != (pCur = pAktTxtNd->GetNumRule()) )
1491         aRule = *pCur;
1492 
1493     // ersetze das Bullet-Zeichen mit dem definiertem
1494     const String& rStr = pAktTxtNd->GetTxt();
1495     xub_StrLen nTxtStt = 0, nOrigTxtStt = 0;
1496     const sal_Unicode* pFndBulletChr;
1497 //  if( aFlags.bAFmtByInput ? aFlags.bSetNumRule : aFlags.bChgEnumNum &&
1498     if( aFlags.bChgEnumNum &&
1499         2 < rStr.Len() &&
1500         0 != ( pFndBulletChr = StrChr( pBulletChar, rStr.GetChar( nTxtStt ) ))
1501         && IsSpace( rStr.GetChar( nTxtStt + 1 ) ) )
1502     {
1503         if( aFlags.bAFmtByInput )
1504         {
1505             if( aFlags.bSetNumRule )
1506             {
1507                 SwCharFmt* pCFmt = pDoc->GetCharFmtFromPool(
1508                                             RES_POOLCHR_BUL_LEVEL );
1509                 bChgBullet = sal_True;
1510                 // wurde das Format schon mal angepasst?
1511                 if( !aRule.GetNumFmt( nLvl ) )
1512                 {
1513                     int nBulletPos = pFndBulletChr - pBulletChar;
1514                     sal_Unicode cBullChar;
1515                     const Font* pBullFnt( 0 );
1516                     if( nBulletPos < cnPosEnDash )
1517                     {
1518                         cBullChar = aFlags.cBullet;
1519                         pBullFnt = &aFlags.aBulletFont;
1520                     }
1521                     else
1522                     {
1523                         cBullChar = nBulletPos < cnPosEmDash
1524                                         ? cStarSymbolEnDash
1525                                         : cStarSymbolEmDash;
1526                         // --> OD 2008-06-03 #i63395#
1527                         // Only apply user defined default bullet font
1528                         if ( numfunc::IsDefBulletFontUserDefined() )
1529                         {
1530                             pBullFnt = &numfunc::GetDefBulletFont();
1531                         }
1532                         // <--
1533                     }
1534 
1535                     sal_uInt16 nAbsPos = lBullIndent;
1536                     sal_uInt16 nSpaceSteps = nLvl
1537                                             ? sal_uInt16(nLeftTxtPos / nLvl)
1538                                             : lBullIndent;
1539                     for( sal_uInt8 n = 0; n < MAXLEVEL; ++n, nAbsPos = nAbsPos + nSpaceSteps )
1540                     {
1541                         SwNumFmt aFmt( aRule.Get( n ) );
1542                         aFmt.SetBulletFont( pBullFnt );
1543                         aFmt.SetBulletChar( cBullChar );
1544                         aFmt.SetNumberingType(SVX_NUM_CHAR_SPECIAL);
1545                         // #i93908# clear suffix for bullet lists
1546                         aFmt.SetPrefix(::rtl::OUString());
1547                         aFmt.SetSuffix(::rtl::OUString());
1548                         aFmt.SetFirstLineOffset( lBullFirstLineOffset );
1549                         aFmt.SetAbsLSpace( nAbsPos );
1550                         if( !aFmt.GetCharFmt() )
1551                             aFmt.SetCharFmt( pCFmt );
1552                         if( bRTL )
1553                             aFmt.SetNumAdjust( SVX_ADJUST_RIGHT );
1554 
1555                         aRule.Set( n, aFmt );
1556 
1557                         if( n == nLvl &&
1558                             nFrmWidth < ( nSpaceSteps * MAXLEVEL ) )
1559                             nSpaceSteps = static_cast<sal_uInt16>(( nFrmWidth - nLeftTxtPos ) /
1560                                                 ( MAXLEVEL - nLvl ));
1561                     }
1562                 }
1563             }
1564         }
1565         else
1566         {
1567             bChgBullet = sal_True;
1568             SetColl( static_cast<sal_uInt16>(RES_POOLCOLL_BUL_LEVEL1 + ( Min( nLvl, cnNumBullColls ) * 4 )) );
1569         }
1570     }
1571     else
1572     {
1573         // dann ist das eine Nummerierung
1574 
1575         //JP 21.11.97: Der NumLevel wird entweder der DigitLevel oder
1576         //              wenn der nicht vorhanden oder 0 ist, durch den
1577         //              (Einrueckungs-)Level.
1578 
1579         String aPostFix, aPreFix, aNumTypes;
1580         if( USHRT_MAX != ( nDigitLevel = GetDigitLevel( *pAktTxtNd, nTxtStt,
1581                                         &aPreFix, &aPostFix, &aNumTypes )) )
1582         {
1583             bChgEnum = sal_True;
1584 
1585             // Ebene 0 und Einrueckung dann wird die Ebene durch den linken
1586             // Einzug und der default NumEinrueckung bestimmt.
1587             if( !nDigitLevel && nLeftTxtPos )
1588                 nLvl = Min( sal_uInt16( nLeftTxtPos / lNumIndent ),
1589                             sal_uInt16( MAXLEVEL - 1 ) );
1590             else
1591                 nLvl = nDigitLevel;
1592         }
1593 
1594         if( bChgEnum && aFlags.bSetNumRule )
1595         {
1596             if( !pCur )         // NumRule anpassen, wenn sie neu ist
1597             {
1598                 SwCharFmt* pCFmt = pDoc->GetCharFmtFromPool(
1599                                             RES_POOLCHR_NUM_LEVEL );
1600                 if( !nDigitLevel )
1601                 {
1602                     SwNumFmt aFmt( aRule.Get( nLvl ) );
1603                     aFmt.SetStart( static_cast<sal_uInt16>(aPreFix.GetToken( 1,
1604                                             (sal_Unicode)1 ).ToInt32()));
1605                     aFmt.SetPrefix( aPreFix.GetToken( 0, (sal_Unicode)1 ));
1606                     aFmt.SetSuffix( aPostFix.GetToken( 0, (sal_Unicode)1 ));
1607                     aFmt.SetIncludeUpperLevels( 0 );
1608 
1609                     if( !aFmt.GetCharFmt() )
1610                         aFmt.SetCharFmt( pCFmt );
1611 
1612                     if( aNumTypes.Len() )
1613                         aFmt.SetNumberingType(aNumTypes.GetChar( 0 ) - '0');
1614 
1615                     if( bRTL )
1616                         aFmt.SetNumAdjust( SVX_ADJUST_RIGHT );
1617                     aRule.Set( nLvl, aFmt );
1618                 }
1619                 else
1620                 {
1621                     sal_uInt16 nSpaceSteps = nLvl ? sal_uInt16(nLeftTxtPos / nLvl) : 0;
1622                     sal_uInt8 n;
1623                     for( n = 0; n <= nLvl; ++n )
1624                     {
1625                         SwNumFmt aFmt( aRule.Get( n ) );
1626 
1627                         aFmt.SetStart( static_cast<sal_uInt16>(aPreFix.GetToken( n+1,
1628                                                     (sal_Unicode)1 ).ToInt32() ));
1629                         if( !n )
1630                             aFmt.SetPrefix( aPreFix.GetToken( n, (sal_Unicode)1 ));
1631                         aFmt.SetSuffix( aPostFix.GetToken( n, (sal_Unicode)1 ));
1632                         aFmt.SetIncludeUpperLevels( MAXLEVEL );
1633                         if( n < aNumTypes.Len() )
1634                             aFmt.SetNumberingType((aNumTypes.GetChar( n ) - '0'));
1635 
1636                         aFmt.SetAbsLSpace( sal_uInt16( nSpaceSteps * n )
1637                                             + lNumIndent );
1638 
1639                         if( !aFmt.GetCharFmt() )
1640                             aFmt.SetCharFmt( pCFmt );
1641                         if( bRTL )
1642                             aFmt.SetNumAdjust( SVX_ADJUST_RIGHT );
1643 
1644                         aRule.Set( n, aFmt );
1645                     }
1646 
1647                     // passt alles vollstaendig in den Frame?
1648                     sal_Bool bDefStep = nFrmWidth < (nSpaceSteps * MAXLEVEL);
1649                     for( ; n < MAXLEVEL; ++n )
1650                     {
1651                         SwNumFmt aFmt( aRule.Get( n ) );
1652                         aFmt.SetIncludeUpperLevels( MAXLEVEL );
1653                         if( bDefStep )
1654                             aFmt.SetAbsLSpace( sal_uInt16( (nLeftTxtPos +
1655                                 SwNumRule::GetNumIndent(static_cast<sal_uInt8>(n-nLvl)))));
1656                         else
1657                             aFmt.SetAbsLSpace( sal_uInt16( nSpaceSteps * n )
1658                                                 + lNumIndent );
1659                         aRule.Set( n, aFmt );
1660                     }
1661                 }
1662             }
1663         }
1664         else if( !aFlags.bAFmtByInput )
1665             SetColl( static_cast<sal_uInt16>(RES_POOLCOLL_NUM_LEVEL1 + ( Min( nLvl, cnNumBullColls ) * 4 ) ));
1666         else
1667             bChgEnum = sal_False;
1668     }
1669 
1670     if( bChgEnum || bChgBullet )
1671     {
1672         aDelPam.DeleteMark();
1673         aDelPam.GetPoint()->nNode = aNdIdx;
1674 
1675         if( aFlags.bSetNumRule )
1676         {
1677             if( aFlags.bAFmtByInput )
1678             {
1679                 aDelPam.SetMark();
1680                 aDelPam.GetMark()->nNode++;
1681                 aDelPam.GetNode(sal_False)->GetTxtNode()->SetAttrListLevel( nLvl );
1682             }
1683 
1684             pAktTxtNd->SetAttrListLevel(nLvl);
1685             pAktTxtNd->SetNumLSpace( sal_True );
1686 
1687             // --> OD 2008-03-17 #refactorlists#
1688             // start new list
1689             pDoc->SetNumRule( aDelPam, aRule, true );
1690             // <--
1691             aDelPam.DeleteMark();
1692 
1693             aDelPam.GetPoint()->nContent.Assign( pAktTxtNd, 0 );
1694         }
1695         else
1696             aDelPam.GetPoint()->nContent.Assign( pAktTxtNd,
1697                         bChgEnum ? (nTxtStt - nOrigTxtStt) : 0 );
1698         aDelPam.SetMark();
1699 
1700         if( bChgBullet )
1701             nTxtStt += 2;
1702 
1703         while( nTxtStt < rStr.Len() && IsSpace( rStr.GetChar( nTxtStt ) ))
1704             nTxtStt++;
1705 
1706         aDelPam.GetPoint()->nContent = nTxtStt - nOrigTxtStt;
1707         DeleteSel( aDelPam );
1708 
1709         if( !aFlags.bSetNumRule )
1710         {
1711             String sChgStr( '\t' );
1712             if( bChgBullet )
1713                 sChgStr.Insert( aFlags.cBullet, 0 );
1714             pDoc->InsertString( aDelPam, sChgStr );
1715 
1716             SfxItemSet aSet( pDoc->GetAttrPool(), aTxtNodeSetRange );
1717             if( bChgBullet )
1718             {
1719                 aDelPam.GetPoint()->nContent = 0;
1720                 aDelPam.SetMark();
1721                 aDelPam.GetMark()->nContent = 1;
1722                 SetAllScriptItem( aSet,
1723                      SvxFontItem( aFlags.aBulletFont.GetFamily(),
1724                                   aFlags.aBulletFont.GetName(),
1725                                   aFlags.aBulletFont.GetStyleName(),
1726                                   aFlags.aBulletFont.GetPitch(),
1727                                   aFlags.aBulletFont.GetCharSet(),
1728                                   RES_CHRATR_FONT ) );
1729                 pDoc->SetFmtItemByAutoFmt( aDelPam, aSet );
1730                 aDelPam.DeleteMark();
1731                 nAutoCorrPos = 2;
1732                 aSet.ClearItem();
1733             }
1734             SvxTabStopItem aTStops( RES_PARATR_TABSTOP );    aTStops.Insert( SvxTabStop( 0 ));
1735             aSet.Put( aTStops );
1736             pDoc->SetFmtItemByAutoFmt( aDelPam, aSet );
1737         }
1738     }
1739 
1740     if( bBreak )
1741     {
1742         AutoCorrect( nAutoCorrPos );       /* Offset wegen Bullet + Tab */
1743         return;
1744     }
1745 
1746     const SwTxtNode* pNxtNd = GetNextNode();
1747     while( CanJoin( pNxtNd ) &&
1748             nLvl == CalcLevel( *pNxtNd ) )
1749     {
1750         SetRedlineTxt( STR_AUTOFMTREDL_DEL_MORELINES );
1751         bBreak = !IsFastFullLine( *pNxtNd ) || IsBlanksInString( *pNxtNd ) ||
1752                 IsSentenceAtEnd( *pNxtNd );
1753         if( DeleteAktNxtPara( pNxtNd->GetTxt() ) )
1754         {
1755             pDoc->InsertString( aDelPam, sal_Unicode(' ') );
1756         }
1757         if( bBreak )
1758             break;
1759         const SwTxtNode* pCurrNode = pNxtNd;
1760         pNxtNd = GetNextNode();
1761         if(!pNxtNd || pCurrNode == pNxtNd)
1762             break;
1763     }
1764     DeleteAktPara( sal_False, sal_True );
1765     AutoCorrect( nAutoCorrPos );
1766 }
1767 
1768 
1769 void SwAutoFormat::BuildNegIndent( SwTwips nSpaces )
1770 {
1771     SetRedlineTxt( STR_AUTOFMTREDL_SET_TMPL_NEG_INDENT );
1772     // Test auf Gegenueberstellung:
1773     // (n Worte, durch Space/Tabs getrennt, mit gleicher
1774     //   Einrueckung in der 2.Zeile)
1775 
1776     // lese alle nachfolgenden Absaetze die zu dieser Aufzaehlung gehoeren
1777     sal_Bool bBreak = sal_True;
1778     xub_StrLen nSpacePos, nTxtPos = GetBigIndent( nSpacePos );
1779     if( bMoreLines )
1780         DelMoreLinesBlanks( sal_True );
1781     else
1782         bBreak = !IsFastFullLine( *pAktTxtNd ) ||
1783                     ( !nTxtPos && IsBlanksInString( *pAktTxtNd )) ||
1784                     IsSentenceAtEnd( *pAktTxtNd );
1785 
1786     SetColl( static_cast<sal_uInt16>( nTxtPos
1787                 ? RES_POOLCOLL_CONFRONTATION
1788                 : RES_POOLCOLL_TEXT_NEGIDENT ) );
1789 
1790     if( nTxtPos )
1791     {
1792         const String& rStr = pAktTxtNd->GetTxt();
1793         sal_Bool bInsTab = sal_True;
1794 
1795         if( '\t' == rStr.GetChar( nSpacePos+1 ))       // ein Tab, das belassen wir
1796         {
1797             --nSpacePos;
1798             bInsTab = sal_False;
1799         }
1800 
1801         xub_StrLen nSpaceStt = nSpacePos;
1802         while( nSpaceStt && IsSpace( rStr.GetChar( --nSpaceStt ) ) )
1803             ;
1804         ++nSpaceStt;
1805 
1806         if( bInsTab && '\t' == rStr.GetChar( nSpaceStt ) )      // ein Tab, das belassen wir
1807         {
1808             ++nSpaceStt;
1809             bInsTab = sal_False;
1810         }
1811 
1812 
1813         aDelPam.DeleteMark();
1814         aDelPam.GetPoint()->nNode = aNdIdx;
1815         aDelPam.GetPoint()->nContent.Assign( pAktTxtNd, nSpacePos );
1816 
1817         // alten Spaces, usw. loeschen
1818         if( nSpaceStt < nSpacePos )
1819         {
1820             aDelPam.SetMark();
1821             aDelPam.GetMark()->nContent = nSpaceStt;
1822             DeleteSel( aDelPam );
1823             if( bInsTab )
1824             {
1825                 pDoc->InsertString( aDelPam, sal_Unicode('\t') );
1826             }
1827         }
1828     }
1829 
1830     if( !bBreak )
1831     {
1832         SetRedlineTxt( STR_AUTOFMTREDL_DEL_MORELINES );
1833         SwTxtFrmInfo aFInfo( pAktTxtFrm );
1834         const SwTxtNode* pNxtNd = GetNextNode();
1835         while(  CanJoin( pNxtNd ) &&
1836                 20 < Abs( (long)(nSpaces - aFInfo.SetFrm(
1837                                 GetFrm( *pNxtNd ) ).GetLineStart() ))
1838             )
1839         {
1840             bBreak = !IsFastFullLine( *pNxtNd ) ||
1841                     IsBlanksInString( *pNxtNd ) ||
1842                     IsSentenceAtEnd( *pNxtNd );
1843             if( DeleteAktNxtPara( pNxtNd->GetTxt() ) )
1844             {
1845                 pDoc->InsertString( aDelPam, sal_Unicode(' ') );
1846             }
1847             if( bBreak )
1848                 break;
1849             pNxtNd = GetNextNode();
1850         }
1851     }
1852     DeleteAktPara( sal_True, sal_True );
1853     AutoCorrect();
1854 }
1855 
1856 
1857 void SwAutoFormat::BuildHeadLine( sal_uInt16 nLvl )
1858 {
1859     if( aFlags.bWithRedlining )
1860     {
1861         String sTxt( *ViewShell::GetShellRes()->GetAutoFmtNameLst()[
1862                                     STR_AUTOFMTREDL_SET_TMPL_HEADLINE ] );
1863         sTxt.SearchAndReplace( String::CreateFromAscii(
1864                                     RTL_CONSTASCII_STRINGPARAM( "$(ARG1)" )),
1865                                 String::CreateFromInt32( nLvl + 1 ) );
1866         pDoc->SetAutoFmtRedlineComment( &sTxt );
1867     }
1868 
1869     SetColl( static_cast<sal_uInt16>(RES_POOLCOLL_HEADLINE1 + nLvl ), sal_True );
1870     if( aFlags.bAFmtByInput )
1871     {
1872         SwTxtFmtColl& rNxtColl = pAktTxtNd->GetTxtColl()->GetNextTxtFmtColl();
1873 
1874         DelPrevPara();
1875 
1876         DeleteAktPara( sal_True, sal_False );
1877         DeleteAktNxtPara( aEmptyStr );
1878 
1879         aDelPam.DeleteMark();
1880         aDelPam.GetPoint()->nNode = aNdIdx.GetIndex() + 1;
1881         aDelPam.GetPoint()->nContent.Assign( aDelPam.GetCntntNode(), 0 );
1882         pDoc->SetTxtFmtColl( aDelPam, &rNxtColl );
1883     }
1884     else
1885     {
1886         DeleteAktPara( sal_True, sal_True );
1887         AutoCorrect();
1888     }
1889 }
1890 
1891 
1892         // dann lasse doch mal das AutoCorrect auf den akt. TextNode los
1893 void SwAutoFormat::AutoCorrect( xub_StrLen nPos )
1894 {
1895     SvxAutoCorrect* pATst = SvxAutoCorrCfg::Get()->GetAutoCorrect();
1896     long aSvxFlags = pATst->GetFlags( );
1897     bool bReplaceQuote = ( aSvxFlags & ChgQuotes ) > 0;
1898     bool bReplaceSglQuote = ( aSvxFlags & ChgSglQuotes ) > 0;
1899 
1900     if( aFlags.bAFmtByInput ||
1901         (!aFlags.bAutoCorrect && !bReplaceQuote && !bReplaceSglQuote &&
1902         !aFlags.bCptlSttSntnc && !aFlags.bCptlSttWrd &&
1903         !aFlags.bChgOrdinalNumber &&
1904         !aFlags.bChgToEnEmDash && !aFlags.bSetINetAttr &&
1905         !aFlags.bChgWeightUnderl && !aFlags.bAddNonBrkSpace) )
1906         return;
1907 
1908     const String* pTxt = &pAktTxtNd->GetTxt();
1909     if( nPos >= pTxt->Len() )
1910         return;
1911 
1912     sal_Bool bGetLanguage = aFlags.bChgOrdinalNumber ||
1913                         aFlags.bChgToEnEmDash || aFlags.bSetINetAttr ||
1914                         aFlags.bCptlSttWrd || aFlags.bCptlSttSntnc ||
1915                         aFlags.bAddNonBrkSpace;
1916 
1917 
1918     aDelPam.DeleteMark();
1919     aDelPam.GetPoint()->nNode = aNdIdx;
1920     aDelPam.GetPoint()->nContent.Assign( pAktTxtNd, 0 );
1921 
1922     SwAutoCorrDoc aACorrDoc( *pEditShell, aDelPam );
1923 
1924     SwTxtFrmInfo aFInfo( 0 );
1925 
1926     xub_StrLen nSttPos, nLastBlank = nPos;
1927     sal_Bool bFirst = aFlags.bCptlSttSntnc, bFirstSent = bFirst;
1928     sal_Unicode cChar = 0;
1929 
1930     CharClass& rAppCC = GetAppCharClass();
1931 
1932     do {
1933         while( nPos < pTxt->Len() && IsSpace( cChar = pTxt->GetChar( nPos ) ))
1934             ++nPos;
1935         if( nPos == pTxt->Len() )
1936             break;      // das wars
1937 
1938         if( ( ( bReplaceQuote && '\"' == cChar ) ||
1939               ( bReplaceSglQuote && '\'' == cChar ) ) &&
1940             ( !nPos || ' ' == pTxt->GetChar( nPos-1 ) ) )
1941         {
1942             // --------------------------------------
1943             // beachte: Sonderfall Symbolfonts !!!
1944             if( !aFInfo.GetFrm() )
1945                 aFInfo.SetFrm( GetFrm( *pAktTxtNd ) );
1946             if( !aFInfo.IsBullet( nPos ))
1947             {
1948                 SetRedlineTxt( STR_AUTOFMTREDL_TYPO );
1949                 aDelPam.GetPoint()->nContent = nPos;
1950                 sal_Bool bSetHardBlank = sal_False;
1951 
1952                 String sReplace( pATst->GetQuote( aACorrDoc,
1953                                     nPos, cChar, sal_True ));
1954 
1955                 aDelPam.SetMark();
1956                 aDelPam.GetPoint()->nContent = nPos+1;
1957                 if( 2 == sReplace.Len() && ' ' == sReplace.GetChar( 1 ))
1958                 {
1959                     sReplace.Erase( 1 );
1960                     bSetHardBlank = sal_True;
1961                 }
1962                 pDoc->ReplaceRange( aDelPam, sReplace, false );
1963 
1964                 if( aFlags.bWithRedlining )
1965                 {
1966                     aNdIdx = aDelPam.GetPoint()->nNode;
1967                     pAktTxtNd = aNdIdx.GetNode().GetTxtNode();
1968                     pTxt = &pAktTxtNd->GetTxt();
1969                     aDelPam.SetMark();
1970                     aFInfo.SetFrm( 0 );
1971                 }
1972 
1973                 nPos += sReplace.Len() - 1;
1974                 aDelPam.DeleteMark();
1975                 if( bSetHardBlank )
1976                 {
1977                     pDoc->InsertString( aDelPam, CHAR_HARDBLANK );
1978                     ++nPos;
1979                 }
1980             }
1981         }
1982 
1983         int bCallACorr = sal_False;
1984         int bBreak = 0;
1985         if( nPos && IsSpace( pTxt->GetChar( nPos-1 )))
1986             nLastBlank = nPos;
1987         for( nSttPos = nPos; !bBreak && nPos < pTxt->Len(); ++nPos )
1988             switch( cChar = pTxt->GetChar( nPos ) )
1989             {
1990             case '\"':
1991             case '\'':
1992                 if( ( cChar == '\"' && bReplaceQuote ) || ( cChar == '\'' && bReplaceSglQuote ) )
1993                 {
1994                     // --------------------------------------
1995                     // beachte: Sonderfall Symbolfonts !!!
1996                     if( !aFInfo.GetFrm() )
1997                         aFInfo.SetFrm( GetFrm( *pAktTxtNd ) );
1998                     if( !aFInfo.IsBullet( nPos ))
1999                     {
2000                         SetRedlineTxt( STR_AUTOFMTREDL_TYPO );
2001                         sal_Bool bSetHardBlank = sal_False;
2002                         aDelPam.GetPoint()->nContent = nPos;
2003                         String sReplace( pATst->GetQuote( aACorrDoc,
2004                                                     nPos, cChar, sal_False ));
2005 
2006                         if( 2 == sReplace.Len() && ' ' == sReplace.GetChar( 0 ))
2007                         {
2008                             sReplace.Erase( 0, 1 );
2009                             bSetHardBlank = sal_True;
2010                         }
2011 
2012                         aDelPam.SetMark();
2013                         aDelPam.GetPoint()->nContent = nPos+1;
2014                         pDoc->ReplaceRange( aDelPam, sReplace, false );
2015 
2016                         if( aFlags.bWithRedlining )
2017                         {
2018                             aNdIdx = aDelPam.GetPoint()->nNode;
2019                             pAktTxtNd = aNdIdx.GetNode().GetTxtNode();
2020                             pTxt = &pAktTxtNd->GetTxt();
2021                             aDelPam.SetMark();
2022                             aDelPam.DeleteMark();
2023                             aFInfo.SetFrm( 0 );
2024                         }
2025 
2026                         nPos += sReplace.Len() - 1;
2027                         aDelPam.DeleteMark();
2028 
2029                         if( bSetHardBlank )
2030                         {
2031                             aDelPam.GetPoint()->nContent = nPos;
2032                             pDoc->InsertString( aDelPam, CHAR_HARDBLANK );
2033                             aDelPam.GetPoint()->nContent = ++nPos;
2034                         }
2035                     }
2036                 }
2037                 break;
2038             case '*':
2039             case '_':
2040                 if( aFlags.bChgWeightUnderl )
2041                 {
2042                     // --------------------------------------
2043                     // beachte: Sonderfall Symbolfonts !!!
2044                     if( !aFInfo.GetFrm() )
2045                         aFInfo.SetFrm( GetFrm( *pAktTxtNd ) );
2046                     if( !aFInfo.IsBullet( nPos ))
2047                     {
2048                         SetRedlineTxt( '*' == cChar
2049                                             ? STR_AUTOFMTREDL_BOLD
2050                                             : STR_AUTOFMTREDL_UNDER );
2051 
2052                         sal_Unicode cBlank = nSttPos ? pTxt->GetChar(nSttPos - 1) : 0;
2053                         aDelPam.GetPoint()->nContent = nPos;
2054 
2055                         if( pATst->FnChgWeightUnderl( aACorrDoc, *pTxt,
2056                                                             nSttPos, nPos ))
2057                         {
2058                             if( aFlags.bWithRedlining )
2059                             {
2060                                 aNdIdx = aDelPam.GetPoint()->nNode;
2061                                 pAktTxtNd = aNdIdx.GetNode().GetTxtNode();
2062                                 pTxt = &pAktTxtNd->GetTxt();
2063                                 aDelPam.SetMark();
2064                                 aDelPam.DeleteMark();
2065                                 aFInfo.SetFrm( 0 );
2066                             }
2067                             //#125102# in case of the mode REDLINE_SHOW_DELETE the ** are still contained in pTxt
2068                             if(0 == (pDoc->GetRedlineMode() & nsRedlineMode_t::REDLINE_SHOW_DELETE))
2069                                 nPos = aDelPam.GetPoint()->nContent.GetIndex() - 1;
2070                             // wurde vorm Start ein Zeichen entfernt?
2071                             if( cBlank && cBlank != pTxt->GetChar(nSttPos - 1) )
2072                                 --nSttPos;
2073                         }
2074                     }
2075                 }
2076                 break;
2077             case '/':
2078                 if ( aFlags.bAddNonBrkSpace )
2079                 {
2080                     LanguageType eLang = (bGetLanguage && pAktTxtNd)
2081                                            ? pAktTxtNd->GetLang( nSttPos )
2082                                            : LANGUAGE_SYSTEM;
2083 
2084                     SetRedlineTxt( STR_AUTOFMTREDL_NON_BREAK_SPACE );
2085                     if ( pATst->FnAddNonBrkSpace( aACorrDoc, *pTxt, nSttPos, nPos, eLang ) )
2086                         --nPos;
2087                 }
2088                 break;
2089 
2090             case '.':
2091             case '!':
2092             case '?':
2093                 if( aFlags.bCptlSttSntnc )
2094                     bFirstSent = sal_True;
2095 //alle Wortrenner loesen die Autokorrektur aus!
2096 //              break;
2097             default:
2098 //alle Wortrenner loesen die Autokorrektur aus!
2099 //          case ' ':
2100 //          case '\t':
2101                 if( !( rAppCC.isLetterNumeric( *pTxt, nPos )
2102                         || '/' == cChar )) //  '/' should not be a word seperator (e.g. '1/2' needs to be handled as one word for replacement)
2103                 {
2104                     --nPos;     // ++nPos von dem for ungueltig machen !
2105                     ++bBreak;
2106                 }
2107                 break;
2108             }
2109 
2110         if( nPos == nSttPos )
2111         {
2112             if( ++nPos == pTxt->Len() )
2113                 bCallACorr = sal_True;
2114         }
2115         else
2116             bCallACorr = sal_True;
2117 
2118 
2119         if( bCallACorr )
2120         {
2121             bCallACorr = sal_False;
2122             aDelPam.GetPoint()->nContent = nPos;
2123             SetRedlineTxt( STR_AUTOFMTREDL_USE_REPLACE );
2124             if( aFlags.bAutoCorrect &&
2125                 aACorrDoc.ChgAutoCorrWord( nSttPos, nPos, *pATst, 0 ) )
2126             {
2127                 nPos = aDelPam.GetPoint()->nContent.GetIndex();
2128 
2129                 if( aFlags.bWithRedlining )
2130                 {
2131                     aNdIdx = aDelPam.GetPoint()->nNode;
2132                     pAktTxtNd = aNdIdx.GetNode().GetTxtNode();
2133                     pTxt = &pAktTxtNd->GetTxt();
2134                     aDelPam.SetMark();
2135                     aDelPam.DeleteMark();
2136                 }
2137 
2138                 continue;       // nichts weiter mehr abpruefen
2139             }
2140 
2141             LanguageType eLang = (bGetLanguage && pAktTxtNd)
2142                                            ? pAktTxtNd->GetLang( nSttPos )
2143                                            : LANGUAGE_SYSTEM;
2144 
2145             if ( aFlags.bAddNonBrkSpace )
2146             {
2147                 SetRedlineTxt( STR_AUTOFMTREDL_NON_BREAK_SPACE );
2148                 pATst->FnAddNonBrkSpace( aACorrDoc, *pTxt, nSttPos, nPos, eLang );
2149             }
2150 
2151             if( ( aFlags.bChgOrdinalNumber &&
2152                     SetRedlineTxt( STR_AUTOFMTREDL_ORDINAL ) &&
2153                     pATst->FnChgOrdinalNumber( aACorrDoc, *pTxt, nSttPos, nPos, eLang ) ) ||
2154                 ( aFlags.bChgToEnEmDash &&
2155                     SetRedlineTxt( STR_AUTOFMTREDL_DASH ) &&
2156                     pATst->FnChgToEnEmDash( aACorrDoc, *pTxt, nSttPos, nPos, eLang ) ) ||
2157                 ( aFlags.bSetINetAttr &&
2158                     ( nPos == pTxt->Len() || IsSpace( pTxt->GetChar( nPos )) ) &&
2159                     SetRedlineTxt( STR_AUTOFMTREDL_DETECT_URL ) &&
2160                     pATst->FnSetINetAttr( aACorrDoc, *pTxt, nLastBlank, nPos, eLang ) ) )
2161                     nPos = aDelPam.GetPoint()->nContent.GetIndex();
2162             else
2163             {
2164                 // Zwei Grossbuchstaben am Wort-Anfang ??
2165                 if( aFlags.bCptlSttWrd )
2166                 {
2167                     SetRedlineTxt( STR_AUTOFMTREDL_CPTL_STT_WORD );
2168                     pATst->FnCptlSttWrd( aACorrDoc, *pTxt, nSttPos, nPos, eLang );
2169                 }
2170                 // Grossbuchstabe am Satz-Anfang ??
2171                 if( aFlags.bCptlSttSntnc && bFirst )
2172                 {
2173                     SetRedlineTxt( STR_AUTOFMTREDL_CPTL_STT_SENT );
2174                     pATst->FnCptlSttSntnc( aACorrDoc, *pTxt, sal_True, nSttPos, nPos, eLang);
2175                     bFirst = sal_False;
2176                 }
2177 
2178                 bFirst = bFirstSent;
2179                 bFirstSent = sal_False;
2180 
2181                 if( aFlags.bWithRedlining )
2182                 {
2183                     aNdIdx = aDelPam.GetPoint()->nNode;
2184                     pAktTxtNd = aNdIdx.GetNode().GetTxtNode();
2185                     pTxt = &pAktTxtNd->GetTxt();
2186                     aDelPam.SetMark();
2187                     aDelPam.DeleteMark();
2188                 }
2189             }
2190         }
2191     } while( nPos < pTxt->Len() );
2192     ClearRedlineTxt();
2193 }
2194 
2195 
2196 SwAutoFormat::SwAutoFormat( SwEditShell* pEdShell, SvxSwAutoFmtFlags& rFlags,
2197                             SwNodeIndex* pSttNd, SwNodeIndex* pEndNd )
2198     : aFlags( rFlags ),
2199     aDelPam( pEdShell->GetDoc()->GetNodes().GetEndOfExtras() ),
2200     aNdIdx( pEdShell->GetDoc()->GetNodes().GetEndOfExtras(), +1 ),
2201     aEndNdIdx( pEdShell->GetDoc()->GetNodes().GetEndOfContent() ),
2202     pEditShell( pEdShell ),
2203     pDoc( pEdShell->GetDoc() ),
2204     pAktTxtNd( 0 ), pAktTxtFrm( 0 ),
2205     pCharClass( 0 ),
2206     nRedlAutoFmtSeqId( 0 )
2207 {
2208     ASSERT( (pSttNd && pEndNd) || (!pSttNd && !pEndNd),
2209             "Kein Bereich angegeben" );
2210 
2211     if( aFlags.bSetNumRule && !aFlags.bAFmtByInput )
2212         aFlags.bSetNumRule = sal_False;
2213 
2214     sal_Bool bReplaceStyles = !aFlags.bAFmtByInput || aFlags.bReplaceStyles;
2215 
2216     const SwTxtNode* pNxtNd = 0;
2217     sal_Bool bNxtEmpty = sal_False;
2218     sal_Bool bNxtAlpha = sal_False;
2219     sal_uInt16 nNxtLevel = 0;
2220 
2221     // setze den Bereich zum Autoformatieren
2222     if( pSttNd )
2223     {
2224         aNdIdx = *pSttNd;
2225         aNdIdx--;           // fuer GoNextPara, ein Absatz davor
2226         aEndNdIdx = *pEndNd;
2227         aEndNdIdx++;
2228 
2229         // teste den vorhergehenden TextNode
2230         pNxtNd = aNdIdx.GetNode().GetTxtNode();
2231         bEmptyLine = !pNxtNd ||
2232                     IsEmptyLine( *pNxtNd ) ||
2233                     IsNoAlphaLine( *pNxtNd );
2234     }
2235     else
2236         bEmptyLine = sal_True;      // am Dokument Anfang
2237 
2238     bEnde = sal_False;
2239 
2240     // setze die Werte fuer die Prozent-Anzeige
2241     nEndNdIdx = aEndNdIdx.GetIndex();
2242 
2243     if( !aFlags.bAFmtByInput )
2244         ::StartProgress( STR_STATSTR_AUTOFORMAT, aNdIdx.GetIndex(),
2245                          nEndNdIdx = aEndNdIdx.GetIndex(),
2246                          pDoc->GetDocShell() );
2247 
2248     RedlineMode_t eRedlMode = pDoc->GetRedlineMode(), eOldMode = eRedlMode;
2249     if( aFlags.bWithRedlining )
2250     {
2251         pDoc->SetAutoFmtRedline( sal_True );
2252         eRedlMode = (RedlineMode_t)(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_SHOW_INSERT);
2253     }
2254     else
2255       eRedlMode = (RedlineMode_t)(nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_IGNORE);
2256     pDoc->SetRedlineMode( eRedlMode );
2257 
2258     // save undo state (might be turned off)
2259     bool const bUndoState = pDoc->GetIDocumentUndoRedo().DoesUndo();
2260 
2261     // wenn mehrere Zeilen, dann erstmal nicht mit
2262     // dem nachfolgenden Absatz zusammenfassen.
2263     bMoreLines = sal_False;
2264 
2265     nLastCalcHeadLvl = nLastCalcEnumLvl = 0;
2266     nLastHeadLvl = nLastEnumLvl = USHRT_MAX;
2267     sal_uInt16 nLevel = 0;
2268     sal_uInt16 nDigitLvl = 0;
2269 
2270     // defaulten
2271     SwTxtFrmInfo aFInfo( 0 );
2272 
2273     // das ist unser Automat fuer die Auto-Formatierung
2274     eStat = READ_NEXT_PARA;
2275     while( !bEnde )
2276     {
2277         switch( eStat )
2278         {
2279         case READ_NEXT_PARA:
2280             {
2281                 GoNextPara();
2282                 eStat = bEnde ? IS_ENDE : TST_EMPTY_LINE;
2283             }
2284             break;
2285 
2286         case TST_EMPTY_LINE:
2287             if( IsEmptyLine( *pAktTxtNd ) )
2288             {
2289                 if( aFlags.bDelEmptyNode && !HasObjects( *pAktTxtNd ) )
2290                 {
2291                     bEmptyLine = sal_True;
2292                     sal_uLong nOldCnt = pDoc->GetNodes().Count();
2293                     DelEmptyLine();
2294                     // wurde wiklich ein Node geloescht ?
2295                     if( nOldCnt != pDoc->GetNodes().Count() )
2296                         aNdIdx--;       // nicht den naechsten Absatz ueberspringen
2297                 }
2298                 eStat = READ_NEXT_PARA;
2299             }
2300             else
2301                 eStat = TST_ALPHA_LINE;
2302             break;
2303 
2304         case TST_ALPHA_LINE:
2305             if( IsNoAlphaLine( *pAktTxtNd ))
2306             {
2307                 // erkenne eine Tabellendefinition +---+---+
2308                 if( aFlags.bAFmtByInput && aFlags.bCreateTable && DoTable() )
2309                 {
2310                     //JP 30.09.96: das DoTable() verlaesst sich auf das
2311                     //              Pop und Move - Crsr nach dem AutoFormat!
2312                     pEdShell->Pop( sal_False );
2313                     *pEdShell->GetCrsr() = aDelPam;
2314                     pEdShell->Push();
2315 
2316                     eStat = IS_ENDE;
2317                     break;
2318                 }
2319 
2320                 // dann teste mal auf 3 "---" oder "===". In dem Fall
2321                 // soll der vorherige Absatz unterstrichen und dieser
2322                 // geloescht werden!
2323                 if( !DoUnderline() && bReplaceStyles )
2324                 {
2325                     SetColl( RES_POOLCOLL_STANDARD, sal_True );
2326                     bEmptyLine = sal_True;
2327                 }
2328                 eStat = READ_NEXT_PARA;
2329             }
2330             else
2331                 eStat = GET_ALL_INFO;
2332             break;
2333 
2334         case GET_ALL_INFO:
2335             {
2336                 if( pAktTxtNd->GetNumRule() )
2337                 {
2338                     // in Numerierung nichts machen, zum naechsten
2339                     bEmptyLine = sal_False;
2340                     eStat = READ_NEXT_PARA;
2341                     // loesche alle Blanks am Anfang/Ende
2342                     // und alle mitten drin
2343                     //JP 29.04.98: erstmal nur alle "mitten drin".
2344                     DelMoreLinesBlanks( sal_False );
2345                     break;
2346                 }
2347 
2348                 aFInfo.SetFrm( pAktTxtFrm );
2349 
2350                 // erstmal: wurden schon mal entsprechende Vorlagen
2351                 //          vergeben, so behalte die bei, gehe zum
2352                 //          naechsten Node.
2353                 sal_uInt16 nPoolId = pAktTxtNd->GetTxtColl()->GetPoolFmtId();
2354                 if( IsPoolUserFmt( nPoolId )
2355                         ? !aFlags.bChgUserColl
2356                         : ( RES_POOLCOLL_STANDARD != nPoolId &&
2357                            ( !aFlags.bAFmtByInput ||
2358                             (RES_POOLCOLL_TEXT_MOVE != nPoolId &&
2359                              RES_POOLCOLL_TEXT != nPoolId )) ))
2360                 {
2361                     eStat = HAS_FMTCOLL;
2362                     break;
2363                 }
2364 
2365                 // teste auf Harte oder aus Vorlagen gesetzte LRSpaces
2366                 if( IsPoolUserFmt( nPoolId ) ||
2367                     RES_POOLCOLL_STANDARD == nPoolId )
2368                 {
2369                     short nSz;
2370                     SvxLRSpaceItem* pLRSpace;
2371                     if( SFX_ITEM_SET == pAktTxtNd->GetSwAttrSet().
2372                         GetItemState( RES_LR_SPACE, sal_True,
2373                                         (const SfxPoolItem**)&pLRSpace ) &&
2374                         ( 0 != (nSz = pLRSpace->GetTxtFirstLineOfst()) ||
2375                             0 != pLRSpace->GetTxtLeft() ) )
2376                     {
2377                         // Ausnahme: Numerierun/Aufzaehlung kann mit Einzug
2378                         //      existieren!!
2379                         if( IsEnumericChar( *pAktTxtNd ))
2380                         {
2381                             nLevel = CalcLevel( *pAktTxtNd, &nDigitLvl );
2382                             if( nLevel >= MAXLEVEL )
2383                                 nLevel = MAXLEVEL-1;
2384                             BuildEnum( nLevel, nDigitLvl );
2385                             eStat = READ_NEXT_PARA;
2386                             break;
2387                         }
2388 
2389 
2390                         // nie zusammenfassen, so belassen
2391                         // (Opt. vielleicht als Ausnahmen nur Einzug)
2392                         bMoreLines = sal_True;
2393 
2394                         if( bReplaceStyles )
2395                         {
2396                             // dann setze doch eine unserer Vorlagen
2397                             if( 0 < nSz )           // positiver 1. Zeileneinzug
2398                                 BuildIndent();
2399                             else if( 0 > nSz )      // negativer 1. Zeileneinzug
2400                                 BuildNegIndent( aFInfo.GetLineStart() );
2401                             else if( pLRSpace->GetTxtLeft() )   // ist ein Einzug
2402                                 BuildTextIndent();
2403                         }
2404                         eStat = READ_NEXT_PARA;
2405                         break;
2406                     }
2407                 }
2408 
2409                 nLevel = CalcLevel( *pAktTxtNd, &nDigitLvl );
2410                 bMoreLines = !IsOneLine( *pAktTxtNd );
2411                 pNxtNd = GetNextNode();
2412                 if( pNxtNd )
2413                 {
2414                     bNxtEmpty = IsEmptyLine( *pNxtNd );
2415                     bNxtAlpha = IsNoAlphaLine( *pNxtNd );
2416                     nNxtLevel = CalcLevel( *pNxtNd );
2417 
2418                     if( !bEmptyLine && HasBreakAttr( *pAktTxtNd ) )
2419                         bEmptyLine = sal_True;
2420                     if( !bNxtEmpty && HasBreakAttr( *pNxtNd ) )
2421                         bNxtEmpty = sal_True;
2422 
2423                     // fuer z.B. selbst definierte Einzuege oder
2424                     // rechts/zentierte Ausrichtung
2425 //                  if( !nLevel && 0 != aFInfo.GetLineStart() )
2426 //                      nLevel = 1;
2427                 }
2428                 else
2429                 {
2430                     bNxtEmpty = sal_False; // sal_True;
2431                     bNxtAlpha = sal_False;
2432                     nNxtLevel = 0;
2433                 }
2434                 eStat = !bMoreLines ? IS_ONE_LINE : TST_ENUMERIC;
2435             }
2436             break;
2437 
2438         case IS_ONE_LINE:
2439             {
2440                 eStat = TST_ENUMERIC;
2441                 if( !bReplaceStyles )
2442                     break;
2443 
2444                 String sClrStr( pAktTxtNd->GetTxt() );
2445 
2446                 if( !DelLeadingBlanks( sClrStr ).Len() )
2447                 {
2448                     bEmptyLine = sal_True;
2449                     eStat = READ_NEXT_PARA;
2450                     break;      // naechsten Absatz lesen
2451                 }
2452 
2453                 // Teste auf Ueberschrift
2454                 if( !bEmptyLine || !IsFirstCharCapital( *pAktTxtNd ) ||
2455                     IsBlanksInString( *pAktTxtNd ) )
2456                     break;
2457 
2458                 bEmptyLine = sal_False;
2459                 String sEndClrStr( sClrStr );
2460                 xub_StrLen nLen = DelTrailingBlanks( sEndClrStr ).Len();
2461 
2462                 // nicht, dann teste auf Ueberschrift
2463                 if( ':' == sEndClrStr.GetChar( nLen - 1 ) )
2464                 {
2465 //---------------------------------------------------------------------------
2466 // Wie ist denn nun die Bedingung fuer die Ueberschrift auf Ebene 3 ??
2467 // Zur Zeit: generell wenn am Ende ein ':' ist.
2468 //
2469 //                  if( bNxtEmpty || bNxtAlpha )
2470 //                      !IsEnumericChar( *pNxtNd ) )
2471 //---------------------------------------------------------------------------
2472                     {
2473                         BuildHeadLine( 2 );
2474                         eStat = READ_NEXT_PARA;
2475                         break;
2476                     }
2477                 }
2478                 else if( 256 <= sEndClrStr.GetChar( nLen-1 ) ||
2479                          !strchr( ",.;", sEndClrStr.GetChar( nLen-1 )) )
2480                 {
2481                     if( bNxtEmpty || bNxtAlpha
2482                         || ( pNxtNd && IsEnumericChar( *pNxtNd ))
2483 
2484 //---------------------------------------------------------------------------
2485 // ist zum Verwechseln mit neg. Einzug !!
2486                         /*|| nLevel < nNxtLevel*/
2487 //---------------------------------------------------------------------------
2488 
2489                         )
2490                     {
2491                         // wurde Level vom Text vorgegeben ?
2492 //                      if( USHRT_MAX != nDigitLvl )
2493 //                          nLevel = nDigitLvl;
2494 
2495                         // eine Ebene runter ?
2496                         if( nLevel >= MAXLEVEL )
2497                             nLevel = MAXLEVEL-1;
2498 
2499                         if( USHRT_MAX == nLastHeadLvl )
2500                             nLastHeadLvl = 0;
2501                         else if( nLastCalcHeadLvl < nLevel )
2502                         {
2503                             if( nLastHeadLvl+1 < MAXLEVEL )
2504                                 ++nLastHeadLvl;
2505                         }
2506                         // eine Ebene hoch ?
2507                         else if( nLastCalcHeadLvl > nLevel )
2508                         {
2509                             if( nLastHeadLvl )
2510                                 --nLastHeadLvl;
2511                         }
2512                         nLastCalcHeadLvl = nLevel;
2513 
2514                         if( aFlags.bAFmtByInput )
2515                             BuildHeadLine( nLevel );
2516                         else
2517                             BuildHeadLine( nLastHeadLvl );
2518                         eStat = READ_NEXT_PARA;
2519                         break;
2520                     }
2521                 }
2522             }
2523             break;
2524 
2525         case TST_ENUMERIC:
2526             {
2527                 bEmptyLine = sal_False;
2528                 if( IsEnumericChar( *pAktTxtNd ))
2529                 {
2530                     if( nLevel >= MAXLEVEL )
2531                         nLevel = MAXLEVEL-1;
2532                     BuildEnum( nLevel, nDigitLvl );
2533                     eStat = READ_NEXT_PARA;
2534                 }
2535 //JP 25.03.96: Vorlagen fuer Einzug zulassen
2536 //              else if( aFlags.bAFmtByInput )
2537 //                  eStat = READ_NEXT_PARA;
2538                 else if( bReplaceStyles )
2539                     eStat = nLevel ? TST_IDENT : TST_NEG_IDENT;
2540                 else
2541                     eStat = READ_NEXT_PARA;
2542             }
2543             break;
2544 
2545         case TST_IDENT:
2546             // Spaces am Anfang, dann teste doch mal auf Einzuege
2547             if( bMoreLines && nLevel )
2548             {
2549                 SwTwips nSz = aFInfo.GetFirstIndent();
2550                 if( 0 < nSz )           // positiver 1. Zeileneinzug
2551                     BuildIndent();
2552                 else if( 0 > nSz )      // negativer 1. Zeileneinzug
2553                     BuildNegIndent( aFInfo.GetLineStart() );
2554                 else                    // ist ein Einzug
2555                     BuildTextIndent();
2556                 eStat = READ_NEXT_PARA;
2557             }
2558             else if( nLevel && pNxtNd && !bEnde &&
2559                      !bNxtEmpty && !bNxtAlpha && !nNxtLevel &&
2560                      !IsEnumericChar( *pNxtNd ) )
2561             {
2562                 // ist ein Einzug
2563                 BuildIndent();
2564                 eStat = READ_NEXT_PARA;
2565             }
2566             else
2567                 eStat = TST_TXT_BODY;
2568             break;
2569 
2570         case TST_NEG_IDENT:
2571             // keine Spaces am Anfang, dann teste doch mal auf neg. Einzuege
2572             {
2573                 if( bMoreLines && !nLevel )
2574                 {
2575                     SwTwips nSz = aFInfo.GetFirstIndent();
2576                     if( 0 < nSz )           // positiver 1. Zeileneinzug
2577                         BuildIndent();
2578                     else if( 0 > nSz )      // negativer 1. Zeileneinzug
2579                         BuildNegIndent( aFInfo.GetLineStart() );
2580                     else                    // ist ein kein Einzug
2581                         BuildText();
2582                     eStat = READ_NEXT_PARA;
2583                 }
2584                 else if( !nLevel && pNxtNd && !bEnde &&
2585                          !bNxtEmpty && !bNxtAlpha && nNxtLevel &&
2586                          !IsEnumericChar( *pNxtNd ) )
2587                 {
2588                     // ist ein neg. Einzug
2589                     BuildNegIndent( aFInfo.GetLineStart() );
2590                     eStat = READ_NEXT_PARA;
2591                 }
2592                 else
2593                     eStat = TST_TXT_BODY;
2594             }
2595             break;
2596 
2597         case TST_TXT_BODY:
2598             {
2599                 if( bMoreLines )
2600                 {
2601                     SwTwips nSz = aFInfo.GetFirstIndent();
2602                     if( 0 < nSz )           // positiver 1. Zeileneinzug
2603                         BuildIndent();
2604                     else if( 0 > nSz )      // negativer 1. Zeileneinzug
2605                         BuildNegIndent( aFInfo.GetLineStart() );
2606                     else if( nLevel )       // ist ein Einzug
2607                         BuildTextIndent();
2608                     else
2609                         BuildText();
2610                 }
2611                 else if( nLevel )
2612                     BuildTextIndent();
2613                 else
2614                     BuildText();
2615                 eStat = READ_NEXT_PARA;
2616             }
2617             break;
2618 
2619         case HAS_FMTCOLL:
2620             {
2621                 // erstmal: wurden schon mal entsprechende Vorlagen
2622                 //          vergeben, so behalte die bei, gehe zum
2623                 //          naechsten Node.
2624                 bEmptyLine = sal_False;
2625                 eStat = READ_NEXT_PARA;
2626                 // loesche alle Blanks am Anfang/Ende
2627                 // und alle mitten drin
2628                 //JP 29.04.98: erstmal nur alle "mitten drin".
2629                 DelMoreLinesBlanks( sal_False );
2630 
2631                 // behandel die harte Attributierung
2632                 if( pAktTxtNd->HasSwAttrSet() )
2633                 {
2634                     short nSz;
2635                     SvxLRSpaceItem* pLRSpace;
2636                     if( bReplaceStyles &&
2637                         SFX_ITEM_SET == pAktTxtNd->GetSwAttrSet().
2638                         GetItemState( RES_LR_SPACE, sal_False,
2639                                         (const SfxPoolItem**)&pLRSpace ) &&
2640                         ( 0 != (nSz = pLRSpace->GetTxtFirstLineOfst()) ||
2641                             0 != pLRSpace->GetTxtLeft() ) )
2642                     {
2643                         // dann setze doch eine unserer Vorlagen
2644                         if( 0 < nSz )           // positiver 1. Zeileneinzug
2645                             BuildIndent();
2646                         else if( 0 > nSz )      // negativer 1. Zeileneinzug
2647                         {
2648                             BuildNegIndent( aFInfo.GetLineStart() );
2649                         }
2650                         else if( pLRSpace->GetTxtLeft() )   // ist ein Einzug
2651                             BuildTextIndent();
2652                         else
2653                             BuildText();
2654                     }
2655                 }
2656             }
2657             break;
2658 
2659         case IS_ENDE:
2660             bEnde = sal_True;
2661             break;
2662         }
2663     }
2664 
2665     if( aFlags.bWithRedlining )
2666         pDoc->SetAutoFmtRedline( sal_False );
2667     pDoc->SetRedlineMode( eOldMode );
2668 
2669     // restore undo (in case it has been changed)
2670     pDoc->GetIDocumentUndoRedo().DoUndo(bUndoState);
2671 
2672     // Prozent-Anzeige wieder abschalten
2673     if( !aFlags.bAFmtByInput )
2674         ::EndProgress( pDoc->GetDocShell() );
2675 }
2676 
2677 void SwEditShell::AutoFormat( const SvxSwAutoFmtFlags* pAFlags )
2678 {
2679     SwWait* pWait = 0;
2680 
2681     SET_CURR_SHELL( this );
2682     StartAllAction();
2683     StartUndo( UNDO_AUTOFORMAT );
2684 
2685     SvxSwAutoFmtFlags aAFFlags;     // erst mal default - Werte
2686     if( pAFlags )                   // oder doch angegeben ??
2687     {
2688         aAFFlags = *pAFlags;
2689         if( !aAFFlags.bAFmtByInput )
2690             pWait = new SwWait( *GetDoc()->GetDocShell(), sal_True );
2691     }
2692 
2693     SwPaM* pCrsr = GetCrsr();
2694     // es gibt mehr als einen oder ist eine Selektion offen
2695     if( pCrsr->GetNext() != pCrsr || pCrsr->HasMark() )
2696     {
2697         FOREACHPAM_START(this)
2698             if( PCURCRSR->HasMark() )
2699             {
2700                 SwAutoFormat aFmt( this, aAFFlags, &PCURCRSR->Start()->nNode,
2701                                      &PCURCRSR->End()->nNode );
2702             }
2703         FOREACHPAM_END()
2704     }
2705     else
2706     {
2707         SwAutoFormat aFmt( this, aAFFlags );
2708     }
2709 
2710     EndUndo( UNDO_AUTOFORMAT );
2711     EndAllAction();
2712 
2713     delete pWait;
2714 }
2715 
2716 
2717 void SwEditShell::AutoFmtBySplitNode()
2718 {
2719     SET_CURR_SHELL( this );
2720     SwPaM* pCrsr = GetCrsr();
2721     if( pCrsr->GetNext() == pCrsr && pCrsr->Move( fnMoveBackward, fnGoNode ) )
2722     {
2723         StartAllAction();
2724         StartUndo( UNDO_AUTOFORMAT );
2725 
2726         sal_Bool bRange = sal_False;
2727         pCrsr->SetMark();
2728         SwIndex* pCntnt = &pCrsr->GetMark()->nContent;
2729         if( pCntnt->GetIndex() )
2730         {
2731             *pCntnt = 0;
2732             bRange = sal_True;
2733         }
2734         else
2735         {
2736             // dann einen Node zurueckspringen
2737             SwNodeIndex aNdIdx( pCrsr->GetMark()->nNode, -1 );
2738             SwTxtNode* pTxtNd = aNdIdx.GetNode().GetTxtNode();
2739             if( pTxtNd && pTxtNd->GetTxt().Len() )
2740             {
2741                 pCntnt->Assign( pTxtNd, 0 );
2742                 pCrsr->GetMark()->nNode = aNdIdx;
2743                 bRange = sal_True;
2744             }
2745         }
2746 
2747         if( bRange )
2748         {
2749             Push();     // Cursor sichern
2750 
2751             SvxSwAutoFmtFlags aAFFlags = *GetAutoFmtFlags();        // erst mal default - Werte
2752 
2753             SwAutoFormat aFmt( this, aAFFlags, &pCrsr->GetMark()->nNode,
2754                                     &pCrsr->GetPoint()->nNode );
2755 
2756             //JP 30.09.96: das DoTable() verlaesst sich auf das PopCrsr
2757             //              und MoveCrsr!
2758             Pop( sal_False );
2759             pCrsr = GetCrsr();
2760         }
2761         pCrsr->DeleteMark();
2762         pCrsr->Move( fnMoveForward, fnGoNode );
2763 
2764         EndUndo( UNDO_AUTOFORMAT );
2765         EndAllAction();
2766     }
2767 }
2768 
2769 SvxSwAutoFmtFlags* SwEditShell::GetAutoFmtFlags()
2770 {
2771     if (!pAutoFmtFlags)
2772         pAutoFmtFlags = new SvxSwAutoFmtFlags;
2773 
2774     return pAutoFmtFlags;
2775 }
2776 
2777 void SwEditShell::SetAutoFmtFlags(SvxSwAutoFmtFlags * pFlags)
2778 {
2779     SvxSwAutoFmtFlags* pEditFlags = GetAutoFmtFlags();
2780 
2781     pEditFlags->bSetNumRule     = pFlags->bSetNumRule;
2782     pEditFlags->bChgEnumNum     = pFlags->bChgEnumNum;
2783     pEditFlags->bSetBorder      = pFlags->bSetBorder;
2784     pEditFlags->bCreateTable    = pFlags->bCreateTable;
2785     pEditFlags->bReplaceStyles  = pFlags->bReplaceStyles;
2786     pEditFlags->bAFmtByInpDelSpacesAtSttEnd =
2787                                     pFlags->bAFmtByInpDelSpacesAtSttEnd;
2788     pEditFlags->bAFmtByInpDelSpacesBetweenLines =
2789                                     pFlags->bAFmtByInpDelSpacesBetweenLines;
2790 
2791     //JP 15.12.98: BulletZeichen und Font in die "normalen" kopieren,
2792     //          weil beim Autoformat nur mit diesen gearbeitet wird!
2793     pEditFlags->cBullet             = pFlags->cByInputBullet;
2794     pEditFlags->aBulletFont         = pFlags->aByInputBulletFont;
2795     pEditFlags->cByInputBullet      = pFlags->cByInputBullet;
2796     pEditFlags->aByInputBulletFont  = pFlags->aByInputBulletFont;
2797 }
2798 
2799