dictionaries | 2 sw/qa/extras/ooxmlexport/data/tdf152425.docx |binary sw/qa/extras/ooxmlexport/ooxmlexport13.cxx | 8 sw/qa/extras/ooxmlexport/ooxmlexport16.cxx | 2 sw/qa/extras/ooxmlexport/ooxmlexport18.cxx | 14 + sw/source/filter/inc/wwstyles.hxx | 1 sw/source/filter/ww8/docxattributeoutput.cxx | 16 - sw/source/filter/ww8/styles.cxx | 186 +++++++++---------- sw/source/filter/ww8/wrtw8sty.cxx | 149 ++++++++------- sw/source/filter/ww8/wrtww8.hxx | 10 - writerfilter/source/dmapper/StyleSheetTable.cxx | 232 +++++++++++++----------- 11 files changed, 340 insertions(+), 280 deletions(-)
New commits: commit 7f0b6db955ee52f4216416566e108245f2b3a821 Author: Shulhan <m...@kilabit.info> AuthorDate: Thu Jan 12 11:34:31 2023 +0700 Commit: Gerrit Code Review <ger...@gerrit.libreoffice.org> CommitDate: Thu Jan 12 04:34:31 2023 +0000 Update git submodules * Update dictionaries from branch 'master' to 40580c5dbb5b06fbf402b5864e736527b05cd2f5 - id: sync dictionaries to version v2.3.0 (2022.09.21) In the dictionary file we add 15773 new root words, sort them out to simplify search and update in the future. In the affix file we fix some format for Lucene. The README updated to match with upstream [1]. [1] https://github.com/shuLhan/hunspell-id Change-Id: Ie96776aba2399b90cfbc113782c720a157458bc3 Reviewed-on: https://gerrit.libreoffice.org/c/dictionaries/+/140263 Tested-by: Aron Budea <aron.bu...@collabora.com> Reviewed-by: Aron Budea <aron.bu...@collabora.com> diff --git a/dictionaries b/dictionaries index f191df059976..40580c5dbb5b 160000 --- a/dictionaries +++ b/dictionaries @@ -1 +1 @@ -Subproject commit f191df059976deba5f60983bb4a87ab184835fd4 +Subproject commit 40580c5dbb5b06fbf402b5864e736527b05cd2f5 commit 13d30067370353ae5a43c2f2cbd69bb824363815 Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Wed Jan 11 17:02:04 2023 +0300 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Thu Jan 12 04:34:27 2023 +0000 tdf#152425 Synchronize import and export style names mapping 1. Make the mapping in StyleSheetTable::ConvertStyleName match the opposite direction mapping happening in MSWordStyles::GetWWId and ww::GetEnglishNameFromSti. Add missing styles, provide comments to clarify the process and find respective pool format ids. 2. Instead of appending " (user)" to conflicting style names, which is the method used by SwStyleNameMapper to disambiguate API names, append " (WW)", which allows to avoid unwanted merging conflicting styles. Change-Id: I47b1c7f570da6e6e21155669fdd1b77de5cc17da Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145349 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport18.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport18.cxx index 92e13b4b7d3b..7b7213e0f019 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport18.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport18.cxx @@ -264,17 +264,12 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf152425) // Check that "List Number" and "List 5" styles don't get merged const OUString Para3Style = getProperty<OUString>(getParagraph(3), "ParaStyleName"); - CPPUNIT_ASSERT_EQUAL(OUString("List Number"), Para3Style); + CPPUNIT_ASSERT_EQUAL(OUString("Numbering 1"), Para3Style); const OUString Para4Style = getProperty<OUString>(getParagraph(4), "ParaStyleName"); - // Eventually, we need to check this: - // CPPUNIT_ASSERT_EQUAL(OUString("List 5"), Para4Style); - // But for now, just make sure that the style names differ - CPPUNIT_ASSERT(Para4Style != Para3Style); + CPPUNIT_ASSERT_EQUAL(OUString("List 5 (WW)"), Para4Style); + // Also check that "List 5" and "List Bullet 5" styles don't get merged const OUString Para5Style = getProperty<OUString>(getParagraph(5), "ParaStyleName"); - // Eventually, we need to check this: - // CPPUNIT_ASSERT_EQUAL(OUString("List Bullet 5"), Para5Style); - // But for now, just make sure that the style names differ - CPPUNIT_ASSERT(Para5Style != Para4Style); + CPPUNIT_ASSERT_EQUAL(OUString("List 5"), Para5Style); } CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/source/filter/ww8/styles.cxx b/sw/source/filter/ww8/styles.cxx index c7a28e77e60b..33d0ad3dec5f 100644 --- a/sw/source/filter/ww8/styles.cxx +++ b/sw/source/filter/ww8/styles.cxx @@ -23,6 +23,7 @@ namespace { + // Keep in sync with StyleSheetTable::ConvertStyleName const char **GetStiNames() noexcept { // Matches enum ww::sti in sw/source/filter/inc/wwstyles.hxx diff --git a/sw/source/filter/ww8/wrtw8sty.cxx b/sw/source/filter/ww8/wrtw8sty.cxx index 9f534b1b55d2..72fca1b3696f 100644 --- a/sw/source/filter/ww8/wrtw8sty.cxx +++ b/sw/source/filter/ww8/wrtw8sty.cxx @@ -200,6 +200,7 @@ static sal_uInt16 BuildGetSlot(const SwFormat& rFormat) } +// Keep in sync with StyleSheetTable::ConvertStyleName sal_uInt16 MSWordStyles::GetWWId( const SwFormat& rFormat ) { sal_uInt16 nRet = ww::stiUser; // user style as default @@ -319,6 +320,14 @@ void MSWordStyles::BuildStylesTable() } } +// StyleSheetTable::ConvertStyleName appends the suffix do disambiguate conflicting style names +static OUString StripWWSuffix(const OUString& s) +{ + OUString ret = s; + ret.endsWith(" (WW)", &ret); + return ret; +} + void MSWordStyles::BuildWwNames() { std::unordered_set<OUString> aUsed; @@ -363,9 +372,9 @@ void MSWordStyles::BuildWwNames() if (!entry.ww_name.isEmpty()) continue; if (entry.format) - entry.ww_name = entry.format->GetName(); + entry.ww_name = StripWWSuffix(entry.format->GetName()); else if (entry.num_rule) - entry.ww_name = entry.num_rule->GetName(); + entry.ww_name = StripWWSuffix(entry.num_rule->GetName()); else continue; makeUniqueName(entry.ww_name); diff --git a/writerfilter/source/dmapper/StyleSheetTable.cxx b/writerfilter/source/dmapper/StyleSheetTable.cxx index 9641a2a032bd..963ff9c907b6 100644 --- a/writerfilter/source/dmapper/StyleSheetTable.cxx +++ b/writerfilter/source/dmapper/StyleSheetTable.cxx @@ -1420,129 +1420,141 @@ OUString StyleSheetTable::ConvertStyleName( const OUString& rWWName, bool bExten //search for the rWWName in the IdentifierD of the existing styles and convert the sStyleName member auto findIt = m_pImpl->m_aStyleSheetEntriesMap.find(rWWName); if (findIt != m_pImpl->m_aStyleSheetEntriesMap.end()) + { + if (!findIt->second->sConvertedStyleName.isEmpty()) + return findIt->second->sConvertedStyleName; sRet = findIt->second->sStyleName; + } } // create a map only once + // This maps Word's special style manes to Writer's (the opposite to what MSWordStyles::GetWWId + // and ww::GetEnglishNameFromSti do on export). The mapping gives a Writer's style name, which + // will point to a style with specific RES_POOL* in its m_nPoolFormatId. Then on export, the + // pool format id will map to a ww::sti enum value, and finally to a Word style name. Keep this + // part in sync with the export functions mentioned above! + // In addition to "standard" names, some case variations are handled here; and also there are + // a number of strange mappings like "BodyTextIndentItalic" -> "Text body indent italic", which + // map something unused in Word to something unused in Writer :-/ static const std::map< OUString, OUString> StyleNameMap { - { "Normal", "Standard" }, - { "heading 1", "Heading 1" }, - { "heading 2", "Heading 2" }, - { "heading 3", "Heading 3" }, - { "heading 4", "Heading 4" }, - { "heading 5", "Heading 5" }, - { "heading 6", "Heading 6" }, - { "heading 7", "Heading 7" }, - { "heading 8", "Heading 8" }, - { "heading 9", "Heading 9" }, - { "Heading 1", "Heading 1" }, - { "Heading 2", "Heading 2" }, - { "Heading 3", "Heading 3" }, - { "Heading 4", "Heading 4" }, - { "Heading 5", "Heading 5" }, - { "Heading 6", "Heading 6" }, - { "Heading 7", "Heading 7" }, - { "Heading 8", "Heading 8" }, - { "Heading 9", "Heading 9" }, - { "Index 1", "Index 1" }, - { "Index 2", "Index 2" }, - { "Index 3", "Index 3" }, + { "Normal", "Standard" }, // RES_POOLCOLL_STANDARD + { "heading 1", "Heading 1" }, // RES_POOLCOLL_HEADLINE1 + { "heading 2", "Heading 2" }, // RES_POOLCOLL_HEADLINE2 + { "heading 3", "Heading 3" }, // RES_POOLCOLL_HEADLINE3 + { "heading 4", "Heading 4" }, // RES_POOLCOLL_HEADLINE4 + { "heading 5", "Heading 5" }, // RES_POOLCOLL_HEADLINE5 + { "heading 6", "Heading 6" }, // RES_POOLCOLL_HEADLINE6 + { "heading 7", "Heading 7" }, // RES_POOLCOLL_HEADLINE7 + { "heading 8", "Heading 8" }, // RES_POOLCOLL_HEADLINE8 + { "heading 9", "Heading 9" }, // RES_POOLCOLL_HEADLINE9 + { "Heading 1", "Heading 1" }, // RES_POOLCOLL_HEADLINE1 + { "Heading 2", "Heading 2" }, // RES_POOLCOLL_HEADLINE2 + { "Heading 3", "Heading 3" }, // RES_POOLCOLL_HEADLINE3 + { "Heading 4", "Heading 4" }, // RES_POOLCOLL_HEADLINE4 + { "Heading 5", "Heading 5" }, // RES_POOLCOLL_HEADLINE5 + { "Heading 6", "Heading 6" }, // RES_POOLCOLL_HEADLINE6 + { "Heading 7", "Heading 7" }, // RES_POOLCOLL_HEADLINE7 + { "Heading 8", "Heading 8" }, // RES_POOLCOLL_HEADLINE8 + { "Heading 9", "Heading 9" }, // RES_POOLCOLL_HEADLINE9 + { "Index 1", "Index 1" }, // RES_POOLCOLL_TOX_IDX1 + { "Index 2", "Index 2" }, // RES_POOLCOLL_TOX_IDX2 + { "Index 3", "Index 3" }, // RES_POOLCOLL_TOX_IDX3 // { "Index 4", "" }, // { "Index 5", "" }, // { "Index 6", "" }, // { "Index 7", "" }, // { "Index 8", "" }, // { "Index 9", "" }, - { "TOC 1", "Contents 1" }, - { "TOC 2", "Contents 2" }, - { "TOC 3", "Contents 3" }, - { "TOC 4", "Contents 4" }, - { "TOC 5", "Contents 5" }, - { "TOC 6", "Contents 6" }, - { "TOC 7", "Contents 7" }, - { "TOC 8", "Contents 8" }, - { "TOC 9", "Contents 9" }, - { "TOC Heading", "Contents Heading" }, - { "TOCHeading", "Contents Heading" }, - { "toc 1", "Contents 1" }, - { "toc 2", "Contents 2" }, - { "toc 3", "Contents 3" }, - { "toc 4", "Contents 4" }, - { "toc 5", "Contents 5" }, - { "toc 6", "Contents 6" }, - { "toc 7", "Contents 7" }, - { "toc 8", "Contents 8" }, - { "toc 9", "Contents 9" }, - { "TOC1", "Contents 1" }, - { "TOC2", "Contents 2" }, - { "TOC3", "Contents 3" }, - { "TOC4", "Contents 4" }, - { "TOC5", "Contents 5" }, - { "TOC6", "Contents 6" }, - { "TOC7", "Contents 7" }, - { "TOC8", "Contents 8" }, - { "TOC9", "Contents 9" }, + { "TOC 1", "Contents 1" }, // RES_POOLCOLL_TOX_CNTNT1 + { "TOC 2", "Contents 2" }, // RES_POOLCOLL_TOX_CNTNT2 + { "TOC 3", "Contents 3" }, // RES_POOLCOLL_TOX_CNTNT3 + { "TOC 4", "Contents 4" }, // RES_POOLCOLL_TOX_CNTNT4 + { "TOC 5", "Contents 5" }, // RES_POOLCOLL_TOX_CNTNT5 + { "TOC 6", "Contents 6" }, // RES_POOLCOLL_TOX_CNTNT6 + { "TOC 7", "Contents 7" }, // RES_POOLCOLL_TOX_CNTNT7 + { "TOC 8", "Contents 8" }, // RES_POOLCOLL_TOX_CNTNT8 + { "TOC 9", "Contents 9" }, // RES_POOLCOLL_TOX_CNTNT9 + { "TOC Heading", "Contents Heading" }, // RES_POOLCOLL_TOX_CNTNTH + { "TOCHeading", "Contents Heading" }, // RES_POOLCOLL_TOX_CNTNTH + { "toc 1", "Contents 1" }, // RES_POOLCOLL_TOX_CNTNT1 + { "toc 2", "Contents 2" }, // RES_POOLCOLL_TOX_CNTNT2 + { "toc 3", "Contents 3" }, // RES_POOLCOLL_TOX_CNTNT3 + { "toc 4", "Contents 4" }, // RES_POOLCOLL_TOX_CNTNT4 + { "toc 5", "Contents 5" }, // RES_POOLCOLL_TOX_CNTNT5 + { "toc 6", "Contents 6" }, // RES_POOLCOLL_TOX_CNTNT6 + { "toc 7", "Contents 7" }, // RES_POOLCOLL_TOX_CNTNT7 + { "toc 8", "Contents 8" }, // RES_POOLCOLL_TOX_CNTNT8 + { "toc 9", "Contents 9" }, // RES_POOLCOLL_TOX_CNTNT9 + { "TOC1", "Contents 1" }, // RES_POOLCOLL_TOX_CNTNT1 + { "TOC2", "Contents 2" }, // RES_POOLCOLL_TOX_CNTNT2 + { "TOC3", "Contents 3" }, // RES_POOLCOLL_TOX_CNTNT3 + { "TOC4", "Contents 4" }, // RES_POOLCOLL_TOX_CNTNT4 + { "TOC5", "Contents 5" }, // RES_POOLCOLL_TOX_CNTNT5 + { "TOC6", "Contents 6" }, // RES_POOLCOLL_TOX_CNTNT6 + { "TOC7", "Contents 7" }, // RES_POOLCOLL_TOX_CNTNT7 + { "TOC8", "Contents 8" }, // RES_POOLCOLL_TOX_CNTNT8 + { "TOC9", "Contents 9" }, // RES_POOLCOLL_TOX_CNTNT9 // { "Normal Indent", "" }, - { "footnote text", "Footnote" }, - { "Footnote Text", "Footnote" }, -// { "Annotation Text", "" }, - { "Header", "Header" }, - { "header", "Header" }, - { "Footer", "Footer" }, - { "footer", "Footer" }, - { "Index Heading", "Index Heading" }, -// { "Caption", "" }, -// { "Table of Figures", "" }, - { "Envelope Address", "Addressee" }, - { "Envelope Return", "Sender" }, - { "footnote reference", "Footnote Symbol" }, - { "Footnote Reference", "Footnote Symbol" }, + { "footnote text", "Footnote" }, // RES_POOLCOLL_FOOTNOTE + { "Footnote Text", "Footnote" }, // RES_POOLCOLL_FOOTNOTE + { "Annotation Text", "Marginalia" }, // RES_POOLCOLL_MARGINAL + { "Header", "Header" }, // RES_POOLCOLL_HEADER + { "header", "Header" }, // RES_POOLCOLL_HEADER + { "Footer", "Footer" }, // RES_POOLCOLL_FOOTER + { "footer", "Footer" }, // RES_POOLCOLL_FOOTER + { "Index Heading", "Index Heading" }, // RES_POOLCOLL_TOX_IDXH + { "Caption", "Caption" }, // RES_POOLCOLL_LABEL + { "Table of Figures", "Drawing" }, // RES_POOLCOLL_LABEL_DRAWING + { "Envelope Address", "Addressee" }, // RES_POOLCOLL_ENVELOPE_ADDRESS + { "Envelope Return", "Sender" }, // RES_POOLCOLL_SEND_ADDRESS + { "footnote reference", "Footnote Symbol" }, // RES_POOLCHR_FOOTNOTE; tdf#82173 + { "Footnote Reference", "Footnote Symbol" }, // RES_POOLCHR_FOOTNOTE; tdf#82173 // { "Annotation Reference", "" }, - { "Line Number", "Line numbering" }, - { "Page Number", "Page Number" }, - { "endnote reference", "Endnote Symbol" }, - { "Endnote Reference", "Endnote Symbol" }, - { "endnote text", "Endnote" }, - { "Endnote Text", "Endnote" }, -// { "Table of Authorities", "" }, + { "Line Number", "Line numbering" }, // RES_POOLCHR_LINENUM + { "Page Number", "Page Number" }, // RES_POOLCHR_PAGENO + { "endnote reference", "Endnote Symbol" }, // RES_POOLCHR_ENDNOTE; tdf#82173 + { "Endnote Reference", "Endnote Symbol" }, // RES_POOLCHR_ENDNOTE; tdf#82173 + { "endnote text", "Endnote" }, // RES_POOLCOLL_ENDNOTE + { "Endnote Text", "Endnote" }, // RES_POOLCOLL_ENDNOTE + { "Table of Authorities", "Bibliography Heading" }, // RES_POOLCOLL_TOX_AUTHORITIESH // { "Macro Text", "" }, // { "TOA Heading", "" }, - { "List", "List" }, + { "List", "List" }, // RES_POOLCOLL_NUMBER_BULLET_BASE // { "List 2", "" }, // { "List 3", "" }, // { "List 4", "" }, // { "List 5", "" }, -// { "List Bullet", "" }, -// { "List Bullet 2", "" }, -// { "List Bullet 3", "" }, -// { "List Bullet 4", "" }, -// { "List Bullet 5", "" }, -// { "List Number", "" }, -// { "List Number 2", "" }, -// { "List Number 3", "" }, -// { "List Number 4", "" }, -// { "List Number 5", "" }, - { "Title", "Title" }, -// { "Closing", "" }, - { "Signature", "Signature" }, + { "List Bullet", "List 1" }, // RES_POOLCOLL_BULLET_LEVEL1 + { "List Bullet 2", "List 2" }, // RES_POOLCOLL_BULLET_LEVEL2 + { "List Bullet 3", "List 3" }, // RES_POOLCOLL_BULLET_LEVEL3 + { "List Bullet 4", "List 4" }, // RES_POOLCOLL_BULLET_LEVEL4 + { "List Bullet 5", "List 5" }, // RES_POOLCOLL_BULLET_LEVEL5 + { "List Number", "Numbering 1" }, // RES_POOLCOLL_NUM_LEVEL1 + { "List Number 2", "Numbering 2" }, // RES_POOLCOLL_NUM_LEVEL2 + { "List Number 3", "Numbering 3" }, // RES_POOLCOLL_NUM_LEVEL3 + { "List Number 4", "Numbering 4" }, // RES_POOLCOLL_NUM_LEVEL4 + { "List Number 5", "Numbering 5" }, // RES_POOLCOLL_NUM_LEVEL5 + { "Title", "Title" }, // RES_POOLCOLL_DOC_TITLE + { "Closing", "Appendix" }, // RES_POOLCOLL_DOC_APPENDIX + { "Signature", "Signature" }, // RES_POOLCOLL_SIGNATURE // { "Default Paragraph Font", "" }, { "DefaultParagraphFont", "Default Paragraph Font" }, - { "Body Text", "Text body" }, - { "BodyText", "Text body" }, + { "Body Text", "Text body" }, // RES_POOLCOLL_TEXT + { "BodyText", "Text body" }, // RES_POOLCOLL_TEXT { "BodyTextIndentItalic", "Text body indent italic" }, - { "Body Text Indent", "Text body indent" }, - { "BodyTextIndent", "Text body indent" }, + { "Body Text Indent", "Text body indent" }, // RES_POOLCOLL_TEXT_MOVE + { "BodyTextIndent", "Text body indent" }, // RES_POOLCOLL_TEXT_MOVE { "BodyTextIndent2", "Text body indent2" }, -// { "List Continue", "" }, -// { "List Continue 2", "" }, -// { "List Continue 3", "" }, -// { "List Continue 4", "" }, -// { "List Continue 5", "" }, + { "List Continue", "List 1 Cont." }, // RES_POOLCOLL_BULLET_NONUM1 + { "List Continue 2", "List 2 Cont." }, // RES_POOLCOLL_BULLET_NONUM2 + { "List Continue 3", "List 3 Cont." }, // RES_POOLCOLL_BULLET_NONUM3 + { "List Continue 4", "List 4 Cont." }, // RES_POOLCOLL_BULLET_NONUM4 + { "List Continue 5", "List 5 Cont." }, // RES_POOLCOLL_BULLET_NONUM5 // { "Message Header", "" }, - { "Subtitle", "Subtitle" }, -// { "Salutation", "" }, + { "Subtitle", "Subtitle" }, // RES_POOLCOLL_DOC_SUBTITLE + { "Salutation", "Salutation" }, // RES_POOLCOLL_GREETING // { "Date", "" }, - { "Body Text First Indent", "Body Text Indent" }, + { "Body Text First Indent", "First line indent" }, // RES_POOLCOLL_TEXT_IDENT // { "Body Text First Indent 2", "" }, // { "Note Heading", "" }, // { "Body Text 2", "" }, @@ -1550,15 +1562,16 @@ OUString StyleSheetTable::ConvertStyleName( const OUString& rWWName, bool bExten // { "Body Text Indent 2", "" }, // { "Body Text Indent 3", "" }, // { "Block Text", "" }, - { "Hyperlink", "Internet link" }, - { "FollowedHyperlink", "Visited Internet Link" }, - { "Emphasis", "Emphasis" }, + { "Hyperlink", "Internet link" }, // RES_POOLCHR_INET_NORMAL + { "FollowedHyperlink", "Visited Internet Link" }, // RES_POOLCHR_INET_VISIT + { "Strong", "Strong Emphasis" }, // RES_POOLCHR_HTML_STRONG + { "Emphasis", "Emphasis" }, // RES_POOLCHR_HTML_EMPHASIS // { "Document Map", "" }, // { "Plain Text", "" }, { "NoList", "No List" }, { "AbstractHeading", "Abstract Heading" }, { "AbstractBody", "Abstract Body" }, - { "PageNumber", "page number" }, + { "PageNumber", "Page Number" }, // RES_POOLCHR_PAGENO { "TableNormal", "Normal Table" }, { "DocumentMap", "Document Map" }, }; @@ -1577,10 +1590,17 @@ OUString StyleSheetTable::ConvertStyleName( const OUString& rWWName, bool bExten set.insert(pair.second); return set; }(); - // SwStyleNameMapper doc says: If the UI style name equals a - // programmatic name, then it must append " (user)" to the end. - if (ReservedStyleNames.find(sRet) != ReservedStyleNames.end()) - sRet += " (user)"; + // Similar to SwStyleNameMapper convention (where a " (user)" suffix is used to + // disambiguate user styles with reserved names in localization where respective + // built-in styles have different UI names), we add a " (WW)" suffix here. Unlike + // the " (user)" suffix, it is not hidden from the UI; it will be handled when + // exported to Word formats - see MSWordStyles::BuildWwNames. + // We can't use the " (user)" suffix, because that system is built upon the assumption + // that UI names of respective built-in styles are different from the user style name. + // That is not necessarily true here, since the current localization may not change + // the UI names of built-in styles. + if (ReservedStyleNames.find(sRet) != ReservedStyleNames.end() || sRet.endsWith(" (WW)")) + sRet += " (WW)"; } return sRet; commit 319e2e0cbc6a1d25abd01fb27d6250cee825c072 Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Sat Dec 10 08:58:10 2022 +0300 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Thu Jan 12 04:34:22 2023 +0000 tdf#152425 Make Word names unique, and use them for style ids generation Before, a style id was generated from LibreOffice name, and then the name was replaced with Word name. Given that Writer's List N maps to Word's List Bullet N, and Word's List N doesn't map to anything in Writer, this led to styles.xml having after roundtrip: <w:style w:type="paragraph" w:styleId="List5"> <w:name w:val="List Bullet 5"/> ... <w:style w:type="paragraph" w:styleId="ListBullet5"> <w:name w:val="List Bullet 5"/> So the idea is to do the following steps: 1. Collect all the exported styles (unchanged); 2. Build unique Word names for collected styles (new): a. Process all the styles that map to special Word styles first, so that their Word names don't get changed when made unique; b. Process the rest of the styles, making sure to append a sequential number after the Writer name, if a clash happens. 3. Build Style Ids from the Word names (previously Writer name could be used), also making sure they are unique. Change-Id: I9f8f254aa6ae713671234f0109b94cc72a588150 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/143905 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport13.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport13.cxx index f42b5e7f9a28..a1610c35dbbb 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport13.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport13.cxx @@ -1228,8 +1228,8 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf123628) xmlDocUniquePtr pXmlStyles = parseExport("word/styles.xml"); - assertXPath(pXmlDoc, "/w:document/w:body/w:p[1]/w:hyperlink/w:r/w:rPr/w:rStyle", "val", "InternetLink"); - assertXPath(pXmlStyles, "/w:styles/w:style[@w:styleId='InternetLink']/w:name", "val", "Hyperlink"); + assertXPath(pXmlDoc, "/w:document/w:body/w:p[1]/w:hyperlink/w:r/w:rPr/w:rStyle", "val", "Hyperlink"); + assertXPath(pXmlStyles, "/w:styles/w:style[@w:styleId='Hyperlink']/w:name", "val", "Hyperlink"); } DECLARE_OOXMLEXPORT_TEST(testTdf127741, "tdf127741.docx") @@ -1255,7 +1255,7 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf127925) loadAndSave("tdf127925.odt"); CPPUNIT_ASSERT_EQUAL(1, getPages()); xmlDocUniquePtr pXmlStyles = parseExport("word/styles.xml"); - assertXPath(pXmlStyles, "/w:styles/w:style[@w:styleId='VisitedInternetLink']/w:name", "val", "FollowedHyperlink"); + assertXPath(pXmlStyles, "/w:styles/w:style[@w:styleId='FollowedHyperlink']/w:name", "val", "FollowedHyperlink"); } CPPUNIT_TEST_FIXTURE(Test, testTdf127579) @@ -1263,7 +1263,7 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf127579) loadAndSave("tdf127579.odt"); CPPUNIT_ASSERT_EQUAL(1, getPages()); xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml"); - assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:hyperlink/w:r/w:rPr/w:rStyle", "val", "InternetLink"); + assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:hyperlink/w:r/w:rPr/w:rStyle", "val", "Hyperlink"); } CPPUNIT_TEST_FIXTURE(Test, testTdf128304) diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx index f5230adb643a..4c27a18101fd 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx @@ -1013,7 +1013,7 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf143726) CPPUNIT_ASSERT(pXmlStyles); // Without the fix this was "TOA Heading" which belongs to the "Table of Authorities" index in Word // TOC's heading style should be exported as "TOC Heading" as that's the default Word style name - assertXPath(pXmlStyles, "/w:styles/w:style[@w:styleId='ContentsHeading']/w:name", "val", "TOC Heading"); + assertXPath(pXmlStyles, "/w:styles/w:style[@w:styleId='TOCHeading']/w:name", "val", "TOC Heading"); } CPPUNIT_TEST_FIXTURE(Test, testTdf152153) diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport18.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport18.cxx index c9d7528f6297..92e13b4b7d3b 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport18.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport18.cxx @@ -270,6 +270,11 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf152425) // CPPUNIT_ASSERT_EQUAL(OUString("List 5"), Para4Style); // But for now, just make sure that the style names differ CPPUNIT_ASSERT(Para4Style != Para3Style); + const OUString Para5Style = getProperty<OUString>(getParagraph(5), "ParaStyleName"); + // Eventually, we need to check this: + // CPPUNIT_ASSERT_EQUAL(OUString("List Bullet 5"), Para5Style); + // But for now, just make sure that the style names differ + CPPUNIT_ASSERT(Para5Style != Para4Style); } CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx index 7b6f8126afe1..db4299d582b3 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -3874,7 +3874,12 @@ void DocxAttributeOutput::Redline( const SwRedlineData* pRedlineData) m_pSerializer->startElementNS(XML_w, XML_pPr); - OString sStyleName = MSWordStyles::CreateStyleId( sParaStyleName ); + OString sStyleName; + if (auto format = m_rExport.m_rDoc.FindTextFormatCollByName(sParaStyleName)) + if (auto slot = m_rExport.m_pStyles->GetSlot(format); slot != 0xfff) + sStyleName = m_rExport.m_pStyles->GetStyleId(slot); + if (sStyleName.isEmpty()) + sStyleName = MSWordStyles::CreateStyleId(sParaStyleName); if ( !sStyleName.isEmpty() ) m_pSerializer->singleElementNS(XML_w, XML_pStyle, FSNS(XML_w, XML_val), sStyleName); @@ -7164,20 +7169,14 @@ void DocxAttributeOutput::StartStyle( const OUString& rName, StyleType eType, SAL_WARN("sw.ww8", "Unhandled style property: " << rProp.Name); } - // MSO exports English names and writerfilter only recognize them. - const char *pEnglishName = nullptr; const char* pType = nullptr; switch (eType) { case STYLE_TYPE_PARA: pType = "paragraph"; - if ( nWwId < ww::stiMax) - pEnglishName = ww::GetEnglishNameFromSti( static_cast<ww::sti>(nWwId ) ); break; case STYLE_TYPE_CHAR: pType = "character"; - if (nWwId < ww::stiMax) - pEnglishName = ww::GetEnglishNameFromSti(static_cast<ww::sti>(nWwId)); break; case STYLE_TYPE_LIST: pType = "numbering"; break; } @@ -7188,8 +7187,7 @@ void DocxAttributeOutput::StartStyle( const OUString& rName, StyleType eType, if (bCustomStyle) pStyleAttributeList->add(FSNS(XML_w, XML_customStyle), "1"); m_pSerializer->startElementNS( XML_w, XML_style, pStyleAttributeList); - m_pSerializer->singleElementNS( XML_w, XML_name, - FSNS( XML_w, XML_val ), pEnglishName ? pEnglishName : rName.toUtf8() ); + m_pSerializer->singleElementNS(XML_w, XML_name, FSNS(XML_w, XML_val), rName); if ( nBase != 0x0FFF && eType != STYLE_TYPE_LIST) { diff --git a/sw/source/filter/ww8/wrtw8sty.cxx b/sw/source/filter/ww8/wrtw8sty.cxx index efd2c230465f..9f534b1b55d2 100644 --- a/sw/source/filter/ww8/wrtw8sty.cxx +++ b/sw/source/filter/ww8/wrtw8sty.cxx @@ -158,6 +158,7 @@ MSWordStyles::MSWordStyles( MSWordExportBase& rExport, bool bListStyles ) memset( m_aHeadingParagraphStyles, -1 , MAXLEVEL * sizeof( sal_uInt16)); BuildStylesTable(); + BuildWwNames(); BuildStyleIds(); } @@ -288,7 +289,7 @@ void MSWordStyles::BuildStylesTable() sal_uInt16 nSlot = BuildGetSlot(*pFormat); if (nSlot != 0xfff) { - m_aStyles[nSlot].format = pFormat; + m_aStyles[nSlot] = { pFormat }; } else { @@ -318,6 +319,59 @@ void MSWordStyles::BuildStylesTable() } } +void MSWordStyles::BuildWwNames() +{ + std::unordered_set<OUString> aUsed; + + auto makeUniqueName = [&aUsed](OUString& name) { + // toAsciiLowerCase rules out e.g. user's "normal"; no problem if there are non-ASCII chars + OUString lower(name.toAsciiLowerCase()); + if (!aUsed.insert(lower).second) + { + int nFree = 1; + while (!aUsed.insert(lower + OUString::number(nFree)).second) + ++nFree; + + name += OUString::number(nFree); + } + }; + + // We want to map LO's default style to Word's "Normal" style. + // Word looks for this specific style name when reading docx files. + // (It must be the English word regardless of language settings) + assert(!m_aStyles.empty()); + assert(!m_aStyles[0].format || m_aStyles[0].ww_id == ww::stiNormal); + m_aStyles[0].ww_name = "Normal"; + aUsed.insert("normal"); + + // 1. Handle styles having special wwIds, and thus pre-defined names + for (auto& entry : m_aStyles) + { + if (!entry.ww_name.isEmpty()) + continue; // "Normal" is already added + if (entry.ww_id >= ww::stiMax) + continue; // Not a format with special name + assert(entry.format); + + entry.ww_name = OUString::createFromAscii(ww::GetEnglishNameFromSti(static_cast<ww::sti>(entry.ww_id))); + makeUniqueName(entry.ww_name); + } + + // 2. Now handle other styles + for (auto& entry : m_aStyles) + { + if (!entry.ww_name.isEmpty()) + continue; + if (entry.format) + entry.ww_name = entry.format->GetName(); + else if (entry.num_rule) + entry.ww_name = entry.num_rule->GetName(); + else + continue; + makeUniqueName(entry.ww_name); + } +} + OString MSWordStyles::CreateStyleId(std::u16string_view aName) { OStringBuffer aStyleIdBuf(aName.size()); @@ -340,23 +394,9 @@ void MSWordStyles::BuildStyleIds() { std::unordered_set<OString> aUsed; - assert(!m_aStyles.empty()); - m_aStyles[0].style_id = "Normal"; - aUsed.insert("normal"); - for (auto& entry : m_aStyles) { - if (!entry.style_id.isEmpty()) - continue; // "Normal" is already added - - assert(entry.style_id.isEmpty()); - OUString name; - if (entry.format) - name = entry.format->GetName(); - else if (entry.num_rule) - name = entry.num_rule->GetName(); - - OString aStyleId = CreateStyleId(name); + OString aStyleId = CreateStyleId(entry.ww_name); if (aStyleId.isEmpty()) aStyleId = "Style"; @@ -589,68 +629,45 @@ void WW8AttributeOutput::DefaultStyle() m_rWW8Export.m_pTableStrm->WriteUInt16(0); // empty Style } -void MSWordStyles::OutputStyle(const SwNumRule* pNumRule, sal_uInt16 nSlot) +void MSWordStyles::OutputStyle(sal_uInt16 nSlot) { - m_rExport.AttrOutput().StartStyle( pNumRule->GetName(), STYLE_TYPE_LIST, + const auto& entry = m_aStyles[nSlot]; + + if (entry.num_rule) + { + m_rExport.AttrOutput().StartStyle( entry.ww_name, STYLE_TYPE_LIST, /*nBase =*/ 0, /*nWwNext =*/ 0, /*nWwLink =*/ 0, /*nWWId =*/ 0, nSlot, /*bAutoUpdateFormat =*/ false ); - m_rExport.AttrOutput().EndStyle(); -} - -// OutputStyle applies for TextFormatColls and CharFormats -void MSWordStyles::OutputStyle( const SwFormat* pFormat, sal_uInt16 nSlot) -{ - if ( !pFormat ) + m_rExport.AttrOutput().EndStyle(); + } + else if (!entry.format) + { m_rExport.AttrOutput().DefaultStyle(); + } else { bool bFormatColl; sal_uInt16 nBase, nWwNext; sal_uInt16 nWwLink = 0x0FFF; - GetStyleData(pFormat, bFormatColl, nBase, nWwNext, nWwLink); + GetStyleData(entry.format, bFormatColl, nBase, nWwNext, nWwLink); - OUString aName = pFormat->GetName(); - // We want to map LO's default style to Word's "Normal" style. - // Word looks for this specific style name when reading docx files. - // (It must be the English word regardless of language settings) - if (nSlot == 0) - { - assert( pFormat->GetPoolFormatId() == RES_POOLCOLL_STANDARD ); - aName = "Normal"; - } - else if (aName.equalsIgnoreAsciiCase("Normal")) - { - // If LO has a style named "Normal"(!) rename it to something unique - const OUString aBaseName = "LO-" + aName; - aName = aBaseName; - // Check if we still have a clash, in which case we add a suffix - for ( int nSuffix = 0; ; ++nSuffix ) { - if (std::none_of(m_aStyles.begin() + 1, m_aStyles.end(), - [&aName](const auto& entry) { - return entry.format - && entry.format->GetName().equalsIgnoreAsciiCase(aName); - })) - break; // Found a unique name - aName = aBaseName + OUString::number(nSuffix); - } - } - else if (!bFormatColl && m_rExport.GetExportFormat() == MSWordExportBase::DOCX && - m_rExport.m_pStyles->GetStyleId(nSlot).startsWith("ListLabel")) + if (!bFormatColl && m_rExport.GetExportFormat() == MSWordExportBase::DOCX && + entry.style_id.startsWith("ListLabel")) { // tdf#92335 don't export redundant DOCX import style "ListLabel" return; } - m_rExport.AttrOutput().StartStyle( aName, (bFormatColl ? STYLE_TYPE_PARA : STYLE_TYPE_CHAR), - nBase, nWwNext, nWwLink, GetWWId( *pFormat ), nSlot, - pFormat->IsAutoUpdateOnDirectFormat() ); + m_rExport.AttrOutput().StartStyle(entry.ww_name, (bFormatColl ? STYLE_TYPE_PARA : STYLE_TYPE_CHAR), + nBase, nWwNext, nWwLink, m_aStyles[nSlot].ww_id, nSlot, + entry.format->IsAutoUpdateOnDirectFormat() ); if ( bFormatColl ) - WriteProperties( pFormat, true, nSlot, nBase==0xfff ); // UPX.papx + WriteProperties( entry.format, true, nSlot, nBase==0xfff ); // UPX.papx - WriteProperties( pFormat, false, nSlot, bFormatColl && nBase==0xfff ); // UPX.chpx + WriteProperties( entry.format, false, nSlot, bFormatColl && nBase==0xfff ); // UPX.chpx m_rExport.AttrOutput().EndStyle(); } @@ -699,12 +716,7 @@ void MSWordStyles::OutputStylesTable() // Implementing check for all exports DOCX, DOC, RTF assert(m_aStyles.size() <= MSWORD_MAX_STYLES_LIMIT); for (size_t slot = 0; slot < m_aStyles.size(); ++slot) - { - if (m_aStyles[slot].num_rule) - OutputStyle(m_aStyles[slot].num_rule, slot); - else - OutputStyle(m_aStyles[slot].format, slot); - } + OutputStyle(slot); m_rExport.AttrOutput().EndStyles(m_aStyles.size()); diff --git a/sw/source/filter/ww8/wrtww8.hxx b/sw/source/filter/ww8/wrtww8.hxx index 5af10e91fdc3..cf5d0bfa104b 100644 --- a/sw/source/filter/ww8/wrtww8.hxx +++ b/sw/source/filter/ww8/wrtww8.hxx @@ -1587,10 +1587,12 @@ class MSWordStyles const SwFormat* format = nullptr; const SwNumRule* num_rule = nullptr; /// We need to build style id's for DOCX export; ideally we should roundtrip that, but this is good enough. + sal_uInt16 ww_id = ww::stiUser; + OUString ww_name; OString style_id; MapEntry() = default; - MapEntry(const SwFormat* f) : format(f) {} + MapEntry(const SwFormat* f) : format(f) { if (f) ww_id = GetWWId(*f); } MapEntry(const SwNumRule* r) : num_rule(r) {} }; std::vector<MapEntry> m_aStyles; ///< Slot <-> Character/paragraph/list style array. @@ -1599,6 +1601,9 @@ class MSWordStyles /// Create the style table, called from the constructor. void BuildStylesTable(); + /// Generate proper Word names, taking mapping between special types into account + void BuildWwNames(); + /// Based on style names, fill in unique, MS-like names. void BuildStyleIds(); @@ -1613,8 +1618,7 @@ class MSWordStyles void SetStyleDefaults( const SwFormat& rFormat, bool bPap ); /// Outputs one style - called (in a loop) from OutputStylesTable(). - void OutputStyle( const SwFormat* pFormat, sal_uInt16 nSlot ); - void OutputStyle( const SwNumRule* pNumRule, sal_uInt16 nSlot); + void OutputStyle( sal_uInt16 nSlot ); MSWordStyles( const MSWordStyles& ) = delete; MSWordStyles& operator=( const MSWordStyles& ) = delete; commit 4ac0a27c7cb0e8d09e701aaf150414d136e58310 Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Thu Dec 8 19:13:43 2022 +0300 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Thu Jan 12 04:34:14 2023 +0000 tdf#152425 Fix order in stiName array Since their introduction in commit 552d05f57175ecdd0736dc257319bc30aa88d696 (INTEGRATION: CWS portlaoisefilterteam16 (1.1.2); FILE ADDED, 2003-12-09) and commit 9ba054a180fe1fcd410a2887351c2ff1fcb30847 (INTEGRATION: CWS portlaoisefilterteam16 (1.1.2); FILE ADDED, 2003-12-09), the enum sti and GetStiNames were accidentally not matching each other. commit 78284714b73a8307174c596295894e8f3951e09a (tdf#76817: fix missing heading styles assigned to outline levels in ooxml, 2016-02-04) introduced a use of ww::GetEnglishNameFromSti, and since then, the unmatched elements started to get written to DOCX styles with wrong names, like <w:style w:type="paragraph" w:styleId="List5"> <w:name w:val="List Number"/> instead of original name "List 5". Change-Id: I8888b3f117e0b7f57c2dbb90565475d529416c60 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/143828 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> diff --git a/sw/qa/extras/ooxmlexport/data/tdf152425.docx b/sw/qa/extras/ooxmlexport/data/tdf152425.docx new file mode 100644 index 000000000000..53a65cc63438 Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/tdf152425.docx differ diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport18.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport18.cxx index a145a3054a4e..c9d7528f6297 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport18.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport18.cxx @@ -258,6 +258,20 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf126477) CPPUNIT_ASSERT_EQUAL(sal_Int32(1), aSeq2.getLength()); } +CPPUNIT_TEST_FIXTURE(Test, testTdf152425) +{ + loadAndReload("tdf152425.docx"); + + // Check that "List Number" and "List 5" styles don't get merged + const OUString Para3Style = getProperty<OUString>(getParagraph(3), "ParaStyleName"); + CPPUNIT_ASSERT_EQUAL(OUString("List Number"), Para3Style); + const OUString Para4Style = getProperty<OUString>(getParagraph(4), "ParaStyleName"); + // Eventually, we need to check this: + // CPPUNIT_ASSERT_EQUAL(OUString("List 5"), Para4Style); + // But for now, just make sure that the style names differ + CPPUNIT_ASSERT(Para4Style != Para3Style); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/filter/inc/wwstyles.hxx b/sw/source/filter/inc/wwstyles.hxx index 32dce11e3692..7a253d87c508 100644 --- a/sw/source/filter/inc/wwstyles.hxx +++ b/sw/source/filter/inc/wwstyles.hxx @@ -24,6 +24,7 @@ namespace ww { + // When changing, make sure to update GetStiNames in sw/source/filter/ww8/styles.cxx accordingly enum sti : sal_uInt16 { stiNormal = 0, // 0x0000 diff --git a/sw/source/filter/ww8/styles.cxx b/sw/source/filter/ww8/styles.cxx index 86ec89a37798..c7a28e77e60b 100644 --- a/sw/source/filter/ww8/styles.cxx +++ b/sw/source/filter/ww8/styles.cxx @@ -25,102 +25,103 @@ namespace { const char **GetStiNames() noexcept { + // Matches enum ww::sti in sw/source/filter/inc/wwstyles.hxx static const char *stiName[] = { - "Normal", - "Heading 1", - "Heading 2", - "Heading 3", - "Heading 4", - "Heading 5", - "Heading 6", - "Heading 7", - "Heading 8", - "Heading 9", - "Index 1", - "Index 2", - "Index 3", - "Index 4", - "Index 5", - "Index 6", - "Index 7", - "Index 8", - "Index 9", - "TOC 1", - "TOC 2", - "TOC 3", - "TOC 4", - "TOC 5", - "TOC 6", - "TOC 7", - "TOC 8", - "TOC 9", - "Normal Indent", - "Footnote Text", - "Annotation Text", - "Header", - "Footer", - "Index Heading", - "Caption", - "Table of Figures", - "Envelope Address", - "Envelope Return", - "Footnote Reference", - "Annotation Reference", - "Line Number", - "Page Number", - "Endnote Reference", - "Endnote Text", - "Table of Authorities", - "Macro Text", - "TOC Heading", - "List", - "List 2", - "List 3", - "List 4", - "List 5", - "List Bullet", - "List Bullet 2", - "List Bullet 3", - "List Bullet 4", - "List Bullet 5", - "List Number", - "List Number 2", - "List Number 3", - "List Number 4", - "List Number 5", - "Title", - "Closing", - "Signature", - "Default Paragraph Font", - "Body Text", - "Body Text Indent", - "List Continue", - "List Continue 2", - "List Continue 3", - "List Continue 4", - "List Continue 5", - "Message Header", - "Subtitle", - "Salutation", - "Date", - "Body Text First Indent", - "Body Text First Indent 2", - "Note Heading", - "Body Text 2", - "Body Text 3", - "Body Text Indent 2", - "Body Text Indent 3", - "Block Text", - "Hyperlink", - "FollowedHyperlink", - "Strong", - "Emphasis", - "Document Map", - "Plain Text" + "Normal", // stiNormal + "Heading 1", // stiLev1 + "Heading 2", // stiLev2 + "Heading 3", // stiLev3 + "Heading 4", // stiLev4 + "Heading 5", // stiLev5 + "Heading 6", // stiLev6 + "Heading 7", // stiLev7 + "Heading 8", // stiLev8 + "Heading 9", // stiLev9 + "Index 1", // stiIndex1 + "Index 2", // stiIndex2 + "Index 3", // stiIndex3 + "Index 4", // stiIndex4 + "Index 5", // stiIndex5 + "Index 6", // stiIndex6 + "Index 7", // stiIndex7 + "Index 8", // stiIndex8 + "Index 9", // stiIndex9 + "TOC 1", // stiToc1 + "TOC 2", // stiToc2 + "TOC 3", // stiToc3 + "TOC 4", // stiToc4 + "TOC 5", // stiToc5 + "TOC 6", // stiToc6 + "TOC 7", // stiToc7 + "TOC 8", // stiToc8 + "TOC 9", // stiToc9 + "Normal Indent", // stiNormIndent + "Footnote Text", // stiFootnoteText + "Annotation Text", // stiAtnText + "Header", // stiHeader + "Footer", // stiFooter + "Index Heading", // stiIndexHeading + "Caption", // stiCaption + "Table of Figures", // stiToCaption + "Envelope Address", // stiEnvAddr + "Envelope Return", // stiEnvRet + "Footnote Reference", // stiFootnoteRef + "Annotation Reference", // stiAtnRef + "Line Number", // stiLnn + "Page Number", // stiPgn + "Endnote Reference", // stiEdnRef + "Endnote Text", // stiEdnText + "Table of Authorities", // stiToa + "Macro Text", // stiMacro + "TOC Heading", // stiToaHeading - tdf143726 + "List", // stiList + "List Bullet", // stiListBullet + "List Number", // stiListNumber + "List 2", // stiList2 + "List 3", // stiList3 + "List 4", // stiList4 + "List 5", // stiList5 + "List Bullet 2", // stiListBullet2 + "List Bullet 3", // stiListBullet3 + "List Bullet 4", // stiListBullet4 + "List Bullet 5", // stiListBullet5 + "List Number 2", // stiListNumber2 + "List Number 3", // stiListNumber3 + "List Number 4", // stiListNumber4 + "List Number 5", // stiListNumber5 + "Title", // stiTitle + "Closing", // stiClosing + "Signature", // stiSignature + "Default Paragraph Font", // stiNormalChar + "Body Text", // stiBodyText + "Body Text Indent", // stiBodyTextInd1 + "List Continue", // stiListCont + "List Continue 2", // stiListCont2 + "List Continue 3", // stiListCont3 + "List Continue 4", // stiListCont4 + "List Continue 5", // stiListCont5 + "Message Header", // stiMsgHeader + "Subtitle", // stiSubtitle + "Salutation", // stiSalutation + "Date", // stiDate + "Body Text First Indent", // stiBodyText1I + "Body Text First Indent 2", // stiBodyText1I2 + "Note Heading", // stiNoteHeading + "Body Text 2", // stiBodyText2 + "Body Text 3", // stiBodyText3 + "Body Text Indent 2", // stiBodyTextInd2 + "Body Text Indent 3", // stiBodyTextInd3 + "Block Text", // stiBlockQuote + "Hyperlink", // stiHyperlink + "FollowedHyperlink", // stiHyperlinkFollowed + "Strong", // stiStrong + "Emphasis", // stiEmphasis + "Document Map", // stiNavPane + "Plain Text", // stiPlainText }; - OSL_ENSURE( SAL_N_ELEMENTS(stiName) == ww::stiMax, "WrongSizeOfArray" ); + static_assert(SAL_N_ELEMENTS(stiName) == ww::stiMax, "WrongSizeOfArray"); return stiName; }