/**************************************************************
 * 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 *************************************************************/



// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sw.hxx"


#define _SVSTDARR_LONGS
#define _SVSTDARR_USHORTS

#include <ctype.h>
#include <hintids.hxx>

#include <svl/svstdarr.hxx>

#include <unotools/charclass.hxx>

#include <vcl/msgbox.hxx>

#include <editeng/boxitem.hxx>
#include <editeng/lrspitem.hxx>
#include <editeng/brkitem.hxx>
#include <editeng/adjitem.hxx>
#include <editeng/tstpitem.hxx>
#include <editeng/fontitem.hxx>
#include <editeng/langitem.hxx>
#include <editeng/cscoitem.hxx>
#include <editeng/unolingu.hxx>
#include <editeng/acorrcfg.hxx>

#include <swwait.hxx>
#include <fmtpdsc.hxx>
#include <fmtanchr.hxx>
#include <doc.hxx>
#include <IDocumentUndoRedo.hxx>
#include <docary.hxx>
#include <editsh.hxx>
#include <index.hxx>
#include <pam.hxx>
#include <edimp.hxx>
#include <fesh.hxx>
#include <swundo.hxx>		// fuer die UndoIds
#include <poolfmt.hxx>
#include <ndtxt.hxx>
#include <txtfrm.hxx>
#include <frminf.hxx>
#include <pagedesc.hxx>
#include <paratr.hxx>
#include <swtable.hxx>
#include <acorrect.hxx>
#include <shellres.hxx>
#include <section.hxx>
#include <frmatr.hxx>
#include <charatr.hxx>
#include <mdiexp.hxx>
#include <statstr.hrc>
#include <comcore.hrc>
#include <numrule.hxx>

using namespace ::com::sun::star;

//-------------------------------------------------------------------

//JP 16.12.99: definition:
//		from pos cPosEnDash to cPosEmDash all chars changed to endashes,
//		from pos cPosEmDash to cPosEnd    all chars changed to emdashes
// 		all other chars are changed to the user configuration

const sal_Unicode pBulletChar[6] = { '+', '*', '-', 0x2013, 0x2014, 0 };
const int cnPosEnDash = 2, cnPosEmDash = 4, cnPosEnd = 5;

const sal_Unicode cStarSymbolEnDash = 0x2013;
const sal_Unicode cStarSymbolEmDash = 0x2014;


SvxSwAutoFmtFlags* SwEditShell::pAutoFmtFlags = 0;

// Anzahl von Num-/Bullet-Absatzvorlagen. MAXLEVEL wird demnaechst auf
// x erhoeht, die Anzahl Vorlagen aber nicht (Ueberbleibsel aus <= 4.0)
const sal_uInt16 cnNumBullColls = 4;

class SwAutoFormat
{
	SvxSwAutoFmtFlags aFlags;
	SwPaM aDelPam;				// ein Pam der benutzt werden kann
	SwNodeIndex aNdIdx;			// der Index auf den akt. TextNode
	SwNodeIndex aEndNdIdx;		// Index auf das Ende vom Bereich

	SwEditShell* pEditShell;
	SwDoc* pDoc;
	SwTxtNode* pAktTxtNd;		// der akt. TextNode
	SwTxtFrm* pAktTxtFrm;		// Frame vom akt. TextNode
	CharClass* pCharClass;		// Character classification
	sal_uLong nEndNdIdx;			// fuer die Prozent-Anzeige
	LanguageType eCharClassLang;

	sal_uInt16 nLastHeadLvl, nLastCalcHeadLvl;
	sal_uInt16 nLastEnumLvl, nLastCalcEnumLvl;
	sal_uInt16 nRedlAutoFmtSeqId;

	enum
	{
		NONE = 0,
		DELIM = 1,
		DIGIT = 2,
		CHG = 4,
		LOWER_ALPHA = 8,
		UPPER_ALPHA = 16,
		LOWER_ROMAN = 32,
		UPPER_ROMAN = 64,
		NO_DELIM = (DIGIT|LOWER_ALPHA|UPPER_ALPHA|LOWER_ROMAN|UPPER_ROMAN)
	};

	enum Format_Status
	{
		READ_NEXT_PARA,
		TST_EMPTY_LINE,
		TST_ALPHA_LINE,
		GET_ALL_INFO,
		IS_ONE_LINE,
		TST_ENUMERIC,
		TST_IDENT,
		TST_NEG_IDENT,
		TST_TXT_BODY,
		HAS_FMTCOLL,
		IS_ENDE
	} eStat;

	sal_Bool bEnde : 1;
	sal_Bool bEmptyLine : 1;
	sal_Bool bMoreLines : 1;

    static sal_Bool  m_bAskForCancelUndoWhileBufferOverflow;
    static short m_nActionWhileAutoformatUndoBufferOverflow;


	// ------------- private methods -----------------------------
	void _GetCharClass( LanguageType eLang );
	CharClass& GetCharClass( LanguageType eLang ) const
	{
		if( !pCharClass || eLang != eCharClassLang )
		{
			SwAutoFormat* pThis = (SwAutoFormat*)this;
			pThis->_GetCharClass( eLang );
		}
		return *pCharClass;
	}


	sal_Bool IsSpace( const sal_Unicode c ) const
		{ return (' ' == c || '\t' == c || 0x0a == c|| 0x3000 == c /* Jap. space */) ? sal_True : sal_False; }

	void SetColl( sal_uInt16 nId, sal_Bool bHdLineOrText = sal_False );
	String GoNextPara();
	sal_Bool HasObjects( const SwNode& rNd );

	// TxtNode Methoden
	const SwTxtNode* GetNextNode() const;
	sal_Bool IsEmptyLine( const SwTxtNode& rNd ) const
		{	return 0 == rNd.GetTxt().Len() ||
				rNd.GetTxt().Len() == GetLeadingBlanks( rNd.GetTxt() ); }

	sal_Bool IsOneLine( const SwTxtNode& ) const;
	sal_Bool IsFastFullLine( const SwTxtNode& ) const;
	sal_Bool IsNoAlphaLine( const SwTxtNode&) const;
	sal_Bool IsEnumericChar( const SwTxtNode&) const;
	sal_Bool IsBlanksInString( const SwTxtNode&) const;
	sal_uInt16 CalcLevel( const SwTxtNode&, sal_uInt16 *pDigitLvl = 0 ) const;
	xub_StrLen GetBigIndent( xub_StrLen& rAktSpacePos ) const;

	String& DelLeadingBlanks( String& rStr ) const;
	String& DelTrailingBlanks( String& rStr ) const;
	xub_StrLen GetLeadingBlanks( const String& rStr ) const;
	xub_StrLen GetTrailingBlanks( const String& rStr ) const;

	sal_Bool IsFirstCharCapital( const SwTxtNode& rNd ) const;
	sal_uInt16 GetDigitLevel( const SwTxtNode& rTxtNd, xub_StrLen& rPos,
							String* pPreFix = 0, String* pPostFix = 0,
							String* pNumTypes = 0 ) const;
		// hole den FORMATIERTEN TextFrame
	SwTxtFrm* GetFrm( const SwTxtNode& rTxtNd ) const;

	void BuildIndent();
	void BuildText();
	void BuildTextIndent();
	void BuildEnum( sal_uInt16 nLvl, sal_uInt16 nDigitLevel );
	void BuildNegIndent( SwTwips nSpaces );
	void BuildHeadLine( sal_uInt16 nLvl );

	sal_Bool HasSelBlanks( SwPaM& rPam ) const;
	sal_Bool HasBreakAttr( const SwTxtNode& ) const;
	void DeleteSel( SwPaM& rPam );
	sal_Bool DeleteAktNxtPara( const String& rNxtPara );
	// loesche im Node Anfang oder/und Ende
	void DeleteAktPara( sal_Bool bStart = sal_True, sal_Bool nEnd = sal_True );
	void DelEmptyLine( sal_Bool bTstNextPara = sal_True );
		// loesche bei mehrzeiligen Absaetzen die "linken" und/oder
		// "rechten" Raender
	void DelMoreLinesBlanks( sal_Bool bWithLineBreaks = sal_False );
		// loesche den vorherigen Absatz
	void DelPrevPara();
		// dann lasse doch mal das AutoCorrect auf den akt. TextNode los
	void AutoCorrect( xub_StrLen nSttPos = 0 );

	sal_Bool CanJoin( const SwTxtNode* pTxtNd ) const
	{
		return !bEnde && pTxtNd &&
			 !IsEmptyLine( *pTxtNd ) &&
			 !IsNoAlphaLine( *pTxtNd) &&
			 !IsEnumericChar( *pTxtNd ) &&
			 ((STRING_MAXLEN - 50 - pTxtNd->GetTxt().Len()) >
					pAktTxtNd->GetTxt().Len()) &&
			 !HasBreakAttr( *pTxtNd );
	}

	// ist ein Punkt am Ende ??
	sal_Bool IsSentenceAtEnd( const SwTxtNode& rTxtNd ) const;

	sal_Bool DoUnderline();
	sal_Bool DoTable();

	void _SetRedlineTxt( sal_uInt16 nId );
	sal_Bool SetRedlineTxt( sal_uInt16 nId )
		{ if( aFlags.bWithRedlining )	_SetRedlineTxt( nId );  return sal_True; }
	sal_Bool ClearRedlineTxt()
		{ if( aFlags.bWithRedlining )	pDoc->SetAutoFmtRedlineComment(0);  return sal_True; }

public:
	SwAutoFormat( SwEditShell* pEdShell, SvxSwAutoFmtFlags& rFlags,
				SwNodeIndex* pSttNd = 0, SwNodeIndex* pEndNd = 0 );
	~SwAutoFormat() {
		delete pCharClass;
	}
};

sal_Bool  SwAutoFormat::m_bAskForCancelUndoWhileBufferOverflow     = sal_True;
short SwAutoFormat::m_nActionWhileAutoformatUndoBufferOverflow = RET_YES;

const sal_Unicode* StrChr( const sal_Unicode* pSrc, sal_Unicode c )
{
	while( *pSrc && *pSrc != c )
		++pSrc;
	return *pSrc ? pSrc : 0;
}

SwTxtFrm* SwAutoFormat::GetFrm( const SwTxtNode& rTxtNd ) const
{
	// besorge mal den Frame
	const SwCntntFrm *pFrm = rTxtNd.getLayoutFrm( pEditShell->GetLayout() );
	ASSERT( pFrm, "zum Autoformat muss das Layout vorhanden sein" );
	if( aFlags.bAFmtByInput && !pFrm->IsValid() )
	{
		SwRect aTmpFrm( pFrm->Frm() );
		SwRect aTmpPrt( pFrm->Prt() );
		pFrm->Calc();
		if( pFrm->Frm() != aTmpFrm || pFrm->Prt() != aTmpPrt ||
			( pFrm->IsTxtFrm() && !((SwTxtFrm*)pFrm)->Paint().IsEmpty() ) )
			pFrm->SetCompletePaint();
	}
	return ((SwTxtFrm*)pFrm)->GetFormatted();
}

void SwAutoFormat::_GetCharClass( LanguageType eLang )
{
	delete pCharClass;
	pCharClass = new CharClass( SvxCreateLocale( eLang ));
	eCharClassLang = eLang;
}

void SwAutoFormat::_SetRedlineTxt( sal_uInt16 nActionId )
{
	String sTxt;
	sal_uInt16 nSeqNo = 0;
	if( STR_AUTOFMTREDL_END > nActionId )
	{
		sTxt = *ViewShell::GetShellRes()->GetAutoFmtNameLst()[ nActionId ];
		switch( nActionId )
		{
		case STR_AUTOFMTREDL_SET_NUMBULET:
		case STR_AUTOFMTREDL_DEL_MORELINES:

		// AutoCorrect-Actions
		case STR_AUTOFMTREDL_USE_REPLACE:
		case STR_AUTOFMTREDL_CPTL_STT_WORD:
		case STR_AUTOFMTREDL_CPTL_STT_SENT:
		case STR_AUTOFMTREDL_TYPO:
		case STR_AUTOFMTREDL_UNDER:
		case STR_AUTOFMTREDL_BOLD:
		case STR_AUTOFMTREDL_FRACTION:
		case STR_AUTOFMTREDL_DASH:
		case STR_AUTOFMTREDL_ORDINAL:
        case STR_AUTOFMTREDL_NON_BREAK_SPACE:
			nSeqNo = ++nRedlAutoFmtSeqId;
			break;
		}
	}
#if OSL_DEBUG_LEVEL > 1
	else
		sTxt = String::CreateFromAscii(
							RTL_CONSTASCII_STRINGPARAM( "Action-Text fehlt" ));
#endif

	pDoc->SetAutoFmtRedlineComment( &sTxt, nSeqNo );
}

String SwAutoFormat::GoNextPara()
{
	SwNode* pNewNd = 0;
	do {
		//has to be checed twice before and after incrementation
		if( aNdIdx.GetIndex() >= aEndNdIdx.GetIndex() )
		{
			bEnde = sal_True;
			return aEmptyStr;
		}

		aNdIdx++;
		if( aNdIdx.GetIndex() >= aEndNdIdx.GetIndex() )
		{
			bEnde = sal_True;
			return aEmptyStr;
		}
		else
			pNewNd = &aNdIdx.GetNode();

		// kein TextNode ->
		// 		TableNode	: Tabelle ueberspringen
		// 		NoTxtNode	: Nodes ueberspringen
		// 		EndNode		: Ende erreicht, beenden
		if( pNewNd->IsEndNode() )
		{
			bEnde = sal_True;
			return aEmptyStr;
		}
		else if( pNewNd->IsTableNode() )
			aNdIdx = *pNewNd->EndOfSectionNode();
		else if( pNewNd->IsSectionNode() )
		{
			const SwSection& rSect = pNewNd->GetSectionNode()->GetSection();
			if( rSect.IsHiddenFlag() || rSect.IsProtectFlag() )
				aNdIdx = *pNewNd->EndOfSectionNode();
		}
	} while( !pNewNd->IsTxtNode() );

	if( !aFlags.bAFmtByInput )
		::SetProgressState( aNdIdx.GetIndex() + nEndNdIdx - aEndNdIdx.GetIndex(),
							pDoc->GetDocShell() );

	pAktTxtNd = (SwTxtNode*)pNewNd;
	pAktTxtFrm = GetFrm( *pAktTxtNd );
	return pAktTxtNd->GetTxt();
}

