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 <fmtfld.hxx> 34 #include <txtfld.hxx> 35 #include <charfmt.hxx> 36 37 #include "viewsh.hxx" // NewFldPortion, GetDoc() 38 #include "doc.hxx" // NewFldPortion, GetSysFldType() 39 #include "rootfrm.hxx" // Info ueber virt. PageNumber 40 #include "pagefrm.hxx" // NewFldPortion, GetVirtPageNum() 41 #include "ndtxt.hxx" // NewNumberPortion, pHints->GetNum() 42 #include "fldbas.hxx" // SwField 43 #include "viewopt.hxx" // SwViewOptions 44 #include "flyfrm.hxx" //IsInBody() 45 #include "viewimp.hxx" 46 #include "txtatr.hxx" // SwTxtFld 47 #include "txtcfg.hxx" 48 #include "swfont.hxx" // NewFldPortion, new SwFont 49 #include "fntcache.hxx" // NewFldPortion, SwFntAccess 50 #include "porfld.hxx" 51 #include "porftn.hxx" // NewExtraPortion 52 #include "porref.hxx" // NewExtraPortion 53 #include "portox.hxx" // NewExtraPortion 54 #include "porhyph.hxx" // NewExtraPortion 55 #include "porfly.hxx" // NewExtraPortion 56 #include "itrform2.hxx" // SwTxtFormatter 57 #include "chpfld.hxx" 58 #include "dbfld.hxx" 59 #include "expfld.hxx" 60 #include "docufld.hxx" 61 #include "pagedesc.hxx" // NewFldPortion, GetNum() 62 #include <pormulti.hxx> // SwMultiPortion 63 #include "fmtmeta.hxx" // lcl_NewMetaPortion 64 65 66 /************************************************************************* 67 * SwTxtFormatter::NewFldPortion() 68 *************************************************************************/ 69 70 71 sal_Bool lcl_IsInBody( SwFrm *pFrm ) 72 { 73 if ( pFrm->IsInDocBody() ) 74 return sal_True; 75 else 76 { 77 const SwFrm *pTmp = pFrm; 78 const SwFlyFrm *pFly; 79 while ( 0 != (pFly = pTmp->FindFlyFrm()) ) 80 pTmp = pFly->GetAnchorFrm(); 81 return pTmp->IsInDocBody(); 82 } 83 } 84 85 86 SwExpandPortion *SwTxtFormatter::NewFldPortion( SwTxtFormatInfo &rInf, 87 const SwTxtAttr *pHint ) const 88 { 89 SwExpandPortion *pRet = 0; 90 SwFrm *pFrame = (SwFrm*)pFrm; 91 SwField *pFld = (SwField*)pHint->GetFld().GetFld(); 92 const sal_Bool bName = rInf.GetOpt().IsFldName(); 93 94 SwCharFmt* pChFmt = 0; 95 sal_Bool bNewFlyPor = sal_False, 96 bINet = sal_False; 97 98 // set language 99 ((SwTxtFormatter*)this)->SeekAndChg( rInf ); 100 if (pFld->GetLanguage() != GetFnt()->GetLanguage()) 101 { 102 pFld->SetLanguage( GetFnt()->GetLanguage() ); 103 // let the visual note know about its new language 104 if (pFld->GetTyp()->Which()==RES_POSTITFLD) 105 const_cast<SwFmtFld*> (&pHint->GetFld())->Broadcast( SwFmtFldHint( &pHint->GetFld(), SWFMTFLD_LANGUAGE ) ); 106 } 107 108 ViewShell *pSh = rInf.GetVsh(); 109 SwDoc *const pDoc( (pSh) ? pSh->GetDoc() : 0 ); 110 bool const bInClipboard( (pDoc) ? pDoc->IsClipBoard() : true ); 111 sal_Bool bPlaceHolder = sal_False; 112 113 switch( pFld->GetTyp()->Which() ) 114 { 115 case RES_SCRIPTFLD: 116 case RES_POSTITFLD: 117 pRet = new SwPostItsPortion( RES_SCRIPTFLD == pFld->GetTyp()->Which() ); 118 break; 119 120 case RES_COMBINED_CHARS: 121 { 122 if( bName ) 123 { 124 String const sName( pFld->GetFieldName() ); 125 pRet = new SwFldPortion(sName); 126 } 127 else 128 { 129 String const sContent( pFld->ExpandField(bInClipboard) ); 130 pRet = new SwCombinedPortion(sContent); 131 } 132 } 133 break; 134 135 case RES_HIDDENTXTFLD: 136 { 137 String const str( (bName) 138 ? pFld->GetFieldName() 139 : pFld->ExpandField(bInClipboard) ); 140 pRet = new SwHiddenPortion(str); 141 } 142 break; 143 144 case RES_CHAPTERFLD: 145 if( !bName && pSh && !pSh->Imp()->IsUpdateExpFlds() ) 146 { 147 ((SwChapterField*)pFld)->ChangeExpansion( pFrame, 148 &((SwTxtFld*)pHint)->GetTxtNode() ); 149 } 150 { 151 String const str( (bName) 152 ? pFld->GetFieldName() 153 : pFld->ExpandField(bInClipboard) ); 154 pRet = new SwFldPortion( str ); 155 } 156 break; 157 158 case RES_DOCSTATFLD: 159 if( !bName && pSh && !pSh->Imp()->IsUpdateExpFlds() ) 160 { 161 ((SwDocStatField*)pFld)->ChangeExpansion( pFrame ); 162 } 163 { 164 String const str( (bName) 165 ? pFld->GetFieldName() 166 : pFld->ExpandField(bInClipboard) ); 167 pRet = new SwFldPortion( str ); 168 } 169 break; 170 171 case RES_PAGENUMBERFLD: 172 { 173 if( !bName && pSh && pSh->GetLayout() && !pSh->Imp()->IsUpdateExpFlds() )//swmod 080122 174 { 175 SwPageNumberFieldType *pPageNr = (SwPageNumberFieldType *)pFld->GetTyp(); 176 177 const SwRootFrm* pTmpRootFrm = pSh->GetLayout(); 178 const sal_Bool bVirt = pTmpRootFrm->IsVirtPageNum(); 179 180 MSHORT nVirtNum = pFrame->GetVirtPageNum(); 181 MSHORT nNumPages = pTmpRootFrm->GetPageNum(); 182 sal_Int16 nNumFmt = -1; 183 if(SVX_NUM_PAGEDESC == pFld->GetFormat()) 184 nNumFmt = pFrame->FindPageFrm()->GetPageDesc()->GetNumType().GetNumberingType(); 185 186 pPageNr->ChangeExpansion( pDoc, nVirtNum, nNumPages, 187 bVirt, nNumFmt > -1 ? &nNumFmt : 0); 188 } 189 { 190 String const str( (bName) 191 ? pFld->GetFieldName() 192 : pFld->ExpandField(bInClipboard) ); 193 pRet = new SwFldPortion( str ); 194 } 195 break; 196 } 197 case RES_GETEXPFLD: 198 { 199 if( !bName && pSh && !pSh->Imp()->IsUpdateExpFlds() ) 200 { 201 SwGetExpField* pExpFld = (SwGetExpField*)pFld; 202 if( !::lcl_IsInBody( pFrame ) ) 203 { 204 pExpFld->ChgBodyTxtFlag( sal_False ); 205 pExpFld->ChangeExpansion( *pFrame, *((SwTxtFld*)pHint) ); 206 } 207 else if( !pExpFld->IsInBodyTxt() ) 208 { 209 // war vorher anders, also erst expandieren, dann umsetzen!! 210 pExpFld->ChangeExpansion( *pFrame, *((SwTxtFld*)pHint) ); 211 pExpFld->ChgBodyTxtFlag( sal_True ); 212 } 213 } 214 { 215 String const str( (bName) 216 ? pFld->GetFieldName() 217 : pFld->ExpandField(bInClipboard) ); 218 pRet = new SwFldPortion( str ); 219 } 220 break; 221 } 222 case RES_DBFLD: 223 { 224 if( !bName ) 225 { 226 SwDBField* pDBFld = (SwDBField*)pFld; 227 pDBFld->ChgBodyTxtFlag( ::lcl_IsInBody( pFrame ) ); 228 /* Solange das ChangeExpansion auskommentiert ist. 229 * Aktualisieren in Kopf/Fuszeilen geht aktuell nicht. 230 if( !::lcl_IsInBody( pFrame ) ) 231 { 232 pDBFld->ChgBodyTxtFlag( sal_False ); 233 pDBFld->ChangeExpansion( pFrame, (SwTxtFld*)pHint ); 234 } 235 else if( !pDBFld->IsInBodyTxt() ) 236 { 237 // war vorher anders, also erst expandieren, dann umsetzen!! 238 pDBFld->ChangeExpansion( pFrame, (SwTxtFld*)pHint ); 239 pDBFld->ChgBodyTxtFlag( sal_True ); 240 } 241 */ 242 } 243 { 244 String const str( (bName) 245 ? pFld->GetFieldName() 246 : pFld->ExpandField(bInClipboard) ); 247 pRet = new SwFldPortion(str); 248 } 249 break; 250 } 251 case RES_REFPAGEGETFLD: 252 if( !bName && pSh && !pSh->Imp()->IsUpdateExpFlds() ) 253 { 254 ((SwRefPageGetField*)pFld)->ChangeExpansion( pFrame, (SwTxtFld*)pHint ); 255 } 256 { 257 String const str( (bName) 258 ? pFld->GetFieldName() 259 : pFld->ExpandField(bInClipboard) ); 260 pRet = new SwFldPortion(str); 261 } 262 break; 263 264 case RES_JUMPEDITFLD: 265 if( !bName ) 266 pChFmt = ((SwJumpEditField*)pFld)->GetCharFmt(); 267 bNewFlyPor = sal_True; 268 bPlaceHolder = sal_True; 269 break; 270 271 default: 272 { 273 String const str( (bName) 274 ? pFld->GetFieldName() 275 : pFld->ExpandField(bInClipboard) ); 276 pRet = new SwFldPortion(str); 277 } 278 } 279 280 if( bNewFlyPor ) 281 { 282 SwFont *pTmpFnt = 0; 283 if( !bName ) 284 { 285 pTmpFnt = new SwFont( *pFnt ); 286 if( bINet ) 287 { 288 SwAttrPool* pPool = pChFmt->GetAttrSet().GetPool(); 289 SfxItemSet aSet( *pPool, RES_CHRATR_BEGIN, RES_CHRATR_END ); 290 SfxItemSet aTmpSet( aSet ); 291 pFrm->GetTxtNode()->GetAttr(aSet,rInf.GetIdx(),rInf.GetIdx()+1); 292 aTmpSet.Set( pChFmt->GetAttrSet() ); 293 aTmpSet.Differentiate( aSet ); 294 if( aTmpSet.Count() ) 295 pTmpFnt->SetDiffFnt( &aTmpSet, pFrm->GetTxtNode()->getIDocumentSettingAccess() ); 296 } 297 else 298 pTmpFnt->SetDiffFnt( &pChFmt->GetAttrSet(), pFrm->GetTxtNode()->getIDocumentSettingAccess() ); 299 } 300 { 301 String const str( (bName) 302 ? pFld->GetFieldName() 303 : pFld->ExpandField(bInClipboard) ); 304 pRet = new SwFldPortion(str, pTmpFnt, bPlaceHolder); 305 } 306 } 307 308 return pRet; 309 } 310 311 /************************************************************************* 312 * SwTxtFormatter::TryNewNoLengthPortion() 313 *************************************************************************/ 314 315 SwFldPortion * lcl_NewMetaPortion(SwTxtAttr & rHint, const bool bPrefix) 316 { 317 ::sw::Meta *const pMeta( 318 static_cast<SwFmtMeta &>(rHint.GetAttr()).GetMeta() ); 319 ::rtl::OUString fix; 320 ::sw::MetaField *const pField( dynamic_cast< ::sw::MetaField * >(pMeta) ); 321 OSL_ENSURE(pField, "lcl_NewMetaPortion: no meta field?"); 322 if (pField) 323 { 324 pField->GetPrefixAndSuffix((bPrefix) ? &fix : 0, (bPrefix) ? 0 : &fix); 325 } 326 return new SwFldPortion( fix ); 327 } 328 329 /** Try to create a new portion with zero length, for an end of a hint 330 (where there is no CH_TXTATR). Because there may be multiple hint ends at a 331 given index, m_nHintEndIndex is used to keep track of the already created 332 portions. But the portions created here may actually be deleted again, 333 due to UnderFlow. In that case, m_nHintEndIndex must be decremented, 334 so the portion will be created again on the next line. 335 */ 336 SwExpandPortion * 337 SwTxtFormatter::TryNewNoLengthPortion(SwTxtFormatInfo & rInfo) 338 { 339 if (pHints) 340 { 341 const xub_StrLen nIdx(rInfo.GetIdx()); 342 while (m_nHintEndIndex < pHints->GetEndCount()) 343 { 344 SwTxtAttr & rHint( *pHints->GetEnd(m_nHintEndIndex) ); 345 xub_StrLen const nEnd( *rHint.GetAnyEnd() ); 346 if (nEnd > nIdx) 347 { 348 break; 349 } 350 ++m_nHintEndIndex; 351 if (nEnd == nIdx) 352 { 353 if (RES_TXTATR_METAFIELD == rHint.Which()) 354 { 355 SwFldPortion *const pPortion( 356 lcl_NewMetaPortion(rHint, false)); 357 pPortion->SetNoLength(); // no CH_TXTATR at hint end! 358 return pPortion; 359 } 360 } 361 } 362 } 363 return 0; 364 } 365 366 /************************************************************************* 367 * SwTxtFormatter::NewExtraPortion() 368 *************************************************************************/ 369 370 SwLinePortion *SwTxtFormatter::NewExtraPortion( SwTxtFormatInfo &rInf ) 371 { 372 SwTxtAttr *pHint = GetAttr( rInf.GetIdx() ); 373 SwLinePortion *pRet = 0; 374 if( !pHint ) 375 { 376 #if OSL_DEBUG_LEVEL > 1 377 // aDbstream << "NewExtraPortion: hint not found?" << endl; 378 #endif 379 pRet = new SwTxtPortion; 380 pRet->SetLen( 1 ); 381 rInf.SetLen( 1 ); 382 return pRet; 383 } 384 385 switch( pHint->Which() ) 386 { 387 case RES_TXTATR_FLYCNT : 388 { 389 pRet = NewFlyCntPortion( rInf, pHint ); 390 break; 391 } 392 case RES_TXTATR_FTN : 393 { 394 pRet = NewFtnPortion( rInf, pHint ); 395 break; 396 } 397 case RES_TXTATR_FIELD : 398 { 399 pRet = NewFldPortion( rInf, pHint ); 400 break; 401 } 402 case RES_TXTATR_REFMARK : 403 { 404 pRet = new SwIsoRefPortion; 405 break; 406 } 407 case RES_TXTATR_TOXMARK : 408 { 409 pRet = new SwIsoToxPortion; 410 break; 411 } 412 case RES_TXTATR_METAFIELD: 413 { 414 pRet = lcl_NewMetaPortion( *pHint, true ); 415 break; 416 } 417 default: ; 418 } 419 if( !pRet ) 420 { 421 #if OSL_DEBUG_LEVEL > 1 422 // aDbstream << "NewExtraPortion: unknown hint" << endl; 423 #endif 424 const XubString aNothing; 425 pRet = new SwFldPortion( aNothing ); 426 rInf.SetLen( 1 ); 427 } 428 return pRet; 429 } 430 431 /************************************************************************* 432 * SwTxtFormatter::NewNumberPortion() 433 *************************************************************************/ 434 435 436 SwNumberPortion *SwTxtFormatter::NewNumberPortion( SwTxtFormatInfo &rInf ) const 437 { 438 if( rInf.IsNumDone() || rInf.GetTxtStart() != nStart 439 || rInf.GetTxtStart() != rInf.GetIdx() ) 440 return 0; 441 442 SwNumberPortion *pRet = 0; 443 const SwTxtNode* pTxtNd = GetTxtFrm()->GetTxtNode(); 444 const SwNumRule* pNumRule = pTxtNd->GetNumRule(); 445 446 // hat ein "gueltige" Nummer ? 447 if( pTxtNd->IsNumbered() && pTxtNd->IsCountedInList()) 448 { 449 const SwNumFmt &rNumFmt = pNumRule->Get( static_cast<sal_uInt16>(pTxtNd->GetActualListLevel()) ); 450 const sal_Bool bLeft = SVX_ADJUST_LEFT == rNumFmt.GetNumAdjust(); 451 const sal_Bool bCenter = SVX_ADJUST_CENTER == rNumFmt.GetNumAdjust(); 452 // --> OD 2008-01-23 #newlistlevelattrs# 453 const bool bLabelAlignmentPosAndSpaceModeActive( 454 rNumFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT ); 455 const KSHORT nMinDist = bLabelAlignmentPosAndSpaceModeActive 456 ? 0 : rNumFmt.GetCharTextDistance(); 457 // <-- 458 459 if( SVX_NUM_BITMAP == rNumFmt.GetNumberingType() ) 460 { 461 // --> OD 2008-01-23 #newlistlevelattrs# 462 pRet = new SwGrfNumPortion( (SwFrm*)GetTxtFrm(), 463 pTxtNd->GetLabelFollowedBy(), 464 rNumFmt.GetBrush(), 465 rNumFmt.GetGraphicOrientation(), 466 rNumFmt.GetGraphicSize(), 467 bLeft, bCenter, nMinDist, 468 bLabelAlignmentPosAndSpaceModeActive ); 469 // <-- 470 long nTmpA = rInf.GetLast()->GetAscent(); 471 long nTmpD = rInf.GetLast()->Height() - nTmpA; 472 if( !rInf.IsTest() ) 473 ((SwGrfNumPortion*)pRet)->SetBase( nTmpA, nTmpD, nTmpA, nTmpD ); 474 } 475 else 476 { 477 // Der SwFont wird dynamisch angelegt und im CTOR uebergeben, 478 // weil das CharFmt nur einen SV-Font zurueckliefert. 479 // Im Dtor vom SwNumberPortion wird der SwFont deletet. 480 SwFont *pNumFnt = 0; 481 const SwAttrSet* pFmt = rNumFmt.GetCharFmt() ? 482 &rNumFmt.GetCharFmt()->GetAttrSet() : 483 NULL; 484 const IDocumentSettingAccess* pIDSA = pTxtNd->getIDocumentSettingAccess(); 485 486 if( SVX_NUM_CHAR_SPECIAL == rNumFmt.GetNumberingType() ) 487 { 488 const Font *pFmtFnt = rNumFmt.GetBulletFont(); 489 490 // 491 // Build a new bullet font basing on the current paragraph font: 492 // 493 pNumFnt = new SwFont( &rInf.GetCharAttr(), pIDSA ); 494 495 // --> FME 2005-08-11 #i53199# 496 if ( !pIDSA->get(IDocumentSettingAccess::DO_NOT_RESET_PARA_ATTRS_FOR_NUM_FONT) ) 497 { 498 // i18463: 499 // Underline style of paragraph font should not be considered 500 // Overline style of paragraph font should not be considered 501 // Weight style of paragraph font should not be considered 502 // Posture style of paragraph font should not be considered 503 pNumFnt->SetUnderline( UNDERLINE_NONE ); 504 pNumFnt->SetOverline( UNDERLINE_NONE ); 505 pNumFnt->SetItalic( ITALIC_NONE, SW_LATIN ); 506 pNumFnt->SetItalic( ITALIC_NONE, SW_CJK ); 507 pNumFnt->SetItalic( ITALIC_NONE, SW_CTL ); 508 pNumFnt->SetWeight( WEIGHT_NORMAL, SW_LATIN ); 509 pNumFnt->SetWeight( WEIGHT_NORMAL, SW_CJK ); 510 pNumFnt->SetWeight( WEIGHT_NORMAL, SW_CTL ); 511 } 512 513 // 514 // Apply the explicit attributes from the character style 515 // associated with the numering to the new bullet font. 516 // 517 if( pFmt ) 518 pNumFnt->SetDiffFnt( pFmt, pIDSA ); 519 520 if ( pFmtFnt ) 521 { 522 const sal_uInt8 nAct = pNumFnt->GetActual(); 523 pNumFnt->SetFamily( pFmtFnt->GetFamily(), nAct ); 524 pNumFnt->SetName( pFmtFnt->GetName(), nAct ); 525 pNumFnt->SetStyleName( pFmtFnt->GetStyleName(), nAct ); 526 pNumFnt->SetCharSet( pFmtFnt->GetCharSet(), nAct ); 527 pNumFnt->SetPitch( pFmtFnt->GetPitch(), nAct ); 528 } 529 530 // we do not allow a vertical font 531 pNumFnt->SetVertical( pNumFnt->GetOrientation(), 532 pFrm->IsVertical() ); 533 534 // --> OD 2008-01-23 #newlistelevelattrs# 535 pRet = new SwBulletPortion( rNumFmt.GetBulletChar(), 536 pTxtNd->GetLabelFollowedBy(), 537 pNumFnt, 538 bLeft, bCenter, nMinDist, 539 bLabelAlignmentPosAndSpaceModeActive ); 540 // <-- 541 } 542 else 543 { 544 XubString aTxt( pTxtNd->GetNumString() ); 545 // --> OD 2008-01-23 #newlistlevelattrs# 546 if ( aTxt.Len() > 0 ) 547 { 548 aTxt.Insert( pTxtNd->GetLabelFollowedBy() ); 549 } 550 // <-- 551 552 // 7974: Nicht nur eine Optimierung... 553 // Eine Numberportion ohne Text wird die Breite von 0 554 // erhalten. Die nachfolgende Textportion wird im BreakLine 555 // in das BreakCut laufen, obwohl rInf.GetLast()->GetFlyPortion() 556 // vorliegt! 557 if( aTxt.Len() ) 558 { 559 // 560 // Build a new numbering font basing on the current paragraph font: 561 // 562 pNumFnt = new SwFont( &rInf.GetCharAttr(), pIDSA ); 563 564 // --> FME 2005-08-11 #i53199# 565 if ( !pIDSA->get(IDocumentSettingAccess::DO_NOT_RESET_PARA_ATTRS_FOR_NUM_FONT) ) 566 { 567 // i18463: 568 // Underline style of paragraph font should not be considered 569 pNumFnt->SetUnderline( UNDERLINE_NONE ); 570 // Overline style of paragraph font should not be considered 571 pNumFnt->SetOverline( UNDERLINE_NONE ); 572 } 573 574 575 // 576 // Apply the explicit attributes from the character style 577 // associated with the numering to the new bullet font. 578 // 579 if( pFmt ) 580 pNumFnt->SetDiffFnt( pFmt, pIDSA ); 581 582 // we do not allow a vertical font 583 pNumFnt->SetVertical( pNumFnt->GetOrientation(), pFrm->IsVertical() ); 584 585 // --> OD 2008-01-23 #newlistlevelattrs# 586 pRet = new SwNumberPortion( aTxt, pNumFnt, 587 bLeft, bCenter, nMinDist, 588 bLabelAlignmentPosAndSpaceModeActive ); 589 // <-- 590 } 591 } 592 } 593 } 594 return pRet; 595 } 596 597