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