sw/qa/uibase/fldui/fldui.cxx | 20 +++++ sw/source/core/fields/docufld.cxx | 3 sw/source/core/inc/unoparaframeenum.hxx | 4 + sw/source/core/unocore/unoobj2.cxx | 25 ++++-- sw/source/core/unocore/unoparagraph.cxx | 18 +++++ writerfilter/source/dmapper/DomainMapper_Impl.cxx | 79 +++++++++++++++------- 6 files changed, 112 insertions(+), 37 deletions(-)
New commits: commit 2f9ecce61b0c806a33a9f641e43f4a71ed699fee Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Fri Dec 15 08:42:02 2023 +0300 Commit: Xisco Fauli <xiscofa...@libreoffice.org> CommitDate: Thu Dec 21 12:03:32 2023 +0100 tdf#158556: provide objects anchored to node as a hidden property This introduces a hidden property of SwXParagraph, named OOXMLImport_AnchoredShapes. Testing on my system, starting the main process first, then launching another one like time soffice path/to/bugdoc.docx ... so that it only measures time spent in import, gave the following figures: LibreOffice 7.5.0.3 (TDF build): real 1m49.016s user 0m0.000s sys 0m0.000s LibreOffice 7.6.0.3 (TDF build): real 8m37.386s user 0m0.000s sys 0m0.000s Current master (my no-debug build): real 10m6.776s user 0m0.000s sys 0m0.000s Current master with this patch (my no-debug build): real 5m41.524s user 0m0.000s sys 0m0.015s Indeed, it is not as fast as it used to be; and the fix doesn't really remove the quadratic complexity, just uses faster iteration. If there is a way to directly list objects anchored to a given paragraph, rather than iterating over all objects checking their anchors, that would get much faster, but that would be a rather large change. Change-Id: Ie50515815e85fdce498d065185199c9b31d95794 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/160813 Tested-by: Mike Kaganski <mike.kagan...@collabora.com> Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> (cherry picked from commit dcae6615ed254cf7884fa6415f64561f85b93588) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/160807 Tested-by: Jenkins Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org> diff --git a/sw/source/core/inc/unoparaframeenum.hxx b/sw/source/core/inc/unoparaframeenum.hxx index 81a653aac57f..c44e0f660c6d 100644 --- a/sw/source/core/inc/unoparaframeenum.hxx +++ b/sw/source/core/inc/unoparaframeenum.hxx @@ -31,6 +31,8 @@ class SwNodeIndex; class SwPaM; class SwFrameFormat; +namespace com { namespace sun { namespace star { namespace text { class XTextContent; } } } } + namespace sw { struct FrameClient final : public SwClient @@ -70,6 +72,8 @@ struct SwXParaFrameEnumeration static rtl::Reference<SwXParaFrameEnumeration> Create(const SwPaM& rPaM, const enum ParaFrameMode eParaFrameMode, SwFrameFormat* const pFormat = nullptr); }; +css::uno::Reference<css::text::XTextContent> FrameClientToXTextContent(sw::FrameClient* pClient); + #endif // INCLUDED_SW_SOURCE_CORE_INC_UNOPARAFRAMEENUM_HXX /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/unocore/unoobj2.cxx b/sw/source/core/unocore/unoobj2.cxx index e4f5ccdf22d9..7614f0a31485 100644 --- a/sw/source/core/unocore/unoobj2.cxx +++ b/sw/source/core/unocore/unoobj2.cxx @@ -1788,9 +1788,17 @@ bool SwXParaFrameEnumerationImpl::CreateNextObject() if (m_vFrames.empty()) return false; - SwFrameFormat* const pFormat = static_cast<SwFrameFormat*>( - m_vFrames.front()->GetRegisteredIn()); + m_xNextObject.set(FrameClientToXTextContent(m_vFrames.front().get())); m_vFrames.pop_front(); + return m_xNextObject.is(); +} + +uno::Reference<text::XTextContent> FrameClientToXTextContent(sw::FrameClient* pClient) +{ + assert(pClient); + + uno::Reference<text::XTextContent> xRet; + SwFrameFormat* const pFormat = static_cast<SwFrameFormat*>(pClient->GetRegisteredIn()); // the format should be valid here, otherwise the client // would have been removed by PurgeFrameClients // check for a shape first @@ -1799,33 +1807,32 @@ bool SwXParaFrameEnumerationImpl::CreateNextObject() SdrObject* pObject(nullptr); pFormat->CallSwClientNotify(sw::FindSdrObjectHint(pObject)); if(pObject) - m_xNextObject.set(pObject->getUnoShape(), uno::UNO_QUERY); + xRet.set(pObject->getUnoShape(), uno::UNO_QUERY); } else { const SwNodeIndex* pIdx = pFormat->GetContent().GetContentIdx(); OSL_ENSURE(pIdx, "where is the index?"); - SwNode const*const pNd = - m_pUnoCursor->GetDoc().GetNodes()[ pIdx->GetIndex() + 1 ]; + SwNode const* const pNd = pIdx->GetNodes()[pIdx->GetIndex() + 1]; if (!pNd->IsNoTextNode()) { - m_xNextObject = static_cast<SwXFrame*>(SwXTextFrame::CreateXTextFrame( + xRet = static_cast<SwXFrame*>(SwXTextFrame::CreateXTextFrame( *pFormat->GetDoc(), pFormat).get()); } else if (pNd->IsGrfNode()) { - m_xNextObject.set(SwXTextGraphicObject::CreateXTextGraphicObject( + xRet.set(SwXTextGraphicObject::CreateXTextGraphicObject( *pFormat->GetDoc(), pFormat)); } else { assert(pNd->IsOLENode()); - m_xNextObject.set(SwXTextEmbeddedObject::CreateXTextEmbeddedObject( + xRet.set(SwXTextEmbeddedObject::CreateXTextEmbeddedObject( *pFormat->GetDoc(), pFormat)); } } - return m_xNextObject.is(); + return xRet; } sal_Bool SAL_CALL diff --git a/sw/source/core/unocore/unoparagraph.cxx b/sw/source/core/unocore/unoparagraph.cxx index 68dbe34f55d5..dab5270588e3 100644 --- a/sw/source/core/unocore/unoparagraph.cxx +++ b/sw/source/core/unocore/unoparagraph.cxx @@ -54,6 +54,7 @@ #include <com/sun/star/drawing/BitmapMode.hpp> #include <comphelper/propertyvalue.hxx> +#include <comphelper/sequence.hxx> #include <comphelper/servicehelper.hxx> #include <editeng/unoipset.hxx> #include <svl/listener.hxx> @@ -550,6 +551,23 @@ uno::Sequence< uno::Any > SwXParagraph::Impl::GetPropertyValues_Impl( continue; } + if (pPropertyNames[nProp] == "OOXMLImport_AnchoredShapes") + { + // A hack to provide list of anchored objects fast + // See reanchorObjects in writerfilter/source/dmapper/DomainMapper_Impl.cxx + FrameClientSortList_t aFrames; + CollectFrameAtNode(rTextNode, aFrames, false); // Frames anchored to paragraph + CollectFrameAtNode(rTextNode, aFrames, true); // Frames anchored to character + std::vector<uno::Reference<text::XTextContent>> aRet; + aRet.reserve(aFrames.size()); + for (const auto& rFrame : aFrames) + if (auto xContent = FrameClientToXTextContent(rFrame.pFrameClient.get())) + aRet.push_back(xContent); + + pValues[nProp] <<= comphelper::containerToSequence(aRet); + continue; + } + SfxItemPropertyMapEntry const*const pEntry = rMap.getByName( pPropertyNames[nProp] ); if (!pEntry) diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx index 57a9f3bc5223..0ae745eec97a 100644 --- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx +++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx @@ -750,6 +750,59 @@ void DomainMapper_Impl::AddDummyParaForTableInSection() return sName; } +static void reanchorObjects(const uno::Reference<uno::XInterface>& xFrom, + const uno::Reference<text::XTextRange>& xTo, + const uno::Reference<drawing::XDrawPage>& xDrawPage) +{ + std::vector<uno::Reference<text::XTextContent>> aShapes; + bool bFastPathDone = false; + if (uno::Reference<beans::XPropertySet> xProps{ xFrom, uno::UNO_QUERY }) + { + try + { + // See SwXParagraph::Impl::GetPropertyValues_Impl + uno::Sequence<uno::Reference<text::XTextContent>> aSeq; + xProps->getPropertyValue(u"OOXMLImport_AnchoredShapes"_ustr) >>= aSeq; + aShapes.insert(aShapes.end(), aSeq.begin(), aSeq.end()); + bFastPathDone = true; + } + catch (const uno::Exception&) + { + } + } + + if (!bFastPathDone) + { + // Can this happen? Fallback to slow DrawPage iteration and range comparison + uno::Reference<text::XTextRange> xRange(xFrom, uno::UNO_QUERY_THROW); + uno::Reference<text::XTextRangeCompare> xCompare(xRange->getText(), uno::UNO_QUERY_THROW); + + const sal_Int32 count = xDrawPage->getCount(); + for (sal_Int32 i = 0; i < count; ++i) + { + try + { + uno::Reference<text::XTextContent> xShape(xDrawPage->getByIndex(i), + uno::UNO_QUERY_THROW); + uno::Reference<text::XTextRange> xAnchor(xShape->getAnchor(), uno::UNO_SET_THROW); + if (xCompare->compareRegionStarts(xAnchor, xRange) <= 0 + && xCompare->compareRegionEnds(xAnchor, xRange) >= 0) + { + aShapes.push_back(xShape); + } + } + catch (const uno::Exception&) + { + // Can happen e.g. in compareRegion*, when the shape is in a header, + // and paragraph in body + } + } + } + + for (const auto& xShape : aShapes) + xShape->attach(xTo); +} + void DomainMapper_Impl::RemoveLastParagraph( ) { if (m_bDiscardHeaderFooter) @@ -828,31 +881,7 @@ void DomainMapper_Impl::RemoveLastParagraph( ) auto xEnumeration = xEA->createEnumeration(); uno::Reference<text::XTextRange> xPrevParagraph(xEnumeration->nextElement(), uno::UNO_QUERY_THROW); - - uno::Reference<text::XTextRange> xParaRange(xParagraph, uno::UNO_QUERY_THROW); - uno::Reference<text::XTextRangeCompare> xRegionCompare(xParaRange->getText(), - uno::UNO_QUERY_THROW); - const sal_Int32 count = xDrawPage->getCount(); - for (sal_Int32 i = 0; i < count; ++i) - { - try - { - uno::Reference<text::XTextContent> xShape(xDrawPage->getByIndex(i), - uno::UNO_QUERY_THROW); - uno::Reference<text::XTextRange> xAnchor(xShape->getAnchor(), - uno::UNO_SET_THROW); - if (xRegionCompare->compareRegionStarts(xAnchor, xParaRange) <= 0 - && xRegionCompare->compareRegionEnds(xAnchor, xParaRange) >= 0) - { - xShape->attach(xPrevParagraph); - } - } - catch (const uno::Exception&) - { - // Can happen e.g. in compareRegion*, when the shape is in a header, - // and paragraph in body - } - } + reanchorObjects(xParagraph, xPrevParagraph, xDrawPage); } xParagraph->dispose(); commit 57d32cde67239f6723dfb09d8809c989f4c3bf78 Author: Andreas Heinisch <andreas.heini...@yahoo.de> AuthorDate: Mon Dec 18 10:54:15 2023 +0100 Commit: Xisco Fauli <xiscofa...@libreoffice.org> CommitDate: Thu Dec 21 12:03:22 2023 +0100 tdf#68364 - Don't assume a database if only two dots are present Additionally, a database table name (database.table.column) has to be retrieved from the database to be valid. Change-Id: I8949ae61d96043412425d634763d2ea33ce6a0f3 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/160910 Tested-by: Jenkins Reviewed-by: Andreas Heinisch <andreas.heini...@yahoo.de> (cherry picked from commit 74f25206bc5a1a36b85683555cb27179e5da3275) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161094 Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org> diff --git a/sw/qa/uibase/fldui/fldui.cxx b/sw/qa/uibase/fldui/fldui.cxx index 78b2fcedd42a..0bf6bfa33fb6 100644 --- a/sw/qa/uibase/fldui/fldui.cxx +++ b/sw/qa/uibase/fldui/fldui.cxx @@ -121,6 +121,26 @@ CPPUNIT_TEST_FIXTURE(Test, testInsertRefmark) CPPUNIT_ASSERT_EQUAL(OUString("aaabbbccc"), pTextNode->GetText()); } +CPPUNIT_TEST_FIXTURE(Test, testTdf68364InsertConditionalFieldWithTwoDots) +{ + // Create an empty document + createSwDoc(); + SwDoc* pDoc = getSwDoc(); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + + // Insert a conditional field containing exactly two dots for its condition + SwFieldMgr aFieldMgr(pWrtShell); + SwInsertField_Data aFieldData(SwFieldTypesEnum::ConditionalText, 0, "true", "19.12.2023", 0); + CPPUNIT_ASSERT(aFieldMgr.InsertField(aFieldData)); + pWrtShell->SttEndDoc(true); + + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 19.12.2023 + // - Actual : + CPPUNIT_ASSERT_EQUAL(OUString("19.12.2023"), + pWrtShell->GetCurField()->ExpandField(true, nullptr)); +} + CPPUNIT_TEST_FIXTURE(Test, testInsertRefmarkSelection) { // Given a document with a single selected word: diff --git a/sw/source/core/fields/docufld.cxx b/sw/source/core/fields/docufld.cxx index 37249555a0e4..ba5f45beceec 100644 --- a/sw/source/core/fields/docufld.cxx +++ b/sw/source/core/fields/docufld.cxx @@ -1389,9 +1389,6 @@ void SwHiddenTextField::Evaluate(SwDoc& rDoc) GetLanguage(), m_aContent, &fNumber ); m_bValid = true; } - else if( !sDBName.isEmpty() && !sDataSource.isEmpty() && - !sDataTableOrQuery.isEmpty() ) - m_bValid = true; } #endif }