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