Files
libreoffice/sw/source/core/undo/untbl.cxx
Stephan Bergmann 8bc3751ea3 bool improvements
Change-Id: Ibeb658e73b588f90242c95d23149f2ef45a7a815
2014-01-28 20:26:21 +01:00

3119 lines
100 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include <vector>
#include <boost/shared_ptr.hpp>
#include <UndoTable.hxx>
#include <UndoRedline.hxx>
#include <UndoDelete.hxx>
#include <UndoSplitMove.hxx>
#include <UndoCore.hxx>
#include <hintids.hxx>
#include <hints.hxx>
#include <editeng/formatbreakitem.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>
#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>
#ifdef DBG_UTIL
#define CHECK_TABLE(t) (t).CheckConsistency();
#else
#define CHECK_TABLE(t)
#endif
#ifdef DBG_UTIL
void sw_DebugRedline( const SwDoc* pDoc ); // docredln.cxx
#define _DEBUG_REDLINE( pDoc ) sw_DebugRedline( pDoc );
#else
#define _DEBUG_REDLINE( pDoc )
#endif
extern void ClearFEShellTabCols();
typedef std::vector<boost::shared_ptr<SfxItemSet> > SfxItemSets;
class SwUndoSaveSections : public boost::ptr_vector<SwUndoSaveSection> {
public:
SwUndoSaveSections(size_type n) : boost::ptr_vector<SwUndoSaveSection>(n) {}
};
class SwUndoMoves : public boost::ptr_vector<SwUndoMove> {};
struct SwTblToTxtSave;
class SwTblToTxtSaves : public boost::ptr_vector<SwTblToTxtSave> {
public:
SwTblToTxtSaves(size_type n) : boost::ptr_vector<SwTblToTxtSave>(n) {}
};
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();
};
class _UndoTblCpyTbl_Entries : public boost::ptr_vector<_UndoTblCpyTbl_Entry> {};
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;
bool bModifyBox : 1;
bool bSaveFormula : 1;
bool bNewModel : 1;
public:
_SaveTable( const SwTable& rTbl, sal_uInt16 nLnCnt = USHRT_MAX,
bool bSaveFml = true );
~_SaveTable();
sal_uInt16 AddFmt( SwFrmFmt* pFmt, bool bIsLine );
void NewFrmFmt( const SwTableLine* , const SwTableBox*, sal_uInt16 nFmtPos,
SwFrmFmt* pOldFmt );
void RestoreAttr( SwTable& rTbl, bool bModifyBox = false );
void SaveCntntAttrs( SwDoc* pDoc );
void CreateNew( SwTable& rTbl, bool bCreateFrms = true,
bool bRestoreChart = true );
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( std::vector<sal_uInt16>& rArr, sal_uInt16 nIdx, sal_uInt16* pInsPos = 0 );
#if OSL_DEBUG_LEVEL > 0
#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;
sal_Int32 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, sal_Int32 nCntnt );
~SwTblToTxtSave() { delete m_pHstry; }
};
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 std::vector<sal_uInt16> *pColArr,
const OUString & 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 std::vector<sal_uInt16>(*pColArr);
}
if( pTAFmt )
pAutoFmt = new SwTableAutoFmt( *pTAFmt );
// consider redline
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, "no TableNode" );
pTblNd->DelFrms();
if( IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() ))
rDoc.DeleteRedline( *pTblNd, true, USHRT_MAX );
RemoveIdxFromSection( rDoc, nSttNode );
// move hard page breaks into next node
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 );
delete pDDEFldType, pDDEFldType = 0;
}
if( (pRedlData && IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() )) ||
( !( nsRedlineMode_t::REDLINE_IGNORE & GetRedlineMode() ) &&
!rDoc.GetRedlineTbl().empty() ))
{
SwPaM aPam( *pTblNode->EndOfSectionNode(), *pTblNode, 1 );
SwCntntNode* pCNd = aPam.GetCntntNode( 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 SwRangeRedline( *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(UndoArg1, SW_RES(STR_START_QUOTE));
aRewriter.AddRule(UndoArg2, sTblNm);
aRewriter.AddRule(UndoArg3, SW_RES(STR_END_QUOTE));
return aRewriter;
}
SwTblToTxtSave::SwTblToTxtSave( SwDoc& rDoc, sal_uLong nNd, sal_uLong nEndIdx, sal_Int32 nCnt )
: m_nSttNd( nNd ), m_nEndNd( nEndIdx), m_nCntnt( nCnt ), m_pHstry( 0 )
{
// keep attributes of the joined node
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().getLength(), 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( (SwTblToTxtSaves::size_type)rTbl.GetTabSortBoxes().size() );
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 SwFrmFmts& rFrmFmtTbl = *pTblNd->GetDoc()->GetSpzFrmFmts();
for( sal_uInt16 n = 0; n < rFrmFmtTbl.size(); ++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();
// now collect all Uppers
SwNode2Layout aNode2Layout( aFrmIdx.GetNode() );
// create TableNode structure
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 );
// create old table structure
pTblSave->CreateNew( pTblNd->GetTable() );
if( pDDEFldType )
{
SwDDEFieldType* pNewType = (SwDDEFieldType*)rDoc.InsertFldType(
*pDDEFldType);
SwDDETable* pDDETbl = new SwDDETable( pTblNd->GetTable(), pNewType );
pTblNd->SetNewTable( pDDETbl, sal_False );
delete pDDEFldType, pDDEFldType = 0;
}
if( bCheckNumFmt )
{
SwTableSortBoxes& rBxs = pTblNd->GetTable().GetTabSortBoxes();
for (size_t nBoxes = rBxs.size(); 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 );
// Is a table selection requested?
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();
}
// located in untbl.cxx and only an Undo object is allowed to call it
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;
}
}
// than create table structure partially. First a single line that contains
// all boxes. The correct structure is than taken from SaveStruct.
SwTableBoxFmt* pBoxFmt = GetDoc()->MakeTableBoxFmt();
SwTableLineFmt* pLineFmt = GetDoc()->MakeTableLineFmt();
SwTableLine* pLine = new SwTableLine( pLineFmt, rSavedData.size(), 0 );
pTblNd->GetTable().GetTabLines().insert( pTblNd->GetTable().GetTabLines().begin(), pLine );
std::vector<sal_uLong> aBkmkArr;
for( sal_uInt16 n = rSavedData.size(); n; )
{
const 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 - ( ( SAL_MAX_INT32 != pSave->m_nCntnt ) ? 1 : 0);
SwTxtNode* pTxtNd = aSttIdx.GetNode().GetTxtNode();
if( SAL_MAX_INT32 != pSave->m_nCntnt )
{
// split at ContentPosition, delete previous char (= separator)
OSL_ENSURE( pTxtNd, "Where is my TextNode?" );
SwIndex aCntPos( pTxtNd, pSave->m_nCntnt - 1 );
pTxtNd->EraseText( aCntPos, 1 );
SwCntntNode* pNewNd = pTxtNd->SplitCntntNode(
SwPosition( aSttIdx, aCntPos ));
if( !aBkmkArr.empty() )
_RestoreCntntIdx( aBkmkArr, *pNewNd, pSave->m_nCntnt,
pSave->m_nCntnt + 1 );
}
else
{
aBkmkArr.clear();
if( pTxtNd )
_SaveCntntIdx( GetDoc(), aSttIdx.GetIndex(),
pTxtNd->GetTxt().getLength(), 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().insert( pLine->GetTabBoxes().begin(), pBox );
}
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(); // log off all indices
pPam->DeleteMark();
SwTableNode* pTblNd = pPam->GetNode()->GetTableNode();
OSL_ENSURE( pTblNd, "Could not find any TableNode" );
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( "Where is the TextNode now?" );
}
pPam->GetPoint()->nNode = aSaveIdx;
pPam->GetPoint()->nContent.Assign( pCNd, 0 );
pPam->SetMark(); // log off all indices
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, sal_Int32 nCntntIdx )
{
SwTblToTxtSave* pNew = new SwTblToTxtSave( rDoc, nNdIdx, nEndIdx, nCntntIdx );
pBoxSaves->push_back( pNew );
}
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 was splitted previously
SwNodeIndex aIdx( rDoc.GetNodes(), nTblNd );
SwTableNode *const pTNd = aIdx.GetNode().GetTableNode();
OSL_ENSURE( pTNd, "Could not find a TableNode" );
RemoveIdxFromSection( rDoc, nTblNd );
sTblNm = pTNd->GetTable().GetFrmFmt()->GetName();
if( pHistory )
{
pHistory->TmpRollback( &rDoc, 0 );
pHistory->SetTmpEnd( pHistory->Count() );
}
if( pDelBoxes )
{
pTNd->DelFrms();
SwTable& rTbl = pTNd->GetTable();
for( sal_uInt16 n = pDelBoxes->size(); n; )
{
SwTableBox* pBox = rTbl.GetTblBox( (*pDelBoxes)[ --n ] );
if( pBox )
::_DeleteBox( rTbl, pBox, 0, false, false );
else {
OSL_ENSURE( !this, "Where is my box?" );
}
}
}
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;
// than move, relatively, the Crsr/etc. again
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 );
// than move, relatively, the Crsr/etc. again
pPos->nContent.Assign(pTxtNd, pTxtNd->GetTxt().getLength());
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 std::vector<sal_uLong>;
pDelBoxes->push_back( rBox.GetSttIdx() );
}
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().empty(), "Table without content" );
const SwStartNode *pSttNd = rTbl.GetTabSortBoxes()[ 0 ]->GetSttNd();
OSL_ENSURE( pSttNd, "Box without content" );
nTblNd = pSttNd->StartOfSectionIndex();
}
void SwUndoTblHeadline::UndoImpl(::sw::UndoRedoContext & rContext)
{
SwDoc & rDoc = rContext.GetDoc();
SwTableNode* pTNd = rDoc.GetNodes()[ nTblNd ]->GetTableNode();
OSL_ENSURE( pTNd, "could not find any TableNode" );
rDoc.SetRowsToRepeat( pTNd->GetTable(), nOldHeadline );
}
void SwUndoTblHeadline::RedoImpl(::sw::UndoRedoContext & rContext)
{
SwDoc & rDoc = rContext.GetDoc();
SwTableNode* pTNd = rDoc.GetNodes()[ nTblNd ]->GetTableNode();
OSL_ENSURE( pTNd, "could not find any TableNode" );
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, bool bSaveFml )
: aTblSet( *rTbl.GetFrmFmt()->GetAttrSet().GetPool(), aTableSetRange ),
pSwTable( &rTbl ), nLineCount( nLnCnt ), bSaveFormula( bSaveFml )
{
bModifyBox = 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().size();
for( sal_uInt16 n = 1; n < nLnCnt; ++n )
pLn = new _SaveLine( pLn, *rTbl.GetTabLines()[ n ], *this );
aFrmFmts.clear();
pSwTable = 0;
}
_SaveTable::~_SaveTable()
{
delete pLine;
}
sal_uInt16 _SaveTable::AddFmt( SwFrmFmt* pFmt, bool bIsLine )
{
sal_uInt16 nRet = aFrmFmts.GetPos( pFmt );
if( USHRT_MAX == nRet )
{
// Create copy of ItemSet
boost::shared_ptr<SfxItemSet> pSet( new SfxItemSet( *pFmt->GetAttrSet().GetPool(),
bIsLine ? aTableLineSetRange : aTableBoxSetRange ) );
pSet->Put( pFmt->GetAttrSet() );
// When a formula is set, never save the value. It possibly must be
// recalculated.
// Save formulas always in plain text.
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 );
}
}
nRet = aSets.size();
aSets.push_back( pSet );
aFrmFmts.insert( aFrmFmts.begin() + nRet, pFmt );
}
return nRet;
}
void _SaveTable::RestoreAttr( SwTable& rTbl, bool bMdfyBox )
{
sal_uInt16 n;
bModifyBox = bMdfyBox;
// first, get back attributes of TableFrmFormat
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 );
}
// for safety, invalidate all TableFrames
SwIterator<SwTabFrm,SwFmt> aIter( *pFmt );
for( SwTabFrm* pLast = aIter.First(); pLast; pLast = aIter.Next() )
if( pLast->GetTable() == &rTbl )
{
pLast->InvalidateAll();
pLast->SetCompletePaint();
}
// fill FrmFmts with defaults (0)
pFmt = 0;
for( n = aSets.size(); n; --n )
aFrmFmts.push_back( pFmt );
sal_uInt16 nLnCnt = nLineCount;
if( USHRT_MAX == nLnCnt )
nLnCnt = rTbl.GetTabLines().size();
_SaveLine* pLn = pLine;
for( n = 0; n < nLnCnt; ++n, pLn = pLn->pNext )
{
if( !pLn )
{
OSL_ENSURE( !this, "Number of lines changed" );
break;
}
pLn->RestoreAttr( *rTbl.GetTabLines()[ n ], *this );
}
aFrmFmts.clear();
bModifyBox = false;
}
void _SaveTable::SaveCntntAttrs( SwDoc* pDoc )
{
pLine->SaveCntntAttrs( pDoc );
}
void _SaveTable::CreateNew( SwTable& rTbl, bool bCreateFrms,
bool bRestoreChart )
{
sal_uInt16 n;
_FndBox aTmpBox( 0, 0 );
aTmpBox.DelFrms( rTbl );
// first, get back attributes of TableFrmFormat
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 must have a format
SwTableBox aParent( (SwTableBoxFmt*)pFmt, rTbl.GetTabLines().size(), 0 );
// fill FrmFmts with defaults (0)
pFmt = 0;
for( n = aSets.size(); n; --n )
aFrmFmts.push_back( pFmt );
pLine->CreateNew( rTbl, aParent, *this );
aFrmFmts.clear();
// add new lines, delete old ones
sal_uInt16 nOldLines = nLineCount;
if( USHRT_MAX == nLineCount )
nOldLines = rTbl.GetTabLines().size();
SwDoc *pDoc = rTbl.GetFrmFmt()->GetDoc();
SwChartDataProvider *pPCD = pDoc->GetChartDataProvider();
for( n = 0; n < aParent.GetTabLines().size(); ++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.size();
for (sal_uInt16 k = 0; k < nBoxes; ++k)
{
SwTableBox *pBox = rBoxes[k];
if (pPCD)
pPCD->DeleteBox( &rTbl, *pBox );
}
rTbl.GetTabLines()[n] = pLn;
delete pOld;
}
else
rTbl.GetTabLines().insert( rTbl.GetTabLines().begin() + n, pLn );
}
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.size();
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 );
}
}
for( SwTableLines::const_iterator it = rTbl.GetTabLines().begin() + n;
it != rTbl.GetTabLines().begin() + nOldLines; ++it )
delete *it;
rTbl.GetTabLines().erase( rTbl.GetTabLines().begin() + n, rTbl.GetTabLines().begin() + nOldLines );
}
aParent.GetTabLines().erase( aParent.GetTabLines().begin(), aParent.GetTabLines().begin() + 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[nFmtPos] = pFmt;
}
// first re-assign Frms
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();
}
}
}
// than re-assign myself
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().size(); ++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().size(); ++n, pBx = pBx->pNext )
{
if( !pBx )
{
OSL_ENSURE( !this, "Number of boxes changed" );
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[ nItemSet ] = pFmt;
}
SwTableLine* pNew = new SwTableLine( pFmt, 1, &rParent );
rParent.GetTabLines().push_back( pNew );
// 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().size(); ++n )
pLn = new _SaveLine( pLn, *rBox.GetTabLines()[ n ], rSTbl );
}
}
_SaveBox::~_SaveBox()
{
if( ULONG_MAX == nSttNode ) // no 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 ) // no EndBox
{
if( !rBox.GetTabLines().size() )
{
OSL_ENSURE( !this, "Number of lines changed" );
}
else
{
_SaveLine* pLn = Ptrs.pLine;
for( sal_uInt16 n = 0; n < rBox.GetTabLines().size(); ++n, pLn = pLn->pNext )
{
if( !pLn )
{
OSL_ENSURE( !this, "Number of lines changed" );
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 )
{
boost::shared_ptr<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 not anymore at the same node" );
}
}
void _SaveBox::SaveCntntAttrs( SwDoc* pDoc )
{
if( ULONG_MAX == nSttNode ) // no EndBox
{
// continue in current line
Ptrs.pLine->SaveCntntAttrs( pDoc );
}
else
{
sal_uLong nEnd = pDoc->GetNodes()[ nSttNode ]->EndOfSectionIndex();
Ptrs.pCntntAttrs = new SfxItemSets( (sal_uInt8)(nEnd - nSttNode - 1 ) );
for( sal_uLong n = nSttNode + 1; n < nEnd; ++n )
{
SwCntntNode* pCNd = pDoc->GetNodes()[ n ]->GetCntntNode();
if( pCNd )
{
boost::shared_ptr<SfxItemSet> pSet;
if( pCNd->HasSwAttrSet() )
{
pSet.reset( new SfxItemSet( pDoc->GetAttrPool(),
aSave_BoxCntntSet ) );
pSet->Put( *pCNd->GetpSwAttrSet() );
}
Ptrs.pCntntAttrs->push_back( pSet );
}
}
}
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[nItemSet] = pFmt;
}
if( ULONG_MAX == nSttNode ) // no EndBox
{
SwTableBox* pNew = new SwTableBox( pFmt, 1, &rParent );
rParent.GetTabBoxes().push_back( pNew );
Ptrs.pLine->CreateNew( rTbl, *pNew, rSTbl );
}
else
{
// search box for StartNode in old table
SwTableBox* pBox = rTbl.GetTblBox( nSttNode );
OSL_ENSURE( pBox, "Where is my TableBox?" );
SwFrmFmt* pOld = pBox->GetFrmFmt();
pBox->RegisterToFormat( *pFmt );
if( !pOld->GetDepends() )
delete pOld;
pBox->setRowSpan( nRowSpan );
SwTableBoxes* pTBoxes = &pBox->GetUpper()->GetTabBoxes();
pTBoxes->erase( std::find( pTBoxes->begin(), pTBoxes->end(), pBox ) );
pBox->SetUpper( &rParent );
pTBoxes = &rParent.GetTabBoxes();
pTBoxes->push_back( pBox );
}
if( pNext )
pNext->CreateNew( rTbl, rParent, rSTbl );
}
// UndoObject for attribute changes on table
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, "no TableNode" );
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 for AutoFormat on Table
SwUndoTblAutoFmt::SwUndoTblAutoFmt( const SwTableNode& rTblNd,
const SwTableAutoFmt& rAFmt )
: SwUndo( UNDO_TABLE_AUTOFMT ),
nSttNode( rTblNd.GetIndex() ),
bSaveCntntAttr( sal_False )
, m_nRepeatHeading(rTblNd.GetTable().GetRowsToRepeat())
{
pSaveTbl = new _SaveTable( rTblNd.GetTable() );
if( rAFmt.IsFont() || rAFmt.IsJustify() )
{
// than also go over the ContentNodes of the EndBoxes and collect
// all paragraph attributes
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, "no TableNode" );
SwTable& table = pTblNd->GetTable();
_SaveTable* pOrig = new _SaveTable( table );
// than go also over the ContentNodes of the EndBoxes and collect
// all paragraph attributes
if( bSaveCntntAttr )
pOrig->SaveCntntAttrs( &rDoc );
if (bUndo)
{
for (size_t n = m_Undos.size(); 0 < n; --n)
{
m_Undos.at(n-1)->UndoImpl(rContext);
}
table.SetRowsToRepeat(m_nRepeatHeading);
}
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 ),
nMin( nMn ), nMax( nMx ),
nSttNode( rTblNd.GetIndex() ), nCurrBox( 0 ),
nCount( nCnt ), nRelDiff( 0 ), nAbsDiff( 0 ),
nSetColType( USHRT_MAX ),
bFlag( bFlg ),
bSameHeight( bSmHght )
{
const SwTable& rTbl = rTblNd.GetTable();
pSaveTbl = new _SaveTable( rTbl );
// and remember selection
ReNewBoxes( rBoxes );
}
SwUndoTblNdsChg::SwUndoTblNdsChg( SwUndoId nAction,
const SwSelBoxes& rBoxes,
const SwTableNode& rTblNd )
: SwUndo( nAction ),
nMin( 0 ), nMax( 0 ),
nSttNode( rTblNd.GetIndex() ), nCurrBox( 0 ),
nCount( 0 ), nRelDiff( 0 ), nAbsDiff( 0 ),
nSetColType( USHRT_MAX ),
bFlag( sal_False ),
bSameHeight( sal_False )
{
const SwTable& rTbl = rTblNd.GetTable();
pSaveTbl = new _SaveTable( rTbl );
// and remember selection
ReNewBoxes( rBoxes );
}
void SwUndoTblNdsChg::ReNewBoxes( const SwSelBoxes& rBoxes )
{
if (rBoxes.size() != m_Boxes.size())
{
m_Boxes.clear();
for (size_t n = 0; n < rBoxes.size(); ++n)
{
m_Boxes.insert( rBoxes[n]->GetSttIdx() );
}
}
}
SwUndoTblNdsChg::~SwUndoTblNdsChg()
{
delete pSaveTbl;
}
void SwUndoTblNdsChg::SaveNewBoxes( const SwTableNode& rTblNd,
const SwTableSortBoxes& rOld )
{
const SwTable& rTbl = rTblNd.GetTable();
const SwTableSortBoxes& rTblBoxes = rTbl.GetTabSortBoxes();
OSL_ENSURE( ! IsDelBox(), "wrong Action" );
pNewSttNds.reset( new std::set<_BoxMove> );
size_t i = 0;
for (size_t n = 0; n < rOld.size(); ++i)
{
if( rOld[ n ] == rTblBoxes[ i ] )
++n;
else
// new box: insert sorted
pNewSttNds->insert( _BoxMove(rTblBoxes[ i ]->GetSttIdx()) );
}
for( ; i < rTblBoxes.size(); ++i )
// new box: insert sorted
pNewSttNds->insert( _BoxMove(rTblBoxes[ i ]->GetSttIdx()) );
}
static 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.GetPos( pLine );
pRet = rTableLines[nLineNo - 1];
return pRet;
}
static 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 std::vector<sal_uLong> &rNodeCnts )
{
const SwTable& rTbl = rTblNd.GetTable();
const SwTableSortBoxes& rTblBoxes = rTbl.GetTabSortBoxes();
OSL_ENSURE( ! IsDelBox(), "wrong Action" );
pNewSttNds.reset( new std::set<_BoxMove> );
OSL_ENSURE( rTbl.IsNewModel() || rOld.size() + nCount * rBoxes.size() == rTblBoxes.size(),
"unexpected boxes" );
OSL_ENSURE( rOld.size() <= rTblBoxes.size(), "more unexpected boxes" );
for (size_t n = 0, i = 0; i < rTblBoxes.size(); ++i)
{
if( ( n < rOld.size() ) &&
( rOld[ n ] == rTblBoxes[ i ] ) )
{
// box already known? Then nothing to be done.
++n;
}
else
{
// new box found: insert (obey sort order)
const SwTableBox* pBox = rTblBoxes[ i ];
// 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).GetPos(pBoxLine);
sal_uInt16 nLineNo = 0;
for (size_t j = 0; j < rBoxes.size(); ++j)
{
pCheckBox = rBoxes[j];
if( pCheckBox->GetUpper()->GetUpper() == pBox->GetUpper()->GetUpper() )
{
const SwTableLine* pCheckLine = pCheckBox->GetUpper();
sal_uInt16 nCheckLine = lcl_FindParentLines( rTbl, *pCheckBox ).
GetPos( 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)
size_t 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.
sal_Bool bNodesMoved =
( nNodes != ( pSourceBox->GetSttNd()->EndOfSectionIndex() -
pSourceBox->GetSttIdx() ) )
&& ( nNodes - 1 > nLineDiff );
pNewSttNds->insert( _BoxMove(pBox->GetSttIdx(), bNodesMoved) );
}
}
}
void SwUndoTblNdsChg::SaveSection( SwStartNode* pSttNd )
{
OSL_ENSURE( IsDelBox(), "wrong Action" );
if( pDelSects.get() == NULL )
pDelSects.reset( new SwUndoSaveSections( 10 ) );
SwTableNode* pTblNd = pSttNd->FindTableNode();
SwUndoSaveSection* pSave = new SwUndoSaveSection;
pSave->SaveSection( pSttNd->GetDoc(), SwNodeIndex( *pSttNd ));
pDelSects->push_back( pSave );
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, "no TableNode" );
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: add missing boxes in any line, they will be connected
// correctly when calling CreateNew
SwTableBox* pCpyBox = pTblNd->GetTable().GetTabSortBoxes()[0];
SwTableBoxes& rLnBoxes = pCpyBox->GetUpper()->GetTabBoxes();
// restore sections
for( sal_uInt16 n = pDelSects->size(); n; )
{
SwUndoSaveSection* pSave = &(*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.push_back( pBox );
}
pDelSects->clear();
}
else if( !pNewSttNds->empty() )
{
// Than the nodes have be moved and not deleted!
// But for that we need a temp array.
std::vector<_BoxMove> aTmp( pNewSttNds->begin(), pNewSttNds->end() );
// backwards
for (size_t n = aTmp.size(); n > 0 ; )
{
--n;
// delete box from table structure
sal_uLong nIdx = aTmp[n].index;
SwTableBox* pBox = pTblNd->GetTable().GetTblBox( nIdx );
OSL_ENSURE( pBox, "Where is my TableBox?" );
// TL_CHART2: notify chart about box to be removed
if (pPCD)
pPCD->DeleteBox( &pTblNd->GetTable(), *pBox );
if( aTmp[n].hasMoved )
{
SwNodeRange aRg( *pBox->GetSttNd(), 1,
*pBox->GetSttNd()->EndOfSectionNode() );
SwTableLine* pLine = lcl_FindTableLine( pTblNd->GetTable(), *pBox );
SwNodeIndex aInsPos( *(pLine->GetTabBoxes()[0]->GetSttNd()), 2 );
// adjust all StartNode indices
size_t i = n;
sal_uLong nSttIdx = aInsPos.GetIndex() - 2,
nNdCnt = aRg.aEnd.GetIndex() - aRg.aStart.GetIndex();
while( i && aTmp[ --i ].index > nSttIdx )
aTmp[ i ].index += nNdCnt;
// first delete box
delete pBox;
// than move nodes
rDoc.GetNodes()._MoveNodes( aRg, rDoc.GetNodes(), aInsPos, sal_False );
}
else
{ // first disconnect box from node, otherwise ~SwTableBox would
// access pBox->pSttNd, deleted by DeleteSection
pBox->RemoveFromTable();
rDoc.DeleteSection( rDoc.GetNodes()[ nIdx ] );
}
aDelBoxes.insert( aDelBoxes.end(), pBox );
}
}
else
{
// Remove nodes from nodes array (backwards!)
std::set<_BoxMove>::reverse_iterator it;
for( it = pNewSttNds->rbegin(); it != pNewSttNds->rend(); ++it )
{
sal_uLong nIdx = (*it).index;
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 );
pBox->RemoveFromTable(); // ~SwTableBox would access pBox->pSttNd
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->erase( std::find( pTBoxes->begin(), pTBoxes->end(), pCurrBox ) );
delete pCurrBox;
}
pSaveTbl->CreateNew( pTblNd->GetTable(), true, 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, "no TableNode" );
CHECK_TABLE( pTblNd->GetTable() )
SwSelBoxes aSelBoxes;
for (std::set<sal_uLong>::iterator it = m_Boxes.begin();
it != m_Boxes.end(); ++it)
{
SwTableBox* pBox = pTblNd->GetTable().GetTblBox( *it );
aSelBoxes.insert( pBox );
}
// create SelBoxes and call InsertCell/-Row/SplitTbl
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, true, 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 )
{
pDelSects->transfer( pDelSects->begin(), *pUndo->pDelSects.get() );
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, "Where is the TableNode?" );
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, "no TableNode" );
SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() );
aMsgHnt.eFlags = TBL_BOXPTR;
rDoc.UpdateTblFlds( &aMsgHnt );
_FndBox aTmpBox( 0, 0 );
// ? TL_CHART2: notification or locking of controller required ?
// 1. restore deleted boxes:
// Trick: add missing boxes in any line, they will be connected
// correctly when calling CreateNew
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;
std::set<sal_uLong>::iterator it;
for (it = m_Boxes.begin(); it != m_Boxes.end(); ++it)
{
aIdx = *it;
SwStartNode* pSttNd = rDoc.GetNodes().MakeTextSection( aIdx,
SwTableBoxStartNode, pColl );
pBox = new SwTableBox( (SwTableBoxFmt*)pCpyBox->GetFrmFmt(), *pSttNd,
pCpyBox->GetUpper() );
rLnBoxes.push_back( pBox );
aSelBoxes.insert( pBox );
}
CHECKTABLE(pTblNd->GetTable())
SwChartDataProvider *pPCD = rDoc.GetChartDataProvider();
// 2. deleted the inserted boxes
// delete nodes (from last to first)
for( n = aNewSttNds.size(); n; )
{
// remove box from table structure
sal_uLong nIdx = aNewSttNds[ --n ];
if( !nIdx && n )
{
nIdx = aNewSttNds[ --n ];
pBox = pTblNd->GetTable().GetTblBox( nIdx );
OSL_ENSURE( pBox, "Where is my TableBox?" );
if( !pSaveTbl->IsNewModel() )
rDoc.GetNodes().MakeTxtNode( SwNodeIndex(
*pBox->GetSttNd()->EndOfSectionNode() ), pColl );
// this was the separator -> restore moved ones
for( sal_uInt16 i = pMoves->size(); i; )
{
SwTxtNode* pTxtNd = 0;
sal_Int32 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() )
{
// delete the unnecessary node
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 )
{
// also delete not needed attributes
SwIndex aTmpIdx( pTxtNd, nDelPos );
if( pTxtNd->GetpSwpHints() && pTxtNd->GetpSwpHints()->Count() )
pTxtNd->RstTxtAttr( aTmpIdx, pTxtNd->GetTxt().getLength() - nDelPos + 1 );
// delete separator
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->erase( std::find(pTBoxes->begin(), pTBoxes->end(), pBox ) );
// delete indices from section
{
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(), true, 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() );
}
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->push_back( pUndo );
}
void SwUndoTblMerge::SetSelBoxes( const SwSelBoxes& rBoxes )
{
// memorize selection
for (size_t n = 0; n < rBoxes.size(); ++n)
{
m_Boxes.insert(rBoxes[n]->GetSttIdx());
}
// as separator for inserts of new boxes after shifting
aNewSttNds.push_back( (sal_uLong)0 );
// 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.empty() )
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().getLength(), 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();
}
}
// is a history needed at all?
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, "without StartNode no TableBox" );
SwTableBox* pBox = pSttNd->FindTableNode()->GetTable().GetTblBox(
pSttNd->GetIndex() );
OSL_ENSURE( pBox, "found no TableBox" );
SwTableBoxFmt* pFmt = rDoc.MakeTableBoxFmt();
pFmt->SetFmtAttr( *pBoxSet );
pBox->ChgFrmFmt( pFmt );
if( ULONG_MAX == nNdPos )
return;
SwTxtNode* pTxtNd = rDoc.GetNodes()[ nNdPos ]->GetTxtNode();
// If more than one node was deleted than all "node" attributes were also
// saved
if( pTxtNd->HasSwAttrSet() )
pTxtNd->ResetAllAttr();
if( pTxtNd->GetpSwpHints() && !aStr.isEmpty() )
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.isEmpty() )
{
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)
{
// Could the box be changed?
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, "without StartNode no TableBox" );
SwTableBox* pBox = pSttNd->FindTableNode()->GetTable().GetTblBox(
pSttNd->GetIndex() );
OSL_ENSURE( pBox, "found no TableBox" );
SwFrmFmt* pBoxFmt = pBox->ClaimFrmFmt();
if( bNewFmt || bNewFml || bNewValue )
{
SfxItemSet aBoxSet( rDoc.GetAttrPool(),
RES_BOXATR_FORMAT, RES_BOXATR_VALUE );
// Resetting attributes is not enough. In addition, take care that the
// text will be also formatted correctly.
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 ));
// Resetting attributes is not enough. In addition, take care that the
// text will be also formatted correctly.
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
{
// it's no number
// Resetting attributes is not enough. In addition, take care that the
// text will be also formatted correctly.
pBoxFmt->SetFmtAttr( *GetDfltAttr( RES_BOXATR_FORMAT ));
pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMAT, RES_BOXATR_VALUE );
}
if( bNewFml )
{
// No matter what was set, an update of the table is always a good idea
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->size(); 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->size(); ++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, bool bDelCntnt )
{
if( !pArr->empty() && !bDelCntnt )
return;
_UndoTblCpyTbl_Entry* pEntry = new _UndoTblCpyTbl_Entry( rBox );
pArr->push_back( pEntry );
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, bool bDelCntnt )
{
_UndoTblCpyTbl_Entry* pEntry = &(*pArr).back();
// If the content was deleted than remove also the temporarily created 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().getLength());
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 deletion 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().getLength());
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 SwRangeRedline( 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 SwRangeRedline( nsRedlineType_t::REDLINE_INSERT, aTmpPam ), true );
}
pDoc->SetRedlineMode_intern( eOld );
return pUndo;
}
bool SwUndoTblCpyTbl::InsertRow( SwTable& rTbl, const SwSelBoxes& rBoxes,
sal_uInt16 nCnt )
{
SwTableNode* pTblNd = (SwTableNode*)rTbl.GetTabSortBoxes()[0]->
GetSttNd()->FindTableNode();
pInsRowUndo = new SwUndoTblNdsChg( UNDO_TABLE_INSROW, rBoxes, *pTblNd,
0, 0, nCnt, sal_True, sal_False );
SwTableSortBoxes aTmpLst( rTbl.GetTabSortBoxes() );
bool bRet = rTbl.InsertRow( rTbl.GetFrmFmt()->GetDoc(), rBoxes, nCnt, true );
if( bRet )
pInsRowUndo->SaveNewBoxes( *pTblNd, aTmpLst );
else
delete pInsRowUndo, pInsRowUndo = 0;
return bRet;
}
sal_Bool SwUndoTblCpyTbl::IsEmpty() const
{
return !pInsRowUndo && pArr->empty();
}
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();
// move hard page breaks into next node
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;
// no break
case HEADLINE_BORDERCOPY:
case HEADLINE_BOXATTRCOPY:
pSavTbl = new _SaveTable( rTblNd.GetTable(), 1, 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;
// remove implicitly created paragraph again
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 );
// no break
case HEADLINE_BOXATTRCOPY:
case HEADLINE_BORDERCOPY:
{
pSavTbl->CreateNew( rTbl, false );
pSavTbl->RestoreAttr( rTbl );
}
break;
case HEADLINE_CNTNTCOPY:
// the created first line has to be removed again
{
SwSelBoxes aSelBoxes;
SwTableBox* pBox = rTbl.GetTblBox( nTblNode + nOffset + 1 );
rTbl.SelLineFromBox( pBox, aSelBoxes, true );
_FndBox aTmpBox( 0, 0 );
aTmpBox.SetTableLines( aSelBoxes, rTbl );
aTmpBox.DelFrms( rTbl );
rTbl.DeleteSel( pDoc, aSelBoxes, 0, 0, false, 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 )
{
// memorize end node of the last table cell that'll stay in position
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 );
// get lines for layout update
_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 );
// update layout
aFndBox.MakeFrms( *pTbl );
// ? TL_CHART2: notification or locking of controller required ?
if( bWithPrev )
{
// move name
pNew->GetTable().GetFrmFmt()->SetName( pTbl->GetFrmFmt()->GetName() );
pSavHdl->RestoreAttr( pNew->GetTable() );
}
else
pTbl = &pNew->GetTable();
pTbl->GetFrmFmt()->SetName( aName );
pSavTbl->RestoreAttr( *pTbl );
if( pHistory )
{
pHistory->TmpRollback( pDoc, 0 );
pHistory->SetTmpEnd( pHistory->Count() );
}
// create frames for the new table
SwNodeIndex aTmpIdx( *pNew );
pNew->MakeFrms( &aTmpIdx );
// position cursor somewhere in content
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( std::vector<sal_uInt16>& rArr, sal_uInt16 nIdx, sal_uInt16* pInsPos )
{
sal_uInt16 nO = rArr.size(), nM, nU = 0;
if( nO > 0 )
{
nO--;
while( nU <= nO )
{
nM = nU + ( nO - nU ) / 2;
if ( rArr[nM] == nIdx )
{
OSL_FAIL( "Index already exists. This should never happen." );
return;
}
if( rArr[nM] < nIdx )
nU = nM + 1;
else if( nM == 0 )
break;
else
nO = nM - 1;
}
}
rArr.insert( rArr.begin() + nU, nIdx );
if( pInsPos )
*pInsPos = nU;
}
#if OSL_DEBUG_LEVEL > 0
void CheckTable( const SwTable& rTbl )
{
const SwNodes& rNds = rTbl.GetFrmFmt()->GetDoc()->GetNodes();
const SwTableSortBoxes& rSrtArr = rTbl.GetTabSortBoxes();
for (size_t n = 0; n < rSrtArr.size(); ++n)
{
const SwTableBox* pBox = rSrtArr[ n ];
const SwNode* pNd = pBox->GetSttNd();
OSL_ENSURE( rNds[ pBox->GetSttIdx() ] == pNd, "Box with wrong StartNode" );
}
}
#endif
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */