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