[Libreoffice-commits] core.git: Branch 'feature/refactor-god-objects' - sw/inc sw/Library_sw.mk sw/source

Valentin Kettner vakevk+libreoffice at gmail.com
Wed Jul 9 13:28:03 PDT 2014


Rebased ref, commits from common ancestor:
commit aad25a4349f14c64f80b1807a2c2f49c2bcd3082
Author: Valentin Kettner <vakevk+libreoffice at gmail.com>
Date:   Mon Jul 7 14:32:02 2014 +0200

    Started refactoring IDocumentContentOperations out of SwDoc.
    
    The work all done except for moving all calls to the interface's functions
    from SwDoc::.. to SwDoc::getIDocumentContentOperations::..
    I didnt do that yet in case we make some design change.
    
    Things I had to change that are not simply refactoring:
    
    Made SwNodes in sw/inc/ndarr.hxx friend class to
    DocumentContentOperationsManager so it can call DelNodes at end of
    DocumentContentOperationsManager::DeleteSection .
    
    Added DeleteAutoCorrExceptWord to SwDoc, its needed in the Manager.
    
    Added a non const version of SwDoc::GetDfltGrfFmtColl() to SwDoc
    because its needed in the Manager.
    
    Made SwDoc a friend class to DocumentContentOperationsManager so it
    can call SwDoc::checkRedlining and SwDocL::_MakeFlySection.
    
    Moved SwDoc::CopyImpl_ , SwDoc::CopyWithFlyInFly and
    SwDoc::CopyFlyInFlyImpl into the Manager.
    
    Moved "struct ParaRstFmt" and "lcl_RstTxtAttr" from docfmt.cxx
    in DocumentContentOperationsManager.hxx .
    
    Other things I noticed:
    
    Why are sw_GetJoinFlags and sw_JoinText apparently global functions
    defined in docedt.cxx . It looks like they should be moved somewhere.
    They are only used in this Manager and one other place.
    
    UpdateParRsid and UpdateRsid where grouped under
    IDocumentContentOperations in SwDoc but  are not part of the interface.
    
    Change-Id: Icaab57f4a8c158a85e549ecb4aacc752bc95bbc9

