API CHANGE: add a "position" parameter to XParagraph/TextPortionAppend methods

So we can use the new RTF import for clipboard pastes in Writer without
inserting text content to the end of the document only.

Notes:

- SwXText::insertTextPortion: the MovePara() call is removed, as all it did was
trying to move the cursor beyond the end of the document.
- SwRTFReader::Read: the double fake paragraph insertion / deletion is
motivated by the ODT filter.
- RtfFilter::filter: if TextInsertModeRange is not passed, then the behaviour
is not changed.

v2:

- added missing @since tags
- added insertTextContentWithProperties() method
- removed unused appendParagraph() method

Change-Id: I24cddb00a78e3b798e7d88764e59e6a77a6e98a4
Helped-by: Michael Stahl <mstahl@redhat.com>
diff --git a/editeng/inc/editeng/unotext.hxx b/editeng/inc/editeng/unotext.hxx
index 397e64b..13ab909 100644
--- a/editeng/inc/editeng/unotext.hxx
+++ b/editeng/inc/editeng/unotext.hxx
@@ -440,12 +440,14 @@ public:
    virtual void SAL_CALL moveTextRange( const ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextRange >& xRange, sal_Int16 nParagraphs ) throw(::com::sun::star::uno::RuntimeException);

    // com::sun::star::text::XParagraphAppend (new import API)
    virtual ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextRange > SAL_CALL appendParagraph( const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& CharacterAndParagraphProperties ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException);
    virtual ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextRange > SAL_CALL finishParagraph( const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& CharacterAndParagraphProperties ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException);
    virtual ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextRange > SAL_CALL finishParagraphInsert( const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& CharacterAndParagraphProperties, const ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextRange >& xInsertPosition ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException);

    // com::sun::star::text::XTextPortionAppend (new import API)
    virtual ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextRange > SAL_CALL appendTextPortion( const ::rtl::OUString& Text, const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& CharacterAndParagraphProperties ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException);

    virtual ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextRange > SAL_CALL insertTextPortion( const ::rtl::OUString& Text, const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& CharacterAndParagraphProperties, const com::sun::star::uno::Reference< com::sun::star::text::XTextRange>& rTextRange ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException);

    // com::sun::star::text::XTextCopy
    virtual void SAL_CALL copyText( const ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextCopy >& xSource ) throw (::com::sun::star::uno::RuntimeException);

diff --git a/editeng/source/uno/unotext.cxx b/editeng/source/uno/unotext.cxx
index 3b5033b..659f0f1 100644
--- a/editeng/source/uno/unotext.cxx
+++ b/editeng/source/uno/unotext.cxx
@@ -2142,34 +2142,12 @@ void SvxPropertyValuesToItemSet(
    }
}

// com::sun::star::text::XParagraphAppend (new import API)
uno::Reference< text::XTextRange > SAL_CALL SvxUnoTextBase::appendParagraph(
        const uno::Sequence< beans::PropertyValue >& rCharAndParaProps )
uno::Reference< text::XTextRange > SAL_CALL SvxUnoTextBase::finishParagraphInsert(
        const uno::Sequence< beans::PropertyValue >& /*rCharAndParaProps*/,
        const uno::Reference< text::XTextRange >& /*rTextRange*/ )
    throw (lang::IllegalArgumentException, beans::UnknownPropertyException, uno::RuntimeException)
{
    SolarMutexGuard aGuard;
    uno::Reference< text::XTextRange > xRet;
    SvxEditSource *pEditSource = GetEditSource();
    SvxTextForwarder *pTextForwarder = pEditSource ? pEditSource->GetTextForwarder() : 0;
    if (pTextForwarder)
    {
        sal_uInt16 nParaCount = pTextForwarder->GetParagraphCount();
        DBG_ASSERT( nParaCount > 0, "paragraph count is 0 or negative" );
        pTextForwarder->AppendParagraph();

        // set properties for new appended (now last) paragraph
        ESelection aSel( nParaCount, 0, nParaCount, 0 );
        SfxItemSet aItemSet( *pTextForwarder->GetEmptyItemSetPtr() );
        SvxPropertyValuesToItemSet( aItemSet, rCharAndParaProps,
                            ImplGetSvxUnoOutlinerTextCursorSfxPropertySet(),
                            pTextForwarder,
                            nParaCount );
        pTextForwarder->QuickSetAttribs( aItemSet, aSel );
        pEditSource->UpdateData();
        SvxUnoTextRange* pRange = new SvxUnoTextRange( *this );
        xRet = pRange;
        pRange->SetSelection( aSel );
    }
    return xRet;
}

@@ -2203,6 +2181,16 @@ uno::Reference< text::XTextRange > SAL_CALL SvxUnoTextBase::finishParagraph(
    return xRet;
}

uno::Reference< text::XTextRange > SAL_CALL SvxUnoTextBase::insertTextPortion(
        const ::rtl::OUString& /*rText*/,
        const uno::Sequence< beans::PropertyValue >& /*rCharAndParaProps*/,
        const uno::Reference< text::XTextRange>& /*rTextRange*/ )
    throw (lang::IllegalArgumentException, beans::UnknownPropertyException, uno::RuntimeException)
{
    uno::Reference< text::XTextRange > xRet;
    return xRet;
}

// com::sun::star::text::XTextPortionAppend (new import API)
uno::Reference< text::XTextRange > SAL_CALL SvxUnoTextBase::appendTextPortion(
        const ::rtl::OUString& rText,
diff --git a/offapi/com/sun/star/text/XParagraphAppend.idl b/offapi/com/sun/star/text/XParagraphAppend.idl
index 9c2ce13..343ca9e 100644
--- a/offapi/com/sun/star/text/XParagraphAppend.idl
+++ b/offapi/com/sun/star/text/XParagraphAppend.idl
@@ -35,19 +35,6 @@
 */
interface XParagraphAppend : com::sun::star::uno::XInterface
{
        /** appends a new and empty paragraph at the end of the text.

                <p>The properties are applied to the new paragraph.
        </p>

        @param
            CharacterAndParagraphProperties can contain all the properties defined by the service
                      <type scope="com::sun::star::text">Paragraph.

     */
         com::sun::star::text::XTextRange appendParagraph(  [in] com::sun::star::beans::PropertyValues CharacterAndParagraphProperties )
                        raises( com::sun::star::lang::IllegalArgumentException,
                                       com::sun::star::beans::UnknownPropertyException );
         /** appends a new and empty paragraph at the end of the text.

                <p>The properties are applied to the last paragraph before the new paragraph is inserted.
@@ -62,6 +49,26 @@ interface XParagraphAppend : com::sun::star::uno::XInterface
                        raises( com::sun::star::lang::IllegalArgumentException,
                                       com::sun::star::beans::UnknownPropertyException );

         /** inserts a new and empty paragraph to the text at a given position.

                <p>The properties are applied to the last paragraph before the new paragraph is inserted.
                </p>

        @param
            CharacterAndParagraphProperties can contain all the properties defined by the service
                      <type scope="com::sun::star::text">Paragraph.

        @param
            TextRange specifies the position of the insertion.

        @since LibreOffice 4.0

         */
         com::sun::star::text::XTextRange finishParagraphInsert(  [in] com::sun::star::beans::PropertyValues CharacterAndParagraphProperties,
                                                                  [in] com::sun::star::text::XTextRange TextRange )
                        raises( com::sun::star::lang::IllegalArgumentException,
                                       com::sun::star::beans::UnknownPropertyException );

};


diff --git a/offapi/com/sun/star/text/XTextContentAppend.idl b/offapi/com/sun/star/text/XTextContentAppend.idl
index 0e9c46d..afac7ab 100644
--- a/offapi/com/sun/star/text/XTextContentAppend.idl
+++ b/offapi/com/sun/star/text/XTextContentAppend.idl
@@ -55,6 +55,27 @@ interface XTextContentAppend : com::sun::star::uno::XInterface
                                raises( com::sun::star::lang::IllegalArgumentException,
                                       com::sun::star::beans::UnknownPropertyException );

        /** inserts a text content at the given position.

        @param TextContent
            contains the object to be inserted.
        @param CharacterAndParagraphProperties
            can contain all the properties defined by the service
                      <type scope="com::sun::star::text">Paragraph.
        @param TextRange
            insert position
        @return
            the anchor text range of the inserted text content.

        @since LibreOffice 4.0
     */
         com::sun::star::text::XTextRange insertTextContentWithProperties(
             [in] com::sun::star::text::XTextContent TextContent,
             [in] com::sun::star::beans::PropertyValues CharacterAndParagraphProperties,
             [in] com::sun::star::text::XTextRange TextRange )
                                raises( com::sun::star::lang::IllegalArgumentException,
                                       com::sun::star::beans::UnknownPropertyException );

};


diff --git a/offapi/com/sun/star/text/XTextPortionAppend.idl b/offapi/com/sun/star/text/XTextPortionAppend.idl
index a1aaf58..3c6c478e 100644
--- a/offapi/com/sun/star/text/XTextPortionAppend.idl
+++ b/offapi/com/sun/star/text/XTextPortionAppend.idl
@@ -53,6 +53,31 @@ interface XTextPortionAppend : com::sun::star::uno::XInterface
                        raises( com::sun::star::lang::IllegalArgumentException,
                                        com::sun::star::beans::UnknownPropertyException );

        /** inserts a new text portion to the paragraph at a given position.

                <p> The sequence can contain all the properties defined by the service <type scope="com::sun::star::text">TextPortion.
        </p>

        @param
            Text contains the text to be inserted.

        @param
            CharacterAndParagraphProperties can contain all the properties defined by the service
                      <type scope="com::sun::star::text">Paragraph.

        @param
            TextRange specifies the position of the insert.

        @since LibreOffice 4.0

     */
         com::sun::star::text::XTextRange  insertTextPortion(
                                [in] string Text,
                                [in] com::sun::star::beans::PropertyValues CharacterAndParagraphProperties,
                                [in] com::sun::star::text::XTextRange TextRange)
                        raises( com::sun::star::lang::IllegalArgumentException,
                                        com::sun::star::beans::UnknownPropertyException );

};


diff --git a/sw/inc/unotext.hxx b/sw/inc/unotext.hxx
index 0d5d47b..7c01aed 100644
--- a/sw/inc/unotext.hxx
+++ b/sw/inc/unotext.hxx
@@ -206,7 +206,7 @@ public:
    // XParagraphAppend
    virtual ::com::sun::star::uno::Reference<
                ::com::sun::star::text::XTextRange > SAL_CALL
        appendParagraph(
        finishParagraph(
            const ::com::sun::star::uno::Sequence<
                    ::com::sun::star::beans::PropertyValue >&
                rCharacterAndParagraphProperties)
@@ -214,10 +214,13 @@ public:
                ::com::sun::star::uno::RuntimeException);
    virtual ::com::sun::star::uno::Reference<
                ::com::sun::star::text::XTextRange > SAL_CALL
        finishParagraph(
        finishParagraphInsert(
            const ::com::sun::star::uno::Sequence<
                    ::com::sun::star::beans::PropertyValue >&
                rCharacterAndParagraphProperties)
                rCharacterAndParagraphProperties,
            const ::com::sun::star::uno::Reference<
                    ::com::sun::star::text::XTextRange >&
                xInsertPosition)
        throw (::com::sun::star::lang::IllegalArgumentException,
                ::com::sun::star::uno::RuntimeException);

