summaryrefslogtreecommitdiff
path: root/sw/source/core/docnode/node2lay.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/core/docnode/node2lay.cxx')
-rw-r--r--sw/source/core/docnode/node2lay.cxx405
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 );
+}
+
+