diff --git a/sw/Library_sw.mk b/sw/Library_sw.mk
index 0f5d0a4..06e38a9 100644
--- a/sw/Library_sw.mk
+++ b/sw/Library_sw.mk
@@ -193,6 +193,7 @@ $(eval $(call gb_Library_add_exception_objects,sw,\
     sw/source/core/doc/DocumentListItemsManager \
     sw/source/core/doc/DocumentListsManager \
     sw/source/core/doc/DocumentOutlineNodesManager \
+    sw/source/core/doc/DocumentContentOperationsManager \
     sw/source/core/doc/extinput \
     sw/source/core/doc/fmtcol \
     sw/source/core/doc/ftnidx \
diff --git a/sw/inc/IDocumentContentOperations.hxx b/sw/inc/IDocumentContentOperations.hxx
index 5768460..5227528 100644
--- a/sw/inc/IDocumentContentOperations.hxx
+++ b/sw/inc/IDocumentContentOperations.hxx
@@ -21,6 +21,8 @@
 #define INCLUDED_SW_INC_IDOCUMENTCONTENTOPERATIONS_HXX
 
 #include <sal/types.h>
+#include <rtl/ustring.hxx>
+using rtl::OUString;
 
 class SwPaM;
 struct SwPosition;
diff --git a/sw/inc/doc.hxx b/sw/inc/doc.hxx
index ab74b4e..8f5a721 100644
--- a/sw/inc/doc.hxx
+++ b/sw/inc/doc.hxx
@@ -24,13 +24,13 @@
 #include <IDocumentMarkAccess.hxx>
 #include <IDocumentRedlineAccess.hxx>
 #include <IDocumentFieldsAccess.hxx>
-#include <IDocumentContentOperations.hxx>
 #include <IDocumentStylePoolAccess.hxx>
 #include <IDocumentLineNumberAccess.hxx>
 #include <IDocumentStatistics.hxx>
 #include <IDocumentState.hxx>
 #include <IDocumentLayoutAccess.hxx>
 #include <IDocumentExternalData.hxx>
+#include <IDocumentContentOperations.hxx>
 #include <com/sun/star/embed/XEmbeddedObject.hpp>
 #include <com/sun/star/embed/XStorage.hpp>
 #include <vcl/timer.hxx>
@@ -193,6 +193,7 @@ class IDocumentLinksAdministration;
 class IDocumentListItems;
 class IDocumentListsAccess;
 class IDocumentOutlineNodes;
+class IDocumentContentOperations;
 class _SetGetExpFlds;
 
 namespace sw { namespace mark {
@@ -211,6 +212,7 @@ namespace sw {
     class DocumentListItemsManager;
     class DocumentListsManager;
     class DocumentOutlineNodesManager;
+    class DocumentContentOperationsManager;
 }
 
 namespace com { namespace sun { namespace star {
@@ -250,14 +252,15 @@ class SW_DLLPUBLIC SwDoc :
     public IInterface,
     public IDocumentRedlineAccess,
     public IDocumentFieldsAccess,
-    public IDocumentContentOperations,
     public IDocumentStylePoolAccess,
     public IDocumentLineNumberAccess,
     public IDocumentStatistics,
     public IDocumentState,
     public IDocumentLayoutAccess,
-    public IDocumentExternalData
+    public IDocumentExternalData,
+    public IDocumentContentOperations
 {
+    friend class ::sw::DocumentContentOperationsManager;
 
     friend void _InitCore();
     friend void _FinitCore();
@@ -292,6 +295,7 @@ class SW_DLLPUBLIC SwDoc :
     const ::boost::scoped_ptr< ::sw::DocumentListItemsManager > m_pDocumentListItemsManager;
     const ::boost::scoped_ptr< ::sw::DocumentListsManager > m_pDocumentListsManager;
     const ::boost::scoped_ptr< ::sw::DocumentOutlineNodesManager > m_pDocumentOutlineNodesManager;
+    const ::boost::scoped_ptr< ::sw::DocumentContentOperationsManager > m_pDocumentContentOperationsManager;
 
     // Pointer
     SwFrmFmt        *mpDfltFrmFmt;       //< Default formats.
@@ -427,26 +431,10 @@ private:
     // private methods
     void checkRedlining(RedlineMode_t& _rReadlineMode);
 
-    /** Only for internal use and therefore private.
-     Copy a range within the same or to another document.
-     Position may not lie within range! */
-    bool CopyImpl( SwPaM&, SwPosition&, const bool MakeNewFrms /*= true */,
-            const bool bCopyAll, SwPaM *const pCpyRng /*= 0*/ ) const;
-
     SwFlyFrmFmt* _MakeFlySection( const SwPosition& rAnchPos,
                                 const SwCntntNode& rNode, RndStdIds eRequestId,
                                 const SfxItemSet* pFlyAttrSet,
                                 SwFrmFmt* = 0 );
-
-    SwFlyFrmFmt* _InsNoTxtNode( const SwPosition&rPos, SwNoTxtNode*,
-                                const SfxItemSet* pFlyAttrSet,
-                                const SfxItemSet* pGrfAttrSet,
-                                SwFrmFmt* = 0 );
-
-    void CopyFlyInFlyImpl(  const SwNodeRange& rRg,
-                            const sal_Int32 nEndContentIndex,
-                            const SwNodeIndex& rStartIdx,
-                            const bool bCopyFlyAtFly = false ) const;
     sal_Int8 SetFlyFrmAnchor( SwFrmFmt& rFlyFmt, SfxItemSet& rSet, bool bNewFrms );
 
     typedef SwFmt* (SwDoc:: *FNCopyFmt)( const OUString&, SwFmt*, bool, bool );
@@ -507,11 +495,6 @@ private:
 
     void InitTOXTypes();
     void Paste( const SwDoc& );
-    bool DeleteAndJoinImpl(SwPaM&, const bool);
-    bool DeleteAndJoinWithRedlineImpl(SwPaM&, const bool unused = false);
-    bool DeleteRangeImpl(SwPaM&, const bool unused = false);
-    bool DeleteRangeImplImpl(SwPaM &);
-    bool ReplaceRangeImpl(SwPaM&, OUString const&, const bool);
 
 public:
     enum DocumentType {
@@ -645,6 +628,14 @@ public:
     bool containsUpdatableFields();
 
     // IDocumentContentOperations
+    IDocumentContentOperations const & getIDocumentContentOperations() const;
+    IDocumentContentOperations & getIDocumentContentOperations();
+    ::sw::DocumentContentOperationsManager const & GetDocumentContentOperationsManager() const;
+    ::sw::DocumentContentOperationsManager & GetDocumentContentOperationsManager();
+
+    virtual bool UpdateParRsid( SwTxtNode *pTxtNode, sal_uInt32 nVal = 0 );
+    virtual bool UpdateRsid( const SwPaM &rRg, sal_Int32 nLen );
+
     virtual bool CopyRange(SwPaM&, SwPosition&, const bool bCopyAll) const SAL_OVERRIDE;
     virtual void DeleteSection(SwNode* pNode) SAL_OVERRIDE;
     virtual bool DeleteRange(SwPaM&) SAL_OVERRIDE;
@@ -659,8 +650,6 @@ public:
     virtual bool Overwrite(const SwPaM &rRg, const OUString& rStr) SAL_OVERRIDE;
     virtual bool InsertString(const SwPaM &rRg, const OUString&,
               const enum InsertFlags nInsertMode = INS_EMPTYEXPAND ) SAL_OVERRIDE;
-    virtual bool UpdateParRsid( SwTxtNode *pTxtNode, sal_uInt32 nVal = 0 );
-    virtual bool UpdateRsid( const SwPaM &rRg, sal_Int32 nLen );
     virtual SwFlyFrmFmt* Insert(const SwPaM &rRg, const OUString& rGrfName, const OUString& rFltName, const Graphic* pGraphic,
                         const SfxItemSet* pFlyAttrSet, const SfxItemSet* pGrfAttrSet, SwFrmFmt*) SAL_OVERRIDE;
     virtual SwFlyFrmFmt* Insert(const SwPaM& rRg, const GraphicObject& rGrfObj, const SfxItemSet* pFlyAttrSet,
@@ -671,7 +660,6 @@ public:
         const SfxItemSet& rFlyAttrSet ) SAL_OVERRIDE;
     virtual SwFlyFrmFmt* Insert(const SwPaM &rRg, const svt::EmbeddedObjectRef& xObj, const SfxItemSet* pFlyAttrSet,
                         const SfxItemSet* pGrfAttrSet, SwFrmFmt*) SAL_OVERRIDE;
-
     // Add a para for the char attribute exp...
     virtual bool InsertPoolItem(
         const SwPaM &rRg,
@@ -845,14 +833,6 @@ public:
                                 const SwSelBoxes* pSelBoxes = 0,
                                 SwFrmFmt *pParent = 0 );
 
-    void CopyWithFlyInFly( const SwNodeRange& rRg,
-                            const sal_Int32 nEndContentIndex,
-                            const SwNodeIndex& rInsPos,
-                            const SwPaM* pCopiedPaM = NULL,
-                            bool bMakeNewFrms = true,
-                            bool bDelRedlines = true,
-                            bool bCopyFlyAtFly = false ) const;
-
     //UUUU Helper that checks for unique items for DrawingLayer items of type NameOrIndex
     // and evtl. corrects that items to ensure unique names for that type. This call may
     // modify/correct entries inside of the given SfxItemSet, and it will apply a name to
@@ -1043,6 +1023,7 @@ public:
     void ChkCondColls();
 
     const SwGrfFmtColl* GetDfltGrfFmtColl() const   { return mpDfltGrfFmtColl; }
+    SwGrfFmtColl* GetDfltGrfFmtColl()  { return mpDfltGrfFmtColl; }
     const SwGrfFmtColls *GetGrfFmtColls() const     { return mpGrfFmtCollTbl; }
     SwGrfFmtColl *MakeGrfFmtColl(const OUString &rFmtName,
                                     SwGrfFmtColl *pDerivedFrom);
@@ -1592,6 +1573,7 @@ public:
     // Save current values for automatic registration of exceptions in Autocorrection.
     void SetAutoCorrExceptWord( SwAutoCorrExceptWord* pNew );
     SwAutoCorrExceptWord* GetAutoCorrExceptWord()       { return mpACEWord; }
+    void DeleteAutoCorrExceptWord();
 
     const SwFmtINetFmt* FindINetAttr( const OUString& rName ) const;
 
diff --git a/sw/inc/ndarr.hxx b/sw/inc/ndarr.hxx
index d8c71d6..a004af3 100644
--- a/sw/inc/ndarr.hxx
+++ b/sw/inc/ndarr.hxx
@@ -64,6 +64,8 @@ class SwUndoTblToTxt;
 class SwUndoTxtToTbl;
 struct SwPosition;
 
+namespace sw { class DocumentContentOperationsManager; }
+
 // class SwNodes
 
 typedef SwNode * SwNodePtr;
@@ -88,6 +90,7 @@ class SW_DLLPUBLIC SwNodes
     friend class SwDoc;
     friend class SwNode;
     friend class SwNodeIndex;
+    friend class ::sw::DocumentContentOperationsManager;
 
     SwNodeIndex* pRoot;                 ///< List of all indices on nodes.
 
diff --git a/sw/source/core/doc/DocumentContentOperationsManager.cxx b/sw/source/core/doc/DocumentContentOperationsManager.cxx
new file mode 100644
index 0000000..3127e1b
--- /dev/null
+++ b/sw/source/core/doc/DocumentContentOperationsManager.cxx
@@ -0,0 +1,4441 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include <DocumentContentOperationsManager.hxx>
+#include <doc.hxx>
+#include <IDocumentUndoRedo.hxx>
+#include <IDocumentMarkAccess.hxx>
+#include <UndoManager.hxx>
+#include <docary.hxx>
+#include <textboxhelper.hxx>
+#include <dcontact.hxx>
+#include <grfatr.hxx>
+#include <numrule.hxx>
+#include <charfmt.hxx>
+#include <ndgrf.hxx>
+#include <ndnotxt.hxx>
+#include <ndole.hxx>
+#include <fmtcol.hxx>
+#include <breakit.hxx>
+#include <frmfmt.hxx>
+#include <fmtanchr.hxx>
+#include <fmtcntnt.hxx>
+#include <fmtinfmt.hxx>
+#include <fmtpdsc.hxx>
+#include <fmtcnct.hxx>
+#include <SwStyleNameMapper.hxx>
+#include <redline.hxx>
+#include <unocrsr.hxx>
+#include <mvsave.hxx>
+#include <ndtxt.hxx>
+#include <poolfmt.hxx>
+#include <paratr.hxx>
+#include <txatbase.hxx>
+#include <UndoRedline.hxx>
+#include <undobj.hxx>
+#include <UndoDelete.hxx>
+#include <UndoSplitMove.hxx>
+#include <UndoOverwrite.hxx>
+#include <UndoInsert.hxx>
+#include <UndoAttribute.hxx>
+#include <rolbck.hxx>
+#include <acorrect.hxx>
+#include <ftnidx.hxx>
+#include <txtftn.hxx>
+#include <hints.hxx>
+#include <crsrsh.hxx>
+#include <fmtflcnt.hxx>
+#include <unotools/charclass.hxx>
+#include <sfx2/Metadatable.hxx>
+#include <svl/stritem.hxx>
+#include <svl/itemiter.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdouno.hxx>
+#include <editeng/formatbreakitem.hxx>
+#include <com/sun/star/i18n/Boundary.hpp>
+
+using namespace ::com::sun::star::i18n;
+
+//local functions originally from sw/source/core/docnode/ndcopy.cxx
+namespace
+{
+    // Copy method from SwDoc
+    // Prevent copying in Flys that are anchored in the area
+    static bool lcl_ChkFlyFly( SwDoc* pDoc, sal_uLong nSttNd, sal_uLong nEndNd,
+                        sal_uLong nInsNd )
+    {
+        const SwFrmFmts& rFrmFmtTbl = *pDoc->GetSpzFrmFmts();
+
+        for( sal_uInt16 n = 0; n < rFrmFmtTbl.size(); ++n )
+        {
+            SwFrmFmt const*const  pFmt = rFrmFmtTbl[n];
+            SwFmtAnchor const*const pAnchor = &pFmt->GetAnchor();
+            SwPosition const*const pAPos = pAnchor->GetCntntAnchor();
+            if (pAPos &&
+                ((FLY_AS_CHAR == pAnchor->GetAnchorId()) ||
+                 (FLY_AT_CHAR == pAnchor->GetAnchorId()) ||
+                 (FLY_AT_FLY  == pAnchor->GetAnchorId()) ||
+                 (FLY_AT_PARA == pAnchor->GetAnchorId())) &&
+                nSttNd <= pAPos->nNode.GetIndex() &&
+                pAPos->nNode.GetIndex() < nEndNd )
+            {
+                const SwFmtCntnt& rCntnt = pFmt->GetCntnt();
+                SwStartNode* pSNd;
+                if( !rCntnt.GetCntntIdx() ||
+                    0 == ( pSNd = rCntnt.GetCntntIdx()->GetNode().GetStartNode() ))
+                    continue;
+
+                if( pSNd->GetIndex() < nInsNd &&
+                    nInsNd < pSNd->EndOfSectionIndex() )
+                    // Do not copy !
+                    return true;
+
+                if( lcl_ChkFlyFly( pDoc, pSNd->GetIndex(),
+                            pSNd->EndOfSectionIndex(), nInsNd ) )
+                    // Do not copy !
+                    return true;
+            }
+        }
+
+        return false;
+    }
+
+    /*
+        The lcl_CopyBookmarks function has to copy bookmarks from the source to the destination nodes
+        array. It is called after a call of the _CopyNodes(..) function. But this function does not copy
+        every node (at least at the moment: 2/08/2006 ), section start and end nodes will not be copied if the corresponding end/start node is outside the copied pam.
+        The lcl_NonCopyCount function counts the number of these nodes, given the copied pam and a node
+        index inside the pam.
+        rPam is the original source pam, rLastIdx is the last calculated position, rDelCount the number
+        of "non-copy" nodes between rPam.Start() and rLastIdx.
+        nNewIdx is the new position of interest.
+    */
+
+    static void lcl_NonCopyCount( const SwPaM& rPam, SwNodeIndex& rLastIdx, const sal_uLong nNewIdx, sal_uLong& rDelCount )
+    {
+        sal_uLong nStart = rPam.Start()->nNode.GetIndex();
+        sal_uLong nEnd = rPam.End()->nNode.GetIndex();
+        if( rLastIdx.GetIndex() < nNewIdx ) // Moving forward?
+        {
+            do // count "non-copy" nodes
+            {
+                SwNode& rNode = rLastIdx.GetNode();
+                if( ( rNode.IsSectionNode() && rNode.EndOfSectionIndex() >= nEnd )
+                    || ( rNode.IsEndNode() && rNode.StartOfSectionNode()->GetIndex() < nStart ) )
+                    ++rDelCount;
+                ++rLastIdx;
+            }
+            while( rLastIdx.GetIndex() < nNewIdx );
+        }
+        else if( rDelCount ) // optimization: if there are no "non-copy" nodes until now,
+                             // no move backward needed
+        {
+            while( rLastIdx.GetIndex() > nNewIdx )
+            {
+                SwNode& rNode = rLastIdx.GetNode();
+                if( ( rNode.IsSectionNode() && rNode.EndOfSectionIndex() >= nEnd )
+                    || ( rNode.IsEndNode() && rNode.StartOfSectionNode()->GetIndex() < nStart ) )
+                    --rDelCount;
+                rLastIdx--;
+            }
+        }
+    }
+
+    static void lcl_SetCpyPos( const SwPosition& rOrigPos,
+                        const SwPosition& rOrigStt,
+                        const SwPosition& rCpyStt,
+                        SwPosition& rChgPos,
+                        sal_uLong nDelCount )
+    {
+        sal_uLong nNdOff = rOrigPos.nNode.GetIndex();
+        nNdOff -= rOrigStt.nNode.GetIndex();
+        nNdOff -= nDelCount;
+        sal_Int32 nCntntPos = rOrigPos.nContent.GetIndex();
+
+        // Always adjust <nNode> at to be changed <SwPosition> instance <rChgPos>
+        rChgPos.nNode = nNdOff + rCpyStt.nNode.GetIndex();
+        if( !nNdOff )
+        {
+            // dann nur den Content anpassen
+            if( nCntntPos > rOrigStt.nContent.GetIndex() )
+                nCntntPos -= rOrigStt.nContent.GetIndex();
+            else
+                nCntntPos = 0;
+            nCntntPos += rCpyStt.nContent.GetIndex();
+        }
+        rChgPos.nContent.Assign( rChgPos.nNode.GetNode().GetCntntNode(), nCntntPos );
+    }
+
+    // TODO: use SaveBookmark (from _DelBookmarks)
+    static void lcl_CopyBookmarks(
+        const SwPaM& rPam,
+        SwPaM& rCpyPam )
+    {
+        const SwDoc* pSrcDoc = rPam.GetDoc();
+        SwDoc* pDestDoc =  rCpyPam.GetDoc();
+        const IDocumentMarkAccess* const pSrcMarkAccess = pSrcDoc->getIDocumentMarkAccess();
+        ::sw::UndoGuard const undoGuard(pDestDoc->GetIDocumentUndoRedo());
+
+        const SwPosition &rStt = *rPam.Start(), &rEnd = *rPam.End();
+        SwPosition* pCpyStt = rCpyPam.Start();
+
+        typedef ::std::vector< const ::sw::mark::IMark* > mark_vector_t;
+        mark_vector_t vMarksToCopy;
+        for ( IDocumentMarkAccess::const_iterator_t ppMark = pSrcMarkAccess->getAllMarksBegin();
+              ppMark != pSrcMarkAccess->getAllMarksEnd();
+              ++ppMark )
+        {
+            const ::sw::mark::IMark* const pMark = ppMark->get();
+
+            const SwPosition& rMarkStart = pMark->GetMarkStart();
+            const SwPosition& rMarkEnd = pMark->GetMarkEnd();
+            // only include marks that are in the range and not touching both start and end
+            // - not for annotation marks.
+            const bool bIsNotOnBoundary =
+                pMark->IsExpanded()
+                ? (rMarkStart != rStt || rMarkEnd != rEnd)  // rMarkStart != rMarkEnd
+                : (rMarkStart != rStt && rMarkEnd != rEnd); // rMarkStart == rMarkEnd
+            if ( rMarkStart >= rStt && rMarkEnd <= rEnd
+                 && ( bIsNotOnBoundary
+                      || IDocumentMarkAccess::GetType( *pMark ) == IDocumentMarkAccess::ANNOTATIONMARK ) )
+            {
+                vMarksToCopy.push_back(pMark);
+            }
+        }
+        // We have to count the "non-copied" nodes..
+        SwNodeIndex aCorrIdx(rStt.nNode);
+        sal_uLong nDelCount = 0;
+        for(mark_vector_t::const_iterator ppMark = vMarksToCopy.begin();
+            ppMark != vMarksToCopy.end();
+            ++ppMark)
+        {
+            const ::sw::mark::IMark* const pMark = *ppMark;
+            SwPaM aTmpPam(*pCpyStt);
+            lcl_NonCopyCount(rPam, aCorrIdx, pMark->GetMarkPos().nNode.GetIndex(), nDelCount);
+            lcl_SetCpyPos( pMark->GetMarkPos(), rStt, *pCpyStt, *aTmpPam.GetPoint(), nDelCount);
+            if(pMark->IsExpanded())
+            {
+                aTmpPam.SetMark();
+                lcl_NonCopyCount(rPam, aCorrIdx, pMark->GetOtherMarkPos().nNode.GetIndex(), nDelCount);
+                lcl_SetCpyPos(pMark->GetOtherMarkPos(), rStt, *pCpyStt, *aTmpPam.GetMark(), nDelCount);
+            }
+
+            ::sw::mark::IMark* const pNewMark = pDestDoc->getIDocumentMarkAccess()->makeMark(
+                aTmpPam,
+                pMark->GetName(),
+                IDocumentMarkAccess::GetType(*pMark));
+            // Explicitly try to get exactly the same name as in the source
+            // because NavigatorReminders, DdeBookmarks etc. ignore the proposed name
+            pDestDoc->getIDocumentMarkAccess()->renameMark(pNewMark, pMark->GetName());
+
+            // copying additional attributes for bookmarks or fieldmarks
+            ::sw::mark::IBookmark* const pNewBookmark =
+                dynamic_cast< ::sw::mark::IBookmark* const >(pNewMark);
+            const ::sw::mark::IBookmark* const pOldBookmark =
+                dynamic_cast< const ::sw::mark::IBookmark* >(pMark);
+            if (pNewBookmark && pOldBookmark)
+            {
+                pNewBookmark->SetKeyCode(pOldBookmark->GetKeyCode());
+                pNewBookmark->SetShortName(pOldBookmark->GetShortName());
+            }
+            ::sw::mark::IFieldmark* const pNewFieldmark =
+                dynamic_cast< ::sw::mark::IFieldmark* const >(pNewMark);
+            const ::sw::mark::IFieldmark* const pOldFieldmark =
+                dynamic_cast< const ::sw::mark::IFieldmark* >(pMark);
+            if (pNewFieldmark && pOldFieldmark)
+            {
+                pNewFieldmark->SetFieldname(pOldFieldmark->GetFieldname());
+                pNewFieldmark->SetFieldHelptext(pOldFieldmark->GetFieldHelptext());
+                ::sw::mark::IFieldmark::parameter_map_t* pNewParams = pNewFieldmark->GetParameters();
+                const ::sw::mark::IFieldmark::parameter_map_t* pOldParams = pOldFieldmark->GetParameters();
+                ::sw::mark::IFieldmark::parameter_map_t::const_iterator pIt = pOldParams->begin();
+                for (; pIt != pOldParams->end(); ++pIt )
+                {
+                    pNewParams->insert( *pIt );
+                }
+            }
+
+            ::sfx2::Metadatable const*const pMetadatable(
+                    dynamic_cast< ::sfx2::Metadatable const* >(pMark));
+            ::sfx2::Metadatable      *const pNewMetadatable(
+                    dynamic_cast< ::sfx2::Metadatable      * >(pNewMark));
+            if (pMetadatable && pNewMetadatable)
+            {
+                pNewMetadatable->RegisterAsCopyOf(*pMetadatable);
+            }
+        }
+    }
+
+    static void lcl_DeleteRedlines( const SwPaM& rPam, SwPaM& rCpyPam )
+    {
+        const SwDoc* pSrcDoc = rPam.GetDoc();
+        const SwRedlineTbl& rTbl = pSrcDoc->GetRedlineTbl();
+        if( !rTbl.empty() )
+        {
+            SwDoc* pDestDoc = rCpyPam.GetDoc();
+            SwPosition* pCpyStt = rCpyPam.Start(), *pCpyEnd = rCpyPam.End();
+            SwPaM* pDelPam = 0;
+            const SwPosition *pStt = rPam.Start(), *pEnd = rPam.End();
+            // We have to count the "non-copied" nodes
+            sal_uLong nDelCount = 0;
+            SwNodeIndex aCorrIdx( pStt->nNode );
+
+            sal_uInt16 n = 0;
+            pSrcDoc->GetRedline( *pStt, &n );
+            for( ; n < rTbl.size(); ++n )
+            {
+                const SwRangeRedline* pRedl = rTbl[ n ];
+                if( nsRedlineType_t::REDLINE_DELETE == pRedl->GetType() && pRedl->IsVisible() )
+                {
+                    const SwPosition *pRStt = pRedl->Start(), *pREnd = pRedl->End();
+
+                    SwComparePosition eCmpPos = ComparePosition( *pStt, *pEnd, *pRStt, *pREnd );
+                    switch( eCmpPos )
+                    {
+                    case POS_COLLIDE_END:
+                    case POS_BEFORE:
+                        // Pos1 is before Pos2
+                        break;
+
+                    case POS_COLLIDE_START:
+                    case POS_BEHIND:
+                        // Pos1 is after Pos2
+                        n = rTbl.size();
+                        break;
+
+                    default:
+                        {
+                            pDelPam = new SwPaM( *pCpyStt, pDelPam );
+                            if( *pStt < *pRStt )
+                            {
+                                lcl_NonCopyCount( rPam, aCorrIdx, pRStt->nNode.GetIndex(), nDelCount );
+                                lcl_SetCpyPos( *pRStt, *pStt, *pCpyStt,
+                                                *pDelPam->GetPoint(), nDelCount );
+                            }
+                            pDelPam->SetMark();
+
+                            if( *pEnd < *pREnd )
+                                *pDelPam->GetPoint() = *pCpyEnd;
+                            else
+                            {
+                                lcl_NonCopyCount( rPam, aCorrIdx, pREnd->nNode.GetIndex(), nDelCount );
+                                lcl_SetCpyPos( *pREnd, *pStt, *pCpyStt,
+                                                *pDelPam->GetPoint(), nDelCount );
+                            }
+                        }
+                    }
+                }
+            }
+
+            if( pDelPam )
+            {
+                RedlineMode_t eOld = pDestDoc->GetRedlineMode();
+                pDestDoc->SetRedlineMode_intern( (RedlineMode_t)(eOld | nsRedlineMode_t::REDLINE_IGNORE));
+
+                ::sw::UndoGuard const undoGuard(pDestDoc->GetIDocumentUndoRedo());
+
+                do {
+                    pDestDoc->DeleteAndJoin( *(SwPaM*)pDelPam->GetNext() );
+                    if( pDelPam->GetNext() == pDelPam )
+                        break;
+                    delete pDelPam->GetNext();
+                } while( true );
+                delete pDelPam;
+
+                pDestDoc->SetRedlineMode_intern( eOld );
+            }
+        }
+    }
+
+    static void lcl_DeleteRedlines( const SwNodeRange& rRg, SwNodeRange& rCpyRg )
+    {
+        SwDoc* pSrcDoc = rRg.aStart.GetNode().GetDoc();
+        if( !pSrcDoc->GetRedlineTbl().empty() )
+        {
+            SwPaM aRgTmp( rRg.aStart, rRg.aEnd );
+            SwPaM aCpyTmp( rCpyRg.aStart, rCpyRg.aEnd );
+            lcl_DeleteRedlines( aRgTmp, aCpyTmp );
+        }
+    }
+
+    static void lcl_ChainFmts( SwFlyFrmFmt *pSrc, SwFlyFrmFmt *pDest )
+    {
+        SwFmtChain aSrc( pSrc->GetChain() );
+        if ( !aSrc.GetNext() )
+        {
+            aSrc.SetNext( pDest );
+            pSrc->SetFmtAttr( aSrc );
+        }
+        SwFmtChain aDest( pDest->GetChain() );
+        if ( !aDest.GetPrev() )
+        {
+            aDest.SetPrev( pSrc );
+            pDest->SetFmtAttr( aDest );
+        }
+    }
+
+    // #i86492#
+    static bool lcl_ContainsOnlyParagraphsInList( const SwPaM& rPam )
+    {
+        bool bRet = false;
+
+        const SwTxtNode* pTxtNd = rPam.Start()->nNode.GetNode().GetTxtNode();
+        const SwTxtNode* pEndTxtNd = rPam.End()->nNode.GetNode().GetTxtNode();
+        if ( pTxtNd && pTxtNd->IsInList() &&
+             pEndTxtNd && pEndTxtNd->IsInList() )
+        {
+            bRet = true;
+            SwNodeIndex aIdx(rPam.Start()->nNode);
+
+            do
+            {
+                ++aIdx;
+                pTxtNd = aIdx.GetNode().GetTxtNode();
+
+                if ( !pTxtNd || !pTxtNd->IsInList() )
+                {
+                    bRet = false;
+                    break;
+                }
+            } while ( pTxtNd && pTxtNd != pEndTxtNd );
+        }
+
+        return bRet;
+    }
+
+    static bool lcl_MarksWholeNode(const SwPaM & rPam)
+    {
+        bool bResult = false;
+        const SwPosition* pStt = rPam.Start();
+        const SwPosition* pEnd = rPam.End();
+
+        if (NULL != pStt && NULL != pEnd)
+        {
+            const SwTxtNode* pSttNd = pStt->nNode.GetNode().GetTxtNode();
+            const SwTxtNode* pEndNd = pEnd->nNode.GetNode().GetTxtNode();
+
+            if (NULL != pSttNd && NULL != pEndNd &&
+                pStt->nContent.GetIndex() == 0 &&
+                pEnd->nContent.GetIndex() == pEndNd->Len())
+            {
+                bResult = true;
+            }
+        }
+
+        return bResult;
+    }
+}
+
+//local functions originally from sw/source/core/doc/docedt.cxx
+namespace
+{
+    static void
+    lcl_CalcBreaks( ::std::vector<sal_Int32> & rBreaks, SwPaM const & rPam )
+    {
+        SwTxtNode const * const pTxtNode(
+                rPam.End()->nNode.GetNode().GetTxtNode() );
+        if (!pTxtNode)
+            return; // left-overlap only possible at end of selection...
+
+        const sal_Int32 nStart(rPam.Start()->nContent.GetIndex());
+        const sal_Int32 nEnd  (rPam.End  ()->nContent.GetIndex());
+        if (nEnd == pTxtNode->Len())
+            return; // paragraph selected until the end
+
+        for (sal_Int32 i = nStart; i < nEnd; ++i)
+        {
+            const sal_Unicode c(pTxtNode->GetTxt()[i]);
+            if ((CH_TXTATR_INWORD == c) || (CH_TXTATR_BREAKWORD == c))
+            {
+                SwTxtAttr const * const pAttr( pTxtNode->GetTxtAttrForCharAt(i) );
+                if (pAttr && pAttr->End() && (*pAttr->End() > nEnd))
+                {
+                    OSL_ENSURE(pAttr->HasDummyChar(), "GetTxtAttrForCharAt broken?");
+                    rBreaks.push_back(i);
+                }
+            }
+        }
+    }
+
+    static bool lcl_DoWithBreaks(::sw::DocumentContentOperationsManager & rDocumentContentOperations, SwPaM & rPam,
+            bool (::sw::DocumentContentOperationsManager::*pFunc)(SwPaM&, bool), const bool bForceJoinNext = false)
+    {
+        ::std::vector<sal_Int32> Breaks;
+
+        lcl_CalcBreaks(Breaks, rPam);
+
+        if (!Breaks.size())
+        {
+            return (rDocumentContentOperations.*pFunc)(rPam, bForceJoinNext);
+        }
+
+        // Deletion must be split into several parts if the text node
+        // contains a text attribute with end and with dummy character
+        // and the selection does not contain the text attribute completely,
+        // but overlaps its start (left), where the dummy character is.
+
+        SwPosition const & rSelectionEnd( *rPam.End() );
+
+        bool bRet( true );
+        // iterate from end to start, to avoid invalidating the offsets!
+        ::std::vector<sal_Int32>::reverse_iterator iter( Breaks.rbegin() );
+        SwPaM aPam( rSelectionEnd, rSelectionEnd ); // end node!
+        SwPosition & rEnd( *aPam.End() );
+        SwPosition & rStart( *aPam.Start() );
+
+        while (iter != Breaks.rend())
+        {
+            rStart.nContent = *iter + 1;
+            if (rEnd.nContent > rStart.nContent) // check if part is empty
+            {
+                bRet &= (rDocumentContentOperations.*pFunc)(aPam, bForceJoinNext);
+            }
+            rEnd.nContent = *iter;
+            ++iter;
+        }
+
+        rStart = *rPam.Start(); // set to original start
+        if (rEnd.nContent > rStart.nContent) // check if part is empty
+        {
+            bRet &= (rDocumentContentOperations.*pFunc)(aPam, bForceJoinNext);
+        }
+
+        return bRet;
+    }
+
+    static bool lcl_StrLenOverflow( const SwPaM& rPam )
+    {
+        // If we try to merge two paragraphs we have to test if afterwards
+        // the string doesn't exceed the allowed string length
+        if( rPam.GetPoint()->nNode != rPam.GetMark()->nNode )
+        {
+            const SwPosition* pStt = rPam.Start(), *pEnd = rPam.End();
+            const SwTxtNode* pEndNd = pEnd->nNode.GetNode().GetTxtNode();
+            if( (0 != pEndNd) && pStt->nNode.GetNode().IsTxtNode() )
+            {
+                const sal_uInt64 nSum = pStt->nContent.GetIndex() +
+                    pEndNd->GetTxt().getLength() - pEnd->nContent.GetIndex();
+                return nSum > static_cast<sal_uInt64>(SAL_MAX_INT32);
+            }
+        }
+        return false;
+    }
+
+    struct _SaveRedline
+    {
+        SwRangeRedline* pRedl;
+        sal_uInt32 nStt, nEnd;
+        sal_Int32 nSttCnt;
+        sal_Int32 nEndCnt;
+
+        _SaveRedline( SwRangeRedline* pR, const SwNodeIndex& rSttIdx )
+            : pRedl(pR)
+            , nEnd(0)
+            , nEndCnt(0)
+        {
+            const SwPosition* pStt = pR->Start(),
+                * pEnd = pR->GetMark() == pStt ? pR->GetPoint() : pR->GetMark();
+            sal_uInt32 nSttIdx = rSttIdx.GetIndex();
+            nStt = pStt->nNode.GetIndex() - nSttIdx;
+            nSttCnt = pStt->nContent.GetIndex();
+            if( pR->HasMark() )
+            {
+                nEnd = pEnd->nNode.GetIndex() - nSttIdx;
+                nEndCnt = pEnd->nContent.GetIndex();
+            }
+
+            pRedl->GetPoint()->nNode = 0;
+            pRedl->GetPoint()->nContent.Assign( 0, 0 );
+            pRedl->GetMark()->nNode = 0;
+            pRedl->GetMark()->nContent.Assign( 0, 0 );
+        }
+
+        _SaveRedline( SwRangeRedline* pR, const SwPosition& rPos )
+            : pRedl(pR)
+            , nEnd(0)
+            , nEndCnt(0)
+        {
+            const SwPosition* pStt = pR->Start(),
+                * pEnd = pR->GetMark() == pStt ? pR->GetPoint() : pR->GetMark();
+            sal_uInt32 nSttIdx = rPos.nNode.GetIndex();
+            nStt = pStt->nNode.GetIndex() - nSttIdx;
+            nSttCnt = pStt->nContent.GetIndex();
+            if( nStt == 0 )
+                nSttCnt = nSttCnt - rPos.nContent.GetIndex();
+            if( pR->HasMark() )
+            {
+                nEnd = pEnd->nNode.GetIndex() - nSttIdx;
+                nEndCnt = pEnd->nContent.GetIndex();
+                if( nEnd == 0 )
+                    nEndCnt = nEndCnt - rPos.nContent.GetIndex();
+            }
+
+            pRedl->GetPoint()->nNode = 0;
+            pRedl->GetPoint()->nContent.Assign( 0, 0 );
+            pRedl->GetMark()->nNode = 0;
+            pRedl->GetMark()->nContent.Assign( 0, 0 );
+        }
+
+        void SetPos( sal_uInt32 nInsPos )
+        {
+            pRedl->GetPoint()->nNode = nInsPos + nStt;
+            pRedl->GetPoint()->nContent.Assign( pRedl->GetCntntNode(), nSttCnt );
+            if( pRedl->HasMark() )
+            {
+                pRedl->GetMark()->nNode = nInsPos + nEnd;
+                pRedl->GetMark()->nContent.Assign( pRedl->GetCntntNode(false), nEndCnt );
+            }
+        }
+
+        void SetPos( const SwPosition& aPos )
+        {
+            pRedl->GetPoint()->nNode = aPos.nNode.GetIndex() + nStt;
+            pRedl->GetPoint()->nContent.Assign( pRedl->GetCntntNode(), nSttCnt + ( nStt == 0 ? aPos.nContent.GetIndex() : 0 ) );
+            if( pRedl->HasMark() )
+            {
+                pRedl->GetMark()->nNode = aPos.nNode.GetIndex() + nEnd;
+                pRedl->GetMark()->nContent.Assign( pRedl->GetCntntNode(false), nEndCnt  + ( nEnd == 0 ? aPos.nContent.GetIndex() : 0 ) );
+            }
+        }
+    };
+
+    typedef boost::ptr_vector< _SaveRedline > _SaveRedlines;
+
+    static void lcl_SaveRedlines( const SwPaM& aPam, _SaveRedlines& rArr )
+    {
+        SwDoc* pDoc = aPam.GetNode().GetDoc();
+
+        const SwPosition* pStart = aPam.Start();
+        const SwPosition* pEnd = aPam.End();
+
+        // get first relevant redline
+        sal_uInt16 nCurrentRedline;
+        pDoc->GetRedline( *pStart, &nCurrentRedline );
+        if( nCurrentRedline > 0)
+            nCurrentRedline--;
+
+        // redline mode REDLINE_IGNORE|REDLINE_ON; save old mode
+        RedlineMode_t eOld = pDoc->GetRedlineMode();
+        pDoc->SetRedlineMode_intern( (RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON ));
+
+        // iterate over relevant redlines and decide for each whether it should
+        // be saved, or split + saved
+        SwRedlineTbl& rRedlineTable = const_cast<SwRedlineTbl&>( pDoc->GetRedlineTbl() );
+        for( ; nCurrentRedline < rRedlineTable.size(); nCurrentRedline++ )
+        {
+            SwRangeRedline* pCurrent = rRedlineTable[ nCurrentRedline ];
+            SwComparePosition eCompare =
+                ComparePosition( *pCurrent->Start(), *pCurrent->End(),
+                                 *pStart, *pEnd);
+
+            // we must save this redline if it overlaps aPam
+            // (we may have to split it, too)
+            if( eCompare == POS_OVERLAP_BEHIND  ||
+                eCompare == POS_OVERLAP_BEFORE  ||
+                eCompare == POS_OUTSIDE ||
+                eCompare == POS_INSIDE ||
+                eCompare == POS_EQUAL )
+            {
+                rRedlineTable.Remove( nCurrentRedline-- );
+
+                // split beginning, if necessary
+                if( eCompare == POS_OVERLAP_BEFORE  ||
+                    eCompare == POS_OUTSIDE )
+                {
+                    SwRangeRedline* pNewRedline = new SwRangeRedline( *pCurrent );
+                    *pNewRedline->End() = *pStart;
+                    *pCurrent->Start() = *pStart;
+                    pDoc->AppendRedline( pNewRedline, true );
+                }
+
+                // split end, if necessary
+                if( eCompare == POS_OVERLAP_BEHIND  ||
+                    eCompare == POS_OUTSIDE )
+                {
+                    SwRangeRedline* pNewRedline = new SwRangeRedline( *pCurrent );
+                    *pNewRedline->Start() = *pEnd;
+                    *pCurrent->End() = *pEnd;
+                    pDoc->AppendRedline( pNewRedline, true );
+                }
+
+                // save the current redline
+                _SaveRedline* pSave = new _SaveRedline( pCurrent, *pStart );
+                rArr.push_back( pSave );
+            }
+        }
+
+        // restore old redline mode
+        pDoc->SetRedlineMode_intern( eOld );
+    }
+
+    static void lcl_RestoreRedlines( SwDoc* pDoc, const SwPosition& rPos, _SaveRedlines& rArr )
+    {
+        RedlineMode_t eOld = pDoc->GetRedlineMode();
+        pDoc->SetRedlineMode_intern( (RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON ));
+
+        for( size_t n = 0; n < rArr.size(); ++n )
+        {
+            rArr[ n ].SetPos( rPos );
+            pDoc->AppendRedline( rArr[ n ].pRedl, true );
+        }
+
+        pDoc->SetRedlineMode_intern( eOld );
+    }
+
+    static void lcl_SaveRedlines( const SwNodeRange& rRg, _SaveRedlines& rArr )
+    {
+        SwDoc* pDoc = rRg.aStart.GetNode().GetDoc();
+        sal_uInt16 nRedlPos;
+        SwPosition aSrchPos( rRg.aStart ); aSrchPos.nNode--;
+        aSrchPos.nContent.Assign( aSrchPos.nNode.GetNode().GetCntntNode(), 0 );
+        if( pDoc->GetRedline( aSrchPos, &nRedlPos ) && nRedlPos )
+            --nRedlPos;
+        else if( nRedlPos >= pDoc->GetRedlineTbl().size() )
+            return ;
+
+        RedlineMode_t eOld = pDoc->GetRedlineMode();
+        pDoc->SetRedlineMode_intern( (RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON ));
+        SwRedlineTbl& rRedlTbl = (SwRedlineTbl&)pDoc->GetRedlineTbl();
+
+        do {
+            SwRangeRedline* pTmp = rRedlTbl[ nRedlPos ];
+
+            const SwPosition* pRStt = pTmp->Start(),
+                            * pREnd = pTmp->GetMark() == pRStt
+                                ? pTmp->GetPoint() : pTmp->GetMark();
+
+            if( pRStt->nNode < rRg.aStart )
+            {
+                if( pREnd->nNode > rRg.aStart && pREnd->nNode < rRg.aEnd )
+                {
+                    // Create a copy and set the end of the original to the end of the MoveArea.
+                    // The copy is moved too.
+                    SwRangeRedline* pNewRedl = new SwRangeRedline( *pTmp );
+                    SwPosition* pTmpPos = pNewRedl->Start();
+                    pTmpPos->nNode = rRg.aStart;
+                    pTmpPos->nContent.Assign(
+                                pTmpPos->nNode.GetNode().GetCntntNode(), 0 );
+
+                    _SaveRedline* pSave = new _SaveRedline( pNewRedl, rRg.aStart );
+                    rArr.push_back( pSave );
+
+                    pTmpPos = pTmp->End();
+                    pTmpPos->nNode = rRg.aEnd;
+                    pTmpPos->nContent.Assign(
+                                pTmpPos->nNode.GetNode().GetCntntNode(), 0 );
+                }
+                else if( pREnd->nNode == rRg.aStart )
+                {
+                    SwPosition* pTmpPos = pTmp->End();
+                    pTmpPos->nNode = rRg.aEnd;
+                    pTmpPos->nContent.Assign(
+                                pTmpPos->nNode.GetNode().GetCntntNode(), 0 );
+                }
+            }
+            else if( pRStt->nNode < rRg.aEnd )
+            {
+                rRedlTbl.Remove( nRedlPos-- );
+                if( pREnd->nNode < rRg.aEnd ||
+                    ( pREnd->nNode == rRg.aEnd && !pREnd->nContent.GetIndex()) )
+                {
+                    // move everything
+                    _SaveRedline* pSave = new _SaveRedline( pTmp, rRg.aStart );
+                    rArr.push_back( pSave );
+                }
+                else
+                {
+                    // split
+                    SwRangeRedline* pNewRedl = new SwRangeRedline( *pTmp );
+                    SwPosition* pTmpPos = pNewRedl->End();
+                    pTmpPos->nNode = rRg.aEnd;
+                    pTmpPos->nContent.Assign(
+                                pTmpPos->nNode.GetNode().GetCntntNode(), 0 );
+
+                    _SaveRedline* pSave = new _SaveRedline( pNewRedl, rRg.aStart );
+                    rArr.push_back( pSave );
+
+                    pTmpPos = pTmp->Start();
+                    pTmpPos->nNode = rRg.aEnd;
+                    pTmpPos->nContent.Assign(
+                                pTmpPos->nNode.GetNode().GetCntntNode(), 0 );
+                    pDoc->AppendRedline( pTmp, true );
+                }
+            }
+            else
+                break;
+
+        } while( ++nRedlPos < pDoc->GetRedlineTbl().size() );
+        pDoc->SetRedlineMode_intern( eOld );
+    }
+
+    static void lcl_RestoreRedlines( SwDoc* pDoc, sal_uInt32 nInsPos, _SaveRedlines& rArr )
+    {
+        RedlineMode_t eOld = pDoc->GetRedlineMode();
+        pDoc->SetRedlineMode_intern( (RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON ));
+
+        for( size_t n = 0; n < rArr.size(); ++n )
+        {
+            rArr[ n ].SetPos( nInsPos );
+            pDoc->AppendRedline( rArr[ n ].pRedl, true );
+        }
+
+        pDoc->SetRedlineMode_intern( eOld );
+    }
+
+    static bool lcl_SaveFtn( const SwNodeIndex& rSttNd, const SwNodeIndex& rEndNd,
+                     const SwNodeIndex& rInsPos,
+                     SwFtnIdxs& rFtnArr, SwFtnIdxs& rSaveArr,
+                     const SwIndex* pSttCnt = 0, const SwIndex* pEndCnt = 0 )
+    {
+        bool bUpdateFtn = false;
+        const SwNodes& rNds = rInsPos.GetNodes();
+        const bool bDelFtn = rInsPos.GetIndex() < rNds.GetEndOfAutotext().GetIndex() &&
+                    rSttNd.GetIndex() >= rNds.GetEndOfAutotext().GetIndex();
+        const bool bSaveFtn = !bDelFtn &&
+                        rInsPos.GetIndex() >= rNds.GetEndOfExtras().GetIndex();
+        if( !rFtnArr.empty() )
+        {
+
+            sal_uInt16 nPos;
+            rFtnArr.SeekEntry( rSttNd, &nPos );
+            SwTxtFtn* pSrch;
+            const SwNode* pFtnNd;
+
+            // Delete/save all that come after it
+            while( nPos < rFtnArr.size() && ( pFtnNd =
+                &( pSrch = rFtnArr[ nPos ] )->GetTxtNode())->GetIndex()
+                        <= rEndNd.GetIndex() )
+            {
+                const sal_Int32 nFtnSttIdx = pSrch->GetStart();
+                if( ( pEndCnt && pSttCnt )
+                    ? (( &rSttNd.GetNode() == pFtnNd &&
+                         pSttCnt->GetIndex() > nFtnSttIdx) ||
+                       ( &rEndNd.GetNode() == pFtnNd &&
+                        nFtnSttIdx >= pEndCnt->GetIndex() ))
+                    : ( &rEndNd.GetNode() == pFtnNd ))
+                {
+                    ++nPos;     // continue searching
+                }
+                else
+                {
+                    // delete it
+                    if( bDelFtn )
+                    {
+                        SwTxtNode& rTxtNd = (SwTxtNode&)pSrch->GetTxtNode();
+                        SwIndex aIdx( &rTxtNd, nFtnSttIdx );
+                        rTxtNd.EraseText( aIdx, 1 );
+                    }
+                    else
+                    {
+                        pSrch->DelFrms(0);
+                        rFtnArr.erase( rFtnArr.begin() + nPos );
+                        if( bSaveFtn )
+                            rSaveArr.insert( pSrch );
+                    }
+                    bUpdateFtn = true;
+                }
+            }
+
+            while( nPos-- && ( pFtnNd = &( pSrch = rFtnArr[ nPos ] )->
+                    GetTxtNode())->GetIndex() >= rSttNd.GetIndex() )
+            {
+                const sal_Int32 nFtnSttIdx = pSrch->GetStart();
+                if( !pEndCnt || !pSttCnt ||
+                    !( (( &rSttNd.GetNode() == pFtnNd &&
+                        pSttCnt->GetIndex() > nFtnSttIdx ) ||
+                       ( &rEndNd.GetNode() == pFtnNd &&
+                        nFtnSttIdx >= pEndCnt->GetIndex() )) ))
+                {
+                    if( bDelFtn )
+                    {
+                        // delete it
+                        SwTxtNode& rTxtNd = (SwTxtNode&)pSrch->GetTxtNode();
+                        SwIndex aIdx( &rTxtNd, nFtnSttIdx );
+                        rTxtNd.EraseText( aIdx, 1 );
+                    }
+                    else
+                    {
+                        pSrch->DelFrms(0);
+                        rFtnArr.erase( rFtnArr.begin() + nPos );
+                        if( bSaveFtn )
+                            rSaveArr.insert( pSrch );
+                    }
+                    bUpdateFtn = true;
+                }
+            }
+        }
+        // When moving from redline section into document content section, e.g.
+        // after loading a document with (delete-)redlines, the footnote array
+        // has to be adjusted... (#i70572)
+        if( bSaveFtn )
+        {
+            SwNodeIndex aIdx( rSttNd );
+            while( aIdx < rEndNd ) // Check the moved section
+            {
+                SwNode* pNode = &aIdx.GetNode();
+                if( pNode->IsTxtNode() ) // Looking for text nodes...
+                {
+                    SwpHints *pHints =
+                        static_cast<SwTxtNode*>(pNode)->GetpSwpHints();
+                    if( pHints && pHints->HasFtn() ) //...with footnotes
+                    {
+                        bUpdateFtn = true; // Heureka
+                        sal_uInt16 nCount = pHints->Count();
+                        for( sal_uInt16 i = 0; i < nCount; ++i )
+                        {
+                            SwTxtAttr *pAttr = pHints->GetTextHint( i );
+                            if ( pAttr->Which() == RES_TXTATR_FTN )
+                            {
+                                rSaveArr.insert( static_cast<SwTxtFtn*>(pAttr) );
+                            }
+                        }
+                    }
+                }
+                ++aIdx;
+            }
+        }
+        return bUpdateFtn;
+    }
+
+    static bool lcl_MayOverwrite( const SwTxtNode *pNode, const sal_Int32 nPos )
+    {
+        sal_Unicode const cChr = pNode->GetTxt()[nPos];
+        switch (cChr)
+        {
+            case CH_TXTATR_BREAKWORD:
+            case CH_TXTATR_INWORD:
+                return !pNode->GetTxtAttrForCharAt(nPos);// how could there be none?
+            case CH_TXT_ATR_FIELDSTART:
+            case CH_TXT_ATR_FIELDEND:
+            case CH_TXT_ATR_FORMELEMENT:
+                return false;
+            default:
+                return true;
+        }
+    }
+
+    static void lcl_SkipAttr( const SwTxtNode *pNode, SwIndex &rIdx, sal_Int32 &rStart )
+    {
+        if( !lcl_MayOverwrite( pNode, rStart ) )
+        {
+            // skip all special attributes
+            do {
+                ++rIdx;
+                rStart = rIdx.GetIndex();
+            } while (rStart < pNode->GetTxt().getLength()
+                   && !lcl_MayOverwrite(pNode, rStart) );
+        }
+    }
+
+    static bool lcl_GetTokenToParaBreak( OUString& rStr, OUString& rRet, bool bRegExpRplc )
+    {
+        if( bRegExpRplc )
+        {
+            sal_Int32 nPos = 0;
+            const OUString sPara("\\n");
+            for (;;)
+            {
+                nPos = rStr.indexOf( sPara, nPos );
+                if (nPos<0)
+                {
+                    break;
+                }
+                // Has this been escaped?
+                if( nPos && '\\' == rStr[nPos-1])
+                {
+                    ++nPos;
+                    if( nPos >= rStr.getLength() )
+                    {
+                        break;
+                    }
+                }
+                else
+                {
+                    rRet = rStr.copy( 0, nPos );
+                    rStr = rStr.copy( nPos + sPara.getLength() );
+                    return true;
+                }
+            }
+        }
+        rRet = rStr;
+        rStr = OUString();
+        return false;
+    }
+}
+
+namespace //local functions originally from docfmt.cxx
+{
+    #define DELETECHARSETS if ( bDelete ) { delete pCharSet; delete pOtherSet; }
+
+    /// Insert Hints according to content types;
+    // Is used in SwDoc::Insert(..., SwFmtHint &rHt)
+
+    static bool lcl_InsAttr(
+        SwDoc *const pDoc,
+        const SwPaM &rRg,
+        const SfxItemSet& rChgSet,
+        const SetAttrMode nFlags,
+        SwUndoAttr *const pUndo,
+        const bool bExpandCharToPara=false)
+    {
+        // Divide the Sets (for selections in Nodes)
+        const SfxItemSet* pCharSet = 0;
+        const SfxItemSet* pOtherSet = 0;
+        bool bDelete = false;
+        bool bCharAttr = false;
+        bool bOtherAttr = false;
+
+        // Check, if we can work with rChgSet or if we have to create additional SfxItemSets
+        if ( 1 == rChgSet.Count() )
+        {
+            SfxItemIter aIter( rChgSet );
+            const SfxPoolItem* pItem = aIter.FirstItem();
+            if (!IsInvalidItem(pItem))
+            {
+                const sal_uInt16 nWhich = pItem->Which();
+
+                if ( isCHRATR(nWhich) ||
+                     (RES_TXTATR_CHARFMT == nWhich) ||
+                     (RES_TXTATR_INETFMT == nWhich) ||
+                     (RES_TXTATR_AUTOFMT == nWhich) ||
+                     (RES_TXTATR_UNKNOWN_CONTAINER == nWhich) )
+                {
+                    pCharSet  = &rChgSet;
+                    bCharAttr = true;
+                }
+
+                if (    isPARATR(nWhich)
+                     || isPARATR_LIST(nWhich)
+                     || isFRMATR(nWhich)
+                     || isGRFATR(nWhich)
+                     || isUNKNOWNATR(nWhich) )
+                {
+                    pOtherSet = &rChgSet;
+                    bOtherAttr = true;
+                }
+            }
+        }
+
+        // Build new itemset if either
+        // - rChgSet.Count() > 1 or
+        // - The attribute in rChgSet does not belong to one of the above categories
+        if ( !bCharAttr && !bOtherAttr )
+        {
+            SfxItemSet* pTmpCharItemSet = new SfxItemSet( pDoc->GetAttrPool(),
+                                       RES_CHRATR_BEGIN, RES_CHRATR_END-1,
+                                       RES_TXTATR_AUTOFMT, RES_TXTATR_AUTOFMT,
+                                       RES_TXTATR_INETFMT, RES_TXTATR_INETFMT,
+                                       RES_TXTATR_CHARFMT, RES_TXTATR_CHARFMT,
+                   RES_TXTATR_UNKNOWN_CONTAINER, RES_TXTATR_UNKNOWN_CONTAINER,
+                                       0 );
+
+            SfxItemSet* pTmpOtherItemSet = new SfxItemSet( pDoc->GetAttrPool(),
+                                        RES_PARATR_BEGIN, RES_PARATR_END-1,
+                                        RES_PARATR_LIST_BEGIN, RES_PARATR_LIST_END-1,
+                                        RES_FRMATR_BEGIN, RES_FRMATR_END-1,
+                                        RES_GRFATR_BEGIN, RES_GRFATR_END-1,
+                                        RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1,
+                                        0 );
+
+            pTmpCharItemSet->Put( rChgSet );
+            pTmpOtherItemSet->Put( rChgSet );
+
+            pCharSet = pTmpCharItemSet;
+            pOtherSet = pTmpOtherItemSet;
+
+            bDelete = true;
+        }
+
+        SwHistory* pHistory = pUndo ? &pUndo->GetHistory() : 0;
+        bool bRet = false;
+        const SwPosition *pStt = rRg.Start(), *pEnd = rRg.End();
+        SwCntntNode* pNode = pStt->nNode.GetNode().GetCntntNode();
+
+        if( pNode && pNode->IsTxtNode() )
+        {
+            // #i27615#
+            if (rRg.IsInFrontOfLabel())
+            {
+                SwTxtNode * pTxtNd = pNode->GetTxtNode();
+                SwNumRule * pNumRule = pTxtNd->GetNumRule();
+
+                if ( !pNumRule )
+                {
+                    OSL_FAIL( "<InsAttr(..)> - PaM in front of label, but text node has no numbering rule set. This is a serious defect, please inform OD." );
+                    DELETECHARSETS
+                    return false;
+                }
+
+                int nLevel = pTxtNd->GetActualListLevel();
+
+                if (nLevel < 0)
+                    nLevel = 0;
+
+                if (nLevel >= MAXLEVEL)
+                    nLevel = MAXLEVEL - 1;
+
+                SwNumFmt aNumFmt = pNumRule->Get(static_cast<sal_uInt16>(nLevel));
+                SwCharFmt * pCharFmt =
+                    pDoc->FindCharFmtByName(aNumFmt.GetCharFmtName());
+
+                if (pCharFmt)
+                {
+                    if (pHistory)
+                        pHistory->Add(pCharFmt->GetAttrSet(), *pCharFmt);
+
+                    if ( pCharSet )
+                        pCharFmt->SetFmtAttr(*pCharSet);
+                }
+
+                DELETECHARSETS
+                return true;
+            }
+
+            const SwIndex& rSt = pStt->nContent;
+
+            // Attributes without an end do not have a range
+            if ( !bCharAttr && !bOtherAttr )
+            {
+                SfxItemSet aTxtSet( pDoc->GetAttrPool(),
+                            RES_TXTATR_NOEND_BEGIN, RES_TXTATR_NOEND_END-1 );
+                aTxtSet.Put( rChgSet );
+                if( aTxtSet.Count() )
+                {
+                    SwRegHistory history( pNode, *pNode, pHistory );
+                    bRet = history.InsertItems(
+                        aTxtSet, rSt.GetIndex(), rSt.GetIndex(), nFlags ) || bRet;
+
+                    if (bRet && (pDoc->IsRedlineOn() || (!pDoc->IsIgnoreRedline()
+                                    && !pDoc->GetRedlineTbl().empty())))
+                    {
+                        SwPaM aPam( pStt->nNode, pStt->nContent.GetIndex()-1,
+                                    pStt->nNode, pStt->nContent.GetIndex() );
+
+                        if( pUndo )
+                            pUndo->SaveRedlineData( aPam, true );
+
+                        if( pDoc->IsRedlineOn() )
+                            pDoc->AppendRedline( new SwRangeRedline( nsRedlineType_t::REDLINE_INSERT, aPam ), true);
+                        else
+                            pDoc->SplitRedline( aPam );
+                    }
+                }
+            }
+
+            // TextAttributes with an end never expand their range
+            if ( !bCharAttr && !bOtherAttr )
+            {
+                // CharFmt and URL attributes are treated separately!
+                // TEST_TEMP ToDo: AutoFmt!
+                SfxItemSet aTxtSet( pDoc->GetAttrPool(),
+                                    RES_TXTATR_REFMARK, RES_TXTATR_TOXMARK,
+                                    RES_TXTATR_META, RES_TXTATR_METAFIELD,
+                                    RES_TXTATR_CJK_RUBY, RES_TXTATR_CJK_RUBY,
+                                    RES_TXTATR_INPUTFIELD, RES_TXTATR_INPUTFIELD,
+                                    0 );
+
+                aTxtSet.Put( rChgSet );
+                if( aTxtSet.Count() )
+                {
+                    const sal_Int32 nInsCnt = rSt.GetIndex();
+                    const sal_Int32 nEnd = pStt->nNode == pEnd->nNode
+                                    ? pEnd->nContent.GetIndex()
+                                    : pNode->Len();
+                    SwRegHistory history( pNode, *pNode, pHistory );
+                    bRet = history.InsertItems( aTxtSet, nInsCnt, nEnd, nFlags )
+                           || bRet;
+
+                    if (bRet && (pDoc->IsRedlineOn() || (!pDoc->IsIgnoreRedline()
+                                    && !pDoc->GetRedlineTbl().empty())))
+                    {
+                        // Was text content inserted? (RefMark/TOXMarks without an end)
+                        bool bTxtIns = nInsCnt != rSt.GetIndex();
+                        // Was content inserted or set over the selection?
+                        SwPaM aPam( pStt->nNode, bTxtIns ? nInsCnt + 1 : nEnd,
+                                    pStt->nNode, nInsCnt );
+                        if( pUndo )
+                            pUndo->SaveRedlineData( aPam, bTxtIns );
+
+                        if( pDoc->IsRedlineOn() )
+                            pDoc->AppendRedline(
+                                new SwRangeRedline(
+                                    bTxtIns ? nsRedlineType_t::REDLINE_INSERT : nsRedlineType_t::REDLINE_FORMAT, aPam ),
+                                    true);
+                        else if( bTxtIns )
+                            pDoc->SplitRedline( aPam );
+                    }
+                }
+            }
+        }
+
+        // We always have to set the auto flag for PageDescs that are set at the Node!
+        if( pOtherSet && pOtherSet->Count() )
+        {
+            SwTableNode* pTblNd;
+            const SwFmtPageDesc* pDesc;
+            if( SFX_ITEM_SET == pOtherSet->GetItemState( RES_PAGEDESC,
+                            false, (const SfxPoolItem**)&pDesc ))
+            {
+                if( pNode )
+                {
+                    // Set auto flag. Only in the template it's without auto!
+                    SwFmtPageDesc aNew( *pDesc );
+
+                    // Tables now also know line breaks
+                    if( 0 == (nFlags & nsSetAttrMode::SETATTR_APICALL) &&
+                        0 != ( pTblNd = pNode->FindTableNode() ) )
+                    {
+                        SwTableNode* pCurTblNd = pTblNd;
+                        while ( 0 != ( pCurTblNd = pCurTblNd->StartOfSectionNode()->FindTableNode() ) )
+                            pTblNd = pCurTblNd;
+
+                        // set the table format
+                        SwFrmFmt* pFmt = pTblNd->GetTable().GetFrmFmt();
+                        SwRegHistory aRegH( pFmt, *pTblNd, pHistory );
+                        pFmt->SetFmtAttr( aNew );
+                        bRet = true;
+                    }
+                    else
+                    {
+                        SwRegHistory aRegH( pNode, *pNode, pHistory );
+                        bRet = pNode->SetAttr( aNew ) || bRet;
+                    }
+                }
+
+                // bOtherAttr = true means that pOtherSet == rChgSet. In this case
+                // we know, that there is only one attribute in pOtherSet. We cannot
+                // perform the following operations, instead we return:
+                if ( bOtherAttr )
+                    return bRet;
+
+                const_cast<SfxItemSet*>(pOtherSet)->ClearItem( RES_PAGEDESC );
+                if( !pOtherSet->Count() )
+                {
+                    DELETECHARSETS
+                    return bRet;
+                }
+            }
+
+            // Tables now also know line breaks
+            const SvxFmtBreakItem* pBreak;
+            if( pNode && 0 == (nFlags & nsSetAttrMode::SETATTR_APICALL) &&
+                0 != (pTblNd = pNode->FindTableNode() ) &&
+                SFX_ITEM_SET == pOtherSet->GetItemState( RES_BREAK,
+                            false, (const SfxPoolItem**)&pBreak ) )
+            {
+                SwTableNode* pCurTblNd = pTblNd;
+                while ( 0 != ( pCurTblNd = pCurTblNd->StartOfSectionNode()->FindTableNode() ) )
+                    pTblNd = pCurTblNd;
+
+                 // set the table format
+                SwFrmFmt* pFmt = pTblNd->GetTable().GetFrmFmt();
+                SwRegHistory aRegH( pFmt, *pTblNd, pHistory );
+                pFmt->SetFmtAttr( *pBreak );
+                bRet = true;
+
+                // bOtherAttr = true means that pOtherSet == rChgSet. In this case
+                // we know, that there is only one attribute in pOtherSet. We cannot
+                // perform the following operations, instead we return:
+                if ( bOtherAttr )
+                    return bRet;
+
+                const_cast<SfxItemSet*>(pOtherSet)->ClearItem( RES_BREAK );
+                if( !pOtherSet->Count() )
+                {
+                    DELETECHARSETS
+                    return bRet;
+                }
+            }
+
+            {
+                // If we have a PoolNumRule, create it if needed
+                const SwNumRuleItem* pRule;
+                sal_uInt16 nPoolId=0;
+                if( SFX_ITEM_SET == pOtherSet->GetItemState( RES_PARATR_NUMRULE,
+                                    false, (const SfxPoolItem**)&pRule ) &&
+                    !pDoc->FindNumRulePtr( pRule->GetValue() ) &&
+                    USHRT_MAX != (nPoolId = SwStyleNameMapper::GetPoolIdFromUIName ( pRule->GetValue(),
+                                    nsSwGetPoolIdFromName::GET_POOLID_NUMRULE )) )
+                    pDoc->GetNumRuleFromPool( nPoolId );
+            }
+        }
+
+        if( !rRg.HasMark() )        // no range
+        {
+            if( !pNode )
+            {
+                DELETECHARSETS
+                return bRet;
+            }
+
+            if( pNode->IsTxtNode() && pCharSet && pCharSet->Count() )
+            {
+                SwTxtNode* pTxtNd = static_cast<SwTxtNode*>(pNode);
+                const SwIndex& rSt = pStt->nContent;
+                sal_Int32 nMkPos, nPtPos = rSt.GetIndex();
+                const OUString& rStr = pTxtNd->GetTxt();
+
+                // Special case: if the Crsr is located within a URL attribute, we take over it's area
+                SwTxtAttr const*const pURLAttr(
+                    pTxtNd->GetTxtAttrAt(rSt.GetIndex(), RES_TXTATR_INETFMT));
+                if (pURLAttr && !pURLAttr->GetINetFmt().GetValue().isEmpty())
+                {
+                    nMkPos = pURLAttr->GetStart();
+                    nPtPos = *pURLAttr->End();
+                }
+                else
+                {
+                    Boundary aBndry;
+                    if( g_pBreakIt->GetBreakIter().is() )
+                        aBndry = g_pBreakIt->GetBreakIter()->getWordBoundary(
+                                    pTxtNd->GetTxt(), nPtPos,
+                                    g_pBreakIt->GetLocale( pTxtNd->GetLang( nPtPos ) ),
+                                    WordType::ANY_WORD /*ANYWORD_IGNOREWHITESPACES*/,
+                                    sal_True );
+
+                    if( aBndry.startPos < nPtPos && nPtPos < aBndry.endPos )
+                    {
+                        nMkPos = aBndry.startPos;
+                        nPtPos = aBndry.endPos;
+                    }
+                    else
+                        nPtPos = nMkPos = rSt.GetIndex();
+                }
+
+                // Remove the overriding attributes from the SwpHintsArray,
+                // if the selection spans across the whole paragraph.
+                // These attributes are inserted as FormatAttributes and
+                // never override the TextAttributes!
+                if( !(nFlags & nsSetAttrMode::SETATTR_DONTREPLACE ) &&
+                    pTxtNd->HasHints() && !nMkPos && nPtPos == rStr.getLength())
+                {
+                    SwIndex aSt( pTxtNd );
+                    if( pHistory )
+                    {
+                        // Save all attributes for the Undo.
+                        SwRegHistory aRHst( *pTxtNd, pHistory );
+                        pTxtNd->GetpSwpHints()->Register( &aRHst );
+                        pTxtNd->RstTxtAttr( aSt, nPtPos, 0, pCharSet );
+                        if( pTxtNd->GetpSwpHints() )
+                            pTxtNd->GetpSwpHints()->DeRegister();
+                    }
+                    else
+                        pTxtNd->RstTxtAttr( aSt, nPtPos, 0, pCharSet );
+                }
+
+                // the SwRegHistory inserts the attribute into the TxtNode!
+                SwRegHistory history( pNode, *pNode, pHistory );
+                bRet = history.InsertItems( *pCharSet, nMkPos, nPtPos, nFlags )
+                    || bRet;
+
+                if( pDoc->IsRedlineOn() )
+                {
+                    SwPaM aPam( *pNode, nMkPos, *pNode, nPtPos );
+
+                    if( pUndo )
+                        pUndo->SaveRedlineData( aPam, false );
+                    pDoc->AppendRedline( new SwRangeRedline( nsRedlineType_t::REDLINE_FORMAT, aPam ), true);
+                }
+            }
+            if( pOtherSet && pOtherSet->Count() )
+            {
+                SwRegHistory aRegH( pNode, *pNode, pHistory );
+                bRet = pNode->SetAttr( *pOtherSet ) || bRet;
+            }
+
+            DELETECHARSETS
+            return bRet;
+        }
+
+        if( pDoc->IsRedlineOn() && pCharSet && pCharSet->Count() )
+        {
+            if( pUndo )
+                pUndo->SaveRedlineData( rRg, false );
+            pDoc->AppendRedline( new SwRangeRedline( nsRedlineType_t::REDLINE_FORMAT, rRg ), true);
+        }
+
+        /* now if range */
+        sal_uLong nNodes = 0;
+
+        SwNodeIndex aSt( pDoc->GetNodes() );
+        SwNodeIndex aEnd( pDoc->GetNodes() );
+        SwIndex aCntEnd( pEnd->nContent );
+
+        if( pNode )
+        {
+            const sal_Int32 nLen = pNode->Len();
+            if( pStt->nNode != pEnd->nNode )
+                aCntEnd.Assign( pNode, nLen );
+
+            if( pStt->nContent.GetIndex() != 0 || aCntEnd.GetIndex() != nLen )
+            {
+                // the SwRegHistory inserts the attribute into the TxtNode!
+                if( pNode->IsTxtNode() && pCharSet && pCharSet->Count() )
+                {
+                    SwRegHistory history( pNode, *pNode, pHistory );
+                    bRet = history.InsertItems(*pCharSet,
+                            pStt->nContent.GetIndex(), aCntEnd.GetIndex(), nFlags)
+                        || bRet;
+                }
+
+                if( pOtherSet && pOtherSet->Count() )
+                {
+                    SwRegHistory aRegH( pNode, *pNode, pHistory );
+                    bRet = pNode->SetAttr( *pOtherSet ) || bRet;
+                }
+
+                // Only selection in a Node.
+                if( pStt->nNode == pEnd->nNode )
+                {
+                //The data parameter flag: bExpandCharToPara, comes from the data member of SwDoc,
+                //Which is set in SW MS word Binary filter WW8ImplRreader. With this flag on, means that
+                //current setting attribute set is a character range properties set and comes from a MS word
+                //binary file, And the setting range include a paragraph end position (0X0D);
+                //More specifications, as such property inside the character range properties set recorded in
+                //MS word binary file are dealed and inserted into data model (SwDoc) one by one, so we
+                //only dealing the scenario that the char properties set with 1 item inside;
+
+                    if (bExpandCharToPara && pCharSet && pCharSet->Count() ==1 )
+                    {
+                        SwTxtNode* pCurrentNd = pStt->nNode.GetNode().GetTxtNode();
+
+                        if (pCurrentNd)
+                        {
+                             pCurrentNd->TryCharSetExpandToNum(*pCharSet);
+
+                        }
+                    }
+                    DELETECHARSETS
+                    return bRet;
+                }
+                ++nNodes;
+                aSt.Assign( pStt->nNode.GetNode(), +1 );
+            }
+            else
+                aSt = pStt->nNode;
+            aCntEnd = pEnd->nContent; // aEnd was changed!
+        }
+        else
+            aSt.Assign( pStt->nNode.GetNode(), +1 );
+
+        // aSt points to the first full Node now
+
+        /*
+         * The selection spans more than one Node.
+         */
+        if( pStt->nNode < pEnd->nNode )
+        {
+            pNode = pEnd->nNode.GetNode().GetCntntNode();
+            if(pNode)
+            {
+                if( aCntEnd.GetIndex() != pNode->Len() )
+                {
+                    // the SwRegHistory inserts the attribute into the TxtNode!
+                    if( pNode->IsTxtNode() && pCharSet && pCharSet->Count() )
+                    {
+                        SwRegHistory history( pNode, *pNode, pHistory );
+                        history.InsertItems(*pCharSet,
+                                0, aCntEnd.GetIndex(), nFlags);
+                    }
+
+                    if( pOtherSet && pOtherSet->Count() )
+                    {
+                        SwRegHistory aRegH( pNode, *pNode, pHistory );
+                        pNode->SetAttr( *pOtherSet );
+                    }
+
+                    ++nNodes;
+                    aEnd = pEnd->nNode;
+                }
+                else
+                    aEnd.Assign( pEnd->nNode.GetNode(), +1 );
+            }
+            else
+                aEnd = pEnd->nNode;
+        }
+        else
+            aEnd.Assign( pEnd->nNode.GetNode(), +1 );
+
+        // aEnd points BEHIND the last full node now
+
+        /* Edit the fully selected Nodes. */
+        // Reset all attributes from the set!
+        if( pCharSet && pCharSet->Count() && !( nsSetAttrMode::SETATTR_DONTREPLACE & nFlags ) )
+        {
+            sw::DocumentContentOperationsManager::ParaRstFmt aPara( pStt, pEnd, pHistory, 0, pCharSet );
+            pDoc->GetNodes().ForEach( aSt, aEnd, sw::DocumentContentOperationsManager::lcl_RstTxtAttr, &aPara );
+        }
+
+        bool bCreateSwpHints = pCharSet && (
+            SFX_ITEM_SET == pCharSet->GetItemState( RES_TXTATR_CHARFMT, false ) ||
+            SFX_ITEM_SET == pCharSet->GetItemState( RES_TXTATR_INETFMT, false ) );
+
+        for(; aSt < aEnd; ++aSt )
+        {
+            pNode = aSt.GetNode().GetCntntNode();
+            if( !pNode )
+                continue;
+
+            SwTxtNode* pTNd = pNode->GetTxtNode();
+            if( pHistory )
+            {
+                SwRegHistory aRegH( pNode, *pNode, pHistory );
+                SwpHints *pSwpHints;
+
+                if( pTNd && pCharSet && pCharSet->Count() )
+                {
+                    pSwpHints = bCreateSwpHints ? &pTNd->GetOrCreateSwpHints()
+                                                : pTNd->GetpSwpHints();
+                    if( pSwpHints )
+                        pSwpHints->Register( &aRegH );
+
+                    pTNd->SetAttr(*pCharSet, 0, pTNd->GetTxt().getLength(), nFlags);
+                    if( pSwpHints )
+                        pSwpHints->DeRegister();
+                }
+                if( pOtherSet && pOtherSet->Count() )
+                    pNode->SetAttr( *pOtherSet );
+            }
+            else
+            {
+                if( pTNd && pCharSet && pCharSet->Count() )
+                    pTNd->SetAttr(*pCharSet, 0, pTNd->GetTxt().getLength(), nFlags);
+                if( pOtherSet && pOtherSet->Count() )
+                    pNode->SetAttr( *pOtherSet );
+            }
+            ++nNodes;
+        }
+
+        //The data parameter flag: bExpandCharToPara, comes from the data member of SwDoc,
+        //Which is set in SW MS word Binary filter WW8ImplRreader. With this flag on, means that
+        //current setting attribute set is a character range properties set and comes from a MS word
+        //binary file, And the setting range include a paragraph end position (0X0D);
+        //More specifications, as such property inside the character range properties set recorded in
+        //MS word binary file are dealed and inserted into data model (SwDoc) one by one, so we
+        //only dealing the scenario that the char properties set with 1 item inside;
+        if (bExpandCharToPara && pCharSet && pCharSet->Count() ==1)
+        {
+            SwPosition aStartPos (*rRg.Start());
+            SwPosition aEndPos (*rRg.End());
+
+            if (aEndPos.nNode.GetNode().GetTxtNode() && aEndPos.nContent != aEndPos.nNode.GetNode().GetTxtNode()->Len())
+                aEndPos.nNode--;
+
+            sal_uLong nStart = aStartPos.nNode.GetIndex();
+            sal_uLong nEnd = aEndPos.nNode.GetIndex();
+            for(; nStart <= nEnd; ++nStart)
+            {
+                SwNode* pNd = pDoc->GetNodes()[ nStart ];
+                if (!pNd || !pNd->IsTxtNode())
+                    continue;
+                SwTxtNode *pCurrentNd = (SwTxtNode*)pNd;
+                pCurrentNd->TryCharSetExpandToNum(*pCharSet);
+            }
+        }
+
+        DELETECHARSETS
+        return (nNodes != 0) || bRet;
+    }
+}
+
+namespace sw
+{
+
+DocumentContentOperationsManager::DocumentContentOperationsManager( SwDoc& i_rSwdoc ) : m_rSwdoc( i_rSwdoc )
+{
+}
+
+// Copy an area into this document or into another document
+bool
+DocumentContentOperationsManager::CopyRange( SwPaM& rPam, SwPosition& rPos, const bool bCopyAll ) const
+{
+    const SwPosition *pStt = rPam.Start(), *pEnd = rPam.End();
+
+    SwDoc* pDoc = rPos.nNode.GetNode().GetDoc();
+    bool bColumnSel = pDoc->IsClipBoard() && pDoc->IsColumnSelection();
+
+    // Catch if there's no copy to do
+    if( !rPam.HasMark() || ( *pStt >= *pEnd && !bColumnSel ) )
+        return false;
+
+    // Prevent copying in Flys that are anchored in the area
+    if( pDoc == &m_rSwdoc )
+    {
+        // Correct the Start-/EndNode
+        sal_uLong nStt = pStt->nNode.GetIndex(),
+                nEnd = pEnd->nNode.GetIndex(),
+                nDiff = nEnd - nStt +1;
+        SwNode* pNd = m_rSwdoc.GetNodes()[ nStt ];
+        if( pNd->IsCntntNode() && pStt->nContent.GetIndex() )
+            ++nStt, --nDiff;
+        if( (pNd = m_rSwdoc.GetNodes()[ nEnd ])->IsCntntNode() &&
+            ((SwCntntNode*)pNd)->Len() != pEnd->nContent.GetIndex() )
+            --nEnd, --nDiff;
+        if( nDiff &&
+            lcl_ChkFlyFly( pDoc, nStt, nEnd, rPos.nNode.GetIndex() ) )
+        {
+            return false;
+        }
+    }
+
+    SwPaM* pRedlineRange = 0;
+    if( pDoc->IsRedlineOn() ||
+        (!pDoc->IsIgnoreRedline() && !pDoc->GetRedlineTbl().empty() ) )
+        pRedlineRange = new SwPaM( rPos );
+
+    RedlineMode_t eOld = pDoc->GetRedlineMode();
+
+    bool bRet = false;
+
+    if( pDoc != &m_rSwdoc )
+    {   // ordinary copy
+        bRet = CopyImpl( rPam, rPos, true, bCopyAll, pRedlineRange );
+    }
+    else if( ! ( *pStt <= rPos && rPos < *pEnd &&
+            ( pStt->nNode != pEnd->nNode ||
+              !pStt->nNode.GetNode().IsTxtNode() )) )
+    {
+        // Copy to a position outside of the area, or copy a single TextNode
+        // Do an ordinary copy
+        bRet = CopyImpl( rPam, rPos, true, bCopyAll, pRedlineRange );
+    }
+    else
+    {
+        // Copy the area in itself
+        // Special case for handling an area with several nodes,
+        // or a single node that is not a TextNode
+        OSL_ENSURE( &m_rSwdoc == pDoc, " invalid copy branch!" );
+        OSL_FAIL("mst: i thought this could be dead code;"
+                "please tell me what you did to get here!");
+        pDoc->SetRedlineMode_intern((RedlineMode_t)(eOld | nsRedlineMode_t::REDLINE_IGNORE));
+
+        // Then copy the area to the underlying document area
+        // (with start/end nodes clamped) and move them to
+        // the desired position.
+
+        SwUndoCpyDoc* pUndo = 0;
+        // Save the Undo area
+        SwPaM aPam( rPos );
+        if (pDoc->GetIDocumentUndoRedo().DoesUndo())
+        {
+            pDoc->GetIDocumentUndoRedo().ClearRedo();
+            pUndo = new SwUndoCpyDoc( aPam );
+        }
+
+        {
+            ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo());
+            SwStartNode* pSttNd = pDoc->GetNodes().MakeEmptySection(
+                                SwNodeIndex( m_rSwdoc.GetNodes().GetEndOfAutotext() ));
+            aPam.GetPoint()->nNode = *pSttNd->EndOfSectionNode();
+            // copy without Frames
+            pDoc->GetDocumentContentOperationsManager().CopyImpl( rPam, *aPam.GetPoint(), false, bCopyAll, 0 );
+
+            aPam.GetPoint()->nNode = pDoc->GetNodes().GetEndOfAutotext();
+            aPam.SetMark();
+            SwCntntNode* pNode =
+                pDoc->GetNodes().GoPrevious( &aPam.GetMark()->nNode );
+            pNode->MakeEndIndex( &aPam.GetMark()->nContent );
+
+            aPam.GetPoint()->nNode = *aPam.GetNode().StartOfSectionNode();
+            pNode = pDoc->GetNodes().GoNext( &aPam.GetPoint()->nNode );
+            pNode->MakeStartIndex( &aPam.GetPoint()->nContent );
+            // move to desired position
+            pDoc->MoveRange( aPam, rPos, DOC_MOVEDEFAULT );
+
+            pNode = aPam.GetCntntNode();
+            *aPam.GetPoint() = rPos;      // Move the cursor for Undo
+            aPam.SetMark();               // also move the Mark
+            aPam.DeleteMark();            // But don't mark any area
+            pDoc->DeleteSection( pNode ); // Delete the area again
+        }
+
+        // if Undo is enabled, store the insertion range
+        if (pDoc->GetIDocumentUndoRedo().DoesUndo())
+        {
+            pUndo->SetInsertRange( aPam );
+            pDoc->GetIDocumentUndoRedo().AppendUndo(pUndo);
+        }
+
+        if( pRedlineRange )
+        {
+            pRedlineRange->SetMark();
+            *pRedlineRange->GetPoint() = *aPam.GetPoint();
+            *pRedlineRange->GetMark() = *aPam.GetMark();
+        }
+
+        pDoc->SetModified();
+        bRet = true;
+    }
+
+    pDoc->SetRedlineMode_intern( eOld );
+    if( pRedlineRange )
+    {
+        if( pDoc->IsRedlineOn() )
+            pDoc->AppendRedline( new SwRangeRedline( nsRedlineType_t::REDLINE_INSERT, *pRedlineRange ), true);
+        else
+            pDoc->SplitRedline( *pRedlineRange );
+        delete pRedlineRange;
+    }
+
+    return bRet;
+}
+
+/// Delete a full Section of the NodeArray.
+/// The passed Node is located somewhere in the designated Section.
+void DocumentContentOperationsManager::DeleteSection( SwNode *pNode )
+{
+    OSL_ENSURE( pNode, "Didn't pass a Node." );
+    SwStartNode* pSttNd = pNode->IsStartNode() ? (SwStartNode*)pNode
+                                               : pNode->StartOfSectionNode();
+    SwNodeIndex aSttIdx( *pSttNd ), aEndIdx( *pNode->EndOfSectionNode() );
+
+    // delete all Flys, Bookmarks, ...
+    DelFlyInRange( aSttIdx, aEndIdx );
+    m_rSwdoc.DeleteRedline( *pSttNd, true, USHRT_MAX );
+    _DelBookmarks(aSttIdx, aEndIdx);
+
+    {
+        // move all Crsr/StkCrsr/UnoCrsr out of the to-be-deleted area
+        SwNodeIndex aMvStt( aSttIdx, 1 );
+        m_rSwdoc.CorrAbs( aMvStt, aEndIdx, SwPosition( aSttIdx ), true );
+    }
+
+    m_rSwdoc.GetNodes().DelNodes( aSttIdx, aEndIdx.GetIndex() - aSttIdx.GetIndex() + 1 );
+}
+
+bool DocumentContentOperationsManager::DeleteRange( SwPaM & rPam )
+{
+    return lcl_DoWithBreaks( *this, rPam, &DocumentContentOperationsManager::DeleteRangeImpl );
+}
+
+bool DocumentContentOperationsManager::DelFullPara( SwPaM& rPam )
+{
+    const SwPosition &rStt = *rPam.Start(), &rEnd = *rPam.End();
+    const SwNode* pNd = &rStt.nNode.GetNode();
+    sal_uInt32 nSectDiff = pNd->StartOfSectionNode()->EndOfSectionIndex() -
+                        pNd->StartOfSectionIndex();
+    sal_uInt32 nNodeDiff = rEnd.nNode.GetIndex() - rStt.nNode.GetIndex();
+
+    if ( nSectDiff-2 <= nNodeDiff || m_rSwdoc.IsRedlineOn() ||
+         /* #i9185# Prevent getting the node after the end node (see below) */
+        rEnd.nNode.GetIndex() + 1 == m_rSwdoc.GetNodes().Count() )
+    {
+        return false;
+    }
+
+    // Move hard page brakes to the following Node.
+    bool bSavePageBreak = false, bSavePageDesc = false;
+
+    /* #i9185# This whould lead to a segmentation fault if not caught above. */
+    sal_uLong nNextNd = rEnd.nNode.GetIndex() + 1;
+    SwTableNode *const pTblNd = m_rSwdoc.GetNodes()[ nNextNd ]->GetTableNode();
+
+    if( pTblNd && pNd->IsCntntNode() )
+    {
+        SwFrmFmt* pTableFmt = pTblNd->GetTable().GetFrmFmt();
+
+        {
+            const SfxPoolItem *pItem;
+            const SfxItemSet* pSet = ((SwCntntNode*)pNd)->GetpSwAttrSet();
+            if( pSet && SFX_ITEM_SET == pSet->GetItemState( RES_PAGEDESC,
+                false, &pItem ) )
+            {
+                pTableFmt->SetFmtAttr( *pItem );
+                bSavePageDesc = true;
+            }
+
+            if( pSet && SFX_ITEM_SET == pSet->GetItemState( RES_BREAK,
+                false, &pItem ) )
+            {
+                pTableFmt->SetFmtAttr( *pItem );
+                bSavePageBreak = true;
+            }
+        }
+    }
+
+    bool const bDoesUndo = m_rSwdoc.GetIDocumentUndoRedo().DoesUndo();
+    if( bDoesUndo )
+    {
+        if( !rPam.HasMark() )
+            rPam.SetMark();
+        else if( rPam.GetPoint() == &rStt )
+            rPam.Exchange();
+        rPam.GetPoint()->nNode++;
+
+        SwCntntNode *pTmpNode = rPam.GetPoint()->nNode.GetNode().GetCntntNode();
+        rPam.GetPoint()->nContent.Assign( pTmpNode, 0 );
+        bool bGoNext = (0 == pTmpNode);
+        pTmpNode = rPam.GetMark()->nNode.GetNode().GetCntntNode();
+        rPam.GetMark()->nContent.Assign( pTmpNode, 0 );
+
+        m_rSwdoc.GetIDocumentUndoRedo().ClearRedo();
+
+        SwPaM aDelPam( *rPam.GetMark(), *rPam.GetPoint() );
+        {
+            SwPosition aTmpPos( *aDelPam.GetPoint() );
+            if( bGoNext )
+            {
+                pTmpNode = m_rSwdoc.GetNodes().GoNext( &aTmpPos.nNode );
+                aTmpPos.nContent.Assign( pTmpNode, 0 );
+            }
+            ::PaMCorrAbs( aDelPam, aTmpPos );
+        }
+
+        SwUndoDelete* pUndo = new SwUndoDelete( aDelPam, true );
+
+        *rPam.GetPoint() = *aDelPam.GetPoint();
+        pUndo->SetPgBrkFlags( bSavePageBreak, bSavePageDesc );
+        m_rSwdoc.GetIDocumentUndoRedo().AppendUndo(pUndo);
+    }
+    else
+    {
+        SwNodeRange aRg( rStt.nNode, rEnd.nNode );
+        if( rPam.GetPoint() != &rEnd )
+            rPam.Exchange();
+
+        // Try to move past the End
+        if( !rPam.Move( fnMoveForward, fnGoNode ) )
+        {
+            // Fair enough, at the Beginning then
+            rPam.Exchange();
+            if( !rPam.Move( fnMoveBackward, fnGoNode ))
+            {
+                OSL_FAIL( "no more Nodes" );
+                return false;
+            }
+        }
+        // move bookmarks, redlines etc.
+        if (aRg.aStart == aRg.aEnd) // only first CorrAbs variant handles this
+        {
+            m_rSwdoc.CorrAbs( aRg.aStart, *rPam.GetPoint(), 0, true );
+        }
+        else
+        {
+            m_rSwdoc.CorrAbs( aRg.aStart, aRg.aEnd, *rPam.GetPoint(), true );
+        }
+
+            // What's with Flys?
+        {
+            // If there are FlyFrames left, delete these too
+            for( sal_uInt16 n = 0; n < m_rSwdoc.GetSpzFrmFmts()->size(); ++n )
+            {
+                SwFrmFmt* pFly = (*m_rSwdoc.GetSpzFrmFmts())[n];
+                const SwFmtAnchor* pAnchor = &pFly->GetAnchor();
+                SwPosition const*const pAPos = pAnchor->GetCntntAnchor();
+                if (pAPos &&
+                    ((FLY_AT_PARA == pAnchor->GetAnchorId()) ||
+                     (FLY_AT_CHAR == pAnchor->GetAnchorId())) &&
+                    aRg.aStart <= pAPos->nNode && pAPos->nNode <= aRg.aEnd )
+                {
+                    m_rSwdoc.DelLayoutFmt( pFly );
+                    --n;
+                }
+            }
+        }
+
+        SwCntntNode *pTmpNode = rPam.GetBound( true ).nNode.GetNode().GetCntntNode();
+        rPam.GetBound( true ).nContent.Assign( pTmpNode, 0 );
+        pTmpNode = rPam.GetBound( false ).nNode.GetNode().GetCntntNode();
+        rPam.GetBound( false ).nContent.Assign( pTmpNode, 0 );
+        m_rSwdoc.GetNodes().Delete( aRg.aStart, nNodeDiff+1 );
+    }
+    rPam.DeleteMark();
+    m_rSwdoc.SetModified();
+
+    return true;
+}
+
+// #i100466# Add handling of new optional parameter <bForceJoinNext>
+bool DocumentContentOperationsManager::DeleteAndJoin( SwPaM & rPam,
+                           const bool bForceJoinNext )
+{
+    if ( lcl_StrLenOverflow( rPam ) )
+        return false;
+
+    return lcl_DoWithBreaks( *this, rPam, (m_rSwdoc.IsRedlineOn())
+                ? &DocumentContentOperationsManager::DeleteAndJoinWithRedlineImpl
+                : &DocumentContentOperationsManager::DeleteAndJoinImpl,
+                bForceJoinNext );
+}
+
+// It seems that this is mostly used by SwDoc internals; the only
+// way to call this from the outside seems to be the special case in
+// SwDoc::CopyRange (but I have not managed to actually hit that case).
+bool DocumentContentOperationsManager::MoveRange( SwPaM& rPaM, SwPosition& rPos, SwMoveFlags eMvFlags )
+{
+    // nothing moved: return
+    const SwPosition *pStt = rPaM.Start(), *pEnd = rPaM.End();
+    if( !rPaM.HasMark() || *pStt >= *pEnd || (*pStt <= rPos && rPos < *pEnd))
+        return false;
+
+    // Save the paragraph anchored Flys, so that they can be moved.
+    _SaveFlyArr aSaveFlyArr;
+    _SaveFlyInRange( rPaM, rPos.nNode, aSaveFlyArr, 0 != ( DOC_MOVEALLFLYS & eMvFlags ) );
+
+    // save redlines (if DOC_MOVEREDLINES is used)
+    _SaveRedlines aSaveRedl;
+    if( DOC_MOVEREDLINES & eMvFlags && !m_rSwdoc.GetRedlineTbl().empty() )
+    {
+        lcl_SaveRedlines( rPaM, aSaveRedl );
+
+        // #i17764# unfortunately, code below relies on undos being
+        //          in a particular order, and presence of bookmarks
+        //          will change this order. Hence, we delete bookmarks
+        //          here without undo.
+        ::sw::UndoGuard const undoGuard(m_rSwdoc.GetIDocumentUndoRedo());
+        _DelBookmarks(
+            pStt->nNode,
+            pEnd->nNode,
+            NULL,
+            &pStt->nContent,
+            &pEnd->nContent);
+    }
+
+    bool bUpdateFtn = false;
+    SwFtnIdxs aTmpFntIdx;
+
+    SwUndoMove * pUndoMove = 0;
+    if (m_rSwdoc.GetIDocumentUndoRedo().DoesUndo())
+    {
+        m_rSwdoc.GetIDocumentUndoRedo().ClearRedo();
+        pUndoMove = new SwUndoMove( rPaM, rPos );
+        pUndoMove->SetMoveRedlines( eMvFlags == DOC_MOVEREDLINES );
+    }
+    else
+    {
+        bUpdateFtn = lcl_SaveFtn( pStt->nNode, pEnd->nNode, rPos.nNode,
+                                    m_rSwdoc.GetFtnIdxs(), aTmpFntIdx,
+                                    &pStt->nContent, &pEnd->nContent );
+    }
+
+    bool bSplit = false;
+    SwPaM aSavePam( rPos, rPos );
+
+    // Move the SPoint to the beginning of the range
+    if( rPaM.GetPoint() == pEnd )
+        rPaM.Exchange();
+
+    // If there is a TextNode before and after the Move, create a JoinNext in the EditShell.
+    SwTxtNode* pSrcNd = rPaM.GetPoint()->nNode.GetNode().GetTxtNode();
+    bool bCorrSavePam = pSrcNd && pStt->nNode != pEnd->nNode;
+
+    // If one ore more TextNodes are moved, SwNodes::Move will do a SplitNode.
+    // However, this does not update the cursor. So we create a TextNode to keep
+    // updating the indices. After the Move the Node is optionally deleted.
+    SwTxtNode * pTNd = rPos.nNode.GetNode().GetTxtNode();
+    if( pTNd && rPaM.GetPoint()->nNode != rPaM.GetMark()->nNode &&
+        ( rPos.nContent.GetIndex() || ( pTNd->Len() && bCorrSavePam  )) )
+    {
+        bSplit = true;
+        const sal_Int32 nMkCntnt = rPaM.GetMark()->nContent.GetIndex();
+
+        const boost::shared_ptr<sw::mark::CntntIdxStore> pCntntStore(sw::mark::CntntIdxStore::Create());
+        pCntntStore->Save( &m_rSwdoc, rPos.nNode.GetIndex(), rPos.nContent.GetIndex(), SAVEFLY_SPLIT );
+
+        pTNd = static_cast<SwTxtNode*>(pTNd->SplitCntntNode( rPos ));
+
+        if( !pCntntStore->Empty() )
+            pCntntStore->Restore( &m_rSwdoc, rPos.nNode.GetIndex()-1, 0, true );
+
+        // correct the PaM!
+        if( rPos.nNode == rPaM.GetMark()->nNode )
+        {
+            rPaM.GetMark()->nNode = rPos.nNode.GetIndex()-1;
+            rPaM.GetMark()->nContent.Assign( pTNd, nMkCntnt );
+        }
+    }
+
+    // Put back the Pam by one "content"; so that it's always outside of
+    // the manipulated range.
+    // If there's no content anymore, set it to the StartNode (that's
+    // always there).
+    const bool bNullCntnt = !aSavePam.Move( fnMoveBackward, fnGoCntnt );
+    if( bNullCntnt )
+    {
+        aSavePam.GetPoint()->nNode--;
+    }
+
+    // Copy all Bookmarks that are within the Move range into an array,
+    // that saves the position as an offset.
+    ::std::vector< ::sw::mark::SaveBookmark> aSaveBkmks;
+    _DelBookmarks(
+        pStt->nNode,
+        pEnd->nNode,
+        &aSaveBkmks,
+        &pStt->nContent,
+        &pEnd->nContent);
+
+    // If there is no range anymore due to the above deletions (e.g. the
+    // footnotes got deleted), it's still a valid Move!
+    if( *rPaM.GetPoint() != *rPaM.GetMark() )
+    {
+        // now do the actual move
+        m_rSwdoc.GetNodes().MoveRange( rPaM, rPos, m_rSwdoc.GetNodes() );
+
+        // after a MoveRange() the Mark is deleted
+        if ( rPaM.HasMark() ) // => no Move occurred!
+        {
+            delete pUndoMove;
+            return false;
+        }
+    }
+    else
+        rPaM.DeleteMark();
+
+    OSL_ENSURE( *aSavePam.GetMark() == rPos ||
+            ( aSavePam.GetMark()->nNode.GetNode().GetCntntNode() == NULL ),
+            "PaM was not moved. Aren't there ContentNodes at the beginning/end?" );
+    *aSavePam.GetMark() = rPos;
+
+    rPaM.SetMark();         // create a Sel. around the new range
+    pTNd = aSavePam.GetNode().GetTxtNode();
+    if (m_rSwdoc.GetIDocumentUndoRedo().DoesUndo())
+    {
+        // correct the SavePam's Content first
+        if( bNullCntnt )
+        {
+            aSavePam.GetPoint()->nContent = 0;
+        }
+
+        // The method SwEditShell::Move() merges the TextNode after the Move,
+        // where the rPaM is located.
+        // If the Content was moved to the back and the SavePam's SPoint is
+        // in the next Node, we have to deal with this when saving the Undo object!
+        SwTxtNode * pPamTxtNd = 0;
+
+        // Is passed to SwUndoMove, which happens when subsequently calling Undo JoinNext.
+        // If it's not possible to call Undo JoinNext here.
+        bool bJoin = bSplit && pTNd;
+        bCorrSavePam = bCorrSavePam &&
+                        0 != ( pPamTxtNd = rPaM.GetNode().GetTxtNode() )
+                        && pPamTxtNd->CanJoinNext()
+                        && (*rPaM.GetPoint() <= *aSavePam.GetPoint());
+
+        // Do two Nodes have to be joined at the SavePam?
+        if( bJoin && pTNd->CanJoinNext() )
+        {
+            pTNd->JoinNext();
+            // No temporary Index when using &&.
+            // We probably only want to compare the indices.
+            if( bCorrSavePam && rPaM.GetPoint()->nNode.GetIndex()+1 ==
+                                aSavePam.GetPoint()->nNode.GetIndex() )
+            {
+                aSavePam.GetPoint()->nContent += pPamTxtNd->Len();
+            }
+            bJoin = false;
+        }
+        else if ( !aSavePam.Move( fnMoveForward, fnGoCntnt ) )
+        {
+            aSavePam.GetPoint()->nNode++;
+        }
+
+        // The newly inserted range is now inbetween SPoint and GetMark.
+        pUndoMove->SetDestRange( aSavePam, *rPaM.GetPoint(),
+                                    bJoin, bCorrSavePam );
+        m_rSwdoc.GetIDocumentUndoRedo().AppendUndo( pUndoMove );
+    }
+    else
+    {
+        bool bRemove = true;
+        // Do two Nodes have to be joined at the SavePam?
+        if( bSplit && pTNd )
+        {
+            if( pTNd->CanJoinNext())
+            {
+                // Always join next, because <pTNd> has to stay as it is.
+                // A join previous from its next would more or less delete <pTNd>
+                pTNd->JoinNext();
+                bRemove = false;
+            }
+        }
+        if( bNullCntnt )
+        {
+            aSavePam.GetPoint()->nNode++;
+            aSavePam.GetPoint()->nContent.Assign( aSavePam.GetCntntNode(), 0 );
+        }
+        else if( bRemove ) // No move forward after joining with next paragraph
+        {
+            aSavePam.Move( fnMoveForward, fnGoCntnt );
+        }
+    }
+
+    // Insert the Bookmarks back into the Document.
+    *rPaM.GetMark() = *aSavePam.Start();
+    for(
+        ::std::vector< ::sw::mark::SaveBookmark>::iterator pBkmk = aSaveBkmks.begin();
+        pBkmk != aSaveBkmks.end();
+        ++pBkmk)
+        pBkmk->SetInDoc(
+            &m_rSwdoc,
+            rPaM.GetMark()->nNode,
+            &rPaM.GetMark()->nContent);
+    *rPaM.GetPoint() = *aSavePam.End();
+
+    // Move the Flys to the new position.
+    _RestFlyInRange( aSaveFlyArr, rPaM.Start()->nNode, &(rPos.nNode) );
+
+    // restore redlines (if DOC_MOVEREDLINES is used)
+    if( !aSaveRedl.empty() )
+    {
+        lcl_RestoreRedlines( &m_rSwdoc, *aSavePam.Start(), aSaveRedl );
+    }
+
+    if( bUpdateFtn )
+    {
+        if( !aTmpFntIdx.empty() )
+        {
+            m_rSwdoc.GetFtnIdxs().insert( aTmpFntIdx );
+            aTmpFntIdx.clear();
+        }
+
+        m_rSwdoc.GetFtnIdxs().UpdateAllFtn();
+    }
+
+    m_rSwdoc.SetModified();
+    return true;
+}
+
+bool DocumentContentOperationsManager::MoveNodeRange( SwNodeRange& rRange, SwNodeIndex& rPos,
+        SwMoveFlags eMvFlags )
+{
+    // Moves all Nodes to the new position.
+    // Bookmarks are moved too (currently without Undo support).
+
+    // If footnotes are being moved to the special section, remove them now.
+
+    // Or else delete the Frames for all footnotes that are being moved
+    // and have it rebuild after the Move (footnotes can change pages).
+    // Additionally we have to correct the FtnIdx array's sorting.
+    bool bUpdateFtn = false;
+    SwFtnIdxs aTmpFntIdx;
+
+    SwUndoMove* pUndo = 0;
+    if ((DOC_CREATEUNDOOBJ & eMvFlags ) && m_rSwdoc.GetIDocumentUndoRedo().DoesUndo())
+    {
+        pUndo = new SwUndoMove( &m_rSwdoc, rRange, rPos );
+    }
+    else
+    {
+        bUpdateFtn = lcl_SaveFtn( rRange.aStart, rRange.aEnd, rPos,
+                                    m_rSwdoc.GetFtnIdxs(), aTmpFntIdx );
+    }
+
+    _SaveRedlines aSaveRedl;
+    std::vector<SwRangeRedline*> aSavRedlInsPosArr;
+    if( DOC_MOVEREDLINES & eMvFlags && !m_rSwdoc.GetRedlineTbl().empty() )
+    {
+        lcl_SaveRedlines( rRange, aSaveRedl );
+
+        // Find all RedLines that end at the InsPos.
+        // These have to be moved back to the "old" position after the Move.
+        sal_uInt16 nRedlPos = m_rSwdoc.GetRedlinePos( rPos.GetNode(), USHRT_MAX );
+        if( USHRT_MAX != nRedlPos )
+        {
+            const SwPosition *pRStt, *pREnd;
+            do {
+                SwRangeRedline* pTmp = m_rSwdoc.GetRedlineTbl()[ nRedlPos ];
+                pRStt = pTmp->Start();
+                pREnd = pTmp->End();
+                if( pREnd->nNode == rPos && pRStt->nNode < rPos )
+                {
+                    aSavRedlInsPosArr.push_back( pTmp );
+                }
+            } while( pRStt->nNode < rPos && ++nRedlPos < m_rSwdoc.GetRedlineTbl().size());
+        }
+    }
+
+    // Copy all Bookmarks that are within the Move range into an array
+    // that stores all references to positions as an offset.
+    // The final mapping happens after the Move.
+    ::std::vector< ::sw::mark::SaveBookmark> aSaveBkmks;
+    _DelBookmarks(rRange.aStart, rRange.aEnd, &aSaveBkmks);
+
+    // Save the paragraph-bound Flys, so that they can be moved.
+    _SaveFlyArr aSaveFlyArr;
+    if( !m_rSwdoc.GetSpzFrmFmts()->empty() )
+        _SaveFlyInRange( rRange, aSaveFlyArr );
+
+    // Set it to before the Position, so that it cannot be moved further.
+    SwNodeIndex aIdx( rPos, -1 );
+
+    SwNodeIndex* pSaveInsPos = 0;
+    if( pUndo )
+        pSaveInsPos = new SwNodeIndex( rRange.aStart, -1 );
+
+    // move the Nodes
+    bool bNoDelFrms = 0 != (DOC_NO_DELFRMS & eMvFlags);
+    if( m_rSwdoc.GetNodes()._MoveNodes( rRange, m_rSwdoc.GetNodes(), rPos, !bNoDelFrms ) )
+    {
+        ++aIdx;     // again back to old position
+        if( pSaveInsPos )
+            ++(*pSaveInsPos);
+    }
+    else
+    {
+        aIdx = rRange.aStart;
+        delete pUndo, pUndo = 0;
+    }
+
+    // move the Flys to the new position
+    if( !aSaveFlyArr.empty() )
+        _RestFlyInRange( aSaveFlyArr, aIdx, NULL );
+
+    // Add the Bookmarks back to the Document
+    for(
+        ::std::vector< ::sw::mark::SaveBookmark>::iterator pBkmk = aSaveBkmks.begin();
+        pBkmk != aSaveBkmks.end();
+        ++pBkmk)
+        pBkmk->SetInDoc(&m_rSwdoc, aIdx);
+
+    if( !aSavRedlInsPosArr.empty() )
+    {
+        SwNode* pNewNd = &aIdx.GetNode();
+        for( sal_uInt16 n = 0; n < aSavRedlInsPosArr.size(); ++n )
+        {
+            SwRangeRedline* pTmp = aSavRedlInsPosArr[ n ];
+            if( m_rSwdoc.GetRedlineTbl().Contains( pTmp ) )
+            {
+                SwPosition* pEnd = pTmp->End();
+                pEnd->nNode = aIdx;
+                pEnd->nContent.Assign( pNewNd->GetCntntNode(), 0 );
+            }
+        }
+    }
+
+    if( !aSaveRedl.empty() )
+        lcl_RestoreRedlines( &m_rSwdoc, aIdx.GetIndex(), aSaveRedl );
+
+    if( pUndo )
+    {
+        pUndo->SetDestRange( aIdx, rPos, *pSaveInsPos );
+        m_rSwdoc.GetIDocumentUndoRedo().AppendUndo(pUndo);
+    }
+
+    delete pSaveInsPos;
+
+    if( bUpdateFtn )
+    {
+        if( !aTmpFntIdx.empty() )
+        {
+            m_rSwdoc.GetFtnIdxs().insert( aTmpFntIdx );
+            aTmpFntIdx.clear();
+        }
+
+        m_rSwdoc.GetFtnIdxs().UpdateAllFtn();
+    }
+
+    m_rSwdoc.SetModified();
+    return true;
+}
+
+bool DocumentContentOperationsManager::MoveAndJoin( SwPaM& rPaM, SwPosition& rPos, SwMoveFlags eMvFlags )
+{

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list