sal_Bool SwAutoFormat::HasObjects( const SwNode& rNd )
{
	// haengt irgend etwas absatzgebundenes am Absatz?
	// z.B. Rahmen, DrawObjecte, ..
	sal_Bool bRet = sal_False;
	const SwSpzFrmFmts& rFmts = *pDoc->GetSpzFrmFmts();
	for( sal_uInt16 n = 0; n < rFmts.Count(); ++n )
	{
		const SwFmtAnchor& rAnchor = rFmts[ n ]->GetAnchor();
        if ((FLY_AT_PAGE != rAnchor.GetAnchorId()) &&
			rAnchor.GetCntntAnchor() &&
			&rAnchor.GetCntntAnchor()->nNode.GetNode() == &rNd )
		{
			bRet = sal_True;
			break;
		}
	}
	return bRet;
}

const SwTxtNode* SwAutoFormat::GetNextNode() const
{
	if( aNdIdx.GetIndex()+1 >= aEndNdIdx.GetIndex() )
		return 0;
	return pDoc->GetNodes()[ aNdIdx.GetIndex() + 1 ]->GetTxtNode();
}


sal_Bool SwAutoFormat::IsOneLine( const SwTxtNode& rNd ) const
{
	SwTxtFrmInfo aFInfo( GetFrm( rNd ) );
	return aFInfo.IsOneLine();
}


sal_Bool SwAutoFormat::IsFastFullLine( const SwTxtNode& rNd ) const
{
	sal_Bool bRet = aFlags.bRightMargin;
	if( bRet )
	{
		SwTxtFrmInfo aFInfo( GetFrm( rNd ) );
		bRet = aFInfo.IsFilled( aFlags.nRightMargin );
	}
	return bRet;
}


sal_Bool SwAutoFormat::IsEnumericChar( const SwTxtNode& rNd ) const
{
	const String& rTxt = rNd.GetTxt();
	String sTmp( rTxt );
	xub_StrLen nBlnks = GetLeadingBlanks( sTmp );
	xub_StrLen nLen = rTxt.Len() - nBlnks;
	if( !nLen )
		return sal_False;

	// -, +, * getrennt durch Blank ??
	if( 2 < nLen && IsSpace( rTxt.GetChar( nBlnks + 1 ) ) )
	{
		if( StrChr( pBulletChar, rTxt.GetChar( nBlnks ) ) )
			return sal_True;
		// sollte an der Position ein Symbolfont existieren ?
		SwTxtFrmInfo aFInfo( GetFrm( rNd ) );
		if( aFInfo.IsBullet( nBlnks ))
			return sal_True;
	}

	// 1.) / 1. / 1.1.1 / (1). / (1) / ....
	return USHRT_MAX != GetDigitLevel( rNd, nBlnks );
}


sal_Bool SwAutoFormat::IsBlanksInString( const SwTxtNode& rNd ) const
{
	// suche im String mehr als 5 Blanks/Tabs
	String sTmp( rNd.GetTxt() );
	DelTrailingBlanks( DelLeadingBlanks( sTmp ));
	const sal_Unicode* pTmp = sTmp.GetBuffer();
	while( *pTmp )
	{
		if( IsSpace( *pTmp ) )
		{
			if( IsSpace( *++pTmp ))		// 2 Space nach einander
			{
				const sal_Unicode* pStt = pTmp;
				while( *pTmp && IsSpace( *++pTmp ))
					;
				if( 5 <= pTmp - pStt )
					return sal_True;
			}
			else
				++pTmp;
		}
		else
			++pTmp;
	}
	return sal_False;
}


sal_uInt16 SwAutoFormat::CalcLevel( const SwTxtNode& rNd, sal_uInt16 *pDigitLvl ) const
{
	sal_uInt16 nLvl = 0, nBlnk = 0;
	const String& rTxt = rNd.GetTxt();
	if( pDigitLvl )
		*pDigitLvl = USHRT_MAX;

	if( RES_POOLCOLL_TEXT_MOVE == rNd.GetTxtColl()->GetPoolFmtId() )
	{
		if( aFlags.bAFmtByInput )
		{
			nLvl = rNd.GetAutoFmtLvl();
			((SwTxtNode&)rNd).SetAutoFmtLvl( 0 );
			if( nLvl )
				return nLvl;
		}
		++nLvl;
	}


	for( xub_StrLen n = 0, nEnd = rTxt.Len(); n < nEnd; ++n )
	{
		switch( rTxt.GetChar( n ) )
		{
		case ' ': 	if( 3 == ++nBlnk )
						++nLvl, nBlnk = 0;
					break;
		case '\t':	++nLvl, nBlnk = 0;
					break;
		default:
			if( pDigitLvl )
				// Teste auf 1.) / 1. / 1.1.1 / (1). / (1) / ....
				*pDigitLvl = GetDigitLevel( rNd, n );
			return nLvl;
		}
	}
	return nLvl;
}



xub_StrLen SwAutoFormat::GetBigIndent( xub_StrLen& rAktSpacePos ) const
{
	SwTxtFrmInfo aFInfo( GetFrm( *pAktTxtNd ) );
	const SwTxtFrm* pNxtFrm = 0;

	if( !bMoreLines )
	{
		const SwTxtNode* pNxtNd = GetNextNode();
		if( !CanJoin( pNxtNd ) || !IsOneLine( *pNxtNd ) )
			return 0;

		pNxtFrm = GetFrm( *pNxtNd );
	}

	return aFInfo.GetBigIndent( rAktSpacePos, pNxtFrm );
}


sal_Bool SwAutoFormat::IsNoAlphaLine( const SwTxtNode& rNd ) const
{
	const String& rStr = rNd.GetTxt();
	if( !rStr.Len() )
		return sal_False;
	// oder besser: ueber die Anzahl von Alpha/Num- und !AN-Zeichen
	//				bestimmen.
	xub_StrLen nANChar = 0, nBlnk = 0;

	CharClass& rCC = GetCharClass( rNd.GetSwAttrSet().GetLanguage().GetLanguage() );
	for( xub_StrLen n = 0, nEnd = rStr.Len(); n < nEnd; ++n )
		if( IsSpace( rStr.GetChar( n ) ) )
			++nBlnk;
		else if( rCC.isLetterNumeric( rStr, n ))
			++nANChar;

	// sind zu 75% keine Alpha-Nummerische-Zeichen, dann sal_True
	sal_uLong nLen = rStr.Len() - nBlnk;
	nLen = ( nLen * 3 ) / 4;		    // long overflow, if the strlen > sal_uInt16
	return xub_StrLen(nLen) < (rStr.Len() - nANChar - nBlnk);
}



sal_Bool SwAutoFormat::DoUnderline()
{
	if( !aFlags.bSetBorder )
		return sal_False;

	const sal_Unicode* pStr = pAktTxtNd->GetTxt().GetBuffer();
	int eState = 0;
	xub_StrLen nCnt = 0;
	while( *pStr )
	{
//JP 29.03.96: Spaces unterbrechen die Umrandung!
//		if( !IsSpace( *pStr ) )
		{
			int eTmp = 0;
			switch( *pStr )
			{
			case '-': eTmp = 1;	break;
			case '_': eTmp = 2;	break;
			case '=': eTmp = 3;	break;
			case '*': eTmp = 4;	break;
			case '~': eTmp = 5;	break;
			case '#': eTmp = 6;	break;
			default:
				return sal_False;
			}
			if( 0 == eState )
				eState = eTmp;
			else if( eState != eTmp )
				return sal_False;
			++nCnt;
		}
		++pStr;
	}

	if( 2 < nCnt )
	{
		// dann unterstreiche mal den vorherigen Absatz, wenn es diesen gibt!
		DelEmptyLine( sal_False );
		aDelPam.SetMark();
		aDelPam.GetMark()->nContent = 0;
//JP 19.03.96: kein Underline sondern eine Umrandung setzen!
//		pDoc->Insert( aDelPam, SvxUnderlineItem( eState ) );

		SvxBorderLine aLine;
		switch( eState )
		{
		case 1:			// einfach, 0,05 pt
			aLine.SetOutWidth( DEF_LINE_WIDTH_0 );
			break;
		case 2:			// einfach, 1,0 pt
			aLine.SetOutWidth( DEF_LINE_WIDTH_1 );
			break;
		case 3:			// doppelt, 1,1 pt
			aLine.SetOutWidth( DEF_DOUBLE_LINE0_OUT );
			aLine.SetInWidth( DEF_DOUBLE_LINE0_IN );
			aLine.SetDistance( DEF_DOUBLE_LINE0_DIST );
			break;
		case 4:			// doppelt, 4,5 pt
			aLine.SetOutWidth( DEF_DOUBLE_LINE4_OUT );
			aLine.SetInWidth( DEF_DOUBLE_LINE4_IN );
			aLine.SetDistance( DEF_DOUBLE_LINE4_DIST );
			break;
		case 5:			// doppelt, 6,0 pt
			aLine.SetOutWidth( DEF_DOUBLE_LINE5_OUT );
			aLine.SetInWidth( DEF_DOUBLE_LINE5_IN );
			aLine.SetDistance( DEF_DOUBLE_LINE5_DIST );
			break;
		case 6:			// doppelt, 9,0 pt
			aLine.SetOutWidth( DEF_DOUBLE_LINE6_OUT );
			aLine.SetInWidth( DEF_DOUBLE_LINE6_IN );
			aLine.SetDistance( DEF_DOUBLE_LINE6_DIST );
			break;
		}
        SfxItemSet aSet(pDoc->GetAttrPool(),
                    RES_PARATR_CONNECT_BORDER, RES_PARATR_CONNECT_BORDER,
                    RES_BOX, RES_BOX,
                    0);
        aSet.Put( SwParaConnectBorderItem( sal_False ) );
        SvxBoxItem aBox( RES_BOX );
		aBox.SetLine( &aLine, BOX_LINE_BOTTOM );
		aBox.SetDistance( 42 );		// ~0,75 mm
        aSet.Put(aBox);
        pDoc->InsertItemSet( aDelPam, aSet, 0 );

		aDelPam.DeleteMark();
	}
	return 2 < nCnt;
}


sal_Bool SwAutoFormat::DoTable()
{
	if( !aFlags.bCreateTable || !aFlags.bAFmtByInput ||
		pAktTxtNd->FindTableNode() )
		return sal_False;

	const String& rTmp = pAktTxtNd->GetTxt();
	xub_StrLen nSttPlus = GetLeadingBlanks( rTmp );
	xub_StrLen nEndPlus = GetTrailingBlanks( rTmp );
	sal_Unicode cChar;

	if( 2 > nEndPlus - nSttPlus ||
		( '+' != ( cChar = rTmp.GetChar( nSttPlus )) && '|' != cChar ) ||
		( '+' != ( cChar = rTmp.GetChar( nEndPlus - 1)) && '|' != cChar ))
		return sal_False;

	SwTxtFrmInfo aInfo( pAktTxtFrm );

	xub_StrLen n = nSttPlus;
	const sal_Unicode* pStr = rTmp.GetBuffer() + n;
	SvUShorts aPosArr( 5, 5 );

	while( *pStr )
	{
		switch( *pStr )
		{
		case '-':
		case '_':
		case '=':
		case ' ':
		case '\t':
			break;

		case '+':
		case '|':
			aPosArr.Insert( static_cast<sal_uInt16>(aInfo.GetCharPos(n)), aPosArr.Count() );
			break;

		default:
			return sal_False;
		}
		if( ++n == nEndPlus )
			break;

		++pStr;
	}

	if( 1 < aPosArr.Count() )
	{
		// Ausrichtung vom Textnode besorgen:
		sal_uInt16 nColCnt = aPosArr.Count() - 1;
		SwTwips nSttPos = aPosArr[ 0 ];
        sal_Int16 eHori;
		switch( pAktTxtNd->GetSwAttrSet().GetAdjust().GetAdjust() )
		{
        case SVX_ADJUST_CENTER:     eHori = text::HoriOrientation::CENTER;    break;
        case SVX_ADJUST_RIGHT:      eHori = text::HoriOrientation::RIGHT;     break;

		default:
			if( nSttPos )
			{
                eHori = text::HoriOrientation::NONE;
				// dann muss als letztes noch die akt. FrameBreite
				// ins Array
				aPosArr.Insert( static_cast<sal_uInt16>(pAktTxtFrm->Frm().Width()), aPosArr.Count() );
			}
			else
                eHori = text::HoriOrientation::LEFT;
			break;
		}

		// dann erzeuge eine Tabelle, die den Zeichen entspricht
		DelEmptyLine();
		SwNodeIndex aIdx( aDelPam.GetPoint()->nNode );
		aDelPam.Move( fnMoveForward );
        pDoc->InsertTable( SwInsertTableOptions( tabopts::ALL_TBL_INS_ATTR , 1 ),
                           *aDelPam.GetPoint(), 1, nColCnt, eHori,
                           0, &aPosArr );
		aDelPam.GetPoint()->nNode = aIdx;
	}
	return 1 < aPosArr.Count();
}


String& SwAutoFormat::DelLeadingBlanks( String& rStr ) const
{
	xub_StrLen nL;
	xub_StrLen n;

	for( nL = rStr.Len(), n = 0; n < nL && IsSpace( rStr.GetChar(n) ); ++n )
		;
	if( n )		// keine Spaces
		rStr.Erase( 0, n );
	return rStr;
}


String& SwAutoFormat::DelTrailingBlanks( String& rStr ) const
{
	xub_StrLen nL = rStr.Len(), n = nL;
	if( !nL )
		return rStr;

	while( --n && IsSpace( rStr.GetChar( n ) )  )
		;
	if( n+1 != nL )		// keine Spaces
		rStr.Erase( n+1 );
	return rStr;
}


xub_StrLen SwAutoFormat::GetLeadingBlanks( const String& rStr ) const
{
	xub_StrLen nL;
	xub_StrLen n;

	for( nL = rStr.Len(), n = 0; n < nL && IsSpace( rStr.GetChar( n ) ); ++n )
		;
	return n;
}


xub_StrLen SwAutoFormat::GetTrailingBlanks( const String& rStr ) const
{
	xub_StrLen nL = rStr.Len(), n = nL;
	if( !nL )
		return 0;

	while( --n && IsSpace( rStr.GetChar( n ) )  )
		;
	return ++n;
}


sal_Bool SwAutoFormat::IsFirstCharCapital( const SwTxtNode& rNd ) const
{
	const String& rTxt = rNd.GetTxt();
	for( xub_StrLen n = 0, nEnd = rTxt.Len(); n < nEnd; ++n )
		if( !IsSpace( rTxt.GetChar( n ) ) )
		{
			CharClass& rCC = GetCharClass( rNd.GetSwAttrSet().
										GetLanguage().GetLanguage() );
			sal_Int32 nCharType = rCC.getCharacterType( rTxt, n );
			return CharClass::isLetterType( nCharType ) &&
                   0 != ( i18n::KCharacterType::UPPER &
													nCharType );
		}
	return sal_False;
}


sal_uInt16 SwAutoFormat::GetDigitLevel( const SwTxtNode& rNd, xub_StrLen& rPos,
		String* pPreFix, String* pPostFix, String* pNumTypes ) const
{
	// Teste auf 1.) / 1. / 1.1.1 / (1). / (1) / ....
	const String& rTxt = rNd.GetTxt();
	xub_StrLen nPos = rPos;
	int eScan = NONE;

	sal_uInt16 nStart = 0;
	sal_uInt8 nDigitLvl = 0, nDigitCnt = 0;
	//count number of parenthesis to assure a sensible order is found
	sal_uInt16 nOpeningParentheses = 0;
	sal_uInt16 nClosingParentheses = 0;

	CharClass& rCC = GetCharClass( rNd.GetSwAttrSet().GetLanguage().GetLanguage() );

	while( nPos < rTxt.Len() && nDigitLvl < MAXLEVEL - 1)
	{
		const sal_Unicode cCurrentChar = rTxt.GetChar( nPos );
		if( ('0' <= cCurrentChar &&  '9' >= cCurrentChar) ||
            (0xff10 <= cCurrentChar &&  0xff19 >= cCurrentChar) )
		{
			if( eScan & DELIM )
			{
				if( eScan & CHG )		// nicht wenns mit einer Zahl beginnt
				{
					++nDigitLvl;
					if( pPostFix )
						*pPostFix += (sal_Unicode)1;
				}

				if( pNumTypes )
					*pNumTypes += (sal_Unicode)('0' + SVX_NUM_ARABIC);

				eScan = eScan | CHG;
			}
			else if( pNumTypes && !(eScan & DIGIT) )
				*pNumTypes += (sal_Unicode)('0' + SVX_NUM_ARABIC);

			eScan &= ~DELIM;		// Delim raus
			if( 0 != (eScan & ~CHG) && DIGIT != (eScan & ~CHG))
				return USHRT_MAX;

			eScan |= DIGIT;			// Digit rein
			if( 3 == ++nDigitCnt )	// mehr als 2 Nummern sind kein Enum mehr
				return USHRT_MAX;

			nStart *= 10;
            nStart += cCurrentChar <= '9' ? cCurrentChar - '0' : cCurrentChar - 0xff10;
		}
		else if( rCC.isAlpha( rTxt, nPos ) )
		{
			sal_Bool bIsUpper =
                0 != ( i18n::KCharacterType::UPPER &
										rCC.getCharacterType( rTxt, nPos ));
			sal_Unicode cLow = rCC.toLower( rTxt, nPos, 1 ).GetChar(0), cNumTyp;
			int eTmpScan;

			// roemische Zeichen sind "mdclxvi". Da man aber eher mal eine
			// Numerierung mit c oder d anfangen will, werden diese erstmal
			// zu chars und spaeter ggfs. zu romischen Zeichen!
//			if( strchr( "mdclxvi", cLow ))
#ifdef WITH_ALPHANUM_AS_NUMFMT
			//detection of 'c' and 'd' a ROMAN numbering should not be done here
			if( 256 > cLow  &&( (eScan & (LOWER_ROMAN|UPPER_ROMAN))
									? strchr( "mdclxvi", cLow )
									: strchr( "mlxvi", cLow ) ))
#else
			if( 256 > cLow  && ( strchr( "mdclxvi", cLow ) ))
#endif
			{
				if( bIsUpper )
					cNumTyp = '0' + SVX_NUM_ROMAN_UPPER, eTmpScan = UPPER_ROMAN;
				else
					cNumTyp = '0' + SVX_NUM_ROMAN_LOWER, eTmpScan = LOWER_ROMAN;
			}
			else if( bIsUpper )
				cNumTyp = '0' + SVX_NUM_CHARS_UPPER_LETTER, eTmpScan = UPPER_ALPHA;
			else
				cNumTyp = '0' + SVX_NUM_CHARS_LOWER_LETTER, eTmpScan = LOWER_ALPHA;


			//ggfs. auf roemische Zeichen umschalten (nur bei c/d!)?
			if( 1 == nDigitCnt && ( eScan & (UPPER_ALPHA|LOWER_ALPHA) ) &&
				( 3 == nStart || 4 == nStart) && 256 > cLow &&
				strchr( "mdclxvi", cLow ) &&
				(( eScan & UPPER_ALPHA ) ? (eTmpScan & (UPPER_ALPHA|UPPER_ROMAN))
										 : (eTmpScan & (LOWER_ALPHA|LOWER_ROMAN))) )
			{
				sal_Unicode c = '0';
				nStart = 3 == nStart ? 100 : 500;
				if( UPPER_ALPHA == eTmpScan )
					eTmpScan = UPPER_ROMAN, c += SVX_NUM_ROMAN_UPPER;
				else
					eTmpScan = LOWER_ROMAN, c += SVX_NUM_ROMAN_LOWER;

				( eScan &= ~(UPPER_ALPHA|LOWER_ALPHA)) |= eTmpScan;
				if( pNumTypes )
					pNumTypes->SetChar( pNumTypes->Len() - 1, c );
			}

			if( eScan & DELIM )
			{
				if( eScan & CHG )		// nicht wenns mit einer Zahl beginnt
				{
					++nDigitLvl;
					if( pPostFix )
						*pPostFix += (sal_Unicode)1;
				}

				if( pNumTypes )
					*pNumTypes += cNumTyp;
				eScan = eScan | CHG;
			}
			else if( pNumTypes && !(eScan & eTmpScan) )
				*pNumTypes += cNumTyp;

			eScan &= ~DELIM;		// Delim raus

			// falls ein andere Type gesetzt ist, brechen wir ab
			if( 0 != ( eScan & ~CHG ) && eTmpScan != ( eScan & ~CHG ))
				return USHRT_MAX;

			if( eTmpScan & (UPPER_ALPHA | LOWER_ALPHA) )
			{
				// Buchstaben nur zulassen, wenn sie einmalig vorkommen
                return USHRT_MAX;
			}
			else
			{
				// roemische Zahlen: checke ob das gueltige Zeichen sind
				sal_uInt16 nVal;
				sal_Bool bError = sal_False;
				switch( cLow )
				{
				case 'm':	nVal = 1000; goto CHECK_ROMAN_1;
				case 'd':	nVal =  500; goto CHECK_ROMAN_5;
				case 'c':	nVal =  100; goto CHECK_ROMAN_1;
				case 'l':	nVal =   50; goto CHECK_ROMAN_5;
				case 'x':	nVal =   10; goto CHECK_ROMAN_1;
				case 'v':	nVal =    5; goto CHECK_ROMAN_5;

CHECK_ROMAN_1:
					{
						int nMod5 = nStart % (nVal * 5);
						int nLast = nStart % nVal;
						int n10 = nVal / 10;

						if( nMod5 == ((3 * nVal) + n10 ) ||
							nMod5 == ((4 * nVal) + n10 ) ||
							nLast == n10 )
							nStart = static_cast<sal_uInt16>(nStart + (n10 * 8));
						else if( nMod5 == 0 ||
								 nMod5 == (1 * nVal) ||
								 nMod5 == (2 * nVal) )
							nStart = nStart + nVal;
						else
							bError = sal_True;
					}
					break;

CHECK_ROMAN_5:
					{
						if( ( nStart / nVal ) & 1 )
							bError = sal_True;
						else
						{
							int nMod = nStart % nVal;
							int n10 = nVal / 5;
							if( n10 == nMod )
								nStart = static_cast<sal_uInt16>(nStart + (3 * n10));
							else if( 0 == nMod )
								nStart = nStart + nVal;
							else
								bError = sal_True;
						}
					}
					break;

				case 'i':
						if( nStart % 5 >= 3 )
							bError = sal_True;
						else
							nStart += 1;
						break;

				default:
					bError = sal_True;
				}

				if( bError )
					return USHRT_MAX;
			}
			eScan |= eTmpScan;			// Digit rein
			++nDigitCnt;
		}
        else if( (256 > cCurrentChar &&
                 strchr( ".)(", cCurrentChar )) ||
                 0x3002 == cCurrentChar /* Chinese trad. dot */||
                 0xff0e == cCurrentChar /* Japanese dot */||
                 0xFF08 == cCurrentChar /* opening bracket Chin./Jap.*/||
                 0xFF09 == cCurrentChar )/* closing bracket Chin./Jap. */
		{
            if(cCurrentChar == '(' || cCurrentChar == 0xFF09)
				nOpeningParentheses++;
            else if(cCurrentChar == ')'|| cCurrentChar == 0xFF08)
				nClosingParentheses++;
			// nur wenn noch keine Zahlen gelesen wurden!
			if( pPreFix && !( eScan & ( NO_DELIM | CHG )) )
				*pPreFix += rTxt.GetChar( nPos );
			else if( pPostFix )
				*pPostFix += rTxt.GetChar( nPos );

			if( NO_DELIM & eScan )
			{
				eScan |= CHG;
				if( pPreFix )
					(*pPreFix += (sal_Unicode)1)
							  += String::CreateFromInt32( nStart );
			}
			eScan &= ~NO_DELIM;		// Delim raus
			eScan |= DELIM;			// Digit rein
			nDigitCnt = 0;
			nStart = 0;
		}
		else
			break;
		++nPos;
	}
    if( !( CHG & eScan ) || rPos == nPos ||
		nPos == rTxt.Len() || !IsSpace( rTxt.GetChar( nPos ) ) ||
		(nOpeningParentheses > nClosingParentheses))
		return USHRT_MAX;

	if( (NO_DELIM & eScan) && pPreFix )		// den letzen nicht vergessen
		(*pPreFix += (sal_Unicode)1) += String::CreateFromInt32( nStart );

	rPos = nPos;
	return nDigitLvl;		// 0 .. 9 (MAXLEVEL - 1)
}


void SwAutoFormat::SetColl( sal_uInt16 nId, sal_Bool bHdLineOrText )
{
	aDelPam.DeleteMark();
	aDelPam.GetPoint()->nNode = aNdIdx;
	aDelPam.GetPoint()->nContent.Assign( pAktTxtNd, 0 );

	// behalte harte Tabs, Ausrichtung, Sprache, Silbentrennung,
	// DropCaps und fast alle Frame-Attribute
	SfxItemSet aSet( pDoc->GetAttrPool(),
						RES_PARATR_ADJUST, RES_PARATR_ADJUST,
						RES_PARATR_TABSTOP, RES_PARATR_DROP,
						RES_CHRATR_LANGUAGE, RES_CHRATR_LANGUAGE,
						RES_BACKGROUND, RES_SHADOW,
						0 );

    if( pAktTxtNd->HasSwAttrSet() )
	{
		aSet.Put( *pAktTxtNd->GetpSwAttrSet() );
		// einige Sonderbedingungen:
		// HeaderLine/Textkoerper: nur zentriert oder rechts mitnehmem
		// sonst nur den Blocksatz
		SvxAdjustItem* pAdj;
		if( SFX_ITEM_SET == aSet.GetItemState( RES_PARATR_ADJUST,
						sal_False, (const SfxPoolItem**)&pAdj ))
		{
			SvxAdjust eAdj = pAdj->GetAdjust();
			if( bHdLineOrText ? (SVX_ADJUST_RIGHT != eAdj &&
								 SVX_ADJUST_CENTER != eAdj)
							  : SVX_ADJUST_BLOCK != eAdj )
				aSet.ClearItem( RES_PARATR_ADJUST );
		}
	}

	pDoc->SetTxtFmtCollByAutoFmt( *aDelPam.GetPoint(), nId, &aSet );
}


sal_Bool SwAutoFormat::HasSelBlanks( SwPaM& rPam ) const
{
	// noch ein Blank am Anfang oder Ende ?
	// nicht loeschen, wird wieder eingefuegt.
	SwPosition * pPos = rPam.End();
	xub_StrLen nBlnkPos = pPos->nContent.GetIndex();
	SwTxtNode* pTxtNd = pPos->nNode.GetNode().GetTxtNode();
	if( nBlnkPos && nBlnkPos-- < pTxtNd->GetTxt().Len() &&
		( ' ' == pTxtNd->GetTxt().GetChar( nBlnkPos ) ))
// JP 23.08.95: keine Tabs stehen lassen, diese in Blanks wandeln
//        ( ' ' == ( cCh = pTxtNd->GetTxt()[ nBlnkPos ] ) || '\t' == cCh ))
		pPos->nContent--;
	else
	{
		pPos = rPam.GetPoint() == pPos ? rPam.GetMark() : rPam.GetPoint();
		nBlnkPos = pPos->nContent.GetIndex();
		pTxtNd = pPos->nNode.GetNode().GetTxtNode();
		if( nBlnkPos < pTxtNd->GetTxt().Len() &&
			( ' ' == pTxtNd->GetTxt().GetChar( nBlnkPos )))
// JP 23.08.95: keine Tabs stehen lassen, diese in Blanks wandeln
//            ( ' ' == ( cCh = pTxtNd->GetTxt()[ nBlnkPos ] ) || '\t' == cCh ))
			pPos->nContent++;
		else
			return sal_False;
	}
	return sal_True;
}


sal_Bool SwAutoFormat::HasBreakAttr( const SwTxtNode& rTxtNd ) const
{
    const SfxItemSet* pSet = rTxtNd.GetpSwAttrSet();
	if( !pSet )
		return sal_False;

	const SfxPoolItem* pItem;
	if( SFX_ITEM_SET == pSet->GetItemState( RES_BREAK, sal_False, &pItem )
		&& SVX_BREAK_NONE != ((SvxFmtBreakItem*)pItem)->GetBreak() )
		return sal_True;

	if( SFX_ITEM_SET == pSet->GetItemState( RES_PAGEDESC, sal_False, &pItem )
		&& ((SwFmtPageDesc*)pItem)->GetPageDesc()
		&& nsUseOnPage::PD_NONE != ((SwFmtPageDesc*)pItem)->GetPageDesc()->GetUseOn() )
		return sal_True;
	return sal_False;
}


// ist ein Punkt am Ende ??
sal_Bool SwAutoFormat::IsSentenceAtEnd( const SwTxtNode& rTxtNd ) const
{
	const String& rStr = rTxtNd.GetTxt();
	xub_StrLen n = rStr.Len();
	if( !n )
		return sal_True;

	while( --n && IsSpace( rStr.GetChar( n  ) ) )
		;
	return '.' == rStr.GetChar( n );
}


// loesche im Node Anfang oder/und Ende
void SwAutoFormat::DeleteAktPara( sal_Bool bStart, sal_Bool bEnd )
{
	if( aFlags.bAFmtByInput
		? aFlags.bAFmtByInpDelSpacesAtSttEnd
		: aFlags.bAFmtDelSpacesAtSttEnd )
	{
		// Loesche Blanks am Ende vom akt. und am Anfang vom naechsten
		aDelPam.DeleteMark();
		aDelPam.GetPoint()->nNode = aNdIdx;
		xub_StrLen nPos;
		if( bStart && 0 != ( nPos = GetLeadingBlanks( pAktTxtNd->GetTxt() )))
		{
			aDelPam.GetPoint()->nContent.Assign( pAktTxtNd, 0 );
			aDelPam.SetMark();
			aDelPam.GetPoint()->nContent = nPos;
			DeleteSel( aDelPam );
			aDelPam.DeleteMark();
		}
		if( bEnd && pAktTxtNd->GetTxt().Len() !=
					( nPos = GetTrailingBlanks( pAktTxtNd->GetTxt() )) )
		{
			aDelPam.GetPoint()->nContent.Assign( pAktTxtNd, pAktTxtNd->GetTxt().Len() );
			aDelPam.SetMark();
			aDelPam.GetPoint()->nContent = nPos;
			DeleteSel( aDelPam );
			aDelPam.DeleteMark();
		}
	}
}

void SwAutoFormat::DeleteSel( SwPaM& rDelPam )
{
	if( aFlags.bWithRedlining )
	{
		// damit der DelPam auch verschoben wird, in den Shell-Cursr-Ring
		// mit aufnehmen !!
		SwPaM* pShCrsr = pEditShell->_GetCrsr();
		SwPaM aTmp( *pAktTxtNd, 0, pShCrsr );

		Ring *pPrev = rDelPam.GetPrev();
		rDelPam.MoveRingTo( pShCrsr );

		pEditShell->DeleteSel( rDelPam );

		// und den Pam wieder herausnehmen:
		Ring *p, *pNext = (Ring*)&rDelPam;
		do {
			p = pNext;
			pNext = p->GetNext();
			p->MoveTo( &rDelPam );
		} while( p != pPrev );

		aNdIdx = aTmp.GetPoint()->nNode;
		pAktTxtNd = aNdIdx.GetNode().GetTxtNode();
	}
	else
		pEditShell->DeleteSel( rDelPam );
}

sal_Bool SwAutoFormat::DeleteAktNxtPara( const String& rNxtPara )
{
	// Loesche Blanks am Ende vom akt. und am Anfang vom naechsten
	aDelPam.DeleteMark();
	aDelPam.GetPoint()->nNode = aNdIdx;
	aDelPam.GetPoint()->nContent.Assign( pAktTxtNd,
					GetTrailingBlanks( pAktTxtNd->GetTxt() ) );
	aDelPam.SetMark();

	aDelPam.GetPoint()->nNode++;
	SwTxtNode* pTNd = aDelPam.GetNode()->GetTxtNode();
	if( !pTNd )
	{
		// dann nur bis zum Ende von Absatz loeschen
		aDelPam.GetPoint()->nNode--;
		aDelPam.GetPoint()->nContent = pAktTxtNd->GetTxt().Len();
	}
	else
		aDelPam.GetPoint()->nContent.Assign( pTNd,
							GetLeadingBlanks( rNxtPara ));

	// noch ein Blank am Anfang oder Ende ?
	// nicht loeschen, wird wieder eingefuegt.
	sal_Bool bHasBlnks = HasSelBlanks( aDelPam );

	if( *aDelPam.GetPoint() != *aDelPam.GetMark() )
		DeleteSel( aDelPam );
	aDelPam.DeleteMark();

	return !bHasBlnks;
}


void SwAutoFormat::DelEmptyLine( sal_Bool bTstNextPara )
{
	SetRedlineTxt( STR_AUTOFMTREDL_DEL_EMPTY_PARA );
	// Loesche Blanks den leeren Absatz
	aDelPam.DeleteMark();
	aDelPam.GetPoint()->nNode = aNdIdx;
	aDelPam.GetPoint()->nContent.Assign( pAktTxtNd, pAktTxtNd->GetTxt().Len() );
	aDelPam.SetMark();

	aDelPam.GetMark()->nNode--;
	SwTxtNode* pTNd = aDelPam.GetNode( sal_False )->GetTxtNode();
	if( pTNd )
		// erstmal den vorherigen Textnode benutzen.
		aDelPam.GetMark()->nContent.Assign( pTNd, pTNd->GetTxt().Len() );
	else if( bTstNextPara )
	{
		// dann versuche den naechsten (am Anfang vom Dok, Tabellen-Zellen,
		// Rahmen, ...
		aDelPam.GetMark()->nNode += 2;
		pTNd = aDelPam.GetNode( sal_False )->GetTxtNode();
		if( pTNd )
		{
			aDelPam.GetMark()->nContent.Assign( pTNd, 0 );
			aDelPam.GetPoint()->nContent = 0;
		}
	}
	else
	{
		aDelPam.GetMark()->nNode = aNdIdx;
		aDelPam.GetMark()->nContent = 0;
		pTNd = pAktTxtNd;
	}
	if( pTNd )
		DeleteSel( aDelPam );

	aDelPam.DeleteMark();
	ClearRedlineTxt();
}


void SwAutoFormat::DelMoreLinesBlanks( sal_Bool bWithLineBreaks )
{
	if( aFlags.bAFmtByInput
		? aFlags.bAFmtByInpDelSpacesBetweenLines
		: aFlags.bAFmtDelSpacesBetweenLines	)
	{
		// loesche alle "Blanks" Links und Rechts vom Einzug
		aDelPam.DeleteMark();
		aDelPam.GetPoint()->nNode = aNdIdx;
		aDelPam.GetPoint()->nContent.Assign( pAktTxtNd, 0 );

		SwTxtFrmInfo aFInfo( pAktTxtFrm );
		aFInfo.GetSpaces( aDelPam, !aFlags.bAFmtByInput || bWithLineBreaks );

		SwPaM* pNxt;
		do {
			pNxt = (SwPaM*)aDelPam.GetNext();
			if( pNxt->HasMark() && *pNxt->GetPoint() != *pNxt->GetMark() )
			{
				sal_Bool bHasBlnks = HasSelBlanks( *pNxt );
				DeleteSel( *pNxt );
				if( !bHasBlnks )
                {
                    pDoc->InsertString( *pNxt, sal_Unicode(' ') );
                }
			}

			if( pNxt == &aDelPam )
				break;
			delete pNxt;
		} while( sal_True );

		aDelPam.DeleteMark();
	}
}


		// loesche den vorherigen Absatz
void SwAutoFormat::DelPrevPara()
{
	aDelPam.DeleteMark();
	aDelPam.GetPoint()->nNode = aNdIdx;
	aDelPam.GetPoint()->nContent.Assign( pAktTxtNd, 0 );
	aDelPam.SetMark();

	aDelPam.GetPoint()->nNode--;
	SwTxtNode* pTNd = aDelPam.GetNode()->GetTxtNode();
	if( pTNd )
	{
		// erstmal den vorherigen Textnode benutzen.
		aDelPam.GetPoint()->nContent.Assign( pTNd, pTNd->GetTxt().Len() );
		DeleteSel( aDelPam );
	}
	aDelPam.DeleteMark();
}


void SwAutoFormat::BuildIndent()
{
	SetRedlineTxt( STR_AUTOFMTREDL_SET_TMPL_INDENT );

	// lese alle nachfolgenden Absaetze die zu diesem Einzug gehoeren
	sal_Bool bBreak = sal_True;
	if( bMoreLines )
		DelMoreLinesBlanks( sal_True );
	else
		bBreak = !IsFastFullLine( *pAktTxtNd ) ||
				IsBlanksInString( *pAktTxtNd ) ||
				IsSentenceAtEnd( *pAktTxtNd );
	SetColl( RES_POOLCOLL_TEXT_IDENT );
	if( !bBreak )
	{
		SetRedlineTxt( STR_AUTOFMTREDL_DEL_MORELINES );
		const SwTxtNode* pNxtNd = GetNextNode();
		if( pNxtNd && !bEnde )
		{
			do {
				bBreak = !IsFastFullLine( *pNxtNd ) ||
						IsBlanksInString( *pNxtNd ) ||
						IsSentenceAtEnd( *pNxtNd );
				if( DeleteAktNxtPara( pNxtNd->GetTxt() ))
                {
                    pDoc->InsertString( aDelPam, sal_Unicode(' ') );
                }
				if( bBreak )
					break;
				pNxtNd = GetNextNode();
			} while( CanJoin( pNxtNd ) &&
					!CalcLevel( *pNxtNd ) );
		}
	}
	DeleteAktPara( sal_True, sal_True );
	AutoCorrect();
}


void SwAutoFormat::BuildTextIndent()
{
	SetRedlineTxt( STR_AUTOFMTREDL_SET_TMPL_TEXT_INDENT);
	// lese alle nachfolgenden Absaetze die zu diesem Einzug gehoeren
	sal_Bool bBreak = sal_True;
	if( bMoreLines )
		DelMoreLinesBlanks( sal_True );
	else
		bBreak = !IsFastFullLine( *pAktTxtNd ) ||
					IsBlanksInString( *pAktTxtNd ) ||
					IsSentenceAtEnd( *pAktTxtNd );

	if( aFlags.bAFmtByInput )
		pAktTxtNd->SetAutoFmtLvl( (sal_uInt8)CalcLevel( *pAktTxtNd ) );

	SetColl( RES_POOLCOLL_TEXT_MOVE );
	if( !bBreak )
	{
		SetRedlineTxt( STR_AUTOFMTREDL_DEL_MORELINES );
		const SwTxtNode* pNxtNd = GetNextNode();
		while(	CanJoin( pNxtNd ) &&
				CalcLevel( *pNxtNd ) )
		{
			bBreak = !IsFastFullLine( *pNxtNd ) || IsBlanksInString( *pNxtNd ) ||
					IsSentenceAtEnd( *pNxtNd );
			if( DeleteAktNxtPara( pNxtNd->GetTxt() ) )
            {
                pDoc->InsertString( aDelPam, sal_Unicode(' ') );
            }
			if( bBreak )
				break;
			pNxtNd = GetNextNode();
		}
	}
	DeleteAktPara( sal_True, sal_True );
	AutoCorrect();
}


