/************************************************************** * * 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 #include #include #include #include #include #include #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* 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::FirstElement(*(SwCntntNode*)pNd) != 0); else if ( pNd->IsTableNode() ) bFound = ( SwIterator::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::FirstElement(*(SwCntntNode*)pNd) != 0); else if ( pNd->IsTableNode() ) bFound = ( SwIterator::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( *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(pFrm)->Lower() && !static_cast(pFrm)->Lower()->IsFlowFrm() && static_cast(pFrm)->Lower()->IsLayoutFrm() ) { pFrm = static_cast(pFrm)->Lower(); } ASSERT( pFrm->IsLayoutFrm(), " - expected upper frame isn't a layout frame." ); rpFrm = bMaster ? NULL : static_cast(pFrm)->Lower(); ASSERT( !rpFrm || rpFrm->IsFlowFrm(), " - expected sibling isn't a flow frame." ); return static_cast(pFrm); } pUpper = new SwSectionFrm(((SwSectionNode*)pNode)->GetSection(), rpFrm); pUpper->Paste( rpFrm->GetUpper(), bMaster ? rpFrm : rpFrm->GetNext() ); static_cast(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(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 ); }