diff options
Diffstat (limited to 'sw/source/core/doc/docbm.cxx')
-rw-r--r-- | sw/source/core/doc/docbm.cxx | 1747 |
1 files changed, 1747 insertions, 0 deletions
diff --git a/sw/source/core/doc/docbm.cxx b/sw/source/core/doc/docbm.cxx new file mode 100644 index 000000000000..0080694722ba --- /dev/null +++ b/sw/source/core/doc/docbm.cxx @@ -0,0 +1,1747 @@ +/************************************************************************* + * + * 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 <MarkManager.hxx> +#include <bookmrk.hxx> +#include <boost/bind.hpp> +#include <cntfrm.hxx> +#include <crossrefbookmark.hxx> +#include <dcontact.hxx> +#include <doc.hxx> +#include <docary.hxx> +#include <xmloff/odffields.hxx> +#include <editsh.hxx> +#include <errhdl.hxx> +#include <fmtanchr.hxx> +#include <frmfmt.hxx> +#include <functional> +#include <hintids.hxx> +#include <mvsave.hxx> +#include <ndtxt.hxx> +#include <node.hxx> +#include <pam.hxx> +#include <redline.hxx> +#include <rolbck.hxx> +#include <rtl/ustrbuf.hxx> +#include <rtl/ustring.hxx> +#include <sal/types.h> +#include <sortedobjs.hxx> +#include <sfx2/linkmgr.hxx> +#include <swserv.hxx> +#include <swundo.hxx> +#include <tools/pstm.hxx> +#include <undobj.hxx> +#include <unocrsr.hxx> +#include <viscrs.hxx> +#include <stdio.h> + + +using namespace ::std; +using namespace ::boost; +using namespace ::sw::mark; + +namespace +{ + static bool lcl_GreaterThan( const SwPosition& rPos, const SwNodeIndex& rNdIdx, const SwIndex* pIdx ) + { + return pIdx ? ( rPos.nNode > rNdIdx || ( rPos.nNode == rNdIdx && rPos.nContent >= pIdx->GetIndex() )) : rPos.nNode >= rNdIdx; + } + + static bool lcl_Lower( const SwPosition& rPos, const SwNodeIndex& rNdIdx, const SwIndex* pIdx ) + { + return rPos.nNode < rNdIdx || ( pIdx && rPos.nNode == rNdIdx && rPos.nContent < pIdx->GetIndex() ); + } + + static bool lcl_MarkOrderingByStart(const IDocumentMarkAccess::pMark_t& rpFirst, + const IDocumentMarkAccess::pMark_t& rpSecond) + { + return rpFirst->GetMarkStart() < rpSecond->GetMarkStart(); + } + + static bool lcl_MarkOrderingByEnd(const IDocumentMarkAccess::pMark_t& rpFirst, + const IDocumentMarkAccess::pMark_t& rpSecond) + { + return rpFirst->GetMarkEnd() < rpSecond->GetMarkEnd(); + } + + static void lcl_InsertMarkSorted(IDocumentMarkAccess::container_t& io_vMarks, + const IDocumentMarkAccess::pMark_t& pMark) + { + io_vMarks.insert( + lower_bound( + io_vMarks.begin(), + io_vMarks.end(), + pMark, + &lcl_MarkOrderingByStart), + pMark); + } + + static inline auto_ptr<SwPosition> lcl_PositionFromCntntNode(SwCntntNode * const pCntntNode, const bool bAtEnd=false) + { + auto_ptr<SwPosition> pResult(new SwPosition(*pCntntNode)); + pResult->nContent.Assign(pCntntNode, bAtEnd ? pCntntNode->Len() : 0); + return pResult; + } + + // return a position at the begin of rEnd, if it is a CntntNode + // else set it to the begin of the Node after rEnd, if there is one + // else set it to the end of the node before rStt + // else set it to the CntntNode of the Pos outside the Range + static inline auto_ptr<SwPosition> lcl_FindExpelPosition(const SwNodeIndex& rStt, + const SwNodeIndex& rEnd, + const SwPosition& rOtherPosition) + { + SwCntntNode * pNode = rEnd.GetNode().GetCntntNode(); + SwNodeIndex aStt = SwNodeIndex(rStt); + SwNodeIndex aEnd = SwNodeIndex(rEnd); + bool bAtEnd = false; + if(!pNode) + pNode = rEnd.GetNodes().GoNext(&aEnd), bAtEnd = false; + if(!pNode) + pNode = rStt.GetNodes().GoPrevious(&aStt), bAtEnd = true; + if(pNode) + return lcl_PositionFromCntntNode(pNode, bAtEnd); + return auto_ptr<SwPosition>(new SwPosition(rOtherPosition)); + }; + + static IMark* lcl_getMarkAfter(const IDocumentMarkAccess::container_t& rMarks, const SwPosition& rPos) + { + IDocumentMarkAccess::const_iterator_t pMarkAfter = upper_bound( + rMarks.begin(), + rMarks.end(), + rPos, + bind(&IMark::StartsAfter, _2, _1)); // finds the first that is starting after + if(pMarkAfter == rMarks.end()) return NULL; + return pMarkAfter->get(); + }; + + static IMark* lcl_getMarkBefore(const IDocumentMarkAccess::container_t& rMarks, const SwPosition& rPos) + { + // candidates from which to choose the mark before + IDocumentMarkAccess::container_t vCandidates; + // no need to consider marks starting after rPos + IDocumentMarkAccess::const_iterator_t pCandidatesEnd = upper_bound( + rMarks.begin(), + rMarks.end(), + rPos, + bind(&IMark::StartsAfter, _2, _1)); + vCandidates.reserve(pCandidatesEnd - rMarks.begin()); + // only marks ending before are candidates + remove_copy_if( + rMarks.begin(), + pCandidatesEnd, + back_inserter(vCandidates), + bind(logical_not<bool>(), bind(&IMark::EndsBefore, _1, rPos))); + // no candidate left => we are in front of the first mark or there are none + if(!vCandidates.size()) return NULL; + // return the highest (last) candidate using mark end ordering + return max_element(vCandidates.begin(), vCandidates.end(), &lcl_MarkOrderingByEnd)->get(); + } + + static bool lcl_FixCorrectedMark(bool bChangedPos, bool bChangedOPos, MarkBase* io_pMark) + { + if( (bChangedPos || bChangedOPos) && io_pMark->IsExpanded() && + io_pMark->GetOtherMarkPos().nNode.GetNode().FindTableBoxStartNode() != + io_pMark->GetMarkPos().nNode.GetNode().FindTableBoxStartNode() ) + { + if(!bChangedOPos) + io_pMark->SetMarkPos(io_pMark->GetOtherMarkPos()); + io_pMark->ClearOtherMarkPos(); + DdeBookmark * const pDdeBkmk = dynamic_cast< DdeBookmark*>(io_pMark); + if(pDdeBkmk && pDdeBkmk->IsServer()) + pDdeBkmk->SetRefObject(NULL); + return true; + } + return false; + } + + static IDocumentMarkAccess::iterator_t lcl_FindMark( + IDocumentMarkAccess::container_t& rMarks, + const IDocumentMarkAccess::pMark_t& rpMarkToFind) + { + IDocumentMarkAccess::iterator_t ppCurrentMark = lower_bound( + rMarks.begin(), rMarks.end(), + rpMarkToFind, &lcl_MarkOrderingByStart); + // since there are usually not too many marks on the same start + // position, we are not doing a bisect search for the upper bound + // but instead start to iterate from pMarkLow directly + while(ppCurrentMark != rMarks.end() && **ppCurrentMark == *rpMarkToFind) + { + if(ppCurrentMark->get() == rpMarkToFind.get()) + { + //OSL_TRACE("found mark named '%s'", + // ::rtl::OUStringToOString(ppCurrentMark->get()->GetName(), RTL_TEXTENCODING_UTF8).getStr()); + return ppCurrentMark; + } + ++ppCurrentMark; + } + // reached a mark starting on a later start pos or the end of the + // vector => not found + return rMarks.end(); + }; + + static IDocumentMarkAccess::iterator_t lcl_FindMarkAtPos( + IDocumentMarkAccess::container_t& rMarks, + const SwPosition& rPos, + const IDocumentMarkAccess::MarkType eType) + { + for(IDocumentMarkAccess::iterator_t ppCurrentMark = lower_bound( + rMarks.begin(), rMarks.end(), + rPos, + bind(&IMark::StartsBefore, _1, _2)); + ppCurrentMark != rMarks.end(); + ++ppCurrentMark) + { + // Once we reach a mark starting after the target pos + // we do not need to continue + if(ppCurrentMark->get()->StartsAfter(rPos)) + break; + if(IDocumentMarkAccess::GetType(**ppCurrentMark) == eType) + { + //OSL_TRACE("found mark named '%s'", + // ::rtl::OUStringToOString(ppCurrentMark->get()->GetName(), RTL_TEXTENCODING_UTF8).getStr()); + return ppCurrentMark; + } + } + // reached a mark starting on a later start pos or the end of the + // vector => not found + return rMarks.end(); + }; + + static IDocumentMarkAccess::const_iterator_t lcl_FindMarkByName( + const ::rtl::OUString& rName, + IDocumentMarkAccess::const_iterator_t ppMarksBegin, + IDocumentMarkAccess::const_iterator_t ppMarksEnd) + { + return find_if( + ppMarksBegin, + ppMarksEnd, + bind(&::rtl::OUString::equals, bind(&IMark::GetName, _1), rName)); + } + +#if FALSE + static void lcl_DebugMarks(IDocumentMarkAccess::container_t vMarks) + { + OSL_TRACE("%d Marks", vMarks.size()); + for(IDocumentMarkAccess::iterator_t ppMark = vMarks.begin(); + ppMark != vMarks.end(); + ppMark++) + { + IMark* pMark = ppMark->get(); + ::rtl::OString sName = ::rtl::OUStringToOString(pMark->GetName(), RTL_TEXTENCODING_UTF8); + const SwPosition* const pStPos = &pMark->GetMarkStart(); + const SwPosition* const pEndPos = &pMark->GetMarkEnd(); + OSL_TRACE("%s %s %d,%d %d,%d", + typeid(*pMark).name(), + sName.getStr(), + pStPos->nNode.GetIndex(), + pStPos->nContent.GetIndex(), + pEndPos->nNode.GetIndex(), + pEndPos->nContent.GetIndex()); + } + }; +#endif +} + +IDocumentMarkAccess::MarkType IDocumentMarkAccess::GetType(const IMark& rBkmk) +{ + const std::type_info* const pMarkTypeInfo = &typeid(rBkmk); + // not using dynamic_cast<> here for performance + if(*pMarkTypeInfo == typeid(UnoMark)) + return UNO_BOOKMARK; + else if(*pMarkTypeInfo == typeid(DdeBookmark)) + return DDE_BOOKMARK; + else if(*pMarkTypeInfo == typeid(Bookmark)) + return BOOKMARK; + else if(*pMarkTypeInfo == typeid(CrossRefHeadingBookmark)) + return CROSSREF_HEADING_BOOKMARK; + else if(*pMarkTypeInfo == typeid(CrossRefNumItemBookmark)) + return CROSSREF_NUMITEM_BOOKMARK; + else if(*pMarkTypeInfo == typeid(TextFieldmark)) + return TEXT_FIELDMARK; + else if(*pMarkTypeInfo == typeid(CheckboxFieldmark)) + return CHECKBOX_FIELDMARK; + else if(*pMarkTypeInfo == typeid(NavigatorReminder)) + return NAVIGATOR_REMINDER; + else + { + OSL_ENSURE(false, + "IDocumentMarkAccess::GetType(..)" + " - unknown MarkType. This needs to be fixed!"); + return UNO_BOOKMARK; + } +} + +namespace sw { namespace mark +{ + MarkManager::MarkManager(SwDoc& rDoc) + : m_pDoc(&rDoc) + { } + + void MarkManager::dumpFieldmarks( ) const + { + const_iterator_t pIt = m_vFieldmarks.begin(); + for (; pIt != m_vFieldmarks.end( ); pIt++) + { + rtl::OUString str = (*pIt)->ToString(); + OSL_TRACE("%s\n", + ::rtl::OUStringToOString(str, RTL_TEXTENCODING_UTF8).getStr()); + } + } + + ::sw::mark::IMark* MarkManager::makeMark(const SwPaM& rPaM, + const ::rtl::OUString& rName, + const IDocumentMarkAccess::MarkType eType) + { +#if FALSE + { + ::rtl::OString sName = ::rtl::OUStringToOString(rName, RTL_TEXTENCODING_UTF8); + const SwPosition* const pPos1 = rPaM.GetPoint(); + const SwPosition* pPos2 = pPos1; + if(rPaM.HasMark()) + pPos2 = rPaM.GetMark(); + OSL_TRACE("%s %d,%d %d,%d", + sName.getStr(), + pPos1->nNode.GetIndex(), + pPos1->nContent.GetIndex(), + pPos2->nNode.GetIndex(), + pPos2->nContent.GetIndex()); + } +#endif + // see for example _SaveCntntIdx, Shells + OSL_PRECOND(m_vMarks.size() < USHRT_MAX, + "MarkManager::makeMark(..)" + " - more than USHRT_MAX marks are not supported correctly"); + // There should only be one CrossRefBookmark per Textnode per Type + OSL_PRECOND( + (eType != CROSSREF_NUMITEM_BOOKMARK && eType != CROSSREF_HEADING_BOOKMARK) + || (lcl_FindMarkAtPos(m_vBookmarks, *rPaM.GetPoint(), eType) == m_vBookmarks.end()), + "MarkManager::makeMark(..)" + " - creating duplicate CrossRefBookmark"); + + // create mark + pMark_t pMark; + switch(eType) + { + case IDocumentMarkAccess::TEXT_FIELDMARK: + pMark = shared_ptr<IMark>(new TextFieldmark(rPaM)); + break; + case IDocumentMarkAccess::CHECKBOX_FIELDMARK: + pMark = shared_ptr<IMark>(new CheckboxFieldmark(rPaM)); + break; + case IDocumentMarkAccess::NAVIGATOR_REMINDER: + pMark = shared_ptr<IMark>(new NavigatorReminder(rPaM)); + break; + case IDocumentMarkAccess::BOOKMARK: + pMark = shared_ptr<IMark>(new Bookmark(rPaM, KeyCode(), rName, ::rtl::OUString())); + break; + case IDocumentMarkAccess::DDE_BOOKMARK: + pMark = shared_ptr<IMark>(new DdeBookmark(rPaM)); + break; + case IDocumentMarkAccess::CROSSREF_HEADING_BOOKMARK: + pMark = shared_ptr<IMark>(new CrossRefHeadingBookmark(rPaM, KeyCode(), rName, ::rtl::OUString())); + break; + case IDocumentMarkAccess::CROSSREF_NUMITEM_BOOKMARK: + pMark = shared_ptr<IMark>(new CrossRefNumItemBookmark(rPaM, KeyCode(), rName, ::rtl::OUString())); + break; + case IDocumentMarkAccess::UNO_BOOKMARK: + pMark = shared_ptr<IMark>(new UnoMark(rPaM)); + break; + } + OSL_ENSURE(pMark.get(), + "MarkManager::makeMark(..)" + " - Mark was not created."); + MarkBase* pMarkBase = dynamic_cast<MarkBase*>(pMark.get()); + + if(pMark->GetMarkPos() != pMark->GetMarkStart()) + pMarkBase->Swap(); + + // for performance reasons, we trust UnoMarks to have a (generated) unique name + if(eType != IDocumentMarkAccess::UNO_BOOKMARK) + pMarkBase->SetName(getUniqueMarkName(pMarkBase->GetName())); + + // register mark + lcl_InsertMarkSorted(m_vMarks, pMark); + switch(eType) + { + case IDocumentMarkAccess::BOOKMARK: + case IDocumentMarkAccess::CROSSREF_NUMITEM_BOOKMARK: + case IDocumentMarkAccess::CROSSREF_HEADING_BOOKMARK: + // if(dynamic_cast<IBookmark*>) + lcl_InsertMarkSorted(m_vBookmarks, pMark); + break; + case IDocumentMarkAccess::TEXT_FIELDMARK: + case IDocumentMarkAccess::CHECKBOX_FIELDMARK: + // if(dynamic_cast<IFieldmark*> + lcl_InsertMarkSorted(m_vFieldmarks, pMark); + break; + case IDocumentMarkAccess::NAVIGATOR_REMINDER: + case IDocumentMarkAccess::DDE_BOOKMARK: + case IDocumentMarkAccess::UNO_BOOKMARK: + // no special array for these + break; + } + pMarkBase->InitDoc(m_pDoc); +#if FALSE + OSL_TRACE("--- makeType ---"); + OSL_TRACE("Marks"); + lcl_DebugMarks(m_vMarks); + OSL_TRACE("Bookmarks"); + lcl_DebugMarks(m_vBookmarks); + OSL_TRACE("Fieldmarks"); + lcl_DebugMarks(m_vFieldmarks); +#endif + return pMark.get(); + } + + ::sw::mark::IFieldmark* MarkManager::makeFieldBookmark( const SwPaM& rPaM, + const rtl::OUString& rName, + const rtl::OUString& rType ) + { + sw::mark::IMark* pMark = makeMark( rPaM, rName, + IDocumentMarkAccess::TEXT_FIELDMARK ); + sw::mark::IFieldmark* pFieldMark = dynamic_cast<sw::mark::IFieldmark*>( pMark ); + pFieldMark->SetFieldname( rType ); + + return pFieldMark; + } + + ::sw::mark::IFieldmark* MarkManager::makeNoTextFieldBookmark( const SwPaM& rPaM, + const rtl::OUString& rName, + const rtl::OUString& rType) + { + sw::mark::IMark* pMark = makeMark( rPaM, rName, + IDocumentMarkAccess::CHECKBOX_FIELDMARK ); + sw::mark::IFieldmark* pFieldMark = dynamic_cast<sw::mark::IFieldmark*>( pMark ); + pFieldMark->SetFieldname( rType ); + + return pFieldMark; + } + + ::sw::mark::IMark* MarkManager::getMarkForTxtNode(const SwTxtNode& rTxtNode, + const IDocumentMarkAccess::MarkType eType) + { + SwPosition aPos(rTxtNode); + aPos.nContent.Assign(&(const_cast<SwTxtNode&>(rTxtNode)), 0); + const iterator_t ppExistingMark = lcl_FindMarkAtPos(m_vBookmarks, aPos, eType); + if(ppExistingMark != m_vBookmarks.end()) + return ppExistingMark->get(); + const SwPaM aPaM(aPos); + return makeMark(aPaM, ::rtl::OUString(), eType); + } + + void MarkManager::repositionMark( ::sw::mark::IMark* const io_pMark, + const SwPaM& rPaM) + { + OSL_PRECOND(io_pMark->GetMarkPos().GetDoc() == m_pDoc, + "<MarkManager::repositionMark(..)>" + " - Mark is not in my doc."); + MarkBase* const pMarkBase = dynamic_cast< MarkBase* >(io_pMark); + pMarkBase->SetMarkPos(*(rPaM.GetPoint())); + if(rPaM.HasMark()) + pMarkBase->SetOtherMarkPos(*(rPaM.GetMark())); + else + pMarkBase->ClearOtherMarkPos(); + + if(pMarkBase->GetMarkPos() != pMarkBase->GetMarkStart()) + pMarkBase->Swap(); + + sortMarks(); + } + + bool MarkManager::renameMark(::sw::mark::IMark* io_pMark, const ::rtl::OUString& rNewName) + { + OSL_PRECOND(io_pMark->GetMarkPos().GetDoc() == m_pDoc, + "<MarkManager::repositionMark(..)>" + " - Mark is not in my doc."); + if(io_pMark->GetName() == rNewName) + return true; + if(findMark(rNewName) != getMarksEnd()) + return false; + dynamic_cast< ::sw::mark::MarkBase* >(io_pMark)->SetName(rNewName); + return true; + } + + void MarkManager::correctMarksAbsolute(const SwNodeIndex& rOldNode, const SwPosition& rNewPos, const xub_StrLen nOffset) + { + const SwNode* const pOldNode = &rOldNode.GetNode(); + SwPosition aNewPos(rNewPos); + aNewPos.nContent += nOffset; + bool isSortingNeeded = false; + for(iterator_t ppMark = m_vMarks.begin(); + ppMark != m_vMarks.end(); + ppMark++) + { + // is on position ?? + bool bChangedPos = false, bChangedOPos = false; + ::sw::mark::MarkBase* pMark = dynamic_cast< ::sw::mark::MarkBase* >(ppMark->get()); + if(&pMark->GetMarkPos().nNode.GetNode() == pOldNode) + { + pMark->SetMarkPos(aNewPos); + bChangedPos = true; + } + if (pMark->IsExpanded() && + &pMark->GetOtherMarkPos().nNode.GetNode() == pOldNode) + { + pMark->SetMarkPos(aNewPos); + bChangedOPos= true; + } + // illegal selection? collapse the mark and restore sorting later + isSortingNeeded |= lcl_FixCorrectedMark(bChangedPos, bChangedOPos, pMark); + } + // restore sorting if needed + if(isSortingNeeded) + sortMarks(); +#if FALSE + OSL_TRACE("correctMarksAbsolute"); + lcl_DebugMarks(m_vMarks); +#endif + } + + void MarkManager::correctMarksRelative(const SwNodeIndex& rOldNode, const SwPosition& rNewPos, const xub_StrLen nOffset) + { + const SwNode* const pOldNode = &rOldNode.GetNode(); + SwPosition aNewPos(rNewPos); + aNewPos.nContent += nOffset; + bool isSortingNeeded = false; + for(iterator_t ppMark = m_vMarks.begin(); + ppMark != m_vMarks.end(); + ppMark++) + { + // is on position ?? + bool bChangedPos = false, bChangedOPos = false; + ::sw::mark::MarkBase* const pMark = dynamic_cast< ::sw::mark::MarkBase* >(ppMark->get()); + if(&pMark->GetMarkPos().nNode.GetNode() == pOldNode) + { + SwPosition aNewPosRel(aNewPos); + aNewPosRel.nContent += pMark->GetMarkPos().nContent.GetIndex(); + pMark->SetMarkPos(aNewPosRel); + bChangedPos = true; + } + if(pMark->IsExpanded() && + &pMark->GetOtherMarkPos().nNode.GetNode() == pOldNode) + { + SwPosition aNewPosRel(aNewPos); + aNewPosRel.nContent += pMark->GetOtherMarkPos().nContent.GetIndex(); + pMark->SetOtherMarkPos(aNewPosRel); + bChangedOPos = true; + } + // illegal selection? collapse the mark and restore sorting later + isSortingNeeded |= lcl_FixCorrectedMark(bChangedPos, bChangedOPos, pMark); + } + // restore sorting if needed + if(isSortingNeeded) + sortMarks(); +#if FALSE + OSL_TRACE("correctMarksRelative"); + lcl_DebugMarks(m_vMarks); +#endif + } + + void MarkManager::deleteMarks( + const SwNodeIndex& rStt, + const SwNodeIndex& rEnd, + ::std::vector<SaveBookmark>* pSaveBkmk, + const SwIndex* pSttIdx, + const SwIndex* pEndIdx ) + { + vector<const_iterator_t> vMarksToDelete; + bool isSortingNeeded = false; + // copy all bookmarks in the move area to a vector storing all position data as offset + // reassignment is performed after the move + for(iterator_t ppMark = m_vMarks.begin(); + ppMark != m_vMarks.end(); + ppMark++) + { + // navigator marks should not be moved + // TODO: Check if this might make them invalid + if(IDocumentMarkAccess::GetType(**ppMark) == NAVIGATOR_REMINDER) + continue; + + ::sw::mark::MarkBase* pMark = dynamic_cast< ::sw::mark::MarkBase* >(ppMark->get()); + // on position ?? + bool isPosInRange = (lcl_GreaterThan(pMark->GetMarkPos(), rStt, pSttIdx) && + lcl_Lower(pMark->GetMarkPos(), rEnd, pEndIdx)); + bool isOtherPosInRange = (pMark->IsExpanded() && + lcl_GreaterThan(pMark->GetOtherMarkPos(), rStt, pSttIdx) && + lcl_Lower(pMark->GetOtherMarkPos(), rEnd, pEndIdx)); + // special case: completely in range, touching the end? + if(pEndIdx && + ((isOtherPosInRange + && pMark->GetMarkPos().nNode == rEnd + && pMark->GetMarkPos().nContent == *pEndIdx) + || (isPosInRange + && pMark->IsExpanded() + && pMark->GetOtherMarkPos().nNode == rEnd + && pMark->GetOtherMarkPos().nContent == *pEndIdx))) + { + isPosInRange = true, isOtherPosInRange = true; + } + + if(isPosInRange && (isOtherPosInRange || !pMark->IsExpanded())) + { + // completely in range + + // --> OD 2009-08-07 #i92125# + bool bKeepCrossRefBkmk( false ); + { + if ( rStt == rEnd && + ( IDocumentMarkAccess::GetType(*pMark) == + IDocumentMarkAccess::CROSSREF_HEADING_BOOKMARK || + IDocumentMarkAccess::GetType(*pMark) == + IDocumentMarkAccess::CROSSREF_NUMITEM_BOOKMARK ) ) + { + bKeepCrossRefBkmk = true; + } + } + if ( !bKeepCrossRefBkmk ) + { + if(pSaveBkmk) + pSaveBkmk->push_back(SaveBookmark(true, true, *pMark, rStt, pSttIdx)); + vMarksToDelete.push_back(ppMark); + } + // <-- + } + else if(isPosInRange ^ isOtherPosInRange) + { + // the bookmark is partitially in the range + // move position of that is in the range out of it + auto_ptr<SwPosition> pNewPos; + if(pEndIdx) + pNewPos = auto_ptr<SwPosition>(new SwPosition( + rEnd, + *pEndIdx)); + else + pNewPos = lcl_FindExpelPosition( + rStt, + rEnd, + isPosInRange ? pMark->GetOtherMarkPos() : pMark->GetMarkPos()); + + // --> OD 2009-08-06 #i92125# + // no move of position for cross-reference bookmarks, + // if move occurs inside a certain node + if ( ( IDocumentMarkAccess::GetType(*pMark) != + IDocumentMarkAccess::CROSSREF_HEADING_BOOKMARK && + IDocumentMarkAccess::GetType(*pMark) != + IDocumentMarkAccess::CROSSREF_NUMITEM_BOOKMARK ) || + pMark->GetMarkPos().nNode != pNewPos->nNode ) + { + if(isPosInRange) + pMark->SetMarkPos(*pNewPos); + else + pMark->SetOtherMarkPos(*pNewPos); + + // illegal selection? collapse the mark and restore sorting later + isSortingNeeded |= lcl_FixCorrectedMark(isPosInRange, isOtherPosInRange, pMark); + } + // <-- + } + } + + // we just remembered the iterators to delete, so we do not need to search + // for the shared_ptr<> (the entry in m_vMarks) again + // reverse iteration, since erasing an entry invalidates iterators + // behind it (the iterators in vMarksToDelete are sorted) + for(vector<const_iterator_t>::reverse_iterator pppMark = vMarksToDelete.rbegin(); + pppMark != vMarksToDelete.rend(); + pppMark++) + { + deleteMark(*pppMark); + } + if(isSortingNeeded) + sortMarks(); +#if FALSE + OSL_TRACE("deleteMarks"); + lcl_DebugMarks(m_vMarks); +#endif + } + + void MarkManager::deleteMark(const const_iterator_t ppMark) + { + if(ppMark == m_vMarks.end()) return; + + switch(IDocumentMarkAccess::GetType(**ppMark)) + { + case IDocumentMarkAccess::BOOKMARK: + case IDocumentMarkAccess::CROSSREF_HEADING_BOOKMARK: + case IDocumentMarkAccess::CROSSREF_NUMITEM_BOOKMARK: + // if(dynamic_cast<IBookmark*>) + { + IDocumentMarkAccess::iterator_t ppBookmark = lcl_FindMark(m_vBookmarks, *ppMark); + OSL_ENSURE(ppBookmark != m_vBookmarks.end(), + "<MarkManager::deleteMark(..)>" + " - Bookmark not found."); + m_vBookmarks.erase(ppBookmark); + break; + } + case IDocumentMarkAccess::TEXT_FIELDMARK: + case IDocumentMarkAccess::CHECKBOX_FIELDMARK: + // if(dynamic_cast<IFieldmark*> + { + IDocumentMarkAccess::iterator_t ppFieldmark = lcl_FindMark(m_vFieldmarks, *ppMark); + OSL_ENSURE(ppFieldmark != m_vFieldmarks.end(), + "<MarkManager::deleteMark(..)>" + " - Bookmark not found."); + m_vFieldmarks.erase(ppFieldmark); + break; + } + case IDocumentMarkAccess::NAVIGATOR_REMINDER: + case IDocumentMarkAccess::DDE_BOOKMARK: + case IDocumentMarkAccess::UNO_BOOKMARK: + // no special array for these + break; + } + DdeBookmark* const pDdeBookmark = dynamic_cast<DdeBookmark*>(ppMark->get()); + if(pDdeBookmark) + pDdeBookmark->DeregisterFromDoc(m_pDoc); + m_vMarks.erase(m_vMarks.begin() + (ppMark - m_vMarks.begin())); // clumsy const-cast + } + + void MarkManager::deleteMark(const IMark* const pMark) + { + OSL_PRECOND(pMark->GetMarkPos().GetDoc() == m_pDoc, + "<MarkManager::repositionMark(..)>" + " - Mark is not in my doc."); + // finds the last Mark that is starting before pMark + // (pMarkLow < pMark) + iterator_t pMarkLow = lower_bound( + m_vMarks.begin(), m_vMarks.end(), + pMark->GetMarkStart(), + bind(&IMark::StartsBefore, _1, _2)); + // finds the first Mark that pMark is starting before + // (pMark < pMarkHigh) + //iterator_t pMarkHigh = upper_bound( + // pMarkLow, m_vMarks.end(), + // pMark->GetMarkStart(), + // bind(&IMark::StartsBefore, _2, _1)); + // since it should be rare that pMark isnt found at all + // we skip the bisect search on the upper bound + iterator_t pMarkHigh = m_vMarks.end(); + iterator_t pMarkFound = find_if( + pMarkLow, pMarkHigh, + bind(equal_to<const IMark*>(), bind(&shared_ptr<IMark>::get, _1), pMark)); + if(pMarkFound != pMarkHigh) + deleteMark(pMarkFound); + } + + void MarkManager::clearAllMarks() + { + m_vFieldmarks.clear(); + m_vBookmarks.clear(); +#ifdef DEBUG + for(iterator_t pBkmk = m_vMarks.begin(); + pBkmk != m_vMarks.end(); + ++pBkmk) + OSL_ENSURE(pBkmk->unique(), + "<MarkManager::clearAllMarks(..)>" + " - a Bookmark is still in use."); +#endif + m_vMarks.clear(); + } + + IDocumentMarkAccess::const_iterator_t MarkManager::findMark(const ::rtl::OUString& rName) const + { + return lcl_FindMarkByName(rName, m_vMarks.begin(), m_vMarks.end()); + } + + IDocumentMarkAccess::const_iterator_t MarkManager::findBookmark(const ::rtl::OUString& rName) const + { + return lcl_FindMarkByName(rName, m_vBookmarks.begin(), m_vBookmarks.end()); + } + + IDocumentMarkAccess::const_iterator_t MarkManager::getMarksBegin() const + { return m_vMarks.begin(); } + + IDocumentMarkAccess::const_iterator_t MarkManager::getMarksEnd() const + { return m_vMarks.end(); } + + sal_Int32 MarkManager::getMarksCount() const + { return m_vMarks.size(); } + + IDocumentMarkAccess::const_iterator_t MarkManager::getBookmarksBegin() const + { return m_vBookmarks.begin(); } + + IDocumentMarkAccess::const_iterator_t MarkManager::getBookmarksEnd() const + { return m_vBookmarks.end(); } + + sal_Int32 MarkManager::getBookmarksCount() const + { return m_vBookmarks.size(); } + + IFieldmark* MarkManager::getFieldmarkFor(const SwPosition& rPos) const + { + const_iterator_t pFieldmark = find_if( + m_vFieldmarks.begin(), + m_vFieldmarks.end( ), + bind(&IMark::IsCoveringPosition, _1, rPos)); + if(pFieldmark == m_vFieldmarks.end()) return NULL; + return dynamic_cast<IFieldmark*>(pFieldmark->get()); + } + + IFieldmark* MarkManager::getFieldmarkAfter(const SwPosition& rPos) const + { return dynamic_cast<IFieldmark*>(lcl_getMarkAfter(m_vFieldmarks, rPos)); } + + IFieldmark* MarkManager::getFieldmarkBefore(const SwPosition& rPos) const + { return dynamic_cast<IFieldmark*>(lcl_getMarkBefore(m_vFieldmarks, rPos)); } + + ::rtl::OUString MarkManager::getUniqueMarkName(const ::rtl::OUString& rName) const + { + OSL_ENSURE(rName.getLength(), + "<MarkManager::getUniqueMarkName(..)>" + " - a name should be proposed"); + if(findMark(rName) == getMarksEnd()) return rName; + ::rtl::OUStringBuffer sBuf; + ::rtl::OUString sTmp; + for(sal_Int32 nCnt = 1; nCnt < SAL_MAX_INT32; nCnt++) + { + sTmp = sBuf.append(rName).append(nCnt).makeStringAndClear(); + if(findMark(sTmp) == getMarksEnd()) break; + } + return sTmp; + } + + void MarkManager::sortMarks() + { + sort(m_vMarks.begin(), m_vMarks.end(), &lcl_MarkOrderingByStart); + sort(m_vBookmarks.begin(), m_vBookmarks.end(), &lcl_MarkOrderingByStart); + sort(m_vFieldmarks.begin(), m_vFieldmarks.end(), &lcl_MarkOrderingByStart); + } + +}} // namespace ::sw::mark + + +// old implementation + +//SV_IMPL_OP_PTRARR_SORT(SwBookmarks, SwBookmarkPtr) + +#define PCURCRSR (_pCurrCrsr) +#define FOREACHPAM_START(pSttCrsr) \ + {\ + SwPaM *_pStartCrsr = pSttCrsr, *_pCurrCrsr = pSttCrsr; \ + do { + +#define FOREACHPAM_END() \ + } while( (_pCurrCrsr=(SwPaM *)_pCurrCrsr->GetNext()) != _pStartCrsr ); \ + } +#define PCURSH ((SwCrsrShell*)_pStartShell) +#define FOREACHSHELL_START( pEShell ) \ + {\ + ViewShell *_pStartShell = pEShell; \ + do { \ + if( _pStartShell->IsA( TYPE( SwCrsrShell )) ) \ + { + +#define FOREACHSHELL_END( pEShell ) \ + } \ + } while((_pStartShell=(ViewShell*)_pStartShell->GetNext())!= pEShell ); \ + } + +namespace +{ + // Aufbau vom Array: 2 longs, + // 1. Long enthaelt Type und Position im DocArray, + // 2. die ContentPosition + // + // CntntType -- + // 0x8000 = Bookmark Pos1 + // 0x8001 = Bookmark Pos2 + // 0x2000 = Absatzgebundener Rahmen + // 0x2001 = Auto-Absatzgebundener Rahmen, der umgehaengt werden soll + // 0x1000 = Redline Mark + // 0x1001 = Redline Point + // 0x0800 = Crsr aus der CrsrShell Mark + // 0x0801 = Crsr aus der CrsrShell Point + // 0x0400 = UnoCrsr Mark + // 0x0401 = UnoCrsr Point + // + + class _SwSaveTypeCountContent + { + union { + struct { USHORT nType, nCount; } TC; + ULONG nTypeCount; + } TYPECOUNT; + xub_StrLen nContent; + + public: + _SwSaveTypeCountContent() { TYPECOUNT.nTypeCount = 0; nContent = 0; } + _SwSaveTypeCountContent( USHORT nType ) + { + SetTypeAndCount( nType, 0 ); + nContent = 0; + } + _SwSaveTypeCountContent( const SvULongs& rArr, USHORT& rPos ) + { + TYPECOUNT.nTypeCount = rArr[ rPos++ ]; + nContent = static_cast<xub_StrLen>(rArr[ rPos++ ]); + } + void Add( SvULongs& rArr ) + { + rArr.Insert( TYPECOUNT.nTypeCount, rArr.Count() ); + rArr.Insert( nContent, rArr.Count() ); + } + + void SetType( USHORT n ) { TYPECOUNT.TC.nType = n; } + USHORT GetType() const { return TYPECOUNT.TC.nType; } + void IncType() { ++TYPECOUNT.TC.nType; } + void DecType() { --TYPECOUNT.TC.nType; } + + void SetCount( USHORT n ) { TYPECOUNT.TC.nCount = n; } + USHORT GetCount() const { return TYPECOUNT.TC.nCount; } + USHORT IncCount() { return ++TYPECOUNT.TC.nCount; } + USHORT DecCount() { return --TYPECOUNT.TC.nCount; } + + void SetTypeAndCount( USHORT nT, USHORT nC ) + { TYPECOUNT.TC.nCount = nC; TYPECOUNT.TC.nType = nT; } + + void SetContent( xub_StrLen n ) { nContent = n; } + xub_StrLen GetContent() const { return nContent; } + }; + + // #i59534: If a paragraph will be splitted we have to restore some redline positions + // This help function checks a position compared with a node and an content index + + static const int BEFORE_NODE = 0; // Position before the given node index + static const int BEFORE_SAME_NODE = 1; // Same node index but content index before given content index + static const int SAME_POSITION = 2; // Same node index and samecontent index + static const int BEHIND_SAME_NODE = 3; // Same node index but content index behind given content index + static const int BEHIND_NODE = 4; // Position behind the given node index + + static int lcl_RelativePosition( const SwPosition& rPos, ULONG nNode, xub_StrLen nCntnt ) + { + ULONG nIndex = rPos.nNode.GetIndex(); + int nReturn = BEFORE_NODE; + if( nIndex == nNode ) + { + xub_StrLen nCntIdx = rPos.nContent.GetIndex(); + if( nCntIdx < nCntnt ) + nReturn = BEFORE_SAME_NODE; + else if( nCntIdx == nCntnt ) + nReturn = SAME_POSITION; + else + nReturn = BEHIND_SAME_NODE; + } + else if( nIndex > nNode ) + nReturn = BEHIND_NODE; + return nReturn; + } + + + static inline int lcl_Greater( const SwPosition& rPos, const SwNodeIndex& rNdIdx, const SwIndex* pIdx ) + { + return rPos.nNode > rNdIdx || ( pIdx && rPos.nNode == rNdIdx && rPos.nContent > pIdx->GetIndex() ); + } + + static void lcl_ChkPaM( SvULongs& rSaveArr, ULONG nNode, xub_StrLen nCntnt, + const SwPaM& rPam, _SwSaveTypeCountContent& rSave, + BOOL bChkSelDirection ) + { + // SelektionsRichtung beachten + bool bBound1IsStart = !bChkSelDirection ? TRUE : + ( *rPam.GetPoint() < *rPam.GetMark() + ? rPam.GetPoint() == &rPam.GetBound() + : rPam.GetMark() == &rPam.GetBound()); + + const SwPosition* pPos = &rPam.GetBound( TRUE ); + if( pPos->nNode.GetIndex() == nNode && + ( bBound1IsStart ? pPos->nContent.GetIndex() < nCntnt + : pPos->nContent.GetIndex() <= nCntnt )) + { + rSave.SetContent( pPos->nContent.GetIndex() ); + rSave.Add( rSaveArr ); + } + + pPos = &rPam.GetBound( FALSE ); + if( pPos->nNode.GetIndex() == nNode && + ( (bBound1IsStart && bChkSelDirection) + ? pPos->nContent.GetIndex() <= nCntnt + : pPos->nContent.GetIndex() < nCntnt )) + { + rSave.SetContent( pPos->nContent.GetIndex() ); + rSave.IncType(); + rSave.Add( rSaveArr ); + rSave.DecType(); + } + } + +} + + +// IDocumentMarkAccess for SwDoc + +IDocumentMarkAccess* SwDoc::getIDocumentMarkAccess() + { return static_cast< IDocumentMarkAccess* >(pMarkManager.get()); } + +const IDocumentMarkAccess* SwDoc::getIDocumentMarkAccess() const + { return static_cast< IDocumentMarkAccess* >(pMarkManager.get()); } + +// SaveBookmark + +SaveBookmark::SaveBookmark( + bool bSavePos, + bool bSaveOtherPos, + const IMark& rBkmk, + const SwNodeIndex & rMvPos, + const SwIndex* pIdx) + : m_aName(rBkmk.GetName()) + , m_aShortName() + , m_aCode() + , m_bSavePos(bSavePos) + , m_bSaveOtherPos(bSaveOtherPos) + , m_eOrigBkmType(IDocumentMarkAccess::GetType(rBkmk)) +{ + const IBookmark* const pBookmark = dynamic_cast< const IBookmark* >(&rBkmk); + if(pBookmark) + { + m_aShortName = pBookmark->GetShortName(); + m_aCode = pBookmark->GetKeyCode(); + + ::sfx2::Metadatable const*const pMetadatable( + dynamic_cast< ::sfx2::Metadatable const* >(pBookmark)); + if (pMetadatable) + { + m_pMetadataUndo = pMetadatable->CreateUndo(); + } + } + m_nNode1 = rBkmk.GetMarkPos().nNode.GetIndex(); + m_nCntnt1 = rBkmk.GetMarkPos().nContent.GetIndex(); + + if(m_bSavePos) + { + m_nNode1 -= rMvPos.GetIndex(); + if(pIdx && !m_nNode1) + m_nCntnt1 -= pIdx->GetIndex(); + } + + if(rBkmk.IsExpanded()) + { + m_nNode2 = rBkmk.GetOtherMarkPos().nNode.GetIndex(); + m_nCntnt2 = rBkmk.GetOtherMarkPos().nContent.GetIndex(); + + if(m_bSaveOtherPos) + { + m_nNode2 -= rMvPos.GetIndex(); + if(pIdx && !m_nNode2) + m_nCntnt2 -= pIdx->GetIndex(); + } + } + else + m_nNode2 = ULONG_MAX, m_nCntnt2 = STRING_NOTFOUND; +} + +void SaveBookmark::SetInDoc( + SwDoc* pDoc, + const SwNodeIndex& rNewPos, + const SwIndex* pIdx) +{ + SwPaM aPam(rNewPos.GetNode()); + if(pIdx) + aPam.GetPoint()->nContent = *pIdx; + + if(ULONG_MAX != m_nNode2) + { + aPam.SetMark(); + + if(m_bSaveOtherPos) + { + aPam.GetMark()->nNode += m_nNode2; + if(pIdx && !m_nNode2) + aPam.GetMark()->nContent += m_nCntnt2; + else + aPam.GetMark()->nContent.Assign(aPam.GetCntntNode(FALSE), m_nCntnt2); + } + else + { + aPam.GetMark()->nNode = m_nNode2; + aPam.GetMark()->nContent.Assign(aPam.GetCntntNode(FALSE), m_nCntnt2); + } + } + + if(m_bSavePos) + { + aPam.GetPoint()->nNode += m_nNode1; + + if(pIdx && !m_nNode1) + aPam.GetPoint()->nContent += m_nCntnt1; + else + aPam.GetPoint()->nContent.Assign(aPam.GetCntntNode(), m_nCntnt1); + } + else + { + aPam.GetPoint()->nNode = m_nNode1; + aPam.GetPoint()->nContent.Assign(aPam.GetCntntNode(), m_nCntnt1); + } + + if(!aPam.HasMark() + || CheckNodesRange(aPam.GetPoint()->nNode, aPam.GetMark()->nNode, TRUE)) + { + ::sw::mark::IBookmark* const pBookmark = dynamic_cast< ::sw::mark::IBookmark* >(pDoc->getIDocumentMarkAccess()->makeMark(aPam, m_aName, m_eOrigBkmType)); + if(pBookmark) + { + pBookmark->SetKeyCode(m_aCode); + 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); + } + } + } + } +} + +// _DelBookmarks, _{Save,Restore}CntntIdx + +void _DelBookmarks( + const SwNodeIndex& rStt, + const SwNodeIndex& rEnd, + ::std::vector<SaveBookmark> * pSaveBkmk, + const SwIndex* pSttIdx, + const SwIndex* pEndIdx) +{ + // illegal range ?? + if(rStt.GetIndex() > rEnd.GetIndex() + || (rStt == rEnd && (!pSttIdx || pSttIdx->GetIndex() >= pEndIdx->GetIndex()))) + return; + SwDoc* const pDoc = rStt.GetNode().GetDoc(); + + pDoc->getIDocumentMarkAccess()->deleteMarks(rStt, rEnd, pSaveBkmk, pSttIdx, pEndIdx); + + // kopiere alle Redlines, die im Move Bereich stehen in ein + // Array, das alle Angaben auf die Position als Offset speichert. + // Die neue Zuordung erfolgt nach dem Moven. + SwRedlineTbl& rTbl = (SwRedlineTbl&)pDoc->GetRedlineTbl(); + for(USHORT nCnt = 0; nCnt < rTbl.Count(); ++nCnt ) + { + // liegt auf der Position ?? + SwRedline* pRedl = rTbl[ nCnt ]; + + SwPosition *pRStt = &pRedl->GetBound(TRUE), + *pREnd = &pRedl->GetBound(FALSE); + if( *pRStt > *pREnd ) + { + SwPosition *pTmp = pRStt; pRStt = pREnd, pREnd = pTmp; + } + + if( lcl_Greater( *pRStt, rStt, pSttIdx ) && lcl_Lower( *pRStt, rEnd, pEndIdx )) + { + pRStt->nNode = rEnd; + if( pEndIdx ) + pRStt->nContent = *pEndIdx; + else + { + BOOL bStt = TRUE; + SwCntntNode* pCNd = pRStt->nNode.GetNode().GetCntntNode(); + if( !pCNd && 0 == ( pCNd = pDoc->GetNodes().GoNext( &pRStt->nNode )) ) + { + bStt = FALSE; + pRStt->nNode = rStt; + if( 0 == ( pCNd = pDoc->GetNodes().GoPrevious( &pRStt->nNode )) ) + { + pRStt->nNode = pREnd->nNode; + pCNd = pRStt->nNode.GetNode().GetCntntNode(); + } + } + xub_StrLen nTmp = bStt ? 0 : pCNd->Len(); + pRStt->nContent.Assign( pCNd, nTmp ); + } + } + if( lcl_Greater( *pREnd, rStt, pSttIdx ) && lcl_Lower( *pREnd, rEnd, pEndIdx )) + { + pREnd->nNode = rStt; + if( pSttIdx ) + pREnd->nContent = *pSttIdx; + else + { + BOOL bStt = FALSE; + SwCntntNode* pCNd = pREnd->nNode.GetNode().GetCntntNode(); + if( !pCNd && 0 == ( pCNd = pDoc->GetNodes().GoPrevious( &pREnd->nNode )) ) + { + bStt = TRUE; + pREnd->nNode = rEnd; + if( 0 == ( pCNd = pDoc->GetNodes().GoNext( &pREnd->nNode )) ) + { + pREnd->nNode = pRStt->nNode; + pCNd = pREnd->nNode.GetNode().GetCntntNode(); + } + } + xub_StrLen nTmp = bStt ? 0 : pCNd->Len(); + pREnd->nContent.Assign( pCNd, nTmp ); + } + } + } +} + +void _SaveCntntIdx(SwDoc* pDoc, + ULONG nNode, + xub_StrLen nCntnt, + SvULongs& rSaveArr, + BYTE nSaveFly) +{ + // 1. Bookmarks + _SwSaveTypeCountContent aSave; + aSave.SetTypeAndCount( 0x8000, 0 ); + + IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess(); + const sal_Int32 nBkmks = pMarkAccess->getMarksCount(); + for(; aSave.GetCount() < nBkmks; aSave.IncCount()) + { + bool bEqual = false; + bool bLower = false; + const ::sw::mark::IMark* pBkmk = (pMarkAccess->getMarksBegin() + aSave.GetCount())->get(); + if(pBkmk->GetMarkPos().nNode.GetIndex() == nNode + && pBkmk->GetMarkPos().nContent.GetIndex() <= nCntnt) + { + if(pBkmk->GetMarkPos().nContent.GetIndex() < nCntnt) + { + bLower = true; // a hint for the other position... + aSave.SetContent(pBkmk->GetMarkPos().nContent.GetIndex()); + aSave.Add(rSaveArr); + } + else // if a bookmark position is equal nCntnt, the other position + bEqual = true; // has to decide if it is added to the array + } + + if(pBkmk->IsExpanded() + && pBkmk->GetOtherMarkPos().nNode.GetIndex() == nNode + && pBkmk->GetOtherMarkPos().nContent.GetIndex() <= nCntnt) + { + if(bLower || pBkmk->GetOtherMarkPos().nContent.GetIndex() < nCntnt) + { + if(bEqual) + { // the other position is before, the (main) position is equal + aSave.SetContent(pBkmk->GetMarkPos().nContent.GetIndex()); + aSave.Add(rSaveArr); + } + aSave.SetContent(pBkmk->GetOtherMarkPos().nContent.GetIndex()); + aSave.IncType(); + aSave.Add(rSaveArr); + aSave.DecType(); + } + } + } + + // 2. Redlines + aSave.SetTypeAndCount( 0x1000, 0 ); + const SwRedlineTbl& rRedlTbl = pDoc->GetRedlineTbl(); + for( ; aSave.GetCount() < rRedlTbl.Count(); aSave.IncCount() ) + { + const SwRedline* pRdl = rRedlTbl[ aSave.GetCount() ]; + int nPointPos = lcl_RelativePosition( *pRdl->GetPoint(), nNode, nCntnt ); + int nMarkPos = pRdl->HasMark() ? lcl_RelativePosition( *pRdl->GetMark(), nNode, nCntnt ) : + nPointPos; + // #i59534: We have to store the positions inside the same node before the insert position + // and the one at the insert position if the corresponding Point/Mark position is before + // the insert position. + if( nPointPos == BEFORE_SAME_NODE || + ( nPointPos == SAME_POSITION && nMarkPos < SAME_POSITION ) ) + { + aSave.SetContent( pRdl->GetPoint()->nContent.GetIndex() ); + aSave.IncType(); + aSave.Add( rSaveArr ); + aSave.DecType(); + } + if( pRdl->HasMark() && ( nMarkPos == BEFORE_SAME_NODE || + ( nMarkPos == SAME_POSITION && nPointPos < SAME_POSITION ) ) ) + { + aSave.SetContent( pRdl->GetMark()->nContent.GetIndex() ); + aSave.Add( rSaveArr ); + } + } + + // 4. Absatzgebundene Objekte + { + SwCntntNode *pNode = pDoc->GetNodes()[nNode]->GetCntntNode(); + if( pNode ) + { + + SwFrm* pFrm = pNode->GetFrm(); +#if OSL_DEBUG_LEVEL > 1 + static BOOL bViaDoc = FALSE; + if( bViaDoc ) + pFrm = NULL; +#endif + if( pFrm ) // gibt es ein Layout? Dann ist etwas billiger... + { + if( pFrm->GetDrawObjs() ) + { + const SwSortedObjs& rDObj = *pFrm->GetDrawObjs(); + for( sal_uInt32 n = rDObj.Count(); n; ) + { + SwAnchoredObject* pObj = rDObj[ --n ]; + const SwFrmFmt& rFmt = pObj->GetFrmFmt(); + const SwFmtAnchor& rAnchor = rFmt.GetAnchor(); + SwPosition const*const pAPos = rAnchor.GetCntntAnchor(); + if ( pAPos && + ( ( nSaveFly && + FLY_AT_PARA == rAnchor.GetAnchorId() ) || + ( FLY_AT_CHAR == rAnchor.GetAnchorId() ) ) ) + { + aSave.SetType( 0x2000 ); + aSave.SetContent( pAPos->nContent.GetIndex() ); + + OSL_ENSURE( nNode == pAPos->nNode.GetIndex(), + "_SaveCntntIdx: Wrong Node-Index" ); + if ( FLY_AT_CHAR == rAnchor.GetAnchorId() ) + { + if( nCntnt <= aSave.GetContent() ) + { + if( SAVEFLY_SPLIT == nSaveFly ) + aSave.IncType(); // = 0x2001; + else + continue; + } + } + aSave.SetCount( pDoc->GetSpzFrmFmts()->Count() ); + while( aSave.GetCount() && + &rFmt != (*pDoc->GetSpzFrmFmts())[ + aSave.DecCount() ] ) + ; // nothing + OSL_ENSURE( &rFmt == (*pDoc->GetSpzFrmFmts())[ + aSave.GetCount() ], + "_SaveCntntIdx: Lost FrameFormat" ); + aSave.Add( rSaveArr ); + } + } + } + } + else // Schade, kein Layout, dann ist es eben etwas teurer... + { + for( aSave.SetCount( pDoc->GetSpzFrmFmts()->Count() ); + aSave.GetCount() ; ) + { + SwFrmFmt* pFrmFmt = (*pDoc->GetSpzFrmFmts())[ + aSave.DecCount() ]; + if ( RES_FLYFRMFMT != pFrmFmt->Which() && + RES_DRAWFRMFMT != pFrmFmt->Which() ) + continue; + + const SwFmtAnchor& rAnchor = pFrmFmt->GetAnchor(); + SwPosition const*const pAPos = rAnchor.GetCntntAnchor(); + if ( pAPos && ( nNode == pAPos->nNode.GetIndex() ) && + ( FLY_AT_PARA == rAnchor.GetAnchorId() || + FLY_AT_CHAR == rAnchor.GetAnchorId() ) ) + { + aSave.SetType( 0x2000 ); + aSave.SetContent( pAPos->nContent.GetIndex() ); + if ( FLY_AT_CHAR == rAnchor.GetAnchorId() ) + { + if( nCntnt <= aSave.GetContent() ) + { + if( SAVEFLY_SPLIT == nSaveFly ) + aSave.IncType(); // = 0x2001; + else + continue; + } + } + aSave.Add( rSaveArr ); + } + } + } + } + } + // 5. CrsrShell + { + SwCrsrShell* pShell = pDoc->GetEditShell(); + if( pShell ) + { + aSave.SetTypeAndCount( 0x800, 0 ); + FOREACHSHELL_START( pShell ) + SwPaM *_pStkCrsr = PCURSH->GetStkCrsr(); + if( _pStkCrsr ) + do { + lcl_ChkPaM( rSaveArr, nNode, nCntnt, *_pStkCrsr, + aSave, FALSE ); + aSave.IncCount(); + } while ( (_pStkCrsr != 0 ) && + ((_pStkCrsr=(SwPaM *)_pStkCrsr->GetNext()) != PCURSH->GetStkCrsr()) ); + + FOREACHPAM_START( PCURSH->_GetCrsr() ) + lcl_ChkPaM( rSaveArr, nNode, nCntnt, *PCURCRSR, + aSave, FALSE ); + aSave.IncCount(); + FOREACHPAM_END() + + FOREACHSHELL_END( pShell ) + } + } + // 6. UnoCrsr + { + aSave.SetTypeAndCount( 0x400, 0 ); + const SwUnoCrsrTbl& rTbl = pDoc->GetUnoCrsrTbl(); + for( USHORT n = 0; n < rTbl.Count(); ++n ) + { + FOREACHPAM_START( rTbl[ n ] ) + lcl_ChkPaM( rSaveArr, nNode, nCntnt, *PCURCRSR, aSave, FALSE ); + aSave.IncCount(); + FOREACHPAM_END() + + SwUnoTableCrsr* pUnoTblCrsr = + dynamic_cast<SwUnoTableCrsr*>(rTbl[ n ]); + if( pUnoTblCrsr ) + { + FOREACHPAM_START( &pUnoTblCrsr->GetSelRing() ) + lcl_ChkPaM( rSaveArr, nNode, nCntnt, *PCURCRSR, aSave, FALSE ); + aSave.IncCount(); + FOREACHPAM_END() + } + } + } +} + + +void _RestoreCntntIdx(SwDoc* pDoc, + SvULongs& rSaveArr, + ULONG nNode, + xub_StrLen nOffset, + BOOL bAuto) +{ + SwCntntNode* pCNd = pDoc->GetNodes()[ nNode ]->GetCntntNode(); + const SwRedlineTbl& rRedlTbl = pDoc->GetRedlineTbl(); + SwSpzFrmFmts* pSpz = pDoc->GetSpzFrmFmts(); + IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess(); + USHORT n = 0; + while( n < rSaveArr.Count() ) + { + _SwSaveTypeCountContent aSave( rSaveArr, n ); + SwPosition* pPos = 0; + switch( aSave.GetType() ) + { + case 0x8000: + { + MarkBase* pMark = dynamic_cast<MarkBase*>(pMarkAccess->getMarksBegin()[aSave.GetCount()].get()); + SwPosition aNewPos(pMark->GetMarkPos()); + aNewPos.nNode = *pCNd; + aNewPos.nContent.Assign(pCNd, aSave.GetContent() + nOffset); + pMark->SetMarkPos(aNewPos); + } + break; + case 0x8001: + { + MarkBase* pMark = dynamic_cast<MarkBase*>(pMarkAccess->getMarksBegin()[aSave.GetCount()].get()); + SwPosition aNewPos(pMark->GetOtherMarkPos()); + aNewPos.nNode = *pCNd; + aNewPos.nContent.Assign(pCNd, aSave.GetContent() + nOffset); + pMark->SetOtherMarkPos(aNewPos); + } + break; + case 0x1001: + pPos = (SwPosition*)rRedlTbl[ aSave.GetCount() ]->GetPoint(); + break; + case 0x1000: + pPos = (SwPosition*)rRedlTbl[ aSave.GetCount() ]->GetMark(); + break; + case 0x2000: + { + SwFrmFmt *pFrmFmt = (*pSpz)[ aSave.GetCount() ]; + const SwFmtAnchor& rFlyAnchor = pFrmFmt->GetAnchor(); + if( rFlyAnchor.GetCntntAnchor() ) + { + SwFmtAnchor aNew( rFlyAnchor ); + SwPosition aNewPos( *rFlyAnchor.GetCntntAnchor() ); + aNewPos.nNode = *pCNd; + if ( FLY_AT_CHAR == rFlyAnchor.GetAnchorId() ) + { + aNewPos.nContent.Assign( pCNd, + aSave.GetContent() + nOffset ); + } + else + { + aNewPos.nContent.Assign( 0, 0 ); + } + aNew.SetAnchor( &aNewPos ); + pFrmFmt->SetFmtAttr( aNew ); + } + } + break; + case 0x2001: + if( bAuto ) + { + SwFrmFmt *pFrmFmt = (*pSpz)[ aSave.GetCount() ]; + SfxPoolItem *pAnchor = (SfxPoolItem*)&pFrmFmt->GetAnchor(); + pFrmFmt->SwModify::Modify( pAnchor, pAnchor ); + } + break; + + case 0x0800: + case 0x0801: + { + USHORT nCnt = 0; + SwCrsrShell* pShell = pDoc->GetEditShell(); + if( pShell ) + { + FOREACHSHELL_START( pShell ) + SwPaM *_pStkCrsr = PCURSH->GetStkCrsr(); + if( _pStkCrsr ) + do { + if( aSave.GetCount() == nCnt ) + { + pPos = &_pStkCrsr->GetBound( 0x0800 == + aSave.GetType() ); + break; + } + ++nCnt; + } while ( (_pStkCrsr != 0 ) && + ((_pStkCrsr=(SwPaM *)_pStkCrsr->GetNext()) != PCURSH->GetStkCrsr()) ); + + if( pPos ) + break; + + FOREACHPAM_START( PCURSH->_GetCrsr() ) + if( aSave.GetCount() == nCnt ) + { + pPos = &PCURCRSR->GetBound( 0x0800 == + aSave.GetType() ); + break; + } + ++nCnt; + FOREACHPAM_END() + if( pPos ) + break; + + FOREACHSHELL_END( pShell ) + } + } + break; + + case 0x0400: + case 0x0401: + { + USHORT nCnt = 0; + const SwUnoCrsrTbl& rTbl = pDoc->GetUnoCrsrTbl(); + for( USHORT i = 0; i < rTbl.Count(); ++i ) + { + FOREACHPAM_START( rTbl[ i ] ) + if( aSave.GetCount() == nCnt ) + { + pPos = &PCURCRSR->GetBound( 0x0400 == + aSave.GetType() ); + break; + } + ++nCnt; + FOREACHPAM_END() + if( pPos ) + break; + + SwUnoTableCrsr* pUnoTblCrsr = + dynamic_cast<SwUnoTableCrsr*>(rTbl[ i ]); + if ( pUnoTblCrsr ) + { + FOREACHPAM_START( &pUnoTblCrsr->GetSelRing() ) + if( aSave.GetCount() == nCnt ) + { + pPos = &PCURCRSR->GetBound( 0x0400 == + aSave.GetType() ); + break; + } + ++nCnt; + FOREACHPAM_END() + } + if ( pPos ) + break; + } + } + break; + } + + if( pPos ) + { + pPos->nNode = *pCNd; + pPos->nContent.Assign( pCNd, aSave.GetContent() + nOffset ); + } + } +} + +void _RestoreCntntIdx(SvULongs& rSaveArr, + const SwNode& rNd, + xub_StrLen nLen, + xub_StrLen nChkLen) +{ + const SwDoc* pDoc = rNd.GetDoc(); + const SwRedlineTbl& rRedlTbl = pDoc->GetRedlineTbl(); + const SwSpzFrmFmts* pSpz = pDoc->GetSpzFrmFmts(); + const IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess(); + SwCntntNode* pCNd = (SwCntntNode*)rNd.GetCntntNode(); + + USHORT n = 0; + while( n < rSaveArr.Count() ) + { + _SwSaveTypeCountContent aSave( rSaveArr, n ); + if( aSave.GetContent() >= nChkLen ) + rSaveArr[ n-1 ] -= nChkLen; + else + { + SwPosition* pPos = 0; + switch( aSave.GetType() ) + { + case 0x8000: + { + MarkBase* pMark = dynamic_cast<MarkBase*>(pMarkAccess->getMarksBegin()[aSave.GetCount()].get()); + SwPosition aNewPos(pMark->GetMarkPos()); + aNewPos.nNode = rNd; + aNewPos.nContent.Assign(pCNd, Min(aSave.GetContent(), nLen)); + pMark->SetMarkPos(aNewPos); + } + break; + case 0x8001: + { + MarkBase* pMark = dynamic_cast<MarkBase*>(pMarkAccess->getMarksBegin()[aSave.GetCount()].get()); + SwPosition aNewPos(pMark->GetOtherMarkPos()); + aNewPos.nNode = rNd; + aNewPos.nContent.Assign(pCNd, Min(aSave.GetContent(), nLen)); + pMark->SetOtherMarkPos(aNewPos); + } + break; + case 0x1001: + pPos = (SwPosition*)rRedlTbl[ aSave.GetCount() ]->GetPoint(); + break; + case 0x1000: + pPos = (SwPosition*)rRedlTbl[ aSave.GetCount() ]->GetMark(); + break; + case 0x2000: + case 0x2001: + { + SwFrmFmt *pFrmFmt = (*pSpz)[ aSave.GetCount() ]; + const SwFmtAnchor& rFlyAnchor = pFrmFmt->GetAnchor(); + if( rFlyAnchor.GetCntntAnchor() ) + { + SwFmtAnchor aNew( rFlyAnchor ); + SwPosition aNewPos( *rFlyAnchor.GetCntntAnchor() ); + aNewPos.nNode = rNd; + if ( FLY_AT_CHAR == rFlyAnchor.GetAnchorId() ) + { + aNewPos.nContent.Assign( pCNd, Min( + aSave.GetContent(), nLen ) ); + } + else + { + aNewPos.nContent.Assign( 0, 0 ); + } + aNew.SetAnchor( &aNewPos ); + pFrmFmt->SetFmtAttr( aNew ); + } + } + break; + + case 0x0800: + case 0x0801: + { + USHORT nCnt = 0; + SwCrsrShell* pShell = pDoc->GetEditShell(); + if( pShell ) + { + FOREACHSHELL_START( pShell ) + SwPaM *_pStkCrsr = PCURSH->GetStkCrsr(); + if( _pStkCrsr ) + do { + if( aSave.GetCount() == nCnt ) + { + pPos = &_pStkCrsr->GetBound( 0x0800 == + aSave.GetType() ); + break; + } + ++nCnt; + } while ( (_pStkCrsr != 0 ) && + ((_pStkCrsr=(SwPaM *)_pStkCrsr->GetNext()) != PCURSH->GetStkCrsr()) ); + + if( pPos ) + break; + + FOREACHPAM_START( PCURSH->_GetCrsr() ) + if( aSave.GetCount() == nCnt ) + { + pPos = &PCURCRSR->GetBound( 0x0800 == + aSave.GetType() ); + break; + } + ++nCnt; + FOREACHPAM_END() + if( pPos ) + break; + + FOREACHSHELL_END( pShell ) + } + } + break; + + case 0x0400: + case 0x0401: + { + USHORT nCnt = 0; + const SwUnoCrsrTbl& rTbl = pDoc->GetUnoCrsrTbl(); + for( USHORT i = 0; i < rTbl.Count(); ++i ) + { + FOREACHPAM_START( rTbl[ i ] ) + if( aSave.GetCount() == nCnt ) + { + pPos = &PCURCRSR->GetBound( 0x0400 == + aSave.GetType() ); + break; + } + ++nCnt; + FOREACHPAM_END() + if( pPos ) + break; + + SwUnoTableCrsr* pUnoTblCrsr = + dynamic_cast<SwUnoTableCrsr*>(rTbl[ i ]); + if ( pUnoTblCrsr ) + { + FOREACHPAM_START( &pUnoTblCrsr->GetSelRing() ) + if( aSave.GetCount() == nCnt ) + { + pPos = &PCURCRSR->GetBound( 0x0400 == + aSave.GetType() ); + break; + } + ++nCnt; + FOREACHPAM_END() + } + if ( pPos ) + break; + } + } + break; + } + + if( pPos ) + { + pPos->nNode = rNd; + pPos->nContent.Assign( pCNd, Min( aSave.GetContent(), nLen ) ); + } + n -= 2; + rSaveArr.Remove( n, 2 ); + } + } +} |