void SwAutoFormat::BuildText()
{
	SetRedlineTxt( STR_AUTOFMTREDL_SET_TMPL_TEXT );
	// lese alle nachfolgenden Absaetze die zu diesem Text
	// ohne Einzug gehoeren
	sal_Bool bBreak = sal_True;
	if( bMoreLines )
		DelMoreLinesBlanks();
	else
		bBreak = !IsFastFullLine( *pAktTxtNd ) ||
					IsBlanksInString( *pAktTxtNd ) ||
					IsSentenceAtEnd( *pAktTxtNd );
	SetColl( RES_POOLCOLL_TEXT, sal_True );
	if( !bBreak )
	{
		SetRedlineTxt( STR_AUTOFMTREDL_DEL_MORELINES );
		const SwTxtNode* pNxtNd = GetNextNode();
		while(	CanJoin( pNxtNd ) &&
				!CalcLevel( *pNxtNd ) )
		{
			bBreak = !IsFastFullLine( *pNxtNd ) || IsBlanksInString( *pNxtNd ) ||
					IsSentenceAtEnd( *pNxtNd );
			if( DeleteAktNxtPara( pNxtNd->GetTxt() ) )
            {
                pDoc->InsertString( aDelPam, sal_Unicode(' ') );
            }
			if( bBreak )
				break;
            const SwTxtNode* pCurrNode = pNxtNd;
			pNxtNd = GetNextNode();
            if(!pNxtNd || pCurrNode == pNxtNd)
                break;
		}
	}
	DeleteAktPara( sal_True, sal_True );
	AutoCorrect();
}


void SwAutoFormat::BuildEnum( sal_uInt16 nLvl, sal_uInt16 nDigitLevel )
{
	SetRedlineTxt( STR_AUTOFMTREDL_SET_NUMBULET );

	sal_Bool bBreak = sal_True;

	// als erstes den akt. Einzug bestimmen und die Framebreite bestimmen
	SwTwips nFrmWidth = pAktTxtFrm->Prt().Width();;
	SwTwips nLeftTxtPos;
	{
		const sal_Unicode* pTxt = pAktTxtNd->GetTxt().GetBuffer(), *pSav = pTxt;
		while( IsSpace( *pTxt ) )
			++pTxt;

		SwTxtFrmInfo aInfo( pAktTxtFrm );
		nLeftTxtPos = aInfo.GetCharPos( static_cast<xub_StrLen>(pTxt - pSav) );
        nLeftTxtPos -= pAktTxtNd->GetSwAttrSet().GetLRSpace().GetLeft();
    }

	if( bMoreLines )
		DelMoreLinesBlanks();
	else
		bBreak = !IsFastFullLine( *pAktTxtNd ) ||
					IsBlanksInString( *pAktTxtNd ) ||
					IsSentenceAtEnd( *pAktTxtNd );
    sal_Bool bRTL = pEditShell->IsInRightToLeftText();
//	SetColl( RES_POOLCOLL_NUM_LEVEL1 + ( nLvl * 4 ) );
	DeleteAktPara( sal_True, sal_True );

	sal_Bool bChgBullet = sal_False, bChgEnum = sal_False;
	xub_StrLen nAutoCorrPos = 0;

	// falls die Numerierung gesetzt werden, die akt. besorgen
    // --> OD 2008-02-11 #newlistlevelattrs#
    SwNumRule aRule( pDoc->GetUniqueNumRuleName(),
                     // --> OD 2008-06-06 #i89178#
                     numfunc::GetDefaultPositionAndSpaceMode() );
                     // <--
    // <--
    const SwNumRule* pCur = 0;
	if( aFlags.bSetNumRule && 0 != (pCur = pAktTxtNd->GetNumRule()) )
		aRule = *pCur;

	// ersetze das Bullet-Zeichen mit dem definiertem
	const String& rStr = pAktTxtNd->GetTxt();
	xub_StrLen nTxtStt = 0, nOrigTxtStt = 0;
	const sal_Unicode* pFndBulletChr;
//	if( aFlags.bAFmtByInput ? aFlags.bSetNumRule : aFlags.bChgEnumNum &&
	if( aFlags.bChgEnumNum &&
		2 < rStr.Len() &&
		0 != ( pFndBulletChr = StrChr( pBulletChar, rStr.GetChar( nTxtStt ) ))
		&& IsSpace( rStr.GetChar( nTxtStt + 1 ) ) )
	{
		if( aFlags.bAFmtByInput )
		{
			if( aFlags.bSetNumRule )
			{
				SwCharFmt* pCFmt = pDoc->GetCharFmtFromPool(
											RES_POOLCHR_BUL_LEVEL );
				bChgBullet = sal_True;
				// wurde das Format schon mal angepasst?
				if( !aRule.GetNumFmt( nLvl ) )
				{
					int nBulletPos = pFndBulletChr - pBulletChar;
					sal_Unicode cBullChar;
                    const Font* pBullFnt( 0 );
					if( nBulletPos < cnPosEnDash )
					{
						cBullChar = aFlags.cBullet;
						pBullFnt = &aFlags.aBulletFont;
					}
					else
					{
						cBullChar = nBulletPos < cnPosEmDash
										? cStarSymbolEnDash
										: cStarSymbolEmDash;
                        // --> OD 2008-06-03 #i63395#
                        // Only apply user defined default bullet font
                        if ( numfunc::IsDefBulletFontUserDefined() )
                        {
                            pBullFnt = &numfunc::GetDefBulletFont();
                        }
                        // <--
					}

					sal_uInt16 nAbsPos = lBullIndent;
					sal_uInt16 nSpaceSteps = nLvl
											? sal_uInt16(nLeftTxtPos / nLvl)
											: lBullIndent;
					for( sal_uInt8 n = 0; n < MAXLEVEL; ++n, nAbsPos = nAbsPos + nSpaceSteps )
					{
						SwNumFmt aFmt( aRule.Get( n ) );
						aFmt.SetBulletFont( pBullFnt );
						aFmt.SetBulletChar( cBullChar );
						aFmt.SetNumberingType(SVX_NUM_CHAR_SPECIAL);
                        // #i93908# clear suffix for bullet lists
                        aFmt.SetPrefix(::rtl::OUString());
                        aFmt.SetSuffix(::rtl::OUString());
						aFmt.SetFirstLineOffset( lBullFirstLineOffset );
						aFmt.SetAbsLSpace( nAbsPos );
						if( !aFmt.GetCharFmt() )
							aFmt.SetCharFmt( pCFmt );
                        if( bRTL )
                            aFmt.SetNumAdjust( SVX_ADJUST_RIGHT );

						aRule.Set( n, aFmt );

						if( n == nLvl &&
							nFrmWidth < ( nSpaceSteps * MAXLEVEL ) )
							nSpaceSteps = static_cast<sal_uInt16>(( nFrmWidth - nLeftTxtPos ) /
												( MAXLEVEL - nLvl ));
					}
				}
			}
		}
		else
		{
			bChgBullet = sal_True;
			SetColl( static_cast<sal_uInt16>(RES_POOLCOLL_BUL_LEVEL1 + ( Min( nLvl, cnNumBullColls ) * 4 )) );
		}
	}
	else
	{
		// dann ist das eine Nummerierung

		//JP 21.11.97: Der NumLevel wird entweder der DigitLevel oder
		// 				wenn der nicht vorhanden oder 0 ist, durch den
		//				(Einrueckungs-)Level.

		String aPostFix, aPreFix, aNumTypes;
		if( USHRT_MAX != ( nDigitLevel = GetDigitLevel( *pAktTxtNd, nTxtStt,
										&aPreFix, &aPostFix, &aNumTypes )) )
		{
			bChgEnum = sal_True;

			// Ebene 0 und Einrueckung dann wird die Ebene durch den linken
			// Einzug und der default NumEinrueckung bestimmt.
			if( !nDigitLevel && nLeftTxtPos )
				nLvl = Min( sal_uInt16( nLeftTxtPos / lNumIndent ),
							sal_uInt16( MAXLEVEL - 1 ) );
			else
				nLvl = nDigitLevel;
		}

		if( bChgEnum && aFlags.bSetNumRule )
		{
			if( !pCur )			// NumRule anpassen, wenn sie neu ist
			{
				SwCharFmt* pCFmt = pDoc->GetCharFmtFromPool(
											RES_POOLCHR_NUM_LEVEL );
				if( !nDigitLevel )
				{
					SwNumFmt aFmt( aRule.Get( nLvl ) );
					aFmt.SetStart( static_cast<sal_uInt16>(aPreFix.GetToken( 1,
											(sal_Unicode)1 ).ToInt32()));
					aFmt.SetPrefix( aPreFix.GetToken( 0, (sal_Unicode)1 ));
					aFmt.SetSuffix( aPostFix.GetToken( 0, (sal_Unicode)1 ));
					aFmt.SetIncludeUpperLevels( 0 );

					if( !aFmt.GetCharFmt() )
						aFmt.SetCharFmt( pCFmt );

					if( aNumTypes.Len() )
						aFmt.SetNumberingType(aNumTypes.GetChar( 0 ) - '0');

                    if( bRTL )
                        aFmt.SetNumAdjust( SVX_ADJUST_RIGHT );
					aRule.Set( nLvl, aFmt );
				}
				else
				{
					sal_uInt16 nSpaceSteps = nLvl ? sal_uInt16(nLeftTxtPos / nLvl) : 0;
                    sal_uInt8 n;
                    for( n = 0; n <= nLvl; ++n )
					{
						SwNumFmt aFmt( aRule.Get( n ) );

						aFmt.SetStart( static_cast<sal_uInt16>(aPreFix.GetToken( n+1,
													(sal_Unicode)1 ).ToInt32() ));
						if( !n )
							aFmt.SetPrefix( aPreFix.GetToken( n, (sal_Unicode)1 ));
						aFmt.SetSuffix( aPostFix.GetToken( n, (sal_Unicode)1 ));
						aFmt.SetIncludeUpperLevels( MAXLEVEL );
						if( n < aNumTypes.Len() )
							aFmt.SetNumberingType((aNumTypes.GetChar( n ) - '0'));

						aFmt.SetAbsLSpace( sal_uInt16( nSpaceSteps * n )
											+ lNumIndent );

						if( !aFmt.GetCharFmt() )
							aFmt.SetCharFmt( pCFmt );
                        if( bRTL )
                            aFmt.SetNumAdjust( SVX_ADJUST_RIGHT );

						aRule.Set( n, aFmt );
					}

					// passt alles vollstaendig in den Frame?
					sal_Bool bDefStep = nFrmWidth < (nSpaceSteps * MAXLEVEL);
					for( ; n < MAXLEVEL; ++n )
					{
						SwNumFmt aFmt( aRule.Get( n ) );
						aFmt.SetIncludeUpperLevels( MAXLEVEL );
						if( bDefStep )
							aFmt.SetAbsLSpace( sal_uInt16( (nLeftTxtPos +
                                SwNumRule::GetNumIndent(static_cast<sal_uInt8>(n-nLvl)))));
						else
							aFmt.SetAbsLSpace( sal_uInt16( nSpaceSteps * n )
												+ lNumIndent );
						aRule.Set( n, aFmt );
					}
				}
			}
		}
		else if( !aFlags.bAFmtByInput )
			SetColl( static_cast<sal_uInt16>(RES_POOLCOLL_NUM_LEVEL1 + ( Min( nLvl, cnNumBullColls ) * 4 ) ));
		else
			bChgEnum = sal_False;
	}

	if( bChgEnum || bChgBullet )
	{
		aDelPam.DeleteMark();
		aDelPam.GetPoint()->nNode = aNdIdx;

		if( aFlags.bSetNumRule )
		{
			if( aFlags.bAFmtByInput )
			{
				aDelPam.SetMark();
				aDelPam.GetMark()->nNode++;
                aDelPam.GetNode(sal_False)->GetTxtNode()->SetAttrListLevel( nLvl );
			}

            pAktTxtNd->SetAttrListLevel(nLvl);
			pAktTxtNd->SetNumLSpace( sal_True );

            // --> OD 2008-03-17 #refactorlists#
            // start new list
            pDoc->SetNumRule( aDelPam, aRule, true );
            // <--
			aDelPam.DeleteMark();

			aDelPam.GetPoint()->nContent.Assign( pAktTxtNd, 0 );
		}
		else
			aDelPam.GetPoint()->nContent.Assign( pAktTxtNd,
						bChgEnum ? (nTxtStt - nOrigTxtStt) : 0 );
		aDelPam.SetMark();

		if( bChgBullet )
			nTxtStt += 2;

		while( nTxtStt < rStr.Len() && IsSpace( rStr.GetChar( nTxtStt ) ))
			nTxtStt++;

		aDelPam.GetPoint()->nContent = nTxtStt - nOrigTxtStt;
		DeleteSel( aDelPam );

		if( !aFlags.bSetNumRule )
		{
			String sChgStr( '\t' );
			if( bChgBullet )
				sChgStr.Insert( aFlags.cBullet, 0 );
            pDoc->InsertString( aDelPam, sChgStr );

			SfxItemSet aSet( pDoc->GetAttrPool(), aTxtNodeSetRange );
			if( bChgBullet )
			{
				aDelPam.GetPoint()->nContent = 0;
				aDelPam.SetMark();
				aDelPam.GetMark()->nContent = 1;
				SetAllScriptItem( aSet,
					 SvxFontItem( aFlags.aBulletFont.GetFamily(),
								  aFlags.aBulletFont.GetName(),
								  aFlags.aBulletFont.GetStyleName(),
								  aFlags.aBulletFont.GetPitch(),
                                  aFlags.aBulletFont.GetCharSet(),
                                  RES_CHRATR_FONT ) );
				pDoc->SetFmtItemByAutoFmt( aDelPam, aSet );
				aDelPam.DeleteMark();
				nAutoCorrPos = 2;
				aSet.ClearItem();
			}
            SvxTabStopItem aTStops( RES_PARATR_TABSTOP );    aTStops.Insert( SvxTabStop( 0 ));
			aSet.Put( aTStops );
			pDoc->SetFmtItemByAutoFmt( aDelPam, aSet );
		}
	}

	if( bBreak )
	{
		AutoCorrect( nAutoCorrPos );	   /* Offset wegen Bullet + Tab */
		return;
	}

	const SwTxtNode* pNxtNd = GetNextNode();
	while( CanJoin( pNxtNd ) &&
			nLvl == CalcLevel( *pNxtNd ) )
	{
		SetRedlineTxt( STR_AUTOFMTREDL_DEL_MORELINES );
		bBreak = !IsFastFullLine( *pNxtNd ) || IsBlanksInString( *pNxtNd ) ||
				IsSentenceAtEnd( *pNxtNd );
		if( DeleteAktNxtPara( pNxtNd->GetTxt() ) )
        {
            pDoc->InsertString( aDelPam, sal_Unicode(' ') );
        }
		if( bBreak )
			break;
        const SwTxtNode* pCurrNode = pNxtNd;
		pNxtNd = GetNextNode();
        if(!pNxtNd || pCurrNode == pNxtNd)
            break;
	}
	DeleteAktPara( sal_False, sal_True );
	AutoCorrect( nAutoCorrPos );
}


