| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_sw.hxx" |
| #include "viewsh.hxx" |
| #include "doc.hxx" |
| #include "pagefrm.hxx" |
| #include "rootfrm.hxx" |
| #include "ndtxt.hxx" |
| #include "txtatr.hxx" |
| #include <SwPortionHandler.hxx> |
| #include <txtftn.hxx> |
| #include <flyfrm.hxx> |
| #include <fmtftn.hxx> |
| #include <ftninfo.hxx> |
| #include <charfmt.hxx> |
| #include <dflyobj.hxx> |
| #include <rowfrm.hxx> |
| #include <editeng/brshitem.hxx> |
| #include <editeng/charrotateitem.hxx> |
| #include <breakit.hxx> |
| #ifndef _COM_SUN_STAR_I18N_SCRIPTTYPE_HDL_ |
| #include <com/sun/star/i18n/ScriptType.hdl> |
| #endif |
| #include <tabfrm.hxx> |
| // OD 2004-05-24 #i28701# |
| #include <sortedobjs.hxx> |
| |
| #include "txtcfg.hxx" |
| #include "swfont.hxx" // new SwFont |
| #include "porftn.hxx" |
| #include "porfly.hxx" |
| #include "porlay.hxx" |
| #include "txtfrm.hxx" |
| #include "itrform2.hxx" |
| #include "ftnfrm.hxx" // FindQuoVadisFrm(), |
| #include "pagedesc.hxx" |
| #include "redlnitr.hxx" // SwRedlnItr |
| #include "sectfrm.hxx" // SwSectionFrm |
| #include "layouter.hxx" // Endnote-Collection |
| #include "frmtool.hxx" |
| #include "ndindex.hxx" |
| |
| using namespace ::com::sun::star; |
| |
| /************************************************************************* |
| * _IsFtnNumFrm() |
| *************************************************************************/ |
| |
| sal_Bool SwTxtFrm::_IsFtnNumFrm() const |
| { |
| const SwFtnFrm* pFtn = FindFtnFrm()->GetMaster(); |
| while( pFtn && !pFtn->ContainsCntnt() ) |
| pFtn = pFtn->GetMaster(); |
| return !pFtn; |
| } |
| |
| /************************************************************************* |
| * FindFtn() |
| *************************************************************************/ |
| |
| // Sucht innerhalb einer Master-Follow-Kette den richtigen TxtFrm zum SwTxtFtn |
| |
| SwTxtFrm *SwTxtFrm::FindFtnRef( const SwTxtFtn *pFtn ) |
| { |
| SwTxtFrm *pFrm = this; |
| const sal_Bool bFwd = *pFtn->GetStart() >= GetOfst(); |
| while( pFrm ) |
| { |
| if( SwFtnBossFrm::FindFtn( pFrm, pFtn ) ) |
| return pFrm; |
| pFrm = bFwd ? pFrm->GetFollow() : |
| pFrm->IsFollow() ? pFrm->FindMaster() : 0; |
| } |
| return pFrm; |
| } |
| |
| /************************************************************************* |
| * CalcFtnFlag() |
| *************************************************************************/ |
| |
| #ifndef DBG_UTIL |
| void SwTxtFrm::CalcFtnFlag() |
| #else |
| void SwTxtFrm::CalcFtnFlag( xub_StrLen nStop )//Fuer den Test von SplitFrm |
| #endif |
| { |
| bFtn = sal_False; |
| |
| const SwpHints *pHints = GetTxtNode()->GetpSwpHints(); |
| if( !pHints ) |
| return; |
| |
| const sal_uInt16 nSize = pHints->Count(); |
| |
| #ifndef DBG_UTIL |
| const xub_StrLen nEnd = GetFollow() ? GetFollow()->GetOfst() : STRING_LEN; |
| #else |
| const xub_StrLen nEnd = nStop != STRING_LEN ? nStop |
| : GetFollow() ? GetFollow()->GetOfst() : STRING_LEN; |
| #endif |
| |
| for ( sal_uInt16 i = 0; i < nSize; ++i ) |
| { |
| const SwTxtAttr *pHt = (*pHints)[i]; |
| if ( pHt->Which() == RES_TXTATR_FTN ) |
| { |
| const xub_StrLen nIdx = *pHt->GetStart(); |
| if ( nEnd < nIdx ) |
| break; |
| if( GetOfst() <= nIdx ) |
| { |
| bFtn = sal_True; |
| break; |
| } |
| } |
| } |
| } |
| |
| /************************************************************************* |
| * CalcPrepFtnAdjust() |
| *************************************************************************/ |
| |
| sal_Bool SwTxtFrm::CalcPrepFtnAdjust() |
| { |
| ASSERT( HasFtn(), "Wer ruft mich da?" ); |
| SwFtnBossFrm *pBoss = FindFtnBossFrm( sal_True ); |
| const SwFtnFrm *pFtn = pBoss->FindFirstFtn( this ); |
| if( pFtn && FTNPOS_CHAPTER != GetNode()->GetDoc()->GetFtnInfo().ePos && |
| ( !pBoss->GetUpper()->IsSctFrm() || |
| !((SwSectionFrm*)pBoss->GetUpper())->IsFtnAtEnd() ) ) |
| { |
| const SwFtnContFrm *pCont = pBoss->FindFtnCont(); |
| sal_Bool bReArrange = sal_True; |
| |
| SWRECTFN( this ) |
| if ( pCont && (*fnRect->fnYDiff)( (pCont->Frm().*fnRect->fnGetTop)(), |
| (Frm().*fnRect->fnGetBottom)() ) > 0 ) |
| { |
| pBoss->RearrangeFtns( (Frm().*fnRect->fnGetBottom)(), sal_False, |
| pFtn->GetAttr() ); |
| ValidateBodyFrm(); |
| ValidateFrm(); |
| pFtn = pBoss->FindFirstFtn( this ); |
| } |
| else |
| bReArrange = sal_False; |
| if( !pCont || !pFtn || bReArrange != (pFtn->FindFtnBossFrm() == pBoss) ) |
| { |
| SwTxtFormatInfo aInf( this ); |
| SwTxtFormatter aLine( this, &aInf ); |
| aLine.TruncLines(); |
| SetPara( 0 ); //Wird ggf. geloescht! |
| ResetPreps(); |
| return sal_False; |
| } |
| } |
| return sal_True; |
| } |
| |
| |
| /************************************************************************* |
| * lcl_GetFtnLower() |
| * |
| * Local helper function. Checks if nLower should be taken as the boundary |
| * for the footnote. |
| *************************************************************************/ |
| |
| SwTwips lcl_GetFtnLower( const SwTxtFrm* pFrm, SwTwips nLower ) |
| { |
| // nLower is an absolute value. It denotes the bottom of the line |
| // containing the footnote. |
| SWRECTFN( pFrm ) |
| |
| ASSERT( !pFrm->IsVertical() || !pFrm->IsSwapped(), |
| "lcl_GetFtnLower with swapped frame" ); |
| |
| SwTwips nAdd; |
| SwTwips nRet = nLower; |
| |
| // |
| // Check if text is inside a table. |
| // |
| if ( pFrm->IsInTab() ) |
| { |
| // |
| // If pFrm is inside a table, we have to check if |
| // a) The table is not allowed to split or |
| // b) The table row is not allowed to split |
| // |
| // Inside a table, there are no footnotes, |
| // see SwFrm::FindFtnBossFrm. So we don't have to check |
| // the case that pFrm is inside a (footnote collecting) section |
| // within the table. |
| // |
| const SwFrm* pRow = pFrm; |
| while( !pRow->IsRowFrm() || !pRow->GetUpper()->IsTabFrm() ) |
| pRow = pRow->GetUpper(); |
| const SwTabFrm* pTabFrm = (SwTabFrm*)pRow->GetUpper(); |
| |
| ASSERT( pTabFrm && pRow && |
| pRow->GetUpper()->IsTabFrm(), "Upper of row should be tab" ) |
| |
| const sal_Bool bDontSplit = !pTabFrm->IsFollow() && |
| !pTabFrm->IsLayoutSplitAllowed(); |
| |
| SwTwips nMin = 0; |
| if ( bDontSplit ) |
| nMin = (pTabFrm->Frm().*fnRect->fnGetBottom)(); |
| else if ( !((SwRowFrm*)pRow)->IsRowSplitAllowed() ) |
| nMin = (pRow->Frm().*fnRect->fnGetBottom)(); |
| |
| if ( nMin && (*fnRect->fnYDiff)( nMin, nLower ) > 0 ) |
| nRet = nMin; |
| |
| nAdd = (pRow->GetUpper()->*fnRect->fnGetBottomMargin)(); |
| } |
| else |
| nAdd = (pFrm->*fnRect->fnGetBottomMargin)(); |
| |
| if( nAdd > 0 ) |
| { |
| if ( bVert ) |
| nRet -= nAdd; |
| else |
| nRet += nAdd; |
| } |
| |
| // #i10770#: If there are fly frames anchored at previous paragraphs, |
| // the deadline should consider their lower borders. |
| const SwFrm* pStartFrm = pFrm->GetUpper()->GetLower(); |
| ASSERT( pStartFrm, "Upper has no lower" ) |
| SwTwips nFlyLower = bVert ? LONG_MAX : 0; |
| while ( pStartFrm != pFrm ) |
| { |
| ASSERT( pStartFrm, "Frame chain is broken" ) |
| if ( pStartFrm->GetDrawObjs() ) |
| { |
| const SwSortedObjs &rObjs = *pStartFrm->GetDrawObjs(); |
| for ( sal_uInt16 i = 0; i < rObjs.Count(); ++i ) |
| { |
| SwAnchoredObject* pAnchoredObj = rObjs[i]; |
| SwRect aRect( pAnchoredObj->GetObjRect() ); |
| |
| if ( !pAnchoredObj->ISA(SwFlyFrm) || |
| static_cast<SwFlyFrm*>(pAnchoredObj)->IsValid() ) |
| { |
| const SwTwips nBottom = (aRect.*fnRect->fnGetBottom)(); |
| if ( (*fnRect->fnYDiff)( nBottom, nFlyLower ) > 0 ) |
| nFlyLower = nBottom; |
| } |
| } |
| } |
| |
| pStartFrm = pStartFrm->GetNext(); |
| } |
| |
| if ( bVert ) |
| nRet = Min( nRet, nFlyLower ); |
| else |
| nRet = Max( nRet, nFlyLower ); |
| |
| return nRet; |
| } |
| |
| |
| /************************************************************************* |
| * SwTxtFrm::GetFtnLine() |
| *************************************************************************/ |
| |
| SwTwips SwTxtFrm::GetFtnLine( const SwTxtFtn *pFtn ) const |
| { |
| ASSERT( ! IsVertical() || ! IsSwapped(), |
| "SwTxtFrm::GetFtnLine with swapped frame" ) |
| |
| SwTxtFrm *pThis = (SwTxtFrm*)this; |
| |
| if( !HasPara() ) |
| { |
| // #109071# GetFormatted() does not work here, bacause most probably |
| // the frame is currently locked. We return the previous value. |
| return pThis->mnFtnLine > 0 ? |
| pThis->mnFtnLine : |
| IsVertical() ? Frm().Left() : Frm().Bottom(); |
| } |
| |
| SWAP_IF_NOT_SWAPPED( this ) |
| |
| SwTxtInfo aInf( pThis ); |
| SwTxtIter aLine( pThis, &aInf ); |
| const xub_StrLen nPos = *pFtn->GetStart(); |
| aLine.CharToLine( nPos ); |
| |
| SwTwips nRet = aLine.Y() + SwTwips(aLine.GetLineHeight()); |
| if( IsVertical() ) |
| nRet = SwitchHorizontalToVertical( nRet ); |
| |
| UNDO_SWAP( this ) |
| |
| nRet = lcl_GetFtnLower( pThis, nRet ); |
| |
| pThis->mnFtnLine = nRet; |
| return nRet; |
| } |
| |
| /************************************************************************* |
| * SwTxtFrm::GetFtnRstHeight() |
| *************************************************************************/ |
| |
| // Ermittelt die max. erreichbare Hoehe des TxtFrm im Ftn-Bereich. |
| // Sie wird eingeschraenkt durch den unteren Rand der Zeile mit |
| // der Ftn-Referenz. |
| |
| SwTwips SwTxtFrm::_GetFtnFrmHeight() const |
| { |
| ASSERT( !IsFollow() && IsInFtn(), "SwTxtFrm::SetFtnLine: moon walk" ); |
| |
| const SwFtnFrm *pFtnFrm = FindFtnFrm(); |
| const SwTxtFrm *pRef = (const SwTxtFrm *)pFtnFrm->GetRef(); |
| const SwFtnBossFrm *pBoss = FindFtnBossFrm(); |
| if( pBoss != pRef->FindFtnBossFrm( !pFtnFrm->GetAttr()-> |
| GetFtn().IsEndNote() ) ) |
| return 0; |
| |
| SWAP_IF_SWAPPED( this ) |
| |
| SwTwips nHeight = pRef->IsInFtnConnect() ? |
| 1 : pRef->GetFtnLine( pFtnFrm->GetAttr() ); |
| if( nHeight ) |
| { |
| // So komisch es aussehen mag: Die erste Ftn auf der Seite darf sich |
| // nicht mit der Ftn-Referenz beruehren, wenn wir im Ftn-Bereich Text |
| // eingeben. |
| const SwFrm *pCont = pFtnFrm->GetUpper(); |
| //Hoehe innerhalb des Cont, die ich mir 'eh noch genehmigen darf. |
| SWRECTFN( pCont ) |
| SwTwips nTmp = (*fnRect->fnYDiff)( (pCont->*fnRect->fnGetPrtBottom)(), |
| (Frm().*fnRect->fnGetTop)() ); |
| |
| #ifdef DBG_UTIL |
| if( nTmp < 0 ) |
| { |
| sal_Bool bInvalidPos = sal_False; |
| const SwLayoutFrm* pTmp = GetUpper(); |
| while( !bInvalidPos && pTmp ) |
| { |
| bInvalidPos = !pTmp->GetValidPosFlag() || |
| !pTmp->Lower()->GetValidPosFlag(); |
| if( pTmp == pCont ) |
| break; |
| pTmp = pTmp->GetUpper(); |
| } |
| ASSERT( bInvalidPos, "Hanging below FtnCont" ); |
| } |
| #endif |
| |
| if ( (*fnRect->fnYDiff)( (pCont->Frm().*fnRect->fnGetTop)(), nHeight) > 0 ) |
| { |
| //Wachstumspotential den Containers. |
| if ( !pRef->IsInFtnConnect() ) |
| { |
| SwSaveFtnHeight aSave( (SwFtnBossFrm*)pBoss, nHeight ); |
| nHeight = ((SwFtnContFrm*)pCont)->Grow( LONG_MAX, sal_True ); |
| } |
| else |
| nHeight = ((SwFtnContFrm*)pCont)->Grow( LONG_MAX, sal_True ); |
| |
| nHeight += nTmp; |
| if( nHeight < 0 ) |
| nHeight = 0; |
| } |
| else |
| { // The container has to shrink |
| nTmp += (*fnRect->fnYDiff)( (pCont->Frm().*fnRect->fnGetTop)(), nHeight); |
| if( nTmp > 0 ) |
| nHeight = nTmp; |
| else |
| nHeight = 0; |
| } |
| } |
| |
| UNDO_SWAP( this ) |
| |
| return nHeight; |
| } |
| |
| /************************************************************************* |
| * SwTxtFrm::FindQuoVadisFrm() |
| *************************************************************************/ |
| |
| SwTxtFrm *SwTxtFrm::FindQuoVadisFrm() |
| { |
| // Erstmal feststellen, ob wir in einem FtnFrm stehen: |
| if( GetIndPrev() || !IsInFtn() ) |
| return 0; |
| |
| // Zum Vorgaenger-FtnFrm |
| SwFtnFrm *pFtnFrm = FindFtnFrm()->GetMaster(); |
| if( !pFtnFrm ) |
| return 0; |
| |
| // Nun den letzten Cntnt: |
| const SwCntntFrm *pCnt = pFtnFrm->ContainsCntnt(); |
| if( !pCnt ) |
| return NULL; |
| const SwCntntFrm *pLast; |
| do |
| { pLast = pCnt; |
| pCnt = pCnt->GetNextCntntFrm(); |
| } while( pCnt && pFtnFrm->IsAnLower( pCnt ) ); |
| return (SwTxtFrm*)pLast; |
| } |
| |
| /************************************************************************* |
| * SwTxtFrm::RemoveFtn() |
| *************************************************************************/ |
| |
| void SwTxtFrm::RemoveFtn( const xub_StrLen nStart, const xub_StrLen nLen ) |
| { |
| if ( !IsFtnAllowed() ) |
| return; |
| |
| SwpHints *pHints = GetTxtNode()->GetpSwpHints(); |
| if( !pHints ) |
| return; |
| |
| sal_Bool bRollBack = nLen != STRING_LEN; |
| sal_uInt16 nSize = pHints->Count(); |
| xub_StrLen nEnd; |
| SwTxtFrm* pSource; |
| if( bRollBack ) |
| { |
| nEnd = nStart + nLen; |
| pSource = GetFollow(); |
| if( !pSource ) |
| return; |
| } |
| else |
| { |
| nEnd = STRING_LEN; |
| pSource = this; |
| } |
| |
| if( nSize ) |
| { |
| SwPageFrm* pUpdate = NULL; |
| sal_Bool bRemove = sal_False; |
| SwFtnBossFrm *pFtnBoss = 0; |
| SwFtnBossFrm *pEndBoss = 0; |
| sal_Bool bFtnEndDoc |
| = FTNPOS_CHAPTER == GetNode()->GetDoc()->GetFtnInfo().ePos; |
| for ( sal_uInt16 i = nSize; i; ) |
| { |
| SwTxtAttr *pHt = pHints->GetTextHint(--i); |
| if ( RES_TXTATR_FTN != pHt->Which() ) |
| continue; |
| |
| const xub_StrLen nIdx = *pHt->GetStart(); |
| if( nStart > nIdx ) |
| break; |
| |
| if( nEnd >= nIdx ) |
| { |
| SwTxtFtn *pFtn = (SwTxtFtn*)pHt; |
| sal_Bool bEndn = pFtn->GetFtn().IsEndNote(); |
| |
| if( bEndn ) |
| { |
| if( !pEndBoss ) |
| pEndBoss = pSource->FindFtnBossFrm(); |
| } |
| else |
| { |
| if( !pFtnBoss ) |
| { |
| pFtnBoss = pSource->FindFtnBossFrm( sal_True ); |
| if( pFtnBoss->GetUpper()->IsSctFrm() ) |
| { |
| SwSectionFrm* pSect = (SwSectionFrm*) |
| pFtnBoss->GetUpper(); |
| if( pSect->IsFtnAtEnd() ) |
| bFtnEndDoc = sal_False; |
| } |
| } |
| } |
| |
| // Wir loeschen nicht, sondern wollen die Ftn verschieben. |
| // Drei Faelle koennen auftreten: |
| // 1) Es gibt weder Follow noch PrevFollow |
| // -> RemoveFtn() (vielleicht sogar ein ASSERT wert) |
| // 2) nStart > GetOfst, ich habe einen Follow |
| // -> Ftn wandert in den Follow |
| // 3) nStart < GetOfst, ich bin ein Follow |
| // -> Ftn wandert in den PrevFollow |
| // beide muessen auf einer Seite/in einer Spalte stehen. |
| |
| SwFtnFrm *pFtnFrm = bEndn ? pEndBoss->FindFtn( pSource, pFtn ) : |
| pFtnBoss->FindFtn( pSource, pFtn ); |
| |
| if( pFtnFrm ) |
| { |
| const sal_Bool bEndDoc = bEndn ? sal_True : bFtnEndDoc; |
| if( bRollBack ) |
| { |
| while ( pFtnFrm ) |
| { |
| pFtnFrm->SetRef( this ); |
| pFtnFrm = pFtnFrm->GetFollow(); |
| SetFtn( sal_True ); |
| } |
| } |
| else if( GetFollow() ) |
| { |
| SwCntntFrm *pDest = GetFollow(); |
| while( pDest->GetFollow() && ((SwTxtFrm*)pDest-> |
| GetFollow())->GetOfst() <= nIdx ) |
| pDest = pDest->GetFollow(); |
| ASSERT( !pDest->FindFtnBossFrm( !bEndn )->FindFtn( |
| pDest,pFtn),"SwTxtFrm::RemoveFtn: footnote exists"); |
| |
| //Nicht ummelden sondern immer Moven. |
| // OD 08.11.2002 #104840# - use <SwlayoutFrm::IsBefore(::)> |
| if ( bEndDoc || |
| !pFtnFrm->FindFtnBossFrm()->IsBefore( pDest->FindFtnBossFrm( !bEndn ) ) |
| ) |
| { |
| SwPageFrm* pTmp = pFtnFrm->FindPageFrm(); |
| if( pUpdate && pUpdate != pTmp ) |
| pUpdate->UpdateFtnNum(); |
| pUpdate = pTmp; |
| while ( pFtnFrm ) |
| { |
| pFtnFrm->SetRef( pDest ); |
| pFtnFrm = pFtnFrm->GetFollow(); |
| } |
| } |
| else |
| { |
| if( bEndn ) |
| pEndBoss->MoveFtns( this, pDest, pFtn ); |
| else |
| pFtnBoss->MoveFtns( this, pDest, pFtn ); |
| bRemove = sal_True; |
| } |
| ((SwTxtFrm*)pDest)->SetFtn( sal_True ); |
| |
| ASSERT( pDest->FindFtnBossFrm( !bEndn )->FindFtn( pDest, |
| pFtn),"SwTxtFrm::RemoveFtn: footnote ChgRef failed"); |
| } |
| else |
| { |
| if( !bEndDoc || ( bEndn && pEndBoss->IsInSct() && |
| !SwLayouter::Collecting( GetNode()->GetDoc(), |
| pEndBoss->FindSctFrm(), NULL ) ) ) |
| { |
| if( bEndn ) |
| pEndBoss->RemoveFtn( this, pFtn ); |
| else |
| pFtnBoss->RemoveFtn( this, pFtn ); |
| bRemove = bRemove || !bEndDoc; |
| ASSERT( bEndn ? !pEndBoss->FindFtn( this, pFtn ) : |
| !pFtnBoss->FindFtn( this, pFtn ), |
| "SwTxtFrm::RemoveFtn: can't get off that footnote" ); |
| } |
| } |
| } |
| } |
| } |
| if( pUpdate ) |
| pUpdate->UpdateFtnNum(); |
| // Wir bringen die Oszillation zum stehen: |
| if( bRemove && !bFtnEndDoc && HasPara() ) |
| { |
| ValidateBodyFrm(); |
| ValidateFrm(); |
| } |
| } |
| // Folgendes Problem: Aus dem FindBreak heraus wird das RemoveFtn aufgerufen, |
| // weil die letzte Zeile an den Follow abgegeben werden soll. Der Offset |
| // des Follows ist aber veraltet, er wird demnaechst gesetzt. CalcFntFlag ist |
| // auf einen richtigen Follow-Offset angewiesen. Deshalb wird hier kurzfristig |
| // der Follow-Offset manipuliert. |
| xub_StrLen nOldOfst = STRING_LEN; |
| if( HasFollow() && nStart > GetOfst() ) |
| { |
| nOldOfst = GetFollow()->GetOfst(); |
| GetFollow()->ManipOfst( nStart + ( bRollBack ? nLen : 0 ) ); |
| } |
| pSource->CalcFtnFlag(); |
| if( nOldOfst < STRING_LEN ) |
| GetFollow()->ManipOfst( nOldOfst ); |
| } |
| |
| /************************************************************************* |
| * SwTxtFormatter::ConnectFtn() |
| *************************************************************************/ |
| // sal_False, wenn irgendetwas schief gegangen ist. |
| // Es gibt eigentlich nur zwei Moeglichkeiten: |
| // a) Die Ftn ist bereits vorhanden |
| // => dann wird sie gemoved, wenn ein anderer pSrcFrm gefunden wurde |
| // b) Die Ftn ist nicht vorhanden |
| // => dann wird sie fuer uns angelegt. |
| // Ob die Ftn schliesslich auf unserer Spalte/Seite landet oder nicht, |
| // spielt in diesem Zusammenhang keine Rolle. |
| // Optimierungen bei Endnoten. |
| // Noch ein Problem: wenn die Deadline im Ftn-Bereich liegt, muss die |
| // Ftn verschoben werden. |
| |
| void SwTxtFrm::ConnectFtn( SwTxtFtn *pFtn, const SwTwips nDeadLine ) |
| { |
| ASSERT( !IsVertical() || !IsSwapped(), |
| "SwTxtFrm::ConnectFtn with swapped frame" ); |
| |
| bFtn = sal_True; |
| bInFtnConnect = sal_True; //Bloss zuruecksetzen! |
| sal_Bool bEnd = pFtn->GetFtn().IsEndNote(); |
| |
| // |
| // We want to store this value, because it is needed as a fallback |
| // in GetFtnLine(), if there is no paragraph information available |
| // |
| mnFtnLine = nDeadLine; |
| |
| // Wir brauchen immer einen Boss (Spalte/Seite) |
| SwSectionFrm *pSect; |
| SwCntntFrm *pCntnt = this; |
| if( bEnd && IsInSct() ) |
| { |
| pSect = FindSctFrm(); |
| if( pSect->IsEndnAtEnd() ) |
| pCntnt = pSect->FindLastCntnt( FINDMODE_ENDNOTE ); |
| if( !pCntnt ) |
| pCntnt = this; |
| } |
| |
| SwFtnBossFrm *pBoss = pCntnt->FindFtnBossFrm( !bEnd ); |
| |
| #if OSL_DEBUG_LEVEL > 1 |
| SwTwips nRstHeight = GetRstHeight(); |
| #endif |
| |
| pSect = pBoss->FindSctFrm(); |
| sal_Bool bDocEnd = bEnd ? !( pSect && pSect->IsEndnAtEnd() ) : |
| ( !( pSect && pSect->IsFtnAtEnd() ) && |
| FTNPOS_CHAPTER == GetNode()->GetDoc()->GetFtnInfo().ePos ); |
| //Ftn kann beim Follow angemeldet sein. |
| SwCntntFrm *pSrcFrm = FindFtnRef( pFtn ); |
| |
| if( bDocEnd ) |
| { |
| if( pSect && pSrcFrm ) |
| { |
| SwFtnFrm *pFtnFrm = pBoss->FindFtn( pSrcFrm, pFtn ); |
| if( pFtnFrm && pFtnFrm->IsInSct() ) |
| { |
| pBoss->RemoveFtn( pSrcFrm, pFtn ); |
| pSrcFrm = 0; |
| } |
| } |
| } |
| else if( bEnd && pSect ) |
| { |
| SwFtnFrm *pFtnFrm = pSrcFrm ? pBoss->FindFtn( pSrcFrm, pFtn ) : NULL; |
| if( pFtnFrm && !pFtnFrm->GetUpper() ) |
| pFtnFrm = NULL; |
| SwDoc *pDoc = GetNode()->GetDoc(); |
| if( SwLayouter::Collecting( pDoc, pSect, pFtnFrm ) ) |
| { |
| if( !pSrcFrm ) |
| { |
| SwFtnFrm *pNew = new SwFtnFrm(pDoc->GetDfltFrmFmt(),this,this,pFtn); |
| SwNodeIndex aIdx( *pFtn->GetStartNode(), 1 ); |
| ::_InsertCnt( pNew, pDoc, aIdx.GetIndex() ); |
| GetNode()->getIDocumentLayoutAccess()->GetLayouter()->CollectEndnote( pNew ); |
| } |
| else if( pSrcFrm != this ) |
| pBoss->ChangeFtnRef( pSrcFrm, pFtn, this ); |
| bInFtnConnect = sal_False; |
| return; |
| } |
| else if( pSrcFrm ) |
| { |
| SwFtnBossFrm *pFtnBoss = pFtnFrm->FindFtnBossFrm(); |
| if( !pFtnBoss->IsInSct() || |
| pFtnBoss->ImplFindSctFrm()->GetSection()!=pSect->GetSection() ) |
| { |
| pBoss->RemoveFtn( pSrcFrm, pFtn ); |
| pSrcFrm = 0; |
| } |
| } |
| } |
| |
| if( bDocEnd || bEnd ) |
| { |
| if( !pSrcFrm ) |
| pBoss->AppendFtn( this, pFtn ); |
| else if( pSrcFrm != this ) |
| pBoss->ChangeFtnRef( pSrcFrm, pFtn, this ); |
| bInFtnConnect = sal_False; |
| return; |
| } |
| |
| SwSaveFtnHeight aHeight( pBoss, nDeadLine ); |
| |
| if( !pSrcFrm ) // Es wurde ueberhaupt keine Ftn gefunden. |
| pBoss->AppendFtn( this, pFtn ); |
| else |
| { |
| SwFtnFrm *pFtnFrm = pBoss->FindFtn( pSrcFrm, pFtn ); |
| SwFtnBossFrm *pFtnBoss = pFtnFrm->FindFtnBossFrm(); |
| |
| sal_Bool bBrutal = sal_False; |
| |
| if( pFtnBoss == pBoss ) // Ref und Ftn sind auf der selben Seite/Spalte. |
| { |
| SwFrm *pCont = pFtnFrm->GetUpper(); |
| |
| SWRECTFN ( pCont ) |
| long nDiff = (*fnRect->fnYDiff)( (pCont->Frm().*fnRect->fnGetTop)(), |
| nDeadLine ); |
| |
| if( nDiff >= 0 ) |
| { |
| //Wenn die Fussnote bei einem Follow angemeldet ist, so ist |
| //es jetzt an der Zeit sie umzumelden. |
| if ( pSrcFrm != this ) |
| pBoss->ChangeFtnRef( pSrcFrm, pFtn, this ); |
| //Es steht Platz zur Verfuegung, also kann die Fussnote evtl. |
| //wachsen. |
| if ( pFtnFrm->GetFollow() && nDiff > 0 ) |
| { |
| SwTwips nHeight = (pCont->Frm().*fnRect->fnGetHeight)(); |
| pBoss->RearrangeFtns( nDeadLine, sal_False, pFtn ); |
| ValidateBodyFrm(); |
| ValidateFrm(); |
| ViewShell *pSh = getRootFrm()->GetCurrShell(); |
| if ( pSh && nHeight == (pCont->Frm().*fnRect->fnGetHeight)() ) |
| //Damit uns nix durch die Lappen geht. |
| pSh->InvalidateWindows( pCont->Frm() ); |
| } |
| bInFtnConnect = sal_False; |
| return; |
| } |
| else |
| bBrutal = sal_True; |
| } |
| else |
| { |
| // Ref und Ftn sind nicht auf einer Seite, Move-Versuch ist noetig. |
| SwFrm* pTmp = this; |
| while( pTmp->GetNext() && pSrcFrm != pTmp ) |
| pTmp = pTmp->GetNext(); |
| if( pSrcFrm == pTmp ) |
| bBrutal = sal_True; |
| else |
| { // Wenn unser Boss in einem spaltigen Bereich sitzt, es aber auf |
| // der Seite schon einen FtnContainer gibt, hilft nur die brutale |
| // Methode |
| if( pSect && pSect->FindFtnBossFrm( !bEnd )->FindFtnCont() ) |
| bBrutal = sal_True; |
| // OD 08.11.2002 #104840# - use <SwLayoutFrm::IsBefore(..)> |
| else if ( !pFtnFrm->GetPrev() || |
| pFtnBoss->IsBefore( pBoss ) |
| ) |
| { |
| SwFtnBossFrm *pSrcBoss = pSrcFrm->FindFtnBossFrm( !bEnd ); |
| pSrcBoss->MoveFtns( pSrcFrm, this, pFtn ); |
| } |
| else |
| pBoss->ChangeFtnRef( pSrcFrm, pFtn, this ); |
| } |
| } |
| |
| // Die brutale Loesung: Fussnote entfernen und appenden. |
| // Es muss SetFtnDeadLine() gerufen werden, weil nach |
| // RemoveFtn die nMaxFtnHeight evtl. besser auf unsere Wuensche |
| // eingestellt werden kann. |
| if( bBrutal ) |
| { |
| pBoss->RemoveFtn( pSrcFrm, pFtn, sal_False ); |
| SwSaveFtnHeight *pHeight = bEnd ? NULL : |
| new SwSaveFtnHeight( pBoss, nDeadLine ); |
| pBoss->AppendFtn( this, pFtn ); |
| delete pHeight; |
| } |
| } |
| |
| // In spaltigen Bereichen, die noch nicht bis zum Seitenrand gehen, |
| // ist kein RearrangeFtns sinnvoll, da der Fussnotencontainer noch |
| // nicht kalkuliert worden ist. |
| if( !pSect || !pSect->Growable() ) |
| { |
| // Umgebung validieren, um Oszillationen zu verhindern. |
| SwSaveFtnHeight aNochmal( pBoss, nDeadLine ); |
| ValidateBodyFrm(); |
| pBoss->RearrangeFtns( nDeadLine, sal_True ); |
| ValidateFrm(); |
| } |
| else if( pSect->IsFtnAtEnd() ) |
| { |
| ValidateBodyFrm(); |
| ValidateFrm(); |
| } |
| |
| #if OSL_DEBUG_LEVEL > 1 |
| // pFtnFrm kann sich durch Calc veraendert haben ... |
| SwFtnFrm *pFtnFrm = pBoss->FindFtn( this, pFtn ); |
| if( pFtnFrm && pBoss != pFtnFrm->FindFtnBossFrm( !bEnd ) ) |
| { |
| int bla = 5; |
| (void)bla; |
| } |
| nRstHeight = GetRstHeight(); |
| #endif |
| bInFtnConnect = sal_False; |
| return; |
| } |
| |
| |
| |
| /************************************************************************* |
| * SwTxtFormatter::NewFtnPortion() |
| *************************************************************************/ |
| |
| // Die Portion fuer die Ftn-Referenz im Text |
| SwFtnPortion *SwTxtFormatter::NewFtnPortion( SwTxtFormatInfo &rInf, |
| SwTxtAttr *pHint ) |
| { |
| ASSERT( ! pFrm->IsVertical() || pFrm->IsSwapped(), |
| "NewFtnPortion with unswapped frame" ); |
| |
| if( !pFrm->IsFtnAllowed() ) |
| return 0; |
| |
| SwTxtFtn *pFtn = (SwTxtFtn*)pHint; |
| SwFmtFtn& rFtn = (SwFmtFtn&)pFtn->GetFtn(); |
| SwDoc *pDoc = pFrm->GetNode()->GetDoc(); |
| |
| if( rInf.IsTest() ) |
| return new SwFtnPortion( rFtn.GetViewNumStr( *pDoc ), pFrm, pFtn ); |
| |
| SWAP_IF_SWAPPED( pFrm ) |
| |
| KSHORT nReal; |
| { |
| KSHORT nOldReal = pCurr->GetRealHeight(); |
| KSHORT nOldAscent = pCurr->GetAscent(); |
| KSHORT nOldHeight = pCurr->Height(); |
| ((SwTxtFormatter*)this)->CalcRealHeight(); |
| nReal = pCurr->GetRealHeight(); |
| if( nReal < nOldReal ) |
| nReal = nOldReal; |
| pCurr->SetRealHeight( nOldReal ); |
| pCurr->Height( nOldHeight ); |
| pCurr->SetAscent( nOldAscent ); |
| } |
| |
| SwTwips nLower = Y() + nReal; |
| |
| const bool bVertical = pFrm->IsVertical(); |
| if( bVertical ) |
| nLower = pFrm->SwitchHorizontalToVertical( nLower ); |
| |
| nLower = lcl_GetFtnLower( pFrm, nLower ); |
| |
| //6995: Wir frischen nur auf. Das Connect tut fuer diesen Fall nix |
| //Brauchbares, sondern wuerde stattdessen fuer diesen Fall meist die |
| //Ftn wegwerfen und neu erzeugen. |
| |
| if( !rInf.IsQuick() ) |
| pFrm->ConnectFtn( pFtn, nLower ); |
| |
| SwTxtFrm *pScrFrm = pFrm->FindFtnRef( pFtn ); |
| SwFtnBossFrm *pBoss = pFrm->FindFtnBossFrm( !rFtn.IsEndNote() ); |
| SwFtnFrm *pFtnFrm = NULL; |
| if( pScrFrm ) |
| pFtnFrm = pBoss->FindFtn( pScrFrm, pFtn ); |
| |
| // Wir erkundigen uns, ob durch unser Append irgendeine |
| // Fussnote noch auf der Seite/Spalte steht. Wenn nicht verschwindet |
| // auch unsere Zeile. Dies fuehrt zu folgendem erwuenschten |
| // Verhalten: Ftn1 pass noch auf die Seite/Spalte, Ftn2 nicht mehr. |
| // Also bleibt die Ftn2-Referenz auf der Seite/Spalte stehen. Die |
| // Fussnote selbst folgt aber erst auf der naechsten Seite/Spalte. |
| // Ausnahme: Wenn keine weitere Zeile auf diese Seite/Spalte passt, |
| // so sollte die Ftn2-Referenz auch auf die naechste wandern. |
| if( !rFtn.IsEndNote() ) |
| { |
| SwSectionFrm *pSct = pBoss->FindSctFrm(); |
| sal_Bool bAtSctEnd = pSct && pSct->IsFtnAtEnd(); |
| if( FTNPOS_CHAPTER != pDoc->GetFtnInfo().ePos || bAtSctEnd ) |
| { |
| SwFrm* pFtnCont = pBoss->FindFtnCont(); |
| // Wenn der Boss in einem Bereich liegt, kann es sich nur um eine |
| // Spalte dieses Bereichs handeln. Wenn dies nicht die erste Spalte |
| // ist, duerfen wir ausweichen |
| if( !pFrm->IsInTab() && ( GetLineNr() > 1 || pFrm->GetPrev() || |
| ( !bAtSctEnd && pFrm->GetIndPrev() ) || |
| ( pSct && pBoss->GetPrev() ) ) ) |
| { |
| if( !pFtnCont ) |
| { |
| rInf.SetStop( sal_True ); |
| UNDO_SWAP( pFrm ) |
| return 0; |
| } |
| else |
| { |
| // Es darf keine Fussnotencontainer in spaltigen Bereichen und |
| // gleichzeitig auf der Seite/Seitenspalte geben |
| if( pSct && !bAtSctEnd ) // liegt unser Container in einem (spaltigen) Bereich? |
| { |
| SwFtnBossFrm* pTmp = pBoss->FindSctFrm()->FindFtnBossFrm( sal_True ); |
| SwFtnContFrm* pFtnC = pTmp->FindFtnCont(); |
| if( pFtnC ) |
| { |
| SwFtnFrm* pTmpFrm = (SwFtnFrm*)pFtnC->Lower(); |
| if( pTmpFrm && *pTmpFrm < pFtn ) |
| { |
| rInf.SetStop( sal_True ); |
| UNDO_SWAP( pFrm ) |
| return 0; |
| } |
| } |
| } |
| // Ist dies die letzte passende Zeile? |
| SwTwips nTmpBot = Y() + nReal * 2; |
| |
| if( bVertical ) |
| nTmpBot = pFrm->SwitchHorizontalToVertical( nTmpBot ); |
| |
| SWRECTFN( pFtnCont ) |
| |
| const long nDiff = (*fnRect->fnYDiff)( |
| (pFtnCont->Frm().*fnRect->fnGetTop)(), |
| nTmpBot ); |
| |
| if( pScrFrm && nDiff < 0 ) |
| { |
| if( pFtnFrm ) |
| { |
| SwFtnBossFrm *pFtnBoss = pFtnFrm->FindFtnBossFrm(); |
| if( pFtnBoss != pBoss ) |
| { |
| // Wir sind in der letzte Zeile und die Fussnote |
| // ist auf eine andere Seite gewandert, dann wollen |
| // wir mit ... |
| rInf.SetStop( sal_True ); |
| UNDO_SWAP( pFrm ) |
| return 0; |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| // Endlich: FtnPortion anlegen und raus hier... |
| SwFtnPortion *pRet = new SwFtnPortion( rFtn.GetViewNumStr( *pDoc ), |
| pFrm, pFtn, nReal ); |
| rInf.SetFtnInside( sal_True ); |
| |
| UNDO_SWAP( pFrm ) |
| |
| return pRet; |
| } |
| |
| /************************************************************************* |
| * SwTxtFormatter::NewFtnNumPortion() |
| *************************************************************************/ |
| |
| // Die Portion fuer die Ftn-Nummerierung im Ftn-Bereich |
| |
| SwNumberPortion *SwTxtFormatter::NewFtnNumPortion( SwTxtFormatInfo &rInf ) const |
| { |
| ASSERT( pFrm->IsInFtn() && !pFrm->GetIndPrev() && !rInf.IsFtnDone(), |
| "This is the wrong place for a ftnnumber" ); |
| if( rInf.GetTxtStart() != nStart || |
| rInf.GetTxtStart() != rInf.GetIdx() ) |
| return 0; |
| |
| const SwFtnFrm* pFtnFrm = pFrm->FindFtnFrm(); |
| const SwTxtFtn* pFtn = pFtnFrm->GetAttr(); |
| |
| // Aha, wir sind also im Fussnotenbereich |
| SwFmtFtn& rFtn = (SwFmtFtn&)pFtn->GetFtn(); |
| |
| SwDoc *pDoc = pFrm->GetNode()->GetDoc(); |
| XubString aFtnTxt( rFtn.GetViewNumStr( *pDoc, sal_True )); |
| |
| const SwEndNoteInfo* pInfo; |
| if( rFtn.IsEndNote() ) |
| pInfo = &pDoc->GetEndNoteInfo(); |
| else |
| pInfo = &pDoc->GetFtnInfo(); |
| const SwAttrSet& rSet = pInfo->GetCharFmt(*pDoc)->GetAttrSet(); |
| |
| const SwAttrSet* pParSet = &rInf.GetCharAttr(); |
| const IDocumentSettingAccess* pIDSA = pFrm->GetTxtNode()->getIDocumentSettingAccess(); |
| SwFont *pNumFnt = new SwFont( pParSet, pIDSA ); |
| |
| // --> FME 2005-02-17 #i37142# |
| // Underline style of paragraph font should not be considered |
| // Overline style of paragraph font should not be considered |
| // Weight style of paragraph font should not be considered |
| // Posture style of paragraph font should not be considered |
| // See also #i18463# and SwTxtFormatter::NewNumberPortion() |
| pNumFnt->SetUnderline( UNDERLINE_NONE ); |
| pNumFnt->SetOverline( UNDERLINE_NONE ); |
| pNumFnt->SetItalic( ITALIC_NONE, SW_LATIN ); |
| pNumFnt->SetItalic( ITALIC_NONE, SW_CJK ); |
| pNumFnt->SetItalic( ITALIC_NONE, SW_CTL ); |
| pNumFnt->SetWeight( WEIGHT_NORMAL, SW_LATIN ); |
| pNumFnt->SetWeight( WEIGHT_NORMAL, SW_CJK ); |
| pNumFnt->SetWeight( WEIGHT_NORMAL, SW_CTL ); |
| // <-- |
| |
| pNumFnt->SetDiffFnt(&rSet, pIDSA ); |
| pNumFnt->SetVertical( pNumFnt->GetOrientation(), pFrm->IsVertical() ); |
| |
| SwFtnNumPortion* pNewPor = new SwFtnNumPortion( aFtnTxt, pNumFnt ); |
| pNewPor->SetLeft( !pFrm->IsRightToLeft() ); |
| return pNewPor; |
| } |
| |
| /************************************************************************* |
| * SwTxtFormatter::NewErgoSumPortion() |
| *************************************************************************/ |
| |
| XubString lcl_GetPageNumber( const SwPageFrm* pPage ) |
| { |
| ASSERT( pPage, "GetPageNumber: Homeless TxtFrm" ); |
| MSHORT nVirtNum = pPage->GetVirtPageNum(); |
| const SvxNumberType& rNum = pPage->GetPageDesc()->GetNumType(); |
| return rNum.GetNumStr( nVirtNum ); |
| } |
| |
| SwErgoSumPortion *SwTxtFormatter::NewErgoSumPortion( SwTxtFormatInfo &rInf ) const |
| { |
| // Wir koennen nicht davon ausgehen, dass wir ein Follow sind |
| // 7983: GetIdx() nicht nStart |
| if( !pFrm->IsInFtn() || pFrm->GetPrev() || |
| rInf.IsErgoDone() || rInf.GetIdx() != pFrm->GetOfst() || |
| pFrm->ImplFindFtnFrm()->GetAttr()->GetFtn().IsEndNote() ) |
| return 0; |
| |
| // Aha, wir sind also im Fussnotenbereich |
| const SwFtnInfo &rFtnInfo = pFrm->GetNode()->GetDoc()->GetFtnInfo(); |
| SwTxtFrm *pQuoFrm = pFrm->FindQuoVadisFrm(); |
| if( !pQuoFrm ) |
| return 0; |
| const SwPageFrm* pPage = pFrm->FindPageFrm(); |
| const SwPageFrm* pQuoPage = pQuoFrm->FindPageFrm(); |
| if( pPage == pQuoFrm->FindPageFrm() ) |
| return 0; // Wenn der QuoVadis auf der selben (spaltigen) Seite steht |
| const XubString aPage = lcl_GetPageNumber( pPage ); |
| SwParaPortion *pPara = pQuoFrm->GetPara(); |
| if( pPara ) |
| pPara->SetErgoSumNum( aPage ); |
| if( !rFtnInfo.aErgoSum.Len() ) |
| return 0; |
| SwErgoSumPortion *pErgo = new SwErgoSumPortion( rFtnInfo.aErgoSum, |
| lcl_GetPageNumber( pQuoPage ) ); |
| return pErgo; |
| } |
| |
| /************************************************************************* |
| * SwTxtFormatter::FormatQuoVadis() |
| *************************************************************************/ |
| |
| xub_StrLen SwTxtFormatter::FormatQuoVadis( const xub_StrLen nOffset ) |
| { |
| ASSERT( ! pFrm->IsVertical() || ! pFrm->IsSwapped(), |
| "SwTxtFormatter::FormatQuoVadis with swapped frame" ); |
| |
| if( !pFrm->IsInFtn() || pFrm->ImplFindFtnFrm()->GetAttr()->GetFtn().IsEndNote() ) |
| return nOffset; |
| |
| const SwFrm* pErgoFrm = pFrm->FindFtnFrm()->GetFollow(); |
| if( !pErgoFrm && pFrm->HasFollow() ) |
| pErgoFrm = pFrm->GetFollow(); |
| if( !pErgoFrm ) |
| return nOffset; |
| |
| if( pErgoFrm == pFrm->GetNext() ) |
| { |
| SwFrm *pCol = pFrm->FindColFrm(); |
| while( pCol && !pCol->GetNext() ) |
| pCol = pCol->GetUpper()->FindColFrm(); |
| if( pCol ) |
| return nOffset; |
| } |
| else |
| { |
| const SwPageFrm* pPage = pFrm->FindPageFrm(); |
| const SwPageFrm* pErgoPage = pErgoFrm->FindPageFrm(); |
| if( pPage == pErgoPage ) |
| return nOffset; // Wenn der ErgoSum auf der selben Seite steht |
| } |
| |
| SwTxtFormatInfo &rInf = GetInfo(); |
| const SwFtnInfo &rFtnInfo = pFrm->GetNode()->GetDoc()->GetFtnInfo(); |
| if( !rFtnInfo.aQuoVadis.Len() ) |
| return nOffset; |
| |
| // Ein Wort zu QuoVadis/ErgoSum: |
| // Fuer diese Texte wird der am Absatz eingestellte Font verwendet. |
| // Wir initialisieren uns also: |
| // ResetFont(); |
| FeedInf( rInf ); |
| SeekStartAndChg( rInf, sal_True ); |
| if( GetRedln() && pCurr->HasRedline() ) |
| GetRedln()->Seek( *pFnt, nOffset, 0 ); |
| |
| // Ein fieser Sonderfall: Flyfrms reichen in die Zeile und stehen |
| // natuerlich da, wo wir unseren Quovadis Text reinsetzen wollen. |
| // Erst mal sehen, ob es so schlimm ist: |
| SwLinePortion *pPor = pCurr->GetFirstPortion(); |
| KSHORT nLastLeft = 0; |
| while( pPor ) |
| { |
| if ( pPor->IsFlyPortion() ) |
| nLastLeft = ( (SwFlyPortion*) pPor)->Fix() + |
| ( (SwFlyPortion*) pPor)->Width(); |
| pPor = pPor->GetPortion(); |
| } |
| // Das alte Spiel: wir wollen, dass die Zeile an einer bestimmten |
| // Stelle umbricht, also beeinflussen wir die Width. |
| // nLastLeft ist jetzt quasi der rechte Rand. |
| const KSHORT nOldRealWidth = rInf.RealWidth(); |
| rInf.RealWidth( nOldRealWidth - nLastLeft ); |
| |
| XubString aErgo = lcl_GetPageNumber( pErgoFrm->FindPageFrm() ); |
| SwQuoVadisPortion *pQuo = new SwQuoVadisPortion(rFtnInfo.aQuoVadis, aErgo ); |
| pQuo->SetAscent( rInf.GetAscent() ); |
| pQuo->Height( rInf.GetTxtHeight() ); |
| pQuo->Format( rInf ); |
| sal_uInt16 nQuoWidth = pQuo->Width(); |
| SwLinePortion* pCurrPor = pQuo; |
| |
| while ( rInf.GetRest() ) |
| { |
| SwLinePortion* pFollow = rInf.GetRest(); |
| rInf.SetRest( 0 ); |
| pCurrPor->Move( rInf ); |
| |
| ASSERT( pFollow->IsQuoVadisPortion(), |
| "Quo Vadis, rest of QuoVadisPortion" ) |
| |
| // format the rest and append it to the other QuoVadis parts |
| pFollow->Format( rInf ); |
| nQuoWidth = nQuoWidth + pFollow->Width(); |
| |
| pCurrPor->Append( pFollow ); |
| pCurrPor = pFollow; |
| } |
| |
| nLastLeft = nOldRealWidth - nQuoWidth; |
| Right( Right() - nQuoWidth ); |
| |
| SWAP_IF_NOT_SWAPPED( pFrm ) |
| |
| const xub_StrLen nRet = FormatLine( nStart ); |
| |
| UNDO_SWAP( pFrm ) |
| |
| Right( rInf.Left() + nOldRealWidth - 1 ); |
| |
| nLastLeft = nOldRealWidth - pCurr->Width(); |
| FeedInf( rInf ); |
| |
| // Es kann durchaus sein, dass am Ende eine Marginportion steht, |
| // die beim erneuten Aufspannen nur Aerger bereiten wuerde. |
| pPor = pCurr->FindLastPortion(); |
| SwGluePortion *pGlue = pPor->IsMarginPortion() ? |
| (SwMarginPortion*) pPor : 0; |
| if( pGlue ) |
| { |
| pGlue->Height( 0 ); |
| pGlue->Width( 0 ); |
| pGlue->SetLen( 0 ); |
| pGlue->SetAscent( 0 ); |
| pGlue->SetPortion( NULL ); |
| pGlue->SetFixWidth(0); |
| } |
| |
| // Luxus: Wir sorgen durch das Aufspannen von Glues dafuer, |
| // dass der QuoVadis-Text rechts erscheint: |
| nLastLeft = nLastLeft - nQuoWidth; |
| if( nLastLeft ) |
| { |
| if( nLastLeft > pQuo->GetAscent() ) // Mindestabstand |
| { |
| switch( GetAdjust() ) |
| { |
| case SVX_ADJUST_BLOCK: |
| { |
| if( !pCurr->GetLen() || |
| CH_BREAK != GetInfo().GetChar(nStart+pCurr->GetLen()-1)) |
| nLastLeft = pQuo->GetAscent(); |
| nQuoWidth = nQuoWidth + nLastLeft; |
| break; |
| } |
| case SVX_ADJUST_RIGHT: |
| { |
| nLastLeft = pQuo->GetAscent(); |
| nQuoWidth = nQuoWidth + nLastLeft; |
| break; |
| } |
| case SVX_ADJUST_CENTER: |
| { |
| nQuoWidth = nQuoWidth + pQuo->GetAscent(); |
| long nDiff = nLastLeft - nQuoWidth; |
| if( nDiff < 0 ) |
| { |
| nLastLeft = pQuo->GetAscent(); |
| nQuoWidth = (sal_uInt16)(-nDiff + nLastLeft); |
| } |
| else |
| { |
| nQuoWidth = 0; |
| nLastLeft = sal_uInt16(( pQuo->GetAscent() + nDiff ) / 2); |
| } |
| break; |
| } |
| default: |
| nQuoWidth = nQuoWidth + nLastLeft; |
| } |
| } |
| else |
| nQuoWidth = nQuoWidth + nLastLeft; |
| if( nLastLeft ) |
| { |
| pGlue = new SwGluePortion(0); |
| pGlue->Width( nLastLeft ); |
| pPor->Append( pGlue ); |
| pPor = pPor->GetPortion(); |
| } |
| } |
| |
| // Jetzt aber: die QuoVadis-Portion wird angedockt: |
| pCurrPor = pQuo; |
| while ( pCurrPor ) |
| { |
| // pPor->Append deletes the pPortoin pointer of pPor. Therefore |
| // we have to keep a pointer to the next portion |
| pQuo = (SwQuoVadisPortion*)pCurrPor->GetPortion(); |
| pPor->Append( pCurrPor ); |
| pPor = pPor->GetPortion(); |
| pCurrPor = pQuo; |
| } |
| |
| pCurr->Width( pCurr->Width() + KSHORT( nQuoWidth ) ); |
| |
| // Und noch einmal adjustieren wegen des Adjustment und nicht zu Letzt |
| // wegen folgendem Sonderfall: In der Zeile hat der DummUser durchgaengig |
| // einen kleineren Font eingestellt als der vom QuoVadis-Text ... |
| CalcAdjustLine( pCurr ); |
| |
| #if OSL_DEBUG_LEVEL > 1 |
| if( OPTDBG( rInf ) ) |
| { |
| // aDbstream << "FormatQuoVadis:" << endl; |
| // pCurr->DebugPortions( aDbstream, rInf.GetTxt(), nStart ); |
| } |
| #endif |
| |
| // Uff... |
| return nRet; |
| } |
| |
| |
| /************************************************************************* |
| * SwTxtFormatter::MakeDummyLine() |
| *************************************************************************/ |
| |
| // MakeDummyLine() erzeugt eine Line, die bis zum unteren Seitenrand |
| // reicht. DummyLines bzw. DummyPortions sorgen dafuer, dass Oszillationen |
| // zum stehen kommen, weil Rueckflussmoeglichkeiten genommen werden. |
| // Sie werden bei absatzgebundenen Frames in Fussnoten und bei Ftn- |
| // Oszillationen verwendet. |
| |
| void SwTxtFormatter::MakeDummyLine() |
| { |
| KSHORT nRstHeight = GetFrmRstHeight(); |
| if( pCurr && nRstHeight > pCurr->Height() ) |
| { |
| SwLineLayout *pLay = new SwLineLayout; |
| nRstHeight = nRstHeight - pCurr->Height(); |
| pLay->Height( nRstHeight ); |
| pLay->SetAscent( nRstHeight ); |
| Insert( pLay ); |
| Next(); |
| } |
| } |
| |
| /************************************************************************* |
| * class SwFtnSave |
| *************************************************************************/ |
| class SwFtnSave |
| { |
| SwTxtSizeInfo *pInf; |
| SwFont *pFnt; |
| SwFont *pOld; |
| public: |
| SwFtnSave( const SwTxtSizeInfo &rInf, |
| const SwTxtFtn *pTxtFtn, |
| const bool bApplyGivenScriptType, |
| const sal_uInt8 nGivenScriptType ); |
| ~SwFtnSave(); |
| }; |
| |
| /************************************************************************* |
| * SwFtnSave::SwFtnSave() |
| *************************************************************************/ |
| |
| SwFtnSave::SwFtnSave( const SwTxtSizeInfo &rInf, |
| const SwTxtFtn* pTxtFtn, |
| const bool bApplyGivenScriptType, |
| const sal_uInt8 nGivenScriptType ) |
| : pInf( &((SwTxtSizeInfo&)rInf) ) |
| , pFnt( 0 ) |
| , pOld( 0 ) |
| { |
| if( pTxtFtn && rInf.GetTxtFrm() ) |
| { |
| pFnt = ((SwTxtSizeInfo&)rInf).GetFont(); |
| pOld = new SwFont( *pFnt ); |
| pOld->GetTox() = pFnt->GetTox(); |
| pFnt->GetTox() = 0; |
| SwFmtFtn& rFtn = (SwFmtFtn&)pTxtFtn->GetFtn(); |
| const SwDoc *pDoc = rInf.GetTxtFrm()->GetNode()->GetDoc(); |
| |
| // --> OD 2009-01-29 #i98418# |
| if ( bApplyGivenScriptType ) |
| { |
| pFnt->SetActual( nGivenScriptType ); |
| } |
| else |
| { |
| // examine text and set script |
| String aTmpStr( rFtn.GetViewNumStr( *pDoc ) ); |
| pFnt->SetActual( SwScriptInfo::WhichFont( 0, &aTmpStr, 0 ) ); |
| } |
| // <-- |
| |
| const SwEndNoteInfo* pInfo; |
| if( rFtn.IsEndNote() ) |
| pInfo = &pDoc->GetEndNoteInfo(); |
| else |
| pInfo = &pDoc->GetFtnInfo(); |
| const SwAttrSet& rSet = pInfo->GetAnchorCharFmt((SwDoc&)*pDoc)->GetAttrSet(); |
| pFnt->SetDiffFnt( &rSet, rInf.GetTxtFrm()->GetNode()->getIDocumentSettingAccess() ); |
| |
| // we reduce footnote size, if we are inside a double line portion |
| if ( ! pOld->GetEscapement() && 50 == pOld->GetPropr() ) |
| { |
| Size aSize = pFnt->GetSize( pFnt->GetActual() ); |
| pFnt->SetSize( Size( (long)aSize.Width() / 2, |
| (long)aSize.Height() / 2 ), |
| pFnt->GetActual() ); |
| } |
| |
| // set the correct rotation at the footnote font |
| const SfxPoolItem* pItem; |
| if( SFX_ITEM_SET == rSet.GetItemState( RES_CHRATR_ROTATE, |
| sal_True, &pItem )) |
| pFnt->SetVertical( ((SvxCharRotateItem*)pItem)->GetValue(), |
| rInf.GetTxtFrm()->IsVertical() ); |
| |
| pFnt->ChgPhysFnt( pInf->GetVsh(), *pInf->GetOut() ); |
| |
| if( SFX_ITEM_SET == rSet.GetItemState( RES_CHRATR_BACKGROUND, |
| sal_True, &pItem )) |
| pFnt->SetBackColor( new Color( ((SvxBrushItem*)pItem)->GetColor() ) ); |
| } |
| else |
| pFnt = NULL; |
| } |
| |
| /************************************************************************* |
| * SwFtnSave::~SwFtnSave() |
| *************************************************************************/ |
| |
| SwFtnSave::~SwFtnSave() |
| { |
| if( pFnt ) |
| { |
| // SwFont zurueckstellen |
| *pFnt = *pOld; |
| pFnt->GetTox() = pOld->GetTox(); |
| pFnt->ChgPhysFnt( pInf->GetVsh(), *pInf->GetOut() ); |
| delete pOld; |
| } |
| } |
| |
| /************************************************************************* |
| * SwFtnPortion::SwFtnPortion() |
| *************************************************************************/ |
| |
| SwFtnPortion::SwFtnPortion( const XubString &rExpand, SwTxtFrm *pFrame, |
| SwTxtFtn *pFootn, KSHORT nReal ) |
| : SwFldPortion( rExpand, 0 ) |
| , pFrm(pFrame) |
| , pFtn(pFootn) |
| , nOrigHeight( nReal ) |
| // --> OD 2009-01-29 #i98418# |
| , mbPreferredScriptTypeSet( false ) |
| , mnPreferredScriptType( SW_LATIN ) |
| // <-- |
| { |
| SetLen(1); |
| SetWhichPor( POR_FTN ); |
| } |
| |
| /************************************************************************* |
| * SwFtnPortion::GetExpTxt() |
| *************************************************************************/ |
| |
| sal_Bool SwFtnPortion::GetExpTxt( const SwTxtSizeInfo &, XubString &rTxt ) const |
| { |
| rTxt = aExpand; |
| return sal_True; |
| } |
| |
| /************************************************************************* |
| * virtual SwFtnPortion::Format() |
| *************************************************************************/ |
| |
| sal_Bool SwFtnPortion::Format( SwTxtFormatInfo &rInf ) |
| { |
| // --> OD 2009-01-29 #i98418# |
| // SwFtnSave aFtnSave( rInf, pFtn ); |
| SwFtnSave aFtnSave( rInf, pFtn, mbPreferredScriptTypeSet, mnPreferredScriptType ); |
| // <-- |
| // the idx is manipulated in SwExpandPortion::Format |
| // this flag indicates, that a footnote is allowed to trigger |
| // an underflow during SwTxtGuess::Guess |
| rInf.SetFakeLineStart( rInf.GetIdx() > rInf.GetLineStart() ); |
| sal_Bool bFull = SwFldPortion::Format( rInf ); |
| rInf.SetFakeLineStart( sal_False ); |
| SetAscent( rInf.GetAscent() ); |
| Height( rInf.GetTxtHeight() ); |
| rInf.SetFtnDone( !bFull ); |
| if( !bFull ) |
| rInf.SetParaFtn(); |
| return bFull; |
| } |
| |
| /************************************************************************* |
| * virtual SwFtnPortion::Paint() |
| *************************************************************************/ |
| |
| void SwFtnPortion::Paint( const SwTxtPaintInfo &rInf ) const |
| { |
| // --> OD 2009-01-29 #i98418# |
| // SwFtnSave aFtnSave( rInf, pFtn ); |
| SwFtnSave aFtnSave( rInf, pFtn, mbPreferredScriptTypeSet, mnPreferredScriptType ); |
| // <-- |
| rInf.DrawViewOpt( *this, POR_FTN ); |
| SwExpandPortion::Paint( rInf ); |
| } |
| |
| /************************************************************************* |
| * virtual SwFtnPortion::GetTxtSize() |
| *************************************************************************/ |
| |
| SwPosSize SwFtnPortion::GetTxtSize( const SwTxtSizeInfo &rInfo ) const |
| { |
| // --> OD 2009-01-29 #i98418# |
| // SwFtnSave aFtnSave( rInfo, pFtn ); |
| SwFtnSave aFtnSave( rInfo, pFtn, mbPreferredScriptTypeSet, mnPreferredScriptType ); |
| // <-- |
| return SwExpandPortion::GetTxtSize( rInfo ); |
| } |
| |
| // --> OD 2009-01-29 #i98418# |
| void SwFtnPortion::SetPreferredScriptType( sal_uInt8 nPreferredScriptType ) |
| { |
| mbPreferredScriptTypeSet = true; |
| mnPreferredScriptType = nPreferredScriptType; |
| } |
| // <-- |
| |
| /************************************************************************* |
| * class SwQuoVadisPortion |
| *************************************************************************/ |
| |
| SwFldPortion *SwQuoVadisPortion::Clone( const XubString &rExpand ) const |
| { return new SwQuoVadisPortion( rExpand, aErgo ); } |
| |
| SwQuoVadisPortion::SwQuoVadisPortion( const XubString &rExp, const XubString& rStr ) |
| : SwFldPortion( rExp ), aErgo(rStr) |
| { |
| SetLen(0); |
| SetWhichPor( POR_QUOVADIS ); |
| } |
| |
| /************************************************************************* |
| * virtual SwQuoVadisPortion::Format() |
| *************************************************************************/ |
| |
| sal_Bool SwQuoVadisPortion::Format( SwTxtFormatInfo &rInf ) |
| { |
| // erster Versuch, vielleicht passt der Text |
| CheckScript( rInf ); |
| sal_Bool bFull = SwFldPortion::Format( rInf ); |
| SetLen( 0 ); |
| |
| if( bFull ) |
| { |
| // zweiter Versuch, wir kuerzen den String: |
| aExpand = XubString( "...", RTL_TEXTENCODING_MS_1252 ); |
| bFull = SwFldPortion::Format( rInf ); |
| SetLen( 0 ); |
| if( bFull ) |
| // dritter Versuch, es langt: jetzt wird gestaucht: |
| Width( sal_uInt16(rInf.Width() - rInf.X()) ); |
| |
| // 8317: keine mehrzeiligen Felder bei QuoVadis und ErgoSum |
| if( rInf.GetRest() ) |
| { |
| delete rInf.GetRest(); |
| rInf.SetRest( 0 ); |
| } |
| } |
| return bFull; |
| } |
| |
| /************************************************************************* |
| * virtual SwQuoVadisPortion::GetExpTxt() |
| *************************************************************************/ |
| |
| sal_Bool SwQuoVadisPortion::GetExpTxt( const SwTxtSizeInfo &, XubString &rTxt ) const |
| { |
| rTxt = aExpand; |
| // if this QuoVadisPortion has a follow, the follow is responsible for |
| // the ergo text. |
| if ( ! HasFollow() ) |
| rTxt += aErgo; |
| return sal_True; |
| } |
| |
| /************************************************************************* |
| * virtual SwQuoVadisPortion::HandlePortion() |
| *************************************************************************/ |
| |
| void SwQuoVadisPortion::HandlePortion( SwPortionHandler& rPH ) const |
| { |
| String aString( aExpand ); |
| aString += aErgo; |
| rPH.Special( GetLen(), aString, GetWhichPor() ); |
| } |
| |
| /************************************************************************* |
| * virtual SwQuoVadisPortion::Paint() |
| *************************************************************************/ |
| |
| void SwQuoVadisPortion::Paint( const SwTxtPaintInfo &rInf ) const |
| { |
| // Wir wollen _immer_ per DrawStretchText ausgeben, |
| // weil nErgo schnell mal wechseln kann. |
| if( PrtWidth() ) |
| { |
| rInf.DrawViewOpt( *this, POR_QUOVADIS ); |
| SwTxtSlot aDiffTxt( &rInf, this, true, false ); |
| SwFontSave aSave( rInf, pFnt ); |
| rInf.DrawText( *this, rInf.GetLen(), sal_True ); |
| } |
| } |
| |
| /************************************************************************* |
| * class SwErgoSumPortion |
| *************************************************************************/ |
| |
| SwFldPortion *SwErgoSumPortion::Clone( const XubString &rExpand ) const |
| { |
| UniString aTmp; // = UniString::CreateFromInt32( 0 ); |
| return new SwErgoSumPortion( rExpand, aTmp ); |
| } |
| |
| SwErgoSumPortion::SwErgoSumPortion( const XubString &rExp, const XubString& rStr ) |
| : SwFldPortion( rExp ) |
| { |
| SetLen(0); |
| aExpand += rStr; |
| |
| // 7773: sinnvolle Massnahme: ein Blank Abstand zum Text |
| aExpand += ' '; |
| SetWhichPor( POR_ERGOSUM ); |
| } |
| |
| xub_StrLen SwErgoSumPortion::GetCrsrOfst( const KSHORT ) const |
| { |
| return 0; |
| } |
| |
| /************************************************************************* |
| * virtual SwErgoSumPortion::Format() |
| *************************************************************************/ |
| |
| sal_Bool SwErgoSumPortion::Format( SwTxtFormatInfo &rInf ) |
| { |
| sal_Bool bFull = SwFldPortion::Format( rInf ); |
| SetLen( 0 ); |
| rInf.SetErgoDone( sal_True ); |
| |
| // 8317: keine mehrzeiligen Felder bei QuoVadis und ErgoSum |
| if( bFull && rInf.GetRest() ) |
| { |
| delete rInf.GetRest(); |
| rInf.SetRest( 0 ); |
| } |
| |
| // We return false in order to get some text into the current line, |
| // even if it's full (better than looping) |
| return sal_False; |
| } |
| |
| |
| /************************************************************************* |
| * SwParaPortion::SetErgoSumNum() |
| *************************************************************************/ |
| |
| void SwParaPortion::SetErgoSumNum( const XubString& rErgo ) |
| { |
| SwLineLayout *pLay = this; |
| while( pLay->GetNext() ) |
| { |
| DBG_LOOP; |
| pLay = pLay->GetNext(); |
| } |
| SwLinePortion *pPor = pLay; |
| SwQuoVadisPortion *pQuo = 0; |
| while( pPor && !pQuo ) |
| { |
| if ( pPor->IsQuoVadisPortion() ) |
| pQuo = (SwQuoVadisPortion*)pPor; |
| pPor = pPor->GetPortion(); |
| } |
| if( pQuo ) |
| pQuo->SetNumber( rErgo ); |
| } |
| |
| /************************************************************************* |
| * SwParaPortion::UpdateQuoVadis() |
| * |
| * Wird im SwTxtFrm::Prepare() gerufen |
| *************************************************************************/ |
| |
| sal_Bool SwParaPortion::UpdateQuoVadis( const XubString &rQuo ) |
| { |
| SwLineLayout *pLay = this; |
| while( pLay->GetNext() ) |
| { |
| DBG_LOOP; |
| pLay = pLay->GetNext(); |
| } |
| SwLinePortion *pPor = pLay; |
| SwQuoVadisPortion *pQuo = 0; |
| while( pPor && !pQuo ) |
| { |
| if ( pPor->IsQuoVadisPortion() ) |
| pQuo = (SwQuoVadisPortion*)pPor; |
| pPor = pPor->GetPortion(); |
| } |
| |
| if( !pQuo ) |
| return sal_False; |
| |
| return pQuo->GetQuoTxt() == rQuo; |
| } |
| |
| |
| |