summaryrefslogtreecommitdiff
path: root/sw/source/core/frmedt/tblsel.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/core/frmedt/tblsel.cxx')
-rw-r--r--sw/source/core/frmedt/tblsel.cxx2728
1 files changed, 2728 insertions, 0 deletions
diff --git a/sw/source/core/frmedt/tblsel.cxx b/sw/source/core/frmedt/tblsel.cxx
new file mode 100644
index 000000000000..8cabf285e12b
--- /dev/null
+++ b/sw/source/core/frmedt/tblsel.cxx
@@ -0,0 +1,2728 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sw.hxx"
+
+#include <hintids.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/protitem.hxx>
+#include <fmtanchr.hxx>
+#include <fmtfsize.hxx>
+#include <frmatr.hxx>
+#include <tblsel.hxx>
+#include <crsrsh.hxx>
+#include <doc.hxx>
+#include <docary.hxx>
+#include <pam.hxx>
+#include <ndtxt.hxx>
+#include <ndole.hxx>
+#include <swtable.hxx>
+#include <cntfrm.hxx>
+#include <tabfrm.hxx>
+#include <rowfrm.hxx>
+#include <cellfrm.hxx>
+#include <pagefrm.hxx>
+#include <rootfrm.hxx>
+#include <viscrs.hxx>
+#include <swtblfmt.hxx>
+#include <undobj.hxx>
+#include <mvsave.hxx>
+// OD 26.08.2003 #i18103#
+#include <sectfrm.hxx>
+#include <frmtool.hxx>
+
+//siehe auch swtable.cxx
+#define COLFUZZY 20L
+
+// defines, die bestimmen, wie Tabellen Boxen gemergt werden:
+// - 1. alle leeren Zeilen entfernen, alle Boxen werden mit Blank,
+// alle Lines mit ParaBreak getrennt
+// - 2. alle leeren Zeilen und alle leeren Boxen am Anfang und Ende
+// entfernen, alle Boxen werden mit Blank,
+// alle Lines mit ParaBreak getrennt
+// - 3. alle leeren Boxen entfernen, alle Boxen werden mit Blank,
+// alle Lines mit ParaBreak getrennt
+
+#undef DEL_ONLY_EMPTY_LINES
+#undef DEL_EMPTY_BOXES_AT_START_AND_END
+#define DEL_ALL_EMPTY_BOXES
+
+
+_SV_IMPL_SORTAR_ALG( SwSelBoxes, SwTableBoxPtr )
+BOOL SwSelBoxes::Seek_Entry( const SwTableBoxPtr rSrch, USHORT* pFndPos ) const
+{
+ ULONG nIdx = rSrch->GetSttIdx();
+
+ USHORT nO = Count(), nM, nU = 0;
+ if( nO > 0 )
+ {
+ nO--;
+ while( nU <= nO )
+ {
+ nM = nU + ( nO - nU ) / 2;
+ if( (*this)[ nM ]->GetSttNd() == rSrch->GetSttNd() )
+ {
+ if( pFndPos )
+ *pFndPos = nM;
+ return TRUE;
+ }
+ else if( (*this)[ nM ]->GetSttIdx() < nIdx )
+ nU = nM + 1;
+ else if( nM == 0 )
+ {
+ if( pFndPos )
+ *pFndPos = nU;
+ return FALSE;
+ }
+ else
+ nO = nM - 1;
+ }
+ }
+ if( pFndPos )
+ *pFndPos = nU;
+ return FALSE;
+}
+
+
+SV_IMPL_PTRARR( SwCellFrms, SwCellFrm* )
+
+struct _CmpLPt
+{
+ Point aPos;
+ const SwTableBox* pSelBox;
+ BOOL bVert;
+
+ _CmpLPt( const Point& rPt, const SwTableBox* pBox, BOOL bVertical );
+
+ BOOL operator==( const _CmpLPt& rCmp ) const
+ { return X() == rCmp.X() && Y() == rCmp.Y() ? TRUE : FALSE; }
+
+ BOOL operator<( const _CmpLPt& rCmp ) const
+ {
+ if ( bVert )
+ return X() > rCmp.X() || ( X() == rCmp.X() && Y() < rCmp.Y() )
+ ? TRUE : FALSE;
+ else
+ return Y() < rCmp.Y() || ( Y() == rCmp.Y() && X() < rCmp.X() )
+ ? TRUE : FALSE;
+ }
+
+ long X() const { return aPos.X(); }
+ long Y() const { return aPos.Y(); }
+};
+
+
+SV_DECL_VARARR_SORT( _MergePos, _CmpLPt, 0, 40 )
+SV_IMPL_VARARR_SORT( _MergePos, _CmpLPt )
+
+SV_IMPL_PTRARR( _FndBoxes, _FndBox* )
+SV_IMPL_PTRARR( _FndLines, _FndLine* )
+
+
+struct _Sort_CellFrm
+{
+ const SwCellFrm* pFrm;
+
+ _Sort_CellFrm( const SwCellFrm& rCFrm )
+ : pFrm( &rCFrm ) {}
+};
+
+SV_DECL_VARARR( _Sort_CellFrms, _Sort_CellFrm, 16, 16 )
+SV_IMPL_VARARR( _Sort_CellFrms, _Sort_CellFrm )
+
+SV_IMPL_PTRARR( SwChartBoxes, SwTableBoxPtr );
+SV_IMPL_PTRARR( SwChartLines, SwChartBoxes* );
+
+const SwLayoutFrm *lcl_FindCellFrm( const SwLayoutFrm *pLay )
+{
+ while ( pLay && !pLay->IsCellFrm() )
+ pLay = pLay->GetUpper();
+ return pLay;
+}
+
+const SwLayoutFrm *lcl_FindNextCellFrm( const SwLayoutFrm *pLay )
+{
+ //Dafuer sorgen, dass die Zelle auch verlassen wird (Bereiche)
+ const SwLayoutFrm *pTmp = pLay;
+ do {
+ pTmp = pTmp->GetNextLayoutLeaf();
+ } while( pLay->IsAnLower( pTmp ) );
+
+ while( pTmp && !pTmp->IsCellFrm() )
+ pTmp = pTmp->GetUpper();
+ return pTmp;
+}
+
+void GetTblSelCrs( const SwCrsrShell &rShell, SwSelBoxes& rBoxes )
+{
+ if( rBoxes.Count() )
+ rBoxes.Remove( USHORT(0), rBoxes.Count() );
+ if( rShell.IsTableMode() && ((SwCrsrShell&)rShell).UpdateTblSelBoxes())
+ rBoxes.Insert( &rShell.GetTableCrsr()->GetBoxes() );
+}
+
+void GetTblSelCrs( const SwTableCursor& rTblCrsr, SwSelBoxes& rBoxes )
+{
+ if( rBoxes.Count() )
+ rBoxes.Remove( USHORT(0), rBoxes.Count() );
+
+ if( rTblCrsr.IsChgd() || !rTblCrsr.GetBoxesCount() )
+ {
+ SwTableCursor* pTCrsr = (SwTableCursor*)&rTblCrsr;
+ pTCrsr->GetDoc()->GetRootFrm()->MakeTblCrsrs( *pTCrsr );
+ }
+
+ if( rTblCrsr.GetBoxesCount() )
+ rBoxes.Insert( &rTblCrsr.GetBoxes() );
+}
+
+void GetTblSel( const SwCrsrShell& rShell, SwSelBoxes& rBoxes,
+ const SwTblSearchType eSearchType )
+{
+ //Start- und Endzelle besorgen und den naechsten fragen.
+ if ( !rShell.IsTableMode() )
+ rShell.GetCrsr();
+
+ GetTblSel( *rShell.getShellCrsr(false), rBoxes, eSearchType );
+}
+
+void GetTblSel( const SwCursor& rCrsr, SwSelBoxes& rBoxes,
+ const SwTblSearchType eSearchType )
+{
+ //Start- und Endzelle besorgen und den naechsten fragen.
+ ASSERT( rCrsr.GetCntntNode() && rCrsr.GetCntntNode( FALSE ),
+ "Tabselection nicht auf Cnt." );
+
+ // Zeilen-Selektion:
+ // teste ob Tabelle komplex ist. Wenn ja, dann immer uebers Layout
+ // die selektierten Boxen zusammen suchen. Andernfalls ueber die
+ // Tabellen-Struktur (fuer Makros !!)
+ const SwCntntNode* pContentNd = rCrsr.GetNode()->GetCntntNode();
+ const SwTableNode* pTblNd = pContentNd ? pContentNd->FindTableNode() : 0;
+ if( pTblNd && pTblNd->GetTable().IsNewModel() )
+ {
+ SwTable::SearchType eSearch;
+ switch( nsSwTblSearchType::TBLSEARCH_COL & eSearchType )
+ {
+ case nsSwTblSearchType::TBLSEARCH_ROW: eSearch = SwTable::SEARCH_ROW; break;
+ case nsSwTblSearchType::TBLSEARCH_COL: eSearch = SwTable::SEARCH_COL; break;
+ default: eSearch = SwTable::SEARCH_NONE; break;
+ }
+ const bool bChkP = 0 != ( nsSwTblSearchType::TBLSEARCH_PROTECT & eSearchType );
+ pTblNd->GetTable().CreateSelection( rCrsr, rBoxes, eSearch, bChkP );
+ return;
+ }
+ if( nsSwTblSearchType::TBLSEARCH_ROW == ((~nsSwTblSearchType::TBLSEARCH_PROTECT ) & eSearchType ) &&
+ pTblNd && !pTblNd->GetTable().IsTblComplex() )
+ {
+ const SwTable& rTbl = pTblNd->GetTable();
+ const SwTableLines& rLines = rTbl.GetTabLines();
+
+ const SwNode* pMarkNode = rCrsr.GetNode( FALSE );
+ const ULONG nMarkSectionStart = pMarkNode->StartOfSectionIndex();
+ const SwTableBox* pMarkBox = rTbl.GetTblBox( nMarkSectionStart );
+
+ ASSERT( pMarkBox, "Point in table, mark outside?" )
+
+ const SwTableLine* pLine = pMarkBox ? pMarkBox->GetUpper() : 0;
+ USHORT nSttPos = rLines.GetPos( pLine );
+ ASSERT( USHRT_MAX != nSttPos, "Wo ist meine Zeile in der Tabelle?" );
+ pLine = rTbl.GetTblBox( rCrsr.GetNode( TRUE )->StartOfSectionIndex() )->GetUpper();
+ USHORT nEndPos = rLines.GetPos( pLine );
+ ASSERT( USHRT_MAX != nEndPos, "Wo ist meine Zeile in der Tabelle?" );
+ // pb: #i20193# if tableintable then nSttPos == nEndPos == USHRT_MAX
+ if ( nSttPos != USHRT_MAX && nEndPos != USHRT_MAX )
+ {
+ if( nEndPos < nSttPos ) // vertauschen
+ {
+ USHORT nTmp = nSttPos; nSttPos = nEndPos; nEndPos = nTmp;
+ }
+
+ int bChkProtected = nsSwTblSearchType::TBLSEARCH_PROTECT & eSearchType;
+ for( ; nSttPos <= nEndPos; ++nSttPos )
+ {
+ pLine = rLines[ nSttPos ];
+ for( USHORT n = pLine->GetTabBoxes().Count(); n ; )
+ {
+ SwTableBox* pBox = pLine->GetTabBoxes()[ --n ];
+ // Zellenschutzt beachten ??
+ if( !bChkProtected ||
+ !pBox->GetFrmFmt()->GetProtect().IsCntntProtected() )
+ rBoxes.Insert( pBox );
+ }
+ }
+ }
+ }
+ else
+ {
+ Point aPtPos, aMkPos;
+ const SwShellCrsr* pShCrsr = dynamic_cast<const SwShellCrsr*>(&rCrsr);
+ if( pShCrsr )
+ {
+ aPtPos = pShCrsr->GetPtPos();
+ aMkPos = pShCrsr->GetMkPos();
+ }
+ const SwCntntNode *pCntNd = rCrsr.GetCntntNode();
+ const SwLayoutFrm *pStart = pCntNd ?
+ pCntNd->GetFrm( &aPtPos )->GetUpper() : 0;
+ pCntNd = rCrsr.GetCntntNode(FALSE);
+ const SwLayoutFrm *pEnd = pCntNd ?
+ pCntNd->GetFrm( &aMkPos )->GetUpper() : 0;
+ if( pStart && pEnd )
+ GetTblSel( pStart, pEnd, rBoxes, 0, eSearchType );
+ }
+}
+
+void GetTblSel( const SwLayoutFrm* pStart, const SwLayoutFrm* pEnd,
+ SwSelBoxes& rBoxes, SwCellFrms* pCells,
+ const SwTblSearchType eSearchType )
+{
+ // #112697# Robust:
+ const SwTabFrm* pStartTab = pStart->FindTabFrm();
+ if ( !pStartTab )
+ {
+ ASSERT( false, "GetTblSel without start table" )
+ return;
+ }
+
+ int bChkProtected = nsSwTblSearchType::TBLSEARCH_PROTECT & eSearchType;
+
+ BOOL bTblIsValid;
+ // --> FME 2006-01-25 #i55421# Reduced value 10
+ int nLoopMax = 10; //JP 28.06.99: max 100 loops - Bug 67292
+ // <--
+ USHORT i;
+
+ do {
+ bTblIsValid = TRUE;
+
+ //Zuerst lassen wir uns die Tabellen und die Rechtecke heraussuchen.
+ SwSelUnions aUnions;
+ ::MakeSelUnions( aUnions, pStart, pEnd, eSearchType );
+
+ Point aCurrentTopLeft( LONG_MAX, LONG_MAX );
+ Point aCurrentTopRight( 0, LONG_MAX );
+ Point aCurrentBottomLeft( LONG_MAX, 0 );
+ Point aCurrentBottomRight( 0, 0 );
+ const SwCellFrm* pCurrentTopLeftFrm = 0;
+ const SwCellFrm* pCurrentTopRightFrm = 0;
+ const SwCellFrm* pCurrentBottomLeftFrm = 0;
+ const SwCellFrm* pCurrentBottomRightFrm = 0;
+
+ //Jetzt zu jedem Eintrag die Boxen herausfischen und uebertragen.
+ for( i = 0; i < aUnions.Count() && bTblIsValid; ++i )
+ {
+ SwSelUnion *pUnion = aUnions[i];
+ const SwTabFrm *pTable = pUnion->GetTable();
+ if( !pTable->IsValid() && nLoopMax )
+ {
+ bTblIsValid = FALSE;
+ break;
+ }
+
+ // Skip any repeated headlines in the follow:
+ const SwLayoutFrm* pRow = pTable->IsFollow() ?
+ pTable->GetFirstNonHeadlineRow() :
+ (const SwLayoutFrm*)pTable->Lower();
+
+ while( pRow && bTblIsValid )
+ {
+ if( !pRow->IsValid() && nLoopMax )
+ {
+ bTblIsValid = FALSE;
+ break;
+ }
+
+ if ( pRow->Frm().IsOver( pUnion->GetUnion() ) )
+ {
+ const SwLayoutFrm *pCell = pRow->FirstCell();
+
+ while( bTblIsValid && pCell && pRow->IsAnLower( pCell ) )
+ {
+ if( !pCell->IsValid() && nLoopMax )
+ {
+ bTblIsValid = FALSE;
+ break;
+ }
+
+ ASSERT( pCell->IsCellFrm(), "Frame ohne Celle" );
+ if( ::IsFrmInTblSel( pUnion->GetUnion(), pCell ) )
+ {
+ SwTableBox* pBox = (SwTableBox*)
+ ((SwCellFrm*)pCell)->GetTabBox();
+ // Zellenschutzt beachten ??
+ if( !bChkProtected ||
+ !pBox->GetFrmFmt()->GetProtect().IsCntntProtected() )
+ rBoxes.Insert( pBox );
+
+ if ( pCells )
+ {
+ const Point aTopLeft( pCell->Frm().TopLeft() );
+ const Point aTopRight( pCell->Frm().TopRight() );
+ const Point aBottomLeft( pCell->Frm().BottomLeft() );
+ const Point aBottomRight( pCell->Frm().BottomRight() );
+
+ if ( aTopLeft.Y() < aCurrentTopLeft.Y() ||
+ ( aTopLeft.Y() == aCurrentTopLeft.Y() &&
+ aTopLeft.X() < aCurrentTopLeft.X() ) )
+ {
+ aCurrentTopLeft = aTopLeft;
+ pCurrentTopLeftFrm = static_cast<const SwCellFrm*>( pCell );
+ }
+
+ if ( aTopRight.Y() < aCurrentTopRight.Y() ||
+ ( aTopRight.Y() == aCurrentTopRight.Y() &&
+ aTopRight.X() > aCurrentTopRight.X() ) )
+ {
+ aCurrentTopRight = aTopRight;
+ pCurrentTopRightFrm = static_cast<const SwCellFrm*>( pCell );
+ }
+
+ if ( aBottomLeft.Y() > aCurrentBottomLeft.Y() ||
+ ( aBottomLeft.Y() == aCurrentBottomLeft.Y() &&
+ aBottomLeft.X() < aCurrentBottomLeft.X() ) )
+ {
+ aCurrentBottomLeft = aBottomLeft;
+ pCurrentBottomLeftFrm = static_cast<const SwCellFrm*>( pCell );
+ }
+
+ if ( aBottomRight.Y() > aCurrentBottomRight.Y() ||
+ ( aBottomRight.Y() == aCurrentBottomRight.Y() &&
+ aBottomRight.X() > aCurrentBottomRight.X() ) )
+ {
+ aCurrentBottomRight = aBottomRight;
+ pCurrentBottomRightFrm = static_cast<const SwCellFrm*>( pCell );
+ }
+
+ }
+ }
+ if ( pCell->GetNext() )
+ {
+ pCell = (const SwLayoutFrm*)pCell->GetNext();
+ if ( pCell->Lower() && pCell->Lower()->IsRowFrm() )
+ pCell = pCell->FirstCell();
+ }
+ else
+ pCell = ::lcl_FindNextCellFrm( pCell );
+ }
+ }
+ pRow = (const SwLayoutFrm*)pRow->GetNext();
+ }
+ }
+
+ if ( pCells )
+ {
+ pCells->Remove( 0, pCells->Count() );
+ pCells->Insert( pCurrentTopLeftFrm, 0 );
+ pCells->Insert( pCurrentTopRightFrm, 1 );
+ pCells->Insert( pCurrentBottomLeftFrm, 2 );
+ pCells->Insert( pCurrentBottomRightFrm, 3 );
+ }
+
+ if( bTblIsValid )
+ break;
+
+ SwDeletionChecker aDelCheck( pStart );
+
+ // ansonsten das Layout der Tabelle kurz "kalkulieren" lassen
+ // und nochmals neu aufsetzen
+ SwTabFrm *pTable = aUnions[0]->GetTable();
+ while( pTable )
+ {
+ if( pTable->IsValid() )
+ pTable->InvalidatePos();
+ pTable->SetONECalcLowers();
+ pTable->Calc();
+ pTable->SetCompletePaint();
+ if( 0 == (pTable = pTable->GetFollow()) )
+ break;
+ }
+
+ // --> FME 2005-10-13 #125337# Make code robust, check if pStart has
+ // been deleted due to the formatting of the table:
+ if ( aDelCheck.HasBeenDeleted() )
+ {
+ ASSERT( false, "Current box has been deleted during GetTblSel()" )
+ break;
+ }
+ // <--
+
+ i = 0;
+ rBoxes.Remove( i, rBoxes.Count() );
+ --nLoopMax;
+
+ } while( TRUE );
+ ASSERT( nLoopMax, "das Layout der Tabelle wurde nicht valide!" );
+}
+
+
+
+BOOL ChkChartSel( const SwNode& rSttNd, const SwNode& rEndNd,
+ SwChartLines* pGetCLines )
+{
+ const SwTableNode* pTNd = rSttNd.FindTableNode();
+ if( !pTNd )
+ return FALSE;
+
+ Point aNullPos;
+ SwNodeIndex aIdx( rSttNd );
+ const SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode();
+ if( !pCNd )
+ pCNd = aIdx.GetNodes().GoNextSection( &aIdx, FALSE, FALSE );
+
+ // #109394# if table is invisible, return
+ // (layout needed for forming table selection further down, so we can't
+ // continue with invisible tables)
+ // OD 07.11.2003 #i22135# - Also the content of the table could be
+ // invisible - e.g. in a hidden section
+ // Robust: check, if content was found (e.g. empty table cells)
+ if ( !pCNd || pCNd->GetFrm() == NULL )
+ return FALSE;
+
+ const SwLayoutFrm *pStart = pCNd ? pCNd->GetFrm( &aNullPos )->GetUpper() : 0;
+ ASSERT( pStart, "ohne Frame geht gar nichts" );
+
+ aIdx = rEndNd;
+ pCNd = aIdx.GetNode().GetCntntNode();
+ if( !pCNd )
+ pCNd = aIdx.GetNodes().GoNextSection( &aIdx, FALSE, FALSE );
+
+ // OD 07.11.2003 #i22135# - Robust: check, if content was found and if it's visible
+ if ( !pCNd || pCNd->GetFrm() == NULL )
+ {
+ return FALSE;
+ }
+
+ const SwLayoutFrm *pEnd = pCNd ? pCNd->GetFrm( &aNullPos )->GetUpper() : 0;
+ ASSERT( pEnd, "ohne Frame geht gar nichts" );
+
+
+ BOOL bTblIsValid, bValidChartSel;
+ // --> FME 2006-01-25 #i55421# Reduced value 10
+ int nLoopMax = 10; //JP 28.06.99: max 100 loops - Bug 67292
+ // <--
+ USHORT i = 0;
+
+ do {
+ bTblIsValid = TRUE;
+ bValidChartSel = TRUE;
+
+ USHORT nRowCells = USHRT_MAX;
+
+ //Zuerst lassen wir uns die Tabellen und die Rechtecke heraussuchen.
+ SwSelUnions aUnions;
+ ::MakeSelUnions( aUnions, pStart, pEnd, nsSwTblSearchType::TBLSEARCH_NO_UNION_CORRECT );
+
+ //Jetzt zu jedem Eintrag die Boxen herausfischen und uebertragen.
+ for( i = 0; i < aUnions.Count() && bTblIsValid &&
+ bValidChartSel; ++i )
+ {
+ SwSelUnion *pUnion = aUnions[i];
+ const SwTabFrm *pTable = pUnion->GetTable();
+
+ SWRECTFN( pTable )
+ sal_Bool bRTL = pTable->IsRightToLeft();
+
+ if( !pTable->IsValid() && nLoopMax )
+ {
+ bTblIsValid = FALSE;
+ break;
+ }
+
+ _Sort_CellFrms aCellFrms;
+
+ // Skip any repeated headlines in the follow:
+ const SwLayoutFrm* pRow = pTable->IsFollow() ?
+ pTable->GetFirstNonHeadlineRow() :
+ (const SwLayoutFrm*)pTable->Lower();
+
+ while( pRow && bTblIsValid && bValidChartSel )
+ {
+ if( !pRow->IsValid() && nLoopMax )
+ {
+ bTblIsValid = FALSE;
+ break;
+ }
+
+ if( pRow->Frm().IsOver( pUnion->GetUnion() ) )
+ {
+ const SwLayoutFrm *pCell = pRow->FirstCell();
+
+ while( bValidChartSel && bTblIsValid && pCell &&
+ pRow->IsAnLower( pCell ) )
+ {
+ if( !pCell->IsValid() && nLoopMax )
+ {
+ bTblIsValid = FALSE;
+ break;
+ }
+
+ ASSERT( pCell->IsCellFrm(), "Frame ohne Celle" );
+ const SwRect& rUnion = pUnion->GetUnion(),
+ & rFrmRect = pCell->Frm();
+
+ const long nUnionRight = rUnion.Right();
+ const long nUnionBottom = rUnion.Bottom();
+ const long nFrmRight = rFrmRect.Right();
+ const long nFrmBottom = rFrmRect.Bottom();
+
+ // liegt das FrmRect ausserhalb der Union, kann es
+ // ignoriert werden.
+
+ const long nXFuzzy = bVert ? 0 : 20;
+ const long nYFuzzy = bVert ? 20 : 0;
+
+ if( !( rUnion.Top() + nYFuzzy > nFrmBottom ||
+ nUnionBottom < rFrmRect.Top() + nYFuzzy ||
+ rUnion.Left() + nXFuzzy > nFrmRight ||
+ nUnionRight < rFrmRect.Left() + nXFuzzy ))
+ {
+ // ok, rUnion is _not_ completely outside of rFrmRect
+
+ // wenn es aber nicht komplett in der Union liegt,
+ // dann ist es fuers Chart eine ungueltige
+ // Selektion.
+ if( rUnion.Left() <= rFrmRect.Left() + nXFuzzy &&
+ rFrmRect.Left() <= nUnionRight &&
+ rUnion.Left() <= nFrmRight &&
+ nFrmRight <= nUnionRight + nXFuzzy &&
+ rUnion.Top() <= rFrmRect.Top() + nYFuzzy &&
+ rFrmRect.Top() <= nUnionBottom &&
+ rUnion.Top() <= nFrmBottom &&
+ nFrmBottom <= nUnionBottom+ nYFuzzy )
+
+ aCellFrms.Insert(
+ _Sort_CellFrm( *(SwCellFrm*)pCell ),
+ aCellFrms.Count() );
+ else
+ {
+ bValidChartSel = FALSE;
+ break;
+ }
+ }
+ if ( pCell->GetNext() )
+ {
+ pCell = (const SwLayoutFrm*)pCell->GetNext();
+ if ( pCell->Lower() && pCell->Lower()->IsRowFrm() )
+ pCell = pCell->FirstCell();
+ }
+ else
+ pCell = ::lcl_FindNextCellFrm( pCell );
+ }
+ }
+ pRow = (const SwLayoutFrm*)pRow->GetNext();
+ }
+
+ if( !bValidChartSel )
+ break;
+
+ // alle Zellen der (Teil-)Tabelle zusammen. Dann teste mal ob
+ // all huebsch nebeneinander liegen.
+ USHORT n, nEnd, nCellCnt = 0;
+ long nYPos = LONG_MAX;
+ long nXPos = 0;
+ long nHeight = 0;
+
+ for( n = 0, nEnd = aCellFrms.Count(); n < nEnd; ++n )
+ {
+ const _Sort_CellFrm& rCF = aCellFrms[ n ];
+ if( (rCF.pFrm->Frm().*fnRect->fnGetTop)() != nYPos )
+ {
+ // neue Zeile
+ if( n )
+ {
+ if( USHRT_MAX == nRowCells ) // 1. Zeilenwechsel
+ nRowCells = nCellCnt;
+ else if( nRowCells != nCellCnt )
+ {
+ bValidChartSel = FALSE;
+ break;
+ }
+ }
+ nCellCnt = 1;
+ nYPos = (rCF.pFrm->Frm().*fnRect->fnGetTop)();
+ nHeight = (rCF.pFrm->Frm().*fnRect->fnGetHeight)();
+
+ nXPos = bRTL ?
+ (rCF.pFrm->Frm().*fnRect->fnGetLeft)() :
+ (rCF.pFrm->Frm().*fnRect->fnGetRight)();
+ }
+ else if( nXPos == ( bRTL ?
+ (rCF.pFrm->Frm().*fnRect->fnGetRight)() :
+ (rCF.pFrm->Frm().*fnRect->fnGetLeft)() ) &&
+ nHeight == (rCF.pFrm->Frm().*fnRect->fnGetHeight)() )
+ {
+ nXPos += ( bRTL ? (-1) : 1 ) *
+ (rCF.pFrm->Frm().*fnRect->fnGetWidth)();
+ ++nCellCnt;
+ }
+ else
+ {
+ bValidChartSel = FALSE;
+ break;
+ }
+ }
+ if( bValidChartSel )
+ {
+ if( USHRT_MAX == nRowCells )
+ nRowCells = nCellCnt;
+ else if( nRowCells != nCellCnt )
+ bValidChartSel = FALSE;
+ }
+
+ if( bValidChartSel && pGetCLines )
+ {
+ nYPos = LONG_MAX;
+ SwChartBoxes* pBoxes = 0;
+ for( n = 0, nEnd = aCellFrms.Count(); n < nEnd; ++n )
+ {
+ const _Sort_CellFrm& rCF = aCellFrms[ n ];
+ if( (rCF.pFrm->Frm().*fnRect->fnGetTop)() != nYPos )
+ {
+ pBoxes = new SwChartBoxes( 255 < nRowCells
+ ? 255 : (BYTE)nRowCells);
+ pGetCLines->C40_INSERT( SwChartBoxes, pBoxes, pGetCLines->Count() );
+ nYPos = (rCF.pFrm->Frm().*fnRect->fnGetTop)();
+ }
+ SwTableBoxPtr pBox = (SwTableBox*)rCF.pFrm->GetTabBox();
+ pBoxes->Insert( pBox, pBoxes->Count() );
+ }
+ }
+ }
+
+ if( bTblIsValid )
+ break;
+
+ // ansonsten das Layout der Tabelle kurz "kalkulieren" lassen
+ // und nochmals neu aufsetzen
+ SwTabFrm *pTable = aUnions[0]->GetTable();
+ for( i = 0; i < aUnions.Count(); ++i )
+ {
+ if( pTable->IsValid() )
+ pTable->InvalidatePos();
+ pTable->SetONECalcLowers();
+ pTable->Calc();
+ pTable->SetCompletePaint();
+ if( 0 == (pTable = pTable->GetFollow()) )
+ break;
+ }
+ --nLoopMax;
+ if( pGetCLines )
+ pGetCLines->DeleteAndDestroy( 0, pGetCLines->Count() );
+ } while( TRUE );
+
+ ASSERT( nLoopMax, "das Layout der Tabelle wurde nicht valide!" );
+
+ if( !bValidChartSel && pGetCLines )
+ pGetCLines->DeleteAndDestroy( 0, pGetCLines->Count() );
+
+ return bValidChartSel;
+}
+
+
+BOOL IsFrmInTblSel( const SwRect& rUnion, const SwFrm* pCell )
+{
+ ASSERT( pCell->IsCellFrm(), "Frame ohne Gazelle" );
+
+ if( pCell->FindTabFrm()->IsVertical() )
+ return ( rUnion.Right() >= pCell->Frm().Right() &&
+ rUnion.Left() <= pCell->Frm().Left() &&
+ (( rUnion.Top() <= pCell->Frm().Top()+20 &&
+ rUnion.Bottom() > pCell->Frm().Top() ) ||
+ ( rUnion.Top() >= pCell->Frm().Top() &&
+ rUnion.Bottom() < pCell->Frm().Bottom() )) ? TRUE : FALSE );
+
+ return (
+ rUnion.Top() <= pCell->Frm().Top() &&
+ rUnion.Bottom() >= pCell->Frm().Bottom() &&
+
+ (( rUnion.Left() <= pCell->Frm().Left()+20 &&
+ rUnion.Right() > pCell->Frm().Left() ) ||
+
+ ( rUnion.Left() >= pCell->Frm().Left() &&
+ rUnion.Right() < pCell->Frm().Right() )) ? TRUE : FALSE );
+}
+
+BOOL GetAutoSumSel( const SwCrsrShell& rShell, SwCellFrms& rBoxes )
+{
+ SwShellCrsr* pCrsr = rShell.pCurCrsr;
+ if ( rShell.IsTableMode() )
+ pCrsr = rShell.pTblCrsr;
+
+ const SwLayoutFrm *pStart = pCrsr->GetCntntNode()->GetFrm(
+ &pCrsr->GetPtPos() )->GetUpper(),
+ *pEnd = pCrsr->GetCntntNode(FALSE)->GetFrm(
+ &pCrsr->GetMkPos() )->GetUpper();
+
+ const SwLayoutFrm* pSttCell = pStart;
+ while( pSttCell && !pSttCell->IsCellFrm() )
+ pSttCell = pSttCell->GetUpper();
+
+ //Zuerst lassen wir uns die Tabellen und die Rechtecke heraussuchen.
+ SwSelUnions aUnions;
+
+ // default erstmal nach oben testen, dann nach links
+ ::MakeSelUnions( aUnions, pStart, pEnd, nsSwTblSearchType::TBLSEARCH_COL );
+
+ BOOL bTstRow = TRUE, bFound = FALSE;
+ USHORT i;
+
+ // 1. teste ob die darueber liegende Box Value/Formel enhaelt:
+ for( i = 0; i < aUnions.Count(); ++i )
+ {
+ SwSelUnion *pUnion = aUnions[i];
+ const SwTabFrm *pTable = pUnion->GetTable();
+
+ // Skip any repeated headlines in the follow:
+ const SwLayoutFrm* pRow = pTable->IsFollow() ?
+ pTable->GetFirstNonHeadlineRow() :
+ (const SwLayoutFrm*)pTable->Lower();
+
+ while( pRow )
+ {
+ if( pRow->Frm().IsOver( pUnion->GetUnion() ) )
+ {
+ const SwCellFrm* pUpperCell = 0;
+ const SwLayoutFrm *pCell = pRow->FirstCell();
+
+ while( pCell && pRow->IsAnLower( pCell ) )
+ {
+ if( pCell == pSttCell )
+ {
+ USHORT nWhichId = 0;
+ for( USHORT n = rBoxes.Count(); n; )
+ if( USHRT_MAX != ( nWhichId = rBoxes[ --n ]
+ ->GetTabBox()->IsFormulaOrValueBox() ))
+ break;
+
+ // alle Boxen zusammen, nicht mehr die Zeile
+ // pruefen, wenn eine Formel oder Value gefunden wurde
+ bTstRow = 0 == nWhichId || USHRT_MAX == nWhichId;
+ bFound = TRUE;
+ break;
+ }
+
+ ASSERT( pCell->IsCellFrm(), "Frame ohne Celle" );
+ if( ::IsFrmInTblSel( pUnion->GetUnion(), pCell ) )
+ pUpperCell = (SwCellFrm*)pCell;
+
+ if( pCell->GetNext() )
+ {
+ pCell = (const SwLayoutFrm*)pCell->GetNext();
+ if ( pCell->Lower() && pCell->Lower()->IsRowFrm() )
+ pCell = pCell->FirstCell();
+ }
+ else
+ pCell = ::lcl_FindNextCellFrm( pCell );
+ }
+
+ if( pUpperCell )
+ rBoxes.Insert( pUpperCell, rBoxes.Count() );
+ }
+ if( bFound )
+ {
+ i = aUnions.Count();
+ break;
+ }
+ pRow = (const SwLayoutFrm*)pRow->GetNext();
+ }
+ }
+
+
+ // 2. teste ob die links liegende Box Value/Formel enhaelt:
+ if( bTstRow )
+ {
+ bFound = FALSE;
+
+ rBoxes.Remove( 0, rBoxes.Count() );
+ aUnions.DeleteAndDestroy( 0, aUnions.Count() );
+ ::MakeSelUnions( aUnions, pStart, pEnd, nsSwTblSearchType::TBLSEARCH_ROW );
+
+ for( i = 0; i < aUnions.Count(); ++i )
+ {
+ SwSelUnion *pUnion = aUnions[i];
+ const SwTabFrm *pTable = pUnion->GetTable();
+
+ // Skip any repeated headlines in the follow:
+ const SwLayoutFrm* pRow = pTable->IsFollow() ?
+ pTable->GetFirstNonHeadlineRow() :
+ (const SwLayoutFrm*)pTable->Lower();
+
+ while( pRow )
+ {
+ if( pRow->Frm().IsOver( pUnion->GetUnion() ) )
+ {
+ const SwLayoutFrm *pCell = pRow->FirstCell();
+
+ while( pCell && pRow->IsAnLower( pCell ) )
+ {
+ if( pCell == pSttCell )
+ {
+ USHORT nWhichId = 0;
+ for( USHORT n = rBoxes.Count(); n; )
+ if( USHRT_MAX != ( nWhichId = rBoxes[ --n ]
+ ->GetTabBox()->IsFormulaOrValueBox() ))
+ break;
+
+ // alle Boxen zusammen, nicht mehr die Zeile
+ // pruefen, wenn eine Formel oder Value gefunden wurde
+ bFound = 0 != nWhichId && USHRT_MAX != nWhichId;
+ bTstRow = FALSE;
+ break;
+ }
+
+ ASSERT( pCell->IsCellFrm(), "Frame ohne Celle" );
+ if( ::IsFrmInTblSel( pUnion->GetUnion(), pCell ) )
+ {
+ const SwCellFrm* pC = (SwCellFrm*)pCell;
+ rBoxes.Insert( pC, rBoxes.Count() );
+ }
+ if( pCell->GetNext() )
+ {
+ pCell = (const SwLayoutFrm*)pCell->GetNext();
+ if ( pCell->Lower() && pCell->Lower()->IsRowFrm() )
+ pCell = pCell->FirstCell();
+ }
+ else
+ pCell = ::lcl_FindNextCellFrm( pCell );
+ }
+ }
+ if( !bTstRow )
+ {
+ i = aUnions.Count();
+ break;
+ }
+
+ pRow = (const SwLayoutFrm*)pRow->GetNext();
+ }
+ }
+ }
+
+ return bFound;
+}
+
+BOOL HasProtectedCells( const SwSelBoxes& rBoxes )
+{
+ BOOL bRet = FALSE;
+ for( USHORT n = 0, nCnt = rBoxes.Count(); n < nCnt; ++n )
+ if( rBoxes[ n ]->GetFrmFmt()->GetProtect().IsCntntProtected() )
+ {
+ bRet = TRUE;
+ break;
+ }
+ return bRet;
+}
+
+
+_CmpLPt::_CmpLPt( const Point& rPt, const SwTableBox* pBox, BOOL bVertical )
+ : aPos( rPt ), pSelBox( pBox ), bVert( bVertical )
+{}
+
+void lcl_InsTblBox( SwTableNode* pTblNd, SwDoc* pDoc, SwTableBox* pBox,
+ USHORT nInsPos, USHORT nCnt = 1 )
+{
+ ASSERT( pBox->GetSttNd(), "Box ohne Start-Node" );
+ SwCntntNode* pCNd = pDoc->GetNodes()[ pBox->GetSttIdx() + 1 ]
+ ->GetCntntNode();
+ if( pCNd && pCNd->IsTxtNode() )
+ pDoc->GetNodes().InsBoxen( pTblNd, pBox->GetUpper(),
+ (SwTableBoxFmt*)pBox->GetFrmFmt(),
+ ((SwTxtNode*)pCNd)->GetTxtColl(),
+ pCNd->GetpSwAttrSet(),
+ nInsPos, nCnt );
+ else
+ pDoc->GetNodes().InsBoxen( pTblNd, pBox->GetUpper(),
+ (SwTableBoxFmt*)pBox->GetFrmFmt(),
+ (SwTxtFmtColl*)pDoc->GetDfltTxtFmtColl(), 0,
+ nInsPos, nCnt );
+}
+
+BOOL IsEmptyBox( const SwTableBox& rBox, SwPaM& rPam )
+{
+ rPam.GetPoint()->nNode = *rBox.GetSttNd()->EndOfSectionNode();
+ rPam.Move( fnMoveBackward, fnGoCntnt );
+ rPam.SetMark();
+ rPam.GetPoint()->nNode = *rBox.GetSttNd();
+ rPam.Move( fnMoveForward, fnGoCntnt );
+ BOOL bRet = *rPam.GetMark() == *rPam.GetPoint()
+ && ( rBox.GetSttNd()->GetIndex() + 1 == rPam.GetPoint()->nNode.GetIndex() );
+
+ if( bRet )
+ {
+ // dann teste mal auf absatzgebundenen Flys
+ const SwSpzFrmFmts& rFmts = *rPam.GetDoc()->GetSpzFrmFmts();
+ ULONG nSttIdx = rPam.GetPoint()->nNode.GetIndex(),
+ nEndIdx = rBox.GetSttNd()->EndOfSectionIndex(),
+ nIdx;
+
+ for( USHORT n = 0; n < rFmts.Count(); ++n )
+ {
+ const SwFmtAnchor& rAnchor = rFmts[n]->GetAnchor();
+ const SwPosition* pAPos = rAnchor.GetCntntAnchor();
+ if (pAPos &&
+ ((FLY_AT_PARA == rAnchor.GetAnchorId()) ||
+ (FLY_AT_CHAR == rAnchor.GetAnchorId())) &&
+ nSttIdx <= ( nIdx = pAPos->nNode.GetIndex() ) &&
+ nIdx < nEndIdx )
+ {
+ bRet = FALSE;
+ break;
+ }
+ }
+ }
+ return bRet;
+}
+
+
+void GetMergeSel( const SwPaM& rPam, SwSelBoxes& rBoxes,
+ SwTableBox** ppMergeBox, SwUndoTblMerge* pUndo )
+{
+ if( rBoxes.Count() )
+ rBoxes.Remove( USHORT(0), rBoxes.Count() );
+
+ //Zuerst lassen wir uns die Tabellen und die Rechtecke heraussuchen.
+ ASSERT( rPam.GetCntntNode() && rPam.GetCntntNode( FALSE ),
+ "Tabselection nicht auf Cnt." );
+
+//JP 24.09.96: Merge mit wiederholenden TabellenHeadline funktioniert nicht
+// richtig. Warum nicht Point 0,0 benutzen? Dann ist garantiert,
+// das die 1. Headline mit drin ist.
+// Point aPt( rShell.GetCharRect().Pos() );
+ Point aPt( 0, 0 );
+ const SwLayoutFrm *pStart = rPam.GetCntntNode()->GetFrm(
+ &aPt )->GetUpper(),
+ *pEnd = rPam.GetCntntNode(FALSE)->GetFrm(
+ &aPt )->GetUpper();
+
+ SwSelUnions aUnions;
+ ::MakeSelUnions( aUnions, pStart, pEnd );
+ if( !aUnions.Count() )
+ return;
+
+ const SwTable *pTable = aUnions[0]->GetTable()->GetTable();
+ SwDoc* pDoc = (SwDoc*)pStart->GetFmt()->GetDoc();
+ SwTableNode* pTblNd = (SwTableNode*)pTable->GetTabSortBoxes()[ 0 ]->
+ GetSttNd()->FindTableNode();
+
+ _MergePos aPosArr; // Sort-Array mit den Positionen der Frames
+ long nWidth;
+ SwTableBox* pLastBox = 0;
+
+ SWRECTFN( pStart->GetUpper() )
+
+ for ( USHORT i = 0; i < aUnions.Count(); ++i )
+ {
+ const SwTabFrm *pTabFrm = aUnions[i]->GetTable();
+
+ SwRect &rUnion = aUnions[i]->GetUnion();
+
+ // Skip any repeated headlines in the follow:
+ const SwLayoutFrm* pRow = pTabFrm->IsFollow() ?
+ pTabFrm->GetFirstNonHeadlineRow() :
+ (const SwLayoutFrm*)pTabFrm->Lower();
+
+ while ( pRow )
+ {
+ if ( pRow->Frm().IsOver( rUnion ) )
+ {
+ const SwLayoutFrm *pCell = pRow->FirstCell();
+
+ while ( pCell && pRow->IsAnLower( pCell ) )
+ {
+ ASSERT( pCell->IsCellFrm(), "Frame ohne Celle" );
+ // in der vollen Breite ueberlappend ?
+ if( rUnion.Top() <= pCell->Frm().Top() &&
+ rUnion.Bottom() >= pCell->Frm().Bottom() )
+ {
+ SwTableBox* pBox =(SwTableBox*)((SwCellFrm*)pCell)->GetTabBox();
+
+ // nur nach rechts ueberlappend
+ if( ( rUnion.Left() - COLFUZZY ) <= pCell->Frm().Left() &&
+ ( rUnion.Right() - COLFUZZY ) > pCell->Frm().Left() )
+ {
+ if( ( rUnion.Right() + COLFUZZY ) < pCell->Frm().Right() )
+ {
+ USHORT nInsPos = pBox->GetUpper()->
+ GetTabBoxes().C40_GETPOS( SwTableBox, pBox )+1;
+ lcl_InsTblBox( pTblNd, pDoc, pBox, nInsPos );
+ pBox->ClaimFrmFmt();
+ SwFmtFrmSize aNew(
+ pBox->GetFrmFmt()->GetFrmSize() );
+ nWidth = rUnion.Right() - pCell->Frm().Left();
+ nWidth = nWidth * aNew.GetWidth() /
+ pCell->Frm().Width();
+ long nTmpWidth = aNew.GetWidth() - nWidth;
+ aNew.SetWidth( nWidth );
+ pBox->GetFrmFmt()->SetFmtAttr( aNew );
+ // diese Box ist selektiert
+ pLastBox = pBox;
+ rBoxes.Insert( pBox );
+ aPosArr.Insert(
+ _CmpLPt( (pCell->Frm().*fnRect->fnGetPos)(),
+ pBox, bVert ) );
+
+ pBox = pBox->GetUpper()->GetTabBoxes()[ nInsPos ];
+ aNew.SetWidth( nTmpWidth );
+ pBox->ClaimFrmFmt();
+ pBox->GetFrmFmt()->SetFmtAttr( aNew );
+
+ if( pUndo )
+ pUndo->AddNewBox( pBox->GetSttIdx() );
+ }
+ else
+ {
+ // diese Box ist selektiert
+ pLastBox = pBox;
+ rBoxes.Insert( pBox );
+#if OSL_DEBUG_LEVEL > 1
+ Point aInsPoint( (pCell->Frm().*fnRect->fnGetPos)() );
+#endif
+ aPosArr.Insert(
+ _CmpLPt( (pCell->Frm().*fnRect->fnGetPos)(),
+ pBox, bVert ) );
+ }
+ }
+ // oder rechts und links ueberlappend
+ else if( ( rUnion.Left() - COLFUZZY ) >= pCell->Frm().Left() &&
+ ( rUnion.Right() + COLFUZZY ) < pCell->Frm().Right() )
+ {
+ USHORT nInsPos = pBox->GetUpper()->GetTabBoxes().
+ C40_GETPOS( SwTableBox, pBox )+1;
+ lcl_InsTblBox( pTblNd, pDoc, pBox, nInsPos, 2 );
+ pBox->ClaimFrmFmt();
+ SwFmtFrmSize aNew(
+ pBox->GetFrmFmt()->GetFrmSize() );
+ long nLeft = rUnion.Left() - pCell->Frm().Left();
+ nLeft = nLeft * aNew.GetWidth() /
+ pCell->Frm().Width();
+ long nRight = pCell->Frm().Right() - rUnion.Right();
+ nRight = nRight * aNew.GetWidth() /
+ pCell->Frm().Width();
+ nWidth = aNew.GetWidth() - nLeft - nRight;
+
+ aNew.SetWidth( nLeft );
+ pBox->GetFrmFmt()->SetFmtAttr( aNew );
+
+ {
+ const SfxPoolItem* pItem;
+ if( SFX_ITEM_SET == pBox->GetFrmFmt()->GetAttrSet()
+ .GetItemState( RES_BOX, FALSE, &pItem ))
+ {
+ SvxBoxItem aBox( *(SvxBoxItem*)pItem );
+ aBox.SetLine( 0, BOX_LINE_RIGHT );
+ pBox->GetFrmFmt()->SetFmtAttr( aBox );
+ }
+ }
+
+ pBox = pBox->GetUpper()->GetTabBoxes()[ nInsPos ];
+ aNew.SetWidth( nWidth );
+ pBox->ClaimFrmFmt();
+ pBox->GetFrmFmt()->SetFmtAttr( aNew );
+
+ if( pUndo )
+ pUndo->AddNewBox( pBox->GetSttIdx() );
+
+ // diese Box ist selektiert
+ pLastBox = pBox;
+ rBoxes.Insert( pBox );
+ aPosArr.Insert(
+ _CmpLPt( (pCell->Frm().*fnRect->fnGetPos)(),
+ pBox, bVert ) );
+
+ pBox = pBox->GetUpper()->GetTabBoxes()[ nInsPos+1 ];
+ aNew.SetWidth( nRight );
+ pBox->ClaimFrmFmt();
+ pBox->GetFrmFmt()->SetFmtAttr( aNew );
+
+ if( pUndo )
+ pUndo->AddNewBox( pBox->GetSttIdx() );
+ }
+ // oder reicht die rechte Kante der Box in den
+ // selektierten Bereich?
+ else if( ( pCell->Frm().Right() - COLFUZZY ) < rUnion.Right() &&
+ ( pCell->Frm().Right() - COLFUZZY ) > rUnion.Left() &&
+ ( pCell->Frm().Left() + COLFUZZY ) < rUnion.Left() )
+ {
+ // dann muss eine neue Box einfuegt und die
+ // Breiten angepasst werden
+ USHORT nInsPos = pBox->GetUpper()->GetTabBoxes().
+ C40_GETPOS( SwTableBox, pBox )+1;
+ lcl_InsTblBox( pTblNd, pDoc, pBox, nInsPos, 1 );
+
+ SwFmtFrmSize aNew(pBox->GetFrmFmt()->GetFrmSize() );
+ long nLeft = rUnion.Left() - pCell->Frm().Left(),
+ nRight = pCell->Frm().Right() - rUnion.Left();
+
+ nLeft = nLeft * aNew.GetWidth() /
+ pCell->Frm().Width();
+ nRight = nRight * aNew.GetWidth() /
+ pCell->Frm().Width();
+
+ aNew.SetWidth( nLeft );
+ pBox->ClaimFrmFmt()->SetFmtAttr( aNew );
+
+ // diese Box ist selektiert
+ pBox = pBox->GetUpper()->GetTabBoxes()[ nInsPos ];
+ aNew.SetWidth( nRight );
+ pBox->ClaimFrmFmt();
+ pBox->GetFrmFmt()->SetFmtAttr( aNew );
+
+ pLastBox = pBox;
+ rBoxes.Insert( pBox );
+ aPosArr.Insert( _CmpLPt( Point( rUnion.Left(),
+ pCell->Frm().Top()), pBox, bVert ));
+
+ if( pUndo )
+ pUndo->AddNewBox( pBox->GetSttIdx() );
+ }
+ }
+ if ( pCell->GetNext() )
+ {
+ pCell = (const SwLayoutFrm*)pCell->GetNext();
+ // --> FME 2005-11-03 #125288# Check if table cell is not empty
+ if ( pCell->Lower() && pCell->Lower()->IsRowFrm() )
+ pCell = pCell->FirstCell();
+ }
+ else
+ pCell = ::lcl_FindNextCellFrm( pCell );
+ }
+ }
+ pRow = (const SwLayoutFrm*)pRow->GetNext();
+ }
+ }
+
+ // keine SSelection / keine gefundenen Boxen
+ if( 1 >= rBoxes.Count() )
+ return;
+
+ // dann suche mal alle Boxen, die nebeneinander liegen, und verbinde
+ // deren Inhalte mit Blanks. Alle untereinander liegende werden als
+ // Absaetze zusammengefasst
+
+ // 1. Loesung: gehe ueber das Array und
+ // alle auf der gleichen Y-Ebene werden mit Blanks getrennt
+ // alle anderen werden als Absaetze getrennt.
+ BOOL bCalcWidth = TRUE;
+ const SwTableBox* pFirstBox = aPosArr[ 0 ].pSelBox;
+
+ // JP 27.03.98: Optimierung - falls die Boxen einer Line leer sind,
+ // dann werden jetzt dafuer keine Blanks und
+ // kein Umbruch mehr eingefuegt.
+ //Block damit SwPaM, SwPosition vom Stack geloescht werden
+ {
+ SwPaM aPam( pDoc->GetNodes() );
+
+#if defined( DEL_ONLY_EMPTY_LINES )
+ nWidth = pFirstBox->GetFrmFmt()->GetFrmSize().GetWidth();
+ BOOL bEmptyLine = TRUE;
+ USHORT n, nSttPos = 0;
+
+ for( n = 0; n < aPosArr.Count(); ++n )
+ {
+ const _CmpLPt& rPt = aPosArr[ n ];
+ if( n && aPosArr[ n - 1 ].Y() == rPt.Y() ) // gleiche Ebene ?
+ {
+ if( bEmptyLine && !IsEmptyBox( *rPt.pSelBox, aPam ))
+ bEmptyLine = FALSE;
+ if( bCalcWidth )
+ nWidth += rPt.pSelBox->GetFrmFmt()->GetFrmSize().GetWidth();
+ }
+ else
+ {
+ if( bCalcWidth && n )
+ bCalcWidth = FALSE; // eine Zeile fertig
+
+ if( bEmptyLine && nSttPos < n )
+ {
+ // dann ist die gesamte Line leer und braucht
+ // nicht mit Blanks aufgefuellt und als Absatz
+ // eingefuegt werden.
+ if( pUndo )
+ for( USHORT i = nSttPos; i < n; ++i )
+ pUndo->SaveCollection( *aPosArr[ i ].pSelBox );
+
+ aPosArr.Remove( nSttPos, n - nSttPos );
+ n = nSttPos;
+ }
+ else
+ nSttPos = n;
+
+ bEmptyLine = IsEmptyBox( *aPosArr[n].pSelBox, aPam );
+ }
+ }
+ if( bEmptyLine && nSttPos < n )
+ {
+ if( pUndo )
+ for( USHORT i = nSttPos; i < n; ++i )
+ pUndo->SaveCollection( *aPosArr[ i ].pSelBox );
+ aPosArr.Remove( nSttPos, n - nSttPos );
+ }
+#elsif defined( DEL_EMPTY_BOXES_AT_START_AND_END )
+
+ nWidth = pFirstBox->GetFrmFmt()->GetFrmSize().GetWidth();
+ USHORT n, nSttPos = 0, nSEndPos = 0, nESttPos = 0;
+
+ for( n = 0; n < aPosArr.Count(); ++n )
+ {
+ const _CmpLPt& rPt = aPosArr[ n ];
+ if( n && aPosArr[ n - 1 ].Y() == rPt.Y() ) // gleiche Ebene ?
+ {
+ BOOL bEmptyBox = IsEmptyBox( *rPt.pSelBox, aPam );
+ if( bEmptyBox )
+ {
+ if( nSEndPos == n ) // der Anfang ist leer
+ nESttPos = ++nSEndPos;
+ }
+ else // das Ende kann leer sein
+ nESttPos = n+1;
+
+ if( bCalcWidth )
+ nWidth += rPt.pSelBox->GetFrmFmt()->GetFrmSize().GetWidth();
+ }
+ else
+ {
+ if( bCalcWidth && n )
+ bCalcWidth = FALSE; // eine Zeile fertig
+
+ // zuerst die vom Anfang
+ if( nSttPos < nSEndPos )
+ {
+ // dann ist der vorder Teil der Line leer und braucht
+ // nicht mit Blanks aufgefuellt werden.
+ if( pUndo )
+ for( USHORT i = nSttPos; i < nSEndPos; ++i )
+ pUndo->SaveCollection( *aPosArr[ i ].pSelBox );
+
+ USHORT nCnt = nSEndPos - nSttPos;
+ aPosArr.Remove( nSttPos, nCnt );
+ nESttPos -= nCnt;
+ n -= nCnt;
+ }
+
+ if( nESttPos < n )
+ {
+ // dann ist der vorder Teil der Line leer und braucht
+ // nicht mit Blanks aufgefuellt werden.
+ if( pUndo )
+ for( USHORT i = nESttPos; i < n; ++i )
+ pUndo->SaveCollection( *aPosArr[ i ].pSelBox );
+
+ USHORT nCnt = n - nESttPos;
+ aPosArr.Remove( nESttPos, nCnt );
+ n -= nCnt;
+ }
+
+ nSttPos = nSEndPos = nESttPos = n;
+ if( IsEmptyBox( *aPosArr[n].pSelBox, aPam ))
+ ++nSEndPos;
+ else
+ ++nESttPos;
+ }
+ }
+
+ // zuerst die vom Anfang
+ if( nSttPos < nSEndPos )
+ {
+ // dann ist der vorder Teil der Line leer und braucht
+ // nicht mit Blanks aufgefuellt werden.
+ if( pUndo )
+ for( USHORT i = nSttPos; i < nSEndPos; ++i )
+ pUndo->SaveCollection( *aPosArr[ i ].pSelBox );
+
+ USHORT nCnt = nSEndPos - nSttPos;
+ aPosArr.Remove( nSttPos, nCnt );
+ nESttPos -= nCnt;
+ n -= nCnt;
+ }
+ if( nESttPos < n )
+ {
+ // dann ist der vorder Teil der Line leer und braucht
+ // nicht mit Blanks aufgefuellt werden.
+ if( pUndo )
+ for( USHORT i = nESttPos; i < n; ++i )
+ pUndo->SaveCollection( *aPosArr[ i ].pSelBox );
+
+ USHORT nCnt = n - nESttPos;
+ aPosArr.Remove( nESttPos, nCnt );
+ }
+#else
+// DEL_ALL_EMPTY_BOXES
+
+ nWidth = 0;
+ long nY = aPosArr.Count() ?
+ ( bVert ?
+ aPosArr[ 0 ].X() :
+ aPosArr[ 0 ].Y() ) :
+ 0;
+
+ for( USHORT n = 0; n < aPosArr.Count(); ++n )
+ {
+ const _CmpLPt& rPt = aPosArr[ n ];
+ if( bCalcWidth )
+ {
+ if( nY == ( bVert ? rPt.X() : rPt.Y() ) ) // gleiche Ebene ?
+ nWidth += rPt.pSelBox->GetFrmFmt()->GetFrmSize().GetWidth();
+ else
+ bCalcWidth = FALSE; // eine Zeile fertig
+ }
+
+ if( IsEmptyBox( *rPt.pSelBox, aPam ) )
+ {
+ if( pUndo )
+ pUndo->SaveCollection( *rPt.pSelBox );
+
+ aPosArr.Remove( n, 1 );
+ --n;
+ }
+ }
+#endif
+ }
+
+ // lege schon mal die neue Box an
+ {
+ SwTableBox* pTmpBox = rBoxes[0];
+ SwTableLine* pInsLine = pTmpBox->GetUpper();
+ USHORT nInsPos = pInsLine->GetTabBoxes().C40_GETPOS( SwTableBox, pTmpBox );
+
+ lcl_InsTblBox( pTblNd, pDoc, pTmpBox, nInsPos );
+ (*ppMergeBox) = pInsLine->GetTabBoxes()[ nInsPos ];
+ pInsLine->GetTabBoxes().Remove( nInsPos ); // wieder austragen
+ (*ppMergeBox)->SetUpper( 0 );
+ (*ppMergeBox)->ClaimFrmFmt();
+
+ // setze die Umrandung: von der 1. Box die linke/obere von der
+ // letzten Box die rechte/untere Kante:
+ if( pLastBox && pFirstBox )
+ {
+ SvxBoxItem aBox( pFirstBox->GetFrmFmt()->GetBox() );
+ const SvxBoxItem& rBox = pLastBox->GetFrmFmt()->GetBox();
+ aBox.SetLine( rBox.GetRight(), BOX_LINE_RIGHT );
+ aBox.SetLine( rBox.GetBottom(), BOX_LINE_BOTTOM );
+ if( aBox.GetLeft() || aBox.GetTop() ||
+ aBox.GetRight() || aBox.GetBottom() )
+ (*ppMergeBox)->GetFrmFmt()->SetFmtAttr( aBox );
+ }
+ }
+
+ //Block damit SwPaM, SwPosition vom Stack geloescht werden
+ if( aPosArr.Count() )
+ {
+ SwTxtNode* pTxtNd = 0;
+ SwPosition aInsPos( *(*ppMergeBox)->GetSttNd() );
+ SwNodeIndex& rInsPosNd = aInsPos.nNode;
+
+ SwPaM aPam( aInsPos );
+
+ for( USHORT n = 0; n < aPosArr.Count(); ++n )
+ {
+ const _CmpLPt& rPt = aPosArr[ n ];
+ aPam.GetPoint()->nNode.Assign( *rPt.pSelBox->GetSttNd()->
+ EndOfSectionNode(), -1 );
+ SwCntntNode* pCNd = aPam.GetCntntNode();
+ USHORT nL = pCNd ? pCNd->Len() : 0;
+ aPam.GetPoint()->nContent.Assign( pCNd, nL );
+
+ SwNodeIndex aSttNdIdx( *rPt.pSelBox->GetSttNd(), 1 );
+ // ein Node muss in der Box erhalten bleiben (sonst wird beim
+ // Move die gesamte Section geloescht)
+ if( pUndo )
+ pDoc->DoUndo( FALSE );
+ pDoc->AppendTxtNode( *aPam.GetPoint() );
+ if( pUndo )
+ pDoc->DoUndo( TRUE );
+ SwNodeRange aRg( aSttNdIdx, aPam.GetPoint()->nNode );
+ rInsPosNd++;
+ if( pUndo )
+ pUndo->MoveBoxCntnt( pDoc, aRg, rInsPosNd );
+ else
+ {
+ pDoc->MoveNodeRange( aRg, rInsPosNd,
+ IDocumentContentOperations::DOC_MOVEDEFAULT );
+ }
+ // wo steht jetzt aInsPos ??
+
+ if( bCalcWidth )
+ bCalcWidth = FALSE; // eine Zeile fertig
+
+ // den initialen TextNode ueberspringen
+ rInsPosNd.Assign( pDoc->GetNodes(),
+ rInsPosNd.GetNode().EndOfSectionIndex() - 2 );
+ pTxtNd = rInsPosNd.GetNode().GetTxtNode();
+ if( pTxtNd )
+ aInsPos.nContent.Assign( pTxtNd, pTxtNd->GetTxt().Len() );
+ }
+
+ // in der MergeBox sollte jetzt der gesamte Text stehen
+ // loesche jetzt noch den initialen TextNode
+ ASSERT( (*ppMergeBox)->GetSttIdx()+2 <
+ (*ppMergeBox)->GetSttNd()->EndOfSectionIndex(),
+ "leere Box" );
+ SwNodeIndex aIdx( *(*ppMergeBox)->GetSttNd()->EndOfSectionNode(), -1 );
+ pDoc->GetNodes().Delete( aIdx, 1 );
+ }
+
+ // setze die Breite der Box
+ (*ppMergeBox)->GetFrmFmt()->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nWidth, 0 ));
+ if( pUndo )
+ pUndo->AddNewBox( (*ppMergeBox)->GetSttIdx() );
+}
+
+
+static BOOL lcl_CheckCol( const _FndBox*& rpFndBox, void* pPara );
+
+static BOOL lcl_CheckRow( const _FndLine*& rpFndLine, void* pPara )
+{
+ ((_FndLine*)rpFndLine)->GetBoxes().ForEach( &lcl_CheckCol, pPara );
+ return *(BOOL*)pPara;
+}
+
+static BOOL lcl_CheckCol( const _FndBox*& rpFndBox, void* pPara )
+{
+ if( !rpFndBox->GetBox()->GetSttNd() )
+ {
+ if( rpFndBox->GetLines().Count() !=
+ rpFndBox->GetBox()->GetTabLines().Count() )
+ *((BOOL*)pPara) = FALSE;
+ else
+ ((_FndBox*)rpFndBox)->GetLines().ForEach( &lcl_CheckRow, pPara );
+ }
+ // Box geschuetzt ??
+ else if( rpFndBox->GetBox()->GetFrmFmt()->GetProtect().IsCntntProtected() )
+ *((BOOL*)pPara) = FALSE;
+ return *(BOOL*)pPara;
+}
+
+
+USHORT CheckMergeSel( const SwPaM& rPam )
+{
+ SwSelBoxes aBoxes;
+//JP 24.09.96: Merge mit wiederholenden TabellenHeadline funktioniert nicht
+// richtig. Warum nicht Point 0,0 benutzen? Dann ist garantiert,
+// das die 1. Headline mit drin ist.
+ Point aPt;
+ const SwLayoutFrm *pStart = rPam.GetCntntNode()->GetFrm(
+ &aPt )->GetUpper(),
+ *pEnd = rPam.GetCntntNode(FALSE)->GetFrm(
+ &aPt )->GetUpper();
+ GetTblSel( pStart, pEnd, aBoxes, 0 );
+ return CheckMergeSel( aBoxes );
+}
+
+USHORT CheckMergeSel( const SwSelBoxes& rBoxes )
+{
+ USHORT eRet = TBLMERGE_NOSELECTION;
+ if( rBoxes.Count() )
+ {
+ eRet = TBLMERGE_OK;
+
+ _FndBox aFndBox( 0, 0 );
+ _FndPara aPara( rBoxes, &aFndBox );
+ const SwTableNode* pTblNd = aPara.rBoxes[0]->GetSttNd()->FindTableNode();
+ ((SwTable&)pTblNd->GetTable()).GetTabLines().ForEach(
+ &_FndLineCopyCol, &aPara );
+ if( aFndBox.GetLines().Count() )
+ {
+ BOOL bMergeSelOk = TRUE;
+ _FndBox* pFndBox = &aFndBox;
+ _FndLine* pFndLine = 0;
+ while( pFndBox && 1 == pFndBox->GetLines().Count() )
+ {
+ pFndLine = pFndBox->GetLines()[0];
+ if( 1 == pFndLine->GetBoxes().Count() )
+ pFndBox = pFndLine->GetBoxes()[0];
+ else
+ pFndBox = 0;
+ }
+ if( pFndBox )
+ pFndBox->GetLines().ForEach( &lcl_CheckRow, &bMergeSelOk );
+ else if( pFndLine )
+ pFndLine->GetBoxes().ForEach( &lcl_CheckCol, &bMergeSelOk );
+ if( !bMergeSelOk )
+ eRet = TBLMERGE_TOOCOMPLEX;
+ }
+ else
+ eRet = TBLMERGE_NOSELECTION;
+ }
+ return eRet;
+}
+
+//Ermittelt die von einer Tabellenselektion betroffenen Tabellen und die
+//Union-Rechteckte der Selektionen - auch fuer aufgespaltene Tabellen.
+SV_IMPL_PTRARR( SwSelUnions, SwSelUnion* );
+
+SwTwips lcl_CalcWish( const SwLayoutFrm *pCell, long nWish,
+ const long nAct )
+{
+ const SwLayoutFrm *pTmp = pCell;
+ if ( !nWish )
+ nWish = 1;
+
+ const sal_Bool bRTL = pCell->IsRightToLeft();
+ SwTwips nRet = bRTL ?
+ nAct - pCell->Frm().Width() :
+ 0;
+
+ while ( pTmp )
+ {
+ while ( pTmp->GetPrev() )
+ {
+ pTmp = (SwLayoutFrm*)pTmp->GetPrev();
+ long nTmp = pTmp->GetFmt()->GetFrmSize().GetWidth();
+ nRet += ( bRTL ? ( -1 ) : 1 ) * nTmp * nAct / nWish;
+ }
+ pTmp = pTmp->GetUpper()->GetUpper();
+ if ( pTmp && !pTmp->IsCellFrm() )
+ pTmp = 0;
+ }
+ return nRet;
+}
+
+/* MA: 20. Sep. 93 wird nicht mehr gebraucht.
+static const SwLayoutFrm *GetPrevCell( const SwLayoutFrm *pCell )
+{
+ const SwLayoutFrm *pLay = pCell->GetPrevLayoutLeaf();
+ if ( pLay && pLay->IsLayoutFrm() && !pLay->IsTab() )
+ {
+ //GetPrevLayoutLeaf() liefert ggf. auch die Umgebung einer Tab zurueck
+ //(naehmlich genau dann, wenn die Zelle noch Vorgaenger hat).
+ const SwFrm *pFrm = pLay->Lower();
+ while ( pFrm->GetNext() )
+ pFrm = pFrm->GetNext();
+ pLay = pFrm->IsTabFrm() ? (SwLayoutFrm*)pFrm : 0;
+ }
+ if ( pLay && pLay->IsTabFrm() )
+ {
+ //GetPrevLayoutLeaf() liefert ggf. auch Tabellen zurueck die letzte
+ //Zelle dieser Tabelle ist das das gesuchte Blatt.
+ pLay = ((SwTabFrm*)pLay)->FindLastCntnt()->GetUpper();
+ while ( !pLay->IsCellFrm() )
+ pLay = pLay->GetUpper();
+ }
+ return pLay;
+}
+*/
+
+void lcl_FindStartEndRow( const SwLayoutFrm *&rpStart,
+ const SwLayoutFrm *&rpEnd,
+ const int bChkProtected )
+{
+ //Start an den Anfang seiner Zeile setzen.
+ //End an das Ende seiner Zeile setzen.
+ rpStart = (SwLayoutFrm*)rpStart->GetUpper()->Lower();
+ while ( rpEnd->GetNext() )
+ rpEnd = (SwLayoutFrm*)rpEnd->GetNext();
+
+ SvPtrarr aSttArr( 8, 8 ), aEndArr( 8, 8 );
+ const SwLayoutFrm *pTmp;
+ for( pTmp = rpStart; (FRM_CELL|FRM_ROW) & pTmp->GetType();
+ pTmp = pTmp->GetUpper() )
+ {
+ void* p = (void*)pTmp;
+ aSttArr.Insert( p, 0 );
+ }
+ for( pTmp = rpEnd; (FRM_CELL|FRM_ROW) & pTmp->GetType();
+ pTmp = pTmp->GetUpper() )
+ {
+ void* p = (void*)pTmp;
+ aEndArr.Insert( p, 0 );
+ }
+
+ for( USHORT n = 0; n < aEndArr.Count() && n < aSttArr.Count(); ++n )
+ if( aSttArr[ n ] != aEndArr[ n ] )
+ {
+ // first unequal line or box - all odds are
+ if( n & 1 ) // 1, 3, 5, ... are boxes
+ {
+ rpStart = (SwLayoutFrm*)aSttArr[ n ];
+ rpEnd = (SwLayoutFrm*)aEndArr[ n ];
+ }
+ else // 0, 2, 4, ... are lines
+ {
+ // check if start & end line are the first & last Line of the
+ // box. If not return these cells.
+ // Else the hole line with all Boxes has to be deleted.
+ rpStart = (SwLayoutFrm*)aSttArr[ n+1 ];
+ rpEnd = (SwLayoutFrm*)aEndArr[ n+1 ];
+ if( n )
+ {
+ const SwCellFrm* pCellFrm = (SwCellFrm*)aSttArr[ n-1 ];
+ const SwTableLines& rLns = pCellFrm->
+ GetTabBox()->GetTabLines();
+ if( rLns[ 0 ] == ((SwRowFrm*)aSttArr[ n ])->GetTabLine() &&
+ rLns[ rLns.Count() - 1 ] ==
+ ((SwRowFrm*)aEndArr[ n ])->GetTabLine() )
+ {
+ rpStart = rpEnd = pCellFrm;
+ while ( rpStart->GetPrev() )
+ rpStart = (SwLayoutFrm*)rpStart->GetPrev();
+ while ( rpEnd->GetNext() )
+ rpEnd = (SwLayoutFrm*)rpEnd->GetNext();
+ }
+ }
+ }
+ break;
+ }
+
+ if( !bChkProtected ) // geschuetzte Zellen beachten ?
+ return;
+
+
+ //Anfang und Ende duerfen nicht auf geschuetzten Zellen liegen.
+ while ( rpStart->GetFmt()->GetProtect().IsCntntProtected() )
+ rpStart = (SwLayoutFrm*)rpStart->GetNext();
+ while ( rpEnd->GetFmt()->GetProtect().IsCntntProtected() )
+ rpEnd = (SwLayoutFrm*)rpEnd->GetPrev();
+}
+
+
+void lcl_FindStartEndCol( const SwLayoutFrm *&rpStart,
+ const SwLayoutFrm *&rpEnd,
+ const int bChkProtected )
+{
+ //Start und End senkrecht bis an den Rand der Tabelle denken; es muss
+ //die Gesamttabelle betrachtet werden, also inklusive Masters und
+ //Follows.
+ //Fuer den Start brauchen wir den Mutter-TabellenFrm.
+ if( !rpStart )
+ return;
+ const SwTabFrm *pOrg = rpStart->FindTabFrm();
+ const SwTabFrm *pTab = pOrg;
+
+ SWRECTFN( pTab )
+
+ sal_Bool bRTL = pTab->IsRightToLeft();
+ const long nTmpWish = pOrg->GetFmt()->GetFrmSize().GetWidth();
+ const long nWish = ( nTmpWish > 0 ) ? nTmpWish : 1;
+
+ while ( pTab->IsFollow() )
+ {
+ const SwFrm *pTmp = pTab->FindPrev();
+ ASSERT( pTmp->IsTabFrm(), "Vorgaenger vom Follow nicht der Master." );
+ pTab = (const SwTabFrm*)pTmp;
+ }
+
+ SwTwips nSX = 0;
+ SwTwips nSX2 = 0;
+
+ if ( pTab->GetTable()->IsNewModel() )
+ {
+ nSX = (rpStart->Frm().*fnRect->fnGetLeft )();
+ nSX2 = (rpStart->Frm().*fnRect->fnGetRight)();
+ }
+ else
+ {
+ const SwTwips nPrtWidth = (pTab->Prt().*fnRect->fnGetWidth)();
+ nSX = ::lcl_CalcWish( rpStart, nWish, nPrtWidth ) + (pTab->*fnRect->fnGetPrtLeft)();
+ nSX2 = nSX + (rpStart->GetFmt()->GetFrmSize().GetWidth() * nPrtWidth / nWish);
+ }
+
+ const SwLayoutFrm *pTmp = pTab->FirstCell();
+
+ while ( pTmp &&
+ (!pTmp->IsCellFrm() ||
+ ( ( ! bRTL && (pTmp->Frm().*fnRect->fnGetLeft)() < nSX &&
+ (pTmp->Frm().*fnRect->fnGetRight)()< nSX2 ) ||
+ bRTL && (pTmp->Frm().*fnRect->fnGetLeft)() > nSX &&
+ (pTmp->Frm().*fnRect->fnGetRight)()> nSX2 ) ) )
+ pTmp = pTmp->GetNextLayoutLeaf();
+
+ if ( pTmp )
+ rpStart = pTmp;
+
+ pTab = pOrg;
+
+ const SwTabFrm* pLastValidTab = pTab;
+ while ( pTab->GetFollow() )
+ {
+ //
+ // Check if pTab->GetFollow() is a valid follow table:
+ // Only follow tables with at least on non-FollowFlowLine
+ // should be considered.
+ //
+ if ( pTab->HasFollowFlowLine() )
+ {
+ pTab = pTab->GetFollow();
+ const SwFrm* pTmpRow = pTab->GetFirstNonHeadlineRow();
+ if ( pTmpRow && pTmpRow->GetNext() )
+ pLastValidTab = pTab;
+ }
+ else
+ pLastValidTab = pTab = pTab->GetFollow();
+ }
+ pTab = pLastValidTab;
+
+ SwTwips nEX = 0;
+
+ if ( pTab->GetTable()->IsNewModel() )
+ {
+ nEX = (rpEnd->Frm().*fnRect->fnGetLeft )();
+ }
+ else
+ {
+ const SwTwips nPrtWidth = (pTab->Prt().*fnRect->fnGetWidth)();
+ nEX = ::lcl_CalcWish( rpEnd, nWish, nPrtWidth ) + (pTab->*fnRect->fnGetPrtLeft)();
+ }
+
+ const SwCntntFrm* pLastCntnt = pTab->FindLastCntnt();
+ rpEnd = pLastCntnt ? pLastCntnt->GetUpper() : 0;
+ // --> FME 2006-07-17 #134385# Made code robust. If pTab does not have a lower,
+ // we would crash here.
+ if ( !pLastCntnt ) return;
+ // <--
+
+ while( !rpEnd->IsCellFrm() )
+ rpEnd = rpEnd->GetUpper();
+
+ while ( ( bRTL && (rpEnd->Frm().*fnRect->fnGetLeft)() < nEX ) ||
+ ( ! bRTL && (rpEnd->Frm().*fnRect->fnGetLeft)() > nEX ) )
+ {
+ const SwLayoutFrm* pTmpLeaf = rpEnd->GetPrevLayoutLeaf();
+ if( !pTmpLeaf || !pTab->IsAnLower( pTmpLeaf ) )
+ break;
+ rpEnd = pTmpLeaf;
+ }
+
+ if( !bChkProtected ) // geschuetzte Zellen beachten ?
+ return;
+
+ //Anfang und Ende duerfen nicht auf geschuetzten Zellen liegen.
+ //Also muss ggf. nocheinmal rueckwaerts gesucht werden.
+ while ( rpStart->GetFmt()->GetProtect().IsCntntProtected() )
+ {
+ const SwLayoutFrm *pTmpLeaf = rpStart;
+ pTmpLeaf = pTmpLeaf->GetNextLayoutLeaf();
+ while ( pTmpLeaf && (pTmpLeaf->Frm().*fnRect->fnGetLeft)() > nEX )//erstmal die Zeile ueberspr.
+ pTmpLeaf = pTmpLeaf->GetNextLayoutLeaf();
+ while ( pTmpLeaf && (pTmpLeaf->Frm().*fnRect->fnGetLeft)() < nSX &&
+ (pTmpLeaf->Frm().*fnRect->fnGetRight)()< nSX2 )
+ pTmpLeaf = pTmpLeaf->GetNextLayoutLeaf();
+ const SwTabFrm *pTmpTab = rpStart->FindTabFrm();
+ if ( !pTmpTab->IsAnLower( pTmpLeaf ) )
+ {
+ pTmpTab = pTmpTab->GetFollow();
+ rpStart = pTmpTab->FirstCell();
+ while ( (rpStart->Frm().*fnRect->fnGetLeft)() < nSX &&
+ (rpStart->Frm().*fnRect->fnGetRight)()< nSX2 )
+ rpStart = rpStart->GetNextLayoutLeaf();
+ }
+ else
+ rpStart = pTmpLeaf;
+ }
+ while ( rpEnd->GetFmt()->GetProtect().IsCntntProtected() )
+ {
+ const SwLayoutFrm *pTmpLeaf = rpEnd;
+ pTmpLeaf = pTmpLeaf->GetPrevLayoutLeaf();
+ while ( pTmpLeaf && (pTmpLeaf->Frm().*fnRect->fnGetLeft)() < nEX )//erstmal die Zeile ueberspr.
+ pTmpLeaf = pTmpLeaf->GetPrevLayoutLeaf();
+ while ( pTmpLeaf && (pTmpLeaf->Frm().*fnRect->fnGetLeft)() > nEX )
+ pTmpLeaf = pTmpLeaf->GetPrevLayoutLeaf();
+ const SwTabFrm *pTmpTab = rpEnd->FindTabFrm();
+ if ( !pTmpLeaf || !pTmpTab->IsAnLower( pTmpLeaf ) )
+ {
+ pTmpTab = (const SwTabFrm*)pTmpTab->FindPrev();
+ ASSERT( pTmpTab->IsTabFrm(), "Vorgaenger vom Follow nicht der Master.");
+ rpEnd = pTmpTab->FindLastCntnt()->GetUpper();
+ while( !rpEnd->IsCellFrm() )
+ rpEnd = rpEnd->GetUpper();
+ while ( (rpEnd->Frm().*fnRect->fnGetLeft)() > nEX )
+ rpEnd = rpEnd->GetPrevLayoutLeaf();
+ }
+ else
+ rpEnd = pTmpLeaf;
+ }
+}
+
+
+void MakeSelUnions( SwSelUnions& rUnions, const SwLayoutFrm *pStart,
+ const SwLayoutFrm *pEnd, const SwTblSearchType eSearchType )
+{
+ while ( pStart && !pStart->IsCellFrm() )
+ pStart = pStart->GetUpper();
+ while ( pEnd && !pEnd->IsCellFrm() )
+ pEnd = pEnd->GetUpper();
+
+ // #112697# Robust:
+ if ( !pStart || !pEnd )
+ {
+ ASSERT( false, "MakeSelUnions with pStart or pEnd not in CellFrm" )
+ return;
+ }
+
+ const SwTabFrm *pTable = pStart->FindTabFrm();
+ const SwTabFrm *pEndTable = pEnd->FindTabFrm();
+ if( !pTable || !pEndTable )
+ return;
+ BOOL bExchange = FALSE;
+
+ if ( pTable != pEndTable )
+ {
+ if ( !pTable->IsAnFollow( pEndTable ) )
+ {
+ ASSERT( pEndTable->IsAnFollow( pTable ), "Tabkette verknotet." );
+ bExchange = TRUE;
+ }
+ }
+ else
+ {
+ SWRECTFN( pTable )
+ long nSttTop = (pStart->Frm().*fnRect->fnGetTop)();
+ long nEndTop = (pEnd->Frm().*fnRect->fnGetTop)();
+ if( nSttTop == nEndTop )
+ {
+ if( (pStart->Frm().*fnRect->fnGetLeft)() >
+ (pEnd->Frm().*fnRect->fnGetLeft)() )
+ bExchange = TRUE;
+ }
+ else if( bVert == ( nSttTop < nEndTop ) )
+ bExchange = TRUE;
+ }
+ if ( bExchange )
+ {
+ const SwLayoutFrm *pTmp = pStart;
+ pStart = pEnd;
+ pEnd = pTmp;
+ //pTable und pEndTable nicht umsortieren, werden unten neu gesetzt.
+ //MA: 28. Dec. 93 Bug: 5190
+ }
+
+ //Start und End sind jetzt huebsch sortiert, jetzt muessen sie falls
+ //erwuenscht noch versetzt werden.
+ if( nsSwTblSearchType::TBLSEARCH_ROW == ((~nsSwTblSearchType::TBLSEARCH_PROTECT ) & eSearchType ) )
+ ::lcl_FindStartEndRow( pStart, pEnd, nsSwTblSearchType::TBLSEARCH_PROTECT & eSearchType );
+ else if( nsSwTblSearchType::TBLSEARCH_COL == ((~nsSwTblSearchType::TBLSEARCH_PROTECT ) & eSearchType ) )
+ ::lcl_FindStartEndCol( pStart, pEnd, nsSwTblSearchType::TBLSEARCH_PROTECT & eSearchType );
+
+ // --> FME 2006-07-17 #134385# Made code robust.
+ if ( !pEnd ) return;
+ // <--
+
+ //neu besorgen, da sie jetzt verschoben sind. MA: 28. Dec. 93 Bug 5190
+ pTable = pStart->FindTabFrm();
+ pEndTable = pEnd->FindTabFrm();
+
+ const long nStSz = pStart->GetFmt()->GetFrmSize().GetWidth();
+ const long nEdSz = pEnd->GetFmt()->GetFrmSize().GetWidth();
+ const long nWish = Max( 1L, pTable->GetFmt()->GetFrmSize().GetWidth() );
+ while ( pTable )
+ {
+ SWRECTFN( pTable )
+ const long nOfst = (pTable->*fnRect->fnGetPrtLeft)();
+ const long nPrtWidth = (pTable->Prt().*fnRect->fnGetWidth)();
+ long nSt1 = ::lcl_CalcWish( pStart, nWish, nPrtWidth ) + nOfst;
+ long nEd1 = ::lcl_CalcWish( pEnd, nWish, nPrtWidth ) + nOfst;
+
+ if ( nSt1 <= nEd1 )
+ nEd1 += (long)((nEdSz * nPrtWidth) / nWish) - 1;
+ else
+ nSt1 += (long)((nStSz * nPrtWidth) / nWish) - 1;
+
+ long nSt2;
+ long nEd2;
+ if( pTable->IsAnLower( pStart ) )
+ nSt2 = (pStart->Frm().*fnRect->fnGetTop)();
+ else
+ nSt2 = (pTable->Frm().*fnRect->fnGetTop)();
+ if( pTable->IsAnLower( pEnd ) )
+ nEd2 = (pEnd->Frm().*fnRect->fnGetBottom)();
+ else
+ nEd2 = (pTable->Frm().*fnRect->fnGetBottom)();
+ Point aSt, aEd;
+ if( nSt1 > nEd1 )
+ {
+ long nTmp = nSt1;
+ nSt1 = nEd1;
+ nEd1 = nTmp;
+ }
+ if( nSt2 > nEd2 )
+ {
+ long nTmp = nSt2;
+ nSt2 = nEd2;
+ nEd2 = nTmp;
+ }
+ if( bVert )
+ {
+ aSt = Point( nSt2, nSt1 );
+ aEd = Point( nEd2, nEd1 );
+ }
+ else
+ {
+ aSt = Point( nSt1, nSt2 );
+ aEd = Point( nEd1, nEd2 );
+ }
+
+ const Point aDiff( aEd - aSt );
+ SwRect aUnion( aSt, Size( aDiff.X(), aDiff.Y() ) );
+ aUnion.Justify();
+
+ // fuers
+ if( !(nsSwTblSearchType::TBLSEARCH_NO_UNION_CORRECT & eSearchType ))
+ {
+ //Leider ist die Union jetzt mit Rundungsfehlern behaftet und dadurch
+ //wuerden beim Split/Merge fehlertraechtige Umstaende entstehen.
+ //Um dies zu vermeiden werden jetzt fuer die Table die erste und
+ //letzte Zelle innerhalb der Union ermittelt und aus genau deren
+ //Werten wird die Union neu gebildet.
+ const SwLayoutFrm* pRow = pTable->IsFollow() ?
+ pTable->GetFirstNonHeadlineRow() :
+ (const SwLayoutFrm*)pTable->Lower();
+
+ while ( pRow && !pRow->Frm().IsOver( aUnion ) )
+ pRow = (SwLayoutFrm*)pRow->GetNext();
+
+ // --> FME 2004-07-26 #i31976#
+ // A follow flow row may contain emtpy cells. These are not
+ // considered by FirstCell(). Therefore we have to find
+ // the first cell manually:
+ const SwFrm* pTmpCell = 0;
+ if ( pTable->IsFollow() && pRow && pRow->IsInFollowFlowRow() )
+ {
+ const SwFrm* pTmpRow = pRow;
+ while ( pTmpRow && pTmpRow->IsRowFrm() )
+ {
+ pTmpCell = static_cast<const SwRowFrm*>(pTmpRow)->Lower();
+ pTmpRow = static_cast<const SwCellFrm*>(pTmpCell)->Lower();
+ }
+ ASSERT( !pTmpCell || pTmpCell->IsCellFrm(), "Lower of rowframe != cellframe?!" )
+ }
+ // <--
+
+ const SwLayoutFrm* pFirst = pTmpCell ?
+ static_cast<const SwLayoutFrm*>(pTmpCell) :
+ pRow ?
+ pRow->FirstCell() :
+ 0;
+
+ while ( pFirst && !::IsFrmInTblSel( aUnion, pFirst ) )
+ {
+ if ( pFirst->GetNext() )
+ {
+ pFirst = (const SwLayoutFrm*)pFirst->GetNext();
+ if ( pFirst->Lower() && pFirst->Lower()->IsRowFrm() )
+ pFirst = pFirst->FirstCell();
+ }
+ else
+ pFirst = ::lcl_FindNextCellFrm( pFirst );
+ }
+ const SwLayoutFrm* pLast = 0;
+ const SwFrm* pLastCntnt = pTable->FindLastCntnt();
+ if ( pLastCntnt )
+ pLast = ::lcl_FindCellFrm( pLastCntnt->GetUpper() );
+
+ while ( pLast && !::IsFrmInTblSel( aUnion, pLast ) )
+ pLast = ::lcl_FindCellFrm( pLast->GetPrevLayoutLeaf() );
+
+ if ( pFirst && pLast ) //Robust
+ {
+ aUnion = pFirst->Frm();
+ aUnion.Union( pLast->Frm() );
+ }
+ else
+ aUnion.Width( 0 );
+ }
+
+ if( (aUnion.*fnRect->fnGetWidth)() )
+ {
+ SwSelUnion *pTmp = new SwSelUnion( aUnion, (SwTabFrm*)pTable );
+ rUnions.C40_INSERT( SwSelUnion, pTmp, rUnions.Count() );
+ }
+
+ pTable = pTable->GetFollow();
+ if ( pTable != pEndTable && pEndTable->IsAnFollow( pTable ) )
+ pTable = 0;
+ }
+}
+
+BOOL CheckSplitCells( const SwCrsrShell& rShell, USHORT nDiv,
+ const SwTblSearchType eSearchType )
+{
+ if( !rShell.IsTableMode() )
+ rShell.GetCrsr();
+
+ return CheckSplitCells( *rShell.getShellCrsr(false), nDiv, eSearchType );
+}
+
+BOOL CheckSplitCells( const SwCursor& rCrsr, USHORT nDiv,
+ const SwTblSearchType eSearchType )
+{
+ if( 1 >= nDiv )
+ return FALSE;
+
+ USHORT nMinValue = nDiv * MINLAY;
+
+ //Start- und Endzelle besorgen und den naechsten fragen.
+ Point aPtPos, aMkPos;
+ const SwShellCrsr* pShCrsr = dynamic_cast<const SwShellCrsr*>(&rCrsr);
+ if( pShCrsr )
+ {
+ aPtPos = pShCrsr->GetPtPos();
+ aMkPos = pShCrsr->GetMkPos();
+ }
+ const SwLayoutFrm *pStart = rCrsr.GetCntntNode()->GetFrm(
+ &aPtPos )->GetUpper(),
+ *pEnd = rCrsr.GetCntntNode(FALSE)->GetFrm(
+ &aMkPos )->GetUpper();
+
+ SWRECTFN( pStart->GetUpper() )
+
+ //Zuerst lassen wir uns die Tabellen und die Rechtecke heraussuchen.
+ SwSelUnions aUnions;
+
+ ::MakeSelUnions( aUnions, pStart, pEnd, eSearchType );
+
+ //Jetzt zu jedem Eintrag die Boxen herausfischen und uebertragen.
+ for ( USHORT i = 0; i < aUnions.Count(); ++i )
+ {
+ SwSelUnion *pUnion = aUnions[i];
+ const SwTabFrm *pTable = pUnion->GetTable();
+
+ // Skip any repeated headlines in the follow:
+ const SwLayoutFrm* pRow = pTable->IsFollow() ?
+ pTable->GetFirstNonHeadlineRow() :
+ (const SwLayoutFrm*)pTable->Lower();
+
+ while ( pRow )
+ {
+ if ( pRow->Frm().IsOver( pUnion->GetUnion() ) )
+ {
+ const SwLayoutFrm *pCell = pRow->FirstCell();
+
+ while ( pCell && pRow->IsAnLower( pCell ) )
+ {
+ ASSERT( pCell->IsCellFrm(), "Frame ohne Celle" );
+ if( ::IsFrmInTblSel( pUnion->GetUnion(), pCell ) )
+ {
+ if( (pCell->Frm().*fnRect->fnGetWidth)() < nMinValue )
+ return FALSE;
+ }
+
+ if ( pCell->GetNext() )
+ {
+ pCell = (const SwLayoutFrm*)pCell->GetNext();
+ if ( pCell->Lower() && pCell->Lower()->IsRowFrm() )
+ pCell = pCell->FirstCell();
+ }
+ else
+ pCell = ::lcl_FindNextCellFrm( pCell );
+ }
+ }
+ pRow = (const SwLayoutFrm*)pRow->GetNext();
+ }
+ }
+ return TRUE;
+}
+
+// -------------------------------------------------------------------
+// Diese Klassen kopieren die aktuelle Tabellen-Selektion (rBoxes)
+// unter Beibehaltung der Tabellen-Struktur in eine eigene Struktur
+// neu: SS zum gezielten Loeschen/Retaurieren des Layouts.
+
+void lcl_InsertRow( SwTableLine &rLine, SwLayoutFrm *pUpper, SwFrm *pSibling )
+{
+ SwRowFrm *pRow = new SwRowFrm( rLine );
+ if ( pUpper->IsTabFrm() && ((SwTabFrm*)pUpper)->IsFollow() )
+ {
+ SwTabFrm* pTabFrm = (SwTabFrm*)pUpper;
+ pTabFrm->FindMaster()->InvalidatePos(); //kann die Zeile vielleicht aufnehmen
+
+ if ( pSibling && pTabFrm->IsInHeadline( *pSibling ) )
+ {
+ // Skip any repeated headlines in the follow:
+ pSibling = pTabFrm->GetFirstNonHeadlineRow();
+ }
+ }
+ pRow->Paste( pUpper, pSibling );
+ pRow->RegistFlys();
+}
+
+
+BOOL _FndBoxCopyCol( const SwTableBox*& rpBox, void* pPara )
+{
+ _FndPara* pFndPara = (_FndPara*)pPara;
+ _FndBox* pFndBox = new _FndBox( (SwTableBox*)rpBox, pFndPara->pFndLine );
+ if( rpBox->GetTabLines().Count() )
+ {
+ _FndPara aPara( *pFndPara, pFndBox );
+ pFndBox->GetBox()->GetTabLines().ForEach( &_FndLineCopyCol, &aPara );
+ if( !pFndBox->GetLines().Count() )
+ {
+ delete pFndBox;
+ return TRUE;
+ }
+ }
+ else
+ {
+ SwTableBoxPtr pSrch = (SwTableBoxPtr)rpBox;
+ USHORT nFndPos;
+ if( !pFndPara->rBoxes.Seek_Entry( pSrch, &nFndPos ))
+ {
+ delete pFndBox;
+ return TRUE;
+ }
+ }
+ pFndPara->pFndLine->GetBoxes().C40_INSERT( _FndBox, pFndBox,
+ pFndPara->pFndLine->GetBoxes().Count() );
+ return TRUE;
+}
+
+BOOL _FndLineCopyCol( const SwTableLine*& rpLine, void* pPara )
+{
+ _FndPara* pFndPara = (_FndPara*)pPara;
+ _FndLine* pFndLine = new _FndLine( (SwTableLine*)rpLine, pFndPara->pFndBox );
+ _FndPara aPara( *pFndPara, pFndLine );
+ pFndLine->GetLine()->GetTabBoxes().ForEach( &_FndBoxCopyCol, &aPara );
+ if( pFndLine->GetBoxes().Count() )
+ {
+ pFndPara->pFndBox->GetLines().C40_INSERT( _FndLine, pFndLine,
+ pFndPara->pFndBox->GetLines().Count() );
+ }
+ else
+ delete pFndLine;
+ return TRUE;
+}
+
+void _FndBox::SetTableLines( const SwSelBoxes &rBoxes, const SwTable &rTable )
+{
+ //Pointer auf die Lines vor und hinter den zu verarbeitenden Bereich
+ //setzen. Wenn die erste/letzte Zeile in den Bereich eingeschlossen
+ //sind, so bleiben die Pointer eben einfach 0.
+ //Gesucht werden zunachst die Positionen der ersten/letzten betroffenen
+ //Line im Array der SwTable. Damit die 0 fuer 'keine Line' verwand werden
+ //kann werden die Positionen um 1 nach oben versetzt!
+
+ USHORT nStPos = USHRT_MAX;
+ USHORT nEndPos= 0;
+
+ for ( USHORT i = 0; i < rBoxes.Count(); ++i )
+ {
+ SwTableLine *pLine = rBoxes[i]->GetUpper();
+ while ( pLine->GetUpper() )
+ pLine = pLine->GetUpper()->GetUpper();
+ const USHORT nPos = rTable.GetTabLines().GetPos(
+ (const SwTableLine*&)pLine ) + 1;
+
+ ASSERT( nPos != USHRT_MAX, "TableLine not found." );
+
+ if( nStPos > nPos )
+ nStPos = nPos;
+
+ if( nEndPos < nPos )
+ nEndPos = nPos;
+ }
+ if ( nStPos > 1 )
+ pLineBefore = rTable.GetTabLines()[nStPos - 2];
+ if ( nEndPos < rTable.GetTabLines().Count() )
+ pLineBehind = rTable.GetTabLines()[nEndPos];
+}
+
+void _FndBox::SetTableLines( const SwTable &rTable )
+{
+ // Pointer auf die Lines vor und hinter den zu verarbeitenden Bereich
+ // setzen. Wenn die erste/letzte Zeile in den Bereich eingeschlossen
+ // sind, so bleiben die Pointer eben einfach 0.
+ // Die Positionen der ersten/letzten betroffenen Line im Array der
+ // SwTable steht in der FndBox. Damit die 0 fuer 'keine Line' verwand
+ // werdenkann werden die Positionen um 1 nach oben versetzt!
+
+ if( !GetLines().Count() )
+ return;
+
+ SwTableLine* pTmpLine = GetLines()[0]->GetLine();
+ USHORT nPos = rTable.GetTabLines().C40_GETPOS( SwTableLine, pTmpLine );
+ ASSERT( USHRT_MAX != nPos, "Line steht nicht in der Tabelle" );
+ if( nPos )
+ pLineBefore = rTable.GetTabLines()[ nPos - 1 ];
+
+ pTmpLine = GetLines()[GetLines().Count()-1]->GetLine();
+ nPos = rTable.GetTabLines().C40_GETPOS( SwTableLine, pTmpLine );
+ ASSERT( USHRT_MAX != nPos, "Line steht nicht in der Tabelle" );
+ if( ++nPos < rTable.GetTabLines().Count() )
+ pLineBehind = rTable.GetTabLines()[nPos];
+}
+
+inline void UnsetFollow( SwFlowFrm *pTab )
+{
+ pTab->bIsFollow = FALSE;
+}
+
+void _FndBox::DelFrms( SwTable &rTable )
+{
+ //Alle Lines zwischen pLineBefore und pLineBehind muessen aus dem
+ //Layout ausgeschnitten und geloescht werden.
+ //Entstehen dabei leere Follows so muessen diese vernichtet werden.
+ //Wird ein Master vernichtet, so muss der Follow Master werden.
+ //Ein TabFrm muss immer uebrigbleiben.
+
+ USHORT nStPos = 0;
+ USHORT nEndPos= rTable.GetTabLines().Count() - 1;
+ if( rTable.IsNewModel() && pLineBefore )
+ rTable.CheckRowSpan( pLineBefore, true );
+ if ( pLineBefore )
+ {
+ nStPos = rTable.GetTabLines().GetPos(
+ (const SwTableLine*&)pLineBefore );
+ ASSERT( nStPos != USHRT_MAX, "Fuchs Du hast die Line gestohlen!" );
+ ++nStPos;
+ }
+ if( rTable.IsNewModel() && pLineBehind )
+ rTable.CheckRowSpan( pLineBehind, false );
+ if ( pLineBehind )
+ {
+ nEndPos = rTable.GetTabLines().GetPos(
+ (const SwTableLine*&)pLineBehind );
+ ASSERT( nEndPos != USHRT_MAX, "Fuchs Du hast die Line gestohlen!" );
+ --nEndPos;
+ }
+
+ for ( USHORT i = nStPos; i <= nEndPos; ++i)
+ {
+ SwFrmFmt *pFmt = rTable.GetTabLines()[i]->GetFrmFmt();
+ SwClientIter aIter( *pFmt );
+ SwClient* pLast = aIter.GoStart();
+ if( pLast )
+ {
+ do {
+ SwFrm *pFrm = PTR_CAST( SwFrm, pLast );
+ if ( pFrm &&
+ ((SwRowFrm*)pFrm)->GetTabLine() == rTable.GetTabLines()[i] )
+ {
+ BOOL bDel = TRUE;
+ SwTabFrm *pUp = !pFrm->GetPrev() && !pFrm->GetNext() ?
+ (SwTabFrm*)pFrm->GetUpper() : 0;
+ if ( !pUp )
+ {
+ const USHORT nRepeat =
+ ((SwTabFrm*)pFrm->GetUpper())->GetTable()->GetRowsToRepeat();
+ if ( nRepeat > 0 &&
+ ((SwTabFrm*)pFrm->GetUpper())->IsFollow() )
+ {
+ if ( !pFrm->GetNext() )
+ {
+ SwRowFrm* pFirstNonHeadline =
+ ((SwTabFrm*)pFrm->GetUpper())->GetFirstNonHeadlineRow();
+ if ( pFirstNonHeadline == pFrm )
+ {
+ pUp = (SwTabFrm*)pFrm->GetUpper();
+ }
+ }
+ }
+ }
+ if ( pUp )
+ {
+ SwTabFrm *pFollow = pUp->GetFollow();
+ SwTabFrm *pPrev = pUp->IsFollow() ? pUp : 0;
+ if ( pPrev )
+ {
+ SwFrm *pTmp = pPrev->FindPrev();
+ ASSERT( pTmp->IsTabFrm(),
+ "Vorgaenger vom Follow kein Master.");
+ pPrev = (SwTabFrm*)pTmp;
+ }
+ if ( pPrev )
+ {
+ pPrev->SetFollow( pFollow );
+ // --> FME 2006-01-31 #i60340# Do not transfer the
+ // flag from pUp to pPrev. pUp may still have the
+ // flag set although there is not more follow flow
+ // line associated with pUp.
+ pPrev->SetFollowFlowLine( FALSE );
+ // <--
+ }
+ else if ( pFollow )
+ ::UnsetFollow( pFollow );
+
+ //Ein TabellenFrm muss immer stehenbleiben!
+ if ( pPrev || pFollow )
+ {
+ // OD 26.08.2003 #i18103# - if table is in a section,
+ // lock the section, to avoid its delete.
+ {
+ SwSectionFrm* pSctFrm = pUp->FindSctFrm();
+ bool bOldSectLock = false;
+ if ( pSctFrm )
+ {
+ bOldSectLock = pSctFrm->IsColLocked();
+ pSctFrm->ColLock();
+ }
+ pUp->Cut();
+ if ( pSctFrm && !bOldSectLock )
+ {
+ pSctFrm->ColUnlock();
+ }
+ }
+ delete pUp;
+ bDel = FALSE;//Die Row wird mit in den Abgrund
+ //gerissen.
+ }
+ }
+ if ( bDel )
+ {
+ SwFrm* pTabFrm = pFrm->GetUpper();
+ if ( pTabFrm->IsTabFrm() &&
+ !pFrm->GetNext() &&
+ ((SwTabFrm*)pTabFrm)->GetFollow() )
+ {
+ // We do not delete the follow flow line,
+ // this will be done automatically in the
+ // next turn.
+ ((SwTabFrm*)pTabFrm)->SetFollowFlowLine( FALSE );
+ }
+
+ pFrm->Cut();
+ delete pFrm;
+ }
+ }
+ } while( 0 != ( pLast = aIter++ ));
+ }
+ }
+}
+
+BOOL lcl_IsLineOfTblFrm( const SwTabFrm& rTable, const SwFrm& rChk )
+{
+ const SwTabFrm* pTblFrm = rChk.FindTabFrm();
+ if( pTblFrm->IsFollow() )
+ pTblFrm = pTblFrm->FindMaster( true );
+ return &rTable == pTblFrm;
+}
+
+/*
+ * lcl_UpdateRepeatedHeadlines
+ */
+void lcl_UpdateRepeatedHeadlines( SwTabFrm& rTabFrm, bool bCalcLowers )
+{
+ ASSERT( rTabFrm.IsFollow(), "lcl_UpdateRepeatedHeadlines called for non-follow tab" )
+
+ // Delete remaining headlines:
+ SwRowFrm* pLower = 0;
+ while ( 0 != ( pLower = (SwRowFrm*)rTabFrm.Lower() ) && pLower->IsRepeatedHeadline() )
+ {
+ pLower->Cut();
+ delete pLower;
+ }
+
+ // Insert fresh set of headlines:
+ pLower = (SwRowFrm*)rTabFrm.Lower();
+ SwTable& rTable = *rTabFrm.GetTable();
+ const USHORT nRepeat = rTable.GetRowsToRepeat();
+ for ( USHORT nIdx = 0; nIdx < nRepeat; ++nIdx )
+ {
+ SwRowFrm* pHeadline = new SwRowFrm(
+ *rTable.GetTabLines()[ nIdx ] );
+ pHeadline->SetRepeatedHeadline( true );
+ pHeadline->Paste( &rTabFrm, pLower );
+ pHeadline->RegistFlys();
+ }
+
+ if ( bCalcLowers )
+ rTabFrm.SetCalcLowers();
+}
+
+void _FndBox::MakeFrms( SwTable &rTable )
+{
+ //Alle Lines zwischen pLineBefore und pLineBehind muessen im Layout
+ //wieder neu erzeugt werden.
+ //Und Zwar fuer alle Auspraegungen der Tabelle (mehrere z.B. im Kopf/Fuss).
+
+ USHORT nStPos = 0;
+ USHORT nEndPos= rTable.GetTabLines().Count() - 1;
+ if ( pLineBefore )
+ {
+ nStPos = rTable.GetTabLines().GetPos(
+ (const SwTableLine*&)pLineBefore );
+ ASSERT( nStPos != USHRT_MAX, "Fuchs Du hast die Line gestohlen!" );
+ ++nStPos;
+
+ }
+ if ( pLineBehind )
+ {
+ nEndPos = rTable.GetTabLines().GetPos(
+ (const SwTableLine*&)pLineBehind );
+ ASSERT( nEndPos != USHRT_MAX, "Fuchs Du hast die Line gestohlen!" );
+ --nEndPos;
+ }
+ //Jetzt die grosse Einfuegeoperation fuer alle Tabllen.
+ SwClientIter aTabIter( *rTable.GetFrmFmt() );
+ for ( SwTabFrm *pTable = (SwTabFrm*)aTabIter.First( TYPE(SwFrm) ); pTable;
+ pTable = (SwTabFrm*)aTabIter.Next() )
+ {
+ if ( !pTable->IsFollow() )
+ {
+ SwFrm *pSibling = 0;
+ SwFrm *pUpperFrm = 0;
+ int i;
+ for ( i = rTable.GetTabLines().Count()-1;
+ i >= 0 && !pSibling; --i )
+ {
+ SwTableLine *pLine = pLineBehind ? pLineBehind :
+ rTable.GetTabLines()[static_cast<USHORT>(i)];
+ SwClientIter aIter( *pLine->GetFrmFmt() );
+ pSibling = (SwFrm*)aIter.First( TYPE(SwFrm) );
+ while ( pSibling && (
+ static_cast<SwRowFrm*>(pSibling)->GetTabLine() != pLine ||
+ !lcl_IsLineOfTblFrm( *pTable, *pSibling ) ||
+ static_cast<SwRowFrm*>(pSibling)->IsRepeatedHeadline() ||
+ // --> FME 2005-08-24 #i53647# If !pLineBehind,
+ // IsInSplitTableRow() should be checked.
+ ( pLineBehind && pSibling->IsInFollowFlowRow() ) ||
+ (!pLineBehind && pSibling->IsInSplitTableRow() ) ) )
+ // <--
+ {
+ pSibling = (SwFrm*)aIter.Next();
+ }
+ }
+ if ( pSibling )
+ {
+ pUpperFrm = pSibling->GetUpper();
+ if ( !pLineBehind )
+ pSibling = 0;
+ }
+ else
+// ???? oder das der Letzte Follow der Tabelle ????
+ pUpperFrm = pTable;
+
+ for ( i = nStPos; (USHORT)i <= nEndPos; ++i )
+ ::lcl_InsertRow( *rTable.GetTabLines()[static_cast<USHORT>(i)],
+ (SwLayoutFrm*)pUpperFrm, pSibling );
+ if ( pUpperFrm->IsTabFrm() )
+ ((SwTabFrm*)pUpperFrm)->SetCalcLowers();
+ }
+ else if ( rTable.GetRowsToRepeat() > 0 )
+ {
+ // Insert new headlines:
+ lcl_UpdateRepeatedHeadlines( *pTable, true );
+ }
+ }
+}
+
+void _FndBox::MakeNewFrms( SwTable &rTable, const USHORT nNumber,
+ const BOOL bBehind )
+{
+ //Frms fuer neu eingefuege Zeilen erzeugen.
+ //bBehind == TRUE: vor pLineBehind
+ // == FALSE: hinter pLineBefore
+ const USHORT nBfPos = pLineBefore ?
+ rTable.GetTabLines().GetPos( (const SwTableLine*&)pLineBefore ) :
+ USHRT_MAX;
+ const USHORT nBhPos = pLineBehind ?
+ rTable.GetTabLines().GetPos( (const SwTableLine*&)pLineBehind ) :
+ USHRT_MAX;
+
+ //nNumber: wie oft ist eingefuegt worden.
+ //nCnt: wieviele sind nNumber mal eingefuegt worden.
+
+ const USHORT nCnt =
+ ((nBhPos != USHRT_MAX ? nBhPos : rTable.GetTabLines().Count()) -
+ (nBfPos != USHRT_MAX ? nBfPos + 1 : 0)) / (nNumber + 1);
+
+ //Den Master-TabFrm suchen
+ SwClientIter aTabIter( *rTable.GetFrmFmt() );
+ SwTabFrm *pTable;
+ for ( pTable = (SwTabFrm*)aTabIter.First( TYPE(SwFrm) ); pTable;
+ pTable = (SwTabFrm*)aTabIter.Next() )
+ {
+ if( !pTable->IsFollow() )
+ {
+ SwFrm *pSibling = 0;
+ SwLayoutFrm *pUpperFrm = 0;
+ if ( bBehind )
+ {
+ if ( pLineBehind )
+ {
+ SwClientIter aIter( *pLineBehind->GetFrmFmt() );
+ pSibling = (SwFrm*)aIter.First( TYPE(SwFrm) );
+ while ( pSibling && (
+ // only consider row frames associated with pLineBehind:
+ static_cast<SwRowFrm*>(pSibling)->GetTabLine() != pLineBehind ||
+ // only consider row frames that are in pTables Master-Follow chain:
+ !lcl_IsLineOfTblFrm( *pTable, *pSibling ) ||
+ // only consider row frames that are not repeated headlines:
+ static_cast<SwRowFrm*>(pSibling)->IsRepeatedHeadline() ||
+ // only consider row frames that are not follow flow rows
+ pSibling->IsInFollowFlowRow() ) )
+ {
+ pSibling = (SwFrm*)aIter.Next();
+ }
+ }
+ if ( pSibling )
+ pUpperFrm = pSibling->GetUpper();
+ else
+ {
+ while( pTable->GetFollow() )
+ pTable = pTable->GetFollow();
+ pUpperFrm = pTable;
+ }
+ const USHORT nMax = nBhPos != USHRT_MAX ?
+ nBhPos : rTable.GetTabLines().Count();
+
+ USHORT i = nBfPos != USHRT_MAX ? nBfPos + 1 + nCnt : nCnt;
+
+ for ( ; i < nMax; ++i )
+ ::lcl_InsertRow( *rTable.GetTabLines()[i], pUpperFrm, pSibling );
+ if ( pUpperFrm->IsTabFrm() )
+ ((SwTabFrm*)pUpperFrm)->SetCalcLowers();
+ }
+ else //davor einfuegen
+ {
+ USHORT i;
+
+ // We are looking for the frame that is behind the row frame
+ // that should be inserted.
+ for ( i = 0; !pSibling; ++i )
+ {
+ SwTableLine* pLine = pLineBefore ? pLineBefore : rTable.GetTabLines()[i];
+
+ SwClientIter aIter( *pLine->GetFrmFmt() );
+ pSibling = (SwFrm*)aIter.First( TYPE(SwFrm) );
+
+ while ( pSibling && (
+ // only consider row frames associated with pLineBefore:
+ static_cast<SwRowFrm*>(pSibling)->GetTabLine() != pLine ||
+ // only consider row frames that are in pTables Master-Follow chain:
+ !lcl_IsLineOfTblFrm( *pTable, *pSibling ) ||
+ // only consider row frames that are not repeated headlines:
+ static_cast<SwRowFrm*>(pSibling)->IsRepeatedHeadline() ||
+ // 1. case: pLineBefore == 0:
+ // only consider row frames that are not follow flow rows
+ // 2. case: pLineBefore != 0:
+ // only consider row frames that are not split table rows
+ // --> FME 2004-11-23 #i37476# If !pLineBefore,
+ // check IsInFollowFlowRow instead of IsInSplitTableRow.
+ ( ( !pLineBefore && pSibling->IsInFollowFlowRow() ) ||
+ ( pLineBefore && pSibling->IsInSplitTableRow() ) ) ) )
+ // <--
+ {
+ pSibling = (SwFrm*)aIter.Next();
+ }
+ }
+
+ pUpperFrm = pSibling->GetUpper();
+ if ( pLineBefore )
+ pSibling = pSibling->GetNext();
+
+ USHORT nMax = nBhPos != USHRT_MAX ?
+ nBhPos - nCnt :
+ rTable.GetTabLines().Count() - nCnt;
+
+ i = nBfPos != USHRT_MAX ? nBfPos + 1 : 0;
+ for ( ; i < nMax; ++i )
+ ::lcl_InsertRow( *rTable.GetTabLines()[i],
+ pUpperFrm, pSibling );
+ if ( pUpperFrm->IsTabFrm() )
+ ((SwTabFrm*)pUpperFrm)->SetCalcLowers();
+ }
+ }
+ }
+
+ //Die Headlines mussen ggf. auch verarbeitet werden. Um gut arbeitenden
+ //Code nicht zu zerfasern wird hier nochmals iteriert.
+ const USHORT nRowsToRepeat = rTable.GetRowsToRepeat();
+ if ( nRowsToRepeat > 0 &&
+ ( ( !bBehind && ( nBfPos == USHRT_MAX || nBfPos + 1 < nRowsToRepeat ) ) ||
+ ( bBehind && ( ( nBfPos == USHRT_MAX && nRowsToRepeat > 1 ) || nBfPos + 2 < nRowsToRepeat ) ) ) )
+ {
+ for ( pTable = (SwTabFrm*)aTabIter.First( TYPE(SwFrm) ); pTable;
+ pTable = (SwTabFrm*)aTabIter.Next() )
+ {
+ if ( pTable->Lower() )
+ {
+ if ( pTable->IsFollow() )
+ {
+ lcl_UpdateRepeatedHeadlines( *pTable, true );
+ }
+
+ ASSERT( ((SwRowFrm*)pTable->Lower())->GetTabLine() ==
+ rTable.GetTabLines()[0], "MakeNewFrms: Table corruption!" )
+ }
+ }
+ }
+}
+
+BOOL _FndBox::AreLinesToRestore( const SwTable &rTable ) const
+{
+ //Lohnt es sich MakeFrms zu rufen?
+
+ if ( !pLineBefore && !pLineBehind && rTable.GetTabLines().Count() )
+ return TRUE;
+
+ USHORT nBfPos;
+ if(pLineBefore)
+ {
+ const SwTableLine* rLBefore = (const SwTableLine*)pLineBefore;
+ nBfPos = rTable.GetTabLines().GetPos( rLBefore );
+ }
+ else
+ nBfPos = USHRT_MAX;
+
+ USHORT nBhPos;
+ if(pLineBehind)
+ {
+ const SwTableLine* rLBehind = (const SwTableLine*)pLineBehind;
+ nBhPos = rTable.GetTabLines().GetPos( rLBehind );
+ }
+ else
+ nBhPos = USHRT_MAX;
+
+ if ( nBfPos == nBhPos ) //Duerfte eigentlich nie vorkommen.
+ {
+ ASSERT( FALSE, "Table, Loeschen auf keinem Bereich !?!" );
+ return FALSE;
+ }
+
+ if ( rTable.GetRowsToRepeat() > 0 )
+ {
+ // ups. sollte unsere zu wiederholende Kopfzeile geloescht worden
+ // sein??
+ SwClientIter aIter( *rTable.GetFrmFmt() );
+ for( SwTabFrm* pTable = (SwTabFrm*)aIter.First( TYPE( SwFrm ));
+ pTable; pTable = (SwTabFrm*)aIter.Next() )
+ {
+ if( pTable->IsFollow() )
+ {
+ // Insert new headlines:
+ lcl_UpdateRepeatedHeadlines( *pTable, false );
+ }
+ }
+ }
+
+ // Some adjacent lines at the beginning of the table have been deleted:
+ if ( nBfPos == USHRT_MAX && nBhPos == 0 )
+ return FALSE;
+
+ // Some adjacent lines at the end of the table have been deleted:
+ if ( nBhPos == USHRT_MAX && nBfPos == (rTable.GetTabLines().Count() - 1) )
+ return FALSE;
+
+ // Some adjacent lines in the middle of the table have been deleted:
+ if ( nBfPos != USHRT_MAX && nBhPos != USHRT_MAX && (nBfPos + 1) == nBhPos )
+ return FALSE;
+
+ // The structure of the deleted lines is more complex due to split lines.
+ // A call of MakeFrms() is necessary.
+ return TRUE;
+}
+
+