xref: /aoo42x/main/sw/source/core/docnode/node2lay.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sw.hxx"
30 
31 #include <switerator.hxx>
32 #include <calbck.hxx>
33 #include <node.hxx>
34 #include <ndindex.hxx>
35 #include <swtable.hxx>
36 #include <ftnfrm.hxx>
37 #include <sectfrm.hxx>
38 #include "frmfmt.hxx"
39 #include "cntfrm.hxx"
40 #include "tabfrm.hxx"
41 #include "frmtool.hxx"
42 #include "section.hxx"
43 #include "node2lay.hxx"
44 
45 /* -----------------25.02.99 10:31-------------------
46  * Die SwNode2LayImpl-Klasse erledigt die eigentliche Arbeit,
47  * die SwNode2Layout-Klasse ist nur die der Oefffentlichkeit bekannte Schnittstelle
48  * --------------------------------------------------*/
49 class SwNode2LayImpl
50 {
51 	SwIterator<SwFrm,SwModify>* pIter;
52     SwModify* pMod;
53 	SvPtrarr *pUpperFrms;// Zum Einsammeln der Upper
54 	sal_uLong nIndex;        // Der Index des einzufuegenden Nodes
55 	sal_Bool bMaster	: 1; // sal_True => nur Master , sal_False => nur Frames ohne Follow
56 	sal_Bool bInit		: 1; // Ist am SwClient bereits ein First()-Aufruf erfolgt?
57 public:
58 	SwNode2LayImpl( const SwNode& rNode, sal_uLong nIdx, sal_Bool bSearch );
59 	~SwNode2LayImpl() { delete pIter; delete pUpperFrms; }
60 	SwFrm* NextFrm(); // liefert den naechsten "sinnvollen" Frame
61 	SwLayoutFrm* UpperFrm( SwFrm* &rpFrm, const SwNode &rNode );
62 	void SaveUpperFrms(); // Speichert (und lockt ggf.) die pUpper
63 	// Fuegt unter jeden pUpper des Arrays einen Frame ein.
64 	void RestoreUpperFrms( SwNodes& rNds, sal_uLong nStt, sal_uLong nEnd );
65 
66 	SwFrm* GetFrm( const Point* pDocPos = 0,
67 					const SwPosition *pPos = 0,
68 					const sal_Bool bCalcFrm = sal_True ) const;
69 };
70 
71 /* -----------------25.02.99 10:38-------------------
72  * Hauptaufgabe des Ctor: Das richtige SwModify zu ermitteln,
73  * ueber das iteriert wird.
74  * Uebergibt man bSearch == sal_True, so wird der naechste Cntnt- oder TableNode
75  * gesucht, der Frames besitzt ( zum Einsammeln der pUpper ), ansonsten wird
76  * erwartet, das rNode bereits auf einem solchen Cntnt- oder TableNode sitzt,
77  * vor oder hinter den eingefuegt werden soll.
78  * --------------------------------------------------*/
79 
80 SwNode* GoNextWithFrm(const SwNodes& rNodes, SwNodeIndex *pIdx)
81 {
82 	if( pIdx->GetIndex() >= rNodes.Count() - 1 )
83 		return 0;
84 
85 	SwNodeIndex aTmp(*pIdx, +1);
86     SwNode* pNd = 0;
87 	while( aTmp < rNodes.Count()-1 )
88 	{
89 		pNd = &aTmp.GetNode();
90         bool bFound = false;
91 		if ( pNd->IsCntntNode() )
92 			bFound = ( SwIterator<SwFrm,SwCntntNode>::FirstElement(*(SwCntntNode*)pNd) != 0);
93 		else if ( pNd->IsTableNode() )
94 			bFound = ( SwIterator<SwFrm,SwFmt>::FirstElement(*((SwTableNode*)pNd)->GetTable().GetFrmFmt()) != 0 );
95         else if( pNd->IsEndNode() && !pNd->StartOfSectionNode()->IsSectionNode() )
96 		{
97 			pNd = 0;
98 			break;
99 		}
100 		if ( bFound )
101 				break;
102 		aTmp++;
103 	}
104 
105 	if( aTmp == rNodes.Count()-1 )
106 		pNd = 0;
107 	else if( pNd )
108 		(*pIdx) = aTmp;
109 	return pNd;
110 }
111 
112 SwNode* GoPreviousWithFrm(SwNodeIndex *pIdx)
113 {
114 	if( !pIdx->GetIndex() )
115 		return 0;
116 
117 	SwNodeIndex aTmp( *pIdx, -1 );
118 	SwNode* pNd(0);
119 	while( aTmp.GetIndex() )
120 	{
121 		pNd = &aTmp.GetNode();
122         bool bFound = false;
123 		if ( pNd->IsCntntNode() )
124 			bFound = ( SwIterator<SwFrm,SwCntntNode>::FirstElement(*(SwCntntNode*)pNd) != 0);
125 		else if ( pNd->IsTableNode() )
126 			bFound = ( SwIterator<SwFrm,SwFmt>::FirstElement(*((SwTableNode*)pNd)->GetTable().GetFrmFmt()) != 0 );
127 		else if( pNd->IsStartNode() && !pNd->IsSectionNode() )
128 		{
129 			pNd = 0;
130 			break;
131 		}
132 		if ( bFound )
133 				break;
134 		aTmp--;
135 	}
136 
137 	if( !aTmp.GetIndex() )
138 		pNd = 0;
139 	else if( pNd )
140 		(*pIdx) = aTmp;
141 	return pNd;
142 }
143 
144 
145 SwNode2LayImpl::SwNode2LayImpl( const SwNode& rNode, sal_uLong nIdx, sal_Bool bSearch )
146 	: pUpperFrms( NULL ), nIndex( nIdx ), bInit( sal_False )
147 {
148 	const SwNode* pNd;
149 	if( bSearch || rNode.IsSectionNode() )
150 	{
151 		// Suche den naechsten Cntnt/TblNode, der einen Frame besitzt,
152 		// damit wir uns vor/hinter ihn haengen koennen
153 		if( !bSearch && rNode.GetIndex() < nIndex )
154 		{
155 			SwNodeIndex aTmp( *rNode.EndOfSectionNode(), +1 );
156 			pNd = GoPreviousWithFrm( &aTmp );
157 			if( !bSearch && pNd && rNode.GetIndex() > pNd->GetIndex() )
158 				pNd = NULL; // Nicht ueber den Bereich hinausschiessen
159 			bMaster = sal_False;
160 		}
161 		else
162 		{
163 			SwNodeIndex aTmp( rNode, -1 );
164 			pNd = GoNextWithFrm( rNode.GetNodes(), &aTmp );
165 			bMaster = sal_True;
166 			if( !bSearch && pNd && rNode.EndOfSectionIndex() < pNd->GetIndex() )
167 				pNd = NULL; // Nicht ueber den Bereich hinausschiessen
168 		}
169 	}
170 	else
171 	{
172 		pNd = &rNode;
173 		bMaster = nIndex < rNode.GetIndex();
174 	}
175 	if( pNd )
176 	{
177 		if( pNd->IsCntntNode() )
178 			pMod = (SwModify*)pNd->GetCntntNode();
179 		else
180 		{
181 			ASSERT( pNd->IsTableNode(), "For Tablenodes only" );
182 			pMod = pNd->GetTableNode()->GetTable().GetFrmFmt();
183 		}
184 		pIter = new SwIterator<SwFrm,SwModify>( *pMod );
185 	}
186 	else
187     {
188 		pIter = NULL;
189         pMod = 0;
190     }
191 }
192 
193 /* -----------------25.02.99 10:41-------------------
194  * SwNode2LayImpl::NextFrm() liefert den naechsten "sinnvollen" Frame,
195  * beim ersten Aufruf wird am eigentlichen Iterator ein First gerufen,
196  * danach die Next-Methode. Das Ergebnis wird auf Brauchbarkeit untersucht,
197  * so werden keine Follows akzeptiert, ein Master wird beim Einsammeln der
198  * pUpper und beim Einfuegen vor ihm akzeptiert. Beim Einfuegen dahinter
199  * wird vom Master ausgehend der letzte Follow gesucht und zurueckgegeben.
200  * Wenn der Frame innerhalb eines SectionFrms liegt, wird noch festgestellt,
201  * ob statt des Frames der SectionFrm der geeignete Rueckgabewert ist, dies
202  * ist der Fall, wenn der neu einzufuegende Node ausserhalb des Bereichs liegt.
203  * --------------------------------------------------*/
204 SwFrm* SwNode2LayImpl::NextFrm()
205 {
206 	SwFrm* pRet;
207 	if( !pIter )
208 		return sal_False;
209 	if( !bInit )
210 	{
211 		 pRet = pIter->First();
212 		 bInit = sal_True;
213 	}
214 	else
215 		pRet = pIter->Next();
216 	while( pRet )
217 	{
218 		SwFlowFrm* pFlow = SwFlowFrm::CastFlowFrm( pRet );
219 		ASSERT( pFlow, "Cntnt or Table expected?!" );
220 		// Follows sind fluechtige Gestalten, deshalb werden sie ignoriert.
221 		// Auch wenn wir hinter dem Frame eingefuegt werden sollen, nehmen wir
222 		// zunaechst den Master, hangeln uns dann aber zum letzten Follow durch.
223 		if( !pFlow->IsFollow() )
224 		{
225 			if( !bMaster )
226 			{
227 				while( pFlow->HasFollow() )
228 					pFlow = pFlow->GetFollow();
229 				pRet = pFlow->GetFrm();
230 			}
231 			if( pRet->IsInSct() )
232 			{
233 				SwSectionFrm* pSct = pRet->FindSctFrm();
234 				// Vorsicht: Wenn wir in einer Fussnote sind, so kann diese
235 				// Layoutmaessig in einem spaltigen Bereich liegen, obwohl
236 				// sie nodemaessig ausserhalb liegt. Deshalb muss bei Fussnoten
237 				// ueberprueft werden, ob auch der SectionFrm in der Fussnote
238 				// und nicht ausserhalb liegt.
239 				if( !pRet->IsInFtn() || pSct->IsInFtn() )
240 				{
241 					ASSERT( pSct && pSct->GetSection(), "Where's my section?" );
242 					SwSectionNode* pNd = pSct->GetSection()->GetFmt()->GetSectionNode();
243 					ASSERT( pNd, "Lost SectionNode" );
244 					// Wenn der erhaltene Frame in einem Bereichsframe steht,
245 					// dessen Bereich den Ausgangsnode nicht umfasst, so kehren
246 					// wir mit dem SectionFrm zurueck, sonst mit dem Cntnt/TabFrm
247 					if( bMaster )
248 					{
249 						if( pNd->GetIndex() >= nIndex )
250 							pRet = pSct;
251 					}
252 					else if( pNd->EndOfSectionIndex() < nIndex )
253 						pRet = pSct;
254 				}
255 			}
256 			return pRet;
257 		}
258 		pRet = pIter->Next();
259 	}
260 	return NULL;
261 }
262 
263 void SwNode2LayImpl::SaveUpperFrms()
264 {
265 	pUpperFrms = new SvPtrarr( 0, 20 );
266 	SwFrm* pFrm;
267 	while( 0 != (pFrm = NextFrm()) )
268 	{
269 		SwFrm* pPrv = pFrm->GetPrev();
270 		pFrm = pFrm->GetUpper();
271 		if( pFrm )
272 		{
273 			if( pFrm->IsFtnFrm() )
274 				((SwFtnFrm*)pFrm)->ColLock();
275 			else if( pFrm->IsInSct() )
276 				pFrm->FindSctFrm()->ColLock();
277 			if( pPrv && pPrv->IsSctFrm() )
278 				((SwSectionFrm*)pPrv)->LockJoin();
279 			pUpperFrms->Insert( (void*)pPrv, pUpperFrms->Count() );
280 			pUpperFrms->Insert( (void*)pFrm, pUpperFrms->Count() );
281 		}
282 	}
283 	delete pIter;
284 	pIter = NULL;
285     pMod = 0;
286 }
287 
288 SwLayoutFrm* SwNode2LayImpl::UpperFrm( SwFrm* &rpFrm, const SwNode &rNode )
289 {
290 	rpFrm = NextFrm();
291 	if( !rpFrm )
292 		return NULL;
293 	SwLayoutFrm* pUpper = rpFrm->GetUpper();
294 	if( rpFrm->IsSctFrm() )
295 	{
296 		const SwNode* pNode = rNode.StartOfSectionNode();
297 		if( pNode->IsSectionNode() )
298 		{
299 			SwFrm* pFrm = bMaster ? rpFrm->FindPrev() : rpFrm->FindNext();
300 			if( pFrm && pFrm->IsSctFrm() )
301 			{
302                 // #137684#: pFrm could be a "dummy"-section
303 				if( ((SwSectionFrm*)pFrm)->GetSection() &&
304                     (&((SwSectionNode*)pNode)->GetSection() ==
305                      ((SwSectionFrm*)pFrm)->GetSection()) )
306 				{
307                     // OD 2004-06-02 #i22922# - consider columned sections
308                     // 'Go down' the section frame as long as the layout frame
309                     // is found, which would contain content.
310                     while ( pFrm->IsLayoutFrm() &&
311                             static_cast<SwLayoutFrm*>(pFrm)->Lower() &&
312                             !static_cast<SwLayoutFrm*>(pFrm)->Lower()->IsFlowFrm() &&
313                             static_cast<SwLayoutFrm*>(pFrm)->Lower()->IsLayoutFrm() )
314                     {
315                         pFrm = static_cast<SwLayoutFrm*>(pFrm)->Lower();
316                     }
317                     ASSERT( pFrm->IsLayoutFrm(),
318                             "<SwNode2LayImpl::UpperFrm(..)> - expected upper frame isn't a layout frame." );
319                     rpFrm = bMaster ? NULL
320                                     : static_cast<SwLayoutFrm*>(pFrm)->Lower();
321                     ASSERT( !rpFrm || rpFrm->IsFlowFrm(),
322                             "<SwNode2LayImpl::UpperFrm(..)> - expected sibling isn't a flow frame." );
323                     return static_cast<SwLayoutFrm*>(pFrm);
324 				}
325 
326                 pUpper = new SwSectionFrm(((SwSectionNode*)pNode)->GetSection(), rpFrm);
327 				pUpper->Paste( rpFrm->GetUpper(),
328 							   bMaster ? rpFrm : rpFrm->GetNext() );
329                 static_cast<SwSectionFrm*>(pUpper)->Init();
330 				rpFrm = NULL;
331                 // 'Go down' the section frame as long as the layout frame
332                 // is found, which would contain content.
333                 while ( pUpper->Lower() &&
334                         !pUpper->Lower()->IsFlowFrm() &&
335                         pUpper->Lower()->IsLayoutFrm() )
336                 {
337                     pUpper = static_cast<SwLayoutFrm*>(pUpper->Lower());
338                 }
339 				return pUpper;
340 			}
341 		}
342 	};
343 	if( !bMaster )
344 		rpFrm = rpFrm->GetNext();
345 	return pUpper;
346 }
347 
348 void SwNode2LayImpl::RestoreUpperFrms( SwNodes& rNds, sal_uLong nStt, sal_uLong nEnd )
349 {
350 	ASSERT( pUpperFrms, "RestoreUpper without SaveUpper?" )
351 	SwNode* pNd;
352 	SwDoc *pDoc = rNds.GetDoc();
353 	sal_Bool bFirst = sal_True;
354 	for( ; nStt < nEnd; ++nStt )
355 	{
356 		SwFrm* pNew = 0;
357 		SwFrm* pNxt;
358 		SwLayoutFrm* pUp;
359 		if( (pNd = rNds[nStt])->IsCntntNode() )
360 			for( sal_uInt16 n = 0; n < pUpperFrms->Count(); )
361 			{
362 				pNxt = (SwFrm*)(*pUpperFrms)[n++];
363 				if( bFirst && pNxt && pNxt->IsSctFrm() )
364 					((SwSectionFrm*)pNxt)->UnlockJoin();
365 				pUp = (SwLayoutFrm*)(*pUpperFrms)[n++];
366 				if( pNxt )
367 					pNxt = pNxt->GetNext();
368 				else
369 					pNxt = pUp->Lower();
370 				pNew = ((SwCntntNode*)pNd)->MakeFrm( pUp );
371 				pNew->Paste( pUp, pNxt );
372 				(*pUpperFrms)[n-2] = pNew;
373 			}
374 		else if( pNd->IsTableNode() )
375 			for( sal_uInt16 x = 0; x < pUpperFrms->Count(); )
376 			{
377 				pNxt = (SwFrm*)(*pUpperFrms)[x++];
378 				if( bFirst && pNxt && pNxt->IsSctFrm() )
379 					((SwSectionFrm*)pNxt)->UnlockJoin();
380 				pUp = (SwLayoutFrm*)(*pUpperFrms)[x++];
381 				if( pNxt )
382 					pNxt = pNxt->GetNext();
383 				else
384 					pNxt = pUp->Lower();
385 				pNew = ((SwTableNode*)pNd)->MakeFrm( pUp );
386 				ASSERT( pNew->IsTabFrm(), "Table exspected" );
387 				pNew->Paste( pUp, pNxt );
388 				((SwTabFrm*)pNew)->RegistFlys();
389 				(*pUpperFrms)[x-2] = pNew;
390 			}
391 		else if( pNd->IsSectionNode() )
392 		{
393 			nStt = pNd->EndOfSectionIndex();
394 			for( sal_uInt16 x = 0; x < pUpperFrms->Count(); )
395 			{
396 				pNxt = (SwFrm*)(*pUpperFrms)[x++];
397 				if( bFirst && pNxt && pNxt->IsSctFrm() )
398 					((SwSectionFrm*)pNxt)->UnlockJoin();
399 				pUp = (SwLayoutFrm*)(*pUpperFrms)[x++];
400 				ASSERT( pUp->GetUpper() || pUp->IsFlyFrm(), "Lost Upper" );
401 				::_InsertCnt( pUp, pDoc, pNd->GetIndex(), sal_False, nStt+1, pNxt );
402                 pNxt = pUp->GetLastLower();
403                 (*pUpperFrms)[x-2] = pNxt;
404 			}
405 		}
406 		bFirst = sal_False;
407 	}
408 	for( sal_uInt16 x = 0; x < pUpperFrms->Count(); ++x )
409 	{
410 		SwFrm* pTmp = (SwFrm*)(*pUpperFrms)[++x];
411 		if( pTmp->IsFtnFrm() )
412 			((SwFtnFrm*)pTmp)->ColUnlock();
413         else if ( pTmp->IsInSct() )
414         {
415             SwSectionFrm* pSctFrm = pTmp->FindSctFrm();
416             pSctFrm->ColUnlock();
417             // OD 26.08.2003 #i18103# - invalidate size of section in order to
418             // assure, that the section is formatted, unless it was 'Collocked'
419             // from its 'collection' until its 'restoration'.
420             pSctFrm->_InvalidateSize();
421         }
422 	}
423 }
424 
425 SwFrm* SwNode2LayImpl::GetFrm( const Point* pDocPos,
426 								const SwPosition *pPos,
427 								const sal_Bool bCalcFrm ) const
428 {
429     // mba: test if change of member pIter -> pMod broke anything
430 	return pMod ? ::GetFrmOfModify( 0, *pMod, USHRT_MAX, pDocPos, pPos, bCalcFrm ) : 0;
431 }
432 
433 SwNode2Layout::SwNode2Layout( const SwNode& rNd, sal_uLong nIdx )
434 {
435 	pImpl = new SwNode2LayImpl( rNd, nIdx, sal_False );
436 }
437 
438 SwNode2Layout::SwNode2Layout( const SwNode& rNd )
439 {
440 	pImpl = new SwNode2LayImpl( rNd, rNd.GetIndex(), sal_True );
441 	pImpl->SaveUpperFrms();
442 }
443 
444 void SwNode2Layout::RestoreUpperFrms( SwNodes& rNds, sal_uLong nStt, sal_uLong nEnd )
445 {
446 	ASSERT( pImpl, "RestoreUpperFrms without SaveUpperFrms" );
447 	pImpl->RestoreUpperFrms( rNds, nStt, nEnd );
448 }
449 
450 SwFrm* SwNode2Layout::NextFrm()
451 {
452 	return pImpl->NextFrm();
453 }
454 
455 SwLayoutFrm* SwNode2Layout::UpperFrm( SwFrm* &rpFrm, const SwNode &rNode )
456 {
457 	return pImpl->UpperFrm( rpFrm, rNode );
458 }
459 
460 SwNode2Layout::~SwNode2Layout()
461 {
462 	delete pImpl;
463 }
464 
465 SwFrm* SwNode2Layout::GetFrm( const Point* pDocPos,
466 								const SwPosition *pPos,
467 								const sal_Bool bCalcFrm ) const
468 {
469 	return pImpl->GetFrm( pDocPos, pPos, bCalcFrm );
470 }
471 
472 
473