Update ooo320-m1
[ooovba.git] / sw / source / core / frmedt / tblsel.cxx
blob26eed5bdf86303bac80da98f1d05e1b98bbb591f
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: tblsel.cxx,v $
10 * $Revision: 1.52 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
33 #include <hintids.hxx>
34 #include <svx/boxitem.hxx>
35 #include <svx/protitem.hxx>
36 #include <fmtanchr.hxx>
37 #include <fmtfsize.hxx>
38 #include <frmatr.hxx>
39 #include <tblsel.hxx>
40 #include <crsrsh.hxx>
41 #include <doc.hxx>
42 #include <docary.hxx>
43 #include <pam.hxx>
44 #include <ndtxt.hxx>
45 #include <ndole.hxx>
46 #include <swtable.hxx>
47 #include <cntfrm.hxx>
48 #include <tabfrm.hxx>
49 #include <rowfrm.hxx>
50 #include <cellfrm.hxx>
51 #include <pagefrm.hxx>
52 #include <rootfrm.hxx>
53 #include <viscrs.hxx>
54 #include <swtblfmt.hxx>
55 #include <undobj.hxx>
56 #include <mvsave.hxx>
57 // OD 26.08.2003 #i18103#
58 #include <sectfrm.hxx>
59 #include <frmtool.hxx>
61 //siehe auch swtable.cxx
62 #define COLFUZZY 20L
64 // defines, die bestimmen, wie Tabellen Boxen gemergt werden:
65 // - 1. alle leeren Zeilen entfernen, alle Boxen werden mit Blank,
66 // alle Lines mit ParaBreak getrennt
67 // - 2. alle leeren Zeilen und alle leeren Boxen am Anfang und Ende
68 // entfernen, alle Boxen werden mit Blank,
69 // alle Lines mit ParaBreak getrennt
70 // - 3. alle leeren Boxen entfernen, alle Boxen werden mit Blank,
71 // alle Lines mit ParaBreak getrennt
73 #undef DEL_ONLY_EMPTY_LINES
74 #undef DEL_EMPTY_BOXES_AT_START_AND_END
75 #define DEL_ALL_EMPTY_BOXES
78 _SV_IMPL_SORTAR_ALG( SwSelBoxes, SwTableBoxPtr )
79 BOOL SwSelBoxes::Seek_Entry( const SwTableBoxPtr rSrch, USHORT* pFndPos ) const
81 ULONG nIdx = rSrch->GetSttIdx();
83 USHORT nO = Count(), nM, nU = 0;
84 if( nO > 0 )
86 nO--;
87 while( nU <= nO )
89 nM = nU + ( nO - nU ) / 2;
90 if( (*this)[ nM ]->GetSttNd() == rSrch->GetSttNd() )
92 if( pFndPos )
93 *pFndPos = nM;
94 return TRUE;
96 else if( (*this)[ nM ]->GetSttIdx() < nIdx )
97 nU = nM + 1;
98 else if( nM == 0 )
100 if( pFndPos )
101 *pFndPos = nU;
102 return FALSE;
104 else
105 nO = nM - 1;
108 if( pFndPos )
109 *pFndPos = nU;
110 return FALSE;
114 SV_IMPL_PTRARR( SwCellFrms, SwCellFrm* )
116 struct _CmpLPt
118 Point aPos;
119 const SwTableBox* pSelBox;
120 BOOL bVert;
122 _CmpLPt( const Point& rPt, const SwTableBox* pBox, BOOL bVertical );
124 BOOL operator==( const _CmpLPt& rCmp ) const
125 { return X() == rCmp.X() && Y() == rCmp.Y() ? TRUE : FALSE; }
127 BOOL operator<( const _CmpLPt& rCmp ) const
129 if ( bVert )
130 return X() > rCmp.X() || ( X() == rCmp.X() && Y() < rCmp.Y() )
131 ? TRUE : FALSE;
132 else
133 return Y() < rCmp.Y() || ( Y() == rCmp.Y() && X() < rCmp.X() )
134 ? TRUE : FALSE;
137 long X() const { return aPos.X(); }
138 long Y() const { return aPos.Y(); }
142 SV_DECL_VARARR_SORT( _MergePos, _CmpLPt, 0, 40 )
143 SV_IMPL_VARARR_SORT( _MergePos, _CmpLPt )
145 SV_IMPL_PTRARR( _FndBoxes, _FndBox* )
146 SV_IMPL_PTRARR( _FndLines, _FndLine* )
149 struct _Sort_CellFrm
151 const SwCellFrm* pFrm;
153 _Sort_CellFrm( const SwCellFrm& rCFrm )
154 : pFrm( &rCFrm ) {}
157 SV_DECL_VARARR( _Sort_CellFrms, _Sort_CellFrm, 16, 16 )
158 SV_IMPL_VARARR( _Sort_CellFrms, _Sort_CellFrm )
160 SV_IMPL_PTRARR( SwChartBoxes, SwTableBoxPtr );
161 SV_IMPL_PTRARR( SwChartLines, SwChartBoxes* );
163 const SwLayoutFrm *lcl_FindCellFrm( const SwLayoutFrm *pLay )
165 while ( pLay && !pLay->IsCellFrm() )
166 pLay = pLay->GetUpper();
167 return pLay;
170 const SwLayoutFrm *lcl_FindNextCellFrm( const SwLayoutFrm *pLay )
172 //Dafuer sorgen, dass die Zelle auch verlassen wird (Bereiche)
173 const SwLayoutFrm *pTmp = pLay;
174 do {
175 pTmp = pTmp->GetNextLayoutLeaf();
176 } while( pLay->IsAnLower( pTmp ) );
178 while( pTmp && !pTmp->IsCellFrm() )
179 pTmp = pTmp->GetUpper();
180 return pTmp;
183 void GetTblSelCrs( const SwCrsrShell &rShell, SwSelBoxes& rBoxes )
185 if( rBoxes.Count() )
186 rBoxes.Remove( USHORT(0), rBoxes.Count() );
187 if( rShell.IsTableMode() && ((SwCrsrShell&)rShell).UpdateTblSelBoxes())
188 rBoxes.Insert( &rShell.GetTableCrsr()->GetBoxes() );
191 void GetTblSelCrs( const SwTableCursor& rTblCrsr, SwSelBoxes& rBoxes )
193 if( rBoxes.Count() )
194 rBoxes.Remove( USHORT(0), rBoxes.Count() );
196 if( rTblCrsr.IsChgd() || !rTblCrsr.GetBoxesCount() )
198 SwTableCursor* pTCrsr = (SwTableCursor*)&rTblCrsr;
199 pTCrsr->GetDoc()->GetRootFrm()->MakeTblCrsrs( *pTCrsr );
202 if( rTblCrsr.GetBoxesCount() )
203 rBoxes.Insert( &rTblCrsr.GetBoxes() );
206 void GetTblSel( const SwCrsrShell& rShell, SwSelBoxes& rBoxes,
207 const SwTblSearchType eSearchType )
209 //Start- und Endzelle besorgen und den naechsten fragen.
210 if ( !rShell.IsTableMode() )
211 rShell.GetCrsr();
213 GetTblSel( *rShell.getShellCrsr(false), rBoxes, eSearchType );
216 void GetTblSel( const SwCursor& rCrsr, SwSelBoxes& rBoxes,
217 const SwTblSearchType eSearchType )
219 //Start- und Endzelle besorgen und den naechsten fragen.
220 ASSERT( rCrsr.GetCntntNode() && rCrsr.GetCntntNode( FALSE ),
221 "Tabselection nicht auf Cnt." );
223 // Zeilen-Selektion:
224 // teste ob Tabelle komplex ist. Wenn ja, dann immer uebers Layout
225 // die selektierten Boxen zusammen suchen. Andernfalls ueber die
226 // Tabellen-Struktur (fuer Makros !!)
227 const SwCntntNode* pContentNd = rCrsr.GetNode()->GetCntntNode();
228 const SwTableNode* pTblNd = pContentNd ? pContentNd->FindTableNode() : 0;
229 if( pTblNd && pTblNd->GetTable().IsNewModel() )
231 SwTable::SearchType eSearch;
232 switch( nsSwTblSearchType::TBLSEARCH_COL & eSearchType )
234 case nsSwTblSearchType::TBLSEARCH_ROW: eSearch = SwTable::SEARCH_ROW; break;
235 case nsSwTblSearchType::TBLSEARCH_COL: eSearch = SwTable::SEARCH_COL; break;
236 default: eSearch = SwTable::SEARCH_NONE; break;
238 const bool bChkP = 0 != ( nsSwTblSearchType::TBLSEARCH_PROTECT & eSearchType );
239 pTblNd->GetTable().CreateSelection( rCrsr, rBoxes, eSearch, bChkP );
240 return;
242 if( nsSwTblSearchType::TBLSEARCH_ROW == ((~nsSwTblSearchType::TBLSEARCH_PROTECT ) & eSearchType ) &&
243 pTblNd && !pTblNd->GetTable().IsTblComplex() )
245 const SwTable& rTbl = pTblNd->GetTable();
246 const SwTableLines& rLines = rTbl.GetTabLines();
248 const SwNode* pMarkNode = rCrsr.GetNode( FALSE );
249 const ULONG nMarkSectionStart = pMarkNode->StartOfSectionIndex();
250 const SwTableBox* pMarkBox = rTbl.GetTblBox( nMarkSectionStart );
252 ASSERT( pMarkBox, "Point in table, mark outside?" )
254 const SwTableLine* pLine = pMarkBox ? pMarkBox->GetUpper() : 0;
255 USHORT nSttPos = rLines.GetPos( pLine );
256 ASSERT( USHRT_MAX != nSttPos, "Wo ist meine Zeile in der Tabelle?" );
257 pLine = rTbl.GetTblBox( rCrsr.GetNode( TRUE )->StartOfSectionIndex() )->GetUpper();
258 USHORT nEndPos = rLines.GetPos( pLine );
259 ASSERT( USHRT_MAX != nEndPos, "Wo ist meine Zeile in der Tabelle?" );
260 // pb: #i20193# if tableintable then nSttPos == nEndPos == USHRT_MAX
261 if ( nSttPos != USHRT_MAX && nEndPos != USHRT_MAX )
263 if( nEndPos < nSttPos ) // vertauschen
265 USHORT nTmp = nSttPos; nSttPos = nEndPos; nEndPos = nTmp;
268 int bChkProtected = nsSwTblSearchType::TBLSEARCH_PROTECT & eSearchType;
269 for( ; nSttPos <= nEndPos; ++nSttPos )
271 pLine = rLines[ nSttPos ];
272 for( USHORT n = pLine->GetTabBoxes().Count(); n ; )
274 SwTableBox* pBox = pLine->GetTabBoxes()[ --n ];
275 // Zellenschutzt beachten ??
276 if( !bChkProtected ||
277 !pBox->GetFrmFmt()->GetProtect().IsCntntProtected() )
278 rBoxes.Insert( pBox );
283 else
285 Point aPtPos, aMkPos;
286 const SwShellCrsr* pShCrsr = dynamic_cast<const SwShellCrsr*>(&rCrsr);
287 if( pShCrsr )
289 aPtPos = pShCrsr->GetPtPos();
290 aMkPos = pShCrsr->GetMkPos();
292 const SwCntntNode *pCntNd = rCrsr.GetCntntNode();
293 const SwLayoutFrm *pStart = pCntNd ?
294 pCntNd->GetFrm( &aPtPos )->GetUpper() : 0;
295 pCntNd = rCrsr.GetCntntNode(FALSE);
296 const SwLayoutFrm *pEnd = pCntNd ?
297 pCntNd->GetFrm( &aMkPos )->GetUpper() : 0;
298 if( pStart && pEnd )
299 GetTblSel( pStart, pEnd, rBoxes, 0, eSearchType );
303 void GetTblSel( const SwLayoutFrm* pStart, const SwLayoutFrm* pEnd,
304 SwSelBoxes& rBoxes, SwCellFrms* pCells,
305 const SwTblSearchType eSearchType )
307 // #112697# Robust:
308 const SwTabFrm* pStartTab = pStart->FindTabFrm();
309 if ( !pStartTab )
311 ASSERT( false, "GetTblSel without start table" )
312 return;
315 int bChkProtected = nsSwTblSearchType::TBLSEARCH_PROTECT & eSearchType;
317 BOOL bTblIsValid;
318 // --> FME 2006-01-25 #i55421# Reduced value 10
319 int nLoopMax = 10; //JP 28.06.99: max 100 loops - Bug 67292
320 // <--
321 USHORT i;
323 do {
324 bTblIsValid = TRUE;
326 //Zuerst lassen wir uns die Tabellen und die Rechtecke heraussuchen.
327 SwSelUnions aUnions;
328 ::MakeSelUnions( aUnions, pStart, pEnd, eSearchType );
330 Point aCurrentTopLeft( LONG_MAX, LONG_MAX );
331 Point aCurrentTopRight( 0, LONG_MAX );
332 Point aCurrentBottomLeft( LONG_MAX, 0 );
333 Point aCurrentBottomRight( 0, 0 );
334 const SwCellFrm* pCurrentTopLeftFrm = 0;
335 const SwCellFrm* pCurrentTopRightFrm = 0;
336 const SwCellFrm* pCurrentBottomLeftFrm = 0;
337 const SwCellFrm* pCurrentBottomRightFrm = 0;
339 //Jetzt zu jedem Eintrag die Boxen herausfischen und uebertragen.
340 for( i = 0; i < aUnions.Count() && bTblIsValid; ++i )
342 SwSelUnion *pUnion = aUnions[i];
343 const SwTabFrm *pTable = pUnion->GetTable();
344 if( !pTable->IsValid() && nLoopMax )
346 bTblIsValid = FALSE;
347 break;
350 // Skip any repeated headlines in the follow:
351 const SwLayoutFrm* pRow = pTable->IsFollow() ?
352 pTable->GetFirstNonHeadlineRow() :
353 (const SwLayoutFrm*)pTable->Lower();
355 while( pRow && bTblIsValid )
357 if( !pRow->IsValid() && nLoopMax )
359 bTblIsValid = FALSE;
360 break;
363 if ( pRow->Frm().IsOver( pUnion->GetUnion() ) )
365 const SwLayoutFrm *pCell = pRow->FirstCell();
367 while( bTblIsValid && pCell && pRow->IsAnLower( pCell ) )
369 if( !pCell->IsValid() && nLoopMax )
371 bTblIsValid = FALSE;
372 break;
375 ASSERT( pCell->IsCellFrm(), "Frame ohne Celle" );
376 if( ::IsFrmInTblSel( pUnion->GetUnion(), pCell ) )
378 SwTableBox* pBox = (SwTableBox*)
379 ((SwCellFrm*)pCell)->GetTabBox();
380 // Zellenschutzt beachten ??
381 if( !bChkProtected ||
382 !pBox->GetFrmFmt()->GetProtect().IsCntntProtected() )
383 rBoxes.Insert( pBox );
385 if ( pCells )
387 const Point aTopLeft( pCell->Frm().TopLeft() );
388 const Point aTopRight( pCell->Frm().TopRight() );
389 const Point aBottomLeft( pCell->Frm().BottomLeft() );
390 const Point aBottomRight( pCell->Frm().BottomRight() );
392 if ( aTopLeft.Y() < aCurrentTopLeft.Y() ||
393 ( aTopLeft.Y() == aCurrentTopLeft.Y() &&
394 aTopLeft.X() < aCurrentTopLeft.X() ) )
396 aCurrentTopLeft = aTopLeft;
397 pCurrentTopLeftFrm = static_cast<const SwCellFrm*>( pCell );
400 if ( aTopRight.Y() < aCurrentTopRight.Y() ||
401 ( aTopRight.Y() == aCurrentTopRight.Y() &&
402 aTopRight.X() > aCurrentTopRight.X() ) )
404 aCurrentTopRight = aTopRight;
405 pCurrentTopRightFrm = static_cast<const SwCellFrm*>( pCell );
408 if ( aBottomLeft.Y() > aCurrentBottomLeft.Y() ||
409 ( aBottomLeft.Y() == aCurrentBottomLeft.Y() &&
410 aBottomLeft.X() < aCurrentBottomLeft.X() ) )
412 aCurrentBottomLeft = aBottomLeft;
413 pCurrentBottomLeftFrm = static_cast<const SwCellFrm*>( pCell );
416 if ( aBottomRight.Y() > aCurrentBottomRight.Y() ||
417 ( aBottomRight.Y() == aCurrentBottomRight.Y() &&
418 aBottomRight.X() > aCurrentBottomRight.X() ) )
420 aCurrentBottomRight = aBottomRight;
421 pCurrentBottomRightFrm = static_cast<const SwCellFrm*>( pCell );
426 if ( pCell->GetNext() )
428 pCell = (const SwLayoutFrm*)pCell->GetNext();
429 if ( pCell->Lower() && pCell->Lower()->IsRowFrm() )
430 pCell = pCell->FirstCell();
432 else
433 pCell = ::lcl_FindNextCellFrm( pCell );
436 pRow = (const SwLayoutFrm*)pRow->GetNext();
440 if ( pCells )
442 pCells->Remove( 0, pCells->Count() );
443 pCells->Insert( pCurrentTopLeftFrm, 0 );
444 pCells->Insert( pCurrentTopRightFrm, 1 );
445 pCells->Insert( pCurrentBottomLeftFrm, 2 );
446 pCells->Insert( pCurrentBottomRightFrm, 3 );
449 if( bTblIsValid )
450 break;
452 SwDeletionChecker aDelCheck( pStart );
454 // ansonsten das Layout der Tabelle kurz "kalkulieren" lassen
455 // und nochmals neu aufsetzen
456 SwTabFrm *pTable = aUnions[0]->GetTable();
457 while( pTable )
459 if( pTable->IsValid() )
460 pTable->InvalidatePos();
461 pTable->SetONECalcLowers();
462 pTable->Calc();
463 pTable->SetCompletePaint();
464 if( 0 == (pTable = pTable->GetFollow()) )
465 break;
468 // --> FME 2005-10-13 #125337# Make code robust, check if pStart has
469 // been deleted due to the formatting of the table:
470 if ( aDelCheck.HasBeenDeleted() )
472 ASSERT( false, "Current box has been deleted during GetTblSel()" )
473 break;
475 // <--
477 i = 0;
478 rBoxes.Remove( i, rBoxes.Count() );
479 --nLoopMax;
481 } while( TRUE );
482 ASSERT( nLoopMax, "das Layout der Tabelle wurde nicht valide!" );
487 BOOL ChkChartSel( const SwNode& rSttNd, const SwNode& rEndNd,
488 SwChartLines* pGetCLines )
490 const SwTableNode* pTNd = rSttNd.FindTableNode();
491 if( !pTNd )
492 return FALSE;
494 Point aNullPos;
495 SwNodeIndex aIdx( rSttNd );
496 const SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode();
497 if( !pCNd )
498 pCNd = aIdx.GetNodes().GoNextSection( &aIdx, FALSE, FALSE );
500 // #109394# if table is invisible, return
501 // (layout needed for forming table selection further down, so we can't
502 // continue with invisible tables)
503 // OD 07.11.2003 #i22135# - Also the content of the table could be
504 // invisible - e.g. in a hidden section
505 // Robust: check, if content was found (e.g. empty table cells)
506 if ( !pCNd || pCNd->GetFrm() == NULL )
507 return FALSE;
509 const SwLayoutFrm *pStart = pCNd ? pCNd->GetFrm( &aNullPos )->GetUpper() : 0;
510 ASSERT( pStart, "ohne Frame geht gar nichts" );
512 aIdx = rEndNd;
513 pCNd = aIdx.GetNode().GetCntntNode();
514 if( !pCNd )
515 pCNd = aIdx.GetNodes().GoNextSection( &aIdx, FALSE, FALSE );
517 // OD 07.11.2003 #i22135# - Robust: check, if content was found and if it's visible
518 if ( !pCNd || pCNd->GetFrm() == NULL )
520 return FALSE;
523 const SwLayoutFrm *pEnd = pCNd ? pCNd->GetFrm( &aNullPos )->GetUpper() : 0;
524 ASSERT( pEnd, "ohne Frame geht gar nichts" );
527 BOOL bTblIsValid, bValidChartSel;
528 // --> FME 2006-01-25 #i55421# Reduced value 10
529 int nLoopMax = 10; //JP 28.06.99: max 100 loops - Bug 67292
530 // <--
531 USHORT i = 0;
533 do {
534 bTblIsValid = TRUE;
535 bValidChartSel = TRUE;
537 USHORT nRowCells = USHRT_MAX;
539 //Zuerst lassen wir uns die Tabellen und die Rechtecke heraussuchen.
540 SwSelUnions aUnions;
541 ::MakeSelUnions( aUnions, pStart, pEnd, nsSwTblSearchType::TBLSEARCH_NO_UNION_CORRECT );
543 //Jetzt zu jedem Eintrag die Boxen herausfischen und uebertragen.
544 for( i = 0; i < aUnions.Count() && bTblIsValid &&
545 bValidChartSel; ++i )
547 SwSelUnion *pUnion = aUnions[i];
548 const SwTabFrm *pTable = pUnion->GetTable();
550 SWRECTFN( pTable )
551 sal_Bool bRTL = pTable->IsRightToLeft();
553 if( !pTable->IsValid() && nLoopMax )
555 bTblIsValid = FALSE;
556 break;
559 _Sort_CellFrms aCellFrms;
561 // Skip any repeated headlines in the follow:
562 const SwLayoutFrm* pRow = pTable->IsFollow() ?
563 pTable->GetFirstNonHeadlineRow() :
564 (const SwLayoutFrm*)pTable->Lower();
566 while( pRow && bTblIsValid && bValidChartSel )
568 if( !pRow->IsValid() && nLoopMax )
570 bTblIsValid = FALSE;
571 break;
574 if( pRow->Frm().IsOver( pUnion->GetUnion() ) )
576 const SwLayoutFrm *pCell = pRow->FirstCell();
578 while( bValidChartSel && bTblIsValid && pCell &&
579 pRow->IsAnLower( pCell ) )
581 if( !pCell->IsValid() && nLoopMax )
583 bTblIsValid = FALSE;
584 break;
587 ASSERT( pCell->IsCellFrm(), "Frame ohne Celle" );
588 const SwRect& rUnion = pUnion->GetUnion(),
589 & rFrmRect = pCell->Frm();
591 const long nUnionRight = rUnion.Right();
592 const long nUnionBottom = rUnion.Bottom();
593 const long nFrmRight = rFrmRect.Right();
594 const long nFrmBottom = rFrmRect.Bottom();
596 // liegt das FrmRect ausserhalb der Union, kann es
597 // ignoriert werden.
599 const long nXFuzzy = bVert ? 0 : 20;
600 const long nYFuzzy = bVert ? 20 : 0;
602 if( !( rUnion.Top() + nYFuzzy > nFrmBottom ||
603 nUnionBottom < rFrmRect.Top() + nYFuzzy ||
604 rUnion.Left() + nXFuzzy > nFrmRight ||
605 nUnionRight < rFrmRect.Left() + nXFuzzy ))
607 // ok, rUnion is _not_ completely outside of rFrmRect
609 // wenn es aber nicht komplett in der Union liegt,
610 // dann ist es fuers Chart eine ungueltige
611 // Selektion.
612 if( rUnion.Left() <= rFrmRect.Left() + nXFuzzy &&
613 rFrmRect.Left() <= nUnionRight &&
614 rUnion.Left() <= nFrmRight &&
615 nFrmRight <= nUnionRight + nXFuzzy &&
616 rUnion.Top() <= rFrmRect.Top() + nYFuzzy &&
617 rFrmRect.Top() <= nUnionBottom &&
618 rUnion.Top() <= nFrmBottom &&
619 nFrmBottom <= nUnionBottom+ nYFuzzy )
621 aCellFrms.Insert(
622 _Sort_CellFrm( *(SwCellFrm*)pCell ),
623 aCellFrms.Count() );
624 else
626 bValidChartSel = FALSE;
627 break;
630 if ( pCell->GetNext() )
632 pCell = (const SwLayoutFrm*)pCell->GetNext();
633 if ( pCell->Lower() && pCell->Lower()->IsRowFrm() )
634 pCell = pCell->FirstCell();
636 else
637 pCell = ::lcl_FindNextCellFrm( pCell );
640 pRow = (const SwLayoutFrm*)pRow->GetNext();
643 if( !bValidChartSel )
644 break;
646 // alle Zellen der (Teil-)Tabelle zusammen. Dann teste mal ob
647 // all huebsch nebeneinander liegen.
648 USHORT n, nEnd, nCellCnt = 0;
649 long nYPos = LONG_MAX;
650 long nXPos = 0;
651 long nHeight = 0;
653 for( n = 0, nEnd = aCellFrms.Count(); n < nEnd; ++n )
655 const _Sort_CellFrm& rCF = aCellFrms[ n ];
656 if( (rCF.pFrm->Frm().*fnRect->fnGetTop)() != nYPos )
658 // neue Zeile
659 if( n )
661 if( USHRT_MAX == nRowCells ) // 1. Zeilenwechsel
662 nRowCells = nCellCnt;
663 else if( nRowCells != nCellCnt )
665 bValidChartSel = FALSE;
666 break;
669 nCellCnt = 1;
670 nYPos = (rCF.pFrm->Frm().*fnRect->fnGetTop)();
671 nHeight = (rCF.pFrm->Frm().*fnRect->fnGetHeight)();
673 nXPos = bRTL ?
674 (rCF.pFrm->Frm().*fnRect->fnGetLeft)() :
675 (rCF.pFrm->Frm().*fnRect->fnGetRight)();
677 else if( nXPos == ( bRTL ?
678 (rCF.pFrm->Frm().*fnRect->fnGetRight)() :
679 (rCF.pFrm->Frm().*fnRect->fnGetLeft)() ) &&
680 nHeight == (rCF.pFrm->Frm().*fnRect->fnGetHeight)() )
682 nXPos += ( bRTL ? (-1) : 1 ) *
683 (rCF.pFrm->Frm().*fnRect->fnGetWidth)();
684 ++nCellCnt;
686 else
688 bValidChartSel = FALSE;
689 break;
692 if( bValidChartSel )
694 if( USHRT_MAX == nRowCells )
695 nRowCells = nCellCnt;
696 else if( nRowCells != nCellCnt )
697 bValidChartSel = FALSE;
700 if( bValidChartSel && pGetCLines )
702 nYPos = LONG_MAX;
703 SwChartBoxes* pBoxes = 0;
704 for( n = 0, nEnd = aCellFrms.Count(); n < nEnd; ++n )
706 const _Sort_CellFrm& rCF = aCellFrms[ n ];
707 if( (rCF.pFrm->Frm().*fnRect->fnGetTop)() != nYPos )
709 pBoxes = new SwChartBoxes( 255 < nRowCells
710 ? 255 : (BYTE)nRowCells);
711 pGetCLines->C40_INSERT( SwChartBoxes, pBoxes, pGetCLines->Count() );
712 nYPos = (rCF.pFrm->Frm().*fnRect->fnGetTop)();
714 SwTableBoxPtr pBox = (SwTableBox*)rCF.pFrm->GetTabBox();
715 pBoxes->Insert( pBox, pBoxes->Count() );
720 if( bTblIsValid )
721 break;
723 // ansonsten das Layout der Tabelle kurz "kalkulieren" lassen
724 // und nochmals neu aufsetzen
725 SwTabFrm *pTable = aUnions[0]->GetTable();
726 for( i = 0; i < aUnions.Count(); ++i )
728 if( pTable->IsValid() )
729 pTable->InvalidatePos();
730 pTable->SetONECalcLowers();
731 pTable->Calc();
732 pTable->SetCompletePaint();
733 if( 0 == (pTable = pTable->GetFollow()) )
734 break;
736 --nLoopMax;
737 if( pGetCLines )
738 pGetCLines->DeleteAndDestroy( 0, pGetCLines->Count() );
739 } while( TRUE );
741 ASSERT( nLoopMax, "das Layout der Tabelle wurde nicht valide!" );
743 if( !bValidChartSel && pGetCLines )
744 pGetCLines->DeleteAndDestroy( 0, pGetCLines->Count() );
746 return bValidChartSel;
750 BOOL IsFrmInTblSel( const SwRect& rUnion, const SwFrm* pCell )
752 ASSERT( pCell->IsCellFrm(), "Frame ohne Gazelle" );
754 if( pCell->FindTabFrm()->IsVertical() )
755 return ( rUnion.Right() >= pCell->Frm().Right() &&
756 rUnion.Left() <= pCell->Frm().Left() &&
757 (( rUnion.Top() <= pCell->Frm().Top()+20 &&
758 rUnion.Bottom() > pCell->Frm().Top() ) ||
759 ( rUnion.Top() >= pCell->Frm().Top() &&
760 rUnion.Bottom() < pCell->Frm().Bottom() )) ? TRUE : FALSE );
762 return (
763 rUnion.Top() <= pCell->Frm().Top() &&
764 rUnion.Bottom() >= pCell->Frm().Bottom() &&
766 (( rUnion.Left() <= pCell->Frm().Left()+20 &&
767 rUnion.Right() > pCell->Frm().Left() ) ||
769 ( rUnion.Left() >= pCell->Frm().Left() &&
770 rUnion.Right() < pCell->Frm().Right() )) ? TRUE : FALSE );
773 BOOL GetAutoSumSel( const SwCrsrShell& rShell, SwCellFrms& rBoxes )
775 SwShellCrsr* pCrsr = rShell.pCurCrsr;
776 if ( rShell.IsTableMode() )
777 pCrsr = rShell.pTblCrsr;
779 const SwLayoutFrm *pStart = pCrsr->GetCntntNode()->GetFrm(
780 &pCrsr->GetPtPos() )->GetUpper(),
781 *pEnd = pCrsr->GetCntntNode(FALSE)->GetFrm(
782 &pCrsr->GetMkPos() )->GetUpper();
784 const SwLayoutFrm* pSttCell = pStart;
785 while( pSttCell && !pSttCell->IsCellFrm() )
786 pSttCell = pSttCell->GetUpper();
788 //Zuerst lassen wir uns die Tabellen und die Rechtecke heraussuchen.
789 SwSelUnions aUnions;
791 // default erstmal nach oben testen, dann nach links
792 ::MakeSelUnions( aUnions, pStart, pEnd, nsSwTblSearchType::TBLSEARCH_COL );
794 BOOL bTstRow = TRUE, bFound = FALSE;
795 USHORT i;
797 // 1. teste ob die darueber liegende Box Value/Formel enhaelt:
798 for( i = 0; i < aUnions.Count(); ++i )
800 SwSelUnion *pUnion = aUnions[i];
801 const SwTabFrm *pTable = pUnion->GetTable();
803 // Skip any repeated headlines in the follow:
804 const SwLayoutFrm* pRow = pTable->IsFollow() ?
805 pTable->GetFirstNonHeadlineRow() :
806 (const SwLayoutFrm*)pTable->Lower();
808 while( pRow )
810 if( pRow->Frm().IsOver( pUnion->GetUnion() ) )
812 const SwCellFrm* pUpperCell = 0;
813 const SwLayoutFrm *pCell = pRow->FirstCell();
815 while( pCell && pRow->IsAnLower( pCell ) )
817 if( pCell == pSttCell )
819 USHORT nWhichId = 0;
820 for( USHORT n = rBoxes.Count(); n; )
821 if( USHRT_MAX != ( nWhichId = rBoxes[ --n ]
822 ->GetTabBox()->IsFormulaOrValueBox() ))
823 break;
825 // alle Boxen zusammen, nicht mehr die Zeile
826 // pruefen, wenn eine Formel oder Value gefunden wurde
827 bTstRow = 0 == nWhichId || USHRT_MAX == nWhichId;
828 bFound = TRUE;
829 break;
832 ASSERT( pCell->IsCellFrm(), "Frame ohne Celle" );
833 if( ::IsFrmInTblSel( pUnion->GetUnion(), pCell ) )
834 pUpperCell = (SwCellFrm*)pCell;
836 if( pCell->GetNext() )
838 pCell = (const SwLayoutFrm*)pCell->GetNext();
839 if ( pCell->Lower() && pCell->Lower()->IsRowFrm() )
840 pCell = pCell->FirstCell();
842 else
843 pCell = ::lcl_FindNextCellFrm( pCell );
846 if( pUpperCell )
847 rBoxes.Insert( pUpperCell, rBoxes.Count() );
849 if( bFound )
851 i = aUnions.Count();
852 break;
854 pRow = (const SwLayoutFrm*)pRow->GetNext();
859 // 2. teste ob die links liegende Box Value/Formel enhaelt:
860 if( bTstRow )
862 bFound = FALSE;
864 rBoxes.Remove( 0, rBoxes.Count() );
865 aUnions.DeleteAndDestroy( 0, aUnions.Count() );
866 ::MakeSelUnions( aUnions, pStart, pEnd, nsSwTblSearchType::TBLSEARCH_ROW );
868 for( i = 0; i < aUnions.Count(); ++i )
870 SwSelUnion *pUnion = aUnions[i];
871 const SwTabFrm *pTable = pUnion->GetTable();
873 // Skip any repeated headlines in the follow:
874 const SwLayoutFrm* pRow = pTable->IsFollow() ?
875 pTable->GetFirstNonHeadlineRow() :
876 (const SwLayoutFrm*)pTable->Lower();
878 while( pRow )
880 if( pRow->Frm().IsOver( pUnion->GetUnion() ) )
882 const SwLayoutFrm *pCell = pRow->FirstCell();
884 while( pCell && pRow->IsAnLower( pCell ) )
886 if( pCell == pSttCell )
888 USHORT nWhichId = 0;
889 for( USHORT n = rBoxes.Count(); n; )
890 if( USHRT_MAX != ( nWhichId = rBoxes[ --n ]
891 ->GetTabBox()->IsFormulaOrValueBox() ))
892 break;
894 // alle Boxen zusammen, nicht mehr die Zeile
895 // pruefen, wenn eine Formel oder Value gefunden wurde
896 bFound = 0 != nWhichId && USHRT_MAX != nWhichId;
897 bTstRow = FALSE;
898 break;
901 ASSERT( pCell->IsCellFrm(), "Frame ohne Celle" );
902 if( ::IsFrmInTblSel( pUnion->GetUnion(), pCell ) )
904 const SwCellFrm* pC = (SwCellFrm*)pCell;
905 rBoxes.Insert( pC, rBoxes.Count() );
907 if( pCell->GetNext() )
909 pCell = (const SwLayoutFrm*)pCell->GetNext();
910 if ( pCell->Lower() && pCell->Lower()->IsRowFrm() )
911 pCell = pCell->FirstCell();
913 else
914 pCell = ::lcl_FindNextCellFrm( pCell );
917 if( !bTstRow )
919 i = aUnions.Count();
920 break;
923 pRow = (const SwLayoutFrm*)pRow->GetNext();
928 return bFound;
931 BOOL HasProtectedCells( const SwSelBoxes& rBoxes )
933 BOOL bRet = FALSE;
934 for( USHORT n = 0, nCnt = rBoxes.Count(); n < nCnt; ++n )
935 if( rBoxes[ n ]->GetFrmFmt()->GetProtect().IsCntntProtected() )
937 bRet = TRUE;
938 break;
940 return bRet;
944 _CmpLPt::_CmpLPt( const Point& rPt, const SwTableBox* pBox, BOOL bVertical )
945 : aPos( rPt ), pSelBox( pBox ), bVert( bVertical )
948 void lcl_InsTblBox( SwTableNode* pTblNd, SwDoc* pDoc, SwTableBox* pBox,
949 USHORT nInsPos, USHORT nCnt = 1 )
951 ASSERT( pBox->GetSttNd(), "Box ohne Start-Node" );
952 SwCntntNode* pCNd = pDoc->GetNodes()[ pBox->GetSttIdx() + 1 ]
953 ->GetCntntNode();
954 if( pCNd && pCNd->IsTxtNode() )
955 pDoc->GetNodes().InsBoxen( pTblNd, pBox->GetUpper(),
956 (SwTableBoxFmt*)pBox->GetFrmFmt(),
957 ((SwTxtNode*)pCNd)->GetTxtColl(),
958 pCNd->GetpSwAttrSet(),
959 nInsPos, nCnt );
960 else
961 pDoc->GetNodes().InsBoxen( pTblNd, pBox->GetUpper(),
962 (SwTableBoxFmt*)pBox->GetFrmFmt(),
963 (SwTxtFmtColl*)pDoc->GetDfltTxtFmtColl(), 0,
964 nInsPos, nCnt );
967 BOOL IsEmptyBox( const SwTableBox& rBox, SwPaM& rPam )
969 rPam.GetPoint()->nNode = *rBox.GetSttNd()->EndOfSectionNode();
970 rPam.Move( fnMoveBackward, fnGoCntnt );
971 rPam.SetMark();
972 rPam.GetPoint()->nNode = *rBox.GetSttNd();
973 rPam.Move( fnMoveForward, fnGoCntnt );
974 BOOL bRet = *rPam.GetMark() == *rPam.GetPoint()
975 && ( rBox.GetSttNd()->GetIndex() + 1 == rPam.GetPoint()->nNode.GetIndex() );
977 if( bRet )
979 // dann teste mal auf absatzgebundenen Flys
980 const SwSpzFrmFmts& rFmts = *rPam.GetDoc()->GetSpzFrmFmts();
981 ULONG nSttIdx = rPam.GetPoint()->nNode.GetIndex(),
982 nEndIdx = rBox.GetSttNd()->EndOfSectionIndex(),
983 nIdx;
985 for( USHORT n = 0; n < rFmts.Count(); ++n )
987 const SwPosition* pAPos;
988 const SwFmtAnchor& rAnchor = rFmts[n]->GetAnchor();
989 if( ( FLY_AT_CNTNT == rAnchor.GetAnchorId() ||
990 FLY_AUTO_CNTNT == rAnchor.GetAnchorId() ) &&
991 0 != ( pAPos = rAnchor.GetCntntAnchor() ) &&
992 nSttIdx <= ( nIdx = pAPos->nNode.GetIndex() ) &&
993 nIdx < nEndIdx )
995 bRet = FALSE;
996 break;
1000 return bRet;
1004 void GetMergeSel( const SwPaM& rPam, SwSelBoxes& rBoxes,
1005 SwTableBox** ppMergeBox, SwUndoTblMerge* pUndo )
1007 if( rBoxes.Count() )
1008 rBoxes.Remove( USHORT(0), rBoxes.Count() );
1010 //Zuerst lassen wir uns die Tabellen und die Rechtecke heraussuchen.
1011 ASSERT( rPam.GetCntntNode() && rPam.GetCntntNode( FALSE ),
1012 "Tabselection nicht auf Cnt." );
1014 //JP 24.09.96: Merge mit wiederholenden TabellenHeadline funktioniert nicht
1015 // richtig. Warum nicht Point 0,0 benutzen? Dann ist garantiert,
1016 // das die 1. Headline mit drin ist.
1017 // Point aPt( rShell.GetCharRect().Pos() );
1018 Point aPt( 0, 0 );
1019 const SwLayoutFrm *pStart = rPam.GetCntntNode()->GetFrm(
1020 &aPt )->GetUpper(),
1021 *pEnd = rPam.GetCntntNode(FALSE)->GetFrm(
1022 &aPt )->GetUpper();
1024 SwSelUnions aUnions;
1025 ::MakeSelUnions( aUnions, pStart, pEnd );
1026 if( !aUnions.Count() )
1027 return;
1029 const SwTable *pTable = aUnions[0]->GetTable()->GetTable();
1030 SwDoc* pDoc = (SwDoc*)pStart->GetFmt()->GetDoc();
1031 SwTableNode* pTblNd = (SwTableNode*)pTable->GetTabSortBoxes()[ 0 ]->
1032 GetSttNd()->FindTableNode();
1034 _MergePos aPosArr; // Sort-Array mit den Positionen der Frames
1035 long nWidth;
1036 SwTableBox* pLastBox = 0;
1038 SWRECTFN( pStart->GetUpper() )
1040 for ( USHORT i = 0; i < aUnions.Count(); ++i )
1042 const SwTabFrm *pTabFrm = aUnions[i]->GetTable();
1044 SwRect &rUnion = aUnions[i]->GetUnion();
1046 // Skip any repeated headlines in the follow:
1047 const SwLayoutFrm* pRow = pTabFrm->IsFollow() ?
1048 pTabFrm->GetFirstNonHeadlineRow() :
1049 (const SwLayoutFrm*)pTabFrm->Lower();
1051 while ( pRow )
1053 if ( pRow->Frm().IsOver( rUnion ) )
1055 const SwLayoutFrm *pCell = pRow->FirstCell();
1057 while ( pCell && pRow->IsAnLower( pCell ) )
1059 ASSERT( pCell->IsCellFrm(), "Frame ohne Celle" );
1060 // in der vollen Breite ueberlappend ?
1061 if( rUnion.Top() <= pCell->Frm().Top() &&
1062 rUnion.Bottom() >= pCell->Frm().Bottom() )
1064 SwTableBox* pBox =(SwTableBox*)((SwCellFrm*)pCell)->GetTabBox();
1066 // nur nach rechts ueberlappend
1067 if( ( rUnion.Left() - COLFUZZY ) <= pCell->Frm().Left() &&
1068 ( rUnion.Right() - COLFUZZY ) > pCell->Frm().Left() )
1070 if( ( rUnion.Right() + COLFUZZY ) < pCell->Frm().Right() )
1072 USHORT nInsPos = pBox->GetUpper()->
1073 GetTabBoxes().C40_GETPOS( SwTableBox, pBox )+1;
1074 lcl_InsTblBox( pTblNd, pDoc, pBox, nInsPos );
1075 pBox->ClaimFrmFmt();
1076 SwFmtFrmSize aNew(
1077 pBox->GetFrmFmt()->GetFrmSize() );
1078 nWidth = rUnion.Right() - pCell->Frm().Left();
1079 nWidth = nWidth * aNew.GetWidth() /
1080 pCell->Frm().Width();
1081 long nTmpWidth = aNew.GetWidth() - nWidth;
1082 aNew.SetWidth( nWidth );
1083 pBox->GetFrmFmt()->SetFmtAttr( aNew );
1084 // diese Box ist selektiert
1085 pLastBox = pBox;
1086 rBoxes.Insert( pBox );
1087 aPosArr.Insert(
1088 _CmpLPt( (pCell->Frm().*fnRect->fnGetPos)(),
1089 pBox, bVert ) );
1091 pBox = pBox->GetUpper()->GetTabBoxes()[ nInsPos ];
1092 aNew.SetWidth( nTmpWidth );
1093 pBox->ClaimFrmFmt();
1094 pBox->GetFrmFmt()->SetFmtAttr( aNew );
1096 if( pUndo )
1097 pUndo->AddNewBox( pBox->GetSttIdx() );
1099 else
1101 // diese Box ist selektiert
1102 pLastBox = pBox;
1103 rBoxes.Insert( pBox );
1104 #if OSL_DEBUG_LEVEL > 1
1105 Point aInsPoint( (pCell->Frm().*fnRect->fnGetPos)() );
1106 #endif
1107 aPosArr.Insert(
1108 _CmpLPt( (pCell->Frm().*fnRect->fnGetPos)(),
1109 pBox, bVert ) );
1112 // oder rechts und links ueberlappend
1113 else if( ( rUnion.Left() - COLFUZZY ) >= pCell->Frm().Left() &&
1114 ( rUnion.Right() + COLFUZZY ) < pCell->Frm().Right() )
1116 USHORT nInsPos = pBox->GetUpper()->GetTabBoxes().
1117 C40_GETPOS( SwTableBox, pBox )+1;
1118 lcl_InsTblBox( pTblNd, pDoc, pBox, nInsPos, 2 );
1119 pBox->ClaimFrmFmt();
1120 SwFmtFrmSize aNew(
1121 pBox->GetFrmFmt()->GetFrmSize() );
1122 long nLeft = rUnion.Left() - pCell->Frm().Left();
1123 nLeft = nLeft * aNew.GetWidth() /
1124 pCell->Frm().Width();
1125 long nRight = pCell->Frm().Right() - rUnion.Right();
1126 nRight = nRight * aNew.GetWidth() /
1127 pCell->Frm().Width();
1128 nWidth = aNew.GetWidth() - nLeft - nRight;
1130 aNew.SetWidth( nLeft );
1131 pBox->GetFrmFmt()->SetFmtAttr( aNew );
1134 const SfxPoolItem* pItem;
1135 if( SFX_ITEM_SET == pBox->GetFrmFmt()->GetAttrSet()
1136 .GetItemState( RES_BOX, FALSE, &pItem ))
1138 SvxBoxItem aBox( *(SvxBoxItem*)pItem );
1139 aBox.SetLine( 0, BOX_LINE_RIGHT );
1140 pBox->GetFrmFmt()->SetFmtAttr( aBox );
1144 pBox = pBox->GetUpper()->GetTabBoxes()[ nInsPos ];
1145 aNew.SetWidth( nWidth );
1146 pBox->ClaimFrmFmt();
1147 pBox->GetFrmFmt()->SetFmtAttr( aNew );
1149 if( pUndo )
1150 pUndo->AddNewBox( pBox->GetSttIdx() );
1152 // diese Box ist selektiert
1153 pLastBox = pBox;
1154 rBoxes.Insert( pBox );
1155 aPosArr.Insert(
1156 _CmpLPt( (pCell->Frm().*fnRect->fnGetPos)(),
1157 pBox, bVert ) );
1159 pBox = pBox->GetUpper()->GetTabBoxes()[ nInsPos+1 ];
1160 aNew.SetWidth( nRight );
1161 pBox->ClaimFrmFmt();
1162 pBox->GetFrmFmt()->SetFmtAttr( aNew );
1164 if( pUndo )
1165 pUndo->AddNewBox( pBox->GetSttIdx() );
1167 // oder reicht die rechte Kante der Box in den
1168 // selektierten Bereich?
1169 else if( ( pCell->Frm().Right() - COLFUZZY ) < rUnion.Right() &&
1170 ( pCell->Frm().Right() - COLFUZZY ) > rUnion.Left() &&
1171 ( pCell->Frm().Left() + COLFUZZY ) < rUnion.Left() )
1173 // dann muss eine neue Box einfuegt und die
1174 // Breiten angepasst werden
1175 USHORT nInsPos = pBox->GetUpper()->GetTabBoxes().
1176 C40_GETPOS( SwTableBox, pBox )+1;
1177 lcl_InsTblBox( pTblNd, pDoc, pBox, nInsPos, 1 );
1179 SwFmtFrmSize aNew(pBox->GetFrmFmt()->GetFrmSize() );
1180 long nLeft = rUnion.Left() - pCell->Frm().Left(),
1181 nRight = pCell->Frm().Right() - rUnion.Left();
1183 nLeft = nLeft * aNew.GetWidth() /
1184 pCell->Frm().Width();
1185 nRight = nRight * aNew.GetWidth() /
1186 pCell->Frm().Width();
1188 aNew.SetWidth( nLeft );
1189 pBox->ClaimFrmFmt()->SetFmtAttr( aNew );
1191 // diese Box ist selektiert
1192 pBox = pBox->GetUpper()->GetTabBoxes()[ nInsPos ];
1193 aNew.SetWidth( nRight );
1194 pBox->ClaimFrmFmt();
1195 pBox->GetFrmFmt()->SetFmtAttr( aNew );
1197 pLastBox = pBox;
1198 rBoxes.Insert( pBox );
1199 aPosArr.Insert( _CmpLPt( Point( rUnion.Left(),
1200 pCell->Frm().Top()), pBox, bVert ));
1202 if( pUndo )
1203 pUndo->AddNewBox( pBox->GetSttIdx() );
1206 if ( pCell->GetNext() )
1208 pCell = (const SwLayoutFrm*)pCell->GetNext();
1209 // --> FME 2005-11-03 #125288# Check if table cell is not empty
1210 if ( pCell->Lower() && pCell->Lower()->IsRowFrm() )
1211 pCell = pCell->FirstCell();
1213 else
1214 pCell = ::lcl_FindNextCellFrm( pCell );
1217 pRow = (const SwLayoutFrm*)pRow->GetNext();
1221 // keine SSelection / keine gefundenen Boxen
1222 if( 1 >= rBoxes.Count() )
1223 return;
1225 // dann suche mal alle Boxen, die nebeneinander liegen, und verbinde
1226 // deren Inhalte mit Blanks. Alle untereinander liegende werden als
1227 // Absaetze zusammengefasst
1229 // 1. Loesung: gehe ueber das Array und
1230 // alle auf der gleichen Y-Ebene werden mit Blanks getrennt
1231 // alle anderen werden als Absaetze getrennt.
1232 BOOL bCalcWidth = TRUE;
1233 const SwTableBox* pFirstBox = aPosArr[ 0 ].pSelBox;
1235 // JP 27.03.98: Optimierung - falls die Boxen einer Line leer sind,
1236 // dann werden jetzt dafuer keine Blanks und
1237 // kein Umbruch mehr eingefuegt.
1238 //Block damit SwPaM, SwPosition vom Stack geloescht werden
1240 SwPaM aPam( pDoc->GetNodes() );
1242 #if defined( DEL_ONLY_EMPTY_LINES )
1243 nWidth = pFirstBox->GetFrmFmt()->GetFrmSize().GetWidth();
1244 BOOL bEmptyLine = TRUE;
1245 USHORT n, nSttPos = 0;
1247 for( n = 0; n < aPosArr.Count(); ++n )
1249 const _CmpLPt& rPt = aPosArr[ n ];
1250 if( n && aPosArr[ n - 1 ].Y() == rPt.Y() ) // gleiche Ebene ?
1252 if( bEmptyLine && !IsEmptyBox( *rPt.pSelBox, aPam ))
1253 bEmptyLine = FALSE;
1254 if( bCalcWidth )
1255 nWidth += rPt.pSelBox->GetFrmFmt()->GetFrmSize().GetWidth();
1257 else
1259 if( bCalcWidth && n )
1260 bCalcWidth = FALSE; // eine Zeile fertig
1262 if( bEmptyLine && nSttPos < n )
1264 // dann ist die gesamte Line leer und braucht
1265 // nicht mit Blanks aufgefuellt und als Absatz
1266 // eingefuegt werden.
1267 if( pUndo )
1268 for( USHORT i = nSttPos; i < n; ++i )
1269 pUndo->SaveCollection( *aPosArr[ i ].pSelBox );
1271 aPosArr.Remove( nSttPos, n - nSttPos );
1272 n = nSttPos;
1274 else
1275 nSttPos = n;
1277 bEmptyLine = IsEmptyBox( *aPosArr[n].pSelBox, aPam );
1280 if( bEmptyLine && nSttPos < n )
1282 if( pUndo )
1283 for( USHORT i = nSttPos; i < n; ++i )
1284 pUndo->SaveCollection( *aPosArr[ i ].pSelBox );
1285 aPosArr.Remove( nSttPos, n - nSttPos );
1287 #elsif defined( DEL_EMPTY_BOXES_AT_START_AND_END )
1289 nWidth = pFirstBox->GetFrmFmt()->GetFrmSize().GetWidth();
1290 USHORT n, nSttPos = 0, nSEndPos = 0, nESttPos = 0;
1292 for( n = 0; n < aPosArr.Count(); ++n )
1294 const _CmpLPt& rPt = aPosArr[ n ];
1295 if( n && aPosArr[ n - 1 ].Y() == rPt.Y() ) // gleiche Ebene ?
1297 BOOL bEmptyBox = IsEmptyBox( *rPt.pSelBox, aPam );
1298 if( bEmptyBox )
1300 if( nSEndPos == n ) // der Anfang ist leer
1301 nESttPos = ++nSEndPos;
1303 else // das Ende kann leer sein
1304 nESttPos = n+1;
1306 if( bCalcWidth )
1307 nWidth += rPt.pSelBox->GetFrmFmt()->GetFrmSize().GetWidth();
1309 else
1311 if( bCalcWidth && n )
1312 bCalcWidth = FALSE; // eine Zeile fertig
1314 // zuerst die vom Anfang
1315 if( nSttPos < nSEndPos )
1317 // dann ist der vorder Teil der Line leer und braucht
1318 // nicht mit Blanks aufgefuellt werden.
1319 if( pUndo )
1320 for( USHORT i = nSttPos; i < nSEndPos; ++i )
1321 pUndo->SaveCollection( *aPosArr[ i ].pSelBox );
1323 USHORT nCnt = nSEndPos - nSttPos;
1324 aPosArr.Remove( nSttPos, nCnt );
1325 nESttPos -= nCnt;
1326 n -= nCnt;
1329 if( nESttPos < n )
1331 // dann ist der vorder Teil der Line leer und braucht
1332 // nicht mit Blanks aufgefuellt werden.
1333 if( pUndo )
1334 for( USHORT i = nESttPos; i < n; ++i )
1335 pUndo->SaveCollection( *aPosArr[ i ].pSelBox );
1337 USHORT nCnt = n - nESttPos;
1338 aPosArr.Remove( nESttPos, nCnt );
1339 n -= nCnt;
1342 nSttPos = nSEndPos = nESttPos = n;
1343 if( IsEmptyBox( *aPosArr[n].pSelBox, aPam ))
1344 ++nSEndPos;
1345 else
1346 ++nESttPos;
1350 // zuerst die vom Anfang
1351 if( nSttPos < nSEndPos )
1353 // dann ist der vorder Teil der Line leer und braucht
1354 // nicht mit Blanks aufgefuellt werden.
1355 if( pUndo )
1356 for( USHORT i = nSttPos; i < nSEndPos; ++i )
1357 pUndo->SaveCollection( *aPosArr[ i ].pSelBox );
1359 USHORT nCnt = nSEndPos - nSttPos;
1360 aPosArr.Remove( nSttPos, nCnt );
1361 nESttPos -= nCnt;
1362 n -= nCnt;
1364 if( nESttPos < n )
1366 // dann ist der vorder Teil der Line leer und braucht
1367 // nicht mit Blanks aufgefuellt werden.
1368 if( pUndo )
1369 for( USHORT i = nESttPos; i < n; ++i )
1370 pUndo->SaveCollection( *aPosArr[ i ].pSelBox );
1372 USHORT nCnt = n - nESttPos;
1373 aPosArr.Remove( nESttPos, nCnt );
1375 #else
1376 // DEL_ALL_EMPTY_BOXES
1378 nWidth = 0;
1379 long nY = aPosArr.Count() ?
1380 ( bVert ?
1381 aPosArr[ 0 ].X() :
1382 aPosArr[ 0 ].Y() ) :
1385 for( USHORT n = 0; n < aPosArr.Count(); ++n )
1387 const _CmpLPt& rPt = aPosArr[ n ];
1388 if( bCalcWidth )
1390 if( nY == ( bVert ? rPt.X() : rPt.Y() ) ) // gleiche Ebene ?
1391 nWidth += rPt.pSelBox->GetFrmFmt()->GetFrmSize().GetWidth();
1392 else
1393 bCalcWidth = FALSE; // eine Zeile fertig
1396 if( IsEmptyBox( *rPt.pSelBox, aPam ) )
1398 if( pUndo )
1399 pUndo->SaveCollection( *rPt.pSelBox );
1401 aPosArr.Remove( n, 1 );
1402 --n;
1405 #endif
1408 // lege schon mal die neue Box an
1410 SwTableBox* pTmpBox = rBoxes[0];
1411 SwTableLine* pInsLine = pTmpBox->GetUpper();
1412 USHORT nInsPos = pInsLine->GetTabBoxes().C40_GETPOS( SwTableBox, pTmpBox );
1414 lcl_InsTblBox( pTblNd, pDoc, pTmpBox, nInsPos );
1415 (*ppMergeBox) = pInsLine->GetTabBoxes()[ nInsPos ];
1416 pInsLine->GetTabBoxes().Remove( nInsPos ); // wieder austragen
1417 (*ppMergeBox)->SetUpper( 0 );
1418 (*ppMergeBox)->ClaimFrmFmt();
1420 // setze die Umrandung: von der 1. Box die linke/obere von der
1421 // letzten Box die rechte/untere Kante:
1422 if( pLastBox && pFirstBox )
1424 SvxBoxItem aBox( pFirstBox->GetFrmFmt()->GetBox() );
1425 const SvxBoxItem& rBox = pLastBox->GetFrmFmt()->GetBox();
1426 aBox.SetLine( rBox.GetRight(), BOX_LINE_RIGHT );
1427 aBox.SetLine( rBox.GetBottom(), BOX_LINE_BOTTOM );
1428 if( aBox.GetLeft() || aBox.GetTop() ||
1429 aBox.GetRight() || aBox.GetBottom() )
1430 (*ppMergeBox)->GetFrmFmt()->SetFmtAttr( aBox );
1434 //Block damit SwPaM, SwPosition vom Stack geloescht werden
1435 if( aPosArr.Count() )
1437 SwTxtNode* pTxtNd = 0;
1438 SwPosition aInsPos( *(*ppMergeBox)->GetSttNd() );
1439 SwNodeIndex& rInsPosNd = aInsPos.nNode;
1441 SwPaM aPam( aInsPos );
1443 for( USHORT n = 0; n < aPosArr.Count(); ++n )
1445 const _CmpLPt& rPt = aPosArr[ n ];
1446 aPam.GetPoint()->nNode.Assign( *rPt.pSelBox->GetSttNd()->
1447 EndOfSectionNode(), -1 );
1448 SwCntntNode* pCNd = aPam.GetCntntNode();
1449 USHORT nL = pCNd ? pCNd->Len() : 0;
1450 aPam.GetPoint()->nContent.Assign( pCNd, nL );
1452 SwNodeIndex aSttNdIdx( *rPt.pSelBox->GetSttNd(), 1 );
1453 // ein Node muss in der Box erhalten bleiben (sonst wird beim
1454 // Move die gesamte Section geloescht)
1455 if( pUndo )
1456 pDoc->DoUndo( FALSE );
1457 pDoc->AppendTxtNode( *aPam.GetPoint() );
1458 if( pUndo )
1459 pDoc->DoUndo( TRUE );
1460 SwNodeRange aRg( aSttNdIdx, aPam.GetPoint()->nNode );
1461 rInsPosNd++;
1462 if( pUndo )
1463 pUndo->MoveBoxCntnt( pDoc, aRg, rInsPosNd );
1464 else
1466 pDoc->MoveNodeRange( aRg, rInsPosNd,
1467 IDocumentContentOperations::DOC_MOVEDEFAULT );
1469 // wo steht jetzt aInsPos ??
1471 if( bCalcWidth )
1472 bCalcWidth = FALSE; // eine Zeile fertig
1474 // den initialen TextNode ueberspringen
1475 rInsPosNd.Assign( pDoc->GetNodes(),
1476 rInsPosNd.GetNode().EndOfSectionIndex() - 2 );
1477 pTxtNd = rInsPosNd.GetNode().GetTxtNode();
1478 if( pTxtNd )
1479 aInsPos.nContent.Assign( pTxtNd, pTxtNd->GetTxt().Len() );
1482 // in der MergeBox sollte jetzt der gesamte Text stehen
1483 // loesche jetzt noch den initialen TextNode
1484 ASSERT( (*ppMergeBox)->GetSttIdx()+2 <
1485 (*ppMergeBox)->GetSttNd()->EndOfSectionIndex(),
1486 "leere Box" );
1487 SwNodeIndex aIdx( *(*ppMergeBox)->GetSttNd()->EndOfSectionNode(), -1 );
1488 pDoc->GetNodes().Delete( aIdx, 1 );
1491 // setze die Breite der Box
1492 (*ppMergeBox)->GetFrmFmt()->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nWidth, 0 ));
1493 if( pUndo )
1494 pUndo->AddNewBox( (*ppMergeBox)->GetSttIdx() );
1498 static BOOL lcl_CheckCol( const _FndBox*& rpFndBox, void* pPara );
1500 static BOOL lcl_CheckRow( const _FndLine*& rpFndLine, void* pPara )
1502 ((_FndLine*)rpFndLine)->GetBoxes().ForEach( &lcl_CheckCol, pPara );
1503 return *(BOOL*)pPara;
1506 static BOOL lcl_CheckCol( const _FndBox*& rpFndBox, void* pPara )
1508 if( !rpFndBox->GetBox()->GetSttNd() )
1510 if( rpFndBox->GetLines().Count() !=
1511 rpFndBox->GetBox()->GetTabLines().Count() )
1512 *((BOOL*)pPara) = FALSE;
1513 else
1514 ((_FndBox*)rpFndBox)->GetLines().ForEach( &lcl_CheckRow, pPara );
1516 // Box geschuetzt ??
1517 else if( rpFndBox->GetBox()->GetFrmFmt()->GetProtect().IsCntntProtected() )
1518 *((BOOL*)pPara) = FALSE;
1519 return *(BOOL*)pPara;
1523 USHORT CheckMergeSel( const SwPaM& rPam )
1525 SwSelBoxes aBoxes;
1526 //JP 24.09.96: Merge mit wiederholenden TabellenHeadline funktioniert nicht
1527 // richtig. Warum nicht Point 0,0 benutzen? Dann ist garantiert,
1528 // das die 1. Headline mit drin ist.
1529 Point aPt;
1530 const SwLayoutFrm *pStart = rPam.GetCntntNode()->GetFrm(
1531 &aPt )->GetUpper(),
1532 *pEnd = rPam.GetCntntNode(FALSE)->GetFrm(
1533 &aPt )->GetUpper();
1534 GetTblSel( pStart, pEnd, aBoxes, 0 );
1535 return CheckMergeSel( aBoxes );
1538 USHORT CheckMergeSel( const SwSelBoxes& rBoxes )
1540 USHORT eRet = TBLMERGE_NOSELECTION;
1541 if( rBoxes.Count() )
1543 eRet = TBLMERGE_OK;
1545 _FndBox aFndBox( 0, 0 );
1546 _FndPara aPara( rBoxes, &aFndBox );
1547 const SwTableNode* pTblNd = aPara.rBoxes[0]->GetSttNd()->FindTableNode();
1548 ((SwTable&)pTblNd->GetTable()).GetTabLines().ForEach(
1549 &_FndLineCopyCol, &aPara );
1550 if( aFndBox.GetLines().Count() )
1552 BOOL bMergeSelOk = TRUE;
1553 _FndBox* pFndBox = &aFndBox;
1554 _FndLine* pFndLine = 0;
1555 while( pFndBox && 1 == pFndBox->GetLines().Count() )
1557 pFndLine = pFndBox->GetLines()[0];
1558 if( 1 == pFndLine->GetBoxes().Count() )
1559 pFndBox = pFndLine->GetBoxes()[0];
1560 else
1561 pFndBox = 0;
1563 if( pFndBox )
1564 pFndBox->GetLines().ForEach( &lcl_CheckRow, &bMergeSelOk );
1565 else if( pFndLine )
1566 pFndLine->GetBoxes().ForEach( &lcl_CheckCol, &bMergeSelOk );
1567 if( !bMergeSelOk )
1568 eRet = TBLMERGE_TOOCOMPLEX;
1570 else
1571 eRet = TBLMERGE_NOSELECTION;
1573 return eRet;
1576 //Ermittelt die von einer Tabellenselektion betroffenen Tabellen und die
1577 //Union-Rechteckte der Selektionen - auch fuer aufgespaltene Tabellen.
1578 SV_IMPL_PTRARR( SwSelUnions, SwSelUnion* );
1580 SwTwips lcl_CalcWish( const SwLayoutFrm *pCell, long nWish,
1581 const long nAct )
1583 const SwLayoutFrm *pTmp = pCell;
1584 if ( !nWish )
1585 nWish = 1;
1587 const sal_Bool bRTL = pCell->IsRightToLeft();
1588 SwTwips nRet = bRTL ?
1589 nAct - pCell->Frm().Width() :
1592 while ( pTmp )
1594 while ( pTmp->GetPrev() )
1596 pTmp = (SwLayoutFrm*)pTmp->GetPrev();
1597 long nTmp = pTmp->GetFmt()->GetFrmSize().GetWidth();
1598 nRet += ( bRTL ? ( -1 ) : 1 ) * nTmp * nAct / nWish;
1600 pTmp = pTmp->GetUpper()->GetUpper();
1601 if ( pTmp && !pTmp->IsCellFrm() )
1602 pTmp = 0;
1604 return nRet;
1607 /* MA: 20. Sep. 93 wird nicht mehr gebraucht.
1608 static const SwLayoutFrm *GetPrevCell( const SwLayoutFrm *pCell )
1610 const SwLayoutFrm *pLay = pCell->GetPrevLayoutLeaf();
1611 if ( pLay && pLay->IsLayoutFrm() && !pLay->IsTab() )
1613 //GetPrevLayoutLeaf() liefert ggf. auch die Umgebung einer Tab zurueck
1614 //(naehmlich genau dann, wenn die Zelle noch Vorgaenger hat).
1615 const SwFrm *pFrm = pLay->Lower();
1616 while ( pFrm->GetNext() )
1617 pFrm = pFrm->GetNext();
1618 pLay = pFrm->IsTabFrm() ? (SwLayoutFrm*)pFrm : 0;
1620 if ( pLay && pLay->IsTabFrm() )
1622 //GetPrevLayoutLeaf() liefert ggf. auch Tabellen zurueck die letzte
1623 //Zelle dieser Tabelle ist das das gesuchte Blatt.
1624 pLay = ((SwTabFrm*)pLay)->FindLastCntnt()->GetUpper();
1625 while ( !pLay->IsCellFrm() )
1626 pLay = pLay->GetUpper();
1628 return pLay;
1632 void lcl_FindStartEndRow( const SwLayoutFrm *&rpStart,
1633 const SwLayoutFrm *&rpEnd,
1634 const int bChkProtected )
1636 //Start an den Anfang seiner Zeile setzen.
1637 //End an das Ende seiner Zeile setzen.
1638 rpStart = (SwLayoutFrm*)rpStart->GetUpper()->Lower();
1639 while ( rpEnd->GetNext() )
1640 rpEnd = (SwLayoutFrm*)rpEnd->GetNext();
1642 SvPtrarr aSttArr( 8, 8 ), aEndArr( 8, 8 );
1643 const SwLayoutFrm *pTmp;
1644 for( pTmp = rpStart; (FRM_CELL|FRM_ROW) & pTmp->GetType();
1645 pTmp = pTmp->GetUpper() )
1647 void* p = (void*)pTmp;
1648 aSttArr.Insert( p, 0 );
1650 for( pTmp = rpEnd; (FRM_CELL|FRM_ROW) & pTmp->GetType();
1651 pTmp = pTmp->GetUpper() )
1653 void* p = (void*)pTmp;
1654 aEndArr.Insert( p, 0 );
1657 for( USHORT n = 0; n < aEndArr.Count() && n < aSttArr.Count(); ++n )
1658 if( aSttArr[ n ] != aEndArr[ n ] )
1660 // first unequal line or box - all odds are
1661 if( n & 1 ) // 1, 3, 5, ... are boxes
1663 rpStart = (SwLayoutFrm*)aSttArr[ n ];
1664 rpEnd = (SwLayoutFrm*)aEndArr[ n ];
1666 else // 0, 2, 4, ... are lines
1668 // check if start & end line are the first & last Line of the
1669 // box. If not return these cells.
1670 // Else the hole line with all Boxes has to be deleted.
1671 rpStart = (SwLayoutFrm*)aSttArr[ n+1 ];
1672 rpEnd = (SwLayoutFrm*)aEndArr[ n+1 ];
1673 if( n )
1675 const SwCellFrm* pCellFrm = (SwCellFrm*)aSttArr[ n-1 ];
1676 const SwTableLines& rLns = pCellFrm->
1677 GetTabBox()->GetTabLines();
1678 if( rLns[ 0 ] == ((SwRowFrm*)aSttArr[ n ])->GetTabLine() &&
1679 rLns[ rLns.Count() - 1 ] ==
1680 ((SwRowFrm*)aEndArr[ n ])->GetTabLine() )
1682 rpStart = rpEnd = pCellFrm;
1683 while ( rpStart->GetPrev() )
1684 rpStart = (SwLayoutFrm*)rpStart->GetPrev();
1685 while ( rpEnd->GetNext() )
1686 rpEnd = (SwLayoutFrm*)rpEnd->GetNext();
1690 break;
1693 if( !bChkProtected ) // geschuetzte Zellen beachten ?
1694 return;
1697 //Anfang und Ende duerfen nicht auf geschuetzten Zellen liegen.
1698 while ( rpStart->GetFmt()->GetProtect().IsCntntProtected() )
1699 rpStart = (SwLayoutFrm*)rpStart->GetNext();
1700 while ( rpEnd->GetFmt()->GetProtect().IsCntntProtected() )
1701 rpEnd = (SwLayoutFrm*)rpEnd->GetPrev();
1705 void lcl_FindStartEndCol( const SwLayoutFrm *&rpStart,
1706 const SwLayoutFrm *&rpEnd,
1707 const int bChkProtected )
1709 //Start und End senkrecht bis an den Rand der Tabelle denken; es muss
1710 //die Gesamttabelle betrachtet werden, also inklusive Masters und
1711 //Follows.
1712 //Fuer den Start brauchen wir den Mutter-TabellenFrm.
1713 if( !rpStart )
1714 return;
1715 const SwTabFrm *pOrg = rpStart->FindTabFrm();
1716 const SwTabFrm *pTab = pOrg;
1718 SWRECTFN( pTab )
1720 sal_Bool bRTL = pTab->IsRightToLeft();
1721 const long nTmpWish = pOrg->GetFmt()->GetFrmSize().GetWidth();
1722 const long nWish = ( nTmpWish > 0 ) ? nTmpWish : 1;
1724 while ( pTab->IsFollow() )
1726 const SwFrm *pTmp = pTab->FindPrev();
1727 ASSERT( pTmp->IsTabFrm(), "Vorgaenger vom Follow nicht der Master." );
1728 pTab = (const SwTabFrm*)pTmp;
1731 SwTwips nSX = 0;
1732 SwTwips nSX2 = 0;
1734 if ( pTab->GetTable()->IsNewModel() )
1736 nSX = (rpStart->Frm().*fnRect->fnGetLeft )();
1737 nSX2 = (rpStart->Frm().*fnRect->fnGetRight)();
1739 else
1741 const SwTwips nPrtWidth = (pTab->Prt().*fnRect->fnGetWidth)();
1742 nSX = ::lcl_CalcWish( rpStart, nWish, nPrtWidth ) + (pTab->*fnRect->fnGetPrtLeft)();
1743 nSX2 = nSX + (rpStart->GetFmt()->GetFrmSize().GetWidth() * nPrtWidth / nWish);
1746 const SwLayoutFrm *pTmp = pTab->FirstCell();
1748 while ( pTmp &&
1749 (!pTmp->IsCellFrm() ||
1750 ( ( ! bRTL && (pTmp->Frm().*fnRect->fnGetLeft)() < nSX &&
1751 (pTmp->Frm().*fnRect->fnGetRight)()< nSX2 ) ||
1752 bRTL && (pTmp->Frm().*fnRect->fnGetLeft)() > nSX &&
1753 (pTmp->Frm().*fnRect->fnGetRight)()> nSX2 ) ) )
1754 pTmp = pTmp->GetNextLayoutLeaf();
1756 if ( pTmp )
1757 rpStart = pTmp;
1759 pTab = pOrg;
1761 const SwTabFrm* pLastValidTab = pTab;
1762 while ( pTab->GetFollow() )
1765 // Check if pTab->GetFollow() is a valid follow table:
1766 // Only follow tables with at least on non-FollowFlowLine
1767 // should be considered.
1769 if ( pTab->HasFollowFlowLine() )
1771 pTab = pTab->GetFollow();
1772 const SwFrm* pTmpRow = pTab->GetFirstNonHeadlineRow();
1773 if ( pTmpRow && pTmpRow->GetNext() )
1774 pLastValidTab = pTab;
1776 else
1777 pLastValidTab = pTab = pTab->GetFollow();
1779 pTab = pLastValidTab;
1781 SwTwips nEX = 0;
1783 if ( pTab->GetTable()->IsNewModel() )
1785 nEX = (rpEnd->Frm().*fnRect->fnGetLeft )();
1787 else
1789 const SwTwips nPrtWidth = (pTab->Prt().*fnRect->fnGetWidth)();
1790 nEX = ::lcl_CalcWish( rpEnd, nWish, nPrtWidth ) + (pTab->*fnRect->fnGetPrtLeft)();
1793 const SwCntntFrm* pLastCntnt = pTab->FindLastCntnt();
1794 rpEnd = pLastCntnt ? pLastCntnt->GetUpper() : 0;
1795 // --> FME 2006-07-17 #134385# Made code robust. If pTab does not have a lower,
1796 // we would crash here.
1797 if ( !pLastCntnt ) return;
1798 // <--
1800 while( !rpEnd->IsCellFrm() )
1801 rpEnd = rpEnd->GetUpper();
1803 while ( ( bRTL && (rpEnd->Frm().*fnRect->fnGetLeft)() < nEX ) ||
1804 ( ! bRTL && (rpEnd->Frm().*fnRect->fnGetLeft)() > nEX ) )
1806 const SwLayoutFrm* pTmpLeaf = rpEnd->GetPrevLayoutLeaf();
1807 if( !pTmpLeaf || !pTab->IsAnLower( pTmpLeaf ) )
1808 break;
1809 rpEnd = pTmpLeaf;
1812 if( !bChkProtected ) // geschuetzte Zellen beachten ?
1813 return;
1815 //Anfang und Ende duerfen nicht auf geschuetzten Zellen liegen.
1816 //Also muss ggf. nocheinmal rueckwaerts gesucht werden.
1817 while ( rpStart->GetFmt()->GetProtect().IsCntntProtected() )
1819 const SwLayoutFrm *pTmpLeaf = rpStart;
1820 pTmpLeaf = pTmpLeaf->GetNextLayoutLeaf();
1821 while ( pTmpLeaf && (pTmpLeaf->Frm().*fnRect->fnGetLeft)() > nEX )//erstmal die Zeile ueberspr.
1822 pTmpLeaf = pTmpLeaf->GetNextLayoutLeaf();
1823 while ( pTmpLeaf && (pTmpLeaf->Frm().*fnRect->fnGetLeft)() < nSX &&
1824 (pTmpLeaf->Frm().*fnRect->fnGetRight)()< nSX2 )
1825 pTmpLeaf = pTmpLeaf->GetNextLayoutLeaf();
1826 const SwTabFrm *pTmpTab = rpStart->FindTabFrm();
1827 if ( !pTmpTab->IsAnLower( pTmpLeaf ) )
1829 pTmpTab = pTmpTab->GetFollow();
1830 rpStart = pTmpTab->FirstCell();
1831 while ( (rpStart->Frm().*fnRect->fnGetLeft)() < nSX &&
1832 (rpStart->Frm().*fnRect->fnGetRight)()< nSX2 )
1833 rpStart = rpStart->GetNextLayoutLeaf();
1835 else
1836 rpStart = pTmpLeaf;
1838 while ( rpEnd->GetFmt()->GetProtect().IsCntntProtected() )
1840 const SwLayoutFrm *pTmpLeaf = rpEnd;
1841 pTmpLeaf = pTmpLeaf->GetPrevLayoutLeaf();
1842 while ( pTmpLeaf && (pTmpLeaf->Frm().*fnRect->fnGetLeft)() < nEX )//erstmal die Zeile ueberspr.
1843 pTmpLeaf = pTmpLeaf->GetPrevLayoutLeaf();
1844 while ( pTmpLeaf && (pTmpLeaf->Frm().*fnRect->fnGetLeft)() > nEX )
1845 pTmpLeaf = pTmpLeaf->GetPrevLayoutLeaf();
1846 const SwTabFrm *pTmpTab = rpEnd->FindTabFrm();
1847 if ( !pTmpLeaf || !pTmpTab->IsAnLower( pTmpLeaf ) )
1849 pTmpTab = (const SwTabFrm*)pTmpTab->FindPrev();
1850 ASSERT( pTmpTab->IsTabFrm(), "Vorgaenger vom Follow nicht der Master.");
1851 rpEnd = pTmpTab->FindLastCntnt()->GetUpper();
1852 while( !rpEnd->IsCellFrm() )
1853 rpEnd = rpEnd->GetUpper();
1854 while ( (rpEnd->Frm().*fnRect->fnGetLeft)() > nEX )
1855 rpEnd = rpEnd->GetPrevLayoutLeaf();
1857 else
1858 rpEnd = pTmpLeaf;
1863 void MakeSelUnions( SwSelUnions& rUnions, const SwLayoutFrm *pStart,
1864 const SwLayoutFrm *pEnd, const SwTblSearchType eSearchType )
1866 while ( pStart && !pStart->IsCellFrm() )
1867 pStart = pStart->GetUpper();
1868 while ( pEnd && !pEnd->IsCellFrm() )
1869 pEnd = pEnd->GetUpper();
1871 // #112697# Robust:
1872 if ( !pStart || !pEnd )
1874 ASSERT( false, "MakeSelUnions with pStart or pEnd not in CellFrm" )
1875 return;
1878 const SwTabFrm *pTable = pStart->FindTabFrm();
1879 const SwTabFrm *pEndTable = pEnd->FindTabFrm();
1880 if( !pTable || !pEndTable )
1881 return;
1882 BOOL bExchange = FALSE;
1884 if ( pTable != pEndTable )
1886 if ( !pTable->IsAnFollow( pEndTable ) )
1888 ASSERT( pEndTable->IsAnFollow( pTable ), "Tabkette verknotet." );
1889 bExchange = TRUE;
1892 else
1894 SWRECTFN( pTable )
1895 long nSttTop = (pStart->Frm().*fnRect->fnGetTop)();
1896 long nEndTop = (pEnd->Frm().*fnRect->fnGetTop)();
1897 if( nSttTop == nEndTop )
1899 if( (pStart->Frm().*fnRect->fnGetLeft)() >
1900 (pEnd->Frm().*fnRect->fnGetLeft)() )
1901 bExchange = TRUE;
1903 else if( bVert == ( nSttTop < nEndTop ) )
1904 bExchange = TRUE;
1906 if ( bExchange )
1908 const SwLayoutFrm *pTmp = pStart;
1909 pStart = pEnd;
1910 pEnd = pTmp;
1911 //pTable und pEndTable nicht umsortieren, werden unten neu gesetzt.
1912 //MA: 28. Dec. 93 Bug: 5190
1915 //Start und End sind jetzt huebsch sortiert, jetzt muessen sie falls
1916 //erwuenscht noch versetzt werden.
1917 if( nsSwTblSearchType::TBLSEARCH_ROW == ((~nsSwTblSearchType::TBLSEARCH_PROTECT ) & eSearchType ) )
1918 ::lcl_FindStartEndRow( pStart, pEnd, nsSwTblSearchType::TBLSEARCH_PROTECT & eSearchType );
1919 else if( nsSwTblSearchType::TBLSEARCH_COL == ((~nsSwTblSearchType::TBLSEARCH_PROTECT ) & eSearchType ) )
1920 ::lcl_FindStartEndCol( pStart, pEnd, nsSwTblSearchType::TBLSEARCH_PROTECT & eSearchType );
1922 // --> FME 2006-07-17 #134385# Made code robust.
1923 if ( !pEnd ) return;
1924 // <--
1926 //neu besorgen, da sie jetzt verschoben sind. MA: 28. Dec. 93 Bug 5190
1927 pTable = pStart->FindTabFrm();
1928 pEndTable = pEnd->FindTabFrm();
1930 const long nStSz = pStart->GetFmt()->GetFrmSize().GetWidth();
1931 const long nEdSz = pEnd->GetFmt()->GetFrmSize().GetWidth();
1932 const long nWish = Max( 1L, pTable->GetFmt()->GetFrmSize().GetWidth() );
1933 while ( pTable )
1935 SWRECTFN( pTable )
1936 const long nOfst = (pTable->*fnRect->fnGetPrtLeft)();
1937 const long nPrtWidth = (pTable->Prt().*fnRect->fnGetWidth)();
1938 long nSt1 = ::lcl_CalcWish( pStart, nWish, nPrtWidth ) + nOfst;
1939 long nEd1 = ::lcl_CalcWish( pEnd, nWish, nPrtWidth ) + nOfst;
1941 if ( nSt1 <= nEd1 )
1942 nEd1 += (long)((nEdSz * nPrtWidth) / nWish) - 1;
1943 else
1944 nSt1 += (long)((nStSz * nPrtWidth) / nWish) - 1;
1946 long nSt2;
1947 long nEd2;
1948 if( pTable->IsAnLower( pStart ) )
1949 nSt2 = (pStart->Frm().*fnRect->fnGetTop)();
1950 else
1951 nSt2 = (pTable->Frm().*fnRect->fnGetTop)();
1952 if( pTable->IsAnLower( pEnd ) )
1953 nEd2 = (pEnd->Frm().*fnRect->fnGetBottom)();
1954 else
1955 nEd2 = (pTable->Frm().*fnRect->fnGetBottom)();
1956 Point aSt, aEd;
1957 if( nSt1 > nEd1 )
1959 long nTmp = nSt1;
1960 nSt1 = nEd1;
1961 nEd1 = nTmp;
1963 if( nSt2 > nEd2 )
1965 long nTmp = nSt2;
1966 nSt2 = nEd2;
1967 nEd2 = nTmp;
1969 if( bVert )
1971 aSt = Point( nSt2, nSt1 );
1972 aEd = Point( nEd2, nEd1 );
1974 else
1976 aSt = Point( nSt1, nSt2 );
1977 aEd = Point( nEd1, nEd2 );
1980 const Point aDiff( aEd - aSt );
1981 SwRect aUnion( aSt, Size( aDiff.X(), aDiff.Y() ) );
1982 aUnion.Justify();
1984 // fuers
1985 if( !(nsSwTblSearchType::TBLSEARCH_NO_UNION_CORRECT & eSearchType ))
1987 //Leider ist die Union jetzt mit Rundungsfehlern behaftet und dadurch
1988 //wuerden beim Split/Merge fehlertraechtige Umstaende entstehen.
1989 //Um dies zu vermeiden werden jetzt fuer die Table die erste und
1990 //letzte Zelle innerhalb der Union ermittelt und aus genau deren
1991 //Werten wird die Union neu gebildet.
1992 const SwLayoutFrm* pRow = pTable->IsFollow() ?
1993 pTable->GetFirstNonHeadlineRow() :
1994 (const SwLayoutFrm*)pTable->Lower();
1996 while ( pRow && !pRow->Frm().IsOver( aUnion ) )
1997 pRow = (SwLayoutFrm*)pRow->GetNext();
1999 // --> FME 2004-07-26 #i31976#
2000 // A follow flow row may contain emtpy cells. These are not
2001 // considered by FirstCell(). Therefore we have to find
2002 // the first cell manually:
2003 const SwFrm* pTmpCell = 0;
2004 if ( pTable->IsFollow() && pRow && pRow->IsInFollowFlowRow() )
2006 const SwFrm* pTmpRow = pRow;
2007 while ( pTmpRow && pTmpRow->IsRowFrm() )
2009 pTmpCell = static_cast<const SwRowFrm*>(pTmpRow)->Lower();
2010 pTmpRow = static_cast<const SwCellFrm*>(pTmpCell)->Lower();
2012 ASSERT( !pTmpCell || pTmpCell->IsCellFrm(), "Lower of rowframe != cellframe?!" )
2014 // <--
2016 const SwLayoutFrm* pFirst = pTmpCell ?
2017 static_cast<const SwLayoutFrm*>(pTmpCell) :
2018 pRow ?
2019 pRow->FirstCell() :
2022 while ( pFirst && !::IsFrmInTblSel( aUnion, pFirst ) )
2024 if ( pFirst->GetNext() )
2026 pFirst = (const SwLayoutFrm*)pFirst->GetNext();
2027 if ( pFirst->Lower() && pFirst->Lower()->IsRowFrm() )
2028 pFirst = pFirst->FirstCell();
2030 else
2031 pFirst = ::lcl_FindNextCellFrm( pFirst );
2033 const SwLayoutFrm* pLast = 0;
2034 const SwFrm* pLastCntnt = pTable->FindLastCntnt();
2035 if ( pLastCntnt )
2036 pLast = ::lcl_FindCellFrm( pLastCntnt->GetUpper() );
2038 while ( pLast && !::IsFrmInTblSel( aUnion, pLast ) )
2039 pLast = ::lcl_FindCellFrm( pLast->GetPrevLayoutLeaf() );
2041 if ( pFirst && pLast ) //Robust
2043 aUnion = pFirst->Frm();
2044 aUnion.Union( pLast->Frm() );
2046 else
2047 aUnion.Width( 0 );
2050 if( (aUnion.*fnRect->fnGetWidth)() )
2052 SwSelUnion *pTmp = new SwSelUnion( aUnion, (SwTabFrm*)pTable );
2053 rUnions.C40_INSERT( SwSelUnion, pTmp, rUnions.Count() );
2056 pTable = pTable->GetFollow();
2057 if ( pTable != pEndTable && pEndTable->IsAnFollow( pTable ) )
2058 pTable = 0;
2062 BOOL CheckSplitCells( const SwCrsrShell& rShell, USHORT nDiv,
2063 const SwTblSearchType eSearchType )
2065 if( !rShell.IsTableMode() )
2066 rShell.GetCrsr();
2068 return CheckSplitCells( *rShell.getShellCrsr(false), nDiv, eSearchType );
2071 BOOL CheckSplitCells( const SwCursor& rCrsr, USHORT nDiv,
2072 const SwTblSearchType eSearchType )
2074 if( 1 >= nDiv )
2075 return FALSE;
2077 USHORT nMinValue = nDiv * MINLAY;
2079 //Start- und Endzelle besorgen und den naechsten fragen.
2080 Point aPtPos, aMkPos;
2081 const SwShellCrsr* pShCrsr = dynamic_cast<const SwShellCrsr*>(&rCrsr);
2082 if( pShCrsr )
2084 aPtPos = pShCrsr->GetPtPos();
2085 aMkPos = pShCrsr->GetMkPos();
2087 const SwLayoutFrm *pStart = rCrsr.GetCntntNode()->GetFrm(
2088 &aPtPos )->GetUpper(),
2089 *pEnd = rCrsr.GetCntntNode(FALSE)->GetFrm(
2090 &aMkPos )->GetUpper();
2092 SWRECTFN( pStart->GetUpper() )
2094 //Zuerst lassen wir uns die Tabellen und die Rechtecke heraussuchen.
2095 SwSelUnions aUnions;
2097 ::MakeSelUnions( aUnions, pStart, pEnd, eSearchType );
2099 //Jetzt zu jedem Eintrag die Boxen herausfischen und uebertragen.
2100 for ( USHORT i = 0; i < aUnions.Count(); ++i )
2102 SwSelUnion *pUnion = aUnions[i];
2103 const SwTabFrm *pTable = pUnion->GetTable();
2105 // Skip any repeated headlines in the follow:
2106 const SwLayoutFrm* pRow = pTable->IsFollow() ?
2107 pTable->GetFirstNonHeadlineRow() :
2108 (const SwLayoutFrm*)pTable->Lower();
2110 while ( pRow )
2112 if ( pRow->Frm().IsOver( pUnion->GetUnion() ) )
2114 const SwLayoutFrm *pCell = pRow->FirstCell();
2116 while ( pCell && pRow->IsAnLower( pCell ) )
2118 ASSERT( pCell->IsCellFrm(), "Frame ohne Celle" );
2119 if( ::IsFrmInTblSel( pUnion->GetUnion(), pCell ) )
2121 if( (pCell->Frm().*fnRect->fnGetWidth)() < nMinValue )
2122 return FALSE;
2125 if ( pCell->GetNext() )
2127 pCell = (const SwLayoutFrm*)pCell->GetNext();
2128 if ( pCell->Lower() && pCell->Lower()->IsRowFrm() )
2129 pCell = pCell->FirstCell();
2131 else
2132 pCell = ::lcl_FindNextCellFrm( pCell );
2135 pRow = (const SwLayoutFrm*)pRow->GetNext();
2138 return TRUE;
2141 // -------------------------------------------------------------------
2142 // Diese Klassen kopieren die aktuelle Tabellen-Selektion (rBoxes)
2143 // unter Beibehaltung der Tabellen-Struktur in eine eigene Struktur
2144 // neu: SS zum gezielten Loeschen/Retaurieren des Layouts.
2146 void lcl_InsertRow( SwTableLine &rLine, SwLayoutFrm *pUpper, SwFrm *pSibling )
2148 SwRowFrm *pRow = new SwRowFrm( rLine );
2149 if ( pUpper->IsTabFrm() && ((SwTabFrm*)pUpper)->IsFollow() )
2151 SwTabFrm* pTabFrm = (SwTabFrm*)pUpper;
2152 pTabFrm->FindMaster()->InvalidatePos(); //kann die Zeile vielleicht aufnehmen
2154 if ( pSibling && pTabFrm->IsInHeadline( *pSibling ) )
2156 // Skip any repeated headlines in the follow:
2157 pSibling = pTabFrm->GetFirstNonHeadlineRow();
2160 pRow->Paste( pUpper, pSibling );
2161 pRow->RegistFlys();
2165 BOOL _FndBoxCopyCol( const SwTableBox*& rpBox, void* pPara )
2167 _FndPara* pFndPara = (_FndPara*)pPara;
2168 _FndBox* pFndBox = new _FndBox( (SwTableBox*)rpBox, pFndPara->pFndLine );
2169 if( rpBox->GetTabLines().Count() )
2171 _FndPara aPara( *pFndPara, pFndBox );
2172 pFndBox->GetBox()->GetTabLines().ForEach( &_FndLineCopyCol, &aPara );
2173 if( !pFndBox->GetLines().Count() )
2175 delete pFndBox;
2176 return TRUE;
2179 else
2181 SwTableBoxPtr pSrch = (SwTableBoxPtr)rpBox;
2182 USHORT nFndPos;
2183 if( !pFndPara->rBoxes.Seek_Entry( pSrch, &nFndPos ))
2185 delete pFndBox;
2186 return TRUE;
2189 pFndPara->pFndLine->GetBoxes().C40_INSERT( _FndBox, pFndBox,
2190 pFndPara->pFndLine->GetBoxes().Count() );
2191 return TRUE;
2194 BOOL _FndLineCopyCol( const SwTableLine*& rpLine, void* pPara )
2196 _FndPara* pFndPara = (_FndPara*)pPara;
2197 _FndLine* pFndLine = new _FndLine( (SwTableLine*)rpLine, pFndPara->pFndBox );
2198 _FndPara aPara( *pFndPara, pFndLine );
2199 pFndLine->GetLine()->GetTabBoxes().ForEach( &_FndBoxCopyCol, &aPara );
2200 if( pFndLine->GetBoxes().Count() )
2202 pFndPara->pFndBox->GetLines().C40_INSERT( _FndLine, pFndLine,
2203 pFndPara->pFndBox->GetLines().Count() );
2205 else
2206 delete pFndLine;
2207 return TRUE;
2210 void _FndBox::SetTableLines( const SwSelBoxes &rBoxes, const SwTable &rTable )
2212 //Pointer auf die Lines vor und hinter den zu verarbeitenden Bereich
2213 //setzen. Wenn die erste/letzte Zeile in den Bereich eingeschlossen
2214 //sind, so bleiben die Pointer eben einfach 0.
2215 //Gesucht werden zunachst die Positionen der ersten/letzten betroffenen
2216 //Line im Array der SwTable. Damit die 0 fuer 'keine Line' verwand werden
2217 //kann werden die Positionen um 1 nach oben versetzt!
2219 USHORT nStPos = USHRT_MAX;
2220 USHORT nEndPos= 0;
2222 for ( USHORT i = 0; i < rBoxes.Count(); ++i )
2224 SwTableLine *pLine = rBoxes[i]->GetUpper();
2225 while ( pLine->GetUpper() )
2226 pLine = pLine->GetUpper()->GetUpper();
2227 const USHORT nPos = rTable.GetTabLines().GetPos(
2228 (const SwTableLine*&)pLine ) + 1;
2230 ASSERT( nPos != USHRT_MAX, "TableLine not found." );
2232 if( nStPos > nPos )
2233 nStPos = nPos;
2235 if( nEndPos < nPos )
2236 nEndPos = nPos;
2238 if ( nStPos > 1 )
2239 pLineBefore = rTable.GetTabLines()[nStPos - 2];
2240 if ( nEndPos < rTable.GetTabLines().Count() )
2241 pLineBehind = rTable.GetTabLines()[nEndPos];
2244 void _FndBox::SetTableLines( const SwTable &rTable )
2246 // Pointer auf die Lines vor und hinter den zu verarbeitenden Bereich
2247 // setzen. Wenn die erste/letzte Zeile in den Bereich eingeschlossen
2248 // sind, so bleiben die Pointer eben einfach 0.
2249 // Die Positionen der ersten/letzten betroffenen Line im Array der
2250 // SwTable steht in der FndBox. Damit die 0 fuer 'keine Line' verwand
2251 // werdenkann werden die Positionen um 1 nach oben versetzt!
2253 if( !GetLines().Count() )
2254 return;
2256 SwTableLine* pTmpLine = GetLines()[0]->GetLine();
2257 USHORT nPos = rTable.GetTabLines().C40_GETPOS( SwTableLine, pTmpLine );
2258 ASSERT( USHRT_MAX != nPos, "Line steht nicht in der Tabelle" );
2259 if( nPos )
2260 pLineBefore = rTable.GetTabLines()[ nPos - 1 ];
2262 pTmpLine = GetLines()[GetLines().Count()-1]->GetLine();
2263 nPos = rTable.GetTabLines().C40_GETPOS( SwTableLine, pTmpLine );
2264 ASSERT( USHRT_MAX != nPos, "Line steht nicht in der Tabelle" );
2265 if( ++nPos < rTable.GetTabLines().Count() )
2266 pLineBehind = rTable.GetTabLines()[nPos];
2269 inline void UnsetFollow( SwFlowFrm *pTab )
2271 pTab->bIsFollow = FALSE;
2274 void _FndBox::DelFrms( SwTable &rTable )
2276 //Alle Lines zwischen pLineBefore und pLineBehind muessen aus dem
2277 //Layout ausgeschnitten und geloescht werden.
2278 //Entstehen dabei leere Follows so muessen diese vernichtet werden.
2279 //Wird ein Master vernichtet, so muss der Follow Master werden.
2280 //Ein TabFrm muss immer uebrigbleiben.
2282 USHORT nStPos = 0;
2283 USHORT nEndPos= rTable.GetTabLines().Count() - 1;
2284 if( rTable.IsNewModel() && pLineBefore )
2285 rTable.CheckRowSpan( pLineBefore, true );
2286 if ( pLineBefore )
2288 nStPos = rTable.GetTabLines().GetPos(
2289 (const SwTableLine*&)pLineBefore );
2290 ASSERT( nStPos != USHRT_MAX, "Fuchs Du hast die Line gestohlen!" );
2291 ++nStPos;
2293 if( rTable.IsNewModel() && pLineBehind )
2294 rTable.CheckRowSpan( pLineBehind, false );
2295 if ( pLineBehind )
2297 nEndPos = rTable.GetTabLines().GetPos(
2298 (const SwTableLine*&)pLineBehind );
2299 ASSERT( nEndPos != USHRT_MAX, "Fuchs Du hast die Line gestohlen!" );
2300 --nEndPos;
2303 for ( USHORT i = nStPos; i <= nEndPos; ++i)
2305 SwFrmFmt *pFmt = rTable.GetTabLines()[i]->GetFrmFmt();
2306 SwClientIter aIter( *pFmt );
2307 SwClient* pLast = aIter.GoStart();
2308 if( pLast )
2310 do {
2311 SwFrm *pFrm = PTR_CAST( SwFrm, pLast );
2312 if ( pFrm &&
2313 ((SwRowFrm*)pFrm)->GetTabLine() == rTable.GetTabLines()[i] )
2315 BOOL bDel = TRUE;
2316 SwTabFrm *pUp = !pFrm->GetPrev() && !pFrm->GetNext() ?
2317 (SwTabFrm*)pFrm->GetUpper() : 0;
2318 if ( !pUp )
2320 const USHORT nRepeat =
2321 ((SwTabFrm*)pFrm->GetUpper())->GetTable()->GetRowsToRepeat();
2322 if ( nRepeat > 0 &&
2323 ((SwTabFrm*)pFrm->GetUpper())->IsFollow() )
2325 if ( !pFrm->GetNext() )
2327 SwRowFrm* pFirstNonHeadline =
2328 ((SwTabFrm*)pFrm->GetUpper())->GetFirstNonHeadlineRow();
2329 if ( pFirstNonHeadline == pFrm )
2331 pUp = (SwTabFrm*)pFrm->GetUpper();
2336 if ( pUp )
2338 SwTabFrm *pFollow = pUp->GetFollow();
2339 SwTabFrm *pPrev = pUp->IsFollow() ? pUp : 0;
2340 if ( pPrev )
2342 SwFrm *pTmp = pPrev->FindPrev();
2343 ASSERT( pTmp->IsTabFrm(),
2344 "Vorgaenger vom Follow kein Master.");
2345 pPrev = (SwTabFrm*)pTmp;
2347 if ( pPrev )
2349 pPrev->SetFollow( pFollow );
2350 // --> FME 2006-01-31 #i60340# Do not transfer the
2351 // flag from pUp to pPrev. pUp may still have the
2352 // flag set although there is not more follow flow
2353 // line associated with pUp.
2354 pPrev->SetFollowFlowLine( FALSE );
2355 // <--
2357 else if ( pFollow )
2358 ::UnsetFollow( pFollow );
2360 //Ein TabellenFrm muss immer stehenbleiben!
2361 if ( pPrev || pFollow )
2363 // OD 26.08.2003 #i18103# - if table is in a section,
2364 // lock the section, to avoid its delete.
2366 SwSectionFrm* pSctFrm = pUp->FindSctFrm();
2367 bool bOldSectLock = false;
2368 if ( pSctFrm )
2370 bOldSectLock = pSctFrm->IsColLocked();
2371 pSctFrm->ColLock();
2373 pUp->Cut();
2374 if ( pSctFrm && !bOldSectLock )
2376 pSctFrm->ColUnlock();
2379 delete pUp;
2380 bDel = FALSE;//Die Row wird mit in den Abgrund
2381 //gerissen.
2384 if ( bDel )
2386 SwFrm* pTabFrm = pFrm->GetUpper();
2387 if ( pTabFrm->IsTabFrm() &&
2388 !pFrm->GetNext() &&
2389 ((SwTabFrm*)pTabFrm)->GetFollow() )
2391 // We do not delete the follow flow line,
2392 // this will be done automatically in the
2393 // next turn.
2394 ((SwTabFrm*)pTabFrm)->SetFollowFlowLine( FALSE );
2397 pFrm->Cut();
2398 delete pFrm;
2401 } while( 0 != ( pLast = aIter++ ));
2406 BOOL lcl_IsLineOfTblFrm( const SwTabFrm& rTable, const SwFrm& rChk )
2408 const SwTabFrm* pTblFrm = rChk.FindTabFrm();
2409 if( pTblFrm->IsFollow() )
2410 pTblFrm = pTblFrm->FindMaster( true );
2411 return &rTable == pTblFrm;
2415 * lcl_UpdateRepeatedHeadlines
2417 void lcl_UpdateRepeatedHeadlines( SwTabFrm& rTabFrm, bool bCalcLowers )
2419 ASSERT( rTabFrm.IsFollow(), "lcl_UpdateRepeatedHeadlines called for non-follow tab" )
2421 // Delete remaining headlines:
2422 SwRowFrm* pLower = 0;
2423 while ( 0 != ( pLower = (SwRowFrm*)rTabFrm.Lower() ) && pLower->IsRepeatedHeadline() )
2425 pLower->Cut();
2426 delete pLower;
2429 // Insert fresh set of headlines:
2430 pLower = (SwRowFrm*)rTabFrm.Lower();
2431 SwTable& rTable = *rTabFrm.GetTable();
2432 const USHORT nRepeat = rTable.GetRowsToRepeat();
2433 for ( USHORT nIdx = 0; nIdx < nRepeat; ++nIdx )
2435 SwRowFrm* pHeadline = new SwRowFrm(
2436 *rTable.GetTabLines()[ nIdx ] );
2437 pHeadline->SetRepeatedHeadline( true );
2438 pHeadline->Paste( &rTabFrm, pLower );
2439 pHeadline->RegistFlys();
2442 if ( bCalcLowers )
2443 rTabFrm.SetCalcLowers();
2446 void _FndBox::MakeFrms( SwTable &rTable )
2448 //Alle Lines zwischen pLineBefore und pLineBehind muessen im Layout
2449 //wieder neu erzeugt werden.
2450 //Und Zwar fuer alle Auspraegungen der Tabelle (mehrere z.B. im Kopf/Fuss).
2452 USHORT nStPos = 0;
2453 USHORT nEndPos= rTable.GetTabLines().Count() - 1;
2454 if ( pLineBefore )
2456 nStPos = rTable.GetTabLines().GetPos(
2457 (const SwTableLine*&)pLineBefore );
2458 ASSERT( nStPos != USHRT_MAX, "Fuchs Du hast die Line gestohlen!" );
2459 ++nStPos;
2462 if ( pLineBehind )
2464 nEndPos = rTable.GetTabLines().GetPos(
2465 (const SwTableLine*&)pLineBehind );
2466 ASSERT( nEndPos != USHRT_MAX, "Fuchs Du hast die Line gestohlen!" );
2467 --nEndPos;
2469 //Jetzt die grosse Einfuegeoperation fuer alle Tabllen.
2470 SwClientIter aTabIter( *rTable.GetFrmFmt() );
2471 for ( SwTabFrm *pTable = (SwTabFrm*)aTabIter.First( TYPE(SwFrm) ); pTable;
2472 pTable = (SwTabFrm*)aTabIter.Next() )
2474 if ( !pTable->IsFollow() )
2476 SwFrm *pSibling = 0;
2477 SwFrm *pUpperFrm = 0;
2478 int i;
2479 for ( i = rTable.GetTabLines().Count()-1;
2480 i >= 0 && !pSibling; --i )
2482 SwTableLine *pLine = pLineBehind ? pLineBehind :
2483 rTable.GetTabLines()[static_cast<USHORT>(i)];
2484 SwClientIter aIter( *pLine->GetFrmFmt() );
2485 pSibling = (SwFrm*)aIter.First( TYPE(SwFrm) );
2486 while ( pSibling && (
2487 static_cast<SwRowFrm*>(pSibling)->GetTabLine() != pLine ||
2488 !lcl_IsLineOfTblFrm( *pTable, *pSibling ) ||
2489 static_cast<SwRowFrm*>(pSibling)->IsRepeatedHeadline() ||
2490 // --> FME 2005-08-24 #i53647# If !pLineBehind,
2491 // IsInSplitTableRow() should be checked.
2492 ( pLineBehind && pSibling->IsInFollowFlowRow() ) ||
2493 (!pLineBehind && pSibling->IsInSplitTableRow() ) ) )
2494 // <--
2496 pSibling = (SwFrm*)aIter.Next();
2499 if ( pSibling )
2501 pUpperFrm = pSibling->GetUpper();
2502 if ( !pLineBehind )
2503 pSibling = 0;
2505 else
2506 // ???? oder das der Letzte Follow der Tabelle ????
2507 pUpperFrm = pTable;
2509 for ( i = nStPos; (USHORT)i <= nEndPos; ++i )
2510 ::lcl_InsertRow( *rTable.GetTabLines()[static_cast<USHORT>(i)],
2511 (SwLayoutFrm*)pUpperFrm, pSibling );
2512 if ( pUpperFrm->IsTabFrm() )
2513 ((SwTabFrm*)pUpperFrm)->SetCalcLowers();
2515 else if ( rTable.GetRowsToRepeat() > 0 )
2517 // Insert new headlines:
2518 lcl_UpdateRepeatedHeadlines( *pTable, true );
2523 void _FndBox::MakeNewFrms( SwTable &rTable, const USHORT nNumber,
2524 const BOOL bBehind )
2526 //Frms fuer neu eingefuege Zeilen erzeugen.
2527 //bBehind == TRUE: vor pLineBehind
2528 // == FALSE: hinter pLineBefore
2529 const USHORT nBfPos = pLineBefore ?
2530 rTable.GetTabLines().GetPos( (const SwTableLine*&)pLineBefore ) :
2531 USHRT_MAX;
2532 const USHORT nBhPos = pLineBehind ?
2533 rTable.GetTabLines().GetPos( (const SwTableLine*&)pLineBehind ) :
2534 USHRT_MAX;
2536 //nNumber: wie oft ist eingefuegt worden.
2537 //nCnt: wieviele sind nNumber mal eingefuegt worden.
2539 const USHORT nCnt =
2540 ((nBhPos != USHRT_MAX ? nBhPos : rTable.GetTabLines().Count()) -
2541 (nBfPos != USHRT_MAX ? nBfPos + 1 : 0)) / (nNumber + 1);
2543 //Den Master-TabFrm suchen
2544 SwClientIter aTabIter( *rTable.GetFrmFmt() );
2545 SwTabFrm *pTable;
2546 for ( pTable = (SwTabFrm*)aTabIter.First( TYPE(SwFrm) ); pTable;
2547 pTable = (SwTabFrm*)aTabIter.Next() )
2549 if( !pTable->IsFollow() )
2551 SwFrm *pSibling = 0;
2552 SwLayoutFrm *pUpperFrm = 0;
2553 if ( bBehind )
2555 if ( pLineBehind )
2557 SwClientIter aIter( *pLineBehind->GetFrmFmt() );
2558 pSibling = (SwFrm*)aIter.First( TYPE(SwFrm) );
2559 while ( pSibling && (
2560 // only consider row frames associated with pLineBehind:
2561 static_cast<SwRowFrm*>(pSibling)->GetTabLine() != pLineBehind ||
2562 // only consider row frames that are in pTables Master-Follow chain:
2563 !lcl_IsLineOfTblFrm( *pTable, *pSibling ) ||
2564 // only consider row frames that are not repeated headlines:
2565 static_cast<SwRowFrm*>(pSibling)->IsRepeatedHeadline() ||
2566 // only consider row frames that are not follow flow rows
2567 pSibling->IsInFollowFlowRow() ) )
2569 pSibling = (SwFrm*)aIter.Next();
2572 if ( pSibling )
2573 pUpperFrm = pSibling->GetUpper();
2574 else
2576 while( pTable->GetFollow() )
2577 pTable = pTable->GetFollow();
2578 pUpperFrm = pTable;
2580 const USHORT nMax = nBhPos != USHRT_MAX ?
2581 nBhPos : rTable.GetTabLines().Count();
2583 USHORT i = nBfPos != USHRT_MAX ? nBfPos + 1 + nCnt : nCnt;
2585 for ( ; i < nMax; ++i )
2586 ::lcl_InsertRow( *rTable.GetTabLines()[i], pUpperFrm, pSibling );
2587 if ( pUpperFrm->IsTabFrm() )
2588 ((SwTabFrm*)pUpperFrm)->SetCalcLowers();
2590 else //davor einfuegen
2592 USHORT i;
2594 // We are looking for the frame that is behind the row frame
2595 // that should be inserted.
2596 for ( i = 0; !pSibling; ++i )
2598 SwTableLine* pLine = pLineBefore ? pLineBefore : rTable.GetTabLines()[i];
2600 SwClientIter aIter( *pLine->GetFrmFmt() );
2601 pSibling = (SwFrm*)aIter.First( TYPE(SwFrm) );
2603 while ( pSibling && (
2604 // only consider row frames associated with pLineBefore:
2605 static_cast<SwRowFrm*>(pSibling)->GetTabLine() != pLine ||
2606 // only consider row frames that are in pTables Master-Follow chain:
2607 !lcl_IsLineOfTblFrm( *pTable, *pSibling ) ||
2608 // only consider row frames that are not repeated headlines:
2609 static_cast<SwRowFrm*>(pSibling)->IsRepeatedHeadline() ||
2610 // 1. case: pLineBefore == 0:
2611 // only consider row frames that are not follow flow rows
2612 // 2. case: pLineBefore != 0:
2613 // only consider row frames that are not split table rows
2614 // --> FME 2004-11-23 #i37476# If !pLineBefore,
2615 // check IsInFollowFlowRow instead of IsInSplitTableRow.
2616 ( ( !pLineBefore && pSibling->IsInFollowFlowRow() ) ||
2617 ( pLineBefore && pSibling->IsInSplitTableRow() ) ) ) )
2618 // <--
2620 pSibling = (SwFrm*)aIter.Next();
2624 pUpperFrm = pSibling->GetUpper();
2625 if ( pLineBefore )
2626 pSibling = pSibling->GetNext();
2628 USHORT nMax = nBhPos != USHRT_MAX ?
2629 nBhPos - nCnt :
2630 rTable.GetTabLines().Count() - nCnt;
2632 i = nBfPos != USHRT_MAX ? nBfPos + 1 : 0;
2633 for ( ; i < nMax; ++i )
2634 ::lcl_InsertRow( *rTable.GetTabLines()[i],
2635 pUpperFrm, pSibling );
2636 if ( pUpperFrm->IsTabFrm() )
2637 ((SwTabFrm*)pUpperFrm)->SetCalcLowers();
2642 //Die Headlines mussen ggf. auch verarbeitet werden. Um gut arbeitenden
2643 //Code nicht zu zerfasern wird hier nochmals iteriert.
2644 const USHORT nRowsToRepeat = rTable.GetRowsToRepeat();
2645 if ( nRowsToRepeat > 0 &&
2646 ( ( !bBehind && ( nBfPos == USHRT_MAX || nBfPos + 1 < nRowsToRepeat ) ) ||
2647 ( bBehind && ( ( nBfPos == USHRT_MAX && nRowsToRepeat > 1 ) || nBfPos + 2 < nRowsToRepeat ) ) ) )
2649 for ( pTable = (SwTabFrm*)aTabIter.First( TYPE(SwFrm) ); pTable;
2650 pTable = (SwTabFrm*)aTabIter.Next() )
2652 if ( pTable->Lower() )
2654 if ( pTable->IsFollow() )
2656 lcl_UpdateRepeatedHeadlines( *pTable, true );
2659 ASSERT( ((SwRowFrm*)pTable->Lower())->GetTabLine() ==
2660 rTable.GetTabLines()[0], "MakeNewFrms: Table corruption!" )
2666 BOOL _FndBox::AreLinesToRestore( const SwTable &rTable ) const
2668 //Lohnt es sich MakeFrms zu rufen?
2670 if ( !pLineBefore && !pLineBehind && rTable.GetTabLines().Count() )
2671 return TRUE;
2673 USHORT nBfPos;
2674 if(pLineBefore)
2676 const SwTableLine* rLBefore = (const SwTableLine*)pLineBefore;
2677 nBfPos = rTable.GetTabLines().GetPos( rLBefore );
2679 else
2680 nBfPos = USHRT_MAX;
2682 USHORT nBhPos;
2683 if(pLineBehind)
2685 const SwTableLine* rLBehind = (const SwTableLine*)pLineBehind;
2686 nBhPos = rTable.GetTabLines().GetPos( rLBehind );
2688 else
2689 nBhPos = USHRT_MAX;
2691 if ( nBfPos == nBhPos ) //Duerfte eigentlich nie vorkommen.
2693 ASSERT( FALSE, "Table, Loeschen auf keinem Bereich !?!" );
2694 return FALSE;
2697 if ( rTable.GetRowsToRepeat() > 0 )
2699 // ups. sollte unsere zu wiederholende Kopfzeile geloescht worden
2700 // sein??
2701 SwClientIter aIter( *rTable.GetFrmFmt() );
2702 for( SwTabFrm* pTable = (SwTabFrm*)aIter.First( TYPE( SwFrm ));
2703 pTable; pTable = (SwTabFrm*)aIter.Next() )
2705 if( pTable->IsFollow() )
2707 // Insert new headlines:
2708 lcl_UpdateRepeatedHeadlines( *pTable, false );
2713 // Some adjacent lines at the beginning of the table have been deleted:
2714 if ( nBfPos == USHRT_MAX && nBhPos == 0 )
2715 return FALSE;
2717 // Some adjacent lines at the end of the table have been deleted:
2718 if ( nBhPos == USHRT_MAX && nBfPos == (rTable.GetTabLines().Count() - 1) )
2719 return FALSE;
2721 // Some adjacent lines in the middle of the table have been deleted:
2722 if ( nBfPos != USHRT_MAX && nBhPos != USHRT_MAX && (nBfPos + 1) == nBhPos )
2723 return FALSE;
2725 // The structure of the deleted lines is more complex due to split lines.
2726 // A call of MakeFrms() is necessary.
2727 return TRUE;