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 // start new list 1684 pDoc->SetNumRule( aDelPam, aRule, true ); 1685 // <-- 1686 aDelPam.DeleteMark(); 1687 1688 aDelPam.GetPoint()->nContent.Assign( pAktTxtNd, 0 ); 1689 } 1690 else 1691 { 1692 aDelPam.GetPoint()->nContent.Assign( pAktTxtNd, bChgEnum ? ( nTxtStt - nOrigTxtStt ) : 0 ); 1693 } 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 ); 1731 aTStops.Insert( SvxTabStop( 0 ) ); 1732 aSet.Put( aTStops ); 1733 pDoc->SetFmtItemByAutoFmt( aDelPam, aSet ); 1734 } 1735 } 1736 1737 if( bBreak ) 1738 { 1739 AutoCorrect( nAutoCorrPos ); /* Offset wegen Bullet + Tab */ 1740 return; 1741 } 1742 1743 const SwTxtNode* pNxtNd = GetNextNode(); 1744 while( CanJoin( pNxtNd ) && 1745 nLvl == CalcLevel( *pNxtNd ) ) 1746 { 1747 SetRedlineTxt( STR_AUTOFMTREDL_DEL_MORELINES ); 1748 bBreak = !IsFastFullLine( *pNxtNd ) || IsBlanksInString( *pNxtNd ) || 1749 IsSentenceAtEnd( *pNxtNd ); 1750 if( DeleteAktNxtPara( pNxtNd->GetTxt() ) ) 1751 { 1752 pDoc->InsertString( aDelPam, sal_Unicode(' ') ); 1753 } 1754 if( bBreak ) 1755 break; 1756 const SwTxtNode* pCurrNode = pNxtNd; 1757 pNxtNd = GetNextNode(); 1758 if(!pNxtNd || pCurrNode == pNxtNd) 1759 break; 1760 } 1761 DeleteAktPara( sal_False, sal_True ); 1762 AutoCorrect( nAutoCorrPos ); 1763 } 1764 1765 1766 void SwAutoFormat::BuildNegIndent( SwTwips nSpaces ) 1767 { 1768 SetRedlineTxt( STR_AUTOFMTREDL_SET_TMPL_NEG_INDENT ); 1769 // Test auf Gegenueberstellung: 1770 // (n Worte, durch Space/Tabs getrennt, mit gleicher 1771 // Einrueckung in der 2.Zeile) 1772 1773 // lese alle nachfolgenden Absaetze die zu dieser Aufzaehlung gehoeren 1774 sal_Bool bBreak = sal_True; 1775 xub_StrLen nSpacePos, nTxtPos = GetBigIndent( nSpacePos ); 1776 if( bMoreLines ) 1777 DelMoreLinesBlanks( sal_True ); 1778 else 1779 bBreak = !IsFastFullLine( *pAktTxtNd ) || 1780 ( !nTxtPos && IsBlanksInString( *pAktTxtNd )) || 1781 IsSentenceAtEnd( *pAktTxtNd ); 1782 1783 SetColl( static_cast<sal_uInt16>( nTxtPos 1784 ? RES_POOLCOLL_CONFRONTATION 1785 : RES_POOLCOLL_TEXT_NEGIDENT ) ); 1786 1787 if( nTxtPos ) 1788 { 1789 const String& rStr = pAktTxtNd->GetTxt(); 1790 sal_Bool bInsTab = sal_True; 1791 1792 if( '\t' == rStr.GetChar( nSpacePos+1 )) // ein Tab, das belassen wir 1793 { 1794 --nSpacePos; 1795 bInsTab = sal_False; 1796 } 1797 1798 xub_StrLen nSpaceStt = nSpacePos; 1799 while( nSpaceStt && IsSpace( rStr.GetChar( --nSpaceStt ) ) ) 1800 ; 1801 ++nSpaceStt; 1802 1803 if( bInsTab && '\t' == rStr.GetChar( nSpaceStt ) ) // ein Tab, das belassen wir 1804 { 1805 ++nSpaceStt; 1806 bInsTab = sal_False; 1807 } 1808 1809 1810 aDelPam.DeleteMark(); 1811 aDelPam.GetPoint()->nNode = aNdIdx; 1812 aDelPam.GetPoint()->nContent.Assign( pAktTxtNd, nSpacePos ); 1813 1814 // alten Spaces, usw. loeschen 1815 if( nSpaceStt < nSpacePos ) 1816 { 1817 aDelPam.SetMark(); 1818 aDelPam.GetMark()->nContent = nSpaceStt; 1819 DeleteSel( aDelPam ); 1820 if( bInsTab ) 1821 { 1822 pDoc->InsertString( aDelPam, sal_Unicode('\t') ); 1823 } 1824 } 1825 } 1826 1827 if( !bBreak ) 1828 { 1829 SetRedlineTxt( STR_AUTOFMTREDL_DEL_MORELINES ); 1830 SwTxtFrmInfo aFInfo( pAktTxtFrm ); 1831 const SwTxtNode* pNxtNd = GetNextNode(); 1832 while( CanJoin( pNxtNd ) && 1833 20 < Abs( (long)(nSpaces - aFInfo.SetFrm( 1834 GetFrm( *pNxtNd ) ).GetLineStart() )) 1835 ) 1836 { 1837 bBreak = !IsFastFullLine( *pNxtNd ) || 1838 IsBlanksInString( *pNxtNd ) || 1839 IsSentenceAtEnd( *pNxtNd ); 1840 if( DeleteAktNxtPara( pNxtNd->GetTxt() ) ) 1841 { 1842 pDoc->InsertString( aDelPam, sal_Unicode(' ') ); 1843 } 1844 if( bBreak ) 1845 break; 1846 pNxtNd = GetNextNode(); 1847 } 1848 } 1849 DeleteAktPara( sal_True, sal_True ); 1850 AutoCorrect(); 1851 } 1852 1853 1854 void SwAutoFormat::BuildHeadLine( sal_uInt16 nLvl ) 1855 { 1856 if( aFlags.bWithRedlining ) 1857 { 1858 String sTxt( *ViewShell::GetShellRes()->GetAutoFmtNameLst()[ 1859 STR_AUTOFMTREDL_SET_TMPL_HEADLINE ] ); 1860 sTxt.SearchAndReplace( String::CreateFromAscii( 1861 RTL_CONSTASCII_STRINGPARAM( "$(ARG1)" )), 1862 String::CreateFromInt32( nLvl + 1 ) ); 1863 pDoc->SetAutoFmtRedlineComment( &sTxt ); 1864 } 1865 1866 SetColl( static_cast<sal_uInt16>(RES_POOLCOLL_HEADLINE1 + nLvl ), sal_True ); 1867 if( aFlags.bAFmtByInput ) 1868 { 1869 SwTxtFmtColl& rNxtColl = pAktTxtNd->GetTxtColl()->GetNextTxtFmtColl(); 1870 1871 DelPrevPara(); 1872 1873 DeleteAktPara( sal_True, sal_False ); 1874 DeleteAktNxtPara( aEmptyStr ); 1875 1876 aDelPam.DeleteMark(); 1877 aDelPam.GetPoint()->nNode = aNdIdx.GetIndex() + 1; 1878 aDelPam.GetPoint()->nContent.Assign( aDelPam.GetCntntNode(), 0 ); 1879 pDoc->SetTxtFmtColl( aDelPam, &rNxtColl ); 1880 } 1881 else 1882 { 1883 DeleteAktPara( sal_True, sal_True ); 1884 AutoCorrect(); 1885 } 1886 } 1887 1888 1889 // dann lasse doch mal das AutoCorrect auf den akt. TextNode los 1890 void SwAutoFormat::AutoCorrect( xub_StrLen nPos ) 1891 { 1892 SvxAutoCorrect* pATst = SvxAutoCorrCfg::Get()->GetAutoCorrect(); 1893 long aSvxFlags = pATst->GetFlags( ); 1894 bool bReplaceQuote = ( aSvxFlags & ChgQuotes ) > 0; 1895 bool bReplaceSglQuote = ( aSvxFlags & ChgSglQuotes ) > 0; 1896 1897 if( aFlags.bAFmtByInput || 1898 (!aFlags.bAutoCorrect && !bReplaceQuote && !bReplaceSglQuote && 1899 !aFlags.bCptlSttSntnc && !aFlags.bCptlSttWrd && 1900 !aFlags.bChgOrdinalNumber && 1901 !aFlags.bChgToEnEmDash && !aFlags.bSetINetAttr && 1902 !aFlags.bChgWeightUnderl && !aFlags.bAddNonBrkSpace) ) 1903 return; 1904 1905 const String* pTxt = &pAktTxtNd->GetTxt(); 1906 if( nPos >= pTxt->Len() ) 1907 return; 1908 1909 sal_Bool bGetLanguage = aFlags.bChgOrdinalNumber || 1910 aFlags.bChgToEnEmDash || aFlags.bSetINetAttr || 1911 aFlags.bCptlSttWrd || aFlags.bCptlSttSntnc || 1912 aFlags.bAddNonBrkSpace; 1913 1914 1915 aDelPam.DeleteMark(); 1916 aDelPam.GetPoint()->nNode = aNdIdx; 1917 aDelPam.GetPoint()->nContent.Assign( pAktTxtNd, 0 ); 1918 1919 SwAutoCorrDoc aACorrDoc( *pEditShell, aDelPam ); 1920 1921 SwTxtFrmInfo aFInfo( 0 ); 1922 1923 xub_StrLen nSttPos, nLastBlank = nPos; 1924 sal_Bool bFirst = aFlags.bCptlSttSntnc, bFirstSent = bFirst; 1925 sal_Unicode cChar = 0; 1926 1927 CharClass& rAppCC = GetAppCharClass(); 1928 1929 do { 1930 while( nPos < pTxt->Len() && IsSpace( cChar = pTxt->GetChar( nPos ) )) 1931 ++nPos; 1932 if( nPos == pTxt->Len() ) 1933 break; // das wars 1934 1935 if( ( ( bReplaceQuote && '\"' == cChar ) || 1936 ( bReplaceSglQuote && '\'' == cChar ) ) && 1937 ( !nPos || ' ' == pTxt->GetChar( nPos-1 ) ) ) 1938 { 1939 // -------------------------------------- 1940 // beachte: Sonderfall Symbolfonts !!! 1941 if( !aFInfo.GetFrm() ) 1942 aFInfo.SetFrm( GetFrm( *pAktTxtNd ) ); 1943 if( !aFInfo.IsBullet( nPos )) 1944 { 1945 SetRedlineTxt( STR_AUTOFMTREDL_TYPO ); 1946 aDelPam.GetPoint()->nContent = nPos; 1947 sal_Bool bSetHardBlank = sal_False; 1948 1949 String sReplace( pATst->GetQuote( aACorrDoc, 1950 nPos, cChar, sal_True )); 1951 1952 aDelPam.SetMark(); 1953 aDelPam.GetPoint()->nContent = nPos+1; 1954 if( 2 == sReplace.Len() && ' ' == sReplace.GetChar( 1 )) 1955 { 1956 sReplace.Erase( 1 ); 1957 bSetHardBlank = sal_True; 1958 } 1959 pDoc->ReplaceRange( aDelPam, sReplace, false ); 1960 1961 if( aFlags.bWithRedlining ) 1962 { 1963 aNdIdx = aDelPam.GetPoint()->nNode; 1964 pAktTxtNd = aNdIdx.GetNode().GetTxtNode(); 1965 pTxt = &pAktTxtNd->GetTxt(); 1966 aDelPam.SetMark(); 1967 aFInfo.SetFrm( 0 ); 1968 } 1969 1970 nPos += sReplace.Len() - 1; 1971 aDelPam.DeleteMark(); 1972 if( bSetHardBlank ) 1973 { 1974 pDoc->InsertString( aDelPam, CHAR_HARDBLANK ); 1975 ++nPos; 1976 } 1977 } 1978 } 1979 1980 int bCallACorr = sal_False; 1981 int bBreak = 0; 1982 if( nPos && IsSpace( pTxt->GetChar( nPos-1 ))) 1983 nLastBlank = nPos; 1984 for( nSttPos = nPos; !bBreak && nPos < pTxt->Len(); ++nPos ) 1985 switch( cChar = pTxt->GetChar( nPos ) ) 1986 { 1987 case '\"': 1988 case '\'': 1989 if( ( cChar == '\"' && bReplaceQuote ) || ( cChar == '\'' && bReplaceSglQuote ) ) 1990 { 1991 // -------------------------------------- 1992 // beachte: Sonderfall Symbolfonts !!! 1993 if( !aFInfo.GetFrm() ) 1994 aFInfo.SetFrm( GetFrm( *pAktTxtNd ) ); 1995 if( !aFInfo.IsBullet( nPos )) 1996 { 1997 SetRedlineTxt( STR_AUTOFMTREDL_TYPO ); 1998 sal_Bool bSetHardBlank = sal_False; 1999 aDelPam.GetPoint()->nContent = nPos; 2000 String sReplace( pATst->GetQuote( aACorrDoc, 2001 nPos, cChar, sal_False )); 2002 2003 if( 2 == sReplace.Len() && ' ' == sReplace.GetChar( 0 )) 2004 { 2005 sReplace.Erase( 0, 1 ); 2006 bSetHardBlank = sal_True; 2007 } 2008 2009 aDelPam.SetMark(); 2010 aDelPam.GetPoint()->nContent = nPos+1; 2011 pDoc->ReplaceRange( aDelPam, sReplace, false ); 2012 2013 if( aFlags.bWithRedlining ) 2014 { 2015 aNdIdx = aDelPam.GetPoint()->nNode; 2016 pAktTxtNd = aNdIdx.GetNode().GetTxtNode(); 2017 pTxt = &pAktTxtNd->GetTxt(); 2018 aDelPam.SetMark(); 2019 aDelPam.DeleteMark(); 2020 aFInfo.SetFrm( 0 ); 2021 } 2022 2023 nPos += sReplace.Len() - 1; 2024 aDelPam.DeleteMark(); 2025 2026 if( bSetHardBlank ) 2027 { 2028 aDelPam.GetPoint()->nContent = nPos; 2029 pDoc->InsertString( aDelPam, CHAR_HARDBLANK ); 2030 aDelPam.GetPoint()->nContent = ++nPos; 2031 } 2032 } 2033 } 2034 break; 2035 case '*': 2036 case '_': 2037 if( aFlags.bChgWeightUnderl ) 2038 { 2039 // -------------------------------------- 2040 // beachte: Sonderfall Symbolfonts !!! 2041 if( !aFInfo.GetFrm() ) 2042 aFInfo.SetFrm( GetFrm( *pAktTxtNd ) ); 2043 if( !aFInfo.IsBullet( nPos )) 2044 { 2045 SetRedlineTxt( '*' == cChar 2046 ? STR_AUTOFMTREDL_BOLD 2047 : STR_AUTOFMTREDL_UNDER ); 2048 2049 sal_Unicode cBlank = nSttPos ? pTxt->GetChar(nSttPos - 1) : 0; 2050 aDelPam.GetPoint()->nContent = nPos; 2051 2052 if( pATst->FnChgWeightUnderl( aACorrDoc, *pTxt, 2053 nSttPos, nPos )) 2054 { 2055 if( aFlags.bWithRedlining ) 2056 { 2057 aNdIdx = aDelPam.GetPoint()->nNode; 2058 pAktTxtNd = aNdIdx.GetNode().GetTxtNode(); 2059 pTxt = &pAktTxtNd->GetTxt(); 2060 aDelPam.SetMark(); 2061 aDelPam.DeleteMark(); 2062 aFInfo.SetFrm( 0 ); 2063 } 2064 //#125102# in case of the mode REDLINE_SHOW_DELETE the ** are still contained in pTxt 2065 if(0 == (pDoc->GetRedlineMode() & nsRedlineMode_t::REDLINE_SHOW_DELETE)) 2066 nPos = aDelPam.GetPoint()->nContent.GetIndex() - 1; 2067 // wurde vorm Start ein Zeichen entfernt? 2068 if( cBlank && cBlank != pTxt->GetChar(nSttPos - 1) ) 2069 --nSttPos; 2070 } 2071 } 2072 } 2073 break; 2074 case '/': 2075 if ( aFlags.bAddNonBrkSpace ) 2076 { 2077 LanguageType eLang = (bGetLanguage && pAktTxtNd) 2078 ? pAktTxtNd->GetLang( nSttPos ) 2079 : LANGUAGE_SYSTEM; 2080 2081 SetRedlineTxt( STR_AUTOFMTREDL_NON_BREAK_SPACE ); 2082 if ( pATst->FnAddNonBrkSpace( aACorrDoc, *pTxt, nSttPos, nPos, eLang ) ) 2083 --nPos; 2084 } 2085 break; 2086 2087 case '.': 2088 case '!': 2089 case '?': 2090 if( aFlags.bCptlSttSntnc ) 2091 bFirstSent = sal_True; 2092 //alle Wortrenner loesen die Autokorrektur aus! 2093 // break; 2094 default: 2095 //alle Wortrenner loesen die Autokorrektur aus! 2096 // case ' ': 2097 // case '\t': 2098 if( !( rAppCC.isLetterNumeric( *pTxt, nPos ) 2099 || '/' == cChar )) // '/' should not be a word seperator (e.g. '1/2' needs to be handled as one word for replacement) 2100 { 2101 --nPos; // ++nPos von dem for ungueltig machen ! 2102 ++bBreak; 2103 } 2104 break; 2105 } 2106 2107 if( nPos == nSttPos ) 2108 { 2109 if( ++nPos == pTxt->Len() ) 2110 bCallACorr = sal_True; 2111 } 2112 else 2113 bCallACorr = sal_True; 2114 2115 2116 if( bCallACorr ) 2117 { 2118 bCallACorr = sal_False; 2119 aDelPam.GetPoint()->nContent = nPos; 2120 SetRedlineTxt( STR_AUTOFMTREDL_USE_REPLACE ); 2121 if( aFlags.bAutoCorrect && 2122 aACorrDoc.ChgAutoCorrWord( nSttPos, nPos, *pATst, 0 ) ) 2123 { 2124 nPos = aDelPam.GetPoint()->nContent.GetIndex(); 2125 2126 if( aFlags.bWithRedlining ) 2127 { 2128 aNdIdx = aDelPam.GetPoint()->nNode; 2129 pAktTxtNd = aNdIdx.GetNode().GetTxtNode(); 2130 pTxt = &pAktTxtNd->GetTxt(); 2131 aDelPam.SetMark(); 2132 aDelPam.DeleteMark(); 2133 } 2134 2135 continue; // nichts weiter mehr abpruefen 2136 } 2137 2138 LanguageType eLang = (bGetLanguage && pAktTxtNd) 2139 ? pAktTxtNd->GetLang( nSttPos ) 2140 : LANGUAGE_SYSTEM; 2141 2142 if ( aFlags.bAddNonBrkSpace ) 2143 { 2144 SetRedlineTxt( STR_AUTOFMTREDL_NON_BREAK_SPACE ); 2145 pATst->FnAddNonBrkSpace( aACorrDoc, *pTxt, nSttPos, nPos, eLang ); 2146 } 2147 2148 if( ( aFlags.bChgOrdinalNumber && 2149 SetRedlineTxt( STR_AUTOFMTREDL_ORDINAL ) && 2150 pATst->FnChgOrdinalNumber( aACorrDoc, *pTxt, nSttPos, nPos, eLang ) ) || 2151 ( aFlags.bChgToEnEmDash && 2152 SetRedlineTxt( STR_AUTOFMTREDL_DASH ) && 2153 pATst->FnChgToEnEmDash( aACorrDoc, *pTxt, nSttPos, nPos, eLang ) ) || 2154 ( aFlags.bSetINetAttr && 2155 ( nPos == pTxt->Len() || IsSpace( pTxt->GetChar( nPos )) ) && 2156 SetRedlineTxt( STR_AUTOFMTREDL_DETECT_URL ) && 2157 pATst->FnSetINetAttr( aACorrDoc, *pTxt, nLastBlank, nPos, eLang ) ) ) 2158 nPos = aDelPam.GetPoint()->nContent.GetIndex(); 2159 else 2160 { 2161 // Zwei Grossbuchstaben am Wort-Anfang ?? 2162 if( aFlags.bCptlSttWrd ) 2163 { 2164 SetRedlineTxt( STR_AUTOFMTREDL_CPTL_STT_WORD ); 2165 pATst->FnCptlSttWrd( aACorrDoc, *pTxt, nSttPos, nPos, eLang ); 2166 } 2167 // Grossbuchstabe am Satz-Anfang ?? 2168 if( aFlags.bCptlSttSntnc && bFirst ) 2169 { 2170 SetRedlineTxt( STR_AUTOFMTREDL_CPTL_STT_SENT ); 2171 pATst->FnCptlSttSntnc( aACorrDoc, *pTxt, sal_True, nSttPos, nPos, eLang); 2172 bFirst = sal_False; 2173 } 2174 2175 bFirst = bFirstSent; 2176 bFirstSent = sal_False; 2177 2178 if( aFlags.bWithRedlining ) 2179 { 2180 aNdIdx = aDelPam.GetPoint()->nNode; 2181 pAktTxtNd = aNdIdx.GetNode().GetTxtNode(); 2182 pTxt = &pAktTxtNd->GetTxt(); 2183 aDelPam.SetMark(); 2184 aDelPam.DeleteMark(); 2185 } 2186 } 2187 } 2188 } while( nPos < pTxt->Len() ); 2189 ClearRedlineTxt(); 2190 } 2191 2192 2193 SwAutoFormat::SwAutoFormat( SwEditShell* pEdShell, SvxSwAutoFmtFlags& rFlags, 2194 SwNodeIndex* pSttNd, SwNodeIndex* pEndNd ) 2195 : aFlags( rFlags ), 2196 aDelPam( pEdShell->GetDoc()->GetNodes().GetEndOfExtras() ), 2197 aNdIdx( pEdShell->GetDoc()->GetNodes().GetEndOfExtras(), +1 ), 2198 aEndNdIdx( pEdShell->GetDoc()->GetNodes().GetEndOfContent() ), 2199 pEditShell( pEdShell ), 2200 pDoc( pEdShell->GetDoc() ), 2201 pAktTxtNd( 0 ), pAktTxtFrm( 0 ), 2202 pCharClass( 0 ), 2203 nRedlAutoFmtSeqId( 0 ) 2204 { 2205 ASSERT( (pSttNd && pEndNd) || (!pSttNd && !pEndNd), 2206 "Kein Bereich angegeben" ); 2207 2208 if( aFlags.bSetNumRule && !aFlags.bAFmtByInput ) 2209 aFlags.bSetNumRule = sal_False; 2210 2211 sal_Bool bReplaceStyles = !aFlags.bAFmtByInput || aFlags.bReplaceStyles; 2212 2213 const SwTxtNode* pNxtNd = 0; 2214 sal_Bool bNxtEmpty = sal_False; 2215 sal_Bool bNxtAlpha = sal_False; 2216 sal_uInt16 nNxtLevel = 0; 2217 2218 // setze den Bereich zum Autoformatieren 2219 if( pSttNd ) 2220 { 2221 aNdIdx = *pSttNd; 2222 aNdIdx--; // fuer GoNextPara, ein Absatz davor 2223 aEndNdIdx = *pEndNd; 2224 aEndNdIdx++; 2225 2226 // teste den vorhergehenden TextNode 2227 pNxtNd = aNdIdx.GetNode().GetTxtNode(); 2228 bEmptyLine = !pNxtNd || 2229 IsEmptyLine( *pNxtNd ) || 2230 IsNoAlphaLine( *pNxtNd ); 2231 } 2232 else 2233 bEmptyLine = sal_True; // am Dokument Anfang 2234 2235 bEnde = sal_False; 2236 2237 // setze die Werte fuer die Prozent-Anzeige 2238 nEndNdIdx = aEndNdIdx.GetIndex(); 2239 2240 if( !aFlags.bAFmtByInput ) 2241 ::StartProgress( STR_STATSTR_AUTOFORMAT, aNdIdx.GetIndex(), 2242 nEndNdIdx = aEndNdIdx.GetIndex(), 2243 pDoc->GetDocShell() ); 2244 2245 RedlineMode_t eRedlMode = pDoc->GetRedlineMode(), eOldMode = eRedlMode; 2246 if( aFlags.bWithRedlining ) 2247 { 2248 pDoc->SetAutoFmtRedline( sal_True ); 2249 eRedlMode = (RedlineMode_t)(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_SHOW_INSERT); 2250 } 2251 else 2252 eRedlMode = (RedlineMode_t)(nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_IGNORE); 2253 pDoc->SetRedlineMode( eRedlMode ); 2254 2255 // save undo state (might be turned off) 2256 bool const bUndoState = pDoc->GetIDocumentUndoRedo().DoesUndo(); 2257 2258 // wenn mehrere Zeilen, dann erstmal nicht mit 2259 // dem nachfolgenden Absatz zusammenfassen. 2260 bMoreLines = sal_False; 2261 2262 nLastCalcHeadLvl = nLastCalcEnumLvl = 0; 2263 nLastHeadLvl = nLastEnumLvl = USHRT_MAX; 2264 sal_uInt16 nLevel = 0; 2265 sal_uInt16 nDigitLvl = 0; 2266 2267 // defaulten 2268 SwTxtFrmInfo aFInfo( 0 ); 2269 2270 // das ist unser Automat fuer die Auto-Formatierung 2271 eStat = READ_NEXT_PARA; 2272 while( !bEnde ) 2273 { 2274 switch( eStat ) 2275 { 2276 case READ_NEXT_PARA: 2277 { 2278 GoNextPara(); 2279 eStat = bEnde ? IS_ENDE : TST_EMPTY_LINE; 2280 } 2281 break; 2282 2283 case TST_EMPTY_LINE: 2284 if( IsEmptyLine( *pAktTxtNd ) ) 2285 { 2286 if( aFlags.bDelEmptyNode && !HasObjects( *pAktTxtNd ) ) 2287 { 2288 bEmptyLine = sal_True; 2289 sal_uLong nOldCnt = pDoc->GetNodes().Count(); 2290 DelEmptyLine(); 2291 // wurde wiklich ein Node geloescht ? 2292 if( nOldCnt != pDoc->GetNodes().Count() ) 2293 aNdIdx--; // nicht den naechsten Absatz ueberspringen 2294 } 2295 eStat = READ_NEXT_PARA; 2296 } 2297 else 2298 eStat = TST_ALPHA_LINE; 2299 break; 2300 2301 case TST_ALPHA_LINE: 2302 if( IsNoAlphaLine( *pAktTxtNd )) 2303 { 2304 // erkenne eine Tabellendefinition +---+---+ 2305 if( aFlags.bAFmtByInput && aFlags.bCreateTable && DoTable() ) 2306 { 2307 //JP 30.09.96: das DoTable() verlaesst sich auf das 2308 // Pop und Move - Crsr nach dem AutoFormat! 2309 pEdShell->Pop( sal_False ); 2310 *pEdShell->GetCrsr() = aDelPam; 2311 pEdShell->Push(); 2312 2313 eStat = IS_ENDE; 2314 break; 2315 } 2316 2317 // dann teste mal auf 3 "---" oder "===". In dem Fall 2318 // soll der vorherige Absatz unterstrichen und dieser 2319 // geloescht werden! 2320 if( !DoUnderline() && bReplaceStyles ) 2321 { 2322 SetColl( RES_POOLCOLL_STANDARD, sal_True ); 2323 bEmptyLine = sal_True; 2324 } 2325 eStat = READ_NEXT_PARA; 2326 } 2327 else 2328 eStat = GET_ALL_INFO; 2329 break; 2330 2331 case GET_ALL_INFO: 2332 { 2333 if( pAktTxtNd->GetNumRule() ) 2334 { 2335 // in Numerierung nichts machen, zum naechsten 2336 bEmptyLine = sal_False; 2337 eStat = READ_NEXT_PARA; 2338 // loesche alle Blanks am Anfang/Ende 2339 // und alle mitten drin 2340 //JP 29.04.98: erstmal nur alle "mitten drin". 2341 DelMoreLinesBlanks( sal_False ); 2342 break; 2343 } 2344 2345 aFInfo.SetFrm( pAktTxtFrm ); 2346 2347 // erstmal: wurden schon mal entsprechende Vorlagen 2348 // vergeben, so behalte die bei, gehe zum 2349 // naechsten Node. 2350 sal_uInt16 nPoolId = pAktTxtNd->GetTxtColl()->GetPoolFmtId(); 2351 if( IsPoolUserFmt( nPoolId ) 2352 ? !aFlags.bChgUserColl 2353 : ( RES_POOLCOLL_STANDARD != nPoolId && 2354 ( !aFlags.bAFmtByInput || 2355 (RES_POOLCOLL_TEXT_MOVE != nPoolId && 2356 RES_POOLCOLL_TEXT != nPoolId )) )) 2357 { 2358 eStat = HAS_FMTCOLL; 2359 break; 2360 } 2361 2362 // teste auf Harte oder aus Vorlagen gesetzte LRSpaces 2363 if( IsPoolUserFmt( nPoolId ) || 2364 RES_POOLCOLL_STANDARD == nPoolId ) 2365 { 2366 short nSz; 2367 SvxLRSpaceItem* pLRSpace; 2368 if( SFX_ITEM_SET == pAktTxtNd->GetSwAttrSet(). 2369 GetItemState( RES_LR_SPACE, sal_True, 2370 (const SfxPoolItem**)&pLRSpace ) && 2371 ( 0 != (nSz = pLRSpace->GetTxtFirstLineOfst()) || 2372 0 != pLRSpace->GetTxtLeft() ) ) 2373 { 2374 // Ausnahme: Numerierun/Aufzaehlung kann mit Einzug 2375 // existieren!! 2376 if( IsEnumericChar( *pAktTxtNd )) 2377 { 2378 nLevel = CalcLevel( *pAktTxtNd, &nDigitLvl ); 2379 if( nLevel >= MAXLEVEL ) 2380 nLevel = MAXLEVEL-1; 2381 BuildEnum( nLevel, nDigitLvl ); 2382 eStat = READ_NEXT_PARA; 2383 break; 2384 } 2385 2386 2387 // nie zusammenfassen, so belassen 2388 // (Opt. vielleicht als Ausnahmen nur Einzug) 2389 bMoreLines = sal_True; 2390 2391 if( bReplaceStyles ) 2392 { 2393 // dann setze doch eine unserer Vorlagen 2394 if( 0 < nSz ) // positiver 1. Zeileneinzug 2395 BuildIndent(); 2396 else if( 0 > nSz ) // negativer 1. Zeileneinzug 2397 BuildNegIndent( aFInfo.GetLineStart() ); 2398 else if( pLRSpace->GetTxtLeft() ) // ist ein Einzug 2399 BuildTextIndent(); 2400 } 2401 eStat = READ_NEXT_PARA; 2402 break; 2403 } 2404 } 2405 2406 nLevel = CalcLevel( *pAktTxtNd, &nDigitLvl ); 2407 bMoreLines = !IsOneLine( *pAktTxtNd ); 2408 pNxtNd = GetNextNode(); 2409 if( pNxtNd ) 2410 { 2411 bNxtEmpty = IsEmptyLine( *pNxtNd ); 2412 bNxtAlpha = IsNoAlphaLine( *pNxtNd ); 2413 nNxtLevel = CalcLevel( *pNxtNd ); 2414 2415 if( !bEmptyLine && HasBreakAttr( *pAktTxtNd ) ) 2416 bEmptyLine = sal_True; 2417 if( !bNxtEmpty && HasBreakAttr( *pNxtNd ) ) 2418 bNxtEmpty = sal_True; 2419 2420 // fuer z.B. selbst definierte Einzuege oder 2421 // rechts/zentierte Ausrichtung 2422 // if( !nLevel && 0 != aFInfo.GetLineStart() ) 2423 // nLevel = 1; 2424 } 2425 else 2426 { 2427 bNxtEmpty = sal_False; // sal_True; 2428 bNxtAlpha = sal_False; 2429 nNxtLevel = 0; 2430 } 2431 eStat = !bMoreLines ? IS_ONE_LINE : TST_ENUMERIC; 2432 } 2433 break; 2434 2435 case IS_ONE_LINE: 2436 { 2437 eStat = TST_ENUMERIC; 2438 if( !bReplaceStyles ) 2439 break; 2440 2441 String sClrStr( pAktTxtNd->GetTxt() ); 2442 2443 if( !DelLeadingBlanks( sClrStr ).Len() ) 2444 { 2445 bEmptyLine = sal_True; 2446 eStat = READ_NEXT_PARA; 2447 break; // naechsten Absatz lesen 2448 } 2449 2450 // Teste auf Ueberschrift 2451 if( !bEmptyLine || !IsFirstCharCapital( *pAktTxtNd ) || 2452 IsBlanksInString( *pAktTxtNd ) ) 2453 break; 2454 2455 bEmptyLine = sal_False; 2456 String sEndClrStr( sClrStr ); 2457 xub_StrLen nLen = DelTrailingBlanks( sEndClrStr ).Len(); 2458 2459 // nicht, dann teste auf Ueberschrift 2460 if( ':' == sEndClrStr.GetChar( nLen - 1 ) ) 2461 { 2462 //--------------------------------------------------------------------------- 2463 // Wie ist denn nun die Bedingung fuer die Ueberschrift auf Ebene 3 ?? 2464 // Zur Zeit: generell wenn am Ende ein ':' ist. 2465 // 2466 // if( bNxtEmpty || bNxtAlpha ) 2467 // !IsEnumericChar( *pNxtNd ) ) 2468 //--------------------------------------------------------------------------- 2469 { 2470 BuildHeadLine( 2 ); 2471 eStat = READ_NEXT_PARA; 2472 break; 2473 } 2474 } 2475 else if( 256 <= sEndClrStr.GetChar( nLen-1 ) || 2476 !strchr( ",.;", sEndClrStr.GetChar( nLen-1 )) ) 2477 { 2478 if( bNxtEmpty || bNxtAlpha 2479 || ( pNxtNd && IsEnumericChar( *pNxtNd )) 2480 2481 //--------------------------------------------------------------------------- 2482 // ist zum Verwechseln mit neg. Einzug !! 2483 /*|| nLevel < nNxtLevel*/ 2484 //--------------------------------------------------------------------------- 2485 2486 ) 2487 { 2488 // wurde Level vom Text vorgegeben ? 2489 // if( USHRT_MAX != nDigitLvl ) 2490 // nLevel = nDigitLvl; 2491 2492 // eine Ebene runter ? 2493 if( nLevel >= MAXLEVEL ) 2494 nLevel = MAXLEVEL-1; 2495 2496 if( USHRT_MAX == nLastHeadLvl ) 2497 nLastHeadLvl = 0; 2498 else if( nLastCalcHeadLvl < nLevel ) 2499 { 2500 if( nLastHeadLvl+1 < MAXLEVEL ) 2501 ++nLastHeadLvl; 2502 } 2503 // eine Ebene hoch ? 2504 else if( nLastCalcHeadLvl > nLevel ) 2505 { 2506 if( nLastHeadLvl ) 2507 --nLastHeadLvl; 2508 } 2509 nLastCalcHeadLvl = nLevel; 2510 2511 if( aFlags.bAFmtByInput ) 2512 BuildHeadLine( nLevel ); 2513 else 2514 BuildHeadLine( nLastHeadLvl ); 2515 eStat = READ_NEXT_PARA; 2516 break; 2517 } 2518 } 2519 } 2520 break; 2521 2522 case TST_ENUMERIC: 2523 { 2524 bEmptyLine = sal_False; 2525 if( IsEnumericChar( *pAktTxtNd )) 2526 { 2527 if( nLevel >= MAXLEVEL ) 2528 nLevel = MAXLEVEL-1; 2529 BuildEnum( nLevel, nDigitLvl ); 2530 eStat = READ_NEXT_PARA; 2531 } 2532 //JP 25.03.96: Vorlagen fuer Einzug zulassen 2533 // else if( aFlags.bAFmtByInput ) 2534 // eStat = READ_NEXT_PARA; 2535 else if( bReplaceStyles ) 2536 eStat = nLevel ? TST_IDENT : TST_NEG_IDENT; 2537 else 2538 eStat = READ_NEXT_PARA; 2539 } 2540 break; 2541 2542 case TST_IDENT: 2543 // Spaces am Anfang, dann teste doch mal auf Einzuege 2544 if( bMoreLines && nLevel ) 2545 { 2546 SwTwips nSz = aFInfo.GetFirstIndent(); 2547 if( 0 < nSz ) // positiver 1. Zeileneinzug 2548 BuildIndent(); 2549 else if( 0 > nSz ) // negativer 1. Zeileneinzug 2550 BuildNegIndent( aFInfo.GetLineStart() ); 2551 else // ist ein Einzug 2552 BuildTextIndent(); 2553 eStat = READ_NEXT_PARA; 2554 } 2555 else if( nLevel && pNxtNd && !bEnde && 2556 !bNxtEmpty && !bNxtAlpha && !nNxtLevel && 2557 !IsEnumericChar( *pNxtNd ) ) 2558 { 2559 // ist ein Einzug 2560 BuildIndent(); 2561 eStat = READ_NEXT_PARA; 2562 } 2563 else 2564 eStat = TST_TXT_BODY; 2565 break; 2566 2567 case TST_NEG_IDENT: 2568 // keine Spaces am Anfang, dann teste doch mal auf neg. Einzuege 2569 { 2570 if( bMoreLines && !nLevel ) 2571 { 2572 SwTwips nSz = aFInfo.GetFirstIndent(); 2573 if( 0 < nSz ) // positiver 1. Zeileneinzug 2574 BuildIndent(); 2575 else if( 0 > nSz ) // negativer 1. Zeileneinzug 2576 BuildNegIndent( aFInfo.GetLineStart() ); 2577 else // ist ein kein Einzug 2578 BuildText(); 2579 eStat = READ_NEXT_PARA; 2580 } 2581 else if( !nLevel && pNxtNd && !bEnde && 2582 !bNxtEmpty && !bNxtAlpha && nNxtLevel && 2583 !IsEnumericChar( *pNxtNd ) ) 2584 { 2585 // ist ein neg. Einzug 2586 BuildNegIndent( aFInfo.GetLineStart() ); 2587 eStat = READ_NEXT_PARA; 2588 } 2589 else 2590 eStat = TST_TXT_BODY; 2591 } 2592 break; 2593 2594 case TST_TXT_BODY: 2595 { 2596 if( bMoreLines ) 2597 { 2598 SwTwips nSz = aFInfo.GetFirstIndent(); 2599 if( 0 < nSz ) // positiver 1. Zeileneinzug 2600 BuildIndent(); 2601 else if( 0 > nSz ) // negativer 1. Zeileneinzug 2602 BuildNegIndent( aFInfo.GetLineStart() ); 2603 else if( nLevel ) // ist ein Einzug 2604 BuildTextIndent(); 2605 else 2606 BuildText(); 2607 } 2608 else if( nLevel ) 2609 BuildTextIndent(); 2610 else 2611 BuildText(); 2612 eStat = READ_NEXT_PARA; 2613 } 2614 break; 2615 2616 case HAS_FMTCOLL: 2617 { 2618 // erstmal: wurden schon mal entsprechende Vorlagen 2619 // vergeben, so behalte die bei, gehe zum 2620 // naechsten Node. 2621 bEmptyLine = sal_False; 2622 eStat = READ_NEXT_PARA; 2623 // loesche alle Blanks am Anfang/Ende 2624 // und alle mitten drin 2625 //JP 29.04.98: erstmal nur alle "mitten drin". 2626 DelMoreLinesBlanks( sal_False ); 2627 2628 // behandel die harte Attributierung 2629 if( pAktTxtNd->HasSwAttrSet() ) 2630 { 2631 short nSz; 2632 SvxLRSpaceItem* pLRSpace; 2633 if( bReplaceStyles && 2634 SFX_ITEM_SET == pAktTxtNd->GetSwAttrSet(). 2635 GetItemState( RES_LR_SPACE, sal_False, 2636 (const SfxPoolItem**)&pLRSpace ) && 2637 ( 0 != (nSz = pLRSpace->GetTxtFirstLineOfst()) || 2638 0 != pLRSpace->GetTxtLeft() ) ) 2639 { 2640 // dann setze doch eine unserer Vorlagen 2641 if( 0 < nSz ) // positiver 1. Zeileneinzug 2642 BuildIndent(); 2643 else if( 0 > nSz ) // negativer 1. Zeileneinzug 2644 { 2645 BuildNegIndent( aFInfo.GetLineStart() ); 2646 } 2647 else if( pLRSpace->GetTxtLeft() ) // ist ein Einzug 2648 BuildTextIndent(); 2649 else 2650 BuildText(); 2651 } 2652 } 2653 } 2654 break; 2655 2656 case IS_ENDE: 2657 bEnde = sal_True; 2658 break; 2659 } 2660 } 2661 2662 if( aFlags.bWithRedlining ) 2663 pDoc->SetAutoFmtRedline( sal_False ); 2664 pDoc->SetRedlineMode( eOldMode ); 2665 2666 // restore undo (in case it has been changed) 2667 pDoc->GetIDocumentUndoRedo().DoUndo(bUndoState); 2668 2669 // Prozent-Anzeige wieder abschalten 2670 if( !aFlags.bAFmtByInput ) 2671 ::EndProgress( pDoc->GetDocShell() ); 2672 } 2673 2674 void SwEditShell::AutoFormat( const SvxSwAutoFmtFlags* pAFlags ) 2675 { 2676 SwWait* pWait = 0; 2677 2678 SET_CURR_SHELL( this ); 2679 StartAllAction(); 2680 StartUndo( UNDO_AUTOFORMAT ); 2681 2682 SvxSwAutoFmtFlags aAFFlags; // erst mal default - Werte 2683 if( pAFlags ) // oder doch angegeben ?? 2684 { 2685 aAFFlags = *pAFlags; 2686 if( !aAFFlags.bAFmtByInput ) 2687 pWait = new SwWait( *GetDoc()->GetDocShell(), true ); 2688 } 2689 2690 SwPaM* pCrsr = GetCrsr(); 2691 // es gibt mehr als einen oder ist eine Selektion offen 2692 if( pCrsr->GetNext() != pCrsr || pCrsr->HasMark() ) 2693 { 2694 FOREACHPAM_START(this) 2695 if( PCURCRSR->HasMark() ) 2696 { 2697 SwAutoFormat aFmt( this, aAFFlags, &PCURCRSR->Start()->nNode, 2698 &PCURCRSR->End()->nNode ); 2699 } 2700 FOREACHPAM_END() 2701 } 2702 else 2703 { 2704 SwAutoFormat aFmt( this, aAFFlags ); 2705 } 2706 2707 EndUndo( UNDO_AUTOFORMAT ); 2708 EndAllAction(); 2709 2710 delete pWait; 2711 } 2712 2713 2714 void SwEditShell::AutoFmtBySplitNode() 2715 { 2716 SET_CURR_SHELL( this ); 2717 SwPaM* pCrsr = GetCrsr(); 2718 if( pCrsr->GetNext() == pCrsr && pCrsr->Move( fnMoveBackward, fnGoNode ) ) 2719 { 2720 StartAllAction(); 2721 StartUndo( UNDO_AUTOFORMAT ); 2722 2723 sal_Bool bRange = sal_False; 2724 pCrsr->SetMark(); 2725 SwIndex* pCntnt = &pCrsr->GetMark()->nContent; 2726 if( pCntnt->GetIndex() ) 2727 { 2728 *pCntnt = 0; 2729 bRange = sal_True; 2730 } 2731 else 2732 { 2733 // dann einen Node zurueckspringen 2734 SwNodeIndex aNdIdx( pCrsr->GetMark()->nNode, -1 ); 2735 SwTxtNode* pTxtNd = aNdIdx.GetNode().GetTxtNode(); 2736 if( pTxtNd && pTxtNd->GetTxt().Len() ) 2737 { 2738 pCntnt->Assign( pTxtNd, 0 ); 2739 pCrsr->GetMark()->nNode = aNdIdx; 2740 bRange = sal_True; 2741 } 2742 } 2743 2744 if( bRange ) 2745 { 2746 Push(); // Cursor sichern 2747 2748 SvxSwAutoFmtFlags aAFFlags = *GetAutoFmtFlags(); // erst mal default - Werte 2749 2750 SwAutoFormat aFmt( this, aAFFlags, &pCrsr->GetMark()->nNode, 2751 &pCrsr->GetPoint()->nNode ); 2752 2753 //JP 30.09.96: das DoTable() verlaesst sich auf das PopCrsr 2754 // und MoveCrsr! 2755 Pop( sal_False ); 2756 pCrsr = GetCrsr(); 2757 } 2758 pCrsr->DeleteMark(); 2759 pCrsr->Move( fnMoveForward, fnGoNode ); 2760 2761 EndUndo( UNDO_AUTOFORMAT ); 2762 EndAllAction(); 2763 } 2764 } 2765 2766 SvxSwAutoFmtFlags* SwEditShell::GetAutoFmtFlags() 2767 { 2768 if (!pAutoFmtFlags) 2769 pAutoFmtFlags = new SvxSwAutoFmtFlags; 2770 2771 return pAutoFmtFlags; 2772 } 2773 2774 void SwEditShell::SetAutoFmtFlags(SvxSwAutoFmtFlags * pFlags) 2775 { 2776 SvxSwAutoFmtFlags* pEditFlags = GetAutoFmtFlags(); 2777 2778 pEditFlags->bSetNumRule = pFlags->bSetNumRule; 2779 pEditFlags->bChgEnumNum = pFlags->bChgEnumNum; 2780 pEditFlags->bSetBorder = pFlags->bSetBorder; 2781 pEditFlags->bCreateTable = pFlags->bCreateTable; 2782 pEditFlags->bReplaceStyles = pFlags->bReplaceStyles; 2783 pEditFlags->bAFmtByInpDelSpacesAtSttEnd = 2784 pFlags->bAFmtByInpDelSpacesAtSttEnd; 2785 pEditFlags->bAFmtByInpDelSpacesBetweenLines = 2786 pFlags->bAFmtByInpDelSpacesBetweenLines; 2787 2788 //JP 15.12.98: BulletZeichen und Font in die "normalen" kopieren, 2789 // weil beim Autoformat nur mit diesen gearbeitet wird! 2790 pEditFlags->cBullet = pFlags->cByInputBullet; 2791 pEditFlags->aBulletFont = pFlags->aByInputBulletFont; 2792 pEditFlags->cByInputBullet = pFlags->cByInputBullet; 2793 pEditFlags->aByInputBulletFont = pFlags->aByInputBulletFont; 2794 } 2795