diff options
Diffstat (limited to 'sw/source/core/undo')
28 files changed, 17028 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..afde2760904d --- /dev/null +++ b/sw/source/core/undo/SwRewriter.cxx @@ -0,0 +1,80 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <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; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/undo/SwUndoField.cxx b/sw/source/core/undo/SwUndoField.cxx new file mode 100644 index 000000000000..b89f38dc23c4 --- /dev/null +++ b/sw/source/core/undo/SwUndoField.cxx @@ -0,0 +1,165 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <tools/rtti.hxx> + +#include <SwUndoField.hxx> +#include <swundo.hxx> +#include <doc.hxx> +#include <IDocumentUndoRedo.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, sal_Bool _bUpdate, SwUndoId _nId) + : SwUndoField(rPos,_nId) + , pOldField(rOldField.CopyField()) + , pNewField(rNewField.CopyField()) + , pHnt(_pHnt) + , bUpdate(_bUpdate) +{ + OSL_ENSURE(pOldField, "No old field!"); + OSL_ENSURE(pNewField, "No new field!"); + OSL_ENSURE(pDoc, "No document!"); +} + +SwUndoFieldFromDoc::~SwUndoFieldFromDoc() +{ + delete pOldField; + delete pNewField; +} + +void SwUndoFieldFromDoc::UndoImpl(::sw::UndoRedoContext &) +{ + SwTxtFld * pTxtFld = SwDoc::GetTxtFld(GetPosition()); + + const SwField * pField = pTxtFld ? pTxtFld->GetFld().GetFld() : NULL; + + if (pField) + { + pDoc->UpdateFld(pTxtFld, *pOldField, pHnt, bUpdate); + } +} + +void SwUndoFieldFromDoc::DoImpl() +{ + SwTxtFld * pTxtFld = SwDoc::GetTxtFld(GetPosition()); + const SwField * pField = pTxtFld ? pTxtFld->GetFld().GetFld() : NULL; + + if (pField) + { + 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 ) ); + } +} + +void SwUndoFieldFromDoc::RedoImpl(::sw::UndoRedoContext &) +{ + DoImpl(); +} + +void SwUndoFieldFromDoc::RepeatImpl(::sw::RepeatContext &) +{ + ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo()); + DoImpl(); +} + +SwUndoFieldFromAPI::SwUndoFieldFromAPI(const SwPosition & rPos, + const Any & rOldVal, const Any & rNewVal, + sal_uInt16 _nWhich) + : SwUndoField(rPos), aOldVal(rOldVal), aNewVal(rNewVal), nWhich(_nWhich) +{ +} + +SwUndoFieldFromAPI::~SwUndoFieldFromAPI() +{ +} + +void SwUndoFieldFromAPI::UndoImpl(::sw::UndoRedoContext &) +{ + SwField * pField = SwDoc::GetField(GetPosition()); + + if (pField) + pField->PutValue(aOldVal, nWhich); +} + +void SwUndoFieldFromAPI::DoImpl() +{ + SwField * pField = SwDoc::GetField(GetPosition()); + + if (pField) + pField->PutValue(aNewVal, nWhich); +} + +void SwUndoFieldFromAPI::RedoImpl(::sw::UndoRedoContext &) +{ + DoImpl(); +} + +void SwUndoFieldFromAPI::RepeatImpl(::sw::RepeatContext &) +{ + DoImpl(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/undo/SwUndoFmt.cxx b/sw/source/core/undo/SwUndoFmt.cxx new file mode 100644 index 000000000000..a63b09519bc3 --- /dev/null +++ b/sw/source/core/undo/SwUndoFmt.cxx @@ -0,0 +1,462 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <tools/resid.hxx> +#include <tools/string.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 <doc.hxx> +#include <IDocumentUndoRedo.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(sal_False) +{ + if (_pDerivedFrom) + sDerivedFrom = _pDerivedFrom->GetName(); +} + +SwUndoFmtCreate::~SwUndoFmtCreate() +{ +} + +void SwUndoFmtCreate::UndoImpl(::sw::UndoRedoContext &) +{ + 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(); + + Delete(); + } + } +} + +void SwUndoFmtCreate::RedoImpl(::sw::UndoRedoContext &) +{ + 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; +} + +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::UndoImpl(::sw::UndoRedoContext &) +{ + 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); + } +} + +void SwUndoFmtDelete::RedoImpl(::sw::UndoRedoContext &) +{ + SwFmt * pOld = Find(sOldName); + + if (pOld) + { + Delete(pOld); + } +} + +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::UndoImpl(::sw::UndoRedoContext &) +{ + SwFmt * pFmt = Find(sNewName); + + if (pFmt) + { + pDoc->RenameFmt(*pFmt, sOldName, sal_True); + } +} + +void SwUndoRenameFmt::RedoImpl(::sw::UndoRedoContext &) +{ + SwFmt * pFmt = Find(sOldName); + + if (pFmt) + { + pDoc->RenameFmt(*pFmt, sNewName, sal_True); + } +} + +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, sal_True); +} + +void SwUndoTxtFmtCollCreate::Delete() +{ + pDoc->DelTxtFmtColl((SwTxtFmtColl *) pNew, sal_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, sal_True); +} + +void SwUndoTxtFmtCollDelete::Delete(SwFmt * pOld) +{ + pDoc->DelTxtFmtColl((SwTxtFmtColl *) pOld, sal_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, sal_True); +} + +void SwUndoCharFmtCreate::Delete() +{ + pDoc->DelCharFmt((SwCharFmt *) pNew, sal_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, sal_True); +} + +void SwUndoCharFmtDelete::Delete(SwFmt * pFmt) +{ + pDoc->DelCharFmt((SwCharFmt *) pFmt, sal_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, sal_True, bAuto); +} + +void SwUndoFrmFmtCreate::Delete() +{ + pDoc->DelFrmFmt((SwFrmFmt *) pNew, sal_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, sal_True); +} + +void SwUndoFrmFmtDelete::Delete(SwFmt * pFmt) +{ + pDoc->DelFrmFmt((SwFrmFmt *) pFmt, sal_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::UndoImpl(::sw::UndoRedoContext &) +{ + if (! bInitialized) + { + aNew = *pNew; + bInitialized = true; + } + + pDoc->DelNumRule(aNew.GetName(), sal_True); +} + +void SwUndoNumruleCreate::RedoImpl(::sw::UndoRedoContext &) +{ + pDoc->MakeNumRule(aNew.GetName(), &aNew, sal_True); +} + +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::UndoImpl(::sw::UndoRedoContext &) +{ + pDoc->MakeNumRule(aOld.GetName(), &aOld, sal_True); +} + +void SwUndoNumruleDelete::RedoImpl(::sw::UndoRedoContext &) +{ + pDoc->DelNumRule(aOld.GetName(), sal_True); +} + +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::UndoImpl(::sw::UndoRedoContext &) +{ + pDoc->RenameNumRule(aNewName, aOldName, sal_True); +} + +void SwUndoNumruleRename::RedoImpl(::sw::UndoRedoContext &) +{ + pDoc->RenameNumRule(aOldName, aNewName, sal_True); +} + +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; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/undo/SwUndoPageDesc.cxx b/sw/source/core/undo/SwUndoPageDesc.cxx new file mode 100644 index 000000000000..2b6494003109 --- /dev/null +++ b/sw/source/core/undo/SwUndoPageDesc.cxx @@ -0,0 +1,435 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <tools/resid.hxx> +#include <doc.hxx> +#include <IDocumentUndoRedo.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 ) +{ + sal_uLong nHeaderMaster = ULONG_MAX; + sal_uLong nHeaderLeft = ULONG_MAX; + sal_uLong nFooterMaster = ULONG_MAX; + sal_uLong nFooterLeft = ULONG_MAX; + + 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 ) + { + nHeaderCount = pHeaderFmt->GetClientCount(); + { + int nHeaderCount = 0; + } + const SwFmtCntnt* pCntnt = &pHeaderFmt->GetCntnt(); + if( pCntnt->GetCntntIdx() ) + nHeaderMaster = pCntnt->GetCntntIdx()->GetIndex(); + else + nHeaderMaster = 0; + } + SwFrmFmt* pLeftHeaderFmt = rLeftHead.GetHeaderFmt(); + if( pLeftHeaderFmt ) + { + nLeftHeaderCount = pLeftHeaderFmt->GetClientCount(); + { + int nLeftHeaderCount = 0; + } + const SwFmtCntnt* pLeftCntnt = &pLeftHeaderFmt->GetCntnt(); + if( pLeftCntnt->GetCntntIdx() ) + nHeaderLeft = pLeftCntnt->GetCntntIdx()->GetIndex(); + else + nHeaderLeft = 0; + } + } + if( rFoot.IsActive() ) + { + SwFrmFmt* pFooterFmt = rFoot.GetFooterFmt(); + if( pFooterFmt ) + { + nFooterCount = pFooterFmt->GetClientCount(); + { + int nFooterCount = 0; + } + const SwFmtCntnt* pCntnt = &pFooterFmt->GetCntnt(); + if( pCntnt->GetCntntIdx() ) + nFooterMaster = pCntnt->GetCntntIdx()->GetIndex(); + else + nFooterMaster = 0; + } + SwFrmFmt* pLeftFooterFmt = rLeftFoot.GetFooterFmt(); + if( pLeftFooterFmt ) + { + nLeftFooterCount = pLeftFooterFmt->GetClientCount(); + { + int nLeftFooterCount = 0; + } + 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 ) +{ + OSL_ENSURE(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 ) +{ + OSL_ENSURE( 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, sal_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, sal_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, sal_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, sal_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, sal_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, sal_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, sal_False, &pItem ); + pNewItem = pItem->Clone(); + pNewFmt = ((SwFmtFooter*)pNewItem)->GetFooterFmt(); + pNewFmt->SetFmtAttr( rSourceLeftFoot.GetFooterFmt()->GetCntnt() ); + delete pNewItem; + rSource.GetLeft().GetAttrSet().GetItemState( RES_FOOTER, sal_False, &pItem ); + pNewItem = pItem->Clone(); + pNewFmt = ((SwFmtFooter*)pNewItem)->GetFooterFmt(); + pNewFmt->SetFmtAttr( SwFmtCntnt() ); + delete pNewItem; + } + } +} + +void SwUndoPageDesc::UndoImpl(::sw::UndoRedoContext &) +{ + // 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); +} + +void SwUndoPageDesc::RedoImpl(::sw::UndoRedoContext &) +{ + // 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); +} + +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) +{ + OSL_ENSURE(0 != pDoc, "no document?"); +} + +SwUndoPageDescCreate::~SwUndoPageDescCreate() +{ +} + +void SwUndoPageDescCreate::UndoImpl(::sw::UndoRedoContext &) +{ + // -> #116530# + if (pDesc) + { + aNew = *pDesc; + pDesc = NULL; + } + // <- #116530# + + pDoc->DelPageDesc(aNew.GetName(), sal_True); +} + +void SwUndoPageDescCreate::DoImpl() +{ + SwPageDesc aPageDesc = aNew; + pDoc->MakePageDesc(aNew.GetName(), &aPageDesc, sal_False, sal_True); // #116530# +} + +void SwUndoPageDescCreate::RedoImpl(::sw::UndoRedoContext &) +{ + DoImpl(); +} + +void SwUndoPageDescCreate::RepeatImpl(::sw::RepeatContext &) +{ + ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo()); + DoImpl(); +} + +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) +{ + OSL_ENSURE(0 != pDoc, "no document?"); +} + +SwUndoPageDescDelete::~SwUndoPageDescDelete() +{ +} + +void SwUndoPageDescDelete::UndoImpl(::sw::UndoRedoContext &) +{ + SwPageDesc aPageDesc = aOld; + pDoc->MakePageDesc(aOld.GetName(), &aPageDesc, sal_False, sal_True); // #116530# +} + +void SwUndoPageDescDelete::DoImpl() +{ + pDoc->DelPageDesc(aOld.GetName(), sal_True); // #116530# +} + +void SwUndoPageDescDelete::RedoImpl(::sw::UndoRedoContext &) +{ + DoImpl(); +} + +void SwUndoPageDescDelete::RepeatImpl(::sw::RepeatContext &) +{ + ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo()); + DoImpl(); +} + +SwRewriter SwUndoPageDescDelete::GetRewriter() const +{ + SwRewriter aResult; + + aResult.AddRule(UNDO_ARG1, aOld.GetName()); + + return aResult; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/undo/SwUndoTOXChange.cxx b/sw/source/core/undo/SwUndoTOXChange.cxx new file mode 100644 index 000000000000..8b5b8c254090 --- /dev/null +++ b/sw/source/core/undo/SwUndoTOXChange.cxx @@ -0,0 +1,79 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <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::UndoImpl(::sw::UndoRedoContext &) +{ + *pTOX = aOld; + + UpdateTOXBaseSection(); +} + +void SwUndoTOXChange::DoImpl() +{ + *pTOX = aNew; + + UpdateTOXBaseSection(); +} + +void SwUndoTOXChange::RedoImpl(::sw::UndoRedoContext &) +{ + DoImpl(); +} + +void SwUndoTOXChange::RepeatImpl(::sw::RepeatContext &) +{ + DoImpl(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/undo/docundo.cxx b/sw/source/core/undo/docundo.cxx new file mode 100644 index 000000000000..441bf84096a4 --- /dev/null +++ b/sw/source/core/undo/docundo.cxx @@ -0,0 +1,581 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <UndoManager.hxx> + +#include <unotools/undoopt.hxx> + +#include <vcl/wrkwin.hxx> + +#include <svx/svdmodel.hxx> + +#include <swmodule.hxx> +#include <doc.hxx> +#include <ndarr.hxx> +#include <pam.hxx> +#include <ndtxt.hxx> +#include <swundo.hxx> +#include <UndoCore.hxx> +#include <rolbck.hxx> +#include <undo.hrc> +#include <editsh.hxx> +#include <unobaseclass.hxx> + +#include <limits> + +using namespace ::com::sun::star; + + +// the undo array should never grow beyond this limit: +#define UNDO_ACTION_LIMIT (USHRT_MAX - 1000) + + +// UndoManager /////////////////////////////////////////////////////////// + +namespace sw { + +UndoManager::UndoManager(::std::auto_ptr<SwNodes> pUndoNodes, + IDocumentDrawModelAccess & rDrawModelAccess, + IDocumentRedlineAccess & rRedlineAccess, + IDocumentState & rState) + : m_rDrawModelAccess(rDrawModelAccess) + , m_rRedlineAccess(rRedlineAccess) + , m_rState(rState) + , m_pUndoNodes(pUndoNodes) + , m_bGroupUndo(true) + , m_bDrawUndo(true) + , m_bLockUndoNoModifiedPosition(false) + , m_UndoSaveMark(MARK_INVALID) +{ + OSL_ASSERT(m_pUndoNodes.get()); + // writer expects it to be disabled initially + // Undo is enabled by SwEditShell constructor + SfxUndoManager::EnableUndo(false); +} + +SwNodes const& UndoManager::GetUndoNodes() const +{ + return *m_pUndoNodes; +} + +SwNodes & UndoManager::GetUndoNodes() +{ + return *m_pUndoNodes; +} + +bool UndoManager::IsUndoNodes(SwNodes const& rNodes) const +{ + return & rNodes == m_pUndoNodes.get(); +} + +void UndoManager::DoUndo(bool const bDoUndo) +{ + EnableUndo(bDoUndo); + + SdrModel *const pSdrModel = m_rDrawModelAccess.GetDrawModel(); + if( pSdrModel ) + { + pSdrModel->EnableUndo(bDoUndo); + } +} + +bool UndoManager::DoesUndo() const +{ + return IsUndoEnabled(); +} + +void UndoManager::DoGroupUndo(bool const bDoUndo) +{ + m_bGroupUndo = bDoUndo; +} + +bool UndoManager::DoesGroupUndo() const +{ + return m_bGroupUndo; +} + +void UndoManager::DoDrawUndo(bool const bDoUndo) +{ + m_bDrawUndo = bDoUndo; +} + +bool UndoManager::DoesDrawUndo() const +{ + return m_bDrawUndo; +} + + +bool UndoManager::IsUndoNoResetModified() const +{ + return MARK_INVALID == m_UndoSaveMark; +} + +void UndoManager::SetUndoNoResetModified() +{ + if (MARK_INVALID != m_UndoSaveMark) + { + RemoveMark(m_UndoSaveMark); + m_UndoSaveMark = MARK_INVALID; + } +} + +void UndoManager::SetUndoNoModifiedPosition() +{ + if (!m_bLockUndoNoModifiedPosition) + { + m_UndoSaveMark = MarkTopUndoAction(); + } +} + +void UndoManager::LockUndoNoModifiedPosition() +{ + m_bLockUndoNoModifiedPosition = true; +} + +void UndoManager::UnLockUndoNoModifiedPosition() +{ + m_bLockUndoNoModifiedPosition = false; +} + + +SwUndo* UndoManager::GetLastUndo() +{ + if (!SfxUndoManager::GetUndoActionCount(CurrentLevel)) + { + return 0; + } + SfxUndoAction *const pAction( SfxUndoManager::GetUndoAction(0) ); + return dynamic_cast<SwUndo*>(pAction); +} + +void UndoManager::AppendUndo(SwUndo *const pUndo) +{ + AddUndoAction(pUndo); +} + +void UndoManager::ClearRedo() +{ + return SfxUndoManager::ImplClearRedo_NoLock(TopLevel); +} + +void UndoManager::DelAllUndoObj() +{ + ::sw::UndoGuard const undoGuard(*this); + + SfxUndoManager::ClearAllLevels(); + + m_UndoSaveMark = MARK_INVALID; +} + + +/**************** UNDO ******************/ + +SwUndoId +UndoManager::StartUndo(SwUndoId const i_eUndoId, + SwRewriter const*const pRewriter) +{ + if (!IsUndoEnabled()) + { + return UNDO_EMPTY; + } + + SwUndoId const eUndoId( (0 == i_eUndoId) ? UNDO_START : i_eUndoId ); + + OSL_ASSERT(UNDO_END != eUndoId); + String comment( (UNDO_START == eUndoId) + ? String("??", RTL_TEXTENCODING_ASCII_US) + : String(SW_RES(UNDO_BASE + eUndoId)) ); + if (pRewriter) + { + OSL_ASSERT(UNDO_START != eUndoId); + comment = pRewriter->Apply(comment); + } + + SfxUndoManager::EnterListAction(comment, comment, eUndoId); + + return eUndoId; +} + + +SwUndoId +UndoManager::EndUndo(SwUndoId const i_eUndoId, SwRewriter const*const pRewriter) +{ + if (!IsUndoEnabled()) + { + return UNDO_EMPTY; + } + + SwUndoId const eUndoId( ((0 == i_eUndoId) || (UNDO_START == i_eUndoId)) + ? UNDO_END : i_eUndoId ); + OSL_ENSURE(!((UNDO_END == eUndoId) && pRewriter), + "EndUndo(): no Undo ID, but rewriter given?"); + + SfxUndoAction *const pLastUndo( + (0 == SfxUndoManager::GetUndoActionCount(CurrentLevel)) + ? 0 : SfxUndoManager::GetUndoAction(0) ); + + int const nCount = LeaveListAction(); + + if (nCount) // otherwise: empty list action not inserted! + { + OSL_ASSERT(pLastUndo); + OSL_ASSERT(UNDO_START != eUndoId); + SfxUndoAction *const pUndoAction(SfxUndoManager::GetUndoAction(0)); + SfxListUndoAction *const pListAction( + dynamic_cast<SfxListUndoAction*>(pUndoAction)); + OSL_ASSERT(pListAction); + if (pListAction) + { + if (UNDO_END != eUndoId) + { + OSL_ENSURE(pListAction->GetId() == eUndoId, + "EndUndo(): given ID different from StartUndo()"); + // comment set by caller of EndUndo + String comment = String(SW_RES(UNDO_BASE + eUndoId)); + if (pRewriter) + { + comment = pRewriter->Apply(comment); + } + pListAction->SetComment(comment); + } + else if ((UNDO_START != pListAction->GetId())) + { + // comment set by caller of StartUndo: nothing to do here + } + else if (pLastUndo) + { + // comment was not set at StartUndo or EndUndo: + // take comment of last contained action + // (note that this works recursively, i.e. the last contained + // action may be a list action created by StartUndo/EndUndo) + String const comment(pLastUndo->GetComment()); + pListAction->SetComment(comment); + } + else + { + OSL_ENSURE(false, "EndUndo(): no comment?"); + } + } + } + + return eUndoId; +} + +bool +UndoManager::GetLastUndoInfo( + ::rtl::OUString *const o_pStr, SwUndoId *const o_pId) const +{ + // this is actually expected to work on the current level, + // but that was really not obvious from the previous implementation... + if (!SfxUndoManager::GetUndoActionCount(CurrentLevel)) + { + return false; + } + + SfxUndoAction *const pAction( SfxUndoManager::GetUndoAction(0) ); + if (o_pStr) + { + *o_pStr = pAction->GetComment(); + } + if (o_pId) + { + sal_uInt16 const nId(pAction->GetId()); + *o_pId = static_cast<SwUndoId>(nId); + } + + return true; +} + +SwUndoComments_t UndoManager::GetUndoComments() const +{ + OSL_ENSURE(!SfxUndoManager::IsInListAction(), + "GetUndoComments() called while in list action?"); + + SwUndoComments_t ret; + sal_uInt16 const nUndoCount(SfxUndoManager::GetUndoActionCount(TopLevel)); + for (sal_uInt16 n = 0; n < nUndoCount; ++n) + { + ::rtl::OUString const comment( + SfxUndoManager::GetUndoActionComment(n, TopLevel)); + ret.push_back(comment); + } + + return ret; +} + + +/**************** REDO ******************/ +bool UndoManager::GetFirstRedoInfo(::rtl::OUString *const o_pStr) const +{ + if (!SfxUndoManager::GetRedoActionCount(CurrentLevel)) + { + return false; + } + + if (o_pStr) + { + *o_pStr = SfxUndoManager::GetRedoActionComment(0, CurrentLevel); + } + + return true; +} + + +SwUndoComments_t UndoManager::GetRedoComments() const +{ + OSL_ENSURE(!SfxUndoManager::IsInListAction(), + "GetRedoComments() called while in list action?"); + + SwUndoComments_t ret; + sal_uInt16 const nRedoCount(SfxUndoManager::GetRedoActionCount(TopLevel)); + for (sal_uInt16 n = 0; n < nRedoCount; ++n) + { + ::rtl::OUString const comment( + SfxUndoManager::GetRedoActionComment(n, TopLevel)); + ret.push_back(comment); + } + + return ret; +} + +/**************** REPEAT ******************/ + +SwUndoId UndoManager::GetRepeatInfo(::rtl::OUString *const o_pStr) const +{ + SwUndoId nRepeatId(UNDO_EMPTY); + GetLastUndoInfo(o_pStr, & nRepeatId); + if( REPEAT_START <= nRepeatId && REPEAT_END > nRepeatId ) + { + return nRepeatId; + } + if (o_pStr) // not repeatable -> clear comment + { + *o_pStr = String(); + } + return UNDO_EMPTY; +} + +SwUndo * UndoManager::RemoveLastUndo() +{ + if (SfxUndoManager::GetRedoActionCount(CurrentLevel) || + SfxUndoManager::GetRedoActionCount(TopLevel)) + { + OSL_ENSURE(false, "RemoveLastUndoAction(): there are Redo actions?"); + return 0; + } + if (!SfxUndoManager::GetUndoActionCount(CurrentLevel)) + { + OSL_ENSURE(false, "RemoveLastUndoAction(): no Undo actions"); + return 0; + } + SfxUndoAction *const pLastUndo(GetUndoAction(0)); + SfxUndoManager::RemoveLastUndoAction(); + return dynamic_cast<SwUndo *>(pLastUndo); +} + +// svl::IUndoManager ///////////////////////////////////////////////////// + +void UndoManager::EnableUndo(bool bEnable) +{ + // UGLY: SfxUndoManager has a counter to match enable/disable calls + // but the writer code expects that a single call switches + while (IsUndoEnabled() != bEnable) + { + SfxUndoManager::EnableUndo(bEnable); + } +} + +void UndoManager::AddUndoAction(SfxUndoAction *pAction, sal_Bool bTryMerge) +{ + SwUndo *const pUndo( dynamic_cast<SwUndo *>(pAction) ); + if (pUndo) + { + if (nsRedlineMode_t::REDLINE_NONE == pUndo->GetRedlineMode()) + { + pUndo->SetRedlineMode( m_rRedlineAccess.GetRedlineMode() ); + } + } + SfxUndoManager::AddUndoAction(pAction, bTryMerge); + // if the undo nodes array is too large, delete some actions + while (UNDO_ACTION_LIMIT < GetUndoNodes().Count()) + { + RemoveOldestUndoActions(1); + } +} + +class CursorGuard +{ +public: + CursorGuard(SwEditShell & rShell, bool const bSave) + : m_rShell(rShell) + , m_bSaveCursor(bSave) + { + if (m_bSaveCursor) + { + m_rShell.Push(); // prevent modification of current cursor + } + } + ~CursorGuard() + { + if (m_bSaveCursor) + { + m_rShell.Pop(); + } + } +private: + SwEditShell & m_rShell; + bool const m_bSaveCursor; +}; + +bool UndoManager::impl_DoUndoRedo(UndoOrRedo_t const undoOrRedo) +{ + SwDoc & rDoc(*GetUndoNodes().GetDoc()); + + UnoActionContext c(& rDoc); // exception-safe StartAllAction/EndAllAction + + SwEditShell *const pEditShell( rDoc.GetEditShell() ); + + OSL_ENSURE(pEditShell, "sw::UndoManager needs a SwEditShell!"); + if (!pEditShell) + { + throw uno::RuntimeException(); + } + + // in case the model has controllers locked, the Undo should not + // change the view cursors! + bool const bSaveCursors(pEditShell->CursorsLocked()); + CursorGuard(*pEditShell, bSaveCursors); + if (!bSaveCursors) + { + // (in case Undo was called via API) clear the cursors: + pEditShell->KillPams(); + pEditShell->SetMark(); + pEditShell->ClearMark(); + } + + bool bRet(false); + + ::sw::UndoRedoContext context(rDoc, *pEditShell); + + // N.B. these may throw! + if (UNDO == undoOrRedo) + { + bRet = SfxUndoManager::UndoWithContext(context); + } + else + { + bRet = SfxUndoManager::RedoWithContext(context); + } + + if (bRet) + { + // if we are at the "last save" position, the document is not modified + if (SfxUndoManager::HasTopUndoActionMark(m_UndoSaveMark)) + { + m_rState.ResetModified(); + } + else + { + m_rState.SetModified(); + } + } + + pEditShell->HandleUndoRedoContext(context); + + return bRet; +} + +sal_Bool UndoManager::Undo() +{ + bool const bRet = impl_DoUndoRedo(UNDO); + return bRet; +} + +sal_Bool UndoManager::Redo() +{ + bool const bRet = impl_DoUndoRedo(REDO); + return bRet; +} + +/** N.B.: this does _not_ call SfxUndoManager::Repeat because it is not + possible to wrap a list action around it: + calling EnterListAction here will cause SfxUndoManager::Repeat + to repeat the list action! + */ +bool +UndoManager::Repeat(::sw::RepeatContext & rContext, + sal_uInt16 const nRepeatCount) +{ + if (SfxUndoManager::IsInListAction()) + { + OSL_ENSURE(false, "repeat in open list action???"); + return false; + } + if (!SfxUndoManager::GetUndoActionCount(TopLevel)) + { + return false; + } + SfxUndoAction *const pRepeatAction(GetUndoAction(0)); + OSL_ASSERT(pRepeatAction); + if (!pRepeatAction || !pRepeatAction->CanRepeat(rContext)) + { + return false; + } + + ::rtl::OUString const comment(pRepeatAction->GetComment()); + ::rtl::OUString const rcomment(pRepeatAction->GetRepeatComment(rContext)); + sal_uInt16 const nId(pRepeatAction->GetId()); + if (DoesUndo()) + { + EnterListAction(comment, rcomment, nId); + } + + SwPaM *const pFirstCursor(& rContext.GetRepeatPaM()); + do { // iterate over ring + for (sal_uInt16 nRptCnt = nRepeatCount; nRptCnt > 0; --nRptCnt) + { + pRepeatAction->Repeat(rContext); + } + rContext.m_bDeleteRepeated = false; // reset for next PaM + rContext.m_pCurrentPaM = + static_cast<SwPaM*>(rContext.m_pCurrentPaM->GetNext()); + } while (pFirstCursor != & rContext.GetRepeatPaM()); + + if (DoesUndo()) + { + LeaveListAction(); + } + return true; +} + +} // namespace sw + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/undo/rolbck.cxx b/sw/source/core/undo/rolbck.cxx new file mode 100644 index 000000000000..970403d5cd1f --- /dev/null +++ b/sw/source/core/undo/rolbck.cxx @@ -0,0 +1,1516 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <rolbck.hxx> + +#include <tools/resid.hxx> + +#include <svl/itemiter.hxx> + +#include <editeng/brkitem.hxx> + +#include <hints.hxx> +#include <hintids.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 <IDocumentUndoRedo.hxx> +#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 <ndgrf.hxx> // SwGrfNode +#include <UndoCore.hxx> +#include <IMark.hxx> // fuer SwBookmark +#include <charfmt.hxx> // #i27615# +#include <comcore.hrc> +#include <undo.hrc> +#include <bookmrk.hxx> + +SV_IMPL_PTRARR( SwpHstry, SwHistoryHintPtr) + +String SwHistoryHint::GetDescription() const +{ + return String(); +} + + +SwHistorySetFmt::SwHistorySetFmt( const SfxPoolItem* pFmtHt, sal_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 ; + + sal_uInt16 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() +{ +} + + +SwHistoryResetFmt::SwHistoryResetFmt(const SfxPoolItem* pFmtHt, sal_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, sal_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 + sal_uInt16 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(); + OSL_ENSURE( 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, sal_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(); + OSL_ENSURE( pTxtNd, "SwHistorySetTxtFld: no TextNode" ); + + if ( pTxtNd ) + { + pTxtNd->InsertItem( *m_pFld, m_nPos, m_nPos, + nsSetAttrMode::SETATTR_NOTXTATRCHR ); + } +} + + + +SwHistorySetRefMark::SwHistorySetRefMark( SwTxtRefMark* pTxtHt, sal_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(); + OSL_ENSURE( 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, sal_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() ) +{ + m_TOXMark.DeRegister(); +} + + +void SwHistorySetTOXMark::SetInDoc( SwDoc* pDoc, bool ) +{ + SwTxtNode * pTxtNd = pDoc->GetNodes()[ m_nNodeIndex ]->GetTxtNode(); + OSL_ENSURE( pTxtNd, "SwHistorySetTOXMark: no TextNode" ); + if ( !pTxtNd ) + return; + + // search for respective TOX type + sal_uInt16 nCnt = pDoc->GetTOXTypeCount( m_eTOXTypes ); + SwTOXType* pToxType = 0; + for ( sal_uInt16 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 ); + aNew.RegisterToTOXType( *pToxType ); + + 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( sal_uInt16 nWhich, + xub_StrLen nAttrStart, xub_StrLen nAttrEnd, sal_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(); + OSL_ENSURE( pTxtNd, "SwHistoryResetTxt: no TextNode" ); + if ( pTxtNd ) + { + pTxtNd->DeleteAttributes( m_nAttr, m_nStart, m_nEnd ); + } +} + + +SwHistorySetFootnote::SwHistorySetFootnote( SwTxtFtn* pTxtFtn, sal_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() ) +{ + OSL_ENSURE( 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, sal_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() ) +{ + OSL_ENSURE( 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(); + OSL_ENSURE( 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, sal_uLong nNd, + sal_uInt8 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(); + OSL_ENSURE( 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 ) ) +{ + OSL_ENSURE( pFlyFmt, "SwHistoryTxtFlyCnt: no Format" ); + m_pUndo->ChgShowSel( sal_False ); +} + + +SwHistoryTxtFlyCnt::~SwHistoryTxtFlyCnt() +{ +} + + +void SwHistoryTxtFlyCnt::SetInDoc( SwDoc* pDoc, bool ) +{ + ::sw::IShellCursorSupplier *const pISCS(pDoc->GetIShellCursorSupplier()); + OSL_ASSERT(pISCS); + ::sw::UndoRedoContext context(*pDoc, *pISCS); + m_pUndo->UndoImpl(context); +} + + + +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 ) +{ + ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo()); + + 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); + } + } + } + } +} + + +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, + sal_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( sal_True ); +} + +void SwHistorySetAttrSet::SetInDoc( SwDoc* pDoc, bool ) +{ + ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo()); + + 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() ); + } + } +} + +/*************************************************************************/ + + +SwHistoryResetAttrSet::SwHistoryResetAttrSet( const SfxItemSet& rSet, + sal_uLong nNodePos, xub_StrLen nAttrStt, xub_StrLen nAttrEnd ) + : SwHistoryHint( HSTRY_RESETATTRSET ) + , m_nNodeIndex( nNodePos ), m_nStart( nAttrStt ), m_nEnd( nAttrEnd ) + , m_Array( (sal_uInt8)rSet.Count() ) +{ + SfxItemIter aIter( rSet ); + bool bAutoStyle = false; + + while( sal_True ) + { + const sal_uInt16 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: + OSL_ENSURE(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 ) +{ + ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo()); + + SwCntntNode * pCntntNd = pDoc->GetNodes()[ m_nNodeIndex ]->GetCntntNode(); + OSL_ENSURE( pCntntNd, "SwHistoryResetAttrSet: no CntntNode" ); + + if (pCntntNd) + { + const sal_uInt16* pArr = m_Array.GetData(); + if ( USHRT_MAX == m_nEnd && USHRT_MAX == m_nStart ) + { + // no area: use ContentNode + for ( sal_uInt16 n = m_Array.Count(); n; --n, ++pArr ) + { + pCntntNd->ResetAttr( *pArr ); + } + } + else + { + // area: use TextNode + for ( sal_uInt16 n = m_Array.Count(); n; --n, ++pArr ) + { + static_cast<SwTxtNode*>(pCntntNd)-> + DeleteAttributes( *pArr, m_nStart, m_nEnd ); + } + } + } +} + + +/*************************************************************************/ + + +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 ) +{ + ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo()); + + sal_uInt16 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 ) + { + OSL_ENSURE(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->getLayoutFrm( pDoc->GetCurrentLayout(), 0, 0, sal_False ) ) + { + m_rFmt.DelFrms(); + } + + m_rFmt.SetFmtAttr( aTmp ); + } +} + + +/*************************************************************************/ + +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( sal_uInt16 nInitSz, sal_uInt16 nGrowSz ) + : m_SwpHstry( (sal_uInt8)nInitSz, (sal_uInt8)nGrowSz ) + , m_nEndDiff( 0 ) +{} + + +SwHistory::~SwHistory() +{ + Delete( 0 ); +} + + +/************************************************************************* +|* +|* void SwHistory::Add() +|* +|* Beschreibung Dokument 1.0 +|* +*************************************************************************/ + +void SwHistory::Add( const SfxPoolItem* pOldValue, const SfxPoolItem* pNewValue, + sal_uLong nNodeIdx ) +{ + OSL_ENSURE( !m_nEndDiff, "History was not deleted after REDO" ); + + sal_uInt16 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, sal_uLong nNodeIdx, bool bNewAttr ) +{ + OSL_ENSURE( !m_nEndDiff, "History was not deleted after REDO" ); + + SwHistoryHint * pHt; + sal_uInt16 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, sal_uLong nNodeIdx, sal_uInt8 nWhichNd ) +{ + OSL_ENSURE( !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) +{ + OSL_ENSURE( !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, sal_uInt16& rSetPos ) +{ + OSL_ENSURE( !m_nEndDiff, "History was not deleted after REDO" ); + + SwHistoryHint * pHint; + const sal_uInt16 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, sal_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()); +} + +/************************************************************************* +|* +|* sal_Bool SwHistory::Rollback() +|* +|* Beschreibung Dokument 1.0 +|* +*************************************************************************/ + + +bool SwHistory::Rollback( SwDoc* pDoc, sal_uInt16 nStart ) +{ + if ( !Count() ) + return false; + + SwHistoryHint * pHHt; + sal_uInt16 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, sal_uInt16 nStart, bool bToFirst ) +{ + sal_uInt16 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( sal_uInt16 nStart ) +{ + for ( sal_uInt16 n = Count(); n > nStart; ) + { + m_SwpHstry.DeleteAndDestroy( --n, 1 ); + } + m_nEndDiff = 0; +} + + +sal_uInt16 SwHistory::SetTmpEnd( sal_uInt16 nNewTmpEnd ) +{ + OSL_ENSURE( nNewTmpEnd <= Count(), "SwHistory::SetTmpEnd: out of bounds" ); + + sal_uInt16 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 ( sal_uInt16 n = nOld; n < nNewTmpEnd; n++ ) + { + if ( HSTRY_FLYCNT == (*this)[ n ]->Which() ) + { + static_cast<SwHistoryTxtFlyCnt*>((*this)[ n ]) + ->GetUDelLFmt()->RedoForRollback(); + } + } + + return nOld; +} + +void SwHistory::CopyFmtAttr( const SfxItemSet& rSet, sal_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( sal_True ); + } +} + +void SwHistory::CopyAttr( SwpHints* pHts, sal_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( sal_uInt16 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 !! + sal_Bool bNextAttr = sal_False; + switch( pHt->Which() ) + { + case RES_TXTATR_FIELD: + // keine Felder, .. kopieren ?? + if( !bFields ) + bNextAttr = sal_True; + break; + case RES_TXTATR_FLYCNT: + case RES_TXTATR_FTN: + bNextAttr = sal_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( const SfxPoolItem* pOld, const SfxPoolItem* pNew ) +{ + // --> OD 2010-10-05 #i114861# + // Do not handle a "noop" modify + // - e.g. <SwTxtNode::NumRuleChgd()> uses such a "noop" modify +// if ( m_pHistory && ( pOld || pNew ) ) + if ( m_pHistory && ( pOld || pNew ) && + 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<const 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())); + + OSL_ENSURE(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 ); + sal_uInt16 nW = aIter.FirstItem()->Which(); + while( sal_True ) + { + m_WhichIdSet.Insert( nW ); + if( aIter.IsAtEnd() ) + break; + nW = aIter.NextItem()->Which(); + } + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/undo/unattr.cxx b/sw/source/core/undo/unattr.cxx new file mode 100644 index 000000000000..0d585f42aa0e --- /dev/null +++ b/sw/source/core/undo/unattr.cxx @@ -0,0 +1,1259 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#define _SVSTDARR_USHORTS +#define _SVSTDARR_USHORTSSORT +#include <UndoAttribute.hxx> + +#include <svl/itemiter.hxx> + +#include <editeng/tstpitem.hxx> + +#include <svx/svdmodel.hxx> +#include <svx/svdpage.hxx> + +#include <hintids.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 <IDocumentUndoRedo.hxx> +#include <IShellCursorSupplier.hxx> +#include <docary.hxx> +#include <swundo.hxx> // fuer die UndoIds +#include <pam.hxx> +#include <ndtxt.hxx> +#include <swtable.hxx> +#include <swtblfmt.hxx> +#include <UndoCore.hxx> +#include <hints.hxx> +#include <rolbck.hxx> +#include <ndnotxt.hxx> +#include <dcontact.hxx> +#include <ftninfo.hxx> +#include <redline.hxx> +#include <section.hxx> +#include <charfmt.hxx> +#include <switerator.hxx> + + +// ----------------------------------------------------- + +SwUndoFmtAttrHelper::SwUndoFmtAttrHelper( SwFmt& rFmt, bool bSvDrwPt ) + : SwClient( &rFmt ) + , m_pUndo( 0 ) + , m_bSaveDrawPt( bSvDrwPt ) +{ +} + +void SwUndoFmtAttrHelper::Modify( const SfxPoolItem* pOld, const SfxPoolItem* pNew ) +{ + if( pOld ) + { + if ( pOld->Which() == RES_OBJECTDYING ) + { + CheckRegistration( pOld, pNew ); + } + else if ( pNew ) + { + if( POOLATTR_END >= pOld->Which() ) + { + if ( GetUndo() ) + { + m_pUndo->PutAttr( *pOld ); + } + else + { + m_pUndo.reset( new SwUndoFmtAttr( *pOld, + *static_cast<SwFmt*>(GetRegisteredInNonConst()), m_bSaveDrawPt ) ); + } + } + else if ( RES_ATTRSET_CHG == pOld->Which() ) + { + if ( GetUndo() ) + { + SfxItemIter aIter( + *(static_cast<const 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<const SwAttrSetChg*>(pOld)->GetChgSet(), + *static_cast<SwFmt*>(GetRegisteredInNonConst()), m_bSaveDrawPt ) ); + } + } + } + } +} + +// ----------------------------------------------------- + +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( sal_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, sal_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 = SwIterator<SwTable,SwFmt>::FirstElement( *m_pFmt ); + 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 = SwIterator<SwTableBox,SwFmt>::FirstElement( *m_pFmt ); + if ( pTblBox ) + { + m_nNodeIndex = pTblBox->GetSttIdx(); + } + } + } +} + +SwUndoFmtAttr::~SwUndoFmtAttr() +{ +} + +void SwUndoFmtAttr::UndoImpl(::sw::UndoRedoContext & rContext) +{ + // OD 2004-10-26 #i35443# + // Important note: <Undo(..)> also called by <ReDo(..)> + + if ( !m_pOldSet.get() || !m_pFmt || !IsFmtInDoc( &rContext.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, sal_False )) + { + bAnchorAttrRestored = RestoreFlyAnchor(rContext); + 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 ) + { + rContext.SetSelections(static_cast<SwFrmFmt*>(m_pFmt), 0); + } + } +} + +bool SwUndoFmtAttr::IsFmtInDoc( SwDoc* pDoc ) +{ + // search for the Format in the Document; if it does not exist any more, + // the attribute is not restored! + sal_uInt16 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::RedoImpl(::sw::UndoRedoContext & rContext) +{ + // --> OD 2004-10-26 #i35443# - Because the undo stores the attributes for + // redo, the same code as for <Undo(..)> can be applied for <Redo(..)> + UndoImpl(rContext); + // <-- +} + +void SwUndoFmtAttr::RepeatImpl(::sw::RepeatContext & rContext) +{ + if ( !m_pOldSet.get() ) + return; + + SwDoc & rDoc(rContext.GetDoc()); + + switch ( m_nFmtWhich ) + { + case RES_GRFFMTCOLL: + { + SwNoTxtNode *const pNd = + rContext.GetRepeatPaM().GetNode()->GetNoTxtNode(); + if( pNd ) + { + rDoc.SetAttr( m_pFmt->GetAttrSet(), *pNd->GetFmtColl() ); + } + } + break; + + case RES_TXTFMTCOLL: + { + SwTxtNode *const pNd = + rContext.GetRepeatPaM().GetNode()->GetTxtNode(); + if( pNd ) + { + rDoc.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 *const pFly = + rContext.GetRepeatPaM().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() ) + { + rDoc.SetAttr( aTmpSet, *pFly ); + } + } + else + { + rDoc.SetAttr( m_pFmt->GetAttrSet(), *pFly ); + } + } + break; + } + } +} + +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, sal_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(::sw::UndoRedoContext & rContext) +{ + SwDoc *const pDoc = & rContext.GetDoc(); + SwFlyFrmFmt* pFrmFmt = static_cast<SwFlyFrmFmt*>(m_pFmt); + const SwFmtAnchor& rAnchor = + static_cast<const SwFmtAnchor&>( m_pOldSet->Get( RES_ANCHOR, sal_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->GetCurrentViewShell() ) //swmod 071108//swmod 071225 + { + 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(); + OSL_ENSURE( pTxtNode->HasHints(), "Missing FlyInCnt-Hint." ); + const xub_StrLen nIdx = pPos->nContent.GetIndex(); + SwTxtAttr * const pHnt = + pTxtNode->GetTxtAttrForCharAt( nIdx, RES_TXTATR_FLYCNT ); + OSL_ENSURE( pHnt && pHnt->Which() == RES_TXTATR_FLYCNT, + "Missing FlyInCnt-Hint." ); + OSL_ENSURE( 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() ) + { + OSL_ENSURE( 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(); + OSL_ENSURE( pTxtNd, "no Text Node at position." ); + SwFmtFlyCnt aFmt( pFrmFmt ); + pTxtNd->InsertItem( aFmt, pPos->nContent.GetIndex(), 0 ); + } + + + if( RES_DRAWFRMFMT != pFrmFmt->Which() ) + pFrmFmt->MakeFrms(); + + rContext.SetSelections(pFrmFmt, 0); + + // --> OD 2004-10-26 #i35443# - anchor attribute restored. + return true; + // <-- +} + +// ----------------------------------------------------- +SwUndoFmtResetAttr::SwUndoFmtResetAttr( SwFmt& rChangedFormat, + const sal_uInt16 nWhichId ) + : SwUndo( UNDO_RESETATTR ) + , m_pChangedFormat( &rChangedFormat ) + , m_nWhichId( nWhichId ) + , m_pOldItem( 0 ) +{ + const SfxPoolItem* pItem = 0; + if (rChangedFormat.GetItemState( nWhichId, sal_False, &pItem ) == SFX_ITEM_SET) + { + m_pOldItem.reset( pItem->Clone() ); + } +} + +SwUndoFmtResetAttr::~SwUndoFmtResetAttr() +{ +} + +void SwUndoFmtResetAttr::UndoImpl(::sw::UndoRedoContext &) +{ + if ( m_pOldItem.get() ) + { + m_pChangedFormat->SetFmtAttr( *m_pOldItem ); + } +} + +void SwUndoFmtResetAttr::RedoImpl(::sw::UndoRedoContext &) +{ + if ( m_pOldItem.get() ) + { + m_pChangedFormat->ResetFmtAttr( m_nWhichId ); + } +} +// <-- + +// ----------------------------------------------------- + +SwUndoResetAttr::SwUndoResetAttr( const SwPaM& rRange, sal_uInt16 nFmtId ) + : SwUndo( UNDO_RESETATTR ), SwUndRng( rRange ) + , m_pHistory( new SwHistory ) + , m_nFormatId( nFmtId ) +{ +} + +SwUndoResetAttr::SwUndoResetAttr( const SwPosition& rPos, sal_uInt16 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::UndoImpl(::sw::UndoRedoContext & rContext) +{ + // reset old values + SwDoc & rDoc = rContext.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, sal_False ); + } + } + + AddUndoRedoPaM(rContext); +} + +void SwUndoResetAttr::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + SwPaM & rPam = AddUndoRedoPaM(rContext); + SvUShortsSort* pIdArr = m_Ids.Count() ? &m_Ids : 0; + + switch ( m_nFormatId ) + { + case RES_CHRFMT: + rDoc.RstTxtAttrs(rPam); + break; + case RES_TXTFMTCOLL: + rDoc.ResetAttrs(rPam, sal_False, pIdArr ); + break; + case RES_CONDTXTFMTCOLL: + rDoc.ResetAttrs(rPam, sal_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 )); + + sal_uInt16 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; + } +} + +void SwUndoResetAttr::RepeatImpl(::sw::RepeatContext & rContext) +{ + if (m_nFormatId < RES_FMT_BEGIN) + { + return; + } + + SvUShortsSort* pIdArr = m_Ids.Count() ? &m_Ids : 0; + switch ( m_nFormatId ) + { + case RES_CHRFMT: + rContext.GetDoc().RstTxtAttrs(rContext.GetRepeatPaM()); + break; + case RES_TXTFMTCOLL: + rContext.GetDoc().ResetAttrs(rContext.GetRepeatPaM(), false, pIdArr); + break; + case RES_CONDTXTFMTCOLL: + rContext.GetDoc().ResetAttrs(rContext.GetRepeatPaM(), true, pIdArr); + break; + } +} + + +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, sal_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::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc *const pDoc = & rContext.GetDoc(); + + RemoveIdx( *pDoc ); + + if( IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() ) ) + { + SwPaM aPam(pDoc->GetNodes().GetEndOfContent()); + if ( ULONG_MAX != m_nNodeIndex ) + { + aPam.DeleteMark(); + aPam.GetPoint()->nNode = m_nNodeIndex; + aPam.GetPoint()->nContent.Assign( aPam.GetCntntNode(), nSttCntnt ); + aPam.SetMark(); + aPam.GetPoint()->nContent++; + pDoc->DeleteRedline(aPam, false, USHRT_MAX); + } + else + { + // alle Format-Redlines entfernen, werden ggfs. neu gesetzt + SetPaM(aPam); + pDoc->DeleteRedline(aPam, 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 + AddUndoRedoPaM(rContext); +} + +void SwUndoAttr::RepeatImpl(::sw::RepeatContext & rContext) +{ + // RefMarks are not repeat capable + if ( SFX_ITEM_SET != m_AttrSet.GetItemState( RES_TXTATR_REFMARK, sal_False ) ) + { + rContext.GetDoc().InsertItemSet( rContext.GetRepeatPaM(), + m_AttrSet, m_nInsertFlags ); + } + else if ( 1 < m_AttrSet.Count() ) + { + SfxItemSet aTmpSet( m_AttrSet ); + aTmpSet.ClearItem( RES_TXTATR_REFMARK ); + rContext.GetDoc().InsertItemSet( rContext.GetRepeatPaM(), + aTmpSet, m_nInsertFlags ); + } +} + +void SwUndoAttr::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + SwPaM & rPam = AddUndoRedoPaM(rContext); + + 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 ); + } +} + + +void SwUndoAttr::RemoveIdx( SwDoc& rDoc ) +{ + if ( SFX_ITEM_SET != m_AttrSet.GetItemState( RES_TXTATR_FTN, sal_False )) + return ; + + SwHistoryHint* pHstHnt; + SwNodes& rNds = rDoc.GetNodes(); + for ( sal_uInt16 n = 0; n < m_pHistory->Count(); ++n ) + { + xub_StrLen nCntnt = 0; + sal_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 ( sal_uInt16 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, sal_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::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.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::RedoImpl(::sw::UndoRedoContext & rContext) +{ + UndoImpl(rContext); +} + +// ----------------------------------------------------- + +SwUndoMoveLeftMargin::SwUndoMoveLeftMargin( + const SwPaM& rPam, sal_Bool bFlag, sal_Bool bMod ) + : SwUndo( bFlag ? UNDO_INC_LEFTMARGIN : UNDO_DEC_LEFTMARGIN ) + , SwUndRng( rPam ) + , m_pHistory( new SwHistory ) + , m_bModulus( bMod ) +{ +} + +SwUndoMoveLeftMargin::~SwUndoMoveLeftMargin() +{ +} + +void SwUndoMoveLeftMargin::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + + // restore old values + m_pHistory->TmpRollback( & rDoc, 0 ); + m_pHistory->SetTmpEnd( m_pHistory->Count() ); + + AddUndoRedoPaM(rContext); +} + +void SwUndoMoveLeftMargin::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + SwPaM & rPam = AddUndoRedoPaM(rContext); + + rDoc.MoveLeftMargin( rPam, + GetId() == UNDO_INC_LEFTMARGIN, m_bModulus ); +} + +void SwUndoMoveLeftMargin::RepeatImpl(::sw::RepeatContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + rDoc.MoveLeftMargin(rContext.GetRepeatPaM(), GetId() == UNDO_INC_LEFTMARGIN, + m_bModulus ); +} + +// ----------------------------------------------------- + +SwUndoChangeFootNote::SwUndoChangeFootNote( + const SwPaM& rRange, const String& rTxt, + sal_uInt16 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::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + + m_pHistory->TmpRollback( &rDoc, 0 ); + m_pHistory->SetTmpEnd( m_pHistory->Count() ); + + rDoc.GetFtnIdxs().UpdateAllFtn(); + + AddUndoRedoPaM(rContext); +} + +void SwUndoChangeFootNote::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc( rContext.GetDoc() ); + SwPaM & rPaM = AddUndoRedoPaM(rContext); + rDoc.SetCurFtn(rPaM, m_Text, m_nNumber, m_bEndNote); + SetPaM(rPaM); +} + +void SwUndoChangeFootNote::RepeatImpl(::sw::RepeatContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + rDoc.SetCurFtn( rContext.GetRepeatPaM(), m_Text, m_nNumber, m_bEndNote ); +} + + +// ----------------------------------------------------- + + +SwUndoFootNoteInfo::SwUndoFootNoteInfo( const SwFtnInfo &rInfo ) + : SwUndo( UNDO_FTNINFO ) + , m_pFootNoteInfo( new SwFtnInfo( rInfo ) ) +{ +} + +SwUndoFootNoteInfo::~SwUndoFootNoteInfo() +{ +} + +void SwUndoFootNoteInfo::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + SwFtnInfo *pInf = new SwFtnInfo( rDoc.GetFtnInfo() ); + rDoc.SetFtnInfo( *m_pFootNoteInfo ); + m_pFootNoteInfo.reset( pInf ); +} + +void SwUndoFootNoteInfo::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.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::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + SwEndNoteInfo *pInf = new SwEndNoteInfo( rDoc.GetEndNoteInfo() ); + rDoc.SetEndNoteInfo( *m_pEndNoteInfo ); + m_pEndNoteInfo.reset( pInf ); +} + +void SwUndoEndNoteInfo::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.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::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor()); + SwDoc *const pDoc = & rContext.GetDoc(); + + SwPosition& rPos = *pPam->GetPoint(); + rPos.nNode = m_nNodeIndex; + rPos.nContent.Assign( rPos.nNode.GetNode().GetCntntNode(), m_nContentIndex); + pDoc->DontExpandFmt( rPos, sal_False ); +} + + +void SwUndoDontExpandFmt::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor()); + SwDoc *const pDoc = & rContext.GetDoc(); + + SwPosition& rPos = *pPam->GetPoint(); + rPos.nNode = m_nNodeIndex; + rPos.nContent.Assign( rPos.nNode.GetNode().GetCntntNode(), m_nContentIndex); + pDoc->DontExpandFmt( rPos ); +} + +void SwUndoDontExpandFmt::RepeatImpl(::sw::RepeatContext & rContext) +{ + SwPaM & rPam = rContext.GetRepeatPaM(); + SwDoc & rDoc = rContext.GetDoc(); + rDoc.DontExpandFmt( *rPam.GetPoint() ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/undo/unbkmk.cxx b/sw/source/core/undo/unbkmk.cxx new file mode 100644 index 000000000000..26dfc0b1c256 --- /dev/null +++ b/sw/source/core/undo/unbkmk.cxx @@ -0,0 +1,107 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <UndoBookmark.hxx> + +#include "doc.hxx" +#include "docary.hxx" +#include "swundo.hxx" // fuer die UndoIds +#include "pam.hxx" + +#include <UndoCore.hxx> +#include "IMark.hxx" +#include "rolbck.hxx" + +#include "SwRewriter.hxx" + + +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::UndoImpl(::sw::UndoRedoContext & rContext) +{ + ResetInDoc( &rContext.GetDoc() ); +} + +void SwUndoInsBookmark::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SetInDoc( &rContext.GetDoc() ); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
\ No newline at end of file diff --git a/sw/source/core/undo/undel.cxx b/sw/source/core/undo/undel.cxx new file mode 100644 index 000000000000..6c296013e966 --- /dev/null +++ b/sw/source/core/undo/undel.cxx @@ -0,0 +1,991 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <UndoDelete.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 <UndoManager.hxx> +#include <swtable.hxx> +#include <swundo.hxx> // fuer die UndoIds +#include <pam.hxx> +#include <ndtxt.hxx> +#include <UndoCore.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> + + +// 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, sal_uLong nMovedIndex ) +{ + if( rSpzArr.Count() ) + { + SwFlyFrmFmt* pFmt; + const SwFmtAnchor* pAnchor; + for( sal_uInt16 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, sal_Bool bFullPara, sal_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( sal_False ), bBackSp( sal_False ), bJoinNext( sal_False ), bTblDelLastNd( sal_False ), + bDelFullPara( bFullPara ), bResetPgDesc( sal_False ), bResetPgBrk( sal_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 ) + { + OSL_ENSURE( rPam.HasMark(), "PaM ohne Mark" ); + DelCntntIndex( *rPam.GetMark(), *rPam.GetPoint(), + DelCntntType(nsDelCntntType::DELCNT_ALL | nsDelCntntType::DELCNT_CHKNOCNTNT) ); + + ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo()); + _DelBookmarks(pStt->nNode, pEnd->nNode); + } + 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(); + } + + sal_Bool bMoveNds = *pStt == *pEnd // noch ein Bereich vorhanden ?? + ? sal_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, sal_False ) ) + pEndTxtNd->ResetAttr( RES_BREAK ); + if( pEndTxtNd->HasSwAttrSet() && + SFX_ITEM_SET == pEndTxtNd->GetpSwAttrSet()->GetItemState( + RES_PAGEDESC, sal_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 = pDoc->GetUndoManager().GetUndoNodes(); + 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 ); + ::sw::UndoGuard const ug(pDoc->GetIDocumentUndoRedo()); + pDoc->SplitNode( aSplitPos, false ); + rDocNds._MoveNodes( aMvRg, rDocNds, aRg.aEnd, sal_True ); + 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 ); + ::sw::UndoGuard const ug(pDoc->GetIDocumentUndoRedo()); + pDoc->SplitNode( aSplitPos, false ); + rDocNds._MoveNodes( aMvRg, rDocNds, aRg.aStart, sal_True ); + 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, sal_True ); + } + else + { + SwNodeRange aMvRg( *pSttTxtNd, 0, *pSttTxtNd, 1 ); + rDocNds._MoveNodes( aMvRg, rDocNds, aRg.aEnd, sal_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 ); +} + +sal_Bool SwUndoDelete::SaveCntnt( const SwPosition* pStt, const SwPosition* pEnd, + SwTxtNode* pSttTxtNd, SwTxtNode* pEndTxtNd ) +{ + sal_uLong nNdIdx = pStt->nNode.GetIndex(); + // 1 - kopiere den Anfang in den Start-String + if( pSttTxtNd ) + { + sal_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 sal_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 sal_False; // keine Nodes mehr verschieben + + return sal_True; // verschiebe die dazwischen liegenden Nodes +} + + +sal_Bool SwUndoDelete::CanGrouping( SwDoc* pDoc, const SwPaM& rDelPam ) +{ + // ist das Undo groesser als 1 Node ? (sprich: Start und EndString) + if( pSttStr ? !pSttStr->Len() || pEndStr : sal_True ) + return sal_False; + + // es kann nur das Loeschen von einzelnen char's zusammengefasst werden + if( nSttNode != nEndNode || ( !bGroup && nSttCntnt+1 != nEndCntnt )) + return sal_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 sal_False; + + // untercheide zwischen BackSpace und Delete. Es muss dann das + // Undo-Array unterschiedlich aufgebaut werden !! + if( pEnd->nContent == nSttCntnt ) + { + if( bGroup && !bBackSp ) return sal_False; + bBackSp = sal_True; + } + else if( pStt->nContent == nSttCntnt ) + { + if( bGroup && bBackSp ) return sal_False; + bBackSp = sal_False; + } + else + return sal_False; + + // sind die beiden Nodes (Nodes-/Undo-Array) ueberhaupt TextNodes? + SwTxtNode * pDelTxtNd = pStt->nNode.GetNode().GetTxtNode(); + if( !pDelTxtNd ) return sal_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 sal_False; + + { + SwRedlineSaveDatas* pTmpSav = new SwRedlineSaveDatas; + if( !FillSaveData( rDelPam, *pTmpSav, sal_False )) + delete pTmpSav, pTmpSav = 0; + + sal_Bool bOk = ( !pRedlSaveData && !pTmpSav ) || + ( pRedlSaveData && pTmpSav && + SwUndo::CanRedlineGroup( *pRedlSaveData, *pTmpSav, bBackSp )); + delete pTmpSav; + if( !bOk ) + return sal_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 = sal_True; + return sal_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 ( sal_uInt16 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, sal_uLong nOldIdx ) +{ + if( rSpzArr.Count() ) + { + SwFlyFrmFmt* pFmt; + const SwFmtAnchor* pAnchor; + const SwPosition* pAPos; + for( sal_uInt16 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::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc *const pDoc = & rContext.GetDoc(); + + sal_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 !! + + sal_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 ) + { + sal_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() ) + { + sal_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 ) + { + sal_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, sal_True ); + aPos.nNode++; + } + + if( bNodeMove ) + { + SwNodeRange aRange( *pMvStt, 0, *pMvStt, nNode ); + SwNodeIndex aCopyIndex( aPos.nNode, -1 ); + pDoc->GetUndoManager().GetUndoNodes()._Copy( aRange, aPos.nNode ); + + if( nReplaceDummy ) + { + sal_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, sal_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 ) + { + sal_uInt16 nStt = static_cast<sal_uInt16>( bResetPgDesc ? RES_PAGEDESC : RES_BREAK ); + sal_uInt16 nEnd = static_cast<sal_uInt16>( 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 ); + + AddUndoRedoPaM(rContext, true); +} + +void SwUndoDelete::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwPaM & rPam = AddUndoRedoPaM(rContext); + SwDoc& rDoc = *rPam.GetDoc(); + + if( pRedlSaveData ) + { + bool bSuccess = FillSaveData(rPam, *pRedlSaveData, sal_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, sal_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 ) + { + OSL_ENSURE( 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 ) + { + OSL_ENSURE( 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, + sal_False, &pItem ) ) + pNextNd->SetAttr( *pItem ); + + if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_BREAK, + sal_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::RepeatImpl(::sw::RepeatContext & rContext) +{ + // this action does not seem idempotent, + // so make sure it is only executed once on repeat + if (rContext.m_bDeleteRepeated) + return; + + SwPaM & rPam = rContext.GetRepeatPaM(); + SwDoc& rDoc = *rPam.GetDoc(); + ::sw::GroupUndoGuard const undoGuard(rDoc.GetIDocumentUndoRedo()); + if( !rPam.HasMark() ) + { + rPam.SetMark(); + rPam.Move( fnMoveForward, fnGoCntnt ); + } + if( bDelFullPara ) + rDoc.DelFullPara( rPam ); + else + rDoc.DeleteAndJoin( rPam ); + rContext.m_bDeleteRepeated = true; +} + + +void SwUndoDelete::SetTableName(const String & rName) +{ + sTableName = rName; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 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..c394da3e8e87 --- /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..4d17b8fa51a1 --- /dev/null +++ b/sw/source/core/undo/undobj.cxx @@ -0,0 +1,1347 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <IShellCursorSupplier.hxx> +#include <txtftn.hxx> +#include <fmtanchr.hxx> +#include <ftnidx.hxx> +#include <frmfmt.hxx> +#include <doc.hxx> +#include <UndoManager.hxx> +#include <docary.hxx> +#include <swundo.hxx> // fuer die UndoIds +#include <pam.hxx> +#include <ndtxt.hxx> +#include <UndoCore.hxx> +#include <rolbck.hxx> +#include <ndnotxt.hxx> +#include <IMark.hxx> +#include <mvsave.hxx> +#include <redline.hxx> +#include <crossrefbookmark.hxx> +#include <undo.hrc> +#include <comcore.hrc> +#include <docsh.hxx> + +class SwRedlineSaveData : public SwUndRng, public SwRedlineData, + private SwUndoSaveSection +{ +public: + SwRedlineSaveData( SwComparePosition eCmpPos, + const SwPosition& rSttPos, const SwPosition& rEndPos, + SwRedline& rRedl, sal_Bool bCopyNext ); + ~SwRedlineSaveData(); + void RedlineToDoc( SwPaM& rPam ); + SwNodeIndex* GetMvSttIdx() const + { return SwUndoSaveSection::GetMvSttIdx(); } + +#if OSL_DEBUG_LEVEL > 1 + sal_uInt16 nRedlineCount; +#endif +}; + +SV_IMPL_PTRARR( SwRedlineSaveDatas, SwRedlineSaveDataPtr ) + + +//------------------------------------------------------------ + +// Diese Klasse speichert den Pam als sal_uInt16'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, sal_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 ); +} + +SwPaM & SwUndRng::AddUndoRedoPaM( + ::sw::UndoRedoContext & rContext, bool bCorrToCntnt) const +{ + SwPaM & rPaM( rContext.GetCursorSupplier().CreateNewShellCursor() ); + SetPaM( rPaM, bCorrToCntnt ); + return rPaM; +} + + +//------------------------------------------------------------ + + +void SwUndo::RemoveIdxFromSection( SwDoc& rDoc, sal_uLong nSttIdx, + sal_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, sal_True ); +} + +void SwUndo::RemoveIdxFromRange( SwPaM& rPam, sal_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(), sal_True ); + } + else + rPam.GetDoc()->CorrAbs( rPam, *pEnd, sal_True ); +} + +void SwUndo::RemoveIdxRel( sal_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 const nId) + : m_nId(nId), 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; +} + + +class UndoRedoRedlineGuard +{ +public: + UndoRedoRedlineGuard(::sw::UndoRedoContext & rContext, SwUndo & rUndo) + : m_rRedlineAccess(rContext.GetDoc()) + , m_eMode(m_rRedlineAccess.GetRedlineMode()) + { + RedlineMode_t const eTmpMode = + static_cast<RedlineMode_t>(rUndo.GetRedlineMode()); + if ((nsRedlineMode_t::REDLINE_SHOW_MASK & eTmpMode) != + (nsRedlineMode_t::REDLINE_SHOW_MASK & m_eMode)) + { + m_rRedlineAccess.SetRedlineMode( eTmpMode ); + } + m_rRedlineAccess.SetRedlineMode_intern( static_cast<RedlineMode_t>( + eTmpMode | nsRedlineMode_t::REDLINE_IGNORE) ); + } + ~UndoRedoRedlineGuard() + { + m_rRedlineAccess.SetRedlineMode(m_eMode); + } +private: + IDocumentRedlineAccess & m_rRedlineAccess; + RedlineMode_t const m_eMode; +}; + +void SwUndo::Undo() +{ + OSL_ENSURE(false, "SwUndo::Undo(): ERROR: must call Undo(context) instead"); +} + +void SwUndo::Redo() +{ + OSL_ENSURE(false, "SwUndo::Redo(): ERROR: must call Redo(context) instead"); +} + +void SwUndo::UndoWithContext(SfxUndoContext & rContext) +{ + ::sw::UndoRedoContext *const pContext( + dynamic_cast< ::sw::UndoRedoContext * >(& rContext)); + OSL_ASSERT(pContext); + if (!pContext) { return; } + UndoRedoRedlineGuard(*pContext, *this); + UndoImpl(*pContext); +} + +void SwUndo::RedoWithContext(SfxUndoContext & rContext) +{ + ::sw::UndoRedoContext *const pContext( + dynamic_cast< ::sw::UndoRedoContext * >(& rContext)); + OSL_ASSERT(pContext); + if (!pContext) { return; } + UndoRedoRedlineGuard(*pContext, *this); + RedoImpl(*pContext); +} + +void SwUndo::Repeat(SfxRepeatTarget & rContext) +{ + ::sw::RepeatContext *const pRepeatContext( + dynamic_cast< ::sw::RepeatContext * >(& rContext)); + OSL_ASSERT(pRepeatContext); + if (!pRepeatContext) { return; } + RepeatImpl(*pRepeatContext); +} + +sal_Bool SwUndo::CanRepeat(SfxRepeatTarget & rContext) const +{ + ::sw::RepeatContext *const pRepeatContext( + dynamic_cast< ::sw::RepeatContext * >(& rContext)); + OSL_ASSERT(pRepeatContext); + if (!pRepeatContext) { return false; } + return CanRepeatImpl(*pRepeatContext); +} + +void SwUndo::RepeatImpl( ::sw::RepeatContext & ) +{ +} + +bool SwUndo::CanRepeatImpl( ::sw::RepeatContext & ) const +{ +// return false; + return ((REPEAT_START <= GetId()) && (GetId() < REPEAT_END)); +} + +String SwUndo::GetComment() const +{ + String aResult; + + if (bCacheComment) + { + if (! pComment) + { + pComment = new String(SW_RES(UNDO_BASE + GetId())); + + SwRewriter aRewriter = GetRewriter(); + + *pComment = aRewriter.Apply(*pComment); + } + + aResult = *pComment; + } + else + { + aResult = String(SW_RES(UNDO_BASE + GetId())); + + SwRewriter aRewriter = GetRewriter(); + + aResult = aRewriter.Apply(aResult); + } + + return aResult; +} + +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, sal_uLong* pEndNdIdx, xub_StrLen* pEndCntIdx ) +{ + SwDoc& rDoc = *rPaM.GetDoc(); + ::sw::UndoGuard const undoGuard(rDoc.GetIDocumentUndoRedo()); + + SwNoTxtNode* pCpyNd = rPaM.GetNode()->GetNoTxtNode(); + + // jetzt kommt das eigentliche Loeschen(Verschieben) + SwNodes & rNds = rDoc.GetUndoManager().GetUndoNodes(); + 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 sal_uInt16 merken; die Indizies verschieben sich !! + sal_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, sal_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 ); + } +} + +void SwUndoSaveCntnt::MoveFromUndoNds( SwDoc& rDoc, sal_uLong nNodeIdx, + xub_StrLen nCntIdx, SwPosition& rInsPos, + sal_uLong* pEndNdIdx, xub_StrLen* pEndCntIdx ) +{ + // jetzt kommt das wiederherstellen + SwNodes & rNds = rDoc.GetUndoManager().GetUndoNodes(); + if( nNodeIdx == rNds.GetEndOfPostIts().GetIndex() ) + return; // nichts gespeichert + + ::sw::UndoGuard const undoGuard(rDoc.GetIDocumentUndoRedo()); + + 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 { + OSL_FAIL( "was ist es denn nun?" ); + } +} + +// 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. + +sal_Bool SwUndoSaveCntnt::MovePtBackward( SwPaM& rPam ) +{ + rPam.SetMark(); + if( rPam.Move( fnMoveBackward )) + return sal_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 sal_False; +} + +void SwUndoSaveCntnt::MovePtForward( SwPaM& rPam, sal_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(); + + ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo()); + + // 1. Fussnoten + if( nsDelCntntType::DELCNT_FTN & nDelCntntType ) + { + SwFtnIdxs& rFtnArr = pDoc->GetFtnIdxs(); + if( rFtnArr.Count() ) + { + const SwNode* pFtnNd; + sal_uInt16 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 ); + OSL_ENSURE( 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 ); + OSL_ENSURE( pFtnHnt, "kein FtnAttribut" ); + SwIndex aIdx( pTxtNd, nFtnSttIdx ); + pHistory->Add( pFtnHnt, pTxtNd->GetIndex(), false ); + pTxtNd->EraseText( aIdx, 1 ); + } + } + } + + // 2. Flys + if( nsDelCntntType::DELCNT_FLY & nDelCntntType ) + { + sal_uInt16 nChainInsPos = pHistory ? pHistory->Count() : 0; + const SwSpzFrmFmts& rSpzArr = *pDoc->GetSpzFrmFmts(); + if( rSpzArr.Count() ) + { + const sal_Bool bDelFwrd = rMark.nNode.GetIndex() <= rPoint.nNode.GetIndex(); + SwFlyFrmFmt* pFmt; + const SwFmtAnchor* pAnchor; + sal_uInt16 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 *const pTxtNd = + pAPos->nNode.GetNode().GetTxtNode(); + SwTxtAttr* const pFlyHnt = pTxtNd->GetTxtAttrForCharAt( + pAPos->nContent.GetIndex()); + OSL_ENSURE( 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( sal_uInt16 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--; + } + } + } + } + } +} + + +// 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, sal_True, sal_True )) + delete pRedlSaveData, pRedlSaveData = 0; + + nStartPos = rRange.aStart.GetIndex(); + + aPam.GetPoint()->nNode--; + aPam.GetMark()->nNode++; + + SwCntntNode* pCNd = aPam.GetCntntNode( sal_False ); + if( pCNd ) + aPam.GetMark()->nContent.Assign( pCNd, 0 ); + if( 0 != ( pCNd = aPam.GetCntntNode( sal_True )) ) + aPam.GetPoint()->nContent.Assign( pCNd, pCNd->Len() ); + + // Positionen als SwIndex merken, damit im DTOR dieser Bereich + // entfernt werden kann !! + sal_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, + sal_uInt16 nSectType ) +{ + if( ULONG_MAX != nStartPos ) // gab es ueberhaupt Inhalt ? + { + // ueberpruefe, ob der Inhalt an der alten Position steht + SwNodeIndex aSttIdx( pDoc->GetNodes(), nStartPos ); +// OSL_ENSURE( !pDoc->GetNodes()[ aSttIdx ]->GetCntntNode(), +// "RestoreSection(): Position on content node"); + + // 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 ); + sal_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; + } + } +} + + // sicher und setze die RedlineDaten + +SwRedlineSaveData::SwRedlineSaveData( SwComparePosition eCmpPos, + const SwPosition& rSttPos, + const SwPosition& rEndPos, + SwRedline& rRedl, + sal_Bool bCopyNext ) + : SwUndRng( rRedl ), + SwRedlineData( rRedl.GetRedlineData(), bCopyNext ) +{ + OSL_ENSURE( 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: + OSL_ENSURE( !this, "keine gueltigen Daten!" ); + } + +#if OSL_DEBUG_LEVEL > 1 + 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()) ) + 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 ); +} + +sal_Bool SwUndo::FillSaveData( const SwPaM& rRange, SwRedlineSaveDatas& rSData, + sal_Bool bDelRange, sal_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(); + sal_uInt16 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(); +} + +sal_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(); + sal_uInt16 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, sal_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( sal_uInt16 n = rSData.Count(); n; ) + rSData[ --n ]->RedlineToDoc( aPam ); + +#if OSL_DEBUG_LEVEL > 1 + // check redline count against count saved in RedlineSaveData object + OSL_ENSURE( (rSData.Count() == 0) || + (rSData[0]->nRedlineCount == rDoc.GetRedlineTbl().Count()), + "redline count not restored properly" ); +#endif + + rDoc.SetRedlineMode_intern( eOld ); +} + +sal_Bool SwUndo::HasHiddenRedlines( const SwRedlineSaveDatas& rSData ) +{ + for( sal_uInt16 n = rSData.Count(); n; ) + if( rSData[ --n ]->GetMvSttIdx() ) + return sal_True; + return sal_False; +} + +sal_Bool SwUndo::CanRedlineGroup( SwRedlineSaveDatas& rCurr, + const SwRedlineSaveDatas& rCheck, sal_Bool bCurrIsEnd ) +{ + sal_Bool bRet = sal_False; + sal_uInt16 n; + + if( rCurr.Count() == rCheck.Count() ) + { + bRet = sal_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 = sal_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) +{ + OSL_ENSURE( 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() + ); +} + +const String UNDO_ARG1("$1", RTL_TEXTENCODING_ASCII_US); +const String UNDO_ARG2("$2", RTL_TEXTENCODING_ASCII_US); +const String UNDO_ARG3("$3", RTL_TEXTENCODING_ASCII_US); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/undo/undobj1.cxx b/sw/source/core/undo/undobj1.cxx new file mode 100644 index 000000000000..49471cf4501f --- /dev/null +++ b/sw/source/core/undo/undobj1.cxx @@ -0,0 +1,729 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <svl/itemiter.hxx> + +#include <hintids.hxx> +#include <hints.hxx> +#include <fmtflcnt.hxx> +#include <fmtanchr.hxx> +#include <fmtcntnt.hxx> +#include <txtflcnt.hxx> +#include <frmfmt.hxx> +#include <flyfrm.hxx> +#include <UndoCore.hxx> +#include <UndoDraw.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> + + +//--------------------------------------------------------------------- +// SwUndoLayBase ///////////////////////////////////////////////////////// + +SwUndoFlyBase::SwUndoFlyBase( SwFrmFmt* pFormat, SwUndoId nUndoId ) + : SwUndo( nUndoId ), pFrmFmt( pFormat ) +{ +} + +SwUndoFlyBase::~SwUndoFlyBase() +{ + if( bDelFmt ) // loeschen waehrend eines Undo's ?? + delete pFrmFmt; +} + +void SwUndoFlyBase::InsFly(::sw::UndoRedoContext & rContext, bool bShowSelFrm) +{ + SwDoc *const pDoc = & rContext.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( (sal_uInt16)nNdPgPos ); + } + else + { + SwPosition aNewPos(pDoc->GetNodes().GetEndOfContent()); + 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(); + OSL_ENSURE( pCNd->IsTxtNode(), "no Text Node at position." ); + SwFmtFlyCnt aFmt( pFrmFmt ); + static_cast<SwTxtNode*>(pCNd)->InsertItem( aFmt, nCntPos, nCntPos ); + } + + pFrmFmt->MakeFrms(); + + if( bShowSelFrm ) + { + rContext.SetSelections(pFrmFmt, 0); + } + + 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 = sal_False; +} + +void SwUndoFlyBase::DelFly( SwDoc* pDoc ) +{ + bDelFmt = sal_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->ModifyNotification( &aMsgHint, &aMsgHint ); + } + + if ( RES_DRAWFRMFMT != pFrmFmt->Which() ) + { + // gibt es ueberhaupt Inhalt, dann sicher diesen + const SwFmtCntnt& rCntnt = pFrmFmt->GetCntnt(); + OSL_ENSURE( 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<sal_uInt16>(rAnchor.GetAnchorId()); + if (FLY_AS_CHAR == nRndId) + { + nNdPgPos = pPos->nNode.GetIndex(); + nCntPos = pPos->nContent.GetIndex(); + SwTxtNode *const pTxtNd = pPos->nNode.GetNode().GetTxtNode(); + OSL_ENSURE( 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 )); +} + +// SwUndoInsLayFmt /////////////////////////////////////////////////////// + +SwUndoInsLayFmt::SwUndoInsLayFmt( SwFrmFmt* pFormat, sal_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<sal_uInt16>(rAnchor.GetAnchorId()); + bDelFmt = sal_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: + OSL_FAIL( "Was denn fuer ein FlyFrame?" ); + } +} + +SwUndoInsLayFmt::~SwUndoInsLayFmt() +{ +} + +void SwUndoInsLayFmt::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc(rContext.GetDoc()); + const SwFmtCntnt& rCntnt = pFrmFmt->GetCntnt(); + if( rCntnt.GetCntntIdx() ) // kein Inhalt + { + bool bRemoveIdx = true; + if( mnCrsrSaveIndexPara > 0 ) + { + SwTxtNode *const pNode = + rDoc.GetNodes()[mnCrsrSaveIndexPara]->GetTxtNode(); + if( pNode ) + { + SwNodeIndex aIdx( rDoc.GetNodes(), + rCntnt.GetCntntIdx()->GetIndex() ); + SwNodeIndex aEndIdx( rDoc.GetNodes(), + aIdx.GetNode().EndOfSectionIndex() ); + SwIndex aIndex( pNode, mnCrsrSaveIndexPos ); + SwPosition aPos( *pNode, aIndex ); + rDoc.CorrAbs( aIdx, aEndIdx, aPos, sal_True ); + bRemoveIdx = false; + } + } + if( bRemoveIdx ) + { + RemoveIdxFromSection( rDoc, rCntnt.GetCntntIdx()->GetIndex() ); + } + } + DelFly(& rDoc); +} + +void SwUndoInsLayFmt::RedoImpl(::sw::UndoRedoContext & rContext) +{ + InsFly(rContext); +} + +void SwUndoInsLayFmt::RepeatImpl(::sw::RepeatContext & rContext) +{ + SwDoc *const pDoc = & rContext.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( *rContext.GetRepeatPaM().GetPoint() ); + if (FLY_AT_PARA == aAnchor.GetAnchorId()) + { + aPos.nContent.Assign( 0, 0 ); + } + aAnchor.SetAnchor( &aPos ); + } + else if( FLY_AT_FLY == aAnchor.GetAnchorId() ) + { + SwStartNode const*const pSttNd = + rContext.GetRepeatPaM().GetNode()->FindFlyStartNode(); + if( pSttNd ) + { + SwPosition aPos( *pSttNd ); + aAnchor.SetAnchor( &aPos ); + } + else + { + return ; + } + } + else if (FLY_AT_PAGE == aAnchor.GetAnchorId()) + { + aAnchor.SetPageNum( pDoc->GetCurrentLayout()->GetCurrPage( &rContext.GetRepeatPaM() )); + } + else { + OSL_FAIL( "was fuer ein Anker ist es denn nun?" ); + } + + SwFrmFmt* pFlyFmt = pDoc->CopyLayoutFmt( *pFrmFmt, aAnchor, true, true ); + (void) pFlyFmt; +//FIXME nobody ever did anything with this selection: +// rContext.SetSelections(pFlyFmt, 0); +} + +// #111827# +String SwUndoInsLayFmt::GetComment() const +{ + String aResult; + + // HACK: disable caching: + // the SfxUndoManager calls GetComment() too early: the pFrmFmt does not + // have a SwDrawContact yet, so it will fall back to SwUndo::GetComment(), + // which sets pComment to a wrong value. +// if (! pComment) + if (true) + { + /* + 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; +} + +// SwUndoDelLayFmt /////////////////////////////////////////////////////// + +static SwUndoId +lcl_GetSwUndoId(SwFrmFmt *const pFrmFmt) +{ + if (RES_DRAWFRMFMT != pFrmFmt->Which()) + { + const SwFmtCntnt& rCntnt = pFrmFmt->GetCntnt(); + OSL_ENSURE( rCntnt.GetCntntIdx(), "Fly without content" ); + + SwNodeIndex firstNode(*rCntnt.GetCntntIdx(), 1); + SwNoTxtNode *const pNoTxtNode(firstNode.GetNode().GetNoTxtNode()); + if (pNoTxtNode && pNoTxtNode->IsGrfNode()) + { + return UNDO_DELGRF; + } + else if (pNoTxtNode && pNoTxtNode->IsOLENode()) + { + // surprisingly not UNDO_DELOLE, which does not seem to work + return UNDO_DELETE; + } + } + return UNDO_DELLAYFMT; +} + +SwUndoDelLayFmt::SwUndoDelLayFmt( SwFrmFmt* pFormat ) + : SwUndoFlyBase( pFormat, lcl_GetSwUndoId(pFormat) ) + , bShowSelFrm( sal_True ) +{ + SwDoc* pDoc = pFormat->GetDoc(); + DelFly( pDoc ); +} + +SwRewriter SwUndoDelLayFmt::GetRewriter() const +{ + SwRewriter aRewriter; + + SwDoc * pDoc = pFrmFmt->GetDoc(); + + if (pDoc) + { + SwNodeIndex* pIdx = GetMvSttIdx(); + if( 1 == GetMvNodeCnt() && pIdx) + { + SwNode *const pNd = & pIdx->GetNode(); + + if ( pNd->IsNoTxtNode() && pNd->IsOLENode()) + { + SwOLENode * pOLENd = pNd->GetOLENode(); + + aRewriter.AddRule(UNDO_ARG1, pOLENd->GetDescription()); + } + } + } + + return aRewriter; +} + +void SwUndoDelLayFmt::UndoImpl(::sw::UndoRedoContext & rContext) +{ + InsFly( rContext, bShowSelFrm ); +} + +void SwUndoDelLayFmt::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc(rContext.GetDoc()); + const SwFmtCntnt& rCntnt = pFrmFmt->GetCntnt(); + if( rCntnt.GetCntntIdx() ) // kein Inhalt + { + RemoveIdxFromSection(rDoc, rCntnt.GetCntntIdx()->GetIndex()); + } + + DelFly(& rDoc); +} + +void SwUndoDelLayFmt::RedoForRollback() +{ + const SwFmtCntnt& rCntnt = pFrmFmt->GetCntnt(); + if( rCntnt.GetCntntIdx() ) // kein Inhalt + RemoveIdxFromSection( *pFrmFmt->GetDoc(), + rCntnt.GetCntntIdx()->GetIndex() ); + + DelFly( pFrmFmt->GetDoc() ); +} + +// SwUndoSetFlyFmt /////////////////////////////////////////////////////// + +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( sal_False ) +{ +} + +SwRewriter SwUndoSetFlyFmt::GetRewriter() const +{ + SwRewriter aRewriter; + + if (pNewFmt) + aRewriter.AddRule(UNDO_ARG1, pNewFmt->GetName()); + + return aRewriter; +} + + +SwUndoSetFlyFmt::~SwUndoSetFlyFmt() +{ + delete pItemSet; +} + +void SwUndoSetFlyFmt::DeRegisterFromFormat( SwFmt& rFmt ) +{ + rFmt.Remove(this); +} + +void SwUndoSetFlyFmt::GetAnchor( SwFmtAnchor& rAnchor, + sal_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::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.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(); + OSL_ENSURE( pTxtNode->HasHints(), "Missing FlyInCnt-Hint." ); + const xub_StrLen nIdx = pPos->nContent.GetIndex(); + SwTxtAttr * pHnt = pTxtNode->GetTxtAttrForCharAt( + nIdx, RES_TXTATR_FLYCNT ); + OSL_ENSURE( pHnt && pHnt->Which() == RES_TXTATR_FLYCNT, + "Missing FlyInCnt-Hint." ); + OSL_ENSURE( 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(); + } + rContext.SetSelections(pFrmFmt, 0); + } +} + +void SwUndoSetFlyFmt::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.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 ); + + rContext.SetSelections(pFrmFmt, 0); + } +} + +void SwUndoSetFlyFmt::PutAttr( sal_uInt16 nWhich, const SfxPoolItem* pItem ) +{ + if( pItem && pItem != GetDfltAttr( nWhich ) ) + { + // Sonderbehandlung fuer den Anchor + if( RES_ANCHOR == nWhich ) + { + // nur den 1. Ankerwechsel vermerken + OSL_ENSURE( !bAnchorChgd, "mehrfacher Ankerwechsel nicht erlaubt!" ); + + bAnchorChgd = sal_True; + + const SwFmtAnchor* pAnchor = (SwFmtAnchor*)pItem; + switch( nOldAnchorTyp = static_cast<sal_uInt16>(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<sal_uInt16>(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( const SfxPoolItem* pOld, const SfxPoolItem* ) +{ + if( pOld ) + { + sal_uInt16 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(); + } + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/undo/undoflystrattr.cxx b/sw/source/core/undo/undoflystrattr.cxx new file mode 100644 index 000000000000..8358603fbed4 --- /dev/null +++ b/sw/source/core/undo/undoflystrattr.cxx @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <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 ) +{ + OSL_ENSURE( eUndoId == UNDO_FLYFRMFMT_TITLE || + eUndoId == UNDO_FLYFRMFMT_DESCRIPTION, + "<SwUndoFlyStrAttr::SwUndoFlyStrAttr(..)> - unexpected undo id --> Undo will not work" ); +} + +SwUndoFlyStrAttr::~SwUndoFlyStrAttr() +{ +} + +void SwUndoFlyStrAttr::UndoImpl(::sw::UndoRedoContext &) +{ + switch ( GetId() ) + { + case UNDO_FLYFRMFMT_TITLE: + { + mrFlyFrmFmt.SetObjTitle( msOldStr, true ); + } + break; + case UNDO_FLYFRMFMT_DESCRIPTION: + { + mrFlyFrmFmt.SetObjDescription( msOldStr, true ); + } + break; + default: + { + } + } +} + +void SwUndoFlyStrAttr::RedoImpl(::sw::UndoRedoContext &) +{ + switch ( GetId() ) + { + case UNDO_FLYFRMFMT_TITLE: + { + mrFlyFrmFmt.SetObjTitle( msNewStr, true ); + } + break; + case UNDO_FLYFRMFMT_DESCRIPTION: + { + mrFlyFrmFmt.SetObjDescription( msNewStr, true ); + } + break; + default: + { + } + } +} + +SwRewriter SwUndoFlyStrAttr::GetRewriter() const +{ + SwRewriter aResult; + + aResult.AddRule( UNDO_ARG1, mrFlyFrmFmt.GetName() ); + + return aResult; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/undo/undraw.cxx b/sw/source/core/undo/undraw.cxx new file mode 100644 index 000000000000..b92ce4f488a9 --- /dev/null +++ b/sw/source/core/undo/undraw.cxx @@ -0,0 +1,608 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <UndoDraw.hxx> + +#include <rtl/string.h> +#include <rtl/memory.h> + +#include <rtl/string.h> +#include <svx/svdogrp.hxx> +#include <svx/svdundo.hxx> +#include <svx/svdpage.hxx> +#include <svx/svdmark.hxx> + +#include <hintids.hxx> +#include <hints.hxx> +#include <fmtanchr.hxx> +#include <fmtflcnt.hxx> +#include <txtflcnt.hxx> +#include <frmfmt.hxx> +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <docary.hxx> +#include <frame.hxx> +#include <swundo.hxx> // fuer die UndoIds +#include <pam.hxx> +#include <ndtxt.hxx> +#include <UndoCore.hxx> +#include <dcontact.hxx> +#include <dview.hxx> +#include <rootfrm.hxx> +#include <viewsh.hxx> + + +struct SwUndoGroupObjImpl +{ + SwDrawFrmFmt* pFmt; + SdrObject* pObj; + sal_uLong nNodeIdx; +}; + + +// Draw-Objecte + +IMPL_LINK( SwDoc, AddDrawUndo, SdrUndoAction *, pUndo ) +{ +#if OSL_DEBUG_LEVEL > 1 + sal_uInt16 nId = pUndo->GetId(); + (void)nId; + String sComment( pUndo->GetComment() ); +#endif + + if (GetIDocumentUndoRedo().DoesUndo() && + GetIDocumentUndoRedo().DoesDrawUndo()) + { + const SdrMarkList* pMarkList = 0; + ViewShell* pSh = GetCurrentViewShell(); + if( pSh && pSh->HasDrawView() ) + pMarkList = &pSh->GetDrawView()->GetMarkedObjectList(); + + GetIDocumentUndoRedo().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::UndoImpl(::sw::UndoRedoContext & rContext) +{ + pSdrUndo->Undo(); + rContext.SetSelections(0, pMarkList); +} + +void SwSdrUndo::RedoImpl(::sw::UndoRedoContext & rContext) +{ + pSdrUndo->Redo(); + rContext.SetSelections(0, pMarkList); +} + +String SwSdrUndo::GetComment() const +{ + return pSdrUndo->GetComment(); +} + +//-------------------------------------------- + +void lcl_SendRemoveToUno( SwFmt& rFmt ) +{ + SwPtrMsgPoolItem aMsgHint( RES_REMOVE_UNO_OBJECT, &rFmt ); + rFmt.ModifyNotification( &aMsgHint, &aMsgHint ); +} + +void lcl_SaveAnchor( SwFrmFmt* pFmt, sal_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(); + + // destroy TextAttribute + SwTxtNode *pTxtNd = pFmt->GetDoc()->GetNodes()[ rNodePos ]->GetTxtNode(); + OSL_ENSURE( pTxtNd, "No text node found!" ); + SwTxtFlyCnt* pAttr = static_cast<SwTxtFlyCnt*>( + pTxtNd->GetTxtAttrForCharAt( nCntntPos, RES_TXTATR_FLYCNT )); + // attribute still in text node, delete + if( pAttr && pAttr->GetFlyCnt().GetFrmFmt() == pFmt ) + { + // just set pointer to 0, don't delete + ((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, sal_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(); + OSL_ENSURE( pTxtNd, "no Text Node" ); + SwFmtFlyCnt aFmt( pFmt ); + pTxtNd->InsertItem( aFmt, nCntntPos, nCntntPos ); + } + } +} + +SwUndoDrawGroup::SwUndoDrawGroup( sal_uInt16 nCnt ) + : SwUndo( UNDO_DRAWGROUP ), nSize( nCnt + 1 ), bDelFmt( sal_True ) +{ + pObjArr = new SwUndoGroupObjImpl[ nSize ]; +} + +SwUndoDrawGroup::~SwUndoDrawGroup() +{ + if( bDelFmt ) + { + SwUndoGroupObjImpl* pTmp = pObjArr + 1; + for( sal_uInt16 n = 1; n < nSize; ++n, ++pTmp ) + delete pTmp->pFmt; + } + else + delete pObjArr->pFmt; + + delete [] pObjArr; +} + +void SwUndoDrawGroup::UndoImpl(::sw::UndoRedoContext &) +{ + bDelFmt = sal_False; + + // save group object + SwDrawFrmFmt* pFmt = pObjArr->pFmt; + SwDrawContact* pDrawContact = (SwDrawContact*)pFmt->FindContactObj(); + SdrObject* pObj = pDrawContact->GetMaster(); + pObjArr->pObj = pObj; + + // object will destroy itself + pDrawContact->Changed( *pObj, SDRUSERCALL_DELETE, pObj->GetLastBoundRect() ); + pObj->SetUserCall( 0 ); + + ::lcl_SaveAnchor( pFmt, pObjArr->nNodeIdx ); + + // notify UNO objects to decouple + ::lcl_SendRemoveToUno( *pFmt ); + + // remove from array + SwDoc* pDoc = pFmt->GetDoc(); + SwSpzFrmFmts& rFlyFmts = *(SwSpzFrmFmts*)pDoc->GetSpzFrmFmts(); + rFlyFmts.Remove( rFlyFmts.GetPos( pFmt )); + + for( sal_uInt16 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(); + // #i45718# - follow-up of #i35635# move object to visible layer + pContact->MoveObjToVisibleLayer( pObj ); + // #i45952# - notify that position attributes are already set + OSL_ENSURE( 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::RedoImpl(::sw::UndoRedoContext &) +{ + bDelFmt = sal_True; + + // remove from array + SwDoc* pDoc = pObjArr->pFmt->GetDoc(); + SwSpzFrmFmts& rFlyFmts = *(SwSpzFrmFmts*)pDoc->GetSpzFrmFmts(); + SdrObject* pObj; + + for( sal_uInt16 n = 1; n < nSize; ++n ) + { + SwUndoGroupObjImpl& rSave = *( pObjArr + n ); + + pObj = rSave.pObj; + + SwDrawContact *pContact = (SwDrawContact*)GetUserCall(pObj); + + // object will destroy itself + pContact->Changed( *pObj, SDRUSERCALL_DELETE, pObj->GetLastBoundRect() ); + pObj->SetUserCall( 0 ); + + ::lcl_SaveAnchor( rSave.pFmt, rSave.nNodeIdx ); + + // notify UNO objects to decouple + ::lcl_SendRemoveToUno( *rSave.pFmt ); + + rFlyFmts.Remove( rFlyFmts.GetPos( rSave.pFmt )); + } + + // re-insert group object + ::lcl_RestoreAnchor( pObjArr->pFmt, pObjArr->nNodeIdx ); + rFlyFmts.Insert( pObjArr->pFmt, rFlyFmts.Count() ); + + SwDrawContact *pContact = new SwDrawContact( pObjArr->pFmt, pObjArr->pObj ); + // #i26791# - correction: connect object to layout + pContact->ConnectToLayout(); + // #i45718# - follow-up of #i35635# move object to visible layer + pContact->MoveObjToVisibleLayer( pObjArr->pObj ); + // #i45952# - notify that position attributes are already set + OSL_ENSURE( 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( sal_uInt16 nPos, SwDrawFrmFmt* pFmt, SdrObject* pObj ) +{ + SwUndoGroupObjImpl& rSave = *( pObjArr + nPos + 1 ); + rSave.pObj = pObj; + rSave.pFmt = pFmt; + ::lcl_SaveAnchor( pFmt, rSave.nNodeIdx ); + + // notify UNO objects to decouple + ::lcl_SendRemoveToUno( *pFmt ); + + // remove from array + 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( sal_False ) +{ + nSize = (sal_uInt16)pObj->GetSubList()->GetObjCount() + 1; + pObjArr = new SwUndoGroupObjImpl[ nSize ]; + + SwDrawContact *pContact = (SwDrawContact*)GetUserCall(pObj); + SwDrawFrmFmt* pFmt = (SwDrawFrmFmt*)pContact->GetFmt(); + + pObjArr->pObj = pObj; + pObjArr->pFmt = pFmt; + + // object will destroy itself + pContact->Changed( *pObj, SDRUSERCALL_DELETE, pObj->GetLastBoundRect() ); + pObj->SetUserCall( 0 ); + + ::lcl_SaveAnchor( pFmt, pObjArr->nNodeIdx ); + + // notify UNO objects to decouple + ::lcl_SendRemoveToUno( *pFmt ); + + // remove from array + SwSpzFrmFmts& rFlyFmts = *(SwSpzFrmFmts*)pFmt->GetDoc()->GetSpzFrmFmts(); + rFlyFmts.Remove( rFlyFmts.GetPos( pFmt )); +} + +SwUndoDrawUnGroup::~SwUndoDrawUnGroup() +{ + if( bDelFmt ) + { + SwUndoGroupObjImpl* pTmp = pObjArr + 1; + for( sal_uInt16 n = 1; n < nSize; ++n, ++pTmp ) + delete pTmp->pFmt; + } + else + delete pObjArr->pFmt; + + delete [] pObjArr; +} + +void SwUndoDrawUnGroup::UndoImpl(::sw::UndoRedoContext & rContext) +{ + bDelFmt = sal_True; + + SwDoc *const pDoc = & rContext.GetDoc(); + SwSpzFrmFmts& rFlyFmts = *(SwSpzFrmFmts*)pDoc->GetSpzFrmFmts(); + + // remove from array + for( sal_uInt16 n = 1; n < nSize; ++n ) + { + SwUndoGroupObjImpl& rSave = *( pObjArr + n ); + + ::lcl_SaveAnchor( rSave.pFmt, rSave.nNodeIdx ); + + // notify UNO objects to decouple + ::lcl_SendRemoveToUno( *rSave.pFmt ); + + rFlyFmts.Remove( rFlyFmts.GetPos( rSave.pFmt )); + } + + // re-insert group object + ::lcl_RestoreAnchor( pObjArr->pFmt, pObjArr->nNodeIdx ); + rFlyFmts.Insert( pObjArr->pFmt, rFlyFmts.Count() ); + + SwDrawContact *pContact = new SwDrawContact( pObjArr->pFmt, pObjArr->pObj ); + pContact->ConnectToLayout(); + // #i45718# - follow-up of #i35635# move object to visible layer + pContact->MoveObjToVisibleLayer( pObjArr->pObj ); + // #i45952# - notify that position attributes are already set + OSL_ENSURE( 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::RedoImpl(::sw::UndoRedoContext &) +{ + bDelFmt = sal_False; + + // save group object + SwDrawFrmFmt* pFmt = pObjArr->pFmt; + SwDrawContact* pContact = (SwDrawContact*)pFmt->FindContactObj(); + + // object will destroy itself + pContact->Changed( *pObjArr->pObj, SDRUSERCALL_DELETE, + pObjArr->pObj->GetLastBoundRect() ); + pObjArr->pObj->SetUserCall( 0 ); + + ::lcl_SaveAnchor( pFmt, pObjArr->nNodeIdx ); + + // notify UNO objects to decouple + ::lcl_SendRemoveToUno( *pFmt ); + + // remove from array + SwDoc* pDoc = pFmt->GetDoc(); + SwSpzFrmFmts& rFlyFmts = *(SwSpzFrmFmts*)pDoc->GetSpzFrmFmts(); + rFlyFmts.Remove( rFlyFmts.GetPos( pFmt )); + + for( sal_uInt16 n = 1; n < nSize; ++n ) + { + SwUndoGroupObjImpl& rSave = *( pObjArr + n ); + + ::lcl_RestoreAnchor( rSave.pFmt, rSave.nNodeIdx ); + rFlyFmts.Insert( rSave.pFmt, rFlyFmts.Count() ); + + // #i45952# - notify that position attributes are already set + OSL_ENSURE( 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( sal_uInt16 nPos, SwDrawFrmFmt* pFmt ) +{ + SwUndoGroupObjImpl& rSave = *( pObjArr + nPos + 1 ); + rSave.pFmt = pFmt; + rSave.pObj = 0; +} + +SwUndoDrawUnGroupConnectToLayout::SwUndoDrawUnGroupConnectToLayout() + : SwUndo( UNDO_DRAWUNGROUP ) +{ +} + +SwUndoDrawUnGroupConnectToLayout::~SwUndoDrawUnGroupConnectToLayout() +{ +} + +void +SwUndoDrawUnGroupConnectToLayout::UndoImpl(::sw::UndoRedoContext &) +{ + for ( std::vector< SdrObject >::size_type i = 0; + i < aDrawFmtsAndObjs.size(); ++i ) + { + SdrObject* pObj( aDrawFmtsAndObjs[i].second ); + SwDrawContact* pDrawContact( dynamic_cast<SwDrawContact*>(pObj->GetUserCall()) ); + OSL_ENSURE( 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::RedoImpl(::sw::UndoRedoContext &) +{ + 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( sal_uInt16 nCnt ) + : SwUndo( UNDO_DRAWDELETE ), nSize( nCnt ), bDelFmt( sal_True ) +{ + pObjArr = new SwUndoGroupObjImpl[ nSize ]; + pMarkLst = new SdrMarkList(); +} + +SwUndoDrawDelete::~SwUndoDrawDelete() +{ + if( bDelFmt ) + { + SwUndoGroupObjImpl* pTmp = pObjArr; + for( sal_uInt16 n = 0; n < pMarkLst->GetMarkCount(); ++n, ++pTmp ) + delete pTmp->pFmt; + } + delete [] pObjArr; + delete pMarkLst; +} + +void SwUndoDrawDelete::UndoImpl(::sw::UndoRedoContext & rContext) +{ + bDelFmt = sal_False; + SwSpzFrmFmts & rFlyFmts = *rContext.GetDoc().GetSpzFrmFmts(); + for( sal_uInt16 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 ); + // #i45718# - follow-up of #i35635# move object to visible layer + pContact->MoveObjToVisibleLayer( pObj ); + // #i45952# - notify that position attributes are already set + OSL_ENSURE( 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(); + } + // <-- + } + rContext.SetSelections(0, pMarkLst); +} + +void SwUndoDrawDelete::RedoImpl(::sw::UndoRedoContext & rContext) +{ + bDelFmt = sal_True; + SwSpzFrmFmts & rFlyFmts = *rContext.GetDoc().GetSpzFrmFmts(); + for( sal_uInt16 n = 0; n < pMarkLst->GetMarkCount(); ++n ) + { + SwUndoGroupObjImpl& rSave = *( pObjArr + n ); + SdrObject *pObj = rSave.pObj; + SwDrawContact *pContact = (SwDrawContact*)GetUserCall(pObj); + SwDrawFrmFmt *pFmt = (SwDrawFrmFmt*)pContact->GetFmt(); + + // object will destroy itself + pContact->Changed( *pObj, SDRUSERCALL_DELETE, pObj->GetLastBoundRect() ); + pObj->SetUserCall( 0 ); + + // notify UNO objects to decouple + ::lcl_SendRemoveToUno( *pFmt ); + + rFlyFmts.Remove( rFlyFmts.GetPos( pFmt )); + ::lcl_SaveAnchor( pFmt, rSave.nNodeIdx ); + } +} + +void SwUndoDrawDelete::AddObj( sal_uInt16 , SwDrawFrmFmt* pFmt, + const SdrMark& rMark ) +{ + SwUndoGroupObjImpl& rSave = *( pObjArr + pMarkLst->GetMarkCount() ); + rSave.pObj = rMark.GetMarkedSdrObj(); + rSave.pFmt = pFmt; + ::lcl_SaveAnchor( pFmt, rSave.nNodeIdx ); + + // notify UNO objects to decouple + ::lcl_SendRemoveToUno( *pFmt ); + + // remove from array + SwDoc* pDoc = pFmt->GetDoc(); + SwSpzFrmFmts& rFlyFmts = *(SwSpzFrmFmts*)pDoc->GetSpzFrmFmts(); + rFlyFmts.Remove( rFlyFmts.GetPos( pFmt )); + + pMarkLst->InsertEntry( rMark ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/undo/unfmco.cxx b/sw/source/core/undo/unfmco.cxx new file mode 100644 index 000000000000..4ba736443dba --- /dev/null +++ b/sw/source/core/undo/unfmco.cxx @@ -0,0 +1,122 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + + +#include "doc.hxx" +#include "swundo.hxx" // fuer die UndoIds +#include "pam.hxx" +#include "ndtxt.hxx" + +#include <UndoCore.hxx> +#include "rolbck.hxx" + + +//-------------------------------------------------- + + +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::UndoImpl(::sw::UndoRedoContext & rContext) +{ + // restore old values + pHistory->TmpRollback(& rContext.GetDoc(), 0); + pHistory->SetTmpEnd( pHistory->Count() ); + + // create cursor for undo range + AddUndoRedoPaM(rContext); +} + + +void SwUndoFmtColl::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwPaM & rPam = AddUndoRedoPaM(rContext); + + DoSetFmtColl(rContext.GetDoc(), rPam); +} + +void SwUndoFmtColl::RepeatImpl(::sw::RepeatContext & rContext) +{ + DoSetFmtColl(rContext.GetDoc(), rContext.GetRepeatPaM()); +} + +void SwUndoFmtColl::DoSetFmtColl(SwDoc & rDoc, SwPaM & rPaM) +{ + // es kann nur eine TextFmtColl auf einen Bereich angewendet werden, + // also erfrage auch nur in dem Array + sal_uInt16 const nPos = rDoc.GetTxtFmtColls()->GetPos( + (SwTxtFmtColl*)pFmtColl ); + // does the format still exist? + if( USHRT_MAX != nPos ) + { + rDoc.SetTxtFmtColl(rPaM, + (SwTxtFmtColl*)pFmtColl, + mbReset, + mbResetListAttrs ); + } +} + +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; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/undo/unins.cxx b/sw/source/core/undo/unins.cxx new file mode 100644 index 000000000000..4cb2b0e94b63 --- /dev/null +++ b/sw/source/core/undo/unins.cxx @@ -0,0 +1,1068 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <UndoInsert.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 <IDocumentUndoRedo.hxx> +#include <swundo.hxx> // fuer die UndoIds +#include <pam.hxx> +#include <ndtxt.hxx> +#include <UndoCore.hxx> +#include <UndoDelete.hxx> +#include <UndoAttribute.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; + + +//------------------------------------------------------------ + +// 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, + sal_Bool bWDelim ) + : SwUndo(UNDO_TYPING), pPos( 0 ), pTxt( 0 ), pRedlData( 0 ), + nNode( rNd.GetIndex() ), nCntnt(nCnt), nLen(nL), + bIsWordDelim( bWDelim ), bIsAppend( sal_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( sal_False ), bIsAppend( sal_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. + +sal_Bool SwUndoInsert::CanGrouping( sal_Unicode cIns ) +{ + if( !bIsAppend && bIsWordDelim == + !GetAppCharClass().isLetterNumeric( String( cIns )) ) + { + nLen++; + nCntnt++; + + if (pUndoTxt) + pUndoTxt->Insert(cIns); + + return sal_True; + } + return sal_False; +} + +sal_Bool SwUndoInsert::CanGrouping( const SwPosition& rPos ) +{ + sal_Bool bRet = sal_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 = sal_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( sal_uInt16 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 = sal_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(); + OSL_ENSURE( 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::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc *const pTmpDoc = & rContext.GetDoc(); + SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor()); + + if( bIsAppend ) + { + 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 + { + sal_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, sal_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, sal_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(); + } + + // set cursor to Undo range + pPam->DeleteMark(); + + pPam->GetPoint()->nNode = nNd; + pPam->GetPoint()->nContent.Assign( + pPam->GetPoint()->nNode.GetNode().GetCntntNode(), nCnt ); + } + + DELETEZ(pUndoTxt); +} + + +void SwUndoInsert::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc *const pTmpDoc = & rContext.GetDoc(); + SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor()); + 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 *const pCNd = + pPam->GetPoint()->nNode.GetNode().GetCntntNode(); + pPam->GetPoint()->nContent.Assign( pCNd, nCntnt ); + + if( nLen ) + { + sal_Bool bMvBkwrd = MovePtBackward( *pPam ); + + if( pTxt ) + { + SwTxtNode *const pTxtNode = pCNd->GetTxtNode(); + OSL_ENSURE( pTxtNode, "where is my textnode ?" ); + pTxtNode->InsertText( *pTxt, pPam->GetMark()->nContent, + m_nInsertFlags ); + DELETEZ( pTxt ); + } + else + { + // Inhalt wieder einfuegen. (erst pPos abmelden !!) + sal_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 ); + 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); + } + } + + pUndoTxt = GetTxtFromDoc(); +} + + +void SwUndoInsert::RepeatImpl(::sw::RepeatContext & rContext) +{ + if( !nLen ) + return; + + SwDoc & rDoc = rContext.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( *rContext.GetRepeatPaM().GetPoint() ); + } + else + { + String aTxt( ((SwTxtNode*)pCNd)->GetTxt() ); + ::sw::GroupUndoGuard const undoGuard(rDoc.GetIDocumentUndoRedo()); + rDoc.InsertString( rContext.GetRepeatPaM(), + aTxt.Copy( nCntnt - nLen, nLen ) ); + } + break; + case ND_GRFNODE: + { + SwGrfNode* pGrfNd = (SwGrfNode*)pCNd; + String sFile, sFilter; + if( pGrfNd->IsGrfLink() ) + pGrfNd->GetFileFilterNms( &sFile, &sFilter ); + + rDoc.Insert( rContext.GetRepeatPaM(), 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( rContext.GetRepeatPaM(), + svt::EmbeddedObjectRef( aNew, + static_cast<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 ///////////////////////////////////////////////////////// + + +class SwUndoReplace::Impl + : private SwUndoSaveCntnt +{ + ::rtl::OUString m_sOld; + ::rtl::OUString m_sIns; + sal_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: + Impl(SwPaM const& rPam, ::rtl::OUString const& rIns, bool const bRegExp); + virtual ~Impl() + { + } + + virtual void UndoImpl( ::sw::UndoRedoContext & ); + virtual void RedoImpl( ::sw::UndoRedoContext & ); + + void SetEnd(SwPaM const& rPam); + + ::rtl::OUString const& GetOld() const { return m_sOld; } + ::rtl::OUString const& GetIns() const { return m_sIns; } +}; + + +SwUndoReplace::SwUndoReplace(SwPaM const& rPam, + ::rtl::OUString const& rIns, bool const bRegExp) + : SwUndo( UNDO_REPLACE ) + , m_pImpl(new Impl(rPam, rIns, bRegExp)) +{ +} + +SwUndoReplace::~SwUndoReplace() +{ +} + +void SwUndoReplace::UndoImpl(::sw::UndoRedoContext & rContext) +{ + m_pImpl->UndoImpl(rContext); +} + +void SwUndoReplace::RedoImpl(::sw::UndoRedoContext & rContext) +{ + m_pImpl->RedoImpl(rContext); +} + +SwRewriter +MakeUndoReplaceRewriter(sal_uLong const occurrences, + ::rtl::OUString const& sOld, ::rtl::OUString const& sNew) +{ + SwRewriter aResult; + + if (1 < occurrences) + { + aResult.AddRule(UNDO_ARG1, String::CreateFromInt32(occurrences)); + aResult.AddRule(UNDO_ARG2, String(SW_RES(STR_OCCURRENCES_OF))); + + String aTmpStr; + aTmpStr += String(SW_RES(STR_START_QUOTE)); + aTmpStr += ShortenString(sOld, nUndoStringLength, + SW_RES(STR_LDOTS)); + aTmpStr += String(SW_RES(STR_END_QUOTE)); + aResult.AddRule(UNDO_ARG3, aTmpStr); + } + else if (1 == occurrences) + { + { + String aTmpStr; + + aTmpStr += String(SW_RES(STR_START_QUOTE)); + // #i33488 # + aTmpStr += ShortenString(sOld, 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(sNew, nUndoStringLength, + SW_RES(STR_LDOTS)); + aTmpStr += String(SW_RES(STR_END_QUOTE)); + aResult.AddRule(UNDO_ARG3, aTmpStr); + } + } + + return aResult; +} + +// #111827# +SwRewriter SwUndoReplace::GetRewriter() const +{ + return MakeUndoReplaceRewriter(1, m_pImpl->GetOld(), m_pImpl->GetIns()); +} + +void SwUndoReplace::SetEnd(SwPaM const& rPam) +{ + m_pImpl->SetEnd(rPam); +} + +SwUndoReplace::Impl::Impl( + SwPaM const& rPam, ::rtl::OUString const& rIns, bool const bRegExp) + : m_sIns( rIns ) + , m_nOffset( 0 ) + , m_bRegExp(bRegExp) +{ + + 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(); + OSL_ENSURE( pNd, "wo ist der TextNode" ); + + pHistory = new SwHistory; + DelCntntIndex( *rPam.GetMark(), *rPam.GetPoint() ); + + m_nSetPos = pHistory->Count(); + + sal_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(); + sal_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 ); +} + +void SwUndoReplace::Impl::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc *const pDoc = & rContext.GetDoc(); + SwPaM & rPam(rContext.GetCursorSupplier().CreateNewShellCursor()); + rPam.DeleteMark(); + + SwTxtNode* pNd = pDoc->GetNodes()[ m_nSttNd - m_nOffset ]->GetTxtNode(); + OSL_ENSURE( pNd, "Wo ist der TextNode geblieben?" ); + + SwAutoCorrExceptWord* pACEWord = pDoc->GetAutoCorrExceptWord(); + if( pACEWord ) + { + if ((1 == m_sIns.getLength()) && (1 == m_sOld.getLength())) + { + SwPosition aPos( *pNd ); aPos.nContent.Assign( pNd, m_nSttCnt ); + pACEWord->CheckChar( aPos, m_sOld[ 0 ] ); + } + pDoc->SetAutoCorrExceptWord( 0 ); + } + + SwIndex aIdx( pNd, sal_uInt16( m_nSttCnt ) ); + if( m_nSttNd == m_nEndNd ) + { + pNd->EraseText( aIdx, sal_uInt16( m_sIns.getLength() ) ); + } + 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(); + OSL_ENSURE( 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.getLength()) + { + 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 SwUndoReplace::Impl::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + SwPaM & rPam(rContext.GetCursorSupplier().CreateNewShellCursor()); + rPam.DeleteMark(); + rPam.GetPoint()->nNode = m_nSttNd; + + SwTxtNode* pNd = rPam.GetPoint()->nNode.GetNode().GetTxtNode(); + OSL_ENSURE( 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(); +} + +void SwUndoReplace::Impl::SetEnd(SwPaM const& rPam) +{ + if( rPam.GetPoint()->nNode != rPam.GetMark()->nNode ) + { + // multiple paragraphs were inserted + const SwPosition* pEnd = rPam.End(); + m_nEndNd = m_nOffset + pEnd->nNode.GetIndex(); + m_nEndCnt = pEnd->nContent.GetIndex(); + } +} + + +// SwUndoReRead ////////////////////////////////////////////////////////// + + +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(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + SwGrfNode* pGrfNd = rDoc.GetNodes()[ nPos ]->GetGrfNode(); + + if( !pGrfNd ) + return ; + + // die alten Werte zwischen speichern + Graphic* pOldGrf = pGrf; + String* pOldNm = pNm; + String* pOldFltr = pFltr; + sal_uInt16 nOldMirr = nMirr; + + SaveGraphicData( *pGrfNd ); + if( pOldNm ) + { + pGrfNd->ReRead( *pOldNm, pFltr ? *pFltr : aEmptyStr, 0, 0, sal_True ); + delete pOldNm; + delete pOldFltr; + } + else + { + pGrfNd->ReRead( aEmptyStr, aEmptyStr, pOldGrf, 0, sal_True ); + delete pOldGrf; + } + + if( RES_MIRROR_GRAPH_DONT != nOldMirr ) + pGrfNd->SetAttr( SwMirrorGrf() ); + + rContext.SetSelections(pGrfNd->GetFlyFmt(), 0); +} + + +void SwUndoReRead::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SetAndSave(rContext); +} + + +void SwUndoReRead::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SetAndSave(rContext); +} + + +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( sal_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 sal_Bool bBef, + const sal_uInt16 nInitId, + const String& rCharacterStyle, + const sal_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 = sal_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::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + + if( LTYPE_OBJECT == eType || LTYPE_DRAW == eType ) + { + OSL_ENSURE( 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->UndoImpl(rContext); + OBJECT.pUndoFly->UndoImpl(rContext); + 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( rDoc.GetNodes().GetEndOfContent() ); + aPam.GetPoint()->nNode = NODE.nNode; + aPam.SetMark(); + aPam.GetPoint()->nNode = NODE.nNode + 1; + NODE.pUndoInsNd = new SwUndoDelete( aPam, sal_True ); + } +} + + +void SwUndoInsertLabel::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + + if( LTYPE_OBJECT == eType || LTYPE_DRAW == eType ) + { + OSL_ENSURE( 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->RedoImpl(rContext); + OBJECT.pUndoAttr->RedoImpl(rContext); + 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(sal_True, RES_KEEP) ); + } + NODE.pUndoInsNd->UndoImpl(rContext); + delete NODE.pUndoInsNd, NODE.pUndoInsNd = 0; + } +} + +void SwUndoInsertLabel::RepeatImpl(::sw::RepeatContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + const SwPosition& rPos = *rContext.GetRepeatPaM().GetPoint(); + + sal_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->getLayoutFrm( rDoc.GetCurrentLayout() ); + 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( sal_uInt8 nLId ) +{ + if( LTYPE_DRAW == eType ) + { + nLayerId = nLId; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/undo/unmove.cxx b/sw/source/core/undo/unmove.cxx new file mode 100644 index 000000000000..f7b01da4caa2 --- /dev/null +++ b/sw/source/core/undo/unmove.cxx @@ -0,0 +1,357 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <UndoSplitMove.hxx> + +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <pam.hxx> +#include <swundo.hxx> // fuer die UndoIds +#include <ndtxt.hxx> +#include <UndoCore.hxx> +#include <rolbck.hxx> + + +// 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 = sal_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 ); + } + + pTxtNd = rMvPos.nNode.GetNode().GetTxtNode(); + if (0 != pTxtNd) + { + 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 = sal_True; + bJoinNext = bJoinPrev = sal_False; + + nSttCntnt = nEndCntnt = nMvDestCntnt = STRING_MAXLEN; + + nSttNode = rRg.aStart.GetIndex(); + nEndNode = rRg.aEnd.GetIndex(); + +// DelFtn( rRange ); + + // wird aus dem CntntBereich in den Sonderbereich verschoben ? + sal_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, + sal_Bool bJoin, sal_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::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc *const pDoc = & rContext.GetDoc(); + + // 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, sal_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, sal_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( sal_False ); + + if( pHistory ) + { + if( nFtnStt != pHistory->Count() ) + pHistory->Rollback( pDoc, nFtnStt ); + pHistory->TmpRollback( pDoc, 0 ); + pHistory->SetTmpEnd( pHistory->Count() ); + } + + // setze noch den Cursor auf den Undo-Bereich + if( !bMoveRange ) + { + AddUndoRedoPaM(rContext); + } +} + + +void SwUndoMove::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwPaM *const pPam = & AddUndoRedoPaM(rContext); + SwDoc & rDoc = rContext.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, sal_False ); + + aIdx = aPam.Start()->nNode; + sal_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(); + sal_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; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/undo/unnum.cxx b/sw/source/core/undo/unnum.cxx new file mode 100644 index 000000000000..c775da164d01 --- /dev/null +++ b/sw/source/core/undo/unnum.cxx @@ -0,0 +1,454 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <UndoNumbering.hxx> + +#include <hintids.hxx> +#include <editeng/lrspitem.hxx> +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <swundo.hxx> // fuer die UndoIds +#include <pam.hxx> +#include <ndtxt.hxx> +#include <UndoCore.hxx> +#include <rolbck.hxx> + + +SV_DECL_PTRARR_DEL( _SfxPoolItems, SfxPoolItem*, 16, 16 ) +SV_IMPL_PTRARR( _SfxPoolItems, SfxPoolItem* ); + + +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::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + + if( pOldNumRule ) + rDoc.ChgNumRuleFmts( *pOldNumRule ); + + if( pHistory ) + { + SwTxtNode* pNd; + if( ULONG_MAX != nSttSet && + 0 != ( pNd = rDoc.GetNodes()[ nSttSet ]->GetTxtNode() )) + pNd->SetListRestart( sal_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(); + + pHistory->TmpRollback( &rDoc, nLRSavePos ); + + } + pHistory->TmpRollback( &rDoc, 0 ); + pHistory->SetTmpEnd( pHistory->Count() ); + } + + if (nSttNode) + { + AddUndoRedoPaM(rContext); + } +} + +void SwUndoInsNum::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + + if( pOldNumRule ) + rDoc.ChgNumRuleFmts( aNumRule ); + else if( pHistory ) + { + SwPaM & rPam( AddUndoRedoPaM(rContext) ); + if( sReplaceRule.Len() ) + { + rDoc.ReplaceNumRule(*rPam.GetPoint(), + sReplaceRule, aNumRule.GetName() ); + } + else + { + // --> OD 2005-02-25 #i42921# - adapt to changed signature + rDoc.SetNumRule(rPam, aNumRule, false); + // <-- + } + } +} + +void SwUndoInsNum::SetLRSpaceEndPos() +{ + if( pHistory ) + nLRSavePos = pHistory->Count(); +} + +void SwUndoInsNum::RepeatImpl(::sw::RepeatContext & rContext) +{ + SwDoc & rDoc(rContext.GetDoc()); + if( nSttNode ) + { + if( !sReplaceRule.Len() ) + { + // --> OD 2005-02-25 #i42921# - adapt to changed signature + rDoc.SetNumRule(rContext.GetRepeatPaM(), aNumRule, false); + // <-- + } + } + else + { + rDoc.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 ) +{ + aNodes.reserve( nEndNode - nSttNode > 255 ? 255 : nEndNode - nSttNode ); + pHistory = new SwHistory; +} + +SwUndoDelNum::~SwUndoDelNum() +{ + delete pHistory; +} + +void SwUndoDelNum::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + + pHistory->TmpRollback( &rDoc, 0 ); + pHistory->SetTmpEnd( pHistory->Count() ); + + for( std::vector<NodeLevel>::const_iterator i = aNodes.begin(); i != aNodes.end(); ++i ) + { + SwTxtNode* pNd = rDoc.GetNodes()[ i->index ]->GetTxtNode(); + OSL_ENSURE( pNd, "Where has the TextNode gone?" ); + pNd->SetAttrListLevel( i->level ); + + if( pNd->GetCondFmtColl() ) + pNd->ChkCondColl(); + } + + AddUndoRedoPaM(rContext); +} + +void SwUndoDelNum::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwPaM & rPam( AddUndoRedoPaM(rContext) ); + rContext.GetDoc().DelNumRules(rPam); +} + +void SwUndoDelNum::RepeatImpl(::sw::RepeatContext & rContext) +{ + rContext.GetDoc().DelNumRules(rContext.GetRepeatPaM()); +} + +void SwUndoDelNum::AddNode( const SwTxtNode& rNd, sal_Bool ) +{ + if( rNd.GetNumRule() ) + { + aNodes.push_back( NodeLevel( rNd.GetIndex(), rNd.GetActualListLevel() ) ); + } +} + + +/* */ + + +SwUndoMoveNum::SwUndoMoveNum( const SwPaM& rPam, long nOff, sal_Bool bIsOutlMv ) + : SwUndo( bIsOutlMv ? UNDO_OUTLINE_UD : UNDO_MOVENUM ), + SwUndRng( rPam ), + nNewStt( 0 ), nOffset( nOff ) +{ + // nOffset: nach unten => 1 + // nach oben => -1 +} + +void SwUndoMoveNum::UndoImpl(::sw::UndoRedoContext & rContext) +{ + sal_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, sal_True ); + + SwPaM & rPam( AddUndoRedoPaM(rContext) ); + rContext.GetDoc().MoveParagraph( rPam, -nOffset, + UNDO_OUTLINE_UD == GetId() ); + nSttNode = nTmpStt; + nEndNode = nTmpEnd; +} + +void SwUndoMoveNum::RedoImpl(::sw::UndoRedoContext & rContext) +{ +//JP 22.06.95: wird wollen die Bookmarks/Verzeichnisse behalten, oder? +// SetPaM( rUndoIter ); +// RemoveIdxFromRange( *rUndoIter.pAktPam, sal_True ); + + SwPaM & rPam( AddUndoRedoPaM(rContext) ); + rContext.GetDoc().MoveParagraph(rPam, nOffset, UNDO_OUTLINE_UD == GetId()); +} + +void SwUndoMoveNum::RepeatImpl(::sw::RepeatContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + if( UNDO_OUTLINE_UD == GetId() ) + { + rDoc.MoveOutlinePara(rContext.GetRepeatPaM(), + 0 < nOffset ? 1 : -1 ); + } + else + { + rDoc.MoveParagraph(rContext.GetRepeatPaM(), nOffset, sal_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::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwPaM & rPam( AddUndoRedoPaM(rContext) ); + rContext.GetDoc().NumUpDown(rPam, 1 != nOffset ); +} + +void SwUndoNumUpDown::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwPaM & rPam( AddUndoRedoPaM(rContext) ); + rContext.GetDoc().NumUpDown(rPam, 1 == nOffset); +} + +void SwUndoNumUpDown::RepeatImpl(::sw::RepeatContext & rContext) +{ + rContext.GetDoc().NumUpDown(rContext.GetRepeatPaM(), 1 == nOffset); +} + +/* */ + +// #115901# +SwUndoNumOrNoNum::SwUndoNumOrNoNum( const SwNodeIndex& rIdx, sal_Bool bOldNum, + sal_Bool bNewNum) + : SwUndo( UNDO_NUMORNONUM ), nIdx( rIdx.GetIndex() ), mbNewNum(bNewNum), + mbOldNum(bOldNum) +{ +} + +// #115901#, #i40034# +void SwUndoNumOrNoNum::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwNodeIndex aIdx( rContext.GetDoc().GetNodes(), nIdx ); + SwTxtNode * pTxtNd = aIdx.GetNode().GetTxtNode(); + + if (NULL != pTxtNd) + { + pTxtNd->SetCountedInList(mbOldNum); + } +} + +// #115901#, #i40034# +void SwUndoNumOrNoNum::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwNodeIndex aIdx( rContext.GetDoc().GetNodes(), nIdx ); + SwTxtNode * pTxtNd = aIdx.GetNode().GetTxtNode(); + + if (NULL != pTxtNd) + { + pTxtNd->SetCountedInList(mbNewNum); + } +} + +// #115901# +void SwUndoNumOrNoNum::RepeatImpl(::sw::RepeatContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + if (mbOldNum && ! mbNewNum) + { + rDoc.NumOrNoNum(rContext.GetRepeatPaM().GetPoint()->nNode, sal_False); + } + else if ( ! mbOldNum && mbNewNum ) + { + rDoc.NumOrNoNum(rContext.GetRepeatPaM().GetPoint()->nNode, sal_True); + } +} + +/* */ + +SwUndoNumRuleStart::SwUndoNumRuleStart( const SwPosition& rPos, sal_Bool bFlg ) + : SwUndo( UNDO_SETNUMRULESTART ), + nIdx( rPos.nNode.GetIndex() ), nOldStt( USHRT_MAX ), + nNewStt( USHRT_MAX ), bSetSttValue( sal_False ), bFlag( bFlg ) +{ +} + +SwUndoNumRuleStart::SwUndoNumRuleStart( const SwPosition& rPos, sal_uInt16 nStt ) + : SwUndo( UNDO_SETNUMRULESTART ), + nIdx( rPos.nNode.GetIndex() ), + nOldStt( USHRT_MAX ), nNewStt( nStt ), bSetSttValue( sal_True ) +{ + SwTxtNode* pTxtNd = rPos.nNode.GetNode().GetTxtNode(); + if ( pTxtNd ) + { + if ( pTxtNd->HasAttrListRestartValue() ) + { + nOldStt = static_cast<sal_uInt16>(pTxtNd->GetAttrListRestartValue()); + } + else + { + nOldStt = USHRT_MAX; // indicating, that the list restart value is not set + } + } +} + + +void SwUndoNumRuleStart::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + SwPosition const aPos( *rDoc.GetNodes()[ nIdx ] ); + if( bSetSttValue ) + { + rDoc.SetNodeNumStart( aPos, nOldStt ); + } + else + { + rDoc.SetNumRuleStart( aPos, !bFlag ); + } +} + + +void SwUndoNumRuleStart::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + SwPosition const aPos( *rDoc.GetNodes()[ nIdx ] ); + if( bSetSttValue ) + { + rDoc.SetNodeNumStart( aPos, nNewStt ); + } + else + { + rDoc.SetNumRuleStart( aPos, bFlag ); + } +} + + +void SwUndoNumRuleStart::RepeatImpl(::sw::RepeatContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + if( bSetSttValue ) + { + rDoc.SetNodeNumStart(*rContext.GetRepeatPaM().GetPoint(), nNewStt); + } + else + { + rDoc.SetNumRuleStart(*rContext.GetRepeatPaM().GetPoint(), bFlag); + } +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/undo/unoutl.cxx b/sw/source/core/undo/unoutl.cxx new file mode 100644 index 000000000000..109387765fc6 --- /dev/null +++ b/sw/source/core/undo/unoutl.cxx @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include "doc.hxx" +#include "swundo.hxx" // fuer die UndoIds +#include "pam.hxx" +#include "ndtxt.hxx" + +#include <UndoCore.hxx> + + +SwUndoOutlineLeftRight::SwUndoOutlineLeftRight( const SwPaM& rPam, + short nOff ) + : SwUndo( UNDO_OUTLINE_LR ), SwUndRng( rPam ), nOffset( nOff ) +{ +} + +void SwUndoOutlineLeftRight::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwPaM & rPaM( AddUndoRedoPaM(rContext) ); + rContext.GetDoc().OutlineUpDown(rPaM, -nOffset); +} + +void SwUndoOutlineLeftRight::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwPaM & rPaM( AddUndoRedoPaM(rContext) ); + rContext.GetDoc().OutlineUpDown(rPaM, nOffset); +} + +void SwUndoOutlineLeftRight::RepeatImpl(::sw::RepeatContext & rContext) +{ + rContext.GetDoc().OutlineUpDown(rContext.GetRepeatPaM(), nOffset); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
\ No newline at end of file diff --git a/sw/source/core/undo/unovwr.cxx b/sw/source/core/undo/unovwr.cxx new file mode 100644 index 000000000000..f2f83a06fd42 --- /dev/null +++ b/sw/source/core/undo/unovwr.cxx @@ -0,0 +1,504 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <UndoOverwrite.hxx> + +#include <tools/resid.hxx> + +#include <unotools/charclass.hxx> +#include <unotools/transliterationwrapper.hxx> + +#include <comphelper/processfactory.hxx> + +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <IShellCursorSupplier.hxx> +#include <swundo.hxx> // fuer die UndoIds +#include <pam.hxx> +#include <ndtxt.hxx> +#include <UndoCore.hxx> +#include <rolbck.hxx> +#include <acorrect.hxx> +#include <docary.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; + + +//------------------------------------------------------------ + +// OVERWRITE + + +SwUndoOverwrite::SwUndoOverwrite( SwDoc* pDoc, SwPosition& rPos, + sal_Unicode cIns ) + : SwUndo(UNDO_OVERWRITE), + pRedlSaveData( 0 ), bGroup( sal_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, sal_False )) + delete pRedlSaveData, pRedlSaveData = 0; + } + + nSttNode = rPos.nNode.GetIndex(); + nSttCntnt = rPos.nContent.GetIndex(); + + SwTxtNode* pTxtNd = rPos.nNode.GetNode().GetTxtNode(); + OSL_ENSURE( pTxtNd, "Overwrite nicht im TextNode?" ); + + bInsChar = sal_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 = sal_False; + } + + sal_Bool bOldExpFlg = pTxtNd->IsIgnoreDontExpand(); + pTxtNd->SetIgnoreDontExpand( sal_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; +} + +sal_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 sal_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 sal_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 sal_False; + + { + SwRedlineSaveDatas* pTmpSav = new SwRedlineSaveDatas; + SwPaM aPam( rPos.nNode, rPos.nContent.GetIndex(), + rPos.nNode, rPos.nContent.GetIndex()+1 ); + + if( !FillSaveData( aPam, *pTmpSav, sal_False )) + delete pTmpSav, pTmpSav = 0; + + sal_Bool bOk = ( !pRedlSaveData && !pTmpSav ) || + ( pRedlSaveData && pTmpSav && + SwUndo::CanRedlineGroup( *pRedlSaveData, *pTmpSav, + nSttCntnt > rPos.nContent.GetIndex() )); + delete pTmpSav; + if( !bOk ) + return sal_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 = sal_True; + } + + sal_Bool bOldExpFlg = pDelTxtNd->IsIgnoreDontExpand(); + pDelTxtNd->SetIgnoreDontExpand( sal_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 = sal_True; + return sal_True; +} + + + + + +void SwUndoOverwrite::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc *const pDoc = & rContext.GetDoc(); + SwPaM *const pAktPam(& rContext.GetCursorSupplier().CreateNewShellCursor()); + + pAktPam->DeleteMark(); + pAktPam->GetPoint()->nNode = nSttNode; + SwTxtNode* pTxtNd = pAktPam->GetNode()->GetTxtNode(); + OSL_ENSURE( 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(); + + sal_Bool bOldExpFlg = pTxtNd->IsIgnoreDontExpand(); + pTxtNd->SetIgnoreDontExpand( sal_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::RepeatImpl(::sw::RepeatContext & rContext) +{ + SwPaM *const pAktPam = & rContext.GetRepeatPaM(); + if( !aInsStr.Len() || pAktPam->HasMark() ) + return; + + SwDoc & rDoc = rContext.GetDoc(); + + { + ::sw::GroupUndoGuard const undoGuard(rDoc.GetIDocumentUndoRedo()); + rDoc.Overwrite(*pAktPam, aInsStr.GetChar(0)); + } + for( xub_StrLen n = 1; n < aInsStr.Len(); ++n ) + rDoc.Overwrite( *pAktPam, aInsStr.GetChar( n ) ); +} + +void SwUndoOverwrite::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc *const pDoc = & rContext.GetDoc(); + SwPaM *const pAktPam(& rContext.GetCursorSupplier().CreateNewShellCursor()); + + pAktPam->DeleteMark(); + pAktPam->GetPoint()->nNode = nSttNode; + SwTxtNode* pTxtNd = pAktPam->GetNode()->GetTxtNode(); + OSL_ENSURE( 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 ); + + sal_Bool bOldExpFlg = pTxtNd->IsIgnoreDontExpand(); + pTxtNd->SetIgnoreDontExpand( sal_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; + sal_uLong nNdIdx; + xub_StrLen nStart, nLen; + + _UndoTransliterate_Data( sal_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::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + + // 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 ); + + AddUndoRedoPaM(rContext, true); +} + +void SwUndoTransliterate::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwPaM & rPam( AddUndoRedoPaM(rContext) ); + DoTransliterate(rContext.GetDoc(), rPam); +} + +void SwUndoTransliterate::RepeatImpl(::sw::RepeatContext & rContext) +{ + DoTransliterate(rContext.GetDoc(), rContext.GetRepeatPaM()); +} + +void SwUndoTransliterate::DoTransliterate(SwDoc & rDoc, SwPaM & rPam) +{ + utl::TransliterationWrapper aTrans( ::comphelper::getProcessServiceFactory(), nType ); + rDoc.TransliterateText( rPam, aTrans ); +} + +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() ); + } + } +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/undo/unredln.cxx b/sw/source/core/undo/unredln.cxx new file mode 100644 index 000000000000..90d8d261e604 --- /dev/null +++ b/sw/source/core/undo/unredln.cxx @@ -0,0 +1,541 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <UndoRedline.hxx> + +#include <hintids.hxx> +#include <unotools/charclass.hxx> +#include <doc.hxx> +#include <swundo.hxx> // fuer die UndoIds +#include <pam.hxx> +#include <ndtxt.hxx> +#include <UndoCore.hxx> +#include <UndoDelete.hxx> +#include <rolbck.hxx> +#include <redline.hxx> +#include <docary.hxx> +#include <sortopt.hxx> + +extern void lcl_JoinText( SwPaM& rPam, sal_Bool bJoinPrev ); +extern void lcl_GetJoinFlags( SwPaM& rPam, sal_Bool& rJoinTxt, sal_Bool& rJoinPrev ); + +//------------------------------------------------------------------ + +SwUndoRedline::SwUndoRedline( SwUndoId nUsrId, const SwPaM& rRange ) + : SwUndo( UNDO_REDLINE ), SwUndRng( rRange ), + pRedlData( 0 ), pRedlSaveData( 0 ), nUserId( nUsrId ), + bHiddenRedlines( sal_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() ); + } + + sal_uLong nEndExtra = rDoc.GetNodes().GetEndOfExtras().GetIndex(); + + pRedlSaveData = new SwRedlineSaveDatas; + if( !FillSaveData( rRange, *pRedlSaveData, sal_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; +} + +sal_uInt16 SwUndoRedline::GetRedlSaveCount() const +{ + return pRedlSaveData ? pRedlSaveData->Count() : 0; +} + + +void SwUndoRedline::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc *const pDoc = & rContext.GetDoc(); + SwPaM & rPam( AddUndoRedoPaM(rContext) ); + + UndoRedlineImpl(*pDoc, rPam); + + if( pRedlSaveData ) + { + sal_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(rPam, true); + } +} + + +void SwUndoRedline::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc *const pDoc = & rContext.GetDoc(); + RedlineMode_t eOld = pDoc->GetRedlineMode(); + pDoc->SetRedlineMode_intern((RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON )); + + SwPaM & rPam( AddUndoRedoPaM(rContext) ); + if( pRedlSaveData && bHiddenRedlines ) + { + sal_uLong nEndExtra = pDoc->GetNodes().GetEndOfExtras().GetIndex(); + FillSaveData(rPam, *pRedlSaveData, sal_False, + UNDO_REJECT_REDLINE != nUserId ); + + nEndExtra -= pDoc->GetNodes().GetEndOfExtras().GetIndex(); + nSttNode -= nEndExtra; + nEndNode -= nEndExtra; + } + + RedoRedlineImpl(*pDoc, rPam); + + SetPaM(rPam, true); + pDoc->SetRedlineMode_intern( eOld ); +} + +void SwUndoRedline::UndoRedlineImpl(SwDoc &, SwPaM &) +{ +} + +// default: remove redlines +void SwUndoRedline::RedoRedlineImpl(SwDoc & rDoc, SwPaM & rPam) +{ + rDoc.DeleteRedline(rPam, true, USHRT_MAX); +} + + +// SwUndoRedlineDelete /////////////////////////////////////////////////// + +SwUndoRedlineDelete::SwUndoRedlineDelete( const SwPaM& rRange, SwUndoId nUsrId ) + : SwUndoRedline( nUsrId = (nUsrId ? nUsrId : UNDO_DELETE), rRange ), + bCanGroup( sal_False ), bIsDelim( sal_False ), bIsBackspace( sal_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 = sal_True; + bIsDelim = !GetAppCharClass().isLetterNumeric( pTNd->GetTxt(), + nSttCntnt ); + bIsBackspace = nSttCntnt == rRange.GetPoint()->nContent.GetIndex(); + } + } + + bCacheComment = false; +} + +void SwUndoRedlineDelete::UndoRedlineImpl(SwDoc & rDoc, SwPaM & rPam) +{ + rDoc.DeleteRedline(rPam, true, USHRT_MAX); +} + +void SwUndoRedlineDelete::RedoRedlineImpl(SwDoc & rDoc, SwPaM & rPam) +{ + if (rPam.GetPoint() != rPam.GetMark()) + { + rDoc.AppendRedline( new SwRedline(*pRedlData, rPam), sal_False ); + } +} + +sal_Bool SwUndoRedlineDelete::CanGrouping( const SwUndoRedlineDelete& rNext ) +{ + sal_Bool bRet = sal_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 = sal_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::UndoRedlineImpl(SwDoc & rDoc, SwPaM & rPam) +{ + // rPam contains the sorted range + // aSaveRange contains copied (i.e. original) range + + SwPosition *const pStart = rPam.Start(); + SwPosition *const pEnd = rPam.End(); + + SwNodeIndex aPrevIdx( pStart->nNode, -1 ); + sal_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 + sal_uInt16 nFnd = rDoc.GetRedlinePos( + *rDoc.GetNodes()[ nSttNode + 1 ], + nsRedlineType_t::REDLINE_INSERT ); + OSL_ENSURE( USHRT_MAX != nFnd && nFnd+1 < rDoc.GetRedlineTbl().Count(), + "kein Insert Object gefunden" ); + ++nFnd; + rDoc.GetRedlineTbl()[nFnd]->Show( 1 ); + } + + { + SwPaM aTmp( *rPam.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(rPam); + + SwPaM *const pPam = & rPam; + 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(rPam); +} + +void SwUndoRedlineSort::RedoRedlineImpl(SwDoc & rDoc, SwPaM & rPam) +{ + SwPaM* pPam = &rPam; + SwPosition* pStart = pPam->Start(); + SwPosition* pEnd = pPam->End(); + + SwNodeIndex aPrevIdx( pStart->nNode, -1 ); + sal_uLong nOffsetTemp = pEnd->nNode.GetIndex() - pStart->nNode.GetIndex(); + xub_StrLen nCntStt = pStart->nContent.GetIndex(); + + rDoc.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::RepeatImpl(::sw::RepeatContext & rContext) +{ + rContext.GetDoc().SortText( rContext.GetRepeatPaM(), *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::SwUndoAcceptRedline( const SwPaM& rRange ) + : SwUndoRedline( UNDO_ACCEPT_REDLINE, rRange ) +{ +} + +void SwUndoAcceptRedline::RedoRedlineImpl(SwDoc & rDoc, SwPaM & rPam) +{ + rDoc.AcceptRedline(rPam, false); +} + +void SwUndoAcceptRedline::RepeatImpl(::sw::RepeatContext & rContext) +{ + rContext.GetDoc().AcceptRedline(rContext.GetRepeatPaM(), true); +} + +SwUndoRejectRedline::SwUndoRejectRedline( const SwPaM& rRange ) + : SwUndoRedline( UNDO_REJECT_REDLINE, rRange ) +{ +} + +void SwUndoRejectRedline::RedoRedlineImpl(SwDoc & rDoc, SwPaM & rPam) +{ + rDoc.RejectRedline(rPam, false); +} + +void SwUndoRejectRedline::RepeatImpl(::sw::RepeatContext & rContext) +{ + rContext.GetDoc().RejectRedline(rContext.GetRepeatPaM(), true); +} + +// SwUndoCompDoc ///////////////////////////////////////////////////////// + +SwUndoCompDoc::SwUndoCompDoc( const SwPaM& rRg, sal_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, sal_False, sal_True )) + delete pRedlSaveData, pRedlSaveData = 0; +} + +SwUndoCompDoc::~SwUndoCompDoc() +{ + delete pRedlData; + delete pUnDel; + delete pUnDel2; + delete pRedlSaveData; +} + +void SwUndoCompDoc::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc *const pDoc = & rContext.GetDoc(); + SwPaM *const pPam( & AddUndoRedoPaM(rContext) ); + + 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( sal_False ); + SwCntntNode* pCEndNd = pPam->GetCntntNode( sal_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(); + + sal_Bool bJoinTxt, bJoinPrev; + ::lcl_GetJoinFlags( *pPam, bJoinTxt, bJoinPrev ); + + pUnDel = new SwUndoDelete( *pPam, sal_False ); + + if( bJoinTxt ) + ::lcl_JoinText( *pPam, bJoinPrev ); + + if( pCSttNd && !pCEndNd) + { + // #112139# Do not step behind the end of content. + SwNode * pTmp = pPam->GetNode(sal_True); + if (pTmp) + { + SwNode * pEnd = pDoc->GetNodes().DocumentSectionEndNode(pTmp); + + if (pTmp != pEnd) + { + pPam->SetMark(); + pPam->GetPoint()->nNode++; + pPam->GetBound( sal_True ).nContent.Assign( 0, 0 ); + pPam->GetBound( sal_False ).nContent.Assign( 0, 0 ); + pUnDel2 = new SwUndoDelete( *pPam, sal_True ); + } + } + } + pPam->DeleteMark(); + } + else + { + if( IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() )) + { + pDoc->DeleteRedline( *pPam, true, USHRT_MAX ); + + if( pRedlSaveData ) + SetSaveData( *pDoc, *pRedlSaveData ); + } + SetPaM(*pPam, true); + } +} + +void SwUndoCompDoc::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc *const pDoc = & rContext.GetDoc(); + SwPaM *const pPam( & AddUndoRedoPaM(rContext) ); + + if( bInsert ) + { + 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->UndoImpl(rContext); + delete pUnDel2, pUnDel2 = 0; + } + pUnDel->UndoImpl(rContext); + 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(*pPam, true); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
\ No newline at end of file diff --git a/sw/source/core/undo/unsect.cxx b/sw/source/core/undo/unsect.cxx new file mode 100644 index 000000000000..dd9a6ce93c62 --- /dev/null +++ b/sw/source/core/undo/unsect.cxx @@ -0,0 +1,501 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <UndoSection.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 <UndoCore.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> + + +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() ) + { + sal_uInt16 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::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + + RemoveIdxFromSection( rDoc, m_nSectionNodePos ); + + SwSectionNode *const pNd = + rDoc.GetNodes()[ m_nSectionNodePos ]->GetSectionNode(); + OSL_ENSURE( 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 ); + } + + AddUndoRedoPaM(rContext); +} + +void SwUndoInsSection::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + SwPaM & rPam( AddUndoRedoPaM(rContext) ); + + const SwTOXBaseSection* pUpdateTOX = 0; + if (m_pTOXBase.get()) + { + pUpdateTOX = rDoc.InsertTableOf( *rPam.GetPoint(), + *m_pTOXBase, m_pAttrSet.get(), true); + } + else + { + rDoc.InsertSwSection(rPam, *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::RepeatImpl(::sw::RepeatContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + if (m_pTOXBase.get()) + { + rDoc.InsertTableOf(*rContext.GetRepeatPaM().GetPoint(), + *m_pTOXBase, m_pAttrSet.get(), true); + } + else + { + rDoc.InsertSwSection(rContext.GetRepeatPaM(), + *m_pSectionData, 0, m_pAttrSet.get()); + } +} + +void SwUndoInsSection::Join( SwDoc& rDoc, sal_uLong nNode ) +{ + SwNodeIndex aIdx( rDoc.GetNodes(), nNode ); + SwTxtNode* pTxtNd = aIdx.GetNode().GetTxtNode(); + OSL_ENSURE( 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; + sal_uLong const m_nStartNode; + sal_uLong const m_nEndNode; + +public: + SwUndoDelSection( + SwSectionFmt const&, SwSection const&, SwNodeIndex const*const); + + virtual ~SwUndoDelSection(); + + virtual void UndoImpl( ::sw::UndoRedoContext & ); + virtual void RedoImpl( ::sw::UndoRedoContext & ); +}; + +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::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.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::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + + SwSectionNode *const pNd = + rDoc.GetNodes()[ m_nStartNode ]->GetSectionNode(); + OSL_ENSURE( 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; + sal_uLong const m_nStartNode; + bool const m_bOnlyAttrChanged; + +public: + SwUndoUpdateSection( + SwSection const&, SwNodeIndex const*const, bool const bOnlyAttr); + + virtual ~SwUndoUpdateSection(); + + virtual void UndoImpl( ::sw::UndoRedoContext & ); + virtual void RedoImpl( ::sw::UndoRedoContext & ); +}; + +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::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + SwSectionNode *const pSectNd = + rDoc.GetNodes()[ m_nStartNode ]->GetSectionNode(); + OSL_ENSURE( 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, sal_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::RedoImpl(::sw::UndoRedoContext & rContext) +{ + UndoImpl(rContext); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/undo/unsort.cxx b/sw/source/core/undo/unsort.cxx new file mode 100644 index 000000000000..1b72dba58572 --- /dev/null +++ b/sw/source/core/undo/unsort.cxx @@ -0,0 +1,282 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <UndoSort.hxx> + +#include <doc.hxx> +#include <swundo.hxx> // fuer die UndoIds +#include <pam.hxx> +#include <swtable.hxx> +#include <ndtxt.hxx> +#include <UndoCore.hxx> +#include <UndoTable.hxx> +#include <sortopt.hxx> +#include <docsort.hxx> +#include <redline.hxx> +#include <node2lay.hxx> + + +/*-------------------------------------------------------------------- + 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( sal_uLong nStt, sal_uLong nEnd, const SwTableNode& rTblNd, + const SwSortOptions& rOpt, sal_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::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + if(pSortOpt->bTable) + { + // Undo Tabelle + RemoveIdxFromSection( rDoc, nSttNode, &nEndNode ); + + if( pUndoTblAttr ) + { + pUndoTblAttr->UndoImpl(rContext); + } + + 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( sal_uInt16 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 sal_uLong nIdx = pTblNd->GetIndex(); + aNode2Layout.RestoreUpperFrms( rDoc.GetNodes(), nIdx, nIdx + 1 ); + // <-- + } + else + { + // Undo Text + SwPaM & rPam( AddUndoRedoPaM(rContext) ); + RemoveIdxFromRange(rPam, true); + + // fuer die sorted Positions einen Index anlegen. + // JP 25.11.97: Die IndexList muss aber nach SourcePosition + // aufsteigend sortiert aufgebaut werden + SwUndoSortList aIdxList( (sal_uInt8)aSortList.Count() ); + sal_uInt16 i; + + for( i = 0; i < aSortList.Count(); ++i) + for( sal_uInt16 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(rPam, true); + } +} + +void SwUndoSort::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.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(sal_uInt16 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->RedoImpl(rContext); + } + + // 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 sal_uLong nIdx = pTblNd->GetIndex(); + aNode2Layout.RestoreUpperFrms( rDoc.GetNodes(), nIdx, nIdx + 1 ); + // <-- + } + else + { + // Redo for Text + SwPaM & rPam( AddUndoRedoPaM(rContext) ); + SetPaM(rPam); + RemoveIdxFromRange(rPam, true); + + SwUndoSortList aIdxList( (sal_uInt8)aSortList.Count() ); + sal_uInt16 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(rPam, true); + SwTxtNode const*const pTNd = rPam.GetNode()->GetTxtNode(); + if( pTNd ) + { + rPam.GetPoint()->nContent = pTNd->GetTxt().Len(); + } + } +} + +void SwUndoSort::RepeatImpl(::sw::RepeatContext & rContext) +{ + // table not repeat capable + if(!pSortOpt->bTable) + { + SwPaM *const pPam = & rContext.GetRepeatPaM(); + SwDoc& rDoc = *pPam->GetDoc(); + + if( !rDoc.IsIdxInTbl( pPam->Start()->nNode ) ) + rDoc.SortText(*pPam, *pSortOpt); + } +} + +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( sal_uLong nOrgPos, sal_uLong nNewPos) +{ + SwSortUndoElement* pEle = new SwSortUndoElement(nOrgPos, nNewPos); + aSortList.C40_INSERT( SwSortUndoElement, pEle, aSortList.Count() ); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
\ No newline at end of file diff --git a/sw/source/core/undo/unspnd.cxx b/sw/source/core/undo/unspnd.cxx new file mode 100644 index 000000000000..317d1baa4652 --- /dev/null +++ b/sw/source/core/undo/unspnd.cxx @@ -0,0 +1,206 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <UndoSplitMove.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 <UndoCore.hxx> +#include "rolbck.hxx" +#include "redline.hxx" +#include "docary.hxx" +#include <IShellCursorSupplier.hxx> + + +//------------------------------------------------------------------ + +// SPLITNODE + + +SwUndoSplitNode::SwUndoSplitNode( SwDoc* pDoc, const SwPosition& rPos, + sal_Bool bChkTable ) + : SwUndo( UNDO_SPLITNODE ), pHistory( 0 ), pRedlData( 0 ), nNode( rPos.nNode.GetIndex() ), + nCntnt( rPos.nContent.GetIndex() ), + bTblFlag( sal_False ), bChkTblStt( bChkTable ) +{ + SwTxtNode *const pTxtNd = rPos.nNode.GetNode().GetTxtNode(); + OSL_ENSURE( 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::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc *const pDoc = & rContext.GetDoc(); + SwPaM & rPam( rContext.GetCursorSupplier().CreateNewShellCursor() ); + 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, sal_False, + &pItem ) ) + pTableFmt->SetFmtAttr( *pItem ); + + if( SFX_ITEM_SET == pNdSet->GetItemState( RES_BREAK, sal_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, sal_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::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwPaM & rPam( rContext.GetCursorSupplier().CreateNewShellCursor() ); + rPam.GetPoint()->nNode = nNode; + SwTxtNode * pTNd = rPam.GetNode()->GetTxtNode(); + OSL_ENSURE(pTNd, "SwUndoSplitNode::RedoImpl(): SwTxtNode expected"); + if (pTNd) + { + 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(); + } + } +} + +void SwUndoSplitNode::RepeatImpl(::sw::RepeatContext & rContext) +{ + rContext.GetDoc().SplitNode( + *rContext.GetRepeatPaM().GetPoint(), bChkTblStt ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/undo/untbl.cxx b/sw/source/core/undo/untbl.cxx new file mode 100644 index 000000000000..ee16891ab5e1 --- /dev/null +++ b/sw/source/core/undo/untbl.cxx @@ -0,0 +1,3269 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <UndoTable.hxx> + +#include <UndoRedline.hxx> +#include <UndoDelete.hxx> +#include <UndoSplitMove.hxx> +#include <UndoCore.hxx> +#include <hintids.hxx> +#include <hints.hxx> +#include <editeng/brkitem.hxx> +#include <fmtornt.hxx> +#include <fmtpdsc.hxx> +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <editsh.hxx> +#include <docary.hxx> +#include <ndtxt.hxx> +#include <swtable.hxx> +#include <pam.hxx> +#include <cntfrm.hxx> +#include <tblsel.hxx> +#include <swundo.hxx> // fuer die UndoIds +#include <rolbck.hxx> +#include <ddefld.hxx> +#include <tabcol.hxx> +#include <tabfrm.hxx> +#include <rowfrm.hxx> +#include <cellfrm.hxx> +#include <swcache.hxx> +#include <tblafmt.hxx> +#include <poolfmt.hxx> +#include <mvsave.hxx> +#include <cellatr.hxx> +#include <swtblfmt.hxx> +#include <swddetbl.hxx> +#include <redline.hxx> +#include <node2lay.hxx> +#include <tblrwcl.hxx> +#include <fmtanchr.hxx> +#include <comcore.hrc> +#include <unochart.hxx> +#include <switerator.hxx> + +#if OSL_DEBUG_LEVEL > 1 +#define CHECK_TABLE(t) (t).CheckConsistency(); +#else +#define CHECK_TABLE(t) +#endif + +#if OSL_DEBUG_LEVEL > 1 + void lcl_DebugRedline( const SwDoc* pDoc ); + #define _DEBUG_REDLINE( pDoc ) lcl_DebugRedline( pDoc ); +#else + #define _DEBUG_REDLINE( pDoc ) +#endif + +extern void ClearFEShellTabCols(); + +typedef SfxItemSet* SfxItemSetPtr; +SV_DECL_PTRARR_DEL( SfxItemSets, SfxItemSetPtr, 10, 5 ) + +typedef SwUndoSaveSection* SwUndoSaveSectionPtr; +SV_DECL_PTRARR_DEL( SwUndoSaveSections, SwUndoSaveSectionPtr, 0, 10 ) + +typedef SwUndoMove* SwUndoMovePtr; +SV_DECL_PTRARR_DEL( SwUndoMoves, SwUndoMovePtr, 0, 10 ) + +struct SwTblToTxtSave; +typedef SwTblToTxtSave* SwTblToTxtSavePtr; +SV_DECL_PTRARR_DEL( SwTblToTxtSaves, SwTblToTxtSavePtr, 0, 10 ) + +struct _UndoTblCpyTbl_Entry +{ + sal_uLong nBoxIdx, nOffset; + SfxItemSet* pBoxNumAttr; + SwUndo* pUndo; + + // Was the last paragraph of the new and the first paragraph of the old content joined? + bool bJoin; // For redlining only + + _UndoTblCpyTbl_Entry( const SwTableBox& rBox ); + ~_UndoTblCpyTbl_Entry(); +}; +typedef _UndoTblCpyTbl_Entry* _UndoTblCpyTbl_EntryPtr; +SV_DECL_PTRARR_DEL( _UndoTblCpyTbl_Entries, _UndoTblCpyTbl_EntryPtr, 0, 10 ) + +class _SaveBox; +class _SaveLine; + +class _SaveTable +{ + friend class _SaveBox; + friend class _SaveLine; + SfxItemSet aTblSet; + _SaveLine* pLine; + const SwTable* pSwTable; + SfxItemSets aSets; + SwFrmFmts aFrmFmts; + sal_uInt16 nLineCount; + sal_Bool bModifyBox : 1; + sal_Bool bSaveFormula : 1; + sal_Bool bNewModel : 1; + +public: + _SaveTable( const SwTable& rTbl, sal_uInt16 nLnCnt = USHRT_MAX, + sal_Bool bSaveFml = sal_True ); + ~_SaveTable(); + + sal_uInt16 AddFmt( SwFrmFmt* pFmt, bool bIsLine ); + void NewFrmFmt( const SwTableLine* , const SwTableBox*, sal_uInt16 nFmtPos, + SwFrmFmt* pOldFmt ); + + void RestoreAttr( SwTable& rTbl, sal_Bool bModifyBox = sal_False ); + void SaveCntntAttrs( SwDoc* pDoc ); + void CreateNew( SwTable& rTbl, sal_Bool bCreateFrms = sal_True, + sal_Bool bRestoreChart = sal_True ); + sal_Bool IsNewModel() const { return bNewModel; } +}; + +class _SaveLine +{ + friend class _SaveTable; + friend class _SaveBox; + + _SaveLine* pNext; + _SaveBox* pBox; + sal_uInt16 nItemSet; + +public: + + _SaveLine( _SaveLine* pPrev, const SwTableLine& rLine, _SaveTable& rSTbl ); + ~_SaveLine(); + + void RestoreAttr( SwTableLine& rLine, _SaveTable& rSTbl ); + void SaveCntntAttrs( SwDoc* pDoc ); + + void CreateNew( SwTable& rTbl, SwTableBox& rParent, _SaveTable& rSTbl ); +}; + +class _SaveBox +{ + friend class _SaveLine; + + _SaveBox* pNext; + sal_uLong nSttNode; + long nRowSpan; + sal_uInt16 nItemSet; + union + { + SfxItemSets* pCntntAttrs; + _SaveLine* pLine; + } Ptrs; + +public: + _SaveBox( _SaveBox* pPrev, const SwTableBox& rBox, _SaveTable& rSTbl ); + ~_SaveBox(); + + void RestoreAttr( SwTableBox& rBox, _SaveTable& rSTbl ); + void SaveCntntAttrs( SwDoc* pDoc ); + + void CreateNew( SwTable& rTbl, SwTableLine& rParent, _SaveTable& rSTbl ); +}; + +void InsertSort( SvUShorts& rArr, sal_uInt16 nIdx, sal_uInt16* pInsPos = 0 ); +void InsertSort( SvULongs& rArr, sal_uLong nIdx, sal_uInt16* pInsPos = 0 ); + +#if OSL_DEBUG_LEVEL > 1 +#include "shellio.hxx" +void CheckTable( const SwTable& ); +#define CHECKTABLE(t) CheckTable( t ); +#else +#define CHECKTABLE(t) +#endif + +/* #130880: Crash in undo of table to text when the table has (freshly) merged cells +The order of cell content nodes in the nodes array is not given by the recursive table structure. +The algorithmn must not rely on this even it holds for a fresh loaded table in odt file format. +So we need to remember not only the start node position but the end node position as well. +*/ + +struct SwTblToTxtSave +{ + sal_uLong m_nSttNd; + sal_uLong m_nEndNd; + xub_StrLen m_nCntnt; + SwHistory* m_pHstry; + // metadata references for first and last paragraph in cell + ::boost::shared_ptr< ::sfx2::MetadatableUndo > m_pMetadataUndoStart; + ::boost::shared_ptr< ::sfx2::MetadatableUndo > m_pMetadataUndoEnd; + + SwTblToTxtSave( SwDoc& rDoc, sal_uLong nNd, sal_uLong nEndIdx, xub_StrLen nCntnt ); + ~SwTblToTxtSave() { delete m_pHstry; } +}; + +SV_IMPL_PTRARR( SfxItemSets, SfxItemSetPtr ) +SV_IMPL_PTRARR( SwUndoSaveSections, SwUndoSaveSectionPtr ) +SV_IMPL_PTRARR( SwUndoMoves, SwUndoMovePtr ) +SV_IMPL_PTRARR( SwTblToTxtSaves, SwTblToTxtSavePtr ) +SV_IMPL_PTRARR( _UndoTblCpyTbl_Entries, _UndoTblCpyTbl_EntryPtr ) + +sal_uInt16 aSave_BoxCntntSet[] = { + RES_CHRATR_COLOR, RES_CHRATR_CROSSEDOUT, + RES_CHRATR_FONT, RES_CHRATR_FONTSIZE, + RES_CHRATR_POSTURE, RES_CHRATR_POSTURE, + RES_CHRATR_SHADOWED, RES_CHRATR_WEIGHT, + RES_PARATR_ADJUST, RES_PARATR_ADJUST, + 0 }; + + + +SwUndoInsTbl::SwUndoInsTbl( const SwPosition& rPos, sal_uInt16 nCl, sal_uInt16 nRw, + sal_uInt16 nAdj, const SwInsertTableOptions& rInsTblOpts, + const SwTableAutoFmt* pTAFmt, + const SvUShorts* pColArr, + const String & rName) + : SwUndo( UNDO_INSTABLE ), + aInsTblOpts( rInsTblOpts ), pDDEFldType( 0 ), pColWidth( 0 ), pRedlData( 0 ), pAutoFmt( 0 ), + nSttNode( rPos.nNode.GetIndex() ), nRows( nRw ), nCols( nCl ), nAdjust( nAdj ) +{ + if( pColArr ) + { + pColWidth = new SvUShorts( 0, 1 ); + pColWidth->Insert( pColArr, 0 ); + } + if( pTAFmt ) + pAutoFmt = new SwTableAutoFmt( *pTAFmt ); + + // Redline beachten + SwDoc& rDoc = *rPos.nNode.GetNode().GetDoc(); + if( rDoc.IsRedlineOn() ) + { + pRedlData = new SwRedlineData( nsRedlineType_t::REDLINE_INSERT, rDoc.GetRedlineAuthor() ); + SetRedlineMode( rDoc.GetRedlineMode() ); + } + + sTblNm = rName; +} + + +SwUndoInsTbl::~SwUndoInsTbl() +{ + delete pDDEFldType; + delete pColWidth; + delete pRedlData; + delete pAutoFmt; +} + +void SwUndoInsTbl::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + SwNodeIndex aIdx( rDoc.GetNodes(), nSttNode ); + + SwTableNode* pTblNd = aIdx.GetNode().GetTableNode(); + OSL_ENSURE( pTblNd, "kein TabellenNode" ); + pTblNd->DelFrms(); + + if( IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() )) + rDoc.DeleteRedline( *pTblNd, true, USHRT_MAX ); + RemoveIdxFromSection( rDoc, nSttNode ); + + // harte SeitenUmbrueche am nachfolgenden Node verschieben + SwCntntNode* pNextNd = rDoc.GetNodes()[ pTblNd->EndOfSectionIndex()+1 ]->GetCntntNode(); + if( pNextNd ) + { + SwFrmFmt* pTableFmt = pTblNd->GetTable().GetFrmFmt(); + const SfxPoolItem *pItem; + + if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_PAGEDESC, + sal_False, &pItem ) ) + pNextNd->SetAttr( *pItem ); + + if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_BREAK, + sal_False, &pItem ) ) + pNextNd->SetAttr( *pItem ); + } + + + sTblNm = pTblNd->GetTable().GetFrmFmt()->GetName(); + if( pTblNd->GetTable().IsA( TYPE( SwDDETable )) ) + pDDEFldType = (SwDDEFieldType*)((SwDDETable&)pTblNd->GetTable()). + GetDDEFldType()->Copy(); + + rDoc.GetNodes().Delete( aIdx, pTblNd->EndOfSectionIndex() - + aIdx.GetIndex() + 1 ); + + SwPaM & rPam( rContext.GetCursorSupplier().CreateNewShellCursor() ); + rPam.DeleteMark(); + rPam.GetPoint()->nNode = aIdx; + rPam.GetPoint()->nContent.Assign( rPam.GetCntntNode(), 0 ); +} + + +void SwUndoInsTbl::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + + SwPosition const aPos(SwNodeIndex(rDoc.GetNodes(), nSttNode)); + const SwTable* pTbl = rDoc.InsertTable( aInsTblOpts, aPos, nRows, nCols, + nAdjust, + pAutoFmt, pColWidth ); + ((SwFrmFmt*)pTbl->GetFrmFmt())->SetName( sTblNm ); + SwTableNode* pTblNode = (SwTableNode*)rDoc.GetNodes()[nSttNode]->GetTableNode(); + + if( pDDEFldType ) + { + SwDDEFieldType* pNewType = (SwDDEFieldType*)rDoc.InsertFldType( + *pDDEFldType); + SwDDETable* pDDETbl = new SwDDETable( pTblNode->GetTable(), pNewType ); + pTblNode->SetNewTable( pDDETbl ); // setze die DDE-Tabelle + delete pDDEFldType, pDDEFldType = 0; + } + + if( (pRedlData && IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() )) || + ( !( nsRedlineMode_t::REDLINE_IGNORE & GetRedlineMode() ) && + rDoc.GetRedlineTbl().Count() )) + { + SwPaM aPam( *pTblNode->EndOfSectionNode(), *pTblNode, 1 ); + SwCntntNode* pCNd = aPam.GetCntntNode( sal_False ); + if( pCNd ) + aPam.GetMark()->nContent.Assign( pCNd, 0 ); + + if( pRedlData && IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() ) ) + { + RedlineMode_t eOld = rDoc.GetRedlineMode(); + rDoc.SetRedlineMode_intern((RedlineMode_t)(eOld & ~nsRedlineMode_t::REDLINE_IGNORE)); + + rDoc.AppendRedline( new SwRedline( *pRedlData, aPam ), true); + rDoc.SetRedlineMode_intern( eOld ); + } + else + rDoc.SplitRedline( aPam ); + } +} + + +void SwUndoInsTbl::RepeatImpl(::sw::RepeatContext & rContext) +{ + rContext.GetDoc().InsertTable( + aInsTblOpts, *rContext.GetRepeatPaM().GetPoint(), + nRows, nCols, nAdjust, pAutoFmt, pColWidth ); +} + +SwRewriter SwUndoInsTbl::GetRewriter() const +{ + SwRewriter aRewriter; + + aRewriter.AddRule(UNDO_ARG1, SW_RES(STR_START_QUOTE)); + aRewriter.AddRule(UNDO_ARG2, sTblNm); + aRewriter.AddRule(UNDO_ARG3, SW_RES(STR_END_QUOTE)); + + return aRewriter; +} + +// ----------------------------------------------------- + +SwTblToTxtSave::SwTblToTxtSave( SwDoc& rDoc, sal_uLong nNd, sal_uLong nEndIdx, xub_StrLen nCnt ) + : m_nSttNd( nNd ), m_nEndNd( nEndIdx), m_nCntnt( nCnt ), m_pHstry( 0 ) +{ + // Attributierung des gejointen Node merken. + SwTxtNode* pNd = rDoc.GetNodes()[ nNd ]->GetTxtNode(); + if( pNd ) + { + m_pHstry = new SwHistory; + + m_pHstry->Add( pNd->GetTxtColl(), nNd, ND_TEXTNODE ); + if ( pNd->GetpSwpHints() ) + { + m_pHstry->CopyAttr( pNd->GetpSwpHints(), nNd, 0, + pNd->GetTxt().Len(), false ); + } + if( pNd->HasSwAttrSet() ) + m_pHstry->CopyFmtAttr( *pNd->GetpSwAttrSet(), nNd ); + + if( !m_pHstry->Count() ) + delete m_pHstry, m_pHstry = 0; + + // METADATA: store + m_pMetadataUndoStart = pNd->CreateUndo(); + } + + // we also need to store the metadata reference of the _last_ paragraph + // we subtract 1 to account for the removed cell start/end node pair + // (after SectionUp, the end of the range points to the node after the cell) + if ( nEndIdx - 1 > nNd ) + { + SwTxtNode* pLastNode( rDoc.GetNodes()[ nEndIdx - 1 ]->GetTxtNode() ); + if( pLastNode ) + { + // METADATA: store + m_pMetadataUndoEnd = pLastNode->CreateUndo(); + } + } +} + +SwUndoTblToTxt::SwUndoTblToTxt( const SwTable& rTbl, sal_Unicode cCh ) + : SwUndo( UNDO_TABLETOTEXT ), + sTblNm( rTbl.GetFrmFmt()->GetName() ), pDDEFldType( 0 ), pHistory( 0 ), + nSttNd( 0 ), nEndNd( 0 ), + nAdjust( static_cast<sal_uInt16>(rTbl.GetFrmFmt()->GetHoriOrient().GetHoriOrient()) ), + cTrenner( cCh ), nHdlnRpt( rTbl.GetRowsToRepeat() ) +{ + pTblSave = new _SaveTable( rTbl ); + pBoxSaves = new SwTblToTxtSaves( (sal_uInt8)rTbl.GetTabSortBoxes().Count() ); + + if( rTbl.IsA( TYPE( SwDDETable ) ) ) + pDDEFldType = (SwDDEFieldType*)((SwDDETable&)rTbl).GetDDEFldType()->Copy(); + + bCheckNumFmt = rTbl.GetFrmFmt()->GetDoc()->IsInsTblFormatNum(); + + pHistory = new SwHistory; + const SwTableNode* pTblNd = rTbl.GetTableNode(); + sal_uLong nTblStt = pTblNd->GetIndex(), nTblEnd = pTblNd->EndOfSectionIndex(); + + const SwSpzFrmFmts& rFrmFmtTbl = *pTblNd->GetDoc()->GetSpzFrmFmts(); + for( sal_uInt16 n = 0; n < rFrmFmtTbl.Count(); ++n ) + { + SwFrmFmt* pFmt = rFrmFmtTbl[ n ]; + SwFmtAnchor const*const pAnchor = &pFmt->GetAnchor(); + SwPosition const*const pAPos = pAnchor->GetCntntAnchor(); + if (pAPos && + ((FLY_AT_CHAR == pAnchor->GetAnchorId()) || + (FLY_AT_PARA == pAnchor->GetAnchorId())) && + nTblStt <= pAPos->nNode.GetIndex() && + pAPos->nNode.GetIndex() < nTblEnd ) + { + pHistory->Add( *pFmt ); + } + } + + if( !pHistory->Count() ) + delete pHistory, pHistory = 0; +} + + +SwUndoTblToTxt::~SwUndoTblToTxt() +{ + delete pDDEFldType; + delete pTblSave; + delete pBoxSaves; + delete pHistory; +} + + + +void SwUndoTblToTxt::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor()); + + SwNodeIndex aFrmIdx( rDoc.GetNodes(), nSttNd ); + SwNodeIndex aEndIdx( rDoc.GetNodes(), nEndNd ); + + pPam->GetPoint()->nNode = aFrmIdx; + pPam->SetMark(); + pPam->GetPoint()->nNode = aEndIdx; + rDoc.DelNumRules( *pPam ); + pPam->DeleteMark(); + + // dann sammel mal alle Uppers ein + SwNode2Layout aNode2Layout( aFrmIdx.GetNode() ); + + // erzeuge die TabelleNode Structur + SwTableNode* pTblNd = rDoc.GetNodes().UndoTableToText( nSttNd, nEndNd, *pBoxSaves ); + pTblNd->GetTable().SetTableModel( pTblSave->IsNewModel() ); + SwTableFmt* pTableFmt = rDoc.MakeTblFrmFmt( sTblNm, rDoc.GetDfltFrmFmt() ); + pTblNd->GetTable().RegisterToFormat( *pTableFmt ); + pTblNd->GetTable().SetRowsToRepeat( nHdlnRpt ); + + // erzeuge die alte Tabellen Struktur + pTblSave->CreateNew( pTblNd->GetTable() ); + + if( pDDEFldType ) + { + SwDDEFieldType* pNewType = (SwDDEFieldType*)rDoc.InsertFldType( + *pDDEFldType); + SwDDETable* pDDETbl = new SwDDETable( pTblNd->GetTable(), pNewType ); + pTblNd->SetNewTable( pDDETbl, sal_False ); // setze die DDE-Tabelle + delete pDDEFldType, pDDEFldType = 0; + } + + if( bCheckNumFmt ) + { + SwTableSortBoxes& rBxs = pTblNd->GetTable().GetTabSortBoxes(); + for( sal_uInt16 nBoxes = rBxs.Count(); nBoxes; ) + rDoc.ChkBoxNumFmt( *rBxs[ --nBoxes ], sal_False ); + } + + if( pHistory ) + { + sal_uInt16 nTmpEnd = pHistory->GetTmpEnd(); + pHistory->TmpRollback( &rDoc, 0 ); + pHistory->SetTmpEnd( nTmpEnd ); + } + + aNode2Layout.RestoreUpperFrms( rDoc.GetNodes(), + pTblNd->GetIndex(), pTblNd->GetIndex()+1 ); + + // will man eine TabellenSelektion ?? + pPam->DeleteMark(); + pPam->GetPoint()->nNode = *pTblNd->EndOfSectionNode(); + pPam->SetMark(); + pPam->GetPoint()->nNode = *pPam->GetNode()->StartOfSectionNode(); + pPam->Move( fnMoveForward, fnGoCntnt ); + pPam->Exchange(); + pPam->Move( fnMoveBackward, fnGoCntnt ); + + ClearFEShellTabCols(); +} + + // steht im untbl.cxx und darf nur vom Undoobject gerufen werden +SwTableNode* SwNodes::UndoTableToText( sal_uLong nSttNd, sal_uLong nEndNd, + const SwTblToTxtSaves& rSavedData ) +{ + SwNodeIndex aSttIdx( *this, nSttNd ); + SwNodeIndex aEndIdx( *this, nEndNd+1 ); + + SwTableNode * pTblNd = new SwTableNode( aSttIdx ); + SwEndNode* pEndNd = new SwEndNode( aEndIdx, *pTblNd ); + + aEndIdx = *pEndNd; + + /* Set pTblNd as start of section for all nodes in [nSttNd, nEndNd]. + Delete all Frames attached to the nodes in that range. */ + SwNode* pNd; + { + sal_uLong n, nTmpEnd = aEndIdx.GetIndex(); + for( n = pTblNd->GetIndex() + 1; n < nTmpEnd; ++n ) + { + if( ( pNd = (*this)[ n ] )->IsCntntNode() ) + ((SwCntntNode*)pNd)->DelFrms(); + pNd->pStartOfSection = pTblNd; + } + } + + // dann die Tabellen Struktur teilweise aufbauen. Erstmal eine Line + // in der alle Boxen stehen! Die korrekte Struktur kommt dann aus der + // SaveStruct + SwTableBoxFmt* pBoxFmt = GetDoc()->MakeTableBoxFmt(); + SwTableLineFmt* pLineFmt = GetDoc()->MakeTableLineFmt(); + SwTableLine* pLine = new SwTableLine( pLineFmt, rSavedData.Count(), 0 ); + pTblNd->GetTable().GetTabLines().C40_INSERT( SwTableLine, pLine, 0 ); + + SvULongs aBkmkArr( 0, 4 ); + for( sal_uInt16 n = rSavedData.Count(); n; ) + { + SwTblToTxtSave* pSave = rSavedData[ --n ]; + // if the start node was merged with last from prev. cell, + // subtract 1 from index to get the merged paragraph, and split that + aSttIdx = pSave->m_nSttNd - ( ( USHRT_MAX != pSave->m_nCntnt ) ? 1 : 0); + SwTxtNode* pTxtNd = aSttIdx.GetNode().GetTxtNode(); + + if( USHRT_MAX != pSave->m_nCntnt ) + { + // an der ContentPosition splitten, das vorherige Zeichen + // loeschen (ist der Trenner!) + OSL_ENSURE( pTxtNd, "Wo ist der TextNode geblieben?" ); + SwIndex aCntPos( pTxtNd, pSave->m_nCntnt - 1 ); + + pTxtNd->EraseText( aCntPos, 1 ); + SwCntntNode* pNewNd = pTxtNd->SplitCntntNode( + SwPosition( aSttIdx, aCntPos )); + if( aBkmkArr.Count() ) + _RestoreCntntIdx( aBkmkArr, *pNewNd, pSave->m_nCntnt, + pSave->m_nCntnt + 1 ); + } + else + { + if( aBkmkArr.Count() ) + aBkmkArr.Remove( 0, aBkmkArr.Count() ); + if( pTxtNd ) + _SaveCntntIdx( GetDoc(), aSttIdx.GetIndex(), + pTxtNd->GetTxt().Len(), aBkmkArr ); + } + + if( pTxtNd ) + { + // METADATA: restore + pTxtNd->GetTxtNode()->RestoreMetadata(pSave->m_pMetadataUndoStart); + if( pTxtNd->HasSwAttrSet() ) + pTxtNd->ResetAllAttr(); + + if( pTxtNd->GetpSwpHints() ) + pTxtNd->ClearSwpHintsArr( false ); + } + + if( pSave->m_pHstry ) + { + sal_uInt16 nTmpEnd = pSave->m_pHstry->GetTmpEnd(); + pSave->m_pHstry->TmpRollback( GetDoc(), 0 ); + pSave->m_pHstry->SetTmpEnd( nTmpEnd ); + } + + // METADATA: restore + // end points to node after cell + if ( pSave->m_nEndNd - 1 > pSave->m_nSttNd ) + { + SwTxtNode* pLastNode = (*this)[ pSave->m_nEndNd - 1 ]->GetTxtNode(); + if (pLastNode) + { + pLastNode->RestoreMetadata(pSave->m_pMetadataUndoEnd); + } + } + + aEndIdx = pSave->m_nEndNd; + SwStartNode* pSttNd = new SwStartNode( aSttIdx, ND_STARTNODE, + SwTableBoxStartNode ); + pSttNd->pStartOfSection = pTblNd; + new SwEndNode( aEndIdx, *pSttNd ); + + for( sal_uLong i = aSttIdx.GetIndex(); i < aEndIdx.GetIndex()-1; ++i ) + { + pNd = (*this)[ i ]; + pNd->pStartOfSection = pSttNd; + if( pNd->IsStartNode() ) + i = pNd->EndOfSectionIndex(); + } + + SwTableBox* pBox = new SwTableBox( pBoxFmt, *pSttNd, pLine ); + pLine->GetTabBoxes().C40_INSERT( SwTableBox, pBox, 0 ); + } + return pTblNd; +} + + +void SwUndoTblToTxt::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor()); + + pPam->GetPoint()->nNode = nSttNd; + pPam->GetPoint()->nContent.Assign( 0, 0 ); + SwNodeIndex aSaveIdx( pPam->GetPoint()->nNode, -1 ); + + pPam->SetMark(); // alle Indizies abmelden + pPam->DeleteMark(); + + SwTableNode* pTblNd = pPam->GetNode()->GetTableNode(); + OSL_ENSURE( pTblNd, "keinen TableNode gefunden" ); + + if( pTblNd->GetTable().IsA( TYPE( SwDDETable )) ) + pDDEFldType = (SwDDEFieldType*)((SwDDETable&)pTblNd->GetTable()). + GetDDEFldType()->Copy(); + + rDoc.TableToText( pTblNd, cTrenner ); + + aSaveIdx++; + SwCntntNode* pCNd = aSaveIdx.GetNode().GetCntntNode(); + if( !pCNd && 0 == ( pCNd = rDoc.GetNodes().GoNext( &aSaveIdx ) ) && + 0 == ( pCNd = rDoc.GetNodes().GoPrevious( &aSaveIdx )) ) + { + OSL_FAIL( "wo steht denn nun der TextNode" ); + } + + pPam->GetPoint()->nNode = aSaveIdx; + pPam->GetPoint()->nContent.Assign( pCNd, 0 ); + + pPam->SetMark(); // alle Indizies abmelden + pPam->DeleteMark(); +} + + +void SwUndoTblToTxt::RepeatImpl(::sw::RepeatContext & rContext) +{ + SwPaM *const pPam = & rContext.GetRepeatPaM(); + SwTableNode *const pTblNd = pPam->GetNode()->FindTableNode(); + if( pTblNd ) + { + // move cursor out of table + pPam->GetPoint()->nNode = *pTblNd->EndOfSectionNode(); + pPam->Move( fnMoveForward, fnGoCntnt ); + pPam->SetMark(); + pPam->DeleteMark(); + + rContext.GetDoc().TableToText( pTblNd, cTrenner ); + } +} + +void SwUndoTblToTxt::SetRange( const SwNodeRange& rRg ) +{ + nSttNd = rRg.aStart.GetIndex(); + nEndNd = rRg.aEnd.GetIndex(); +} + +void SwUndoTblToTxt::AddBoxPos( SwDoc& rDoc, sal_uLong nNdIdx, sal_uLong nEndIdx, xub_StrLen nCntntIdx ) +{ + SwTblToTxtSave* pNew = new SwTblToTxtSave( rDoc, nNdIdx, nEndIdx, nCntntIdx ); + pBoxSaves->Insert( pNew, pBoxSaves->Count() ); +} + +// ----------------------------------------------------- + +SwUndoTxtToTbl::SwUndoTxtToTbl( const SwPaM& rRg, + const SwInsertTableOptions& rInsTblOpts, + sal_Unicode cCh, sal_uInt16 nAdj, + const SwTableAutoFmt* pAFmt ) + : SwUndo( UNDO_TEXTTOTABLE ), SwUndRng( rRg ), aInsTblOpts( rInsTblOpts ), + pDelBoxes( 0 ), pAutoFmt( 0 ), + pHistory( 0 ), cTrenner( cCh ), nAdjust( nAdj ) +{ + if( pAFmt ) + pAutoFmt = new SwTableAutoFmt( *pAFmt ); + + const SwPosition* pEnd = rRg.End(); + SwNodes& rNds = rRg.GetDoc()->GetNodes(); + bSplitEnd = pEnd->nContent.GetIndex() && ( pEnd->nContent.GetIndex() + != pEnd->nNode.GetNode().GetCntntNode()->Len() || + pEnd->nNode.GetIndex() >= rNds.GetEndOfContent().GetIndex()-1 ); +} + +SwUndoTxtToTbl::~SwUndoTxtToTbl() +{ + delete pDelBoxes; + delete pAutoFmt; +} + +void SwUndoTxtToTbl::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + + sal_uLong nTblNd = nSttNode; + if( nSttCntnt ) + ++nTblNd; // Node wurde vorher gesplittet + SwNodeIndex aIdx( rDoc.GetNodes(), nTblNd ); + SwTableNode *const pTNd = aIdx.GetNode().GetTableNode(); + OSL_ENSURE( pTNd, "keinen Tabellen-Node gefunden" ); + + RemoveIdxFromSection( rDoc, nTblNd ); + + sTblNm = pTNd->GetTable().GetFrmFmt()->GetName(); + + if( pHistory ) + { + pHistory->TmpRollback( &rDoc, 0 ); + pHistory->SetTmpEnd( pHistory->Count() ); + } + + if( pDelBoxes ) + { + SwTable& rTbl = pTNd->GetTable(); + for( sal_uInt16 n = pDelBoxes->Count(); n; ) + { + SwTableBox* pBox = rTbl.GetTblBox( (*pDelBoxes)[ --n ] ); + if( pBox ) + ::_DeleteBox( rTbl, pBox, 0, sal_False, sal_False ); + else { + OSL_ENSURE( !this, "Wo ist die Box geblieben?" ); + } + } + } + + SwNodeIndex aEndIdx( *pTNd->EndOfSectionNode() ); + rDoc.TableToText( pTNd, 0x0b == cTrenner ? 0x09 : cTrenner ); + + // join again at start? + SwPaM aPam(rDoc.GetNodes().GetEndOfContent()); + SwPosition *const pPos = aPam.GetPoint(); + if( nSttCntnt ) + { + pPos->nNode = nTblNd; + pPos->nContent.Assign(pPos->nNode.GetNode().GetCntntNode(), 0); + if (aPam.Move(fnMoveBackward, fnGoCntnt)) + { + SwNodeIndex & rIdx = aPam.GetPoint()->nNode; + + // dann die Crsr/etc. nochmal relativ verschieben + RemoveIdxRel( rIdx.GetIndex()+1, *pPos ); + + rIdx.GetNode().GetCntntNode()->JoinNext(); + } + } + + // join again at end? + if( bSplitEnd ) + { + SwNodeIndex& rIdx = pPos->nNode; + rIdx = nEndNode; + SwTxtNode* pTxtNd = rIdx.GetNode().GetTxtNode(); + if( pTxtNd && pTxtNd->CanJoinNext() ) + { + aPam.GetMark()->nContent.Assign( 0, 0 ); + aPam.GetPoint()->nContent.Assign( 0, 0 ); + + // dann die Crsr/etc. nochmal relativ verschieben + pPos->nContent.Assign( pTxtNd, pTxtNd->GetTxt().Len() ); + RemoveIdxRel( nEndNode + 1, *pPos ); + + pTxtNd->JoinNext(); + } + } + + AddUndoRedoPaM(rContext); +} + + +void SwUndoTxtToTbl::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwPaM & rPam( AddUndoRedoPaM(rContext) ); + RemoveIdxFromRange(rPam, false); + SetPaM(rPam); + + SwTable const*const pTable = rContext.GetDoc().TextToTable( + aInsTblOpts, rPam, cTrenner, nAdjust, pAutoFmt ); + ((SwFrmFmt*)pTable->GetFrmFmt())->SetName( sTblNm ); +} + + +void SwUndoTxtToTbl::RepeatImpl(::sw::RepeatContext & rContext) +{ + // no Table In Table + if (!rContext.GetRepeatPaM().GetNode()->FindTableNode()) + { + rContext.GetDoc().TextToTable( aInsTblOpts, rContext.GetRepeatPaM(), + cTrenner, nAdjust, + pAutoFmt ); + } +} + +void SwUndoTxtToTbl::AddFillBox( const SwTableBox& rBox ) +{ + if( !pDelBoxes ) + pDelBoxes = new SvULongs; + pDelBoxes->Insert( rBox.GetSttIdx(), pDelBoxes->Count() ); +} + +SwHistory& SwUndoTxtToTbl::GetHistory() +{ + if( !pHistory ) + pHistory = new SwHistory; + return *pHistory; +} + +// ----------------------------------------------------- + +SwUndoTblHeadline::SwUndoTblHeadline( const SwTable& rTbl, sal_uInt16 nOldHdl, + sal_uInt16 nNewHdl ) + : SwUndo( UNDO_TABLEHEADLINE ), + nOldHeadline( nOldHdl ), + nNewHeadline( nNewHdl ) +{ + OSL_ENSURE( rTbl.GetTabSortBoxes().Count(), "Tabelle ohne Inhalt" ); + const SwStartNode *pSttNd = rTbl.GetTabSortBoxes()[ 0 ]->GetSttNd(); + OSL_ENSURE( pSttNd, "Box ohne Inhalt" ); + + nTblNd = pSttNd->StartOfSectionIndex(); +} + +void SwUndoTblHeadline::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + SwTableNode* pTNd = rDoc.GetNodes()[ nTblNd ]->GetTableNode(); + OSL_ENSURE( pTNd, "keinen Tabellen-Node gefunden" ); + + rDoc.SetRowsToRepeat( pTNd->GetTable(), nOldHeadline ); +} + +void SwUndoTblHeadline::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + + SwTableNode* pTNd = rDoc.GetNodes()[ nTblNd ]->GetTableNode(); + OSL_ENSURE( pTNd, "keinen Tabellen-Node gefunden" ); + + rDoc.SetRowsToRepeat( pTNd->GetTable(), nNewHeadline ); +} + +void SwUndoTblHeadline::RepeatImpl(::sw::RepeatContext & rContext) +{ + SwTableNode *const pTblNd = + rContext.GetRepeatPaM().GetNode()->FindTableNode(); + if( pTblNd ) + { + rContext.GetDoc().SetRowsToRepeat( pTblNd->GetTable(), nNewHeadline ); + } +} + + +////////////////////////////////////////////////////////////////////////// + + +_SaveTable::_SaveTable( const SwTable& rTbl, sal_uInt16 nLnCnt, sal_Bool bSaveFml ) + : aTblSet( *rTbl.GetFrmFmt()->GetAttrSet().GetPool(), aTableSetRange ), + pSwTable( &rTbl ), nLineCount( nLnCnt ), bSaveFormula( bSaveFml ) +{ + bModifyBox = sal_False; + bNewModel = rTbl.IsNewModel(); + aTblSet.Put( rTbl.GetFrmFmt()->GetAttrSet() ); + pLine = new _SaveLine( 0, *rTbl.GetTabLines()[ 0 ], *this ); + + _SaveLine* pLn = pLine; + if( USHRT_MAX == nLnCnt ) + nLnCnt = rTbl.GetTabLines().Count(); + for( sal_uInt16 n = 1; n < nLnCnt; ++n ) + pLn = new _SaveLine( pLn, *rTbl.GetTabLines()[ n ], *this ); + + aFrmFmts.Remove( 0, aFrmFmts.Count() ); + pSwTable = 0; +} + + +_SaveTable::~_SaveTable() +{ + delete pLine; +} + + +sal_uInt16 _SaveTable::AddFmt( SwFrmFmt* pFmt, bool bIsLine ) +{ + sal_uInt16 nRet = aFrmFmts.GetPos( pFmt ); + if( USHRT_MAX == nRet ) + { + // Kopie vom ItemSet anlegen + SfxItemSet* pSet = new SfxItemSet( *pFmt->GetAttrSet().GetPool(), + bIsLine ? aTableLineSetRange : aTableBoxSetRange ); + pSet->Put( pFmt->GetAttrSet() ); + //JP 20.04.98: Bug 49502 - wenn eine Formel gesetzt ist, nie den + // Value mit sichern. Der muss gegebenfalls neu + // errechnet werden! + //JP 30.07.98: Bug 54295 - Formeln immer im Klartext speichern + const SfxPoolItem* pItem; + if( SFX_ITEM_SET == pSet->GetItemState( RES_BOXATR_FORMULA, sal_True, &pItem )) + { + pSet->ClearItem( RES_BOXATR_VALUE ); + if( pSwTable && bSaveFormula ) + { + SwTableFmlUpdate aMsgHnt( pSwTable ); + aMsgHnt.eFlags = TBL_BOXNAME; + ((SwTblBoxFormula*)pItem)->ChgDefinedIn( pFmt ); + ((SwTblBoxFormula*)pItem)->ChangeState( &aMsgHnt ); + ((SwTblBoxFormula*)pItem)->ChgDefinedIn( 0 ); + } + } + aSets.Insert( pSet, (nRet = aSets.Count() ) ); + aFrmFmts.Insert( pFmt, nRet ); + } + return nRet; +} + + +void _SaveTable::RestoreAttr( SwTable& rTbl, sal_Bool bMdfyBox ) +{ + sal_uInt16 n; + + bModifyBox = bMdfyBox; + + // zuerst die Attribute des TabellenFrmFormates zurueck holen + SwFrmFmt* pFmt = rTbl.GetFrmFmt(); + SfxItemSet& rFmtSet = (SfxItemSet&)pFmt->GetAttrSet(); + rFmtSet.ClearItem(); + rFmtSet.Put( aTblSet ); + + if( pFmt->IsInCache() ) + { + SwFrm::GetCache().Delete( pFmt ); + pFmt->SetInCache( sal_False ); + } + + // zur Sicherheit alle Tableframes invalidieren + SwIterator<SwTabFrm,SwFmt> aIter( *pFmt ); + for( SwTabFrm* pLast = aIter.First(); pLast; pLast = aIter.Next() ) + if( pLast->GetTable() == &rTbl ) + { + pLast->InvalidateAll(); + pLast->SetCompletePaint(); + } + + // FrmFmts mit Defaults (0) fuellen + pFmt = 0; + for( n = aSets.Count(); n; --n ) + aFrmFmts.Insert( pFmt, aFrmFmts.Count() ); + + sal_uInt16 nLnCnt = nLineCount; + if( USHRT_MAX == nLnCnt ) + nLnCnt = rTbl.GetTabLines().Count(); + + _SaveLine* pLn = pLine; + for( n = 0; n < nLnCnt; ++n, pLn = pLn->pNext ) + { + if( !pLn ) + { + OSL_ENSURE( !this, "Anzahl der Lines hat sich veraendert" ); + break; + } + + pLn->RestoreAttr( *rTbl.GetTabLines()[ n ], *this ); + } + + aFrmFmts.Remove( 0, aFrmFmts.Count() ); + bModifyBox = sal_False; +} + + +void _SaveTable::SaveCntntAttrs( SwDoc* pDoc ) +{ + pLine->SaveCntntAttrs( pDoc ); +} + + +void _SaveTable::CreateNew( SwTable& rTbl, sal_Bool bCreateFrms, + sal_Bool bRestoreChart ) +{ + sal_uInt16 n; + + _FndBox aTmpBox( 0, 0 ); + //if( bRestoreChart ) + // // ? TL_CHART2: notification or locking of controller required ? + aTmpBox.DelFrms( rTbl ); + + // zuerst die Attribute des TabellenFrmFormates zurueck holen + SwFrmFmt* pFmt = rTbl.GetFrmFmt(); + SfxItemSet& rFmtSet = (SfxItemSet&)pFmt->GetAttrSet(); + rFmtSet.ClearItem(); + rFmtSet.Put( aTblSet ); + + if( pFmt->IsInCache() ) + { + SwFrm::GetCache().Delete( pFmt ); + pFmt->SetInCache( sal_False ); + } + + // SwTableBox muss ein Format haben!! + SwTableBox aParent( (SwTableBoxFmt*)pFmt, rTbl.GetTabLines().Count(), 0 ); + + // FrmFmts mit Defaults (0) fuellen + pFmt = 0; + for( n = aSets.Count(); n; --n ) + aFrmFmts.Insert( pFmt, aFrmFmts.Count() ); + + pLine->CreateNew( rTbl, aParent, *this ); + aFrmFmts.Remove( 0, aFrmFmts.Count() ); + + // die neuen Lines eintragen, die alten loeschen + sal_uInt16 nOldLines = nLineCount; + if( USHRT_MAX == nLineCount ) + nOldLines = rTbl.GetTabLines().Count(); + + SwDoc *pDoc = rTbl.GetFrmFmt()->GetDoc(); + SwChartDataProvider *pPCD = pDoc->GetChartDataProvider(); + for( n = 0; n < aParent.GetTabLines().Count(); ++n ) + { + SwTableLine* pLn = aParent.GetTabLines()[ n ]; + pLn->SetUpper( 0 ); + if( n < nOldLines ) + { + SwTableLine* pOld = rTbl.GetTabLines()[ n ]; + + // TL_CHART2: notify chart about boxes to be removed + const SwTableBoxes &rBoxes = pOld->GetTabBoxes(); + sal_uInt16 nBoxes = rBoxes.Count(); + for (sal_uInt16 k = 0; k < nBoxes; ++k) + { + SwTableBox *pBox = rBoxes[k]; + if (pPCD) + pPCD->DeleteBox( &rTbl, *pBox ); + } + + rTbl.GetTabLines().C40_REPLACE( SwTableLine, pLn, n ); + delete pOld; + } + else + rTbl.GetTabLines().C40_INSERT( SwTableLine, pLn, n ); + } + + if( n < nOldLines ) + { + // remove remaining lines... + + for (sal_uInt16 k1 = 0; k1 < nOldLines - n; ++k1) + { + const SwTableBoxes &rBoxes = rTbl.GetTabLines()[n + k1]->GetTabBoxes(); + sal_uInt16 nBoxes = rBoxes.Count(); + for (sal_uInt16 k2 = 0; k2 < nBoxes; ++k2) + { + SwTableBox *pBox = rBoxes[k2]; + // TL_CHART2: notify chart about boxes to be removed + if (pPCD) + pPCD->DeleteBox( &rTbl, *pBox ); + } + } + + rTbl.GetTabLines().DeleteAndDestroy( n, nOldLines - n ); + } + + aParent.GetTabLines().Remove( 0, n ); + + if( bCreateFrms ) + aTmpBox.MakeFrms( rTbl ); + if( bRestoreChart ) + { + // TL_CHART2: need to inform chart of probably changed cell names + pDoc->UpdateCharts( rTbl.GetFrmFmt()->GetName() ); + } +} + + +void _SaveTable::NewFrmFmt( const SwTableLine* pTblLn, const SwTableBox* pTblBx, + sal_uInt16 nFmtPos, SwFrmFmt* pOldFmt ) +{ + SwDoc* pDoc = pOldFmt->GetDoc(); + + SwFrmFmt* pFmt = aFrmFmts[ nFmtPos ]; + if( !pFmt ) + { + if( pTblLn ) + pFmt = pDoc->MakeTableLineFmt(); + else + pFmt = pDoc->MakeTableBoxFmt(); + pFmt->SetFmtAttr( *aSets[ nFmtPos ] ); + aFrmFmts.Replace( pFmt, nFmtPos ); + } + + //Erstmal die Frms ummelden. + SwIterator<SwTabFrm,SwFmt> aIter( *pOldFmt ); + for( SwFrm* pLast = aIter.First(); pLast; pLast = aIter.Next() ) + { + if( pTblLn ? ((SwRowFrm*)pLast)->GetTabLine() == pTblLn + : ((SwCellFrm*)pLast)->GetTabBox() == pTblBx ) + { + pLast->RegisterToFormat(*pFmt); + pLast->InvalidateAll(); + pLast->ReinitializeFrmSizeAttrFlags(); + if ( !pTblLn ) + { + ((SwCellFrm*)pLast)->SetDerivedVert( sal_False ); + ((SwCellFrm*)pLast)->CheckDirChange(); + } + } + } + + //Jetzt noch mich selbst ummelden. + if ( pTblLn ) + const_cast<SwTableLine*>(pTblLn)->RegisterToFormat( *pFmt ); + else if ( pTblBx ) + const_cast<SwTableBox*>(pTblBx)->RegisterToFormat( *pFmt ); + + if( bModifyBox && !pTblLn ) + { + const SfxPoolItem& rOld = pOldFmt->GetFmtAttr( RES_BOXATR_FORMAT ), + & rNew = pFmt->GetFmtAttr( RES_BOXATR_FORMAT ); + if( rOld != rNew ) + pFmt->ModifyNotification( (SfxPoolItem*)&rOld, (SfxPoolItem*)&rNew ); + } + + if( !pOldFmt->GetDepends() ) + delete pOldFmt; + +} + + +_SaveLine::_SaveLine( _SaveLine* pPrev, const SwTableLine& rLine, _SaveTable& rSTbl ) + : pNext( 0 ) +{ + if( pPrev ) + pPrev->pNext = this; + + nItemSet = rSTbl.AddFmt( rLine.GetFrmFmt(), true ); + + pBox = new _SaveBox( 0, *rLine.GetTabBoxes()[ 0 ], rSTbl ); + _SaveBox* pBx = pBox; + for( sal_uInt16 n = 1; n < rLine.GetTabBoxes().Count(); ++n ) + pBx = new _SaveBox( pBx, *rLine.GetTabBoxes()[ n ], rSTbl ); +} + + +_SaveLine::~_SaveLine() +{ + delete pBox; + delete pNext; +} + + +void _SaveLine::RestoreAttr( SwTableLine& rLine, _SaveTable& rSTbl ) +{ + rSTbl.NewFrmFmt( &rLine, 0, nItemSet, rLine.GetFrmFmt() ); + + _SaveBox* pBx = pBox; + for( sal_uInt16 n = 0; n < rLine.GetTabBoxes().Count(); ++n, pBx = pBx->pNext ) + { + if( !pBx ) + { + OSL_ENSURE( !this, "Anzahl der Boxen hat sich veraendert" ); + break; + } + pBx->RestoreAttr( *rLine.GetTabBoxes()[ n ], rSTbl ); + } +} + + +void _SaveLine::SaveCntntAttrs( SwDoc* pDoc ) +{ + pBox->SaveCntntAttrs( pDoc ); + if( pNext ) + pNext->SaveCntntAttrs( pDoc ); +} + + +void _SaveLine::CreateNew( SwTable& rTbl, SwTableBox& rParent, _SaveTable& rSTbl ) +{ + SwTableLineFmt* pFmt = (SwTableLineFmt*)rSTbl.aFrmFmts[ nItemSet ]; + if( !pFmt ) + { + SwDoc* pDoc = rTbl.GetFrmFmt()->GetDoc(); + pFmt = pDoc->MakeTableLineFmt(); + pFmt->SetFmtAttr( *rSTbl.aSets[ nItemSet ] ); + rSTbl.aFrmFmts.Replace( pFmt, nItemSet ); + } + SwTableLine* pNew = new SwTableLine( pFmt, 1, &rParent ); + + rParent.GetTabLines().C40_INSERT( SwTableLine, pNew, rParent.GetTabLines().Count() ); + + // HB, #127868# robustness: in some cases - which I + // cannot reproduce nor see from the code - pNew seems + // to be set to NULL in C40_INSERT. + OSL_ENSURE(pNew, "Table line just created set to NULL in C40_INSERT"); + + if (pNew) + { + pBox->CreateNew( rTbl, *pNew, rSTbl ); + } + + if( pNext ) + pNext->CreateNew( rTbl, rParent, rSTbl ); +} + + +_SaveBox::_SaveBox( _SaveBox* pPrev, const SwTableBox& rBox, _SaveTable& rSTbl ) + : pNext( 0 ), nSttNode( ULONG_MAX ), nRowSpan(0) +{ + Ptrs.pLine = 0; + + if( pPrev ) + pPrev->pNext = this; + + nItemSet = rSTbl.AddFmt( rBox.GetFrmFmt(), false ); + + if( rBox.GetSttNd() ) + { + nSttNode = rBox.GetSttIdx(); + nRowSpan = rBox.getRowSpan(); + } + else + { + Ptrs.pLine = new _SaveLine( 0, *rBox.GetTabLines()[ 0 ], rSTbl ); + + _SaveLine* pLn = Ptrs.pLine; + for( sal_uInt16 n = 1; n < rBox.GetTabLines().Count(); ++n ) + pLn = new _SaveLine( pLn, *rBox.GetTabLines()[ n ], rSTbl ); + } +} + + +_SaveBox::~_SaveBox() +{ + if( ULONG_MAX == nSttNode ) // keine EndBox + delete Ptrs.pLine; + else + delete Ptrs.pCntntAttrs; + delete pNext; +} + + +void _SaveBox::RestoreAttr( SwTableBox& rBox, _SaveTable& rSTbl ) +{ + rSTbl.NewFrmFmt( 0, &rBox, nItemSet, rBox.GetFrmFmt() ); + + if( ULONG_MAX == nSttNode ) // keine EndBox + { + if( !rBox.GetTabLines().Count() ) + { + OSL_ENSURE( !this, "Anzahl der Lines hat sich veraendert" ); + } + else + { + _SaveLine* pLn = Ptrs.pLine; + for( sal_uInt16 n = 0; n < rBox.GetTabLines().Count(); ++n, pLn = pLn->pNext ) + { + if( !pLn ) + { + OSL_ENSURE( !this, "Anzahl der Lines hat sich veraendert" ); + break; + } + + pLn->RestoreAttr( *rBox.GetTabLines()[ n ], rSTbl ); + } + } + } + else if( rBox.GetSttNd() && rBox.GetSttIdx() == nSttNode ) + { + if( Ptrs.pCntntAttrs ) + { + SwNodes& rNds = rBox.GetFrmFmt()->GetDoc()->GetNodes(); + sal_uInt16 nSet = 0; + sal_uLong nEnd = rBox.GetSttNd()->EndOfSectionIndex(); + for( sal_uLong n = nSttNode + 1; n < nEnd; ++n ) + { + SwCntntNode* pCNd = rNds[ n ]->GetCntntNode(); + if( pCNd ) + { + SfxItemSet* pSet = (*Ptrs.pCntntAttrs)[ nSet++ ]; + if( pSet ) + { + sal_uInt16 *pRstAttr = aSave_BoxCntntSet; + while( *pRstAttr ) + { + pCNd->ResetAttr( *pRstAttr, *(pRstAttr+1) ); + pRstAttr += 2; + } + pCNd->SetAttr( *pSet ); + } + else + pCNd->ResetAllAttr(); + } + } + } + } + else + { + OSL_ENSURE( !this, "Box nicht mehr am gleichen Node" ); + } +} + + +void _SaveBox::SaveCntntAttrs( SwDoc* pDoc ) +{ + if( ULONG_MAX == nSttNode ) // keine EndBox + { + // weiter in der Line + Ptrs.pLine->SaveCntntAttrs( pDoc ); + } + else + { + sal_uLong nEnd = pDoc->GetNodes()[ nSttNode ]->EndOfSectionIndex(); + Ptrs.pCntntAttrs = new SfxItemSets( (sal_uInt8)(nEnd - nSttNode - 1 ), 5 ); + for( sal_uLong n = nSttNode + 1; n < nEnd; ++n ) + { + SwCntntNode* pCNd = pDoc->GetNodes()[ n ]->GetCntntNode(); + if( pCNd ) + { + SfxItemSet* pSet = 0; + if( pCNd->HasSwAttrSet() ) + { + pSet = new SfxItemSet( pDoc->GetAttrPool(), + aSave_BoxCntntSet ); + pSet->Put( *pCNd->GetpSwAttrSet() ); + } + + Ptrs.pCntntAttrs->Insert( pSet, Ptrs.pCntntAttrs->Count() ); + } + } + } + if( pNext ) + pNext->SaveCntntAttrs( pDoc ); +} + + +void _SaveBox::CreateNew( SwTable& rTbl, SwTableLine& rParent, _SaveTable& rSTbl ) +{ + SwTableBoxFmt* pFmt = (SwTableBoxFmt*)rSTbl.aFrmFmts[ nItemSet ]; + if( !pFmt ) + { + SwDoc* pDoc = rTbl.GetFrmFmt()->GetDoc(); + pFmt = pDoc->MakeTableBoxFmt(); + pFmt->SetFmtAttr( *rSTbl.aSets[ nItemSet ] ); + rSTbl.aFrmFmts.Replace( pFmt, nItemSet ); + } + + if( ULONG_MAX == nSttNode ) // keine EndBox + { + SwTableBox* pNew = new SwTableBox( pFmt, 1, &rParent ); + rParent.GetTabBoxes().C40_INSERT( SwTableBox, pNew, rParent.GetTabBoxes().Count() ); + + Ptrs.pLine->CreateNew( rTbl, *pNew, rSTbl ); + } + else + { + // Box zum StartNode in der alten Tabelle suchen + SwTableBox* pBox = rTbl.GetTblBox( nSttNode ); + OSL_ENSURE( pBox, "Wo ist meine TabellenBox geblieben?" ); + + SwFrmFmt* pOld = pBox->GetFrmFmt(); + pBox->RegisterToFormat( *pFmt ); + if( !pOld->GetDepends() ) + delete pOld; + + pBox->setRowSpan( nRowSpan ); + + SwTableBoxes* pTBoxes = &pBox->GetUpper()->GetTabBoxes(); + pTBoxes->Remove( pTBoxes->C40_GETPOS( SwTableBox, pBox ) ); + + pBox->SetUpper( &rParent ); + pTBoxes = &rParent.GetTabBoxes(); + pTBoxes->C40_INSERT( SwTableBox, pBox, pTBoxes->Count() ); + } + + if( pNext ) + pNext->CreateNew( rTbl, rParent, rSTbl ); +} + + +////////////////////////////////////////////////////////////////////////// + +// UndoObject fuer Attribut Aenderung an der Tabelle + + +SwUndoAttrTbl::SwUndoAttrTbl( const SwTableNode& rTblNd, sal_Bool bClearTabCols ) + : SwUndo( UNDO_TABLE_ATTR ), + nSttNode( rTblNd.GetIndex() ) +{ + bClearTabCol = bClearTabCols; + pSaveTbl = new _SaveTable( rTblNd.GetTable() ); +} + +SwUndoAttrTbl::~SwUndoAttrTbl() +{ + delete pSaveTbl; +} + +void SwUndoAttrTbl::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + SwTableNode* pTblNd = rDoc.GetNodes()[ nSttNode ]->GetTableNode(); + OSL_ENSURE( pTblNd, "kein TabellenNode" ); + + if (pTblNd) + { + _SaveTable* pOrig = new _SaveTable( pTblNd->GetTable() ); + pSaveTbl->RestoreAttr( pTblNd->GetTable() ); + delete pSaveTbl; + pSaveTbl = pOrig; + } + + if( bClearTabCol ) + ClearFEShellTabCols(); +} + +void SwUndoAttrTbl::RedoImpl(::sw::UndoRedoContext & rContext) +{ + UndoImpl(rContext); +} + + +////////////////////////////////////////////////////////////////////////// + +// UndoObject fuer AutoFormat an der Tabelle + + +SwUndoTblAutoFmt::SwUndoTblAutoFmt( const SwTableNode& rTblNd, + const SwTableAutoFmt& rAFmt ) + : SwUndo( UNDO_TABLE_AUTOFMT ), + nSttNode( rTblNd.GetIndex() ), + bSaveCntntAttr( sal_False ) +{ + pSaveTbl = new _SaveTable( rTblNd.GetTable() ); + + if( rAFmt.IsFont() || rAFmt.IsJustify() ) + { + // dann auch noch ueber die ContentNodes der EndBoxen und + // und alle Absatz-Attribute zusammen sammeln + pSaveTbl->SaveCntntAttrs( (SwDoc*)rTblNd.GetDoc() ); + bSaveCntntAttr = sal_True; + } +} + +SwUndoTblAutoFmt::~SwUndoTblAutoFmt() +{ + delete pSaveTbl; +} + +void SwUndoTblAutoFmt::SaveBoxCntnt( const SwTableBox& rBox ) +{ + ::boost::shared_ptr<SwUndoTblNumFmt> const p(new SwUndoTblNumFmt(rBox)); + m_Undos.push_back(p); +} + + +void +SwUndoTblAutoFmt::UndoRedo(bool const bUndo, ::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + SwTableNode* pTblNd = rDoc.GetNodes()[ nSttNode ]->GetTableNode(); + OSL_ENSURE( pTblNd, "kein TabellenNode" ); + + _SaveTable* pOrig = new _SaveTable( pTblNd->GetTable() ); + // dann auch noch ueber die ContentNodes der EndBoxen und + // und alle Absatz-Attribute zusammen sammeln + if( bSaveCntntAttr ) + pOrig->SaveCntntAttrs( &rDoc ); + + if (bUndo) + { + for (size_t n = m_Undos.size(); 0 < n; --n) + { + m_Undos.at(n-1)->UndoImpl(rContext); + } + } + + pSaveTbl->RestoreAttr( pTblNd->GetTable(), !bUndo ); + delete pSaveTbl; + pSaveTbl = pOrig; +} + +void SwUndoTblAutoFmt::UndoImpl(::sw::UndoRedoContext & rContext) +{ + UndoRedo(true, rContext); +} + +void SwUndoTblAutoFmt::RedoImpl(::sw::UndoRedoContext & rContext) +{ + UndoRedo(false, rContext); +} + + +////////////////////////////////////////////////////////////////////////// + +SwUndoTblNdsChg::SwUndoTblNdsChg( SwUndoId nAction, + const SwSelBoxes& rBoxes, + const SwTableNode& rTblNd, + long nMn, long nMx, + sal_uInt16 nCnt, sal_Bool bFlg, sal_Bool bSmHght ) + : SwUndo( nAction ), + aBoxes( rBoxes.Count() < 255 ? (sal_uInt8)rBoxes.Count() : 255, 10 ), + nMin( nMn ), nMax( nMx ), + nSttNode( rTblNd.GetIndex() ), nCurrBox( 0 ), + nCount( nCnt ), nRelDiff( 0 ), nAbsDiff( 0 ), + nSetColType( USHRT_MAX ), + bFlag( bFlg ), + bSameHeight( bSmHght ) +{ + Ptrs.pNewSttNds = 0; + + const SwTable& rTbl = rTblNd.GetTable(); + pSaveTbl = new _SaveTable( rTbl ); + + // und die Selektion merken + for( sal_uInt16 n = 0; n < rBoxes.Count(); ++n ) + aBoxes.Insert( rBoxes[n]->GetSttIdx(), n ); +} + + +SwUndoTblNdsChg::SwUndoTblNdsChg( SwUndoId nAction, + const SwSelBoxes& rBoxes, + const SwTableNode& rTblNd ) + : SwUndo( nAction ), + aBoxes( rBoxes.Count() < 255 ? (sal_uInt8)rBoxes.Count() : 255, 10 ), + nMin( 0 ), nMax( 0 ), + nSttNode( rTblNd.GetIndex() ), nCurrBox( 0 ), + nCount( 0 ), nRelDiff( 0 ), nAbsDiff( 0 ), + nSetColType( USHRT_MAX ), + bFlag( sal_False ), + bSameHeight( sal_False ) +{ + Ptrs.pNewSttNds = 0; + + const SwTable& rTbl = rTblNd.GetTable(); + pSaveTbl = new _SaveTable( rTbl ); + + // und die Selektion merken + for( sal_uInt16 n = 0; n < rBoxes.Count(); ++n ) + aBoxes.Insert( rBoxes[n]->GetSttIdx(), n ); +} + +void SwUndoTblNdsChg::ReNewBoxes( const SwSelBoxes& rBoxes ) +{ + if( rBoxes.Count() != aBoxes.Count() ) + { + aBoxes.Remove( 0, aBoxes.Count() ); + for( sal_uInt16 n = 0; n < rBoxes.Count(); ++n ) + aBoxes.Insert( rBoxes[n]->GetSttIdx(), n ); + } +} + +SwUndoTblNdsChg::~SwUndoTblNdsChg() +{ + delete pSaveTbl; + + if( IsDelBox() ) + delete Ptrs.pDelSects; + else + delete Ptrs.pNewSttNds; +} + +void SwUndoTblNdsChg::SaveNewBoxes( const SwTableNode& rTblNd, + const SwTableSortBoxes& rOld ) +{ + const SwTable& rTbl = rTblNd.GetTable(); + const SwTableSortBoxes& rTblBoxes = rTbl.GetTabSortBoxes(); + sal_uInt16 n; + sal_uInt16 i; + + OSL_ENSURE( ! IsDelBox(), "falsche Action" ); + Ptrs.pNewSttNds = new SvULongs( (sal_uInt8)(rTblBoxes.Count() - rOld.Count()), 5 ); + + for( n = 0, i = 0; n < rOld.Count(); ++i ) + { + if( rOld[ n ] == rTblBoxes[ i ] ) + ++n; + else + // neue Box: sortiert einfuegen!! + InsertSort( *Ptrs.pNewSttNds, rTblBoxes[ i ]->GetSttIdx() ); + } + + for( ; i < rTblBoxes.Count(); ++i ) + // neue Box: sortiert einfuegen!! + InsertSort( *Ptrs.pNewSttNds, rTblBoxes[ i ]->GetSttIdx() ); +} + + +SwTableLine* lcl_FindTableLine( const SwTable& rTable, + const SwTableBox& rBox ) +{ + SwTableLine* pRet = NULL; + // i63949: For nested cells we have to take nLineNo - 1, too, not 0! + const SwTableLines &rTableLines = ( rBox.GetUpper()->GetUpper() != NULL ) ? + rBox.GetUpper()->GetUpper()->GetTabLines() + : rTable.GetTabLines(); + const SwTableLine* pLine = rBox.GetUpper(); + sal_uInt16 nLineNo = rTableLines.C40_GETPOS( SwTableLine, pLine ); + pRet = rTableLines[nLineNo - 1]; + + return pRet; +} + +const SwTableLines& lcl_FindParentLines( const SwTable& rTable, + const SwTableBox& rBox ) +{ + const SwTableLines& rRet = + ( rBox.GetUpper()->GetUpper() != NULL ) ? + rBox.GetUpper()->GetUpper()->GetTabLines() : + rTable.GetTabLines(); + + return rRet; +} + + +void SwUndoTblNdsChg::SaveNewBoxes( const SwTableNode& rTblNd, + const SwTableSortBoxes& rOld, + const SwSelBoxes& rBoxes, + const SvULongs& rNodeCnts ) +{ + const SwTable& rTbl = rTblNd.GetTable(); + const SwTableSortBoxes& rTblBoxes = rTbl.GetTabSortBoxes(); + + OSL_ENSURE( ! IsDelBox(), "falsche Action" ); + Ptrs.pNewSttNds = new SvULongs( (sal_uInt8)(rTblBoxes.Count() - rOld.Count()), 5 ); + + OSL_ENSURE( rTbl.IsNewModel() || rOld.Count() + nCount * rBoxes.Count() == rTblBoxes.Count(), + "unexpected boxes" ); + OSL_ENSURE( rOld.Count() <= rTblBoxes.Count(), "more unexpected boxes" ); + for( sal_uInt16 n = 0, i = 0; i < rTblBoxes.Count(); ++i ) + { + if( ( n < rOld.Count() ) && + ( rOld[ n ] == rTblBoxes[ i ] ) ) + { + // box already known? Then nothing to be done. + ++n; + } + else + { + // new box found: insert (obey sort order) + sal_uInt16 nInsPos; + const SwTableBox* pBox = rTblBoxes[ i ]; + InsertSort( *Ptrs.pNewSttNds, pBox->GetSttIdx(), &nInsPos ); + + // find the source box. It must be one in rBoxes. + // We found the right one if it's in the same column as pBox. + // No, if more than one selected cell in the same column has been splitted, + // we have to look for the nearest one (i65201)! + const SwTableBox* pSourceBox = NULL; + const SwTableBox* pCheckBox = NULL; + const SwTableLine* pBoxLine = pBox->GetUpper(); + sal_uInt16 nLineDiff = lcl_FindParentLines(rTbl,*pBox).C40_GETPOS(SwTableLine,pBoxLine); + sal_uInt16 nLineNo = 0; + for( sal_uInt16 j = 0; j < rBoxes.Count(); ++j ) + { + pCheckBox = rBoxes[j]; + if( pCheckBox->GetUpper()->GetUpper() == pBox->GetUpper()->GetUpper() ) + { + const SwTableLine* pCheckLine = pCheckBox->GetUpper(); + sal_uInt16 nCheckLine = lcl_FindParentLines( rTbl, *pCheckBox ). + C40_GETPOS( SwTableLine, pCheckLine ); + if( ( !pSourceBox || nCheckLine > nLineNo ) && nCheckLine < nLineDiff ) + { + nLineNo = nCheckLine; + pSourceBox = pCheckBox; + } + } + } + + // find the line number difference + // (to help determine bNodesMoved flag below) + nLineDiff = nLineDiff - nLineNo; + OSL_ENSURE( pSourceBox, "Splitted source box not found!" ); + // find out how many nodes the source box used to have + // (to help determine bNodesMoved flag below) + sal_uInt16 nNdsPos = 0; + while( rBoxes[ nNdsPos ] != pSourceBox ) + ++nNdsPos; + sal_uLong nNodes = rNodeCnts[ nNdsPos ]; + + // When a new table cell is created, it either gets a new + // node, or it gets node(s) from elsewhere. The undo must + // know, of course, and thus we must determine here just + // where pBox's nodes are from: + // If 1) the source box has lost nodes, and + // 2) we're in the node range that got nodes + // then pBox received nodes from elsewhere. + // If bNodesMoved is set for pBox the undo must move the + // boxes back, otherwise it must delete them. + // The bNodesMoved flag is stored in a seperate array + // which mirrors Ptrs.pNewSttNds, i.e. Ptrs.pNewSttNds[i] + // and aMvBoxes[i] belong together. + sal_Bool bNodesMoved = + ( nNodes != ( pSourceBox->GetSttNd()->EndOfSectionIndex() - + pSourceBox->GetSttIdx() ) ) + && ( nNodes - 1 > nLineDiff ); + aMvBoxes.insert( aMvBoxes.begin() + nInsPos, bNodesMoved ); + } + } +} + + +void SwUndoTblNdsChg::SaveSection( SwStartNode* pSttNd ) +{ + OSL_ENSURE( IsDelBox(), "falsche Action" ); + if( !Ptrs.pDelSects ) + Ptrs.pDelSects = new SwUndoSaveSections( 10, 5 ); + + SwTableNode* pTblNd = pSttNd->FindTableNode(); + SwUndoSaveSection* pSave = new SwUndoSaveSection; + pSave->SaveSection( pSttNd->GetDoc(), SwNodeIndex( *pSttNd )); + + Ptrs.pDelSects->Insert( pSave, Ptrs.pDelSects->Count() ); + nSttNode = pTblNd->GetIndex(); +} + + +void SwUndoTblNdsChg::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + SwNodeIndex aIdx( rDoc.GetNodes(), nSttNode ); + + SwTableNode *const pTblNd = aIdx.GetNode().GetTableNode(); + OSL_ENSURE( pTblNd, "kein TabellenNode" ); + + SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() ); + aMsgHnt.eFlags = TBL_BOXPTR; + rDoc.UpdateTblFlds( &aMsgHnt ); + + CHECK_TABLE( pTblNd->GetTable() ) + + _FndBox aTmpBox( 0, 0 ); + // ? TL_CHART2: notification or locking of controller required ? + + SwChartDataProvider *pPCD = rDoc.GetChartDataProvider(); + std::vector< SwTableBox* > aDelBoxes; + if( IsDelBox() ) + { + // Trick: die fehlenden Boxen in irgendeine Line einfuegen, beim + // CreateNew werden sie korrekt verbunden. + SwTableBox* pCpyBox = pTblNd->GetTable().GetTabSortBoxes()[0]; + SwTableBoxes& rLnBoxes = pCpyBox->GetUpper()->GetTabBoxes(); + + // die Sections wieder herstellen + for( sal_uInt16 n = Ptrs.pDelSects->Count(); n; ) + { + SwUndoSaveSection* pSave = (*Ptrs.pDelSects)[ --n ]; + pSave->RestoreSection( &rDoc, &aIdx, SwTableBoxStartNode ); + if( pSave->GetHistory() ) + pSave->GetHistory()->Rollback( &rDoc ); + SwTableBox* pBox = new SwTableBox( (SwTableBoxFmt*)pCpyBox->GetFrmFmt(), aIdx, + pCpyBox->GetUpper() ); + rLnBoxes.C40_INSERT( SwTableBox, pBox, rLnBoxes.Count() ); + } + Ptrs.pDelSects->DeleteAndDestroy( 0, Ptrs.pDelSects->Count() ); + } + else if( !aMvBoxes.empty() ) + { + // dann muessen Nodes verschoben und nicht geloescht werden! + // Dafuer brauchen wir aber ein temp Array + SvULongs aTmp( 0, 5); + aTmp.Insert( Ptrs.pNewSttNds, 0 ); + + // von hinten anfangen + for( sal_uInt16 n = aTmp.Count(); n; ) + { + // Box aus der Tabellen-Struktur entfernen + sal_uLong nIdx = aTmp[ --n ]; + SwTableBox* pBox = pTblNd->GetTable().GetTblBox( nIdx ); + OSL_ENSURE( pBox, "Wo ist meine TabellenBox geblieben?" ); + + // TL_CHART2: notify chart about box to be removed + if (pPCD) + pPCD->DeleteBox( &pTblNd->GetTable(), *pBox ); + + if( aMvBoxes[ n ] ) + { + SwNodeRange aRg( *pBox->GetSttNd(), 1, + *pBox->GetSttNd()->EndOfSectionNode() ); + + SwTableLine* pLine = lcl_FindTableLine( pTblNd->GetTable(), *pBox ); + SwNodeIndex aInsPos( *(pLine->GetTabBoxes()[0]->GetSttNd()), 2 ); + + // alle StartNode Indizies anpassen + sal_uInt16 i = n; + sal_uLong nSttIdx = aInsPos.GetIndex() - 2, + nNdCnt = aRg.aEnd.GetIndex() - aRg.aStart.GetIndex(); + while( i && aTmp[ --i ] > nSttIdx ) + aTmp[ i ] += nNdCnt; + + // erst die Box loeschen + delete pBox; + // dann die Nodes verschieben, + rDoc.GetNodes()._MoveNodes( aRg, rDoc.GetNodes(), aInsPos, sal_False ); + } + else + rDoc.DeleteSection( rDoc.GetNodes()[ nIdx ] ); + aDelBoxes.insert( aDelBoxes.end(), pBox ); + } + } + else + { + // Remove nodes from nodes array (backwards!) + for( sal_uInt16 n = Ptrs.pNewSttNds->Count(); n; ) + { + sal_uLong nIdx = (*Ptrs.pNewSttNds)[ --n ]; + SwTableBox* pBox = pTblNd->GetTable().GetTblBox( nIdx ); + OSL_ENSURE( pBox, "Where's my table box?" ); + // TL_CHART2: notify chart about box to be removed + if (pPCD) + pPCD->DeleteBox( &pTblNd->GetTable(), *pBox ); + aDelBoxes.insert( aDelBoxes.end(), pBox ); + rDoc.DeleteSection( rDoc.GetNodes()[ nIdx ] ); + } + } + // Remove boxes from table structure + for( sal_uInt16 n = 0; n < aDelBoxes.size(); ++n ) + { + SwTableBox* pCurrBox = aDelBoxes[n]; + SwTableBoxes* pTBoxes = &pCurrBox->GetUpper()->GetTabBoxes(); + pTBoxes->Remove( pTBoxes->C40_GETPOS( SwTableBox, pCurrBox ) ); + delete pCurrBox; + } + + pSaveTbl->CreateNew( pTblNd->GetTable(), sal_True, sal_False ); + + // TL_CHART2: need to inform chart of probably changed cell names + rDoc.UpdateCharts( pTblNd->GetTable().GetFrmFmt()->GetName() ); + + if( IsDelBox() ) + nSttNode = pTblNd->GetIndex(); + ClearFEShellTabCols(); + CHECK_TABLE( pTblNd->GetTable() ) +} + + +void SwUndoTblNdsChg::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + + SwTableNode* pTblNd = rDoc.GetNodes()[ nSttNode ]->GetTableNode(); + OSL_ENSURE( pTblNd, "kein TabellenNode" ); + CHECK_TABLE( pTblNd->GetTable() ) + + SwSelBoxes aSelBoxes; + for( sal_uInt16 n = 0; n < aBoxes.Count(); ++n ) + { + SwTableBox* pBox = pTblNd->GetTable().GetTblBox( aBoxes[ n ] ); + aSelBoxes.Insert( pBox ); + } + + // SelBoxes erzeugen und InsertCell/-Row/SplitTbl aufrufen + switch( GetId() ) + { + case UNDO_TABLE_INSCOL: + if( USHRT_MAX == nSetColType ) + rDoc.InsertCol( aSelBoxes, nCount, bFlag ); + else + { + SwTableBox* pBox = pTblNd->GetTable().GetTblBox( nCurrBox ); + rDoc.SetColRowWidthHeight( *pBox, nSetColType, nAbsDiff, + nRelDiff ); + } + break; + + case UNDO_TABLE_INSROW: + if( USHRT_MAX == nSetColType ) + rDoc.InsertRow( aSelBoxes, nCount, bFlag ); + else + { + SwTable& rTbl = pTblNd->GetTable(); + SwTableBox* pBox = rTbl.GetTblBox( nCurrBox ); + TblChgMode eOldMode = rTbl.GetTblChgMode(); + rTbl.SetTblChgMode( (TblChgMode)nCount ); + rDoc.SetColRowWidthHeight( *pBox, nSetColType, nAbsDiff, nRelDiff ); + rTbl.SetTblChgMode( eOldMode ); + } + break; + + case UNDO_TABLE_SPLIT: + rDoc.SplitTbl( aSelBoxes, bFlag, nCount, bSameHeight ); + break; + case UNDO_TABLE_DELBOX: + case UNDO_ROW_DELETE: + case UNDO_COL_DELETE: + if( USHRT_MAX == nSetColType ) + { + SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() ); + aMsgHnt.eFlags = TBL_BOXPTR; + rDoc.UpdateTblFlds( &aMsgHnt ); + SwTable &rTable = pTblNd->GetTable(); + if( nMax > nMin && rTable.IsNewModel() ) + rTable.PrepareDeleteCol( nMin, nMax ); + rTable.DeleteSel( &rDoc, aSelBoxes, 0, this, sal_True, sal_True ); + } + else + { + SwTable& rTbl = pTblNd->GetTable(); + + SwTableFmlUpdate aMsgHnt( &rTbl ); + aMsgHnt.eFlags = TBL_BOXPTR; + rDoc.UpdateTblFlds( &aMsgHnt ); + + SwTableBox* pBox = rTbl.GetTblBox( nCurrBox ); + TblChgMode eOldMode = rTbl.GetTblChgMode(); + rTbl.SetTblChgMode( (TblChgMode)nCount ); + + // need the SaveSections! + rDoc.GetIDocumentUndoRedo().DoUndo( true ); + SwUndoTblNdsChg* pUndo = 0; + + switch( nSetColType & 0xff ) + { + case nsTblChgWidthHeightType::WH_COL_LEFT: + case nsTblChgWidthHeightType::WH_COL_RIGHT: + case nsTblChgWidthHeightType::WH_CELL_LEFT: + case nsTblChgWidthHeightType::WH_CELL_RIGHT: + rTbl.SetColWidth( *pBox, nSetColType, nAbsDiff, + nRelDiff, (SwUndo**)&pUndo ); + break; + case nsTblChgWidthHeightType::WH_ROW_TOP: + case nsTblChgWidthHeightType::WH_ROW_BOTTOM: + case nsTblChgWidthHeightType::WH_CELL_TOP: + case nsTblChgWidthHeightType::WH_CELL_BOTTOM: + rTbl.SetRowHeight( *pBox, nSetColType, nAbsDiff, + nRelDiff, (SwUndo**)&pUndo ); + break; + } + + if( pUndo ) + { + Ptrs.pDelSects->Insert( pUndo->Ptrs.pDelSects, 0 ); + pUndo->Ptrs.pDelSects->Remove( 0, pUndo->Ptrs.pDelSects->Count() ); + + delete pUndo; + } + rDoc.GetIDocumentUndoRedo().DoUndo( false ); + + rTbl.SetTblChgMode( eOldMode ); + } + nSttNode = pTblNd->GetIndex(); + break; + default: + ; + } + ClearFEShellTabCols(); + CHECK_TABLE( pTblNd->GetTable() ) +} + + +////////////////////////////////////////////////////////////////////////// + +SwUndoTblMerge::SwUndoTblMerge( const SwPaM& rTblSel ) + : SwUndo( UNDO_TABLE_MERGE ), SwUndRng( rTblSel ), pHistory( 0 ) +{ + const SwTableNode* pTblNd = rTblSel.GetNode()->FindTableNode(); + OSL_ENSURE( pTblNd, "Wo ist TabllenNode" ); + pSaveTbl = new _SaveTable( pTblNd->GetTable() ); + pMoves = new SwUndoMoves; + nTblNode = pTblNd->GetIndex(); +} + +SwUndoTblMerge::~SwUndoTblMerge() +{ + delete pSaveTbl; + delete pMoves; + delete pHistory; +} + +void SwUndoTblMerge::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + SwNodeIndex aIdx( rDoc.GetNodes(), nTblNode ); + + SwTableNode *const pTblNd = aIdx.GetNode().GetTableNode(); + OSL_ENSURE( pTblNd, "kein TabellenNode" ); + + SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() ); + aMsgHnt.eFlags = TBL_BOXPTR; + rDoc.UpdateTblFlds( &aMsgHnt ); + + _FndBox aTmpBox( 0, 0 ); + // ? TL_CHART2: notification or locking of controller required ? + + + // 1. die geloeschten Boxen wiederherstellen: + + // Trick: die fehlenden Boxen in irgendeine Line einfuegen, beim + // CreateNew werden sie korrekt verbunden. + SwTableBox *pBox, *pCpyBox = pTblNd->GetTable().GetTabSortBoxes()[0]; + SwTableBoxes& rLnBoxes = pCpyBox->GetUpper()->GetTabBoxes(); + +CHECKTABLE(pTblNd->GetTable()) + + SwSelBoxes aSelBoxes; + SwTxtFmtColl* pColl = rDoc.GetTxtCollFromPool( RES_POOLCOLL_STANDARD ); + sal_uInt16 n; + + for( n = 0; n < aBoxes.Count(); ++n ) + { + aIdx = aBoxes[ n ]; + SwStartNode* pSttNd = rDoc.GetNodes().MakeTextSection( aIdx, + SwTableBoxStartNode, pColl ); + pBox = new SwTableBox( (SwTableBoxFmt*)pCpyBox->GetFrmFmt(), *pSttNd, + pCpyBox->GetUpper() ); + rLnBoxes.C40_INSERT( SwTableBox, pBox, rLnBoxes.Count() ); + + aSelBoxes.Insert( pBox ); + } + +CHECKTABLE(pTblNd->GetTable()) + + SwChartDataProvider *pPCD = rDoc.GetChartDataProvider(); + // 2. die eingefuegten Boxen loeschen + // die Nodes loeschen (von Hinten!!) + for( n = aNewSttNds.Count(); n; ) + { + // Box aus der Tabellen-Struktur entfernen + sal_uLong nIdx = aNewSttNds[ --n ]; + + if( !nIdx && n ) + { + nIdx = aNewSttNds[ --n ]; + pBox = pTblNd->GetTable().GetTblBox( nIdx ); + OSL_ENSURE( pBox, "Wo ist meine TabellenBox geblieben?" ); + + if( !pSaveTbl->IsNewModel() ) + rDoc.GetNodes().MakeTxtNode( SwNodeIndex( + *pBox->GetSttNd()->EndOfSectionNode() ), pColl ); + + // das war der Trenner, -> die verschobenen herstellen + for( sal_uInt16 i = pMoves->Count(); i; ) + { + SwTxtNode* pTxtNd = 0; + sal_uInt16 nDelPos = 0; + SwUndoMove* pUndo = (*pMoves)[ --i ]; + if( !pUndo->IsMoveRange() ) + { + pTxtNd = rDoc.GetNodes()[ pUndo->GetDestSttNode() ]->GetTxtNode(); + nDelPos = pUndo->GetDestSttCntnt() - 1; + } + pUndo->UndoImpl(rContext); + if( pUndo->IsMoveRange() ) + { + // den ueberfluessigen Node loeschen + aIdx = pUndo->GetEndNode(); + SwCntntNode *pCNd = aIdx.GetNode().GetCntntNode(); + if( pCNd ) + { + SwNodeIndex aTmp( aIdx, -1 ); + SwCntntNode *pMove = aTmp.GetNode().GetCntntNode(); + if( pMove ) + pCNd->MoveTo( *pMove ); + } + rDoc.GetNodes().Delete( aIdx, 1 ); + } + else if( pTxtNd ) + { + // evt. noch ueberflussige Attribute loeschen + SwIndex aTmpIdx( pTxtNd, nDelPos ); + if( pTxtNd->GetpSwpHints() && pTxtNd->GetpSwpHints()->Count() ) + pTxtNd->RstAttr( aTmpIdx, pTxtNd->GetTxt().Len() - + nDelPos + 1 ); + // das Trennzeichen loeschen + pTxtNd->EraseText( aTmpIdx, 1 ); + } + } + nIdx = pBox->GetSttIdx(); + } + else + pBox = pTblNd->GetTable().GetTblBox( nIdx ); + + if( !pSaveTbl->IsNewModel() ) + { + // TL_CHART2: notify chart about box to be removed + if (pPCD) + pPCD->DeleteBox( &pTblNd->GetTable(), *pBox ); + + SwTableBoxes* pTBoxes = &pBox->GetUpper()->GetTabBoxes(); + pTBoxes->Remove( pTBoxes->C40_GETPOS( SwTableBox, pBox ) ); + + + // Indizies aus dem Bereich loeschen + { + SwNodeIndex aTmpIdx( *pBox->GetSttNd() ); + rDoc.CorrAbs( SwNodeIndex( aTmpIdx, 1 ), + SwNodeIndex( *aTmpIdx.GetNode().EndOfSectionNode() ), + SwPosition( aTmpIdx, SwIndex( 0, 0 )), sal_True ); + } + + delete pBox; + rDoc.DeleteSection( rDoc.GetNodes()[ nIdx ] ); + } + } +CHECKTABLE(pTblNd->GetTable()) + + + pSaveTbl->CreateNew( pTblNd->GetTable(), sal_True, sal_False ); + + // TL_CHART2: need to inform chart of probably changed cell names + rDoc.UpdateCharts( pTblNd->GetTable().GetFrmFmt()->GetName() ); + + if( pHistory ) + { + pHistory->TmpRollback( &rDoc, 0 ); + pHistory->SetTmpEnd( pHistory->Count() ); + } +// nTblNode = pTblNd->GetIndex(); + + SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor()); + pPam->DeleteMark(); + pPam->GetPoint()->nNode = nSttNode; + pPam->GetPoint()->nContent.Assign( pPam->GetCntntNode(), nSttCntnt ); + pPam->SetMark(); + pPam->DeleteMark(); + +CHECKTABLE(pTblNd->GetTable()) + ClearFEShellTabCols(); +} + +void SwUndoTblMerge::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + SwPaM & rPam( AddUndoRedoPaM(rContext) ); + rDoc.MergeTbl(rPam); +} + +void SwUndoTblMerge::MoveBoxCntnt( SwDoc* pDoc, SwNodeRange& rRg, SwNodeIndex& rPos ) +{ + SwNodeIndex aTmp( rRg.aStart, -1 ), aTmp2( rPos, -1 ); + SwUndoMove* pUndo = new SwUndoMove( pDoc, rRg, rPos ); + ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo()); + pDoc->MoveNodeRange( rRg, rPos, (pSaveTbl->IsNewModel()) ? + IDocumentContentOperations::DOC_NO_DELFRMS : + IDocumentContentOperations::DOC_MOVEDEFAULT ); + aTmp++; + aTmp2++; + pUndo->SetDestRange( aTmp2, rPos, aTmp ); + + pMoves->Insert( pUndo, pMoves->Count() ); +} + +void SwUndoTblMerge::SetSelBoxes( const SwSelBoxes& rBoxes ) +{ + // die Selektion merken + for( sal_uInt16 n = 0; n < rBoxes.Count(); ++n ) + InsertSort( aBoxes, rBoxes[n]->GetSttIdx() ); + + // als Trennung fuers einfuegen neuer Boxen nach dem Verschieben! + aNewSttNds.Insert( (sal_uLong)0, aNewSttNds.Count() ); + + // The new table model does not delete overlapped cells (by row span), + // so the rBoxes array might be empty even some cells have been merged. + if( rBoxes.Count() ) + nTblNode = rBoxes[ 0 ]->GetSttNd()->FindTableNode()->GetIndex(); +} + +void SwUndoTblMerge::SaveCollection( const SwTableBox& rBox ) +{ + if( !pHistory ) + pHistory = new SwHistory; + + SwNodeIndex aIdx( *rBox.GetSttNd(), 1 ); + SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode(); + if( !pCNd ) + pCNd = aIdx.GetNodes().GoNext( &aIdx ); + + pHistory->Add( pCNd->GetFmtColl(), aIdx.GetIndex(), pCNd->GetNodeType()); + if( pCNd->HasSwAttrSet() ) + pHistory->CopyFmtAttr( *pCNd->GetpSwAttrSet(), aIdx.GetIndex() ); +} + + +////////////////////////////////////////////////////////////////////////// + +SwUndoTblNumFmt::SwUndoTblNumFmt( const SwTableBox& rBox, + const SfxItemSet* pNewSet ) + : SwUndo( UNDO_TBLNUMFMT ), + pBoxSet( 0 ), pHistory( 0 ), nFmtIdx( NUMBERFORMAT_TEXT ) +{ + bNewFmt = bNewFml = bNewValue = sal_False; + nNode = rBox.GetSttIdx(); + + nNdPos = rBox.IsValidNumTxtNd( 0 == pNewSet ); + SwDoc* pDoc = rBox.GetFrmFmt()->GetDoc(); + + if( ULONG_MAX != nNdPos ) + { + SwTxtNode* pTNd = pDoc->GetNodes()[ nNdPos ]->GetTxtNode(); + + pHistory = new SwHistory; + SwRegHistory aRHst( *rBox.GetSttNd(), pHistory ); + // always save all text atttibutes because of possibly overlapping + // areas of on/off + pHistory->CopyAttr( pTNd->GetpSwpHints(), nNdPos, 0, + pTNd->GetTxt().Len(), true ); + + if( pTNd->HasSwAttrSet() ) + pHistory->CopyFmtAttr( *pTNd->GetpSwAttrSet(), nNdPos ); + + aStr = pTNd->GetTxt(); + if( pTNd->GetpSwpHints() ) + pTNd->GetpSwpHints()->DeRegister(); + } + + pBoxSet = new SfxItemSet( pDoc->GetAttrPool(), aTableBoxSetRange ); + pBoxSet->Put( rBox.GetFrmFmt()->GetAttrSet() ); + + if( pNewSet ) + { + const SfxPoolItem* pItem; + if( SFX_ITEM_SET == pNewSet->GetItemState( RES_BOXATR_FORMAT, + sal_False, &pItem )) + { + bNewFmt = sal_True; + nNewFmtIdx = ((SwTblBoxNumFormat*)pItem)->GetValue(); + } + if( SFX_ITEM_SET == pNewSet->GetItemState( RES_BOXATR_FORMULA, + sal_False, &pItem )) + { + bNewFml = sal_True; + aNewFml = ((SwTblBoxFormula*)pItem)->GetFormula(); + } + if( SFX_ITEM_SET == pNewSet->GetItemState( RES_BOXATR_VALUE, + sal_False, &pItem )) + { + bNewValue = sal_True; + fNewNum = ((SwTblBoxValue*)pItem)->GetValue(); + } + } + + // wird die History ueberhaupt benoetigt ?? + if( pHistory && !pHistory->Count() ) + DELETEZ( pHistory ); +} + +SwUndoTblNumFmt::~SwUndoTblNumFmt() +{ + delete pHistory; + delete pBoxSet; +} + +void SwUndoTblNumFmt::UndoImpl(::sw::UndoRedoContext & rContext) +{ + OSL_ENSURE( pBoxSet, "Where's the stored item set?" ); + + SwDoc & rDoc = rContext.GetDoc(); + SwStartNode* pSttNd = rDoc.GetNodes()[ nNode ]-> + FindSttNodeByType( SwTableBoxStartNode ); + OSL_ENSURE( pSttNd, "ohne StartNode kein TabellenBox" ); + SwTableBox* pBox = pSttNd->FindTableNode()->GetTable().GetTblBox( + pSttNd->GetIndex() ); + OSL_ENSURE( pBox, "keine TabellenBox gefunden" ); + + SwTableBoxFmt* pFmt = rDoc.MakeTableBoxFmt(); + pFmt->SetFmtAttr( *pBoxSet ); + pBox->ChgFrmFmt( pFmt ); + + if( ULONG_MAX == nNdPos ) + return; + + SwTxtNode* pTxtNd = rDoc.GetNodes()[ nNdPos ]->GetTxtNode(); + // wenn mehr als ein Node geloescht wurde, dann wurden auch + // alle "Node"-Attribute gespeichert + if( pTxtNd->HasSwAttrSet() ) + pTxtNd->ResetAllAttr(); + + if( pTxtNd->GetpSwpHints() && aStr.Len() ) + pTxtNd->ClearSwpHintsArr( true ); + + // ChgTextToNum(..) only acts when the strings are different. We + // need to do the same here. + if( pTxtNd->GetTxt() != aStr ) + { + rDoc.DeleteRedline( *( pBox->GetSttNd() ), false, USHRT_MAX ); + + SwIndex aIdx( pTxtNd, 0 ); + if( aStr.Len() ) + { + pTxtNd->EraseText( aIdx ); + pTxtNd->InsertText( aStr, aIdx, + IDocumentContentOperations::INS_NOHINTEXPAND ); + } + } + + if( pHistory ) + { + sal_uInt16 nTmpEnd = pHistory->GetTmpEnd(); + pHistory->TmpRollback( &rDoc, 0 ); + pHistory->SetTmpEnd( nTmpEnd ); + } + + SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor()); + pPam->DeleteMark(); + pPam->GetPoint()->nNode = nNode + 1; + pPam->GetPoint()->nContent.Assign( pTxtNd, 0 ); +} + +/** switch the RedlineMode on the given document, using + * SetRedlineMode_intern. This class set the mode in the constructor, + * and changes it back in the destructor, i.e. it uses the + * initialization-is-resource-acquisition idiom. + */ +class RedlineModeInternGuard +{ + SwDoc& mrDoc; + RedlineMode_t meOldRedlineMode; + +public: + RedlineModeInternGuard( + SwDoc& rDoc, /// change mode of this document + RedlineMode_t eNewRedlineMode, /// new redline mode + RedlineMode_t eRedlineModeMask = (RedlineMode_t)(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_IGNORE /*change only bits set in this mask*/)); + + ~RedlineModeInternGuard(); +}; + +RedlineModeInternGuard::RedlineModeInternGuard( + SwDoc& rDoc, + RedlineMode_t eNewRedlineMode, + RedlineMode_t eRedlineModeMask ) + : mrDoc( rDoc ), + meOldRedlineMode( rDoc.GetRedlineMode() ) +{ + mrDoc.SetRedlineMode_intern((RedlineMode_t)( ( meOldRedlineMode & ~eRedlineModeMask ) | + ( eNewRedlineMode & eRedlineModeMask ) )); +} + +RedlineModeInternGuard::~RedlineModeInternGuard() +{ + mrDoc.SetRedlineMode_intern( meOldRedlineMode ); +} + + + +void SwUndoTblNumFmt::RedoImpl(::sw::UndoRedoContext & rContext) +{ + // konnte die Box veraendert werden ? + if( !pBoxSet ) + return ; + + SwDoc & rDoc = rContext.GetDoc(); + SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor()); + + pPam->DeleteMark(); + pPam->GetPoint()->nNode = nNode; + + SwNode * pNd = & pPam->GetPoint()->nNode.GetNode(); + SwStartNode* pSttNd = pNd->FindSttNodeByType( SwTableBoxStartNode ); + OSL_ENSURE( pSttNd, "ohne StartNode kein TabellenBox" ); + SwTableBox* pBox = pSttNd->FindTableNode()->GetTable().GetTblBox( + pSttNd->GetIndex() ); + OSL_ENSURE( pBox, "keine TabellenBox gefunden" ); + + SwFrmFmt* pBoxFmt = pBox->ClaimFrmFmt(); + if( bNewFmt || bNewFml || bNewValue ) + { + SfxItemSet aBoxSet( rDoc.GetAttrPool(), + RES_BOXATR_FORMAT, RES_BOXATR_VALUE ); + + // JP 15.01.99: Nur Attribute zuruecksetzen reicht nicht. + // Sorge dafuer, das der Text auch entsprechend + // formatiert wird! + pBoxFmt->LockModify(); + + if( bNewFml ) + aBoxSet.Put( SwTblBoxFormula( aNewFml )); + else + pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMULA ); + if( bNewFmt ) + aBoxSet.Put( SwTblBoxNumFormat( nNewFmtIdx )); + else + pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMAT ); + if( bNewValue ) + aBoxSet.Put( SwTblBoxValue( fNewNum )); + else + pBoxFmt->ResetFmtAttr( RES_BOXATR_VALUE ); + pBoxFmt->UnlockModify(); + + // dvo: When redlining is (was) enabled, setting the attribute + // will also change the cell content. To allow this, the + // REDLINE_IGNORE flag must be removed during Redo. #108450# + RedlineModeInternGuard aGuard( rDoc, nsRedlineMode_t::REDLINE_NONE, nsRedlineMode_t::REDLINE_IGNORE ); + pBoxFmt->SetFmtAttr( aBoxSet ); + } + else if( NUMBERFORMAT_TEXT != nFmtIdx ) + { + SfxItemSet aBoxSet( rDoc.GetAttrPool(), + RES_BOXATR_FORMAT, RES_BOXATR_VALUE ); + + aBoxSet.Put( SwTblBoxNumFormat( nFmtIdx )); + aBoxSet.Put( SwTblBoxValue( fNum )); + + // JP 15.01.99: Nur Attribute zuruecksetzen reicht nicht. + // Sorge dafuer, das der Text auch entsprechend + // formatiert wird! + pBoxFmt->LockModify(); + pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMULA ); + pBoxFmt->UnlockModify(); + + // dvo: When redlining is (was) enabled, setting the attribute + // will also change the cell content. To allow this, the + // REDLINE_IGNORE flag must be removed during Redo. #108450# + RedlineModeInternGuard aGuard( rDoc, nsRedlineMode_t::REDLINE_NONE, nsRedlineMode_t::REDLINE_IGNORE ); + pBoxFmt->SetFmtAttr( aBoxSet ); + } + else + { + // es ist keine Zahl + + // JP 15.01.99: Nur Attribute zuruecksetzen reicht nicht. + // Sorge dafuer, das der Text auch entsprechend + // formatiert wird! + pBoxFmt->SetFmtAttr( *GetDfltAttr( RES_BOXATR_FORMAT )); + + pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMAT, RES_BOXATR_VALUE ); + } + + if( bNewFml ) + { + // egal was gesetzt wurde, ein Update der Tabelle macht sich immer gut + SwTableFmlUpdate aTblUpdate( &pSttNd->FindTableNode()->GetTable() ); + rDoc.UpdateTblFlds( &aTblUpdate ); + } + + if( !pNd->IsCntntNode() ) + pNd = rDoc.GetNodes().GoNext( &pPam->GetPoint()->nNode ); + pPam->GetPoint()->nContent.Assign( (SwCntntNode*)pNd, 0 ); +} + +void SwUndoTblNumFmt::SetBox( const SwTableBox& rBox ) +{ + nNode = rBox.GetSttIdx(); +} + + +////////////////////////////////////////////////////////////////////////// + +_UndoTblCpyTbl_Entry::_UndoTblCpyTbl_Entry( const SwTableBox& rBox ) + : nBoxIdx( rBox.GetSttIdx() ), nOffset( 0 ), + pBoxNumAttr( 0 ), pUndo( 0 ), bJoin( false ) +{ +} + +_UndoTblCpyTbl_Entry::~_UndoTblCpyTbl_Entry() +{ + delete pUndo; + delete pBoxNumAttr; +} + + +SwUndoTblCpyTbl::SwUndoTblCpyTbl() + : SwUndo( UNDO_TBLCPYTBL ), pInsRowUndo( 0 ) +{ + pArr = new _UndoTblCpyTbl_Entries; +} + +SwUndoTblCpyTbl::~SwUndoTblCpyTbl() +{ + delete pArr; + delete pInsRowUndo; +} + +void SwUndoTblCpyTbl::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + _DEBUG_REDLINE( &rDoc ) + + SwTableNode* pTblNd = 0; + for( sal_uInt16 n = pArr->Count(); n; ) + { + _UndoTblCpyTbl_Entry* pEntry = (*pArr)[ --n ]; + sal_uLong nSttPos = pEntry->nBoxIdx + pEntry->nOffset; + SwStartNode* pSNd = rDoc.GetNodes()[ nSttPos ]->StartOfSectionNode(); + if( !pTblNd ) + pTblNd = pSNd->FindTableNode(); + + SwTableBox& rBox = *pTblNd->GetTable().GetTblBox( nSttPos ); + + SwNodeIndex aInsIdx( *rBox.GetSttNd(), 1 ); + rDoc.GetNodes().MakeTxtNode( aInsIdx, (SwTxtFmtColl*)rDoc.GetDfltTxtFmtColl() ); + + // b62341295: Redline for copying tables + const SwNode *pEndNode = rBox.GetSttNd()->EndOfSectionNode(); + SwPaM aPam( aInsIdx.GetNode(), *pEndNode ); + SwUndoDelete* pUndo = 0; + + if( IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() ) ) + { + bool bDeleteCompleteParagraph = false; + bool bShiftPam = false; + // There are a couple of different situations to consider during redlining + if( pEntry->pUndo ) + { + SwUndoDelete *const pUndoDelete = + dynamic_cast<SwUndoDelete*>(pEntry->pUndo); + SwUndoRedlineDelete *const pUndoRedlineDelete = + dynamic_cast<SwUndoRedlineDelete*>(pEntry->pUndo); + OSL_ASSERT(pUndoDelete || pUndoRedlineDelete); + if (pUndoRedlineDelete) + { + // The old content was not empty or he has been merged with the new content + bDeleteCompleteParagraph = !pEntry->bJoin; // bJoin is set when merged + // Set aTmpIdx to the beginning fo the old content + SwNodeIndex aTmpIdx( *pEndNode, + pUndoRedlineDelete->NodeDiff()-1 ); + SwTxtNode *pTxt = aTmpIdx.GetNode().GetTxtNode(); + if( pTxt ) + { + aPam.GetPoint()->nNode = *pTxt; + aPam.GetPoint()->nContent.Assign( pTxt, + pUndoRedlineDelete->ContentStart() ); + } + else + *aPam.GetPoint() = SwPosition( aTmpIdx ); + } + else if (pUndoDelete && pUndoDelete->IsDelFullPara()) + { + // When the old content was an empty paragraph, but could not be joined + // with the new content (e.g. because of a section or table) + // We "save" the aPam.Point, we go one step backwards (because later on the + // empty paragraph will be inserted by the undo) and set the "ShiftPam-flag + // for step forward later on. + bDeleteCompleteParagraph = true; + bShiftPam = true; + SwNodeIndex aTmpIdx( *pEndNode, -1 ); + SwTxtNode *pTxt = aTmpIdx.GetNode().GetTxtNode(); + if( pTxt ) + { + aPam.GetPoint()->nNode = *pTxt; + aPam.GetPoint()->nContent.Assign( pTxt, 0 ); + } + else + *aPam.GetPoint() = SwPosition( aTmpIdx ); + } + } + rDoc.DeleteRedline( aPam, true, USHRT_MAX ); + + if( pEntry->pUndo ) + { + pEntry->pUndo->UndoImpl(rContext); + delete pEntry->pUndo; + pEntry->pUndo = 0; + } + if( bShiftPam ) + { + // The aPam.Point is at the moment at the last position of the new content and has to be + // moved to the first postion of the old content for the SwUndoDelete operation + SwNodeIndex aTmpIdx( aPam.GetPoint()->nNode, 1 ); + SwTxtNode *pTxt = aTmpIdx.GetNode().GetTxtNode(); + if( pTxt ) + { + aPam.GetPoint()->nNode = *pTxt; + aPam.GetPoint()->nContent.Assign( pTxt, 0 ); + } + else + *aPam.GetPoint() = SwPosition( aTmpIdx ); + } + pUndo = new SwUndoDelete( aPam, bDeleteCompleteParagraph, sal_True ); + } + else + { + pUndo = new SwUndoDelete( aPam, true ); + if( pEntry->pUndo ) + { + pEntry->pUndo->UndoImpl(rContext); + delete pEntry->pUndo; + pEntry->pUndo = 0; + } + } + pEntry->pUndo = pUndo; + + aInsIdx = rBox.GetSttIdx() + 1; + rDoc.GetNodes().Delete( aInsIdx, 1 ); + + SfxItemSet aTmpSet( rDoc.GetAttrPool(), RES_BOXATR_FORMAT, RES_BOXATR_VALUE, + RES_VERT_ORIENT, RES_VERT_ORIENT, 0 ); + aTmpSet.Put( rBox.GetFrmFmt()->GetAttrSet() ); + if( aTmpSet.Count() ) + { + SwFrmFmt* pBoxFmt = rBox.ClaimFrmFmt(); + pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMAT, RES_BOXATR_VALUE ); + pBoxFmt->ResetFmtAttr( RES_VERT_ORIENT ); + } + + if( pEntry->pBoxNumAttr ) + { + rBox.ClaimFrmFmt()->SetFmtAttr( *pEntry->pBoxNumAttr ); + delete pEntry->pBoxNumAttr, pEntry->pBoxNumAttr = 0; + } + + if( aTmpSet.Count() ) + { + pEntry->pBoxNumAttr = new SfxItemSet( rDoc.GetAttrPool(), + RES_BOXATR_FORMAT, RES_BOXATR_VALUE, + RES_VERT_ORIENT, RES_VERT_ORIENT, 0 ); + pEntry->pBoxNumAttr->Put( aTmpSet ); + } + + pEntry->nOffset = rBox.GetSttIdx() - pEntry->nBoxIdx; + } + + if( pInsRowUndo ) + { + pInsRowUndo->UndoImpl(rContext); + } + _DEBUG_REDLINE( &rDoc ) +} + +void SwUndoTblCpyTbl::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + _DEBUG_REDLINE( &rDoc ) + + if( pInsRowUndo ) + { + pInsRowUndo->RedoImpl(rContext); + } + + SwTableNode* pTblNd = 0; + for( sal_uInt16 n = 0; n < pArr->Count(); ++n ) + { + _UndoTblCpyTbl_Entry* pEntry = (*pArr)[ n ]; + sal_uLong nSttPos = pEntry->nBoxIdx + pEntry->nOffset; + SwStartNode* pSNd = rDoc.GetNodes()[ nSttPos ]->StartOfSectionNode(); + if( !pTblNd ) + pTblNd = pSNd->FindTableNode(); + + SwTableBox& rBox = *pTblNd->GetTable().GetTblBox( nSttPos ); + + SwNodeIndex aInsIdx( *rBox.GetSttNd(), 1 ); + + // b62341295: Redline for copying tables - Start. + rDoc.GetNodes().MakeTxtNode( aInsIdx, (SwTxtFmtColl*)rDoc.GetDfltTxtFmtColl() ); + SwPaM aPam( aInsIdx.GetNode(), *rBox.GetSttNd()->EndOfSectionNode()); + SwUndo* pUndo = IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() ) ? 0 : new SwUndoDelete( aPam, sal_True ); + if( pEntry->pUndo ) + { + pEntry->pUndo->UndoImpl(rContext); + if( IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() ) ) + { + // PrepareRedline has to be called with the beginning of the old content + // When new and old content has been joined, the rIter.pAktPam has been set + // by the Undo operation to this point. + // Otherwise aInsIdx has been moved during the Undo operation + if( pEntry->bJoin ) + { + SwPaM const& rLastPam = + rContext.GetCursorSupplier().GetCurrentShellCursor(); + pUndo = PrepareRedline( &rDoc, rBox, *rLastPam.GetPoint(), + pEntry->bJoin, true ); + } + else + { + SwPosition aTmpPos( aInsIdx ); + pUndo = PrepareRedline( &rDoc, rBox, aTmpPos, pEntry->bJoin, true ); + } + } + delete pEntry->pUndo; + pEntry->pUndo = 0; + } + pEntry->pUndo = pUndo; + // b62341295: Redline for copying tables - End. + + aInsIdx = rBox.GetSttIdx() + 1; + rDoc.GetNodes().Delete( aInsIdx, 1 ); + + SfxItemSet aTmpSet( rDoc.GetAttrPool(), RES_BOXATR_FORMAT, RES_BOXATR_VALUE, + RES_VERT_ORIENT, RES_VERT_ORIENT, 0 ); + aTmpSet.Put( rBox.GetFrmFmt()->GetAttrSet() ); + if( aTmpSet.Count() ) + { + SwFrmFmt* pBoxFmt = rBox.ClaimFrmFmt(); + pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMAT, RES_BOXATR_VALUE ); + pBoxFmt->ResetFmtAttr( RES_VERT_ORIENT ); + } + if( pEntry->pBoxNumAttr ) + { + rBox.ClaimFrmFmt()->SetFmtAttr( *pEntry->pBoxNumAttr ); + delete pEntry->pBoxNumAttr, pEntry->pBoxNumAttr = 0; + } + + if( aTmpSet.Count() ) + { + pEntry->pBoxNumAttr = new SfxItemSet( rDoc.GetAttrPool(), + RES_BOXATR_FORMAT, RES_BOXATR_VALUE, + RES_VERT_ORIENT, RES_VERT_ORIENT, 0 ); + pEntry->pBoxNumAttr->Put( aTmpSet ); + } + + pEntry->nOffset = rBox.GetSttIdx() - pEntry->nBoxIdx; + } + _DEBUG_REDLINE( &rDoc ) +} + +void SwUndoTblCpyTbl::AddBoxBefore( const SwTableBox& rBox, sal_Bool bDelCntnt ) +{ + if( pArr->Count() && !bDelCntnt ) + return; + + _UndoTblCpyTbl_Entry* pEntry = new _UndoTblCpyTbl_Entry( rBox ); + pArr->Insert( pEntry, pArr->Count() ); + + SwDoc* pDoc = rBox.GetFrmFmt()->GetDoc(); + _DEBUG_REDLINE( pDoc ) + if( bDelCntnt ) + { + SwNodeIndex aInsIdx( *rBox.GetSttNd(), 1 ); + pDoc->GetNodes().MakeTxtNode( aInsIdx, (SwTxtFmtColl*)pDoc->GetDfltTxtFmtColl() ); + SwPaM aPam( aInsIdx.GetNode(), *rBox.GetSttNd()->EndOfSectionNode() ); + + if( !pDoc->IsRedlineOn() ) + pEntry->pUndo = new SwUndoDelete( aPam, sal_True ); + } + + pEntry->pBoxNumAttr = new SfxItemSet( pDoc->GetAttrPool(), + RES_BOXATR_FORMAT, RES_BOXATR_VALUE, + RES_VERT_ORIENT, RES_VERT_ORIENT, 0 ); + pEntry->pBoxNumAttr->Put( rBox.GetFrmFmt()->GetAttrSet() ); + if( !pEntry->pBoxNumAttr->Count() ) + delete pEntry->pBoxNumAttr, pEntry->pBoxNumAttr = 0; + _DEBUG_REDLINE( pDoc ) +} + +void SwUndoTblCpyTbl::AddBoxAfter( const SwTableBox& rBox, const SwNodeIndex& rIdx, sal_Bool bDelCntnt ) +{ + _UndoTblCpyTbl_Entry* pEntry = (*pArr)[ pArr->Count() - 1 ]; + + // wurde der Inhalt geloescht, so loesche jetzt auch noch den temp. + // erzeugten Node + if( bDelCntnt ) + { + SwDoc* pDoc = rBox.GetFrmFmt()->GetDoc(); + _DEBUG_REDLINE( pDoc ) + + if( pDoc->IsRedlineOn() ) + { + SwPosition aTmpPos( rIdx ); + pEntry->pUndo = PrepareRedline( pDoc, rBox, aTmpPos, pEntry->bJoin, false ); + } + SwNodeIndex aDelIdx( *rBox.GetSttNd(), 1 ); + rBox.GetFrmFmt()->GetDoc()->GetNodes().Delete( aDelIdx, 1 ); + _DEBUG_REDLINE( pDoc ) + } + + pEntry->nOffset = rBox.GetSttIdx() - pEntry->nBoxIdx; +} + +// PrepareRedline is called from AddBoxAfter() and from Redo() in slightly different situations. +// bRedo is set by calling from Redo() +// rJoin is false by calling from AddBoxAfter() and will be set if the old and new content has +// been merged. +// rJoin is true if Redo() is calling and the content has already been merged + +SwUndo* SwUndoTblCpyTbl::PrepareRedline( SwDoc* pDoc, const SwTableBox& rBox, + const SwPosition& rPos, bool& rJoin, bool bRedo ) +{ + SwUndo *pUndo = 0; + // b62341295: Redline for copying tables + // What's to do? + // Mark the cell content before rIdx as insertion, + // mark the cell content behind rIdx as deletion + // merge text nodes at rIdx if possible + RedlineMode_t eOld = pDoc->GetRedlineMode(); + pDoc->SetRedlineMode_intern((RedlineMode_t)( ( eOld | nsRedlineMode_t::REDLINE_DONTCOMBINE_REDLINES ) & + ~nsRedlineMode_t::REDLINE_IGNORE )); + SwPosition aInsertEnd( rPos ); + SwTxtNode* pTxt; + if( !rJoin ) + { + // If the content is not merged, the end of the insertion is at the end of the node + // _before_ the given position rPos + --aInsertEnd.nNode; + pTxt = aInsertEnd.nNode.GetNode().GetTxtNode(); + if( pTxt ) + { + aInsertEnd.nContent.Assign( pTxt, pTxt->GetTxt().Len() ); + if( !bRedo && rPos.nNode.GetNode().GetTxtNode() ) + { // Try to merge, if not called by Redo() + rJoin = true; + pTxt->JoinNext(); + } + } + else + aInsertEnd.nContent = SwIndex( 0 ); + } + // For joined (merged) contents the start of deletionm and end of insertion are identical + // otherwise adjacent nodes. + SwPosition aDeleteStart( rJoin ? aInsertEnd : rPos ); + if( !rJoin ) + { + pTxt = aDeleteStart.nNode.GetNode().GetTxtNode(); + if( pTxt ) + aDeleteStart.nContent.Assign( pTxt, 0 ); + } + SwPosition aCellEnd( SwNodeIndex( *rBox.GetSttNd()->EndOfSectionNode(), -1 ) ); + pTxt = aCellEnd.nNode.GetNode().GetTxtNode(); + if( pTxt ) + aCellEnd.nContent.Assign( pTxt, pTxt->GetTxt().Len() ); + if( aDeleteStart != aCellEnd ) + { // If the old (deleted) part is not empty, here we are... + SwPaM aDeletePam( aDeleteStart, aCellEnd ); + pUndo = new SwUndoRedlineDelete( aDeletePam, UNDO_DELETE ); + pDoc->AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_DELETE, aDeletePam ), true ); + } + else if( !rJoin ) // If the old part is empty and joined, we are finished + { // if it is not joined, we have to delete this empty paragraph + aCellEnd = SwPosition( + SwNodeIndex( *rBox.GetSttNd()->EndOfSectionNode() )); + SwPaM aTmpPam( aDeleteStart, aCellEnd ); + pUndo = new SwUndoDelete( aTmpPam, sal_True ); + } + SwPosition aCellStart( SwNodeIndex( *rBox.GetSttNd(), 2 ) ); + pTxt = aCellStart.nNode.GetNode().GetTxtNode(); + if( pTxt ) + aCellStart.nContent.Assign( pTxt, 0 ); + if( aCellStart != aInsertEnd ) // An empty insertion will not been marked + { + SwPaM aTmpPam( aCellStart, aInsertEnd ); + pDoc->AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_INSERT, aTmpPam ), true ); + } + + pDoc->SetRedlineMode_intern( eOld ); + return pUndo; +} + + +sal_Bool SwUndoTblCpyTbl::InsertRow( SwTable& rTbl, const SwSelBoxes& rBoxes, + sal_uInt16 nCnt ) +{ + SwTableNode* pTblNd = (SwTableNode*)rTbl.GetTabSortBoxes()[0]-> + GetSttNd()->FindTableNode(); + + SwTableSortBoxes aTmpLst( 0, 5 ); + pInsRowUndo = new SwUndoTblNdsChg( UNDO_TABLE_INSROW, rBoxes, *pTblNd, + 0, 0, nCnt, sal_True, sal_False ); + aTmpLst.Insert( &rTbl.GetTabSortBoxes(), 0, rTbl.GetTabSortBoxes().Count() ); + + sal_Bool bRet = rTbl.InsertRow( rTbl.GetFrmFmt()->GetDoc(), rBoxes, nCnt, sal_True ); + if( bRet ) + pInsRowUndo->SaveNewBoxes( *pTblNd, aTmpLst ); + else + delete pInsRowUndo, pInsRowUndo = 0; + return bRet; +} + +sal_Bool SwUndoTblCpyTbl::IsEmpty() const +{ + return !pInsRowUndo && !pArr->Count(); +} + + +////////////////////////////////////////////////////////////////////////// + +SwUndoCpyTbl::SwUndoCpyTbl() + : SwUndo( UNDO_CPYTBL ), pDel( 0 ), nTblNode( 0 ) +{ +} + +SwUndoCpyTbl::~SwUndoCpyTbl() +{ + delete pDel; +} + +void SwUndoCpyTbl::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + SwTableNode* pTNd = rDoc.GetNodes()[ nTblNode ]->GetTableNode(); + + // harte SeitenUmbrueche am nachfolgenden Node verschieben + SwCntntNode* pNextNd = rDoc.GetNodes()[ pTNd->EndOfSectionIndex()+1 ]->GetCntntNode(); + if( pNextNd ) + { + SwFrmFmt* pTableFmt = pTNd->GetTable().GetFrmFmt(); + const SfxPoolItem *pItem; + + if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_PAGEDESC, + sal_False, &pItem ) ) + pNextNd->SetAttr( *pItem ); + + if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_BREAK, + sal_False, &pItem ) ) + pNextNd->SetAttr( *pItem ); + } + + SwPaM aPam( *pTNd, *pTNd->EndOfSectionNode(), 0 , 1 ); + pDel = new SwUndoDelete( aPam, sal_True ); +} + +void SwUndoCpyTbl::RedoImpl(::sw::UndoRedoContext & rContext) +{ + pDel->UndoImpl(rContext); + delete pDel, pDel = 0; +} + + +////////////////////////////////////////////////////////////////////////// + +SwUndoSplitTbl::SwUndoSplitTbl( const SwTableNode& rTblNd, + SwSaveRowSpan* pRowSp, sal_uInt16 eMode, sal_Bool bNewSize ) + : SwUndo( UNDO_SPLIT_TABLE ), + nTblNode( rTblNd.GetIndex() ), nOffset( 0 ), mpSaveRowSpan( pRowSp ), pSavTbl( 0 ), + pHistory( 0 ), nMode( eMode ), nFmlEnd( 0 ), bCalcNewSize( bNewSize ) +{ + switch( nMode ) + { + case HEADLINE_BOXATRCOLLCOPY: + pHistory = new SwHistory; + // kein break; + case HEADLINE_BORDERCOPY: + case HEADLINE_BOXATTRCOPY: + pSavTbl = new _SaveTable( rTblNd.GetTable(), 1, sal_False ); + break; + } +} + +SwUndoSplitTbl::~SwUndoSplitTbl() +{ + delete pSavTbl; + delete pHistory; + delete mpSaveRowSpan; +} + +void SwUndoSplitTbl::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc *const pDoc = & rContext.GetDoc(); + SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor()); + + pPam->DeleteMark(); + SwNodeIndex& rIdx = pPam->GetPoint()->nNode; + rIdx = nTblNode + nOffset; + + //Den implizit erzeugten Absatz wieder entfernen. + pDoc->GetNodes().Delete( rIdx, 1 ); + + rIdx = nTblNode + nOffset; + SwTableNode* pTblNd = rIdx.GetNode().GetTableNode(); + SwTable& rTbl = pTblNd->GetTable(); + + SwTableFmlUpdate aMsgHnt( &rTbl ); + aMsgHnt.eFlags = TBL_BOXPTR; + pDoc->UpdateTblFlds( &aMsgHnt ); + + switch( nMode ) + { + case HEADLINE_BOXATRCOLLCOPY: + if( pHistory ) + pHistory->TmpRollback( pDoc, nFmlEnd ); + + // kein break + case HEADLINE_BOXATTRCOPY: + case HEADLINE_BORDERCOPY: + { + pSavTbl->CreateNew( rTbl, sal_False ); + pSavTbl->RestoreAttr( rTbl ); + } + break; + + case HEADLINE_CNTNTCOPY: + // die erzeugte 1. Line muss wieder entfernt werden + { + SwSelBoxes aSelBoxes; + SwTableBox* pBox = rTbl.GetTblBox( nTblNode + nOffset + 1 ); + rTbl.SelLineFromBox( pBox, aSelBoxes, sal_True ); + _FndBox aTmpBox( 0, 0 ); + aTmpBox.SetTableLines( aSelBoxes, rTbl ); + aTmpBox.DelFrms( rTbl ); + rTbl.DeleteSel( pDoc, aSelBoxes, 0, 0, sal_False, sal_False ); + } + break; + } + + pDoc->GetNodes().MergeTable( rIdx ); + + if( pHistory ) + { + pHistory->TmpRollback( pDoc, 0 ); + pHistory->SetTmpEnd( pHistory->Count() ); + } + if( mpSaveRowSpan ) + { + pTblNd = rIdx.GetNode().FindTableNode(); + if( pTblNd ) + pTblNd->GetTable().RestoreRowSpan( *mpSaveRowSpan ); + } + ClearFEShellTabCols(); +} + +void SwUndoSplitTbl::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc *const pDoc = & rContext.GetDoc(); + SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor()); + + pPam->DeleteMark(); + pPam->GetPoint()->nNode = nTblNode; + pDoc->SplitTable( *pPam->GetPoint(), nMode, bCalcNewSize ); + + ClearFEShellTabCols(); +} + +void SwUndoSplitTbl::RepeatImpl(::sw::RepeatContext & rContext) +{ + SwPaM *const pPam = & rContext.GetRepeatPaM(); + SwDoc *const pDoc = & rContext.GetDoc(); + + pDoc->SplitTable( *pPam->GetPoint(), nMode, bCalcNewSize ); + ClearFEShellTabCols(); +} + +void SwUndoSplitTbl::SaveFormula( SwHistory& rHistory ) +{ + if( !pHistory ) + pHistory = new SwHistory; + + nFmlEnd = rHistory.Count(); + pHistory->Move( 0, &rHistory ); +} + + +////////////////////////////////////////////////////////////////////////// + +SwUndoMergeTbl::SwUndoMergeTbl( const SwTableNode& rTblNd, + const SwTableNode& rDelTblNd, + sal_Bool bWithPrv, sal_uInt16 nMd ) + : SwUndo( UNDO_MERGE_TABLE ), pSavTbl( 0 ), + pHistory( 0 ), nMode( nMd ), bWithPrev( bWithPrv ) +{ + // Endnode der letzen Tabellenzelle merken, die auf der Position verbleibt + if( bWithPrev ) + nTblNode = rDelTblNd.EndOfSectionIndex() - 1; + else + nTblNode = rTblNd.EndOfSectionIndex() - 1; + + aName = rDelTblNd.GetTable().GetFrmFmt()->GetName(); + pSavTbl = new _SaveTable( rDelTblNd.GetTable() ); + + pSavHdl = bWithPrev ? new _SaveTable( rTblNd.GetTable(), 1 ) : 0; +} + +SwUndoMergeTbl::~SwUndoMergeTbl() +{ + delete pSavTbl; + delete pSavHdl; + delete pHistory; +} + +void SwUndoMergeTbl::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc *const pDoc = & rContext.GetDoc(); + SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor()); + + pPam->DeleteMark(); + SwNodeIndex& rIdx = pPam->GetPoint()->nNode; + rIdx = nTblNode; + + SwTableNode* pTblNd = rIdx.GetNode().FindTableNode(); + SwTable* pTbl = &pTblNd->GetTable(); + + SwTableFmlUpdate aMsgHnt( pTbl ); + aMsgHnt.eFlags = TBL_BOXPTR; + pDoc->UpdateTblFlds( &aMsgHnt ); + + //Lines fuer das Layout-Update herausuchen. + _FndBox aFndBox( 0, 0 ); + aFndBox.SetTableLines( *pTbl ); + aFndBox.DelFrms( *pTbl ); + // ? TL_CHART2: notification or locking of controller required ? + + SwTableNode* pNew = pDoc->GetNodes().SplitTable( rIdx, sal_True, sal_False ); + + //Layout updaten + aFndBox.MakeFrms( *pTbl ); + // ? TL_CHART2: notification or locking of controller required ? + + if( bWithPrev ) + { + // den Namen umsetzen + pNew->GetTable().GetFrmFmt()->SetName( pTbl->GetFrmFmt()->GetName() ); + pSavHdl->RestoreAttr( pNew->GetTable() ); + } + else + pTbl = &pNew->GetTable(); + pTbl->GetFrmFmt()->SetName( aName ); + +// pSavTbl->CreateNew( *pTbl, sal_False ); + pSavTbl->RestoreAttr( *pTbl ); + + + if( pHistory ) + { + pHistory->TmpRollback( pDoc, 0 ); + pHistory->SetTmpEnd( pHistory->Count() ); + } + + // fuer die neue Tabelle die Frames anlegen + SwNodeIndex aTmpIdx( *pNew ); + pNew->MakeFrms( &aTmpIdx ); + + // Cursor irgendwo in den Content stellen + SwCntntNode* pCNd = pDoc->GetNodes().GoNext( &rIdx ); + pPam->GetPoint()->nContent.Assign( pCNd, 0 ); + + ClearFEShellTabCols(); + + // TL_CHART2: need to inform chart of probably changed cell names + SwChartDataProvider *pPCD = pDoc->GetChartDataProvider(); + if (pPCD) + { + pDoc->UpdateCharts( pTbl->GetFrmFmt()->GetName() ); + pDoc->UpdateCharts( pNew->GetTable().GetFrmFmt()->GetName() ); + } +} + +void SwUndoMergeTbl::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc *const pDoc = & rContext.GetDoc(); + SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor()); + + pPam->DeleteMark(); + pPam->GetPoint()->nNode = nTblNode; + if( bWithPrev ) + pPam->GetPoint()->nNode = nTblNode + 3; + else + pPam->GetPoint()->nNode = nTblNode; + + pDoc->MergeTable( *pPam->GetPoint(), bWithPrev, nMode ); + + ClearFEShellTabCols(); +} + +void SwUndoMergeTbl::RepeatImpl(::sw::RepeatContext & rContext) +{ + SwDoc *const pDoc = & rContext.GetDoc(); + SwPaM *const pPam = & rContext.GetRepeatPaM(); + + pDoc->MergeTable( *pPam->GetPoint(), bWithPrev, nMode ); + ClearFEShellTabCols(); +} + +void SwUndoMergeTbl::SaveFormula( SwHistory& rHistory ) +{ + if( !pHistory ) + pHistory = new SwHistory; + pHistory->Move( 0, &rHistory ); +} + + +////////////////////////////////////////////////////////////////////////// + +void InsertSort( SvUShorts& rArr, sal_uInt16 nIdx, sal_uInt16* pInsPos ) +{ + sal_uInt16 nO = rArr.Count(), nM, nU = 0; + if( nO > 0 ) + { + nO--; + while( nU <= nO ) + { + nM = nU + ( nO - nU ) / 2; + if( *(rArr.GetData() + nM) == nIdx ) + { + OSL_FAIL( "Index already exists. This should never happen." ); + return; + } + if( *(rArr.GetData() + nM) < nIdx ) + nU = nM + 1; + else if( nM == 0 ) + break; + else + nO = nM - 1; + } + } + rArr.Insert( nIdx, nU ); + if( pInsPos ) + *pInsPos = nU; +} + +void InsertSort( SvULongs& rArr, sal_uLong nIdx, sal_uInt16* pInsPos ) +{ + sal_uInt16 nO = rArr.Count(), nM, nU = 0; + if( nO > 0 ) + { + nO--; + while( nU <= nO ) + { + nM = nU + ( nO - nU ) / 2; + if( *(rArr.GetData() + nM) == nIdx ) + { + OSL_FAIL( "Index ist schon vorhanden, darf nie sein!" ); + return; + } + if( *(rArr.GetData() + nM) < nIdx ) + nU = nM + 1; + else if( nM == 0 ) + break; + else + nO = nM - 1; + } + } + rArr.Insert( nIdx, nU ); + if( pInsPos ) + *pInsPos = nU; +} + +#if OSL_DEBUG_LEVEL > 1 + + +void CheckTable( const SwTable& rTbl ) +{ + const SwNodes& rNds = rTbl.GetFrmFmt()->GetDoc()->GetNodes(); + const SwTableSortBoxes& rSrtArr = rTbl.GetTabSortBoxes(); + for( sal_uInt16 n = 0; n < rSrtArr.Count(); ++n ) + { + const SwTableBox* pBox = rSrtArr[ n ]; + const SwNode* pNd = pBox->GetSttNd(); + OSL_ENSURE( rNds[ pBox->GetSttIdx() ] == pNd, "Box mit falchem StartNode" ); + } +} +#endif + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/undo/untblk.cxx b/sw/source/core/undo/untblk.cxx new file mode 100644 index 000000000000..ca6f3359ab53 --- /dev/null +++ b/sw/source/core/undo/untblk.cxx @@ -0,0 +1,357 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <hintids.hxx> +#include <fmtanchr.hxx> +#include <frmfmt.hxx> +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <docary.hxx> +#include <swundo.hxx> // fuer die UndoIds +#include <pam.hxx> +#include <ndtxt.hxx> +#include <UndoCore.hxx> +#include <rolbck.hxx> +#include <redline.hxx> + + + +SwUndoInserts::SwUndoInserts( SwUndoId nUndoId, const SwPaM& rPam ) + : SwUndo( nUndoId ), SwUndRng( rPam ), + pTxtFmtColl( 0 ), pLastNdColl(0), pFrmFmts( 0 ), pRedlData( 0 ), + bSttWasTxtNd( sal_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 !! + { + sal_uInt16 nArrLen = pDoc->GetSpzFrmFmts()->Count(); + for( sal_uInt16 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, sal_Bool bScanFlys, + sal_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 = sal_False; + } + } + + if( bScanFlys && !nSttCntnt ) + { + // dann alle neuen Flys zusammen sammeln !! + SwDoc* pDoc = (SwDoc*)rPam.GetDoc(); + sal_uInt16 nFndPos, nArrLen = pDoc->GetSpzFrmFmts()->Count(); + for( sal_uInt16 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 ) ) ) + { + ::boost::shared_ptr<SwUndoInsLayFmt> const pFlyUndo( + new SwUndoInsLayFmt(pFmt, 0, 0)); + m_FlyUndos.push_back(pFlyUndo); + } + else + pFrmFmts->Remove( nFndPos ); + } + } + delete pFrmFmts, pFrmFmts = 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(); + OSL_ENSURE( 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 pRedlData; +} + + +void SwUndoInserts::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc *const pDoc = & rContext.GetDoc(); + SwPaM *const pPam = & AddUndoRedoPaM(rContext); + + if( IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() )) + pDoc->DeleteRedline( *pPam, true, USHRT_MAX ); + + // sind an Point/Mark 2 unterschiedliche TextNodes, dann muss ein + // JoinNext ausgefuehrt werden. + sal_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, sal_False ); + SetPaM(*pPam); + + // 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 (m_FlyUndos.size()) + { + sal_uLong nTmp = pPam->GetPoint()->nNode.GetIndex(); + for (size_t n = m_FlyUndos.size(); 0 < n; --n) + { + m_FlyUndos[ n-1 ]->UndoImpl(rContext); + } + 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 ); + } + } +} + +void SwUndoInserts::RedoImpl(::sw::UndoRedoContext & rContext) +{ + // setze noch den Cursor auf den Redo-Bereich + SwPaM *const pPam = & AddUndoRedoPaM(rContext); + 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 ) + { + sal_Bool bMvBkwrd = MovePtBackward( *pPam ); + + // Inhalt wieder einfuegen. (erst pPos abmelden !!) + sal_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 ); + } + + for (size_t n = m_FlyUndos.size(); 0 < n; --n) + { + m_FlyUndos[ n-1 ]->RedoImpl(rContext); + } + + 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::RepeatImpl(::sw::RepeatContext & rContext) +{ + SwPaM aPam( rContext.GetDoc().GetNodes().GetEndOfContent() ); + SetPaM( aPam ); + SwPaM & rRepeatPaM( rContext.GetRepeatPaM() ); + aPam.GetDoc()->CopyRange( aPam, *rRepeatPaM.GetPoint(), false ); +} + + +////////////////////////////////////////////////////////////////////////// + +SwUndoInsDoc::SwUndoInsDoc( const SwPaM& rPam ) + : SwUndoInserts( UNDO_INSDOKUMENT, rPam ) +{ +} + +SwUndoCpyDoc::SwUndoCpyDoc( const SwPaM& rPam ) + : SwUndoInserts( UNDO_COPY, rPam ) +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |