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