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