diff options
Diffstat (limited to 'sw/source/core/undo/untbl.cxx')
-rw-r--r-- | sw/source/core/undo/untbl.cxx | 3269 |
1 files changed, 3269 insertions, 0 deletions
diff --git a/sw/source/core/undo/untbl.cxx b/sw/source/core/undo/untbl.cxx new file mode 100644 index 000000000000..ee16891ab5e1 --- /dev/null +++ b/sw/source/core/undo/untbl.cxx @@ -0,0 +1,3269 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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 <UndoTable.hxx> + +#include <UndoRedline.hxx> +#include <UndoDelete.hxx> +#include <UndoSplitMove.hxx> +#include <UndoCore.hxx> +#include <hintids.hxx> +#include <hints.hxx> +#include <editeng/brkitem.hxx> +#include <fmtornt.hxx> +#include <fmtpdsc.hxx> +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <editsh.hxx> +#include <docary.hxx> +#include <ndtxt.hxx> +#include <swtable.hxx> +#include <pam.hxx> +#include <cntfrm.hxx> +#include <tblsel.hxx> +#include <swundo.hxx> // fuer die UndoIds +#include <rolbck.hxx> +#include <ddefld.hxx> +#include <tabcol.hxx> +#include <tabfrm.hxx> +#include <rowfrm.hxx> +#include <cellfrm.hxx> +#include <swcache.hxx> +#include <tblafmt.hxx> +#include <poolfmt.hxx> +#include <mvsave.hxx> +#include <cellatr.hxx> +#include <swtblfmt.hxx> +#include <swddetbl.hxx> +#include <redline.hxx> +#include <node2lay.hxx> +#include <tblrwcl.hxx> +#include <fmtanchr.hxx> +#include <comcore.hrc> +#include <unochart.hxx> +#include <switerator.hxx> + +#if OSL_DEBUG_LEVEL > 1 +#define CHECK_TABLE(t) (t).CheckConsistency(); +#else +#define CHECK_TABLE(t) +#endif + +#if OSL_DEBUG_LEVEL > 1 + void lcl_DebugRedline( const SwDoc* pDoc ); + #define _DEBUG_REDLINE( pDoc ) lcl_DebugRedline( pDoc ); +#else + #define _DEBUG_REDLINE( pDoc ) +#endif + +extern void ClearFEShellTabCols(); + +typedef SfxItemSet* SfxItemSetPtr; +SV_DECL_PTRARR_DEL( SfxItemSets, SfxItemSetPtr, 10, 5 ) + +typedef SwUndoSaveSection* SwUndoSaveSectionPtr; +SV_DECL_PTRARR_DEL( SwUndoSaveSections, SwUndoSaveSectionPtr, 0, 10 ) + +typedef SwUndoMove* SwUndoMovePtr; +SV_DECL_PTRARR_DEL( SwUndoMoves, SwUndoMovePtr, 0, 10 ) + +struct SwTblToTxtSave; +typedef SwTblToTxtSave* SwTblToTxtSavePtr; +SV_DECL_PTRARR_DEL( SwTblToTxtSaves, SwTblToTxtSavePtr, 0, 10 ) + +struct _UndoTblCpyTbl_Entry +{ + sal_uLong nBoxIdx, nOffset; + SfxItemSet* pBoxNumAttr; + SwUndo* pUndo; + + // Was the last paragraph of the new and the first paragraph of the old content joined? + bool bJoin; // For redlining only + + _UndoTblCpyTbl_Entry( const SwTableBox& rBox ); + ~_UndoTblCpyTbl_Entry(); +}; +typedef _UndoTblCpyTbl_Entry* _UndoTblCpyTbl_EntryPtr; +SV_DECL_PTRARR_DEL( _UndoTblCpyTbl_Entries, _UndoTblCpyTbl_EntryPtr, 0, 10 ) + +class _SaveBox; +class _SaveLine; + +class _SaveTable +{ + friend class _SaveBox; + friend class _SaveLine; + SfxItemSet aTblSet; + _SaveLine* pLine; + const SwTable* pSwTable; + SfxItemSets aSets; + SwFrmFmts aFrmFmts; + sal_uInt16 nLineCount; + sal_Bool bModifyBox : 1; + sal_Bool bSaveFormula : 1; + sal_Bool bNewModel : 1; + +public: + _SaveTable( const SwTable& rTbl, sal_uInt16 nLnCnt = USHRT_MAX, + sal_Bool bSaveFml = sal_True ); + ~_SaveTable(); + + sal_uInt16 AddFmt( SwFrmFmt* pFmt, bool bIsLine ); + void NewFrmFmt( const SwTableLine* , const SwTableBox*, sal_uInt16 nFmtPos, + SwFrmFmt* pOldFmt ); + + void RestoreAttr( SwTable& rTbl, sal_Bool bModifyBox = sal_False ); + void SaveCntntAttrs( SwDoc* pDoc ); + void CreateNew( SwTable& rTbl, sal_Bool bCreateFrms = sal_True, + sal_Bool bRestoreChart = sal_True ); + sal_Bool IsNewModel() const { return bNewModel; } +}; + +class _SaveLine +{ + friend class _SaveTable; + friend class _SaveBox; + + _SaveLine* pNext; + _SaveBox* pBox; + sal_uInt16 nItemSet; + +public: + + _SaveLine( _SaveLine* pPrev, const SwTableLine& rLine, _SaveTable& rSTbl ); + ~_SaveLine(); + + void RestoreAttr( SwTableLine& rLine, _SaveTable& rSTbl ); + void SaveCntntAttrs( SwDoc* pDoc ); + + void CreateNew( SwTable& rTbl, SwTableBox& rParent, _SaveTable& rSTbl ); +}; + +class _SaveBox +{ + friend class _SaveLine; + + _SaveBox* pNext; + sal_uLong nSttNode; + long nRowSpan; + sal_uInt16 nItemSet; + union + { + SfxItemSets* pCntntAttrs; + _SaveLine* pLine; + } Ptrs; + +public: + _SaveBox( _SaveBox* pPrev, const SwTableBox& rBox, _SaveTable& rSTbl ); + ~_SaveBox(); + + void RestoreAttr( SwTableBox& rBox, _SaveTable& rSTbl ); + void SaveCntntAttrs( SwDoc* pDoc ); + + void CreateNew( SwTable& rTbl, SwTableLine& rParent, _SaveTable& rSTbl ); +}; + +void InsertSort( SvUShorts& rArr, sal_uInt16 nIdx, sal_uInt16* pInsPos = 0 ); +void InsertSort( SvULongs& rArr, sal_uLong nIdx, sal_uInt16* pInsPos = 0 ); + +#if OSL_DEBUG_LEVEL > 1 +#include "shellio.hxx" +void CheckTable( const SwTable& ); +#define CHECKTABLE(t) CheckTable( t ); +#else +#define CHECKTABLE(t) +#endif + +/* #130880: Crash in undo of table to text when the table has (freshly) merged cells +The order of cell content nodes in the nodes array is not given by the recursive table structure. +The algorithmn must not rely on this even it holds for a fresh loaded table in odt file format. +So we need to remember not only the start node position but the end node position as well. +*/ + +struct SwTblToTxtSave +{ + sal_uLong m_nSttNd; + sal_uLong m_nEndNd; + xub_StrLen m_nCntnt; + SwHistory* m_pHstry; + // metadata references for first and last paragraph in cell + ::boost::shared_ptr< ::sfx2::MetadatableUndo > m_pMetadataUndoStart; + ::boost::shared_ptr< ::sfx2::MetadatableUndo > m_pMetadataUndoEnd; + + SwTblToTxtSave( SwDoc& rDoc, sal_uLong nNd, sal_uLong nEndIdx, xub_StrLen nCntnt ); + ~SwTblToTxtSave() { delete m_pHstry; } +}; + +SV_IMPL_PTRARR( SfxItemSets, SfxItemSetPtr ) +SV_IMPL_PTRARR( SwUndoSaveSections, SwUndoSaveSectionPtr ) +SV_IMPL_PTRARR( SwUndoMoves, SwUndoMovePtr ) +SV_IMPL_PTRARR( SwTblToTxtSaves, SwTblToTxtSavePtr ) +SV_IMPL_PTRARR( _UndoTblCpyTbl_Entries, _UndoTblCpyTbl_EntryPtr ) + +sal_uInt16 aSave_BoxCntntSet[] = { + RES_CHRATR_COLOR, RES_CHRATR_CROSSEDOUT, + RES_CHRATR_FONT, RES_CHRATR_FONTSIZE, + RES_CHRATR_POSTURE, RES_CHRATR_POSTURE, + RES_CHRATR_SHADOWED, RES_CHRATR_WEIGHT, + RES_PARATR_ADJUST, RES_PARATR_ADJUST, + 0 }; + + + +SwUndoInsTbl::SwUndoInsTbl( const SwPosition& rPos, sal_uInt16 nCl, sal_uInt16 nRw, + sal_uInt16 nAdj, const SwInsertTableOptions& rInsTblOpts, + const SwTableAutoFmt* pTAFmt, + const SvUShorts* pColArr, + const String & rName) + : SwUndo( UNDO_INSTABLE ), + aInsTblOpts( rInsTblOpts ), pDDEFldType( 0 ), pColWidth( 0 ), pRedlData( 0 ), pAutoFmt( 0 ), + nSttNode( rPos.nNode.GetIndex() ), nRows( nRw ), nCols( nCl ), nAdjust( nAdj ) +{ + if( pColArr ) + { + pColWidth = new SvUShorts( 0, 1 ); + pColWidth->Insert( pColArr, 0 ); + } + if( pTAFmt ) + pAutoFmt = new SwTableAutoFmt( *pTAFmt ); + + // Redline beachten + SwDoc& rDoc = *rPos.nNode.GetNode().GetDoc(); + if( rDoc.IsRedlineOn() ) + { + pRedlData = new SwRedlineData( nsRedlineType_t::REDLINE_INSERT, rDoc.GetRedlineAuthor() ); + SetRedlineMode( rDoc.GetRedlineMode() ); + } + + sTblNm = rName; +} + + +SwUndoInsTbl::~SwUndoInsTbl() +{ + delete pDDEFldType; + delete pColWidth; + delete pRedlData; + delete pAutoFmt; +} + +void SwUndoInsTbl::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + SwNodeIndex aIdx( rDoc.GetNodes(), nSttNode ); + + SwTableNode* pTblNd = aIdx.GetNode().GetTableNode(); + OSL_ENSURE( pTblNd, "kein TabellenNode" ); + pTblNd->DelFrms(); + + if( IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() )) + rDoc.DeleteRedline( *pTblNd, true, USHRT_MAX ); + RemoveIdxFromSection( rDoc, nSttNode ); + + // harte SeitenUmbrueche am nachfolgenden Node verschieben + SwCntntNode* pNextNd = rDoc.GetNodes()[ pTblNd->EndOfSectionIndex()+1 ]->GetCntntNode(); + if( pNextNd ) + { + SwFrmFmt* pTableFmt = pTblNd->GetTable().GetFrmFmt(); + const SfxPoolItem *pItem; + + if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_PAGEDESC, + sal_False, &pItem ) ) + pNextNd->SetAttr( *pItem ); + + if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_BREAK, + sal_False, &pItem ) ) + pNextNd->SetAttr( *pItem ); + } + + + sTblNm = pTblNd->GetTable().GetFrmFmt()->GetName(); + if( pTblNd->GetTable().IsA( TYPE( SwDDETable )) ) + pDDEFldType = (SwDDEFieldType*)((SwDDETable&)pTblNd->GetTable()). + GetDDEFldType()->Copy(); + + rDoc.GetNodes().Delete( aIdx, pTblNd->EndOfSectionIndex() - + aIdx.GetIndex() + 1 ); + + SwPaM & rPam( rContext.GetCursorSupplier().CreateNewShellCursor() ); + rPam.DeleteMark(); + rPam.GetPoint()->nNode = aIdx; + rPam.GetPoint()->nContent.Assign( rPam.GetCntntNode(), 0 ); +} + + +void SwUndoInsTbl::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + + SwPosition const aPos(SwNodeIndex(rDoc.GetNodes(), nSttNode)); + const SwTable* pTbl = rDoc.InsertTable( aInsTblOpts, aPos, nRows, nCols, + nAdjust, + pAutoFmt, pColWidth ); + ((SwFrmFmt*)pTbl->GetFrmFmt())->SetName( sTblNm ); + SwTableNode* pTblNode = (SwTableNode*)rDoc.GetNodes()[nSttNode]->GetTableNode(); + + if( pDDEFldType ) + { + SwDDEFieldType* pNewType = (SwDDEFieldType*)rDoc.InsertFldType( + *pDDEFldType); + SwDDETable* pDDETbl = new SwDDETable( pTblNode->GetTable(), pNewType ); + pTblNode->SetNewTable( pDDETbl ); // setze die DDE-Tabelle + delete pDDEFldType, pDDEFldType = 0; + } + + if( (pRedlData && IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() )) || + ( !( nsRedlineMode_t::REDLINE_IGNORE & GetRedlineMode() ) && + rDoc.GetRedlineTbl().Count() )) + { + SwPaM aPam( *pTblNode->EndOfSectionNode(), *pTblNode, 1 ); + SwCntntNode* pCNd = aPam.GetCntntNode( sal_False ); + if( pCNd ) + aPam.GetMark()->nContent.Assign( pCNd, 0 ); + + if( pRedlData && IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() ) ) + { + RedlineMode_t eOld = rDoc.GetRedlineMode(); + rDoc.SetRedlineMode_intern((RedlineMode_t)(eOld & ~nsRedlineMode_t::REDLINE_IGNORE)); + + rDoc.AppendRedline( new SwRedline( *pRedlData, aPam ), true); + rDoc.SetRedlineMode_intern( eOld ); + } + else + rDoc.SplitRedline( aPam ); + } +} + + +void SwUndoInsTbl::RepeatImpl(::sw::RepeatContext & rContext) +{ + rContext.GetDoc().InsertTable( + aInsTblOpts, *rContext.GetRepeatPaM().GetPoint(), + nRows, nCols, nAdjust, pAutoFmt, pColWidth ); +} + +SwRewriter SwUndoInsTbl::GetRewriter() const +{ + SwRewriter aRewriter; + + aRewriter.AddRule(UNDO_ARG1, SW_RES(STR_START_QUOTE)); + aRewriter.AddRule(UNDO_ARG2, sTblNm); + aRewriter.AddRule(UNDO_ARG3, SW_RES(STR_END_QUOTE)); + + return aRewriter; +} + +// ----------------------------------------------------- + +SwTblToTxtSave::SwTblToTxtSave( SwDoc& rDoc, sal_uLong nNd, sal_uLong nEndIdx, xub_StrLen nCnt ) + : m_nSttNd( nNd ), m_nEndNd( nEndIdx), m_nCntnt( nCnt ), m_pHstry( 0 ) +{ + // Attributierung des gejointen Node merken. + SwTxtNode* pNd = rDoc.GetNodes()[ nNd ]->GetTxtNode(); + if( pNd ) + { + m_pHstry = new SwHistory; + + m_pHstry->Add( pNd->GetTxtColl(), nNd, ND_TEXTNODE ); + if ( pNd->GetpSwpHints() ) + { + m_pHstry->CopyAttr( pNd->GetpSwpHints(), nNd, 0, + pNd->GetTxt().Len(), false ); + } + if( pNd->HasSwAttrSet() ) + m_pHstry->CopyFmtAttr( *pNd->GetpSwAttrSet(), nNd ); + + if( !m_pHstry->Count() ) + delete m_pHstry, m_pHstry = 0; + + // METADATA: store + m_pMetadataUndoStart = pNd->CreateUndo(); + } + + // we also need to store the metadata reference of the _last_ paragraph + // we subtract 1 to account for the removed cell start/end node pair + // (after SectionUp, the end of the range points to the node after the cell) + if ( nEndIdx - 1 > nNd ) + { + SwTxtNode* pLastNode( rDoc.GetNodes()[ nEndIdx - 1 ]->GetTxtNode() ); + if( pLastNode ) + { + // METADATA: store + m_pMetadataUndoEnd = pLastNode->CreateUndo(); + } + } +} + +SwUndoTblToTxt::SwUndoTblToTxt( const SwTable& rTbl, sal_Unicode cCh ) + : SwUndo( UNDO_TABLETOTEXT ), + sTblNm( rTbl.GetFrmFmt()->GetName() ), pDDEFldType( 0 ), pHistory( 0 ), + nSttNd( 0 ), nEndNd( 0 ), + nAdjust( static_cast<sal_uInt16>(rTbl.GetFrmFmt()->GetHoriOrient().GetHoriOrient()) ), + cTrenner( cCh ), nHdlnRpt( rTbl.GetRowsToRepeat() ) +{ + pTblSave = new _SaveTable( rTbl ); + pBoxSaves = new SwTblToTxtSaves( (sal_uInt8)rTbl.GetTabSortBoxes().Count() ); + + if( rTbl.IsA( TYPE( SwDDETable ) ) ) + pDDEFldType = (SwDDEFieldType*)((SwDDETable&)rTbl).GetDDEFldType()->Copy(); + + bCheckNumFmt = rTbl.GetFrmFmt()->GetDoc()->IsInsTblFormatNum(); + + pHistory = new SwHistory; + const SwTableNode* pTblNd = rTbl.GetTableNode(); + sal_uLong nTblStt = pTblNd->GetIndex(), nTblEnd = pTblNd->EndOfSectionIndex(); + + const SwSpzFrmFmts& rFrmFmtTbl = *pTblNd->GetDoc()->GetSpzFrmFmts(); + for( sal_uInt16 n = 0; n < rFrmFmtTbl.Count(); ++n ) + { + SwFrmFmt* pFmt = rFrmFmtTbl[ n ]; + SwFmtAnchor const*const pAnchor = &pFmt->GetAnchor(); + SwPosition const*const pAPos = pAnchor->GetCntntAnchor(); + if (pAPos && + ((FLY_AT_CHAR == pAnchor->GetAnchorId()) || + (FLY_AT_PARA == pAnchor->GetAnchorId())) && + nTblStt <= pAPos->nNode.GetIndex() && + pAPos->nNode.GetIndex() < nTblEnd ) + { + pHistory->Add( *pFmt ); + } + } + + if( !pHistory->Count() ) + delete pHistory, pHistory = 0; +} + + +SwUndoTblToTxt::~SwUndoTblToTxt() +{ + delete pDDEFldType; + delete pTblSave; + delete pBoxSaves; + delete pHistory; +} + + + +void SwUndoTblToTxt::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor()); + + SwNodeIndex aFrmIdx( rDoc.GetNodes(), nSttNd ); + SwNodeIndex aEndIdx( rDoc.GetNodes(), nEndNd ); + + pPam->GetPoint()->nNode = aFrmIdx; + pPam->SetMark(); + pPam->GetPoint()->nNode = aEndIdx; + rDoc.DelNumRules( *pPam ); + pPam->DeleteMark(); + + // dann sammel mal alle Uppers ein + SwNode2Layout aNode2Layout( aFrmIdx.GetNode() ); + + // erzeuge die TabelleNode Structur + SwTableNode* pTblNd = rDoc.GetNodes().UndoTableToText( nSttNd, nEndNd, *pBoxSaves ); + pTblNd->GetTable().SetTableModel( pTblSave->IsNewModel() ); + SwTableFmt* pTableFmt = rDoc.MakeTblFrmFmt( sTblNm, rDoc.GetDfltFrmFmt() ); + pTblNd->GetTable().RegisterToFormat( *pTableFmt ); + pTblNd->GetTable().SetRowsToRepeat( nHdlnRpt ); + + // erzeuge die alte Tabellen Struktur + pTblSave->CreateNew( pTblNd->GetTable() ); + + if( pDDEFldType ) + { + SwDDEFieldType* pNewType = (SwDDEFieldType*)rDoc.InsertFldType( + *pDDEFldType); + SwDDETable* pDDETbl = new SwDDETable( pTblNd->GetTable(), pNewType ); + pTblNd->SetNewTable( pDDETbl, sal_False ); // setze die DDE-Tabelle + delete pDDEFldType, pDDEFldType = 0; + } + + if( bCheckNumFmt ) + { + SwTableSortBoxes& rBxs = pTblNd->GetTable().GetTabSortBoxes(); + for( sal_uInt16 nBoxes = rBxs.Count(); nBoxes; ) + rDoc.ChkBoxNumFmt( *rBxs[ --nBoxes ], sal_False ); + } + + if( pHistory ) + { + sal_uInt16 nTmpEnd = pHistory->GetTmpEnd(); + pHistory->TmpRollback( &rDoc, 0 ); + pHistory->SetTmpEnd( nTmpEnd ); + } + + aNode2Layout.RestoreUpperFrms( rDoc.GetNodes(), + pTblNd->GetIndex(), pTblNd->GetIndex()+1 ); + + // will man eine TabellenSelektion ?? + pPam->DeleteMark(); + pPam->GetPoint()->nNode = *pTblNd->EndOfSectionNode(); + pPam->SetMark(); + pPam->GetPoint()->nNode = *pPam->GetNode()->StartOfSectionNode(); + pPam->Move( fnMoveForward, fnGoCntnt ); + pPam->Exchange(); + pPam->Move( fnMoveBackward, fnGoCntnt ); + + ClearFEShellTabCols(); +} + + // steht im untbl.cxx und darf nur vom Undoobject gerufen werden +SwTableNode* SwNodes::UndoTableToText( sal_uLong nSttNd, sal_uLong nEndNd, + const SwTblToTxtSaves& rSavedData ) +{ + SwNodeIndex aSttIdx( *this, nSttNd ); + SwNodeIndex aEndIdx( *this, nEndNd+1 ); + + SwTableNode * pTblNd = new SwTableNode( aSttIdx ); + SwEndNode* pEndNd = new SwEndNode( aEndIdx, *pTblNd ); + + aEndIdx = *pEndNd; + + /* Set pTblNd as start of section for all nodes in [nSttNd, nEndNd]. + Delete all Frames attached to the nodes in that range. */ + SwNode* pNd; + { + sal_uLong n, nTmpEnd = aEndIdx.GetIndex(); + for( n = pTblNd->GetIndex() + 1; n < nTmpEnd; ++n ) + { + if( ( pNd = (*this)[ n ] )->IsCntntNode() ) + ((SwCntntNode*)pNd)->DelFrms(); + pNd->pStartOfSection = pTblNd; + } + } + + // dann die Tabellen Struktur teilweise aufbauen. Erstmal eine Line + // in der alle Boxen stehen! Die korrekte Struktur kommt dann aus der + // SaveStruct + SwTableBoxFmt* pBoxFmt = GetDoc()->MakeTableBoxFmt(); + SwTableLineFmt* pLineFmt = GetDoc()->MakeTableLineFmt(); + SwTableLine* pLine = new SwTableLine( pLineFmt, rSavedData.Count(), 0 ); + pTblNd->GetTable().GetTabLines().C40_INSERT( SwTableLine, pLine, 0 ); + + SvULongs aBkmkArr( 0, 4 ); + for( sal_uInt16 n = rSavedData.Count(); n; ) + { + SwTblToTxtSave* pSave = rSavedData[ --n ]; + // if the start node was merged with last from prev. cell, + // subtract 1 from index to get the merged paragraph, and split that + aSttIdx = pSave->m_nSttNd - ( ( USHRT_MAX != pSave->m_nCntnt ) ? 1 : 0); + SwTxtNode* pTxtNd = aSttIdx.GetNode().GetTxtNode(); + + if( USHRT_MAX != pSave->m_nCntnt ) + { + // an der ContentPosition splitten, das vorherige Zeichen + // loeschen (ist der Trenner!) + OSL_ENSURE( pTxtNd, "Wo ist der TextNode geblieben?" ); + SwIndex aCntPos( pTxtNd, pSave->m_nCntnt - 1 ); + + pTxtNd->EraseText( aCntPos, 1 ); + SwCntntNode* pNewNd = pTxtNd->SplitCntntNode( + SwPosition( aSttIdx, aCntPos )); + if( aBkmkArr.Count() ) + _RestoreCntntIdx( aBkmkArr, *pNewNd, pSave->m_nCntnt, + pSave->m_nCntnt + 1 ); + } + else + { + if( aBkmkArr.Count() ) + aBkmkArr.Remove( 0, aBkmkArr.Count() ); + if( pTxtNd ) + _SaveCntntIdx( GetDoc(), aSttIdx.GetIndex(), + pTxtNd->GetTxt().Len(), aBkmkArr ); + } + + if( pTxtNd ) + { + // METADATA: restore + pTxtNd->GetTxtNode()->RestoreMetadata(pSave->m_pMetadataUndoStart); + if( pTxtNd->HasSwAttrSet() ) + pTxtNd->ResetAllAttr(); + + if( pTxtNd->GetpSwpHints() ) + pTxtNd->ClearSwpHintsArr( false ); + } + + if( pSave->m_pHstry ) + { + sal_uInt16 nTmpEnd = pSave->m_pHstry->GetTmpEnd(); + pSave->m_pHstry->TmpRollback( GetDoc(), 0 ); + pSave->m_pHstry->SetTmpEnd( nTmpEnd ); + } + + // METADATA: restore + // end points to node after cell + if ( pSave->m_nEndNd - 1 > pSave->m_nSttNd ) + { + SwTxtNode* pLastNode = (*this)[ pSave->m_nEndNd - 1 ]->GetTxtNode(); + if (pLastNode) + { + pLastNode->RestoreMetadata(pSave->m_pMetadataUndoEnd); + } + } + + aEndIdx = pSave->m_nEndNd; + SwStartNode* pSttNd = new SwStartNode( aSttIdx, ND_STARTNODE, + SwTableBoxStartNode ); + pSttNd->pStartOfSection = pTblNd; + new SwEndNode( aEndIdx, *pSttNd ); + + for( sal_uLong i = aSttIdx.GetIndex(); i < aEndIdx.GetIndex()-1; ++i ) + { + pNd = (*this)[ i ]; + pNd->pStartOfSection = pSttNd; + if( pNd->IsStartNode() ) + i = pNd->EndOfSectionIndex(); + } + + SwTableBox* pBox = new SwTableBox( pBoxFmt, *pSttNd, pLine ); + pLine->GetTabBoxes().C40_INSERT( SwTableBox, pBox, 0 ); + } + return pTblNd; +} + + +void SwUndoTblToTxt::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor()); + + pPam->GetPoint()->nNode = nSttNd; + pPam->GetPoint()->nContent.Assign( 0, 0 ); + SwNodeIndex aSaveIdx( pPam->GetPoint()->nNode, -1 ); + + pPam->SetMark(); // alle Indizies abmelden + pPam->DeleteMark(); + + SwTableNode* pTblNd = pPam->GetNode()->GetTableNode(); + OSL_ENSURE( pTblNd, "keinen TableNode gefunden" ); + + if( pTblNd->GetTable().IsA( TYPE( SwDDETable )) ) + pDDEFldType = (SwDDEFieldType*)((SwDDETable&)pTblNd->GetTable()). + GetDDEFldType()->Copy(); + + rDoc.TableToText( pTblNd, cTrenner ); + + aSaveIdx++; + SwCntntNode* pCNd = aSaveIdx.GetNode().GetCntntNode(); + if( !pCNd && 0 == ( pCNd = rDoc.GetNodes().GoNext( &aSaveIdx ) ) && + 0 == ( pCNd = rDoc.GetNodes().GoPrevious( &aSaveIdx )) ) + { + OSL_FAIL( "wo steht denn nun der TextNode" ); + } + + pPam->GetPoint()->nNode = aSaveIdx; + pPam->GetPoint()->nContent.Assign( pCNd, 0 ); + + pPam->SetMark(); // alle Indizies abmelden + pPam->DeleteMark(); +} + + +void SwUndoTblToTxt::RepeatImpl(::sw::RepeatContext & rContext) +{ + SwPaM *const pPam = & rContext.GetRepeatPaM(); + SwTableNode *const pTblNd = pPam->GetNode()->FindTableNode(); + if( pTblNd ) + { + // move cursor out of table + pPam->GetPoint()->nNode = *pTblNd->EndOfSectionNode(); + pPam->Move( fnMoveForward, fnGoCntnt ); + pPam->SetMark(); + pPam->DeleteMark(); + + rContext.GetDoc().TableToText( pTblNd, cTrenner ); + } +} + +void SwUndoTblToTxt::SetRange( const SwNodeRange& rRg ) +{ + nSttNd = rRg.aStart.GetIndex(); + nEndNd = rRg.aEnd.GetIndex(); +} + +void SwUndoTblToTxt::AddBoxPos( SwDoc& rDoc, sal_uLong nNdIdx, sal_uLong nEndIdx, xub_StrLen nCntntIdx ) +{ + SwTblToTxtSave* pNew = new SwTblToTxtSave( rDoc, nNdIdx, nEndIdx, nCntntIdx ); + pBoxSaves->Insert( pNew, pBoxSaves->Count() ); +} + +// ----------------------------------------------------- + +SwUndoTxtToTbl::SwUndoTxtToTbl( const SwPaM& rRg, + const SwInsertTableOptions& rInsTblOpts, + sal_Unicode cCh, sal_uInt16 nAdj, + const SwTableAutoFmt* pAFmt ) + : SwUndo( UNDO_TEXTTOTABLE ), SwUndRng( rRg ), aInsTblOpts( rInsTblOpts ), + pDelBoxes( 0 ), pAutoFmt( 0 ), + pHistory( 0 ), cTrenner( cCh ), nAdjust( nAdj ) +{ + if( pAFmt ) + pAutoFmt = new SwTableAutoFmt( *pAFmt ); + + const SwPosition* pEnd = rRg.End(); + SwNodes& rNds = rRg.GetDoc()->GetNodes(); + bSplitEnd = pEnd->nContent.GetIndex() && ( pEnd->nContent.GetIndex() + != pEnd->nNode.GetNode().GetCntntNode()->Len() || + pEnd->nNode.GetIndex() >= rNds.GetEndOfContent().GetIndex()-1 ); +} + +SwUndoTxtToTbl::~SwUndoTxtToTbl() +{ + delete pDelBoxes; + delete pAutoFmt; +} + +void SwUndoTxtToTbl::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + + sal_uLong nTblNd = nSttNode; + if( nSttCntnt ) + ++nTblNd; // Node wurde vorher gesplittet + SwNodeIndex aIdx( rDoc.GetNodes(), nTblNd ); + SwTableNode *const pTNd = aIdx.GetNode().GetTableNode(); + OSL_ENSURE( pTNd, "keinen Tabellen-Node gefunden" ); + + RemoveIdxFromSection( rDoc, nTblNd ); + + sTblNm = pTNd->GetTable().GetFrmFmt()->GetName(); + + if( pHistory ) + { + pHistory->TmpRollback( &rDoc, 0 ); + pHistory->SetTmpEnd( pHistory->Count() ); + } + + if( pDelBoxes ) + { + SwTable& rTbl = pTNd->GetTable(); + for( sal_uInt16 n = pDelBoxes->Count(); n; ) + { + SwTableBox* pBox = rTbl.GetTblBox( (*pDelBoxes)[ --n ] ); + if( pBox ) + ::_DeleteBox( rTbl, pBox, 0, sal_False, sal_False ); + else { + OSL_ENSURE( !this, "Wo ist die Box geblieben?" ); + } + } + } + + SwNodeIndex aEndIdx( *pTNd->EndOfSectionNode() ); + rDoc.TableToText( pTNd, 0x0b == cTrenner ? 0x09 : cTrenner ); + + // join again at start? + SwPaM aPam(rDoc.GetNodes().GetEndOfContent()); + SwPosition *const pPos = aPam.GetPoint(); + if( nSttCntnt ) + { + pPos->nNode = nTblNd; + pPos->nContent.Assign(pPos->nNode.GetNode().GetCntntNode(), 0); + if (aPam.Move(fnMoveBackward, fnGoCntnt)) + { + SwNodeIndex & rIdx = aPam.GetPoint()->nNode; + + // dann die Crsr/etc. nochmal relativ verschieben + RemoveIdxRel( rIdx.GetIndex()+1, *pPos ); + + rIdx.GetNode().GetCntntNode()->JoinNext(); + } + } + + // join again at end? + if( bSplitEnd ) + { + SwNodeIndex& rIdx = pPos->nNode; + rIdx = nEndNode; + SwTxtNode* pTxtNd = rIdx.GetNode().GetTxtNode(); + if( pTxtNd && pTxtNd->CanJoinNext() ) + { + aPam.GetMark()->nContent.Assign( 0, 0 ); + aPam.GetPoint()->nContent.Assign( 0, 0 ); + + // dann die Crsr/etc. nochmal relativ verschieben + pPos->nContent.Assign( pTxtNd, pTxtNd->GetTxt().Len() ); + RemoveIdxRel( nEndNode + 1, *pPos ); + + pTxtNd->JoinNext(); + } + } + + AddUndoRedoPaM(rContext); +} + + +void SwUndoTxtToTbl::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwPaM & rPam( AddUndoRedoPaM(rContext) ); + RemoveIdxFromRange(rPam, false); + SetPaM(rPam); + + SwTable const*const pTable = rContext.GetDoc().TextToTable( + aInsTblOpts, rPam, cTrenner, nAdjust, pAutoFmt ); + ((SwFrmFmt*)pTable->GetFrmFmt())->SetName( sTblNm ); +} + + +void SwUndoTxtToTbl::RepeatImpl(::sw::RepeatContext & rContext) +{ + // no Table In Table + if (!rContext.GetRepeatPaM().GetNode()->FindTableNode()) + { + rContext.GetDoc().TextToTable( aInsTblOpts, rContext.GetRepeatPaM(), + cTrenner, nAdjust, + pAutoFmt ); + } +} + +void SwUndoTxtToTbl::AddFillBox( const SwTableBox& rBox ) +{ + if( !pDelBoxes ) + pDelBoxes = new SvULongs; + pDelBoxes->Insert( rBox.GetSttIdx(), pDelBoxes->Count() ); +} + +SwHistory& SwUndoTxtToTbl::GetHistory() +{ + if( !pHistory ) + pHistory = new SwHistory; + return *pHistory; +} + +// ----------------------------------------------------- + +SwUndoTblHeadline::SwUndoTblHeadline( const SwTable& rTbl, sal_uInt16 nOldHdl, + sal_uInt16 nNewHdl ) + : SwUndo( UNDO_TABLEHEADLINE ), + nOldHeadline( nOldHdl ), + nNewHeadline( nNewHdl ) +{ + OSL_ENSURE( rTbl.GetTabSortBoxes().Count(), "Tabelle ohne Inhalt" ); + const SwStartNode *pSttNd = rTbl.GetTabSortBoxes()[ 0 ]->GetSttNd(); + OSL_ENSURE( pSttNd, "Box ohne Inhalt" ); + + nTblNd = pSttNd->StartOfSectionIndex(); +} + +void SwUndoTblHeadline::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + SwTableNode* pTNd = rDoc.GetNodes()[ nTblNd ]->GetTableNode(); + OSL_ENSURE( pTNd, "keinen Tabellen-Node gefunden" ); + + rDoc.SetRowsToRepeat( pTNd->GetTable(), nOldHeadline ); +} + +void SwUndoTblHeadline::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + + SwTableNode* pTNd = rDoc.GetNodes()[ nTblNd ]->GetTableNode(); + OSL_ENSURE( pTNd, "keinen Tabellen-Node gefunden" ); + + rDoc.SetRowsToRepeat( pTNd->GetTable(), nNewHeadline ); +} + +void SwUndoTblHeadline::RepeatImpl(::sw::RepeatContext & rContext) +{ + SwTableNode *const pTblNd = + rContext.GetRepeatPaM().GetNode()->FindTableNode(); + if( pTblNd ) + { + rContext.GetDoc().SetRowsToRepeat( pTblNd->GetTable(), nNewHeadline ); + } +} + + +////////////////////////////////////////////////////////////////////////// + + +_SaveTable::_SaveTable( const SwTable& rTbl, sal_uInt16 nLnCnt, sal_Bool bSaveFml ) + : aTblSet( *rTbl.GetFrmFmt()->GetAttrSet().GetPool(), aTableSetRange ), + pSwTable( &rTbl ), nLineCount( nLnCnt ), bSaveFormula( bSaveFml ) +{ + bModifyBox = sal_False; + bNewModel = rTbl.IsNewModel(); + aTblSet.Put( rTbl.GetFrmFmt()->GetAttrSet() ); + pLine = new _SaveLine( 0, *rTbl.GetTabLines()[ 0 ], *this ); + + _SaveLine* pLn = pLine; + if( USHRT_MAX == nLnCnt ) + nLnCnt = rTbl.GetTabLines().Count(); + for( sal_uInt16 n = 1; n < nLnCnt; ++n ) + pLn = new _SaveLine( pLn, *rTbl.GetTabLines()[ n ], *this ); + + aFrmFmts.Remove( 0, aFrmFmts.Count() ); + pSwTable = 0; +} + + +_SaveTable::~_SaveTable() +{ + delete pLine; +} + + +sal_uInt16 _SaveTable::AddFmt( SwFrmFmt* pFmt, bool bIsLine ) +{ + sal_uInt16 nRet = aFrmFmts.GetPos( pFmt ); + if( USHRT_MAX == nRet ) + { + // Kopie vom ItemSet anlegen + SfxItemSet* pSet = new SfxItemSet( *pFmt->GetAttrSet().GetPool(), + bIsLine ? aTableLineSetRange : aTableBoxSetRange ); + pSet->Put( pFmt->GetAttrSet() ); + //JP 20.04.98: Bug 49502 - wenn eine Formel gesetzt ist, nie den + // Value mit sichern. Der muss gegebenfalls neu + // errechnet werden! + //JP 30.07.98: Bug 54295 - Formeln immer im Klartext speichern + const SfxPoolItem* pItem; + if( SFX_ITEM_SET == pSet->GetItemState( RES_BOXATR_FORMULA, sal_True, &pItem )) + { + pSet->ClearItem( RES_BOXATR_VALUE ); + if( pSwTable && bSaveFormula ) + { + SwTableFmlUpdate aMsgHnt( pSwTable ); + aMsgHnt.eFlags = TBL_BOXNAME; + ((SwTblBoxFormula*)pItem)->ChgDefinedIn( pFmt ); + ((SwTblBoxFormula*)pItem)->ChangeState( &aMsgHnt ); + ((SwTblBoxFormula*)pItem)->ChgDefinedIn( 0 ); + } + } + aSets.Insert( pSet, (nRet = aSets.Count() ) ); + aFrmFmts.Insert( pFmt, nRet ); + } + return nRet; +} + + +void _SaveTable::RestoreAttr( SwTable& rTbl, sal_Bool bMdfyBox ) +{ + sal_uInt16 n; + + bModifyBox = bMdfyBox; + + // zuerst die Attribute des TabellenFrmFormates zurueck holen + SwFrmFmt* pFmt = rTbl.GetFrmFmt(); + SfxItemSet& rFmtSet = (SfxItemSet&)pFmt->GetAttrSet(); + rFmtSet.ClearItem(); + rFmtSet.Put( aTblSet ); + + if( pFmt->IsInCache() ) + { + SwFrm::GetCache().Delete( pFmt ); + pFmt->SetInCache( sal_False ); + } + + // zur Sicherheit alle Tableframes invalidieren + SwIterator<SwTabFrm,SwFmt> aIter( *pFmt ); + for( SwTabFrm* pLast = aIter.First(); pLast; pLast = aIter.Next() ) + if( pLast->GetTable() == &rTbl ) + { + pLast->InvalidateAll(); + pLast->SetCompletePaint(); + } + + // FrmFmts mit Defaults (0) fuellen + pFmt = 0; + for( n = aSets.Count(); n; --n ) + aFrmFmts.Insert( pFmt, aFrmFmts.Count() ); + + sal_uInt16 nLnCnt = nLineCount; + if( USHRT_MAX == nLnCnt ) + nLnCnt = rTbl.GetTabLines().Count(); + + _SaveLine* pLn = pLine; + for( n = 0; n < nLnCnt; ++n, pLn = pLn->pNext ) + { + if( !pLn ) + { + OSL_ENSURE( !this, "Anzahl der Lines hat sich veraendert" ); + break; + } + + pLn->RestoreAttr( *rTbl.GetTabLines()[ n ], *this ); + } + + aFrmFmts.Remove( 0, aFrmFmts.Count() ); + bModifyBox = sal_False; +} + + +void _SaveTable::SaveCntntAttrs( SwDoc* pDoc ) +{ + pLine->SaveCntntAttrs( pDoc ); +} + + +void _SaveTable::CreateNew( SwTable& rTbl, sal_Bool bCreateFrms, + sal_Bool bRestoreChart ) +{ + sal_uInt16 n; + + _FndBox aTmpBox( 0, 0 ); + //if( bRestoreChart ) + // // ? TL_CHART2: notification or locking of controller required ? + aTmpBox.DelFrms( rTbl ); + + // zuerst die Attribute des TabellenFrmFormates zurueck holen + SwFrmFmt* pFmt = rTbl.GetFrmFmt(); + SfxItemSet& rFmtSet = (SfxItemSet&)pFmt->GetAttrSet(); + rFmtSet.ClearItem(); + rFmtSet.Put( aTblSet ); + + if( pFmt->IsInCache() ) + { + SwFrm::GetCache().Delete( pFmt ); + pFmt->SetInCache( sal_False ); + } + + // SwTableBox muss ein Format haben!! + SwTableBox aParent( (SwTableBoxFmt*)pFmt, rTbl.GetTabLines().Count(), 0 ); + + // FrmFmts mit Defaults (0) fuellen + pFmt = 0; + for( n = aSets.Count(); n; --n ) + aFrmFmts.Insert( pFmt, aFrmFmts.Count() ); + + pLine->CreateNew( rTbl, aParent, *this ); + aFrmFmts.Remove( 0, aFrmFmts.Count() ); + + // die neuen Lines eintragen, die alten loeschen + sal_uInt16 nOldLines = nLineCount; + if( USHRT_MAX == nLineCount ) + nOldLines = rTbl.GetTabLines().Count(); + + SwDoc *pDoc = rTbl.GetFrmFmt()->GetDoc(); + SwChartDataProvider *pPCD = pDoc->GetChartDataProvider(); + for( n = 0; n < aParent.GetTabLines().Count(); ++n ) + { + SwTableLine* pLn = aParent.GetTabLines()[ n ]; + pLn->SetUpper( 0 ); + if( n < nOldLines ) + { + SwTableLine* pOld = rTbl.GetTabLines()[ n ]; + + // TL_CHART2: notify chart about boxes to be removed + const SwTableBoxes &rBoxes = pOld->GetTabBoxes(); + sal_uInt16 nBoxes = rBoxes.Count(); + for (sal_uInt16 k = 0; k < nBoxes; ++k) + { + SwTableBox *pBox = rBoxes[k]; + if (pPCD) + pPCD->DeleteBox( &rTbl, *pBox ); + } + + rTbl.GetTabLines().C40_REPLACE( SwTableLine, pLn, n ); + delete pOld; + } + else + rTbl.GetTabLines().C40_INSERT( SwTableLine, pLn, n ); + } + + if( n < nOldLines ) + { + // remove remaining lines... + + for (sal_uInt16 k1 = 0; k1 < nOldLines - n; ++k1) + { + const SwTableBoxes &rBoxes = rTbl.GetTabLines()[n + k1]->GetTabBoxes(); + sal_uInt16 nBoxes = rBoxes.Count(); + for (sal_uInt16 k2 = 0; k2 < nBoxes; ++k2) + { + SwTableBox *pBox = rBoxes[k2]; + // TL_CHART2: notify chart about boxes to be removed + if (pPCD) + pPCD->DeleteBox( &rTbl, *pBox ); + } + } + + rTbl.GetTabLines().DeleteAndDestroy( n, nOldLines - n ); + } + + aParent.GetTabLines().Remove( 0, n ); + + if( bCreateFrms ) + aTmpBox.MakeFrms( rTbl ); + if( bRestoreChart ) + { + // TL_CHART2: need to inform chart of probably changed cell names + pDoc->UpdateCharts( rTbl.GetFrmFmt()->GetName() ); + } +} + + +void _SaveTable::NewFrmFmt( const SwTableLine* pTblLn, const SwTableBox* pTblBx, + sal_uInt16 nFmtPos, SwFrmFmt* pOldFmt ) +{ + SwDoc* pDoc = pOldFmt->GetDoc(); + + SwFrmFmt* pFmt = aFrmFmts[ nFmtPos ]; + if( !pFmt ) + { + if( pTblLn ) + pFmt = pDoc->MakeTableLineFmt(); + else + pFmt = pDoc->MakeTableBoxFmt(); + pFmt->SetFmtAttr( *aSets[ nFmtPos ] ); + aFrmFmts.Replace( pFmt, nFmtPos ); + } + + //Erstmal die Frms ummelden. + SwIterator<SwTabFrm,SwFmt> aIter( *pOldFmt ); + for( SwFrm* pLast = aIter.First(); pLast; pLast = aIter.Next() ) + { + if( pTblLn ? ((SwRowFrm*)pLast)->GetTabLine() == pTblLn + : ((SwCellFrm*)pLast)->GetTabBox() == pTblBx ) + { + pLast->RegisterToFormat(*pFmt); + pLast->InvalidateAll(); + pLast->ReinitializeFrmSizeAttrFlags(); + if ( !pTblLn ) + { + ((SwCellFrm*)pLast)->SetDerivedVert( sal_False ); + ((SwCellFrm*)pLast)->CheckDirChange(); + } + } + } + + //Jetzt noch mich selbst ummelden. + if ( pTblLn ) + const_cast<SwTableLine*>(pTblLn)->RegisterToFormat( *pFmt ); + else if ( pTblBx ) + const_cast<SwTableBox*>(pTblBx)->RegisterToFormat( *pFmt ); + + if( bModifyBox && !pTblLn ) + { + const SfxPoolItem& rOld = pOldFmt->GetFmtAttr( RES_BOXATR_FORMAT ), + & rNew = pFmt->GetFmtAttr( RES_BOXATR_FORMAT ); + if( rOld != rNew ) + pFmt->ModifyNotification( (SfxPoolItem*)&rOld, (SfxPoolItem*)&rNew ); + } + + if( !pOldFmt->GetDepends() ) + delete pOldFmt; + +} + + +_SaveLine::_SaveLine( _SaveLine* pPrev, const SwTableLine& rLine, _SaveTable& rSTbl ) + : pNext( 0 ) +{ + if( pPrev ) + pPrev->pNext = this; + + nItemSet = rSTbl.AddFmt( rLine.GetFrmFmt(), true ); + + pBox = new _SaveBox( 0, *rLine.GetTabBoxes()[ 0 ], rSTbl ); + _SaveBox* pBx = pBox; + for( sal_uInt16 n = 1; n < rLine.GetTabBoxes().Count(); ++n ) + pBx = new _SaveBox( pBx, *rLine.GetTabBoxes()[ n ], rSTbl ); +} + + +_SaveLine::~_SaveLine() +{ + delete pBox; + delete pNext; +} + + +void _SaveLine::RestoreAttr( SwTableLine& rLine, _SaveTable& rSTbl ) +{ + rSTbl.NewFrmFmt( &rLine, 0, nItemSet, rLine.GetFrmFmt() ); + + _SaveBox* pBx = pBox; + for( sal_uInt16 n = 0; n < rLine.GetTabBoxes().Count(); ++n, pBx = pBx->pNext ) + { + if( !pBx ) + { + OSL_ENSURE( !this, "Anzahl der Boxen hat sich veraendert" ); + break; + } + pBx->RestoreAttr( *rLine.GetTabBoxes()[ n ], rSTbl ); + } +} + + +void _SaveLine::SaveCntntAttrs( SwDoc* pDoc ) +{ + pBox->SaveCntntAttrs( pDoc ); + if( pNext ) + pNext->SaveCntntAttrs( pDoc ); +} + + +void _SaveLine::CreateNew( SwTable& rTbl, SwTableBox& rParent, _SaveTable& rSTbl ) +{ + SwTableLineFmt* pFmt = (SwTableLineFmt*)rSTbl.aFrmFmts[ nItemSet ]; + if( !pFmt ) + { + SwDoc* pDoc = rTbl.GetFrmFmt()->GetDoc(); + pFmt = pDoc->MakeTableLineFmt(); + pFmt->SetFmtAttr( *rSTbl.aSets[ nItemSet ] ); + rSTbl.aFrmFmts.Replace( pFmt, nItemSet ); + } + SwTableLine* pNew = new SwTableLine( pFmt, 1, &rParent ); + + rParent.GetTabLines().C40_INSERT( SwTableLine, pNew, rParent.GetTabLines().Count() ); + + // HB, #127868# robustness: in some cases - which I + // cannot reproduce nor see from the code - pNew seems + // to be set to NULL in C40_INSERT. + OSL_ENSURE(pNew, "Table line just created set to NULL in C40_INSERT"); + + if (pNew) + { + pBox->CreateNew( rTbl, *pNew, rSTbl ); + } + + if( pNext ) + pNext->CreateNew( rTbl, rParent, rSTbl ); +} + + +_SaveBox::_SaveBox( _SaveBox* pPrev, const SwTableBox& rBox, _SaveTable& rSTbl ) + : pNext( 0 ), nSttNode( ULONG_MAX ), nRowSpan(0) +{ + Ptrs.pLine = 0; + + if( pPrev ) + pPrev->pNext = this; + + nItemSet = rSTbl.AddFmt( rBox.GetFrmFmt(), false ); + + if( rBox.GetSttNd() ) + { + nSttNode = rBox.GetSttIdx(); + nRowSpan = rBox.getRowSpan(); + } + else + { + Ptrs.pLine = new _SaveLine( 0, *rBox.GetTabLines()[ 0 ], rSTbl ); + + _SaveLine* pLn = Ptrs.pLine; + for( sal_uInt16 n = 1; n < rBox.GetTabLines().Count(); ++n ) + pLn = new _SaveLine( pLn, *rBox.GetTabLines()[ n ], rSTbl ); + } +} + + +_SaveBox::~_SaveBox() +{ + if( ULONG_MAX == nSttNode ) // keine EndBox + delete Ptrs.pLine; + else + delete Ptrs.pCntntAttrs; + delete pNext; +} + + +void _SaveBox::RestoreAttr( SwTableBox& rBox, _SaveTable& rSTbl ) +{ + rSTbl.NewFrmFmt( 0, &rBox, nItemSet, rBox.GetFrmFmt() ); + + if( ULONG_MAX == nSttNode ) // keine EndBox + { + if( !rBox.GetTabLines().Count() ) + { + OSL_ENSURE( !this, "Anzahl der Lines hat sich veraendert" ); + } + else + { + _SaveLine* pLn = Ptrs.pLine; + for( sal_uInt16 n = 0; n < rBox.GetTabLines().Count(); ++n, pLn = pLn->pNext ) + { + if( !pLn ) + { + OSL_ENSURE( !this, "Anzahl der Lines hat sich veraendert" ); + break; + } + + pLn->RestoreAttr( *rBox.GetTabLines()[ n ], rSTbl ); + } + } + } + else if( rBox.GetSttNd() && rBox.GetSttIdx() == nSttNode ) + { + if( Ptrs.pCntntAttrs ) + { + SwNodes& rNds = rBox.GetFrmFmt()->GetDoc()->GetNodes(); + sal_uInt16 nSet = 0; + sal_uLong nEnd = rBox.GetSttNd()->EndOfSectionIndex(); + for( sal_uLong n = nSttNode + 1; n < nEnd; ++n ) + { + SwCntntNode* pCNd = rNds[ n ]->GetCntntNode(); + if( pCNd ) + { + SfxItemSet* pSet = (*Ptrs.pCntntAttrs)[ nSet++ ]; + if( pSet ) + { + sal_uInt16 *pRstAttr = aSave_BoxCntntSet; + while( *pRstAttr ) + { + pCNd->ResetAttr( *pRstAttr, *(pRstAttr+1) ); + pRstAttr += 2; + } + pCNd->SetAttr( *pSet ); + } + else + pCNd->ResetAllAttr(); + } + } + } + } + else + { + OSL_ENSURE( !this, "Box nicht mehr am gleichen Node" ); + } +} + + +void _SaveBox::SaveCntntAttrs( SwDoc* pDoc ) +{ + if( ULONG_MAX == nSttNode ) // keine EndBox + { + // weiter in der Line + Ptrs.pLine->SaveCntntAttrs( pDoc ); + } + else + { + sal_uLong nEnd = pDoc->GetNodes()[ nSttNode ]->EndOfSectionIndex(); + Ptrs.pCntntAttrs = new SfxItemSets( (sal_uInt8)(nEnd - nSttNode - 1 ), 5 ); + for( sal_uLong n = nSttNode + 1; n < nEnd; ++n ) + { + SwCntntNode* pCNd = pDoc->GetNodes()[ n ]->GetCntntNode(); + if( pCNd ) + { + SfxItemSet* pSet = 0; + if( pCNd->HasSwAttrSet() ) + { + pSet = new SfxItemSet( pDoc->GetAttrPool(), + aSave_BoxCntntSet ); + pSet->Put( *pCNd->GetpSwAttrSet() ); + } + + Ptrs.pCntntAttrs->Insert( pSet, Ptrs.pCntntAttrs->Count() ); + } + } + } + if( pNext ) + pNext->SaveCntntAttrs( pDoc ); +} + + +void _SaveBox::CreateNew( SwTable& rTbl, SwTableLine& rParent, _SaveTable& rSTbl ) +{ + SwTableBoxFmt* pFmt = (SwTableBoxFmt*)rSTbl.aFrmFmts[ nItemSet ]; + if( !pFmt ) + { + SwDoc* pDoc = rTbl.GetFrmFmt()->GetDoc(); + pFmt = pDoc->MakeTableBoxFmt(); + pFmt->SetFmtAttr( *rSTbl.aSets[ nItemSet ] ); + rSTbl.aFrmFmts.Replace( pFmt, nItemSet ); + } + + if( ULONG_MAX == nSttNode ) // keine EndBox + { + SwTableBox* pNew = new SwTableBox( pFmt, 1, &rParent ); + rParent.GetTabBoxes().C40_INSERT( SwTableBox, pNew, rParent.GetTabBoxes().Count() ); + + Ptrs.pLine->CreateNew( rTbl, *pNew, rSTbl ); + } + else + { + // Box zum StartNode in der alten Tabelle suchen + SwTableBox* pBox = rTbl.GetTblBox( nSttNode ); + OSL_ENSURE( pBox, "Wo ist meine TabellenBox geblieben?" ); + + SwFrmFmt* pOld = pBox->GetFrmFmt(); + pBox->RegisterToFormat( *pFmt ); + if( !pOld->GetDepends() ) + delete pOld; + + pBox->setRowSpan( nRowSpan ); + + SwTableBoxes* pTBoxes = &pBox->GetUpper()->GetTabBoxes(); + pTBoxes->Remove( pTBoxes->C40_GETPOS( SwTableBox, pBox ) ); + + pBox->SetUpper( &rParent ); + pTBoxes = &rParent.GetTabBoxes(); + pTBoxes->C40_INSERT( SwTableBox, pBox, pTBoxes->Count() ); + } + + if( pNext ) + pNext->CreateNew( rTbl, rParent, rSTbl ); +} + + +////////////////////////////////////////////////////////////////////////// + +// UndoObject fuer Attribut Aenderung an der Tabelle + + +SwUndoAttrTbl::SwUndoAttrTbl( const SwTableNode& rTblNd, sal_Bool bClearTabCols ) + : SwUndo( UNDO_TABLE_ATTR ), + nSttNode( rTblNd.GetIndex() ) +{ + bClearTabCol = bClearTabCols; + pSaveTbl = new _SaveTable( rTblNd.GetTable() ); +} + +SwUndoAttrTbl::~SwUndoAttrTbl() +{ + delete pSaveTbl; +} + +void SwUndoAttrTbl::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + SwTableNode* pTblNd = rDoc.GetNodes()[ nSttNode ]->GetTableNode(); + OSL_ENSURE( pTblNd, "kein TabellenNode" ); + + if (pTblNd) + { + _SaveTable* pOrig = new _SaveTable( pTblNd->GetTable() ); + pSaveTbl->RestoreAttr( pTblNd->GetTable() ); + delete pSaveTbl; + pSaveTbl = pOrig; + } + + if( bClearTabCol ) + ClearFEShellTabCols(); +} + +void SwUndoAttrTbl::RedoImpl(::sw::UndoRedoContext & rContext) +{ + UndoImpl(rContext); +} + + +////////////////////////////////////////////////////////////////////////// + +// UndoObject fuer AutoFormat an der Tabelle + + +SwUndoTblAutoFmt::SwUndoTblAutoFmt( const SwTableNode& rTblNd, + const SwTableAutoFmt& rAFmt ) + : SwUndo( UNDO_TABLE_AUTOFMT ), + nSttNode( rTblNd.GetIndex() ), + bSaveCntntAttr( sal_False ) +{ + pSaveTbl = new _SaveTable( rTblNd.GetTable() ); + + if( rAFmt.IsFont() || rAFmt.IsJustify() ) + { + // dann auch noch ueber die ContentNodes der EndBoxen und + // und alle Absatz-Attribute zusammen sammeln + pSaveTbl->SaveCntntAttrs( (SwDoc*)rTblNd.GetDoc() ); + bSaveCntntAttr = sal_True; + } +} + +SwUndoTblAutoFmt::~SwUndoTblAutoFmt() +{ + delete pSaveTbl; +} + +void SwUndoTblAutoFmt::SaveBoxCntnt( const SwTableBox& rBox ) +{ + ::boost::shared_ptr<SwUndoTblNumFmt> const p(new SwUndoTblNumFmt(rBox)); + m_Undos.push_back(p); +} + + +void +SwUndoTblAutoFmt::UndoRedo(bool const bUndo, ::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + SwTableNode* pTblNd = rDoc.GetNodes()[ nSttNode ]->GetTableNode(); + OSL_ENSURE( pTblNd, "kein TabellenNode" ); + + _SaveTable* pOrig = new _SaveTable( pTblNd->GetTable() ); + // dann auch noch ueber die ContentNodes der EndBoxen und + // und alle Absatz-Attribute zusammen sammeln + if( bSaveCntntAttr ) + pOrig->SaveCntntAttrs( &rDoc ); + + if (bUndo) + { + for (size_t n = m_Undos.size(); 0 < n; --n) + { + m_Undos.at(n-1)->UndoImpl(rContext); + } + } + + pSaveTbl->RestoreAttr( pTblNd->GetTable(), !bUndo ); + delete pSaveTbl; + pSaveTbl = pOrig; +} + +void SwUndoTblAutoFmt::UndoImpl(::sw::UndoRedoContext & rContext) +{ + UndoRedo(true, rContext); +} + +void SwUndoTblAutoFmt::RedoImpl(::sw::UndoRedoContext & rContext) +{ + UndoRedo(false, rContext); +} + + +////////////////////////////////////////////////////////////////////////// + +SwUndoTblNdsChg::SwUndoTblNdsChg( SwUndoId nAction, + const SwSelBoxes& rBoxes, + const SwTableNode& rTblNd, + long nMn, long nMx, + sal_uInt16 nCnt, sal_Bool bFlg, sal_Bool bSmHght ) + : SwUndo( nAction ), + aBoxes( rBoxes.Count() < 255 ? (sal_uInt8)rBoxes.Count() : 255, 10 ), + nMin( nMn ), nMax( nMx ), + nSttNode( rTblNd.GetIndex() ), nCurrBox( 0 ), + nCount( nCnt ), nRelDiff( 0 ), nAbsDiff( 0 ), + nSetColType( USHRT_MAX ), + bFlag( bFlg ), + bSameHeight( bSmHght ) +{ + Ptrs.pNewSttNds = 0; + + const SwTable& rTbl = rTblNd.GetTable(); + pSaveTbl = new _SaveTable( rTbl ); + + // und die Selektion merken + for( sal_uInt16 n = 0; n < rBoxes.Count(); ++n ) + aBoxes.Insert( rBoxes[n]->GetSttIdx(), n ); +} + + +SwUndoTblNdsChg::SwUndoTblNdsChg( SwUndoId nAction, + const SwSelBoxes& rBoxes, + const SwTableNode& rTblNd ) + : SwUndo( nAction ), + aBoxes( rBoxes.Count() < 255 ? (sal_uInt8)rBoxes.Count() : 255, 10 ), + nMin( 0 ), nMax( 0 ), + nSttNode( rTblNd.GetIndex() ), nCurrBox( 0 ), + nCount( 0 ), nRelDiff( 0 ), nAbsDiff( 0 ), + nSetColType( USHRT_MAX ), + bFlag( sal_False ), + bSameHeight( sal_False ) +{ + Ptrs.pNewSttNds = 0; + + const SwTable& rTbl = rTblNd.GetTable(); + pSaveTbl = new _SaveTable( rTbl ); + + // und die Selektion merken + for( sal_uInt16 n = 0; n < rBoxes.Count(); ++n ) + aBoxes.Insert( rBoxes[n]->GetSttIdx(), n ); +} + +void SwUndoTblNdsChg::ReNewBoxes( const SwSelBoxes& rBoxes ) +{ + if( rBoxes.Count() != aBoxes.Count() ) + { + aBoxes.Remove( 0, aBoxes.Count() ); + for( sal_uInt16 n = 0; n < rBoxes.Count(); ++n ) + aBoxes.Insert( rBoxes[n]->GetSttIdx(), n ); + } +} + +SwUndoTblNdsChg::~SwUndoTblNdsChg() +{ + delete pSaveTbl; + + if( IsDelBox() ) + delete Ptrs.pDelSects; + else + delete Ptrs.pNewSttNds; +} + +void SwUndoTblNdsChg::SaveNewBoxes( const SwTableNode& rTblNd, + const SwTableSortBoxes& rOld ) +{ + const SwTable& rTbl = rTblNd.GetTable(); + const SwTableSortBoxes& rTblBoxes = rTbl.GetTabSortBoxes(); + sal_uInt16 n; + sal_uInt16 i; + + OSL_ENSURE( ! IsDelBox(), "falsche Action" ); + Ptrs.pNewSttNds = new SvULongs( (sal_uInt8)(rTblBoxes.Count() - rOld.Count()), 5 ); + + for( n = 0, i = 0; n < rOld.Count(); ++i ) + { + if( rOld[ n ] == rTblBoxes[ i ] ) + ++n; + else + // neue Box: sortiert einfuegen!! + InsertSort( *Ptrs.pNewSttNds, rTblBoxes[ i ]->GetSttIdx() ); + } + + for( ; i < rTblBoxes.Count(); ++i ) + // neue Box: sortiert einfuegen!! + InsertSort( *Ptrs.pNewSttNds, rTblBoxes[ i ]->GetSttIdx() ); +} + + +SwTableLine* lcl_FindTableLine( const SwTable& rTable, + const SwTableBox& rBox ) +{ + SwTableLine* pRet = NULL; + // i63949: For nested cells we have to take nLineNo - 1, too, not 0! + const SwTableLines &rTableLines = ( rBox.GetUpper()->GetUpper() != NULL ) ? + rBox.GetUpper()->GetUpper()->GetTabLines() + : rTable.GetTabLines(); + const SwTableLine* pLine = rBox.GetUpper(); + sal_uInt16 nLineNo = rTableLines.C40_GETPOS( SwTableLine, pLine ); + pRet = rTableLines[nLineNo - 1]; + + return pRet; +} + +const SwTableLines& lcl_FindParentLines( const SwTable& rTable, + const SwTableBox& rBox ) +{ + const SwTableLines& rRet = + ( rBox.GetUpper()->GetUpper() != NULL ) ? + rBox.GetUpper()->GetUpper()->GetTabLines() : + rTable.GetTabLines(); + + return rRet; +} + + +void SwUndoTblNdsChg::SaveNewBoxes( const SwTableNode& rTblNd, + const SwTableSortBoxes& rOld, + const SwSelBoxes& rBoxes, + const SvULongs& rNodeCnts ) +{ + const SwTable& rTbl = rTblNd.GetTable(); + const SwTableSortBoxes& rTblBoxes = rTbl.GetTabSortBoxes(); + + OSL_ENSURE( ! IsDelBox(), "falsche Action" ); + Ptrs.pNewSttNds = new SvULongs( (sal_uInt8)(rTblBoxes.Count() - rOld.Count()), 5 ); + + OSL_ENSURE( rTbl.IsNewModel() || rOld.Count() + nCount * rBoxes.Count() == rTblBoxes.Count(), + "unexpected boxes" ); + OSL_ENSURE( rOld.Count() <= rTblBoxes.Count(), "more unexpected boxes" ); + for( sal_uInt16 n = 0, i = 0; i < rTblBoxes.Count(); ++i ) + { + if( ( n < rOld.Count() ) && + ( rOld[ n ] == rTblBoxes[ i ] ) ) + { + // box already known? Then nothing to be done. + ++n; + } + else + { + // new box found: insert (obey sort order) + sal_uInt16 nInsPos; + const SwTableBox* pBox = rTblBoxes[ i ]; + InsertSort( *Ptrs.pNewSttNds, pBox->GetSttIdx(), &nInsPos ); + + // find the source box. It must be one in rBoxes. + // We found the right one if it's in the same column as pBox. + // No, if more than one selected cell in the same column has been splitted, + // we have to look for the nearest one (i65201)! + const SwTableBox* pSourceBox = NULL; + const SwTableBox* pCheckBox = NULL; + const SwTableLine* pBoxLine = pBox->GetUpper(); + sal_uInt16 nLineDiff = lcl_FindParentLines(rTbl,*pBox).C40_GETPOS(SwTableLine,pBoxLine); + sal_uInt16 nLineNo = 0; + for( sal_uInt16 j = 0; j < rBoxes.Count(); ++j ) + { + pCheckBox = rBoxes[j]; + if( pCheckBox->GetUpper()->GetUpper() == pBox->GetUpper()->GetUpper() ) + { + const SwTableLine* pCheckLine = pCheckBox->GetUpper(); + sal_uInt16 nCheckLine = lcl_FindParentLines( rTbl, *pCheckBox ). + C40_GETPOS( SwTableLine, pCheckLine ); + if( ( !pSourceBox || nCheckLine > nLineNo ) && nCheckLine < nLineDiff ) + { + nLineNo = nCheckLine; + pSourceBox = pCheckBox; + } + } + } + + // find the line number difference + // (to help determine bNodesMoved flag below) + nLineDiff = nLineDiff - nLineNo; + OSL_ENSURE( pSourceBox, "Splitted source box not found!" ); + // find out how many nodes the source box used to have + // (to help determine bNodesMoved flag below) + sal_uInt16 nNdsPos = 0; + while( rBoxes[ nNdsPos ] != pSourceBox ) + ++nNdsPos; + sal_uLong nNodes = rNodeCnts[ nNdsPos ]; + + // When a new table cell is created, it either gets a new + // node, or it gets node(s) from elsewhere. The undo must + // know, of course, and thus we must determine here just + // where pBox's nodes are from: + // If 1) the source box has lost nodes, and + // 2) we're in the node range that got nodes + // then pBox received nodes from elsewhere. + // If bNodesMoved is set for pBox the undo must move the + // boxes back, otherwise it must delete them. + // The bNodesMoved flag is stored in a seperate array + // which mirrors Ptrs.pNewSttNds, i.e. Ptrs.pNewSttNds[i] + // and aMvBoxes[i] belong together. + sal_Bool bNodesMoved = + ( nNodes != ( pSourceBox->GetSttNd()->EndOfSectionIndex() - + pSourceBox->GetSttIdx() ) ) + && ( nNodes - 1 > nLineDiff ); + aMvBoxes.insert( aMvBoxes.begin() + nInsPos, bNodesMoved ); + } + } +} + + +void SwUndoTblNdsChg::SaveSection( SwStartNode* pSttNd ) +{ + OSL_ENSURE( IsDelBox(), "falsche Action" ); + if( !Ptrs.pDelSects ) + Ptrs.pDelSects = new SwUndoSaveSections( 10, 5 ); + + SwTableNode* pTblNd = pSttNd->FindTableNode(); + SwUndoSaveSection* pSave = new SwUndoSaveSection; + pSave->SaveSection( pSttNd->GetDoc(), SwNodeIndex( *pSttNd )); + + Ptrs.pDelSects->Insert( pSave, Ptrs.pDelSects->Count() ); + nSttNode = pTblNd->GetIndex(); +} + + +void SwUndoTblNdsChg::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + SwNodeIndex aIdx( rDoc.GetNodes(), nSttNode ); + + SwTableNode *const pTblNd = aIdx.GetNode().GetTableNode(); + OSL_ENSURE( pTblNd, "kein TabellenNode" ); + + SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() ); + aMsgHnt.eFlags = TBL_BOXPTR; + rDoc.UpdateTblFlds( &aMsgHnt ); + + CHECK_TABLE( pTblNd->GetTable() ) + + _FndBox aTmpBox( 0, 0 ); + // ? TL_CHART2: notification or locking of controller required ? + + SwChartDataProvider *pPCD = rDoc.GetChartDataProvider(); + std::vector< SwTableBox* > aDelBoxes; + if( IsDelBox() ) + { + // Trick: die fehlenden Boxen in irgendeine Line einfuegen, beim + // CreateNew werden sie korrekt verbunden. + SwTableBox* pCpyBox = pTblNd->GetTable().GetTabSortBoxes()[0]; + SwTableBoxes& rLnBoxes = pCpyBox->GetUpper()->GetTabBoxes(); + + // die Sections wieder herstellen + for( sal_uInt16 n = Ptrs.pDelSects->Count(); n; ) + { + SwUndoSaveSection* pSave = (*Ptrs.pDelSects)[ --n ]; + pSave->RestoreSection( &rDoc, &aIdx, SwTableBoxStartNode ); + if( pSave->GetHistory() ) + pSave->GetHistory()->Rollback( &rDoc ); + SwTableBox* pBox = new SwTableBox( (SwTableBoxFmt*)pCpyBox->GetFrmFmt(), aIdx, + pCpyBox->GetUpper() ); + rLnBoxes.C40_INSERT( SwTableBox, pBox, rLnBoxes.Count() ); + } + Ptrs.pDelSects->DeleteAndDestroy( 0, Ptrs.pDelSects->Count() ); + } + else if( !aMvBoxes.empty() ) + { + // dann muessen Nodes verschoben und nicht geloescht werden! + // Dafuer brauchen wir aber ein temp Array + SvULongs aTmp( 0, 5); + aTmp.Insert( Ptrs.pNewSttNds, 0 ); + + // von hinten anfangen + for( sal_uInt16 n = aTmp.Count(); n; ) + { + // Box aus der Tabellen-Struktur entfernen + sal_uLong nIdx = aTmp[ --n ]; + SwTableBox* pBox = pTblNd->GetTable().GetTblBox( nIdx ); + OSL_ENSURE( pBox, "Wo ist meine TabellenBox geblieben?" ); + + // TL_CHART2: notify chart about box to be removed + if (pPCD) + pPCD->DeleteBox( &pTblNd->GetTable(), *pBox ); + + if( aMvBoxes[ n ] ) + { + SwNodeRange aRg( *pBox->GetSttNd(), 1, + *pBox->GetSttNd()->EndOfSectionNode() ); + + SwTableLine* pLine = lcl_FindTableLine( pTblNd->GetTable(), *pBox ); + SwNodeIndex aInsPos( *(pLine->GetTabBoxes()[0]->GetSttNd()), 2 ); + + // alle StartNode Indizies anpassen + sal_uInt16 i = n; + sal_uLong nSttIdx = aInsPos.GetIndex() - 2, + nNdCnt = aRg.aEnd.GetIndex() - aRg.aStart.GetIndex(); + while( i && aTmp[ --i ] > nSttIdx ) + aTmp[ i ] += nNdCnt; + + // erst die Box loeschen + delete pBox; + // dann die Nodes verschieben, + rDoc.GetNodes()._MoveNodes( aRg, rDoc.GetNodes(), aInsPos, sal_False ); + } + else + rDoc.DeleteSection( rDoc.GetNodes()[ nIdx ] ); + aDelBoxes.insert( aDelBoxes.end(), pBox ); + } + } + else + { + // Remove nodes from nodes array (backwards!) + for( sal_uInt16 n = Ptrs.pNewSttNds->Count(); n; ) + { + sal_uLong nIdx = (*Ptrs.pNewSttNds)[ --n ]; + SwTableBox* pBox = pTblNd->GetTable().GetTblBox( nIdx ); + OSL_ENSURE( pBox, "Where's my table box?" ); + // TL_CHART2: notify chart about box to be removed + if (pPCD) + pPCD->DeleteBox( &pTblNd->GetTable(), *pBox ); + aDelBoxes.insert( aDelBoxes.end(), pBox ); + rDoc.DeleteSection( rDoc.GetNodes()[ nIdx ] ); + } + } + // Remove boxes from table structure + for( sal_uInt16 n = 0; n < aDelBoxes.size(); ++n ) + { + SwTableBox* pCurrBox = aDelBoxes[n]; + SwTableBoxes* pTBoxes = &pCurrBox->GetUpper()->GetTabBoxes(); + pTBoxes->Remove( pTBoxes->C40_GETPOS( SwTableBox, pCurrBox ) ); + delete pCurrBox; + } + + pSaveTbl->CreateNew( pTblNd->GetTable(), sal_True, sal_False ); + + // TL_CHART2: need to inform chart of probably changed cell names + rDoc.UpdateCharts( pTblNd->GetTable().GetFrmFmt()->GetName() ); + + if( IsDelBox() ) + nSttNode = pTblNd->GetIndex(); + ClearFEShellTabCols(); + CHECK_TABLE( pTblNd->GetTable() ) +} + + +void SwUndoTblNdsChg::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + + SwTableNode* pTblNd = rDoc.GetNodes()[ nSttNode ]->GetTableNode(); + OSL_ENSURE( pTblNd, "kein TabellenNode" ); + CHECK_TABLE( pTblNd->GetTable() ) + + SwSelBoxes aSelBoxes; + for( sal_uInt16 n = 0; n < aBoxes.Count(); ++n ) + { + SwTableBox* pBox = pTblNd->GetTable().GetTblBox( aBoxes[ n ] ); + aSelBoxes.Insert( pBox ); + } + + // SelBoxes erzeugen und InsertCell/-Row/SplitTbl aufrufen + switch( GetId() ) + { + case UNDO_TABLE_INSCOL: + if( USHRT_MAX == nSetColType ) + rDoc.InsertCol( aSelBoxes, nCount, bFlag ); + else + { + SwTableBox* pBox = pTblNd->GetTable().GetTblBox( nCurrBox ); + rDoc.SetColRowWidthHeight( *pBox, nSetColType, nAbsDiff, + nRelDiff ); + } + break; + + case UNDO_TABLE_INSROW: + if( USHRT_MAX == nSetColType ) + rDoc.InsertRow( aSelBoxes, nCount, bFlag ); + else + { + SwTable& rTbl = pTblNd->GetTable(); + SwTableBox* pBox = rTbl.GetTblBox( nCurrBox ); + TblChgMode eOldMode = rTbl.GetTblChgMode(); + rTbl.SetTblChgMode( (TblChgMode)nCount ); + rDoc.SetColRowWidthHeight( *pBox, nSetColType, nAbsDiff, nRelDiff ); + rTbl.SetTblChgMode( eOldMode ); + } + break; + + case UNDO_TABLE_SPLIT: + rDoc.SplitTbl( aSelBoxes, bFlag, nCount, bSameHeight ); + break; + case UNDO_TABLE_DELBOX: + case UNDO_ROW_DELETE: + case UNDO_COL_DELETE: + if( USHRT_MAX == nSetColType ) + { + SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() ); + aMsgHnt.eFlags = TBL_BOXPTR; + rDoc.UpdateTblFlds( &aMsgHnt ); + SwTable &rTable = pTblNd->GetTable(); + if( nMax > nMin && rTable.IsNewModel() ) + rTable.PrepareDeleteCol( nMin, nMax ); + rTable.DeleteSel( &rDoc, aSelBoxes, 0, this, sal_True, sal_True ); + } + else + { + SwTable& rTbl = pTblNd->GetTable(); + + SwTableFmlUpdate aMsgHnt( &rTbl ); + aMsgHnt.eFlags = TBL_BOXPTR; + rDoc.UpdateTblFlds( &aMsgHnt ); + + SwTableBox* pBox = rTbl.GetTblBox( nCurrBox ); + TblChgMode eOldMode = rTbl.GetTblChgMode(); + rTbl.SetTblChgMode( (TblChgMode)nCount ); + + // need the SaveSections! + rDoc.GetIDocumentUndoRedo().DoUndo( true ); + SwUndoTblNdsChg* pUndo = 0; + + switch( nSetColType & 0xff ) + { + case nsTblChgWidthHeightType::WH_COL_LEFT: + case nsTblChgWidthHeightType::WH_COL_RIGHT: + case nsTblChgWidthHeightType::WH_CELL_LEFT: + case nsTblChgWidthHeightType::WH_CELL_RIGHT: + rTbl.SetColWidth( *pBox, nSetColType, nAbsDiff, + nRelDiff, (SwUndo**)&pUndo ); + break; + case nsTblChgWidthHeightType::WH_ROW_TOP: + case nsTblChgWidthHeightType::WH_ROW_BOTTOM: + case nsTblChgWidthHeightType::WH_CELL_TOP: + case nsTblChgWidthHeightType::WH_CELL_BOTTOM: + rTbl.SetRowHeight( *pBox, nSetColType, nAbsDiff, + nRelDiff, (SwUndo**)&pUndo ); + break; + } + + if( pUndo ) + { + Ptrs.pDelSects->Insert( pUndo->Ptrs.pDelSects, 0 ); + pUndo->Ptrs.pDelSects->Remove( 0, pUndo->Ptrs.pDelSects->Count() ); + + delete pUndo; + } + rDoc.GetIDocumentUndoRedo().DoUndo( false ); + + rTbl.SetTblChgMode( eOldMode ); + } + nSttNode = pTblNd->GetIndex(); + break; + default: + ; + } + ClearFEShellTabCols(); + CHECK_TABLE( pTblNd->GetTable() ) +} + + +////////////////////////////////////////////////////////////////////////// + +SwUndoTblMerge::SwUndoTblMerge( const SwPaM& rTblSel ) + : SwUndo( UNDO_TABLE_MERGE ), SwUndRng( rTblSel ), pHistory( 0 ) +{ + const SwTableNode* pTblNd = rTblSel.GetNode()->FindTableNode(); + OSL_ENSURE( pTblNd, "Wo ist TabllenNode" ); + pSaveTbl = new _SaveTable( pTblNd->GetTable() ); + pMoves = new SwUndoMoves; + nTblNode = pTblNd->GetIndex(); +} + +SwUndoTblMerge::~SwUndoTblMerge() +{ + delete pSaveTbl; + delete pMoves; + delete pHistory; +} + +void SwUndoTblMerge::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + SwNodeIndex aIdx( rDoc.GetNodes(), nTblNode ); + + SwTableNode *const pTblNd = aIdx.GetNode().GetTableNode(); + OSL_ENSURE( pTblNd, "kein TabellenNode" ); + + SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() ); + aMsgHnt.eFlags = TBL_BOXPTR; + rDoc.UpdateTblFlds( &aMsgHnt ); + + _FndBox aTmpBox( 0, 0 ); + // ? TL_CHART2: notification or locking of controller required ? + + + // 1. die geloeschten Boxen wiederherstellen: + + // Trick: die fehlenden Boxen in irgendeine Line einfuegen, beim + // CreateNew werden sie korrekt verbunden. + SwTableBox *pBox, *pCpyBox = pTblNd->GetTable().GetTabSortBoxes()[0]; + SwTableBoxes& rLnBoxes = pCpyBox->GetUpper()->GetTabBoxes(); + +CHECKTABLE(pTblNd->GetTable()) + + SwSelBoxes aSelBoxes; + SwTxtFmtColl* pColl = rDoc.GetTxtCollFromPool( RES_POOLCOLL_STANDARD ); + sal_uInt16 n; + + for( n = 0; n < aBoxes.Count(); ++n ) + { + aIdx = aBoxes[ n ]; + SwStartNode* pSttNd = rDoc.GetNodes().MakeTextSection( aIdx, + SwTableBoxStartNode, pColl ); + pBox = new SwTableBox( (SwTableBoxFmt*)pCpyBox->GetFrmFmt(), *pSttNd, + pCpyBox->GetUpper() ); + rLnBoxes.C40_INSERT( SwTableBox, pBox, rLnBoxes.Count() ); + + aSelBoxes.Insert( pBox ); + } + +CHECKTABLE(pTblNd->GetTable()) + + SwChartDataProvider *pPCD = rDoc.GetChartDataProvider(); + // 2. die eingefuegten Boxen loeschen + // die Nodes loeschen (von Hinten!!) + for( n = aNewSttNds.Count(); n; ) + { + // Box aus der Tabellen-Struktur entfernen + sal_uLong nIdx = aNewSttNds[ --n ]; + + if( !nIdx && n ) + { + nIdx = aNewSttNds[ --n ]; + pBox = pTblNd->GetTable().GetTblBox( nIdx ); + OSL_ENSURE( pBox, "Wo ist meine TabellenBox geblieben?" ); + + if( !pSaveTbl->IsNewModel() ) + rDoc.GetNodes().MakeTxtNode( SwNodeIndex( + *pBox->GetSttNd()->EndOfSectionNode() ), pColl ); + + // das war der Trenner, -> die verschobenen herstellen + for( sal_uInt16 i = pMoves->Count(); i; ) + { + SwTxtNode* pTxtNd = 0; + sal_uInt16 nDelPos = 0; + SwUndoMove* pUndo = (*pMoves)[ --i ]; + if( !pUndo->IsMoveRange() ) + { + pTxtNd = rDoc.GetNodes()[ pUndo->GetDestSttNode() ]->GetTxtNode(); + nDelPos = pUndo->GetDestSttCntnt() - 1; + } + pUndo->UndoImpl(rContext); + if( pUndo->IsMoveRange() ) + { + // den ueberfluessigen Node loeschen + aIdx = pUndo->GetEndNode(); + SwCntntNode *pCNd = aIdx.GetNode().GetCntntNode(); + if( pCNd ) + { + SwNodeIndex aTmp( aIdx, -1 ); + SwCntntNode *pMove = aTmp.GetNode().GetCntntNode(); + if( pMove ) + pCNd->MoveTo( *pMove ); + } + rDoc.GetNodes().Delete( aIdx, 1 ); + } + else if( pTxtNd ) + { + // evt. noch ueberflussige Attribute loeschen + SwIndex aTmpIdx( pTxtNd, nDelPos ); + if( pTxtNd->GetpSwpHints() && pTxtNd->GetpSwpHints()->Count() ) + pTxtNd->RstAttr( aTmpIdx, pTxtNd->GetTxt().Len() - + nDelPos + 1 ); + // das Trennzeichen loeschen + pTxtNd->EraseText( aTmpIdx, 1 ); + } + } + nIdx = pBox->GetSttIdx(); + } + else + pBox = pTblNd->GetTable().GetTblBox( nIdx ); + + if( !pSaveTbl->IsNewModel() ) + { + // TL_CHART2: notify chart about box to be removed + if (pPCD) + pPCD->DeleteBox( &pTblNd->GetTable(), *pBox ); + + SwTableBoxes* pTBoxes = &pBox->GetUpper()->GetTabBoxes(); + pTBoxes->Remove( pTBoxes->C40_GETPOS( SwTableBox, pBox ) ); + + + // Indizies aus dem Bereich loeschen + { + SwNodeIndex aTmpIdx( *pBox->GetSttNd() ); + rDoc.CorrAbs( SwNodeIndex( aTmpIdx, 1 ), + SwNodeIndex( *aTmpIdx.GetNode().EndOfSectionNode() ), + SwPosition( aTmpIdx, SwIndex( 0, 0 )), sal_True ); + } + + delete pBox; + rDoc.DeleteSection( rDoc.GetNodes()[ nIdx ] ); + } + } +CHECKTABLE(pTblNd->GetTable()) + + + pSaveTbl->CreateNew( pTblNd->GetTable(), sal_True, sal_False ); + + // TL_CHART2: need to inform chart of probably changed cell names + rDoc.UpdateCharts( pTblNd->GetTable().GetFrmFmt()->GetName() ); + + if( pHistory ) + { + pHistory->TmpRollback( &rDoc, 0 ); + pHistory->SetTmpEnd( pHistory->Count() ); + } +// nTblNode = pTblNd->GetIndex(); + + SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor()); + pPam->DeleteMark(); + pPam->GetPoint()->nNode = nSttNode; + pPam->GetPoint()->nContent.Assign( pPam->GetCntntNode(), nSttCntnt ); + pPam->SetMark(); + pPam->DeleteMark(); + +CHECKTABLE(pTblNd->GetTable()) + ClearFEShellTabCols(); +} + +void SwUndoTblMerge::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + SwPaM & rPam( AddUndoRedoPaM(rContext) ); + rDoc.MergeTbl(rPam); +} + +void SwUndoTblMerge::MoveBoxCntnt( SwDoc* pDoc, SwNodeRange& rRg, SwNodeIndex& rPos ) +{ + SwNodeIndex aTmp( rRg.aStart, -1 ), aTmp2( rPos, -1 ); + SwUndoMove* pUndo = new SwUndoMove( pDoc, rRg, rPos ); + ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo()); + pDoc->MoveNodeRange( rRg, rPos, (pSaveTbl->IsNewModel()) ? + IDocumentContentOperations::DOC_NO_DELFRMS : + IDocumentContentOperations::DOC_MOVEDEFAULT ); + aTmp++; + aTmp2++; + pUndo->SetDestRange( aTmp2, rPos, aTmp ); + + pMoves->Insert( pUndo, pMoves->Count() ); +} + +void SwUndoTblMerge::SetSelBoxes( const SwSelBoxes& rBoxes ) +{ + // die Selektion merken + for( sal_uInt16 n = 0; n < rBoxes.Count(); ++n ) + InsertSort( aBoxes, rBoxes[n]->GetSttIdx() ); + + // als Trennung fuers einfuegen neuer Boxen nach dem Verschieben! + aNewSttNds.Insert( (sal_uLong)0, aNewSttNds.Count() ); + + // The new table model does not delete overlapped cells (by row span), + // so the rBoxes array might be empty even some cells have been merged. + if( rBoxes.Count() ) + nTblNode = rBoxes[ 0 ]->GetSttNd()->FindTableNode()->GetIndex(); +} + +void SwUndoTblMerge::SaveCollection( const SwTableBox& rBox ) +{ + if( !pHistory ) + pHistory = new SwHistory; + + SwNodeIndex aIdx( *rBox.GetSttNd(), 1 ); + SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode(); + if( !pCNd ) + pCNd = aIdx.GetNodes().GoNext( &aIdx ); + + pHistory->Add( pCNd->GetFmtColl(), aIdx.GetIndex(), pCNd->GetNodeType()); + if( pCNd->HasSwAttrSet() ) + pHistory->CopyFmtAttr( *pCNd->GetpSwAttrSet(), aIdx.GetIndex() ); +} + + +////////////////////////////////////////////////////////////////////////// + +SwUndoTblNumFmt::SwUndoTblNumFmt( const SwTableBox& rBox, + const SfxItemSet* pNewSet ) + : SwUndo( UNDO_TBLNUMFMT ), + pBoxSet( 0 ), pHistory( 0 ), nFmtIdx( NUMBERFORMAT_TEXT ) +{ + bNewFmt = bNewFml = bNewValue = sal_False; + nNode = rBox.GetSttIdx(); + + nNdPos = rBox.IsValidNumTxtNd( 0 == pNewSet ); + SwDoc* pDoc = rBox.GetFrmFmt()->GetDoc(); + + if( ULONG_MAX != nNdPos ) + { + SwTxtNode* pTNd = pDoc->GetNodes()[ nNdPos ]->GetTxtNode(); + + pHistory = new SwHistory; + SwRegHistory aRHst( *rBox.GetSttNd(), pHistory ); + // always save all text atttibutes because of possibly overlapping + // areas of on/off + pHistory->CopyAttr( pTNd->GetpSwpHints(), nNdPos, 0, + pTNd->GetTxt().Len(), true ); + + if( pTNd->HasSwAttrSet() ) + pHistory->CopyFmtAttr( *pTNd->GetpSwAttrSet(), nNdPos ); + + aStr = pTNd->GetTxt(); + if( pTNd->GetpSwpHints() ) + pTNd->GetpSwpHints()->DeRegister(); + } + + pBoxSet = new SfxItemSet( pDoc->GetAttrPool(), aTableBoxSetRange ); + pBoxSet->Put( rBox.GetFrmFmt()->GetAttrSet() ); + + if( pNewSet ) + { + const SfxPoolItem* pItem; + if( SFX_ITEM_SET == pNewSet->GetItemState( RES_BOXATR_FORMAT, + sal_False, &pItem )) + { + bNewFmt = sal_True; + nNewFmtIdx = ((SwTblBoxNumFormat*)pItem)->GetValue(); + } + if( SFX_ITEM_SET == pNewSet->GetItemState( RES_BOXATR_FORMULA, + sal_False, &pItem )) + { + bNewFml = sal_True; + aNewFml = ((SwTblBoxFormula*)pItem)->GetFormula(); + } + if( SFX_ITEM_SET == pNewSet->GetItemState( RES_BOXATR_VALUE, + sal_False, &pItem )) + { + bNewValue = sal_True; + fNewNum = ((SwTblBoxValue*)pItem)->GetValue(); + } + } + + // wird die History ueberhaupt benoetigt ?? + if( pHistory && !pHistory->Count() ) + DELETEZ( pHistory ); +} + +SwUndoTblNumFmt::~SwUndoTblNumFmt() +{ + delete pHistory; + delete pBoxSet; +} + +void SwUndoTblNumFmt::UndoImpl(::sw::UndoRedoContext & rContext) +{ + OSL_ENSURE( pBoxSet, "Where's the stored item set?" ); + + SwDoc & rDoc = rContext.GetDoc(); + SwStartNode* pSttNd = rDoc.GetNodes()[ nNode ]-> + FindSttNodeByType( SwTableBoxStartNode ); + OSL_ENSURE( pSttNd, "ohne StartNode kein TabellenBox" ); + SwTableBox* pBox = pSttNd->FindTableNode()->GetTable().GetTblBox( + pSttNd->GetIndex() ); + OSL_ENSURE( pBox, "keine TabellenBox gefunden" ); + + SwTableBoxFmt* pFmt = rDoc.MakeTableBoxFmt(); + pFmt->SetFmtAttr( *pBoxSet ); + pBox->ChgFrmFmt( pFmt ); + + if( ULONG_MAX == nNdPos ) + return; + + SwTxtNode* pTxtNd = rDoc.GetNodes()[ nNdPos ]->GetTxtNode(); + // wenn mehr als ein Node geloescht wurde, dann wurden auch + // alle "Node"-Attribute gespeichert + if( pTxtNd->HasSwAttrSet() ) + pTxtNd->ResetAllAttr(); + + if( pTxtNd->GetpSwpHints() && aStr.Len() ) + pTxtNd->ClearSwpHintsArr( true ); + + // ChgTextToNum(..) only acts when the strings are different. We + // need to do the same here. + if( pTxtNd->GetTxt() != aStr ) + { + rDoc.DeleteRedline( *( pBox->GetSttNd() ), false, USHRT_MAX ); + + SwIndex aIdx( pTxtNd, 0 ); + if( aStr.Len() ) + { + pTxtNd->EraseText( aIdx ); + pTxtNd->InsertText( aStr, aIdx, + IDocumentContentOperations::INS_NOHINTEXPAND ); + } + } + + if( pHistory ) + { + sal_uInt16 nTmpEnd = pHistory->GetTmpEnd(); + pHistory->TmpRollback( &rDoc, 0 ); + pHistory->SetTmpEnd( nTmpEnd ); + } + + SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor()); + pPam->DeleteMark(); + pPam->GetPoint()->nNode = nNode + 1; + pPam->GetPoint()->nContent.Assign( pTxtNd, 0 ); +} + +/** switch the RedlineMode on the given document, using + * SetRedlineMode_intern. This class set the mode in the constructor, + * and changes it back in the destructor, i.e. it uses the + * initialization-is-resource-acquisition idiom. + */ +class RedlineModeInternGuard +{ + SwDoc& mrDoc; + RedlineMode_t meOldRedlineMode; + +public: + RedlineModeInternGuard( + SwDoc& rDoc, /// change mode of this document + RedlineMode_t eNewRedlineMode, /// new redline mode + RedlineMode_t eRedlineModeMask = (RedlineMode_t)(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_IGNORE /*change only bits set in this mask*/)); + + ~RedlineModeInternGuard(); +}; + +RedlineModeInternGuard::RedlineModeInternGuard( + SwDoc& rDoc, + RedlineMode_t eNewRedlineMode, + RedlineMode_t eRedlineModeMask ) + : mrDoc( rDoc ), + meOldRedlineMode( rDoc.GetRedlineMode() ) +{ + mrDoc.SetRedlineMode_intern((RedlineMode_t)( ( meOldRedlineMode & ~eRedlineModeMask ) | + ( eNewRedlineMode & eRedlineModeMask ) )); +} + +RedlineModeInternGuard::~RedlineModeInternGuard() +{ + mrDoc.SetRedlineMode_intern( meOldRedlineMode ); +} + + + +void SwUndoTblNumFmt::RedoImpl(::sw::UndoRedoContext & rContext) +{ + // konnte die Box veraendert werden ? + if( !pBoxSet ) + return ; + + SwDoc & rDoc = rContext.GetDoc(); + SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor()); + + pPam->DeleteMark(); + pPam->GetPoint()->nNode = nNode; + + SwNode * pNd = & pPam->GetPoint()->nNode.GetNode(); + SwStartNode* pSttNd = pNd->FindSttNodeByType( SwTableBoxStartNode ); + OSL_ENSURE( pSttNd, "ohne StartNode kein TabellenBox" ); + SwTableBox* pBox = pSttNd->FindTableNode()->GetTable().GetTblBox( + pSttNd->GetIndex() ); + OSL_ENSURE( pBox, "keine TabellenBox gefunden" ); + + SwFrmFmt* pBoxFmt = pBox->ClaimFrmFmt(); + if( bNewFmt || bNewFml || bNewValue ) + { + SfxItemSet aBoxSet( rDoc.GetAttrPool(), + RES_BOXATR_FORMAT, RES_BOXATR_VALUE ); + + // JP 15.01.99: Nur Attribute zuruecksetzen reicht nicht. + // Sorge dafuer, das der Text auch entsprechend + // formatiert wird! + pBoxFmt->LockModify(); + + if( bNewFml ) + aBoxSet.Put( SwTblBoxFormula( aNewFml )); + else + pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMULA ); + if( bNewFmt ) + aBoxSet.Put( SwTblBoxNumFormat( nNewFmtIdx )); + else + pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMAT ); + if( bNewValue ) + aBoxSet.Put( SwTblBoxValue( fNewNum )); + else + pBoxFmt->ResetFmtAttr( RES_BOXATR_VALUE ); + pBoxFmt->UnlockModify(); + + // dvo: When redlining is (was) enabled, setting the attribute + // will also change the cell content. To allow this, the + // REDLINE_IGNORE flag must be removed during Redo. #108450# + RedlineModeInternGuard aGuard( rDoc, nsRedlineMode_t::REDLINE_NONE, nsRedlineMode_t::REDLINE_IGNORE ); + pBoxFmt->SetFmtAttr( aBoxSet ); + } + else if( NUMBERFORMAT_TEXT != nFmtIdx ) + { + SfxItemSet aBoxSet( rDoc.GetAttrPool(), + RES_BOXATR_FORMAT, RES_BOXATR_VALUE ); + + aBoxSet.Put( SwTblBoxNumFormat( nFmtIdx )); + aBoxSet.Put( SwTblBoxValue( fNum )); + + // JP 15.01.99: Nur Attribute zuruecksetzen reicht nicht. + // Sorge dafuer, das der Text auch entsprechend + // formatiert wird! + pBoxFmt->LockModify(); + pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMULA ); + pBoxFmt->UnlockModify(); + + // dvo: When redlining is (was) enabled, setting the attribute + // will also change the cell content. To allow this, the + // REDLINE_IGNORE flag must be removed during Redo. #108450# + RedlineModeInternGuard aGuard( rDoc, nsRedlineMode_t::REDLINE_NONE, nsRedlineMode_t::REDLINE_IGNORE ); + pBoxFmt->SetFmtAttr( aBoxSet ); + } + else + { + // es ist keine Zahl + + // 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( RES_BOXATR_FORMAT, RES_BOXATR_VALUE ); + } + + if( bNewFml ) + { + // egal was gesetzt wurde, ein Update der Tabelle macht sich immer gut + SwTableFmlUpdate aTblUpdate( &pSttNd->FindTableNode()->GetTable() ); + rDoc.UpdateTblFlds( &aTblUpdate ); + } + + if( !pNd->IsCntntNode() ) + pNd = rDoc.GetNodes().GoNext( &pPam->GetPoint()->nNode ); + pPam->GetPoint()->nContent.Assign( (SwCntntNode*)pNd, 0 ); +} + +void SwUndoTblNumFmt::SetBox( const SwTableBox& rBox ) +{ + nNode = rBox.GetSttIdx(); +} + + +////////////////////////////////////////////////////////////////////////// + +_UndoTblCpyTbl_Entry::_UndoTblCpyTbl_Entry( const SwTableBox& rBox ) + : nBoxIdx( rBox.GetSttIdx() ), nOffset( 0 ), + pBoxNumAttr( 0 ), pUndo( 0 ), bJoin( false ) +{ +} + +_UndoTblCpyTbl_Entry::~_UndoTblCpyTbl_Entry() +{ + delete pUndo; + delete pBoxNumAttr; +} + + +SwUndoTblCpyTbl::SwUndoTblCpyTbl() + : SwUndo( UNDO_TBLCPYTBL ), pInsRowUndo( 0 ) +{ + pArr = new _UndoTblCpyTbl_Entries; +} + +SwUndoTblCpyTbl::~SwUndoTblCpyTbl() +{ + delete pArr; + delete pInsRowUndo; +} + +void SwUndoTblCpyTbl::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + _DEBUG_REDLINE( &rDoc ) + + SwTableNode* pTblNd = 0; + for( sal_uInt16 n = pArr->Count(); n; ) + { + _UndoTblCpyTbl_Entry* pEntry = (*pArr)[ --n ]; + sal_uLong nSttPos = pEntry->nBoxIdx + pEntry->nOffset; + SwStartNode* pSNd = rDoc.GetNodes()[ nSttPos ]->StartOfSectionNode(); + if( !pTblNd ) + pTblNd = pSNd->FindTableNode(); + + SwTableBox& rBox = *pTblNd->GetTable().GetTblBox( nSttPos ); + + SwNodeIndex aInsIdx( *rBox.GetSttNd(), 1 ); + rDoc.GetNodes().MakeTxtNode( aInsIdx, (SwTxtFmtColl*)rDoc.GetDfltTxtFmtColl() ); + + // b62341295: Redline for copying tables + const SwNode *pEndNode = rBox.GetSttNd()->EndOfSectionNode(); + SwPaM aPam( aInsIdx.GetNode(), *pEndNode ); + SwUndoDelete* pUndo = 0; + + if( IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() ) ) + { + bool bDeleteCompleteParagraph = false; + bool bShiftPam = false; + // There are a couple of different situations to consider during redlining + if( pEntry->pUndo ) + { + SwUndoDelete *const pUndoDelete = + dynamic_cast<SwUndoDelete*>(pEntry->pUndo); + SwUndoRedlineDelete *const pUndoRedlineDelete = + dynamic_cast<SwUndoRedlineDelete*>(pEntry->pUndo); + OSL_ASSERT(pUndoDelete || pUndoRedlineDelete); + if (pUndoRedlineDelete) + { + // The old content was not empty or he has been merged with the new content + bDeleteCompleteParagraph = !pEntry->bJoin; // bJoin is set when merged + // Set aTmpIdx to the beginning fo the old content + SwNodeIndex aTmpIdx( *pEndNode, + pUndoRedlineDelete->NodeDiff()-1 ); + SwTxtNode *pTxt = aTmpIdx.GetNode().GetTxtNode(); + if( pTxt ) + { + aPam.GetPoint()->nNode = *pTxt; + aPam.GetPoint()->nContent.Assign( pTxt, + pUndoRedlineDelete->ContentStart() ); + } + else + *aPam.GetPoint() = SwPosition( aTmpIdx ); + } + else if (pUndoDelete && pUndoDelete->IsDelFullPara()) + { + // When the old content was an empty paragraph, but could not be joined + // with the new content (e.g. because of a section or table) + // We "save" the aPam.Point, we go one step backwards (because later on the + // empty paragraph will be inserted by the undo) and set the "ShiftPam-flag + // for step forward later on. + bDeleteCompleteParagraph = true; + bShiftPam = true; + SwNodeIndex aTmpIdx( *pEndNode, -1 ); + SwTxtNode *pTxt = aTmpIdx.GetNode().GetTxtNode(); + if( pTxt ) + { + aPam.GetPoint()->nNode = *pTxt; + aPam.GetPoint()->nContent.Assign( pTxt, 0 ); + } + else + *aPam.GetPoint() = SwPosition( aTmpIdx ); + } + } + rDoc.DeleteRedline( aPam, true, USHRT_MAX ); + + if( pEntry->pUndo ) + { + pEntry->pUndo->UndoImpl(rContext); + delete pEntry->pUndo; + pEntry->pUndo = 0; + } + if( bShiftPam ) + { + // The aPam.Point is at the moment at the last position of the new content and has to be + // moved to the first postion of the old content for the SwUndoDelete operation + SwNodeIndex aTmpIdx( aPam.GetPoint()->nNode, 1 ); + SwTxtNode *pTxt = aTmpIdx.GetNode().GetTxtNode(); + if( pTxt ) + { + aPam.GetPoint()->nNode = *pTxt; + aPam.GetPoint()->nContent.Assign( pTxt, 0 ); + } + else + *aPam.GetPoint() = SwPosition( aTmpIdx ); + } + pUndo = new SwUndoDelete( aPam, bDeleteCompleteParagraph, sal_True ); + } + else + { + pUndo = new SwUndoDelete( aPam, true ); + if( pEntry->pUndo ) + { + pEntry->pUndo->UndoImpl(rContext); + delete pEntry->pUndo; + pEntry->pUndo = 0; + } + } + pEntry->pUndo = pUndo; + + aInsIdx = rBox.GetSttIdx() + 1; + rDoc.GetNodes().Delete( aInsIdx, 1 ); + + SfxItemSet aTmpSet( rDoc.GetAttrPool(), RES_BOXATR_FORMAT, RES_BOXATR_VALUE, + RES_VERT_ORIENT, RES_VERT_ORIENT, 0 ); + aTmpSet.Put( rBox.GetFrmFmt()->GetAttrSet() ); + if( aTmpSet.Count() ) + { + SwFrmFmt* pBoxFmt = rBox.ClaimFrmFmt(); + pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMAT, RES_BOXATR_VALUE ); + pBoxFmt->ResetFmtAttr( RES_VERT_ORIENT ); + } + + if( pEntry->pBoxNumAttr ) + { + rBox.ClaimFrmFmt()->SetFmtAttr( *pEntry->pBoxNumAttr ); + delete pEntry->pBoxNumAttr, pEntry->pBoxNumAttr = 0; + } + + if( aTmpSet.Count() ) + { + pEntry->pBoxNumAttr = new SfxItemSet( rDoc.GetAttrPool(), + RES_BOXATR_FORMAT, RES_BOXATR_VALUE, + RES_VERT_ORIENT, RES_VERT_ORIENT, 0 ); + pEntry->pBoxNumAttr->Put( aTmpSet ); + } + + pEntry->nOffset = rBox.GetSttIdx() - pEntry->nBoxIdx; + } + + if( pInsRowUndo ) + { + pInsRowUndo->UndoImpl(rContext); + } + _DEBUG_REDLINE( &rDoc ) +} + +void SwUndoTblCpyTbl::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + _DEBUG_REDLINE( &rDoc ) + + if( pInsRowUndo ) + { + pInsRowUndo->RedoImpl(rContext); + } + + SwTableNode* pTblNd = 0; + for( sal_uInt16 n = 0; n < pArr->Count(); ++n ) + { + _UndoTblCpyTbl_Entry* pEntry = (*pArr)[ n ]; + sal_uLong nSttPos = pEntry->nBoxIdx + pEntry->nOffset; + SwStartNode* pSNd = rDoc.GetNodes()[ nSttPos ]->StartOfSectionNode(); + if( !pTblNd ) + pTblNd = pSNd->FindTableNode(); + + SwTableBox& rBox = *pTblNd->GetTable().GetTblBox( nSttPos ); + + SwNodeIndex aInsIdx( *rBox.GetSttNd(), 1 ); + + // b62341295: Redline for copying tables - Start. + rDoc.GetNodes().MakeTxtNode( aInsIdx, (SwTxtFmtColl*)rDoc.GetDfltTxtFmtColl() ); + SwPaM aPam( aInsIdx.GetNode(), *rBox.GetSttNd()->EndOfSectionNode()); + SwUndo* pUndo = IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() ) ? 0 : new SwUndoDelete( aPam, sal_True ); + if( pEntry->pUndo ) + { + pEntry->pUndo->UndoImpl(rContext); + if( IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() ) ) + { + // PrepareRedline has to be called with the beginning of the old content + // When new and old content has been joined, the rIter.pAktPam has been set + // by the Undo operation to this point. + // Otherwise aInsIdx has been moved during the Undo operation + if( pEntry->bJoin ) + { + SwPaM const& rLastPam = + rContext.GetCursorSupplier().GetCurrentShellCursor(); + pUndo = PrepareRedline( &rDoc, rBox, *rLastPam.GetPoint(), + pEntry->bJoin, true ); + } + else + { + SwPosition aTmpPos( aInsIdx ); + pUndo = PrepareRedline( &rDoc, rBox, aTmpPos, pEntry->bJoin, true ); + } + } + delete pEntry->pUndo; + pEntry->pUndo = 0; + } + pEntry->pUndo = pUndo; + // b62341295: Redline for copying tables - End. + + aInsIdx = rBox.GetSttIdx() + 1; + rDoc.GetNodes().Delete( aInsIdx, 1 ); + + SfxItemSet aTmpSet( rDoc.GetAttrPool(), RES_BOXATR_FORMAT, RES_BOXATR_VALUE, + RES_VERT_ORIENT, RES_VERT_ORIENT, 0 ); + aTmpSet.Put( rBox.GetFrmFmt()->GetAttrSet() ); + if( aTmpSet.Count() ) + { + SwFrmFmt* pBoxFmt = rBox.ClaimFrmFmt(); + pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMAT, RES_BOXATR_VALUE ); + pBoxFmt->ResetFmtAttr( RES_VERT_ORIENT ); + } + if( pEntry->pBoxNumAttr ) + { + rBox.ClaimFrmFmt()->SetFmtAttr( *pEntry->pBoxNumAttr ); + delete pEntry->pBoxNumAttr, pEntry->pBoxNumAttr = 0; + } + + if( aTmpSet.Count() ) + { + pEntry->pBoxNumAttr = new SfxItemSet( rDoc.GetAttrPool(), + RES_BOXATR_FORMAT, RES_BOXATR_VALUE, + RES_VERT_ORIENT, RES_VERT_ORIENT, 0 ); + pEntry->pBoxNumAttr->Put( aTmpSet ); + } + + pEntry->nOffset = rBox.GetSttIdx() - pEntry->nBoxIdx; + } + _DEBUG_REDLINE( &rDoc ) +} + +void SwUndoTblCpyTbl::AddBoxBefore( const SwTableBox& rBox, sal_Bool bDelCntnt ) +{ + if( pArr->Count() && !bDelCntnt ) + return; + + _UndoTblCpyTbl_Entry* pEntry = new _UndoTblCpyTbl_Entry( rBox ); + pArr->Insert( pEntry, pArr->Count() ); + + SwDoc* pDoc = rBox.GetFrmFmt()->GetDoc(); + _DEBUG_REDLINE( pDoc ) + if( bDelCntnt ) + { + SwNodeIndex aInsIdx( *rBox.GetSttNd(), 1 ); + pDoc->GetNodes().MakeTxtNode( aInsIdx, (SwTxtFmtColl*)pDoc->GetDfltTxtFmtColl() ); + SwPaM aPam( aInsIdx.GetNode(), *rBox.GetSttNd()->EndOfSectionNode() ); + + if( !pDoc->IsRedlineOn() ) + pEntry->pUndo = new SwUndoDelete( aPam, sal_True ); + } + + pEntry->pBoxNumAttr = new SfxItemSet( pDoc->GetAttrPool(), + RES_BOXATR_FORMAT, RES_BOXATR_VALUE, + RES_VERT_ORIENT, RES_VERT_ORIENT, 0 ); + pEntry->pBoxNumAttr->Put( rBox.GetFrmFmt()->GetAttrSet() ); + if( !pEntry->pBoxNumAttr->Count() ) + delete pEntry->pBoxNumAttr, pEntry->pBoxNumAttr = 0; + _DEBUG_REDLINE( pDoc ) +} + +void SwUndoTblCpyTbl::AddBoxAfter( const SwTableBox& rBox, const SwNodeIndex& rIdx, sal_Bool bDelCntnt ) +{ + _UndoTblCpyTbl_Entry* pEntry = (*pArr)[ pArr->Count() - 1 ]; + + // wurde der Inhalt geloescht, so loesche jetzt auch noch den temp. + // erzeugten Node + if( bDelCntnt ) + { + SwDoc* pDoc = rBox.GetFrmFmt()->GetDoc(); + _DEBUG_REDLINE( pDoc ) + + if( pDoc->IsRedlineOn() ) + { + SwPosition aTmpPos( rIdx ); + pEntry->pUndo = PrepareRedline( pDoc, rBox, aTmpPos, pEntry->bJoin, false ); + } + SwNodeIndex aDelIdx( *rBox.GetSttNd(), 1 ); + rBox.GetFrmFmt()->GetDoc()->GetNodes().Delete( aDelIdx, 1 ); + _DEBUG_REDLINE( pDoc ) + } + + pEntry->nOffset = rBox.GetSttIdx() - pEntry->nBoxIdx; +} + +// PrepareRedline is called from AddBoxAfter() and from Redo() in slightly different situations. +// bRedo is set by calling from Redo() +// rJoin is false by calling from AddBoxAfter() and will be set if the old and new content has +// been merged. +// rJoin is true if Redo() is calling and the content has already been merged + +SwUndo* SwUndoTblCpyTbl::PrepareRedline( SwDoc* pDoc, const SwTableBox& rBox, + const SwPosition& rPos, bool& rJoin, bool bRedo ) +{ + SwUndo *pUndo = 0; + // b62341295: Redline for copying tables + // What's to do? + // Mark the cell content before rIdx as insertion, + // mark the cell content behind rIdx as deletion + // merge text nodes at rIdx if possible + RedlineMode_t eOld = pDoc->GetRedlineMode(); + pDoc->SetRedlineMode_intern((RedlineMode_t)( ( eOld | nsRedlineMode_t::REDLINE_DONTCOMBINE_REDLINES ) & + ~nsRedlineMode_t::REDLINE_IGNORE )); + SwPosition aInsertEnd( rPos ); + SwTxtNode* pTxt; + if( !rJoin ) + { + // If the content is not merged, the end of the insertion is at the end of the node + // _before_ the given position rPos + --aInsertEnd.nNode; + pTxt = aInsertEnd.nNode.GetNode().GetTxtNode(); + if( pTxt ) + { + aInsertEnd.nContent.Assign( pTxt, pTxt->GetTxt().Len() ); + if( !bRedo && rPos.nNode.GetNode().GetTxtNode() ) + { // Try to merge, if not called by Redo() + rJoin = true; + pTxt->JoinNext(); + } + } + else + aInsertEnd.nContent = SwIndex( 0 ); + } + // For joined (merged) contents the start of deletionm and end of insertion are identical + // otherwise adjacent nodes. + SwPosition aDeleteStart( rJoin ? aInsertEnd : rPos ); + if( !rJoin ) + { + pTxt = aDeleteStart.nNode.GetNode().GetTxtNode(); + if( pTxt ) + aDeleteStart.nContent.Assign( pTxt, 0 ); + } + SwPosition aCellEnd( SwNodeIndex( *rBox.GetSttNd()->EndOfSectionNode(), -1 ) ); + pTxt = aCellEnd.nNode.GetNode().GetTxtNode(); + if( pTxt ) + aCellEnd.nContent.Assign( pTxt, pTxt->GetTxt().Len() ); + if( aDeleteStart != aCellEnd ) + { // If the old (deleted) part is not empty, here we are... + SwPaM aDeletePam( aDeleteStart, aCellEnd ); + pUndo = new SwUndoRedlineDelete( aDeletePam, UNDO_DELETE ); + pDoc->AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_DELETE, aDeletePam ), true ); + } + else if( !rJoin ) // If the old part is empty and joined, we are finished + { // if it is not joined, we have to delete this empty paragraph + aCellEnd = SwPosition( + SwNodeIndex( *rBox.GetSttNd()->EndOfSectionNode() )); + SwPaM aTmpPam( aDeleteStart, aCellEnd ); + pUndo = new SwUndoDelete( aTmpPam, sal_True ); + } + SwPosition aCellStart( SwNodeIndex( *rBox.GetSttNd(), 2 ) ); + pTxt = aCellStart.nNode.GetNode().GetTxtNode(); + if( pTxt ) + aCellStart.nContent.Assign( pTxt, 0 ); + if( aCellStart != aInsertEnd ) // An empty insertion will not been marked + { + SwPaM aTmpPam( aCellStart, aInsertEnd ); + pDoc->AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_INSERT, aTmpPam ), true ); + } + + pDoc->SetRedlineMode_intern( eOld ); + return pUndo; +} + + +sal_Bool SwUndoTblCpyTbl::InsertRow( SwTable& rTbl, const SwSelBoxes& rBoxes, + sal_uInt16 nCnt ) +{ + SwTableNode* pTblNd = (SwTableNode*)rTbl.GetTabSortBoxes()[0]-> + GetSttNd()->FindTableNode(); + + SwTableSortBoxes aTmpLst( 0, 5 ); + pInsRowUndo = new SwUndoTblNdsChg( UNDO_TABLE_INSROW, rBoxes, *pTblNd, + 0, 0, nCnt, sal_True, sal_False ); + aTmpLst.Insert( &rTbl.GetTabSortBoxes(), 0, rTbl.GetTabSortBoxes().Count() ); + + sal_Bool bRet = rTbl.InsertRow( rTbl.GetFrmFmt()->GetDoc(), rBoxes, nCnt, sal_True ); + if( bRet ) + pInsRowUndo->SaveNewBoxes( *pTblNd, aTmpLst ); + else + delete pInsRowUndo, pInsRowUndo = 0; + return bRet; +} + +sal_Bool SwUndoTblCpyTbl::IsEmpty() const +{ + return !pInsRowUndo && !pArr->Count(); +} + + +////////////////////////////////////////////////////////////////////////// + +SwUndoCpyTbl::SwUndoCpyTbl() + : SwUndo( UNDO_CPYTBL ), pDel( 0 ), nTblNode( 0 ) +{ +} + +SwUndoCpyTbl::~SwUndoCpyTbl() +{ + delete pDel; +} + +void SwUndoCpyTbl::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + SwTableNode* pTNd = rDoc.GetNodes()[ nTblNode ]->GetTableNode(); + + // harte SeitenUmbrueche am nachfolgenden Node verschieben + SwCntntNode* pNextNd = rDoc.GetNodes()[ pTNd->EndOfSectionIndex()+1 ]->GetCntntNode(); + if( pNextNd ) + { + SwFrmFmt* pTableFmt = pTNd->GetTable().GetFrmFmt(); + const SfxPoolItem *pItem; + + if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_PAGEDESC, + sal_False, &pItem ) ) + pNextNd->SetAttr( *pItem ); + + if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_BREAK, + sal_False, &pItem ) ) + pNextNd->SetAttr( *pItem ); + } + + SwPaM aPam( *pTNd, *pTNd->EndOfSectionNode(), 0 , 1 ); + pDel = new SwUndoDelete( aPam, sal_True ); +} + +void SwUndoCpyTbl::RedoImpl(::sw::UndoRedoContext & rContext) +{ + pDel->UndoImpl(rContext); + delete pDel, pDel = 0; +} + + +////////////////////////////////////////////////////////////////////////// + +SwUndoSplitTbl::SwUndoSplitTbl( const SwTableNode& rTblNd, + SwSaveRowSpan* pRowSp, sal_uInt16 eMode, sal_Bool bNewSize ) + : SwUndo( UNDO_SPLIT_TABLE ), + nTblNode( rTblNd.GetIndex() ), nOffset( 0 ), mpSaveRowSpan( pRowSp ), pSavTbl( 0 ), + pHistory( 0 ), nMode( eMode ), nFmlEnd( 0 ), bCalcNewSize( bNewSize ) +{ + switch( nMode ) + { + case HEADLINE_BOXATRCOLLCOPY: + pHistory = new SwHistory; + // kein break; + case HEADLINE_BORDERCOPY: + case HEADLINE_BOXATTRCOPY: + pSavTbl = new _SaveTable( rTblNd.GetTable(), 1, sal_False ); + break; + } +} + +SwUndoSplitTbl::~SwUndoSplitTbl() +{ + delete pSavTbl; + delete pHistory; + delete mpSaveRowSpan; +} + +void SwUndoSplitTbl::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc *const pDoc = & rContext.GetDoc(); + SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor()); + + pPam->DeleteMark(); + SwNodeIndex& rIdx = pPam->GetPoint()->nNode; + rIdx = nTblNode + nOffset; + + //Den implizit erzeugten Absatz wieder entfernen. + pDoc->GetNodes().Delete( rIdx, 1 ); + + rIdx = nTblNode + nOffset; + SwTableNode* pTblNd = rIdx.GetNode().GetTableNode(); + SwTable& rTbl = pTblNd->GetTable(); + + SwTableFmlUpdate aMsgHnt( &rTbl ); + aMsgHnt.eFlags = TBL_BOXPTR; + pDoc->UpdateTblFlds( &aMsgHnt ); + + switch( nMode ) + { + case HEADLINE_BOXATRCOLLCOPY: + if( pHistory ) + pHistory->TmpRollback( pDoc, nFmlEnd ); + + // kein break + case HEADLINE_BOXATTRCOPY: + case HEADLINE_BORDERCOPY: + { + pSavTbl->CreateNew( rTbl, sal_False ); + pSavTbl->RestoreAttr( rTbl ); + } + break; + + case HEADLINE_CNTNTCOPY: + // die erzeugte 1. Line muss wieder entfernt werden + { + SwSelBoxes aSelBoxes; + SwTableBox* pBox = rTbl.GetTblBox( nTblNode + nOffset + 1 ); + rTbl.SelLineFromBox( pBox, aSelBoxes, sal_True ); + _FndBox aTmpBox( 0, 0 ); + aTmpBox.SetTableLines( aSelBoxes, rTbl ); + aTmpBox.DelFrms( rTbl ); + rTbl.DeleteSel( pDoc, aSelBoxes, 0, 0, sal_False, sal_False ); + } + break; + } + + pDoc->GetNodes().MergeTable( rIdx ); + + if( pHistory ) + { + pHistory->TmpRollback( pDoc, 0 ); + pHistory->SetTmpEnd( pHistory->Count() ); + } + if( mpSaveRowSpan ) + { + pTblNd = rIdx.GetNode().FindTableNode(); + if( pTblNd ) + pTblNd->GetTable().RestoreRowSpan( *mpSaveRowSpan ); + } + ClearFEShellTabCols(); +} + +void SwUndoSplitTbl::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc *const pDoc = & rContext.GetDoc(); + SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor()); + + pPam->DeleteMark(); + pPam->GetPoint()->nNode = nTblNode; + pDoc->SplitTable( *pPam->GetPoint(), nMode, bCalcNewSize ); + + ClearFEShellTabCols(); +} + +void SwUndoSplitTbl::RepeatImpl(::sw::RepeatContext & rContext) +{ + SwPaM *const pPam = & rContext.GetRepeatPaM(); + SwDoc *const pDoc = & rContext.GetDoc(); + + pDoc->SplitTable( *pPam->GetPoint(), nMode, bCalcNewSize ); + ClearFEShellTabCols(); +} + +void SwUndoSplitTbl::SaveFormula( SwHistory& rHistory ) +{ + if( !pHistory ) + pHistory = new SwHistory; + + nFmlEnd = rHistory.Count(); + pHistory->Move( 0, &rHistory ); +} + + +////////////////////////////////////////////////////////////////////////// + +SwUndoMergeTbl::SwUndoMergeTbl( const SwTableNode& rTblNd, + const SwTableNode& rDelTblNd, + sal_Bool bWithPrv, sal_uInt16 nMd ) + : SwUndo( UNDO_MERGE_TABLE ), pSavTbl( 0 ), + pHistory( 0 ), nMode( nMd ), bWithPrev( bWithPrv ) +{ + // Endnode der letzen Tabellenzelle merken, die auf der Position verbleibt + if( bWithPrev ) + nTblNode = rDelTblNd.EndOfSectionIndex() - 1; + else + nTblNode = rTblNd.EndOfSectionIndex() - 1; + + aName = rDelTblNd.GetTable().GetFrmFmt()->GetName(); + pSavTbl = new _SaveTable( rDelTblNd.GetTable() ); + + pSavHdl = bWithPrev ? new _SaveTable( rTblNd.GetTable(), 1 ) : 0; +} + +SwUndoMergeTbl::~SwUndoMergeTbl() +{ + delete pSavTbl; + delete pSavHdl; + delete pHistory; +} + +void SwUndoMergeTbl::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc *const pDoc = & rContext.GetDoc(); + SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor()); + + pPam->DeleteMark(); + SwNodeIndex& rIdx = pPam->GetPoint()->nNode; + rIdx = nTblNode; + + SwTableNode* pTblNd = rIdx.GetNode().FindTableNode(); + SwTable* pTbl = &pTblNd->GetTable(); + + SwTableFmlUpdate aMsgHnt( pTbl ); + aMsgHnt.eFlags = TBL_BOXPTR; + pDoc->UpdateTblFlds( &aMsgHnt ); + + //Lines fuer das Layout-Update herausuchen. + _FndBox aFndBox( 0, 0 ); + aFndBox.SetTableLines( *pTbl ); + aFndBox.DelFrms( *pTbl ); + // ? TL_CHART2: notification or locking of controller required ? + + SwTableNode* pNew = pDoc->GetNodes().SplitTable( rIdx, sal_True, sal_False ); + + //Layout updaten + aFndBox.MakeFrms( *pTbl ); + // ? TL_CHART2: notification or locking of controller required ? + + if( bWithPrev ) + { + // den Namen umsetzen + pNew->GetTable().GetFrmFmt()->SetName( pTbl->GetFrmFmt()->GetName() ); + pSavHdl->RestoreAttr( pNew->GetTable() ); + } + else + pTbl = &pNew->GetTable(); + pTbl->GetFrmFmt()->SetName( aName ); + +// pSavTbl->CreateNew( *pTbl, sal_False ); + pSavTbl->RestoreAttr( *pTbl ); + + + if( pHistory ) + { + pHistory->TmpRollback( pDoc, 0 ); + pHistory->SetTmpEnd( pHistory->Count() ); + } + + // fuer die neue Tabelle die Frames anlegen + SwNodeIndex aTmpIdx( *pNew ); + pNew->MakeFrms( &aTmpIdx ); + + // Cursor irgendwo in den Content stellen + SwCntntNode* pCNd = pDoc->GetNodes().GoNext( &rIdx ); + pPam->GetPoint()->nContent.Assign( pCNd, 0 ); + + ClearFEShellTabCols(); + + // TL_CHART2: need to inform chart of probably changed cell names + SwChartDataProvider *pPCD = pDoc->GetChartDataProvider(); + if (pPCD) + { + pDoc->UpdateCharts( pTbl->GetFrmFmt()->GetName() ); + pDoc->UpdateCharts( pNew->GetTable().GetFrmFmt()->GetName() ); + } +} + +void SwUndoMergeTbl::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc *const pDoc = & rContext.GetDoc(); + SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor()); + + pPam->DeleteMark(); + pPam->GetPoint()->nNode = nTblNode; + if( bWithPrev ) + pPam->GetPoint()->nNode = nTblNode + 3; + else + pPam->GetPoint()->nNode = nTblNode; + + pDoc->MergeTable( *pPam->GetPoint(), bWithPrev, nMode ); + + ClearFEShellTabCols(); +} + +void SwUndoMergeTbl::RepeatImpl(::sw::RepeatContext & rContext) +{ + SwDoc *const pDoc = & rContext.GetDoc(); + SwPaM *const pPam = & rContext.GetRepeatPaM(); + + pDoc->MergeTable( *pPam->GetPoint(), bWithPrev, nMode ); + ClearFEShellTabCols(); +} + +void SwUndoMergeTbl::SaveFormula( SwHistory& rHistory ) +{ + if( !pHistory ) + pHistory = new SwHistory; + pHistory->Move( 0, &rHistory ); +} + + +////////////////////////////////////////////////////////////////////////// + +void InsertSort( SvUShorts& rArr, sal_uInt16 nIdx, sal_uInt16* pInsPos ) +{ + sal_uInt16 nO = rArr.Count(), nM, nU = 0; + if( nO > 0 ) + { + nO--; + while( nU <= nO ) + { + nM = nU + ( nO - nU ) / 2; + if( *(rArr.GetData() + nM) == nIdx ) + { + OSL_FAIL( "Index already exists. This should never happen." ); + return; + } + if( *(rArr.GetData() + nM) < nIdx ) + nU = nM + 1; + else if( nM == 0 ) + break; + else + nO = nM - 1; + } + } + rArr.Insert( nIdx, nU ); + if( pInsPos ) + *pInsPos = nU; +} + +void InsertSort( SvULongs& rArr, sal_uLong nIdx, sal_uInt16* pInsPos ) +{ + sal_uInt16 nO = rArr.Count(), nM, nU = 0; + if( nO > 0 ) + { + nO--; + while( nU <= nO ) + { + nM = nU + ( nO - nU ) / 2; + if( *(rArr.GetData() + nM) == nIdx ) + { + OSL_FAIL( "Index ist schon vorhanden, darf nie sein!" ); + return; + } + if( *(rArr.GetData() + nM) < nIdx ) + nU = nM + 1; + else if( nM == 0 ) + break; + else + nO = nM - 1; + } + } + rArr.Insert( nIdx, nU ); + if( pInsPos ) + *pInsPos = nU; +} + +#if OSL_DEBUG_LEVEL > 1 + + +void CheckTable( const SwTable& rTbl ) +{ + const SwNodes& rNds = rTbl.GetFrmFmt()->GetDoc()->GetNodes(); + const SwTableSortBoxes& rSrtArr = rTbl.GetTabSortBoxes(); + for( sal_uInt16 n = 0; n < rSrtArr.Count(); ++n ) + { + const SwTableBox* pBox = rSrtArr[ n ]; + const SwNode* pNd = pBox->GetSttNd(); + OSL_ENSURE( rNds[ pBox->GetSttIdx() ] == pNd, "Box mit falchem StartNode" ); + } +} +#endif + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |