diff options
Diffstat (limited to 'sw/source/core/table/swtable.cxx')
-rw-r--r-- | sw/source/core/table/swtable.cxx | 2846 |
1 files changed, 2846 insertions, 0 deletions
diff --git a/sw/source/core/table/swtable.cxx b/sw/source/core/table/swtable.cxx new file mode 100644 index 000000000000..e4fc3278d4e1 --- /dev/null +++ b/sw/source/core/table/swtable.cxx @@ -0,0 +1,2846 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <ctype.h> +#include <float.h> +#include <hintids.hxx> +#include <hints.hxx> // fuer SwAttrSetChg +#include <editeng/lrspitem.hxx> +#include <editeng/shaditem.hxx> +#include <editeng/adjitem.hxx> +#include <editeng/colritem.hxx> +#include <sfx2/linkmgr.hxx> +#include <editeng/boxitem.hxx> +#include <fmtfsize.hxx> +#include <fmtornt.hxx> +#include <fmtpdsc.hxx> +#include <fldbas.hxx> +#include <fmtfld.hxx> +#include <frmatr.hxx> +#include <doc.hxx> +#include <docary.hxx> // fuer RedlineTbl() +#include <frame.hxx> +#include <swtable.hxx> +#include <ndtxt.hxx> +#include <tabcol.hxx> +#include <tabfrm.hxx> +#include <cellfrm.hxx> +#include <rowfrm.hxx> +#include <swserv.hxx> +#include <expfld.hxx> +#include <mdiexp.hxx> +#include <cellatr.hxx> +#include <txatbase.hxx> +#include <htmltbl.hxx> +#include <swtblfmt.hxx> +#include <ndindex.hxx> +#include <tblrwcl.hxx> +#include <shellres.hxx> +#include <viewsh.hxx> +#include <redline.hxx> +#include <list> +#include <switerator.hxx> + +#ifndef DBG_UTIL +#define CHECK_TABLE(t) +#else +#ifdef DEBUG +#define CHECK_TABLE(t) (t).CheckConsistency(); +#else +#define CHECK_TABLE(t) +#endif +#endif + +using namespace com::sun::star; + +TYPEINIT1( SwTable, SwClient ); +TYPEINIT1( SwTableBox, SwClient ); +TYPEINIT1( SwTableLine, SwClient ); +TYPEINIT1( SwTableFmt, SwFrmFmt ); +TYPEINIT1( SwTableBoxFmt, SwFrmFmt ); +TYPEINIT1( SwTableLineFmt, SwFrmFmt ); + +SV_IMPL_PTRARR(SwTableLines,SwTableLine*); +SV_IMPL_PTRARR(SwTableBoxes,SwTableBox*); +SV_IMPL_PTRARR_SORT(SwTableSortBoxes,SwTableBoxPtr); + +SV_IMPL_REF( SwServerObject ) + +#define COLFUZZY 20 + +void ChgTextToNum( SwTableBox& rBox, const String& rTxt, const Color* pCol, + sal_Bool bChgAlign,sal_uLong nNdPos ); +//---------------------------------- + +class SwTableBox_Impl +{ + Color *mpUserColor, *mpNumFmtColor; + long mnRowSpan; + bool mbDummyFlag; + + void SetNewCol( Color** ppCol, const Color* pNewCol ); +public: + SwTableBox_Impl() : mpUserColor(0), mpNumFmtColor(0), mnRowSpan(1), + mbDummyFlag( false ) {} + ~SwTableBox_Impl() { delete mpUserColor; delete mpNumFmtColor; } + + const Color* GetSaveUserColor() const { return mpUserColor; } + const Color* GetSaveNumFmtColor() const { return mpNumFmtColor; } + void SetSaveUserColor(const Color* p ) { SetNewCol( &mpUserColor, p ); } + void SetSaveNumFmtColor( const Color* p ) { SetNewCol( &mpNumFmtColor, p ); } + long getRowSpan() const { return mnRowSpan; } + void setRowSpan( long nNewRowSpan ) { mnRowSpan = nNewRowSpan; } + bool getDummyFlag() const { return mbDummyFlag; } + void setDummyFlag( bool bDummy ) { mbDummyFlag = bDummy; } +}; + +// ----------- Inlines ----------------------------- + +inline const Color* SwTableBox::GetSaveUserColor() const +{ + return pImpl ? pImpl->GetSaveUserColor() : 0; +} + +inline const Color* SwTableBox::GetSaveNumFmtColor() const +{ + return pImpl ? pImpl->GetSaveNumFmtColor() : 0; +} + +inline void SwTableBox::SetSaveUserColor(const Color* p ) +{ + if( pImpl ) + pImpl->SetSaveUserColor( p ); + else if( p ) + ( pImpl = new SwTableBox_Impl ) ->SetSaveUserColor( p ); +} + +inline void SwTableBox::SetSaveNumFmtColor( const Color* p ) +{ + if( pImpl ) + pImpl->SetSaveNumFmtColor( p ); + else if( p ) + ( pImpl = new SwTableBox_Impl )->SetSaveNumFmtColor( p ); +} + +long SwTableBox::getRowSpan() const +{ + return pImpl ? pImpl->getRowSpan() : 1; +} + +void SwTableBox::setRowSpan( long nNewRowSpan ) +{ + if( !pImpl ) + { + if( nNewRowSpan == 1 ) + return; + pImpl = new SwTableBox_Impl(); + } + pImpl->setRowSpan( nNewRowSpan ); +} + +bool SwTableBox::getDummyFlag() const +{ + return pImpl ? pImpl->getDummyFlag() : false; +} + +void SwTableBox::setDummyFlag( bool bDummy ) +{ + if( !pImpl ) + { + if( !bDummy ) + return; + pImpl = new SwTableBox_Impl(); + } + pImpl->setDummyFlag( bDummy ); +} + +//JP 15.09.98: Bug 55741 - Tabs beibehalten (vorne und hinten) +String& lcl_TabToBlankAtSttEnd( String& rTxt ) +{ + sal_Unicode c; + xub_StrLen n; + + for( n = 0; n < rTxt.Len() && ' ' >= ( c = rTxt.GetChar( n )); ++n ) + if( '\x9' == c ) + rTxt.SetChar( n, ' ' ); + for( n = rTxt.Len(); n && ' ' >= ( c = rTxt.GetChar( --n )); ) + if( '\x9' == c ) + rTxt.SetChar( n, ' ' ); + return rTxt; +} + +String& lcl_DelTabsAtSttEnd( String& rTxt ) +{ + sal_Unicode c; + xub_StrLen n; + + for( n = 0; n < rTxt.Len() && ' ' >= ( c = rTxt.GetChar( n )); ++n ) + if( '\x9' == c ) + rTxt.Erase( n--, 1 ); + for( n = rTxt.Len(); n && ' ' >= ( c = rTxt.GetChar( --n )); ) + if( '\x9' == c ) + rTxt.Erase( n, 1 ); + return rTxt; +} + +void _InsTblBox( SwDoc* pDoc, SwTableNode* pTblNd, + SwTableLine* pLine, SwTableBoxFmt* pBoxFrmFmt, + SwTableBox* pBox, + sal_uInt16 nInsPos, sal_uInt16 nCnt ) +{ + ASSERT( pBox->GetSttNd(), "Box ohne Start-Node" ); + SwNodeIndex aIdx( *pBox->GetSttNd(), +1 ); + SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode(); + if( !pCNd ) + pCNd = pDoc->GetNodes().GoNext( &aIdx ); + ASSERT( pCNd, "Box ohne ContentNode" ); + + if( pCNd->IsTxtNode() ) + { + if( pBox->GetSaveNumFmtColor() && pCNd->GetpSwAttrSet() ) + { + SwAttrSet aAttrSet( *pCNd->GetpSwAttrSet() ); + if( pBox->GetSaveUserColor() ) + aAttrSet.Put( SvxColorItem( *pBox->GetSaveUserColor(), RES_CHRATR_COLOR )); + else + aAttrSet.ClearItem( RES_CHRATR_COLOR ); + pDoc->GetNodes().InsBoxen( pTblNd, pLine, pBoxFrmFmt, + ((SwTxtNode*)pCNd)->GetTxtColl(), + &aAttrSet, nInsPos, nCnt ); + } + else + pDoc->GetNodes().InsBoxen( pTblNd, pLine, pBoxFrmFmt, + ((SwTxtNode*)pCNd)->GetTxtColl(), + pCNd->GetpSwAttrSet(), + nInsPos, nCnt ); + } + else + pDoc->GetNodes().InsBoxen( pTblNd, pLine, pBoxFrmFmt, + (SwTxtFmtColl*)pDoc->GetDfltTxtFmtColl(), 0, + nInsPos, nCnt ); + + long nRowSpan = pBox->getRowSpan(); + if( nRowSpan != 1 ) + { + SwTableBoxes& rTblBoxes = pLine->GetTabBoxes(); + for( sal_uInt16 i = 0; i < nCnt; ++i ) + { + pBox = rTblBoxes[ i + nInsPos ]; + pBox->setRowSpan( nRowSpan ); + } + } +} + +/************************************************************************* +|* +|* SwTable::SwTable() +|* +|*************************************************************************/ +SwTable::SwTable( SwTableFmt* pFmt ) + : SwClient( pFmt ), + pHTMLLayout( 0 ), + pTableNode( 0 ), + nGrfsThatResize( 0 ), + nRowsToRepeat( 1 ), + bModifyLocked( sal_False ), + bNewModel( sal_True ) +{ + // default Wert aus den Optionen setzen + eTblChgMode = (TblChgMode)GetTblChgDefaultMode(); +} + +SwTable::SwTable( const SwTable& rTable ) + : SwClient( rTable.GetFrmFmt() ), + pHTMLLayout( 0 ), + pTableNode( 0 ), + eTblChgMode( rTable.eTblChgMode ), + nGrfsThatResize( 0 ), + nRowsToRepeat( rTable.GetRowsToRepeat() ), + bModifyLocked( sal_False ), + bNewModel( rTable.bNewModel ) +{ +} + +void DelBoxNode( SwTableSortBoxes& rSortCntBoxes ) +{ + for( sal_uInt16 n = 0; n < rSortCntBoxes.Count(); ++n ) + rSortCntBoxes[ n ]->pSttNd = 0; +} + +SwTable::~SwTable() +{ + if( refObj.Is() ) + { + SwDoc* pDoc = GetFrmFmt()->GetDoc(); + if( !pDoc->IsInDtor() ) // dann aus der Liste entfernen + pDoc->GetLinkManager().RemoveServer( &refObj ); + + refObj->Closed(); + } + + // ist die Tabelle der letzte Client im FrameFormat, kann dieses + // geloescht werden + SwTableFmt* pFmt = (SwTableFmt*)GetFrmFmt(); + pFmt->Remove( this ); // austragen, + + if( !pFmt->GetDepends() ) + pFmt->GetDoc()->DelTblFrmFmt( pFmt ); // und loeschen + + // Loesche die Pointer aus dem SortArray der Boxen, die + // Objecte bleiben erhalten und werden vom DTOR der Lines/Boxes + // Arrays geloescht. + //JP: reicht leider nicht, es muessen die Pointer auf den StartNode + // der Section geloescht werden + DelBoxNode( aSortCntBoxes ); + aSortCntBoxes.Remove( (sal_uInt16)0, aSortCntBoxes.Count() ); + delete pHTMLLayout; +} + +/************************************************************************* +|* +|* SwTable::Modify() +|* +|*************************************************************************/ +inline void FmtInArr( SvPtrarr& rFmtArr, SwFmt* pBoxFmt ) +{ + sal_Bool bRet = USHRT_MAX != rFmtArr.GetPos( (VoidPtr)pBoxFmt ); + if( !bRet ) + rFmtArr.Insert( (VoidPtr)pBoxFmt, rFmtArr.Count() ); +} + +void lcl_ModifyBoxes( SwTableBoxes &rBoxes, const long nOld, + const long nNew, SvPtrarr& rFmtArr ); + +void lcl_ModifyLines( SwTableLines &rLines, const long nOld, + const long nNew, SvPtrarr& rFmtArr, const bool bCheckSum ) +{ + for ( sal_uInt16 i = 0; i < rLines.Count(); ++i ) + ::lcl_ModifyBoxes( rLines[i]->GetTabBoxes(), nOld, nNew, rFmtArr ); + if( bCheckSum ) + { + for( sal_uInt16 i = 0; i < rFmtArr.Count(); ++i ) + { + SwFmt* pFmt = (SwFmt*)rFmtArr[i]; + sal_uInt64 nBox = pFmt->GetFrmSize().GetWidth(); + nBox *= nNew; + nBox /= nOld; + SwFmtFrmSize aNewBox( ATT_VAR_SIZE, SwTwips(nBox), 0 ); + pFmt->LockModify(); + pFmt->SetFmtAttr( aNewBox ); + pFmt->UnlockModify(); + } + } +} + +void lcl_ModifyBoxes( SwTableBoxes &rBoxes, const long nOld, + const long nNew, SvPtrarr& rFmtArr ) +{ + sal_uInt64 nSum = 0; // To avoid rounding errors we summarize all box widths + sal_uInt64 nOriginalSum = 0; // Sum of original widths + for ( sal_uInt16 i = 0; i < rBoxes.Count(); ++i ) + { + SwTableBox &rBox = *rBoxes[i]; + if ( rBox.GetTabLines().Count() ) + { + // For SubTables the rounding problem will not be solved :-( + ::lcl_ModifyLines( rBox.GetTabLines(), nOld, nNew, rFmtArr, false ); + } + //Die Box anpassen + SwFrmFmt *pFmt = rBox.GetFrmFmt(); + sal_uInt64 nBox = pFmt->GetFrmSize().GetWidth(); + nOriginalSum += nBox; + nBox *= nNew; + nBox /= nOld; + sal_uInt64 nWishedSum = nOriginalSum; + nWishedSum *= nNew; + nWishedSum /= nOld; + nWishedSum -= nSum; + if( nWishedSum > 0 ) + { + if( nBox == nWishedSum ) + FmtInArr( rFmtArr, pFmt ); + else + { + nBox = nWishedSum; + pFmt = rBox.ClaimFrmFmt(); + SwFmtFrmSize aNewBox( ATT_VAR_SIZE, static_cast< SwTwips >(nBox), 0 ); + pFmt->LockModify(); + pFmt->SetFmtAttr( aNewBox ); + pFmt->UnlockModify(); + } + } + else { + ASSERT( false, "Rounding error" ); + } + nSum += nBox; + } +} + +void SwTable::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew ) +{ + // fange SSize Aenderungen ab, um die Lines/Boxen anzupassen + sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0 ; + const SwFmtFrmSize* pNewSize = 0, *pOldSize = 0; + + if( RES_ATTRSET_CHG == nWhich ) + { + if( SFX_ITEM_SET == ((SwAttrSetChg*)pNew)->GetChgSet()->GetItemState( + RES_FRM_SIZE, sal_False, (const SfxPoolItem**)&pNewSize )) + pOldSize = &((SwAttrSetChg*)pOld)->GetChgSet()->GetFrmSize(); + } + else if( RES_FRM_SIZE == nWhich ) + { + pOldSize = (const SwFmtFrmSize*)pOld; + pNewSize = (const SwFmtFrmSize*)pNew; + } + else + CheckRegistration( pOld, pNew ); + + if( pOldSize || pNewSize ) + { + if ( !IsModifyLocked() ) + { + ASSERT( pOldSize && pOldSize->Which() == RES_FRM_SIZE && + pNewSize && pNewSize->Which() == RES_FRM_SIZE, + "Kein Old oder New fuer FmtFrmSize-Modify der SwTable." ); + AdjustWidths( pOldSize->GetWidth(), pNewSize->GetWidth() ); + } + } +} + +void SwTable::AdjustWidths( const long nOld, const long nNew ) +{ + SvPtrarr aFmtArr( (sal_uInt8)aLines[0]->GetTabBoxes().Count(), 1 ); + ::lcl_ModifyLines( aLines, nOld, nNew, aFmtArr, true ); +} + +/************************************************************************* +|* +|* SwTable::GetTabCols() +|* +|*************************************************************************/ +void lcl_RefreshHidden( SwTabCols &rToFill, sal_uInt16 nPos ) +{ + for ( sal_uInt16 i = 0; i < rToFill.Count(); ++i ) + { + if ( Abs((long)(nPos - rToFill[i])) <= COLFUZZY ) + { + rToFill.SetHidden( i, sal_False ); + break; + } + } +} + +void lcl_SortedTabColInsert( SwTabCols &rToFill, const SwTableBox *pBox, + const SwFrmFmt *pTabFmt, const sal_Bool bHidden, + const FASTBOOL bRefreshHidden ) +{ + const long nWish = pTabFmt->GetFrmSize().GetWidth(); + const long nAct = rToFill.GetRight() - rToFill.GetLeft(); // +1 why? + + //Der Wert fuer die linke Kante der Box errechnet sich aus den + //Breiten der vorhergehenden Boxen. + sal_uInt16 nPos = 0; + sal_uInt16 nSum = 0; + sal_uInt16 nLeftMin = 0; + sal_uInt16 nRightMax = 0; + const SwTableBox *pCur = pBox; + const SwTableLine *pLine = pBox->GetUpper(); + while ( pLine ) + { const SwTableBoxes &rBoxes = pLine->GetTabBoxes(); + for ( sal_uInt16 i = 0; i < rBoxes.Count(); ++i ) + { + SwTwips nWidth = rBoxes[i]->GetFrmFmt()->GetFrmSize().GetWidth(); + nSum = (sal_uInt16)(nSum + nWidth); + sal_uInt64 nTmp = nSum; + nTmp *= nAct; + nTmp /= nWish; + if (rBoxes[i] != pCur) + { + if ( pLine == pBox->GetUpper() || 0 == nLeftMin ) + nLeftMin = (sal_uInt16)(nTmp - nPos); + nPos = (sal_uInt16)nTmp; + } + else + { + nSum = (sal_uInt16)(nSum - nWidth); + if ( 0 == nRightMax ) + nRightMax = (sal_uInt16)(nTmp - nPos); + break; + } + } + pCur = pLine->GetUpper(); + pLine = pCur ? pCur->GetUpper() : 0; + } + + sal_Bool bInsert = !bRefreshHidden; + for ( sal_uInt16 j = 0; bInsert && (j < rToFill.Count()); ++j ) + { + long nCmp = rToFill[j]; + if ( (nPos >= ((nCmp >= COLFUZZY) ? nCmp - COLFUZZY : nCmp)) && + (nPos <= (nCmp + COLFUZZY)) ) + { + bInsert = sal_False; //Hat ihn schon. + } + else if ( nPos < nCmp ) + { + bInsert = sal_False; + rToFill.Insert( nPos, bHidden, j ); + } + } + if ( bInsert ) + rToFill.Insert( nPos, bHidden, rToFill.Count() ); + else if ( bRefreshHidden ) + ::lcl_RefreshHidden( rToFill, nPos ); + + if ( bHidden && !bRefreshHidden ) + { + // calculate minimum/maximum values for the existing entries: + nLeftMin = nPos - nLeftMin; + nRightMax = nPos + nRightMax; + + // check if nPos is entry: + bool bFoundPos = false; + bool bFoundMax = false; + for ( sal_uInt16 j = 0; !(bFoundPos && bFoundMax ) && j < rToFill.Count(); ++j ) + { + SwTabColsEntry& rEntry = rToFill.GetEntry( j ); + long nCmp = rToFill[j]; + + if ( (nPos >= ((nCmp >= COLFUZZY) ? nCmp - COLFUZZY : nCmp)) && + (nPos <= (nCmp + COLFUZZY)) ) + { + // check if nLeftMin is > old minimum for entry nPos: + const long nOldMin = rEntry.nMin; + if ( nLeftMin > nOldMin ) + rEntry.nMin = nLeftMin; + // check if nRightMin is < old maximum for entry nPos: + const long nOldMax = rEntry.nMax; + if ( nRightMax < nOldMax ) + rEntry.nMax = nRightMax; + + bFoundPos = true; + } + else if ( (nRightMax >= ((nCmp >= COLFUZZY) ? nCmp - COLFUZZY : nCmp)) && + (nRightMax <= (nCmp + COLFUZZY)) ) + { + // check if nPos is > old minimum for entry nRightMax: + const long nOldMin = rEntry.nMin; + if ( nPos > nOldMin ) + rEntry.nMin = nPos; + + bFoundMax = true; + } + } + } +} + +void lcl_ProcessBoxGet( const SwTableBox *pBox, SwTabCols &rToFill, + const SwFrmFmt *pTabFmt, FASTBOOL bRefreshHidden ) +{ + if ( pBox->GetTabLines().Count() ) + { + const SwTableLines &rLines = pBox->GetTabLines(); + for ( sal_uInt16 i = 0; i < rLines.Count(); ++i ) + { const SwTableBoxes &rBoxes = rLines[i]->GetTabBoxes(); + for ( sal_uInt16 j = 0; j < rBoxes.Count(); ++j ) + ::lcl_ProcessBoxGet( rBoxes[j], rToFill, pTabFmt, bRefreshHidden); + } + } + else + ::lcl_SortedTabColInsert( rToFill, pBox, pTabFmt, sal_False, bRefreshHidden ); +} + +void lcl_ProcessLineGet( const SwTableLine *pLine, SwTabCols &rToFill, + const SwFrmFmt *pTabFmt ) +{ + for ( sal_uInt16 i = 0; i < pLine->GetTabBoxes().Count(); ++i ) + { + const SwTableBox *pBox = pLine->GetTabBoxes()[i]; + if ( pBox->GetSttNd() ) + ::lcl_SortedTabColInsert( rToFill, pBox, pTabFmt, sal_True, sal_False ); + else + for ( sal_uInt16 j = 0; j < pBox->GetTabLines().Count(); ++j ) + ::lcl_ProcessLineGet( pBox->GetTabLines()[j], rToFill, pTabFmt ); + } +} + +// MS: Sonst Absturz auf der DEC-Kiste +// +#if defined(ALPHA) && defined(WNT) +#pragma optimize("", off) +#endif + +void SwTable::GetTabCols( SwTabCols &rToFill, const SwTableBox *pStart, + sal_Bool bRefreshHidden, sal_Bool bCurRowOnly ) const +{ + //MA 30. Nov. 95: Opt: wenn bHidden gesetzt ist, wird nur das Hidden + //Array aktualisiert. + if ( bRefreshHidden ) + { + //Korrekturen entfernen + sal_uInt16 i; + for ( i = 0; i < rToFill.Count(); ++i ) + { + SwTabColsEntry& rEntry = rToFill.GetEntry( i ); + rEntry.nPos -= rToFill.GetLeft(); + rEntry.nMin -= rToFill.GetLeft(); + rEntry.nMax -= rToFill.GetLeft(); + } + + //Alle sind hidden, dann die sichtbaren eintragen. + for ( i = 0; i < rToFill.Count(); ++i ) + rToFill.SetHidden( i, sal_True ); + } + else + { + rToFill.Remove( 0, rToFill.Count() ); + } + + //Eingetragen werden: + //1. Alle Boxen unterhalb der dem Start uebergeordneten Line sowie + // deren untergeordnete Boxen falls vorhanden. + //2. Ausgehend von der Line die uebergeordnete Box sowie deren Nachbarn; + // nicht aber deren untergeordnete. + //3. Mit der der Boxenkette uebergeordneten Line wieder wie 2. bis einer + // Line keine Box (sondern die Table) uebergeordnet ist. + //Es werden nur diejenigen Boxen eingetragen, die keine weiteren Zeilen + //enhalten. Die eintragende Funktion sorgt dafuer, dass keine doppelten + //eingetragen werden. Um dies zu gewaehrleisten wird mit einer gewissen + //Unschaerfe gearbeitet (um Rundungsfehler auszuschalten). + //Es werden nur die linken Kanten der Boxen eingetragen. + //Am Schluss wird der Erste wieder ausgetragen denn er ist bereits vom + //Rand abgedeckt. + + //4. Nochmalige abscannen der Tabelle und eintragen _aller_ Boxen, + // jetzt aber als Hidden. + + const SwFrmFmt *pTabFmt = GetFrmFmt(); + + //1. + const SwTableBoxes &rBoxes = pStart->GetUpper()->GetTabBoxes(); + + sal_uInt16 i; + for ( i = 0; i < rBoxes.Count(); ++i ) + ::lcl_ProcessBoxGet( rBoxes[i], rToFill, pTabFmt, bRefreshHidden ); + + //2. und 3. + const SwTableLine *pLine = pStart->GetUpper()->GetUpper() ? + pStart->GetUpper()->GetUpper()->GetUpper() : 0; + while ( pLine ) + { + const SwTableBoxes &rBoxes2 = pLine->GetTabBoxes(); + for ( sal_uInt16 k = 0; k < rBoxes2.Count(); ++k ) + ::lcl_SortedTabColInsert( rToFill, rBoxes2[k], + pTabFmt, sal_False, bRefreshHidden ); + pLine = pLine->GetUpper() ? pLine->GetUpper()->GetUpper() : 0; + } + + if ( !bRefreshHidden ) + { + //4. + if ( !bCurRowOnly ) + { + for ( i = 0; i < aLines.Count(); ++i ) + ::lcl_ProcessLineGet( aLines[i], rToFill, pTabFmt ); + } + + rToFill.Remove( 0, 1 ); + } + + //Die Koordinaten sind jetzt relativ zum linken Rand der Tabelle - also + //relativ zum nLeft vom SwTabCols. Die Werte werden aber relativ zum + //linken Rand - also nLeftMin vom SwTabCols - erwartet. + //Alle Werte muessen also um nLeft erweitert werden. + for ( i = 0; i < rToFill.Count(); ++i ) + { + SwTabColsEntry& rEntry = rToFill.GetEntry( i ); + rEntry.nPos += rToFill.GetLeft(); + rEntry.nMin += rToFill.GetLeft(); + rEntry.nMax += rToFill.GetLeft(); + } +} + +#if defined(ALPHA) && defined(WNT) +#pragma optimize("", on) +#endif + +/************************************************************************* +|* +|* SwTable::SetTabCols() +|* +|*************************************************************************/ +//Struktur zur Parameteruebergabe +struct Parm +{ + const SwTabCols &rNew; + const SwTabCols &rOld; + long nNewWish, + nOldWish; + SvPtrarr aBoxArr; + SwShareBoxFmts aShareFmts; + + Parm( const SwTabCols &rN, const SwTabCols &rO ) : + rNew( rN ), rOld( rO ), aBoxArr( 10, 1 ) {} +}; +inline sal_Bool BoxInArr( SvPtrarr& rArr, SwTableBox* pBox ) +{ + sal_Bool bRet = USHRT_MAX != rArr.GetPos( (VoidPtr)pBox ); + if( !bRet ) + rArr.Insert( (VoidPtr)pBox, rArr.Count() ); + return bRet; +} + +void lcl_ProcessBoxSet( SwTableBox *pBox, Parm &rParm ); + +void lcl_ProcessLine( SwTableLine *pLine, Parm &rParm ) +{ + SwTableBoxes &rBoxes = pLine->GetTabBoxes(); + for ( int i = rBoxes.Count()-1; i >= 0; --i ) + ::lcl_ProcessBoxSet( rBoxes[ static_cast< sal_uInt16 >(i) ], rParm ); +} + +void lcl_ProcessBoxSet( SwTableBox *pBox, Parm &rParm ) +{ + if ( pBox->GetTabLines().Count() ) + { SwTableLines &rLines = pBox->GetTabLines(); + for ( int i = rLines.Count()-1; i >= 0; --i ) + lcl_ProcessLine( rLines[ static_cast< sal_uInt16 >(i) ], rParm ); + } + else + { + //Aktuelle Position (linke und rechte Kante berechnen) und im + //alten TabCols suchen. Im neuen TabCols die Werte vergleichen und + //wenn es Unterschiede gibt die Box entsprechend anpassen. + //Wenn an der veraenderten Kante kein Nachbar existiert werden auch + //alle uebergeordneten Boxen angepasst. + + const long nOldAct = rParm.rOld.GetRight() - + rParm.rOld.GetLeft(); // +1 why? + + //Der Wert fuer die linke Kante der Box errechnet sich aus den + //Breiten der vorhergehenden Boxen plus dem linken Rand + long nLeft = rParm.rOld.GetLeft(); + const SwTableBox *pCur = pBox; + const SwTableLine *pLine = pBox->GetUpper(); + + while ( pLine ) + { const SwTableBoxes &rBoxes = pLine->GetTabBoxes(); + for ( sal_uInt16 i = 0; (i < rBoxes.Count()) && (rBoxes[i] != pCur); ++i) + { + sal_uInt64 nWidth = rBoxes[i]->GetFrmFmt()-> + GetFrmSize().GetWidth(); + nWidth *= nOldAct; + nWidth /= rParm.nOldWish; + nLeft += (sal_uInt16)nWidth; + } + pCur = pLine->GetUpper(); + pLine = pCur ? pCur->GetUpper() : 0; + } + long nLeftDiff; + long nRightDiff = 0; + if ( nLeft != rParm.rOld.GetLeft() ) //Es gibt noch Boxen davor. + { + //Rechte Kante ist linke Kante plus Breite. + sal_uInt64 nWidth = pBox->GetFrmFmt()->GetFrmSize().GetWidth(); + nWidth *= nOldAct; + nWidth /= rParm.nOldWish; + long nRight = nLeft + (long)nWidth; + sal_uInt16 nLeftPos = USHRT_MAX, + nRightPos = USHRT_MAX; + for ( sal_uInt16 i = 0; i < rParm.rOld.Count(); ++i ) + { + if ( nLeft >= (rParm.rOld[i] - COLFUZZY) && + nLeft <= (rParm.rOld[i] + COLFUZZY) ) + nLeftPos = i; + else if ( nRight >= (rParm.rOld[i] - COLFUZZY) && + nRight <= (rParm.rOld[i] + COLFUZZY) ) + nRightPos = i; + } + nLeftDiff = nLeftPos != USHRT_MAX ? + (int)rParm.rOld[nLeftPos] - (int)rParm.rNew[nLeftPos] : 0; + nRightDiff= nRightPos!= USHRT_MAX ? + (int)rParm.rNew[nRightPos] - (int)rParm.rOld[nRightPos] : 0; + } + else //Die erste Box. + { + nLeftDiff = (long)rParm.rOld.GetLeft() - (long)rParm.rNew.GetLeft(); + if ( rParm.rOld.Count() ) + { + //Differnz zu der Kante berechnen, von der die erste Box + //beruehrt wird. + sal_uInt64 nWidth = pBox->GetFrmFmt()->GetFrmSize().GetWidth(); + nWidth *= nOldAct; + nWidth /= rParm.nOldWish; + long nTmp = (long)nWidth; + nTmp += rParm.rOld.GetLeft(); + sal_uInt16 nLeftPos = USHRT_MAX; + for ( sal_uInt16 i = 0; i < rParm.rOld.Count() && + nLeftPos == USHRT_MAX; ++i ) + { + if ( nTmp >= (rParm.rOld[i] - COLFUZZY) && + nTmp <= (rParm.rOld[i] + COLFUZZY) ) + nLeftPos = i; + } + if ( nLeftPos != USHRT_MAX ) + nRightDiff = (long)rParm.rNew[nLeftPos] - + (long)rParm.rOld[nLeftPos]; + } +//MA 11. Feb. 99: #61577# 0 sollte doch gerade richtig sein, weil die +//Kante doch schon in SetTabCols() korrigiert wurde. +// else +// nRightDiff = (long)rParm.rNew.GetRight() - +// (long)rParm.rOld.GetRight(); + } + + if( pBox->getRowSpan() == 1 ) + { + SwTableBoxes& rTblBoxes = pBox->GetUpper()->GetTabBoxes(); + sal_uInt16 nPos = rTblBoxes.C40_GETPOS( SwTableBox, pBox ); + if( nPos && rTblBoxes[ nPos - 1 ]->getRowSpan() != 1 ) + nLeftDiff = 0; + if( nPos + 1 < rTblBoxes.Count() && + rTblBoxes[ nPos + 1 ]->getRowSpan() != 1 ) + nRightDiff = 0; + } + else + nLeftDiff = nRightDiff = 0; + + if ( nLeftDiff || nRightDiff ) + { + //Die Differenz ist der tatsaechliche Differenzbetrag; die + //Attribute der Boxen um diesen Betrag anzupassen macht keinen + //Sinn wenn die Tabelle gestrecht ist. Der Differenzbetrag muss + //entsprechend umgerechnet werden. + long nTmp = rParm.rNew.GetRight() - rParm.rNew.GetLeft(); // +1 why? + nLeftDiff *= rParm.nNewWish; + nLeftDiff /= nTmp; + nRightDiff *= rParm.nNewWish; + nRightDiff /= nTmp; + long nDiff = nLeftDiff + nRightDiff; + + //Box und alle uebergeordneten um den Differenzbetrag anpassen. + while ( pBox ) + { + SwFmtFrmSize aFmtFrmSize( pBox->GetFrmFmt()->GetFrmSize() ); + aFmtFrmSize.SetWidth( aFmtFrmSize.GetWidth() + nDiff ); + if ( aFmtFrmSize.GetWidth() < 0 ) + aFmtFrmSize.SetWidth( -aFmtFrmSize.GetWidth() ); + rParm.aShareFmts.SetSize( *pBox, aFmtFrmSize ); + + // The outer cells of the last row are responsible to adjust a surrounding cell. + // Last line check: + if ( pBox->GetUpper()->GetUpper() && + pBox->GetUpper() != pBox->GetUpper()->GetUpper()->GetTabLines() + [pBox->GetUpper()->GetUpper()->GetTabLines().Count()-1]) + { + pBox = 0; + } + else + { + // Middle cell check: + if ( pBox != pBox->GetUpper()->GetTabBoxes()[0] ) + nDiff = nRightDiff; + + if ( pBox != pBox->GetUpper()->GetTabBoxes() + [pBox->GetUpper()->GetTabBoxes().Count()-1] ) + nDiff -= nRightDiff; + + pBox = nDiff ? pBox->GetUpper()->GetUpper() : 0; + } + } + } + } +} + +void lcl_ProcessBoxPtr( SwTableBox *pBox, SvPtrarr &rBoxArr, + sal_Bool bBefore ) +{ + if ( pBox->GetTabLines().Count() ) + { + const SwTableLines &rLines = pBox->GetTabLines(); + for ( sal_uInt16 i = 0; i < rLines.Count(); ++i ) + { + const SwTableBoxes &rBoxes = rLines[i]->GetTabBoxes(); + for ( sal_uInt16 j = 0; j < rBoxes.Count(); ++j ) + ::lcl_ProcessBoxPtr( rBoxes[j], rBoxArr, bBefore ); + } + } + else if ( bBefore ) + rBoxArr.Insert( (VoidPtr)pBox, 0 ); + else + rBoxArr.Insert( (VoidPtr)pBox, rBoxArr.Count() ); +} + +void lcl_AdjustBox( SwTableBox *pBox, const long nDiff, Parm &rParm ); + +void lcl_AdjustLines( SwTableLines &rLines, const long nDiff, Parm &rParm ) +{ + for ( sal_uInt16 i = 0; i < rLines.Count(); ++i ) + { + SwTableBox *pBox = rLines[i]->GetTabBoxes() + [rLines[i]->GetTabBoxes().Count()-1]; + lcl_AdjustBox( pBox, nDiff, rParm ); + } +} + +void lcl_AdjustBox( SwTableBox *pBox, const long nDiff, Parm &rParm ) +{ + if ( pBox->GetTabLines().Count() ) + ::lcl_AdjustLines( pBox->GetTabLines(), nDiff, rParm ); + + //Groesse der Box anpassen. + SwFmtFrmSize aFmtFrmSize( pBox->GetFrmFmt()->GetFrmSize() ); + aFmtFrmSize.SetWidth( aFmtFrmSize.GetWidth() + nDiff ); +//#30009# if ( aFmtFrmSize.GetWidth() < 0 ) +// aFmtFrmSize.SetWidth( -aFmtFrmSize.GetWidth() ); + + rParm.aShareFmts.SetSize( *pBox, aFmtFrmSize ); +} + +void SwTable::SetTabCols( const SwTabCols &rNew, const SwTabCols &rOld, + const SwTableBox *pStart, sal_Bool bCurRowOnly ) +{ + CHECK_TABLE( *this ) + + SetHTMLTableLayout( 0 ); // MIB 9.7.97: HTML-Layout loeschen + + // FME: Made rOld const. The caller is responsible for passing correct + // values of rOld. Therefore we do not have to call GetTabCols anymore: + //GetTabCols( rOld, pStart ); + + Parm aParm( rNew, rOld ); + + ASSERT( rOld.Count() == rNew.Count(), "Columnanzahl veraendert."); + + //Raender verarbeiten. Groesse der Tabelle und ein paar Boxen mussen + //angepasst werden. Bei der Groesseneinstellung darf allerdings das + //Modify nicht verarbeitet werden - dieses wuerde alle Boxen anpassen + //und das koennen wir ueberhaupt nicht gebrauchen. + SwFrmFmt *pFmt = GetFrmFmt(); + aParm.nOldWish = aParm.nNewWish = pFmt->GetFrmSize().GetWidth(); + if ( (rOld.GetLeft() != rNew.GetLeft()) || + (rOld.GetRight()!= rNew.GetRight()) ) + { + LockModify(); + { + SvxLRSpaceItem aLR( pFmt->GetLRSpace() ); + SvxShadowItem aSh( pFmt->GetShadow() ); + + SwTwips nShRight = aSh.CalcShadowSpace( SHADOW_RIGHT ); + SwTwips nShLeft = aSh.CalcShadowSpace( SHADOW_LEFT ); + + aLR.SetLeft ( rNew.GetLeft() - nShLeft ); + aLR.SetRight( rNew.GetRightMax() - rNew.GetRight() - nShRight ); + pFmt->SetFmtAttr( aLR ); + + //Die Ausrichtung der Tabelle muss entsprechend angepasst werden, + //das geschieht so, dass die Tabelle genauso stehenbleibt wie der + //Anwender sie gerade hingezuppelt hat. + SwFmtHoriOrient aOri( pFmt->GetHoriOrient() ); + if(text::HoriOrientation::NONE != aOri.GetHoriOrient()) + { + const sal_Bool bLeftDist = rNew.GetLeft() != nShLeft; + const sal_Bool bRightDist = rNew.GetRight() + nShRight != rNew.GetRightMax(); + if(!bLeftDist && !bRightDist) + aOri.SetHoriOrient( text::HoriOrientation::FULL ); + else if(!bRightDist && rNew.GetLeft() > nShLeft ) + aOri.SetHoriOrient( text::HoriOrientation::RIGHT ); + else if(!bLeftDist && rNew.GetRight() + nShRight < rNew.GetRightMax()) + aOri.SetHoriOrient( text::HoriOrientation::LEFT ); + else + aOri.SetHoriOrient( text::HoriOrientation::NONE ); + } + pFmt->SetFmtAttr( aOri ); + } + const long nAct = rOld.GetRight() - rOld.GetLeft(); // +1 why? + long nTabDiff = 0; + + if ( rOld.GetLeft() != rNew.GetLeft() ) + { + nTabDiff = rOld.GetLeft() - rNew.GetLeft(); + nTabDiff *= aParm.nOldWish; + nTabDiff /= nAct; + } + if ( rOld.GetRight() != rNew.GetRight() ) + { + long nDiff = rNew.GetRight() - rOld.GetRight(); + nDiff *= aParm.nOldWish; + nDiff /= nAct; + nTabDiff += nDiff; + if( !IsNewModel() ) + ::lcl_AdjustLines( GetTabLines(), nDiff, aParm ); + } + + //Groesse der Tabelle anpassen. Es muss beachtet werden, das die + //Tabelle gestrecht sein kann. + if ( nTabDiff ) + { + aParm.nNewWish += nTabDiff; + if ( aParm.nNewWish < 0 ) + aParm.nNewWish = USHRT_MAX; //Uuups! Eine Rolle rueckwaerts. + SwFmtFrmSize aSz( pFmt->GetFrmSize() ); + if ( aSz.GetWidth() != aParm.nNewWish ) + { + aSz.SetWidth( aParm.nNewWish ); + aSz.SetWidthPercent( 0 ); + pFmt->SetFmtAttr( aSz ); + } + } + UnlockModify(); + } + + if( IsNewModel() ) + NewSetTabCols( aParm, rNew, rOld, pStart, bCurRowOnly ); + else + { + if ( bCurRowOnly ) + { + //Um die aktuelle Zeile anzupassen muessen wir analog zu dem + //Verfahren zum fuellen der TabCols (siehe GetTabCols()) die + //Boxen der aktuellen Zeile abklappern. + //Leider muessen wir auch hier dafuer sorgen, dass die Boxen von + //hinten nach vorne bzw. von innen nach aussen veraendert werden. + //Der beste Weg hierzu scheint mir darin zu liegen die + //entsprechenden Boxen in einem PtrArray vorzumerken. + + const SwTableBoxes &rBoxes = pStart->GetUpper()->GetTabBoxes(); + for ( sal_uInt16 i = 0; i < rBoxes.Count(); ++i ) + ::lcl_ProcessBoxPtr( rBoxes[i], aParm.aBoxArr, sal_False ); + + const SwTableLine *pLine = pStart->GetUpper()->GetUpper() ? + pStart->GetUpper()->GetUpper()->GetUpper() : 0; + const SwTableBox *pExcl = pStart->GetUpper()->GetUpper(); + while ( pLine ) + { + const SwTableBoxes &rBoxes2 = pLine->GetTabBoxes(); + sal_Bool bBefore = sal_True; + for ( sal_uInt16 i = 0; i < rBoxes2.Count(); ++i ) + { + if ( rBoxes2[i] != pExcl ) + ::lcl_ProcessBoxPtr( rBoxes2[i], aParm.aBoxArr, bBefore ); + else + bBefore = sal_False; + } + pExcl = pLine->GetUpper(); + pLine = pLine->GetUpper() ? pLine->GetUpper()->GetUpper() : 0; + } + //Nachdem wir haufenweise Boxen (hoffentlich alle und in der richtigen + //Reihenfolge) eingetragen haben, brauchen diese nur noch rueckwaerts + //verarbeitet zu werden. + for ( int j = aParm.aBoxArr.Count()-1; j >= 0; --j ) + { + SwTableBox *pBox = (SwTableBox*)aParm.aBoxArr[ static_cast< sal_uInt16 >(j)]; + ::lcl_ProcessBoxSet( pBox, aParm ); + } + } + else + { //Die gesamte Tabelle anzupassen ist 'einfach'. + //Es werden alle Boxen, die keine Lines mehr enthalten angepasst. + //Diese Boxen passen alle uebergeordneten Boxen entsprechend mit an. + //Um uns nicht selbst hereinzulegen muss natuerlich rueckwaerst + //gearbeitet werden! + SwTableLines &rLines = GetTabLines(); + for ( int i = rLines.Count()-1; i >= 0; --i ) + ::lcl_ProcessLine( rLines[ static_cast< sal_uInt16 >(i) ], aParm ); + } + } + +#ifdef DBG_UTIL + { +// steht im tblrwcl.cxx +extern void _CheckBoxWidth( const SwTableLine&, SwTwips ); + // checke doch mal ob die Tabellen korrekte Breiten haben + SwTwips nSize = GetFrmFmt()->GetFrmSize().GetWidth(); + for( sal_uInt16 n = 0; n < aLines.Count(); ++n ) + _CheckBoxWidth( *aLines[ n ], nSize ); + } +#endif +} + +typedef std::pair<sal_uInt16, sal_uInt16> ColChange; +typedef std::list< ColChange > ChangeList; + +static void lcl_AdjustWidthsInLine( SwTableLine* pLine, ChangeList& rOldNew, + Parm& rParm, sal_uInt16 nColFuzzy ) +{ + ChangeList::iterator pCurr = rOldNew.begin(); + if( pCurr == rOldNew.end() ) + return; + sal_uInt16 nCount = pLine->GetTabBoxes().Count(); + sal_uInt16 i = 0; + SwTwips nBorder = 0; + SwTwips nRest = 0; + while( i < nCount ) + { + SwTableBox* pBox = pLine->GetTabBoxes()[i++]; + SwTwips nWidth = pBox->GetFrmFmt()->GetFrmSize().GetWidth(); + SwTwips nNewWidth = nWidth - nRest; + nRest = 0; + nBorder += nWidth; + if( pCurr != rOldNew.end() && nBorder + nColFuzzy >= pCurr->first ) + { + nBorder -= nColFuzzy; + while( pCurr != rOldNew.end() && nBorder > pCurr->first ) + ++pCurr; + if( pCurr != rOldNew.end() ) + { + nBorder += nColFuzzy; + if( nBorder + nColFuzzy >= pCurr->first ) + { + if( pCurr->second == pCurr->first ) + nRest = 0; + else + nRest = pCurr->second - nBorder; + nNewWidth += nRest; + ++pCurr; + } + } + } + if( nNewWidth != nWidth ) + { + if( nNewWidth < 0 ) + { + nRest += 1 - nNewWidth; + nNewWidth = 1; + } + SwFmtFrmSize aFmtFrmSize( pBox->GetFrmFmt()->GetFrmSize() ); + aFmtFrmSize.SetWidth( nNewWidth ); + rParm.aShareFmts.SetSize( *pBox, aFmtFrmSize ); + } + } +} + +static void lcl_CalcNewWidths( std::list<sal_uInt16> &rSpanPos, ChangeList& rChanges, + SwTableLine* pLine, long nWish, long nWidth, bool bTop ) +{ + if( !rChanges.size() ) + { + rSpanPos.clear(); + return; + } + if( !rSpanPos.size() ) + { + rChanges.clear(); + return; + } + std::list<sal_uInt16> aNewSpanPos; + ChangeList aNewChanges; + ChangeList::iterator pCurr = rChanges.begin(); + aNewChanges.push_back( *pCurr ); // Nullposition + std::list<sal_uInt16>::iterator pSpan = rSpanPos.begin(); + sal_uInt16 nCurr = 0; + sal_uInt16 nOrgSum = 0; + bool bRowSpan = false; + sal_uInt16 nRowSpanCount = 0; + sal_uInt16 nCount = pLine->GetTabBoxes().Count(); + for( sal_uInt16 nCurrBox = 0; nCurrBox < nCount; ++nCurrBox ) + { + SwTableBox* pBox = pLine->GetTabBoxes()[nCurrBox]; + SwTwips nCurrWidth = pBox->GetFrmFmt()->GetFrmSize().GetWidth(); + const long nRowSpan = pBox->getRowSpan(); + const bool bCurrRowSpan = bTop ? nRowSpan < 0 : + ( nRowSpan > 1 || nRowSpan < -1 ); + if( bRowSpan || bCurrRowSpan ) + aNewSpanPos.push_back( nRowSpanCount ); + bRowSpan = bCurrRowSpan; + nOrgSum = (sal_uInt16)(nOrgSum + nCurrWidth); + sal_uInt64 nSum = nOrgSum; + nSum *= nWidth; + nSum /= nWish; + nSum *= nWish; + nSum /= nWidth; + sal_uInt16 nPos = (sal_uInt16)nSum; + while( pCurr != rChanges.end() && pCurr->first < nPos ) + { +#ifdef DBG_UTIL + sal_uInt16 nTemp = pCurr->first; + nTemp = pCurr->second; +#endif + ++nCurr; + ++pCurr; + } + bool bNew = true; + if( pCurr != rChanges.end() && pCurr->first <= nPos && + pCurr->first != pCurr->second ) + { + while( pSpan != rSpanPos.end() && *pSpan < nCurr ) + ++pSpan; + if( pSpan != rSpanPos.end() && *pSpan == nCurr ) + { + aNewChanges.push_back( *pCurr ); + ++nRowSpanCount; + bNew = false; + } + } + if( bNew ) + { + ColChange aTmp( nPos, nPos ); + aNewChanges.push_back( aTmp ); + ++nRowSpanCount; + } + } + + pCurr = aNewChanges.begin(); + ChangeList::iterator pLast = pCurr; + ChangeList::iterator pLeftMove = pCurr; + while( pCurr != aNewChanges.end() ) + { + if( pLeftMove == pCurr ) + { + while( ++pLeftMove != aNewChanges.end() && pLeftMove->first <= pLeftMove->second ) + ; + } + if( pCurr->second == pCurr->first ) + { + if( pLeftMove != aNewChanges.end() && pCurr->second > pLeftMove->second ) + { + if( pLeftMove->first == pLast->first ) + pCurr->second = pLeftMove->second; + else + { + sal_uInt64 nTmp = pCurr->first - pLast->first; + nTmp *= pLeftMove->second - pLast->second; + nTmp /= pLeftMove->first - pLast->first; + nTmp += pLast->second; + pCurr->second = (sal_uInt16)nTmp; + } + } + pLast = pCurr; + ++pCurr; + } + else if( pCurr->second > pCurr->first ) + { + pLast = pCurr; + ++pCurr; + ChangeList::iterator pNext = pCurr; + while( pNext != pLeftMove && pNext->second == pNext->first && + pNext->second < pLast->second ) + ++pNext; + while( pCurr != pNext ) + { + if( pNext == aNewChanges.end() || pNext->first == pLast->first ) + pCurr->second = pLast->second; + else + { + sal_uInt64 nTmp = pCurr->first - pLast->first; + nTmp *= pNext->second - pLast->second; + nTmp /= pNext->first - pLast->first; + nTmp += pLast->second; + pCurr->second = (sal_uInt16)nTmp; + } + ++pCurr; + } + pLast = pCurr; + } + else + { + pLast = pCurr; + ++pCurr; + } + } + + rChanges.clear(); + ChangeList::iterator pCopy = aNewChanges.begin(); + while( pCopy != aNewChanges.end() ) + rChanges.push_back( *pCopy++ ); + rSpanPos.clear(); + std::list<sal_uInt16>::iterator pSpCopy = aNewSpanPos.begin(); + while( pSpCopy != aNewSpanPos.end() ) + rSpanPos.push_back( *pSpCopy++ ); +} + +void SwTable::NewSetTabCols( Parm &rParm, const SwTabCols &rNew, + const SwTabCols &rOld, const SwTableBox *pStart, sal_Bool bCurRowOnly ) +{ +#ifdef DBG_UTIL + static int nCallCount = 0; + ++nCallCount; +#endif + // First step: evaluate which lines have been moved/which widths changed + ChangeList aOldNew; + const long nNewWidth = rParm.rNew.GetRight() - rParm.rNew.GetLeft(); + const long nOldWidth = rParm.rOld.GetRight() - rParm.rOld.GetLeft(); + if( nNewWidth < 1 || nOldWidth < 1 ) + return; + for( sal_uInt16 i = 0; i <= rOld.Count(); ++i ) + { + sal_uInt64 nNewPos; + sal_uInt64 nOldPos; + if( i == rOld.Count() ) + { + nOldPos = rParm.rOld.GetRight() - rParm.rOld.GetLeft(); + nNewPos = rParm.rNew.GetRight() - rParm.rNew.GetLeft(); + } + else + { + nOldPos = rOld[i] - rParm.rOld.GetLeft(); + nNewPos = rNew[i] - rParm.rNew.GetLeft(); + } + nNewPos *= rParm.nNewWish; + nNewPos /= nNewWidth; + nOldPos *= rParm.nOldWish; + nOldPos /= nOldWidth; + if( nOldPos != nNewPos && nNewPos > 0 && nOldPos > 0 ) + { + ColChange aChg( (sal_uInt16)nOldPos, (sal_uInt16)nNewPos ); + aOldNew.push_back( aChg ); + } + } + // Finished first step + int nCount = aOldNew.size(); + if( !nCount ) + return; // no change, nothing to do + SwTableLines &rLines = GetTabLines(); + if( bCurRowOnly ) + { + const SwTableLine* pCurrLine = pStart->GetUpper(); + sal_uInt16 nCurr = rLines.C40_GETPOS( SwTableLine, pCurrLine ); + if( nCurr >= USHRT_MAX ) + return; + + ColChange aChg( 0, 0 ); + aOldNew.push_front( aChg ); + std::list<sal_uInt16> aRowSpanPos; + if( nCurr ) + { + ChangeList aCopy; + ChangeList::iterator pCop = aOldNew.begin(); + sal_uInt16 nPos = 0; + while( pCop != aOldNew.end() ) + { + aCopy.push_back( *pCop ); + ++pCop; + aRowSpanPos.push_back( nPos++ ); + } + lcl_CalcNewWidths( aRowSpanPos, aCopy, rLines[nCurr], + rParm.nOldWish, nOldWidth, true ); + bool bGoOn = aRowSpanPos.size() > 0; + sal_uInt16 j = nCurr; + while( bGoOn ) + { + lcl_CalcNewWidths( aRowSpanPos, aCopy, rLines[--j], + rParm.nOldWish, nOldWidth, true ); + lcl_AdjustWidthsInLine( rLines[j], aCopy, rParm, 0 ); + bGoOn = aRowSpanPos.size() > 0 && j > 0; + }; + aRowSpanPos.clear(); + } + if( nCurr+1 < rLines.Count() ) + { + ChangeList aCopy; + ChangeList::iterator pCop = aOldNew.begin(); + sal_uInt16 nPos = 0; + while( pCop != aOldNew.end() ) + { + aCopy.push_back( *pCop ); + ++pCop; + aRowSpanPos.push_back( nPos++ ); + } + lcl_CalcNewWidths( aRowSpanPos, aCopy, rLines[nCurr], + rParm.nOldWish, nOldWidth, false ); + bool bGoOn = aRowSpanPos.size() > 0; + sal_uInt16 j = nCurr; + while( bGoOn ) + { + lcl_CalcNewWidths( aRowSpanPos, aCopy, rLines[++j], + rParm.nOldWish, nOldWidth, false ); + lcl_AdjustWidthsInLine( rLines[j], aCopy, rParm, 0 ); + bGoOn = aRowSpanPos.size() > 0 && j+1 < rLines.Count(); + }; + } + ::lcl_AdjustWidthsInLine( rLines[nCurr], aOldNew, rParm, 1 ); + } + else for( sal_uInt16 i = 0; i < rLines.Count(); ++i ) + ::lcl_AdjustWidthsInLine( rLines[i], aOldNew, rParm, COLFUZZY ); + CHECK_TABLE( *this ) +} + + +/************************************************************************* +|* +|* const SwTableBox* SwTable::GetTblBox( const Strn?ng& rName ) const +|* gebe den Pointer auf die benannte Box zurueck. +|* +|*************************************************************************/ + +sal_Bool IsValidRowName( const String& rStr ) +{ + sal_Bool bIsValid = sal_True; + xub_StrLen nLen = rStr.Len(); + for (xub_StrLen i = 0; i < nLen && bIsValid; ++i) + { + const sal_Unicode cChar = rStr.GetChar(i); + if (cChar < '0' || cChar > '9') + bIsValid = sal_False; + } + return bIsValid; +} + +// --> OD 2007-08-03 #i80314# +// add 3rd parameter and its handling +sal_uInt16 SwTable::_GetBoxNum( String& rStr, sal_Bool bFirstPart, + const bool bPerformValidCheck ) +{ + sal_uInt16 nRet = 0; + xub_StrLen nPos = 0; + if( bFirstPart ) // sal_True == column; sal_False == row + { + // die 1. ist mit Buchstaben addressiert! + sal_Unicode cChar; + sal_Bool bFirst = sal_True; + while( 0 != ( cChar = rStr.GetChar( nPos )) && + ( (cChar >= 'A' && cChar <= 'Z') || + (cChar >= 'a' && cChar <= 'z') ) ) + { + if( (cChar -= 'A') >= 26 ) + cChar -= 'a' - '['; + if( bFirst ) + bFirst = sal_False; + else + ++nRet; + nRet = nRet * 52 + cChar; + ++nPos; + } + rStr.Erase( 0, nPos ); // Zeichen aus dem String loeschen + } + else if( STRING_NOTFOUND == ( nPos = rStr.Search( aDotStr ) )) + { + nRet = 0; + if ( !bPerformValidCheck || IsValidRowName( rStr ) ) + { + nRet = static_cast<sal_uInt16>(rStr.ToInt32()); + } + rStr.Erase(); + } + else + { + nRet = 0; + String aTxt( rStr.Copy( 0, nPos ) ); + if ( !bPerformValidCheck || IsValidRowName( aTxt ) ) + { + nRet = static_cast<sal_uInt16>(aTxt.ToInt32()); + } + rStr.Erase( 0, nPos+1 ); + } + return nRet; +} +// <-- + +// --> OD 2007-08-03 #i80314# +// add 2nd parameter and its handling +const SwTableBox* SwTable::GetTblBox( const String& rName, + const bool bPerformValidCheck ) const +{ + const SwTableBox* pBox = 0; + const SwTableLine* pLine; + const SwTableLines* pLines; + const SwTableBoxes* pBoxes; + + sal_uInt16 nLine, nBox; + String aNm( rName ); + while( aNm.Len() ) + { + nBox = SwTable::_GetBoxNum( aNm, 0 == pBox, bPerformValidCheck ); + // erste Box ? + if( !pBox ) + pLines = &GetTabLines(); + else + { + pLines = &pBox->GetTabLines(); + if( nBox ) + --nBox; + } + + nLine = SwTable::_GetBoxNum( aNm, sal_False, bPerformValidCheck ); + + // bestimme die Line + if( !nLine || nLine > pLines->Count() ) + return 0; + pLine = (*pLines)[ nLine-1 ]; + + // bestimme die Box + pBoxes = &pLine->GetTabBoxes(); + if( nBox >= pBoxes->Count() ) + return 0; + pBox = (*pBoxes)[ nBox ]; + } + + // abpruefen, ob die gefundene Box auch wirklich eine Inhaltstragende + // Box ist ?? + if( pBox && !pBox->GetSttNd() ) + { + ASSERT( sal_False, "Box ohne Inhalt, suche die naechste !!" ); + // "herunterfallen lassen" bis zur ersten Box + while( pBox->GetTabLines().Count() ) + pBox = pBox->GetTabLines()[0]->GetTabBoxes()[0]; + } + return pBox; +} + +SwTableBox* SwTable::GetTblBox( sal_uLong nSttIdx ) +{ + //MA: Zur Optimierung nicht immer umstaendlich das ganze SortArray abhuenern. + //OS: #102675# converting text to table tries und certain conditions + // to ask for a table box of a table that is not yet having a format + if(!GetFrmFmt()) + return 0; + SwTableBox* pRet = 0; + SwNodes& rNds = GetFrmFmt()->GetDoc()->GetNodes(); + sal_uLong nIndex = nSttIdx + 1; + SwCntntNode* pCNd = 0; + SwTableNode* pTblNd = 0; + + while ( nIndex < rNds.Count() ) + { + pTblNd = rNds[ nIndex ]->GetTableNode(); + if ( pTblNd ) + break; + + pCNd = rNds[ nIndex ]->GetCntntNode(); + if ( pCNd ) + break; + + ++nIndex; + } + + if ( pCNd || pTblNd ) + { + SwModify* pModify = pCNd; + // --> FME 2007-3-26 #144862# Better handling of table in table: + if ( pTblNd && pTblNd->GetTable().GetFrmFmt() ) + pModify = pTblNd->GetTable().GetFrmFmt(); + // <-- + + SwFrm* pFrm = SwIterator<SwFrm,SwModify>::FirstElement( *pModify ); + while ( pFrm && !pFrm->IsCellFrm() ) + pFrm = pFrm->GetUpper(); + if ( pFrm ) + pRet = (SwTableBox*)((SwCellFrm*)pFrm)->GetTabBox(); + } + + //Falls es das Layout noch nicht gibt oder sonstwie etwas schieft geht. + if ( !pRet ) + { + for( sal_uInt16 n = aSortCntBoxes.Count(); n; ) + if( aSortCntBoxes[ --n ]->GetSttIdx() == nSttIdx ) + return aSortCntBoxes[ n ]; + } + return pRet; +} + +sal_Bool SwTable::IsTblComplex() const +{ + // returnt sal_True wenn sich in der Tabelle Verschachtelungen befinden + // steht eine Box nicht in der obersten Line, da wurde gesplittet/ + // gemergt und die Struktur ist komplexer. + for( sal_uInt16 n = 0; n < aSortCntBoxes.Count(); ++n ) + if( aSortCntBoxes[ n ]->GetUpper()->GetUpper() ) + return sal_True; + return sal_False; +} + + + +/************************************************************************* +|* +|* SwTableLine::SwTableLine() +|* +|*************************************************************************/ +SwTableLine::SwTableLine( SwTableLineFmt *pFmt, sal_uInt16 nBoxes, + SwTableBox *pUp ) + : SwClient( pFmt ), + aBoxes( (sal_uInt8)nBoxes, 1 ), + pUpper( pUp ) +{ +} + +SwTableLine::~SwTableLine() +{ + // ist die TabelleLine der letzte Client im FrameFormat, kann dieses + // geloescht werden + SwModify* pMod = GetFrmFmt(); + pMod->Remove( this ); // austragen, + if( !pMod->GetDepends() ) + delete pMod; // und loeschen +} + +/************************************************************************* +|* +|* SwTableLine::ClaimFrmFmt(), ChgFrmFmt() +|* +|*************************************************************************/ +SwFrmFmt* SwTableLine::ClaimFrmFmt() +{ + // This method makes sure that this object is an exclusive SwTableLine client + // of an SwTableLineFmt object + // If other SwTableLine objects currently listen to the same SwTableLineFmt as + // this one, something needs to be done + SwTableLineFmt *pRet = (SwTableLineFmt*)GetFrmFmt(); + SwIterator<SwTableLine,SwFmt> aIter( *pRet ); + for( SwTableLine* pLast = aIter.First(); pLast; pLast = aIter.Next() ) + { + if ( pLast != this ) + { + // found another SwTableLine that is a client of the current Fmt + // create a new Fmt as a copy and use it for this object + SwTableLineFmt *pNewFmt = pRet->GetDoc()->MakeTableLineFmt(); + *pNewFmt = *pRet; + + // register SwRowFrms that know me as clients at the new Fmt + SwIterator<SwRowFrm,SwFmt> aFrmIter( *pRet ); + for( SwRowFrm* pFrm = aFrmIter.First(); pFrm; pFrm = aFrmIter.Next() ) + if( pFrm->GetTabLine() == this ) + pFrm->RegisterToFormat( *pNewFmt ); + + // register myself + pNewFmt->Add( this ); + pRet = pNewFmt; + break; + } + } + + return pRet; +} + +void SwTableLine::ChgFrmFmt( SwTableLineFmt *pNewFmt ) +{ + SwFrmFmt *pOld = GetFrmFmt(); + SwIterator<SwRowFrm,SwFmt> aIter( *pOld ); + + //Erstmal die Frms ummelden. + for( SwRowFrm* pRow = aIter.First(); pRow; pRow = aIter.Next() ) + { + if( pRow->GetTabLine() == this ) + { + pRow->RegisterToFormat( *pNewFmt ); + + pRow->InvalidateSize(); + pRow->_InvalidatePrt(); + pRow->SetCompletePaint(); + pRow->ReinitializeFrmSizeAttrFlags(); + + // --> FME 2004-10-27 #i35063# + // consider 'split row allowed' attribute + SwTabFrm* pTab = pRow->FindTabFrm(); + bool bInFollowFlowRow = false; + const bool bInFirstNonHeadlineRow = pTab->IsFollow() && + pRow == pTab->GetFirstNonHeadlineRow(); + if ( bInFirstNonHeadlineRow || + !pRow->GetNext() || + 0 != ( bInFollowFlowRow = pRow->IsInFollowFlowRow() ) || + 0 != pRow->IsInSplitTableRow() ) + { + if ( bInFirstNonHeadlineRow || bInFollowFlowRow ) + pTab = pTab->FindMaster(); + + pTab->SetRemoveFollowFlowLinePending( sal_True ); + pTab->InvalidatePos(); + } + // <-- + } + } + + //Jetzt noch mich selbst ummelden. + pNewFmt->Add( this ); + + if ( !pOld->GetDepends() ) + delete pOld; +} + +SwTwips SwTableLine::GetTableLineHeight( bool& bLayoutAvailable ) const +{ + SwTwips nRet = 0; + bLayoutAvailable = false; + SwIterator<SwRowFrm,SwFmt> aIter( *GetFrmFmt() ); + // A row could appear several times in headers/footers so only one chain of master/follow tables + // will be accepted... + const SwTabFrm* pChain = NULL; // My chain + for( SwRowFrm* pLast = aIter.First(); pLast; pLast = aIter.Next() ) + { + if( pLast->GetTabLine() == this ) + { + const SwTabFrm* pTab = pLast->FindTabFrm(); + bLayoutAvailable = ( pTab && pTab->IsVertical() ) ? + ( 0 < pTab->Frm().Height() ) : + ( 0 < pTab->Frm().Width() ); + + // The first one defines the chain, if a chain is defined, only members of the chain + // will be added. + if( !pChain || pChain->IsAnFollow( pTab ) || pTab->IsAnFollow( pChain ) ) + { + pChain = pTab; // defines my chain (even it is already) + if( pTab->IsVertical() ) + nRet += pLast->Frm().Width(); + else + nRet += pLast->Frm().Height(); + // Optimization, if there are no master/follows in my chain, nothing more to add + if( !pTab->HasFollow() && !pTab->IsFollow() ) + break; + // This is not an optimization, this is necessary to avoid double additions of + // repeating rows + if( pTab->IsInHeadline(*pLast) ) + break; + } + } + } + return nRet; +} + +/************************************************************************* +|* +|* SwTableBox::SwTableBox() +|* +|*************************************************************************/ +SwTableBox::SwTableBox( SwTableBoxFmt* pFmt, sal_uInt16 nLines, SwTableLine *pUp ) + : SwClient( 0 ), + aLines( (sal_uInt8)nLines, 1 ), + pSttNd( 0 ), + pUpper( pUp ), + pImpl( 0 ) +{ + CheckBoxFmt( pFmt )->Add( this ); +} + +SwTableBox::SwTableBox( SwTableBoxFmt* pFmt, const SwNodeIndex &rIdx, + SwTableLine *pUp ) + : SwClient( 0 ), + aLines( 0, 0 ), + pUpper( pUp ), + pImpl( 0 ) +{ + CheckBoxFmt( pFmt )->Add( this ); + + pSttNd = rIdx.GetNode().GetStartNode(); + + // an der Table eintragen + const SwTableNode* pTblNd = pSttNd->FindTableNode(); + ASSERT( pTblNd, "in welcher Tabelle steht denn die Box?" ); + SwTableSortBoxes& rSrtArr = (SwTableSortBoxes&)pTblNd->GetTable(). + GetTabSortBoxes(); + SwTableBox* p = this; // error: &this + rSrtArr.Insert( p ); // eintragen +} + +SwTableBox::SwTableBox( SwTableBoxFmt* pFmt, const SwStartNode& rSttNd, SwTableLine *pUp ) : + SwClient( 0 ), + aLines( 0, 0 ), + pSttNd( &rSttNd ), + pUpper( pUp ), + pImpl( 0 ) +{ + CheckBoxFmt( pFmt )->Add( this ); + + // an der Table eintragen + const SwTableNode* pTblNd = pSttNd->FindTableNode(); + ASSERT( pTblNd, "in welcher Tabelle steht denn die Box?" ); + SwTableSortBoxes& rSrtArr = (SwTableSortBoxes&)pTblNd->GetTable(). + GetTabSortBoxes(); + SwTableBox* p = this; // error: &this + rSrtArr.Insert( p ); // eintragen +} + +SwTableBox::~SwTableBox() +{ + // Inhaltstragende Box ? + if( !GetFrmFmt()->GetDoc()->IsInDtor() && pSttNd ) + { + // an der Table austragen + const SwTableNode* pTblNd = pSttNd->FindTableNode(); + ASSERT( pTblNd, "in welcher Tabelle steht denn die Box?" ); + SwTableSortBoxes& rSrtArr = (SwTableSortBoxes&)pTblNd->GetTable(). + GetTabSortBoxes(); + SwTableBox *p = this; // error: &this + rSrtArr.Remove( p ); // austragen + } + + // ist die TabelleBox der letzte Client im FrameFormat, kann dieses + // geloescht werden + SwModify* pMod = GetFrmFmt(); + pMod->Remove( this ); // austragen, + if( !pMod->GetDepends() ) + delete pMod; // und loeschen + + delete pImpl; +} + +SwTableBoxFmt* SwTableBox::CheckBoxFmt( SwTableBoxFmt* pFmt ) +{ + // sollte das Format eine Formel oder einen Value tragen, dann muss die + // Box alleine am Format haengen. Ggfs. muss ein neues angelegt werden. + if( SFX_ITEM_SET == pFmt->GetItemState( RES_BOXATR_VALUE, sal_False ) || + SFX_ITEM_SET == pFmt->GetItemState( RES_BOXATR_FORMULA, sal_False ) ) + { + SwTableBox* pOther = SwIterator<SwTableBox,SwFmt>::FirstElement( *pFmt ); + if( pOther ) + { + SwTableBoxFmt* pNewFmt = pFmt->GetDoc()->MakeTableBoxFmt(); + pNewFmt->LockModify(); + *pNewFmt = *pFmt; + + // Values und Formeln entfernen + pNewFmt->ResetFmtAttr( RES_BOXATR_FORMULA, RES_BOXATR_VALUE ); + pNewFmt->UnlockModify(); + + pFmt = pNewFmt; + } + } + return pFmt; +} + +/************************************************************************* +|* +|* SwTableBox::ClaimFrmFmt(), ChgFrmFmt() +|* +|*************************************************************************/ +SwFrmFmt* SwTableBox::ClaimFrmFmt() +{ + // This method makes sure that this object is an exclusive SwTableBox client + // of an SwTableBoxFmt object + // If other SwTableBox objects currently listen to the same SwTableBoxFmt as + // this one, something needs to be done + SwTableBoxFmt *pRet = (SwTableBoxFmt*)GetFrmFmt(); + SwIterator<SwTableBox,SwFmt> aIter( *pRet ); + for( SwTableBox* pLast = aIter.First(); pLast; pLast = aIter.Next() ) + { + if ( pLast != this ) + { + // Found another SwTableBox object + // create a new Fmt as a copy and assign me to it + // don't copy values and formulas + SwTableBoxFmt* pNewFmt = pRet->GetDoc()->MakeTableBoxFmt(); + pNewFmt->LockModify(); + *pNewFmt = *pRet; + pNewFmt->ResetFmtAttr( RES_BOXATR_FORMULA, RES_BOXATR_VALUE ); + pNewFmt->UnlockModify(); + + // re-register SwCellFrm objects that know me + SwIterator<SwCellFrm,SwFmt> aFrmIter( *pRet ); + for( SwCellFrm* pCell = aFrmIter.First(); pCell; pCell = aFrmIter.Next() ) + if( pCell->GetTabBox() == this ) + pCell->RegisterToFormat( *pNewFmt ); + + // re-register myself + pNewFmt->Add( this ); + pRet = pNewFmt; + break; + } + } + return pRet; +} + +void SwTableBox::ChgFrmFmt( SwTableBoxFmt* pNewFmt ) +{ + SwFrmFmt *pOld = GetFrmFmt(); + SwIterator<SwCellFrm,SwFmt> aIter( *pOld ); + + //Erstmal die Frms ummelden. + for( SwCellFrm* pCell = aIter.First(); pCell; pCell = aIter.Next() ) + { + if( pCell->GetTabBox() == this ) + { + pCell->RegisterToFormat( *pNewFmt ); + pCell->InvalidateSize(); + pCell->_InvalidatePrt(); + pCell->SetCompletePaint(); + pCell->SetDerivedVert( sal_False ); + pCell->CheckDirChange(); + + // --> FME 2005-04-15 #i47489# + // make sure that the row will be formatted, in order + // to have the correct Get(Top|Bottom)MarginForLowers values + // set at the row. + const SwTabFrm* pTab = pCell->FindTabFrm(); + if ( pTab && pTab->IsCollapsingBorders() ) + { + SwFrm* pRow = pCell->GetUpper(); + pRow->_InvalidateSize(); + pRow->_InvalidatePrt(); + } + // <-- + } + } + + //Jetzt noch mich selbst ummelden. + pNewFmt->Add( this ); + + if( !pOld->GetDepends() ) + delete pOld; +} + +/************************************************************************* +|* +|* String SwTableBox::GetName() const +|* gebe den Namen dieser Box zurueck. Dieser wird dynamisch bestimmt +|* und ergibt sich aus der Position in den Lines/Boxen/Tabelle +|* +|*************************************************************************/ +void lcl_GetTblBoxColStr( sal_uInt16 nCol, String& rNm ) +{ + const sal_uInt16 coDiff = 52; // 'A'-'Z' 'a' - 'z' + sal_uInt16 nCalc; + + do { + nCalc = nCol % coDiff; + if( nCalc >= 26 ) + rNm.Insert( sal_Unicode('a' - 26 + nCalc ), 0 ); + else + rNm.Insert( sal_Unicode('A' + nCalc ), 0 ); + + if( 0 == (nCol = nCol - nCalc) ) + break; + nCol /= coDiff; + --nCol; + } while( 1 ); +} + +String SwTableBox::GetName() const +{ + if( !pSttNd ) // keine Content Box ?? + { + // die naechste erste Box suchen ?? + return aEmptyStr; + } + + const SwTable& rTbl = pSttNd->FindTableNode()->GetTable(); + sal_uInt16 nPos; + String sNm, sTmp; + const SwTableBox* pBox = this; + do { + const SwTableBoxes* pBoxes = &pBox->GetUpper()->GetTabBoxes(); + const SwTableLine* pLine = pBox->GetUpper(); + // auf oberstere Ebene ? + const SwTableLines* pLines = pLine->GetUpper() + ? &pLine->GetUpper()->GetTabLines() : &rTbl.GetTabLines(); + + sTmp = String::CreateFromInt32( nPos = pLines->GetPos( pLine ) + 1 ); + if( sNm.Len() ) + sNm.Insert( aDotStr, 0 ).Insert( sTmp, 0 ); + else + sNm = sTmp; + + sTmp = String::CreateFromInt32(( nPos = pBoxes->GetPos( pBox )) + 1 ); + if( 0 != ( pBox = pLine->GetUpper()) ) + sNm.Insert( aDotStr, 0 ).Insert( sTmp, 0 ); + else + ::lcl_GetTblBoxColStr( nPos, sNm ); + + } while( pBox ); + return sNm; +} + +sal_Bool SwTableBox::IsInHeadline( const SwTable* pTbl ) const +{ + if( !GetUpper() ) // sollte nur beim Merge vorkommen. + return sal_False; + + if( !pTbl ) + pTbl = &pSttNd->FindTableNode()->GetTable(); + + const SwTableLine* pLine = GetUpper(); + while( pLine->GetUpper() ) + pLine = pLine->GetUpper()->GetUpper(); + + // Headerline? + return pTbl->GetTabLines()[ 0 ] == pLine; +} + +#ifdef DBG_UTIL + +sal_uLong SwTableBox::GetSttIdx() const +{ + return pSttNd ? pSttNd->GetIndex() : 0; +} +#endif + + // erfrage vom Client Informationen +sal_Bool SwTable::GetInfo( SfxPoolItem& rInfo ) const +{ + switch( rInfo.Which() ) + { + case RES_AUTOFMT_DOCNODE: + { + const SwTableNode* pTblNode = GetTableNode(); + if( pTblNode && &pTblNode->GetNodes() == ((SwAutoFmtGetDocNode&)rInfo).pNodes ) + { + if ( aSortCntBoxes.Count() ) + { + SwNodeIndex aIdx( *aSortCntBoxes[ 0 ]->GetSttNd() ); + ((SwAutoFmtGetDocNode&)rInfo).pCntntNode = + GetFrmFmt()->GetDoc()->GetNodes().GoNext( &aIdx ); + } + return sal_False; + } + break; + } + case RES_FINDNEARESTNODE: + if( GetFrmFmt() && ((SwFmtPageDesc&)GetFrmFmt()->GetFmtAttr( + RES_PAGEDESC )).GetPageDesc() && + aSortCntBoxes.Count() && + aSortCntBoxes[ 0 ]->GetSttNd()->GetNodes().IsDocNodes() ) + ((SwFindNearestNode&)rInfo).CheckNode( * + aSortCntBoxes[ 0 ]->GetSttNd()->FindTableNode() ); + break; + + case RES_CONTENT_VISIBLE: + { + ((SwPtrMsgPoolItem&)rInfo).pObject = SwIterator<SwFrm,SwFmt>::FirstElement( *GetFrmFmt() ); + } + return sal_False; + } + return sal_True; +} + +SwTable * SwTable::FindTable( SwFrmFmt const*const pFmt ) +{ + return (pFmt) + ? SwIterator<SwTable,SwFmt>::FirstElement(*pFmt) + : 0; +} + +SwTableNode* SwTable::GetTableNode() const +{ + return GetTabSortBoxes().Count() ? + (SwTableNode*)GetTabSortBoxes()[ 0 ]->GetSttNd()->FindTableNode() : + pTableNode; +} + +void SwTable::SetRefObject( SwServerObject* pObj ) +{ + if( refObj.Is() ) + refObj->Closed(); + + refObj = pObj; +} + + +void SwTable::SetHTMLTableLayout( SwHTMLTableLayout *p ) +{ + delete pHTMLLayout; + pHTMLLayout = p; +} + +void ChgTextToNum( SwTableBox& rBox, const String& rTxt, const Color* pCol, + sal_Bool bChgAlign ) +{ + sal_uLong nNdPos = rBox.IsValidNumTxtNd( sal_True ); + ChgTextToNum( rBox,rTxt,pCol,bChgAlign,nNdPos); +} +void ChgTextToNum( SwTableBox& rBox, const String& rTxt, const Color* pCol, + sal_Bool bChgAlign,sal_uLong nNdPos ) +{ + + if( ULONG_MAX != nNdPos ) + { + SwDoc* pDoc = rBox.GetFrmFmt()->GetDoc(); + SwTxtNode* pTNd = pDoc->GetNodes()[ nNdPos ]->GetTxtNode(); + const SfxPoolItem* pItem; + + // Ausrichtung umsetzen + if( bChgAlign ) + { + pItem = &pTNd->SwCntntNode::GetAttr( RES_PARATR_ADJUST ); + SvxAdjust eAdjust = ((SvxAdjustItem*)pItem)->GetAdjust(); + if( SVX_ADJUST_LEFT == eAdjust || SVX_ADJUST_BLOCK == eAdjust ) + { + SvxAdjustItem aAdjust( *(SvxAdjustItem*)pItem ); + aAdjust.SetAdjust( SVX_ADJUST_RIGHT ); + pTNd->SetAttr( aAdjust ); + } + } + + // Farbe umsetzen oder "Benutzer Farbe" sichern + if( !pTNd->GetpSwAttrSet() || SFX_ITEM_SET != pTNd->GetpSwAttrSet()-> + GetItemState( RES_CHRATR_COLOR, sal_False, &pItem )) + pItem = 0; + + const Color* pOldNumFmtColor = rBox.GetSaveNumFmtColor(); + const Color* pNewUserColor = pItem ? &((SvxColorItem*)pItem)->GetValue() : 0; + + if( ( pNewUserColor && pOldNumFmtColor && + *pNewUserColor == *pOldNumFmtColor ) || + ( !pNewUserColor && !pOldNumFmtColor )) + { + // User Color nicht veraendern aktuellen Werte setzen + // ggfs. die alte NumFmtColor loeschen + if( pCol ) + // ggfs. die Farbe setzen + pTNd->SetAttr( SvxColorItem( *pCol, RES_CHRATR_COLOR )); + else if( pItem ) + { + pNewUserColor = rBox.GetSaveUserColor(); + if( pNewUserColor ) + pTNd->SetAttr( SvxColorItem( *pNewUserColor, RES_CHRATR_COLOR )); + else + pTNd->ResetAttr( RES_CHRATR_COLOR ); + } + } + else + { + // User Color merken, ggfs. die NumFormat Color setzen, aber + // nie die Farbe zurueck setzen + rBox.SetSaveUserColor( pNewUserColor ); + + if( pCol ) + // ggfs. die Farbe setzen + pTNd->SetAttr( SvxColorItem( *pCol, RES_CHRATR_COLOR )); + + } + rBox.SetSaveNumFmtColor( pCol ); + + if( pTNd->GetTxt() != rTxt ) + { + // Text austauschen + //JP 15.09.98: Bug 55741 - Tabs beibehalten (vorne und hinten!) + const String& rOrig = pTNd->GetTxt(); + xub_StrLen n; + + for( n = 0; n < rOrig.Len() && '\x9' == rOrig.GetChar( n ); ++n ) + ; + for( ; n < rOrig.Len() && '\x01' == rOrig.GetChar( n ); ++n ) + ; + SwIndex aIdx( pTNd, n ); + for( n = rOrig.Len(); n && '\x9' == rOrig.GetChar( --n ); ) + ; + n -= aIdx.GetIndex() - 1; + + //JP 06.04.99: Bug 64321 - DontExpand-Flags vorm Austauschen + // zuruecksetzen, damit sie wieder aufgespannt werden + { + SwIndex aResetIdx( aIdx, n ); + pTNd->DontExpandFmt( aResetIdx, sal_False, sal_False ); + } + + if( !pDoc->IsIgnoreRedline() && pDoc->GetRedlineTbl().Count() ) + { + SwPaM aTemp(*pTNd, 0, *pTNd, rOrig.Len()); + pDoc->DeleteRedline(aTemp, true, USHRT_MAX); + } + + pTNd->EraseText( aIdx, n, + IDocumentContentOperations::INS_EMPTYEXPAND ); + pTNd->InsertText( rTxt, aIdx, + IDocumentContentOperations::INS_EMPTYEXPAND ); + + if( pDoc->IsRedlineOn() ) + { + SwPaM aTemp(*pTNd, 0, *pTNd, rTxt.Len()); + pDoc->AppendRedline(new SwRedline(nsRedlineType_t::REDLINE_INSERT, aTemp), true); + } + } + + // vertikale Ausrichtung umsetzen + if( bChgAlign && + ( SFX_ITEM_SET != rBox.GetFrmFmt()->GetItemState( + RES_VERT_ORIENT, sal_True, &pItem ) || + text::VertOrientation::TOP == ((SwFmtVertOrient*)pItem)->GetVertOrient() )) + { + rBox.GetFrmFmt()->SetFmtAttr( SwFmtVertOrient( 0, text::VertOrientation::BOTTOM )); + } + } +} + +void ChgNumToText( SwTableBox& rBox, sal_uLong nFmt ) +{ + sal_uLong nNdPos = rBox.IsValidNumTxtNd( sal_False ); + if( ULONG_MAX != nNdPos ) + { + SwDoc* pDoc = rBox.GetFrmFmt()->GetDoc(); + SwTxtNode* pTNd = pDoc->GetNodes()[ nNdPos ]->GetTxtNode(); + sal_Bool bChgAlign = pDoc->IsInsTblAlignNum(); + const SfxPoolItem* pItem; + + Color* pCol = 0; + if( NUMBERFORMAT_TEXT != nFmt ) + { + // speziellen Textformat: + String sTmp, sTxt( pTNd->GetTxt() ); + pDoc->GetNumberFormatter()->GetOutputString( sTxt, nFmt, sTmp, &pCol ); + if( sTxt != sTmp ) + { + // Text austauschen + SwIndex aIdx( pTNd, sTxt.Len() ); + //JP 06.04.99: Bug 64321 - DontExpand-Flags vorm Austauschen + // zuruecksetzen, damit sie wieder aufgespannt werden + pTNd->DontExpandFmt( aIdx, sal_False, sal_False ); + aIdx = 0; + pTNd->EraseText( aIdx, STRING_LEN, + IDocumentContentOperations::INS_EMPTYEXPAND ); + pTNd->InsertText( sTmp, aIdx, + IDocumentContentOperations::INS_EMPTYEXPAND ); + } + } + + const SfxItemSet* pAttrSet = pTNd->GetpSwAttrSet(); + + // Ausrichtung umsetzen + if( bChgAlign && pAttrSet && SFX_ITEM_SET == pAttrSet->GetItemState( + RES_PARATR_ADJUST, sal_False, &pItem ) && + SVX_ADJUST_RIGHT == ((SvxAdjustItem*)pItem)->GetAdjust() ) + { + pTNd->SetAttr( SvxAdjustItem( SVX_ADJUST_LEFT, RES_PARATR_ADJUST ) ); + } + + // Farbe umsetzen oder "Benutzer Farbe" sichern + if( !pAttrSet || SFX_ITEM_SET != pAttrSet-> + GetItemState( RES_CHRATR_COLOR, sal_False, &pItem )) + pItem = 0; + + const Color* pOldNumFmtColor = rBox.GetSaveNumFmtColor(); + const Color* pNewUserColor = pItem ? &((SvxColorItem*)pItem)->GetValue() : 0; + + if( ( pNewUserColor && pOldNumFmtColor && + *pNewUserColor == *pOldNumFmtColor ) || + ( !pNewUserColor && !pOldNumFmtColor )) + { + // User Color nicht veraendern aktuellen Werte setzen + // ggfs. die alte NumFmtColor loeschen + if( pCol ) + // ggfs. die Farbe setzen + pTNd->SetAttr( SvxColorItem( *pCol, RES_CHRATR_COLOR )); + else if( pItem ) + { + pNewUserColor = rBox.GetSaveUserColor(); + if( pNewUserColor ) + pTNd->SetAttr( SvxColorItem( *pNewUserColor, RES_CHRATR_COLOR )); + else + pTNd->ResetAttr( RES_CHRATR_COLOR ); + } + } + else + { + // User Color merken, ggfs. die NumFormat Color setzen, aber + // nie die Farbe zurueck setzen + rBox.SetSaveUserColor( pNewUserColor ); + + if( pCol ) + // ggfs. die Farbe setzen + pTNd->SetAttr( SvxColorItem( *pCol, RES_CHRATR_COLOR )); + + } + rBox.SetSaveNumFmtColor( pCol ); + + + // vertikale Ausrichtung umsetzen + if( bChgAlign && + SFX_ITEM_SET == rBox.GetFrmFmt()->GetItemState( + RES_VERT_ORIENT, sal_False, &pItem ) && + text::VertOrientation::BOTTOM == ((SwFmtVertOrient*)pItem)->GetVertOrient() ) + { + rBox.GetFrmFmt()->SetFmtAttr( SwFmtVertOrient( 0, text::VertOrientation::TOP )); + } + } +} + +// zum Erkennen von Veraenderungen (haupts. TableBoxAttribute) +void SwTableBoxFmt::Modify( const SfxPoolItem* pOld, const SfxPoolItem* pNew ) +{ + if( !IsModifyLocked() && !IsInDocDTOR() ) + { + const SwTblBoxNumFormat *pNewFmt = 0; + const SwTblBoxFormula *pNewFml = 0; + const SwTblBoxValue *pNewVal = 0; + double aOldValue = 0; + sal_uLong nOldFmt = NUMBERFORMAT_TEXT; + + switch( pNew ? pNew->Which() : 0 ) + { + case RES_ATTRSET_CHG: + { + const SfxItemSet& rSet = *((SwAttrSetChg*)pNew)->GetChgSet(); + if( SFX_ITEM_SET == rSet.GetItemState( RES_BOXATR_FORMAT, + sal_False, (const SfxPoolItem**)&pNewFmt ) ) + nOldFmt = ((SwTblBoxNumFormat&)((SwAttrSetChg*)pOld)-> + GetChgSet()->Get( RES_BOXATR_FORMAT )).GetValue(); + rSet.GetItemState( RES_BOXATR_FORMULA, sal_False, + (const SfxPoolItem**)&pNewFml ); + if( SFX_ITEM_SET == rSet.GetItemState( RES_BOXATR_VALUE, + sal_False, (const SfxPoolItem**)&pNewVal ) ) + aOldValue = ((SwTblBoxValue&)((SwAttrSetChg*)pOld)-> + GetChgSet()->Get( RES_BOXATR_VALUE )).GetValue(); + } + break; + + case RES_BOXATR_FORMAT: + pNewFmt = (SwTblBoxNumFormat*)pNew; + nOldFmt = ((SwTblBoxNumFormat*)pOld)->GetValue(); + break; + case RES_BOXATR_FORMULA: + pNewFml = (SwTblBoxFormula*)pNew; + break; + case RES_BOXATR_VALUE: + pNewVal = (SwTblBoxValue*)pNew; + aOldValue = ((SwTblBoxValue*)pOld)->GetValue(); + break; + } + + // es hat sich etwas getan und im Set ist noch irgendein BoxAttribut + // vorhanden! + if( pNewFmt || pNewFml || pNewVal ) + { + GetDoc()->SetFieldsDirty(true, NULL, 0); + + if( SFX_ITEM_SET == GetItemState( RES_BOXATR_FORMAT, sal_False ) || + SFX_ITEM_SET == GetItemState( RES_BOXATR_VALUE, sal_False ) || + SFX_ITEM_SET == GetItemState( RES_BOXATR_FORMULA, sal_False ) ) + { + // die Box holen + SwIterator<SwTableBox,SwFmt> aIter( *this ); + SwTableBox* pBox = aIter.First(); + if( pBox ) + { + ASSERT( !aIter.Next(), "keine Box oder mehrere am Format" ); + + sal_uLong nNewFmt; + if( pNewFmt ) + { + nNewFmt = pNewFmt->GetValue(); + // neu Formatieren + // ist es neuer oder wurde der akt. entfernt? + if( SFX_ITEM_SET != GetItemState( RES_BOXATR_VALUE, sal_False )) + pNewFmt = 0; + } + else + { + // das akt. Item besorgen + GetItemState( RES_BOXATR_FORMAT, sal_False, + (const SfxPoolItem**)&pNewFmt ); + nOldFmt = GetTblBoxNumFmt().GetValue(); + nNewFmt = pNewFmt ? pNewFmt->GetValue() : nOldFmt; + } + + // ist es neuer oder wurde der akt. entfernt? + if( pNewVal ) + { + if( NUMBERFORMAT_TEXT != nNewFmt ) + { + if( SFX_ITEM_SET == GetItemState( + RES_BOXATR_VALUE, sal_False )) + nOldFmt = NUMBERFORMAT_TEXT; + else + nNewFmt = NUMBERFORMAT_TEXT; + } + else if( NUMBERFORMAT_TEXT == nNewFmt ) + nOldFmt = 0; + } + + // Logik: + // ValueAenderung: -> "simuliere" eine FormatAenderung! + // FormatAenderung: + // Text -> !Text oder FormatAenderung: + // - Ausrichtung auf RECHTS, wenn LINKS oder Blocksatz + // - vertikale Ausrichtung auf UNTEN wenn OBEN oder nicht + // gesetzt ist. + // - Text ersetzen (Farbe?? neg. Zahlen ROT??) + // !Text -> Text: + // - Ausrichtung auf LINKS, wenn RECHTS + // - vertikale Ausrichtung auf OEBN, wenn UNTEN gesetzt ist + + SvNumberFormatter* pNumFmtr = GetDoc()->GetNumberFormatter(); + sal_Bool bNewIsTxtFmt = pNumFmtr->IsTextFormat( nNewFmt ) || + NUMBERFORMAT_TEXT == nNewFmt; + + if( (!bNewIsTxtFmt && nOldFmt != nNewFmt) || pNewFml ) + { + sal_Bool bChgTxt = sal_True; + double fVal = 0; + if( !pNewVal && SFX_ITEM_SET != GetItemState( + RES_BOXATR_VALUE, sal_False, (const SfxPoolItem**)&pNewVal )) + { + // es wurde noch nie ein Wert gesetzt, dann versuche + // doch mal den Inhalt auszuwerten + sal_uLong nNdPos = pBox->IsValidNumTxtNd( sal_True ); + if( ULONG_MAX != nNdPos ) + { + sal_uInt32 nTmpFmtIdx = nNewFmt; + String aTxt( GetDoc()->GetNodes()[ nNdPos ] + ->GetTxtNode()->GetRedlineTxt()); + if( !aTxt.Len() ) + bChgTxt = sal_False; + else + { + //JP 15.09.98: Bug 55741 - Tabs beibehalten + lcl_TabToBlankAtSttEnd( aTxt ); + + // JP 22.04.98: Bug 49659 - + // Sonderbehandlung fuer Prozent + sal_Bool bIsNumFmt = sal_False; + if( NUMBERFORMAT_PERCENT == + pNumFmtr->GetType( nNewFmt )) + { + sal_uInt32 nTmpFmt = 0; + if( pNumFmtr->IsNumberFormat( + aTxt, nTmpFmt, fVal )) + { + if( NUMBERFORMAT_NUMBER == + pNumFmtr->GetType( nTmpFmt )) + aTxt += '%'; + + bIsNumFmt = pNumFmtr->IsNumberFormat( + aTxt, nTmpFmtIdx, fVal ); + } + } + else + bIsNumFmt = pNumFmtr->IsNumberFormat( + aTxt, nTmpFmtIdx, fVal ); + + if( bIsNumFmt ) + { + // dann setze den Value direkt in den Set - + // ohne Modify + int bIsLockMod = IsModifyLocked(); + LockModify(); + SetFmtAttr( SwTblBoxValue( fVal )); + if( !bIsLockMod ) + UnlockModify(); + } + } + } + } + else + fVal = pNewVal->GetValue(); + + // den Inhalt mit dem neuen Wert Formtieren und in den Absatz + // schbreiben + Color* pCol = 0; + String sNewTxt; + if( DBL_MAX == fVal ) + sNewTxt = ViewShell::GetShellRes()->aCalc_Error; + else + { + pNumFmtr->GetOutputString( fVal, nNewFmt, sNewTxt, &pCol ); + + if( !bChgTxt ) + sNewTxt.Erase(); + } + + // ueber alle Boxen + ChgTextToNum( *pBox, sNewTxt, pCol, + GetDoc()->IsInsTblAlignNum() ); + + } + else if( bNewIsTxtFmt && nOldFmt != nNewFmt ) + { + // auf jedenfall muessen jetzt die Formeln/Values + // geloescht werden! + // LockModify(); + // ResetAttr( RES_BOXATR_FORMULA, RES_BOXATR_VALUE ); + // UnlockModify(); + + + ChgNumToText( *pBox, nNewFmt ); + } + } + } + } + } + // Und die Basis-Klasse rufen + SwFrmFmt::Modify( pOld, pNew ); +} + +sal_Bool SwTableBox::HasNumCntnt( double& rNum, sal_uInt32& rFmtIndex, + sal_Bool& rIsEmptyTxtNd ) const +{ + sal_Bool bRet = sal_False; + sal_uLong nNdPos = IsValidNumTxtNd( sal_True ); + if( ULONG_MAX != nNdPos ) + { + String aTxt( pSttNd->GetNodes()[ nNdPos ]->GetTxtNode()-> + GetRedlineTxt() ); + //JP 15.09.98: Bug 55741 - Tabs beibehalten + lcl_TabToBlankAtSttEnd( aTxt ); + rIsEmptyTxtNd = 0 == aTxt.Len(); + SvNumberFormatter* pNumFmtr = GetFrmFmt()->GetDoc()->GetNumberFormatter(); + + const SfxPoolItem* pItem; + if( SFX_ITEM_SET == GetFrmFmt()->GetItemState( RES_BOXATR_FORMAT, + sal_False, &pItem )) + { + rFmtIndex = ((SwTblBoxNumFormat*)pItem)->GetValue(); + // JP 22.04.98: Bug 49659 - Sonderbehandlung fuer Prozent + if( !rIsEmptyTxtNd && + NUMBERFORMAT_PERCENT == pNumFmtr->GetType( rFmtIndex )) + { + sal_uInt32 nTmpFmt = 0; + if( pNumFmtr->IsNumberFormat( aTxt, nTmpFmt, rNum ) && + NUMBERFORMAT_NUMBER == pNumFmtr->GetType( nTmpFmt )) + aTxt += '%'; + } + } + else + rFmtIndex = 0; + + bRet = pNumFmtr->IsNumberFormat( aTxt, rFmtIndex, rNum ); + } + else + rIsEmptyTxtNd = sal_False; + return bRet; +} + +sal_Bool SwTableBox::IsNumberChanged() const +{ + sal_Bool bRet = sal_True; + + if( SFX_ITEM_SET == GetFrmFmt()->GetItemState( RES_BOXATR_FORMULA, sal_False )) + { + const SwTblBoxNumFormat *pNumFmt; + const SwTblBoxValue *pValue; + + if( SFX_ITEM_SET != GetFrmFmt()->GetItemState( RES_BOXATR_VALUE, sal_False, + (const SfxPoolItem**)&pValue )) + pValue = 0; + if( SFX_ITEM_SET != GetFrmFmt()->GetItemState( RES_BOXATR_FORMAT, sal_False, + (const SfxPoolItem**)&pNumFmt )) + pNumFmt = 0; + + sal_uLong nNdPos; + if( pNumFmt && pValue && + ULONG_MAX != ( nNdPos = IsValidNumTxtNd( sal_True ) ) ) + { + String sNewTxt, sOldTxt( pSttNd->GetNodes()[ nNdPos ]-> + GetTxtNode()->GetRedlineTxt() ); + lcl_DelTabsAtSttEnd( sOldTxt ); + + Color* pCol = 0; + GetFrmFmt()->GetDoc()->GetNumberFormatter()->GetOutputString( + pValue->GetValue(), pNumFmt->GetValue(), sNewTxt, &pCol ); + + bRet = sNewTxt != sOldTxt || + !( ( !pCol && !GetSaveNumFmtColor() ) || + ( pCol && GetSaveNumFmtColor() && + *pCol == *GetSaveNumFmtColor() )); + } + } + return bRet; +} + +sal_uLong SwTableBox::IsValidNumTxtNd( sal_Bool bCheckAttr ) const +{ + sal_uLong nPos = ULONG_MAX; + if( pSttNd ) + { + SwNodeIndex aIdx( *pSttNd ); + sal_uLong nIndex = aIdx.GetIndex(); + const sal_uLong nIndexEnd = pSttNd->GetNodes()[ nIndex ]->EndOfSectionIndex(); + const SwTxtNode *pTextNode = 0; + while( ++nIndex < nIndexEnd ) + { + const SwNode* pNode = pSttNd->GetNodes()[nIndex]; + if( pNode->IsTableNode() ) + { /*return ULONG_MAX if the cell contains a table(in table)*/ + pTextNode = 0; + break; + } + if( pNode->IsTxtNode() ) + { + if( pTextNode ) + { /*return ULONG_MAX if the cell contains complex paragraphs*/ + pTextNode = 0; + break; + } + else + { + pTextNode = pNode->GetTxtNode(); + nPos = nIndex; + } + } + } + if( pTextNode ) + { + if( bCheckAttr ) + { + const SwpHints* pHts = pTextNode->GetpSwpHints(); + const String& rTxt = pTextNode->GetTxt(); + // dann teste doch mal, ob das wirklich nur Text im Node steht! + // Flys/Felder/.. + if( pHts ) + { + for( sal_uInt16 n = 0; n < pHts->Count(); ++n ) + { + const SwTxtAttr* pAttr = (*pHts)[ n ]; + if( RES_TXTATR_NOEND_BEGIN <= pAttr->Which() || + *pAttr->GetStart() || + *pAttr->GetAnyEnd() < rTxt.Len() ) + { + if ( pAttr->Which() == RES_TXTATR_FIELD ) + { + const SwField* pField = pAttr->GetFld().GetFld(); + if ( pField && pField->GetTypeId() == TYP_SETFLD ) + { + continue; + } + } + nPos = ULONG_MAX; + break; + } + } + } + } + } + else + nPos = ULONG_MAX; + } + return nPos; +} + +// ist das eine FormelBox oder eine Box mit numerischen Inhalt (AutoSum) +sal_uInt16 SwTableBox::IsFormulaOrValueBox() const +{ + sal_uInt16 nWhich = 0; + const SwTxtNode* pTNd; + SwFrmFmt* pFmt = GetFrmFmt(); + if( SFX_ITEM_SET == pFmt->GetItemState( RES_BOXATR_FORMULA, sal_False )) + nWhich = RES_BOXATR_FORMULA; + else if( SFX_ITEM_SET == pFmt->GetItemState( RES_BOXATR_VALUE, sal_False ) && + !pFmt->GetDoc()->GetNumberFormatter()->IsTextFormat( + pFmt->GetTblBoxNumFmt().GetValue() )) + nWhich = RES_BOXATR_VALUE; + else if( pSttNd && pSttNd->GetIndex() + 2 == pSttNd->EndOfSectionIndex() + && 0 != ( pTNd = pSttNd->GetNodes()[ pSttNd->GetIndex() + 1 ] + ->GetTxtNode() ) && !pTNd->GetTxt().Len() ) + nWhich = USHRT_MAX; + + return nWhich; +} + +void SwTableBox::ActualiseValueBox() +{ + const SfxPoolItem *pFmtItem, *pValItem; + SwFrmFmt* pFmt = GetFrmFmt(); + if( SFX_ITEM_SET == pFmt->GetItemState( RES_BOXATR_FORMAT, sal_True, &pFmtItem ) + && SFX_ITEM_SET == pFmt->GetItemState( RES_BOXATR_VALUE, sal_True, &pValItem )) + { + const sal_uLong nFmtId = ((SwTblBoxNumFormat*)pFmtItem)->GetValue(); + sal_uLong nNdPos = ULONG_MAX; + SvNumberFormatter* pNumFmtr = pFmt->GetDoc()->GetNumberFormatter(); + + if( !pNumFmtr->IsTextFormat( nFmtId ) && + ULONG_MAX != (nNdPos = IsValidNumTxtNd( sal_True )) ) + { + double fVal = ((SwTblBoxValue*)pValItem)->GetValue(); + Color* pCol = 0; + String sNewTxt; + pNumFmtr->GetOutputString( fVal, nFmtId, sNewTxt, &pCol ); + + const String& rTxt = pSttNd->GetNodes()[ nNdPos ]->GetTxtNode()->GetTxt(); + if( rTxt != sNewTxt ) + ChgTextToNum( *this, sNewTxt, pCol, sal_False ,nNdPos); + } + } +} + +void SwTableBox_Impl::SetNewCol( Color** ppCol, const Color* pNewCol ) +{ + if( *ppCol != pNewCol ) + { + delete *ppCol; + if( pNewCol ) + *ppCol = new Color( *pNewCol ); + else + *ppCol = 0; + } +} + +struct SwTableCellInfo::Impl +{ + const SwTable * m_pTable; + const SwCellFrm * m_pCellFrm; + const SwTabFrm * m_pTabFrm; + typedef ::std::set<const SwTableBox *> TableBoxes_t; + TableBoxes_t m_HandledTableBoxes; + +public: + Impl() + : m_pTable(NULL), m_pCellFrm(NULL), m_pTabFrm(NULL) + { + } + + ~Impl() {} + + void setTable(const SwTable * pTable) { + m_pTable = pTable; + SwFrmFmt * pFrmFmt = m_pTable->GetFrmFmt(); + m_pTabFrm = SwIterator<SwTabFrm,SwFmt>::FirstElement(*pFrmFmt); + if (m_pTabFrm->IsFollow()) + m_pTabFrm = m_pTabFrm->FindMaster(true); + } + const SwTable * getTable() const { return m_pTable; } + + const SwCellFrm * getCellFrm() const { return m_pCellFrm; } + + const SwFrm * getNextFrmInTable(const SwFrm * pFrm); + const SwCellFrm * getNextCellFrm(const SwFrm * pFrm); + const SwCellFrm * getNextTableBoxsCellFrm(const SwFrm * pFrm); + bool getNext(); +}; + +const SwFrm * SwTableCellInfo::Impl::getNextFrmInTable(const SwFrm * pFrm) +{ + const SwFrm * pResult = NULL; + + if (((! pFrm->IsTabFrm()) || pFrm == m_pTabFrm) && pFrm->GetLower()) + pResult = pFrm->GetLower(); + else if (pFrm->GetNext()) + pResult = pFrm->GetNext(); + else + { + while (pFrm->GetUpper() != NULL) + { + pFrm = pFrm->GetUpper(); + + if (pFrm->IsTabFrm()) + { + m_pTabFrm = static_cast<const SwTabFrm *>(pFrm)->GetFollow(); + pResult = m_pTabFrm; + break; + } + else if (pFrm->GetNext()) + { + pResult = pFrm->GetNext(); + break; + } + } + } + + return pResult; +} + +const SwCellFrm * SwTableCellInfo::Impl::getNextCellFrm(const SwFrm * pFrm) +{ + const SwCellFrm * pResult = NULL; + + while ((pFrm = getNextFrmInTable(pFrm)) != NULL) + { + if (pFrm->IsCellFrm()) + { + pResult = static_cast<const SwCellFrm *>(pFrm); + break; + } + } + + return pResult; +} + +const SwCellFrm * SwTableCellInfo::Impl::getNextTableBoxsCellFrm(const SwFrm * pFrm) +{ + const SwCellFrm * pResult = NULL; + + while ((pFrm = getNextCellFrm(pFrm)) != NULL) + { + const SwCellFrm * pCellFrm = static_cast<const SwCellFrm *>(pFrm); + const SwTableBox * pTabBox = pCellFrm->GetTabBox(); + TableBoxes_t::const_iterator aIt = m_HandledTableBoxes.find(pTabBox); + + if (aIt == m_HandledTableBoxes.end()) + { + pResult = pCellFrm; + m_HandledTableBoxes.insert(pTabBox); + break; + } + } + + return pResult; +} + +const SwCellFrm * SwTableCellInfo::getCellFrm() const +{ + return m_pImpl->getCellFrm(); +} + +bool SwTableCellInfo::Impl::getNext() +{ + if (m_pCellFrm == NULL) + { + if (m_pTabFrm != NULL) + m_pCellFrm = Impl::getNextTableBoxsCellFrm(m_pTabFrm); + } + else + m_pCellFrm = Impl::getNextTableBoxsCellFrm(m_pCellFrm); + + return m_pCellFrm != NULL; +} + +SwTableCellInfo::SwTableCellInfo(const SwTable * pTable) +{ + m_pImpl.reset(new Impl()); + m_pImpl->setTable(pTable); +} + +SwTableCellInfo::~SwTableCellInfo() +{ +} + +bool SwTableCellInfo::getNext() +{ + return m_pImpl->getNext(); +} + +SwRect SwTableCellInfo::getRect() const +{ + SwRect aRet; + + if (getCellFrm() != NULL) + aRet = getCellFrm()->Frm(); + + return aRet; +} + +const SwTableBox * SwTableCellInfo::getTableBox() const +{ + const SwTableBox * pRet = NULL; + + if (getCellFrm() != NULL) + pRet = getCellFrm()->GetTabBox(); + + return pRet; +} + +void SwTable::RegisterToFormat( SwFmt& rFmt ) +{ + rFmt.Add( this ); +} + +void SwTableLine::RegisterToFormat( SwFmt& rFmt ) +{ + rFmt.Add( this ); +} + +void SwTableBox::RegisterToFormat( SwFmt& rFmt ) +{ + rFmt.Add( this ); +} + +void SwTableBox::ForgetFrmFmt() +{ + if ( GetRegisteredIn() ) + GetRegisteredInNonConst()->Remove(this); +} + + |