/************************************************************** * * 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 "hintids.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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" #include "switerator.hxx" #include using namespace ::com::sun::star; extern void ClearFEShellTabCols(); //siehe auch swtable.cxx #define COLFUZZY 20L inline sal_Bool IsSame( long nA, long nB ) { return Abs(nA-nB) <= COLFUZZY; } class SwTblFmtCmp { public: SwFrmFmt *pOld, *pNew; sal_Int16 nType; SwTblFmtCmp( SwFrmFmt *pOld, SwFrmFmt *pNew, sal_Int16 nType ); static SwFrmFmt *FindNewFmt( SvPtrarr &rArr, SwFrmFmt*pOld, sal_Int16 nType ); static void Delete( SvPtrarr &rArr ); }; SwTblFmtCmp::SwTblFmtCmp( SwFrmFmt *pO, SwFrmFmt *pN, sal_Int16 nT ) : pOld ( pO ), pNew ( pN ), nType( nT ) { } SwFrmFmt *SwTblFmtCmp::FindNewFmt( SvPtrarr &rArr, SwFrmFmt *pOld, sal_Int16 nType ) { for ( sal_uInt16 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 ( sal_uInt16 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( sal_False ), "Tabselection nicht auf Cnt." ); Point aPtPos, aMkPos; const SwShellCrsr* pShCrsr = dynamic_cast(&rCrsr); if( pShCrsr ) { aPtPos = pShCrsr->GetPtPos(); aMkPos = pShCrsr->GetMkPos(); } // robust: SwCntntNode* pPointNd = rCrsr.GetCntntNode(); SwCntntNode* pMarkNd = rCrsr.GetCntntNode(sal_False); SwFrm* pPointFrm = pPointNd ? pPointNd->getLayoutFrm( pPointNd->GetDoc()->GetCurrentLayout(), &aPtPos ) : 0; SwFrm* pMarkFrm = pMarkNd ? pMarkNd->getLayoutFrm( pMarkNd->GetDoc()->GetCurrentLayout(), &aMkPos ) : 0; prStart = pPointFrm ? pPointFrm->GetUpper() : 0; prEnd = pMarkFrm ? pMarkFrm->GetUpper() : 0; } sal_Bool lcl_GetBoxSel( const SwCursor& rCursor, SwSelBoxes& rBoxes, sal_Bool bAllCrsr = sal_False ) { const SwTableCursor* pTblCrsr = dynamic_cast(&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() ); } //----------------------------------------------------------------------------- sal_Bool lcl_IsAnLower( const SwTableLine *pLine, const SwTableLine *pAssumed ) { const SwTableLine *pTmp = pAssumed->GetUpper() ? pAssumed->GetUpper()->GetUpper() : 0; while ( pTmp ) { if ( pTmp == pLine ) return sal_True; pTmp = pTmp->GetUpper() ? pTmp->GetUpper()->GetUpper() : 0; } return sal_False; } //----------------------------------------------------------------------------- struct LinesAndTable { SvPtrarr &rLines; const SwTable &rTable; sal_Bool bInsertLines; LinesAndTable( SvPtrarr &rL, const SwTable &rTbl ) : rLines( rL ), rTable( rTbl ), bInsertLines( sal_True ) {} }; sal_Bool _FindLine( const _FndLine*& rpLine, void* pPara ); sal_Bool _FindBox( const _FndBox*& rpBox, void* pPara ) { if ( rpBox->GetLines().Count() ) { ((LinesAndTable*)pPara)->bInsertLines = sal_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 ( sal_uInt16 i = 0; i < rLines.Count(); ++i ) ::InsertLine( ((LinesAndTable*)pPara)->rLines, (SwTableLine*)rLines[i] ); } else ((LinesAndTable*)pPara)->bInsertLines = sal_False; } } else if ( rpBox->GetBox() ) ::InsertLine( ((LinesAndTable*)pPara)->rLines, (SwTableLine*)rpBox->GetBox()->GetUpper() ); return sal_True; } sal_Bool _FindLine( const _FndLine*& rpLine, void* pPara ) { ((_FndLine*)rpLine)->GetBoxes().ForEach( _FindBox, pPara ); return sal_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 ( sal_uInt16 i = 0; i < rArr.Count(); ++i ) { SwTableLine *pUpLine = (SwTableLine*)rArr[i]; for ( sal_uInt16 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 ( sal_uInt16 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 ( sal_uInt16 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 (GetIDocumentUndoRedo().DoesUndo()) { GetIDocumentUndoRedo().AppendUndo(new SwUndoAttrTbl(*pTblNd)); } SvPtrarr aFmtCmp( Max( sal_uInt8(255), sal_uInt8(aRowArr.Count()) ), 255 ); for( sal_uInt16 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 ( sal_uInt16 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 (GetIDocumentUndoRedo().DoesUndo()) { GetIDocumentUndoRedo().AppendUndo(new SwUndoAttrTbl(*pTblNd)); } SvPtrarr aFmtCmp( Max( sal_uInt8(255), sal_uInt8(aRowArr.Count()) ), 255 ); for ( sal_uInt16 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 ( sal_uInt16 i = 1; i < aRowArr.Count() && rpSz; ++i ) { if ( *rpSz != ((SwTableLine*)aRowArr[i])->GetFrmFmt()->GetFrmSize() ) rpSz = 0; } if ( rpSz ) rpSz = new SwFmtFrmSize( *rpSz ); } } } sal_Bool SwDoc::BalanceRowHeight( const SwCursor& rCursor, sal_Bool bTstOnly ) { sal_Bool bRet = sal_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; sal_uInt16 i; for ( i = 0; i < aRowArr.Count(); ++i ) { SwIterator aIter( *((SwTableLine*)aRowArr[i])->GetFrmFmt() ); SwFrm* pFrm = aIter.First(); while ( pFrm ) { nHeight = Max( nHeight, pFrm->Frm().Height() ); pFrm = aIter.Next(); } } SwFmtFrmSize aNew( ATT_MIN_SIZE, 0, nHeight ); if (GetIDocumentUndoRedo().DoesUndo()) { GetIDocumentUndoRedo().AppendUndo( new SwUndoAttrTbl(*pTblNd)); } SvPtrarr aFmtCmp( Max( sal_uInt8(255), sal_uInt8(aRowArr.Count()) ), 255 ); for( i = 0; i < aRowArr.Count(); ++i ) ::lcl_ProcessRowSize( aFmtCmp, (SwTableLine*)aRowArr[i], aNew ); SwTblFmtCmp::Delete( aFmtCmp ); SetModified(); } bRet = sal_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 (GetIDocumentUndoRedo().DoesUndo()) { GetIDocumentUndoRedo().AppendUndo(new SwUndoAttrTbl(*pTblNd)); } SvPtrarr aFmtCmp( Max( sal_uInt8(255), sal_uInt8(aRowArr.Count()) ), 255 ); for( sal_uInt16 i = 0; i < aRowArr.Count(); ++i ) ::lcl_ProcessRowAttr( aFmtCmp, (SwTableLine*)aRowArr[i], rNew ); SwTblFmtCmp::Delete( aFmtCmp ); SetModified(); } } } /****************************************************************************** * SwTwips SwDoc::GetRowBackground() const ******************************************************************************/ sal_Bool SwDoc::GetRowBackground( const SwCursor& rCursor, SvxBrushItem &rToFill ) const { sal_Bool bRet = sal_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 = sal_True; for ( sal_uInt16 i = 1; i < aRowArr.Count(); ++i ) if ( rToFill != ((SwTableLine*)aRowArr[i])->GetFrmFmt()->GetBackground() ) { bRet = sal_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 (GetIDocumentUndoRedo().DoesUndo()) { GetIDocumentUndoRedo().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; sal_Bool bHoriValid = sal_True, bVertValid = sal_True, bTopValid = sal_True, bBottomValid = sal_True, bLeftValid = sal_True, bRightValid = sal_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, sal_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, sal_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 = sal_False; pSetBox = 0; } sal_Bool bFirst = sal_True; for ( sal_uInt16 i = 0; i < aUnions.Count(); ++i ) { SwSelUnion *pUnion = aUnions[i]; SwTabFrm *pTab = pUnion->GetTable(); const SwRect &rUnion = pUnion->GetUnion(); const sal_Bool bLast = i == aUnions.Count() - 1 ? sal_True : sal_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 ( sal_uInt16 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() ); sal_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 sal_uInt16 __READONLY_DATA aBorders[] = { BOX_LINE_BOTTOM, BOX_LINE_TOP, BOX_LINE_RIGHT, BOX_LINE_LEFT }; const sal_uInt16* 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 = sal_False; } SwHTMLTableLayout *pTableLayout = rTable.GetHTMLTableLayout(); if( pTableLayout ) { SwCntntFrm* pFrm = rCursor.GetCntntNode()->getLayoutFrm( rCursor.GetCntntNode()->GetDoc()->GetCurrentLayout() ); SwTabFrm* pTabFrm = pFrm->ImplFindTabFrm(); pTableLayout->BordersChanged( pTableLayout->GetBrowseWidthByTabFrm( *pTabFrm ), sal_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, sal_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 (GetIDocumentUndoRedo().DoesUndo()) { GetIDocumentUndoRedo().AppendUndo(new SwUndoAttrTbl(*pTblNd)); } for( sal_uInt16 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 ( sal_uInt16 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()->getLayoutFrm( rCursor.GetCntntNode()->GetDoc()->GetCurrentLayout() ); SwTabFrm* pTabFrm = pFrm->ImplFindTabFrm(); pTableLayout->BordersChanged( pTableLayout->GetBrowseWidthByTabFrm( *pTabFrm ), sal_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)); sal_Bool bTopSet = sal_False, bBottomSet = sal_False, bLeftSet = sal_False, bRightSet = sal_False, bHoriSet = sal_False, bVertSet = sal_False, bDistanceSet = sal_False; aSetBoxInfo.ResetFlags(); for ( sal_uInt16 i = 0; i < aUnions.Count(); ++i ) { SwSelUnion *pUnion = aUnions[i]; const SwTabFrm *pTab = pUnion->GetTable(); const SwRect &rUnion = pUnion->GetUnion(); const sal_Bool bFirst = i == 0 ? sal_True : sal_False; const sal_Bool bLast = i == aUnions.Count() - 1 ? sal_True : sal_False; SvPtrarr aCellArr( 255, 255 ); ::lcl_CollectCells( aCellArr, rUnion, (SwTabFrm*)pTab ); for ( sal_uInt16 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 = sal_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 sal_True, wenn genau einer der beiden Pointer 0 ist { aSetBoxInfo.SetValid(VALID_TOP, sal_False ); aSetBox.SetLine( 0, BOX_LINE_TOP ); } } } //Linke Kante if ( bLeftOver ) { if (aSetBoxInfo.IsValid(VALID_LEFT)) { if ( !bLeftSet ) { bLeftSet = sal_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, sal_False ); aSetBox.SetLine( 0, BOX_LINE_LEFT ); } } } else { if (aSetBoxInfo.IsValid(VALID_VERT)) { if ( !bVertSet ) { bVertSet = sal_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, sal_False ); aSetBoxInfo.SetLine( 0, BOXINFO_LINE_VERT ); } } } //Rechte Kante if ( aSetBoxInfo.IsValid(VALID_RIGHT) && bRightOver ) { if ( !bRightSet ) { bRightSet = sal_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, sal_False ); aSetBox.SetLine( 0, BOX_LINE_RIGHT ); } } //Untere Kante if ( bLast && bBottomOver ) { if ( aSetBoxInfo.IsValid(VALID_BOTTOM) ) { if ( !bBottomSet ) { bBottomSet = sal_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, sal_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 = sal_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, sal_False ); aSetBoxInfo.SetLine( 0, BOXINFO_LINE_HORI ); } } } // Abstand zum Text if (aSetBoxInfo.IsValid(VALID_DISTANCE)) { static sal_uInt16 __READONLY_DATA aBorders[] = { BOX_LINE_BOTTOM, BOX_LINE_TOP, BOX_LINE_RIGHT, BOX_LINE_LEFT }; const sal_uInt16* pBrd = aBorders; if( !bDistanceSet ) // bei 1. Durchlauf erstmal setzen { bDistanceSet = sal_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, sal_False ); aSetBox.SetDistance( (sal_uInt16) 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, sal_True ) ) { SwTable& rTable = pTblNd->GetTable(); if (GetIDocumentUndoRedo().DoesUndo()) { GetIDocumentUndoRedo().AppendUndo( new SwUndoAttrTbl(*pTblNd) ); } SvPtrarr aFmtCmp( Max( sal_uInt8(255), sal_uInt8(aBoxes.Count()) ), 255 ); for ( sal_uInt16 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()->getLayoutFrm( rCursor.GetCntntNode()->GetDoc()->GetCurrentLayout() ); SwTabFrm* pTabFrm = pFrm->ImplFindTabFrm(); pTableLayout->Resize( pTableLayout->GetBrowseWidthByTabFrm( *pTabFrm ), sal_True ); } SwTblFmtCmp::Delete( aFmtCmp ); SetModified(); } } /*********************************************************************** #* Class : SwDoc #* Methoden : GetBoxAttr() #* Datum : MA 01. Jun. 93 #* Update : JP 29.04.98 #***********************************************************************/ sal_Bool SwDoc::GetBoxAttr( const SwCursor& rCursor, SfxPoolItem& rToFill ) const { sal_Bool bRet = sal_False; SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode(); SwSelBoxes aBoxes; if( pTblNd && lcl_GetBoxSel( rCursor, aBoxes )) { bRet = sal_True; sal_Bool bOneFound = sal_False; const sal_uInt16 nWhich = rToFill.Which(); for( sal_uInt16 i = 0; i < aBoxes.Count(); ++i ) { switch ( nWhich ) { case RES_BACKGROUND: { const SvxBrushItem &rBack = aBoxes[i]->GetFrmFmt()->GetBackground(); if( !bOneFound ) { (SvxBrushItem&)rToFill = rBack; bOneFound = sal_True; } else if( rToFill != rBack ) bRet = sal_False; } break; case RES_FRAMEDIR: { const SvxFrameDirectionItem& rDir = aBoxes[i]->GetFrmFmt()->GetFrmDir(); if( !bOneFound ) { (SvxFrameDirectionItem&)rToFill = rDir; bOneFound = sal_True; } else if( rToFill != rDir ) bRet = sal_False; } } if ( sal_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, sal_uInt16 nAlign ) { ASSERT( nAlign == text::VertOrientation::NONE || nAlign == text::VertOrientation::CENTER || nAlign == text::VertOrientation::BOTTOM, "wrong alignment" ); SwFmtVertOrient aVertOri( 0, nAlign ); SetBoxAttr( rCursor, aVertOri ); } sal_uInt16 SwDoc::GetBoxAlign( const SwCursor& rCursor ) const { sal_uInt16 nAlign = USHRT_MAX; SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode(); SwSelBoxes aBoxes; if( pTblNd && ::lcl_GetBoxSel( rCursor, aBoxes )) for( sal_uInt16 i = 0; i < aBoxes.Count(); ++i ) { const SwFmtVertOrient &rOri = aBoxes[i]->GetFrmFmt()->GetVertOrient(); if( USHRT_MAX == nAlign ) nAlign = static_cast(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 #***********************************************************************/ sal_uInt16 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 (sal_uInt16)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, sal_Bool bWishValues ) { const sal_uInt16 nWish = bWishValues ? ::lcl_CalcCellFit( pCell ) : MINLAY + sal_uInt16(pCell->Frm().Width() - pCell->Prt().Width()); SWRECTFN( pTab ) for ( sal_uInt16 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() != sal_uInt16((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 ( sal_uInt16(nTmp) > rToFill[i] ) rToFill[i] = sal_uInt16(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 == sal_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 == sal_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, sal_Bool bWishValues ) { SwSelUnions aUnions; ::MakeSelUnions( aUnions, pStart, pEnd, bWishValues ? nsSwTblSearchType::TBLSEARCH_NONE : nsSwTblSearchType::TBLSEARCH_COL ); for ( sal_uInt16 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)(); sal_Bool bNotInCols = sal_True; for ( sal_uInt16 i = 0; i <= rCols.Count(); ++i ) { sal_uInt16 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() != sal_uInt16((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 = sal_False; if ( bWishValues ) { const sal_uInt16 nWish = ::lcl_CalcCellFit( pCell ); if ( nWish > nFit ) nFit = nWish; } else { const sal_uInt16 nMin = MINLAY + sal_uInt16(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, sal_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 sal_uInt8 nTmp = (sal_uInt8)Max( sal_uInt16(255), sal_uInt16(aTabCols.Count() + 1) ); SvUShorts aWish( nTmp, nTmp ), aMins( nTmp, nTmp ); sal_uInt16 i; for ( i = 0; i <= aTabCols.Count(); ++i ) { aWish.Insert( sal_uInt16(0), aWish.Count() ); aMins.Insert( sal_uInt16(0), aMins.Count() ); } ::lcl_CalcColValues( aWish, aTabCols, pStart, pEnd, sal_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, sal_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. sal_uInt16 nWish = 0, nCnt = 0; for ( i = 0; i <= aTabCols.Count(); ++i ) { int nDiff = aWish[i]; if ( nDiff ) { if ( i == 0 ) nWish = static_cast( nWish + aTabCols[i] - aTabCols.GetLeft() ); else if ( i == aTabCols.Count() ) nWish = static_cast(nWish + aTabCols.GetRight() - aTabCols[i-1] ); else nWish = static_cast(nWish + aTabCols[i] - aTabCols[i-1] ); ++nCnt; } } nWish = nWish / nCnt; for ( i = 0; i < aWish.Count(); ++i ) if ( aWish[i] ) aWish[i] = nWish; } const sal_uInt16 nOldRight = static_cast(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 ( sal_uInt16 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 ( sal_uInt16 i2 = i; i2 < aTabCols.Count(); ++i2 ) aTabCols[i2] += nDiff; aTabCols.SetRight( nTabRight ); } } } const sal_uInt16 nNewRight = static_cast(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, sal_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(); }