| /************************************************************** |
| * |
| * 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 <switerator.hxx> |
| #include <calbck.hxx> |
| #include <node.hxx> |
| #include <ndindex.hxx> |
| #include <swtable.hxx> |
| #include <ftnfrm.hxx> |
| #include <sectfrm.hxx> |
| #include "frmfmt.hxx" |
| #include "cntfrm.hxx" |
| #include "tabfrm.hxx" |
| #include "frmtool.hxx" |
| #include "section.hxx" |
| #include "node2lay.hxx" |
| |
| /* -----------------25.02.99 10:31------------------- |
| * Die SwNode2LayImpl-Klasse erledigt die eigentliche Arbeit, |
| * die SwNode2Layout-Klasse ist nur die der Oefffentlichkeit bekannte Schnittstelle |
| * --------------------------------------------------*/ |
| class SwNode2LayImpl |
| { |
| SwIterator<SwFrm,SwModify>* pIter; |
| SwModify* pMod; |
| SvPtrarr *pUpperFrms;// Zum Einsammeln der Upper |
| sal_uLong nIndex; // Der Index des einzufuegenden Nodes |
| sal_Bool bMaster : 1; // sal_True => nur Master , sal_False => nur Frames ohne Follow |
| sal_Bool bInit : 1; // Ist am SwClient bereits ein First()-Aufruf erfolgt? |
| public: |
| SwNode2LayImpl( const SwNode& rNode, sal_uLong nIdx, sal_Bool bSearch ); |
| ~SwNode2LayImpl() { delete pIter; delete pUpperFrms; } |
| SwFrm* NextFrm(); // liefert den naechsten "sinnvollen" Frame |
| SwLayoutFrm* UpperFrm( SwFrm* &rpFrm, const SwNode &rNode ); |
| void SaveUpperFrms(); // Speichert (und lockt ggf.) die pUpper |
| // Fuegt unter jeden pUpper des Arrays einen Frame ein. |
| void RestoreUpperFrms( SwNodes& rNds, sal_uLong nStt, sal_uLong nEnd ); |
| |
| SwFrm* GetFrm( const Point* pDocPos = 0, |
| const SwPosition *pPos = 0, |
| const sal_Bool bCalcFrm = sal_True ) const; |
| }; |
| |
| /* -----------------25.02.99 10:38------------------- |
| * Hauptaufgabe des Ctor: Das richtige SwModify zu ermitteln, |
| * ueber das iteriert wird. |
| * Uebergibt man bSearch == sal_True, so wird der naechste Cntnt- oder TableNode |
| * gesucht, der Frames besitzt ( zum Einsammeln der pUpper ), ansonsten wird |
| * erwartet, das rNode bereits auf einem solchen Cntnt- oder TableNode sitzt, |
| * vor oder hinter den eingefuegt werden soll. |
| * --------------------------------------------------*/ |
| |
| SwNode* GoNextWithFrm(const SwNodes& rNodes, SwNodeIndex *pIdx) |
| { |
| if( pIdx->GetIndex() >= rNodes.Count() - 1 ) |
| return 0; |
| |
| SwNodeIndex aTmp(*pIdx, +1); |
| SwNode* pNd = 0; |
| while( aTmp < rNodes.Count()-1 ) |
| { |
| pNd = &aTmp.GetNode(); |
| bool bFound = false; |
| if ( pNd->IsCntntNode() ) |
| bFound = ( SwIterator<SwFrm,SwCntntNode>::FirstElement(*(SwCntntNode*)pNd) != 0); |
| else if ( pNd->IsTableNode() ) |
| bFound = ( SwIterator<SwFrm,SwFmt>::FirstElement(*((SwTableNode*)pNd)->GetTable().GetFrmFmt()) != 0 ); |
| else if( pNd->IsEndNode() && !pNd->StartOfSectionNode()->IsSectionNode() ) |
| { |
| pNd = 0; |
| break; |
| } |
| if ( bFound ) |
| break; |
| aTmp++; |
| } |
| |
| if( aTmp == rNodes.Count()-1 ) |
| pNd = 0; |
| else if( pNd ) |
| (*pIdx) = aTmp; |
| return pNd; |
| } |
| |
| SwNode* GoPreviousWithFrm(SwNodeIndex *pIdx) |
| { |
| if( !pIdx->GetIndex() ) |
| return 0; |
| |
| SwNodeIndex aTmp( *pIdx, -1 ); |
| SwNode* pNd(0); |
| while( aTmp.GetIndex() ) |
| { |
| pNd = &aTmp.GetNode(); |
| bool bFound = false; |
| if ( pNd->IsCntntNode() ) |
| bFound = ( SwIterator<SwFrm,SwCntntNode>::FirstElement(*(SwCntntNode*)pNd) != 0); |
| else if ( pNd->IsTableNode() ) |
| bFound = ( SwIterator<SwFrm,SwFmt>::FirstElement(*((SwTableNode*)pNd)->GetTable().GetFrmFmt()) != 0 ); |
| else if( pNd->IsStartNode() && !pNd->IsSectionNode() ) |
| { |
| pNd = 0; |
| break; |
| } |
| if ( bFound ) |
| break; |
| aTmp--; |
| } |
| |
| if( !aTmp.GetIndex() ) |
| pNd = 0; |
| else if( pNd ) |
| (*pIdx) = aTmp; |
| return pNd; |
| } |
| |
| |
| SwNode2LayImpl::SwNode2LayImpl( const SwNode& rNode, sal_uLong nIdx, sal_Bool bSearch ) |
| : pUpperFrms( NULL ), nIndex( nIdx ), bInit( sal_False ) |
| { |
| const SwNode* pNd; |
| if( bSearch || rNode.IsSectionNode() ) |
| { |
| // Suche den naechsten Cntnt/TblNode, der einen Frame besitzt, |
| // damit wir uns vor/hinter ihn haengen koennen |
| if( !bSearch && rNode.GetIndex() < nIndex ) |
| { |
| SwNodeIndex aTmp( *rNode.EndOfSectionNode(), +1 ); |
| pNd = GoPreviousWithFrm( &aTmp ); |
| if( !bSearch && pNd && rNode.GetIndex() > pNd->GetIndex() ) |
| pNd = NULL; // Nicht ueber den Bereich hinausschiessen |
| bMaster = sal_False; |
| } |
| else |
| { |
| SwNodeIndex aTmp( rNode, -1 ); |
| pNd = GoNextWithFrm( rNode.GetNodes(), &aTmp ); |
| bMaster = sal_True; |
| if( !bSearch && pNd && rNode.EndOfSectionIndex() < pNd->GetIndex() ) |
| pNd = NULL; // Nicht ueber den Bereich hinausschiessen |
| } |
| } |
| else |
| { |
| pNd = &rNode; |
| bMaster = nIndex < rNode.GetIndex(); |
| } |
| if( pNd ) |
| { |
| if( pNd->IsCntntNode() ) |
| pMod = (SwModify*)pNd->GetCntntNode(); |
| else |
| { |
| ASSERT( pNd->IsTableNode(), "For Tablenodes only" ); |
| pMod = pNd->GetTableNode()->GetTable().GetFrmFmt(); |
| } |
| pIter = new SwIterator<SwFrm,SwModify>( *pMod ); |
| } |
| else |
| { |
| pIter = NULL; |
| pMod = 0; |
| } |
| } |
| |
| /* -----------------25.02.99 10:41------------------- |
| * SwNode2LayImpl::NextFrm() liefert den naechsten "sinnvollen" Frame, |
| * beim ersten Aufruf wird am eigentlichen Iterator ein First gerufen, |
| * danach die Next-Methode. Das Ergebnis wird auf Brauchbarkeit untersucht, |
| * so werden keine Follows akzeptiert, ein Master wird beim Einsammeln der |
| * pUpper und beim Einfuegen vor ihm akzeptiert. Beim Einfuegen dahinter |
| * wird vom Master ausgehend der letzte Follow gesucht und zurueckgegeben. |
| * Wenn der Frame innerhalb eines SectionFrms liegt, wird noch festgestellt, |
| * ob statt des Frames der SectionFrm der geeignete Rueckgabewert ist, dies |
| * ist der Fall, wenn der neu einzufuegende Node ausserhalb des Bereichs liegt. |
| * --------------------------------------------------*/ |
| SwFrm* SwNode2LayImpl::NextFrm() |
| { |
| SwFrm* pRet; |
| if( !pIter ) |
| return NULL; |
| if( !bInit ) |
| { |
| pRet = pIter->First(); |
| bInit = sal_True; |
| } |
| else |
| pRet = pIter->Next(); |
| while( pRet ) |
| { |
| SwFlowFrm* pFlow = SwFlowFrm::CastFlowFrm( pRet ); |
| ASSERT( pFlow, "Cntnt or Table expected?!" ); |
| // Follows sind fluechtige Gestalten, deshalb werden sie ignoriert. |
| // Auch wenn wir hinter dem Frame eingefuegt werden sollen, nehmen wir |
| // zunaechst den Master, hangeln uns dann aber zum letzten Follow durch. |
| if( !pFlow->IsFollow() ) |
| { |
| if( !bMaster ) |
| { |
| while( pFlow->HasFollow() ) |
| pFlow = pFlow->GetFollow(); |
| pRet = pFlow->GetFrm(); |
| } |
| if( pRet->IsInSct() ) |
| { |
| SwSectionFrm* pSct = pRet->FindSctFrm(); |
| // Vorsicht: Wenn wir in einer Fussnote sind, so kann diese |
| // Layoutmaessig in einem spaltigen Bereich liegen, obwohl |
| // sie nodemaessig ausserhalb liegt. Deshalb muss bei Fussnoten |
| // ueberprueft werden, ob auch der SectionFrm in der Fussnote |
| // und nicht ausserhalb liegt. |
| if( !pRet->IsInFtn() || pSct->IsInFtn() ) |
| { |
| ASSERT( pSct && pSct->GetSection(), "Where's my section?" ); |
| SwSectionNode* pNd = pSct->GetSection()->GetFmt()->GetSectionNode(); |
| ASSERT( pNd, "Lost SectionNode" ); |
| // Wenn der erhaltene Frame in einem Bereichsframe steht, |
| // dessen Bereich den Ausgangsnode nicht umfasst, so kehren |
| // wir mit dem SectionFrm zurueck, sonst mit dem Cntnt/TabFrm |
| if( bMaster ) |
| { |
| if( pNd->GetIndex() >= nIndex ) |
| pRet = pSct; |
| } |
| else if( pNd->EndOfSectionIndex() < nIndex ) |
| pRet = pSct; |
| } |
| } |
| return pRet; |
| } |
| pRet = pIter->Next(); |
| } |
| return NULL; |
| } |
| |
| void SwNode2LayImpl::SaveUpperFrms() |
| { |
| pUpperFrms = new SvPtrarr( 0, 20 ); |
| SwFrm* pFrm; |
| while( 0 != (pFrm = NextFrm()) ) |
| { |
| SwFrm* pPrv = pFrm->GetPrev(); |
| pFrm = pFrm->GetUpper(); |
| if( pFrm ) |
| { |
| if( pFrm->IsFtnFrm() ) |
| ((SwFtnFrm*)pFrm)->ColLock(); |
| else if( pFrm->IsInSct() ) |
| pFrm->FindSctFrm()->ColLock(); |
| if( pPrv && pPrv->IsSctFrm() ) |
| ((SwSectionFrm*)pPrv)->LockJoin(); |
| pUpperFrms->Insert( (void*)pPrv, pUpperFrms->Count() ); |
| pUpperFrms->Insert( (void*)pFrm, pUpperFrms->Count() ); |
| } |
| } |
| delete pIter; |
| pIter = NULL; |
| pMod = 0; |
| } |
| |
| SwLayoutFrm* SwNode2LayImpl::UpperFrm( SwFrm* &rpFrm, const SwNode &rNode ) |
| { |
| rpFrm = NextFrm(); |
| if( !rpFrm ) |
| return NULL; |
| SwLayoutFrm* pUpper = rpFrm->GetUpper(); |
| if( rpFrm->IsSctFrm() ) |
| { |
| const SwNode* pNode = rNode.StartOfSectionNode(); |
| if( pNode->IsSectionNode() ) |
| { |
| SwFrm* pFrm = bMaster ? rpFrm->FindPrev() : rpFrm->FindNext(); |
| if( pFrm && pFrm->IsSctFrm() ) |
| { |
| // #137684#: pFrm could be a "dummy"-section |
| if( ((SwSectionFrm*)pFrm)->GetSection() && |
| (&((SwSectionNode*)pNode)->GetSection() == |
| ((SwSectionFrm*)pFrm)->GetSection()) ) |
| { |
| // OD 2004-06-02 #i22922# - consider columned sections |
| // 'Go down' the section frame as long as the layout frame |
| // is found, which would contain content. |
| while ( pFrm->IsLayoutFrm() && |
| static_cast<SwLayoutFrm*>(pFrm)->Lower() && |
| !static_cast<SwLayoutFrm*>(pFrm)->Lower()->IsFlowFrm() && |
| static_cast<SwLayoutFrm*>(pFrm)->Lower()->IsLayoutFrm() ) |
| { |
| pFrm = static_cast<SwLayoutFrm*>(pFrm)->Lower(); |
| } |
| ASSERT( pFrm->IsLayoutFrm(), |
| "<SwNode2LayImpl::UpperFrm(..)> - expected upper frame isn't a layout frame." ); |
| rpFrm = bMaster ? NULL |
| : static_cast<SwLayoutFrm*>(pFrm)->Lower(); |
| ASSERT( !rpFrm || rpFrm->IsFlowFrm(), |
| "<SwNode2LayImpl::UpperFrm(..)> - expected sibling isn't a flow frame." ); |
| return static_cast<SwLayoutFrm*>(pFrm); |
| } |
| |
| pUpper = new SwSectionFrm(((SwSectionNode*)pNode)->GetSection(), rpFrm); |
| pUpper->Paste( rpFrm->GetUpper(), |
| bMaster ? rpFrm : rpFrm->GetNext() ); |
| static_cast<SwSectionFrm*>(pUpper)->Init(); |
| rpFrm = NULL; |
| // 'Go down' the section frame as long as the layout frame |
| // is found, which would contain content. |
| while ( pUpper->Lower() && |
| !pUpper->Lower()->IsFlowFrm() && |
| pUpper->Lower()->IsLayoutFrm() ) |
| { |
| pUpper = static_cast<SwLayoutFrm*>(pUpper->Lower()); |
| } |
| return pUpper; |
| } |
| } |
| }; |
| if( !bMaster ) |
| rpFrm = rpFrm->GetNext(); |
| return pUpper; |
| } |
| |
| void SwNode2LayImpl::RestoreUpperFrms( SwNodes& rNds, sal_uLong nStt, sal_uLong nEnd ) |
| { |
| ASSERT( pUpperFrms, "RestoreUpper without SaveUpper?" ) |
| SwNode* pNd; |
| SwDoc *pDoc = rNds.GetDoc(); |
| sal_Bool bFirst = sal_True; |
| for( ; nStt < nEnd; ++nStt ) |
| { |
| SwFrm* pNew = 0; |
| SwFrm* pNxt; |
| SwLayoutFrm* pUp; |
| if( (pNd = rNds[nStt])->IsCntntNode() ) |
| for( sal_uInt16 n = 0; n < pUpperFrms->Count(); ) |
| { |
| pNxt = (SwFrm*)(*pUpperFrms)[n++]; |
| if( bFirst && pNxt && pNxt->IsSctFrm() ) |
| ((SwSectionFrm*)pNxt)->UnlockJoin(); |
| pUp = (SwLayoutFrm*)(*pUpperFrms)[n++]; |
| if( pNxt ) |
| pNxt = pNxt->GetNext(); |
| else |
| pNxt = pUp->Lower(); |
| pNew = ((SwCntntNode*)pNd)->MakeFrm( pUp ); |
| pNew->Paste( pUp, pNxt ); |
| (*pUpperFrms)[n-2] = pNew; |
| } |
| else if( pNd->IsTableNode() ) |
| for( sal_uInt16 x = 0; x < pUpperFrms->Count(); ) |
| { |
| pNxt = (SwFrm*)(*pUpperFrms)[x++]; |
| if( bFirst && pNxt && pNxt->IsSctFrm() ) |
| ((SwSectionFrm*)pNxt)->UnlockJoin(); |
| pUp = (SwLayoutFrm*)(*pUpperFrms)[x++]; |
| if( pNxt ) |
| pNxt = pNxt->GetNext(); |
| else |
| pNxt = pUp->Lower(); |
| pNew = ((SwTableNode*)pNd)->MakeFrm( pUp ); |
| ASSERT( pNew->IsTabFrm(), "Table exspected" ); |
| pNew->Paste( pUp, pNxt ); |
| ((SwTabFrm*)pNew)->RegistFlys(); |
| (*pUpperFrms)[x-2] = pNew; |
| } |
| else if( pNd->IsSectionNode() ) |
| { |
| nStt = pNd->EndOfSectionIndex(); |
| for( sal_uInt16 x = 0; x < pUpperFrms->Count(); ) |
| { |
| pNxt = (SwFrm*)(*pUpperFrms)[x++]; |
| if( bFirst && pNxt && pNxt->IsSctFrm() ) |
| ((SwSectionFrm*)pNxt)->UnlockJoin(); |
| pUp = (SwLayoutFrm*)(*pUpperFrms)[x++]; |
| ASSERT( pUp->GetUpper() || pUp->IsFlyFrm(), "Lost Upper" ); |
| ::_InsertCnt( pUp, pDoc, pNd->GetIndex(), sal_False, nStt+1, pNxt ); |
| pNxt = pUp->GetLastLower(); |
| (*pUpperFrms)[x-2] = pNxt; |
| } |
| } |
| bFirst = sal_False; |
| } |
| for( sal_uInt16 x = 0; x < pUpperFrms->Count(); ++x ) |
| { |
| SwFrm* pTmp = (SwFrm*)(*pUpperFrms)[++x]; |
| if( pTmp->IsFtnFrm() ) |
| ((SwFtnFrm*)pTmp)->ColUnlock(); |
| else if ( pTmp->IsInSct() ) |
| { |
| SwSectionFrm* pSctFrm = pTmp->FindSctFrm(); |
| pSctFrm->ColUnlock(); |
| // OD 26.08.2003 #i18103# - invalidate size of section in order to |
| // assure, that the section is formatted, unless it was 'Collocked' |
| // from its 'collection' until its 'restoration'. |
| pSctFrm->_InvalidateSize(); |
| } |
| } |
| } |
| |
| SwFrm* SwNode2LayImpl::GetFrm( const Point* pDocPos, |
| const SwPosition *pPos, |
| const sal_Bool bCalcFrm ) const |
| { |
| // mba: test if change of member pIter -> pMod broke anything |
| return pMod ? ::GetFrmOfModify( 0, *pMod, USHRT_MAX, pDocPos, pPos, bCalcFrm ) : 0; |
| } |
| |
| SwNode2Layout::SwNode2Layout( const SwNode& rNd, sal_uLong nIdx ) |
| { |
| pImpl = new SwNode2LayImpl( rNd, nIdx, sal_False ); |
| } |
| |
| SwNode2Layout::SwNode2Layout( const SwNode& rNd ) |
| { |
| pImpl = new SwNode2LayImpl( rNd, rNd.GetIndex(), sal_True ); |
| pImpl->SaveUpperFrms(); |
| } |
| |
| void SwNode2Layout::RestoreUpperFrms( SwNodes& rNds, sal_uLong nStt, sal_uLong nEnd ) |
| { |
| ASSERT( pImpl, "RestoreUpperFrms without SaveUpperFrms" ); |
| pImpl->RestoreUpperFrms( rNds, nStt, nEnd ); |
| } |
| |
| SwFrm* SwNode2Layout::NextFrm() |
| { |
| return pImpl->NextFrm(); |
| } |
| |
| SwLayoutFrm* SwNode2Layout::UpperFrm( SwFrm* &rpFrm, const SwNode &rNode ) |
| { |
| return pImpl->UpperFrm( rpFrm, rNode ); |
| } |
| |
| SwNode2Layout::~SwNode2Layout() |
| { |
| delete pImpl; |
| } |
| |
| SwFrm* SwNode2Layout::GetFrm( const Point* pDocPos, |
| const SwPosition *pPos, |
| const sal_Bool bCalcFrm ) const |
| { |
| return pImpl->GetFrm( pDocPos, pPos, bCalcFrm ); |
| } |
| |
| |