diff options
Diffstat (limited to 'sw/source/core/doc/tblrwcl.cxx')
-rw-r--r-- | sw/source/core/doc/tblrwcl.cxx | 4772 |
1 files changed, 4772 insertions, 0 deletions
diff --git a/sw/source/core/doc/tblrwcl.cxx b/sw/source/core/doc/tblrwcl.cxx new file mode 100644 index 000000000000..14a3ed87a8d1 --- /dev/null +++ b/sw/source/core/doc/tblrwcl.cxx @@ -0,0 +1,4772 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: tblrwcl.cxx,v $ + * $Revision: 1.29 $ + * + * 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 <com/sun/star/text/HoriOrientation.hpp> +#include <com/sun/star/chart2/XChartDocument.hpp> +#include <hintids.hxx> + +#define _ZFORLIST_DECLARE_TABLE +#include <svx/brshitem.hxx> +#include <svx/lrspitem.hxx> +#include <svx/protitem.hxx> +#include <svx/boxitem.hxx> +#include <tools/fract.hxx> +#include <fmtfsize.hxx> +#include <fmtornt.hxx> +#include <doc.hxx> +#include <cntfrm.hxx> +#include <tabfrm.hxx> +#include <frmtool.hxx> +#include <pam.hxx> +#include <swtable.hxx> +#include <ndtxt.hxx> +#include <tblsel.hxx> +#include <fldbas.hxx> +#include <swundo.hxx> +#include <rowfrm.hxx> +#include <ddefld.hxx> +#include <undobj.hxx> +#include <cellatr.hxx> +#include <mvsave.hxx> +#include <swtblfmt.hxx> +#include <swddetbl.hxx> +#include <poolfmt.hxx> +#include <tblrwcl.hxx> +#include <unochart.hxx> +#include <boost/shared_ptr.hpp> + +using namespace com::sun::star; +using namespace com::sun::star::uno; + + +#define COLFUZZY 20 +#define ROWFUZZY 10 + +using namespace ::com::sun::star; + +#ifdef PRODUCT +#define CHECK_TABLE(t) +#else +#ifdef DEBUG +#define CHECK_TABLE(t) (t).CheckConsistency(); +#else +#define CHECK_TABLE(t) +#endif +#endif + +typedef SwTableLine* SwTableLinePtr; +SV_DECL_PTRARR_SORT( SwSortTableLines, SwTableLinePtr, 16, 16 ) +SV_IMPL_PTRARR_SORT( SwSortTableLines, SwTableLinePtr ); + +SV_IMPL_PTRARR( _SwShareBoxFmts, SwShareBoxFmt* ) + +// fuers setzen der Frame-Formate an den Boxen reicht es, das aktuelle +// im Array zu suchen. Ist es vorhanden, so gebe das neue zurueck +struct _CpyTabFrm +{ + union { + SwTableBoxFmt *pFrmFmt; // fuer CopyCol + SwTwips nSize; // fuer DelCol + } Value; + SwTableBoxFmt *pNewFrmFmt; + + _CpyTabFrm( SwTableBoxFmt* pAktFrmFmt ) : pNewFrmFmt( 0 ) + { Value.pFrmFmt = pAktFrmFmt; } + + _CpyTabFrm& operator=( const _CpyTabFrm& ); + + BOOL operator==( const _CpyTabFrm& rCpyTabFrm ) + { return (ULONG)Value.nSize == (ULONG)rCpyTabFrm.Value.nSize; } + BOOL operator<( const _CpyTabFrm& rCpyTabFrm ) + { return (ULONG)Value.nSize < (ULONG)rCpyTabFrm.Value.nSize; } +}; + +struct CR_SetBoxWidth +{ + SwSelBoxes aBoxes; + SwSortTableLines aLines; + SvUShorts aLinesWidth; + SwShareBoxFmts aShareFmts; + SwTableNode* pTblNd; + SwUndoTblNdsChg* pUndo; + SwTwips nDiff, nSide, nMaxSize, nLowerDiff; + TblChgMode nMode; + USHORT nTblWidth, nRemainWidth, nBoxWidth; + BOOL bBigger, bLeft, bSplittBox, bAnyBoxFnd; + + CR_SetBoxWidth( USHORT eType, SwTwips nDif, SwTwips nSid, SwTwips nTblW, + SwTwips nMax, SwTableNode* pTNd ) + : pTblNd( pTNd ), + nDiff( nDif ), nSide( nSid ), nMaxSize( nMax ), nLowerDiff( 0 ), + nTblWidth( (USHORT)nTblW ), nRemainWidth( 0 ), nBoxWidth( 0 ), + bSplittBox( FALSE ), bAnyBoxFnd( FALSE ) + { + bLeft = nsTblChgWidthHeightType::WH_COL_LEFT == ( eType & 0xff ) || + nsTblChgWidthHeightType::WH_CELL_LEFT == ( eType & 0xff ); + bBigger = 0 != (eType & nsTblChgWidthHeightType::WH_FLAG_BIGGER ); + nMode = pTblNd->GetTable().GetTblChgMode(); + } + CR_SetBoxWidth( const CR_SetBoxWidth& rCpy ) + : pTblNd( rCpy.pTblNd ), + pUndo( rCpy.pUndo ), + nDiff( rCpy.nDiff ), nSide( rCpy.nSide ), + nMaxSize( rCpy.nMaxSize ), nLowerDiff( 0 ), + nMode( rCpy.nMode ), nTblWidth( rCpy.nTblWidth ), + nRemainWidth( rCpy.nRemainWidth ), nBoxWidth( nBoxWidth ), + bBigger( rCpy.bBigger ), bLeft( rCpy.bLeft ), + bSplittBox( rCpy.bSplittBox ), bAnyBoxFnd( rCpy.bAnyBoxFnd ) + { + aLines.Insert( &rCpy.aLines ); + aLinesWidth.Insert( &rCpy.aLinesWidth, 0 ); + } + + SwUndoTblNdsChg* CreateUndo( SwUndoId eUndoType ) + { + return pUndo = new SwUndoTblNdsChg( eUndoType, aBoxes, *pTblNd ); + } + + void LoopClear() + { + nLowerDiff = 0; nRemainWidth = 0; + } + + void AddBoxWidth( const SwTableBox& rBox, USHORT nWidth ) + { + SwTableLinePtr p = (SwTableLine*)rBox.GetUpper(); + USHORT nFndPos; + if( aLines.Insert( p, nFndPos )) + aLinesWidth.Insert( nWidth, nFndPos ); + else + aLinesWidth[ nFndPos ] = aLinesWidth[ nFndPos ] + nWidth; + } + + USHORT GetBoxWidth( const SwTableLine& rLn ) const + { + SwTableLinePtr p = (SwTableLine*)&rLn; + USHORT nFndPos; + if( aLines.Seek_Entry( p, &nFndPos ) ) + nFndPos = aLinesWidth[ nFndPos ]; + else + nFndPos = 0; + return nFndPos; + } +}; + +BOOL lcl_SetSelBoxWidth( SwTableLine* pLine, CR_SetBoxWidth& rParam, + SwTwips nDist, BOOL bCheck ); +BOOL lcl_SetOtherBoxWidth( SwTableLine* pLine, CR_SetBoxWidth& rParam, + SwTwips nDist, BOOL bCheck ); +BOOL lcl_InsSelBox( SwTableLine* pLine, CR_SetBoxWidth& rParam, + SwTwips nDist, BOOL bCheck ); +BOOL lcl_InsOtherBox( SwTableLine* pLine, CR_SetBoxWidth& rParam, + SwTwips nDist, BOOL bCheck ); +BOOL lcl_DelSelBox( SwTableLine* pLine, CR_SetBoxWidth& rParam, + SwTwips nDist, BOOL bCheck ); +BOOL lcl_DelOtherBox( SwTableLine* pLine, CR_SetBoxWidth& rParam, + SwTwips nDist, BOOL bCheck ); + +typedef BOOL (*FN_lcl_SetBoxWidth)(SwTableLine*, CR_SetBoxWidth&, SwTwips, BOOL ); + +#if !defined( PRODUCT ) || defined( JP_DEBUG ) + +void _CheckBoxWidth( const SwTableLine& rLine, SwTwips nSize ); + +#define CHECKBOXWIDTH \ + { \ + SwTwips nSize = GetFrmFmt()->GetFrmSize().GetWidth(); \ + for( USHORT nTmp = 0; nTmp < aLines.Count(); ++nTmp ) \ + ::_CheckBoxWidth( *aLines[ nTmp ], nSize ); \ + } + +#define CHECKTABLELAYOUT \ + { \ + for ( USHORT i = 0; i < GetTabLines().Count(); ++i ) \ + { \ + SwFrmFmt* pFmt = GetTabLines()[i]->GetFrmFmt(); \ + SwClientIter aIter( *pFmt ); \ + SwClient* pLast = aIter.GoStart(); \ + if( pLast ) \ + { \ + do \ + { \ + SwFrm *pFrm = PTR_CAST( SwFrm, pLast ); \ + if ( pFrm && \ + ((SwRowFrm*)pFrm)->GetTabLine() == GetTabLines()[i] ) \ + { \ + ASSERT( pFrm->GetUpper()->IsTabFrm(), \ + "Table layout does not match table structure" ) \ + } \ + } while ( 0 != ( pLast = aIter++ ) ); \ + } \ + } \ + } + +#else + +#define CHECKBOXWIDTH +#define CHECKTABLELAYOUT + +#endif + + +struct CR_SetLineHeight +{ + SwSelBoxes aBoxes; + SwShareBoxFmts aShareFmts; + SwTableNode* pTblNd; + SwUndoTblNdsChg* pUndo; + SwTwips nMaxSpace, nMaxHeight; + TblChgMode nMode; + USHORT nLines; + BOOL bBigger, bTop, bSplittBox, bAnyBoxFnd; + + CR_SetLineHeight( USHORT eType, SwTableNode* pTNd ) + : pTblNd( pTNd ), pUndo( 0 ), + nMaxSpace( 0 ), nMaxHeight( 0 ), nLines( 0 ), + bSplittBox( FALSE ), bAnyBoxFnd( FALSE ) + { + bTop = nsTblChgWidthHeightType::WH_ROW_TOP == ( eType & 0xff ) || nsTblChgWidthHeightType::WH_CELL_TOP == ( eType & 0xff ); + bBigger = 0 != (eType & nsTblChgWidthHeightType::WH_FLAG_BIGGER ); + if( eType & nsTblChgWidthHeightType::WH_FLAG_INSDEL ) + bBigger = !bBigger; + nMode = pTblNd->GetTable().GetTblChgMode(); + } + CR_SetLineHeight( const CR_SetLineHeight& rCpy ) + : pTblNd( rCpy.pTblNd ), pUndo( rCpy.pUndo ), + nMaxSpace( rCpy.nMaxSpace ), nMaxHeight( rCpy.nMaxHeight ), + nMode( rCpy.nMode ), nLines( rCpy.nLines ), + bBigger( rCpy.bBigger ), bTop( rCpy.bTop ), + bSplittBox( rCpy.bSplittBox ), bAnyBoxFnd( rCpy.bAnyBoxFnd ) + {} + + SwUndoTblNdsChg* CreateUndo( SwUndoId nUndoType ) + { + return pUndo = new SwUndoTblNdsChg( nUndoType, aBoxes, *pTblNd ); + } +}; + +BOOL lcl_SetSelLineHeight( SwTableLine* pLine, CR_SetLineHeight& rParam, + SwTwips nDist, BOOL bCheck ); +BOOL lcl_SetOtherLineHeight( SwTableLine* pLine, CR_SetLineHeight& rParam, + SwTwips nDist, BOOL bCheck ); +BOOL lcl_InsDelSelLine( SwTableLine* pLine, CR_SetLineHeight& rParam, + SwTwips nDist, BOOL bCheck ); + +typedef BOOL (*FN_lcl_SetLineHeight)(SwTableLine*, CR_SetLineHeight&, SwTwips, BOOL ); + +_CpyTabFrm& _CpyTabFrm::operator=( const _CpyTabFrm& rCpyTabFrm ) +{ + pNewFrmFmt = rCpyTabFrm.pNewFrmFmt; + Value = rCpyTabFrm.Value; + return *this; +} + +SV_DECL_VARARR_SORT( _CpyTabFrms, _CpyTabFrm, 0, 50 ) +SV_IMPL_VARARR_SORT( _CpyTabFrms, _CpyTabFrm ) + +void lcl_DelCpyTabFrmFmts( _CpyTabFrm& rArr ); + +// --------------------------------------------------------------- + +struct _CpyPara +{ + boost::shared_ptr< std::vector< std::vector< ULONG > > > pWidths; + SwDoc* pDoc; + SwTableNode* pTblNd; + _CpyTabFrms& rTabFrmArr; + SwTableLine* pInsLine; + SwTableBox* pInsBox; + ULONG nOldSize, nNewSize; // zum Korrigieren der Size-Attribute + ULONG nMinLeft, nMaxRight; + USHORT nCpyCnt, nInsPos; + USHORT nLnIdx, nBoxIdx; + BYTE nDelBorderFlag; + BOOL bCpyCntnt; + + _CpyPara( SwTableNode* pNd, USHORT nCopies, _CpyTabFrms& rFrmArr, + BOOL bCopyContent = TRUE ) + : pDoc( pNd->GetDoc() ), pTblNd( pNd ), rTabFrmArr(rFrmArr), + pInsLine(0), pInsBox(0), nOldSize(0), nNewSize(0), + nMinLeft(ULONG_MAX), nMaxRight(0), + nCpyCnt(nCopies), nInsPos(0), + nLnIdx(0), nBoxIdx(0), + nDelBorderFlag(0), bCpyCntnt( bCopyContent ) + {} + _CpyPara( const _CpyPara& rPara, SwTableLine* pLine ) + : pWidths( rPara.pWidths ), pDoc(rPara.pDoc), pTblNd(rPara.pTblNd), + rTabFrmArr(rPara.rTabFrmArr), pInsLine(pLine), pInsBox(rPara.pInsBox), + nOldSize(0), nNewSize(rPara.nNewSize), nMinLeft( rPara.nMinLeft ), + nMaxRight( rPara.nMaxRight ), nCpyCnt(rPara.nCpyCnt), nInsPos(0), + nLnIdx( rPara.nLnIdx), nBoxIdx( rPara.nBoxIdx ), + nDelBorderFlag( rPara.nDelBorderFlag ), bCpyCntnt( rPara.bCpyCntnt ) + {} + _CpyPara( const _CpyPara& rPara, SwTableBox* pBox ) + : pWidths( rPara.pWidths ), pDoc(rPara.pDoc), pTblNd(rPara.pTblNd), + rTabFrmArr(rPara.rTabFrmArr), pInsLine(rPara.pInsLine), pInsBox(pBox), + nOldSize(rPara.nOldSize), nNewSize(rPara.nNewSize), + nMinLeft( rPara.nMinLeft ), nMaxRight( rPara.nMaxRight ), + nCpyCnt(rPara.nCpyCnt), nInsPos(0), nLnIdx(rPara.nLnIdx), nBoxIdx(rPara.nBoxIdx), + nDelBorderFlag( rPara.nDelBorderFlag ), bCpyCntnt( rPara.bCpyCntnt ) + {} + void SetBoxWidth( SwTableBox* pBox ); +}; + + +BOOL lcl_CopyCol( const _FndBox*& rpFndBox, void* pPara ) +{ + _CpyPara* pCpyPara = (_CpyPara*)pPara; + + // suche das FrmFmt im Array aller Frame-Formate + SwTableBox* pBox = (SwTableBox*)rpFndBox->GetBox(); + _CpyTabFrm aFindFrm( (SwTableBoxFmt*)pBox->GetFrmFmt() ); + + USHORT nFndPos; + if( pCpyPara->nCpyCnt ) + { + if( !pCpyPara->rTabFrmArr.Seek_Entry( aFindFrm, &nFndPos )) + { + // fuer das verschachtelte Kopieren sicher auch das neue Format + // als alt. + SwTableBoxFmt* pNewFmt = (SwTableBoxFmt*)pBox->ClaimFrmFmt(); + + // suche die selektierten Boxen in der Line: + _FndLine* pCmpLine = NULL; + SwFmtFrmSize aFrmSz( pNewFmt->GetFrmSize() ); + + bool bDiffCount = false; + if( pBox->GetTabLines().Count() ) + { + pCmpLine = rpFndBox->GetLines()[ 0 ]; + if ( pCmpLine->GetBoxes().Count() != pCmpLine->GetLine()->GetTabBoxes().Count() ) + bDiffCount = true; + } + + if( bDiffCount ) + { + // die erste Line sollte reichen + _FndBoxes& rFndBoxes = pCmpLine->GetBoxes(); + long nSz = 0; + for( USHORT n = rFndBoxes.Count(); n; ) + nSz += rFndBoxes[ --n ]->GetBox()->GetFrmFmt()->GetFrmSize().GetWidth(); + aFrmSz.SetWidth( aFrmSz.GetWidth() - + nSz / ( pCpyPara->nCpyCnt + 1 ) ); + pNewFmt->SetFmtAttr( aFrmSz ); + aFrmSz.SetWidth( nSz / ( pCpyPara->nCpyCnt + 1 ) ); + + // fuer die neue Box ein neues Format mit der Groesse anlegen! + aFindFrm.pNewFrmFmt = (SwTableBoxFmt*)pNewFmt->GetDoc()-> + MakeTableLineFmt(); + *aFindFrm.pNewFrmFmt = *pNewFmt; + aFindFrm.pNewFrmFmt->SetFmtAttr( aFrmSz ); + } + else + { + aFrmSz.SetWidth( aFrmSz.GetWidth() / ( pCpyPara->nCpyCnt + 1 ) ); + pNewFmt->SetFmtAttr( aFrmSz ); + + aFindFrm.pNewFrmFmt = pNewFmt; + pCpyPara->rTabFrmArr.Insert( aFindFrm ); + aFindFrm.Value.pFrmFmt = pNewFmt; + pCpyPara->rTabFrmArr.Insert( aFindFrm ); + } + } + else + { + aFindFrm = pCpyPara->rTabFrmArr[ nFndPos ]; +// aFindFrm.pNewFrmFmt->Add( pBox ); + pBox->ChgFrmFmt( (SwTableBoxFmt*)aFindFrm.pNewFrmFmt ); + } + } + else + { + if( pCpyPara->nDelBorderFlag && + pCpyPara->rTabFrmArr.Seek_Entry( aFindFrm, &nFndPos )) + aFindFrm = pCpyPara->rTabFrmArr[ nFndPos ]; + else + aFindFrm.pNewFrmFmt = (SwTableBoxFmt*)pBox->GetFrmFmt(); + } + + if( rpFndBox->GetLines().Count() ) + { + pBox = new SwTableBox( aFindFrm.pNewFrmFmt, + rpFndBox->GetLines().Count(), pCpyPara->pInsLine ); + pCpyPara->pInsLine->GetTabBoxes().C40_INSERT( SwTableBox, pBox, pCpyPara->nInsPos++); + _CpyPara aPara( *pCpyPara, pBox ); + aPara.nDelBorderFlag &= 7; + + ((_FndBox*)rpFndBox)->GetLines().ForEach( &lcl_CopyRow, &aPara ); + } + else + { + ::_InsTblBox( pCpyPara->pDoc, pCpyPara->pTblNd, pCpyPara->pInsLine, + aFindFrm.pNewFrmFmt, pBox, pCpyPara->nInsPos++ ); + + const _FndBoxes& rFndBxs = rpFndBox->GetUpper()->GetBoxes(); + if( 8 > pCpyPara->nDelBorderFlag + ? pCpyPara->nDelBorderFlag + : rpFndBox == rFndBxs[ rFndBxs.Count() - 1 ] ) + { + const SvxBoxItem& rBoxItem = pBox->GetFrmFmt()->GetBox(); + if( 8 > pCpyPara->nDelBorderFlag + ? rBoxItem.GetTop() + : rBoxItem.GetRight() ) + { + aFindFrm.Value.pFrmFmt = (SwTableBoxFmt*)pBox->GetFrmFmt(); + + SvxBoxItem aNew( rBoxItem ); + if( 8 > pCpyPara->nDelBorderFlag ) + aNew.SetLine( 0, BOX_LINE_TOP ); + else + aNew.SetLine( 0, BOX_LINE_RIGHT ); + + if( 1 == pCpyPara->nDelBorderFlag || + 8 == pCpyPara->nDelBorderFlag ) + { + // es wird dahinter kopiert, bei allen Boxen die + // TopBorderLine loeschen + pBox = pCpyPara->pInsLine->GetTabBoxes()[ + pCpyPara->nInsPos - 1 ]; + } + + aFindFrm.pNewFrmFmt = (SwTableBoxFmt*)pBox->GetFrmFmt(); + + // ansonsten wird davor kopiert und die erste Line behaelt + // die TopLine und an der originalen wird sie entfernt + pBox->ClaimFrmFmt()->SetFmtAttr( aNew ); + + if( !pCpyPara->nCpyCnt ) + pCpyPara->rTabFrmArr.Insert( aFindFrm ); + } + } + } + return TRUE; +} + +BOOL lcl_CopyRow( const _FndLine*& rpFndLine, void* pPara ) +{ + _CpyPara* pCpyPara = (_CpyPara*)pPara; + SwTableLine* pNewLine = new SwTableLine( + (SwTableLineFmt*)rpFndLine->GetLine()->GetFrmFmt(), + rpFndLine->GetBoxes().Count(), pCpyPara->pInsBox ); + if( pCpyPara->pInsBox ) + { + pCpyPara->pInsBox->GetTabLines().C40_INSERT( SwTableLine, pNewLine, pCpyPara->nInsPos++ ); + } + else + { + pCpyPara->pTblNd->GetTable().GetTabLines().C40_INSERT( SwTableLine, pNewLine, + pCpyPara->nInsPos++ ); + } + + _CpyPara aPara( *pCpyPara, pNewLine ); + ((_FndLine*)rpFndLine)->GetBoxes().ForEach( &lcl_CopyCol, &aPara ); + + pCpyPara->nDelBorderFlag &= 0xf8; + return TRUE; +} + +//----------------------------------------------------------- + +void lcl_InsCol( _FndLine* pFndLn, _CpyPara& rCpyPara, USHORT nCpyCnt, + BOOL bBehind ) +{ + // Bug 29124: nicht nur in den Grundlines kopieren. Wenns geht, so weit + // runter wie moeglich. + _FndBox* pFBox; + if( 1 == pFndLn->GetBoxes().Count() && + !( pFBox = pFndLn->GetBoxes()[ 0 ] )->GetBox()->GetSttNd() ) + { + // eine Box mit mehreren Lines, also in diese Lines einfuegen + for( USHORT n = 0; n < pFBox->GetLines().Count(); ++n ) + lcl_InsCol( pFBox->GetLines()[ n ], rCpyPara, nCpyCnt, bBehind ); + } + else + { + rCpyPara.pInsLine = pFndLn->GetLine(); + SwTableBox* pBox = pFndLn->GetBoxes()[ bBehind ? + pFndLn->GetBoxes().Count()-1 : 0 ]->GetBox(); + rCpyPara.nInsPos = pFndLn->GetLine()->GetTabBoxes().C40_GETPOS( SwTableBox, pBox ); + if( bBehind ) + ++rCpyPara.nInsPos; + + for( USHORT n = 0; n < nCpyCnt; ++n ) + { + if( n + 1 == nCpyCnt && bBehind ) + rCpyPara.nDelBorderFlag = 9; + else + rCpyPara.nDelBorderFlag = 8; + pFndLn->GetBoxes().ForEach( &lcl_CopyCol, &rCpyPara ); + } + } +} + +SwRowFrm* GetRowFrm( SwTableLine& rLine ) +{ + SwClientIter aIter( *rLine.GetFrmFmt() ); + for( SwClient* pFrm = aIter.First( TYPE( SwRowFrm )); pFrm; + pFrm = aIter.Next() ) + if( ((SwRowFrm*)pFrm)->GetTabLine() == &rLine ) + return (SwRowFrm*)pFrm; + return 0; +} + + +BOOL SwTable::InsertCol( SwDoc* pDoc, const SwSelBoxes& rBoxes, USHORT nCnt, BOOL bBehind ) +{ + ASSERT( rBoxes.Count() && nCnt, "keine gueltige Box-Liste" ); + SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode(); + if( !pTblNd ) + return FALSE; + + BOOL bRes = TRUE; + if( IsNewModel() ) + bRes = NewInsertCol( pDoc, rBoxes, nCnt, bBehind ); + else + { + // suche alle Boxen / Lines + _FndBox aFndBox( 0, 0 ); + { + _FndPara aPara( rBoxes, &aFndBox ); + GetTabLines().ForEach( &_FndLineCopyCol, &aPara ); + } + if( !aFndBox.GetLines().Count() ) + return FALSE; + + SetHTMLTableLayout( 0 ); // MIB 9.7.97: HTML-Layout loeschen + + //Lines fuer das Layout-Update herausuchen. + aFndBox.SetTableLines( *this ); + aFndBox.DelFrms( *this ); + + // TL_CHART2: nothing to be done since chart2 currently does not want to + // get notified about new rows/cols. + + _CpyTabFrms aTabFrmArr; + _CpyPara aCpyPara( pTblNd, nCnt, aTabFrmArr ); + + for( USHORT n = 0; n < aFndBox.GetLines().Count(); ++n ) + lcl_InsCol( aFndBox.GetLines()[ n ], aCpyPara, nCnt, bBehind ); + + // dann raeume die Struktur dieser Line noch mal auf, generell alle + GCLines(); + + //Layout updaten + aFndBox.MakeFrms( *this ); + + CHECKBOXWIDTH + CHECKTABLELAYOUT + bRes = TRUE; + } + + SwChartDataProvider *pPCD = pDoc->GetChartDataProvider(); + if (pPCD && nCnt) + pPCD->AddRowCols( *this, rBoxes, nCnt, bBehind ); + pDoc->UpdateCharts( GetFrmFmt()->GetName() ); + + return bRes; +} + +BOOL SwTable::_InsertRow( SwDoc* pDoc, const SwSelBoxes& rBoxes, + USHORT nCnt, BOOL bBehind ) +{ + ASSERT( pDoc && rBoxes.Count() && nCnt, "keine gueltige Box-Liste" ); + SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode(); + if( !pTblNd ) + return FALSE; + + // suche alle Boxen / Lines + _FndBox aFndBox( 0, 0 ); + { + _FndPara aPara( rBoxes, &aFndBox ); + GetTabLines().ForEach( &_FndLineCopyCol, &aPara ); + } + if( !aFndBox.GetLines().Count() ) + return FALSE; + + SetHTMLTableLayout( 0 ); // MIB 9.7.97: HTML-Layout loeschen + + _FndBox* pFndBox = &aFndBox; + { + _FndLine* pFndLine; + while( 1 == pFndBox->GetLines().Count() && + 1 == ( pFndLine = pFndBox->GetLines()[ 0 ])->GetBoxes().Count() ) + { + // nicht zu weit runter, eine Line mit Boxen muss nachbleiben!! + _FndBox* pTmpBox = pFndLine->GetBoxes()[ 0 ]; + if( pTmpBox->GetLines().Count() ) + pFndBox = pTmpBox; + else + break; + } + } + + //Lines fuer das Layout-Update herausuchen. + const BOOL bLayout = !IsNewModel() && + 0 != SwClientIter( *GetFrmFmt() ).First( TYPE(SwTabFrm) ); + + if ( bLayout ) + { + aFndBox.SetTableLines( *this ); + if( pFndBox != &aFndBox ) + aFndBox.DelFrms( *this ); + // TL_CHART2: nothing to be done since chart2 currently does not want to + // get notified about new rows/cols. + } + + _CpyTabFrms aTabFrmArr; + _CpyPara aCpyPara( pTblNd, 0, aTabFrmArr ); + + SwTableLine* pLine = pFndBox->GetLines()[ bBehind ? + pFndBox->GetLines().Count()-1 : 0 ]->GetLine(); + if( &aFndBox == pFndBox ) + aCpyPara.nInsPos = GetTabLines().C40_GETPOS( SwTableLine, pLine ); + else + { + aCpyPara.pInsBox = pFndBox->GetBox(); + aCpyPara.nInsPos = pFndBox->GetBox()->GetTabLines().C40_GETPOS( SwTableLine, pLine ); + } + + if( bBehind ) + { + ++aCpyPara.nInsPos; + aCpyPara.nDelBorderFlag = 1; + } + else + aCpyPara.nDelBorderFlag = 2; + + for( USHORT nCpyCnt = 0; nCpyCnt < nCnt; ++nCpyCnt ) + { + if( bBehind ) + aCpyPara.nDelBorderFlag = 1; + pFndBox->GetLines().ForEach( &lcl_CopyRow, &aCpyPara ); + } + + // dann raeume die Struktur dieser Line noch mal auf, generell alle + if( !pDoc->IsInReading() ) + GCLines(); + + //Layout updaten + if ( bLayout ) + { + if( pFndBox != &aFndBox ) + aFndBox.MakeFrms( *this ); + else + aFndBox.MakeNewFrms( *this, nCnt, bBehind ); + } + + CHECKBOXWIDTH + CHECKTABLELAYOUT + + SwChartDataProvider *pPCD = pDoc->GetChartDataProvider(); + if (pPCD && nCnt) + pPCD->AddRowCols( *this, rBoxes, nCnt, bBehind ); + pDoc->UpdateCharts( GetFrmFmt()->GetName() ); + + return TRUE; +} + +BOOL _FndBoxAppendRowLine( const SwTableLine*& rpLine, void* pPara ); + +BOOL _FndBoxAppendRowBox( 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( &_FndBoxAppendRowLine, &aPara ); + if( !pFndBox->GetLines().Count() ) + delete pFndBox; + } + else + pFndPara->pFndLine->GetBoxes().C40_INSERT( _FndBox, pFndBox, + pFndPara->pFndLine->GetBoxes().Count() ); + return TRUE; +} + +BOOL _FndBoxAppendRowLine( 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( &_FndBoxAppendRowBox, &aPara ); + if( pFndLine->GetBoxes().Count() ) + { + pFndPara->pFndBox->GetLines().C40_INSERT( _FndLine, pFndLine, + pFndPara->pFndBox->GetLines().Count() ); + } + else + delete pFndLine; + return TRUE; +} + + +BOOL SwTable::AppendRow( SwDoc* pDoc, USHORT nCnt ) +{ + SwTableNode* pTblNd = (SwTableNode*)aSortCntBoxes[0]->GetSttNd()->FindTableNode(); + if( !pTblNd ) + return FALSE; + + // suche alle Boxen / Lines + _FndBox aFndBox( 0, 0 ); + { + const SwTableLine* pLLine = GetTabLines()[ GetTabLines().Count()-1 ]; + + const SwSelBoxes* pBxs = 0; // Dummy !!! + _FndPara aPara( *pBxs, &aFndBox ); + + _FndBoxAppendRowLine( pLLine, &aPara ); + } + if( !aFndBox.GetLines().Count() ) + return FALSE; + + SetHTMLTableLayout( 0 ); // MIB 9.7.97: HTML-Layout loeschen + + //Lines fuer das Layout-Update herausuchen. + const BOOL bLayout = 0 != SwClientIter( *GetFrmFmt() ).First( TYPE(SwTabFrm) ); + if( bLayout ) + { + aFndBox.SetTableLines( *this ); + // TL_CHART2: nothing to be done since chart2 currently does not want to + // get notified about new rows/cols. + } + + _CpyTabFrms aTabFrmArr; + _CpyPara aCpyPara( pTblNd, 0, aTabFrmArr ); + aCpyPara.nInsPos = GetTabLines().Count(); + aCpyPara.nDelBorderFlag = 1; + + for( USHORT nCpyCnt = 0; nCpyCnt < nCnt; ++nCpyCnt ) + { + aCpyPara.nDelBorderFlag = 1; + aFndBox.GetLines().ForEach( &lcl_CopyRow, &aCpyPara ); + } + + // dann raeume die Struktur dieser Line noch mal auf, generell alle + if( !pDoc->IsInReading() ) + GCLines(); + + //Layout updaten + if ( bLayout ) + { + aFndBox.MakeNewFrms( *this, nCnt, TRUE ); + } + // TL_CHART2: need to inform chart of probably changed cell names + pDoc->UpdateCharts( GetFrmFmt()->GetName() ); + + CHECKBOXWIDTH + CHECKTABLELAYOUT + + return TRUE; +} + + +void lcl_LastBoxSetWidth( SwTableBoxes &rBoxes, const long nOffset, + BOOL bFirst, SwShareBoxFmts& rShareFmts ); + +void lcl_LastBoxSetWidthLine( SwTableLines &rLines, const long nOffset, + BOOL bFirst, SwShareBoxFmts& rShareFmts ) +{ + for ( USHORT i = 0; i < rLines.Count(); ++i ) + ::lcl_LastBoxSetWidth( rLines[i]->GetTabBoxes(), nOffset, bFirst, + rShareFmts ); +} + +void lcl_LastBoxSetWidth( SwTableBoxes &rBoxes, const long nOffset, + BOOL bFirst, SwShareBoxFmts& rShareFmts ) +{ + SwTableBox& rBox = *rBoxes[ bFirst ? 0 : rBoxes.Count() - 1 ]; + if( !rBox.GetSttNd() ) + ::lcl_LastBoxSetWidthLine( rBox.GetTabLines(), nOffset, + bFirst, rShareFmts ); + + //Die Box anpassen + SwFrmFmt *pBoxFmt = rBox.GetFrmFmt(); + SwFmtFrmSize aNew( pBoxFmt->GetFrmSize() ); + aNew.SetWidth( aNew.GetWidth() + nOffset ); + SwFrmFmt *pFmt = rShareFmts.GetFormat( *pBoxFmt, aNew ); + if( pFmt ) + rBox.ChgFrmFmt( (SwTableBoxFmt*)pFmt ); + else + { + pFmt = rBox.ClaimFrmFmt(); + + pFmt->LockModify(); + pFmt->SetFmtAttr( aNew ); + pFmt->UnlockModify(); + + rShareFmts.AddFormat( *pBoxFmt, *pFmt ); + } +} + +void _DeleteBox( SwTable& rTbl, SwTableBox* pBox, SwUndo* pUndo, + BOOL bCalcNewSize, const BOOL bCorrBorder, + SwShareBoxFmts* pShareFmts ) +{ + do { + SwTwips nBoxSz = bCalcNewSize ? + pBox->GetFrmFmt()->GetFrmSize().GetWidth() : 0; + SwTableLine* pLine = pBox->GetUpper(); + SwTableBoxes& rTblBoxes = pLine->GetTabBoxes(); + USHORT nDelPos = rTblBoxes.C40_GETPOS( SwTableBox, pBox ); + SwTableBox* pUpperBox = pBox->GetUpper()->GetUpper(); + + // Sonderbehandlung fuer Umrandung: + if( bCorrBorder && 1 < rTblBoxes.Count() ) + { + BOOL bChgd = FALSE; + const SvxBoxItem& rBoxItem = pBox->GetFrmFmt()->GetBox(); + + if( rBoxItem.GetLeft() || rBoxItem.GetRight() ) + { + //JP 02.04.97: 1.Teil fuer Bug 36271 + // zuerst die linken/rechten Kanten + if( nDelPos + 1 < rTblBoxes.Count() ) + { + SwTableBox* pNxtBox = rTblBoxes[ nDelPos + 1 ]; + const SvxBoxItem& rNxtBoxItem = pNxtBox->GetFrmFmt()->GetBox(); + + SwTableBox* pPrvBox = nDelPos ? rTblBoxes[ nDelPos - 1 ] : 0; + + if( pNxtBox->GetSttNd() && !rNxtBoxItem.GetLeft() && + ( !pPrvBox || !pPrvBox->GetFrmFmt()->GetBox().GetRight()) ) + { + SvxBoxItem aTmp( rNxtBoxItem ); + aTmp.SetLine( rBoxItem.GetLeft() ? rBoxItem.GetLeft() + : rBoxItem.GetRight(), + BOX_LINE_LEFT ); + if( pShareFmts ) + pShareFmts->SetAttr( *pNxtBox, aTmp ); + else + pNxtBox->ClaimFrmFmt()->SetFmtAttr( aTmp ); + bChgd = TRUE; + } + } + if( !bChgd && nDelPos ) + { + SwTableBox* pPrvBox = rTblBoxes[ nDelPos - 1 ]; + const SvxBoxItem& rPrvBoxItem = pPrvBox->GetFrmFmt()->GetBox(); + + SwTableBox* pNxtBox = nDelPos + 1 < rTblBoxes.Count() + ? rTblBoxes[ nDelPos + 1 ] : 0; + + if( pPrvBox->GetSttNd() && !rPrvBoxItem.GetRight() && + ( !pNxtBox || !pNxtBox->GetFrmFmt()->GetBox().GetLeft()) ) + { + SvxBoxItem aTmp( rPrvBoxItem ); + aTmp.SetLine( rBoxItem.GetLeft() ? rBoxItem.GetLeft() + : rBoxItem.GetRight(), + BOX_LINE_RIGHT ); + if( pShareFmts ) + pShareFmts->SetAttr( *pPrvBox, aTmp ); + else + pPrvBox->ClaimFrmFmt()->SetFmtAttr( aTmp ); + } + } + } + + } + + // erst die Box, dann die Nodes loeschen!! + SwStartNode* pSttNd = (SwStartNode*)pBox->GetSttNd(); + if( pShareFmts ) + pShareFmts->RemoveFormat( *rTblBoxes[ nDelPos ]->GetFrmFmt() ); + rTblBoxes.DeleteAndDestroy( nDelPos ); + + if( pSttNd ) + { + // ist das UndoObject zum speichern der Section vorbereitet? + if( pUndo && pUndo->IsDelBox() ) + ((SwUndoTblNdsChg*)pUndo)->SaveSection( pSttNd ); + else + pSttNd->GetDoc()->DeleteSection( pSttNd ); + } + + // auch die Zeile noch loeschen ?? + if( rTblBoxes.Count() ) + { + // dann passe noch die Frame-SSize an + BOOL bLastBox = nDelPos == rTblBoxes.Count(); + if( bLastBox ) + --nDelPos; + pBox = rTblBoxes[nDelPos]; + if( bCalcNewSize ) + { + SwFmtFrmSize aNew( pBox->GetFrmFmt()->GetFrmSize() ); + aNew.SetWidth( aNew.GetWidth() + nBoxSz ); + if( pShareFmts ) + pShareFmts->SetSize( *pBox, aNew ); + else + pBox->ClaimFrmFmt()->SetFmtAttr( aNew ); + + if( !pBox->GetSttNd() ) + { + // dann muss es auch rekursiv in allen Zeilen, in allen + // Zellen erfolgen! + SwShareBoxFmts aShareFmts; + ::lcl_LastBoxSetWidthLine( pBox->GetTabLines(), nBoxSz, + !bLastBox, + pShareFmts ? *pShareFmts + : aShareFmts ); + } + } + break; // nichts mehr loeschen + } + // loesche die Line aus Tabelle/Box + if( !pUpperBox ) + { + // dann loesche auch noch die Line aus der Tabelle + nDelPos = rTbl.GetTabLines().C40_GETPOS( SwTableLine, pLine ); + if( pShareFmts ) + pShareFmts->RemoveFormat( *rTbl.GetTabLines()[ nDelPos ]->GetFrmFmt() ); + rTbl.GetTabLines().DeleteAndDestroy( nDelPos ); + break; // mehr kann nicht geloescht werden + } + + // dann loesche auch noch die Line + pBox = pUpperBox; + nDelPos = pBox->GetTabLines().C40_GETPOS( SwTableLine, pLine ); + if( pShareFmts ) + pShareFmts->RemoveFormat( *pBox->GetTabLines()[ nDelPos ]->GetFrmFmt() ); + pBox->GetTabLines().DeleteAndDestroy( nDelPos ); + } while( !pBox->GetTabLines().Count() ); +} + +SwTableBox* lcl_FndNxtPrvDelBox( const SwTableLines& rTblLns, + SwTwips nBoxStt, SwTwips nBoxWidth, + USHORT nLinePos, BOOL bNxt, + SwSelBoxes* pAllDelBoxes, USHORT* pCurPos ) +{ + SwTableBox* pFndBox = 0; + do { + if( bNxt ) + ++nLinePos; + else + --nLinePos; + SwTableLine* pLine = rTblLns[ nLinePos ]; + SwTwips nFndBoxWidth = 0; + SwTwips nFndWidth = nBoxStt + nBoxWidth; + USHORT nBoxCnt = pLine->GetTabBoxes().Count(); + + pFndBox = pLine->GetTabBoxes()[ 0 ]; + for( USHORT n = 0; 0 < nFndWidth && n < nBoxCnt; ++n ) + { + pFndBox = pLine->GetTabBoxes()[ n ]; + nFndWidth -= (nFndBoxWidth = pFndBox->GetFrmFmt()-> + GetFrmSize().GetWidth()); + } + + // suche die erste ContentBox + while( !pFndBox->GetSttNd() ) + { + const SwTableLines& rLowLns = pFndBox->GetTabLines(); + if( bNxt ) + pFndBox = rLowLns[ 0 ]->GetTabBoxes()[ 0 ]; + else + pFndBox = rLowLns[ rLowLns.Count() - 1 ]->GetTabBoxes()[ 0 ]; + } + + if( Abs( nFndWidth ) > COLFUZZY || + Abs( nBoxWidth - nFndBoxWidth ) > COLFUZZY ) + pFndBox = 0; + else if( pAllDelBoxes ) + { + // falls der Vorganger auch geloscht wird, ist nicht zu tun + USHORT nFndPos; + if( !pAllDelBoxes->Seek_Entry( pFndBox, &nFndPos ) ) + break; + + // sonst noch mal weitersuchen + // Die Box muessen wir aber nicht nochmal abpruefen + pFndBox = 0; + if( nFndPos <= *pCurPos ) + --*pCurPos; + pAllDelBoxes->Remove( nFndPos ); + } + } while( bNxt ? ( nLinePos + 1 < rTblLns.Count() ) : nLinePos ); + return pFndBox; +} + +void lcl_SaveUpperLowerBorder( SwTable& rTbl, const SwTableBox& rBox, + SwShareBoxFmts& rShareFmts, + SwSelBoxes* pAllDelBoxes = 0, + USHORT* pCurPos = 0 ) +{ +//JP 16.04.97: 2.Teil fuer Bug 36271 + BOOL bChgd = FALSE; + const SwTableLine* pLine = rBox.GetUpper(); + const SwTableBoxes& rTblBoxes = pLine->GetTabBoxes(); + const SwTableBox* pUpperBox = &rBox; + USHORT nDelPos = rTblBoxes.C40_GETPOS( SwTableBox, pUpperBox ); + pUpperBox = rBox.GetUpper()->GetUpper(); + const SvxBoxItem& rBoxItem = rBox.GetFrmFmt()->GetBox(); + + // dann die unteren/oberen Kanten + if( rBoxItem.GetTop() || rBoxItem.GetBottom() ) + { + bChgd = FALSE; + const SwTableLines* pTblLns; + if( pUpperBox ) + pTblLns = &pUpperBox->GetTabLines(); + else + pTblLns = &rTbl.GetTabLines(); + + USHORT nLnPos = pTblLns->GetPos( pLine ); + + // bestimme die Attr.Position der akt. zu loeschenden Box + // und suche dann in der unteren / oberen Line die entspr. + // Gegenstuecke + SwTwips nBoxStt = 0; + for( USHORT n = 0; n < nDelPos; ++n ) + nBoxStt += rTblBoxes[ n ]->GetFrmFmt()->GetFrmSize().GetWidth(); + SwTwips nBoxWidth = rBox.GetFrmFmt()->GetFrmSize().GetWidth(); + + SwTableBox *pPrvBox = 0, *pNxtBox = 0; + if( nLnPos ) // Vorgaenger? + pPrvBox = ::lcl_FndNxtPrvDelBox( *pTblLns, nBoxStt, nBoxWidth, + nLnPos, FALSE, pAllDelBoxes, pCurPos ); + + if( nLnPos + 1 < pTblLns->Count() ) // Nachfolger? + pNxtBox = ::lcl_FndNxtPrvDelBox( *pTblLns, nBoxStt, nBoxWidth, + nLnPos, TRUE, pAllDelBoxes, pCurPos ); + + if( pNxtBox && pNxtBox->GetSttNd() ) + { + const SvxBoxItem& rNxtBoxItem = pNxtBox->GetFrmFmt()->GetBox(); + if( !rNxtBoxItem.GetTop() && ( !pPrvBox || + !pPrvBox->GetFrmFmt()->GetBox().GetBottom()) ) + { + SvxBoxItem aTmp( rNxtBoxItem ); + aTmp.SetLine( rBoxItem.GetTop() ? rBoxItem.GetTop() + : rBoxItem.GetBottom(), + BOX_LINE_TOP ); + rShareFmts.SetAttr( *pNxtBox, aTmp ); + bChgd = TRUE; + } + } + if( !bChgd && pPrvBox && pPrvBox->GetSttNd() ) + { + const SvxBoxItem& rPrvBoxItem = pPrvBox->GetFrmFmt()->GetBox(); + if( !rPrvBoxItem.GetTop() && ( !pNxtBox || + !pNxtBox->GetFrmFmt()->GetBox().GetTop()) ) + { + SvxBoxItem aTmp( rPrvBoxItem ); + aTmp.SetLine( rBoxItem.GetTop() ? rBoxItem.GetTop() + : rBoxItem.GetBottom(), + BOX_LINE_BOTTOM ); + rShareFmts.SetAttr( *pPrvBox, aTmp ); + } + } + + } +} + + +BOOL SwTable::DeleteSel( + SwDoc* pDoc + , + const SwSelBoxes& rBoxes, + const SwSelBoxes* pMerged, SwUndo* pUndo, + const BOOL bDelMakeFrms, const BOOL bCorrBorder ) +{ + ASSERT( pDoc, "No doc?" ); + SwTableNode* pTblNd = 0; + if( rBoxes.Count() ) + { + pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode(); + if( !pTblNd ) + return FALSE; + } + + SetHTMLTableLayout( 0 ); // MIB 9.7.97: HTML-Layout loeschen + + //Lines fuer das Layout-Update herausuchen. + _FndBox aFndBox( 0, 0 ); + if ( bDelMakeFrms ) + { + if( pMerged && pMerged->Count() ) + aFndBox.SetTableLines( *pMerged, *this ); + else if( rBoxes.Count() ) + aFndBox.SetTableLines( rBoxes, *this ); + aFndBox.DelFrms( *this ); + } + + SwShareBoxFmts aShareFmts; + + // erst die Umrandung umsetzen, dann loeschen + if( bCorrBorder ) + { + SwSelBoxes aBoxes; + aBoxes.Insert( &rBoxes ); + for( USHORT n = 0; n < aBoxes.Count(); ++n ) + ::lcl_SaveUpperLowerBorder( *this, *rBoxes[ n ], aShareFmts, + &aBoxes, &n ); + } + + PrepareDelBoxes( rBoxes ); + + SwChartDataProvider *pPCD = pDoc->GetChartDataProvider(); + // + // delete boxes from last to first + for( USHORT n = 0; n < rBoxes.Count(); ++n ) + { + USHORT nIdx = rBoxes.Count() - 1 - n; + + // first adapt the data-sequence for chart if necessary + // (needed to move the implementation cursor properly to it's new + // position which can't be done properly if the cell is already gone) + if (pPCD && pTblNd) + pPCD->DeleteBox( &pTblNd->GetTable(), *rBoxes[nIdx] ); + + // ... then delete the boxes + _DeleteBox( *this, rBoxes[nIdx], pUndo, TRUE, bCorrBorder, &aShareFmts ); + } + + // dann raeume die Struktur aller Lines auf + GCLines(); + + if( bDelMakeFrms && aFndBox.AreLinesToRestore( *this ) ) + aFndBox.MakeFrms( *this ); + + // TL_CHART2: now inform chart that sth has changed + pDoc->UpdateCharts( GetFrmFmt()->GetName() ); + + CHECKTABLELAYOUT + CHECK_TABLE( *this ) + + return TRUE; +} + + +// --------------------------------------------------------------- + +BOOL SwTable::OldSplitRow( SwDoc* pDoc, const SwSelBoxes& rBoxes, USHORT nCnt, + BOOL bSameHeight ) +{ + ASSERT( pDoc && rBoxes.Count() && nCnt, "keine gueltigen Werte" ); + SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode(); + if( !pTblNd ) + return FALSE; + + // TL_CHART2: splitting/merging of a number of cells or rows will usually make + // the table to complex to be handled with chart. + // Thus we tell the charts to use their own data provider and forget about this table + pDoc->CreateChartInternalDataProviders( this ); + + SetHTMLTableLayout( 0 ); // MIB 9.7.97: HTML-Layout loeschen + + // If the rows should get the same (min) height, we first have + // to store the old row heights before deleting the frames + long* pRowHeights = 0; + if ( bSameHeight ) + { + pRowHeights = new long[ rBoxes.Count() ]; + for( USHORT n = 0; n < rBoxes.Count(); ++n ) + { + SwTableBox* pSelBox = *( rBoxes.GetData() + n ); + const SwRowFrm* pRow = GetRowFrm( *pSelBox->GetUpper() ); + ASSERT( pRow, "wo ist der Frm von der SwTableLine?" ) + SWRECTFN( pRow ) + pRowHeights[ n ] = (pRow->Frm().*fnRect->fnGetHeight)(); + } + } + + //Lines fuer das Layout-Update herausuchen. + _FndBox aFndBox( 0, 0 ); + aFndBox.SetTableLines( rBoxes, *this ); + aFndBox.DelFrms( *this ); + + for( USHORT n = 0; n < rBoxes.Count(); ++n ) + { + SwTableBox* pSelBox = *( rBoxes.GetData() + n ); + ASSERT( pSelBox, "Box steht nicht in der Tabelle" ); + + // dann fuege in die Box nCnt neue Zeilen ein + SwTableLine* pInsLine = pSelBox->GetUpper(); + SwTableBoxFmt* pFrmFmt = (SwTableBoxFmt*)pSelBox->GetFrmFmt(); + + // Hoehe der Line beachten, gegebenenfalls neu setzen + SwFmtFrmSize aFSz( pInsLine->GetFrmFmt()->GetFrmSize() ); + if ( bSameHeight && ATT_VAR_SIZE == aFSz.GetHeightSizeType() ) + aFSz.SetHeightSizeType( ATT_MIN_SIZE ); + + BOOL bChgLineSz = 0 != aFSz.GetHeight() || bSameHeight; + if ( bChgLineSz ) + aFSz.SetHeight( ( bSameHeight ? pRowHeights[ n ] : aFSz.GetHeight() ) / + (nCnt + 1) ); + + SwTableBox* pNewBox = new SwTableBox( pFrmFmt, nCnt, pInsLine ); + USHORT nBoxPos = pInsLine->GetTabBoxes().C40_GETPOS( SwTableBox, pSelBox ); + pInsLine->GetTabBoxes().Remove( nBoxPos ); // alte loeschen + pInsLine->GetTabBoxes().C40_INSERT( SwTableBox, pNewBox, nBoxPos ); + + // Hintergrund- / Rand Attribut loeschen + SwTableBox* pLastBox = pSelBox; // zum verteilen der TextNodes !! + // sollte Bereiche in der Box stehen, dann bleibt sie so bestehen + // !! FALLS DAS GEAENDERT WIRD MUSS DAS UNDO ANGEPASST WERDEN !!! + BOOL bMoveNodes = TRUE; + { + ULONG nSttNd = pLastBox->GetSttIdx() + 1, + nEndNd = pLastBox->GetSttNd()->EndOfSectionIndex(); + while( nSttNd < nEndNd ) + if( !pDoc->GetNodes()[ nSttNd++ ]->IsTxtNode() ) + { + bMoveNodes = FALSE; + break; + } + } + + SwTableBoxFmt* pCpyBoxFrmFmt = (SwTableBoxFmt*)pSelBox->GetFrmFmt(); + BOOL bChkBorder = 0 != pCpyBoxFrmFmt->GetBox().GetTop(); + if( bChkBorder ) + pCpyBoxFrmFmt = (SwTableBoxFmt*)pSelBox->ClaimFrmFmt(); + + for( USHORT i = 0; i <= nCnt; ++i ) + { + // also erstmal eine neue Linie in der neuen Box + SwTableLine* pNewLine = new SwTableLine( + (SwTableLineFmt*)pInsLine->GetFrmFmt(), 1, pNewBox ); + if( bChgLineSz ) + { + pNewLine->ClaimFrmFmt()->SetFmtAttr( aFSz ); + } + + pNewBox->GetTabLines().C40_INSERT( SwTableLine, pNewLine, i ); + // dann eine neue Box in der Line + if( !i ) // haenge die originale Box ein + { + pSelBox->SetUpper( pNewLine ); + pNewLine->GetTabBoxes().C40_INSERT( SwTableBox, pSelBox, 0 ); + } + else + { + ::_InsTblBox( pDoc, pTblNd, pNewLine, pCpyBoxFrmFmt, + pLastBox, 0 ); + + if( bChkBorder ) + { + pCpyBoxFrmFmt = (SwTableBoxFmt*)pNewLine->GetTabBoxes()[ 0 ]->ClaimFrmFmt(); + SvxBoxItem aTmp( pCpyBoxFrmFmt->GetBox() ); + aTmp.SetLine( 0, BOX_LINE_TOP ); + pCpyBoxFrmFmt->SetFmtAttr( aTmp ); + bChkBorder = FALSE; + } + + if( bMoveNodes ) + { + const SwNode* pEndNd = pLastBox->GetSttNd()->EndOfSectionNode(); + if( pLastBox->GetSttIdx()+2 != pEndNd->GetIndex() ) + { + // TextNodes verschieben + SwNodeRange aRg( *pLastBox->GetSttNd(), +2, *pEndNd ); + pLastBox = pNewLine->GetTabBoxes()[0]; // neu setzen + SwNodeIndex aInsPos( *pLastBox->GetSttNd(), 1 ); + pDoc->GetNodes()._MoveNodes(aRg, pDoc->GetNodes(), aInsPos, FALSE); + pDoc->GetNodes().Delete( aInsPos, 1 ); // den leeren noch loeschen + } + } + } + } + // in Boxen mit Lines darf es nur noch Size/Fillorder geben + pFrmFmt = (SwTableBoxFmt*)pNewBox->ClaimFrmFmt(); + pFrmFmt->ResetFmtAttr( RES_LR_SPACE, RES_FRMATR_END - 1 ); + pFrmFmt->ResetFmtAttr( RES_BOXATR_BEGIN, RES_BOXATR_END - 1 ); + } + + delete[] pRowHeights; + + GCLines(); + + aFndBox.MakeFrms( *this ); + + CHECKBOXWIDTH + CHECKTABLELAYOUT + return TRUE; +} + +BOOL SwTable::SplitCol( SwDoc* pDoc, const SwSelBoxes& rBoxes, USHORT nCnt ) +{ + ASSERT( pDoc && rBoxes.Count() && nCnt, "keine gueltigen Werte" ); + SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode(); + if( !pTblNd ) + return FALSE; + + // TL_CHART2: splitting/merging of a number of cells or rows will usually make + // the table to complex to be handled with chart. + // Thus we tell the charts to use their own data provider and forget about this table + pDoc->CreateChartInternalDataProviders( this ); + + SetHTMLTableLayout( 0 ); // MIB 9.7.97: HTML-Layout loeschen + SwSelBoxes aSelBoxes; + aSelBoxes.Insert(rBoxes.GetData(), rBoxes.Count()); + ExpandSelection( aSelBoxes ); + + //Lines fuer das Layout-Update herausuchen. + _FndBox aFndBox( 0, 0 ); + aFndBox.SetTableLines( aSelBoxes, *this ); + aFndBox.DelFrms( *this ); + + _CpyTabFrms aFrmArr; + SvPtrarr aLastBoxArr; + USHORT nFndPos; + for( USHORT n = 0; n < aSelBoxes.Count(); ++n ) + { + SwTableBox* pSelBox = *( aSelBoxes.GetData() + n ); + ASSERT( pSelBox, "Box steht nicht in der Tabelle" ); + + // We don't want to split small table cells into very very small cells + if( pSelBox->GetFrmFmt()->GetFrmSize().GetWidth()/( nCnt + 1 ) < 10 ) + continue; + + // dann teile die Box nCnt in nCnt Boxen + SwTableLine* pInsLine = pSelBox->GetUpper(); + USHORT nBoxPos = pInsLine->GetTabBoxes().C40_GETPOS( SwTableBox, pSelBox ); + + // suche das FrmFmt im Array aller Frame-Formate + SwTableBoxFmt* pLastBoxFmt; + _CpyTabFrm aFindFrm( (SwTableBoxFmt*)pSelBox->GetFrmFmt() ); + if( !aFrmArr.Seek_Entry( aFindFrm, &nFndPos )) + { + // aender das FrmFmt + aFindFrm.pNewFrmFmt = (SwTableBoxFmt*)pSelBox->ClaimFrmFmt(); + SwTwips nBoxSz = aFindFrm.pNewFrmFmt->GetFrmSize().GetWidth(); + SwTwips nNewBoxSz = nBoxSz / ( nCnt + 1 ); + aFindFrm.pNewFrmFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, + nNewBoxSz, 0 ) ); + aFrmArr.Insert( aFindFrm ); + + pLastBoxFmt = aFindFrm.pNewFrmFmt; + if( nBoxSz != ( nNewBoxSz * (nCnt + 1))) + { + // es bleibt ein Rest, also muss fuer die letzte Box ein + // eigenes Format definiert werden + pLastBoxFmt = new SwTableBoxFmt( *aFindFrm.pNewFrmFmt ); + pLastBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, + nBoxSz - ( nNewBoxSz * nCnt ), 0 ) ); + } + void* p = pLastBoxFmt; + aLastBoxArr.Insert( p, nFndPos ); + } + else + { + aFindFrm = aFrmArr[ nFndPos ]; + pSelBox->ChgFrmFmt( (SwTableBoxFmt*)aFindFrm.pNewFrmFmt ); + pLastBoxFmt = (SwTableBoxFmt*)aLastBoxArr[ nFndPos ]; + } + + // dann fuege mal an der Position die neuen Boxen ein + for( USHORT i = 1; i < nCnt; ++i ) + ::_InsTblBox( pDoc, pTblNd, pInsLine, aFindFrm.pNewFrmFmt, + pSelBox, nBoxPos + i ); // dahinter einfuegen + + ::_InsTblBox( pDoc, pTblNd, pInsLine, pLastBoxFmt, + pSelBox, nBoxPos + nCnt ); // dahinter einfuegen + + // Sonderbehandlung fuer die Umrandung: + const SvxBoxItem& aSelBoxItem = aFindFrm.pNewFrmFmt->GetBox(); + if( aSelBoxItem.GetRight() ) + { + pInsLine->GetTabBoxes()[ nBoxPos + nCnt ]->ClaimFrmFmt(); + + SvxBoxItem aTmp( aSelBoxItem ); + aTmp.SetLine( 0, BOX_LINE_RIGHT ); + aFindFrm.pNewFrmFmt->SetFmtAttr( aTmp ); + + // und dann das Format aus dem "cache" entfernen + for( USHORT i = aFrmArr.Count(); i; ) + { + const _CpyTabFrm& rCTF = aFrmArr[ --i ]; + if( rCTF.pNewFrmFmt == aFindFrm.pNewFrmFmt || + rCTF.Value.pFrmFmt == aFindFrm.pNewFrmFmt ) + { + aFrmArr.Remove( i ); + aLastBoxArr.Remove( i ); + } + } + } + } + + //Layout updaten + aFndBox.MakeFrms( *this ); + + CHECKBOXWIDTH + CHECKTABLELAYOUT + return TRUE; +} + +// --------------------------------------------------------------- + +/* + ----------------------- >> MERGE << ------------------------ + Algorithmus: + ist in der _FndBox nur eine Line angegeben, nehme die Line + und teste die Anzahl der Boxen + - ist mehr als 1 Box angegeben, so wird auf Boxenebene zusammen- + gefasst, d.H. die neue Box wird so Breit wie die alten. + - Alle Lines die ueber/unter dem Bereich liegen werden in die + Box als Line + Box mit Lines eingefuegt + - Alle Lines die vor/hinter dem Bereich liegen werden in + die Boxen Left/Right eingetragen + + ----------------------- >> MERGE << ------------------------ +*/ + +void lcl_CpyLines( USHORT nStt, USHORT nEnd, + SwTableLines& rLines, + SwTableBox* pInsBox, + USHORT nPos = USHRT_MAX ) +{ + for( USHORT n = nStt; n < nEnd; ++n ) + rLines[n]->SetUpper( pInsBox ); + if( USHRT_MAX == nPos ) + nPos = pInsBox->GetTabLines().Count(); + pInsBox->GetTabLines().Insert( &rLines, nPos, nStt, nEnd ); + rLines.Remove( nStt, nEnd - nStt ); +} + +void lcl_CpyBoxes( USHORT nStt, USHORT nEnd, + SwTableBoxes& rBoxes, + SwTableLine* pInsLine, + USHORT nPos = USHRT_MAX ) +{ + for( USHORT n = nStt; n < nEnd; ++n ) + rBoxes[n]->SetUpper( pInsLine ); + if( USHRT_MAX == nPos ) + nPos = pInsLine->GetTabBoxes().Count(); + pInsLine->GetTabBoxes().Insert( &rBoxes, nPos, nStt, nEnd ); + rBoxes.Remove( nStt, nEnd - nStt ); +} + +void lcl_CalcWidth( SwTableBox* pBox ) +{ + // Annahme: jede Line in der Box ist gleich gross + SwFrmFmt* pFmt = pBox->ClaimFrmFmt(); + ASSERT( pBox->GetTabLines().Count(), "Box hat keine Lines" ); + + SwTableLine* pLine = pBox->GetTabLines()[0]; + ASSERT( pLine, "Box steht in keiner Line" ); + + long nWidth = 0; + for( USHORT n = 0; n < pLine->GetTabBoxes().Count(); ++n ) + nWidth += pLine->GetTabBoxes()[n]->GetFrmFmt()->GetFrmSize().GetWidth(); + + pFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nWidth, 0 )); + + // in Boxen mit Lines darf es nur noch Size/Fillorder geben + pFmt->ResetFmtAttr( RES_LR_SPACE, RES_FRMATR_END - 1 ); + pFmt->ResetFmtAttr( RES_BOXATR_BEGIN, RES_BOXATR_END - 1 ); +} + + + +struct _InsULPara +{ + SwTableNode* pTblNd; + SwTableLine* pInsLine; + SwTableBox* pInsBox; + BOOL bUL_LR : 1; // Upper-Lower(TRUE) oder Left-Right(FALSE) ? + BOOL bUL : 1; // Upper-Left(TRUE) oder Lower-Right(FALSE) ? + + SwTableBox* pLeftBox; + SwTableBox* pRightBox; + SwTableBox* pMergeBox; + + _InsULPara( SwTableNode* pTNd, BOOL bUpperLower, BOOL bUpper, + SwTableBox* pLeft, SwTableBox* pMerge, SwTableBox* pRight, + SwTableLine* pLine=0, SwTableBox* pBox=0 ) + : pTblNd( pTNd ), pInsLine( pLine ), pInsBox( pBox ), + pLeftBox( pLeft ), pRightBox( pRight ), pMergeBox( pMerge ) + { bUL_LR = bUpperLower; bUL = bUpper; } + + void SetLeft( SwTableBox* pBox=0 ) + { bUL_LR = FALSE; bUL = TRUE; if( pBox ) pInsBox = pBox; } + void SetRight( SwTableBox* pBox=0 ) + { bUL_LR = FALSE; bUL = FALSE; if( pBox ) pInsBox = pBox; } + void SetUpper( SwTableLine* pLine=0 ) + { bUL_LR = TRUE; bUL = TRUE; if( pLine ) pInsLine = pLine; } + void SetLower( SwTableLine* pLine=0 ) + { bUL_LR = TRUE; bUL = FALSE; if( pLine ) pInsLine = pLine; } +}; + + +BOOL lcl_Merge_MoveBox( const _FndBox*& rpFndBox, void* pPara ) +{ + _InsULPara* pULPara = (_InsULPara*)pPara; + SwTableBoxes* pBoxes; + + USHORT nStt = 0, nEnd = rpFndBox->GetLines().Count(); + USHORT nInsPos = USHRT_MAX; + if( !pULPara->bUL_LR ) // Left/Right + { + USHORT nPos; + SwTableBox* pFndBox = (SwTableBox*)rpFndBox->GetBox(); + pBoxes = &pFndBox->GetUpper()->GetTabBoxes(); + if( pULPara->bUL ) // Left ? + { + // gibt es noch davor Boxen, dann move sie + if( 0 != ( nPos = pBoxes->C40_GETPOS( SwTableBox, pFndBox )) ) + lcl_CpyBoxes( 0, nPos, *pBoxes, pULPara->pInsLine ); + } + else // Right + // gibt es noch dahinter Boxen, dann move sie + if( (nPos = pBoxes->C40_GETPOS( SwTableBox, pFndBox )) +1 < pBoxes->Count() ) + { + nInsPos = pULPara->pInsLine->GetTabBoxes().Count(); + lcl_CpyBoxes( nPos+1, pBoxes->Count(), + *pBoxes, pULPara->pInsLine ); + } + } + // Upper/Lower und gehts noch tiefer ?? + else if( rpFndBox->GetLines().Count() ) + { + // suche nur die Line, ab der Verschoben werden muss + nStt = pULPara->bUL ? 0 : rpFndBox->GetLines().Count()-1; + nEnd = nStt+1; + } + + pBoxes = &pULPara->pInsLine->GetTabBoxes(); + + // geht es noch eine weitere Stufe runter? + if( rpFndBox->GetBox()->GetTabLines().Count() ) + { + SwTableBox* pBox = new SwTableBox( + (SwTableBoxFmt*)rpFndBox->GetBox()->GetFrmFmt(), 0, pULPara->pInsLine ); + _InsULPara aPara( *pULPara ); + aPara.pInsBox = pBox; + ((_FndBox*)rpFndBox)->GetLines().ForEach( nStt, nEnd, + &lcl_Merge_MoveLine, &aPara ); + if( pBox->GetTabLines().Count() ) + { + if( USHRT_MAX == nInsPos ) + nInsPos = pBoxes->Count(); + pBoxes->C40_INSERT( SwTableBox, pBox, nInsPos ); + lcl_CalcWidth( pBox ); // bereche die Breite der Box + } + else + delete pBox; + } + return TRUE; +} + +BOOL lcl_Merge_MoveLine( const _FndLine*& rpFndLine, void* pPara ) +{ + _InsULPara* pULPara = (_InsULPara*)pPara; + SwTableLines* pLines; + + USHORT nStt = 0, nEnd = rpFndLine->GetBoxes().Count(); + USHORT nInsPos = USHRT_MAX; + if( pULPara->bUL_LR ) // UpperLower ? + { + USHORT nPos; + SwTableLine* pFndLn = (SwTableLine*)rpFndLine->GetLine(); + pLines = pFndLn->GetUpper() ? + &pFndLn->GetUpper()->GetTabLines() : + &pULPara->pTblNd->GetTable().GetTabLines(); + + SwTableBox* pLBx = rpFndLine->GetBoxes()[0]->GetBox(); + SwTableBox* pRBx = rpFndLine->GetBoxes()[ + rpFndLine->GetBoxes().Count()-1]->GetBox(); + USHORT nLeft = pFndLn->GetTabBoxes().C40_GETPOS( SwTableBox, pLBx ); + USHORT nRight = pFndLn->GetTabBoxes().C40_GETPOS( SwTableBox, pRBx ); + +// if( ( nLeft && nRight+1 < pFndLn->GetTabBoxes().Count() ) || +// ( !nLeft && nRight+1 >= pFndLn->GetTabBoxes().Count() ) ) + if( !nLeft || nRight == pFndLn->GetTabBoxes().Count() ) + { + if( pULPara->bUL ) // Upper ? + { + // gibt es noch davor Zeilen, dann move sie + if( 0 != ( nPos = pLines->C40_GETPOS( SwTableLine, pFndLn )) ) + lcl_CpyLines( 0, nPos, *pLines, pULPara->pInsBox ); + } + else + // gibt es noch dahinter Zeilen, dann move sie + if( (nPos = pLines->C40_GETPOS( SwTableLine, pFndLn )) +1 < pLines->Count() ) + { + nInsPos = pULPara->pInsBox->GetTabLines().Count(); + lcl_CpyLines( nPos+1, pLines->Count(), *pLines, + pULPara->pInsBox ); + } + } + else if( nLeft ) + { + // es gibt links noch weitere Boxen, also setze Left- + // und Merge-Box in eine Box und Line, fuege davor/dahinter + // eine Line mit Box ein, in die die oberen/unteren Lines + // eingefuegt werden + SwTableLine* pInsLine = pULPara->pLeftBox->GetUpper(); + SwTableBox* pLMBox = new SwTableBox( + (SwTableBoxFmt*)pULPara->pLeftBox->GetFrmFmt(), 0, pInsLine ); + SwTableLine* pLMLn = new SwTableLine( + (SwTableLineFmt*)pInsLine->GetFrmFmt(), 2, pLMBox ); + pLMLn->ClaimFrmFmt()->ResetFmtAttr( RES_FRM_SIZE ); + + pLMBox->GetTabLines().C40_INSERT( SwTableLine, pLMLn, 0 ); + + lcl_CpyBoxes( 0, 2, pInsLine->GetTabBoxes(), pLMLn ); + + pInsLine->GetTabBoxes().C40_INSERT( SwTableBox, pLMBox, 0 ); + + if( pULPara->bUL ) // Upper ? + { + // gibt es noch davor Zeilen, dann move sie + if( 0 != ( nPos = pLines->C40_GETPOS( SwTableLine, pFndLn )) ) + lcl_CpyLines( 0, nPos, *pLines, pLMBox, 0 ); + } + else + // gibt es noch dahinter Zeilen, dann move sie + if( (nPos = pLines->C40_GETPOS( SwTableLine, pFndLn )) +1 < pLines->Count() ) + lcl_CpyLines( nPos+1, pLines->Count(), *pLines, + pLMBox ); + lcl_CalcWidth( pLMBox ); // bereche die Breite der Box + } + else if( nRight+1 < pFndLn->GetTabBoxes().Count() ) + { + // es gibt rechts noch weitere Boxen, also setze Right- + // und Merge-Box in eine Box und Line, fuege davor/dahinter + // eine Line mit Box ein, in die die oberen/unteren Lines + // eingefuegt werden + SwTableLine* pInsLine = pULPara->pRightBox->GetUpper(); + SwTableBox* pRMBox; + if( pULPara->pLeftBox->GetUpper() == pInsLine ) + { + pRMBox = new SwTableBox( + (SwTableBoxFmt*)pULPara->pRightBox->GetFrmFmt(), 0, pInsLine ); + SwTableLine* pRMLn = new SwTableLine( + (SwTableLineFmt*)pInsLine->GetFrmFmt(), 2, pRMBox ); + pRMLn->ClaimFrmFmt()->ResetFmtAttr( RES_FRM_SIZE ); + pRMBox->GetTabLines().C40_INSERT( SwTableLine, pRMLn, 0 ); + + lcl_CpyBoxes( 1, 3, pInsLine->GetTabBoxes(), pRMLn ); + + pInsLine->GetTabBoxes().C40_INSERT( SwTableBox, pRMBox, 0 ); + } + else + { + // Left und Merge wurden schon zusammengefuegt, also move + // Right auch mit in die Line + + pInsLine = pULPara->pLeftBox->GetUpper(); + USHORT nMvPos = pULPara->pRightBox->GetUpper()->GetTabBoxes(). + C40_GETPOS( SwTableBox, pULPara->pRightBox ); + lcl_CpyBoxes( nMvPos, nMvPos+1, + pULPara->pRightBox->GetUpper()->GetTabBoxes(), + pInsLine ); + pRMBox = pInsLine->GetUpper(); + + // sind schon Lines vorhanden, dann muessen diese in eine + // neue Line und Box + nMvPos = pRMBox->GetTabLines().C40_GETPOS( SwTableLine, pInsLine ); + if( pULPara->bUL ? nMvPos + : nMvPos+1 < pRMBox->GetTabLines().Count() ) + { + // alle Lines zu einer neuen Line und Box zusammenfassen + SwTableLine* pNewLn = new SwTableLine( + (SwTableLineFmt*)pInsLine->GetFrmFmt(), 1, pRMBox ); + pNewLn->ClaimFrmFmt()->ResetFmtAttr( RES_FRM_SIZE ); + pRMBox->GetTabLines().C40_INSERT( SwTableLine, pNewLn, + pULPara->bUL ? nMvPos : nMvPos+1 ); + pRMBox = new SwTableBox( (SwTableBoxFmt*)pRMBox->GetFrmFmt(), 0, pNewLn ); + pNewLn->GetTabBoxes().C40_INSERT( SwTableBox, pRMBox, 0 ); + + USHORT nPos1, nPos2; + if( pULPara->bUL ) + nPos1 = 0, + nPos2 = nMvPos; + else + nPos1 = nMvPos+2, + nPos2 = pNewLn->GetUpper()->GetTabLines().Count(); + + lcl_CpyLines( nPos1, nPos2, + pNewLn->GetUpper()->GetTabLines(), pRMBox ); + lcl_CalcWidth( pRMBox ); // bereche die Breite der Box + + pRMBox = new SwTableBox( (SwTableBoxFmt*)pRMBox->GetFrmFmt(), 0, pNewLn ); + pNewLn->GetTabBoxes().C40_INSERT( SwTableBox, pRMBox, + pNewLn->GetTabBoxes().Count() ); + } + } + if( pULPara->bUL ) // Upper ? + { + // gibt es noch davor Zeilen, dann move sie + if( 0 != ( nPos = pLines->C40_GETPOS( SwTableLine, pFndLn )) ) + lcl_CpyLines( 0, nPos, *pLines, pRMBox, 0 ); + } + else + // gibt es noch dahinter Zeilen, dann move sie + if( (nPos = pLines->C40_GETPOS( SwTableLine, pFndLn )) +1 < pLines->Count() ) + lcl_CpyLines( nPos+1, pLines->Count(), *pLines, + pRMBox ); + lcl_CalcWidth( pRMBox ); // bereche die Breite der Box + } + else { + ASSERT( FALSE , "Was denn nun" ); + } + } + // Left/Right + else + { + // suche nur die Line, ab der Verschoben werden muss + nStt = pULPara->bUL ? 0 : rpFndLine->GetBoxes().Count()-1; + nEnd = nStt+1; + } + pLines = &pULPara->pInsBox->GetTabLines(); + + SwTableLine* pNewLine = new SwTableLine( + (SwTableLineFmt*)rpFndLine->GetLine()->GetFrmFmt(), 0, pULPara->pInsBox ); + _InsULPara aPara( *pULPara ); // kopieren + aPara.pInsLine = pNewLine; + ((_FndLine*)rpFndLine)->GetBoxes().ForEach( nStt, nEnd, + &lcl_Merge_MoveBox, &aPara ); + if( pNewLine->GetTabBoxes().Count() ) + { + if( USHRT_MAX == nInsPos ) + nInsPos = pLines->Count(); + pLines->C40_INSERT( SwTableLine, pNewLine, nInsPos ); + } + else + delete pNewLine; + + return TRUE; +} + + +BOOL SwTable::OldMerge( SwDoc* pDoc, const SwSelBoxes& rBoxes, + SwTableBox* pMergeBox, SwUndoTblMerge* pUndo ) +{ + ASSERT( rBoxes.Count() && pMergeBox, "keine gueltigen Werte" ); + SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode(); + if( !pTblNd ) + return FALSE; + + // suche alle Boxen / Lines + _FndBox aFndBox( 0, 0 ); + { + _FndPara aPara( rBoxes, &aFndBox ); + GetTabLines().ForEach( &_FndLineCopyCol, &aPara ); + } + if( !aFndBox.GetLines().Count() ) + return FALSE; + + // TL_CHART2: splitting/merging of a number of cells or rows will usually make + // the table to complex to be handled with chart. + // Thus we tell the charts to use their own data provider and forget about this table + pDoc->CreateChartInternalDataProviders( this ); + + SetHTMLTableLayout( 0 ); // MIB 9.7.97: HTML-Layout loeschen + + if( pUndo ) + pUndo->SetSelBoxes( rBoxes ); + + //Lines fuer das Layout-Update herausuchen. + aFndBox.SetTableLines( *this ); + aFndBox.DelFrms( *this ); + + _FndBox* pFndBox = &aFndBox; + while( 1 == pFndBox->GetLines().Count() && + 1 == pFndBox->GetLines()[0]->GetBoxes().Count() ) + pFndBox = pFndBox->GetLines()[0]->GetBoxes()[0]; + + SwTableLine* pInsLine = new SwTableLine( + (SwTableLineFmt*)pFndBox->GetLines()[0]->GetLine()->GetFrmFmt(), 0, + !pFndBox->GetUpper() ? 0 : pFndBox->GetBox() ); + pInsLine->ClaimFrmFmt()->ResetFmtAttr( RES_FRM_SIZE ); + + // trage die neue Line ein + SwTableLines* pLines = pFndBox->GetUpper() ? + &pFndBox->GetBox()->GetTabLines() : &GetTabLines(); + + SwTableLine* pNewLine = pFndBox->GetLines()[0]->GetLine(); + USHORT nInsPos = pLines->C40_GETPOS( SwTableLine, pNewLine ); + pLines->C40_INSERT( SwTableLine, pInsLine, nInsPos ); + + SwTableBox* pLeftBox = new SwTableBox( (SwTableBoxFmt*)pMergeBox->GetFrmFmt(), 0, pInsLine ); + SwTableBox* pRightBox = new SwTableBox( (SwTableBoxFmt*)pMergeBox->GetFrmFmt(), 0, pInsLine ); + pMergeBox->SetUpper( pInsLine ); + pInsLine->GetTabBoxes().C40_INSERT( SwTableBox, pLeftBox, 0 ); + pLeftBox->ClaimFrmFmt(); + pInsLine->GetTabBoxes().C40_INSERT( SwTableBox, pMergeBox, 1 ); + pInsLine->GetTabBoxes().C40_INSERT( SwTableBox, pRightBox, 2 ); + pRightBox->ClaimFrmFmt(); + + // in diese kommen alle Lines, die ueber dem selektierten Bereich stehen + // Sie bilden also eine Upper/Lower Line + _InsULPara aPara( pTblNd, TRUE, TRUE, pLeftBox, pMergeBox, pRightBox, pInsLine ); + + // move die oben/unten ueberhaengenden Lines vom selektierten Bereich + pFndBox->GetLines()[0]->GetBoxes().ForEach( &lcl_Merge_MoveBox, + &aPara ); + aPara.SetLower( pInsLine ); + USHORT nEnd = pFndBox->GetLines().Count()-1; + pFndBox->GetLines()[nEnd]->GetBoxes().ForEach( &lcl_Merge_MoveBox, + &aPara ); + + // move die links/rechts hereinreichenden Boxen vom selektierten Bereich + aPara.SetLeft( pLeftBox ); + pFndBox->GetLines().ForEach( &lcl_Merge_MoveLine, &aPara ); + + aPara.SetRight( pRightBox ); + pFndBox->GetLines().ForEach( &lcl_Merge_MoveLine, &aPara ); + + if( !pLeftBox->GetTabLines().Count() ) + _DeleteBox( *this, pLeftBox, 0, FALSE, FALSE ); + else + { + lcl_CalcWidth( pLeftBox ); // bereche die Breite der Box + if( pUndo && pLeftBox->GetSttNd() ) + pUndo->AddNewBox( pLeftBox->GetSttIdx() ); + } + if( !pRightBox->GetTabLines().Count() ) + _DeleteBox( *this, pRightBox, 0, FALSE, FALSE ); + else + { + lcl_CalcWidth( pRightBox ); // bereche die Breite der Box + if( pUndo && pRightBox->GetSttNd() ) + pUndo->AddNewBox( pRightBox->GetSttIdx() ); + } + + DeleteSel( pDoc, rBoxes, 0, 0, FALSE, FALSE ); + + // dann raeume die Struktur dieser Line noch mal auf: + // generell alle Aufraeumen + GCLines(); + + GetTabLines()[0]->GetTabBoxes().ForEach( &lcl_BoxSetHeadCondColl, 0 ); + + aFndBox.MakeFrms( *this ); + + CHECKBOXWIDTH + CHECKTABLELAYOUT + + return TRUE; +} + +// --------------------------------------------------------------- + +void lcl_CheckRowSpan( SwTable &rTbl ) +{ + USHORT nLineCount = rTbl.GetTabLines().Count(); + USHORT nMaxSpan = nLineCount; + long nMinSpan = 1; + while( nMaxSpan ) + { + SwTableLine* pLine = rTbl.GetTabLines()[ nLineCount - nMaxSpan ]; + for( USHORT nBox = 0; nBox < pLine->GetTabBoxes().Count(); ++nBox ) + { + SwTableBox* pBox = pLine->GetTabBoxes()[nBox]; + long nRowSpan = pBox->getRowSpan(); + if( nRowSpan > nMaxSpan ) + pBox->setRowSpan( nMaxSpan ); + else if( nRowSpan < nMinSpan ) + pBox->setRowSpan( nMinSpan > 0 ? nMaxSpan : nMinSpan ); + } + --nMaxSpan; + nMinSpan = -nMaxSpan; + } +} + +USHORT lcl_GetBoxOffset( const _FndBox& rBox ) +{ + // suche die erste Box + const _FndBox* pFirstBox = &rBox; + while( pFirstBox->GetLines().Count() ) + pFirstBox = pFirstBox->GetLines()[ 0 ]->GetBoxes()[ 0 ]; + + USHORT nRet = 0; + // dann ueber die Lines nach oben die Position bestimmen + const SwTableBox* pBox = pFirstBox->GetBox(); + do { + const SwTableBoxes& rBoxes = pBox->GetUpper()->GetTabBoxes(); + const SwTableBox* pCmp; + for( USHORT n = 0; pBox != ( pCmp = rBoxes[ n ] ); ++n ) + nRet = nRet + (USHORT) pCmp->GetFrmFmt()->GetFrmSize().GetWidth(); + pBox = pBox->GetUpper()->GetUpper(); + } while( pBox ); + return nRet; +} + +USHORT lcl_GetLineWidth( const _FndLine& rLine ) +{ + USHORT nRet = 0; + for( USHORT n = rLine.GetBoxes().Count(); n; ) + nRet = nRet + (USHORT)rLine.GetBoxes()[ --n ]->GetBox()->GetFrmFmt() + ->GetFrmSize().GetWidth(); + return nRet; +} + +void lcl_CalcNewWidths( const _FndLines& rFndLines, _CpyPara& rPara ) +{ + rPara.pWidths.reset(); + USHORT nLineCount = rFndLines.Count(); + if( nLineCount ) + { + rPara.pWidths = boost::shared_ptr< std::vector< std::vector< ULONG > > > + ( new std::vector< std::vector< ULONG > >( nLineCount )); + // First we collect information about the left/right borders of all + // selected cells + for( USHORT nLine = 0; nLine < nLineCount; ++nLine ) + { + std::vector< ULONG > &rWidth = (*rPara.pWidths.get())[ nLine ]; + const _FndLine *pFndLine = rFndLines[ nLine ]; + if( pFndLine && pFndLine->GetBoxes().Count() ) + { + const SwTableLine *pLine = pFndLine->GetLine(); + if( pLine && pLine->GetTabBoxes().Count() ) + { + USHORT nBoxCount = pLine->GetTabBoxes().Count(); + ULONG nPos = 0; + // The first selected box... + const SwTableBox *pSel = pFndLine->GetBoxes()[0]->GetBox(); + USHORT nBox = 0; + // Sum up the width of all boxes before the first selected box + while( nBox < nBoxCount ) + { + SwTableBox* pBox = pLine->GetTabBoxes()[nBox++]; + if( pBox != pSel ) + nPos += pBox->GetFrmFmt()->GetFrmSize().GetWidth(); + else + break; + } + // nPos is now the left border of the first selceted box + if( rPara.nMinLeft > nPos ) + rPara.nMinLeft = nPos; + nBoxCount = pFndLine->GetBoxes().Count(); + rWidth = std::vector< ULONG >( nBoxCount+2 ); + rWidth[ 0 ] = nPos; + // Add now the widths of all selected boxes and store + // the positions in the vector + for( nBox = 0; nBox < nBoxCount; ) + { + nPos += pFndLine->GetBoxes()[nBox] + ->GetBox()->GetFrmFmt()->GetFrmSize().GetWidth(); + rWidth[ ++nBox ] = nPos; + } + // nPos: The right border of the last selected box + if( rPara.nMaxRight < nPos ) + rPara.nMaxRight = nPos; + if( nPos <= rWidth[ 0 ] ) + rWidth.clear(); + } + } + } + } + // Second step: calculate the new widths for the copied cells + ULONG nSelSize = rPara.nMaxRight - rPara.nMinLeft; + if( nSelSize ) + { + for( USHORT nLine = 0; nLine < nLineCount; ++nLine ) + { + std::vector< ULONG > &rWidth = (*rPara.pWidths.get())[ nLine ]; + USHORT nCount = (USHORT)rWidth.size(); + if( nCount > 2 ) + { + rWidth[ nCount - 1 ] = rPara.nMaxRight; + ULONG nLastPos = 0; + for( USHORT nBox = 0; nBox < nCount; ++nBox ) + { + sal_uInt64 nNextPos = rWidth[ nBox ]; + nNextPos -= rPara.nMinLeft; + nNextPos *= rPara.nNewSize; + nNextPos /= nSelSize; + rWidth[ nBox ] = (ULONG)(nNextPos - nLastPos); + nLastPos = (ULONG)nNextPos; + } + } + } + } +} + +BOOL lcl_CopyBoxToDoc( const _FndBox*& rpFndBox, void* pPara ) +{ + _CpyPara* pCpyPara = (_CpyPara*)pPara; + + // Calculation of new size + ULONG nRealSize; + ULONG nDummy1 = 0; + ULONG nDummy2 = 0; + if( pCpyPara->pTblNd->GetTable().IsNewModel() ) + { + if( pCpyPara->nBoxIdx == 1 ) + nDummy1 = (*pCpyPara->pWidths.get())[pCpyPara->nLnIdx][0]; + nRealSize = (*pCpyPara->pWidths.get())[pCpyPara->nLnIdx][pCpyPara->nBoxIdx++]; + if( pCpyPara->nBoxIdx == (*pCpyPara->pWidths.get())[pCpyPara->nLnIdx].size()-1 ) + nDummy2 = (*pCpyPara->pWidths.get())[pCpyPara->nLnIdx][pCpyPara->nBoxIdx]; + } + else + { + nRealSize = pCpyPara->nNewSize; + nRealSize *= rpFndBox->GetBox()->GetFrmFmt()->GetFrmSize().GetWidth(); + nRealSize /= pCpyPara->nOldSize; + } + + ULONG nSize; + bool bDummy = nDummy1 > 0; + if( bDummy ) + nSize = nDummy1; + else + { + nSize = nRealSize; + nRealSize = 0; + } + do + { + // suche das Frame-Format in der Liste aller Frame-Formate + _CpyTabFrm aFindFrm( (SwTableBoxFmt*)rpFndBox->GetBox()->GetFrmFmt() ); + + SwFmtFrmSize aFrmSz; + USHORT nFndPos; + if( !pCpyPara->rTabFrmArr.Seek_Entry( aFindFrm, &nFndPos ) || + ( aFrmSz = ( aFindFrm = pCpyPara->rTabFrmArr[ nFndPos ]).pNewFrmFmt-> + GetFrmSize()).GetWidth() != (SwTwips)nSize ) + { + // es ist noch nicht vorhanden, also kopiere es + aFindFrm.pNewFrmFmt = pCpyPara->pDoc->MakeTableBoxFmt(); + aFindFrm.pNewFrmFmt->CopyAttrs( *rpFndBox->GetBox()->GetFrmFmt() ); + if( !pCpyPara->bCpyCntnt ) + aFindFrm.pNewFrmFmt->ResetFmtAttr( RES_BOXATR_FORMULA, RES_BOXATR_VALUE ); + aFrmSz.SetWidth( nSize ); + aFindFrm.pNewFrmFmt->SetFmtAttr( aFrmSz ); + pCpyPara->rTabFrmArr.Insert( aFindFrm ); + } + + SwTableBox* pBox; + if( rpFndBox->GetLines().Count() ) + { + pBox = new SwTableBox( aFindFrm.pNewFrmFmt, + rpFndBox->GetLines().Count(), pCpyPara->pInsLine ); + pCpyPara->pInsLine->GetTabBoxes().C40_INSERT( SwTableBox, pBox, pCpyPara->nInsPos++ ); + _CpyPara aPara( *pCpyPara, pBox ); + aPara.nNewSize = nSize; // hole die Groesse + ((_FndBox*)rpFndBox)->GetLines().ForEach( &lcl_CopyLineToDoc, &aPara ); + } + else + { + // erzeuge eine leere Box + pCpyPara->pDoc->GetNodes().InsBoxen( pCpyPara->pTblNd, pCpyPara->pInsLine, + aFindFrm.pNewFrmFmt, + (SwTxtFmtColl*)pCpyPara->pDoc->GetDfltTxtFmtColl(), + 0, pCpyPara->nInsPos ); + pBox = pCpyPara->pInsLine->GetTabBoxes()[ pCpyPara->nInsPos ]; + if( bDummy ) + pBox->setDummyFlag( true ); + else if( pCpyPara->bCpyCntnt ) + { + // dann kopiere mal den Inhalt in diese leere Box + pBox->setRowSpan( rpFndBox->GetBox()->getRowSpan() ); + + // der Inhalt kopiert wird, dann koennen auch Formeln&Values + // kopiert werden. + { + SfxItemSet aBoxAttrSet( pCpyPara->pDoc->GetAttrPool(), + RES_BOXATR_FORMAT, RES_BOXATR_VALUE ); + aBoxAttrSet.Put( rpFndBox->GetBox()->GetFrmFmt()->GetAttrSet() ); + if( aBoxAttrSet.Count() ) + { + const SfxPoolItem* pItem; + SvNumberFormatter* pN = pCpyPara->pDoc->GetNumberFormatter( FALSE ); + if( pN && pN->HasMergeFmtTbl() && SFX_ITEM_SET == aBoxAttrSet. + GetItemState( RES_BOXATR_FORMAT, FALSE, &pItem ) ) + { + ULONG nOldIdx = ((SwTblBoxNumFormat*)pItem)->GetValue(); + ULONG nNewIdx = pN->GetMergeFmtIndex( nOldIdx ); + if( nNewIdx != nOldIdx ) + aBoxAttrSet.Put( SwTblBoxNumFormat( nNewIdx )); + } + pBox->ClaimFrmFmt()->SetFmtAttr( aBoxAttrSet ); + } + } + SwDoc* pFromDoc = rpFndBox->GetBox()->GetFrmFmt()->GetDoc(); + SwNodeRange aCpyRg( *rpFndBox->GetBox()->GetSttNd(), 1, + *rpFndBox->GetBox()->GetSttNd()->EndOfSectionNode() ); + SwNodeIndex aInsIdx( *pBox->GetSttNd(), 1 ); + + pFromDoc->CopyWithFlyInFly( aCpyRg, 0, aInsIdx, FALSE ); + // den initialen TextNode loeschen + pCpyPara->pDoc->GetNodes().Delete( aInsIdx, 1 ); + } + ++pCpyPara->nInsPos; + } + if( nRealSize ) + { + bDummy = false; + nSize = nRealSize; + nRealSize = 0; + } + else + { + bDummy = true; + nSize = nDummy2; + nDummy2 = 0; + } + } + while( nSize ); + return TRUE; +} + +BOOL lcl_CopyLineToDoc( const _FndLine*& rpFndLine, void* pPara ) +{ + _CpyPara* pCpyPara = (_CpyPara*)pPara; + + // suche das Format in der Liste aller Formate + _CpyTabFrm aFindFrm( (SwTableBoxFmt*)rpFndLine->GetLine()->GetFrmFmt() ); + USHORT nFndPos; + if( !pCpyPara->rTabFrmArr.Seek_Entry( aFindFrm, &nFndPos )) + { + // es ist noch nicht vorhanden, also kopiere es + aFindFrm.pNewFrmFmt = (SwTableBoxFmt*)pCpyPara->pDoc->MakeTableLineFmt(); + aFindFrm.pNewFrmFmt->CopyAttrs( *rpFndLine->GetLine()->GetFrmFmt() ); + pCpyPara->rTabFrmArr.Insert( aFindFrm ); + } + else + aFindFrm = pCpyPara->rTabFrmArr[ nFndPos ]; + + SwTableLine* pNewLine = new SwTableLine( (SwTableLineFmt*)aFindFrm.pNewFrmFmt, + rpFndLine->GetBoxes().Count(), pCpyPara->pInsBox ); + if( pCpyPara->pInsBox ) + { + pCpyPara->pInsBox->GetTabLines().C40_INSERT( SwTableLine, pNewLine, pCpyPara->nInsPos++ ); + } + else + { + pCpyPara->pTblNd->GetTable().GetTabLines().C40_INSERT( SwTableLine, pNewLine, + pCpyPara->nInsPos++ ); + } + + _CpyPara aPara( *pCpyPara, pNewLine ); + + if( pCpyPara->pTblNd->GetTable().IsNewModel() ) + { + aPara.nOldSize = 0; // will not be used + aPara.nBoxIdx = 1; + } + else if( rpFndLine->GetBoxes().Count() == + rpFndLine->GetLine()->GetTabBoxes().Count() ) + { + // hole die Size vom Parent + const SwFrmFmt* pFmt; + + if( rpFndLine->GetLine()->GetUpper() ) + pFmt = rpFndLine->GetLine()->GetUpper()->GetFrmFmt(); + else + pFmt = pCpyPara->pTblNd->GetTable().GetFrmFmt(); + aPara.nOldSize = pFmt->GetFrmSize().GetWidth(); + } + else + // errechne sie + for( USHORT n = 0; n < rpFndLine->GetBoxes().Count(); ++n ) + aPara.nOldSize += rpFndLine->GetBoxes()[n] + ->GetBox()->GetFrmFmt()->GetFrmSize().GetWidth(); + + ((_FndLine*)rpFndLine)->GetBoxes().ForEach( &lcl_CopyBoxToDoc, &aPara ); + if( pCpyPara->pTblNd->GetTable().IsNewModel() ) + ++pCpyPara->nLnIdx; + return TRUE; +} + +BOOL SwTable::CopyHeadlineIntoTable( SwTableNode& rTblNd ) +{ + // suche alle Boxen / Lines + SwSelBoxes aSelBoxes; + SwTableBox* pBox = GetTabSortBoxes()[ 0 ]; + pBox = GetTblBox( pBox->GetSttNd()->StartOfSectionNode()->GetIndex() + 1 ); + SelLineFromBox( pBox, aSelBoxes, TRUE ); + + _FndBox aFndBox( 0, 0 ); + { + _FndPara aPara( aSelBoxes, &aFndBox ); + ((SwTableLines&)GetTabLines()).ForEach( &_FndLineCopyCol, &aPara ); + } + if( !aFndBox.GetLines().Count() ) + return FALSE; + + { + // Tabellen-Formeln in die relative Darstellung umwandeln + SwTableFmlUpdate aMsgHnt( this ); + aMsgHnt.eFlags = TBL_RELBOXNAME; + GetFrmFmt()->GetDoc()->UpdateTblFlds( &aMsgHnt ); + } + + _CpyTabFrms aCpyFmt; + _CpyPara aPara( &rTblNd, 1, aCpyFmt, TRUE ); + aPara.nNewSize = aPara.nOldSize = rTblNd.GetTable().GetFrmFmt()->GetFrmSize().GetWidth(); + // dann kopiere mal + if( IsNewModel() ) + lcl_CalcNewWidths( aFndBox.GetLines(), aPara ); + aFndBox.GetLines().ForEach( &lcl_CopyLineToDoc, &aPara ); + if( rTblNd.GetTable().IsNewModel() ) + { // The copied line must not contain any row span attributes > 1 + SwTableLine* pLine = rTblNd.GetTable().GetTabLines()[0]; + USHORT nColCount = pLine->GetTabBoxes().Count(); + ASSERT( nColCount, "Empty Table Line" ) + for( USHORT nCurrCol = 0; nCurrCol < nColCount; ++nCurrCol ) + { + SwTableBox* pTableBox = pLine->GetTabBoxes()[nCurrCol]; + ASSERT( pTableBox, "Missing Table Box" ); + pTableBox->setRowSpan( 1 ); + } + } + + return TRUE; +} + +BOOL SwTable::MakeCopy( SwDoc* pInsDoc, const SwPosition& rPos, + const SwSelBoxes& rSelBoxes, BOOL bCpyNds, + BOOL bCpyName ) const +{ + // suche alle Boxen / Lines + _FndBox aFndBox( 0, 0 ); + { + _FndPara aPara( rSelBoxes, &aFndBox ); + ((SwTableLines&)GetTabLines()).ForEach( &_FndLineCopyCol, &aPara ); + } + if( !aFndBox.GetLines().Count() ) + return FALSE; + + // erst die Poolvorlagen fuer die Tabelle kopieren, damit die dann + // wirklich kopiert und damit die gueltigen Werte haben. + SwDoc* pSrcDoc = GetFrmFmt()->GetDoc(); + if( pSrcDoc != pInsDoc ) + { + pInsDoc->CopyTxtColl( *pSrcDoc->GetTxtCollFromPool( RES_POOLCOLL_TABLE ) ); + pInsDoc->CopyTxtColl( *pSrcDoc->GetTxtCollFromPool( RES_POOLCOLL_TABLE_HDLN ) ); + } + + SwTable* pNewTbl = (SwTable*)pInsDoc->InsertTable( + SwInsertTableOptions( tabopts::HEADLINE_NO_BORDER, 1 ), + rPos, 1, 1, GetFrmFmt()->GetHoriOrient().GetHoriOrient(), + 0, 0, FALSE, IsNewModel() ); + if( !pNewTbl ) + return FALSE; + + SwNodeIndex aIdx( rPos.nNode, -1 ); + SwTableNode* pTblNd = aIdx.GetNode().FindTableNode(); + aIdx++; + ASSERT( pTblNd, "wo ist denn nun der TableNode?" ); + + pTblNd->GetTable().SetRowsToRepeat( GetRowsToRepeat() ); + + if( IS_TYPE( SwDDETable, this )) + { + // es wird eine DDE-Tabelle kopiert + // ist im neuen Dokument ueberhaupt der FeldTyp vorhanden ? + SwFieldType* pFldType = pInsDoc->InsertFldType( + *((SwDDETable*)this)->GetDDEFldType() ); + ASSERT( pFldType, "unbekannter FieldType" ); + + // tauschen am Node den Tabellen-Pointer aus + pNewTbl = new SwDDETable( *pNewTbl, + (SwDDEFieldType*)pFldType ); + pTblNd->SetNewTable( pNewTbl, FALSE ); + } + + pNewTbl->GetFrmFmt()->CopyAttrs( *GetFrmFmt() ); + pNewTbl->SetTblChgMode( GetTblChgMode() ); + + //Vernichten der Frms die bereits angelegt wurden. + pTblNd->DelFrms(); + + { + // Tabellen-Formeln in die relative Darstellung umwandeln + SwTableFmlUpdate aMsgHnt( this ); + aMsgHnt.eFlags = TBL_RELBOXNAME; + pSrcDoc->UpdateTblFlds( &aMsgHnt ); + } + + SwTblNumFmtMerge aTNFM( *pSrcDoc, *pInsDoc ); + + // Namen auch kopieren oder neuen eindeutigen erzeugen + if( bCpyName ) + pNewTbl->GetFrmFmt()->SetName( GetFrmFmt()->GetName() ); + + _CpyTabFrms aCpyFmt; + _CpyPara aPara( pTblNd, 1, aCpyFmt, bCpyNds ); + aPara.nNewSize = aPara.nOldSize = GetFrmFmt()->GetFrmSize().GetWidth(); + + if( IsNewModel() ) + lcl_CalcNewWidths( aFndBox.GetLines(), aPara ); + // dann kopiere mal + aFndBox.GetLines().ForEach( &lcl_CopyLineToDoc, &aPara ); + + // dann setze oben und unten noch die "richtigen" Raender: + { + _FndLine* pFndLn = aFndBox.GetLines()[ 0 ]; + SwTableLine* pLn = pFndLn->GetLine(); + const SwTableLine* pTmp = pLn; + USHORT nLnPos = GetTabLines().GetPos( pTmp ); + if( USHRT_MAX != nLnPos && nLnPos ) + { + // es gibt eine Line davor + SwCollectTblLineBoxes aLnPara( FALSE, HEADLINE_BORDERCOPY ); + + pLn = GetTabLines()[ nLnPos - 1 ]; + pLn->GetTabBoxes().ForEach( &lcl_Box_CollectBox, &aLnPara ); + + if( aLnPara.Resize( lcl_GetBoxOffset( aFndBox ), + lcl_GetLineWidth( *pFndLn )) ) + { + aLnPara.SetValues( TRUE ); + pLn = pNewTbl->GetTabLines()[ 0 ]; + pLn->GetTabBoxes().ForEach( &lcl_BoxSetSplitBoxFmts, &aLnPara ); + } + } + + pFndLn = aFndBox.GetLines()[ aFndBox.GetLines().Count() -1 ]; + pLn = pFndLn->GetLine(); + pTmp = pLn; + nLnPos = GetTabLines().GetPos( pTmp ); + if( nLnPos < GetTabLines().Count() - 1 ) + { + // es gibt eine Line dahinter + SwCollectTblLineBoxes aLnPara( TRUE, HEADLINE_BORDERCOPY ); + + pLn = GetTabLines()[ nLnPos + 1 ]; + pLn->GetTabBoxes().ForEach( &lcl_Box_CollectBox, &aLnPara ); + + if( aLnPara.Resize( lcl_GetBoxOffset( aFndBox ), + lcl_GetLineWidth( *pFndLn )) ) + { + aLnPara.SetValues( FALSE ); + pLn = pNewTbl->GetTabLines()[ pNewTbl->GetTabLines().Count()-1 ]; + pLn->GetTabBoxes().ForEach( &lcl_BoxSetSplitBoxFmts, &aLnPara ); + } + } + } + + // die initiale Box muss noch geloescht werden + _DeleteBox( *pNewTbl, pNewTbl->GetTabLines()[ + pNewTbl->GetTabLines().Count() - 1 ]->GetTabBoxes()[0], + 0, FALSE, FALSE ); + + if( pNewTbl->IsNewModel() ) + lcl_CheckRowSpan( *pNewTbl ); + // Mal kurz aufraeumen: + pNewTbl->GCLines(); + + pTblNd->MakeFrms( &aIdx ); // erzeuge die Frames neu + + CHECKTABLELAYOUT + + return TRUE; +} + + + +// --------------------------------------------------------------- + +// suche ab dieser Line nach der naechsten Box mit Inhalt +SwTableBox* SwTableLine::FindNextBox( const SwTable& rTbl, + const SwTableBox* pSrchBox, BOOL bOvrTblLns ) const +{ + const SwTableLine* pLine = this; // fuer M800 + SwTableBox* pBox; + USHORT nFndPos; + if( GetTabBoxes().Count() && pSrchBox && + USHRT_MAX != ( nFndPos = GetTabBoxes().GetPos( pSrchBox )) && + nFndPos + 1 != GetTabBoxes().Count() ) + { + pBox = GetTabBoxes()[ nFndPos + 1 ]; + while( pBox->GetTabLines().Count() ) + pBox = pBox->GetTabLines()[0]->GetTabBoxes()[0]; + return pBox; + } + + if( GetUpper() ) + { + nFndPos = GetUpper()->GetTabLines().GetPos( pLine ); + ASSERT( USHRT_MAX != nFndPos, "Line nicht in der Tabelle" ); + // gibts eine weitere Line + if( nFndPos+1 >= GetUpper()->GetTabLines().Count() ) + return GetUpper()->GetUpper()->FindNextBox( rTbl, GetUpper(), bOvrTblLns ); + pLine = GetUpper()->GetTabLines()[nFndPos+1]; + } + else if( bOvrTblLns ) // ueber die "GrundLines" einer Tabelle ? + { + // suche in der Tabelle nach der naechsten Line + nFndPos = rTbl.GetTabLines().GetPos( pLine ); + if( nFndPos + 1 >= rTbl.GetTabLines().Count() ) + return 0; // es gibt keine weitere Box mehr + + pLine = rTbl.GetTabLines()[ nFndPos+1 ]; + } + else + return 0; + + if( pLine->GetTabBoxes().Count() ) + { + pBox = pLine->GetTabBoxes()[0]; + while( pBox->GetTabLines().Count() ) + pBox = pBox->GetTabLines()[0]->GetTabBoxes()[0]; + return pBox; + } + return pLine->FindNextBox( rTbl, 0, bOvrTblLns ); +} + +// suche ab dieser Line nach der vorherigen Box +SwTableBox* SwTableLine::FindPreviousBox( const SwTable& rTbl, + const SwTableBox* pSrchBox, BOOL bOvrTblLns ) const +{ + const SwTableLine* pLine = this; // fuer M800 + SwTableBox* pBox; + USHORT nFndPos; + if( GetTabBoxes().Count() && pSrchBox && + USHRT_MAX != ( nFndPos = GetTabBoxes().GetPos( pSrchBox )) && + nFndPos ) + { + pBox = GetTabBoxes()[ nFndPos - 1 ]; + while( pBox->GetTabLines().Count() ) + { + pLine = pBox->GetTabLines()[pBox->GetTabLines().Count()-1]; + pBox = pLine->GetTabBoxes()[pLine->GetTabBoxes().Count()-1]; + } + return pBox; + } + + if( GetUpper() ) + { + nFndPos = GetUpper()->GetTabLines().GetPos( pLine ); + ASSERT( USHRT_MAX != nFndPos, "Line nicht in der Tabelle" ); + // gibts eine weitere Line + if( !nFndPos ) + return GetUpper()->GetUpper()->FindPreviousBox( rTbl, GetUpper(), bOvrTblLns ); + pLine = GetUpper()->GetTabLines()[nFndPos-1]; + } + else if( bOvrTblLns ) // ueber die "GrundLines" einer Tabelle ? + { + // suche in der Tabelle nach der naechsten Line + nFndPos = rTbl.GetTabLines().GetPos( pLine ); + if( !nFndPos ) + return 0; // es gibt keine weitere Box mehr + + pLine = rTbl.GetTabLines()[ nFndPos-1 ]; + } + else + return 0; + + if( pLine->GetTabBoxes().Count() ) + { + pBox = pLine->GetTabBoxes()[pLine->GetTabBoxes().Count()-1]; + while( pBox->GetTabLines().Count() ) + { + pLine = pBox->GetTabLines()[pBox->GetTabLines().Count()-1]; + pBox = pLine->GetTabBoxes()[pLine->GetTabBoxes().Count()-1]; + } + return pBox; + } + return pLine->FindPreviousBox( rTbl, 0, bOvrTblLns ); +} + +// suche ab dieser Line nach der naechsten Box mit Inhalt +SwTableBox* SwTableBox::FindNextBox( const SwTable& rTbl, + const SwTableBox* pSrchBox, BOOL bOvrTblLns ) const +{ + if( !pSrchBox && !GetTabLines().Count() ) + return (SwTableBox*)this; + return GetUpper()->FindNextBox( rTbl, pSrchBox ? pSrchBox : this, + bOvrTblLns ); + +} + +// suche ab dieser Line nach der naechsten Box mit Inhalt +SwTableBox* SwTableBox::FindPreviousBox( const SwTable& rTbl, + const SwTableBox* pSrchBox, BOOL bOvrTblLns ) const +{ + if( !pSrchBox && !GetTabLines().Count() ) + return (SwTableBox*)this; + return GetUpper()->FindPreviousBox( rTbl, pSrchBox ? pSrchBox : this, + bOvrTblLns ); +} + + +BOOL lcl_BoxSetHeadCondColl( const SwTableBox*& rpBox, void* ) +{ + // in der HeadLine sind die Absaetze mit BedingtenVorlage anzupassen + const SwStartNode* pSttNd = rpBox->GetSttNd(); + if( pSttNd ) + pSttNd->CheckSectionCondColl(); + else + ((SwTableBox*)rpBox)->GetTabLines().ForEach( &lcl_LineSetHeadCondColl, 0 ); + return TRUE; +} + +BOOL lcl_LineSetHeadCondColl( const SwTableLine*& rpLine, void* ) +{ + ((SwTableLine*)rpLine)->GetTabBoxes().ForEach( &lcl_BoxSetHeadCondColl, 0 ); + return TRUE; +} + +/* */ + +SwTwips lcl_GetDistance( SwTableBox* pBox, BOOL bLeft ) +{ + BOOL bFirst = TRUE; + SwTwips nRet = 0; + SwTableLine* pLine; + while( pBox && 0 != ( pLine = pBox->GetUpper() ) ) + { + USHORT nStt = 0, nPos = pLine->GetTabBoxes().C40_GETPOS( SwTableBox, pBox ); + + if( bFirst && !bLeft ) + ++nPos; + bFirst = FALSE; + + while( nStt < nPos ) + nRet += pLine->GetTabBoxes()[ nStt++ ]->GetFrmFmt() + ->GetFrmSize().GetWidth(); + pBox = pLine->GetUpper(); + } + return nRet; +} + +BOOL lcl_SetSelBoxWidth( SwTableLine* pLine, CR_SetBoxWidth& rParam, + SwTwips nDist, BOOL bCheck ) +{ + SwTableBoxes& rBoxes = pLine->GetTabBoxes(); + for( USHORT n = 0; n < rBoxes.Count(); ++n ) + { + SwTableBox* pBox = rBoxes[ n ]; + SwFrmFmt* pFmt = pBox->GetFrmFmt(); + const SwFmtFrmSize& rSz = pFmt->GetFrmSize(); + SwTwips nWidth = rSz.GetWidth(); + BOOL bGreaterBox = FALSE; + + if( bCheck ) + { + for( USHORT i = 0; i < pBox->GetTabLines().Count(); ++i ) + if( !::lcl_SetSelBoxWidth( pBox->GetTabLines()[ i ], rParam, + nDist, TRUE )) + return FALSE; + + // dann noch mal alle "ContentBoxen" sammeln + if( ( 0 != ( bGreaterBox = TBLFIX_CHGABS != rParam.nMode && ( nDist + ( rParam.bLeft ? 0 : nWidth ) ) >= rParam.nSide)) || + ( !rParam.bBigger && ( Abs( nDist + (( rParam.nMode && rParam.bLeft ) ? 0 : nWidth ) - rParam.nSide ) < COLFUZZY ) ) ) + { + rParam.bAnyBoxFnd = TRUE; + SwTwips nLowerDiff; + if( bGreaterBox && TBLFIX_CHGPROP == rParam.nMode ) + { + // die "anderen Boxen" wurden angepasst, + // also sich um diesen Betrag aendern + nLowerDiff = (nDist + ( rParam.bLeft ? 0 : nWidth ) ) - rParam.nSide; + nLowerDiff *= rParam.nDiff; + nLowerDiff /= rParam.nMaxSize; + nLowerDiff = rParam.nDiff - nLowerDiff; + } + else + nLowerDiff = rParam.nDiff; + + if( nWidth < nLowerDiff || nWidth - nLowerDiff < MINLAY ) + return FALSE; + } + } + else + { + SwTwips nLowerDiff = 0, nOldLower = rParam.nLowerDiff; + for( USHORT i = 0; i < pBox->GetTabLines().Count(); ++i ) + { + rParam.nLowerDiff = 0; + lcl_SetSelBoxWidth( pBox->GetTabLines()[ i ], rParam, nDist, FALSE ); + + if( nLowerDiff < rParam.nLowerDiff ) + nLowerDiff = rParam.nLowerDiff; + } + rParam.nLowerDiff = nOldLower; + + + if( nLowerDiff || + ( 0 != ( bGreaterBox = !nOldLower && TBLFIX_CHGABS != rParam.nMode && + ( nDist + ( rParam.bLeft ? 0 : nWidth ) ) >= rParam.nSide)) || + ( Abs( nDist + ( (rParam.nMode && rParam.bLeft) ? 0 : nWidth ) + - rParam.nSide ) < COLFUZZY )) + { + // in dieser Spalte ist der Cursor - also verkleinern / vergroessern + SwFmtFrmSize aNew( rSz ); + + if( !nLowerDiff ) + { + if( bGreaterBox && TBLFIX_CHGPROP == rParam.nMode ) + { + // die "anderen Boxen" wurden angepasst, + // also sich um diesen Betrag aendern + nLowerDiff = (nDist + ( rParam.bLeft ? 0 : nWidth ) ) - rParam.nSide; + nLowerDiff *= rParam.nDiff; + nLowerDiff /= rParam.nMaxSize; + nLowerDiff = rParam.nDiff - nLowerDiff; + } + else + nLowerDiff = rParam.nDiff; + } + + rParam.nLowerDiff += nLowerDiff; + + if( rParam.bBigger ) + aNew.SetWidth( nWidth + nLowerDiff ); + else + aNew.SetWidth( nWidth - nLowerDiff ); + rParam.aShareFmts.SetSize( *pBox, aNew ); + break; + } + } + + if( rParam.bLeft && rParam.nMode && nDist >= rParam.nSide ) + break; + + nDist += nWidth; + + // wenns groesser wird, dann wars das + if( ( TBLFIX_CHGABS == rParam.nMode || !rParam.bLeft ) && + nDist >= rParam.nSide ) + break; + } + return TRUE; +} + +BOOL lcl_SetOtherBoxWidth( SwTableLine* pLine, CR_SetBoxWidth& rParam, + SwTwips nDist, BOOL bCheck ) +{ + SwTableBoxes& rBoxes = pLine->GetTabBoxes(); + for( USHORT n = 0; n < rBoxes.Count(); ++n ) + { + SwTableBox* pBox = rBoxes[ n ]; + SwFrmFmt* pFmt = pBox->GetFrmFmt(); + const SwFmtFrmSize& rSz = pFmt->GetFrmSize(); + SwTwips nWidth = rSz.GetWidth(); + + if( bCheck ) + { + for( USHORT i = 0; i < pBox->GetTabLines().Count(); ++i ) + if( !::lcl_SetOtherBoxWidth( pBox->GetTabLines()[ i ], + rParam, nDist, TRUE )) + return FALSE; + + if( rParam.bBigger && ( TBLFIX_CHGABS == rParam.nMode + ? Abs( nDist - rParam.nSide ) < COLFUZZY + : ( rParam.bLeft ? nDist < rParam.nSide - COLFUZZY + : nDist >= rParam.nSide - COLFUZZY )) ) + { + rParam.bAnyBoxFnd = TRUE; + SwTwips nDiff; + if( TBLFIX_CHGPROP == rParam.nMode ) // Tabelle fix, proport. + { + // relativ berechnen + nDiff = nWidth; + nDiff *= rParam.nDiff; + nDiff /= rParam.nMaxSize; + } + else + nDiff = rParam.nDiff; + + if( nWidth < nDiff || nWidth - nDiff < MINLAY ) + return FALSE; + } + } + else + { + SwTwips nLowerDiff = 0, nOldLower = rParam.nLowerDiff; + for( USHORT i = 0; i < pBox->GetTabLines().Count(); ++i ) + { + rParam.nLowerDiff = 0; + lcl_SetOtherBoxWidth( pBox->GetTabLines()[ i ], rParam, + nDist, FALSE ); + + if( nLowerDiff < rParam.nLowerDiff ) + nLowerDiff = rParam.nLowerDiff; + } + rParam.nLowerDiff = nOldLower; + + if( nLowerDiff || + ( TBLFIX_CHGABS == rParam.nMode + ? Abs( nDist - rParam.nSide ) < COLFUZZY + : ( rParam.bLeft ? nDist < rParam.nSide - COLFUZZY + : nDist >= rParam.nSide - COLFUZZY) + ) ) + { + SwFmtFrmSize aNew( rSz ); + + if( !nLowerDiff ) + { + if( TBLFIX_CHGPROP == rParam.nMode ) // Tabelle fix, proport. + { + // relativ berechnen + nLowerDiff = nWidth; + nLowerDiff *= rParam.nDiff; + nLowerDiff /= rParam.nMaxSize; + } + else + nLowerDiff = rParam.nDiff; + } + + rParam.nLowerDiff += nLowerDiff; + + if( rParam.bBigger ) + aNew.SetWidth( nWidth - nLowerDiff ); + else + aNew.SetWidth( nWidth + nLowerDiff ); + + rParam.aShareFmts.SetSize( *pBox, aNew ); + } + } + + nDist += nWidth; + if( ( TBLFIX_CHGABS == rParam.nMode || rParam.bLeft ) && + nDist > rParam.nSide ) + break; + } + return TRUE; +} + +/**/ + +BOOL lcl_InsSelBox( SwTableLine* pLine, CR_SetBoxWidth& rParam, + SwTwips nDist, BOOL bCheck ) +{ + SwTableBoxes& rBoxes = pLine->GetTabBoxes(); + USHORT n, nCmp; + for( n = 0; n < rBoxes.Count(); ++n ) + { + SwTableBox* pBox = rBoxes[ n ]; + SwTableBoxFmt* pFmt = (SwTableBoxFmt*)pBox->GetFrmFmt(); + const SwFmtFrmSize& rSz = pFmt->GetFrmSize(); + SwTwips nWidth = rSz.GetWidth(); + + if( bCheck ) + { + for( USHORT i = 0; i < pBox->GetTabLines().Count(); ++i ) + if( !::lcl_InsSelBox( pBox->GetTabLines()[ i ], rParam, + nDist, TRUE )) + return FALSE; + + // dann noch mal alle "ContentBoxen" sammeln + if( Abs( nDist + ( rParam.bLeft ? 0 : nWidth ) + - rParam.nSide ) < COLFUZZY ) + nCmp = 1; + else if( nDist + ( rParam.bLeft ? 0 : nWidth/2 ) > rParam.nSide ) + nCmp = 2; + else + nCmp = 0; + + if( nCmp ) + { + rParam.bAnyBoxFnd = TRUE; + if( pFmt->GetProtect().IsCntntProtected() ) + return FALSE; + + if( rParam.bSplittBox && + nWidth - rParam.nDiff <= COLFUZZY + + ( 567 / 2 /* min. 0,5 cm Platz lassen*/) ) + return FALSE; + + if( pBox->GetSttNd() ) + rParam.aBoxes.Insert( pBox ); + + break; + } + } + else + { + SwTwips nLowerDiff = 0, nOldLower = rParam.nLowerDiff; + for( USHORT i = 0; i < pBox->GetTabLines().Count(); ++i ) + { + rParam.nLowerDiff = 0; + lcl_InsSelBox( pBox->GetTabLines()[ i ], rParam, nDist, FALSE ); + + if( nLowerDiff < rParam.nLowerDiff ) + nLowerDiff = rParam.nLowerDiff; + } + rParam.nLowerDiff = nOldLower; + + if( nLowerDiff ) + nCmp = 1; + else if( Abs( nDist + ( rParam.bLeft ? 0 : nWidth ) + - rParam.nSide ) < COLFUZZY ) + nCmp = 2; + else if( nDist + nWidth / 2 > rParam.nSide ) + nCmp = 3; + else + nCmp = 0; + + if( nCmp ) + { + // in dieser Spalte ist der Cursor - also verkleinern / vergroessern + if( 1 == nCmp ) + { + if( !rParam.bSplittBox ) + { + // die akt. Box auf + SwFmtFrmSize aNew( rSz ); + aNew.SetWidth( nWidth + rParam.nDiff ); + rParam.aShareFmts.SetSize( *pBox, aNew ); + } + } + else + { + ASSERT( pBox->GetSttNd(), "Das muss eine EndBox sein!"); + + if( !rParam.bLeft && 3 != nCmp ) + ++n; + + ::_InsTblBox( pFmt->GetDoc(), rParam.pTblNd, + pLine, pFmt, pBox, n ); + + SwTableBox* pNewBox = rBoxes[ n ]; + SwFmtFrmSize aNew( rSz ); + aNew.SetWidth( rParam.nDiff ); + rParam.aShareFmts.SetSize( *pNewBox, aNew ); + + // Sonderfall: kein Platz in den anderen Boxen + // aber in der Zelle + if( rParam.bSplittBox ) + { + // die akt. Box auf + SwFmtFrmSize aNewSize( rSz ); + aNewSize.SetWidth( nWidth - rParam.nDiff ); + rParam.aShareFmts.SetSize( *pBox, aNewSize ); + } + + // Sonderbehandlung fuer Umrandung die Rechte muss + // entfernt werden + { + const SvxBoxItem& rBoxItem = pBox->GetFrmFmt()->GetBox(); + if( rBoxItem.GetRight() ) + { + SvxBoxItem aTmp( rBoxItem ); + aTmp.SetLine( 0, BOX_LINE_RIGHT ); + rParam.aShareFmts.SetAttr( rParam.bLeft + ? *pNewBox + : *pBox, aTmp ); + } + } + } + + rParam.nLowerDiff = rParam.nDiff; + break; + } + } + + if( rParam.bLeft && rParam.nMode && nDist >= rParam.nSide ) + break; + + nDist += nWidth; + } + return TRUE; +} + +BOOL lcl_InsOtherBox( SwTableLine* pLine, CR_SetBoxWidth& rParam, + SwTwips nDist, BOOL bCheck ) +{ + // Sonderfall: kein Platz in den anderen Boxen aber in der Zelle + if( rParam.bSplittBox ) + return TRUE; + + SwTableBoxes& rBoxes = pLine->GetTabBoxes(); + USHORT n; + + // Tabelle fix, proport. + if( !rParam.nRemainWidth && TBLFIX_CHGPROP == rParam.nMode ) + { + // dann die richtige Breite suchen, auf die sich die relative + // Breitenanpassung bezieht. + SwTwips nTmpDist = nDist; + for( n = 0; n < rBoxes.Count(); ++n ) + { + SwTwips nWidth = rBoxes[ n ]->GetFrmFmt()->GetFrmSize().GetWidth(); + if( (nTmpDist + nWidth / 2 ) > rParam.nSide ) + { + rParam.nRemainWidth = rParam.bLeft + ? USHORT(nTmpDist) + : USHORT(rParam.nTblWidth - nTmpDist); + break; + } + nTmpDist += nWidth; + } + } + + for( n = 0; n < rBoxes.Count(); ++n ) + { + SwTableBox* pBox = rBoxes[ n ]; + SwFrmFmt* pFmt = pBox->GetFrmFmt(); + const SwFmtFrmSize& rSz = pFmt->GetFrmSize(); + SwTwips nWidth = rSz.GetWidth(); + + if( bCheck ) + { + for( USHORT i = 0; i < pBox->GetTabLines().Count(); ++i ) + if( !::lcl_InsOtherBox( pBox->GetTabLines()[ i ], + rParam, nDist, TRUE )) + return FALSE; + + if( + rParam.bLeft ? ((nDist + nWidth / 2 ) <= rParam.nSide && + (TBLFIX_CHGABS != rParam.nMode || + n < rBoxes.Count() && + (nDist + nWidth + rBoxes[ n+1 ]-> + GetFrmFmt()->GetFrmSize().GetWidth() / 2) + > rParam.nSide )) + : (nDist + nWidth / 2 ) > rParam.nSide + ) + { + rParam.bAnyBoxFnd = TRUE; + SwTwips nDiff; + if( TBLFIX_CHGPROP == rParam.nMode ) // Tabelle fix, proport. + { + // relativ berechnen + nDiff = nWidth; + nDiff *= rParam.nDiff; + nDiff /= rParam.nRemainWidth; + + if( nWidth < nDiff || nWidth - nDiff < MINLAY ) + return FALSE; + } + else + { + nDiff = rParam.nDiff; + + // teste ob die linke oder rechte Box gross genug + // ist, um den Platz abzugeben! + // es wird davor oder dahinter eine Box eingefuegt! + SwTwips nTmpWidth = nWidth; + if( rParam.bLeft && pBox->GetUpper()->GetUpper() ) + { + const SwTableBox* pTmpBox = pBox; + USHORT nBoxPos = n; + while( !nBoxPos && pTmpBox->GetUpper()->GetUpper() ) + { + pTmpBox = pTmpBox->GetUpper()->GetUpper(); + nBoxPos = pTmpBox->GetUpper()->GetTabBoxes().GetPos( pTmpBox ); + } +// if( nBoxPos ) + nTmpWidth = pTmpBox->GetFrmFmt()->GetFrmSize().GetWidth(); +// else +// nTmpWidth = 0; + } + + if( nTmpWidth < nDiff || nTmpWidth - nDiff < MINLAY ) + return FALSE; + break; + } + } + } + else + { + SwTwips nLowerDiff = 0, nOldLower = rParam.nLowerDiff; + for( USHORT i = 0; i < pBox->GetTabLines().Count(); ++i ) + { + rParam.nLowerDiff = 0; + lcl_InsOtherBox( pBox->GetTabLines()[ i ], rParam, + nDist, FALSE ); + + if( nLowerDiff < rParam.nLowerDiff ) + nLowerDiff = rParam.nLowerDiff; + } + rParam.nLowerDiff = nOldLower; + + if( nLowerDiff || + (rParam.bLeft ? ((nDist + nWidth / 2 ) <= rParam.nSide && + (TBLFIX_CHGABS != rParam.nMode || + n < rBoxes.Count() && + (nDist + nWidth + rBoxes[ n+1 ]-> + GetFrmFmt()->GetFrmSize().GetWidth() / 2) + > rParam.nSide )) + : (nDist + nWidth / 2 ) > rParam.nSide )) + { + if( !nLowerDiff ) + { + if( TBLFIX_CHGPROP == rParam.nMode ) // Tabelle fix, proport. + { + // relativ berechnen + nLowerDiff = nWidth; + nLowerDiff *= rParam.nDiff; + nLowerDiff /= rParam.nRemainWidth; + } + else + nLowerDiff = rParam.nDiff; + } + + SwFmtFrmSize aNew( rSz ); + rParam.nLowerDiff += nLowerDiff; + + if( rParam.bBigger ) + aNew.SetWidth( nWidth - nLowerDiff ); + else + aNew.SetWidth( nWidth + nLowerDiff ); + rParam.aShareFmts.SetSize( *pBox, aNew ); + + if( TBLFIX_CHGABS == rParam.nMode ) + break; + } + } + + nDist += nWidth; + } + return TRUE; +} + + +// das Ergebnis des Positions Vergleiches +// POS_BEFORE, // Box liegt davor +// POS_BEHIND, // Box liegt dahinter +// POS_INSIDE, // Box liegt vollstaendig in Start/End +// POS_OUTSIDE, // Box ueberlappt Start/End vollstaendig +// POS_EQUAL, // Box und Start/End sind gleich +// POS_OVERLAP_BEFORE, // Box ueberlappt den Start +// POS_OVERLAP_BEHIND // Box ueberlappt das Ende + +SwComparePosition _CheckBoxInRange( USHORT nStt, USHORT nEnd, + USHORT nBoxStt, USHORT nBoxEnd ) +{ +// COLFUZZY noch beachten!! + SwComparePosition nRet; + if( nBoxStt + COLFUZZY < nStt ) + { + if( nBoxEnd > nStt + COLFUZZY ) + { + if( nBoxEnd >= nEnd + COLFUZZY ) + nRet = POS_OUTSIDE; + else + nRet = POS_OVERLAP_BEFORE; + } + else + nRet = POS_BEFORE; + } + else if( nEnd > nBoxStt + COLFUZZY ) + { + if( nEnd + COLFUZZY >= nBoxEnd ) + { + if( COLFUZZY > Abs( long(nEnd) - long(nBoxEnd) ) && + COLFUZZY > Abs( long(nStt) - long(nBoxStt) ) ) + nRet = POS_EQUAL; + else + nRet = POS_INSIDE; + } + else + nRet = POS_OVERLAP_BEHIND; + } + else + nRet = POS_BEHIND; + + return nRet; +} + +void lcl_DelSelBox_CorrLowers( SwTableLine& rLine, CR_SetBoxWidth& rParam, + SwTwips nWidth ) +{ + // 1. Schritt die eigene Breite feststellen + SwTableBoxes& rBoxes = rLine.GetTabBoxes(); + SwTwips nBoxWidth = 0; + USHORT n; + + for( n = rBoxes.Count(); n; ) + nBoxWidth += rBoxes[ --n ]->GetFrmFmt()->GetFrmSize().GetWidth(); + + if( COLFUZZY < Abs( nWidth - nBoxWidth )) + { + // sie muessen also angepasst werden + for( n = rBoxes.Count(); n; ) + { + SwTableBox* pBox = rBoxes[ --n ]; + SwFmtFrmSize aNew( pBox->GetFrmFmt()->GetFrmSize() ); + long nDiff = aNew.GetWidth(); + nDiff *= nWidth; + nDiff /= nBoxWidth; + aNew.SetWidth( nDiff ); + + rParam.aShareFmts.SetSize( *pBox, aNew ); + + if( !pBox->GetSttNd() ) + { + // hat selbst auch Lower, also auch die anpassen + for( USHORT i = pBox->GetTabLines().Count(); i; ) + ::lcl_DelSelBox_CorrLowers( *pBox->GetTabLines()[ --i ], + rParam, nDiff ); + } + } + } +} + +void lcl_ChgBoxSize( SwTableBox& rBox, CR_SetBoxWidth& rParam, + const SwFmtFrmSize& rOldSz, + USHORT& rDelWidth, SwTwips nDist ) +{ + long nDiff; + BOOL bSetSize = FALSE; + + switch( rParam.nMode ) + { + case TBLFIX_CHGABS: // Tabelle feste Breite, den Nachbar andern + nDiff = rDelWidth + rParam.nLowerDiff; + bSetSize = TRUE; + break; + + case TBLFIX_CHGPROP: // Tabelle feste Breite, alle Nachbarn aendern + if( !rParam.nRemainWidth ) + { + // dann kurz berechnen: + if( rParam.bLeft ) + rParam.nRemainWidth = USHORT(nDist); + else + rParam.nRemainWidth = USHORT(rParam.nTblWidth - nDist); + } + + // relativ berechnen + nDiff = rOldSz.GetWidth(); + nDiff *= rDelWidth + rParam.nLowerDiff; + nDiff /= rParam.nRemainWidth; + + bSetSize = TRUE; + break; + + case TBLVAR_CHGABS: // Tabelle variable, alle Nachbarn aendern + if( COLFUZZY < Abs( rParam.nBoxWidth - + ( rDelWidth + rParam.nLowerDiff ))) + { + nDiff = rDelWidth + rParam.nLowerDiff - rParam.nBoxWidth; + if( 0 < nDiff ) + rDelWidth = rDelWidth - USHORT(nDiff); + else + rDelWidth = rDelWidth + USHORT(-nDiff); + bSetSize = TRUE; + } + break; + } + + if( bSetSize ) + { + SwFmtFrmSize aNew( rOldSz ); + aNew.SetWidth( aNew.GetWidth() + nDiff ); + rParam.aShareFmts.SetSize( rBox, aNew ); + + // dann leider nochmals die Lower anpassen + for( USHORT i = rBox.GetTabLines().Count(); i; ) + ::lcl_DelSelBox_CorrLowers( *rBox.GetTabLines()[ --i ], rParam, + aNew.GetWidth() ); + } +} + +BOOL lcl_DeleteBox_Rekursiv( CR_SetBoxWidth& rParam, SwTableBox& rBox, + BOOL bCheck ) +{ + BOOL bRet = TRUE; + if( rBox.GetSttNd() ) + { + if( bCheck ) + { + rParam.bAnyBoxFnd = TRUE; + if( rBox.GetFrmFmt()->GetProtect().IsCntntProtected() ) + bRet = FALSE; + else + { + SwTableBox* pBox = &rBox; + rParam.aBoxes.Insert( pBox ); + } + } + else + ::_DeleteBox( rParam.pTblNd->GetTable(), &rBox, + rParam.pUndo, FALSE, TRUE, &rParam.aShareFmts ); + } + else + { + // die muessen leider alle sequentiel ueber die + // Contentboxen geloescht werden + for( USHORT i = rBox.GetTabLines().Count(); i; ) + { + SwTableLine& rLine = *rBox.GetTabLines()[ --i ]; + for( USHORT n = rLine.GetTabBoxes().Count(); n; ) + if( !::lcl_DeleteBox_Rekursiv( rParam, + *rLine.GetTabBoxes()[ --n ], bCheck )) + return FALSE; + } + } + return bRet; +} + +BOOL lcl_DelSelBox( SwTableLine* pTabLine, CR_SetBoxWidth& rParam, + SwTwips nDist, BOOL bCheck ) +{ + SwTableBoxes& rBoxes = pTabLine->GetTabBoxes(); + USHORT n, nCntEnd, nBoxChkStt, nBoxChkEnd, nDelWidth = 0; + if( rParam.bLeft ) + { + n = rBoxes.Count(); + nCntEnd = 0; + nBoxChkStt = (USHORT)rParam.nSide; + nBoxChkEnd = static_cast<USHORT>(rParam.nSide + rParam.nBoxWidth); + } + else + { + n = 0; + nCntEnd = rBoxes.Count(); + nBoxChkStt = static_cast<USHORT>(rParam.nSide - rParam.nBoxWidth); + nBoxChkEnd = (USHORT)rParam.nSide; + } + + + while( n != nCntEnd ) + { + SwTableBox* pBox; + if( rParam.bLeft ) + pBox = rBoxes[ --n ]; + else + pBox = rBoxes[ n++ ]; + + SwFrmFmt* pFmt = pBox->GetFrmFmt(); + const SwFmtFrmSize& rSz = pFmt->GetFrmSize(); + long nWidth = rSz.GetWidth(); + BOOL bDelBox = FALSE, bChgLowers = FALSE; + + // die Boxenbreite testen und entpsrechend reagieren + SwComparePosition ePosType = ::_CheckBoxInRange( + nBoxChkStt, nBoxChkEnd, + USHORT(rParam.bLeft ? nDist - nWidth : nDist), + USHORT(rParam.bLeft ? nDist : nDist + nWidth)); + + switch( ePosType ) + { + case POS_BEFORE: + if( bCheck ) + { + if( rParam.bLeft ) + return TRUE; + } + else if( rParam.bLeft ) + { + ::lcl_ChgBoxSize( *pBox, rParam, rSz, nDelWidth, nDist ); + if( TBLFIX_CHGABS == rParam.nMode ) + n = nCntEnd; + } + break; + + case POS_BEHIND: + if( bCheck ) + { + if( !rParam.bLeft ) + return TRUE; + } + else if( !rParam.bLeft ) + { + ::lcl_ChgBoxSize( *pBox, rParam, rSz, nDelWidth, nDist ); + if( TBLFIX_CHGABS == rParam.nMode ) + n = nCntEnd; + } + break; + + case POS_OUTSIDE: // Box ueberlappt Start/End vollstaendig + case POS_INSIDE: // Box liegt vollstaendig in Start/End + case POS_EQUAL: // Box und Start/End sind gleich + bDelBox = TRUE; + break; + + case POS_OVERLAP_BEFORE: // Box ueberlappt den Start + if( nBoxChkStt <= ( nDist + (rParam.bLeft ? - nWidth / 2 + : nWidth / 2 ))) + { + if( !pBox->GetSttNd() ) + bChgLowers = TRUE; + else + bDelBox = TRUE; + } + else if( !bCheck && rParam.bLeft ) + { + if( !pBox->GetSttNd() ) + bChgLowers = TRUE; + else + { + ::lcl_ChgBoxSize( *pBox, rParam, rSz, nDelWidth, nDist ); + if( TBLFIX_CHGABS == rParam.nMode ) + n = nCntEnd; + } + } + break; + + case POS_OVERLAP_BEHIND: // Box ueberlappt das Ende + // JP 10.02.99: + // generell loeschen oder wie beim OVERLAP_Before nur die, die + // bis zur Haelfte in die "Loesch-"Box reicht ??? + if( !pBox->GetSttNd() ) + bChgLowers = TRUE; + else + bDelBox = TRUE; + break; + default: break; + } + + if( bDelBox ) + { + nDelWidth = nDelWidth + USHORT(nWidth); + if( bCheck ) + { + // die letzte/erste Box kann nur bei Tbl-Var geloescht werden, + // wenn diese so gross ist, wie die Aenderung an der Tabelle + if( (( TBLVAR_CHGABS != rParam.nMode || + nDelWidth != rParam.nBoxWidth ) && + COLFUZZY > Abs( rParam.bLeft + ? nWidth - nDist + : (nDist + nWidth - rParam.nTblWidth ))) + || !::lcl_DeleteBox_Rekursiv( rParam, *pBox, bCheck ) ) + return FALSE; + + if( pFmt->GetProtect().IsCntntProtected() ) + return FALSE; + } + else + { + ::lcl_DeleteBox_Rekursiv( rParam, *pBox, bCheck ); + + if( !rParam.bLeft ) + --n, --nCntEnd; + } + } + else if( bChgLowers ) + { + BOOL bFirst = TRUE, bCorrLowers = FALSE; + long nLowerDiff = 0; + long nOldLower = rParam.nLowerDiff; + USHORT nOldRemain = rParam.nRemainWidth; + USHORT i; + + for( i = pBox->GetTabLines().Count(); i; ) + { + rParam.nLowerDiff = nDelWidth + nOldLower; + rParam.nRemainWidth = nOldRemain; + SwTableLine* pLine = pBox->GetTabLines()[ --i ]; + if( !::lcl_DelSelBox( pLine, rParam, nDist, bCheck )) + return FALSE; + + // gibt es die Box und die darin enthaltenen Lines noch?? + if( n < rBoxes.Count() && + pBox == rBoxes[ rParam.bLeft ? n : n-1 ] && + i < pBox->GetTabLines().Count() && + pLine == pBox->GetTabLines()[ i ] ) + { + if( !bFirst && !bCorrLowers && + COLFUZZY < Abs( nLowerDiff - rParam.nLowerDiff ) ) + bCorrLowers = TRUE; + + // die groesste "loesch" Breite entscheidet, aber nur wenn + // nicht die gesamte Line geloescht wurde + if( nLowerDiff < rParam.nLowerDiff ) + nLowerDiff = rParam.nLowerDiff; + + bFirst = FALSE; + } + } + rParam.nLowerDiff = nOldLower; + rParam.nRemainWidth = nOldRemain; + + // wurden alle Boxen geloescht? Dann ist die DelBreite natuerlich + // die Boxenbreite + if( !nLowerDiff ) + nLowerDiff = nWidth; + + // DelBreite anpassen!! + nDelWidth = nDelWidth + USHORT(nLowerDiff); + + if( !bCheck ) + { + // wurde die Box schon entfernt? + if( n > rBoxes.Count() || + pBox != rBoxes[ ( rParam.bLeft ? n : n-1 ) ] ) + { + // dann beim Loeschen nach rechts die Laufvar. anpassen + if( !rParam.bLeft ) + --n, --nCntEnd; + } + else + { + // sonst muss die Groesse der Box angepasst werden + SwFmtFrmSize aNew( rSz ); + BOOL bCorrRel = FALSE; + + if( TBLVAR_CHGABS != rParam.nMode ) + { + switch( ePosType ) + { + case POS_OVERLAP_BEFORE: // Box ueberlappt den Start + if( TBLFIX_CHGPROP == rParam.nMode ) + bCorrRel = rParam.bLeft; + else if( rParam.bLeft ) // TBLFIX_CHGABS + { + nLowerDiff = nLowerDiff - nDelWidth; + bCorrLowers = TRUE; + n = nCntEnd; + } + break; + + case POS_OVERLAP_BEHIND: // Box ueberlappt das Ende + if( TBLFIX_CHGPROP == rParam.nMode ) + bCorrRel = !rParam.bLeft; + else if( !rParam.bLeft ) // TBLFIX_CHGABS + { + nLowerDiff = nLowerDiff - nDelWidth; + bCorrLowers = TRUE; + n = nCntEnd; + } + break; + + default: + ASSERT( !pBox, "hier sollte man nie hinkommen" ); + break; + } + } + + if( bCorrRel ) + { + if( !rParam.nRemainWidth ) + { + // dann kurz berechnen: + if( rParam.bLeft ) + rParam.nRemainWidth = USHORT(nDist - nLowerDiff); + else + rParam.nRemainWidth = USHORT(rParam.nTblWidth - nDist + - nLowerDiff ); + } + + long nDiff = aNew.GetWidth() - nLowerDiff; + nDiff *= nDelWidth + rParam.nLowerDiff; + nDiff /= rParam.nRemainWidth; + + aNew.SetWidth( aNew.GetWidth() - nLowerDiff + nDiff ); + } + else + aNew.SetWidth( aNew.GetWidth() - nLowerDiff ); + rParam.aShareFmts.SetSize( *pBox, aNew ); + + if( bCorrLowers ) + { + // dann leider nochmals die Lower anpassen + for( i = pBox->GetTabLines().Count(); i; ) + ::lcl_DelSelBox_CorrLowers( *pBox-> + GetTabLines()[ --i ], rParam, aNew.GetWidth() ); + } + } + } + } + + if( rParam.bLeft ) + nDist -= nWidth; + else + nDist += nWidth; + } + rParam.nLowerDiff = nDelWidth; + return TRUE; +} + +// Dummy Funktion fuer die Methode SetColWidth +BOOL lcl_DelOtherBox( SwTableLine* , CR_SetBoxWidth& , SwTwips , BOOL ) +{ + return TRUE; +} + +/**/ + +void lcl_AjustLines( SwTableLine* pLine, CR_SetBoxWidth& rParam ) +{ + SwTableBoxes& rBoxes = pLine->GetTabBoxes(); + for( USHORT n = 0; n < rBoxes.Count(); ++n ) + { + SwTableBox* pBox = rBoxes[ n ]; + + SwFmtFrmSize aSz( pBox->GetFrmFmt()->GetFrmSize() ); + SwTwips nWidth = aSz.GetWidth(); + nWidth *= rParam.nDiff; + nWidth /= rParam.nMaxSize; + aSz.SetWidth( nWidth ); + rParam.aShareFmts.SetSize( *pBox, aSz ); + + for( USHORT i = 0; i < pBox->GetTabLines().Count(); ++i ) + ::lcl_AjustLines( pBox->GetTabLines()[ i ], rParam ); + } +} + +#if !defined( PRODUCT ) || defined( JP_DEBUG ) + +void _CheckBoxWidth( const SwTableLine& rLine, SwTwips nSize ) +{ + const SwTableBoxes& rBoxes = rLine.GetTabBoxes(); + + SwTwips nAktSize = 0; + // checke doch mal ob die Tabellen korrekte Breiten haben + for( USHORT n = 0; n < rBoxes.Count(); ++n ) + { + const SwTableBox* pBox = rBoxes[ n ]; + const SwTwips nBoxW = pBox->GetFrmFmt()->GetFrmSize().GetWidth(); + nAktSize += nBoxW; + + for( USHORT i = 0; i < pBox->GetTabLines().Count(); ++i ) + _CheckBoxWidth( *pBox->GetTabLines()[ i ], nBoxW ); + } + + if( Abs( nAktSize - nSize ) > ( COLFUZZY * rBoxes.Count() ) ) + { + DBG_ERROR( "Boxen der Line zu klein/gross" ); +#if defined( WNT ) && defined( JP_DEBUG ) + __asm int 3; +#endif + } +} + +#endif + +_FndBox* lcl_SaveInsDelData( CR_SetBoxWidth& rParam, SwUndo** ppUndo, + SwTableSortBoxes& rTmpLst, SwTwips nDistStt ) +{ + // suche alle Boxen / Lines + SwTable& rTbl = rParam.pTblNd->GetTable(); + + if( !rParam.aBoxes.Count() ) + { + // erstmal die Boxen besorgen ! + if( rParam.bBigger ) + for( USHORT n = 0; n < rTbl.GetTabLines().Count(); ++n ) + ::lcl_DelSelBox( rTbl.GetTabLines()[ n ], rParam, nDistStt, TRUE ); + else + for( USHORT n = 0; n < rTbl.GetTabLines().Count(); ++n ) + ::lcl_InsSelBox( rTbl.GetTabLines()[ n ], rParam, nDistStt, TRUE ); + } + + // loeschen der gesamten Tabelle verhindern + if( rParam.bBigger && rParam.aBoxes.Count() == + rTbl.GetTabSortBoxes().Count() ) + return 0; + + _FndBox* pFndBox = new _FndBox( 0, 0 ); + if( rParam.bBigger ) + pFndBox->SetTableLines( rParam.aBoxes, rTbl ); + else + { + _FndPara aPara( rParam.aBoxes, pFndBox ); + rTbl.GetTabLines().ForEach( &_FndLineCopyCol, &aPara ); + ASSERT( pFndBox->GetLines().Count(), "Wo sind die Boxen" ); + pFndBox->SetTableLines( rTbl ); + + if( ppUndo ) + rTmpLst.Insert( &rTbl.GetTabSortBoxes(), 0, rTbl.GetTabSortBoxes().Count() ); + } + + //Lines fuer das Layout-Update herausuchen. + pFndBox->DelFrms( rTbl ); + + // TL_CHART2: this function gest called from SetColWidth exclusively, + // thus it is currently speculated that nothing needs to be done here. + // Note: that SetColWidth is currently not completely understood though :-( + + return pFndBox; +} + +BOOL SwTable::SetColWidth( SwTableBox& rAktBox, USHORT eType, + SwTwips nAbsDiff, SwTwips nRelDiff, SwUndo** ppUndo ) +{ + SetHTMLTableLayout( 0 ); // MIB 9.7.97: HTML-Layout loeschen + + const SwFmtFrmSize& rSz = GetFrmFmt()->GetFrmSize(); + const SvxLRSpaceItem& rLR = GetFrmFmt()->GetLRSpace(); + + _FndBox* pFndBox = 0; // fuers Einfuegen/Loeschen + SwTableSortBoxes aTmpLst( 0, 5 ); // fuers Undo + BOOL bBigger, + bRet = FALSE, + bLeft = nsTblChgWidthHeightType::WH_COL_LEFT == ( eType & 0xff ) || + nsTblChgWidthHeightType::WH_CELL_LEFT == ( eType & 0xff ), + bInsDel = 0 != (eType & nsTblChgWidthHeightType::WH_FLAG_INSDEL ); + USHORT n; + ULONG nBoxIdx = rAktBox.GetSttIdx(); + + // bestimme die akt. Kante der Box + // wird nur fuer die Breitenmanipulation benoetigt! + const SwTwips nDist = ::lcl_GetDistance( &rAktBox, bLeft ); + SwTwips nDistStt = 0; + CR_SetBoxWidth aParam( eType, nRelDiff, nDist, rSz.GetWidth(), + bLeft ? nDist : rSz.GetWidth() - nDist, + (SwTableNode*)rAktBox.GetSttNd()->FindTableNode() ); + bBigger = aParam.bBigger; + + FN_lcl_SetBoxWidth fnSelBox, fnOtherBox; + if( bInsDel ) + { + if( bBigger ) + { + fnSelBox = lcl_DelSelBox; + fnOtherBox = lcl_DelOtherBox; + aParam.nBoxWidth = (USHORT)rAktBox.GetFrmFmt()->GetFrmSize().GetWidth(); + if( bLeft ) + nDistStt = rSz.GetWidth(); + } + else + { + fnSelBox = lcl_InsSelBox; + fnOtherBox = lcl_InsOtherBox; + } + } + else + { + fnSelBox = lcl_SetSelBoxWidth; + fnOtherBox = lcl_SetOtherBoxWidth; + } + + + switch( eType & 0xff ) + { + case nsTblChgWidthHeightType::WH_COL_RIGHT: + case nsTblChgWidthHeightType::WH_COL_LEFT: + if( TBLVAR_CHGABS == eTblChgMode ) + { + if( bInsDel ) + bBigger = !bBigger; + + // erstmal testen, ob ueberhaupt Platz ist + BOOL bChgLRSpace = TRUE; + if( bBigger ) + { + if( GetFrmFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::BROWSE_MODE) && + !rSz.GetWidthPercent() ) + { + bRet = rSz.GetWidth() < USHRT_MAX - nRelDiff; + bChgLRSpace = bLeft ? rLR.GetLeft() >= nAbsDiff + : rLR.GetRight() >= nAbsDiff; + } + else + bRet = bLeft ? rLR.GetLeft() >= nAbsDiff + : rLR.GetRight() >= nAbsDiff; + + if( !bRet && bInsDel && + // auf der anderen Seite Platz? + ( bLeft ? rLR.GetRight() >= nAbsDiff + : rLR.GetLeft() >= nAbsDiff )) + { + bRet = TRUE; bLeft = !bLeft; + } + + if( !bRet ) + { + // dann sich selbst rekursiv aufrufen; nur mit + // einem anderen Mode -> proprotional + TblChgMode eOld = eTblChgMode; + eTblChgMode = TBLFIX_CHGPROP; + + bRet = SetColWidth( rAktBox, eType, nAbsDiff, nRelDiff, + ppUndo ); + eTblChgMode = eOld; + return bRet; + } + } + else + { + bRet = TRUE; + for( n = 0; n < aLines.Count(); ++n ) + { + aParam.LoopClear(); + if( !(*fnSelBox)( aLines[ n ], aParam, nDistStt, TRUE )) + { + bRet = FALSE; + break; + } + } + } + + if( bRet ) + { + if( bInsDel ) + { + pFndBox = ::lcl_SaveInsDelData( aParam, ppUndo, + aTmpLst, nDistStt ); + if( aParam.bBigger && aParam.aBoxes.Count() == + aSortCntBoxes.Count() ) + { + // dies gesamte Tabelle soll geloescht werden!! + GetFrmFmt()->GetDoc()->DeleteRowCol( aParam.aBoxes ); + return FALSE; + } + + if( ppUndo ) + *ppUndo = aParam.CreateUndo( + aParam.bBigger ? UNDO_COL_DELETE + : UNDO_TABLE_INSCOL ); + } + else if( ppUndo ) + *ppUndo = new SwUndoAttrTbl( *aParam.pTblNd, TRUE ); + + long nFrmWidth = LONG_MAX; + LockModify(); + SwFmtFrmSize aSz( rSz ); + SvxLRSpaceItem aLR( rLR ); + if( bBigger ) + { + // falls die Tabelle keinen Platz zum Wachsen hat, dann + // muessen wir welchen schaffen! + if( aSz.GetWidth() + nRelDiff > USHRT_MAX ) + { + // dann mal herunterbrechen auf USHRT_MAX / 2 + CR_SetBoxWidth aTmpPara( 0, aSz.GetWidth() / 2, + 0, aSz.GetWidth(), aSz.GetWidth(), aParam.pTblNd ); + for( USHORT nLn = 0; nLn < aLines.Count(); ++nLn ) + ::lcl_AjustLines( aLines[ nLn ], aTmpPara ); + aSz.SetWidth( aSz.GetWidth() / 2 ); + aParam.nDiff = nRelDiff /= 2; + aParam.nSide /= 2; + aParam.nMaxSize /= 2; + } + + if( bLeft ) + aLR.SetLeft( USHORT( aLR.GetLeft() - nAbsDiff ) ); + else + aLR.SetRight( USHORT( aLR.GetRight() - nAbsDiff ) ); + } + else if( bLeft ) + aLR.SetLeft( USHORT( aLR.GetLeft() + nAbsDiff ) ); + else + aLR.SetRight( USHORT( aLR.GetRight() + nAbsDiff ) ); + + if( bChgLRSpace ) + GetFrmFmt()->SetFmtAttr( aLR ); + const SwFmtHoriOrient& rHOri = GetFrmFmt()->GetHoriOrient(); + if( text::HoriOrientation::FULL == rHOri.GetHoriOrient() || + (text::HoriOrientation::LEFT == rHOri.GetHoriOrient() && aLR.GetLeft()) || + (text::HoriOrientation::RIGHT == rHOri.GetHoriOrient() && aLR.GetRight())) + { + SwFmtHoriOrient aHOri( rHOri ); + aHOri.SetHoriOrient( text::HoriOrientation::NONE ); + GetFrmFmt()->SetFmtAttr( aHOri ); + + // sollte die Tabelle noch auf relativen Werten + // (USHRT_MAX) stehen dann muss es jetzt auf absolute + // umgerechnet werden. Bug 61494 + if( GetFrmFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::BROWSE_MODE) && + !rSz.GetWidthPercent() ) + { + SwTabFrm* pTabFrm = (SwTabFrm*)SwClientIter( + *GetFrmFmt() ).First( TYPE( SwTabFrm )); + if( pTabFrm && + pTabFrm->Prt().Width() != rSz.GetWidth() ) + { + nFrmWidth = pTabFrm->Prt().Width(); + if( bBigger ) + nFrmWidth += nAbsDiff; + else + nFrmWidth -= nAbsDiff; + } + } + } + + if( bBigger ) + aSz.SetWidth( aSz.GetWidth() + nRelDiff ); + else + aSz.SetWidth( aSz.GetWidth() - nRelDiff ); + + if( rSz.GetWidthPercent() ) + aSz.SetWidthPercent( static_cast<BYTE>(( aSz.GetWidth() * 100 ) / + ( aSz.GetWidth() + aLR.GetRight() + aLR.GetLeft()))); + + GetFrmFmt()->SetFmtAttr( aSz ); + aParam.nTblWidth = USHORT( aSz.GetWidth() ); + + UnlockModify(); + + for( n = aLines.Count(); n; ) + { + --n; + aParam.LoopClear(); + (*fnSelBox)( aLines[ n ], aParam, nDistStt, FALSE ); + } + + // sollte die Tabelle noch auf relativen Werten + // (USHRT_MAX) stehen dann muss es jetzt auf absolute + // umgerechnet werden. Bug 61494 + if( LONG_MAX != nFrmWidth ) + { + SwFmtFrmSize aAbsSz( aSz ); + aAbsSz.SetWidth( nFrmWidth ); + GetFrmFmt()->SetFmtAttr( aAbsSz ); + } + } + } + else if( bInsDel || + ( bLeft ? nDist : Abs( rSz.GetWidth() - nDist ) > COLFUZZY ) ) + { + bRet = TRUE; + if( bLeft && TBLFIX_CHGABS == eTblChgMode && !bInsDel ) + aParam.bBigger = !bBigger; + + // erstmal testen, ob ueberhaupt Platz ist + if( bInsDel ) + { + if( aParam.bBigger ) + { + for( n = 0; n < aLines.Count(); ++n ) + { + aParam.LoopClear(); + if( !(*fnSelBox)( aLines[ n ], aParam, nDistStt, TRUE )) + { + bRet = FALSE; + break; + } + } + } + else + { + if( 0 != ( bRet = bLeft ? nDist != 0 + : ( rSz.GetWidth() - nDist ) > COLFUZZY ) ) + { + for( n = 0; n < aLines.Count(); ++n ) + { + aParam.LoopClear(); + if( !(*fnOtherBox)( aLines[ n ], aParam, 0, TRUE )) + { + bRet = FALSE; + break; + } + } + if( bRet && !aParam.bAnyBoxFnd ) + bRet = FALSE; + } + + if( !bRet && rAktBox.GetFrmFmt()->GetFrmSize().GetWidth() + - nRelDiff > COLFUZZY + + ( 567 / 2 /* min. 0,5 cm Platz lassen*/) ) + { + // dann den Platz von der akt. Zelle nehmen + aParam.bSplittBox = TRUE; + // aber das muss auch mal getestet werden! + bRet = TRUE; + + for( n = 0; n < aLines.Count(); ++n ) + { + aParam.LoopClear(); + if( !(*fnSelBox)( aLines[ n ], aParam, nDistStt, TRUE )) + { + bRet = FALSE; + break; + } + } + } + } + } + else if( aParam.bBigger ) + { + for( n = 0; n < aLines.Count(); ++n ) + { + aParam.LoopClear(); + if( !(*fnOtherBox)( aLines[ n ], aParam, 0, TRUE )) + { + bRet = FALSE; + break; + } + } + } + else + { + for( n = 0; n < aLines.Count(); ++n ) + { + aParam.LoopClear(); + if( !(*fnSelBox)( aLines[ n ], aParam, nDistStt, TRUE )) + { + bRet = FALSE; + break; + } + } + } + + // wenn ja, dann setzen + if( bRet ) + { + CR_SetBoxWidth aParam1( aParam ); + if( bInsDel ) + { + aParam1.bBigger = !aParam.bBigger; + pFndBox = ::lcl_SaveInsDelData( aParam, ppUndo, + aTmpLst, nDistStt ); + if( ppUndo ) + *ppUndo = aParam.CreateUndo( + aParam.bBigger ? UNDO_TABLE_DELBOX + : UNDO_TABLE_INSCOL ); + } + else if( ppUndo ) + *ppUndo = new SwUndoAttrTbl( *aParam.pTblNd, TRUE ); + + if( bInsDel + ? ( TBLFIX_CHGABS == eTblChgMode ? bLeft : bLeft ) + : ( TBLFIX_CHGABS != eTblChgMode && bLeft ) ) + { + for( n = aLines.Count(); n; ) + { + --n; + aParam.LoopClear(); + aParam1.LoopClear(); + (*fnSelBox)( aLines[ n ], aParam, nDistStt, FALSE ); + (*fnOtherBox)( aLines[ n ], aParam1, nDistStt, FALSE ); + } + } + else + for( n = aLines.Count(); n; ) + { + --n; + aParam.LoopClear(); + aParam1.LoopClear(); + (*fnOtherBox)( aLines[ n ], aParam1, nDistStt, FALSE ); + (*fnSelBox)( aLines[ n ], aParam, nDistStt, FALSE ); + } + } + } + break; + + case nsTblChgWidthHeightType::WH_CELL_RIGHT: + case nsTblChgWidthHeightType::WH_CELL_LEFT: + if( TBLVAR_CHGABS == eTblChgMode ) + { + // dann sich selbst rekursiv aufrufen; nur mit + // einem anderen Mode -> Nachbarn + TblChgMode eOld = eTblChgMode; + eTblChgMode = TBLFIX_CHGABS; + + bRet = SetColWidth( rAktBox, eType, nAbsDiff, nRelDiff, + ppUndo ); + eTblChgMode = eOld; + return bRet; + } + else if( bInsDel || ( bLeft ? nDist + : (rSz.GetWidth() - nDist) > COLFUZZY )) + { + if( bLeft && TBLFIX_CHGABS == eTblChgMode && !bInsDel ) + aParam.bBigger = !bBigger; + + // erstmal testen, ob ueberhaupt Platz ist + SwTableBox* pBox = &rAktBox; + SwTableLine* pLine = rAktBox.GetUpper(); + while( pLine->GetUpper() ) + { + USHORT nPos = pLine->GetTabBoxes().C40_GETPOS( SwTableBox, pBox ); + if( bLeft ? nPos : nPos + 1 != pLine->GetTabBoxes().Count() ) + break; + + pBox = pLine->GetUpper(); + pLine = pBox->GetUpper(); + } + + if( pLine->GetUpper() ) + { + // dann muss die Distanz wieder korriegiert werden! + aParam.nSide -= ::lcl_GetDistance( pLine->GetUpper(), TRUE ); + + if( bLeft ) + aParam.nMaxSize = aParam.nSide; + else + aParam.nMaxSize = pLine->GetUpper()->GetFrmFmt()-> + GetFrmSize().GetWidth() - aParam.nSide; + } + + // erstmal testen, ob ueberhaupt Platz ist + if( bInsDel ) + { + if( 0 != ( bRet = bLeft ? nDist != 0 + : ( rSz.GetWidth() - nDist ) > COLFUZZY ) && + !aParam.bBigger ) + { + bRet = (*fnOtherBox)( pLine, aParam, 0, TRUE ); + if( bRet && !aParam.bAnyBoxFnd ) + bRet = FALSE; + } + + if( !bRet && !aParam.bBigger && rAktBox.GetFrmFmt()-> + GetFrmSize().GetWidth() - nRelDiff > COLFUZZY + + ( 567 / 2 /* min. 0,5 cm Platz lassen*/) ) + { + // dann den Platz von der akt. Zelle nehmen + aParam.bSplittBox = TRUE; + bRet = TRUE; + } + } + else + { + FN_lcl_SetBoxWidth fnTmp = aParam.bBigger ? fnOtherBox : fnSelBox; + bRet = (*fnTmp)( pLine, aParam, nDistStt, TRUE ); + } + + // wenn ja, dann setzen + if( bRet ) + { + CR_SetBoxWidth aParam1( aParam ); + if( bInsDel ) + { + aParam1.bBigger = !aParam.bBigger; + pFndBox = ::lcl_SaveInsDelData( aParam, ppUndo, aTmpLst, nDistStt ); + if( ppUndo ) + *ppUndo = aParam.CreateUndo( + aParam.bBigger ? UNDO_TABLE_DELBOX + : UNDO_TABLE_INSCOL ); + } + else if( ppUndo ) + *ppUndo = new SwUndoAttrTbl( *aParam.pTblNd, TRUE ); + + if( bInsDel + ? ( TBLFIX_CHGABS == eTblChgMode ? (bBigger && bLeft) : bLeft ) + : ( TBLFIX_CHGABS != eTblChgMode && bLeft ) ) + { + (*fnSelBox)( pLine, aParam, nDistStt, FALSE ); + (*fnOtherBox)( pLine, aParam1, nDistStt, FALSE ); + } + else + { + (*fnOtherBox)( pLine, aParam1, nDistStt, FALSE ); + (*fnSelBox)( pLine, aParam, nDistStt, FALSE ); + } + } + } + break; + + } + + if( pFndBox ) + { + // dann raeume die Struktur aller Lines auf + GCLines(); + + //Layout updaten + if( !bBigger || pFndBox->AreLinesToRestore( *this ) ) + pFndBox->MakeFrms( *this ); + + // TL_CHART2: it is currently unclear if sth has to be done here. + // The function name hints that nothing needs to be done, on the other + // hand there is a case where sth gets deleted. :-( + + delete pFndBox; + + if( ppUndo && *ppUndo ) + { + aParam.pUndo->SetColWidthParam( nBoxIdx, static_cast<USHORT>(eTblChgMode), eType, + nAbsDiff, nRelDiff ); + if( !aParam.bBigger ) + aParam.pUndo->SaveNewBoxes( *aParam.pTblNd, aTmpLst ); + } + } + + if( bRet ) + { + CHECKBOXWIDTH + CHECKTABLELAYOUT + } + + return bRet; +} +/* */ + +_FndBox* lcl_SaveInsDelData( CR_SetLineHeight& rParam, SwUndo** ppUndo, + SwTableSortBoxes& rTmpLst ) +{ + // suche alle Boxen / Lines + SwTable& rTbl = rParam.pTblNd->GetTable(); + + ASSERT( rParam.aBoxes.Count(), "ohne Boxen ist nichts zu machen!" ); + + // loeschen der gesamten Tabelle verhindern + if( !rParam.bBigger && rParam.aBoxes.Count() == + rTbl.GetTabSortBoxes().Count() ) + return 0; + + _FndBox* pFndBox = new _FndBox( 0, 0 ); + if( !rParam.bBigger ) + pFndBox->SetTableLines( rParam.aBoxes, rTbl ); + else + { + _FndPara aPara( rParam.aBoxes, pFndBox ); + rTbl.GetTabLines().ForEach( &_FndLineCopyCol, &aPara ); + ASSERT( pFndBox->GetLines().Count(), "Wo sind die Boxen" ); + pFndBox->SetTableLines( rTbl ); + + if( ppUndo ) + rTmpLst.Insert( &rTbl.GetTabSortBoxes(), 0, rTbl.GetTabSortBoxes().Count() ); + } + + //Lines fuer das Layout-Update heraussuchen. + pFndBox->DelFrms( rTbl ); + + // TL_CHART2: it is currently unclear if sth has to be done here. + + return pFndBox; +} + +void SetLineHeight( SwTableLine& rLine, SwTwips nOldHeight, SwTwips nNewHeight, + BOOL bMinSize ) +{ + SwLayoutFrm* pLineFrm = GetRowFrm( rLine ); + ASSERT( pLineFrm, "wo ist der Frm von der SwTableLine?" ); + + SwFrmFmt* pFmt = rLine.ClaimFrmFmt(); + + SwTwips nMyNewH, nMyOldH = pLineFrm->Frm().Height(); + if( !nOldHeight ) // die BaseLine und absolut + nMyNewH = nMyOldH + nNewHeight; + else + { + // moeglichst genau rechnen + Fraction aTmp( nMyOldH ); + aTmp *= Fraction( nNewHeight, nOldHeight ); + aTmp += Fraction( 1, 2 ); // ggfs. aufrunden + nMyNewH = aTmp; + } + + SwFrmSize eSize = ATT_MIN_SIZE; + if( !bMinSize && + ( nMyOldH - nMyNewH ) > ( CalcRowRstHeight( pLineFrm ) + ROWFUZZY )) + eSize = ATT_FIX_SIZE; + + pFmt->SetFmtAttr( SwFmtFrmSize( eSize, 0, nMyNewH ) ); + + // erst alle inneren anpassen + SwTableBoxes& rBoxes = rLine.GetTabBoxes(); + for( USHORT n = 0; n < rBoxes.Count(); ++n ) + { + SwTableBox& rBox = *rBoxes[ n ]; + for( USHORT i = 0; i < rBox.GetTabLines().Count(); ++i ) + SetLineHeight( *rBox.GetTabLines()[ i ], nMyOldH, nMyNewH, bMinSize ); + } +} + +BOOL lcl_SetSelLineHeight( SwTableLine* pLine, CR_SetLineHeight& rParam, + SwTwips nDist, BOOL bCheck ) +{ + BOOL bRet = TRUE; + if( !bCheck ) + { + // Zeilenhoehe einstellen + SetLineHeight( *pLine, 0, rParam.bBigger ? nDist : -nDist, + rParam.bBigger ); + } + else if( !rParam.bBigger ) + { + // anhand der alten Size die neue relative errechnen + SwLayoutFrm* pLineFrm = GetRowFrm( *pLine ); + ASSERT( pLineFrm, "wo ist der Frm von der SwTableLine?" ); + SwTwips nRstHeight = CalcRowRstHeight( pLineFrm ); + if( (nRstHeight + ROWFUZZY) < nDist ) + bRet = FALSE; + } + return bRet; +} + +BOOL lcl_SetOtherLineHeight( SwTableLine* pLine, CR_SetLineHeight& rParam, + SwTwips nDist, BOOL bCheck ) +{ + BOOL bRet = TRUE; + if( bCheck ) + { + if( rParam.bBigger ) + { + // anhand der alten Size die neue relative errechnen + SwLayoutFrm* pLineFrm = GetRowFrm( *pLine ); + ASSERT( pLineFrm, "wo ist der Frm von der SwTableLine?" ); + + if( TBLFIX_CHGPROP == rParam.nMode ) + { + nDist *= pLineFrm->Frm().Height(); + nDist /= rParam.nMaxHeight; + } + bRet = nDist <= CalcRowRstHeight( pLineFrm ); + } + } + else + { + // Zeilenhoehe einstellen + // pLine ist die nachfolgende / vorhergehende -> also anpassen + if( TBLFIX_CHGPROP == rParam.nMode ) + { + SwLayoutFrm* pLineFrm = GetRowFrm( *pLine ); + ASSERT( pLineFrm, "wo ist der Frm von der SwTableLine?" ); + + // aus der alten Size die neue relative errechnen + // Wird die selektierte Box groesser ueber den MaxSpace anpassen, + // sonst ueber die MaxHeight + if( 1 /*!rParam.bBigger*/ ) + { + nDist *= pLineFrm->Frm().Height(); + nDist /= rParam.nMaxHeight; + } + else + { + // aus der alten Size die neue relative errechnen + nDist *= CalcRowRstHeight( pLineFrm ); + nDist /= rParam.nMaxSpace; + } + } + SetLineHeight( *pLine, 0, rParam.bBigger ? -nDist : nDist, + !rParam.bBigger ); + } + return bRet; +} + +BOOL lcl_InsDelSelLine( SwTableLine* pLine, CR_SetLineHeight& rParam, + SwTwips nDist, BOOL bCheck ) +{ + BOOL bRet = TRUE; + if( !bCheck ) + { + SwTableBoxes& rBoxes = pLine->GetTabBoxes(); + SwDoc* pDoc = pLine->GetFrmFmt()->GetDoc(); + if( !rParam.bBigger ) + { + USHORT n; + + for( n = rBoxes.Count(); n; ) + ::lcl_SaveUpperLowerBorder( rParam.pTblNd->GetTable(), + *rBoxes[ --n ], + rParam.aShareFmts ); + for( n = rBoxes.Count(); n; ) + ::_DeleteBox( rParam.pTblNd->GetTable(), + rBoxes[ --n ], rParam.pUndo, FALSE, + FALSE, &rParam.aShareFmts ); + } + else + { + // Zeile einfuegen + SwTableLine* pNewLine = new SwTableLine( (SwTableLineFmt*)pLine->GetFrmFmt(), + rBoxes.Count(), pLine->GetUpper() ); + SwTableLines* pLines; + if( pLine->GetUpper() ) + pLines = &pLine->GetUpper()->GetTabLines(); + else + pLines = &rParam.pTblNd->GetTable().GetTabLines(); + USHORT nPos = pLines->C40_GETPOS( SwTableLine, pLine ); + if( !rParam.bTop ) + ++nPos; + pLines->C40_INSERT( SwTableLine, pNewLine, nPos ); + + SwFrmFmt* pNewFmt = pNewLine->ClaimFrmFmt(); + pNewFmt->SetFmtAttr( SwFmtFrmSize( ATT_MIN_SIZE, 0, nDist ) ); + + // und noch mal die Anzahl Boxen erzeugen + SwTableBoxes& rNewBoxes = pNewLine->GetTabBoxes(); + for( USHORT n = 0; n < rBoxes.Count(); ++n ) + { + SwTwips nWidth = 0; + SwTableBox* pOld = rBoxes[ n ]; + if( !pOld->GetSttNd() ) + { + // keine normale "Content"-Box also auf die 1. naechste + // Box zurueckfallen + nWidth = pOld->GetFrmFmt()->GetFrmSize().GetWidth(); + while( !pOld->GetSttNd() ) + pOld = pOld->GetTabLines()[ 0 ]->GetTabBoxes()[ 0 ]; + } + ::_InsTblBox( pDoc, rParam.pTblNd, pNewLine, + (SwTableBoxFmt*)pOld->GetFrmFmt(), pOld, n ); + + // Sonderbehandlung fuer Umrandung die Obere muss + // entfernt werden + const SvxBoxItem& rBoxItem = pOld->GetFrmFmt()->GetBox(); + if( rBoxItem.GetTop() ) + { + SvxBoxItem aTmp( rBoxItem ); + aTmp.SetLine( 0, BOX_LINE_TOP ); + rParam.aShareFmts.SetAttr( rParam.bTop + ? *pOld + : *rNewBoxes[ n ], aTmp ); + } + + if( nWidth ) + rParam.aShareFmts.SetAttr( *rNewBoxes[ n ], + SwFmtFrmSize( ATT_FIX_SIZE, nWidth, 0 ) ); + } + } + } + else + { + // Boxen einsammeln! + SwTableBoxes& rBoxes = pLine->GetTabBoxes(); + for( USHORT n = rBoxes.Count(); n; ) + { + SwTableBox* pBox = rBoxes[ --n ]; + if( pBox->GetFrmFmt()->GetProtect().IsCntntProtected() ) + return FALSE; + + if( pBox->GetSttNd() ) + rParam.aBoxes.Insert( pBox ); + else + { + for( USHORT i = pBox->GetTabLines().Count(); i; ) + lcl_InsDelSelLine( pBox->GetTabLines()[ --i ], + rParam, 0, TRUE ); + } + } + } + return bRet; +} + +BOOL SwTable::SetRowHeight( SwTableBox& rAktBox, USHORT eType, + SwTwips nAbsDiff, SwTwips nRelDiff,SwUndo** ppUndo ) +{ + SwTableLine* pLine = rAktBox.GetUpper(); + + SwTableLine* pBaseLine = pLine; + while( pBaseLine->GetUpper() ) + pBaseLine = pBaseLine->GetUpper()->GetUpper(); + + _FndBox* pFndBox = 0; // fuers Einfuegen/Loeschen + SwTableSortBoxes aTmpLst( 0, 5 ); // fuers Undo + BOOL bBigger, + bRet = FALSE, + bTop = nsTblChgWidthHeightType::WH_ROW_TOP == ( eType & 0xff ) || + nsTblChgWidthHeightType::WH_CELL_TOP == ( eType & 0xff ), + bInsDel = 0 != (eType & nsTblChgWidthHeightType::WH_FLAG_INSDEL ); + USHORT n, nBaseLinePos = GetTabLines().C40_GETPOS( SwTableLine, pBaseLine ); + ULONG nBoxIdx = rAktBox.GetSttIdx(); + + CR_SetLineHeight aParam( eType, + (SwTableNode*)rAktBox.GetSttNd()->FindTableNode() ); + bBigger = aParam.bBigger; + + FN_lcl_SetLineHeight fnSelLine, fnOtherLine = lcl_SetOtherLineHeight; + if( bInsDel ) + fnSelLine = lcl_InsDelSelLine; + else + fnSelLine = lcl_SetSelLineHeight; + + SwTableLines* pLines = &aLines; + + // wie kommt man an die Hoehen heran? + switch( eType & 0xff ) + { + case nsTblChgWidthHeightType::WH_CELL_TOP: + case nsTblChgWidthHeightType::WH_CELL_BOTTOM: + if( pLine == pBaseLine ) + break; // dann geht es nicht! + + // ist eine verschachtelte Line (Box!) + pLines = &pLine->GetUpper()->GetTabLines(); + nBaseLinePos = pLines->C40_GETPOS( SwTableLine, pLine ); + pBaseLine = pLine; + // kein break! + + case nsTblChgWidthHeightType::WH_ROW_TOP: + case nsTblChgWidthHeightType::WH_ROW_BOTTOM: + { + if( bInsDel && !bBigger ) // um wieviel wird es Hoeher? + { + nAbsDiff = GetRowFrm( *pBaseLine )->Frm().Height(); + } + + if( TBLVAR_CHGABS == eTblChgMode ) + { + // erstmal testen, ob ueberhaupt Platz ist + if( bBigger ) + { + bRet = TRUE; +// was ist mit Top, was ist mit Tabelle im Rahmen oder in Kopf-/Fusszeile +// mit fester Hoehe ?? + if( !bRet ) + { + // dann sich selbst rekursiv aufrufen; nur mit + // einem anderen Mode -> proprotional + TblChgMode eOld = eTblChgMode; + eTblChgMode = TBLFIX_CHGPROP; + + bRet = SetRowHeight( rAktBox, eType, nAbsDiff, + nRelDiff, ppUndo ); + + eTblChgMode = eOld; + return bRet; + } + } + else + bRet = (*fnSelLine)( (*pLines)[ nBaseLinePos ], aParam, + nAbsDiff, TRUE ); + + if( bRet ) + { + if( bInsDel ) + { + if( !aParam.aBoxes.Count() ) + ::lcl_InsDelSelLine( (*pLines)[ nBaseLinePos ], + aParam, 0, TRUE ); + + pFndBox = ::lcl_SaveInsDelData( aParam, ppUndo, aTmpLst ); + + // #110525# delete complete table when last row is + // deleted + if( !bBigger && + aParam.aBoxes.Count() == aSortCntBoxes.Count() ) + { + GetFrmFmt()->GetDoc()->DeleteRowCol( aParam.aBoxes ); + return FALSE; + } + + + if( ppUndo ) + *ppUndo = aParam.CreateUndo( + bBigger ? UNDO_TABLE_INSROW + : UNDO_ROW_DELETE ); + } + else if( ppUndo ) + *ppUndo = new SwUndoAttrTbl( *aParam.pTblNd, TRUE ); + + (*fnSelLine)( (*pLines)[ nBaseLinePos ], aParam, + nAbsDiff, FALSE ); + } + } + else + { + bRet = TRUE; + USHORT nStt, nEnd; + if( bTop ) + nStt = 0, nEnd = nBaseLinePos; + else + nStt = nBaseLinePos + 1, nEnd = pLines->Count(); + + // die akt. Hoehe der Lines besorgen + if( TBLFIX_CHGPROP == eTblChgMode ) + { + for( n = nStt; n < nEnd; ++n ) + { + SwLayoutFrm* pLineFrm = GetRowFrm( *(*pLines)[ n ] ); + ASSERT( pLineFrm, "wo ist der Frm von der SwTableLine?" ); + aParam.nMaxSpace += CalcRowRstHeight( pLineFrm ); + aParam.nMaxHeight += pLineFrm->Frm().Height(); + } + if( bBigger && aParam.nMaxSpace < nAbsDiff ) + bRet = FALSE; + } + else + { + if( bTop ? nEnd : nStt < nEnd ) + { + if( bTop ) + nStt = nEnd - 1; + else + nEnd = nStt + 1; + } + else + bRet = FALSE; + } + + if( bRet ) + { + if( bBigger ) + { + for( n = nStt; n < nEnd; ++n ) + { + if( !(*fnOtherLine)( (*pLines)[ n ], aParam, + nAbsDiff, TRUE )) + { + bRet = FALSE; + break; + } + } + } + else + bRet = (*fnSelLine)( (*pLines)[ nBaseLinePos ], aParam, + nAbsDiff, TRUE ); + } + + if( bRet ) + { + // dann mal anpassen + if( bInsDel ) + { + if( !aParam.aBoxes.Count() ) + ::lcl_InsDelSelLine( (*pLines)[ nBaseLinePos ], + aParam, 0, TRUE ); + pFndBox = ::lcl_SaveInsDelData( aParam, ppUndo, aTmpLst ); + if( ppUndo ) + *ppUndo = aParam.CreateUndo( + bBigger ? UNDO_TABLE_INSROW + : UNDO_ROW_DELETE ); + } + else if( ppUndo ) + *ppUndo = new SwUndoAttrTbl( *aParam.pTblNd, TRUE ); + + CR_SetLineHeight aParam1( aParam ); + if( TBLFIX_CHGPROP == eTblChgMode && !bBigger && + !aParam.nMaxSpace ) + { + // dann muss der gesamte Platz auf alle Lines + // gleichmaessig verteilt werden. Dafuer wird die + // Anzahl benoetigt + aParam1.nLines = nEnd - nStt; + } + + if( bTop ) + { + (*fnSelLine)( (*pLines)[ nBaseLinePos ], aParam, + nAbsDiff, FALSE ); + for( n = nStt; n < nEnd; ++n ) + (*fnOtherLine)( (*pLines)[ n ], aParam1, + nAbsDiff, FALSE ); + } + else + { + for( n = nStt; n < nEnd; ++n ) + (*fnOtherLine)( (*pLines)[ n ], aParam1, + nAbsDiff, FALSE ); + (*fnSelLine)( (*pLines)[ nBaseLinePos ], aParam, + nAbsDiff, FALSE ); + } + } + else + { + // dann sich selbst rekursiv aufrufen; nur mit + // einem anderen Mode -> proprotional + TblChgMode eOld = eTblChgMode; + eTblChgMode = TBLVAR_CHGABS; + + bRet = SetRowHeight( rAktBox, eType, nAbsDiff, + nRelDiff, ppUndo ); + + eTblChgMode = eOld; + pFndBox = 0; + } + } + } + break; + } + + if( pFndBox ) + { + // dann raeume die Struktur aller Lines auf + GCLines(); + + //Layout updaten + if( bBigger || pFndBox->AreLinesToRestore( *this ) ) + pFndBox->MakeFrms( *this ); + + // TL_CHART2: it is currently unclear if sth has to be done here. + + delete pFndBox; + + if( ppUndo && *ppUndo ) + { + aParam.pUndo->SetColWidthParam( nBoxIdx, static_cast<USHORT>(eTblChgMode), eType, + nAbsDiff, nRelDiff ); + if( bBigger ) + aParam.pUndo->SaveNewBoxes( *aParam.pTblNd, aTmpLst ); + } + } + + CHECKTABLELAYOUT + + return bRet; +} + +/* */ + +SwFrmFmt* SwShareBoxFmt::GetFormat( long nWidth ) const +{ + SwFrmFmt *pRet = 0, *pTmp; + for( USHORT n = aNewFmts.Count(); n; ) + if( ( pTmp = (SwFrmFmt*)aNewFmts[ --n ])->GetFrmSize().GetWidth() + == nWidth ) + { + pRet = pTmp; + break; + } + return pRet; +} + +SwFrmFmt* SwShareBoxFmt::GetFormat( const SfxPoolItem& rItem ) const +{ + const SfxPoolItem* pItem; + USHORT nWhich = rItem.Which(); + SwFrmFmt *pRet = 0, *pTmp; + const SfxPoolItem& rFrmSz = pOldFmt->GetFmtAttr( RES_FRM_SIZE, FALSE ); + for( USHORT n = aNewFmts.Count(); n; ) + if( SFX_ITEM_SET == ( pTmp = (SwFrmFmt*)aNewFmts[ --n ])-> + GetItemState( nWhich, FALSE, &pItem ) && *pItem == rItem && + pTmp->GetFmtAttr( RES_FRM_SIZE, FALSE ) == rFrmSz ) + { + pRet = pTmp; + break; + } + return pRet; +} + +void SwShareBoxFmt::AddFormat( const SwFrmFmt& rNew ) +{ + void* pFmt = (void*)&rNew; + aNewFmts.Insert( pFmt, aNewFmts.Count() ); +} + +BOOL SwShareBoxFmt::RemoveFormat( const SwFrmFmt& rFmt ) +{ + // returnt TRUE, wenn geloescht werden kann + if( pOldFmt == &rFmt ) + return TRUE; + + void* p = (void*)&rFmt; + USHORT nFnd = aNewFmts.GetPos( p ); + if( USHRT_MAX != nFnd ) + aNewFmts.Remove( nFnd ); + return 0 == aNewFmts.Count(); +} + +SwShareBoxFmts::~SwShareBoxFmts() +{ +} + +SwFrmFmt* SwShareBoxFmts::GetFormat( const SwFrmFmt& rFmt, long nWidth ) const +{ + USHORT nPos; + return Seek_Entry( rFmt, &nPos ) + ? aShareArr[ nPos ]->GetFormat( nWidth ) + : 0; +} +SwFrmFmt* SwShareBoxFmts::GetFormat( const SwFrmFmt& rFmt, + const SfxPoolItem& rItem ) const +{ + USHORT nPos; + return Seek_Entry( rFmt, &nPos ) + ? aShareArr[ nPos ]->GetFormat( rItem ) + : 0; +} + +void SwShareBoxFmts::AddFormat( const SwFrmFmt& rOld, const SwFrmFmt& rNew ) +{ + // wenn das Format nicht geshared ist, braucht es auch nicht in die + // Liste aufgenommen werden. Denn es gibt keinen 2. der es sucht. +//leider werden auch die CellFrms gefunden +// if( !rOld.IsLastDepend() ) + { + USHORT nPos; + SwShareBoxFmt* pEntry; + if( !Seek_Entry( rOld, &nPos )) + { + pEntry = new SwShareBoxFmt( rOld ); + aShareArr.C40_INSERT( SwShareBoxFmt, pEntry, nPos ); + } + else + pEntry = aShareArr[ nPos ]; + + pEntry->AddFormat( rNew ); + } +} +void SwShareBoxFmts::ChangeFrmFmt( SwTableBox* pBox, SwTableLine* pLn, + SwFrmFmt& rFmt ) +{ + SwClient aCl; + SwFrmFmt* pOld = 0; + if( pBox ) + { + pOld = pBox->GetFrmFmt(); + pOld->Add( &aCl ); + pBox->ChgFrmFmt( (SwTableBoxFmt*)&rFmt ); + } + else if( pLn ) + { + pOld = pLn->GetFrmFmt(); + pOld->Add( &aCl ); + pLn->ChgFrmFmt( (SwTableLineFmt*)&rFmt ); + } + if( pOld && pOld->IsLastDepend() ) + { + RemoveFormat( *pOld ); + delete pOld; + } +} + +void SwShareBoxFmts::SetSize( SwTableBox& rBox, const SwFmtFrmSize& rSz ) +{ + SwFrmFmt *pBoxFmt = rBox.GetFrmFmt(), + *pRet = GetFormat( *pBoxFmt, rSz.GetWidth() ); + if( pRet ) + ChangeFrmFmt( &rBox, 0, *pRet ); + else + { + pRet = rBox.ClaimFrmFmt(); + pRet->SetFmtAttr( rSz ); + AddFormat( *pBoxFmt, *pRet ); + } +} + +void SwShareBoxFmts::SetAttr( SwTableBox& rBox, const SfxPoolItem& rItem ) +{ + SwFrmFmt *pBoxFmt = rBox.GetFrmFmt(), + *pRet = GetFormat( *pBoxFmt, rItem ); + if( pRet ) + ChangeFrmFmt( &rBox, 0, *pRet ); + else + { + pRet = rBox.ClaimFrmFmt(); + pRet->SetFmtAttr( rItem ); + AddFormat( *pBoxFmt, *pRet ); + } +} + +void SwShareBoxFmts::SetAttr( SwTableLine& rLine, const SfxPoolItem& rItem ) +{ + SwFrmFmt *pLineFmt = rLine.GetFrmFmt(), + *pRet = GetFormat( *pLineFmt, rItem ); + if( pRet ) + ChangeFrmFmt( 0, &rLine, *pRet ); + else + { + pRet = rLine.ClaimFrmFmt(); + pRet->SetFmtAttr( rItem ); + AddFormat( *pLineFmt, *pRet ); + } +} + +void SwShareBoxFmts::RemoveFormat( const SwFrmFmt& rFmt ) +{ + for( USHORT i = aShareArr.Count(); i; ) + if( aShareArr[ --i ]->RemoveFormat( rFmt )) + aShareArr.DeleteAndDestroy( i ); +} + +BOOL SwShareBoxFmts::Seek_Entry( const SwFrmFmt& rFmt, USHORT* pPos ) const +{ + ULONG nIdx = (ULONG)&rFmt; + USHORT nO = aShareArr.Count(), nM, nU = 0; + if( nO > 0 ) + { + nO--; + while( nU <= nO ) + { + nM = nU + ( nO - nU ) / 2; + ULONG nFmt = (ULONG)&aShareArr[ nM ]->GetOldFormat(); + if( nFmt == nIdx ) + { + if( pPos ) + *pPos = nM; + return TRUE; + } + else if( nFmt < nIdx ) + nU = nM + 1; + else if( nM == 0 ) + { + if( pPos ) + *pPos = nU; + return FALSE; + } + else + nO = nM - 1; + } + } + if( pPos ) + *pPos = nU; + return FALSE; +} + + |