/************************************************************************* * * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: tblrwcl.cxx,v $ * * $Revision: 1.20 $ * * last change: $Author: vg $ $Date: 2007-05-22 16:25:55 $ * * The Contents of this file are made available subject to * the terms of GNU Lesser General Public License Version 2.1. * * * GNU Lesser General Public License Version 2.1 * ============================================= * Copyright 2005 by Sun Microsystems, Inc. * 901 San Antonio Road, Palo Alto, CA 94303, USA * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software Foundation. * * This library 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 for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * ************************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_sw.hxx" #include #ifndef _HINTIDS_HXX #include #endif #define _ZFORLIST_DECLARE_TABLE #ifndef _SVX_BRSHITEM_HXX //autogen #include #endif #ifndef _SVX_LRSPITEM_HXX //autogen #include #endif #ifndef _SVX_PROTITEM_HXX //autogen #include #endif #ifndef _SVX_BOXITEM_HXX //autogen #include #endif #ifndef _FRACT_HXX #include #endif #ifndef _FMTFSIZE_HXX //autogen #include #endif #ifndef _FMTORNT_HXX //autogen #include #endif #ifndef _DOC_HXX #include #endif #ifndef _CNTFRM_HXX #include #endif #ifndef _TABFRM_HXX //autogen #include #endif #ifndef _FRMTOOL_HXX #include #endif #ifndef _PAM_HXX #include #endif #ifndef _SWTABLE_HXX #include #endif #ifndef _NDTXT_HXX #include #endif #ifndef _TBLSEL_HXX #include #endif #ifndef _FLDBAS_HXX #include #endif #ifndef _SWUNDO_HXX #include #endif #ifndef _ROWFRM_HXX #include #endif #ifndef _DDEFLD_HXX #include #endif #ifndef _UNDOBJ_HXX #include #endif #ifndef _CELLATR_HXX #include #endif #ifndef _MVSAVE_HXX #include #endif #ifndef _SWTBLFMT_HXX #include #endif #ifndef _SWDDETBL_HXX #include #endif #ifndef _POOLFMT_HXX #include #endif #ifndef _TBLRWCL_HXX #include #endif #ifndef _UNOCHART_HXX #include #endif #include using namespace com::sun::star; using namespace com::sun::star::uno; #define COLFUZZY 20 #define ROWFUZZY 10 #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; USHORT nMode, nTblWidth, nRemainWidth, nBoxWidth; BOOL bBigger, bLeft, bSplittBox, bAnyBoxFnd; CR_SetBoxWidth( USHORT eType, SwTwips nDif, SwTwips nSid, SwTwips nTblW, SwTwips nMax, SwTableNode* pTNd ) : nDiff( nDif ), nSide( nSid ), nMaxSize( nMax ), nTblWidth( (USHORT)nTblW ), nRemainWidth( 0 ), nLowerDiff( 0 ), bAnyBoxFnd( FALSE ), pTblNd( pTNd ), bSplittBox( FALSE ), nBoxWidth( 0 ) { bLeft = WH_COL_LEFT == ( eType & 0xff ) || WH_CELL_LEFT == ( eType & 0xff ); bBigger = 0 != (eType & WH_FLAG_BIGGER ); nMode = pTblNd->GetTable().GetTblChgMode(); } CR_SetBoxWidth( const CR_SetBoxWidth& rCpy ) : nDiff( rCpy.nDiff ), nMode( rCpy.nMode ), nSide( rCpy.nSide ), bBigger( rCpy.bBigger ), bLeft( rCpy.bLeft ), bSplittBox( rCpy.bSplittBox ), bAnyBoxFnd( rCpy.bAnyBoxFnd ), nTblWidth( rCpy.nTblWidth ), nRemainWidth( rCpy.nRemainWidth ), pTblNd( rCpy.pTblNd ), nMaxSize( rCpy.nMaxSize ), nLowerDiff( 0 ), pUndo( rCpy.pUndo ), nBoxWidth( nBoxWidth ) { aLines.Insert( &rCpy.aLines ); aLinesWidth.Insert( &rCpy.aLinesWidth, 0 ); } SwUndoTblNdsChg* CreateUndo( USHORT nUndoType ) { return pUndo = new SwUndoTblNdsChg( nUndoType, 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 ] += 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 n = 0; n < aLines.Count(); ++n ) \ ::_CheckBoxWidth( *aLines[ n ], nSize ); \ } #define CHECKTABLELAYOUT \ { \ for ( int 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; USHORT nMode, nLines; BOOL bBigger, bTop, bSplittBox, bAnyBoxFnd; CR_SetLineHeight( USHORT eType, SwTableNode* pTNd ) : nMaxSpace( 0 ), nLines( 0 ), nMaxHeight( 0 ), bAnyBoxFnd( FALSE ), bSplittBox( FALSE ) , pTblNd( pTNd ), pUndo( 0 ) { bTop = WH_ROW_TOP == ( eType & 0xff ) || WH_CELL_TOP == ( eType & 0xff ); bBigger = 0 != (eType & WH_FLAG_BIGGER ); if( eType & WH_FLAG_INSDEL ) bBigger = !bBigger; nMode = pTblNd->GetTable().GetTblChgMode(); } CR_SetLineHeight( const CR_SetLineHeight& rCpy ) : nMode( rCpy.nMode ), nMaxSpace( rCpy.nMaxSpace ), bBigger( rCpy.bBigger ), bTop( rCpy.bTop ), bSplittBox( rCpy.bSplittBox ), bAnyBoxFnd( rCpy.bAnyBoxFnd ), pTblNd( rCpy.pTblNd ), nLines( rCpy.nLines ), nMaxHeight( rCpy.nMaxHeight ), pUndo( rCpy.pUndo ) {} SwUndoTblNdsChg* CreateUndo( USHORT 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; SwFmtFrmSize aFrmSz( pNewFmt->GetFrmSize() ); if( pBox->GetTabLines().Count() && ( pCmpLine = rpFndBox->GetLines()[ 0 ])->GetBoxes().Count() != pCmpLine->GetLine()->GetTabBoxes().Count() ) { // 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->SetAttr( 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->SetAttr( aFrmSz ); } else { aFrmSz.SetWidth( aFrmSz.GetWidth() / ( pCpyPara->nCpyCnt + 1 ) ); pNewFmt->SetAttr( 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()->SetAttr( 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( pDoc && rBoxes.Count() && nCnt, "keine gueltige Box-Liste" ); SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode(); if( !pTblNd ) return FALSE; if( IsNewModel() ) return NewInsertCol( pDoc, rBoxes, nCnt, bBehind ); // 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 ); // TL_CHART2: need to inform chart of probably changed cell names pDoc->UpdateCharts( GetFrmFmt()->GetName() ); CHECKBOXWIDTH CHECKTABLELAYOUT return TRUE; } 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 FASTBOOL 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 ); } // TL_CHART2: need to inform chart of probably changed cell names pDoc->UpdateCharts( GetFrmFmt()->GetName() ); CHECKBOXWIDTH CHECKTABLELAYOUT 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 FASTBOOL 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->SetAttr( 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()->SetAttr( 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()->SetAttr( 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()->SetAttr( 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, 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()->SetAttr( 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->SetAttr( 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->ResetAttr( RES_LR_SPACE, RES_FRMATR_END - 1 ); pFrmFmt->ResetAttr( 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->SetAttr( 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->SetAttr( 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->SetAttr( 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->SetAttr( SwFmtFrmSize( ATT_VAR_SIZE, nWidth, 0 )); // in Boxen mit Lines darf es nur noch Size/Fillorder geben pFmt->ResetAttr( RES_LR_SPACE, RES_FRMATR_END - 1 ); pFmt->ResetAttr( 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 ), pMergeBox( pMerge ), pRightBox( pRight ) { 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()->ResetAttr( 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()->ResetAttr( 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()->ResetAttr( 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( pDoc && 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()->ResetAttr( 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* pLeft = new SwTableBox( (SwTableBoxFmt*)pMergeBox->GetFrmFmt(), 0, pInsLine ); SwTableBox* pRight = new SwTableBox( (SwTableBoxFmt*)pMergeBox->GetFrmFmt(), 0, pInsLine ); pMergeBox->SetUpper( pInsLine ); pInsLine->GetTabBoxes().C40_INSERT( SwTableBox, pLeft, 0 ); pLeft->ClaimFrmFmt(); pInsLine->GetTabBoxes().C40_INSERT( SwTableBox, pMergeBox, 1 ); pInsLine->GetTabBoxes().C40_INSERT( SwTableBox, pRight, 2 ); pRight->ClaimFrmFmt(); // in diese kommen alle Lines, die ueber dem selektierten Bereich stehen // Sie bilden also eine Upper/Lower Line _InsULPara aPara( pTblNd, TRUE, TRUE, pLeft, pMergeBox, pRight, 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( pLeft ); pFndBox->GetLines().ForEach( &lcl_Merge_MoveLine, &aPara ); aPara.SetRight( pRight ); pFndBox->GetLines().ForEach( &lcl_Merge_MoveLine, &aPara ); if( !pLeft->GetTabLines().Count() ) _DeleteBox( *this, pLeft, 0, FALSE, FALSE ); else { lcl_CalcWidth( pLeft ); // bereche die Breite der Box if( pUndo && pLeft->GetSttNd() ) pUndo->AddNewBox( pLeft->GetSttIdx() ); } if( !pRight->GetTabLines().Count() ) _DeleteBox( *this, pRight, 0, FALSE, FALSE ); else { lcl_CalcWidth( pRight ); // bereche die Breite der Box if( pUndo && pRight->GetSttNd() ) pUndo->AddNewBox( pRight->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 += (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 += (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->ResetAttr( RES_BOXATR_FORMULA, RES_BOXATR_VALUE ); aFrmSz.SetWidth( nSize ); aFindFrm.pNewFrmFmt->SetAttr( 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()->SetAttr( 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, 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 ); 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* pPara ) { // 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* pPara ) { ((SwTableLine*)rpLine)->GetTabBoxes().ForEach( &lcl_BoxSetHeadCondColl, 0 ); return TRUE; } /* */ #pragma optimize( "", off ) 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; } //#pragma optimize( "", on ) 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; 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( !rParam.bBigger && ( Abs( nDist + (( rParam.nMode && rParam.bLeft ) ? 0 : nWidth ) - rParam.nSide ) < COLFUZZY ) || ( 0 != ( bGreaterBox = TBLFIX_CHGABS != rParam.nMode && ( nDist + ( rParam.bLeft ? 0 : nWidth ) ) >= rParam.nSide)) ) { 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 || ( Abs( nDist + ( (rParam.nMode && rParam.bLeft) ? 0 : nWidth ) - rParam.nSide ) < COLFUZZY ) || ( 0 != ( bGreaterBox = !nOldLower && TBLFIX_CHGABS != rParam.nMode && ( nDist + ( rParam.bLeft ? 0 : nWidth ) ) >= rParam.nSide)) ) { // 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; } /* */ //#pragma optimize( "", off ) 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 aNew( rSz ); aNew.SetWidth( nWidth - rParam.nDiff ); rParam.aShareFmts.SetSize( *pBox, aNew ); } // 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; } //#pragma optimize( "", on ) 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 -= USHORT(nDiff); else 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* pLine, CR_SetBoxWidth& rParam, SwTwips nDist, BOOL bCheck ) { SwTableBoxes& rBoxes = pLine->GetTabBoxes(); USHORT n, nCntEnd, nBoxChkStt, nBoxChkEnd, nDelWidth = 0; if( rParam.bLeft ) { n = rBoxes.Count(); nCntEnd = 0; nBoxChkStt = (USHORT)rParam.nSide; nBoxChkEnd = rParam.nSide + rParam.nBoxWidth; } else { n = 0; nCntEnd = rBoxes.Count(); nBoxChkStt = 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; } if( bDelBox ) { 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 += 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 ]; 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 = WH_COL_LEFT == ( eType & 0xff ) || WH_CELL_LEFT == ( eType & 0xff ), bInsDel = 0 != (eType & WH_FLAG_INSDEL ); USHORT n; ULONG nBoxIdx = rAktBox.GetSttIdx(); // bestimme die akt. Kante der Box // wird nur fuer die Breitenmanipulation benoetigt! SwTwips nDist = ::lcl_GetDistance( &rAktBox, bLeft ), 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 WH_COL_RIGHT: case 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 n = 0; n < aLines.Count(); ++n ) ::lcl_AjustLines( aLines[ n ], 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()->SetAttr( aLR ); const SwFmtHoriOrient& rHOri = GetFrmFmt()->GetHoriOrient(); if( HORI_FULL == rHOri.GetHoriOrient() || (HORI_LEFT == rHOri.GetHoriOrient() && aLR.GetLeft()) || (HORI_RIGHT == rHOri.GetHoriOrient() && aLR.GetRight())) { SwFmtHoriOrient aHOri( rHOri ); aHOri.SetHoriOrient( HORI_NONE ); GetFrmFmt()->SetAttr( 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( ( aSz.GetWidth() * 100 ) / ( aSz.GetWidth() + aLR.GetRight() + aLR.GetLeft())); GetFrmFmt()->SetAttr( 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()->SetAttr( 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 : ( 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 WH_CELL_RIGHT: case 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 : ( 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, eTblChgMode, eType, nAbsDiff, nRelDiff ); if( !aParam.bBigger ) aParam.pUndo->SaveNewBoxes( *aParam.pTblNd, aTmpLst ); } } if( bRet ) { CHECKBOXWIDTH CHECKTABLELAYOUT } return bRet; } #pragma optimize( "", on ) /* */ _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->SetAttr( 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->SetAttr( 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 = WH_ROW_TOP == ( eType & 0xff ) || WH_CELL_TOP == ( eType & 0xff ), bInsDel = 0 != (eType & 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 WH_CELL_TOP: case 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 WH_ROW_TOP: case 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, 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->GetAttr( 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->GetAttr( 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() ); } FASTBOOL 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->SetAttr( 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->SetAttr( 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->SetAttr( 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; register 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; }