blob: 018fd32c881630ed3afd7a71471555580a41bff4 [file] [log] [blame]
/**************************************************************
*
* 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 <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 <IDocumentUndoRedo.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"
#include "switerator.hxx"
#include <UndoTable.hxx>
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<const SwShellCrsr*>(&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<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() );
}
//-----------------------------------------------------------------------------
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<SwFrm,SwFmt> 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<sal_uInt16>(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<sal_uInt16>( nWish + aTabCols[i] - aTabCols.GetLeft() );
else if ( i == aTabCols.Count() )
nWish = static_cast<sal_uInt16>(nWish + aTabCols.GetRight() - aTabCols[i-1] );
else
nWish = static_cast<sal_uInt16>(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<sal_uInt16>(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<sal_uInt16>(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();
}