| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the 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 ) |
| { |
| xub_StrLen nNextSetField = 0; |
| 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->GetStart() == nNextSetField) |
| && (pAttr->Which() == RES_TXTATR_FIELD)) |
| { |
| // #i104949# hideous hack for report builder: |
| // it inserts hidden variable-set fields at |
| // the beginning of para in cell, but they |
| // should not turn cell into text cell |
| const SwField* pField = pAttr->GetFmtFld().GetField(); |
| if (pField && |
| (pField->GetTypeId() == TYP_SETFLD) && |
| (0 != (static_cast<SwSetExpField const*> |
| (pField)->GetSubType() & |
| nsSwExtendedSubType::SUB_INVISIBLE))) |
| { |
| nNextSetField = *pAttr->GetStart() + 1; |
| 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); |
| } |
| |
| |