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