xref: /aoo41x/main/sw/source/core/frmedt/tblsel.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 <editeng/boxitem.hxx>
32 #include <editeng/protitem.hxx>
33 
34 #include <hintids.hxx>
35 #include <fmtanchr.hxx>
36 #include <fmtfsize.hxx>
37 #include <frmatr.hxx>
38 #include <tblsel.hxx>
39 #include <crsrsh.hxx>
40 #include <doc.hxx>
41 #include <IDocumentUndoRedo.hxx>
42 #include <docary.hxx>
43 #include <pam.hxx>
44 #include <ndtxt.hxx>
45 #include <ndole.hxx>
46 #include <swtable.hxx>
47 #include <cntfrm.hxx>
48 #include <tabfrm.hxx>
49 #include <rowfrm.hxx>
50 #include <cellfrm.hxx>
51 #include <pagefrm.hxx>
52 #include <rootfrm.hxx>
53 #include <viscrs.hxx>
54 #include <swtblfmt.hxx>
55 #include <UndoTable.hxx>
56 #include <mvsave.hxx>
57 #include <sectfrm.hxx>
58 #include <frmtool.hxx>
59 #include <switerator.hxx>
60 #include <deque>
61 
62 //siehe auch swtable.cxx
63 #define COLFUZZY 20L
64 
65 // defines, die bestimmen, wie Tabellen Boxen gemergt werden:
66 // 	- 1. alle leeren Zeilen entfernen, alle Boxen werden mit Blank,
67 //		alle Lines mit ParaBreak getrennt
68 // 	- 2. alle leeren Zeilen und alle leeren Boxen am Anfang und Ende
69 //		entfernen, alle Boxen werden mit Blank,
70 //		alle Lines mit ParaBreak getrennt
71 // 	- 3. alle leeren Boxen entfernen, alle Boxen werden mit Blank,
72 //		alle Lines mit ParaBreak getrennt
73 
74 #undef 		DEL_ONLY_EMPTY_LINES
75 #undef 		DEL_EMPTY_BOXES_AT_START_AND_END
76 #define 	DEL_ALL_EMPTY_BOXES
77 
78 
79 _SV_IMPL_SORTAR_ALG( SwSelBoxes, SwTableBoxPtr )
80 sal_Bool SwSelBoxes::Seek_Entry( const SwTableBoxPtr rSrch, sal_uInt16* pFndPos ) const
81 {
82 	sal_uLong nIdx = rSrch->GetSttIdx();
83 
84 	sal_uInt16 nO = Count(), nM, nU = 0;
85 	if( nO > 0 )
86 	{
87 		nO--;
88 		while( nU <= nO )
89 		{
90 			nM = nU + ( nO - nU ) / 2;
91 			if( (*this)[ nM ]->GetSttNd() == rSrch->GetSttNd() )
92 			{
93 				if( pFndPos )
94 					*pFndPos = nM;
95 				return sal_True;
96 			}
97 			else if( (*this)[ nM ]->GetSttIdx() < nIdx )
98 				nU = nM + 1;
99 			else if( nM == 0 )
100 			{
101 				if( pFndPos )
102 					*pFndPos = nU;
103 				return sal_False;
104 			}
105 			else
106 				nO = nM - 1;
107 		}
108 	}
109 	if( pFndPos )
110 		*pFndPos = nU;
111 	return sal_False;
112 }
113 
114 
115 SV_IMPL_PTRARR( SwCellFrms, SwCellFrm* )
116 
117 struct _CmpLPt
118 {
119     Point aPos;
120 	const SwTableBox* pSelBox;
121     sal_Bool bVert;
122 
123     _CmpLPt( const Point& rPt, const SwTableBox* pBox, sal_Bool bVertical );
124 
125     sal_Bool operator==( const _CmpLPt& rCmp ) const
126 	{   return X() == rCmp.X() && Y() == rCmp.Y() ? sal_True : sal_False; }
127 
128     sal_Bool operator<( const _CmpLPt& rCmp ) const
129     {
130         if ( bVert )
131             return X() > rCmp.X() || ( X() == rCmp.X() && Y() < rCmp.Y() )
132                     ? sal_True : sal_False;
133         else
134             return Y() < rCmp.Y() || ( Y() == rCmp.Y() && X() < rCmp.X() )
135                     ? sal_True : sal_False;
136     }
137 
138 	long X() const { return aPos.X(); }
139 	long Y() const { return aPos.Y(); }
140 };
141 
142 
143 SV_DECL_VARARR_SORT( _MergePos, _CmpLPt, 0, 40 )
144 SV_IMPL_VARARR_SORT( _MergePos, _CmpLPt )
145 
146 SV_IMPL_PTRARR( _FndBoxes, _FndBox* )
147 SV_IMPL_PTRARR( _FndLines, _FndLine* )
148 
149 
150 struct _Sort_CellFrm
151 {
152 	const SwCellFrm* pFrm;
153 
154     _Sort_CellFrm( const SwCellFrm& rCFrm )
155         : pFrm( &rCFrm ) {}
156 };
157 
158 typedef std::deque< _Sort_CellFrm > _Sort_CellFrms;
159 
160 SV_IMPL_PTRARR( SwChartBoxes, SwTableBoxPtr );
161 SV_IMPL_PTRARR( SwChartLines, SwChartBoxes* );
162 
163 const SwLayoutFrm *lcl_FindCellFrm( const SwLayoutFrm *pLay )
164 {
165 	while ( pLay && !pLay->IsCellFrm() )
166 		pLay = pLay->GetUpper();
167 	return pLay;
168 }
169 
170 const SwLayoutFrm *lcl_FindNextCellFrm( const SwLayoutFrm *pLay )
171 {
172 	//Dafuer sorgen, dass die Zelle auch verlassen wird (Bereiche)
173 	const SwLayoutFrm *pTmp = pLay;
174 	do {
175 		pTmp = pTmp->GetNextLayoutLeaf();
176 	} while( pLay->IsAnLower( pTmp ) );
177 
178 	while( pTmp && !pTmp->IsCellFrm() )
179 		pTmp = pTmp->GetUpper();
180 	return pTmp;
181 }
182 
183 void GetTblSelCrs( const SwCrsrShell &rShell, SwSelBoxes& rBoxes )
184 {
185 	if( rBoxes.Count() )
186 		rBoxes.Remove( sal_uInt16(0), rBoxes.Count() );
187 	if( rShell.IsTableMode() && ((SwCrsrShell&)rShell).UpdateTblSelBoxes())
188 		rBoxes.Insert( &rShell.GetTableCrsr()->GetBoxes() );
189 }
190 
191 void GetTblSelCrs( const SwTableCursor& rTblCrsr, SwSelBoxes& rBoxes )
192 {
193 	if( rBoxes.Count() )
194 		rBoxes.Remove( sal_uInt16(0), rBoxes.Count() );
195 
196 	if( rTblCrsr.IsChgd() || !rTblCrsr.GetBoxesCount() )
197 	{
198 		SwTableCursor* pTCrsr = (SwTableCursor*)&rTblCrsr;
199 		pTCrsr->GetDoc()->GetCurrentLayout()->MakeTblCrsrs( *pTCrsr );	//swmod 080218
200 	}
201 
202 	if( rTblCrsr.GetBoxesCount() )
203 		rBoxes.Insert( &rTblCrsr.GetBoxes() );
204 }
205 
206 void GetTblSel( const SwCrsrShell& rShell, SwSelBoxes& rBoxes,
207 				const SwTblSearchType eSearchType )
208 {
209 	//Start- und Endzelle besorgen und den naechsten fragen.
210 	if ( !rShell.IsTableMode() )
211 		rShell.GetCrsr();
212 
213     GetTblSel( *rShell.getShellCrsr(false), rBoxes, eSearchType );
214 }
215 
216 void GetTblSel( const SwCursor& rCrsr, SwSelBoxes& rBoxes,
217 				const SwTblSearchType eSearchType )
218 {
219 	//Start- und Endzelle besorgen und den naechsten fragen.
220 	ASSERT( rCrsr.GetCntntNode() && rCrsr.GetCntntNode( sal_False ),
221 			"Tabselection nicht auf Cnt." );
222 
223 	// Zeilen-Selektion:
224 	// teste ob Tabelle komplex ist. Wenn ja, dann immer uebers Layout
225 	// die selektierten Boxen zusammen suchen. Andernfalls ueber die
226 	// Tabellen-Struktur (fuer Makros !!)
227 	const SwCntntNode* pContentNd = rCrsr.GetNode()->GetCntntNode();
228 	const SwTableNode* pTblNd = pContentNd ? pContentNd->FindTableNode() : 0;
229     if( pTblNd && pTblNd->GetTable().IsNewModel() )
230     {
231         SwTable::SearchType eSearch;
232         switch( nsSwTblSearchType::TBLSEARCH_COL & eSearchType )
233         {
234             case nsSwTblSearchType::TBLSEARCH_ROW: eSearch = SwTable::SEARCH_ROW; break;
235             case nsSwTblSearchType::TBLSEARCH_COL: eSearch = SwTable::SEARCH_COL; break;
236             default: eSearch = SwTable::SEARCH_NONE; break;
237         }
238         const bool bChkP = 0 != ( nsSwTblSearchType::TBLSEARCH_PROTECT & eSearchType );
239         pTblNd->GetTable().CreateSelection( rCrsr, rBoxes, eSearch, bChkP );
240         return;
241     }
242 	if( nsSwTblSearchType::TBLSEARCH_ROW == ((~nsSwTblSearchType::TBLSEARCH_PROTECT ) & eSearchType ) &&
243 		pTblNd && !pTblNd->GetTable().IsTblComplex() )
244 	{
245 		const SwTable& rTbl = pTblNd->GetTable();
246 		const SwTableLines& rLines = rTbl.GetTabLines();
247 
248         const SwNode* pMarkNode = rCrsr.GetNode( sal_False );
249         const sal_uLong nMarkSectionStart = pMarkNode->StartOfSectionIndex();
250         const SwTableBox* pMarkBox = rTbl.GetTblBox( nMarkSectionStart );
251 
252         ASSERT( pMarkBox, "Point in table, mark outside?" )
253 
254         const SwTableLine* pLine = pMarkBox ? pMarkBox->GetUpper() : 0;
255         sal_uInt16 nSttPos = rLines.GetPos( pLine );
256 		ASSERT( USHRT_MAX != nSttPos, "Wo ist meine Zeile in der Tabelle?" );
257 		pLine = rTbl.GetTblBox( rCrsr.GetNode( sal_True )->StartOfSectionIndex() )->GetUpper();
258 		sal_uInt16 nEndPos = rLines.GetPos( pLine );
259 		ASSERT( USHRT_MAX != nEndPos, "Wo ist meine Zeile in der Tabelle?" );
260 		// pb: #i20193# if tableintable then nSttPos == nEndPos == USHRT_MAX
261 		if ( nSttPos != USHRT_MAX && nEndPos != USHRT_MAX )
262 		{
263 			if( nEndPos < nSttPos )		// vertauschen
264 			{
265 				sal_uInt16 nTmp = nSttPos; nSttPos = nEndPos; nEndPos = nTmp;
266 			}
267 
268 			int bChkProtected = nsSwTblSearchType::TBLSEARCH_PROTECT & eSearchType;
269 			for( ; nSttPos <= nEndPos; ++nSttPos )
270 			{
271 				pLine = rLines[ nSttPos ];
272 				for( sal_uInt16 n = pLine->GetTabBoxes().Count(); n ; )
273 				{
274 					SwTableBox* pBox = pLine->GetTabBoxes()[ --n ];
275 					// Zellenschutzt beachten ??
276 					if( !bChkProtected ||
277 						!pBox->GetFrmFmt()->GetProtect().IsCntntProtected() )
278 						rBoxes.Insert( pBox );
279 				}
280 			}
281 		}
282 	}
283 	else
284 	{
285 		Point aPtPos, aMkPos;
286         const SwShellCrsr* pShCrsr = dynamic_cast<const SwShellCrsr*>(&rCrsr);
287 		if( pShCrsr )
288 		{
289 			aPtPos = pShCrsr->GetPtPos();
290 			aMkPos = pShCrsr->GetMkPos();
291 		}
292         const SwCntntNode *pCntNd = rCrsr.GetCntntNode();
293 		const SwLayoutFrm *pStart = pCntNd ?
294             pCntNd->getLayoutFrm( pCntNd->GetDoc()->GetCurrentLayout(), &aPtPos )->GetUpper() : 0;
295         pCntNd = rCrsr.GetCntntNode(sal_False);
296 		const SwLayoutFrm *pEnd = pCntNd ?
297             pCntNd->getLayoutFrm( pCntNd->GetDoc()->GetCurrentLayout(), &aMkPos )->GetUpper() : 0;
298         if( pStart && pEnd )
299             GetTblSel( pStart, pEnd, rBoxes, 0, eSearchType );
300 	}
301 }
302 
303 void GetTblSel( const SwLayoutFrm* pStart, const SwLayoutFrm* pEnd,
304                 SwSelBoxes& rBoxes, SwCellFrms* pCells,
305                 const SwTblSearchType eSearchType )
306 {
307     // #112697# Robust:
308     const SwTabFrm* pStartTab = pStart->FindTabFrm();
309     if ( !pStartTab )
310     {
311         ASSERT( false, "GetTblSel without start table" )
312         return;
313     }
314 
315     int bChkProtected = nsSwTblSearchType::TBLSEARCH_PROTECT & eSearchType;
316 
317 	sal_Bool bTblIsValid;
318     // --> FME 2006-01-25 #i55421# Reduced value 10
319 	int nLoopMax = 10;		//JP 28.06.99: max 100 loops - Bug 67292
320     // <--
321 	sal_uInt16 i;
322 
323 	do {
324 		bTblIsValid = sal_True;
325 
326 		//Zuerst lassen wir uns die Tabellen und die Rechtecke heraussuchen.
327 		SwSelUnions aUnions;
328 		::MakeSelUnions( aUnions, pStart, pEnd, eSearchType );
329 
330         Point aCurrentTopLeft( LONG_MAX, LONG_MAX );
331         Point aCurrentTopRight( 0, LONG_MAX );
332         Point aCurrentBottomLeft( LONG_MAX, 0 );
333         Point aCurrentBottomRight( 0, 0 );
334         const SwCellFrm* pCurrentTopLeftFrm     = 0;
335         const SwCellFrm* pCurrentTopRightFrm    = 0;
336         const SwCellFrm* pCurrentBottomLeftFrm  = 0;
337         const SwCellFrm* pCurrentBottomRightFrm  = 0;
338 
339 		//Jetzt zu jedem Eintrag die Boxen herausfischen und uebertragen.
340 		for( i = 0; i < aUnions.Count() && bTblIsValid; ++i )
341 		{
342 			SwSelUnion *pUnion = aUnions[i];
343 			const SwTabFrm *pTable = pUnion->GetTable();
344 			if( !pTable->IsValid() && nLoopMax )
345 			{
346 				bTblIsValid = sal_False;
347 				break;
348 			}
349 
350             // Skip any repeated headlines in the follow:
351             const SwLayoutFrm* pRow = pTable->IsFollow() ?
352                                       pTable->GetFirstNonHeadlineRow() :
353                                      (const SwLayoutFrm*)pTable->Lower();
354 
355             while( pRow && bTblIsValid )
356 			{
357 				if( !pRow->IsValid() && nLoopMax )
358 				{
359 					bTblIsValid = sal_False;
360 					break;
361 				}
362 
363 				if ( pRow->Frm().IsOver( pUnion->GetUnion() ) )
364 				{
365 					const SwLayoutFrm *pCell = pRow->FirstCell();
366 
367 					while( bTblIsValid && pCell && pRow->IsAnLower( pCell ) )
368 					{
369 						if( !pCell->IsValid() && nLoopMax )
370 						{
371 							bTblIsValid = sal_False;
372 							break;
373 						}
374 
375 						ASSERT( pCell->IsCellFrm(), "Frame ohne Celle" );
376 						if( ::IsFrmInTblSel( pUnion->GetUnion(), pCell ) )
377 						{
378 							SwTableBox* pBox = (SwTableBox*)
379 								((SwCellFrm*)pCell)->GetTabBox();
380 							// Zellenschutzt beachten ??
381 							if( !bChkProtected ||
382 								!pBox->GetFrmFmt()->GetProtect().IsCntntProtected() )
383 								rBoxes.Insert( pBox );
384 
385                             if ( pCells )
386                             {
387                                 const Point aTopLeft( pCell->Frm().TopLeft() );
388                                 const Point aTopRight( pCell->Frm().TopRight() );
389                                 const Point aBottomLeft( pCell->Frm().BottomLeft() );
390                                 const Point aBottomRight( pCell->Frm().BottomRight() );
391 
392                                 if ( aTopLeft.Y() < aCurrentTopLeft.Y() ||
393                                      ( aTopLeft.Y() == aCurrentTopLeft.Y() &&
394                                        aTopLeft.X() <  aCurrentTopLeft.X() ) )
395                                 {
396                                     aCurrentTopLeft = aTopLeft;
397                                     pCurrentTopLeftFrm = static_cast<const SwCellFrm*>( pCell );
398                                 }
399 
400                                 if ( aTopRight.Y() < aCurrentTopRight.Y() ||
401                                      ( aTopRight.Y() == aCurrentTopRight.Y() &&
402                                        aTopRight.X() >  aCurrentTopRight.X() ) )
403                                 {
404                                     aCurrentTopRight = aTopRight;
405                                     pCurrentTopRightFrm = static_cast<const SwCellFrm*>( pCell );
406                                 }
407 
408                                 if ( aBottomLeft.Y() > aCurrentBottomLeft.Y() ||
409                                      ( aBottomLeft.Y() == aCurrentBottomLeft.Y() &&
410                                        aBottomLeft.X() <  aCurrentBottomLeft.X() ) )
411                                 {
412                                     aCurrentBottomLeft = aBottomLeft;
413                                     pCurrentBottomLeftFrm = static_cast<const SwCellFrm*>( pCell );
414                                 }
415 
416                                 if ( aBottomRight.Y() > aCurrentBottomRight.Y() ||
417                                      ( aBottomRight.Y() == aCurrentBottomRight.Y() &&
418                                        aBottomRight.X() >  aCurrentBottomRight.X() ) )
419                                 {
420                                     aCurrentBottomRight = aBottomRight;
421                                     pCurrentBottomRightFrm = static_cast<const SwCellFrm*>( pCell );
422                                 }
423 
424                             }
425                         }
426 						if ( pCell->GetNext() )
427 						{
428 							pCell = (const SwLayoutFrm*)pCell->GetNext();
429 							if ( pCell->Lower() && pCell->Lower()->IsRowFrm() )
430 								pCell = pCell->FirstCell();
431 						}
432 						else
433 							pCell = ::lcl_FindNextCellFrm( pCell );
434 					}
435 				}
436 				pRow = (const SwLayoutFrm*)pRow->GetNext();
437 			}
438 		}
439 
440         if ( pCells )
441         {
442             pCells->Remove( 0, pCells->Count() );
443             pCells->Insert( pCurrentTopLeftFrm, 0 );
444             pCells->Insert( pCurrentTopRightFrm, 1 );
445             pCells->Insert( pCurrentBottomLeftFrm, 2 );
446             pCells->Insert( pCurrentBottomRightFrm, 3 );
447         }
448 
449 		if( bTblIsValid )
450 			break;
451 
452         SwDeletionChecker aDelCheck( pStart );
453 
454         // ansonsten das Layout der Tabelle kurz "kalkulieren" lassen
455 		// und nochmals neu aufsetzen
456 		SwTabFrm *pTable = aUnions[0]->GetTable();
457         while( pTable )
458         {
459 			if( pTable->IsValid() )
460 				pTable->InvalidatePos();
461 			pTable->SetONECalcLowers();
462 			pTable->Calc();
463 			pTable->SetCompletePaint();
464 			if( 0 == (pTable = pTable->GetFollow()) )
465 				break;
466 		}
467 
468         // --> FME 2005-10-13 #125337# Make code robust, check if pStart has
469         // been deleted due to the formatting of the table:
470         if ( aDelCheck.HasBeenDeleted() )
471         {
472             ASSERT( false, "Current box has been deleted during GetTblSel()" )
473             break;
474         }
475         // <--
476 
477 		i = 0;
478 		rBoxes.Remove( i, rBoxes.Count() );
479 		--nLoopMax;
480 
481 	} while( sal_True );
482 	ASSERT( nLoopMax, "das Layout der Tabelle wurde nicht valide!" );
483 }
484 
485 
486 
487 sal_Bool ChkChartSel( const SwNode& rSttNd, const SwNode& rEndNd,
488 					SwChartLines* pGetCLines )
489 {
490 	const SwTableNode* pTNd = rSttNd.FindTableNode();
491 	if( !pTNd )
492 		return sal_False;
493 
494 	Point aNullPos;
495 	SwNodeIndex aIdx( rSttNd );
496 	const SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode();
497 	if( !pCNd )
498 		pCNd = aIdx.GetNodes().GoNextSection( &aIdx, sal_False, sal_False );
499 
500     // #109394# if table is invisible, return
501     // (layout needed for forming table selection further down, so we can't
502     //  continue with invisible tables)
503     // OD 07.11.2003 #i22135# - Also the content of the table could be
504     //                          invisible - e.g. in a hidden section
505     // Robust: check, if content was found (e.g. empty table cells)
506     if ( !pCNd || pCNd->getLayoutFrm( pCNd->GetDoc()->GetCurrentLayout() ) == NULL )
507             return sal_False;
508 
509 	const SwLayoutFrm *pStart = pCNd ? pCNd->getLayoutFrm( pCNd->GetDoc()->GetCurrentLayout(), &aNullPos )->GetUpper() : 0;
510 	ASSERT( pStart, "ohne Frame geht gar nichts" );
511 
512 	aIdx = rEndNd;
513 	pCNd = aIdx.GetNode().GetCntntNode();
514 	if( !pCNd )
515 		pCNd = aIdx.GetNodes().GoNextSection( &aIdx, sal_False, sal_False );
516 
517     // OD 07.11.2003 #i22135# - Robust: check, if content was found and if it's visible
518     if ( !pCNd || pCNd->getLayoutFrm( pCNd->GetDoc()->GetCurrentLayout() ) == NULL )
519     {
520         return sal_False;
521     }
522 
523     const SwLayoutFrm *pEnd = pCNd ? pCNd->getLayoutFrm( pCNd->GetDoc()->GetCurrentLayout(), &aNullPos )->GetUpper() : 0;
524 	ASSERT( pEnd, "ohne Frame geht gar nichts" );
525 
526 
527     sal_Bool bTblIsValid, bValidChartSel;
528     // --> FME 2006-01-25 #i55421# Reduced value 10
529 	int nLoopMax = 10;		//JP 28.06.99: max 100 loops - Bug 67292
530     // <--
531 	sal_uInt16 i = 0;
532 
533 	do {
534 		bTblIsValid = sal_True;
535 		bValidChartSel = sal_True;
536 
537 		sal_uInt16 nRowCells = USHRT_MAX;
538 
539 		//Zuerst lassen wir uns die Tabellen und die Rechtecke heraussuchen.
540 		SwSelUnions aUnions;
541 		::MakeSelUnions( aUnions, pStart, pEnd, nsSwTblSearchType::TBLSEARCH_NO_UNION_CORRECT );
542 
543 		//Jetzt zu jedem Eintrag die Boxen herausfischen und uebertragen.
544 		for( i = 0; i < aUnions.Count() && bTblIsValid &&
545 									bValidChartSel; ++i )
546 		{
547 			SwSelUnion *pUnion = aUnions[i];
548 			const SwTabFrm *pTable = pUnion->GetTable();
549 
550 			SWRECTFN( pTable )
551             sal_Bool bRTL = pTable->IsRightToLeft();
552 
553 			if( !pTable->IsValid() && nLoopMax  )
554 			{
555 				bTblIsValid = sal_False;
556 				break;
557 			}
558 
559 			_Sort_CellFrms aCellFrms;
560 
561             // Skip any repeated headlines in the follow:
562             const SwLayoutFrm* pRow = pTable->IsFollow() ?
563                                       pTable->GetFirstNonHeadlineRow() :
564                                       (const SwLayoutFrm*)pTable->Lower();
565 
566 			while( pRow && bTblIsValid && bValidChartSel )
567 			{
568 				if( !pRow->IsValid() && nLoopMax )
569 				{
570 					bTblIsValid = sal_False;
571 					break;
572 				}
573 
574 				if( pRow->Frm().IsOver( pUnion->GetUnion() ) )
575 				{
576 					const SwLayoutFrm *pCell = pRow->FirstCell();
577 
578 					while( bValidChartSel && bTblIsValid && pCell &&
579 							pRow->IsAnLower( pCell ) )
580 					{
581 						if( !pCell->IsValid() && nLoopMax  )
582 						{
583 							bTblIsValid = sal_False;
584 							break;
585 						}
586 
587 						ASSERT( pCell->IsCellFrm(), "Frame ohne Celle" );
588 						const SwRect& rUnion = pUnion->GetUnion(),
589 									& rFrmRect = pCell->Frm();
590 
591 						const long nUnionRight = rUnion.Right();
592 						const long nUnionBottom = rUnion.Bottom();
593 						const long nFrmRight = rFrmRect.Right();
594 						const long nFrmBottom = rFrmRect.Bottom();
595 
596 						// liegt das FrmRect ausserhalb der Union, kann es
597 						// ignoriert werden.
598 
599 						const long nXFuzzy = bVert ? 0 : 20;
600 						const long nYFuzzy = bVert ? 20 : 0;
601 
602 						if( !(	rUnion.Top()  + nYFuzzy > nFrmBottom ||
603                                 nUnionBottom < rFrmRect.Top() + nYFuzzy ||
604 								rUnion.Left() + nXFuzzy > nFrmRight ||
605                                 nUnionRight < rFrmRect.Left() + nXFuzzy ))
606 						{
607 							// ok, rUnion is _not_ completely outside of rFrmRect
608 
609 							// wenn es aber nicht komplett in der Union liegt,
610 							// dann ist es fuers Chart eine ungueltige
611 							// Selektion.
612 							if( rUnion.Left() 	<= rFrmRect.Left() + nXFuzzy &&
613 								rFrmRect.Left()	<= nUnionRight &&
614 								rUnion.Left()	<= nFrmRight &&
615 								nFrmRight		<= nUnionRight + nXFuzzy &&
616 								rUnion.Top() 	<= rFrmRect.Top() + nYFuzzy &&
617 								rFrmRect.Top()	<= nUnionBottom &&
618 								rUnion.Top()  	<= nFrmBottom &&
619 								nFrmBottom		<= nUnionBottom+ nYFuzzy )
620 
621 								aCellFrms.push_back(
622                                         _Sort_CellFrm( *(SwCellFrm*)pCell) );
623 							else
624 							{
625 								bValidChartSel = sal_False;
626 								break;
627 							}
628 						}
629 						if ( pCell->GetNext() )
630 						{
631 							pCell = (const SwLayoutFrm*)pCell->GetNext();
632 							if ( pCell->Lower() && pCell->Lower()->IsRowFrm() )
633 								pCell = pCell->FirstCell();
634 						}
635 						else
636 							pCell = ::lcl_FindNextCellFrm( pCell );
637 					}
638 				}
639 				pRow = (const SwLayoutFrm*)pRow->GetNext();
640 			}
641 
642 			if( !bValidChartSel )
643 				break;
644 
645 			// alle Zellen der (Teil-)Tabelle zusammen. Dann teste mal ob
646 			// all huebsch nebeneinander liegen.
647 			size_t n, nCellCnt = 0;
648             long nYPos = LONG_MAX;
649             long nXPos = 0;
650             long nHeight = 0;
651 
652 			for( n = 0 ; n < aCellFrms.size(); ++n )
653 			{
654 				const _Sort_CellFrm& rCF = aCellFrms[ n ];
655 				if( (rCF.pFrm->Frm().*fnRect->fnGetTop)() != nYPos )
656 				{
657 					// neue Zeile
658 					if( n )
659 					{
660 						if( USHRT_MAX == nRowCells )		// 1. Zeilenwechsel
661 							nRowCells = nCellCnt;
662 						else if( nRowCells != nCellCnt )
663 						{
664 							bValidChartSel = sal_False;
665 							break;
666 						}
667 					}
668 					nCellCnt = 1;
669 					nYPos = (rCF.pFrm->Frm().*fnRect->fnGetTop)();
670 					nHeight = (rCF.pFrm->Frm().*fnRect->fnGetHeight)();
671 
672                     nXPos = bRTL ?
673                             (rCF.pFrm->Frm().*fnRect->fnGetLeft)() :
674                             (rCF.pFrm->Frm().*fnRect->fnGetRight)();
675                 }
676                 else if( nXPos == ( bRTL ?
677                                     (rCF.pFrm->Frm().*fnRect->fnGetRight)() :
678                                     (rCF.pFrm->Frm().*fnRect->fnGetLeft)() ) &&
679                          nHeight == (rCF.pFrm->Frm().*fnRect->fnGetHeight)() )
680                 {
681                     nXPos += ( bRTL ? (-1) : 1 ) *
682                              (rCF.pFrm->Frm().*fnRect->fnGetWidth)();
683                     ++nCellCnt;
684                 }
685 				else
686 				{
687 					bValidChartSel = sal_False;
688 					break;
689 				}
690 			}
691 			if( bValidChartSel )
692 			{
693 				if( USHRT_MAX == nRowCells )
694 					nRowCells = nCellCnt;
695 				else if( nRowCells != nCellCnt )
696 					bValidChartSel = sal_False;
697 			}
698 
699 			if( bValidChartSel && pGetCLines )
700 			{
701 				nYPos = LONG_MAX;
702 				SwChartBoxes* pBoxes = 0;
703 				for( n = 0; n < aCellFrms.size(); ++n )
704 				{
705 					const _Sort_CellFrm& rCF = aCellFrms[ n ];
706 					if( (rCF.pFrm->Frm().*fnRect->fnGetTop)() != nYPos )
707 					{
708 						pBoxes = new SwChartBoxes( 255 < nRowCells
709 													? 255 : (sal_uInt8)nRowCells);
710 						pGetCLines->C40_INSERT( SwChartBoxes, pBoxes, pGetCLines->Count() );
711                         nYPos = (rCF.pFrm->Frm().*fnRect->fnGetTop)();
712 					}
713 					SwTableBoxPtr pBox = (SwTableBox*)rCF.pFrm->GetTabBox();
714 					pBoxes->Insert( pBox, pBoxes->Count() );
715 				}
716 			}
717 		}
718 
719 		if( bTblIsValid )
720 			break;
721 
722 		// ansonsten das Layout der Tabelle kurz "kalkulieren" lassen
723 		// und nochmals neu aufsetzen
724 		SwTabFrm *pTable = aUnions[0]->GetTable();
725 		for( i = 0; i < aUnions.Count(); ++i )
726 		{
727 			if( pTable->IsValid() )
728 				pTable->InvalidatePos();
729 			pTable->SetONECalcLowers();
730 			pTable->Calc();
731 			pTable->SetCompletePaint();
732 			if( 0 == (pTable = pTable->GetFollow()) )
733 				break;
734 		}
735 		--nLoopMax;
736 		if( pGetCLines )
737 			pGetCLines->DeleteAndDestroy( 0, pGetCLines->Count() );
738 	} while( sal_True );
739 
740 	ASSERT( nLoopMax, "das Layout der Tabelle wurde nicht valide!" );
741 
742 	if( !bValidChartSel && pGetCLines )
743 		pGetCLines->DeleteAndDestroy( 0, pGetCLines->Count() );
744 
745 	return bValidChartSel;
746 }
747 
748 
749 sal_Bool IsFrmInTblSel( const SwRect& rUnion, const SwFrm* pCell )
750 {
751 	ASSERT( pCell->IsCellFrm(), "Frame ohne Gazelle" );
752 
753     if( pCell->FindTabFrm()->IsVertical() )
754         return ( rUnion.Right() >= pCell->Frm().Right() &&
755                  rUnion.Left() <= pCell->Frm().Left() &&
756             (( rUnion.Top() <= pCell->Frm().Top()+20 &&
757                rUnion.Bottom() > pCell->Frm().Top() ) ||
758              ( rUnion.Top() >= pCell->Frm().Top() &&
759                rUnion.Bottom() < pCell->Frm().Bottom() )) ? sal_True : sal_False );
760 
761     return (
762 		rUnion.Top() <= pCell->Frm().Top() &&
763 		rUnion.Bottom() >= pCell->Frm().Bottom() &&
764 
765 		(( rUnion.Left() <= pCell->Frm().Left()+20 &&
766 		   rUnion.Right() > pCell->Frm().Left() ) ||
767 
768 		 ( rUnion.Left() >= pCell->Frm().Left() &&
769 		   rUnion.Right() < pCell->Frm().Right() )) ? sal_True : sal_False );
770 }
771 
772 sal_Bool GetAutoSumSel( const SwCrsrShell& rShell, SwCellFrms& rBoxes )
773 {
774     SwShellCrsr* pCrsr = rShell.pCurCrsr;
775     if ( rShell.IsTableMode() )
776         pCrsr = rShell.pTblCrsr;
777 
778 	const SwLayoutFrm *pStart = pCrsr->GetCntntNode()->getLayoutFrm( rShell.GetLayout(),
779 					  &pCrsr->GetPtPos() )->GetUpper(),
780 					  *pEnd	  = pCrsr->GetCntntNode(sal_False)->getLayoutFrm( rShell.GetLayout(),
781 					  &pCrsr->GetMkPos() )->GetUpper();
782 
783     const SwLayoutFrm* pSttCell = pStart;
784 	while( pSttCell && !pSttCell->IsCellFrm() )
785 		pSttCell = pSttCell->GetUpper();
786 
787 	//Zuerst lassen wir uns die Tabellen und die Rechtecke heraussuchen.
788 	SwSelUnions aUnions;
789 
790 	// default erstmal nach oben testen, dann nach links
791 	::MakeSelUnions( aUnions, pStart, pEnd, nsSwTblSearchType::TBLSEARCH_COL );
792 
793 	sal_Bool bTstRow = sal_True, bFound = sal_False;
794 	sal_uInt16 i;
795 
796 	// 1. teste ob die darueber liegende Box Value/Formel enhaelt:
797 	for( i = 0; i < aUnions.Count(); ++i )
798 	{
799 		SwSelUnion *pUnion = aUnions[i];
800 		const SwTabFrm *pTable = pUnion->GetTable();
801 
802         // Skip any repeated headlines in the follow:
803         const SwLayoutFrm* pRow = pTable->IsFollow() ?
804                                   pTable->GetFirstNonHeadlineRow() :
805                                   (const SwLayoutFrm*)pTable->Lower();
806 
807 		while( pRow )
808 		{
809 			if( pRow->Frm().IsOver( pUnion->GetUnion() ) )
810 			{
811 				const SwCellFrm* pUpperCell = 0;
812 				const SwLayoutFrm *pCell = pRow->FirstCell();
813 
814 				while( pCell && pRow->IsAnLower( pCell ) )
815 				{
816 					if( pCell == pSttCell )
817 					{
818 						sal_uInt16 nWhichId = 0;
819 						for( sal_uInt16 n = rBoxes.Count(); n; )
820 							if( USHRT_MAX != ( nWhichId = rBoxes[ --n ]
821 								->GetTabBox()->IsFormulaOrValueBox() ))
822 								break;
823 
824 						// alle Boxen zusammen, nicht mehr die Zeile
825 						// pruefen, wenn eine Formel oder Value gefunden wurde
826 						bTstRow = 0 == nWhichId || USHRT_MAX == nWhichId;
827 						bFound = sal_True;
828 						break;
829 					}
830 
831 					ASSERT( pCell->IsCellFrm(), "Frame ohne Celle" );
832 					if( ::IsFrmInTblSel( pUnion->GetUnion(), pCell ) )
833 						pUpperCell = (SwCellFrm*)pCell;
834 
835 					if( pCell->GetNext() )
836 					{
837 						pCell = (const SwLayoutFrm*)pCell->GetNext();
838                         if ( pCell->Lower() && pCell->Lower()->IsRowFrm() )
839 							pCell = pCell->FirstCell();
840 					}
841 					else
842 						pCell = ::lcl_FindNextCellFrm( pCell );
843 				}
844 
845 				if( pUpperCell )
846 					rBoxes.Insert( pUpperCell, rBoxes.Count() );
847 			}
848 			if( bFound )
849 			{
850 				i = aUnions.Count();
851 				break;
852 			}
853 			pRow = (const SwLayoutFrm*)pRow->GetNext();
854 		}
855 	}
856 
857 
858 	// 2. teste ob die links liegende Box Value/Formel enhaelt:
859 	if( bTstRow )
860 	{
861 		bFound = sal_False;
862 
863 		rBoxes.Remove( 0, rBoxes.Count() );
864 		aUnions.DeleteAndDestroy( 0, aUnions.Count() );
865 		::MakeSelUnions( aUnions, pStart, pEnd, nsSwTblSearchType::TBLSEARCH_ROW );
866 
867 		for( i = 0; i < aUnions.Count(); ++i )
868 		{
869 			SwSelUnion *pUnion = aUnions[i];
870 			const SwTabFrm *pTable = pUnion->GetTable();
871 
872             // Skip any repeated headlines in the follow:
873             const SwLayoutFrm* pRow = pTable->IsFollow() ?
874                                       pTable->GetFirstNonHeadlineRow() :
875                                       (const SwLayoutFrm*)pTable->Lower();
876 
877 			while( pRow )
878 			{
879 				if( pRow->Frm().IsOver( pUnion->GetUnion() ) )
880 				{
881 					const SwLayoutFrm *pCell = pRow->FirstCell();
882 
883 					while( pCell && pRow->IsAnLower( pCell ) )
884 					{
885 						if( pCell == pSttCell )
886 						{
887 							sal_uInt16 nWhichId = 0;
888 							for( sal_uInt16 n = rBoxes.Count(); n; )
889 								if( USHRT_MAX != ( nWhichId = rBoxes[ --n ]
890 									->GetTabBox()->IsFormulaOrValueBox() ))
891 									break;
892 
893 							// alle Boxen zusammen, nicht mehr die Zeile
894 							// pruefen, wenn eine Formel oder Value gefunden wurde
895 							bFound = 0 != nWhichId && USHRT_MAX != nWhichId;
896 							bTstRow = sal_False;
897 							break;
898 						}
899 
900 						ASSERT( pCell->IsCellFrm(), "Frame ohne Celle" );
901 						if( ::IsFrmInTblSel( pUnion->GetUnion(), pCell ) )
902 						{
903 							const SwCellFrm* pC = (SwCellFrm*)pCell;
904 							rBoxes.Insert( pC, rBoxes.Count() );
905 						}
906 						if( pCell->GetNext() )
907 						{
908 							pCell = (const SwLayoutFrm*)pCell->GetNext();
909                             if ( pCell->Lower() && pCell->Lower()->IsRowFrm() )
910 								pCell = pCell->FirstCell();
911 						}
912 						else
913 							pCell = ::lcl_FindNextCellFrm( pCell );
914 					}
915 				}
916 				if( !bTstRow )
917 				{
918 					i = aUnions.Count();
919 					break;
920 				}
921 
922 				pRow = (const SwLayoutFrm*)pRow->GetNext();
923 			}
924 		}
925 	}
926 
927 	return bFound;
928 }
929 
930 sal_Bool HasProtectedCells( const SwSelBoxes& rBoxes )
931 {
932 	sal_Bool bRet = sal_False;
933 	for( sal_uInt16 n = 0, nCnt = rBoxes.Count(); n < nCnt; ++n )
934 		if( rBoxes[ n ]->GetFrmFmt()->GetProtect().IsCntntProtected() )
935 		{
936 			bRet = sal_True;
937 			break;
938 		}
939 	return bRet;
940 }
941 
942 
943 _CmpLPt::_CmpLPt( const Point& rPt, const SwTableBox* pBox, sal_Bool bVertical )
944     : aPos( rPt ), pSelBox( pBox ), bVert( bVertical )
945 {}
946 
947 void lcl_InsTblBox( SwTableNode* pTblNd, SwDoc* pDoc, SwTableBox* pBox,
948 						sal_uInt16 nInsPos, sal_uInt16 nCnt = 1 )
949 {
950 	ASSERT( pBox->GetSttNd(), "Box ohne Start-Node" );
951 	SwCntntNode* pCNd = pDoc->GetNodes()[ pBox->GetSttIdx() + 1 ]
952 								->GetCntntNode();
953 	if( pCNd && pCNd->IsTxtNode() )
954 		pDoc->GetNodes().InsBoxen( pTblNd, pBox->GetUpper(),
955 				(SwTableBoxFmt*)pBox->GetFrmFmt(),
956 				((SwTxtNode*)pCNd)->GetTxtColl(),
957                 pCNd->GetpSwAttrSet(),
958 				nInsPos, nCnt );
959 	else
960 		pDoc->GetNodes().InsBoxen( pTblNd, pBox->GetUpper(),
961 				(SwTableBoxFmt*)pBox->GetFrmFmt(),
962 				(SwTxtFmtColl*)pDoc->GetDfltTxtFmtColl(), 0,
963 				nInsPos, nCnt );
964 }
965 
966 sal_Bool IsEmptyBox( const SwTableBox& rBox, SwPaM& rPam )
967 {
968 	rPam.GetPoint()->nNode = *rBox.GetSttNd()->EndOfSectionNode();
969 	rPam.Move( fnMoveBackward, fnGoCntnt );
970 	rPam.SetMark();
971 	rPam.GetPoint()->nNode = *rBox.GetSttNd();
972 	rPam.Move( fnMoveForward, fnGoCntnt );
973 	sal_Bool bRet = *rPam.GetMark() == *rPam.GetPoint()
974         && ( rBox.GetSttNd()->GetIndex() + 1 == rPam.GetPoint()->nNode.GetIndex() );
975 
976 	if( bRet )
977 	{
978 		// dann teste mal auf absatzgebundenen Flys
979 		const SwSpzFrmFmts& rFmts = *rPam.GetDoc()->GetSpzFrmFmts();
980 		sal_uLong nSttIdx = rPam.GetPoint()->nNode.GetIndex(),
981 			  nEndIdx = rBox.GetSttNd()->EndOfSectionIndex(),
982 			  nIdx;
983 
984 		for( sal_uInt16 n = 0; n < rFmts.Count(); ++n )
985 		{
986 			const SwFmtAnchor& rAnchor = rFmts[n]->GetAnchor();
987             const SwPosition* pAPos = rAnchor.GetCntntAnchor();
988             if (pAPos &&
989                 ((FLY_AT_PARA == rAnchor.GetAnchorId()) ||
990                  (FLY_AT_CHAR == rAnchor.GetAnchorId())) &&
991 				nSttIdx <= ( nIdx = pAPos->nNode.GetIndex() ) &&
992 				nIdx < nEndIdx )
993 			{
994 				bRet = sal_False;
995 				break;
996 			}
997 		}
998 	}
999 	return bRet;
1000 }
1001 
1002 
1003 void GetMergeSel( const SwPaM& rPam, SwSelBoxes& rBoxes,
1004 				SwTableBox** ppMergeBox, SwUndoTblMerge* pUndo )
1005 {
1006 	if( rBoxes.Count() )
1007 		rBoxes.Remove( sal_uInt16(0), rBoxes.Count() );
1008 
1009 	//Zuerst lassen wir uns die Tabellen und die Rechtecke heraussuchen.
1010 	ASSERT( rPam.GetCntntNode() && rPam.GetCntntNode( sal_False ),
1011 			"Tabselection nicht auf Cnt." );
1012 
1013 //JP 24.09.96: Merge mit wiederholenden TabellenHeadline funktioniert nicht
1014 // 				richtig. Warum nicht Point 0,0 benutzen? Dann ist garantiert,
1015 //				das die 1. Headline mit drin ist.
1016 //	Point aPt( rShell.GetCharRect().Pos() );
1017 	Point aPt( 0, 0 );
1018 
1019     const SwCntntNode* pCntNd = rPam.GetCntntNode();
1020 	const SwLayoutFrm *pStart = pCntNd->getLayoutFrm( pCntNd->GetDoc()->GetCurrentLayout(),
1021 														&aPt )->GetUpper();
1022     pCntNd = rPam.GetCntntNode(sal_False);
1023 	const SwLayoutFrm *pEnd = pCntNd->getLayoutFrm( pCntNd->GetDoc()->GetCurrentLayout(),
1024 														&aPt )->GetUpper();
1025 
1026 	SwSelUnions aUnions;
1027 	::MakeSelUnions( aUnions, pStart, pEnd );
1028 	if( !aUnions.Count() )
1029 		return;
1030 
1031 	const SwTable *pTable = aUnions[0]->GetTable()->GetTable();
1032 	SwDoc* pDoc = (SwDoc*)pStart->GetFmt()->GetDoc();
1033 	SwTableNode* pTblNd = (SwTableNode*)pTable->GetTabSortBoxes()[ 0 ]->
1034 										GetSttNd()->FindTableNode();
1035 
1036 	_MergePos aPosArr;		// Sort-Array mit den Positionen der Frames
1037 	long nWidth;
1038 	SwTableBox* pLastBox = 0;
1039 
1040     SWRECTFN( pStart->GetUpper() )
1041 
1042 	for ( sal_uInt16 i = 0; i < aUnions.Count(); ++i )
1043 	{
1044 		const SwTabFrm *pTabFrm = aUnions[i]->GetTable();
1045 
1046 		SwRect &rUnion = aUnions[i]->GetUnion();
1047 
1048         // Skip any repeated headlines in the follow:
1049         const SwLayoutFrm* pRow = pTabFrm->IsFollow() ?
1050                                   pTabFrm->GetFirstNonHeadlineRow() :
1051                                   (const SwLayoutFrm*)pTabFrm->Lower();
1052 
1053 		while ( pRow )
1054 		{
1055 			if ( pRow->Frm().IsOver( rUnion ) )
1056 			{
1057 				const SwLayoutFrm *pCell = pRow->FirstCell();
1058 
1059 				while ( pCell && pRow->IsAnLower( pCell ) )
1060 				{
1061 					ASSERT( pCell->IsCellFrm(), "Frame ohne Celle" );
1062 						// in der vollen Breite ueberlappend ?
1063 					if( rUnion.Top() <= pCell->Frm().Top() &&
1064 						rUnion.Bottom() >= pCell->Frm().Bottom() )
1065 					{
1066 						SwTableBox* pBox =(SwTableBox*)((SwCellFrm*)pCell)->GetTabBox();
1067 
1068 						// nur nach rechts ueberlappend
1069 						if( ( rUnion.Left() - COLFUZZY ) <= pCell->Frm().Left() &&
1070 							( rUnion.Right() - COLFUZZY ) > pCell->Frm().Left() )
1071 						{
1072 							if( ( rUnion.Right() + COLFUZZY ) < pCell->Frm().Right() )
1073 							{
1074 								sal_uInt16 nInsPos = pBox->GetUpper()->
1075 													GetTabBoxes().C40_GETPOS( SwTableBox, pBox )+1;
1076 								lcl_InsTblBox( pTblNd, pDoc, pBox, nInsPos );
1077 								pBox->ClaimFrmFmt();
1078 								SwFmtFrmSize aNew(
1079 										pBox->GetFrmFmt()->GetFrmSize() );
1080 								nWidth = rUnion.Right() - pCell->Frm().Left();
1081 								nWidth = nWidth * aNew.GetWidth() /
1082 										 pCell->Frm().Width();
1083 								long nTmpWidth = aNew.GetWidth() - nWidth;
1084 								aNew.SetWidth( nWidth );
1085                                 pBox->GetFrmFmt()->SetFmtAttr( aNew );
1086 								// diese Box ist selektiert
1087 								pLastBox = pBox;
1088 								rBoxes.Insert( pBox );
1089                                 aPosArr.Insert(
1090                                     _CmpLPt( (pCell->Frm().*fnRect->fnGetPos)(),
1091                                     pBox, bVert ) );
1092 
1093 								pBox = pBox->GetUpper()->GetTabBoxes()[ nInsPos ];
1094 								aNew.SetWidth( nTmpWidth );
1095 								pBox->ClaimFrmFmt();
1096                                 pBox->GetFrmFmt()->SetFmtAttr( aNew );
1097 
1098 								if( pUndo )
1099 									pUndo->AddNewBox( pBox->GetSttIdx() );
1100 							}
1101 							else
1102 							{
1103 								// diese Box ist selektiert
1104 								pLastBox = pBox;
1105 								rBoxes.Insert( pBox );
1106 #if OSL_DEBUG_LEVEL > 1
1107                                 Point aInsPoint( (pCell->Frm().*fnRect->fnGetPos)() );
1108 #endif
1109                                 aPosArr.Insert(
1110                                     _CmpLPt( (pCell->Frm().*fnRect->fnGetPos)(),
1111 									pBox, bVert ) );
1112 							}
1113 						}
1114 						// oder rechts und links ueberlappend
1115 						else if( ( rUnion.Left() - COLFUZZY ) >= pCell->Frm().Left() &&
1116 								( rUnion.Right() + COLFUZZY ) < pCell->Frm().Right() )
1117 						{
1118 							sal_uInt16 nInsPos = pBox->GetUpper()->GetTabBoxes().
1119 											C40_GETPOS( SwTableBox, pBox )+1;
1120 							lcl_InsTblBox( pTblNd, pDoc, pBox, nInsPos, 2 );
1121 							pBox->ClaimFrmFmt();
1122 							SwFmtFrmSize aNew(
1123 										pBox->GetFrmFmt()->GetFrmSize() );
1124 							long nLeft = rUnion.Left() - pCell->Frm().Left();
1125 							nLeft = nLeft * aNew.GetWidth() /
1126 									pCell->Frm().Width();
1127 							long nRight = pCell->Frm().Right() - rUnion.Right();
1128 							nRight = nRight * aNew.GetWidth() /
1129 									 pCell->Frm().Width();
1130 							nWidth = aNew.GetWidth() - nLeft - nRight;
1131 
1132 							aNew.SetWidth( nLeft );
1133                             pBox->GetFrmFmt()->SetFmtAttr( aNew );
1134 
1135 							{
1136 							const SfxPoolItem* pItem;
1137 							if( SFX_ITEM_SET == pBox->GetFrmFmt()->GetAttrSet()
1138 										.GetItemState( RES_BOX, sal_False, &pItem ))
1139 							{
1140 								SvxBoxItem aBox( *(SvxBoxItem*)pItem );
1141 								aBox.SetLine( 0, BOX_LINE_RIGHT );
1142                                 pBox->GetFrmFmt()->SetFmtAttr( aBox );
1143 							}
1144 							}
1145 
1146 							pBox = pBox->GetUpper()->GetTabBoxes()[ nInsPos ];
1147 							aNew.SetWidth( nWidth );
1148 							pBox->ClaimFrmFmt();
1149                             pBox->GetFrmFmt()->SetFmtAttr( aNew );
1150 
1151 							if( pUndo )
1152 								pUndo->AddNewBox( pBox->GetSttIdx() );
1153 
1154 							// diese Box ist selektiert
1155 							pLastBox = pBox;
1156 							rBoxes.Insert( pBox );
1157                             aPosArr.Insert(
1158                                 _CmpLPt( (pCell->Frm().*fnRect->fnGetPos)(),
1159                                 pBox, bVert ) );
1160 
1161 							pBox = pBox->GetUpper()->GetTabBoxes()[ nInsPos+1 ];
1162 							aNew.SetWidth( nRight );
1163 							pBox->ClaimFrmFmt();
1164                             pBox->GetFrmFmt()->SetFmtAttr( aNew );
1165 
1166 							if( pUndo )
1167 								pUndo->AddNewBox( pBox->GetSttIdx() );
1168 						}
1169 						// oder reicht die rechte Kante der Box in den
1170 						// selektierten Bereich?
1171 						else if( ( pCell->Frm().Right() - COLFUZZY ) < rUnion.Right() &&
1172 								 ( pCell->Frm().Right() - COLFUZZY ) > rUnion.Left() &&
1173 								 ( pCell->Frm().Left() + COLFUZZY ) < rUnion.Left() )
1174 						{
1175 							// dann muss eine neue Box einfuegt und die
1176 							// Breiten angepasst werden
1177 							sal_uInt16 nInsPos = pBox->GetUpper()->GetTabBoxes().
1178 											C40_GETPOS( SwTableBox, pBox )+1;
1179 							lcl_InsTblBox( pTblNd, pDoc, pBox, nInsPos, 1 );
1180 
1181 							SwFmtFrmSize aNew(pBox->GetFrmFmt()->GetFrmSize() );
1182 							long nLeft = rUnion.Left() - pCell->Frm().Left(),
1183 								nRight = pCell->Frm().Right() - rUnion.Left();
1184 
1185 							nLeft = nLeft * aNew.GetWidth() /
1186 									pCell->Frm().Width();
1187 							nRight = nRight * aNew.GetWidth() /
1188 									pCell->Frm().Width();
1189 
1190 							aNew.SetWidth( nLeft );
1191                             pBox->ClaimFrmFmt()->SetFmtAttr( aNew );
1192 
1193 								// diese Box ist selektiert
1194 							pBox = pBox->GetUpper()->GetTabBoxes()[ nInsPos ];
1195 							aNew.SetWidth( nRight );
1196 							pBox->ClaimFrmFmt();
1197                             pBox->GetFrmFmt()->SetFmtAttr( aNew );
1198 
1199 							pLastBox = pBox;
1200 							rBoxes.Insert( pBox );
1201                             aPosArr.Insert( _CmpLPt( Point( rUnion.Left(),
1202                                                 pCell->Frm().Top()), pBox, bVert ));
1203 
1204 							if( pUndo )
1205 								pUndo->AddNewBox( pBox->GetSttIdx() );
1206 						}
1207 					}
1208 					if ( pCell->GetNext() )
1209 					{
1210 						pCell = (const SwLayoutFrm*)pCell->GetNext();
1211                         // --> FME 2005-11-03 #125288# Check if table cell is not empty
1212                         if ( pCell->Lower() && pCell->Lower()->IsRowFrm() )
1213 							pCell = pCell->FirstCell();
1214 					}
1215 					else
1216 						pCell = ::lcl_FindNextCellFrm( pCell );
1217 				}
1218 			}
1219 			pRow = (const SwLayoutFrm*)pRow->GetNext();
1220 		}
1221 	}
1222 
1223 	// keine SSelection / keine gefundenen Boxen
1224 	if( 1 >= rBoxes.Count() )
1225 		return;
1226 
1227 	// dann suche mal alle Boxen, die nebeneinander liegen, und verbinde
1228 	// deren Inhalte mit Blanks. Alle untereinander liegende werden als
1229 	// Absaetze zusammengefasst
1230 
1231 	// 1. Loesung: gehe ueber das Array und
1232 	// 		alle auf der gleichen Y-Ebene werden mit Blanks getrennt
1233 	//		alle anderen werden als Absaetze getrennt.
1234 	sal_Bool bCalcWidth = sal_True;
1235 	const SwTableBox* pFirstBox = aPosArr[ 0 ].pSelBox;
1236 
1237 	// JP 27.03.98:  Optimierung - falls die Boxen einer Line leer sind,
1238 	//				dann werden jetzt dafuer keine Blanks und
1239 	//				kein Umbruch mehr eingefuegt.
1240 	//Block damit SwPaM, SwPosition vom Stack geloescht werden
1241 	{
1242 		SwPaM aPam( pDoc->GetNodes() );
1243 
1244 #if defined( DEL_ONLY_EMPTY_LINES )
1245 		nWidth = pFirstBox->GetFrmFmt()->GetFrmSize().GetWidth();
1246 		sal_Bool bEmptyLine = sal_True;
1247 		sal_uInt16 n, nSttPos = 0;
1248 
1249 		for( n = 0; n < aPosArr.Count(); ++n )
1250 		{
1251 			const _CmpLPt& rPt = aPosArr[ n ];
1252 			if( n && aPosArr[ n - 1 ].Y() == rPt.Y() )	// gleiche Ebene ?
1253 			{
1254 				if( bEmptyLine && !IsEmptyBox( *rPt.pSelBox, aPam ))
1255 					bEmptyLine = sal_False;
1256 				if( bCalcWidth )
1257 					nWidth += rPt.pSelBox->GetFrmFmt()->GetFrmSize().GetWidth();
1258 			}
1259 			else
1260 			{
1261 				if( bCalcWidth && n )
1262 					bCalcWidth = sal_False;		// eine Zeile fertig
1263 
1264 				if( bEmptyLine && nSttPos < n )
1265 				{
1266 					// dann ist die gesamte Line leer und braucht
1267 					// nicht mit Blanks aufgefuellt und als Absatz
1268 					// eingefuegt werden.
1269 					if( pUndo )
1270 						for( sal_uInt16 i = nSttPos; i < n; ++i )
1271 							pUndo->SaveCollection( *aPosArr[ i ].pSelBox );
1272 
1273 					aPosArr.Remove( nSttPos, n - nSttPos );
1274 					n = nSttPos;
1275 				}
1276 				else
1277 					nSttPos = n;
1278 
1279 				bEmptyLine = IsEmptyBox( *aPosArr[n].pSelBox, aPam );
1280 			}
1281 		}
1282 		if( bEmptyLine && nSttPos < n )
1283 		{
1284 			if( pUndo )
1285 				for( sal_uInt16 i = nSttPos; i < n; ++i )
1286 					pUndo->SaveCollection( *aPosArr[ i ].pSelBox );
1287 			aPosArr.Remove( nSttPos, n - nSttPos );
1288 		}
1289 #elsif defined( DEL_EMPTY_BOXES_AT_START_AND_END )
1290 
1291 		nWidth = pFirstBox->GetFrmFmt()->GetFrmSize().GetWidth();
1292 		sal_uInt16 n, nSttPos = 0, nSEndPos = 0, nESttPos = 0;
1293 
1294 		for( n = 0; n < aPosArr.Count(); ++n )
1295 		{
1296 			const _CmpLPt& rPt = aPosArr[ n ];
1297 			if( n && aPosArr[ n - 1 ].Y() == rPt.Y() )	// gleiche Ebene ?
1298 			{
1299 				sal_Bool bEmptyBox = IsEmptyBox( *rPt.pSelBox, aPam );
1300 				if( bEmptyBox )
1301 				{
1302 					if( nSEndPos == n )		// der Anfang ist leer
1303 						nESttPos = ++nSEndPos;
1304 				}
1305 				else 						// das Ende kann leer sein
1306 					nESttPos = n+1;
1307 
1308 				if( bCalcWidth )
1309 					nWidth += rPt.pSelBox->GetFrmFmt()->GetFrmSize().GetWidth();
1310 			}
1311 			else
1312 			{
1313 				if( bCalcWidth && n )
1314 					bCalcWidth = sal_False;		// eine Zeile fertig
1315 
1316 				// zuerst die vom Anfang
1317 				if( nSttPos < nSEndPos )
1318 				{
1319 					// dann ist der vorder Teil der Line leer und braucht
1320 					// nicht mit Blanks aufgefuellt werden.
1321 					if( pUndo )
1322 						for( sal_uInt16 i = nSttPos; i < nSEndPos; ++i )
1323 							pUndo->SaveCollection( *aPosArr[ i ].pSelBox );
1324 
1325 					sal_uInt16 nCnt = nSEndPos - nSttPos;
1326 					aPosArr.Remove( nSttPos, nCnt );
1327 					nESttPos -= nCnt;
1328 					n -= nCnt;
1329 				}
1330 
1331 				if( nESttPos < n )
1332 				{
1333 					// dann ist der vorder Teil der Line leer und braucht
1334 					// nicht mit Blanks aufgefuellt werden.
1335 					if( pUndo )
1336 						for( sal_uInt16 i = nESttPos; i < n; ++i )
1337 							pUndo->SaveCollection( *aPosArr[ i ].pSelBox );
1338 
1339 					sal_uInt16 nCnt = n - nESttPos;
1340 					aPosArr.Remove( nESttPos, nCnt );
1341 					n -= nCnt;
1342 				}
1343 
1344 				nSttPos = nSEndPos = nESttPos = n;
1345 				if( IsEmptyBox( *aPosArr[n].pSelBox, aPam ))
1346 					++nSEndPos;
1347 				else
1348 					++nESttPos;
1349 			}
1350 		}
1351 
1352 		// zuerst die vom Anfang
1353 		if( nSttPos < nSEndPos )
1354 		{
1355 			// dann ist der vorder Teil der Line leer und braucht
1356 			// nicht mit Blanks aufgefuellt werden.
1357 			if( pUndo )
1358 				for( sal_uInt16 i = nSttPos; i < nSEndPos; ++i )
1359 					pUndo->SaveCollection( *aPosArr[ i ].pSelBox );
1360 
1361 			sal_uInt16 nCnt = nSEndPos - nSttPos;
1362 			aPosArr.Remove( nSttPos, nCnt );
1363 			nESttPos -= nCnt;
1364 			n -= nCnt;
1365 		}
1366 		if( nESttPos < n )
1367 		{
1368 			// dann ist der vorder Teil der Line leer und braucht
1369 			// nicht mit Blanks aufgefuellt werden.
1370 			if( pUndo )
1371 				for( sal_uInt16 i = nESttPos; i < n; ++i )
1372 					pUndo->SaveCollection( *aPosArr[ i ].pSelBox );
1373 
1374 			sal_uInt16 nCnt = n - nESttPos;
1375 			aPosArr.Remove( nESttPos, nCnt );
1376 		}
1377 #else
1378 // DEL_ALL_EMPTY_BOXES
1379 
1380 		nWidth = 0;
1381 		long nY = aPosArr.Count() ?
1382                     ( bVert ?
1383 					  aPosArr[ 0 ].X() :
1384 					  aPosArr[ 0 ].Y() ) :
1385 				  0;
1386 
1387 		for( sal_uInt16 n = 0; n < aPosArr.Count(); ++n )
1388 		{
1389 			const _CmpLPt& rPt = aPosArr[ n ];
1390             if( bCalcWidth )
1391 			{
1392                 if( nY == ( bVert ? rPt.X() : rPt.Y() ) )            // gleiche Ebene ?
1393 					nWidth += rPt.pSelBox->GetFrmFmt()->GetFrmSize().GetWidth();
1394 				else
1395 					bCalcWidth = sal_False;		// eine Zeile fertig
1396 			}
1397 
1398 			if( IsEmptyBox( *rPt.pSelBox, aPam ) )
1399 			{
1400 				if( pUndo )
1401 					pUndo->SaveCollection( *rPt.pSelBox );
1402 
1403 				aPosArr.Remove( n, 1 );
1404 				--n;
1405 			}
1406 		}
1407 #endif
1408 	}
1409 
1410 	// lege schon mal die neue Box an
1411 	{
1412 		SwTableBox* pTmpBox = rBoxes[0];
1413 		SwTableLine* pInsLine = pTmpBox->GetUpper();
1414 		sal_uInt16 nInsPos = pInsLine->GetTabBoxes().C40_GETPOS( SwTableBox, pTmpBox );
1415 
1416 		lcl_InsTblBox( pTblNd, pDoc, pTmpBox, nInsPos );
1417 		(*ppMergeBox) = pInsLine->GetTabBoxes()[ nInsPos ];
1418 		pInsLine->GetTabBoxes().Remove( nInsPos );		// wieder austragen
1419 		(*ppMergeBox)->SetUpper( 0 );
1420 		(*ppMergeBox)->ClaimFrmFmt();
1421 
1422 		// setze die Umrandung: von der 1. Box die linke/obere von der
1423 		// letzten Box die rechte/untere Kante:
1424 		if( pLastBox && pFirstBox )
1425 		{
1426 			SvxBoxItem aBox( pFirstBox->GetFrmFmt()->GetBox() );
1427 			const SvxBoxItem& rBox = pLastBox->GetFrmFmt()->GetBox();
1428 			aBox.SetLine( rBox.GetRight(), BOX_LINE_RIGHT );
1429 			aBox.SetLine( rBox.GetBottom(), BOX_LINE_BOTTOM );
1430 			if( aBox.GetLeft() || aBox.GetTop() ||
1431 				aBox.GetRight() || aBox.GetBottom() )
1432                 (*ppMergeBox)->GetFrmFmt()->SetFmtAttr( aBox );
1433 		}
1434 	}
1435 
1436 	//Block damit SwPaM, SwPosition vom Stack geloescht werden
1437 	if( aPosArr.Count() )
1438 	{
1439         SwTxtNode* pTxtNd = 0;
1440 		SwPosition aInsPos( *(*ppMergeBox)->GetSttNd() );
1441 		SwNodeIndex& rInsPosNd = aInsPos.nNode;
1442 
1443 		SwPaM aPam( aInsPos );
1444 
1445 		for( sal_uInt16 n = 0; n < aPosArr.Count(); ++n )
1446 		{
1447 			const _CmpLPt& rPt = aPosArr[ n ];
1448 			aPam.GetPoint()->nNode.Assign( *rPt.pSelBox->GetSttNd()->
1449 											EndOfSectionNode(), -1 );
1450 			SwCntntNode* pCNd = aPam.GetCntntNode();
1451 			sal_uInt16 nL = pCNd ? pCNd->Len() : 0;
1452 			aPam.GetPoint()->nContent.Assign( pCNd, nL );
1453 
1454 			SwNodeIndex aSttNdIdx( *rPt.pSelBox->GetSttNd(), 1 );
1455             // ein Node muss in der Box erhalten bleiben (sonst wird beim
1456             // Move die gesamte Section geloescht)
1457             bool const bUndo(pDoc->GetIDocumentUndoRedo().DoesUndo());
1458             if( pUndo )
1459             {
1460                 pDoc->GetIDocumentUndoRedo().DoUndo(false);
1461             }
1462             pDoc->AppendTxtNode( *aPam.GetPoint() );
1463             if( pUndo )
1464             {
1465                 pDoc->GetIDocumentUndoRedo().DoUndo(bUndo);
1466             }
1467             SwNodeRange aRg( aSttNdIdx, aPam.GetPoint()->nNode );
1468             rInsPosNd++;
1469             if( pUndo )
1470                 pUndo->MoveBoxCntnt( pDoc, aRg, rInsPosNd );
1471             else
1472             {
1473                 pDoc->MoveNodeRange( aRg, rInsPosNd,
1474                     IDocumentContentOperations::DOC_MOVEDEFAULT );
1475             }
1476             // wo steht jetzt aInsPos ??
1477 
1478             if( bCalcWidth )
1479                 bCalcWidth = sal_False;		// eine Zeile fertig
1480 
1481 			// den initialen TextNode ueberspringen
1482 			rInsPosNd.Assign( pDoc->GetNodes(),
1483 							rInsPosNd.GetNode().EndOfSectionIndex() - 2 );
1484 			pTxtNd = rInsPosNd.GetNode().GetTxtNode();
1485 			if( pTxtNd )
1486 				aInsPos.nContent.Assign( pTxtNd, pTxtNd->GetTxt().Len() );
1487 		}
1488 
1489 		// in der MergeBox sollte jetzt der gesamte Text stehen
1490 		// loesche jetzt noch den initialen TextNode
1491 		ASSERT( (*ppMergeBox)->GetSttIdx()+2 <
1492 				(*ppMergeBox)->GetSttNd()->EndOfSectionIndex(),
1493 					"leere Box" );
1494 		SwNodeIndex aIdx( *(*ppMergeBox)->GetSttNd()->EndOfSectionNode(), -1 );
1495 		pDoc->GetNodes().Delete( aIdx, 1 );
1496 	}
1497 
1498 	// setze die Breite der Box
1499     (*ppMergeBox)->GetFrmFmt()->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nWidth, 0 ));
1500 	if( pUndo )
1501 		pUndo->AddNewBox( (*ppMergeBox)->GetSttIdx() );
1502 }
1503 
1504 
1505 static sal_Bool lcl_CheckCol( const _FndBox*& rpFndBox, void* pPara );
1506 
1507 static sal_Bool lcl_CheckRow( const _FndLine*& rpFndLine, void* pPara )
1508 {
1509 	((_FndLine*)rpFndLine)->GetBoxes().ForEach( &lcl_CheckCol, pPara );
1510 	return *(sal_Bool*)pPara;
1511 }
1512 
1513 static sal_Bool lcl_CheckCol( const _FndBox*& rpFndBox, void* pPara )
1514 {
1515 	if( !rpFndBox->GetBox()->GetSttNd() )
1516 	{
1517 		if( rpFndBox->GetLines().Count() !=
1518 			rpFndBox->GetBox()->GetTabLines().Count() )
1519 			*((sal_Bool*)pPara) = sal_False;
1520 		else
1521 			((_FndBox*)rpFndBox)->GetLines().ForEach( &lcl_CheckRow, pPara );
1522 	}
1523 	// Box geschuetzt ??
1524 	else if( rpFndBox->GetBox()->GetFrmFmt()->GetProtect().IsCntntProtected() )
1525 		*((sal_Bool*)pPara) = sal_False;
1526 	return *(sal_Bool*)pPara;
1527 }
1528 
1529 
1530 sal_uInt16 CheckMergeSel( const SwPaM& rPam )
1531 {
1532 	SwSelBoxes aBoxes;
1533 //JP 24.09.96: Merge mit wiederholenden TabellenHeadline funktioniert nicht
1534 // 				richtig. Warum nicht Point 0,0 benutzen? Dann ist garantiert,
1535 //				das die 1. Headline mit drin ist.
1536 	Point aPt;
1537     const SwCntntNode* pCntNd = rPam.GetCntntNode();
1538 	const SwLayoutFrm *pStart = pCntNd->getLayoutFrm( pCntNd->GetDoc()->GetCurrentLayout(),
1539 														&aPt )->GetUpper();
1540     pCntNd = rPam.GetCntntNode(sal_False);
1541 	const SwLayoutFrm *pEnd = pCntNd->getLayoutFrm( pCntNd->GetDoc()->GetCurrentLayout(),
1542 													&aPt )->GetUpper();
1543     GetTblSel( pStart, pEnd, aBoxes, 0 );
1544 	return CheckMergeSel( aBoxes );
1545 }
1546 
1547 sal_uInt16 CheckMergeSel( const SwSelBoxes& rBoxes )
1548 {
1549 	sal_uInt16 eRet = TBLMERGE_NOSELECTION;
1550 	if( rBoxes.Count() )
1551 	{
1552 		eRet = TBLMERGE_OK;
1553 
1554 		_FndBox aFndBox( 0, 0 );
1555 		_FndPara aPara( rBoxes, &aFndBox );
1556 		const SwTableNode* pTblNd = aPara.rBoxes[0]->GetSttNd()->FindTableNode();
1557 		((SwTable&)pTblNd->GetTable()).GetTabLines().ForEach(
1558 					&_FndLineCopyCol, &aPara );
1559 		if( aFndBox.GetLines().Count() )
1560 		{
1561 			sal_Bool bMergeSelOk = sal_True;
1562 			_FndBox* pFndBox = &aFndBox;
1563 			_FndLine* pFndLine = 0;
1564 			while( pFndBox && 1 == pFndBox->GetLines().Count() )
1565 			{
1566 				pFndLine = pFndBox->GetLines()[0];
1567 				if( 1 == pFndLine->GetBoxes().Count() )
1568 					pFndBox = pFndLine->GetBoxes()[0];
1569 				else
1570 					pFndBox = 0;
1571 			}
1572 			if( pFndBox )
1573 				pFndBox->GetLines().ForEach( &lcl_CheckRow, &bMergeSelOk );
1574 			else if( pFndLine )
1575 				pFndLine->GetBoxes().ForEach( &lcl_CheckCol, &bMergeSelOk );
1576 			if( !bMergeSelOk )
1577 				eRet = TBLMERGE_TOOCOMPLEX;
1578 		}
1579 		else
1580 			eRet = TBLMERGE_NOSELECTION;
1581 	}
1582 	return eRet;
1583 }
1584 
1585 //Ermittelt die von einer Tabellenselektion betroffenen Tabellen und die
1586 //Union-Rechteckte der Selektionen - auch fuer aufgespaltene Tabellen.
1587 SV_IMPL_PTRARR( SwSelUnions, SwSelUnion* );
1588 
1589 SwTwips lcl_CalcWish( const SwLayoutFrm *pCell, long nWish,
1590 												const long nAct )
1591 {
1592 	const SwLayoutFrm *pTmp = pCell;
1593 	if ( !nWish )
1594 		nWish = 1;
1595 
1596 	const sal_Bool bRTL = pCell->IsRightToLeft();
1597 	SwTwips nRet = bRTL ?
1598         nAct - pCell->Frm().Width() :
1599         0;
1600 
1601 	while ( pTmp )
1602 	{
1603 		while ( pTmp->GetPrev() )
1604 		{
1605 			pTmp = (SwLayoutFrm*)pTmp->GetPrev();
1606 			long nTmp = pTmp->GetFmt()->GetFrmSize().GetWidth();
1607             nRet += ( bRTL ? ( -1 ) : 1 ) * nTmp * nAct / nWish;
1608 		}
1609 		pTmp = pTmp->GetUpper()->GetUpper();
1610 		if ( pTmp && !pTmp->IsCellFrm() )
1611 			pTmp = 0;
1612 	}
1613 	return nRet;
1614 }
1615 
1616 void lcl_FindStartEndRow( const SwLayoutFrm *&rpStart,
1617 							 const SwLayoutFrm *&rpEnd,
1618 							 const int bChkProtected )
1619 {
1620 	//Start an den Anfang seiner Zeile setzen.
1621 	//End an das Ende seiner Zeile setzen.
1622 	rpStart = (SwLayoutFrm*)rpStart->GetUpper()->Lower();
1623 	while ( rpEnd->GetNext() )
1624 		rpEnd = (SwLayoutFrm*)rpEnd->GetNext();
1625 
1626 	SvPtrarr aSttArr( 8, 8 ), aEndArr( 8, 8 );
1627 	const SwLayoutFrm *pTmp;
1628 	for( pTmp = rpStart; (FRM_CELL|FRM_ROW) & pTmp->GetType();
1629 				pTmp = pTmp->GetUpper() )
1630 	{
1631 		void* p = (void*)pTmp;
1632 		aSttArr.Insert( p, 0 );
1633 	}
1634 	for( pTmp = rpEnd; (FRM_CELL|FRM_ROW) & pTmp->GetType();
1635 				pTmp = pTmp->GetUpper() )
1636 	{
1637 		void* p = (void*)pTmp;
1638 		aEndArr.Insert( p, 0 );
1639 	}
1640 
1641 	for( sal_uInt16 n = 0; n < aEndArr.Count() && n < aSttArr.Count(); ++n )
1642 		if( aSttArr[ n ] != aEndArr[ n ] )
1643 		{
1644 			// first unequal line or box - all odds are
1645 			if( n & 1 )			        // 1, 3, 5, ... are boxes
1646 			{
1647 				rpStart = (SwLayoutFrm*)aSttArr[ n ];
1648 				rpEnd = (SwLayoutFrm*)aEndArr[ n ];
1649 			}
1650 			else								// 0, 2, 4, ... are lines
1651 			{
1652 				// check if start & end line are the first & last Line of the
1653 				// box. If not return these cells.
1654 				// Else the hole line with all Boxes has to be deleted.
1655 				rpStart = (SwLayoutFrm*)aSttArr[ n+1 ];
1656 				rpEnd = (SwLayoutFrm*)aEndArr[ n+1 ];
1657 				if( n )
1658 				{
1659 					const SwCellFrm* pCellFrm = (SwCellFrm*)aSttArr[ n-1 ];
1660 					const SwTableLines& rLns = pCellFrm->
1661 												GetTabBox()->GetTabLines();
1662 					if( rLns[ 0 ] == ((SwRowFrm*)aSttArr[ n ])->GetTabLine() &&
1663 						rLns[ rLns.Count() - 1 ] ==
1664 									((SwRowFrm*)aEndArr[ n ])->GetTabLine() )
1665 					{
1666 						rpStart = rpEnd = pCellFrm;
1667 						while ( rpStart->GetPrev() )
1668 							rpStart = (SwLayoutFrm*)rpStart->GetPrev();
1669 						while ( rpEnd->GetNext() )
1670 							rpEnd = (SwLayoutFrm*)rpEnd->GetNext();
1671 					}
1672 				}
1673 			}
1674 			break;
1675 		}
1676 
1677 	if( !bChkProtected )	// geschuetzte Zellen beachten ?
1678 		return;
1679 
1680 
1681 	//Anfang und Ende duerfen nicht auf geschuetzten Zellen liegen.
1682 	while ( rpStart->GetFmt()->GetProtect().IsCntntProtected() )
1683 		rpStart = (SwLayoutFrm*)rpStart->GetNext();
1684 	while ( rpEnd->GetFmt()->GetProtect().IsCntntProtected() )
1685 		rpEnd = (SwLayoutFrm*)rpEnd->GetPrev();
1686 }
1687 
1688 
1689 void lcl_FindStartEndCol( const SwLayoutFrm *&rpStart,
1690 							 const SwLayoutFrm *&rpEnd,
1691 							 const int bChkProtected )
1692 {
1693 	//Start und End senkrecht bis an den Rand der Tabelle denken; es muss
1694 	//die Gesamttabelle betrachtet werden, also inklusive Masters und
1695 	//Follows.
1696 	//Fuer den Start brauchen wir den Mutter-TabellenFrm.
1697     if( !rpStart )
1698         return;
1699 	const SwTabFrm *pOrg = rpStart->FindTabFrm();
1700 	const SwTabFrm *pTab = pOrg;
1701 
1702 	SWRECTFN( pTab )
1703 
1704     sal_Bool bRTL = pTab->IsRightToLeft();
1705     const long nTmpWish = pOrg->GetFmt()->GetFrmSize().GetWidth();
1706     const long nWish = ( nTmpWish > 0 ) ? nTmpWish : 1;
1707 
1708     while ( pTab->IsFollow() )
1709 	{
1710 		const SwFrm *pTmp = pTab->FindPrev();
1711 		ASSERT( pTmp->IsTabFrm(), "Vorgaenger vom Follow nicht der Master." );
1712 		pTab = (const SwTabFrm*)pTmp;
1713 	}
1714 
1715     SwTwips nSX  = 0;
1716     SwTwips nSX2 = 0;
1717 
1718     if ( pTab->GetTable()->IsNewModel() )
1719     {
1720         nSX  = (rpStart->Frm().*fnRect->fnGetLeft )();
1721         nSX2 = (rpStart->Frm().*fnRect->fnGetRight)();
1722     }
1723     else
1724     {
1725         const SwTwips nPrtWidth = (pTab->Prt().*fnRect->fnGetWidth)();
1726         nSX = ::lcl_CalcWish( rpStart, nWish, nPrtWidth ) + (pTab->*fnRect->fnGetPrtLeft)();
1727         nSX2 = nSX + (rpStart->GetFmt()->GetFrmSize().GetWidth() * nPrtWidth / nWish);
1728     }
1729 
1730 	const SwLayoutFrm *pTmp = pTab->FirstCell();
1731 
1732 	while ( pTmp &&
1733 			(!pTmp->IsCellFrm() ||
1734              ( ( ! bRTL && (pTmp->Frm().*fnRect->fnGetLeft)() < nSX &&
1735                            (pTmp->Frm().*fnRect->fnGetRight)()< nSX2 ) ||
1736                (   bRTL && (pTmp->Frm().*fnRect->fnGetLeft)() > nSX &&
1737                            (pTmp->Frm().*fnRect->fnGetRight)()> nSX2 ) ) ) )
1738         pTmp = pTmp->GetNextLayoutLeaf();
1739 
1740 	if ( pTmp )
1741 		rpStart = pTmp;
1742 
1743 	pTab = pOrg;
1744 
1745     const SwTabFrm* pLastValidTab = pTab;
1746 	while ( pTab->GetFollow() )
1747     {
1748         //
1749         // Check if pTab->GetFollow() is a valid follow table:
1750         // Only follow tables with at least on non-FollowFlowLine
1751         // should be considered.
1752         //
1753         if ( pTab->HasFollowFlowLine() )
1754         {
1755             pTab = pTab->GetFollow();
1756             const SwFrm* pTmpRow = pTab->GetFirstNonHeadlineRow();
1757             if ( pTmpRow && pTmpRow->GetNext() )
1758     		    pLastValidTab = pTab;
1759         }
1760         else
1761             pLastValidTab = pTab = pTab->GetFollow();
1762     }
1763     pTab = pLastValidTab;
1764 
1765     SwTwips nEX = 0;
1766 
1767     if ( pTab->GetTable()->IsNewModel() )
1768     {
1769         nEX = (rpEnd->Frm().*fnRect->fnGetLeft )();
1770     }
1771     else
1772     {
1773         const SwTwips nPrtWidth = (pTab->Prt().*fnRect->fnGetWidth)();
1774         nEX = ::lcl_CalcWish( rpEnd, nWish, nPrtWidth ) + (pTab->*fnRect->fnGetPrtLeft)();
1775     }
1776 
1777     const SwCntntFrm* pLastCntnt = pTab->FindLastCntnt();
1778     rpEnd = pLastCntnt ? pLastCntnt->GetUpper() : 0;
1779     // --> FME 2006-07-17 #134385# Made code robust. If pTab does not have a lower,
1780     // we would crash here.
1781     if ( !pLastCntnt ) return;
1782     // <--
1783 
1784 	while( !rpEnd->IsCellFrm() )
1785 		rpEnd = rpEnd->GetUpper();
1786 
1787     while ( (   bRTL && (rpEnd->Frm().*fnRect->fnGetLeft)() < nEX ) ||
1788             ( ! bRTL && (rpEnd->Frm().*fnRect->fnGetLeft)() > nEX ) )
1789     {
1790         const SwLayoutFrm* pTmpLeaf = rpEnd->GetPrevLayoutLeaf();
1791         if( !pTmpLeaf || !pTab->IsAnLower( pTmpLeaf ) )
1792             break;
1793         rpEnd = pTmpLeaf;
1794     }
1795 
1796 	if( !bChkProtected )	// geschuetzte Zellen beachten ?
1797 		return;
1798 
1799 	//Anfang und Ende duerfen nicht auf geschuetzten Zellen liegen.
1800 	//Also muss ggf. nocheinmal rueckwaerts gesucht werden.
1801 	while ( rpStart->GetFmt()->GetProtect().IsCntntProtected() )
1802 	{
1803         const SwLayoutFrm *pTmpLeaf = rpStart;
1804         pTmpLeaf = pTmpLeaf->GetNextLayoutLeaf();
1805         while ( pTmpLeaf && (pTmpLeaf->Frm().*fnRect->fnGetLeft)() > nEX )//erstmal die Zeile ueberspr.
1806             pTmpLeaf = pTmpLeaf->GetNextLayoutLeaf();
1807         while ( pTmpLeaf && (pTmpLeaf->Frm().*fnRect->fnGetLeft)() < nSX &&
1808                             (pTmpLeaf->Frm().*fnRect->fnGetRight)()< nSX2 )
1809             pTmpLeaf = pTmpLeaf->GetNextLayoutLeaf();
1810         const SwTabFrm *pTmpTab = rpStart->FindTabFrm();
1811         if ( !pTmpTab->IsAnLower( pTmpLeaf ) )
1812 		{
1813             pTmpTab = pTmpTab->GetFollow();
1814             rpStart = pTmpTab->FirstCell();
1815 			while ( (rpStart->Frm().*fnRect->fnGetLeft)() < nSX &&
1816 					(rpStart->Frm().*fnRect->fnGetRight)()< nSX2 )
1817 				rpStart = rpStart->GetNextLayoutLeaf();
1818 		}
1819 		else
1820             rpStart = pTmpLeaf;
1821 	}
1822 	while ( rpEnd->GetFmt()->GetProtect().IsCntntProtected() )
1823 	{
1824         const SwLayoutFrm *pTmpLeaf = rpEnd;
1825         pTmpLeaf = pTmpLeaf->GetPrevLayoutLeaf();
1826         while ( pTmpLeaf && (pTmpLeaf->Frm().*fnRect->fnGetLeft)() < nEX )//erstmal die Zeile ueberspr.
1827             pTmpLeaf = pTmpLeaf->GetPrevLayoutLeaf();
1828         while ( pTmpLeaf && (pTmpLeaf->Frm().*fnRect->fnGetLeft)() > nEX )
1829             pTmpLeaf = pTmpLeaf->GetPrevLayoutLeaf();
1830         const SwTabFrm *pTmpTab = rpEnd->FindTabFrm();
1831         if ( !pTmpLeaf || !pTmpTab->IsAnLower( pTmpLeaf ) )
1832 		{
1833             pTmpTab = (const SwTabFrm*)pTmpTab->FindPrev();
1834             ASSERT( pTmpTab->IsTabFrm(), "Vorgaenger vom Follow nicht der Master.");
1835             rpEnd = pTmpTab->FindLastCntnt()->GetUpper();
1836 			while( !rpEnd->IsCellFrm() )
1837 				rpEnd = rpEnd->GetUpper();
1838 			while ( (rpEnd->Frm().*fnRect->fnGetLeft)() > nEX )
1839 				rpEnd = rpEnd->GetPrevLayoutLeaf();
1840 		}
1841 		else
1842             rpEnd = pTmpLeaf;
1843 	}
1844 }
1845 
1846 
1847 void MakeSelUnions( SwSelUnions& rUnions, const SwLayoutFrm *pStart,
1848 					const SwLayoutFrm *pEnd, const SwTblSearchType eSearchType )
1849 {
1850     while ( pStart && !pStart->IsCellFrm() )
1851 		pStart = pStart->GetUpper();
1852     while ( pEnd && !pEnd->IsCellFrm() )
1853 		pEnd = pEnd->GetUpper();
1854 
1855     // #112697# Robust:
1856     if ( !pStart || !pEnd )
1857     {
1858         ASSERT( false, "MakeSelUnions with pStart or pEnd not in CellFrm" )
1859         return;
1860     }
1861 
1862 	const SwTabFrm *pTable = pStart->FindTabFrm();
1863 	const SwTabFrm *pEndTable = pEnd->FindTabFrm();
1864     if( !pTable || !pEndTable )
1865         return;
1866 	sal_Bool bExchange = sal_False;
1867 
1868 	if ( pTable != pEndTable )
1869 	{
1870 		if ( !pTable->IsAnFollow( pEndTable ) )
1871 		{
1872 			ASSERT( pEndTable->IsAnFollow( pTable ), "Tabkette verknotet." );
1873 			bExchange = sal_True;
1874 		}
1875 	}
1876     else
1877     {
1878         SWRECTFN( pTable )
1879         long nSttTop = (pStart->Frm().*fnRect->fnGetTop)();
1880         long nEndTop = (pEnd->Frm().*fnRect->fnGetTop)();
1881         if( nSttTop == nEndTop )
1882         {
1883             if( (pStart->Frm().*fnRect->fnGetLeft)() >
1884                 (pEnd->Frm().*fnRect->fnGetLeft)() )
1885                 bExchange = sal_True;
1886         }
1887         else if( bVert == ( nSttTop < nEndTop ) )
1888             bExchange = sal_True;
1889     }
1890 	if ( bExchange )
1891 	{
1892 		const SwLayoutFrm *pTmp = pStart;
1893 		pStart = pEnd;
1894 		pEnd = pTmp;
1895 		//pTable und pEndTable nicht umsortieren, werden unten neu gesetzt.
1896 		//MA: 28. Dec. 93 Bug: 5190
1897 	}
1898 
1899 	//Start und End sind jetzt huebsch sortiert, jetzt muessen sie falls
1900 	//erwuenscht noch versetzt werden.
1901 	if( nsSwTblSearchType::TBLSEARCH_ROW == ((~nsSwTblSearchType::TBLSEARCH_PROTECT ) & eSearchType ) )
1902 		::lcl_FindStartEndRow( pStart, pEnd, nsSwTblSearchType::TBLSEARCH_PROTECT & eSearchType );
1903 	else if( nsSwTblSearchType::TBLSEARCH_COL == ((~nsSwTblSearchType::TBLSEARCH_PROTECT ) & eSearchType ) )
1904 		::lcl_FindStartEndCol( pStart, pEnd, nsSwTblSearchType::TBLSEARCH_PROTECT & eSearchType );
1905 
1906     // --> FME 2006-07-17 #134385# Made code robust.
1907     if ( !pEnd ) return;
1908     // <--
1909 
1910 	//neu besorgen, da sie jetzt verschoben sind. MA: 28. Dec. 93 Bug 5190
1911 	pTable = pStart->FindTabFrm();
1912 	pEndTable = pEnd->FindTabFrm();
1913 
1914     const long nStSz = pStart->GetFmt()->GetFrmSize().GetWidth();
1915 	const long nEdSz = pEnd->GetFmt()->GetFrmSize().GetWidth();
1916 	const long nWish = Max( 1L, pTable->GetFmt()->GetFrmSize().GetWidth() );
1917 	while ( pTable )
1918 	{
1919         SWRECTFN( pTable )
1920         const long nOfst = (pTable->*fnRect->fnGetPrtLeft)();
1921         const long nPrtWidth = (pTable->Prt().*fnRect->fnGetWidth)();
1922         long nSt1 = ::lcl_CalcWish( pStart, nWish, nPrtWidth ) + nOfst;
1923         long nEd1 = ::lcl_CalcWish( pEnd,   nWish, nPrtWidth ) + nOfst;
1924 
1925         if ( nSt1 <= nEd1 )
1926             nEd1 += (long)((nEdSz * nPrtWidth) / nWish) - 1;
1927 		else
1928             nSt1 += (long)((nStSz * nPrtWidth) / nWish) - 1;
1929 
1930         long nSt2;
1931         long nEd2;
1932         if( pTable->IsAnLower( pStart ) )
1933             nSt2 = (pStart->Frm().*fnRect->fnGetTop)();
1934         else
1935             nSt2 = (pTable->Frm().*fnRect->fnGetTop)();
1936         if( pTable->IsAnLower( pEnd ) )
1937             nEd2 = (pEnd->Frm().*fnRect->fnGetBottom)();
1938         else
1939             nEd2 = (pTable->Frm().*fnRect->fnGetBottom)();
1940         Point aSt, aEd;
1941         if( nSt1 > nEd1 )
1942         {
1943             long nTmp = nSt1;
1944             nSt1 = nEd1;
1945             nEd1 = nTmp;
1946         }
1947         if( nSt2 > nEd2 )
1948         {
1949             long nTmp = nSt2;
1950             nSt2 = nEd2;
1951             nEd2 = nTmp;
1952         }
1953         if( bVert )
1954         {
1955             aSt = Point( nSt2, nSt1 );
1956             aEd = Point( nEd2, nEd1 );
1957         }
1958         else
1959         {
1960             aSt = Point( nSt1, nSt2 );
1961             aEd = Point( nEd1, nEd2 );
1962         }
1963 
1964         const Point aDiff( aEd - aSt );
1965 		SwRect aUnion( aSt, Size( aDiff.X(), aDiff.Y() ) );
1966 		aUnion.Justify();
1967 
1968 		// fuers
1969 		if( !(nsSwTblSearchType::TBLSEARCH_NO_UNION_CORRECT & eSearchType ))
1970 		{
1971 			//Leider ist die Union jetzt mit Rundungsfehlern behaftet und dadurch
1972 			//wuerden beim Split/Merge fehlertraechtige Umstaende entstehen.
1973 			//Um dies zu vermeiden werden jetzt fuer die Table die erste und
1974 			//letzte Zelle innerhalb der Union ermittelt und aus genau deren
1975 			//Werten wird die Union neu gebildet.
1976             const SwLayoutFrm* pRow = pTable->IsFollow() ?
1977                                       pTable->GetFirstNonHeadlineRow() :
1978                                       (const SwLayoutFrm*)pTable->Lower();
1979 
1980             while ( pRow && !pRow->Frm().IsOver( aUnion ) )
1981 				pRow = (SwLayoutFrm*)pRow->GetNext();
1982 
1983             // --> FME 2004-07-26 #i31976#
1984             // A follow flow row may contain emtpy cells. These are not
1985             // considered by FirstCell(). Therefore we have to find
1986             // the first cell manually:
1987             const SwFrm* pTmpCell = 0;
1988             if ( pTable->IsFollow() && pRow && pRow->IsInFollowFlowRow() )
1989             {
1990                 const SwFrm* pTmpRow = pRow;
1991                 while ( pTmpRow && pTmpRow->IsRowFrm() )
1992                 {
1993                     pTmpCell = static_cast<const SwRowFrm*>(pTmpRow)->Lower();
1994                     pTmpRow  = static_cast<const SwCellFrm*>(pTmpCell)->Lower();
1995                 }
1996                 ASSERT( !pTmpCell || pTmpCell->IsCellFrm(), "Lower of rowframe != cellframe?!" )
1997             }
1998             // <--
1999 
2000             const SwLayoutFrm* pFirst = pTmpCell ?
2001                                         static_cast<const SwLayoutFrm*>(pTmpCell) :
2002                                         pRow ?
2003                                         pRow->FirstCell() :
2004                                         0;
2005 
2006 			while ( pFirst && !::IsFrmInTblSel( aUnion, pFirst ) )
2007 			{
2008 				if ( pFirst->GetNext() )
2009 				{
2010 					pFirst = (const SwLayoutFrm*)pFirst->GetNext();
2011 					if ( pFirst->Lower() && pFirst->Lower()->IsRowFrm() )
2012 						pFirst = pFirst->FirstCell();
2013 				}
2014 				else
2015 					pFirst = ::lcl_FindNextCellFrm( pFirst );
2016 			}
2017             const SwLayoutFrm* pLast = 0;
2018             const SwFrm* pLastCntnt = pTable->FindLastCntnt();
2019             if ( pLastCntnt )
2020                 pLast = ::lcl_FindCellFrm( pLastCntnt->GetUpper() );
2021 
2022 			while ( pLast && !::IsFrmInTblSel( aUnion, pLast ) )
2023 				pLast = ::lcl_FindCellFrm( pLast->GetPrevLayoutLeaf() );
2024 
2025 			if ( pFirst && pLast ) //Robust
2026             {
2027                 aUnion = pFirst->Frm();
2028                 aUnion.Union( pLast->Frm() );
2029             }
2030             else
2031 				aUnion.Width( 0 );
2032 		}
2033 
2034 		if( (aUnion.*fnRect->fnGetWidth)() )
2035 		{
2036 			SwSelUnion *pTmp = new SwSelUnion( aUnion, (SwTabFrm*)pTable );
2037 			rUnions.C40_INSERT( SwSelUnion, pTmp, rUnions.Count() );
2038 		}
2039 
2040 		pTable = pTable->GetFollow();
2041 		if ( pTable != pEndTable && pEndTable->IsAnFollow( pTable ) )
2042 			pTable = 0;
2043 	}
2044 }
2045 
2046 sal_Bool CheckSplitCells( const SwCrsrShell& rShell, sal_uInt16 nDiv,
2047 						const SwTblSearchType eSearchType )
2048 {
2049 	if( !rShell.IsTableMode() )
2050 		rShell.GetCrsr();
2051 
2052     return CheckSplitCells( *rShell.getShellCrsr(false), nDiv, eSearchType );
2053 }
2054 
2055 sal_Bool CheckSplitCells( const SwCursor& rCrsr, sal_uInt16 nDiv,
2056 						const SwTblSearchType eSearchType )
2057 {
2058 	if( 1 >= nDiv )
2059 		return sal_False;
2060 
2061 	sal_uInt16 nMinValue = nDiv * MINLAY;
2062 
2063 	//Start- und Endzelle besorgen und den naechsten fragen.
2064 	Point aPtPos, aMkPos;
2065     const SwShellCrsr* pShCrsr = dynamic_cast<const SwShellCrsr*>(&rCrsr);
2066 	if( pShCrsr )
2067 	{
2068 		aPtPos = pShCrsr->GetPtPos();
2069 		aMkPos = pShCrsr->GetMkPos();
2070 	}
2071 
2072     const SwCntntNode* pCntNd = rCrsr.GetCntntNode();
2073 	const SwLayoutFrm *pStart = pCntNd->getLayoutFrm( pCntNd->GetDoc()->GetCurrentLayout(),
2074 														&aPtPos )->GetUpper();
2075     pCntNd = rCrsr.GetCntntNode(sal_False);
2076 	const SwLayoutFrm *pEnd = pCntNd->getLayoutFrm( pCntNd->GetDoc()->GetCurrentLayout(),
2077 								&aMkPos )->GetUpper();
2078 
2079     SWRECTFN( pStart->GetUpper() )
2080 
2081 	//Zuerst lassen wir uns die Tabellen und die Rechtecke heraussuchen.
2082 	SwSelUnions aUnions;
2083 
2084 	::MakeSelUnions( aUnions, pStart, pEnd, eSearchType );
2085 
2086     //Jetzt zu jedem Eintrag die Boxen herausfischen und uebertragen.
2087 	for ( sal_uInt16 i = 0; i < aUnions.Count(); ++i )
2088 	{
2089 		SwSelUnion *pUnion = aUnions[i];
2090 		const SwTabFrm *pTable = pUnion->GetTable();
2091 
2092         // Skip any repeated headlines in the follow:
2093         const SwLayoutFrm* pRow = pTable->IsFollow() ?
2094                                   pTable->GetFirstNonHeadlineRow() :
2095                                   (const SwLayoutFrm*)pTable->Lower();
2096 
2097 		while ( pRow )
2098 		{
2099 			if ( pRow->Frm().IsOver( pUnion->GetUnion() ) )
2100 			{
2101 				const SwLayoutFrm *pCell = pRow->FirstCell();
2102 
2103 				while ( pCell && pRow->IsAnLower( pCell ) )
2104 				{
2105 					ASSERT( pCell->IsCellFrm(), "Frame ohne Celle" );
2106 					if( ::IsFrmInTblSel( pUnion->GetUnion(), pCell ) )
2107 					{
2108                         if( (pCell->Frm().*fnRect->fnGetWidth)() < nMinValue )
2109 							return sal_False;
2110 					}
2111 
2112 					if ( pCell->GetNext() )
2113 					{
2114 						pCell = (const SwLayoutFrm*)pCell->GetNext();
2115 						if ( pCell->Lower() && pCell->Lower()->IsRowFrm() )
2116 							pCell = pCell->FirstCell();
2117 					}
2118 					else
2119 						pCell = ::lcl_FindNextCellFrm( pCell );
2120 				}
2121 			}
2122 			pRow = (const SwLayoutFrm*)pRow->GetNext();
2123 		}
2124 	}
2125 	return sal_True;
2126 }
2127 
2128 // -------------------------------------------------------------------
2129 // Diese Klassen kopieren die aktuelle Tabellen-Selektion (rBoxes)
2130 // unter Beibehaltung der Tabellen-Struktur in eine eigene Struktur
2131 // neu: SS zum gezielten Loeschen/Retaurieren des Layouts.
2132 
2133 void lcl_InsertRow( SwTableLine &rLine, SwLayoutFrm *pUpper, SwFrm *pSibling )
2134 {
2135 	SwRowFrm *pRow = new SwRowFrm( rLine, pUpper );
2136 	if ( pUpper->IsTabFrm() && ((SwTabFrm*)pUpper)->IsFollow() )
2137 	{
2138         SwTabFrm* pTabFrm = (SwTabFrm*)pUpper;
2139         pTabFrm->FindMaster()->InvalidatePos(); //kann die Zeile vielleicht aufnehmen
2140 
2141         if ( pSibling && pTabFrm->IsInHeadline( *pSibling ) )
2142 		{
2143             // Skip any repeated headlines in the follow:
2144             pSibling = pTabFrm->GetFirstNonHeadlineRow();
2145 		}
2146 	}
2147 	pRow->Paste( pUpper, pSibling );
2148 	pRow->RegistFlys();
2149 }
2150 
2151 
2152 sal_Bool _FndBoxCopyCol( const SwTableBox*& rpBox, void* pPara )
2153 {
2154 	_FndPara* pFndPara = (_FndPara*)pPara;
2155 	_FndBox* pFndBox = new _FndBox( (SwTableBox*)rpBox, pFndPara->pFndLine );
2156 	if( rpBox->GetTabLines().Count() )
2157 	{
2158 		_FndPara aPara( *pFndPara, pFndBox );
2159 		pFndBox->GetBox()->GetTabLines().ForEach( &_FndLineCopyCol, &aPara );
2160 		if( !pFndBox->GetLines().Count() )
2161 		{
2162 			delete pFndBox;
2163 			return sal_True;
2164 		}
2165 	}
2166 	else
2167 	{
2168 		SwTableBoxPtr pSrch = (SwTableBoxPtr)rpBox;
2169 		sal_uInt16 nFndPos;
2170 		if( !pFndPara->rBoxes.Seek_Entry( pSrch, &nFndPos ))
2171 		{
2172 			delete pFndBox;
2173 			return sal_True;
2174 		}
2175 	}
2176 	pFndPara->pFndLine->GetBoxes().C40_INSERT( _FndBox, pFndBox,
2177 					pFndPara->pFndLine->GetBoxes().Count() );
2178 	return sal_True;
2179 }
2180 
2181 sal_Bool _FndLineCopyCol( const SwTableLine*& rpLine, void* pPara )
2182 {
2183 	_FndPara* pFndPara = (_FndPara*)pPara;
2184 	_FndLine* pFndLine = new _FndLine( (SwTableLine*)rpLine, pFndPara->pFndBox );
2185 	_FndPara aPara( *pFndPara, pFndLine );
2186 	pFndLine->GetLine()->GetTabBoxes().ForEach( &_FndBoxCopyCol, &aPara );
2187 	if( pFndLine->GetBoxes().Count() )
2188 	{
2189 		pFndPara->pFndBox->GetLines().C40_INSERT( _FndLine, pFndLine,
2190 				pFndPara->pFndBox->GetLines().Count() );
2191 	}
2192 	else
2193 		delete pFndLine;
2194 	return sal_True;
2195 }
2196 
2197 void _FndBox::SetTableLines( const SwSelBoxes &rBoxes, const SwTable &rTable )
2198 {
2199 	//Pointer auf die Lines vor und hinter den zu verarbeitenden Bereich
2200 	//setzen. Wenn die erste/letzte Zeile in den Bereich eingeschlossen
2201 	//sind, so bleiben die Pointer eben einfach 0.
2202 	//Gesucht werden zunachst die Positionen der ersten/letzten betroffenen
2203 	//Line im Array der SwTable. Damit die 0 fuer 'keine Line' verwand werden
2204 	//kann werden die Positionen um 1 nach oben versetzt!
2205 
2206 	sal_uInt16 nStPos = USHRT_MAX;
2207 	sal_uInt16 nEndPos= 0;
2208 
2209 	for ( sal_uInt16 i = 0; i < rBoxes.Count(); ++i )
2210 	{
2211 		SwTableLine *pLine = rBoxes[i]->GetUpper();
2212 		while ( pLine->GetUpper() )
2213 			pLine = pLine->GetUpper()->GetUpper();
2214 		const sal_uInt16 nPos = rTable.GetTabLines().GetPos(
2215 					(const SwTableLine*&)pLine ) + 1;
2216 
2217 		ASSERT( nPos != USHRT_MAX, "TableLine not found." );
2218 
2219 		if( nStPos > nPos )
2220 			nStPos = nPos;
2221 
2222 		if( nEndPos < nPos )
2223 			nEndPos = nPos;
2224 	}
2225 	if ( nStPos > 1 )
2226 		pLineBefore = rTable.GetTabLines()[nStPos - 2];
2227 	if ( nEndPos < rTable.GetTabLines().Count() )
2228 		pLineBehind = rTable.GetTabLines()[nEndPos];
2229 }
2230 
2231 void _FndBox::SetTableLines( const SwTable &rTable )
2232 {
2233 	// Pointer auf die Lines vor und hinter den zu verarbeitenden Bereich
2234 	// setzen. Wenn die erste/letzte Zeile in den Bereich eingeschlossen
2235 	// sind, so bleiben die Pointer eben einfach 0.
2236 	// Die Positionen der ersten/letzten betroffenen Line im Array der
2237 	// SwTable steht in der FndBox. Damit die 0 fuer 'keine Line' verwand
2238 	// werdenkann werden die Positionen um 1 nach oben versetzt!
2239 
2240 	if( !GetLines().Count() )
2241 		return;
2242 
2243 	SwTableLine* pTmpLine = GetLines()[0]->GetLine();
2244 	sal_uInt16 nPos = rTable.GetTabLines().C40_GETPOS( SwTableLine, pTmpLine );
2245 	ASSERT( USHRT_MAX != nPos, "Line steht nicht in der Tabelle" );
2246 	if( nPos )
2247 		pLineBefore = rTable.GetTabLines()[ nPos - 1 ];
2248 
2249 	pTmpLine = GetLines()[GetLines().Count()-1]->GetLine();
2250 	nPos = rTable.GetTabLines().C40_GETPOS( SwTableLine, pTmpLine );
2251 	ASSERT( USHRT_MAX != nPos, "Line steht nicht in der Tabelle" );
2252 	if( ++nPos < rTable.GetTabLines().Count() )
2253 		pLineBehind = rTable.GetTabLines()[nPos];
2254 }
2255 
2256 inline void UnsetFollow( SwFlowFrm *pTab )
2257 {
2258 	pTab->bIsFollow = sal_False;
2259 }
2260 
2261 void _FndBox::DelFrms( SwTable &rTable )
2262 {
2263 	//Alle Lines zwischen pLineBefore und pLineBehind muessen aus dem
2264 	//Layout ausgeschnitten und geloescht werden.
2265 	//Entstehen dabei leere Follows so muessen diese vernichtet werden.
2266 	//Wird ein Master vernichtet, so muss der Follow Master werden.
2267 	//Ein TabFrm muss immer uebrigbleiben.
2268 
2269     sal_uInt16 nStPos = 0;
2270     sal_uInt16 nEndPos= rTable.GetTabLines().Count() - 1;
2271     if( rTable.IsNewModel() && pLineBefore )
2272         rTable.CheckRowSpan( pLineBefore, true );
2273 	if ( pLineBefore )
2274 	{
2275 		nStPos = rTable.GetTabLines().GetPos(
2276 						(const SwTableLine*&)pLineBefore );
2277 		ASSERT( nStPos != USHRT_MAX, "Fuchs Du hast die Line gestohlen!" );
2278 		++nStPos;
2279 	}
2280     if( rTable.IsNewModel() && pLineBehind )
2281         rTable.CheckRowSpan( pLineBehind, false );
2282 	if ( pLineBehind )
2283 	{
2284 		nEndPos = rTable.GetTabLines().GetPos(
2285 						(const SwTableLine*&)pLineBehind );
2286 		ASSERT( nEndPos != USHRT_MAX, "Fuchs Du hast die Line gestohlen!" );
2287 		--nEndPos;
2288 	}
2289 
2290     for ( sal_uInt16 i = nStPos; i <= nEndPos; ++i)
2291 	{
2292 		SwFrmFmt *pFmt = rTable.GetTabLines()[i]->GetFrmFmt();
2293 		SwIterator<SwRowFrm,SwFmt> aIter( *pFmt );
2294 		for ( SwRowFrm* pFrm = aIter.First(); pFrm; pFrm = aIter.Next() )
2295 		{
2296 				if ( pFrm->GetTabLine() == rTable.GetTabLines()[i] )
2297                 {
2298 					sal_Bool bDel = sal_True;
2299 					SwTabFrm *pUp = !pFrm->GetPrev() && !pFrm->GetNext() ?
2300 											(SwTabFrm*)pFrm->GetUpper() : 0;
2301                     if ( !pUp )
2302                     {
2303                         const sal_uInt16 nRepeat =
2304                                 ((SwTabFrm*)pFrm->GetUpper())->GetTable()->GetRowsToRepeat();
2305                         if ( nRepeat > 0 &&
2306                              ((SwTabFrm*)pFrm->GetUpper())->IsFollow() )
2307                         {
2308                             if ( !pFrm->GetNext() )
2309                             {
2310                                 SwRowFrm* pFirstNonHeadline =
2311                                     ((SwTabFrm*)pFrm->GetUpper())->GetFirstNonHeadlineRow();
2312                                 if ( pFirstNonHeadline == pFrm )
2313                                 {
2314                                     pUp = (SwTabFrm*)pFrm->GetUpper();
2315                                 }
2316                             }
2317                         }
2318                     }
2319                     if ( pUp )
2320 					{
2321 						SwTabFrm *pFollow = pUp->GetFollow();
2322 						SwTabFrm *pPrev   = pUp->IsFollow() ? pUp : 0;
2323 						if ( pPrev )
2324 						{
2325 							SwFrm *pTmp = pPrev->FindPrev();
2326 							ASSERT( pTmp->IsTabFrm(),
2327 									"Vorgaenger vom Follow kein Master.");
2328 							pPrev = (SwTabFrm*)pTmp;
2329 						}
2330 						if ( pPrev )
2331                         {
2332 							pPrev->SetFollow( pFollow );
2333                             // --> FME 2006-01-31 #i60340# Do not transfer the
2334                             // flag from pUp to pPrev. pUp may still have the
2335                             // flag set although there is not more follow flow
2336                             // line associated with pUp.
2337                             pPrev->SetFollowFlowLine( sal_False );
2338                             // <--
2339                         }
2340 						else if ( pFollow )
2341 							::UnsetFollow( pFollow );
2342 
2343 						//Ein TabellenFrm muss immer stehenbleiben!
2344 						if ( pPrev || pFollow )
2345 						{
2346                             // OD 26.08.2003 #i18103# - if table is in a section,
2347                             // lock the section, to avoid its delete.
2348                             {
2349                                 SwSectionFrm* pSctFrm = pUp->FindSctFrm();
2350                                 bool bOldSectLock = false;
2351                                 if ( pSctFrm )
2352                                 {
2353                                     bOldSectLock = pSctFrm->IsColLocked();
2354                                     pSctFrm->ColLock();
2355                                 }
2356                                 pUp->Cut();
2357                                 if ( pSctFrm && !bOldSectLock )
2358                                 {
2359                                     pSctFrm->ColUnlock();
2360                                 }
2361                             }
2362 							delete pUp;
2363 							bDel = sal_False;//Die Row wird mit in den Abgrund
2364 										 //gerissen.
2365 						}
2366 					}
2367 					if ( bDel )
2368 					{
2369                         SwFrm* pTabFrm = pFrm->GetUpper();
2370                         if ( pTabFrm->IsTabFrm() &&
2371                             !pFrm->GetNext() &&
2372                              ((SwTabFrm*)pTabFrm)->GetFollow() )
2373                         {
2374                             // We do not delete the follow flow line,
2375                             // this will be done automatically in the
2376                             // next turn.
2377                             ((SwTabFrm*)pTabFrm)->SetFollowFlowLine( sal_False );
2378                         }
2379 
2380                         pFrm->Cut();
2381 						delete pFrm;
2382 					}
2383 				}
2384 		}
2385 	}
2386 }
2387 
2388 sal_Bool lcl_IsLineOfTblFrm( const SwTabFrm& rTable, const SwFrm& rChk )
2389 {
2390 	const SwTabFrm* pTblFrm = rChk.FindTabFrm();
2391     if( pTblFrm->IsFollow() )
2392         pTblFrm = pTblFrm->FindMaster( true );
2393     return &rTable == pTblFrm;
2394 }
2395 
2396 /*
2397  * lcl_UpdateRepeatedHeadlines
2398  */
2399 void lcl_UpdateRepeatedHeadlines( SwTabFrm& rTabFrm, bool bCalcLowers )
2400 {
2401     ASSERT( rTabFrm.IsFollow(), "lcl_UpdateRepeatedHeadlines called for non-follow tab" )
2402 
2403     // Delete remaining headlines:
2404     SwRowFrm* pLower = 0;
2405     while ( 0 != ( pLower = (SwRowFrm*)rTabFrm.Lower() ) && pLower->IsRepeatedHeadline() )
2406     {
2407         pLower->Cut();
2408         delete pLower;
2409     }
2410 
2411     // Insert fresh set of headlines:
2412     pLower = (SwRowFrm*)rTabFrm.Lower();
2413     SwTable& rTable = *rTabFrm.GetTable();
2414     const sal_uInt16 nRepeat = rTable.GetRowsToRepeat();
2415     for ( sal_uInt16 nIdx = 0; nIdx < nRepeat; ++nIdx )
2416     {
2417         SwRowFrm* pHeadline = new SwRowFrm( *rTable.GetTabLines()[ nIdx ], &rTabFrm );
2418         pHeadline->SetRepeatedHeadline( true );
2419         pHeadline->Paste( &rTabFrm, pLower );
2420         pHeadline->RegistFlys();
2421     }
2422 
2423     if ( bCalcLowers )
2424         rTabFrm.SetCalcLowers();
2425 }
2426 
2427 void _FndBox::MakeFrms( SwTable &rTable )
2428 {
2429 	//Alle Lines zwischen pLineBefore und pLineBehind muessen im Layout
2430 	//wieder neu erzeugt werden.
2431 	//Und Zwar fuer alle Auspraegungen der Tabelle (mehrere z.B. im Kopf/Fuss).
2432 
2433 	sal_uInt16 nStPos = 0;
2434 	sal_uInt16 nEndPos= rTable.GetTabLines().Count() - 1;
2435 	if ( pLineBefore )
2436 	{
2437 		nStPos = rTable.GetTabLines().GetPos(
2438 						(const SwTableLine*&)pLineBefore );
2439 		ASSERT( nStPos != USHRT_MAX, "Fuchs Du hast die Line gestohlen!" );
2440 		++nStPos;
2441 
2442 	}
2443 	if ( pLineBehind )
2444 	{
2445 		nEndPos = rTable.GetTabLines().GetPos(
2446 						(const SwTableLine*&)pLineBehind );
2447 		ASSERT( nEndPos != USHRT_MAX, "Fuchs Du hast die Line gestohlen!" );
2448 		--nEndPos;
2449 	}
2450 	//Jetzt die grosse Einfuegeoperation fuer alle Tabllen.
2451 	SwIterator<SwTabFrm,SwFmt> aTabIter( *rTable.GetFrmFmt() );
2452 	for ( SwTabFrm *pTable = aTabIter.First(); pTable; pTable = aTabIter.Next() )
2453 	{
2454 		if ( !pTable->IsFollow() )
2455 		{
2456 			SwRowFrm  *pSibling = 0;
2457             SwFrm  *pUpperFrm  = 0;
2458 			int i;
2459 			for ( i = rTable.GetTabLines().Count()-1;
2460 					i >= 0 && !pSibling; --i )
2461 			{
2462 				SwTableLine *pLine = pLineBehind ? pLineBehind :
2463 													rTable.GetTabLines()[static_cast<sal_uInt16>(i)];
2464 				SwIterator<SwRowFrm,SwFmt> aIter( *pLine->GetFrmFmt() );
2465                 pSibling = aIter.First();
2466                 while ( pSibling && (
2467                             pSibling->GetTabLine() != pLine ||
2468                             !lcl_IsLineOfTblFrm( *pTable, *pSibling ) ||
2469                             pSibling->IsRepeatedHeadline() ||
2470                             // --> FME 2005-08-24 #i53647# If !pLineBehind,
2471                             // IsInSplitTableRow() should be checked.
2472                             ( pLineBehind && pSibling->IsInFollowFlowRow() ) ||
2473                             (!pLineBehind && pSibling->IsInSplitTableRow() ) ) )
2474                             // <--
2475                 {
2476                     pSibling = aIter.Next();
2477                 }
2478             }
2479 			if ( pSibling )
2480 			{
2481                 pUpperFrm = pSibling->GetUpper();
2482 				if ( !pLineBehind )
2483 					pSibling = 0;
2484 			}
2485 			else
2486 // ???? oder das der Letzte Follow der Tabelle ????
2487                 pUpperFrm = pTable;
2488 
2489 			for ( i = nStPos; (sal_uInt16)i <= nEndPos; ++i )
2490 				::lcl_InsertRow( *rTable.GetTabLines()[static_cast<sal_uInt16>(i)],
2491                                 (SwLayoutFrm*)pUpperFrm, pSibling );
2492             if ( pUpperFrm->IsTabFrm() )
2493                 ((SwTabFrm*)pUpperFrm)->SetCalcLowers();
2494 		}
2495         else if ( rTable.GetRowsToRepeat() > 0 )
2496 		{
2497             // Insert new headlines:
2498             lcl_UpdateRepeatedHeadlines( *pTable, true );
2499         }
2500 	}
2501 }
2502 
2503 void _FndBox::MakeNewFrms( SwTable &rTable, const sal_uInt16 nNumber,
2504 											const sal_Bool bBehind )
2505 {
2506 	//Frms fuer neu eingefuege Zeilen erzeugen.
2507 	//bBehind == sal_True:	vor		pLineBehind
2508 	//		  == sal_False: hinter	pLineBefore
2509 	const sal_uInt16 nBfPos = pLineBefore ?
2510 		rTable.GetTabLines().GetPos( (const SwTableLine*&)pLineBefore ) :
2511 		USHRT_MAX;
2512 	const sal_uInt16 nBhPos = pLineBehind ?
2513 		rTable.GetTabLines().GetPos( (const SwTableLine*&)pLineBehind ) :
2514 		USHRT_MAX;
2515 
2516 	//nNumber: wie oft ist eingefuegt worden.
2517 	//nCnt:	   wieviele sind nNumber mal eingefuegt worden.
2518 
2519 	const sal_uInt16 nCnt =
2520 		((nBhPos != USHRT_MAX ? nBhPos : rTable.GetTabLines().Count()) -
2521 		 (nBfPos != USHRT_MAX ? nBfPos + 1 : 0)) / (nNumber + 1);
2522 
2523 	//Den Master-TabFrm suchen
2524 	SwIterator<SwTabFrm,SwFmt> aTabIter( *rTable.GetFrmFmt() );
2525 	SwTabFrm *pTable;
2526 	for ( pTable = aTabIter.First(); pTable; pTable = aTabIter.Next() )
2527     {
2528 		if( !pTable->IsFollow() )
2529 		{
2530 			SwRowFrm* pSibling = 0;
2531             SwLayoutFrm *pUpperFrm   = 0;
2532 			if ( bBehind )
2533 			{
2534 				if ( pLineBehind )
2535 				{
2536 					SwIterator<SwRowFrm,SwFmt> aIter( *pLineBehind->GetFrmFmt() );
2537                     pSibling = aIter.First();
2538                     while ( pSibling && (
2539                                 // only consider row frames associated with pLineBehind:
2540                                 pSibling->GetTabLine() != pLineBehind ||
2541                                 // only consider row frames that are in pTables Master-Follow chain:
2542                                 !lcl_IsLineOfTblFrm( *pTable, *pSibling ) ||
2543                                 // only consider row frames that are not repeated headlines:
2544                                 pSibling->IsRepeatedHeadline() ||
2545                                 // only consider row frames that are not follow flow rows
2546                                 pSibling->IsInFollowFlowRow() ) )
2547                     {
2548                           pSibling = aIter.Next();
2549                     }
2550 				}
2551 				if ( pSibling )
2552                     pUpperFrm = pSibling->GetUpper();
2553 				else
2554 				{
2555 					while( pTable->GetFollow() )
2556 						pTable = pTable->GetFollow();
2557                     pUpperFrm = pTable;
2558 				}
2559 				const sal_uInt16 nMax = nBhPos != USHRT_MAX ?
2560 									nBhPos : rTable.GetTabLines().Count();
2561 
2562 				sal_uInt16 i = nBfPos != USHRT_MAX ? nBfPos + 1 + nCnt : nCnt;
2563 
2564 				for ( ; i < nMax; ++i )
2565                     ::lcl_InsertRow( *rTable.GetTabLines()[i], pUpperFrm, pSibling );
2566                 if ( pUpperFrm->IsTabFrm() )
2567                     ((SwTabFrm*)pUpperFrm)->SetCalcLowers();
2568 			}
2569             else //davor einfuegen
2570             {
2571                 sal_uInt16 i;
2572 
2573                 // We are looking for the frame that is behind the row frame
2574                 // that should be inserted.
2575                 for ( i = 0; !pSibling; ++i )
2576                 {
2577                     SwTableLine* pLine = pLineBefore ? pLineBefore : rTable.GetTabLines()[i];
2578 
2579                     SwIterator<SwRowFrm,SwFmt> aIter( *pLine->GetFrmFmt() );
2580                     pSibling = aIter.First();
2581 
2582                     while ( pSibling && (
2583                             // only consider row frames associated with pLineBefore:
2584                             pSibling->GetTabLine() != pLine ||
2585                             // only consider row frames that are in pTables Master-Follow chain:
2586                             !lcl_IsLineOfTblFrm( *pTable, *pSibling ) ||
2587                             // only consider row frames that are not repeated headlines:
2588                             pSibling->IsRepeatedHeadline() ||
2589                             // 1. case: pLineBefore == 0:
2590                             // only consider row frames that are not follow flow rows
2591                             // 2. case: pLineBefore != 0:
2592                             // only consider row frames that are not split table rows
2593                             // --> FME 2004-11-23 #i37476# If !pLineBefore,
2594                             // check IsInFollowFlowRow instead of IsInSplitTableRow.
2595                             ( ( !pLineBefore && pSibling->IsInFollowFlowRow() ) ||
2596                               (  pLineBefore && pSibling->IsInSplitTableRow() ) ) ) )
2597                             // <--
2598                     {
2599                         pSibling = aIter.Next();
2600                     }
2601                 }
2602 
2603                 pUpperFrm = pSibling->GetUpper();
2604                 if ( pLineBefore )
2605                     pSibling = (SwRowFrm*) pSibling->GetNext();
2606 
2607                 sal_uInt16 nMax = nBhPos != USHRT_MAX ?
2608                                     nBhPos - nCnt :
2609                                     rTable.GetTabLines().Count() - nCnt;
2610 
2611                 i = nBfPos != USHRT_MAX ? nBfPos + 1 : 0;
2612                 for ( ; i < nMax; ++i )
2613                     ::lcl_InsertRow( *rTable.GetTabLines()[i],
2614                                 pUpperFrm, pSibling );
2615                 if ( pUpperFrm->IsTabFrm() )
2616                     ((SwTabFrm*)pUpperFrm)->SetCalcLowers();
2617             }
2618         }
2619     }
2620 
2621 	//Die Headlines mussen ggf. auch verarbeitet werden. Um gut arbeitenden
2622 	//Code nicht zu zerfasern wird hier nochmals iteriert.
2623     const sal_uInt16 nRowsToRepeat = rTable.GetRowsToRepeat();
2624     if ( nRowsToRepeat > 0 &&
2625          ( ( !bBehind && ( nBfPos == USHRT_MAX || nBfPos + 1 < nRowsToRepeat ) ) ||
2626            (  bBehind && ( ( nBfPos == USHRT_MAX && nRowsToRepeat > 1 ) || nBfPos + 2 < nRowsToRepeat ) ) ) )
2627 	{
2628         for ( pTable = aTabIter.First(); pTable; pTable = aTabIter.Next() )
2629         {
2630             if ( pTable->Lower() )
2631             {
2632                 if ( pTable->IsFollow() )
2633                 {
2634                     lcl_UpdateRepeatedHeadlines( *pTable, true );
2635                 }
2636 
2637                 ASSERT( ((SwRowFrm*)pTable->Lower())->GetTabLine() ==
2638                         rTable.GetTabLines()[0], "MakeNewFrms: Table corruption!" )
2639             }
2640         }
2641 	}
2642 }
2643 
2644 sal_Bool _FndBox::AreLinesToRestore( const SwTable &rTable ) const
2645 {
2646 	//Lohnt es sich MakeFrms zu rufen?
2647 
2648 	if ( !pLineBefore && !pLineBehind && rTable.GetTabLines().Count() )
2649 		return sal_True;
2650 
2651 	sal_uInt16 nBfPos;
2652 	if(pLineBefore)
2653 	{
2654 		const SwTableLine* rLBefore = (const SwTableLine*)pLineBefore;
2655 		nBfPos = rTable.GetTabLines().GetPos( rLBefore );
2656 	}
2657 	else
2658 		nBfPos = USHRT_MAX;
2659 
2660 	sal_uInt16 nBhPos;
2661 	if(pLineBehind)
2662 	{
2663 		const SwTableLine* rLBehind = (const SwTableLine*)pLineBehind;
2664 		nBhPos = rTable.GetTabLines().GetPos( rLBehind );
2665 	}
2666 	else
2667 		nBhPos = USHRT_MAX;
2668 
2669 	if ( nBfPos == nBhPos )	//Duerfte eigentlich nie vorkommen.
2670 	{
2671 		ASSERT( sal_False, "Table, Loeschen auf keinem Bereich !?!" );
2672 		return sal_False;
2673 	}
2674 
2675     if ( rTable.GetRowsToRepeat() > 0 )
2676 	{
2677 		// ups. sollte unsere zu wiederholende Kopfzeile geloescht worden
2678 		// sein??
2679         SwIterator<SwTabFrm,SwFmt> aIter( *rTable.GetFrmFmt() );
2680         for( SwTabFrm* pTable = aIter.First(); pTable; pTable = aIter.Next() )
2681         {
2682             if( pTable->IsFollow() )
2683             {
2684                 // Insert new headlines:
2685                 lcl_UpdateRepeatedHeadlines( *pTable, false );
2686             }
2687         }
2688 	}
2689 
2690     // Some adjacent lines at the beginning of the table have been deleted:
2691     if ( nBfPos == USHRT_MAX && nBhPos == 0 )
2692 		return sal_False;
2693 
2694     // Some adjacent lines at the end of the table have been deleted:
2695     if ( nBhPos == USHRT_MAX && nBfPos == (rTable.GetTabLines().Count() - 1) )
2696 		return sal_False;
2697 
2698     // Some adjacent lines in the middle of the table have been deleted:
2699 	if ( nBfPos != USHRT_MAX && nBhPos != USHRT_MAX && (nBfPos + 1) == nBhPos )
2700 		return sal_False;
2701 
2702     // The structure of the deleted lines is more complex due to split lines.
2703     // A call of MakeFrms() is necessary.
2704 	return sal_True;
2705 }
2706 
2707 
2708