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 <ctype.h> 33 34 #ifndef _COM_SUN_STAR_I18N_SCRIPTTYPE_HDL_ 35 #include <com/sun/star/i18n/ScriptType.hdl> 36 #endif 37 #include <hintids.hxx> // CH_TXTATR 38 #include <errhdl.hxx> // ASSERT 39 #include <SwPortionHandler.hxx> 40 #include <txtcfg.hxx> 41 #include <porlay.hxx> 42 #include <inftxt.hxx> 43 #include <guess.hxx> // SwTxtGuess, Zeilenumbruch 44 #include <porglue.hxx> 45 #include <portab.hxx> // pLastTab-> 46 #include <porfld.hxx> // SwFldPortion 47 #include <wrong.hxx> 48 #include <viewsh.hxx> 49 #include <IDocumentSettingAccess.hxx> 50 #include <viewopt.hxx> // SwViewOptions 51 52 #include <IMark.hxx> 53 #include <pam.hxx> 54 #include <doc.hxx> 55 #include <xmloff/odffields.hxx> 56 57 #if OSL_DEBUG_LEVEL > 1 58 const sal_Char *GetLangName( const MSHORT nLang ); 59 #endif 60 61 using namespace ::sw::mark; 62 using namespace ::com::sun::star; 63 using namespace ::com::sun::star::i18n::ScriptType; 64 65 /************************************************************************* 66 * lcl_AddSpace 67 * Returns for how many characters an extra space has to be added 68 * (for justified alignment). 69 *************************************************************************/ 70 71 sal_uInt16 lcl_AddSpace( const SwTxtSizeInfo &rInf, const XubString* pStr, 72 const SwLinePortion& rPor ) 73 { 74 xub_StrLen nPos, nEnd; 75 const SwScriptInfo* pSI = 0; 76 77 if ( pStr ) 78 { 79 // passing a string means we are inside a field 80 nPos = 0; 81 nEnd = pStr->Len(); 82 } 83 else 84 { 85 nPos = rInf.GetIdx(); 86 nEnd = rInf.GetIdx() + rPor.GetLen(); 87 pStr = &rInf.GetTxt(); 88 pSI = &((SwParaPortion*)rInf.GetParaPortion())->GetScriptInfo(); 89 } 90 91 sal_uInt16 nCnt = 0; 92 sal_uInt8 nScript = 0; 93 94 // If portion consists of Asian characters and language is not 95 // Korean, we add extra space to each character. 96 // first we get the script type 97 if ( pSI ) 98 nScript = pSI->ScriptType( nPos ); 99 else if ( pBreakIt->GetBreakIter().is() ) 100 nScript = (sal_uInt8)pBreakIt->GetBreakIter()->getScriptType( *pStr, nPos ); 101 102 // Note: rInf.GetIdx() can differ from nPos, 103 // e.g., when rPor is a field portion. nPos referes to the string passed 104 // to the function, rInf.GetIdx() referes to the original string. 105 106 // We try to find out which justification mode is required. This is done by 107 // evaluating the script type and the language attribute set for this portion 108 109 // Asian Justification: Each character get some extra space 110 if ( nEnd > nPos && ASIAN == nScript ) 111 { 112 LanguageType aLang = 113 rInf.GetTxtFrm()->GetTxtNode()->GetLang( rInf.GetIdx(), 1, nScript ); 114 115 if ( LANGUAGE_KOREAN != aLang && LANGUAGE_KOREAN_JOHAB != aLang ) 116 { 117 const SwLinePortion* pPor = rPor.GetPortion(); 118 if ( pPor && ( pPor->IsKernPortion() || 119 pPor->IsControlCharPortion() || 120 pPor->IsPostItsPortion() ) ) 121 pPor = pPor->GetPortion(); 122 123 nCnt += nEnd - nPos; 124 125 if ( !pPor || pPor->IsHolePortion() || pPor->InFixMargGrp() || 126 pPor->IsBreakPortion() ) 127 --nCnt; 128 129 return nCnt; 130 } 131 } 132 133 // Kashida Justification: Insert Kashidas 134 if ( nEnd > nPos && pSI && COMPLEX == nScript ) 135 { 136 if ( SwScriptInfo::IsArabicText( *pStr, nPos, nEnd - nPos ) && pSI->CountKashida() ) 137 { 138 const sal_uInt16 nKashRes = pSI->KashidaJustify( 0, 0, nPos, nEnd - nPos ); 139 // i60591: need to check result of KashidaJustify 140 // determine if kashida justification is applicable 141 if( nKashRes != STRING_LEN ) 142 return nKashRes; 143 } 144 } 145 146 // Thai Justification: Each character cell gets some extra space 147 if ( nEnd > nPos && COMPLEX == nScript ) 148 { 149 LanguageType aLang = 150 rInf.GetTxtFrm()->GetTxtNode()->GetLang( rInf.GetIdx(), 1, nScript ); 151 152 if ( LANGUAGE_THAI == aLang ) 153 { 154 nCnt = SwScriptInfo::ThaiJustify( *pStr, 0, 0, nPos, nEnd - nPos ); 155 156 const SwLinePortion* pPor = rPor.GetPortion(); 157 if ( pPor && ( pPor->IsKernPortion() || 158 pPor->IsControlCharPortion() || 159 pPor->IsPostItsPortion() ) ) 160 pPor = pPor->GetPortion(); 161 162 if ( nCnt && ( ! pPor || pPor->IsHolePortion() || pPor->InFixMargGrp() ) ) 163 --nCnt; 164 165 return nCnt; 166 } 167 } 168 169 // Here starts the good old "Look for blanks and add space to them" part. 170 // Note: We do not want to add space to an isolated latin blank in front 171 // of some complex characters in RTL environment 172 const sal_Bool bDoNotAddSpace = 173 LATIN == nScript && ( nEnd == nPos + 1 ) && pSI && 174 ( i18n::ScriptType::COMPLEX == 175 pSI->ScriptType( nPos + 1 ) ) && 176 rInf.GetTxtFrm() && rInf.GetTxtFrm()->IsRightToLeft(); 177 178 if ( bDoNotAddSpace ) 179 return nCnt; 180 181 for ( ; nPos < nEnd; ++nPos ) 182 { 183 if( CH_BLANK == pStr->GetChar( nPos ) ) 184 ++nCnt; 185 } 186 187 // We still have to examine the next character: 188 // If the next character is ASIAN and not KOREAN we have 189 // to add an extra space 190 // nPos referes to the original string, even if a field string has 191 // been passed to this function 192 nPos = rInf.GetIdx() + rPor.GetLen(); 193 if ( nPos < rInf.GetTxt().Len() ) 194 { 195 sal_uInt8 nNextScript = 0; 196 const SwLinePortion* pPor = rPor.GetPortion(); 197 if ( pPor && pPor->IsKernPortion() ) 198 pPor = pPor->GetPortion(); 199 200 if ( ! pBreakIt->GetBreakIter().is() || ! pPor || pPor->InFixMargGrp() ) 201 return nCnt; 202 203 // next character is inside a field? 204 if ( CH_TXTATR_BREAKWORD == rInf.GetChar( nPos ) && pPor->InExpGrp() ) 205 { 206 sal_Bool bOldOnWin = rInf.OnWin(); 207 ((SwTxtSizeInfo &)rInf).SetOnWin( sal_False ); 208 209 XubString aStr( aEmptyStr ); 210 pPor->GetExpTxt( rInf, aStr ); 211 ((SwTxtSizeInfo &)rInf).SetOnWin( bOldOnWin ); 212 213 nNextScript = (sal_uInt8)pBreakIt->GetBreakIter()->getScriptType( aStr, 0 ); 214 } 215 else 216 nNextScript = (sal_uInt8)pBreakIt->GetBreakIter()->getScriptType( rInf.GetTxt(), nPos ); 217 218 if( ASIAN == nNextScript ) 219 { 220 LanguageType aLang = 221 rInf.GetTxtFrm()->GetTxtNode()->GetLang( nPos, 1, nNextScript ); 222 223 if ( LANGUAGE_KOREAN != aLang && LANGUAGE_KOREAN_JOHAB != aLang ) 224 ++nCnt; 225 } 226 } 227 228 return nCnt; 229 } 230 231 /************************************************************************* 232 * class SwTxtPortion 233 *************************************************************************/ 234 235 SwTxtPortion::SwTxtPortion( const SwLinePortion &rPortion ) 236 : SwLinePortion( rPortion ) 237 { 238 SetWhichPor( POR_TXT ); 239 } 240 241 /************************************************************************* 242 * SwTxtPortion::BreakCut() 243 *************************************************************************/ 244 245 void SwTxtPortion::BreakCut( SwTxtFormatInfo &rInf, const SwTxtGuess &rGuess ) 246 { 247 // Das Wort/Zeichen ist groesser als die Zeile 248 // Sonderfall Nr.1: Das Wort ist groesser als die Zeile 249 // Wir kappen... 250 const KSHORT nLineWidth = (KSHORT)(rInf.Width() - rInf.X()); 251 xub_StrLen nLen = rGuess.CutPos() - rInf.GetIdx(); 252 if( nLen ) 253 { 254 // special case: guess does not always provide the correct 255 // width, only in common cases. 256 if ( !rGuess.BreakWidth() ) 257 { 258 rInf.SetLen( nLen ); 259 SetLen( nLen ); 260 CalcTxtSize( rInf ); 261 262 // changing these values requires also changing them in 263 // guess.cxx 264 KSHORT nItalic = 0; 265 if( ITALIC_NONE != rInf.GetFont()->GetItalic() && !rInf.NotEOL() ) 266 { 267 nItalic = Height() / 12; 268 } 269 Width( Width() + nItalic ); 270 } 271 else 272 { 273 Width( rGuess.BreakWidth() ); 274 SetLen( nLen ); 275 } 276 } 277 // special case: first character does not fit to line 278 else if ( rGuess.CutPos() == rInf.GetLineStart() ) 279 { 280 SetLen( 1 ); 281 Width( nLineWidth ); 282 } 283 else 284 { 285 SetLen( 0 ); 286 Width( 0 ); 287 } 288 } 289 290 /************************************************************************* 291 * SwTxtPortion::BreakUnderflow() 292 *************************************************************************/ 293 294 void SwTxtPortion::BreakUnderflow( SwTxtFormatInfo &rInf ) 295 { 296 Truncate(); 297 Height( 0 ); 298 Width( 0 ); 299 SetLen( 0 ); 300 SetAscent( 0 ); 301 rInf.SetUnderFlow( this ); 302 } 303 304 /************************************************************************* 305 * SwTxtPortion::_Format() 306 *************************************************************************/ 307 308 sal_Bool lcl_HasContent( const SwFldPortion& rFld, SwTxtFormatInfo &rInf ) 309 { 310 String aTxt; 311 return rFld.GetExpTxt( rInf, aTxt ) && aTxt.Len(); 312 } 313 314 sal_Bool SwTxtPortion::_Format( SwTxtFormatInfo &rInf ) 315 { 316 // 5744: wenn nur der Trennstrich nicht mehr passt, 317 // muss trotzdem das Wort umgebrochen werden, ansonsten return sal_True! 318 if( rInf.IsUnderFlow() && rInf.GetSoftHyphPos() ) 319 { 320 // soft hyphen portion has triggered an underflow event because 321 // of an alternative spelling position 322 sal_Bool bFull = sal_False; 323 const sal_Bool bHyph = rInf.ChgHyph( sal_True ); 324 if( rInf.IsHyphenate() ) 325 { 326 SwTxtGuess aGuess; 327 // check for alternative spelling left from the soft hyphen 328 // this should usually be true but 329 aGuess.AlternativeSpelling( rInf, rInf.GetSoftHyphPos() - 1 ); 330 bFull = CreateHyphen( rInf, aGuess ); 331 ASSERT( bFull, "Problem with hyphenation!!!" ); 332 } 333 rInf.ChgHyph( bHyph ); 334 rInf.SetSoftHyphPos( 0 ); 335 return bFull; 336 } 337 338 SwTxtGuess aGuess; 339 const sal_Bool bFull = !aGuess.Guess( *this, rInf, Height() ); 340 341 // these are the possible cases: 342 // A Portion fits to current line 343 // B Portion does not fit to current line but a possible line break 344 // within the portion has been found by the break iterator, 2 subcases 345 // B1 break is hyphen 346 // B2 break is word end 347 // C Portion does not fit to current line and no possible line break 348 // has been found by break iterator, 2 subcases: 349 // C1 break iterator found a possible line break in portion before us 350 // ==> this break is used (underflow) 351 // C2 break iterator does not found a possible line break at all: 352 // ==> line break 353 354 // case A: line not yet full 355 if ( !bFull ) 356 { 357 Width( aGuess.BreakWidth() ); 358 // Vorsicht ! 359 if( !InExpGrp() || InFldGrp() ) 360 SetLen( rInf.GetLen() ); 361 362 short nKern = rInf.GetFont()->CheckKerning(); 363 if( nKern > 0 && rInf.Width() < rInf.X() + Width() + nKern ) 364 { 365 nKern = (short)(rInf.Width() - rInf.X() - Width() - 1); 366 if( nKern < 0 ) 367 nKern = 0; 368 } 369 if( nKern ) 370 new SwKernPortion( *this, nKern ); 371 } 372 // special case: hanging portion 373 else if( bFull && aGuess.GetHangingPortion() ) 374 { 375 Width( aGuess.BreakWidth() ); 376 SetLen( aGuess.BreakPos() - rInf.GetIdx() ); 377 Insert( aGuess.GetHangingPortion() ); 378 aGuess.GetHangingPortion()->SetAscent( GetAscent() ); 379 aGuess.ClearHangingPortion(); 380 } 381 // breakPos >= index 382 else if ( aGuess.BreakPos() >= rInf.GetIdx() && aGuess.BreakPos() != STRING_LEN ) 383 { 384 // case B1 385 if( aGuess.HyphWord().is() && aGuess.BreakPos() > rInf.GetLineStart() 386 && ( aGuess.BreakPos() > rInf.GetIdx() || 387 ( rInf.GetLast() && ! rInf.GetLast()->IsFlyPortion() ) ) ) 388 { 389 CreateHyphen( rInf, aGuess ); 390 if ( rInf.GetFly() ) 391 rInf.GetRoot()->SetMidHyph( sal_True ); 392 else 393 rInf.GetRoot()->SetEndHyph( sal_True ); 394 } 395 // case C1 396 // - Footnote portions with fake line start (i.e., not at beginning of line) 397 // should keep together with the text portion. (Note: no keep together 398 // with only footnote portions. 399 // - TabPortions not at beginning of line should keep together with the 400 // text portion, if they are not followed by a blank 401 // (work around different definition of tab stop character - breaking or 402 // non breaking character - in compatibility mode) 403 else if ( ( IsFtnPortion() && rInf.IsFakeLineStart() && 404 // --> OD 2010-01-29 #b6921213# 405 rInf.IsOtherThanFtnInside() ) || 406 // <-- 407 ( rInf.GetLast() && 408 rInf.GetTxtFrm()->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::TAB_COMPAT) && 409 rInf.GetLast()->InTabGrp() && 410 rInf.GetLineStart() + rInf.GetLast()->GetLen() < rInf.GetIdx() && 411 aGuess.BreakPos() == rInf.GetIdx() && 412 CH_BLANK != rInf.GetChar( rInf.GetIdx() ) && 413 0x3000 != rInf.GetChar( rInf.GetIdx() ) ) ) 414 BreakUnderflow( rInf ); 415 // case B2 416 else if( rInf.GetIdx() > rInf.GetLineStart() || 417 aGuess.BreakPos() > rInf.GetIdx() || 418 // this is weird: during formatting the follow of a field 419 // the values rInf.GetIdx and rInf.GetLineStart are replaced 420 // IsFakeLineStart indicates GetIdx > GetLineStart 421 rInf.IsFakeLineStart() || 422 rInf.GetFly() || 423 rInf.IsFirstMulti() || 424 ( rInf.GetLast() && 425 ( rInf.GetLast()->IsFlyPortion() || 426 ( rInf.GetLast()->InFldGrp() && 427 ! rInf.GetLast()->InNumberGrp() && 428 ! rInf.GetLast()->IsErgoSumPortion() && 429 lcl_HasContent(*((SwFldPortion*)rInf.GetLast()),rInf ) ) ) ) ) 430 { 431 if ( rInf.X() + aGuess.BreakWidth() <= rInf.Width() ) 432 Width( aGuess.BreakWidth() ); 433 else 434 // this actually should not happen 435 Width( KSHORT(rInf.Width() - rInf.X()) ); 436 437 SetLen( aGuess.BreakPos() - rInf.GetIdx() ); 438 439 ASSERT( aGuess.BreakStart() >= aGuess.FieldDiff(), 440 "Trouble with expanded field portions during line break" ); 441 const xub_StrLen nRealStart = aGuess.BreakStart() - aGuess.FieldDiff(); 442 if( aGuess.BreakPos() < nRealStart && !InExpGrp() ) 443 { 444 SwHolePortion *pNew = new SwHolePortion( *this ); 445 pNew->SetLen( nRealStart - aGuess.BreakPos() ); 446 Insert( pNew ); 447 } 448 } 449 else // case C2, last exit 450 BreakCut( rInf, aGuess ); 451 } 452 // breakPos < index or no breakpos at all 453 else 454 { 455 sal_Bool bFirstPor = rInf.GetLineStart() == rInf.GetIdx(); 456 if( aGuess.BreakPos() != STRING_LEN && 457 aGuess.BreakPos() != rInf.GetLineStart() && 458 ( !bFirstPor || rInf.GetFly() || rInf.GetLast()->IsFlyPortion() || 459 rInf.IsFirstMulti() ) && 460 ( !rInf.GetLast()->IsBlankPortion() || ((SwBlankPortion*) 461 rInf.GetLast())->MayUnderFlow( rInf, rInf.GetIdx()-1, sal_True ))) 462 { // case C1 (former BreakUnderflow()) 463 BreakUnderflow( rInf ); 464 } 465 else 466 // case C2, last exit 467 BreakCut( rInf, aGuess ); 468 } 469 470 return bFull; 471 } 472 473 /************************************************************************* 474 * virtual SwTxtPortion::Format() 475 *************************************************************************/ 476 477 478 479 sal_Bool SwTxtPortion::Format( SwTxtFormatInfo &rInf ) 480 { 481 #if OSL_DEBUG_LEVEL > 1 482 const XubString aDbgTxt( rInf.GetTxt().Copy( rInf.GetIdx(), rInf.GetLen() ) ); 483 #endif 484 485 if( rInf.X() > rInf.Width() || (!GetLen() && !InExpGrp()) ) 486 { 487 Height( 0 ); 488 Width( 0 ); 489 SetLen( 0 ); 490 SetAscent( 0 ); 491 SetPortion( NULL ); // ???? 492 return sal_True; 493 } 494 495 ASSERT( rInf.RealWidth() || (rInf.X() == rInf.Width()), 496 "SwTxtPortion::Format: missing real width" ); 497 ASSERT( Height(), "SwTxtPortion::Format: missing height" ); 498 499 return _Format( rInf ); 500 } 501 502 /************************************************************************* 503 * virtual SwTxtPortion::FormatEOL() 504 *************************************************************************/ 505 506 // Format end of line 507 // 5083: Es kann schon manchmal unguenstige Faelle geben... 508 // "vom {Nikolaus}", Nikolaus bricht um "vom " wird im Blocksatz 509 // zu "vom" und " ", wobei der Glue expandiert wird, statt in die 510 // MarginPortion aufzugehen. 511 // rInf.nIdx steht auf dem naechsten Wort, nIdx-1 ist der letzte 512 // Buchstabe der Portion. 513 514 515 516 void SwTxtPortion::FormatEOL( SwTxtFormatInfo &rInf ) 517 { 518 if( ( !GetPortion() || ( GetPortion()->IsKernPortion() && 519 !GetPortion()->GetPortion() ) ) && GetLen() && 520 rInf.GetIdx() < rInf.GetTxt().Len() && 521 1 < rInf.GetIdx() && ' ' == rInf.GetChar( rInf.GetIdx() - 1 ) 522 && !rInf.GetLast()->IsHolePortion() ) 523 { 524 // calculate number of blanks 525 xub_StrLen nX = rInf.GetIdx() - 1; 526 sal_uInt16 nHoleLen = 1; 527 while( nX && nHoleLen < GetLen() && CH_BLANK == rInf.GetChar( --nX ) ) 528 nHoleLen++; 529 530 // Erst uns einstellen und dann Inserten, weil wir ja auch ein 531 // SwLineLayout sein koennten. 532 KSHORT nBlankSize; 533 if( nHoleLen == GetLen() ) 534 nBlankSize = Width(); 535 else 536 nBlankSize = nHoleLen * rInf.GetTxtSize( ' ' ).Width(); 537 Width( Width() - nBlankSize ); 538 rInf.X( rInf.X() - nBlankSize ); 539 SetLen( GetLen() - nHoleLen ); 540 SwLinePortion *pHole = new SwHolePortion( *this ); 541 ( (SwHolePortion *)pHole )->SetBlankWidth( nBlankSize ); 542 ( (SwHolePortion *)pHole )->SetLen( nHoleLen ); 543 Insert( pHole ); 544 } 545 } 546 547 /************************************************************************* 548 * virtual SwTxtPortion::GetCrsrOfst() 549 *************************************************************************/ 550 551 552 553 xub_StrLen SwTxtPortion::GetCrsrOfst( const KSHORT nOfst ) const 554 { 555 ASSERT( !this, "SwTxtPortion::GetCrsrOfst: don't use this method!" ); 556 return SwLinePortion::GetCrsrOfst( nOfst ); 557 } 558 559 /************************************************************************* 560 * virtual SwTxtPortion::GetTxtSize() 561 *************************************************************************/ 562 // Das GetTxtSize() geht davon aus, dass die eigene Laenge korrekt ist 563 564 SwPosSize SwTxtPortion::GetTxtSize( const SwTxtSizeInfo &rInf ) const 565 { 566 return rInf.GetTxtSize(); 567 } 568 569 /************************************************************************* 570 * virtual SwTxtPortion::Paint() 571 *************************************************************************/ 572 573 574 575 void SwTxtPortion::Paint( const SwTxtPaintInfo &rInf ) const 576 { 577 if (rInf.OnWin() && 1==rInf.GetLen() && CH_TXT_ATR_FIELDEND==rInf.GetTxt().GetChar(rInf.GetIdx())) 578 { 579 rInf.DrawBackBrush( *this ); 580 const XubString aTxt = XubString::CreateFromAscii(CH_TXT_ATR_SUBST_FIELDEND); 581 rInf.DrawText( aTxt, *this, 0, aTxt.Len(), false ); 582 } 583 else if (rInf.OnWin() && 1==rInf.GetLen() && CH_TXT_ATR_FIELDSTART==rInf.GetTxt().GetChar(rInf.GetIdx())) 584 { 585 rInf.DrawBackBrush( *this ); 586 const XubString aTxt = XubString::CreateFromAscii(CH_TXT_ATR_SUBST_FIELDSTART); 587 rInf.DrawText( aTxt, *this, 0, aTxt.Len(), false ); 588 } 589 else if( GetLen() ) 590 { 591 rInf.DrawBackBrush( *this ); 592 593 // do we have to repaint a post it portion? 594 if( rInf.OnWin() && pPortion && !pPortion->Width() ) 595 pPortion->PrePaint( rInf, this ); 596 597 const SwWrongList *pWrongList = rInf.GetpWrongList(); 598 const SwWrongList *pGrammarCheckList = rInf.GetGrammarCheckList(); 599 // SMARTTAGS 600 const SwWrongList *pSmarttags = rInf.GetSmartTags(); 601 602 const bool bWrong = 0 != pWrongList; 603 const bool bGrammarCheck = 0 != pGrammarCheckList; 604 const bool bSmartTags = 0 != pSmarttags; 605 606 if ( bWrong || bSmartTags || bGrammarCheck ) 607 rInf.DrawMarkedText( *this, rInf.GetLen(), sal_False, bWrong, bSmartTags, bGrammarCheck ); 608 else 609 rInf.DrawText( *this, rInf.GetLen(), sal_False ); 610 } 611 } 612 613 /************************************************************************* 614 * virtual SwTxtPortion::GetExpTxt() 615 *************************************************************************/ 616 617 618 619 sal_Bool SwTxtPortion::GetExpTxt( const SwTxtSizeInfo &, XubString & ) const 620 { 621 return sal_False; 622 } 623 624 /************************************************************************* 625 * xub_StrLen SwTxtPortion::GetSpaceCnt() 626 * long SwTxtPortion::CalcSpacing() 627 * sind fuer den Blocksatz zustaendig und ermitteln die Anzahl der Blanks 628 * und den daraus resultierenden zusaetzlichen Zwischenraum 629 *************************************************************************/ 630 631 xub_StrLen SwTxtPortion::GetSpaceCnt( const SwTxtSizeInfo &rInf, 632 xub_StrLen& rCharCnt ) const 633 { 634 xub_StrLen nCnt = 0; 635 xub_StrLen nPos = 0; 636 if ( InExpGrp() ) 637 { 638 if( !IsBlankPortion() && !InNumberGrp() && !IsCombinedPortion() ) 639 { 640 // Bei OnWin() wird anstatt eines Leerstrings gern mal ein Blank 641 // zurueckgeliefert, das koennen wir hier aber gar nicht gebrauchen 642 sal_Bool bOldOnWin = rInf.OnWin(); 643 ((SwTxtSizeInfo &)rInf).SetOnWin( sal_False ); 644 645 XubString aStr( aEmptyStr ); 646 GetExpTxt( rInf, aStr ); 647 ((SwTxtSizeInfo &)rInf).SetOnWin( bOldOnWin ); 648 649 nCnt = nCnt + lcl_AddSpace( rInf, &aStr, *this ); 650 nPos = aStr.Len(); 651 } 652 } 653 else if( !IsDropPortion() ) 654 { 655 nCnt = nCnt + lcl_AddSpace( rInf, 0, *this ); 656 nPos = GetLen(); 657 } 658 rCharCnt = rCharCnt + nPos; 659 return nCnt; 660 } 661 662 long SwTxtPortion::CalcSpacing( long nSpaceAdd, const SwTxtSizeInfo &rInf ) const 663 { 664 xub_StrLen nCnt = 0; 665 666 if ( InExpGrp() ) 667 { 668 if( !IsBlankPortion() && !InNumberGrp() && !IsCombinedPortion() ) 669 { 670 // Bei OnWin() wird anstatt eines Leerstrings gern mal ein Blank 671 // zurueckgeliefert, das koennen wir hier aber gar nicht gebrauchen 672 sal_Bool bOldOnWin = rInf.OnWin(); 673 ((SwTxtSizeInfo &)rInf).SetOnWin( sal_False ); 674 675 XubString aStr( aEmptyStr ); 676 GetExpTxt( rInf, aStr ); 677 ((SwTxtSizeInfo &)rInf).SetOnWin( bOldOnWin ); 678 if( nSpaceAdd > 0 ) 679 nCnt = nCnt + lcl_AddSpace( rInf, &aStr, *this ); 680 else 681 { 682 nSpaceAdd = -nSpaceAdd; 683 nCnt = aStr.Len(); 684 } 685 } 686 } 687 else if( !IsDropPortion() ) 688 { 689 if( nSpaceAdd > 0 ) 690 nCnt = nCnt + lcl_AddSpace( rInf, 0, *this ); 691 else 692 { 693 nSpaceAdd = -nSpaceAdd; 694 nCnt = GetLen(); 695 SwLinePortion* pPor = GetPortion(); 696 697 // we do not want an extra space in front of margin portions 698 if ( nCnt ) 699 { 700 while ( pPor && !pPor->Width() && ! pPor->IsHolePortion() ) 701 pPor = pPor->GetPortion(); 702 703 if ( !pPor || pPor->InFixMargGrp() || pPor->IsHolePortion() ) 704 --nCnt; 705 } 706 } 707 } 708 709 return nCnt * nSpaceAdd / SPACING_PRECISION_FACTOR; 710 } 711 712 /************************************************************************* 713 * virtual SwTxtPortion::HandlePortion() 714 *************************************************************************/ 715 716 void SwTxtPortion::HandlePortion( SwPortionHandler& rPH ) const 717 { 718 rPH.Text( GetLen(), GetWhichPor() ); 719 } 720 721 /************************************************************************* 722 * class SwHolePortion 723 *************************************************************************/ 724 725 726 727 SwHolePortion::SwHolePortion( const SwTxtPortion &rPor ) 728 : nBlankWidth( 0 ) 729 { 730 SetLen( 1 ); 731 Height( rPor.Height() ); 732 SetAscent( rPor.GetAscent() ); 733 SetWhichPor( POR_HOLE ); 734 } 735 736 SwLinePortion *SwHolePortion::Compress() { return this; } 737 738 /************************************************************************* 739 * virtual SwHolePortion::Paint() 740 *************************************************************************/ 741 742 743 744 void SwHolePortion::Paint( const SwTxtPaintInfo &rInf ) const 745 { 746 // --> FME 2004-06-24 #i16816# tagged pdf support 747 if( rInf.GetVsh() && rInf.GetVsh()->GetViewOptions()->IsPDFExport() ) 748 { 749 const XubString aTxt( ' ' ); 750 rInf.DrawText( aTxt, *this, 0, 1, false ); 751 } 752 // <-- 753 } 754 755 /************************************************************************* 756 * virtual SwHolePortion::Format() 757 *************************************************************************/ 758 759 760 761 sal_Bool SwHolePortion::Format( SwTxtFormatInfo &rInf ) 762 { 763 return rInf.IsFull() || rInf.X() >= rInf.Width(); 764 } 765 766 /************************************************************************* 767 * virtual SwHolePortion::HandlePortion() 768 *************************************************************************/ 769 770 void SwHolePortion::HandlePortion( SwPortionHandler& rPH ) const 771 { 772 rPH.Text( GetLen(), GetWhichPor() ); 773 } 774 775 void SwFieldMarkPortion::Paint( const SwTxtPaintInfo & /*rInf*/) const 776 { 777 // These shouldn't be painted! 778 // SwTxtPortion::Paint(rInf); 779 } 780 781 sal_Bool SwFieldMarkPortion::Format( SwTxtFormatInfo & ) 782 { 783 sal_Bool ret=0; 784 Width(0); 785 return ret; 786 } 787 788 namespace { 789 static sal_Int32 getCurrentListIndex( IFieldmark* pBM, 790 ::rtl::OUString* io_pCurrentText = NULL ) 791 { 792 const IFieldmark::parameter_map_t* const pParameters = pBM->GetParameters(); 793 sal_Int32 nCurrentIdx = 0; 794 const IFieldmark::parameter_map_t::const_iterator pResult = pParameters->find(::rtl::OUString::createFromAscii(ODF_FORMDROPDOWN_RESULT)); 795 if(pResult != pParameters->end()) 796 pResult->second >>= nCurrentIdx; 797 if(io_pCurrentText) 798 { 799 const IFieldmark::parameter_map_t::const_iterator pListEntries = pParameters->find(::rtl::OUString::createFromAscii(ODF_FORMDROPDOWN_LISTENTRY)); 800 if(pListEntries != pParameters->end()) 801 { 802 uno::Sequence< ::rtl::OUString > vListEntries; 803 pListEntries->second >>= vListEntries; 804 if(nCurrentIdx < vListEntries.getLength()) 805 *io_pCurrentText = vListEntries[nCurrentIdx]; 806 } 807 } 808 return nCurrentIdx; 809 } 810 } 811 812 //FIXME Fieldbk 813 void SwFieldFormPortion::Paint( const SwTxtPaintInfo& rInf ) const 814 { 815 SwTxtNode* pNd = const_cast<SwTxtNode*>(rInf.GetTxtFrm()->GetTxtNode()); 816 const SwDoc *doc=pNd->GetDoc(); 817 SwIndex aIndex( pNd, rInf.GetIdx() ); 818 SwPosition aPosition(*pNd, aIndex); 819 820 IFieldmark* pBM = doc->getIDocumentMarkAccess( )->getFieldmarkFor( aPosition ); 821 822 OSL_ENSURE( pBM, 823 "SwFieldFormPortion::Paint(..)" 824 " - Where is my form field bookmark???"); 825 826 if ( pBM != NULL ) 827 { 828 if ( pBM->GetFieldname( ).equalsAscii( ODF_FORMCHECKBOX ) ) 829 { // a checkbox... 830 ICheckboxFieldmark* pCheckboxFm = dynamic_cast< ICheckboxFieldmark* >(pBM); 831 bool checked = pCheckboxFm->IsChecked(); 832 rInf.DrawCheckBox(*this, checked); 833 } 834 else if ( pBM->GetFieldname( ).equalsAscii( ODF_FORMDROPDOWN ) ) 835 { // a list... 836 rtl::OUString aTxt; 837 rInf.DrawViewOpt( *this, POR_FLD ); 838 rInf.DrawText( aTxt, *this, 0, 0/*aTxt.getLength()*/, false ); 839 } 840 else 841 { 842 assert(0); // unknown type... 843 } 844 } 845 } 846 847 sal_Bool SwFieldFormPortion::Format( SwTxtFormatInfo & rInf ) 848 { 849 sal_Bool ret = 0; 850 SwTxtNode *pNd = const_cast < SwTxtNode * >( rInf.GetTxtFrm( )->GetTxtNode( ) ); 851 const SwDoc *doc = pNd->GetDoc( ); 852 SwIndex aIndex( pNd, rInf.GetIdx( ) ); 853 SwPosition aPosition( *pNd, aIndex ); 854 IFieldmark *pBM = doc->getIDocumentMarkAccess( )->getFieldmarkFor( aPosition ); 855 ASSERT( pBM != NULL, "Where is my form field bookmark???" ); 856 if ( pBM != NULL ) 857 { 858 if ( pBM->GetFieldname( ).equalsAscii( ODF_FORMCHECKBOX ) ) 859 { 860 Width( rInf.GetTxtHeight( ) ); 861 Height( rInf.GetTxtHeight( ) ); 862 SetAscent( rInf.GetAscent( ) ); 863 } 864 else if ( pBM->GetFieldname( ).equalsAscii( ODF_FORMDROPDOWN ) ) 865 { 866 ::rtl::OUString aTxt; 867 getCurrentListIndex( pBM, &aTxt ); 868 SwPosSize aPosSize = rInf.GetTxtSize( aTxt ); 869 Width( aPosSize.Width( ) ); 870 Height( aPosSize.Height( ) ); 871 SetAscent( rInf.GetAscent( ) ); 872 } 873 else 874 { 875 assert( 0 ); // unknown type... 876 } 877 } 878 return ret; 879 } 880 881 882