1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_sw.hxx" 30 31 32 #include <hintids.hxx> 33 #include <editeng/unolingu.hxx> 34 #include <com/sun/star/i18n/WordType.hpp> 35 #include <EnhancedPDFExportHelper.hxx> 36 #include <viewopt.hxx> // SwViewOptions 37 #include <viewsh.hxx> 38 #include <errhdl.hxx> 39 #include <txtcfg.hxx> 40 #include <SwPortionHandler.hxx> 41 #include <porhyph.hxx> // 42 #include <inftxt.hxx> 43 #include <itrform2.hxx> // 44 #include <guess.hxx> // 45 #include <splargs.hxx> // SwInterHyphInfo 46 47 #ifdef DBG_UTIL 48 extern const sal_Char *GetLangName( const MSHORT nLang ); 49 #endif 50 51 using ::rtl::OUString; 52 using namespace ::com::sun::star; 53 using namespace ::com::sun::star::uno; 54 using namespace ::com::sun::star::beans; 55 using namespace ::com::sun::star::linguistic2; 56 using namespace ::com::sun::star::i18n; 57 58 /************************************************************************* 59 * SwTxtFormatInfo::HyphWord() 60 *************************************************************************/ 61 62 Reference< XHyphenatedWord > SwTxtFormatInfo::HyphWord( 63 const XubString &rTxt, const MSHORT nMinTrail ) 64 { 65 if( rTxt.Len() < 4 || pFnt->IsSymbol(pVsh) ) 66 return 0; 67 // ASSERT( IsHyphenate(), "SwTxtFormatter::HyphWord: why?" ); 68 Reference< XHyphenator > xHyph = ::GetHyphenator(); 69 Reference< XHyphenatedWord > xHyphWord; 70 71 if( xHyph.is() ) 72 xHyphWord = xHyph->hyphenate( OUString(rTxt), 73 pBreakIt->GetLocale( pFnt->GetLanguage() ), 74 rTxt.Len() - nMinTrail, GetHyphValues() ); 75 return xHyphWord; 76 77 } 78 79 /************************************************************************* 80 * SwTxtFrm::Hyphenate 81 * 82 * Wir formatieren eine Zeile fuer die interaktive Trennung 83 *************************************************************************/ 84 85 sal_Bool SwTxtFrm::Hyphenate( SwInterHyphInfo &rHyphInf ) 86 { 87 ASSERT( ! IsVertical() || ! IsSwapped(),"swapped frame at SwTxtFrm::Hyphenate" ); 88 89 if( !pBreakIt->GetBreakIter().is() ) 90 return sal_False;; 91 // Wir machen den Laden erstmal dicht: 92 ASSERT( !IsLocked(), "SwTxtFrm::Hyphenate: this is locked" ); 93 // 4935: Der frame::Frame muss eine gueltige SSize haben! 94 Calc(); 95 GetFormatted(); 96 97 sal_Bool bRet = sal_False; 98 if( !IsEmpty() ) 99 { 100 // Wir muessen die Trennung immer einschalten. 101 // Keine Angst, der SwTxtIter sichert im Hyphenate die alte Zeile. 102 SwTxtFrmLocker aLock( this ); 103 104 if ( IsVertical() ) 105 SwapWidthAndHeight(); 106 107 SwTxtFormatInfo aInf( this, sal_True ); // sal_True fuer interactive hyph! 108 SwTxtFormatter aLine( this, &aInf ); 109 aLine.CharToLine( rHyphInf.nStart ); 110 // Wenn wir innerhalb des ersten Wortes einer Zeile stehen, so koennte 111 // dieses in der vorherigen getrennt werden, deshalb gehen wir ein Zeile 112 // zurueck. 113 if( aLine.Prev() ) 114 { 115 SwLinePortion *pPor = aLine.GetCurr()->GetFirstPortion(); 116 while( pPor->GetPortion() ) 117 pPor = pPor->GetPortion(); 118 if( pPor->GetWhichPor() == POR_SOFTHYPH || 119 pPor->GetWhichPor() == POR_SOFTHYPHSTR ) 120 aLine.Next(); 121 } 122 123 const xub_StrLen nEnd = rHyphInf.GetEnd(); 124 while( !bRet && aLine.GetStart() < nEnd ) 125 { 126 DBG_LOOP; 127 bRet = aLine.Hyphenate( rHyphInf ); 128 if( !aLine.Next() ) 129 break; 130 } 131 132 if ( IsVertical() ) 133 SwapWidthAndHeight(); 134 } 135 return bRet; 136 } 137 138 /************************************************************************* 139 * SwTxtFormatter::Hyphenate 140 * 141 * Wir formatieren eine Zeile fuer die interaktive Trennung 142 *************************************************************************/ 143 // Wir koennen davon ausgehen, dass bereits formatiert wurde. 144 // Fuer die CeBIT'93 gehen wir den einfachen, sicheren Weg: 145 // Die Zeile wird einfach neu formatiert, der Hyphenator wird dann 146 // so vorbereitet, wie ihn die UI erwartet. 147 // Hier stehen natuerlich enorme Optimierungsmoeglichkeiten offen. 148 149 void SetParaPortion( SwTxtInfo *pInf, SwParaPortion *pRoot ) 150 { 151 ASSERT( pRoot, "SetParaPortion: no root anymore" ); 152 pInf->pPara = pRoot; 153 } 154 155 sal_Bool SwTxtFormatter::Hyphenate( SwInterHyphInfo &rHyphInf ) 156 { 157 SwTxtFormatInfo &rInf = GetInfo(); 158 sal_Bool bRet = sal_False; 159 160 // In der letzten Zeile gibt es nie etwas zu trennen. 161 // Es sei denn, es befindet sich eine FlyPortion darin, 162 // oder es ist die letzte Zeile des Masters 163 if( !GetNext() && !rInf.GetTxtFly()->IsOn() && !pFrm->GetFollow() ) 164 return bRet; 165 166 xub_StrLen nWrdStart = nStart; 167 168 // Wir muessen die alte Zeile erhalten. Ein Beispiel: 169 // Das Attribut fuer Trennung wurde nicht gesetzt, 170 // in SwTxtFrm::Hyphenate wird es jedoch immer gesetzt, 171 // weil wir Trennpositionen im Hyphenator einstellen wollen. 172 SwLineLayout *pOldCurr = pCurr; 173 174 InitCntHyph(); 175 176 // 5298: IsParaLine() (ex.IsFirstLine) fragt auf GetParaPortion() ab. 177 // wir muessen gleiche Bedingungen schaffen: in der ersten 178 // Zeile formatieren wir SwParaPortions... 179 if( pOldCurr->IsParaPortion() ) 180 { 181 SwParaPortion *pPara = new SwParaPortion(); 182 SetParaPortion( &rInf, pPara ); 183 pCurr = pPara; 184 ASSERT( IsParaLine(), "SwTxtFormatter::Hyphenate: not the first" ); 185 } 186 else 187 pCurr = new SwLineLayout(); 188 189 nWrdStart = FormatLine( nWrdStart ); 190 191 // Man muss immer im Hinterkopf behalten, dass es z.B. 192 // Felder gibt, die aufgetrennt werden koennen ... 193 if( pCurr->PrtWidth() && pCurr->GetLen() ) 194 { 195 // Wir muessen uns darauf einstellen, dass in der Zeile 196 // FlyFrms haengen, an denen auch umgebrochen werden darf. 197 // Wir suchen also die erste HyphPortion in dem angegebenen 198 // Bereich. 199 200 SwLinePortion *pPos = pCurr->GetPortion(); 201 const xub_StrLen nPamStart = rHyphInf.nStart; 202 nWrdStart = nStart; 203 const xub_StrLen nEnd = rHyphInf.GetEnd(); 204 while( pPos ) 205 { 206 // Entweder wir liegen drueber oder wir laufen gerade auf eine 207 // Hyphportion die am Ende der Zeile oder vor einem Flys steht. 208 if( nWrdStart >= nEnd ) 209 { 210 nWrdStart = 0; 211 break; 212 } 213 214 if( nWrdStart >= nPamStart && pPos->InHyphGrp() 215 && ( !pPos->IsSoftHyphPortion() 216 || ((SwSoftHyphPortion*)pPos)->IsExpand() ) ) 217 { 218 nWrdStart = nWrdStart + pPos->GetLen(); 219 break; 220 } 221 222 nWrdStart = nWrdStart + pPos->GetLen(); 223 pPos = pPos->GetPortion(); 224 } 225 // Wenn pPos 0 ist, wurde keine Trennstelle ermittelt. 226 if( !pPos ) 227 nWrdStart = 0; 228 } 229 230 // Das alte LineLayout wird wieder eingestellt ... 231 delete pCurr; 232 pCurr = pOldCurr; 233 234 if( pOldCurr->IsParaPortion() ) 235 { 236 SetParaPortion( &rInf, (SwParaPortion*)pOldCurr ); 237 ASSERT( IsParaLine(), "SwTxtFormatter::Hyphenate: even not the first" ); 238 } 239 240 if( nWrdStart ) 241 { 242 // nWrdStart bezeichnet nun die Position im String, der 243 // fuer eine Trennung zur Debatte steht. 244 // Start() hangelt sich zum End() 245 rHyphInf.nWordStart = nWrdStart; 246 247 xub_StrLen nLen = 0; 248 const xub_StrLen nEnd = nWrdStart; 249 250 // Wir suchen vorwaerts 251 Reference< XHyphenatedWord > xHyphWord; 252 253 Boundary aBound = 254 pBreakIt->GetBreakIter()->getWordBoundary( rInf.GetTxt(), nWrdStart, 255 pBreakIt->GetLocale( rInf.GetFont()->GetLanguage() ), WordType::DICTIONARY_WORD, sal_True ); 256 nWrdStart = static_cast<xub_StrLen>(aBound.startPos); 257 nLen = static_cast<xub_StrLen>(aBound.endPos - nWrdStart); 258 bRet = 0 != nLen; 259 if( bRet ) 260 { 261 XubString aSelTxt( rInf.GetTxt().Copy(nWrdStart, nLen) ); 262 xub_StrLen nCnt = 0; 263 264 // these things should be handled by the dialog 265 // for( xub_StrLen i = 0; i < nLen; ++i ) 266 // { 267 // sal_Unicode cCh = aSelTxt.GetChar(i); 268 // if( (CH_TXTATR_BREAKWORD == cCh || CH_TXTATR_INWORD == cCh ) 269 // && rInf.HasHint( nWrdStart + i ) ) 270 // { 271 // aSelTxt.Erase( i , 1 ); 272 // nCnt++; 273 // --nLen; 274 // if( i ) 275 // --i; 276 // } 277 // } 278 279 { 280 MSHORT nMinTrail = 0; 281 if( nWrdStart + nLen > nEnd ) 282 nMinTrail = nWrdStart + nLen - nEnd - 1; 283 284 //!! rHyphInf.SetHyphWord( ... ) mu??? hier geschehen 285 xHyphWord = rInf.HyphWord( aSelTxt, nMinTrail ); 286 bRet = xHyphWord.is(); 287 if ( !rHyphInf.IsCheck() && sal_False == bRet ) 288 rHyphInf.SetNoLang( sal_True ); 289 } 290 291 if( bRet ) 292 { 293 rHyphInf.SetHyphWord( xHyphWord ); 294 rHyphInf.nWordStart = nWrdStart; 295 rHyphInf.nWordLen = nLen+nCnt; 296 rHyphInf.SetNoLang( sal_False ); 297 rHyphInf.SetCheck( sal_True ); 298 } 299 #ifdef DEBUGGY 300 if( OPTDBG( rInf ) ) 301 { 302 ASSERT( aSelTxt == aHyphWord, 303 "!SwTxtFormatter::Hyphenate: different words, different planets" ); 304 aDbstream << "Diff: \"" << aSelTxt.GetStr() << "\" != \"" 305 << aHyphWord.GetStr() << "\"" << endl; 306 ASSERT( bRet, "!SwTxtFormatter::Hyphenate: three of a perfect pair" ); 307 aDbstream << "Hyphenate: "; 308 } 309 #endif 310 } 311 } 312 return bRet; 313 } 314 315 /************************************************************************* 316 * SwTxtPortion::CreateHyphen() 317 *************************************************************************/ 318 319 sal_Bool SwTxtPortion::CreateHyphen( SwTxtFormatInfo &rInf, SwTxtGuess &rGuess ) 320 { 321 Reference< XHyphenatedWord > xHyphWord = rGuess.HyphWord(); 322 323 ASSERT( !pPortion, "SwTxtPortion::CreateHyphen(): another portion, another planet..." ) 324 ASSERT( xHyphWord.is(), "SwTxtPortion::CreateHyphen(): You are lucky! The code is robust here." ) 325 326 if( rInf.IsHyphForbud() || 327 pPortion || // robust 328 !xHyphWord.is() || // more robust 329 // Mehrzeilige Felder duerfen nicht interaktiv getrennt werden. 330 ( rInf.IsInterHyph() && InFldGrp() ) ) 331 return sal_False; 332 333 SwHyphPortion *pHyphPor; 334 xub_StrLen nPorEnd; 335 SwTxtSizeInfo aInf( rInf ); 336 337 // first case: hyphenated word has alternative spelling 338 if ( xHyphWord->isAlternativeSpelling() ) 339 { 340 SvxAlternativeSpelling aAltSpell; 341 aAltSpell = SvxGetAltSpelling( xHyphWord ); 342 ASSERT( aAltSpell.bIsAltSpelling, "no alternatve spelling" ); 343 344 XubString aAltTxt = aAltSpell.aReplacement; 345 nPorEnd = aAltSpell.nChangedPos + rGuess.BreakStart() - rGuess.FieldDiff(); 346 xub_StrLen nTmpLen = 0; 347 348 // soft hyphen at alternative spelling position? 349 if( rInf.GetTxt().GetChar( rInf.GetSoftHyphPos() ) == CHAR_SOFTHYPHEN ) 350 { 351 pHyphPor = new SwSoftHyphStrPortion( aAltTxt ); 352 nTmpLen = 1; 353 } 354 else { 355 pHyphPor = new SwHyphStrPortion( aAltTxt ); 356 } 357 358 // length of pHyphPor is adjusted 359 pHyphPor->SetLen( aAltTxt.Len() + 1 ); 360 (SwPosSize&)(*pHyphPor) = pHyphPor->GetTxtSize( rInf ); 361 pHyphPor->SetLen( aAltSpell.nChangedLength + nTmpLen ); 362 } 363 else 364 { 365 // second case: no alternative spelling 366 SwHyphPortion aHyphPor; 367 aHyphPor.SetLen( 1 ); 368 369 static const void* pLastMagicNo = 0; 370 static KSHORT aMiniCacheH = 0, aMiniCacheW = 0; 371 const void* pTmpMagic; 372 MSHORT nFntIdx; 373 rInf.GetFont()->GetMagic( pTmpMagic, nFntIdx, rInf.GetFont()->GetActual() ); 374 if( !pLastMagicNo || pLastMagicNo != pTmpMagic ) { 375 pLastMagicNo = pTmpMagic; 376 (SwPosSize&)aHyphPor = aHyphPor.GetTxtSize( rInf ); 377 aMiniCacheH = aHyphPor.Height(), aMiniCacheW = aHyphPor.Width(); 378 } else { 379 aHyphPor.Height( aMiniCacheH ), aHyphPor.Width( aMiniCacheW ); 380 } 381 aHyphPor.SetLen( 0 ); 382 pHyphPor = new SwHyphPortion( aHyphPor ); 383 384 pHyphPor->SetWhichPor( POR_HYPH ); 385 386 // values required for this 387 nPorEnd = xHyphWord->getHyphenPos() + 1 + rGuess.BreakStart() 388 - rGuess.FieldDiff(); 389 } 390 391 // portion end must be in front of us 392 // we do not put hyphens at start of line 393 if ( nPorEnd > rInf.GetIdx() || 394 ( nPorEnd == rInf.GetIdx() && rInf.GetLineStart() != rInf.GetIdx() ) ) 395 { 396 aInf.SetLen( nPorEnd - rInf.GetIdx() ); 397 pHyphPor->SetAscent( GetAscent() ); 398 SetLen( aInf.GetLen() ); 399 CalcTxtSize( aInf ); 400 401 Insert( pHyphPor ); 402 403 short nKern = rInf.GetFont()->CheckKerning(); 404 if( nKern ) 405 new SwKernPortion( *this, nKern ); 406 407 return sal_True; 408 } 409 410 // last exit for the lost 411 delete pHyphPor; 412 BreakCut( rInf, rGuess ); 413 return sal_False; 414 } 415 416 417 /************************************************************************* 418 * virtual SwHyphPortion::GetExpTxt() 419 *************************************************************************/ 420 421 sal_Bool SwHyphPortion::GetExpTxt( const SwTxtSizeInfo &rInf, XubString &rTxt ) const 422 { 423 // --> FME 2004-06-24 #i16816# tagged pdf support 424 const sal_Unicode cChar = rInf.GetVsh() && 425 rInf.GetVsh()->GetViewOptions()->IsPDFExport() && 426 SwTaggedPDFHelper::IsExportTaggedPDF( *rInf.GetOut() ) ? 427 0xad : 428 '-'; 429 // <-- 430 431 rTxt = cChar; 432 return sal_True; 433 } 434 435 /************************************************************************* 436 * virtual SwHyphPortion::HandlePortion() 437 *************************************************************************/ 438 439 void SwHyphPortion::HandlePortion( SwPortionHandler& rPH ) const 440 { 441 String aString( '-' ); 442 rPH.Special( GetLen(), aString, GetWhichPor() ); 443 } 444 445 /************************************************************************* 446 * virtual SwHyphPortion::Format() 447 *************************************************************************/ 448 449 sal_Bool SwHyphPortion::Format( SwTxtFormatInfo &rInf ) 450 { 451 const SwLinePortion *pLast = rInf.GetLast(); 452 Height( pLast->Height() ); 453 SetAscent( pLast->GetAscent() ); 454 XubString aTxt; 455 456 if( !GetExpTxt( rInf, aTxt ) ) 457 return sal_False; 458 459 PrtWidth( rInf.GetTxtSize( aTxt ).Width() ); 460 const sal_Bool bFull = rInf.Width() <= rInf.X() + PrtWidth(); 461 if( bFull && !rInf.IsUnderFlow() ) { 462 Truncate(); 463 rInf.SetUnderFlow( this ); 464 } 465 466 return bFull; 467 } 468 469 /************************************************************************* 470 * virtual SwHyphStrPortion::GetExpTxt() 471 *************************************************************************/ 472 473 sal_Bool SwHyphStrPortion::GetExpTxt( const SwTxtSizeInfo &, XubString &rTxt ) const 474 { 475 rTxt = aExpand; 476 return sal_True; 477 } 478 479 /************************************************************************* 480 * virtual SwHyphStrPortion::HandlePortion() 481 *************************************************************************/ 482 483 void SwHyphStrPortion::HandlePortion( SwPortionHandler& rPH ) const 484 { 485 rPH.Special( GetLen(), aExpand, GetWhichPor() ); 486 } 487 488 /************************************************************************* 489 * class SwSoftHyphPortion 490 *************************************************************************/ 491 492 SwLinePortion *SwSoftHyphPortion::Compress() { return this; } 493 494 SwSoftHyphPortion::SwSoftHyphPortion() : 495 bExpand(sal_False), nViewWidth(0), nHyphWidth(0) 496 { 497 SetLen(1); 498 SetWhichPor( POR_SOFTHYPH ); 499 } 500 501 KSHORT SwSoftHyphPortion::GetViewWidth( const SwTxtSizeInfo &rInf ) const 502 { 503 // Wir stehen zwar im const, aber nViewWidth sollte erst im letzten 504 // Moment errechnet werden: 505 if( !Width() && rInf.OnWin() && rInf.GetOpt().IsSoftHyph() && !IsExpand() ) 506 { 507 if( !nViewWidth ) 508 ((SwSoftHyphPortion*)this)->nViewWidth 509 = rInf.GetTxtSize( '-' ).Width(); 510 } 511 else 512 ((SwSoftHyphPortion*)this)->nViewWidth = 0; 513 return nViewWidth; 514 } 515 516 /* Faelle: 517 * 1) SoftHyph steht in der Zeile, ViewOpt aus. 518 * -> unsichtbar, Nachbarn unveraendert 519 * 2) SoftHyph steht in der Zeile, ViewOpt an. 520 * -> sichtbar, Nachbarn veraendert 521 * 3) SoftHyph steht am Zeilenende, ViewOpt aus/an. 522 * -> immer sichtbar, Nachbarn unveraendert 523 */ 524 525 void SwSoftHyphPortion::Paint( const SwTxtPaintInfo &rInf ) const 526 { 527 if( Width() ) 528 { 529 rInf.DrawViewOpt( *this, POR_SOFTHYPH ); 530 SwExpandPortion::Paint( rInf ); 531 } 532 } 533 534 /************************************************************************* 535 * virtual SwSoftHyphPortion::Format() 536 *************************************************************************/ 537 538 /* Die endgueltige Breite erhalten wir im FormatEOL(). 539 * In der Underflow-Phase stellen wir fest, ob ueberhaupt ein 540 * alternatives Spelling vorliegt. Wenn ja ... 541 * 542 * Fall 1: "Au-to" 543 * 1) {Au}{-}{to}, {to} passt nicht mehr => Underflow 544 * 2) {-} ruft Hyphenate => keine Alternative 545 * 3) FormatEOL() und bFull = sal_True 546 * 547 * Fall 2: "Zuc-ker" 548 * 1) {Zuc}{-}{ker}, {ker} passt nicht mehr => Underflow 549 * 2) {-} ruft Hyphenate => Alternative! 550 * 3) Underflow() und bFull = sal_True 551 * 4) {Zuc} ruft Hyphenate => {Zuk}{-}{ker} 552 */ 553 554 sal_Bool SwSoftHyphPortion::Format( SwTxtFormatInfo &rInf ) 555 { 556 sal_Bool bFull = sal_True; 557 558 // special case for old german spelling 559 if( rInf.IsUnderFlow() ) 560 { 561 if( rInf.GetSoftHyphPos() ) 562 return sal_True; 563 564 const sal_Bool bHyph = rInf.ChgHyph( sal_True ); 565 if( rInf.IsHyphenate() ) 566 { 567 rInf.SetSoftHyphPos( rInf.GetIdx() ); 568 Width(0); 569 // if the soft hyphend word has an alternative spelling 570 // when hyphenated (old german spelling), the soft hyphen 571 // portion has to trigger an underflow 572 SwTxtGuess aGuess; 573 bFull = rInf.IsInterHyph() || 574 !aGuess.AlternativeSpelling( rInf, rInf.GetIdx() - 1 ); 575 } 576 rInf.ChgHyph( bHyph ); 577 578 if( bFull && !rInf.IsHyphForbud() ) 579 { 580 rInf.SetSoftHyphPos(0); 581 FormatEOL( rInf ); 582 if ( rInf.GetFly() ) 583 rInf.GetRoot()->SetMidHyph( sal_True ); 584 else 585 rInf.GetRoot()->SetEndHyph( sal_True ); 586 } 587 else 588 { 589 rInf.SetSoftHyphPos( rInf.GetIdx() ); 590 Truncate(); 591 rInf.SetUnderFlow( this ); 592 } 593 return sal_True; 594 } 595 596 rInf.SetSoftHyphPos(0); 597 SetExpand( sal_True ); 598 bFull = SwHyphPortion::Format( rInf ); 599 SetExpand( sal_False ); 600 if( !bFull ) 601 { 602 // default-maessig besitzen wir keine Breite, aber eine Hoehe 603 nHyphWidth = Width(); 604 Width(0); 605 } 606 return bFull; 607 } 608 609 /************************************************************************* 610 * virtual SwSoftHyphPortion::FormatEOL() 611 *************************************************************************/ 612 // Format end of Line 613 614 void SwSoftHyphPortion::FormatEOL( SwTxtFormatInfo &rInf ) 615 { 616 if( !IsExpand() ) 617 { 618 SetExpand( sal_True ); 619 if( rInf.GetLast() == this ) 620 rInf.SetLast( FindPrevPortion( rInf.GetRoot() ) ); 621 622 // 5964: alte Werte muessen wieder zurueckgesetzt werden. 623 const SwTwips nOldX = rInf.X(); 624 const xub_StrLen nOldIdx = rInf.GetIdx(); 625 rInf.X( rInf.X() - PrtWidth() ); 626 rInf.SetIdx( rInf.GetIdx() - GetLen() ); 627 const sal_Bool bFull = SwHyphPortion::Format( rInf ); 628 nHyphWidth = Width(); 629 630 // 6976: Eine truebe Sache: Wir werden erlaubterweise breiter, 631 // aber gleich wird noch ein Fly verarbeitet, der eine korrekte 632 // X-Position braucht. 633 if( bFull || !rInf.GetFly() ) 634 rInf.X( nOldX ); 635 else 636 rInf.X( nOldX + Width() ); 637 rInf.SetIdx( nOldIdx ); 638 } 639 } 640 641 /************************************************************************* 642 * virtual SwSoftHyphPortion::GetExpTxt() 643 * 644 * Wir expandieren: 645 * - wenn die Sonderzeichen sichtbar sein sollen 646 * - wenn wir am Ende der Zeile stehen. 647 * - wenn wir vor einem (echten/emuliertem) Zeilenumbruch stehen 648 *************************************************************************/ 649 650 sal_Bool SwSoftHyphPortion::GetExpTxt( const SwTxtSizeInfo &rInf, XubString &rTxt ) const 651 { 652 if( IsExpand() || ( rInf.OnWin() && rInf.GetOpt().IsSoftHyph() ) || 653 ( GetPortion() && ( GetPortion()->InFixGrp() || 654 GetPortion()->IsDropPortion() || GetPortion()->IsLayPortion() || 655 GetPortion()->IsParaPortion() || GetPortion()->IsBreakPortion() ) ) ) 656 { 657 return SwHyphPortion::GetExpTxt( rInf, rTxt ); 658 } 659 return sal_False; 660 } 661 662 /************************************************************************* 663 * virtual SwSoftHyphPortion::HandlePortion() 664 *************************************************************************/ 665 666 void SwSoftHyphPortion::HandlePortion( SwPortionHandler& rPH ) const 667 { 668 const String aString( '-' ); 669 const sal_uInt16 nWhich = ! Width() ? 670 POR_SOFTHYPH_COMP : 671 GetWhichPor(); 672 rPH.Special( GetLen(), aString, nWhich ); 673 } 674 675 /************************************************************************* 676 * SwSoftHyphStrPortion::Paint 677 *************************************************************************/ 678 679 void SwSoftHyphStrPortion::Paint( const SwTxtPaintInfo &rInf ) const 680 { 681 // Bug oder feature?: 682 // {Zu}{k-}{ker}, {k-} wird grau statt {-} 683 rInf.DrawViewOpt( *this, POR_SOFTHYPH ); 684 SwHyphStrPortion::Paint( rInf ); 685 } 686 687 SwSoftHyphStrPortion::SwSoftHyphStrPortion( const XubString &rStr ) 688 : SwHyphStrPortion( rStr ) 689 { 690 SetLen( 1 ); 691 SetWhichPor( POR_SOFTHYPHSTR ); 692 } 693 694 695 696