@@ -232,6 +235,19 @@ public:
        throw (::com::sun::star::lang::IllegalArgumentException,
                ::com::sun::star::uno::RuntimeException);

    virtual ::com::sun::star::uno::Reference<
                ::com::sun::star::text::XTextRange > SAL_CALL
        insertTextPortion(
            const ::rtl::OUString& rText,
            const ::com::sun::star::uno::Sequence<
                    ::com::sun::star::beans::PropertyValue >&
                rCharacterAndParagraphProperties,
            const ::com::sun::star::uno::Reference<
                    ::com::sun::star::text::XTextRange >&
                rTextRange)
        throw (::com::sun::star::lang::IllegalArgumentException,
                ::com::sun::star::uno::RuntimeException);

    // XTextContentAppend
    virtual ::com::sun::star::uno::Reference<
                ::com::sun::star::text::XTextRange > SAL_CALL
@@ -243,6 +259,17 @@ public:
                rCharacterAndParagraphProperties)
        throw (::com::sun::star::lang::IllegalArgumentException,
                ::com::sun::star::uno::RuntimeException);
    virtual ::com::sun::star::uno::Reference<
                ::com::sun::star::text::XTextRange > SAL_CALL
        insertTextContentWithProperties(
            const ::com::sun::star::uno::Reference<
                ::com::sun::star::text::XTextContent >& xTextContent,
            const ::com::sun::star::uno::Sequence<
                    ::com::sun::star::beans::PropertyValue >&
                rCharacterAndParagraphProperties,
            const ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextRange >& xInsertPosition)
        throw (::com::sun::star::lang::IllegalArgumentException,
                ::com::sun::star::uno::RuntimeException);

    // XTextConvert
    virtual ::com::sun::star::uno::Reference<
diff --git a/sw/inc/unotextrange.hxx b/sw/inc/unotextrange.hxx
index 46576ef..cfd3737 100644
--- a/sw/inc/unotextrange.hxx
+++ b/sw/inc/unotextrange.hxx
@@ -43,7 +43,7 @@ class SwPaM;
class SwUnoCrsr;
class SwFrmFmt;

class SwUnoInternalPaM
class SW_DLLPUBLIC SwUnoInternalPaM
    : public SwPaM
{

@@ -62,7 +62,7 @@ namespace sw {

    void DeepCopyPaM(SwPaM const & rSource, SwPaM & rTarget);

    bool XTextRangeToSwPaM(SwUnoInternalPaM& rToFill,
    SW_DLLPUBLIC bool XTextRangeToSwPaM(SwUnoInternalPaM& rToFill,
            const ::com::sun::star::uno::Reference<
                ::com::sun::star::text::XTextRange > & xTextRange);

diff --git a/sw/source/core/unocore/unotext.cxx b/sw/source/core/unocore/unotext.cxx
index 68e67c2..a575719 100644
--- a/sw/source/core/unocore/unotext.cxx
+++ b/sw/source/core/unocore/unotext.cxx
@@ -108,7 +108,8 @@ public:
        finishOrAppendParagraph(
            const bool bFinish,
            const uno::Sequence< beans::PropertyValue >&
                rCharacterAndParagraphProperties)
                rCharacterAndParagraphProperties,
            const uno::Reference< text::XTextRange >& xInsertPosition)
        throw (lang::IllegalArgumentException, uno::RuntimeException);

    sal_Int16 ComparePositions(
@@ -1251,29 +1252,31 @@ throw (uno::RuntimeException)
}

uno::Reference< text::XTextRange > SAL_CALL
SwXText::appendParagraph(
        const uno::Sequence< beans::PropertyValue > & rProperties)
throw (lang::IllegalArgumentException, uno::RuntimeException)
{
    SolarMutexGuard g;

    return m_pImpl->finishOrAppendParagraph(false, rProperties);
}

uno::Reference< text::XTextRange > SAL_CALL
SwXText::finishParagraph(
        const uno::Sequence< beans::PropertyValue > & rProperties)
throw (lang::IllegalArgumentException, uno::RuntimeException)
{
    SolarMutexGuard g;

    return m_pImpl->finishOrAppendParagraph(true, rProperties);
    return m_pImpl->finishOrAppendParagraph(true, rProperties, uno::Reference< text::XTextRange >());
}

uno::Reference< text::XTextRange > SAL_CALL
SwXText::finishParagraphInsert(
        const uno::Sequence< beans::PropertyValue > & rProperties,
        const uno::Reference< text::XTextRange >& xInsertPosition)
throw (lang::IllegalArgumentException, uno::RuntimeException)
{
    SolarMutexGuard g;

    return m_pImpl->finishOrAppendParagraph(true, rProperties, xInsertPosition);
}

uno::Reference< text::XTextRange >
SwXText::Impl::finishOrAppendParagraph(
        const bool bFinish,
        const uno::Sequence< beans::PropertyValue > & rProperties)
        const uno::Sequence< beans::PropertyValue > & rProperties,
        const uno::Reference< text::XTextRange >& xInsertPosition)
throw (lang::IllegalArgumentException, uno::RuntimeException)
{
    if (!m_bIsValid)
@@ -1298,6 +1301,15 @@ throw (lang::IllegalArgumentException, uno::RuntimeException)
    SwPosition aInsertPosition(
            SwNodeIndex( *pStartNode->EndOfSectionNode(), -1 ) );
    SwPaM aPam(aInsertPosition);
    // If we got a position reference, then the insert point is not the end of
    // the document.
    if (xInsertPosition.is())
    {
        SwUnoInternalPaM aStartPam(*m_rThis.GetDoc());
        ::sw::XTextRangeToSwPaM(aStartPam, xInsertPosition);
        aPam = aStartPam;
        aPam.SetMark();
    }
    m_pDoc->AppendTxtNode( *aPam.GetPoint() );
    // remove attributes from the previous paragraph
    m_pDoc->ResetAttrs(aPam);
@@ -1371,15 +1383,12 @@ throw (lang::IllegalArgumentException, uno::RuntimeException)
    return xRet;
}

/*-------------------------------------------------------------------------
    Append text portions at the end of the last paragraph of the text
    interface. Support of import filters.
  -----------------------------------------------------------------------*/
uno::Reference< text::XTextRange > SAL_CALL
SwXText::appendTextPortion(
SwXText::insertTextPortion(
        const ::rtl::OUString& rText,
        const uno::Sequence< beans::PropertyValue > &
            rCharacterAndParagraphProperties)
            rCharacterAndParagraphProperties,
        const uno::Reference<text::XTextRange>& xInsertPosition)
throw (lang::IllegalArgumentException, uno::RuntimeException)
{
    SolarMutexGuard aGuard;
@@ -1390,7 +1399,7 @@ throw (lang::IllegalArgumentException, uno::RuntimeException)
    }
    uno::Reference< text::XTextRange > xRet;
    const uno::Reference< text::XTextCursor > xTextCursor = CreateCursor();
    xTextCursor->gotoEnd(sal_False);
    xTextCursor->gotoRange(xInsertPosition, sal_False);

    const uno::Reference< lang::XUnoTunnel > xRangeTunnel(
            xTextCursor, uno::UNO_QUERY_THROW );
@@ -1405,7 +1414,6 @@ throw (lang::IllegalArgumentException, uno::RuntimeException)
//        SwPaM aPam(*pStartNode->EndOfSectionNode());
    //aPam.Move( fnMoveBackward, fnGoNode );
    SwUnoCrsr *const pCursor = pTextCursor->GetCursor();
    pCursor->MovePara( fnParaCurr, fnParaEnd );
    m_pImpl->m_pDoc->DontExpandFmt( *pCursor->Start() );

    if (!rText.isEmpty())
@@ -1477,14 +1485,32 @@ throw (lang::IllegalArgumentException, uno::RuntimeException)
}

