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