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