/*-------------------------------------------------------------------------
    enable appending text contents like graphic objects, shapes and so on
    Append text portions at the end of the last paragraph of the text
    interface. Support of import filters.
  -----------------------------------------------------------------------*/
uno::Reference< text::XTextRange > SAL_CALL
SwXText::appendTextPortion(
        const ::rtl::OUString& rText,
        const uno::Sequence< beans::PropertyValue > &
            rCharacterAndParagraphProperties)
throw (lang::IllegalArgumentException, uno::RuntimeException)
{
    // Right now this doesn't need a guard, as it's just calling the insert
    // version, that has it already.
    uno::Reference<text::XTextRange> xInsertPosition = getEnd();
    return insertTextPortion(rText, rCharacterAndParagraphProperties, xInsertPosition);
}

/*-------------------------------------------------------------------------
    enable inserting/appending text contents like graphic objects, shapes and so on
    to support import filters
  -----------------------------------------------------------------------*/
uno::Reference< text::XTextRange > SAL_CALL
SwXText::appendTextContent(
SwXText::insertTextContentWithProperties(
    const uno::Reference< text::XTextContent >& xTextContent,
    const uno::Sequence< beans::PropertyValue >&
        rCharacterAndParagraphProperties)
        rCharacterAndParagraphProperties,
    const uno::Reference< text::XTextRange >& xInsertPosition)
throw (lang::IllegalArgumentException, uno::RuntimeException)
{
    SolarMutexGuard aGuard;
@@ -1493,25 +1519,11 @@ throw (lang::IllegalArgumentException, uno::RuntimeException)
    {
        throw  uno::RuntimeException();
    }
    SwStartNode const*const pStartNode = GetStartNode();
    if(!pStartNode)
    {
        throw  uno::RuntimeException();
    }

    uno::Reference< text::XTextRange > xRet;
    m_pImpl->m_pDoc->GetIDocumentUndoRedo().StartUndo(UNDO_INSERT, NULL);
    // find end node, go backward - don't skip tables because the
    // new paragraph has to be the last node
    SwPaM aPam(*pStartNode->EndOfSectionNode());
    aPam.Move( fnMoveBackward, fnGoNode );
    // set cursor to the end of the last text node
    SwCursor aCursor( *aPam.Start(), 0, false );
    xRet = new SwXTextRange(aCursor, this);
    aCursor.MovePara( fnParaCurr, fnParaEnd );
    m_pImpl->m_pDoc->DontExpandFmt( *aCursor.Start() );

    // now attach the text content here
    insertTextContent( xRet, xTextContent, false );
    insertTextContent( xInsertPosition, xTextContent, false );
    // now apply the properties to the anchor
    if (rCharacterAndParagraphProperties.getLength())
    {
@@ -1536,7 +1548,20 @@ throw (lang::IllegalArgumentException, uno::RuntimeException)
        }
    }
    m_pImpl->m_pDoc->GetIDocumentUndoRedo().EndUndo(UNDO_INSERT, NULL);
    return xRet;
    return xInsertPosition;
}

uno::Reference< text::XTextRange > SAL_CALL
SwXText::appendTextContent(
    const uno::Reference< text::XTextContent >& xTextContent,
    const uno::Sequence< beans::PropertyValue >&
        rCharacterAndParagraphProperties)
throw (lang::IllegalArgumentException, uno::RuntimeException)
{
    // Right now this doesn't need a guard, as it's just calling the insert
    // version, that has it already.
    uno::Reference<text::XTextRange> xInsertPosition = getEnd();
    return insertTextContentWithProperties(xTextContent, rCharacterAndParagraphProperties, xInsertPosition);
}

// move previously appended paragraphs into a text frames
diff --git a/sw/source/filter/rtf/swparrtf.cxx b/sw/source/filter/rtf/swparrtf.cxx
index d4d59c0..e06c02b 100644
--- a/sw/source/filter/rtf/swparrtf.cxx
+++ b/sw/source/filter/rtf/swparrtf.cxx
@@ -89,6 +89,7 @@

