xref: /trunk/main/sw/source/core/frmedt/tblsel.cxx (revision c0286415)
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;
644             sal_uInt16 nCellCnt = 0;
645             long nYPos = LONG_MAX;
646             long nXPos = 0;
647             long nHeight = 0;
648 
649 			for( n = 0 ; n < aCellFrms.size(); ++n )
650 			{
651 				const _Sort_CellFrm& rCF = aCellFrms[ n ];
652 				if( (rCF.pFrm->Frm().*fnRect->fnGetTop)() != nYPos )
653 				{
654 					// neue Zeile
655 					if( n )
656 					{
657 						if( USHRT_MAX == nRowCells )		// 1. Zeilenwechsel
658 							nRowCells = nCellCnt;
659 						else if( nRowCells != nCellCnt )
660 						{
661 							bValidChartSel = sal_False;
662 							break;
663 						}
664 					}
665 					nCellCnt = 1;
666 					nYPos = (rCF.pFrm->Frm().*fnRect->fnGetTop)();
667 					nHeight = (rCF.pFrm->Frm().*fnRect->fnGetHeight)();
668 
669                     nXPos = bRTL ?
670                             (rCF.pFrm->Frm().*fnRect->fnGetLeft)() :
671                             (rCF.pFrm->Frm().*fnRect->fnGetRight)();
672                 }
673                 else if( nXPos == ( bRTL ?
674                                     (rCF.pFrm->Frm().*fnRect->fnGetRight)() :
675                                     (rCF.pFrm->Frm().*fnRect->fnGetLeft)() ) &&
676                          nHeight == (rCF.pFrm->Frm().*fnRect->fnGetHeight)() )
677                 {
678                     nXPos += ( bRTL ? (-1) : 1 ) *
679                              (rCF.pFrm->Frm().*fnRect->fnGetWidth)();
680                     ++nCellCnt;
681                 }
682 				else
683 				{
684 					bValidChartSel = sal_False;
685 					break;
686 				}
687 			}
688 			if( bValidChartSel )
689 			{
690 				if( USHRT_MAX == nRowCells )
691 					nRowCells = nCellCnt;
692 				else if( nRowCells != nCellCnt )
693 					bValidChartSel = sal_False;
694 			}
695 
696 			if( bValidChartSel && pGetCLines )
697 			{
698 				nYPos = LONG_MAX;
699 				SwChartBoxes* pBoxes = 0;
700 				for( n = 0; n < aCellFrms.size(); ++n )
701 				{
702 					const _Sort_CellFrm& rCF = aCellFrms[ n ];
703 					if( (rCF.pFrm->Frm().*fnRect->fnGetTop)() != nYPos )
704 					{
705 						pBoxes = new SwChartBoxes( 255 < nRowCells
706 													? 255 : (sal_uInt8)nRowCells);
707 						pGetCLines->C40_INSERT( SwChartBoxes, pBoxes, pGetCLines->Count() );
708                         nYPos = (rCF.pFrm->Frm().*fnRect->fnGetTop)();
709 					}
710 					SwTableBoxPtr pBox = (SwTableBox*)rCF.pFrm->GetTabBox();
711 					pBoxes->Insert( pBox, pBoxes->Count() );
712 				}
713 			}
714 		}
715 
716 		if( bTblIsValid )
717 			break;
718 
719 		// ansonsten das Layout der Tabelle kurz "kalkulieren" lassen
720 		// und nochmals neu aufsetzen
721 		SwTabFrm *pTable = aUnions[0]->GetTable();
722 		for( i = 0; i < aUnions.Count(); ++i )
723 		{
724 			if( pTable->IsValid() )
725 				pTable->InvalidatePos();
726 			pTable->SetONECalcLowers();
727 			pTable->Calc();
728 			pTable->SetCompletePaint();
729 			if( 0 == (pTable = pTable->GetFollow()) )
730 				break;
731 		}
732 		--nLoopMax;
733 		if( pGetCLines )
734 			pGetCLines->DeleteAndDestroy( 0, pGetCLines->Count() );
735 	} while( sal_True );
736 
737 	ASSERT( nLoopMax, "das Layout der Tabelle wurde nicht valide!" );
738 
739 	if( !bValidChartSel && pGetCLines )
740 		pGetCLines->DeleteAndDestroy( 0, pGetCLines->Count() );
741 
742 	return bValidChartSel;
743 }
744 
745 
746 sal_Bool IsFrmInTblSel( const SwRect& rUnion, const SwFrm* pCell )
747 {
748 	ASSERT( pCell->IsCellFrm(), "Frame ohne Gazelle" );
749 
750     if( pCell->FindTabFrm()->IsVertical() )
751         return ( rUnion.Right() >= pCell->Frm().Right() &&
752                  rUnion.Left() <= pCell->Frm().Left() &&
753             (( rUnion.Top() <= pCell->Frm().Top()+20 &&
754                rUnion.Bottom() > pCell->Frm().Top() ) ||
755              ( rUnion.Top() >= pCell->Frm().Top() &&
756                rUnion.Bottom() < pCell->Frm().Bottom() )) ? sal_True : sal_False );
757 
758     return (
759 		rUnion.Top() <= pCell->Frm().Top() &&
760 		rUnion.Bottom() >= pCell->Frm().Bottom() &&
761 
762 		(( rUnion.Left() <= pCell->Frm().Left()+20 &&
763 		   rUnion.Right() > pCell->Frm().Left() ) ||
764 
765 		 ( rUnion.Left() >= pCell->Frm().Left() &&
766 		   rUnion.Right() < pCell->Frm().Right() )) ? sal_True : sal_False );
767 }
768 
769 sal_Bool GetAutoSumSel( const SwCrsrShell& rShell, SwCellFrms& rBoxes )
770 {
771     SwShellCrsr* pCrsr = rShell.pCurCrsr;
772     if ( rShell.IsTableMode() )
773         pCrsr = rShell.pTblCrsr;
774 
775 	const SwLayoutFrm *pStart = pCrsr->GetCntntNode()->getLayoutFrm( rShell.GetLayout(),
776 					  &pCrsr->GetPtPos() )->GetUpper(),
777 					  *pEnd	  = pCrsr->GetCntntNode(sal_False)->getLayoutFrm( rShell.GetLayout(),
778 					  &pCrsr->GetMkPos() )->GetUpper();
779 
780     const SwLayoutFrm* pSttCell = pStart;
781 	while( pSttCell && !pSttCell->IsCellFrm() )
782 		pSttCell = pSttCell->GetUpper();
783 
784 	//Zuerst lassen wir uns die Tabellen und die Rechtecke heraussuchen.
785 	SwSelUnions aUnions;
786 
787 	// default erstmal nach oben testen, dann nach links
788 	::MakeSelUnions( aUnions, pStart, pEnd, nsSwTblSearchType::TBLSEARCH_COL );
789 
790 	sal_Bool bTstRow = sal_True, bFound = sal_False;
791 	sal_uInt16 i;
792 
793 	// 1. teste ob die darueber liegende Box Value/Formel enhaelt:
794 	for( i = 0; i < aUnions.Count(); ++i )
795 	{
796 		SwSelUnion *pUnion = aUnions[i];
797 		const SwTabFrm *pTable = pUnion->GetTable();
798 
799         // Skip any repeated headlines in the follow:
800         const SwLayoutFrm* pRow = pTable->IsFollow() ?
801                                   pTable->GetFirstNonHeadlineRow() :
802                                   (const SwLayoutFrm*)pTable->Lower();
803 
804 		while( pRow )
805 		{
806 			if( pRow->Frm().IsOver( pUnion->GetUnion() ) )
807 			{
808 				const SwCellFrm* pUpperCell = 0;
809 				const SwLayoutFrm *pCell = pRow->FirstCell();
810 
811 				while( pCell && pRow->IsAnLower( pCell ) )
812 				{
813 					if( pCell == pSttCell )
814 					{
815 						sal_uInt16 nWhichId = 0;
816 						for( sal_uInt16 n = rBoxes.Count(); n; )
817 							if( USHRT_MAX != ( nWhichId = rBoxes[ --n ]
818 								->GetTabBox()->IsFormulaOrValueBox() ))
819 								break;
820 
821 						// alle Boxen zusammen, nicht mehr die Zeile
822 						// pruefen, wenn eine Formel oder Value gefunden wurde
823 						bTstRow = 0 == nWhichId || USHRT_MAX == nWhichId;
824 						bFound = sal_True;
825 						break;
826 					}
827 
828 					ASSERT( pCell->IsCellFrm(), "Frame ohne Celle" );
829 					if( ::IsFrmInTblSel( pUnion->GetUnion(), pCell ) )
830 						pUpperCell = (SwCellFrm*)pCell;
831 
832 					if( pCell->GetNext() )
833 					{
834 						pCell = (const SwLayoutFrm*)pCell->GetNext();
835                         if ( pCell->Lower() && pCell->Lower()->IsRowFrm() )
836 							pCell = pCell->FirstCell();
837 					}
838 					else
839 						pCell = ::lcl_FindNextCellFrm( pCell );
840 				}
841 
842 				if( pUpperCell )
843 					rBoxes.Insert( pUpperCell, rBoxes.Count() );
844 			}
845 			if( bFound )
846 			{
847 				i = aUnions.Count();
848 				break;
849 			}
850 			pRow = (const SwLayoutFrm*)pRow->GetNext();
851 		}
852 	}
853 
854 
855 	// 2. teste ob die links liegende Box Value/Formel enhaelt:
856 	if( bTstRow )
857 	{
858 		bFound = sal_False;
859 
860 		rBoxes.Remove( 0, rBoxes.Count() );
861 		aUnions.DeleteAndDestroy( 0, aUnions.Count() );
862 		::MakeSelUnions( aUnions, pStart, pEnd, nsSwTblSearchType::TBLSEARCH_ROW );
863 
864 		for( i = 0; i < aUnions.Count(); ++i )
865 		{
866 			SwSelUnion *pUnion = aUnions[i];
867 			const SwTabFrm *pTable = pUnion->GetTable();
868 
869             // Skip any repeated headlines in the follow:
870             const SwLayoutFrm* pRow = pTable->IsFollow() ?
871                                       pTable->GetFirstNonHeadlineRow() :
872                                       (const SwLayoutFrm*)pTable->Lower();
873 
874 			while( pRow )
875 			{
876 				if( pRow->Frm().IsOver( pUnion->GetUnion() ) )
877 				{
878 					const SwLayoutFrm *pCell = pRow->FirstCell();
879 
880 					while( pCell && pRow->IsAnLower( pCell ) )
881 					{
882 						if( pCell == pSttCell )
883 						{
884 							sal_uInt16 nWhichId = 0;
885 							for( sal_uInt16 n = rBoxes.Count(); n; )
886 								if( USHRT_MAX != ( nWhichId = rBoxes[ --n ]
887 									->GetTabBox()->IsFormulaOrValueBox() ))
888 									break;
889 
890 							// alle Boxen zusammen, nicht mehr die Zeile
891 							// pruefen, wenn eine Formel oder Value gefunden wurde
892 							bFound = 0 != nWhichId && USHRT_MAX != nWhichId;
893 							bTstRow = sal_False;
894 							break;
895 						}
896 
897 						ASSERT( pCell->IsCellFrm(), "Frame ohne Celle" );
898 						if( ::IsFrmInTblSel( pUnion->GetUnion(), pCell ) )
899 						{
900 							const SwCellFrm* pC = (SwCellFrm*)pCell;
901 							rBoxes.Insert( pC, rBoxes.Count() );
902 						}
903 						if( pCell->GetNext() )
904 						{
905 							pCell = (const SwLayoutFrm*)pCell->GetNext();
906                             if ( pCell->Lower() && pCell->Lower()->IsRowFrm() )
907 								pCell = pCell->FirstCell();
908 						}
909 						else
910 							pCell = ::lcl_FindNextCellFrm( pCell );
911 					}
912 				}
913 				if( !bTstRow )
914 				{
915 					i = aUnions.Count();
916 					break;
917 				}
918 
919 				pRow = (const SwLayoutFrm*)pRow->GetNext();
920 			}
921 		}
922 	}
923 
924 	return bFound;
925 }
926 
927 sal_Bool HasProtectedCells( const SwSelBoxes& rBoxes )
928 {
929 	sal_Bool bRet = sal_False;
930 	for( sal_uInt16 n = 0, nCnt = rBoxes.Count(); n < nCnt; ++n )
931 		if( rBoxes[ n ]->GetFrmFmt()->GetProtect().IsCntntProtected() )
932 		{
933 			bRet = sal_True;
934 			break;
935 		}
936 	return bRet;
937 }
938 
939 
940 _CmpLPt::_CmpLPt( const Point& rPt, const SwTableBox* pBox, sal_Bool bVertical )
941     : aPos( rPt ), pSelBox( pBox ), bVert( bVertical )
942 {}
943 
944 void lcl_InsTblBox( SwTableNode* pTblNd, SwDoc* pDoc, SwTableBox* pBox,
945 						sal_uInt16 nInsPos, sal_uInt16 nCnt = 1 )
946 {
947 	ASSERT( pBox->GetSttNd(), "Box ohne Start-Node" );
948 	SwCntntNode* pCNd = pDoc->GetNodes()[ pBox->GetSttIdx() + 1 ]
949 								->GetCntntNode();
950 	if( pCNd && pCNd->IsTxtNode() )
951 		pDoc->GetNodes().InsBoxen( pTblNd, pBox->GetUpper(),
952 				(SwTableBoxFmt*)pBox->GetFrmFmt(),
953 				((SwTxtNode*)pCNd)->GetTxtColl(),
954                 pCNd->GetpSwAttrSet(),
955 				nInsPos, nCnt );
956 	else
957 		pDoc->GetNodes().InsBoxen( pTblNd, pBox->GetUpper(),
958 				(SwTableBoxFmt*)pBox->GetFrmFmt(),
959 				(SwTxtFmtColl*)pDoc->GetDfltTxtFmtColl(), 0,
960 				nInsPos, nCnt );
961 }
962 
963 sal_Bool IsEmptyBox( const SwTableBox& rBox, SwPaM& rPam )
964 {
965 	rPam.GetPoint()->nNode = *rBox.GetSttNd()->EndOfSectionNode();
966 	rPam.Move( fnMoveBackward, fnGoCntnt );
967 	rPam.SetMark();
968 	rPam.GetPoint()->nNode = *rBox.GetSttNd();
969 	rPam.Move( fnMoveForward, fnGoCntnt );
970 	sal_Bool bRet = *rPam.GetMark() == *rPam.GetPoint()
971         && ( rBox.GetSttNd()->GetIndex() + 1 == rPam.GetPoint()->nNode.GetIndex() );
972 
973 	if( bRet )
974 	{
975 		// dann teste mal auf absatzgebundenen Flys
976 		const SwSpzFrmFmts& rFmts = *rPam.GetDoc()->GetSpzFrmFmts();
977 		sal_uLong nSttIdx = rPam.GetPoint()->nNode.GetIndex(),
978 			  nEndIdx = rBox.GetSttNd()->EndOfSectionIndex(),
979 			  nIdx;
980 
981 		for( sal_uInt16 n = 0; n < rFmts.Count(); ++n )
982 		{
983 			const SwFmtAnchor& rAnchor = rFmts[n]->GetAnchor();
984             const SwPosition* pAPos = rAnchor.GetCntntAnchor();
985             if (pAPos &&
986                 ((FLY_AT_PARA == rAnchor.GetAnchorId()) ||
987                  (FLY_AT_CHAR == rAnchor.GetAnchorId())) &&
988 				nSttIdx <= ( nIdx = pAPos->nNode.GetIndex() ) &&
989 				nIdx < nEndIdx )
990 			{
991 				bRet = sal_False;
992 				break;
993 			}
994 		}
995 	}
996 	return bRet;
997 }
998 
999 
1000 void GetMergeSel( const SwPaM& rPam, SwSelBoxes& rBoxes,
1001 				SwTableBox** ppMergeBox, SwUndoTblMerge* pUndo )
1002 {
1003 	if( rBoxes.Count() )
1004 		rBoxes.Remove( sal_uInt16(0), rBoxes.Count() );
1005 
1006 	//Zuerst lassen wir uns die Tabellen und die Rechtecke heraussuchen.
1007 	ASSERT( rPam.GetCntntNode() && rPam.GetCntntNode( sal_False ),
1008 			"Tabselection nicht auf Cnt." );
1009 
1010 //JP 24.09.96: Merge mit wiederholenden TabellenHeadline funktioniert nicht
1011 // 				richtig. Warum nicht Point 0,0 benutzen? Dann ist garantiert,
1012 //				das die 1. Headline mit drin ist.
1013 //	Point aPt( rShell.GetCharRect().Pos() );
1014 	Point aPt( 0, 0 );
1015 
1016     const SwCntntNode* pCntNd = rPam.GetCntntNode();
1017 	const SwLayoutFrm *pStart = pCntNd->getLayoutFrm( pCntNd->GetDoc()->GetCurrentLayout(),
1018 														&aPt )->GetUpper();
1019     pCntNd = rPam.GetCntntNode(sal_False);
1020 	const SwLayoutFrm *pEnd = pCntNd->getLayoutFrm( pCntNd->GetDoc()->GetCurrentLayout(),
1021 														&aPt )->GetUpper();
1022 
1023 	SwSelUnions aUnions;
1024 	::MakeSelUnions( aUnions, pStart, pEnd );
1025 	if( !aUnions.Count() )
1026 		return;
1027 
1028 	const SwTable *pTable = aUnions[0]->GetTable()->GetTable();
1029 	SwDoc* pDoc = (SwDoc*)pStart->GetFmt()->GetDoc();
1030 	SwTableNode* pTblNd = (SwTableNode*)pTable->GetTabSortBoxes()[ 0 ]->
1031 										GetSttNd()->FindTableNode();
1032 
1033 	_MergePos aPosArr;		// Sort-Array mit den Positionen der Frames
1034 	long nWidth;
1035 	SwTableBox* pLastBox = 0;
1036 
1037     SWRECTFN( pStart->GetUpper() )
1038 
1039 	for ( sal_uInt16 i = 0; i < aUnions.Count(); ++i )
1040 	{
1041 		const SwTabFrm *pTabFrm = aUnions[i]->GetTable();
1042 
1043 		SwRect &rUnion = aUnions[i]->GetUnion();
1044 
1045         // Skip any repeated headlines in the follow:
1046         const SwLayoutFrm* pRow = pTabFrm->IsFollow() ?
1047                                   pTabFrm->GetFirstNonHeadlineRow() :
1048                                   (const SwLayoutFrm*)pTabFrm->Lower();
1049 
1050 		while ( pRow )
1051 		{
1052 			if ( pRow->Frm().IsOver( rUnion ) )
1053 			{
1054 				const SwLayoutFrm *pCell = pRow->FirstCell();
1055 
1056 				while ( pCell && pRow->IsAnLower( pCell ) )
1057 				{
1058 					ASSERT( pCell->IsCellFrm(), "Frame ohne Celle" );
1059 						// in der vollen Breite ueberlappend ?
1060 					if( rUnion.Top() <= pCell->Frm().Top() &&
1061 						rUnion.Bottom() >= pCell->Frm().Bottom() )
1062 					{
1063 						SwTableBox* pBox =(SwTableBox*)((SwCellFrm*)pCell)->GetTabBox();
1064 
1065 						// nur nach rechts ueberlappend
1066 						if( ( rUnion.Left() - COLFUZZY ) <= pCell->Frm().Left() &&
1067 							( rUnion.Right() - COLFUZZY ) > pCell->Frm().Left() )
1068 						{
1069 							if( ( rUnion.Right() + COLFUZZY ) < pCell->Frm().Right() )
1070 							{
1071 								sal_uInt16 nInsPos = pBox->GetUpper()->
1072 													GetTabBoxes().C40_GETPOS( SwTableBox, pBox )+1;
1073 								lcl_InsTblBox( pTblNd, pDoc, pBox, nInsPos );
1074 								pBox->ClaimFrmFmt();
1075 								SwFmtFrmSize aNew(
1076 										pBox->GetFrmFmt()->GetFrmSize() );
1077 								nWidth = rUnion.Right() - pCell->Frm().Left();
1078 								nWidth = nWidth * aNew.GetWidth() /
1079 										 pCell->Frm().Width();
1080 								long nTmpWidth = aNew.GetWidth() - nWidth;
1081 								aNew.SetWidth( nWidth );
1082                                 pBox->GetFrmFmt()->SetFmtAttr( aNew );
1083 								// diese Box ist selektiert
1084 								pLastBox = pBox;
1085 								rBoxes.Insert( pBox );
1086                                 aPosArr.Insert(
1087                                     _CmpLPt( (pCell->Frm().*fnRect->fnGetPos)(),
1088                                     pBox, bVert ) );
1089 
1090 								pBox = pBox->GetUpper()->GetTabBoxes()[ nInsPos ];
1091 								aNew.SetWidth( nTmpWidth );
1092 								pBox->ClaimFrmFmt();
1093                                 pBox->GetFrmFmt()->SetFmtAttr( aNew );
1094 
1095 								if( pUndo )
1096 									pUndo->AddNewBox( pBox->GetSttIdx() );
1097 							}
1098 							else
1099 							{
1100 								// diese Box ist selektiert
1101 								pLastBox = pBox;
1102 								rBoxes.Insert( pBox );
1103 #if OSL_DEBUG_LEVEL > 1
1104                                 Point aInsPoint( (pCell->Frm().*fnRect->fnGetPos)() );
1105 #endif
1106                                 aPosArr.Insert(
1107                                     _CmpLPt( (pCell->Frm().*fnRect->fnGetPos)(),
1108 									pBox, bVert ) );
1109 							}
1110 						}
1111 						// oder rechts und links ueberlappend
1112 						else if( ( rUnion.Left() - COLFUZZY ) >= pCell->Frm().Left() &&
1113 								( rUnion.Right() + COLFUZZY ) < pCell->Frm().Right() )
1114 						{
1115 							sal_uInt16 nInsPos = pBox->GetUpper()->GetTabBoxes().
1116 											C40_GETPOS( SwTableBox, pBox )+1;
1117 							lcl_InsTblBox( pTblNd, pDoc, pBox, nInsPos, 2 );
1118 							pBox->ClaimFrmFmt();
1119 							SwFmtFrmSize aNew(
1120 										pBox->GetFrmFmt()->GetFrmSize() );
1121 							long nLeft = rUnion.Left() - pCell->Frm().Left();
1122 							nLeft = nLeft * aNew.GetWidth() /
1123 									pCell->Frm().Width();
1124 							long nRight = pCell->Frm().Right() - rUnion.Right();
1125 							nRight = nRight * aNew.GetWidth() /
1126 									 pCell->Frm().Width();
1127 							nWidth = aNew.GetWidth() - nLeft - nRight;
1128 
1129 							aNew.SetWidth( nLeft );
1130                             pBox->GetFrmFmt()->SetFmtAttr( aNew );
1131 
1132 							{
1133 							const SfxPoolItem* pItem;
1134 							if( SFX_ITEM_SET == pBox->GetFrmFmt()->GetAttrSet()
1135 										.GetItemState( RES_BOX, sal_False, &pItem ))
1136 							{
1137 								SvxBoxItem aBox( *(SvxBoxItem*)pItem );
1138 								aBox.SetLine( 0, BOX_LINE_RIGHT );
1139                                 pBox->GetFrmFmt()->SetFmtAttr( aBox );
1140 							}
1141 							}
1142 
1143 							pBox = pBox->GetUpper()->GetTabBoxes()[ nInsPos ];
1144 							aNew.SetWidth( nWidth );
1145 							pBox->ClaimFrmFmt();
1146                             pBox->GetFrmFmt()->SetFmtAttr( aNew );
1147 
1148 							if( pUndo )
1149 								pUndo->AddNewBox( pBox->GetSttIdx() );
1150 
1151 							// diese Box ist selektiert
1152 							pLastBox = pBox;
1153 							rBoxes.Insert( pBox );
1154                             aPosArr.Insert(
1155                                 _CmpLPt( (pCell->Frm().*fnRect->fnGetPos)(),
1156                                 pBox, bVert ) );
1157 
1158 							pBox = pBox->GetUpper()->GetTabBoxes()[ nInsPos+1 ];
1159 							aNew.SetWidth( nRight );
1160 							pBox->ClaimFrmFmt();
1161                             pBox->GetFrmFmt()->SetFmtAttr( aNew );
1162 
1163 							if( pUndo )
1164 								pUndo->AddNewBox( pBox->GetSttIdx() );
1165 						}
1166 						// oder reicht die rechte Kante der Box in den
1167 						// selektierten Bereich?
1168 						else if( ( pCell->Frm().Right() - COLFUZZY ) < rUnion.Right() &&
1169 								 ( pCell->Frm().Right() - COLFUZZY ) > rUnion.Left() &&
1170 								 ( pCell->Frm().Left() + COLFUZZY ) < rUnion.Left() )
1171 						{
1172 							// dann muss eine neue Box einfuegt und die
1173 							// Breiten angepasst werden
1174 							sal_uInt16 nInsPos = pBox->GetUpper()->GetTabBoxes().
1175 											C40_GETPOS( SwTableBox, pBox )+1;
1176 							lcl_InsTblBox( pTblNd, pDoc, pBox, nInsPos, 1 );
1177 
1178 							SwFmtFrmSize aNew(pBox->GetFrmFmt()->GetFrmSize() );
1179 							long nLeft = rUnion.Left() - pCell->Frm().Left(),
1180 								nRight = pCell->Frm().Right() - rUnion.Left();
1181 
1182 							nLeft = nLeft * aNew.GetWidth() /
1183 									pCell->Frm().Width();
1184 							nRight = nRight * aNew.GetWidth() /
1185 									pCell->Frm().Width();
1186 
1187 							aNew.SetWidth( nLeft );
1188                             pBox->ClaimFrmFmt()->SetFmtAttr( aNew );
1189 
1190 								// diese Box ist selektiert
1191 							pBox = pBox->GetUpper()->GetTabBoxes()[ nInsPos ];
1192 							aNew.SetWidth( nRight );
1193 							pBox->ClaimFrmFmt();
1194                             pBox->GetFrmFmt()->SetFmtAttr( aNew );
1195 
1196 							pLastBox = pBox;
1197 							rBoxes.Insert( pBox );
1198                             aPosArr.Insert( _CmpLPt( Point( rUnion.Left(),
1199                                                 pCell->Frm().Top()), pBox, bVert ));
1200 
1201 							if( pUndo )
1202 								pUndo->AddNewBox( pBox->GetSttIdx() );
1203 						}
1204 					}
1205 					if ( pCell->GetNext() )
1206 					{
1207 						pCell = (const SwLayoutFrm*)pCell->GetNext();
1208                         // --> FME 2005-11-03 #125288# Check if table cell is not empty
1209                         if ( pCell->Lower() && pCell->Lower()->IsRowFrm() )
1210 							pCell = pCell->FirstCell();
1211 					}
1212 					else
1213 						pCell = ::lcl_FindNextCellFrm( pCell );
1214 				}
1215 			}
1216 			pRow = (const SwLayoutFrm*)pRow->GetNext();
1217 		}
1218 	}
1219 
1220 	// keine SSelection / keine gefundenen Boxen
1221 	if( 1 >= rBoxes.Count() )
1222 		return;
1223 
1224 	// dann suche mal alle Boxen, die nebeneinander liegen, und verbinde
1225 	// deren Inhalte mit Blanks. Alle untereinander liegende werden als
1226 	// Absaetze zusammengefasst
1227 
1228 	// 1. Loesung: gehe ueber das Array und
1229 	// 		alle auf der gleichen Y-Ebene werden mit Blanks getrennt
1230 	//		alle anderen werden als Absaetze getrennt.
1231 	sal_Bool bCalcWidth = sal_True;
1232 	const SwTableBox* pFirstBox = aPosArr[ 0 ].pSelBox;
1233 
1234 	// JP 27.03.98:  Optimierung - falls die Boxen einer Line leer sind,
1235 	//				dann werden jetzt dafuer keine Blanks und
1236 	//				kein Umbruch mehr eingefuegt.
1237 	//Block damit SwPaM, SwPosition vom Stack geloescht werden
1238 	{
1239 		SwPaM aPam( pDoc->GetNodes() );
1240 
1241 #if defined( DEL_ONLY_EMPTY_LINES )
1242 		nWidth = pFirstBox->GetFrmFmt()->GetFrmSize().GetWidth();
1243 		sal_Bool bEmptyLine = sal_True;
1244 		sal_uInt16 n, nSttPos = 0;
1245 
1246 		for( n = 0; n < aPosArr.Count(); ++n )
1247 		{
1248 			const _CmpLPt& rPt = aPosArr[ n ];
1249 			if( n && aPosArr[ n - 1 ].Y() == rPt.Y() )	// gleiche Ebene ?
1250 			{
1251 				if( bEmptyLine && !IsEmptyBox( *rPt.pSelBox, aPam ))
1252 					bEmptyLine = sal_False;
1253 				if( bCalcWidth )
1254 					nWidth += rPt.pSelBox->GetFrmFmt()->GetFrmSize().GetWidth();
1255 			}
1256 			else
1257 			{
1258 				if( bCalcWidth && n )
1259 					bCalcWidth = sal_False;		// eine Zeile fertig
1260 
1261 				if( bEmptyLine && nSttPos < n )
1262 				{
1263 					// dann ist die gesamte Line leer und braucht
1264 					// nicht mit Blanks aufgefuellt und als Absatz
1265 					// eingefuegt werden.
1266 					if( pUndo )
1267 						for( sal_uInt16 i = nSttPos; i < n; ++i )
1268 							pUndo->SaveCollection( *aPosArr[ i ].pSelBox );
1269 
1270 					aPosArr.Remove( nSttPos, n - nSttPos );
1271 					n = nSttPos;
1272 				}
1273 				else
1274 					nSttPos = n;
1275 
1276 				bEmptyLine = IsEmptyBox( *aPosArr[n].pSelBox, aPam );
1277 			}
1278 		}
1279 		if( bEmptyLine && nSttPos < n )
1280 		{
1281 			if( pUndo )
1282 				for( sal_uInt16 i = nSttPos; i < n; ++i )
1283 					pUndo->SaveCollection( *aPosArr[ i ].pSelBox );
1284 			aPosArr.Remove( nSttPos, n - nSttPos );
1285 		}
1286 #elsif defined( DEL_EMPTY_BOXES_AT_START_AND_END )
1287 
1288 		nWidth = pFirstBox->GetFrmFmt()->GetFrmSize().GetWidth();
1289 		sal_uInt16 n, nSttPos = 0, nSEndPos = 0, nESttPos = 0;
1290 
1291 		for( n = 0; n < aPosArr.Count(); ++n )
1292 		{
1293 			const _CmpLPt& rPt = aPosArr[ n ];
1294 			if( n && aPosArr[ n - 1 ].Y() == rPt.Y() )	// gleiche Ebene ?
1295 			{
1296 				sal_Bool bEmptyBox = IsEmptyBox( *rPt.pSelBox, aPam );
1297 				if( bEmptyBox )
1298 				{
1299 					if( nSEndPos == n )		// der Anfang ist leer
1300 						nESttPos = ++nSEndPos;
1301 				}
1302 				else 						// das Ende kann leer sein
1303 					nESttPos = n+1;
1304 
1305 				if( bCalcWidth )
1306 					nWidth += rPt.pSelBox->GetFrmFmt()->GetFrmSize().GetWidth();
1307 			}
1308 			else
1309 			{
1310 				if( bCalcWidth && n )
1311 					bCalcWidth = sal_False;		// eine Zeile fertig
1312 
1313 				// zuerst die vom Anfang
1314 				if( nSttPos < nSEndPos )
1315 				{
1316 					// dann ist der vorder Teil der Line leer und braucht
1317 					// nicht mit Blanks aufgefuellt werden.
1318 					if( pUndo )
1319 						for( sal_uInt16 i = nSttPos; i < nSEndPos; ++i )
1320 							pUndo->SaveCollection( *aPosArr[ i ].pSelBox );
1321 
1322 					sal_uInt16 nCnt = nSEndPos - nSttPos;
1323 					aPosArr.Remove( nSttPos, nCnt );
1324 					nESttPos -= nCnt;
1325 					n -= nCnt;
1326 				}
1327 
1328 				if( nESttPos < n )
1329 				{
1330 					// dann ist der vorder Teil der Line leer und braucht
1331 					// nicht mit Blanks aufgefuellt werden.
1332 					if( pUndo )
1333 						for( sal_uInt16 i = nESttPos; i < n; ++i )
1334 							pUndo->SaveCollection( *aPosArr[ i ].pSelBox );
1335 
1336 					sal_uInt16 nCnt = n - nESttPos;
1337 					aPosArr.Remove( nESttPos, nCnt );
1338 					n -= nCnt;
1339 				}
1340 
1341 				nSttPos = nSEndPos = nESttPos = n;
1342 				if( IsEmptyBox( *aPosArr[n].pSelBox, aPam ))
1343 					++nSEndPos;
1344 				else
1345 					++nESttPos;
1346 			}
1347 		}
1348 
1349 		// zuerst die vom Anfang
1350 		if( nSttPos < nSEndPos )
1351 		{
1352 			// dann ist der vorder Teil der Line leer und braucht
1353 			// nicht mit Blanks aufgefuellt werden.
1354 			if( pUndo )
1355 				for( sal_uInt16 i = nSttPos; i < nSEndPos; ++i )
1356 					pUndo->SaveCollection( *aPosArr[ i ].pSelBox );
1357 
1358 			sal_uInt16 nCnt = nSEndPos - nSttPos;
1359 			aPosArr.Remove( nSttPos, nCnt );
1360 			nESttPos -= nCnt;
1361 			n -= nCnt;
1362 		}
1363 		if( nESttPos < n )
1364 		{
1365 			// dann ist der vorder Teil der Line leer und braucht
1366 			// nicht mit Blanks aufgefuellt werden.
1367 			if( pUndo )
1368 				for( sal_uInt16 i = nESttPos; i < n; ++i )
1369 					pUndo->SaveCollection( *aPosArr[ i ].pSelBox );
1370 
1371 			sal_uInt16 nCnt = n - nESttPos;
1372 			aPosArr.Remove( nESttPos, nCnt );
1373 		}
1374 #else
1375 // DEL_ALL_EMPTY_BOXES
1376 
1377 		nWidth = 0;
1378 		long nY = aPosArr.Count() ?
1379                     ( bVert ?
1380 					  aPosArr[ 0 ].X() :
1381 					  aPosArr[ 0 ].Y() ) :
1382 				  0;
1383 
1384 		for( sal_uInt16 n = 0; n < aPosArr.Count(); ++n )
1385 		{
1386 			const _CmpLPt& rPt = aPosArr[ n ];
1387             if( bCalcWidth )
1388 			{
1389                 if( nY == ( bVert ? rPt.X() : rPt.Y() ) )            // gleiche Ebene ?
1390 					nWidth += rPt.pSelBox->GetFrmFmt()->GetFrmSize().GetWidth();
1391 				else
1392 					bCalcWidth = sal_False;		// eine Zeile fertig
1393 			}
1394 
1395 			if( IsEmptyBox( *rPt.pSelBox, aPam ) )
1396 			{
1397 				if( pUndo )
1398 					pUndo->SaveCollection( *rPt.pSelBox );
1399 
1400 				aPosArr.Remove( n, 1 );
1401 				--n;
1402 			}
1403 		}
1404 #endif
1405 	}
1406 
1407 	// lege schon mal die neue Box an
1408 	{
1409 		SwTableBox* pTmpBox = rBoxes[0];
1410 		SwTableLine* pInsLine = pTmpBox->GetUpper();
1411 		sal_uInt16 nInsPos = pInsLine->GetTabBoxes().C40_GETPOS( SwTableBox, pTmpBox );
1412 
1413 		lcl_InsTblBox( pTblNd, pDoc, pTmpBox, nInsPos );
1414 		(*ppMergeBox) = pInsLine->GetTabBoxes()[ nInsPos ];
1415 		pInsLine->GetTabBoxes().Remove( nInsPos );		// wieder austragen
1416 		(*ppMergeBox)->SetUpper( 0 );
1417 		(*ppMergeBox)->ClaimFrmFmt();
1418 
1419 		// setze die Umrandung: von der 1. Box die linke/obere von der
1420 		// letzten Box die rechte/untere Kante:
1421 		if( pLastBox && pFirstBox )
1422 		{
1423 			SvxBoxItem aBox( pFirstBox->GetFrmFmt()->GetBox() );
1424 			const SvxBoxItem& rBox = pLastBox->GetFrmFmt()->GetBox();
1425 			aBox.SetLine( rBox.GetRight(), BOX_LINE_RIGHT );
1426 			aBox.SetLine( rBox.GetBottom(), BOX_LINE_BOTTOM );
1427 			if( aBox.GetLeft() || aBox.GetTop() ||
1428 				aBox.GetRight() || aBox.GetBottom() )
1429                 (*ppMergeBox)->GetFrmFmt()->SetFmtAttr( aBox );
1430 		}
1431 	}
1432 
1433 	//Block damit SwPaM, SwPosition vom Stack geloescht werden
1434 	if( aPosArr.Count() )
1435 	{
1436         SwTxtNode* pTxtNd = 0;
1437 		SwPosition aInsPos( *(*ppMergeBox)->GetSttNd() );
1438 		SwNodeIndex& rInsPosNd = aInsPos.nNode;
1439 
1440 		SwPaM aPam( aInsPos );
1441 
1442 		for( sal_uInt16 n = 0; n < aPosArr.Count(); ++n )
1443 		{
1444 			const _CmpLPt& rPt = aPosArr[ n ];
1445 			aPam.GetPoint()->nNode.Assign( *rPt.pSelBox->GetSttNd()->
1446 											EndOfSectionNode(), -1 );
1447 			SwCntntNode* pCNd = aPam.GetCntntNode();
1448 			sal_uInt16 nL = pCNd ? pCNd->Len() : 0;
1449 			aPam.GetPoint()->nContent.Assign( pCNd, nL );
1450 
1451 			SwNodeIndex aSttNdIdx( *rPt.pSelBox->GetSttNd(), 1 );
1452             // ein Node muss in der Box erhalten bleiben (sonst wird beim
1453             // Move die gesamte Section geloescht)
1454             bool const bUndo(pDoc->GetIDocumentUndoRedo().DoesUndo());
1455             if( pUndo )
1456             {
1457                 pDoc->GetIDocumentUndoRedo().DoUndo(false);
1458             }
1459             pDoc->AppendTxtNode( *aPam.GetPoint() );
1460             if( pUndo )
1461             {
1462                 pDoc->GetIDocumentUndoRedo().DoUndo(bUndo);
1463             }
1464             SwNodeRange aRg( aSttNdIdx, aPam.GetPoint()->nNode );
1465             rInsPosNd++;
1466             if( pUndo )
1467                 pUndo->MoveBoxCntnt( pDoc, aRg, rInsPosNd );
1468             else
1469             {
1470                 pDoc->MoveNodeRange( aRg, rInsPosNd,
1471                     IDocumentContentOperations::DOC_MOVEDEFAULT );
1472             }
1473             // wo steht jetzt aInsPos ??
1474 
1475             if( bCalcWidth )
1476                 bCalcWidth = sal_False;		// eine Zeile fertig
1477 
1478 			// den initialen TextNode ueberspringen
1479 			rInsPosNd.Assign( pDoc->GetNodes(),
1480 							rInsPosNd.GetNode().EndOfSectionIndex() - 2 );
1481 			pTxtNd = rInsPosNd.GetNode().GetTxtNode();
1482 			if( pTxtNd )
1483 				aInsPos.nContent.Assign( pTxtNd, pTxtNd->GetTxt().Len() );
1484 		}
1485 
1486 		// in der MergeBox sollte jetzt der gesamte Text stehen
1487 		// loesche jetzt noch den initialen TextNode
1488 		ASSERT( (*ppMergeBox)->GetSttIdx()+2 <
1489 				(*ppMergeBox)->GetSttNd()->EndOfSectionIndex(),
1490 					"leere Box" );
1491 		SwNodeIndex aIdx( *(*ppMergeBox)->GetSttNd()->EndOfSectionNode(), -1 );
1492 		pDoc->GetNodes().Delete( aIdx, 1 );
1493 	}
1494 
1495 	// setze die Breite der Box
1496     (*ppMergeBox)->GetFrmFmt()->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nWidth, 0 ));
1497 	if( pUndo )
1498 		pUndo->AddNewBox( (*ppMergeBox)->GetSttIdx() );
1499 }
1500 
1501 
1502 static sal_Bool lcl_CheckCol( const _FndBox*& rpFndBox, void* pPara );
1503 
1504 static sal_Bool lcl_CheckRow( const _FndLine*& rpFndLine, void* pPara )
1505 {
1506 	((_FndLine*)rpFndLine)->GetBoxes().ForEach( &lcl_CheckCol, pPara );
1507 	return *(sal_Bool*)pPara;
1508 }
1509 
1510 static sal_Bool lcl_CheckCol( const _FndBox*& rpFndBox, void* pPara )
1511 {
1512 	if( !rpFndBox->GetBox()->GetSttNd() )
1513 	{
1514 		if( rpFndBox->GetLines().Count() !=
1515 			rpFndBox->GetBox()->GetTabLines().Count() )
1516 			*((sal_Bool*)pPara) = sal_False;
1517 		else
1518 			((_FndBox*)rpFndBox)->GetLines().ForEach( &lcl_CheckRow, pPara );
1519 	}
1520 	// Box geschuetzt ??
1521 	else if( rpFndBox->GetBox()->GetFrmFmt()->GetProtect().IsCntntProtected() )
1522 		*((sal_Bool*)pPara) = sal_False;
1523 	return *(sal_Bool*)pPara;
1524 }
1525 
1526 
1527 sal_uInt16 CheckMergeSel( const SwPaM& rPam )
1528 {
1529 	SwSelBoxes aBoxes;
1530 //JP 24.09.96: Merge mit wiederholenden TabellenHeadline funktioniert nicht
1531 // 				richtig. Warum nicht Point 0,0 benutzen? Dann ist garantiert,
1532 //				das die 1. Headline mit drin ist.
1533 	Point aPt;
1534     const SwCntntNode* pCntNd = rPam.GetCntntNode();
1535 	const SwLayoutFrm *pStart = pCntNd->getLayoutFrm( pCntNd->GetDoc()->GetCurrentLayout(),
1536 														&aPt )->GetUpper();
1537     pCntNd = rPam.GetCntntNode(sal_False);
1538 	const SwLayoutFrm *pEnd = pCntNd->getLayoutFrm( pCntNd->GetDoc()->GetCurrentLayout(),
1539 													&aPt )->GetUpper();
1540     GetTblSel( pStart, pEnd, aBoxes, 0 );
1541 	return CheckMergeSel( aBoxes );
1542 }
1543 
1544 sal_uInt16 CheckMergeSel( const SwSelBoxes& rBoxes )
1545 {
1546 	sal_uInt16 eRet = TBLMERGE_NOSELECTION;
1547 	if( rBoxes.Count() )
1548 	{
1549 		eRet = TBLMERGE_OK;
1550 
1551 		_FndBox aFndBox( 0, 0 );
1552 		_FndPara aPara( rBoxes, &aFndBox );
1553 		const SwTableNode* pTblNd = aPara.rBoxes[0]->GetSttNd()->FindTableNode();
1554 		((SwTable&)pTblNd->GetTable()).GetTabLines().ForEach(
1555 					&_FndLineCopyCol, &aPara );
1556 		if( aFndBox.GetLines().Count() )
1557 		{
1558 			sal_Bool bMergeSelOk = sal_True;
1559 			_FndBox* pFndBox = &aFndBox;
1560 			_FndLine* pFndLine = 0;
1561 			while( pFndBox && 1 == pFndBox->GetLines().Count() )
1562 			{
1563 				pFndLine = pFndBox->GetLines()[0];
1564 				if( 1 == pFndLine->GetBoxes().Count() )
1565 					pFndBox = pFndLine->GetBoxes()[0];
1566 				else
1567 					pFndBox = 0;
1568 			}
1569 			if( pFndBox )
1570 				pFndBox->GetLines().ForEach( &lcl_CheckRow, &bMergeSelOk );
1571 			else if( pFndLine )
1572 				pFndLine->GetBoxes().ForEach( &lcl_CheckCol, &bMergeSelOk );
1573 			if( !bMergeSelOk )
1574 				eRet = TBLMERGE_TOOCOMPLEX;
1575 		}
1576 		else
1577 			eRet = TBLMERGE_NOSELECTION;
1578 	}
1579 	return eRet;
1580 }
1581 
1582 //Ermittelt die von einer Tabellenselektion betroffenen Tabellen und die
1583 //Union-Rechteckte der Selektionen - auch fuer aufgespaltene Tabellen.
1584 SV_IMPL_PTRARR( SwSelUnions, SwSelUnion* );
1585 
1586 SwTwips lcl_CalcWish( const SwLayoutFrm *pCell, long nWish,
1587 												const long nAct )
1588 {
1589 	const SwLayoutFrm *pTmp = pCell;
1590 	if ( !nWish )
1591 		nWish = 1;
1592 
1593 	const sal_Bool bRTL = pCell->IsRightToLeft();
1594 	SwTwips nRet = bRTL ?
1595         nAct - pCell->Frm().Width() :
1596         0;
1597 
1598 	while ( pTmp )
1599 	{
1600 		while ( pTmp->GetPrev() )
1601 		{
1602 			pTmp = (SwLayoutFrm*)pTmp->GetPrev();
1603 			long nTmp = pTmp->GetFmt()->GetFrmSize().GetWidth();
1604             nRet += ( bRTL ? ( -1 ) : 1 ) * nTmp * nAct / nWish;
1605 		}
1606 		pTmp = pTmp->GetUpper()->GetUpper();
1607 		if ( pTmp && !pTmp->IsCellFrm() )
1608 			pTmp = 0;
1609 	}
1610 	return nRet;
1611 }
1612 
1613 void lcl_FindStartEndRow( const SwLayoutFrm *&rpStart,
1614 							 const SwLayoutFrm *&rpEnd,
1615 							 const int bChkProtected )
1616 {
1617 	//Start an den Anfang seiner Zeile setzen.
1618 	//End an das Ende seiner Zeile setzen.
1619 	rpStart = (SwLayoutFrm*)rpStart->GetUpper()->Lower();
1620 	while ( rpEnd->GetNext() )
1621 		rpEnd = (SwLayoutFrm*)rpEnd->GetNext();
1622 
1623 	SvPtrarr aSttArr( 8, 8 ), aEndArr( 8, 8 );
1624 	const SwLayoutFrm *pTmp;
1625 	for( pTmp = rpStart; (FRM_CELL|FRM_ROW) & pTmp->GetType();
1626 				pTmp = pTmp->GetUpper() )
1627 	{
1628 		void* p = (void*)pTmp;
1629 		aSttArr.Insert( p, 0 );
1630 	}
1631 	for( pTmp = rpEnd; (FRM_CELL|FRM_ROW) & pTmp->GetType();
1632 				pTmp = pTmp->GetUpper() )
1633 	{
1634 		void* p = (void*)pTmp;
1635 		aEndArr.Insert( p, 0 );
1636 	}
1637 
1638 	for( sal_uInt16 n = 0; n < aEndArr.Count() && n < aSttArr.Count(); ++n )
1639 		if( aSttArr[ n ] != aEndArr[ n ] )
1640 		{
1641 			// first unequal line or box - all odds are
1642 			if( n & 1 )			        // 1, 3, 5, ... are boxes
1643 			{
1644 				rpStart = (SwLayoutFrm*)aSttArr[ n ];
1645 				rpEnd = (SwLayoutFrm*)aEndArr[ n ];
1646 			}
1647 			else								// 0, 2, 4, ... are lines
1648 			{
1649 				// check if start & end line are the first & last Line of the
1650 				// box. If not return these cells.
1651 				// Else the hole line with all Boxes has to be deleted.
1652 				rpStart = (SwLayoutFrm*)aSttArr[ n+1 ];
1653 				rpEnd = (SwLayoutFrm*)aEndArr[ n+1 ];
1654 				if( n )
1655 				{
1656 					const SwCellFrm* pCellFrm = (SwCellFrm*)aSttArr[ n-1 ];
1657 					const SwTableLines& rLns = pCellFrm->
1658 												GetTabBox()->GetTabLines();
1659 					if( rLns[ 0 ] == ((SwRowFrm*)aSttArr[ n ])->GetTabLine() &&
1660 						rLns[ rLns.Count() - 1 ] ==
1661 									((SwRowFrm*)aEndArr[ n ])->GetTabLine() )
1662 					{
1663 						rpStart = rpEnd = pCellFrm;
1664 						while ( rpStart->GetPrev() )
1665 							rpStart = (SwLayoutFrm*)rpStart->GetPrev();
1666 						while ( rpEnd->GetNext() )
1667 							rpEnd = (SwLayoutFrm*)rpEnd->GetNext();
1668 					}
1669 				}
1670 			}
1671 			break;
1672 		}
1673 
1674 	if( !bChkProtected )	// geschuetzte Zellen beachten ?
1675 		return;
1676 
1677 
1678 	//Anfang und Ende duerfen nicht auf geschuetzten Zellen liegen.
1679 	while ( rpStart->GetFmt()->GetProtect().IsCntntProtected() )
1680 		rpStart = (SwLayoutFrm*)rpStart->GetNext();
1681 	while ( rpEnd->GetFmt()->GetProtect().IsCntntProtected() )
1682 		rpEnd = (SwLayoutFrm*)rpEnd->GetPrev();
1683 }
1684 
1685 
1686 void lcl_FindStartEndCol( const SwLayoutFrm *&rpStart,
1687 							 const SwLayoutFrm *&rpEnd,
1688 							 const int bChkProtected )
1689 {
1690 	//Start und End senkrecht bis an den Rand der Tabelle denken; es muss
1691 	//die Gesamttabelle betrachtet werden, also inklusive Masters und
1692 	//Follows.
1693 	//Fuer den Start brauchen wir den Mutter-TabellenFrm.
1694     if( !rpStart )
1695         return;
1696 	const SwTabFrm *pOrg = rpStart->FindTabFrm();
1697 	const SwTabFrm *pTab = pOrg;
1698 
1699 	SWRECTFN( pTab )
1700 
1701     sal_Bool bRTL = pTab->IsRightToLeft();
1702     const long nTmpWish = pOrg->GetFmt()->GetFrmSize().GetWidth();
1703     const long nWish = ( nTmpWish > 0 ) ? nTmpWish : 1;
1704 
1705     while ( pTab->IsFollow() )
1706 	{
1707 		const SwFrm *pTmp = pTab->FindPrev();
1708 		ASSERT( pTmp->IsTabFrm(), "Vorgaenger vom Follow nicht der Master." );
1709 		pTab = (const SwTabFrm*)pTmp;
1710 	}
1711 
1712     SwTwips nSX  = 0;
1713     SwTwips nSX2 = 0;
1714 
1715     if ( pTab->GetTable()->IsNewModel() )
1716     {
1717         nSX  = (rpStart->Frm().*fnRect->fnGetLeft )();
1718         nSX2 = (rpStart->Frm().*fnRect->fnGetRight)();
1719     }
1720     else
1721     {
1722         const SwTwips nPrtWidth = (pTab->Prt().*fnRect->fnGetWidth)();
1723         nSX = ::lcl_CalcWish( rpStart, nWish, nPrtWidth ) + (pTab->*fnRect->fnGetPrtLeft)();
1724         nSX2 = nSX + (rpStart->GetFmt()->GetFrmSize().GetWidth() * nPrtWidth / nWish);
1725     }
1726 
1727 	const SwLayoutFrm *pTmp = pTab->FirstCell();
1728 
1729 	while ( pTmp &&
1730 			(!pTmp->IsCellFrm() ||
1731              ( ( ! bRTL && (pTmp->Frm().*fnRect->fnGetLeft)() < nSX &&
1732                            (pTmp->Frm().*fnRect->fnGetRight)()< nSX2 ) ||
1733                (   bRTL && (pTmp->Frm().*fnRect->fnGetLeft)() > nSX &&
1734                            (pTmp->Frm().*fnRect->fnGetRight)()> nSX2 ) ) ) )
1735         pTmp = pTmp->GetNextLayoutLeaf();
1736 
1737 	if ( pTmp )
1738 		rpStart = pTmp;
1739 
1740 	pTab = pOrg;
1741 
1742     const SwTabFrm* pLastValidTab = pTab;
1743 	while ( pTab->GetFollow() )
1744     {
1745         //
1746         // Check if pTab->GetFollow() is a valid follow table:
1747         // Only follow tables with at least on non-FollowFlowLine
1748         // should be considered.
1749         //
1750         if ( pTab->HasFollowFlowLine() )
1751         {
1752             pTab = pTab->GetFollow();
1753             const SwFrm* pTmpRow = pTab->GetFirstNonHeadlineRow();
1754             if ( pTmpRow && pTmpRow->GetNext() )
1755     		    pLastValidTab = pTab;
1756         }
1757         else
1758             pLastValidTab = pTab = pTab->GetFollow();
1759     }
1760     pTab = pLastValidTab;
1761 
1762     SwTwips nEX = 0;
1763 
1764     if ( pTab->GetTable()->IsNewModel() )
1765     {
1766         nEX = (rpEnd->Frm().*fnRect->fnGetLeft )();
1767     }
1768     else
1769     {
1770         const SwTwips nPrtWidth = (pTab->Prt().*fnRect->fnGetWidth)();
1771         nEX = ::lcl_CalcWish( rpEnd, nWish, nPrtWidth ) + (pTab->*fnRect->fnGetPrtLeft)();
1772     }
1773 
1774     const SwCntntFrm* pLastCntnt = pTab->FindLastCntnt();
1775     rpEnd = pLastCntnt ? pLastCntnt->GetUpper() : 0;
1776     // --> FME 2006-07-17 #134385# Made code robust. If pTab does not have a lower,
1777     // we would crash here.
1778     if ( !pLastCntnt ) return;
1779     // <--
1780 
1781 	while( !rpEnd->IsCellFrm() )
1782 		rpEnd = rpEnd->GetUpper();
1783 
1784     while ( (   bRTL && (rpEnd->Frm().*fnRect->fnGetLeft)() < nEX ) ||
1785             ( ! bRTL && (rpEnd->Frm().*fnRect->fnGetLeft)() > nEX ) )
1786     {
1787         const SwLayoutFrm* pTmpLeaf = rpEnd->GetPrevLayoutLeaf();
1788         if( !pTmpLeaf || !pTab->IsAnLower( pTmpLeaf ) )
1789             break;
1790         rpEnd = pTmpLeaf;
1791     }
1792 
1793 	if( !bChkProtected )	// geschuetzte Zellen beachten ?
1794 		return;
1795 
1796 	//Anfang und Ende duerfen nicht auf geschuetzten Zellen liegen.
1797 	//Also muss ggf. nocheinmal rueckwaerts gesucht werden.
1798 	while ( rpStart->GetFmt()->GetProtect().IsCntntProtected() )
1799 	{
1800         const SwLayoutFrm *pTmpLeaf = rpStart;
1801         pTmpLeaf = pTmpLeaf->GetNextLayoutLeaf();
1802         while ( pTmpLeaf && (pTmpLeaf->Frm().*fnRect->fnGetLeft)() > nEX )//erstmal die Zeile ueberspr.
1803             pTmpLeaf = pTmpLeaf->GetNextLayoutLeaf();
1804         while ( pTmpLeaf && (pTmpLeaf->Frm().*fnRect->fnGetLeft)() < nSX &&
1805                             (pTmpLeaf->Frm().*fnRect->fnGetRight)()< nSX2 )
1806             pTmpLeaf = pTmpLeaf->GetNextLayoutLeaf();
1807         const SwTabFrm *pTmpTab = rpStart->FindTabFrm();
1808         if ( !pTmpTab->IsAnLower( pTmpLeaf ) )
1809 		{
1810             pTmpTab = pTmpTab->GetFollow();
1811             rpStart = pTmpTab->FirstCell();
1812 			while ( (rpStart->Frm().*fnRect->fnGetLeft)() < nSX &&
1813 					(rpStart->Frm().*fnRect->fnGetRight)()< nSX2 )
1814 				rpStart = rpStart->GetNextLayoutLeaf();
1815 		}
1816 		else
1817             rpStart = pTmpLeaf;
1818 	}
1819 	while ( rpEnd->GetFmt()->GetProtect().IsCntntProtected() )
1820 	{
1821         const SwLayoutFrm *pTmpLeaf = rpEnd;
1822         pTmpLeaf = pTmpLeaf->GetPrevLayoutLeaf();
1823         while ( pTmpLeaf && (pTmpLeaf->Frm().*fnRect->fnGetLeft)() < nEX )//erstmal die Zeile ueberspr.
1824             pTmpLeaf = pTmpLeaf->GetPrevLayoutLeaf();
1825         while ( pTmpLeaf && (pTmpLeaf->Frm().*fnRect->fnGetLeft)() > nEX )
1826             pTmpLeaf = pTmpLeaf->GetPrevLayoutLeaf();
1827         const SwTabFrm *pTmpTab = rpEnd->FindTabFrm();
1828         if ( !pTmpLeaf || !pTmpTab->IsAnLower( pTmpLeaf ) )
1829 		{
1830             pTmpTab = (const SwTabFrm*)pTmpTab->FindPrev();
1831             ASSERT( pTmpTab->IsTabFrm(), "Vorgaenger vom Follow nicht der Master.");
1832             rpEnd = pTmpTab->FindLastCntnt()->GetUpper();
1833 			while( !rpEnd->IsCellFrm() )
1834 				rpEnd = rpEnd->GetUpper();
1835 			while ( (rpEnd->Frm().*fnRect->fnGetLeft)() > nEX )
1836 				rpEnd = rpEnd->GetPrevLayoutLeaf();
1837 		}
1838 		else
1839             rpEnd = pTmpLeaf;
1840 	}
1841 }
1842 
1843 
1844 void MakeSelUnions( SwSelUnions& rUnions, const SwLayoutFrm *pStart,
1845 					const SwLayoutFrm *pEnd, const SwTblSearchType eSearchType )
1846 {
1847     while ( pStart && !pStart->IsCellFrm() )
1848 		pStart = pStart->GetUpper();
1849     while ( pEnd && !pEnd->IsCellFrm() )
1850 		pEnd = pEnd->GetUpper();
1851 
1852     // #112697# Robust:
1853     if ( !pStart || !pEnd )
1854     {
1855         ASSERT( false, "MakeSelUnions with pStart or pEnd not in CellFrm" )
1856         return;
1857     }
1858 
1859 	const SwTabFrm *pTable = pStart->FindTabFrm();
1860 	const SwTabFrm *pEndTable = pEnd->FindTabFrm();
1861     if( !pTable || !pEndTable )
1862         return;
1863 	sal_Bool bExchange = sal_False;
1864 
1865 	if ( pTable != pEndTable )
1866 	{
1867 		if ( !pTable->IsAnFollow( pEndTable ) )
1868 		{
1869 			ASSERT( pEndTable->IsAnFollow( pTable ), "Tabkette verknotet." );
1870 			bExchange = sal_True;
1871 		}
1872 	}
1873     else
1874     {
1875         SWRECTFN( pTable )
1876         long nSttTop = (pStart->Frm().*fnRect->fnGetTop)();
1877         long nEndTop = (pEnd->Frm().*fnRect->fnGetTop)();
1878         if( nSttTop == nEndTop )
1879         {
1880             if( (pStart->Frm().*fnRect->fnGetLeft)() >
1881                 (pEnd->Frm().*fnRect->fnGetLeft)() )
1882                 bExchange = sal_True;
1883         }
1884         else if( bVert == ( nSttTop < nEndTop ) )
1885             bExchange = sal_True;
1886     }
1887 	if ( bExchange )
1888 	{
1889 		const SwLayoutFrm *pTmp = pStart;
1890 		pStart = pEnd;
1891 		pEnd = pTmp;
1892 		//pTable und pEndTable nicht umsortieren, werden unten neu gesetzt.
1893 		//MA: 28. Dec. 93 Bug: 5190
1894 	}
1895 
1896 	//Start und End sind jetzt huebsch sortiert, jetzt muessen sie falls
1897 	//erwuenscht noch versetzt werden.
1898 	if( nsSwTblSearchType::TBLSEARCH_ROW == ((~nsSwTblSearchType::TBLSEARCH_PROTECT ) & eSearchType ) )
1899 		::lcl_FindStartEndRow( pStart, pEnd, nsSwTblSearchType::TBLSEARCH_PROTECT & eSearchType );
1900 	else if( nsSwTblSearchType::TBLSEARCH_COL == ((~nsSwTblSearchType::TBLSEARCH_PROTECT ) & eSearchType ) )
1901 		::lcl_FindStartEndCol( pStart, pEnd, nsSwTblSearchType::TBLSEARCH_PROTECT & eSearchType );
1902 
1903     // --> FME 2006-07-17 #134385# Made code robust.
1904     if ( !pEnd ) return;
1905     // <--
1906 
1907 	//neu besorgen, da sie jetzt verschoben sind. MA: 28. Dec. 93 Bug 5190
1908 	pTable = pStart->FindTabFrm();
1909 	pEndTable = pEnd->FindTabFrm();
1910 
1911     const long nStSz = pStart->GetFmt()->GetFrmSize().GetWidth();
1912 	const long nEdSz = pEnd->GetFmt()->GetFrmSize().GetWidth();
1913 	const long nWish = Max( 1L, pTable->GetFmt()->GetFrmSize().GetWidth() );
1914 	while ( pTable )
1915 	{
1916         SWRECTFN( pTable )
1917         const long nOfst = (pTable->*fnRect->fnGetPrtLeft)();
1918         const long nPrtWidth = (pTable->Prt().*fnRect->fnGetWidth)();
1919         long nSt1 = ::lcl_CalcWish( pStart, nWish, nPrtWidth ) + nOfst;
1920         long nEd1 = ::lcl_CalcWish( pEnd,   nWish, nPrtWidth ) + nOfst;
1921 
1922         if ( nSt1 <= nEd1 )
1923             nEd1 += (long)((nEdSz * nPrtWidth) / nWish) - 1;
1924 		else
1925             nSt1 += (long)((nStSz * nPrtWidth) / nWish) - 1;
1926 
1927         long nSt2;
1928         long nEd2;
1929         if( pTable->IsAnLower( pStart ) )
1930             nSt2 = (pStart->Frm().*fnRect->fnGetTop)();
1931         else
1932             nSt2 = (pTable->Frm().*fnRect->fnGetTop)();
1933         if( pTable->IsAnLower( pEnd ) )
1934             nEd2 = (pEnd->Frm().*fnRect->fnGetBottom)();
1935         else
1936             nEd2 = (pTable->Frm().*fnRect->fnGetBottom)();
1937         Point aSt, aEd;
1938         if( nSt1 > nEd1 )
1939         {
1940             long nTmp = nSt1;
1941             nSt1 = nEd1;
1942             nEd1 = nTmp;
1943         }
1944         if( nSt2 > nEd2 )
1945         {
1946             long nTmp = nSt2;
1947             nSt2 = nEd2;
1948             nEd2 = nTmp;
1949         }
1950         if( bVert )
1951         {
1952             aSt = Point( nSt2, nSt1 );
1953             aEd = Point( nEd2, nEd1 );
1954         }
1955         else
1956         {
1957             aSt = Point( nSt1, nSt2 );
1958             aEd = Point( nEd1, nEd2 );
1959         }
1960 
1961         const Point aDiff( aEd - aSt );
1962 		SwRect aUnion( aSt, Size( aDiff.X(), aDiff.Y() ) );
1963 		aUnion.Justify();
1964 
1965 		// fuers
1966 		if( !(nsSwTblSearchType::TBLSEARCH_NO_UNION_CORRECT & eSearchType ))
1967 		{
1968 			//Leider ist die Union jetzt mit Rundungsfehlern behaftet und dadurch
1969 			//wuerden beim Split/Merge fehlertraechtige Umstaende entstehen.
1970 			//Um dies zu vermeiden werden jetzt fuer die Table die erste und
1971 			//letzte Zelle innerhalb der Union ermittelt und aus genau deren
1972 			//Werten wird die Union neu gebildet.
1973             const SwLayoutFrm* pRow = pTable->IsFollow() ?
1974                                       pTable->GetFirstNonHeadlineRow() :
1975                                       (const SwLayoutFrm*)pTable->Lower();
1976 
1977             while ( pRow && !pRow->Frm().IsOver( aUnion ) )
1978 				pRow = (SwLayoutFrm*)pRow->GetNext();
1979 
1980             // --> FME 2004-07-26 #i31976#
1981             // A follow flow row may contain emtpy cells. These are not
1982             // considered by FirstCell(). Therefore we have to find
1983             // the first cell manually:
1984             const SwFrm* pTmpCell = 0;
1985             if ( pTable->IsFollow() && pRow && pRow->IsInFollowFlowRow() )
1986             {
1987                 const SwFrm* pTmpRow = pRow;
1988                 while ( pTmpRow && pTmpRow->IsRowFrm() )
1989                 {
1990                     pTmpCell = static_cast<const SwRowFrm*>(pTmpRow)->Lower();
1991                     pTmpRow  = static_cast<const SwCellFrm*>(pTmpCell)->Lower();
1992                 }
1993                 ASSERT( !pTmpCell || pTmpCell->IsCellFrm(), "Lower of rowframe != cellframe?!" )
1994             }
1995             // <--
1996 
1997             const SwLayoutFrm* pFirst = pTmpCell ?
1998                                         static_cast<const SwLayoutFrm*>(pTmpCell) :
1999                                         pRow ?
2000                                         pRow->FirstCell() :
2001                                         0;
2002 
2003 			while ( pFirst && !::IsFrmInTblSel( aUnion, pFirst ) )
2004 			{
2005 				if ( pFirst->GetNext() )
2006 				{
2007 					pFirst = (const SwLayoutFrm*)pFirst->GetNext();
2008 					if ( pFirst->Lower() && pFirst->Lower()->IsRowFrm() )
2009 						pFirst = pFirst->FirstCell();
2010 				}
2011 				else
2012 					pFirst = ::lcl_FindNextCellFrm( pFirst );
2013 			}
2014             const SwLayoutFrm* pLast = 0;
2015             const SwFrm* pLastCntnt = pTable->FindLastCntnt();
2016             if ( pLastCntnt )
2017                 pLast = ::lcl_FindCellFrm( pLastCntnt->GetUpper() );
2018 
2019 			while ( pLast && !::IsFrmInTblSel( aUnion, pLast ) )
2020 				pLast = ::lcl_FindCellFrm( pLast->GetPrevLayoutLeaf() );
2021 
2022 			if ( pFirst && pLast ) //Robust
2023             {
2024                 aUnion = pFirst->Frm();
2025                 aUnion.Union( pLast->Frm() );
2026             }
2027             else
2028 				aUnion.Width( 0 );
2029 		}
2030 
2031 		if( (aUnion.*fnRect->fnGetWidth)() )
2032 		{
2033 			SwSelUnion *pTmp = new SwSelUnion( aUnion, (SwTabFrm*)pTable );
2034 			rUnions.C40_INSERT( SwSelUnion, pTmp, rUnions.Count() );
2035 		}
2036 
2037 		pTable = pTable->GetFollow();
2038 		if ( pTable != pEndTable && pEndTable->IsAnFollow( pTable ) )
2039 			pTable = 0;
2040 	}
2041 }
2042 
2043 sal_Bool CheckSplitCells( const SwCrsrShell& rShell, sal_uInt16 nDiv,
2044 						const SwTblSearchType eSearchType )
2045 {
2046 	if( !rShell.IsTableMode() )
2047 		rShell.GetCrsr();
2048 
2049     return CheckSplitCells( *rShell.getShellCrsr(false), nDiv, eSearchType );
2050 }
2051 
2052 sal_Bool CheckSplitCells( const SwCursor& rCrsr, sal_uInt16 nDiv,
2053 						const SwTblSearchType eSearchType )
2054 {
2055 	if( 1 >= nDiv )
2056 		return sal_False;
2057 
2058 	sal_uInt16 nMinValue = nDiv * MINLAY;
2059 
2060 	//Start- und Endzelle besorgen und den naechsten fragen.
2061 	Point aPtPos, aMkPos;
2062     const SwShellCrsr* pShCrsr = dynamic_cast<const SwShellCrsr*>(&rCrsr);
2063 	if( pShCrsr )
2064 	{
2065 		aPtPos = pShCrsr->GetPtPos();
2066 		aMkPos = pShCrsr->GetMkPos();
2067 	}
2068 
2069     const SwCntntNode* pCntNd = rCrsr.GetCntntNode();
2070 	const SwLayoutFrm *pStart = pCntNd->getLayoutFrm( pCntNd->GetDoc()->GetCurrentLayout(),
2071 														&aPtPos )->GetUpper();
2072     pCntNd = rCrsr.GetCntntNode(sal_False);
2073 	const SwLayoutFrm *pEnd = pCntNd->getLayoutFrm( pCntNd->GetDoc()->GetCurrentLayout(),
2074 								&aMkPos )->GetUpper();
2075 
2076     SWRECTFN( pStart->GetUpper() )
2077 
2078 	//Zuerst lassen wir uns die Tabellen und die Rechtecke heraussuchen.
2079 	SwSelUnions aUnions;
2080 
2081 	::MakeSelUnions( aUnions, pStart, pEnd, eSearchType );
2082 
2083     //Jetzt zu jedem Eintrag die Boxen herausfischen und uebertragen.
2084 	for ( sal_uInt16 i = 0; i < aUnions.Count(); ++i )
2085 	{
2086 		SwSelUnion *pUnion = aUnions[i];
2087 		const SwTabFrm *pTable = pUnion->GetTable();
2088 
2089         // Skip any repeated headlines in the follow:
2090         const SwLayoutFrm* pRow = pTable->IsFollow() ?
2091                                   pTable->GetFirstNonHeadlineRow() :
2092                                   (const SwLayoutFrm*)pTable->Lower();
2093 
2094 		while ( pRow )
2095 		{
2096 			if ( pRow->Frm().IsOver( pUnion->GetUnion() ) )
2097 			{
2098 				const SwLayoutFrm *pCell = pRow->FirstCell();
2099 
2100 				while ( pCell && pRow->IsAnLower( pCell ) )
2101 				{
2102 					ASSERT( pCell->IsCellFrm(), "Frame ohne Celle" );
2103 					if( ::IsFrmInTblSel( pUnion->GetUnion(), pCell ) )
2104 					{
2105                         if( (pCell->Frm().*fnRect->fnGetWidth)() < nMinValue )
2106 							return sal_False;
2107 					}
2108 
2109 					if ( pCell->GetNext() )
2110 					{
2111 						pCell = (const SwLayoutFrm*)pCell->GetNext();
2112 						if ( pCell->Lower() && pCell->Lower()->IsRowFrm() )
2113 							pCell = pCell->FirstCell();
2114 					}
2115 					else
2116 						pCell = ::lcl_FindNextCellFrm( pCell );
2117 				}
2118 			}
2119 			pRow = (const SwLayoutFrm*)pRow->GetNext();
2120 		}
2121 	}
2122 	return sal_True;
2123 }
2124 
2125 // -------------------------------------------------------------------
2126 // Diese Klassen kopieren die aktuelle Tabellen-Selektion (rBoxes)
2127 // unter Beibehaltung der Tabellen-Struktur in eine eigene Struktur
2128 // neu: SS zum gezielten Loeschen/Retaurieren des Layouts.
2129 
2130 void lcl_InsertRow( SwTableLine &rLine, SwLayoutFrm *pUpper, SwFrm *pSibling )
2131 {
2132 	SwRowFrm *pRow = new SwRowFrm( rLine, pUpper );
2133 	if ( pUpper->IsTabFrm() && ((SwTabFrm*)pUpper)->IsFollow() )
2134 	{
2135         SwTabFrm* pTabFrm = (SwTabFrm*)pUpper;
2136         pTabFrm->FindMaster()->InvalidatePos(); //kann die Zeile vielleicht aufnehmen
2137 
2138         if ( pSibling && pTabFrm->IsInHeadline( *pSibling ) )
2139 		{
2140             // Skip any repeated headlines in the follow:
2141             pSibling = pTabFrm->GetFirstNonHeadlineRow();
2142 		}
2143 	}
2144 	pRow->Paste( pUpper, pSibling );
2145 	pRow->RegistFlys();
2146 }
2147 
2148 
2149 sal_Bool _FndBoxCopyCol( const SwTableBox*& rpBox, void* pPara )
2150 {
2151 	_FndPara* pFndPara = (_FndPara*)pPara;
2152 	_FndBox* pFndBox = new _FndBox( (SwTableBox*)rpBox, pFndPara->pFndLine );
2153 	if( rpBox->GetTabLines().Count() )
2154 	{
2155 		_FndPara aPara( *pFndPara, pFndBox );
2156 		pFndBox->GetBox()->GetTabLines().ForEach( &_FndLineCopyCol, &aPara );
2157 		if( !pFndBox->GetLines().Count() )
2158 		{
2159 			delete pFndBox;
2160 			return sal_True;
2161 		}
2162 	}
2163 	else
2164 	{
2165 		SwTableBoxPtr pSrch = (SwTableBoxPtr)rpBox;
2166 		sal_uInt16 nFndPos;
2167 		if( !pFndPara->rBoxes.Seek_Entry( pSrch, &nFndPos ))
2168 		{
2169 			delete pFndBox;
2170 			return sal_True;
2171 		}
2172 	}
2173 	pFndPara->pFndLine->GetBoxes().C40_INSERT( _FndBox, pFndBox,
2174 					pFndPara->pFndLine->GetBoxes().Count() );
2175 	return sal_True;
2176 }
2177 
2178 sal_Bool _FndLineCopyCol( const SwTableLine*& rpLine, void* pPara )
2179 {
2180 	_FndPara* pFndPara = (_FndPara*)pPara;
2181 	_FndLine* pFndLine = new _FndLine( (SwTableLine*)rpLine, pFndPara->pFndBox );
2182 	_FndPara aPara( *pFndPara, pFndLine );
2183 	pFndLine->GetLine()->GetTabBoxes().ForEach( &_FndBoxCopyCol, &aPara );
2184 	if( pFndLine->GetBoxes().Count() )
2185 	{
2186 		pFndPara->pFndBox->GetLines().C40_INSERT( _FndLine, pFndLine,
2187 				pFndPara->pFndBox->GetLines().Count() );
2188 	}
2189 	else
2190 		delete pFndLine;
2191 	return sal_True;
2192 }
2193 
2194 void _FndBox::SetTableLines( const SwSelBoxes &rBoxes, const SwTable &rTable )
2195 {
2196 	//Pointer auf die Lines vor und hinter den zu verarbeitenden Bereich
2197 	//setzen. Wenn die erste/letzte Zeile in den Bereich eingeschlossen
2198 	//sind, so bleiben die Pointer eben einfach 0.
2199 	//Gesucht werden zunachst die Positionen der ersten/letzten betroffenen
2200 	//Line im Array der SwTable. Damit die 0 fuer 'keine Line' verwand werden
2201 	//kann werden die Positionen um 1 nach oben versetzt!
2202 
2203 	sal_uInt16 nStPos = USHRT_MAX;
2204 	sal_uInt16 nEndPos= 0;
2205 
2206 	for ( sal_uInt16 i = 0; i < rBoxes.Count(); ++i )
2207 	{
2208 		SwTableLine *pLine = rBoxes[i]->GetUpper();
2209 		while ( pLine->GetUpper() )
2210 			pLine = pLine->GetUpper()->GetUpper();
2211 		const sal_uInt16 nPos = rTable.GetTabLines().GetPos(
2212 					(const SwTableLine*&)pLine ) + 1;
2213 
2214 		ASSERT( nPos != USHRT_MAX, "TableLine not found." );
2215 
2216 		if( nStPos > nPos )
2217 			nStPos = nPos;
2218 
2219 		if( nEndPos < nPos )
2220 			nEndPos = nPos;
2221 	}
2222 	if ( nStPos > 1 )
2223 		pLineBefore = rTable.GetTabLines()[nStPos - 2];
2224 	if ( nEndPos < rTable.GetTabLines().Count() )
2225 		pLineBehind = rTable.GetTabLines()[nEndPos];
2226 }
2227 
2228 void _FndBox::SetTableLines( const SwTable &rTable )
2229 {
2230 	// Pointer auf die Lines vor und hinter den zu verarbeitenden Bereich
2231 	// setzen. Wenn die erste/letzte Zeile in den Bereich eingeschlossen
2232 	// sind, so bleiben die Pointer eben einfach 0.
2233 	// Die Positionen der ersten/letzten betroffenen Line im Array der
2234 	// SwTable steht in der FndBox. Damit die 0 fuer 'keine Line' verwand
2235 	// werdenkann werden die Positionen um 1 nach oben versetzt!
2236 
2237 	if( !GetLines().Count() )
2238 		return;
2239 
2240 	SwTableLine* pTmpLine = GetLines()[0]->GetLine();
2241 	sal_uInt16 nPos = rTable.GetTabLines().C40_GETPOS( SwTableLine, pTmpLine );
2242 	ASSERT( USHRT_MAX != nPos, "Line steht nicht in der Tabelle" );
2243 	if( nPos )
2244 		pLineBefore = rTable.GetTabLines()[ nPos - 1 ];
2245 
2246 	pTmpLine = GetLines()[GetLines().Count()-1]->GetLine();
2247 	nPos = rTable.GetTabLines().C40_GETPOS( SwTableLine, pTmpLine );
2248 	ASSERT( USHRT_MAX != nPos, "Line steht nicht in der Tabelle" );
2249 	if( ++nPos < rTable.GetTabLines().Count() )
2250 		pLineBehind = rTable.GetTabLines()[nPos];
2251 }
2252 
2253 inline void UnsetFollow( SwFlowFrm *pTab )
2254 {
2255 	pTab->bIsFollow = sal_False;
2256 }
2257 
2258 void _FndBox::DelFrms( SwTable &rTable )
2259 {
2260 	//Alle Lines zwischen pLineBefore und pLineBehind muessen aus dem
2261 	//Layout ausgeschnitten und geloescht werden.
2262 	//Entstehen dabei leere Follows so muessen diese vernichtet werden.
2263 	//Wird ein Master vernichtet, so muss der Follow Master werden.
2264 	//Ein TabFrm muss immer uebrigbleiben.
2265 
2266     sal_uInt16 nStPos = 0;
2267     sal_uInt16 nEndPos= rTable.GetTabLines().Count() - 1;
2268     if( rTable.IsNewModel() && pLineBefore )
2269         rTable.CheckRowSpan( pLineBefore, true );
2270 	if ( pLineBefore )
2271 	{
2272 		nStPos = rTable.GetTabLines().GetPos(
2273 						(const SwTableLine*&)pLineBefore );
2274 		ASSERT( nStPos != USHRT_MAX, "Fuchs Du hast die Line gestohlen!" );
2275 		++nStPos;
2276 	}
2277     if( rTable.IsNewModel() && pLineBehind )
2278         rTable.CheckRowSpan( pLineBehind, false );
2279 	if ( pLineBehind )
2280 	{
2281 		nEndPos = rTable.GetTabLines().GetPos(
2282 						(const SwTableLine*&)pLineBehind );
2283 		ASSERT( nEndPos != USHRT_MAX, "Fuchs Du hast die Line gestohlen!" );
2284 		--nEndPos;
2285 	}
2286 
2287     for ( sal_uInt16 i = nStPos; i <= nEndPos; ++i)
2288 	{
2289 		SwFrmFmt *pFmt = rTable.GetTabLines()[i]->GetFrmFmt();
2290 		SwIterator<SwRowFrm,SwFmt> aIter( *pFmt );
2291 		for ( SwRowFrm* pFrm = aIter.First(); pFrm; pFrm = aIter.Next() )
2292 		{
2293 				if ( pFrm->GetTabLine() == rTable.GetTabLines()[i] )
2294                 {
2295 					sal_Bool bDel = sal_True;
2296 					SwTabFrm *pUp = !pFrm->GetPrev() && !pFrm->GetNext() ?
2297 											(SwTabFrm*)pFrm->GetUpper() : 0;
2298                     if ( !pUp )
2299                     {
2300                         const sal_uInt16 nRepeat =
2301                                 ((SwTabFrm*)pFrm->GetUpper())->GetTable()->GetRowsToRepeat();
2302                         if ( nRepeat > 0 &&
2303                              ((SwTabFrm*)pFrm->GetUpper())->IsFollow() )
2304                         {
2305                             if ( !pFrm->GetNext() )
2306                             {
2307                                 SwRowFrm* pFirstNonHeadline =
2308                                     ((SwTabFrm*)pFrm->GetUpper())->GetFirstNonHeadlineRow();
2309                                 if ( pFirstNonHeadline == pFrm )
2310                                 {
2311                                     pUp = (SwTabFrm*)pFrm->GetUpper();
2312                                 }
2313                             }
2314                         }
2315                     }
2316                     if ( pUp )
2317 					{
2318 						SwTabFrm *pFollow = pUp->GetFollow();
2319 						SwTabFrm *pPrev   = pUp->IsFollow() ? pUp : 0;
2320 						if ( pPrev )
2321 						{
2322 							SwFrm *pTmp = pPrev->FindPrev();
2323 							ASSERT( pTmp->IsTabFrm(),
2324 									"Vorgaenger vom Follow kein Master.");
2325 							pPrev = (SwTabFrm*)pTmp;
2326 						}
2327 						if ( pPrev )
2328                         {
2329 							pPrev->SetFollow( pFollow );
2330                             // --> FME 2006-01-31 #i60340# Do not transfer the
2331                             // flag from pUp to pPrev. pUp may still have the
2332                             // flag set although there is not more follow flow
2333                             // line associated with pUp.
2334                             pPrev->SetFollowFlowLine( sal_False );
2335                             // <--
2336                         }
2337 						else if ( pFollow )
2338 							::UnsetFollow( pFollow );
2339 
2340 						//Ein TabellenFrm muss immer stehenbleiben!
2341 						if ( pPrev || pFollow )
2342 						{
2343                             // OD 26.08.2003 #i18103# - if table is in a section,
2344                             // lock the section, to avoid its delete.
2345                             {
2346                                 SwSectionFrm* pSctFrm = pUp->FindSctFrm();
2347                                 bool bOldSectLock = false;
2348                                 if ( pSctFrm )
2349                                 {
2350                                     bOldSectLock = pSctFrm->IsColLocked();
2351                                     pSctFrm->ColLock();
2352                                 }
2353                                 pUp->Cut();
2354                                 if ( pSctFrm && !bOldSectLock )
2355                                 {
2356                                     pSctFrm->ColUnlock();
2357                                 }
2358                             }
2359 							delete pUp;
2360 							bDel = sal_False;//Die Row wird mit in den Abgrund
2361 										 //gerissen.
2362 						}
2363 					}
2364 					if ( bDel )
2365 					{
2366                         SwFrm* pTabFrm = pFrm->GetUpper();
2367                         if ( pTabFrm->IsTabFrm() &&
2368                             !pFrm->GetNext() &&
2369                              ((SwTabFrm*)pTabFrm)->GetFollow() )
2370                         {
2371                             // We do not delete the follow flow line,
2372                             // this will be done automatically in the
2373                             // next turn.
2374                             ((SwTabFrm*)pTabFrm)->SetFollowFlowLine( sal_False );
2375                         }
2376 
2377                         pFrm->Cut();
2378 						delete pFrm;
2379 					}
2380 				}
2381 		}
2382 	}
2383 }
2384 
2385 sal_Bool lcl_IsLineOfTblFrm( const SwTabFrm& rTable, const SwFrm& rChk )
2386 {
2387 	const SwTabFrm* pTblFrm = rChk.FindTabFrm();
2388     if( pTblFrm->IsFollow() )
2389         pTblFrm = pTblFrm->FindMaster( true );
2390     return &rTable == pTblFrm;
2391 }
2392 
2393 /*
2394  * lcl_UpdateRepeatedHeadlines
2395  */
2396 void lcl_UpdateRepeatedHeadlines( SwTabFrm& rTabFrm, bool bCalcLowers )
2397 {
2398     ASSERT( rTabFrm.IsFollow(), "lcl_UpdateRepeatedHeadlines called for non-follow tab" )
2399 
2400     // Delete remaining headlines:
2401     SwRowFrm* pLower = 0;
2402     while ( 0 != ( pLower = (SwRowFrm*)rTabFrm.Lower() ) && pLower->IsRepeatedHeadline() )
2403     {
2404         pLower->Cut();
2405         delete pLower;
2406     }
2407 
2408     // Insert fresh set of headlines:
2409     pLower = (SwRowFrm*)rTabFrm.Lower();
2410     SwTable& rTable = *rTabFrm.GetTable();
2411     const sal_uInt16 nRepeat = rTable.GetRowsToRepeat();
2412     for ( sal_uInt16 nIdx = 0; nIdx < nRepeat; ++nIdx )
2413     {
2414         SwRowFrm* pHeadline = new SwRowFrm( *rTable.GetTabLines()[ nIdx ], &rTabFrm );
2415         pHeadline->SetRepeatedHeadline( true );
2416         pHeadline->Paste( &rTabFrm, pLower );
2417         pHeadline->RegistFlys();
2418     }
2419 
2420     if ( bCalcLowers )
2421         rTabFrm.SetCalcLowers();
2422 }
2423 
2424 void _FndBox::MakeFrms( SwTable &rTable )
2425 {
2426 	//Alle Lines zwischen pLineBefore und pLineBehind muessen im Layout
2427 	//wieder neu erzeugt werden.
2428 	//Und Zwar fuer alle Auspraegungen der Tabelle (mehrere z.B. im Kopf/Fuss).
2429 
2430 	sal_uInt16 nStPos = 0;
2431 	sal_uInt16 nEndPos= rTable.GetTabLines().Count() - 1;
2432 	if ( pLineBefore )
2433 	{
2434 		nStPos = rTable.GetTabLines().GetPos(
2435 						(const SwTableLine*&)pLineBefore );
2436 		ASSERT( nStPos != USHRT_MAX, "Fuchs Du hast die Line gestohlen!" );
2437 		++nStPos;
2438 
2439 	}
2440 	if ( pLineBehind )
2441 	{
2442 		nEndPos = rTable.GetTabLines().GetPos(
2443 						(const SwTableLine*&)pLineBehind );
2444 		ASSERT( nEndPos != USHRT_MAX, "Fuchs Du hast die Line gestohlen!" );
2445 		--nEndPos;
2446 	}
2447 	//Jetzt die grosse Einfuegeoperation fuer alle Tabllen.
2448 	SwIterator<SwTabFrm,SwFmt> aTabIter( *rTable.GetFrmFmt() );
2449 	for ( SwTabFrm *pTable = aTabIter.First(); pTable; pTable = aTabIter.Next() )
2450 	{
2451 		if ( !pTable->IsFollow() )
2452 		{
2453 			SwRowFrm  *pSibling = 0;
2454             SwFrm  *pUpperFrm  = 0;
2455 			int i;
2456 			for ( i = rTable.GetTabLines().Count()-1;
2457 					i >= 0 && !pSibling; --i )
2458 			{
2459 				SwTableLine *pLine = pLineBehind ? pLineBehind :
2460 													rTable.GetTabLines()[static_cast<sal_uInt16>(i)];
2461 				SwIterator<SwRowFrm,SwFmt> aIter( *pLine->GetFrmFmt() );
2462                 pSibling = aIter.First();
2463                 while ( pSibling && (
2464                             pSibling->GetTabLine() != pLine ||
2465                             !lcl_IsLineOfTblFrm( *pTable, *pSibling ) ||
2466                             pSibling->IsRepeatedHeadline() ||
2467                             // --> FME 2005-08-24 #i53647# If !pLineBehind,
2468                             // IsInSplitTableRow() should be checked.
2469                             ( pLineBehind && pSibling->IsInFollowFlowRow() ) ||
2470                             (!pLineBehind && pSibling->IsInSplitTableRow() ) ) )
2471                             // <--
2472                 {
2473                     pSibling = aIter.Next();
2474                 }
2475             }
2476 			if ( pSibling )
2477 			{
2478                 pUpperFrm = pSibling->GetUpper();
2479 				if ( !pLineBehind )
2480 					pSibling = 0;
2481 			}
2482 			else
2483 // ???? oder das der Letzte Follow der Tabelle ????
2484                 pUpperFrm = pTable;
2485 
2486 			for ( i = nStPos; (sal_uInt16)i <= nEndPos; ++i )
2487 				::lcl_InsertRow( *rTable.GetTabLines()[static_cast<sal_uInt16>(i)],
2488                                 (SwLayoutFrm*)pUpperFrm, pSibling );
2489             if ( pUpperFrm->IsTabFrm() )
2490                 ((SwTabFrm*)pUpperFrm)->SetCalcLowers();
2491 		}
2492         else if ( rTable.GetRowsToRepeat() > 0 )
2493 		{
2494             // Insert new headlines:
2495             lcl_UpdateRepeatedHeadlines( *pTable, true );
2496         }
2497 	}
2498 }
2499 
2500 void _FndBox::MakeNewFrms( SwTable &rTable, const sal_uInt16 nNumber,
2501 											const sal_Bool bBehind )
2502 {
2503 	//Frms fuer neu eingefuege Zeilen erzeugen.
2504 	//bBehind == sal_True:	vor		pLineBehind
2505 	//		  == sal_False: hinter	pLineBefore
2506 	const sal_uInt16 nBfPos = pLineBefore ?
2507 		rTable.GetTabLines().GetPos( (const SwTableLine*&)pLineBefore ) :
2508 		USHRT_MAX;
2509 	const sal_uInt16 nBhPos = pLineBehind ?
2510 		rTable.GetTabLines().GetPos( (const SwTableLine*&)pLineBehind ) :
2511 		USHRT_MAX;
2512 
2513 	//nNumber: wie oft ist eingefuegt worden.
2514 	//nCnt:	   wieviele sind nNumber mal eingefuegt worden.
2515 
2516 	const sal_uInt16 nCnt =
2517 		((nBhPos != USHRT_MAX ? nBhPos : rTable.GetTabLines().Count()) -
2518 		 (nBfPos != USHRT_MAX ? nBfPos + 1 : 0)) / (nNumber + 1);
2519 
2520 	//Den Master-TabFrm suchen
2521 	SwIterator<SwTabFrm,SwFmt> aTabIter( *rTable.GetFrmFmt() );
2522 	SwTabFrm *pTable;
2523 	for ( pTable = aTabIter.First(); pTable; pTable = aTabIter.Next() )
2524     {
2525 		if( !pTable->IsFollow() )
2526 		{
2527 			SwRowFrm* pSibling = 0;
2528             SwLayoutFrm *pUpperFrm   = 0;
2529 			if ( bBehind )
2530 			{
2531 				if ( pLineBehind )
2532 				{
2533 					SwIterator<SwRowFrm,SwFmt> aIter( *pLineBehind->GetFrmFmt() );
2534                     pSibling = aIter.First();
2535                     while ( pSibling && (
2536                                 // only consider row frames associated with pLineBehind:
2537                                 pSibling->GetTabLine() != pLineBehind ||
2538                                 // only consider row frames that are in pTables Master-Follow chain:
2539                                 !lcl_IsLineOfTblFrm( *pTable, *pSibling ) ||
2540                                 // only consider row frames that are not repeated headlines:
2541                                 pSibling->IsRepeatedHeadline() ||
2542                                 // only consider row frames that are not follow flow rows
2543                                 pSibling->IsInFollowFlowRow() ) )
2544                     {
2545                           pSibling = aIter.Next();
2546                     }
2547 				}
2548 				if ( pSibling )
2549                     pUpperFrm = pSibling->GetUpper();
2550 				else
2551 				{
2552 					while( pTable->GetFollow() )
2553 						pTable = pTable->GetFollow();
2554                     pUpperFrm = pTable;
2555 				}
2556 				const sal_uInt16 nMax = nBhPos != USHRT_MAX ?
2557 									nBhPos : rTable.GetTabLines().Count();
2558 
2559 				sal_uInt16 i = nBfPos != USHRT_MAX ? nBfPos + 1 + nCnt : nCnt;
2560 
2561 				for ( ; i < nMax; ++i )
2562                     ::lcl_InsertRow( *rTable.GetTabLines()[i], pUpperFrm, pSibling );
2563                 if ( pUpperFrm->IsTabFrm() )
2564                     ((SwTabFrm*)pUpperFrm)->SetCalcLowers();
2565 			}
2566             else //davor einfuegen
2567             {
2568                 sal_uInt16 i;
2569 
2570                 // We are looking for the frame that is behind the row frame
2571                 // that should be inserted.
2572                 for ( i = 0; !pSibling; ++i )
2573                 {
2574                     SwTableLine* pLine = pLineBefore ? pLineBefore : rTable.GetTabLines()[i];
2575 
2576                     SwIterator<SwRowFrm,SwFmt> aIter( *pLine->GetFrmFmt() );
2577                     pSibling = aIter.First();
2578 
2579                     while ( pSibling && (
2580                             // only consider row frames associated with pLineBefore:
2581                             pSibling->GetTabLine() != pLine ||
2582                             // only consider row frames that are in pTables Master-Follow chain:
2583                             !lcl_IsLineOfTblFrm( *pTable, *pSibling ) ||
2584                             // only consider row frames that are not repeated headlines:
2585                             pSibling->IsRepeatedHeadline() ||
2586                             // 1. case: pLineBefore == 0:
2587                             // only consider row frames that are not follow flow rows
2588                             // 2. case: pLineBefore != 0:
2589                             // only consider row frames that are not split table rows
2590                             // --> FME 2004-11-23 #i37476# If !pLineBefore,
2591                             // check IsInFollowFlowRow instead of IsInSplitTableRow.
2592                             ( ( !pLineBefore && pSibling->IsInFollowFlowRow() ) ||
2593                               (  pLineBefore && pSibling->IsInSplitTableRow() ) ) ) )
2594                             // <--
2595                     {
2596                         pSibling = aIter.Next();
2597                     }
2598                 }
2599 
2600                 pUpperFrm = pSibling->GetUpper();
2601                 if ( pLineBefore )
2602                     pSibling = (SwRowFrm*) pSibling->GetNext();
2603 
2604                 sal_uInt16 nMax = nBhPos != USHRT_MAX ?
2605                                     nBhPos - nCnt :
2606                                     rTable.GetTabLines().Count() - nCnt;
2607 
2608                 i = nBfPos != USHRT_MAX ? nBfPos + 1 : 0;
2609                 for ( ; i < nMax; ++i )
2610                     ::lcl_InsertRow( *rTable.GetTabLines()[i],
2611                                 pUpperFrm, pSibling );
2612                 if ( pUpperFrm->IsTabFrm() )
2613                     ((SwTabFrm*)pUpperFrm)->SetCalcLowers();
2614             }
2615         }
2616     }
2617 
2618 	//Die Headlines mussen ggf. auch verarbeitet werden. Um gut arbeitenden
2619 	//Code nicht zu zerfasern wird hier nochmals iteriert.
2620     const sal_uInt16 nRowsToRepeat = rTable.GetRowsToRepeat();
2621     if ( nRowsToRepeat > 0 &&
2622          ( ( !bBehind && ( nBfPos == USHRT_MAX || nBfPos + 1 < nRowsToRepeat ) ) ||
2623            (  bBehind && ( ( nBfPos == USHRT_MAX && nRowsToRepeat > 1 ) || nBfPos + 2 < nRowsToRepeat ) ) ) )
2624 	{
2625         for ( pTable = aTabIter.First(); pTable; pTable = aTabIter.Next() )
2626         {
2627             if ( pTable->Lower() )
2628             {
2629                 if ( pTable->IsFollow() )
2630                 {
2631                     lcl_UpdateRepeatedHeadlines( *pTable, true );
2632                 }
2633 
2634                 ASSERT( ((SwRowFrm*)pTable->Lower())->GetTabLine() ==
2635                         rTable.GetTabLines()[0], "MakeNewFrms: Table corruption!" )
2636             }
2637         }
2638 	}
2639 }
2640 
2641 sal_Bool _FndBox::AreLinesToRestore( const SwTable &rTable ) const
2642 {
2643 	//Lohnt es sich MakeFrms zu rufen?
2644 
2645 	if ( !pLineBefore && !pLineBehind && rTable.GetTabLines().Count() )
2646 		return sal_True;
2647 
2648 	sal_uInt16 nBfPos;
2649 	if(pLineBefore)
2650 	{
2651 		const SwTableLine* rLBefore = (const SwTableLine*)pLineBefore;
2652 		nBfPos = rTable.GetTabLines().GetPos( rLBefore );
2653 	}
2654 	else
2655 		nBfPos = USHRT_MAX;
2656 
2657 	sal_uInt16 nBhPos;
2658 	if(pLineBehind)
2659 	{
2660 		const SwTableLine* rLBehind = (const SwTableLine*)pLineBehind;
2661 		nBhPos = rTable.GetTabLines().GetPos( rLBehind );
2662 	}
2663 	else
2664 		nBhPos = USHRT_MAX;
2665 
2666 	if ( nBfPos == nBhPos )	//Duerfte eigentlich nie vorkommen.
2667 	{
2668 		ASSERT( sal_False, "Table, Loeschen auf keinem Bereich !?!" );
2669 		return sal_False;
2670 	}
2671 
2672     if ( rTable.GetRowsToRepeat() > 0 )
2673 	{
2674 		// ups. sollte unsere zu wiederholende Kopfzeile geloescht worden
2675 		// sein??
2676         SwIterator<SwTabFrm,SwFmt> aIter( *rTable.GetFrmFmt() );
2677         for( SwTabFrm* pTable = aIter.First(); pTable; pTable = aIter.Next() )
2678         {
2679             if( pTable->IsFollow() )
2680             {
2681                 // Insert new headlines:
2682                 lcl_UpdateRepeatedHeadlines( *pTable, false );
2683             }
2684         }
2685 	}
2686 
2687     // Some adjacent lines at the beginning of the table have been deleted:
2688     if ( nBfPos == USHRT_MAX && nBhPos == 0 )
2689 		return sal_False;
2690 
2691     // Some adjacent lines at the end of the table have been deleted:
2692     if ( nBhPos == USHRT_MAX && nBfPos == (rTable.GetTabLines().Count() - 1) )
2693 		return sal_False;
2694 
2695     // Some adjacent lines in the middle of the table have been deleted:
2696 	if ( nBfPos != USHRT_MAX && nBhPos != USHRT_MAX && (nBfPos + 1) == nBhPos )
2697 		return sal_False;
2698 
2699     // The structure of the deleted lines is more complex due to split lines.
2700     // A call of MakeFrms() is necessary.
2701 	return sal_True;
2702 }
2703 
2704 
2705