diff options
Diffstat (limited to 'sw/source/core/docnode/ndtbl.cxx')
-rw-r--r-- | sw/source/core/docnode/ndtbl.cxx | 4690 |
1 files changed, 4690 insertions, 0 deletions
diff --git a/sw/source/core/docnode/ndtbl.cxx b/sw/source/core/docnode/ndtbl.cxx new file mode 100644 index 000000000000..b213eb1d075d --- /dev/null +++ b/sw/source/core/docnode/ndtbl.cxx @@ -0,0 +1,4690 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <com/sun/star/chart2/XChartDocument.hpp> + +#ifdef WTC +#define private public +#endif +#include <hintids.hxx> + +#include <editeng/lrspitem.hxx> +#include <editeng/brkitem.hxx> +#include <editeng/protitem.hxx> +#include <editeng/boxitem.hxx> +// OD 06.08.2003 #i17174# +#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 <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 <undobj.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> +#ifndef _COMCORE_HRC +#include <comcore.hrc> +#endif +#include "docsh.hxx" +#include <tabcol.hxx> +#include <unochart.hxx> + +#include <node.hxx> +#include <ndtxt.hxx> + +#include <map> +#include <algorithm> +// --> OD 2005-12-05 #i27138# +#include <rootfrm.hxx> +// <-- +#include <fldupde.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 BOOL lcl_GC_Line_Border( const SwTableLine*& , void* pPara ); + +#ifdef DEL_TABLE_REDLINES +class lcl_DelRedlines +{ + SwDoc* pDoc; +public: + lcl_DelRedlines( const SwTableNode& rNd, BOOL bCheckForOwnRedline ); + lcl_DelRedlines( SwPaM& rPam ); + + ~lcl_DelRedlines() { pDoc->EndUndo(UNDO_EMPTY, NULL); } +}; + +lcl_DelRedlines::lcl_DelRedlines( SwPaM & rPam) : pDoc( rPam.GetDoc() ) +{ + pDoc->StartUndo(UNDO_EMPTY, NULL); + if( !pDoc->IsIgnoreRedline() && pDoc->GetRedlineTbl().Count() ) + pDoc->AcceptRedline( rPam, true ); +} +#endif + +void lcl_SetDfltBoxAttr( SwFrmFmt& rFmt, BYTE nId ) +{ + BOOL bTop = FALSE, bBottom = FALSE, bLeft = FALSE, bRight = FALSE; + switch ( nId ) + { + case 0: bTop = bBottom = bLeft = TRUE; break; + case 1: bTop = bBottom = bLeft = bRight = TRUE; break; + case 2: bBottom = bLeft = TRUE; break; + case 3: bBottom = bLeft = bRight = TRUE; break; + } + + const 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, BYTE 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( USHORT 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( 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, + USHORT nCols, BYTE 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, + USHORT nCols, BYTE nId ) +{ + if( !rBoxFmtArr[nId] ) + { + SwTableBoxFmt* pBoxFmt = rDoc.MakeTableBoxFmt(); + rAutoFmt.UpdateToSet( nId, (SfxItemSet&)pBoxFmt->GetAttrSet(), + SwTableAutoFmt::UPDATE_BOX, + rDoc.GetNumberFormatter( 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; + 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. + +BOOL SwNodes::InsBoxen( SwTableNode* pTblNd, + SwTableLine* pLine, + SwTableBoxFmt* pBoxFmt, + SwTxtFmtColl* pTxtColl, + const SfxItemSet* pAutoAttr, + USHORT nInsPos, + USHORT nCnt ) +{ + if( !nCnt ) + return FALSE; + ASSERT( pLine, "keine gueltige Zeile" ); + + // Index hinter die letzte Box der Line + 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 ) + { + BOOL bSetIdxPos = 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 = 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( USHORT 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 ); + pLine->GetTabBoxes().C40_INSERT( SwTableBox, pPrvBox, nInsPos + n ); + + //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 TRUE; +} + +// --------------- einfuegen einer neuen Tabelle -------------- + +const SwTable* SwDoc::InsertTable( const SwInsertTableOptions& rInsTblOpts, + const SwPosition& rPos, USHORT nRows, + USHORT nCols, sal_Int16 eAdjust, + const SwTableAutoFmt* pTAFmt, + const SvUShorts* pColArr, + BOOL bCalledFromShell, + 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( DoesUndo() ) + { + ClearRedo(); + AppendUndo( new SwUndoInsTbl( rPos, nCols, nRows, static_cast<USHORT>(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; + + BOOL bDfltBorders = 0 != ( rInsTblOpts.mnInsMode & tabopts::DEFAULT_BORDER ); + + if( (rInsTblOpts.mnInsMode & tabopts::HEADLINE) && (1 != nRows || !bDfltBorders) ) + pHeadColl = GetTxtCollFromPool( RES_POOLCOLL_TABLE_HDLN ); + + const USHORT 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, 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 ) + { + USHORT nSttPos = (*pColArr)[ 0 ]; + USHORT nLastPos = (*pColArr)[ USHORT(pColArr->Count()-1)]; + if( text::HoriOrientation::NONE == eAdjust ) + { + USHORT nFrmWidth = nLastPos; + nLastPos = (*pColArr)[ USHORT(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( 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, FALSE, + &pItem ) ) + { + pTableFmt->SetFmtAttr( *pItem ); + pNextNd->ResetAttr( RES_PAGEDESC ); + pNdSet = pNextNd->GetpSwAttrSet(); + } + if( pNdSet && SFX_ITEM_SET == pNdSet->GetItemState( RES_BREAK, FALSE, + &pItem ) ) + { + pTableFmt->SetFmtAttr( *pItem ); + pNextNd->ResetAttr( RES_BREAK ); + } + } + + SwTable * pNdTbl = &pTblNd->GetTable(); + pTableFmt->Add( pNdTbl ); // das Frame-Format setzen + + 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 USHORT nBoxArrLen = pTAFmt ? 16 : 4; + for( USHORT 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( USHORT n = 0; n < nRows; ++n ) + { + SwTableLine* pLine = new SwTableLine( pLineFmt, nCols, 0 ); + rLines.C40_INSERT( SwTableLine, pLine, n ); + SwTableBoxes& rBoxes = pLine->GetTabBoxes(); + for( USHORT i = 0; i < nCols; ++i ) + { + SwTableBoxFmt *pBoxF; + if( pTAFmt ) + { + BYTE nId = static_cast<BYTE>(!n ? 0 : (( n+1 == nRows ) + ? 12 : (4 * (1 + ((n-1) & 1 ))))); + nId = nId + static_cast<BYTE>( !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 ) + { + BYTE 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)[ USHORT(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, + USHORT nBoxes, + SwTxtFmtColl* pCntntTxtColl, + USHORT nLines, + USHORT 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( USHORT nL = 0; nL < nLines; ++nL ) + { + for( USHORT 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 USHORT 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 USHORT* pIdx = aPropagateItems; + while ( *pIdx != 0 ) + { + if ( SFX_ITEM_SET != pTmpNd->GetSwAttrSet().GetItemState( *pIdx ) && + SFX_ITEM_SET == pAttrSet->GetItemState( *pIdx, 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(); + { + 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( DoesUndo() ) + { + StartUndo( UNDO_TEXTTOTABLE, NULL ); + pUndo = new SwUndoTxtToTbl( aOriginal, rInsTblOpts, cCh, + static_cast<USHORT>(eAdjust), pTAFmt ); + AppendUndo( pUndo ); + + // das Splitten vom TextNode nicht in die Undohistory aufnehmen + 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 ); + + 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( FALSE, "Kein Bereich" ); + aRg.aEnd++; + } + + // Wir gehen jetzt immer ueber die Upper, um die Tabelle einzufuegen: + SwNode2Layout aNode2Layout( aRg.aStart.GetNode() ); + + 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( 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, 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 USHORT nRowsToRepeat = + tabopts::HEADLINE == (rInsTblOpts.mnInsMode & tabopts::HEADLINE) ? + rInsTblOpts.mnRowsToRepeat : + 0; + pNdTbl->SetRowsToRepeat( nRowsToRepeat ); + + BOOL bUseBoxFmt = 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 = TRUE; + pTableFmt->SetFmtAttr( pBoxFmt->GetFrmSize() ); + delete pBoxFmt; + eAdjust = text::HoriOrientation::NONE; + } + + //Orientation am Fmt der Table setzen + pTableFmt->SetFmtAttr( SwFmtHoriOrient( 0, eAdjust ) ); + pTableFmt->Add( pNdTbl ); // das Frame-Format setzen + + if( pTAFmt || ( rInsTblOpts.mnInsMode & tabopts::DEFAULT_BORDER) ) + { + BYTE nBoxArrLen = pTAFmt ? 16 : 4; + SvPtrarr aBoxFmtArr( nBoxArrLen, 0 ); + { + for( BYTE 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(); + USHORT nRows = rLines.Count(); + for( USHORT n = 0; n < nRows; ++n ) + { + SwTableBoxes& rBoxes = rLines[ n ]->GetTabBoxes(); + USHORT nCols = rBoxes.Count(); + for( USHORT i = 0; i < nCols; ++i ) + { + SwTableBox* pBox = rBoxes[ i ]; + BOOL bChgSz = FALSE; + + if( pTAFmt ) + { + BYTE nId = static_cast<BYTE>(!n ? 0 : (( n+1 == nRows ) + ? 12 : (4 * (1 + ((n-1) & 1 ))))); + nId = nId + static_cast<BYTE>(!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() ) + { + ULONG nSttNd = pBox->GetSttIdx()+1; + 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 + { + BYTE 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( BYTE 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( USHORT nBoxes = pNdTbl->GetTabSortBoxes().Count(); nBoxes; ) + ChkBoxNumFmt( *pNdTbl->GetTabSortBoxes()[ --nBoxes ], FALSE ); + } + + 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 ) + 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; + USHORT 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->GetFrm() ); + 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<USHORT>( + aFInfo.GetCharPos( nChPos+1, FALSE )), + aPosArr.Count() ); + } + } + + aPosArr.Insert( /*aFInfo.GetFrm()->Frm().Left() +*/ + static_cast<USHORT>(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, FALSE, &pItem ) ) + { + if( !nLines ) + pTblFmt->SetFmtAttr( *pItem ); + pTxtNd->ResetAttr( RES_BREAK ); + pSet = pTxtNd->GetpSwAttrSet(); + } + + if( pSet && SFX_ITEM_SET == pSet->GetItemState( + RES_PAGEDESC, 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 + USHORT 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( USHORT 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(); + USHORT nLastPos = 0; + for( n = 0; n < aPosArr.Count(); ++n ) + { + SwTableBoxFmt *pNewFmt = pDoc->MakeTableBoxFmt(); + pNewFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, + aPosArr[ n ] - nLastPos )); + for( USHORT 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; + if( DoesUndo() ) + { +// StartUndo( UNDO_TEXTTOTABLE ); +// pUndo = new SwUndoTxtToTbl( aOriginal, rInsTblOpts, cCh, eAdjust, pTAFmt ); +// AppendUndo( pUndo ); + + // das Splitten vom TextNode nicht in die Undohistory aufnehmen + 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 ); + + 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( FALSE, "Kein Bereich" ); + aRg.aEnd++; + } + + // Wir gehen jetzt immer ueber die Upper, um die Tabelle einzufuegen: + SwNode2Layout aNode2Layout( aRg.aStart.GetNode() ); + + 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->SetAttr( SwFmtLayoutSplit( 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, 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." ) + pTableFmt->Add( pNdTbl ); // das Frame-Format setzen + +// const USHORT nRowsToRepeat = +// tabopts::HEADLINE == (rInsTblOpts.mnInsMode & tabopts::HEADLINE) ? +// rInsTblOpts.mnRowsToRepeat : +// 0; +// pNdTbl->SetRowsToRepeat( nRowsToRepeat ); + + BOOL bUseBoxFmt = 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 = TRUE; + pTableFmt->SetFmtAttr( pBoxFmt->GetFrmSize() ); + delete pBoxFmt; +// eAdjust = HORI_NONE; + } + + //Orientation am Fmt der Table setzen +// pTableFmt->SetAttr( SwFmtHoriOrient( 0, eAdjust ) ); +// pTableFmt->Add( pNdTbl ); // das Frame-Format setzen + + + 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 ) +// EndUndo( UNDO_TEXTTOTABLE ); + + 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; + USHORT 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, FALSE, &pItem ) ) + { + if( !nLines ) + pTblFmt->SetFmtAttr( *pItem ); + rTxtNode.ResetAttr( RES_BREAK ); + pSet = rTxtNode.GetpSwAttrSet(); + } + + if( pSet && SFX_ITEM_SET == pSet->GetItemState( + RES_PAGEDESC, 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 + USHORT n; + + if( aPosArr.Count() ) + { + SwTableLines& rLns = pTable->GetTabLines(); + USHORT nLastPos = 0; + for( n = 0; n < aPosArr.Count(); ++n ) + { + SwTableBoxFmt *pNewFmt = pDoc->MakeTableBoxFmt(); + pNewFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, + aPosArr[ n ] - nLastPos )); + for( USHORT 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 ----------------------- + + +BOOL SwDoc::TableToText( const SwTableNode* pTblNd, sal_Unicode cCh ) +{ + if( !pTblNd ) + return 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, FALSE ); +#endif + + SwNodeRange aRg( *pTblNd, 0, *pTblNd->EndOfSectionNode() ); + SwUndoTblToTxt* pUndo = 0; + SwNodeRange* pUndoRg = 0; + if( DoesUndo() ) + { + 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 ); + + BOOL bRet = GetNodes().TableToText( aRg, cCh, pUndo ); + if( pUndoRg ) + { + pUndoRg->aStart++; + pUndoRg->aEnd--; + pUndo->SetRange( *pUndoRg ); + 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. +BOOL lcl_DelBox( const SwTableBox*&, void *pPara ); + +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 TRUE; +} + + +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 + 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 TRUE; +} + + +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 = (*this)[ rRange.aStart ]->GetTableNode()) || + &rRange.aEnd.GetNode() != pTblNd->EndOfSectionNode() ) + return 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, FALSE, &pDesc )) + pDesc = 0; + if( SFX_ITEM_SET != rTblSet.GetItemState( RES_BREAK, 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# + 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( USHORT 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 TRUE; +} + + +// ----- einfuegen von Spalten/Zeilen ------------------------ + +BOOL SwDoc::InsertCol( const SwCursor& rCursor, USHORT nCnt, BOOL bBehind ) +{ + if( !::CheckSplitCells( rCursor, nCnt + 1, nsSwTblSearchType::TBLSEARCH_COL ) ) + return FALSE; + + // lasse ueber das Layout die Boxen suchen + SwSelBoxes aBoxes; + ::GetTblSel( rCursor, aBoxes, nsSwTblSearchType::TBLSEARCH_COL ); + + BOOL bRet = FALSE; + if( aBoxes.Count() ) + bRet = InsertCol( aBoxes, nCnt, bBehind ); + return bRet; +} + +BOOL SwDoc::InsertCol( const SwSelBoxes& rBoxes, USHORT nCnt, BOOL bBehind ) +{ + // uebers SwDoc fuer Undo !! + ASSERT( rBoxes.Count(), "keine gueltige Box-Liste" ); + SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode(); + if( !pTblNd ) + return FALSE; + + SwTable& rTbl = pTblNd->GetTable(); + if( rTbl.ISA( SwDDETable )) + return FALSE; + +#ifdef DEL_TABLE_REDLINES + lcl_DelRedlines aDelRedl( *pTblNd, TRUE ); +#endif + + SwTableSortBoxes aTmpLst( 0, 5 ); + SwUndoTblNdsChg* pUndo = 0; + if( DoesUndo() ) + { + DoUndo( FALSE ); + pUndo = new SwUndoTblNdsChg( UNDO_TABLE_INSCOL, rBoxes, *pTblNd, + 0, 0, nCnt, bBehind, FALSE ); + aTmpLst.Insert( &rTbl.GetTabSortBoxes(), 0, rTbl.GetTabSortBoxes().Count() ); + } + + SwTableFmlUpdate aMsgHnt( &rTbl ); + aMsgHnt.eFlags = TBL_BOXPTR; + UpdateTblFlds( &aMsgHnt ); + + BOOL bRet = rTbl.InsertCol( this, rBoxes, nCnt, bBehind ); + if( bRet ) + { + SetModified(); + ::ClearFEShellTabCols(); + SetFieldsDirty( true, NULL, 0 ); + } + + if( pUndo ) + { + DoUndo( TRUE ); + if( bRet ) + { + ClearRedo(); + pUndo->SaveNewBoxes( *pTblNd, aTmpLst ); + AppendUndo( pUndo ); + } + else + delete pUndo; + } + return bRet; +} + +BOOL SwDoc::InsertRow( const SwCursor& rCursor, USHORT nCnt, BOOL bBehind ) +{ + // lasse ueber das Layout die Boxen suchen + SwSelBoxes aBoxes; + GetTblSel( rCursor, aBoxes, nsSwTblSearchType::TBLSEARCH_ROW ); + + BOOL bRet = FALSE; + if( aBoxes.Count() ) + bRet = InsertRow( aBoxes, nCnt, bBehind ); + return bRet; +} + +BOOL SwDoc::InsertRow( const SwSelBoxes& rBoxes, USHORT nCnt, BOOL bBehind ) +{ + // uebers SwDoc fuer Undo !! + ASSERT( rBoxes.Count(), "keine gueltige Box-Liste" ); + SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode(); + if( !pTblNd ) + return FALSE; + + SwTable& rTbl = pTblNd->GetTable(); + if( rTbl.ISA( SwDDETable )) + return FALSE; + +#ifdef DEL_TABLE_REDLINES + lcl_DelRedlines aDelRedl( *pTblNd, TRUE ); +#endif + + SwTableSortBoxes aTmpLst( 0, 5 ); + SwUndoTblNdsChg* pUndo = 0; + if( DoesUndo() ) + { + DoUndo( FALSE ); + pUndo = new SwUndoTblNdsChg( UNDO_TABLE_INSROW,rBoxes, *pTblNd, + 0, 0, nCnt, bBehind, FALSE ); + aTmpLst.Insert( &rTbl.GetTabSortBoxes(), 0, rTbl.GetTabSortBoxes().Count() ); + } + + SwTableFmlUpdate aMsgHnt( &rTbl ); + aMsgHnt.eFlags = TBL_BOXPTR; + UpdateTblFlds( &aMsgHnt ); + + BOOL bRet = rTbl.InsertRow( this, rBoxes, nCnt, bBehind ); + if( bRet ) + { + SetModified(); + ::ClearFEShellTabCols(); + SetFieldsDirty( true, NULL, 0 ); + } + + if( pUndo ) + { + DoUndo( TRUE ); + if( bRet ) + { + ClearRedo(); + pUndo->SaveNewBoxes( *pTblNd, aTmpLst ); + AppendUndo( pUndo ); + } + else + delete pUndo; + } + return bRet; + +} + +// ----- loeschen von Spalten/Zeilen ------------------------ + +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 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 FALSE; + + // suche alle Boxen / Lines + _FndBox aFndBox( 0, 0 ); + { + _FndPara aPara( aBoxes, &aFndBox ); + pTblNd->GetTable().GetTabLines().ForEach( &_FndLineCopyCol, &aPara ); + } + + if( !aFndBox.GetLines().Count() ) + return 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, 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, TRUE ); + while( pNextBox && + pNextBox->GetFrmFmt()->GetProtect().IsCntntProtected() ) + pNextBox = pNextBox->FindPreviousBox( pTblNd->GetTable(), pNextBox ); + } + + 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 + + StartUndo(UNDO_ROW_DELETE, NULL); + BOOL bResult = DeleteRowCol( aBoxes ); + EndUndo(UNDO_ROW_DELETE, NULL); + + return bResult; +} + +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 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 + StartUndo(UNDO_COL_DELETE, NULL); + BOOL bResult = DeleteRowCol( aBoxes, true ); + EndUndo(UNDO_COL_DELETE, NULL); + + return bResult; +} + +BOOL SwDoc::DeleteRowCol( const SwSelBoxes& rBoxes, bool bColumn ) +{ + if( ::HasProtectedCells( rBoxes )) + return FALSE; + + // uebers SwDoc fuer Undo !! + ASSERT( rBoxes.Count(), "keine gueltige Box-Liste" ); + SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode(); + if( !pTblNd ) + return FALSE; + + if( pTblNd->GetTable().ISA( SwDDETable )) + return 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, TRUE ); +#endif + + // soll die gesamte Tabelle geloescht werden ?? + const ULONG nTmpIdx1 = pTblNd->GetIndex(); + const ULONG nTmpIdx2 = aSelBoxes[ aSelBoxes.Count()-1 ]->GetSttNd()-> + EndOfSectionIndex()+1; + if( pTblNd->GetTable().GetTabSortBoxes().Count() == aSelBoxes.Count() && + aSelBoxes[0]->GetSttIdx()-1 == nTmpIdx1 && + nTmpIdx2 == pTblNd->EndOfSectionIndex() ) + { + BOOL bNewTxtNd = FALSE; + // steht diese auch noch alleine in einem FlyFrame ? + SwNodeIndex aIdx( *pTblNd, -1 ); + const SwStartNode* pSttNd = aIdx.GetNode().GetStartNode(); + if( pSttNd ) + { + const ULONG nTblEnd = pTblNd->EndOfSectionIndex() + 1; + const 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 TRUE; + } + } + // kein Fly ?? also Kopf- oder Fusszeile: dann immer einen + // TextNode ueberig lassen. + // Undo koennen wir dann vergessen !! + bNewTxtNd = TRUE; + } + } + + // kein Fly ?? also Kopf- oder Fusszeile: dann immer einen + // TextNode ueberig lassen. + aIdx++; + if( DoesUndo() ) + { + 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 ); + } + ::PaMCorrAbs( SwNodeIndex( *pTblNd ), + SwNodeIndex( *pTblNd->EndOfSectionNode() ), + *aSavePaM.GetMark() ); + + // harte SeitenUmbrueche am nachfolgenden Node verschieben + BOOL bSavePageBreak = FALSE, bSavePageDesc = FALSE; + 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, + FALSE, &pItem ) ) + { + pNextNd->SetAttr( *pItem ); + bSavePageDesc = TRUE; + } + + if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_BREAK, + FALSE, &pItem ) ) + { + pNextNd->SetAttr( *pItem ); + bSavePageBreak = TRUE; + } + } + } + SwUndoDelete* pUndo = new SwUndoDelete( aPaM ); + if( bNewTxtNd ) + pUndo->SetTblDelLastNd(); + pUndo->SetPgBrkFlags( bSavePageBreak, bSavePageDesc ); + pUndo->SetTableName(pTblNd->GetTable().GetFrmFmt()->GetName()); + 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 ); + } + ::PaMCorrAbs( SwNodeIndex( *pTblNd ), + SwNodeIndex( *pTblNd->EndOfSectionNode() ), + *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, + FALSE, &pItem ) ) + pNextNd->SetAttr( *pItem ); + + if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_BREAK, + FALSE, &pItem ) ) + pNextNd->SetAttr( *pItem ); + } + + pTblNd->DelFrms(); + DeleteSection( pTblNd ); + } + SetModified(); + SetFieldsDirty( true, NULL, 0 ); + return TRUE; + } + + SwUndoTblNdsChg* pUndo = 0; + if( DoesUndo() ) + { + DoUndo( FALSE ); + pUndo = new SwUndoTblNdsChg( UNDO_TABLE_DELBOX, aSelBoxes, *pTblNd, + nMin, nMax, 0, FALSE, FALSE ); + } + + 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 ); + } + const BOOL bRet = rTable.DeleteSel( this, aSelBoxes, 0, pUndo, TRUE, TRUE ); + if( bRet ) + { + SetModified(); + SetFieldsDirty( true, NULL, 0 ); + } + + if( pUndo ) + { + DoUndo( TRUE ); + if( bRet ) + { + ClearRedo(); + AppendUndo( pUndo ); + } + else + delete pUndo; + } + + return bRet; +} + + +// ---------- teilen / zusammenfassen von Boxen in der Tabelle -------- + +BOOL SwDoc::SplitTbl( const SwSelBoxes& rBoxes, sal_Bool bVert, USHORT 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 FALSE; + + SwTable& rTbl = pTblNd->GetTable(); + if( rTbl.ISA( SwDDETable )) + return FALSE; + +#ifdef DEL_TABLE_REDLINES + lcl_DelRedlines aDelRedl( *pTblNd, TRUE ); +#endif + + SvULongs aNdsCnts; + SwTableSortBoxes aTmpLst( 0, 5 ); + SwUndoTblNdsChg* pUndo = 0; + BOOL bDoUndo = DoesUndo(); + if( bDoUndo ) + { + DoUndo( FALSE ); + pUndo = new SwUndoTblNdsChg( UNDO_TABLE_SPLIT, rBoxes, *pTblNd, 0, 0, + nCnt, bVert, bSameHeight ); + + aTmpLst.Insert( &rTbl.GetTabSortBoxes(), 0, rTbl.GetTabSortBoxes().Count() ); + if( !bVert ) + { + for( USHORT n = 0; n < rBoxes.Count(); ++n ) + { + const SwStartNode* pSttNd = rBoxes[ n ]->GetSttNd(); + aNdsCnts.Insert( pSttNd->EndOfSectionIndex() - + pSttNd->GetIndex(), n ); + } + } + } + + SwTableFmlUpdate aMsgHnt( &rTbl ); + aMsgHnt.eFlags = TBL_BOXPTR; + UpdateTblFlds( &aMsgHnt ); + + BOOL bRet; + if( bVert ) + bRet = rTbl.SplitCol( this, rBoxes, nCnt ); + else + bRet = rTbl.SplitRow( this, rBoxes, nCnt, bSameHeight ); + + if( bRet ) + { + SetModified(); + SetFieldsDirty( true, NULL, 0 ); + } + + DoUndo( bDoUndo ); + if( pUndo ) + { + if( bRet ) + { + ClearRedo(); + if( bVert ) + pUndo->SaveNewBoxes( *pTblNd, aTmpLst ); + else + pUndo->SaveNewBoxes( *pTblNd, aTmpLst, rBoxes, aNdsCnts ); + AppendUndo( pUndo ); + } + else + delete pUndo; + } + + return bRet; +} + + +USHORT 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; + USHORT nRet = TBLMERGE_NOSELECTION; + if( !rTable.IsNewModel() ) + { + nRet =::CheckMergeSel( rPam ); + if( TBLMERGE_OK != nRet ) + return nRet; + nRet = TBLMERGE_NOSELECTION; + } + + // --> FME 2004-10-08 #i33394# + 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* pUndo = 0; + if( DoesUndo() ) + pUndo = new SwUndoTblMerge( rPam ); + + // 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; + if( UNDO_REDLINE == GetUndoIds(NULL, NULL) ) + { + SwUndoRedline* pU = (SwUndoRedline*)RemoveLastUndo( UNDO_REDLINE ); + if( pU->GetRedlSaveCount() ) + { + SwUndoIter aUndoIter( &rPam, UNDO_REDLINE ); + pU->Undo( aUndoIter ); + } + 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( (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 ) + AppendUndo( pUndo ); + } + else if( pUndo ) + delete pUndo; + + rPam.GetPoint()->nNode = *pMergeBox->GetSttNd(); + rPam.Move(); + + ::ClearFEShellTabCols(); + SetRedlineMode_intern( eOld ); + } + 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->Modify( &aMsgHint, &aMsgHint ); + DelFrms(); + delete pTable; +} + +SwTabFrm *SwTableNode::MakeFrm() +{ + return new SwTabFrm( *pTable ); +} + +//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."); + + BOOL bBefore = rIdx < GetIndex(); + + SwNode2Layout aNode2Layout( *this, rIdx.GetIndex() ); + + while( 0 != (pFrm = aNode2Layout.NextFrm()) ) + { + pNew = pNode->MakeFrm(); + // 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(); + 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->GetShell() ); + 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. + + SwClientIter aIter( *(pTable->GetFrmFmt()) ); + SwClient *pLast = aIter.GoStart(); + while ( pLast ) + { + BOOL bAgain = FALSE; + if ( pLast->IsA( TYPE(SwFrm) ) ) + { + SwTabFrm *pFrm = (SwTabFrm*)pLast; + 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->GetShell() ); + 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 = TRUE; + } + } + pLast = bAgain ? aIter.GoStart() : aIter++; + } +} + + +void SwTableNode::SetNewTable( SwTable* pNewTable, 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->GetFrm( &aPt, 0, 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 ULONG nLeftMin = (pTab->Frm().*fnRect->fnGetLeft)() - + (pPage->Frm().*fnRect->fnGetLeft)(); + const 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( USHORT 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 ( BYTE 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: + USHORT 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, 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->GetFrm( &aPt, 0, 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 ULONG nLeftMin = (pTab->Frm().*fnRect->fnGetLeft)() - + (pPage->Frm().*fnRect->fnGetLeft)(); + const 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, 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 ); + + StartUndo( UNDO_TABLE_ATTR, NULL ); + + // check for differences between aOld and rNew: + const USHORT nCount = rNew.Count(); + const SwTable* pTable = pTab->GetTable(); + ASSERT( pTable, "My colleague told me, this couldn't happen" ); + + for ( USHORT i = 0; i <= nCount; ++i ) + { + const USHORT nIdxStt = bVert ? nCount - i : i - 1; + const USHORT 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 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(); + } + } + } + + 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, BOOL bCurRowOnly ) +{ + if( DoesUndo() ) + { + ClearRedo(); + AppendUndo( new SwUndoAttrTbl( *rTab.GetTableNode(), TRUE )); + } + rTab.SetTabCols( rNew, rOld, pStart, bCurRowOnly ); + ::ClearFEShellTabCols(); + SetModified(); +} + +void SwDoc::SetRowsToRepeat( SwTable &rTable, USHORT nSet ) +{ + if( nSet == rTable.GetRowsToRepeat() ) + return; + + if( DoesUndo() ) + { + ClearRedo(); + AppendUndo( new SwUndoTblHeadline( rTable, rTable.GetRowsToRepeat() , nSet) ); + } + + SwMsgPoolItem aChg( RES_TBLHEADLINECHG ); + rTable.SetRowsToRepeat( nSet ); + rTable.GetFrmFmt()->Modify( &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 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 + (USHORT)rBox.GetFrmFmt()->GetFrmSize().GetWidth(); +} + +const SwTableBox* SwCollectTblLineBoxes::GetBoxOfPos( const SwTableBox& rBox ) +{ + const SwTableBox* pRet = 0; + USHORT 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 + (USHORT)rBox.GetFrmFmt()->GetFrmSize().GetWidth(); + pRet = aBoxes[ n ]; + } + return pRet; +} + +BOOL SwCollectTblLineBoxes::Resize( USHORT nOffset, USHORT nOldWidth ) +{ + USHORT 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 ) + { + ULONG nSize = nWidth; + nSize *= ( aPosArr[ n ] - nOffset ); + nSize /= nOldWidth; + aPosArr[ n ] = USHORT( nSize ); + } + } + return 0 != aPosArr.Count(); +} + +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 TRUE; +} + +BOOL lcl_Box_CollectBox( const SwTableBox*& rpBox, void* pPara ) +{ + SwCollectTblLineBoxes* pSplPara = (SwCollectTblLineBoxes*)pPara; + USHORT 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 TRUE; +} + +BOOL lcl_BoxSetSplitBoxFmts( const SwTableBox*& rpBox, void* pPara ) +{ + SwCollectTblLineBoxes* pSplPara = (SwCollectTblLineBoxes*)pPara; + USHORT 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 + { +USHORT __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 TRUE; +} + + +BOOL SwDoc::SplitTable( const SwPosition& rPos, USHORT eHdlnMode, + BOOL bCalcNewSize ) +{ + SwNode* pNd = &rPos.nNode.GetNode(); + SwTableNode* pTNd = pNd->FindTableNode(); + if( !pTNd || pNd->IsTableNode() ) + return 0; + + if( pTNd->GetTable().ISA( SwDDETable )) + return FALSE; + + SwTable& rTbl = pTNd->GetTable(); + rTbl.SetHTMLTableLayout( 0 ); // MIB 9.7.97: HTML-Layout loeschen + + SwTableFmlUpdate aMsgHnt( &rTbl ); + + SwHistory aHistory; + if( DoesUndo() ) + aMsgHnt.pHistory = &aHistory; + + { + 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, FALSE, bCalcNewSize ); + + if( pNew ) + { + SwSaveRowSpan* pSaveRowSp = pNew->GetTable().CleanUpTopRowSpan( rTbl.GetTabLines().Count() ); + SwUndoSplitTbl* pUndo = 0; + if( DoesUndo() ) + { + ClearRedo(); + AppendUndo( pUndo = new SwUndoSplitTbl( *pNew, pSaveRowSp, eHdlnMode, bCalcNewSize )); + 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( FALSE, eHdlnMode ); + SwTableLine* pLn = rTbl.GetTabLines()[ + rTbl.GetTabLines().Count() - 1 ]; + pLn->GetTabBoxes().ForEach( &lcl_Box_CollectBox, &aPara ); + + aPara.SetValues( 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( TRUE, eHdlnMode, pHst ); + SwTableLine* pLn = rTbl.GetTabLines()[ 0 ]; + pLn->GetTabBoxes().ForEach( &lcl_Box_CollectBox, &aPara ); + + aPara.SetValues( 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; +} + +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 FALSE; + + BOOL bLocked = pFmt->IsModifyLocked(); + pFmt->LockModify(); + + aTblMaxSz.SetWidth( 0 ); + + SwTableLines& rLns = rTbl.GetTabLines(); + for( USHORT nLns = 0; nLns < rLns.Count(); ++nLns ) + { + SwTwips nMaxLnWidth = 0; + SwTableBoxes& rBoxes = rLns[ nLns ]->GetTabBoxes(); + for( USHORT 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 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 ) + {} + USHORT 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( USHORT nPos ) const + { return (SwFrmFmt*)aDest[ nPos ]; } + + void ChgBox( SwTableBox* pBox ) + { + rOldTbl.GetTabSortBoxes().Remove( pBox ); + pNewTblNd->GetTable().GetTabSortBoxes().Insert( pBox ); + } +}; + + +BOOL lcl_SplitTable_CpyBox( const SwTableBox*& rpBox, void* pPara ); + +BOOL lcl_SplitTable_CpyLine( const SwTableLine*& rpLine, void* pPara ) +{ + SwTableLine* pLn = (SwTableLine*)rpLine; + _SplitTable_Para& rPara = *(_SplitTable_Para*)pPara; + + SwFrmFmt *pSrcFmt = pLn->GetFrmFmt(); + USHORT 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 TRUE; +} + +BOOL lcl_SplitTable_CpyBox( const SwTableBox*& rpBox, void* pPara ) +{ + SwTableBox* pBox = (SwTableBox*)rpBox; + _SplitTable_Para& rPara = *(_SplitTable_Para*)pPara; + + SwFrmFmt *pSrcFmt = pBox->GetFrmFmt(); + USHORT 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 TRUE; +} + +SwTableNode* SwNodes::SplitTable( const SwNodeIndex& rPos, BOOL bAfter, + BOOL bCalcNewSize ) +{ + SwNode* pNd = &rPos.GetNode(); + SwTableNode* pTNd = pNd->FindTableNode(); + if( !pTNd || pNd->IsTableNode() ) + return 0; + + 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. + USHORT 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 (USHORT k = nLinePos; k < rTbl.GetTabLines().Count(); ++k) + { + USHORT nLineIdx = (rTbl.GetTabLines().Count() - 1) - k + nLinePos; + USHORT nBoxCnt = rTbl.GetTabLines()[ nLineIdx ]->GetTabBoxes().Count(); + for (USHORT j = 0; j < nBoxCnt; ++j) + { + USHORT nIdx = nBoxCnt - 1 - j; + pPCD->DeleteBox( &rTbl, *rTbl.GetTabLines()[ nLineIdx ]->GetTabBoxes()[nIdx] ); + } + } + } + // + // ...und loeschen + USHORT 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; + pNewTblFmt->Add( &pNewTblNd->GetTable() ); + + // 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. +BOOL SwDoc::MergeTable( const SwPosition& rPos, BOOL bWithPrev, USHORT nMode ) +{ + SwTableNode* pTblNd = rPos.nNode.GetNode().FindTableNode(), *pDelTblNd; + if( !pTblNd ) + return FALSE; + + SwNodes& rNds = GetNodes(); + if( bWithPrev ) + pDelTblNd = rNds[ pTblNd->GetIndex() - 1 ]->FindTableNode(); + else + pDelTblNd = rNds[ pTblNd->EndOfSectionIndex() + 1 ]->GetTableNode(); + if( !pDelTblNd ) + return FALSE; + + if( pTblNd->GetTable().ISA( SwDDETable ) || + pDelTblNd->GetTable().ISA( SwDDETable )) + return 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( DoesUndo() ) + { + ClearRedo(); + AppendUndo( pUndo = new SwUndoMergeTbl( *pTblNd, *pDelTblNd, + bWithPrev, nMode )); + 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 ); + 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; +} + +BOOL SwNodes::MergeTable( const SwNodeIndex& rPos, BOOL bWithPrev, + USHORT 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 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 + USHORT 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( (USHORT)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 TRUE; +} + +// ------------------------------------------------------------------- + + +// -- benutze die ForEach Methode vom PtrArray +struct _SetAFmtTabPara +{ + SwTableAutoFmt& rTblFmt; + SwUndoTblAutoFmt* pUndo; + USHORT nEndBox, nCurBox; + BYTE 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. +BOOL lcl_SetAFmtBox( const _FndBox*&, void *pPara ); +BOOL lcl_SetAFmtLine( const _FndLine*&, void *pPara ); + +BOOL lcl_SetAFmtLine( const _FndLine*& rpLine, void *pPara ) +{ + ((_FndLine*&)rpLine)->GetBoxes().ForEach( &lcl_SetAFmtBox, pPara ); + return TRUE; +} + +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 = (BYTE)(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 ); + BYTE 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( TRUE ) ); + if( aCharSet.Count() ) + { + ULONG nSttNd = pSetBox->GetSttIdx()+1; + 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 TRUE; +} + + + // AutoFormat fuer die Tabelle/TabellenSelection +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 FALSE; + + // suche alle Boxen / Lines + _FndBox aFndBox( 0, 0 ); + { + _FndPara aPara( rBoxes, &aFndBox ); + pTblNd->GetTable().GetTabLines().ForEach( &_FndLineCopyCol, &aPara ); + } + if( !aFndBox.GetLines().Count() ) + return 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; + if( DoesUndo() ) + { + ClearRedo(); + AppendUndo( pUndo = new SwUndoTblAutoFmt( *pTblNd, rNew ) ); + DoUndo( FALSE ); + } + + _SetAFmtTabPara aPara( rNew ); + _FndLines& rFLns = pFndBox->GetLines(); + _FndLine* pLine; + + for( USHORT 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 = (BYTE)(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 ) + DoUndo( TRUE ); + + SetModified(); + SetFieldsDirty( true, NULL, 0 ); + + return TRUE; +} + + + // Erfrage wie attributiert ist +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 FALSE; + + // suche alle Boxen / Lines + _FndBox aFndBox( 0, 0 ); + { + _FndPara aPara( rBoxes, &aFndBox ); + pTblNd->GetTable().GetTabLines().ForEach( &_FndLineCopyCol, &aPara ); + } + if( !aFndBox.GetLines().Count() ) + return 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(); + + USHORT 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( BYTE nLine = 0; nLine < 4; ++nLine ) + { + _FndLine& rLine = *rFLns[ aLnArr[ nLine ] ]; + + USHORT 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( BYTE 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]; + + BYTE 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( TRUE ) ); + } + } + + return TRUE; +} + +String SwDoc::GetUniqueTblName() const +{ + ResId aId( STR_TABLE_DEFNAME, *pSwResMgr ); + String aName( aId ); + xub_StrLen nNmLen = aName.Len(); + + USHORT nNum, nTmp, nFlagSize = ( pTblFrmFmtTbl->Count() / 8 ) +2; + USHORT n; + + BYTE* pSetFlags = new BYTE[ 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<USHORT>(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, BOOL bAll ) const +{ + const SwFmt* pRet = 0; + if( bAll ) + pRet = FindFmtByName( (SvPtrarr&)*pTblFrmFmtTbl, rName ); + else + { + // dann nur die, die im Doc gesetzt sind + for( USHORT 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; +} + +BOOL SwDoc::SetColRowWidthHeight( SwTableBox& rAktBox, USHORT 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 FALSE; + + SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() ); + aMsgHnt.eFlags = TBL_BOXPTR; + UpdateTblFlds( &aMsgHnt ); + + BOOL bRet = 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, + DoesUndo() ? &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, + DoesUndo() ? &pUndo : 0 ); + break; + } + + if( pUndo ) + { + ClearRedo(); + AppendUndo( pUndo ); + DoUndo( TRUE ); // im SetColWidth kann es abgeschaltet werden! + } + + if( bRet ) + { + SetModified(); + if( nsTblChgWidthHeightType::WH_FLAG_INSDEL & eType ) + SetFieldsDirty( true, NULL, 0 ); + } + return bRet; +} + + +void SwDoc::ChkBoxNumFmt( SwTableBox& rBox, 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, + FALSE, &pNumFmtItem ) && GetNumberFormatter()->IsTextFormat( + ((SwTblBoxNumFormat*)pNumFmtItem)->GetValue() )) + return ; + + SwUndoTblNumFmt* pUndo = 0; + + BOOL bIsEmptyTxtNd, bChgd = TRUE; + sal_uInt32 nFmtIdx; + double fNumber; + if( rBox.HasNumCntnt( fNumber, nFmtIdx, bIsEmptyTxtNd ) ) + { + if( !rBox.IsNumberChanged() ) + bChgd = FALSE; + else + { + if( DoesUndo() ) + { + 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 ); + + BOOL bSetNumFmt = IsInsTblFormatNum(), bLockModify = TRUE; + if( bSetNumFmt ) + { + if( !IsInsTblChangeNumFormat() ) + { + if( !pNumFmtItem ) + bSetNumFmt = FALSE; + else + { + 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 = 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, + FALSE, &pFmtItem ) || + SFX_ITEM_SET == pBoxFmt->GetItemState( RES_BOXATR_VALUE, + FALSE, &pValueItem )) + { + if( DoesUndo() ) + { + StartUndo( UNDO_TABLE_AUTOFMT, NULL ); + pUndo = new SwUndoTblNumFmt( rBox ); + } + + pBoxFmt = (SwTableBoxFmt*)rBox.ClaimFrmFmt(); + + // alle Zahlenformate entfernen + USHORT 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 = FALSE; + } + + if( bChgd ) + { + if( pUndo ) + { + pUndo->SetBox( rBox ); + AppendUndo( pUndo ); + 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( DoesUndo() ) + { + ClearRedo(); + 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 = GetNodes()[ rNode ]-> + 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, FALSE, &pFmtItem ) || + SFX_ITEM_SET == rSet.GetItemState( RES_BOXATR_FORMULA, FALSE ) || + SFX_ITEM_SET == rSet.GetItemState( RES_BOXATR_VALUE, FALSE )) + { + if( DoesUndo() ) + { + ClearRedo(); + AppendUndo( new SwUndoTblNumFmt( *pBox ) ); + } + + SwFrmFmt* pBoxFmt = pBox->ClaimFrmFmt(); + + //JP 01.09.97: TextFormate bleiben erhalten! + USHORT 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 + +BOOL SwDoc::InsCopyOfTbl( SwPosition& rInsPos, const SwSelBoxes& rBoxes, + const SwTable* pCpyTbl, BOOL bCpyName, BOOL bCorrPos ) +{ + BOOL bRet; + + const SwTableNode* pSrcTblNd = pCpyTbl + ? pCpyTbl->GetTableNode() + : rBoxes[ 0 ]->GetSttNd()->FindTableNode(); + + SwTableNode* pInsTblNd = GetNodes()[ rInsPos.nNode ]->FindTableNode(); + + if( !pCpyTbl && !pInsTblNd ) + { + SwUndoCpyTbl* pUndo = 0; + if( DoesUndo() ) + { + ClearRedo(); + pUndo = new SwUndoCpyTbl; + DoUndo( FALSE ); + } + + bRet = pSrcTblNd->GetTable().MakeCopy( this, rInsPos, rBoxes, + TRUE, bCpyName ); + if( pUndo ) + { + if( !bRet ) + delete pUndo; + else + { + pInsTblNd = GetNodes()[ rInsPos.nNode.GetIndex() - 1 ]->FindTableNode(); + + pUndo->SetTableSttIdx( pInsTblNd->GetIndex() ); + AppendUndo( pUndo ); + } + DoUndo( TRUE ); + } + } + 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( DoesUndo() ) + { + ClearRedo(); + pUndo = new SwUndoTblCpyTbl; + DoUndo( FALSE ); + } + + SwDoc* pCpyDoc = (SwDoc*)pSrcTblNd->GetDoc(); + SfxObjectShellRef* pRefForDocSh = 0; + BOOL bDelCpyDoc = pCpyDoc == this; + + if( bDelCpyDoc ) + { + // kopiere die Tabelle erstmal in ein temp. Doc + pCpyDoc = new SwDoc; + pCpyDoc->acquire(); + pRefForDocSh = new SfxObjectShellRef(); + pCpyDoc->SetRefForDocShell( pRefForDocSh ); + + SwPosition aPos( SwNodeIndex( pCpyDoc->GetNodes().GetEndOfContent() )); + if( !pSrcTblNd->GetTable().MakeCopy( pCpyDoc, aPos, rBoxes, TRUE, TRUE )) + { + delete pRefForDocSh; + if( pCpyDoc->release() == 0 ) + delete pCpyDoc; + + if( pUndo ) + { + DoUndo( TRUE ); + delete pUndo; + } + return FALSE; + } + aPos.nNode -= 1; // auf den EndNode der Tabelle + pSrcTblNd = aPos.nNode.GetNode().FindTableNode(); + + pCpyDoc->SetRefForDocShell( NULL ); + } + + 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 ) + { + delete pRefForDocSh; + if( pCpyDoc->release() == 0 ) + delete pCpyDoc; + } + + if( pUndo ) + { + // falls die Tabelle nicht kopiert werden konnte, das Undo-Object + // wieder loeschen + if( !bRet && pUndo->IsEmpty() ) + delete pUndo; + else + AppendUndo( pUndo ); + DoUndo( TRUE ); + } + + if( bCorrPos ) + { + rInsPos.nNode = *pSttNd; + rInsPos.nContent.Assign( GetNodes().GoNext( &rInsPos.nNode ), 0 ); + } + SetRedlineMode( eOld ); + } + + if( bRet ) + { + SetModified(); + SetFieldsDirty( true, NULL, 0 ); + } + return bRet; +} + + + +BOOL SwDoc::_UnProtectTblCells( SwTable& rTbl ) +{ + BOOL bChgd = FALSE; + SwUndoAttrTbl* pUndo = DoesUndo() ? new SwUndoAttrTbl( *rTbl.GetTableNode() ) + : 0; + + SwTableSortBoxes& rSrtBox = rTbl.GetTabSortBoxes(); + for( USHORT i = rSrtBox.Count(); i; ) + { + SwFrmFmt *pBoxFmt = rSrtBox[ --i ]->GetFrmFmt(); + if( pBoxFmt->GetProtect().IsCntntProtected() ) + { + pBoxFmt->ResetFmtAttr( RES_PROTECT ); + bChgd = TRUE; + } + } + + if( pUndo ) + { + if( bChgd ) + { + ClearRedo(); + AppendUndo( pUndo ); + } + else + delete pUndo; + } + return bChgd; +} + + +BOOL SwDoc::UnProtectCells( const String& rName ) +{ + BOOL bChgd = FALSE; + SwTableFmt* pFmt = FindTblFmtByName( rName ); + if( pFmt ) + { + bChgd = _UnProtectTblCells( *SwTable::FindTable( pFmt ) ); + if( bChgd ) + SetModified(); + } + + return bChgd; +} + +BOOL SwDoc::UnProtectCells( const SwSelBoxes& rBoxes ) +{ + BOOL bChgd = FALSE; + if( rBoxes.Count() ) + { + SwUndoAttrTbl* pUndo = DoesUndo() + ? new SwUndoAttrTbl( *rBoxes[0]->GetSttNd()->FindTableNode() ) + : 0; + + SvPtrarr aFmts( 16 ), aNewFmts( 16 ); + for( USHORT i = rBoxes.Count(); i; ) + { + SwTableBox* pBox = rBoxes[ --i ]; + SwFrmFmt* pBoxFmt = pBox->GetFrmFmt(); + if( pBoxFmt->GetProtect().IsCntntProtected() ) + { + USHORT 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 = TRUE; + } + } + + if( pUndo ) + { + if( bChgd ) + { + ClearRedo(); + AppendUndo( pUndo ); + } + else + delete pUndo; + } + } + return bChgd; +} + +BOOL SwDoc::UnProtectTbls( const SwPaM& rPam ) +{ + StartUndo(UNDO_EMPTY, NULL); + + BOOL bChgd = FALSE, bHasSel = rPam.HasMark() || + rPam.GetNext() != (SwPaM*)&rPam; + SwFrmFmts& rFmts = *GetTblFrmFmts(); + SwTable* pTbl; + const SwTableNode* pTblNd; + for( USHORT n = rFmts.Count(); n ; ) + if( 0 != (pTbl = SwTable::FindTable( rFmts[ --n ] )) && + 0 != (pTblNd = pTbl->GetTableNode() ) && + pTblNd->GetNodes().IsDocNodes() ) + { + ULONG nTblIdx = pTblNd->GetIndex(); + + // dann ueberpruefe ob Tabelle in der Selection liegt + if( bHasSel ) + { + int bFound = 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 ); + } + + EndUndo(UNDO_EMPTY, NULL); + if( bChgd ) + SetModified(); + + return bChgd; +} + +BOOL SwDoc::HasTblAnyProtection( const SwPosition* pPos, + const String* pTblName, + BOOL* pFullTblProtection ) +{ + BOOL bHasProtection = 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( USHORT i = rSrtBox.Count(); i; ) + { + SwFrmFmt *pBoxFmt = rSrtBox[ --i ]->GetFrmFmt(); + if( pBoxFmt->GetProtect().IsCntntProtected() ) + { + if( !bHasProtection ) + { + bHasProtection = TRUE; + if( !pFullTblProtection ) + break; + *pFullTblProtection = TRUE; + } + } + else if( bHasProtection && pFullTblProtection ) + { + *pFullTblProtection = FALSE; + break; + } + } + } + return bHasProtection; +} + +#ifdef DEL_TABLE_REDLINES +lcl_DelRedlines::lcl_DelRedlines( const SwTableNode& rNd, + BOOL bCheckForOwnRedline ) + : pDoc( (SwDoc*)rNd.GetNodes().GetDoc() ) +{ + pDoc->StartUndo(UNDO_EMPTY, NULL); + const SwRedlineTbl& rTbl = pDoc->GetRedlineTbl(); + if( !pDoc->IsIgnoreRedline() && rTbl.Count() ) + { + BOOL bDelete = 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 = FALSE; + break; + } + } + else + break; + } + } + if( bDelete ) + { + SwPaM aPam(*rNd.EndOfSectionNode(), rNd); + pDoc->AcceptRedline( aPam, true ); + } + } +} +#endif + + |