update dev300-m58
[ooovba.git] / sw / source / core / frmedt / tblsel.cxx
blob4719448b3e6b6d0100b21b02ab61d77a5c45ab48
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
1465 pDoc->Move( aRg, rInsPosNd, IDocumentContentOperations::DOC_MOVEDEFAULT );
1466 // wo steht jetzt aInsPos ??
1468 if( bCalcWidth )
1469 bCalcWidth = FALSE; // eine Zeile fertig
1471 // den initialen TextNode ueberspringen
1472 rInsPosNd.Assign( pDoc->GetNodes(),
1473 rInsPosNd.GetNode().EndOfSectionIndex() - 2 );
1474 pTxtNd = rInsPosNd.GetNode().GetTxtNode();
1475 if( pTxtNd )
1476 aInsPos.nContent.Assign( pTxtNd, pTxtNd->GetTxt().Len() );
1479 // in der MergeBox sollte jetzt der gesamte Text stehen
1480 // loesche jetzt noch den initialen TextNode
1481 ASSERT( (*ppMergeBox)->GetSttIdx()+2 <
1482 (*ppMergeBox)->GetSttNd()->EndOfSectionIndex(),
1483 "leere Box" );
1484 SwNodeIndex aIdx( *(*ppMergeBox)->GetSttNd()->EndOfSectionNode(), -1 );
1485 pDoc->GetNodes().Delete( aIdx, 1 );
1488 // setze die Breite der Box
1489 (*ppMergeBox)->GetFrmFmt()->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nWidth, 0 ));
1490 if( pUndo )
1491 pUndo->AddNewBox( (*ppMergeBox)->GetSttIdx() );
1495 static BOOL lcl_CheckCol( const _FndBox*& rpFndBox, void* pPara );
1497 static BOOL lcl_CheckRow( const _FndLine*& rpFndLine, void* pPara )
1499 ((_FndLine*)rpFndLine)->GetBoxes().ForEach( &lcl_CheckCol, pPara );
1500 return *(BOOL*)pPara;
1503 static BOOL lcl_CheckCol( const _FndBox*& rpFndBox, void* pPara )
1505 if( !rpFndBox->GetBox()->GetSttNd() )
1507 if( rpFndBox->GetLines().Count() !=
1508 rpFndBox->GetBox()->GetTabLines().Count() )
1509 *((BOOL*)pPara) = FALSE;
1510 else
1511 ((_FndBox*)rpFndBox)->GetLines().ForEach( &lcl_CheckRow, pPara );
1513 // Box geschuetzt ??
1514 else if( rpFndBox->GetBox()->GetFrmFmt()->GetProtect().IsCntntProtected() )
1515 *((BOOL*)pPara) = FALSE;
1516 return *(BOOL*)pPara;
1520 USHORT CheckMergeSel( const SwPaM& rPam )
1522 SwSelBoxes aBoxes;
1523 //JP 24.09.96: Merge mit wiederholenden TabellenHeadline funktioniert nicht
1524 // richtig. Warum nicht Point 0,0 benutzen? Dann ist garantiert,
1525 // das die 1. Headline mit drin ist.
1526 Point aPt;
1527 const SwLayoutFrm *pStart = rPam.GetCntntNode()->GetFrm(
1528 &aPt )->GetUpper(),
1529 *pEnd = rPam.GetCntntNode(FALSE)->GetFrm(
1530 &aPt )->GetUpper();
1531 GetTblSel( pStart, pEnd, aBoxes, 0 );
1532 return CheckMergeSel( aBoxes );
1535 USHORT CheckMergeSel( const SwSelBoxes& rBoxes )
1537 USHORT eRet = TBLMERGE_NOSELECTION;
1538 if( rBoxes.Count() )
1540 eRet = TBLMERGE_OK;
1542 _FndBox aFndBox( 0, 0 );
1543 _FndPara aPara( rBoxes, &aFndBox );
1544 const SwTableNode* pTblNd = aPara.rBoxes[0]->GetSttNd()->FindTableNode();
1545 ((SwTable&)pTblNd->GetTable()).GetTabLines().ForEach(
1546 &_FndLineCopyCol, &aPara );
1547 if( aFndBox.GetLines().Count() )
1549 BOOL bMergeSelOk = TRUE;
1550 _FndBox* pFndBox = &aFndBox;
1551 _FndLine* pFndLine = 0;
1552 while( pFndBox && 1 == pFndBox->GetLines().Count() )
1554 pFndLine = pFndBox->GetLines()[0];
1555 if( 1 == pFndLine->GetBoxes().Count() )
1556 pFndBox = pFndLine->GetBoxes()[0];
1557 else
1558 pFndBox = 0;
1560 if( pFndBox )
1561 pFndBox->GetLines().ForEach( &lcl_CheckRow, &bMergeSelOk );
1562 else if( pFndLine )
1563 pFndLine->GetBoxes().ForEach( &lcl_CheckCol, &bMergeSelOk );
1564 if( !bMergeSelOk )
1565 eRet = TBLMERGE_TOOCOMPLEX;
1567 else
1568 eRet = TBLMERGE_NOSELECTION;
1570 return eRet;
1573 //Ermittelt die von einer Tabellenselektion betroffenen Tabellen und die
1574 //Union-Rechteckte der Selektionen - auch fuer aufgespaltene Tabellen.
1575 SV_IMPL_PTRARR( SwSelUnions, SwSelUnion* );
1577 SwTwips lcl_CalcWish( const SwLayoutFrm *pCell, long nWish,
1578 const long nAct )
1580 const SwLayoutFrm *pTmp = pCell;
1581 if ( !nWish )
1582 nWish = 1;
1584 const sal_Bool bRTL = pCell->IsRightToLeft();
1585 SwTwips nRet = bRTL ?
1586 nAct - pCell->Frm().Width() :
1589 while ( pTmp )
1591 while ( pTmp->GetPrev() )
1593 pTmp = (SwLayoutFrm*)pTmp->GetPrev();
1594 long nTmp = pTmp->GetFmt()->GetFrmSize().GetWidth();
1595 nRet += ( bRTL ? ( -1 ) : 1 ) * nTmp * nAct / nWish;
1597 pTmp = pTmp->GetUpper()->GetUpper();
1598 if ( pTmp && !pTmp->IsCellFrm() )
1599 pTmp = 0;
1601 return nRet;
1604 /* MA: 20. Sep. 93 wird nicht mehr gebraucht.
1605 static const SwLayoutFrm *GetPrevCell( const SwLayoutFrm *pCell )
1607 const SwLayoutFrm *pLay = pCell->GetPrevLayoutLeaf();
1608 if ( pLay && pLay->IsLayoutFrm() && !pLay->IsTab() )
1610 //GetPrevLayoutLeaf() liefert ggf. auch die Umgebung einer Tab zurueck
1611 //(naehmlich genau dann, wenn die Zelle noch Vorgaenger hat).
1612 const SwFrm *pFrm = pLay->Lower();
1613 while ( pFrm->GetNext() )
1614 pFrm = pFrm->GetNext();
1615 pLay = pFrm->IsTabFrm() ? (SwLayoutFrm*)pFrm : 0;
1617 if ( pLay && pLay->IsTabFrm() )
1619 //GetPrevLayoutLeaf() liefert ggf. auch Tabellen zurueck die letzte
1620 //Zelle dieser Tabelle ist das das gesuchte Blatt.
1621 pLay = ((SwTabFrm*)pLay)->FindLastCntnt()->GetUpper();
1622 while ( !pLay->IsCellFrm() )
1623 pLay = pLay->GetUpper();
1625 return pLay;
1629 void lcl_FindStartEndRow( const SwLayoutFrm *&rpStart,
1630 const SwLayoutFrm *&rpEnd,
1631 const int bChkProtected )
1633 //Start an den Anfang seiner Zeile setzen.
1634 //End an das Ende seiner Zeile setzen.
1635 rpStart = (SwLayoutFrm*)rpStart->GetUpper()->Lower();
1636 while ( rpEnd->GetNext() )
1637 rpEnd = (SwLayoutFrm*)rpEnd->GetNext();
1639 SvPtrarr aSttArr( 8, 8 ), aEndArr( 8, 8 );
1640 const SwLayoutFrm *pTmp;
1641 for( pTmp = rpStart; (FRM_CELL|FRM_ROW) & pTmp->GetType();
1642 pTmp = pTmp->GetUpper() )
1644 void* p = (void*)pTmp;
1645 aSttArr.Insert( p, 0 );
1647 for( pTmp = rpEnd; (FRM_CELL|FRM_ROW) & pTmp->GetType();
1648 pTmp = pTmp->GetUpper() )
1650 void* p = (void*)pTmp;
1651 aEndArr.Insert( p, 0 );
1654 for( USHORT n = 0; n < aEndArr.Count() && n < aSttArr.Count(); ++n )
1655 if( aSttArr[ n ] != aEndArr[ n ] )
1657 // first unequal line or box - all odds are
1658 if( n & 1 ) // 1, 3, 5, ... are boxes
1660 rpStart = (SwLayoutFrm*)aSttArr[ n ];
1661 rpEnd = (SwLayoutFrm*)aEndArr[ n ];
1663 else // 0, 2, 4, ... are lines
1665 // check if start & end line are the first & last Line of the
1666 // box. If not return these cells.
1667 // Else the hole line with all Boxes has to be deleted.
1668 rpStart = (SwLayoutFrm*)aSttArr[ n+1 ];
1669 rpEnd = (SwLayoutFrm*)aEndArr[ n+1 ];
1670 if( n )
1672 const SwCellFrm* pCellFrm = (SwCellFrm*)aSttArr[ n-1 ];
1673 const SwTableLines& rLns = pCellFrm->
1674 GetTabBox()->GetTabLines();
1675 if( rLns[ 0 ] == ((SwRowFrm*)aSttArr[ n ])->GetTabLine() &&
1676 rLns[ rLns.Count() - 1 ] ==
1677 ((SwRowFrm*)aEndArr[ n ])->GetTabLine() )
1679 rpStart = rpEnd = pCellFrm;
1680 while ( rpStart->GetPrev() )
1681 rpStart = (SwLayoutFrm*)rpStart->GetPrev();
1682 while ( rpEnd->GetNext() )
1683 rpEnd = (SwLayoutFrm*)rpEnd->GetNext();
1687 break;
1690 if( !bChkProtected ) // geschuetzte Zellen beachten ?
1691 return;
1694 //Anfang und Ende duerfen nicht auf geschuetzten Zellen liegen.
1695 while ( rpStart->GetFmt()->GetProtect().IsCntntProtected() )
1696 rpStart = (SwLayoutFrm*)rpStart->GetNext();
1697 while ( rpEnd->GetFmt()->GetProtect().IsCntntProtected() )
1698 rpEnd = (SwLayoutFrm*)rpEnd->GetPrev();
1702 void lcl_FindStartEndCol( const SwLayoutFrm *&rpStart,
1703 const SwLayoutFrm *&rpEnd,
1704 const int bChkProtected )
1706 //Start und End senkrecht bis an den Rand der Tabelle denken; es muss
1707 //die Gesamttabelle betrachtet werden, also inklusive Masters und
1708 //Follows.
1709 //Fuer den Start brauchen wir den Mutter-TabellenFrm.
1710 if( !rpStart )
1711 return;
1712 const SwTabFrm *pOrg = rpStart->FindTabFrm();
1713 const SwTabFrm *pTab = pOrg;
1715 SWRECTFN( pTab )
1717 sal_Bool bRTL = pTab->IsRightToLeft();
1718 const long nTmpWish = pOrg->GetFmt()->GetFrmSize().GetWidth();
1719 const long nWish = ( nTmpWish > 0 ) ? nTmpWish : 1;
1721 while ( pTab->IsFollow() )
1723 const SwFrm *pTmp = pTab->FindPrev();
1724 ASSERT( pTmp->IsTabFrm(), "Vorgaenger vom Follow nicht der Master." );
1725 pTab = (const SwTabFrm*)pTmp;
1728 SwTwips nSX = 0;
1729 SwTwips nSX2 = 0;
1731 if ( pTab->GetTable()->IsNewModel() )
1733 nSX = (rpStart->Frm().*fnRect->fnGetLeft )();
1734 nSX2 = (rpStart->Frm().*fnRect->fnGetRight)();
1736 else
1738 const SwTwips nPrtWidth = (pTab->Prt().*fnRect->fnGetWidth)();
1739 nSX = ::lcl_CalcWish( rpStart, nWish, nPrtWidth ) + (pTab->*fnRect->fnGetPrtLeft)();
1740 nSX2 = nSX + (rpStart->GetFmt()->GetFrmSize().GetWidth() * nPrtWidth / nWish);
1743 const SwLayoutFrm *pTmp = pTab->FirstCell();
1745 while ( pTmp &&
1746 (!pTmp->IsCellFrm() ||
1747 ( ( ! bRTL && (pTmp->Frm().*fnRect->fnGetLeft)() < nSX &&
1748 (pTmp->Frm().*fnRect->fnGetRight)()< nSX2 ) ||
1749 bRTL && (pTmp->Frm().*fnRect->fnGetLeft)() > nSX &&
1750 (pTmp->Frm().*fnRect->fnGetRight)()> nSX2 ) ) )
1751 pTmp = pTmp->GetNextLayoutLeaf();
1753 if ( pTmp )
1754 rpStart = pTmp;
1756 pTab = pOrg;
1758 const SwTabFrm* pLastValidTab = pTab;
1759 while ( pTab->GetFollow() )
1762 // Check if pTab->GetFollow() is a valid follow table:
1763 // Only follow tables with at least on non-FollowFlowLine
1764 // should be considered.
1766 if ( pTab->HasFollowFlowLine() )
1768 pTab = pTab->GetFollow();
1769 const SwFrm* pTmpRow = pTab->GetFirstNonHeadlineRow();
1770 if ( pTmpRow && pTmpRow->GetNext() )
1771 pLastValidTab = pTab;
1773 else
1774 pLastValidTab = pTab = pTab->GetFollow();
1776 pTab = pLastValidTab;
1778 SwTwips nEX = 0;
1780 if ( pTab->GetTable()->IsNewModel() )
1782 nEX = (rpEnd->Frm().*fnRect->fnGetLeft )();
1784 else
1786 const SwTwips nPrtWidth = (pTab->Prt().*fnRect->fnGetWidth)();
1787 nEX = ::lcl_CalcWish( rpEnd, nWish, nPrtWidth ) + (pTab->*fnRect->fnGetPrtLeft)();
1790 const SwCntntFrm* pLastCntnt = pTab->FindLastCntnt();
1791 rpEnd = pLastCntnt ? pLastCntnt->GetUpper() : 0;
1792 // --> FME 2006-07-17 #134385# Made code robust. If pTab does not have a lower,
1793 // we would crash here.
1794 if ( !pLastCntnt ) return;
1795 // <--
1797 while( !rpEnd->IsCellFrm() )
1798 rpEnd = rpEnd->GetUpper();
1800 while ( ( bRTL && (rpEnd->Frm().*fnRect->fnGetLeft)() < nEX ) ||
1801 ( ! bRTL && (rpEnd->Frm().*fnRect->fnGetLeft)() > nEX ) )
1803 const SwLayoutFrm* pTmpLeaf = rpEnd->GetPrevLayoutLeaf();
1804 if( !pTmpLeaf || !pTab->IsAnLower( pTmpLeaf ) )
1805 break;
1806 rpEnd = pTmpLeaf;
1809 if( !bChkProtected ) // geschuetzte Zellen beachten ?
1810 return;
1812 //Anfang und Ende duerfen nicht auf geschuetzten Zellen liegen.
1813 //Also muss ggf. nocheinmal rueckwaerts gesucht werden.
1814 while ( rpStart->GetFmt()->GetProtect().IsCntntProtected() )
1816 const SwLayoutFrm *pTmpLeaf = rpStart;
1817 pTmpLeaf = pTmpLeaf->GetNextLayoutLeaf();
1818 while ( pTmpLeaf && (pTmpLeaf->Frm().*fnRect->fnGetLeft)() > nEX )//erstmal die Zeile ueberspr.
1819 pTmpLeaf = pTmpLeaf->GetNextLayoutLeaf();
1820 while ( pTmpLeaf && (pTmpLeaf->Frm().*fnRect->fnGetLeft)() < nSX &&
1821 (pTmpLeaf->Frm().*fnRect->fnGetRight)()< nSX2 )
1822 pTmpLeaf = pTmpLeaf->GetNextLayoutLeaf();
1823 const SwTabFrm *pTmpTab = rpStart->FindTabFrm();
1824 if ( !pTmpTab->IsAnLower( pTmpLeaf ) )
1826 pTmpTab = pTmpTab->GetFollow();
1827 rpStart = pTmpTab->FirstCell();
1828 while ( (rpStart->Frm().*fnRect->fnGetLeft)() < nSX &&
1829 (rpStart->Frm().*fnRect->fnGetRight)()< nSX2 )
1830 rpStart = rpStart->GetNextLayoutLeaf();
1832 else
1833 rpStart = pTmpLeaf;
1835 while ( rpEnd->GetFmt()->GetProtect().IsCntntProtected() )
1837 const SwLayoutFrm *pTmpLeaf = rpEnd;
1838 pTmpLeaf = pTmpLeaf->GetPrevLayoutLeaf();
1839 while ( pTmpLeaf && (pTmpLeaf->Frm().*fnRect->fnGetLeft)() < nEX )//erstmal die Zeile ueberspr.
1840 pTmpLeaf = pTmpLeaf->GetPrevLayoutLeaf();
1841 while ( pTmpLeaf && (pTmpLeaf->Frm().*fnRect->fnGetLeft)() > nEX )
1842 pTmpLeaf = pTmpLeaf->GetPrevLayoutLeaf();
1843 const SwTabFrm *pTmpTab = rpEnd->FindTabFrm();
1844 if ( !pTmpLeaf || !pTmpTab->IsAnLower( pTmpLeaf ) )
1846 pTmpTab = (const SwTabFrm*)pTmpTab->FindPrev();
1847 ASSERT( pTmpTab->IsTabFrm(), "Vorgaenger vom Follow nicht der Master.");
1848 rpEnd = pTmpTab->FindLastCntnt()->GetUpper();
1849 while( !rpEnd->IsCellFrm() )
1850 rpEnd = rpEnd->GetUpper();
1851 while ( (rpEnd->Frm().*fnRect->fnGetLeft)() > nEX )
1852 rpEnd = rpEnd->GetPrevLayoutLeaf();
1854 else
1855 rpEnd = pTmpLeaf;
1860 void MakeSelUnions( SwSelUnions& rUnions, const SwLayoutFrm *pStart,
1861 const SwLayoutFrm *pEnd, const SwTblSearchType eSearchType )
1863 while ( pStart && !pStart->IsCellFrm() )
1864 pStart = pStart->GetUpper();
1865 while ( pEnd && !pEnd->IsCellFrm() )
1866 pEnd = pEnd->GetUpper();
1868 // #112697# Robust:
1869 if ( !pStart || !pEnd )
1871 ASSERT( false, "MakeSelUnions with pStart or pEnd not in CellFrm" )
1872 return;
1875 const SwTabFrm *pTable = pStart->FindTabFrm();
1876 const SwTabFrm *pEndTable = pEnd->FindTabFrm();
1877 if( !pTable || !pEndTable )
1878 return;
1879 BOOL bExchange = FALSE;
1881 if ( pTable != pEndTable )
1883 if ( !pTable->IsAnFollow( pEndTable ) )
1885 ASSERT( pEndTable->IsAnFollow( pTable ), "Tabkette verknotet." );
1886 bExchange = TRUE;
1889 else
1891 SWRECTFN( pTable )
1892 long nSttTop = (pStart->Frm().*fnRect->fnGetTop)();
1893 long nEndTop = (pEnd->Frm().*fnRect->fnGetTop)();
1894 if( nSttTop == nEndTop )
1896 if( (pStart->Frm().*fnRect->fnGetLeft)() >
1897 (pEnd->Frm().*fnRect->fnGetLeft)() )
1898 bExchange = TRUE;
1900 else if( bVert == ( nSttTop < nEndTop ) )
1901 bExchange = TRUE;
1903 if ( bExchange )
1905 const SwLayoutFrm *pTmp = pStart;
1906 pStart = pEnd;
1907 pEnd = pTmp;
1908 //pTable und pEndTable nicht umsortieren, werden unten neu gesetzt.
1909 //MA: 28. Dec. 93 Bug: 5190
1912 //Start und End sind jetzt huebsch sortiert, jetzt muessen sie falls
1913 //erwuenscht noch versetzt werden.
1914 if( nsSwTblSearchType::TBLSEARCH_ROW == ((~nsSwTblSearchType::TBLSEARCH_PROTECT ) & eSearchType ) )
1915 ::lcl_FindStartEndRow( pStart, pEnd, nsSwTblSearchType::TBLSEARCH_PROTECT & eSearchType );
1916 else if( nsSwTblSearchType::TBLSEARCH_COL == ((~nsSwTblSearchType::TBLSEARCH_PROTECT ) & eSearchType ) )
1917 ::lcl_FindStartEndCol( pStart, pEnd, nsSwTblSearchType::TBLSEARCH_PROTECT & eSearchType );
1919 // --> FME 2006-07-17 #134385# Made code robust.
1920 if ( !pEnd ) return;
1921 // <--
1923 //neu besorgen, da sie jetzt verschoben sind. MA: 28. Dec. 93 Bug 5190
1924 pTable = pStart->FindTabFrm();
1925 pEndTable = pEnd->FindTabFrm();
1927 const long nStSz = pStart->GetFmt()->GetFrmSize().GetWidth();
1928 const long nEdSz = pEnd->GetFmt()->GetFrmSize().GetWidth();
1929 const long nWish = Max( 1L, pTable->GetFmt()->GetFrmSize().GetWidth() );
1930 while ( pTable )
1932 SWRECTFN( pTable )
1933 const long nOfst = (pTable->*fnRect->fnGetPrtLeft)();
1934 const long nPrtWidth = (pTable->Prt().*fnRect->fnGetWidth)();
1935 long nSt1 = ::lcl_CalcWish( pStart, nWish, nPrtWidth ) + nOfst;
1936 long nEd1 = ::lcl_CalcWish( pEnd, nWish, nPrtWidth ) + nOfst;
1938 if ( nSt1 <= nEd1 )
1939 nEd1 += (long)((nEdSz * nPrtWidth) / nWish) - 1;
1940 else
1941 nSt1 += (long)((nStSz * nPrtWidth) / nWish) - 1;
1943 long nSt2;
1944 long nEd2;
1945 if( pTable->IsAnLower( pStart ) )
1946 nSt2 = (pStart->Frm().*fnRect->fnGetTop)();
1947 else
1948 nSt2 = (pTable->Frm().*fnRect->fnGetTop)();
1949 if( pTable->IsAnLower( pEnd ) )
1950 nEd2 = (pEnd->Frm().*fnRect->fnGetBottom)();
1951 else
1952 nEd2 = (pTable->Frm().*fnRect->fnGetBottom)();
1953 Point aSt, aEd;
1954 if( nSt1 > nEd1 )
1956 long nTmp = nSt1;
1957 nSt1 = nEd1;
1958 nEd1 = nTmp;
1960 if( nSt2 > nEd2 )
1962 long nTmp = nSt2;
1963 nSt2 = nEd2;
1964 nEd2 = nTmp;
1966 if( bVert )
1968 aSt = Point( nSt2, nSt1 );
1969 aEd = Point( nEd2, nEd1 );
1971 else
1973 aSt = Point( nSt1, nSt2 );
1974 aEd = Point( nEd1, nEd2 );
1977 const Point aDiff( aEd - aSt );
1978 SwRect aUnion( aSt, Size( aDiff.X(), aDiff.Y() ) );
1979 aUnion.Justify();
1981 // fuers
1982 if( !(nsSwTblSearchType::TBLSEARCH_NO_UNION_CORRECT & eSearchType ))
1984 //Leider ist die Union jetzt mit Rundungsfehlern behaftet und dadurch
1985 //wuerden beim Split/Merge fehlertraechtige Umstaende entstehen.
1986 //Um dies zu vermeiden werden jetzt fuer die Table die erste und
1987 //letzte Zelle innerhalb der Union ermittelt und aus genau deren
1988 //Werten wird die Union neu gebildet.
1989 const SwLayoutFrm* pRow = pTable->IsFollow() ?
1990 pTable->GetFirstNonHeadlineRow() :
1991 (const SwLayoutFrm*)pTable->Lower();
1993 while ( pRow && !pRow->Frm().IsOver( aUnion ) )
1994 pRow = (SwLayoutFrm*)pRow->GetNext();
1996 // --> FME 2004-07-26 #i31976#
1997 // A follow flow row may contain emtpy cells. These are not
1998 // considered by FirstCell(). Therefore we have to find
1999 // the first cell manually:
2000 const SwFrm* pTmpCell = 0;
2001 if ( pTable->IsFollow() && pRow && pRow->IsInFollowFlowRow() )
2003 const SwFrm* pTmpRow = pRow;
2004 while ( pTmpRow && pTmpRow->IsRowFrm() )
2006 pTmpCell = static_cast<const SwRowFrm*>(pTmpRow)->Lower();
2007 pTmpRow = static_cast<const SwCellFrm*>(pTmpCell)->Lower();
2009 ASSERT( !pTmpCell || pTmpCell->IsCellFrm(), "Lower of rowframe != cellframe?!" )
2011 // <--
2013 const SwLayoutFrm* pFirst = pTmpCell ?
2014 static_cast<const SwLayoutFrm*>(pTmpCell) :
2015 pRow ?
2016 pRow->FirstCell() :
2019 while ( pFirst && !::IsFrmInTblSel( aUnion, pFirst ) )
2021 if ( pFirst->GetNext() )
2023 pFirst = (const SwLayoutFrm*)pFirst->GetNext();
2024 if ( pFirst->Lower() && pFirst->Lower()->IsRowFrm() )
2025 pFirst = pFirst->FirstCell();
2027 else
2028 pFirst = ::lcl_FindNextCellFrm( pFirst );
2030 const SwLayoutFrm* pLast = 0;
2031 const SwFrm* pLastCntnt = pTable->FindLastCntnt();
2032 if ( pLastCntnt )
2033 pLast = ::lcl_FindCellFrm( pLastCntnt->GetUpper() );
2035 while ( pLast && !::IsFrmInTblSel( aUnion, pLast ) )
2036 pLast = ::lcl_FindCellFrm( pLast->GetPrevLayoutLeaf() );
2038 if ( pFirst && pLast ) //Robust
2040 aUnion = pFirst->Frm();
2041 aUnion.Union( pLast->Frm() );
2043 else
2044 aUnion.Width( 0 );
2047 if( (aUnion.*fnRect->fnGetWidth)() )
2049 SwSelUnion *pTmp = new SwSelUnion( aUnion, (SwTabFrm*)pTable );
2050 rUnions.C40_INSERT( SwSelUnion, pTmp, rUnions.Count() );
2053 pTable = pTable->GetFollow();
2054 if ( pTable != pEndTable && pEndTable->IsAnFollow( pTable ) )
2055 pTable = 0;
2059 BOOL CheckSplitCells( const SwCrsrShell& rShell, USHORT nDiv,
2060 const SwTblSearchType eSearchType )
2062 if( !rShell.IsTableMode() )
2063 rShell.GetCrsr();
2065 return CheckSplitCells( *rShell.getShellCrsr(false), nDiv, eSearchType );
2068 BOOL CheckSplitCells( const SwCursor& rCrsr, USHORT nDiv,
2069 const SwTblSearchType eSearchType )
2071 if( 1 >= nDiv )
2072 return FALSE;
2074 USHORT nMinValue = nDiv * MINLAY;
2076 //Start- und Endzelle besorgen und den naechsten fragen.
2077 Point aPtPos, aMkPos;
2078 const SwShellCrsr* pShCrsr = dynamic_cast<const SwShellCrsr*>(&rCrsr);
2079 if( pShCrsr )
2081 aPtPos = pShCrsr->GetPtPos();
2082 aMkPos = pShCrsr->GetMkPos();
2084 const SwLayoutFrm *pStart = rCrsr.GetCntntNode()->GetFrm(
2085 &aPtPos )->GetUpper(),
2086 *pEnd = rCrsr.GetCntntNode(FALSE)->GetFrm(
2087 &aMkPos )->GetUpper();
2089 SWRECTFN( pStart->GetUpper() )
2091 //Zuerst lassen wir uns die Tabellen und die Rechtecke heraussuchen.
2092 SwSelUnions aUnions;
2094 ::MakeSelUnions( aUnions, pStart, pEnd, eSearchType );
2096 //Jetzt zu jedem Eintrag die Boxen herausfischen und uebertragen.
2097 for ( USHORT i = 0; i < aUnions.Count(); ++i )
2099 SwSelUnion *pUnion = aUnions[i];
2100 const SwTabFrm *pTable = pUnion->GetTable();
2102 // Skip any repeated headlines in the follow:
2103 const SwLayoutFrm* pRow = pTable->IsFollow() ?
2104 pTable->GetFirstNonHeadlineRow() :
2105 (const SwLayoutFrm*)pTable->Lower();
2107 while ( pRow )
2109 if ( pRow->Frm().IsOver( pUnion->GetUnion() ) )
2111 const SwLayoutFrm *pCell = pRow->FirstCell();
2113 while ( pCell && pRow->IsAnLower( pCell ) )
2115 ASSERT( pCell->IsCellFrm(), "Frame ohne Celle" );
2116 if( ::IsFrmInTblSel( pUnion->GetUnion(), pCell ) )
2118 if( (pCell->Frm().*fnRect->fnGetWidth)() < nMinValue )
2119 return FALSE;
2122 if ( pCell->GetNext() )
2124 pCell = (const SwLayoutFrm*)pCell->GetNext();
2125 if ( pCell->Lower() && pCell->Lower()->IsRowFrm() )
2126 pCell = pCell->FirstCell();
2128 else
2129 pCell = ::lcl_FindNextCellFrm( pCell );
2132 pRow = (const SwLayoutFrm*)pRow->GetNext();
2135 return TRUE;
2138 // -------------------------------------------------------------------
2139 // Diese Klassen kopieren die aktuelle Tabellen-Selektion (rBoxes)
2140 // unter Beibehaltung der Tabellen-Struktur in eine eigene Struktur
2141 // neu: SS zum gezielten Loeschen/Retaurieren des Layouts.
2143 void lcl_InsertRow( SwTableLine &rLine, SwLayoutFrm *pUpper, SwFrm *pSibling )
2145 SwRowFrm *pRow = new SwRowFrm( rLine );
2146 if ( pUpper->IsTabFrm() && ((SwTabFrm*)pUpper)->IsFollow() )
2148 SwTabFrm* pTabFrm = (SwTabFrm*)pUpper;
2149 pTabFrm->FindMaster()->InvalidatePos(); //kann die Zeile vielleicht aufnehmen
2151 if ( pSibling && pTabFrm->IsInHeadline( *pSibling ) )
2153 // Skip any repeated headlines in the follow:
2154 pSibling = pTabFrm->GetFirstNonHeadlineRow();
2157 pRow->Paste( pUpper, pSibling );
2158 pRow->RegistFlys();
2162 BOOL _FndBoxCopyCol( const SwTableBox*& rpBox, void* pPara )
2164 _FndPara* pFndPara = (_FndPara*)pPara;
2165 _FndBox* pFndBox = new _FndBox( (SwTableBox*)rpBox, pFndPara->pFndLine );
2166 if( rpBox->GetTabLines().Count() )
2168 _FndPara aPara( *pFndPara, pFndBox );
2169 pFndBox->GetBox()->GetTabLines().ForEach( &_FndLineCopyCol, &aPara );
2170 if( !pFndBox->GetLines().Count() )
2172 delete pFndBox;
2173 return TRUE;
2176 else
2178 SwTableBoxPtr pSrch = (SwTableBoxPtr)rpBox;
2179 USHORT nFndPos;
2180 if( !pFndPara->rBoxes.Seek_Entry( pSrch, &nFndPos ))
2182 delete pFndBox;
2183 return TRUE;
2186 pFndPara->pFndLine->GetBoxes().C40_INSERT( _FndBox, pFndBox,
2187 pFndPara->pFndLine->GetBoxes().Count() );
2188 return TRUE;
2191 BOOL _FndLineCopyCol( const SwTableLine*& rpLine, void* pPara )
2193 _FndPara* pFndPara = (_FndPara*)pPara;
2194 _FndLine* pFndLine = new _FndLine( (SwTableLine*)rpLine, pFndPara->pFndBox );
2195 _FndPara aPara( *pFndPara, pFndLine );
2196 pFndLine->GetLine()->GetTabBoxes().ForEach( &_FndBoxCopyCol, &aPara );
2197 if( pFndLine->GetBoxes().Count() )
2199 pFndPara->pFndBox->GetLines().C40_INSERT( _FndLine, pFndLine,
2200 pFndPara->pFndBox->GetLines().Count() );
2202 else
2203 delete pFndLine;
2204 return TRUE;
2207 void _FndBox::SetTableLines( const SwSelBoxes &rBoxes, const SwTable &rTable )
2209 //Pointer auf die Lines vor und hinter den zu verarbeitenden Bereich
2210 //setzen. Wenn die erste/letzte Zeile in den Bereich eingeschlossen
2211 //sind, so bleiben die Pointer eben einfach 0.
2212 //Gesucht werden zunachst die Positionen der ersten/letzten betroffenen
2213 //Line im Array der SwTable. Damit die 0 fuer 'keine Line' verwand werden
2214 //kann werden die Positionen um 1 nach oben versetzt!
2216 USHORT nStPos = USHRT_MAX;
2217 USHORT nEndPos= 0;
2219 for ( USHORT i = 0; i < rBoxes.Count(); ++i )
2221 SwTableLine *pLine = rBoxes[i]->GetUpper();
2222 while ( pLine->GetUpper() )
2223 pLine = pLine->GetUpper()->GetUpper();
2224 const USHORT nPos = rTable.GetTabLines().GetPos(
2225 (const SwTableLine*&)pLine ) + 1;
2227 ASSERT( nPos != USHRT_MAX, "TableLine not found." );
2229 if( nStPos > nPos )
2230 nStPos = nPos;
2232 if( nEndPos < nPos )
2233 nEndPos = nPos;
2235 if ( nStPos > 1 )
2236 pLineBefore = rTable.GetTabLines()[nStPos - 2];
2237 if ( nEndPos < rTable.GetTabLines().Count() )
2238 pLineBehind = rTable.GetTabLines()[nEndPos];
2241 void _FndBox::SetTableLines( const SwTable &rTable )
2243 // Pointer auf die Lines vor und hinter den zu verarbeitenden Bereich
2244 // setzen. Wenn die erste/letzte Zeile in den Bereich eingeschlossen
2245 // sind, so bleiben die Pointer eben einfach 0.
2246 // Die Positionen der ersten/letzten betroffenen Line im Array der
2247 // SwTable steht in der FndBox. Damit die 0 fuer 'keine Line' verwand
2248 // werdenkann werden die Positionen um 1 nach oben versetzt!
2250 if( !GetLines().Count() )
2251 return;
2253 SwTableLine* pTmpLine = GetLines()[0]->GetLine();
2254 USHORT nPos = rTable.GetTabLines().C40_GETPOS( SwTableLine, pTmpLine );
2255 ASSERT( USHRT_MAX != nPos, "Line steht nicht in der Tabelle" );
2256 if( nPos )
2257 pLineBefore = rTable.GetTabLines()[ nPos - 1 ];
2259 pTmpLine = GetLines()[GetLines().Count()-1]->GetLine();
2260 nPos = rTable.GetTabLines().C40_GETPOS( SwTableLine, pTmpLine );
2261 ASSERT( USHRT_MAX != nPos, "Line steht nicht in der Tabelle" );
2262 if( ++nPos < rTable.GetTabLines().Count() )
2263 pLineBehind = rTable.GetTabLines()[nPos];
2266 inline void UnsetFollow( SwFlowFrm *pTab )
2268 pTab->bIsFollow = FALSE;
2271 void _FndBox::DelFrms( SwTable &rTable )
2273 //Alle Lines zwischen pLineBefore und pLineBehind muessen aus dem
2274 //Layout ausgeschnitten und geloescht werden.
2275 //Entstehen dabei leere Follows so muessen diese vernichtet werden.
2276 //Wird ein Master vernichtet, so muss der Follow Master werden.
2277 //Ein TabFrm muss immer uebrigbleiben.
2279 USHORT nStPos = 0;
2280 USHORT nEndPos= rTable.GetTabLines().Count() - 1;
2281 if( rTable.IsNewModel() && pLineBefore )
2282 rTable.CheckRowSpan( pLineBefore, true );
2283 if ( pLineBefore )
2285 nStPos = rTable.GetTabLines().GetPos(
2286 (const SwTableLine*&)pLineBefore );
2287 ASSERT( nStPos != USHRT_MAX, "Fuchs Du hast die Line gestohlen!" );
2288 ++nStPos;
2290 if( rTable.IsNewModel() && pLineBehind )
2291 rTable.CheckRowSpan( pLineBehind, false );
2292 if ( pLineBehind )
2294 nEndPos = rTable.GetTabLines().GetPos(
2295 (const SwTableLine*&)pLineBehind );
2296 ASSERT( nEndPos != USHRT_MAX, "Fuchs Du hast die Line gestohlen!" );
2297 --nEndPos;
2300 for ( USHORT i = nStPos; i <= nEndPos; ++i)
2302 SwFrmFmt *pFmt = rTable.GetTabLines()[i]->GetFrmFmt();
2303 SwClientIter aIter( *pFmt );
2304 SwClient* pLast = aIter.GoStart();
2305 if( pLast )
2307 do {
2308 SwFrm *pFrm = PTR_CAST( SwFrm, pLast );
2309 if ( pFrm &&
2310 ((SwRowFrm*)pFrm)->GetTabLine() == rTable.GetTabLines()[i] )
2312 BOOL bDel = TRUE;
2313 SwTabFrm *pUp = !pFrm->GetPrev() && !pFrm->GetNext() ?
2314 (SwTabFrm*)pFrm->GetUpper() : 0;
2315 if ( !pUp )
2317 const USHORT nRepeat =
2318 ((SwTabFrm*)pFrm->GetUpper())->GetTable()->GetRowsToRepeat();
2319 if ( nRepeat > 0 &&
2320 ((SwTabFrm*)pFrm->GetUpper())->IsFollow() )
2322 if ( !pFrm->GetNext() )
2324 SwRowFrm* pFirstNonHeadline =
2325 ((SwTabFrm*)pFrm->GetUpper())->GetFirstNonHeadlineRow();
2326 if ( pFirstNonHeadline == pFrm )
2328 pUp = (SwTabFrm*)pFrm->GetUpper();
2333 if ( pUp )
2335 SwTabFrm *pFollow = pUp->GetFollow();
2336 SwTabFrm *pPrev = pUp->IsFollow() ? pUp : 0;
2337 if ( pPrev )
2339 SwFrm *pTmp = pPrev->FindPrev();
2340 ASSERT( pTmp->IsTabFrm(),
2341 "Vorgaenger vom Follow kein Master.");
2342 pPrev = (SwTabFrm*)pTmp;
2344 if ( pPrev )
2346 pPrev->SetFollow( pFollow );
2347 // --> FME 2006-01-31 #i60340# Do not transfer the
2348 // flag from pUp to pPrev. pUp may still have the
2349 // flag set although there is not more follow flow
2350 // line associated with pUp.
2351 pPrev->SetFollowFlowLine( FALSE );
2352 // <--
2354 else if ( pFollow )
2355 ::UnsetFollow( pFollow );
2357 //Ein TabellenFrm muss immer stehenbleiben!
2358 if ( pPrev || pFollow )
2360 // OD 26.08.2003 #i18103# - if table is in a section,
2361 // lock the section, to avoid its delete.
2363 SwSectionFrm* pSctFrm = pUp->FindSctFrm();
2364 bool bOldSectLock = false;
2365 if ( pSctFrm )
2367 bOldSectLock = pSctFrm->IsColLocked();
2368 pSctFrm->ColLock();
2370 pUp->Cut();
2371 if ( pSctFrm && !bOldSectLock )
2373 pSctFrm->ColUnlock();
2376 delete pUp;
2377 bDel = FALSE;//Die Row wird mit in den Abgrund
2378 //gerissen.
2381 if ( bDel )
2383 SwFrm* pTabFrm = pFrm->GetUpper();
2384 if ( pTabFrm->IsTabFrm() &&
2385 !pFrm->GetNext() &&
2386 ((SwTabFrm*)pTabFrm)->GetFollow() )
2388 // We do not delete the follow flow line,
2389 // this will be done automatically in the
2390 // next turn.
2391 ((SwTabFrm*)pTabFrm)->SetFollowFlowLine( FALSE );
2394 pFrm->Cut();
2395 delete pFrm;
2398 } while( 0 != ( pLast = aIter++ ));
2403 BOOL lcl_IsLineOfTblFrm( const SwTabFrm& rTable, const SwFrm& rChk )
2405 const SwTabFrm* pTblFrm = rChk.FindTabFrm();
2406 if( pTblFrm->IsFollow() )
2407 pTblFrm = pTblFrm->FindMaster( true );
2408 return &rTable == pTblFrm;
2412 * lcl_UpdateRepeatedHeadlines
2414 void lcl_UpdateRepeatedHeadlines( SwTabFrm& rTabFrm, bool bCalcLowers )
2416 ASSERT( rTabFrm.IsFollow(), "lcl_UpdateRepeatedHeadlines called for non-follow tab" )
2418 // Delete remaining headlines:
2419 SwRowFrm* pLower = 0;
2420 while ( 0 != ( pLower = (SwRowFrm*)rTabFrm.Lower() ) && pLower->IsRepeatedHeadline() )
2422 pLower->Cut();
2423 delete pLower;
2426 // Insert fresh set of headlines:
2427 pLower = (SwRowFrm*)rTabFrm.Lower();
2428 SwTable& rTable = *rTabFrm.GetTable();
2429 const USHORT nRepeat = rTable.GetRowsToRepeat();
2430 for ( USHORT nIdx = 0; nIdx < nRepeat; ++nIdx )
2432 SwRowFrm* pHeadline = new SwRowFrm(
2433 *rTable.GetTabLines()[ nIdx ] );
2434 pHeadline->SetRepeatedHeadline( true );
2435 pHeadline->Paste( &rTabFrm, pLower );
2436 pHeadline->RegistFlys();
2439 if ( bCalcLowers )
2440 rTabFrm.SetCalcLowers();
2443 void _FndBox::MakeFrms( SwTable &rTable )
2445 //Alle Lines zwischen pLineBefore und pLineBehind muessen im Layout
2446 //wieder neu erzeugt werden.
2447 //Und Zwar fuer alle Auspraegungen der Tabelle (mehrere z.B. im Kopf/Fuss).
2449 USHORT nStPos = 0;
2450 USHORT nEndPos= rTable.GetTabLines().Count() - 1;
2451 if ( pLineBefore )
2453 nStPos = rTable.GetTabLines().GetPos(
2454 (const SwTableLine*&)pLineBefore );
2455 ASSERT( nStPos != USHRT_MAX, "Fuchs Du hast die Line gestohlen!" );
2456 ++nStPos;
2459 if ( pLineBehind )
2461 nEndPos = rTable.GetTabLines().GetPos(
2462 (const SwTableLine*&)pLineBehind );
2463 ASSERT( nEndPos != USHRT_MAX, "Fuchs Du hast die Line gestohlen!" );
2464 --nEndPos;
2466 //Jetzt die grosse Einfuegeoperation fuer alle Tabllen.
2467 SwClientIter aTabIter( *rTable.GetFrmFmt() );
2468 for ( SwTabFrm *pTable = (SwTabFrm*)aTabIter.First( TYPE(SwFrm) ); pTable;
2469 pTable = (SwTabFrm*)aTabIter.Next() )
2471 if ( !pTable->IsFollow() )
2473 SwFrm *pSibling = 0;
2474 SwFrm *pUpperFrm = 0;
2475 int i;
2476 for ( i = rTable.GetTabLines().Count()-1;
2477 i >= 0 && !pSibling; --i )
2479 SwTableLine *pLine = pLineBehind ? pLineBehind :
2480 rTable.GetTabLines()[static_cast<USHORT>(i)];
2481 SwClientIter aIter( *pLine->GetFrmFmt() );
2482 pSibling = (SwFrm*)aIter.First( TYPE(SwFrm) );
2483 while ( pSibling && (
2484 static_cast<SwRowFrm*>(pSibling)->GetTabLine() != pLine ||
2485 !lcl_IsLineOfTblFrm( *pTable, *pSibling ) ||
2486 static_cast<SwRowFrm*>(pSibling)->IsRepeatedHeadline() ||
2487 // --> FME 2005-08-24 #i53647# If !pLineBehind,
2488 // IsInSplitTableRow() should be checked.
2489 ( pLineBehind && pSibling->IsInFollowFlowRow() ) ||
2490 (!pLineBehind && pSibling->IsInSplitTableRow() ) ) )
2491 // <--
2493 pSibling = (SwFrm*)aIter.Next();
2496 if ( pSibling )
2498 pUpperFrm = pSibling->GetUpper();
2499 if ( !pLineBehind )
2500 pSibling = 0;
2502 else
2503 // ???? oder das der Letzte Follow der Tabelle ????
2504 pUpperFrm = pTable;
2506 for ( i = nStPos; (USHORT)i <= nEndPos; ++i )
2507 ::lcl_InsertRow( *rTable.GetTabLines()[static_cast<USHORT>(i)],
2508 (SwLayoutFrm*)pUpperFrm, pSibling );
2509 if ( pUpperFrm->IsTabFrm() )
2510 ((SwTabFrm*)pUpperFrm)->SetCalcLowers();
2512 else if ( rTable.GetRowsToRepeat() > 0 )
2514 // Insert new headlines:
2515 lcl_UpdateRepeatedHeadlines( *pTable, true );
2520 void _FndBox::MakeNewFrms( SwTable &rTable, const USHORT nNumber,
2521 const BOOL bBehind )
2523 //Frms fuer neu eingefuege Zeilen erzeugen.
2524 //bBehind == TRUE: vor pLineBehind
2525 // == FALSE: hinter pLineBefore
2526 const USHORT nBfPos = pLineBefore ?
2527 rTable.GetTabLines().GetPos( (const SwTableLine*&)pLineBefore ) :
2528 USHRT_MAX;
2529 const USHORT nBhPos = pLineBehind ?
2530 rTable.GetTabLines().GetPos( (const SwTableLine*&)pLineBehind ) :
2531 USHRT_MAX;
2533 //nNumber: wie oft ist eingefuegt worden.
2534 //nCnt: wieviele sind nNumber mal eingefuegt worden.
2536 const USHORT nCnt =
2537 ((nBhPos != USHRT_MAX ? nBhPos : rTable.GetTabLines().Count()) -
2538 (nBfPos != USHRT_MAX ? nBfPos + 1 : 0)) / (nNumber + 1);
2540 //Den Master-TabFrm suchen
2541 SwClientIter aTabIter( *rTable.GetFrmFmt() );
2542 SwTabFrm *pTable;
2543 for ( pTable = (SwTabFrm*)aTabIter.First( TYPE(SwFrm) ); pTable;
2544 pTable = (SwTabFrm*)aTabIter.Next() )
2546 if( !pTable->IsFollow() )
2548 SwFrm *pSibling = 0;
2549 SwLayoutFrm *pUpperFrm = 0;
2550 if ( bBehind )
2552 if ( pLineBehind )
2554 SwClientIter aIter( *pLineBehind->GetFrmFmt() );
2555 pSibling = (SwFrm*)aIter.First( TYPE(SwFrm) );
2556 while ( pSibling && (
2557 // only consider row frames associated with pLineBehind:
2558 static_cast<SwRowFrm*>(pSibling)->GetTabLine() != pLineBehind ||
2559 // only consider row frames that are in pTables Master-Follow chain:
2560 !lcl_IsLineOfTblFrm( *pTable, *pSibling ) ||
2561 // only consider row frames that are not repeated headlines:
2562 static_cast<SwRowFrm*>(pSibling)->IsRepeatedHeadline() ||
2563 // only consider row frames that are not follow flow rows
2564 pSibling->IsInFollowFlowRow() ) )
2566 pSibling = (SwFrm*)aIter.Next();
2569 if ( pSibling )
2570 pUpperFrm = pSibling->GetUpper();
2571 else
2573 while( pTable->GetFollow() )
2574 pTable = pTable->GetFollow();
2575 pUpperFrm = pTable;
2577 const USHORT nMax = nBhPos != USHRT_MAX ?
2578 nBhPos : rTable.GetTabLines().Count();
2580 USHORT i = nBfPos != USHRT_MAX ? nBfPos + 1 + nCnt : nCnt;
2582 for ( ; i < nMax; ++i )
2583 ::lcl_InsertRow( *rTable.GetTabLines()[i], pUpperFrm, pSibling );
2584 if ( pUpperFrm->IsTabFrm() )
2585 ((SwTabFrm*)pUpperFrm)->SetCalcLowers();
2587 else //davor einfuegen
2589 USHORT i;
2591 // We are looking for the frame that is behind the row frame
2592 // that should be inserted.
2593 for ( i = 0; !pSibling; ++i )
2595 SwTableLine* pLine = pLineBefore ? pLineBefore : rTable.GetTabLines()[i];
2597 SwClientIter aIter( *pLine->GetFrmFmt() );
2598 pSibling = (SwFrm*)aIter.First( TYPE(SwFrm) );
2600 while ( pSibling && (
2601 // only consider row frames associated with pLineBefore:
2602 static_cast<SwRowFrm*>(pSibling)->GetTabLine() != pLine ||
2603 // only consider row frames that are in pTables Master-Follow chain:
2604 !lcl_IsLineOfTblFrm( *pTable, *pSibling ) ||
2605 // only consider row frames that are not repeated headlines:
2606 static_cast<SwRowFrm*>(pSibling)->IsRepeatedHeadline() ||
2607 // 1. case: pLineBefore == 0:
2608 // only consider row frames that are not follow flow rows
2609 // 2. case: pLineBefore != 0:
2610 // only consider row frames that are not split table rows
2611 // --> FME 2004-11-23 #i37476# If !pLineBefore,
2612 // check IsInFollowFlowRow instead of IsInSplitTableRow.
2613 ( ( !pLineBefore && pSibling->IsInFollowFlowRow() ) ||
2614 ( pLineBefore && pSibling->IsInSplitTableRow() ) ) ) )
2615 // <--
2617 pSibling = (SwFrm*)aIter.Next();
2621 pUpperFrm = pSibling->GetUpper();
2622 if ( pLineBefore )
2623 pSibling = pSibling->GetNext();
2625 USHORT nMax = nBhPos != USHRT_MAX ?
2626 nBhPos - nCnt :
2627 rTable.GetTabLines().Count() - nCnt;
2629 i = nBfPos != USHRT_MAX ? nBfPos + 1 : 0;
2630 for ( ; i < nMax; ++i )
2631 ::lcl_InsertRow( *rTable.GetTabLines()[i],
2632 pUpperFrm, pSibling );
2633 if ( pUpperFrm->IsTabFrm() )
2634 ((SwTabFrm*)pUpperFrm)->SetCalcLowers();
2639 //Die Headlines mussen ggf. auch verarbeitet werden. Um gut arbeitenden
2640 //Code nicht zu zerfasern wird hier nochmals iteriert.
2641 const USHORT nRowsToRepeat = rTable.GetRowsToRepeat();
2642 if ( nRowsToRepeat > 0 &&
2643 ( ( !bBehind && ( nBfPos == USHRT_MAX || nBfPos + 1 < nRowsToRepeat ) ) ||
2644 ( bBehind && ( ( nBfPos == USHRT_MAX && nRowsToRepeat > 1 ) || nBfPos + 2 < nRowsToRepeat ) ) ) )
2646 for ( pTable = (SwTabFrm*)aTabIter.First( TYPE(SwFrm) ); pTable;
2647 pTable = (SwTabFrm*)aTabIter.Next() )
2649 if ( pTable->Lower() )
2651 if ( pTable->IsFollow() )
2653 lcl_UpdateRepeatedHeadlines( *pTable, true );
2656 ASSERT( ((SwRowFrm*)pTable->Lower())->GetTabLine() ==
2657 rTable.GetTabLines()[0], "MakeNewFrms: Table corruption!" )
2663 BOOL _FndBox::AreLinesToRestore( const SwTable &rTable ) const
2665 //Lohnt es sich MakeFrms zu rufen?
2667 if ( !pLineBefore && !pLineBehind && rTable.GetTabLines().Count() )
2668 return TRUE;
2670 USHORT nBfPos;
2671 if(pLineBefore)
2673 const SwTableLine* rLBefore = (const SwTableLine*)pLineBefore;
2674 nBfPos = rTable.GetTabLines().GetPos( rLBefore );
2676 else
2677 nBfPos = USHRT_MAX;
2679 USHORT nBhPos;
2680 if(pLineBehind)
2682 const SwTableLine* rLBehind = (const SwTableLine*)pLineBehind;
2683 nBhPos = rTable.GetTabLines().GetPos( rLBehind );
2685 else
2686 nBhPos = USHRT_MAX;
2688 if ( nBfPos == nBhPos ) //Duerfte eigentlich nie vorkommen.
2690 ASSERT( FALSE, "Table, Loeschen auf keinem Bereich !?!" );
2691 return FALSE;
2694 if ( rTable.GetRowsToRepeat() > 0 )
2696 // ups. sollte unsere zu wiederholende Kopfzeile geloescht worden
2697 // sein??
2698 SwClientIter aIter( *rTable.GetFrmFmt() );
2699 for( SwTabFrm* pTable = (SwTabFrm*)aIter.First( TYPE( SwFrm ));
2700 pTable; pTable = (SwTabFrm*)aIter.Next() )
2702 if( pTable->IsFollow() )
2704 // Insert new headlines:
2705 lcl_UpdateRepeatedHeadlines( *pTable, false );
2710 // Some adjacent lines at the beginning of the table have been deleted:
2711 if ( nBfPos == USHRT_MAX && nBhPos == 0 )
2712 return FALSE;
2714 // Some adjacent lines at the end of the table have been deleted:
2715 if ( nBhPos == USHRT_MAX && nBfPos == (rTable.GetTabLines().Count() - 1) )
2716 return FALSE;
2718 // Some adjacent lines in the middle of the table have been deleted:
2719 if ( nBfPos != USHRT_MAX && nBhPos != USHRT_MAX && (nBfPos + 1) == nBhPos )
2720 return FALSE;
2722 // The structure of the deleted lines is more complex due to split lines.
2723 // A call of MakeFrms() is necessary.
2724 return TRUE;