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 #include "viewsh.hxx" 31 #include "doc.hxx" 32 #include "pagefrm.hxx" 33 #include "rootfrm.hxx" 34 #include "ndtxt.hxx" 35 #include "txtatr.hxx" 36 #include <SwPortionHandler.hxx> 37 #include <txtftn.hxx> 38 #include <flyfrm.hxx> 39 #include <fmtftn.hxx> 40 #include <ftninfo.hxx> 41 #include <charfmt.hxx> 42 #include <dflyobj.hxx> 43 #include <rowfrm.hxx> 44 #include <editeng/brshitem.hxx> 45 #include <editeng/charrotateitem.hxx> 46 #include <breakit.hxx> 47 #ifndef _COM_SUN_STAR_I18N_SCRIPTTYPE_HDL_ 48 #include <com/sun/star/i18n/ScriptType.hdl> 49 #endif 50 #include <tabfrm.hxx> 51 // OD 2004-05-24 #i28701# 52 #include <sortedobjs.hxx> 53 54 #include "txtcfg.hxx" 55 #include "swfont.hxx" // new SwFont 56 #include "porftn.hxx" 57 #include "porfly.hxx" 58 #include "porlay.hxx" 59 #include "txtfrm.hxx" 60 #include "itrform2.hxx" 61 #include "ftnfrm.hxx" // FindQuoVadisFrm(), 62 #include "pagedesc.hxx" 63 #include "redlnitr.hxx" // SwRedlnItr 64 #include "sectfrm.hxx" // SwSectionFrm 65 #include "layouter.hxx" // Endnote-Collection 66 #include "frmtool.hxx" 67 #include "ndindex.hxx" 68 69 using namespace ::com::sun::star; 70 71 /************************************************************************* 72 * _IsFtnNumFrm() 73 *************************************************************************/ 74 75 sal_Bool SwTxtFrm::_IsFtnNumFrm() const 76 { 77 const SwFtnFrm* pFtn = FindFtnFrm()->GetMaster(); 78 while( pFtn && !pFtn->ContainsCntnt() ) 79 pFtn = pFtn->GetMaster(); 80 return !pFtn; 81 } 82 83 /************************************************************************* 84 * FindFtn() 85 *************************************************************************/ 86 87 // Sucht innerhalb einer Master-Follow-Kette den richtigen TxtFrm zum SwTxtFtn 88 89 SwTxtFrm *SwTxtFrm::FindFtnRef( const SwTxtFtn *pFtn ) 90 { 91 SwTxtFrm *pFrm = this; 92 const sal_Bool bFwd = *pFtn->GetStart() >= GetOfst(); 93 while( pFrm ) 94 { 95 if( SwFtnBossFrm::FindFtn( pFrm, pFtn ) ) 96 return pFrm; 97 pFrm = bFwd ? pFrm->GetFollow() : 98 pFrm->IsFollow() ? pFrm->FindMaster() : 0; 99 } 100 return pFrm; 101 } 102 103 /************************************************************************* 104 * CalcFtnFlag() 105 *************************************************************************/ 106 107 #ifndef DBG_UTIL 108 void SwTxtFrm::CalcFtnFlag() 109 #else 110 void SwTxtFrm::CalcFtnFlag( xub_StrLen nStop )//Fuer den Test von SplitFrm 111 #endif 112 { 113 bFtn = sal_False; 114 115 const SwpHints *pHints = GetTxtNode()->GetpSwpHints(); 116 if( !pHints ) 117 return; 118 119 const sal_uInt16 nSize = pHints->Count(); 120 121 #ifndef DBG_UTIL 122 const xub_StrLen nEnd = GetFollow() ? GetFollow()->GetOfst() : STRING_LEN; 123 #else 124 const xub_StrLen nEnd = nStop != STRING_LEN ? nStop 125 : GetFollow() ? GetFollow()->GetOfst() : STRING_LEN; 126 #endif 127 128 for ( sal_uInt16 i = 0; i < nSize; ++i ) 129 { 130 const SwTxtAttr *pHt = (*pHints)[i]; 131 if ( pHt->Which() == RES_TXTATR_FTN ) 132 { 133 const xub_StrLen nIdx = *pHt->GetStart(); 134 if ( nEnd < nIdx ) 135 break; 136 if( GetOfst() <= nIdx ) 137 { 138 bFtn = sal_True; 139 break; 140 } 141 } 142 } 143 } 144 145 /************************************************************************* 146 * CalcPrepFtnAdjust() 147 *************************************************************************/ 148 149 sal_Bool SwTxtFrm::CalcPrepFtnAdjust() 150 { 151 ASSERT( HasFtn(), "Wer ruft mich da?" ); 152 SwFtnBossFrm *pBoss = FindFtnBossFrm( sal_True ); 153 const SwFtnFrm *pFtn = pBoss->FindFirstFtn( this ); 154 if( pFtn && FTNPOS_CHAPTER != GetNode()->GetDoc()->GetFtnInfo().ePos && 155 ( !pBoss->GetUpper()->IsSctFrm() || 156 !((SwSectionFrm*)pBoss->GetUpper())->IsFtnAtEnd() ) ) 157 { 158 const SwFtnContFrm *pCont = pBoss->FindFtnCont(); 159 sal_Bool bReArrange = sal_True; 160 161 SWRECTFN( this ) 162 if ( pCont && (*fnRect->fnYDiff)( (pCont->Frm().*fnRect->fnGetTop)(), 163 (Frm().*fnRect->fnGetBottom)() ) > 0 ) 164 { 165 pBoss->RearrangeFtns( (Frm().*fnRect->fnGetBottom)(), sal_False, 166 pFtn->GetAttr() ); 167 ValidateBodyFrm(); 168 ValidateFrm(); 169 pFtn = pBoss->FindFirstFtn( this ); 170 } 171 else 172 bReArrange = sal_False; 173 if( !pCont || !pFtn || bReArrange != (pFtn->FindFtnBossFrm() == pBoss) ) 174 { 175 SwTxtFormatInfo aInf( this ); 176 SwTxtFormatter aLine( this, &aInf ); 177 aLine.TruncLines(); 178 SetPara( 0 ); //Wird ggf. geloescht! 179 ResetPreps(); 180 return sal_False; 181 } 182 } 183 return sal_True; 184 } 185 186 187 /************************************************************************* 188 * lcl_GetFtnLower() 189 * 190 * Local helper function. Checks if nLower should be taken as the boundary 191 * for the footnote. 192 *************************************************************************/ 193 194 SwTwips lcl_GetFtnLower( const SwTxtFrm* pFrm, SwTwips nLower ) 195 { 196 // nLower is an absolute value. It denotes the bottom of the line 197 // containing the footnote. 198 SWRECTFN( pFrm ) 199 200 ASSERT( !pFrm->IsVertical() || !pFrm->IsSwapped(), 201 "lcl_GetFtnLower with swapped frame" ); 202 203 SwTwips nAdd; 204 SwTwips nRet = nLower; 205 206 // 207 // Check if text is inside a table. 208 // 209 if ( pFrm->IsInTab() ) 210 { 211 // 212 // If pFrm is inside a table, we have to check if 213 // a) The table is not allowed to split or 214 // b) The table row is not allowed to split 215 // 216 // Inside a table, there are no footnotes, 217 // see SwFrm::FindFtnBossFrm. So we don't have to check 218 // the case that pFrm is inside a (footnote collecting) section 219 // within the table. 220 // 221 const SwFrm* pRow = pFrm; 222 while( !pRow->IsRowFrm() || !pRow->GetUpper()->IsTabFrm() ) 223 pRow = pRow->GetUpper(); 224 const SwTabFrm* pTabFrm = (SwTabFrm*)pRow->GetUpper(); 225 226 ASSERT( pTabFrm && pRow && 227 pRow->GetUpper()->IsTabFrm(), "Upper of row should be tab" ) 228 229 const sal_Bool bDontSplit = !pTabFrm->IsFollow() && 230 !pTabFrm->IsLayoutSplitAllowed(); 231 232 SwTwips nMin = 0; 233 if ( bDontSplit ) 234 nMin = (pTabFrm->Frm().*fnRect->fnGetBottom)(); 235 else if ( !((SwRowFrm*)pRow)->IsRowSplitAllowed() ) 236 nMin = (pRow->Frm().*fnRect->fnGetBottom)(); 237 238 if ( nMin && (*fnRect->fnYDiff)( nMin, nLower ) > 0 ) 239 nRet = nMin; 240 241 nAdd = (pRow->GetUpper()->*fnRect->fnGetBottomMargin)(); 242 } 243 else 244 nAdd = (pFrm->*fnRect->fnGetBottomMargin)(); 245 246 if( nAdd > 0 ) 247 { 248 if ( bVert ) 249 nRet -= nAdd; 250 else 251 nRet += nAdd; 252 } 253 254 // #i10770#: If there are fly frames anchored at previous paragraphs, 255 // the deadline should consider their lower borders. 256 const SwFrm* pStartFrm = pFrm->GetUpper()->GetLower(); 257 ASSERT( pStartFrm, "Upper has no lower" ) 258 SwTwips nFlyLower = bVert ? LONG_MAX : 0; 259 while ( pStartFrm != pFrm ) 260 { 261 ASSERT( pStartFrm, "Frame chain is broken" ) 262 if ( pStartFrm->GetDrawObjs() ) 263 { 264 const SwSortedObjs &rObjs = *pStartFrm->GetDrawObjs(); 265 for ( sal_uInt16 i = 0; i < rObjs.Count(); ++i ) 266 { 267 SwAnchoredObject* pAnchoredObj = rObjs[i]; 268 SwRect aRect( pAnchoredObj->GetObjRect() ); 269 270 if ( !pAnchoredObj->ISA(SwFlyFrm) || 271 static_cast<SwFlyFrm*>(pAnchoredObj)->IsValid() ) 272 { 273 const SwTwips nBottom = (aRect.*fnRect->fnGetBottom)(); 274 if ( (*fnRect->fnYDiff)( nBottom, nFlyLower ) > 0 ) 275 nFlyLower = nBottom; 276 } 277 } 278 } 279 280 pStartFrm = pStartFrm->GetNext(); 281 } 282 283 if ( bVert ) 284 nRet = Min( nRet, nFlyLower ); 285 else 286 nRet = Max( nRet, nFlyLower ); 287 288 return nRet; 289 } 290 291 292 /************************************************************************* 293 * SwTxtFrm::GetFtnLine() 294 *************************************************************************/ 295 296 SwTwips SwTxtFrm::GetFtnLine( const SwTxtFtn *pFtn ) const 297 { 298 ASSERT( ! IsVertical() || ! IsSwapped(), 299 "SwTxtFrm::GetFtnLine with swapped frame" ) 300 301 SwTxtFrm *pThis = (SwTxtFrm*)this; 302 303 if( !HasPara() ) 304 { 305 // #109071# GetFormatted() does not work here, bacause most probably 306 // the frame is currently locked. We return the previous value. 307 return pThis->mnFtnLine > 0 ? 308 pThis->mnFtnLine : 309 IsVertical() ? Frm().Left() : Frm().Bottom(); 310 } 311 312 SWAP_IF_NOT_SWAPPED( this ) 313 314 SwTxtInfo aInf( pThis ); 315 SwTxtIter aLine( pThis, &aInf ); 316 const xub_StrLen nPos = *pFtn->GetStart(); 317 aLine.CharToLine( nPos ); 318 319 SwTwips nRet = aLine.Y() + SwTwips(aLine.GetLineHeight()); 320 if( IsVertical() ) 321 nRet = SwitchHorizontalToVertical( nRet ); 322 323 UNDO_SWAP( this ) 324 325 nRet = lcl_GetFtnLower( pThis, nRet ); 326 327 pThis->mnFtnLine = nRet; 328 return nRet; 329 } 330 331 /************************************************************************* 332 * SwTxtFrm::GetFtnRstHeight() 333 *************************************************************************/ 334 335 // Ermittelt die max. erreichbare Hoehe des TxtFrm im Ftn-Bereich. 336 // Sie wird eingeschraenkt durch den unteren Rand der Zeile mit 337 // der Ftn-Referenz. 338 339 SwTwips SwTxtFrm::_GetFtnFrmHeight() const 340 { 341 ASSERT( !IsFollow() && IsInFtn(), "SwTxtFrm::SetFtnLine: moon walk" ); 342 343 const SwFtnFrm *pFtnFrm = FindFtnFrm(); 344 const SwTxtFrm *pRef = (const SwTxtFrm *)pFtnFrm->GetRef(); 345 const SwFtnBossFrm *pBoss = FindFtnBossFrm(); 346 if( pBoss != pRef->FindFtnBossFrm( !pFtnFrm->GetAttr()-> 347 GetFtn().IsEndNote() ) ) 348 return 0; 349 350 SWAP_IF_SWAPPED( this ) 351 352 SwTwips nHeight = pRef->IsInFtnConnect() ? 353 1 : pRef->GetFtnLine( pFtnFrm->GetAttr() ); 354 if( nHeight ) 355 { 356 // So komisch es aussehen mag: Die erste Ftn auf der Seite darf sich 357 // nicht mit der Ftn-Referenz beruehren, wenn wir im Ftn-Bereich Text 358 // eingeben. 359 const SwFrm *pCont = pFtnFrm->GetUpper(); 360 //Hoehe innerhalb des Cont, die ich mir 'eh noch genehmigen darf. 361 SWRECTFN( pCont ) 362 SwTwips nTmp = (*fnRect->fnYDiff)( (pCont->*fnRect->fnGetPrtBottom)(), 363 (Frm().*fnRect->fnGetTop)() ); 364 365 #ifdef DBG_UTIL 366 if( nTmp < 0 ) 367 { 368 sal_Bool bInvalidPos = sal_False; 369 const SwLayoutFrm* pTmp = GetUpper(); 370 while( !bInvalidPos && pTmp ) 371 { 372 bInvalidPos = !pTmp->GetValidPosFlag() || 373 !pTmp->Lower()->GetValidPosFlag(); 374 if( pTmp == pCont ) 375 break; 376 pTmp = pTmp->GetUpper(); 377 } 378 ASSERT( bInvalidPos, "Hanging below FtnCont" ); 379 } 380 #endif 381 382 if ( (*fnRect->fnYDiff)( (pCont->Frm().*fnRect->fnGetTop)(), nHeight) > 0 ) 383 { 384 //Wachstumspotential den Containers. 385 if ( !pRef->IsInFtnConnect() ) 386 { 387 SwSaveFtnHeight aSave( (SwFtnBossFrm*)pBoss, nHeight ); 388 nHeight = ((SwFtnContFrm*)pCont)->Grow( LONG_MAX, sal_True ); 389 } 390 else 391 nHeight = ((SwFtnContFrm*)pCont)->Grow( LONG_MAX, sal_True ); 392 393 nHeight += nTmp; 394 if( nHeight < 0 ) 395 nHeight = 0; 396 } 397 else 398 { // The container has to shrink 399 nTmp += (*fnRect->fnYDiff)( (pCont->Frm().*fnRect->fnGetTop)(), nHeight); 400 if( nTmp > 0 ) 401 nHeight = nTmp; 402 else 403 nHeight = 0; 404 } 405 } 406 407 UNDO_SWAP( this ) 408 409 return nHeight; 410 } 411 412 /************************************************************************* 413 * SwTxtFrm::FindQuoVadisFrm() 414 *************************************************************************/ 415 416 SwTxtFrm *SwTxtFrm::FindQuoVadisFrm() 417 { 418 // Erstmal feststellen, ob wir in einem FtnFrm stehen: 419 if( GetIndPrev() || !IsInFtn() ) 420 return 0; 421 422 // Zum Vorgaenger-FtnFrm 423 SwFtnFrm *pFtnFrm = FindFtnFrm()->GetMaster(); 424 if( !pFtnFrm ) 425 return 0; 426 427 // Nun den letzten Cntnt: 428 const SwCntntFrm *pCnt = pFtnFrm->ContainsCntnt(); 429 if( !pCnt ) 430 return NULL; 431 const SwCntntFrm *pLast; 432 do 433 { pLast = pCnt; 434 pCnt = pCnt->GetNextCntntFrm(); 435 } while( pCnt && pFtnFrm->IsAnLower( pCnt ) ); 436 return (SwTxtFrm*)pLast; 437 } 438 439 /************************************************************************* 440 * SwTxtFrm::RemoveFtn() 441 *************************************************************************/ 442 443 void SwTxtFrm::RemoveFtn( const xub_StrLen nStart, const xub_StrLen nLen ) 444 { 445 if ( !IsFtnAllowed() ) 446 return; 447 448 SwpHints *pHints = GetTxtNode()->GetpSwpHints(); 449 if( !pHints ) 450 return; 451 452 sal_Bool bRollBack = nLen != STRING_LEN; 453 sal_uInt16 nSize = pHints->Count(); 454 xub_StrLen nEnd; 455 SwTxtFrm* pSource; 456 if( bRollBack ) 457 { 458 nEnd = nStart + nLen; 459 pSource = GetFollow(); 460 if( !pSource ) 461 return; 462 } 463 else 464 { 465 nEnd = STRING_LEN; 466 pSource = this; 467 } 468 469 if( nSize ) 470 { 471 SwPageFrm* pUpdate = NULL; 472 sal_Bool bRemove = sal_False; 473 SwFtnBossFrm *pFtnBoss = 0; 474 SwFtnBossFrm *pEndBoss = 0; 475 sal_Bool bFtnEndDoc 476 = FTNPOS_CHAPTER == GetNode()->GetDoc()->GetFtnInfo().ePos; 477 for ( sal_uInt16 i = nSize; i; ) 478 { 479 SwTxtAttr *pHt = pHints->GetTextHint(--i); 480 if ( RES_TXTATR_FTN != pHt->Which() ) 481 continue; 482 483 const xub_StrLen nIdx = *pHt->GetStart(); 484 if( nStart > nIdx ) 485 break; 486 487 if( nEnd >= nIdx ) 488 { 489 SwTxtFtn *pFtn = (SwTxtFtn*)pHt; 490 sal_Bool bEndn = pFtn->GetFtn().IsEndNote(); 491 492 if( bEndn ) 493 { 494 if( !pEndBoss ) 495 pEndBoss = pSource->FindFtnBossFrm(); 496 } 497 else 498 { 499 if( !pFtnBoss ) 500 { 501 pFtnBoss = pSource->FindFtnBossFrm( sal_True ); 502 if( pFtnBoss->GetUpper()->IsSctFrm() ) 503 { 504 SwSectionFrm* pSect = (SwSectionFrm*) 505 pFtnBoss->GetUpper(); 506 if( pSect->IsFtnAtEnd() ) 507 bFtnEndDoc = sal_False; 508 } 509 } 510 } 511 512 // Wir loeschen nicht, sondern wollen die Ftn verschieben. 513 // Drei Faelle koennen auftreten: 514 // 1) Es gibt weder Follow noch PrevFollow 515 // -> RemoveFtn() (vielleicht sogar ein ASSERT wert) 516 // 2) nStart > GetOfst, ich habe einen Follow 517 // -> Ftn wandert in den Follow 518 // 3) nStart < GetOfst, ich bin ein Follow 519 // -> Ftn wandert in den PrevFollow 520 // beide muessen auf einer Seite/in einer Spalte stehen. 521 522 SwFtnFrm *pFtnFrm = bEndn ? pEndBoss->FindFtn( pSource, pFtn ) : 523 pFtnBoss->FindFtn( pSource, pFtn ); 524 525 if( pFtnFrm ) 526 { 527 const sal_Bool bEndDoc = bEndn ? sal_True : bFtnEndDoc; 528 if( bRollBack ) 529 { 530 while ( pFtnFrm ) 531 { 532 pFtnFrm->SetRef( this ); 533 pFtnFrm = pFtnFrm->GetFollow(); 534 SetFtn( sal_True ); 535 } 536 } 537 else if( GetFollow() ) 538 { 539 SwCntntFrm *pDest = GetFollow(); 540 while( pDest->GetFollow() && ((SwTxtFrm*)pDest-> 541 GetFollow())->GetOfst() <= nIdx ) 542 pDest = pDest->GetFollow(); 543 ASSERT( !pDest->FindFtnBossFrm( !bEndn )->FindFtn( 544 pDest,pFtn),"SwTxtFrm::RemoveFtn: footnote exists"); 545 546 //Nicht ummelden sondern immer Moven. 547 // OD 08.11.2002 #104840# - use <SwlayoutFrm::IsBefore(::)> 548 if ( bEndDoc || 549 !pFtnFrm->FindFtnBossFrm()->IsBefore( pDest->FindFtnBossFrm( !bEndn ) ) 550 ) 551 { 552 SwPageFrm* pTmp = pFtnFrm->FindPageFrm(); 553 if( pUpdate && pUpdate != pTmp ) 554 pUpdate->UpdateFtnNum(); 555 pUpdate = pTmp; 556 while ( pFtnFrm ) 557 { 558 pFtnFrm->SetRef( pDest ); 559 pFtnFrm = pFtnFrm->GetFollow(); 560 } 561 } 562 else 563 { 564 if( bEndn ) 565 pEndBoss->MoveFtns( this, pDest, pFtn ); 566 else 567 pFtnBoss->MoveFtns( this, pDest, pFtn ); 568 bRemove = sal_True; 569 } 570 ((SwTxtFrm*)pDest)->SetFtn( sal_True ); 571 572 ASSERT( pDest->FindFtnBossFrm( !bEndn )->FindFtn( pDest, 573 pFtn),"SwTxtFrm::RemoveFtn: footnote ChgRef failed"); 574 } 575 else 576 { 577 if( !bEndDoc || ( bEndn && pEndBoss->IsInSct() && 578 !SwLayouter::Collecting( GetNode()->GetDoc(), 579 pEndBoss->FindSctFrm(), NULL ) ) ) 580 { 581 if( bEndn ) 582 pEndBoss->RemoveFtn( this, pFtn ); 583 else 584 pFtnBoss->RemoveFtn( this, pFtn ); 585 bRemove = bRemove || !bEndDoc; 586 ASSERT( bEndn ? !pEndBoss->FindFtn( this, pFtn ) : 587 !pFtnBoss->FindFtn( this, pFtn ), 588 "SwTxtFrm::RemoveFtn: can't get off that footnote" ); 589 } 590 } 591 } 592 } 593 } 594 if( pUpdate ) 595 pUpdate->UpdateFtnNum(); 596 // Wir bringen die Oszillation zum stehen: 597 if( bRemove && !bFtnEndDoc && HasPara() ) 598 { 599 ValidateBodyFrm(); 600 ValidateFrm(); 601 } 602 } 603 // Folgendes Problem: Aus dem FindBreak heraus wird das RemoveFtn aufgerufen, 604 // weil die letzte Zeile an den Follow abgegeben werden soll. Der Offset 605 // des Follows ist aber veraltet, er wird demnaechst gesetzt. CalcFntFlag ist 606 // auf einen richtigen Follow-Offset angewiesen. Deshalb wird hier kurzfristig 607 // der Follow-Offset manipuliert. 608 xub_StrLen nOldOfst = STRING_LEN; 609 if( HasFollow() && nStart > GetOfst() ) 610 { 611 nOldOfst = GetFollow()->GetOfst(); 612 GetFollow()->ManipOfst( nStart + ( bRollBack ? nLen : 0 ) ); 613 } 614 pSource->CalcFtnFlag(); 615 if( nOldOfst < STRING_LEN ) 616 GetFollow()->ManipOfst( nOldOfst ); 617 } 618 619 /************************************************************************* 620 * SwTxtFormatter::ConnectFtn() 621 *************************************************************************/ 622 // sal_False, wenn irgendetwas schief gegangen ist. 623 // Es gibt eigentlich nur zwei Moeglichkeiten: 624 // a) Die Ftn ist bereits vorhanden 625 // => dann wird sie gemoved, wenn ein anderer pSrcFrm gefunden wurde 626 // b) Die Ftn ist nicht vorhanden 627 // => dann wird sie fuer uns angelegt. 628 // Ob die Ftn schliesslich auf unserer Spalte/Seite landet oder nicht, 629 // spielt in diesem Zusammenhang keine Rolle. 630 // Optimierungen bei Endnoten. 631 // Noch ein Problem: wenn die Deadline im Ftn-Bereich liegt, muss die 632 // Ftn verschoben werden. 633 634 void SwTxtFrm::ConnectFtn( SwTxtFtn *pFtn, const SwTwips nDeadLine ) 635 { 636 ASSERT( !IsVertical() || !IsSwapped(), 637 "SwTxtFrm::ConnectFtn with swapped frame" ); 638 639 bFtn = sal_True; 640 bInFtnConnect = sal_True; //Bloss zuruecksetzen! 641 sal_Bool bEnd = pFtn->GetFtn().IsEndNote(); 642 643 // 644 // We want to store this value, because it is needed as a fallback 645 // in GetFtnLine(), if there is no paragraph information available 646 // 647 mnFtnLine = nDeadLine; 648 649 // Wir brauchen immer einen Boss (Spalte/Seite) 650 SwSectionFrm *pSect; 651 SwCntntFrm *pCntnt = this; 652 if( bEnd && IsInSct() ) 653 { 654 pSect = FindSctFrm(); 655 if( pSect->IsEndnAtEnd() ) 656 pCntnt = pSect->FindLastCntnt( FINDMODE_ENDNOTE ); 657 if( !pCntnt ) 658 pCntnt = this; 659 } 660 661 SwFtnBossFrm *pBoss = pCntnt->FindFtnBossFrm( !bEnd ); 662 663 #if OSL_DEBUG_LEVEL > 1 664 SwTwips nRstHeight = GetRstHeight(); 665 #endif 666 667 pSect = pBoss->FindSctFrm(); 668 sal_Bool bDocEnd = bEnd ? !( pSect && pSect->IsEndnAtEnd() ) : 669 ( !( pSect && pSect->IsFtnAtEnd() ) && 670 FTNPOS_CHAPTER == GetNode()->GetDoc()->GetFtnInfo().ePos ); 671 //Ftn kann beim Follow angemeldet sein. 672 SwCntntFrm *pSrcFrm = FindFtnRef( pFtn ); 673 674 if( bDocEnd ) 675 { 676 if( pSect && pSrcFrm ) 677 { 678 SwFtnFrm *pFtnFrm = pBoss->FindFtn( pSrcFrm, pFtn ); 679 if( pFtnFrm && pFtnFrm->IsInSct() ) 680 { 681 pBoss->RemoveFtn( pSrcFrm, pFtn ); 682 pSrcFrm = 0; 683 } 684 } 685 } 686 else if( bEnd && pSect ) 687 { 688 SwFtnFrm *pFtnFrm = pSrcFrm ? pBoss->FindFtn( pSrcFrm, pFtn ) : NULL; 689 if( pFtnFrm && !pFtnFrm->GetUpper() ) 690 pFtnFrm = NULL; 691 SwDoc *pDoc = GetNode()->GetDoc(); 692 if( SwLayouter::Collecting( pDoc, pSect, pFtnFrm ) ) 693 { 694 if( !pSrcFrm ) 695 { 696 SwFtnFrm *pNew = new SwFtnFrm(pDoc->GetDfltFrmFmt(),this,this,pFtn); 697 SwNodeIndex aIdx( *pFtn->GetStartNode(), 1 ); 698 ::_InsertCnt( pNew, pDoc, aIdx.GetIndex() ); 699 GetNode()->getIDocumentLayoutAccess()->GetLayouter()->CollectEndnote( pNew ); 700 } 701 else if( pSrcFrm != this ) 702 pBoss->ChangeFtnRef( pSrcFrm, pFtn, this ); 703 bInFtnConnect = sal_False; 704 return; 705 } 706 else if( pSrcFrm ) 707 { 708 SwFtnBossFrm *pFtnBoss = pFtnFrm->FindFtnBossFrm(); 709 if( !pFtnBoss->IsInSct() || 710 pFtnBoss->ImplFindSctFrm()->GetSection()!=pSect->GetSection() ) 711 { 712 pBoss->RemoveFtn( pSrcFrm, pFtn ); 713 pSrcFrm = 0; 714 } 715 } 716 } 717 718 if( bDocEnd || bEnd ) 719 { 720 if( !pSrcFrm ) 721 pBoss->AppendFtn( this, pFtn ); 722 else if( pSrcFrm != this ) 723 pBoss->ChangeFtnRef( pSrcFrm, pFtn, this ); 724 bInFtnConnect = sal_False; 725 return; 726 } 727 728 SwSaveFtnHeight aHeight( pBoss, nDeadLine ); 729 730 if( !pSrcFrm ) // Es wurde ueberhaupt keine Ftn gefunden. 731 pBoss->AppendFtn( this, pFtn ); 732 else 733 { 734 SwFtnFrm *pFtnFrm = pBoss->FindFtn( pSrcFrm, pFtn ); 735 SwFtnBossFrm *pFtnBoss = pFtnFrm->FindFtnBossFrm(); 736 737 sal_Bool bBrutal = sal_False; 738 739 if( pFtnBoss == pBoss ) // Ref und Ftn sind auf der selben Seite/Spalte. 740 { 741 SwFrm *pCont = pFtnFrm->GetUpper(); 742 743 SWRECTFN ( pCont ) 744 long nDiff = (*fnRect->fnYDiff)( (pCont->Frm().*fnRect->fnGetTop)(), 745 nDeadLine ); 746 747 if( nDiff >= 0 ) 748 { 749 //Wenn die Fussnote bei einem Follow angemeldet ist, so ist 750 //es jetzt an der Zeit sie umzumelden. 751 if ( pSrcFrm != this ) 752 pBoss->ChangeFtnRef( pSrcFrm, pFtn, this ); 753 //Es steht Platz zur Verfuegung, also kann die Fussnote evtl. 754 //wachsen. 755 if ( pFtnFrm->GetFollow() && nDiff > 0 ) 756 { 757 SwTwips nHeight = (pCont->Frm().*fnRect->fnGetHeight)(); 758 pBoss->RearrangeFtns( nDeadLine, sal_False, pFtn ); 759 ValidateBodyFrm(); 760 ValidateFrm(); 761 ViewShell *pSh = getRootFrm()->GetCurrShell(); 762 if ( pSh && nHeight == (pCont->Frm().*fnRect->fnGetHeight)() ) 763 //Damit uns nix durch die Lappen geht. 764 pSh->InvalidateWindows( pCont->Frm() ); 765 } 766 bInFtnConnect = sal_False; 767 return; 768 } 769 else 770 bBrutal = sal_True; 771 } 772 else 773 { 774 // Ref und Ftn sind nicht auf einer Seite, Move-Versuch ist noetig. 775 SwFrm* pTmp = this; 776 while( pTmp->GetNext() && pSrcFrm != pTmp ) 777 pTmp = pTmp->GetNext(); 778 if( pSrcFrm == pTmp ) 779 bBrutal = sal_True; 780 else 781 { // Wenn unser Boss in einem spaltigen Bereich sitzt, es aber auf 782 // der Seite schon einen FtnContainer gibt, hilft nur die brutale 783 // Methode 784 if( pSect && pSect->FindFtnBossFrm( !bEnd )->FindFtnCont() ) 785 bBrutal = sal_True; 786 // OD 08.11.2002 #104840# - use <SwLayoutFrm::IsBefore(..)> 787 else if ( !pFtnFrm->GetPrev() || 788 pFtnBoss->IsBefore( pBoss ) 789 ) 790 { 791 SwFtnBossFrm *pSrcBoss = pSrcFrm->FindFtnBossFrm( !bEnd ); 792 pSrcBoss->MoveFtns( pSrcFrm, this, pFtn ); 793 } 794 else 795 pBoss->ChangeFtnRef( pSrcFrm, pFtn, this ); 796 } 797 } 798 799 // Die brutale Loesung: Fussnote entfernen und appenden. 800 // Es muss SetFtnDeadLine() gerufen werden, weil nach 801 // RemoveFtn die nMaxFtnHeight evtl. besser auf unsere Wuensche 802 // eingestellt werden kann. 803 if( bBrutal ) 804 { 805 pBoss->RemoveFtn( pSrcFrm, pFtn, sal_False ); 806 SwSaveFtnHeight *pHeight = bEnd ? NULL : 807 new SwSaveFtnHeight( pBoss, nDeadLine ); 808 pBoss->AppendFtn( this, pFtn ); 809 delete pHeight; 810 } 811 } 812 813 // In spaltigen Bereichen, die noch nicht bis zum Seitenrand gehen, 814 // ist kein RearrangeFtns sinnvoll, da der Fussnotencontainer noch 815 // nicht kalkuliert worden ist. 816 if( !pSect || !pSect->Growable() ) 817 { 818 // Umgebung validieren, um Oszillationen zu verhindern. 819 SwSaveFtnHeight aNochmal( pBoss, nDeadLine ); 820 ValidateBodyFrm(); 821 pBoss->RearrangeFtns( nDeadLine, sal_True ); 822 ValidateFrm(); 823 } 824 else if( pSect->IsFtnAtEnd() ) 825 { 826 ValidateBodyFrm(); 827 ValidateFrm(); 828 } 829 830 #if OSL_DEBUG_LEVEL > 1 831 // pFtnFrm kann sich durch Calc veraendert haben ... 832 SwFtnFrm *pFtnFrm = pBoss->FindFtn( this, pFtn ); 833 if( pFtnFrm && pBoss != pFtnFrm->FindFtnBossFrm( !bEnd ) ) 834 { 835 int bla = 5; 836 (void)bla; 837 } 838 nRstHeight = GetRstHeight(); 839 #endif 840 bInFtnConnect = sal_False; 841 return; 842 } 843 844 845 846 /************************************************************************* 847 * SwTxtFormatter::NewFtnPortion() 848 *************************************************************************/ 849 850 // Die Portion fuer die Ftn-Referenz im Text 851 SwFtnPortion *SwTxtFormatter::NewFtnPortion( SwTxtFormatInfo &rInf, 852 SwTxtAttr *pHint ) 853 { 854 ASSERT( ! pFrm->IsVertical() || pFrm->IsSwapped(), 855 "NewFtnPortion with unswapped frame" ); 856 857 if( !pFrm->IsFtnAllowed() ) 858 return 0; 859 860 SwTxtFtn *pFtn = (SwTxtFtn*)pHint; 861 SwFmtFtn& rFtn = (SwFmtFtn&)pFtn->GetFtn(); 862 SwDoc *pDoc = pFrm->GetNode()->GetDoc(); 863 864 if( rInf.IsTest() ) 865 return new SwFtnPortion( rFtn.GetViewNumStr( *pDoc ), pFrm, pFtn ); 866 867 SWAP_IF_SWAPPED( pFrm ) 868 869 KSHORT nReal; 870 { 871 KSHORT nOldReal = pCurr->GetRealHeight(); 872 KSHORT nOldAscent = pCurr->GetAscent(); 873 KSHORT nOldHeight = pCurr->Height(); 874 ((SwTxtFormatter*)this)->CalcRealHeight(); 875 nReal = pCurr->GetRealHeight(); 876 if( nReal < nOldReal ) 877 nReal = nOldReal; 878 pCurr->SetRealHeight( nOldReal ); 879 pCurr->Height( nOldHeight ); 880 pCurr->SetAscent( nOldAscent ); 881 } 882 883 SwTwips nLower = Y() + nReal; 884 885 const bool bVertical = pFrm->IsVertical(); 886 if( bVertical ) 887 nLower = pFrm->SwitchHorizontalToVertical( nLower ); 888 889 nLower = lcl_GetFtnLower( pFrm, nLower ); 890 891 //6995: Wir frischen nur auf. Das Connect tut fuer diesen Fall nix 892 //Brauchbares, sondern wuerde stattdessen fuer diesen Fall meist die 893 //Ftn wegwerfen und neu erzeugen. 894 895 if( !rInf.IsQuick() ) 896 pFrm->ConnectFtn( pFtn, nLower ); 897 898 SwTxtFrm *pScrFrm = pFrm->FindFtnRef( pFtn ); 899 SwFtnBossFrm *pBoss = pFrm->FindFtnBossFrm( !rFtn.IsEndNote() ); 900 SwFtnFrm *pFtnFrm = NULL; 901 if( pScrFrm ) 902 pFtnFrm = pBoss->FindFtn( pScrFrm, pFtn ); 903 904 // Wir erkundigen uns, ob durch unser Append irgendeine 905 // Fussnote noch auf der Seite/Spalte steht. Wenn nicht verschwindet 906 // auch unsere Zeile. Dies fuehrt zu folgendem erwuenschten 907 // Verhalten: Ftn1 pass noch auf die Seite/Spalte, Ftn2 nicht mehr. 908 // Also bleibt die Ftn2-Referenz auf der Seite/Spalte stehen. Die 909 // Fussnote selbst folgt aber erst auf der naechsten Seite/Spalte. 910 // Ausnahme: Wenn keine weitere Zeile auf diese Seite/Spalte passt, 911 // so sollte die Ftn2-Referenz auch auf die naechste wandern. 912 if( !rFtn.IsEndNote() ) 913 { 914 SwSectionFrm *pSct = pBoss->FindSctFrm(); 915 sal_Bool bAtSctEnd = pSct && pSct->IsFtnAtEnd(); 916 if( FTNPOS_CHAPTER != pDoc->GetFtnInfo().ePos || bAtSctEnd ) 917 { 918 SwFrm* pFtnCont = pBoss->FindFtnCont(); 919 // Wenn der Boss in einem Bereich liegt, kann es sich nur um eine 920 // Spalte dieses Bereichs handeln. Wenn dies nicht die erste Spalte 921 // ist, duerfen wir ausweichen 922 if( !pFrm->IsInTab() && ( GetLineNr() > 1 || pFrm->GetPrev() || 923 ( !bAtSctEnd && pFrm->GetIndPrev() ) || 924 ( pSct && pBoss->GetPrev() ) ) ) 925 { 926 if( !pFtnCont ) 927 { 928 rInf.SetStop( sal_True ); 929 UNDO_SWAP( pFrm ) 930 return 0; 931 } 932 else 933 { 934 // Es darf keine Fussnotencontainer in spaltigen Bereichen und 935 // gleichzeitig auf der Seite/Seitenspalte geben 936 if( pSct && !bAtSctEnd ) // liegt unser Container in einem (spaltigen) Bereich? 937 { 938 SwFtnBossFrm* pTmp = pBoss->FindSctFrm()->FindFtnBossFrm( sal_True ); 939 SwFtnContFrm* pFtnC = pTmp->FindFtnCont(); 940 if( pFtnC ) 941 { 942 SwFtnFrm* pTmpFrm = (SwFtnFrm*)pFtnC->Lower(); 943 if( pTmpFrm && *pTmpFrm < pFtn ) 944 { 945 rInf.SetStop( sal_True ); 946 UNDO_SWAP( pFrm ) 947 return 0; 948 } 949 } 950 } 951 // Ist dies die letzte passende Zeile? 952 SwTwips nTmpBot = Y() + nReal * 2; 953 954 if( bVertical ) 955 nTmpBot = pFrm->SwitchHorizontalToVertical( nTmpBot ); 956 957 SWRECTFN( pFtnCont ) 958 959 const long nDiff = (*fnRect->fnYDiff)( 960 (pFtnCont->Frm().*fnRect->fnGetTop)(), 961 nTmpBot ); 962 963 if( pScrFrm && nDiff < 0 ) 964 { 965 if( pFtnFrm ) 966 { 967 SwFtnBossFrm *pFtnBoss = pFtnFrm->FindFtnBossFrm(); 968 if( pFtnBoss != pBoss ) 969 { 970 // Wir sind in der letzte Zeile und die Fussnote 971 // ist auf eine andere Seite gewandert, dann wollen 972 // wir mit ... 973 rInf.SetStop( sal_True ); 974 UNDO_SWAP( pFrm ) 975 return 0; 976 } 977 } 978 } 979 } 980 } 981 } 982 } 983 // Endlich: FtnPortion anlegen und raus hier... 984 SwFtnPortion *pRet = new SwFtnPortion( rFtn.GetViewNumStr( *pDoc ), 985 pFrm, pFtn, nReal ); 986 rInf.SetFtnInside( sal_True ); 987 988 UNDO_SWAP( pFrm ) 989 990 return pRet; 991 } 992 993 /************************************************************************* 994 * SwTxtFormatter::NewFtnNumPortion() 995 *************************************************************************/ 996 997 // Die Portion fuer die Ftn-Nummerierung im Ftn-Bereich 998 999 SwNumberPortion *SwTxtFormatter::NewFtnNumPortion( SwTxtFormatInfo &rInf ) const 1000 { 1001 ASSERT( pFrm->IsInFtn() && !pFrm->GetIndPrev() && !rInf.IsFtnDone(), 1002 "This is the wrong place for a ftnnumber" ); 1003 if( rInf.GetTxtStart() != nStart || 1004 rInf.GetTxtStart() != rInf.GetIdx() ) 1005 return 0; 1006 1007 const SwFtnFrm* pFtnFrm = pFrm->FindFtnFrm(); 1008 const SwTxtFtn* pFtn = pFtnFrm->GetAttr(); 1009 1010 // Aha, wir sind also im Fussnotenbereich 1011 SwFmtFtn& rFtn = (SwFmtFtn&)pFtn->GetFtn(); 1012 1013 SwDoc *pDoc = pFrm->GetNode()->GetDoc(); 1014 XubString aFtnTxt( rFtn.GetViewNumStr( *pDoc, sal_True )); 1015 1016 const SwEndNoteInfo* pInfo; 1017 if( rFtn.IsEndNote() ) 1018 pInfo = &pDoc->GetEndNoteInfo(); 1019 else 1020 pInfo = &pDoc->GetFtnInfo(); 1021 const SwAttrSet& rSet = pInfo->GetCharFmt(*pDoc)->GetAttrSet(); 1022 1023 const SwAttrSet* pParSet = &rInf.GetCharAttr(); 1024 const IDocumentSettingAccess* pIDSA = pFrm->GetTxtNode()->getIDocumentSettingAccess(); 1025 SwFont *pNumFnt = new SwFont( pParSet, pIDSA ); 1026 1027 // --> FME 2005-02-17 #i37142# 1028 // Underline style of paragraph font should not be considered 1029 // Overline style of paragraph font should not be considered 1030 // Weight style of paragraph font should not be considered 1031 // Posture style of paragraph font should not be considered 1032 // See also #i18463# and SwTxtFormatter::NewNumberPortion() 1033 pNumFnt->SetUnderline( UNDERLINE_NONE ); 1034 pNumFnt->SetOverline( UNDERLINE_NONE ); 1035 pNumFnt->SetItalic( ITALIC_NONE, SW_LATIN ); 1036 pNumFnt->SetItalic( ITALIC_NONE, SW_CJK ); 1037 pNumFnt->SetItalic( ITALIC_NONE, SW_CTL ); 1038 pNumFnt->SetWeight( WEIGHT_NORMAL, SW_LATIN ); 1039 pNumFnt->SetWeight( WEIGHT_NORMAL, SW_CJK ); 1040 pNumFnt->SetWeight( WEIGHT_NORMAL, SW_CTL ); 1041 // <-- 1042 1043 pNumFnt->SetDiffFnt(&rSet, pIDSA ); 1044 pNumFnt->SetVertical( pNumFnt->GetOrientation(), pFrm->IsVertical() ); 1045 1046 SwFtnNumPortion* pNewPor = new SwFtnNumPortion( aFtnTxt, pNumFnt ); 1047 pNewPor->SetLeft( !pFrm->IsRightToLeft() ); 1048 return pNewPor; 1049 } 1050 1051 /************************************************************************* 1052 * SwTxtFormatter::NewErgoSumPortion() 1053 *************************************************************************/ 1054 1055 XubString lcl_GetPageNumber( const SwPageFrm* pPage ) 1056 { 1057 ASSERT( pPage, "GetPageNumber: Homeless TxtFrm" ); 1058 MSHORT nVirtNum = pPage->GetVirtPageNum(); 1059 const SvxNumberType& rNum = pPage->GetPageDesc()->GetNumType(); 1060 return rNum.GetNumStr( nVirtNum ); 1061 } 1062 1063 SwErgoSumPortion *SwTxtFormatter::NewErgoSumPortion( SwTxtFormatInfo &rInf ) const 1064 { 1065 // Wir koennen nicht davon ausgehen, dass wir ein Follow sind 1066 // 7983: GetIdx() nicht nStart 1067 if( !pFrm->IsInFtn() || pFrm->GetPrev() || 1068 rInf.IsErgoDone() || rInf.GetIdx() != pFrm->GetOfst() || 1069 pFrm->ImplFindFtnFrm()->GetAttr()->GetFtn().IsEndNote() ) 1070 return 0; 1071 1072 // Aha, wir sind also im Fussnotenbereich 1073 const SwFtnInfo &rFtnInfo = pFrm->GetNode()->GetDoc()->GetFtnInfo(); 1074 SwTxtFrm *pQuoFrm = pFrm->FindQuoVadisFrm(); 1075 if( !pQuoFrm ) 1076 return 0; 1077 const SwPageFrm* pPage = pFrm->FindPageFrm(); 1078 const SwPageFrm* pQuoPage = pQuoFrm->FindPageFrm(); 1079 if( pPage == pQuoFrm->FindPageFrm() ) 1080 return 0; // Wenn der QuoVadis auf der selben (spaltigen) Seite steht 1081 const XubString aPage = lcl_GetPageNumber( pPage ); 1082 SwParaPortion *pPara = pQuoFrm->GetPara(); 1083 if( pPara ) 1084 pPara->SetErgoSumNum( aPage ); 1085 if( !rFtnInfo.aErgoSum.Len() ) 1086 return 0; 1087 SwErgoSumPortion *pErgo = new SwErgoSumPortion( rFtnInfo.aErgoSum, 1088 lcl_GetPageNumber( pQuoPage ) ); 1089 return pErgo; 1090 } 1091 1092 /************************************************************************* 1093 * SwTxtFormatter::FormatQuoVadis() 1094 *************************************************************************/ 1095 1096 xub_StrLen SwTxtFormatter::FormatQuoVadis( const xub_StrLen nOffset ) 1097 { 1098 ASSERT( ! pFrm->IsVertical() || ! pFrm->IsSwapped(), 1099 "SwTxtFormatter::FormatQuoVadis with swapped frame" ); 1100 1101 if( !pFrm->IsInFtn() || pFrm->ImplFindFtnFrm()->GetAttr()->GetFtn().IsEndNote() ) 1102 return nOffset; 1103 1104 const SwFrm* pErgoFrm = pFrm->FindFtnFrm()->GetFollow(); 1105 if( !pErgoFrm && pFrm->HasFollow() ) 1106 pErgoFrm = pFrm->GetFollow(); 1107 if( !pErgoFrm ) 1108 return nOffset; 1109 1110 if( pErgoFrm == pFrm->GetNext() ) 1111 { 1112 SwFrm *pCol = pFrm->FindColFrm(); 1113 while( pCol && !pCol->GetNext() ) 1114 pCol = pCol->GetUpper()->FindColFrm(); 1115 if( pCol ) 1116 return nOffset; 1117 } 1118 else 1119 { 1120 const SwPageFrm* pPage = pFrm->FindPageFrm(); 1121 const SwPageFrm* pErgoPage = pErgoFrm->FindPageFrm(); 1122 if( pPage == pErgoPage ) 1123 return nOffset; // Wenn der ErgoSum auf der selben Seite steht 1124 } 1125 1126 SwTxtFormatInfo &rInf = GetInfo(); 1127 const SwFtnInfo &rFtnInfo = pFrm->GetNode()->GetDoc()->GetFtnInfo(); 1128 if( !rFtnInfo.aQuoVadis.Len() ) 1129 return nOffset; 1130 1131 // Ein Wort zu QuoVadis/ErgoSum: 1132 // Fuer diese Texte wird der am Absatz eingestellte Font verwendet. 1133 // Wir initialisieren uns also: 1134 // ResetFont(); 1135 FeedInf( rInf ); 1136 SeekStartAndChg( rInf, sal_True ); 1137 if( GetRedln() && pCurr->HasRedline() ) 1138 GetRedln()->Seek( *pFnt, nOffset, 0 ); 1139 1140 // Ein fieser Sonderfall: Flyfrms reichen in die Zeile und stehen 1141 // natuerlich da, wo wir unseren Quovadis Text reinsetzen wollen. 1142 // Erst mal sehen, ob es so schlimm ist: 1143 SwLinePortion *pPor = pCurr->GetFirstPortion(); 1144 KSHORT nLastLeft = 0; 1145 while( pPor ) 1146 { 1147 if ( pPor->IsFlyPortion() ) 1148 nLastLeft = ( (SwFlyPortion*) pPor)->Fix() + 1149 ( (SwFlyPortion*) pPor)->Width(); 1150 pPor = pPor->GetPortion(); 1151 } 1152 // Das alte Spiel: wir wollen, dass die Zeile an einer bestimmten 1153 // Stelle umbricht, also beeinflussen wir die Width. 1154 // nLastLeft ist jetzt quasi der rechte Rand. 1155 const KSHORT nOldRealWidth = rInf.RealWidth(); 1156 rInf.RealWidth( nOldRealWidth - nLastLeft ); 1157 1158 XubString aErgo = lcl_GetPageNumber( pErgoFrm->FindPageFrm() ); 1159 SwQuoVadisPortion *pQuo = new SwQuoVadisPortion(rFtnInfo.aQuoVadis, aErgo ); 1160 pQuo->SetAscent( rInf.GetAscent() ); 1161 pQuo->Height( rInf.GetTxtHeight() ); 1162 pQuo->Format( rInf ); 1163 sal_uInt16 nQuoWidth = pQuo->Width(); 1164 SwLinePortion* pCurrPor = pQuo; 1165 1166 while ( rInf.GetRest() ) 1167 { 1168 SwLinePortion* pFollow = rInf.GetRest(); 1169 rInf.SetRest( 0 ); 1170 pCurrPor->Move( rInf ); 1171 1172 ASSERT( pFollow->IsQuoVadisPortion(), 1173 "Quo Vadis, rest of QuoVadisPortion" ) 1174 1175 // format the rest and append it to the other QuoVadis parts 1176 pFollow->Format( rInf ); 1177 nQuoWidth = nQuoWidth + pFollow->Width(); 1178 1179 pCurrPor->Append( pFollow ); 1180 pCurrPor = pFollow; 1181 } 1182 1183 nLastLeft = nOldRealWidth - nQuoWidth; 1184 Right( Right() - nQuoWidth ); 1185 1186 SWAP_IF_NOT_SWAPPED( pFrm ) 1187 1188 const xub_StrLen nRet = FormatLine( nStart ); 1189 1190 UNDO_SWAP( pFrm ) 1191 1192 Right( rInf.Left() + nOldRealWidth - 1 ); 1193 1194 nLastLeft = nOldRealWidth - pCurr->Width(); 1195 FeedInf( rInf ); 1196 1197 // Es kann durchaus sein, dass am Ende eine Marginportion steht, 1198 // die beim erneuten Aufspannen nur Aerger bereiten wuerde. 1199 pPor = pCurr->FindLastPortion(); 1200 SwGluePortion *pGlue = pPor->IsMarginPortion() ? 1201 (SwMarginPortion*) pPor : 0; 1202 if( pGlue ) 1203 { 1204 pGlue->Height( 0 ); 1205 pGlue->Width( 0 ); 1206 pGlue->SetLen( 0 ); 1207 pGlue->SetAscent( 0 ); 1208 pGlue->SetPortion( NULL ); 1209 pGlue->SetFixWidth(0); 1210 } 1211 1212 // Luxus: Wir sorgen durch das Aufspannen von Glues dafuer, 1213 // dass der QuoVadis-Text rechts erscheint: 1214 nLastLeft = nLastLeft - nQuoWidth; 1215 if( nLastLeft ) 1216 { 1217 if( nLastLeft > pQuo->GetAscent() ) // Mindestabstand 1218 { 1219 switch( GetAdjust() ) 1220 { 1221 case SVX_ADJUST_BLOCK: 1222 { 1223 if( !pCurr->GetLen() || 1224 CH_BREAK != GetInfo().GetChar(nStart+pCurr->GetLen()-1)) 1225 nLastLeft = pQuo->GetAscent(); 1226 nQuoWidth = nQuoWidth + nLastLeft; 1227 break; 1228 } 1229 case SVX_ADJUST_RIGHT: 1230 { 1231 nLastLeft = pQuo->GetAscent(); 1232 nQuoWidth = nQuoWidth + nLastLeft; 1233 break; 1234 } 1235 case SVX_ADJUST_CENTER: 1236 { 1237 nQuoWidth = nQuoWidth + pQuo->GetAscent(); 1238 long nDiff = nLastLeft - nQuoWidth; 1239 if( nDiff < 0 ) 1240 { 1241 nLastLeft = pQuo->GetAscent(); 1242 nQuoWidth = (sal_uInt16)(-nDiff + nLastLeft); 1243 } 1244 else 1245 { 1246 nQuoWidth = 0; 1247 nLastLeft = sal_uInt16(( pQuo->GetAscent() + nDiff ) / 2); 1248 } 1249 break; 1250 } 1251 default: 1252 nQuoWidth = nQuoWidth + nLastLeft; 1253 } 1254 } 1255 else 1256 nQuoWidth = nQuoWidth + nLastLeft; 1257 if( nLastLeft ) 1258 { 1259 pGlue = new SwGluePortion(0); 1260 pGlue->Width( nLastLeft ); 1261 pPor->Append( pGlue ); 1262 pPor = pPor->GetPortion(); 1263 } 1264 } 1265 1266 // Jetzt aber: die QuoVadis-Portion wird angedockt: 1267 pCurrPor = pQuo; 1268 while ( pCurrPor ) 1269 { 1270 // pPor->Append deletes the pPortoin pointer of pPor. Therefore 1271 // we have to keep a pointer to the next portion 1272 pQuo = (SwQuoVadisPortion*)pCurrPor->GetPortion(); 1273 pPor->Append( pCurrPor ); 1274 pPor = pPor->GetPortion(); 1275 pCurrPor = pQuo; 1276 } 1277 1278 pCurr->Width( pCurr->Width() + KSHORT( nQuoWidth ) ); 1279 1280 // Und noch einmal adjustieren wegen des Adjustment und nicht zu Letzt 1281 // wegen folgendem Sonderfall: In der Zeile hat der DummUser durchgaengig 1282 // einen kleineren Font eingestellt als der vom QuoVadis-Text ... 1283 CalcAdjustLine( pCurr ); 1284 1285 #if OSL_DEBUG_LEVEL > 1 1286 if( OPTDBG( rInf ) ) 1287 { 1288 // aDbstream << "FormatQuoVadis:" << endl; 1289 // pCurr->DebugPortions( aDbstream, rInf.GetTxt(), nStart ); 1290 } 1291 #endif 1292 1293 // Uff... 1294 return nRet; 1295 } 1296 1297 1298 /************************************************************************* 1299 * SwTxtFormatter::MakeDummyLine() 1300 *************************************************************************/ 1301 1302 // MakeDummyLine() erzeugt eine Line, die bis zum unteren Seitenrand 1303 // reicht. DummyLines bzw. DummyPortions sorgen dafuer, dass Oszillationen 1304 // zum stehen kommen, weil Rueckflussmoeglichkeiten genommen werden. 1305 // Sie werden bei absatzgebundenen Frames in Fussnoten und bei Ftn- 1306 // Oszillationen verwendet. 1307 1308 void SwTxtFormatter::MakeDummyLine() 1309 { 1310 KSHORT nRstHeight = GetFrmRstHeight(); 1311 if( pCurr && nRstHeight > pCurr->Height() ) 1312 { 1313 SwLineLayout *pLay = new SwLineLayout; 1314 nRstHeight = nRstHeight - pCurr->Height(); 1315 pLay->Height( nRstHeight ); 1316 pLay->SetAscent( nRstHeight ); 1317 Insert( pLay ); 1318 Next(); 1319 } 1320 } 1321 1322 /************************************************************************* 1323 * class SwFtnSave 1324 *************************************************************************/ 1325 class SwFtnSave 1326 { 1327 SwTxtSizeInfo *pInf; 1328 SwFont *pFnt; 1329 SwFont *pOld; 1330 public: 1331 SwFtnSave( const SwTxtSizeInfo &rInf, 1332 const SwTxtFtn *pTxtFtn, 1333 const bool bApplyGivenScriptType, 1334 const sal_uInt8 nGivenScriptType ); 1335 ~SwFtnSave(); 1336 }; 1337 1338 /************************************************************************* 1339 * SwFtnSave::SwFtnSave() 1340 *************************************************************************/ 1341 1342 SwFtnSave::SwFtnSave( const SwTxtSizeInfo &rInf, 1343 const SwTxtFtn* pTxtFtn, 1344 const bool bApplyGivenScriptType, 1345 const sal_uInt8 nGivenScriptType ) 1346 : pInf( &((SwTxtSizeInfo&)rInf) ) 1347 , pFnt( 0 ) 1348 , pOld( 0 ) 1349 { 1350 if( pTxtFtn && rInf.GetTxtFrm() ) 1351 { 1352 pFnt = ((SwTxtSizeInfo&)rInf).GetFont(); 1353 pOld = new SwFont( *pFnt ); 1354 pOld->GetTox() = pFnt->GetTox(); 1355 pFnt->GetTox() = 0; 1356 SwFmtFtn& rFtn = (SwFmtFtn&)pTxtFtn->GetFtn(); 1357 const SwDoc *pDoc = rInf.GetTxtFrm()->GetNode()->GetDoc(); 1358 1359 // --> OD 2009-01-29 #i98418# 1360 if ( bApplyGivenScriptType ) 1361 { 1362 pFnt->SetActual( nGivenScriptType ); 1363 } 1364 else 1365 { 1366 // examine text and set script 1367 String aTmpStr( rFtn.GetViewNumStr( *pDoc ) ); 1368 pFnt->SetActual( SwScriptInfo::WhichFont( 0, &aTmpStr, 0 ) ); 1369 } 1370 // <-- 1371 1372 const SwEndNoteInfo* pInfo; 1373 if( rFtn.IsEndNote() ) 1374 pInfo = &pDoc->GetEndNoteInfo(); 1375 else 1376 pInfo = &pDoc->GetFtnInfo(); 1377 const SwAttrSet& rSet = pInfo->GetAnchorCharFmt((SwDoc&)*pDoc)->GetAttrSet(); 1378 pFnt->SetDiffFnt( &rSet, rInf.GetTxtFrm()->GetNode()->getIDocumentSettingAccess() ); 1379 1380 // we reduce footnote size, if we are inside a double line portion 1381 if ( ! pOld->GetEscapement() && 50 == pOld->GetPropr() ) 1382 { 1383 Size aSize = pFnt->GetSize( pFnt->GetActual() ); 1384 pFnt->SetSize( Size( (long)aSize.Width() / 2, 1385 (long)aSize.Height() / 2 ), 1386 pFnt->GetActual() ); 1387 } 1388 1389 // set the correct rotation at the footnote font 1390 const SfxPoolItem* pItem; 1391 if( SFX_ITEM_SET == rSet.GetItemState( RES_CHRATR_ROTATE, 1392 sal_True, &pItem )) 1393 pFnt->SetVertical( ((SvxCharRotateItem*)pItem)->GetValue(), 1394 rInf.GetTxtFrm()->IsVertical() ); 1395 1396 pFnt->ChgPhysFnt( pInf->GetVsh(), *pInf->GetOut() ); 1397 1398 if( SFX_ITEM_SET == rSet.GetItemState( RES_CHRATR_BACKGROUND, 1399 sal_True, &pItem )) 1400 pFnt->SetBackColor( new Color( ((SvxBrushItem*)pItem)->GetColor() ) ); 1401 } 1402 else 1403 pFnt = NULL; 1404 } 1405 1406 /************************************************************************* 1407 * SwFtnSave::~SwFtnSave() 1408 *************************************************************************/ 1409 1410 SwFtnSave::~SwFtnSave() 1411 { 1412 if( pFnt ) 1413 { 1414 // SwFont zurueckstellen 1415 *pFnt = *pOld; 1416 pFnt->GetTox() = pOld->GetTox(); 1417 pFnt->ChgPhysFnt( pInf->GetVsh(), *pInf->GetOut() ); 1418 delete pOld; 1419 } 1420 } 1421 1422 /************************************************************************* 1423 * SwFtnPortion::SwFtnPortion() 1424 *************************************************************************/ 1425 1426 SwFtnPortion::SwFtnPortion( const XubString &rExpand, SwTxtFrm *pFrame, 1427 SwTxtFtn *pFootn, KSHORT nReal ) 1428 : SwFldPortion( rExpand, 0 ) 1429 , pFrm(pFrame) 1430 , pFtn(pFootn) 1431 , nOrigHeight( nReal ) 1432 // --> OD 2009-01-29 #i98418# 1433 , mbPreferredScriptTypeSet( false ) 1434 , mnPreferredScriptType( SW_LATIN ) 1435 // <-- 1436 { 1437 SetLen(1); 1438 SetWhichPor( POR_FTN ); 1439 } 1440 1441 /************************************************************************* 1442 * SwFtnPortion::GetExpTxt() 1443 *************************************************************************/ 1444 1445 sal_Bool SwFtnPortion::GetExpTxt( const SwTxtSizeInfo &, XubString &rTxt ) const 1446 { 1447 rTxt = aExpand; 1448 return sal_True; 1449 } 1450 1451 /************************************************************************* 1452 * virtual SwFtnPortion::Format() 1453 *************************************************************************/ 1454 1455 sal_Bool SwFtnPortion::Format( SwTxtFormatInfo &rInf ) 1456 { 1457 // --> OD 2009-01-29 #i98418# 1458 // SwFtnSave aFtnSave( rInf, pFtn ); 1459 SwFtnSave aFtnSave( rInf, pFtn, mbPreferredScriptTypeSet, mnPreferredScriptType ); 1460 // <-- 1461 // the idx is manipulated in SwExpandPortion::Format 1462 // this flag indicates, that a footnote is allowed to trigger 1463 // an underflow during SwTxtGuess::Guess 1464 rInf.SetFakeLineStart( rInf.GetIdx() > rInf.GetLineStart() ); 1465 sal_Bool bFull = SwFldPortion::Format( rInf ); 1466 rInf.SetFakeLineStart( sal_False ); 1467 SetAscent( rInf.GetAscent() ); 1468 Height( rInf.GetTxtHeight() ); 1469 rInf.SetFtnDone( !bFull ); 1470 if( !bFull ) 1471 rInf.SetParaFtn(); 1472 return bFull; 1473 } 1474 1475 /************************************************************************* 1476 * virtual SwFtnPortion::Paint() 1477 *************************************************************************/ 1478 1479 void SwFtnPortion::Paint( const SwTxtPaintInfo &rInf ) const 1480 { 1481 // --> OD 2009-01-29 #i98418# 1482 // SwFtnSave aFtnSave( rInf, pFtn ); 1483 SwFtnSave aFtnSave( rInf, pFtn, mbPreferredScriptTypeSet, mnPreferredScriptType ); 1484 // <-- 1485 rInf.DrawViewOpt( *this, POR_FTN ); 1486 SwExpandPortion::Paint( rInf ); 1487 } 1488 1489 /************************************************************************* 1490 * virtual SwFtnPortion::GetTxtSize() 1491 *************************************************************************/ 1492 1493 SwPosSize SwFtnPortion::GetTxtSize( const SwTxtSizeInfo &rInfo ) const 1494 { 1495 // --> OD 2009-01-29 #i98418# 1496 // SwFtnSave aFtnSave( rInfo, pFtn ); 1497 SwFtnSave aFtnSave( rInfo, pFtn, mbPreferredScriptTypeSet, mnPreferredScriptType ); 1498 // <-- 1499 return SwExpandPortion::GetTxtSize( rInfo ); 1500 } 1501 1502 // --> OD 2009-01-29 #i98418# 1503 void SwFtnPortion::SetPreferredScriptType( sal_uInt8 nPreferredScriptType ) 1504 { 1505 mbPreferredScriptTypeSet = true; 1506 mnPreferredScriptType = nPreferredScriptType; 1507 } 1508 // <-- 1509 1510 /************************************************************************* 1511 * class SwQuoVadisPortion 1512 *************************************************************************/ 1513 1514 SwFldPortion *SwQuoVadisPortion::Clone( const XubString &rExpand ) const 1515 { return new SwQuoVadisPortion( rExpand, aErgo ); } 1516 1517 SwQuoVadisPortion::SwQuoVadisPortion( const XubString &rExp, const XubString& rStr ) 1518 : SwFldPortion( rExp ), aErgo(rStr) 1519 { 1520 SetLen(0); 1521 SetWhichPor( POR_QUOVADIS ); 1522 } 1523 1524 /************************************************************************* 1525 * virtual SwQuoVadisPortion::Format() 1526 *************************************************************************/ 1527 1528 sal_Bool SwQuoVadisPortion::Format( SwTxtFormatInfo &rInf ) 1529 { 1530 // erster Versuch, vielleicht passt der Text 1531 CheckScript( rInf ); 1532 sal_Bool bFull = SwFldPortion::Format( rInf ); 1533 SetLen( 0 ); 1534 1535 if( bFull ) 1536 { 1537 // zweiter Versuch, wir kuerzen den String: 1538 aExpand = XubString( "...", RTL_TEXTENCODING_MS_1252 ); 1539 bFull = SwFldPortion::Format( rInf ); 1540 SetLen( 0 ); 1541 if( bFull ) 1542 // dritter Versuch, es langt: jetzt wird gestaucht: 1543 Width( sal_uInt16(rInf.Width() - rInf.X()) ); 1544 1545 // 8317: keine mehrzeiligen Felder bei QuoVadis und ErgoSum 1546 if( rInf.GetRest() ) 1547 { 1548 delete rInf.GetRest(); 1549 rInf.SetRest( 0 ); 1550 } 1551 } 1552 return bFull; 1553 } 1554 1555 /************************************************************************* 1556 * virtual SwQuoVadisPortion::GetExpTxt() 1557 *************************************************************************/ 1558 1559 sal_Bool SwQuoVadisPortion::GetExpTxt( const SwTxtSizeInfo &, XubString &rTxt ) const 1560 { 1561 rTxt = aExpand; 1562 // if this QuoVadisPortion has a follow, the follow is responsible for 1563 // the ergo text. 1564 if ( ! HasFollow() ) 1565 rTxt += aErgo; 1566 return sal_True; 1567 } 1568 1569 /************************************************************************* 1570 * virtual SwQuoVadisPortion::HandlePortion() 1571 *************************************************************************/ 1572 1573 void SwQuoVadisPortion::HandlePortion( SwPortionHandler& rPH ) const 1574 { 1575 String aString( aExpand ); 1576 aString += aErgo; 1577 rPH.Special( GetLen(), aString, GetWhichPor() ); 1578 } 1579 1580 /************************************************************************* 1581 * virtual SwQuoVadisPortion::Paint() 1582 *************************************************************************/ 1583 1584 void SwQuoVadisPortion::Paint( const SwTxtPaintInfo &rInf ) const 1585 { 1586 // Wir wollen _immer_ per DrawStretchText ausgeben, 1587 // weil nErgo schnell mal wechseln kann. 1588 if( PrtWidth() ) 1589 { 1590 rInf.DrawViewOpt( *this, POR_QUOVADIS ); 1591 SwTxtSlot aDiffTxt( &rInf, this, true, false ); 1592 SwFontSave aSave( rInf, pFnt ); 1593 rInf.DrawText( *this, rInf.GetLen(), sal_True ); 1594 } 1595 } 1596 1597 /************************************************************************* 1598 * class SwErgoSumPortion 1599 *************************************************************************/ 1600 1601 SwFldPortion *SwErgoSumPortion::Clone( const XubString &rExpand ) const 1602 { 1603 UniString aTmp; // = UniString::CreateFromInt32( 0 ); 1604 return new SwErgoSumPortion( rExpand, aTmp ); 1605 } 1606 1607 SwErgoSumPortion::SwErgoSumPortion( const XubString &rExp, const XubString& rStr ) 1608 : SwFldPortion( rExp ) 1609 { 1610 SetLen(0); 1611 aExpand += rStr; 1612 1613 // 7773: sinnvolle Massnahme: ein Blank Abstand zum Text 1614 aExpand += ' '; 1615 SetWhichPor( POR_ERGOSUM ); 1616 } 1617 1618 xub_StrLen SwErgoSumPortion::GetCrsrOfst( const KSHORT ) const 1619 { 1620 return 0; 1621 } 1622 1623 /************************************************************************* 1624 * virtual SwErgoSumPortion::Format() 1625 *************************************************************************/ 1626 1627 sal_Bool SwErgoSumPortion::Format( SwTxtFormatInfo &rInf ) 1628 { 1629 sal_Bool bFull = SwFldPortion::Format( rInf ); 1630 SetLen( 0 ); 1631 rInf.SetErgoDone( sal_True ); 1632 1633 // 8317: keine mehrzeiligen Felder bei QuoVadis und ErgoSum 1634 if( bFull && rInf.GetRest() ) 1635 { 1636 delete rInf.GetRest(); 1637 rInf.SetRest( 0 ); 1638 } 1639 1640 // We return false in order to get some text into the current line, 1641 // even if it's full (better than looping) 1642 return sal_False; 1643 } 1644 1645 1646 /************************************************************************* 1647 * SwParaPortion::SetErgoSumNum() 1648 *************************************************************************/ 1649 1650 void SwParaPortion::SetErgoSumNum( const XubString& rErgo ) 1651 { 1652 SwLineLayout *pLay = this; 1653 while( pLay->GetNext() ) 1654 { 1655 DBG_LOOP; 1656 pLay = pLay->GetNext(); 1657 } 1658 SwLinePortion *pPor = pLay; 1659 SwQuoVadisPortion *pQuo = 0; 1660 while( pPor && !pQuo ) 1661 { 1662 if ( pPor->IsQuoVadisPortion() ) 1663 pQuo = (SwQuoVadisPortion*)pPor; 1664 pPor = pPor->GetPortion(); 1665 } 1666 if( pQuo ) 1667 pQuo->SetNumber( rErgo ); 1668 } 1669 1670 /************************************************************************* 1671 * SwParaPortion::UpdateQuoVadis() 1672 * 1673 * Wird im SwTxtFrm::Prepare() gerufen 1674 *************************************************************************/ 1675 1676 sal_Bool SwParaPortion::UpdateQuoVadis( const XubString &rQuo ) 1677 { 1678 SwLineLayout *pLay = this; 1679 while( pLay->GetNext() ) 1680 { 1681 DBG_LOOP; 1682 pLay = pLay->GetNext(); 1683 } 1684 SwLinePortion *pPor = pLay; 1685 SwQuoVadisPortion *pQuo = 0; 1686 while( pPor && !pQuo ) 1687 { 1688 if ( pPor->IsQuoVadisPortion() ) 1689 pQuo = (SwQuoVadisPortion*)pPor; 1690 pPor = pPor->GetPortion(); 1691 } 1692 1693 if( !pQuo ) 1694 return sal_False; 1695 1696 return pQuo->GetQuoTxt() == rQuo; 1697 } 1698 1699 1700 1701