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