blob: ee02795c1104020a2fca7dab3e13484eac9c9f5f [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 <com/sun/star/chart2/XChartDocument.hpp>
#include <hintids.hxx>
#include <editeng/lrspitem.hxx>
#include <editeng/brkitem.hxx>
#include <editeng/protitem.hxx>
#include <editeng/boxitem.hxx>
#include <editeng/shaditem.hxx>
#include <fmtfsize.hxx>
#include <fmtornt.hxx>
#include <fmtfordr.hxx>
#include <fmtpdsc.hxx>
#include <fmtanchr.hxx>
#include <fmtlsplt.hxx>
#include <frmatr.hxx>
#include <charatr.hxx>
#include <cellfrm.hxx>
#include <pagefrm.hxx>
#include <tabcol.hxx>
#include <doc.hxx>
#include <IDocumentUndoRedo.hxx>
#include <UndoManager.hxx>
#include <cntfrm.hxx>
#include <pam.hxx>
#include <swcrsr.hxx>
#include <viscrs.hxx>
#include <swtable.hxx>
#include <ndtxt.hxx>
#include <swundo.hxx>
#include <tblsel.hxx>
#include <fldbas.hxx>
#include <poolfmt.hxx>
#include <tabfrm.hxx>
#include <UndoCore.hxx>
#include <UndoRedline.hxx>
#include <UndoDelete.hxx>
#include <UndoTable.hxx>
#include <hints.hxx>
#include <tblafmt.hxx>
#include <swcache.hxx>
#include <ddefld.hxx>
#include <frminf.hxx>
#include <cellatr.hxx>
#include <swtblfmt.hxx>
#include <swddetbl.hxx>
#include <mvsave.hxx>
#include <docary.hxx>
#include <redline.hxx>
#include <rolbck.hxx>
#include <tblrwcl.hxx>
#include <editsh.hxx>
#include <txtfrm.hxx>
#include <ftnfrm.hxx>
#include <section.hxx>
#include <frmtool.hxx>
#include <node2lay.hxx>
#include <comcore.hrc>
#include "docsh.hxx"
#include <tabcol.hxx>
#include <unochart.hxx>
#include <node.hxx>
#include <ndtxt.hxx>
#include <map>
#include <algorithm>
#include <rootfrm.hxx>
#include <fldupde.hxx>
#include <switerator.hxx>
#ifndef DBG_UTIL
#define CHECK_TABLE(t)
#else
#ifdef DEBUG
#define CHECK_TABLE(t) (t).CheckConsistency();
#else
#define CHECK_TABLE(t)
#endif
#endif
using namespace ::com::sun::star;
// #i17764# delete table redlines when modifying the table structure?
// #define DEL_TABLE_REDLINES 1
const sal_Unicode T2T_PARA = 0x0a;
extern void ClearFEShellTabCols();
// steht im gctable.cxx
extern sal_Bool lcl_GC_Line_Border( const SwTableLine*& , void* pPara );
#ifdef DEL_TABLE_REDLINES
class lcl_DelRedlines
{
SwDoc* pDoc;
public:
lcl_DelRedlines( const SwTableNode& rNd, sal_Bool bCheckForOwnRedline );
lcl_DelRedlines( SwPaM& rPam );
~lcl_DelRedlines() { pDoc->EndUndo(UNDO_EMPTY, NULL); }
};
lcl_DelRedlines::lcl_DelRedlines( SwPaM & rPam) : pDoc( rPam.GetDoc() )
{
pDoc->GetIDocumentUndoRedo().StartUndo(UNDO_EMPTY, NULL);
if( !pDoc->IsIgnoreRedline() && pDoc->GetRedlineTbl().Count() )
pDoc->AcceptRedline( rPam, true );
}
#endif
void lcl_SetDfltBoxAttr( SwFrmFmt& rFmt, sal_uInt8 nId )
{
sal_Bool bTop = sal_False, bBottom = sal_False, bLeft = sal_False, bRight = sal_False;
switch ( nId )
{
case 0: bTop = bBottom = bLeft = sal_True; break;
case 1: bTop = bBottom = bLeft = bRight = sal_True; break;
case 2: bBottom = bLeft = sal_True; break;
case 3: bBottom = bLeft = bRight = sal_True; break;
}
const sal_Bool bHTML = rFmt.getIDocumentSettingAccess()->get(IDocumentSettingAccess::HTML_MODE);
Color aCol( bHTML ? COL_GRAY : COL_BLACK );
SvxBorderLine aLine( &aCol, DEF_LINE_WIDTH_0 );
if ( bHTML )
{
aLine.SetOutWidth( DEF_DOUBLE_LINE7_OUT );
aLine.SetInWidth ( DEF_DOUBLE_LINE7_IN );
aLine.SetDistance( DEF_DOUBLE_LINE7_DIST);
}
SvxBoxItem aBox(RES_BOX); aBox.SetDistance( 55 );
if ( bTop )
aBox.SetLine( &aLine, BOX_LINE_TOP );
if ( bBottom )
aBox.SetLine( &aLine, BOX_LINE_BOTTOM );
if ( bLeft )
aBox.SetLine( &aLine, BOX_LINE_LEFT );
if ( bRight )
aBox.SetLine( &aLine, BOX_LINE_RIGHT );
rFmt.SetFmtAttr( aBox );
}
void lcl_SetDfltBoxAttr( SwTableBox& rBox, SvPtrarr &rBoxFmtArr, sal_uInt8 nId,
const SwTableAutoFmt* pAutoFmt = 0 )
{
SvPtrarr* pArr = (SvPtrarr*)rBoxFmtArr[ nId ];
if( !pArr )
{
pArr = new SvPtrarr;
rBoxFmtArr.Replace( pArr, nId );
}
SwTableBoxFmt* pNewBoxFmt = 0;
SwFrmFmt* pBoxFmt = rBox.GetFrmFmt();
for( sal_uInt16 n = 0; n < pArr->Count(); n += 2 )
if( pArr->GetObject( n ) == pBoxFmt )
{
pNewBoxFmt = (SwTableBoxFmt*)pArr->GetObject( n + 1 );
break;
}
if( !pNewBoxFmt )
{
SwDoc* pDoc = pBoxFmt->GetDoc();
// das Format ist also nicht vorhanden, also neu erzeugen
pNewBoxFmt = pDoc->MakeTableBoxFmt();
pNewBoxFmt->SetFmtAttr( pBoxFmt->GetAttrSet().Get( RES_FRM_SIZE ) );
if( pAutoFmt )
pAutoFmt->UpdateToSet( nId, (SfxItemSet&)pNewBoxFmt->GetAttrSet(),
SwTableAutoFmt::UPDATE_BOX,
pDoc->GetNumberFormatter( sal_True ) );
else
::lcl_SetDfltBoxAttr( *pNewBoxFmt, nId );
void* p = pBoxFmt;
pArr->Insert( p, pArr->Count() );
p = pNewBoxFmt;
pArr->Insert( p, pArr->Count() );
}
rBox.ChgFrmFmt( pNewBoxFmt );
}
SwTableBoxFmt *lcl_CreateDfltBoxFmt( SwDoc &rDoc, SvPtrarr &rBoxFmtArr,
sal_uInt16 nCols, sal_uInt8 nId )
{
if ( !rBoxFmtArr[nId] )
{
SwTableBoxFmt* pBoxFmt = rDoc.MakeTableBoxFmt();
if( USHRT_MAX != nCols )
pBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE,
USHRT_MAX / nCols, 0 ));
::lcl_SetDfltBoxAttr( *pBoxFmt, nId );
rBoxFmtArr.Replace( pBoxFmt, nId );
}
return (SwTableBoxFmt*)rBoxFmtArr[nId];
}
SwTableBoxFmt *lcl_CreateAFmtBoxFmt( SwDoc &rDoc, SvPtrarr &rBoxFmtArr,
const SwTableAutoFmt& rAutoFmt,
sal_uInt16 nCols, sal_uInt8 nId )
{
if( !rBoxFmtArr[nId] )
{
SwTableBoxFmt* pBoxFmt = rDoc.MakeTableBoxFmt();
rAutoFmt.UpdateToSet( nId, (SfxItemSet&)pBoxFmt->GetAttrSet(),
SwTableAutoFmt::UPDATE_BOX,
rDoc.GetNumberFormatter( sal_True ) );
if( USHRT_MAX != nCols )
pBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE,
USHRT_MAX / nCols, 0 ));
rBoxFmtArr.Replace( pBoxFmt, nId );
}
return (SwTableBoxFmt*)rBoxFmtArr[nId];
}
SwTableNode* SwDoc::IsIdxInTbl(const SwNodeIndex& rIdx)
{
SwTableNode* pTableNd = 0;
sal_uLong nIndex = rIdx.GetIndex();
do {
SwNode* pNd = (SwNode*)GetNodes()[ nIndex ]->StartOfSectionNode();
if( 0 != ( pTableNd = pNd->GetTableNode() ) )
break;
nIndex = pNd->GetIndex();
} while ( nIndex );
return pTableNd;
}
// --------------- einfuegen einer neuen Box --------------
// fuege in der Line, vor der InsPos eine neue Box ein.
sal_Bool SwNodes::InsBoxen( SwTableNode* pTblNd,
SwTableLine* pLine,
SwTableBoxFmt* pBoxFmt,
SwTxtFmtColl* pTxtColl,
const SfxItemSet* pAutoAttr,
sal_uInt16 nInsPos,
sal_uInt16 nCnt )
{
if( !nCnt )
return sal_False;
ASSERT( pLine, "keine gueltige Zeile" );
// Index hinter die letzte Box der Line
sal_uLong nIdxPos = 0;
SwTableBox *pPrvBox = 0, *pNxtBox = 0;
if( pLine->GetTabBoxes().Count() )
{
if( nInsPos < pLine->GetTabBoxes().Count() )
{
if( 0 == (pPrvBox = pLine->FindPreviousBox( pTblNd->GetTable(),
pLine->GetTabBoxes()[ nInsPos ] )))
pPrvBox = pLine->FindPreviousBox( pTblNd->GetTable() );
}
else if( 0 == ( pNxtBox = pLine->FindNextBox( pTblNd->GetTable(),
pLine->GetTabBoxes()[ nInsPos-1 ] )))
pNxtBox = pLine->FindNextBox( pTblNd->GetTable() );
}
else if( 0 == ( pNxtBox = pLine->FindNextBox( pTblNd->GetTable() )))
pPrvBox = pLine->FindPreviousBox( pTblNd->GetTable() );
if( !pPrvBox && !pNxtBox )
{
sal_Bool bSetIdxPos = sal_True;
if( pTblNd->GetTable().GetTabLines().Count() && !nInsPos )
{
const SwTableLine* pTblLn = pLine;
while( pTblLn->GetUpper() )
pTblLn = pTblLn->GetUpper()->GetUpper();
if( pTblNd->GetTable().GetTabLines()[ 0 ] == pTblLn )
{
// also vor die erste Box der Tabelle
while( ( pNxtBox = pLine->GetTabBoxes()[0])->GetTabLines().Count() )
pLine = pNxtBox->GetTabLines()[0];
nIdxPos = pNxtBox->GetSttIdx();
bSetIdxPos = sal_False;
}
}
if( bSetIdxPos )
// Tabelle ohne irgendeinen Inhalt oder am Ende, also vors Ende
nIdxPos = pTblNd->EndOfSectionIndex();
}
else if( pNxtBox ) // es gibt einen Nachfolger
nIdxPos = pNxtBox->GetSttIdx();
else // es gibt einen Vorgaenger
nIdxPos = pPrvBox->GetSttNd()->EndOfSectionIndex() + 1;
SwNodeIndex aEndIdx( *this, nIdxPos );
for( sal_uInt16 n = 0; n < nCnt; ++n )
{
SwStartNode* pSttNd = new SwStartNode( aEndIdx, ND_STARTNODE,
SwTableBoxStartNode );
pSttNd->pStartOfSection = pTblNd;
new SwEndNode( aEndIdx, *pSttNd );
pPrvBox = new SwTableBox( pBoxFmt, *pSttNd, pLine );
SwTableBoxes & rTabBoxes = pLine->GetTabBoxes();
sal_uInt16 nRealInsPos = nInsPos + n;
if (nRealInsPos > rTabBoxes.Count())
nRealInsPos = rTabBoxes.Count();
rTabBoxes.C40_INSERT( SwTableBox, pPrvBox, nRealInsPos );
//if( NO_NUMBERING == pTxtColl->GetOutlineLevel()//#outline level,zhaojianwei
if( ! pTxtColl->IsAssignedToListLevelOfOutlineStyle()//<-end,zhaojianwei
//FEATURE::CONDCOLL
&& RES_CONDTXTFMTCOLL != pTxtColl->Which()
//FEATURE::CONDCOLL
)
new SwTxtNode( SwNodeIndex( *pSttNd->EndOfSectionNode() ),
pTxtColl, pAutoAttr );
else
{
// Outline-Numerierung richtig behandeln !!!
SwTxtNode* pTNd = new SwTxtNode(
SwNodeIndex( *pSttNd->EndOfSectionNode() ),
(SwTxtFmtColl*)GetDoc()->GetDfltTxtFmtColl(),
pAutoAttr );
pTNd->ChgFmtColl( pTxtColl );
}
}
return sal_True;
}
// --------------- einfuegen einer neuen Tabelle --------------
const SwTable* SwDoc::InsertTable( const SwInsertTableOptions& rInsTblOpts,
const SwPosition& rPos, sal_uInt16 nRows,
sal_uInt16 nCols, sal_Int16 eAdjust,
const SwTableAutoFmt* pTAFmt,
const SvUShorts* pColArr,
sal_Bool bCalledFromShell,
sal_Bool bNewModel )
{
ASSERT( nRows, "Tabelle ohne Zeile?" );
ASSERT( nCols, "Tabelle ohne Spalten?" );
{
// nicht in Fussnoten kopieren !!
if( rPos.nNode < GetNodes().GetEndOfInserts().GetIndex() &&
rPos.nNode >= GetNodes().GetEndOfInserts().StartOfSectionIndex() )
return 0;
// sollte das ColumnArray die falsche Anzahl haben wird es ignoriert!
if( pColArr &&
(nCols + ( text::HoriOrientation::NONE == eAdjust ? 2 : 1 )) != pColArr->Count() )
pColArr = 0;
}
String aTblName = GetUniqueTblName();
if( GetIDocumentUndoRedo().DoesUndo() )
{
GetIDocumentUndoRedo().AppendUndo(
new SwUndoInsTbl( rPos, nCols, nRows, static_cast<sal_uInt16>(eAdjust),
rInsTblOpts, pTAFmt, pColArr,
aTblName));
}
// fuege erstmal die Nodes ein
// hole das Auto-Format fuer die Tabelle
SwTxtFmtColl *pBodyColl = GetTxtCollFromPool( RES_POOLCOLL_TABLE ),
*pHeadColl = pBodyColl;
sal_Bool bDfltBorders = 0 != ( rInsTblOpts.mnInsMode & tabopts::DEFAULT_BORDER );
if( (rInsTblOpts.mnInsMode & tabopts::HEADLINE) && (1 != nRows || !bDfltBorders) )
pHeadColl = GetTxtCollFromPool( RES_POOLCOLL_TABLE_HDLN );
const sal_uInt16 nRowsToRepeat =
tabopts::HEADLINE == (rInsTblOpts.mnInsMode & tabopts::HEADLINE) ?
rInsTblOpts.mnRowsToRepeat :
0;
/* #106283# Save content node to extract FRAMEDIR from. */
const SwCntntNode * pCntntNd = rPos.nNode.GetNode().GetCntntNode();
/* #109161# If we are called from a shell pass the attrset from
pCntntNd (aka the node the table is inserted at) thus causing
SwNodes::InsertTable to propagate an adjust item if
necessary. */
SwTableNode *pTblNd = GetNodes().InsertTable(
rPos.nNode,
nCols,
pBodyColl,
nRows,
nRowsToRepeat,
pHeadColl,
bCalledFromShell ? &pCntntNd->GetSwAttrSet() : 0 );
// dann erstelle die Box/Line/Table-Struktur
SwTableLineFmt* pLineFmt = MakeTableLineFmt();
SwTableFmt* pTableFmt = MakeTblFrmFmt( aTblName, GetDfltFrmFmt() );
/* #106283# If the node to insert the table at is a context node and has a
non-default FRAMEDIR propagate it to the table. */
if (pCntntNd)
{
const SwAttrSet & aNdSet = pCntntNd->GetSwAttrSet();
const SfxPoolItem *pItem = NULL;
if (SFX_ITEM_SET == aNdSet.GetItemState( RES_FRAMEDIR, sal_True, &pItem )
&& pItem != NULL)
{
pTableFmt->SetFmtAttr( *pItem );
}
}
//Orientation am Fmt der Table setzen
pTableFmt->SetFmtAttr( SwFmtHoriOrient( 0, eAdjust ) );
// alle Zeilen haben die Fill-Order von links nach rechts !
pLineFmt->SetFmtAttr( SwFmtFillOrder( ATT_LEFT_TO_RIGHT ));
// die Tabelle bekommt USHRT_MAX als default SSize
SwTwips nWidth = USHRT_MAX;
if( pColArr )
{
sal_uInt16 nSttPos = (*pColArr)[ 0 ];
sal_uInt16 nLastPos = (*pColArr)[ sal_uInt16(pColArr->Count()-1)];
if( text::HoriOrientation::NONE == eAdjust )
{
sal_uInt16 nFrmWidth = nLastPos;
nLastPos = (*pColArr)[ sal_uInt16(pColArr->Count()-2)];
pTableFmt->SetFmtAttr( SvxLRSpaceItem( nSttPos, nFrmWidth - nLastPos, 0, 0, RES_LR_SPACE ) );
}
nWidth = nLastPos - nSttPos;
}
else if( nCols )
{
nWidth /= nCols;
nWidth *= nCols; // to avoid rounding problems
}
pTableFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nWidth ));
if( !(rInsTblOpts.mnInsMode & tabopts::SPLIT_LAYOUT) )
pTableFmt->SetFmtAttr( SwFmtLayoutSplit( sal_False ));
// verschiebe ggfs. die harten PageDesc/PageBreak Attribute:
SwCntntNode* pNextNd = GetNodes()[ pTblNd->EndOfSectionIndex()+1 ]
->GetCntntNode();
if( pNextNd && pNextNd->HasSwAttrSet() )
{
const SfxItemSet* pNdSet = pNextNd->GetpSwAttrSet();
const SfxPoolItem *pItem;
if( SFX_ITEM_SET == pNdSet->GetItemState( RES_PAGEDESC, sal_False,
&pItem ) )
{
pTableFmt->SetFmtAttr( *pItem );
pNextNd->ResetAttr( RES_PAGEDESC );
pNdSet = pNextNd->GetpSwAttrSet();
}
if( pNdSet && SFX_ITEM_SET == pNdSet->GetItemState( RES_BREAK, sal_False,
&pItem ) )
{
pTableFmt->SetFmtAttr( *pItem );
pNextNd->ResetAttr( RES_BREAK );
}
}
SwTable * pNdTbl = &pTblNd->GetTable();
pNdTbl->RegisterToFormat( *pTableFmt );
pNdTbl->SetRowsToRepeat( nRowsToRepeat );
pNdTbl->SetTableModel( bNewModel );
SvPtrarr aBoxFmtArr( 0, 16 );
SwTableBoxFmt* pBoxFmt = 0;
if( !bDfltBorders && !pTAFmt )
{
pBoxFmt = MakeTableBoxFmt();
pBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, USHRT_MAX / nCols, 0 ));
}
else
{
const sal_uInt16 nBoxArrLen = pTAFmt ? 16 : 4;
for( sal_uInt16 i = 0; i < nBoxArrLen; ++i )
aBoxFmtArr.Insert( (void*)0, i );
}
// --> OD 2008-02-25 #refactorlists#
// SfxItemSet aCharSet( GetAttrPool(), RES_CHRATR_BEGIN, RES_PARATR_END-1 );
SfxItemSet aCharSet( GetAttrPool(), RES_CHRATR_BEGIN, RES_PARATR_LIST_END-1 );
// <--
SwNodeIndex aNdIdx( *pTblNd, 1 ); // auf den ersten Box-StartNode
SwTableLines& rLines = pNdTbl->GetTabLines();
for( sal_uInt16 n = 0; n < nRows; ++n )
{
SwTableLine* pLine = new SwTableLine( pLineFmt, nCols, 0 );
rLines.C40_INSERT( SwTableLine, pLine, n );
SwTableBoxes& rBoxes = pLine->GetTabBoxes();
for( sal_uInt16 i = 0; i < nCols; ++i )
{
SwTableBoxFmt *pBoxF;
if( pTAFmt )
{
sal_uInt8 nId = static_cast<sal_uInt8>(!n ? 0 : (( n+1 == nRows )
? 12 : (4 * (1 + ((n-1) & 1 )))));
nId = nId + static_cast<sal_uInt8>( !i ? 0 :
( i+1 == nCols ? 3 : (1 + ((i-1) & 1))));
pBoxF = ::lcl_CreateAFmtBoxFmt( *this, aBoxFmtArr, *pTAFmt,
nCols, nId );
// ggfs. noch die Absatz/ZeichenAttribute setzen
if( pTAFmt->IsFont() || pTAFmt->IsJustify() )
{
aCharSet.ClearItem();
pTAFmt->UpdateToSet( nId, aCharSet,
SwTableAutoFmt::UPDATE_CHAR, 0 );
if( aCharSet.Count() )
GetNodes()[ aNdIdx.GetIndex()+1 ]->GetCntntNode()->
SetAttr( aCharSet );
}
}
else if( bDfltBorders )
{
sal_uInt8 nBoxId = (i < nCols - 1 ? 0 : 1) + (n ? 2 : 0 );
pBoxF = ::lcl_CreateDfltBoxFmt( *this, aBoxFmtArr, nCols, nBoxId);
}
else
pBoxF = pBoxFmt;
// fuer AutoFormat bei der Eingabe: beim Einfuegen der Tabelle
// werden gleich die Spalten gesetzt. Im Array stehen die
// Positionen der Spalten!! (nicht deren Breite!)
if( pColArr )
{
nWidth = (*pColArr)[ sal_uInt16(i + 1) ] - (*pColArr)[ i ];
if( pBoxF->GetFrmSize().GetWidth() != nWidth )
{
if( pBoxF->GetDepends() ) // neues Format erzeugen!
{
SwTableBoxFmt *pNewFmt = MakeTableBoxFmt();
*pNewFmt = *pBoxF;
pBoxF = pNewFmt;
}
pBoxF->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nWidth ));
}
}
SwTableBox *pBox = new SwTableBox( pBoxF, aNdIdx, pLine);
rBoxes.C40_INSERT( SwTableBox, pBox, i );
aNdIdx += 3; // StartNode, TextNode, EndNode == 3 Nodes
}
}
// und Frms einfuegen.
GetNodes().GoNext( &aNdIdx ); // zum naechsten ContentNode
pTblNd->MakeFrms( &aNdIdx );
if( IsRedlineOn() || (!IsIgnoreRedline() && pRedlineTbl->Count() ))
{
SwPaM aPam( *pTblNd->EndOfSectionNode(), *pTblNd, 1 );
if( IsRedlineOn() )
AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_INSERT, aPam ), true);
else
SplitRedline( aPam );
}
SetModified();
CHECK_TABLE( *pNdTbl );
return pNdTbl;
}
SwTableNode* SwNodes::InsertTable( const SwNodeIndex& rNdIdx,
sal_uInt16 nBoxes,
SwTxtFmtColl* pCntntTxtColl,
sal_uInt16 nLines,
sal_uInt16 nRepeat,
SwTxtFmtColl* pHeadlineTxtColl,
const SwAttrSet * pAttrSet)
{
if( !nBoxes )
return 0;
// wenn Lines angegeben, erzeuge die Matrix aus Lines & Boxen
if( !pHeadlineTxtColl || !nLines )
pHeadlineTxtColl = pCntntTxtColl;
SwTableNode * pTblNd = new SwTableNode( rNdIdx );
SwEndNode* pEndNd = new SwEndNode( rNdIdx, *pTblNd );
if( !nLines ) // fuer die FOR-Schleife
++nLines;
SwNodeIndex aIdx( *pEndNd );
SwTxtFmtColl* pTxtColl = pHeadlineTxtColl;
for( sal_uInt16 nL = 0; nL < nLines; ++nL )
{
for( sal_uInt16 nB = 0; nB < nBoxes; ++nB )
{
SwStartNode* pSttNd = new SwStartNode( aIdx, ND_STARTNODE,
SwTableBoxStartNode );
pSttNd->pStartOfSection = pTblNd;
SwTxtNode * pTmpNd = new SwTxtNode( aIdx, pTxtColl );
// --> FME 2006-04-13 #i60422# Propagate some more attributes.
// Adjustment was done for #109161#
const SfxPoolItem* pItem = NULL;
if ( NULL != pAttrSet )
{
static const sal_uInt16 aPropagateItems[] = {
RES_PARATR_ADJUST,
RES_CHRATR_FONT, RES_CHRATR_FONTSIZE,
RES_CHRATR_CJK_FONT, RES_CHRATR_CJK_FONTSIZE,
RES_CHRATR_CTL_FONT, RES_CHRATR_CTL_FONTSIZE, 0 };
const sal_uInt16* pIdx = aPropagateItems;
while ( *pIdx != 0 )
{
if ( SFX_ITEM_SET != pTmpNd->GetSwAttrSet().GetItemState( *pIdx ) &&
SFX_ITEM_SET == pAttrSet->GetItemState( *pIdx, sal_True, &pItem ) )
static_cast<SwCntntNode *>(pTmpNd)->SetAttr(*pItem);
++pIdx;
}
}
// <--
new SwEndNode( aIdx, *pSttNd );
}
if ( nL + 1 >= nRepeat )
pTxtColl = pCntntTxtColl;
}
return pTblNd;
}
//---------------- Text -> Tabelle -----------------------
const SwTable* SwDoc::TextToTable( const SwInsertTableOptions& rInsTblOpts,
const SwPaM& rRange, sal_Unicode cCh,
sal_Int16 eAdjust,
const SwTableAutoFmt* pTAFmt )
{
// pruefe ob in der Selection eine Tabelle liegt
const SwPosition *pStt = rRange.Start(), *pEnd = rRange.End();
{
sal_uLong nCnt = pStt->nNode.GetIndex();
for( ; nCnt <= pEnd->nNode.GetIndex(); ++nCnt )
if( !GetNodes()[ nCnt ]->IsTxtNode() )
return 0;
}
/* #106283# Save first node in the selection if it is a context node. */
SwCntntNode * pSttCntntNd = pStt->nNode.GetNode().GetCntntNode();
SwPaM aOriginal( *pStt, *pEnd );
pStt = aOriginal.GetMark();
pEnd = aOriginal.GetPoint();
#ifdef DEL_TABLE_REDLINES
lcl_DelRedlines aDelRedl( aOriginal );
#endif
SwUndoTxtToTbl* pUndo = 0;
if( GetIDocumentUndoRedo().DoesUndo() )
{
GetIDocumentUndoRedo().StartUndo( UNDO_TEXTTOTABLE, NULL );
pUndo = new SwUndoTxtToTbl( aOriginal, rInsTblOpts, cCh,
static_cast<sal_uInt16>(eAdjust), pTAFmt );
GetIDocumentUndoRedo().AppendUndo( pUndo );
// das Splitten vom TextNode nicht in die Undohistory aufnehmen
GetIDocumentUndoRedo().DoUndo( false );
}
::PaMCorrAbs( aOriginal, *pEnd );
// sorge dafuer, das der Bereich auf Node-Grenzen liegt
SwNodeRange aRg( pStt->nNode, pEnd->nNode );
if( pStt->nContent.GetIndex() )
SplitNode( *pStt, false );
sal_Bool bEndCntnt = 0 != pEnd->nContent.GetIndex();
// nicht splitten am Ende der Zeile (aber am Ende vom Doc!!)
if( bEndCntnt )
{
if( pEnd->nNode.GetNode().GetCntntNode()->Len() != pEnd->nContent.GetIndex()
|| pEnd->nNode.GetIndex() >= GetNodes().GetEndOfContent().GetIndex()-1 )
{
SplitNode( *pEnd, false );
((SwNodeIndex&)pEnd->nNode)--;
((SwIndex&)pEnd->nContent).Assign(
pEnd->nNode.GetNode().GetCntntNode(), 0 );
// ein Node und am Ende ??
if( pStt->nNode.GetIndex() >= pEnd->nNode.GetIndex() )
aRg.aStart--;
}
else
aRg.aEnd++;
}
if( aRg.aEnd.GetIndex() == aRg.aStart.GetIndex() )
{
ASSERT( sal_False, "Kein Bereich" );
aRg.aEnd++;
}
// Wir gehen jetzt immer ueber die Upper, um die Tabelle einzufuegen:
SwNode2Layout aNode2Layout( aRg.aStart.GetNode() );
GetIDocumentUndoRedo().DoUndo( 0 != pUndo );
// dann erstelle die Box/Line/Table-Struktur
SwTableBoxFmt* pBoxFmt = MakeTableBoxFmt();
SwTableLineFmt* pLineFmt = MakeTableLineFmt();
SwTableFmt* pTableFmt = MakeTblFrmFmt( GetUniqueTblName(), GetDfltFrmFmt() );
// alle Zeilen haben die Fill-Order von links nach rechts !
pLineFmt->SetFmtAttr( SwFmtFillOrder( ATT_LEFT_TO_RIGHT ));
// die Tabelle bekommt USHRT_MAX als default SSize
pTableFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, USHRT_MAX ));
if( !(rInsTblOpts.mnInsMode & tabopts::SPLIT_LAYOUT) )
pTableFmt->SetFmtAttr( SwFmtLayoutSplit( sal_False ));
/* #106283# If the first node in the selection is a context node and if it
has an item FRAMEDIR set (no default) propagate the item to the
replacing table. */
if (pSttCntntNd)
{
const SwAttrSet & aNdSet = pSttCntntNd->GetSwAttrSet();
const SfxPoolItem *pItem = NULL;
if (SFX_ITEM_SET == aNdSet.GetItemState( RES_FRAMEDIR, sal_True, &pItem )
&& pItem != NULL)
{
pTableFmt->SetFmtAttr( *pItem );
}
}
SwTableNode* pTblNd = GetNodes().TextToTable(
aRg, cCh, pTableFmt, pLineFmt, pBoxFmt,
GetTxtCollFromPool( RES_POOLCOLL_STANDARD ), pUndo );
SwTable * pNdTbl = &pTblNd->GetTable();
ASSERT( pNdTbl, "kein Tabellen-Node angelegt." )
const sal_uInt16 nRowsToRepeat =
tabopts::HEADLINE == (rInsTblOpts.mnInsMode & tabopts::HEADLINE) ?
rInsTblOpts.mnRowsToRepeat :
0;
pNdTbl->SetRowsToRepeat( nRowsToRepeat );
sal_Bool bUseBoxFmt = sal_False;
if( !pBoxFmt->GetDepends() )
{
// die Formate an den Boxen haben schon die richtige Size, es darf
// also nur noch die richtige Umrandung/AutoFmt gesetzt werden.
bUseBoxFmt = sal_True;
pTableFmt->SetFmtAttr( pBoxFmt->GetFrmSize() );
delete pBoxFmt;
eAdjust = text::HoriOrientation::NONE;
}
//Orientation am Fmt der Table setzen
pTableFmt->SetFmtAttr( SwFmtHoriOrient( 0, eAdjust ) );
pNdTbl->RegisterToFormat( *pTableFmt );
if( pTAFmt || ( rInsTblOpts.mnInsMode & tabopts::DEFAULT_BORDER) )
{
sal_uInt8 nBoxArrLen = pTAFmt ? 16 : 4;
SvPtrarr aBoxFmtArr( nBoxArrLen, 0 );
{
for( sal_uInt8 i = 0; i < nBoxArrLen; ++i )
aBoxFmtArr.Insert( (void*)0, i );
}
// --> OD 2008-02-25 #refactorlists#
// SfxItemSet aCharSet( GetAttrPool(), RES_CHRATR_BEGIN, RES_PARATR_END-1 );
SfxItemSet aCharSet( GetAttrPool(), RES_CHRATR_BEGIN, RES_PARATR_LIST_END-1 );
// <--
SwHistory* pHistory = pUndo ? &pUndo->GetHistory() : 0;
SwTableBoxFmt *pBoxF = 0;
SwTableLines& rLines = pNdTbl->GetTabLines();
sal_uInt16 nRows = rLines.Count();
for( sal_uInt16 n = 0; n < nRows; ++n )
{
SwTableBoxes& rBoxes = rLines[ n ]->GetTabBoxes();
sal_uInt16 nCols = rBoxes.Count();
for( sal_uInt16 i = 0; i < nCols; ++i )
{
SwTableBox* pBox = rBoxes[ i ];
sal_Bool bChgSz = sal_False;
if( pTAFmt )
{
sal_uInt8 nId = static_cast<sal_uInt8>(!n ? 0 : (( n+1 == nRows )
? 12 : (4 * (1 + ((n-1) & 1 )))));
nId = nId + static_cast<sal_uInt8>(!i ? 0 :
( i+1 == nCols ? 3 : (1 + ((i-1) & 1))));
if( bUseBoxFmt )
::lcl_SetDfltBoxAttr( *pBox, aBoxFmtArr, nId, pTAFmt );
else
{
bChgSz = 0 == aBoxFmtArr[ nId ];
pBoxF = ::lcl_CreateAFmtBoxFmt( *this, aBoxFmtArr,
*pTAFmt, USHRT_MAX, nId );
}
// ggfs. noch die Absatz/ZeichenAttribute setzen
if( pTAFmt->IsFont() || pTAFmt->IsJustify() )
{
aCharSet.ClearItem();
pTAFmt->UpdateToSet( nId, aCharSet,
SwTableAutoFmt::UPDATE_CHAR, 0 );
if( aCharSet.Count() )
{
sal_uLong nSttNd = pBox->GetSttIdx()+1;
sal_uLong nEndNd = pBox->GetSttNd()->EndOfSectionIndex();
for( ; nSttNd < nEndNd; ++nSttNd )
{
SwCntntNode* pNd = GetNodes()[ nSttNd ]->GetCntntNode();
if( pNd )
{
if( pHistory )
{
SwRegHistory aReg( pNd, *pNd, pHistory );
pNd->SetAttr( aCharSet );
}
else
pNd->SetAttr( aCharSet );
}
}
}
}
}
else
{
sal_uInt8 nId = (i < nCols - 1 ? 0 : 1) + (n ? 2 : 0 );
if( bUseBoxFmt )
::lcl_SetDfltBoxAttr( *pBox, aBoxFmtArr, nId );
else
{
bChgSz = 0 == aBoxFmtArr[ nId ];
pBoxF = ::lcl_CreateDfltBoxFmt( *this, aBoxFmtArr,
USHRT_MAX, nId );
}
}
if( !bUseBoxFmt )
{
if( bChgSz )
pBoxF->SetFmtAttr( pBox->GetFrmFmt()->GetFrmSize() );
pBox->ChgFrmFmt( pBoxF );
}
}
}
if( bUseBoxFmt )
{
for( sal_uInt8 i = 0; i < nBoxArrLen; ++i )
{
SvPtrarr* pArr = (SvPtrarr*)aBoxFmtArr[ i ];
delete pArr;
}
}
}
// JP 03.04.97: Inhalt der Boxen auf Zahlen abpruefen
if( IsInsTblFormatNum() )
{
for( sal_uInt16 nBoxes = pNdTbl->GetTabSortBoxes().Count(); nBoxes; )
ChkBoxNumFmt( *pNdTbl->GetTabSortBoxes()[ --nBoxes ], sal_False );
}
sal_uLong nIdx = pTblNd->GetIndex();
aNode2Layout.RestoreUpperFrms( GetNodes(), nIdx, nIdx + 1 );
{
SwPaM& rTmp = (SwPaM&)rRange; // Point immer an den Anfang
rTmp.DeleteMark();
rTmp.GetPoint()->nNode = *pTblNd;
SwCntntNode* pCNd = GetNodes().GoNext( &rTmp.GetPoint()->nNode );
rTmp.GetPoint()->nContent.Assign( pCNd, 0 );
}
if( pUndo )
{
GetIDocumentUndoRedo().EndUndo( UNDO_TEXTTOTABLE, NULL );
}
SetModified();
SetFieldsDirty(true, NULL, 0);
return pNdTbl;
}
SwTableNode* SwNodes::TextToTable( const SwNodeRange& rRange, sal_Unicode cCh,
SwTableFmt* pTblFmt,
SwTableLineFmt* pLineFmt,
SwTableBoxFmt* pBoxFmt,
SwTxtFmtColl* pTxtColl,
SwUndoTxtToTbl* pUndo )
{
if( rRange.aStart >= rRange.aEnd )
return 0;
SwTableNode * pTblNd = new SwTableNode( rRange.aStart );
new SwEndNode( rRange.aEnd, *pTblNd );
SwDoc* pDoc = GetDoc();
SvUShorts aPosArr( 0, 16 );
SwTable * pTable = &pTblNd->GetTable();
SwTableLine* pLine;
SwTableBox* pBox;
sal_uInt16 nBoxes, nLines, nMaxBoxes = 0;
SwNodeIndex aSttIdx( *pTblNd, 1 );
SwNodeIndex aEndIdx( rRange.aEnd, -1 );
for( nLines = 0, nBoxes = 0;
aSttIdx.GetIndex() < aEndIdx.GetIndex();
aSttIdx += 2, nLines++, nBoxes = 0 )
{
SwTxtNode* pTxtNd = aSttIdx.GetNode().GetTxtNode();
ASSERT( pTxtNd, "nur TextNodes in der Tabelle aufnehmen" );
if( !nLines && 0x0b == cCh )
{
cCh = 0x09;
// JP 28.10.96: vom 1. Node die Positionen des Trenners besorgen,
// damit die Boxen entsprechend eingestellt werden
SwTxtFrmInfo aFInfo( (SwTxtFrm*)pTxtNd->getLayoutFrm( pTxtNd->GetDoc()->GetCurrentLayout() ) );
if( aFInfo.IsOneLine() ) // nur dann sinnvoll!
{
const sal_Unicode* pTxt = pTxtNd->GetTxt().GetBuffer();
for( xub_StrLen nChPos = 0; *pTxt; ++nChPos, ++pTxt )
{
if( *pTxt == cCh )
{
aPosArr.Insert( static_cast<sal_uInt16>(
aFInfo.GetCharPos( nChPos+1, sal_False )),
aPosArr.Count() );
}
}
aPosArr.Insert( /*aFInfo.GetFrm()->Frm().Left() +*/
static_cast<sal_uInt16>(aFInfo.GetFrm()->IsVertical() ?
aFInfo.GetFrm()->Prt().Bottom() :
aFInfo.GetFrm()->Prt().Right()),
aPosArr.Count() );
}
}
// die alten Frames loeschen, es werden neue erzeugt
pTxtNd->DelFrms();
// PageBreaks/PageDesc/ColBreak rausschmeissen.
const SfxItemSet* pSet = pTxtNd->GetpSwAttrSet();
if( pSet )
{
// das entfernen der PageBreaks erst nach dem erzeugen der Tabelle
// erfolgen, denn sonst stehen sie falsch in der History !!!
// SwRegHistory aRegH( pTxtNd, *pTxtNd, pHistory );
const SfxPoolItem* pItem;
if( SFX_ITEM_SET == pSet->GetItemState( RES_BREAK, sal_False, &pItem ) )
{
if( !nLines )
pTblFmt->SetFmtAttr( *pItem );
pTxtNd->ResetAttr( RES_BREAK );
pSet = pTxtNd->GetpSwAttrSet();
}
if( pSet && SFX_ITEM_SET == pSet->GetItemState(
RES_PAGEDESC, sal_False, &pItem ) &&
((SwFmtPageDesc*)pItem)->GetPageDesc() )
{
if( !nLines )
pTblFmt->SetFmtAttr( *pItem );
pTxtNd->ResetAttr( RES_PAGEDESC );
}
}
// setze den bei allen TextNode in der Tabelle den TableNode
// als StartNode
pTxtNd->pStartOfSection = pTblNd;
pLine = new SwTableLine( pLineFmt, 1, 0 );
pTable->GetTabLines().C40_INSERT( SwTableLine, pLine, nLines );
SwStartNode* pSttNd;
SwPosition aCntPos( aSttIdx, SwIndex( pTxtNd ));
SvULongs aBkmkArr( 15, 15 );
_SaveCntntIdx( pDoc, aSttIdx.GetIndex(), pTxtNd->GetTxt().Len(), aBkmkArr );
const sal_Unicode* pTxt = pTxtNd->GetTxt().GetBuffer();
if( T2T_PARA != cCh )
for( xub_StrLen nChPos = 0; *pTxt; ++nChPos, ++pTxt )
if( *pTxt == cCh )
{
aCntPos.nContent = nChPos;
SwCntntNode* pNewNd = pTxtNd->SplitCntntNode( aCntPos );
if( aBkmkArr.Count() )
_RestoreCntntIdx( aBkmkArr, *pNewNd, nChPos,
nChPos + 1 );
// Trennzeichen loeschen und SuchString korrigieren
pTxtNd->EraseText( aCntPos.nContent, 1 );
pTxt = pTxtNd->GetTxt().GetBuffer();
nChPos = 0;
--nChPos, --pTxt; // for the ++ in the for loop !!!
// setze bei allen TextNodes in der Tabelle den TableNode
// als StartNode
const SwNodeIndex aTmpIdx( aCntPos.nNode, -1 );
pSttNd = new SwStartNode( aTmpIdx, ND_STARTNODE,
SwTableBoxStartNode );
new SwEndNode( aCntPos.nNode, *pSttNd );
pNewNd->pStartOfSection = pSttNd;
// Section der Box zuweisen
pBox = new SwTableBox( pBoxFmt, *pSttNd, pLine );
pLine->GetTabBoxes().C40_INSERT( SwTableBox, pBox, nBoxes++ );
}
// und jetzt den letzten Teil-String
if( aBkmkArr.Count() )
_RestoreCntntIdx( aBkmkArr, *pTxtNd, pTxtNd->GetTxt().Len(),
pTxtNd->GetTxt().Len()+1 );
pSttNd = new SwStartNode( aCntPos.nNode, ND_STARTNODE, SwTableBoxStartNode );
const SwNodeIndex aTmpIdx( aCntPos.nNode, 1 );
new SwEndNode( aTmpIdx, *pSttNd );
pTxtNd->pStartOfSection = pSttNd;
pBox = new SwTableBox( pBoxFmt, *pSttNd, pLine );
pLine->GetTabBoxes().C40_INSERT( SwTableBox, pBox, nBoxes++ );
if( nMaxBoxes < nBoxes )
nMaxBoxes = nBoxes;
}
// die Tabelle ausgleichen, leere Sections einfuegen
sal_uInt16 n;
for( n = 0; n < pTable->GetTabLines().Count(); ++n )
{
SwTableLine* pCurrLine = pTable->GetTabLines()[ n ];
if( nMaxBoxes != ( nBoxes = pCurrLine->GetTabBoxes().Count() ))
{
InsBoxen( pTblNd, pCurrLine, pBoxFmt, pTxtColl, 0,
nBoxes, nMaxBoxes - nBoxes );
if( pUndo )
for( sal_uInt16 i = nBoxes; i < nMaxBoxes; ++i )
pUndo->AddFillBox( *pCurrLine->GetTabBoxes()[ i ] );
// fehlen der 1. Line Boxen, dann kann man das Breiten Array
// vergessen!
if( !n )
aPosArr.Remove( 0, aPosArr.Count() );
}
}
if( aPosArr.Count() )
{
SwTableLines& rLns = pTable->GetTabLines();
sal_uInt16 nLastPos = 0;
for( n = 0; n < aPosArr.Count(); ++n )
{
SwTableBoxFmt *pNewFmt = pDoc->MakeTableBoxFmt();
pNewFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE,
aPosArr[ n ] - nLastPos ));
for( sal_uInt16 nTmpLine = 0; nTmpLine < rLns.Count(); ++nTmpLine )
//JP 24.06.98: hier muss ein Add erfolgen, da das BoxFormat
// von der rufenden Methode noch gebraucht wird!
pNewFmt->Add( rLns[ nTmpLine ]->GetTabBoxes()[ n ] );
nLastPos = aPosArr[ n ];
}
// damit die Tabelle die richtige Groesse bekommt, im BoxFormat die
// Groesse nach "oben" transportieren.
ASSERT( !pBoxFmt->GetDepends(), "wer ist in dem Format noch angemeldet" );
pBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nLastPos ));
}
else
pBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, USHRT_MAX / nMaxBoxes ));
// das wars doch wohl ??
return pTblNd;
}
/*-- 18.05.2006 10:30:29---------------------------------------------------
-----------------------------------------------------------------------*/
const SwTable* SwDoc::TextToTable( const std::vector< std::vector<SwNodeRange> >& rTableNodes )
{
/* #106283# Save first node in the selection if it is a content node. */
SwCntntNode * pSttCntntNd = rTableNodes.begin()->begin()->aStart.GetNode().GetCntntNode();
/**debug**/
#if OSL_DEBUG_LEVEL > 1
const SwNodeRange& rStartRange = *rTableNodes.begin()->begin();
const SwNodeRange& rEndRange = *rTableNodes.rbegin()->rbegin();
(void) rStartRange;
(void) rEndRange;
#endif
/**debug**/
//!!! not necessarily TextNodes !!!
SwPaM aOriginal( rTableNodes.begin()->begin()->aStart, rTableNodes.rbegin()->rbegin()->aEnd );
const SwPosition *pStt = aOriginal.GetMark();
const SwPosition *pEnd = aOriginal.GetPoint();
#ifdef DEL_TABLE_REDLINES
lcl_DelRedlines aDelRedl( aOriginal );
#endif
// SwUndoTxtToTbl* pUndo = 0;
bool const bUndo(GetIDocumentUndoRedo().DoesUndo());
if (bUndo)
{
// das Splitten vom TextNode nicht in die Undohistory aufnehmen
GetIDocumentUndoRedo().DoUndo(false);
}
::PaMCorrAbs( aOriginal, *pEnd );
// sorge dafuer, das der Bereich auf Node-Grenzen liegt
SwNodeRange aRg( pStt->nNode, pEnd->nNode );
if( pStt->nContent.GetIndex() )
SplitNode( *pStt, false );
sal_Bool bEndCntnt = 0 != pEnd->nContent.GetIndex();
// nicht splitten am Ende der Zeile (aber am Ende vom Doc!!)
if( bEndCntnt )
{
if( pEnd->nNode.GetNode().GetCntntNode()->Len() != pEnd->nContent.GetIndex()
|| pEnd->nNode.GetIndex() >= GetNodes().GetEndOfContent().GetIndex()-1 )
{
SplitNode( *pEnd, false );
((SwNodeIndex&)pEnd->nNode)--;
((SwIndex&)pEnd->nContent).Assign(
pEnd->nNode.GetNode().GetCntntNode(), 0 );
// ein Node und am Ende ??
if( pStt->nNode.GetIndex() >= pEnd->nNode.GetIndex() )
aRg.aStart--;
}
else
aRg.aEnd++;
}
if( aRg.aEnd.GetIndex() == aRg.aStart.GetIndex() )
{
ASSERT( sal_False, "Kein Bereich" );
aRg.aEnd++;
}
// Wir gehen jetzt immer ueber die Upper, um die Tabelle einzufuegen:
SwNode2Layout aNode2Layout( aRg.aStart.GetNode() );
GetIDocumentUndoRedo().DoUndo(bUndo);
// dann erstelle die Box/Line/Table-Struktur
SwTableBoxFmt* pBoxFmt = MakeTableBoxFmt();
SwTableLineFmt* pLineFmt = MakeTableLineFmt();
SwTableFmt* pTableFmt = MakeTblFrmFmt( GetUniqueTblName(), GetDfltFrmFmt() );
// alle Zeilen haben die Fill-Order von links nach rechts !
pLineFmt->SetFmtAttr( SwFmtFillOrder( ATT_LEFT_TO_RIGHT ));
// die Tabelle bekommt USHRT_MAX als default SSize
pTableFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, USHRT_MAX ));
/* #106283# If the first node in the selection is a context node and if it
has an item FRAMEDIR set (no default) propagate the item to the
replacing table. */
if (pSttCntntNd)
{
const SwAttrSet & aNdSet = pSttCntntNd->GetSwAttrSet();
const SfxPoolItem *pItem = NULL;
if (SFX_ITEM_SET == aNdSet.GetItemState( RES_FRAMEDIR, sal_True, &pItem )
&& pItem != NULL)
{
pTableFmt->SetFmtAttr( *pItem );
}
}
SwTableNode* pTblNd = GetNodes().TextToTable(
rTableNodes, pTableFmt, pLineFmt, pBoxFmt,
GetTxtCollFromPool( RES_POOLCOLL_STANDARD )/*, pUndo*/ );
SwTable * pNdTbl = &pTblNd->GetTable();
ASSERT( pNdTbl, "kein Tabellen-Node angelegt." )
pNdTbl->RegisterToFormat( *pTableFmt );
sal_Bool bUseBoxFmt = sal_False;
if( !pBoxFmt->GetDepends() )
{
// die Formate an den Boxen haben schon die richtige Size, es darf
// also nur noch die richtige Umrandung/AutoFmt gesetzt werden.
bUseBoxFmt = sal_True;
pTableFmt->SetFmtAttr( pBoxFmt->GetFrmSize() );
delete pBoxFmt;
}
sal_uLong nIdx = pTblNd->GetIndex();
aNode2Layout.RestoreUpperFrms( GetNodes(), nIdx, nIdx + 1 );
SetModified();
SetFieldsDirty( true, NULL, 0 );
return pNdTbl;
}
SwNodeRange * SwNodes::ExpandRangeForTableBox(const SwNodeRange & rRange)
{
SwNodeRange * pResult = NULL;
bool bChanged = false;
SwNodeIndex aNewStart = rRange.aStart;
SwNodeIndex aNewEnd = rRange.aEnd;
SwNodeIndex aEndIndex = rRange.aEnd;
SwNodeIndex aIndex = rRange.aStart;
while (aIndex < aEndIndex)
{
SwNode& rNode = aIndex.GetNode();
if (rNode.IsStartNode())
{
// advance aIndex to the end node of this start node
SwNode * pEndNode = rNode.EndOfSectionNode();
aIndex = *pEndNode;
if (aIndex > aNewEnd)
{
aNewEnd = aIndex;
bChanged = true;
}
}
else if (rNode.IsEndNode())
{
SwNode * pStartNode = rNode.StartOfSectionNode();
SwNodeIndex aStartIndex = *pStartNode;
if (aStartIndex < aNewStart)
{
aNewStart = aStartIndex;
bChanged = true;
}
}
if (aIndex < aEndIndex)
++aIndex;
}
SwNode * pNode = &aIndex.GetNode();
while (pNode->IsEndNode())
{
SwNode * pStartNode = pNode->StartOfSectionNode();
SwNodeIndex aStartIndex(*pStartNode);
aNewStart = aStartIndex;
aNewEnd = aIndex;
bChanged = true;
++aIndex;
pNode = &aIndex.GetNode();
}
if (bChanged)
pResult = new SwNodeRange(aNewStart, aNewEnd);
return pResult;
}
/*-- 18.05.2006 08:23:28---------------------------------------------------
-----------------------------------------------------------------------*/
SwTableNode* SwNodes::TextToTable( const SwNodes::TableRanges_t & rTableNodes,
SwTableFmt* pTblFmt,
SwTableLineFmt* pLineFmt,
SwTableBoxFmt* pBoxFmt,
SwTxtFmtColl* /*pTxtColl*/ /*, SwUndo... pUndo*/ )
{
if( !rTableNodes.size() )
return 0;
SwTableNode * pTblNd = new SwTableNode( rTableNodes.begin()->begin()->aStart );
//insert the end node after the last text node
SwNodeIndex aInsertIndex( rTableNodes.rbegin()->rbegin()->aEnd );
++aInsertIndex;
//!! owner ship will be transferred in c-tor to SwNodes array.
//!! Thus no real problem here...
new SwEndNode( aInsertIndex, *pTblNd );
#if OSL_DEBUG_LEVEL > 1
/**debug**/
const SwNodeRange& rStartRange = *rTableNodes.begin()->begin();
const SwNodeRange& rEndRange = *rTableNodes.rbegin()->rbegin();
(void) rStartRange;
(void) rEndRange;
/**debug**/
#endif
SwDoc* pDoc = GetDoc();
SvUShorts aPosArr( 0, 16 );
SwTable * pTable = &pTblNd->GetTable();
SwTableLine* pLine;
SwTableBox* pBox;
sal_uInt16 nBoxes, nLines, nMaxBoxes = 0;
// SwHistory* pHistory = pUndo ? &pUndo->GetHistory() : 0;
SwNodeIndex aNodeIndex = rTableNodes.begin()->begin()->aStart;
// delete frames of all contained content nodes
for( nLines = 0; aNodeIndex <= rTableNodes.rbegin()->rbegin()->aEnd; ++aNodeIndex,++nLines )
{
SwNode& rNode = aNodeIndex.GetNode();
if( rNode.IsCntntNode() )
{
static_cast<SwCntntNode&>(rNode).DelFrms();
if(rNode.IsTxtNode())
{
SwTxtNode& rTxtNode = static_cast<SwTxtNode&>(rNode);
// setze den bei allen TextNode in der Tabelle den TableNode
// als StartNode
// FIXME: this is setting wrong node StartOfSections in nested tables.
// rTxtNode.pStartOfSection = pTblNd;
// remove PageBreaks/PageDesc/ColBreak
const SwAttrSet* pSet = rTxtNode.GetpSwAttrSet();
if( pSet )
{
// das entfernen der PageBreaks erst nach dem erzeugen der Tabelle
// erfolgen, denn sonst stehen sie falsch in der History !!!
// SwRegHistory aRegH( pTxtNd, *pTxtNd, pHistory );
const SfxPoolItem* pItem;
if( SFX_ITEM_SET == pSet->GetItemState( RES_BREAK, sal_False, &pItem ) )
{
if( !nLines )
pTblFmt->SetFmtAttr( *pItem );
rTxtNode.ResetAttr( RES_BREAK );
pSet = rTxtNode.GetpSwAttrSet();
}
if( pSet && SFX_ITEM_SET == pSet->GetItemState(
RES_PAGEDESC, sal_False, &pItem ) &&
((SwFmtPageDesc*)pItem)->GetPageDesc() )
{
if( !nLines )
pTblFmt->SetFmtAttr( *pItem );
rTxtNode.ResetAttr( RES_PAGEDESC );
}
}
}
}
}
// SwNodeIndex aSttIdx( *pTblNd, 1 );
// SwNodeIndex aEndIdx( rlNodes.rbegin()->aEnd, -1 );
std::vector<std::vector < SwNodeRange > >::const_iterator aRowIter = rTableNodes.begin();
for( nLines = 0, nBoxes = 0;
aRowIter != rTableNodes.end();
++aRowIter, /*aSttIdx += 2, */nLines++, nBoxes = 0 )
{
// SwTxtNode* pTxtNd = aSttIdx.GetNode().GetTxtNode();
// ASSERT( pTxtNd, "nur TextNodes in der Tabelle aufnehmen" );
pLine = new SwTableLine( pLineFmt, 1, 0 );
pTable->GetTabLines().C40_INSERT( SwTableLine, pLine, nLines );
// SwStartNode* pSttNd;
// SwPosition aCntPos( aSttIdx, SwIndex( pTxtNd ));
std::vector< SwNodeRange >::const_iterator aCellIter = aRowIter->begin();
// SvULongs aBkmkArr( 15, 15 );
// _SaveCntntIdx( pDoc, aCellIter->aStart.GetIndex(), pTxtNd->GetTxt().Len(), aBkmkArr );
// const sal_Unicode* pTxt = pTxtNd->GetTxt().GetBuffer();
for( ; aCellIter != aRowIter->end(); ++aCellIter )
{
// aCellIter->aStart aCellIter->aEnd
// aCntPos.nContent = nChPos;
// SwCntntNode* pNewNd = pTxtNd->SplitNode( aCntPos );
// auch f?rs undo?
// if( aBkmkArr.Count() )
// _RestoreCntntIdx( aBkmkArr, *pNewNd, nChPos,
// nChPos + 1 );
const SwNodeIndex aTmpIdx( aCellIter->aStart, 0 );
SwNodeIndex aCellEndIdx(aCellIter->aEnd);
++aCellEndIdx;
SwStartNode* pSttNd = new SwStartNode( aTmpIdx, ND_STARTNODE,
SwTableBoxStartNode );
new SwEndNode( aCellEndIdx, *pSttNd );
//set the start node on all node of the current cell
SwNodeIndex aCellNodeIdx = aCellIter->aStart;
for(;aCellNodeIdx <= aCellIter->aEnd; ++aCellNodeIdx )
{
aCellNodeIdx.GetNode().pStartOfSection = pSttNd;
//skip start/end node pairs
if( aCellNodeIdx.GetNode().IsStartNode() )
aCellNodeIdx = SwNodeIndex( *aCellNodeIdx.GetNode().EndOfSectionNode() );
}
// Section der Box zuweisen
pBox = new SwTableBox( pBoxFmt, *pSttNd, pLine );
pLine->GetTabBoxes().C40_INSERT( SwTableBox, pBox, nBoxes++ );
}
if( nMaxBoxes < nBoxes )
nMaxBoxes = nBoxes;
}
// die Tabelle ausgleichen, leere Sections einfuegen
sal_uInt16 n;
if( aPosArr.Count() )
{
SwTableLines& rLns = pTable->GetTabLines();
sal_uInt16 nLastPos = 0;
for( n = 0; n < aPosArr.Count(); ++n )
{
SwTableBoxFmt *pNewFmt = pDoc->MakeTableBoxFmt();
pNewFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE,
aPosArr[ n ] - nLastPos ));
for( sal_uInt16 nLines2 = 0; nLines2 < rLns.Count(); ++nLines2 )
//JP 24.06.98: hier muss ein Add erfolgen, da das BoxFormat
// von der rufenden Methode noch gebraucht wird!
pNewFmt->Add( rLns[ nLines2 ]->GetTabBoxes()[ n ] );
nLastPos = aPosArr[ n ];
}
// damit die Tabelle die richtige Groesse bekommt, im BoxFormat die
// Groesse nach "oben" transportieren.
ASSERT( !pBoxFmt->GetDepends(), "wer ist in dem Format noch angemeldet" );
pBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nLastPos ));
}
else
pBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, USHRT_MAX / nMaxBoxes ));
// das wars doch wohl ??
return pTblNd;
}
//---------------- Tabelle -> Text -----------------------
sal_Bool SwDoc::TableToText( const SwTableNode* pTblNd, sal_Unicode cCh )
{
if( !pTblNd )
return sal_False;
// --> FME 2004-09-28 #i34471#
// If this is trigged by SwUndoTblToTxt::Repeat() nobody ever deleted
// the table cursor.
SwEditShell* pESh = GetEditShell();
if( pESh && pESh->IsTableMode() )
pESh->ClearMark();
// <--
#ifdef DEL_TABLE_REDLINES
lcl_DelRedlines aDelRedl( *pTblNd, sal_False );
#endif
SwNodeRange aRg( *pTblNd, 0, *pTblNd->EndOfSectionNode() );
SwUndoTblToTxt* pUndo = 0;
SwNodeRange* pUndoRg = 0;
if (GetIDocumentUndoRedo().DoesUndo())
{
GetIDocumentUndoRedo().ClearRedo();
pUndoRg = new SwNodeRange( aRg.aStart, -1, aRg.aEnd, +1 );
pUndo = new SwUndoTblToTxt( pTblNd->GetTable(), cCh );
}
SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() );
aMsgHnt.eFlags = TBL_BOXNAME;
UpdateTblFlds( &aMsgHnt );
sal_Bool bRet = GetNodes().TableToText( aRg, cCh, pUndo );
if( pUndoRg )
{
pUndoRg->aStart++;
pUndoRg->aEnd--;
pUndo->SetRange( *pUndoRg );
GetIDocumentUndoRedo().AppendUndo(pUndo);
delete pUndoRg;
}
if( bRet )
SetModified();
return bRet;
}
// -- benutze die ForEach Methode vom PtrArray um aus einer Tabelle wieder
// Text zuerzeugen. (Die Boxen koennen auch noch Lines enthalten !!)
struct _DelTabPara
{
SwTxtNode* pLastNd;
SwNodes& rNds;
SwUndoTblToTxt* pUndo;
sal_Unicode cCh;
_DelTabPara( SwNodes& rNodes, sal_Unicode cChar, SwUndoTblToTxt* pU ) :
pLastNd(0), rNds( rNodes ), pUndo( pU ), cCh( cChar ) {}
_DelTabPara( const _DelTabPara& rPara ) :
pLastNd(rPara.pLastNd), rNds( rPara.rNds ),
pUndo( rPara.pUndo ), cCh( rPara.cCh ) {}
};
// forward deklarieren damit sich die Lines und Boxen rekursiv aufrufen
// koennen.
sal_Bool lcl_DelBox( const SwTableBox*&, void *pPara );
sal_Bool lcl_DelLine( const SwTableLine*& rpLine, void* pPara )
{
ASSERT( pPara, "die Parameter fehlen" );
_DelTabPara aPara( *(_DelTabPara*)pPara );
((SwTableLine*&)rpLine)->GetTabBoxes().ForEach( &lcl_DelBox, &aPara );
if( rpLine->GetUpper() ) // gibt es noch eine uebergeordnete Box ??
// dann gebe den letzten TextNode zurueck
((_DelTabPara*)pPara)->pLastNd = aPara.pLastNd;
return sal_True;
}
sal_Bool lcl_DelBox( const SwTableBox*& rpBox, void* pPara )
{
ASSERT( pPara, "die Parameter fehlen" );
// loesche erstmal die Lines der Box
_DelTabPara* pDelPara = (_DelTabPara*)pPara;
if( rpBox->GetTabLines().Count() )
((SwTableBox*&)rpBox)->GetTabLines().ForEach( &lcl_DelLine, pDelPara );
else
{
SwDoc* pDoc = pDelPara->rNds.GetDoc();
SwNodeRange aDelRg( *rpBox->GetSttNd(), 0,
*rpBox->GetSttNd()->EndOfSectionNode() );
// loesche die Section
pDelPara->rNds.SectionUp( &aDelRg );
const SwTxtNode* pCurTxtNd;
if( T2T_PARA != pDelPara->cCh && pDelPara->pLastNd &&
0 != ( pCurTxtNd = aDelRg.aStart.GetNode().GetTxtNode() ))
{
// Join the current text node with the last from the previous box if possible
sal_uLong nNdIdx = aDelRg.aStart.GetIndex();
aDelRg.aStart--;
if( pDelPara->pLastNd == &aDelRg.aStart.GetNode() )
{
// Inserting the seperator
SwIndex aCntIdx( pDelPara->pLastNd, pDelPara->pLastNd->GetTxt().Len());
pDelPara->pLastNd->InsertText( pDelPara->cCh, aCntIdx,
IDocumentContentOperations::INS_EMPTYEXPAND );
if( pDelPara->pUndo )
pDelPara->pUndo->AddBoxPos( *pDoc, nNdIdx, aDelRg.aEnd.GetIndex(),
aCntIdx.GetIndex() );
SvULongs aBkmkArr( 4, 4 );
xub_StrLen nOldTxtLen = aCntIdx.GetIndex();
_SaveCntntIdx( pDoc, nNdIdx, pCurTxtNd->GetTxt().Len(),
aBkmkArr );
pDelPara->pLastNd->JoinNext();
if( aBkmkArr.Count() )
_RestoreCntntIdx( pDoc, aBkmkArr,
pDelPara->pLastNd->GetIndex(),
nOldTxtLen );
}
else if( pDelPara->pUndo )
{
aDelRg.aStart++;
pDelPara->pUndo->AddBoxPos( *pDoc, nNdIdx, aDelRg.aEnd.GetIndex() );
}
}
else if( pDelPara->pUndo )
pDelPara->pUndo->AddBoxPos( *pDoc, aDelRg.aStart.GetIndex(), aDelRg.aEnd.GetIndex() );
aDelRg.aEnd--;
pDelPara->pLastNd = aDelRg.aEnd.GetNode().GetTxtNode();
//JP 03.04.97: die Ausrichtung der ZahlenFormatierung auf
// keinen Fall uebernehmen
if( pDelPara->pLastNd && pDelPara->pLastNd->HasSwAttrSet() )
pDelPara->pLastNd->ResetAttr( RES_PARATR_ADJUST );
}
return sal_True;
}
sal_Bool SwNodes::TableToText( const SwNodeRange& rRange, sal_Unicode cCh,
SwUndoTblToTxt* pUndo )
{
// ist eine Tabelle selektiert ?
SwTableNode* pTblNd;
if( rRange.aStart.GetIndex() >= rRange.aEnd.GetIndex() ||
0 == ( pTblNd = rRange.aStart.GetNode().GetTableNode()) ||
&rRange.aEnd.GetNode() != pTblNd->EndOfSectionNode() )
return sal_False;
// stand die Tabelle ganz alleine in einer Section ?
// dann ueber den Upper der Tabelle die Frames anlegen
SwNode2Layout* pNode2Layout = 0;
SwNodeIndex aFrmIdx( rRange.aStart );
SwNode* pFrmNd = FindPrvNxtFrmNode( aFrmIdx, &rRange.aEnd.GetNode() );
if( !pFrmNd )
// dann sammel mal alle Uppers ein
pNode2Layout = new SwNode2Layout( *pTblNd );
// loesche schon mal die Frames
pTblNd->DelFrms();
// dann "loeschen" die Tabellen und fasse alle Lines/Boxen zusammen
_DelTabPara aDelPara( *this, cCh, pUndo );
pTblNd->pTable->GetTabLines().ForEach( &lcl_DelLine, &aDelPara );
// jetzt ist aus jeder TableLine ein TextNode mit dem entsprechenden
// Trenner erzeugt worden. Es braucht nur noch die Table-Section
// geloescht und fuer die neuen TextNode die Frames erzeugt werden.
SwNodeRange aDelRg( rRange.aStart, rRange.aEnd );
// JP 14.01.97: hat die Tabelle PageDesc-/Break-Attribute? Dann in den
// ersten TextNode uebernehmen
{
// was ist mit UNDO???
const SfxItemSet& rTblSet = pTblNd->pTable->GetFrmFmt()->GetAttrSet();
const SfxPoolItem *pBreak, *pDesc;
if( SFX_ITEM_SET != rTblSet.GetItemState( RES_PAGEDESC, sal_False, &pDesc ))
pDesc = 0;
if( SFX_ITEM_SET != rTblSet.GetItemState( RES_BREAK, sal_False, &pBreak ))
pBreak = 0;
if( pBreak || pDesc )
{
SwNodeIndex aIdx( *pTblNd );
SwCntntNode* pCNd = GoNext( &aIdx );
if( pBreak )
pCNd->SetAttr( *pBreak );
if( pDesc )
pCNd->SetAttr( *pDesc );
}
}
SectionUp( &aDelRg ); // loesche die Section und damit die Tabelle
// #i28006#
sal_uLong nStt = aDelRg.aStart.GetIndex(), nEnd = aDelRg.aEnd.GetIndex();
if( !pFrmNd )
{
pNode2Layout->RestoreUpperFrms( *this,
aDelRg.aStart.GetIndex(), aDelRg.aEnd.GetIndex() );
delete pNode2Layout;
}
else
{
SwCntntNode *pCNd;
SwSectionNode *pSNd;
while( aDelRg.aStart.GetIndex() < nEnd )
{
if( 0 != ( pCNd = aDelRg.aStart.GetNode().GetCntntNode()))
{
if( pFrmNd->IsCntntNode() )
((SwCntntNode*)pFrmNd)->MakeFrms( *pCNd );
else if( pFrmNd->IsTableNode() )
((SwTableNode*)pFrmNd)->MakeFrms( aDelRg.aStart );
else if( pFrmNd->IsSectionNode() )
((SwSectionNode*)pFrmNd)->MakeFrms( aDelRg.aStart );
pFrmNd = pCNd;
}
else if( 0 != ( pSNd = aDelRg.aStart.GetNode().GetSectionNode()))
{
if( !pSNd->GetSection().IsHidden() && !pSNd->IsCntntHidden() )
{
pSNd->MakeFrms( &aFrmIdx, &aDelRg.aEnd );
pFrmNd = pSNd;
break;
}
aDelRg.aStart = *pSNd->EndOfSectionNode();
}
aDelRg.aStart++;
}
}
// #i28006# Fly frames have to be restored even if the table was
// #alone in the section
const SwSpzFrmFmts& rFlyArr = *GetDoc()->GetSpzFrmFmts();
for( sal_uInt16 n = 0; n < rFlyArr.Count(); ++n )
{
SwFrmFmt *const pFmt = (SwFrmFmt*)rFlyArr[n];
const SwFmtAnchor& rAnchor = pFmt->GetAnchor();
SwPosition const*const pAPos = rAnchor.GetCntntAnchor();
if (pAPos &&
((FLY_AT_PARA == rAnchor.GetAnchorId()) ||
(FLY_AT_CHAR == rAnchor.GetAnchorId())) &&
nStt <= pAPos->nNode.GetIndex() &&
pAPos->nNode.GetIndex() < nEnd )
{
pFmt->MakeFrms();
}
}
return sal_True;
}
// ----- einfuegen von Spalten/Zeilen ------------------------
sal_Bool SwDoc::InsertCol( const SwCursor& rCursor, sal_uInt16 nCnt, sal_Bool bBehind )
{
if( !::CheckSplitCells( rCursor, nCnt + 1, nsSwTblSearchType::TBLSEARCH_COL ) )
return sal_False;
// lasse ueber das Layout die Boxen suchen
SwSelBoxes aBoxes;
::GetTblSel( rCursor, aBoxes, nsSwTblSearchType::TBLSEARCH_COL );
sal_Bool bRet = sal_False;
if( aBoxes.Count() )
bRet = InsertCol( aBoxes, nCnt, bBehind );
return bRet;
}
sal_Bool SwDoc::InsertCol( const SwSelBoxes& rBoxes, sal_uInt16 nCnt, sal_Bool bBehind )
{
// uebers SwDoc fuer Undo !!
ASSERT( rBoxes.Count(), "keine gueltige Box-Liste" );
SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
if( !pTblNd )
return sal_False;
SwTable& rTbl = pTblNd->GetTable();
if( rTbl.ISA( SwDDETable ))
return sal_False;
#ifdef DEL_TABLE_REDLINES
lcl_DelRedlines aDelRedl( *pTblNd, sal_True );
#endif
SwTableSortBoxes aTmpLst( 0, 5 );
SwUndoTblNdsChg* pUndo = 0;
if (GetIDocumentUndoRedo().DoesUndo())
{
pUndo = new SwUndoTblNdsChg( UNDO_TABLE_INSCOL, rBoxes, *pTblNd,
0, 0, nCnt, bBehind, sal_False );
aTmpLst.Insert( &rTbl.GetTabSortBoxes(), 0, rTbl.GetTabSortBoxes().Count() );
}
bool bRet(false);
{
::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
SwTableFmlUpdate aMsgHnt( &rTbl );
aMsgHnt.eFlags = TBL_BOXPTR;
UpdateTblFlds( &aMsgHnt );
bRet = rTbl.InsertCol( this, rBoxes, nCnt, bBehind );
if (bRet)
{
SetModified();
::ClearFEShellTabCols();
SetFieldsDirty( true, NULL, 0 );
}
}
if( pUndo )
{
if( bRet )
{
pUndo->SaveNewBoxes( *pTblNd, aTmpLst );
GetIDocumentUndoRedo().AppendUndo( pUndo );
}
else
delete pUndo;
}
return bRet;
}
sal_Bool SwDoc::InsertRow( const SwCursor& rCursor, sal_uInt16 nCnt, sal_Bool bBehind )
{
// lasse ueber das Layout die Boxen suchen
SwSelBoxes aBoxes;
GetTblSel( rCursor, aBoxes, nsSwTblSearchType::TBLSEARCH_ROW );
sal_Bool bRet = sal_False;
if( aBoxes.Count() )
bRet = InsertRow( aBoxes, nCnt, bBehind );
return bRet;
}
sal_Bool SwDoc::InsertRow( const SwSelBoxes& rBoxes, sal_uInt16 nCnt, sal_Bool bBehind )
{
// uebers SwDoc fuer Undo !!
ASSERT( rBoxes.Count(), "keine gueltige Box-Liste" );
SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
if( !pTblNd )
return sal_False;
SwTable& rTbl = pTblNd->GetTable();
if( rTbl.ISA( SwDDETable ))
return sal_False;
#ifdef DEL_TABLE_REDLINES
lcl_DelRedlines aDelRedl( *pTblNd, sal_True );
#endif
SwTableSortBoxes aTmpLst( 0, 5 );
SwUndoTblNdsChg* pUndo = 0;
if (GetIDocumentUndoRedo().DoesUndo())
{
pUndo = new SwUndoTblNdsChg( UNDO_TABLE_INSROW,rBoxes, *pTblNd,
0, 0, nCnt, bBehind, sal_False );
aTmpLst.Insert( &rTbl.GetTabSortBoxes(), 0, rTbl.GetTabSortBoxes().Count() );
}
bool bRet(false);
{
::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
SwTableFmlUpdate aMsgHnt( &rTbl );
aMsgHnt.eFlags = TBL_BOXPTR;
UpdateTblFlds( &aMsgHnt );
bRet = rTbl.InsertRow( this, rBoxes, nCnt, bBehind );
if (bRet)
{
SetModified();
::ClearFEShellTabCols();
SetFieldsDirty( true, NULL, 0 );
}
}
if( pUndo )
{
if( bRet )
{
pUndo->SaveNewBoxes( *pTblNd, aTmpLst );
GetIDocumentUndoRedo().AppendUndo( pUndo );
}
else
delete pUndo;
}
return bRet;
}
// ----- loeschen von Spalten/Zeilen ------------------------
sal_Bool SwDoc::DeleteRow( const SwCursor& rCursor )
{
// lasse ueber das Layout die Boxen suchen
SwSelBoxes aBoxes;
GetTblSel( rCursor, aBoxes, nsSwTblSearchType::TBLSEARCH_ROW );
if( ::HasProtectedCells( aBoxes ))
return sal_False;
// die Crsr aus dem Loeschbereich entfernen.
// Der Cursor steht danach:
// - es folgt noch eine Zeile, in dieser
// - vorher steht noch eine Zeile, in dieser
// - sonst immer dahinter
{
SwTableNode* pTblNd = rCursor.GetNode()->FindTableNode();
if( pTblNd->GetTable().ISA( SwDDETable ))
return sal_False;
// suche alle Boxen / Lines
_FndBox aFndBox( 0, 0 );
{
_FndPara aPara( aBoxes, &aFndBox );
pTblNd->GetTable().GetTabLines().ForEach( &_FndLineCopyCol, &aPara );
}
if( !aFndBox.GetLines().Count() )
return sal_False;
SwEditShell* pESh = GetEditShell();
if( pESh )
{
pESh->KillPams();
// JP: eigentlich sollte man ueber alle Shells iterieren!!
}
_FndBox* pFndBox = &aFndBox;
while( 1 == pFndBox->GetLines().Count() &&
1 == pFndBox->GetLines()[0]->GetBoxes().Count() )
{
_FndBox* pTmp = pFndBox->GetLines()[0]->GetBoxes()[0];
if( pTmp->GetBox()->GetSttNd() )
break; // das ist sonst zu weit
pFndBox = pTmp;
}
SwTableLine* pDelLine = pFndBox->GetLines()[
pFndBox->GetLines().Count()-1 ]->GetLine();
SwTableBox* pDelBox = pDelLine->GetTabBoxes()[
pDelLine->GetTabBoxes().Count() - 1 ];
while( !pDelBox->GetSttNd() )
{
SwTableLine* pLn = pDelBox->GetTabLines()[
pDelBox->GetTabLines().Count()-1 ];
pDelBox = pLn->GetTabBoxes()[ pLn->GetTabBoxes().Count() - 1 ];
}
SwTableBox* pNextBox = pDelLine->FindNextBox( pTblNd->GetTable(),
pDelBox, sal_True );
while( pNextBox &&
pNextBox->GetFrmFmt()->GetProtect().IsCntntProtected() )
pNextBox = pNextBox->FindNextBox( pTblNd->GetTable(), pNextBox );
if( !pNextBox ) // keine nachfolgende? dann die vorhergehende
{
pDelLine = pFndBox->GetLines()[ 0 ]->GetLine();
pDelBox = pDelLine->GetTabBoxes()[ 0 ];
while( !pDelBox->GetSttNd() )
pDelBox = pDelBox->GetTabLines()[0]->GetTabBoxes()[0];
pNextBox = pDelLine->FindPreviousBox( pTblNd->GetTable(),
pDelBox, sal_True );
while( pNextBox &&
pNextBox->GetFrmFmt()->GetProtect().IsCntntProtected() )
pNextBox = pNextBox->FindPreviousBox( pTblNd->GetTable(), pNextBox );
}
sal_uLong nIdx;
if( pNextBox ) // dann den Cursor hier hinein
nIdx = pNextBox->GetSttIdx() + 1;
else // ansonsten hinter die Tabelle
nIdx = pTblNd->EndOfSectionIndex() + 1;
SwNodeIndex aIdx( GetNodes(), nIdx );
SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode();
if( !pCNd )
pCNd = GetNodes().GoNext( &aIdx );
if( pCNd )
{
// die Cursor von der Shell oder den uebergebenen Cursor aendern?
SwPaM* pPam = (SwPaM*)&rCursor;
pPam->GetPoint()->nNode = aIdx;
pPam->GetPoint()->nContent.Assign( pCNd, 0 );
pPam->SetMark(); // beide wollen etwas davon haben
pPam->DeleteMark();
}
}
// dann loesche doch die Zeilen
GetIDocumentUndoRedo().StartUndo(UNDO_ROW_DELETE, NULL);
sal_Bool bResult = DeleteRowCol( aBoxes );
GetIDocumentUndoRedo().EndUndo(UNDO_ROW_DELETE, NULL);
return bResult;
}
sal_Bool SwDoc::DeleteCol( const SwCursor& rCursor )
{
// lasse ueber das Layout die Boxen suchen
SwSelBoxes aBoxes;
GetTblSel( rCursor, aBoxes, nsSwTblSearchType::TBLSEARCH_COL );
if( ::HasProtectedCells( aBoxes ))
return sal_False;
// die Crsr muessen noch aus dem Loesch Bereich entfernt
// werden. Setze sie immer hinter/auf die Tabelle; ueber die
// Dokument-Position werden sie dann immer an die alte Position gesetzt.
SwEditShell* pESh = GetEditShell();
if( pESh )
{
const SwNode* pNd = rCursor.GetNode()->FindTableBoxStartNode();
pESh->ParkCrsr( SwNodeIndex( *pNd ) );
}
// dann loesche doch die Spalten
GetIDocumentUndoRedo().StartUndo(UNDO_COL_DELETE, NULL);
sal_Bool bResult = DeleteRowCol( aBoxes, true );
GetIDocumentUndoRedo().EndUndo(UNDO_COL_DELETE, NULL);
return bResult;
}
sal_Bool SwDoc::DeleteRowCol( const SwSelBoxes& rBoxes, bool bColumn )
{
if( ::HasProtectedCells( rBoxes ))
return sal_False;
// uebers SwDoc fuer Undo !!
ASSERT( rBoxes.Count(), "keine gueltige Box-Liste" );
SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
if( !pTblNd )
return sal_False;
if( pTblNd->GetTable().ISA( SwDDETable ))
return sal_False;
::ClearFEShellTabCols();
SwSelBoxes aSelBoxes;
aSelBoxes.Insert(rBoxes.GetData(), rBoxes.Count());
SwTable &rTable = pTblNd->GetTable();
long nMin = 0;
long nMax = 0;
if( rTable.IsNewModel() )
{
if( bColumn )
rTable.ExpandColumnSelection( aSelBoxes, nMin, nMax );
else
rTable.FindSuperfluousRows( aSelBoxes );
}
#ifdef DEL_TABLE_REDLINES
lcl_DelRedlines aDelRedl( *pTblNd, sal_True );
#endif
// soll die gesamte Tabelle geloescht werden ??
const sal_uLong nTmpIdx1 = pTblNd->GetIndex();
const sal_uLong nTmpIdx2 = aSelBoxes[ aSelBoxes.Count()-1 ]->GetSttNd()->
EndOfSectionIndex()+1;
if( pTblNd->GetTable().GetTabSortBoxes().Count() == aSelBoxes.Count() &&
aSelBoxes[0]->GetSttIdx()-1 == nTmpIdx1 &&
nTmpIdx2 == pTblNd->EndOfSectionIndex() )
{
sal_Bool bNewTxtNd = sal_False;
// steht diese auch noch alleine in einem FlyFrame ?
SwNodeIndex aIdx( *pTblNd, -1 );
const SwStartNode* pSttNd = aIdx.GetNode().GetStartNode();
if( pSttNd )
{
const sal_uLong nTblEnd = pTblNd->EndOfSectionIndex() + 1;
const sal_uLong nSectEnd = pSttNd->EndOfSectionIndex();
if( nTblEnd == nSectEnd )
{
if( SwFlyStartNode == pSttNd->GetStartNodeType() )
{
SwFrmFmt* pFmt = pSttNd->GetFlyFmt();
if( pFmt )
{
// Ok, das ist das gesuchte FlyFormat
DelLayoutFmt( pFmt );
return sal_True;
}
}
// kein Fly ?? also Kopf- oder Fusszeile: dann immer einen
// TextNode ueberig lassen.
// Undo koennen wir dann vergessen !!
bNewTxtNd = sal_True;
}
}
// kein Fly ?? also Kopf- oder Fusszeile: dann immer einen
// TextNode ueberig lassen.
aIdx++;
if (GetIDocumentUndoRedo().DoesUndo())
{
GetIDocumentUndoRedo().ClearRedo();
SwPaM aPaM( *pTblNd->EndOfSectionNode(), aIdx.GetNode() );
if( bNewTxtNd )
{
const SwNodeIndex aTmpIdx( *pTblNd->EndOfSectionNode(), 1 );
GetNodes().MakeTxtNode( aTmpIdx,
GetTxtCollFromPool( RES_POOLCOLL_STANDARD ) );
}
// save the cursors (UNO and otherwise)
SwPaM aSavePaM( SwNodeIndex( *pTblNd->EndOfSectionNode() ) );
if( ! aSavePaM.Move( fnMoveForward, fnGoNode ) )
{
*aSavePaM.GetMark() = SwPosition( *pTblNd );
aSavePaM.Move( fnMoveBackward, fnGoNode );
}
{
SwPaM const tmpPaM(*pTblNd, *pTblNd->EndOfSectionNode());
::PaMCorrAbs(tmpPaM, *aSavePaM.GetMark());
}
// harte SeitenUmbrueche am nachfolgenden Node verschieben
sal_Bool bSavePageBreak = sal_False, bSavePageDesc = sal_False;
sal_uLong nNextNd = pTblNd->EndOfSectionIndex()+1;
SwCntntNode* pNextNd = GetNodes()[ nNextNd ]->GetCntntNode();
if( pNextNd )
{
//JP 24.08.98: will man wirklich den PageDesc/Break vom
// nachfolgen Absatz ueberbuegeln?
// const SwAttrSet& rAttrSet = pNextNd->GetSwAttrSet();
// if( SFX_ITEM_SET != rAttrSet.GetItemState( RES_PAGEDESC ) &&
// SFX_ITEM_SET != rAttrSet.GetItemState( RES_BREAK ))
{
SwFrmFmt* pTableFmt = pTblNd->GetTable().GetFrmFmt();
const SfxPoolItem *pItem;
if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_PAGEDESC,
sal_False, &pItem ) )
{
pNextNd->SetAttr( *pItem );
bSavePageDesc = sal_True;
}
if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_BREAK,
sal_False, &pItem ) )
{
pNextNd->SetAttr( *pItem );
bSavePageBreak = sal_True;
}
}
}
SwUndoDelete* pUndo = new SwUndoDelete( aPaM );
if( bNewTxtNd )
pUndo->SetTblDelLastNd();
pUndo->SetPgBrkFlags( bSavePageBreak, bSavePageDesc );
pUndo->SetTableName(pTblNd->GetTable().GetFrmFmt()->GetName());
GetIDocumentUndoRedo().AppendUndo( pUndo );
}
else
{
if( bNewTxtNd )
{
const SwNodeIndex aTmpIdx( *pTblNd->EndOfSectionNode(), 1 );
GetNodes().MakeTxtNode( aTmpIdx,
GetTxtCollFromPool( RES_POOLCOLL_STANDARD ) );
}
// save the cursors (UNO and otherwise)
SwPaM aSavePaM( SwNodeIndex( *pTblNd->EndOfSectionNode() ) );
if( ! aSavePaM.Move( fnMoveForward, fnGoNode ) )
{
*aSavePaM.GetMark() = SwPosition( *pTblNd );
aSavePaM.Move( fnMoveBackward, fnGoNode );
}
{
SwPaM const tmpPaM(*pTblNd, *pTblNd->EndOfSectionNode());
::PaMCorrAbs(tmpPaM, *aSavePaM.GetMark());
}
// harte SeitenUmbrueche am nachfolgenden Node verschieben
SwCntntNode* pNextNd = GetNodes()[ pTblNd->EndOfSectionIndex()+1 ]->GetCntntNode();
if( pNextNd )
{
SwFrmFmt* pTableFmt = pTblNd->GetTable().GetFrmFmt();
const SfxPoolItem *pItem;
if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_PAGEDESC,
sal_False, &pItem ) )
pNextNd->SetAttr( *pItem );
if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_BREAK,
sal_False, &pItem ) )
pNextNd->SetAttr( *pItem );
}
pTblNd->DelFrms();
DeleteSection( pTblNd );
}
SetModified();
SetFieldsDirty( true, NULL, 0 );
return sal_True;
}
SwUndoTblNdsChg* pUndo = 0;
if (GetIDocumentUndoRedo().DoesUndo())
{
pUndo = new SwUndoTblNdsChg( UNDO_TABLE_DELBOX, aSelBoxes, *pTblNd,
nMin, nMax, 0, sal_False, sal_False );
}
bool bRet(false);
{
::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() );
aMsgHnt.eFlags = TBL_BOXPTR;
UpdateTblFlds( &aMsgHnt );
if (rTable.IsNewModel())
{
if (bColumn)
rTable.PrepareDeleteCol( nMin, nMax );
rTable.FindSuperfluousRows( aSelBoxes );
if (pUndo)
pUndo->ReNewBoxes( aSelBoxes );
}
bRet = rTable.DeleteSel( this, aSelBoxes, 0, pUndo, sal_True, sal_True );
if (bRet)
{
SetModified();
SetFieldsDirty( true, NULL, 0 );
}
}
if( pUndo )
{
if( bRet )
{
GetIDocumentUndoRedo().AppendUndo( pUndo );
}
else
delete pUndo;
}
return bRet;
}
// ---------- teilen / zusammenfassen von Boxen in der Tabelle --------
sal_Bool SwDoc::SplitTbl( const SwSelBoxes& rBoxes, sal_Bool bVert, sal_uInt16 nCnt,
sal_Bool bSameHeight )
{
// uebers SwDoc fuer Undo !!
ASSERT( rBoxes.Count() && nCnt, "keine gueltige Box-Liste" );
SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
if( !pTblNd )
return sal_False;
SwTable& rTbl = pTblNd->GetTable();
if( rTbl.ISA( SwDDETable ))
return sal_False;
#ifdef DEL_TABLE_REDLINES
lcl_DelRedlines aDelRedl( *pTblNd, sal_True );
#endif
SvULongs aNdsCnts;
SwTableSortBoxes aTmpLst( 0, 5 );
SwUndoTblNdsChg* pUndo = 0;
if (GetIDocumentUndoRedo().DoesUndo())
{
pUndo = new SwUndoTblNdsChg( UNDO_TABLE_SPLIT, rBoxes, *pTblNd, 0, 0,
nCnt, bVert, bSameHeight );
aTmpLst.Insert( &rTbl.GetTabSortBoxes(), 0, rTbl.GetTabSortBoxes().Count() );
if( !bVert )
{
for( sal_uInt16 n = 0; n < rBoxes.Count(); ++n )
{
const SwStartNode* pSttNd = rBoxes[ n ]->GetSttNd();
aNdsCnts.Insert( pSttNd->EndOfSectionIndex() -
pSttNd->GetIndex(), n );
}
}
}
bool bRet(false);
{
::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
SwTableFmlUpdate aMsgHnt( &rTbl );
aMsgHnt.eFlags = TBL_BOXPTR;
UpdateTblFlds( &aMsgHnt );
if (bVert)
bRet = rTbl.SplitCol( this, rBoxes, nCnt );
else
bRet = rTbl.SplitRow( this, rBoxes, nCnt, bSameHeight );
if (bRet)
{
SetModified();
SetFieldsDirty( true, NULL, 0 );
}
}
if( pUndo )
{
if( bRet )
{
if( bVert )
pUndo->SaveNewBoxes( *pTblNd, aTmpLst );
else
pUndo->SaveNewBoxes( *pTblNd, aTmpLst, rBoxes, aNdsCnts );
GetIDocumentUndoRedo().AppendUndo( pUndo );
}
else
delete pUndo;
}
return bRet;
}
sal_uInt16 SwDoc::MergeTbl( SwPaM& rPam )
{
// pruefe ob vom aktuellen Crsr der SPoint/Mark in einer Tabelle stehen
SwTableNode* pTblNd = rPam.GetNode()->FindTableNode();
if( !pTblNd )
return TBLMERGE_NOSELECTION;
SwTable& rTable = pTblNd->GetTable();
if( rTable.ISA(SwDDETable) )
return TBLMERGE_NOSELECTION;
sal_uInt16 nRet = TBLMERGE_NOSELECTION;
if( !rTable.IsNewModel() )
{
nRet =::CheckMergeSel( rPam );
if( TBLMERGE_OK != nRet )
return nRet;
nRet = TBLMERGE_NOSELECTION;
}
// --> FME 2004-10-08 #i33394#
GetIDocumentUndoRedo().StartUndo( UNDO_TABLE_MERGE, NULL );
// <--
#ifdef DEL_TABLE_REDLINES
if( !IsIgnoreRedline() && GetRedlineTbl().Count() )
DeleteRedline( *pTblNd, true, USHRT_MAX );
#endif
RedlineMode_t eOld = GetRedlineMode();
SetRedlineMode_intern((RedlineMode_t)(eOld | nsRedlineMode_t::REDLINE_IGNORE));
SwUndoTblMerge *const pUndo( (GetIDocumentUndoRedo().DoesUndo())
? new SwUndoTblMerge( rPam )
: 0 );
// lasse ueber das Layout die Boxen suchen
SwSelBoxes aBoxes;
SwSelBoxes aMerged;
SwTableBox* pMergeBox;
if( !rTable.PrepareMerge( rPam, aBoxes, aMerged, &pMergeBox, pUndo ) )
{ // no cells found to merge
SetRedlineMode_intern( eOld );
if( pUndo )
{
delete pUndo;
SwUndoId nLastUndoId(UNDO_EMPTY);
if (GetIDocumentUndoRedo().GetLastUndoInfo(0, & nLastUndoId)
&& (UNDO_REDLINE == nLastUndoId))
{
// FIXME: why is this horrible cleanup necessary?
SwUndoRedline *const pU = dynamic_cast<SwUndoRedline*>(
GetUndoManager().RemoveLastUndo());
if( pU->GetRedlSaveCount() )
{
SwEditShell *const pEditShell(GetEditShell(0));
OSL_ASSERT(pEditShell);
::sw::UndoRedoContext context(*this, *pEditShell);
static_cast<SfxUndoAction *>(pU)->UndoWithContext(context);
}
delete pU;
}
}
}
else
{
// die PaMs muessen noch aus dem Loesch Bereich entfernt
// werden. Setze sie immer hinter/auf die Tabelle; ueber die
// Dokument-Position werden sie dann immer an die alte Position gesetzt.
// Erstmal einen Index auf die Parkposition merken, denn nach GetMergeSel
// komme ich nicht mehr dran.
{
rPam.DeleteMark();
rPam.GetPoint()->nNode = *pMergeBox->GetSttNd();
rPam.GetPoint()->nContent.Assign( 0, 0 );
rPam.SetMark();
rPam.DeleteMark();
SwPaM* pTmp = &rPam;
while( &rPam != ( pTmp = (SwPaM*)pTmp->GetNext() ))
for( int i = 0; i < 2; ++i )
pTmp->GetBound( (sal_Bool)i ) = *rPam.GetPoint();
}
// dann fuege sie zusammen
SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() );
aMsgHnt.eFlags = TBL_BOXPTR;
UpdateTblFlds( &aMsgHnt );
if( pTblNd->GetTable().Merge( this, aBoxes, aMerged, pMergeBox, pUndo ))
{
nRet = TBLMERGE_OK;
SetModified();
SetFieldsDirty( true, NULL, 0 );
if( pUndo )
{
GetIDocumentUndoRedo().AppendUndo( pUndo );
}
}
else if( pUndo )
delete pUndo;
rPam.GetPoint()->nNode = *pMergeBox->GetSttNd();
rPam.Move();
::ClearFEShellTabCols();
SetRedlineMode_intern( eOld );
}
GetIDocumentUndoRedo().EndUndo( UNDO_TABLE_MERGE, NULL );
return nRet;
}
// -------------------------------------------------------
//---------
// SwTableNode
//---------
SwTableNode::SwTableNode( const SwNodeIndex& rIdx )
: SwStartNode( rIdx, ND_TABLENODE )
{
pTable = new SwTable( 0 );
}
SwTableNode::~SwTableNode()
{
//don't forget to notify uno wrappers
SwFrmFmt* pTblFmt = GetTable().GetFrmFmt();
SwPtrMsgPoolItem aMsgHint( RES_REMOVE_UNO_OBJECT,
pTblFmt );
pTblFmt->ModifyNotification( &aMsgHint, &aMsgHint );
DelFrms();
delete pTable;
}
SwTabFrm *SwTableNode::MakeFrm( SwFrm* pSib )
{
return new SwTabFrm( *pTable, pSib );
}
//Methode erzeugt fuer den vorhergehenden Node alle Ansichten vom
//Dokument. Die erzeugten Contentframes werden in das entsprechende
//Layout gehaengt.
void SwTableNode::MakeFrms(const SwNodeIndex & rIdx )
{
if( !GetTable().GetFrmFmt()->GetDepends())//gibt es ueberhaupt Frames ??
return;
SwFrm *pFrm, *pNew;
SwCntntNode * pNode = rIdx.GetNode().GetCntntNode();
ASSERT( pNode, "Kein Contentnode oder Copy-Node und neuer Node identisch.");
sal_Bool bBefore = rIdx < GetIndex();
SwNode2Layout aNode2Layout( *this, rIdx.GetIndex() );
while( 0 != (pFrm = aNode2Layout.NextFrm()) )
{
pNew = pNode->MakeFrm( pFrm );
// wird ein Node vorher oder nachher mit Frames versehen
if ( bBefore )
// der neue liegt vor mir
pNew->Paste( pFrm->GetUpper(), pFrm );
else
// der neue liegt hinter mir
pNew->Paste( pFrm->GetUpper(), pFrm->GetNext() );
}
}
//Fuer jede Shell einen TblFrm anlegen und vor den entsprechenden
//CntntFrm pasten.
void SwTableNode::MakeFrms( SwNodeIndex* pIdxBehind )
{
ASSERT( pIdxBehind, "kein Index" );
*pIdxBehind = *this;
SwNode *pNd = GetNodes().FindPrvNxtFrmNode( *pIdxBehind, EndOfSectionNode() );
if( !pNd )
return ;
SwFrm *pFrm( 0L );
SwLayoutFrm *pUpper( 0L );
SwNode2Layout aNode2Layout( *pNd, GetIndex() );
while( 0 != (pUpper = aNode2Layout.UpperFrm( pFrm, *this )) )
{
SwTabFrm* pNew = MakeFrm( pUpper );
pNew->Paste( pUpper, pFrm );
// --> OD 2005-12-01 #i27138#
// notify accessibility paragraphs objects about changed
// CONTENT_FLOWS_FROM/_TO relation.
// Relation CONTENT_FLOWS_FROM for next paragraph will change
// and relation CONTENT_FLOWS_TO for previous paragraph will change.
{
ViewShell* pViewShell( pNew->getRootFrm()->GetCurrShell() );
if ( pViewShell && pViewShell->GetLayout() &&
pViewShell->GetLayout()->IsAnyShellAccessible() )
{
pViewShell->InvalidateAccessibleParaFlowRelation(
dynamic_cast<SwTxtFrm*>(pNew->FindNextCnt( true )),
dynamic_cast<SwTxtFrm*>(pNew->FindPrevCnt( true )) );
}
}
// <--
((SwTabFrm*)pNew)->RegistFlys();
}
}
void SwTableNode::DelFrms()
{
//Erstmal die TabFrms ausschneiden und deleten, die Columns und Rows
//nehmen sie mit in's Grab.
//Die TabFrms haengen am FrmFmt des SwTable.
//Sie muessen etwas umstaendlich zerstort werden, damit die Master
//die Follows mit in's Grab nehmen.
SwIterator<SwTabFrm,SwFmt> aIter( *(pTable->GetFrmFmt()) );
SwTabFrm *pFrm = aIter.First();
while ( pFrm )
{
sal_Bool bAgain = sal_False;
{
if ( !pFrm->IsFollow() )
{
while ( pFrm->HasFollow() )
pFrm->JoinAndDelFollows();
// --> OD 2005-12-01 #i27138#
// notify accessibility paragraphs objects about changed
// CONTENT_FLOWS_FROM/_TO relation.
// Relation CONTENT_FLOWS_FROM for current next paragraph will change
// and relation CONTENT_FLOWS_TO for current previous paragraph will change.
{
ViewShell* pViewShell( pFrm->getRootFrm()->GetCurrShell() );
if ( pViewShell && pViewShell->GetLayout() &&
pViewShell->GetLayout()->IsAnyShellAccessible() )
{
pViewShell->InvalidateAccessibleParaFlowRelation(
dynamic_cast<SwTxtFrm*>(pFrm->FindNextCnt( true )),
dynamic_cast<SwTxtFrm*>(pFrm->FindPrevCnt( true )) );
}
}
// <--
pFrm->Cut();
delete pFrm;
bAgain = sal_True;
}
}
pFrm = bAgain ? aIter.First() : aIter.Next();
}
}
void SwTableNode::SetNewTable( SwTable* pNewTable, sal_Bool bNewFrames )
{
DelFrms();
delete pTable;
pTable = pNewTable;
if( bNewFrames )
{
SwNodeIndex aIdx( *EndOfSectionNode());
GetNodes().GoNext( &aIdx );
MakeFrms( &aIdx );
}
}
void SwDoc::GetTabCols( SwTabCols &rFill, const SwCursor* pCrsr,
const SwCellFrm* pBoxFrm ) const
{
const SwTableBox* pBox = 0;
SwTabFrm *pTab = 0;
if( pBoxFrm )
{
pTab = ((SwFrm*)pBoxFrm)->ImplFindTabFrm();
pBox = pBoxFrm->GetTabBox();
}
else if( pCrsr )
{
const SwCntntNode* pCNd = pCrsr->GetCntntNode();
if( !pCNd )
return ;
Point aPt;
const SwShellCrsr *pShCrsr = dynamic_cast<const SwShellCrsr*>(pCrsr);
if( pShCrsr )
aPt = pShCrsr->GetPtPos();
const SwFrm* pTmpFrm = pCNd->getLayoutFrm( pCNd->GetDoc()->GetCurrentLayout(), &aPt, 0, sal_False );
do {
pTmpFrm = pTmpFrm->GetUpper();
} while ( !pTmpFrm->IsCellFrm() );
pBoxFrm = (SwCellFrm*)pTmpFrm;
pTab = ((SwFrm*)pBoxFrm)->ImplFindTabFrm();
pBox = pBoxFrm->GetTabBox();
}
else if( !pCrsr && !pBoxFrm )
{
ASSERT( !this, "einer von beiden muss angegeben werden!" );
return ;
}
//Fix-Punkte setzen, LeftMin in Dokumentkoordinaten die anderen relativ.
SWRECTFN( pTab )
const SwPageFrm* pPage = pTab->FindPageFrm();
const sal_uLong nLeftMin = (pTab->Frm().*fnRect->fnGetLeft)() -
(pPage->Frm().*fnRect->fnGetLeft)();
const sal_uLong nRightMax = (pTab->Frm().*fnRect->fnGetRight)() -
(pPage->Frm().*fnRect->fnGetLeft)();
rFill.SetLeftMin ( nLeftMin );
rFill.SetLeft ( (pTab->Prt().*fnRect->fnGetLeft)() );
rFill.SetRight ( (pTab->Prt().*fnRect->fnGetRight)());
rFill.SetRightMax( nRightMax - nLeftMin );
pTab->GetTable()->GetTabCols( rFill, pBox );
}
//
// Here are some little helpers used in SwDoc::GetTabRows
//
#define ROWFUZZY 25
struct FuzzyCompare
{
bool operator() ( long s1, long s2 ) const;
};
bool FuzzyCompare::operator() ( long s1, long s2 ) const
{
return ( s1 < s2 && abs( s1 - s2 ) > ROWFUZZY );
}
bool lcl_IsFrmInColumn( const SwCellFrm& rFrm, SwSelBoxes& rBoxes )
{
for( sal_uInt16 i = 0; i < rBoxes.Count(); ++i )
{
if ( rFrm.GetTabBox() == rBoxes[ i ] )
return true;
}
return false;
}
//
// SwDoc::GetTabRows()
//
void SwDoc::GetTabRows( SwTabCols &rFill, const SwCursor* ,
const SwCellFrm* pBoxFrm ) const
{
ASSERT( pBoxFrm, "GetTabRows called without pBoxFrm" )
// --> FME 2005-09-12 #121591# Make code robust:
if ( !pBoxFrm )
return;
// <--
// --> FME 2005-01-06 #i39552# Collection of the boxes of the current
// column has to be done at the beginning of this function, because
// the table may be formatted in ::GetTblSel.
SwDeletionChecker aDelCheck( pBoxFrm );
SwSelBoxes aBoxes;
const SwCntntFrm* pCntnt = ::GetCellCntnt( *pBoxFrm );
if ( pCntnt && pCntnt->IsTxtFrm() )
{
const SwPosition aPos( *((SwTxtFrm*)pCntnt)->GetTxtNode() );
const SwCursor aTmpCrsr( aPos, 0, false );
::GetTblSel( aTmpCrsr, aBoxes, nsSwTblSearchType::TBLSEARCH_COL );
}
// <--
// --> FME 2005-09-12 #121591# Make code robust:
if ( aDelCheck.HasBeenDeleted() )
{
ASSERT( false, "Current box has been deleted during GetTabRows()" )
return;
}
// <--
// --> FME 2005-09-12 #121591# Make code robust:
const SwTabFrm* pTab = pBoxFrm->FindTabFrm();
ASSERT( pTab, "GetTabRows called without a table" )
if ( !pTab )
return;
// <--
const SwFrm* pFrm = pTab->GetNextLayoutLeaf();
//Fix-Punkte setzen, LeftMin in Dokumentkoordinaten die anderen relativ.
SWRECTFN( pTab )
const SwPageFrm* pPage = pTab->FindPageFrm();
const long nLeftMin = ( bVert ?
pTab->GetPrtLeft() - pPage->Frm().Left() :
pTab->GetPrtTop() - pPage->Frm().Top() );
const long nLeft = bVert ? LONG_MAX : 0;
const long nRight = (pTab->Prt().*fnRect->fnGetHeight)();
const long nRightMax = bVert ? nRight : LONG_MAX;
rFill.SetLeftMin( nLeftMin );
rFill.SetLeft( nLeft );
rFill.SetRight( nRight );
rFill.SetRightMax( nRightMax );
typedef std::map< long, std::pair< long, long >, FuzzyCompare > BoundaryMap;
BoundaryMap aBoundaries;
BoundaryMap::iterator aIter;
std::pair< long, long > aPair;
typedef std::map< long, bool > HiddenMap;
HiddenMap aHidden;
HiddenMap::iterator aHiddenIter;
while ( pFrm && pTab->IsAnLower( pFrm ) )
{
if ( pFrm->IsCellFrm() && pFrm->FindTabFrm() == pTab )
{
// upper and lower borders of current cell frame:
long nUpperBorder = (pFrm->Frm().*fnRect->fnGetTop)();
long nLowerBorder = (pFrm->Frm().*fnRect->fnGetBottom)();
// get boundaries for nUpperBorder:
aIter = aBoundaries.find( nUpperBorder );
if ( aIter == aBoundaries.end() )
{
aPair.first = nUpperBorder; aPair.second = LONG_MAX;
aBoundaries[ nUpperBorder ] = aPair;
}
// get boundaries for nLowerBorder:
aIter = aBoundaries.find( nLowerBorder );
if ( aIter == aBoundaries.end() )
{
aPair.first = nUpperBorder; aPair.second = LONG_MAX;
}
else
{
nLowerBorder = (*aIter).first;
long nNewLowerBorderUpperBoundary = Max( (*aIter).second.first, nUpperBorder );
aPair.first = nNewLowerBorderUpperBoundary; aPair.second = LONG_MAX;
}
aBoundaries[ nLowerBorder ] = aPair;
// calculate hidden flags for entry nUpperBorder/nLowerBorder:
long nTmpVal = nUpperBorder;
for ( sal_uInt8 i = 0; i < 2; ++i )
{
aHiddenIter = aHidden.find( nTmpVal );
if ( aHiddenIter == aHidden.end() )
aHidden[ nTmpVal ] = !lcl_IsFrmInColumn( *((SwCellFrm*)pFrm), aBoxes );
else
{
if ( aHidden[ nTmpVal ] &&
lcl_IsFrmInColumn( *((SwCellFrm*)pFrm), aBoxes ) )
aHidden[ nTmpVal ] = false;
}
nTmpVal = nLowerBorder;
}
}
pFrm = pFrm->GetNextLayoutLeaf();
}
// transfer calculated values from BoundaryMap and HiddenMap into rFill:
sal_uInt16 nIdx = 0;
for ( aIter = aBoundaries.begin(); aIter != aBoundaries.end(); ++aIter )
{
const long nTabTop = (pTab->*fnRect->fnGetPrtTop)();
const long nKey = (*fnRect->fnYDiff)( (*aIter).first, nTabTop );
const std::pair< long, long > aTmpPair = (*aIter).second;
const long nFirst = (*fnRect->fnYDiff)( aTmpPair.first, nTabTop );
const long nSecond = aTmpPair.second;
aHiddenIter = aHidden.find( (*aIter).first );
const bool bHidden = aHiddenIter != aHidden.end() && (*aHiddenIter).second;
rFill.Insert( nKey, nFirst, nSecond, bHidden, nIdx++ );
}
// delete first and last entry
ASSERT( rFill.Count(), "Deleting from empty vector. Fasten your seatbelts!" )
// --> FME 2006-01-19 #i60818# There may be only one entry in rFill. Make
// code robust by checking count of rFill.
if ( rFill.Count() ) rFill.Remove( 0, 1 );
if ( rFill.Count() ) rFill.Remove( rFill.Count() - 1 , 1 );
// <--
rFill.SetLastRowAllowedToChange( !pTab->HasFollowFlowLine() );
}
void SwDoc::SetTabCols( const SwTabCols &rNew, sal_Bool bCurRowOnly,
const SwCursor* pCrsr, const SwCellFrm* pBoxFrm )
{
const SwTableBox* pBox = 0;
SwTabFrm *pTab = 0;
if( pBoxFrm )
{
pTab = ((SwFrm*)pBoxFrm)->ImplFindTabFrm();
pBox = pBoxFrm->GetTabBox();
}
else if( pCrsr )
{
const SwCntntNode* pCNd = pCrsr->GetCntntNode();
if( !pCNd )
return ;
Point aPt;
const SwShellCrsr *pShCrsr = dynamic_cast<const SwShellCrsr*>(pCrsr);
if( pShCrsr )
aPt = pShCrsr->GetPtPos();
const SwFrm* pTmpFrm = pCNd->getLayoutFrm( pCNd->GetDoc()->GetCurrentLayout(), &aPt, 0, sal_False );
do {
pTmpFrm = pTmpFrm->GetUpper();
} while ( !pTmpFrm->IsCellFrm() );
pBoxFrm = (SwCellFrm*)pTmpFrm;
pTab = ((SwFrm*)pBoxFrm)->ImplFindTabFrm();
pBox = pBoxFrm->GetTabBox();
}
else if( !pCrsr && !pBoxFrm )
{
ASSERT( !this, "einer von beiden muss angegeben werden!" );
return ;
}
// sollte die Tabelle noch auf relativen Werten (USHRT_MAX) stehen
// dann muss es jetzt auf absolute umgerechnet werden.
SwTable& rTab = *pTab->GetTable();
const SwFmtFrmSize& rTblFrmSz = rTab.GetFrmFmt()->GetFrmSize();
SWRECTFN( pTab )
// OD 06.08.2003 #i17174# - With fix for #i9040# the shadow size is taken
// from the table width. Thus, add its left and right size to current table
// printing area width in order to get the correct table size attribute.
SwTwips nPrtWidth = (pTab->Prt().*fnRect->fnGetWidth)();
{
SvxShadowItem aShadow( rTab.GetFrmFmt()->GetShadow() );
nPrtWidth += aShadow.CalcShadowSpace( SHADOW_LEFT ) +
aShadow.CalcShadowSpace( SHADOW_RIGHT );
}
if( nPrtWidth != rTblFrmSz.GetWidth() )
{
SwFmtFrmSize aSz( rTblFrmSz );
aSz.SetWidth( nPrtWidth );
rTab.GetFrmFmt()->SetFmtAttr( aSz );
}
SwTabCols aOld( rNew.Count() );
const SwPageFrm* pPage = pTab->FindPageFrm();
const sal_uLong nLeftMin = (pTab->Frm().*fnRect->fnGetLeft)() -
(pPage->Frm().*fnRect->fnGetLeft)();
const sal_uLong nRightMax = (pTab->Frm().*fnRect->fnGetRight)() -
(pPage->Frm().*fnRect->fnGetLeft)();
//Fix-Punkte setzen, LeftMin in Dokumentkoordinaten die anderen relativ.
aOld.SetLeftMin ( nLeftMin );
aOld.SetLeft ( (pTab->Prt().*fnRect->fnGetLeft)() );
aOld.SetRight ( (pTab->Prt().*fnRect->fnGetRight)());
aOld.SetRightMax( nRightMax - nLeftMin );
rTab.GetTabCols( aOld, pBox );
SetTabCols(rTab, rNew, aOld, pBox, bCurRowOnly );
}
void SwDoc::SetTabRows( const SwTabCols &rNew, sal_Bool bCurColOnly, const SwCursor*,
const SwCellFrm* pBoxFrm )
{
const SwTableBox* pBox;
SwTabFrm *pTab;
ASSERT( pBoxFrm, "SetTabRows called without pBoxFrm" )
pTab = ((SwFrm*)pBoxFrm)->ImplFindTabFrm();
pBox = pBoxFrm->GetTabBox();
// sollte die Tabelle noch auf relativen Werten (USHRT_MAX) stehen
// dann muss es jetzt auf absolute umgerechnet werden.
SWRECTFN( pTab )
SwTabCols aOld( rNew.Count() );
//Fix-Punkte setzen, LeftMin in Dokumentkoordinaten die anderen relativ.
const SwPageFrm* pPage = pTab->FindPageFrm();
aOld.SetRight( (pTab->Prt().*fnRect->fnGetHeight)() );
long nLeftMin;
if ( bVert )
{
nLeftMin = pTab->GetPrtLeft() - pPage->Frm().Left();
aOld.SetLeft ( LONG_MAX );
aOld.SetRightMax( aOld.GetRight() );
}
else
{
nLeftMin = pTab->GetPrtTop() - pPage->Frm().Top();
aOld.SetLeft ( 0 );
aOld.SetRightMax( LONG_MAX );
}
aOld.SetLeftMin ( nLeftMin );
GetTabRows( aOld, 0, pBoxFrm );
GetIDocumentUndoRedo().StartUndo( UNDO_TABLE_ATTR, NULL );
// check for differences between aOld and rNew:
const sal_uInt16 nCount = rNew.Count();
const SwTable* pTable = pTab->GetTable();
ASSERT( pTable, "My colleague told me, this couldn't happen" );
for ( sal_uInt16 i = 0; i <= nCount; ++i )
{
const sal_uInt16 nIdxStt = bVert ? nCount - i : i - 1;
const sal_uInt16 nIdxEnd = bVert ? nCount - i - 1 : i;
const long nOldRowStart = i == 0 ? 0 : aOld[ nIdxStt ];
const long nOldRowEnd = i == nCount ? aOld.GetRight() : aOld[ nIdxEnd ];
const long nOldRowHeight = nOldRowEnd - nOldRowStart;
const long nNewRowStart = i == 0 ? 0 : rNew[ nIdxStt ];
const long nNewRowEnd = i == nCount ? rNew.GetRight() : rNew[ nIdxEnd ];
const long nNewRowHeight = nNewRowEnd - nNewRowStart;
const long nDiff = nNewRowHeight - nOldRowHeight;
if ( abs( nDiff ) >= ROWFUZZY )
{
// For the old table model pTxtFrm and pLine will be set for every box.
// For the new table model pTxtFrm will be set if the box is not covered,
// but the pLine will be set if the box is not an overlapping box
// In the new table model the row height can be adjusted,
// when both variables are set.
SwTxtFrm* pTxtFrm = 0;
const SwTableLine* pLine = 0;
// Iterate over all SwCellFrms with Bottom = nOldPos
const SwFrm* pFrm = pTab->GetNextLayoutLeaf();
while ( pFrm && pTab->IsAnLower( pFrm ) )
{
if ( pFrm->IsCellFrm() && pFrm->FindTabFrm() == pTab )
{
const long nLowerBorder = (pFrm->Frm().*fnRect->fnGetBottom)();
const sal_uLong nTabTop = (pTab->*fnRect->fnGetPrtTop)();
if ( abs( (*fnRect->fnYInc)( nTabTop, nOldRowEnd ) - nLowerBorder ) <= ROWFUZZY )
{
if ( !bCurColOnly || pFrm == pBoxFrm )
{
const SwFrm* pCntnt = ::GetCellCntnt( static_cast<const SwCellFrm&>(*pFrm) );
if ( pCntnt && pCntnt->IsTxtFrm() )
{
pBox = ((SwCellFrm*)pFrm)->GetTabBox();
const long nRowSpan = pBox->getRowSpan();
if( nRowSpan > 0 ) // Not overlapped
pTxtFrm = (SwTxtFrm*)pCntnt;
if( nRowSpan < 2 ) // Not overlapping for row height
pLine = pBox->GetUpper();
if( pLine && pTxtFrm ) // always for old table model
{
// The new row height must not to be calculated from a overlapping box
SwFmtFrmSize aNew( pLine->GetFrmFmt()->GetFrmSize() );
const long nNewSize = (pFrm->Frm().*fnRect->fnGetHeight)() + nDiff;
if( nNewSize != aNew.GetHeight() )
{
aNew.SetHeight( nNewSize );
if ( ATT_VAR_SIZE == aNew.GetHeightSizeType() )
aNew.SetHeightSizeType( ATT_MIN_SIZE );
// This position must not be in an overlapped box
const SwPosition aPos( *((SwTxtFrm*)pCntnt)->GetTxtNode() );
const SwCursor aTmpCrsr( aPos, 0, false );
SetRowHeight( aTmpCrsr, aNew );
// For the new table model we're done, for the old one
// there might be another (sub)row to adjust...
if( pTable->IsNewModel() )
break;
}
pLine = 0;
}
}
}
}
}
pFrm = pFrm->GetNextLayoutLeaf();
}
}
}
GetIDocumentUndoRedo().EndUndo( UNDO_TABLE_ATTR, NULL );
::ClearFEShellTabCols();
}
/* -----------------18.07.98 11:45-------------------
* Direktzugriff fuer UNO
* --------------------------------------------------*/
void SwDoc::SetTabCols(SwTable& rTab, const SwTabCols &rNew, const SwTabCols &rOld,
const SwTableBox *pStart, sal_Bool bCurRowOnly )
{
if (GetIDocumentUndoRedo().DoesUndo())
{
GetIDocumentUndoRedo().AppendUndo(
new SwUndoAttrTbl( *rTab.GetTableNode(), sal_True ));
}
rTab.SetTabCols( rNew, rOld, pStart, bCurRowOnly );
::ClearFEShellTabCols();
SetModified();
}
void SwDoc::SetRowsToRepeat( SwTable &rTable, sal_uInt16 nSet )
{
if( nSet == rTable.GetRowsToRepeat() )
return;
if (GetIDocumentUndoRedo().DoesUndo())
{
GetIDocumentUndoRedo().AppendUndo(
new SwUndoTblHeadline(rTable, rTable.GetRowsToRepeat(), nSet) );
}
SwMsgPoolItem aChg( RES_TBLHEADLINECHG );
rTable.SetRowsToRepeat( nSet );
rTable.GetFrmFmt()->ModifyNotification( &aChg, &aChg );
SetModified();
}
// Splittet eine Tabelle in der Grund-Zeile, in der der Index steht.
// Alle GrundZeilen dahinter wandern in eine neue Tabelle/-Node.
// Ist das Flag bCalcNewSize auf sal_True, wird fuer beide neuen Tabellen
// die neue Size aus dem Max der Boxen errechnet; vorrausgesetzt,
// die Size ist "absolut" gesetzt (USHRT_MAX)
void SwCollectTblLineBoxes::AddToUndoHistory( const SwCntntNode& rNd )
{
if( pHst )
pHst->Add( rNd.GetFmtColl(), rNd.GetIndex(), ND_TEXTNODE );
}
void SwCollectTblLineBoxes::AddBox( const SwTableBox& rBox )
{
aPosArr.Insert( nWidth, aPosArr.Count() );
SwTableBox* p = (SwTableBox*)&rBox;
aBoxes.Insert( p, aBoxes.Count() );
nWidth = nWidth + (sal_uInt16)rBox.GetFrmFmt()->GetFrmSize().GetWidth();
}
const SwTableBox* SwCollectTblLineBoxes::GetBoxOfPos( const SwTableBox& rBox )
{
const SwTableBox* pRet = 0;
sal_uInt16 n;
if( aPosArr.Count() )
{
for( n = 0; n < aPosArr.Count(); ++n )
if( aPosArr[ n ] == nWidth )
break;
else if( aPosArr[ n ] > nWidth )
{
if( n )
--n;
break;
}
if( n >= aPosArr.Count() )
--n;
nWidth = nWidth + (sal_uInt16)rBox.GetFrmFmt()->GetFrmSize().GetWidth();
pRet = aBoxes[ n ];
}
return pRet;
}
sal_Bool SwCollectTblLineBoxes::Resize( sal_uInt16 nOffset, sal_uInt16 nOldWidth )
{
sal_uInt16 n;
if( aPosArr.Count() )
{
for( n = 0; n < aPosArr.Count(); ++n )
if( aPosArr[ n ] == nOffset )
break;
else if( aPosArr[ n ] > nOffset )
{
if( n )
--n;
break;
}
aPosArr.Remove( 0, n );
aBoxes.Remove( 0, n );
// dann die Positionen der neuen Size anpassen
for( n = 0; n < aPosArr.Count(); ++n )
{
sal_uLong nSize = nWidth;
nSize *= ( aPosArr[ n ] - nOffset );
nSize /= nOldWidth;
aPosArr[ n ] = sal_uInt16( nSize );
}
}
return 0 != aPosArr.Count();
}
sal_Bool lcl_Line_CollectBox( const SwTableLine*& rpLine, void* pPara )
{
SwCollectTblLineBoxes* pSplPara = (SwCollectTblLineBoxes*)pPara;
if( pSplPara->IsGetValues() )
((SwTableLine*)rpLine)->GetTabBoxes().ForEach( &lcl_Box_CollectBox, pPara );
else
((SwTableLine*)rpLine)->GetTabBoxes().ForEach( &lcl_BoxSetSplitBoxFmts, pPara );
return sal_True;
}
sal_Bool lcl_Box_CollectBox( const SwTableBox*& rpBox, void* pPara )
{
SwCollectTblLineBoxes* pSplPara = (SwCollectTblLineBoxes*)pPara;
sal_uInt16 nLen = rpBox->GetTabLines().Count();
if( nLen )
{
// dann mit der richtigen Line weitermachen
if( pSplPara->IsGetFromTop() )
nLen = 0;
else
--nLen;
const SwTableLine* pLn = rpBox->GetTabLines()[ nLen ];
lcl_Line_CollectBox( pLn, pPara );
}
else
pSplPara->AddBox( *rpBox );
return sal_True;
}
sal_Bool lcl_BoxSetSplitBoxFmts( const SwTableBox*& rpBox, void* pPara )
{
SwCollectTblLineBoxes* pSplPara = (SwCollectTblLineBoxes*)pPara;
sal_uInt16 nLen = rpBox->GetTabLines().Count();
if( nLen )
{
// dann mit der richtigen Line weitermachen
if( pSplPara->IsGetFromTop() )
nLen = 0;
else
--nLen;
const SwTableLine* pLn = rpBox->GetTabLines()[ nLen ];
lcl_Line_CollectBox( pLn, pPara );
}
else
{
const SwTableBox* pSrcBox = pSplPara->GetBoxOfPos( *rpBox );
SwFrmFmt* pFmt = pSrcBox->GetFrmFmt();
SwTableBox* pBox = (SwTableBox*)rpBox;
if( HEADLINE_BORDERCOPY == pSplPara->GetMode() )
{
const SvxBoxItem& rBoxItem = pBox->GetFrmFmt()->GetBox();
if( !rBoxItem.GetTop() )
{
SvxBoxItem aNew( rBoxItem );
aNew.SetLine( pFmt->GetBox().GetBottom(), BOX_LINE_TOP );
if( aNew != rBoxItem )
pBox->ClaimFrmFmt()->SetFmtAttr( aNew );
}
}
else
{
sal_uInt16 __FAR_DATA aTableSplitBoxSetRange[] = {
RES_LR_SPACE, RES_UL_SPACE,
RES_BACKGROUND, RES_SHADOW,
RES_PROTECT, RES_PROTECT,
RES_VERT_ORIENT, RES_VERT_ORIENT,
0 };
SfxItemSet aTmpSet( pFmt->GetDoc()->GetAttrPool(),
aTableSplitBoxSetRange );
aTmpSet.Put( pFmt->GetAttrSet() );
if( aTmpSet.Count() )
pBox->ClaimFrmFmt()->SetFmtAttr( aTmpSet );
if( HEADLINE_BOXATRCOLLCOPY == pSplPara->GetMode() )
{
SwNodeIndex aIdx( *pSrcBox->GetSttNd(), 1 );
SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode();
if( !pCNd )
pCNd = aIdx.GetNodes().GoNext( &aIdx );
aIdx = *pBox->GetSttNd();
SwCntntNode* pDNd = aIdx.GetNodes().GoNext( &aIdx );
// nur wenn der Node alleine in der Section steht
if( 2 == pDNd->EndOfSectionIndex() -
pDNd->StartOfSectionIndex() )
{
pSplPara->AddToUndoHistory( *pDNd );
pDNd->ChgFmtColl( pCNd->GetFmtColl() );
}
}
// bedingte Vorlage beachten
pBox->GetSttNd()->CheckSectionCondColl();
}
}
return sal_True;
}
sal_Bool SwDoc::SplitTable( const SwPosition& rPos, sal_uInt16 eHdlnMode,
sal_Bool bCalcNewSize )
{
SwNode* pNd = &rPos.nNode.GetNode();
SwTableNode* pTNd = pNd->FindTableNode();
if( !pTNd || pNd->IsTableNode() )
return 0;
if( pTNd->GetTable().ISA( SwDDETable ))
return sal_False;
SwTable& rTbl = pTNd->GetTable();
rTbl.SetHTMLTableLayout( 0 ); // MIB 9.7.97: HTML-Layout loeschen
SwTableFmlUpdate aMsgHnt( &rTbl );
SwHistory aHistory;
if (GetIDocumentUndoRedo().DoesUndo())
{
aMsgHnt.pHistory = &aHistory;
}
{
sal_uLong nSttIdx = pNd->FindTableBoxStartNode()->GetIndex();
// Suche die Grund-Line dieser Box:
SwTableBox* pBox = rTbl.GetTblBox( nSttIdx );
if( pBox )
{
SwTableLine* pLine = pBox->GetUpper();
while( pLine->GetUpper() )
pLine = pLine->GetUpper()->GetUpper();
// in pLine steht jetzt die GrundLine.
aMsgHnt.nSplitLine = rTbl.GetTabLines().C40_GETPOS( SwTableLine, pLine );
}
String sNewTblNm( GetUniqueTblName() );
aMsgHnt.DATA.pNewTblNm = &sNewTblNm;
aMsgHnt.eFlags = TBL_SPLITTBL;
UpdateTblFlds( &aMsgHnt );
}
//Lines fuer das Layout-Update heraussuchen.
_FndBox aFndBox( 0, 0 );
aFndBox.SetTableLines( rTbl );
aFndBox.DelFrms( rTbl );
// TL_CHART2: need to inform chart of probably changed cell names
//pDoc->UpdateCharts( rTbl.GetFrmFmt()->GetName() );
SwTableNode* pNew = GetNodes().SplitTable( rPos.nNode, sal_False, bCalcNewSize );
if( pNew )
{
SwSaveRowSpan* pSaveRowSp = pNew->GetTable().CleanUpTopRowSpan( rTbl.GetTabLines().Count() );
SwUndoSplitTbl* pUndo = 0;
if (GetIDocumentUndoRedo().DoesUndo())
{
pUndo = new SwUndoSplitTbl(
*pNew, pSaveRowSp, eHdlnMode, bCalcNewSize);
GetIDocumentUndoRedo().AppendUndo(pUndo);
if( aHistory.Count() )
pUndo->SaveFormula( aHistory );
}
switch( eHdlnMode )
{
// setze die untere Border der vorherige Line,
// an der aktuellen als obere
case HEADLINE_BORDERCOPY:
{
SwCollectTblLineBoxes aPara( sal_False, eHdlnMode );
SwTableLine* pLn = rTbl.GetTabLines()[
rTbl.GetTabLines().Count() - 1 ];
pLn->GetTabBoxes().ForEach( &lcl_Box_CollectBox, &aPara );
aPara.SetValues( sal_True );
pLn = pNew->GetTable().GetTabLines()[ 0 ];
pLn->GetTabBoxes().ForEach( &lcl_BoxSetSplitBoxFmts, &aPara );
// Kopfzeile wiederholen abschalten
pNew->GetTable().SetRowsToRepeat( 0 );
}
break;
// setze die Attributierung der ersten Line an der neuen ersten
case HEADLINE_BOXATTRCOPY:
case HEADLINE_BOXATRCOLLCOPY:
{
SwHistory* pHst = 0;
if( HEADLINE_BOXATRCOLLCOPY == eHdlnMode && pUndo )
pHst = pUndo->GetHistory();
SwCollectTblLineBoxes aPara( sal_True, eHdlnMode, pHst );
SwTableLine* pLn = rTbl.GetTabLines()[ 0 ];
pLn->GetTabBoxes().ForEach( &lcl_Box_CollectBox, &aPara );
aPara.SetValues( sal_True );
pLn = pNew->GetTable().GetTabLines()[ 0 ];
pLn->GetTabBoxes().ForEach( &lcl_BoxSetSplitBoxFmts, &aPara );
}
break;
case HEADLINE_CNTNTCOPY:
rTbl.CopyHeadlineIntoTable( *pNew );
if( pUndo )
pUndo->SetTblNodeOffset( pNew->GetIndex() );
break;
case HEADLINE_NONE:
// Kopfzeile wiederholen abschalten
pNew->GetTable().SetRowsToRepeat( 0 );
break;
}
// und Frms einfuegen.
SwNodeIndex aNdIdx( *pNew->EndOfSectionNode() );
GetNodes().GoNext( &aNdIdx ); // zum naechsten ContentNode
pNew->MakeFrms( &aNdIdx );
//Zwischen die Tabellen wird ein Absatz geschoben
GetNodes().MakeTxtNode( SwNodeIndex( *pNew ),
GetTxtCollFromPool( RES_POOLCOLL_TEXT ) );
}
//Layout updaten
aFndBox.MakeFrms( rTbl );
// TL_CHART2: need to inform chart of probably changed cell names
UpdateCharts( rTbl.GetFrmFmt()->GetName() );
SetFieldsDirty( true, NULL, 0 );
return 0 != pNew;
}
sal_Bool lcl_ChgTblSize( SwTable& rTbl )
{
// das Attribut darf nicht ueber das Modify an der
// Tabelle gesetzt werden, denn sonst werden alle
// Boxen wieder auf 0 zurueck gesetzt. Also locke das Format
SwFrmFmt* pFmt = rTbl.GetFrmFmt();
SwFmtFrmSize aTblMaxSz( pFmt->GetFrmSize() );
if( USHRT_MAX == aTblMaxSz.GetWidth() )
return sal_False;
sal_Bool bLocked = pFmt->IsModifyLocked();
pFmt->LockModify();
aTblMaxSz.SetWidth( 0 );
SwTableLines& rLns = rTbl.GetTabLines();
for( sal_uInt16 nLns = 0; nLns < rLns.Count(); ++nLns )
{
SwTwips nMaxLnWidth = 0;
SwTableBoxes& rBoxes = rLns[ nLns ]->GetTabBoxes();
for( sal_uInt16 nBox = 0; nBox < rBoxes.Count(); ++nBox )
nMaxLnWidth += rBoxes[nBox]->GetFrmFmt()->GetFrmSize().GetWidth();
if( nMaxLnWidth > aTblMaxSz.GetWidth() )
aTblMaxSz.SetWidth( nMaxLnWidth );
}
pFmt->SetFmtAttr( aTblMaxSz );
if( !bLocked ) // und gegebenenfalls Lock wieder freigeben
pFmt->UnlockModify();
return sal_True;
}
class _SplitTable_Para
{
SvPtrarr aSrc, aDest;
SwTableNode* pNewTblNd;
SwTable& rOldTbl;
public:
_SplitTable_Para( SwTableNode* pNew, SwTable& rOld )
: aSrc( 16, 16 ), aDest( 16, 16 ), pNewTblNd( pNew ), rOldTbl( rOld )
{}
sal_uInt16 SrcFmt_GetPos( void* pFmt ) const
{ return aSrc.GetPos( pFmt ); }
void DestFmt_Insert( void* pFmt )
{ aDest.Insert( pFmt, aDest.Count() ); }
void SrcFmt_Insert( void* pFmt )
{ aSrc.Insert( pFmt, aSrc.Count() ); }
SwFrmFmt* DestFmt_Get( sal_uInt16 nPos ) const
{ return (SwFrmFmt*)aDest[ nPos ]; }
void ChgBox( SwTableBox* pBox )
{
rOldTbl.GetTabSortBoxes().Remove( pBox );
pNewTblNd->GetTable().GetTabSortBoxes().Insert( pBox );
}
};
sal_Bool lcl_SplitTable_CpyBox( const SwTableBox*& rpBox, void* pPara );
sal_Bool lcl_SplitTable_CpyLine( const SwTableLine*& rpLine, void* pPara )
{
SwTableLine* pLn = (SwTableLine*)rpLine;
_SplitTable_Para& rPara = *(_SplitTable_Para*)pPara;
SwFrmFmt *pSrcFmt = pLn->GetFrmFmt();
sal_uInt16 nPos = rPara.SrcFmt_GetPos( pSrcFmt );
if( USHRT_MAX == nPos )
{
rPara.DestFmt_Insert( pLn->ClaimFrmFmt() );
rPara.SrcFmt_Insert( pSrcFmt );
}
else
pLn->ChgFrmFmt( (SwTableLineFmt*)rPara.DestFmt_Get( nPos ) );
pLn->GetTabBoxes().ForEach( &lcl_SplitTable_CpyBox, pPara );
return sal_True;
}
sal_Bool lcl_SplitTable_CpyBox( const SwTableBox*& rpBox, void* pPara )
{
SwTableBox* pBox = (SwTableBox*)rpBox;
_SplitTable_Para& rPara = *(_SplitTable_Para*)pPara;
SwFrmFmt *pSrcFmt = pBox->GetFrmFmt();
sal_uInt16 nPos = rPara.SrcFmt_GetPos( pSrcFmt );
if( USHRT_MAX == nPos )
{
rPara.DestFmt_Insert( pBox->ClaimFrmFmt() );
rPara.SrcFmt_Insert( pSrcFmt );
}
else
pBox->ChgFrmFmt( (SwTableBoxFmt*)rPara.DestFmt_Get( nPos ) );
if( pBox->GetSttNd() )
rPara.ChgBox( pBox );
else
pBox->GetTabLines().ForEach( &lcl_SplitTable_CpyLine, pPara );
return sal_True;
}
SwTableNode* SwNodes::SplitTable( const SwNodeIndex& rPos, sal_Bool bAfter,
sal_Bool bCalcNewSize )
{
SwNode* pNd = &rPos.GetNode();
SwTableNode* pTNd = pNd->FindTableNode();
if( !pTNd || pNd->IsTableNode() )
return 0;
sal_uLong nSttIdx = pNd->FindTableBoxStartNode()->GetIndex();
// Suche die Grund-Line dieser Box:
SwTable& rTbl = pTNd->GetTable();
SwTableBox* pBox = rTbl.GetTblBox( nSttIdx );
if( !pBox )
return 0;
SwTableLine* pLine = pBox->GetUpper();
while( pLine->GetUpper() )
pLine = pLine->GetUpper()->GetUpper();
// in pLine steht jetzt die GrundLine.
sal_uInt16 nLinePos = rTbl.GetTabLines().C40_GETPOS( SwTableLine, pLine );
if( USHRT_MAX == nLinePos ||
( bAfter ? ++nLinePos >= rTbl.GetTabLines().Count() : !nLinePos ))
return 0; // nicht gefunden oder letze Line !!
// Suche jetzt die 1. Box der nachfolgenden Line
SwTableLine* pNextLine = rTbl.GetTabLines()[ nLinePos ];
pBox = pNextLine->GetTabBoxes()[0];
while( !pBox->GetSttNd() )
pBox = pBox->GetTabLines()[0]->GetTabBoxes()[0];
// dann fuege mal einen End- und TabelleNode ins Nodes-Array ein.
SwTableNode * pNewTblNd;
{
SwEndNode* pOldTblEndNd = (SwEndNode*)pTNd->EndOfSectionNode()->GetEndNode();
ASSERT( pOldTblEndNd, "wo ist der EndNode?" )
SwNodeIndex aIdx( *pBox->GetSttNd() );
new SwEndNode( aIdx, *pTNd );
pNewTblNd = new SwTableNode( aIdx );
pNewTblNd->GetTable().SetTableModel( rTbl.IsNewModel() );
pOldTblEndNd->pStartOfSection = pNewTblNd;
pNewTblNd->pEndOfSection = pOldTblEndNd;
SwNode* pBoxNd = aIdx.GetNode().GetStartNode();
do {
ASSERT( pBoxNd->IsStartNode(), "das muss ein StartNode sein!" );
pBoxNd->pStartOfSection = pNewTblNd;
pBoxNd = (*this)[ pBoxNd->EndOfSectionIndex() + 1 ];
} while( pBoxNd != pOldTblEndNd );
}
{
// die Lines ruebermoven...
SwTable& rNewTbl = pNewTblNd->GetTable();
rNewTbl.GetTabLines().Insert( &rTbl.GetTabLines(), 0, nLinePos );
//
// von hinten (unten-rechts) nach vorn (oben-links) alle Boxen
// beim chart data provider austragen (das modified event wird dann
// in der aufrufenden Funktion getriggert.
// TL_CHART2:
SwChartDataProvider *pPCD = rTbl.GetFrmFmt()->getIDocumentChartDataProviderAccess()->GetChartDataProvider();
if( pPCD )
{
for (sal_uInt16 k = nLinePos; k < rTbl.GetTabLines().Count(); ++k)
{
sal_uInt16 nLineIdx = (rTbl.GetTabLines().Count() - 1) - k + nLinePos;
sal_uInt16 nBoxCnt = rTbl.GetTabLines()[ nLineIdx ]->GetTabBoxes().Count();
for (sal_uInt16 j = 0; j < nBoxCnt; ++j)
{
sal_uInt16 nIdx = nBoxCnt - 1 - j;
pPCD->DeleteBox( &rTbl, *rTbl.GetTabLines()[ nLineIdx ]->GetTabBoxes()[nIdx] );
}
}
}
//
// ...und loeschen
sal_uInt16 nDeleted = rTbl.GetTabLines().Count() - nLinePos;
rTbl.GetTabLines().Remove( nLinePos, nDeleted );
// und die betr. Boxen verschieben. Dabei die Formate eindeutig
// machen und die StartNodes korrigieren
_SplitTable_Para aPara( pNewTblNd, rTbl );
rNewTbl.GetTabLines().ForEach( &lcl_SplitTable_CpyLine, &aPara );
rTbl.CleanUpBottomRowSpan( nDeleted );
}
{
// Das Tabellen-FrmFormat kopieren
SwFrmFmt* pOldTblFmt = rTbl.GetFrmFmt();
SwFrmFmt* pNewTblFmt = pOldTblFmt->GetDoc()->MakeTblFrmFmt(
pOldTblFmt->GetDoc()->GetUniqueTblName(),
pOldTblFmt->GetDoc()->GetDfltFrmFmt() );
*pNewTblFmt = *pOldTblFmt;
pNewTblNd->GetTable().RegisterToFormat( *pNewTblFmt );
// neue Size errechnen ? (lcl_ChgTblSize nur das 2. aufrufen, wenn es
// beim 1. schon geklappt hat; also absolute Groesse hat)
if( bCalcNewSize && lcl_ChgTblSize( rTbl ) )
lcl_ChgTblSize( pNewTblNd->GetTable() );
}
// TL_CHART2: need to inform chart of probably changed cell names
rTbl.UpdateCharts();
return pNewTblNd; // das wars
}
// und die Umkehrung davon. rPos muss in der Tabelle stehen, die bestehen
// bleibt. Das Flag besagt ob die aktuelle mit der davor oder dahinter
// stehenden vereint wird.
sal_Bool SwDoc::MergeTable( const SwPosition& rPos, sal_Bool bWithPrev, sal_uInt16 nMode )
{
SwTableNode* pTblNd = rPos.nNode.GetNode().FindTableNode(), *pDelTblNd;
if( !pTblNd )
return sal_False;
SwNodes& rNds = GetNodes();
if( bWithPrev )
pDelTblNd = rNds[ pTblNd->GetIndex() - 1 ]->FindTableNode();
else
pDelTblNd = rNds[ pTblNd->EndOfSectionIndex() + 1 ]->GetTableNode();
if( !pDelTblNd )
return sal_False;
if( pTblNd->GetTable().ISA( SwDDETable ) ||
pDelTblNd->GetTable().ISA( SwDDETable ))
return sal_False;
// MIB 9.7.97: HTML-Layout loeschen
pTblNd->GetTable().SetHTMLTableLayout( 0 );
pDelTblNd->GetTable().SetHTMLTableLayout( 0 );
// beide Tabellen vorhanden, also kanns losgehen
SwUndoMergeTbl* pUndo = 0;
SwHistory* pHistory = 0;
if (GetIDocumentUndoRedo().DoesUndo())
{
pUndo = new SwUndoMergeTbl( *pTblNd, *pDelTblNd, bWithPrev, nMode );
GetIDocumentUndoRedo().AppendUndo(pUndo);
pHistory = new SwHistory;
}
// alle "Tabellenformeln" anpassen
SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() );
aMsgHnt.DATA.pDelTbl = &pDelTblNd->GetTable();
aMsgHnt.eFlags = TBL_MERGETBL;
aMsgHnt.pHistory = pHistory;
UpdateTblFlds( &aMsgHnt );
// das eigentliche Mergen
SwNodeIndex aIdx( bWithPrev ? *pTblNd : *pDelTblNd );
sal_Bool bRet = rNds.MergeTable( aIdx, !bWithPrev, nMode, pHistory );
if( pHistory )
{
if( pHistory->Count() )
pUndo->SaveFormula( *pHistory );
delete pHistory;
}
if( bRet )
{
SetModified();
SetFieldsDirty( true, NULL, 0 );
}
return bRet;
}
sal_Bool SwNodes::MergeTable( const SwNodeIndex& rPos, sal_Bool bWithPrev,
sal_uInt16 nMode, SwHistory* )
{
SwTableNode* pDelTblNd = rPos.GetNode().GetTableNode();
ASSERT( pDelTblNd, "wo ist der TableNode geblieben?" );
SwTableNode* pTblNd = (*this)[ rPos.GetIndex() - 1]->FindTableNode();
ASSERT( pTblNd, "wo ist der TableNode geblieben?" );
if( !pDelTblNd || !pTblNd )
return sal_False;
pDelTblNd->DelFrms();
SwTable& rDelTbl = pDelTblNd->GetTable();
SwTable& rTbl = pTblNd->GetTable();
//Lines fuer das Layout-Update herausuchen.
_FndBox aFndBox( 0, 0 );
aFndBox.SetTableLines( rTbl );
aFndBox.DelFrms( rTbl );
// TL_CHART2: since chart currently does not want to get informed about
// additional rows/cols there is no need for a modified event in the
// remaining first table. Also, if it is required it should be done
// after the merging and not here...
// pDoc->UpdateCharts( rTbl.GetFrmFmt()->GetName() );
// TL_CHART2:
// tell the charts about the table to be deleted and have them use their own data
GetDoc()->CreateChartInternalDataProviders( &rDelTbl );
// die Breite der TabellenFormate abgleichen:
{
const SwFmtFrmSize& rTblSz = rTbl.GetFrmFmt()->GetFrmSize();
const SwFmtFrmSize& rDelTblSz = rDelTbl.GetFrmFmt()->GetFrmSize();
if( rTblSz != rDelTblSz )
{
// dann sollten die mal schleunigst korrigiert werden
if( bWithPrev )
rDelTbl.GetFrmFmt()->SetFmtAttr( rTblSz );
else
rTbl.GetFrmFmt()->SetFmtAttr( rDelTblSz );
}
}
if( !bWithPrev )
{
// dann mussen alle Attruibute der hinteren Tabelle auf die
// vordere uebertragen werden, weil die hintere ueber das loeschen
// des Node geloescht wird.
rTbl.SetRowsToRepeat( rDelTbl.GetRowsToRepeat() );
rTbl.SetTblChgMode( rDelTbl.GetTblChgMode() );
rTbl.GetFrmFmt()->LockModify();
*rTbl.GetFrmFmt() = *rDelTbl.GetFrmFmt();
// auch den Namen umsetzen!
rTbl.GetFrmFmt()->SetName( rDelTbl.GetFrmFmt()->GetName() );
rTbl.GetFrmFmt()->UnlockModify();
}
// die Lines und Boxen ruebermoven
sal_uInt16 nOldSize = rTbl.GetTabLines().Count();
rTbl.GetTabLines().Insert( &rDelTbl.GetTabLines(), nOldSize );
rDelTbl.GetTabLines().Remove( 0, rDelTbl.GetTabLines().Count() );
rTbl.GetTabSortBoxes().Insert( &rDelTbl.GetTabSortBoxes() );
rDelTbl.GetTabSortBoxes().Remove( (sal_uInt16)0, rDelTbl.GetTabSortBoxes().Count() );
// die vordere Tabelle bleibt immer stehen, die hintere wird geloescht
SwEndNode* pTblEndNd = pDelTblNd->EndOfSectionNode();
pTblNd->pEndOfSection = pTblEndNd;
SwNodeIndex aIdx( *pDelTblNd, 1 );
SwNode* pBoxNd = aIdx.GetNode().GetStartNode();
do {
ASSERT( pBoxNd->IsStartNode(), "das muss ein StartNode sein!" );
pBoxNd->pStartOfSection = pTblNd;
pBoxNd = (*this)[ pBoxNd->EndOfSectionIndex() + 1 ];
} while( pBoxNd != pTblEndNd );
pBoxNd->pStartOfSection = pTblNd;
aIdx -= 2;
DelNodes( aIdx, 2 );
// jetzt an der 1. eingefuegten Line die bedingten Vorlagen umschubsen
const SwTableLine* pFirstLn = rTbl.GetTabLines()[ nOldSize ];
if( 1 == nMode ) //
{
// Header-Vorlagen in der Zeile setzen
// und ggfs. in der History speichern fuers Undo!!!
}
lcl_LineSetHeadCondColl( pFirstLn, 0 );
// und die Borders "aufrauemen"
if( nOldSize )
{
_SwGCLineBorder aPara( rTbl );
aPara.nLinePos = --nOldSize;
pFirstLn = rTbl.GetTabLines()[ nOldSize ];
lcl_GC_Line_Border( pFirstLn, &aPara );
}
//Layout updaten
aFndBox.MakeFrms( rTbl );
return sal_True;
}
// -------------------------------------------------------------------
// -- benutze die ForEach Methode vom PtrArray
struct _SetAFmtTabPara
{
SwTableAutoFmt& rTblFmt;
SwUndoTblAutoFmt* pUndo;
sal_uInt16 nEndBox, nCurBox;
sal_uInt8 nAFmtLine, nAFmtBox;
_SetAFmtTabPara( const SwTableAutoFmt& rNew )
: rTblFmt( (SwTableAutoFmt&)rNew ), pUndo( 0 ),
nEndBox( 0 ), nCurBox( 0 ), nAFmtLine( 0 ), nAFmtBox( 0 )
{}
};
// forward deklarieren damit sich die Lines und Boxen rekursiv aufrufen
// koennen.
sal_Bool lcl_SetAFmtBox( const _FndBox*&, void *pPara );
sal_Bool lcl_SetAFmtLine( const _FndLine*&, void *pPara );
sal_Bool lcl_SetAFmtLine( const _FndLine*& rpLine, void *pPara )
{
((_FndLine*&)rpLine)->GetBoxes().ForEach( &lcl_SetAFmtBox, pPara );
return sal_True;
}
sal_Bool lcl_SetAFmtBox( const _FndBox*& rpBox, void *pPara )
{
_SetAFmtTabPara* pSetPara = (_SetAFmtTabPara*)pPara;
if( !rpBox->GetUpper()->GetUpper() ) // Box auf 1. Ebene ?
{
if( !pSetPara->nCurBox )
pSetPara->nAFmtBox = 0;
else if( pSetPara->nCurBox == pSetPara->nEndBox )
pSetPara->nAFmtBox = 3;
else
pSetPara->nAFmtBox = (sal_uInt8)(1 + ((pSetPara->nCurBox-1) & 1));
}
if( rpBox->GetBox()->GetSttNd() )
{
SwTableBox* pSetBox = (SwTableBox*)rpBox->GetBox();
SwDoc* pDoc = pSetBox->GetFrmFmt()->GetDoc();
// --> OD 2008-02-25 #refactorlists#
// SfxItemSet aCharSet( pDoc->GetAttrPool(), RES_CHRATR_BEGIN, RES_PARATR_END-1 );
SfxItemSet aCharSet( pDoc->GetAttrPool(), RES_CHRATR_BEGIN, RES_PARATR_LIST_END-1 );
// <--
SfxItemSet aBoxSet( pDoc->GetAttrPool(), aTableBoxSetRange );
sal_uInt8 nPos = pSetPara->nAFmtLine * 4 + pSetPara->nAFmtBox;
pSetPara->rTblFmt.UpdateToSet( nPos, aCharSet,
SwTableAutoFmt::UPDATE_CHAR, 0 );
pSetPara->rTblFmt.UpdateToSet( nPos, aBoxSet,
SwTableAutoFmt::UPDATE_BOX,
pDoc->GetNumberFormatter( sal_True ) );
if( aCharSet.Count() )
{
sal_uLong nSttNd = pSetBox->GetSttIdx()+1;
sal_uLong nEndNd = pSetBox->GetSttNd()->EndOfSectionIndex();
for( ; nSttNd < nEndNd; ++nSttNd )
{
SwCntntNode* pNd = pDoc->GetNodes()[ nSttNd ]->GetCntntNode();
if( pNd )
pNd->SetAttr( aCharSet );
}
}
if( aBoxSet.Count() )
{
if( pSetPara->pUndo &&
SFX_ITEM_SET == aBoxSet.GetItemState( RES_BOXATR_FORMAT ))
pSetPara->pUndo->SaveBoxCntnt( *pSetBox );
pSetBox->ClaimFrmFmt()->SetFmtAttr( aBoxSet );
}
}
else
((_FndBox*&)rpBox)->GetLines().ForEach( &lcl_SetAFmtLine, pPara );
if( !rpBox->GetUpper()->GetUpper() ) // eine BaseLine
++pSetPara->nCurBox;
return sal_True;
}
// AutoFormat fuer die Tabelle/TabellenSelection
sal_Bool SwDoc::SetTableAutoFmt( const SwSelBoxes& rBoxes, const SwTableAutoFmt& rNew )
{
ASSERT( rBoxes.Count(), "keine gueltige Box-Liste" );
SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
if( !pTblNd )
return sal_False;
// suche alle Boxen / Lines
_FndBox aFndBox( 0, 0 );
{
_FndPara aPara( rBoxes, &aFndBox );
pTblNd->GetTable().GetTabLines().ForEach( &_FndLineCopyCol, &aPara );
}
if( !aFndBox.GetLines().Count() )
return sal_False;
pTblNd->GetTable().SetHTMLTableLayout( 0 );
_FndBox* pFndBox = &aFndBox;
while( 1 == pFndBox->GetLines().Count() &&
1 == pFndBox->GetLines()[0]->GetBoxes().Count() )
pFndBox = pFndBox->GetLines()[0]->GetBoxes()[0];
if( !pFndBox->GetLines().Count() ) // eine zu weit? (nur 1 sel.Box)
pFndBox = pFndBox->GetUpper()->GetUpper();
// Undo abschalten, Attribute werden sich vorher gemerkt
SwUndoTblAutoFmt* pUndo = 0;
bool const bUndo(GetIDocumentUndoRedo().DoesUndo());
if (bUndo)
{
pUndo = new SwUndoTblAutoFmt( *pTblNd, rNew );
GetIDocumentUndoRedo().AppendUndo(pUndo);
GetIDocumentUndoRedo().DoUndo(false);
}
_SetAFmtTabPara aPara( rNew );
_FndLines& rFLns = pFndBox->GetLines();
_FndLine* pLine;
for( sal_uInt16 n = 0; n < rFLns.Count(); ++n )
{
pLine = rFLns[n];
// Upper auf 0 setzen (Base-Line simulieren!)
_FndBox* pSaveBox = pLine->GetUpper();
pLine->SetUpper( 0 );
if( !n )
aPara.nAFmtLine = 0;
else if( n+1 == rFLns.Count() )
aPara.nAFmtLine = 3;
else
aPara.nAFmtLine = (sal_uInt8)(1 + ((n-1) & 1 ));
aPara.nAFmtBox = 0;
aPara.nCurBox = 0;
aPara.nEndBox = pLine->GetBoxes().Count()-1;
aPara.pUndo = pUndo;
pLine->GetBoxes().ForEach( &lcl_SetAFmtBox, &aPara );
pLine->SetUpper( pSaveBox );
}
if( pUndo )
{
GetIDocumentUndoRedo().DoUndo(bUndo);
}
SetModified();
SetFieldsDirty( true, NULL, 0 );
return sal_True;
}
// Erfrage wie attributiert ist
sal_Bool SwDoc::GetTableAutoFmt( const SwSelBoxes& rBoxes, SwTableAutoFmt& rGet )
{
ASSERT( rBoxes.Count(), "keine gueltige Box-Liste" );
SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
if( !pTblNd )
return sal_False;
// suche alle Boxen / Lines
_FndBox aFndBox( 0, 0 );
{
_FndPara aPara( rBoxes, &aFndBox );
pTblNd->GetTable().GetTabLines().ForEach( &_FndLineCopyCol, &aPara );
}
if( !aFndBox.GetLines().Count() )
return sal_False;
_FndBox* pFndBox = &aFndBox;
while( 1 == pFndBox->GetLines().Count() &&
1 == pFndBox->GetLines()[0]->GetBoxes().Count() )
pFndBox = pFndBox->GetLines()[0]->GetBoxes()[0];
if( !pFndBox->GetLines().Count() ) // eine zu weit? (nur 1 sel.Box)
pFndBox = pFndBox->GetUpper()->GetUpper();
_FndLines& rFLns = pFndBox->GetLines();
sal_uInt16 aLnArr[4];
aLnArr[0] = 0;
aLnArr[1] = 1 < rFLns.Count() ? 1 : 0;
aLnArr[2] = 2 < rFLns.Count() ? 2 : aLnArr[1];
aLnArr[3] = rFLns.Count() - 1;
for( sal_uInt8 nLine = 0; nLine < 4; ++nLine )
{
_FndLine& rLine = *rFLns[ aLnArr[ nLine ] ];
sal_uInt16 aBoxArr[4];
aBoxArr[0] = 0;
aBoxArr[1] = 1 < rLine.GetBoxes().Count() ? 1 : 0;
aBoxArr[2] = 2 < rLine.GetBoxes().Count() ? 2 : aBoxArr[1];
aBoxArr[3] = rLine.GetBoxes().Count() - 1;
for( sal_uInt8 nBox = 0; nBox < 4; ++nBox )
{
SwTableBox* pFBox = rLine.GetBoxes()[ aBoxArr[ nBox ] ]->GetBox();
// immer auf die 1. runterfallen
while( !pFBox->GetSttNd() )
pFBox = pFBox->GetTabLines()[0]->GetTabBoxes()[0];
sal_uInt8 nPos = nLine * 4 + nBox;
SwNodeIndex aIdx( *pFBox->GetSttNd(), 1 );
SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode();
if( !pCNd )
pCNd = GetNodes().GoNext( &aIdx );
if( pCNd )
rGet.UpdateFromSet( nPos, pCNd->GetSwAttrSet(),
SwTableAutoFmt::UPDATE_CHAR, 0 );
rGet.UpdateFromSet( nPos, pFBox->GetFrmFmt()->GetAttrSet(),
SwTableAutoFmt::UPDATE_BOX,
GetNumberFormatter( sal_True ) );
}
}
return sal_True;
}
String SwDoc::GetUniqueTblName() const
{
ResId aId( STR_TABLE_DEFNAME, *pSwResMgr );
String aName( aId );
xub_StrLen nNmLen = aName.Len();
sal_uInt16 nNum, nTmp, nFlagSize = ( pTblFrmFmtTbl->Count() / 8 ) +2;
sal_uInt16 n;
sal_uInt8* pSetFlags = new sal_uInt8[ nFlagSize ];
memset( pSetFlags, 0, nFlagSize );
for( n = 0; n < pTblFrmFmtTbl->Count(); ++n )
{
const SwFrmFmt* pFmt = (*pTblFrmFmtTbl)[ n ];
if( !pFmt->IsDefault() && IsUsed( *pFmt ) &&
pFmt->GetName().Match( aName ) == nNmLen )
{
// Nummer bestimmen und das Flag setzen
nNum = static_cast<sal_uInt16>(pFmt->GetName().Copy( nNmLen ).ToInt32());
if( nNum-- && nNum < pTblFrmFmtTbl->Count() )
pSetFlags[ nNum / 8 ] |= (0x01 << ( nNum & 0x07 ));
}
}
// alle Nummern entsprechend geflag, also bestimme die richtige Nummer
nNum = pTblFrmFmtTbl->Count();
for( n = 0; n < nFlagSize; ++n )
if( 0xff != ( nTmp = pSetFlags[ n ] ))
{
// also die Nummer bestimmen
nNum = n * 8;
while( nTmp & 1 )
++nNum, nTmp >>= 1;
break;
}
delete [] pSetFlags;
return aName += String::CreateFromInt32( ++nNum );
}
SwTableFmt* SwDoc::FindTblFmtByName( const String& rName, sal_Bool bAll ) const
{
const SwFmt* pRet = 0;
if( bAll )
pRet = FindFmtByName( (SvPtrarr&)*pTblFrmFmtTbl, rName );
else
{
// dann nur die, die im Doc gesetzt sind
for( sal_uInt16 n = 0; n < pTblFrmFmtTbl->Count(); ++n )
{
const SwFrmFmt* pFmt = (*pTblFrmFmtTbl)[ n ];
if( !pFmt->IsDefault() && IsUsed( *pFmt ) &&
pFmt->GetName() == rName )
{
pRet = pFmt;
break;
}
}
}
return (SwTableFmt*)pRet;
}
sal_Bool SwDoc::SetColRowWidthHeight( SwTableBox& rAktBox, sal_uInt16 eType,
SwTwips nAbsDiff, SwTwips nRelDiff )
{
SwTableNode* pTblNd = (SwTableNode*)rAktBox.GetSttNd()->FindTableNode();
SwUndo* pUndo = 0;
if( nsTblChgWidthHeightType::WH_FLAG_INSDEL & eType && pTblNd->GetTable().ISA( SwDDETable ))
return sal_False;
SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() );
aMsgHnt.eFlags = TBL_BOXPTR;
UpdateTblFlds( &aMsgHnt );
bool const bUndo(GetIDocumentUndoRedo().DoesUndo());
sal_Bool bRet = sal_False;
switch( eType & 0xff )
{
case nsTblChgWidthHeightType::WH_COL_LEFT:
case nsTblChgWidthHeightType::WH_COL_RIGHT:
case nsTblChgWidthHeightType::WH_CELL_LEFT:
case nsTblChgWidthHeightType::WH_CELL_RIGHT:
{
bRet = pTblNd->GetTable().SetColWidth( rAktBox,
eType, nAbsDiff, nRelDiff,
(bUndo) ? &pUndo : 0 );
}
break;
case nsTblChgWidthHeightType::WH_ROW_TOP:
case nsTblChgWidthHeightType::WH_ROW_BOTTOM:
case nsTblChgWidthHeightType::WH_CELL_TOP:
case nsTblChgWidthHeightType::WH_CELL_BOTTOM:
bRet = pTblNd->GetTable().SetRowHeight( rAktBox,
eType, nAbsDiff, nRelDiff,
(bUndo) ? &pUndo : 0 );
break;
}
GetIDocumentUndoRedo().DoUndo(bUndo); // SetColWidth can turn it off
if( pUndo )
{
GetIDocumentUndoRedo().AppendUndo( pUndo );
}
if( bRet )
{
SetModified();
if( nsTblChgWidthHeightType::WH_FLAG_INSDEL & eType )
SetFieldsDirty( true, NULL, 0 );
}
return bRet;
}
void SwDoc::ChkBoxNumFmt( SwTableBox& rBox, sal_Bool bCallUpdate )
{
//JP 09.07.97: Optimierung: wenn die Box schon sagt, das es Text
// sein soll, dann bleibt das auch Text!
const SfxPoolItem* pNumFmtItem = 0;
if( SFX_ITEM_SET == rBox.GetFrmFmt()->GetItemState( RES_BOXATR_FORMAT,
sal_False, &pNumFmtItem ) && GetNumberFormatter()->IsTextFormat(
((SwTblBoxNumFormat*)pNumFmtItem)->GetValue() ))
return ;
SwUndoTblNumFmt* pUndo = 0;
sal_Bool bIsEmptyTxtNd, bChgd = sal_True;
sal_uInt32 nFmtIdx;
double fNumber;
if( rBox.HasNumCntnt( fNumber, nFmtIdx, bIsEmptyTxtNd ) )
{
if( !rBox.IsNumberChanged() )
bChgd = sal_False;
else
{
if (GetIDocumentUndoRedo().DoesUndo())
{
GetIDocumentUndoRedo().StartUndo( UNDO_TABLE_AUTOFMT, NULL );
pUndo = new SwUndoTblNumFmt( rBox );
pUndo->SetNumFmt( nFmtIdx, fNumber );
}
SwTableBoxFmt* pBoxFmt = (SwTableBoxFmt*)rBox.GetFrmFmt();
SfxItemSet aBoxSet( GetAttrPool(), RES_BOXATR_FORMAT, RES_BOXATR_VALUE );
sal_Bool bSetNumFmt = IsInsTblFormatNum(), bLockModify = sal_True;
if( bSetNumFmt )
{
if( !IsInsTblChangeNumFormat() )
{
if( !pNumFmtItem )
bSetNumFmt = sal_False;
else
{
sal_uLong nOldNumFmt = ((SwTblBoxNumFormat*)pNumFmtItem)->
GetValue();
SvNumberFormatter* pNumFmtr = GetNumberFormatter();
short nFmtType = pNumFmtr->GetType( nFmtIdx );
if( nFmtType == pNumFmtr->GetType( nOldNumFmt ) ||
NUMBERFORMAT_NUMBER == nFmtType )
// eingstelltes und vorgegebenes NumFormat
// stimmen ueberein -> altes Format beibehalten
nFmtIdx = nOldNumFmt;
else
// eingstelltes und vorgegebenes NumFormat
// stimmen nicht ueberein -> als Text einfuegen
bLockModify = bSetNumFmt = sal_False;
}
}
if( bSetNumFmt )
{
pBoxFmt = (SwTableBoxFmt*)rBox.ClaimFrmFmt();
aBoxSet.Put( SwTblBoxValue( fNumber ));
aBoxSet.Put( SwTblBoxNumFormat( nFmtIdx ));
}
}
// JP 28.04.98: Nur Formel zuruecksetzen reicht nicht.
// Sorge dafuer, das der Text auch entsprechend
// formatiert wird!
if( !bSetNumFmt && !bIsEmptyTxtNd && pNumFmtItem )
{
// JP 15.01.99: Nur Attribute zuruecksetzen reicht nicht.
// Sorge dafuer, das der Text auch entsprechend
// formatiert wird!
pBoxFmt->SetFmtAttr( *GetDfltAttr( RES_BOXATR_FORMAT ));
}
if( bLockModify ) pBoxFmt->LockModify();
pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMAT, RES_BOXATR_VALUE );
if( bLockModify ) pBoxFmt->UnlockModify();
if( bSetNumFmt )
pBoxFmt->SetFmtAttr( aBoxSet );
}
}
else
{
// es ist keine Zahl
const SfxPoolItem* pValueItem = 0, *pFmtItem = 0;
SwTableBoxFmt* pBoxFmt = (SwTableBoxFmt*)rBox.GetFrmFmt();
if( SFX_ITEM_SET == pBoxFmt->GetItemState( RES_BOXATR_FORMAT,
sal_False, &pFmtItem ) ||
SFX_ITEM_SET == pBoxFmt->GetItemState( RES_BOXATR_VALUE,
sal_False, &pValueItem ))
{
if (GetIDocumentUndoRedo().DoesUndo())
{
GetIDocumentUndoRedo().StartUndo( UNDO_TABLE_AUTOFMT, NULL );
pUndo = new SwUndoTblNumFmt( rBox );
}
pBoxFmt = (SwTableBoxFmt*)rBox.ClaimFrmFmt();
// alle Zahlenformate entfernen
sal_uInt16 nWhich1 = RES_BOXATR_FORMULA;
if( !bIsEmptyTxtNd )
//JP 15.01.99: dieser Teil wurde doch schon oben abgeprueft!
/* && pFmtItem && !GetNumberFormatter()->
IsTextFormat( ((SwTblBoxNumFormat*)pFmtItem)->GetValue() ) )*/
{
nWhich1 = RES_BOXATR_FORMAT;
// JP 15.01.99: Nur Attribute zuruecksetzen reicht nicht.
// Sorge dafuer, das der Text auch entsprechend
// formatiert wird!
pBoxFmt->SetFmtAttr( *GetDfltAttr( nWhich1 ));
}
pBoxFmt->ResetFmtAttr( nWhich1, RES_BOXATR_VALUE );
}
else
bChgd = sal_False;
}
if( bChgd )
{
if( pUndo )
{
pUndo->SetBox( rBox );
GetIDocumentUndoRedo().AppendUndo(pUndo);
GetIDocumentUndoRedo().EndUndo( UNDO_END, NULL );
}
const SwTableNode* pTblNd = rBox.GetSttNd()->FindTableNode();
if( bCallUpdate )
{
SwTableFmlUpdate aTblUpdate( &pTblNd->GetTable() );
UpdateTblFlds( &aTblUpdate );
// TL_CHART2: update charts (when cursor leaves cell and
// automatic update is enabled)
if (AUTOUPD_FIELD_AND_CHARTS == getFieldUpdateFlags(true))
pTblNd->GetTable().UpdateCharts();
}
SetModified();
}
}
void SwDoc::SetTblBoxFormulaAttrs( SwTableBox& rBox, const SfxItemSet& rSet )
{
if (GetIDocumentUndoRedo().DoesUndo())
{
GetIDocumentUndoRedo().AppendUndo( new SwUndoTblNumFmt(rBox, &rSet) );
}
SwFrmFmt* pBoxFmt = rBox.ClaimFrmFmt();
if( SFX_ITEM_SET == rSet.GetItemState( RES_BOXATR_FORMULA ))
{
pBoxFmt->LockModify();
pBoxFmt->ResetFmtAttr( RES_BOXATR_VALUE );
pBoxFmt->UnlockModify();
}
else if( SFX_ITEM_SET == rSet.GetItemState( RES_BOXATR_VALUE ))
{
pBoxFmt->LockModify();
pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMULA );
pBoxFmt->UnlockModify();
}
pBoxFmt->SetFmtAttr( rSet );
SetModified();
}
void SwDoc::ClearBoxNumAttrs( const SwNodeIndex& rNode )
{
SwStartNode* pSttNd;
if( 0 != ( pSttNd = rNode.GetNode().
FindSttNodeByType( SwTableBoxStartNode )) &&
2 == pSttNd->EndOfSectionIndex() - pSttNd->GetIndex() )
{
SwTableBox* pBox = pSttNd->FindTableNode()->GetTable().
GetTblBox( pSttNd->GetIndex() );
const SfxPoolItem* pFmtItem = 0;
const SfxItemSet& rSet = pBox->GetFrmFmt()->GetAttrSet();
if( SFX_ITEM_SET == rSet.GetItemState( RES_BOXATR_FORMAT, sal_False, &pFmtItem ) ||
SFX_ITEM_SET == rSet.GetItemState( RES_BOXATR_FORMULA, sal_False ) ||
SFX_ITEM_SET == rSet.GetItemState( RES_BOXATR_VALUE, sal_False ))
{
if (GetIDocumentUndoRedo().DoesUndo())
{
GetIDocumentUndoRedo().AppendUndo(new SwUndoTblNumFmt(*pBox));
}
SwFrmFmt* pBoxFmt = pBox->ClaimFrmFmt();
//JP 01.09.97: TextFormate bleiben erhalten!
sal_uInt16 nWhich1 = RES_BOXATR_FORMAT;
if( pFmtItem && GetNumberFormatter()->IsTextFormat(
((SwTblBoxNumFormat*)pFmtItem)->GetValue() ))
nWhich1 = RES_BOXATR_FORMULA;
else
// JP 15.01.99: Nur Attribute zuruecksetzen reicht nicht.
// Sorge dafuer, das der Text auch entsprechend
// formatiert wird!
pBoxFmt->SetFmtAttr( *GetDfltAttr( RES_BOXATR_FORMAT ));
pBoxFmt->ResetFmtAttr( nWhich1, RES_BOXATR_VALUE );
SetModified();
}
}
}
// kopiert eine Tabelle aus dem selben oder einem anderen Doc in sich
// selbst. Dabei wird eine neue Tabelle angelegt oder eine bestehende
// mit dem Inhalt gefuellt; wobei entweder der Inhalt ab einer Box oder
// in eine bestehende TblSelektion gefuellt wird.
// Gerufen wird es von: edglss.cxx/fecopy.cxx
sal_Bool SwDoc::InsCopyOfTbl( SwPosition& rInsPos, const SwSelBoxes& rBoxes,
const SwTable* pCpyTbl, sal_Bool bCpyName, sal_Bool bCorrPos )
{
sal_Bool bRet;
const SwTableNode* pSrcTblNd = pCpyTbl
? pCpyTbl->GetTableNode()
: rBoxes[ 0 ]->GetSttNd()->FindTableNode();
SwTableNode * pInsTblNd = rInsPos.nNode.GetNode().FindTableNode();
bool const bUndo( GetIDocumentUndoRedo().DoesUndo() );
if( !pCpyTbl && !pInsTblNd )
{
SwUndoCpyTbl* pUndo = 0;
if (bUndo)
{
GetIDocumentUndoRedo().ClearRedo();
pUndo = new SwUndoCpyTbl;
}
{
::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
bRet = pSrcTblNd->GetTable().MakeCopy( this, rInsPos, rBoxes,
sal_True, bCpyName );
}
if( pUndo )
{
if( !bRet )
{
delete pUndo;
pUndo = 0;
}
else
{
pInsTblNd = GetNodes()[ rInsPos.nNode.GetIndex() - 1 ]->FindTableNode();
pUndo->SetTableSttIdx( pInsTblNd->GetIndex() );
GetIDocumentUndoRedo().AppendUndo( pUndo );
}
}
}
else
{
RedlineMode_t eOld = GetRedlineMode();
if( IsRedlineOn() )
SetRedlineMode( (RedlineMode_t)(nsRedlineMode_t::REDLINE_ON |
nsRedlineMode_t::REDLINE_SHOW_INSERT |
nsRedlineMode_t::REDLINE_SHOW_DELETE));
SwUndoTblCpyTbl* pUndo = 0;
if (bUndo)
{
GetIDocumentUndoRedo().ClearRedo();
pUndo = new SwUndoTblCpyTbl;
GetIDocumentUndoRedo().DoUndo(false);
}
SwDoc* pCpyDoc = (SwDoc*)pSrcTblNd->GetDoc();
sal_Bool bDelCpyDoc = pCpyDoc == this;
if( bDelCpyDoc )
{
// kopiere die Tabelle erstmal in ein temp. Doc
pCpyDoc = new SwDoc;
pCpyDoc->acquire();
SwPosition aPos( SwNodeIndex( pCpyDoc->GetNodes().GetEndOfContent() ));
if( !pSrcTblNd->GetTable().MakeCopy( pCpyDoc, aPos, rBoxes, sal_True, sal_True ))
{
if( pCpyDoc->release() == 0 )
delete pCpyDoc;
if( pUndo )
{
GetIDocumentUndoRedo().DoUndo(bUndo);
delete pUndo;
pUndo = 0;
}
return sal_False;
}
aPos.nNode -= 1; // auf den EndNode der Tabelle
pSrcTblNd = aPos.nNode.GetNode().FindTableNode();
}
const SwStartNode* pSttNd = rInsPos.nNode.GetNode().FindTableBoxStartNode();
rInsPos.nContent.Assign( 0, 0 );
// no complex into complex, but copy into or from new model is welcome
if( ( !pSrcTblNd->GetTable().IsTblComplex() || pInsTblNd->GetTable().IsNewModel() )
&& ( bDelCpyDoc || rBoxes.Count() ) )
{
// dann die Tabelle "relativ" kopieren
const SwSelBoxes* pBoxes;
SwSelBoxes aBoxes;
if( bDelCpyDoc )
{
SwTableBox* pBox = pInsTblNd->GetTable().GetTblBox(
pSttNd->GetIndex() );
ASSERT( pBox, "Box steht nicht in dieser Tabelle" );
aBoxes.Insert( pBox );
pBoxes = &aBoxes;
}
else
pBoxes = &rBoxes;
// kopiere die Tabelle in die selktierten Zellen.
bRet = pInsTblNd->GetTable().InsTable( pSrcTblNd->GetTable(),
*pBoxes, pUndo );
}
else
{
SwNodeIndex aNdIdx( *pSttNd, 1 );
bRet = pInsTblNd->GetTable().InsTable( pSrcTblNd->GetTable(),
aNdIdx, pUndo );
}
if( bDelCpyDoc )
{
if( pCpyDoc->release() == 0 )
delete pCpyDoc;
}
if( pUndo )
{
// falls die Tabelle nicht kopiert werden konnte, das Undo-Object
// wieder loeschen
GetIDocumentUndoRedo().DoUndo(bUndo);
if( !bRet && pUndo->IsEmpty() )
delete pUndo;
else
{
GetIDocumentUndoRedo().AppendUndo(pUndo);
}
}
if( bCorrPos )
{
rInsPos.nNode = *pSttNd;
rInsPos.nContent.Assign( GetNodes().GoNext( &rInsPos.nNode ), 0 );
}
SetRedlineMode( eOld );
}
if( bRet )
{
SetModified();
SetFieldsDirty( true, NULL, 0 );
}
return bRet;
}
sal_Bool SwDoc::_UnProtectTblCells( SwTable& rTbl )
{
sal_Bool bChgd = sal_False;
SwUndoAttrTbl *const pUndo = (GetIDocumentUndoRedo().DoesUndo())
? new SwUndoAttrTbl( *rTbl.GetTableNode() )
: 0;
SwTableSortBoxes& rSrtBox = rTbl.GetTabSortBoxes();
for( sal_uInt16 i = rSrtBox.Count(); i; )
{
SwFrmFmt *pBoxFmt = rSrtBox[ --i ]->GetFrmFmt();
if( pBoxFmt->GetProtect().IsCntntProtected() )
{
pBoxFmt->ResetFmtAttr( RES_PROTECT );
bChgd = sal_True;
}
}
if( pUndo )
{
if( bChgd )
{
GetIDocumentUndoRedo().AppendUndo( pUndo );
}
else
delete pUndo;
}
return bChgd;
}
sal_Bool SwDoc::UnProtectCells( const String& rName )
{
sal_Bool bChgd = sal_False;
SwTableFmt* pFmt = FindTblFmtByName( rName );
if( pFmt )
{
bChgd = _UnProtectTblCells( *SwTable::FindTable( pFmt ) );
if( bChgd )
SetModified();
}
return bChgd;
}
sal_Bool SwDoc::UnProtectCells( const SwSelBoxes& rBoxes )
{
sal_Bool bChgd = sal_False;
if( rBoxes.Count() )
{
SwUndoAttrTbl *const pUndo = (GetIDocumentUndoRedo().DoesUndo())
? new SwUndoAttrTbl( *rBoxes[0]->GetSttNd()->FindTableNode() )
: 0;
SvPtrarr aFmts( 16 ), aNewFmts( 16 );
for( sal_uInt16 i = rBoxes.Count(); i; )
{
SwTableBox* pBox = rBoxes[ --i ];
SwFrmFmt* pBoxFmt = pBox->GetFrmFmt();
if( pBoxFmt->GetProtect().IsCntntProtected() )
{
sal_uInt16 nFnd = aFmts.GetPos( pBoxFmt );
if( USHRT_MAX != nFnd )
pBox->ChgFrmFmt( (SwTableBoxFmt*)aNewFmts[ nFnd ] );
else
{
aFmts.Insert( pBoxFmt, aFmts.Count() );
pBoxFmt = pBox->ClaimFrmFmt();
pBoxFmt->ResetFmtAttr( RES_PROTECT );
aNewFmts.Insert( pBoxFmt, aNewFmts.Count() );
}
bChgd = sal_True;
}
}
if( pUndo )
{
if( bChgd )
{
GetIDocumentUndoRedo().AppendUndo( pUndo );
}
else
delete pUndo;
}
}
return bChgd;
}
sal_Bool SwDoc::UnProtectTbls( const SwPaM& rPam )
{
GetIDocumentUndoRedo().StartUndo(UNDO_EMPTY, NULL);
sal_Bool bChgd = sal_False, bHasSel = rPam.HasMark() ||
rPam.GetNext() != (SwPaM*)&rPam;
SwFrmFmts& rFmts = *GetTblFrmFmts();
SwTable* pTbl;
const SwTableNode* pTblNd;
for( sal_uInt16 n = rFmts.Count(); n ; )
if( 0 != (pTbl = SwTable::FindTable( rFmts[ --n ] )) &&
0 != (pTblNd = pTbl->GetTableNode() ) &&
pTblNd->GetNodes().IsDocNodes() )
{
sal_uLong nTblIdx = pTblNd->GetIndex();
// dann ueberpruefe ob Tabelle in der Selection liegt
if( bHasSel )
{
int bFound = sal_False;
SwPaM* pTmp = (SwPaM*)&rPam;
do {
const SwPosition *pStt = pTmp->Start(),
*pEnd = pTmp->End();
bFound = pStt->nNode.GetIndex() < nTblIdx &&
nTblIdx < pEnd->nNode.GetIndex();
} while( !bFound && &rPam != ( pTmp = (SwPaM*)pTmp->GetNext() ) );
if( !bFound )
continue; // weitersuchen
}
// dann mal den Schutz aufheben
bChgd |= _UnProtectTblCells( *pTbl );
}
GetIDocumentUndoRedo().EndUndo(UNDO_EMPTY, NULL);
if( bChgd )
SetModified();
return bChgd;
}
sal_Bool SwDoc::HasTblAnyProtection( const SwPosition* pPos,
const String* pTblName,
sal_Bool* pFullTblProtection )
{
sal_Bool bHasProtection = sal_False;
SwTable* pTbl = 0;
if( pTblName )
pTbl = SwTable::FindTable( FindTblFmtByName( *pTblName ) );
else if( pPos )
{
SwTableNode* pTblNd = pPos->nNode.GetNode().FindTableNode();
if( pTblNd )
pTbl = &pTblNd->GetTable();
}
if( pTbl )
{
SwTableSortBoxes& rSrtBox = pTbl->GetTabSortBoxes();
for( sal_uInt16 i = rSrtBox.Count(); i; )
{
SwFrmFmt *pBoxFmt = rSrtBox[ --i ]->GetFrmFmt();
if( pBoxFmt->GetProtect().IsCntntProtected() )
{
if( !bHasProtection )
{
bHasProtection = sal_True;
if( !pFullTblProtection )
break;
*pFullTblProtection = sal_True;
}
}
else if( bHasProtection && pFullTblProtection )
{
*pFullTblProtection = sal_False;
break;
}
}
}
return bHasProtection;
}
#ifdef DEL_TABLE_REDLINES
lcl_DelRedlines::lcl_DelRedlines( const SwTableNode& rNd,
sal_Bool bCheckForOwnRedline )
: pDoc( (SwDoc*)rNd.GetNodes().GetDoc() )
{
pDoc->StartUndo(UNDO_EMPTY, NULL);
const SwRedlineTbl& rTbl = pDoc->GetRedlineTbl();
if( !pDoc->IsIgnoreRedline() && rTbl.Count() )
{
sal_Bool bDelete = sal_True;
if( bCheckForOwnRedline )
{
sal_uInt16 nRedlPos = pDoc->GetRedlinePos( rNd, USHRT_MAX );
sal_uInt32 nSttNd = rNd.GetIndex(),
nEndNd = rNd.EndOfSectionIndex();
for ( ; nRedlPos < rTbl.Count(); ++nRedlPos )
{
const SwRedline* pRedline = rTbl[ nRedlPos ];
const SwPosition* pStt = pRedline->Start(),
* pEnd = pStt == pRedline->GetPoint()
? pRedline->GetMark()
: pRedline->GetPoint();
if( pStt->nNode <= nSttNd )
{
if( pEnd->nNode >= nEndNd &&
pRedline->GetAuthor() == pDoc->GetRedlineAuthor() )
{
bDelete = sal_False;
break;
}
}
else
break;
}
}
if( bDelete )
{
SwPaM aPam(*rNd.EndOfSectionNode(), rNd);
pDoc->AcceptRedline( aPam, true );
}
}
}
#endif