xref: /aoo41x/main/sw/source/core/layout/findfrm.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 
32 #include "pagefrm.hxx"
33 #include "rootfrm.hxx"
34 #include "cntfrm.hxx"
35 #include "node.hxx"
36 #include "doc.hxx"
37 #include "frmtool.hxx"
38 #include "flyfrm.hxx"
39 #include <frmfmt.hxx>
40 #include <cellfrm.hxx>
41 #include <rowfrm.hxx>
42 #include <swtable.hxx>
43 
44 #include "tabfrm.hxx"
45 #include "sectfrm.hxx"
46 #include "flyfrms.hxx"
47 #include "ftnfrm.hxx"
48 #include "txtftn.hxx"
49 #include "fmtftn.hxx"
50 #include <txtfrm.hxx>   // SwTxtFrm
51 #include <switerator.hxx>
52 
53 /*************************************************************************
54 |*
55 |*	FindBodyCont, FindLastBodyCntnt()
56 |*
57 |*	Beschreibung		Sucht den ersten/letzten CntntFrm im BodyText unterhalb
58 |* 		der Seite.
59 |*	Ersterstellung		MA 15. Feb. 93
60 |*	Letzte Aenderung	MA 18. Apr. 94
61 |*
62 |*************************************************************************/
63 SwLayoutFrm *SwFtnBossFrm::FindBodyCont()
64 {
65 	SwFrm *pLay = Lower();
66 	while ( pLay && !pLay->IsBodyFrm() )
67 		pLay = pLay->GetNext();
68 	return (SwLayoutFrm*)pLay;
69 }
70 
71 SwCntntFrm *SwPageFrm::FindLastBodyCntnt()
72 {
73 	SwCntntFrm *pRet = FindFirstBodyCntnt();
74 	SwCntntFrm *pNxt = pRet;
75 	while ( pNxt && pNxt->IsInDocBody() && IsAnLower( pNxt ) )
76 	{	pRet = pNxt;
77 		pNxt = pNxt->FindNextCnt();
78 	}
79 	return pRet;
80 }
81 
82 /*************************************************************************
83 |*
84 |*	SwLayoutFrm::ContainsCntnt
85 |*
86 |*	Beschreibung			Prueft, ob der Frame irgendwo in seiner
87 |*			untergeordneten Struktur einen oder mehrere CntntFrm's enthaelt;
88 |*			Falls ja wird der erste gefundene CntntFrm zurueckgegeben.
89 |*
90 |*	Ersterstellung		MA 13. May. 92
91 |*	Letzte Aenderung	MA 20. Apr. 94
92 |*
93 |*************************************************************************/
94 
95 const SwCntntFrm *SwLayoutFrm::ContainsCntnt() const
96 {
97 	//LayoutBlatt nach unten hin suchen und wenn dieses keinen Inhalt hat
98 	//solange die weiteren Blatter abklappern bis Inhalt gefunden oder der
99 	//this verlassen wird.
100 	//Sections: Cntnt neben Sections wuerde so nicht gefunden (leere Section
101 	//direct neben CntntFrm), deshalb muss fuer diese Aufwendiger rekursiv gesucht
102 	//werden.
103 
104 	const SwLayoutFrm *pLayLeaf = this;
105 	do
106 	{
107 		while ( (!pLayLeaf->IsSctFrm() || pLayLeaf == this ) &&
108 				pLayLeaf->Lower() && pLayLeaf->Lower()->IsLayoutFrm() )
109 			pLayLeaf = (SwLayoutFrm*)pLayLeaf->Lower();
110 
111 		if( pLayLeaf->IsSctFrm() && pLayLeaf != this )
112 		{
113 			const SwCntntFrm *pCnt = pLayLeaf->ContainsCntnt();
114 			if( pCnt )
115 				return pCnt;
116 			if( pLayLeaf->GetNext() )
117 			{
118 				if( pLayLeaf->GetNext()->IsLayoutFrm() )
119 				{
120 					pLayLeaf = (SwLayoutFrm*)pLayLeaf->GetNext();
121 					continue;
122 				}
123 				else
124 					return (SwCntntFrm*)pLayLeaf->GetNext();
125 			}
126 		}
127 		else if ( pLayLeaf->Lower() )
128 			return (SwCntntFrm*)pLayLeaf->Lower();
129 
130 		pLayLeaf = pLayLeaf->GetNextLayoutLeaf();
131 		if( !IsAnLower( pLayLeaf) )
132 			return 0;
133 	} while( pLayLeaf );
134 	return 0;
135 }
136 
137 /*************************************************************************
138 |*
139 |*	SwLayoutFrm::FirstCell
140 |*
141 |*	Beschreibung	ruft zunaechst ContainsAny auf, um in die innerste Zelle
142 |* 					hineinzukommen. Dort hangelt es sich wieder hoch zum
143 |*					ersten SwCellFrm, seit es SectionFrms gibt, reicht kein
144 |*					ContainsCntnt()->GetUpper() mehr...
145 |*	Ersterstellung		AMA 17. Mar. 99
146 |*	Letzte Aenderung	AMA 17. Mar. 99
147 |*
148 |*************************************************************************/
149 
150 const SwCellFrm *SwLayoutFrm::FirstCell() const
151 {
152 	const SwFrm* pCnt = ContainsAny();
153 	while( pCnt && !pCnt->IsCellFrm() )
154 		pCnt = pCnt->GetUpper();
155 	return (const SwCellFrm*)pCnt;
156 }
157 
158 /*************************************************************************
159 |*
160 |*	SwLayoutFrm::ContainsAny
161 |*
162 |*	Beschreibung wie ContainsCntnt, nur dass nicht nur CntntFrms, sondern auch
163 |*			Bereiche und Tabellen zurueckgegeben werden.
164 |*	Ersterstellung		AMA 10. Mar. 99
165 |*	Letzte Aenderung	AMA 10. Mar. 99
166 |*
167 |*************************************************************************/
168 
169 // --> OD 2006-02-01 #130797#
170 // New parameter <_bInvestigateFtnForSections> controls investigation of
171 // content of footnotes for sections.
172 const SwFrm *SwLayoutFrm::ContainsAny( const bool _bInvestigateFtnForSections ) const
173 {
174 	//LayoutBlatt nach unten hin suchen und wenn dieses keinen Inhalt hat
175 	//solange die weiteren Blatter abklappern bis Inhalt gefunden oder der
176 	//this verlassen wird.
177 	// Oder bis wir einen SectionFrm oder TabFrm gefunden haben
178 
179 	const SwLayoutFrm *pLayLeaf = this;
180     // --> OD 2006-02-01 #130797#
181     const bool bNoFtn = IsSctFrm() && !_bInvestigateFtnForSections;
182     // <--
183 	do
184 	{
185 		while ( ( (!pLayLeaf->IsSctFrm() && !pLayLeaf->IsTabFrm())
186 				 || pLayLeaf == this ) &&
187 				pLayLeaf->Lower() && pLayLeaf->Lower()->IsLayoutFrm() )
188 			pLayLeaf = (SwLayoutFrm*)pLayLeaf->Lower();
189 
190 		if( ( pLayLeaf->IsTabFrm() || pLayLeaf->IsSctFrm() )
191 			&& pLayLeaf != this )
192 		{
193 			// Wir liefern jetzt auch "geloeschte" SectionFrms zurueck,
194 			// damit diese beim SaveCntnt und RestoreCntnt mitgepflegt werden.
195 			return pLayLeaf;
196 		}
197 		else if ( pLayLeaf->Lower() )
198 			return (SwCntntFrm*)pLayLeaf->Lower();
199 
200 		pLayLeaf = pLayLeaf->GetNextLayoutLeaf();
201 		if( bNoFtn && pLayLeaf && pLayLeaf->IsInFtn() )
202 		{
203 			do
204 			{
205 				pLayLeaf = pLayLeaf->GetNextLayoutLeaf();
206 			} while( pLayLeaf && pLayLeaf->IsInFtn() );
207 		}
208 		if( !IsAnLower( pLayLeaf) )
209 			return 0;
210 	} while( pLayLeaf );
211 	return 0;
212 }
213 
214 
215 /*************************************************************************
216 |*
217 |*	SwFrm::GetLower()
218 |*
219 |*	Ersterstellung		MA 27. Jul. 92
220 |*	Letzte Aenderung	MA 09. Oct. 97
221 |*
222 |*************************************************************************/
223 const SwFrm* SwFrm::GetLower() const
224 {
225 	return IsLayoutFrm() ? ((SwLayoutFrm*)this)->Lower() : 0;
226 }
227 
228 SwFrm* SwFrm::GetLower()
229 {
230 	return IsLayoutFrm() ? ((SwLayoutFrm*)this)->Lower() : 0;
231 }
232 
233 /*************************************************************************
234 |*
235 |*	SwLayoutFrm::IsAnLower()
236 |*
237 |*	Ersterstellung		MA 18. Mar. 93
238 |*	Letzte Aenderung	MA 18. Mar. 93
239 |*
240 |*************************************************************************/
241 sal_Bool SwLayoutFrm::IsAnLower( const SwFrm *pAssumed ) const
242 {
243 	const SwFrm *pUp = pAssumed;
244 	while ( pUp )
245 	{
246 		if ( pUp == this )
247 			return sal_True;
248 		if ( pUp->IsFlyFrm() )
249             pUp = ((SwFlyFrm*)pUp)->GetAnchorFrm();
250 		else
251 			pUp = pUp->GetUpper();
252 	}
253 	return sal_False;
254 }
255 
256 /** method to check relative position of layout frame to
257     a given layout frame.
258 
259     OD 08.11.2002 - refactoring of pseudo-local method <lcl_Apres(..)> in
260     <txtftn.cxx> for #104840#.
261 
262     @param _aCheckRefLayFrm
263     constant reference of an instance of class <SwLayoutFrm> which
264     is used as the reference for the relative position check.
265 
266     @author OD
267 
268     @return true, if <this> is positioned before the layout frame <p>
269 */
270 bool SwLayoutFrm::IsBefore( const SwLayoutFrm* _pCheckRefLayFrm ) const
271 {
272     ASSERT( !IsRootFrm() , "<IsBefore> called at a <SwRootFrm>.");
273     ASSERT( !_pCheckRefLayFrm->IsRootFrm() , "<IsBefore> called with a <SwRootFrm>.");
274 
275     bool bReturn;
276 
277     // check, if on different pages
278     const SwPageFrm *pMyPage = FindPageFrm();
279     const SwPageFrm *pCheckRefPage = _pCheckRefLayFrm->FindPageFrm();
280     if( pMyPage != pCheckRefPage )
281     {
282         // being on different page as check reference
283         bReturn = pMyPage->GetPhyPageNum() < pCheckRefPage->GetPhyPageNum();
284     }
285     else
286     {
287         // being on same page as check reference
288         // --> search my supreme parent <pUp>, which doesn't contain check reference.
289         const SwLayoutFrm* pUp = this;
290         while ( pUp->GetUpper() &&
291                 !pUp->GetUpper()->IsAnLower( _pCheckRefLayFrm )
292               )
293             pUp = pUp->GetUpper();
294         if( !pUp->GetUpper() )
295         {
296             // can occur, if <this> is a fly frm
297             bReturn = false;
298         }
299         else
300         {
301             // travel through the next's of <pUp> and check if one of these
302             // contain the check reference.
303             SwLayoutFrm* pUpNext = (SwLayoutFrm*)pUp->GetNext();
304             while ( pUpNext &&
305                     !pUpNext->IsAnLower( _pCheckRefLayFrm ) )
306             {
307                 pUpNext = (SwLayoutFrm*)pUpNext->GetNext();
308             }
309             bReturn = pUpNext != 0;
310         }
311     }
312 
313     return bReturn;
314 }
315 
316 //
317 // Local helper functions for GetNextLayoutLeaf
318 //
319 
320 const SwFrm* lcl_FindLayoutFrame( const SwFrm* pFrm, bool bNext )
321 {
322     const SwFrm* pRet = 0;
323     if ( pFrm->IsFlyFrm() )
324         pRet = bNext ? ((SwFlyFrm*)pFrm)->GetNextLink() : ((SwFlyFrm*)pFrm)->GetPrevLink();
325     else
326         pRet = bNext ? pFrm->GetNext() : pFrm->GetPrev();
327 
328     return pRet;
329 }
330 
331 const SwFrm* lcl_GetLower( const SwFrm* pFrm, bool bFwd )
332 {
333     if ( !pFrm->IsLayoutFrm() )
334         return 0;
335 
336     return bFwd ?
337            static_cast<const SwLayoutFrm*>(pFrm)->Lower() :
338            static_cast<const SwLayoutFrm*>(pFrm)->GetLastLower();
339 }
340 
341 /*************************************************************************
342 |*
343 |*  SwFrm::ImplGetNextLayoutLeaf
344 |*
345 |* Finds the next layout leaf. This is a layout frame, which does not
346  * have a lower which is a LayoutFrame. That means, pLower can be 0 or a
347  * content frame.
348  *
349  * However, pLower may be a TabFrm
350  *
351 |*************************************************************************/
352 
353 const SwLayoutFrm *SwFrm::ImplGetNextLayoutLeaf( bool bFwd ) const
354 {
355     const SwFrm       *pFrm = this;
356     const SwLayoutFrm *pLayoutFrm = 0;
357     const SwFrm       *p = 0;
358     bool bGoingUp = !bFwd;          // false for forward, true for backward
359     do {
360 
361          bool bGoingFwdOrBwd = false, bGoingDown = false;
362 
363          bGoingDown = ( !bGoingUp && ( 0 != (p = lcl_GetLower( pFrm, bFwd ) ) ) );
364          if ( !bGoingDown )
365          {
366              // I cannot go down, because either I'm currently going up or
367              // because the is no lower.
368              // I'll try to go forward:
369              bGoingFwdOrBwd = (0 != (p = lcl_FindLayoutFrame( pFrm, bFwd ) ) );
370              if ( !bGoingFwdOrBwd )
371              {
372                  // I cannot go forward, because there is no next frame.
373                  // I'll try to go up:
374                  bGoingUp = (0 != (p = pFrm->GetUpper() ) );
375                  if ( !bGoingUp )
376                  {
377                     // I cannot go up, because there is no upper frame.
378                     return 0;
379                  }
380              }
381          }
382 
383         // If I could not go down or forward, I'll have to go up
384         bGoingUp = !bGoingFwdOrBwd && !bGoingDown;
385 
386         pFrm = p;
387         p = lcl_GetLower( pFrm, true );
388 
389     } while( ( p && !p->IsFlowFrm() ) ||
390              pFrm == this ||
391              0 == ( pLayoutFrm = pFrm->IsLayoutFrm() ? (SwLayoutFrm*)pFrm : 0 ) ||
392              pLayoutFrm->IsAnLower( this ) );
393 
394     return pLayoutFrm;
395 }
396 
397 
398 
399 /*************************************************************************
400 |*
401 |*    SwFrm::ImplGetNextCntntFrm( bool )
402 |*
403 |*      Rueckwaertswandern im Baum: Den untergeordneten Frm greifen,
404 |*      wenn es einen gibt und nicht gerade zuvor um eine Ebene
405 |*      aufgestiegen wurde (das wuerde zu einem endlosen Auf und Ab
406 |*      fuehren!). Damit wird sichergestellt, dass beim
407 |*      Rueckwaertswandern alle Unterbaeume durchsucht werden. Wenn
408 |*      abgestiegen wurde, wird zuerst an das Ende der Kette gegangen,
409 |*      weil im weiteren ja vom letzten Frm innerhalb eines anderen
410 |*      Frms rueckwaerts gegangen wird.
411 |*      Vorwaetzwander funktioniert analog.
412 |*
413 |*    Ersterstellung    ??
414 |*    Letzte Aenderung  MA 30. Oct. 97
415 |*
416 |*************************************************************************/
417 
418 // Achtung: Fixes in ImplGetNextCntntFrm() muessen moeglicherweise auch in
419 // die weiter oben stehende Methode lcl_NextFrm(..) eingepflegt werden
420 const SwCntntFrm* SwCntntFrm::ImplGetNextCntntFrm( bool bFwd ) const
421 {
422     const SwFrm *pFrm = this;
423     // #100926#
424     SwCntntFrm *pCntntFrm = 0;
425     sal_Bool bGoingUp = sal_False;
426     do {
427         const SwFrm *p = 0;
428         sal_Bool bGoingFwdOrBwd = sal_False, bGoingDown = sal_False;
429 
430         bGoingDown = ( !bGoingUp && ( 0 != ( p = lcl_GetLower( pFrm, true ) ) ) );
431         if ( !bGoingDown )
432         {
433             bGoingFwdOrBwd = ( 0 != ( p = lcl_FindLayoutFrame( pFrm, bFwd ) ) );
434             if ( !bGoingFwdOrBwd )
435             {
436                 bGoingUp = ( 0 != ( p = pFrm->GetUpper() ) );
437                 if ( !bGoingUp )
438                 {
439                     return 0;
440                 }
441             }
442         }
443 
444         bGoingUp = !(bGoingFwdOrBwd || bGoingDown);
445 
446         if ( !bFwd )
447         {
448             if( bGoingDown && p )
449                 while ( p->GetNext() )
450                     p = p->GetNext();
451         }
452 
453         pFrm = p;
454     } while ( 0 == (pCntntFrm = (pFrm->IsCntntFrm() ? (SwCntntFrm*)pFrm:0) ));
455 
456     return pCntntFrm;
457 }
458 
459 
460 
461 
462 /*************************************************************************
463 |*
464 |*	SwFrm::FindRootFrm(), FindTabFrm(), FindFtnFrm(), FindFlyFrm(),
465 |* 		   FindPageFrm(), FindColFrm()
466 |*
467 |*	Ersterstellung		??
468 |*	Letzte Aenderung	MA 05. Sep. 93
469 |*
470 |*************************************************************************/
471 SwPageFrm* SwFrm::FindPageFrm()
472 {
473 	SwFrm *pRet = this;
474 	while ( pRet && !pRet->IsPageFrm() )
475 	{
476 		if ( pRet->GetUpper() )
477 			pRet = pRet->GetUpper();
478 		else if ( pRet->IsFlyFrm() )
479 		{
480             // --> OD 2004-06-30 #i28701# - use new method <GetPageFrm()>
481             if ( static_cast<SwFlyFrm*>(pRet)->GetPageFrm() )
482                 pRet = static_cast<SwFlyFrm*>(pRet)->GetPageFrm();
483 			else
484                 pRet = static_cast<SwFlyFrm*>(pRet)->AnchorFrm();
485 		}
486 		else
487 			return 0;
488 	}
489 	return (SwPageFrm*)pRet;
490 }
491 
492 SwFtnBossFrm* SwFrm::FindFtnBossFrm( sal_Bool bFootnotes )
493 {
494 	SwFrm *pRet = this;
495 	// Innerhalb einer Tabelle gibt es keine Fussnotenbosse, auch spaltige
496 	// Bereiche enthalten dort keine Fussnotentexte
497 	if( pRet->IsInTab() )
498 		pRet = pRet->FindTabFrm();
499 	while ( pRet && !pRet->IsFtnBossFrm() )
500 	{
501 		if ( pRet->GetUpper() )
502 			pRet = pRet->GetUpper();
503 		else if ( pRet->IsFlyFrm() )
504 		{
505             // --> OD 2004-06-30 #i28701# - use new method <GetPageFrm()>
506             if ( static_cast<SwFlyFrm*>(pRet)->GetPageFrm() )
507                 pRet = static_cast<SwFlyFrm*>(pRet)->GetPageFrm();
508             else
509                 pRet = static_cast<SwFlyFrm*>(pRet)->AnchorFrm();
510 		}
511 		else
512 			return 0;
513 	}
514 	if( bFootnotes && pRet && pRet->IsColumnFrm() &&
515 		!pRet->GetNext() && !pRet->GetPrev() )
516 	{
517 		SwSectionFrm* pSct = pRet->FindSctFrm();
518 		ASSERT( pSct, "FindFtnBossFrm: Single column outside section?" );
519 		if( !pSct->IsFtnAtEnd() )
520 			return pSct->FindFtnBossFrm( sal_True );
521 	}
522 	return (SwFtnBossFrm*)pRet;
523 }
524 
525 SwTabFrm* SwFrm::ImplFindTabFrm()
526 {
527 	SwFrm *pRet = this;
528 	while ( !pRet->IsTabFrm() )
529 	{
530 		pRet = pRet->GetUpper();
531 		if ( !pRet )
532 			return 0;
533 	}
534 	return (SwTabFrm*)pRet;
535 }
536 
537 SwSectionFrm* SwFrm::ImplFindSctFrm()
538 {
539 	SwFrm *pRet = this;
540 	while ( !pRet->IsSctFrm() )
541 	{
542 		pRet = pRet->GetUpper();
543 		if ( !pRet )
544 			return 0;
545 	}
546 	return (SwSectionFrm*)pRet;
547 }
548 
549 SwFtnFrm *SwFrm::ImplFindFtnFrm()
550 {
551 	SwFrm *pRet = this;
552 	while ( !pRet->IsFtnFrm() )
553 	{
554 		pRet = pRet->GetUpper();
555 		if ( !pRet )
556 			return 0;
557 	}
558 	return (SwFtnFrm*)pRet;
559 }
560 
561 SwFlyFrm *SwFrm::ImplFindFlyFrm()
562 {
563 	const SwFrm *pRet = this;
564 	do
565 	{
566 		if ( pRet->IsFlyFrm() )
567 			return (SwFlyFrm*)pRet;
568 		else
569 			pRet = pRet->GetUpper();
570 	} while ( pRet );
571 	return 0;
572 }
573 
574 SwFrm *SwFrm::FindColFrm()
575 {
576 	SwFrm *pFrm = this;
577 	do
578 	{	pFrm = pFrm->GetUpper();
579 	} while ( pFrm && !pFrm->IsColumnFrm() );
580 	return pFrm;
581 }
582 
583 SwFrm* SwFrm::FindFooterOrHeader()
584 {
585 	SwFrm* pRet = this;
586 	do
587 	{	if ( pRet->GetType() & 0x0018 )	//Header und Footer
588 			return pRet;
589 		else if ( pRet->GetUpper() )
590 			pRet = pRet->GetUpper();
591 		else if ( pRet->IsFlyFrm() )
592             pRet = ((SwFlyFrm*)pRet)->AnchorFrm();
593 		else
594 			return 0;
595 	} while ( pRet );
596 	return pRet;
597 }
598 
599 const SwFtnFrm* SwFtnContFrm::FindFootNote() const
600 {
601 	const SwFtnFrm* pRet = (SwFtnFrm*)Lower();
602 	if( pRet && !pRet->GetAttr()->GetFtn().IsEndNote() )
603 		return pRet;
604 	return NULL;
605 }
606 
607 const SwPageFrm* SwRootFrm::GetPageAtPos( const Point& rPt, const Size* pSize, bool bExtend ) const
608 {
609     const SwPageFrm* pRet = 0;
610 
611     SwRect aRect;
612     if ( pSize )
613     {
614         aRect.Pos()  = rPt;
615         aRect.SSize() = *pSize;
616     }
617 
618     const SwFrm* pPage = Lower();
619 
620     if ( !bExtend )
621     {
622         if( !Frm().IsInside( rPt ) )
623             return 0;
624 
625         // skip pages above point:
626         while( pPage && rPt.Y() > pPage->Frm().Bottom() )
627             pPage = pPage->GetNext();
628     }
629 
630     ASSERT( GetPageNum() <= maPageRects.size(), "number of pages differes from page rect array size" )
631     sal_uInt16 nPageIdx = 0;
632 
633     while ( pPage && !pRet )
634     {
635         const SwRect& rBoundRect = bExtend ? maPageRects[ nPageIdx++ ] : pPage->Frm();
636 
637         if ( (!pSize && rBoundRect.IsInside(rPt)) ||
638               (pSize && rBoundRect.IsOver(aRect)) )
639         {
640             pRet = static_cast<const SwPageFrm*>(pPage);
641         }
642 
643         pPage = pPage->GetNext();
644     }
645 
646     return pRet;
647 }
648 
649 /*************************************************************************
650 |*
651 |*	SwFrmFrm::GetAttrSet()
652 |*
653 |*	Ersterstellung		MA 02. Aug. 93
654 |*	Letzte Aenderung	MA 02. Aug. 93
655 |*
656 |*************************************************************************/
657 const SwAttrSet* SwFrm::GetAttrSet() const
658 {
659 	if ( IsCntntFrm() )
660 		return &((const SwCntntFrm*)this)->GetNode()->GetSwAttrSet();
661 	else
662 		return &((const SwLayoutFrm*)this)->GetFmt()->GetAttrSet();
663 }
664 
665 /*************************************************************************
666 |*
667 |*	SwFrm::_FindNext(), _FindPrev(), InvalidateNextPos()
668 |* 		   _FindNextCnt() geht in Tabellen und Bereiche hineinund liefert
669 |*         nur SwCntntFrms.
670 |*
671 |*	Beschreibung		Invalidiert die Position des Naechsten Frames.
672 |*		Dies ist der direkte Nachfolger, oder bei CntntFrm's der naechste
673 |*		CntntFrm der im gleichen Fluss liegt wie ich:
674 |* 		- Body,
675 |* 		- Fussnoten,
676 |* 		- Bei Kopf-/Fussbereichen ist die Benachrichtigung nur innerhalb des
677 |* 		  Bereiches weiterzuleiten.
678 |* 		- dito fuer Flys.
679 |* 		- Cntnts in Tabs halten sich ausschliesslich innerhalb ihrer Zelle
680 |* 		  auf.
681 |* 		- Tabellen verhalten sich prinzipiell analog zu den Cntnts
682 |* 		- Bereiche ebenfalls
683 |*	Ersterstellung		AK 14-Feb-1991
684 |*	Letzte Aenderung	AMA 10. Mar. 99
685 |*
686 |*************************************************************************/
687 
688 // Diese Hilfsfunktion ist ein Aequivalent zur ImplGetNextCntntFrm()-Methode,
689 // sie liefert allerdings neben ContentFrames auch TabFrms und SectionFrms.
690 SwFrm* lcl_NextFrm( SwFrm* pFrm )
691 {
692 	SwFrm *pRet = 0;
693 	sal_Bool bGoingUp = sal_False;
694 	do {
695 		SwFrm *p = 0;
696 
697 		sal_Bool bGoingFwd = sal_False;
698         sal_Bool bGoingDown = (!bGoingUp && ( 0 != (p = pFrm->IsLayoutFrm() ? ((SwLayoutFrm*)pFrm)->Lower() : 0)));
699 
700         if( !bGoingDown )
701         {
702             bGoingFwd = (0 != (p = ( pFrm->IsFlyFrm() ? ((SwFlyFrm*)pFrm)->GetNextLink() : pFrm->GetNext())));
703             if ( !bGoingFwd )
704             {
705                 bGoingUp = (0 != (p = pFrm->GetUpper()));
706                 if ( !bGoingUp )
707                 {
708                     return 0;
709                 }
710             }
711         }
712 		bGoingUp = !(bGoingFwd || bGoingDown);
713 		pFrm = p;
714 	} while ( 0 == (pRet = ( ( pFrm->IsCntntFrm() || ( !bGoingUp &&
715 			( pFrm->IsTabFrm() || pFrm->IsSctFrm() ) ) )? pFrm : 0 ) ) );
716 	return pRet;
717 }
718 
719 SwFrm *SwFrm::_FindNext()
720 {
721 	sal_Bool bIgnoreTab = sal_False;
722 	SwFrm *pThis = this;
723 
724 	if ( IsTabFrm() )
725 	{
726 		//Der letzte Cntnt der Tabelle wird
727 		//gegriffen und dessen Nachfolger geliefert. Um die Spezialbeh.
728 		//Fuer Tabellen (s.u.) auszuschalten wird bIgnoreTab gesetzt.
729 		if ( ((SwTabFrm*)this)->GetFollow() )
730 			return ((SwTabFrm*)this)->GetFollow();
731 
732 		pThis = ((SwTabFrm*)this)->FindLastCntnt();
733 		if ( !pThis )
734 			pThis = this;
735 		bIgnoreTab = sal_True;
736 	}
737 	else if ( IsSctFrm() )
738 	{
739 		//Der letzte Cntnt des Bereichs wird gegriffen und dessen Nachfolger
740 		// geliefert.
741 		if ( ((SwSectionFrm*)this)->GetFollow() )
742 			return ((SwSectionFrm*)this)->GetFollow();
743 
744 		pThis = ((SwSectionFrm*)this)->FindLastCntnt();
745 		if ( !pThis )
746 			pThis = this;
747 	}
748 	else if ( IsCntntFrm() )
749 	{
750 		if( ((SwCntntFrm*)this)->GetFollow() )
751 			return ((SwCntntFrm*)this)->GetFollow();
752 	}
753     else if ( IsRowFrm() )
754     {
755         SwFrm* pMyUpper = GetUpper();
756         if ( pMyUpper->IsTabFrm() && ((SwTabFrm*)pMyUpper)->GetFollow() )
757             return ((SwTabFrm*)pMyUpper)->GetFollow()->GetLower();
758         else return NULL;
759     }
760     else
761 		return NULL;
762 
763 	SwFrm* pRet = NULL;
764 	const sal_Bool bFtn  = pThis->IsInFtn();
765 	if ( !bIgnoreTab && pThis->IsInTab() )
766 	{
767 		SwLayoutFrm *pUp = pThis->GetUpper();
768 		while ( !pUp->IsCellFrm() )
769 			pUp = pUp->GetUpper();
770 		ASSERT( pUp, "Cntnt in Tabelle aber nicht in Zelle." );
771         SwFrm* pNxt = ((SwCellFrm*)pUp)->GetFollowCell();
772         if ( pNxt )
773             pNxt = ((SwCellFrm*)pNxt)->ContainsCntnt();
774         if ( !pNxt )
775         {
776 		    pNxt = lcl_NextFrm( pThis );
777             if ( pUp->IsAnLower( pNxt ) )
778 	    		pRet = pNxt;
779         }
780         else
781             pRet = pNxt;
782     }
783 	else
784 	{
785 		const sal_Bool bBody = pThis->IsInDocBody();
786 		SwFrm *pNxtCnt = lcl_NextFrm( pThis );
787 		if ( pNxtCnt )
788 		{
789 			if ( bBody || bFtn )
790 			{
791 				while ( pNxtCnt )
792 				{
793                     // OD 02.04.2003 #108446# - check for endnote, only if found
794                     // next content isn't contained in a section, that collect its
795                     // endnotes at its end.
796                     bool bEndn = IsInSct() && !IsSctFrm() &&
797                                  ( !pNxtCnt->IsInSct() ||
798                                    !pNxtCnt->FindSctFrm()->IsEndnAtEnd()
799                                  );
800                     if ( ( bBody && pNxtCnt->IsInDocBody() ) ||
801                          ( pNxtCnt->IsInFtn() &&
802                            ( bFtn ||
803                              ( bEndn && pNxtCnt->FindFtnFrm()->GetAttr()->GetFtn().IsEndNote() )
804                            )
805                          )
806                        )
807 					{
808 						pRet = pNxtCnt->IsInTab() ? pNxtCnt->FindTabFrm()
809 													: (SwFrm*)pNxtCnt;
810 						break;
811 					}
812 					pNxtCnt = lcl_NextFrm( pNxtCnt );
813 				}
814 			}
815 			else if ( pThis->IsInFly() )
816 			{
817 				pRet = pNxtCnt->IsInTab() ? pNxtCnt->FindTabFrm()
818 											: (SwFrm*)pNxtCnt;
819 			}
820 			else	//Fuss-/oder Kopfbereich
821 			{
822 				const SwFrm *pUp = pThis->GetUpper();
823 				const SwFrm *pCntUp = pNxtCnt->GetUpper();
824 				while ( pUp && pUp->GetUpper() &&
825 						!pUp->IsHeaderFrm() && !pUp->IsFooterFrm() )
826 					pUp = pUp->GetUpper();
827 				while ( pCntUp && pCntUp->GetUpper() &&
828 						!pCntUp->IsHeaderFrm() && !pCntUp->IsFooterFrm() )
829 					pCntUp = pCntUp->GetUpper();
830 				if ( pCntUp == pUp )
831 				{
832 					pRet = pNxtCnt->IsInTab() ? pNxtCnt->FindTabFrm()
833 												: (SwFrm*)pNxtCnt;
834 				}
835 			}
836 		}
837 	}
838 	if( pRet && pRet->IsInSct() )
839 	{
840 		SwSectionFrm* pSct = pRet->FindSctFrm();
841 		//Fussnoten in spaltigen Rahmen duerfen nicht den Bereich
842 		//liefern, der die Fussnoten umfasst
843 		if( !pSct->IsAnLower( this ) &&
844 			(!bFtn || pSct->IsInFtn() ) )
845 			return pSct;
846 	}
847 	return pRet;
848 }
849 
850 // --> OD 2005-12-01 #i27138# - add parameter <_bInSameFtn>
851 SwCntntFrm *SwFrm::_FindNextCnt( const bool _bInSameFtn )
852 {
853 	SwFrm *pThis = this;
854 
855 	if ( IsTabFrm() )
856 	{
857 		if ( ((SwTabFrm*)this)->GetFollow() )
858 		{
859 			pThis = ((SwTabFrm*)this)->GetFollow()->ContainsCntnt();
860 			if( pThis )
861 				return (SwCntntFrm*)pThis;
862 		}
863 		pThis = ((SwTabFrm*)this)->FindLastCntnt();
864 		if ( !pThis )
865 			return 0;
866 	}
867 	else if ( IsSctFrm() )
868 	{
869 		if ( ((SwSectionFrm*)this)->GetFollow() )
870 		{
871 			pThis = ((SwSectionFrm*)this)->GetFollow()->ContainsCntnt();
872 			if( pThis )
873 				return (SwCntntFrm*)pThis;
874 		}
875 		pThis = ((SwSectionFrm*)this)->FindLastCntnt();
876 		if ( !pThis )
877 			return 0;
878 	}
879 	else if ( IsCntntFrm() && ((SwCntntFrm*)this)->GetFollow() )
880 		return ((SwCntntFrm*)this)->GetFollow();
881 
882 	if ( pThis->IsCntntFrm() )
883 	{
884 		const sal_Bool bBody = pThis->IsInDocBody();
885 		const sal_Bool bFtn  = pThis->IsInFtn();
886 		SwCntntFrm *pNxtCnt = ((SwCntntFrm*)pThis)->GetNextCntntFrm();
887 		if ( pNxtCnt )
888 		{
889             // --> OD 2005-12-01 #i27138#
890             if ( bBody || ( bFtn && !_bInSameFtn ) )
891             // <--
892 			{
893                 // handling for environments 'footnotes' and 'document body frames':
894                 while ( pNxtCnt )
895 				{
896 					if ( (bBody && pNxtCnt->IsInDocBody()) ||
897 						 (bFtn	&& pNxtCnt->IsInFtn()) )
898 						return pNxtCnt;
899 					pNxtCnt = pNxtCnt->GetNextCntntFrm();
900 				}
901 			}
902             // --> OD 2005-12-01 #i27138#
903             else if ( bFtn && _bInSameFtn )
904             {
905                 // handling for environments 'each footnote':
906                 // Assure that found next content frame belongs to the same footnotes
907                 const SwFtnFrm* pFtnFrmOfNext( pNxtCnt->FindFtnFrm() );
908                 const SwFtnFrm* pFtnFrmOfCurr( pThis->FindFtnFrm() );
909                 ASSERT( pFtnFrmOfCurr,
910                         "<SwFrm::_FindNextCnt() - unknown layout situation: current frame has to have an upper footnote frame." );
911                 if ( pFtnFrmOfNext == pFtnFrmOfCurr )
912                 {
913                     return pNxtCnt;
914                 }
915                 else if ( pFtnFrmOfCurr->GetFollow() )
916                 {
917                     // next content frame has to be the first content frame
918                     // in the follow footnote, which contains a content frame.
919                     SwFtnFrm* pFollowFtnFrmOfCurr(
920                                         const_cast<SwFtnFrm*>(pFtnFrmOfCurr) );
921                     pNxtCnt = 0L;
922                     do {
923                         pFollowFtnFrmOfCurr = pFollowFtnFrmOfCurr->GetFollow();
924                         pNxtCnt = pFollowFtnFrmOfCurr->ContainsCntnt();
925                     } while ( !pNxtCnt && pFollowFtnFrmOfCurr->GetFollow() );
926                     return pNxtCnt;
927                 }
928                 else
929                 {
930                     // current content frame is the last content frame in the
931                     // footnote - no next content frame exists.
932                     return 0L;
933                 }
934             }
935             // <--
936 			else if ( pThis->IsInFly() )
937                 // handling for environments 'unlinked fly frame' and
938                 // 'group of linked fly frames':
939                 return pNxtCnt;
940             else
941 			{
942                 // handling for environments 'page header' and 'page footer':
943                 const SwFrm *pUp = pThis->GetUpper();
944 				const SwFrm *pCntUp = pNxtCnt->GetUpper();
945 				while ( pUp && pUp->GetUpper() &&
946 						!pUp->IsHeaderFrm() && !pUp->IsFooterFrm() )
947 					pUp = pUp->GetUpper();
948 				while ( pCntUp && pCntUp->GetUpper() &&
949 						!pCntUp->IsHeaderFrm() && !pCntUp->IsFooterFrm() )
950 					pCntUp = pCntUp->GetUpper();
951 				if ( pCntUp == pUp )
952 					return pNxtCnt;
953 			}
954 		}
955 	}
956 	return 0;
957 }
958 
959 /** method to determine previous content frame in the same environment
960     for a flow frame (content frame, table frame, section frame)
961 
962     OD 2005-11-30 #i27138#
963 
964     @author OD
965 */
966 SwCntntFrm* SwFrm::_FindPrevCnt( const bool _bInSameFtn )
967 {
968     if ( !IsFlowFrm() )
969     {
970         // nothing to do, if current frame isn't a flow frame.
971         return 0L;
972     }
973 
974     SwCntntFrm* pPrevCntntFrm( 0L );
975 
976     // Because method <SwCntntFrm::GetPrevCntntFrm()> is used to travel
977     // through the layout, a content frame, at which the travel starts, is needed.
978     SwCntntFrm* pCurrCntntFrm = dynamic_cast<SwCntntFrm*>(this);
979 
980     // perform shortcut, if current frame is a follow, and
981     // determine <pCurrCntntFrm>, if current frame is a table or section frame
982     if ( pCurrCntntFrm && pCurrCntntFrm->IsFollow() )
983     {
984         // previous content frame is its master content frame
985         pPrevCntntFrm = pCurrCntntFrm->FindMaster();
986     }
987     else if ( IsTabFrm() )
988     {
989         SwTabFrm* pTabFrm( static_cast<SwTabFrm*>(this) );
990         if ( pTabFrm->IsFollow() )
991         {
992             // previous content frame is the last content of its master table frame
993             pPrevCntntFrm = pTabFrm->FindMaster()->FindLastCntnt();
994         }
995         else
996         {
997             // start content frame for the search is the first content frame of
998             // the table frame.
999             pCurrCntntFrm = pTabFrm->ContainsCntnt();
1000         }
1001     }
1002     else if ( IsSctFrm() )
1003     {
1004         SwSectionFrm* pSectFrm( static_cast<SwSectionFrm*>(this) );
1005         if ( pSectFrm->IsFollow() )
1006         {
1007             // previous content frame is the last content of its master section frame
1008             pPrevCntntFrm = pSectFrm->FindMaster()->FindLastCntnt();
1009         }
1010         else
1011         {
1012             // start content frame for the search is the first content frame of
1013             // the section frame.
1014             pCurrCntntFrm = pSectFrm->ContainsCntnt();
1015         }
1016     }
1017 
1018     // search for next content frame, depending on the environment, in which
1019     // the current frame is in.
1020     if ( !pPrevCntntFrm && pCurrCntntFrm )
1021     {
1022         pPrevCntntFrm = pCurrCntntFrm->GetPrevCntntFrm();
1023         if ( pPrevCntntFrm )
1024         {
1025             if ( pCurrCntntFrm->IsInFly() )
1026             {
1027                 // handling for environments 'unlinked fly frame' and
1028                 // 'group of linked fly frames':
1029                 // Nothing to do, <pPrevCntntFrm> is the one
1030             }
1031             else
1032             {
1033                 const bool bInDocBody = pCurrCntntFrm->IsInDocBody();
1034                 const bool bInFtn  = pCurrCntntFrm->IsInFtn();
1035                 if ( bInDocBody || ( bInFtn && !_bInSameFtn ) )
1036                 {
1037                     // handling for environments 'footnotes' and 'document body frames':
1038                     // Assure that found previous frame is also in one of these
1039                     // environments. Otherwise, travel further
1040                     while ( pPrevCntntFrm )
1041                     {
1042                         if ( ( bInDocBody && pPrevCntntFrm->IsInDocBody() ) ||
1043                              ( bInFtn && pPrevCntntFrm->IsInFtn() ) )
1044                         {
1045                             break;
1046                         }
1047                         pPrevCntntFrm = pPrevCntntFrm->GetPrevCntntFrm();
1048                     }
1049                 }
1050                 else if ( bInFtn && _bInSameFtn )
1051                 {
1052                     // handling for environments 'each footnote':
1053                     // Assure that found next content frame belongs to the same footnotes
1054                     const SwFtnFrm* pFtnFrmOfPrev( pPrevCntntFrm->FindFtnFrm() );
1055                     const SwFtnFrm* pFtnFrmOfCurr( pCurrCntntFrm->FindFtnFrm() );
1056                     if ( pFtnFrmOfPrev != pFtnFrmOfCurr )
1057                     {
1058                         if ( pFtnFrmOfCurr->GetMaster() )
1059                         {
1060                             SwFtnFrm* pMasterFtnFrmOfCurr(
1061                                         const_cast<SwFtnFrm*>(pFtnFrmOfCurr) );
1062                             pPrevCntntFrm = 0L;
1063                             // --> OD 2007-07-05 #146872#
1064                             // correct wrong loop-condition
1065                             do {
1066                                 pMasterFtnFrmOfCurr = pMasterFtnFrmOfCurr->GetMaster();
1067                                 pPrevCntntFrm = pMasterFtnFrmOfCurr->FindLastCntnt();
1068                             } while ( !pPrevCntntFrm &&
1069                                       pMasterFtnFrmOfCurr->GetMaster() );
1070                             // <--
1071                         }
1072                         else
1073                         {
1074                             // current content frame is the first content in the
1075                             // footnote - no previous content exists.
1076                             pPrevCntntFrm = 0L;;
1077                         }
1078                     }
1079                 }
1080                 else
1081                 {
1082                     // handling for environments 'page header' and 'page footer':
1083                     // Assure that found previous frame is also in the same
1084                     // page header respectively page footer as <pCurrCntntFrm>
1085                     // Note: At this point its clear, that <pCurrCntntFrm> has
1086                     //       to be inside a page header or page footer and that
1087                     //       neither <pCurrCntntFrm> nor <pPrevCntntFrm> are
1088                     //       inside a fly frame.
1089                     //       Thus, method <FindFooterOrHeader()> can be used.
1090                     ASSERT( pCurrCntntFrm->FindFooterOrHeader(),
1091                             "<SwFrm::_FindPrevCnt()> - unknown layout situation: current frame should be in page header or page footer" );
1092                     ASSERT( !pPrevCntntFrm->IsInFly(),
1093                             "<SwFrm::_FindPrevCnt()> - unknown layout situation: found previous frame should *not* be inside a fly frame." );
1094                     if ( pPrevCntntFrm->FindFooterOrHeader() !=
1095                                             pCurrCntntFrm->FindFooterOrHeader() )
1096                     {
1097                         pPrevCntntFrm = 0L;
1098                     }
1099                 }
1100             }
1101         }
1102     }
1103 
1104     return pPrevCntntFrm;
1105 }
1106 
1107 SwFrm *SwFrm::_FindPrev()
1108 {
1109 	sal_Bool bIgnoreTab = sal_False;
1110 	SwFrm *pThis = this;
1111 
1112 	if ( IsTabFrm() )
1113 	{
1114 		//Der erste Cntnt der Tabelle wird
1115 		//gegriffen und dessen Vorgaenger geliefert. Um die Spezialbeh.
1116 		//Fuer Tabellen (s.u.) auszuschalten wird bIgnoreTab gesetzt.
1117         if ( ((SwTabFrm*)this)->IsFollow() )
1118             return ((SwTabFrm*)this)->FindMaster();
1119         else
1120 		    pThis = ((SwTabFrm*)this)->ContainsCntnt();
1121 		bIgnoreTab = sal_True;
1122 	}
1123 
1124     if ( pThis && pThis->IsCntntFrm() )
1125     {
1126 		SwCntntFrm *pPrvCnt = ((SwCntntFrm*)pThis)->GetPrevCntntFrm();
1127 		if( !pPrvCnt )
1128 			return 0;
1129 		if ( !bIgnoreTab && pThis->IsInTab() )
1130 		{
1131 			SwLayoutFrm *pUp = pThis->GetUpper();
1132 			while ( !pUp->IsCellFrm() )
1133 				pUp = pUp->GetUpper();
1134 			ASSERT( pUp, "Cntnt in Tabelle aber nicht in Zelle." );
1135 			if ( pUp->IsAnLower( pPrvCnt ) )
1136 				return pPrvCnt;
1137 		}
1138 		else
1139 		{
1140 			SwFrm* pRet;
1141 			const sal_Bool bBody = pThis->IsInDocBody();
1142 			const sal_Bool bFtn  = bBody ? sal_False : pThis->IsInFtn();
1143 			if ( bBody || bFtn )
1144 			{
1145 				while ( pPrvCnt )
1146 				{
1147 					if ( (bBody && pPrvCnt->IsInDocBody()) ||
1148 							(bFtn	&& pPrvCnt->IsInFtn()) )
1149 					{
1150 						pRet = pPrvCnt->IsInTab() ? pPrvCnt->FindTabFrm()
1151 												  : (SwFrm*)pPrvCnt;
1152 						return pRet;
1153 					}
1154 					pPrvCnt = pPrvCnt->GetPrevCntntFrm();
1155 				}
1156 			}
1157 			else if ( pThis->IsInFly() )
1158 			{
1159 				pRet = pPrvCnt->IsInTab() ? pPrvCnt->FindTabFrm()
1160 											: (SwFrm*)pPrvCnt;
1161 				return pRet;
1162 			}
1163 			else	//Fuss-/oder Kopfbereich oder Fly
1164 			{
1165 				const SwFrm *pUp = pThis->GetUpper();
1166 				const SwFrm *pCntUp = pPrvCnt->GetUpper();
1167 				while ( pUp && pUp->GetUpper() &&
1168 						!pUp->IsHeaderFrm() && !pUp->IsFooterFrm() )
1169 					pUp = pUp->GetUpper();
1170 				while ( pCntUp && pCntUp->GetUpper() )
1171 					pCntUp = pCntUp->GetUpper();
1172 				if ( pCntUp == pUp )
1173 				{
1174 					pRet = pPrvCnt->IsInTab() ? pPrvCnt->FindTabFrm()
1175 												: (SwFrm*)pPrvCnt;
1176 					return pRet;
1177 				}
1178 			}
1179 		}
1180 	}
1181 	return 0;
1182 }
1183 
1184 void SwFrm::ImplInvalidateNextPos( sal_Bool bNoFtn )
1185 {
1186 	SwFrm *pFrm;
1187 	if ( 0 != (pFrm = _FindNext()) )
1188 	{
1189 		if( pFrm->IsSctFrm() )
1190 		{
1191 			while( pFrm && pFrm->IsSctFrm() )
1192 			{
1193 				if( ((SwSectionFrm*)pFrm)->GetSection() )
1194 				{
1195 					SwFrm* pTmp = ((SwSectionFrm*)pFrm)->ContainsAny();
1196 					if( pTmp )
1197                         pTmp->InvalidatePos();
1198 					else if( !bNoFtn )
1199 						((SwSectionFrm*)pFrm)->InvalidateFtnPos();
1200 					if( !IsInSct() || FindSctFrm()->GetFollow() != pFrm )
1201 						pFrm->InvalidatePos();
1202 					return;
1203 				}
1204 				pFrm = pFrm->FindNext();
1205 			}
1206 			if( pFrm )
1207 			{
1208 				if ( pFrm->IsSctFrm())
1209 				{ // Damit der Inhalt eines Bereichs die Chance erhaelt,
1210 				  // die Seite zu wechseln, muss er ebenfalls invalidiert werden.
1211 					SwFrm* pTmp = ((SwSectionFrm*)pFrm)->ContainsAny();
1212 					if( pTmp )
1213                         pTmp->InvalidatePos();
1214 					if( !IsInSct() || FindSctFrm()->GetFollow() != pFrm )
1215 						pFrm->InvalidatePos();
1216 				}
1217 				else
1218 					pFrm->InvalidatePos();
1219 			}
1220 		}
1221 		else
1222 			pFrm->InvalidatePos();
1223 	}
1224 }
1225 
1226 /** method to invalidate printing area of next frame
1227 
1228     OD 09.01.2004 #i11859#
1229 
1230     @author OD
1231 
1232     FME 2004-04-19 #i27145# Moved function from SwTxtFrm to SwFrm
1233 */
1234 void SwFrm::InvalidateNextPrtArea()
1235 {
1236     // determine next frame
1237     SwFrm* pNextFrm = FindNext();
1238     // skip empty section frames and hidden text frames
1239     {
1240         while ( pNextFrm &&
1241                 ( ( pNextFrm->IsSctFrm() &&
1242                     !static_cast<SwSectionFrm*>(pNextFrm)->GetSection() ) ||
1243                   ( pNextFrm->IsTxtFrm() &&
1244                     static_cast<SwTxtFrm*>(pNextFrm)->IsHiddenNow() ) ) )
1245         {
1246             pNextFrm = pNextFrm->FindNext();
1247         }
1248     }
1249 
1250     // Invalidate printing area of found next frame
1251     if ( pNextFrm )
1252     {
1253         if ( pNextFrm->IsSctFrm() )
1254         {
1255             // Invalidate printing area of found section frame, if
1256             // (1) this text frame isn't in a section OR
1257             // (2) found section frame isn't a follow of the section frame this
1258             //     text frame is in.
1259             if ( !IsInSct() || FindSctFrm()->GetFollow() != pNextFrm )
1260             {
1261                 pNextFrm->InvalidatePrt();
1262             }
1263 
1264             // Invalidate printing area of first content in found section.
1265             SwFrm* pFstCntntOfSctFrm =
1266                     static_cast<SwSectionFrm*>(pNextFrm)->ContainsAny();
1267             if ( pFstCntntOfSctFrm )
1268             {
1269                 pFstCntntOfSctFrm->InvalidatePrt();
1270             }
1271         }
1272         else
1273         {
1274             pNextFrm->InvalidatePrt();
1275         }
1276     }
1277 }
1278 
1279 /*************************************************************************
1280 |*
1281 |*	  lcl_IsInColSect()
1282 |*		liefert nur sal_True, wenn der Frame _direkt_ in einem spaltigen Bereich steht,
1283 |*		nicht etwa, wenn er in einer Tabelle steht, die in einem spaltigen Bereich ist.
1284 |*
1285 |*************************************************************************/
1286 
1287 sal_Bool lcl_IsInColSct( const SwFrm *pUp )
1288 {
1289 	sal_Bool bRet = sal_False;
1290 	while( pUp )
1291 	{
1292 		if( pUp->IsColumnFrm() )
1293 			bRet = sal_True;
1294 		else if( pUp->IsSctFrm() )
1295 			return bRet;
1296 		else if( pUp->IsTabFrm() )
1297 			return sal_False;
1298 		pUp = pUp->GetUpper();
1299 	}
1300 	return sal_False;
1301 }
1302 
1303 /*************************************************************************
1304 |*
1305 |*	  SwFrm::IsMoveable();
1306 |*
1307 |*	  Ersterstellung	MA 09. Mar. 93
1308 |*	  Letzte Aenderung	MA 05. May. 95
1309 |*
1310 |*************************************************************************/
1311 /** determine, if frame is moveable in given environment
1312 
1313     OD 08.08.2003 #110978#
1314     method replaced 'old' method <sal_Bool IsMoveable() const>.
1315     Determines, if frame is moveable in given environment. if no environment
1316     is given (parameter _pLayoutFrm == 0L), the movability in the actual
1317     environment (<this->GetUpper()) is checked.
1318 
1319     @author OD
1320 */
1321 
1322 bool SwFrm::IsMoveable( const SwLayoutFrm* _pLayoutFrm ) const
1323 {
1324     bool bRetVal = false;
1325 
1326     if ( !_pLayoutFrm )
1327     {
1328         _pLayoutFrm = GetUpper();
1329     }
1330 
1331     if ( _pLayoutFrm && IsFlowFrm() )
1332     {
1333         if ( _pLayoutFrm->IsInSct() && lcl_IsInColSct( _pLayoutFrm ) )
1334         {
1335             bRetVal = true;
1336         }
1337         else if ( _pLayoutFrm->IsInFly() ||
1338                   _pLayoutFrm->IsInDocBody() ||
1339                   _pLayoutFrm->IsInFtn() )
1340         {
1341             if ( _pLayoutFrm->IsInTab() && !IsTabFrm() &&
1342                  ( !IsCntntFrm() || !const_cast<SwFrm*>(this)->GetNextCellLeaf( MAKEPAGE_NONE ) ) )
1343             {
1344                 bRetVal = false;
1345             }
1346             else
1347             {
1348                 if ( _pLayoutFrm->IsInFly() )
1349                 {
1350                     // if fly frame has a follow (next linked fly frame),
1351                     // frame is moveable.
1352                     if ( const_cast<SwLayoutFrm*>(_pLayoutFrm)->FindFlyFrm()->GetNextLink() )
1353                     {
1354                         bRetVal = true;
1355                     }
1356                     else
1357                     {
1358                         // if environment is columned, frame is moveable, if
1359                         // it isn't in last column.
1360                         // search for column frame
1361                         const SwFrm* pCol = _pLayoutFrm;
1362                         while ( pCol && !pCol->IsColumnFrm() )
1363                         {
1364                             pCol = pCol->GetUpper();
1365                         }
1366                         // frame is moveable, if found column frame isn't last one.
1367                         if ( pCol && pCol->GetNext() )
1368                         {
1369                             bRetVal = true;
1370                         }
1371                     }
1372                 }
1373                 else
1374                 {
1375                     bRetVal = true;
1376                 }
1377             }
1378         }
1379     }
1380 
1381     return bRetVal;
1382 }
1383 
1384 /*************************************************************************
1385 |*
1386 |*	  SwFrm::SetInfFlags();
1387 |*
1388 |*	  Ersterstellung	MA 05. Apr. 94
1389 |*	  Letzte Aenderung	MA 05. Apr. 94
1390 |*
1391 |*************************************************************************/
1392 void SwFrm::SetInfFlags()
1393 {
1394 	if ( !IsFlyFrm() && !GetUpper() ) //noch nicht gepastet, keine Informationen
1395 		return;						  //lieferbar
1396 
1397 	bInfInvalid = bInfBody = bInfTab = bInfFly = bInfFtn = bInfSct = sal_False;
1398 
1399 	SwFrm *pFrm = this;
1400 	if( IsFtnContFrm() )
1401 		bInfFtn = sal_True;
1402 	do
1403 	{   // bInfBody wird nur am Seitenbody, nicht im ColumnBody gesetzt
1404 		if ( pFrm->IsBodyFrm() && !bInfFtn && pFrm->GetUpper()
1405 			 && pFrm->GetUpper()->IsPageFrm() )
1406 			bInfBody = sal_True;
1407 		else if ( pFrm->IsTabFrm() || pFrm->IsCellFrm() )
1408 		{
1409             bInfTab = sal_True;
1410 		}
1411 		else if ( pFrm->IsFlyFrm() )
1412 			bInfFly = sal_True;
1413 		else if ( pFrm->IsSctFrm() )
1414 			bInfSct = sal_True;
1415 		else if ( pFrm->IsFtnFrm() )
1416 			bInfFtn = sal_True;
1417 
1418         pFrm = pFrm->GetUpper();
1419 
1420 	} while ( pFrm && !pFrm->IsPageFrm() ); //Oberhalb der Seite kommt nix
1421 }
1422 
1423 /*-----------------22.8.2001 14:30------------------
1424  * SwFrm::SetDirFlags( sal_Bool )
1425  * actualizes the vertical or the righttoleft-flags.
1426  * If the property is derived, it's from the upper or (for fly frames) from
1427  * the anchor. Otherwise we've to call a virtual method to check the property.
1428  * --------------------------------------------------*/
1429 
1430 void SwFrm::SetDirFlags( sal_Bool bVert )
1431 {
1432     if( bVert )
1433     {
1434         // OD 2004-01-21 #114969# - if derived, valid vertical flag only if
1435         // vertical flag of upper/anchor is valid.
1436         if( bDerivedVert )
1437         {
1438             const SwFrm* pAsk = IsFlyFrm() ?
1439                           ((SwFlyFrm*)this)->GetAnchorFrm() : GetUpper();
1440 
1441             ASSERT( pAsk != this, "Autsch! Stack overflow is about to happen" )
1442 
1443             if( pAsk )
1444             {
1445                 bVertical = pAsk->IsVertical() ? 1 : 0;
1446                 bReverse  = pAsk->IsReverse()  ? 1 : 0;
1447 
1448                 bVertLR  = pAsk->IsVertLR() ? 1 : 0;
1449                 //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
1450                 if ( !pAsk->bInvalidVert )
1451                     bInvalidVert = sal_False;
1452             }
1453         }
1454         else
1455             CheckDirection( bVert );
1456     }
1457     else
1458     {
1459         sal_Bool bInv = 0;
1460         if( !bDerivedR2L ) // CheckDirection is able to set bDerivedR2L!
1461             CheckDirection( bVert );
1462         if( bDerivedR2L )
1463         {
1464             const SwFrm* pAsk = IsFlyFrm() ?
1465                           ((SwFlyFrm*)this)->GetAnchorFrm() : GetUpper();
1466 
1467             ASSERT( pAsk != this, "Autsch! Stack overflow is about to happen" )
1468 
1469             if( pAsk )
1470                 bRightToLeft = pAsk->IsRightToLeft() ? 1 : 0;
1471             if( !pAsk || pAsk->bInvalidR2L )
1472                 bInv = bInvalidR2L;
1473         }
1474         bInvalidR2L = bInv;
1475     }
1476 }
1477 
1478 SwLayoutFrm* SwFrm::GetNextCellLeaf( MakePageType )
1479 {
1480     SwFrm* pTmpFrm = this;
1481     while ( !pTmpFrm->IsCellFrm() )
1482         pTmpFrm = pTmpFrm->GetUpper();
1483 
1484     ASSERT( pTmpFrm, "SwFrm::GetNextCellLeaf() without cell" )
1485     return ((SwCellFrm*)pTmpFrm)->GetFollowCell();
1486 }
1487 
1488 SwLayoutFrm* SwFrm::GetPrevCellLeaf( MakePageType )
1489 {
1490     SwFrm* pTmpFrm = this;
1491     while ( !pTmpFrm->IsCellFrm() )
1492         pTmpFrm = pTmpFrm->GetUpper();
1493 
1494     ASSERT( pTmpFrm, "SwFrm::GetNextPreviousLeaf() without cell" )
1495     return ((SwCellFrm*)pTmpFrm)->GetPreviousCell();
1496 }
1497 
1498 SwCellFrm* lcl_FindCorrespondingCellFrm( const SwRowFrm& rOrigRow,
1499                                          const SwCellFrm& rOrigCell,
1500                                          const SwRowFrm& rCorrRow,
1501                                          bool bInFollow )
1502 {
1503     SwCellFrm* pRet = NULL;
1504     SwCellFrm* pCell = (SwCellFrm*)rOrigRow.Lower();
1505     SwCellFrm* pCorrCell = (SwCellFrm*)rCorrRow.Lower();
1506 
1507     while ( pCell != &rOrigCell && !pCell->IsAnLower( &rOrigCell ) )
1508     {
1509         pCell = (SwCellFrm*)pCell->GetNext();
1510         pCorrCell = (SwCellFrm*)pCorrCell->GetNext();
1511     }
1512 
1513     ASSERT( pCell && pCorrCell, "lcl_FindCorrespondingCellFrm does not work" )
1514 
1515     if ( pCell != &rOrigCell )
1516     {
1517         // rOrigCell must be a lower of pCell. We need to recurse into the rows:
1518         ASSERT( pCell->Lower() && pCell->Lower()->IsRowFrm(),
1519                 "lcl_FindCorrespondingCellFrm does not work" )
1520 
1521         SwRowFrm* pRow = (SwRowFrm*)pCell->Lower();
1522         while ( !pRow->IsAnLower( &rOrigCell ) )
1523             pRow = (SwRowFrm*)pRow->GetNext();
1524 
1525         SwRowFrm* pCorrRow = 0;
1526         if ( bInFollow )
1527             pCorrRow = pRow->GetFollowRow();
1528         else
1529         {
1530             SwRowFrm* pTmpRow = static_cast<SwRowFrm*>(pCorrCell->GetLastLower());
1531 
1532             if ( pTmpRow && pTmpRow->GetFollowRow() == pRow )
1533                 pCorrRow = pTmpRow;
1534         }
1535 
1536         if ( pCorrRow )
1537             pRet = lcl_FindCorrespondingCellFrm( *pRow, rOrigCell, *pCorrRow, bInFollow );
1538     }
1539     else
1540         pRet = pCorrCell;
1541 
1542     return pRet;
1543 }
1544 
1545 // VERSION OF GetFollowCell() that assumes that we always have a follow flow line:
1546 SwCellFrm* SwCellFrm::GetFollowCell() const
1547 {
1548     SwCellFrm* pRet = NULL;
1549 
1550     // NEW TABLES
1551     // Covered cells do not have follow cells!
1552     const long nRowSpan = GetLayoutRowSpan();
1553     if ( nRowSpan < 1 )
1554         return NULL;
1555 
1556     // find most upper row frame
1557     const SwFrm* pRow = GetUpper();
1558     while( !pRow->IsRowFrm() || !pRow->GetUpper()->IsTabFrm() )
1559         pRow = pRow->GetUpper();
1560 
1561     if ( !pRow )
1562         return NULL;
1563 
1564     const SwTabFrm* pTabFrm = static_cast<const SwTabFrm*>( pRow->GetUpper() );
1565     if ( !pRow || !pTabFrm->GetFollow() || !pTabFrm->HasFollowFlowLine() )
1566         return NULL;
1567 
1568     const SwCellFrm* pThisCell = this;
1569 
1570     // Get last cell of the current table frame that belongs to the rowspan:
1571     if ( nRowSpan > 1 )
1572     {
1573         // optimization: Will end of row span be in last row or exceed row?
1574         long nMax = 0;
1575         while ( pRow->GetNext() && ++nMax < nRowSpan )
1576             pRow = pRow->GetNext();
1577 
1578         if ( !pRow->GetNext() )
1579         {
1580             pThisCell = &pThisCell->FindStartEndOfRowSpanCell( false, true );
1581             pRow = pThisCell->GetUpper();
1582         }
1583     }
1584 
1585     const SwRowFrm* pFollowRow = NULL;
1586     if ( !pRow->GetNext() &&
1587          NULL != ( pFollowRow = pRow->IsInSplitTableRow() ) &&
1588          ( !pFollowRow->IsRowSpanLine() || nRowSpan > 1 ) )
1589          pRet = lcl_FindCorrespondingCellFrm( *((SwRowFrm*)pRow), *pThisCell, *pFollowRow, true );
1590 
1591     return pRet;
1592 }
1593 
1594 // VERSION OF GetPreviousCell() THAT ASSUMES THAT WE ALWAYS HAVE A FFL
1595 SwCellFrm* SwCellFrm::GetPreviousCell() const
1596 {
1597     SwCellFrm* pRet = NULL;
1598 
1599     // NEW TABLES
1600     // Covered cells do not have previous cells!
1601     if ( GetLayoutRowSpan() < 1 )
1602         return NULL;
1603 
1604     // find most upper row frame
1605     const SwFrm* pRow = GetUpper();
1606     while( !pRow->IsRowFrm() || !pRow->GetUpper()->IsTabFrm() )
1607         pRow = pRow->GetUpper();
1608 
1609     ASSERT( pRow->GetUpper() && pRow->GetUpper()->IsTabFrm(), "GetPreviousCell without Table" );
1610 
1611     SwTabFrm* pTab = (SwTabFrm*)pRow->GetUpper();
1612 
1613     if ( pTab->IsFollow() )
1614     {
1615         const SwFrm* pTmp = pTab->GetFirstNonHeadlineRow();
1616         const bool bIsInFirstLine = ( pTmp == pRow );
1617 
1618         if ( bIsInFirstLine )
1619         {
1620             SwTabFrm *pMaster = (SwTabFrm*)pTab->FindMaster();
1621             if ( pMaster && pMaster->HasFollowFlowLine() )
1622             {
1623                 SwRowFrm* pMasterRow = static_cast<SwRowFrm*>(pMaster->GetLastLower());
1624                 if ( pMasterRow )
1625                     pRet = lcl_FindCorrespondingCellFrm( *((SwRowFrm*)pRow), *this, *pMasterRow, false );
1626                 if ( pRet && pRet->GetTabBox()->getRowSpan() < 1 )
1627                     pRet = &const_cast<SwCellFrm&>(pRet->FindStartEndOfRowSpanCell( true, true ));
1628             }
1629         }
1630     }
1631 
1632     return pRet;
1633 }
1634 
1635 // --> NEW TABLES
1636 const SwCellFrm& SwCellFrm::FindStartEndOfRowSpanCell( bool bStart, bool bCurrentTableOnly ) const
1637 {
1638     const SwCellFrm* pRet = 0;
1639 
1640     const SwTabFrm* pTableFrm = dynamic_cast<const SwTabFrm*>(GetUpper()->GetUpper());
1641 
1642     if ( !bStart && pTableFrm->IsFollow() && pTableFrm->IsInHeadline( *this ) )
1643         return *this;
1644 
1645     ASSERT( pTableFrm &&
1646             (  bStart && GetTabBox()->getRowSpan() < 1 ||
1647               !bStart && GetLayoutRowSpan() > 1 ),
1648             "SwCellFrm::FindStartRowSpanCell: No rowspan, no table, no cookies" )
1649 
1650     if ( pTableFrm )
1651     {
1652         const SwTable* pTable = pTableFrm->GetTable();
1653 
1654         sal_uInt16 nMax = USHRT_MAX;
1655         if ( bCurrentTableOnly )
1656         {
1657             const SwFrm* pCurrentRow = GetUpper();
1658             const bool bDoNotEnterHeadline = bStart && pTableFrm->IsFollow() &&
1659                                         !pTableFrm->IsInHeadline( *pCurrentRow );
1660 
1661             // check how many rows we are allowed to go up or down until we reach the end of
1662             // the current table frame:
1663             nMax = 0;
1664             while ( bStart ? pCurrentRow->GetPrev() : pCurrentRow->GetNext() )
1665             {
1666                 if ( bStart )
1667                 {
1668                     // do not enter a repeated headline:
1669                     if ( bDoNotEnterHeadline && pTableFrm->IsFollow() &&
1670                          pTableFrm->IsInHeadline( *pCurrentRow->GetPrev() ) )
1671                         break;
1672 
1673                     pCurrentRow = pCurrentRow->GetPrev();
1674                 }
1675                 else
1676                     pCurrentRow = pCurrentRow->GetNext();
1677 
1678                 ++nMax;
1679             }
1680         }
1681 
1682         // By passing the nMax value for Find*OfRowSpan (in case of bCurrentTableOnly
1683         // is set) we assure that we find a rMasterBox that has a SwCellFrm in
1684         // the current table frame:
1685         const SwTableBox& rMasterBox = bStart ?
1686                                        GetTabBox()->FindStartOfRowSpan( *pTable, nMax ) :
1687                                        GetTabBox()->FindEndOfRowSpan( *pTable, nMax );
1688 
1689         SwIterator<SwCellFrm,SwFmt> aIter( *rMasterBox.GetFrmFmt() );
1690 
1691         for ( SwCellFrm* pMasterCell = aIter.First(); pMasterCell; pMasterCell = aIter.Next() )
1692         {
1693             if ( pMasterCell->GetTabBox() == &rMasterBox )
1694             {
1695                 const SwTabFrm* pMasterTable = static_cast<const SwTabFrm*>(pMasterCell->GetUpper()->GetUpper());
1696 
1697                 if ( bCurrentTableOnly )
1698                 {
1699                     if ( pMasterTable == pTableFrm )
1700                     {
1701                         pRet = pMasterCell;
1702                         break;
1703                     }
1704                 }
1705                 else
1706                 {
1707                     if ( pMasterTable == pTableFrm ||
1708                          (  (bStart && pMasterTable->IsAnFollow(pTableFrm)) ||
1709                            (!bStart && pTableFrm->IsAnFollow(pMasterTable)) ) )
1710                     {
1711                         pRet = pMasterCell;
1712                         break;
1713                     }
1714                 }
1715             }
1716         }
1717     }
1718 
1719     ASSERT( pRet, "SwCellFrm::FindStartRowSpanCell: No result" )
1720 
1721     return *pRet;
1722 }
1723 // <-- NEW TABLES
1724 
1725 const SwRowFrm* SwFrm::IsInSplitTableRow() const
1726 {
1727     ASSERT( IsInTab(), "IsInSplitTableRow should only be called for frames in tables" )
1728 
1729     const SwFrm* pRow = this;
1730 
1731     // find most upper row frame
1732     while( pRow && ( !pRow->IsRowFrm() || !pRow->GetUpper()->IsTabFrm() ) )
1733         pRow = pRow->GetUpper();
1734 
1735     if ( !pRow ) return NULL;
1736 
1737     ASSERT( pRow->GetUpper()->IsTabFrm(), "Confusion in table layout" )
1738 
1739     const SwTabFrm* pTab = (SwTabFrm*)pRow->GetUpper();
1740     // --> OD 2006-06-28 #b6443897#
1741     // If most upper row frame is a headline row, the current frame
1742     // can't be in a splitted table row. Thus, add corresponding condition.
1743     if ( pRow->GetNext() ||
1744          pTab->GetTable()->IsHeadline(
1745                     *(static_cast<const SwRowFrm*>(pRow)->GetTabLine()) ) ||
1746          !pTab->HasFollowFlowLine() ||
1747          !pTab->GetFollow() )
1748         return NULL;
1749     // <--
1750 
1751     // skip headline
1752     const SwRowFrm* pFollowRow = pTab->GetFollow()->GetFirstNonHeadlineRow();
1753 
1754     ASSERT( pFollowRow, "SwFrm::IsInSplitTableRow() does not work" )
1755 
1756     return pFollowRow;
1757 }
1758 
1759 const SwRowFrm* SwFrm::IsInFollowFlowRow() const
1760 {
1761     ASSERT( IsInTab(), "IsInSplitTableRow should only be called for frames in tables" )
1762 
1763     // find most upper row frame
1764     const SwFrm* pRow = this;
1765     while( pRow && ( !pRow->IsRowFrm() || !pRow->GetUpper()->IsTabFrm() ) )
1766         pRow = pRow->GetUpper();
1767 
1768     if ( !pRow ) return NULL;
1769 
1770     ASSERT( pRow->GetUpper()->IsTabFrm(), "Confusion in table layout" )
1771 
1772     const SwTabFrm* pTab = (SwTabFrm*)pRow->GetUpper();
1773 
1774     const SwTabFrm* pMaster = pTab->IsFollow() ? pTab->FindMaster() : 0;
1775 
1776     if ( !pMaster || !pMaster->HasFollowFlowLine() )
1777         return NULL;
1778 
1779     const SwFrm* pTmp = pTab->GetFirstNonHeadlineRow();
1780     const bool bIsInFirstLine = ( pTmp == pRow );
1781 
1782     if ( !bIsInFirstLine )
1783         return NULL;
1784 
1785     const SwRowFrm* pMasterRow = static_cast<const SwRowFrm*>(pMaster->GetLastLower());
1786     return pMasterRow;
1787 }
1788 
1789 bool SwFrm::IsInBalancedSection() const
1790 {
1791     bool bRet = false;
1792 
1793     if ( IsInSct() )
1794     {
1795         const SwSectionFrm* pSectionFrm = FindSctFrm();
1796         if ( pSectionFrm )
1797             bRet = pSectionFrm->IsBalancedSection();
1798     }
1799     return bRet;
1800 }
1801 
1802 /*
1803  * SwLayoutFrm::GetLastLower()
1804  */
1805 const SwFrm* SwLayoutFrm::GetLastLower() const
1806 {
1807     const SwFrm* pRet = Lower();
1808     if ( !pRet )
1809         return 0;
1810     while ( pRet->GetNext() )
1811         pRet = pRet->GetNext();
1812     return pRet;
1813 }
1814