diff options
-rw-r--r-- | include/xmloff/txtimp.hxx | 3 | ||||
-rw-r--r-- | sw/inc/IDocumentMarkAccess.hxx | 2 | ||||
-rw-r--r-- | sw/qa/extras/odfexport/odfexport.cxx | 4 | ||||
-rw-r--r-- | sw/source/core/doc/docbm.cxx | 6 | ||||
-rw-r--r-- | sw/source/core/inc/MarkManager.hxx | 2 | ||||
-rw-r--r-- | sw/source/core/unocore/unobkm.cxx | 9 | ||||
-rw-r--r-- | xmloff/source/core/xmlimp.cxx | 2 | ||||
-rw-r--r-- | xmloff/source/text/XMLTextMarkImportContext.cxx | 46 | ||||
-rw-r--r-- | xmloff/source/text/XMLTextMarkImportContext.hxx | 7 | ||||
-rw-r--r-- | xmloff/source/text/txtimp.cxx | 60 | ||||
-rw-r--r-- | xmloff/source/text/txtparai.cxx | 38 |
11 files changed, 150 insertions, 29 deletions
diff --git a/include/xmloff/txtimp.hxx b/include/xmloff/txtimp.hxx index 6d9239f352ea..d91e3d0152dc 100644 --- a/include/xmloff/txtimp.hxx +++ b/include/xmloff/txtimp.hxx @@ -713,6 +713,9 @@ public: void SetCellParaStyleDefault(OUString const& rNewValue); OUString const& GetCellParaStyleDefault(); + + void AddCrossRefHeadingMapping(OUString const& rFrom, OUString const& rTo); + void MapCrossRefHeadingFieldsHorribly(); }; #endif diff --git a/sw/inc/IDocumentMarkAccess.hxx b/sw/inc/IDocumentMarkAccess.hxx index d071f419018d..a0bdeb6a8fac 100644 --- a/sw/inc/IDocumentMarkAccess.hxx +++ b/sw/inc/IDocumentMarkAccess.hxx @@ -77,7 +77,7 @@ class IDocumentMarkAccess */ virtual ::sw::mark::IMark* makeMark(const SwPaM& rPaM, const OUString& rProposedName, - MarkType eMark, bool = false) = 0; + MarkType eMark) = 0; virtual sw::mark::IFieldmark* makeFieldBookmark( const SwPaM& rPaM, const OUString& rName, diff --git a/sw/qa/extras/odfexport/odfexport.cxx b/sw/qa/extras/odfexport/odfexport.cxx index addf9c5c0ba2..04d1d3cdfaba 100644 --- a/sw/qa/extras/odfexport/odfexport.cxx +++ b/sw/qa/extras/odfexport/odfexport.cxx @@ -421,9 +421,7 @@ DECLARE_ODFEXPORT_TEST(testDuplicateCrossRefHeadingBookmark, "CrossRefHeadingBoo uno::Reference<text::XTextContent> xBookmark1( xBookmarks->getByName("__RefHeading__8284_1826734303"), uno::UNO_QUERY); CPPUNIT_ASSERT(xBookmark1.is()); - uno::Reference<text::XTextContent> xBookmark2( - xBookmarks->getByName("__RefHeading__1673_25705824"), uno::UNO_QUERY); - CPPUNIT_ASSERT(xBookmark2.is()); + CPPUNIT_ASSERT_THROW(xBookmarks->getByName("__RefHeading__1673_25705824"), container::NoSuchElementException); uno::Reference<text::XTextFieldsSupplier> xTextFieldsSupplier(mxComponent, uno::UNO_QUERY); uno::Reference<util::XRefreshable>(xTextFieldsSupplier->getTextFields(), uno::UNO_QUERY)->refresh(); diff --git a/sw/source/core/doc/docbm.cxx b/sw/source/core/doc/docbm.cxx index 6efca0e0da42..90f466fd3d8f 100644 --- a/sw/source/core/doc/docbm.cxx +++ b/sw/source/core/doc/docbm.cxx @@ -349,8 +349,7 @@ namespace sw { namespace mark ::sw::mark::IMark* MarkManager::makeMark(const SwPaM& rPaM, const OUString& rName, - const IDocumentMarkAccess::MarkType eType, - bool const isHorribleHackIgnoreDuplicates) + const IDocumentMarkAccess::MarkType eType) { #if 0 { @@ -373,8 +372,7 @@ namespace sw { namespace mark " - more than USHRT_MAX marks are not supported correctly"); // There should only be one CrossRefBookmark per Textnode per Type if ((eType == MarkType::CROSSREF_NUMITEM_BOOKMARK || eType == MarkType::CROSSREF_HEADING_BOOKMARK) - && (lcl_FindMarkAtPos(m_vBookmarks, *rPaM.Start(), eType) != m_vBookmarks.end()) - && !isHorribleHackIgnoreDuplicates) + && (lcl_FindMarkAtPos(m_vBookmarks, *rPaM.Start(), eType) != m_vBookmarks.end())) { // this can happen via UNO API SAL_WARN("sw.core", "MarkManager::makeMark(..)" " - refusing to create duplicate CrossRefBookmark"); diff --git a/sw/source/core/inc/MarkManager.hxx b/sw/source/core/inc/MarkManager.hxx index 6abeb4831196..c0f09c939cc8 100644 --- a/sw/source/core/inc/MarkManager.hxx +++ b/sw/source/core/inc/MarkManager.hxx @@ -37,7 +37,7 @@ namespace sw { public: MarkManager(/*[in/out]*/ SwDoc& rDoc); // IDocumentMarkAccess - virtual ::sw::mark::IMark* makeMark(const SwPaM& rPaM, const OUString& rName, IDocumentMarkAccess::MarkType eMark, bool = false) override; + virtual ::sw::mark::IMark* makeMark(const SwPaM& rPaM, const OUString& rName, IDocumentMarkAccess::MarkType eMark) override; virtual sw::mark::IFieldmark* makeFieldBookmark( const SwPaM& rPaM, const OUString& rName, diff --git a/sw/source/core/unocore/unobkm.cxx b/sw/source/core/unocore/unobkm.cxx index dc049286e6d7..e254fff477d8 100644 --- a/sw/source/core/unocore/unobkm.cxx +++ b/sw/source/core/unocore/unobkm.cxx @@ -227,7 +227,6 @@ throw (lang::IllegalArgumentException, uno::RuntimeException) SwUnoInternalPaM aPam(*m_pImpl->m_pDoc); ::sw::XTextRangeToSwPaM(aPam, xTextRange); UnoActionContext aCont(m_pImpl->m_pDoc); - bool isHorribleHackIgnoreDuplicates(false); if (m_pImpl->m_sMarkName.isEmpty()) { m_pImpl->m_sMarkName = "Bookmark"; @@ -242,16 +241,10 @@ throw (lang::IllegalArgumentException, uno::RuntimeException) IDocumentMarkAccess::IsLegalPaMForCrossRefHeadingBookmark( aPam ) ) { eType = IDocumentMarkAccess::MarkType::CROSSREF_HEADING_BOOKMARK; - // tdf#94804 LO 4.2-5.0 create invalid duplicates that must be preserved - // note: do not check meta:generator, may be preserved by other versions - if (m_pImpl->m_pDoc->IsInXMLImport()) - { - isHorribleHackIgnoreDuplicates = true; - } } m_pImpl->registerInMark(*this, m_pImpl->m_pDoc->getIDocumentMarkAccess()->makeMark( - aPam, m_pImpl->m_sMarkName, eType, isHorribleHackIgnoreDuplicates)); + aPam, m_pImpl->m_sMarkName, eType)); // #i81002# // Check, if bookmark has been created. // E.g., the creation of a cross-reference bookmark is suppress, diff --git a/xmloff/source/core/xmlimp.cxx b/xmloff/source/core/xmlimp.cxx index 52b10a96d853..483cc02cb51f 100644 --- a/xmloff/source/core/xmlimp.cxx +++ b/xmloff/source/core/xmlimp.cxx @@ -545,6 +545,8 @@ void SAL_CALL SvXMLImport::endDocument() // #i9518# All the stuff that accesses the document has to be done here, not in the dtor, // because the SvXMLImport dtor might not be called until after the document has been closed. + GetTextImport()->MapCrossRefHeadingFieldsHorribly(); + if (mpImpl->mpRDFaHelper.get()) { const uno::Reference<rdf::XRepositorySupplier> xRS(mxModel, diff --git a/xmloff/source/text/XMLTextMarkImportContext.cxx b/xmloff/source/text/XMLTextMarkImportContext.cxx index 2ebef98d77d6..a670fdc81390 100644 --- a/xmloff/source/text/XMLTextMarkImportContext.cxx +++ b/xmloff/source/text/XMLTextMarkImportContext.cxx @@ -99,10 +99,12 @@ void XMLFieldParamImportContext::StartElement(const css::uno::Reference< css::xm XMLTextMarkImportContext::XMLTextMarkImportContext( SvXMLImport& rImport, XMLTextImportHelper& rHlp, + uno::Reference<uno::XInterface> & io_rxCrossRefHeadingBookmark, sal_uInt16 nPrefix, const OUString& rLocalName ) : SvXMLImportContext(rImport, nPrefix, rLocalName) , m_rHelper(rHlp) + , m_rxCrossRefHeadingBookmark(io_rxCrossRefHeadingBookmark) , m_bHaveAbout(false) { } @@ -202,9 +204,23 @@ void XMLTextMarkImportContext::EndElement() OUString()); break; - case TypeFieldmark: case TypeBookmark: { + // tdf#94804: detect duplicate heading cross reference bookmarks + if (m_sBookmarkName.startsWith("__RefHeading__")) + { + if (m_rxCrossRefHeadingBookmark.is()) + { + uno::Reference<container::XNamed> const xNamed( + m_rxCrossRefHeadingBookmark, uno::UNO_QUERY); + m_rHelper.AddCrossRefHeadingMapping( + m_sBookmarkName, xNamed->getName()); + break; // don't insert + } + } + } // fall through + case TypeFieldmark: + { const char *formFieldmarkName=lcl_getFormFieldmarkName(m_sFieldName); bool bImportAsField=((lcl_MarkType)nTmp==TypeFieldmark && formFieldmarkName!=nullptr); //@TODO handle abbreviation cases.. // export point bookmark @@ -225,6 +241,12 @@ void XMLTextMarkImportContext::EndElement() } m_rHelper.popFieldCtx(); } + if (TypeBookmark == nTmp + && m_sBookmarkName.startsWith("__RefHeading__")) + { + assert(xContent.is()); + m_rxCrossRefHeadingBookmark = xContent; + } } break; @@ -249,8 +271,22 @@ void XMLTextMarkImportContext::EndElement() } break; - case TypeFieldmarkEnd: case TypeBookmarkEnd: + { + // tdf#94804: detect duplicate heading cross reference bookmarks + if (m_sBookmarkName.startsWith("__RefHeading__")) + { + if (m_rxCrossRefHeadingBookmark.is()) + { + uno::Reference<container::XNamed> const xNamed( + m_rxCrossRefHeadingBookmark, uno::UNO_QUERY); + m_rHelper.AddCrossRefHeadingMapping( + m_sBookmarkName, xNamed->getName()); + break; // don't insert + } + } + } // fall through + case TypeFieldmarkEnd: { // get old range, and construct Reference<XTextRange> xStartRange; @@ -333,6 +369,12 @@ void XMLTextMarkImportContext::EndElement() } m_rHelper.popFieldCtx(); } + if (TypeBookmarkEnd == nTmp + && m_sBookmarkName.startsWith("__RefHeading__")) + { + assert(xContent.is()); + m_rxCrossRefHeadingBookmark = xContent; + } } // else: beginning/end in different XText -> ignore! } diff --git a/xmloff/source/text/XMLTextMarkImportContext.hxx b/xmloff/source/text/XMLTextMarkImportContext.hxx index b768c3567221..cc9bdf992330 100644 --- a/xmloff/source/text/XMLTextMarkImportContext.hxx +++ b/xmloff/source/text/XMLTextMarkImportContext.hxx @@ -60,8 +60,11 @@ public: */ class XMLTextMarkImportContext : public SvXMLImportContext { - +private: XMLTextImportHelper & m_rHelper; + + css::uno::Reference<css::uno::XInterface> & m_rxCrossRefHeadingBookmark; + OUString m_sBookmarkName; OUString m_sFieldName; OUString m_sXmlId; @@ -74,10 +77,10 @@ class XMLTextMarkImportContext : public SvXMLImportContext public: - XMLTextMarkImportContext( SvXMLImport& rImport, XMLTextImportHelper& rHlp, + css::uno::Reference<css::uno::XInterface> & io_rxCrossRefHeadingBookmark, sal_uInt16 nPrfx, const OUString& rLocalName ); diff --git a/xmloff/source/text/txtimp.cxx b/xmloff/source/text/txtimp.cxx index 2ece1f4b4d32..9afcb432d69f 100644 --- a/xmloff/source/text/txtimp.cxx +++ b/xmloff/source/text/txtimp.cxx @@ -25,7 +25,9 @@ #include <com/sun/star/container/XEnumerationAccess.hpp> #include <com/sun/star/lang/XMultiServiceFactory.hpp> #include <com/sun/star/style/XStyleFamiliesSupplier.hpp> +#include <com/sun/star/text/ReferenceFieldSource.hpp> #include <com/sun/star/text/XChapterNumberingSupplier.hpp> +#include <com/sun/star/text/XTextFieldsSupplier.hpp> #include <com/sun/star/text/XTextFramesSupplier.hpp> #include <com/sun/star/text/XTextGraphicObjectsSupplier.hpp> #include <com/sun/star/text/XTextEmbeddedObjectsSupplier.hpp> @@ -575,6 +577,8 @@ struct XMLTextImportHelper::Impl OUString m_sCellParaStyleDefault; + std::unique_ptr<std::map<OUString, OUString>> m_pCrossRefHeadingBookmarkMap; + Impl( uno::Reference<frame::XModel> const& rModel, SvXMLImport & rImport, bool const bInsertMode, bool const bStylesOnlyMode, @@ -2797,4 +2801,60 @@ OUString const& XMLTextImportHelper::GetCellParaStyleDefault() return m_xImpl->m_sCellParaStyleDefault; } +void XMLTextImportHelper::AddCrossRefHeadingMapping(OUString const& rFrom, OUString const& rTo) +{ + if (!m_xImpl->m_pCrossRefHeadingBookmarkMap) + { + m_xImpl->m_pCrossRefHeadingBookmarkMap.reset(new std::map<OUString, OUString>); + } + m_xImpl->m_pCrossRefHeadingBookmarkMap->insert(std::make_pair(rFrom, rTo)); +} + +// tdf#94804: hack to map cross reference fiels that reference duplicate marks +// note that we can't really check meta:generator for this since the file might +// be round-tripped by different versions preserving duplicates => always map +void XMLTextImportHelper::MapCrossRefHeadingFieldsHorribly() +{ + if (!m_xImpl->m_pCrossRefHeadingBookmarkMap) + { + return; + } + + uno::Reference<text::XTextFieldsSupplier> const xFieldsSupplier( + m_xImpl->m_rSvXMLImport.GetModel(), uno::UNO_QUERY); + if (!xFieldsSupplier.is()) + { + return; + } + uno::Reference<container::XEnumerationAccess> const xFieldsEA( + xFieldsSupplier->getTextFields()); + uno::Reference<container::XEnumeration> const xFields( + xFieldsEA->createEnumeration()); + while (xFields->hasMoreElements()) + { + uno::Reference<lang::XServiceInfo> const xFieldInfo( + xFields->nextElement(), uno::UNO_QUERY); + if (!xFieldInfo->supportsService("com.sun.star.text.textfield.GetReference")) + { + continue; + } + uno::Reference<beans::XPropertySet> const xField( + xFieldInfo, uno::UNO_QUERY); + sal_uInt16 nType(0); + xField->getPropertyValue("ReferenceFieldSource") >>= nType; + if (text::ReferenceFieldSource::BOOKMARK != nType) + { + continue; + } + OUString name; + xField->getPropertyValue("SourceName") >>= name; + auto const iter(m_xImpl->m_pCrossRefHeadingBookmarkMap->find(name)); + if (iter == m_xImpl->m_pCrossRefHeadingBookmarkMap->end()) + { + continue; + } + xField->setPropertyValue("SourceName", uno::makeAny(iter->second)); + } +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtparai.cxx b/xmloff/source/text/txtparai.cxx index ffceba4cfbbf..0d4b7e3c83e1 100644 --- a/xmloff/source/text/txtparai.cxx +++ b/xmloff/source/text/txtparai.cxx @@ -68,8 +68,28 @@ using namespace ::xmloff::token; using ::com::sun::star::container::XEnumerationAccess; using ::com::sun::star::container::XEnumeration; -class XMLHints_Impl : public std::vector<std::unique_ptr<XMLHint_Impl>> {}; +class XMLHints_Impl +{ +private: + std::vector<std::unique_ptr<XMLHint_Impl>> m_Hints; + uno::Reference<uno::XInterface> m_xCrossRefHeadingBookmark; + +public: + void push_back(std::unique_ptr<XMLHint_Impl> pHint) + { + m_Hints.push_back(std::move(pHint)); + } + std::vector<std::unique_ptr<XMLHint_Impl>> const& GetHints() + { + return m_Hints; + } + + uno::Reference<uno::XInterface> & GetCrossRefHeadingBookmark() + { + return m_xCrossRefHeadingBookmark; + } +}; XMLCharContext::XMLCharContext( SvXMLImport& rImport, @@ -253,10 +273,10 @@ XMLEndReferenceContext_Impl::XMLEndReferenceContext_Impl( if (XMLStartReferenceContext_Impl::FindName(GetImport(), xAttrList, sName)) { // search for reference start - sal_uInt16 nCount = rHints.size(); + sal_uInt16 nCount = rHints.GetHints().size(); for(sal_uInt16 nPos = 0; nPos < nCount; nPos++) { - XMLHint_Impl *const pHint = rHints[nPos].get(); + XMLHint_Impl *const pHint = rHints.GetHints()[nPos].get(); if ( pHint->IsReference() && sName.equals( static_cast<XMLReferenceHint_Impl *>(pHint)->GetRefName()) ) { @@ -1102,10 +1122,10 @@ void XMLIndexMarkImportContext_Impl::StartElement( if (!sID.isEmpty()) { // if we have an ID, find the hint and set the end position - sal_uInt16 nCount = m_rHints.size(); + sal_uInt16 nCount = m_rHints.GetHints().size(); for(sal_uInt16 nPos = 0; nPos < nCount; nPos++) { - XMLHint_Impl *const pHint = m_rHints[nPos].get(); + XMLHint_Impl *const pHint = m_rHints.GetHints()[nPos].get(); if ( pHint->IsIndexMark() && sID.equals( static_cast<XMLIndexMarkHint_Impl *>(pHint)->GetID()) ) @@ -1629,6 +1649,7 @@ SvXMLImportContext *XMLImpSpanContext_Impl::CreateChildContext( case XML_TOK_TEXT_BOOKMARK_END: pContext = new XMLTextMarkImportContext( rImport, *rImport.GetTextImport().get(), + rHints.GetCrossRefHeadingBookmark(), nPrefix, rLocalName ); break; @@ -1637,6 +1658,7 @@ SvXMLImportContext *XMLImpSpanContext_Impl::CreateChildContext( case XML_TOK_TEXT_FIELDMARK_END: pContext = new XMLTextMarkImportContext( rImport, *rImport.GetTextImport().get(), + rHints.GetCrossRefHeadingBookmark(), nPrefix, rLocalName ); break; @@ -2045,11 +2067,11 @@ XMLParaContext::~XMLParaContext() } } - if( pHints && !pHints->empty() ) + if (pHints && !pHints->GetHints().empty()) { - for( size_t i=0; i<pHints->size(); i++ ) + for (size_t i = 0; i < pHints->GetHints().size(); ++i) { - XMLHint_Impl *const pHint = (*pHints)[i].get(); + XMLHint_Impl *const pHint = pHints->GetHints()[i].get(); xAttrCursor->gotoRange( pHint->GetStart(), sal_False ); xAttrCursor->gotoRange( pHint->GetEnd(), sal_True ); switch( pHint->GetType() ) |