#include <docsh.hxx>
#include <fmtlsplt.hxx> // SwLayoutSplit
#include <unotextrange.hxx>
#include <editeng/keepitem.hxx>
#include <svx/svdopath.hxx>
#include <svx/svdorect.hxx>
@@ -117,6 +118,7 @@
#include <com/sun/star/document/XFilter.hpp>
#include <com/sun/star/document/XImporter.hpp>
#include <com/sun/star/document/XExporter.hpp>
#include <com/sun/star/text/XTextRange.hpp>


using namespace ::com::sun::star;
@@ -136,11 +138,31 @@ class SwRTFReader : public Reader
    virtual sal_uLong Read( SwDoc &, const String& rBaseURL, SwPaM &,const String &);
};

sal_uLong SwRTFReader::Read( SwDoc &rDoc, const String& /*rBaseURL*/, SwPaM& /*rPam*/, const String &)
sal_uLong SwRTFReader::Read( SwDoc &rDoc, const String& /*rBaseURL*/, SwPaM& rPam, const String &)
{
    if (!pStrm)
        return ERR_SWG_READ_ERROR;

    // We want to work in an empty paragraph.
    // Step 1: XTextRange will be updated when content is inserted, so we know
    // the end position.
    const uno::Reference<text::XTextRange> xInsertPosition =
        SwXTextRange::CreateXTextRange(rDoc, *rPam.GetPoint(), 0);
    SwNodeIndex *pSttNdIdx = new SwNodeIndex(rDoc.GetNodes());
    const SwPosition* pPos = rPam.GetPoint();

    // Step 2: Split once and remember the node that has been splitted.
    rDoc.SplitNode( *pPos, false );
    *pSttNdIdx = pPos->nNode.GetIndex()-1;

    // Step 3: Split again.
    rDoc.SplitNode( *pPos, false );

    // Step 4: Insert all content into the new node
    rPam.Move( fnMoveBackward );
    rDoc.SetTxtFmtColl
        ( rPam, rDoc.GetTxtCollFromPool(RES_POOLCOLL_STANDARD, false ) );

    SwDocShell *pDocShell(rDoc.GetDocShell());
    uno::Reference<lang::XMultiServiceFactory> xMultiServiceFactory(comphelper::getProcessServiceFactory());
    uno::Reference<uno::XInterface> xInterface(xMultiServiceFactory->createInstance(
@@ -150,15 +172,53 @@ sal_uLong SwRTFReader::Read( SwDoc &rDoc, const String& /*rBaseURL*/, SwPaM& /*r
    uno::Reference<lang::XComponent> xDstDoc(pDocShell->GetModel(), uno::UNO_QUERY_THROW);
    xImporter->setTargetDocument(xDstDoc);

    const uno::Reference<text::XTextRange> xInsertTextRange =
        SwXTextRange::CreateXTextRange(rDoc, *rPam.GetPoint(), 0);

    uno::Reference<document::XFilter> xFilter(xInterface, uno::UNO_QUERY_THROW);
    uno::Sequence<beans::PropertyValue> aDescriptor(2);
    uno::Sequence<beans::PropertyValue> aDescriptor(3);
    aDescriptor[0].Name = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("InputStream"));
    uno::Reference<io::XStream> xStream(new utl::OStreamWrapper(*pStrm));
    aDescriptor[0].Value <<= xStream;
    aDescriptor[1].Name = "IsNewDoc";
    aDescriptor[1].Value <<= sal_False;
    aDescriptor[2].Name = "TextInsertModeRange";
    aDescriptor[2].Value <<= xInsertTextRange;
    xFilter->filter(aDescriptor);

    // Clean up the fake paragraphs.
    SwUnoInternalPaM aPam(rDoc);
    ::sw::XTextRangeToSwPaM(aPam, xInsertPosition);
    if (pSttNdIdx->GetIndex())
    {
        // If we are in insert mode, join the splitted node that is in front
        // of the new content with the first new node. Or in other words:
        // Revert the first split node.
        SwTxtNode* pTxtNode = pSttNdIdx->GetNode().GetTxtNode();
        SwNodeIndex aNxtIdx( *pSttNdIdx );
        if( pTxtNode && pTxtNode->CanJoinNext( &aNxtIdx ) &&
                pSttNdIdx->GetIndex() + 1 == aNxtIdx.GetIndex() )
        {
            // If the PaM points to the first new node, move the PaM to the
            // end of the previous node.
            if( aPam.GetPoint()->nNode == aNxtIdx )
            {
                aPam.GetPoint()->nNode = *pSttNdIdx;
                aPam.GetPoint()->nContent.Assign( pTxtNode,
                        pTxtNode->GetTxt().Len() );
            }
            // If the first new node isn't empty, convert  the node's text
            // attributes into hints. Otherwise, set the new node's
            // paragraph style at the previous (empty) node.
            SwTxtNode* pDelNd = aNxtIdx.GetNode().GetTxtNode();
            if( pTxtNode->GetTxt().Len() )
                pDelNd->FmtToTxtAttr( pTxtNode );
            else
                pTxtNode->ChgFmtColl( pDelNd->GetTxtColl() );
            pTxtNode->JoinNext();
        }
    }

    return 0;
}

diff --git a/writerfilter/inc/dmapper/DomainMapper.hxx b/writerfilter/inc/dmapper/DomainMapper.hxx
index 87e28d2..26654d72 100644
--- a/writerfilter/inc/dmapper/DomainMapper.hxx
+++ b/writerfilter/inc/dmapper/DomainMapper.hxx
@@ -82,6 +82,7 @@ public:
                                ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent > xModel,
                                bool bRepairStorage,
                                SourceDocumentType eDocumentType,
                                ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextRange > xInsertTextRange,
                                bool bIsNewDoc = true);
    virtual ~DomainMapper();

diff --git a/writerfilter/source/dmapper/DomainMapper.cxx b/writerfilter/source/dmapper/DomainMapper.cxx
index a768dc3..5ae8e13 100644
--- a/writerfilter/source/dmapper/DomainMapper.cxx
+++ b/writerfilter/source/dmapper/DomainMapper.cxx
@@ -87,11 +87,12 @@ DomainMapper::DomainMapper( const uno::Reference< uno::XComponentContext >& xCon
                            uno::Reference< lang::XComponent > xModel,
                            bool bRepairStorage,
                            SourceDocumentType eDocumentType,
                            uno::Reference< text::XTextRange > xInsertTextRange,
                            bool bIsNewDoc ) :
LoggedProperties(dmapper_logger, "DomainMapper"),
LoggedTable(dmapper_logger, "DomainMapper"),
LoggedStream(dmapper_logger, "DomainMapper"),
    m_pImpl( new DomainMapper_Impl( *this, xContext, xModel, eDocumentType, bIsNewDoc )),
    m_pImpl( new DomainMapper_Impl( *this, xContext, xModel, eDocumentType, xInsertTextRange, bIsNewDoc )),
    mnBackgroundColor(0), mbIsHighlightSet(false)
{
    // #i24363# tab stops relative to indent
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
index fbf9acb..a204c69 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -156,6 +156,7 @@ DomainMapper_Impl::DomainMapper_Impl(
            uno::Reference < uno::XComponentContext >  xContext,
            uno::Reference< lang::XComponent >  xModel,
            SourceDocumentType eDocumentType,
            uno::Reference< text::XTextRange > xInsertTextRange,
            bool bIsNewDoc) :
        m_eDocumentType( eDocumentType ),
        m_rDMapper( rDMapper ),
@@ -184,12 +185,14 @@ DomainMapper_Impl::DomainMapper_Impl(
        m_bParaSectpr( false ),
        m_bUsingEnhancedFields( false ),
        m_bSdt(false),
        m_xInsertTextRange(xInsertTextRange),
        m_bIsNewDoc(bIsNewDoc)
{
    appendTableManager( );
    GetBodyText();
    uno::Reference< text::XTextAppend > xBodyTextAppend = uno::Reference< text::XTextAppend >( m_xBodyText, uno::UNO_QUERY );
    m_aTextAppendStack.push(xBodyTextAppend);
    m_aTextAppendStack.push(TextAppendContext(xBodyTextAppend,
                m_bIsNewDoc ? uno::Reference<text::XTextCursor>() : m_xBodyText->createTextCursorByRange(m_xInsertTextRange)));

    //todo: does it make sense to set the body text as static text interface?
    uno::Reference< text::XTextAppendAndConvert > xBodyTextAppendAndConvert( m_xBodyText, uno::UNO_QUERY );
@@ -268,8 +271,14 @@ void DomainMapper_Impl::RemoveLastParagraph( )
        return;
    try
    {
        uno::Reference< text::XTextCursor > xCursor = xTextAppend->createTextCursor();
        xCursor->gotoEnd(false);
        uno::Reference< text::XTextCursor > xCursor;
        if (m_bIsNewDoc)
        {
            xCursor = xTextAppend->createTextCursor();
            xCursor->gotoEnd(false);
        }
        else
            xCursor.set(m_aTextAppendStack.top().xCursor, uno::UNO_QUERY);
        xCursor->goLeft( 1, true );
        xCursor->setString(OUString());
    }
@@ -1043,13 +1052,22 @@ void DomainMapper_Impl::finishParagraph( PropertyMapPtr pPropertyMap )
                    aProperties[nLength].Value <<= aDrop;
                    aProperties[nLength].Name = rPropNameSupplier.GetName(PROP_DROP_CAP_FORMAT);
                }
                uno::Reference< text::XTextRange > xTextRange =
                    xTextAppend->finishParagraph( aProperties );
                uno::Reference< text::XTextRange > xTextRange;
                if (rAppendContext.xInsertPosition.is())
                {
                    xTextRange = xTextAppend->finishParagraphInsert( aProperties, rAppendContext.xInsertPosition );
                    rAppendContext.xCursor->gotoNextParagraph(false);
                }
                else
                    xTextRange = xTextAppend->finishParagraph( aProperties );
                getTableManager( ).handle(xTextRange);

                // Get the end of paragraph character inserted
                uno::Reference< text::XTextCursor > xCur = xTextRange->getText( )->createTextCursor( );
                xCur->gotoEnd( false );
                if (rAppendContext.xInsertPosition.is())
                    xCur->gotoRange( rAppendContext.xInsertPosition, false );
                else
                    xCur->gotoEnd( false );
                xCur->goLeft( 1 , true );
                uno::Reference< text::XTextRange > xParaEnd( xCur, uno::UNO_QUERY );
                CheckParaRedline( xParaEnd );
@@ -1112,9 +1130,14 @@ void DomainMapper_Impl::appendTextPortion( const OUString& rString, PropertyMapP
    {
        try
        {
            uno::Reference< text::XTextRange > xTextRange =
                xTextAppend->appendTextPortion
                (rString, pPropertyMap->GetPropertyValues());
            uno::Reference< text::XTextRange > xTextRange;
            if (m_aTextAppendStack.top().xInsertPosition.is())
            {
                xTextRange = xTextAppend->insertTextPortion(rString, pPropertyMap->GetPropertyValues(), m_aTextAppendStack.top().xInsertPosition);
                m_aTextAppendStack.top().xCursor->gotoRange(xTextRange->getEnd(), false);
            }
            else
                xTextRange = xTextAppend->appendTextPortion(rString, pPropertyMap->GetPropertyValues());
            CheckRedline( xTextRange );
            m_bParaChanged = true;

@@ -1143,7 +1166,10 @@ void DomainMapper_Impl::appendTextContent(
    {
        try
        {
            xTextAppendAndConvert->appendTextContent( xContent, xPropertyValues );
            if (m_aTextAppendStack.top().xInsertPosition.is())
                xTextAppendAndConvert->insertTextContentWithProperties( xContent, xPropertyValues, m_aTextAppendStack.top().xInsertPosition );
            else
                xTextAppendAndConvert->appendTextContent( xContent, xPropertyValues );
        }
        catch(const lang::IllegalArgumentException&)
        {
@@ -1249,7 +1275,10 @@ uno::Reference< beans::XPropertySet > DomainMapper_Impl::appendTextSectionAfter(
                xTextAppend->createTextCursorByRange( xBefore ), uno::UNO_QUERY_THROW);
            //the cursor has been moved to the end of the paragraph because of the appendTextPortion() calls
            xCursor->gotoStartOfParagraph( false );
            xCursor->gotoEnd( true );
            if (m_aTextAppendStack.top().xInsertPosition.is())
                xCursor->gotoRange( m_aTextAppendStack.top().xInsertPosition, true );
            else
                xCursor->gotoEnd( true );
            //the paragraph after this new section is already inserted
            xCursor->goLeft(1, true);
            static const OUString sSectionService("com.sun.star.text.TextSection");
@@ -1299,7 +1328,8 @@ void DomainMapper_Impl::PushPageHeader(SectionPropertyMap::PageType eType)
            //set the interface
            uno::Reference< text::XText > xHeaderText;
            xPageStyle->getPropertyValue(rPropNameSupplier.GetName( bLeft ? PROP_HEADER_TEXT_LEFT : PROP_HEADER_TEXT) ) >>= xHeaderText;
            m_aTextAppendStack.push( uno::Reference< text::XTextAppend >( xHeaderText, uno::UNO_QUERY_THROW));
            m_aTextAppendStack.push( TextAppendContext(uno::Reference< text::XTextAppend >( xHeaderText, uno::UNO_QUERY_THROW),
                        m_bIsNewDoc ? uno::Reference<text::XTextCursor>() : m_xBodyText->createTextCursorByRange(xHeaderText->getStart())));
        }
        catch( const uno::Exception& )
        {
@@ -1339,7 +1369,8 @@ void DomainMapper_Impl::PushPageFooter(SectionPropertyMap::PageType eType)
            //set the interface
            uno::Reference< text::XText > xFooterText;
            xPageStyle->getPropertyValue(rPropNameSupplier.GetName( bLeft ? PROP_FOOTER_TEXT_LEFT : PROP_FOOTER_TEXT) ) >>= xFooterText;
            m_aTextAppendStack.push(uno::Reference< text::XTextAppend >( xFooterText, uno::UNO_QUERY_THROW ));
            m_aTextAppendStack.push(TextAppendContext(uno::Reference< text::XTextAppend >( xFooterText, uno::UNO_QUERY_THROW ),
                        m_bIsNewDoc ? uno::Reference<text::XTextCursor>() : m_xBodyText->createTextCursorByRange(xFooterText->getStart())));
        }
        catch( const uno::Exception& )
        {
@@ -1394,7 +1425,8 @@ void DomainMapper_Impl::PushFootOrEndnote( bool bIsFootnote )
            aFontProperties = aFontProps->GetPropertyValues();
        }
        appendTextContent( uno::Reference< text::XTextContent >( xFootnoteText, uno::UNO_QUERY_THROW ), aFontProperties );
        m_aTextAppendStack.push(uno::Reference< text::XTextAppend >( xFootnoteText, uno::UNO_QUERY_THROW ));
        m_aTextAppendStack.push(TextAppendContext(uno::Reference< text::XTextAppend >( xFootnoteText, uno::UNO_QUERY_THROW ),
                    m_bIsNewDoc ? uno::Reference<text::XTextCursor>() : m_xBodyText->createTextCursorByRange(xFootnoteText->getStart())));

        // Redlines for the footnote anchor
        CheckRedline( xFootnote->getAnchor( ) );
@@ -1493,7 +1525,8 @@ void DomainMapper_Impl::PushAnnotation()
            uno::UNO_QUERY_THROW );
        uno::Reference< text::XText > xAnnotationText;
        m_xAnnotationField->getPropertyValue("TextRange") >>= xAnnotationText;
        m_aTextAppendStack.push(uno::Reference< text::XTextAppend >( xAnnotationText, uno::UNO_QUERY_THROW ));
        m_aTextAppendStack.push(TextAppendContext(uno::Reference< text::XTextAppend >( xAnnotationText, uno::UNO_QUERY_THROW ),
                    m_bIsNewDoc ? uno::Reference<text::XTextCursor>() : m_xBodyText->createTextCursorByRange(xAnnotationText->getStart())));
    }
    catch( const uno::Exception& )
    {
@@ -1548,8 +1581,10 @@ void DomainMapper_Impl::PushShapeContext( const uno::Reference< drawing::XShape 
    uno::Reference<text::XTextAppend> xTextAppend = m_aTextAppendStack.top().xTextAppend;
    try
    {
        uno::Reference< text::XTextRange > xShapeText( xShape, uno::UNO_QUERY_THROW);
        // Add the shape to the text append stack
        m_aTextAppendStack.push( uno::Reference< text::XTextAppend >( xShape, uno::UNO_QUERY_THROW ) );
        m_aTextAppendStack.push( TextAppendContext(uno::Reference< text::XTextAppend >( xShape, uno::UNO_QUERY_THROW ),
                    m_bIsNewDoc ? uno::Reference<text::XTextCursor>() : m_xBodyText->createTextCursorByRange(xShapeText->getStart() )));

        // Add the shape to the anchored objects stack
        uno::Reference< text::XTextContent > xTxtContent( xShape, uno::UNO_QUERY_THROW );
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.hxx b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
index 8714542..5857455 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.hxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
@@ -19,6 +19,7 @@
#ifndef INCLUDED_DMAPPER_DOMAINMAPPER_IMPL_HXX
#define INCLUDED_DMAPPER_DOMAINMAPPER_IMPL_HXX

#include <com/sun/star/text/XParagraphCursor.hpp>
#include <com/sun/star/text/XTextDocument.hpp>
#include <com/sun/star/text/XTextCursor.hpp>
#include <com/sun/star/text/XTextAppend.hpp>
@@ -167,10 +168,17 @@ public:
struct TextAppendContext
{
    ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextAppend >       xTextAppend;
    ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextRange >        xInsertPosition;
    ::com::sun::star::uno::Reference< ::com::sun::star::text::XParagraphCursor >  xCursor;
    ParagraphPropertiesPtr                                                        pLastParagraphProperties;

    TextAppendContext( const ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextAppend >& xAppend ) :
        xTextAppend( xAppend ){}
    TextAppendContext( const ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextAppend >& xAppend,
           const ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextCursor >& xCur ) :
        xTextAppend( xAppend )
    {
        xCursor.set(xCur, uno::UNO_QUERY);
        xInsertPosition.set(xCursor, uno::UNO_QUERY);
    }
};

struct AnchoredContext
@@ -373,6 +381,9 @@ private:

    std::map< sal_Int32, com::sun::star::uno::Any > deferredCharacterProperties;

public:
    ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextRange > m_xInsertTextRange;
private:
    bool m_bIsNewDoc;

public:
@@ -381,6 +392,7 @@ public:
            uno::Reference < uno::XComponentContext >  xContext,
            uno::Reference< lang::XComponent >  xModel,
            SourceDocumentType eDocumentType,
            uno::Reference< text::XTextRange > xInsertTextRange,
            bool bIsNewDoc );
    virtual ~DomainMapper_Impl();

diff --git a/writerfilter/source/filter/ImportFilter.cxx b/writerfilter/source/filter/ImportFilter.cxx
index e482d5b..d58e877 100644
--- a/writerfilter/source/filter/ImportFilter.cxx
+++ b/writerfilter/source/filter/ImportFilter.cxx
@@ -99,7 +99,7 @@ sal_Bool WriterFilter::filter( const uno::Sequence< beans::PropertyValue >& aDes
         m_sFilterName == "writer_OOXML" || m_sFilterName == "writer_OOXML_Text_Template" ) ?
            writerfilter::dmapper::DOCUMENT_OOXML : writerfilter::dmapper::DOCUMENT_DOC;

    writerfilter::Stream::Pointer_t pStream(new writerfilter::dmapper::DomainMapper(m_xContext, xInputStream, m_xDstDoc, bRepairStorage, eType));
    writerfilter::Stream::Pointer_t pStream(new writerfilter::dmapper::DomainMapper(m_xContext, xInputStream, m_xDstDoc, bRepairStorage, eType, uno::Reference<text::XTextRange>()));
    //create the tokenizer and domain mapper
    if( eType == writerfilter::dmapper::DOCUMENT_OOXML )
    {
diff --git a/writerfilter/source/filter/RtfFilter.cxx b/writerfilter/source/filter/RtfFilter.cxx
index 27373a4..ac84d29 100644
--- a/writerfilter/source/filter/RtfFilter.cxx
+++ b/writerfilter/source/filter/RtfFilter.cxx
@@ -29,6 +29,7 @@
#include <com/sun/star/task/XStatusIndicator.hpp>
#include <com/sun/star/io/WrongFormatException.hpp>
#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
#include <com/sun/star/text/XTextRange.hpp>
#ifdef DBG_COPYPASTE
#include <unotools/localfilehelper.hxx>
#include <tools/stream.hxx>
@@ -75,6 +76,7 @@ sal_Bool RtfFilter::filter( const uno::Sequence< beans::PropertyValue >& aDescri
        MediaDescriptor aMediaDesc( aDescriptor );
        bool bRepairStorage = aMediaDesc.getUnpackedValueOrDefault( "RepairPackage", false );
        bool bIsNewDoc = aMediaDesc.getUnpackedValueOrDefault( "IsNewDoc", true );
        uno::Reference<text::XTextRange> xInsertTextRange = aMediaDesc.getUnpackedValueOrDefault( "TextInsertModeRange", uno::Reference<text::XTextRange>());
#ifdef DEBUG_IMPORT
        OUString sURL = aMediaDesc.getUnpackedValueOrDefault( MediaDescriptor::PROP_URL(), OUString() );
        ::std::string sURLc = OUStringToOString(sURL, RTL_TEXTENCODING_ASCII_US).getStr();
@@ -119,7 +121,7 @@ sal_Bool RtfFilter::filter( const uno::Sequence< beans::PropertyValue >& aDescri
                uno::Reference<task::XStatusIndicator>());

        writerfilter::Stream::Pointer_t pStream(
                new writerfilter::dmapper::DomainMapper(m_xContext, xInputStream, m_xDstDoc, bRepairStorage, writerfilter::dmapper::DOCUMENT_RTF, bIsNewDoc));
                new writerfilter::dmapper::DomainMapper(m_xContext, xInputStream, m_xDstDoc, bRepairStorage, writerfilter::dmapper::DOCUMENT_RTF, xInsertTextRange, bIsNewDoc));
        writerfilter::rtftok::RTFDocument::Pointer_t const pDocument(
                writerfilter::rtftok::RTFDocumentFactory::createDocument(m_xContext, xInputStream, m_xDstDoc, xFrame, xStatusIndicator));
        pDocument->resolve(*pStream);