From 232ad2f2588beff50cb5c1f3b689c581ba317583 Mon Sep 17 00:00:00 2001 From: Miklos Vajna Date: Wed, 28 Nov 2012 11:59:00 +0100 Subject: 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 --- sw/inc/unotext.hxx | 33 +++++++++++-- sw/inc/unotextrange.hxx | 4 +- sw/source/core/unocore/unotext.cxx | 95 ++++++++++++++++++++++++-------------- sw/source/filter/rtf/swparrtf.cxx | 64 ++++++++++++++++++++++++- 4 files changed, 154 insertions(+), 42 deletions(-) (limited to 'sw') diff --git a/sw/inc/unotext.hxx b/sw/inc/unotext.hxx index 0d5d47bcd552..7c01aed506fa 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 46576ef47bf2..cfd373766c38 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 68e67c2bd81a..a5757192fe40 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( +SwXText::finishParagraph( const uno::Sequence< beans::PropertyValue > & rProperties) throw (lang::IllegalArgumentException, uno::RuntimeException) { SolarMutexGuard g; - return m_pImpl->finishOrAppendParagraph(false, rProperties); + return m_pImpl->finishOrAppendParagraph(true, rProperties, uno::Reference< text::XTextRange >()); } uno::Reference< text::XTextRange > SAL_CALL -SwXText::finishParagraph( - const uno::Sequence< beans::PropertyValue > & rProperties) +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); + 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& 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 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 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 d4d59c0b62b2..e06c02ba6208 100644 --- a/sw/source/filter/rtf/swparrtf.cxx +++ b/sw/source/filter/rtf/swparrtf.cxx @@ -89,6 +89,7 @@ #include #include // SwLayoutSplit +#include #include #include #include @@ -117,6 +118,7 @@ #include #include #include +#include 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 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 xMultiServiceFactory(comphelper::getProcessServiceFactory()); uno::Reference xInterface(xMultiServiceFactory->createInstance( @@ -150,15 +172,53 @@ sal_uLong SwRTFReader::Read( SwDoc &rDoc, const String& /*rBaseURL*/, SwPaM& /*r uno::Reference xDstDoc(pDocShell->GetModel(), uno::UNO_QUERY_THROW); xImporter->setTargetDocument(xDstDoc); + const uno::Reference xInsertTextRange = + SwXTextRange::CreateXTextRange(rDoc, *rPam.GetPoint(), 0); + uno::Reference xFilter(xInterface, uno::UNO_QUERY_THROW); - uno::Sequence aDescriptor(2); + uno::Sequence aDescriptor(3); aDescriptor[0].Name = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("InputStream")); uno::Reference 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; } -- cgit v1.2.3