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