update dev300-m58
[ooovba.git] / sw / source / core / edit / autofmt.cxx
blobf4499b20ce1d1d671d6c8b7ffedd417f0ba75948
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: autofmt.cxx,v $
10 * $Revision: 1.42 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
35 #define _SVSTDARR_LONGS
36 #define _SVSTDARR_USHORTS
38 #include <ctype.h>
39 #include <hintids.hxx>
41 #include <svtools/svstdarr.hxx>
42 #include <unotools/charclass.hxx>
43 #include <svx/boxitem.hxx>
44 #include <svx/lrspitem.hxx>
45 #include <svx/brkitem.hxx>
46 #include <svx/adjitem.hxx>
47 #ifndef _SVX_TSTPITEM_HXX //autogen
48 #include <svx/tstpitem.hxx>
49 #endif
50 #include <svx/fontitem.hxx>
51 #include <svx/langitem.hxx>
52 #include <svx/cscoitem.hxx>
53 #include <svx/unolingu.hxx>
55 #include <svx/acorrcfg.hxx>
56 #include <swwait.hxx>
57 #include <fmtpdsc.hxx>
58 #include <fmtanchr.hxx>
59 #include <doc.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 <fmthbsh.hxx>
78 #include <frmatr.hxx>
79 #include <charatr.hxx>
80 #include <mdiexp.hxx>
81 #ifndef _STATSTR_HRC
82 #include <statstr.hrc>
83 #endif
84 #ifndef _COMCORE_HRC
85 #include <comcore.hrc>
86 #endif
87 #include <vcl/msgbox.hxx>
88 #include <numrule.hxx>
90 using namespace ::com::sun::star;
92 //-------------------------------------------------------------------
94 //JP 16.12.99: definition:
95 // from pos cPosEnDash to cPosEmDash all chars changed to endashes,
96 // from pos cPosEmDash to cPosEnd all chars changed to emdashes
97 // all other chars are changed to the user configuration
99 const sal_Unicode pBulletChar[6] = { '+', '*', '-', 0x2013, 0x2014, 0 };
100 const int cnPosEnDash = 2, cnPosEmDash = 4, cnPosEnd = 5;
102 const sal_Unicode cStarSymbolEnDash = 0x2013;
103 const sal_Unicode cStarSymbolEmDash = 0x2014;
106 SvxSwAutoFmtFlags* SwEditShell::pAutoFmtFlags = 0;
108 // Anzahl von Num-/Bullet-Absatzvorlagen. MAXLEVEL wird demnaechst auf
109 // x erhoeht, die Anzahl Vorlagen aber nicht (Ueberbleibsel aus <= 4.0)
110 const USHORT cnNumBullColls = 4;
112 class SwAutoFormat
114 SvxSwAutoFmtFlags aFlags;
115 SwPaM aDelPam; // ein Pam der benutzt werden kann
116 SwNodeIndex aNdIdx; // der Index auf den akt. TextNode
117 SwNodeIndex aEndNdIdx; // Index auf das Ende vom Bereich
119 SwEditShell* pEditShell;
120 SwDoc* pDoc;
121 SwTxtNode* pAktTxtNd; // der akt. TextNode
122 SwTxtFrm* pAktTxtFrm; // Frame vom akt. TextNode
123 CharClass* pCharClass; // Character classification
124 ULONG nEndNdIdx; // fuer die Prozent-Anzeige
125 LanguageType eCharClassLang;
127 USHORT nLastHeadLvl, nLastCalcHeadLvl;
128 USHORT nLastEnumLvl, nLastCalcEnumLvl;
129 USHORT nRedlAutoFmtSeqId;
131 enum
133 NONE = 0,
134 DELIM = 1,
135 DIGIT = 2,
136 CHG = 4,
137 LOWER_ALPHA = 8,
138 UPPER_ALPHA = 16,
139 LOWER_ROMAN = 32,
140 UPPER_ROMAN = 64,
141 NO_DELIM = (DIGIT|LOWER_ALPHA|UPPER_ALPHA|LOWER_ROMAN|UPPER_ROMAN)
144 enum Format_Status
146 READ_NEXT_PARA,
147 TST_EMPTY_LINE,
148 TST_ALPHA_LINE,
149 GET_ALL_INFO,
150 IS_ONE_LINE,
151 TST_ENUMERIC,
152 TST_IDENT,
153 TST_NEG_IDENT,
154 TST_TXT_BODY,
155 HAS_FMTCOLL,
156 IS_ENDE
157 } eStat;
159 BOOL bEnde : 1;
160 BOOL bEmptyLine : 1;
161 BOOL bMoreLines : 1;
163 static BOOL m_bAskForCancelUndoWhileBufferOverflow;
164 static short m_nActionWhileAutoformatUndoBufferOverflow;
167 // ------------- private methods -----------------------------
168 void _GetCharClass( LanguageType eLang );
169 CharClass& GetCharClass( LanguageType eLang ) const
171 if( !pCharClass || eLang != eCharClassLang )
173 SwAutoFormat* pThis = (SwAutoFormat*)this;
174 pThis->_GetCharClass( eLang );
176 return *pCharClass;
180 BOOL IsSpace( const sal_Unicode c ) const
181 { return (' ' == c || '\t' == c || 0x0a == c|| 0x3000 == c /* Jap. space */) ? TRUE : FALSE; }
183 void SetColl( USHORT nId, BOOL bHdLineOrText = FALSE );
184 String GoNextPara();
185 BOOL HasObjects( const SwNode& rNd );
187 // TxtNode Methoden
188 const SwTxtNode* GetNextNode() const;
189 BOOL IsEmptyLine( const SwTxtNode& rNd ) const
190 { return 0 == rNd.GetTxt().Len() ||
191 rNd.GetTxt().Len() == GetLeadingBlanks( rNd.GetTxt() ); }
193 BOOL IsOneLine( const SwTxtNode& ) const;
194 BOOL IsFastFullLine( const SwTxtNode& ) const;
195 BOOL IsNoAlphaLine( const SwTxtNode&) const;
196 BOOL IsEnumericChar( const SwTxtNode&) const;
197 BOOL IsBlanksInString( const SwTxtNode&) const;
198 USHORT CalcLevel( const SwTxtNode&, USHORT *pDigitLvl = 0 ) const;
199 xub_StrLen GetBigIndent( xub_StrLen& rAktSpacePos ) const;
201 String& DelLeadingBlanks( String& rStr ) const;
202 String& DelTrailingBlanks( String& rStr ) const;
203 xub_StrLen GetLeadingBlanks( const String& rStr ) const;
204 xub_StrLen GetTrailingBlanks( const String& rStr ) const;
206 BOOL IsFirstCharCapital( const SwTxtNode& rNd ) const;
207 USHORT GetDigitLevel( const SwTxtNode& rTxtNd, xub_StrLen& rPos,
208 String* pPreFix = 0, String* pPostFix = 0,
209 String* pNumTypes = 0 ) const;
210 // hole den FORMATIERTEN TextFrame
211 SwTxtFrm* GetFrm( const SwTxtNode& rTxtNd ) const;
213 void BuildIndent();
214 void BuildText();
215 void BuildTextIndent();
216 void BuildEnum( USHORT nLvl, USHORT nDigitLevel );
217 void BuildNegIndent( SwTwips nSpaces );
218 void BuildHeadLine( USHORT nLvl );
220 BOOL HasSelBlanks( SwPaM& rPam ) const;
221 BOOL HasBreakAttr( const SwTxtNode& ) const;
222 void DeleteSel( SwPaM& rPam );
223 BOOL DeleteAktNxtPara( const String& rNxtPara );
224 // loesche im Node Anfang oder/und Ende
225 void DeleteAktPara( BOOL bStart = TRUE, BOOL nEnd = TRUE );
226 void DelEmptyLine( BOOL bTstNextPara = TRUE );
227 // loesche bei mehrzeiligen Absaetzen die "linken" und/oder
228 // "rechten" Raender
229 void DelMoreLinesBlanks( BOOL bWithLineBreaks = FALSE );
230 // loesche den vorherigen Absatz
231 void DelPrevPara();
232 // dann lasse doch mal das AutoCorrect auf den akt. TextNode los
233 void AutoCorrect( xub_StrLen nSttPos = 0 );
235 BOOL CanJoin( const SwTxtNode* pTxtNd ) const
237 return !bEnde && pTxtNd &&
238 !IsEmptyLine( *pTxtNd ) &&
239 !IsNoAlphaLine( *pTxtNd) &&
240 !IsEnumericChar( *pTxtNd ) &&
241 ((STRING_MAXLEN - 50 - pTxtNd->GetTxt().Len()) >
242 pAktTxtNd->GetTxt().Len()) &&
243 !HasBreakAttr( *pTxtNd );
246 // ist ein Punkt am Ende ??
247 BOOL IsSentenceAtEnd( const SwTxtNode& rTxtNd ) const;
249 BOOL DoUnderline();
250 BOOL DoTable();
252 void _SetRedlineTxt( USHORT nId );
253 BOOL SetRedlineTxt( USHORT nId )
254 { if( aFlags.bWithRedlining ) _SetRedlineTxt( nId ); return TRUE; }
255 BOOL ClearRedlineTxt()
256 { if( aFlags.bWithRedlining ) pDoc->SetAutoFmtRedlineComment(0); return TRUE; }
258 public:
259 SwAutoFormat( SwEditShell* pEdShell, SvxSwAutoFmtFlags& rFlags,
260 SwNodeIndex* pSttNd = 0, SwNodeIndex* pEndNd = 0 );
261 ~SwAutoFormat() {
262 delete pCharClass;
266 BOOL SwAutoFormat::m_bAskForCancelUndoWhileBufferOverflow = TRUE;
267 short SwAutoFormat::m_nActionWhileAutoformatUndoBufferOverflow = RET_YES;
269 const sal_Unicode* StrChr( const sal_Unicode* pSrc, sal_Unicode c )
271 while( *pSrc && *pSrc != c )
272 ++pSrc;
273 return *pSrc ? pSrc : 0;
276 SwTxtFrm* SwAutoFormat::GetFrm( const SwTxtNode& rTxtNd ) const
278 // besorge mal den Frame
279 const SwCntntFrm *pFrm = rTxtNd.GetFrm();
280 ASSERT( pFrm, "zum Autoformat muss das Layout vorhanden sein" );
281 if( aFlags.bAFmtByInput && !pFrm->IsValid() )
283 SwRect aTmpFrm( pFrm->Frm() );
284 SwRect aTmpPrt( pFrm->Prt() );
285 pFrm->Calc();
286 if( pFrm->Frm() != aTmpFrm || pFrm->Prt() != aTmpPrt ||
287 ( pFrm->IsTxtFrm() && !((SwTxtFrm*)pFrm)->Paint().IsEmpty() ) )
288 pFrm->SetCompletePaint();
290 return ((SwTxtFrm*)pFrm)->GetFormatted();
293 void SwAutoFormat::_GetCharClass( LanguageType eLang )
295 delete pCharClass;
296 pCharClass = new CharClass( SvxCreateLocale( eLang ));
297 eCharClassLang = eLang;
300 void SwAutoFormat::_SetRedlineTxt( USHORT nActionId )
302 String sTxt;
303 USHORT nSeqNo = 0;
304 if( STR_AUTOFMTREDL_END > nActionId )
306 sTxt = *ViewShell::GetShellRes()->GetAutoFmtNameLst()[ nActionId ];
307 switch( nActionId )
309 case STR_AUTOFMTREDL_SET_NUMBULET:
310 case STR_AUTOFMTREDL_DEL_MORELINES:
312 // AutoCorrect-Actions
313 case STR_AUTOFMTREDL_USE_REPLACE:
314 case STR_AUTOFMTREDL_CPTL_STT_WORD:
315 case STR_AUTOFMTREDL_CPTL_STT_SENT:
316 case STR_AUTOFMTREDL_TYPO:
317 case STR_AUTOFMTREDL_UNDER:
318 case STR_AUTOFMTREDL_BOLD:
319 case STR_AUTOFMTREDL_FRACTION:
320 case STR_AUTOFMTREDL_DASH:
321 case STR_AUTOFMTREDL_ORDINAL:
322 case STR_AUTOFMTREDL_NON_BREAK_SPACE:
323 nSeqNo = ++nRedlAutoFmtSeqId;
324 break;
327 #if OSL_DEBUG_LEVEL > 1
328 else
329 sTxt = String::CreateFromAscii(
330 RTL_CONSTASCII_STRINGPARAM( "Action-Text fehlt" ));
331 #endif
333 pDoc->SetAutoFmtRedlineComment( &sTxt, nSeqNo );
336 String SwAutoFormat::GoNextPara()
338 SwNode* pNewNd = 0;
339 do {
340 //has to be checed twice before and after incrementation
341 if( aNdIdx.GetIndex() >= aEndNdIdx.GetIndex() )
343 bEnde = TRUE;
344 return aEmptyStr;
347 aNdIdx++;
348 if( aNdIdx.GetIndex() >= aEndNdIdx.GetIndex() )
350 bEnde = TRUE;
351 return aEmptyStr;
353 else
354 pNewNd = &aNdIdx.GetNode();
356 // kein TextNode ->
357 // TableNode : Tabelle ueberspringen
358 // NoTxtNode : Nodes ueberspringen
359 // EndNode : Ende erreicht, beenden
360 if( pNewNd->IsEndNode() )
362 bEnde = TRUE;
363 return aEmptyStr;
365 else if( pNewNd->IsTableNode() )
366 aNdIdx = *pNewNd->EndOfSectionNode();
367 else if( pNewNd->IsSectionNode() )
369 const SwSection& rSect = pNewNd->GetSectionNode()->GetSection();
370 if( rSect.IsHiddenFlag() || rSect.IsProtectFlag() )
371 aNdIdx = *pNewNd->EndOfSectionNode();
373 } while( !pNewNd->IsTxtNode() );
375 if( !aFlags.bAFmtByInput )
376 ::SetProgressState( aNdIdx.GetIndex() + nEndNdIdx - aEndNdIdx.GetIndex(),
377 pDoc->GetDocShell() );
379 pAktTxtNd = (SwTxtNode*)pNewNd;
380 pAktTxtFrm = GetFrm( *pAktTxtNd );
381 return pAktTxtNd->GetTxt();
384 BOOL SwAutoFormat::HasObjects( const SwNode& rNd )
386 // haengt irgend etwas absatzgebundenes am Absatz?
387 // z.B. Rahmen, DrawObjecte, ..
388 BOOL bRet = FALSE;
389 const SwSpzFrmFmts& rFmts = *pDoc->GetSpzFrmFmts();
390 for( USHORT n = 0; n < rFmts.Count(); ++n )
392 const SwFmtAnchor& rAnchor = rFmts[ n ]->GetAnchor();
393 if( FLY_PAGE != rAnchor.GetAnchorId() &&
394 rAnchor.GetCntntAnchor() &&
395 &rAnchor.GetCntntAnchor()->nNode.GetNode() == &rNd )
397 bRet = TRUE;
398 break;
401 return bRet;
404 const SwTxtNode* SwAutoFormat::GetNextNode() const
406 if( aNdIdx.GetIndex()+1 >= aEndNdIdx.GetIndex() )
407 return 0;
408 return pDoc->GetNodes()[ aNdIdx.GetIndex() + 1 ]->GetTxtNode();
412 BOOL SwAutoFormat::IsOneLine( const SwTxtNode& rNd ) const
414 SwTxtFrmInfo aFInfo( GetFrm( rNd ) );
415 return aFInfo.IsOneLine();
419 BOOL SwAutoFormat::IsFastFullLine( const SwTxtNode& rNd ) const
421 BOOL bRet = aFlags.bRightMargin;
422 if( bRet )
424 SwTxtFrmInfo aFInfo( GetFrm( rNd ) );
425 bRet = aFInfo.IsFilled( aFlags.nRightMargin );
427 return bRet;
431 BOOL SwAutoFormat::IsEnumericChar( const SwTxtNode& rNd ) const
433 const String& rTxt = rNd.GetTxt();
434 String sTmp( rTxt );
435 xub_StrLen nBlnks = GetLeadingBlanks( sTmp );
436 xub_StrLen nLen = rTxt.Len() - nBlnks;
437 if( !nLen )
438 return FALSE;
440 // -, +, * getrennt durch Blank ??
441 if( 2 < nLen && IsSpace( rTxt.GetChar( nBlnks + 1 ) ) )
443 if( StrChr( pBulletChar, rTxt.GetChar( nBlnks ) ) )
444 return TRUE;
445 // sollte an der Position ein Symbolfont existieren ?
446 SwTxtFrmInfo aFInfo( GetFrm( rNd ) );
447 if( aFInfo.IsBullet( nBlnks ))
448 return TRUE;
451 // 1.) / 1. / 1.1.1 / (1). / (1) / ....
452 return USHRT_MAX != GetDigitLevel( rNd, nBlnks );
456 BOOL SwAutoFormat::IsBlanksInString( const SwTxtNode& rNd ) const
458 // suche im String mehr als 5 Blanks/Tabs
459 String sTmp( rNd.GetTxt() );
460 DelTrailingBlanks( DelLeadingBlanks( sTmp ));
461 const sal_Unicode* pTmp = sTmp.GetBuffer();
462 while( *pTmp )
464 if( IsSpace( *pTmp ) )
466 if( IsSpace( *++pTmp )) // 2 Space nach einander
468 const sal_Unicode* pStt = pTmp;
469 while( *pTmp && IsSpace( *++pTmp ))
471 if( 5 <= pTmp - pStt )
472 return TRUE;
474 else
475 ++pTmp;
477 else
478 ++pTmp;
480 return FALSE;
484 USHORT SwAutoFormat::CalcLevel( const SwTxtNode& rNd, USHORT *pDigitLvl ) const
486 USHORT nLvl = 0, nBlnk = 0;
487 const String& rTxt = rNd.GetTxt();
488 if( pDigitLvl )
489 *pDigitLvl = USHRT_MAX;
491 if( RES_POOLCOLL_TEXT_MOVE == rNd.GetTxtColl()->GetPoolFmtId() )
493 if( aFlags.bAFmtByInput )
495 nLvl = rNd.GetAutoFmtLvl();
496 ((SwTxtNode&)rNd).SetAutoFmtLvl( 0 );
497 if( nLvl )
498 return nLvl;
500 ++nLvl;
504 for( xub_StrLen n = 0, nEnd = rTxt.Len(); n < nEnd; ++n )
506 switch( rTxt.GetChar( n ) )
508 case ' ': if( 3 == ++nBlnk )
509 ++nLvl, nBlnk = 0;
510 break;
511 case '\t': ++nLvl, nBlnk = 0;
512 break;
513 default:
514 if( pDigitLvl )
515 // Teste auf 1.) / 1. / 1.1.1 / (1). / (1) / ....
516 *pDigitLvl = GetDigitLevel( rNd, n );
517 return nLvl;
520 return nLvl;
525 xub_StrLen SwAutoFormat::GetBigIndent( xub_StrLen& rAktSpacePos ) const
527 SwTxtFrmInfo aFInfo( GetFrm( *pAktTxtNd ) );
528 const SwTxtFrm* pNxtFrm = 0;
530 if( !bMoreLines )
532 const SwTxtNode* pNxtNd = GetNextNode();
533 if( !CanJoin( pNxtNd ) || !IsOneLine( *pNxtNd ) )
534 return 0;
536 pNxtFrm = GetFrm( *pNxtNd );
539 return aFInfo.GetBigIndent( rAktSpacePos, pNxtFrm );
543 BOOL SwAutoFormat::IsNoAlphaLine( const SwTxtNode& rNd ) const
545 const String& rStr = rNd.GetTxt();
546 if( !rStr.Len() )
547 return FALSE;
548 // oder besser: ueber die Anzahl von Alpha/Num- und !AN-Zeichen
549 // bestimmen.
550 xub_StrLen nANChar = 0, nBlnk = 0;
552 CharClass& rCC = GetCharClass( rNd.GetSwAttrSet().GetLanguage().GetLanguage() );
553 for( xub_StrLen n = 0, nEnd = rStr.Len(); n < nEnd; ++n )
554 if( IsSpace( rStr.GetChar( n ) ) )
555 ++nBlnk;
556 else if( rCC.isLetterNumeric( rStr, n ))
557 ++nANChar;
559 // sind zu 75% keine Alpha-Nummerische-Zeichen, dann TRUE
560 ULONG nLen = rStr.Len() - nBlnk;
561 nLen = ( nLen * 3 ) / 4; // long overflow, if the strlen > USHORT
562 return xub_StrLen(nLen) < (rStr.Len() - nANChar - nBlnk);
567 BOOL SwAutoFormat::DoUnderline()
569 if( !aFlags.bSetBorder )
570 return FALSE;
572 const sal_Unicode* pStr = pAktTxtNd->GetTxt().GetBuffer();
573 int eState = 0;
574 xub_StrLen nCnt = 0;
575 while( *pStr )
577 //JP 29.03.96: Spaces unterbrechen die Umrandung!
578 // if( !IsSpace( *pStr ) )
580 int eTmp = 0;
581 switch( *pStr )
583 case '-': eTmp = 1; break;
584 case '_': eTmp = 2; break;
585 case '=': eTmp = 3; break;
586 case '*': eTmp = 4; break;
587 case '~': eTmp = 5; break;
588 case '#': eTmp = 6; break;
589 default:
590 return FALSE;
592 if( 0 == eState )
593 eState = eTmp;
594 else if( eState != eTmp )
595 return FALSE;
596 ++nCnt;
598 ++pStr;
601 if( 2 < nCnt )
603 // dann unterstreiche mal den vorherigen Absatz, wenn es diesen gibt!
604 DelEmptyLine( FALSE );
605 aDelPam.SetMark();
606 aDelPam.GetMark()->nContent = 0;
607 //JP 19.03.96: kein Underline sondern eine Umrandung setzen!
608 // pDoc->Insert( aDelPam, SvxUnderlineItem( eState ) );
610 SvxBorderLine aLine;
611 switch( eState )
613 case 1: // einfach, 0,05 pt
614 aLine.SetOutWidth( DEF_LINE_WIDTH_0 );
615 break;
616 case 2: // einfach, 1,0 pt
617 aLine.SetOutWidth( DEF_LINE_WIDTH_1 );
618 break;
619 case 3: // doppelt, 1,1 pt
620 aLine.SetOutWidth( DEF_DOUBLE_LINE0_OUT );
621 aLine.SetInWidth( DEF_DOUBLE_LINE0_IN );
622 aLine.SetDistance( DEF_DOUBLE_LINE0_DIST );
623 break;
624 case 4: // doppelt, 4,5 pt
625 aLine.SetOutWidth( DEF_DOUBLE_LINE4_OUT );
626 aLine.SetInWidth( DEF_DOUBLE_LINE4_IN );
627 aLine.SetDistance( DEF_DOUBLE_LINE4_DIST );
628 break;
629 case 5: // doppelt, 6,0 pt
630 aLine.SetOutWidth( DEF_DOUBLE_LINE5_OUT );
631 aLine.SetInWidth( DEF_DOUBLE_LINE5_IN );
632 aLine.SetDistance( DEF_DOUBLE_LINE5_DIST );
633 break;
634 case 6: // doppelt, 9,0 pt
635 aLine.SetOutWidth( DEF_DOUBLE_LINE6_OUT );
636 aLine.SetInWidth( DEF_DOUBLE_LINE6_IN );
637 aLine.SetDistance( DEF_DOUBLE_LINE6_DIST );
638 break;
640 SfxItemSet aSet(pDoc->GetAttrPool(),
641 RES_PARATR_CONNECT_BORDER, RES_PARATR_CONNECT_BORDER,
642 RES_BOX, RES_BOX,
644 aSet.Put( SwParaConnectBorderItem( FALSE ) );
645 SvxBoxItem aBox( RES_BOX );
646 aBox.SetLine( &aLine, BOX_LINE_BOTTOM );
647 aBox.SetDistance( 42 ); // ~0,75 mm
648 aSet.Put(aBox);
649 pDoc->Insert( aDelPam, aSet, 0 );
651 aDelPam.DeleteMark();
653 return 2 < nCnt;
657 BOOL SwAutoFormat::DoTable()
659 if( !aFlags.bCreateTable || !aFlags.bAFmtByInput ||
660 pAktTxtNd->FindTableNode() )
661 return FALSE;
663 const String& rTmp = pAktTxtNd->GetTxt();
664 xub_StrLen nSttPlus = GetLeadingBlanks( rTmp );
665 xub_StrLen nEndPlus = GetTrailingBlanks( rTmp );
666 sal_Unicode cChar;
668 if( 2 > nEndPlus - nSttPlus ||
669 ( '+' != ( cChar = rTmp.GetChar( nSttPlus )) && '|' != cChar ) ||
670 ( '+' != ( cChar = rTmp.GetChar( nEndPlus - 1)) && '|' != cChar ))
671 return FALSE;
673 SwTxtFrmInfo aInfo( pAktTxtFrm );
675 xub_StrLen n = nSttPlus;
676 const sal_Unicode* pStr = rTmp.GetBuffer() + n;
677 SvUShorts aPosArr( 5, 5 );
679 while( *pStr )
681 switch( *pStr )
683 case '-':
684 case '_':
685 case '=':
686 case ' ':
687 case '\t':
688 break;
690 case '+':
691 case '|':
692 aPosArr.Insert( static_cast<USHORT>(aInfo.GetCharPos(n)), aPosArr.Count() );
693 break;
695 default:
696 return FALSE;
698 if( ++n == nEndPlus )
699 break;
701 ++pStr;
704 if( 1 < aPosArr.Count() )
706 // Ausrichtung vom Textnode besorgen:
707 USHORT nColCnt = aPosArr.Count() - 1;
708 SwTwips nSttPos = aPosArr[ 0 ];
709 sal_Int16 eHori;
710 switch( pAktTxtNd->GetSwAttrSet().GetAdjust().GetAdjust() )
712 case SVX_ADJUST_CENTER: eHori = text::HoriOrientation::CENTER; break;
713 case SVX_ADJUST_RIGHT: eHori = text::HoriOrientation::RIGHT; break;
715 default:
716 if( nSttPos )
718 eHori = text::HoriOrientation::NONE;
719 // dann muss als letztes noch die akt. FrameBreite
720 // ins Array
721 aPosArr.Insert( static_cast<USHORT>(pAktTxtFrm->Frm().Width()), aPosArr.Count() );
723 else
724 eHori = text::HoriOrientation::LEFT;
725 break;
728 // dann erzeuge eine Tabelle, die den Zeichen entspricht
729 DelEmptyLine();
730 SwNodeIndex aIdx( aDelPam.GetPoint()->nNode );
731 aDelPam.Move( fnMoveForward );
732 pDoc->InsertTable( SwInsertTableOptions( tabopts::ALL_TBL_INS_ATTR , 1 ),
733 *aDelPam.GetPoint(), 1, nColCnt, eHori,
734 0, &aPosArr );
735 aDelPam.GetPoint()->nNode = aIdx;
737 return 1 < aPosArr.Count();
741 String& SwAutoFormat::DelLeadingBlanks( String& rStr ) const
743 xub_StrLen nL;
744 xub_StrLen n;
746 for( nL = rStr.Len(), n = 0; n < nL && IsSpace( rStr.GetChar(n) ); ++n )
748 if( n ) // keine Spaces
749 rStr.Erase( 0, n );
750 return rStr;
754 String& SwAutoFormat::DelTrailingBlanks( String& rStr ) const
756 xub_StrLen nL = rStr.Len(), n = nL;
757 if( !nL )
758 return rStr;
760 while( --n && IsSpace( rStr.GetChar( n ) ) )
762 if( n+1 != nL ) // keine Spaces
763 rStr.Erase( n+1 );
764 return rStr;
768 xub_StrLen SwAutoFormat::GetLeadingBlanks( const String& rStr ) const
770 xub_StrLen nL;
771 xub_StrLen n;
773 for( nL = rStr.Len(), n = 0; n < nL && IsSpace( rStr.GetChar( n ) ); ++n )
775 return n;
779 xub_StrLen SwAutoFormat::GetTrailingBlanks( const String& rStr ) const
781 xub_StrLen nL = rStr.Len(), n = nL;
782 if( !nL )
783 return 0;
785 while( --n && IsSpace( rStr.GetChar( n ) ) )
787 return ++n;
791 BOOL SwAutoFormat::IsFirstCharCapital( const SwTxtNode& rNd ) const
793 const String& rTxt = rNd.GetTxt();
794 for( xub_StrLen n = 0, nEnd = rTxt.Len(); n < nEnd; ++n )
795 if( !IsSpace( rTxt.GetChar( n ) ) )
797 CharClass& rCC = GetCharClass( rNd.GetSwAttrSet().
798 GetLanguage().GetLanguage() );
799 sal_Int32 nCharType = rCC.getCharacterType( rTxt, n );
800 return CharClass::isLetterType( nCharType ) &&
801 0 != ( i18n::KCharacterType::UPPER &
802 nCharType );
804 return FALSE;
808 USHORT SwAutoFormat::GetDigitLevel( const SwTxtNode& rNd, xub_StrLen& rPos,
809 String* pPreFix, String* pPostFix, String* pNumTypes ) const
811 // Teste auf 1.) / 1. / 1.1.1 / (1). / (1) / ....
812 const String& rTxt = rNd.GetTxt();
813 xub_StrLen nPos = rPos;
814 int eScan = NONE;
816 USHORT nStart = 0;
817 BYTE nDigitLvl = 0, nDigitCnt = 0;
818 //count number of parenthesis to assure a sensible order is found
819 USHORT nOpeningParentheses = 0;
820 USHORT nClosingParentheses = 0;
822 CharClass& rCC = GetCharClass( rNd.GetSwAttrSet().GetLanguage().GetLanguage() );
824 while( nPos < rTxt.Len() && nDigitLvl < MAXLEVEL - 1)
826 const sal_Unicode cCurrentChar = rTxt.GetChar( nPos );
827 if( ('0' <= cCurrentChar && '9' >= cCurrentChar) ||
828 (0xff10 <= cCurrentChar && 0xff19 >= cCurrentChar) )
830 if( eScan & DELIM )
832 if( eScan & CHG ) // nicht wenns mit einer Zahl beginnt
834 ++nDigitLvl;
835 if( pPostFix )
836 *pPostFix += (sal_Unicode)1;
839 if( pNumTypes )
840 *pNumTypes += (sal_Unicode)('0' + SVX_NUM_ARABIC);
842 eScan = eScan | CHG;
844 else if( pNumTypes && !(eScan & DIGIT) )
845 *pNumTypes += (sal_Unicode)('0' + SVX_NUM_ARABIC);
847 eScan &= ~DELIM; // Delim raus
848 if( 0 != (eScan & ~CHG) && DIGIT != (eScan & ~CHG))
849 return USHRT_MAX;
851 eScan |= DIGIT; // Digit rein
852 if( 3 == ++nDigitCnt ) // mehr als 2 Nummern sind kein Enum mehr
853 return USHRT_MAX;
855 nStart *= 10;
856 nStart += cCurrentChar <= '9' ? cCurrentChar - '0' : cCurrentChar - 0xff10;
858 else if( rCC.isAlpha( rTxt, nPos ) )
860 BOOL bIsUpper =
861 0 != ( i18n::KCharacterType::UPPER &
862 rCC.getCharacterType( rTxt, nPos ));
863 sal_Unicode cLow = rCC.toLower( rTxt, nPos, 1 ).GetChar(0), cNumTyp;
864 int eTmpScan;
866 // roemische Zeichen sind "mdclxvi". Da man aber eher mal eine
867 // Numerierung mit c oder d anfangen will, werden diese erstmal
868 // zu chars und spaeter ggfs. zu romischen Zeichen!
869 // if( strchr( "mdclxvi", cLow ))
870 #ifdef WITH_ALPHANUM_AS_NUMFMT
871 //detection of 'c' and 'd' a ROMAN numbering should not be done here
872 if( 256 > cLow &&( (eScan & (LOWER_ROMAN|UPPER_ROMAN))
873 ? strchr( "mdclxvi", cLow )
874 : strchr( "mlxvi", cLow ) ))
875 #else
876 if( 256 > cLow && ( strchr( "mdclxvi", cLow ) ))
877 #endif
879 if( bIsUpper )
880 cNumTyp = '0' + SVX_NUM_ROMAN_UPPER, eTmpScan = UPPER_ROMAN;
881 else
882 cNumTyp = '0' + SVX_NUM_ROMAN_LOWER, eTmpScan = LOWER_ROMAN;
884 else if( bIsUpper )
885 cNumTyp = '0' + SVX_NUM_CHARS_UPPER_LETTER, eTmpScan = UPPER_ALPHA;
886 else
887 cNumTyp = '0' + SVX_NUM_CHARS_LOWER_LETTER, eTmpScan = LOWER_ALPHA;
890 //ggfs. auf roemische Zeichen umschalten (nur bei c/d!)?
891 if( 1 == nDigitCnt && ( eScan & (UPPER_ALPHA|LOWER_ALPHA) ) &&
892 ( 3 == nStart || 4 == nStart) && 256 > cLow &&
893 strchr( "mdclxvi", cLow ) &&
894 (( eScan & UPPER_ALPHA ) ? (eTmpScan & (UPPER_ALPHA|UPPER_ROMAN))
895 : (eTmpScan & (LOWER_ALPHA|LOWER_ROMAN))) )
897 sal_Unicode c = '0';
898 nStart = 3 == nStart ? 100 : 500;
899 if( UPPER_ALPHA == eTmpScan )
900 eTmpScan = UPPER_ROMAN, c += SVX_NUM_ROMAN_UPPER;
901 else
902 eTmpScan = LOWER_ROMAN, c += SVX_NUM_ROMAN_LOWER;
904 ( eScan &= ~(UPPER_ALPHA|LOWER_ALPHA)) |= eTmpScan;
905 if( pNumTypes )
906 pNumTypes->SetChar( pNumTypes->Len() - 1, c );
909 if( eScan & DELIM )
911 if( eScan & CHG ) // nicht wenns mit einer Zahl beginnt
913 ++nDigitLvl;
914 if( pPostFix )
915 *pPostFix += (sal_Unicode)1;
918 if( pNumTypes )
919 *pNumTypes += cNumTyp;
920 eScan = eScan | CHG;
922 else if( pNumTypes && !(eScan & eTmpScan) )
923 *pNumTypes += cNumTyp;
925 eScan &= ~DELIM; // Delim raus
927 // falls ein andere Type gesetzt ist, brechen wir ab
928 if( 0 != ( eScan & ~CHG ) && eTmpScan != ( eScan & ~CHG ))
929 return USHRT_MAX;
931 if( eTmpScan & (UPPER_ALPHA | LOWER_ALPHA) )
933 // Buchstaben nur zulassen, wenn sie einmalig vorkommen
934 return USHRT_MAX;
936 else
938 // roemische Zahlen: checke ob das gueltige Zeichen sind
939 USHORT nVal;
940 BOOL bError = FALSE;
941 switch( cLow )
943 case 'm': nVal = 1000; goto CHECK_ROMAN_1;
944 case 'd': nVal = 500; goto CHECK_ROMAN_5;
945 case 'c': nVal = 100; goto CHECK_ROMAN_1;
946 case 'l': nVal = 50; goto CHECK_ROMAN_5;
947 case 'x': nVal = 10; goto CHECK_ROMAN_1;
948 case 'v': nVal = 5; goto CHECK_ROMAN_5;
950 CHECK_ROMAN_1:
952 int nMod5 = nStart % (nVal * 5);
953 int nLast = nStart % nVal;
954 int n10 = nVal / 10;
956 if( nMod5 == ((3 * nVal) + n10 ) ||
957 nMod5 == ((4 * nVal) + n10 ) ||
958 nLast == n10 )
959 nStart = static_cast<USHORT>(nStart + (n10 * 8));
960 else if( nMod5 == 0 ||
961 nMod5 == (1 * nVal) ||
962 nMod5 == (2 * nVal) )
963 nStart = nStart + nVal;
964 else
965 bError = TRUE;
967 break;
969 CHECK_ROMAN_5:
971 if( ( nStart / nVal ) & 1 )
972 bError = TRUE;
973 else
975 int nMod = nStart % nVal;
976 int n10 = nVal / 5;
977 if( n10 == nMod )
978 nStart = static_cast<USHORT>(nStart + (3 * n10));
979 else if( 0 == nMod )
980 nStart = nStart + nVal;
981 else
982 bError = TRUE;
985 break;
987 case 'i':
988 if( nStart % 5 >= 3 )
989 bError = TRUE;
990 else
991 nStart += 1;
992 break;
994 default:
995 bError = TRUE;
998 if( bError )
999 return USHRT_MAX;
1001 eScan |= eTmpScan; // Digit rein
1002 ++nDigitCnt;
1004 else if( (256 > cCurrentChar &&
1005 strchr( ".)(", cCurrentChar )) ||
1006 0x3002 == cCurrentChar /* Chinese trad. dot */||
1007 0xff0e == cCurrentChar /* Japanese dot */||
1008 0xFF08 == cCurrentChar /* opening bracket Chin./Jap.*/||
1009 0xFF09 == cCurrentChar )/* closing bracket Chin./Jap. */
1011 if(cCurrentChar == '(' || cCurrentChar == 0xFF09)
1012 nOpeningParentheses++;
1013 else if(cCurrentChar == ')'|| cCurrentChar == 0xFF08)
1014 nClosingParentheses++;
1015 // nur wenn noch keine Zahlen gelesen wurden!
1016 if( pPreFix && !( eScan & ( NO_DELIM | CHG )) )
1017 *pPreFix += rTxt.GetChar( nPos );
1018 else if( pPostFix )
1019 *pPostFix += rTxt.GetChar( nPos );
1021 if( NO_DELIM & eScan )
1023 eScan |= CHG;
1024 if( pPreFix )
1025 (*pPreFix += (sal_Unicode)1)
1026 += String::CreateFromInt32( nStart );
1028 eScan &= ~NO_DELIM; // Delim raus
1029 eScan |= DELIM; // Digit rein
1030 nDigitCnt = 0;
1031 nStart = 0;
1033 else
1034 break;
1035 ++nPos;
1037 if( !( CHG & eScan ) || rPos == nPos ||
1038 nPos == rTxt.Len() || !IsSpace( rTxt.GetChar( nPos ) ) ||
1039 (nOpeningParentheses > nClosingParentheses))
1040 return USHRT_MAX;
1042 if( (NO_DELIM & eScan) && pPreFix ) // den letzen nicht vergessen
1043 (*pPreFix += (sal_Unicode)1) += String::CreateFromInt32( nStart );
1045 rPos = nPos;
1046 return nDigitLvl; // 0 .. 9 (MAXLEVEL - 1)
1050 void SwAutoFormat::SetColl( USHORT nId, BOOL bHdLineOrText )
1052 aDelPam.DeleteMark();
1053 aDelPam.GetPoint()->nNode = aNdIdx;
1054 aDelPam.GetPoint()->nContent.Assign( pAktTxtNd, 0 );
1056 // behalte harte Tabs, Ausrichtung, Sprache, Silbentrennung,
1057 // DropCaps und fast alle Frame-Attribute
1058 SfxItemSet aSet( pDoc->GetAttrPool(),
1059 RES_PARATR_ADJUST, RES_PARATR_ADJUST,
1060 RES_PARATR_TABSTOP, RES_PARATR_DROP,
1061 RES_CHRATR_LANGUAGE, RES_CHRATR_LANGUAGE,
1062 RES_BACKGROUND, RES_SHADOW,
1063 0 );
1065 if( pAktTxtNd->HasSwAttrSet() )
1067 aSet.Put( *pAktTxtNd->GetpSwAttrSet() );
1068 // einige Sonderbedingungen:
1069 // HeaderLine/Textkoerper: nur zentriert oder rechts mitnehmem
1070 // sonst nur den Blocksatz
1071 SvxAdjustItem* pAdj;
1072 if( SFX_ITEM_SET == aSet.GetItemState( RES_PARATR_ADJUST,
1073 FALSE, (const SfxPoolItem**)&pAdj ))
1075 SvxAdjust eAdj = pAdj->GetAdjust();
1076 if( bHdLineOrText ? (SVX_ADJUST_RIGHT != eAdj &&
1077 SVX_ADJUST_CENTER != eAdj)
1078 : SVX_ADJUST_BLOCK != eAdj )
1079 aSet.ClearItem( RES_PARATR_ADJUST );
1083 pDoc->SetTxtFmtCollByAutoFmt( *aDelPam.GetPoint(), nId, &aSet );
1087 BOOL SwAutoFormat::HasSelBlanks( SwPaM& rPam ) const
1089 // noch ein Blank am Anfang oder Ende ?
1090 // nicht loeschen, wird wieder eingefuegt.
1091 SwPosition * pPos = rPam.End();
1092 xub_StrLen nBlnkPos = pPos->nContent.GetIndex();
1093 SwTxtNode* pTxtNd = pPos->nNode.GetNode().GetTxtNode();
1094 if( nBlnkPos && nBlnkPos-- < pTxtNd->GetTxt().Len() &&
1095 ( ' ' == pTxtNd->GetTxt().GetChar( nBlnkPos ) ))
1096 // JP 23.08.95: keine Tabs stehen lassen, diese in Blanks wandeln
1097 // ( ' ' == ( cCh = pTxtNd->GetTxt()[ nBlnkPos ] ) || '\t' == cCh ))
1098 pPos->nContent--;
1099 else
1101 pPos = rPam.GetPoint() == pPos ? rPam.GetMark() : rPam.GetPoint();
1102 nBlnkPos = pPos->nContent.GetIndex();
1103 pTxtNd = pPos->nNode.GetNode().GetTxtNode();
1104 if( nBlnkPos < pTxtNd->GetTxt().Len() &&
1105 ( ' ' == pTxtNd->GetTxt().GetChar( nBlnkPos )))
1106 // JP 23.08.95: keine Tabs stehen lassen, diese in Blanks wandeln
1107 // ( ' ' == ( cCh = pTxtNd->GetTxt()[ nBlnkPos ] ) || '\t' == cCh ))
1108 pPos->nContent++;
1109 else
1110 return FALSE;
1112 return TRUE;
1116 BOOL SwAutoFormat::HasBreakAttr( const SwTxtNode& rTxtNd ) const
1118 const SfxItemSet* pSet = rTxtNd.GetpSwAttrSet();
1119 if( !pSet )
1120 return FALSE;
1122 const SfxPoolItem* pItem;
1123 if( SFX_ITEM_SET == pSet->GetItemState( RES_BREAK, FALSE, &pItem )
1124 && SVX_BREAK_NONE != ((SvxFmtBreakItem*)pItem)->GetBreak() )
1125 return TRUE;
1127 if( SFX_ITEM_SET == pSet->GetItemState( RES_PAGEDESC, FALSE, &pItem )
1128 && ((SwFmtPageDesc*)pItem)->GetPageDesc()
1129 && nsUseOnPage::PD_NONE != ((SwFmtPageDesc*)pItem)->GetPageDesc()->GetUseOn() )
1130 return TRUE;
1131 return FALSE;
1135 // ist ein Punkt am Ende ??
1136 BOOL SwAutoFormat::IsSentenceAtEnd( const SwTxtNode& rTxtNd ) const
1138 const String& rStr = rTxtNd.GetTxt();
1139 xub_StrLen n = rStr.Len();
1140 if( !n )
1141 return TRUE;
1143 while( --n && IsSpace( rStr.GetChar( n ) ) )
1145 return '.' == rStr.GetChar( n );
1149 // loesche im Node Anfang oder/und Ende
1150 void SwAutoFormat::DeleteAktPara( BOOL bStart, BOOL bEnd )
1152 if( aFlags.bAFmtByInput
1153 ? aFlags.bAFmtByInpDelSpacesAtSttEnd
1154 : aFlags.bAFmtDelSpacesAtSttEnd )
1156 // Loesche Blanks am Ende vom akt. und am Anfang vom naechsten
1157 aDelPam.DeleteMark();
1158 aDelPam.GetPoint()->nNode = aNdIdx;
1159 xub_StrLen nPos;
1160 if( bStart && 0 != ( nPos = GetLeadingBlanks( pAktTxtNd->GetTxt() )))
1162 aDelPam.GetPoint()->nContent.Assign( pAktTxtNd, 0 );
1163 aDelPam.SetMark();
1164 aDelPam.GetPoint()->nContent = nPos;
1165 DeleteSel( aDelPam );
1166 aDelPam.DeleteMark();
1168 if( bEnd && pAktTxtNd->GetTxt().Len() !=
1169 ( nPos = GetTrailingBlanks( pAktTxtNd->GetTxt() )) )
1171 aDelPam.GetPoint()->nContent.Assign( pAktTxtNd, pAktTxtNd->GetTxt().Len() );
1172 aDelPam.SetMark();
1173 aDelPam.GetPoint()->nContent = nPos;
1174 DeleteSel( aDelPam );
1175 aDelPam.DeleteMark();
1180 void SwAutoFormat::DeleteSel( SwPaM& rDelPam )
1182 if( aFlags.bWithRedlining )
1184 // damit der DelPam auch verschoben wird, in den Shell-Cursr-Ring
1185 // mit aufnehmen !!
1186 SwPaM* pShCrsr = pEditShell->_GetCrsr();
1187 SwPaM aTmp( *pAktTxtNd, 0, pShCrsr );
1189 Ring *pPrev = rDelPam.GetPrev();
1190 rDelPam.MoveRingTo( pShCrsr );
1192 pEditShell->DeleteSel( rDelPam );
1194 // und den Pam wieder herausnehmen:
1195 Ring *p, *pNext = (Ring*)&rDelPam;
1196 do {
1197 p = pNext;
1198 pNext = p->GetNext();
1199 p->MoveTo( &rDelPam );
1200 } while( p != pPrev );
1202 aNdIdx = aTmp.GetPoint()->nNode;
1203 pAktTxtNd = aNdIdx.GetNode().GetTxtNode();
1205 else
1206 pEditShell->DeleteSel( rDelPam );
1209 BOOL SwAutoFormat::DeleteAktNxtPara( const String& rNxtPara )
1211 // Loesche Blanks am Ende vom akt. und am Anfang vom naechsten
1212 aDelPam.DeleteMark();
1213 aDelPam.GetPoint()->nNode = aNdIdx;
1214 aDelPam.GetPoint()->nContent.Assign( pAktTxtNd,
1215 GetTrailingBlanks( pAktTxtNd->GetTxt() ) );
1216 aDelPam.SetMark();
1218 aDelPam.GetPoint()->nNode++;
1219 SwTxtNode* pTNd = aDelPam.GetNode()->GetTxtNode();
1220 if( !pTNd )
1222 // dann nur bis zum Ende von Absatz loeschen
1223 aDelPam.GetPoint()->nNode--;
1224 aDelPam.GetPoint()->nContent = pAktTxtNd->GetTxt().Len();
1226 else
1227 aDelPam.GetPoint()->nContent.Assign( pTNd,
1228 GetLeadingBlanks( rNxtPara ));
1230 // noch ein Blank am Anfang oder Ende ?
1231 // nicht loeschen, wird wieder eingefuegt.
1232 BOOL bHasBlnks = HasSelBlanks( aDelPam );
1234 if( *aDelPam.GetPoint() != *aDelPam.GetMark() )
1235 DeleteSel( aDelPam );
1236 aDelPam.DeleteMark();
1238 return !bHasBlnks;
1242 void SwAutoFormat::DelEmptyLine( BOOL bTstNextPara )
1244 SetRedlineTxt( STR_AUTOFMTREDL_DEL_EMPTY_PARA );
1245 // Loesche Blanks den leeren Absatz
1246 aDelPam.DeleteMark();
1247 aDelPam.GetPoint()->nNode = aNdIdx;
1248 aDelPam.GetPoint()->nContent.Assign( pAktTxtNd, pAktTxtNd->GetTxt().Len() );
1249 aDelPam.SetMark();
1251 aDelPam.GetMark()->nNode--;
1252 SwTxtNode* pTNd = aDelPam.GetNode( FALSE )->GetTxtNode();
1253 if( pTNd )
1254 // erstmal den vorherigen Textnode benutzen.
1255 aDelPam.GetMark()->nContent.Assign( pTNd, pTNd->GetTxt().Len() );
1256 else if( bTstNextPara )
1258 // dann versuche den naechsten (am Anfang vom Dok, Tabellen-Zellen,
1259 // Rahmen, ...
1260 aDelPam.GetMark()->nNode += 2;
1261 pTNd = aDelPam.GetNode( FALSE )->GetTxtNode();
1262 if( pTNd )
1264 aDelPam.GetMark()->nContent.Assign( pTNd, 0 );
1265 aDelPam.GetPoint()->nContent = 0;
1268 else
1270 aDelPam.GetMark()->nNode = aNdIdx;
1271 aDelPam.GetMark()->nContent = 0;
1272 pTNd = pAktTxtNd;
1274 if( pTNd )
1275 DeleteSel( aDelPam );
1277 aDelPam.DeleteMark();
1278 ClearRedlineTxt();
1282 void SwAutoFormat::DelMoreLinesBlanks( BOOL bWithLineBreaks )
1284 if( aFlags.bAFmtByInput
1285 ? aFlags.bAFmtByInpDelSpacesBetweenLines
1286 : aFlags.bAFmtDelSpacesBetweenLines )
1288 // loesche alle "Blanks" Links und Rechts vom Einzug
1289 aDelPam.DeleteMark();
1290 aDelPam.GetPoint()->nNode = aNdIdx;
1291 aDelPam.GetPoint()->nContent.Assign( pAktTxtNd, 0 );
1293 SwTxtFrmInfo aFInfo( pAktTxtFrm );
1294 aFInfo.GetSpaces( aDelPam, !aFlags.bAFmtByInput || bWithLineBreaks );
1296 SwPaM* pNxt;
1297 do {
1298 pNxt = (SwPaM*)aDelPam.GetNext();
1299 if( pNxt->HasMark() && *pNxt->GetPoint() != *pNxt->GetMark() )
1301 BOOL bHasBlnks = HasSelBlanks( *pNxt );
1302 DeleteSel( *pNxt );
1303 if( !bHasBlnks )
1304 pDoc->Insert( *pNxt, ' ' );
1307 if( pNxt == &aDelPam )
1308 break;
1309 delete pNxt;
1310 } while( TRUE );
1312 aDelPam.DeleteMark();
1317 // loesche den vorherigen Absatz
1318 void SwAutoFormat::DelPrevPara()
1320 aDelPam.DeleteMark();
1321 aDelPam.GetPoint()->nNode = aNdIdx;
1322 aDelPam.GetPoint()->nContent.Assign( pAktTxtNd, 0 );
1323 aDelPam.SetMark();
1325 aDelPam.GetPoint()->nNode--;
1326 SwTxtNode* pTNd = aDelPam.GetNode()->GetTxtNode();
1327 if( pTNd )
1329 // erstmal den vorherigen Textnode benutzen.
1330 aDelPam.GetPoint()->nContent.Assign( pTNd, pTNd->GetTxt().Len() );
1331 DeleteSel( aDelPam );
1333 aDelPam.DeleteMark();
1337 void SwAutoFormat::BuildIndent()
1339 SetRedlineTxt( STR_AUTOFMTREDL_SET_TMPL_INDENT );
1341 // lese alle nachfolgenden Absaetze die zu diesem Einzug gehoeren
1342 BOOL bBreak = TRUE;
1343 if( bMoreLines )
1344 DelMoreLinesBlanks( TRUE );
1345 else
1346 bBreak = !IsFastFullLine( *pAktTxtNd ) ||
1347 IsBlanksInString( *pAktTxtNd ) ||
1348 IsSentenceAtEnd( *pAktTxtNd );
1349 SetColl( RES_POOLCOLL_TEXT_IDENT );
1350 if( !bBreak )
1352 SetRedlineTxt( STR_AUTOFMTREDL_DEL_MORELINES );
1353 const SwTxtNode* pNxtNd = GetNextNode();
1354 if( pNxtNd && !bEnde )
1356 do {
1357 bBreak = !IsFastFullLine( *pNxtNd ) ||
1358 IsBlanksInString( *pNxtNd ) ||
1359 IsSentenceAtEnd( *pNxtNd );
1360 if( DeleteAktNxtPara( pNxtNd->GetTxt() ))
1361 pDoc->Insert( aDelPam, ' ' );
1362 if( bBreak )
1363 break;
1364 pNxtNd = GetNextNode();
1365 } while( CanJoin( pNxtNd ) &&
1366 !CalcLevel( *pNxtNd ) );
1369 DeleteAktPara( TRUE, TRUE );
1370 AutoCorrect();
1374 void SwAutoFormat::BuildTextIndent()
1376 SetRedlineTxt( STR_AUTOFMTREDL_SET_TMPL_TEXT_INDENT);
1377 // lese alle nachfolgenden Absaetze die zu diesem Einzug gehoeren
1378 BOOL bBreak = TRUE;
1379 if( bMoreLines )
1380 DelMoreLinesBlanks( TRUE );
1381 else
1382 bBreak = !IsFastFullLine( *pAktTxtNd ) ||
1383 IsBlanksInString( *pAktTxtNd ) ||
1384 IsSentenceAtEnd( *pAktTxtNd );
1386 if( aFlags.bAFmtByInput )
1387 pAktTxtNd->SetAutoFmtLvl( (BYTE)CalcLevel( *pAktTxtNd ) );
1389 SetColl( RES_POOLCOLL_TEXT_MOVE );
1390 if( !bBreak )
1392 SetRedlineTxt( STR_AUTOFMTREDL_DEL_MORELINES );
1393 const SwTxtNode* pNxtNd = GetNextNode();
1394 while( CanJoin( pNxtNd ) &&
1395 CalcLevel( *pNxtNd ) )
1397 bBreak = !IsFastFullLine( *pNxtNd ) || IsBlanksInString( *pNxtNd ) ||
1398 IsSentenceAtEnd( *pNxtNd );
1399 if( DeleteAktNxtPara( pNxtNd->GetTxt() ) )
1400 pDoc->Insert( aDelPam, ' ' );
1401 if( bBreak )
1402 break;
1403 pNxtNd = GetNextNode();
1406 DeleteAktPara( TRUE, TRUE );
1407 AutoCorrect();
1411 void SwAutoFormat::BuildText()
1413 SetRedlineTxt( STR_AUTOFMTREDL_SET_TMPL_TEXT );
1414 // lese alle nachfolgenden Absaetze die zu diesem Text
1415 // ohne Einzug gehoeren
1416 BOOL bBreak = TRUE;
1417 if( bMoreLines )
1418 DelMoreLinesBlanks();
1419 else
1420 bBreak = !IsFastFullLine( *pAktTxtNd ) ||
1421 IsBlanksInString( *pAktTxtNd ) ||
1422 IsSentenceAtEnd( *pAktTxtNd );
1423 SetColl( RES_POOLCOLL_TEXT, TRUE );
1424 if( !bBreak )
1426 SetRedlineTxt( STR_AUTOFMTREDL_DEL_MORELINES );
1427 const SwTxtNode* pNxtNd = GetNextNode();
1428 while( CanJoin( pNxtNd ) &&
1429 !CalcLevel( *pNxtNd ) )
1431 bBreak = !IsFastFullLine( *pNxtNd ) || IsBlanksInString( *pNxtNd ) ||
1432 IsSentenceAtEnd( *pNxtNd );
1433 if( DeleteAktNxtPara( pNxtNd->GetTxt() ) )
1434 pDoc->Insert( aDelPam, ' ' );
1435 if( bBreak )
1436 break;
1437 const SwTxtNode* pCurrNode = pNxtNd;
1438 pNxtNd = GetNextNode();
1439 if(!pNxtNd || pCurrNode == pNxtNd)
1440 break;
1443 DeleteAktPara( TRUE, TRUE );
1444 AutoCorrect();
1448 void SwAutoFormat::BuildEnum( USHORT nLvl, USHORT nDigitLevel )
1450 SetRedlineTxt( STR_AUTOFMTREDL_SET_NUMBULET );
1452 BOOL bBreak = TRUE;
1454 // als erstes den akt. Einzug bestimmen und die Framebreite bestimmen
1455 SwTwips nFrmWidth = pAktTxtFrm->Prt().Width();;
1456 SwTwips nLeftTxtPos;
1458 const sal_Unicode* pTxt = pAktTxtNd->GetTxt().GetBuffer(), *pSav = pTxt;
1459 while( IsSpace( *pTxt ) )
1460 ++pTxt;
1462 SwTxtFrmInfo aInfo( pAktTxtFrm );
1463 nLeftTxtPos = aInfo.GetCharPos( static_cast<xub_StrLen>(pTxt - pSav) );
1464 nLeftTxtPos -= pAktTxtNd->GetSwAttrSet().GetLRSpace().GetLeft();
1467 if( bMoreLines )
1468 DelMoreLinesBlanks();
1469 else
1470 bBreak = !IsFastFullLine( *pAktTxtNd ) ||
1471 IsBlanksInString( *pAktTxtNd ) ||
1472 IsSentenceAtEnd( *pAktTxtNd );
1473 sal_Bool bRTL = pEditShell->IsInRightToLeftText();
1474 // SetColl( RES_POOLCOLL_NUM_LEVEL1 + ( nLvl * 4 ) );
1475 DeleteAktPara( TRUE, TRUE );
1477 BOOL bChgBullet = FALSE, bChgEnum = FALSE;
1478 xub_StrLen nAutoCorrPos = 0;
1480 // falls die Numerierung gesetzt werden, die akt. besorgen
1481 // --> OD 2008-02-11 #newlistlevelattrs#
1482 SwNumRule aRule( pDoc->GetUniqueNumRuleName(),
1483 // --> OD 2008-06-06 #i89178#
1484 numfunc::GetDefaultPositionAndSpaceMode() );
1485 // <--
1486 // <--
1487 const SwNumRule* pCur = 0;
1488 if( aFlags.bSetNumRule && 0 != (pCur = pAktTxtNd->GetNumRule()) )
1489 aRule = *pCur;
1491 // ersetze das Bullet-Zeichen mit dem definiertem
1492 const String& rStr = pAktTxtNd->GetTxt();
1493 xub_StrLen nTxtStt = 0, nOrigTxtStt = 0;
1494 const sal_Unicode* pFndBulletChr;
1495 // if( aFlags.bAFmtByInput ? aFlags.bSetNumRule : aFlags.bChgEnumNum &&
1496 if( aFlags.bChgEnumNum &&
1497 2 < rStr.Len() &&
1498 0 != ( pFndBulletChr = StrChr( pBulletChar, rStr.GetChar( nTxtStt ) ))
1499 && IsSpace( rStr.GetChar( nTxtStt + 1 ) ) )
1501 if( aFlags.bAFmtByInput )
1503 if( aFlags.bSetNumRule )
1505 SwCharFmt* pCFmt = pDoc->GetCharFmtFromPool(
1506 RES_POOLCHR_BUL_LEVEL );
1507 bChgBullet = TRUE;
1508 // wurde das Format schon mal angepasst?
1509 if( !aRule.GetNumFmt( nLvl ) )
1511 int nBulletPos = pFndBulletChr - pBulletChar;
1512 sal_Unicode cBullChar;
1513 const Font* pBullFnt( 0 );
1514 if( nBulletPos < cnPosEnDash )
1516 cBullChar = aFlags.cBullet;
1517 pBullFnt = &aFlags.aBulletFont;
1519 else
1521 cBullChar = nBulletPos < cnPosEmDash
1522 ? cStarSymbolEnDash
1523 : cStarSymbolEmDash;
1524 // --> OD 2008-06-03 #i63395#
1525 // Only apply user defined default bullet font
1526 if ( numfunc::IsDefBulletFontUserDefined() )
1528 pBullFnt = &numfunc::GetDefBulletFont();
1530 // <--
1533 USHORT nAbsPos = lBullIndent;
1534 USHORT nSpaceSteps = nLvl
1535 ? USHORT(nLeftTxtPos / nLvl)
1536 : lBullIndent;
1537 for( BYTE n = 0; n < MAXLEVEL; ++n, nAbsPos = nAbsPos + nSpaceSteps )
1539 SwNumFmt aFmt( aRule.Get( n ) );
1540 aFmt.SetBulletFont( pBullFnt );
1541 aFmt.SetBulletChar( cBullChar );
1542 aFmt.SetNumberingType(SVX_NUM_CHAR_SPECIAL);
1543 aFmt.SetFirstLineOffset( lBullFirstLineOffset );
1544 aFmt.SetAbsLSpace( nAbsPos );
1545 if( !aFmt.GetCharFmt() )
1546 aFmt.SetCharFmt( pCFmt );
1547 if( bRTL )
1548 aFmt.SetNumAdjust( SVX_ADJUST_RIGHT );
1550 aRule.Set( n, aFmt );
1552 if( n == nLvl &&
1553 nFrmWidth < ( nSpaceSteps * MAXLEVEL ) )
1554 nSpaceSteps = static_cast<USHORT>(( nFrmWidth - nLeftTxtPos ) /
1555 ( MAXLEVEL - nLvl ));
1560 else
1562 bChgBullet = TRUE;
1563 SetColl( static_cast<USHORT>(RES_POOLCOLL_BUL_LEVEL1 + ( Min( nLvl, cnNumBullColls ) * 4 )) );
1566 else
1568 // dann ist das eine Nummerierung
1570 //JP 21.11.97: Der NumLevel wird entweder der DigitLevel oder
1571 // wenn der nicht vorhanden oder 0 ist, durch den
1572 // (Einrueckungs-)Level.
1574 String aPostFix, aPreFix, aNumTypes;
1575 if( USHRT_MAX != ( nDigitLevel = GetDigitLevel( *pAktTxtNd, nTxtStt,
1576 &aPreFix, &aPostFix, &aNumTypes )) )
1578 bChgEnum = TRUE;
1580 // Ebene 0 und Einrueckung dann wird die Ebene durch den linken
1581 // Einzug und der default NumEinrueckung bestimmt.
1582 if( !nDigitLevel && nLeftTxtPos )
1583 nLvl = Min( USHORT( nLeftTxtPos / lNumIndent ),
1584 USHORT( MAXLEVEL - 1 ) );
1585 else
1586 nLvl = nDigitLevel;
1589 if( bChgEnum && aFlags.bSetNumRule )
1591 if( !pCur ) // NumRule anpassen, wenn sie neu ist
1593 SwCharFmt* pCFmt = pDoc->GetCharFmtFromPool(
1594 RES_POOLCHR_NUM_LEVEL );
1595 if( !nDigitLevel )
1597 SwNumFmt aFmt( aRule.Get( nLvl ) );
1598 aFmt.SetStart( static_cast<USHORT>(aPreFix.GetToken( 1,
1599 (sal_Unicode)1 ).ToInt32()));
1600 aFmt.SetPrefix( aPreFix.GetToken( 0, (sal_Unicode)1 ));
1601 aFmt.SetSuffix( aPostFix.GetToken( 0, (sal_Unicode)1 ));
1602 aFmt.SetIncludeUpperLevels( 0 );
1604 if( !aFmt.GetCharFmt() )
1605 aFmt.SetCharFmt( pCFmt );
1607 if( aNumTypes.Len() )
1608 aFmt.SetNumberingType(aNumTypes.GetChar( 0 ) - '0');
1610 if( bRTL )
1611 aFmt.SetNumAdjust( SVX_ADJUST_RIGHT );
1612 aRule.Set( nLvl, aFmt );
1614 else
1616 USHORT nSpaceSteps = nLvl ? USHORT(nLeftTxtPos / nLvl) : 0;
1617 BYTE n;
1618 for( n = 0; n <= nLvl; ++n )
1620 SwNumFmt aFmt( aRule.Get( n ) );
1622 aFmt.SetStart( static_cast<USHORT>(aPreFix.GetToken( n+1,
1623 (sal_Unicode)1 ).ToInt32() ));
1624 if( !n )
1625 aFmt.SetPrefix( aPreFix.GetToken( n, (sal_Unicode)1 ));
1626 aFmt.SetSuffix( aPostFix.GetToken( n, (sal_Unicode)1 ));
1627 aFmt.SetIncludeUpperLevels( MAXLEVEL );
1628 if( n < aNumTypes.Len() )
1629 aFmt.SetNumberingType((aNumTypes.GetChar( n ) - '0'));
1631 aFmt.SetAbsLSpace( USHORT( nSpaceSteps * n )
1632 + lNumIndent );
1634 if( !aFmt.GetCharFmt() )
1635 aFmt.SetCharFmt( pCFmt );
1636 if( bRTL )
1637 aFmt.SetNumAdjust( SVX_ADJUST_RIGHT );
1639 aRule.Set( n, aFmt );
1642 // passt alles vollstaendig in den Frame?
1643 BOOL bDefStep = nFrmWidth < (nSpaceSteps * MAXLEVEL);
1644 for( ; n < MAXLEVEL; ++n )
1646 SwNumFmt aFmt( aRule.Get( n ) );
1647 aFmt.SetIncludeUpperLevels( MAXLEVEL );
1648 if( bDefStep )
1649 aFmt.SetAbsLSpace( USHORT( (nLeftTxtPos +
1650 SwNumRule::GetNumIndent(static_cast<BYTE>(n-nLvl)))));
1651 else
1652 aFmt.SetAbsLSpace( USHORT( nSpaceSteps * n )
1653 + lNumIndent );
1654 aRule.Set( n, aFmt );
1659 else if( !aFlags.bAFmtByInput )
1660 SetColl( static_cast<USHORT>(RES_POOLCOLL_NUM_LEVEL1 + ( Min( nLvl, cnNumBullColls ) * 4 ) ));
1661 else
1662 bChgEnum = FALSE;
1665 if( bChgEnum || bChgBullet )
1667 aDelPam.DeleteMark();
1668 aDelPam.GetPoint()->nNode = aNdIdx;
1670 if( aFlags.bSetNumRule )
1672 if( aFlags.bAFmtByInput )
1674 aDelPam.SetMark();
1675 aDelPam.GetMark()->nNode++;
1676 aDelPam.GetNode(FALSE)->GetTxtNode()->SetAttrListLevel( nLvl );
1679 pAktTxtNd->SetAttrListLevel(nLvl);
1680 pAktTxtNd->SetNumLSpace( TRUE );
1682 // --> OD 2008-03-17 #refactorlists#
1683 // start new list
1684 pDoc->SetNumRule( aDelPam, aRule, true );
1685 // <--
1686 aDelPam.DeleteMark();
1688 aDelPam.GetPoint()->nContent.Assign( pAktTxtNd, 0 );
1690 else
1691 aDelPam.GetPoint()->nContent.Assign( pAktTxtNd,
1692 bChgEnum ? (nTxtStt - nOrigTxtStt) : 0 );
1693 aDelPam.SetMark();
1695 if( bChgBullet )
1696 nTxtStt += 2;
1698 while( nTxtStt < rStr.Len() && IsSpace( rStr.GetChar( nTxtStt ) ))
1699 nTxtStt++;
1701 aDelPam.GetPoint()->nContent = nTxtStt - nOrigTxtStt;
1702 DeleteSel( aDelPam );
1704 if( !aFlags.bSetNumRule )
1706 String sChgStr( '\t' );
1707 if( bChgBullet )
1708 sChgStr.Insert( aFlags.cBullet, 0 );
1709 pDoc->Insert( aDelPam, sChgStr, true );
1711 SfxItemSet aSet( pDoc->GetAttrPool(), aTxtNodeSetRange );
1712 if( bChgBullet )
1714 aDelPam.GetPoint()->nContent = 0;
1715 aDelPam.SetMark();
1716 aDelPam.GetMark()->nContent = 1;
1717 SetAllScriptItem( aSet,
1718 SvxFontItem( aFlags.aBulletFont.GetFamily(),
1719 aFlags.aBulletFont.GetName(),
1720 aFlags.aBulletFont.GetStyleName(),
1721 aFlags.aBulletFont.GetPitch(),
1722 aFlags.aBulletFont.GetCharSet(),
1723 RES_CHRATR_FONT ) );
1724 pDoc->SetFmtItemByAutoFmt( aDelPam, aSet );
1725 aDelPam.DeleteMark();
1726 nAutoCorrPos = 2;
1727 aSet.ClearItem();
1729 SvxTabStopItem aTStops( RES_PARATR_TABSTOP ); aTStops.Insert( SvxTabStop( 0 ));
1730 aSet.Put( aTStops );
1731 pDoc->SetFmtItemByAutoFmt( aDelPam, aSet );
1735 if( bBreak )
1737 AutoCorrect( nAutoCorrPos ); /* Offset wegen Bullet + Tab */
1738 return;
1741 const SwTxtNode* pNxtNd = GetNextNode();
1742 while( CanJoin( pNxtNd ) &&
1743 nLvl == CalcLevel( *pNxtNd ) )
1745 SetRedlineTxt( STR_AUTOFMTREDL_DEL_MORELINES );
1746 bBreak = !IsFastFullLine( *pNxtNd ) || IsBlanksInString( *pNxtNd ) ||
1747 IsSentenceAtEnd( *pNxtNd );
1748 if( DeleteAktNxtPara( pNxtNd->GetTxt() ) )
1749 pDoc->Insert( aDelPam, ' ' );
1750 if( bBreak )
1751 break;
1752 const SwTxtNode* pCurrNode = pNxtNd;
1753 pNxtNd = GetNextNode();
1754 if(!pNxtNd || pCurrNode == pNxtNd)
1755 break;
1757 DeleteAktPara( FALSE, TRUE );
1758 AutoCorrect( nAutoCorrPos );
1762 void SwAutoFormat::BuildNegIndent( SwTwips nSpaces )
1764 SetRedlineTxt( STR_AUTOFMTREDL_SET_TMPL_NEG_INDENT );
1765 // Test auf Gegenueberstellung:
1766 // (n Worte, durch Space/Tabs getrennt, mit gleicher
1767 // Einrueckung in der 2.Zeile)
1769 // lese alle nachfolgenden Absaetze die zu dieser Aufzaehlung gehoeren
1770 BOOL bBreak = TRUE;
1771 xub_StrLen nSpacePos, nTxtPos = GetBigIndent( nSpacePos );
1772 if( bMoreLines )
1773 DelMoreLinesBlanks( TRUE );
1774 else
1775 bBreak = !IsFastFullLine( *pAktTxtNd ) ||
1776 ( !nTxtPos && IsBlanksInString( *pAktTxtNd )) ||
1777 IsSentenceAtEnd( *pAktTxtNd );
1779 SetColl( static_cast<USHORT>( nTxtPos
1780 ? RES_POOLCOLL_CONFRONTATION
1781 : RES_POOLCOLL_TEXT_NEGIDENT ) );
1783 if( nTxtPos )
1785 const String& rStr = pAktTxtNd->GetTxt();
1786 BOOL bInsTab = TRUE;
1788 if( '\t' == rStr.GetChar( nSpacePos+1 )) // ein Tab, das belassen wir
1790 --nSpacePos;
1791 bInsTab = FALSE;
1794 xub_StrLen nSpaceStt = nSpacePos;
1795 while( nSpaceStt && IsSpace( rStr.GetChar( --nSpaceStt ) ) )
1797 ++nSpaceStt;
1799 if( bInsTab && '\t' == rStr.GetChar( nSpaceStt ) ) // ein Tab, das belassen wir
1801 ++nSpaceStt;
1802 bInsTab = FALSE;
1806 aDelPam.DeleteMark();
1807 aDelPam.GetPoint()->nNode = aNdIdx;
1808 aDelPam.GetPoint()->nContent.Assign( pAktTxtNd, nSpacePos );
1810 // alten Spaces, usw. loeschen
1811 if( nSpaceStt < nSpacePos )
1813 aDelPam.SetMark();
1814 aDelPam.GetMark()->nContent = nSpaceStt;
1815 DeleteSel( aDelPam );
1816 if( bInsTab )
1817 pDoc->Insert( aDelPam, '\t' );
1821 if( !bBreak )
1823 SetRedlineTxt( STR_AUTOFMTREDL_DEL_MORELINES );
1824 SwTxtFrmInfo aFInfo( pAktTxtFrm );
1825 const SwTxtNode* pNxtNd = GetNextNode();
1826 while( CanJoin( pNxtNd ) &&
1827 20 < Abs( (long)(nSpaces - aFInfo.SetFrm(
1828 GetFrm( *pNxtNd ) ).GetLineStart() ))
1831 bBreak = !IsFastFullLine( *pNxtNd ) ||
1832 IsBlanksInString( *pNxtNd ) ||
1833 IsSentenceAtEnd( *pNxtNd );
1834 if( DeleteAktNxtPara( pNxtNd->GetTxt() ) )
1835 pDoc->Insert( aDelPam, ' ' );
1836 if( bBreak )
1837 break;
1838 pNxtNd = GetNextNode();
1841 DeleteAktPara( TRUE, TRUE );
1842 AutoCorrect();
1846 void SwAutoFormat::BuildHeadLine( USHORT nLvl )
1848 if( aFlags.bWithRedlining )
1850 String sTxt( *ViewShell::GetShellRes()->GetAutoFmtNameLst()[
1851 STR_AUTOFMTREDL_SET_TMPL_HEADLINE ] );
1852 sTxt.SearchAndReplace( String::CreateFromAscii(
1853 RTL_CONSTASCII_STRINGPARAM( "$(ARG1)" )),
1854 String::CreateFromInt32( nLvl + 1 ) );
1855 pDoc->SetAutoFmtRedlineComment( &sTxt );
1858 SetColl( static_cast<USHORT>(RES_POOLCOLL_HEADLINE1 + nLvl ), TRUE );
1859 if( aFlags.bAFmtByInput )
1861 SwTxtFmtColl& rNxtColl = pAktTxtNd->GetTxtColl()->GetNextTxtFmtColl();
1863 DelPrevPara();
1865 DeleteAktPara( TRUE, FALSE );
1866 DeleteAktNxtPara( aEmptyStr );
1868 aDelPam.DeleteMark();
1869 aDelPam.GetPoint()->nNode = aNdIdx.GetIndex() + 1;
1870 aDelPam.GetPoint()->nContent.Assign( aDelPam.GetCntntNode(), 0 );
1871 pDoc->SetTxtFmtColl( aDelPam, &rNxtColl );
1873 else
1875 DeleteAktPara( TRUE, TRUE );
1876 AutoCorrect();
1881 // dann lasse doch mal das AutoCorrect auf den akt. TextNode los
1882 void SwAutoFormat::AutoCorrect( xub_StrLen nPos )
1884 if( aFlags.bAFmtByInput ||
1885 (!aFlags.bAutoCorrect && !aFlags.bReplaceQuote &&
1886 !aFlags.bCptlSttSntnc && !aFlags.bCptlSttWrd &&
1887 !aFlags.bChgFracionSymbol && !aFlags.bChgOrdinalNumber &&
1888 !aFlags.bChgToEnEmDash && !aFlags.bSetINetAttr &&
1889 !aFlags.bChgWeightUnderl && !aFlags.bAddNonBrkSpace) )
1890 return;
1892 const String* pTxt = &pAktTxtNd->GetTxt();
1893 if( nPos >= pTxt->Len() )
1894 return;
1896 BOOL bGetLanguage = aFlags.bChgOrdinalNumber ||
1897 aFlags.bChgToEnEmDash || aFlags.bSetINetAttr ||
1898 aFlags.bCptlSttWrd || aFlags.bCptlSttSntnc ||
1899 aFlags.bAddNonBrkSpace;
1902 aDelPam.DeleteMark();
1903 aDelPam.GetPoint()->nNode = aNdIdx;
1904 aDelPam.GetPoint()->nContent.Assign( pAktTxtNd, 0 );
1906 SwAutoCorrDoc aACorrDoc( *pEditShell, aDelPam );
1907 SvxAutoCorrect* pATst = SvxAutoCorrCfg::Get()->GetAutoCorrect();
1909 SwTxtFrmInfo aFInfo( 0 );
1911 xub_StrLen nSttPos, nLastBlank = nPos;
1912 BOOL bFirst = aFlags.bCptlSttSntnc, bFirstSent = bFirst;
1913 sal_Unicode cChar = 0;
1915 CharClass& rAppCC = GetAppCharClass();
1917 do {
1918 while( nPos < pTxt->Len() && IsSpace( cChar = pTxt->GetChar( nPos ) ))
1919 ++nPos;
1920 if( nPos == pTxt->Len() )
1921 break; // das wars
1923 if( aFlags.bReplaceQuote &&
1924 ( '\"' == cChar || '\'' == cChar ) &&
1925 ( !nPos || ' ' == pTxt->GetChar( nPos-1 ) ) )
1927 // --------------------------------------
1928 // beachte: Sonderfall Symbolfonts !!!
1929 if( !aFInfo.GetFrm() )
1930 aFInfo.SetFrm( GetFrm( *pAktTxtNd ) );
1931 if( !aFInfo.IsBullet( nPos ))
1933 SetRedlineTxt( STR_AUTOFMTREDL_TYPO );
1934 aDelPam.GetPoint()->nContent = nPos;
1935 BOOL bSetHardBlank = FALSE;
1937 String sReplace( pATst->GetQuote( aACorrDoc,
1938 nPos, cChar, TRUE ));
1940 aDelPam.SetMark();
1941 aDelPam.GetPoint()->nContent = nPos+1;
1942 if( 2 == sReplace.Len() && ' ' == sReplace.GetChar( 1 ))
1944 sReplace.Erase( 1 );
1945 bSetHardBlank = TRUE;
1947 pDoc->Replace( aDelPam, sReplace, FALSE );
1949 if( aFlags.bWithRedlining )
1951 aNdIdx = aDelPam.GetPoint()->nNode;
1952 pAktTxtNd = aNdIdx.GetNode().GetTxtNode();
1953 pTxt = &pAktTxtNd->GetTxt();
1954 aDelPam.SetMark();
1955 aFInfo.SetFrm( 0 );
1958 nPos += sReplace.Len() - 1;
1959 aDelPam.DeleteMark();
1960 if( bSetHardBlank )
1962 pDoc->Insert( aDelPam, CHAR_HARDBLANK );
1963 ++nPos;
1968 int bCallACorr = FALSE;
1969 int bBreak = 0;
1970 if( nPos && IsSpace( pTxt->GetChar( nPos-1 )))
1971 nLastBlank = nPos;
1972 for( nSttPos = nPos; !bBreak && nPos < pTxt->Len(); ++nPos )
1973 switch( cChar = pTxt->GetChar( nPos ) )
1975 case '\"':
1976 case '\'':
1977 if( aFlags.bReplaceQuote )
1979 // --------------------------------------
1980 // beachte: Sonderfall Symbolfonts !!!
1981 if( !aFInfo.GetFrm() )
1982 aFInfo.SetFrm( GetFrm( *pAktTxtNd ) );
1983 if( !aFInfo.IsBullet( nPos ))
1985 SetRedlineTxt( STR_AUTOFMTREDL_TYPO );
1986 BOOL bSetHardBlank = FALSE;
1987 aDelPam.GetPoint()->nContent = nPos;
1988 String sReplace( pATst->GetQuote( aACorrDoc,
1989 nPos, cChar, FALSE ));
1991 if( 2 == sReplace.Len() && ' ' == sReplace.GetChar( 0 ))
1993 sReplace.Erase( 0, 1 );
1994 bSetHardBlank = TRUE;
1997 aDelPam.SetMark();
1998 aDelPam.GetPoint()->nContent = nPos+1;
1999 pDoc->Replace( aDelPam, sReplace, FALSE );
2001 if( aFlags.bWithRedlining )
2003 aNdIdx = aDelPam.GetPoint()->nNode;
2004 pAktTxtNd = aNdIdx.GetNode().GetTxtNode();
2005 pTxt = &pAktTxtNd->GetTxt();
2006 aDelPam.SetMark();
2007 aDelPam.DeleteMark();
2008 aFInfo.SetFrm( 0 );
2011 nPos += sReplace.Len() - 1;
2012 aDelPam.DeleteMark();
2014 if( bSetHardBlank )
2016 aDelPam.GetPoint()->nContent = nPos;
2017 pDoc->Insert( aDelPam, CHAR_HARDBLANK );
2018 aDelPam.GetPoint()->nContent = ++nPos;
2022 break;
2023 case '*':
2024 case '_':
2025 if( aFlags.bChgWeightUnderl )
2027 // --------------------------------------
2028 // beachte: Sonderfall Symbolfonts !!!
2029 if( !aFInfo.GetFrm() )
2030 aFInfo.SetFrm( GetFrm( *pAktTxtNd ) );
2031 if( !aFInfo.IsBullet( nPos ))
2033 SetRedlineTxt( '*' == cChar
2034 ? STR_AUTOFMTREDL_BOLD
2035 : STR_AUTOFMTREDL_UNDER );
2037 sal_Unicode cBlank = nSttPos ? pTxt->GetChar(nSttPos - 1) : 0;
2038 aDelPam.GetPoint()->nContent = nPos;
2040 if( pATst->FnChgWeightUnderl( aACorrDoc, *pTxt,
2041 nSttPos, nPos ))
2043 if( aFlags.bWithRedlining )
2045 aNdIdx = aDelPam.GetPoint()->nNode;
2046 pAktTxtNd = aNdIdx.GetNode().GetTxtNode();
2047 pTxt = &pAktTxtNd->GetTxt();
2048 aDelPam.SetMark();
2049 aDelPam.DeleteMark();
2050 aFInfo.SetFrm( 0 );
2052 //#125102# in case of the mode REDLINE_SHOW_DELETE the ** are still contained in pTxt
2053 if(0 == (pDoc->GetRedlineMode() & nsRedlineMode_t::REDLINE_SHOW_DELETE))
2054 nPos = aDelPam.GetPoint()->nContent.GetIndex() - 1;
2055 // wurde vorm Start ein Zeichen entfernt?
2056 if( cBlank && cBlank != pTxt->GetChar(nSttPos - 1) )
2057 --nSttPos;
2061 break;
2063 case '.':
2064 case '!':
2065 case '?':
2066 if( aFlags.bCptlSttSntnc )
2067 bFirstSent = TRUE;
2068 //alle Wortrenner loesen die Autokorrektur aus!
2069 // break;
2071 default:
2072 //alle Wortrenner loesen die Autokorrektur aus!
2073 // case ' ':
2074 // case '\t':
2075 if( !( rAppCC.isLetterNumeric( *pTxt, nPos )
2076 || '/' == cChar )) // '/' should not be a word seperator (e.g. '1/2' needs to be handled as one word for replacement)
2078 --nPos; // ++nPos von dem for ungueltig machen !
2079 ++bBreak;
2081 break;
2084 if( nPos == nSttPos )
2086 if( ++nPos == pTxt->Len() )
2087 bCallACorr = TRUE;
2089 else
2090 bCallACorr = TRUE;
2093 if( bCallACorr )
2095 bCallACorr = FALSE;
2096 aDelPam.GetPoint()->nContent = nPos;
2097 SetRedlineTxt( STR_AUTOFMTREDL_USE_REPLACE );
2098 if( aFlags.bAutoCorrect &&
2099 aACorrDoc.ChgAutoCorrWord( nSttPos, nPos, *pATst, 0 ) )
2101 nPos = aDelPam.GetPoint()->nContent.GetIndex();
2103 if( aFlags.bWithRedlining )
2105 aNdIdx = aDelPam.GetPoint()->nNode;
2106 pAktTxtNd = aNdIdx.GetNode().GetTxtNode();
2107 pTxt = &pAktTxtNd->GetTxt();
2108 aDelPam.SetMark();
2109 aDelPam.DeleteMark();
2112 continue; // nichts weiter mehr abpruefen
2115 LanguageType eLang = (bGetLanguage && pAktTxtNd)
2116 ? pAktTxtNd->GetLang( nSttPos )
2117 : LANGUAGE_SYSTEM;
2119 if( ( aFlags.bChgFracionSymbol &&
2120 SetRedlineTxt( STR_AUTOFMTREDL_FRACTION ) &&
2121 pATst->FnChgFractionSymbol( aACorrDoc, *pTxt, nSttPos, nPos ) ) ||
2122 ( aFlags.bChgOrdinalNumber &&
2123 SetRedlineTxt( STR_AUTOFMTREDL_ORDINAL ) &&
2124 pATst->FnChgOrdinalNumber( aACorrDoc, *pTxt, nSttPos, nPos, eLang ) ) ||
2125 ( aFlags.bChgToEnEmDash &&
2126 SetRedlineTxt( STR_AUTOFMTREDL_DASH ) &&
2127 pATst->FnChgToEnEmDash( aACorrDoc, *pTxt, nSttPos, nPos, eLang ) ) ||
2128 ( aFlags.bAddNonBrkSpace &&
2129 SetRedlineTxt( STR_AUTOFMTREDL_NON_BREAK_SPACE ) &&
2130 pATst->FnAddNonBrkSpace( aACorrDoc, *pTxt, nSttPos, nPos, eLang ) ) ||
2131 ( aFlags.bSetINetAttr &&
2132 ( nPos == pTxt->Len() || IsSpace( pTxt->GetChar( nPos )) ) &&
2133 SetRedlineTxt( STR_AUTOFMTREDL_DETECT_URL ) &&
2134 pATst->FnSetINetAttr( aACorrDoc, *pTxt, nLastBlank, nPos, eLang ) ) )
2135 nPos = aDelPam.GetPoint()->nContent.GetIndex();
2136 else
2138 // Zwei Grossbuchstaben am Wort-Anfang ??
2139 if( aFlags.bCptlSttWrd )
2141 SetRedlineTxt( STR_AUTOFMTREDL_CPTL_STT_WORD );
2142 pATst->FnCptlSttWrd( aACorrDoc, *pTxt, nSttPos, nPos, eLang );
2144 // Grossbuchstabe am Satz-Anfang ??
2145 if( aFlags.bCptlSttSntnc && bFirst )
2147 SetRedlineTxt( STR_AUTOFMTREDL_CPTL_STT_SENT );
2148 pATst->FnCptlSttSntnc( aACorrDoc, *pTxt, TRUE, nSttPos, nPos, eLang);
2149 bFirst = FALSE;
2152 bFirst = bFirstSent;
2153 bFirstSent = FALSE;
2155 if( aFlags.bWithRedlining )
2157 aNdIdx = aDelPam.GetPoint()->nNode;
2158 pAktTxtNd = aNdIdx.GetNode().GetTxtNode();
2159 pTxt = &pAktTxtNd->GetTxt();
2160 aDelPam.SetMark();
2161 aDelPam.DeleteMark();
2165 } while( nPos < pTxt->Len() );
2166 ClearRedlineTxt();
2170 SwAutoFormat::SwAutoFormat( SwEditShell* pEdShell, SvxSwAutoFmtFlags& rFlags,
2171 SwNodeIndex* pSttNd, SwNodeIndex* pEndNd )
2172 : aFlags( rFlags ),
2173 aDelPam( pEdShell->GetDoc()->GetNodes().GetEndOfExtras() ),
2174 aNdIdx( pEdShell->GetDoc()->GetNodes().GetEndOfExtras(), +1 ),
2175 aEndNdIdx( pEdShell->GetDoc()->GetNodes().GetEndOfContent() ),
2176 pEditShell( pEdShell ),
2177 pDoc( pEdShell->GetDoc() ),
2178 pAktTxtNd( 0 ), pAktTxtFrm( 0 ),
2179 pCharClass( 0 ),
2180 nRedlAutoFmtSeqId( 0 )
2182 ASSERT( (pSttNd && pEndNd) || (!pSttNd && !pEndNd),
2183 "Kein Bereich angegeben" );
2185 if( aFlags.bSetNumRule && !aFlags.bAFmtByInput )
2186 aFlags.bSetNumRule = FALSE;
2188 BOOL bReplaceStyles = !aFlags.bAFmtByInput || aFlags.bReplaceStyles;
2190 const SwTxtNode* pNxtNd = 0;
2191 BOOL bNxtEmpty = FALSE;
2192 BOOL bNxtAlpha = FALSE;
2193 USHORT nNxtLevel = 0;
2195 // setze den Bereich zum Autoformatieren
2196 if( pSttNd )
2198 aNdIdx = *pSttNd;
2199 aNdIdx--; // fuer GoNextPara, ein Absatz davor
2200 aEndNdIdx = *pEndNd;
2201 aEndNdIdx++;
2203 // teste den vorhergehenden TextNode
2204 pNxtNd = aNdIdx.GetNode().GetTxtNode();
2205 bEmptyLine = !pNxtNd ||
2206 IsEmptyLine( *pNxtNd ) ||
2207 IsNoAlphaLine( *pNxtNd );
2209 else
2210 bEmptyLine = TRUE; // am Dokument Anfang
2212 bEnde = FALSE;
2214 // setze die Werte fuer die Prozent-Anzeige
2215 nEndNdIdx = aEndNdIdx.GetIndex();
2217 if( !aFlags.bAFmtByInput )
2218 ::StartProgress( STR_STATSTR_AUTOFORMAT, aNdIdx.GetIndex(),
2219 nEndNdIdx = aEndNdIdx.GetIndex(),
2220 pDoc->GetDocShell() );
2222 RedlineMode_t eRedlMode = pDoc->GetRedlineMode(), eOldMode = eRedlMode;
2223 if( aFlags.bWithRedlining )
2225 pDoc->SetAutoFmtRedline( TRUE );
2226 eRedlMode = (RedlineMode_t)(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_SHOW_INSERT);
2228 else
2229 eRedlMode = (RedlineMode_t)(nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_IGNORE);
2230 pDoc->SetRedlineMode( eRedlMode );
2232 // save undo state (might be turned off)
2233 sal_Bool bUndoState = pDoc->DoesUndo();
2235 // wenn mehrere Zeilen, dann erstmal nicht mit
2236 // dem nachfolgenden Absatz zusammenfassen.
2237 bMoreLines = FALSE;
2239 nLastCalcHeadLvl = nLastCalcEnumLvl = 0;
2240 nLastHeadLvl = nLastEnumLvl = USHRT_MAX;
2241 USHORT nLevel = 0;
2242 USHORT nDigitLvl = 0;
2244 // defaulten
2245 SwTxtFrmInfo aFInfo( 0 );
2247 // das ist unser Automat fuer die Auto-Formatierung
2248 eStat = READ_NEXT_PARA;
2249 while( !bEnde )
2251 // #95884# limit redline array size to prevent overflow and to conserve
2252 // memory
2253 if( pDoc->HasTooManyUndos() )
2255 DBG_ASSERT( bUndoState, "undo overflow without undo?" );
2257 //ask user
2258 short nResult = m_nActionWhileAutoformatUndoBufferOverflow; // TODO: #102007# read the last decision of the user from configuration
2259 if(m_bAskForCancelUndoWhileBufferOverflow) // #102007# TODO: read the last decision of the user from configuration
2261 Window* pParent = pEditShell?pEditShell->GetWin():NULL;
2262 WarningBox aWarning( pParent,SW_RES(MSG_DISABLE_UNDO_QUESTION));
2263 aWarning.SetDefaultCheckBoxText();
2264 USHORT nDefaultButton = nResult==RET_YES?BUTTONID_YES:(nResult==RET_NO?BUTTONID_NO:BUTTONID_CANCEL);
2265 aWarning.SetFocusButton(nDefaultButton);
2266 nResult = aWarning.Execute();
2267 m_bAskForCancelUndoWhileBufferOverflow = !aWarning.GetCheckBoxState();
2268 m_nActionWhileAutoformatUndoBufferOverflow = nResult;
2269 // TODO: #102007# store m_bAskForCancelUndoWhileBufferOverflow in configuration
2270 // TODO: #102007# store m_nActionWhileAutoformatUndoBufferOverflow in configuration
2273 DBG_ASSERT( (nResult == RET_YES) || (nResult == RET_CANCEL) || (nResult == RET_NO),
2274 "unexpected result" );
2276 if( nResult == RET_YES )
2278 // turn off undo and continue
2279 pDoc->DoUndo( sal_False );
2280 pDoc->DelAllUndoObj();
2282 else if( nResult == RET_NO )
2284 //stop autoformatting and keep changes
2285 eStat = IS_ENDE;
2287 else if( nResult == RET_CANCEL )
2289 //cancel autoformatting and undo changes
2290 eStat = IS_ENDE;
2292 // TODO: #102004# undo changes
2296 switch( eStat )
2298 case READ_NEXT_PARA:
2300 GoNextPara();
2301 eStat = bEnde ? IS_ENDE : TST_EMPTY_LINE;
2303 break;
2305 case TST_EMPTY_LINE:
2306 if( IsEmptyLine( *pAktTxtNd ) )
2308 if( aFlags.bDelEmptyNode && !HasObjects( *pAktTxtNd ) )
2310 bEmptyLine = TRUE;
2311 ULONG nOldCnt = pDoc->GetNodes().Count();
2312 DelEmptyLine();
2313 // wurde wiklich ein Node geloescht ?
2314 if( nOldCnt != pDoc->GetNodes().Count() )
2315 aNdIdx--; // nicht den naechsten Absatz ueberspringen
2317 eStat = READ_NEXT_PARA;
2319 else
2320 eStat = TST_ALPHA_LINE;
2321 break;
2323 case TST_ALPHA_LINE:
2324 if( IsNoAlphaLine( *pAktTxtNd ))
2326 // erkenne eine Tabellendefinition +---+---+
2327 if( aFlags.bAFmtByInput && aFlags.bCreateTable && DoTable() )
2329 //JP 30.09.96: das DoTable() verlaesst sich auf das
2330 // Pop und Move - Crsr nach dem AutoFormat!
2331 pEdShell->Pop( FALSE );
2332 *pEdShell->GetCrsr() = aDelPam;
2333 pEdShell->Push();
2335 eStat = IS_ENDE;
2336 break;
2339 // dann teste mal auf 3 "---" oder "===". In dem Fall
2340 // soll der vorherige Absatz unterstrichen und dieser
2341 // geloescht werden!
2342 if( !DoUnderline() && bReplaceStyles )
2344 SetColl( RES_POOLCOLL_STANDARD, TRUE );
2345 bEmptyLine = TRUE;
2347 eStat = READ_NEXT_PARA;
2349 else
2350 eStat = GET_ALL_INFO;
2351 break;
2353 case GET_ALL_INFO:
2355 if( pAktTxtNd->GetNumRule() )
2357 // in Numerierung nichts machen, zum naechsten
2358 bEmptyLine = FALSE;
2359 eStat = READ_NEXT_PARA;
2360 // loesche alle Blanks am Anfang/Ende
2361 // und alle mitten drin
2362 //JP 29.04.98: erstmal nur alle "mitten drin".
2363 DelMoreLinesBlanks( FALSE );
2364 break;
2367 aFInfo.SetFrm( pAktTxtFrm );
2369 // erstmal: wurden schon mal entsprechende Vorlagen
2370 // vergeben, so behalte die bei, gehe zum
2371 // naechsten Node.
2372 USHORT nPoolId = pAktTxtNd->GetTxtColl()->GetPoolFmtId();
2373 if( IsPoolUserFmt( nPoolId )
2374 ? !aFlags.bChgUserColl
2375 : ( RES_POOLCOLL_STANDARD != nPoolId &&
2376 ( !aFlags.bAFmtByInput ||
2377 (RES_POOLCOLL_TEXT_MOVE != nPoolId &&
2378 RES_POOLCOLL_TEXT != nPoolId )) ))
2380 eStat = HAS_FMTCOLL;
2381 break;
2384 // teste auf Harte oder aus Vorlagen gesetzte LRSpaces
2385 if( IsPoolUserFmt( nPoolId ) ||
2386 RES_POOLCOLL_STANDARD == nPoolId )
2388 short nSz;
2389 SvxLRSpaceItem* pLRSpace;
2390 if( SFX_ITEM_SET == pAktTxtNd->GetSwAttrSet().
2391 GetItemState( RES_LR_SPACE, TRUE,
2392 (const SfxPoolItem**)&pLRSpace ) &&
2393 ( 0 != (nSz = pLRSpace->GetTxtFirstLineOfst()) ||
2394 0 != pLRSpace->GetTxtLeft() ) )
2396 // Ausnahme: Numerierun/Aufzaehlung kann mit Einzug
2397 // existieren!!
2398 if( IsEnumericChar( *pAktTxtNd ))
2400 nLevel = CalcLevel( *pAktTxtNd, &nDigitLvl );
2401 if( nLevel >= MAXLEVEL )
2402 nLevel = MAXLEVEL-1;
2403 BuildEnum( nLevel, nDigitLvl );
2404 eStat = READ_NEXT_PARA;
2405 break;
2409 // nie zusammenfassen, so belassen
2410 // (Opt. vielleicht als Ausnahmen nur Einzug)
2411 bMoreLines = TRUE;
2413 if( bReplaceStyles )
2415 // dann setze doch eine unserer Vorlagen
2416 if( 0 < nSz ) // positiver 1. Zeileneinzug
2417 BuildIndent();
2418 else if( 0 > nSz ) // negativer 1. Zeileneinzug
2419 BuildNegIndent( aFInfo.GetLineStart() );
2420 else if( pLRSpace->GetTxtLeft() ) // ist ein Einzug
2421 BuildTextIndent();
2423 eStat = READ_NEXT_PARA;
2424 break;
2428 nLevel = CalcLevel( *pAktTxtNd, &nDigitLvl );
2429 bMoreLines = !IsOneLine( *pAktTxtNd );
2430 pNxtNd = GetNextNode();
2431 if( pNxtNd )
2433 bNxtEmpty = IsEmptyLine( *pNxtNd );
2434 bNxtAlpha = IsNoAlphaLine( *pNxtNd );
2435 nNxtLevel = CalcLevel( *pNxtNd );
2437 if( !bEmptyLine && HasBreakAttr( *pAktTxtNd ) )
2438 bEmptyLine = TRUE;
2439 if( !bNxtEmpty && HasBreakAttr( *pNxtNd ) )
2440 bNxtEmpty = TRUE;
2442 // fuer z.B. selbst definierte Einzuege oder
2443 // rechts/zentierte Ausrichtung
2444 // if( !nLevel && 0 != aFInfo.GetLineStart() )
2445 // nLevel = 1;
2447 else
2449 bNxtEmpty = FALSE; // TRUE;
2450 bNxtAlpha = FALSE;
2451 nNxtLevel = 0;
2453 eStat = !bMoreLines ? IS_ONE_LINE : TST_ENUMERIC;
2455 break;
2457 case IS_ONE_LINE:
2459 eStat = TST_ENUMERIC;
2460 if( !bReplaceStyles )
2461 break;
2463 String sClrStr( pAktTxtNd->GetTxt() );
2465 if( !DelLeadingBlanks( sClrStr ).Len() )
2467 bEmptyLine = TRUE;
2468 eStat = READ_NEXT_PARA;
2469 break; // naechsten Absatz lesen
2472 // Teste auf Ueberschrift
2473 if( !bEmptyLine || !IsFirstCharCapital( *pAktTxtNd ) ||
2474 IsBlanksInString( *pAktTxtNd ) )
2475 break;
2477 bEmptyLine = FALSE;
2478 String sEndClrStr( sClrStr );
2479 xub_StrLen nLen = DelTrailingBlanks( sEndClrStr ).Len();
2481 // nicht, dann teste auf Ueberschrift
2482 if( ':' == sEndClrStr.GetChar( nLen - 1 ) )
2484 //---------------------------------------------------------------------------
2485 // Wie ist denn nun die Bedingung fuer die Ueberschrift auf Ebene 3 ??
2486 // Zur Zeit: generell wenn am Ende ein ':' ist.
2488 // if( bNxtEmpty || bNxtAlpha )
2489 // !IsEnumericChar( *pNxtNd ) )
2490 //---------------------------------------------------------------------------
2492 BuildHeadLine( 2 );
2493 eStat = READ_NEXT_PARA;
2494 break;
2497 else if( 256 <= sEndClrStr.GetChar( nLen-1 ) ||
2498 !strchr( ",.;", sEndClrStr.GetChar( nLen-1 )) )
2500 if( bNxtEmpty || bNxtAlpha
2501 || ( pNxtNd && IsEnumericChar( *pNxtNd ))
2503 //---------------------------------------------------------------------------
2504 // ist zum Verwechseln mit neg. Einzug !!
2505 /*|| nLevel < nNxtLevel*/
2506 //---------------------------------------------------------------------------
2510 // wurde Level vom Text vorgegeben ?
2511 // if( USHRT_MAX != nDigitLvl )
2512 // nLevel = nDigitLvl;
2514 // eine Ebene runter ?
2515 if( nLevel >= MAXLEVEL )
2516 nLevel = MAXLEVEL-1;
2518 if( USHRT_MAX == nLastHeadLvl )
2519 nLastHeadLvl = 0;
2520 else if( nLastCalcHeadLvl < nLevel )
2522 if( nLastHeadLvl+1 < MAXLEVEL )
2523 ++nLastHeadLvl;
2525 // eine Ebene hoch ?
2526 else if( nLastCalcHeadLvl > nLevel )
2528 if( nLastHeadLvl )
2529 --nLastHeadLvl;
2531 nLastCalcHeadLvl = nLevel;
2533 if( aFlags.bAFmtByInput )
2534 BuildHeadLine( nLevel );
2535 else
2536 BuildHeadLine( nLastHeadLvl );
2537 eStat = READ_NEXT_PARA;
2538 break;
2542 break;
2544 case TST_ENUMERIC:
2546 bEmptyLine = FALSE;
2547 if( IsEnumericChar( *pAktTxtNd ))
2549 if( nLevel >= MAXLEVEL )
2550 nLevel = MAXLEVEL-1;
2551 BuildEnum( nLevel, nDigitLvl );
2552 eStat = READ_NEXT_PARA;
2554 //JP 25.03.96: Vorlagen fuer Einzug zulassen
2555 // else if( aFlags.bAFmtByInput )
2556 // eStat = READ_NEXT_PARA;
2557 else if( bReplaceStyles )
2558 eStat = nLevel ? TST_IDENT : TST_NEG_IDENT;
2559 else
2560 eStat = READ_NEXT_PARA;
2562 break;
2564 case TST_IDENT:
2565 // Spaces am Anfang, dann teste doch mal auf Einzuege
2566 if( bMoreLines && nLevel )
2568 SwTwips nSz = aFInfo.GetFirstIndent();
2569 if( 0 < nSz ) // positiver 1. Zeileneinzug
2570 BuildIndent();
2571 else if( 0 > nSz ) // negativer 1. Zeileneinzug
2572 BuildNegIndent( aFInfo.GetLineStart() );
2573 else // ist ein Einzug
2574 BuildTextIndent();
2575 eStat = READ_NEXT_PARA;
2577 else if( nLevel && pNxtNd && !bEnde &&
2578 !bNxtEmpty && !bNxtAlpha && !nNxtLevel &&
2579 !IsEnumericChar( *pNxtNd ) )
2581 // ist ein Einzug
2582 BuildIndent();
2583 eStat = READ_NEXT_PARA;
2585 else
2586 eStat = TST_TXT_BODY;
2587 break;
2589 case TST_NEG_IDENT:
2590 // keine Spaces am Anfang, dann teste doch mal auf neg. Einzuege
2592 if( bMoreLines && !nLevel )
2594 SwTwips nSz = aFInfo.GetFirstIndent();
2595 if( 0 < nSz ) // positiver 1. Zeileneinzug
2596 BuildIndent();
2597 else if( 0 > nSz ) // negativer 1. Zeileneinzug
2598 BuildNegIndent( aFInfo.GetLineStart() );
2599 else // ist ein kein Einzug
2600 BuildText();
2601 eStat = READ_NEXT_PARA;
2603 else if( !nLevel && pNxtNd && !bEnde &&
2604 !bNxtEmpty && !bNxtAlpha && nNxtLevel &&
2605 !IsEnumericChar( *pNxtNd ) )
2607 // ist ein neg. Einzug
2608 BuildNegIndent( aFInfo.GetLineStart() );
2609 eStat = READ_NEXT_PARA;
2611 else
2612 eStat = TST_TXT_BODY;
2614 break;
2616 case TST_TXT_BODY:
2618 if( bMoreLines )
2620 SwTwips nSz = aFInfo.GetFirstIndent();
2621 if( 0 < nSz ) // positiver 1. Zeileneinzug
2622 BuildIndent();
2623 else if( 0 > nSz ) // negativer 1. Zeileneinzug
2624 BuildNegIndent( aFInfo.GetLineStart() );
2625 else if( nLevel ) // ist ein Einzug
2626 BuildTextIndent();
2627 else
2628 BuildText();
2630 else if( nLevel )
2631 BuildTextIndent();
2632 else
2633 BuildText();
2634 eStat = READ_NEXT_PARA;
2636 break;
2638 case HAS_FMTCOLL:
2640 // erstmal: wurden schon mal entsprechende Vorlagen
2641 // vergeben, so behalte die bei, gehe zum
2642 // naechsten Node.
2643 bEmptyLine = FALSE;
2644 eStat = READ_NEXT_PARA;
2645 // loesche alle Blanks am Anfang/Ende
2646 // und alle mitten drin
2647 //JP 29.04.98: erstmal nur alle "mitten drin".
2648 DelMoreLinesBlanks( FALSE );
2650 // behandel die harte Attributierung
2651 if( pAktTxtNd->HasSwAttrSet() )
2653 short nSz;
2654 SvxLRSpaceItem* pLRSpace;
2655 if( bReplaceStyles &&
2656 SFX_ITEM_SET == pAktTxtNd->GetSwAttrSet().
2657 GetItemState( RES_LR_SPACE, FALSE,
2658 (const SfxPoolItem**)&pLRSpace ) &&
2659 ( 0 != (nSz = pLRSpace->GetTxtFirstLineOfst()) ||
2660 0 != pLRSpace->GetTxtLeft() ) )
2662 // dann setze doch eine unserer Vorlagen
2663 if( 0 < nSz ) // positiver 1. Zeileneinzug
2664 BuildIndent();
2665 else if( 0 > nSz ) // negativer 1. Zeileneinzug
2667 BuildNegIndent( aFInfo.GetLineStart() );
2669 else if( pLRSpace->GetTxtLeft() ) // ist ein Einzug
2670 BuildTextIndent();
2671 else
2672 BuildText();
2676 break;
2678 case IS_ENDE:
2679 bEnde = TRUE;
2680 break;
2684 if( aFlags.bWithRedlining )
2685 pDoc->SetAutoFmtRedline( FALSE );
2686 pDoc->SetRedlineMode( eOldMode );
2688 // restore undo (in case it has been changed)
2689 pDoc->DoUndo( bUndoState );
2691 // Prozent-Anzeige wieder abschalten
2692 if( !aFlags.bAFmtByInput )
2693 ::EndProgress( pDoc->GetDocShell() );
2696 void SwEditShell::AutoFormat( const SvxSwAutoFmtFlags* pAFlags )
2698 SwWait* pWait = 0;
2700 SET_CURR_SHELL( this );
2701 StartAllAction();
2702 StartUndo( UNDO_AUTOFORMAT );
2704 SvxSwAutoFmtFlags aAFFlags; // erst mal default - Werte
2705 if( pAFlags ) // oder doch angegeben ??
2707 aAFFlags = *pAFlags;
2708 if( !aAFFlags.bAFmtByInput )
2709 pWait = new SwWait( *GetDoc()->GetDocShell(), TRUE );
2712 SwPaM* pCrsr = GetCrsr();
2713 // es gibt mehr als einen oder ist eine Selektion offen
2714 if( pCrsr->GetNext() != pCrsr || pCrsr->HasMark() )
2716 FOREACHPAM_START(this)
2717 if( PCURCRSR->HasMark() )
2719 SwAutoFormat aFmt( this, aAFFlags, &PCURCRSR->Start()->nNode,
2720 &PCURCRSR->End()->nNode );
2722 FOREACHPAM_END()
2724 else
2726 SwAutoFormat aFmt( this, aAFFlags );
2729 EndUndo( UNDO_AUTOFORMAT );
2730 EndAllAction();
2732 delete pWait;
2736 void SwEditShell::AutoFmtBySplitNode()
2738 SET_CURR_SHELL( this );
2739 SwPaM* pCrsr = GetCrsr();
2740 if( pCrsr->GetNext() == pCrsr && pCrsr->Move( fnMoveBackward, fnGoNode ) )
2742 StartAllAction();
2743 StartUndo( UNDO_AUTOFORMAT );
2745 BOOL bRange = FALSE;
2746 pCrsr->SetMark();
2747 SwIndex* pCntnt = &pCrsr->GetMark()->nContent;
2748 if( pCntnt->GetIndex() )
2750 *pCntnt = 0;
2751 bRange = TRUE;
2753 else
2755 // dann einen Node zurueckspringen
2756 SwNodeIndex aNdIdx( pCrsr->GetMark()->nNode, -1 );
2757 SwTxtNode* pTxtNd = aNdIdx.GetNode().GetTxtNode();
2758 if( pTxtNd && pTxtNd->GetTxt().Len() )
2760 pCntnt->Assign( pTxtNd, 0 );
2761 pCrsr->GetMark()->nNode = aNdIdx;
2762 bRange = TRUE;
2766 if( bRange )
2768 Push(); // Cursor sichern
2770 SvxSwAutoFmtFlags aAFFlags = *GetAutoFmtFlags(); // erst mal default - Werte
2772 SwAutoFormat aFmt( this, aAFFlags, &pCrsr->GetMark()->nNode,
2773 &pCrsr->GetPoint()->nNode );
2775 //JP 30.09.96: das DoTable() verlaesst sich auf das PopCrsr
2776 // und MoveCrsr!
2777 Pop( FALSE );
2778 pCrsr = GetCrsr();
2780 pCrsr->DeleteMark();
2781 pCrsr->Move( fnMoveForward, fnGoNode );
2783 EndUndo( UNDO_AUTOFORMAT );
2784 EndAllAction();
2788 SvxSwAutoFmtFlags* SwEditShell::GetAutoFmtFlags()
2790 if (!pAutoFmtFlags)
2791 pAutoFmtFlags = new SvxSwAutoFmtFlags;
2793 return pAutoFmtFlags;
2796 void SwEditShell::SetAutoFmtFlags(SvxSwAutoFmtFlags * pFlags)
2798 SvxSwAutoFmtFlags* pEditFlags = GetAutoFmtFlags();
2800 pEditFlags->bSetNumRule = pFlags->bSetNumRule;
2801 pEditFlags->bChgEnumNum = pFlags->bChgEnumNum;
2802 pEditFlags->bSetBorder = pFlags->bSetBorder;
2803 pEditFlags->bCreateTable = pFlags->bCreateTable;
2804 pEditFlags->bReplaceStyles = pFlags->bReplaceStyles;
2805 pEditFlags->bAFmtByInpDelSpacesAtSttEnd =
2806 pFlags->bAFmtByInpDelSpacesAtSttEnd;
2807 pEditFlags->bAFmtByInpDelSpacesBetweenLines =
2808 pFlags->bAFmtByInpDelSpacesBetweenLines;
2810 //JP 15.12.98: BulletZeichen und Font in die "normalen" kopieren,
2811 // weil beim Autoformat nur mit diesen gearbeitet wird!
2812 pEditFlags->cBullet = pFlags->cByInputBullet;
2813 pEditFlags->aBulletFont = pFlags->aByInputBulletFont;
2814 pEditFlags->cByInputBullet = pFlags->cByInputBullet;
2815 pEditFlags->aByInputBulletFont = pFlags->aByInputBulletFont;