diff options
-rw-r--r-- | writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx | 45 | ||||
-rw-r--r-- | writerfilter/qa/cppunittests/dmapper/data/redlined-shape-sdt.docx | bin | 0 -> 13837 bytes | |||
-rw-r--r-- | writerfilter/source/dmapper/DomainMapper_Impl.cxx | 75 | ||||
-rw-r--r-- | writerfilter/source/dmapper/DomainMapper_Impl.hxx | 1 |
4 files changed, 88 insertions, 33 deletions
diff --git a/writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx b/writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx index d0693746f24b..16aa5cbfb2df 100644 --- a/writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx +++ b/writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx @@ -366,6 +366,51 @@ CPPUNIT_TEST_FIXTURE(Test, testFloattableSectend) // i.e. the first table was lost. CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(2), xTables->getCount()); } + +CPPUNIT_TEST_FIXTURE(Test, testRedlinedShapeThenSdt) +{ + // Given a file with a second paragraph where text is followed by a redline, then an SDT: + // When importing that document: + loadFromFile(u"redlined-shape-sdt.docx"); + + // Then make sure the content control doesn't start at para start: + uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY); + uno::Reference<container::XEnumerationAccess> xParaEnumAccess(xTextDocument->getText(), + uno::UNO_QUERY); + uno::Reference<container::XEnumeration> xParaEnum = xParaEnumAccess->createEnumeration(); + xParaEnum->nextElement(); + uno::Reference<container::XEnumerationAccess> xPortionEnumAccess(xParaEnum->nextElement(), + uno::UNO_QUERY); + uno::Reference<container::XEnumeration> xPortionEnum = xPortionEnumAccess->createEnumeration(); + + uno::Reference<beans::XPropertySet> xPortion(xPortionEnum->nextElement(), uno::UNO_QUERY); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: Text + // - Actual : ContentControl + // i.e. the content control started at para start. + CPPUNIT_ASSERT_EQUAL(u"Text"_ustr, + xPortion->getPropertyValue("TextPortionType").get<OUString>()); + xPortion.set(xPortionEnum->nextElement(), uno::UNO_QUERY); + // Redline start+end pair, containing a pair of text portions with an anchored object in the + // middle. + CPPUNIT_ASSERT_EQUAL(u"Redline"_ustr, + xPortion->getPropertyValue("TextPortionType").get<OUString>()); + xPortion.set(xPortionEnum->nextElement(), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(u"Text"_ustr, + xPortion->getPropertyValue("TextPortionType").get<OUString>()); + xPortion.set(xPortionEnum->nextElement(), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(u"Frame"_ustr, + xPortion->getPropertyValue("TextPortionType").get<OUString>()); + xPortion.set(xPortionEnum->nextElement(), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(u"Text"_ustr, + xPortion->getPropertyValue("TextPortionType").get<OUString>()); + xPortion.set(xPortionEnum->nextElement(), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(u"Redline"_ustr, + xPortion->getPropertyValue("TextPortionType").get<OUString>()); + xPortion.set(xPortionEnum->nextElement(), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(u"ContentControl"_ustr, + xPortion->getPropertyValue("TextPortionType").get<OUString>()); +} } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerfilter/qa/cppunittests/dmapper/data/redlined-shape-sdt.docx b/writerfilter/qa/cppunittests/dmapper/data/redlined-shape-sdt.docx Binary files differnew file mode 100644 index 000000000000..ea7f4a5bd664 --- /dev/null +++ b/writerfilter/qa/cppunittests/dmapper/data/redlined-shape-sdt.docx diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx index d5c6d553ea11..f73504824ea0 100644 --- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx +++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx @@ -984,6 +984,10 @@ void DomainMapper_Impl::PushSdt() return; } + // This may delete text, so call it early, before we would set our start position, which may be + // invalidated by a delete. + MergeAtContentImageRedlineWithNext(xTextAppend); + uno::Reference<text::XText> xText = xTextAppend->getText(); if (!xText.is()) { @@ -1022,6 +1026,7 @@ void DomainMapper_Impl::PopSdt() } catch (const uno::RuntimeException&) { + TOOLS_WARN_EXCEPTION("writerfilter", "DomainMapper_Impl::DomainMapper_Impl::PopSdt: createTextCursorByRange() failed"); // We redline form controls and that gets us confused when // we process the SDT around the placeholder. What seems to // happen is we lose the text-range when we pop the SDT position. @@ -3187,6 +3192,42 @@ void DomainMapper_Impl::applyToggleAttributes(const PropertyMapPtr& pPropertyMap } } +void DomainMapper_Impl::MergeAtContentImageRedlineWithNext(const css::uno::Reference<css::text::XTextAppend>& xTextAppend) +{ + // remove workaround for change tracked images, if they are part of a redline, + // i.e. if the next run is a tracked change with the same type, author and date, + // as in the change tracking of the image. + if ( m_bRedlineImageInPreviousRun ) + { + auto pCurrentRedline = m_aRedlines.top().size() > 0 + ? m_aRedlines.top().back() + : GetTopContextOfType(CONTEXT_CHARACTER) && + GetTopContextOfType(CONTEXT_CHARACTER)->Redlines().size() > 0 + ? GetTopContextOfType(CONTEXT_CHARACTER)->Redlines().back() + : nullptr; + if ( m_previousRedline && pCurrentRedline && + // same redline + (m_previousRedline->m_nToken & 0xffff) == (pCurrentRedline->m_nToken & 0xffff) && + m_previousRedline->m_sAuthor == pCurrentRedline->m_sAuthor && + m_previousRedline->m_sDate == pCurrentRedline->m_sDate ) + { + uno::Reference< text::XTextCursor > xCursor = xTextAppend->getEnd()->getText( )->createTextCursor( ); + assert(xCursor.is()); + xCursor->gotoEnd(false); + xCursor->goLeft(2, true); + if ( xCursor->getString() == u"" ) + { + xCursor->goRight(1, true); + xCursor->setString(""); + xCursor->gotoEnd(false); + xCursor->goLeft(1, true); + xCursor->setString(""); + } + } + + m_bRedlineImageInPreviousRun = false; + } +} void DomainMapper_Impl::appendTextPortion( const OUString& rString, const PropertyMapPtr& pPropertyMap ) { @@ -3220,39 +3261,7 @@ void DomainMapper_Impl::applyToggleAttributes(const PropertyMapPtr& pPropertyMap rValue.Value <<= false; } - // remove workaround for change tracked images, if they are part of a redline, - // i.e. if the next run is a tracked change with the same type, author and date, - // as in the change tracking of the image. - if ( m_bRedlineImageInPreviousRun ) - { - auto pCurrentRedline = m_aRedlines.top().size() > 0 - ? m_aRedlines.top().back() - : GetTopContextOfType(CONTEXT_CHARACTER) && - GetTopContextOfType(CONTEXT_CHARACTER)->Redlines().size() > 0 - ? GetTopContextOfType(CONTEXT_CHARACTER)->Redlines().back() - : nullptr; - if ( m_previousRedline && pCurrentRedline && - // same redline - (m_previousRedline->m_nToken & 0xffff) == (pCurrentRedline->m_nToken & 0xffff) && - m_previousRedline->m_sAuthor == pCurrentRedline->m_sAuthor && - m_previousRedline->m_sDate == pCurrentRedline->m_sDate ) - { - uno::Reference< text::XTextCursor > xCursor = xTextAppend->getEnd()->getText( )->createTextCursor( ); - assert(xCursor.is()); - xCursor->gotoEnd(false); - xCursor->goLeft(2, true); - if ( xCursor->getString() == u"" ) - { - xCursor->goRight(1, true); - xCursor->setString(""); - xCursor->gotoEnd(false); - xCursor->goLeft(1, true); - xCursor->setString(""); - } - } - - m_bRedlineImageInPreviousRun = false; - } + MergeAtContentImageRedlineWithNext(xTextAppend); uno::Reference< text::XTextRange > xTextRange; if (m_aTextAppendStack.top().xInsertPosition.is()) diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.hxx b/writerfilter/source/dmapper/DomainMapper_Impl.hxx index 163c92c04d31..4f4f09e58b1f 100644 --- a/writerfilter/source/dmapper/DomainMapper_Impl.hxx +++ b/writerfilter/source/dmapper/DomainMapper_Impl.hxx @@ -804,6 +804,7 @@ public: void finishParagraph( const PropertyMapPtr& pPropertyMap, const bool bRemove = false, const bool bNoNumbering = false); void applyToggleAttributes( const PropertyMapPtr& pPropertyMap ); + void MergeAtContentImageRedlineWithNext(const css::uno::Reference<css::text::XTextAppend>& xTextAppend); void appendTextPortion( const OUString& rString, const PropertyMapPtr& pPropertyMap ); void appendTextContent(const css::uno::Reference<css::text::XTextContent>&, const css::uno::Sequence<css::beans::PropertyValue>&); void appendOLE( const OUString& rStreamName, const std::shared_ptr<OLEHandler>& pOleHandler ); |