blob: e9e582bfc4c84787187bd474548ef4f3a27729bd [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sw.hxx"
#include <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>
#ifndef DBG_UTIL
#define CHECK_TABLE(t)
#else
#ifdef DEBUG
#define CHECK_TABLE(t) (t).CheckConsistency();
#else
#define CHECK_TABLE(t)
#endif
#endif
#ifndef DBG_UTIL
#define _DEBUG_REDLINE( pDoc )
#else
void lcl_DebugRedline( const SwDoc* pDoc );
#define _DEBUG_REDLINE( pDoc ) lcl_DebugRedline( 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 defined( JP_DEBUG ) && defined(DBG_UTIL)
#include "shellio.hxx"
void DumpDoc( SwDoc* pDoc, const String& rFileNm );
void CheckTable( const SwTable& );
#define DUMPDOC(p,s) DumpDoc( p, s);
#define CHECKTABLE(t) CheckTable( t );
#else
#define DUMPDOC(p,s)
#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 __FAR_DATA 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();
ASSERT( 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!)
ASSERT( 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();
ASSERT( 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 )) )
{
ASSERT( sal_False, "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, "SwUndoTxtToTbl: no TableNode" );
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 {
ASSERT( !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 )
{
ASSERT( rTbl.GetTabSortBoxes().Count(), "Tabelle ohne Inhalt" );
const SwStartNode *pSttNd = rTbl.GetTabSortBoxes()[ 0 ]->GetSttNd();
ASSERT( pSttNd, "Box ohne Inhalt" );
nTblNd = pSttNd->StartOfSectionIndex();
}
void SwUndoTblHeadline::UndoImpl(::sw::UndoRedoContext & rContext)
{
SwDoc & rDoc = rContext.GetDoc();
SwTableNode* pTNd = rDoc.GetNodes()[ nTblNd ]->GetTableNode();
ASSERT( 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();
ASSERT( 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 )
{
ASSERT( !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 )
{
ASSERT( !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.
ASSERT(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() )
{
ASSERT( !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 )
{
ASSERT( !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
{
ASSERT( !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 );
ASSERT( 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();
ASSERT( 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();
ASSERT( 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;
ASSERT( ! 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();
ASSERT( ! IsDelBox(), "falsche Action" );
Ptrs.pNewSttNds = new SvULongs( (sal_uInt8)(rTblBoxes.Count() - rOld.Count()), 5 );
ASSERT( rTbl.IsNewModel() || rOld.Count() + nCount * rBoxes.Count() == rTblBoxes.Count(),
"unexpected boxes" );
ASSERT( 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;
ASSERT( 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 )
{
ASSERT( 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, "SwUndoTblNdsChg: 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: 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 );
ASSERT( 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 );
ASSERT( 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();
ASSERT( 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();
ASSERT( 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, "SwUndoTblMerge: 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. 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();
DUMPDOC( &rDoc, "d:\\tmp\\tab_a.db" )
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 );
}
DUMPDOC( &rDoc, "d:\\tmp\\tab_b.db" )
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 );
ASSERT( 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->RstTxtAttr( aTmpIdx, pTxtNd->GetTxt().Len() - nDelPos + 1 );
// das Trennzeichen loeschen
pTxtNd->EraseText( aTmpIdx, 1 );
}
DUMPDOC( &rDoc, String( "d:\\tmp\\tab_") + String( aNewSttNds.Count() - i ) +
String(".db") )
}
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 ] );
}
}
DUMPDOC( &rDoc, "d:\\tmp\\tab_z.db" )
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)
{
ASSERT( pBoxSet, "Where's the stored item set?" )
SwDoc & rDoc = rContext.GetDoc();
SwStartNode* pSttNd = rDoc.GetNodes()[ nNode ]->
FindSttNodeByType( SwTableBoxStartNode );
ASSERT( pSttNd, "ohne StartNode kein TabellenBox" );
SwTableBox* pBox = pSttNd->FindTableNode()->GetTable().GetTblBox(
pSttNd->GetIndex() );
ASSERT( 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 );
ASSERT( pSttNd, "ohne StartNode kein TabellenBox" );
SwTableBox* pBox = pSttNd->FindTableNode()->GetTable().GetTblBox(
pSttNd->GetIndex() );
ASSERT( 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 )
{
ASSERT( sal_False, "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;
}
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 )
{
ASSERT( sal_False, "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 defined( JP_DEBUG ) && defined(DBG_UTIL)
void DumpDoc( SwDoc* pDoc, const String& rFileNm )
{
Writer* pWrt = SwIoSystem::GetWriter( "DEBUG" );
if( pWrt )
{
SvFileStream aStream( rFileNm, STREAM_STD_WRITE );
SwPaM* pPam = new SwPaM( pDoc, SwPosition( pDoc->GetNodes().EndOfContent ,
pDoc->GetNodes().EndOfContent ));
pPam->Move( fnMoveBackward, fnGoDoc );
pPam->SetMark();
pPam->Move( fnMoveForward, fnGoDoc );
pWrt->Write( pPam, *pDoc, aStream, rFileNm.GetStr() );
delete pPam;
}
}
void CheckTable( const SwTable& rTbl )
{
const SwNodes& rNds = rTbl.GetFrmFmt()->GetDoc()->GetNodes();
const SwTableSortBoxes& rSrtArr = pTblNd->GetTable().GetTabSortBoxes();
for( sal_uInt16 n = 0; n < rSrtArr.Count(); ++n )
{
const SwTableBox* pBox = rSrtArr[ n ];
const SwNode* pNd = pBox->GetSttNd();
ASSERT( rNds[ *pBox->GetSttIdx() ] == pNd, "Box mit falchem StartNode" );
}
}
#endif