sw/inc/tox.hxx | 19 --------- sw/inc/unomap.hxx | 1 sw/inc/unoprnms.hxx | 1 sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx | 6 ++ sw/source/core/tox/tox.cxx | 7 --- sw/source/core/unocore/unoidx.cxx | 25 ----------- sw/source/core/unocore/unomap.cxx | 1 sw/source/filter/ww8/wrtw8nds.cxx | 17 +++++++- sw/source/filter/ww8/ww8atr.cxx | 20 +++++---- writerfilter/source/dmapper/DomainMapper_Impl.cxx | 46 +++++++++++++++++----- writerfilter/source/dmapper/PropertyIds.cxx | 1 writerfilter/source/dmapper/PropertyIds.hxx | 1 12 files changed, 69 insertions(+), 76 deletions(-)
New commits: commit 1cb65db9031d40e16f7470f825625c9999409025 Author: László Németh <nem...@numbertext.org> AuthorDate: Fri Oct 1 17:42:48 2021 +0200 Commit: Xisco Fauli <xiscofa...@libreoffice.org> CommitDate: Tue Oct 5 10:17:14 2021 +0200 tdf#77051 DOCX: fix user index and index entry support defined by field code \f. E.g. INDEX \f "user-index" inserts only the entries defined by XE "entry" \f "user-index" field codes. Revert commit a7bc9c1e4977bd3430df69287fa0a8377a686c58 "fdo#77051: Preservation of Index field flag '\f'", which added an undocumented UNO property only for round-trip support of INDEX, but not for XE index entries, so the DOCX export still resulted a broken index with lost entries, not only the import was broken because of the missing functionality in com.sun.star.text.DocumentIndex. Now the import uses com.sun.star.text.UserIndex and com.sun.star.text.UserIndexMark index and index entry fields, which support the requested user index not only during the DOCX and OpenDocument round-trip, but its run-time functionality, the multiple user-defined indices. Note: for manual testing, update the user index (the first index) of the left original unit test document IndexFieldFlagF.docx: the updated index is not empty, as before, but contains the user index entries. Change-Id: Ia6139bba88907051fd050cfd40809f5544b9a89e Reviewed-on: https://gerrit.libreoffice.org/c/core/+/122930 Tested-by: László Németh <nem...@numbertext.org> Reviewed-by: László Németh <nem...@numbertext.org> Signed-off-by: Xisco Fauli <xiscofa...@libreoffice.org> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/123071 Tested-by: Jenkins diff --git a/sw/inc/tox.hxx b/sw/inc/tox.hxx index e16882e87afa..77f7e6cd5e5b 100644 --- a/sw/inc/tox.hxx +++ b/sw/inc/tox.hxx @@ -99,7 +99,6 @@ class SW_DLLPUBLIC SwTOXMark final sal_uInt16 m_nLevel; OUString m_aBookmarkName; - OUString m_aEntryTypeName; // stored specific entry type name for INDEX field \f bool m_bAutoGenerated; // generated using a concordance file bool m_bMainEntry; // main entry emphasized by character style @@ -136,8 +135,6 @@ public: inline sal_uInt16 GetLevel() const; inline void SetBookmarkName( const OUString& bName); inline const OUString& GetBookmarkName() const; - inline void SetEntryTypeName( const OUString& sName); - inline const OUString& GetEntryTypeName() const; // for alphabetical index only inline void SetPrimaryKey(const OUString& rStr ); @@ -381,7 +378,6 @@ enum class SwTOXElement : sal_uInt16 Bookmark = 0x0400, Newline = 0x0800, ParagraphOutlineLevel = 0x1000, - IndexEntryType = 0x2000, }; namespace o3tl { template<> struct typed_flags<SwTOXElement> : is_typed_flags<SwTOXElement, 0x3fff> {}; @@ -432,7 +428,6 @@ class SW_DLLPUBLIC SwTOXBase : public SwClient OUString m_aName; // unique name OUString m_aTitle; // title OUString m_aBookmarkName; //Bookmark Name - OUString m_aEntryTypeName; // Type name OUString m_sMainEntryCharStyle; // name of the character style applied to main index entries @@ -507,10 +502,6 @@ public: const OUString& GetMainEntryCharStyle() const {return m_sMainEntryCharStyle;} void SetMainEntryCharStyle(const OUString& rSet) {m_sMainEntryCharStyle = rSet;} - // for record the Index field expression of MS Word - const OUString& GetEntryTypeName() const; - void SetEntryTypeName(const OUString& sName); - // content index only inline void SetLevel(sal_uInt16); // consider outline level inline sal_uInt16 GetLevel() const; @@ -582,9 +573,6 @@ inline const OUString& SwTOXMark::GetAlternativeText() const inline const OUString& SwTOXMark::GetBookmarkName() const { return m_aBookmarkName; } -inline const OUString& SwTOXMark::GetEntryTypeName() const - { return m_aEntryTypeName; } - inline const SwTOXType* SwTOXMark::GetTOXType() const { return m_pType; } @@ -601,10 +589,6 @@ inline void SwTOXMark::SetBookmarkName(const OUString& bName) m_aBookmarkName = bName; } -inline void SwTOXMark::SetEntryTypeName(const OUString& sName) -{ - m_aEntryTypeName = sName; -} inline void SwTOXMark::SetLevel( sal_uInt16 nLvl ) { SAL_WARN_IF( GetTOXType() && GetTOXType()->GetType() == TOX_INDEX, "sw", "Wrong type"); @@ -723,9 +707,6 @@ inline const OUString& SwTOXBase::GetTitle() const inline const OUString& SwTOXBase::GetBookmarkName() const { return m_aBookmarkName; } -inline const OUString& SwTOXBase::GetEntryTypeName() const - { return m_aEntryTypeName; } - inline OUString const & SwTOXBase::GetTypeName() const { return GetTOXType()->GetTypeName(); } diff --git a/sw/inc/unomap.hxx b/sw/inc/unomap.hxx index d2c54d204188..c4c166032983 100644 --- a/sw/inc/unomap.hxx +++ b/sw/inc/unomap.hxx @@ -223,7 +223,6 @@ struct SfxItemPropertyMapEntry; #define WID_TOC_BOOKMARK 1061 #define WID_TOC_NEWLINE 1062 #define WID_TOC_PARAGRAPH_OUTLINE_LEVEL 1063 -#define WID_INDEX_ENTRY_TYPE 1064 // Text document #define WID_DOC_CHAR_COUNT 1000 diff --git a/sw/inc/unoprnms.hxx b/sw/inc/unoprnms.hxx index a6fe2dba18df..63e91b17146b 100644 --- a/sw/inc/unoprnms.hxx +++ b/sw/inc/unoprnms.hxx @@ -489,7 +489,6 @@ #define UNO_NAME_HIDE_FIELD_TIPS "HideFieldTips" #define UNO_NAME_PARA_SHADOW_FORMAT "ParaShadowFormat" #define UNO_NAME_CONTOUR_POLY_POLYGON "ContourPolyPolygon" -#define UNO_NAME_INDEX_ENTRY_TYPE "IndexEntryType" #define UNO_NAME_IS_PIXEL_CONTOUR "IsPixelContour" #define UNO_NAME_IS_AUTOMATIC_CONTOUR "IsAutomaticContour" diff --git a/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx b/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx index f6e6ea78bc99..658830274534 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx @@ -290,7 +290,11 @@ DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testIndexFieldFlagF,"IndexFieldFlagF.docx") // Specific Entry Type (ex. "Syn" in our case). xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml"); // We check the Index field flag '\f'. - assertXPathContent(pXmlDoc, "/w:document[1]/w:body[1]/w:p[4]/w:r[2]/w:instrText[1]", " INDEX \\c \"2\"\\f \"Syn\" \" \\e \""); + // Note: no syntax error any more (extra quotation mark between "Syn" and \e) + assertXPathContent(pXmlDoc, "/w:document[1]/w:body[1]/w:p[4]/w:r[2]/w:instrText[1]", " INDEX \\c \"2\"\\f \"Syn\"\\e \""); + // XE entries lost their \f "Syn" before + assertXPathContent(pXmlDoc, "/w:document[1]/w:body[1]/w:p[17]/w:r[21]/w:instrText[1]", " XE \"formatting\" \\f \"Syn\" "); + assertXPathContent(pXmlDoc, "/w:document[1]/w:body[1]/w:p[17]/w:r[29]/w:instrText[1]", " XE \"choosing:aaaa\" \\f \"Syn\" "); } DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testBibliography,"FDO75133.docx") diff --git a/sw/source/core/tox/tox.cxx b/sw/source/core/tox/tox.cxx index 021da63a54e3..30a5c6f9da35 100644 --- a/sw/source/core/tox/tox.cxx +++ b/sw/source/core/tox/tox.cxx @@ -587,7 +587,6 @@ void SwTOXBase::CopyTOXBase( SwDoc* pDoc, const SwTOXBase& rSource ) m_aTitle = rSource.m_aTitle; m_aForm = rSource.m_aForm; m_aBookmarkName = rSource.m_aBookmarkName; - m_aEntryTypeName = rSource.m_aEntryTypeName ; m_bProtected = rSource.m_bProtected; m_bFromChapter = rSource.m_bFromChapter; m_bFromObjectNames = rSource.m_bFromObjectNames; @@ -626,18 +625,12 @@ void SwTOXBase::SetBookmarkName(const OUString& bName) m_aBookmarkName = bName; } -void SwTOXBase::SetEntryTypeName(const OUString& sName) -{ - m_aEntryTypeName = sName ; -} - SwTOXBase & SwTOXBase::operator = (const SwTOXBase & rSource) { m_aForm = rSource.m_aForm; m_aName = rSource.m_aName; m_aTitle = rSource.m_aTitle; m_aBookmarkName = rSource.m_aBookmarkName; - m_aEntryTypeName = rSource.m_aEntryTypeName ; m_sMainEntryCharStyle = rSource.m_sMainEntryCharStyle; for(sal_uInt16 nLevel = 0; nLevel < MAXLEVEL; nLevel++) m_aStyleNames[nLevel] = rSource.m_aStyleNames[nLevel]; diff --git a/sw/source/core/unocore/unoidx.cxx b/sw/source/core/unocore/unoidx.cxx index 418dfce96797..1b75e9fb0e24 100644 --- a/sw/source/core/unocore/unoidx.cxx +++ b/sw/source/core/unocore/unoidx.cxx @@ -631,13 +631,6 @@ SwXDocumentIndex::setPropertyValue( rTOXBase.SetCreate(nCreate); } break; - case WID_INDEX_ENTRY_TYPE: - { - rTOXBase.SetEntryTypeName(lcl_AnyToType<OUString>(rValue)); - nCreate = SwTOXElement::IndexEntryType; - rTOXBase.SetCreate(nCreate); - } - break; case WID_CREATE_FROM_MARKS: lcl_AnyToBitMask(rValue, nCreate, SwTOXElement::Mark); break; @@ -952,9 +945,6 @@ SwXDocumentIndex::getPropertyValue(const OUString& rPropertyName) case WID_TOC_BOOKMARK : aRet <<= pTOXBase->GetBookmarkName(); break; - case WID_INDEX_ENTRY_TYPE : - aRet <<= pTOXBase->GetEntryTypeName(); - break; case WID_CREATE_FROM_MARKS: lcl_BitMaskToAny(aRet, nCreate, SwTOXElement::Mark); break; @@ -1504,7 +1494,6 @@ public: bool m_bMainEntry; sal_uInt16 m_nLevel; OUString m_aBookmarkName; - OUString m_aEntryTypeName; OUString m_sAltText; OUString m_sPrimaryKey; OUString m_sSecondaryKey; @@ -2073,9 +2062,6 @@ SwXDocumentIndexMark::setPropertyValue( case WID_TOC_BOOKMARK : aMark.SetBookmarkName(lcl_AnyToType<OUString>(rValue)); break; - case WID_INDEX_ENTRY_TYPE : - aMark.SetEntryTypeName(lcl_AnyToType<OUString>(rValue)); - break; case WID_PRIMARY_KEY : aMark.SetPrimaryKey(lcl_AnyToType<OUString>(rValue)); break; @@ -2132,11 +2118,6 @@ SwXDocumentIndexMark::setPropertyValue( m_pImpl->m_aBookmarkName = lcl_AnyToType<OUString>(rValue); } break; - case WID_INDEX_ENTRY_TYPE : - { - m_pImpl->m_aEntryTypeName = lcl_AnyToType<OUString>(rValue); - } - break; case WID_PRIMARY_KEY: m_pImpl->m_sPrimaryKey = lcl_AnyToType<OUString>(rValue); break; @@ -2207,9 +2188,6 @@ SwXDocumentIndexMark::getPropertyValue(const OUString& rPropertyName) case WID_TOC_BOOKMARK : aRet <<= m_pImpl->m_pTOXMark->GetBookmarkName(); break; - case WID_INDEX_ENTRY_TYPE : - aRet <<= m_pImpl->m_pTOXMark->GetEntryTypeName(); - break; case WID_PRIMARY_KEY : aRet <<= m_pImpl->m_pTOXMark->GetPrimaryKey(); break; @@ -2253,9 +2231,6 @@ SwXDocumentIndexMark::getPropertyValue(const OUString& rPropertyName) case WID_TOC_BOOKMARK : aRet <<= m_pImpl->m_aBookmarkName; break; - case WID_INDEX_ENTRY_TYPE : - aRet <<= m_pImpl->m_aEntryTypeName; - break; case WID_PRIMARY_KEY: aRet <<= m_pImpl->m_sPrimaryKey; break; diff --git a/sw/source/core/unocore/unomap.cxx b/sw/source/core/unocore/unomap.cxx index 3580a8f416a2..4e373b6c511e 100644 --- a/sw/source/core/unocore/unomap.cxx +++ b/sw/source/core/unocore/unomap.cxx @@ -348,7 +348,6 @@ const SfxItemPropertyMapEntry* SwUnoPropertyMapProvider::GetPropertyMapEntries(s { u"" UNO_NAME_IS_RELATIVE_TABSTOPS, WID_IS_RELATIVE_TABSTOPS, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, { u"" UNO_NAME_LOCALE, WID_IDX_LOCALE, cppu::UnoType<css::lang::Locale>::get(), PROPERTY_NONE, 0}, { u"" UNO_NAME_SORT_ALGORITHM, WID_IDX_SORT_ALGORITHM, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, - { u"" UNO_NAME_INDEX_ENTRY_TYPE, WID_INDEX_ENTRY_TYPE, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, { u"", 0, css::uno::Type(), 0, 0 } }; m_aMapEntriesArr[nPropertyId] = aTOXIndexMap_Impl; diff --git a/sw/source/filter/ww8/wrtw8nds.cxx b/sw/source/filter/ww8/wrtw8nds.cxx index da5253f723b7..d87e342a7009 100644 --- a/sw/source/filter/ww8/wrtw8nds.cxx +++ b/sw/source/filter/ww8/wrtw8nds.cxx @@ -1291,7 +1291,17 @@ void AttributeOutputBase::TOXMark( const SwTextNode& rNode, const SwTOXMark& rAt else sText = rAttr.GetAlternativeText(); - switch ( rAttr.GetTOXType()->GetType() ) + OUString sUserTypeName; + auto aType = rAttr.GetTOXType()->GetType(); + // user index mark, it needs XE with \f + if ( TOX_USER == aType ) + { + sUserTypeName = rAttr.GetTOXType()->GetTypeName(); + if ( !sUserTypeName.isEmpty() ) + aType = TOX_INDEX; + } + + switch ( aType ) { case TOX_INDEX: eType = ww::eXE; @@ -1305,6 +1315,11 @@ void AttributeOutputBase::TOXMark( const SwTextNode& rNode, const SwTOXMark& rAt sText = rAttr.GetPrimaryKey() + ":" + sText; } sText = " XE \"" + sText + "\" "; + + if (!sUserTypeName.isEmpty()) + { + sText += "\\f \"" + sUserTypeName + "\" "; + } break; case TOX_USER: diff --git a/sw/source/filter/ww8/ww8atr.cxx b/sw/source/filter/ww8/ww8atr.cxx index 3361e58c5bbc..743fffbd62a5 100644 --- a/sw/source/filter/ww8/ww8atr.cxx +++ b/sw/source/filter/ww8/ww8atr.cxx @@ -2224,7 +2224,16 @@ void AttributeOutputBase::StartTOX( const SwSection& rSect ) OUString sStr = pTOX ->GetMSTOCExpression(); if ( sStr.isEmpty() ) { - switch (pTOX->GetType()) + OUString sUserTypeName; + auto aType = pTOX->GetType(); + // user index, it needs INDEX with \f + if ( TOX_USER == aType ) + { + sUserTypeName = pTOX->GetTOXType()->GetTypeName(); + if ( !sUserTypeName.isEmpty() ) + aType = TOX_INDEX; + } + switch (aType) { case TOX_INDEX: eCode = ww::eINDEX; @@ -2256,14 +2265,9 @@ void AttributeOutputBase::StartTOX( const SwSection& rSect ) if (SwTOIOptions::AlphaDelimiter & pTOX->GetOptions()) sStr += "\\h \"A\" "; - if(SwTOXElement::IndexEntryType & pTOX->GetCreateType()) + if (!sUserTypeName.isEmpty()) { - sStr += "\\f "; - const OUString& sName = pTOX->GetEntryTypeName(); - if(!sName.isEmpty()) - { - sStr += sName + sEntryEnd; - } + sStr += "\\f \"" + sUserTypeName + "\""; } if (!pTOX->GetTOXForm().IsCommaSeparated()) diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx index 6202d7b92790..46bf027d293a 100644 --- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx +++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx @@ -4095,6 +4095,12 @@ static bool lcl_FindInCommand( return bRet; } +static OUString lcl_trim(OUString& sValue) +{ + // it seems, all kind of quotation marks are allowed around index type identifiers + // TODO apply this on bookmarks, too, if needed + return sValue.trim().replaceAll("\"","").replaceAll(u"“", "").replaceAll(u"”", ""); +} void DomainMapper_Impl::GetCurrentLocale(lang::Locale& rLocale) { @@ -5559,15 +5565,21 @@ void DomainMapper_Impl::handleIndex (const FieldContextPtr& pContext, const OUString & sTOCServiceName) { + // only UserIndex can handle user index defined by \f + // e.g. INDEX \f "user-index-id" + OUString sUserIndex; + if ( lcl_FindInCommand( pContext->GetCommand(), 'f', sUserIndex ) ) + sUserIndex = lcl_trim(sUserIndex); + // Create section before setting m_bStartTOC and m_bStartIndex: finishing paragraph // inside StartIndexSectionChecked could do the wrong thing otherwise - const auto xTOC = StartIndexSectionChecked(sTOCServiceName); + const auto xTOC = StartIndexSectionChecked( sUserIndex.isEmpty() + ? sTOCServiceName + : "com.sun.star.text.UserIndex"); m_bStartTOC = true; m_bStartIndex = true; OUString sValue; - OUString sIndexEntryType = "I"; // Default value for field flag '\f' is 'I'. - if (xTOC.is()) { xTOC->setPropertyValue(getPropertyName( PROP_TITLE ), uno::makeAny(OUString())); @@ -5580,11 +5592,9 @@ void DomainMapper_Impl::handleIndex { xTOC->setPropertyValue("UseAlphabeticalSeparators", uno::makeAny(true)); } - if( lcl_FindInCommand( pContext->GetCommand(), 'f', sValue )) + if( !sUserIndex.isEmpty() ) { - if(!sValue.isEmpty()) - sIndexEntryType = sValue ; - xTOC->setPropertyValue(getPropertyName( PROP_INDEX_ENTRY_TYPE ), uno::makeAny(sIndexEntryType)); + xTOC->setPropertyValue("UserIndexName", uno::makeAny(sUserIndex)); } } pContext->SetTOC( xTOC ); @@ -6355,15 +6365,31 @@ void DomainMapper_Impl::CloseFieldCommand() if( !m_xTextFactory.is() ) break; + // only UserIndexMark can handle user index types defined by \f + // e.g. XE "text" \f "user-index-id" + OUString sUserIndex; + OUString sFieldServiceName = + lcl_FindInCommand( pContext->GetCommand(), 'f', sUserIndex ) + ? "com.sun.star.text.UserIndexMark" + : OUString::createFromAscii(aIt->second.cFieldServiceName); uno::Reference< beans::XPropertySet > xTC( - m_xTextFactory->createInstance( - OUString::createFromAscii(aIt->second.cFieldServiceName)), + m_xTextFactory->createInstance(sFieldServiceName), uno::UNO_QUERY_THROW); + if (!sFirstParam.isEmpty()) { - xTC->setPropertyValue("PrimaryKey", + xTC->setPropertyValue(sUserIndex.isEmpty() + ? OUString("PrimaryKey") + : OUString("AlternativeText"), uno::makeAny(sFirstParam)); } + + sUserIndex = lcl_trim(sUserIndex); + if (!sUserIndex.isEmpty()) + { + xTC->setPropertyValue("UserIndexName", + uno::makeAny(sUserIndex)); + } uno::Reference< text::XTextContent > xToInsert( xTC, uno::UNO_QUERY ); uno::Reference< text::XTextAppend > xTextAppend = m_aTextAppendStack.top().xTextAppend; if (xTextAppend.is()) diff --git a/writerfilter/source/dmapper/PropertyIds.cxx b/writerfilter/source/dmapper/PropertyIds.cxx index ebf6e9b7dcf5..02db201e7b82 100644 --- a/writerfilter/source/dmapper/PropertyIds.cxx +++ b/writerfilter/source/dmapper/PropertyIds.cxx @@ -330,7 +330,6 @@ OUString getPropertyName( PropertyIds eId ) case PROP_CHAR_STYLISTICSETS_TEXT_EFFECT : sName = "CharStylisticSetsTextEffect"; break; case PROP_CHAR_CNTXTALTS_TEXT_EFFECT : sName = "CharCntxtAltsTextEffect"; break; case PROP_SDTPR : sName = "SdtPr"; break; - case PROP_INDEX_ENTRY_TYPE : sName = "IndexEntryType"; break; case PROP_CELL_INTEROP_GRAB_BAG : sName = "CellInteropGrabBag"; break; case PROP_TABLE_INTEROP_GRAB_BAG : sName = "TableInteropGrabBag"; break; case PROP_APPLY_PARAGRAPH_MARK_FORMAT_TO_NUMBERING : sName = "ApplyParagraphMarkFormatToNumbering"; break; diff --git a/writerfilter/source/dmapper/PropertyIds.hxx b/writerfilter/source/dmapper/PropertyIds.hxx index cbadf04056e3..86b11bb250e2 100644 --- a/writerfilter/source/dmapper/PropertyIds.hxx +++ b/writerfilter/source/dmapper/PropertyIds.hxx @@ -333,7 +333,6 @@ enum PropertyIds ,PROP_SDTPR ,PROP_CELL_INTEROP_GRAB_BAG ,PROP_TABLE_INTEROP_GRAB_BAG - ,PROP_INDEX_ENTRY_TYPE ,PROP_APPLY_PARAGRAPH_MARK_FORMAT_TO_NUMBERING ,PROP_SDT_END_BEFORE ,PROP_PARA_SDT_END_BEFORE