diff options
Diffstat (limited to 'sw/source/core/docnode/node2lay.cxx')
-rw-r--r-- | sw/source/core/docnode/node2lay.cxx | 405 |
1 files changed, 405 insertions, 0 deletions
diff --git a/sw/source/core/docnode/node2lay.cxx b/sw/source/core/docnode/node2lay.cxx new file mode 100644 index 000000000000..cce0919e1e1a --- /dev/null +++ b/sw/source/core/docnode/node2lay.cxx @@ -0,0 +1,405 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <calbck.hxx> // SwClientIter +#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 +{ + SwClientIter *pIter; // Der eigentliche Iterator + SvPtrarr *pUpperFrms;// Zum Einsammeln der Upper + ULONG nIndex; // Der Index des einzufuegenden Nodes + BOOL bMaster : 1; // TRUE => nur Master , FALSE => nur Frames ohne Follow + BOOL bInit : 1; // Ist am SwClient bereits ein First()-Aufruf erfolgt? +public: + SwNode2LayImpl( const SwNode& rNode, ULONG nIdx, 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, ULONG nStt, ULONG nEnd ); + + SwFrm* GetFrm( const Point* pDocPos = 0, + const SwPosition *pPos = 0, + const BOOL bCalcFrm = TRUE ) const; +}; + +/* -----------------25.02.99 10:38------------------- + * Hauptaufgabe des Ctor: Das richtige SwModify zu ermitteln, + * ueber das iteriert wird. + * Uebergibt man bSearch == 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. + * --------------------------------------------------*/ + +SwNode2LayImpl::SwNode2LayImpl( const SwNode& rNode, ULONG nIdx, BOOL bSearch ) + : pUpperFrms( NULL ), nIndex( nIdx ), bInit( 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 = rNode.GetNodes().GoPreviousWithFrm( &aTmp ); + if( !bSearch && pNd && rNode.GetIndex() > pNd->GetIndex() ) + pNd = NULL; // Nicht ueber den Bereich hinausschiessen + bMaster = FALSE; + } + else + { + SwNodeIndex aTmp( rNode, -1 ); + pNd = rNode.GetNodes().GoNextWithFrm( &aTmp ); + bMaster = TRUE; + if( !bSearch && pNd && rNode.EndOfSectionIndex() < pNd->GetIndex() ) + pNd = NULL; // Nicht ueber den Bereich hinausschiessen + } + } + else + { + pNd = &rNode; + bMaster = nIndex < rNode.GetIndex(); + } + if( pNd ) + { + SwModify *pMod; + if( pNd->IsCntntNode() ) + pMod = (SwModify*)pNd->GetCntntNode(); + else + { + ASSERT( pNd->IsTableNode(), "For Tablenodes only" ); + pMod = pNd->GetTableNode()->GetTable().GetFrmFmt(); + } + pIter = new SwClientIter( *pMod ); + } + else + pIter = NULL; +} + +/* -----------------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 FALSE; + if( !bInit ) + { + pRet = (SwFrm*)pIter->First(TYPE(SwFrm)); + bInit = TRUE; + } + else + pRet = (SwFrm*)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 = (SwFrm*)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; +} + +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()); + 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, ULONG nStt, ULONG nEnd ) +{ + ASSERT( pUpperFrms, "RestoreUpper without SaveUpper?" ) + SwNode* pNd; + SwDoc *pDoc = rNds.GetDoc(); + BOOL bFirst = TRUE; + for( ; nStt < nEnd; ++nStt ) + { + SwFrm* pNew = 0; + SwFrm* pNxt; + SwLayoutFrm* pUp; + if( (pNd = rNds[nStt])->IsCntntNode() ) + for( USHORT 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(); + pNew->Paste( pUp, pNxt ); + (*pUpperFrms)[n-2] = pNew; + } + else if( pNd->IsTableNode() ) + for( USHORT 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(); + ASSERT( pNew->IsTabFrm(), "Table exspected" ); + pNew->Paste( pUp, pNxt ); + ((SwTabFrm*)pNew)->RegistFlys(); + (*pUpperFrms)[x-2] = pNew; + } + else if( pNd->IsSectionNode() ) + { + nStt = pNd->EndOfSectionIndex(); + for( USHORT 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(), FALSE, nStt+1, pNxt ); + pNxt = pUp->GetLastLower(); + (*pUpperFrms)[x-2] = pNxt; + } + } + bFirst = FALSE; + } + for( USHORT 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 BOOL bCalcFrm ) const +{ + return pIter ? ::GetFrmOfModify( pIter->GetModify(), USHRT_MAX, + pDocPos, pPos, bCalcFrm ) + : 0; +} + +SwNode2Layout::SwNode2Layout( const SwNode& rNd, ULONG nIdx ) +{ + pImpl = new SwNode2LayImpl( rNd, nIdx, FALSE ); +} + +SwNode2Layout::SwNode2Layout( const SwNode& rNd ) +{ + pImpl = new SwNode2LayImpl( rNd, rNd.GetIndex(), TRUE ); + pImpl->SaveUpperFrms(); +} + +void SwNode2Layout::RestoreUpperFrms( SwNodes& rNds, ULONG nStt, 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 BOOL bCalcFrm ) const +{ + return pImpl->GetFrm( pDocPos, pPos, bCalcFrm ); +} + + |