cui/source/tabpages/numpages.cxx | 43 +- include/com/sun/star/uno/Any.h | 4 include/com/sun/star/uno/Any.hxx | 8 sw/qa/extras/ooxmlimport/data/tdf154319-ToC_with_s_and_d.docx |binary sw/qa/extras/ooxmlimport/ooxmlimport2.cxx | 50 +++ writerfilter/source/dmapper/DomainMapper_Impl.cxx | 150 ++++++---- 6 files changed, 187 insertions(+), 68 deletions(-)
New commits: commit 128671288204136ceba258a5fe809c354728a175 Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Tue Mar 21 21:35:58 2023 +0300 Commit: Xisco Fauli <xiscofa...@libreoffice.org> CommitDate: Fri Mar 24 09:02:52 2023 +0000 tdf#154319: fix TOC field codes parsing Change-Id: I734697f52df14ca5b316481df8a58fef72ab9571 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/149254 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> (cherry picked from commit 76777c82fa4bb5080c135e2241c3f7122dcbb298) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/149437 Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org> diff --git a/include/com/sun/star/uno/Any.h b/include/com/sun/star/uno/Any.h index f232ccd90fe9..b453f5fa5b0c 100644 --- a/include/com/sun/star/uno/Any.h +++ b/include/com/sun/star/uno/Any.h @@ -451,6 +451,10 @@ template<> inline bool SAL_CALL operator >>= ( const Any & rAny, ::rtl::OUString & value ); template<> inline bool SAL_CALL operator == ( const Any & rAny, const ::rtl::OUString & value ); +#if defined LIBO_INTERNAL_ONLY +template<std::size_t N> +inline bool SAL_CALL operator == (const Any& rAny, const rtl::OUStringLiteral<N>& value); +#endif // type template<> inline bool SAL_CALL operator >>= ( const Any & rAny, Type & value ); diff --git a/include/com/sun/star/uno/Any.hxx b/include/com/sun/star/uno/Any.hxx index d73b2a586d61..6267d41e733c 100644 --- a/include/com/sun/star/uno/Any.hxx +++ b/include/com/sun/star/uno/Any.hxx @@ -600,6 +600,14 @@ inline bool SAL_CALL operator == ( const Any & rAny, const ::rtl::OUString & val return (typelib_TypeClass_STRING == rAny.pType->eTypeClass && value == * static_cast< const ::rtl::OUString * >( rAny.pData ) ); } + +#if defined LIBO_INTERNAL_ONLY +template<std::size_t N> +inline bool SAL_CALL operator == (const Any& rAny, const rtl::OUStringLiteral<N>& value) +{ + return operator ==(rAny, rtl::OUString(value)); +} +#endif // type template<> diff --git a/sw/qa/extras/ooxmlimport/data/tdf154319-ToC_with_s_and_d.docx b/sw/qa/extras/ooxmlimport/data/tdf154319-ToC_with_s_and_d.docx new file mode 100644 index 000000000000..dc5a67824c9d Binary files /dev/null and b/sw/qa/extras/ooxmlimport/data/tdf154319-ToC_with_s_and_d.docx differ diff --git a/sw/qa/extras/ooxmlimport/ooxmlimport2.cxx b/sw/qa/extras/ooxmlimport/ooxmlimport2.cxx index 26ad31df3a78..406812ab7fa5 100644 --- a/sw/qa/extras/ooxmlimport/ooxmlimport2.cxx +++ b/sw/qa/extras/ooxmlimport/ooxmlimport2.cxx @@ -1021,6 +1021,56 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf153791) CPPUNIT_ASSERT_EQUAL(COL_AUTO, getProperty<Color>(xRun, "CharColor")); } +CPPUNIT_TEST_FIXTURE(Test, testTdf154319) +{ + createSwDoc("tdf154319-ToC_with_s_and_d.docx"); + + css::uno::Reference<css::text::XDocumentIndexesSupplier> xSupplier(mxComponent, + css::uno::UNO_QUERY_THROW); + auto xIndexes = xSupplier->getDocumentIndexes(); + css::uno::Reference<css::beans::XPropertySet> xTOCIndex(xIndexes->getByIndex(0), + css::uno::UNO_QUERY_THROW); + css::uno::Reference<css::container::XIndexReplace> xLevelFormats; + CPPUNIT_ASSERT(xTOCIndex->getPropertyValue("LevelFormat") >>= xLevelFormats); + CPPUNIT_ASSERT_EQUAL(sal_Int32(11), xLevelFormats->getCount()); + + const auto checkPropVal = [](const auto& expected, const css::beans::PropertyValues& entry, + const OUString& name) { + auto it + = std::find_if(entry.begin(), entry.end(), + [&name](const css::beans::PropertyValue& p) { return p.Name == name; }); + OString msg = "Property: " + name.toUtf8(); + CPPUNIT_ASSERT_MESSAGE(msg.getStr(), it != entry.end()); + CPPUNIT_ASSERT_EQUAL_MESSAGE(msg.getStr(), css::uno::Any(expected), it->Value); + }; + + //start with level 1, 0 is the header level + for (sal_Int32 nLevel = 1; nLevel < xLevelFormats->getCount(); ++nLevel) + { + css::uno::Sequence<css::beans::PropertyValues> aLevel; + xLevelFormats->getByIndex(nLevel) >>= aLevel; + + CPPUNIT_ASSERT_EQUAL(sal_Int32(8), aLevel.getLength()); + + checkPropVal(OUString("TokenHyperlinkStart"), aLevel[0], "TokenType"); + + checkPropVal(OUString("TokenEntryNumber"), aLevel[1], "TokenType"); + + checkPropVal(OUString("TokenEntryText"), aLevel[2], "TokenType"); + + checkPropVal(OUString("TokenTabStop"), aLevel[3], "TokenType"); + + checkPropVal(OUString("TokenChapterInfo"), aLevel[4], "TokenType"); + + checkPropVal(OUString("TokenText"), aLevel[5], "TokenType"); + checkPropVal(OUString("\""), aLevel[5], "Text"); + + checkPropVal(OUString("TokenPageNumber"), aLevel[6], "TokenType"); + + checkPropVal(OUString("TokenHyperlinkEnd"), aLevel[7], "TokenType"); + } +} + // tests should only be added to ooxmlIMPORT *if* they fail round-tripping in ooxmlEXPORT CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx index 449c75e9b8ce..663e47a1fa70 100644 --- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx +++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx @@ -4752,26 +4752,52 @@ static OUString lcl_ExtractVariableAndHint( std::u16string_view rCommand, OUStri return OUString(sRet); } +static size_t nextCode(std::u16string_view rCommand, size_t pos) +{ + bool inQuotes = false; + for (; pos < rCommand.size(); ++pos) + { + switch (rCommand[pos]) + { + case '"': + inQuotes = !inQuotes; + break; + case '\\': + ++pos; + if (!inQuotes) + return pos; + break; + } + } + return std::u16string_view::npos; +} + +// Returns the position of the field code +static size_t findCode(std::u16string_view rCommand, sal_Unicode cSwitch) +{ + for (size_t i = nextCode(rCommand, 0); i < rCommand.size(); i = nextCode(rCommand, i)) + if (rCommand[i] == cSwitch) + return i; + + return std::u16string_view::npos; +} static bool lcl_FindInCommand( std::u16string_view rCommand, sal_Unicode cSwitch, OUString& rValue ) { - bool bRet = false; - OUString sSearch = "\\" + OUStringChar( cSwitch ); - size_t nIndex = rCommand.find( sSearch ); - if( nIndex != std::u16string_view::npos ) - { - bRet = true; - //find next '\' or end of string - size_t nEndIndex = rCommand.find( '\\', nIndex + 1); - if( nEndIndex == std::u16string_view::npos ) - nEndIndex = rCommand.size() ; - if( nEndIndex - nIndex > 3 ) - rValue = rCommand.substr( nIndex + 3, nEndIndex - nIndex - 3); + if (size_t i = findCode(rCommand, cSwitch); i < rCommand.size()) + { + ++i; + size_t next = nextCode(rCommand, i); + if (next < rCommand.size()) + --next; // get back before the next '\\' + rValue = o3tl::trim(rCommand.substr(i, next - i)); + return true; } - return bRet; + + return false; } static OUString lcl_trim(std::u16string_view sValue) @@ -6005,45 +6031,49 @@ void DomainMapper_Impl::handleAuthor static uno::Sequence< beans::PropertyValues > lcl_createTOXLevelHyperlinks( bool bHyperlinks, const OUString& sChapterNoSeparator, const uno::Sequence< beans::PropertyValues >& aLevel ) { - //create a copy of the level and add two new entries - hyperlink start and end - bool bChapterNoSeparator = !sChapterNoSeparator.isEmpty(); - sal_Int32 nAdd = (bHyperlinks && bChapterNoSeparator) ? 4 : 2; - uno::Sequence< beans::PropertyValues > aNewLevel( aLevel.getLength() + nAdd); - beans::PropertyValues* pNewLevel = aNewLevel.getArray(); - if( bHyperlinks ) - { - beans::PropertyValues aHyperlink{ comphelper::makePropertyValue( - getPropertyName( PROP_TOKEN_TYPE ), getPropertyName( PROP_TOKEN_HYPERLINK_START )) }; - pNewLevel[0] = aHyperlink; - aHyperlink = { comphelper::makePropertyValue( - getPropertyName(PROP_TOKEN_TYPE), getPropertyName( PROP_TOKEN_HYPERLINK_END )) }; - pNewLevel[aNewLevel.getLength() -1] = aHyperlink; - } - if( bChapterNoSeparator ) - { - beans::PropertyValues aChapterNo{ - comphelper::makePropertyValue(getPropertyName( PROP_TOKEN_TYPE ), - getPropertyName( PROP_TOKEN_CHAPTER_INFO )), - comphelper::makePropertyValue(getPropertyName( PROP_CHAPTER_FORMAT ), - //todo: is ChapterFormat::Number correct? - sal_Int16(text::ChapterFormat::NUMBER)) - }; - pNewLevel[aNewLevel.getLength() - (bHyperlinks ? 4 : 2) ] = aChapterNo; + //create a copy of the level and add new entries - beans::PropertyValues aChapterSeparator{ - comphelper::makePropertyValue(getPropertyName( PROP_TOKEN_TYPE ), - getPropertyName( PROP_TOKEN_TEXT )), - comphelper::makePropertyValue(getPropertyName( PROP_TEXT ), sChapterNoSeparator) - }; - pNewLevel[aNewLevel.getLength() - (bHyperlinks ? 3 : 1)] = aChapterSeparator; + std::vector<css::beans::PropertyValues> aNewLevel; + aNewLevel.reserve(aLevel.getLength() + 4); // at most 4 added items + + static constexpr OUStringLiteral tokType(u"TokenType"); + static constexpr OUStringLiteral tokHStart(u"TokenHyperlinkStart"); + static constexpr OUStringLiteral tokHEnd(u"TokenHyperlinkEnd"); + static constexpr OUStringLiteral tokPNum(u"TokenPageNumber"); + + if (bHyperlinks) + aNewLevel.push_back({ comphelper::makePropertyValue(tokType, tokHStart) }); + + for (const auto& item : aLevel) + { + if (bHyperlinks + && std::any_of(item.begin(), item.end(), + [](const css::beans::PropertyValue& p) { + return p.Name == tokType + && (p.Value == tokHStart || p.Value == tokHEnd); + })) + continue; // We add hyperlink ourselves, so just skip existing hyperlink start / end + + if (!sChapterNoSeparator.isEmpty() + && std::any_of(item.begin(), item.end(), + [](const css::beans::PropertyValue& p) + { return p.Name == tokType && p.Value == tokPNum; })) + { + // This is an existing page number token; insert the chapter and separator before it + aNewLevel.push_back( + { comphelper::makePropertyValue(tokType, OUString("TokenChapterInfo")), + comphelper::makePropertyValue("ChapterFormat", text::ChapterFormat::NUMBER) }); + aNewLevel.push_back({ comphelper::makePropertyValue(tokType, OUString("TokenText")), + comphelper::makePropertyValue("Text", sChapterNoSeparator) }); + } + + aNewLevel.push_back(item); } - //copy the 'old' entries except the last (page no) - std::copy(aLevel.begin(), std::prev(aLevel.end()), std::next(pNewLevel)); - //copy page no entry (last or last but one depending on bHyperlinks - sal_Int32 nPageNo = aNewLevel.getLength() - (bHyperlinks ? 2 : 3); - pNewLevel[nPageNo] = aLevel[aLevel.getLength() - 1]; - return aNewLevel; + if (bHyperlinks) + aNewLevel.push_back({ comphelper::makePropertyValue(tokType, tokHEnd) }); + + return comphelper::containerToSequence(aNewLevel); } /// Returns title of the TOC placed in paragraph(s) before TOC field inside STD-frame @@ -6144,6 +6174,26 @@ static auto FilterChars(OUString const& rStyleName) -> OUString return ret.makeStringAndClear(); } +static OUString UnquoteFieldText(std::u16string_view s) +{ + OUStringBuffer result(s.size()); + for (size_t i = 0; i < s.size(); ++i) + { + switch (s[i]) + { + case '"': + continue; + case '\\': + if (i < s.size() - 1) + ++i; + [[fallthrough]]; + default: + result.append(s[i]); + } + } + return result.makeStringAndClear(); +} + OUString DomainMapper_Impl::ConvertTOCStyleName(OUString const& rTOCStyleName) { assert(!rTOCStyleName.isEmpty()); @@ -6209,7 +6259,7 @@ void DomainMapper_Impl::handleToc if( lcl_FindInCommand( pContext->GetCommand(), 'd', sValue )) { //todo: insert the chapter number into each level and insert the separator additionally - sChapterNoSeparator = sValue; + sChapterNoSeparator = UnquoteFieldText(sValue); } // \f Builds a table of contents using TC entries instead of outline levels if( lcl_FindInCommand( pContext->GetCommand(), 'f', sValue )) commit fde07de7155099e1bc1d718e0f82dc354ed96b0f Author: Rafael Lima <rafael.palma.l...@gmail.com> AuthorDate: Fri Feb 24 15:23:48 2023 -0300 Commit: Xisco Fauli <xiscofa...@libreoffice.org> CommitDate: Fri Mar 24 09:02:44 2023 +0000 tdf#153808 Fix numbering preview in dark mode This patch fixes the color used for numbers and bullets in the preview of the Bullets and Numbering dialog in Impress. Currently the implementation causes the bullets and numbers to be rendered in white over a white background when using dark mode. The fix uses DOCCOLOR and FONTCOLOR to create the preview, instead of FieldColor and FieldTextColor. Change-Id: Icf41c5be59c67a2d68e3c520744276492e9baa59 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/147664 Tested-by: Jenkins Reviewed-by: Heiko Tietze <heiko.tie...@documentfoundation.org> (cherry picked from commit 3a4b32c9e1dfc56d9b00e3720834d21c9095f629) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/149435 Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org> diff --git a/cui/source/tabpages/numpages.cxx b/cui/source/tabpages/numpages.cxx index 0c66f69ee637..916e513d9cc0 100644 --- a/cui/source/tabpages/numpages.cxx +++ b/cui/source/tabpages/numpages.cxx @@ -44,6 +44,7 @@ #include <unotools/pathoptions.hxx> #include <svtools/ctrltool.hxx> #include <svtools/unitconv.hxx> +#include <svtools/colorcfg.hxx> #include <com/sun/star/style/NumberingType.hpp> #include <com/sun/star/lang/XMultiServiceFactory.hpp> #include <com/sun/star/container/XIndexAccess.hpp> @@ -2154,10 +2155,10 @@ static tools::Long lcl_DrawBullet(VirtualDevice* pVDev, aFont.SetFontSize(aTmpSize); aFont.SetTransparent(true); Color aBulletColor = rFmt.GetBulletColor(); - if(aBulletColor == COL_AUTO) - aBulletColor = pVDev->GetFillColor().IsDark() ? COL_WHITE : COL_BLACK; - else if(aBulletColor == pVDev->GetFillColor()) - aBulletColor.Invert(); + if (aBulletColor == COL_AUTO) + aBulletColor = pVDev->GetBackgroundColor().IsDark() ? COL_WHITE : COL_BLACK; + else if (pVDev->GetBackgroundColor().IsDark() == aBulletColor.IsDark()) + aBulletColor = pVDev->GetBackgroundColor().IsDark() ? COL_WHITE : COL_BLACK; aFont.SetColor(aBulletColor); pVDev->SetFont( aFont ); sal_UCS4 cChar = rFmt.GetBulletChar(); @@ -2183,9 +2184,9 @@ void SvxNumberingPreview::Paint(vcl::RenderContext& rRenderContext, const ::tool { Size aSize(rRenderContext.PixelToLogic(GetOutputSizePixel())); - const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings(); - const Color aBackColor = rStyleSettings.GetFieldColor(); - const Color aTextColor = rStyleSettings.GetFieldTextColor(); + // Use default document and font colors to create preview + const Color aBackColor = svtools::ColorConfig().GetColorValue(svtools::DOCCOLOR).nColor; + const Color aTextColor = svtools::ColorConfig().GetColorValue(svtools::FONTCOLOR).nColor; ScopedVclPtrInstance<VirtualDevice> pVDev(rRenderContext); pVDev->EnableRTL(rRenderContext.IsRTLEnabled()); @@ -2197,6 +2198,8 @@ void SvxNumberingPreview::Paint(vcl::RenderContext& rRenderContext, const ::tool aLineColor.Invert(); pVDev->SetLineColor(aLineColor); pVDev->SetFillColor(aBackColor); + pVDev->SetBackground(Wallpaper(aBackColor)); + pVDev->DrawWallpaper(pVDev->GetOutputRectPixel(), pVDev->GetBackground()); if (pActNum) { @@ -2224,6 +2227,9 @@ void SvxNumberingPreview::Paint(vcl::RenderContext& rRenderContext, const ::tool if (bPosition) { + // When bPosition == true, draw the preview used in the Writer's "Position" tab + // This is not used in Impress/Draw + tools::Long nLineHeight = nFontHeight * 8 / 7; sal_uInt8 nStart = 0; while (!(nActLevel & (1<<nStart))) @@ -2290,9 +2296,9 @@ void SvxNumberingPreview::Paint(vcl::RenderContext& rRenderContext, const ::tool vcl::Font aColorFont(aSaveFont); Color aTmpBulletColor = rFmt.GetBulletColor(); if (aTmpBulletColor == COL_AUTO) - aTmpBulletColor = aBackColor.IsDark() ? COL_WHITE : COL_BLACK; - else if (aTmpBulletColor == aBackColor) - aTmpBulletColor.Invert(); + aTmpBulletColor = pVDev->GetBackgroundColor().IsDark() ? COL_WHITE : COL_BLACK; + else if (pVDev->GetBackgroundColor().IsDark() == aTmpBulletColor.IsDark()) + aTmpBulletColor = pVDev->GetBackgroundColor().IsDark() ? COL_WHITE : COL_BLACK; aColorFont.SetColor(aTmpBulletColor); pVDev->SetFont(aColorFont); pVDev->DrawText(Point(nNumberXPos, nYStart), aText); @@ -2354,14 +2360,15 @@ void SvxNumberingPreview::Paint(vcl::RenderContext& rRenderContext, const ::tool } else { + // When bPosition == false, draw the preview used in Writer's "Customize" tab + // and in Impress' "Bullets and Numbering" dialog + //#i5153# painting gray or black rectangles as 'normal' numbering text tools::Long nWidth = pVDev->GetTextWidth("Preview"); tools::Long nTextHeight = pVDev->GetTextHeight(); tools::Long nRectHeight = nTextHeight * 2 / 3; tools::Long nTopOffset = nTextHeight - nRectHeight; - Color aBlackColor(COL_BLACK); - if (aBlackColor == aBackColor) - aBlackColor.Invert(); + Color aSelRectColor = pVDev->GetBackgroundColor().IsDark() ? COL_WHITE : COL_BLACK; for (sal_uInt16 nLevel = 0; nLevel < pActNum->GetLevelCount(); ++nLevel, nYStart = nYStart + nYStep) { @@ -2422,9 +2429,9 @@ void SvxNumberingPreview::Paint(vcl::RenderContext& rRenderContext, const ::tool aFont.SetFontSize(aTmpSize); Color aTmpBulletColor = rFmt.GetBulletColor(); if (aTmpBulletColor == COL_AUTO) - aTmpBulletColor = aBackColor.IsDark() ? COL_WHITE : COL_BLACK; - else if (aTmpBulletColor == aBackColor) - aTmpBulletColor.Invert(); + aTmpBulletColor = pVDev->GetBackgroundColor().IsDark() ? COL_WHITE : COL_BLACK; + else if (pVDev->GetBackgroundColor().IsDark() == aTmpBulletColor.IsDark()) + aTmpBulletColor = pVDev->GetBackgroundColor().IsDark() ? COL_WHITE : COL_BLACK; aFont.SetColor(aTmpBulletColor); pVDev->SetFont(aFont); aNum.SetLevel( nLevel ); @@ -2442,8 +2449,8 @@ void SvxNumberingPreview::Paint(vcl::RenderContext& rRenderContext, const ::tool //#i5153# the selected rectangle(s) should be black if (0 != (nActLevel & (1<<nLevel))) { - pVDev->SetFillColor( aBlackColor ); - pVDev->SetLineColor( aBlackColor ); + pVDev->SetFillColor( aSelRectColor ); + pVDev->SetLineColor( aSelRectColor ); } else {