diff options
Diffstat (limited to 'sw/source/core/docnode/ndtbl1.cxx')
-rw-r--r-- | sw/source/core/docnode/ndtbl1.cxx | 1605 |
1 files changed, 1605 insertions, 0 deletions
diff --git a/sw/source/core/docnode/ndtbl1.cxx b/sw/source/core/docnode/ndtbl1.cxx new file mode 100644 index 000000000000..c561f10d0a3f --- /dev/null +++ b/sw/source/core/docnode/ndtbl1.cxx @@ -0,0 +1,1605 @@ +/************************************************************************* + * + * 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" + + +#ifdef WTC +#define private public +#endif + +#include "hintids.hxx" +#include <editeng/lrspitem.hxx> +#include <editeng/boxitem.hxx> +#include <editeng/brshitem.hxx> +#include <editeng/frmdiritem.hxx> +#include <fmtornt.hxx> +#include <fmtfsize.hxx> +#include <fmtlsplt.hxx> +#include <fmtrowsplt.hxx> +#include <tabcol.hxx> +#include <frmatr.hxx> +#include <cellfrm.hxx> +#include <tabfrm.hxx> +#include <cntfrm.hxx> +#include <txtfrm.hxx> +#include <svx/svxids.hrc> +#include "doc.hxx" +#include "pam.hxx" +#include "swcrsr.hxx" +#include "viscrs.hxx" +#include "swtable.hxx" +#include "htmltbl.hxx" +#include "tblsel.hxx" +#include "swtblfmt.hxx" +#include "docary.hxx" +#include "ndindex.hxx" +#include "undobj.hxx" + +using namespace ::com::sun::star; + + +extern void ClearFEShellTabCols(); + +//siehe auch swtable.cxx +#define COLFUZZY 20L + +inline BOOL IsSame( long nA, long nB ) { return Abs(nA-nB) <= COLFUZZY; } + +class SwTblFmtCmp +{ +public: + SwFrmFmt *pOld, + *pNew; + INT16 nType; + + SwTblFmtCmp( SwFrmFmt *pOld, SwFrmFmt *pNew, INT16 nType ); + + static SwFrmFmt *FindNewFmt( SvPtrarr &rArr, SwFrmFmt*pOld, INT16 nType ); + static void Delete( SvPtrarr &rArr ); +}; + + +SwTblFmtCmp::SwTblFmtCmp( SwFrmFmt *pO, SwFrmFmt *pN, INT16 nT ) + : pOld ( pO ), pNew ( pN ), nType( nT ) +{ +} + +SwFrmFmt *SwTblFmtCmp::FindNewFmt( SvPtrarr &rArr, SwFrmFmt *pOld, INT16 nType ) +{ + for ( USHORT i = 0; i < rArr.Count(); ++i ) + { + SwTblFmtCmp *pCmp = (SwTblFmtCmp*)rArr[i]; + if ( pCmp->pOld == pOld && pCmp->nType == nType ) + return pCmp->pNew; + } + return 0; +} + +void SwTblFmtCmp::Delete( SvPtrarr &rArr ) +{ + for ( USHORT i = 0; i < rArr.Count(); ++i ) + delete (SwTblFmtCmp*)rArr[i]; +} + +void lcl_GetStartEndCell( const SwCursor& rCrsr, + SwLayoutFrm *&prStart, SwLayoutFrm *&prEnd ) +{ + ASSERT( rCrsr.GetCntntNode() && rCrsr.GetCntntNode( FALSE ), + "Tabselection nicht auf Cnt." ); + + Point aPtPos, aMkPos; + const SwShellCrsr* pShCrsr = dynamic_cast<const SwShellCrsr*>(&rCrsr); + if( pShCrsr ) + { + aPtPos = pShCrsr->GetPtPos(); + aMkPos = pShCrsr->GetMkPos(); + } + + // robust: + SwCntntNode* pPointNd = rCrsr.GetCntntNode(); + SwCntntNode* pMarkNd = rCrsr.GetCntntNode(FALSE); + + SwFrm* pPointFrm = pPointNd ? pPointNd->GetFrm( &aPtPos ) : 0; + SwFrm* pMarkFrm = pMarkNd ? pMarkNd->GetFrm( &aMkPos ) : 0; + + prStart = pPointFrm ? pPointFrm->GetUpper() : 0; + prEnd = pMarkFrm ? pMarkFrm->GetUpper() : 0; +} + +BOOL lcl_GetBoxSel( const SwCursor& rCursor, SwSelBoxes& rBoxes, + BOOL bAllCrsr = FALSE ) +{ + const SwTableCursor* pTblCrsr = + dynamic_cast<const SwTableCursor*>(&rCursor); + if( pTblCrsr ) + ::GetTblSelCrs( *pTblCrsr, rBoxes ); + else + { + const SwPaM *pCurPam = &rCursor, *pSttPam = pCurPam; + do { + const SwNode* pNd = pCurPam->GetNode()->FindTableBoxStartNode(); + if( pNd ) + { + SwTableBox* pBox = (SwTableBox*)pNd->FindTableNode()->GetTable(). + GetTblBox( pNd->GetIndex() ); + rBoxes.Insert( pBox ); + } + } while( bAllCrsr && + pSttPam != ( pCurPam = (SwPaM*)pCurPam->GetNext()) ); + } + return 0 != rBoxes.Count(); +} + +/*********************************************************************** +#* Class : SwDoc +#* Methoden : SetRowHeight(), GetRowHeight() +#* Datum : MA 17. May. 93 +#* Update : JP 28.04.98 +#***********************************************************************/ +//Die Zeilenhoehe wird ausgehend von der Selektion ermittelt/gesetzt. +//Ausgehend von jeder Zelle innerhalb der Selektion werden nach oben alle +//Zeilen abgeklappert, die oberste Zeile erhaelt den gewuenschten Wert alle +//tieferliegenden Zeilen einen entsprechenden Wert der sich aus der +//Relation der alten und neuen Groesse der obersten Zeile und ihrer +//eigenen Groesse ergiebt. +//Alle veraenderten Zeilen erhalten ggf. ein eigenes FrmFmt. +//Natuerlich darf jede Zeile nur einmal angefasst werden. + +inline void InsertLine( SvPtrarr& rLineArr, SwTableLine* pLine ) +{ + if( USHRT_MAX == rLineArr.GetPos( pLine ) ) + rLineArr.Insert( pLine, rLineArr.Count() ); +} + +//----------------------------------------------------------------------------- + +BOOL lcl_IsAnLower( const SwTableLine *pLine, const SwTableLine *pAssumed ) +{ + const SwTableLine *pTmp = pAssumed->GetUpper() ? + pAssumed->GetUpper()->GetUpper() : 0; + while ( pTmp ) + { + if ( pTmp == pLine ) + return TRUE; + pTmp = pTmp->GetUpper() ? pTmp->GetUpper()->GetUpper() : 0; + } + return FALSE; +} +//----------------------------------------------------------------------------- + +struct LinesAndTable +{ + SvPtrarr &rLines; + const SwTable &rTable; + BOOL bInsertLines; + + LinesAndTable( SvPtrarr &rL, const SwTable &rTbl ) : + rLines( rL ), rTable( rTbl ), bInsertLines( TRUE ) {} +}; + + +BOOL _FindLine( const _FndLine*& rpLine, void* pPara ); + +BOOL _FindBox( const _FndBox*& rpBox, void* pPara ) +{ + if ( rpBox->GetLines().Count() ) + { + ((LinesAndTable*)pPara)->bInsertLines = TRUE; + ((_FndBox*)rpBox)->GetLines().ForEach( _FindLine, pPara ); + if ( ((LinesAndTable*)pPara)->bInsertLines ) + { + const SwTableLines &rLines = rpBox->GetBox() + ? rpBox->GetBox()->GetTabLines() + : ((LinesAndTable*)pPara)->rTable.GetTabLines(); + if ( rpBox->GetLines().Count() == rLines.Count() ) + { + for ( USHORT i = 0; i < rLines.Count(); ++i ) + ::InsertLine( ((LinesAndTable*)pPara)->rLines, + (SwTableLine*)rLines[i] ); + } + else + ((LinesAndTable*)pPara)->bInsertLines = FALSE; + } + } + else if ( rpBox->GetBox() ) + ::InsertLine( ((LinesAndTable*)pPara)->rLines, + (SwTableLine*)rpBox->GetBox()->GetUpper() ); + return TRUE; +} + +BOOL _FindLine( const _FndLine*& rpLine, void* pPara ) +{ + ((_FndLine*)rpLine)->GetBoxes().ForEach( _FindBox, pPara ); + return TRUE; +} + +void lcl_CollectLines( SvPtrarr &rArr, const SwCursor& rCursor, bool bRemoveLines ) +{ + //Zuerst die selektierten Boxen einsammeln. + SwSelBoxes aBoxes; + if( !::lcl_GetBoxSel( rCursor, aBoxes )) + return ; + + //Die selektierte Struktur kopieren. + const SwTable &rTable = aBoxes[0]->GetSttNd()->FindTableNode()->GetTable(); + LinesAndTable aPara( rArr, rTable ); + _FndBox aFndBox( 0, 0 ); + { + _FndPara aTmpPara( aBoxes, &aFndBox ); + ((SwTableLines&)rTable.GetTabLines()).ForEach( &_FndLineCopyCol, &aTmpPara ); + } + + //Diejenigen Lines einsammeln, die nur selektierte Boxen enthalten. + const _FndBox *pTmp = &aFndBox; + ::_FindBox( pTmp, &aPara ); + + // Remove lines, that have a common superordinate row. + // (Not for row split) + if ( bRemoveLines ) + { + for ( USHORT i = 0; i < rArr.Count(); ++i ) + { + SwTableLine *pUpLine = (SwTableLine*)rArr[i]; + for ( USHORT k = 0; k < rArr.Count(); ++k ) + { + if ( k != i && ::lcl_IsAnLower( pUpLine, (SwTableLine*)rArr[k] ) ) + { + rArr.Remove( k ); + if ( k <= i ) + --i; + --k; + } + } + } + } +} + +//----------------------------------------------------------------------------- + +void lcl_ProcessRowAttr( SvPtrarr& rFmtCmp, SwTableLine* pLine, const SfxPoolItem& rNew ) +{ + SwFrmFmt *pNewFmt; + if ( 0 != (pNewFmt = SwTblFmtCmp::FindNewFmt( rFmtCmp, pLine->GetFrmFmt(), 0 ))) + pLine->ChgFrmFmt( (SwTableLineFmt*)pNewFmt ); + else + { + SwFrmFmt *pOld = pLine->GetFrmFmt(); + SwFrmFmt *pNew = pLine->ClaimFrmFmt(); + pNew->SetFmtAttr( rNew ); + rFmtCmp.Insert( new SwTblFmtCmp( pOld, pNew, 0 ), rFmtCmp.Count()); + } +} + +//----------------------------------------------------------------------------- + +void lcl_ProcessBoxSize( SvPtrarr &rFmtCmp, SwTableBox *pBox, const SwFmtFrmSize &rNew ); + +void lcl_ProcessRowSize( SvPtrarr &rFmtCmp, SwTableLine *pLine, const SwFmtFrmSize &rNew ) +{ + lcl_ProcessRowAttr( rFmtCmp, pLine, rNew ); + SwTableBoxes &rBoxes = pLine->GetTabBoxes(); + for ( USHORT i = 0; i < rBoxes.Count(); ++i ) + ::lcl_ProcessBoxSize( rFmtCmp, rBoxes[i], rNew ); +} + +//----------------------------------------------------------------------------- + +void lcl_ProcessBoxSize( SvPtrarr &rFmtCmp, SwTableBox *pBox, const SwFmtFrmSize &rNew ) +{ + SwTableLines &rLines = pBox->GetTabLines(); + if ( rLines.Count() ) + { + SwFmtFrmSize aSz( rNew ); + aSz.SetHeight( rNew.GetHeight() ? rNew.GetHeight() / rLines.Count() : 0 ); + for ( USHORT i = 0; i < rLines.Count(); ++i ) + ::lcl_ProcessRowSize( rFmtCmp, rLines[i], aSz ); + } +} + +//----------------------------------------------------------------------------- + +/****************************************************************************** + * void SwDoc::SetRowSplit() + ******************************************************************************/ +void SwDoc::SetRowSplit( const SwCursor& rCursor, const SwFmtRowSplit &rNew ) +{ + SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode(); + if( pTblNd ) + { + SvPtrarr aRowArr( 25, 50 ); //Zum sammeln Lines. + ::lcl_CollectLines( aRowArr, rCursor, false ); + + if( aRowArr.Count() ) + { + if( DoesUndo() ) + { + ClearRedo(); + AppendUndo( new SwUndoAttrTbl( *pTblNd )); + } + + SvPtrarr aFmtCmp( Max( BYTE(255), BYTE(aRowArr.Count()) ), 255 ); + + for( USHORT i = 0; i < aRowArr.Count(); ++i ) + ::lcl_ProcessRowAttr( aFmtCmp, (SwTableLine*)aRowArr[i], rNew ); + + SwTblFmtCmp::Delete( aFmtCmp ); + SetModified(); + } + } +} + + +/****************************************************************************** + * SwTwips SwDoc::GetRowSplit() const + ******************************************************************************/ +void SwDoc::GetRowSplit( const SwCursor& rCursor, SwFmtRowSplit *& rpSz ) const +{ + rpSz = 0; + + SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode(); + if( pTblNd ) + { + SvPtrarr aRowArr( 25, 50 ); //Zum sammeln der Lines. + ::lcl_CollectLines( aRowArr, rCursor, false ); + + if( aRowArr.Count() ) + { + rpSz = &(SwFmtRowSplit&)((SwTableLine*)aRowArr[0])-> + GetFrmFmt()->GetRowSplit(); + + for ( USHORT i = 1; i < aRowArr.Count() && rpSz; ++i ) + { + if ( (*rpSz).GetValue() != ((SwTableLine*)aRowArr[i])->GetFrmFmt()->GetRowSplit().GetValue() ) + rpSz = 0; + } + if ( rpSz ) + rpSz = new SwFmtRowSplit( *rpSz ); + } + } +} + + +/****************************************************************************** + * void SwDoc::SetRowHeight( SwTwips nNew ) + ******************************************************************************/ +void SwDoc::SetRowHeight( const SwCursor& rCursor, const SwFmtFrmSize &rNew ) +{ + SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode(); + if( pTblNd ) + { + SvPtrarr aRowArr( 25, 50 ); //Zum sammeln Lines. + ::lcl_CollectLines( aRowArr, rCursor, true ); + + if( aRowArr.Count() ) + { + if( DoesUndo() ) + { + ClearRedo(); + AppendUndo( new SwUndoAttrTbl( *pTblNd )); + } + + SvPtrarr aFmtCmp( Max( BYTE(255), BYTE(aRowArr.Count()) ), 255 ); + for ( USHORT i = 0; i < aRowArr.Count(); ++i ) + ::lcl_ProcessRowSize( aFmtCmp, (SwTableLine*)aRowArr[i], rNew ); + SwTblFmtCmp::Delete( aFmtCmp ); + + SetModified(); + } + } +} + + +/****************************************************************************** + * SwTwips SwDoc::GetRowHeight() const + ******************************************************************************/ +void SwDoc::GetRowHeight( const SwCursor& rCursor, SwFmtFrmSize *& rpSz ) const +{ + rpSz = 0; + + SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode(); + if( pTblNd ) + { + SvPtrarr aRowArr( 25, 50 ); //Zum sammeln der Lines. + ::lcl_CollectLines( aRowArr, rCursor, true ); + + if( aRowArr.Count() ) + { + rpSz = &(SwFmtFrmSize&)((SwTableLine*)aRowArr[0])-> + GetFrmFmt()->GetFrmSize(); + + for ( USHORT i = 1; i < aRowArr.Count() && rpSz; ++i ) + { + if ( *rpSz != ((SwTableLine*)aRowArr[i])->GetFrmFmt()->GetFrmSize() ) + rpSz = 0; + } + if ( rpSz ) + rpSz = new SwFmtFrmSize( *rpSz ); + } + } +} + +BOOL SwDoc::BalanceRowHeight( const SwCursor& rCursor, BOOL bTstOnly ) +{ + BOOL bRet = FALSE; + SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode(); + if( pTblNd ) + { + SvPtrarr aRowArr( 25, 50 ); //Zum sammeln der Lines. + ::lcl_CollectLines( aRowArr, rCursor, true ); + + if( 1 < aRowArr.Count() ) + { + if( !bTstOnly ) + { + long nHeight = 0; + USHORT i; + + for ( i = 0; i < aRowArr.Count(); ++i ) + { + SwClientIter aIter( *((SwTableLine*)aRowArr[i])->GetFrmFmt() ); + SwFrm* pFrm = (SwFrm*)aIter.First( TYPE(SwFrm) ); + while ( pFrm ) + { + nHeight = Max( nHeight, pFrm->Frm().Height() ); + pFrm = (SwFrm*)aIter.Next(); + } + } + SwFmtFrmSize aNew( ATT_MIN_SIZE, 0, nHeight ); + + if( DoesUndo() ) + { + ClearRedo(); + AppendUndo( new SwUndoAttrTbl( *pTblNd )); + } + + SvPtrarr aFmtCmp( Max( BYTE(255), BYTE(aRowArr.Count()) ), 255 ); + for( i = 0; i < aRowArr.Count(); ++i ) + ::lcl_ProcessRowSize( aFmtCmp, (SwTableLine*)aRowArr[i], aNew ); + SwTblFmtCmp::Delete( aFmtCmp ); + + SetModified(); + } + bRet = TRUE; + } + } + return bRet; +} + +/****************************************************************************** + * void SwDoc::SetRowBackground() + ******************************************************************************/ +void SwDoc::SetRowBackground( const SwCursor& rCursor, const SvxBrushItem &rNew ) +{ + SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode(); + if( pTblNd ) + { + SvPtrarr aRowArr( 25, 50 ); //Zum sammeln Lines. + ::lcl_CollectLines( aRowArr, rCursor, true ); + + if( aRowArr.Count() ) + { + if( DoesUndo() ) + { + ClearRedo(); + AppendUndo( new SwUndoAttrTbl( *pTblNd )); + } + + SvPtrarr aFmtCmp( Max( BYTE(255), BYTE(aRowArr.Count()) ), 255 ); + + for( USHORT i = 0; i < aRowArr.Count(); ++i ) + ::lcl_ProcessRowAttr( aFmtCmp, (SwTableLine*)aRowArr[i], rNew ); + + SwTblFmtCmp::Delete( aFmtCmp ); + SetModified(); + } + } +} + +/****************************************************************************** + * SwTwips SwDoc::GetRowBackground() const + ******************************************************************************/ +BOOL SwDoc::GetRowBackground( const SwCursor& rCursor, SvxBrushItem &rToFill ) const +{ + BOOL bRet = FALSE; + SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode(); + if( pTblNd ) + { + SvPtrarr aRowArr( 25, 50 ); //Zum sammeln Lines. + ::lcl_CollectLines( aRowArr, rCursor, true ); + + if( aRowArr.Count() ) + { + rToFill = ((SwTableLine*)aRowArr[0])->GetFrmFmt()->GetBackground(); + + bRet = TRUE; + for ( USHORT i = 1; i < aRowArr.Count(); ++i ) + if ( rToFill != ((SwTableLine*)aRowArr[i])->GetFrmFmt()->GetBackground() ) + { + bRet = FALSE; + break; + } + } + } + return bRet; +} + +/*********************************************************************** +#* Class : SwDoc +#* Methoden : SetTabBorders(), GetTabBorders() +#* Datum : MA 18. May. 93 +#* Update : JP 29.04.98 +#***********************************************************************/ +inline void InsertCell( SvPtrarr& rCellArr, SwCellFrm* pCellFrm ) +{ + if( USHRT_MAX == rCellArr.GetPos( pCellFrm ) ) + rCellArr.Insert( pCellFrm, rCellArr.Count() ); +} + +//----------------------------------------------------------------------------- +void lcl_CollectCells( SvPtrarr &rArr, const SwRect &rUnion, + SwTabFrm *pTab ) +{ + SwLayoutFrm *pCell = pTab->FirstCell(); + do + { + // Wenn in der Zelle ein spaltiger Bereich sitzt, muessen wir + // uns erst wieder zur Zelle hochhangeln + while ( !pCell->IsCellFrm() ) + pCell = pCell->GetUpper(); + ASSERT( pCell, "Frame ist keine Zelle." ); + if ( rUnion.IsOver( pCell->Frm() ) ) + ::InsertCell( rArr, (SwCellFrm*)pCell ); + //Dafuer sorgen, dass die Zelle auch verlassen wird (Bereiche) + SwLayoutFrm *pTmp = pCell; + do + { pTmp = pTmp->GetNextLayoutLeaf(); + } while ( pCell->IsAnLower( pTmp ) ); + pCell = pTmp; + } while( pCell && pTab->IsAnLower( pCell ) ); +} + +void SwDoc::SetTabBorders( const SwCursor& rCursor, const SfxItemSet& rSet ) +{ + SwCntntNode* pCntNd = rCursor.GetPoint()->nNode.GetNode().GetCntntNode(); + SwTableNode* pTblNd = pCntNd ? pCntNd->FindTableNode() : 0; + if( !pTblNd ) + return ; + + SwLayoutFrm *pStart, *pEnd; + ::lcl_GetStartEndCell( rCursor, pStart, pEnd ); + + SwSelUnions aUnions; + ::MakeSelUnions( aUnions, pStart, pEnd ); + + if( aUnions.Count() ) + { + SwTable& rTable = pTblNd->GetTable(); + if( DoesUndo() ) + { + ClearRedo(); + AppendUndo( new SwUndoAttrTbl( *pTblNd )); + } + + SvPtrarr aFmtCmp( 255, 255 ); + const SvxBoxItem* pSetBox; + const SvxBoxInfoItem *pSetBoxInfo; + + const SvxBorderLine* pLeft = 0; + const SvxBorderLine* pRight = 0; + const SvxBorderLine* pTop = 0; + const SvxBorderLine* pBottom = 0; + const SvxBorderLine* pHori = 0; + const SvxBorderLine* pVert = 0; + BOOL bHoriValid = TRUE, bVertValid = TRUE, + bTopValid = TRUE, bBottomValid = TRUE, + bLeftValid = TRUE, bRightValid = TRUE; + + // JP 21.07.95: die Flags im BoxInfo-Item entscheiden, wann eine + // BorderLine gueltig ist!! + if( SFX_ITEM_SET == rSet.GetItemState( SID_ATTR_BORDER_INNER, FALSE, + (const SfxPoolItem**)&pSetBoxInfo) ) + { + pHori = pSetBoxInfo->GetHori(); + pVert = pSetBoxInfo->GetVert(); + + bHoriValid = pSetBoxInfo->IsValid(VALID_HORI); + bVertValid = pSetBoxInfo->IsValid(VALID_VERT); + + // wollen wir die auswerten ?? + bTopValid = pSetBoxInfo->IsValid(VALID_TOP); + bBottomValid = pSetBoxInfo->IsValid(VALID_BOTTOM); + bLeftValid = pSetBoxInfo->IsValid(VALID_LEFT); + bRightValid = pSetBoxInfo->IsValid(VALID_RIGHT); + } + + if( SFX_ITEM_SET == rSet.GetItemState( RES_BOX, FALSE, + (const SfxPoolItem**)&pSetBox) ) + { + pLeft = pSetBox->GetLeft(); + pRight = pSetBox->GetRight(); + pTop = pSetBox->GetTop(); + pBottom = pSetBox->GetBottom(); + } + else + { + // nicht gesetzt, also keine gueltigen Werte + bTopValid = bBottomValid = bLeftValid = bRightValid = FALSE; + pSetBox = 0; + } + + BOOL bFirst = TRUE; + for ( USHORT i = 0; i < aUnions.Count(); ++i ) + { + SwSelUnion *pUnion = aUnions[i]; + SwTabFrm *pTab = pUnion->GetTable(); + const SwRect &rUnion = pUnion->GetUnion(); + const BOOL bLast = i == aUnions.Count() - 1 ? TRUE : FALSE; + + SvPtrarr aCellArr( 255, 255 ); + ::lcl_CollectCells( aCellArr, pUnion->GetUnion(), pTab ); + + //Alle Zellenkanten, die mit dem UnionRect uebereinstimmen oder + //darueber hinausragen sind Aussenkanten. Alle anderen sind + //Innenkanten. + //neu: Die Aussenkanten koennen abhaengig davon, ob es sich um eine + //Start/Mittlere/Folge -Tabelle (bei Selektionen ueber FollowTabs) + //handelt doch keine Aussenkanten sein. + //Aussenkanten werden links, rechts, oben und unten gesetzt. + //Innenkanten werden nur oben und links gesetzt. + for ( USHORT j = 0; j < aCellArr.Count(); ++j ) + { + SwCellFrm *pCell = (SwCellFrm*)aCellArr[j]; + const sal_Bool bVert = pTab->IsVertical(); + const sal_Bool bRTL = pTab->IsRightToLeft(); + sal_Bool bTopOver, bLeftOver, bRightOver, bBottomOver; + if ( bVert ) + { + bTopOver = pCell->Frm().Right() >= rUnion.Right(); + bLeftOver = pCell->Frm().Top() <= rUnion.Top(); + bRightOver = pCell->Frm().Bottom() >= rUnion.Bottom(); + bBottomOver = pCell->Frm().Left() <= rUnion.Left(); + } + else + { + bTopOver = pCell->Frm().Top() <= rUnion.Top(); + bLeftOver = pCell->Frm().Left() <= rUnion.Left(); + bRightOver = pCell->Frm().Right() >= rUnion.Right(); + bBottomOver = pCell->Frm().Bottom() >= rUnion.Bottom(); + } + + if ( bRTL ) + { + sal_Bool bTmp = bRightOver; + bRightOver = bLeftOver; + bLeftOver = bTmp; + } + + //Grundsaetzlich nichts setzen in HeadlineRepeats. + if ( pTab->IsFollow() && + ( pTab->IsInHeadline( *pCell ) || + // --> FME 2006-02-07 #126092# Same holds for follow flow rows. + pCell->IsInFollowFlowRow() ) ) + // <-- + continue; + + SvxBoxItem aBox( pCell->GetFmt()->GetBox() ); + + INT16 nType = 0; + + //Obere Kante + if( bTopValid ) + { + if ( bFirst && bTopOver ) + { + aBox.SetLine( pTop, BOX_LINE_TOP ); + nType |= 0x0001; + } + else if ( bHoriValid ) + { + aBox.SetLine( 0, BOX_LINE_TOP ); + nType |= 0x0002; + } + } + + //Linke Kante + if ( bLeftOver ) + { + if( bLeftValid ) + { + aBox.SetLine( pLeft, BOX_LINE_LEFT ); + nType |= 0x0004; + } + } + else if( bVertValid ) + { + aBox.SetLine( pVert, BOX_LINE_LEFT ); + nType |= 0x0008; + } + + //Rechte Kante + if( bRightValid ) + { + if ( bRightOver ) + { + aBox.SetLine( pRight, BOX_LINE_RIGHT ); + nType |= 0x0010; + } + else if ( bVertValid ) + { + aBox.SetLine( 0, BOX_LINE_RIGHT ); + nType |= 0x0020; + } + } + + //Untere Kante + if ( bLast && bBottomOver ) + { + if( bBottomValid ) + { + aBox.SetLine( pBottom, BOX_LINE_BOTTOM ); + nType |= 0x0040; + } + } + else if( bHoriValid ) + { + aBox.SetLine( pHori, BOX_LINE_BOTTOM ); + nType |= 0x0080; + } + + if( pSetBox ) + { + static USHORT __READONLY_DATA aBorders[] = { + BOX_LINE_BOTTOM, BOX_LINE_TOP, + BOX_LINE_RIGHT, BOX_LINE_LEFT }; + const USHORT* pBrd = aBorders; + for( int k = 0; k < 4; ++k, ++pBrd ) + aBox.SetDistance( pSetBox->GetDistance( *pBrd ), *pBrd ); + } + + SwTableBox *pBox = (SwTableBox*)pCell->GetTabBox(); + SwFrmFmt *pNewFmt; + if ( 0 != (pNewFmt = SwTblFmtCmp::FindNewFmt( aFmtCmp, pBox->GetFrmFmt(), nType ))) + pBox->ChgFrmFmt( (SwTableBoxFmt*)pNewFmt ); + else + { + SwFrmFmt *pOld = pBox->GetFrmFmt(); + SwFrmFmt *pNew = pBox->ClaimFrmFmt(); + pNew->SetFmtAttr( aBox ); + aFmtCmp.Insert( new SwTblFmtCmp( pOld, pNew, nType ), aFmtCmp.Count()); + } + } + + bFirst = FALSE; + } + + SwHTMLTableLayout *pTableLayout = rTable.GetHTMLTableLayout(); + if( pTableLayout ) + { + SwCntntFrm* pFrm = rCursor.GetCntntNode()->GetFrm(); + SwTabFrm* pTabFrm = pFrm->ImplFindTabFrm(); + + pTableLayout->BordersChanged( + pTableLayout->GetBrowseWidthByTabFrm( *pTabFrm ), TRUE ); + } + SwTblFmtCmp::Delete( aFmtCmp ); + ::ClearFEShellTabCols(); + SetModified(); + } +} + +void lcl_SetLineStyle( SvxBorderLine *pToSet, + const Color *pColor, const SvxBorderLine *pBorderLine) +{ + if ( pBorderLine ) + { + if ( !pColor ) + { + Color aTmp( pToSet->GetColor() ); + *pToSet = *pBorderLine; + pToSet->SetColor( aTmp ); + } + else + *pToSet = *pBorderLine; + } + if ( pColor ) + pToSet->SetColor( *pColor ); +} + +void SwDoc::SetTabLineStyle( const SwCursor& rCursor, + const Color* pColor, BOOL bSetLine, + const SvxBorderLine* pBorderLine ) +{ + SwCntntNode* pCntNd = rCursor.GetPoint()->nNode.GetNode().GetCntntNode(); + SwTableNode* pTblNd = pCntNd ? pCntNd->FindTableNode() : 0; + if( !pTblNd ) + return ; + + SwLayoutFrm *pStart, *pEnd; + ::lcl_GetStartEndCell( rCursor, pStart, pEnd ); + + SwSelUnions aUnions; + ::MakeSelUnions( aUnions, pStart, pEnd ); + + if( aUnions.Count() ) + { + SwTable& rTable = pTblNd->GetTable(); + if( DoesUndo() ) + { + ClearRedo(); + AppendUndo( new SwUndoAttrTbl( *pTblNd )); + } + + for( USHORT i = 0; i < aUnions.Count(); ++i ) + { + SwSelUnion *pUnion = aUnions[i]; + SwTabFrm *pTab = pUnion->GetTable(); + SvPtrarr aCellArr( 255, 255 ); + ::lcl_CollectCells( aCellArr, pUnion->GetUnion(), pTab ); + + for ( USHORT j = 0; j < aCellArr.Count(); ++j ) + { + SwCellFrm *pCell = ( SwCellFrm* )aCellArr[j]; + + //Grundsaetzlich nichts setzen in HeadlineRepeats. + if ( pTab->IsFollow() && pTab->IsInHeadline( *pCell ) ) + continue; + + ((SwTableBox*)pCell->GetTabBox())->ClaimFrmFmt(); + SwFrmFmt *pFmt = pCell->GetFmt(); + SvxBoxItem aBox( pFmt->GetBox() ); + + if ( !pBorderLine && bSetLine ) + aBox = *(SvxBoxItem*)::GetDfltAttr( RES_BOX ); + else + { + if ( aBox.GetTop() ) + ::lcl_SetLineStyle( (SvxBorderLine*)aBox.GetTop(), + pColor, pBorderLine ); + if ( aBox.GetBottom() ) + ::lcl_SetLineStyle( (SvxBorderLine*)aBox.GetBottom(), + pColor, pBorderLine ); + if ( aBox.GetLeft() ) + ::lcl_SetLineStyle( (SvxBorderLine*)aBox.GetLeft(), + pColor, pBorderLine ); + if ( aBox.GetRight() ) + ::lcl_SetLineStyle( (SvxBorderLine*)aBox.GetRight(), + pColor, pBorderLine ); + } + pFmt->SetFmtAttr( aBox ); + } + } + + SwHTMLTableLayout *pTableLayout = rTable.GetHTMLTableLayout(); + if( pTableLayout ) + { + SwCntntFrm* pFrm = rCursor.GetCntntNode()->GetFrm(); + SwTabFrm* pTabFrm = pFrm->ImplFindTabFrm(); + + pTableLayout->BordersChanged( + pTableLayout->GetBrowseWidthByTabFrm( *pTabFrm ), TRUE ); + } + ::ClearFEShellTabCols(); + SetModified(); + } +} + +void SwDoc::GetTabBorders( const SwCursor& rCursor, SfxItemSet& rSet ) const +{ + SwCntntNode* pCntNd = rCursor.GetPoint()->nNode.GetNode().GetCntntNode(); + SwTableNode* pTblNd = pCntNd ? pCntNd->FindTableNode() : 0; + if( !pTblNd ) + return ; + + SwLayoutFrm *pStart, *pEnd; + ::lcl_GetStartEndCell( rCursor, pStart, pEnd ); + + SwSelUnions aUnions; + ::MakeSelUnions( aUnions, pStart, pEnd ); + + if( aUnions.Count() ) + { + SvxBoxItem aSetBox ((const SvxBoxItem &) rSet.Get(RES_BOX )); + SvxBoxInfoItem aSetBoxInfo((const SvxBoxInfoItem&) rSet.Get(SID_ATTR_BORDER_INNER)); + + BOOL bTopSet = FALSE, + bBottomSet = FALSE, + bLeftSet = FALSE, + bRightSet = FALSE, + bHoriSet = FALSE, + bVertSet = FALSE, + bDistanceSet = FALSE; + + aSetBoxInfo.ResetFlags(); + + for ( USHORT i = 0; i < aUnions.Count(); ++i ) + { + SwSelUnion *pUnion = aUnions[i]; + const SwTabFrm *pTab = pUnion->GetTable(); + const SwRect &rUnion = pUnion->GetUnion(); + const BOOL bFirst = i == 0 ? TRUE : FALSE; + const BOOL bLast = i == aUnions.Count() - 1 ? TRUE : FALSE; + + SvPtrarr aCellArr( 255, 255 ); + ::lcl_CollectCells( aCellArr, rUnion, (SwTabFrm*)pTab ); + + for ( USHORT j = 0; j < aCellArr.Count(); ++j ) + { + const SwCellFrm *pCell = (const SwCellFrm*)aCellArr[j]; + const sal_Bool bVert = pTab->IsVertical(); + const sal_Bool bRTL = pTab->IsRightToLeft(); + sal_Bool bTopOver, bLeftOver, bRightOver, bBottomOver; + if ( bVert ) + { + bTopOver = pCell->Frm().Right() >= rUnion.Right(); + bLeftOver = pCell->Frm().Top() <= rUnion.Top(); + bRightOver = pCell->Frm().Bottom() >= rUnion.Bottom(); + bBottomOver = pCell->Frm().Left() <= rUnion.Left(); + } + else + { + bTopOver = pCell->Frm().Top() <= rUnion.Top(); + bLeftOver = pCell->Frm().Left() <= rUnion.Left(); + bRightOver = pCell->Frm().Right() >= rUnion.Right(); + bBottomOver = pCell->Frm().Bottom() >= rUnion.Bottom(); + } + + if ( bRTL ) + { + sal_Bool bTmp = bRightOver; + bRightOver = bLeftOver; + bLeftOver = bTmp; + } + + const SwFrmFmt *pFmt = pCell->GetFmt(); + const SvxBoxItem &rBox = pFmt->GetBox(); + + //Obere Kante + if ( bFirst && bTopOver ) + { + if (aSetBoxInfo.IsValid(VALID_TOP)) + { + if ( !bTopSet ) + { bTopSet = TRUE; + aSetBox.SetLine( rBox.GetTop(), BOX_LINE_TOP ); + } + else if ((aSetBox.GetTop() && rBox.GetTop() && + !(*aSetBox.GetTop() == *rBox.GetTop())) || + ((!aSetBox.GetTop()) ^ (!rBox.GetTop()))) // XOR-Ausdruck ist TRUE, wenn genau einer der beiden Pointer 0 ist + { + aSetBoxInfo.SetValid(VALID_TOP, FALSE ); + aSetBox.SetLine( 0, BOX_LINE_TOP ); + } + } + } + + //Linke Kante + if ( bLeftOver ) + { + if (aSetBoxInfo.IsValid(VALID_LEFT)) + { + if ( !bLeftSet ) + { bLeftSet = TRUE; + aSetBox.SetLine( rBox.GetLeft(), BOX_LINE_LEFT ); + } + else if ((aSetBox.GetLeft() && rBox.GetLeft() && + !(*aSetBox.GetLeft() == *rBox.GetLeft())) || + ((!aSetBox.GetLeft()) ^ (!rBox.GetLeft()))) + { + aSetBoxInfo.SetValid(VALID_LEFT, FALSE ); + aSetBox.SetLine( 0, BOX_LINE_LEFT ); + } + } + } + else + { + if (aSetBoxInfo.IsValid(VALID_VERT)) + { + if ( !bVertSet ) + { bVertSet = TRUE; + aSetBoxInfo.SetLine( rBox.GetLeft(), BOXINFO_LINE_VERT ); + } + else if ((aSetBoxInfo.GetVert() && rBox.GetLeft() && + !(*aSetBoxInfo.GetVert() == *rBox.GetLeft())) || + ((!aSetBoxInfo.GetVert()) ^ (!rBox.GetLeft()))) + { aSetBoxInfo.SetValid( VALID_VERT, FALSE ); + aSetBoxInfo.SetLine( 0, BOXINFO_LINE_VERT ); + } + } + } + + //Rechte Kante + if ( aSetBoxInfo.IsValid(VALID_RIGHT) && bRightOver ) + { + if ( !bRightSet ) + { bRightSet = TRUE; + aSetBox.SetLine( rBox.GetRight(), BOX_LINE_RIGHT ); + } + else if ((aSetBox.GetRight() && rBox.GetRight() && + !(*aSetBox.GetRight() == *rBox.GetRight())) || + (!aSetBox.GetRight() ^ !rBox.GetRight())) + { aSetBoxInfo.SetValid( VALID_RIGHT, FALSE ); + aSetBox.SetLine( 0, BOX_LINE_RIGHT ); + } + } + + //Untere Kante + if ( bLast && bBottomOver ) + { + if ( aSetBoxInfo.IsValid(VALID_BOTTOM) ) + { + if ( !bBottomSet ) + { bBottomSet = TRUE; + aSetBox.SetLine( rBox.GetBottom(), BOX_LINE_BOTTOM ); + } + else if ((aSetBox.GetBottom() && rBox.GetBottom() && + !(*aSetBox.GetBottom() == *rBox.GetBottom())) || + (!aSetBox.GetBottom() ^ !rBox.GetBottom())) + { aSetBoxInfo.SetValid( VALID_BOTTOM, FALSE ); + aSetBox.SetLine( 0, BOX_LINE_BOTTOM ); + } + } + } + //in allen Zeilen ausser der letzten werden die + // horiz. Linien aus der Bottom-Linie entnommen + else + { + if (aSetBoxInfo.IsValid(VALID_HORI)) + { + if ( !bHoriSet ) + { bHoriSet = TRUE; + aSetBoxInfo.SetLine( rBox.GetBottom(), BOXINFO_LINE_HORI ); + } + else if ((aSetBoxInfo.GetHori() && rBox.GetBottom() && + !(*aSetBoxInfo.GetHori() == *rBox.GetBottom())) || + ((!aSetBoxInfo.GetHori()) ^ (!rBox.GetBottom()))) + { + aSetBoxInfo.SetValid( VALID_HORI, FALSE ); + aSetBoxInfo.SetLine( 0, BOXINFO_LINE_HORI ); + } + } + } + + // Abstand zum Text + if (aSetBoxInfo.IsValid(VALID_DISTANCE)) + { + static USHORT __READONLY_DATA aBorders[] = { + BOX_LINE_BOTTOM, BOX_LINE_TOP, + BOX_LINE_RIGHT, BOX_LINE_LEFT }; + const USHORT* pBrd = aBorders; + + if( !bDistanceSet ) // bei 1. Durchlauf erstmal setzen + { + bDistanceSet = TRUE; + for( int k = 0; k < 4; ++k, ++pBrd ) + aSetBox.SetDistance( rBox.GetDistance( *pBrd ), + *pBrd ); + } + else + { + for( int k = 0; k < 4; ++k, ++pBrd ) + if( aSetBox.GetDistance( *pBrd ) != + rBox.GetDistance( *pBrd ) ) + { + aSetBoxInfo.SetValid( VALID_DISTANCE, FALSE ); + aSetBox.SetDistance( (USHORT) 0 ); + break; + } + } + } + } + } + rSet.Put( aSetBox ); + rSet.Put( aSetBoxInfo ); + } +} + +/*********************************************************************** +#* Class : SwDoc +#* Methoden : SetBoxAttr +#* Datum : MA 18. Dec. 96 +#* Update : JP 29.04.98 +#***********************************************************************/ +void SwDoc::SetBoxAttr( const SwCursor& rCursor, const SfxPoolItem &rNew ) +{ + SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode(); + SwSelBoxes aBoxes; + if( pTblNd && ::lcl_GetBoxSel( rCursor, aBoxes, TRUE ) ) + { + SwTable& rTable = pTblNd->GetTable(); + if( DoesUndo() ) + { + ClearRedo(); + AppendUndo( new SwUndoAttrTbl( *pTblNd )); + } + + SvPtrarr aFmtCmp( Max( BYTE(255), BYTE(aBoxes.Count()) ), 255 ); + for ( USHORT i = 0; i < aBoxes.Count(); ++i ) + { + SwTableBox *pBox = aBoxes[i]; + + SwFrmFmt *pNewFmt; + if ( 0 != (pNewFmt = SwTblFmtCmp::FindNewFmt( aFmtCmp, pBox->GetFrmFmt(), 0 ))) + pBox->ChgFrmFmt( (SwTableBoxFmt*)pNewFmt ); + else + { + SwFrmFmt *pOld = pBox->GetFrmFmt(); + SwFrmFmt *pNew = pBox->ClaimFrmFmt(); + pNew->SetFmtAttr( rNew ); + aFmtCmp.Insert( new SwTblFmtCmp( pOld, pNew, 0 ), aFmtCmp.Count()); + } + } + + SwHTMLTableLayout *pTableLayout = rTable.GetHTMLTableLayout(); + if( pTableLayout ) + { + SwCntntFrm* pFrm = rCursor.GetCntntNode()->GetFrm(); + SwTabFrm* pTabFrm = pFrm->ImplFindTabFrm(); + + pTableLayout->Resize( + pTableLayout->GetBrowseWidthByTabFrm( *pTabFrm ), TRUE ); + } + SwTblFmtCmp::Delete( aFmtCmp ); + SetModified(); + } +} + +/*********************************************************************** +#* Class : SwDoc +#* Methoden : GetBoxAttr() +#* Datum : MA 01. Jun. 93 +#* Update : JP 29.04.98 +#***********************************************************************/ + +BOOL SwDoc::GetBoxAttr( const SwCursor& rCursor, SfxPoolItem& rToFill ) const +{ + BOOL bRet = FALSE; + SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode(); + SwSelBoxes aBoxes; + if( pTblNd && lcl_GetBoxSel( rCursor, aBoxes )) + { + bRet = TRUE; + BOOL bOneFound = FALSE; + const USHORT nWhich = rToFill.Which(); + for( USHORT i = 0; i < aBoxes.Count(); ++i ) + { + switch ( nWhich ) + { + case RES_BACKGROUND: + { + const SvxBrushItem &rBack = + aBoxes[i]->GetFrmFmt()->GetBackground(); + if( !bOneFound ) + { + (SvxBrushItem&)rToFill = rBack; + bOneFound = TRUE; + } + else if( rToFill != rBack ) + bRet = FALSE; + } + break; + + case RES_FRAMEDIR: + { + const SvxFrameDirectionItem& rDir = + aBoxes[i]->GetFrmFmt()->GetFrmDir(); + if( !bOneFound ) + { + (SvxFrameDirectionItem&)rToFill = rDir; + bOneFound = TRUE; + } + else if( rToFill != rDir ) + bRet = FALSE; + } + } + + if ( FALSE == bRet ) + break; + } + } + return bRet; +} + +/*********************************************************************** +#* Class : SwDoc +#* Methoden : SetBoxAlign, SetBoxAlign +#* Datum : MA 18. Dec. 96 +#* Update : JP 29.04.98 +#***********************************************************************/ +void SwDoc::SetBoxAlign( const SwCursor& rCursor, USHORT nAlign ) +{ + ASSERT( nAlign == text::VertOrientation::NONE || + nAlign == text::VertOrientation::CENTER || + nAlign == text::VertOrientation::BOTTOM, "wrong alignment" ); + SwFmtVertOrient aVertOri( 0, nAlign ); + SetBoxAttr( rCursor, aVertOri ); +} + +USHORT SwDoc::GetBoxAlign( const SwCursor& rCursor ) const +{ + USHORT nAlign = USHRT_MAX; + SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode(); + SwSelBoxes aBoxes; + if( pTblNd && ::lcl_GetBoxSel( rCursor, aBoxes )) + for( USHORT i = 0; i < aBoxes.Count(); ++i ) + { + const SwFmtVertOrient &rOri = + aBoxes[i]->GetFrmFmt()->GetVertOrient(); + if( USHRT_MAX == nAlign ) + nAlign = static_cast<USHORT>(rOri.GetVertOrient()); + else if( rOri.GetVertOrient() != nAlign ) + { + nAlign = USHRT_MAX; + break; + } + } + return nAlign; +} + + +/*********************************************************************** +#* Class : SwDoc +#* Methoden : AdjustCellWidth() +#* Datum : MA 20. Feb. 95 +#* Update : JP 29.04.98 +#***********************************************************************/ +USHORT lcl_CalcCellFit( const SwLayoutFrm *pCell ) +{ + SwTwips nRet = 0; + const SwFrm *pFrm = pCell->Lower(); //Die ganze Zelle. + SWRECTFN( pCell ) + while ( pFrm ) + { + const SwTwips nAdd = (pFrm->Frm().*fnRect->fnGetWidth)() - + (pFrm->Prt().*fnRect->fnGetWidth)(); + + // --> FME 2005-12-02 #127801# pFrm does not necessarily have to be a SwTxtFrm! + const SwTwips nCalcFitToContent = pFrm->IsTxtFrm() ? + ((SwTxtFrm*)pFrm)->CalcFitToContent() : + (pFrm->Prt().*fnRect->fnGetWidth)(); + // <-- + + nRet = Max( nRet, nCalcFitToContent + nAdd ); + pFrm = pFrm->GetNext(); + } + //Umrandung und linker/rechter Rand wollen mit kalkuliert werden. + nRet += (pCell->Frm().*fnRect->fnGetWidth)() - + (pCell->Prt().*fnRect->fnGetWidth)(); + + //Um Rechenungenauikeiten, die spaeter bei SwTable::SetTabCols enstehen, + //auszugleichen, addieren wir noch ein bischen. + nRet += COLFUZZY; + return (USHORT)Max( long(MINLAY), nRet ); +} + +/*Die Zelle ist in der Selektion, wird aber nicht von den TabCols beschrieben. + *Das bedeutet, dass die Zelle aufgrund der zweidimensionalen Darstellung von + *anderen Zellen "geteilt" wurde. Wir muessen also den Wunsch- bzw. Minimalwert + *der Zelle auf die Spalten, durch die sie geteilt wurde verteilen. + * + *Dazu sammeln wir zuerst die Spalten - nicht die Spaltentrenner! - ein, die + *sich mit der Zelle ueberschneiden. Den Wunschwert der Zelle verteilen wir + *dann anhand des Betrages der Ueberschneidung auf die Zellen. + *Wenn eine Zelle bereits einen groesseren Wunschwert angemeldet hat, so bleibt + *dieser erhalten, kleinere Wuensche werden ueberschrieben. + */ + +void lcl_CalcSubColValues( SvUShorts &rToFill, const SwTabCols &rCols, + const SwLayoutFrm *pCell, const SwLayoutFrm *pTab, + BOOL bWishValues ) +{ + const USHORT nWish = bWishValues ? + ::lcl_CalcCellFit( pCell ) : + MINLAY + USHORT(pCell->Frm().Width() - pCell->Prt().Width()); + + SWRECTFN( pTab ) + + for ( USHORT i = 0 ; i <= rCols.Count(); ++i ) + { + long nColLeft = i == 0 ? rCols.GetLeft() : rCols[i-1]; + long nColRight = i == rCols.Count() ? rCols.GetRight() : rCols[i]; + nColLeft += rCols.GetLeftMin(); + nColRight += rCols.GetLeftMin(); + + //Werte auf die Verhaeltnisse der Tabelle (Follows) anpassen. + if ( rCols.GetLeftMin() != USHORT((pTab->Frm().*fnRect->fnGetLeft)()) ) + { + const long nDiff = (pTab->Frm().*fnRect->fnGetLeft)() - rCols.GetLeftMin(); + nColLeft += nDiff; + nColRight += nDiff; + } + const long nCellLeft = (pCell->Frm().*fnRect->fnGetLeft)(); + const long nCellRight = (pCell->Frm().*fnRect->fnGetRight)(); + + //Ueberschneidungsbetrag ermitteln. + long nWidth = 0; + if ( nColLeft <= nCellLeft && nColRight >= (nCellLeft+COLFUZZY) ) + nWidth = nColRight - nCellLeft; + else if ( nColLeft <= (nCellRight-COLFUZZY) && nColRight >= nCellRight ) + nWidth = nCellRight - nColLeft; + else if ( nColLeft >= nCellLeft && nColRight <= nCellRight ) + nWidth = nColRight - nColLeft; + if ( nWidth && pCell->Frm().Width() ) + { + long nTmp = nWidth * nWish / pCell->Frm().Width(); + if ( USHORT(nTmp) > rToFill[i] ) + rToFill[i] = USHORT(nTmp); + } + } +} + +/*Besorgt neue Werte zu Einstellung der TabCols. + *Es wird nicht ueber die Eintrage in den TabCols itereriert, sondern + *quasi ueber die Zwischenraeume, die ja die Zellen beschreiben. + * + *bWishValues == TRUE: Es werden zur aktuellen Selektion bzw. zur aktuellen + * Zelle die Wunschwerte aller betroffen Zellen ermittelt. + * Sind mehrere Zellen in einer Spalte, so wird der + * groesste Wunschwert als Ergebnis geliefert. + * Fuer die TabCol-Eintraege, zu denen keine Zellen + * ermittelt wurden, werden 0-en eingetragen. + * + *bWishValues == FALSE: Die Selektion wird senkrecht ausgedehnt. Zu jeder + * Spalte in den TabCols, die sich mit der Selektion + * schneidet wird der Minimalwert ermittelt. + */ + +void lcl_CalcColValues( SvUShorts &rToFill, const SwTabCols &rCols, + const SwLayoutFrm *pStart, const SwLayoutFrm *pEnd, + BOOL bWishValues ) +{ + SwSelUnions aUnions; + ::MakeSelUnions( aUnions, pStart, pEnd, + bWishValues ? nsSwTblSearchType::TBLSEARCH_NONE : nsSwTblSearchType::TBLSEARCH_COL ); + + for ( USHORT i2 = 0; i2 < aUnions.Count(); ++i2 ) + { + SwSelUnion *pSelUnion = aUnions[i2]; + const SwTabFrm *pTab = pSelUnion->GetTable(); + const SwRect &rUnion = pSelUnion->GetUnion(); + + SWRECTFN( pTab ) + sal_Bool bRTL = pTab->IsRightToLeft(); + + const SwLayoutFrm *pCell = pTab->FirstCell(); + do + { + if ( pCell->IsCellFrm() && pCell->FindTabFrm() == pTab && ::IsFrmInTblSel( rUnion, pCell ) ) + { + const long nCLeft = (pCell->Frm().*fnRect->fnGetLeft)(); + const long nCRight = (pCell->Frm().*fnRect->fnGetRight)(); + + BOOL bNotInCols = TRUE; + + for ( USHORT i = 0; i <= rCols.Count(); ++i ) + { + USHORT nFit = rToFill[i]; + long nColLeft = i == 0 ? rCols.GetLeft() : rCols[i-1]; + long nColRight = i == rCols.Count() ? rCols.GetRight() : rCols[i]; + + if ( bRTL ) + { + long nTmpRight = nColRight; + nColRight = rCols.GetRight() - nColLeft; + nColLeft = rCols.GetRight() - nTmpRight; + } + + nColLeft += rCols.GetLeftMin(); + nColRight += rCols.GetLeftMin(); + + //Werte auf die Verhaeltnisse der Tabelle (Follows) anpassen. + long nLeftA = nColLeft; + long nRightA = nColRight; + if ( rCols.GetLeftMin() != USHORT((pTab->Frm().*fnRect->fnGetLeft)()) ) + { + const long nDiff = (pTab->Frm().*fnRect->fnGetLeft)() - rCols.GetLeftMin(); + nLeftA += nDiff; + nRightA += nDiff; + } + + //Wir wollen nicht allzu genau hinsehen. + if ( ::IsSame(nCLeft, nLeftA) && ::IsSame(nCRight, nRightA)) + { + bNotInCols = FALSE; + if ( bWishValues ) + { + const USHORT nWish = ::lcl_CalcCellFit( pCell ); + if ( nWish > nFit ) + nFit = nWish; + } + else + { const USHORT nMin = MINLAY + USHORT(pCell->Frm().Width() - + pCell->Prt().Width()); + if ( !nFit || nMin < nFit ) + nFit = nMin; + } + if ( rToFill[i] < nFit ) + rToFill[i] = nFit; + } + } + if ( bNotInCols ) + ::lcl_CalcSubColValues( rToFill, rCols, pCell, pTab, bWishValues ); + } + do { + pCell = pCell->GetNextLayoutLeaf(); + }while( pCell && pCell->Frm().Width() == 0 ); + } while ( pCell && pTab->IsAnLower( pCell ) ); + } +} + + +void SwDoc::AdjustCellWidth( const SwCursor& rCursor, BOOL bBalance ) +{ + // pruefe ob vom aktuellen Crsr der Point/Mark in einer Tabelle stehen + SwCntntNode* pCntNd = rCursor.GetPoint()->nNode.GetNode().GetCntntNode(); + SwTableNode* pTblNd = pCntNd ? pCntNd->FindTableNode() : 0; + if( !pTblNd ) + return ; + + SwLayoutFrm *pStart, *pEnd; + ::lcl_GetStartEndCell( rCursor, pStart, pEnd ); + + //TabCols besorgen, den ueber diese stellen wir die Tabelle neu ein. + SwFrm* pBoxFrm = pStart; + while( pBoxFrm && !pBoxFrm->IsCellFrm() ) + pBoxFrm = pBoxFrm->GetUpper(); + + if ( !pBoxFrm ) + return; // robust + + SwTabCols aTabCols; + GetTabCols( aTabCols, 0, (SwCellFrm*)pBoxFrm ); + + if ( ! aTabCols.Count() ) + return; + + const BYTE nTmp = (BYTE)Max( USHORT(255), USHORT(aTabCols.Count() + 1) ); + SvUShorts aWish( nTmp, nTmp ), + aMins( nTmp, nTmp ); + USHORT i; + + for ( i = 0; i <= aTabCols.Count(); ++i ) + { + aWish.Insert( USHORT(0), aWish.Count() ); + aMins.Insert( USHORT(0), aMins.Count() ); + } + ::lcl_CalcColValues( aWish, aTabCols, pStart, pEnd, TRUE ); + + //Es ist Robuster wenn wir die Min-Werte fuer die ganze Tabelle berechnen. + const SwTabFrm *pTab = pStart->ImplFindTabFrm(); + pStart = (SwLayoutFrm*)pTab->FirstCell(); + pEnd = (SwLayoutFrm*)pTab->FindLastCntnt()->GetUpper(); + while( !pEnd->IsCellFrm() ) + pEnd = pEnd->GetUpper(); + ::lcl_CalcColValues( aMins, aTabCols, pStart, pEnd, FALSE ); + + if( bBalance ) + { + //Alle Spalten, die makiert sind haben jetzt einen Wunschwert + //eingtragen. Wir addieren die aktuellen Werte, teilen das Ergebnis + //durch die Anzahl und haben eine Wunschwert fuer den ausgleich. + USHORT nWish = 0, nCnt = 0; + for ( i = 0; i <= aTabCols.Count(); ++i ) + { + int nDiff = aWish[i]; + if ( nDiff ) + { + if ( i == 0 ) + nWish = static_cast<USHORT>( nWish + aTabCols[i] - aTabCols.GetLeft() ); + else if ( i == aTabCols.Count() ) + nWish = static_cast<USHORT>(nWish + aTabCols.GetRight() - aTabCols[i-1] ); + else + nWish = static_cast<USHORT>(nWish + aTabCols[i] - aTabCols[i-1] ); + ++nCnt; + } + } + nWish = nWish / nCnt; + for ( i = 0; i < aWish.Count(); ++i ) + if ( aWish[i] ) + aWish[i] = nWish; + } + + const USHORT nOldRight = static_cast<USHORT>(aTabCols.GetRight()); + + //Um die Impl. einfach zu gestalten, aber trotzdem in den meissten Faellen + //den Platz richtig auszunutzen laufen wir zweimal. + //Problem: Erste Spalte wird breiter, die anderen aber erst danach + //schmaler. Die Wunschbreite der ersten Spalte wuerde abgelehnt, weil + //mit ihr die max. Breite der Tabelle ueberschritten wuerde. + for ( USHORT k= 0; k < 2; ++k ) + { + for ( i = 0; i <= aTabCols.Count(); ++i ) + { + int nDiff = aWish[i]; + if ( nDiff ) + { + int nMin = aMins[i]; + if ( nMin > nDiff ) + nDiff = nMin; + + if ( i == 0 ) + { + if( aTabCols.Count() ) + nDiff -= aTabCols[0] - aTabCols.GetLeft(); + else + nDiff -= aTabCols.GetRight() - aTabCols.GetLeft(); + } + else if ( i == aTabCols.Count() ) + nDiff -= aTabCols.GetRight() - aTabCols[i-1]; + else + nDiff -= aTabCols[i] - aTabCols[i-1]; + + long nTabRight = aTabCols.GetRight() + nDiff; + + //Wenn die Tabelle zu breit wuerde begrenzen wir die Anpassung + //auf das erlaubte Maximum. + if ( !bBalance && nTabRight > aTabCols.GetRightMax() ) + { + const long nTmpD = nTabRight - aTabCols.GetRightMax(); + nDiff -= nTmpD; + nTabRight -= nTmpD; + } + for ( USHORT i2 = i; i2 < aTabCols.Count(); ++i2 ) + aTabCols[i2] += nDiff; + aTabCols.SetRight( nTabRight ); + } + } + } + + const USHORT nNewRight = static_cast<USHORT>(aTabCols.GetRight()); + + SwFrmFmt *pFmt = pTblNd->GetTable().GetFrmFmt(); + const sal_Int16 nOriHori = pFmt->GetHoriOrient().GetHoriOrient(); + + //So, die richtige Arbeit koennen wir jetzt der SwTable ueberlassen. + SetTabCols( aTabCols, FALSE, 0, (SwCellFrm*)pBoxFrm ); + + // i54248: lijian/fme + // alignment might have been changed in SetTabCols, restore old value: + const SwFmtHoriOrient &rHori = pFmt->GetHoriOrient(); + SwFmtHoriOrient aHori( rHori ); + if ( aHori.GetHoriOrient() != nOriHori ) + { + aHori.SetHoriOrient( nOriHori ); + pFmt->SetFmtAttr( aHori ); + } + + //Bei Automatischer Breite wird auf Linksbuendig umgeschaltet. + //Bei Randattributen wird der Rechte Rand angepasst. + if( !bBalance && nNewRight < nOldRight ) + { + if( aHori.GetHoriOrient() == text::HoriOrientation::FULL ) + { + aHori.SetHoriOrient( text::HoriOrientation::LEFT ); + pFmt->SetFmtAttr( aHori ); + } + } + + SetModified(); +} + |