diff options
Diffstat (limited to 'sw/source/core/undo')
29 files changed, 17906 insertions, 0 deletions
diff --git a/sw/source/core/undo/SwRewriter.cxx b/sw/source/core/undo/SwRewriter.cxx new file mode 100644 index 000000000000..129bdc8f9b59 --- /dev/null +++ b/sw/source/core/undo/SwRewriter.cxx @@ -0,0 +1,78 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <algorithm> +#include <SwRewriter.hxx> + +using namespace std; + +bool operator == (const SwRewriteRule & a, const SwRewriteRule & b) +{ + return a.first == b.first; +} + +SwRewriter::SwRewriter() +{ +} + +SwRewriter::SwRewriter(const SwRewriter & rSrc) + : mRules(rSrc.mRules) +{ +} + +SwRewriter::~SwRewriter() +{ +} + +void SwRewriter::AddRule(const String & rWhat, const String & rWith) +{ + SwRewriteRule aRule(rWhat, rWith); + + vector<SwRewriteRule>::iterator aIt; + + aIt = find(mRules.begin(), mRules.end(), aRule); + + if (aIt != mRules.end()) + *aIt = aRule; + else + mRules.push_back(aRule); +} + +String SwRewriter::Apply(const String & rStr) const +{ + String aResult = rStr; + vector<SwRewriteRule>::const_iterator aIt; + + for (aIt = mRules.begin(); aIt != mRules.end(); aIt++) + aResult.SearchAndReplaceAll(aIt->first, aIt->second); + + return aResult; +} + diff --git a/sw/source/core/undo/SwUndoField.cxx b/sw/source/core/undo/SwUndoField.cxx new file mode 100644 index 000000000000..8a3c6c507c93 --- /dev/null +++ b/sw/source/core/undo/SwUndoField.cxx @@ -0,0 +1,156 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" +#include <tools/rtti.hxx> +#include <SwUndoField.hxx> +#include <swundo.hxx> +#include <doc.hxx> +#include <txtfld.hxx> +#include <fldbas.hxx> +#include <ndtxt.hxx> +#include <fmtfld.hxx> +#include <dbfld.hxx> +#include <docsh.hxx> + +using namespace ::com::sun::star::uno; + +SwUndoField::SwUndoField(const SwPosition & rPos, SwUndoId _nId ) + : SwUndo(_nId) +{ + nNodeIndex = rPos.nNode.GetIndex(); + nOffset = rPos.nContent.GetIndex(); + pDoc = rPos.GetDoc(); +} + +SwUndoField::~SwUndoField() +{ +} + +SwPosition SwUndoField::GetPosition() +{ + SwNode * pNode = pDoc->GetNodes()[nNodeIndex]; + SwNodeIndex aNodeIndex(*pNode); + SwIndex aIndex(pNode->GetCntntNode(), nOffset); + SwPosition aResult(aNodeIndex, aIndex); + + return aResult; +} + +SwUndoFieldFromDoc::SwUndoFieldFromDoc(const SwPosition & rPos, + const SwField & rOldField, + const SwField & rNewField, + SwMsgPoolItem * _pHnt, BOOL _bUpdate, SwUndoId _nId) + : SwUndoField(rPos,_nId) + , pOldField(rOldField.CopyField()) + , pNewField(rNewField.CopyField()) + , pHnt(_pHnt) + , bUpdate(_bUpdate) +{ + ASSERT(pOldField, "No old field!"); + ASSERT(pNewField, "No new field!"); + ASSERT(pDoc, "No document!"); +} + +SwUndoFieldFromDoc::~SwUndoFieldFromDoc() +{ + delete pOldField; + delete pNewField; +} + +void SwUndoFieldFromDoc::Undo( SwUndoIter& ) +{ + SwTxtFld * pTxtFld = SwDoc::GetTxtFld(GetPosition()); + const SwField * pField = pTxtFld->GetFld().GetFld(); + + if (pField) + { + BOOL bUndo = pDoc->DoesUndo(); + + pDoc->DoUndo(FALSE); + pDoc->UpdateFld(pTxtFld, *pOldField, pHnt, bUpdate); + pDoc->DoUndo(bUndo); + } +} + +void SwUndoFieldFromDoc::Redo( SwUndoIter& ) +{ + SwTxtFld * pTxtFld = SwDoc::GetTxtFld(GetPosition()); + const SwField * pField = pTxtFld->GetFld().GetFld(); + + if (pField) + { + BOOL bUndo = pDoc->DoesUndo(); + + pDoc->DoUndo(FALSE); + pDoc->UpdateFld(pTxtFld, *pNewField, pHnt, bUpdate); + SwFmtFld* pDstFmtFld = (SwFmtFld*)&pTxtFld->GetFld(); + + if ( pDoc->GetFldType(RES_POSTITFLD, aEmptyStr,false) == pDstFmtFld->GetFld()->GetTyp() ) + pDoc->GetDocShell()->Broadcast( SwFmtFldHint( pDstFmtFld, SWFMTFLD_INSERTED ) ); + pDoc->DoUndo(bUndo); + } +} + +void SwUndoFieldFromDoc::Repeat(SwUndoIter & rIt) +{ + Redo(rIt); +} + +SwUndoFieldFromAPI::SwUndoFieldFromAPI(const SwPosition & rPos, + const Any & rOldVal, const Any & rNewVal, + USHORT _nWhich) + : SwUndoField(rPos), aOldVal(rOldVal), aNewVal(rNewVal), nWhich(_nWhich) +{ +} + +SwUndoFieldFromAPI::~SwUndoFieldFromAPI() +{ +} + +void SwUndoFieldFromAPI::Undo( SwUndoIter& ) +{ + SwField * pField = SwDoc::GetField(GetPosition()); + + if (pField) + pField->PutValue(aOldVal, nWhich); +} + +void SwUndoFieldFromAPI::Redo( SwUndoIter& ) +{ + SwField * pField = SwDoc::GetField(GetPosition()); + + if (pField) + pField->PutValue(aNewVal, nWhich); +} + + +void SwUndoFieldFromAPI::Repeat(SwUndoIter & rIter) +{ + Redo(rIter); +} diff --git a/sw/source/core/undo/SwUndoFmt.cxx b/sw/source/core/undo/SwUndoFmt.cxx new file mode 100644 index 000000000000..f3b2fe4d1a25 --- /dev/null +++ b/sw/source/core/undo/SwUndoFmt.cxx @@ -0,0 +1,510 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <tools/resid.hxx> +#include <poolfmt.hxx> +#include <charfmt.hxx> +#include <frmfmt.hxx> +#include <SwUndoFmt.hxx> +#include <SwRewriter.hxx> +#include <swundo.hxx> +#include <undobj.hxx> +#include <fmtcol.hxx> +#include <tools/string.hxx> +#include <doc.hxx> +#include <comcore.hrc> + +SwUndoFmtCreate::SwUndoFmtCreate +(SwUndoId nUndoId, SwFmt * _pNew, SwFmt * _pDerivedFrom, SwDoc * _pDoc) + : SwUndo(nUndoId), pNew(_pNew), + pDoc(_pDoc), pNewSet(NULL), nId(0), bAuto(FALSE) +{ + if (_pDerivedFrom) + sDerivedFrom = _pDerivedFrom->GetName(); +} + +SwUndoFmtCreate::~SwUndoFmtCreate() +{ +} + +void SwUndoFmtCreate::Undo(SwUndoIter &) +{ + if (pNew) + { + if (sNewName.Len() == 0 && pNew) + sNewName = pNew->GetName(); + + if (sNewName.Len() > 0) + pNew = Find(sNewName); + + if (pNew) + { + pNewSet = new SfxItemSet(pNew->GetAttrSet()); + nId = pNew->GetPoolFmtId() & COLL_GET_RANGE_BITS; + bAuto = pNew->IsAuto(); + + BOOL bDoesUndo = pDoc->DoesUndo(); + + pDoc->DoUndo(FALSE); + Delete(); + pDoc->DoUndo(bDoesUndo); + } + } +} + +void SwUndoFmtCreate::Redo(SwUndoIter &) +{ + BOOL bDoesUndo = pDoc->DoesUndo(); + + pDoc->DoUndo(FALSE); + SwFmt * pDerivedFrom = Find(sDerivedFrom); + SwFmt * pFmt = Create(pDerivedFrom); + + if (pFmt && pNewSet) + { + pFmt->SetAuto(bAuto); + pDoc->ChgFmt(*pFmt, *pNewSet); + pFmt->SetPoolFmtId((pFmt->GetPoolFmtId() + & ~COLL_GET_RANGE_BITS) + | nId); + + pNew = pFmt; + } + else + pNew = NULL; + + pDoc->DoUndo(bDoesUndo); +} + +SwRewriter SwUndoFmtCreate::GetRewriter() const +{ + if (sNewName.Len() == 0 && pNew) + sNewName = pNew->GetName(); + + SwRewriter aRewriter; + + aRewriter.AddRule(UNDO_ARG1, sNewName); + + return aRewriter; +} + +SwUndoFmtDelete::SwUndoFmtDelete +(SwUndoId nUndoId, SwFmt * _pOld, SwDoc * _pDoc) + : SwUndo(nUndoId), + pDoc(_pDoc), sOldName(_pOld->GetName()), + aOldSet(_pOld->GetAttrSet()) +{ + sDerivedFrom = _pOld->DerivedFrom()->GetName(); + nId = _pOld->GetPoolFmtId() & COLL_GET_RANGE_BITS; + bAuto = _pOld->IsAuto(); +} + +SwUndoFmtDelete::~SwUndoFmtDelete() +{ +} + +void SwUndoFmtDelete::Undo(SwUndoIter &) +{ + BOOL bDoesUndo = pDoc->DoesUndo(); + + pDoc->DoUndo(FALSE); + + SwFmt * pDerivedFrom = Find(sDerivedFrom); + + SwFmt * pFmt = Create(pDerivedFrom); + + if (pFmt) + { + pDoc->ChgFmt(*pFmt, aOldSet); + pFmt->SetAuto(bAuto); + pFmt->SetPoolFmtId((pFmt->GetPoolFmtId() & + ~COLL_GET_RANGE_BITS) + | nId); + + } + + pDoc->DoUndo(bDoesUndo); +} + +void SwUndoFmtDelete::Redo(SwUndoIter &) +{ + SwFmt * pOld = Find(sOldName); + + if (pOld) + { + BOOL bDoesUndo = pDoc->DoesUndo(); + + pDoc->DoUndo(FALSE); + Delete(pOld); + pDoc->DoUndo(bDoesUndo); + } +} + +SwRewriter SwUndoFmtDelete::GetRewriter() const +{ + SwRewriter aRewriter; + + aRewriter.AddRule(UNDO_ARG1, sOldName); + + return aRewriter; +} + +SwUndoRenameFmt::SwUndoRenameFmt(SwUndoId nUndoId, + const String & _sOldName, + const String & _sNewName, + SwDoc * _pDoc) + : SwUndo(nUndoId), sOldName(_sOldName), + sNewName(_sNewName), pDoc(_pDoc) +{ +} + + +SwUndoRenameFmt::~SwUndoRenameFmt() +{ +} + +void SwUndoRenameFmt::Undo(SwUndoIter &) +{ + SwFmt * pFmt = Find(sNewName); + + if (pFmt) + { + BOOL bDoesUndo = pDoc->DoesUndo(); + + pDoc->DoUndo(FALSE); + pDoc->RenameFmt(*pFmt, sOldName, TRUE); + pDoc->DoUndo(bDoesUndo); + } +} + +void SwUndoRenameFmt::Redo(SwUndoIter &) +{ + SwFmt * pFmt = Find(sOldName); + + if (pFmt) + { + BOOL bDoesUndo = pDoc->DoesUndo(); + + pDoc->DoUndo(FALSE); + pDoc->RenameFmt(*pFmt, sNewName, TRUE); + pDoc->DoUndo(bDoesUndo); + } +} + +SwRewriter SwUndoRenameFmt::GetRewriter() const +{ + SwRewriter aRewriter; + + aRewriter.AddRule(UNDO_ARG1, sOldName); + aRewriter.AddRule(UNDO_ARG2, SW_RES(STR_YIELDS)); + aRewriter.AddRule(UNDO_ARG3, sNewName); + + return aRewriter; +} + +SwUndoTxtFmtCollCreate::SwUndoTxtFmtCollCreate +(SwTxtFmtColl * _pNew, SwTxtFmtColl * _pDerivedFrom, SwDoc * _pDoc) + : SwUndoFmtCreate(UNDO_TXTFMTCOL_CREATE, _pNew, _pDerivedFrom, _pDoc) +{ +} + +SwFmt * SwUndoTxtFmtCollCreate::Create(SwFmt * pDerivedFrom) +{ + return pDoc->MakeTxtFmtColl(sNewName, (SwTxtFmtColl *)pDerivedFrom, TRUE); +} + +void SwUndoTxtFmtCollCreate::Delete() +{ + pDoc->DelTxtFmtColl((SwTxtFmtColl *) pNew, TRUE); +} + +SwFmt * SwUndoTxtFmtCollCreate::Find(const String & rName) const +{ + return pDoc->FindTxtFmtCollByName(rName); +} + +SwUndoTxtFmtCollDelete::SwUndoTxtFmtCollDelete(SwTxtFmtColl * _pOld, + SwDoc * _pDoc) + : SwUndoFmtDelete(UNDO_TXTFMTCOL_DELETE, _pOld, _pDoc) +{ +} + +SwFmt * SwUndoTxtFmtCollDelete::Create(SwFmt * pDerivedFrom) +{ + return pDoc->MakeTxtFmtColl(sOldName, (SwTxtFmtColl *) pDerivedFrom, TRUE); +} + +void SwUndoTxtFmtCollDelete::Delete(SwFmt * pOld) +{ + pDoc->DelTxtFmtColl((SwTxtFmtColl *) pOld, TRUE); +} + +SwFmt * SwUndoTxtFmtCollDelete::Find(const String & rName) const +{ + return pDoc->FindTxtFmtCollByName(rName); +} + +SwUndoRenameFmtColl::SwUndoRenameFmtColl(const String & sInitOldName, + const String & sInitNewName, + SwDoc * _pDoc) + : SwUndoRenameFmt(UNDO_TXTFMTCOL_RENAME, sInitOldName, sInitNewName, _pDoc) +{ +} + +SwFmt * SwUndoRenameFmtColl::Find(const String & rName) const +{ + return pDoc->FindTxtFmtCollByName(rName); +} + +SwUndoCharFmtCreate::SwUndoCharFmtCreate(SwCharFmt * pNewFmt, + SwCharFmt * pDerivedFrom, + SwDoc * pDocument) + : SwUndoFmtCreate(UNDO_CHARFMT_CREATE, pNewFmt, pDerivedFrom, pDocument) +{ +} + +SwFmt * SwUndoCharFmtCreate::Create(SwFmt * pDerivedFrom) +{ + return pDoc->MakeCharFmt(sNewName, (SwCharFmt *) pDerivedFrom, TRUE); +} + +void SwUndoCharFmtCreate::Delete() +{ + pDoc->DelCharFmt((SwCharFmt *) pNew, TRUE); +} + +SwFmt * SwUndoCharFmtCreate::Find(const String & rName) const +{ + return pDoc->FindCharFmtByName(rName); +} + +SwUndoCharFmtDelete::SwUndoCharFmtDelete(SwCharFmt * pOld, SwDoc * pDocument) + : SwUndoFmtDelete(UNDO_CHARFMT_DELETE, pOld, pDocument) +{ +} + +SwFmt * SwUndoCharFmtDelete::Create(SwFmt * pDerivedFrom) +{ + return pDoc->MakeCharFmt(sOldName, (SwCharFmt *) pDerivedFrom, TRUE); +} + +void SwUndoCharFmtDelete::Delete(SwFmt * pFmt) +{ + pDoc->DelCharFmt((SwCharFmt *) pFmt, TRUE); +} + +SwFmt * SwUndoCharFmtDelete::Find(const String & rName) const +{ + return pDoc->FindCharFmtByName(rName); +} + +SwUndoRenameCharFmt::SwUndoRenameCharFmt(const String & sInitOldName, + const String & sInitNewName, + SwDoc * pDocument) + : SwUndoRenameFmt(UNDO_CHARFMT_RENAME, sInitOldName, sInitNewName, pDocument) +{ +} + +SwFmt * SwUndoRenameCharFmt::Find(const String & rName) const +{ + return pDoc->FindCharFmtByName(rName); +} + +SwUndoFrmFmtCreate::SwUndoFrmFmtCreate(SwFrmFmt * pNewFmt, + SwFrmFmt * pDerivedFrom, + SwDoc * pDocument) + : SwUndoFmtCreate(UNDO_FRMFMT_CREATE, pNewFmt, pDerivedFrom, pDocument), + bAuto(pNewFmt->IsAuto()) +{ +} + +SwFmt * SwUndoFrmFmtCreate::Create(SwFmt * pDerivedFrom) +{ + return pDoc->MakeFrmFmt(sNewName, (SwFrmFmt *) pDerivedFrom, TRUE, bAuto); +} + +void SwUndoFrmFmtCreate::Delete() +{ + pDoc->DelFrmFmt((SwFrmFmt *) pNew, TRUE); +} + +SwFmt * SwUndoFrmFmtCreate::Find(const String & rName) const +{ + return pDoc->FindFrmFmtByName(rName); +} + +SwUndoFrmFmtDelete::SwUndoFrmFmtDelete(SwFrmFmt * pOld, SwDoc * pDocument) + : SwUndoFmtDelete(UNDO_FRMFMT_DELETE, pOld, pDocument) +{ +} + +SwFmt * SwUndoFrmFmtDelete::Create(SwFmt * pDerivedFrom) +{ + return pDoc->MakeFrmFmt(sOldName, (SwFrmFmt *) pDerivedFrom, TRUE); +} + +void SwUndoFrmFmtDelete::Delete(SwFmt * pFmt) +{ + pDoc->DelFrmFmt((SwFrmFmt *) pFmt, TRUE); +} + +SwFmt * SwUndoFrmFmtDelete::Find(const String & rName) const +{ + return pDoc->FindFrmFmtByName(rName); +} + +SwUndoRenameFrmFmt::SwUndoRenameFrmFmt(const String & sInitOldName, + const String & sInitNewName, + SwDoc * pDocument) + : SwUndoRenameFmt(UNDO_FRMFMT_RENAME, sInitOldName, sInitNewName, pDocument) +{ +} + +SwFmt * SwUndoRenameFrmFmt::Find(const String & rName) const +{ + return pDoc->FindFrmFmtByName(rName); +} + +SwUndoNumruleCreate::SwUndoNumruleCreate(const SwNumRule * _pNew, + SwDoc * _pDoc) + : SwUndo(UNDO_NUMRULE_CREATE), pNew(_pNew), aNew(*_pNew), pDoc(_pDoc), + bInitialized(false) +{ +} + +void SwUndoNumruleCreate::Undo(SwUndoIter &) +{ + BOOL bDoesUndo = pDoc->DoesUndo(); + + pDoc->DoUndo(FALSE); + + if (! bInitialized) + { + aNew = *pNew; + bInitialized = true; + } + + pDoc->DelNumRule(aNew.GetName(), TRUE); + pDoc->DoUndo(bDoesUndo); +} + +void SwUndoNumruleCreate::Redo(SwUndoIter &) +{ + BOOL bDoesUndo = pDoc->DoesUndo(); + + pDoc->DoUndo(FALSE); + pDoc->MakeNumRule(aNew.GetName(), &aNew, TRUE); + pDoc->DoUndo(bDoesUndo); +} + +SwRewriter SwUndoNumruleCreate::GetRewriter() const +{ + SwRewriter aResult; + + if (! bInitialized) + { + aNew = *pNew; + bInitialized = true; + } + + aResult.AddRule(UNDO_ARG1, aNew.GetName()); + + return aResult; +} + +SwUndoNumruleDelete::SwUndoNumruleDelete(const SwNumRule & rRule, + SwDoc * _pDoc) + : SwUndo(UNDO_NUMRULE_DELETE), aOld(rRule), pDoc(_pDoc) +{ +} + +void SwUndoNumruleDelete::Undo(SwUndoIter &) +{ + BOOL bDoesUndo = pDoc->DoesUndo(); + + pDoc->DoUndo(FALSE); + pDoc->MakeNumRule(aOld.GetName(), &aOld, TRUE); + pDoc->DoUndo(bDoesUndo); +} + +void SwUndoNumruleDelete::Redo(SwUndoIter &) +{ + BOOL bDoesUndo = pDoc->DoesUndo(); + + pDoc->DoUndo(FALSE); + pDoc->DelNumRule(aOld.GetName(), TRUE); + pDoc->DoUndo(bDoesUndo); +} + +SwRewriter SwUndoNumruleDelete::GetRewriter() const +{ + SwRewriter aResult; + + aResult.AddRule(UNDO_ARG1, aOld.GetName()); + + return aResult; +} + +SwUndoNumruleRename::SwUndoNumruleRename(const String & _aOldName, + const String & _aNewName, + SwDoc * _pDoc) + : SwUndo(UNDO_NUMRULE_RENAME), aOldName(_aOldName), aNewName(_aNewName), + pDoc(_pDoc) +{ +} + +void SwUndoNumruleRename::Undo(SwUndoIter &) +{ + BOOL bDoesUndo = pDoc->DoesUndo(); + + pDoc->DoUndo(FALSE); + pDoc->RenameNumRule(aNewName, aOldName, TRUE); + pDoc->DoUndo(bDoesUndo); +} + +void SwUndoNumruleRename::Redo(SwUndoIter &) +{ + BOOL bDoesUndo = pDoc->DoesUndo(); + + pDoc->DoUndo(FALSE); + pDoc->RenameNumRule(aOldName, aNewName, TRUE); + pDoc->DoUndo(bDoesUndo); +} + +SwRewriter SwUndoNumruleRename::GetRewriter() const +{ + SwRewriter aRewriter; + + aRewriter.AddRule(UNDO_ARG1, aOldName); + aRewriter.AddRule(UNDO_ARG2, SW_RES(STR_YIELDS)); + aRewriter.AddRule(UNDO_ARG3, aNewName); + + return aRewriter; +} diff --git a/sw/source/core/undo/SwUndoPageDesc.cxx b/sw/source/core/undo/SwUndoPageDesc.cxx new file mode 100644 index 000000000000..9a395375eabe --- /dev/null +++ b/sw/source/core/undo/SwUndoPageDesc.cxx @@ -0,0 +1,474 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <tools/resid.hxx> +#include <doc.hxx> +#include <swundo.hxx> +#include <pagedesc.hxx> +#include <SwUndoPageDesc.hxx> +#include <SwRewriter.hxx> +#include <undobj.hxx> +#include <comcore.hrc> +#include <fmtcntnt.hxx> +#include <fmthdft.hxx> + +#ifdef DEBUG +#include <ndindex.hxx> +#endif + + +#ifdef DEBUG +// Pure debug help function to have a quick look at the header/footer attributes. +void DebugHeaderFooterContent( const SwPageDesc& rPageDesc ) +{ + ULONG nHeaderMaster = ULONG_MAX; + ULONG nHeaderLeft = ULONG_MAX; + ULONG nFooterMaster = ULONG_MAX; + ULONG nFooterLeft = ULONG_MAX; + int nHeaderCount = 0; + int nLeftHeaderCount = 0; + int nFooterCount = 0; + int nLeftFooterCount = 0; + bool bSharedHeader = false; + bool bSharedFooter = false; + + SwFmtHeader& rHead = (SwFmtHeader&)rPageDesc.GetMaster().GetHeader(); + SwFmtFooter& rFoot = (SwFmtFooter&)rPageDesc.GetMaster().GetFooter(); + SwFmtHeader& rLeftHead = (SwFmtHeader&)rPageDesc.GetLeft().GetHeader(); + SwFmtFooter& rLeftFoot = (SwFmtFooter&)rPageDesc.GetLeft().GetFooter(); + if( rHead.IsActive() ) + { + SwFrmFmt* pHeaderFmt = rHead.GetHeaderFmt(); + if( pHeaderFmt ) + { + SwClientIter aIter( *pHeaderFmt ); + SwClient *pLast = aIter.GoStart(); + if( pLast ) + do + { + ++nHeaderCount; + } while( 0 != ( pLast = aIter++ )); + const SwFmtCntnt* pCntnt = &pHeaderFmt->GetCntnt(); + if( pCntnt->GetCntntIdx() ) + nHeaderMaster = pCntnt->GetCntntIdx()->GetIndex(); + else + nHeaderMaster = 0; + } + bSharedHeader = rPageDesc.IsHeaderShared(); + SwFrmFmt* pLeftHeaderFmt = rLeftHead.GetHeaderFmt(); + if( pLeftHeaderFmt ) + { + SwClientIter aIter( *pLeftHeaderFmt ); + SwClient *pLast = aIter.GoStart(); + if( pLast ) + do + { + ++nLeftHeaderCount; + } while( 0 != ( pLast = aIter++ )); + const SwFmtCntnt* pLeftCntnt = &pLeftHeaderFmt->GetCntnt(); + if( pLeftCntnt->GetCntntIdx() ) + nHeaderLeft = pLeftCntnt->GetCntntIdx()->GetIndex(); + else + nHeaderLeft = 0; + } + } + if( rFoot.IsActive() ) + { + SwFrmFmt* pFooterFmt = rFoot.GetFooterFmt(); + if( pFooterFmt ) + { + SwClientIter aIter( *pFooterFmt ); + SwClient *pLast = aIter.GoStart(); + if( pLast ) + do + { + ++nFooterCount; + } while( 0 != ( pLast = aIter++ )); + const SwFmtCntnt* pCntnt = &pFooterFmt->GetCntnt(); + if( pCntnt->GetCntntIdx() ) + nFooterMaster = pCntnt->GetCntntIdx()->GetIndex(); + else + nFooterMaster = 0; + } + bSharedFooter = rPageDesc.IsFooterShared(); + SwFrmFmt* pLeftFooterFmt = rLeftFoot.GetFooterFmt(); + if( pLeftFooterFmt ) + { + SwClientIter aIter( *pLeftFooterFmt ); + SwClient *pLast = aIter.GoStart(); + if( pLast ) + do + { + ++nLeftFooterCount; + } while( 0 != ( pLast = aIter++ )); + const SwFmtCntnt* pLeftCntnt = &pLeftFooterFmt->GetCntnt(); + if( pLeftCntnt->GetCntntIdx() ) + nFooterLeft = pLeftCntnt->GetCntntIdx()->GetIndex(); + else + nFooterLeft = 0; + } + } + int i = 0; + ++i; // To set a breakpoint +} +#endif + +SwUndoPageDesc::SwUndoPageDesc(const SwPageDesc & _aOld, + const SwPageDesc & _aNew, + SwDoc * _pDoc) + : SwUndo( _aOld.GetName() != _aNew.GetName() ? + UNDO_RENAME_PAGEDESC : + UNDO_CHANGE_PAGEDESC ), + aOld(_aOld, _pDoc), aNew(_aNew, _pDoc), pDoc(_pDoc), bExchange( false ) +{ + ASSERT(0 != pDoc, "no document?"); + +#ifdef DEBUG + DebugHeaderFooterContent( (SwPageDesc&)aOld ); + DebugHeaderFooterContent( (SwPageDesc&)aNew ); +#endif + + /* + The page description changes. + If there are no header/footer content changes like header on/off or change from shared content + to unshared etc., there is no reason to duplicate the content nodes (Crash i55547) + But this happens, this Undo Ctor will destroy the unnecessary duplicate and manipulate the + content pointer of the both page descriptions. + */ + SwPageDesc &rOldDesc = (SwPageDesc&)aOld; + SwPageDesc &rNewDesc = (SwPageDesc&)aNew; + const SwFmtHeader& rOldHead = rOldDesc.GetMaster().GetHeader(); + const SwFmtHeader& rNewHead = rNewDesc.GetMaster().GetHeader(); + const SwFmtFooter& rOldFoot = rOldDesc.GetMaster().GetFooter(); + const SwFmtFooter& rNewFoot = rNewDesc.GetMaster().GetFooter(); + /* bExchange must not be set, if the old page descriptor will stay active. + Two known situations: + #i67735#: renaming a page descriptor + #i67334#: changing the follow style + If header/footer will be activated or deactivated, this undo will not work. + */ + bExchange = ( aOld.GetName() == aNew.GetName() ) && + ( _aOld.GetFollow() == _aNew.GetFollow() ) && + ( rOldHead.IsActive() == rNewHead.IsActive() ) && + ( rOldFoot.IsActive() == rNewFoot.IsActive() ); + if( rOldHead.IsActive() && ( rOldDesc.IsHeaderShared() != rNewDesc.IsHeaderShared() ) ) + bExchange = false; + if( rOldFoot.IsActive() && ( rOldDesc.IsFooterShared() != rNewDesc.IsFooterShared() ) ) + bExchange = false; + if( bExchange ) + { + if( rNewHead.IsActive() ) + { + SwFrmFmt* pFormat = new SwFrmFmt( *rNewHead.GetHeaderFmt() ); + // The Ctor of this object will remove the duplicate! + SwFmtHeader aFmtHeader( pFormat ); + if( !rNewDesc.IsHeaderShared() ) + { + pFormat = new SwFrmFmt( *rNewDesc.GetLeft().GetHeader().GetHeaderFmt() ); + // The Ctor of this object will remove the duplicate! + SwFmtHeader aFormatHeader( pFormat ); + } + } + // Same procedure for footers... + if( rNewFoot.IsActive() ) + { + SwFrmFmt* pFormat = new SwFrmFmt( *rNewFoot.GetFooterFmt() ); + // The Ctor of this object will remove the duplicate! + SwFmtFooter aFmtFooter( pFormat ); + if( !rNewDesc.IsFooterShared() ) + { + pFormat = new SwFrmFmt( *rNewDesc.GetLeft().GetFooter().GetFooterFmt() ); + // The Ctor of this object will remove the duplicate! + SwFmtFooter aFormatFooter( pFormat ); + } + } + + // After this exchange method the old page description will point to zero, + // the new one will point to the node position of the original content nodes. + ExchangeContentNodes( (SwPageDesc&)aOld, (SwPageDesc&)aNew ); +#ifdef DEBUG + DebugHeaderFooterContent( (SwPageDesc&)aOld ); + DebugHeaderFooterContent( (SwPageDesc&)aNew ); +#endif + } +} + +SwUndoPageDesc::~SwUndoPageDesc() +{ +} + + +void SwUndoPageDesc::ExchangeContentNodes( SwPageDesc& rSource, SwPageDesc &rDest ) +{ + ASSERT( bExchange, "You shouldn't do that." ); + const SwFmtHeader& rDestHead = rDest.GetMaster().GetHeader(); + const SwFmtHeader& rSourceHead = rSource.GetMaster().GetHeader(); + if( rDestHead.IsActive() ) + { + // Let the destination page descrition point to the source node position, + // from now on this descriptor is responsible for the content nodes! + const SfxPoolItem* pItem; + rDest.GetMaster().GetAttrSet().GetItemState( RES_HEADER, FALSE, &pItem ); + SfxPoolItem *pNewItem = pItem->Clone(); + SwFrmFmt* pNewFmt = ((SwFmtHeader*)pNewItem)->GetHeaderFmt(); +#ifdef DEBUG + const SwFmtCntnt& rSourceCntnt = rSourceHead.GetHeaderFmt()->GetCntnt(); + (void)rSourceCntnt; + const SwFmtCntnt& rDestCntnt = rDestHead.GetHeaderFmt()->GetCntnt(); + (void)rDestCntnt; +#endif + pNewFmt->SetFmtAttr( rSourceHead.GetHeaderFmt()->GetCntnt() ); + delete pNewItem; + + // Let the source page description point to zero node position, + // it loses the responsible and can be destroyed without removing the content nodes. + rSource.GetMaster().GetAttrSet().GetItemState( RES_HEADER, FALSE, &pItem ); + pNewItem = pItem->Clone(); + pNewFmt = ((SwFmtHeader*)pNewItem)->GetHeaderFmt(); + pNewFmt->SetFmtAttr( SwFmtCntnt() ); + delete pNewItem; + + if( !rDest.IsHeaderShared() ) + { + // Same procedure for unshared header.. + const SwFmtHeader& rSourceLeftHead = rSource.GetLeft().GetHeader(); + rDest.GetLeft().GetAttrSet().GetItemState( RES_HEADER, FALSE, &pItem ); + pNewItem = pItem->Clone(); + pNewFmt = ((SwFmtHeader*)pNewItem)->GetHeaderFmt(); +#ifdef DEBUG + const SwFmtCntnt& rSourceCntnt1 = rSourceLeftHead.GetHeaderFmt()->GetCntnt(); + (void)rSourceCntnt1; + const SwFmtCntnt& rDestCntnt1 = rDest.GetLeft().GetHeader().GetHeaderFmt()->GetCntnt(); + (void)rDestCntnt1; +#endif + pNewFmt->SetFmtAttr( rSourceLeftHead.GetHeaderFmt()->GetCntnt() ); + delete pNewItem; + rSource.GetLeft().GetAttrSet().GetItemState( RES_HEADER, FALSE, &pItem ); + pNewItem = pItem->Clone(); + pNewFmt = ((SwFmtHeader*)pNewItem)->GetHeaderFmt(); + pNewFmt->SetFmtAttr( SwFmtCntnt() ); + delete pNewItem; + } + } + // Same procedure for footers... + const SwFmtFooter& rDestFoot = rDest.GetMaster().GetFooter(); + const SwFmtFooter& rSourceFoot = rSource.GetMaster().GetFooter(); + if( rDestFoot.IsActive() ) + { + const SfxPoolItem* pItem; + rDest.GetMaster().GetAttrSet().GetItemState( RES_FOOTER, FALSE, &pItem ); + SfxPoolItem *pNewItem = pItem->Clone(); + SwFrmFmt *pNewFmt = ((SwFmtFooter*)pNewItem)->GetFooterFmt(); + pNewFmt->SetFmtAttr( rSourceFoot.GetFooterFmt()->GetCntnt() ); + delete pNewItem; + +#ifdef DEBUG + const SwFmtCntnt& rFooterSourceCntnt = rSourceFoot.GetFooterFmt()->GetCntnt(); + (void)rFooterSourceCntnt; + const SwFmtCntnt& rFooterDestCntnt = rDestFoot.GetFooterFmt()->GetCntnt(); + (void)rFooterDestCntnt; +#endif + rSource.GetMaster().GetAttrSet().GetItemState( RES_FOOTER, FALSE, &pItem ); + pNewItem = pItem->Clone(); + pNewFmt = ((SwFmtFooter*)pNewItem)->GetFooterFmt(); + pNewFmt->SetFmtAttr( SwFmtCntnt() ); + delete pNewItem; + + if( !rDest.IsFooterShared() ) + { + const SwFmtFooter& rSourceLeftFoot = rSource.GetLeft().GetFooter(); +#ifdef DEBUG + const SwFmtCntnt& rFooterSourceCntnt2 = rSourceLeftFoot.GetFooterFmt()->GetCntnt(); + const SwFmtCntnt& rFooterDestCntnt2 = + rDest.GetLeft().GetFooter().GetFooterFmt()->GetCntnt(); + (void)rFooterSourceCntnt2; + (void)rFooterDestCntnt2; +#endif + rDest.GetLeft().GetAttrSet().GetItemState( RES_FOOTER, FALSE, &pItem ); + pNewItem = pItem->Clone(); + pNewFmt = ((SwFmtFooter*)pNewItem)->GetFooterFmt(); + pNewFmt->SetFmtAttr( rSourceLeftFoot.GetFooterFmt()->GetCntnt() ); + delete pNewItem; + rSource.GetLeft().GetAttrSet().GetItemState( RES_FOOTER, FALSE, &pItem ); + pNewItem = pItem->Clone(); + pNewFmt = ((SwFmtFooter*)pNewItem)->GetFooterFmt(); + pNewFmt->SetFmtAttr( SwFmtCntnt() ); + delete pNewItem; + } + } +} + +void SwUndoPageDesc::Undo(SwUndoIter &) +{ + BOOL bUndo = pDoc->DoesUndo(); + + pDoc->DoUndo(FALSE); + + // Move (header/footer)content node responsibility from new page descriptor to old one again. + if( bExchange ) + ExchangeContentNodes( (SwPageDesc&)aNew, (SwPageDesc&)aOld ); + pDoc->ChgPageDesc(aOld.GetName(), aOld); + pDoc->DoUndo(bUndo); +} + +void SwUndoPageDesc::Redo(SwUndoIter &) +{ + BOOL bUndo = pDoc->DoesUndo(); + + pDoc->DoUndo(FALSE); + + // Move (header/footer)content node responsibility from old page descriptor to new one again. + if( bExchange ) + ExchangeContentNodes( (SwPageDesc&)aOld, (SwPageDesc&)aNew ); + pDoc->ChgPageDesc(aNew.GetName(), aNew); + pDoc->DoUndo(bUndo); +} + +void SwUndoPageDesc::Repeat(SwUndoIter &) +{ +} + +SwRewriter SwUndoPageDesc::GetRewriter() const +{ + SwRewriter aResult; + + aResult.AddRule(UNDO_ARG1, aOld.GetName()); + aResult.AddRule(UNDO_ARG2, SW_RES(STR_YIELDS)); + aResult.AddRule(UNDO_ARG3, aNew.GetName()); + + return aResult; +} + +// #116530# +SwUndoPageDescCreate::SwUndoPageDescCreate(const SwPageDesc * pNew, + SwDoc * _pDoc) + : SwUndo(UNDO_CREATE_PAGEDESC), pDesc(pNew), aNew(*pNew, _pDoc), + pDoc(_pDoc) +{ + ASSERT(0 != pDoc, "no document?"); +} + +SwUndoPageDescCreate::~SwUndoPageDescCreate() +{ +} + +void SwUndoPageDescCreate::Undo(SwUndoIter &) +{ + BOOL bUndo = pDoc->DoesUndo(); + + pDoc->DoUndo(FALSE); + + // -> #116530# + if (pDesc) + { + aNew = *pDesc; + pDesc = NULL; + } + // <- #116530# + + pDoc->DelPageDesc(aNew.GetName(), TRUE); + pDoc->DoUndo(bUndo); +} + + +void SwUndoPageDescCreate::Redo(SwUndoIter &) +{ + BOOL bUndo = pDoc->DoesUndo(); + + pDoc->DoUndo(FALSE); + + SwPageDesc aPageDesc = aNew; + pDoc->MakePageDesc(aNew.GetName(), &aPageDesc, FALSE, TRUE); // #116530# + + pDoc->DoUndo(bUndo); +} + +void SwUndoPageDescCreate::Repeat(SwUndoIter & rIt) +{ + Redo(rIt); +} + +SwRewriter SwUndoPageDescCreate::GetRewriter() const +{ + SwRewriter aResult; + + if (pDesc) + aResult.AddRule(UNDO_ARG1, pDesc->GetName()); + else + aResult.AddRule(UNDO_ARG1, aNew.GetName()); + + + return aResult; +} + +SwUndoPageDescDelete::SwUndoPageDescDelete(const SwPageDesc & _aOld, + SwDoc * _pDoc) + : SwUndo(UNDO_DELETE_PAGEDESC), aOld(_aOld, _pDoc), pDoc(_pDoc) +{ + ASSERT(0 != pDoc, "no document?"); +} + +SwUndoPageDescDelete::~SwUndoPageDescDelete() +{ +} + +void SwUndoPageDescDelete::Undo(SwUndoIter &) +{ + BOOL bUndo = pDoc->DoesUndo(); + + pDoc->DoUndo(FALSE); + + SwPageDesc aPageDesc = aOld; + pDoc->MakePageDesc(aOld.GetName(), &aPageDesc, FALSE, TRUE); // #116530# + pDoc->DoUndo(bUndo); +} + +void SwUndoPageDescDelete::Redo(SwUndoIter &) +{ + BOOL bUndo = pDoc->DoesUndo(); + + pDoc->DoUndo(FALSE); + pDoc->DelPageDesc(aOld.GetName(), TRUE); // #116530# + pDoc->DoUndo(bUndo); +} + +void SwUndoPageDescDelete::Repeat(SwUndoIter & rIt) +{ + Redo(rIt); +} + +SwRewriter SwUndoPageDescDelete::GetRewriter() const +{ + SwRewriter aResult; + + aResult.AddRule(UNDO_ARG1, aOld.GetName()); + + return aResult; +} diff --git a/sw/source/core/undo/SwUndoTOXChange.cxx b/sw/source/core/undo/SwUndoTOXChange.cxx new file mode 100644 index 000000000000..8628ff70acc7 --- /dev/null +++ b/sw/source/core/undo/SwUndoTOXChange.cxx @@ -0,0 +1,71 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" +#include <SwUndoTOXChange.hxx> +#include <swundo.hxx> +#include <doctxm.hxx> + +SwUndoTOXChange::SwUndoTOXChange(SwTOXBase * _pTOX, const SwTOXBase & rNew) + : SwUndo(UNDO_TOXCHANGE), pTOX(_pTOX), aOld(*_pTOX), aNew(rNew) +{ +} + +SwUndoTOXChange::~SwUndoTOXChange() +{ +} + +void SwUndoTOXChange::UpdateTOXBaseSection() +{ + if (pTOX->ISA(SwTOXBaseSection)) + { + SwTOXBaseSection * pTOXBase = static_cast<SwTOXBaseSection *>(pTOX); + + pTOXBase->Update(); + pTOXBase->UpdatePageNum(); + } +} + +void SwUndoTOXChange::Undo(SwUndoIter &) +{ + *pTOX = aOld; + + UpdateTOXBaseSection(); +} + +void SwUndoTOXChange::Redo(SwUndoIter &) +{ + *pTOX = aNew; + + UpdateTOXBaseSection(); +} + +void SwUndoTOXChange::Repeat(SwUndoIter & rIter) +{ + Redo(rIter); +} diff --git a/sw/source/core/undo/docundo.cxx b/sw/source/core/undo/docundo.cxx new file mode 100644 index 000000000000..85adbd1c7138 --- /dev/null +++ b/sw/source/core/undo/docundo.cxx @@ -0,0 +1,1027 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <svx/svdmodel.hxx> + +#include <vcl/wrkwin.hxx> +#include <doc.hxx> +#include <pam.hxx> +#include <ndtxt.hxx> +#include <swundo.hxx> // fuer die UndoIds +#include <undobj.hxx> +#include <rolbck.hxx> +#include <docary.hxx> +#ifndef _UNDO_HRC +#include <undo.hrc> +#endif + + +using namespace ::com::sun::star; + + +USHORT SwDoc::nUndoActions = UNDO_ACTION_COUNT; // anzahl von Undo-Action + +// the undo array should never grow beyond this limit: +#define UNDO_ACTION_LIMIT (USHRT_MAX - 1000) + + +SV_IMPL_PTRARR( SwUndoIds, SwUndoIdAndNamePtr ) + +//#define _SHOW_UNDORANGE +#ifdef _SHOW_UNDORANGE + + +class UndoArrStatus : public WorkWindow +{ + USHORT nUndo, nUndoNds; + virtual void Paint( const Rectangle& ); +public: + UndoArrStatus(); + void Set( USHORT, USHORT ); +}; +static UndoArrStatus* pUndoMsgWin = 0; + + +UndoArrStatus::UndoArrStatus() + : WorkWindow( APP_GETAPPWINDOW() ), nUndo(0), nUndoNds(0) +{ + SetSizePixel( Size( 200, 100 )); + SetFont( Font( "Courier", Size( 0, 10 )) ); + Show(); +} + + +void UndoArrStatus::Set( USHORT n1, USHORT n2 ) +{ + nUndo = n1; nUndoNds = n2; + Invalidate(); +} + + +void UndoArrStatus::Paint( const Rectangle& ) +{ + String s; + DrawRect( Rectangle( Point(0,0), GetOutputSize() )); + ( s = "Undos: " ) += nUndo; + DrawText( Point( 0, 0 ), s ); + ( s = "UndoNodes: " ) += nUndoNds; + DrawText( Point( 0, 15 ), s ); +} + +#endif + +void SwDoc::SetUndoNoResetModified() +{ + nUndoSavePos = USHRT_MAX; +} + +bool SwDoc::IsUndoNoResetModified() const +{ + return USHRT_MAX == nUndoSavePos; +} + +void SwDoc::DoUndo(bool bUn) +{ + mbUndo = bUn; + + SdrModel* pSdrModel = GetDrawModel(); + if( pSdrModel ) + pSdrModel->EnableUndo(bUn); +} + +bool SwDoc::DoesUndo() const +{ + return mbUndo; +} + +void SwDoc::DoGroupUndo(bool bUn) +{ + mbGroupUndo = bUn; +} + +bool SwDoc::DoesGroupUndo() const +{ + return mbGroupUndo; +} + +sal_uInt16 SwDoc::GetUndoActionCount() +{ + return nUndoActions; +} + +void SwDoc::SetUndoActionCount( sal_uInt16 nNew ) +{ + nUndoActions = nNew; +} + +const SwNodes* SwDoc::GetUndoNds() const +{ + return &aUndoNodes; +} + +void SwDoc::AppendUndo( SwUndo* pUndo ) +{ + if( nsRedlineMode_t::REDLINE_NONE == pUndo->GetRedlineMode() ) + pUndo->SetRedlineMode( GetRedlineMode() ); + + // Unfortunately, the silly SvPtrArr can only store a little less than + // USHRT_MAX elements. Of course it doesn't see any necessity for asserting + // or even doing error handling. pUndos should definitely be replaced by an + // STL container that doesn't have this problem. cf #95884# + DBG_ASSERT( pUndos->Count() < USHRT_MAX - 16, + "Writer will crash soon. I apologize for the inconvenience." ); + + pUndos->Insert( pUndo, nUndoPos ); + ++nUndoPos; + switch( pUndo->GetId() ) + { + case UNDO_START: ++nUndoSttEnd; + break; + + case UNDO_END: ASSERT( nUndoSttEnd, "Undo-Ende ohne Start" ); + --nUndoSttEnd; + // kein break !!! + default: + if( pUndos->Count() != nUndoPos && UNDO_END != pUndo->GetId() ) + ClearRedo(); + else { + ASSERT( pUndos->Count() == nUndoPos || UNDO_END == pUndo->GetId(), + "Redo history not deleted!" ); + } + if( !nUndoSttEnd ) + ++nUndoCnt; + break; + } + +#ifdef _SHOW_UNDORANGE + // zur Anzeige der aktuellen Undo-Groessen + if( !pUndoMsgWin ) + pUndoMsgWin = new UndoArrStatus; + pUndoMsgWin->Set( pUndos->Count(), aUndoNodes.Count() ); +#endif + + // noch eine offene Klammerung, kann man sich den Rest schenken + if( nUndoSttEnd ) + return; + + // folgende Array-Grenzen muessen ueberwacht werden: + // - Undo, Grenze: fester Wert oder USHRT_MAX - 1000 + // - UndoNodes, Grenze: USHRT_MAX - 1000 + // - AttrHistory Grenze: USHRT_MAX - 1000 + // (defined in UNDO_ACTION_LIMIT at the top of this file) + + USHORT nEnde = UNDO_ACTION_LIMIT; + +// nur zum Testen der neuen DOC-Member +#ifdef DBG_UTIL +{ + SwUndoId nId = UNDO_EMPTY; + USHORT nUndosCnt = 0, nSttEndCnt = 0; + for( USHORT nCnt = 0; nCnt < nUndoPos; ++nCnt ) + { + if( UNDO_START == ( nId = (*pUndos)[ nCnt ]->GetId()) ) + ++nSttEndCnt; + else if( UNDO_END == nId ) + --nSttEndCnt; + if( !nSttEndCnt ) + ++nUndosCnt; + } + ASSERT( nSttEndCnt == nUndoSttEnd, "Start-Ende Count ungleich" ); + ASSERT( nUndosCnt == nUndoCnt, "Undo Count ungleich" ); +} +#endif + + if( SwDoc::nUndoActions < nUndoCnt ) + // immer 1/10 loeschen + //JP 23.09.95: oder wenn neu eingestellt wurde um die Differenz + //JP 29.5.2001: Task #83891#: remove only the overlapping actions + DelUndoObj( nUndoCnt - SwDoc::nUndoActions ); + else + { + USHORT nUndosCnt = nUndoCnt; + // immer 1/10 loeschen bis der "Ausloeser" behoben ist + while( aUndoNodes.Count() && nEnde < aUndoNodes.Count() ) + DelUndoObj( nUndosCnt / 10 ); + } +} + + + +void SwDoc::ClearRedo() +{ + if( DoesUndo() && nUndoPos != pUndos->Count() ) + { +//?? why ?? if( !nUndoSttEnd ) + { + // setze UndoCnt auf den neuen Wert + SwUndo* pUndo; + for( USHORT nCnt = pUndos->Count(); nUndoPos < nCnt; --nUndoCnt ) + // Klammerung ueberspringen + if( UNDO_END == (pUndo = (*pUndos)[ --nCnt ])->GetId() ) + nCnt = nCnt - ((SwUndoEnd*)pUndo)->GetSttOffset(); + } + + // loesche die Undo-Aktionen (immer von hinten !) + pUndos->DeleteAndDestroy( nUndoPos, pUndos->Count() - nUndoPos ); + } +} + + + // loescht die gesamten UndoObjecte +void SwDoc::DelAllUndoObj() +{ + ClearRedo(); + + DoUndo( FALSE ); + + // Offene Undo-Klammerungen erhalten !! + SwUndo* pUndo; + USHORT nSize = pUndos->Count(); + while( nSize ) + if( UNDO_START != ( pUndo = (*pUndos)[ --nSize ] )->GetId() || + ((SwUndoStart*)pUndo)->GetEndOffset() ) + // keine offenen Gruppierung ? + pUndos->DeleteAndDestroy( nSize, 1 ); + + nUndoCnt = 0; + nUndoPos = pUndos->Count(); + +/* + while( nUndoPos ) + aUndos.DelDtor( --nUndoPos, 1 ); + nUndoCnt = nUndoSttEnd = nUndoPos = 0; +*/ + nUndoSavePos = USHRT_MAX; + DoUndo( TRUE ); +} + + + // loescht alle UndoObjecte vom Anfang bis zum angegebenen Ende +BOOL SwDoc::DelUndoObj( USHORT nEnde ) +{ + if( !nEnde ) // sollte mal 0 uebergeben werden, + { + if( !pUndos->Count() ) + return FALSE; + ++nEnde; // dann korrigiere es auf 1 + } + + DoUndo( FALSE ); + + // pruefe erstmal, wo das Ende steht + SwUndoId nId = UNDO_EMPTY; + USHORT nSttEndCnt = 0; + USHORT nCnt; + + for( nCnt = 0; nEnde && nCnt < nUndoPos; ++nCnt ) + { + if( UNDO_START == ( nId = (*pUndos)[ nCnt ]->GetId() )) + ++nSttEndCnt; + else if( UNDO_END == nId ) + --nSttEndCnt; + if( !nSttEndCnt ) + --nEnde, --nUndoCnt; + } + + ASSERT( nCnt < nUndoPos || nUndoPos == pUndos->Count(), + "Undo-Del-Ende liegt in einer Redo-Aktion" ); + + // dann setze ab Ende bis Undo-Ende bei allen Undo-Objecte die Werte um + nSttEndCnt = nCnt; // Position merken + if( nUndoSavePos < nSttEndCnt ) // SavePos wird aufgegeben + nUndoSavePos = USHRT_MAX; + else if( nUndoSavePos != USHRT_MAX ) + nUndoSavePos = nUndoSavePos - nSttEndCnt; + + while( nSttEndCnt ) + pUndos->DeleteAndDestroy( --nSttEndCnt, 1 ); + nUndoPos = pUndos->Count(); + + DoUndo( TRUE ); + return TRUE; +} + +/**************** UNDO ******************/ + +void SwDoc::setUndoNoModifiedPosition( SwUndoNoModifiedPosition nNew ) +{ + nUndoSavePos = nNew; + if( !pUndos->Count() || nUndoSavePos > pUndos->Count() - 1 ) + nUndoSavePos = USHRT_MAX; +} + +SwUndoNoModifiedPosition SwDoc::getUndoNoModifiedPosition() const +{ + return nUndoSavePos; +} + + +bool SwDoc::HasUndoId(SwUndoId eId) const +{ + USHORT nSize = nUndoPos; + SwUndo * pUndo; + while( nSize-- ) + if( ( pUndo = (*pUndos)[nSize])->GetId() == eId || + ( UNDO_START == pUndo->GetId() && + ((SwUndoStart*)pUndo)->GetUserId() == eId ) + || ( UNDO_END == pUndo->GetId() && + ((SwUndoEnd*)pUndo)->GetUserId() == eId ) ) + { + return TRUE; + } + + return FALSE; +} + + +bool SwDoc::Undo( SwUndoIter& rUndoIter ) +{ + if ( (rUndoIter.GetId()!=0) && (!HasUndoId(rUndoIter.GetId())) ) + { + rUndoIter.bWeiter = FALSE; + return FALSE; + } + if( !nUndoPos ) + { + rUndoIter.bWeiter = FALSE; + return FALSE; + } + + SwUndo *pUndo = (*pUndos)[ --nUndoPos ]; + + RedlineMode_t eOld = GetRedlineMode(); + RedlineMode_t eTmpMode = (RedlineMode_t)pUndo->GetRedlineMode(); + if( (nsRedlineMode_t::REDLINE_SHOW_MASK & eTmpMode) != (nsRedlineMode_t::REDLINE_SHOW_MASK & eOld) && + UNDO_START != pUndo->GetId() && UNDO_END != pUndo->GetId() ) + SetRedlineMode( eTmpMode ); + + SetRedlineMode_intern((RedlineMode_t)(eTmpMode | nsRedlineMode_t::REDLINE_IGNORE)); + // Undo ausfuehren + + // zum spaeteren ueberpruefen + SwUndoId nAktId = pUndo->GetId(); + //JP 11.05.98: FlyFormate ueber die EditShell selektieren, nicht aus dem + // Undo heraus + switch( nAktId ) + { + case UNDO_START: + case UNDO_END: + case UNDO_INSDRAWFMT: + break; + + default: + rUndoIter.ClearSelections(); + } + + pUndo->Undo( rUndoIter ); + + SetRedlineMode( eOld ); + + // Besonderheit von Undo-Replace (interne History) + if( UNDO_REPLACE == nAktId && ((SwUndoReplace*)pUndo)->nAktPos ) + { + ++nUndoPos; + return TRUE; + } + + // Objekt aus History entfernen und zerstoeren + if( nUndoPos && !rUndoIter.bWeiter && + UNDO_START == ( pUndo = (*pUndos)[ nUndoPos-1 ] )->GetId() ) + --nUndoPos; + + // JP 29.10.96: Start und End setzen kein Modify-Flag. + // Sonst gibt es Probleme mit der autom. Aufnahme von Ausnahmen + // bei der Autokorrektur + if( UNDO_START != nAktId && UNDO_END != nAktId ) + SetModified(); // default: immer setzen, kann zurueck gesetzt werden + + // ist die History leer und wurde nicht wegen Speichermangel + // verworfen, so kann das Dokument als unveraendert gelten + if( nUndoSavePos == nUndoPos ) + ResetModified(); + + return TRUE; +} + + +// setzt Undoklammerung auf, liefert nUndoId der Klammerung + + +SwUndoId SwDoc::StartUndo( SwUndoId eUndoId, const SwRewriter * pRewriter ) +{ + if( !mbUndo ) + return UNDO_EMPTY; + + if( !eUndoId ) + eUndoId = UNDO_START; + + SwUndoStart * pUndo = new SwUndoStart( eUndoId ); + + if (pRewriter) + pUndo->SetRewriter(*pRewriter); + + AppendUndo(pUndo); + + return eUndoId; +} +// schliesst Klammerung der nUndoId, nicht vom UI benutzt + + +SwUndoId SwDoc::EndUndo(SwUndoId eUndoId, const SwRewriter * pRewriter) +{ + USHORT nSize = nUndoPos; + if( !mbUndo || !nSize-- ) + return UNDO_EMPTY; + + if( UNDO_START == eUndoId || !eUndoId ) + eUndoId = UNDO_END; + + SwUndo* pUndo = (*pUndos)[ nSize ]; + if( UNDO_START == pUndo->GetId() ) + { + // leere Start/End-Klammerung ?? + pUndos->DeleteAndDestroy( nSize ); + --nUndoPos; + --nUndoSttEnd; + return UNDO_EMPTY; + } + + // exist above any redo objects? If yes, delete them + if( nUndoPos != pUndos->Count() ) + { + // setze UndoCnt auf den neuen Wert + for( USHORT nCnt = pUndos->Count(); nUndoPos < nCnt; --nUndoCnt ) + // Klammerung ueberspringen + if( UNDO_END == (pUndo = (*pUndos)[ --nCnt ])->GetId() ) + nCnt = nCnt - ((SwUndoEnd*)pUndo)->GetSttOffset(); + + pUndos->DeleteAndDestroy( nUndoPos, pUndos->Count() - nUndoPos ); + } + + // suche den Anfang dieser Klammerung + SwUndoId nId = UNDO_EMPTY; + while( nSize ) + if( UNDO_START == ( nId = (pUndo = (*pUndos)[ --nSize ] )->GetId()) && + !((SwUndoStart*)pUndo)->GetEndOffset() ) + break; // Start gefunden + + if( nId != UNDO_START ) + { + // kann eigentlich nur beim Abspielen von Macros passieren, die + // Undo/Redo/Repeat benutzen und die eine exitierende Selection + // durch Einfuegen loeschen + ASSERT( !this, "kein entsprechendes Ende gefunden" ); + // kein entsprechenden Start gefunden -> Ende nicht einfuegen + // und die Member am Doc updaten + + nUndoSttEnd = 0; + nUndoCnt = 0; + // setze UndoCnt auf den neuen Wert + SwUndo* pTmpUndo; + for( USHORT nCnt = 0; nCnt < pUndos->Count(); ++nCnt, ++nUndoCnt ) + // Klammerung ueberspringen + if( UNDO_START == (pTmpUndo = (*pUndos)[ nCnt ])->GetId() ) + nCnt = nCnt + ((SwUndoStart*)pTmpUndo)->GetEndOffset(); + return UNDO_EMPTY; + + } + + // Klammerung um eine einzelne Action muss nicht sein! + // Aussnahme: es ist eine eigene ID definiert + if( 2 == pUndos->Count() - nSize && + (UNDO_END == eUndoId || eUndoId == (*pUndos)[ nSize+1 ]->GetId() )) + { + pUndos->DeleteAndDestroy( nSize ); + nUndoPos = pUndos->Count(); + if( !--nUndoSttEnd ) + { + ++nUndoCnt; + if( SwDoc::nUndoActions < nUndoCnt ) + // immer 1/10 loeschen + //JP 23.09.95: oder wenn neu eingestellt wurde um die Differenz + //JP 29.5.2001: Task #83891#: remove only the overlapping actions + DelUndoObj( nUndoCnt - SwDoc::nUndoActions ); + else + { + USHORT nEnde = USHRT_MAX - 1000; + USHORT nUndosCnt = nUndoCnt; + // immer 1/10 loeschen bis der "Ausloeser" behoben ist + while( aUndoNodes.Count() && nEnde < aUndoNodes.Count() ) + DelUndoObj( nUndosCnt / 10 ); + } + } + return eUndoId; + } + + // setze die Klammerung am Start/End-Undo + nSize = pUndos->Count() - nSize; + ((SwUndoStart*)pUndo)->SetEndOffset( nSize ); + + SwUndoEnd* pUndoEnd = new SwUndoEnd( eUndoId ); + pUndoEnd->SetSttOffset( nSize ); + +// nur zum Testen der Start/End-Verpointerung vom Start/End Undo +#ifdef DBG_UTIL + { + USHORT nEndCnt = 1, nCnt = pUndos->Count(); + SwUndoId nTmpId = UNDO_EMPTY; + while( nCnt ) + { + if( UNDO_START == ( nTmpId = (*pUndos)[ --nCnt ]->GetId()) ) + { + if( !nEndCnt ) // falls mal ein Start ohne Ende vorhanden ist + continue; + --nEndCnt; + if( !nEndCnt ) // hier ist der Anfang + break; + } + else if( UNDO_END == nTmpId ) + ++nEndCnt; + else if( !nEndCnt ) + break; + } + ASSERT( nCnt == pUndos->Count() - nSize, + "Start-Ende falsch geklammert" ); + } +#endif + + if (pRewriter) + { + ((SwUndoStart *) pUndo)->SetRewriter(*pRewriter); + pUndoEnd->SetRewriter(*pRewriter); + } + else + pUndoEnd->SetRewriter(((SwUndoStart *) pUndo)->GetRewriter()); + + AppendUndo( pUndoEnd ); + return eUndoId; +} + +// liefert die Id der letzten Undofaehigen Aktion zurueck oder 0 +// fuellt ggf. VARARR mit User-UndoIds + +String SwDoc::GetUndoIdsStr( String* pStr, SwUndoIds *pUndoIds) const +{ + String aTmpStr; + + if (pStr != NULL) + { + GetUndoIds( pStr, pUndoIds); + aTmpStr = *pStr; + } + else + GetUndoIds( &aTmpStr, pUndoIds); + + return aTmpStr; +} + +/*-- 24.11.2004 16:11:21--------------------------------------------------- + + -----------------------------------------------------------------------*/ +sal_Bool SwDoc::RestoreInvisibleContent() +{ + sal_Bool bRet = sal_False; + if(nUndoPos > 0 ) + { + SwUndo * pUndo = (*pUndos)[ nUndoPos - 1 ]; + if( ( pUndo->GetId() == UNDO_END && + static_cast<SwUndoEnd *>(pUndo)->GetUserId() == UNDO_UI_DELETE_INVISIBLECNTNT) ) + { + SwPaM aPam( GetNodes().GetEndOfPostIts() ); + SwUndoIter aUndoIter( &aPam ); + do + { + Undo( aUndoIter ); + } + while ( aUndoIter.IsNextUndo() ); + ClearRedo(); + bRet = sal_True; + } + } + return bRet; +} + + +/** + Returns id and comment for a certain undo object in an undo stack. + + Remark: In the following the object type referred to is always the + effective object type. If an UNDO_START or UNDO_END has a user type + it is referred to as this type. + + If the queried object is an UNDO_END and has no user id the result + is taken from the first object that is not an UNDO_END nor an + UNDO_START preceeding the queried object. + + If the queried object is an UNDO_START and has no user id the + result is taken from the first object that is not an UNDO_END nor + an UNDO_START preceeding the UNDO_END object belonging to the + queried object. + + In all other cases the result is taken from the queried object. + + @param rUndos the undo stack + @param nPos position of the undo object to query + + @return SwUndoIdAndName object containing the query result + */ +SwUndoIdAndName * lcl_GetUndoIdAndName(const SwUndos & rUndos, sal_uInt16 nPos ) +{ + SwUndo * pUndo = rUndos[ nPos ]; + SwUndoId nId = UNDO_EMPTY; + String sStr("??", RTL_TEXTENCODING_ASCII_US); + + ASSERT( nPos < rUndos.Count(), "nPos out of range"); + + switch (pUndo->GetId()) + { + case UNDO_START: + { + SwUndoStart * pUndoStart = (SwUndoStart *) pUndo; + nId = pUndoStart->GetUserId(); + + if (nId <= UNDO_END) + { + /** + Start at the according UNDO_END. Search backwards + for first objects that is not a UNDO_END. + */ + int nTmpPos = nPos + pUndoStart->GetEndOffset(); + int nSubstitute = -1; + + // --> OD 2009-09-30 #i105457# + if ( nTmpPos > 0 ) + // <-- + { + SwUndo * pTmpUndo; + do + { + nTmpPos--; + pTmpUndo = rUndos[ static_cast<USHORT>(nTmpPos) ]; + + if (pTmpUndo->GetEffectiveId() > UNDO_END) + nSubstitute = nTmpPos; + } + while (nSubstitute < 0 && nTmpPos > nPos); + + if (nSubstitute >= 0) + { + SwUndo * pSubUndo = rUndos[ static_cast<USHORT>(nSubstitute) ]; + nId = pSubUndo->GetEffectiveId(); + sStr = pSubUndo->GetComment(); + } + } + } + else + sStr = pUndo->GetComment(); + } + + break; + + case UNDO_END: + { + SwUndoEnd * pUndoEnd = (SwUndoEnd *) pUndo; + nId = pUndoEnd->GetUserId(); + + if (nId <= UNDO_END) + { + /** + Start at this UNDO_END. Search backwards + for first objects that is not a UNDO_END. + */ + + int nTmpPos = nPos; + int nUndoStart = nTmpPos - pUndoEnd->GetSttOffset(); + int nSubstitute = -1; + + if (nTmpPos > 0) + { + SwUndo * pTmpUndo; + + do + { + nTmpPos--; + pTmpUndo = rUndos[ static_cast<USHORT>(nTmpPos) ]; + + if (pTmpUndo->GetEffectiveId() > UNDO_END) + nSubstitute = nTmpPos; + } + while (nSubstitute < 0 && nTmpPos > nUndoStart); + + if (nSubstitute >= 0) + { + SwUndo * pSubUndo = rUndos[ static_cast<USHORT>(nSubstitute) ]; + nId = pSubUndo->GetEffectiveId(); + sStr = pSubUndo->GetComment(); + } + } + } + else + sStr = pUndo->GetComment(); + } + + break; + + default: + nId = pUndo->GetId(); + sStr = pUndo->GetComment(); + } + + return new SwUndoIdAndName(nId, &sStr); +} + +SwUndoId SwDoc::GetUndoIds( String* pStr, SwUndoIds *pUndoIds) const +{ + int nTmpPos = nUndoPos - 1; + SwUndoId nId = UNDO_EMPTY; + + while (nTmpPos >= 0) + { + SwUndo * pUndo = (*pUndos)[ static_cast<USHORT>(nTmpPos) ]; + + SwUndoIdAndName * pIdAndName = lcl_GetUndoIdAndName( *pUndos, static_cast<sal_uInt16>(nTmpPos) ); + + if (nTmpPos == nUndoPos - 1) + { + nId = pIdAndName->GetUndoId(); + + if (pStr) + *pStr = *pIdAndName->GetUndoStr(); + } + + if (pUndoIds) + pUndoIds->Insert(pIdAndName, pUndoIds->Count()); + else + break; + + if (pUndo->GetId() == UNDO_END) + nTmpPos -= ((SwUndoEnd *) pUndo)->GetSttOffset(); + + nTmpPos--; + } + + return nId; +} + +bool SwDoc::HasTooManyUndos() const +{ + // AppendUndo checks the UNDO_ACTION_LIMIT, unless there's a nested undo. + // So HasTooManyUndos() may only occur when undos are nested; else + // AppendUndo has some sort of bug. + DBG_ASSERT( (nUndoSttEnd != 0) || (pUndos->Count() < UNDO_ACTION_LIMIT), + "non-nested undos should have been handled in AppendUndo" ); + return (pUndos->Count() >= UNDO_ACTION_LIMIT); +} + + +/**************** REDO ******************/ + + +bool SwDoc::Redo( SwUndoIter& rUndoIter ) +{ + if( rUndoIter.GetId() && !HasUndoId( rUndoIter.GetId() ) ) + { + rUndoIter.bWeiter = FALSE; + return FALSE; + } + if( nUndoPos == pUndos->Count() ) + { + rUndoIter.bWeiter = FALSE; + return FALSE; + } + + SwUndo *pUndo = (*pUndos)[ nUndoPos++ ]; + + RedlineMode_t eOld = GetRedlineMode(); + RedlineMode_t eTmpMode = (RedlineMode_t)pUndo->GetRedlineMode(); + if( (nsRedlineMode_t::REDLINE_SHOW_MASK & eTmpMode) != (nsRedlineMode_t::REDLINE_SHOW_MASK & eOld) && + UNDO_START != pUndo->GetId() && UNDO_END != pUndo->GetId() ) + SetRedlineMode( eTmpMode ); + SetRedlineMode_intern( (RedlineMode_t)(eTmpMode | nsRedlineMode_t::REDLINE_IGNORE)); + + //JP 11.05.98: FlyFormate ueber die EditShell selektieren, nicht aus dem + // Undo heraus + if( UNDO_START != pUndo->GetId() && UNDO_END != pUndo->GetId() ) + rUndoIter.ClearSelections(); + + pUndo->Redo( rUndoIter ); + + SetRedlineMode( eOld ); + + // Besonderheit von Undo-Replace (interne History) + if( UNDO_REPLACE == pUndo->GetId() && + USHRT_MAX != ((SwUndoReplace*)pUndo)->nAktPos ) + { + --nUndoPos; + return TRUE; + } + + if( rUndoIter.bWeiter && nUndoPos >= pUndos->Count() ) + rUndoIter.bWeiter = FALSE; + + // ist die History leer und wurde nicht wegen Speichermangel + // verworfen, so kann das Dokument als unveraendert gelten + if( nUndoSavePos == nUndoPos ) + ResetModified(); + else + SetModified(); + return TRUE; +} + + +// liefert die Id der letzten Redofaehigen Aktion zurueck oder 0 +// fuellt ggf. VARARR mit User-RedoIds + +String SwDoc::GetRedoIdsStr( String* pStr, SwUndoIds *pRedoIds ) const +{ + String aTmpStr; + + if (pStr != NULL) + { + GetRedoIds( pStr, pRedoIds ); + aTmpStr = *pStr; + } + else + GetRedoIds( &aTmpStr, pRedoIds ); + + + return aTmpStr; +} + + +SwUndoId SwDoc::GetRedoIds( String* pStr, SwUndoIds *pRedoIds ) const +{ + sal_uInt16 nTmpPos = nUndoPos; + SwUndoId nId = UNDO_EMPTY; + + while (nTmpPos < pUndos->Count()) + { + SwUndo * pUndo = (*pUndos)[nTmpPos]; + + SwUndoIdAndName * pIdAndName = lcl_GetUndoIdAndName(*pUndos, nTmpPos); + + if (nTmpPos == nUndoPos) + { + nId = pIdAndName->GetUndoId(); + + if (pStr) + *pStr = *pIdAndName->GetUndoStr(); + } + + if (pRedoIds) + pRedoIds->Insert(pIdAndName, pRedoIds->Count()); + else + break; + + if (pUndo->GetId() == UNDO_START) + nTmpPos = nTmpPos + ((SwUndoStart *) pUndo)->GetEndOffset(); + + nTmpPos++; + } + + return nId; +} + +/**************** REPEAT ******************/ + + +bool SwDoc::Repeat( SwUndoIter& rUndoIter, sal_uInt16 nRepeatCnt ) +{ + if( rUndoIter.GetId() && !HasUndoId( rUndoIter.GetId() ) ) + { + rUndoIter.bWeiter = FALSE; + return FALSE; + } + USHORT nSize = nUndoPos; + if( !nSize ) + { + rUndoIter.bWeiter = FALSE; + return FALSE; + } + + // dann suche jetzt ueber die End/Start-Gruppen die gueltige Repeat-Aktion + SwUndo *pUndo = (*pUndos)[ --nSize ]; + if( UNDO_END == pUndo->GetId() ) + nSize = nSize - ((SwUndoEnd*)pUndo)->GetSttOffset(); + + USHORT nEndCnt = nUndoPos; + BOOL bOneUndo = nSize + 1 == nUndoPos; + + SwPaM* pTmpCrsr = rUndoIter.pAktPam; + SwUndoId nId = UNDO_EMPTY; + + if( pTmpCrsr != pTmpCrsr->GetNext() || !bOneUndo ) // Undo-Klammerung aufbauen + { + if (pUndo->GetId() == UNDO_END) + { + SwUndoStart * pStartUndo = + (SwUndoStart *) (*pUndos)[nSize]; + + nId = pStartUndo->GetUserId(); + } + + StartUndo( nId, NULL ); + } + do { // dann durchlaufe mal den gesamten Ring + for( USHORT nRptCnt = nRepeatCnt; nRptCnt > 0; --nRptCnt ) + { + rUndoIter.pLastUndoObj = 0; + for( USHORT nCnt = nSize; nCnt < nEndCnt; ++nCnt ) + (*pUndos)[ nCnt ]->Repeat( rUndoIter ); // Repeat ausfuehren + } + } while( pTmpCrsr != + ( rUndoIter.pAktPam = (SwPaM*)rUndoIter.pAktPam->GetNext() )); + if( pTmpCrsr != pTmpCrsr->GetNext() || !bOneUndo ) + EndUndo( nId, NULL ); + + return TRUE; +} + +// liefert die Id der letzten Repeatfaehigen Aktion zurueck oder 0 +// fuellt ggf. VARARR mit User-RedoIds + +String SwDoc::GetRepeatIdsStr(String* pStr, SwUndoIds *pRepeatIds) const +{ + String aTmpStr; + SwUndoId nId; + + if ( pStr != NULL) + { + nId = GetRepeatIds(pStr, pRepeatIds); + aTmpStr = *pStr; + } + else + nId = GetRepeatIds(&aTmpStr, pRepeatIds); + + if (nId <= UNDO_END) + return String(); + + return aTmpStr; +} + +SwUndoId SwDoc::GetRepeatIds(String* pStr, SwUndoIds *pRepeatIds) const +{ + SwUndoId nRepeatId = GetUndoIds( pStr, pRepeatIds ); + if( REPEAT_START <= nRepeatId && REPEAT_END > nRepeatId ) + return nRepeatId; + return UNDO_EMPTY; +} + + +SwUndo* SwDoc::RemoveLastUndo( SwUndoId eUndoId ) +{ + SwUndo* pUndo = (*pUndos)[ nUndoPos - 1 ]; + if( eUndoId == pUndo->GetId() && nUndoPos == pUndos->Count() ) + { + if( !nUndoSttEnd ) + --nUndoCnt; + --nUndoPos; + pUndos->Remove( nUndoPos, 1 ); + } + else + { + pUndo = 0; + ASSERT( !this, "falsches Undo-Object" ); + } + return pUndo; +} + +SwUndoIdAndName::SwUndoIdAndName( SwUndoId nId, const String* pStr ) + : eUndoId( nId ), pUndoStr( pStr ? new String( *pStr ) : 0 ) +{ +} + +SwUndoIdAndName::~SwUndoIdAndName() +{ + delete pUndoStr; +} + + + diff --git a/sw/source/core/undo/makefile.mk b/sw/source/core/undo/makefile.mk new file mode 100644 index 000000000000..c381761adba1 --- /dev/null +++ b/sw/source/core/undo/makefile.mk @@ -0,0 +1,86 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/..$/.. + +PRJNAME=sw +TARGET=undo + +AUTOSEG=true + +# --- Settings ----------------------------------------------------- + +.INCLUDE : $(PRJ)$/inc$/swpre.mk +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/inc$/sw.mk + +# --- Files -------------------------------------------------------- + +SRS1NAME=$(TARGET) +SRC1FILES = \ + undo.src + +EXCEPTIONSFILES = \ + $(SLO)$/SwRewriter.obj \ + $(SLO)$/unattr.obj \ + $(SLO)$/undobj.obj \ + $(SLO)$/undraw.obj \ + $(SLO)$/unovwr.obj \ + $(SLO)$/untbl.obj + +SLOFILES = \ + $(SLO)$/SwRewriter.obj \ + $(SLO)$/SwUndoField.obj \ + $(SLO)$/SwUndoPageDesc.obj \ + $(SLO)$/SwUndoFmt.obj \ + $(SLO)$/SwUndoTOXChange.obj \ + $(SLO)$/docundo.obj \ + $(SLO)$/rolbck.obj \ + $(SLO)$/unattr.obj \ + $(SLO)$/unbkmk.obj \ + $(SLO)$/undel.obj \ + $(SLO)$/undobj.obj \ + $(SLO)$/undobj1.obj \ + $(SLO)$/undoflystrattr.obj \ + $(SLO)$/undraw.obj \ + $(SLO)$/unfmco.obj \ + $(SLO)$/unins.obj \ + $(SLO)$/unmove.obj \ + $(SLO)$/unnum.obj \ + $(SLO)$/unoutl.obj \ + $(SLO)$/unovwr.obj \ + $(SLO)$/unredln.obj \ + $(SLO)$/unsect.obj \ + $(SLO)$/unsort.obj \ + $(SLO)$/unspnd.obj \ + $(SLO)$/untbl.obj \ + $(SLO)$/untblk.obj + +# --- Tagets ------------------------------------------------------- + +.INCLUDE : target.mk + diff --git a/sw/source/core/undo/rolbck.cxx b/sw/source/core/undo/rolbck.cxx new file mode 100644 index 000000000000..6df9f9aa24b8 --- /dev/null +++ b/sw/source/core/undo/rolbck.cxx @@ -0,0 +1,1524 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <hintids.hxx> +#include <svl/itemiter.hxx> +#include <fmtftn.hxx> +#include <fchrfmt.hxx> +#include <fmtflcnt.hxx> +#include <fmtrfmrk.hxx> +#include <fmtfld.hxx> +#include <fmtpdsc.hxx> +#include <txtfld.hxx> +#include <txtrfmrk.hxx> +#include <txttxmrk.hxx> +#include <txtftn.hxx> +#include <txtflcnt.hxx> +#include <fmtanchr.hxx> +#include <fmtcnct.hxx> +#include <frmfmt.hxx> +#include <ftnidx.hxx> +#include <doc.hxx> // SwDoc.GetNodes() +#include <docary.hxx> +#include <ndtxt.hxx> // SwTxtNode +#include <paratr.hxx> // +#include <cellatr.hxx> // +#include <fldbas.hxx> // fuer Felder +#include <pam.hxx> // fuer SwPaM +#include <swtable.hxx> +#include <rolbck.hxx> +#include <ndgrf.hxx> // SwGrfNode +#include <undobj.hxx> // fuer UndoDelete +#include <IMark.hxx> // fuer SwBookmark +#include <charfmt.hxx> // #i27615# +#ifndef _COMCORE_HRC +#include <comcore.hrc> +#endif +#include <tools/resid.hxx> +#ifndef _UNDO_HRC +#include <undo.hrc> +#endif +#include <editeng/brkitem.hxx> +#include <bookmrk.hxx> + +SV_IMPL_PTRARR( SwpHstry, SwHistoryHintPtr) + +String SwHistoryHint::GetDescription() const +{ + return String(); +} + + +SwHistorySetFmt::SwHistorySetFmt( const SfxPoolItem* pFmtHt, ULONG nNd ) + : SwHistoryHint( HSTRY_SETFMTHNT ) + , m_pAttr( pFmtHt->Clone() ) + , m_nNodeIndex( nNd ) +{ + switch ( m_pAttr->Which() ) + { + case RES_PAGEDESC: + static_cast<SwFmtPageDesc&>(*m_pAttr).ChgDefinedIn( 0 ); + break; + case RES_PARATR_DROP: + static_cast<SwFmtDrop&>(*m_pAttr).ChgDefinedIn( 0 ); + break; + case RES_BOXATR_FORMULA: + { + //JP 30.07.98: Bug 54295 - Formeln immer im Klartext speichern + SwTblBoxFormula& rNew = static_cast<SwTblBoxFormula&>(*m_pAttr); + if ( rNew.IsIntrnlName() ) + { + const SwTblBoxFormula& rOld = + *static_cast<const SwTblBoxFormula*>(pFmtHt); + const SwNode* pNd = rOld.GetNodeOfFormula(); + if ( pNd ) + { + const SwTableNode* pTableNode = pNd->FindTableNode(); + if (pTableNode) + { + SwTableFmlUpdate aMsgHnt( &pTableNode->GetTable() ); + aMsgHnt.eFlags = TBL_BOXNAME; + rNew.ChgDefinedIn( rOld.GetDefinedIn() ); + rNew.ChangeState( &aMsgHnt ); + } + } + } + rNew.ChgDefinedIn( 0 ); + } + break; + } +} + +String SwHistorySetFmt::GetDescription() const +{ + String aResult ; + + USHORT nWhich = m_pAttr->Which(); + switch (nWhich) + { + case RES_BREAK: + switch ((static_cast<SvxFmtBreakItem &>(*m_pAttr)).GetBreak()) + { + case SVX_BREAK_PAGE_BEFORE: + case SVX_BREAK_PAGE_AFTER: + case SVX_BREAK_PAGE_BOTH: + aResult = SW_RES(STR_UNDO_PAGEBREAKS); + + break; + case SVX_BREAK_COLUMN_BEFORE: + case SVX_BREAK_COLUMN_AFTER: + case SVX_BREAK_COLUMN_BOTH: + aResult = SW_RES(STR_UNDO_COLBRKS); + + break; + default: + break; + } + break; + default: + break; + } + + return aResult; +} + +void SwHistorySetFmt::SetInDoc( SwDoc* pDoc, bool bTmpSet ) +{ + SwNode * pNode = pDoc->GetNodes()[ m_nNodeIndex ]; + if ( pNode->IsCntntNode() ) + { + static_cast<SwCntntNode*>(pNode)->SetAttr( *m_pAttr ); + } + else if ( pNode->IsTableNode() ) + { + static_cast<SwTableNode*>(pNode)->GetTable().GetFrmFmt()->SetFmtAttr( + *m_pAttr ); + } + else if ( pNode->IsStartNode() && (SwTableBoxStartNode == + static_cast<SwStartNode*>(pNode)->GetStartNodeType()) ) + { + SwTableNode* pTNd = pNode->FindTableNode(); + if ( pTNd ) + { + SwTableBox* pBox = pTNd->GetTable().GetTblBox( m_nNodeIndex ); + if (pBox) + { + pBox->ClaimFrmFmt()->SetFmtAttr( *m_pAttr ); + } + } + } + + if ( !bTmpSet ) + { + m_pAttr.reset(); + } +} + +SwHistorySetFmt::~SwHistorySetFmt() +{ +} + + +// --> OD 2008-02-27 #refactorlists# - removed <rDoc> +SwHistoryResetFmt::SwHistoryResetFmt(const SfxPoolItem* pFmtHt, ULONG nNodeIdx) +// <-- + : SwHistoryHint( HSTRY_RESETFMTHNT ) + , m_nNodeIndex( nNodeIdx ) + , m_nWhich( pFmtHt->Which() ) +{ +} + + +void SwHistoryResetFmt::SetInDoc( SwDoc* pDoc, bool ) +{ + SwNode * pNode = pDoc->GetNodes()[ m_nNodeIndex ]; + if ( pNode->IsCntntNode() ) + { + static_cast<SwCntntNode*>(pNode)->ResetAttr( m_nWhich ); + } + else if ( pNode->IsTableNode() ) + { + static_cast<SwTableNode*>(pNode)->GetTable().GetFrmFmt()-> + ResetFmtAttr( m_nWhich ); + } +} + + +SwHistorySetTxt::SwHistorySetTxt( SwTxtAttr* pTxtHt, ULONG nNodePos ) + : SwHistoryHint( HSTRY_SETTXTHNT ) + , m_nNodeIndex( nNodePos ) + , m_nStart( *pTxtHt->GetStart() ) + , m_nEnd( *pTxtHt->GetAnyEnd() ) +{ + // !! Achtung: folgende Attribute erzeugen keine FormatAttribute: + // - NoLineBreak, NoHypen, Inserted, Deleted + // Dafuer muessen Sonderbehandlungen gemacht werden !!! + + // ein bisschen kompliziert, aber ist Ok so: erst vom default + // eine Kopie und dann die Werte aus dem Text Attribut zuweisen + USHORT nWhich = pTxtHt->Which(); + if ( RES_TXTATR_CHARFMT == nWhich ) + { + m_pAttr.reset( new SwFmtCharFmt( pTxtHt->GetCharFmt().GetCharFmt() ) ); + } + else + { + m_pAttr.reset( pTxtHt->GetAttr().Clone() ); + } +} + + +SwHistorySetTxt::~SwHistorySetTxt() +{ +} + + +void SwHistorySetTxt::SetInDoc( SwDoc* pDoc, bool ) +{ + if ( !m_pAttr.get() ) + return; + + if ( RES_TXTATR_CHARFMT == m_pAttr->Which() ) + { + // ask the Doc if the CharFmt still exists + if ( USHRT_MAX == pDoc->GetCharFmts()->GetPos( + (static_cast<SwFmtCharFmt&>(*m_pAttr)).GetCharFmt() ) ) + return; // do not set, format does not exist + } + + SwTxtNode * pTxtNd = pDoc->GetNodes()[ m_nNodeIndex ]->GetTxtNode(); + ASSERT( pTxtNd, "SwHistorySetTxt::SetInDoc: not a TextNode" ); + + if ( pTxtNd ) + { + pTxtNd->InsertItem( *m_pAttr, m_nStart, m_nEnd, + nsSetAttrMode::SETATTR_NOTXTATRCHR | + nsSetAttrMode::SETATTR_NOHINTADJUST ); + } +} + + +SwHistorySetTxtFld::SwHistorySetTxtFld( SwTxtFld* pTxtFld, ULONG nNodePos ) + : SwHistoryHint( HSTRY_SETTXTFLDHNT ) + , m_pFldType( 0 ) + , m_pFld( new SwFmtFld( *pTxtFld->GetFld().GetFld() ) ) +{ + // only copy if not Sys-FieldType + SwDoc* pDoc = pTxtFld->GetTxtNode().GetDoc(); + + m_nFldWhich = m_pFld->GetFld()->GetTyp()->Which(); + if (m_nFldWhich == RES_DBFLD || + m_nFldWhich == RES_USERFLD || + m_nFldWhich == RES_SETEXPFLD || + m_nFldWhich == RES_DDEFLD || + !pDoc->GetSysFldType( m_nFldWhich )) + { + m_pFldType.reset( m_pFld->GetFld()->GetTyp()->Copy() ); + m_pFld->GetFld()->ChgTyp( m_pFldType.get() ); // change field type + } + m_nNodeIndex = nNodePos; + m_nPos = *pTxtFld->GetStart(); +} + +String SwHistorySetTxtFld::GetDescription() const +{ + return m_pFld->GetFld()->GetDescription();; +} + +SwHistorySetTxtFld::~SwHistorySetTxtFld() +{ +} + + +void SwHistorySetTxtFld::SetInDoc( SwDoc* pDoc, bool ) +{ + if ( !m_pFld.get() ) + return; + + SwFieldType* pNewFldType = m_pFldType.get(); + if ( !pNewFldType ) + { + pNewFldType = pDoc->GetSysFldType( m_nFldWhich ); + } + else + { + // register type with the document + pNewFldType = pDoc->InsertFldType( *m_pFldType ); + } + + m_pFld->GetFld()->ChgTyp( pNewFldType ); // change field type + + SwTxtNode * pTxtNd = pDoc->GetNodes()[ m_nNodeIndex ]->GetTxtNode(); + ASSERT( pTxtNd, "SwHistorySetTxtFld: no TextNode" ); + + if ( pTxtNd ) + { + pTxtNd->InsertItem( *m_pFld, m_nPos, m_nPos, + nsSetAttrMode::SETATTR_NOTXTATRCHR ); + } +} + + + +SwHistorySetRefMark::SwHistorySetRefMark( SwTxtRefMark* pTxtHt, ULONG nNodePos ) + : SwHistoryHint( HSTRY_SETREFMARKHNT ) + , m_RefName( pTxtHt->GetRefMark().GetRefName() ) + , m_nNodeIndex( nNodePos ) + , m_nStart( *pTxtHt->GetStart() ) + , m_nEnd( *pTxtHt->GetAnyEnd() ) +{ +} + + +void SwHistorySetRefMark::SetInDoc( SwDoc* pDoc, bool ) +{ + SwTxtNode * pTxtNd = pDoc->GetNodes()[ m_nNodeIndex ]->GetTxtNode(); + ASSERT( pTxtNd, "SwHistorySetRefMark: no TextNode" ); + if ( !pTxtNd ) + return; + + SwFmtRefMark aRefMark( m_RefName ); + + // if a reference mark without an end already exists here: must not insert! + if ( m_nStart != m_nEnd || + !pTxtNd->GetTxtAttrForCharAt( m_nStart, RES_TXTATR_REFMARK ) ) + { + pTxtNd->InsertItem( aRefMark, m_nStart, m_nEnd, + nsSetAttrMode::SETATTR_NOTXTATRCHR ); + } +} + + +SwHistorySetTOXMark::SwHistorySetTOXMark( SwTxtTOXMark* pTxtHt, ULONG nNodePos ) + : SwHistoryHint( HSTRY_SETTOXMARKHNT ) + , m_TOXMark( pTxtHt->GetTOXMark() ) + , m_TOXName( m_TOXMark.GetTOXType()->GetTypeName() ) + , m_eTOXTypes( m_TOXMark.GetTOXType()->GetType() ) + , m_nNodeIndex( nNodePos ) + , m_nStart( *pTxtHt->GetStart() ) + , m_nEnd( *pTxtHt->GetAnyEnd() ) +{ + const_cast<SwModify*>(m_TOXMark.GetRegisteredIn())->Remove( &m_TOXMark ); +} + + +void SwHistorySetTOXMark::SetInDoc( SwDoc* pDoc, bool ) +{ + SwTxtNode * pTxtNd = pDoc->GetNodes()[ m_nNodeIndex ]->GetTxtNode(); + ASSERT( pTxtNd, "SwHistorySetTOXMark: no TextNode" ); + if ( !pTxtNd ) + return; + + // search for respective TOX type + USHORT nCnt = pDoc->GetTOXTypeCount( m_eTOXTypes ); + SwTOXType* pToxType = 0; + for ( USHORT n = 0; n < nCnt; ++n ) + { + pToxType = const_cast<SwTOXType*>(pDoc->GetTOXType( m_eTOXTypes, n )); + if ( pToxType->GetTypeName() == m_TOXName ) + break; + pToxType = 0; + } + + if ( !pToxType ) // TOX type not found, create new + { + pToxType = const_cast<SwTOXType*>( + pDoc->InsertTOXType( SwTOXType( m_eTOXTypes, m_TOXName ))); + } + + SwTOXMark aNew( m_TOXMark ); + pToxType->Add( &aNew ); + + pTxtNd->InsertItem( aNew, m_nStart, m_nEnd, + nsSetAttrMode::SETATTR_NOTXTATRCHR ); +} + + +int SwHistorySetTOXMark::IsEqual( const SwTOXMark& rCmp ) const +{ + return m_TOXName == rCmp.GetTOXType()->GetTypeName() && + m_eTOXTypes == rCmp.GetTOXType()->GetType() && + m_TOXMark.GetAlternativeText() == rCmp.GetAlternativeText() && + ( (TOX_INDEX == m_eTOXTypes) + ? ( m_TOXMark.GetPrimaryKey() == rCmp.GetPrimaryKey() && + m_TOXMark.GetSecondaryKey() == rCmp.GetSecondaryKey() ) + : m_TOXMark.GetLevel() == rCmp.GetLevel() + ); +} + + +SwHistoryResetTxt::SwHistoryResetTxt( USHORT nWhich, + xub_StrLen nAttrStart, xub_StrLen nAttrEnd, ULONG nNodePos ) + : SwHistoryHint( HSTRY_RESETTXTHNT ) + , m_nNodeIndex( nNodePos ), m_nStart( nAttrStart ), m_nEnd( nAttrEnd ) + , m_nAttr( nWhich ) +{ +} + + +void SwHistoryResetTxt::SetInDoc( SwDoc* pDoc, bool ) +{ + SwTxtNode * pTxtNd = pDoc->GetNodes()[ m_nNodeIndex ]->GetTxtNode(); + ASSERT( pTxtNd, "SwHistoryResetTxt: no TextNode" ); + if ( pTxtNd ) + { + pTxtNd->DeleteAttributes( m_nAttr, m_nStart, m_nEnd ); + } +} + + +SwHistorySetFootnote::SwHistorySetFootnote( SwTxtFtn* pTxtFtn, ULONG nNodePos ) + : SwHistoryHint( HSTRY_SETFTNHNT ) + , m_pUndo( new SwUndoSaveSection ) + , m_FootnoteNumber( pTxtFtn->GetFtn().GetNumStr() ) + , m_nNodeIndex( nNodePos ) + , m_nStart( *pTxtFtn->GetStart() ) + , m_bEndNote( pTxtFtn->GetFtn().IsEndNote() ) +{ + ASSERT( pTxtFtn->GetStartNode(), + "SwHistorySetFootnote: Footnote without Section" ); + + // merke die alte NodePos, denn wer weiss was alles in der SaveSection + // gespeichert (geloescht) wird + SwDoc* pDoc = const_cast<SwDoc*>(pTxtFtn->GetTxtNode().GetDoc()); + SwNode* pSaveNd = pDoc->GetNodes()[ m_nNodeIndex ]; + + //Pointer auf StartNode der FtnSection merken und erstmal den Pointer im + //Attribut zuruecksetzen -> Damit werden automatisch die Frms vernichtet. + SwNodeIndex aSttIdx( *pTxtFtn->GetStartNode() ); + pTxtFtn->SetStartNode( 0, FALSE ); + + m_pUndo->SaveSection( pDoc, aSttIdx ); + m_nNodeIndex = pSaveNd->GetIndex(); +} + +SwHistorySetFootnote::SwHistorySetFootnote( const SwTxtFtn &rTxtFtn ) + : SwHistoryHint( HSTRY_SETFTNHNT ) + , m_pUndo( 0 ) + , m_FootnoteNumber( rTxtFtn.GetFtn().GetNumStr() ) + , m_nNodeIndex( _SwTxtFtn_GetIndex( (&rTxtFtn) ) ) + , m_nStart( *rTxtFtn.GetStart() ) + , m_bEndNote( rTxtFtn.GetFtn().IsEndNote() ) +{ + ASSERT( rTxtFtn.GetStartNode(), + "SwHistorySetFootnote: Footnote without Section" ); +} + +String SwHistorySetFootnote::GetDescription() const +{ + return SW_RES(STR_FOOTNOTE); +} + +SwHistorySetFootnote::~SwHistorySetFootnote() +{ +} + + +void SwHistorySetFootnote::SetInDoc( SwDoc* pDoc, bool ) +{ + SwTxtNode * pTxtNd = pDoc->GetNodes()[ m_nNodeIndex ]->GetTxtNode(); + ASSERT( pTxtNd, "SwHistorySetFootnote: no TextNode" ); + if ( !pTxtNd ) + return; + + if ( m_pUndo.get() ) + { + // set the footnote in the TextNode + SwFmtFtn aTemp( m_bEndNote ); + SwFmtFtn& rNew = const_cast<SwFmtFtn&>( + static_cast<const SwFmtFtn&>(pDoc->GetAttrPool().Put(aTemp)) ); + if ( m_FootnoteNumber.Len() ) + { + rNew.SetNumStr( m_FootnoteNumber ); + } + SwTxtFtn* pTxtFtn = new SwTxtFtn( rNew, m_nStart ); + + // create the section of the Footnote + SwNodeIndex aIdx( *pTxtNd ); + m_pUndo->RestoreSection( pDoc, &aIdx, SwFootnoteStartNode ); + pTxtFtn->SetStartNode( &aIdx ); + if ( m_pUndo->GetHistory() ) + { + // create frames only now + m_pUndo->GetHistory()->Rollback( pDoc ); + } + + pTxtNd->InsertHint( pTxtFtn ); + } + else + { + SwTxtFtn * const pFtn = + const_cast<SwTxtFtn*>( static_cast<const SwTxtFtn*>( + pTxtNd->GetTxtAttrForCharAt( m_nStart ))); + SwFmtFtn &rFtn = const_cast<SwFmtFtn&>(pFtn->GetFtn()); + rFtn.SetNumStr( m_FootnoteNumber ); + if ( rFtn.IsEndNote() != m_bEndNote ) + { + rFtn.SetEndNote( m_bEndNote ); + pFtn->CheckCondColl(); + } + } +} + + +SwHistoryChangeFmtColl::SwHistoryChangeFmtColl( SwFmtColl* pFmtColl, ULONG nNd, + BYTE nNodeWhich ) + : SwHistoryHint( HSTRY_CHGFMTCOLL ) + , m_pColl( pFmtColl ) + , m_nNodeIndex( nNd ) + , m_nNodeType( nNodeWhich ) +{ +} + +void SwHistoryChangeFmtColl::SetInDoc( SwDoc* pDoc, bool ) +{ + SwCntntNode * pCntntNd = pDoc->GetNodes()[ m_nNodeIndex ]->GetCntntNode(); + ASSERT( pCntntNd, "SwHistoryChangeFmtColl: no ContentNode" ); + + // before setting the format, check if it is still available in the + // document. if it has been deleted, there is no undo! + if ( pCntntNd && m_nNodeType == pCntntNd->GetNodeType() ) + { + if ( ND_TEXTNODE == m_nNodeType ) + { + if ( USHRT_MAX != pDoc->GetTxtFmtColls()->GetPos( + static_cast<SwTxtFmtColl * const>(m_pColl) )) + { + pCntntNd->ChgFmtColl( m_pColl ); + } + } + else if ( USHRT_MAX != pDoc->GetGrfFmtColls()->GetPos( + static_cast<SwGrfFmtColl * const>(m_pColl) )) + { + pCntntNd->ChgFmtColl( m_pColl ); + } + } +} + + +SwHistoryTxtFlyCnt::SwHistoryTxtFlyCnt( SwFrmFmt* const pFlyFmt ) + : SwHistoryHint( HSTRY_FLYCNT ) + , m_pUndo( new SwUndoDelLayFmt( pFlyFmt ) ) +{ + ASSERT( pFlyFmt, "SwHistoryTxtFlyCnt: no Format" ); + m_pUndo->ChgShowSel( FALSE ); +} + + +SwHistoryTxtFlyCnt::~SwHistoryTxtFlyCnt() +{ +} + + +void SwHistoryTxtFlyCnt::SetInDoc( SwDoc* pDoc, bool ) +{ + SwPaM aPam( pDoc->GetNodes().GetEndOfPostIts() ); + SwUndoIter aUndoIter( &aPam ); + m_pUndo->Undo( aUndoIter ); +} + + + +SwHistoryBookmark::SwHistoryBookmark( + const ::sw::mark::IMark& rBkmk, + bool bSavePos, + bool bSaveOtherPos) + : SwHistoryHint(HSTRY_BOOKMARK) + , m_aName(rBkmk.GetName()) + , m_aShortName() + , m_aKeycode() + , m_nNode(bSavePos ? + rBkmk.GetMarkPos().nNode.GetIndex() : 0) + , m_nOtherNode(bSaveOtherPos ? + rBkmk.GetOtherMarkPos().nNode.GetIndex() : 0) + , m_nCntnt(bSavePos ? + rBkmk.GetMarkPos().nContent.GetIndex() : 0) + , m_nOtherCntnt(bSaveOtherPos ? + rBkmk.GetOtherMarkPos().nContent.GetIndex() :0) + , m_bSavePos(bSavePos) + , m_bSaveOtherPos(bSaveOtherPos) + , m_bHadOtherPos(rBkmk.IsExpanded()) + , m_eBkmkType(IDocumentMarkAccess::GetType(rBkmk)) +{ + const ::sw::mark::IBookmark* const pBookmark = dynamic_cast< const ::sw::mark::IBookmark* >(&rBkmk); + if(pBookmark) + { + m_aKeycode = pBookmark->GetKeyCode(); + m_aShortName = pBookmark->GetShortName(); + + ::sfx2::Metadatable const*const pMetadatable( + dynamic_cast< ::sfx2::Metadatable const* >(pBookmark)); + if (pMetadatable) + { + m_pMetadataUndo = pMetadatable->CreateUndo(); + } + } +} + + +void SwHistoryBookmark::SetInDoc( SwDoc* pDoc, bool ) +{ + bool bDoesUndo = pDoc->DoesUndo(); + pDoc->DoUndo(false); + + SwNodes& rNds = pDoc->GetNodes(); + IDocumentMarkAccess* pMarkAccess = pDoc->getIDocumentMarkAccess(); + ::std::auto_ptr<SwPaM> pPam; + ::sw::mark::IMark* pMark = NULL; + + if(m_bSavePos) + { + SwCntntNode* const pCntntNd = rNds[m_nNode]->GetCntntNode(); + OSL_ENSURE(pCntntNd, + "<SwHistoryBookmark::SetInDoc(..)>" + " - wrong node for a mark"); + + // #111660# don't crash when nNode1 doesn't point to content node. + if(pCntntNd) + pPam = ::std::auto_ptr<SwPaM>(new SwPaM(*pCntntNd, m_nCntnt)); + } + else + { + pMark = pMarkAccess->findMark(m_aName)->get(); + pPam = ::std::auto_ptr<SwPaM>(new SwPaM(pMark->GetMarkPos())); + } + + if(m_bSaveOtherPos) + { + SwCntntNode* const pCntntNd = rNds[m_nOtherNode]->GetCntntNode(); + OSL_ENSURE(pCntntNd, + "<SwHistoryBookmark::SetInDoc(..)>" + " - wrong node for a mark"); + + if(pPam.get() != NULL && pCntntNd) + { + pPam->SetMark(); + pPam->GetMark()->nNode = m_nOtherNode; + pPam->GetMark()->nContent.Assign(pCntntNd, m_nOtherCntnt); + } + } + else if(m_bHadOtherPos) + { + if(!pMark) + pMark = pMarkAccess->findMark(m_aName)->get(); + OSL_ENSURE(pMark->IsExpanded(), + "<SwHistoryBookmark::SetInDoc(..)>" + " - missing pos on old mark"); + pPam->SetMark(); + *pPam->GetMark() = pMark->GetOtherMarkPos(); + } + + if(pPam.get()) + { + if(pMark) + pMarkAccess->deleteMark(pMark); + ::sw::mark::IBookmark* const pBookmark = dynamic_cast< ::sw::mark::IBookmark* >( + pMarkAccess->makeMark(*pPam, m_aName, m_eBkmkType)); + if(pBookmark) + { + pBookmark->SetKeyCode(m_aKeycode); + pBookmark->SetShortName(m_aShortName); + if (m_pMetadataUndo) + { + ::sfx2::Metadatable * const pMeta( + dynamic_cast< ::sfx2::Metadatable* >(pBookmark)); + OSL_ENSURE(pMeta, "metadata undo, but not metadatable?"); + if (pMeta) + { + pMeta->RestoreMetadata(m_pMetadataUndo); + } + } + } + } + pDoc->DoUndo(bDoesUndo); +} + + +bool SwHistoryBookmark::IsEqualBookmark(const ::sw::mark::IMark& rBkmk) +{ + return m_nNode == rBkmk.GetMarkPos().nNode.GetIndex() + && m_nCntnt == rBkmk.GetMarkPos().nContent.GetIndex() + && m_aName == rBkmk.GetName(); +} + +const ::rtl::OUString& SwHistoryBookmark::GetName() const +{ + return m_aName; +} + +/*************************************************************************/ + + +SwHistorySetAttrSet::SwHistorySetAttrSet( const SfxItemSet& rSet, + ULONG nNodePos, const SvUShortsSort& rSetArr ) + : SwHistoryHint( HSTRY_SETATTRSET ) + , m_OldSet( rSet ) + , m_ResetArray( 0, 4 ) + , m_nNodeIndex( nNodePos ) +{ + SfxItemIter aIter( m_OldSet ), aOrigIter( rSet ); + const SfxPoolItem* pItem = aIter.FirstItem(), + * pOrigItem = aOrigIter.FirstItem(); + do { + if( !rSetArr.Seek_Entry( pOrigItem->Which() )) + { + m_ResetArray.Insert( pOrigItem->Which(), m_ResetArray.Count() ); + m_OldSet.ClearItem( pOrigItem->Which() ); + } + else + { + switch ( pItem->Which() ) + { + case RES_PAGEDESC: + static_cast<SwFmtPageDesc*>( + const_cast<SfxPoolItem*>(pItem))->ChgDefinedIn( 0 ); + break; + + case RES_PARATR_DROP: + static_cast<SwFmtDrop*>( + const_cast<SfxPoolItem*>(pItem))->ChgDefinedIn( 0 ); + break; + + case RES_BOXATR_FORMULA: + { + //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 + m_OldSet.ClearItem( RES_BOXATR_VALUE ); + + SwTblBoxFormula& rNew = + *static_cast<SwTblBoxFormula*>( + const_cast<SfxPoolItem*>(pItem)); + if ( rNew.IsIntrnlName() ) + { + const SwTblBoxFormula& rOld = + static_cast<const SwTblBoxFormula&>( + rSet.Get( RES_BOXATR_FORMULA )); + const SwNode* pNd = rOld.GetNodeOfFormula(); + if ( pNd ) + { + const SwTableNode* pTableNode + = pNd->FindTableNode(); + if (pTableNode) + { + SwTableFmlUpdate aMsgHnt( + &pTableNode->GetTable() ); + aMsgHnt.eFlags = TBL_BOXNAME; + rNew.ChgDefinedIn( rOld.GetDefinedIn() ); + rNew.ChangeState( &aMsgHnt ); + } + } + } + rNew.ChgDefinedIn( 0 ); + } + break; + } + } + + if( aIter.IsAtEnd() ) + break; + pItem = aIter.NextItem(); + pOrigItem = aOrigIter.NextItem(); + } while( TRUE ); +} + +void SwHistorySetAttrSet::SetInDoc( SwDoc* pDoc, bool ) +{ + BOOL bDoesUndo = pDoc->DoesUndo(); + pDoc->DoUndo( FALSE ); + + SwNode * pNode = pDoc->GetNodes()[ m_nNodeIndex ]; + if ( pNode->IsCntntNode() ) + { + static_cast<SwCntntNode*>(pNode)->SetAttr( m_OldSet ); + if ( m_ResetArray.Count() ) + { + static_cast<SwCntntNode*>(pNode)->ResetAttr( m_ResetArray ); + } + } + else if ( pNode->IsTableNode() ) + { + SwFmt& rFmt = + *static_cast<SwTableNode*>(pNode)->GetTable().GetFrmFmt(); + rFmt.SetFmtAttr( m_OldSet ); + if ( m_ResetArray.Count() ) + { + rFmt.ResetFmtAttr( *m_ResetArray.GetData() ); + } + } + + pDoc->DoUndo( bDoesUndo ); +} + +/*************************************************************************/ + + +SwHistoryResetAttrSet::SwHistoryResetAttrSet( const SfxItemSet& rSet, + ULONG nNodePos, xub_StrLen nAttrStt, xub_StrLen nAttrEnd ) + : SwHistoryHint( HSTRY_RESETATTRSET ) + , m_nNodeIndex( nNodePos ), m_nStart( nAttrStt ), m_nEnd( nAttrEnd ) + , m_Array( (BYTE)rSet.Count() ) +{ + SfxItemIter aIter( rSet ); + bool bAutoStyle = false; + + while( TRUE ) + { + const USHORT nWhich = aIter.GetCurItem()->Which(); + +#ifndef PRODUCT + switch (nWhich) + { + case RES_TXTATR_REFMARK: + case RES_TXTATR_TOXMARK: + if (m_nStart != m_nEnd) break; // else: fall through! + case RES_TXTATR_FIELD: + case RES_TXTATR_FLYCNT: + case RES_TXTATR_FTN: + case RES_TXTATR_META: + case RES_TXTATR_METAFIELD: + ASSERT(rSet.Count() == 1, + "text attribute with CH_TXTATR, but not the only one:" + "\nnot such a good idea"); + break; + } +#endif + + // Character attribute cannot be inserted into the hints array + // anymore. Therefore we have to treat them as one RES_TXTATR_AUTOFMT: + if (isCHRATR(nWhich)) + { + bAutoStyle = true; + } + else + { + m_Array.Insert( aIter.GetCurItem()->Which(), m_Array.Count() ); + } + + if( aIter.IsAtEnd() ) + break; + + aIter.NextItem(); + } + + if ( bAutoStyle ) + { + m_Array.Insert( RES_TXTATR_AUTOFMT, m_Array.Count() ); + } +} + + +void SwHistoryResetAttrSet::SetInDoc( SwDoc* pDoc, bool ) +{ + BOOL bDoesUndo = pDoc->DoesUndo(); + pDoc->DoUndo( FALSE ); + + SwCntntNode * pCntntNd = pDoc->GetNodes()[ m_nNodeIndex ]->GetCntntNode(); + ASSERT( pCntntNd, "SwHistoryResetAttrSet: no CntntNode" ); + + if (pCntntNd) + { + const USHORT* pArr = m_Array.GetData(); + if ( USHRT_MAX == m_nEnd && USHRT_MAX == m_nStart ) + { + // no area: use ContentNode + for ( USHORT n = m_Array.Count(); n; --n, ++pArr ) + { + pCntntNd->ResetAttr( *pArr ); + } + } + else + { + // area: use TextNode + for ( USHORT n = m_Array.Count(); n; --n, ++pArr ) + { + static_cast<SwTxtNode*>(pCntntNd)-> + DeleteAttributes( *pArr, m_nStart, m_nEnd ); + } + } + } + + pDoc->DoUndo( bDoesUndo ); +} + + +/*************************************************************************/ + + +SwHistoryChangeFlyAnchor::SwHistoryChangeFlyAnchor( SwFrmFmt& rFmt ) + : SwHistoryHint( HSTRY_CHGFLYANCHOR ) + , m_rFmt( rFmt ) + , m_nOldNodeIndex( rFmt.GetAnchor().GetCntntAnchor()->nNode.GetIndex() ) + , m_nOldContentIndex( (FLY_AT_CHAR == rFmt.GetAnchor().GetAnchorId()) + ? rFmt.GetAnchor().GetCntntAnchor()->nContent.GetIndex() + : STRING_MAXLEN ) +{ +} + + +void SwHistoryChangeFlyAnchor::SetInDoc( SwDoc* pDoc, bool ) +{ + BOOL bDoesUndo = pDoc->DoesUndo(); + pDoc->DoUndo( FALSE ); + + USHORT nPos = pDoc->GetSpzFrmFmts()->GetPos( &m_rFmt ); + if ( USHRT_MAX != nPos ) // Format does still exist + { + SwFmtAnchor aTmp( m_rFmt.GetAnchor() ); + + SwNode* pNd = pDoc->GetNodes()[ m_nOldNodeIndex ]; + SwCntntNode* pCNd = pNd->GetCntntNode(); + SwPosition aPos( *pNd ); + if ( STRING_MAXLEN != m_nOldContentIndex ) + { + ASSERT(pCNd, "SwHistoryChangeFlyAnchor: no ContentNode"); + if (pCNd) + { + aPos.nContent.Assign( pCNd, m_nOldContentIndex ); + } + } + aTmp.SetAnchor( &aPos ); + + // so the Layout does not get confused + if ( !pCNd || !pCNd->GetFrm( 0, 0, FALSE ) ) + { + m_rFmt.DelFrms(); + } + + m_rFmt.SetFmtAttr( aTmp ); + } + pDoc->DoUndo( bDoesUndo ); +} + + +/*************************************************************************/ + +SwHistoryChangeFlyChain::SwHistoryChangeFlyChain( SwFlyFrmFmt& rFmt, + const SwFmtChain& rAttr ) + : SwHistoryHint( HSTRY_CHGFLYCHAIN ) + , m_pPrevFmt( rAttr.GetPrev() ) + , m_pNextFmt( rAttr.GetNext() ) + , m_pFlyFmt( &rFmt ) +{ +} + + +void SwHistoryChangeFlyChain::SetInDoc( SwDoc* pDoc, bool ) +{ + if ( USHRT_MAX != pDoc->GetSpzFrmFmts()->GetPos( m_pFlyFmt ) ) + { + SwFmtChain aChain; + + if ( m_pPrevFmt && + USHRT_MAX != pDoc->GetSpzFrmFmts()->GetPos( m_pPrevFmt ) ) + { + aChain.SetPrev( m_pPrevFmt ); + SwFmtChain aTmp( m_pPrevFmt->GetChain() ); + aTmp.SetNext( m_pFlyFmt ); + m_pPrevFmt->SetFmtAttr( aTmp ); + } + + if ( m_pNextFmt && + USHRT_MAX != pDoc->GetSpzFrmFmts()->GetPos( m_pNextFmt ) ) + { + aChain.SetNext( m_pNextFmt ); + SwFmtChain aTmp( m_pNextFmt->GetChain() ); + aTmp.SetPrev( m_pFlyFmt ); + m_pNextFmt->SetFmtAttr( aTmp ); + } + + if ( aChain.GetNext() || aChain.GetPrev() ) + { + m_pFlyFmt->SetFmtAttr( aChain ); + } + } +} + + +// -> #i27615# +SwHistoryChangeCharFmt::SwHistoryChangeCharFmt(const SfxItemSet & rSet, + const String & sFmt) + : SwHistoryHint(HSTRY_CHGCHARFMT) + , m_OldSet(rSet), m_Fmt(sFmt) +{ +} + +void SwHistoryChangeCharFmt::SetInDoc(SwDoc * pDoc, bool ) +{ + SwCharFmt * pCharFmt = pDoc->FindCharFmtByName(m_Fmt); + + if (pCharFmt) + { + pCharFmt->SetFmtAttr(m_OldSet); + } +} +// <- #i27615# + +/* */ + + +SwHistory::SwHistory( USHORT nInitSz, USHORT nGrowSz ) + : m_SwpHstry( (BYTE)nInitSz, (BYTE)nGrowSz ) + , m_nEndDiff( 0 ) +{} + + +SwHistory::~SwHistory() +{ + Delete( 0 ); +} + + +/************************************************************************* +|* +|* void SwHistory::Add() +|* +|* Beschreibung Dokument 1.0 +|* Ersterstellung JP 18.02.91 +|* Letzte Aenderung JP 18.02.91 +|* +*************************************************************************/ + +// --> OD 2008-02-27 #refactorlists# - removed <rDoc> +void SwHistory::Add( const SfxPoolItem* pOldValue, const SfxPoolItem* pNewValue, + ULONG nNodeIdx ) +// <-- +{ + ASSERT( !m_nEndDiff, "History was not deleted after REDO" ); + + USHORT nWhich = pNewValue->Which(); + if( (nWhich >= POOLATTR_END) || (nWhich == RES_TXTATR_FIELD) ) + return; + + // no default Attribute? + SwHistoryHint * pHt; + if ( pOldValue && pOldValue != GetDfltAttr( pOldValue->Which() ) ) + { + pHt = new SwHistorySetFmt( pOldValue, nNodeIdx ); + } + else + { + pHt = new SwHistoryResetFmt( pNewValue, nNodeIdx ); + } + m_SwpHstry.Insert( pHt, Count() ); +} + + +void SwHistory::Add( SwTxtAttr* pHint, ULONG nNodeIdx, bool bNewAttr ) +{ + ASSERT( !m_nEndDiff, "History was not deleted after REDO" ); + + SwHistoryHint * pHt; + USHORT nAttrWhich = pHint->Which(); + + if( !bNewAttr ) + { + switch ( nAttrWhich ) + { + case RES_TXTATR_FTN: + pHt = new SwHistorySetFootnote( + static_cast<SwTxtFtn*>(pHint), nNodeIdx ); + break; + case RES_TXTATR_FLYCNT: + pHt = new SwHistoryTxtFlyCnt( static_cast<SwTxtFlyCnt*>(pHint) + ->GetFlyCnt().GetFrmFmt() ); + break; + case RES_TXTATR_FIELD: + pHt = new SwHistorySetTxtFld( + static_cast<SwTxtFld*>(pHint), nNodeIdx ); + break; + case RES_TXTATR_TOXMARK: + pHt = new SwHistorySetTOXMark( + static_cast<SwTxtTOXMark*>(pHint), nNodeIdx ); + break; + case RES_TXTATR_REFMARK: + pHt = new SwHistorySetRefMark( + static_cast<SwTxtRefMark*>(pHint), nNodeIdx ); + break; + default: + pHt = new SwHistorySetTxt( + static_cast<SwTxtAttr*>(pHint), nNodeIdx ); + } + } + else + { + pHt = new SwHistoryResetTxt( pHint->Which(), *pHint->GetStart(), + *pHint->GetAnyEnd(), nNodeIdx ); + } + m_SwpHstry.Insert( pHt, Count() ); +} + + +void SwHistory::Add( SwFmtColl* pColl, ULONG nNodeIdx, BYTE nWhichNd ) +{ + ASSERT( !m_nEndDiff, "History was not deleted after REDO" ); + + SwHistoryHint * pHt = + new SwHistoryChangeFmtColl( pColl, nNodeIdx, nWhichNd ); + m_SwpHstry.Insert( pHt, Count() ); +} + + +void SwHistory::Add(const ::sw::mark::IMark& rBkmk, bool bSavePos, bool bSaveOtherPos) +{ + ASSERT( !m_nEndDiff, "History was not deleted after REDO" ); + + SwHistoryHint * pHt = new SwHistoryBookmark(rBkmk, bSavePos, bSaveOtherPos); + m_SwpHstry.Insert( pHt, Count() ); +} + + +void SwHistory::Add( SwFrmFmt& rFmt ) +{ + SwHistoryHint * pHt = new SwHistoryChangeFlyAnchor( rFmt ); + m_SwpHstry.Insert( pHt, Count() ); +} + +void SwHistory::Add( SwFlyFrmFmt& rFmt, USHORT& rSetPos ) +{ + ASSERT( !m_nEndDiff, "History was not deleted after REDO" ); + + SwHistoryHint * pHint; + const USHORT nWh = rFmt.Which(); + if( RES_FLYFRMFMT == nWh || RES_DRAWFRMFMT == nWh ) + { + pHint = new SwHistoryTxtFlyCnt( &rFmt ); + m_SwpHstry.Insert( pHint, Count() ); + + const SwFmtChain* pChainItem; + if( SFX_ITEM_SET == rFmt.GetItemState( RES_CHAIN, FALSE, + (const SfxPoolItem**)&pChainItem )) + { + if( pChainItem->GetNext() || pChainItem->GetPrev() ) + { + SwHistoryHint * pHt = + new SwHistoryChangeFlyChain( rFmt, *pChainItem ); + m_SwpHstry.Insert( pHt, rSetPos++ ); + if ( pChainItem->GetNext() ) + { + SwFmtChain aTmp( pChainItem->GetNext()->GetChain() ); + aTmp.SetPrev( 0 ); + pChainItem->GetNext()->SetFmtAttr( aTmp ); + } + if ( pChainItem->GetPrev() ) + { + SwFmtChain aTmp( pChainItem->GetPrev()->GetChain() ); + aTmp.SetNext( 0 ); + pChainItem->GetPrev()->SetFmtAttr( aTmp ); + } + } + rFmt.ResetFmtAttr( RES_CHAIN ); + } + } +} + +void SwHistory::Add( const SwTxtFtn& rFtn ) +{ + SwHistoryHint *pHt = new SwHistorySetFootnote( rFtn ); + m_SwpHstry.Insert( pHt, Count() ); +} + +// #i27615# +void SwHistory::Add(const SfxItemSet & rSet, const SwCharFmt & rFmt) +{ + SwHistoryHint * pHt = new SwHistoryChangeCharFmt(rSet, rFmt.GetName()); + m_SwpHstry.Insert(pHt, Count()); +} + +/************************************************************************* +|* +|* BOOL SwHistory::Rollback() +|* +|* Beschreibung Dokument 1.0 +|* Ersterstellung JP 18.02.91 +|* Letzte Aenderung JP 18.02.91 +|* +*************************************************************************/ + + +bool SwHistory::Rollback( SwDoc* pDoc, USHORT nStart ) +{ + if ( !Count() ) + return false; + + SwHistoryHint * pHHt; + USHORT i; + for ( i = Count(); i > nStart ; ) + { + pHHt = m_SwpHstry[ --i ]; + pHHt->SetInDoc( pDoc, false ); + delete pHHt; + } + m_SwpHstry.Remove( nStart, Count() - nStart ); + m_nEndDiff = 0; + return true; +} + + + +bool SwHistory::TmpRollback( SwDoc* pDoc, USHORT nStart, bool bToFirst ) +{ + USHORT nEnd = Count() - m_nEndDiff; + if ( !Count() || !nEnd || nStart >= nEnd ) + return false; + + SwHistoryHint * pHHt; + if ( bToFirst ) + { + for ( ; nEnd > nStart; ++m_nEndDiff ) + { + pHHt = m_SwpHstry[ --nEnd ]; + pHHt->SetInDoc( pDoc, true ); + } + } + else + { + for ( ; nStart < nEnd; ++m_nEndDiff, ++nStart ) + { + pHHt = m_SwpHstry[ nStart ]; + pHHt->SetInDoc( pDoc, true ); + } + } + return true; +} + + +void SwHistory::Delete( USHORT nStart ) +{ + for ( USHORT n = Count(); n > nStart; ) + { + m_SwpHstry.DeleteAndDestroy( --n, 1 ); + } + m_nEndDiff = 0; +} + + +USHORT SwHistory::SetTmpEnd( USHORT nNewTmpEnd ) +{ + ASSERT( nNewTmpEnd <= Count(), "SwHistory::SetTmpEnd: out of bounds" ); + + USHORT nOld = Count() - m_nEndDiff; + m_nEndDiff = Count() - nNewTmpEnd; + + // for every SwHistoryFlyCnt, call the Redo of its UndoObject. + // this saves the formats of the flys! + for ( USHORT n = nOld; n < nNewTmpEnd; n++ ) + { + if ( HSTRY_FLYCNT == (*this)[ n ]->Which() ) + { + static_cast<SwHistoryTxtFlyCnt*>((*this)[ n ]) + ->GetUDelLFmt()->Redo(); + } + } + + return nOld; +} + +void SwHistory::CopyFmtAttr( const SfxItemSet& rSet, ULONG nNodeIdx ) +{ + if( rSet.Count() ) + { + SfxItemIter aIter( rSet ); + do { + if( (SfxPoolItem*)-1 != aIter.GetCurItem() ) + { + const SfxPoolItem* pNew = aIter.GetCurItem(); + Add( pNew, pNew, nNodeIdx ); + } + if( aIter.IsAtEnd() ) + break; + aIter.NextItem(); + } while( TRUE ); + } +} + +void SwHistory::CopyAttr( SwpHints* pHts, ULONG nNodeIdx, + xub_StrLen nStart, xub_StrLen nEnd, bool bFields ) +{ + if( !pHts ) + return; + + // copy all attributes of the TextNode in the area from nStart to nEnd + SwTxtAttr* pHt; + xub_StrLen nAttrStt; + const xub_StrLen * pEndIdx; + for( USHORT n = 0; n < pHts->Count(); n++ ) + { + // BP: nAttrStt muss auch bei !pEndIdx gesetzt werden + pHt = pHts->GetTextHint(n); + nAttrStt = *pHt->GetStart(); +// JP: ???? wieso nAttrStt >= nEnd +// if( 0 != ( pEndIdx = pHt->GetEnd() ) && nAttrStt >= nEnd ) + if( 0 != ( pEndIdx = pHt->GetEnd() ) && nAttrStt > nEnd ) + break; + + // Flys und Ftn nie kopieren !! + BOOL bNextAttr = FALSE; + switch( pHt->Which() ) + { + case RES_TXTATR_FIELD: + // keine Felder, .. kopieren ?? + if( !bFields ) + bNextAttr = TRUE; + break; + case RES_TXTATR_FLYCNT: + case RES_TXTATR_FTN: + bNextAttr = TRUE; + break; + } + + if( bNextAttr ) + continue; + + // save all attributes that are somehow in this area + if ( nStart <= nAttrStt ) + { + if ( nEnd > nAttrStt +// JP: ???? wieso nAttrStt >= nEnd +// || (nEnd == nAttrStt && (!pEndIdx || nEnd == pEndIdx->GetIndex())) + ) + { + Add( pHt, nNodeIdx, false ); + } + } + else if ( pEndIdx && nStart < *pEndIdx ) + { + Add( pHt, nNodeIdx, false ); + } + } +} + + +/*************************************************************************/ + +// Klasse zum Registrieren der History am Node, Format, HintsArray, ... + +SwRegHistory::SwRegHistory( SwHistory* pHst ) + : SwClient( 0 ) + , m_pHistory( pHst ) + , m_nNodeIndex( ULONG_MAX ) +{ + _MakeSetWhichIds(); +} + +SwRegHistory::SwRegHistory( SwModify* pRegIn, const SwNode& rNd, + SwHistory* pHst ) + : SwClient( pRegIn ) + , m_pHistory( pHst ) + , m_nNodeIndex( rNd.GetIndex() ) +{ + _MakeSetWhichIds(); +} + +SwRegHistory::SwRegHistory( const SwNode& rNd, SwHistory* pHst ) + : SwClient( 0 ) + , m_pHistory( pHst ) + , m_nNodeIndex( rNd.GetIndex() ) +{ + _MakeSetWhichIds(); +} + +void SwRegHistory::Modify( SfxPoolItem* pOld, SfxPoolItem* pNew ) +{ + if ( m_pHistory && ( pOld || pNew ) ) + { + if ( pNew->Which() < POOLATTR_END ) + { + m_pHistory->Add( pOld, pNew, m_nNodeIndex ); + } + else if ( RES_ATTRSET_CHG == pNew->Which() ) + { + SwHistoryHint* pNewHstr; + const SfxItemSet& rSet = + *static_cast<SwAttrSetChg*>(pOld)->GetChgSet(); + if ( 1 < rSet.Count() ) + { + pNewHstr = + new SwHistorySetAttrSet( rSet, m_nNodeIndex, m_WhichIdSet ); + } + else + { + const SfxPoolItem* pItem = SfxItemIter( rSet ).FirstItem(); + if ( m_WhichIdSet.Seek_Entry( pItem->Which() ) ) + { + pNewHstr = new SwHistorySetFmt( pItem, m_nNodeIndex ); + } + else + { + pNewHstr = new SwHistoryResetFmt( pItem, m_nNodeIndex ); + } + } + m_pHistory->m_SwpHstry.Insert( pNewHstr, m_pHistory->Count() ); + } + } +} + + + +void SwRegHistory::AddHint( SwTxtAttr* pHt, const bool bNew ) +{ + m_pHistory->Add( pHt, m_nNodeIndex, bNew ); +} + + +bool SwRegHistory::InsertItems( const SfxItemSet& rSet, + xub_StrLen const nStart, xub_StrLen const nEnd, SetAttrMode const nFlags ) +{ + if( !rSet.Count() ) + return false; + + SwTxtNode * const pTxtNode = + dynamic_cast<SwTxtNode *>(const_cast<SwModify *>(GetRegisteredIn())); + + ASSERT(pTxtNode, "SwRegHistory not registered at text node?"); + if (!pTxtNode) + return false; + + if ( pTxtNode->GetpSwpHints() && m_pHistory ) + { + pTxtNode->GetpSwpHints()->Register( this ); + } + + const bool bInserted = pTxtNode->SetAttr( rSet, nStart, nEnd, nFlags ); + + // Achtung: Durch das Einfuegen eines Attributs kann das Array + // geloescht werden!!! Wenn das einzufuegende zunaechst ein vorhandenes + // loescht, selbst aber nicht eingefuegt werden braucht, weil die + // Absatzattribute identisch sind( -> bForgetAttr in SwpHints::Insert ) + if ( pTxtNode->GetpSwpHints() && m_pHistory ) + { + pTxtNode->GetpSwpHints()->DeRegister(); + } + + if ( m_pHistory && bInserted ) + { + SwHistoryHint* pNewHstr = new SwHistoryResetAttrSet( rSet, + pTxtNode->GetIndex(), nStart, nEnd ); + // der NodeIndex kann verschoben sein !! + + m_pHistory->m_SwpHstry.Insert( pNewHstr, m_pHistory->Count() ); + } + + return bInserted; +} + +void SwRegHistory::RegisterInModify( SwModify* pRegIn, const SwNode& rNd ) +{ + if ( m_pHistory && pRegIn ) + { + pRegIn->Add( this ); + m_nNodeIndex = rNd.GetIndex(); + _MakeSetWhichIds(); + } + else if ( m_WhichIdSet.Count() ) + { + m_WhichIdSet.Remove( 0, m_WhichIdSet.Count() ); + } +} + +void SwRegHistory::_MakeSetWhichIds() +{ + if (!m_pHistory) return; + + if ( m_WhichIdSet.Count() ) + { + m_WhichIdSet.Remove( 0, m_WhichIdSet.Count() ); + } + + if( GetRegisteredIn() ) + { + const SfxItemSet* pSet = 0; + if( GetRegisteredIn()->ISA( SwCntntNode ) ) + { + pSet = static_cast<SwCntntNode*>( + const_cast<SwModify*>(GetRegisteredIn()))->GetpSwAttrSet(); + } + else if ( GetRegisteredIn()->ISA( SwFmt ) ) + { + pSet = &static_cast<SwFmt*>( + const_cast<SwModify*>(GetRegisteredIn()))->GetAttrSet(); + } + if( pSet && pSet->Count() ) + { + SfxItemIter aIter( *pSet ); + USHORT nW = aIter.FirstItem()->Which(); + while( TRUE ) + { + m_WhichIdSet.Insert( nW ); + if( aIter.IsAtEnd() ) + break; + nW = aIter.NextItem()->Which(); + } + } + } +} + diff --git a/sw/source/core/undo/unattr.cxx b/sw/source/core/undo/unattr.cxx new file mode 100644 index 000000000000..e3b54c59b142 --- /dev/null +++ b/sw/source/core/undo/unattr.cxx @@ -0,0 +1,1318 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#define _SVSTDARR_USHORTS +#define _SVSTDARR_USHORTSSORT +#include <hintids.hxx> +#include <svx/svdmodel.hxx> +#include <editeng/tstpitem.hxx> +#include <svx/svdpage.hxx> +#include <svl/itemiter.hxx> + + +#include <fmtflcnt.hxx> +#include <txtftn.hxx> +#include <fmtornt.hxx> +#include <fmtanchr.hxx> +#include <fmtfsize.hxx> +#include <frmfmt.hxx> +#include <fmtcntnt.hxx> +#include <ftnidx.hxx> +#include <doc.hxx> +#include <docary.hxx> +#include <swundo.hxx> // fuer die UndoIds +#include <pam.hxx> +#include <ndtxt.hxx> +#include <swtable.hxx> +#include <swtblfmt.hxx> +#include <undobj.hxx> +#include <rolbck.hxx> +#include <ndnotxt.hxx> +#include <dcontact.hxx> +#include <ftninfo.hxx> +#include <redline.hxx> +#include <section.hxx> +#include <charfmt.hxx> + + + +inline SwDoc& SwUndoIter::GetDoc() const +{ return *pAktPam->GetDoc(); } + +// ----------------------------------------------------- + +SwUndoFmtAttrHelper::SwUndoFmtAttrHelper( SwFmt& rFmt, bool bSvDrwPt ) + : SwClient( &rFmt ) + , m_pUndo( 0 ) + , m_bSaveDrawPt( bSvDrwPt ) +{ +} + +void SwUndoFmtAttrHelper::Modify( SfxPoolItem* pOld, SfxPoolItem* pNew ) +{ + if( pOld && pNew ) + { + if( POOLATTR_END >= pOld->Which() ) + { + if ( GetUndo() ) + { + m_pUndo->PutAttr( *pOld ); + } + else + { + m_pUndo.reset( new SwUndoFmtAttr( *pOld, + *static_cast<SwFmt*>(pRegisteredIn), m_bSaveDrawPt ) ); + } + } + else if ( RES_ATTRSET_CHG == pOld->Which() ) + { + if ( GetUndo() ) + { + SfxItemIter aIter( + *(static_cast<SwAttrSetChg*>(pOld))->GetChgSet() ); + const SfxPoolItem* pItem = aIter.GetCurItem(); + while ( pItem ) + { + m_pUndo->PutAttr( *pItem ); + if( aIter.IsAtEnd() ) + break; + pItem = aIter.NextItem(); + } + } + else + { + m_pUndo.reset( new SwUndoFmtAttr( + *static_cast<SwAttrSetChg*>(pOld)->GetChgSet(), + *static_cast<SwFmt*>(pRegisteredIn), m_bSaveDrawPt ) ); + } + } + else + SwClient::Modify( pOld, pNew ); + } + else + SwClient::Modify( pOld, pNew ); +} + +// ----------------------------------------------------- + +SwUndoFmtAttr::SwUndoFmtAttr( const SfxItemSet& rOldSet, + SwFmt& rChgFmt, + bool bSaveDrawPt ) + : SwUndo( UNDO_INSFMTATTR ) + , m_pFmt( &rChgFmt ) + // --> OD 2007-07-11 #i56253# + , m_pOldSet( new SfxItemSet( rOldSet ) ) + // <-- + , m_nNodeIndex( 0 ) + , m_nFmtWhich( rChgFmt.Which() ) + , m_bSaveDrawPt( bSaveDrawPt ) +{ + Init(); +} + +SwUndoFmtAttr::SwUndoFmtAttr( const SfxPoolItem& rItem, SwFmt& rChgFmt, + bool bSaveDrawPt ) + : SwUndo( UNDO_INSFMTATTR ) + , m_pFmt( &rChgFmt ) + , m_pOldSet( m_pFmt->GetAttrSet().Clone( FALSE ) ) + , m_nNodeIndex( 0 ) + , m_nFmtWhich( rChgFmt.Which() ) + , m_bSaveDrawPt( bSaveDrawPt ) +{ + m_pOldSet->Put( rItem ); + Init(); +} + +void SwUndoFmtAttr::Init() +{ + // treat change of anchor specially + if ( SFX_ITEM_SET == m_pOldSet->GetItemState( RES_ANCHOR, FALSE )) + { + SaveFlyAnchor( m_bSaveDrawPt ); + } + else if ( RES_FRMFMT == m_nFmtWhich ) + { + SwDoc* pDoc = m_pFmt->GetDoc(); + if (USHRT_MAX != pDoc->GetTblFrmFmts()->GetPos( + static_cast<const SwFrmFmtPtr>(m_pFmt))) + { + // Table Format: save table position, table formats are volatile! + SwTable * pTbl = static_cast<SwTable*>( + SwClientIter( *m_pFmt ).First( TYPE( SwTable )) ); + if ( pTbl ) + { + m_nNodeIndex = pTbl->GetTabSortBoxes()[ 0 ]->GetSttNd() + ->FindTableNode()->GetIndex(); + } + } + else if (USHRT_MAX != pDoc->GetSections().GetPos( + static_cast<const SwSectionFmtPtr>(m_pFmt))) + { + m_nNodeIndex = m_pFmt->GetCntnt().GetCntntIdx()->GetIndex(); + } + else if ( 0 != dynamic_cast< SwTableBoxFmt* >( m_pFmt ) ) + { + SwTableBox* pTblBox = static_cast< SwTableBox* >( + SwClientIter( *m_pFmt ).First( TYPE( SwTableBox ))); + if ( pTblBox ) + { + m_nNodeIndex = pTblBox->GetSttIdx(); + } + } + } +} + +SwUndoFmtAttr::~SwUndoFmtAttr() +{ +} + +void SwUndoFmtAttr::Undo( SwUndoIter& rUndoIter) +{ + // OD 2004-10-26 #i35443# + // Important note: <Undo(..)> also called by <ReDo(..)> + + if ( !m_pOldSet.get() || !m_pFmt || !IsFmtInDoc( &rUndoIter.GetDoc() )) + return; + + // --> OD 2004-10-26 #i35443# - If anchor attribute has been successfull + // restored, all other attributes are also restored. + // Thus, keep track of its restoration + bool bAnchorAttrRestored( false ); + if ( SFX_ITEM_SET == m_pOldSet->GetItemState( RES_ANCHOR, FALSE )) + { + bAnchorAttrRestored = RestoreFlyAnchor( rUndoIter ); + if ( bAnchorAttrRestored ) + { + // Anchor attribute successfull restored. + // Thus, keep anchor position for redo + SaveFlyAnchor(); + } + else + { + // Anchor attribute not restored due to invalid anchor position. + // Thus, delete anchor attribute. + m_pOldSet->ClearItem( RES_ANCHOR ); + } + } + + if ( !bAnchorAttrRestored ) + // <-- + { + SwUndoFmtAttrHelper aTmp( *m_pFmt, m_bSaveDrawPt ); + m_pFmt->SetFmtAttr( *m_pOldSet ); + if ( aTmp.GetUndo() ) + { + // transfer ownership of helper object's old set + m_pOldSet = aTmp.GetUndo()->m_pOldSet; + } + else + { + m_pOldSet->ClearItem(); + } + + if ( RES_FLYFRMFMT == m_nFmtWhich || RES_DRAWFRMFMT == m_nFmtWhich ) + { + rUndoIter.pSelFmt = static_cast<SwFrmFmt*>(m_pFmt); + } + } +} + +bool SwUndoFmtAttr::IsFmtInDoc( SwDoc* pDoc ) +{ + // search for the Format in the Document; if it does not exist any more, + // the attribute is not restored! + USHORT nPos = USHRT_MAX; + switch ( m_nFmtWhich ) + { + case RES_TXTFMTCOLL: + nPos = pDoc->GetTxtFmtColls()->GetPos( + static_cast<const SwTxtFmtCollPtr>(m_pFmt) ); + break; + + case RES_GRFFMTCOLL: + nPos = pDoc->GetGrfFmtColls()->GetPos( + static_cast<const SwGrfFmtCollPtr>(m_pFmt) ); + break; + + case RES_CHRFMT: + nPos = pDoc->GetCharFmts()->GetPos( + static_cast<SwCharFmtPtr>(m_pFmt) ); + break; + + case RES_FRMFMT: + if ( m_nNodeIndex && (m_nNodeIndex < pDoc->GetNodes().Count()) ) + { + SwNode* pNd = pDoc->GetNodes()[ m_nNodeIndex ]; + if ( pNd->IsTableNode() ) + { + m_pFmt = + static_cast<SwTableNode*>(pNd)->GetTable().GetFrmFmt(); + nPos = 0; + break; + } + else if ( pNd->IsSectionNode() ) + { + m_pFmt = + static_cast<SwSectionNode*>(pNd)->GetSection().GetFmt(); + nPos = 0; + break; + } + else if ( pNd->IsStartNode() && (SwTableBoxStartNode == + static_cast< SwStartNode* >(pNd)->GetStartNodeType()) ) + { + SwTableNode* pTblNode = pNd->FindTableNode(); + if ( pTblNode ) + { + SwTableBox* pBox = + pTblNode->GetTable().GetTblBox( m_nNodeIndex ); + if ( pBox ) + { + m_pFmt = pBox->GetFrmFmt(); + nPos = 0; + break; + } + } + } + } + // no break! + case RES_DRAWFRMFMT: + case RES_FLYFRMFMT: + nPos = pDoc->GetSpzFrmFmts()->GetPos( + static_cast<const SwFrmFmtPtr>(m_pFmt) ); + if ( USHRT_MAX == nPos ) + { + nPos = pDoc->GetFrmFmts()->GetPos( + static_cast<const SwFrmFmtPtr>(m_pFmt) ); + } + break; + } + + if ( USHRT_MAX == nPos ) + { + // Format does not exist; reset + m_pFmt = 0; + } + + return 0 != m_pFmt; +} + +// prueft, ob es noch im Doc ist! +SwFmt* SwUndoFmtAttr::GetFmt( SwDoc& rDoc ) +{ + return m_pFmt && IsFmtInDoc( &rDoc ) ? m_pFmt : 0; +} + +void SwUndoFmtAttr::Redo( SwUndoIter& rUndoIter) +{ + // --> OD 2004-10-26 #i35443# - Because the undo stores the attributes for + // redo, the same code as for <Undo(..)> can be applied for <Redo(..)> + Undo( rUndoIter ); + // <-- +} + +void SwUndoFmtAttr::Repeat( SwUndoIter& rUndoIter) +{ + if ( !m_pOldSet.get() ) + return; + + if ( UNDO_INSFMTATTR == rUndoIter.GetLastUndoId()) + { + SwUndoFmtAttr* pLast + = static_cast<SwUndoFmtAttr*>(rUndoIter.pLastUndoObj); + if (pLast->m_pOldSet.get() && pLast->m_pFmt) + { + return; + } + } + + switch ( m_nFmtWhich ) + { + case RES_GRFFMTCOLL: + { + SwNoTxtNode * pNd = rUndoIter.pAktPam->GetNode()->GetNoTxtNode(); + if( pNd ) + { + rUndoIter.GetDoc().SetAttr( m_pFmt->GetAttrSet(), + *pNd->GetFmtColl() ); + } + } + break; + + case RES_TXTFMTCOLL: + { + SwTxtNode * pNd = rUndoIter.pAktPam->GetNode()->GetTxtNode(); + if( pNd ) + { + rUndoIter.GetDoc().SetAttr( m_pFmt->GetAttrSet(), + *pNd->GetFmtColl() ); + } + } + break; + +// case RES_CHRFMT: +// case RES_FRMFMT: + + case RES_FLYFRMFMT: + { + // erstal pruefen, ob der Cursor ueberhaupt in einem fliegenden + // Rahmen steht. Der Weg ist: suche in allen FlyFrmFormaten + // nach dem FlyCntnt-Attribut und teste ob der Cursor in der + // entsprechenden Section liegt. + SwFrmFmt* pFly = rUndoIter.pAktPam->GetNode()->GetFlyFmt(); + if( pFly ) + { + // Bug 43672: es duerfen nicht alle Attribute gesetzt werden! + if (SFX_ITEM_SET == + m_pFmt->GetAttrSet().GetItemState( RES_CNTNT )) + { + SfxItemSet aTmpSet( m_pFmt->GetAttrSet() ); + aTmpSet.ClearItem( RES_CNTNT ); + if( aTmpSet.Count() ) + rUndoIter.GetDoc().SetAttr( aTmpSet, *pFly ); + } + else + { + rUndoIter.GetDoc().SetAttr( m_pFmt->GetAttrSet(), *pFly ); + } + } + break; + } + } + + rUndoIter.pLastUndoObj = this; +} + +SwRewriter SwUndoFmtAttr::GetRewriter() const +{ + SwRewriter aRewriter; + + if (m_pFmt) + { + aRewriter.AddRule(UNDO_ARG1, m_pFmt->GetName()); + } + + return aRewriter; +} + +void SwUndoFmtAttr::PutAttr( const SfxPoolItem& rItem ) +{ + m_pOldSet->Put( rItem ); + if ( RES_ANCHOR == rItem.Which() ) + { + SaveFlyAnchor( m_bSaveDrawPt ); + } +} + +void SwUndoFmtAttr::SaveFlyAnchor( bool bSvDrwPt ) +{ + // das Format ist gueltig, sonst wuerde man gar bis hier kommen + if( bSvDrwPt ) + { + if ( RES_DRAWFRMFMT == m_pFmt->Which() ) + { + Point aPt( static_cast<SwFrmFmt*>(m_pFmt)->FindSdrObject() + ->GetRelativePos() ); + // store old value as attribute, to keep SwUndoFmtAttr small + m_pOldSet->Put( SwFmtFrmSize( ATT_VAR_SIZE, aPt.X(), aPt.Y() ) ); + } +/* else + { + pOldSet->Put( pFmt->GetVertOrient() ); + pOldSet->Put( pFmt->GetHoriOrient() ); + } +*/ } + + const SwFmtAnchor& rAnchor = + static_cast<const SwFmtAnchor&>( m_pOldSet->Get( RES_ANCHOR, FALSE ) ); + if( !rAnchor.GetCntntAnchor() ) + return; + + xub_StrLen nCntnt = 0; + switch( rAnchor.GetAnchorId() ) + { + case FLY_AS_CHAR: + case FLY_AT_CHAR: + nCntnt = rAnchor.GetCntntAnchor()->nContent.GetIndex(); + case FLY_AT_PARA: + case FLY_AT_FLY: + m_nNodeIndex = rAnchor.GetCntntAnchor()->nNode.GetIndex(); + break; + default: + return; + } + + SwFmtAnchor aAnchor( rAnchor.GetAnchorId(), nCntnt ); + m_pOldSet->Put( aAnchor ); +} + +// --> OD 2004-10-26 #i35443# - Add return value, type <bool>. +// Return value indicates, if anchor attribute is restored. +// Note: If anchor attribute is restored, all other existing attributes +// are also restored. +bool SwUndoFmtAttr::RestoreFlyAnchor( SwUndoIter& rIter ) +{ + SwDoc* pDoc = &rIter.GetDoc(); + SwFlyFrmFmt* pFrmFmt = static_cast<SwFlyFrmFmt*>(m_pFmt); + const SwFmtAnchor& rAnchor = + static_cast<const SwFmtAnchor&>( m_pOldSet->Get( RES_ANCHOR, FALSE ) ); + + SwFmtAnchor aNewAnchor( rAnchor.GetAnchorId() ); + if (FLY_AT_PAGE != rAnchor.GetAnchorId()) + { + SwNode* pNd = pDoc->GetNodes()[ m_nNodeIndex ]; + + if ( (FLY_AT_FLY == rAnchor.GetAnchorId()) + ? ( !pNd->IsStartNode() || (SwFlyStartNode != + static_cast<SwStartNode*>(pNd)->GetStartNodeType()) ) + : !pNd->IsTxtNode() ) + { + // --> OD 2004-10-26 #i35443# - invalid position. + // Thus, anchor attribute not restored + return false; + // <-- + } + + SwPosition aPos( *pNd ); + if ((FLY_AS_CHAR == rAnchor.GetAnchorId()) || + (FLY_AT_CHAR == rAnchor.GetAnchorId())) + { + aPos.nContent.Assign( (SwTxtNode*)pNd, rAnchor.GetPageNum() ); + if ( aPos.nContent.GetIndex() > + static_cast<SwTxtNode*>(pNd)->GetTxt().Len() ) + { + // --> OD 2004-10-26 #i35443# - invalid position. + // Thus, anchor attribute not restored + return false; + // <-- + } + } + aNewAnchor.SetAnchor( &aPos ); + } + else + aNewAnchor.SetPageNum( rAnchor.GetPageNum() ); + + Point aDrawSavePt, aDrawOldPt; + if( pDoc->GetRootFrm() ) + { + if( RES_DRAWFRMFMT == pFrmFmt->Which() ) + { + // den alten zwischengespeicherten Wert herausholen. + const SwFmtFrmSize& rOldSize = static_cast<const SwFmtFrmSize&>( + m_pOldSet->Get( RES_FRM_SIZE ) ); + aDrawSavePt.X() = rOldSize.GetWidth(); + aDrawSavePt.Y() = rOldSize.GetHeight(); + m_pOldSet->ClearItem( RES_FRM_SIZE ); + + // den akt. wieder zwischenspeichern + aDrawOldPt = pFrmFmt->FindSdrObject()->GetRelativePos(); +//JP 08.10.97: ist laut AMA/MA nicht mehr noetig +// pCont->DisconnectFromLayout(); + } + else + { + pFrmFmt->DelFrms(); // delete Frms + } + } + + const SwFmtAnchor &rOldAnch = pFrmFmt->GetAnchor(); + // --> OD 2006-03-13 #i54336# + // Consider case, that as-character anchored object has moved its anchor position. + if (FLY_AS_CHAR == rOldAnch.GetAnchorId()) + // <-- + { + //Bei InCntnt's wird es spannend: Das TxtAttribut muss vernichtet + //werden. Leider reisst dies neben den Frms auch noch das Format mit + //in sein Grab. Um dass zu unterbinden loesen wir vorher die + //Verbindung zwischen Attribut und Format. + const SwPosition *pPos = rOldAnch.GetCntntAnchor(); + SwTxtNode *pTxtNode = (SwTxtNode*)&pPos->nNode.GetNode(); + ASSERT( pTxtNode->HasHints(), "Missing FlyInCnt-Hint." ); + const xub_StrLen nIdx = pPos->nContent.GetIndex(); + SwTxtAttr * const pHnt = + pTxtNode->GetTxtAttrForCharAt( nIdx, RES_TXTATR_FLYCNT ); + ASSERT( pHnt && pHnt->Which() == RES_TXTATR_FLYCNT, + "Missing FlyInCnt-Hint." ); + ASSERT( pHnt && pHnt->GetFlyCnt().GetFrmFmt() == pFrmFmt, + "Wrong TxtFlyCnt-Hint." ); + const_cast<SwFmtFlyCnt&>(pHnt->GetFlyCnt()).SetFlyFmt(); + + //Die Verbindung ist geloest, jetzt muss noch das Attribut vernichtet + //werden. + pTxtNode->DeleteAttributes( RES_TXTATR_FLYCNT, nIdx, nIdx ); + } + + { + m_pOldSet->Put( aNewAnchor ); + SwUndoFmtAttrHelper aTmp( *m_pFmt, m_bSaveDrawPt ); + m_pFmt->SetFmtAttr( *m_pOldSet ); + if ( aTmp.GetUndo() ) + { + m_nNodeIndex = aTmp.GetUndo()->m_nNodeIndex; + // transfer ownership of helper object's old set + m_pOldSet = aTmp.GetUndo()->m_pOldSet; + } + else + { + m_pOldSet->ClearItem(); + } + } + + if ( RES_DRAWFRMFMT == pFrmFmt->Which() ) + { + SwDrawContact *pCont = + static_cast<SwDrawContact*>(pFrmFmt->FindContactObj()); + // das Draw-Model hat auch noch ein Undo-Object fuer die + // richtige Position vorbereitet; dieses ist aber relativ. + // Darum verhinder hier, das durch setzen des Ankers das + // Contact-Object seine Position aendert. +//JP 08.10.97: ist laut AMA/MA nicht mehr noetig +// pCont->ConnectToLayout(); + SdrObject* pObj = pCont->GetMaster(); + + if( pCont->GetAnchorFrm() && !pObj->IsInserted() ) + { + ASSERT( pDoc->GetDrawModel(), "RestoreFlyAnchor without DrawModel" ); + pDoc->GetDrawModel()->GetPage( 0 )->InsertObject( pObj ); + } + pObj->SetRelativePos( aDrawSavePt ); + + // den alten Wert wieder zwischenspeichern. + m_pOldSet->Put( + SwFmtFrmSize( ATT_VAR_SIZE, aDrawOldPt.X(), aDrawOldPt.Y() ) ); + } + + if (FLY_AS_CHAR == aNewAnchor.GetAnchorId()) + { + const SwPosition* pPos = aNewAnchor.GetCntntAnchor(); + SwTxtNode* pTxtNd = pPos->nNode.GetNode().GetTxtNode(); + ASSERT( pTxtNd, "no Text Node at position." ); + SwFmtFlyCnt aFmt( pFrmFmt ); + pTxtNd->InsertItem( aFmt, pPos->nContent.GetIndex(), 0 ); + } + + + if( RES_DRAWFRMFMT != pFrmFmt->Which() ) + pFrmFmt->MakeFrms(); + + rIter.pSelFmt = pFrmFmt; + + // --> OD 2004-10-26 #i35443# - anchor attribute restored. + return true; + // <-- +} + +// ----------------------------------------------------- + +// --> OD 2008-02-12 #newlistlevelattrs# +SwUndoFmtResetAttr::SwUndoFmtResetAttr( SwFmt& rChangedFormat, + const USHORT nWhichId ) + : SwUndo( UNDO_RESETATTR ) + , m_pChangedFormat( &rChangedFormat ) + , m_nWhichId( nWhichId ) + , m_pOldItem( 0 ) +{ + const SfxPoolItem* pItem = 0; + if (rChangedFormat.GetItemState( nWhichId, FALSE, &pItem ) == SFX_ITEM_SET) + { + m_pOldItem.reset( pItem->Clone() ); + } +} + +SwUndoFmtResetAttr::~SwUndoFmtResetAttr() +{ +} + +void SwUndoFmtResetAttr::Undo( SwUndoIter& ) +{ + if ( m_pOldItem.get() ) + { + m_pChangedFormat->SetFmtAttr( *m_pOldItem ); + } +} + +void SwUndoFmtResetAttr::Redo( SwUndoIter& ) +{ + if ( m_pOldItem.get() ) + { + m_pChangedFormat->ResetFmtAttr( m_nWhichId ); + } +} +// <-- + +// ----------------------------------------------------- + +SwUndoResetAttr::SwUndoResetAttr( const SwPaM& rRange, USHORT nFmtId ) + : SwUndo( UNDO_RESETATTR ), SwUndRng( rRange ) + , m_pHistory( new SwHistory ) + , m_nFormatId( nFmtId ) +{ +} + +SwUndoResetAttr::SwUndoResetAttr( const SwPosition& rPos, USHORT nFmtId ) + : SwUndo( UNDO_RESETATTR ) + , m_pHistory( new SwHistory ) + , m_nFormatId( nFmtId ) +{ + nSttNode = nEndNode = rPos.nNode.GetIndex(); + nSttCntnt = nEndCntnt = rPos.nContent.GetIndex(); +} + +SwUndoResetAttr::~SwUndoResetAttr() +{ +} + +void SwUndoResetAttr::Undo( SwUndoIter& rUndoIter ) +{ + // reset old values + SwDoc& rDoc = rUndoIter.GetDoc(); + m_pHistory->TmpRollback( &rDoc, 0 ); + m_pHistory->SetTmpEnd( m_pHistory->Count() ); + + if ((RES_CONDTXTFMTCOLL == m_nFormatId) && + (nSttNode == nEndNode) && (nSttCntnt == nEndCntnt)) + { + SwTxtNode* pTNd = rDoc.GetNodes()[ nSttNode ]->GetTxtNode(); + if( pTNd ) + { + SwIndex aIdx( pTNd, nSttCntnt ); + pTNd->DontExpandFmt( aIdx, FALSE ); + } + } + + // setze noch den Cursor auf den Undo-Bereich + SetPaM( rUndoIter ); +} + +void SwUndoResetAttr::Redo( SwUndoIter& rUndoIter ) +{ + // setze Attribut in dem Bereich: + SetPaM( rUndoIter ); + SwDoc& rDoc = rUndoIter.GetDoc(); + rUndoIter.pLastUndoObj = 0; + SvUShortsSort* pIdArr = m_Ids.Count() ? &m_Ids : 0; + + switch ( m_nFormatId ) + { + case RES_CHRFMT: + rUndoIter.GetDoc().RstTxtAttrs( *rUndoIter.pAktPam ); + break; + case RES_TXTFMTCOLL: + rUndoIter.GetDoc().ResetAttrs( *rUndoIter.pAktPam, FALSE, pIdArr ); + break; + case RES_CONDTXTFMTCOLL: + rUndoIter.GetDoc().ResetAttrs( *rUndoIter.pAktPam, TRUE, pIdArr ); + + break; + case RES_TXTATR_TOXMARK: + // special treatment for TOXMarks + { + SwTOXMarks aArr; + SwNodeIndex aIdx( rDoc.GetNodes(), nSttNode ); + SwPosition aPos( aIdx, SwIndex( aIdx.GetNode().GetCntntNode(), + nSttCntnt )); + + USHORT nCnt = rDoc.GetCurTOXMark( aPos, aArr ); + if( nCnt ) + { + if( 1 < nCnt ) + { + // search for the right one + SwHistoryHint* pHHint = (GetHistory())[ 0 ]; + if( pHHint && HSTRY_SETTOXMARKHNT == pHHint->Which() ) + { + while( nCnt ) + { + if ( static_cast<SwHistorySetTOXMark*>(pHHint) + ->IsEqual( *aArr[ --nCnt ] ) ) + { + ++nCnt; + break; + } + } + } + else + nCnt = 0; + } + // gefunden, also loeschen + if( nCnt-- ) + { + rDoc.DeleteTOXMark( aArr[ nCnt ] ); + } + } + } + break; + } + rUndoIter.pLastUndoObj = 0; +} + +void SwUndoResetAttr::Repeat( SwUndoIter& rUndoIter ) +{ + if ( (RES_FMT_BEGIN > m_nFormatId) || + ( (UNDO_RESETATTR == rUndoIter.GetLastUndoId()) && + (m_nFormatId == static_cast<SwUndoResetAttr*>(rUndoIter.pLastUndoObj) + ->m_nFormatId) ) ) + { + return; + } + + SvUShortsSort* pIdArr = m_Ids.Count() ? &m_Ids : 0; + switch ( m_nFormatId ) + { + case RES_CHRFMT: + rUndoIter.GetDoc().RstTxtAttrs( *rUndoIter.pAktPam ); + break; + case RES_TXTFMTCOLL: + rUndoIter.GetDoc().ResetAttrs( *rUndoIter.pAktPam, FALSE, pIdArr ); + break; + case RES_CONDTXTFMTCOLL: + rUndoIter.GetDoc().ResetAttrs( *rUndoIter.pAktPam, TRUE, pIdArr ); + break; + } + rUndoIter.pLastUndoObj = this; +} + + +void SwUndoResetAttr::SetAttrs( const SvUShortsSort& rArr ) +{ + if ( m_Ids.Count() ) + { + m_Ids.Remove( 0, m_Ids.Count() ); + } + m_Ids.Insert( &rArr ); +} + +// ----------------------------------------------------- + + +SwUndoAttr::SwUndoAttr( const SwPaM& rRange, const SfxPoolItem& rAttr, + const SetAttrMode nFlags ) + : SwUndo( UNDO_INSATTR ), SwUndRng( rRange ) + , m_AttrSet( rRange.GetDoc()->GetAttrPool(), rAttr.Which(), rAttr.Which() ) + , m_pHistory( new SwHistory ) + , m_pRedlineData( 0 ) + , m_pRedlineSaveData( 0 ) + , m_nNodeIndex( ULONG_MAX ) + , m_nInsertFlags( nFlags ) +{ + m_AttrSet.Put( rAttr ); +} + +SwUndoAttr::SwUndoAttr( const SwPaM& rRange, const SfxItemSet& rSet, + const SetAttrMode nFlags ) + : SwUndo( UNDO_INSATTR ), SwUndRng( rRange ) + , m_AttrSet( rSet ) + , m_pHistory( new SwHistory ) + , m_pRedlineData( 0 ) + , m_pRedlineSaveData( 0 ) + , m_nNodeIndex( ULONG_MAX ) + , m_nInsertFlags( nFlags ) +{ +} + +SwUndoAttr::~SwUndoAttr() +{ +} + +void SwUndoAttr::SaveRedlineData( const SwPaM& rPam, BOOL bIsCntnt ) +{ + SwDoc* pDoc = rPam.GetDoc(); + if ( pDoc->IsRedlineOn() ) + { + m_pRedlineData.reset( new SwRedlineData( bIsCntnt + ? nsRedlineType_t::REDLINE_INSERT + : nsRedlineType_t::REDLINE_FORMAT, + pDoc->GetRedlineAuthor() ) ); + } + + m_pRedlineSaveData.reset( new SwRedlineSaveDatas ); + if ( !FillSaveDataForFmt( rPam, *m_pRedlineSaveData )) + { + m_pRedlineSaveData.reset(0); + } + + SetRedlineMode( pDoc->GetRedlineMode() ); + if ( bIsCntnt ) + { + m_nNodeIndex = rPam.GetPoint()->nNode.GetIndex(); + } +} + +void SwUndoAttr::Undo( SwUndoIter& rUndoIter ) +{ + SwDoc* pDoc = &rUndoIter.GetDoc(); + + RemoveIdx( *pDoc ); + + if( IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() ) ) + { + SwPaM& rPam = *rUndoIter.pAktPam; + if ( ULONG_MAX != m_nNodeIndex ) + { + rPam.DeleteMark(); + rPam.GetPoint()->nNode = m_nNodeIndex; + rPam.GetPoint()->nContent.Assign( rPam.GetCntntNode(), nSttCntnt ); + rPam.SetMark(); + rPam.GetPoint()->nContent++; + pDoc->DeleteRedline( rPam, false, USHRT_MAX ); + } + else + { + // alle Format-Redlines entfernen, werden ggfs. neu gesetzt + SetPaM( rUndoIter ); + pDoc->DeleteRedline( rPam, false, nsRedlineType_t::REDLINE_FORMAT ); + if ( m_pRedlineSaveData.get() ) + { + SetSaveData( *pDoc, *m_pRedlineSaveData ); + } + } + } + + const bool bToLast = (1 == m_AttrSet.Count()) + && (RES_TXTATR_FIELD <= *m_AttrSet.GetRanges()) + && (*m_AttrSet.GetRanges() <= RES_TXTATR_FTN); + + // restore old values + m_pHistory->TmpRollback( pDoc, 0, !bToLast ); + m_pHistory->SetTmpEnd( m_pHistory->Count() ); + + // set cursor onto Undo area + SetPaM( rUndoIter ); +} + +int lcl_HasEqualItems( const SfxItemSet& rSet1, const SfxItemSet& rSet2 ) +{ + int nRet = -1; + SfxItemIter aIter1( rSet1 ), aIter2( rSet2 ); + const SfxPoolItem *pI1 = aIter1.FirstItem(), *pI2 = aIter2.FirstItem(); + + while( pI1 && pI2 ) + { + if( pI1->Which() != pI2->Which() || + aIter1.IsAtEnd() != aIter2.IsAtEnd() ) + { + nRet = 0; + break; + } + if( aIter1.IsAtEnd() ) + break; + pI1 = aIter1.NextItem(); + pI2 = aIter2.NextItem(); + } + return nRet; +} + +void SwUndoAttr::Repeat( SwUndoIter& rUndoIter ) +{ + if ( UNDO_INSATTR == rUndoIter.GetLastUndoId() ) + { + SwUndoAttr* pLast = static_cast<SwUndoAttr*>(rUndoIter.pLastUndoObj); + if ((pLast->m_AttrSet.Count() == m_AttrSet.Count()) && + (pLast->m_nInsertFlags == m_nInsertFlags ) && + lcl_HasEqualItems( m_AttrSet, pLast->m_AttrSet )) + { + return; + } + } + + + // RefMarks are not repeat capable + if ( SFX_ITEM_SET != m_AttrSet.GetItemState( RES_TXTATR_REFMARK, FALSE ) ) + { + rUndoIter.GetDoc().InsertItemSet( *rUndoIter.pAktPam, + m_AttrSet, m_nInsertFlags ); + } + else if ( 1 < m_AttrSet.Count() ) + { + SfxItemSet aTmpSet( m_AttrSet ); + aTmpSet.ClearItem( RES_TXTATR_REFMARK ); + rUndoIter.GetDoc().InsertItemSet( *rUndoIter.pAktPam, + aTmpSet, m_nInsertFlags ); + } + rUndoIter.pLastUndoObj = this; +} + +void SwUndoAttr::Redo( SwUndoIter& rUndoIter ) +{ + // setze Attribut in dem Bereich: + SetPaM( rUndoIter ); + SwPaM& rPam = *rUndoIter.pAktPam; + SwDoc& rDoc = rUndoIter.GetDoc(); + + if ( m_pRedlineData.get() && + IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() ) ) + { + RedlineMode_t eOld = rDoc.GetRedlineMode(); + rDoc.SetRedlineMode_intern(static_cast<RedlineMode_t>( + eOld & ~nsRedlineMode_t::REDLINE_IGNORE)); + rDoc.InsertItemSet( rPam, m_AttrSet, m_nInsertFlags ); + + if ( ULONG_MAX != m_nNodeIndex ) + { + rPam.SetMark(); + if ( rPam.Move( fnMoveBackward ) ) + { + rDoc.AppendRedline( new SwRedline( *m_pRedlineData, rPam ), + true); + } + rPam.DeleteMark(); + } + else + { + rDoc.AppendRedline( new SwRedline( *m_pRedlineData, rPam ), true); + } + + rDoc.SetRedlineMode_intern( eOld ); + } + else + { + rDoc.InsertItemSet( rPam, m_AttrSet, m_nInsertFlags ); + } + + rUndoIter.pLastUndoObj = 0; +} + + +void SwUndoAttr::RemoveIdx( SwDoc& rDoc ) +{ + if ( SFX_ITEM_SET != m_AttrSet.GetItemState( RES_TXTATR_FTN, FALSE )) + return ; + + SwHistoryHint* pHstHnt; + SwNodes& rNds = rDoc.GetNodes(); + for ( USHORT n = 0; n < m_pHistory->Count(); ++n ) + { + xub_StrLen nCntnt = 0; + ULONG nNode = 0; + pHstHnt = (*m_pHistory)[ n ]; + switch ( pHstHnt->Which() ) + { + case HSTRY_RESETTXTHNT: + { + SwHistoryResetTxt * pHistoryHint + = static_cast<SwHistoryResetTxt*>(pHstHnt); + if ( RES_TXTATR_FTN == pHistoryHint->GetWhich() ) + { + nNode = pHistoryHint->GetNode(); + nCntnt = pHistoryHint->GetCntnt(); + } + } + break; + + case HSTRY_RESETATTRSET: + { + SwHistoryResetAttrSet * pHistoryHint + = static_cast<SwHistoryResetAttrSet*>(pHstHnt); + nCntnt = pHistoryHint->GetCntnt(); + if ( STRING_MAXLEN != nCntnt ) + { + const SvUShorts& rArr = pHistoryHint->GetArr(); + for ( USHORT i = rArr.Count(); i; ) + { + if ( RES_TXTATR_FTN == rArr[ --i ] ) + { + nNode = pHistoryHint->GetNode(); + break; + } + } + } + } + break; + + default: + break; + } + + if( nNode ) + { + SwTxtNode* pTxtNd = rNds[ nNode ]->GetTxtNode(); + if( pTxtNd ) + { + SwTxtAttr *const pTxtHt = + pTxtNd->GetTxtAttrForCharAt(nCntnt, RES_TXTATR_FTN); + if( pTxtHt ) + { + // ok, dann hole mal die Werte + SwTxtFtn* pFtn = static_cast<SwTxtFtn*>(pTxtHt); + RemoveIdxFromSection( rDoc, pFtn->GetStartNode()->GetIndex() ); + return ; + } + } + } + } +} + +// ----------------------------------------------------- + +SwUndoDefaultAttr::SwUndoDefaultAttr( const SfxItemSet& rSet ) + : SwUndo( UNDO_SETDEFTATTR ) + , m_pOldSet( 0 ) + , m_pTabStop( 0 ) +{ + const SfxPoolItem* pItem; + if( SFX_ITEM_SET == rSet.GetItemState( RES_PARATR_TABSTOP, FALSE, &pItem ) ) + { + // store separately, because it may change! + m_pTabStop.reset( static_cast<SvxTabStopItem*>(pItem->Clone()) ); + if ( 1 != rSet.Count() ) // are there more attributes? + { + m_pOldSet.reset( new SfxItemSet( rSet ) ); + } + } + else + { + m_pOldSet.reset( new SfxItemSet( rSet ) ); + } +} + +SwUndoDefaultAttr::~SwUndoDefaultAttr() +{ +} + +void SwUndoDefaultAttr::Undo( SwUndoIter& rUndoIter) +{ + SwDoc& rDoc = rUndoIter.GetDoc(); + if ( m_pOldSet.get() ) + { + SwUndoFmtAttrHelper aTmp( + *const_cast<SwTxtFmtColl*>(rDoc.GetDfltTxtFmtColl()) ); + rDoc.SetDefault( *m_pOldSet ); + m_pOldSet.reset( 0 ); + if ( aTmp.GetUndo() ) + { + // transfer ownership of helper object's old set + m_pOldSet = aTmp.GetUndo()->m_pOldSet; + } + } + if ( m_pTabStop.get() ) + { + SvxTabStopItem* pOld = static_cast<SvxTabStopItem*>( + rDoc.GetDefault( RES_PARATR_TABSTOP ).Clone() ); + rDoc.SetDefault( *m_pTabStop ); + m_pTabStop.reset( pOld ); + } +} + +void SwUndoDefaultAttr::Redo( SwUndoIter& rUndoIter) +{ + Undo( rUndoIter ); +} + +// ----------------------------------------------------- + +SwUndoMoveLeftMargin::SwUndoMoveLeftMargin( + const SwPaM& rPam, BOOL bFlag, BOOL bMod ) + : SwUndo( bFlag ? UNDO_INC_LEFTMARGIN : UNDO_DEC_LEFTMARGIN ) + , SwUndRng( rPam ) + , m_pHistory( new SwHistory ) + , m_bModulus( bMod ) +{ +} + +SwUndoMoveLeftMargin::~SwUndoMoveLeftMargin() +{ +} + +void SwUndoMoveLeftMargin::Undo( SwUndoIter& rIter ) +{ + SwDoc* pDoc = &rIter.GetDoc(); + BOOL bUndo = pDoc->DoesUndo(); + pDoc->DoUndo( FALSE ); + + // restore old values + m_pHistory->TmpRollback( pDoc, 0 ); + m_pHistory->SetTmpEnd( m_pHistory->Count() ); + + pDoc->DoUndo( bUndo ); + SetPaM( rIter ); +} + +void SwUndoMoveLeftMargin::Redo( SwUndoIter& rIter ) +{ + SwDoc* pDoc = &rIter.GetDoc(); + SetPaM( rIter ); + pDoc->MoveLeftMargin( *rIter.pAktPam, GetId() == UNDO_INC_LEFTMARGIN, + m_bModulus ); +} + +void SwUndoMoveLeftMargin::Repeat( SwUndoIter& rIter ) +{ + SwDoc* pDoc = &rIter.GetDoc(); + pDoc->MoveLeftMargin( *rIter.pAktPam, GetId() == UNDO_INC_LEFTMARGIN, + m_bModulus ); + rIter.pLastUndoObj = this; +} + +// ----------------------------------------------------- + +SwUndoChangeFootNote::SwUndoChangeFootNote( + const SwPaM& rRange, const String& rTxt, + USHORT nNum, bool bIsEndNote ) + : SwUndo( UNDO_CHGFTN ), SwUndRng( rRange ) + , m_pHistory( new SwHistory() ) + , m_Text( rTxt ) + , m_nNumber( nNum ) + , m_bEndNote( bIsEndNote ) +{ +} + +SwUndoChangeFootNote::~SwUndoChangeFootNote() +{ +} + +void SwUndoChangeFootNote::Undo( SwUndoIter& rIter ) +{ + SwDoc& rDoc = rIter.GetDoc(); + SetPaM( rIter ); + + BOOL bUndo = rDoc.DoesUndo(); + rDoc.DoUndo( FALSE ); + + m_pHistory->TmpRollback( &rDoc, 0 ); + m_pHistory->SetTmpEnd( m_pHistory->Count() ); + + rDoc.GetFtnIdxs().UpdateAllFtn(); + + SetPaM( rIter ); + rDoc.DoUndo( bUndo ); +} + +void SwUndoChangeFootNote::Redo( SwUndoIter& rIter ) +{ + SetPaM( rIter ); + rIter.GetDoc().SetCurFtn( *rIter.pAktPam, m_Text, m_nNumber, m_bEndNote ); + SetPaM( rIter ); +} + +void SwUndoChangeFootNote::Repeat( SwUndoIter& rIter ) +{ + SwDoc& rDoc = rIter.GetDoc(); + rDoc.SetCurFtn( *rIter.pAktPam, m_Text, m_nNumber, m_bEndNote ); + rIter.pLastUndoObj = this; +} + + +// ----------------------------------------------------- + + +SwUndoFootNoteInfo::SwUndoFootNoteInfo( const SwFtnInfo &rInfo ) + : SwUndo( UNDO_FTNINFO ) + , m_pFootNoteInfo( new SwFtnInfo( rInfo ) ) +{ +} + +SwUndoFootNoteInfo::~SwUndoFootNoteInfo() +{ +} + +void SwUndoFootNoteInfo::Undo( SwUndoIter &rIter ) +{ + SwDoc &rDoc = rIter.GetDoc(); + SwFtnInfo *pInf = new SwFtnInfo( rDoc.GetFtnInfo() ); + rDoc.SetFtnInfo( *m_pFootNoteInfo ); + m_pFootNoteInfo.reset( pInf ); +} + +void SwUndoFootNoteInfo::Redo( SwUndoIter &rIter ) +{ + SwDoc &rDoc = rIter.GetDoc(); + SwFtnInfo *pInf = new SwFtnInfo( rDoc.GetFtnInfo() ); + rDoc.SetFtnInfo( *m_pFootNoteInfo ); + m_pFootNoteInfo.reset( pInf ); +} + + +// ----------------------------------------------------- + +SwUndoEndNoteInfo::SwUndoEndNoteInfo( const SwEndNoteInfo &rInfo ) + : SwUndo( UNDO_FTNINFO ) + , m_pEndNoteInfo( new SwEndNoteInfo( rInfo ) ) +{ +} + +SwUndoEndNoteInfo::~SwUndoEndNoteInfo() +{ +} + +void SwUndoEndNoteInfo::Undo( SwUndoIter &rIter ) +{ + SwDoc &rDoc = rIter.GetDoc(); + SwEndNoteInfo *pInf = new SwEndNoteInfo( rDoc.GetEndNoteInfo() ); + rDoc.SetEndNoteInfo( *m_pEndNoteInfo ); + m_pEndNoteInfo.reset( pInf ); +} + +void SwUndoEndNoteInfo::Redo( SwUndoIter &rIter ) +{ + SwDoc &rDoc = rIter.GetDoc(); + SwEndNoteInfo *pInf = new SwEndNoteInfo( rDoc.GetEndNoteInfo() ); + rDoc.SetEndNoteInfo( *m_pEndNoteInfo ); + m_pEndNoteInfo.reset( pInf ); +} + +// ----------------------------------------------------- + +SwUndoDontExpandFmt::SwUndoDontExpandFmt( const SwPosition& rPos ) + : SwUndo( UNDO_DONTEXPAND ) + , m_nNodeIndex( rPos.nNode.GetIndex() ) + , m_nContentIndex( rPos.nContent.GetIndex() ) +{ +} + +void SwUndoDontExpandFmt::Undo( SwUndoIter& rIter ) +{ + SwPaM* pPam = rIter.pAktPam; + SwDoc* pDoc = pPam->GetDoc(); + + SwPosition& rPos = *pPam->GetPoint(); + rPos.nNode = m_nNodeIndex; + rPos.nContent.Assign( rPos.nNode.GetNode().GetCntntNode(), m_nContentIndex); + pDoc->DontExpandFmt( rPos, FALSE ); +} + + +void SwUndoDontExpandFmt::Redo( SwUndoIter& rIter ) +{ + SwPaM* pPam = rIter.pAktPam; + SwDoc* pDoc = pPam->GetDoc(); + + SwPosition& rPos = *pPam->GetPoint(); + rPos.nNode = m_nNodeIndex; + rPos.nContent.Assign( rPos.nNode.GetNode().GetCntntNode(), m_nContentIndex); + pDoc->DontExpandFmt( rPos ); +} + +void SwUndoDontExpandFmt::Repeat( SwUndoIter& rIter ) +{ + SwPaM* pPam = rIter.pAktPam; + SwDoc* pDoc = pPam->GetDoc(); + pDoc->DontExpandFmt( *pPam->GetPoint() ); +} + diff --git a/sw/source/core/undo/unbkmk.cxx b/sw/source/core/undo/unbkmk.cxx new file mode 100644 index 000000000000..b86bdad692ac --- /dev/null +++ b/sw/source/core/undo/unbkmk.cxx @@ -0,0 +1,109 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include "doc.hxx" +#include "docary.hxx" +#include "swundo.hxx" // fuer die UndoIds +#include "pam.hxx" + +#include "undobj.hxx" +#include "IMark.hxx" +#include "rolbck.hxx" + +#include "SwRewriter.hxx" + + +inline SwDoc& SwUndoIter::GetDoc() const { return *pAktPam->GetDoc(); } + + +SwUndoBookmark::SwUndoBookmark( SwUndoId nUndoId, + const ::sw::mark::IMark& rBkmk ) + : SwUndo( nUndoId ) + , m_pHistoryBookmark(new SwHistoryBookmark(rBkmk, true, rBkmk.IsExpanded())) +{ +} + +SwUndoBookmark::~SwUndoBookmark() +{ +} + +void SwUndoBookmark::SetInDoc( SwDoc* pDoc ) +{ + m_pHistoryBookmark->SetInDoc( pDoc, false ); +} + + +void SwUndoBookmark::ResetInDoc( SwDoc* pDoc ) +{ + IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess(); + for (IDocumentMarkAccess::const_iterator_t ppBkmk = + pMarkAccess->getMarksBegin(); + ppBkmk != pMarkAccess->getMarksEnd(); + ++ppBkmk) + { + if ( m_pHistoryBookmark->IsEqualBookmark( **ppBkmk ) ) + { + pMarkAccess->deleteMark( ppBkmk ); + break; + } + } +} + +SwRewriter SwUndoBookmark::GetRewriter() const +{ + SwRewriter aResult; + + aResult.AddRule(UNDO_ARG1, m_pHistoryBookmark->GetName()); + + return aResult; +} + +//---------------------------------------------------------------------- + + +SwUndoInsBookmark::SwUndoInsBookmark( const ::sw::mark::IMark& rBkmk ) + : SwUndoBookmark( UNDO_INSBOOKMARK, rBkmk ) +{ +} + + +void SwUndoInsBookmark::Undo( SwUndoIter& rUndoIter ) +{ + ResetInDoc( &rUndoIter.GetDoc() ); +} + + +void SwUndoInsBookmark::Redo( SwUndoIter& rUndoIter ) +{ + SetInDoc( &rUndoIter.GetDoc() ); +} + + diff --git a/sw/source/core/undo/undel.cxx b/sw/source/core/undo/undel.cxx new file mode 100644 index 000000000000..ef39a4e18950 --- /dev/null +++ b/sw/source/core/undo/undel.cxx @@ -0,0 +1,1010 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <hintids.hxx> +#include <unotools/charclass.hxx> +#include <editeng/brkitem.hxx> +#include <fmtpdsc.hxx> +#include <frmfmt.hxx> +#include <fmtanchr.hxx> +#include <doc.hxx> +#include <swtable.hxx> +#include <swundo.hxx> // fuer die UndoIds +#include <pam.hxx> +#include <ndtxt.hxx> +#include <undobj.hxx> +#include <rolbck.hxx> +#include <poolfmt.hxx> +#include <mvsave.hxx> +#include <redline.hxx> +#include <docary.hxx> +#include <sfx2/app.hxx> + +#include <fldbas.hxx> +#include <fmtfld.hxx> +#include <comcore.hrc> // #111827# +#include <undo.hrc> + +// #include <editeng/svxacorr.hxx> +// #include <comphelper/processfactory.hxx> +// #include <editeng/unolingu.hxx> +// #include <unotools/localedatawrapper.hxx> + +// using namespace comphelper; + +inline SwDoc& SwUndoIter::GetDoc() const { return *pAktPam->GetDoc(); } + + +// DELETE +/* lcl_MakeAutoFrms has to call MakeFrms for objects bounded "AtChar" ( == AUTO ), + if the anchor frame has be moved via _MoveNodes(..) and DelFrms(..) +*/ + +void lcl_MakeAutoFrms( const SwSpzFrmFmts& rSpzArr, ULONG nMovedIndex ) +{ + if( rSpzArr.Count() ) + { + SwFlyFrmFmt* pFmt; + const SwFmtAnchor* pAnchor; + for( USHORT n = 0; n < rSpzArr.Count(); ++n ) + { + pFmt = (SwFlyFrmFmt*)rSpzArr[n]; + pAnchor = &pFmt->GetAnchor(); + if (pAnchor->GetAnchorId() == FLY_AT_CHAR) + { + const SwPosition* pAPos = pAnchor->GetCntntAnchor(); + if( pAPos && nMovedIndex == pAPos->nNode.GetIndex() ) + pFmt->MakeFrms(); + } + } + } +} + +/* +SwUndoDelete has to perform a deletion and to record anything that is needed to restore the +situation before the deletion. Unfortunately a part of the deletion will be done after calling +this Ctor, this has to be kept in mind! In this Ctor only the complete paragraphs will be deleted, +the joining of the first and last paragraph of the selection will be handled outside this function. +Here are the main steps of the function: +1. Deletion/recording of content indizes of the selection: footnotes, fly frames and bookmarks +Step 1 could shift all nodes by deletion of footnotes => nNdDiff will be set. +2. If the paragraph where the selection ends, is the last content of a section so that this +section becomes empty when the paragraphs will be joined we have to do some smart actions ;-) +The paragraph will be moved outside the section and replaced by a dummy text node, the complete +section will be deleted in step 3. The difference between replacement dummy and original is +nReplacementDummy. +3. Moving complete selected nodes into the UndoArray. Before this happens the selection has to be +extended if there are sections which would become empty otherwise. BTW: sections will be moved into +the UndoArray if they are complete part of the selection. Sections starting or ending outside of the +selection will not be removed from the DocNodeArray even they got a "dummy"-copy in the UndoArray. +4. We have to anticipate the joining of the two paragraphs if the start paragraph is inside a +section and the end paragraph not. Then we have to move the paragraph into this section and to +record this in nSectDiff. +*/ + +SwUndoDelete::SwUndoDelete( SwPaM& rPam, BOOL bFullPara, BOOL bCalledByTblCpy ) + : SwUndo(UNDO_DELETE), SwUndRng( rPam ), + pMvStt( 0 ), pSttStr(0), pEndStr(0), pRedlData(0), pRedlSaveData(0), + nNode(0), nNdDiff(0), nSectDiff(0), nReplaceDummy(0), nSetPos(0), + bGroup( FALSE ), bBackSp( FALSE ), bJoinNext( FALSE ), bTblDelLastNd( FALSE ), + bDelFullPara( bFullPara ), bResetPgDesc( FALSE ), bResetPgBrk( FALSE ), + bFromTableCopy( bCalledByTblCpy ) +{ + bDelFullPara = bFullPara; // This is set e.g. if an empty paragraph before a table is deleted + + bCacheComment = false; + + SwDoc * pDoc = rPam.GetDoc(); + + if( !pDoc->IsIgnoreRedline() && pDoc->GetRedlineTbl().Count() ) + { + pRedlSaveData = new SwRedlineSaveDatas; + if( !FillSaveData( rPam, *pRedlSaveData )) + delete pRedlSaveData, pRedlSaveData = 0; + } + + if( !pHistory ) + pHistory = new SwHistory; + + // loesche erstmal alle Fussnoten + const SwPosition *pStt = rPam.Start(), + *pEnd = rPam.GetPoint() == pStt + ? rPam.GetMark() + : rPam.GetPoint(); + + // Step 1. deletion/record of content indizes + if( bDelFullPara ) + { + ASSERT( rPam.HasMark(), "PaM ohne Mark" ); + DelCntntIndex( *rPam.GetMark(), *rPam.GetPoint(), + DelCntntType(nsDelCntntType::DELCNT_ALL | nsDelCntntType::DELCNT_CHKNOCNTNT) ); + + BOOL bDoesUndo = pDoc->DoesUndo(); + pDoc->DoUndo( FALSE ); + _DelBookmarks(pStt->nNode, pEnd->nNode); + pDoc->DoUndo( bDoesUndo ); + } + else + DelCntntIndex( *rPam.GetMark(), *rPam.GetPoint() ); + + nSetPos = pHistory ? pHistory->Count() : 0; + + // wurde schon was geloescht ?? + nNdDiff = nSttNode - pStt->nNode.GetIndex(); + + bJoinNext = !bFullPara && pEnd == rPam.GetPoint(); + bBackSp = !bFullPara && !bJoinNext; + + SwTxtNode *pSttTxtNd = 0, *pEndTxtNd = 0; + if( !bFullPara ) + { + pSttTxtNd = pStt->nNode.GetNode().GetTxtNode(); + pEndTxtNd = nSttNode == nEndNode + ? pSttTxtNd + : pEnd->nNode.GetNode().GetTxtNode(); + } + + BOOL bMoveNds = *pStt == *pEnd // noch ein Bereich vorhanden ?? + ? FALSE + : ( SaveCntnt( pStt, pEnd, pSttTxtNd, pEndTxtNd ) || bFromTableCopy ); + + if( pSttTxtNd && pEndTxtNd && pSttTxtNd != pEndTxtNd ) + { + // zwei unterschiedliche TextNodes, also speicher noch die + // TextFormatCollection fuers + pHistory->Add( pSttTxtNd->GetTxtColl(),pStt->nNode.GetIndex(), ND_TEXTNODE ); + pHistory->Add( pEndTxtNd->GetTxtColl(),pEnd->nNode.GetIndex(), ND_TEXTNODE ); + + if( !bJoinNext ) // Selection von Unten nach Oben + { + // Beim JoinPrev() werden die AUTO-PageBreak's richtig + // kopiert. Um diese beim Undo wieder herzustellen, muss das + // Auto-PageBreak aus dem EndNode zurueckgesetzt werden. + // - fuer die PageDesc, ColBreak dito ! + if( pEndTxtNd->HasSwAttrSet() ) + { + SwRegHistory aRegHist( *pEndTxtNd, pHistory ); + if( SFX_ITEM_SET == pEndTxtNd->GetpSwAttrSet()->GetItemState( + RES_BREAK, FALSE ) ) + pEndTxtNd->ResetAttr( RES_BREAK ); + if( pEndTxtNd->HasSwAttrSet() && + SFX_ITEM_SET == pEndTxtNd->GetpSwAttrSet()->GetItemState( + RES_PAGEDESC, FALSE ) ) + pEndTxtNd->ResetAttr( RES_PAGEDESC ); + } + } + } + + + // verschiebe jetzt noch den PaM !!! + // der SPoint steht am Anfang der SSelection + if( pEnd == rPam.GetPoint() && ( !bFullPara || pSttTxtNd || pEndTxtNd ) ) + rPam.Exchange(); + + if( !pSttTxtNd && !pEndTxtNd ) + rPam.GetPoint()->nNode--; + rPam.DeleteMark(); // der SPoint ist aus dem Bereich + + if( !pEndTxtNd ) + nEndCntnt = 0; + if( !pSttTxtNd ) + nSttCntnt = 0; + + if( bMoveNds ) // sind noch Nodes zu verschieben ? + { + SwNodes& rNds = (SwNodes&)*pDoc->GetUndoNds(); + SwNodes& rDocNds = pDoc->GetNodes(); + SwNodeRange aRg( rDocNds, nSttNode - nNdDiff, + rDocNds, nEndNode - nNdDiff ); + if( !bFullPara && !pEndTxtNd && + &aRg.aEnd.GetNode() != &pDoc->GetNodes().GetEndOfContent() ) + { + SwNode* pNode = aRg.aEnd.GetNode().StartOfSectionNode(); + if( pNode->GetIndex() >= nSttNode - nNdDiff ) + aRg.aEnd++; // Deletion of a complete table + } + SwNode* pTmpNd; + // Step 2: Expand selection if necessary + if( bJoinNext || bFullPara ) + { + // If all content of a section will be moved into Undo, + // the section itself should be moved complete. + while( aRg.aEnd.GetIndex() + 2 < rDocNds.Count() && + ( (pTmpNd = rDocNds[ aRg.aEnd.GetIndex()+1 ])->IsEndNode() && + pTmpNd->StartOfSectionNode()->IsSectionNode() && + pTmpNd->StartOfSectionNode()->GetIndex() >= aRg.aStart.GetIndex() ) ) + aRg.aEnd++; + nReplaceDummy = aRg.aEnd.GetIndex() + nNdDiff - nEndNode; + if( nReplaceDummy ) + { // The selection has been expanded, because + aRg.aEnd++; + if( pEndTxtNd ) + { + // The end text node has to leave the (expanded) selection + // The dummy is needed because _MoveNodes deletes empty sections + ++nReplaceDummy; + SwNodeRange aMvRg( *pEndTxtNd, 0, *pEndTxtNd, 1 ); + SwPosition aSplitPos( *pEndTxtNd ); + BOOL bDoesUndo = pDoc->DoesUndo(); + pDoc->DoUndo( FALSE ); + pDoc->SplitNode( aSplitPos, false ); + rDocNds._MoveNodes( aMvRg, rDocNds, aRg.aEnd, TRUE ); + pDoc->DoUndo( bDoesUndo ); + aRg.aEnd--; + } + else + nReplaceDummy = 0; + } + } + if( bBackSp || bFullPara ) + { + //See above, the selection has to expanded if there are "nearly empty" sections + // and a replacement dummy has to be set if needed. + while( 1 < aRg.aStart.GetIndex() && + ( (pTmpNd = rDocNds[ aRg.aStart.GetIndex()-1 ])->IsSectionNode() && + pTmpNd->EndOfSectionIndex() < aRg.aEnd.GetIndex() ) ) + aRg.aStart--; + if( pSttTxtNd ) + { + nReplaceDummy = nSttNode - nNdDiff - aRg.aStart.GetIndex(); + if( nReplaceDummy ) + { + SwNodeRange aMvRg( *pSttTxtNd, 0, *pSttTxtNd, 1 ); + SwPosition aSplitPos( *pSttTxtNd ); + BOOL bDoesUndo = pDoc->DoesUndo(); + pDoc->DoUndo( FALSE ); + pDoc->SplitNode( aSplitPos, false ); + rDocNds._MoveNodes( aMvRg, rDocNds, aRg.aStart, TRUE ); + pDoc->DoUndo( bDoesUndo ); + aRg.aStart--; + } + } + } + + if( bFromTableCopy ) + { + if( !pEndTxtNd ) + { + if( pSttTxtNd ) + aRg.aStart++; + else if( !bFullPara && !aRg.aEnd.GetNode().IsCntntNode() ) + aRg.aEnd--; + } + } + else if( pSttTxtNd && ( pEndTxtNd || pSttTxtNd->GetTxt().Len() ) ) + aRg.aStart++; + + // Step 3: Moving into UndoArray... + nNode = rNds.GetEndOfContent().GetIndex(); + rDocNds._MoveNodes( aRg, rNds, SwNodeIndex( rNds.GetEndOfContent() )); + pMvStt = new SwNodeIndex( rNds, nNode ); + nNode = rNds.GetEndOfContent().GetIndex() - nNode; // Differenz merken ! + if( pSttTxtNd && pEndTxtNd ) + { + //Step 4: Moving around sections + nSectDiff = aRg.aEnd.GetIndex() - aRg.aStart.GetIndex(); + // nSect is the number of sections which starts(ends) between start and end node of the + // selection. The "loser" paragraph has to be moved into the section(s) of the + // "winner" paragraph + if( nSectDiff ) + { + if( bJoinNext ) + { + SwNodeRange aMvRg( *pEndTxtNd, 0, *pEndTxtNd, 1 ); + rDocNds._MoveNodes( aMvRg, rDocNds, aRg.aStart, TRUE ); + } + else + { + SwNodeRange aMvRg( *pSttTxtNd, 0, *pSttTxtNd, 1 ); + rDocNds._MoveNodes( aMvRg, rDocNds, aRg.aEnd, TRUE ); + } + } + } + if( nSectDiff || nReplaceDummy ) + lcl_MakeAutoFrms( *pDoc->GetSpzFrmFmts(), + bJoinNext ? pEndTxtNd->GetIndex() : pSttTxtNd->GetIndex() ); + } + else + nNode = 0; // kein Node verschoben -> keine Differenz zum Ende + + // wurden davor noch Nodes geloescht ?? (FootNotes haben ContentNodes!) + if( !pSttTxtNd && !pEndTxtNd ) + { + nNdDiff = nSttNode - rPam.GetPoint()->nNode.GetIndex() - (bFullPara ? 0 : 1); + rPam.Move( fnMoveForward, fnGoNode ); + } + else + { + nNdDiff = nSttNode; + if( nSectDiff && bBackSp ) + nNdDiff += nSectDiff; + nNdDiff -= rPam.GetPoint()->nNode.GetIndex(); + } + + if( !rPam.GetNode()->IsCntntNode() ) + rPam.GetPoint()->nContent.Assign( 0, 0 ); + + // wird die History ueberhaupt benoetigt ?? + if( pHistory && !pHistory->Count() ) + DELETEZ( pHistory ); +} + +BOOL SwUndoDelete::SaveCntnt( const SwPosition* pStt, const SwPosition* pEnd, + SwTxtNode* pSttTxtNd, SwTxtNode* pEndTxtNd ) +{ + ULONG nNdIdx = pStt->nNode.GetIndex(); + // 1 - kopiere den Anfang in den Start-String + if( pSttTxtNd ) + { + BOOL bOneNode = nSttNode == nEndNode; + xub_StrLen nLen = bOneNode ? nEndCntnt - nSttCntnt + : pSttTxtNd->GetTxt().Len() - nSttCntnt; + SwRegHistory aRHst( *pSttTxtNd, pHistory ); + // always save all text atttibutes because of possibly overlapping + // areas of on/off + pHistory->CopyAttr( pSttTxtNd->GetpSwpHints(), nNdIdx, + 0, pSttTxtNd->GetTxt().Len(), true ); + if( !bOneNode && pSttTxtNd->HasSwAttrSet() ) + pHistory->CopyFmtAttr( *pSttTxtNd->GetpSwAttrSet(), nNdIdx ); + + // die Laenge kann sich veraendert haben (!!Felder!!) + nLen = ( bOneNode ? pEnd->nContent.GetIndex() : pSttTxtNd->GetTxt().Len() ) + - pStt->nContent.GetIndex(); + + + // loesche jetzt noch den Text (alle Attribut-Aenderungen kommen in + // die Undo-History + pSttStr = (String*)new String( pSttTxtNd->GetTxt().Copy( nSttCntnt, nLen )); + pSttTxtNd->EraseText( pStt->nContent, nLen ); + if( pSttTxtNd->GetpSwpHints() ) + pSttTxtNd->GetpSwpHints()->DeRegister(); + + // METADATA: store + bool emptied( pSttStr->Len() && !pSttTxtNd->Len() ); + if (!bOneNode || emptied) // merging may overwrite xmlids... + { + m_pMetadataUndoStart = (emptied) + ? pSttTxtNd->CreateUndoForDelete() + : pSttTxtNd->CreateUndo(); + } + + if( bOneNode ) + return FALSE; // keine Nodes mehr verschieben + } + + + // 2 - kopiere das Ende in den End-String + if( pEndTxtNd ) + { + SwIndex aEndIdx( pEndTxtNd ); + nNdIdx = pEnd->nNode.GetIndex(); + SwRegHistory aRHst( *pEndTxtNd, pHistory ); + + // always save all text atttibutes because of possibly overlapping + // areas of on/off + pHistory->CopyAttr( pEndTxtNd->GetpSwpHints(), nNdIdx, 0, + pEndTxtNd->GetTxt().Len(), true ); + + if( pEndTxtNd->HasSwAttrSet() ) + pHistory->CopyFmtAttr( *pEndTxtNd->GetpSwAttrSet(), nNdIdx ); + + + // loesche jetzt noch den Text (alle Attribut-Aenderungen kommen in + // die Undo-History + pEndStr = (String*)new String( pEndTxtNd->GetTxt().Copy( 0, + pEnd->nContent.GetIndex() )); + pEndTxtNd->EraseText( aEndIdx, pEnd->nContent.GetIndex() ); + if( pEndTxtNd->GetpSwpHints() ) + pEndTxtNd->GetpSwpHints()->DeRegister(); + + // METADATA: store + bool emptied( pEndStr->Len() && !pEndTxtNd->Len() ); + + m_pMetadataUndoEnd = (emptied) + ? pEndTxtNd->CreateUndoForDelete() + : pEndTxtNd->CreateUndo(); + } + + // sind es nur zwei Nodes, dann ist schon alles erledigt. + if( ( pSttTxtNd || pEndTxtNd ) && nSttNode + 1 == nEndNode ) + return FALSE; // keine Nodes mehr verschieben + + return TRUE; // verschiebe die dazwischen liegenden Nodes +} + + +BOOL SwUndoDelete::CanGrouping( SwDoc* pDoc, const SwPaM& rDelPam ) +{ + // ist das Undo groesser als 1 Node ? (sprich: Start und EndString) + if( pSttStr ? !pSttStr->Len() || pEndStr : TRUE ) + return FALSE; + + // es kann nur das Loeschen von einzelnen char's zusammengefasst werden + if( nSttNode != nEndNode || ( !bGroup && nSttCntnt+1 != nEndCntnt )) + return FALSE; + + const SwPosition *pStt = rDelPam.Start(), + *pEnd = rDelPam.GetPoint() == pStt + ? rDelPam.GetMark() + : rDelPam.GetPoint(); + + if( pStt->nNode != pEnd->nNode || + pStt->nContent.GetIndex()+1 != pEnd->nContent.GetIndex() || + pEnd->nNode != nSttNode ) + return FALSE; + + // untercheide zwischen BackSpace und Delete. Es muss dann das + // Undo-Array unterschiedlich aufgebaut werden !! + if( pEnd->nContent == nSttCntnt ) + { + if( bGroup && !bBackSp ) return FALSE; + bBackSp = TRUE; + } + else if( pStt->nContent == nSttCntnt ) + { + if( bGroup && bBackSp ) return FALSE; + bBackSp = FALSE; + } + else + return FALSE; + + // sind die beiden Nodes (Nodes-/Undo-Array) ueberhaupt TextNodes? + SwTxtNode * pDelTxtNd = pStt->nNode.GetNode().GetTxtNode(); + if( !pDelTxtNd ) return FALSE; + + xub_StrLen nUChrPos = bBackSp ? 0 : pSttStr->Len()-1; + sal_Unicode cDelChar = pDelTxtNd->GetTxt().GetChar( pStt->nContent.GetIndex() ); + CharClass& rCC = GetAppCharClass(); + if( ( CH_TXTATR_BREAKWORD == cDelChar || CH_TXTATR_INWORD == cDelChar ) || + rCC.isLetterNumeric( String( cDelChar ), 0 ) != + rCC.isLetterNumeric( *pSttStr, nUChrPos ) ) + return FALSE; + + { + SwRedlineSaveDatas* pTmpSav = new SwRedlineSaveDatas; + if( !FillSaveData( rDelPam, *pTmpSav, FALSE )) + delete pTmpSav, pTmpSav = 0; + + BOOL bOk = ( !pRedlSaveData && !pTmpSav ) || + ( pRedlSaveData && pTmpSav && + SwUndo::CanRedlineGroup( *pRedlSaveData, *pTmpSav, bBackSp )); + delete pTmpSav; + if( !bOk ) + return FALSE; + + pDoc->DeleteRedline( rDelPam, false, USHRT_MAX ); + } + + // Ok, die beiden 'Deletes' koennen zusammen gefasst werden, also + // 'verschiebe' das enstprechende Zeichen + if( bBackSp ) + nSttCntnt--; // BackSpace: Zeichen in Array einfuegen !! + else + { + nEndCntnt++; // Delete: Zeichen am Ende anhaengen + nUChrPos++; + } + pSttStr->Insert( cDelChar, nUChrPos ); + pDelTxtNd->EraseText( pStt->nContent, 1 ); + + bGroup = TRUE; + return TRUE; +} + + + +SwUndoDelete::~SwUndoDelete() +{ + delete pSttStr; + delete pEndStr; + if( pMvStt ) // loesche noch den Bereich aus dem UndoNodes Array + { + // Insert speichert den Inhalt in der IconSection + pMvStt->GetNode().GetNodes().Delete( *pMvStt, nNode ); + delete pMvStt; + } + delete pRedlData; + delete pRedlSaveData; +} + +static SwRewriter lcl_RewriterFromHistory(SwHistory & rHistory) +{ + SwRewriter aRewriter; + + bool bDone = false; + + for ( USHORT n = 0; n < rHistory.Count(); n++) + { + String aDescr = rHistory[n]->GetDescription(); + + if (aDescr.Len() > 0) + { + aRewriter.AddRule(UNDO_ARG2, aDescr); + + bDone = true; + break; + } + } + + if (! bDone) + { + aRewriter.AddRule(UNDO_ARG2, SW_RES(STR_FIELD)); + } + + return aRewriter; +} + +SwRewriter SwUndoDelete::GetRewriter() const +{ + SwRewriter aResult; + String * pStr = NULL; + + if (nNode != 0) + { + if (sTableName.Len() > 0) + { + + SwRewriter aRewriter; + aRewriter.AddRule(UNDO_ARG1, SW_RES(STR_START_QUOTE)); + aRewriter.AddRule(UNDO_ARG2, sTableName); + aRewriter.AddRule(UNDO_ARG3, SW_RES(STR_END_QUOTE)); + + String sTmp = aRewriter.Apply(SW_RES(STR_TABLE_NAME)); + aResult.AddRule(UNDO_ARG1, sTmp); + } + else + aResult.AddRule(UNDO_ARG1, String(SW_RES(STR_PARAGRAPHS))); + } + else + { + String aStr; + + if (pSttStr != NULL && pEndStr != NULL && pSttStr->Len() == 0 && + pEndStr->Len() == 0) + { + aStr = SW_RES(STR_PARAGRAPH_UNDO); + } + else + { + if (pSttStr != NULL) + pStr = pSttStr; + else if (pEndStr != NULL) + pStr = pEndStr; + + if (pStr != NULL) + { + aStr = DenoteSpecialCharacters(*pStr); + } + else + { + aStr = UNDO_ARG2; + } + } + + aStr = ShortenString(aStr, nUndoStringLength, String(SW_RES(STR_LDOTS))); + if (pHistory) + { + SwRewriter aRewriter = lcl_RewriterFromHistory(*pHistory); + aStr = aRewriter.Apply(aStr); + } + + aResult.AddRule(UNDO_ARG1, aStr); + } + + return aResult; +} + +// Every object, anchored "AtCntnt" will be reanchored at rPos +void lcl_ReAnchorAtCntntFlyFrames( const SwSpzFrmFmts& rSpzArr, SwPosition &rPos, ULONG nOldIdx ) +{ + if( rSpzArr.Count() ) + { + SwFlyFrmFmt* pFmt; + const SwFmtAnchor* pAnchor; + const SwPosition* pAPos; + for( USHORT n = 0; n < rSpzArr.Count(); ++n ) + { + pFmt = (SwFlyFrmFmt*)rSpzArr[n]; + pAnchor = &pFmt->GetAnchor(); + if (pAnchor->GetAnchorId() == FLY_AT_PARA) + { + pAPos = pAnchor->GetCntntAnchor(); + if( pAPos && nOldIdx == pAPos->nNode.GetIndex() ) + { + SwFmtAnchor aAnch( *pAnchor ); + aAnch.SetAnchor( &rPos ); + pFmt->SetFmtAttr( aAnch ); + } + } + } + } +} + +void SwUndoDelete::Undo( SwUndoIter& rUndoIter ) +{ + SwDoc* pDoc = &rUndoIter.GetDoc(); + BOOL bUndo = pDoc->DoesUndo(); + pDoc->DoUndo( FALSE ); + + ULONG nCalcStt = nSttNode - nNdDiff; + + if( nSectDiff && bBackSp ) + nCalcStt += nSectDiff; + + SwNodeIndex aIdx( pDoc->GetNodes(), nCalcStt ); + SwNode* pInsNd = &aIdx.GetNode(); + + { // Block, damit der SwPosition beim loeschen vom Node + // abgemeldet ist + SwPosition aPos( aIdx ); + if( !bDelFullPara ) + { + if( pInsNd->IsTableNode() ) + { + pInsNd = pDoc->GetNodes().MakeTxtNode( aIdx, + (SwTxtFmtColl*)pDoc->GetDfltTxtFmtColl() ); + aIdx--; + aPos.nNode = aIdx; + aPos.nContent.Assign( pInsNd->GetCntntNode(), nSttCntnt ); + } + else + { + if( pInsNd->IsCntntNode() ) + aPos.nContent.Assign( (SwCntntNode*)pInsNd, nSttCntnt ); + if( !bTblDelLastNd ) + pInsNd = 0; // Node nicht loeschen !! + } + } + else + pInsNd = 0; // Node nicht loeschen !! + + SwNodes* pUNds = (SwNodes*)pDoc->GetUndoNds(); + BOOL bNodeMove = 0 != nNode; + + if( pEndStr ) + { + // alle Attribute verwerfen, wurden alle gespeichert! + SwTxtNode* pTxtNd = aPos.nNode.GetNode().GetTxtNode(); + + if( pTxtNd && pTxtNd->HasSwAttrSet() ) + pTxtNd->ResetAllAttr(); + + if( pTxtNd && pTxtNd->GetpSwpHints() ) + pTxtNd->ClearSwpHintsArr( true ); + + if( pSttStr && !bFromTableCopy ) + { + ULONG nOldIdx = aPos.nNode.GetIndex(); + pDoc->SplitNode( aPos, false ); + // After the split all objects are anchored at the first paragraph, + // but the pHistory of the fly frame formats relies on anchoring at + // the start of the selection => selection backwards needs a correction. + if( bBackSp ) + lcl_ReAnchorAtCntntFlyFrames( *pDoc->GetSpzFrmFmts(), aPos, nOldIdx ); + pTxtNd = aPos.nNode.GetNode().GetTxtNode(); + } + if( pTxtNd ) + { + pTxtNd->InsertText( *pEndStr, aPos.nContent, + IDocumentContentOperations::INS_NOHINTEXPAND ); + // METADATA: restore + pTxtNd->RestoreMetadata(m_pMetadataUndoEnd); + } + } + else if( pSttStr && bNodeMove ) + { + SwTxtNode * pNd = aPos.nNode.GetNode().GetTxtNode(); + if( pNd ) + { + if( nSttCntnt < pNd->GetTxt().Len() ) + { + ULONG nOldIdx = aPos.nNode.GetIndex(); + pDoc->SplitNode( aPos, false ); + if( bBackSp ) + lcl_ReAnchorAtCntntFlyFrames( *pDoc->GetSpzFrmFmts(), aPos, nOldIdx ); + } + else + aPos.nNode++; + } + } + SwNode* pMovedNode = NULL; + if( nSectDiff ) + { + ULONG nMoveIndex = aPos.nNode.GetIndex(); + int nDiff = 0; + if( bJoinNext ) + { + nMoveIndex += nSectDiff + 1; + pMovedNode = &aPos.nNode.GetNode(); + } + else + { + nMoveIndex -= nSectDiff + 1; + ++nDiff; + } + SwNodeIndex aMvIdx( pDoc->GetNodes(), nMoveIndex ); + SwNodeRange aRg( aPos.nNode, 0 - nDiff, aPos.nNode, 1 - nDiff ); + aPos.nNode--; + if( !bJoinNext ) + pMovedNode = &aPos.nNode.GetNode(); + pDoc->GetNodes()._MoveNodes( aRg, pDoc->GetNodes(), aMvIdx, TRUE ); + aPos.nNode++; + } + + if( bNodeMove ) + { + SwNodeRange aRange( *pMvStt, 0, *pMvStt, nNode ); + SwNodeIndex aCopyIndex( aPos.nNode, -1 ); + pUNds->_Copy( aRange, aPos.nNode ); + + if( nReplaceDummy ) + { + ULONG nMoveIndex; + if( bJoinNext ) + { + nMoveIndex = nEndNode - nNdDiff; + aPos.nNode = nMoveIndex + nReplaceDummy; + } + else + { + aPos = SwPosition( aCopyIndex ); + nMoveIndex = aPos.nNode.GetIndex() + nReplaceDummy + 1; + } + SwNodeIndex aMvIdx( pDoc->GetNodes(), nMoveIndex ); + SwNodeRange aRg( aPos.nNode, 0, aPos.nNode, 1 ); + pMovedNode = &aPos.nNode.GetNode(); + pDoc->GetNodes()._MoveNodes( aRg, pDoc->GetNodes(), aMvIdx, TRUE ); + pDoc->GetNodes().Delete( aMvIdx, 1 ); + } + } + + if( pMovedNode ) + lcl_MakeAutoFrms( *pDoc->GetSpzFrmFmts(), pMovedNode->GetIndex() ); + + if( pSttStr ) + { + aPos.nNode = nSttNode - nNdDiff + ( bJoinNext ? 0 : nReplaceDummy ); + SwTxtNode * pTxtNd = aPos.nNode.GetNode().GetTxtNode(); + // wenn mehr als ein Node geloescht wurde, dann wurden auch + // alle "Node"-Attribute gespeichert + + if (pTxtNd != NULL) + { + if( pTxtNd->HasSwAttrSet() && bNodeMove && !pEndStr ) + pTxtNd->ResetAllAttr(); + + if( pTxtNd->GetpSwpHints() ) + pTxtNd->ClearSwpHintsArr( true ); + + // SectionNode-Modus und von oben nach unten selektiert: + // -> im StartNode steht noch der Rest vom Join => loeschen + aPos.nContent.Assign( pTxtNd, nSttCntnt ); + pTxtNd->InsertText( *pSttStr, aPos.nContent, + IDocumentContentOperations::INS_NOHINTEXPAND ); + // METADATA: restore + pTxtNd->RestoreMetadata(m_pMetadataUndoStart); + } + } + + if( pHistory ) + { + pHistory->TmpRollback( pDoc, nSetPos, false ); + if( nSetPos ) // es gab Fussnoten/FlyFrames + { + // gibts ausser diesen noch andere ? + if( nSetPos < pHistory->Count() ) + { + // dann sicher die Attribute anderen Attribute + SwHistory aHstr; + aHstr.Move( 0, pHistory, nSetPos ); + pHistory->Rollback( pDoc ); + pHistory->Move( 0, &aHstr ); + } + else + { + pHistory->Rollback( pDoc ); + DELETEZ( pHistory ); + } + } + } + + if( bResetPgDesc || bResetPgBrk ) + { + USHORT nStt = static_cast<USHORT>( bResetPgDesc ? RES_PAGEDESC : RES_BREAK ); + USHORT nEnd = static_cast<USHORT>( bResetPgBrk ? RES_BREAK : RES_PAGEDESC ); + + SwNode* pNode = pDoc->GetNodes()[ nEndNode + 1 ]; + if( pNode->IsCntntNode() ) + ((SwCntntNode*)pNode)->ResetAttr( nStt, nEnd ); + else if( pNode->IsTableNode() ) + ((SwTableNode*)pNode)->GetTable().GetFrmFmt()->ResetFmtAttr( nStt, nEnd ); + } + } + // den temp. eingefuegten Node noch loeschen !! + if( pInsNd ) + pDoc->GetNodes().Delete( aIdx, 1 ); + if( pRedlSaveData ) + SetSaveData( *pDoc, *pRedlSaveData ); + + pDoc->DoUndo( bUndo ); // Undo wieder einschalten + SetPaM( rUndoIter, TRUE ); +} + +void SwUndoDelete::Redo( SwUndoIter& rUndoIter ) +{ + rUndoIter.SetUpdateAttr( TRUE ); + + SwPaM& rPam = *rUndoIter.pAktPam; + SwDoc& rDoc = *rPam.GetDoc(); + + SetPaM( rPam ); + + if( pRedlSaveData ) + { + bool bSuccess = FillSaveData(rPam, *pRedlSaveData, TRUE); + OSL_ENSURE(bSuccess, + "SwUndoDelete::Redo: used to have redline data, but now none?"); + if (!bSuccess) + { + delete pRedlSaveData, pRedlSaveData = 0; + } + } + + if( !bDelFullPara ) + { + SwUndRng aTmpRng( rPam ); + RemoveIdxFromRange( rPam, FALSE ); + aTmpRng.SetPaM( rPam ); + + if( !bJoinNext ) // Dann Selektion von unten nach oben + rPam.Exchange(); // wieder herstellen! + } + + if( pHistory ) // wurden Attribute gesichert ? + { + pHistory->SetTmpEnd( pHistory->Count() ); + SwHistory aHstr; + aHstr.Move( 0, pHistory ); + + if( bDelFullPara ) + { + ASSERT( rPam.HasMark(), "PaM ohne Mark" ); + DelCntntIndex( *rPam.GetMark(), *rPam.GetPoint(), + DelCntntType(nsDelCntntType::DELCNT_ALL | nsDelCntntType::DELCNT_CHKNOCNTNT) ); + + _DelBookmarks(rPam.GetMark()->nNode, rPam.GetPoint()->nNode); + } + else + DelCntntIndex( *rPam.GetMark(), *rPam.GetPoint() ); + nSetPos = pHistory ? pHistory->Count() : 0; + + pHistory->Move( nSetPos, &aHstr ); + } + else + { + if( bDelFullPara ) + { + ASSERT( rPam.HasMark(), "PaM ohne Mark" ); + DelCntntIndex( *rPam.GetMark(), *rPam.GetPoint(), + DelCntntType(nsDelCntntType::DELCNT_ALL | nsDelCntntType::DELCNT_CHKNOCNTNT) ); + + _DelBookmarks( rPam.GetMark()->nNode, rPam.GetPoint()->nNode ); + } + else + DelCntntIndex( *rPam.GetMark(), *rPam.GetPoint() ); + nSetPos = pHistory ? pHistory->Count() : 0; + } + + if( !pSttStr && !pEndStr ) + { + SwNodeIndex aSttIdx = ( bDelFullPara || bJoinNext ) + ? rPam.GetMark()->nNode + : rPam.GetPoint()->nNode; + SwTableNode* pTblNd = aSttIdx.GetNode().GetTableNode(); + if( pTblNd ) + { + if( bTblDelLastNd ) + { + // dann am Ende wieder einen Node einfuegen + const SwNodeIndex aTmpIdx( *pTblNd->EndOfSectionNode(), 1 ); + rDoc.GetNodes().MakeTxtNode( aTmpIdx, + rDoc.GetTxtCollFromPool( RES_POOLCOLL_STANDARD ) ); + } + + 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, + FALSE, &pItem ) ) + pNextNd->SetAttr( *pItem ); + + if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_BREAK, + FALSE, &pItem ) ) + pNextNd->SetAttr( *pItem ); + } + pTblNd->DelFrms(); + } + + rPam.SetMark(); + rPam.DeleteMark(); + + rDoc.GetNodes().Delete( aSttIdx, nEndNode - nSttNode ); + + // setze den Cursor immer in einen ContentNode !! + if( !rPam.Move( fnMoveBackward, fnGoCntnt ) && + !rPam.Move( fnMoveForward, fnGoCntnt ) ) + rPam.GetPoint()->nContent.Assign( rPam.GetCntntNode(), 0 ); + } + else if( bDelFullPara ) + { + // der Pam wurde am Point( == Ende) um eins erhoeht, um einen + // Bereich fuers Undo zu haben. Der muss jetzt aber wieder entfernt + // werden!!! + rPam.End()->nNode--; + if( rPam.GetPoint()->nNode == rPam.GetMark()->nNode ) + *rPam.GetMark() = *rPam.GetPoint(); + rDoc.DelFullPara( rPam ); + } + else + rDoc.DeleteAndJoin( rPam ); +} + +void SwUndoDelete::Repeat( SwUndoIter& rUndoIter ) +{ + if( UNDO_DELETE == rUndoIter.GetLastUndoId() ) + return; + + SwPaM& rPam = *rUndoIter.pAktPam; + SwDoc& rDoc = *rPam.GetDoc(); + BOOL bGroupUndo = rDoc.DoesGroupUndo(); + rDoc.DoGroupUndo( FALSE ); + if( !rPam.HasMark() ) + { + rPam.SetMark(); + rPam.Move( fnMoveForward, fnGoCntnt ); + } + if( bDelFullPara ) + rDoc.DelFullPara( rPam ); + else + rDoc.DeleteAndJoin( rPam ); + rDoc.DoGroupUndo( bGroupUndo ); + rUndoIter.pLastUndoObj = this; +} + + +void SwUndoDelete::SetTableName(const String & rName) +{ + sTableName = rName; +} diff --git a/sw/source/core/undo/undo.hrc b/sw/source/core/undo/undo.hrc new file mode 100644 index 000000000000..8edccd344adf --- /dev/null +++ b/sw/source/core/undo/undo.hrc @@ -0,0 +1,185 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <rcid.hrc> +// Undo +#define UNDO_BASE (RC_WRTSH_BEGIN + 8) +#define STR_CANT_UNDO (UNDO_BASE + 0) + +// im enun folgen hier START & END fuer die Klammerungen, + +// Id's fuer die Undo/Redo/Repeat faehigen "Funktionen" +#define STR_DELETE_UNDO (UNDO_BASE + 3) +#define STR_INSERT_UNDO (UNDO_BASE + 4) +#define STR_OVR_UNDO (UNDO_BASE + 5) +#define STR_SPLITNODE_UNDO (UNDO_BASE + 6) +#define STR_INSATTR_UNDO (UNDO_BASE + 7) +#define STR_SETFMTCOLL_UNDO (UNDO_BASE + 8) +#define STR_RESET_ATTR_UNDO (UNDO_BASE + 9) +#define STR_INSFMT_ATTR_UNDO (UNDO_BASE +10) +#define STR_INSERT_DOC_UNDO (UNDO_BASE +11) +#define STR_COPY_UNDO (UNDO_BASE +12) +#define STR_INSTABLE_UNDO (UNDO_BASE +13) +#define STR_TABLETOTEXT_UNDO (UNDO_BASE +14) +#define STR_TEXTTOTABLE_UNDO (UNDO_BASE +15) +#define STR_SORT_TXT (UNDO_BASE +16) +#define STR_INSERTFLY (UNDO_BASE +17) +#define STR_TABLEHEADLINE (UNDO_BASE +18) +#define STR_INSERTSECTION (UNDO_BASE +19) +#define STR_OUTLINE_LR (UNDO_BASE +20) +#define STR_OUTLINE_UD (UNDO_BASE +21) +#define STR_INSNUM (UNDO_BASE +22) +#define STR_NUMUP (UNDO_BASE +23) +#define STR_MOVENUM (UNDO_BASE +24) +#define STR_INSERTDRAW (UNDO_BASE +25) +#define STR_NUMORNONUM (UNDO_BASE +26) +#define STR_INC_LEFTMARGIN (UNDO_BASE +27) +#define STR_DEC_LEFTMARGIN (UNDO_BASE +28) +#define STR_INSERTLABEL (UNDO_BASE +29) +#define STR_SETNUMRULESTART (UNDO_BASE +30) +#define STR_CHANGEFTN (UNDO_BASE +31) +#define STR_REDLINE (UNDO_BASE +32) +#define STR_ACCEPT_REDLINE (UNDO_BASE +33) +#define STR_REJECT_REDLINE (UNDO_BASE +34) +#define STR_SPLIT_TABLE (UNDO_BASE +35) +#define STR_DONTEXPAND (UNDO_BASE +36) +#define STR_AUTOCORRECT (UNDO_BASE +37) +#define STR_MERGE_TABLE (UNDO_BASE +38) +#define STR_TRANSLITERATE (UNDO_BASE +39) +#define STR_PASTE_CLIPBOARD_UNDO (UNDO_BASE +40) +#define STR_TYPING_UNDO (UNDO_BASE +41) + +#define STR_REPEAT_DUMMY_6 (UNDO_BASE +42) +#define STR_REPEAT_DUMMY_7 (UNDO_BASE +43) +#define STR_REPEAT_DUMMY_8 (UNDO_BASE +44) +#define STR_REPEAT_DUMMY_9 (UNDO_BASE +45) +// !!!!!! umsetzen !!!!!!!!!!! umsetzen !!!!!!!!!!! umsetzen !!!! +#define CORE_REPEAT_END STR_REPEAT_DUMMY_9// !!!! umsetzen !!! + + +// Id's nur fuer die Undo/Redo faehigen "Funktionen" +#define STR_MOVE_UNDO (CORE_REPEAT_END + 1) +#define STR_INSERT_GLOSSARY (CORE_REPEAT_END + 2) +#define STR_DELBOOKMARK (CORE_REPEAT_END + 3) +#define STR_INSBOOKMARK (CORE_REPEAT_END + 4) +#define STR_SORT_TBL (CORE_REPEAT_END + 5) +#define STR_DELETEFLY (CORE_REPEAT_END + 6) +#define STR_AUTOFORMAT (CORE_REPEAT_END + 7) +#define STR_REPLACE (CORE_REPEAT_END + 8) +#define STR_DELETESECTION (CORE_REPEAT_END + 9) +#define STR_CHANGESECTION (CORE_REPEAT_END +10) +#define STR_CHANGESECTPASSWD (CORE_REPEAT_END +11) +#define STR_CHANGEDEFATTR (CORE_REPEAT_END +12) +#define STR_DELNUM (CORE_REPEAT_END +13) +#define STR_DRAWUNDO (CORE_REPEAT_END +14) +#define STR_DRAWGROUP (CORE_REPEAT_END +15) +#define STR_DRAWUNGROUP (CORE_REPEAT_END +16) +#define STR_DRAWDELETE (CORE_REPEAT_END +17) +#define STR_REREAD (CORE_REPEAT_END +18) +#define STR_DELGRF (CORE_REPEAT_END +19) +#define STR_DELOLE (CORE_REPEAT_END +20) +#define STR_TABLE_ATTR (CORE_REPEAT_END +21) +#define STR_TABLE_AUTOFMT (CORE_REPEAT_END +22) +#define STR_TABLE_INSCOL (CORE_REPEAT_END +23) +#define STR_TABLE_INSROW (CORE_REPEAT_END +24) +#define STR_TABLE_DELBOX (CORE_REPEAT_END +25) +#define STR_TABLE_SPLIT (CORE_REPEAT_END +26) +#define STR_TABLE_MERGE (CORE_REPEAT_END +27) +#define STR_TABLE_NUMFORMAT (CORE_REPEAT_END +28) +#define STR_INSERT_TOX (CORE_REPEAT_END +29) +#define STR_CLEAR_TOX_RANGE (CORE_REPEAT_END +30) +#define STR_TABLE_TBLCPYTBL (CORE_REPEAT_END +31) +#define STR_TABLE_CPYTBL (CORE_REPEAT_END +32) +#define STR_INS_FROM_SHADOWCRSR (CORE_REPEAT_END +33) +#define STR_UNDO_CHAIN (CORE_REPEAT_END +34) +#define STR_UNDO_UNCHAIN (CORE_REPEAT_END +35) +#define STR_UNDO_FTNINFO (CORE_REPEAT_END +36) +#define STR_UNDO_ENDNOTEINFO (CORE_REPEAT_END +37) +#define STR_UNDO_COMPAREDOC (CORE_REPEAT_END +38) +#define STR_UNDO_SETFLYFRMFMT (CORE_REPEAT_END +39) +#define STR_UNDO_SETRUBYATTR (CORE_REPEAT_END +40) +// #102505# +#define STR_UNDO_TMPAUTOCORR (CORE_REPEAT_END +41) + +#define STR_TOXCHANGE (CORE_REPEAT_END +42) +#define STR_UNDO_PAGEDESC_CREATE (CORE_REPEAT_END +43) +#define STR_UNDO_PAGEDESC (CORE_REPEAT_END +44) +#define STR_UNDO_PAGEDESC_DELETE (CORE_REPEAT_END +45) +#define STR_UNDO_HEADER_FOOTER (CORE_REPEAT_END +46) // #i7983# +#define STR_UNDO_FIELD (CORE_REPEAT_END +47) // #111840# +#define STR_UNDO_TXTFMTCOL_CREATE (CORE_REPEAT_END +48) +#define STR_UNDO_TXTFMTCOL_DELETE (CORE_REPEAT_END +49) +#define STR_UNDO_TXTFMTCOL_RENAME (CORE_REPEAT_END +50) +#define STR_UNDO_CHARFMT_CREATE (CORE_REPEAT_END +51) +#define STR_UNDO_CHARFMT_DELETE (CORE_REPEAT_END +52) +#define STR_UNDO_CHARFMT_RENAME (CORE_REPEAT_END +53) +#define STR_UNDO_FRMFMT_CREATE (CORE_REPEAT_END +54) +#define STR_UNDO_FRMFMT_DELETE (CORE_REPEAT_END +55) +#define STR_UNDO_FRMFMT_RENAME (CORE_REPEAT_END +56) +#define STR_UNDO_NUMRULE_CREATE (CORE_REPEAT_END +57) +#define STR_UNDO_NUMRULE_DELETE (CORE_REPEAT_END +58) +#define STR_UNDO_NUMRULE_RENAME (CORE_REPEAT_END +59) +#define STR_UNDO_BOOKMARK_RENAME (CORE_REPEAT_END +60) +#define STR_UNDO_INDEX_ENTRY_INSERT (CORE_REPEAT_END +61) +#define STR_UNDO_INDEX_ENTRY_DELETE (CORE_REPEAT_END +62) +#define STR_UNDO_COL_DELETE (CORE_REPEAT_END +63) +#define STR_UNDO_ROW_DELETE (CORE_REPEAT_END +64) +#define STR_UNDO_PAGEDESC_RENAME (CORE_REPEAT_END +65) +#define STR_NUMDOWN (CORE_REPEAT_END +66) +#define STR_UNDO_FLYFRMFMT_TITLE (CORE_REPEAT_END +67) +#define STR_UNDO_FLYFRMFMT_DESCRITPTION (CORE_REPEAT_END +68) + +// !!!!!! umsetzen !!!!!!!!!!! umsetzen !!!!!!!!!!! umsetzen !!!! +#define CORE_UNDO_END STR_UNDO_FLYFRMFMT_DESCRITPTION// !!!! umsetzen !!! + +// UI-Undo Klammerungen +#define UI_UNDO_BEGIN (CORE_UNDO_END + 1) +#define STR_REPLACE_UNDO (UI_UNDO_BEGIN) +#define STR_INSERT_PAGE_BREAK_UNDO (UI_UNDO_BEGIN + 1) +#define STR_INSERT_COLUMN_BREAK_UNDO (UI_UNDO_BEGIN + 2) +#define STR_PLAY_MACRO_UNDO (UI_UNDO_BEGIN + 3) +#define STR_INSERT_ENV_UNDO (UI_UNDO_BEGIN + 4) +#define STR_DRAG_AND_COPY (UI_UNDO_BEGIN + 5) +#define STR_DRAG_AND_MOVE (UI_UNDO_BEGIN + 6) +#define STR_INSERT_RULER (UI_UNDO_BEGIN + 7) +#define STR_INSERT_CHART (UI_UNDO_BEGIN + 8) +#define STR_INSERT_FOOTNOTE (UI_UNDO_BEGIN + 9) +#define STR_INSERT_URLBTN (UI_UNDO_BEGIN + 10) +#define STR_INSERT_URLTXT (UI_UNDO_BEGIN + 11) +#define STR_DELETE_INVISIBLECNTNT (UI_UNDO_BEGIN + 12) +#define STR_REPLACE_STYLE (UI_UNDO_BEGIN + 13) +#define UI_UNDO_END STR_REPLACE_STYLE + +#define UNDO_MORE_STRINGS_BEGIN (UI_UNDO_END + 1) +#define STR_OCCURRENCES_OF (UNDO_MORE_STRINGS_BEGIN) +#define STR_UNDO_TABS (UNDO_MORE_STRINGS_BEGIN + 1) +#define STR_UNDO_NLS (UNDO_MORE_STRINGS_BEGIN + 2) +#define STR_UNDO_PAGEBREAKS (UNDO_MORE_STRINGS_BEGIN + 3) +#define STR_UNDO_COLBRKS (UNDO_MORE_STRINGS_BEGIN + 4) +#define STR_UNDO_SPECIALCHAR (UNDO_MORE_STRINGS_BEGIN + 5) + +#define UNDO_ACT_END STR_UNDO_TABLE_NAME diff --git a/sw/source/core/undo/undo.src b/sw/source/core/undo/undo.src new file mode 100644 index 000000000000..1035d8cb0d0f --- /dev/null +++ b/sw/source/core/undo/undo.src @@ -0,0 +1,657 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <comcore.hrc> +#include <undo.hrc> + + // Undo +String STR_CANT_UNDO +{ + Text [ en-US ] = "not possible" ; +}; +String STR_DELETE_UNDO +{ + Text [ en-US ] = "Delete $1" ; +}; +String STR_INSERT_UNDO +{ + Text [ en-US ] = "Insert $1" ; +}; +String STR_OVR_UNDO +{ + Text [ en-US ] = "Overwrite: $1" ; +}; +String STR_SPLITNODE_UNDO +{ + Text [ en-US ] = "New Paragraph" ; +}; +String STR_MOVE_UNDO +{ + Text [ en-US ] = "Move" ; +}; +String STR_INSATTR_UNDO +{ + Text [ en-US ] = "Apply attributes" ; +}; +String STR_SETFMTCOLL_UNDO +{ + Text [ en-US ] = "Apply Styles: $1" ; +}; +String STR_RESET_ATTR_UNDO +{ + Text [ en-US ] = "Reset attributes" ; +}; +String STR_INSFMT_ATTR_UNDO +{ + Text [ en-US ] = "Change style: $1" ; +}; +String STR_INSERT_DOC_UNDO +{ + Text [ en-US ] = "Insert file" ; +}; +String STR_INSERT_GLOSSARY +{ + Text [ en-US ] = "Insert AutoText" ; +}; +String STR_DELBOOKMARK +{ + Text [ en-US ] = "Delete bookmark: $1" ; +}; +String STR_INSBOOKMARK +{ + Text [ en-US ] = "Insert bookmark: $1" ; +}; +String STR_SORT_TBL +{ + Text [ en-US ] = "Sort table" ; +}; +String STR_SORT_TXT +{ + Text [ en-US ] = "Sort text" ; +}; +String STR_INSTABLE_UNDO +{ + Text [ en-US ] = "Insert table: $1$2$3" ; +}; +String STR_TEXTTOTABLE_UNDO +{ + Text [ en-US ] = "Convert text -> table" ; +}; +String STR_TABLETOTEXT_UNDO +{ + Text [ en-US ] = "Convert table -> text" ; +}; +String STR_COPY_UNDO +{ + Text [ en-US ] = "Copy: $1" ; +}; +String STR_REPLACE_UNDO +{ + Text [ en-US ] = "Replace $1 $2 $3" ; +}; +String STR_INSERT_PAGE_BREAK_UNDO +{ + Text [ en-US ] = "Insert page break" ; +}; +String STR_INSERT_COLUMN_BREAK_UNDO +{ + Text [ en-US ] = "Insert column break" ; +}; +String STR_PLAY_MACRO_UNDO +{ + Text [ en-US ] = "Run macro" ; +}; +String STR_INSERT_ENV_UNDO +{ + Text [ en-US ] = "Insert Envelope" ; +}; +String STR_DRAG_AND_COPY +{ + Text [ en-US ] = "Copy: $1" ; +}; +String STR_DRAG_AND_MOVE +{ + Text [ en-US ] = "Move: $1" ; +}; +String STR_INSERT_RULER +{ + Text [ en-US ] = "Insert horizontal ruler" ; +}; +String STR_INSERT_CHART +{ + Text [ en-US ] = "Insert %PRODUCTNAME Chart" ; +}; +String STR_INSERTFLY +{ + Text [ en-US ] = "Insert frame" ; +}; +String STR_DELETEFLY +{ + Text [ en-US ] = "Delete frame" ; +}; +String STR_AUTOFORMAT +{ + Text [ en-US ] = "AutoFormat" ; +}; +String STR_TABLEHEADLINE +{ + Text [ en-US ] = "Table heading" ; +}; +String STR_REPLACE +{ + Text [ en-US ] = "Replace: $1 $2 $3" ; +}; +String STR_INSERTSECTION +{ + Text [ en-US ] = "Insert section" ; +}; +String STR_DELETESECTION +{ + Text [ en-US ] = "Delete section" ; +}; +String STR_CHANGESECTION +{ + Text [ en-US ] = "Modify section" ; +}; +String STR_CHANGESECTPASSWD +{ + Text [ en-US ] = "Change password protection" ; +}; +String STR_CHANGEDEFATTR +{ + Text [ en-US ] = "Modify default values" ; +}; +String STR_REPLACE_STYLE +{ + Text [ en-US ] = "Replace style: $1 $2 $3" ; +}; +String STR_OUTLINE_LR +{ + Text [ en-US ] = "Promote/demote outline" ; +}; +String STR_OUTLINE_UD +{ + Text [ en-US ] = "Move outline" ; +}; +String STR_INSNUM +{ + Text [ en-US ] = "Insert numbering" ; +}; +String STR_NUMUP +{ + Text [ en-US ] = "Promote level" ; +}; +String STR_NUMDOWN +{ + Text [ en-US ] = "Demote level" ; +}; +String STR_MOVENUM +{ + Text [ en-US ] = "Move paragraphs" ; +}; +String STR_INSERTDRAW +{ + Text [ en-US ] = "Insert drawing object: $1" ; +}; +String STR_NUMORNONUM +{ + Text [ en-US ] = "Number On/Off" ; +}; +String STR_INC_LEFTMARGIN +{ + Text [ en-US ] = "Increase Indent" ; +}; +String STR_DEC_LEFTMARGIN +{ + Text [ en-US ] = "Decrease indent" ; +}; +String STR_INSERTLABEL +{ + Text [ en-US ] = "Insert caption: $1" ; +}; +String STR_SETNUMRULESTART +{ + Text [ en-US ] = "Restart numbering" ; +}; +String STR_CHANGEFTN +{ + Text [ en-US ] = "Modify footnote" ; +}; +String STR_REDLINE +{ + /* !! sollte NIE gebraucht/uebersetzt werden !! */ +}; +String STR_ACCEPT_REDLINE +{ + Text [ en-US ] = "Accept change: $1" ; +}; +String STR_REJECT_REDLINE +{ + Text [ en-US ] = "Reject change: $1" ; +}; +String STR_SPLIT_TABLE +{ + Text [ en-US ] = "Split Table" ; +}; +String STR_DONTEXPAND +{ + Text [ en-US ] = "Stop attribute" ; +}; +String STR_AUTOCORRECT +{ + Text [ en-US ] = "AutoCorrect" ; +}; +String STR_MERGE_TABLE +{ + Text [ en-US ] = "Merge table"; +}; + +String STR_TRANSLITERATE +{ + Text [ en-US ] = "Case/Characters"; +}; + +String STR_DELNUM +{ + Text [ en-US ] = "Delete numbering" ; +}; +String STR_DRAWUNDO +{ + Text [ en-US ] = "Drawing objects: $1" ; +}; +String STR_DRAWGROUP +{ + Text [ en-US ] = "Group draw objects" ; +}; +String STR_DRAWUNGROUP +{ + Text [ en-US ] = "Ungroup drawing objects" ; +}; +String STR_DRAWDELETE +{ + Text [ en-US ] = "Delete drawing objects" ; +}; +String STR_REREAD +{ + Text [ en-US ] = "Replace graphics" ; +}; +String STR_DELGRF +{ + Text [ en-US ] = "Delete graphics" ; +}; +String STR_DELOLE +{ + Text [ en-US ] = "Delete object" ; +}; +String STR_TABLE_ATTR +{ + Text [ en-US ] = "Apply table attributes" ; +}; +String STR_TABLE_AUTOFMT +{ + Text [ en-US ] = "AutoFormat Table" ; +}; +String STR_TABLE_INSCOL +{ + Text [ en-US ] = "Insert Column" ; +}; +String STR_TABLE_INSROW +{ + Text [ en-US ] = "Insert Row" ; +}; +String STR_TABLE_DELBOX +{ + Text [ en-US ] = "Delete row/column" ; +}; +String STR_UNDO_COL_DELETE +{ + Text [ en-US ] = "Delete column" ; +}; +String STR_UNDO_ROW_DELETE +{ + Text [ en-US ] = "Delete row" ; +}; +String STR_TABLE_SPLIT +{ + Text [ en-US ] = "Split Cells" ; +}; +String STR_TABLE_MERGE +{ + Text [ en-US ] = "Merge Cells" ; +}; +String STR_TABLE_NUMFORMAT +{ + Text [ en-US ] = "Format cell" ; +}; +String STR_INSERT_TOX +{ + Text [ en-US ] = "Insert index/table" ; +}; +String STR_CLEAR_TOX_RANGE +{ + Text [ en-US ] = "Remove index/table" ; +}; +String STR_TABLE_TBLCPYTBL{ + Text [ en-US ] = "Copy table" ; +}; +String STR_TABLE_CPYTBL +{ + Text [ en-US ] = "Copy table" ; +}; +String STR_INS_FROM_SHADOWCRSR +{ + Text [ en-US ] = "Set cursor" ; +}; +String STR_UNDO_CHAIN +{ + Text [ en-US ] = "Link text frames" ; +}; +String STR_UNDO_UNCHAIN +{ + Text [ en-US ] = "Unlink text frames" ; +}; +String STR_UNDO_FTNINFO +{ + Text [ en-US ] = "Modify footnote options" ; +}; +String STR_UNDO_ENDNOTEINFO +{ + Text [ en-US ] = "Modify endnote settings" ; +}; +String STR_UNDO_COMPAREDOC +{ + Text [ en-US ] = "Compare Document" ; +}; +String STR_UNDO_SETFLYFRMFMT +{ + Text [ en-US ] = "Apply frame style: $1" ; +}; +String STR_UNDO_SETRUBYATTR +{ + Text [ en-US ] = "Ruby Setting"; +}; +#102505# +String STR_UNDO_TMPAUTOCORR +{ + Text [ en-US ] = "AutoCorrect" ; +}; +String STR_INSERT_FOOTNOTE +{ + Text [ en-US ] = "Insert footnote" ; +}; +String STR_INSERT_URLBTN +{ + Text [ en-US ] = "insert URL button"; +}; +String STR_INSERT_URLTXT +{ + Text [ en-US ] = "Insert Hyperlink"; +}; +String STR_DELETE_INVISIBLECNTNT +{ + Text [ en-US ] = "remove invisible content"; +}; +String STR_TOXCHANGE +{ + Text [ en-US ] = "Table/index changed"; +}; +String STR_START_QUOTE +{ + Text [ en-US ] = "'"; +}; +String STR_END_QUOTE +{ + Text [ en-US ] = "'"; +}; +String STR_LDOTS +{ + Text [ en-US ] = "..."; +}; +String STR_CLIPBOARD +{ + Text [ en-US ] = "clipboard"; +}; +String STR_MULTISEL +{ + Text [ en-US ] = "multiple selection"; +}; +String STR_TYPING_UNDO +{ + Text [ en-US ] = "Typing: $1"; +}; +String STR_PASTE_CLIPBOARD_UNDO +{ + Text [ en-US ] = "Paste clipboard"; +}; +String STR_YIELDS +{ + Text [ en-US ] = "->"; +}; +String STR_OCCURRENCES_OF +{ + Text [ en-US ] = "occurrences of"; +}; +String STR_UNDO_TABS +{ + Text [ en-US ] = "$1 tab(s)"; +}; +String STR_UNDO_NLS +{ + Text[ en-US ] = "$1 line break(s)"; +}; +String STR_UNDO_PAGEBREAKS +{ + Text[ en-US ] = "page break"; +}; +String STR_UNDO_COLBRKS +{ + Text[ en-US ] = "column break"; +}; +String STR_REDLINE_INSERT +{ + Text [ en-US ] = "Insert $1"; +}; +String STR_REDLINE_DELETE +{ + Text [ en-US ] = "Delete $1"; +}; +String STR_REDLINE_FORMAT +{ + Text [ en-US ] = "Attributes changed"; +}; +String STR_REDLINE_TABLE +{ + Text [ en-US ] = "Table changed"; +}; +String STR_REDLINE_FMTCOLL +{ + Text [ en-US ] = "Style changed"; +}; +String STR_REDLINE_MULTIPLE +{ + Text [ en-US ] = "multiple changes"; +}; +String STR_N_REDLINES +{ + Text [ en-US ] = "$1 changes"; +}; +String STR_UNDO_PAGEDESC +{ + Text [ en-US ] = "Change page style: $1"; +}; +String STR_UNDO_PAGEDESC_CREATE +{ + Text [ en-US ] = "Create page style: $1"; +}; +String STR_UNDO_PAGEDESC_DELETE +{ + Text [ en-US ] = "Delete page style: $1"; +}; +String STR_UNDO_PAGEDESC_RENAME +{ + Text [ en-US ] = "Rename page style: $1 $2 $3"; +}; +String STR_UNDO_HEADER_FOOTER +{ + Text [ en-US ] = "Header/footer changed"; +}; +String STR_UNDO_FIELD +{ + Text [ en-US ] = "Field changed"; +}; +String STR_UNDO_TXTFMTCOL_CREATE +{ + Text [ en-US ] = "Create paragraph style: $1"; +}; +String STR_UNDO_TXTFMTCOL_DELETE +{ + Text [ en-US ] = "Delete paragraph style: $1"; +}; +String STR_UNDO_TXTFMTCOL_RENAME +{ + Text [ en-US ] = "Rename paragraph style: $1 $2 $3"; +}; +String STR_UNDO_CHARFMT_CREATE +{ + Text [ en-US ] = "Create character style: $1"; +}; +String STR_UNDO_CHARFMT_DELETE +{ + Text [ en-US ] = "Delete character style: $1"; +}; +String STR_UNDO_CHARFMT_RENAME +{ + Text [ en-US ] = "Rename character style: $1 $2 $3"; +}; +String STR_UNDO_FRMFMT_CREATE +{ + Text [ en-US ] = "Create frame style: $1"; +}; +String STR_UNDO_FRMFMT_DELETE +{ + Text [ en-US ] = "Delete frame style: $1"; +}; +String STR_UNDO_FRMFMT_RENAME +{ + Text [ en-US ] = "Rename frame style: $1 $2 $3"; +}; +String STR_UNDO_NUMRULE_CREATE +{ + Text [ en-US ] = "Create numbering style: $1"; +}; +String STR_UNDO_NUMRULE_DELETE +{ + Text [ en-US ] = "Delete numbering style: $1"; +}; +String STR_UNDO_NUMRULE_RENAME +{ + Text [ en-US ] = "Rename numbering style: $1 $2 $3"; +}; +String STR_UNDO_BOOKMARK_RENAME +{ + Text[ en-US ] = "Rename bookmark: $1 $2 $3"; +}; +String STR_UNDO_INDEX_ENTRY_INSERT +{ + Text[ en-US ] = "Insert index entry"; +}; +String STR_UNDO_INDEX_ENTRY_DELETE +{ + Text[ en-US ] = "Delete index entry"; +}; +String STR_FIELD +{ + Text [ en-US ] = "field"; +}; +String STR_PARAGRAPHS +{ + Text [ en-US ] = "Paragraphs" ; +}; +String STR_FRAME +{ + Text [ en-US ] = "frame"; +}; +String STR_OLE +{ + Text [ en-US ] = "OLE-object"; +}; +String STR_MATH_FORMULA +{ + Text [ en-US ] = "formula"; +}; +String STR_CHART +{ + Text [ en-US ] = "chart"; +}; +String STR_NOTE +{ + Text [ en-US ] = "comment"; +}; +String STR_REFERENCE +{ + Text [ en-US ] = "cross-reference"; +}; +String STR_SCRIPT +{ + Text [ en-US ] = "script"; +}; +String STR_AUTHORITY_ENTRY +{ + Text[ en-US ] = "bibliography entry"; +}; +String STR_SPECIALCHAR +{ + Text[ en-US ] = "special character"; +}; +String STR_FOOTNOTE +{ + Text[ en-US ] = "footnote"; +}; +String STR_GRAPHIC +{ + Text[ en-US ] = "picture"; +}; +String STR_DRAWING_OBJECTS +{ + Text[ en-US ] = "drawing object(s)"; +}; +String STR_TABLE_NAME +{ + Text[ en-US ] = "table: $1$2$3"; +}; +String STR_PARAGRAPH_UNDO +{ + Text[ en-US ] = "paragraph"; +}; +String STR_UNDO_FLYFRMFMT_TITLE +{ + Text[ en-US ] = "Change object title of $1"; +}; +String STR_UNDO_FLYFRMFMT_DESCRITPTION +{ + Text[ en-US ] = "Change object description of $1"; +}; diff --git a/sw/source/core/undo/undobj.cxx b/sw/source/core/undo/undobj.cxx new file mode 100644 index 000000000000..1a71a705b2fb --- /dev/null +++ b/sw/source/core/undo/undobj.cxx @@ -0,0 +1,1404 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <txtftn.hxx> +#include <fmtanchr.hxx> +#include <ftnidx.hxx> +#include <frmfmt.hxx> +#include <doc.hxx> +#include <docary.hxx> +#include <swundo.hxx> // fuer die UndoIds +#include <pam.hxx> +#include <ndtxt.hxx> +#include <undobj.hxx> +#include <rolbck.hxx> +#include <ndnotxt.hxx> +#include <IMark.hxx> +#include <mvsave.hxx> +#include <redline.hxx> +#include <crossrefbookmark.hxx> +#ifndef _UNDO_HRC +#include <undo.hrc> +#endif +#ifndef _COMCORE_HRC +#include <comcore.hrc> +#endif +#include <docsh.hxx> + +class SwRedlineSaveData : public SwUndRng, public SwRedlineData, + private SwUndoSaveSection +{ +public: + SwRedlineSaveData( SwComparePosition eCmpPos, + const SwPosition& rSttPos, const SwPosition& rEndPos, + SwRedline& rRedl, BOOL bCopyNext ); + ~SwRedlineSaveData(); + void RedlineToDoc( SwPaM& rPam ); + SwNodeIndex* GetMvSttIdx() const + { return SwUndoSaveSection::GetMvSttIdx(); } + +#ifdef DBG_UTIL + USHORT nRedlineCount; +#endif +}; + +SV_IMPL_PTRARR( SwUndos, SwUndo*) +SV_IMPL_PTRARR( SwRedlineSaveDatas, SwRedlineSaveDataPtr ) + +SwUndoIter::SwUndoIter( SwPaM* pPam, SwUndoId nId ) +{ + nUndoId = nId; + bWeiter = nId ? TRUE : FALSE; + bUpdateAttr = FALSE; + pAktPam = pPam; + nEndCnt = 0; + pSelFmt = 0; + pMarkList = 0; +} +inline SwDoc& SwUndoIter::GetDoc() const { return *pAktPam->GetDoc(); } + +//------------------------------------------------------------ + +// Diese Klasse speichert den Pam als USHORT's und kann diese wieder zu + +// einem PaM zusammensetzen +SwUndRng::SwUndRng() + : nSttNode( 0 ), nEndNode( 0 ), nSttCntnt( 0 ), nEndCntnt( 0 ) +{ +} + +SwUndRng::SwUndRng( const SwPaM& rPam ) +{ + SetValues( rPam ); +} + +void SwUndRng::SetValues( const SwPaM& rPam ) +{ + const SwPosition *pStt = rPam.Start(); + if( rPam.HasMark() ) + { + const SwPosition *pEnd = rPam.GetPoint() == pStt + ? rPam.GetMark() + : rPam.GetPoint(); + nEndNode = pEnd->nNode.GetIndex(); + nEndCntnt = pEnd->nContent.GetIndex(); + } + else + // keine Selektion !! + nEndNode = 0, nEndCntnt = STRING_MAXLEN; + + nSttNode = pStt->nNode.GetIndex(); + nSttCntnt = pStt->nContent.GetIndex(); +} + +void SwUndRng::SetPaM( SwPaM & rPam, BOOL bCorrToCntnt ) const +{ + rPam.DeleteMark(); + rPam.GetPoint()->nNode = nSttNode; + SwNode* pNd = rPam.GetNode(); + if( pNd->IsCntntNode() ) + rPam.GetPoint()->nContent.Assign( pNd->GetCntntNode(), nSttCntnt ); + else if( bCorrToCntnt ) + rPam.Move( fnMoveForward, fnGoCntnt ); + else + rPam.GetPoint()->nContent.Assign( 0, 0 ); + + if( !nEndNode && STRING_MAXLEN == nEndCntnt ) // keine Selection + return ; + + rPam.SetMark(); + if( nSttNode == nEndNode && nSttCntnt == nEndCntnt ) + return; // nichts mehr zu tun + + rPam.GetPoint()->nNode = nEndNode; + if( (pNd = rPam.GetNode())->IsCntntNode() ) + rPam.GetPoint()->nContent.Assign( pNd->GetCntntNode(), nEndCntnt ); + else if( bCorrToCntnt ) + rPam.Move( fnMoveBackward, fnGoCntnt ); + else + rPam.GetPoint()->nContent.Assign( 0, 0 ); +} + +void SwUndRng::SetPaM( SwUndoIter& rIter, BOOL bCorrToCntnt ) const +{ + if( rIter.pAktPam ) + SetPaM( *rIter.pAktPam, bCorrToCntnt ); +} + +//------------------------------------------------------------ + + +void SwUndo::RemoveIdxFromSection( SwDoc& rDoc, ULONG nSttIdx, + ULONG* pEndIdx ) +{ + SwNodeIndex aIdx( rDoc.GetNodes(), nSttIdx ); + SwNodeIndex aEndIdx( rDoc.GetNodes(), pEndIdx ? *pEndIdx + : aIdx.GetNode().EndOfSectionIndex() ); + SwPosition aPos( rDoc.GetNodes().GetEndOfPostIts() ); + rDoc.CorrAbs( aIdx, aEndIdx, aPos, TRUE ); +} + +void SwUndo::RemoveIdxFromRange( SwPaM& rPam, BOOL bMoveNext ) +{ + const SwPosition* pEnd = rPam.End(); + if( bMoveNext ) + { + if( pEnd != rPam.GetPoint() ) + rPam.Exchange(); + + SwNodeIndex aStt( rPam.GetMark()->nNode ); + SwNodeIndex aEnd( rPam.GetPoint()->nNode ); + + if( !rPam.Move( fnMoveForward ) ) + { + rPam.Exchange(); + if( !rPam.Move( fnMoveBackward ) ) + { + rPam.GetPoint()->nNode = rPam.GetDoc()->GetNodes().GetEndOfPostIts(); + rPam.GetPoint()->nContent.Assign( 0, 0 ); + } + } + + rPam.GetDoc()->CorrAbs( aStt, aEnd, *rPam.GetPoint(), TRUE ); + } + else + rPam.GetDoc()->CorrAbs( rPam, *pEnd, TRUE ); +} + +void SwUndo::RemoveIdxRel( ULONG nIdx, const SwPosition& rPos ) +{ + // nur die Crsr verschieben; die Bookmarks/TOXMarks/.. werden vom + // entsp. JoinNext/JoinPrev erledigt! + SwNodeIndex aIdx( rPos.nNode.GetNode().GetNodes(), nIdx ); + ::PaMCorrRel( aIdx, rPos ); +} + +SwUndo::SwUndo( SwUndoId nI ) + : nId(nI), nOrigRedlineMode(nsRedlineMode_t::REDLINE_NONE), + bCacheComment(true), pComment(NULL) +{ +} + +bool SwUndo::IsDelBox() const +{ + return GetId() == UNDO_COL_DELETE || GetId() == UNDO_ROW_DELETE || + GetId() == UNDO_TABLE_DELBOX; +} + +SwUndo::~SwUndo() +{ + delete pComment; +} + +void SwUndo::Repeat( SwUndoIter& rIter ) +{ + rIter.pLastUndoObj = this; +} + +String SwUndo::GetComment() const +{ + String aResult; + + if (bCacheComment) + { + if (! pComment) + { + pComment = new String(SW_RES(UNDO_BASE + nId)); + + SwRewriter aRewriter = GetRewriter(); + + *pComment = aRewriter.Apply(*pComment); + } + + aResult = *pComment; + } + else + { + aResult = String(SW_RES(UNDO_BASE + nId)); + + SwRewriter aRewriter = GetRewriter(); + + aResult = aRewriter.Apply(aResult); + } + + return aResult; +} + +SwUndoId SwUndo::GetEffectiveId() const +{ + return GetId(); +} + +SwRewriter SwUndo::GetRewriter() const +{ + SwRewriter aResult; + + return aResult; +} + +//------------------------------------------------------------ + +SwUndoSaveCntnt::SwUndoSaveCntnt() + : pHistory( 0 ) +{} + +SwUndoSaveCntnt::~SwUndoSaveCntnt() +{ + delete pHistory; +} + + // wird fuer das Loeschen von Inhalt benoetigt. Fuer das ReDo werden + // Inhalte in das UndoNodesArray verschoben. Diese Methoden fuegen + // am Ende eines TextNodes fuer die Attribute einen Trenner ein. + // Dadurch werden die Attribute nicht expandiert. + // MoveTo.. verschiebt aus dem NodesArray in das UndoNodesArray + // MoveFrom.. verschiebt aus dem UndoNodesArray in das NodesArray + + // 2.8.93: ist pEndNdIdx angebenen, wird vom Undo/Redo -Ins/DelFly + // aufgerufen. Dann soll die gesamte Section verschoben werden. + +void SwUndoSaveCntnt::MoveToUndoNds( SwPaM& rPaM, SwNodeIndex* pNodeIdx, + SwIndex* pCntIdx, ULONG* pEndNdIdx, xub_StrLen* pEndCntIdx ) +{ + SwDoc& rDoc = *rPaM.GetDoc(); + BOOL bUndo = rDoc.DoesUndo(); + rDoc.DoUndo( FALSE ); + + SwNoTxtNode* pCpyNd = rPaM.GetNode()->GetNoTxtNode(); + + // jetzt kommt das eigentliche Loeschen(Verschieben) + SwNodes& rNds = (SwNodes&)*rDoc.GetUndoNds(); + SwPosition aPos( pEndNdIdx ? rNds.GetEndOfPostIts() + : rNds.GetEndOfExtras() ); + aPos.nNode--; + + const SwPosition* pStt = rPaM.Start(), *pEnd = rPaM.End(); + + if( pCpyNd || pEndNdIdx || !aPos.nNode.GetNode().GetCntntNode() || + (!pStt->nContent.GetIndex() && (pStt->nNode != pEnd->nNode || + (!pStt->nNode.GetNode().GetCntntNode() || + pStt->nNode.GetNode().GetCntntNode()->Len() == + pEnd->nContent.GetIndex() ) ) ) ) + { + aPos.nNode++; + aPos.nContent = 0; + } + else + aPos.nNode.GetNode().GetCntntNode()->MakeEndIndex( &aPos.nContent ); + + // als USHORT merken; die Indizies verschieben sich !! + ULONG nTmpMvNode = aPos.nNode.GetIndex(); + xub_StrLen nTmpMvCntnt = aPos.nContent.GetIndex(); + + if( pCpyNd || pEndNdIdx ) + { + SwNodeRange aRg( pStt->nNode, 0, pEnd->nNode, 1 ); + rDoc.GetNodes()._MoveNodes( aRg, rNds, aPos.nNode, FALSE ); + aPos.nContent = 0; + aPos.nNode--; + } + else + { + rDoc.GetNodes().MoveRange( rPaM, aPos, rNds ); + + SwTxtNode* pTxtNd = aPos.nNode.GetNode().GetTxtNode(); + if( pTxtNd ) // fuege einen Trenner fuer die Attribute ein ! + { + // weil aber beim Insert die Attribute angefasst/sprich + // aus dem Array geloescht und wieder eingefuegt werden, koennen + // dadurch Attribute verschwinden (z.B "Fett aus" von 10-20, + // "Fett an" von 12-15, dann wird durchs Insert/Delete das + // "Fett an" geloescht !! Ist hier aber nicht erwuenscht !!) + // DARUM: nicht die Hints anfassen, direct den String manipulieren + + String& rStr = (String&)pTxtNd->GetTxt(); + // Zur Sicherheit lieber nur wenn wirklich am Ende steht + if( rStr.Len() == aPos.nContent.GetIndex() ) + { + rStr.Insert( ' ' ); + ++aPos.nContent; + } + else + { + pTxtNd->InsertText( sal_Unicode(' '), aPos.nContent, + IDocumentContentOperations::INS_NOHINTEXPAND ); + } + } + } + if( pEndNdIdx ) + *pEndNdIdx = aPos.nNode.GetIndex(); + if( pEndCntIdx ) + *pEndCntIdx = aPos.nContent.GetIndex(); + + // alte Position + aPos.nNode = nTmpMvNode; + if( pNodeIdx ) + *pNodeIdx = aPos.nNode; + + if( pCntIdx ) + { + SwCntntNode* pCNd = aPos.nNode.GetNode().GetCntntNode(); + if( pCNd ) + pCntIdx->Assign( pCNd, nTmpMvCntnt ); + else + pCntIdx->Assign( 0, 0 ); + } + + rDoc.DoUndo( bUndo ); +} + +void SwUndoSaveCntnt::MoveFromUndoNds( SwDoc& rDoc, ULONG nNodeIdx, + xub_StrLen nCntIdx, SwPosition& rInsPos, + ULONG* pEndNdIdx, xub_StrLen* pEndCntIdx ) +{ + // jetzt kommt das wiederherstellen + SwNodes& rNds = (SwNodes&)*rDoc.GetUndoNds(); + if( nNodeIdx == rNds.GetEndOfPostIts().GetIndex() ) + return; // nichts gespeichert + + BOOL bUndo = rDoc.DoesUndo(); + rDoc.DoUndo( FALSE ); + + SwPaM aPaM( rInsPos ); + if( pEndNdIdx ) // dann hole aus diesem den Bereich + aPaM.GetPoint()->nNode.Assign( rNds, *pEndNdIdx ); + else + { + aPaM.GetPoint()->nNode = rNds.GetEndOfExtras(); + GoInCntnt( aPaM, fnMoveBackward ); + } + + SwTxtNode* pTxtNd = aPaM.GetNode()->GetTxtNode(); + if( !pEndNdIdx && pTxtNd ) // loesche den Trenner wieder + { + if( pEndCntIdx ) + aPaM.GetPoint()->nContent.Assign( pTxtNd, *pEndCntIdx ); + if( pTxtNd->GetTxt().Len() ) + { + GoInCntnt( aPaM, fnMoveBackward ); + pTxtNd->EraseText( aPaM.GetPoint()->nContent, 1 ); + } + + aPaM.SetMark(); + aPaM.GetPoint()->nNode = nNodeIdx; + aPaM.GetPoint()->nContent.Assign( aPaM.GetCntntNode(), nCntIdx ); + + _SaveRedlEndPosForRestore aRedlRest( rInsPos.nNode, rInsPos.nContent.GetIndex() ); + + rNds.MoveRange( aPaM, rInsPos, rDoc.GetNodes() ); + + // noch den letzen Node loeschen. + if( !aPaM.GetPoint()->nContent.GetIndex() || + ( aPaM.GetPoint()->nNode++ && // noch leere Nodes am Ende ?? + &rNds.GetEndOfExtras() != &aPaM.GetPoint()->nNode.GetNode() )) + { + aPaM.GetPoint()->nContent.Assign( 0, 0 ); + aPaM.SetMark(); + rNds.Delete( aPaM.GetPoint()->nNode, + rNds.GetEndOfExtras().GetIndex() - + aPaM.GetPoint()->nNode.GetIndex() ); + } + + aRedlRest.Restore(); + } + else if( pEndNdIdx || !pTxtNd ) + { + SwNodeRange aRg( rNds, nNodeIdx, rNds, (pEndNdIdx + ? ((*pEndNdIdx) + 1) + : rNds.GetEndOfExtras().GetIndex() ) ); + rNds._MoveNodes( aRg, rDoc.GetNodes(), rInsPos.nNode, 0 == pEndNdIdx ); + + } + else { + ASSERT( FALSE, "was ist es denn nun?" ); + } + + rDoc.DoUndo( bUndo ); +} + +// diese beiden Methoden bewegen den Point vom Pam zurueck/vor. Damit +// kann fuer ein Undo/Redo ein Bereich aufgespannt werden. (Der +// Point liegt dann vor dem manipuliertem Bereich !!) +// Das Flag gibt an, ob noch vorm Point Inhalt steht. + +BOOL SwUndoSaveCntnt::MovePtBackward( SwPaM& rPam ) +{ + rPam.SetMark(); + if( rPam.Move( fnMoveBackward )) + return TRUE; + + // gibt es nach vorne keinen Inhalt mehr, so setze den Point einfach + // auf die vorherige Position (Node und Content, damit der Content + // abgemeldet wird !!) + rPam.GetPoint()->nNode--; + rPam.GetPoint()->nContent.Assign( 0, 0 ); + return FALSE; +} + +void SwUndoSaveCntnt::MovePtForward( SwPaM& rPam, BOOL bMvBkwrd ) +{ + // gab es noch Inhalt vor der Position ? + if( bMvBkwrd ) + rPam.Move( fnMoveForward ); + else + { // setzen Point auf die naechste Position + rPam.GetPoint()->nNode++; + SwCntntNode* pCNd = rPam.GetCntntNode(); + if( pCNd ) + pCNd->MakeStartIndex( &rPam.GetPoint()->nContent ); + else + rPam.Move( fnMoveForward ); + } +} + + +/* + JP 21.03.94: loesche alle Objecte, die ContentIndizies auf den ang. + Bereich besitzen. + Zur Zeit gibts folgende Objecte + - Fussnoten + - Flys + - Bookmarks + - Verzeichnisse +*/ +// --> OD 2007-10-17 #i81002# - extending method: +// delete certain (not all) cross-reference bookmarks at text node of <rMark> +// and at text node of <rPoint>, if these text nodes aren't the same. +void SwUndoSaveCntnt::DelCntntIndex( const SwPosition& rMark, + const SwPosition& rPoint, + DelCntntType nDelCntntType ) +{ + const SwPosition *pStt = rMark < rPoint ? &rMark : &rPoint, + *pEnd = &rMark == pStt ? &rPoint : &rMark; + + SwDoc* pDoc = rMark.nNode.GetNode().GetDoc(); + + BOOL bDoesUndo = pDoc->DoesUndo(); + pDoc->DoUndo( FALSE ); + + // 1. Fussnoten + if( nsDelCntntType::DELCNT_FTN & nDelCntntType ) + { + SwFtnIdxs& rFtnArr = pDoc->GetFtnIdxs(); + if( rFtnArr.Count() ) + { + const SwNode* pFtnNd; + USHORT nPos; + rFtnArr.SeekEntry( pStt->nNode, &nPos ); + SwTxtFtn* pSrch; + + // loesche erstmal alle, die dahinter stehen + while( nPos < rFtnArr.Count() && ( pFtnNd = + &( pSrch = rFtnArr[ nPos ] )->GetTxtNode())->GetIndex() + <= pEnd->nNode.GetIndex() ) + { + xub_StrLen nFtnSttIdx = *pSrch->GetStart(); + if( (nsDelCntntType::DELCNT_CHKNOCNTNT & nDelCntntType ) + ? (&pEnd->nNode.GetNode() == pFtnNd ) + : (( &pStt->nNode.GetNode() == pFtnNd && + pStt->nContent.GetIndex() > nFtnSttIdx) || + ( &pEnd->nNode.GetNode() == pFtnNd && + nFtnSttIdx >= pEnd->nContent.GetIndex() )) ) + { + ++nPos; // weiter suchen + continue; + } + + // es muss leider ein Index angelegt werden. Sonst knallts im + // TextNode, weil im DTOR der SwFtn dieser geloescht wird !! + SwTxtNode* pTxtNd = (SwTxtNode*)pFtnNd; + if( !pHistory ) + pHistory = new SwHistory; + SwTxtAttr* const pFtnHnt = + pTxtNd->GetTxtAttrForCharAt( nFtnSttIdx ); + ASSERT( pFtnHnt, "kein FtnAttribut" ); + SwIndex aIdx( pTxtNd, nFtnSttIdx ); + pHistory->Add( pFtnHnt, pTxtNd->GetIndex(), false ); + pTxtNd->EraseText( aIdx, 1 ); + } + + while( nPos-- && ( pFtnNd = &( pSrch = rFtnArr[ nPos ] )-> + GetTxtNode())->GetIndex() >= pStt->nNode.GetIndex() ) + { + xub_StrLen nFtnSttIdx = *pSrch->GetStart(); + if( !(nsDelCntntType::DELCNT_CHKNOCNTNT & nDelCntntType) && ( + ( &pStt->nNode.GetNode() == pFtnNd && + pStt->nContent.GetIndex() > nFtnSttIdx ) || + ( &pEnd->nNode.GetNode() == pFtnNd && + nFtnSttIdx >= pEnd->nContent.GetIndex() ))) + continue; // weiter suchen + + // es muss leider ein Index angelegt werden. Sonst knallts im + // TextNode, weil im DTOR der SwFtn dieser geloescht wird !! + SwTxtNode* pTxtNd = (SwTxtNode*)pFtnNd; + if( !pHistory ) + pHistory = new SwHistory; + SwTxtAttr* const pFtnHnt = + pTxtNd->GetTxtAttrForCharAt( nFtnSttIdx ); + ASSERT( pFtnHnt, "kein FtnAttribut" ); + SwIndex aIdx( pTxtNd, nFtnSttIdx ); + pHistory->Add( pFtnHnt, pTxtNd->GetIndex(), false ); + pTxtNd->EraseText( aIdx, 1 ); + } + } + } + + // 2. Flys + if( nsDelCntntType::DELCNT_FLY & nDelCntntType ) + { + USHORT nChainInsPos = pHistory ? pHistory->Count() : 0; + const SwSpzFrmFmts& rSpzArr = *pDoc->GetSpzFrmFmts(); + if( rSpzArr.Count() ) + { + const BOOL bDelFwrd = rMark.nNode.GetIndex() <= rPoint.nNode.GetIndex(); + SwFlyFrmFmt* pFmt; + const SwFmtAnchor* pAnchor; + USHORT n = rSpzArr.Count(); + const SwPosition* pAPos; + + while( n && rSpzArr.Count() ) + { + pFmt = (SwFlyFrmFmt*)rSpzArr[--n]; + pAnchor = &pFmt->GetAnchor(); + switch( pAnchor->GetAnchorId() ) + { + case FLY_AS_CHAR: + if( 0 != (pAPos = pAnchor->GetCntntAnchor() ) && + (( nsDelCntntType::DELCNT_CHKNOCNTNT & nDelCntntType ) + ? ( pStt->nNode <= pAPos->nNode && + pAPos->nNode < pEnd->nNode ) + : ( *pStt <= *pAPos && *pAPos < *pEnd )) ) + { + if( !pHistory ) + pHistory = new SwHistory; + SwTxtNode* pTxtNd = pDoc->GetNodes()[ pAPos->nNode]->GetTxtNode(); + SwTxtAttr* const pFlyHnt = pTxtNd->GetTxtAttrForCharAt( + pAPos->nContent.GetIndex()); + ASSERT( pFlyHnt, "kein FlyAttribut" ); + pHistory->Add( pFlyHnt, 0, false ); + // n wieder zurueck, damit nicht ein Format uebesprungen wird ! + n = n >= rSpzArr.Count() ? rSpzArr.Count() : n+1; + } + break; + case FLY_AT_PARA: + { + pAPos = pAnchor->GetCntntAnchor(); + if( pAPos ) + { + bool bTmp; + if( nsDelCntntType::DELCNT_CHKNOCNTNT & nDelCntntType ) + bTmp = pStt->nNode <= pAPos->nNode && pAPos->nNode < pEnd->nNode; + else + { + if (bDelFwrd) + bTmp = rMark.nNode < pAPos->nNode && + pAPos->nNode <= rPoint.nNode; + else + bTmp = rPoint.nNode <= pAPos->nNode && + pAPos->nNode < rMark.nNode; + } + + if (bTmp) + { + if( !pHistory ) + pHistory = new SwHistory; + + // Moving the anchor? + if( !( nsDelCntntType::DELCNT_CHKNOCNTNT & nDelCntntType ) && + ( rPoint.nNode.GetIndex() == pAPos->nNode.GetIndex() ) ) + { + // Do not try to move the anchor to a table! + if( rMark.nNode.GetNode().GetTxtNode() ) + { + pHistory->Add( *pFmt ); + SwFmtAnchor aAnch( *pAnchor ); + SwPosition aPos( rMark.nNode ); + aAnch.SetAnchor( &aPos ); + pFmt->SetFmtAttr( aAnch ); + } + } + else + { + pHistory->Add( *pFmt, nChainInsPos ); + // n wieder zurueck, damit nicht ein + // Format uebesprungen wird ! + n = n >= rSpzArr.Count() ? + rSpzArr.Count() : n+1; + } + } + } + } + break; + case FLY_AT_CHAR: + if( 0 != (pAPos = pAnchor->GetCntntAnchor() ) && + ( pStt->nNode <= pAPos->nNode && pAPos->nNode <= pEnd->nNode ) ) + { + if( !pHistory ) + pHistory = new SwHistory; + if (IsDestroyFrameAnchoredAtChar( + *pAPos, *pStt, *pEnd, nDelCntntType)) + { + pHistory->Add( *pFmt, nChainInsPos ); + n = n >= rSpzArr.Count() ? rSpzArr.Count() : n+1; + } + else if( !( nsDelCntntType::DELCNT_CHKNOCNTNT & nDelCntntType ) ) + { + if( *pStt <= *pAPos && *pAPos < *pEnd ) + { + // These are the objects anchored + // between section start and end position + // Do not try to move the anchor to a table! + if( rMark.nNode.GetNode().GetTxtNode() ) + { + pHistory->Add( *pFmt ); + SwFmtAnchor aAnch( *pAnchor ); + aAnch.SetAnchor( &rMark ); + pFmt->SetFmtAttr( aAnch ); + } + } + } + } + break; + case FLY_AT_FLY: + + if( 0 != (pAPos = pAnchor->GetCntntAnchor() ) && + pStt->nNode == pAPos->nNode ) + { + if( !pHistory ) + pHistory = new SwHistory; + + pHistory->Add( *pFmt, nChainInsPos ); + + // n wieder zurueck, damit nicht ein Format uebesprungen wird ! + n = n >= rSpzArr.Count() ? rSpzArr.Count() : n+1; + } + break; + default: break; + } + } + } + } + + // 3. Bookmarks + if( nsDelCntntType::DELCNT_BKM & nDelCntntType ) + { + IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess(); + if( pMarkAccess->getMarksCount() ) + { + + for( USHORT n = 0; n < pMarkAccess->getMarksCount(); ++n ) + { + // --> OD 2007-10-17 #i81002# + bool bSavePos = false; + bool bSaveOtherPos = false; + const ::sw::mark::IMark* pBkmk = (pMarkAccess->getMarksBegin() + n)->get(); + if( nsDelCntntType::DELCNT_CHKNOCNTNT & nDelCntntType ) + { + if( pStt->nNode <= pBkmk->GetMarkPos().nNode && + pBkmk->GetMarkPos().nNode < pEnd->nNode ) + bSavePos = true; + if( pBkmk->IsExpanded() && + pStt->nNode <= pBkmk->GetOtherMarkPos().nNode && + pBkmk->GetOtherMarkPos().nNode < pEnd->nNode ) + bSaveOtherPos = true; + } + else + { + // --> OD 2009-08-06 #i92125# + bool bKeepCrossRefBkmk( false ); + { + if ( rMark.nNode == rPoint.nNode && + ( IDocumentMarkAccess::GetType(*pBkmk) == + IDocumentMarkAccess::CROSSREF_HEADING_BOOKMARK || + IDocumentMarkAccess::GetType(*pBkmk) == + IDocumentMarkAccess::CROSSREF_NUMITEM_BOOKMARK ) ) + { + bKeepCrossRefBkmk = true; + } + } + if ( !bKeepCrossRefBkmk ) + { + bool bMaybe = false; + if ( *pStt <= pBkmk->GetMarkPos() && pBkmk->GetMarkPos() <= *pEnd ) + { + if( pBkmk->GetMarkPos() == *pEnd || + ( *pStt == pBkmk->GetMarkPos() && pBkmk->IsExpanded() ) ) + bMaybe = true; + else + bSavePos = true; + } + if( pBkmk->IsExpanded() && + *pStt <= pBkmk->GetOtherMarkPos() && pBkmk->GetOtherMarkPos() <= *pEnd ) + { + if( bSavePos || bSaveOtherPos || + ( pBkmk->GetOtherMarkPos() < *pEnd && pBkmk->GetOtherMarkPos() > *pStt ) ) + { + if( bMaybe ) + bSavePos = true; + bSaveOtherPos = true; + } + } + } + // <-- + + // --> OD 2007-10-17 #i81002# + const bool bDifferentTxtNodesAtMarkAndPoint( + rMark.nNode != rPoint.nNode && + rMark.nNode.GetNode().GetTxtNode() && + rPoint.nNode.GetNode().GetTxtNode() ); + // <-- + if( !bSavePos && !bSaveOtherPos && bDifferentTxtNodesAtMarkAndPoint && + dynamic_cast< const ::sw::mark::CrossRefBookmark* >(pBkmk)) + { + // delete cross-reference bookmark at <pStt>, if only part of + // <pEnd> text node content is deleted. + if( pStt->nNode == pBkmk->GetMarkPos().nNode && + pEnd->nContent.GetIndex() != + pEnd->nNode.GetNode().GetTxtNode()->Len() ) + { + bSavePos = true; + bSaveOtherPos = false; + } + // delete cross-reference bookmark at <pEnd>, if only part of + // <pStt> text node content is deleted. + else if( pEnd->nNode == pBkmk->GetMarkPos().nNode && + pStt->nContent.GetIndex() != 0 ) + { + bSavePos = true; + bSaveOtherPos = false; + } + } + } + if( bSavePos || bSaveOtherPos ) + { + if( !pHistory ) + pHistory = new SwHistory; + + pHistory->Add( *pBkmk, bSavePos, bSaveOtherPos ); + if(bSavePos && + (bSaveOtherPos || !pBkmk->IsExpanded())) + { + pMarkAccess->deleteMark(pMarkAccess->getMarksBegin()+n); + n--; + } + } + } + } + } + + pDoc->DoUndo( bDoesUndo ); +} + + +// sicher eine vollstaendige Section im Undo-Nodes-Array + +SwUndoSaveSection::SwUndoSaveSection() + : pMvStt( 0 ), pRedlSaveData( 0 ), nMvLen( 0 ), nStartPos( ULONG_MAX ) +{ +} + +SwUndoSaveSection::~SwUndoSaveSection() +{ + if( pMvStt ) // loesche noch den Bereich aus dem UndoNodes Array + { + // SaveSection speichert den Inhalt in der PostIt-Section + SwNodes& rUNds = pMvStt->GetNode().GetNodes(); + rUNds.Delete( *pMvStt, nMvLen ); + + delete pMvStt; + } + delete pRedlSaveData; +} + +void SwUndoSaveSection::SaveSection( SwDoc* pDoc, const SwNodeIndex& rSttIdx ) +{ + SwNodeRange aRg( rSttIdx.GetNode(), *rSttIdx.GetNode().EndOfSectionNode() ); + SaveSection( pDoc, aRg ); +} + + +void SwUndoSaveSection::SaveSection( SwDoc* , const SwNodeRange& rRange ) +{ + SwPaM aPam( rRange.aStart, rRange.aEnd ); + + // loesche alle Fussnoten / FlyFrames / Bookmarks / Verzeichnisse + DelCntntIndex( *aPam.GetMark(), *aPam.GetPoint() ); + + pRedlSaveData = new SwRedlineSaveDatas; + if( !SwUndo::FillSaveData( aPam, *pRedlSaveData, TRUE, TRUE )) + delete pRedlSaveData, pRedlSaveData = 0; + + nStartPos = rRange.aStart.GetIndex(); + + aPam.GetPoint()->nNode--; + aPam.GetMark()->nNode++; + + SwCntntNode* pCNd = aPam.GetCntntNode( FALSE ); + if( pCNd ) + aPam.GetMark()->nContent.Assign( pCNd, 0 ); + if( 0 != ( pCNd = aPam.GetCntntNode( TRUE )) ) + aPam.GetPoint()->nContent.Assign( pCNd, pCNd->Len() ); + + // Positionen als SwIndex merken, damit im DTOR dieser Bereich + // entfernt werden kann !! + ULONG nEnd; + pMvStt = new SwNodeIndex( rRange.aStart ); + MoveToUndoNds( aPam, pMvStt, 0, &nEnd, 0 ); + nMvLen = nEnd - pMvStt->GetIndex() + 1; +} + +void SwUndoSaveSection::RestoreSection( SwDoc* pDoc, SwNodeIndex* pIdx, + USHORT nSectType ) +{ + if( ULONG_MAX != nStartPos ) // gab es ueberhaupt Inhalt ? + { + // ueberpruefe, ob der Inhalt an der alten Position steht + SwNodeIndex aSttIdx( pDoc->GetNodes(), nStartPos ); + ASSERT( !pDoc->GetNodes()[ aSttIdx ]->GetCntntNode(), + "Position in irgendeiner Section" ); + + // move den Inhalt aus dem UndoNodes-Array in den Fly + SwStartNode* pSttNd = pDoc->GetNodes().MakeEmptySection( aSttIdx, + (SwStartNodeType)nSectType ); + + RestoreSection( pDoc, SwNodeIndex( *pSttNd->EndOfSectionNode() )); + + if( pIdx ) + *pIdx = *pSttNd; + } +} + +void SwUndoSaveSection::RestoreSection( SwDoc* pDoc, const SwNodeIndex& rInsPos ) +{ + if( ULONG_MAX != nStartPos ) // gab es ueberhaupt Inhalt ? + { + SwPosition aInsPos( rInsPos ); + ULONG nEnd = pMvStt->GetIndex() + nMvLen - 1; + MoveFromUndoNds( *pDoc, pMvStt->GetIndex(), 0, aInsPos, &nEnd, 0 ); + + // Indizies wieder zerstoren, Inhalt ist aus dem UndoNodes-Array + // entfernt worden. + DELETEZ( pMvStt ); + nMvLen = 0; + + if( pRedlSaveData ) + { + SwUndo::SetSaveData( *pDoc, *pRedlSaveData ); + delete pRedlSaveData, pRedlSaveData = 0; + } + } +} + +// START +SwUndoStart::SwUndoStart( SwUndoId nInitId ) + : SwUndo( UNDO_START ), nUserId( nInitId ), nEndOffset( 0 ) +{ +} + +void SwUndoStart::Undo( SwUndoIter& rUndoIter ) +{ + if( !( --rUndoIter.nEndCnt ) && rUndoIter.bWeiter && + ( rUndoIter.GetId() ? ( rUndoIter.GetId() == nUserId || + ( UNDO_END == rUndoIter.GetId() && UNDO_START == GetId() )) : TRUE )) + rUndoIter.bWeiter = FALSE; +} + +void SwUndoStart::Redo( SwUndoIter& rUndoIter ) +{ + rUndoIter.bWeiter = TRUE; + ++rUndoIter.nEndCnt; +} + +void SwUndoStart::Repeat( SwUndoIter& rUndoIter ) +{ + rUndoIter.bWeiter = FALSE; +} + +String SwUndoStart::GetComment() const +{ + String sResult; + + switch (nUserId) + { + case UNDO_START: + case UNDO_END: + sResult = String("??", RTL_TEXTENCODING_ASCII_US); + + break; + + default: + sResult = String(SW_RES(UNDO_BASE + nUserId)); + sResult = GetRewriter().Apply(sResult); + } + + return sResult; +} + +SwRewriter SwUndoStart::GetRewriter() const +{ + return mRewriter; +} + +SwUndoId SwUndoStart::GetEffectiveId() const +{ + return GetUserId(); +} + +void SwUndoStart::SetRewriter(const SwRewriter & rRewriter) +{ + mRewriter = rRewriter; +} + +// END +SwUndoEnd::SwUndoEnd( SwUndoId nInitId ) + : SwUndo( UNDO_END ), nUserId( nInitId ), nSttOffset( 0 ) +{ +} + +void SwUndoEnd::Undo( SwUndoIter& rUndoIter ) +{ + if( rUndoIter.GetId() == GetId() || !rUndoIter.GetId() ) + rUndoIter.bWeiter = TRUE; + if( rUndoIter.bWeiter ) + ++rUndoIter.nEndCnt; +} + +void SwUndoEnd::Redo( SwUndoIter& rUndoIter ) +{ + if( !( --rUndoIter.nEndCnt ) && rUndoIter.bWeiter && + ( rUndoIter.GetId() ? ( rUndoIter.GetId() == nUserId || + ( UNDO_END == rUndoIter.GetId() && UNDO_START == GetId() )) : TRUE )) + rUndoIter.bWeiter = FALSE; +} + +void SwUndoEnd::Repeat( SwUndoIter& rUndoIter ) +{ + rUndoIter.bWeiter = FALSE; +} + +String SwUndoEnd::GetComment() const +{ + String sResult; + + switch (nUserId) + { + case UNDO_START: + case UNDO_END: + sResult = String("??", RTL_TEXTENCODING_ASCII_US); + + break; + default: + sResult = SW_RES(UNDO_BASE + nUserId); + sResult = GetRewriter().Apply(sResult); + } + + return sResult; +} + +void SwUndoEnd::SetRewriter(const SwRewriter & rRewriter) +{ + mRewriter = rRewriter; +} + +SwUndoId SwUndoEnd::GetEffectiveId() const +{ + return GetUserId(); +} + +SwRewriter SwUndoEnd::GetRewriter() const +{ + return mRewriter; +} + +/* */ + // sicher und setze die RedlineDaten + +SwRedlineSaveData::SwRedlineSaveData( SwComparePosition eCmpPos, + const SwPosition& rSttPos, + const SwPosition& rEndPos, + SwRedline& rRedl, + BOOL bCopyNext ) + : SwUndRng( rRedl ), + SwRedlineData( rRedl.GetRedlineData(), bCopyNext ) +{ + ASSERT( POS_OUTSIDE == eCmpPos || + !rRedl.GetContentIdx(), "Redline mit Content" ); + + switch( eCmpPos ) + { + case POS_OVERLAP_BEFORE: // Pos1 ueberlappt Pos2 am Anfang + nEndNode = rEndPos.nNode.GetIndex(); + nEndCntnt = rEndPos.nContent.GetIndex(); + break; + case POS_OVERLAP_BEHIND: // Pos1 ueberlappt Pos2 am Ende + nSttNode = rSttPos.nNode.GetIndex(); + nSttCntnt = rSttPos.nContent.GetIndex(); + break; + + case POS_INSIDE: // Pos1 liegt vollstaendig in Pos2 + nSttNode = rSttPos.nNode.GetIndex(); + nSttCntnt = rSttPos.nContent.GetIndex(); + nEndNode = rEndPos.nNode.GetIndex(); + nEndCntnt = rEndPos.nContent.GetIndex(); + break; + + case POS_OUTSIDE: // Pos2 liegt vollstaendig in Pos1 + if( rRedl.GetContentIdx() ) + { + // dann den Bereich ins UndoArray verschieben und merken + SaveSection( rRedl.GetDoc(), *rRedl.GetContentIdx() ); + rRedl.SetContentIdx( 0 ); + } + break; + + case POS_EQUAL: // Pos1 ist genauso gross wie Pos2 + break; + + default: + ASSERT( !this, "keine gueltigen Daten!" ) + } + +#ifdef DBG_UTIL + nRedlineCount = rSttPos.nNode.GetNode().GetDoc()->GetRedlineTbl().Count(); +#endif +} + +SwRedlineSaveData::~SwRedlineSaveData() +{ +} + +void SwRedlineSaveData::RedlineToDoc( SwPaM& rPam ) +{ + SwDoc& rDoc = *rPam.GetDoc(); + SwRedline* pRedl = new SwRedline( *this, rPam ); + + if( GetMvSttIdx() ) + { + SwNodeIndex aIdx( rDoc.GetNodes() ); + RestoreSection( &rDoc, &aIdx, SwNormalStartNode ); + if( GetHistory() ) + GetHistory()->Rollback( &rDoc ); + pRedl->SetContentIdx( &aIdx ); + } + SetPaM( *pRedl ); + // erstmal die "alten" entfernen, damit im Append keine unerwarteten + // Dinge passieren, wie z.B. eine Delete in eigenen Insert. Dann wird + // naehmlich das gerade restaurierte wieder geloescht - nicht das gewollte + rDoc.DeleteRedline( *pRedl, false, USHRT_MAX ); + + RedlineMode_t eOld = rDoc.GetRedlineMode(); + rDoc.SetRedlineMode_intern((RedlineMode_t)(eOld | nsRedlineMode_t::REDLINE_DONTCOMBINE_REDLINES)); + //#i92154# let UI know about a new redline with comment + if (rDoc.GetDocShell() && (pRedl->GetComment() != String(::rtl::OUString::createFromAscii(""))) ) + rDoc.GetDocShell()->Broadcast(SwRedlineHint(pRedl,SWREDLINE_INSERTED)); + // +#if OSL_DEBUG_LEVEL > 0 + bool const bSuccess = +#endif + rDoc.AppendRedline( pRedl, true ); + OSL_ENSURE(bSuccess, + "SwRedlineSaveData::RedlineToDoc: insert redline failed"); + rDoc.SetRedlineMode_intern( eOld ); +} + +BOOL SwUndo::FillSaveData( const SwPaM& rRange, SwRedlineSaveDatas& rSData, + BOOL bDelRange, BOOL bCopyNext ) +{ + if( rSData.Count() ) + rSData.DeleteAndDestroy( 0, rSData.Count() ); + + SwRedlineSaveData* pNewData; + const SwPosition *pStt = rRange.Start(), *pEnd = rRange.End(); + const SwRedlineTbl& rTbl = rRange.GetDoc()->GetRedlineTbl(); + USHORT n = 0; + rRange.GetDoc()->GetRedline( *pStt, &n ); + for( ; n < rTbl.Count(); ++n ) + { + SwRedline* pRedl = rTbl[ n ]; + const SwPosition *pRStt = pRedl->Start(), *pREnd = pRedl->End(); + + SwComparePosition eCmpPos = ComparePosition( *pStt, *pEnd, *pRStt, *pREnd ); + if( POS_BEFORE != eCmpPos && POS_BEHIND != eCmpPos && + POS_COLLIDE_END != eCmpPos && POS_COLLIDE_START != eCmpPos ) + { + pNewData = new SwRedlineSaveData( eCmpPos, *pStt, *pEnd, + *pRedl, bCopyNext ); + rSData.Insert( pNewData, rSData.Count() ); + } + } + if( rSData.Count() && bDelRange ) + rRange.GetDoc()->DeleteRedline( rRange, false, USHRT_MAX ); + return 0 != rSData.Count(); +} + +BOOL SwUndo::FillSaveDataForFmt( const SwPaM& rRange, SwRedlineSaveDatas& rSData ) +{ + if( rSData.Count() ) + rSData.DeleteAndDestroy( 0, rSData.Count() ); + + SwRedlineSaveData* pNewData; + const SwPosition *pStt = rRange.Start(), *pEnd = rRange.End(); + const SwRedlineTbl& rTbl = rRange.GetDoc()->GetRedlineTbl(); + USHORT n = 0; + rRange.GetDoc()->GetRedline( *pStt, &n ); + for( ; n < rTbl.Count(); ++n ) + { + SwRedline* pRedl = rTbl[ n ]; + if( nsRedlineType_t::REDLINE_FORMAT == pRedl->GetType() ) + { + const SwPosition *pRStt = pRedl->Start(), *pREnd = pRedl->End(); + + SwComparePosition eCmpPos = ComparePosition( *pStt, *pEnd, *pRStt, *pREnd ); + if( POS_BEFORE != eCmpPos && POS_BEHIND != eCmpPos && + POS_COLLIDE_END != eCmpPos && POS_COLLIDE_START != eCmpPos ) + { + pNewData = new SwRedlineSaveData( eCmpPos, *pStt, *pEnd, + *pRedl, TRUE ); + rSData.Insert( pNewData, rSData.Count() ); + } + + + } + } + return 0 != rSData.Count(); +} + +void SwUndo::SetSaveData( SwDoc& rDoc, const SwRedlineSaveDatas& rSData ) +{ + RedlineMode_t eOld = rDoc.GetRedlineMode(); + rDoc.SetRedlineMode_intern( (RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON )); + SwPaM aPam( rDoc.GetNodes().GetEndOfContent() ); + + for( USHORT n = rSData.Count(); n; ) + rSData[ --n ]->RedlineToDoc( aPam ); + + // check redline count against count saved in RedlineSaveData object + DBG_ASSERT( (rSData.Count() == 0) || + (rSData[0]->nRedlineCount == rDoc.GetRedlineTbl().Count()), + "redline count not restored properly" ); + + rDoc.SetRedlineMode_intern( eOld ); +} + +BOOL SwUndo::HasHiddenRedlines( const SwRedlineSaveDatas& rSData ) +{ + for( USHORT n = rSData.Count(); n; ) + if( rSData[ --n ]->GetMvSttIdx() ) + return TRUE; + return FALSE; +} + +BOOL SwUndo::CanRedlineGroup( SwRedlineSaveDatas& rCurr, + const SwRedlineSaveDatas& rCheck, BOOL bCurrIsEnd ) +{ + BOOL bRet = FALSE; + USHORT n; + + if( rCurr.Count() == rCheck.Count() ) + { + bRet = TRUE; + for( n = 0; n < rCurr.Count(); ++n ) + { + const SwRedlineSaveData& rSet = *rCurr[ n ]; + const SwRedlineSaveData& rGet = *rCheck[ n ]; + if( rSet.nSttNode != rGet.nSttNode || + rSet.GetMvSttIdx() || rGet.GetMvSttIdx() || + ( bCurrIsEnd ? rSet.nSttCntnt != rGet.nEndCntnt + : rSet.nEndCntnt != rGet.nSttCntnt ) || + !rGet.CanCombine( rSet ) ) + { + bRet = FALSE; + break; + } + } + + if( bRet ) + for( n = 0; n < rCurr.Count(); ++n ) + { + SwRedlineSaveData& rSet = *rCurr[ n ]; + const SwRedlineSaveData& rGet = *rCheck[ n ]; + if( bCurrIsEnd ) + rSet.nSttCntnt = rGet.nSttCntnt; + else + rSet.nEndCntnt = rGet.nEndCntnt; + } + } + return bRet; +} + +// #111827# +String ShortenString(const String & rStr, xub_StrLen nLength, const String & rFillStr) +{ + ASSERT( nLength - rFillStr.Len() >= 2, "improper arguments") + + String aResult; + + if (rStr.Len() <= nLength) + aResult = rStr; + else + { + long nTmpLength = nLength - rFillStr.Len(); + if ( nTmpLength < 2 ) + nTmpLength = 2; + + nLength = static_cast<xub_StrLen>(nTmpLength); + + const xub_StrLen nFrontLen = nLength - nLength / 2; + const xub_StrLen nBackLen = nLength - nFrontLen; + + aResult += rStr.Copy(0, nFrontLen); + aResult += rFillStr; + aResult += rStr.Copy(rStr.Len() - nBackLen, nBackLen); + } + + return aResult; +} + +static bool lcl_IsSpecialCharacter(sal_Unicode nChar) +{ + switch (nChar) + { + case CH_TXTATR_BREAKWORD: + case CH_TXTATR_INWORD: + case CH_TXTATR_TAB: + case CH_TXTATR_NEWLINE: + return true; + + default: + break; + } + + return false; +} + +static String lcl_DenotedPortion(String rStr, xub_StrLen nStart, + xub_StrLen nEnd) +{ + String aResult; + + if (nEnd - nStart > 0) + { + sal_Unicode cLast = rStr.GetChar(nEnd - 1); + if (lcl_IsSpecialCharacter(cLast)) + { + switch(cLast) + { + case CH_TXTATR_TAB: + aResult += String(SW_RES(STR_UNDO_TABS)); + + break; + case CH_TXTATR_NEWLINE: + aResult += String(SW_RES(STR_UNDO_NLS)); + + break; + + case CH_TXTATR_INWORD: + case CH_TXTATR_BREAKWORD: + aResult += UNDO_ARG2; + + break; + + } + SwRewriter aRewriter; + aRewriter.AddRule(UNDO_ARG1, + String::CreateFromInt32(nEnd - nStart)); + aResult = aRewriter.Apply(aResult); + } + else + { + aResult = String(SW_RES(STR_START_QUOTE)); + aResult += rStr.Copy(nStart, nEnd - nStart); + aResult += String(SW_RES(STR_END_QUOTE)); + } + } + + return aResult; +} + +String DenoteSpecialCharacters(const String & rStr) +{ + String aResult; + + if (rStr.Len() > 0) + { + bool bStart = false; + xub_StrLen nStart = 0; + sal_Unicode cLast = 0; + + for (xub_StrLen i = 0; i < rStr.Len(); i++) + { + if (lcl_IsSpecialCharacter(rStr.GetChar(i))) + { + if (cLast != rStr.GetChar(i)) + bStart = true; + + } + else + { + if (lcl_IsSpecialCharacter(cLast)) + bStart = true; + } + + if (bStart) + { + aResult += lcl_DenotedPortion(rStr, nStart, i); + + nStart = i; + bStart = false; + } + + cLast = rStr.GetChar(i); + } + + aResult += lcl_DenotedPortion(rStr, nStart, rStr.Len()); + } + else + aResult = UNDO_ARG2; + + return aResult; +} + +bool IsDestroyFrameAnchoredAtChar(SwPosition const & rAnchorPos, + SwPosition const & rStart, SwPosition const & rEnd, + DelCntntType const nDelCntntType) +{ + + // Here we identified the objects to destroy: + // - anchored between start and end of the selection + // - anchored in start of the selection with "CheckNoContent" + // - anchored in start of sel. and the selection start at pos 0 + return (rAnchorPos.nNode < rEnd.nNode) + && ( (nsDelCntntType::DELCNT_CHKNOCNTNT & nDelCntntType) + || (rStart.nNode < rAnchorPos.nNode) + || !rStart.nContent.GetIndex() + ); +} + diff --git a/sw/source/core/undo/undobj1.cxx b/sw/source/core/undo/undobj1.cxx new file mode 100644 index 000000000000..a0ba635549ac --- /dev/null +++ b/sw/source/core/undo/undobj1.cxx @@ -0,0 +1,704 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <hintids.hxx> +#include <svl/itemiter.hxx> +#include <fmtflcnt.hxx> +#include <fmtanchr.hxx> +#include <fmtcntnt.hxx> +#include <txtflcnt.hxx> +#include <frmfmt.hxx> +#include <flyfrm.hxx> +#include <undobj.hxx> +#include <rolbck.hxx> // fuer die Attribut History +#include <doc.hxx> +#include <docary.hxx> +#include <rootfrm.hxx> +#include <swundo.hxx> // fuer die UndoIds +#include <pam.hxx> +#include <ndtxt.hxx> +// OD 26.06.2003 #108784# +#include <dcontact.hxx> +#include <ndole.hxx> + +// Inline Methode vom UndoIter +inline SwDoc& SwUndoIter::GetDoc() const { return *pAktPam->GetDoc(); } + +//--------------------------------------------------------------------- + +SwUndoFlyBase::SwUndoFlyBase( SwFrmFmt* pFormat, SwUndoId nUndoId ) + : SwUndo( nUndoId ), pFrmFmt( pFormat ) +{ +} + +SwUndoFlyBase::~SwUndoFlyBase() +{ + if( bDelFmt ) // loeschen waehrend eines Undo's ?? + delete pFrmFmt; +} + +void SwUndoFlyBase::InsFly( SwUndoIter& rUndoIter, BOOL bShowSelFrm ) +{ + SwDoc* pDoc = &rUndoIter.GetDoc(); + + // ins Array wieder eintragen + SwSpzFrmFmts& rFlyFmts = *(SwSpzFrmFmts*)pDoc->GetSpzFrmFmts(); + rFlyFmts.Insert( pFrmFmt, rFlyFmts.Count() ); + + // OD 26.06.2003 #108784# - insert 'master' drawing object into drawing page + if ( RES_DRAWFRMFMT == pFrmFmt->Which() ) + { + SwDrawContact* pDrawContact = + static_cast<SwDrawContact*>(pFrmFmt->FindContactObj()); + if ( pDrawContact ) + { + pDrawContact->InsertMasterIntoDrawPage(); + // --> OD 2005-01-31 #i40845# - follow-up of #i35635# + // move object to visible layer + pDrawContact->MoveObjToVisibleLayer( pDrawContact->GetMaster() ); + // <-- + } + } + + SwFmtAnchor aAnchor( (RndStdIds)nRndId ); + + if (FLY_AT_PAGE == nRndId) + { + aAnchor.SetPageNum( (USHORT)nNdPgPos ); + } + else + { + SwPosition aNewPos( *rUndoIter.pAktPam->GetPoint() ); + aNewPos.nNode = nNdPgPos; + if ((FLY_AS_CHAR == nRndId) || (FLY_AT_CHAR == nRndId)) + { + aNewPos.nContent.Assign( aNewPos.nNode.GetNode().GetCntntNode(), + nCntPos ); + } + aAnchor.SetAnchor( &aNewPos ); + } + + pFrmFmt->SetFmtAttr( aAnchor ); // Anker neu setzen + + if( RES_DRAWFRMFMT != pFrmFmt->Which() ) + { + // Content holen und -Attribut neu setzen + SwNodeIndex aIdx( pDoc->GetNodes() ); + RestoreSection( pDoc, &aIdx, SwFlyStartNode ); + pFrmFmt->SetFmtAttr( SwFmtCntnt( aIdx.GetNode().GetStartNode() )); + } + + //JP 18.12.98: Bug 60505 - InCntntAttribut erst setzen, wenn der Inhalt + // vorhanden ist! Sonst wuerde das Layout den Fly vorher + // formatieren, aber keine Inhalt finden; so geschene bei + // Grafiken aus dem Internet + if (FLY_AS_CHAR == nRndId) + { + // es muss mindestens das Attribut im TextNode stehen + SwCntntNode* pCNd = aAnchor.GetCntntAnchor()->nNode.GetNode().GetCntntNode(); + ASSERT( pCNd->IsTxtNode(), "no Text Node at position." ); + SwFmtFlyCnt aFmt( pFrmFmt ); + static_cast<SwTxtNode*>(pCNd)->InsertItem( aFmt, nCntPos, nCntPos ); + } + + pFrmFmt->MakeFrms(); + + if( bShowSelFrm ) + rUndoIter.pSelFmt = pFrmFmt; + + if( GetHistory() ) + GetHistory()->Rollback( pDoc ); + + switch( nRndId ) + { + case FLY_AS_CHAR: + case FLY_AT_CHAR: + { + const SwFmtAnchor& rAnchor = pFrmFmt->GetAnchor(); + nNdPgPos = rAnchor.GetCntntAnchor()->nNode.GetIndex(); + nCntPos = rAnchor.GetCntntAnchor()->nContent.GetIndex(); + } + break; + case FLY_AT_PARA: + case FLY_AT_FLY: + { + const SwFmtAnchor& rAnchor = pFrmFmt->GetAnchor(); + nNdPgPos = rAnchor.GetCntntAnchor()->nNode.GetIndex(); + } + break; + case FLY_AT_PAGE: + break; + } + bDelFmt = FALSE; +} + +void SwUndoFlyBase::DelFly( SwDoc* pDoc ) +{ + bDelFmt = TRUE; // im DTOR das Format loeschen + pFrmFmt->DelFrms(); // Frms vernichten. + + // alle Uno-Objecte sollten sich jetzt abmelden + { + SwPtrMsgPoolItem aMsgHint( RES_REMOVE_UNO_OBJECT, pFrmFmt ); + pFrmFmt->Modify( &aMsgHint, &aMsgHint ); + } + + if ( RES_DRAWFRMFMT != pFrmFmt->Which() ) + { + // gibt es ueberhaupt Inhalt, dann sicher diesen + const SwFmtCntnt& rCntnt = pFrmFmt->GetCntnt(); + ASSERT( rCntnt.GetCntntIdx(), "Fly ohne Inhalt" ); + + SaveSection( pDoc, *rCntnt.GetCntntIdx() ); + ((SwFmtCntnt&)rCntnt).SetNewCntntIdx( (const SwNodeIndex*)0 ); + } + // OD 02.07.2003 #108784# - remove 'master' drawing object from drawing page + else if ( RES_DRAWFRMFMT == pFrmFmt->Which() ) + { + SwDrawContact* pDrawContact = + static_cast<SwDrawContact*>(pFrmFmt->FindContactObj()); + if ( pDrawContact ) + { + pDrawContact->RemoveMasterFromDrawPage(); + } + } + + const SwFmtAnchor& rAnchor = pFrmFmt->GetAnchor(); + const SwPosition* pPos = rAnchor.GetCntntAnchor(); + // die Positionen im Nodes-Array haben sich verschoben + nRndId = static_cast<USHORT>(rAnchor.GetAnchorId()); + if (FLY_AS_CHAR == nRndId) + { + nNdPgPos = pPos->nNode.GetIndex(); + nCntPos = pPos->nContent.GetIndex(); + SwTxtNode *pTxtNd = pDoc->GetNodes()[ pPos->nNode ]->GetTxtNode(); + ASSERT( pTxtNd, "Kein Textnode gefunden" ); + SwTxtFlyCnt* const pAttr = static_cast<SwTxtFlyCnt*>( + pTxtNd->GetTxtAttrForCharAt( nCntPos, RES_TXTATR_FLYCNT ) ); + // Attribut steht noch im TextNode, loeschen + if( pAttr && pAttr->GetFlyCnt().GetFrmFmt() == pFrmFmt ) + { + // Pointer auf 0, nicht loeschen + ((SwFmtFlyCnt&)pAttr->GetFlyCnt()).SetFlyFmt(); + SwIndex aIdx( pPos->nContent ); + pTxtNd->EraseText( aIdx, 1 ); + } + } + else if (FLY_AT_CHAR == nRndId) + { + nNdPgPos = pPos->nNode.GetIndex(); + nCntPos = pPos->nContent.GetIndex(); + } + else if ((FLY_AT_PARA == nRndId) || (FLY_AT_FLY == nRndId)) + { + nNdPgPos = pPos->nNode.GetIndex(); + } + else + { + nNdPgPos = rAnchor.GetPageNum(); + } + + pFrmFmt->ResetFmtAttr( RES_ANCHOR ); // Anchor loeschen + + + // aus dem Array austragen + SwSpzFrmFmts& rFlyFmts = *(SwSpzFrmFmts*)pDoc->GetSpzFrmFmts(); + rFlyFmts.Remove( rFlyFmts.GetPos( pFrmFmt )); +} + +// ----- Undo-InsertFly ------ + +SwUndoInsLayFmt::SwUndoInsLayFmt( SwFrmFmt* pFormat, ULONG nNodeIdx, xub_StrLen nCntIdx ) + : SwUndoFlyBase( pFormat, RES_DRAWFRMFMT == pFormat->Which() ? + UNDO_INSDRAWFMT : UNDO_INSLAYFMT ), + mnCrsrSaveIndexPara( nNodeIdx ), mnCrsrSaveIndexPos( nCntIdx ) +{ + const SwFmtAnchor& rAnchor = pFrmFmt->GetAnchor(); + nRndId = static_cast<USHORT>(rAnchor.GetAnchorId()); + bDelFmt = FALSE; + switch( nRndId ) + { + case FLY_AT_PAGE: + nNdPgPos = rAnchor.GetPageNum(); + break; + case FLY_AT_PARA: + case FLY_AT_FLY: + nNdPgPos = rAnchor.GetCntntAnchor()->nNode.GetIndex(); + break; + case FLY_AS_CHAR: + case FLY_AT_CHAR: + { + const SwPosition* pPos = rAnchor.GetCntntAnchor(); + nCntPos = pPos->nContent.GetIndex(); + nNdPgPos = pPos->nNode.GetIndex(); + } + break; + default: + ASSERT( FALSE, "Was denn fuer ein FlyFrame?" ); + } +} + +SwUndoInsLayFmt::~SwUndoInsLayFmt() +{ +} + +void SwUndoInsLayFmt::Undo( SwUndoIter& rUndoIter ) +{ + const SwFmtCntnt& rCntnt = pFrmFmt->GetCntnt(); + if( rCntnt.GetCntntIdx() ) // kein Inhalt + { + bool bRemoveIdx = true; + if( mnCrsrSaveIndexPara > 0 ) + { + SwTxtNode *pNode = rUndoIter.GetDoc().GetNodes()[mnCrsrSaveIndexPara]->GetTxtNode(); + if( pNode ) + { + SwNodeIndex aIdx( rUndoIter.GetDoc().GetNodes(), rCntnt.GetCntntIdx()->GetIndex() ); + SwNodeIndex aEndIdx( rUndoIter.GetDoc().GetNodes(), aIdx.GetNode().EndOfSectionIndex() ); + SwIndex aIndex( pNode, mnCrsrSaveIndexPos ); + SwPosition aPos( *pNode, aIndex ); + rUndoIter.GetDoc().CorrAbs( aIdx, aEndIdx, aPos, TRUE ); + bRemoveIdx = false; + } + } + if( bRemoveIdx ) + RemoveIdxFromSection( rUndoIter.GetDoc(), + rCntnt.GetCntntIdx()->GetIndex() ); + } + DelFly( &rUndoIter.GetDoc() ); +} + +void SwUndoInsLayFmt::Redo( SwUndoIter& rUndoIter ) +{ + rUndoIter.pLastUndoObj = 0; + InsFly( rUndoIter ); +} + +void SwUndoInsLayFmt::Repeat( SwUndoIter& rUndoIter ) +{ + if( UNDO_INSLAYFMT == rUndoIter.GetLastUndoId() && + pFrmFmt == ((SwUndoInsLayFmt*)rUndoIter.pLastUndoObj)->pFrmFmt ) + return; + + SwDoc* pDoc = &rUndoIter.GetDoc(); + // erfrage und setze den Anker neu + SwFmtAnchor aAnchor( pFrmFmt->GetAnchor() ); + if ((FLY_AT_PARA == aAnchor.GetAnchorId()) || + (FLY_AT_CHAR == aAnchor.GetAnchorId()) || + (FLY_AS_CHAR == aAnchor.GetAnchorId())) + { + SwPosition aPos( *rUndoIter.pAktPam->GetPoint() ); + if (FLY_AT_PARA == aAnchor.GetAnchorId()) + { + aPos.nContent.Assign( 0, 0 ); + } + aAnchor.SetAnchor( &aPos ); + } + else if( FLY_AT_FLY == aAnchor.GetAnchorId() ) + { + const SwStartNode* pSttNd = rUndoIter.pAktPam->GetNode()->FindFlyStartNode(); + if( pSttNd ) + { + SwPosition aPos( *pSttNd ); + aAnchor.SetAnchor( &aPos ); + } + else + { + rUndoIter.pLastUndoObj = this; + return ; + } + } + else if (FLY_AT_PAGE == aAnchor.GetAnchorId()) + { + aAnchor.SetPageNum( pDoc->GetRootFrm()->GetCurrPage( + rUndoIter.pAktPam )); + } + else { + ASSERT( FALSE, "was fuer ein Anker ist es denn nun?" ); + } + + SwFrmFmt* pFlyFmt = pDoc->CopyLayoutFmt( *pFrmFmt, aAnchor, true, true ); + rUndoIter.pSelFmt = pFlyFmt; + + rUndoIter.pLastUndoObj = this; +} + +// #111827# +String SwUndoInsLayFmt::GetComment() const +{ + String aResult; + + if (! pComment) + { + /* + If frame format is present and has an SdrObject use the undo + comment of the SdrObject. Otherwise use the default comment. + */ + + bool bDone = false; + if (pFrmFmt) + { + const SdrObject * pSdrObj = pFrmFmt->FindSdrObject(); + if ( pSdrObj ) + { + aResult = SdrUndoNewObj::GetComment( *pSdrObj ); + bDone = true; + } + } + + if (! bDone) + aResult = SwUndo::GetComment(); + } + else + aResult = *pComment; + + return aResult; +} + +// ----- Undo-DeleteFly ------ + +SwUndoDelLayFmt::SwUndoDelLayFmt( SwFrmFmt* pFormat ) + : SwUndoFlyBase( pFormat, UNDO_DELLAYFMT ), bShowSelFrm( TRUE ) +{ + SwDoc* pDoc = pFormat->GetDoc(); + DelFly( pDoc ); + + SwNodeIndex* pIdx = GetMvSttIdx(); + SwNode* pNd; + if( 1 == GetMvNodeCnt() && pIdx && + ( pNd = (*pDoc->GetUndoNds())[ *pIdx ] )->IsNoTxtNode() ) + { + // dann setze eine andere Undo-ID; Grafik oder OLE + if( pNd->IsGrfNode() ) + SetId( UNDO_DELGRF ); + else if( pNd->IsOLENode() ) + { + SetId( UNDO_DELETE ); + + } + } +} + +SwRewriter SwUndoDelLayFmt::GetRewriter() const +{ + SwRewriter aRewriter; + + SwDoc * pDoc = pFrmFmt->GetDoc(); + + if (pDoc) + { + SwNodeIndex* pIdx = GetMvSttIdx(); + if( 1 == GetMvNodeCnt() && pIdx) + { + SwNode * pNd = (*pDoc->GetUndoNds())[ *pIdx ]; + + if ( pNd->IsNoTxtNode() && pNd->IsOLENode()) + { + SwOLENode * pOLENd = pNd->GetOLENode(); + + aRewriter.AddRule(UNDO_ARG1, pOLENd->GetDescription()); + } + } + } + + return aRewriter; +} + +void SwUndoDelLayFmt::Undo( SwUndoIter& rUndoIter ) +{ + InsFly( rUndoIter, bShowSelFrm ); +} + +void SwUndoDelLayFmt::Redo( SwUndoIter& rUndoIter ) +{ + const SwFmtCntnt& rCntnt = pFrmFmt->GetCntnt(); + if( rCntnt.GetCntntIdx() ) // kein Inhalt + RemoveIdxFromSection( rUndoIter.GetDoc(), + rCntnt.GetCntntIdx()->GetIndex() ); + + DelFly( &rUndoIter.GetDoc() ); +} + +void SwUndoDelLayFmt::Redo() +{ + const SwFmtCntnt& rCntnt = pFrmFmt->GetCntnt(); + if( rCntnt.GetCntntIdx() ) // kein Inhalt + RemoveIdxFromSection( *pFrmFmt->GetDoc(), + rCntnt.GetCntntIdx()->GetIndex() ); + + DelFly( pFrmFmt->GetDoc() ); +} + +/* */ + +SwUndoSetFlyFmt::SwUndoSetFlyFmt( SwFrmFmt& rFlyFmt, SwFrmFmt& rNewFrmFmt ) + : SwUndo( UNDO_SETFLYFRMFMT ), SwClient( &rFlyFmt ), pFrmFmt( &rFlyFmt ), + pOldFmt( (SwFrmFmt*)rFlyFmt.DerivedFrom() ), pNewFmt( &rNewFrmFmt ), + pItemSet( new SfxItemSet( *rFlyFmt.GetAttrSet().GetPool(), + rFlyFmt.GetAttrSet().GetRanges() )), + nOldNode( 0 ), nNewNode( 0 ), + nOldCntnt( 0 ), nNewCntnt( 0 ), + nOldAnchorTyp( 0 ), nNewAnchorTyp( 0 ), bAnchorChgd( FALSE ) +{ +} + +SwRewriter SwUndoSetFlyFmt::GetRewriter() const +{ + SwRewriter aRewriter; + + if (pNewFmt) + aRewriter.AddRule(UNDO_ARG1, pNewFmt->GetName()); + + return aRewriter; +} + + +SwUndoSetFlyFmt::~SwUndoSetFlyFmt() +{ + delete pItemSet; +} + +void SwUndoSetFlyFmt::GetAnchor( SwFmtAnchor& rAnchor, + ULONG nNode, xub_StrLen nCntnt ) +{ + RndStdIds nAnchorTyp = rAnchor.GetAnchorId(); + if (FLY_AT_PAGE != nAnchorTyp) + { + SwNode* pNd = pFrmFmt->GetDoc()->GetNodes()[ nNode ]; + + if( FLY_AT_FLY == nAnchorTyp + ? ( !pNd->IsStartNode() || SwFlyStartNode != + ((SwStartNode*)pNd)->GetStartNodeType() ) + : !pNd->IsTxtNode() ) + { + pNd = 0; // invalid position + } + else + { + SwPosition aPos( *pNd ); + if ((FLY_AS_CHAR == nAnchorTyp) || + (FLY_AT_CHAR == nAnchorTyp)) + { + if ( nCntnt > static_cast<SwTxtNode*>(pNd)->GetTxt().Len() ) + { + pNd = 0; // invalid position + } + else + { + aPos.nContent.Assign(static_cast<SwTxtNode*>(pNd), nCntnt); + } + } + if ( pNd ) + { + rAnchor.SetAnchor( &aPos ); + } + } + + if( !pNd ) + { + // ungueltige Position - setze auf 1. Seite + rAnchor.SetType( FLY_AT_PAGE ); + rAnchor.SetPageNum( 1 ); + } + } + else + rAnchor.SetPageNum( nCntnt ); +} + +void SwUndoSetFlyFmt::Undo( SwUndoIter& rIter ) +{ + SwDoc& rDoc = rIter.GetDoc(); + + // ist das neue Format noch vorhanden ?? + if( USHRT_MAX != rDoc.GetFrmFmts()->GetPos( (const SwFrmFmtPtr)pOldFmt ) ) + { + if( bAnchorChgd ) + pFrmFmt->DelFrms(); + + if( pFrmFmt->DerivedFrom() != pOldFmt ) + pFrmFmt->SetDerivedFrom( pOldFmt ); + + SfxItemIter aIter( *pItemSet ); + const SfxPoolItem* pItem = aIter.GetCurItem(); + while( pItem ) + { + if( IsInvalidItem( pItem )) + pFrmFmt->ResetFmtAttr( pItemSet->GetWhichByPos( + aIter.GetCurPos() )); + else + pFrmFmt->SetFmtAttr( *pItem ); + + if( aIter.IsAtEnd() ) + break; + pItem = aIter.NextItem(); + } + + if( bAnchorChgd ) + { + const SwFmtAnchor& rOldAnch = pFrmFmt->GetAnchor(); + if (FLY_AS_CHAR == rOldAnch.GetAnchorId()) + { + // Bei InCntnt's wird es spannend: Das TxtAttribut muss + // vernichtet werden. Leider reisst dies neben den Frms + // auch noch das Format mit in sein Grab. Um dass zu + // unterbinden loesen wir vorher die Verbindung zwischen + // Attribut und Format. + const SwPosition *pPos = rOldAnch.GetCntntAnchor(); + SwTxtNode *pTxtNode = pPos->nNode.GetNode().GetTxtNode(); + ASSERT( pTxtNode->HasHints(), "Missing FlyInCnt-Hint." ); + const xub_StrLen nIdx = pPos->nContent.GetIndex(); + SwTxtAttr * pHnt = pTxtNode->GetTxtAttrForCharAt( + nIdx, RES_TXTATR_FLYCNT ); + ASSERT( pHnt && pHnt->Which() == RES_TXTATR_FLYCNT, + "Missing FlyInCnt-Hint." ); + ASSERT( pHnt && pHnt->GetFlyCnt().GetFrmFmt() == pFrmFmt, + "Wrong TxtFlyCnt-Hint." ); + const_cast<SwFmtFlyCnt&>(pHnt->GetFlyCnt()).SetFlyFmt(); + + // Die Verbindung ist geloest, jetzt muss noch das Attribut + // vernichtet werden. + pTxtNode->DeleteAttributes( RES_TXTATR_FLYCNT, nIdx, nIdx ); + } + + // Anker umsetzen + SwFmtAnchor aNewAnchor( (RndStdIds) nOldAnchorTyp ); + GetAnchor( aNewAnchor, nOldNode, nOldCntnt ); + pFrmFmt->SetFmtAttr( aNewAnchor ); + + if (FLY_AS_CHAR == aNewAnchor.GetAnchorId()) + { + SwPosition* pPos = (SwPosition*)aNewAnchor.GetCntntAnchor(); + SwFmtFlyCnt aFmt( pFrmFmt ); + pPos->nNode.GetNode().GetTxtNode()->InsertItem( aFmt, + nOldCntnt, 0 ); + } + + pFrmFmt->MakeFrms(); + } + rIter.pSelFmt = pFrmFmt; + } +} + +void SwUndoSetFlyFmt::Redo( SwUndoIter& rIter ) +{ + SwDoc& rDoc = rIter.GetDoc(); + + // ist das neue Format noch vorhanden ?? + if( USHRT_MAX != rDoc.GetFrmFmts()->GetPos( (const SwFrmFmtPtr)pNewFmt ) ) + { + + if( bAnchorChgd ) + { + SwFmtAnchor aNewAnchor( (RndStdIds) nNewAnchorTyp ); + GetAnchor( aNewAnchor, nNewNode, nNewCntnt ); + SfxItemSet aSet( rDoc.GetAttrPool(), aFrmFmtSetRange ); + aSet.Put( aNewAnchor ); + rDoc.SetFrmFmtToFly( *pFrmFmt, *pNewFmt, &aSet ); + } + else + rDoc.SetFrmFmtToFly( *pFrmFmt, *pNewFmt, 0 ); + + rIter.pSelFmt = pFrmFmt; + } +} + +void SwUndoSetFlyFmt::PutAttr( USHORT nWhich, const SfxPoolItem* pItem ) +{ + if( pItem && pItem != GetDfltAttr( nWhich ) ) + { + // Sonderbehandlung fuer den Anchor + if( RES_ANCHOR == nWhich ) + { + // nur den 1. Ankerwechsel vermerken + ASSERT( !bAnchorChgd, "mehrfacher Ankerwechsel nicht erlaubt!" ); + + bAnchorChgd = TRUE; + + const SwFmtAnchor* pAnchor = (SwFmtAnchor*)pItem; + switch( nOldAnchorTyp = static_cast<USHORT>(pAnchor->GetAnchorId()) ) + { + case FLY_AS_CHAR: + case FLY_AT_CHAR: + nOldCntnt = pAnchor->GetCntntAnchor()->nContent.GetIndex(); + case FLY_AT_PARA: + case FLY_AT_FLY: + nOldNode = pAnchor->GetCntntAnchor()->nNode.GetIndex(); + break; + + default: + nOldCntnt = pAnchor->GetPageNum(); + } + + pAnchor = (SwFmtAnchor*)&pFrmFmt->GetAnchor(); + switch( nNewAnchorTyp = static_cast<USHORT>(pAnchor->GetAnchorId()) ) + { + case FLY_AS_CHAR: + case FLY_AT_CHAR: + nNewCntnt = pAnchor->GetCntntAnchor()->nContent.GetIndex(); + case FLY_AT_PARA: + case FLY_AT_FLY: + nNewNode = pAnchor->GetCntntAnchor()->nNode.GetIndex(); + break; + + default: + nNewCntnt = pAnchor->GetPageNum(); + } + } + else + pItemSet->Put( *pItem ); + } + else + pItemSet->InvalidateItem( nWhich ); +} + +void SwUndoSetFlyFmt::Modify( SfxPoolItem* pOld, SfxPoolItem* ) +{ + if( pOld ) + { + USHORT nWhich = pOld->Which(); + + if( nWhich < POOLATTR_END ) + PutAttr( nWhich, pOld ); + else if( RES_ATTRSET_CHG == nWhich ) + { + SfxItemIter aIter( *((SwAttrSetChg*)pOld)->GetChgSet() ); + const SfxPoolItem* pItem = aIter.GetCurItem(); + while( pItem ) + { + PutAttr( pItem->Which(), pItem ); + if( aIter.IsAtEnd() ) + break; + pItem = aIter.NextItem(); + } + } + } +} + diff --git a/sw/source/core/undo/undoflystrattr.cxx b/sw/source/core/undo/undoflystrattr.cxx new file mode 100644 index 000000000000..23113d6b0d1b --- /dev/null +++ b/sw/source/core/undo/undoflystrattr.cxx @@ -0,0 +1,104 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <undoflystrattr.hxx> +#include <frmfmt.hxx> + +SwUndoFlyStrAttr::SwUndoFlyStrAttr( SwFlyFrmFmt& rFlyFrmFmt, + const SwUndoId eUndoId, + const String& sOldStr, + const String& sNewStr ) + : SwUndo( eUndoId ), + mrFlyFrmFmt( rFlyFrmFmt ), + msOldStr( sOldStr ), + msNewStr( sNewStr ) +{ + ASSERT( eUndoId == UNDO_FLYFRMFMT_TITLE || + eUndoId == UNDO_FLYFRMFMT_DESCRIPTION, + "<SwUndoFlyStrAttr::SwUndoFlyStrAttr(..)> - unexpected undo id --> Undo will not work" ); +} + +SwUndoFlyStrAttr::~SwUndoFlyStrAttr() +{ +} + +void SwUndoFlyStrAttr::Undo( SwUndoIter& ) +{ + switch ( GetId() ) + { + case UNDO_FLYFRMFMT_TITLE: + { + mrFlyFrmFmt.SetObjTitle( msOldStr, true ); + } + break; + case UNDO_FLYFRMFMT_DESCRIPTION: + { + mrFlyFrmFmt.SetObjDescription( msOldStr, true ); + } + break; + default: + { + } + } +} + +void SwUndoFlyStrAttr::Redo( SwUndoIter& ) +{ + switch ( GetId() ) + { + case UNDO_FLYFRMFMT_TITLE: + { + mrFlyFrmFmt.SetObjTitle( msNewStr, true ); + } + break; + case UNDO_FLYFRMFMT_DESCRIPTION: + { + mrFlyFrmFmt.SetObjDescription( msNewStr, true ); + } + break; + default: + { + } + } +} + +void SwUndoFlyStrAttr::Repeat( SwUndoIter& ) +{ + // no repeat +} + +SwRewriter SwUndoFlyStrAttr::GetRewriter() const +{ + SwRewriter aResult; + + aResult.AddRule( UNDO_ARG1, mrFlyFrmFmt.GetName() ); + + return aResult; +} diff --git a/sw/source/core/undo/undraw.cxx b/sw/source/core/undo/undraw.cxx new file mode 100644 index 000000000000..980496cfd518 --- /dev/null +++ b/sw/source/core/undo/undraw.cxx @@ -0,0 +1,642 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <rtl/string.h> +#include <rtl/memory.h> +#include <hintids.hxx> + +#include <svx/svdogrp.hxx> +#include <svx/svdundo.hxx> +#include <svx/svdpage.hxx> +#include <svx/svdmark.hxx> +#include <fmtanchr.hxx> +#include <fmtflcnt.hxx> +#include <txtflcnt.hxx> +#include <frmfmt.hxx> +#include <doc.hxx> +#include <docary.hxx> +#include <frame.hxx> +#include <swundo.hxx> // fuer die UndoIds +#include <pam.hxx> +#include <ndtxt.hxx> +#include <undobj.hxx> +#include <dcontact.hxx> +#include <dview.hxx> +#include <rootfrm.hxx> +#include <viewsh.hxx> + + +struct SwUndoGroupObjImpl +{ + SwDrawFrmFmt* pFmt; + SdrObject* pObj; + ULONG nNodeIdx; + + // OD 2004-04-15 #i26791# - keeping the anchor and the relative position + // of drawing objects no longer needed +}; + + +inline SwDoc& SwUndoIter::GetDoc() const { return *pAktPam->GetDoc(); } + +// Draw-Objecte + +IMPL_LINK( SwDoc, AddDrawUndo, SdrUndoAction *, pUndo ) +{ +#if OSL_DEBUG_LEVEL > 1 + USHORT nId = pUndo->GetId(); + (void)nId; + String sComment( pUndo->GetComment() ); +#endif + + if( DoesUndo() && !IsNoDrawUndoObj() ) + { + ClearRedo(); + const SdrMarkList* pMarkList = 0; + ViewShell* pSh = GetRootFrm() ? GetRootFrm()->GetCurrShell() : 0; + if( pSh && pSh->HasDrawView() ) + pMarkList = &pSh->GetDrawView()->GetMarkedObjectList(); + + AppendUndo( new SwSdrUndo( pUndo, pMarkList ) ); + } + else + delete pUndo; + return 0; +} + +SwSdrUndo::SwSdrUndo( SdrUndoAction* pUndo, const SdrMarkList* pMrkLst ) + : SwUndo( UNDO_DRAWUNDO ), pSdrUndo( pUndo ) +{ + if( pMrkLst && pMrkLst->GetMarkCount() ) + pMarkList = new SdrMarkList( *pMrkLst ); + else + pMarkList = 0; +} + +SwSdrUndo::~SwSdrUndo() +{ + delete pSdrUndo; + delete pMarkList; +} + +void SwSdrUndo::Undo( SwUndoIter& rUndoIter ) +{ + pSdrUndo->Undo(); + rUndoIter.pMarkList = pMarkList; +} + +void SwSdrUndo::Redo( SwUndoIter& rUndoIter ) +{ + pSdrUndo->Redo(); + rUndoIter.pMarkList = pMarkList; +} + +String SwSdrUndo::GetComment() const +{ + return pSdrUndo->GetComment(); +} + +//-------------------------------------------- + +void lcl_SendRemoveToUno( SwFmt& rFmt ) +{ + SwPtrMsgPoolItem aMsgHint( RES_REMOVE_UNO_OBJECT, &rFmt ); + rFmt.Modify( &aMsgHint, &aMsgHint ); +} + +void lcl_SaveAnchor( SwFrmFmt* pFmt, ULONG& rNodePos ) +{ + const SwFmtAnchor& rAnchor = pFmt->GetAnchor(); + if ((FLY_AT_PARA == rAnchor.GetAnchorId()) || + (FLY_AT_CHAR == rAnchor.GetAnchorId()) || + (FLY_AT_FLY == rAnchor.GetAnchorId()) || + (FLY_AS_CHAR == rAnchor.GetAnchorId())) + { + rNodePos = rAnchor.GetCntntAnchor()->nNode.GetIndex(); + xub_StrLen nCntntPos = 0; + + if (FLY_AS_CHAR == rAnchor.GetAnchorId()) + { + nCntntPos = rAnchor.GetCntntAnchor()->nContent.GetIndex(); + + // TextAttribut zerstoeren + SwTxtNode *pTxtNd = pFmt->GetDoc()->GetNodes()[ rNodePos ]->GetTxtNode(); + ASSERT( pTxtNd, "Kein Textnode gefunden" ); + SwTxtFlyCnt* pAttr = static_cast<SwTxtFlyCnt*>( + pTxtNd->GetTxtAttrForCharAt( nCntntPos, RES_TXTATR_FLYCNT )); + // Attribut steht noch im TextNode, loeschen + if( pAttr && pAttr->GetFlyCnt().GetFrmFmt() == pFmt ) + { + // Pointer auf 0, nicht loeschen + ((SwFmtFlyCnt&)pAttr->GetFlyCnt()).SetFlyFmt(); + SwIndex aIdx( pTxtNd, nCntntPos ); + pTxtNd->EraseText( aIdx, 1 ); + } + } + else if (FLY_AT_CHAR == rAnchor.GetAnchorId()) + { + nCntntPos = rAnchor.GetCntntAnchor()->nContent.GetIndex(); + } + + pFmt->SetFmtAttr( SwFmtAnchor( rAnchor.GetAnchorId(), nCntntPos ) ); + } +} + +void lcl_RestoreAnchor( SwFrmFmt* pFmt, ULONG& rNodePos ) +{ + const SwFmtAnchor& rAnchor = pFmt->GetAnchor(); + if ((FLY_AT_PARA == rAnchor.GetAnchorId()) || + (FLY_AT_CHAR == rAnchor.GetAnchorId()) || + (FLY_AT_FLY == rAnchor.GetAnchorId()) || + (FLY_AS_CHAR == rAnchor.GetAnchorId())) + { + xub_StrLen nCntntPos = rAnchor.GetPageNum(); + SwNodes& rNds = pFmt->GetDoc()->GetNodes(); + + SwNodeIndex aIdx( rNds, rNodePos ); + SwPosition aPos( aIdx ); + + SwFmtAnchor aTmp( rAnchor.GetAnchorId() ); + if ((FLY_AS_CHAR == rAnchor.GetAnchorId()) || + (FLY_AT_CHAR == rAnchor.GetAnchorId())) + { + aPos.nContent.Assign( aIdx.GetNode().GetCntntNode(), nCntntPos ); + } + aTmp.SetAnchor( &aPos ); + pFmt->SetFmtAttr( aTmp ); + + if (FLY_AS_CHAR == rAnchor.GetAnchorId()) + { + SwTxtNode *pTxtNd = aIdx.GetNode().GetTxtNode(); + ASSERT( pTxtNd, "no Text Node" ); + SwFmtFlyCnt aFmt( pFmt ); + pTxtNd->InsertItem( aFmt, nCntntPos, nCntntPos ); + } + } +} + +SwUndoDrawGroup::SwUndoDrawGroup( USHORT nCnt ) + : SwUndo( UNDO_DRAWGROUP ), nSize( nCnt + 1 ), bDelFmt( TRUE ) +{ + pObjArr = new SwUndoGroupObjImpl[ nSize ]; +} + +SwUndoDrawGroup::~SwUndoDrawGroup() +{ + if( bDelFmt ) + { + SwUndoGroupObjImpl* pTmp = pObjArr + 1; + for( USHORT n = 1; n < nSize; ++n, ++pTmp ) + delete pTmp->pFmt; + } + else + delete pObjArr->pFmt; // das GroupObject-Format + + delete [] pObjArr; +} + +void SwUndoDrawGroup::Undo( SwUndoIter& ) +{ + bDelFmt = FALSE; + + // das Group-Object sichern + SwDrawFrmFmt* pFmt = pObjArr->pFmt; + SwDrawContact* pDrawContact = (SwDrawContact*)pFmt->FindContactObj(); + SdrObject* pObj = pDrawContact->GetMaster(); + pObjArr->pObj = pObj; + + //loescht sich selbst! + pDrawContact->Changed( *pObj, SDRUSERCALL_DELETE, pObj->GetLastBoundRect() ); + pObj->SetUserCall( 0 ); + + ::lcl_SaveAnchor( pFmt, pObjArr->nNodeIdx ); + + // alle Uno-Objecte sollten sich jetzt abmelden + ::lcl_SendRemoveToUno( *pFmt ); + + // aus dem Array austragen + SwDoc* pDoc = pFmt->GetDoc(); + SwSpzFrmFmts& rFlyFmts = *(SwSpzFrmFmts*)pDoc->GetSpzFrmFmts(); + rFlyFmts.Remove( rFlyFmts.GetPos( pFmt )); + + for( USHORT n = 1; n < nSize; ++n ) + { + SwUndoGroupObjImpl& rSave = *( pObjArr + n ); + + ::lcl_RestoreAnchor( rSave.pFmt, rSave.nNodeIdx ); + rFlyFmts.Insert( rSave.pFmt, rFlyFmts.Count() ); + + pObj = rSave.pObj; + + SwDrawContact *pContact = new SwDrawContact( rSave.pFmt, pObj ); + pContact->ConnectToLayout(); + // --> OD 2005-03-22 #i45718# - follow-up of #i35635# + // move object to visible layer + pContact->MoveObjToVisibleLayer( pObj ); + // <-- + // --> OD 2005-05-10 #i45952# - notify that position attributes + // are already set + ASSERT( rSave.pFmt->ISA(SwDrawFrmFmt), + "<SwUndoDrawGroup::Undo(..)> - wrong type of frame format for drawing object" ); + if ( rSave.pFmt->ISA(SwDrawFrmFmt) ) + { + static_cast<SwDrawFrmFmt*>(rSave.pFmt)->PosAttrSet(); + } + // <-- + } +} + +void SwUndoDrawGroup::Redo( SwUndoIter& ) +{ + bDelFmt = TRUE; + + // aus dem Array austragen + SwDoc* pDoc = pObjArr->pFmt->GetDoc(); + SwSpzFrmFmts& rFlyFmts = *(SwSpzFrmFmts*)pDoc->GetSpzFrmFmts(); + SdrObject* pObj; + + for( USHORT n = 1; n < nSize; ++n ) + { + SwUndoGroupObjImpl& rSave = *( pObjArr + n ); + + pObj = rSave.pObj; + + SwDrawContact *pContact = (SwDrawContact*)GetUserCall(pObj); + //loescht sich selbst! + pContact->Changed( *pObj, SDRUSERCALL_DELETE, pObj->GetLastBoundRect() ); + pObj->SetUserCall( 0 ); + + ::lcl_SaveAnchor( rSave.pFmt, rSave.nNodeIdx ); + + // alle Uno-Objecte sollten sich jetzt abmelden + ::lcl_SendRemoveToUno( *rSave.pFmt ); + + rFlyFmts.Remove( rFlyFmts.GetPos( rSave.pFmt )); + } + + // das Group-Object wieder einfuegen + ::lcl_RestoreAnchor( pObjArr->pFmt, pObjArr->nNodeIdx ); + rFlyFmts.Insert( pObjArr->pFmt, rFlyFmts.Count() ); + + SwDrawContact *pContact = new SwDrawContact( pObjArr->pFmt, pObjArr->pObj ); + // OD 2004-04-15 #i26791# - correction: connect object to layout + pContact->ConnectToLayout(); + // --> OD 2005-03-22 #i45718# - follow-up of #i35635# + // move object to visible layer + pContact->MoveObjToVisibleLayer( pObjArr->pObj ); + // <-- + // --> OD 2005-05-10 #i45952# - notify that position attributes + // are already set + ASSERT( pObjArr->pFmt->ISA(SwDrawFrmFmt), + "<SwUndoDrawGroup::Undo(..)> - wrong type of frame format for drawing object" ); + if ( pObjArr->pFmt->ISA(SwDrawFrmFmt) ) + { + static_cast<SwDrawFrmFmt*>(pObjArr->pFmt)->PosAttrSet(); + } + // <-- +} + +void SwUndoDrawGroup::AddObj( USHORT nPos, SwDrawFrmFmt* pFmt, SdrObject* pObj ) +{ + SwUndoGroupObjImpl& rSave = *( pObjArr + nPos + 1 ); + rSave.pObj = pObj; + rSave.pFmt = pFmt; + ::lcl_SaveAnchor( pFmt, rSave.nNodeIdx ); + + // alle Uno-Objecte sollten sich jetzt abmelden + ::lcl_SendRemoveToUno( *pFmt ); + + // aus dem Array austragen + SwSpzFrmFmts& rFlyFmts = *(SwSpzFrmFmts*)pFmt->GetDoc()->GetSpzFrmFmts(); + rFlyFmts.Remove( rFlyFmts.GetPos( pFmt )); +} + +void SwUndoDrawGroup::SetGroupFmt( SwDrawFrmFmt* pFmt ) +{ + pObjArr->pObj = 0; + pObjArr->pFmt = pFmt; +} + + +// ------------------------------ + +SwUndoDrawUnGroup::SwUndoDrawUnGroup( SdrObjGroup* pObj ) + : SwUndo( UNDO_DRAWUNGROUP ), bDelFmt( FALSE ) +{ + nSize = (USHORT)pObj->GetSubList()->GetObjCount() + 1; + pObjArr = new SwUndoGroupObjImpl[ nSize ]; + + SwDrawContact *pContact = (SwDrawContact*)GetUserCall(pObj); + SwDrawFrmFmt* pFmt = (SwDrawFrmFmt*)pContact->GetFmt(); + + pObjArr->pObj = pObj; + pObjArr->pFmt = pFmt; + + //loescht sich selbst! + pContact->Changed( *pObj, SDRUSERCALL_DELETE, pObj->GetLastBoundRect() ); + pObj->SetUserCall( 0 ); + + ::lcl_SaveAnchor( pFmt, pObjArr->nNodeIdx ); + + // alle Uno-Objecte sollten sich jetzt abmelden + ::lcl_SendRemoveToUno( *pFmt ); + + // aus dem Array austragen + SwSpzFrmFmts& rFlyFmts = *(SwSpzFrmFmts*)pFmt->GetDoc()->GetSpzFrmFmts(); + rFlyFmts.Remove( rFlyFmts.GetPos( pFmt )); +} + +SwUndoDrawUnGroup::~SwUndoDrawUnGroup() +{ + if( bDelFmt ) + { + SwUndoGroupObjImpl* pTmp = pObjArr + 1; + for( USHORT n = 1; n < nSize; ++n, ++pTmp ) + delete pTmp->pFmt; + } + else + delete pObjArr->pFmt; // das GroupObject-Format + + delete [] pObjArr; +} + +void SwUndoDrawUnGroup::Undo( SwUndoIter& rIter ) +{ + bDelFmt = TRUE; + + // aus dem Array austragen + SwDoc* pDoc = &rIter.GetDoc(); + SwSpzFrmFmts& rFlyFmts = *(SwSpzFrmFmts*)pDoc->GetSpzFrmFmts(); + + for( USHORT n = 1; n < nSize; ++n ) + { + SwUndoGroupObjImpl& rSave = *( pObjArr + n ); + + // --> OD 2006-11-01 #130889# - taken over by <SwUndoDrawUnGroupConnectToLayout> +// SwDrawContact* pContact = (SwDrawContact*)rSave.pFmt->FindContactObj(); + +// rSave.pObj = pContact->GetMaster(); + +// //loescht sich selbst! +// pContact->Changed( *rSave.pObj, SDRUSERCALL_DELETE, +// rSave.pObj->GetLastBoundRect() ); +// rSave.pObj->SetUserCall( 0 ); + // <-- + + ::lcl_SaveAnchor( rSave.pFmt, rSave.nNodeIdx ); + + // alle Uno-Objecte sollten sich jetzt abmelden + ::lcl_SendRemoveToUno( *rSave.pFmt ); + + rFlyFmts.Remove( rFlyFmts.GetPos( rSave.pFmt )); + } + + // das Group-Object wieder einfuegen + ::lcl_RestoreAnchor( pObjArr->pFmt, pObjArr->nNodeIdx ); + rFlyFmts.Insert( pObjArr->pFmt, rFlyFmts.Count() ); + + SwDrawContact *pContact = new SwDrawContact( pObjArr->pFmt, pObjArr->pObj ); + pContact->ConnectToLayout(); + // --> OD 2005-03-22 #i45718# - follow-up of #i35635# + // move object to visible layer + pContact->MoveObjToVisibleLayer( pObjArr->pObj ); + // <-- + // --> OD 2005-05-10 #i45952# - notify that position attributes + // are already set + ASSERT( pObjArr->pFmt->ISA(SwDrawFrmFmt), + "<SwUndoDrawGroup::Undo(..)> - wrong type of frame format for drawing object" ); + if ( pObjArr->pFmt->ISA(SwDrawFrmFmt) ) + { + static_cast<SwDrawFrmFmt*>(pObjArr->pFmt)->PosAttrSet(); + } + // <-- +} + +void SwUndoDrawUnGroup::Redo( SwUndoIter& ) +{ + bDelFmt = FALSE; + + // das Group-Object sichern + SwDrawFrmFmt* pFmt = pObjArr->pFmt; + SwDrawContact* pContact = (SwDrawContact*)pFmt->FindContactObj(); + + //loescht sich selbst! + pContact->Changed( *pObjArr->pObj, SDRUSERCALL_DELETE, + pObjArr->pObj->GetLastBoundRect() ); + pObjArr->pObj->SetUserCall( 0 ); + + ::lcl_SaveAnchor( pFmt, pObjArr->nNodeIdx ); + + // alle Uno-Objecte sollten sich jetzt abmelden + ::lcl_SendRemoveToUno( *pFmt ); + + // aus dem Array austragen + SwDoc* pDoc = pFmt->GetDoc(); + SwSpzFrmFmts& rFlyFmts = *(SwSpzFrmFmts*)pDoc->GetSpzFrmFmts(); + rFlyFmts.Remove( rFlyFmts.GetPos( pFmt )); + + for( USHORT n = 1; n < nSize; ++n ) + { + SwUndoGroupObjImpl& rSave = *( pObjArr + n ); + + ::lcl_RestoreAnchor( rSave.pFmt, rSave.nNodeIdx ); + rFlyFmts.Insert( rSave.pFmt, rFlyFmts.Count() ); + + // --> OD 2006-11-01 #130889# - taken over by <SwUndoDrawUnGroupConnectToLayout> +// SdrObject* pObj = rSave.pObj; + +// SwDrawContact *pContact = new SwDrawContact( rSave.pFmt, rSave.pObj ); +// pContact->ConnectToLayout(); +// // --> OD 2005-03-22 #i45718# - follow-up of #i35635# +// // move object to visible layer +// pContact->MoveObjToVisibleLayer( rSave.pObj ); +// // <-- + // <-- + // --> OD 2005-05-10 #i45952# - notify that position attributes + // are already set + ASSERT( rSave.pFmt->ISA(SwDrawFrmFmt), + "<SwUndoDrawGroup::Undo(..)> - wrong type of frame format for drawing object" ); + if ( rSave.pFmt->ISA(SwDrawFrmFmt) ) + { + static_cast<SwDrawFrmFmt*>(rSave.pFmt)->PosAttrSet(); + } + // <-- + } +} + +void SwUndoDrawUnGroup::AddObj( USHORT nPos, SwDrawFrmFmt* pFmt ) +{ + SwUndoGroupObjImpl& rSave = *( pObjArr + nPos + 1 ); + rSave.pFmt = pFmt; + rSave.pObj = 0; +} + +//------------------------------------- +// --> OD 2006-11-01 #130889# +SwUndoDrawUnGroupConnectToLayout::SwUndoDrawUnGroupConnectToLayout() + : SwUndo( UNDO_DRAWUNGROUP ) +{ +} + +SwUndoDrawUnGroupConnectToLayout::~SwUndoDrawUnGroupConnectToLayout() +{ +} + +void SwUndoDrawUnGroupConnectToLayout::Undo( SwUndoIter& ) +{ + for ( std::vector< SdrObject >::size_type i = 0; + i < aDrawFmtsAndObjs.size(); ++i ) + { + SdrObject* pObj( aDrawFmtsAndObjs[i].second ); + SwDrawContact* pDrawContact( dynamic_cast<SwDrawContact*>(pObj->GetUserCall()) ); + ASSERT( pDrawContact, + "<SwUndoDrawUnGroupConnectToLayout::Undo(..)> -- missing SwDrawContact instance" ); + if ( pDrawContact ) + { + // deletion of instance <pDrawContact> and thus disconnection from + // the Writer layout. + pDrawContact->Changed( *pObj, SDRUSERCALL_DELETE, pObj->GetLastBoundRect() ); + pObj->SetUserCall( 0 ); + } + } +} + +void SwUndoDrawUnGroupConnectToLayout::Redo( SwUndoIter& ) +{ + for ( std::vector< std::pair< SwDrawFrmFmt*, SdrObject* > >::size_type i = 0; + i < aDrawFmtsAndObjs.size(); ++i ) + { + SwDrawFrmFmt* pFmt( aDrawFmtsAndObjs[i].first ); + SdrObject* pObj( aDrawFmtsAndObjs[i].second ); + SwDrawContact *pContact = new SwDrawContact( pFmt, pObj ); + pContact->ConnectToLayout(); + pContact->MoveObjToVisibleLayer( pObj ); + } +} + +void SwUndoDrawUnGroupConnectToLayout::AddFmtAndObj( SwDrawFrmFmt* pDrawFrmFmt, + SdrObject* pDrawObject ) +{ + aDrawFmtsAndObjs.push_back( + std::pair< SwDrawFrmFmt*, SdrObject* >( pDrawFrmFmt, pDrawObject ) ); +} +// <-- + +//------------------------------------- + +SwUndoDrawDelete::SwUndoDrawDelete( USHORT nCnt ) + : SwUndo( UNDO_DRAWDELETE ), nSize( nCnt ), bDelFmt( TRUE ) +{ + pObjArr = new SwUndoGroupObjImpl[ nSize ]; + pMarkLst = new SdrMarkList(); +} + +SwUndoDrawDelete::~SwUndoDrawDelete() +{ + if( bDelFmt ) + { + SwUndoGroupObjImpl* pTmp = pObjArr; + for( USHORT n = 0; n < pMarkLst->GetMarkCount(); ++n, ++pTmp ) + delete pTmp->pFmt; + } + delete [] pObjArr; + delete pMarkLst; +} + +void SwUndoDrawDelete::Undo( SwUndoIter &rIter ) +{ + bDelFmt = FALSE; + SwSpzFrmFmts& rFlyFmts = *rIter.GetDoc().GetSpzFrmFmts(); + for( USHORT n = 0; n < pMarkLst->GetMarkCount(); ++n ) + { + SwUndoGroupObjImpl& rSave = *( pObjArr + n ); + ::lcl_RestoreAnchor( rSave.pFmt, rSave.nNodeIdx ); + rFlyFmts.Insert( rSave.pFmt, rFlyFmts.Count() ); + SdrObject *pObj = rSave.pObj; + SwDrawContact *pContact = new SwDrawContact( rSave.pFmt, pObj ); + pContact->_Changed( *pObj, SDRUSERCALL_INSERTED, NULL ); + // --> OD 2005-03-22 #i45718# - follow-up of #i35635# + // move object to visible layer + pContact->MoveObjToVisibleLayer( pObj ); + // <-- + // --> OD 2005-05-10 #i45952# - notify that position attributes + // are already set + ASSERT( rSave.pFmt->ISA(SwDrawFrmFmt), + "<SwUndoDrawGroup::Undo(..)> - wrong type of frame format for drawing object" ); + if ( rSave.pFmt->ISA(SwDrawFrmFmt) ) + { + static_cast<SwDrawFrmFmt*>(rSave.pFmt)->PosAttrSet(); + } + // <-- + } + rIter.pMarkList = pMarkLst; +} + +void SwUndoDrawDelete::Redo( SwUndoIter &rIter ) +{ + bDelFmt = TRUE; + SwSpzFrmFmts& rFlyFmts = *rIter.GetDoc().GetSpzFrmFmts(); + for( USHORT n = 0; n < pMarkLst->GetMarkCount(); ++n ) + { + SwUndoGroupObjImpl& rSave = *( pObjArr + n ); + SdrObject *pObj = rSave.pObj; + SwDrawContact *pContact = (SwDrawContact*)GetUserCall(pObj); + SwDrawFrmFmt *pFmt = (SwDrawFrmFmt*)pContact->GetFmt(); + //loescht sich selbst! + pContact->Changed( *pObj, SDRUSERCALL_DELETE, pObj->GetLastBoundRect() ); + pObj->SetUserCall( 0 ); + + // alle Uno-Objecte sollten sich jetzt abmelden + ::lcl_SendRemoveToUno( *pFmt ); + + rFlyFmts.Remove( rFlyFmts.GetPos( pFmt )); + ::lcl_SaveAnchor( pFmt, rSave.nNodeIdx ); + } +} + +void SwUndoDrawDelete::AddObj( USHORT , SwDrawFrmFmt* pFmt, + const SdrMark& rMark ) +{ + SwUndoGroupObjImpl& rSave = *( pObjArr + pMarkLst->GetMarkCount() ); + rSave.pObj = rMark.GetMarkedSdrObj(); + rSave.pFmt = pFmt; + ::lcl_SaveAnchor( pFmt, rSave.nNodeIdx ); + + // alle Uno-Objecte sollten sich jetzt abmelden + ::lcl_SendRemoveToUno( *pFmt ); + + // aus dem Array austragen + SwDoc* pDoc = pFmt->GetDoc(); + SwSpzFrmFmts& rFlyFmts = *(SwSpzFrmFmts*)pDoc->GetSpzFrmFmts(); + rFlyFmts.Remove( rFlyFmts.GetPos( pFmt )); + + pMarkLst->InsertEntry( rMark ); +} + diff --git a/sw/source/core/undo/unfmco.cxx b/sw/source/core/undo/unfmco.cxx new file mode 100644 index 000000000000..e67ec2e9d8c2 --- /dev/null +++ b/sw/source/core/undo/unfmco.cxx @@ -0,0 +1,131 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + + +#include "doc.hxx" +#include "swundo.hxx" // fuer die UndoIds +#include "pam.hxx" +#include "ndtxt.hxx" + +#include "undobj.hxx" +#include "rolbck.hxx" + + +inline SwDoc& SwUndoIter::GetDoc() const { return *pAktPam->GetDoc(); } + +//-------------------------------------------------- + + +// --> OD 2008-04-15 #refactorlists# +SwUndoFmtColl::SwUndoFmtColl( const SwPaM& rRange, + SwFmtColl* pColl, + const bool bReset, + const bool bResetListAttrs ) + : SwUndo( UNDO_SETFMTCOLL ), + SwUndRng( rRange ), + pHistory( new SwHistory ), + pFmtColl( pColl ), + mbReset( bReset ), + mbResetListAttrs( bResetListAttrs ) +// <-- +{ + // --> FME 2004-08-06 #i31191# + if ( pColl ) + aFmtName = pColl->GetName(); + // <-- +} + + +SwUndoFmtColl::~SwUndoFmtColl() +{ + delete pHistory; +} + + +void SwUndoFmtColl::Undo( SwUndoIter& rUndoIter ) +{ + // die alten Werte wieder zurueck + pHistory->TmpRollback( &rUndoIter.GetDoc(), 0 ); + pHistory->SetTmpEnd( pHistory->Count() ); + + // setze noch den Cursor auf den Undo-Bereich + SetPaM( rUndoIter ); +} + + +void SwUndoFmtColl::Redo( SwUndoIter& rUndoIter ) +{ + // setze Attribut in dem Bereich: + SetPaM( rUndoIter ); + rUndoIter.pLastUndoObj = 0; + + Repeat( rUndoIter ); // Collection setzen + + rUndoIter.pLastUndoObj = 0; +} + + +void SwUndoFmtColl::Repeat( SwUndoIter& rUndoIter ) +{ + if( UNDO_SETFMTCOLL == rUndoIter.GetLastUndoId() && + pFmtColl == ((SwUndoFmtColl*)rUndoIter.pLastUndoObj)->pFmtColl ) + return; + + // es kann nur eine TextFmtColl auf einen Bereich angewendet werden, + // also erfrage auch nur in dem Array + USHORT nPos = rUndoIter.GetDoc().GetTxtFmtColls()->GetPos( + (SwTxtFmtColl*)pFmtColl ); + // ist das Format ueberhaupt noch vorhanden? + if( USHRT_MAX != nPos ) + { + // --> OD 2008-04-15 #refactorlists# + rUndoIter.GetDoc().SetTxtFmtColl( *rUndoIter.pAktPam, + (SwTxtFmtColl*)pFmtColl, + mbReset, + mbResetListAttrs ); + // <-- + } + + rUndoIter.pLastUndoObj = this; +} + +SwRewriter SwUndoFmtColl::GetRewriter() const +{ + SwRewriter aResult; + + // --> FME 2004-08-06 #i31191# Use stored format name instead of + // pFmtColl->GetName(), because pFmtColl does not have to be available + // anymore. + aResult.AddRule(UNDO_ARG1, aFmtName ); + // <-- + + return aResult; +} diff --git a/sw/source/core/undo/unins.cxx b/sw/source/core/undo/unins.cxx new file mode 100644 index 000000000000..dd95d06a34b1 --- /dev/null +++ b/sw/source/core/undo/unins.cxx @@ -0,0 +1,1100 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" +#include <hintids.hxx> +#include <unotools/charclass.hxx> +#include <sot/storage.hxx> +#include <editeng/keepitem.hxx> +#include <svx/svdobj.hxx> + +#include <docsh.hxx> +#include <fmtcntnt.hxx> +#include <fmtanchr.hxx> +#include <frmfmt.hxx> +#include <doc.hxx> +#include <swundo.hxx> // fuer die UndoIds +#include <pam.hxx> +#include <ndtxt.hxx> +#include <undobj.hxx> +#include <rolbck.hxx> +#include <ndgrf.hxx> +#include <ndole.hxx> +#include <grfatr.hxx> +#include <cntfrm.hxx> +#include <flyfrm.hxx> +#include <fesh.hxx> +#include <swtable.hxx> +#include <redline.hxx> +#include <docary.hxx> +#include <acorrect.hxx> +#include <dcontact.hxx> + +#include <comcore.hrc> // #111827# +#include <undo.hrc> + +using namespace ::com::sun::star; + + +class _UnReplaceData : private SwUndoSaveCntnt +{ + String m_sOld, m_sIns; + ULONG m_nSttNd, m_nEndNd, m_nOffset; + xub_StrLen m_nSttCnt, m_nEndCnt, m_nSetPos, m_nSelEnd; + BOOL m_bSplitNext : 1; + BOOL m_bRegExp : 1; + // metadata references for paragraph and following para (if m_bSplitNext) + ::boost::shared_ptr< ::sfx2::MetadatableUndo > m_pMetadataUndoStart; + ::boost::shared_ptr< ::sfx2::MetadatableUndo > m_pMetadataUndoEnd; + +public: + _UnReplaceData( const SwPaM& rPam, const String& rIns, BOOL bRegExp ); + ~_UnReplaceData(); + + void Undo( SwUndoIter& rIter ); + void Redo( SwUndoIter& rIter ); + void SetEnd( const SwPaM& rPam ); + + const String & GetOld() const { return m_sOld; } + const String & GetIns() const { return m_sIns; } +}; + + +SV_IMPL_PTRARR( _UnReplaceDatas, _UnReplaceData* ) + +//------------------------------------------------------------------ + +inline SwDoc& SwUndoIter::GetDoc() const { return *pAktPam->GetDoc(); } + +// zwei Zugriffs-Funktionen +inline SwPosition* IterPt( SwUndoIter& rUIter ) +{ return rUIter.pAktPam->GetPoint(); } +inline SwPosition* IterMk( SwUndoIter& rUIter ) +{ return rUIter.pAktPam->GetMark(); } + +//------------------------------------------------------------ + +// INSERT + +String * SwUndoInsert::GetTxtFromDoc() const +{ + String * pResult = NULL; + + SwNodeIndex aNd( pDoc->GetNodes(), nNode); + SwCntntNode* pCNd = aNd.GetNode().GetCntntNode(); + SwPaM aPaM( *pCNd, nCntnt ); + + aPaM.SetMark(); + + if( pCNd->IsTxtNode() ) + { + pResult = new String( ((SwTxtNode*)pCNd)->GetTxt().Copy(nCntnt-nLen, + nLen ) ); + + } + + return pResult; +} + +void SwUndoInsert::Init(const SwNodeIndex & rNd) +{ + // Redline beachten + pDoc = rNd.GetNode().GetDoc(); + if( pDoc->IsRedlineOn() ) + { + pRedlData = new SwRedlineData( nsRedlineType_t::REDLINE_INSERT, + pDoc->GetRedlineAuthor() ); + SetRedlineMode( pDoc->GetRedlineMode() ); + } + + pUndoTxt = GetTxtFromDoc(); + + bCacheComment = false; +} + +// #111827# +SwUndoInsert::SwUndoInsert( const SwNodeIndex& rNd, xub_StrLen nCnt, + xub_StrLen nL, + const IDocumentContentOperations::InsertFlags nInsertFlags, + BOOL bWDelim ) + : SwUndo(UNDO_TYPING), pPos( 0 ), pTxt( 0 ), pRedlData( 0 ), + nNode( rNd.GetIndex() ), nCntnt(nCnt), nLen(nL), + bIsWordDelim( bWDelim ), bIsAppend( FALSE ) + , m_nInsertFlags(nInsertFlags) +{ + Init(rNd); +} + +// #111827# +SwUndoInsert::SwUndoInsert( const SwNodeIndex& rNd ) + : SwUndo(UNDO_SPLITNODE), pPos( 0 ), pTxt( 0 ), + pRedlData( 0 ), nNode( rNd.GetIndex() ), nCntnt(0), nLen(1), + bIsWordDelim( FALSE ), bIsAppend( TRUE ) + , m_nInsertFlags(IDocumentContentOperations::INS_EMPTYEXPAND) +{ + Init(rNd); +} + +// stelle fest, ob das naechste Insert mit dem aktuellen zusammengefasst +// werden kann. Wenn ja, dann aender die Laenge und die InsPos. +// Dann wird von SwDoc::Insert kein neues Object in die Undoliste gestellt. + +BOOL SwUndoInsert::CanGrouping( sal_Unicode cIns ) +{ + if( !bIsAppend && bIsWordDelim == + !GetAppCharClass().isLetterNumeric( String( cIns )) ) + { + nLen++; + nCntnt++; + + if (pUndoTxt) + pUndoTxt->Insert(cIns); + + return TRUE; + } + return FALSE; +} + +BOOL SwUndoInsert::CanGrouping( const SwPosition& rPos ) +{ + BOOL bRet = FALSE; + if( nNode == rPos.nNode.GetIndex() && + nCntnt == rPos.nContent.GetIndex() ) + { + // Redline beachten + SwDoc& rDoc = *rPos.nNode.GetNode().GetDoc(); + if( ( ~nsRedlineMode_t::REDLINE_SHOW_MASK & rDoc.GetRedlineMode() ) == + ( ~nsRedlineMode_t::REDLINE_SHOW_MASK & GetRedlineMode() ) ) + { + bRet = TRUE; + + // dann war oder ist noch Redline an: + // pruefe, ob an der InsPosition ein anderer Redline + // rumsteht. Wenn der gleiche nur einmalig vorhanden ist, + // kann zusammen gefasst werden. + const SwRedlineTbl& rTbl = rDoc.GetRedlineTbl(); + if( rTbl.Count() ) + { + SwRedlineData aRData( nsRedlineType_t::REDLINE_INSERT, rDoc.GetRedlineAuthor() ); + const SwIndexReg* pIReg = rPos.nContent.GetIdxReg(); + SwIndex* pIdx; + for( USHORT i = 0; i < rTbl.Count(); ++i ) + { + SwRedline* pRedl = rTbl[ i ]; + if( pIReg == (pIdx = &pRedl->End()->nContent)->GetIdxReg() && + nCntnt == pIdx->GetIndex() ) + { + if( !pRedl->HasMark() || !pRedlData || + *pRedl != *pRedlData || *pRedl != aRData ) + { + bRet = FALSE; + break; + } + } + } + } + } + } + return bRet; +} + +SwUndoInsert::~SwUndoInsert() +{ + if( pPos ) // loesche noch den Bereich aus dem UndoNodes Array + { + // Insert speichert den Inhalt in der IconSection + SwNodes& rUNds = pPos->nNode.GetNode().GetNodes(); + if( pPos->nContent.GetIndex() ) // nicht den gesamten Node loeschen + { + SwTxtNode* pTxtNd = pPos->nNode.GetNode().GetTxtNode(); + ASSERT( pTxtNd, "kein TextNode, aus dem geloescht werden soll" ); + pTxtNd->EraseText( pPos->nContent ); + pPos->nNode++; + } + pPos->nContent.Assign( 0, 0 ); + rUNds.Delete( pPos->nNode, rUNds.GetEndOfExtras().GetIndex() - + pPos->nNode.GetIndex() ); + delete pPos; + } + else if( pTxt ) // der eingefuegte Text + delete pTxt; + delete pRedlData; +} + + + +void SwUndoInsert::Undo( SwUndoIter& rUndoIter ) +{ + SwDoc* pTmpDoc = &rUndoIter.GetDoc(); + + if( bIsAppend ) + { + SwPaM* pPam = rUndoIter.pAktPam; + pPam->GetPoint()->nNode = nNode; + + if( IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() )) + { + pPam->GetPoint()->nContent.Assign( pPam->GetCntntNode(), 0 ); + pPam->SetMark(); + pPam->Move( fnMoveBackward ); + pPam->Exchange(); + pTmpDoc->DeleteRedline( *pPam, true, USHRT_MAX ); + } + pPam->DeleteMark(); + pTmpDoc->DelFullPara( *pPam ); + pPam->GetPoint()->nContent.Assign( pPam->GetCntntNode(), 0 ); + } + else + { + ULONG nNd = nNode; + xub_StrLen nCnt = nCntnt; + if( nLen ) + { + SwNodeIndex aNd( pTmpDoc->GetNodes(), nNode); + SwCntntNode* pCNd = aNd.GetNode().GetCntntNode(); + SwPaM aPaM( *pCNd, nCntnt ); + + aPaM.SetMark(); + + SwTxtNode * const pTxtNode( pCNd->GetTxtNode() ); + if ( pTxtNode ) + { + aPaM.GetPoint()->nContent -= nLen; + if( IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() )) + pTmpDoc->DeleteRedline( aPaM, true, USHRT_MAX ); + RemoveIdxFromRange( aPaM, FALSE ); + pTxt = new String( pTxtNode->GetTxt().Copy(nCntnt-nLen, nLen) ); + pTxtNode->EraseText( aPaM.GetPoint()->nContent, nLen ); + } + else // ansonsten Grafik/OLE/Text/... + { + aPaM.Move(fnMoveBackward); + if( IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() )) + pTmpDoc->DeleteRedline( aPaM, true, USHRT_MAX ); + RemoveIdxFromRange( aPaM, FALSE ); + } + + nNd = aPaM.GetPoint()->nNode.GetIndex(); + nCnt = aPaM.GetPoint()->nContent.GetIndex(); + + if( !pTxt ) + { + pPos = new SwPosition( *aPaM.GetPoint() ); + MoveToUndoNds( aPaM, &pPos->nNode, &pPos->nContent ); + } + nNode = aPaM.GetPoint()->nNode.GetIndex(); + nCntnt = aPaM.GetPoint()->nContent.GetIndex(); + } + + // setze noch den Cursor auf den Undo-Bereich + rUndoIter.pAktPam->DeleteMark(); + + IterPt(rUndoIter)->nNode = nNd; + IterPt(rUndoIter)->nContent.Assign( pTmpDoc->GetNodes()[ + IterPt(rUndoIter)->nNode ]->GetCntntNode(), nCnt ); + // SPoint und GetMark auf der gleichen Position + } + + DELETEZ(pUndoTxt); +} + + +void SwUndoInsert::Redo( SwUndoIter& rUndoIter ) +{ + // setze noch den Cursor auf den Redo-Bereich + SwPaM* pPam = rUndoIter.pAktPam; + SwDoc* pTmpDoc = pPam->GetDoc(); + pPam->DeleteMark(); + + if( bIsAppend ) + { + pPam->GetPoint()->nNode = nNode - 1; + pTmpDoc->AppendTxtNode( *pPam->GetPoint() ); + + pPam->SetMark(); + pPam->Move( fnMoveBackward ); + pPam->Exchange(); + + if( pRedlData && IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() )) + { + RedlineMode_t eOld = pTmpDoc->GetRedlineMode(); + pTmpDoc->SetRedlineMode_intern((RedlineMode_t)(eOld & ~nsRedlineMode_t::REDLINE_IGNORE)); + pTmpDoc->AppendRedline( new SwRedline( *pRedlData, *pPam ), true); + pTmpDoc->SetRedlineMode_intern( eOld ); + } + else if( !( nsRedlineMode_t::REDLINE_IGNORE & GetRedlineMode() ) && + pTmpDoc->GetRedlineTbl().Count() ) + pTmpDoc->SplitRedline( *pPam ); + + pPam->DeleteMark(); + } + else + { + pPam->GetPoint()->nNode = nNode; + SwCntntNode* pCNd = pTmpDoc->GetNodes()[ pPam->GetPoint()->nNode ]->GetCntntNode(); + pPam->GetPoint()->nContent.Assign( pCNd, nCntnt ); + + if( nLen ) + { + BOOL bMvBkwrd = MovePtBackward( *pPam ); + + if( pTxt ) + { + SwTxtNode *const pTxtNode = pCNd->GetTxtNode(); + ASSERT( pTxtNode, "where is my textnode ?" ); + pTxtNode->InsertText( *pTxt, pPam->GetMark()->nContent, + m_nInsertFlags ); + DELETEZ( pTxt ); + } + else + { + // Inhalt wieder einfuegen. (erst pPos abmelden !!) + ULONG nMvNd = pPos->nNode.GetIndex(); + xub_StrLen nMvCnt = pPos->nContent.GetIndex(); + DELETEZ( pPos ); + MoveFromUndoNds( *pTmpDoc, nMvNd, nMvCnt, *pPam->GetMark() ); + } + nNode = pPam->GetMark()->nNode.GetIndex(); + nCntnt = pPam->GetMark()->nContent.GetIndex(); + + MovePtForward( *pPam, bMvBkwrd ); + rUndoIter.pAktPam->Exchange(); + if( pRedlData && IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() )) + { + RedlineMode_t eOld = pTmpDoc->GetRedlineMode(); + pTmpDoc->SetRedlineMode_intern((RedlineMode_t)(eOld & ~nsRedlineMode_t::REDLINE_IGNORE)); + pTmpDoc->AppendRedline( new SwRedline( *pRedlData, + *rUndoIter.pAktPam ), true); + pTmpDoc->SetRedlineMode_intern( eOld ); + } + else if( !( nsRedlineMode_t::REDLINE_IGNORE & GetRedlineMode() ) && + pTmpDoc->GetRedlineTbl().Count() ) + pTmpDoc->SplitRedline( *rUndoIter.pAktPam ); + } + } + + pUndoTxt = GetTxtFromDoc(); +} + + +void SwUndoInsert::Repeat( SwUndoIter& rUndoIter ) +{ + rUndoIter.pLastUndoObj = this; + if( !nLen ) + return; + + SwDoc& rDoc = rUndoIter.GetDoc(); + SwNodeIndex aNd( rDoc.GetNodes(), nNode ); + SwCntntNode* pCNd = aNd.GetNode().GetCntntNode();; + + if( !bIsAppend && 1 == nLen ) // >1 dann immer nur Text, ansonsten Grafik/OLE/Text/... + { + SwPaM aPaM( *pCNd, nCntnt ); + aPaM.SetMark(); + aPaM.Move(fnMoveBackward); + pCNd = aPaM.GetCntntNode(); + } + +// Was passiert mit dem evt. selektierten Bereich ??? + + switch( pCNd->GetNodeType() ) + { + case ND_TEXTNODE: + if( bIsAppend ) + rDoc.AppendTxtNode( *rUndoIter.pAktPam->GetPoint() ); + else + { + String aTxt( ((SwTxtNode*)pCNd)->GetTxt() ); + BOOL bGroupUndo = rDoc.DoesGroupUndo(); + rDoc.DoGroupUndo( FALSE ); + rDoc.InsertString( *rUndoIter.pAktPam, + aTxt.Copy( nCntnt - nLen, nLen ) ); + rDoc.DoGroupUndo( bGroupUndo ); + } + break; + case ND_GRFNODE: + { + SwGrfNode* pGrfNd = (SwGrfNode*)pCNd; + String sFile, sFilter; + if( pGrfNd->IsGrfLink() ) + pGrfNd->GetFileFilterNms( &sFile, &sFilter ); + + rDoc.Insert( *rUndoIter.pAktPam, sFile, sFilter, + &pGrfNd->GetGrf(), + 0/* Grafik-Collection*/, NULL, NULL ); + } + break; + + case ND_OLENODE: + { + // StarView bietet noch nicht die Moeglichkeit ein StarOBJ zu kopieren + SvStorageRef aRef = new SvStorage( aEmptyStr ); + SwOLEObj& rSwOLE = (SwOLEObj&)((SwOLENode*)pCNd)->GetOLEObj(); + + // temporary storage until object is inserted + // TODO/MBA: seems that here a physical copy is done - not as in drawing layer! Testing! + // TODO/LATER: Copying through the container would copy the replacement image as well + comphelper::EmbeddedObjectContainer aCnt; + ::rtl::OUString aName = aCnt.CreateUniqueObjectName(); + if ( aCnt.StoreEmbeddedObject( rSwOLE.GetOleRef(), aName, sal_True ) ) + { + uno::Reference < embed::XEmbeddedObject > aNew = aCnt.GetEmbeddedObject( aName ); + rDoc.Insert( *rUndoIter.pAktPam, svt::EmbeddedObjectRef( aNew, ((SwOLENode*)pCNd)->GetAspect() ), NULL, NULL, NULL ); + } + + break; + } + } +} + +// #111827# +SwRewriter SwUndoInsert::GetRewriter() const +{ + SwRewriter aResult; + String * pStr = NULL; + bool bDone = false; + + if (pTxt) + pStr = pTxt; + else if (pUndoTxt) + pStr = pUndoTxt; + + if (pStr) + { + String aString = ShortenString(DenoteSpecialCharacters(*pStr), + nUndoStringLength, + String(SW_RES(STR_LDOTS))); + + aResult.AddRule(UNDO_ARG1, aString); + + bDone = true; + } + + if ( ! bDone ) + { + aResult.AddRule(UNDO_ARG1, String("??", RTL_TEXTENCODING_ASCII_US)); + } + + return aResult; +} + + +/* */ + +SwUndoReplace::SwUndoReplace() + : SwUndo( UNDO_REPLACE ), nAktPos( USHRT_MAX ) +{ +} + +SwUndoReplace::~SwUndoReplace() +{ +} + +void SwUndoReplace::Undo( SwUndoIter& rUndoIter ) +{ + // war dieses nicht die letze Undo-Aktion, dann setze den + // Count neu + if( rUndoIter.pLastUndoObj != this ) + { + nAktPos = aArr.Count(); + rUndoIter.pLastUndoObj = this; + bOldIterFlag = rUndoIter.bWeiter; + rUndoIter.bWeiter = TRUE; + } + + aArr[ --nAktPos ]->Undo( rUndoIter ); + + if( !nAktPos ) // alten Status wieder zurueck + rUndoIter.bWeiter = bOldIterFlag; +} + + +void SwUndoReplace::Redo( SwUndoIter& rUndoIter ) +{ + // war dieses nicht die letze Undo-Aktion, dann setze den + // Count neu + if( rUndoIter.pLastUndoObj != this ) + { + ASSERT( !nAktPos, "Redo ohne vorheriges Undo??" ); + rUndoIter.pLastUndoObj = this; + bOldIterFlag = rUndoIter.bWeiter; + rUndoIter.bWeiter = TRUE; + } + + aArr[ nAktPos ]->Redo( rUndoIter ); + + if( ++nAktPos >= aArr.Count() ) // alten Status wieder zurueck + { + nAktPos = USHRT_MAX; + rUndoIter.bWeiter = bOldIterFlag; + } +} + +// #111827# +SwRewriter SwUndoReplace::GetRewriter() const +{ + SwRewriter aResult; + + if (aArr.Count() > 1) + { + aResult.AddRule(UNDO_ARG1, String::CreateFromInt32(aArr.Count())); + aResult.AddRule(UNDO_ARG2, String(SW_RES(STR_OCCURRENCES_OF))); + + String aTmpStr; + aTmpStr += String(SW_RES(STR_START_QUOTE)); + aTmpStr += ShortenString(aArr[0]->GetOld(), nUndoStringLength, + SW_RES(STR_LDOTS)); + aTmpStr += String(SW_RES(STR_END_QUOTE)); + aResult.AddRule(UNDO_ARG3, aTmpStr); + } + else if (aArr.Count() == 1) + { + { + String aTmpStr; + + aTmpStr += String(SW_RES(STR_START_QUOTE)); + // #i33488 # + aTmpStr += ShortenString(aArr[0]->GetOld(), nUndoStringLength, + SW_RES(STR_LDOTS)); + aTmpStr += String(SW_RES(STR_END_QUOTE)); + aResult.AddRule(UNDO_ARG1, aTmpStr); + } + + aResult.AddRule(UNDO_ARG2, String(SW_RES(STR_YIELDS))); + + { + String aTmpStr; + + aTmpStr += String(SW_RES(STR_START_QUOTE)); + // #i33488 # + aTmpStr += ShortenString(aArr[0]->GetIns(), nUndoStringLength, + SW_RES(STR_LDOTS)); + aTmpStr += String(SW_RES(STR_END_QUOTE)); + aResult.AddRule(UNDO_ARG3, aTmpStr); + } + } + + return aResult; +} + +void SwUndoReplace::AddEntry( const SwPaM& rPam, const String& rInsert, + BOOL bRegExp ) +{ + _UnReplaceData* pNew = new _UnReplaceData( rPam, rInsert, bRegExp ); + aArr.C40_INSERT(_UnReplaceData, pNew, aArr.Count() ); +} + +void SwUndoReplace::SetEntryEnd( const SwPaM& rPam ) +{ + _UnReplaceData* pEntry = aArr[ aArr.Count()-1 ]; + pEntry->SetEnd( rPam ); +} + +_UnReplaceData::_UnReplaceData( const SwPaM& rPam, const String& rIns, + BOOL bRgExp ) + : m_sIns( rIns ), m_nOffset( 0 ) +{ + m_bRegExp = bRgExp; + + const SwPosition * pStt( rPam.Start() ); + const SwPosition * pEnd( rPam.End() ); + + m_nSttNd = m_nEndNd = pStt->nNode.GetIndex(); + m_nSttCnt = pStt->nContent.GetIndex(); + m_nSelEnd = m_nEndCnt = pEnd->nContent.GetIndex(); + + m_bSplitNext = m_nSttNd != pEnd->nNode.GetIndex(); + + SwTxtNode* pNd = pStt->nNode.GetNode().GetTxtNode(); + ASSERT( pNd, "wo ist der TextNode" ); + + pHistory = new SwHistory; + DelCntntIndex( *rPam.GetMark(), *rPam.GetPoint() ); + + m_nSetPos = pHistory->Count(); + + ULONG nNewPos = pStt->nNode.GetIndex(); + m_nOffset = m_nSttNd - nNewPos; + + if ( pNd->GetpSwpHints() ) + { + pHistory->CopyAttr( pNd->GetpSwpHints(), nNewPos, 0, + pNd->GetTxt().Len(), true ); + } + + if ( m_bSplitNext ) + { + if( pNd->HasSwAttrSet() ) + pHistory->CopyFmtAttr( *pNd->GetpSwAttrSet(), nNewPos ); + pHistory->Add( pNd->GetTxtColl(), nNewPos, ND_TEXTNODE ); + + SwTxtNode* pNext = pEnd->nNode.GetNode().GetTxtNode(); + ULONG nTmp = pNext->GetIndex(); + pHistory->CopyAttr( pNext->GetpSwpHints(), nTmp, 0, + pNext->GetTxt().Len(), true ); + if( pNext->HasSwAttrSet() ) + pHistory->CopyFmtAttr( *pNext->GetpSwAttrSet(), nTmp ); + pHistory->Add( pNext->GetTxtColl(),nTmp, ND_TEXTNODE ); + // METADATA: store + m_pMetadataUndoStart = pNd ->CreateUndo(); + m_pMetadataUndoEnd = pNext->CreateUndo(); + } + + if( !pHistory->Count() ) + delete pHistory, pHistory = 0; + + xub_StrLen nECnt = m_bSplitNext ? pNd->GetTxt().Len() + : pEnd->nContent.GetIndex(); + m_sOld = pNd->GetTxt().Copy( m_nSttCnt, nECnt - m_nSttCnt ); +} + +_UnReplaceData::~_UnReplaceData() +{ +} + +void _UnReplaceData::Undo( SwUndoIter& rIter ) +{ + SwDoc* pDoc = &rIter.GetDoc(); + SwPaM& rPam = *rIter.pAktPam; + rPam.DeleteMark(); + + SwTxtNode* pNd = pDoc->GetNodes()[ m_nSttNd - m_nOffset ]->GetTxtNode(); + ASSERT( pNd, "Wo ist der TextNode geblieben?" ) + + SwAutoCorrExceptWord* pACEWord = pDoc->GetAutoCorrExceptWord(); + if( pACEWord ) + { + if( 1 == m_sIns.Len() && 1 == m_sOld.Len() ) + { + SwPosition aPos( *pNd ); aPos.nContent.Assign( pNd, m_nSttCnt ); + pACEWord->CheckChar( aPos, m_sOld.GetChar( 0 ) ); + } + pDoc->SetAutoCorrExceptWord( 0 ); + } + + SwIndex aIdx( pNd, m_nSttCnt ); + if( m_nSttNd == m_nEndNd ) + { + pNd->EraseText( aIdx, m_sIns.Len() ); + } + else + { + rPam.GetPoint()->nNode = *pNd; + rPam.GetPoint()->nContent.Assign( pNd, m_nSttCnt ); + rPam.SetMark(); + rPam.GetPoint()->nNode = m_nEndNd - m_nOffset; + rPam.GetPoint()->nContent.Assign( rPam.GetCntntNode(), m_nEndCnt ); + + pDoc->DeleteAndJoin( rPam ); + rPam.DeleteMark(); + pNd = rPam.GetNode()->GetTxtNode(); + ASSERT( pNd, "Wo ist der TextNode geblieben?" ); + aIdx.Assign( pNd, m_nSttCnt ); + } + + if( m_bSplitNext ) + { + SwPosition aPos( *pNd, aIdx ); + pDoc->SplitNode( aPos, false ); + pNd->RestoreMetadata(m_pMetadataUndoEnd); + pNd = pDoc->GetNodes()[ m_nSttNd - m_nOffset ]->GetTxtNode(); + aIdx.Assign( pNd, m_nSttCnt ); + // METADATA: restore + pNd->RestoreMetadata(m_pMetadataUndoStart); + } + + if( m_sOld.Len() ) + { + pNd->InsertText( m_sOld, aIdx ); + } + + if( pHistory ) + { + if( pNd->GetpSwpHints() ) + pNd->ClearSwpHintsArr( true ); + + pHistory->TmpRollback( pDoc, m_nSetPos, false ); + if ( m_nSetPos ) // there were footnotes/FlyFrames + { + // gibts ausser diesen noch andere ? + if( m_nSetPos < pHistory->Count() ) + { + // dann sicher die Attribute anderen Attribute + SwHistory aHstr; + aHstr.Move( 0, pHistory, m_nSetPos ); + pHistory->Rollback( pDoc ); + pHistory->Move( 0, &aHstr ); + } + else + { + pHistory->Rollback( pDoc ); + DELETEZ( pHistory ); + } + } + } + + rPam.GetPoint()->nNode = m_nSttNd; + rPam.GetPoint()->nContent = aIdx; +} + +void _UnReplaceData::Redo( SwUndoIter& rIter ) +{ + SwDoc& rDoc = rIter.GetDoc(); + BOOL bUndo = rDoc.DoesUndo(); + rDoc.DoUndo( FALSE ); + + SwPaM& rPam = *rIter.pAktPam; + rPam.DeleteMark(); + rPam.GetPoint()->nNode = m_nSttNd; + + SwTxtNode* pNd = rPam.GetPoint()->nNode.GetNode().GetTxtNode(); + ASSERT( pNd, "Wo ist der TextNode geblieben?" ) + rPam.GetPoint()->nContent.Assign( pNd, m_nSttCnt ); + rPam.SetMark(); + if( m_bSplitNext ) + { + rPam.GetPoint()->nNode = m_nSttNd + 1; + pNd = rPam.GetPoint()->nNode.GetNode().GetTxtNode(); + } + rPam.GetPoint()->nContent.Assign( pNd, m_nSelEnd ); + + if( pHistory ) + { + SwHistory* pSave = pHistory; + SwHistory aHst; + pHistory = &aHst; + DelCntntIndex( *rPam.GetMark(), *rPam.GetPoint() ); + m_nSetPos = pHistory->Count(); + + pHistory = pSave; + pHistory->Move( 0, &aHst ); + } + else + { + pHistory = new SwHistory; + DelCntntIndex( *rPam.GetMark(), *rPam.GetPoint() ); + m_nSetPos = pHistory->Count(); + if( !m_nSetPos ) + delete pHistory, pHistory = 0; + } + + rDoc.ReplaceRange( rPam, m_sIns, m_bRegExp ); + rPam.DeleteMark(); + rDoc.DoUndo( bUndo ); +} + +void _UnReplaceData::SetEnd( const SwPaM& rPam ) +{ + if( rPam.GetPoint()->nNode != rPam.GetMark()->nNode ) + { + // es wurden mehrere Absaetze eingefuegt + const SwPosition* pEnd = rPam.End(); + m_nEndNd = m_nOffset + pEnd->nNode.GetIndex(); + m_nEndCnt = pEnd->nContent.GetIndex(); + } +} + +/* */ + + +SwUndoReRead::SwUndoReRead( const SwPaM& rPam, const SwGrfNode& rGrfNd ) + : SwUndo( UNDO_REREAD ), nPos( rPam.GetPoint()->nNode.GetIndex() ) +{ + SaveGraphicData( rGrfNd ); +} + + +SwUndoReRead::~SwUndoReRead() +{ + delete pGrf; + delete pNm; + delete pFltr; +} + + +void SwUndoReRead::SetAndSave( SwUndoIter& rIter ) +{ + SwDoc& rDoc = rIter.GetDoc(); + SwGrfNode* pGrfNd = rDoc.GetNodes()[ nPos ]->GetGrfNode(); + + if( !pGrfNd ) + return ; + + // die alten Werte zwischen speichern + Graphic* pOldGrf = pGrf; + String* pOldNm = pNm; + String* pOldFltr = pFltr; + USHORT nOldMirr = nMirr; + + SaveGraphicData( *pGrfNd ); + if( pOldNm ) + { + pGrfNd->ReRead( *pOldNm, pFltr ? *pFltr : aEmptyStr, 0, 0, TRUE ); + delete pOldNm; + delete pOldFltr; + } + else + { + pGrfNd->ReRead( aEmptyStr, aEmptyStr, pOldGrf, 0, TRUE ); + delete pOldGrf; + } + + if( RES_MIRROR_GRAPH_DONT != nOldMirr ) + pGrfNd->SetAttr( SwMirrorGrf() ); + + rIter.pSelFmt = pGrfNd->GetFlyFmt(); +} + + +void SwUndoReRead::Undo( SwUndoIter& rIter ) +{ + SetAndSave( rIter ); +} + + +void SwUndoReRead::Redo( SwUndoIter& rIter ) +{ + SetAndSave( rIter ); +} + + +void SwUndoReRead::SaveGraphicData( const SwGrfNode& rGrfNd ) +{ + if( rGrfNd.IsGrfLink() ) + { + pNm = new String; + pFltr = new String; + rGrfNd.GetFileFilterNms( pNm, pFltr ); + pGrf = 0; + } + else + { + ((SwGrfNode&)rGrfNd).SwapIn( TRUE ); + pGrf = new Graphic( rGrfNd.GetGrf() ); + pNm = pFltr = 0; + } + nMirr = rGrfNd.GetSwAttrSet().GetMirrorGrf().GetValue(); +} + +/* */ + +SwUndoInsertLabel::SwUndoInsertLabel( const SwLabelType eTyp, + const String &rTxt, + const String& rSeparator, + const String& rNumberSeparator, + const BOOL bBef, + const USHORT nInitId, + const String& rCharacterStyle, + const BOOL bCpyBorder ) + : SwUndo( UNDO_INSERTLABEL ), + sText( rTxt ), + sSeparator( rSeparator ), + sNumberSeparator( rNumberSeparator ),//#i61007# order of captions + sCharacterStyle( rCharacterStyle ), + nFldId( nInitId ), + eType( eTyp ), + nLayerId( 0 ), + bBefore( bBef ), + bCpyBrd( bCpyBorder ) +{ + bUndoKeep = FALSE; + OBJECT.pUndoFly = 0; + OBJECT.pUndoAttr = 0; +} + +SwUndoInsertLabel::~SwUndoInsertLabel() +{ + if( LTYPE_OBJECT == eType || LTYPE_DRAW == eType ) + { + delete OBJECT.pUndoFly; + delete OBJECT.pUndoAttr; + } + else + delete NODE.pUndoInsNd; +} + +void SwUndoInsertLabel::Undo( SwUndoIter& rIter ) +{ + SwDoc& rDoc = rIter.GetDoc(); + + if( LTYPE_OBJECT == eType || LTYPE_DRAW == eType ) + { + ASSERT( OBJECT.pUndoAttr && OBJECT.pUndoFly, "Pointer nicht initialisiert" ) + SwFrmFmt* pFmt; + SdrObject *pSdrObj = 0; + if( OBJECT.pUndoAttr && + 0 != (pFmt = (SwFrmFmt*)OBJECT.pUndoAttr->GetFmt( rDoc )) && + ( LTYPE_DRAW != eType || + 0 != (pSdrObj = pFmt->FindSdrObject()) ) ) + { + OBJECT.pUndoAttr->Undo( rIter ); + OBJECT.pUndoFly->Undo( rIter ); + if( LTYPE_DRAW == eType ) + { + pSdrObj->SetLayer( nLayerId ); + } + } + } + else if( NODE.nNode ) + { + if ( eType == LTYPE_TABLE && bUndoKeep ) + { + SwTableNode *pNd = rDoc.GetNodes()[ + rDoc.GetNodes()[NODE.nNode-1]->StartOfSectionIndex()]->GetTableNode(); + if ( pNd ) + pNd->GetTable().GetFrmFmt()->ResetFmtAttr( RES_KEEP ); + } + SwPaM aPam( *rIter.pAktPam->GetPoint() ); + aPam.GetPoint()->nNode = NODE.nNode; + aPam.SetMark(); + aPam.GetPoint()->nNode = NODE.nNode + 1; + NODE.pUndoInsNd = new SwUndoDelete( aPam, TRUE ); + } +} + + +void SwUndoInsertLabel::Redo( SwUndoIter& rIter ) +{ + SwDoc& rDoc = rIter.GetDoc(); + + if( LTYPE_OBJECT == eType || LTYPE_DRAW == eType ) + { + ASSERT( OBJECT.pUndoAttr && OBJECT.pUndoFly, "Pointer nicht initialisiert" ) + SwFrmFmt* pFmt; + SdrObject *pSdrObj = 0; + if( OBJECT.pUndoAttr && + 0 != (pFmt = (SwFrmFmt*)OBJECT.pUndoAttr->GetFmt( rDoc )) && + ( LTYPE_DRAW != eType || + 0 != (pSdrObj = pFmt->FindSdrObject()) ) ) + { + OBJECT.pUndoFly->Redo( rIter ); + OBJECT.pUndoAttr->Redo( rIter ); + if( LTYPE_DRAW == eType ) + { + pSdrObj->SetLayer( nLayerId ); + if( pSdrObj->GetLayer() == rDoc.GetHellId() ) + pSdrObj->SetLayer( rDoc.GetHeavenId() ); + // OD 02.07.2003 #108784# + else if( pSdrObj->GetLayer() == rDoc.GetInvisibleHellId() ) + pSdrObj->SetLayer( rDoc.GetInvisibleHeavenId() ); + } + } + } + else if( NODE.pUndoInsNd ) + { + if ( eType == LTYPE_TABLE && bUndoKeep ) + { + SwTableNode *pNd = rDoc.GetNodes()[ + rDoc.GetNodes()[NODE.nNode-1]->StartOfSectionIndex()]->GetTableNode(); + if ( pNd ) + pNd->GetTable().GetFrmFmt()->SetFmtAttr( SvxFmtKeepItem(TRUE, RES_KEEP) ); + } + NODE.pUndoInsNd->Undo( rIter ); + delete NODE.pUndoInsNd, NODE.pUndoInsNd = 0; + } +} + +void SwUndoInsertLabel::Repeat( SwUndoIter& rIter ) +{ + SwDoc& rDoc = rIter.GetDoc(); + const SwPosition& rPos = *rIter.pAktPam->GetPoint(); + + ULONG nIdx = 0; + + SwCntntNode* pCNd = rPos.nNode.GetNode().GetCntntNode(); + if( pCNd ) + switch( eType ) + { + case LTYPE_TABLE: + { + const SwTableNode* pTNd = pCNd->FindTableNode(); + if( pTNd ) + nIdx = pTNd->GetIndex(); + } + break; + + case LTYPE_FLY: + case LTYPE_OBJECT: + { + SwFlyFrm* pFly; + SwCntntFrm *pCnt = pCNd->GetFrm(); + if( pCnt && 0 != ( pFly = pCnt->FindFlyFrm() ) ) + nIdx = pFly->GetFmt()->GetCntnt().GetCntntIdx()->GetIndex(); + } + break; + case LTYPE_DRAW: + break; + } + + if( nIdx ) + { + rDoc.InsertLabel( eType, sText, sSeparator, sNumberSeparator, bBefore, + nFldId, nIdx, sCharacterStyle, bCpyBrd ); + } +} + +// #111827# +SwRewriter SwUndoInsertLabel::GetRewriter() const +{ + SwRewriter aRewriter; + + String aTmpStr; + + aTmpStr += String(SW_RES(STR_START_QUOTE)); + aTmpStr += ShortenString(sText, nUndoStringLength, + String(SW_RES(STR_LDOTS))); + aTmpStr += String(SW_RES(STR_END_QUOTE)); + + aRewriter.AddRule(UNDO_ARG1, aTmpStr); + + return aRewriter; +} + +void SwUndoInsertLabel::SetFlys( SwFrmFmt& rOldFly, SfxItemSet& rChgSet, + SwFrmFmt& rNewFly ) +{ + if( LTYPE_OBJECT == eType || LTYPE_DRAW == eType ) + { + SwUndoFmtAttrHelper aTmp( rOldFly, false ); + rOldFly.SetFmtAttr( rChgSet ); + if ( aTmp.GetUndo() ) + { + OBJECT.pUndoAttr = aTmp.ReleaseUndo(); + } + OBJECT.pUndoFly = new SwUndoInsLayFmt( &rNewFly,0,0 ); + } +} + +void SwUndoInsertLabel::SetDrawObj( BYTE nLId ) +{ + if( LTYPE_DRAW == eType ) + { + nLayerId = nLId; + } +} + diff --git a/sw/source/core/undo/unmove.cxx b/sw/source/core/undo/unmove.cxx new file mode 100644 index 000000000000..4c5fbca4085c --- /dev/null +++ b/sw/source/core/undo/unmove.cxx @@ -0,0 +1,356 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <doc.hxx> +#include <pam.hxx> +#include <swundo.hxx> // fuer die UndoIds +#include <ndtxt.hxx> +#include <undobj.hxx> +#include <rolbck.hxx> + + +inline SwDoc& SwUndoIter::GetDoc() const { return *pAktPam->GetDoc(); } + +// MOVE + +SwUndoMove::SwUndoMove( const SwPaM& rRange, const SwPosition& rMvPos ) + : SwUndo( UNDO_MOVE ), SwUndRng( rRange ), + nMvDestNode( rMvPos.nNode.GetIndex() ), + nMvDestCntnt( rMvPos.nContent.GetIndex() ), + bMoveRedlines( false ) +{ + bMoveRange = bJoinNext = bJoinPrev = FALSE; + + // StartNode vorm loeschen von Fussnoten besorgen! + SwDoc* pDoc = rRange.GetDoc(); + SwTxtNode* pTxtNd = pDoc->GetNodes()[ nSttNode ]->GetTxtNode(); + SwTxtNode* pEndTxtNd = pDoc->GetNodes()[ nEndNode ]->GetTxtNode(); + + pHistory = new SwHistory; + + if( pTxtNd ) + { + pHistory->Add( pTxtNd->GetTxtColl(), nSttNode, ND_TEXTNODE ); + if ( pTxtNd->GetpSwpHints() ) + { + pHistory->CopyAttr( pTxtNd->GetpSwpHints(), nSttNode, + 0, pTxtNd->GetTxt().Len(), false ); + } + if( pTxtNd->HasSwAttrSet() ) + pHistory->CopyFmtAttr( *pTxtNd->GetpSwAttrSet(), nSttNode ); + } + if( pEndTxtNd && pEndTxtNd != pTxtNd ) + { + pHistory->Add( pEndTxtNd->GetTxtColl(), nEndNode, ND_TEXTNODE ); + if ( pEndTxtNd->GetpSwpHints() ) + { + pHistory->CopyAttr( pEndTxtNd->GetpSwpHints(), nEndNode, + 0, pEndTxtNd->GetTxt().Len(), false ); + } + if( pEndTxtNd->HasSwAttrSet() ) + pHistory->CopyFmtAttr( *pEndTxtNd->GetpSwAttrSet(), nEndNode ); + } + + if( 0 != (pTxtNd = rRange.GetDoc()->GetNodes()[ rMvPos.nNode ]->GetTxtNode() )) + { + pHistory->Add( pTxtNd->GetTxtColl(), nMvDestNode, ND_TEXTNODE ); + if ( pTxtNd->GetpSwpHints() ) + { + pHistory->CopyAttr( pTxtNd->GetpSwpHints(), nMvDestNode, + 0, pTxtNd->GetTxt().Len(), false ); + } + if( pTxtNd->HasSwAttrSet() ) + pHistory->CopyFmtAttr( *pTxtNd->GetpSwAttrSet(), nMvDestNode ); + } + + + nFtnStt = pHistory->Count(); + DelFtn( rRange ); + + if( pHistory && !pHistory->Count() ) + DELETEZ( pHistory ); +} + + +SwUndoMove::SwUndoMove( SwDoc* pDoc, const SwNodeRange& rRg, + const SwNodeIndex& rMvPos ) + : SwUndo( UNDO_MOVE ), + nMvDestNode( rMvPos.GetIndex() ), + bMoveRedlines( false ) +{ + bMoveRange = TRUE; + bJoinNext = bJoinPrev = FALSE; + + nSttCntnt = nEndCntnt = nMvDestCntnt = STRING_MAXLEN; + + nSttNode = rRg.aStart.GetIndex(); + nEndNode = rRg.aEnd.GetIndex(); + +// DelFtn( rRange ); + + // wird aus dem CntntBereich in den Sonderbereich verschoben ? + ULONG nCntntStt = pDoc->GetNodes().GetEndOfAutotext().GetIndex(); + if( nMvDestNode < nCntntStt && rRg.aStart.GetIndex() > nCntntStt ) + { + // loesche alle Fussnoten. Diese sind dort nicht erwuenscht. + SwPosition aPtPos( rRg.aEnd ); + SwCntntNode* pCNd = rRg.aEnd.GetNode().GetCntntNode(); + if( pCNd ) + aPtPos.nContent.Assign( pCNd, pCNd->Len() ); + SwPosition aMkPos( rRg.aStart ); + if( 0 != ( pCNd = aMkPos.nNode.GetNode().GetCntntNode() )) + aMkPos.nContent.Assign( pCNd, 0 ); + + DelCntntIndex( aMkPos, aPtPos, nsDelCntntType::DELCNT_FTN ); + + if( pHistory && !pHistory->Count() ) + DELETEZ( pHistory ); + } + + nFtnStt = 0; +} + + + +void SwUndoMove::SetDestRange( const SwPaM& rRange, + const SwPosition& rInsPos, + BOOL bJoin, BOOL bCorrPam ) +{ + const SwPosition *pStt = rRange.Start(), + *pEnd = rRange.GetPoint() == pStt + ? rRange.GetMark() + : rRange.GetPoint(); + + nDestSttNode = pStt->nNode.GetIndex(); + nDestSttCntnt = pStt->nContent.GetIndex(); + nDestEndNode = pEnd->nNode.GetIndex(); + nDestEndCntnt = pEnd->nContent.GetIndex(); + + nInsPosNode = rInsPos.nNode.GetIndex(); + nInsPosCntnt = rInsPos.nContent.GetIndex(); + + if( bCorrPam ) + { + nDestSttNode--; + nDestEndNode--; + } + + bJoinNext = nDestSttNode != nDestEndNode && + pStt->nNode.GetNode().GetTxtNode() && + pEnd->nNode.GetNode().GetTxtNode(); + bJoinPrev = bJoin; +} + + +void SwUndoMove::SetDestRange( const SwNodeIndex& rStt, + const SwNodeIndex& rEnd, + const SwNodeIndex& rInsPos ) +{ + nDestSttNode = rStt.GetIndex(); + nDestEndNode = rEnd.GetIndex(); + if( nDestSttNode > nDestEndNode ) + { + nDestSttNode = nDestEndNode; + nDestEndNode = rStt.GetIndex(); + } + nInsPosNode = rInsPos.GetIndex(); + + nDestSttCntnt = nDestEndCntnt = nInsPosCntnt = STRING_MAXLEN; +} + + +void SwUndoMove::Undo( SwUndoIter& rUndoIter ) +{ + SwDoc* pDoc = &rUndoIter.GetDoc(); + BOOL bUndo = pDoc->DoesUndo(); + pDoc->DoUndo( FALSE ); + + // Block, damit aus diesem gesprungen werden kann + do { + // erzeuge aus den Werten die Insert-Position und den Bereich + SwNodeIndex aIdx( pDoc->GetNodes(), nDestSttNode ); + + if( bMoveRange ) + { + // nur ein Move mit SwRange + SwNodeRange aRg( aIdx, aIdx ); + aRg.aEnd = nDestEndNode; + aIdx = nInsPosNode; + bool bSuccess = pDoc->MoveNodeRange( aRg, aIdx, + IDocumentContentOperations::DOC_MOVEDEFAULT ); + if (!bSuccess) + break; + } + else + { + SwPaM aPam( aIdx.GetNode(), nDestSttCntnt, + *pDoc->GetNodes()[ nDestEndNode ], nDestEndCntnt ); + + // #i17764# if redlines are to be moved, we may not remove them before + // pDoc->Move gets a chance to handle them + if( ! bMoveRedlines ) + RemoveIdxFromRange( aPam, FALSE ); + + SwPosition aPos( *pDoc->GetNodes()[ nInsPosNode] ); + SwCntntNode* pCNd = aPos.nNode.GetNode().GetCntntNode(); + aPos.nContent.Assign( pCNd, nInsPosCntnt ); + + if( pCNd->HasSwAttrSet() ) + pCNd->ResetAllAttr(); + + if( pCNd->IsTxtNode() && ((SwTxtNode*)pCNd)->GetpSwpHints() ) + ((SwTxtNode*)pCNd)->ClearSwpHintsArr( false ); + + // an der InsertPos erstmal alle Attribute entfernen, + const bool bSuccess = pDoc->MoveRange( aPam, aPos, (bMoveRedlines) + ? IDocumentContentOperations::DOC_MOVEREDLINES + : IDocumentContentOperations::DOC_MOVEDEFAULT ); + if (!bSuccess) + break; + + aPam.Exchange(); + aPam.DeleteMark(); +// pDoc->ResetAttr( aPam, FALSE ); + if( aPam.GetNode()->IsCntntNode() ) + aPam.GetNode()->GetCntntNode()->ResetAllAttr(); + // der Pam wird jetzt aufgegeben. + } + + SwTxtNode* pTxtNd = aIdx.GetNode().GetTxtNode(); + if( bJoinNext ) + { + { + RemoveIdxRel( aIdx.GetIndex() + 1, SwPosition( aIdx, + SwIndex( pTxtNd, pTxtNd->GetTxt().Len() ) ) ); + } + // sind keine Pams mehr im naechsten TextNode + pTxtNd->JoinNext(); + } + + if( bJoinPrev && pTxtNd->CanJoinPrev( &aIdx ) ) + { + // ?? sind keine Pams mehr im naechsten TextNode ?? + pTxtNd = aIdx.GetNode().GetTxtNode(); + { + RemoveIdxRel( aIdx.GetIndex() + 1, SwPosition( aIdx, + SwIndex( pTxtNd, pTxtNd->GetTxt().Len() ) ) ); + } + pTxtNd->JoinNext(); + } + + } while( FALSE ); + + if( pHistory ) + { + if( nFtnStt != pHistory->Count() ) + pHistory->Rollback( pDoc, nFtnStt ); + pHistory->TmpRollback( pDoc, 0 ); + pHistory->SetTmpEnd( pHistory->Count() ); + } + + pDoc->DoUndo( bUndo ); + + // setze noch den Cursor auf den Undo-Bereich + if( !bMoveRange ) + SetPaM( rUndoIter ); +} + + +void SwUndoMove::Redo( SwUndoIter& rUndoIter ) +{ + SwPaM* pPam = rUndoIter.pAktPam; + SwDoc& rDoc = *pPam->GetDoc(); + + SwNodes& rNds = rDoc.GetNodes(); + SwNodeIndex aIdx( rNds, nMvDestNode ); + + if( bMoveRange ) + { + // nur ein Move mit SwRange + SwNodeRange aRg( rNds, nSttNode, rNds, nEndNode ); + rDoc.MoveNodeRange( aRg, aIdx, (bMoveRedlines) + ? IDocumentContentOperations::DOC_MOVEREDLINES + : IDocumentContentOperations::DOC_MOVEDEFAULT ); + } + else + { + SwPaM aPam( *pPam->GetPoint() ); + SetPaM( aPam ); + SwPosition aMvPos( aIdx, SwIndex( aIdx.GetNode().GetCntntNode(), + nMvDestCntnt )); + + DelFtn( aPam ); + RemoveIdxFromRange( aPam, FALSE ); + + aIdx = aPam.Start()->nNode; + BOOL bJoinTxt = aIdx.GetNode().IsTxtNode(); + + aIdx--; + rDoc.MoveRange( aPam, aMvPos, + IDocumentContentOperations::DOC_MOVEDEFAULT ); + + if( nSttNode != nEndNode && bJoinTxt ) + { + aIdx++; + SwTxtNode * pTxtNd = aIdx.GetNode().GetTxtNode(); + if( pTxtNd && pTxtNd->CanJoinNext() ) + { + { + RemoveIdxRel( aIdx.GetIndex() + 1, SwPosition( aIdx, + SwIndex( pTxtNd, pTxtNd->GetTxt().Len() ) ) ); + } + pTxtNd->JoinNext(); + } + } + *pPam->GetPoint() = *aPam.GetPoint(); + pPam->SetMark(); + *pPam->GetMark() = *aPam.GetMark(); + } +} + + +void SwUndoMove::DelFtn( const SwPaM& rRange ) +{ + // wird aus dem CntntBereich in den Sonderbereich verschoben ? + SwDoc* pDoc = rRange.GetDoc(); + ULONG nCntntStt = pDoc->GetNodes().GetEndOfAutotext().GetIndex(); + if( nMvDestNode < nCntntStt && + rRange.GetPoint()->nNode.GetIndex() >= nCntntStt ) + { + // loesche alle Fussnoten. Diese sind dort nicht erwuenscht. + DelCntntIndex( *rRange.GetMark(), *rRange.GetPoint(), + nsDelCntntType::DELCNT_FTN ); + + if( pHistory && !pHistory->Count() ) + delete pHistory, pHistory = 0; + } +} + diff --git a/sw/source/core/undo/unnum.cxx b/sw/source/core/undo/unnum.cxx new file mode 100644 index 000000000000..e7885db39b5f --- /dev/null +++ b/sw/source/core/undo/unnum.cxx @@ -0,0 +1,466 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <hintids.hxx> +#include <editeng/lrspitem.hxx> +#include <doc.hxx> +#include <swundo.hxx> // fuer die UndoIds +#include <pam.hxx> +#include <ndtxt.hxx> +#include <undobj.hxx> +#include <rolbck.hxx> + + +SV_DECL_PTRARR_DEL( _SfxPoolItems, SfxPoolItem*, 16, 16 ) +SV_IMPL_PTRARR( _SfxPoolItems, SfxPoolItem* ); + +inline SwDoc& SwUndoIter::GetDoc() const { return *pAktPam->GetDoc(); } + +SwUndoInsNum::SwUndoInsNum( const SwNumRule& rOldRule, + const SwNumRule& rNewRule, + SwUndoId nUndoId ) + : SwUndo( nUndoId ), + aNumRule( rNewRule ), pHistory( 0 ), nSttSet( ULONG_MAX ), + pOldNumRule( new SwNumRule( rOldRule )), nLRSavePos( 0 ) +{ +} + +SwUndoInsNum::SwUndoInsNum( const SwPaM& rPam, const SwNumRule& rRule ) + : SwUndo( UNDO_INSNUM ), SwUndRng( rPam ), + aNumRule( rRule ), pHistory( 0 ), + nSttSet( ULONG_MAX ), pOldNumRule( 0 ), nLRSavePos( 0 ) +{ +} + +SwUndoInsNum::SwUndoInsNum( const SwPosition& rPos, const SwNumRule& rRule, + const String& rReplaceRule ) + : SwUndo( UNDO_INSNUM ), + aNumRule( rRule ), pHistory( 0 ), + nSttSet( ULONG_MAX ), pOldNumRule( 0 ), + sReplaceRule( rReplaceRule ), nLRSavePos( 0 ) +{ + // keine Selektion !! + nEndNode = 0, nEndCntnt = USHRT_MAX; + nSttNode = rPos.nNode.GetIndex(); + nSttCntnt = rPos.nContent.GetIndex(); +} + +SwUndoInsNum::~SwUndoInsNum() +{ + delete pHistory; + delete pOldNumRule; +} + +SwRewriter SwUndoInsNum::GetRewriter() const +{ + SwRewriter aResult; + if( UNDO_INSFMTATTR == GetId() ) + aResult.AddRule(UNDO_ARG1, aNumRule.GetName()); + return aResult; +} + +void SwUndoInsNum::Undo( SwUndoIter& rUndoIter ) +{ + SwDoc& rDoc = rUndoIter.GetDoc(); + if( nSttNode ) + SetPaM( rUndoIter ); + + BOOL bUndo = rDoc.DoesUndo(); + rDoc.DoUndo( FALSE ); + + if( pOldNumRule ) + rDoc.ChgNumRuleFmts( *pOldNumRule ); + + if( pHistory ) + { + SwTxtNode* pNd; + if( ULONG_MAX != nSttSet && + 0 != ( pNd = rDoc.GetNodes()[ nSttSet ]->GetTxtNode() )) + pNd->SetListRestart( TRUE ); + else + pNd = 0; + + + if( nLRSavePos ) + { + // sofort Updaten, damit eventuell "alte" LRSpaces wieder + // gueltig werden. + // !!! Dafuer suche aber erstmal den richtigen NumRule - Namen! + if( !pNd && nSttNode ) + pNd = rDoc.GetNodes()[ nSttNode ]->GetTxtNode(); + + // This code seems to be superfluous because the methods + // don't have any known side effects. + // ToDo: iasue i83806 should be used to remove this code + const SwNumRule* pNdRule; + if( pNd ) + pNdRule = pNd->GetNumRule(); + else + pNdRule = rDoc.FindNumRulePtr( aNumRule.GetName() ); + // End of ToDo for issue i83806 + + pHistory->TmpRollback( &rDoc, nLRSavePos ); + + } + pHistory->TmpRollback( &rDoc, 0 ); + pHistory->SetTmpEnd( pHistory->Count() ); + } + + if( nSttNode ) + SetPaM( rUndoIter ); + rDoc.DoUndo( bUndo ); +} + + +void SwUndoInsNum::Redo( SwUndoIter& rUndoIter ) +{ + SwDoc& rDoc = rUndoIter.GetDoc(); + + if( pOldNumRule ) + rDoc.ChgNumRuleFmts( aNumRule ); + else if( pHistory ) + { + SetPaM( rUndoIter ); + if( sReplaceRule.Len() ) + rDoc.ReplaceNumRule( *rUndoIter.pAktPam->GetPoint(), + sReplaceRule, aNumRule.GetName() ); + else + { + // --> OD 2005-02-25 #i42921# - adapt to changed signature + // --> OD 2008-03-18 #refactorlists# + rDoc.SetNumRule( *rUndoIter.pAktPam, aNumRule, false ); + // <-- + } + } +} + +void SwUndoInsNum::SetLRSpaceEndPos() +{ + if( pHistory ) + nLRSavePos = pHistory->Count(); +} + +void SwUndoInsNum::Repeat( SwUndoIter& rUndoIter ) +{ + if( nSttNode ) + { + if( !sReplaceRule.Len() ) + { + // --> OD 2005-02-25 #i42921# - adapt to changed signature + // --> OD 2008-03-18 #refactorlists# + rUndoIter.GetDoc().SetNumRule( *rUndoIter.pAktPam, aNumRule, false ); + // <-- + } + } + else + rUndoIter.GetDoc().ChgNumRuleFmts( aNumRule ); +} + +SwHistory* SwUndoInsNum::GetHistory() +{ + if( !pHistory ) + pHistory = new SwHistory; + return pHistory; +} + +void SwUndoInsNum::SaveOldNumRule( const SwNumRule& rOld ) +{ + if( !pOldNumRule ) + pOldNumRule = new SwNumRule( rOld ); +} + +/* */ + + +SwUndoDelNum::SwUndoDelNum( const SwPaM& rPam ) + : SwUndo( UNDO_DELNUM ), SwUndRng( rPam ), + aNodeIdx( BYTE( nEndNode - nSttNode > 255 ? 255 : nEndNode - nSttNode )), + aLevels( BYTE( nEndNode - nSttNode > 255 ? 255 : nEndNode - nSttNode )) +{ + pHistory = new SwHistory; +} + + +SwUndoDelNum::~SwUndoDelNum() +{ + delete pHistory; +} + + +void SwUndoDelNum::Undo( SwUndoIter& rUndoIter ) +{ + SwDoc& rDoc = rUndoIter.GetDoc(); + SetPaM( rUndoIter ); + + BOOL bUndo = rDoc.DoesUndo(); + rDoc.DoUndo( FALSE ); + + pHistory->TmpRollback( &rDoc, 0 ); + pHistory->SetTmpEnd( pHistory->Count() ); + + for( USHORT n = 0; n < aNodeIdx.Count(); ++n ) + { + SwTxtNode* pNd = rDoc.GetNodes()[ aNodeIdx[ n ] ]->GetTxtNode(); + ASSERT( pNd, "wo ist der TextNode geblieben?" ); + pNd->SetAttrListLevel(aLevels[ n ] ); + + if( pNd->GetCondFmtColl() ) + pNd->ChkCondColl(); + } + + SetPaM( rUndoIter ); + rDoc.DoUndo( bUndo ); +} + + +void SwUndoDelNum::Redo( SwUndoIter& rUndoIter ) +{ + SetPaM( rUndoIter ); + rUndoIter.GetDoc().DelNumRules( *rUndoIter.pAktPam ); +} + + +void SwUndoDelNum::Repeat( SwUndoIter& rUndoIter ) +{ + SetPaM( rUndoIter ); + rUndoIter.GetDoc().DelNumRules( *rUndoIter.pAktPam ); +} + +void SwUndoDelNum::AddNode( const SwTxtNode& rNd, BOOL ) +{ + if( rNd.GetNumRule() ) + { + USHORT nIns = aNodeIdx.Count(); + aNodeIdx.Insert( rNd.GetIndex(), nIns ); + + aLevels.Insert( static_cast<BYTE>(rNd.GetActualListLevel()), nIns ); + } +} + + +/* */ + + +SwUndoMoveNum::SwUndoMoveNum( const SwPaM& rPam, long nOff, BOOL bIsOutlMv ) + : SwUndo( bIsOutlMv ? UNDO_OUTLINE_UD : UNDO_MOVENUM ), + SwUndRng( rPam ), + nNewStt( 0 ), nOffset( nOff ) +{ + // nOffset: nach unten => 1 + // nach oben => -1 +} + + +void SwUndoMoveNum::Undo( SwUndoIter& rUndoIter ) +{ + ULONG nTmpStt = nSttNode, nTmpEnd = nEndNode; + + if( nEndNode || USHRT_MAX != nEndCntnt ) // Bereich ? + { + if( nNewStt < nSttNode ) // nach vorne verschoben + nEndNode = nEndNode - ( nSttNode - nNewStt ); + else + nEndNode = nEndNode + ( nNewStt - nSttNode ); + } + nSttNode = nNewStt; + +//JP 22.06.95: wird wollen die Bookmarks/Verzeichnisse behalten, oder? +// SetPaM( rUndoIter ); +// RemoveIdxFromRange( *rUndoIter.pAktPam, TRUE ); + + SetPaM( rUndoIter ); + rUndoIter.GetDoc().MoveParagraph( *rUndoIter.pAktPam, -nOffset, + UNDO_OUTLINE_UD == GetId() ); + nSttNode = nTmpStt; + nEndNode = nTmpEnd; +} + + +void SwUndoMoveNum::Redo( SwUndoIter& rUndoIter ) +{ +//JP 22.06.95: wird wollen die Bookmarks/Verzeichnisse behalten, oder? +// SetPaM( rUndoIter ); +// RemoveIdxFromRange( *rUndoIter.pAktPam, TRUE ); + + SetPaM( rUndoIter ); + rUndoIter.GetDoc().MoveParagraph( *rUndoIter.pAktPam, nOffset, + UNDO_OUTLINE_UD == GetId() ); +} + + +void SwUndoMoveNum::Repeat( SwUndoIter& rUndoIter ) +{ + if( UNDO_OUTLINE_UD == GetId() ) + rUndoIter.GetDoc().MoveOutlinePara( *rUndoIter.pAktPam, + 0 < nOffset ? 1 : -1 ); + else + rUndoIter.GetDoc().MoveParagraph( *rUndoIter.pAktPam, nOffset, FALSE ); +} + +/* */ + + +SwUndoNumUpDown::SwUndoNumUpDown( const SwPaM& rPam, short nOff ) + : SwUndo( nOff > 0 ? UNDO_NUMUP : UNDO_NUMDOWN ), SwUndRng( rPam ), + nOffset( nOff ) +{ + // nOffset: Down => 1 + // Up => -1 +} + + +void SwUndoNumUpDown::Undo( SwUndoIter& rUndoIter ) +{ + SetPaM( rUndoIter ); + rUndoIter.GetDoc().NumUpDown( *rUndoIter.pAktPam, 1 != nOffset ); +} + + +void SwUndoNumUpDown::Redo( SwUndoIter& rUndoIter ) +{ + SetPaM( rUndoIter ); + rUndoIter.GetDoc().NumUpDown( *rUndoIter.pAktPam, 1 == nOffset ); +} + + +void SwUndoNumUpDown::Repeat( SwUndoIter& rUndoIter ) +{ + rUndoIter.GetDoc().NumUpDown( *rUndoIter.pAktPam, 1 == nOffset ); +} + +/* */ + +// #115901# +SwUndoNumOrNoNum::SwUndoNumOrNoNum( const SwNodeIndex& rIdx, BOOL bOldNum, + BOOL bNewNum) + : SwUndo( UNDO_NUMORNONUM ), nIdx( rIdx.GetIndex() ), mbNewNum(bNewNum), + mbOldNum(bOldNum) +{ +} + +// #115901#, #i40034# +void SwUndoNumOrNoNum::Undo( SwUndoIter& rUndoIter ) +{ + SwNodeIndex aIdx( rUndoIter.GetDoc().GetNodes(), nIdx ); + SwTxtNode * pTxtNd = aIdx.GetNode().GetTxtNode(); + + if (NULL != pTxtNd) + { + pTxtNd->SetCountedInList(mbOldNum); + } +} + +// #115901#, #i40034# +void SwUndoNumOrNoNum::Redo( SwUndoIter& rUndoIter ) +{ + SwNodeIndex aIdx( rUndoIter.GetDoc().GetNodes(), nIdx ); + SwTxtNode * pTxtNd = aIdx.GetNode().GetTxtNode(); + + if (NULL != pTxtNd) + { + pTxtNd->SetCountedInList(mbNewNum); + } +} + +// #115901# +void SwUndoNumOrNoNum::Repeat( SwUndoIter& rUndoIter ) +{ + + if (mbOldNum && ! mbNewNum) + rUndoIter.GetDoc().NumOrNoNum( rUndoIter.pAktPam->GetPoint()->nNode, + FALSE); + else if ( ! mbOldNum && mbNewNum ) + rUndoIter.GetDoc().NumOrNoNum( rUndoIter.pAktPam->GetPoint()->nNode, + TRUE); +} + +/* */ + +SwUndoNumRuleStart::SwUndoNumRuleStart( const SwPosition& rPos, BOOL bFlg ) + : SwUndo( UNDO_SETNUMRULESTART ), + nIdx( rPos.nNode.GetIndex() ), nOldStt( USHRT_MAX ), + nNewStt( USHRT_MAX ), bSetSttValue( FALSE ), bFlag( bFlg ) +{ +} + +SwUndoNumRuleStart::SwUndoNumRuleStart( const SwPosition& rPos, USHORT nStt ) + : SwUndo( UNDO_SETNUMRULESTART ), + nIdx( rPos.nNode.GetIndex() ), + nOldStt( USHRT_MAX ), nNewStt( nStt ), bSetSttValue( TRUE ) +{ + SwTxtNode* pTxtNd = rPos.nNode.GetNode().GetTxtNode(); + if ( pTxtNd ) + { + // --> OD 2008-02-28 #refactorlists# + if ( pTxtNd->HasAttrListRestartValue() ) + { + nOldStt = static_cast<USHORT>(pTxtNd->GetAttrListRestartValue()); + } + else + { + nOldStt = USHRT_MAX; // indicating, that the list restart value is not set + } + // <-- + } +} + + +void SwUndoNumRuleStart::Undo( SwUndoIter& rUndoIter ) +{ + SwPosition aPos( *rUndoIter.GetDoc().GetNodes()[ nIdx ] ); + if( bSetSttValue ) + rUndoIter.GetDoc().SetNodeNumStart( aPos, nOldStt ); + else + rUndoIter.GetDoc().SetNumRuleStart( aPos, !bFlag ); +} + + +void SwUndoNumRuleStart::Redo( SwUndoIter& rUndoIter ) +{ + SwDoc& rDoc = rUndoIter.GetDoc(); + + SwPosition aPos( *rDoc.GetNodes()[ nIdx ] ); + if( bSetSttValue ) + rDoc.SetNodeNumStart( aPos, nNewStt ); + else + rDoc.SetNumRuleStart( aPos, bFlag ); +} + + +void SwUndoNumRuleStart::Repeat( SwUndoIter& rUndoIter ) +{ + if( bSetSttValue ) + rUndoIter.GetDoc().SetNodeNumStart( *rUndoIter.pAktPam->GetPoint(), nNewStt ); + else + rUndoIter.GetDoc().SetNumRuleStart( *rUndoIter.pAktPam->GetPoint(), bFlag ); +} + + diff --git a/sw/source/core/undo/unoutl.cxx b/sw/source/core/undo/unoutl.cxx new file mode 100644 index 000000000000..2a92097221b6 --- /dev/null +++ b/sw/source/core/undo/unoutl.cxx @@ -0,0 +1,70 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + + +#include "doc.hxx" +#include "swundo.hxx" // fuer die UndoIds +#include "pam.hxx" +#include "ndtxt.hxx" + +#include "undobj.hxx" + + +inline SwDoc& SwUndoIter::GetDoc() const { return *pAktPam->GetDoc(); } + +SwUndoOutlineLeftRight::SwUndoOutlineLeftRight( const SwPaM& rPam, + short nOff ) + : SwUndo( UNDO_OUTLINE_LR ), SwUndRng( rPam ), nOffset( nOff ) +{ +} + + +void SwUndoOutlineLeftRight::Undo( SwUndoIter& rUndoIter ) +{ + SetPaM( rUndoIter ); + rUndoIter.GetDoc().OutlineUpDown( *rUndoIter.pAktPam, -nOffset ); +} + + +void SwUndoOutlineLeftRight::Redo( SwUndoIter& rUndoIter ) +{ + SetPaM( rUndoIter ); + rUndoIter.GetDoc().OutlineUpDown( *rUndoIter.pAktPam, nOffset ); +} + + +void SwUndoOutlineLeftRight::Repeat( SwUndoIter& rUndoIter ) +{ + rUndoIter.GetDoc().OutlineUpDown( *rUndoIter.pAktPam, nOffset ); +} + + + diff --git a/sw/source/core/undo/unovwr.cxx b/sw/source/core/undo/unovwr.cxx new file mode 100644 index 000000000000..91549c84a57e --- /dev/null +++ b/sw/source/core/undo/unovwr.cxx @@ -0,0 +1,512 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <unotools/charclass.hxx> +#include <unotools/transliterationwrapper.hxx> +#include <comphelper/processfactory.hxx> +#include <doc.hxx> +#include <swundo.hxx> // fuer die UndoIds +#include <pam.hxx> +#include <ndtxt.hxx> +#include <undobj.hxx> +#include <rolbck.hxx> +#include <acorrect.hxx> +#include <docary.hxx> + +#include <tools/resid.hxx> +#include <comcore.hrc> // #111827# +#include <undo.hrc> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::i18n; +using namespace ::com::sun::star::uno; + +//------------------------------------------------------------------ + +// zwei Zugriffs-Funktionen +inline SwPosition* IterPt( SwUndoIter& rUIter ) +{ return rUIter.pAktPam->GetPoint(); } +inline SwPosition* IterMk( SwUndoIter& rUIter ) +{ return rUIter.pAktPam->GetMark(); } + +inline SwDoc& SwUndoIter::GetDoc() const { return *pAktPam->GetDoc(); } + +//------------------------------------------------------------ + + +// OVERWRITE + + +SwUndoOverwrite::SwUndoOverwrite( SwDoc* pDoc, SwPosition& rPos, + sal_Unicode cIns ) + : SwUndo(UNDO_OVERWRITE), + pRedlSaveData( 0 ), bGroup( FALSE ) +{ + if( !pDoc->IsIgnoreRedline() && pDoc->GetRedlineTbl().Count() ) + { + SwPaM aPam( rPos.nNode, rPos.nContent.GetIndex(), + rPos.nNode, rPos.nContent.GetIndex()+1 ); + pRedlSaveData = new SwRedlineSaveDatas; + if( !FillSaveData( aPam, *pRedlSaveData, FALSE )) + delete pRedlSaveData, pRedlSaveData = 0; + } + + nSttNode = rPos.nNode.GetIndex(); + nSttCntnt = rPos.nContent.GetIndex(); + + SwTxtNode* pTxtNd = rPos.nNode.GetNode().GetTxtNode(); + ASSERT( pTxtNd, "Overwrite nicht im TextNode?" ); + + bInsChar = TRUE; + xub_StrLen nTxtNdLen = pTxtNd->GetTxt().Len(); + if( nSttCntnt < nTxtNdLen ) // kein reines Einfuegen ? + { + aDelStr.Insert( pTxtNd->GetTxt().GetChar( nSttCntnt ) ); + if( !pHistory ) + pHistory = new SwHistory; + SwRegHistory aRHst( *pTxtNd, pHistory ); + pHistory->CopyAttr( pTxtNd->GetpSwpHints(), nSttNode, 0, + nTxtNdLen, false ); + rPos.nContent++; + bInsChar = FALSE; + } + + BOOL bOldExpFlg = pTxtNd->IsIgnoreDontExpand(); + pTxtNd->SetIgnoreDontExpand( TRUE ); + + pTxtNd->InsertText( cIns, rPos.nContent, + IDocumentContentOperations::INS_EMPTYEXPAND ); + aInsStr.Insert( cIns ); + + if( !bInsChar ) + { + const SwIndex aTmpIndex( rPos.nContent, -2 ); + pTxtNd->EraseText( aTmpIndex, 1 ); + } + pTxtNd->SetIgnoreDontExpand( bOldExpFlg ); + + bCacheComment = false; +} + +SwUndoOverwrite::~SwUndoOverwrite() +{ + delete pRedlSaveData; +} + +BOOL SwUndoOverwrite::CanGrouping( SwDoc* pDoc, SwPosition& rPos, + sal_Unicode cIns ) +{ +/// ?? was ist mit nur eingefuegten Charaktern ??? + + // es kann nur das Loeschen von einzelnen char's zusammengefasst werden + if( rPos.nNode != nSttNode || !aInsStr.Len() || + ( !bGroup && aInsStr.Len() != 1 )) + return FALSE; + + // ist der Node ueberhaupt ein TextNode? + SwTxtNode * pDelTxtNd = rPos.nNode.GetNode().GetTxtNode(); + if( !pDelTxtNd || + ( pDelTxtNd->GetTxt().Len() != rPos.nContent.GetIndex() && + rPos.nContent.GetIndex() != ( nSttCntnt + aInsStr.Len() ))) + return FALSE; + + CharClass& rCC = GetAppCharClass(); + + // befrage das einzufuegende Charakter + if (( CH_TXTATR_BREAKWORD == cIns || CH_TXTATR_INWORD == cIns ) || + rCC.isLetterNumeric( String( cIns ), 0 ) != + rCC.isLetterNumeric( aInsStr, aInsStr.Len()-1 ) ) + return FALSE; + + { + SwRedlineSaveDatas* pTmpSav = new SwRedlineSaveDatas; + SwPaM aPam( rPos.nNode, rPos.nContent.GetIndex(), + rPos.nNode, rPos.nContent.GetIndex()+1 ); + + if( !FillSaveData( aPam, *pTmpSav, FALSE )) + delete pTmpSav, pTmpSav = 0; + + BOOL bOk = ( !pRedlSaveData && !pTmpSav ) || + ( pRedlSaveData && pTmpSav && + SwUndo::CanRedlineGroup( *pRedlSaveData, *pTmpSav, + nSttCntnt > rPos.nContent.GetIndex() )); + delete pTmpSav; + if( !bOk ) + return FALSE; + + pDoc->DeleteRedline( aPam, false, USHRT_MAX ); + } + + // Ok, die beiden 'Overwrites' koennen zusammen gefasst werden, also + // 'verschiebe' das enstprechende Zeichen + if( !bInsChar ) + { + if( rPos.nContent.GetIndex() < pDelTxtNd->GetTxt().Len() ) + { + aDelStr.Insert( pDelTxtNd->GetTxt().GetChar(rPos.nContent.GetIndex()) ); + rPos.nContent++; + } + else + bInsChar = TRUE; + } + + BOOL bOldExpFlg = pDelTxtNd->IsIgnoreDontExpand(); + pDelTxtNd->SetIgnoreDontExpand( TRUE ); + + pDelTxtNd->InsertText( cIns, rPos.nContent, + IDocumentContentOperations::INS_EMPTYEXPAND ); + aInsStr.Insert( cIns ); + + if( !bInsChar ) + { + const SwIndex aTmpIndex( rPos.nContent, -2 ); + pDelTxtNd->EraseText( aTmpIndex, 1 ); + } + pDelTxtNd->SetIgnoreDontExpand( bOldExpFlg ); + + bGroup = TRUE; + return TRUE; +} + + + + + +void SwUndoOverwrite::Undo( SwUndoIter& rUndoIter ) +{ + SwPaM* pAktPam = rUndoIter.pAktPam; + SwDoc* pDoc = pAktPam->GetDoc(); + pAktPam->DeleteMark(); + pAktPam->GetPoint()->nNode = nSttNode; + SwTxtNode* pTxtNd = pAktPam->GetNode()->GetTxtNode(); + ASSERT( pTxtNd, "Overwrite nicht im TextNode?" ); + SwIndex& rIdx = pAktPam->GetPoint()->nContent; + rIdx.Assign( pTxtNd, nSttCntnt ); + + SwAutoCorrExceptWord* pACEWord = pDoc->GetAutoCorrExceptWord(); + if( pACEWord ) + { + if( 1 == aInsStr.Len() && 1 == aDelStr.Len() ) + pACEWord->CheckChar( *pAktPam->GetPoint(), aDelStr.GetChar( 0 ) ); + pDoc->SetAutoCorrExceptWord( 0 ); + } + + // wurde nicht nur ueberschieben sondern auch geinsertet, so loesche + // den Ueberhang + if( aInsStr.Len() > aDelStr.Len() ) + { + rIdx += aDelStr.Len(); + pTxtNd->EraseText( rIdx, aInsStr.Len() - aDelStr.Len() ); + rIdx = nSttCntnt; + } + + if( aDelStr.Len() ) + { + String aTmpStr( '1' ); + sal_Unicode* pTmpStr = aTmpStr.GetBufferAccess(); + + BOOL bOldExpFlg = pTxtNd->IsIgnoreDontExpand(); + pTxtNd->SetIgnoreDontExpand( TRUE ); + + rIdx++; + for( xub_StrLen n = 0; n < aDelStr.Len(); n++ ) + { + // einzeln, damit die Attribute stehen bleiben !!! + *pTmpStr = aDelStr.GetChar( n ); + pTxtNd->InsertText( aTmpStr, rIdx /*???, SETATTR_NOTXTATRCHR*/ ); + rIdx -= 2; + pTxtNd->EraseText( rIdx, 1 ); + rIdx += 2; + } + pTxtNd->SetIgnoreDontExpand( bOldExpFlg ); + rIdx--; + } + if( pHistory ) + { + if( pTxtNd->GetpSwpHints() ) + pTxtNd->ClearSwpHintsArr( false ); + pHistory->TmpRollback( pDoc, 0, false ); + } + + if( pAktPam->GetMark()->nContent.GetIndex() != nSttCntnt ) + { + pAktPam->SetMark(); + pAktPam->GetMark()->nContent = nSttCntnt; + } + + if( pRedlSaveData ) + SetSaveData( *pDoc, *pRedlSaveData ); +} + +void SwUndoOverwrite::Repeat( SwUndoIter& rUndoIter ) +{ + rUndoIter.pLastUndoObj = this; + SwPaM* pAktPam = rUndoIter.pAktPam; + if( !aInsStr.Len() || pAktPam->HasMark() ) + return; + + SwDoc& rDoc = *pAktPam->GetDoc(); + + BOOL bGroupUndo = rDoc.DoesGroupUndo(); + rDoc.DoGroupUndo( FALSE ); + rDoc.Overwrite( *pAktPam, aInsStr.GetChar( 0 )); + rDoc.DoGroupUndo( bGroupUndo ); + for( xub_StrLen n = 1; n < aInsStr.Len(); ++n ) + rDoc.Overwrite( *pAktPam, aInsStr.GetChar( n ) ); +} + + + +void SwUndoOverwrite::Redo( SwUndoIter& rUndoIter ) +{ + SwPaM* pAktPam = rUndoIter.pAktPam; + SwDoc* pDoc = pAktPam->GetDoc(); + pAktPam->DeleteMark(); + pAktPam->GetPoint()->nNode = nSttNode; + SwTxtNode* pTxtNd = pAktPam->GetNode()->GetTxtNode(); + ASSERT( pTxtNd, "Overwrite nicht im TextNode?" ); + SwIndex& rIdx = pAktPam->GetPoint()->nContent; + + if( pRedlSaveData ) + { + rIdx.Assign( pTxtNd, nSttCntnt ); + pAktPam->SetMark(); + pAktPam->GetMark()->nContent += aInsStr.Len(); + pDoc->DeleteRedline( *pAktPam, false, USHRT_MAX ); + pAktPam->DeleteMark(); + } + rIdx.Assign( pTxtNd, aDelStr.Len() ? nSttCntnt+1 : nSttCntnt ); + + BOOL bOldExpFlg = pTxtNd->IsIgnoreDontExpand(); + pTxtNd->SetIgnoreDontExpand( TRUE ); + + for( xub_StrLen n = 0; n < aInsStr.Len(); n++ ) + { + // einzeln, damit die Attribute stehen bleiben !!! + pTxtNd->InsertText( aInsStr.GetChar( n ), rIdx, + IDocumentContentOperations::INS_EMPTYEXPAND ); + if( n < aDelStr.Len() ) + { + rIdx -= 2; + pTxtNd->EraseText( rIdx, 1 ); + rIdx += n+1 < aDelStr.Len() ? 2 : 1; + } + } + pTxtNd->SetIgnoreDontExpand( bOldExpFlg ); + + // alte Anfangs-Position vom UndoNodes-Array zurueckholen + if( pHistory ) + pHistory->SetTmpEnd( pHistory->Count() ); + if( pAktPam->GetMark()->nContent.GetIndex() != nSttCntnt ) + { + pAktPam->SetMark(); + pAktPam->GetMark()->nContent = nSttCntnt; + } +} + +SwRewriter SwUndoOverwrite::GetRewriter() const +{ + SwRewriter aResult; + + String aString; + + aString += String(SW_RES(STR_START_QUOTE)); + aString += ShortenString(aInsStr, nUndoStringLength, + String(SW_RES(STR_LDOTS))); + aString += String(SW_RES(STR_END_QUOTE)); + + aResult.AddRule(UNDO_ARG1, aString); + + return aResult; +} + +//------------------------------------------------------------ + +struct _UndoTransliterate_Data +{ + String sText; + SwHistory* pHistory; + Sequence< sal_Int32 >* pOffsets; + ULONG nNdIdx; + xub_StrLen nStart, nLen; + + _UndoTransliterate_Data( ULONG nNd, xub_StrLen nStt, xub_StrLen nStrLen, const String& rTxt ) + : sText( rTxt ), pHistory( 0 ), pOffsets( 0 ), + nNdIdx( nNd ), nStart( nStt ), nLen( nStrLen ) + {} + ~_UndoTransliterate_Data() { delete pOffsets; delete pHistory; } + + void SetChangeAtNode( SwDoc& rDoc ); +}; + +SwUndoTransliterate::SwUndoTransliterate( + const SwPaM& rPam, + const utl::TransliterationWrapper& rTrans ) + : SwUndo( UNDO_TRANSLITERATE ), SwUndRng( rPam ), nType( rTrans.getType() ) +{ +} + +SwUndoTransliterate::~SwUndoTransliterate() +{ + for (size_t i = 0; i < aChanges.size(); ++i) + delete aChanges[i]; +} + +void SwUndoTransliterate::Undo( SwUndoIter& rUndoIter ) +{ + SwDoc& rDoc = rUndoIter.GetDoc(); + BOOL bUndo = rDoc.DoesUndo(); + rDoc.DoUndo( FALSE ); + + // since the changes were added to the vector from the end of the string/node towards + // the start, we need to revert them from the start towards the end now to keep the + // offset information of the undo data in sync with the changing text. + // Thus we need to iterate from the end of the vector to the start + for (sal_Int32 i = aChanges.size() - 1; i >= 0; --i) + aChanges[i]->SetChangeAtNode( rDoc ); + + rDoc.DoUndo( bUndo ); + SetPaM( rUndoIter, TRUE ); +} + +void SwUndoTransliterate::Redo( SwUndoIter& rUndoIter ) +{ +/* ??? */ rUndoIter.SetUpdateAttr( TRUE ); + + SetPaM( *rUndoIter.pAktPam ); + Repeat( rUndoIter ); +} + +void SwUndoTransliterate::Repeat( SwUndoIter& rUndoIter ) +{ + SwPaM& rPam = *rUndoIter.pAktPam; + SwDoc& rDoc = rUndoIter.GetDoc(); + + utl::TransliterationWrapper aTrans( ::comphelper::getProcessServiceFactory(), nType ); + rDoc.TransliterateText( rPam, aTrans ); + + rUndoIter.pLastUndoObj = this; +} + +void SwUndoTransliterate::AddChanges( SwTxtNode& rTNd, + xub_StrLen nStart, xub_StrLen nLen, + uno::Sequence <sal_Int32>& rOffsets ) +{ + long nOffsLen = rOffsets.getLength(); + _UndoTransliterate_Data* pNew = new _UndoTransliterate_Data( + rTNd.GetIndex(), nStart, (xub_StrLen)nOffsLen, + rTNd.GetTxt().Copy( nStart, nLen )); + + aChanges.push_back( pNew ); + + const sal_Int32* pOffsets = rOffsets.getConstArray(); + // where did we need less memory ? + const sal_Int32* p = pOffsets; + for( long n = 0; n < nOffsLen; ++n, ++p ) + if( *p != ( nStart + n )) + { + // create the Offset array + pNew->pOffsets = new Sequence <sal_Int32> ( nLen ); + sal_Int32* pIdx = pNew->pOffsets->getArray(); + p = pOffsets; + long nMyOff, nNewVal = nStart; + for( n = 0, nMyOff = nStart; n < nOffsLen; ++p, ++n, ++nMyOff ) + { + if( *p < nMyOff ) + { + // something is deleted + nMyOff = *p; + *(pIdx-1) = nNewVal++; + } + else if( *p > nMyOff ) + { + for( ; *p > nMyOff; ++nMyOff ) + *pIdx++ = nNewVal; + --nMyOff; + --n; + --p; + } + else + *pIdx++ = nNewVal++; + } + + // and then we need to save the attributes/bookmarks + // but this data must moved every time to the last in the chain! + for (size_t i = 0; i + 1 < aChanges.size(); ++i) // check all changes but not the current one + { + _UndoTransliterate_Data* pD = aChanges[i]; + if( pD->nNdIdx == pNew->nNdIdx && pD->pHistory ) + { + // same node and have a history? + pNew->pHistory = pD->pHistory; + pD->pHistory = 0; + break; // more can't exist + } + } + + if( !pNew->pHistory ) + { + pNew->pHistory = new SwHistory; + SwRegHistory aRHst( rTNd, pNew->pHistory ); + pNew->pHistory->CopyAttr( rTNd.GetpSwpHints(), + pNew->nNdIdx, 0, rTNd.GetTxt().Len(), false ); + } + break; + } +} + +void _UndoTransliterate_Data::SetChangeAtNode( SwDoc& rDoc ) +{ + SwTxtNode* pTNd = rDoc.GetNodes()[ nNdIdx ]->GetTxtNode(); + if( pTNd ) + { + Sequence <sal_Int32> aOffsets( pOffsets ? pOffsets->getLength() : nLen ); + if( pOffsets ) + aOffsets = *pOffsets; + else + { + sal_Int32* p = aOffsets.getArray(); + for( xub_StrLen n = 0; n < nLen; ++n, ++p ) + *p = n + nStart; + } + pTNd->ReplaceTextOnly( nStart, nLen, sText, aOffsets ); + + if( pHistory ) + { + if( pTNd->GetpSwpHints() ) + pTNd->ClearSwpHintsArr( false ); + pHistory->TmpRollback( &rDoc, 0, false ); + pHistory->SetTmpEnd( pHistory->Count() ); + } + } +} + + diff --git a/sw/source/core/undo/unredln.cxx b/sw/source/core/undo/unredln.cxx new file mode 100644 index 000000000000..7f76697c80a3 --- /dev/null +++ b/sw/source/core/undo/unredln.cxx @@ -0,0 +1,543 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <hintids.hxx> +#include <unotools/charclass.hxx> +#include <doc.hxx> +#include <swundo.hxx> // fuer die UndoIds +#include <pam.hxx> +#include <ndtxt.hxx> +#include <undobj.hxx> +#include <rolbck.hxx> +#include <redline.hxx> +#include <docary.hxx> +#include <sortopt.hxx> + +extern void lcl_JoinText( SwPaM& rPam, BOOL bJoinPrev ); +extern void lcl_GetJoinFlags( SwPaM& rPam, BOOL& rJoinTxt, BOOL& rJoinPrev ); + +//------------------------------------------------------------------ + +inline SwDoc& SwUndoIter::GetDoc() const { return *pAktPam->GetDoc(); } + + +SwUndoRedline::SwUndoRedline( SwUndoId nUsrId, const SwPaM& rRange ) + : SwUndo( UNDO_REDLINE ), SwUndRng( rRange ), + pRedlData( 0 ), pRedlSaveData( 0 ), nUserId( nUsrId ), + bHiddenRedlines( FALSE ) +{ + // Redline beachten + SwDoc& rDoc = *rRange.GetDoc(); + if( rDoc.IsRedlineOn() ) + { + switch( nUserId ) + { + case UNDO_DELETE: + case UNDO_REPLACE: + pRedlData = new SwRedlineData( nsRedlineType_t::REDLINE_DELETE, rDoc.GetRedlineAuthor() ); + break; + default: + ; + } + SetRedlineMode( rDoc.GetRedlineMode() ); + } + + ULONG nEndExtra = rDoc.GetNodes().GetEndOfExtras().GetIndex(); + + pRedlSaveData = new SwRedlineSaveDatas; + if( !FillSaveData( rRange, *pRedlSaveData, FALSE, + UNDO_REJECT_REDLINE != nUserId )) + delete pRedlSaveData, pRedlSaveData = 0; + else + { + bHiddenRedlines = HasHiddenRedlines( *pRedlSaveData ); + if( bHiddenRedlines ) // dann muessen die NodeIndizies + { // vom SwUndRng korrigiert werden + nEndExtra -= rDoc.GetNodes().GetEndOfExtras().GetIndex(); + nSttNode -= nEndExtra; + nEndNode -= nEndExtra; + } + } +} + +SwUndoRedline::~SwUndoRedline() +{ + delete pRedlData; + delete pRedlSaveData; +} + +void SwUndoRedline::Undo( SwUndoIter& rIter ) +{ + SwDoc* pDoc = &rIter.GetDoc(); + SetPaM( *rIter.pAktPam ); + +// RedlineMode setzen? + _Undo( rIter ); + + if( pRedlSaveData ) + { + ULONG nEndExtra = pDoc->GetNodes().GetEndOfExtras().GetIndex(); + SetSaveData( *pDoc, *pRedlSaveData ); + if( bHiddenRedlines ) + { + pRedlSaveData->DeleteAndDestroy( 0, pRedlSaveData->Count() ); + + nEndExtra = pDoc->GetNodes().GetEndOfExtras().GetIndex() - nEndExtra; + nSttNode += nEndExtra; + nEndNode += nEndExtra; + } + SetPaM( *rIter.pAktPam, TRUE ); + } +} + + +void SwUndoRedline::Redo( SwUndoIter& rIter ) +{ + SwDoc* pDoc = &rIter.GetDoc(); + RedlineMode_t eOld = pDoc->GetRedlineMode(); + pDoc->SetRedlineMode_intern((RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON )); + + SetPaM( *rIter.pAktPam ); + if( pRedlSaveData && bHiddenRedlines ) + { + ULONG nEndExtra = pDoc->GetNodes().GetEndOfExtras().GetIndex(); + FillSaveData( *rIter.pAktPam, *pRedlSaveData, FALSE, + UNDO_REJECT_REDLINE != nUserId ); + + nEndExtra -= pDoc->GetNodes().GetEndOfExtras().GetIndex(); + nSttNode -= nEndExtra; + nEndNode -= nEndExtra; + } + _Redo( rIter ); + + SetPaM( *rIter.pAktPam, TRUE ); + pDoc->SetRedlineMode_intern( eOld ); +} + +// default ist leer +void SwUndoRedline::_Undo( SwUndoIter& ) +{ +} + +// default ist Redlines entfernen +void SwUndoRedline::_Redo( SwUndoIter& rIter ) +{ + rIter.GetDoc().DeleteRedline( *rIter.pAktPam, true, USHRT_MAX ); +} + + +/* */ + +SwUndoRedlineDelete::SwUndoRedlineDelete( const SwPaM& rRange, SwUndoId nUsrId ) + : SwUndoRedline( nUsrId = (nUsrId ? nUsrId : UNDO_DELETE), rRange ), + bCanGroup( FALSE ), bIsDelim( FALSE ), bIsBackspace( FALSE ) +{ + const SwTxtNode* pTNd; + if( UNDO_DELETE == nUserId && + nSttNode == nEndNode && nSttCntnt + 1 == nEndCntnt && + 0 != (pTNd = rRange.GetNode()->GetTxtNode()) ) + { + sal_Unicode cCh = pTNd->GetTxt().GetChar( nSttCntnt ); + if( CH_TXTATR_BREAKWORD != cCh && CH_TXTATR_INWORD != cCh ) + { + bCanGroup = TRUE; + bIsDelim = !GetAppCharClass().isLetterNumeric( pTNd->GetTxt(), + nSttCntnt ); + bIsBackspace = nSttCntnt == rRange.GetPoint()->nContent.GetIndex(); + } + } + + bCacheComment = false; +} + +void SwUndoRedlineDelete::_Undo( SwUndoIter& rIter ) +{ + rIter.GetDoc().DeleteRedline( *rIter.pAktPam, true, USHRT_MAX ); +} + +void SwUndoRedlineDelete::_Redo( SwUndoIter& rIter ) +{ + if( *rIter.pAktPam->GetPoint() != *rIter.pAktPam->GetMark() ) + rIter.GetDoc().AppendRedline( new SwRedline( *pRedlData, *rIter.pAktPam ), FALSE ); +} + +BOOL SwUndoRedlineDelete::CanGrouping( const SwUndoRedlineDelete& rNext ) +{ + BOOL bRet = FALSE; + if( UNDO_DELETE == nUserId && nUserId == rNext.nUserId && + bCanGroup == rNext.bCanGroup && + bIsDelim == rNext.bIsDelim && + bIsBackspace == rNext.bIsBackspace && + nSttNode == nEndNode && + rNext.nSttNode == nSttNode && + rNext.nEndNode == nEndNode ) + { + int bIsEnd = 0; + if( rNext.nSttCntnt == nEndCntnt ) + bIsEnd = 1; + else if( rNext.nEndCntnt == nSttCntnt ) + bIsEnd = -1; + + if( bIsEnd && + (( !pRedlSaveData && !rNext.pRedlSaveData ) || + ( pRedlSaveData && rNext.pRedlSaveData && + SwUndo::CanRedlineGroup( *pRedlSaveData, + *rNext.pRedlSaveData, 1 != bIsEnd ) + ))) + { + if( 1 == bIsEnd ) + nEndCntnt = rNext.nEndCntnt; + else + nSttCntnt = rNext.nSttCntnt; + bRet = TRUE; + } + } + return bRet; +} + +/* */ + +SwUndoRedlineSort::SwUndoRedlineSort( const SwPaM& rRange, + const SwSortOptions& rOpt ) + : SwUndoRedline( UNDO_SORT_TXT, rRange ), + pOpt( new SwSortOptions( rOpt ) ), + nSaveEndNode( nEndNode ), nOffset( 0 ), nSaveEndCntnt( nEndCntnt ) +{ +} + +SwUndoRedlineSort::~SwUndoRedlineSort() +{ + delete pOpt; +} + +void SwUndoRedlineSort::_Undo( SwUndoIter& rIter ) +{ + // im rIter.pAktPam ist der sortiete Bereich, + // im aSaveRange steht der kopierte, sprich der originale. + SwDoc& rDoc = rIter.GetDoc(); + + SwPosition* pStart = rIter.pAktPam->Start(); + SwPosition* pEnd = rIter.pAktPam->End(); + + SwNodeIndex aPrevIdx( pStart->nNode, -1 ); + ULONG nOffsetTemp = pEnd->nNode.GetIndex() - pStart->nNode.GetIndex(); + + if( 0 == ( nsRedlineMode_t::REDLINE_SHOW_DELETE & rDoc.GetRedlineMode()) ) + { + // die beiden Redline Objecte suchen und diese dann anzeigen lassen, + // damit die Nodes wieder uebereinstimmen! + // das Geloeschte ist versteckt, also suche das INSERT + // Redline Object. Dahinter steht das Geloeschte + USHORT nFnd = rDoc.GetRedlinePos( + *rDoc.GetNodes()[ nSttNode + 1 ], + nsRedlineType_t::REDLINE_INSERT ); + ASSERT( USHRT_MAX != nFnd && nFnd+1 < rDoc.GetRedlineTbl().Count(), + "kein Insert Object gefunden" ); + ++nFnd; + rDoc.GetRedlineTbl()[nFnd]->Show( 1 ); + } + + { + SwPaM aTmp( *rIter.pAktPam->GetMark() ); + aTmp.GetMark()->nContent = 0; + aTmp.SetMark(); + aTmp.GetPoint()->nNode = nSaveEndNode; + aTmp.GetPoint()->nContent.Assign( aTmp.GetCntntNode(), nSaveEndCntnt ); + rDoc.DeleteRedline( aTmp, true, USHRT_MAX ); + } + + rDoc.DelFullPara( *rIter.pAktPam ); + + SwPaM* pPam = rIter.pAktPam; + pPam->DeleteMark(); + pPam->GetPoint()->nNode.Assign( aPrevIdx.GetNode(), +1 ); + SwCntntNode* pCNd = pPam->GetCntntNode(); + pPam->GetPoint()->nContent.Assign(pCNd, 0 ); + pPam->SetMark(); + + pPam->GetPoint()->nNode += nOffsetTemp; + pCNd = pPam->GetCntntNode(); + pPam->GetPoint()->nContent.Assign( pCNd, pCNd->Len() ); + + SetValues( *pPam ); + + SetPaM( *rIter.pAktPam ); +} + +void SwUndoRedlineSort::_Redo( SwUndoIter& rIter ) +{ + SwPaM& rPam = *rIter.pAktPam; + + SwPaM* pPam = &rPam; + SwPosition* pStart = pPam->Start(); + SwPosition* pEnd = pPam->End(); + + SwNodeIndex aPrevIdx( pStart->nNode, -1 ); + ULONG nOffsetTemp = pEnd->nNode.GetIndex() - pStart->nNode.GetIndex(); + xub_StrLen nCntStt = pStart->nContent.GetIndex(); + + rIter.GetDoc().SortText( rPam, *pOpt ); + + pPam->DeleteMark(); + pPam->GetPoint()->nNode.Assign( aPrevIdx.GetNode(), +1 ); + SwCntntNode* pCNd = pPam->GetCntntNode(); + xub_StrLen nLen = pCNd->Len(); + if( nLen > nCntStt ) + nLen = nCntStt; + pPam->GetPoint()->nContent.Assign(pCNd, nLen ); + pPam->SetMark(); + + pPam->GetPoint()->nNode += nOffsetTemp; + pCNd = pPam->GetCntntNode(); + pPam->GetPoint()->nContent.Assign( pCNd, pCNd->Len() ); + + SetValues( rPam ); + + SetPaM( rPam ); + rPam.GetPoint()->nNode = nSaveEndNode; + rPam.GetPoint()->nContent.Assign( rPam.GetCntntNode(), nSaveEndCntnt ); +} + +void SwUndoRedlineSort::Repeat( SwUndoIter& rIter ) +{ + rIter.GetDoc().SortText( *rIter.pAktPam, *pOpt ); +} + +void SwUndoRedlineSort::SetSaveRange( const SwPaM& rRange ) +{ + const SwPosition& rPos = *rRange.End(); + nSaveEndNode = rPos.nNode.GetIndex(); + nSaveEndCntnt = rPos.nContent.GetIndex(); +} + +void SwUndoRedlineSort::SetOffset( const SwNodeIndex& rIdx ) +{ + nOffset = rIdx.GetIndex() - nSttNode; +} + +/* */ + +SwUndoAcceptRedline::SwUndoAcceptRedline( const SwPaM& rRange ) + : SwUndoRedline( UNDO_ACCEPT_REDLINE, rRange ) +{ +} + +void SwUndoAcceptRedline::_Redo( SwUndoIter& rIter ) +{ + rIter.GetDoc().AcceptRedline( *rIter.pAktPam, false ); +} + +void SwUndoAcceptRedline::Repeat( SwUndoIter& rIter ) +{ + rIter.GetDoc().AcceptRedline( *rIter.pAktPam, true ); +} + +SwUndoRejectRedline::SwUndoRejectRedline( const SwPaM& rRange ) + : SwUndoRedline( UNDO_REJECT_REDLINE, rRange ) +{ +} + +void SwUndoRejectRedline::_Redo( SwUndoIter& rIter ) +{ + rIter.GetDoc().RejectRedline( *rIter.pAktPam, false ); +} + +void SwUndoRejectRedline::Repeat( SwUndoIter& rIter ) +{ + rIter.GetDoc().RejectRedline( *rIter.pAktPam, true ); +} + +/* */ + +SwUndoCompDoc::SwUndoCompDoc( const SwPaM& rRg, BOOL bIns ) + : SwUndo( UNDO_COMPAREDOC ), SwUndRng( rRg ), pRedlData( 0 ), + pUnDel( 0 ), pUnDel2( 0 ), pRedlSaveData( 0 ), bInsert( bIns ) +{ + SwDoc* pDoc = (SwDoc*)rRg.GetDoc(); + if( pDoc->IsRedlineOn() ) + { + RedlineType_t eTyp = bInsert ? nsRedlineType_t::REDLINE_INSERT : nsRedlineType_t::REDLINE_DELETE; + pRedlData = new SwRedlineData( eTyp, pDoc->GetRedlineAuthor() ); + SetRedlineMode( pDoc->GetRedlineMode() ); + } +} + +SwUndoCompDoc::SwUndoCompDoc( const SwRedline& rRedl ) + : SwUndo( UNDO_COMPAREDOC ), SwUndRng( rRedl ), pRedlData( 0 ), + pUnDel( 0 ), pUnDel2( 0 ), pRedlSaveData( 0 ), + // fuers MergeDoc wird aber der jeweils umgekehrte Zweig benoetigt! + bInsert( nsRedlineType_t::REDLINE_DELETE == rRedl.GetType() ) +{ + SwDoc* pDoc = (SwDoc*)rRedl.GetDoc(); + if( pDoc->IsRedlineOn() ) + { + pRedlData = new SwRedlineData( rRedl.GetRedlineData() ); + SetRedlineMode( pDoc->GetRedlineMode() ); + } + + pRedlSaveData = new SwRedlineSaveDatas; + if( !FillSaveData( rRedl, *pRedlSaveData, FALSE, TRUE )) + delete pRedlSaveData, pRedlSaveData = 0; +} + +SwUndoCompDoc::~SwUndoCompDoc() +{ + delete pRedlData; + delete pUnDel; + delete pUnDel2; + delete pRedlSaveData; +} + +void SwUndoCompDoc::Undo( SwUndoIter& rIter ) +{ + SwPaM* pPam = rIter.pAktPam; + SwDoc* pDoc = pPam->GetDoc(); + + SetPaM( *pPam ); + + if( !bInsert ) + { + // die Redlines loeschen + RedlineMode_t eOld = pDoc->GetRedlineMode(); + pDoc->SetRedlineMode_intern((RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON)); + + pDoc->DeleteRedline( *pPam, true, USHRT_MAX ); + + pDoc->SetRedlineMode_intern( eOld ); + + //per definition Point is end (in SwUndRng!) + SwCntntNode* pCSttNd = pPam->GetCntntNode( FALSE ); + SwCntntNode* pCEndNd = pPam->GetCntntNode( TRUE ); + + // if start- and end-content is zero, then the doc-compare moves + // complete nodes into the current doc. And then the selection + // must be from end to start, so the delete join into the right + // direction. + if( !nSttCntnt && !nEndCntnt ) + pPam->Exchange(); + + BOOL bJoinTxt, bJoinPrev; + ::lcl_GetJoinFlags( *pPam, bJoinTxt, bJoinPrev ); + + pUnDel = new SwUndoDelete( *pPam, FALSE ); + + if( bJoinTxt ) + ::lcl_JoinText( *pPam, bJoinPrev ); + + if( pCSttNd && !pCEndNd) + { + // #112139# Do not step behind the end of content. + SwNode * pTmp = pPam->GetNode(TRUE); + if (pTmp) + { + SwNode * pEnd = pDoc->GetNodes().DocumentSectionEndNode(pTmp); + + if (pTmp != pEnd) + { + pPam->SetMark(); + pPam->GetPoint()->nNode++; + pPam->GetBound( TRUE ).nContent.Assign( 0, 0 ); + pPam->GetBound( FALSE ).nContent.Assign( 0, 0 ); + pUnDel2 = new SwUndoDelete( *pPam, TRUE ); + } + } + } + pPam->DeleteMark(); + } + else + { + if( IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() )) + { + pDoc->DeleteRedline( *pPam, true, USHRT_MAX ); + + if( pRedlSaveData ) + SetSaveData( *pDoc, *pRedlSaveData ); + } + SetPaM( rIter, TRUE ); + } +} + +void SwUndoCompDoc::Redo( SwUndoIter& rIter ) +{ + // setze noch den Cursor auf den Redo-Bereich + SwPaM* pPam = rIter.pAktPam; + SwDoc* pDoc = pPam->GetDoc(); + + rIter.pLastUndoObj = 0; + + if( bInsert ) + { + SetPaM( *pPam ); + + if( pRedlData && IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() )) + { + SwRedline* pTmp = new SwRedline( *pRedlData, *pPam ); + ((SwRedlineTbl&)pDoc->GetRedlineTbl()).Insert( pTmp ); + pTmp->InvalidateRange(); + +/* + SwRedlineMode eOld = pDoc->GetRedlineMode(); + pDoc->SetRedlineMode_intern( eOld & ~REDLINE_IGNORE ); + pDoc->AppendRedline( new SwRedline( *pRedlData, *pPam )); + pDoc->SetRedlineMode_intern( eOld ); +*/ + } + else if( !( nsRedlineMode_t::REDLINE_IGNORE & GetRedlineMode() ) && + pDoc->GetRedlineTbl().Count() ) + pDoc->SplitRedline( *pPam ); + } + else + { +// SwRedlineMode eOld = pDoc->GetRedlineMode(); +// pDoc->SetRedlineMode_intern( ( eOld & ~REDLINE_IGNORE) | REDLINE_ON ); + + if( pUnDel2 ) + { + pUnDel2->Undo( rIter ); + delete pUnDel2, pUnDel2 = 0; + } + pUnDel->Undo( rIter ); + delete pUnDel, pUnDel = 0; + + SetPaM( *pPam ); + + SwRedline* pTmp = new SwRedline( *pRedlData, *pPam ); + ((SwRedlineTbl&)pDoc->GetRedlineTbl()).Insert( pTmp ); + if (pTmp) // #i19649# + pTmp->InvalidateRange(); + +// pDoc->SetRedlineMode_intern( eOld ); + } + + SetPaM( rIter, TRUE ); +} + + diff --git a/sw/source/core/undo/unsect.cxx b/sw/source/core/undo/unsect.cxx new file mode 100644 index 000000000000..98d0e41d4616 --- /dev/null +++ b/sw/source/core/undo/unsect.cxx @@ -0,0 +1,499 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <sfx2/linkmgr.hxx> +#include <fmtcntnt.hxx> +#include <doc.hxx> +#include <docary.hxx> +#include <swundo.hxx> // fuer die UndoIds +#include <pam.hxx> +#include <ndtxt.hxx> +#include <undobj.hxx> +#include <section.hxx> +#include <rolbck.hxx> +#include <redline.hxx> +#include <doctxm.hxx> +#include <ftnidx.hxx> +#include <editsh.hxx> +/// OD 04.10.2002 #102894# +/// class Calc needed for calculation of the hidden condition of a section. +#include <calc.hxx> + + +inline SwDoc& SwUndoIter::GetDoc() const { return *pAktPam->GetDoc(); } + +SfxItemSet* lcl_GetAttrSet( const SwSection& rSect ) +{ + // Attribute des Formate sichern (Spalten, Farbe, ... ) + // Cntnt- und Protect- Items interessieren nicht (stehen schon in der + // Section), muessen also entfernen werden + SfxItemSet* pAttr = 0; + if( rSect.GetFmt() ) + { + USHORT nCnt = 1; + if( rSect.IsProtect() ) + ++nCnt; + + if( nCnt < rSect.GetFmt()->GetAttrSet().Count() ) + { + pAttr = new SfxItemSet( rSect.GetFmt()->GetAttrSet() ); + pAttr->ClearItem( RES_PROTECT ); + pAttr->ClearItem( RES_CNTNT ); + if( !pAttr->Count() ) + delete pAttr, pAttr = 0; + } + } + return pAttr; +} + + +//////////////////////////////////////////////////////////////////////////// + +SwUndoInsSection::SwUndoInsSection( + SwPaM const& rPam, SwSectionData const& rNewData, + SfxItemSet const*const pSet, SwTOXBase const*const pTOXBase) + : SwUndo( UNDO_INSSECTION ), SwUndRng( rPam ) + , m_pSectionData(new SwSectionData(rNewData)) + , m_pTOXBase( (pTOXBase) ? new SwTOXBase(*pTOXBase) : 0 ) + , m_pAttrSet( (pSet && pSet->Count()) ? new SfxItemSet( *pSet ) : 0 ) + , m_pHistory(0) + , m_pRedlData(0) + , m_nSectionNodePos(0) + , m_bSplitAtStart(false) + , m_bSplitAtEnd(false) + , m_bUpdateFtn(false) +{ + SwDoc& rDoc = *(SwDoc*)rPam.GetDoc(); + if( rDoc.IsRedlineOn() ) + { + m_pRedlData.reset(new SwRedlineData( nsRedlineType_t::REDLINE_INSERT, + rDoc.GetRedlineAuthor() )); + SetRedlineMode( rDoc.GetRedlineMode() ); + } + + + if( !rPam.HasMark() ) + { + const SwCntntNode* pCNd = rPam.GetPoint()->nNode.GetNode().GetCntntNode(); + if( pCNd && pCNd->HasSwAttrSet() && ( + !rPam.GetPoint()->nContent.GetIndex() || + rPam.GetPoint()->nContent.GetIndex() == pCNd->Len() )) + { + SfxItemSet aBrkSet( rDoc.GetAttrPool(), aBreakSetRange ); + aBrkSet.Put( *pCNd->GetpSwAttrSet() ); + if( aBrkSet.Count() ) + { + m_pHistory.reset( new SwHistory ); + m_pHistory->CopyFmtAttr( aBrkSet, pCNd->GetIndex() ); + } + } + } +} + +SwUndoInsSection::~SwUndoInsSection() +{ +} + +void SwUndoInsSection::Undo( SwUndoIter& rUndoIter ) +{ + SwDoc& rDoc = rUndoIter.GetDoc(); + + RemoveIdxFromSection( rDoc, m_nSectionNodePos ); + + SwSectionNode *const pNd = + rDoc.GetNodes()[ m_nSectionNodePos ]->GetSectionNode(); + ASSERT( pNd, "wo ist mein SectionNode?" ); + + if( IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() )) + rDoc.DeleteRedline( *pNd, true, USHRT_MAX ); + + // lag keine Selektion vor ?? + SwNodeIndex aIdx( *pNd ); + if( ( !nEndNode && STRING_MAXLEN == nEndCntnt ) || + ( nSttNode == nEndNode && nSttCntnt == nEndCntnt )) + // loesche einfach alle Nodes + rDoc.GetNodes().Delete( aIdx, pNd->EndOfSectionIndex() - + aIdx.GetIndex() ); + else + // einfach das Format loeschen, der Rest erfolgt automatisch + rDoc.DelSectionFmt( pNd->GetSection().GetFmt() ); + + // muessen wir noch zusammenfassen ? + if (m_bSplitAtStart) + { + Join( rDoc, nSttNode ); + } + + if (m_bSplitAtEnd) + { + Join( rDoc, nEndNode ); + } + + if (m_pHistory.get()) + { + m_pHistory->TmpRollback( &rDoc, 0, false ); + } + + if (m_bUpdateFtn) + { + rDoc.GetFtnIdxs().UpdateFtn( aIdx ); + } + + SetPaM( rUndoIter ); +} + + +void SwUndoInsSection::Redo( SwUndoIter& rUndoIter ) +{ + SwDoc& rDoc = rUndoIter.GetDoc(); + SetPaM( rUndoIter ); + + const SwTOXBaseSection* pUpdateTOX = 0; + if (m_pTOXBase.get()) + { + pUpdateTOX = rDoc.InsertTableOf( *rUndoIter.pAktPam->GetPoint(), + *m_pTOXBase, m_pAttrSet.get(), true); + } + else + { + rDoc.InsertSwSection(*rUndoIter.pAktPam, + *m_pSectionData, 0, m_pAttrSet.get(), true); + } + + if (m_pHistory.get()) + { + m_pHistory->SetTmpEnd( m_pHistory->Count() ); + } + + SwSectionNode *const pSectNd = + rDoc.GetNodes()[ m_nSectionNodePos ]->GetSectionNode(); + if (m_pRedlData.get() && + IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode())) + { + RedlineMode_t eOld = rDoc.GetRedlineMode(); + rDoc.SetRedlineMode_intern((RedlineMode_t)(eOld & ~nsRedlineMode_t::REDLINE_IGNORE)); + + SwPaM aPam( *pSectNd->EndOfSectionNode(), *pSectNd, 1 ); + rDoc.AppendRedline( new SwRedline( *m_pRedlData, aPam ), true); + rDoc.SetRedlineMode_intern( eOld ); + } + else if( !( nsRedlineMode_t::REDLINE_IGNORE & GetRedlineMode() ) && + rDoc.GetRedlineTbl().Count() ) + { + SwPaM aPam( *pSectNd->EndOfSectionNode(), *pSectNd, 1 ); + rDoc.SplitRedline( aPam ); + } + + if( pUpdateTOX ) + { + // Formatierung anstossen + SwEditShell* pESh = rDoc.GetEditShell(); + if( pESh ) + pESh->CalcLayout(); + + // Seitennummern eintragen + ((SwTOXBaseSection*)pUpdateTOX)->UpdatePageNum(); + } +} + + +void SwUndoInsSection::Repeat( SwUndoIter& rUndoIter ) +{ + if (m_pTOXBase.get()) + { + rUndoIter.GetDoc().InsertTableOf( *rUndoIter.pAktPam->GetPoint(), + *m_pTOXBase, m_pAttrSet.get(), true); + } + else + { + rUndoIter.GetDoc().InsertSwSection( *rUndoIter.pAktPam, + *m_pSectionData, 0, m_pAttrSet.get()); + } +} + + +void SwUndoInsSection::Join( SwDoc& rDoc, ULONG nNode ) +{ + SwNodeIndex aIdx( rDoc.GetNodes(), nNode ); + SwTxtNode* pTxtNd = aIdx.GetNode().GetTxtNode(); + ASSERT( pTxtNd, "wo ist mein TextNode?" ); + + { + RemoveIdxRel( nNode + 1, SwPosition( aIdx, + SwIndex( pTxtNd, pTxtNd->GetTxt().Len() ))); + } + pTxtNd->JoinNext(); + + if (m_pHistory.get()) + { + SwIndex aCntIdx( pTxtNd, 0 ); + pTxtNd->RstAttr( aCntIdx, pTxtNd->Len(), 0, 0, true ); + } +} + + +void +SwUndoInsSection::SaveSplitNode(SwTxtNode *const pTxtNd, bool const bAtStart) +{ + if( pTxtNd->GetpSwpHints() ) + { + if (!m_pHistory.get()) + { + m_pHistory.reset( new SwHistory ); + } + m_pHistory->CopyAttr( pTxtNd->GetpSwpHints(), pTxtNd->GetIndex(), 0, + pTxtNd->GetTxt().Len(), false ); + } + + if (bAtStart) + { + m_bSplitAtStart = true; + } + else + { + m_bSplitAtEnd = true; + } +} + + +//////////////////////////////////////////////////////////////////////////// + +class SwUndoDelSection + : public SwUndo +{ +private: + ::std::auto_ptr<SwSectionData> const m_pSectionData; /// section not TOX + ::std::auto_ptr<SwTOXBase> const m_pTOXBase; /// set iff section is TOX + ::std::auto_ptr<SfxItemSet> const m_pAttrSet; + ::boost::shared_ptr< ::sfx2::MetadatableUndo > const m_pMetadataUndo; + ULONG const m_nStartNode; + ULONG const m_nEndNode; + +public: + SwUndoDelSection( + SwSectionFmt const&, SwSection const&, SwNodeIndex const*const); + virtual ~SwUndoDelSection(); + virtual void Undo( SwUndoIter& ); + virtual void Redo( SwUndoIter& ); +}; + +SW_DLLPRIVATE SwUndo * MakeUndoDelSection(SwSectionFmt const& rFormat) +{ + return new SwUndoDelSection(rFormat, *rFormat.GetSection(), + rFormat.GetCntnt().GetCntntIdx()); +} + +SwUndoDelSection::SwUndoDelSection( + SwSectionFmt const& rSectionFmt, SwSection const& rSection, + SwNodeIndex const*const pIndex) + : SwUndo( UNDO_DELSECTION ) + , m_pSectionData( new SwSectionData(rSection) ) + , m_pTOXBase( rSection.ISA( SwTOXBaseSection ) + ? new SwTOXBase(static_cast<SwTOXBaseSection const&>(rSection)) + : 0 ) + , m_pAttrSet( ::lcl_GetAttrSet(rSection) ) + , m_pMetadataUndo( rSectionFmt.CreateUndo() ) + , m_nStartNode( pIndex->GetIndex() ) + , m_nEndNode( pIndex->GetNode().EndOfSectionIndex() ) +{ +} + +SwUndoDelSection::~SwUndoDelSection() +{ +} + +void SwUndoDelSection::Undo( SwUndoIter& rUndoIter ) +{ + SwDoc& rDoc = rUndoIter.GetDoc(); + + if (m_pTOXBase.get()) + { + rDoc.InsertTableOf(m_nStartNode, m_nEndNode-2, *m_pTOXBase, + m_pAttrSet.get()); + } + else + { + SwNodeIndex aStt( rDoc.GetNodes(), m_nStartNode ); + SwNodeIndex aEnd( rDoc.GetNodes(), m_nEndNode-2 ); + SwSectionFmt* pFmt = rDoc.MakeSectionFmt( 0 ); + if (m_pAttrSet.get()) + { + pFmt->SetFmtAttr( *m_pAttrSet ); + } + + /// OD 04.10.2002 #102894# + /// remember inserted section node for further calculations + SwSectionNode* pInsertedSectNd = rDoc.GetNodes().InsertTextSection( + aStt, *pFmt, *m_pSectionData, 0, & aEnd); + + if( SFX_ITEM_SET == pFmt->GetItemState( RES_FTN_AT_TXTEND ) || + SFX_ITEM_SET == pFmt->GetItemState( RES_END_AT_TXTEND )) + { + rDoc.GetFtnIdxs().UpdateFtn( aStt ); + } + + /// OD 04.10.2002 #102894# + /// consider that section is hidden by condition. + /// If section is hidden by condition, + /// recalculate condition and update hidden condition flag. + /// Recalculation is necessary, because fields, on which the hide + /// condition depends, can be changed - fields changes aren't undoable. + /// NOTE: setting hidden condition flag also creates/deletes corresponding + /// frames, if the hidden condition flag changes. + SwSection& aInsertedSect = pInsertedSectNd->GetSection(); + if ( aInsertedSect.IsHidden() && + aInsertedSect.GetCondition().Len() > 0 ) + { + SwCalc aCalc( rDoc ); + rDoc.FldsToCalc(aCalc, pInsertedSectNd->GetIndex(), USHRT_MAX); + bool bRecalcCondHidden = + aCalc.Calculate( aInsertedSect.GetCondition() ).GetBool() ? true : false; + aInsertedSect.SetCondHidden( bRecalcCondHidden ); + } + + pFmt->RestoreMetadata(m_pMetadataUndo); + } +} + +void SwUndoDelSection::Redo( SwUndoIter& rUndoIter ) +{ + SwDoc& rDoc = rUndoIter.GetDoc(); + + SwSectionNode *const pNd = + rDoc.GetNodes()[ m_nStartNode ]->GetSectionNode(); + ASSERT( pNd, "wo ist mein SectionNode?" ); + // einfach das Format loeschen, der Rest erfolgt automatisch + rDoc.DelSectionFmt( pNd->GetSection().GetFmt() ); +} + + +//////////////////////////////////////////////////////////////////////////// + +class SwUndoUpdateSection + : public SwUndo +{ +private: + ::std::auto_ptr<SwSectionData> m_pSectionData; + ::std::auto_ptr<SfxItemSet> m_pAttrSet; + ULONG const m_nStartNode; + bool const m_bOnlyAttrChanged; + +public: + SwUndoUpdateSection( + SwSection const&, SwNodeIndex const*const, bool const bOnlyAttr); + virtual ~SwUndoUpdateSection(); + virtual void Undo( SwUndoIter& ); + virtual void Redo( SwUndoIter& ); +}; + +SW_DLLPRIVATE SwUndo * +MakeUndoUpdateSection(SwSectionFmt const& rFormat, bool const bOnlyAttr) +{ + return new SwUndoUpdateSection(*rFormat.GetSection(), + rFormat.GetCntnt().GetCntntIdx(), bOnlyAttr); +} + +SwUndoUpdateSection::SwUndoUpdateSection( + SwSection const& rSection, SwNodeIndex const*const pIndex, + bool const bOnlyAttr) + : SwUndo( UNDO_CHGSECTION ) + , m_pSectionData( new SwSectionData(rSection) ) + , m_pAttrSet( ::lcl_GetAttrSet(rSection) ) + , m_nStartNode( pIndex->GetIndex() ) + , m_bOnlyAttrChanged( bOnlyAttr ) +{ +} + +SwUndoUpdateSection::~SwUndoUpdateSection() +{ +} + +void SwUndoUpdateSection::Undo( SwUndoIter& rUndoIter ) +{ + SwDoc& rDoc = rUndoIter.GetDoc(); + SwSectionNode *const pSectNd = + rDoc.GetNodes()[ m_nStartNode ]->GetSectionNode(); + ASSERT( pSectNd, "wo ist mein SectionNode?" ); + + SwSection& rNdSect = pSectNd->GetSection(); + SwFmt* pFmt = rNdSect.GetFmt(); + + SfxItemSet* pCur = ::lcl_GetAttrSet( rNdSect ); + if (m_pAttrSet.get()) + { + // das Content- und Protect-Item muss bestehen bleiben + const SfxPoolItem* pItem; + m_pAttrSet->Put( pFmt->GetFmtAttr( RES_CNTNT )); + if( SFX_ITEM_SET == pFmt->GetItemState( RES_PROTECT, TRUE, &pItem )) + { + m_pAttrSet->Put( *pItem ); + } + pFmt->DelDiffs( *m_pAttrSet ); + m_pAttrSet->ClearItem( RES_CNTNT ); + pFmt->SetFmtAttr( *m_pAttrSet ); + } + else + { + // dann muessen die alten entfernt werden + pFmt->ResetFmtAttr( RES_FRMATR_BEGIN, RES_BREAK ); + pFmt->ResetFmtAttr( RES_HEADER, RES_OPAQUE ); + pFmt->ResetFmtAttr( RES_SURROUND, RES_FRMATR_END-1 ); + } + m_pAttrSet.reset(pCur); + + if (!m_bOnlyAttrChanged) + { + const bool bUpdate = + (!rNdSect.IsLinkType() && m_pSectionData->IsLinkType()) + || ( m_pSectionData->GetLinkFileName().Len() + && (m_pSectionData->GetLinkFileName() != + rNdSect.GetLinkFileName())); + + // swap stored section data with live section data + SwSectionData *const pOld( new SwSectionData(rNdSect) ); + rNdSect.SetSectionData(*m_pSectionData); + m_pSectionData.reset(pOld); + + if( bUpdate ) + rNdSect.CreateLink( CREATE_UPDATE ); + else if( CONTENT_SECTION == rNdSect.GetType() && rNdSect.IsConnected() ) + { + rNdSect.Disconnect(); + rDoc.GetLinkManager().Remove( &rNdSect.GetBaseLink() ); + } + } +} + +void SwUndoUpdateSection::Redo( SwUndoIter& rUndoIter ) +{ + Undo( rUndoIter ); +} + diff --git a/sw/source/core/undo/unsort.cxx b/sw/source/core/undo/unsort.cxx new file mode 100644 index 000000000000..44b73736e458 --- /dev/null +++ b/sw/source/core/undo/unsort.cxx @@ -0,0 +1,302 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" +#include <doc.hxx> +#include <swundo.hxx> // fuer die UndoIds +#include <pam.hxx> +#include <swtable.hxx> +#include <ndtxt.hxx> +#include <undobj.hxx> +#include <sortopt.hxx> +#ifndef _DOCSORT_HXX +#include <docsort.hxx> +#endif +#include <redline.hxx> +#include <node2lay.hxx> + +inline SwDoc& SwUndoIter::GetDoc() const { return *pAktPam->GetDoc(); } + +/*-------------------------------------------------------------------- + Beschreibung: Undo fuers Sorting + --------------------------------------------------------------------*/ + + +SV_IMPL_PTRARR(SwSortList, SwSortUndoElement*) +SV_IMPL_PTRARR(SwUndoSortList, SwNodeIndex*) + + +SwSortUndoElement::~SwSortUndoElement() +{ + // sind String Pointer gespeichert ?? + if( 0xffffffff != SORT_TXT_TBL.TXT.nKenn ) + { + delete SORT_TXT_TBL.TBL.pSource; + delete SORT_TXT_TBL.TBL.pTarget; + } +} + + +SwUndoSort::SwUndoSort(const SwPaM& rRg, const SwSortOptions& rOpt) + : SwUndo(UNDO_SORT_TXT), SwUndRng(rRg), pUndoTblAttr( 0 ), + pRedlData( 0 ) +{ + pSortOpt = new SwSortOptions(rOpt); +} + + +SwUndoSort::SwUndoSort( ULONG nStt, ULONG nEnd, const SwTableNode& rTblNd, + const SwSortOptions& rOpt, BOOL bSaveTable ) + : SwUndo(UNDO_SORT_TBL), pUndoTblAttr( 0 ), pRedlData( 0 ) +{ + nSttNode = nStt; + nEndNode = nEnd; + nTblNd = rTblNd.GetIndex(); + + pSortOpt = new SwSortOptions(rOpt); + if( bSaveTable ) + pUndoTblAttr = new SwUndoAttrTbl( rTblNd ); +} + + + +SwUndoSort::~SwUndoSort() +{ + delete pSortOpt; + delete pUndoTblAttr; + delete pRedlData; +} + + + +void SwUndoSort::Undo( SwUndoIter& rIter) +{ + SwDoc& rDoc = rIter.GetDoc(); + if(pSortOpt->bTable) + { + // Undo Tabelle + RemoveIdxFromSection( rDoc, nSttNode, &nEndNode ); + + if( pUndoTblAttr ) + pUndoTblAttr->Undo( rIter ); + + SwTableNode* pTblNd = rDoc.GetNodes()[ nTblNd ]->GetTableNode(); + + // --> FME 2004-11-26 #i37739# A simple 'MakeFrms' after the node sorting + // does not work if the table is inside a frame and has no prev/next. + SwNode2Layout aNode2Layout( *pTblNd ); + // <-- + + pTblNd->DelFrms(); + const SwTable& rTbl = pTblNd->GetTable(); + + SwMovedBoxes aMovedList; + for( USHORT i=0; i < aSortList.Count(); i++) + { + const SwTableBox* pSource = rTbl.GetTblBox( + *aSortList[i]->SORT_TXT_TBL.TBL.pSource ); + const SwTableBox* pTarget = rTbl.GetTblBox( + *aSortList[i]->SORT_TXT_TBL.TBL.pTarget ); + + // zurueckverschieben + MoveCell(&rDoc, pTarget, pSource, + USHRT_MAX != aMovedList.GetPos(pSource) ); + + // schon Verschobenen in der Liste merken + aMovedList.Insert(pTarget, aMovedList.Count() ); + } + + // Restore table frames: + // --> FME 2004-11-26 #i37739# A simple 'MakeFrms' after the node sorting + // does not work if the table is inside a frame and has no prev/next. + const ULONG nIdx = pTblNd->GetIndex(); + aNode2Layout.RestoreUpperFrms( rDoc.GetNodes(), nIdx, nIdx + 1 ); + // <-- + } + else + { + // Undo Text + RemoveIdx( *rIter.pAktPam ); + + // fuer die sorted Positions einen Index anlegen. + // JP 25.11.97: Die IndexList muss aber nach SourcePosition + // aufsteigend sortiert aufgebaut werden + SwUndoSortList aIdxList( (BYTE)aSortList.Count() ); + USHORT i; + + for( i = 0; i < aSortList.Count(); ++i) + for( USHORT ii=0; ii < aSortList.Count(); ++ii ) + if( aSortList[ii]->SORT_TXT_TBL.TXT.nSource == nSttNode + i ) + { + SwNodeIndex* pIdx = new SwNodeIndex( rDoc.GetNodes(), + aSortList[ii]->SORT_TXT_TBL.TXT.nTarget ); + aIdxList.C40_INSERT(SwNodeIndex, pIdx, i ); + break; + } + + for(i=0; i < aSortList.Count(); ++i) + { + SwNodeIndex aIdx( rDoc.GetNodes(), nSttNode + i ); + SwNodeRange aRg( *aIdxList[i], 0, *aIdxList[i], 1 ); + rDoc.MoveNodeRange(aRg, aIdx, + IDocumentContentOperations::DOC_MOVEDEFAULT); + } + // Indixes loeschen + aIdxList.DeleteAndDestroy(0, aIdxList.Count()); + SetPaM( rIter, TRUE ); + } +} + + +void SwUndoSort::Redo( SwUndoIter& rIter) +{ + SwDoc& rDoc = rIter.GetDoc(); + + if(pSortOpt->bTable) + { + // Redo bei Tabelle + RemoveIdxFromSection( rDoc, nSttNode, &nEndNode ); + + SwTableNode* pTblNd = rDoc.GetNodes()[ nTblNd ]->GetTableNode(); + + // --> FME 2004-11-26 #i37739# A simple 'MakeFrms' after the node sorting + // does not work if the table is inside a frame and has no prev/next. + SwNode2Layout aNode2Layout( *pTblNd ); + // <-- + + pTblNd->DelFrms(); + const SwTable& rTbl = pTblNd->GetTable(); + + SwMovedBoxes aMovedList; + for(USHORT i=0; i < aSortList.Count(); ++i) + { + const SwTableBox* pSource = rTbl.GetTblBox( + (const String&) *aSortList[i]->SORT_TXT_TBL.TBL.pSource ); + const SwTableBox* pTarget = rTbl.GetTblBox( + (const String&) *aSortList[i]->SORT_TXT_TBL.TBL.pTarget ); + + // zurueckverschieben + MoveCell(&rDoc, pSource, pTarget, + USHRT_MAX != aMovedList.GetPos( pTarget ) ); + // schon Verschobenen in der Liste merken + aMovedList.Insert( pSource, aMovedList.Count() ); + } + + if( pUndoTblAttr ) + pUndoTblAttr->Redo( rIter ); + + // Restore table frames: + // --> FME 2004-11-26 #i37739# A simple 'MakeFrms' after the node sorting + // does not work if the table is inside a frame and has no prev/next. + const ULONG nIdx = pTblNd->GetIndex(); + aNode2Layout.RestoreUpperFrms( rDoc.GetNodes(), nIdx, nIdx + 1 ); + // <-- + } + else + { + // Redo bei Text + RemoveIdx( *rIter.pAktPam ); + + SwUndoSortList aIdxList( (BYTE)aSortList.Count() ); + USHORT i; + + for( i = 0; i < aSortList.Count(); ++i) + { // aktuelle Pos ist die Ausgangslage + SwNodeIndex* pIdx = new SwNodeIndex( rDoc.GetNodes(), + aSortList[i]->SORT_TXT_TBL.TXT.nSource); + aIdxList.C40_INSERT( SwNodeIndex, pIdx, i ); + } + + for(i=0; i < aSortList.Count(); ++i) + { + SwNodeIndex aIdx( rDoc.GetNodes(), nSttNode + i); + SwNodeRange aRg( *aIdxList[i], 0, *aIdxList[i], 1 ); + rDoc.MoveNodeRange(aRg, aIdx, + IDocumentContentOperations::DOC_MOVEDEFAULT); + } + // Indixes loeschen + aIdxList.DeleteAndDestroy(0, aIdxList.Count()); + SetPaM( rIter, TRUE ); + const SwTxtNode* pTNd = rIter.pAktPam->GetNode()->GetTxtNode(); + if( pTNd ) + rIter.pAktPam->GetPoint()->nContent = pTNd->GetTxt().Len(); + } +} + + +void SwUndoSort::Repeat(SwUndoIter& rIter) +{ + if(!pSortOpt->bTable) + { + SwPaM* pPam = rIter.pAktPam; + SwDoc& rDoc = *pPam->GetDoc(); + + if( !rDoc.IsIdxInTbl( pPam->Start()->nNode ) ) + rDoc.SortText(*pPam, *pSortOpt); + } + // Tabelle ist nicht Repeat-Faehig + rIter.pLastUndoObj = this; +} + + +void SwUndoSort::RemoveIdx( SwPaM& rPam ) +{ + rPam.DeleteMark(); + rPam.GetPoint()->nNode = nSttNode; + + SwCntntNode* pCNd = rPam.GetCntntNode(); + xub_StrLen nLen = pCNd->Len(); + if( nLen >= nSttCntnt ) + nLen = nSttCntnt; + rPam.GetPoint()->nContent.Assign(pCNd, nLen ); + rPam.SetMark(); + + rPam.GetPoint()->nNode = nEndNode; + pCNd = rPam.GetCntntNode(); + nLen = pCNd->Len(); + if( nLen >= nEndCntnt ) + nLen = nEndCntnt; + rPam.GetPoint()->nContent.Assign(pCNd, nLen ); + RemoveIdxFromRange( rPam, TRUE ); +} + + +void SwUndoSort::Insert( const String& rOrgPos, const String& rNewPos) +{ + SwSortUndoElement* pEle = new SwSortUndoElement(rOrgPos, rNewPos); + aSortList.C40_INSERT( SwSortUndoElement, pEle, aSortList.Count() ); +} + + +void SwUndoSort::Insert( ULONG nOrgPos, ULONG nNewPos) +{ + SwSortUndoElement* pEle = new SwSortUndoElement(nOrgPos, nNewPos); + aSortList.C40_INSERT( SwSortUndoElement, pEle, aSortList.Count() ); +} + + diff --git a/sw/source/core/undo/unspnd.cxx b/sw/source/core/undo/unspnd.cxx new file mode 100644 index 000000000000..14aa18ed6e07 --- /dev/null +++ b/sw/source/core/undo/unspnd.cxx @@ -0,0 +1,216 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include "doc.hxx" +#include "pam.hxx" +#include "swtable.hxx" +#include "ndtxt.hxx" +#include "swundo.hxx" // fuer die UndoIds +#include <editeng/brkitem.hxx> +#include <fmtpdsc.hxx> +#include <frmfmt.hxx> +#include "undobj.hxx" +#include "rolbck.hxx" +#include "redline.hxx" +#include "docary.hxx" + + +inline SwDoc& SwUndoIter::GetDoc() const { return *pAktPam->GetDoc(); } + + +//------------------------------------------------------------------ + +// SPLITNODE + + +SwUndoSplitNode::SwUndoSplitNode( SwDoc* pDoc, const SwPosition& rPos, + BOOL bChkTable ) + : SwUndo( UNDO_SPLITNODE ), pHistory( 0 ), pRedlData( 0 ), nNode( rPos.nNode.GetIndex() ), + nCntnt( rPos.nContent.GetIndex() ), + bTblFlag( FALSE ), bChkTblStt( bChkTable ) +{ + SwTxtNode* pTxtNd = pDoc->GetNodes()[ rPos.nNode ]->GetTxtNode(); + ASSERT( pTxtNd, "nur beim TextNode rufen!" ); + if( pTxtNd->GetpSwpHints() ) + { + pHistory = new SwHistory; + pHistory->CopyAttr( pTxtNd->GetpSwpHints(), nNode, 0, + pTxtNd->GetTxt().Len(), false ); + if( !pHistory->Count() ) + DELETEZ( pHistory ); + } + // Redline beachten + if( pDoc->IsRedlineOn() ) + { + pRedlData = new SwRedlineData( nsRedlineType_t::REDLINE_INSERT, pDoc->GetRedlineAuthor() ); + SetRedlineMode( pDoc->GetRedlineMode() ); + } +} + + + + +SwUndoSplitNode::~SwUndoSplitNode() +{ + delete pHistory; + delete pRedlData; +} + + + +void SwUndoSplitNode::Undo( SwUndoIter& rUndoIter ) +{ + SwDoc* pDoc = &rUndoIter.GetDoc(); + SwPaM& rPam = *rUndoIter.pAktPam; + rPam.DeleteMark(); + if( bTblFlag ) + { + // dann wurde direkt vor der akt. Tabelle ein TextNode eingefuegt. + SwNodeIndex& rIdx = rPam.GetPoint()->nNode; + rIdx = nNode; + SwTxtNode* pTNd; + SwNode* pCurrNd = pDoc->GetNodes()[ nNode + 1 ]; + SwTableNode* pTblNd = pCurrNd->FindTableNode(); + if( pCurrNd->IsCntntNode() && pTblNd && + 0 != ( pTNd = pDoc->GetNodes()[ pTblNd->GetIndex()-1 ]->GetTxtNode() )) + { + // verschiebe die BreakAttribute noch + SwFrmFmt* pTableFmt = pTblNd->GetTable().GetFrmFmt(); + const SfxItemSet* pNdSet = pTNd->GetpSwAttrSet(); + if( pNdSet ) + { + const SfxPoolItem *pItem; + if( SFX_ITEM_SET == pNdSet->GetItemState( RES_PAGEDESC, FALSE, + &pItem ) ) + pTableFmt->SetFmtAttr( *pItem ); + + if( SFX_ITEM_SET == pNdSet->GetItemState( RES_BREAK, FALSE, + &pItem ) ) + pTableFmt->SetFmtAttr( *pItem ); + } + + // dann loesche den wieder + SwNodeIndex aDelNd( *pTblNd, -1 ); + rPam.GetPoint()->nContent.Assign( (SwCntntNode*)pCurrNd, 0 ); + RemoveIdxRel( aDelNd.GetIndex(), *rPam.GetPoint() ); + pDoc->GetNodes().Delete( aDelNd ); + } + } + else + { + SwTxtNode * pTNd = pDoc->GetNodes()[ nNode ]->GetTxtNode(); + if( pTNd ) + { + rPam.GetPoint()->nNode = *pTNd; + rPam.GetPoint()->nContent.Assign( pTNd, pTNd->GetTxt().Len() ); + + if( IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() )) + { + rPam.SetMark(); + rPam.GetMark()->nNode++; + rPam.GetMark()->nContent.Assign( rPam.GetMark()-> + nNode.GetNode().GetCntntNode(), 0 ); + pDoc->DeleteRedline( rPam, true, USHRT_MAX ); + rPam.DeleteMark(); + } + + RemoveIdxRel( nNode+1, *rPam.GetPoint() ); + + pTNd->JoinNext(); + if( pHistory ) + { + rPam.GetPoint()->nContent = 0; + rPam.SetMark(); + rPam.GetPoint()->nContent = pTNd->GetTxt().Len(); + + pDoc->RstTxtAttrs( rPam, TRUE ); + pHistory->TmpRollback( pDoc, 0, false ); + } + } + } + + // setze noch den Cursor auf den Undo-Bereich + rPam.DeleteMark(); + rPam.GetPoint()->nNode = nNode; + rPam.GetPoint()->nContent.Assign( rPam.GetCntntNode(), nCntnt ); +} + + +void SwUndoSplitNode::Repeat( SwUndoIter& rUndoIter ) +{ + if( UNDO_SPLITNODE == rUndoIter.GetLastUndoId() ) + return; + rUndoIter.GetDoc().SplitNode( *rUndoIter.pAktPam->GetPoint(), bChkTblStt ); + rUndoIter.pLastUndoObj = this; +} + + +void SwUndoSplitNode::Redo( SwUndoIter& rUndoIter ) +{ + SwPaM& rPam = *rUndoIter.pAktPam; + ULONG nOldNode = rPam.GetPoint()->nNode.GetIndex(); + rPam.GetPoint()->nNode = nNode; + SwTxtNode * pTNd = rPam.GetNode()->GetTxtNode(); + if( pTNd ) // sollte eigentlich immer ein TextNode sein !! + { + rPam.GetPoint()->nContent.Assign( pTNd, nCntnt ); + + SwDoc* pDoc = rPam.GetDoc(); + pDoc->SplitNode( *rPam.GetPoint(), bChkTblStt ); + + if( pHistory ) + pHistory->SetTmpEnd( pHistory->Count() ); + + if( ( pRedlData && IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() )) || + ( !( nsRedlineMode_t::REDLINE_IGNORE & GetRedlineMode() ) && + pDoc->GetRedlineTbl().Count() )) + { + rPam.SetMark(); + if( rPam.Move( fnMoveBackward )) + { + if( pRedlData && IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() )) + { + RedlineMode_t eOld = pDoc->GetRedlineMode(); + pDoc->SetRedlineMode_intern((RedlineMode_t)(eOld & ~nsRedlineMode_t::REDLINE_IGNORE)); + pDoc->AppendRedline( new SwRedline( *pRedlData, rPam ), true); + pDoc->SetRedlineMode_intern( eOld ); + } + else + pDoc->SplitRedline( rPam ); + rPam.Exchange(); + } + rPam.DeleteMark(); + } + } + else + rPam.GetPoint()->nNode = nOldNode; +} + diff --git a/sw/source/core/undo/untbl.cxx b/sw/source/core/undo/untbl.cxx new file mode 100644 index 000000000000..f66cae89ce21 --- /dev/null +++ b/sw/source/core/undo/untbl.cxx @@ -0,0 +1,3285 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <hintids.hxx> +#include <editeng/brkitem.hxx> +#include <fmtornt.hxx> +#include <fmtpdsc.hxx> +#include <doc.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 <undobj.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> + +#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 + +inline SwDoc& SwUndoIter::GetDoc() const { return *pAktPam->GetDoc(); } +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 +{ + 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; + USHORT nLineCount; + BOOL bModifyBox : 1; + BOOL bSaveFormula : 1; + BOOL bNewModel : 1; + +public: + _SaveTable( const SwTable& rTbl, USHORT nLnCnt = USHRT_MAX, + BOOL bSaveFml = TRUE ); + ~_SaveTable(); + + USHORT AddFmt( SwFrmFmt* pFmt, bool bIsLine ); + void NewFrmFmt( const SwClient* pLnBx, BOOL bIsLine, USHORT 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; + USHORT 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; + ULONG nSttNode; + long nRowSpan; + USHORT 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, USHORT nIdx, USHORT* pInsPos = 0 ); +void InsertSort( SvULongs& rArr, ULONG nIdx, USHORT* 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 +{ + ULONG m_nSttNd; + 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, ULONG nNd, 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 ) + +USHORT __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, USHORT nCl, USHORT nRw, + USHORT 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::Undo( SwUndoIter& rUndoIter ) +{ + SwDoc& rDoc = rUndoIter.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, + FALSE, &pItem ) ) + pNextNd->SetAttr( *pItem ); + + if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_BREAK, + 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 ); + + rUndoIter.pAktPam->DeleteMark(); + rUndoIter.pAktPam->GetPoint()->nNode = aIdx; + rUndoIter.pAktPam->GetPoint()->nContent.Assign( + rUndoIter.pAktPam->GetCntntNode(), 0 ); +} + + +void SwUndoInsTbl::Redo( SwUndoIter& rUndoIter ) +{ + SwDoc& rDoc = rUndoIter.GetDoc(); + + SwPosition aPos( *rUndoIter.pAktPam->GetPoint() ); + aPos.nNode = 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( 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::Repeat( SwUndoIter& rUndoIter ) +{ + rUndoIter.GetDoc().InsertTable( aInsTblOpts, *rUndoIter.pAktPam->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, ULONG nNd, 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<USHORT>(rTbl.GetFrmFmt()->GetHoriOrient().GetHoriOrient()) ), + cTrenner( cCh ), nHdlnRpt( rTbl.GetRowsToRepeat() ) +{ + pTblSave = new _SaveTable( rTbl ); + pBoxSaves = new SwTblToTxtSaves( (BYTE)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(); + ULONG nTblStt = pTblNd->GetIndex(), nTblEnd = pTblNd->EndOfSectionIndex(); + + const SwSpzFrmFmts& rFrmFmtTbl = *pTblNd->GetDoc()->GetSpzFrmFmts(); + for( USHORT 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::Undo( SwUndoIter& rUndoIter ) +{ + SwDoc& rDoc = rUndoIter.GetDoc(); + SwPaM* pPam = rUndoIter.pAktPam; + + 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() ); + pTableFmt->Add( &pTblNd->GetTable() ); // das Frame-Format setzen + 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, FALSE ); // setze die DDE-Tabelle + delete pDDEFldType, pDDEFldType = 0; + } + + if( bCheckNumFmt ) + { + SwTableSortBoxes& rBxs = pTblNd->GetTable().GetTabSortBoxes(); + for( USHORT nBoxes = rBxs.Count(); nBoxes; ) + rDoc.ChkBoxNumFmt( *rBxs[ --nBoxes ], FALSE ); + } + + if( pHistory ) + { + USHORT 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( ULONG nSttNd, 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; + { + 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( USHORT 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 ) + { + USHORT 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( 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::Redo( SwUndoIter& rUndoIter ) +{ + SwDoc& rDoc = rUndoIter.GetDoc(); + SwPaM* pPam = rUndoIter.pAktPam; + + + 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( 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::Repeat( SwUndoIter& rUndoIter ) +{ + SwTableNode* pTblNd = rUndoIter.pAktPam->GetNode()->FindTableNode(); + if( pTblNd ) + { + // bewege den Cursor aus der Tabelle + SwPaM* pPam = rUndoIter.pAktPam; + pPam->GetPoint()->nNode = *pTblNd->EndOfSectionNode(); + pPam->Move( fnMoveForward, fnGoCntnt ); + pPam->SetMark(); + pPam->DeleteMark(); + + rUndoIter.GetDoc().TableToText( pTblNd, cTrenner ); + } +} + +void SwUndoTblToTxt::SetRange( const SwNodeRange& rRg ) +{ + nSttNd = rRg.aStart.GetIndex(); + nEndNd = rRg.aEnd.GetIndex(); +} + +void SwUndoTblToTxt::AddBoxPos( SwDoc& rDoc, ULONG nNdIdx, 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, USHORT 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::Undo( SwUndoIter& rUndoIter ) +{ + SwDoc& rDoc = rUndoIter.GetDoc(); + + ULONG nTblNd = nSttNode; + if( nSttCntnt ) + ++nTblNd; // Node wurde vorher gesplittet + SwNodeIndex aIdx( rDoc.GetNodes(), nTblNd ); + SwTableNode* pTNd = rDoc.GetNodes()[ aIdx ]->GetTableNode(); + ASSERT( pTNd, "keinen Tabellen-Node gefunden" ); + + RemoveIdxFromSection( rDoc, nTblNd ); + + sTblNm = pTNd->GetTable().GetFrmFmt()->GetName(); + + if( pHistory ) + { + pHistory->TmpRollback( &rDoc, 0 ); + pHistory->SetTmpEnd( pHistory->Count() ); + } + + if( pDelBoxes ) + { + SwTable& rTbl = pTNd->GetTable(); + for( USHORT n = pDelBoxes->Count(); n; ) + { + SwTableBox* pBox = rTbl.GetTblBox( (*pDelBoxes)[ --n ] ); + if( pBox ) + ::_DeleteBox( rTbl, pBox, 0, FALSE, FALSE ); + else { + ASSERT( !this, "Wo ist die Box geblieben?" ); + } + } + } + + SwNodeIndex aEndIdx( *pTNd->EndOfSectionNode() ); + rDoc.TableToText( pTNd, 0x0b == cTrenner ? 0x09 : cTrenner ); + + // am Start wieder zusammenfuegen ? + SwPosition* pPos = rUndoIter.pAktPam->GetPoint(); + if( nSttCntnt ) + { + pPos->nNode = nTblNd; + pPos->nContent.Assign( rDoc.GetNodes()[ pPos->nNode ]->GetCntntNode(), 0 ); + if( rUndoIter.pAktPam->Move( fnMoveBackward, fnGoCntnt)) + { + SwNodeIndex& rIdx = rUndoIter.pAktPam->GetPoint()->nNode; + + // dann die Crsr/etc. nochmal relativ verschieben + RemoveIdxRel( rIdx.GetIndex()+1, *pPos ); + + rIdx.GetNode().GetCntntNode()->JoinNext(); + } + } + + // am Ende wieder zusammenfuegen ? + if( bSplitEnd ) + { + SwNodeIndex& rIdx = pPos->nNode; + rIdx = nEndNode; + SwTxtNode* pTxtNd = rIdx.GetNode().GetTxtNode(); + if( pTxtNd && pTxtNd->CanJoinNext() ) + { + rUndoIter.pAktPam->GetMark()->nContent.Assign( 0, 0 ); + rUndoIter.pAktPam->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(); + } + } + + SetPaM( rUndoIter ); // manipulierten Bereich selectieren +} + + +void SwUndoTxtToTbl::Redo( SwUndoIter& rUndoIter ) +{ + SetPaM( rUndoIter ); + RemoveIdxFromRange( *rUndoIter.pAktPam, FALSE ); + SetPaM( rUndoIter ); + + const SwTable* pTable = rUndoIter.GetDoc().TextToTable( + aInsTblOpts, *rUndoIter.pAktPam, cTrenner, + nAdjust, pAutoFmt ); + ((SwFrmFmt*)pTable->GetFrmFmt())->SetName( sTblNm ); +} + + +void SwUndoTxtToTbl::Repeat( SwUndoIter& rUndoIter ) +{ + // keine TABLE IN TABLE + if( !rUndoIter.pAktPam->GetNode()->FindTableNode() ) + rUndoIter.GetDoc().TextToTable( aInsTblOpts, *rUndoIter.pAktPam, + 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, USHORT nOldHdl, + USHORT 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::Undo( SwUndoIter& rUndoIter ) +{ + SwDoc& rDoc = rUndoIter.GetDoc(); + SwTableNode* pTNd = rDoc.GetNodes()[ nTblNd ]->GetTableNode(); + ASSERT( pTNd, "keinen Tabellen-Node gefunden" ); + + rDoc.SetRowsToRepeat( pTNd->GetTable(), nOldHeadline ); +} + + +void SwUndoTblHeadline::Redo( SwUndoIter& rUndoIter ) +{ + SwDoc& rDoc = rUndoIter.GetDoc(); + + SwTableNode* pTNd = rDoc.GetNodes()[ nTblNd ]->GetTableNode(); + ASSERT( pTNd, "keinen Tabellen-Node gefunden" ); + + rDoc.SetRowsToRepeat( pTNd->GetTable(), nNewHeadline ); +} + + +void SwUndoTblHeadline::Repeat( SwUndoIter& rUndoIter ) +{ + SwTableNode* pTblNd = rUndoIter.pAktPam->GetNode()->FindTableNode(); + if( pTblNd ) + rUndoIter.GetDoc().SetRowsToRepeat( pTblNd->GetTable(), nNewHeadline ); +} + + +/* */ + + + +_SaveTable::_SaveTable( const SwTable& rTbl, USHORT 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().Count(); + for( USHORT n = 1; n < nLnCnt; ++n ) + pLn = new _SaveLine( pLn, *rTbl.GetTabLines()[ n ], *this ); + + aFrmFmts.Remove( 0, aFrmFmts.Count() ); + pSwTable = 0; +} + + +_SaveTable::~_SaveTable() +{ + delete pLine; +} + + +USHORT _SaveTable::AddFmt( SwFrmFmt* pFmt, bool bIsLine ) +{ + USHORT 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, 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, BOOL bMdfyBox ) +{ + USHORT 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( FALSE ); + } + + // zur Sicherheit alle Tableframes invalidieren + SwClientIter aIter( *pFmt ); + for( SwClient* pLast = aIter.First( TYPE( SwFrm ) ); pLast; pLast = aIter.Next() ) + if( ((SwTabFrm*)pLast)->GetTable() == &rTbl ) + { + ((SwTabFrm*)pLast)->InvalidateAll(); + ((SwTabFrm*)pLast)->SetCompletePaint(); + } + + // FrmFmts mit Defaults (0) fuellen + pFmt = 0; + for( n = aSets.Count(); n; --n ) + aFrmFmts.Insert( pFmt, aFrmFmts.Count() ); + + USHORT 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 = FALSE; +} + + +void _SaveTable::SaveCntntAttrs( SwDoc* pDoc ) +{ + pLine->SaveCntntAttrs( pDoc ); +} + + +void _SaveTable::CreateNew( SwTable& rTbl, BOOL bCreateFrms, + BOOL bRestoreChart ) +{ + USHORT 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( 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 + USHORT 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(); + USHORT nBoxes = rBoxes.Count(); + for (USHORT 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 (USHORT k1 = 0; k1 < nOldLines - n; ++k1) + { + const SwTableBoxes &rBoxes = rTbl.GetTabLines()[n + k1]->GetTabBoxes(); + USHORT nBoxes = rBoxes.Count(); + for (USHORT 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 SwClient* pLnBx, BOOL bIsLine, + USHORT nFmtPos, SwFrmFmt* pOldFmt ) +{ + SwDoc* pDoc = pOldFmt->GetDoc(); + + SwFrmFmt* pFmt = aFrmFmts[ nFmtPos ]; + if( !pFmt ) + { + if( bIsLine ) + pFmt = pDoc->MakeTableLineFmt(); + else + pFmt = pDoc->MakeTableBoxFmt(); + pFmt->SetFmtAttr( *aSets[ nFmtPos ] ); + aFrmFmts.Replace( pFmt, nFmtPos ); + } + + //Erstmal die Frms ummelden. + SwClientIter aIter( *pOldFmt ); + for( SwClient* pLast = aIter.First( TYPE( SwFrm ) ); pLast; pLast = aIter.Next() ) + { + if( bIsLine ? pLnBx == ((SwRowFrm*)pLast)->GetTabLine() + : pLnBx == ((SwCellFrm*)pLast)->GetTabBox() ) + { + pFmt->Add( pLast ); + ((SwFrm*)pLast)->InvalidateAll(); + ((SwFrm*)pLast)->ReinitializeFrmSizeAttrFlags(); + if ( !bIsLine ) + { + ((SwCellFrm*)pLast)->SetDerivedVert( FALSE ); + ((SwCellFrm*)pLast)->CheckDirChange(); + } + } + } + + //Jetzt noch mich selbst ummelden. + pFmt->Add( (SwClient*)pLnBx ); + + if( bModifyBox && !bIsLine ) + { + const SfxPoolItem& rOld = pOldFmt->GetFmtAttr( RES_BOXATR_FORMAT ), + & rNew = pFmt->GetFmtAttr( RES_BOXATR_FORMAT ); + if( rOld != rNew ) + pFmt->Modify( (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( USHORT 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, TRUE, nItemSet, rLine.GetFrmFmt() ); + + _SaveBox* pBx = pBox; + for( USHORT 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( USHORT 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( &rBox, FALSE, 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( USHORT 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(); + USHORT nSet = 0; + ULONG nEnd = rBox.GetSttNd()->EndOfSectionIndex(); + for( ULONG n = nSttNode + 1; n < nEnd; ++n ) + { + SwCntntNode* pCNd = rNds[ n ]->GetCntntNode(); + if( pCNd ) + { + SfxItemSet* pSet = (*Ptrs.pCntntAttrs)[ nSet++ ]; + if( pSet ) + { + USHORT *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 + { + ULONG nEnd = pDoc->GetNodes()[ nSttNode ]->EndOfSectionIndex(); + Ptrs.pCntntAttrs = new SfxItemSets( (BYTE)(nEnd - nSttNode - 1 ), 5 ); + for( 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(); + pFmt->Add( pBox ); + 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, BOOL bClearTabCols ) + : SwUndo( UNDO_TABLE_ATTR ), + nSttNode( rTblNd.GetIndex() ) +{ + bClearTabCol = bClearTabCols; + pSaveTbl = new _SaveTable( rTblNd.GetTable() ); +} + + +SwUndoAttrTbl::~SwUndoAttrTbl() +{ + delete pSaveTbl; +} + + + +void SwUndoAttrTbl::Undo( SwUndoIter& rUndoIter ) +{ + SwDoc& rDoc = rUndoIter.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::Redo( SwUndoIter& rUndoIter ) +{ + Undo( rUndoIter ); +} + + +/* */ + +// UndoObject fuer AutoFormat an der Tabelle + + +SwUndoTblAutoFmt::SwUndoTblAutoFmt( const SwTableNode& rTblNd, + const SwTableAutoFmt& rAFmt ) + : SwUndo( UNDO_TABLE_AUTOFMT ), + nSttNode( rTblNd.GetIndex() ), pUndos( 0 ), + bSaveCntntAttr( 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 = TRUE; + } +} + + +SwUndoTblAutoFmt::~SwUndoTblAutoFmt() +{ + delete pUndos; + delete pSaveTbl; +} + +void SwUndoTblAutoFmt::SaveBoxCntnt( const SwTableBox& rBox ) +{ + SwUndoTblNumFmt* p = new SwUndoTblNumFmt( rBox ); + if( !pUndos ) + pUndos = new SwUndos( 8, 8 ); + pUndos->Insert( p, pUndos->Count() ); +} + + +void SwUndoTblAutoFmt::UndoRedo( BOOL bUndo, SwUndoIter& rUndoIter ) +{ + SwDoc& rDoc = rUndoIter.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( pUndos && bUndo ) + for( USHORT n = pUndos->Count(); n; ) + pUndos->GetObject( --n )->Undo( rUndoIter ); + + pSaveTbl->RestoreAttr( pTblNd->GetTable(), !bUndo ); + delete pSaveTbl; + pSaveTbl = pOrig; +} + +void SwUndoTblAutoFmt::Undo( SwUndoIter& rUndoIter ) +{ + UndoRedo( TRUE, rUndoIter ); +} + + +void SwUndoTblAutoFmt::Redo( SwUndoIter& rUndoIter ) +{ + UndoRedo( FALSE, rUndoIter ); +} + + +/* */ + + +SwUndoTblNdsChg::SwUndoTblNdsChg( SwUndoId nAction, + const SwSelBoxes& rBoxes, + const SwTableNode& rTblNd, + long nMn, long nMx, + USHORT nCnt, BOOL bFlg, BOOL bSmHght ) + : SwUndo( nAction ), + aBoxes( rBoxes.Count() < 255 ? (BYTE)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( USHORT 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 ? (BYTE)rBoxes.Count() : 255, 10 ), + nMin( 0 ), nMax( 0 ), + nSttNode( rTblNd.GetIndex() ), nCurrBox( 0 ), + nCount( 0 ), nRelDiff( 0 ), nAbsDiff( 0 ), + nSetColType( USHRT_MAX ), + bFlag( FALSE ), + bSameHeight( FALSE ) +{ + Ptrs.pNewSttNds = 0; + + const SwTable& rTbl = rTblNd.GetTable(); + pSaveTbl = new _SaveTable( rTbl ); + + // und die Selektion merken + for( USHORT 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( USHORT 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(); + USHORT n; + USHORT i; + + ASSERT( ! IsDelBox(), "falsche Action" ); + Ptrs.pNewSttNds = new SvULongs( (BYTE)(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(); + USHORT 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( (BYTE)(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( USHORT 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) + USHORT 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(); + USHORT nLineDiff = lcl_FindParentLines(rTbl,*pBox).C40_GETPOS(SwTableLine,pBoxLine); + USHORT nLineNo = 0; + for( USHORT j = 0; j < rBoxes.Count(); ++j ) + { + pCheckBox = rBoxes[j]; + if( pCheckBox->GetUpper()->GetUpper() == pBox->GetUpper()->GetUpper() ) + { + const SwTableLine* pCheckLine = pCheckBox->GetUpper(); + USHORT 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) + USHORT nNdsPos = 0; + while( rBoxes[ nNdsPos ] != pSourceBox ) + ++nNdsPos; + 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. + BOOL bNodesMoved = + ( nNodes != ( pSourceBox->GetSttNd()->EndOfSectionIndex() - + pSourceBox->GetSttIdx() ) ) + && ( nNodes - 1 > nLineDiff ); + aMvBoxes.Insert( bNodesMoved, nInsPos ); + } + } +} + + +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::Undo( SwUndoIter& rUndoIter ) +{ + SwDoc& rDoc = rUndoIter.GetDoc(); + SwNodeIndex aIdx( rDoc.GetNodes(), nSttNode ); + + SwTableNode* pTblNd = rDoc.GetNodes()[ aIdx ]->GetTableNode(); + ASSERT( pTblNd, "kein TabellenNode" ); + + SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() ); + aMsgHnt.eFlags = TBL_BOXPTR; + rDoc.UpdateTblFlds( &aMsgHnt ); + + CHECK_TABLE( pTblNd->GetTable() ) + + _FndBox aTmpBox( 0, 0 ); + // ? TL_CHART2: notification or locking of controller required ? + + SwChartDataProvider *pPCD = rDoc.GetChartDataProvider(); + std::vector< SwTableBox* > aDelBoxes; + if( IsDelBox() ) + { + // Trick: die fehlenden Boxen in irgendeine Line einfuegen, beim + // CreateNew werden sie korrekt verbunden. + SwTableBox* pCpyBox = pTblNd->GetTable().GetTabSortBoxes()[0]; + SwTableBoxes& rLnBoxes = pCpyBox->GetUpper()->GetTabBoxes(); + + // die Sections wieder herstellen + for( USHORT 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.Count() ) + { + // 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( USHORT n = aTmp.Count(); n; ) + { + // Box aus der Tabellen-Struktur entfernen + 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 + USHORT i = n; + 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, FALSE ); + } + else + rDoc.DeleteSection( rDoc.GetNodes()[ nIdx ] ); + aDelBoxes.insert( aDelBoxes.end(), pBox ); + } + } + else + { + // Remove nodes from nodes array (backwards!) + for( USHORT n = Ptrs.pNewSttNds->Count(); n; ) + { + 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( USHORT 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(), 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::Redo( SwUndoIter& rUndoIter ) +{ + SwDoc& rDoc = rUndoIter.GetDoc(); + + SwTableNode* pTblNd = rDoc.GetNodes()[ nSttNode ]->GetTableNode(); + ASSERT( pTblNd, "kein TabellenNode" ); + CHECK_TABLE( pTblNd->GetTable() ) + + SwSelBoxes aSelBoxes; + for( USHORT 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, 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 ); + + rDoc.DoUndo( TRUE ); // wir brauchen die SaveSections! + 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.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::Undo( SwUndoIter& rUndoIter ) +{ + SwDoc& rDoc = rUndoIter.GetDoc(); + SwNodeIndex aIdx( rDoc.GetNodes(), nTblNode ); + + SwTableNode* pTblNd = rDoc.GetNodes()[ aIdx ]->GetTableNode(); + ASSERT( pTblNd, "kein TabellenNode" ); + + SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() ); + aMsgHnt.eFlags = TBL_BOXPTR; + rDoc.UpdateTblFlds( &aMsgHnt ); + + _FndBox aTmpBox( 0, 0 ); + // ? TL_CHART2: notification or locking of controller required ? + + + // 1. die geloeschten Boxen wiederherstellen: + + // Trick: die fehlenden Boxen in irgendeine Line einfuegen, beim + // CreateNew werden sie korrekt verbunden. + SwTableBox *pBox, *pCpyBox = pTblNd->GetTable().GetTabSortBoxes()[0]; + SwTableBoxes& rLnBoxes = pCpyBox->GetUpper()->GetTabBoxes(); + +DUMPDOC( &rDoc, "d:\\tmp\\tab_a.db" ) +CHECKTABLE(pTblNd->GetTable()) + + SwSelBoxes aSelBoxes; + SwTxtFmtColl* pColl = rDoc.GetTxtCollFromPool( RES_POOLCOLL_STANDARD ); + USHORT 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 + 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( USHORT i = pMoves->Count(); i; ) + { + SwTxtNode* pTxtNd = 0; + USHORT nDelPos = 0; + SwUndoMove* pUndo = (*pMoves)[ --i ]; + if( !pUndo->IsMoveRange() ) + { + pTxtNd = rDoc.GetNodes()[ pUndo->GetDestSttNode() ]->GetTxtNode(); + nDelPos = pUndo->GetDestSttCntnt() - 1; + } + pUndo->Undo( rUndoIter ); + if( pUndo->IsMoveRange() ) + { + // den ueberfluessigen Node loeschen + aIdx = pUndo->GetEndNode(); + SwCntntNode *pCNd = aIdx.GetNode().GetCntntNode(); + if( pCNd ) + { + SwNodeIndex aTmp( aIdx, -1 ); + SwCntntNode *pMove = aTmp.GetNode().GetCntntNode(); + if( pMove ) + pCNd->MoveTo( *pMove ); + } + rDoc.GetNodes().Delete( aIdx, 1 ); + } + else if( pTxtNd ) + { + // evt. noch ueberflussige Attribute loeschen + SwIndex aTmpIdx( pTxtNd, nDelPos ); + if( pTxtNd->GetpSwpHints() && pTxtNd->GetpSwpHints()->Count() ) + pTxtNd->RstAttr( aTmpIdx, pTxtNd->GetTxt().Len() - + nDelPos + 1 ); + // das Trennzeichen loeschen + pTxtNd->EraseText( aTmpIdx, 1 ); + } +// delete pUndo; +DUMPDOC( &rDoc, String( "d:\\tmp\\tab_") + String( aNewSttNds.Count() - i ) + + String(".db") ) + } +// pMoves->Remove( 0, pMoves->Count() ); + 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 )), TRUE ); + } + + delete pBox; + rDoc.DeleteSection( rDoc.GetNodes()[ nIdx ] ); + } + } +DUMPDOC( &rDoc, "d:\\tmp\\tab_z.db" ) +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() ); + } +// nTblNode = pTblNd->GetIndex(); + + SwPaM* pPam = rUndoIter.pAktPam; + pPam->DeleteMark(); + pPam->GetPoint()->nNode = nSttNode; + pPam->GetPoint()->nContent.Assign( pPam->GetCntntNode(), nSttCntnt ); + pPam->SetMark(); + pPam->DeleteMark(); + +CHECKTABLE(pTblNd->GetTable()) + ClearFEShellTabCols(); +} + + +void SwUndoTblMerge::Redo( SwUndoIter& rUndoIter ) +{ + SwPaM* pPam = rUndoIter.pAktPam; + SwDoc& rDoc = *pPam->GetDoc(); + + SetPaM( *pPam ); + rDoc.MergeTbl( *pPam ); +} + +void SwUndoTblMerge::MoveBoxCntnt( SwDoc* pDoc, SwNodeRange& rRg, SwNodeIndex& rPos ) +{ + SwNodeIndex aTmp( rRg.aStart, -1 ), aTmp2( rPos, -1 ); + SwUndoMove* pUndo = new SwUndoMove( pDoc, rRg, rPos ); + sal_Bool bDoesUndo = pDoc->DoesUndo(); + pDoc->DoUndo( sal_False ); + pDoc->MoveNodeRange( rRg, rPos, (pSaveTbl->IsNewModel()) ? + IDocumentContentOperations::DOC_NO_DELFRMS : + IDocumentContentOperations::DOC_MOVEDEFAULT ); + if( bDoesUndo ) + pDoc->DoUndo( sal_True ); + aTmp++; + aTmp2++; + pUndo->SetDestRange( aTmp2, rPos, aTmp ); + + pMoves->Insert( pUndo, pMoves->Count() ); +} + + +void SwUndoTblMerge::SetSelBoxes( const SwSelBoxes& rBoxes ) +{ + // die Selektion merken + for( USHORT n = 0; n < rBoxes.Count(); ++n ) + InsertSort( aBoxes, rBoxes[n]->GetSttIdx() ); + + // als Trennung fuers einfuegen neuer Boxen nach dem Verschieben! + aNewSttNds.Insert( (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 = 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, + FALSE, &pItem )) + { + bNewFmt = TRUE; + nNewFmtIdx = ((SwTblBoxNumFormat*)pItem)->GetValue(); + } + if( SFX_ITEM_SET == pNewSet->GetItemState( RES_BOXATR_FORMULA, + FALSE, &pItem )) + { + bNewFml = TRUE; + aNewFml = ((SwTblBoxFormula*)pItem)->GetFormula(); + } + if( SFX_ITEM_SET == pNewSet->GetItemState( RES_BOXATR_VALUE, + FALSE, &pItem )) + { + bNewValue = TRUE; + fNewNum = ((SwTblBoxValue*)pItem)->GetValue(); + } + } + + // wird die History ueberhaupt benoetigt ?? + if( pHistory && !pHistory->Count() ) + DELETEZ( pHistory ); +} + + +SwUndoTblNumFmt::~SwUndoTblNumFmt() +{ + delete pHistory; + delete pBoxSet; +} + +void SwUndoTblNumFmt::Undo( SwUndoIter& rIter ) +{ + ASSERT( pBoxSet, "Where's the stored item set?" ) + + SwDoc& rDoc = rIter.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 ) + { + USHORT nTmpEnd = pHistory->GetTmpEnd(); + pHistory->TmpRollback( &rDoc, 0 ); + pHistory->SetTmpEnd( nTmpEnd ); + } + + SwPaM* pPam = rIter.pAktPam; + 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::Redo( SwUndoIter& rIter ) +{ + // konnte die Box veraendert werden ? + if( !pBoxSet ) + return ; + + SwDoc& rDoc = rIter.GetDoc(); + + SwPaM* pPam = rIter.pAktPam; + pPam->DeleteMark(); + pPam->GetPoint()->nNode = nNode; + + SwNode* pNd = rDoc.GetNodes()[ pPam->GetPoint()->nNode ]; + 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::Undo( SwUndoIter& rIter ) +{ + SwDoc& rDoc = rIter.GetDoc(); + _DEBUG_REDLINE( &rDoc ) + + SwTableNode* pTblNd = 0; + for( USHORT n = pArr->Count(); n; ) + { + _UndoTblCpyTbl_Entry* pEntry = (*pArr)[ --n ]; + 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 *pUnDel = (SwUndoDelete*)pEntry->pUndo; + if( UNDO_REDLINE == pUnDel->GetId() ) + { + // 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, pUnDel->NodeDiff()-1 ); + SwTxtNode *pTxt = aTmpIdx.GetNode().GetTxtNode(); + if( pTxt ) + { + aPam.GetPoint()->nNode = *pTxt; + aPam.GetPoint()->nContent.Assign( pTxt, pUnDel->ContentStart() ); + } + else + *aPam.GetPoint() = SwPosition( aTmpIdx ); + } + else if( pUnDel->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->Undo( rIter ); + delete pEntry->pUndo; + } + 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, TRUE ); + } + else + { + pUndo = new SwUndoDelete( aPam, true ); + if( pEntry->pUndo ) + { + pEntry->pUndo->Undo( rIter ); + delete pEntry->pUndo; + } + } + 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->Undo( rIter ); + _DEBUG_REDLINE( &rDoc ) +} + +void SwUndoTblCpyTbl::Redo( SwUndoIter& rIter ) +{ + SwDoc& rDoc = rIter.GetDoc(); + _DEBUG_REDLINE( &rDoc ) + + if( pInsRowUndo ) + pInsRowUndo->Redo( rIter ); + + SwTableNode* pTblNd = 0; + for( USHORT n = 0; n < pArr->Count(); ++n ) + { + _UndoTblCpyTbl_Entry* pEntry = (*pArr)[ n ]; + 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, TRUE ); + if( pEntry->pUndo ) + { + pEntry->pUndo->Undo( rIter ); + 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 ) + pUndo = PrepareRedline( &rDoc, rBox, *rIter.pAktPam->GetPoint(), + pEntry->bJoin, true ); + else + { + SwPosition aTmpPos( aInsIdx ); + pUndo = PrepareRedline( &rDoc, rBox, aTmpPos, pEntry->bJoin, true ); + } + } + delete pEntry->pUndo; + } + 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->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, 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)[ 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, 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; +} + + +BOOL SwUndoTblCpyTbl::InsertRow( SwTable& rTbl, const SwSelBoxes& rBoxes, + USHORT nCnt ) +{ + SwTableNode* pTblNd = (SwTableNode*)rTbl.GetTabSortBoxes()[0]-> + GetSttNd()->FindTableNode(); + + SwTableSortBoxes aTmpLst( 0, 5 ); + pInsRowUndo = new SwUndoTblNdsChg( UNDO_TABLE_INSROW, rBoxes, *pTblNd, + 0, 0, nCnt, TRUE, FALSE ); + aTmpLst.Insert( &rTbl.GetTabSortBoxes(), 0, rTbl.GetTabSortBoxes().Count() ); + + BOOL bRet = rTbl.InsertRow( rTbl.GetFrmFmt()->GetDoc(), rBoxes, nCnt, TRUE ); + if( bRet ) + pInsRowUndo->SaveNewBoxes( *pTblNd, aTmpLst ); + else + delete pInsRowUndo, pInsRowUndo = 0; + return bRet; +} + +BOOL SwUndoTblCpyTbl::IsEmpty() const +{ + return !pInsRowUndo && !pArr->Count(); +} + +/* */ + +SwUndoCpyTbl::SwUndoCpyTbl() + : SwUndo( UNDO_CPYTBL ), pDel( 0 ), nTblNode( 0 ) +{ +} + +SwUndoCpyTbl::~SwUndoCpyTbl() +{ + delete pDel; +} + +void SwUndoCpyTbl::Undo( SwUndoIter& rIter ) +{ + SwDoc& rDoc = rIter.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, + FALSE, &pItem ) ) + pNextNd->SetAttr( *pItem ); + + if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_BREAK, + FALSE, &pItem ) ) + pNextNd->SetAttr( *pItem ); + } + + SwPaM aPam( *pTNd, *pTNd->EndOfSectionNode(), 0 , 1 ); + pDel = new SwUndoDelete( aPam, TRUE ); +} + +void SwUndoCpyTbl::Redo( SwUndoIter& rIter ) +{ + pDel->Undo( rIter ); + delete pDel, pDel = 0; +} + + +/* */ + +SwUndoSplitTbl::SwUndoSplitTbl( const SwTableNode& rTblNd, + SwSaveRowSpan* pRowSp, USHORT eMode, 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, FALSE ); + break; + } +} + +SwUndoSplitTbl::~SwUndoSplitTbl() +{ + delete pSavTbl; + delete pHistory; + delete mpSaveRowSpan; +} + +void SwUndoSplitTbl::Undo( SwUndoIter& rIter ) +{ + SwPaM* pPam = rIter.pAktPam; + SwDoc* pDoc = pPam->GetDoc(); + + 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, 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, 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::Redo( SwUndoIter& rIter ) +{ + SwPaM* pPam = rIter.pAktPam; + SwDoc* pDoc = pPam->GetDoc(); + + pPam->DeleteMark(); + pPam->GetPoint()->nNode = nTblNode; + pDoc->SplitTable( *pPam->GetPoint(), nMode, bCalcNewSize ); + + ClearFEShellTabCols(); +} + +void SwUndoSplitTbl::Repeat( SwUndoIter& rIter ) +{ + SwPaM* pPam = rIter.pAktPam; + SwDoc* pDoc = pPam->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, + BOOL bWithPrv, USHORT 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::Undo( SwUndoIter& rIter ) +{ + SwPaM* pPam = rIter.pAktPam; + SwDoc* pDoc = pPam->GetDoc(); + + 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, TRUE, 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, 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::Redo( SwUndoIter& rIter ) +{ + SwPaM* pPam = rIter.pAktPam; + SwDoc* pDoc = pPam->GetDoc(); + + 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::Repeat( SwUndoIter& rIter ) +{ + SwPaM* pPam = rIter.pAktPam; + SwDoc* pDoc = pPam->GetDoc(); + + 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, USHORT nIdx, USHORT* pInsPos ) +{ + USHORT nO = rArr.Count(), nM, nU = 0; + if( nO > 0 ) + { + nO--; + while( nU <= nO ) + { + nM = nU + ( nO - nU ) / 2; + if( *(rArr.GetData() + nM) == nIdx ) + { + ASSERT( 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, ULONG nIdx, USHORT* pInsPos ) +{ + USHORT nO = rArr.Count(), nM, nU = 0; + if( nO > 0 ) + { + nO--; + while( nU <= nO ) + { + nM = nU + ( nO - nU ) / 2; + if( *(rArr.GetData() + nM) == nIdx ) + { + ASSERT( 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( USHORT 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 + + diff --git a/sw/source/core/undo/untblk.cxx b/sw/source/core/undo/untblk.cxx new file mode 100644 index 000000000000..e9e7ce1e0e02 --- /dev/null +++ b/sw/source/core/undo/untblk.cxx @@ -0,0 +1,367 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <hintids.hxx> +#include <fmtanchr.hxx> +#include <frmfmt.hxx> +#include <doc.hxx> +#include <docary.hxx> +#include <swundo.hxx> // fuer die UndoIds +#include <pam.hxx> +#include <ndtxt.hxx> +#include <undobj.hxx> +#include <rolbck.hxx> +#include <redline.hxx> + + + +SwUndoInserts::SwUndoInserts( SwUndoId nUndoId, const SwPaM& rPam ) + : SwUndo( nUndoId ), SwUndRng( rPam ), + pTxtFmtColl( 0 ), pLastNdColl(0), pFrmFmts( 0 ), pFlyUndos(0), pRedlData( 0 ), + bSttWasTxtNd( TRUE ), nNdDiff( 0 ), pPos( 0 ), nSetPos( 0 ) +{ + pHistory = new SwHistory; + SwDoc* pDoc = (SwDoc*)rPam.GetDoc(); + + SwTxtNode* pTxtNd = rPam.GetPoint()->nNode.GetNode().GetTxtNode(); + if( pTxtNd ) + { + pTxtFmtColl = pTxtNd->GetTxtColl(); + pHistory->CopyAttr( pTxtNd->GetpSwpHints(), nSttNode, + 0, pTxtNd->GetTxt().Len(), false ); + if( pTxtNd->HasSwAttrSet() ) + pHistory->CopyFmtAttr( *pTxtNd->GetpSwAttrSet(), nSttNode ); + + if( !nSttCntnt ) // dann werden Flys mitgenommen !! + { + USHORT nArrLen = pDoc->GetSpzFrmFmts()->Count(); + for( USHORT n = 0; n < nArrLen; ++n ) + { + SwFrmFmt* pFmt = (*pDoc->GetSpzFrmFmts())[n]; + SwFmtAnchor const*const pAnchor = &pFmt->GetAnchor(); + const SwPosition* pAPos = pAnchor->GetCntntAnchor(); + if (pAPos && + (pAnchor->GetAnchorId() == FLY_AT_PARA) && + nSttNode == pAPos->nNode.GetIndex() ) + { + if( !pFrmFmts ) + pFrmFmts = new SvPtrarr; + pFrmFmts->Insert( pFmt, pFrmFmts->Count() ); + } + } + } + } + // Redline beachten + if( pDoc->IsRedlineOn() ) + { + pRedlData = new SwRedlineData( nsRedlineType_t::REDLINE_INSERT, pDoc->GetRedlineAuthor() ); + SetRedlineMode( pDoc->GetRedlineMode() ); + } +} + +// setze den Destination-Bereich nach dem Einlesen. + +void SwUndoInserts::SetInsertRange( const SwPaM& rPam, BOOL bScanFlys, + BOOL bSttIsTxtNd ) +{ + const SwPosition* pTmpPos = rPam.End(); + nEndNode = pTmpPos->nNode.GetIndex(); + nEndCntnt = pTmpPos->nContent.GetIndex(); + if( rPam.HasMark() ) + { + if( pTmpPos == rPam.GetPoint() ) + pTmpPos = rPam.GetMark(); + else + pTmpPos = rPam.GetPoint(); + + nSttNode = pTmpPos->nNode.GetIndex(); + nSttCntnt = pTmpPos->nContent.GetIndex(); + + if( !bSttIsTxtNd ) // wird eine Tabellenselektion eingefuegt, + { + ++nSttNode; // dann stimmt der CopyPam nicht ganz + bSttWasTxtNd = FALSE; + } + } + + if( bScanFlys && !nSttCntnt ) + { + // dann alle neuen Flys zusammen sammeln !! + SwDoc* pDoc = (SwDoc*)rPam.GetDoc(); + pFlyUndos = new SwUndos(); + USHORT nFndPos, nArrLen = pDoc->GetSpzFrmFmts()->Count(); + for( USHORT n = 0; n < nArrLen; ++n ) + { + SwFrmFmt* pFmt = (*pDoc->GetSpzFrmFmts())[n]; + SwFmtAnchor const*const pAnchor = &pFmt->GetAnchor(); + SwPosition const*const pAPos = pAnchor->GetCntntAnchor(); + if (pAPos && + (pAnchor->GetAnchorId() == FLY_AT_PARA) && + nSttNode == pAPos->nNode.GetIndex() ) + { + if( !pFrmFmts || + USHRT_MAX == ( nFndPos = pFrmFmts->GetPos( pFmt ) ) ) + { + SwUndoInsLayFmt* pFlyUndo = new SwUndoInsLayFmt( pFmt,0,0 ); + pFlyUndos->Insert( pFlyUndo, pFlyUndos->Count() ); + } + else + pFrmFmts->Remove( nFndPos ); + } + } + delete pFrmFmts, pFrmFmts = 0; + if( !pFlyUndos->Count() ) + delete pFlyUndos, pFlyUndos = 0; + } +} + + +SwUndoInserts::~SwUndoInserts() +{ + if( pPos ) // loesche noch den Bereich aus dem UndoNodes Array + { + // Insert speichert den Inhalt in der IconSection + SwNodes& rUNds = pPos->nNode.GetNodes(); + if( pPos->nContent.GetIndex() ) // nicht den gesamten Node loeschen + { + SwTxtNode* pTxtNd = pPos->nNode.GetNode().GetTxtNode(); + ASSERT( pTxtNd, "kein TextNode, aus dem geloescht werden soll" ); + if( pTxtNd ) // Robust + { + pTxtNd->EraseText( pPos->nContent ); + } + pPos->nNode++; + } + pPos->nContent.Assign( 0, 0 ); + rUNds.Delete( pPos->nNode, rUNds.GetEndOfExtras().GetIndex() - + pPos->nNode.GetIndex() ); + delete pPos; + } + delete pFrmFmts; + delete pFlyUndos; + delete pRedlData; +} + + +void SwUndoInserts::Undo( SwUndoIter& rUndoIter ) +{ + SwPaM * pPam = rUndoIter.pAktPam; + SwDoc* pDoc = pPam->GetDoc(); + SetPaM( rUndoIter ); + BOOL bUndo = pDoc->DoesUndo(); + pDoc->DoUndo( FALSE ); + + if( IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() )) + pDoc->DeleteRedline( *pPam, true, USHRT_MAX ); + + // sind an Point/Mark 2 unterschiedliche TextNodes, dann muss ein + // JoinNext ausgefuehrt werden. + BOOL bJoinNext = nSttNode != nEndNode && + pPam->GetMark()->nNode.GetNode().GetTxtNode() && + pPam->GetPoint()->nNode.GetNode().GetTxtNode(); + + + // gibts ueberhaupt Inhalt ? (laden von Zeichenvorlagen hat kein Inhalt!) + if( nSttNode != nEndNode || nSttCntnt != nEndCntnt ) + { + if( nSttNode != nEndNode ) + { + SwTxtNode* pTxtNd = pDoc->GetNodes()[ nEndNode ]->GetTxtNode(); + if( pTxtNd && pTxtNd->GetTxt().Len() == nEndCntnt ) + pLastNdColl = pTxtNd->GetTxtColl(); + } + + RemoveIdxFromRange( *pPam, FALSE ); + SetPaM( rUndoIter ); + + // sind Fussnoten oder CntntFlyFrames im Text ?? + nSetPos = pHistory->Count(); + nNdDiff = pPam->GetMark()->nNode.GetIndex(); + DelCntntIndex( *pPam->GetMark(), *pPam->GetPoint() ); + nNdDiff -= pPam->GetMark()->nNode.GetIndex(); + + if( *pPam->GetPoint() != *pPam->GetMark() ) + { + pPos = new SwPosition( *pPam->GetPoint() ); + MoveToUndoNds( *pPam, &pPos->nNode, &pPos->nContent ); + + if( !bSttWasTxtNd ) + pPam->Move( fnMoveBackward, fnGoCntnt ); + } + } + + if( pFlyUndos ) + { + ULONG nTmp = pPam->GetPoint()->nNode.GetIndex(); + for( USHORT n = pFlyUndos->Count(); n; ) + (*pFlyUndos)[ --n ]->Undo( rUndoIter ); + nNdDiff += nTmp - pPam->GetPoint()->nNode.GetIndex(); + } + + SwNodeIndex& rIdx = pPam->GetPoint()->nNode; + SwTxtNode* pTxtNode = rIdx.GetNode().GetTxtNode(); + if( pTxtNode ) + { + if( !pTxtFmtColl ) // falls 0, dann war hier auch kein TextNode, + { // dann muss dieser geloescht werden, + SwNodeIndex aDelIdx( rIdx ); + rIdx++; + SwCntntNode* pCNd = rIdx.GetNode().GetCntntNode(); + xub_StrLen nCnt = 0; if( pCNd ) nCnt = pCNd->Len(); + pPam->GetPoint()->nContent.Assign( pCNd, nCnt ); + pPam->SetMark(); + pPam->DeleteMark(); + + RemoveIdxRel( aDelIdx.GetIndex(), *pPam->GetPoint() ); + + pDoc->GetNodes().Delete( aDelIdx, 1 ); + } + else + { + if( bJoinNext && pTxtNode->CanJoinNext()) + { + { + RemoveIdxRel( rIdx.GetIndex()+1, SwPosition( rIdx, + SwIndex( pTxtNode, pTxtNode->GetTxt().Len() ))); + } + pTxtNode->JoinNext(); + } + // reset all text attributes in the paragraph! + pTxtNode->RstAttr( SwIndex(pTxtNode, 0), pTxtNode->Len(), + 0, 0, true ); + + // setze alle Attribute im Node zurueck + pTxtNode->ResetAllAttr(); + + if( USHRT_MAX != pDoc->GetTxtFmtColls()->GetPos( pTxtFmtColl )) + pTxtFmtColl = (SwTxtFmtColl*)pTxtNode->ChgFmtColl( pTxtFmtColl ); + + pHistory->SetTmpEnd( nSetPos ); + pHistory->TmpRollback( pDoc, 0, false ); + } + } + + pDoc->DoUndo( bUndo ); + if( pPam != rUndoIter.pAktPam ) + delete pPam; +} + +void SwUndoInserts::Redo( SwUndoIter& rUndoIter ) +{ + // setze noch den Cursor auf den Redo-Bereich + SwPaM* pPam = rUndoIter.pAktPam; + SwDoc* pDoc = pPam->GetDoc(); + pPam->DeleteMark(); + pPam->GetPoint()->nNode = nSttNode - nNdDiff; + SwCntntNode* pCNd = pPam->GetCntntNode(); + pPam->GetPoint()->nContent.Assign( pCNd, nSttCntnt ); + + SwTxtFmtColl* pSavTxtFmtColl = pTxtFmtColl; + if( pTxtFmtColl && pCNd && pCNd->IsTxtNode() ) + pSavTxtFmtColl = ((SwTxtNode*)pCNd)->GetTxtColl(); + + pHistory->SetTmpEnd( nSetPos ); + + // alte Anfangs-Position fuers Rollback zurueckholen + if( ( nSttNode != nEndNode || nSttCntnt != nEndCntnt ) && pPos ) + { + BOOL bMvBkwrd = MovePtBackward( *pPam ); + + // Inhalt wieder einfuegen. (erst pPos abmelden !!) + ULONG nMvNd = pPos->nNode.GetIndex(); + xub_StrLen nMvCnt = pPos->nContent.GetIndex(); + DELETEZ( pPos ); + MoveFromUndoNds( *pDoc, nMvNd, nMvCnt, *pPam->GetMark() ); + if( bSttWasTxtNd ) + MovePtForward( *pPam, bMvBkwrd ); + pPam->Exchange(); + } + + if( USHRT_MAX != pDoc->GetTxtFmtColls()->GetPos( pTxtFmtColl )) + { + SwTxtNode* pTxtNd = pPam->GetMark()->nNode.GetNode().GetTxtNode(); + if( pTxtNd ) + pTxtNd->ChgFmtColl( pTxtFmtColl ); + } + pTxtFmtColl = pSavTxtFmtColl; + + if( pLastNdColl && USHRT_MAX != pDoc->GetTxtFmtColls()->GetPos( pLastNdColl ) && + pPam->GetPoint()->nNode != pPam->GetMark()->nNode ) + { + SwTxtNode* pTxtNd = pPam->GetPoint()->nNode.GetNode().GetTxtNode(); + if( pTxtNd ) + pTxtNd->ChgFmtColl( pLastNdColl ); + } + + if( pFlyUndos ) + for( USHORT n = pFlyUndos->Count(); n; ) + (*pFlyUndos)[ --n ]->Redo( rUndoIter ); + + pHistory->Rollback( pDoc, nSetPos ); + + if( pRedlData && IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() )) + { + RedlineMode_t eOld = pDoc->GetRedlineMode(); + pDoc->SetRedlineMode_intern((RedlineMode_t)( eOld & ~nsRedlineMode_t::REDLINE_IGNORE )); + pDoc->AppendRedline( new SwRedline( *pRedlData, *pPam ), true); + pDoc->SetRedlineMode_intern( eOld ); + } + else if( !( nsRedlineMode_t::REDLINE_IGNORE & GetRedlineMode() ) && + pDoc->GetRedlineTbl().Count() ) + pDoc->SplitRedline( *pPam ); +} + +void SwUndoInserts::Repeat( SwUndoIter& rUndoIter ) +{ + if( GetId() == rUndoIter.GetLastUndoId() ) + return; + + SwPaM aPam( *rUndoIter.pAktPam->GetPoint() ); + SetPaM( aPam ); + aPam.GetDoc()->CopyRange( aPam, *rUndoIter.pAktPam->GetPoint(), false ); + + rUndoIter.pLastUndoObj = this; +} + + +/* */ + + +SwUndoInsDoc::SwUndoInsDoc( const SwPaM& rPam ) + : SwUndoInserts( UNDO_INSDOKUMENT, rPam ) +{ +} + +SwUndoCpyDoc::SwUndoCpyDoc( const SwPaM& rPam ) + : SwUndoInserts( UNDO_COPY, rPam ) +{ +} + |