void SwAutoFormat::BuildNegIndent( SwTwips nSpaces )
{
	SetRedlineTxt( STR_AUTOFMTREDL_SET_TMPL_NEG_INDENT );
	// Test auf Gegenueberstellung:
	// (n Worte, durch Space/Tabs getrennt, mit gleicher
	//   Einrueckung in der 2.Zeile)

	// lese alle nachfolgenden Absaetze die zu dieser Aufzaehlung gehoeren
	sal_Bool bBreak = sal_True;
	xub_StrLen nSpacePos, nTxtPos = GetBigIndent( nSpacePos );
	if( bMoreLines )
		DelMoreLinesBlanks( sal_True );
	else
		bBreak = !IsFastFullLine( *pAktTxtNd ) ||
					( !nTxtPos && IsBlanksInString( *pAktTxtNd )) ||
					IsSentenceAtEnd( *pAktTxtNd );

	SetColl( static_cast<sal_uInt16>( nTxtPos
				? RES_POOLCOLL_CONFRONTATION
				: RES_POOLCOLL_TEXT_NEGIDENT ) );

	if( nTxtPos )
	{
		const String& rStr = pAktTxtNd->GetTxt();
		sal_Bool bInsTab = sal_True;

		if( '\t' == rStr.GetChar( nSpacePos+1 ))       // ein Tab, das belassen wir
		{
			--nSpacePos;
			bInsTab = sal_False;
		}

		xub_StrLen nSpaceStt = nSpacePos;
		while( nSpaceStt && IsSpace( rStr.GetChar( --nSpaceStt ) ) )
			;
		++nSpaceStt;

		if( bInsTab && '\t' == rStr.GetChar( nSpaceStt ) )		// ein Tab, das belassen wir
		{
			++nSpaceStt;
			bInsTab = sal_False;
		}


		aDelPam.DeleteMark();
		aDelPam.GetPoint()->nNode = aNdIdx;
		aDelPam.GetPoint()->nContent.Assign( pAktTxtNd, nSpacePos );

		// alten Spaces, usw. loeschen
		if( nSpaceStt < nSpacePos )
		{
			aDelPam.SetMark();
			aDelPam.GetMark()->nContent = nSpaceStt;
			DeleteSel( aDelPam );
			if( bInsTab )
            {
                pDoc->InsertString( aDelPam, sal_Unicode('\t') );
            }
        }
    }

	if( !bBreak )
	{
		SetRedlineTxt( STR_AUTOFMTREDL_DEL_MORELINES );
		SwTxtFrmInfo aFInfo( pAktTxtFrm );
		const SwTxtNode* pNxtNd = GetNextNode();
		while(	CanJoin( pNxtNd ) &&
				20 < Abs( (long)(nSpaces - aFInfo.SetFrm(
								GetFrm( *pNxtNd ) ).GetLineStart() ))
			)
		{
			bBreak = !IsFastFullLine( *pNxtNd ) ||
					IsBlanksInString( *pNxtNd ) ||
					IsSentenceAtEnd( *pNxtNd );
			if( DeleteAktNxtPara( pNxtNd->GetTxt() ) )
            {
                pDoc->InsertString( aDelPam, sal_Unicode(' ') );
            }
			if( bBreak )
				break;
			pNxtNd = GetNextNode();
		}
	}
	DeleteAktPara( sal_True, sal_True );
	AutoCorrect();
}


void SwAutoFormat::BuildHeadLine( sal_uInt16 nLvl )
{
	if( aFlags.bWithRedlining )
	{
		String sTxt( *ViewShell::GetShellRes()->GetAutoFmtNameLst()[
									STR_AUTOFMTREDL_SET_TMPL_HEADLINE ] );
		sTxt.SearchAndReplace( String::CreateFromAscii(
									RTL_CONSTASCII_STRINGPARAM( "$(ARG1)" )),
								String::CreateFromInt32( nLvl + 1 ) );
		pDoc->SetAutoFmtRedlineComment( &sTxt );
	}

	SetColl( static_cast<sal_uInt16>(RES_POOLCOLL_HEADLINE1 + nLvl ), sal_True );
	if( aFlags.bAFmtByInput )
	{
		SwTxtFmtColl& rNxtColl = pAktTxtNd->GetTxtColl()->GetNextTxtFmtColl();

		DelPrevPara();

		DeleteAktPara( sal_True, sal_False );
		DeleteAktNxtPara( aEmptyStr );

		aDelPam.DeleteMark();
		aDelPam.GetPoint()->nNode = aNdIdx.GetIndex() + 1;
		aDelPam.GetPoint()->nContent.Assign( aDelPam.GetCntntNode(), 0 );
		pDoc->SetTxtFmtColl( aDelPam, &rNxtColl );
	}
	else
	{
		DeleteAktPara( sal_True, sal_True );
		AutoCorrect();
	}
}


		// dann lasse doch mal das AutoCorrect auf den akt. TextNode los
void SwAutoFormat::AutoCorrect( xub_StrLen nPos )
{
	SvxAutoCorrect* pATst = SvxAutoCorrCfg::Get()->GetAutoCorrect();
    long aSvxFlags = pATst->GetFlags( );
    bool bReplaceQuote = ( aSvxFlags & ChgQuotes ) > 0;
    bool bReplaceSglQuote = ( aSvxFlags & ChgSglQuotes ) > 0;

	if( aFlags.bAFmtByInput ||
		(!aFlags.bAutoCorrect && !bReplaceQuote && !bReplaceSglQuote &&
		!aFlags.bCptlSttSntnc && !aFlags.bCptlSttWrd &&
		!aFlags.bChgOrdinalNumber &&
		!aFlags.bChgToEnEmDash && !aFlags.bSetINetAttr &&
		!aFlags.bChgWeightUnderl && !aFlags.bAddNonBrkSpace) )
		return;

	const String* pTxt = &pAktTxtNd->GetTxt();
	if( nPos >= pTxt->Len() )
		return;

	sal_Bool bGetLanguage = aFlags.bChgOrdinalNumber ||
						aFlags.bChgToEnEmDash || aFlags.bSetINetAttr ||
						aFlags.bCptlSttWrd || aFlags.bCptlSttSntnc ||
                        aFlags.bAddNonBrkSpace;


	aDelPam.DeleteMark();
	aDelPam.GetPoint()->nNode = aNdIdx;
	aDelPam.GetPoint()->nContent.Assign( pAktTxtNd, 0 );

	SwAutoCorrDoc aACorrDoc( *pEditShell, aDelPam );

	SwTxtFrmInfo aFInfo( 0 );

	xub_StrLen nSttPos, nLastBlank = nPos;
	sal_Bool bFirst = aFlags.bCptlSttSntnc, bFirstSent = bFirst;
    sal_Unicode cChar = 0;

	CharClass& rAppCC = GetAppCharClass();

	do {
		while( nPos < pTxt->Len() && IsSpace( cChar = pTxt->GetChar( nPos ) ))
			++nPos;
		if( nPos == pTxt->Len() )
			break;		// das wars

		if( ( ( bReplaceQuote && '\"' == cChar ) || 
              ( bReplaceSglQuote && '\'' == cChar ) ) &&
			( !nPos || ' ' == pTxt->GetChar( nPos-1 ) ) )
		{
			// --------------------------------------
			// beachte: Sonderfall Symbolfonts !!!
			if( !aFInfo.GetFrm() )
				aFInfo.SetFrm( GetFrm( *pAktTxtNd ) );
			if( !aFInfo.IsBullet( nPos ))
			{
				SetRedlineTxt( STR_AUTOFMTREDL_TYPO );
				aDelPam.GetPoint()->nContent = nPos;
				sal_Bool bSetHardBlank = sal_False;

				String sReplace( pATst->GetQuote( aACorrDoc,
									nPos, cChar, sal_True ));

				aDelPam.SetMark();
				aDelPam.GetPoint()->nContent = nPos+1;
				if( 2 == sReplace.Len() && ' ' == sReplace.GetChar( 1 ))
				{
					sReplace.Erase( 1 );
					bSetHardBlank = sal_True;
				}
                pDoc->ReplaceRange( aDelPam, sReplace, false );

				if( aFlags.bWithRedlining )
				{
					aNdIdx = aDelPam.GetPoint()->nNode;
					pAktTxtNd = aNdIdx.GetNode().GetTxtNode();
					pTxt = &pAktTxtNd->GetTxt();
					aDelPam.SetMark();
					aFInfo.SetFrm( 0 );
				}

				nPos += sReplace.Len() - 1;
				aDelPam.DeleteMark();
				if( bSetHardBlank )
				{
                    pDoc->InsertString( aDelPam, CHAR_HARDBLANK );
					++nPos;
				}
			}
		}

		int bCallACorr = sal_False;
		int bBreak = 0;
		if( nPos && IsSpace( pTxt->GetChar( nPos-1 )))
			nLastBlank = nPos;
		for( nSttPos = nPos; !bBreak && nPos < pTxt->Len(); ++nPos )
			switch( cChar = pTxt->GetChar( nPos ) )
			{
			case '\"':
			case '\'':
				if( ( cChar == '\"' && bReplaceQuote ) || ( cChar == '\'' && bReplaceSglQuote ) )
				{
					// --------------------------------------
					// beachte: Sonderfall Symbolfonts !!!
					if( !aFInfo.GetFrm() )
						aFInfo.SetFrm( GetFrm( *pAktTxtNd ) );
					if( !aFInfo.IsBullet( nPos ))
					{
						SetRedlineTxt( STR_AUTOFMTREDL_TYPO );
						sal_Bool bSetHardBlank = sal_False;
						aDelPam.GetPoint()->nContent = nPos;
						String sReplace( pATst->GetQuote( aACorrDoc,
													nPos, cChar, sal_False ));

						if( 2 == sReplace.Len() && ' ' == sReplace.GetChar( 0 ))
						{
							sReplace.Erase( 0, 1 );
							bSetHardBlank = sal_True;
						}

						aDelPam.SetMark();
						aDelPam.GetPoint()->nContent = nPos+1;
                        pDoc->ReplaceRange( aDelPam, sReplace, false );

						if( aFlags.bWithRedlining )
						{
							aNdIdx = aDelPam.GetPoint()->nNode;
							pAktTxtNd = aNdIdx.GetNode().GetTxtNode();
							pTxt = &pAktTxtNd->GetTxt();
							aDelPam.SetMark();
							aDelPam.DeleteMark();
							aFInfo.SetFrm( 0 );
						}

						nPos += sReplace.Len() - 1;
						aDelPam.DeleteMark();

						if( bSetHardBlank )
						{
							aDelPam.GetPoint()->nContent = nPos;
                            pDoc->InsertString( aDelPam, CHAR_HARDBLANK );
							aDelPam.GetPoint()->nContent = ++nPos;
						}
					}
				}
				break;
			case '*':
			case '_':
				if( aFlags.bChgWeightUnderl )
				{
					// --------------------------------------
					// beachte: Sonderfall Symbolfonts !!!
					if( !aFInfo.GetFrm() )
						aFInfo.SetFrm( GetFrm( *pAktTxtNd ) );
					if( !aFInfo.IsBullet( nPos ))
					{
						SetRedlineTxt( '*' == cChar
											? STR_AUTOFMTREDL_BOLD
											: STR_AUTOFMTREDL_UNDER );

						sal_Unicode cBlank = nSttPos ? pTxt->GetChar(nSttPos - 1) : 0;
						aDelPam.GetPoint()->nContent = nPos;

						if( pATst->FnChgWeightUnderl( aACorrDoc, *pTxt,
															nSttPos, nPos ))
						{
                            if( aFlags.bWithRedlining )
                            {
                                aNdIdx = aDelPam.GetPoint()->nNode;
                                pAktTxtNd = aNdIdx.GetNode().GetTxtNode();
                                pTxt = &pAktTxtNd->GetTxt();
                                aDelPam.SetMark();
                                aDelPam.DeleteMark();
                                aFInfo.SetFrm( 0 );
                            }
                            //#125102# in case of the mode REDLINE_SHOW_DELETE the ** are still contained in pTxt
                            if(0 == (pDoc->GetRedlineMode() & nsRedlineMode_t::REDLINE_SHOW_DELETE))
                                nPos = aDelPam.GetPoint()->nContent.GetIndex() - 1;
							// wurde vorm Start ein Zeichen entfernt?
							if( cBlank && cBlank != pTxt->GetChar(nSttPos - 1) )
								--nSttPos;
						}
					}
				}
				break;
            case '/':
                if ( aFlags.bAddNonBrkSpace )
                {
			        LanguageType eLang = (bGetLanguage && pAktTxtNd)
										   ? pAktTxtNd->GetLang( nSttPos )
										   : LANGUAGE_SYSTEM;
                
                    SetRedlineTxt( STR_AUTOFMTREDL_NON_BREAK_SPACE );
                    if ( pATst->FnAddNonBrkSpace( aACorrDoc, *pTxt, nSttPos, nPos, eLang ) )
                        --nPos;
                }
                break;

			case '.':
			case '!':
			case '?':
				if( aFlags.bCptlSttSntnc )
					bFirstSent = sal_True;
//alle Wortrenner loesen die Autokorrektur aus!
//				break;
			default:
//alle Wortrenner loesen die Autokorrektur aus!
//			case ' ':
//			case '\t':
				if( !( rAppCC.isLetterNumeric( *pTxt, nPos )
                        || '/' == cChar )) //  '/' should not be a word seperator (e.g. '1/2' needs to be handled as one word for replacement)
				{
					--nPos;		// ++nPos von dem for ungueltig machen !
					++bBreak;
				}
				break;
			}

		if( nPos == nSttPos )
		{
			if( ++nPos == pTxt->Len() )
				bCallACorr = sal_True;
		}
		else
			bCallACorr = sal_True;


		if( bCallACorr )
		{
			bCallACorr = sal_False;
			aDelPam.GetPoint()->nContent = nPos;
			SetRedlineTxt( STR_AUTOFMTREDL_USE_REPLACE );
			if( aFlags.bAutoCorrect &&
				aACorrDoc.ChgAutoCorrWord( nSttPos, nPos, *pATst, 0 ) )
			{
				nPos = aDelPam.GetPoint()->nContent.GetIndex();

				if( aFlags.bWithRedlining )
				{
					aNdIdx = aDelPam.GetPoint()->nNode;
					pAktTxtNd = aNdIdx.GetNode().GetTxtNode();
					pTxt = &pAktTxtNd->GetTxt();
					aDelPam.SetMark();
					aDelPam.DeleteMark();
				}

				continue;		// nichts weiter mehr abpruefen
			}

			LanguageType eLang = (bGetLanguage && pAktTxtNd)
										   ? pAktTxtNd->GetLang( nSttPos )
										   : LANGUAGE_SYSTEM;
                
            if ( aFlags.bAddNonBrkSpace )
            {
                SetRedlineTxt( STR_AUTOFMTREDL_NON_BREAK_SPACE );
                pATst->FnAddNonBrkSpace( aACorrDoc, *pTxt, nSttPos, nPos, eLang );
            }

			if( ( aFlags.bChgOrdinalNumber &&
					SetRedlineTxt( STR_AUTOFMTREDL_ORDINAL ) &&
					pATst->FnChgOrdinalNumber( aACorrDoc, *pTxt, nSttPos, nPos, eLang ) ) ||
				( aFlags.bChgToEnEmDash &&
					SetRedlineTxt( STR_AUTOFMTREDL_DASH ) &&
					pATst->FnChgToEnEmDash( aACorrDoc, *pTxt, nSttPos, nPos, eLang ) ) ||
				( aFlags.bSetINetAttr &&
					( nPos == pTxt->Len() || IsSpace( pTxt->GetChar( nPos )) ) &&
					SetRedlineTxt( STR_AUTOFMTREDL_DETECT_URL ) &&
					pATst->FnSetINetAttr( aACorrDoc, *pTxt, nLastBlank, nPos, eLang ) ) )
					nPos = aDelPam.GetPoint()->nContent.GetIndex();
			else
			{
				// Zwei Grossbuchstaben am Wort-Anfang ??
				if( aFlags.bCptlSttWrd )
				{
					SetRedlineTxt( STR_AUTOFMTREDL_CPTL_STT_WORD );
					pATst->FnCptlSttWrd( aACorrDoc, *pTxt, nSttPos, nPos, eLang );
				}
				// Grossbuchstabe am Satz-Anfang ??
				if( aFlags.bCptlSttSntnc && bFirst )
				{
					SetRedlineTxt( STR_AUTOFMTREDL_CPTL_STT_SENT );
					pATst->FnCptlSttSntnc( aACorrDoc, *pTxt, sal_True, nSttPos, nPos, eLang);
					bFirst = sal_False;
				}

				bFirst = bFirstSent;
				bFirstSent = sal_False;

				if( aFlags.bWithRedlining )
				{
					aNdIdx = aDelPam.GetPoint()->nNode;
					pAktTxtNd = aNdIdx.GetNode().GetTxtNode();
					pTxt = &pAktTxtNd->GetTxt();
					aDelPam.SetMark();
					aDelPam.DeleteMark();
				}
			}
		}
	} while( nPos < pTxt->Len() );
	ClearRedlineTxt();
}


SwAutoFormat::SwAutoFormat( SwEditShell* pEdShell, SvxSwAutoFmtFlags& rFlags,
							SwNodeIndex* pSttNd, SwNodeIndex* pEndNd )
	: aFlags( rFlags ),
	aDelPam( pEdShell->GetDoc()->GetNodes().GetEndOfExtras() ),
	aNdIdx( pEdShell->GetDoc()->GetNodes().GetEndOfExtras(), +1 ),
	aEndNdIdx( pEdShell->GetDoc()->GetNodes().GetEndOfContent() ),
	pEditShell( pEdShell ),
	pDoc( pEdShell->GetDoc() ),
	pAktTxtNd( 0 ), pAktTxtFrm( 0 ),
	pCharClass( 0 ),
	nRedlAutoFmtSeqId( 0 )
{
	ASSERT( (pSttNd && pEndNd) || (!pSttNd && !pEndNd),
			"Kein Bereich angegeben" );

	if( aFlags.bSetNumRule && !aFlags.bAFmtByInput )
		aFlags.bSetNumRule = sal_False;

	sal_Bool bReplaceStyles = !aFlags.bAFmtByInput || aFlags.bReplaceStyles;

    const SwTxtNode* pNxtNd = 0;
    sal_Bool bNxtEmpty = sal_False;
    sal_Bool bNxtAlpha = sal_False;
    sal_uInt16 nNxtLevel = 0;

	// setze den Bereich zum Autoformatieren
	if( pSttNd )
	{
		aNdIdx = *pSttNd;
		aNdIdx--;			// fuer GoNextPara, ein Absatz davor
		aEndNdIdx = *pEndNd;
		aEndNdIdx++;

		// teste den vorhergehenden TextNode
		pNxtNd = aNdIdx.GetNode().GetTxtNode();
		bEmptyLine = !pNxtNd ||
					IsEmptyLine( *pNxtNd ) ||
					IsNoAlphaLine( *pNxtNd );
	}
	else
		bEmptyLine = sal_True;		// am Dokument Anfang

	bEnde = sal_False;

	// setze die Werte fuer die Prozent-Anzeige
	nEndNdIdx = aEndNdIdx.GetIndex();

	if( !aFlags.bAFmtByInput )
		::StartProgress( STR_STATSTR_AUTOFORMAT, aNdIdx.GetIndex(),
						 nEndNdIdx = aEndNdIdx.GetIndex(),
						 pDoc->GetDocShell() );

	RedlineMode_t eRedlMode = pDoc->GetRedlineMode(), eOldMode = eRedlMode;
	if( aFlags.bWithRedlining )
	{
		pDoc->SetAutoFmtRedline( sal_True );
		eRedlMode = (RedlineMode_t)(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_SHOW_INSERT);
	}
	else
	  eRedlMode = (RedlineMode_t)(nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_IGNORE);
	pDoc->SetRedlineMode( eRedlMode );

    // save undo state (might be turned off)
    bool const bUndoState = pDoc->GetIDocumentUndoRedo().DoesUndo();

	// wenn mehrere Zeilen, dann erstmal nicht mit
	// dem nachfolgenden Absatz zusammenfassen.
	bMoreLines = sal_False;

	nLastCalcHeadLvl = nLastCalcEnumLvl = 0;
	nLastHeadLvl = nLastEnumLvl = USHRT_MAX;
    sal_uInt16 nLevel = 0;
    sal_uInt16 nDigitLvl = 0;

	// defaulten
	SwTxtFrmInfo aFInfo( 0 );

	// das ist unser Automat fuer die Auto-Formatierung
	eStat = READ_NEXT_PARA;
	while( !bEnde )
	{
		switch( eStat )
		{
		case READ_NEXT_PARA:
			{
				GoNextPara();
				eStat = bEnde ? IS_ENDE : TST_EMPTY_LINE;
			}
			break;

		case TST_EMPTY_LINE:
			if( IsEmptyLine( *pAktTxtNd ) )
			{
				if( aFlags.bDelEmptyNode && !HasObjects( *pAktTxtNd ) )
				{
					bEmptyLine = sal_True;
					sal_uLong nOldCnt = pDoc->GetNodes().Count();
					DelEmptyLine();
					// wurde wiklich ein Node geloescht ?
					if( nOldCnt != pDoc->GetNodes().Count() )
						aNdIdx--;		// nicht den naechsten Absatz ueberspringen
				}
				eStat = READ_NEXT_PARA;
			}
			else
				eStat = TST_ALPHA_LINE;
			break;

		case TST_ALPHA_LINE:
			if( IsNoAlphaLine( *pAktTxtNd ))
			{
				// erkenne eine Tabellendefinition +---+---+
				if( aFlags.bAFmtByInput && aFlags.bCreateTable && DoTable() )
				{
					//JP 30.09.96: das DoTable() verlaesst sich auf das
					//				Pop und Move - Crsr nach dem AutoFormat!
					pEdShell->Pop( sal_False );
					*pEdShell->GetCrsr() = aDelPam;
					pEdShell->Push();

					eStat = IS_ENDE;
					break;
				}

				// dann teste mal auf 3 "---" oder "===". In dem Fall
				// soll der vorherige Absatz unterstrichen und dieser
				// geloescht werden!
				if( !DoUnderline() && bReplaceStyles )
				{
					SetColl( RES_POOLCOLL_STANDARD, sal_True );
					bEmptyLine = sal_True;
				}
				eStat = READ_NEXT_PARA;
			}
			else
				eStat = GET_ALL_INFO;
			break;

		case GET_ALL_INFO:
			{
				if( pAktTxtNd->GetNumRule() )
				{
					// in Numerierung nichts machen, zum naechsten
					bEmptyLine = sal_False;
					eStat = READ_NEXT_PARA;
					// loesche alle Blanks am Anfang/Ende
					// und alle mitten drin
					//JP 29.04.98: erstmal nur alle "mitten drin".
					DelMoreLinesBlanks( sal_False );
					break;
				}

				aFInfo.SetFrm( pAktTxtFrm );

				// erstmal: wurden schon mal entsprechende Vorlagen
				//			vergeben, so behalte die bei, gehe zum
				//			naechsten Node.
				sal_uInt16 nPoolId = pAktTxtNd->GetTxtColl()->GetPoolFmtId();
				if( IsPoolUserFmt( nPoolId )
						? !aFlags.bChgUserColl
						: ( RES_POOLCOLL_STANDARD != nPoolId &&
						   ( !aFlags.bAFmtByInput ||
							(RES_POOLCOLL_TEXT_MOVE != nPoolId &&
							 RES_POOLCOLL_TEXT != nPoolId )) ))
				{
					eStat = HAS_FMTCOLL;
					break;
				}

				// teste auf Harte oder aus Vorlagen gesetzte LRSpaces
				if( IsPoolUserFmt( nPoolId ) ||
					RES_POOLCOLL_STANDARD == nPoolId )
				{
					short nSz;
					SvxLRSpaceItem* pLRSpace;
					if( SFX_ITEM_SET == pAktTxtNd->GetSwAttrSet().
						GetItemState( RES_LR_SPACE, sal_True,
										(const SfxPoolItem**)&pLRSpace ) &&
						( 0 != (nSz = pLRSpace->GetTxtFirstLineOfst()) ||
							0 != pLRSpace->GetTxtLeft() ) )
					{
						// Ausnahme: Numerierun/Aufzaehlung kann mit Einzug
						//		existieren!!
						if( IsEnumericChar( *pAktTxtNd ))
						{
							nLevel = CalcLevel( *pAktTxtNd, &nDigitLvl );
							if( nLevel >= MAXLEVEL )
								nLevel = MAXLEVEL-1;
							BuildEnum( nLevel, nDigitLvl );
							eStat = READ_NEXT_PARA;
							break;
						}


						// nie zusammenfassen, so belassen
						// (Opt. vielleicht als Ausnahmen nur Einzug)
						bMoreLines = sal_True;

						if( bReplaceStyles )
						{
							// dann setze doch eine unserer Vorlagen
							if( 0 < nSz )			// positiver 1. Zeileneinzug
								BuildIndent();
							else if( 0 > nSz )		// negativer 1. Zeileneinzug
								BuildNegIndent( aFInfo.GetLineStart() );
							else if( pLRSpace->GetTxtLeft() )	// ist ein Einzug
								BuildTextIndent();
						}
						eStat = READ_NEXT_PARA;
						break;
					}
				}

				nLevel = CalcLevel( *pAktTxtNd, &nDigitLvl );
				bMoreLines = !IsOneLine( *pAktTxtNd );
				pNxtNd = GetNextNode();
				if( pNxtNd )
				{
					bNxtEmpty = IsEmptyLine( *pNxtNd );
					bNxtAlpha = IsNoAlphaLine( *pNxtNd );
					nNxtLevel = CalcLevel( *pNxtNd );

					if( !bEmptyLine && HasBreakAttr( *pAktTxtNd ) )
						bEmptyLine = sal_True;
					if( !bNxtEmpty && HasBreakAttr( *pNxtNd ) )
						bNxtEmpty = sal_True;

					// fuer z.B. selbst definierte Einzuege oder
					// rechts/zentierte Ausrichtung
//					if( !nLevel && 0 != aFInfo.GetLineStart() )
//						nLevel = 1;
				}
				else
				{
					bNxtEmpty = sal_False; // sal_True;
					bNxtAlpha = sal_False;
					nNxtLevel = 0;
				}
				eStat = !bMoreLines ? IS_ONE_LINE : TST_ENUMERIC;
			}
			break;

		case IS_ONE_LINE:
			{
				eStat = TST_ENUMERIC;
				if( !bReplaceStyles )
					break;

				String sClrStr( pAktTxtNd->GetTxt() );

				if( !DelLeadingBlanks( sClrStr ).Len() )
				{
					bEmptyLine = sal_True;
					eStat = READ_NEXT_PARA;
					break;		// naechsten Absatz lesen
				}

				// Teste auf Ueberschrift
				if( !bEmptyLine || !IsFirstCharCapital( *pAktTxtNd ) ||
					IsBlanksInString( *pAktTxtNd ) )
					break;

				bEmptyLine = sal_False;
				String sEndClrStr( sClrStr );
				xub_StrLen nLen = DelTrailingBlanks( sEndClrStr ).Len();

				// nicht, dann teste auf Ueberschrift
				if( ':' == sEndClrStr.GetChar( nLen - 1 ) )
				{
//---------------------------------------------------------------------------
// Wie ist denn nun die Bedingung fuer die Ueberschrift auf Ebene 3 ??
// Zur Zeit: generell wenn am Ende ein ':' ist.
//
//					if( bNxtEmpty || bNxtAlpha )
//						!IsEnumericChar( *pNxtNd ) )
//---------------------------------------------------------------------------
					{
						BuildHeadLine( 2 );
						eStat = READ_NEXT_PARA;
						break;
					}
				}
				else if( 256 <= sEndClrStr.GetChar( nLen-1 ) ||
						 !strchr( ",.;", sEndClrStr.GetChar( nLen-1 )) )
				{
					if( bNxtEmpty || bNxtAlpha
						|| ( pNxtNd && IsEnumericChar( *pNxtNd ))

//---------------------------------------------------------------------------
// ist zum Verwechseln mit neg. Einzug !!
						/*|| nLevel < nNxtLevel*/
//---------------------------------------------------------------------------

						)
					{
						// wurde Level vom Text vorgegeben ?
//						if( USHRT_MAX != nDigitLvl )
//							nLevel = nDigitLvl;

						// eine Ebene runter ?
						if( nLevel >= MAXLEVEL )
							nLevel = MAXLEVEL-1;

						if( USHRT_MAX == nLastHeadLvl )
							nLastHeadLvl = 0;
						else if( nLastCalcHeadLvl < nLevel )
						{
							if( nLastHeadLvl+1 < MAXLEVEL )
								++nLastHeadLvl;
						}
						// eine Ebene hoch ?
						else if( nLastCalcHeadLvl > nLevel )
						{
							if( nLastHeadLvl )
								--nLastHeadLvl;
						}
						nLastCalcHeadLvl = nLevel;

						if( aFlags.bAFmtByInput )
							BuildHeadLine( nLevel );
						else
							BuildHeadLine( nLastHeadLvl );
						eStat = READ_NEXT_PARA;
						break;
					}
				}
			}
			break;

		case TST_ENUMERIC:
			{
				bEmptyLine = sal_False;
				if( IsEnumericChar( *pAktTxtNd ))
				{
					if( nLevel >= MAXLEVEL )
						nLevel = MAXLEVEL-1;
					BuildEnum( nLevel, nDigitLvl );
					eStat = READ_NEXT_PARA;
				}
//JP 25.03.96: Vorlagen fuer Einzug zulassen
//				else if( aFlags.bAFmtByInput )
//					eStat = READ_NEXT_PARA;
				else if( bReplaceStyles )
					eStat = nLevel ? TST_IDENT : TST_NEG_IDENT;
				else
					eStat = READ_NEXT_PARA;
			}
			break;

		case TST_IDENT:
			// Spaces am Anfang, dann teste doch mal auf Einzuege
			if( bMoreLines && nLevel )
			{
				SwTwips nSz = aFInfo.GetFirstIndent();
				if( 0 < nSz )			// positiver 1. Zeileneinzug
					BuildIndent();
				else if( 0 > nSz )		// negativer 1. Zeileneinzug
					BuildNegIndent( aFInfo.GetLineStart() );
				else					// ist ein Einzug
					BuildTextIndent();
				eStat = READ_NEXT_PARA;
			}
			else if( nLevel && pNxtNd && !bEnde &&
					 !bNxtEmpty && !bNxtAlpha && !nNxtLevel &&
					 !IsEnumericChar( *pNxtNd ) )
			{
				// ist ein Einzug
				BuildIndent();
				eStat = READ_NEXT_PARA;
			}
			else
				eStat = TST_TXT_BODY;
			break;

		case TST_NEG_IDENT:
			// keine Spaces am Anfang, dann teste doch mal auf neg. Einzuege
			{
				if( bMoreLines && !nLevel )
				{
					SwTwips nSz = aFInfo.GetFirstIndent();
					if( 0 < nSz )			// positiver 1. Zeileneinzug
						BuildIndent();
					else if( 0 > nSz )		// negativer 1. Zeileneinzug
						BuildNegIndent( aFInfo.GetLineStart() );
					else					// ist ein kein Einzug
						BuildText();
					eStat = READ_NEXT_PARA;
				}
				else if( !nLevel && pNxtNd && !bEnde &&
						 !bNxtEmpty && !bNxtAlpha && nNxtLevel &&
						 !IsEnumericChar( *pNxtNd ) )
				{
					// ist ein neg. Einzug
					BuildNegIndent( aFInfo.GetLineStart() );
					eStat = READ_NEXT_PARA;
				}
				else
					eStat = TST_TXT_BODY;
			}
			break;

		case TST_TXT_BODY:
			{
				if( bMoreLines )
				{
					SwTwips nSz = aFInfo.GetFirstIndent();
					if( 0 < nSz )			// positiver 1. Zeileneinzug
						BuildIndent();
					else if( 0 > nSz )		// negativer 1. Zeileneinzug
						BuildNegIndent( aFInfo.GetLineStart() );
					else if( nLevel )		// ist ein Einzug
						BuildTextIndent();
					else
						BuildText();
				}
				else if( nLevel )
					BuildTextIndent();
				else
					BuildText();
				eStat = READ_NEXT_PARA;
			}
			break;

		case HAS_FMTCOLL:
			{
				// erstmal: wurden schon mal entsprechende Vorlagen
				//			vergeben, so behalte die bei, gehe zum
				//			naechsten Node.
				bEmptyLine = sal_False;
				eStat = READ_NEXT_PARA;
				// loesche alle Blanks am Anfang/Ende
				// und alle mitten drin
				//JP 29.04.98: erstmal nur alle "mitten drin".
				DelMoreLinesBlanks( sal_False );

				// behandel die harte Attributierung
                if( pAktTxtNd->HasSwAttrSet() )
				{
					short nSz;
					SvxLRSpaceItem* pLRSpace;
					if( bReplaceStyles &&
                        SFX_ITEM_SET == pAktTxtNd->GetSwAttrSet().
						GetItemState( RES_LR_SPACE, sal_False,
										(const SfxPoolItem**)&pLRSpace ) &&
						( 0 != (nSz = pLRSpace->GetTxtFirstLineOfst()) ||
							0 != pLRSpace->GetTxtLeft() ) )
					{
						// dann setze doch eine unserer Vorlagen
						if( 0 < nSz )			// positiver 1. Zeileneinzug
							BuildIndent();
						else if( 0 > nSz )		// negativer 1. Zeileneinzug
						{
							BuildNegIndent( aFInfo.GetLineStart() );
						}
						else if( pLRSpace->GetTxtLeft() )	// ist ein Einzug
							BuildTextIndent();
						else
							BuildText();
					}
				}
			}
			break;

		case IS_ENDE:
			bEnde = sal_True;
			break;
		}
	}

	if( aFlags.bWithRedlining )
		pDoc->SetAutoFmtRedline( sal_False );
	pDoc->SetRedlineMode( eOldMode );

    // restore undo (in case it has been changed)
    pDoc->GetIDocumentUndoRedo().DoUndo(bUndoState);

	// Prozent-Anzeige wieder abschalten
	if( !aFlags.bAFmtByInput )
		::EndProgress( pDoc->GetDocShell() );
}

void SwEditShell::AutoFormat( const SvxSwAutoFmtFlags* pAFlags )
{
	SwWait* pWait = 0;

	SET_CURR_SHELL( this );
	StartAllAction();
	StartUndo( UNDO_AUTOFORMAT );

	SvxSwAutoFmtFlags aAFFlags;		// erst mal default - Werte
	if( pAFlags )					// oder doch angegeben ??
	{
		aAFFlags = *pAFlags;
		if( !aAFFlags.bAFmtByInput )
			pWait = new SwWait( *GetDoc()->GetDocShell(), sal_True );
	}

	SwPaM* pCrsr = GetCrsr();
	// es gibt mehr als einen oder ist eine Selektion offen
	if( pCrsr->GetNext() != pCrsr || pCrsr->HasMark() )
	{
		FOREACHPAM_START(this)
			if( PCURCRSR->HasMark() )
			{
				SwAutoFormat aFmt( this, aAFFlags, &PCURCRSR->Start()->nNode,
									 &PCURCRSR->End()->nNode );
			}
		FOREACHPAM_END()
	}
	else
	{
		SwAutoFormat aFmt( this, aAFFlags );
	}

	EndUndo( UNDO_AUTOFORMAT );
	EndAllAction();

	delete pWait;
}


void SwEditShell::AutoFmtBySplitNode()
{
	SET_CURR_SHELL( this );
	SwPaM* pCrsr = GetCrsr();
	if( pCrsr->GetNext() == pCrsr && pCrsr->Move( fnMoveBackward, fnGoNode ) )
	{
		StartAllAction();
		StartUndo( UNDO_AUTOFORMAT );

		sal_Bool bRange = sal_False;
		pCrsr->SetMark();
		SwIndex* pCntnt = &pCrsr->GetMark()->nContent;
		if( pCntnt->GetIndex() )
		{
			*pCntnt = 0;
			bRange = sal_True;
		}
		else
		{
			// dann einen Node zurueckspringen
			SwNodeIndex aNdIdx( pCrsr->GetMark()->nNode, -1 );
			SwTxtNode* pTxtNd = aNdIdx.GetNode().GetTxtNode();
			if( pTxtNd && pTxtNd->GetTxt().Len() )
			{
				pCntnt->Assign( pTxtNd, 0 );
				pCrsr->GetMark()->nNode = aNdIdx;
				bRange = sal_True;
			}
		}

		if( bRange )
		{
			Push();		// Cursor sichern

			SvxSwAutoFmtFlags aAFFlags = *GetAutoFmtFlags();		// erst mal default - Werte

			SwAutoFormat aFmt( this, aAFFlags, &pCrsr->GetMark()->nNode,
									&pCrsr->GetPoint()->nNode );

			//JP 30.09.96: das DoTable() verlaesst sich auf das PopCrsr
			//				und MoveCrsr!
			Pop( sal_False );
			pCrsr = GetCrsr();
		}
		pCrsr->DeleteMark();
		pCrsr->Move( fnMoveForward, fnGoNode );

		EndUndo( UNDO_AUTOFORMAT );
		EndAllAction();
	}
}

SvxSwAutoFmtFlags* SwEditShell::GetAutoFmtFlags()
{
	if (!pAutoFmtFlags)
		pAutoFmtFlags = new SvxSwAutoFmtFlags;

	return pAutoFmtFlags;
}

void SwEditShell::SetAutoFmtFlags(SvxSwAutoFmtFlags * pFlags)
{
	SvxSwAutoFmtFlags* pEditFlags = GetAutoFmtFlags();

	pEditFlags->bSetNumRule		= pFlags->bSetNumRule;
	pEditFlags->bChgEnumNum		= pFlags->bChgEnumNum;
	pEditFlags->bSetBorder		= pFlags->bSetBorder;
	pEditFlags->bCreateTable	= pFlags->bCreateTable;
	pEditFlags->bReplaceStyles	= pFlags->bReplaceStyles;
	pEditFlags->bAFmtByInpDelSpacesAtSttEnd =
									pFlags->bAFmtByInpDelSpacesAtSttEnd;
	pEditFlags->bAFmtByInpDelSpacesBetweenLines =
									pFlags->bAFmtByInpDelSpacesBetweenLines;

	//JP 15.12.98: BulletZeichen und Font in die "normalen" kopieren,
	//			weil beim Autoformat nur mit diesen gearbeitet wird!
	pEditFlags->cBullet				= pFlags->cByInputBullet;
	pEditFlags->aBulletFont			= pFlags->aByInputBulletFont;
	pEditFlags->cByInputBullet		= pFlags->cByInputBullet;
	pEditFlags->aByInputBulletFont	= pFlags->aByInputBulletFont;
}

