chart2/source/controller/main/CommandDispatchContainer.cxx | 4 cui/source/inc/page.hxx | 1 cui/source/tabpages/page.cxx | 20 cui/uiconfig/ui/pageformatpage.ui | 28 - desktop/source/lib/init.cxx | 45 + editeng/source/editeng/impedit3.cxx | 2 include/o3tl/lru_map.hxx | 14 include/o3tl/sorted_vector.hxx | 4 include/sfx2/lokhelper.hxx | 2 include/svx/sdr/contact/objectcontact.hxx | 3 include/svx/svxids.hrc | 4 include/vcl/ITiledRenderable.hxx | 17 include/vcl/svapp.hxx | 7 officecfg/registry/data/org/openoffice/Office/UI/Controller.xcu | 11 officecfg/registry/data/org/openoffice/Office/UI/DrawImpressCommands.xcu | 8 officecfg/registry/data/org/openoffice/Office/UI/GenericCommands.xcu | 9 sax/source/fastparser/fastparser.cxx | 29 - sc/inc/conditio.hxx | 13 sc/source/core/data/conditio.cxx | 102 +++ sc/source/core/tool/recursionhelper.cxx | 2 sc/source/filter/excel/xetable.cxx | 2 sd/Library_sd.mk | 1 sd/inc/app.hrc | 1 sd/inc/drawdoc.hxx | 40 + sd/inc/sdpage.hxx | 4 sd/inc/unomodel.hxx | 2 sd/qa/unit/SVGExportTests.cxx | 32 - sd/qa/unit/layout-tests.cxx | 3 sd/sdi/SlideSorterController.sdi | 5 sd/sdi/_drvwsh.sdi | 5 sd/sdi/sdraw.sdi | 17 sd/source/core/drawdoc.cxx | 276 ++++++---- sd/source/core/drawdoc2.cxx | 17 sd/source/core/sdpage.cxx | 2 sd/source/ui/animations/SlideTransitionPane.cxx | 7 sd/source/ui/controller/SlideTransitionsToolBoxControl.cxx | 1 sd/source/ui/controller/SlideTransitionsToolBoxControl.hxx | 1 sd/source/ui/func/fupage.cxx | 14 sd/source/ui/inc/SlideTransitionPane.hxx | 2 sd/source/ui/sidebar/AllMasterPagesSelector.cxx | 33 + sd/source/ui/sidebar/AllMasterPagesSelector.hxx | 14 sd/source/ui/sidebar/CurrentMasterPagesSelector.cxx | 7 sd/source/ui/sidebar/CurrentMasterPagesSelector.hxx | 3 sd/source/ui/sidebar/MasterPagesSelector.cxx | 26 sd/source/ui/sidebar/MasterPagesSelector.hxx | 24 sd/source/ui/sidebar/RecentMasterPagesSelector.cxx | 2 sd/source/ui/sidebar/SlideBackground.cxx | 27 sd/source/ui/sidebar/SlideBackground.hxx | 1 sd/source/ui/sidebar/SlideMasterPagesAllToolBoxControl.cxx | 110 +++ sd/source/ui/sidebar/SlideMasterPagesAllToolBoxControl.hxx | 47 + sd/source/ui/slidesorter/controller/SlsSlotManager.cxx | 14 sd/source/ui/unoidl/unomodel.cxx | 28 + sd/source/ui/view/drviews1.cxx | 38 + sd/source/ui/view/drviews2.cxx | 8 sd/source/ui/view/viewshe2.cxx | 48 + sd/source/ui/view/viewshel.cxx | 15 sd/uiconfig/simpress/ui/notebookbar_online.ui | 24 sd/util/sd.component | 4 sfx2/source/dialog/templdlg.cxx | 17 sfx2/source/view/lokhelper.cxx | 18 svx/inc/sdr/primitive2d/sdrrectangleprimitive2d.hxx | 9 svx/source/inc/StylesPreviewWindow.hxx | 6 svx/source/sdr/contact/objectcontactofpageview.cxx | 12 svx/source/sdr/contact/viewcontactofsdrrectobj.cxx | 3 svx/source/sdr/primitive2d/sdrrectangleprimitive2d.cxx | 25 svx/source/tbxctrls/StylesPreviewToolBoxControl.cxx | 19 svx/source/tbxctrls/StylesPreviewWindow.cxx | 46 - svx/source/unodraw/unoprov.cxx | 1 sw/inc/format.hxx | 5 sw/qa/extras/ooxmlexport/data/nospacing_hidden.docx |binary sw/qa/extras/ooxmlexport/ooxmlexport25.cxx | 12 sw/qa/uitest/writer_tests4/tdf167956.py | 2 sw/source/core/access/accmap.cxx | 4 sw/source/core/attr/format.cxx | 45 - sw/source/core/doc/docnew.cxx | 2 sw/source/core/undo/rolbck.cxx | 4 sw/source/core/view/viewpg.cxx | 4 sw/source/core/view/vprint.cxx | 2 sw/source/filter/ww8/docxattributeoutput.cxx | 10 vcl/inc/jsdialog/enabled.hxx | 4 vcl/inc/salinst.hxx | 4 vcl/jsdialog/enabled.cxx | 17 vcl/source/app/salvtables.cxx | 4 vcl/source/window/builder.cxx | 45 + vcl/source/window/window.cxx | 22 vcl/unx/generic/print/prtsetup.cxx | 2 vcl/unx/gtk3/gtkinst.cxx | 2 vcl/vcl.common.component.headless | 1 xmloff/source/core/xmlimp.cxx | 181 ++++++ 89 files changed, 1465 insertions(+), 293 deletions(-)
New commits: commit 78209fbed4fef148484e33efd3bcf92b8adc0728 Author: Balazs Varga <[email protected]> AuthorDate: Thu Dec 18 16:23:37 2025 +0100 Commit: Andras Timar <[email protected]> CommitDate: Sat Jan 10 13:24:31 2026 +0100 tdf#168110 - sd fix Placeholder default text is visible in presentation mode Do not render empty pres objects texts in slideshow. follow-up of commits: e136900e7a971385be9367a3dcaedea54d1e7207 (tdf#159258 sd: fix to show objects in slideshow if they have) d323976fd6d560a9b91da3e7833dfbe9f6b78f39 (tdf#159258 SD: SS: disable placeholdertext in image) co-author: Armin Le Grand <[email protected]> Change-Id: I6127cdc36a27dfeac79881b57b9b8cbf963c9d3a Reviewed-on: https://gerrit.libreoffice.org/c/core/+/195857 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Balazs Varga <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/196353 Reviewed-by: Armin Le Grand <[email protected]> Tested-by: Jenkins diff --git a/include/svx/sdr/contact/objectcontact.hxx b/include/svx/sdr/contact/objectcontact.hxx index 7cb9da471cdb..df832b0bcb2d 100644 --- a/include/svx/sdr/contact/objectcontact.hxx +++ b/include/svx/sdr/contact/objectcontact.hxx @@ -85,6 +85,9 @@ protected: // interface to allow derivates to set ViewInformation2D void setViewInformation2D2D(const drawinglayer::geometry::ViewInformation2D& rViewInformation2D) { maViewInformation2D = rViewInformation2D; } + // Allow to set EditViewActive early at local ViewInformation2D from ObjectContactOfPageView + void setEditViewActiveEarly() { maViewInformation2D.setEditViewActive(true); } + public: // basic constructor ObjectContact(); diff --git a/sd/qa/unit/SVGExportTests.cxx b/sd/qa/unit/SVGExportTests.cxx index 8eaa8cb9e8d4..5f73bad89f3b 100644 --- a/sd/qa/unit/SVGExportTests.cxx +++ b/sd/qa/unit/SVGExportTests.cxx @@ -131,20 +131,20 @@ public: xmlDocUniquePtr svgDoc = parseXml(maTempFile); CPPUNIT_ASSERT(svgDoc); - assertXPath(svgDoc, SAL_STRINGIFY( /SVG_SVG/SVG_DEFS[9]/SVG_G[2] ), "class", u"Master_Slide"); - assertXPath(svgDoc, SAL_STRINGIFY( /SVG_SVG/SVG_DEFS[9]/SVG_G[2]/SVG_G[2] ), "class", u"BackgroundObjects"); + assertXPath(svgDoc, SAL_STRINGIFY( /SVG_SVG/SVG_DEFS[8]/SVG_G[2] ), "class", u"Master_Slide"); + assertXPath(svgDoc, SAL_STRINGIFY( /SVG_SVG/SVG_DEFS[8]/SVG_G[2]/SVG_G[2] ), "class", u"BackgroundObjects"); // Current Date Field - assertXPath(svgDoc, SAL_STRINGIFY( /SVG_SVG/SVG_DEFS[9]/SVG_G[2]/SVG_G[2]/SVG_G[4] ), "class", u"TextShape"); - assertXPath(svgDoc, SAL_STRINGIFY( /SVG_SVG/SVG_DEFS[9]/SVG_G[2]/SVG_G[2]/SVG_G[4]/SVG_G/SVG_TEXT/SVG_TSPAN/SVG_TSPAN/SVG_TSPAN ), "class", u"PlaceholderText Date"); + assertXPath(svgDoc, SAL_STRINGIFY( /SVG_SVG/SVG_DEFS[8]/SVG_G[2]/SVG_G[2]/SVG_G[4] ), "class", u"TextShape"); + assertXPath(svgDoc, SAL_STRINGIFY( /SVG_SVG/SVG_DEFS[8]/SVG_G[2]/SVG_G[2]/SVG_G[4]/SVG_G/SVG_TEXT/SVG_TSPAN/SVG_TSPAN/SVG_TSPAN ), "class", u"PlaceholderText Date"); // Current Time Field - assertXPath(svgDoc, SAL_STRINGIFY( /SVG_SVG/SVG_DEFS[9]/SVG_G[2]/SVG_G[2]/SVG_G[5] ), "class", u"TextShape"); - assertXPath(svgDoc, SAL_STRINGIFY( /SVG_SVG/SVG_DEFS[9]/SVG_G[2]/SVG_G[2]/SVG_G[5]/SVG_G/SVG_TEXT/SVG_TSPAN/SVG_TSPAN/SVG_TSPAN ), "class", u"PlaceholderText Time"); + assertXPath(svgDoc, SAL_STRINGIFY( /SVG_SVG/SVG_DEFS[8]/SVG_G[2]/SVG_G[2]/SVG_G[5] ), "class", u"TextShape"); + assertXPath(svgDoc, SAL_STRINGIFY( /SVG_SVG/SVG_DEFS[8]/SVG_G[2]/SVG_G[2]/SVG_G[5]/SVG_G/SVG_TEXT/SVG_TSPAN/SVG_TSPAN/SVG_TSPAN ), "class", u"PlaceholderText Time"); // Slide Name Field - assertXPath(svgDoc, SAL_STRINGIFY( /SVG_SVG/SVG_DEFS[9]/SVG_G[2]/SVG_G[2]/SVG_G[6] ), "class", u"TextShape"); - assertXPath(svgDoc, SAL_STRINGIFY( /SVG_SVG/SVG_DEFS[9]/SVG_G[2]/SVG_G[2]/SVG_G[6]/SVG_G/SVG_TEXT/SVG_TSPAN/SVG_TSPAN/SVG_TSPAN ), "class", u"PlaceholderText PageName"); + assertXPath(svgDoc, SAL_STRINGIFY( /SVG_SVG/SVG_DEFS[8]/SVG_G[2]/SVG_G[2]/SVG_G[6] ), "class", u"TextShape"); + assertXPath(svgDoc, SAL_STRINGIFY( /SVG_SVG/SVG_DEFS[8]/SVG_G[2]/SVG_G[2]/SVG_G[6]/SVG_G/SVG_TEXT/SVG_TSPAN/SVG_TSPAN/SVG_TSPAN ), "class", u"PlaceholderText PageName"); // Slide Number Field - assertXPath(svgDoc, SAL_STRINGIFY( /SVG_SVG/SVG_DEFS[9]/SVG_G[2]/SVG_G[2]/SVG_G[7] ), "class", u"TextShape"); - assertXPath(svgDoc, SAL_STRINGIFY( /SVG_SVG/SVG_DEFS[9]/SVG_G[2]/SVG_G[2]/SVG_G[7]/SVG_G/SVG_TEXT/SVG_TSPAN/SVG_TSPAN/SVG_TSPAN ), "class", u"PlaceholderText PageNumber"); + assertXPath(svgDoc, SAL_STRINGIFY( /SVG_SVG/SVG_DEFS[8]/SVG_G[2]/SVG_G[2]/SVG_G[7] ), "class", u"TextShape"); + assertXPath(svgDoc, SAL_STRINGIFY( /SVG_SVG/SVG_DEFS[8]/SVG_G[2]/SVG_G[2]/SVG_G[7]/SVG_G/SVG_TEXT/SVG_TSPAN/SVG_TSPAN/SVG_TSPAN ), "class", u"PlaceholderText PageNumber"); } void testSVGExportEmbeddedVideo() @@ -280,15 +280,15 @@ public: xmlDocUniquePtr svgDoc = parseXml(maTempFile); CPPUNIT_ASSERT(svgDoc); - assertXPath(svgDoc, SAL_STRINGIFY( /SVG_SVG/SVG_DEFS[9]/SVG_G[2] ), "class", u"Master_Slide"); - assertXPath(svgDoc, SAL_STRINGIFY( /SVG_SVG/SVG_DEFS[9]/SVG_G[2]/SVG_G[2] ), "class", u"BackgroundObjects"); + assertXPath(svgDoc, SAL_STRINGIFY( /SVG_SVG/SVG_DEFS[8]/SVG_G[2] ), "class", u"Master_Slide"); + assertXPath(svgDoc, SAL_STRINGIFY( /SVG_SVG/SVG_DEFS[8]/SVG_G[2]/SVG_G[2] ), "class", u"BackgroundObjects"); // Slide Name Field - assertXPath(svgDoc, SAL_STRINGIFY( /SVG_SVG/SVG_DEFS[9]/SVG_G[2]/SVG_G[2]/SVG_G[6] ), "class", u"TextShape"); - assertXPath(svgDoc, SAL_STRINGIFY( /SVG_SVG/SVG_DEFS[9]/SVG_G[2]/SVG_G[2]/SVG_G[6]/SVG_G/SVG_TEXT/SVG_TSPAN/SVG_TSPAN/SVG_TSPAN ), "class", u"PlaceholderText PageName"); + assertXPath(svgDoc, SAL_STRINGIFY( /SVG_SVG/SVG_DEFS[8]/SVG_G[2]/SVG_G[2]/SVG_G[6] ), "class", u"TextShape"); + assertXPath(svgDoc, SAL_STRINGIFY( /SVG_SVG/SVG_DEFS[8]/SVG_G[2]/SVG_G[2]/SVG_G[6]/SVG_G/SVG_TEXT/SVG_TSPAN/SVG_TSPAN/SVG_TSPAN ), "class", u"PlaceholderText PageName"); // Slide Number Field - assertXPath(svgDoc, SAL_STRINGIFY( /SVG_SVG/SVG_DEFS[9]/SVG_G[2]/SVG_G[2]/SVG_G[7] ), "class", u"TextShape"); - assertXPath(svgDoc, SAL_STRINGIFY( /SVG_SVG/SVG_DEFS[9]/SVG_G[2]/SVG_G[2]/SVG_G[7]/SVG_G/SVG_TEXT/SVG_TSPAN/SVG_TSPAN/SVG_TSPAN ), "class", u"PlaceholderText PageNumber"); + assertXPath(svgDoc, SAL_STRINGIFY( /SVG_SVG/SVG_DEFS[8]/SVG_G[2]/SVG_G[2]/SVG_G[7] ), "class", u"TextShape"); + assertXPath(svgDoc, SAL_STRINGIFY( /SVG_SVG/SVG_DEFS[8]/SVG_G[2]/SVG_G[2]/SVG_G[7]/SVG_G/SVG_TEXT/SVG_TSPAN/SVG_TSPAN/SVG_TSPAN ), "class", u"PlaceholderText PageNumber"); } CPPUNIT_TEST_SUITE(SdSVGFilterTest); diff --git a/sd/qa/unit/layout-tests.cxx b/sd/qa/unit/layout-tests.cxx index 553d1841c479..fe3a27418553 100644 --- a/sd/qa/unit/layout-tests.cxx +++ b/sd/qa/unit/layout-tests.cxx @@ -263,7 +263,6 @@ CPPUNIT_TEST_FIXTURE(SdLayoutTest, tdf143258_testTbRlLayout) CPPUNIT_TEST_FIXTURE(SdLayoutTest, numberedList) { const OUString sText[] = { - "Click to add Title", "1.", "Outer, one", "2.", @@ -364,7 +363,7 @@ CPPUNIT_TEST_FIXTURE(SdLayoutTest, testTdf156955) xmlDocUniquePtr pXmlDoc = parseLayout(); // Make sure text box has the right size - without the fix it was 2759. - assertXPath(pXmlDoc, "/metafile/push/push/textarray[5]", "y", u"3183"); + assertXPath(pXmlDoc, "/metafile/push/push/textarray[3]", "y", u"3183"); } CPPUNIT_TEST_FIXTURE(SdLayoutTest, testTdf148966) diff --git a/svx/inc/sdr/primitive2d/sdrrectangleprimitive2d.hxx b/svx/inc/sdr/primitive2d/sdrrectangleprimitive2d.hxx index 07600202ee83..6a614ec192ce 100644 --- a/svx/inc/sdr/primitive2d/sdrrectangleprimitive2d.hxx +++ b/svx/inc/sdr/primitive2d/sdrrectangleprimitive2d.hxx @@ -33,13 +33,15 @@ namespace drawinglayer::primitive2d { private: basegfx::B2DHomMatrix maTransform; - attribute::SdrLineFillEffectsTextAttribute maSdrLFSTAttribute; + attribute::SdrLineFillEffectsTextAttribute maSdrLFSTAttribute; double mfCornerRadiusX; // [0.0..1.0] relative to 1/2 width double mfCornerRadiusY; // [0.0..1.0] relative to 1/2 height // flag which decides if the HitArea should be the filled geometry bool mbForceFillForHitTest : 1; + // flag which decides if the presentation object has empty placeholder text or not + bool mbPlaceholderText : 1; // local decomposition. virtual Primitive2DReference create2DDecomposition(const geometry::ViewInformation2D& aViewInformation) const override; @@ -49,7 +51,8 @@ namespace drawinglayer::primitive2d const attribute::SdrLineFillEffectsTextAttribute& rSdrLFSTAttribute, double fCornerRadiusX, double fCornerRadiusY, - bool bForceFillForHitTest); + bool bForceFillForHitTest, + bool bPlaceholderText = false); // data access const basegfx::B2DHomMatrix& getTransform() const { return maTransform; } @@ -57,6 +60,8 @@ namespace drawinglayer::primitive2d double getCornerRadiusX() const { return mfCornerRadiusX; } double getCornerRadiusY() const { return mfCornerRadiusY; } bool getForceFillForHitTest() const { return mbForceFillForHitTest; } + bool getPlaceholderText() const { return mbPlaceholderText; } + // compare operator virtual bool operator==(const BasePrimitive2D& rPrimitive) const override; diff --git a/svx/source/sdr/contact/objectcontactofpageview.cxx b/svx/source/sdr/contact/objectcontactofpageview.cxx index edef3241f38b..e6badd628b7d 100644 --- a/svx/source/sdr/contact/objectcontactofpageview.cxx +++ b/svx/source/sdr/contact/objectcontactofpageview.cxx @@ -60,6 +60,14 @@ namespace sdr::contact : Idle(pDebugName) , mrPageWindow(rPageWindow) { + // Set EditViewActive early at local ViewInformation2D. Usually this + // gets updated at the 1st paint (see updateViewInformation2D calls). + // To be independent of this mechanism and prepared for cases where + // e.g. a HitTest is used before paint, initialize it here already. + // This is the ObjectContact of PageView, so usage is bound to + // EditView visualization anyways + setEditViewActiveEarly(); + // init PreviewRenderer flag setPreviewRenderer(static_cast<SdrPaintView&>(rPageWindow.GetPageView().GetView()).IsPreviewRenderer()); @@ -224,10 +232,10 @@ namespace sdr::contact if (static_cast<SdrPaintView&>(mrPageWindow.GetPageView().GetView()).IsTextEdit()) aNewViewInformation2D.setTextEditActive(true); - if (!isOutputToRecordingMetaFile()) + if (!isOutputToRecordingMetaFile() && !comphelper::LibreOfficeKit::isSlideshowRendering()) { // this is the EditView repaint, provide that information, - // but only if we do not export to metafile + // but only if we do not export to metafile and do not prepare a SlideShow aNewViewInformation2D.setEditViewActive(true); // also copy the current DrawModeFlags diff --git a/svx/source/sdr/contact/viewcontactofsdrrectobj.cxx b/svx/source/sdr/contact/viewcontactofsdrrectobj.cxx index 46cdd21ad0c2..be3cebabbd53 100644 --- a/svx/source/sdr/contact/viewcontactofsdrrectobj.cxx +++ b/svx/source/sdr/contact/viewcontactofsdrrectobj.cxx @@ -78,7 +78,8 @@ void ViewContactOfSdrRectObj::createViewIndependentPrimitive2DSequence(drawingla fCornerRadiusX, fCornerRadiusY, // #i105856# use fill for HitTest when TextFrame and not PickThrough - GetRectObj().IsTextFrame() && !bPickThroughTransparentTextFrames)); + GetRectObj().IsTextFrame() && !bPickThroughTransparentTextFrames, + GetRectObj().IsEmptyPresObj() && !GetRectObj().IsReallyEdited() /*bPlaceholderText*/)); rVisitor.visit(xReference); } diff --git a/svx/source/sdr/primitive2d/sdrrectangleprimitive2d.cxx b/svx/source/sdr/primitive2d/sdrrectangleprimitive2d.cxx index 60cfa24bd8db..d6eb5bb303ae 100644 --- a/svx/source/sdr/primitive2d/sdrrectangleprimitive2d.cxx +++ b/svx/source/sdr/primitive2d/sdrrectangleprimitive2d.cxx @@ -23,6 +23,7 @@ #include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx> #include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx> #include <drawinglayer/primitive2d/groupprimitive2d.hxx> +#include <drawinglayer/primitive2d/exclusiveeditviewprimitive2d.hxx> #include <basegfx/polygon/b2dpolygon.hxx> #include <basegfx/polygon/b2dpolypolygon.hxx> #include <utility> @@ -122,7 +123,20 @@ namespace drawinglayer::primitive2d // add text glow aTempContentText = createEmbeddedTextGlowPrimitive(std::move(aTempContentText), getSdrLFSTAttribute().getGlowText()); } - aRetval.append(std::move(aTempContentText)); + + if (mbPlaceholderText) + { + // PlaceholderText is exclusive to e.g. EditView, so embed it + // accordingly + drawinglayer::primitive2d::Primitive2DReference aEmbedded( + new drawinglayer::primitive2d::ExclusiveEditViewPrimitive2D( + std::move(aTempContentText))); + aRetval.append(std::move(aEmbedded)); + } + else + { + aRetval.append(std::move(aTempContentText)); + } } // add shadow @@ -141,12 +155,14 @@ namespace drawinglayer::primitive2d const attribute::SdrLineFillEffectsTextAttribute& rSdrLFSTAttribute, double fCornerRadiusX, double fCornerRadiusY, - bool bForceFillForHitTest) + bool bForceFillForHitTest, + bool bPlaceholderText) : maTransform(std::move(aTransform)), maSdrLFSTAttribute(rSdrLFSTAttribute), mfCornerRadiusX(fCornerRadiusX), mfCornerRadiusY(fCornerRadiusY), - mbForceFillForHitTest(bForceFillForHitTest) + mbForceFillForHitTest(bForceFillForHitTest), + mbPlaceholderText(bPlaceholderText) { } @@ -160,7 +176,8 @@ namespace drawinglayer::primitive2d && getCornerRadiusY() == rCompare.getCornerRadiusY() && getTransform() == rCompare.getTransform() && getSdrLFSTAttribute() == rCompare.getSdrLFSTAttribute() - && getForceFillForHitTest() == rCompare.getForceFillForHitTest()); + && getForceFillForHitTest() == rCompare.getForceFillForHitTest() + && getPlaceholderText() == rCompare.getPlaceholderText()); } return false; commit aead261e38b6aafd8f1d6487a97b84c12830f027 Author: Caolán McNamara <[email protected]> AuthorDate: Mon Dec 22 09:27:45 2025 +0000 Commit: Andras Timar <[email protected]> CommitDate: Sat Jan 10 13:24:31 2026 +0100 stray incorrect ReplacementModel property Change-Id: I123c3c0a978fa2752ec6285959d9afe68dd15d45 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/196077 Tested-by: Jenkins Reviewed-by: Tomaž Vajngerl <[email protected]> diff --git a/svx/source/unodraw/unoprov.cxx b/svx/source/unodraw/unoprov.cxx index 3eb154880695..fc376a243dcd 100644 --- a/svx/source/unodraw/unoprov.cxx +++ b/svx/source/unodraw/unoprov.cxx @@ -763,7 +763,6 @@ static std::span<SfxItemPropertyMapEntry const> ImplGetSvxTableShapePropertyMap( { u"UseBandingRowStyle"_ustr, OWN_ATTR_TABLETEMPLATE_BANDINGROWS, cppu::UnoType<bool>::get(),0, 0}, { u"UseBandingColumnStyle"_ustr, OWN_ATTR_TABLETEMPLATE_BANDINGCOLUMNS, cppu::UnoType<bool>::get(),0, 0}, { u"ReplacementGraphic"_ustr, OWN_ATTR_REPLACEMENT_GRAPHIC, cppu::UnoType<css::graphic::XGraphic>::get(), css::beans::PropertyAttribute::READONLY, 0}, - { u"ReplacementModel"_ustr, OWN_ATTR_REPLACEMENT_MODEL, cppu::UnoType<css::lang::XComponent>::get(), css::beans::PropertyAttribute::READONLY, 0}, }; return aTableShapePropertyMap_Impl; commit 183ce940677cde9a41985729a91d502728614edf Author: Szymon Kłos <[email protected]> AuthorDate: Tue Dec 16 12:17:48 2025 +0000 Commit: Andras Timar <[email protected]> CommitDate: Sat Jan 10 13:24:31 2026 +0100 lok: show new style from selection in sidebar - not all options are working yet, show only "new form selection" Change-Id: I5d2321c67eac3ec77fe4f5781b190bfd8ee65434 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/195707 (cherry picked from commit 4debae98eab4bc525f517aacb70e47dbd367fff4) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/196419 Reviewed-by: Szymon Kłos <[email protected]> Tested-by: Jenkins diff --git a/sfx2/source/dialog/templdlg.cxx b/sfx2/source/dialog/templdlg.cxx index bf56e5a2c197..4a1e875bc1f7 100644 --- a/sfx2/source/dialog/templdlg.cxx +++ b/sfx2/source/dialog/templdlg.cxx @@ -812,13 +812,20 @@ SfxTemplateDialog_Impl::SfxTemplateDialog_Impl(SfxBindings* pB, SfxTemplatePanel // shown/hidden in SfxTemplateDialog_Impl::ReplaceUpdateButtonByMenu() m_xActionTbR->set_item_help_id(u"new"_ustr, HID_TEMPLDLG_NEWBYEXAMPLE); m_xActionTbR->set_item_help_id(u"newmenu"_ustr, HID_TEMPLDLG_NEWBYEXAMPLE); - m_xActionTbR->set_item_menu(u"newmenu"_ustr, m_xToolMenu.get()); - m_xToolMenu->connect_activate(LINK(this, SfxTemplateDialog_Impl, ToolMenuSelectHdl)); m_xActionTbR->set_item_help_id(u"update"_ustr, HID_TEMPLDLG_UPDATEBYEXAMPLE); // Features not working in LOK yet if (comphelper::LibreOfficeKit::isActive()) - m_xActionTbR->hide(); + { + m_xActionTbR->set_item_visible(u"watercan"_ustr, false); + m_xActionTbR->set_item_visible(u"newmenu"_ustr, false); + m_xActionTbR->set_item_visible(u"update"_ustr, false); + } + else + { + m_xActionTbR->set_item_menu(u"newmenu"_ustr, m_xToolMenu.get()); + m_xToolMenu->connect_activate(LINK(this, SfxTemplateDialog_Impl, ToolMenuSelectHdl)); + } Initialize(); } @@ -865,6 +872,10 @@ void SfxTemplateDialog_Impl::InsertFamilyItem(sal_uInt16 nId, const SfxStyleFami void SfxTemplateDialog_Impl::ReplaceUpdateButtonByMenu() { + // in LOK we don't support all options yet + if (comphelper::LibreOfficeKit::isActive()) + return; + m_xActionTbR->set_item_visible(u"update"_ustr, false); m_xActionTbR->set_item_visible(u"new"_ustr, false); m_xActionTbR->set_item_visible(u"newmenu"_ustr, true); commit 14cf204631fa9093441a557f4c97b1e2fca307ac Author: Caolán McNamara <[email protected]> AuthorDate: Thu Dec 18 12:19:25 2025 +0000 Commit: Andras Timar <[email protected]> CommitDate: Sat Jan 10 13:24:30 2026 +0100 avoid a possible empty aria node if there was no description, only a name, but we end up not using it so only fetch the name for the case that we will use it. Change-Id: I1075bcc3cd054fbf512b240ffe09e17c12a0d868 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/195852 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Miklos Vajna <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/196525 Reviewed-by: Caolán McNamara <[email protected]> Tested-by: Jenkins diff --git a/vcl/source/window/window.cxx b/vcl/source/window/window.cxx index 814a9f76d066..ae5641b8f8be 100644 --- a/vcl/source/window/window.cxx +++ b/vcl/source/window/window.cxx @@ -3405,25 +3405,16 @@ void Window::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter) if (pAccLabelledBy) rJsonWriter.put("labelledBy", pAccLabelledBy->get_id()); - OUString sAccName = GetAccessibleName(); + OUString sAccName = (!pAccLabelFor && !pAccLabelledBy) ? GetAccessibleName() : OUString(); OUString sAccDesc = GetAccessibleDescription(); if (!sAccName.isEmpty() || !sAccDesc.isEmpty()) { auto aAria = rJsonWriter.startNode("aria"); - if (!sAccDesc.isEmpty()) - { rJsonWriter.put("description", sAccDesc); - } - - if(!pAccLabelFor && !pAccLabelledBy) - { - if (!sAccName.isEmpty()) - { - rJsonWriter.put("label", sAccName); - } - } + if (!sAccName.isEmpty()) + rJsonWriter.put("label", sAccName); } mpWindowImpl->maDumpAsPropertyTreeHdl.Call(rJsonWriter); commit 094c7f60aebdd373e44a15cdc286da80fe8685da Author: Henry Castro <[email protected]> AuthorDate: Tue Dec 16 10:41:03 2025 -0400 Commit: Andras Timar <[email protected]> CommitDate: Sat Jan 10 13:24:30 2026 +0100 lok: a11y: fix the accessible description property The accessible description is useful for setting the image alt attribute on the client side. Change-Id: I86f4e8b6486d89c446019339699ab030dccb6c0f Signed-off-by: Henry Castro <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/195725 Tested-by: Caolán McNamara <[email protected]> Reviewed-by: Caolán McNamara <[email protected]> Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/196524 Tested-by: Jenkins diff --git a/vcl/source/window/window.cxx b/vcl/source/window/window.cxx index b8af7b685dcb..814a9f76d066 100644 --- a/vcl/source/window/window.cxx +++ b/vcl/source/window/window.cxx @@ -3405,18 +3405,24 @@ void Window::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter) if (pAccLabelledBy) rJsonWriter.put("labelledBy", pAccLabelledBy->get_id()); - if(!pAccLabelFor && !pAccLabelledBy) + OUString sAccName = GetAccessibleName(); + OUString sAccDesc = GetAccessibleDescription(); + + if (!sAccName.isEmpty() || !sAccDesc.isEmpty()) { - OUString sAccName = GetAccessibleName(); - OUString sAccDesc = GetAccessibleDescription(); + auto aAria = rJsonWriter.startNode("aria"); + + if (!sAccDesc.isEmpty()) + { + rJsonWriter.put("description", sAccDesc); + } - if (!sAccName.isEmpty() || !sAccDesc.isEmpty()) + if(!pAccLabelFor && !pAccLabelledBy) { - auto aAria = rJsonWriter.startNode("aria"); if (!sAccName.isEmpty()) + { rJsonWriter.put("label", sAccName); - if (!sAccDesc.isEmpty()) - rJsonWriter.put("description", sAccDesc); + } } } commit 0005a9541cca51193d1a10d81575b594c29a4a6f Author: Caolán McNamara <[email protected]> AuthorDate: Fri Dec 12 16:42:55 2025 +0000 Commit: Andras Timar <[email protected]> CommitDate: Sat Jan 10 13:24:30 2026 +0100 add org.libreoffice.uitest.UITest to headless Change-Id: Icc3d22570e43a76bc352c1c88dc3cde4feaea1c2 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/195575 Tested-by: Jenkins Reviewed-by: Caolán McNamara <[email protected]> diff --git a/vcl/vcl.common.component.headless b/vcl/vcl.common.component.headless index e92b54e7ca1b..7b522b79dc0a 100644 --- a/vcl/vcl.common.component.headless +++ b/vcl/vcl.common.component.headless @@ -5,4 +5,5 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. com.sun.star.datatransfer.VCLGenericClipboard com.sun.star.frame.VCLSessionManagerClient +org.libreoffice.uitest.UITest vcl::FontIdentificator commit 1332693850eb2f8d50199980921ee5465ccf449d Author: Caolán McNamara <[email protected]> AuthorDate: Thu Dec 11 11:50:40 2025 +0000 Commit: Andras Timar <[email protected]> CommitDate: Sat Jan 10 13:24:30 2026 +0100 add the names of the writer dialog .ui files that are missing from coverage Change-Id: I1f54dc2197ced0d941df3581bfe6b1db2e357274 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/195451 Reviewed-by: Miklos Vajna <[email protected]> Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/196523 Tested-by: Jenkins Reviewed-by: Caolán McNamara <[email protected]> diff --git a/vcl/inc/jsdialog/enabled.hxx b/vcl/inc/jsdialog/enabled.hxx index 65ccc5b14897..857585a9c58d 100644 --- a/vcl/inc/jsdialog/enabled.hxx +++ b/vcl/inc/jsdialog/enabled.hxx @@ -26,7 +26,8 @@ bool isBuilderEnabledForNavigator(std::u16string_view rUIFile); bool isBuilderEnabledForQuickFind(std::u16string_view rUIFile); bool isInterimBuilderEnabledForNotebookbar(std::u16string_view rUIFile); -bool completeWriterDialogList(const o3tl::sorted_vector<OUString>& entries); +// returns vector of .ui files not seen that should be seen to have complete coverage +std::vector<OUString> completeWriterDialogList(const o3tl::sorted_vector<OUString>& entries); } /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/vcl/jsdialog/enabled.cxx b/vcl/jsdialog/enabled.cxx index 374ccc9fe309..01b6ddf659ba 100644 --- a/vcl/jsdialog/enabled.cxx +++ b/vcl/jsdialog/enabled.cxx @@ -632,14 +632,16 @@ bool isBuilderEnabledForFormulabar(std::u16string_view rUIFile) return isInMap(FormulabarList, rUIFile); } -bool completeWriterDialogList(const o3tl::sorted_vector<OUString>& entries) +std::vector<OUString> completeWriterDialogList(const o3tl::sorted_vector<OUString>& entries) { + std::vector<OUString> missing; for (const auto& entry : SwriterDialogList) { - if (!entries.contains(OUString(entry))) - return false; + OUString sEntry(entry); + if (!entries.contains(sEntry)) + missing.push_back(sEntry); } - return true; + return missing; } } // end of jsdialog diff --git a/vcl/source/window/builder.cxx b/vcl/source/window/builder.cxx index 150f922faa26..3486f1c0d118 100644 --- a/vcl/source/window/builder.cxx +++ b/vcl/source/window/builder.cxx @@ -199,13 +199,21 @@ void Application::UICoverageReport(tools::JsonWriter& rJson) auto resultNode = rJson.startNode("result"); const auto& entries = ImplGetSVData()->mpDefInst->getUsedUIList(); + if (!entries.empty()) { auto childrenNode = rJson.startArray("used"); for (const auto& entry : entries) rJson.putSimpleValue(entry); } - rJson.put("CompleteWriterDialogCoverage", jsdialog::completeWriterDialogList(entries)); + std::vector<OUString> missingWriterDialogUIs = jsdialog::completeWriterDialogList(entries); + rJson.put("CompleteWriterDialogCoverage", missingWriterDialogUIs.empty()); + if (!missingWriterDialogUIs.empty()) + { + auto childrenNode = rJson.startArray("MissingWriterDialogCoverage"); + for (const auto& entry : missingWriterDialogUIs) + rJson.putSimpleValue(entry); + } } std::unique_ptr<weld::Builder> Application::CreateBuilder(weld::Widget* pParent, const OUString &rUIFile, bool bMobile, sal_uInt64 nLOKWindowId) commit cbdb86db897d5a08fb6d2670f239728709744733 Author: Caolán McNamara <[email protected]> AuthorDate: Tue Dec 9 16:28:51 2025 +0000 Commit: Andras Timar <[email protected]> CommitDate: Sat Jan 10 13:24:30 2026 +0100 rename o3tl::sorted_vector::count() to contains() arguably more in line with contemporary naming Change-Id: I25b194b12a17e79bc6bc1052320a6b2497c4107f Reviewed-on: https://gerrit.libreoffice.org/c/core/+/195313 Reviewed-by: Miklos Vajna <[email protected]> Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/195366 Tested-by: Jenkins Reviewed-by: Caolán McNamara <[email protected]> diff --git a/chart2/source/controller/main/CommandDispatchContainer.cxx b/chart2/source/controller/main/CommandDispatchContainer.cxx index e76afa295b12..b1adafced570 100644 --- a/chart2/source/controller/main/CommandDispatchContainer.cxx +++ b/chart2/source/controller/main/CommandDispatchContainer.cxx @@ -113,7 +113,7 @@ Reference< frame::XDispatch > CommandDispatchContainer::getDispatchForURL( m_aToBeDisposedDispatches.push_back(pDispatch); return pDispatch; } - if (s_aContainerDocumentCommands.count(rURL.Path) > 0) + if (s_aContainerDocumentCommands.contains(rURL.Path)) { // ToDo: can those dispatches be cached? return cacheIt(getContainerDispatchForURL(xModel->getCurrentController(), rURL)); @@ -122,7 +122,7 @@ Reference< frame::XDispatch > CommandDispatchContainer::getDispatchForURL( if (m_xChartDispatcher.is() && (m_xChartDispatcher->commandHandled(rURL.Complete) - || m_aAdditionalChartCommands.count(rURL.Path) > 0)) + || m_aAdditionalChartCommands.contains(rURL.Path))) return cacheIt(m_xChartDispatcher); // #i12587# support for shapes in chart diff --git a/editeng/source/editeng/impedit3.cxx b/editeng/source/editeng/impedit3.cxx index 942622090103..fca52b933676 100644 --- a/editeng/source/editeng/impedit3.cxx +++ b/editeng/source/editeng/impedit3.cxx @@ -395,7 +395,7 @@ void ImpEditEngine::FormatDoc() if (!aRepaintParagraphList.empty()) { auto CombineRepaintParasAreas = [&](const LineAreaInfo& rInfo) { - if (aRepaintParagraphList.count(rInfo.nPortion)) + if (aRepaintParagraphList.contains(rInfo.nPortion)) maInvalidRect.Union(rInfo.aArea); return CallbackResult::Continue; }; diff --git a/include/o3tl/sorted_vector.hxx b/include/o3tl/sorted_vector.hxx index 3d26034e2a0e..7afcf4782c25 100644 --- a/include/o3tl/sorted_vector.hxx +++ b/include/o3tl/sorted_vector.hxx @@ -221,9 +221,9 @@ public: return (ret.second) ? ret.first : m_vector.end(); } - size_type count(const Value& v) const + bool contains(const Value& v) const { - return find(v) != end() ? 1 : 0; + return find(v) != end(); } bool operator==(const sorted_vector & other) const diff --git a/sc/source/core/tool/recursionhelper.cxx b/sc/source/core/tool/recursionhelper.cxx index 59601f37a0a6..3055fc78d3d8 100644 --- a/sc/source/core/tool/recursionhelper.cxx +++ b/sc/source/core/tool/recursionhelper.cxx @@ -230,7 +230,7 @@ void ScRecursionHelper::CleanTemporaryGroupCells() bool ScRecursionHelper::CheckFGIndependence(ScFormulaCellGroup* pFG) { - if (pFGSet && pFGSet->count(pFG)) + if (pFGSet && pFGSet->contains(pFG)) { bGroupsIndependent = false; return false; diff --git a/sc/source/filter/excel/xetable.cxx b/sc/source/filter/excel/xetable.cxx index 3b3981f118c5..e28f6b6e657f 100644 --- a/sc/source/filter/excel/xetable.cxx +++ b/sc/source/filter/excel/xetable.cxx @@ -262,7 +262,7 @@ XclExpShrfmlaRef XclExpShrfmlaBuffer::CreateOrExtendShrfmla( return xRec; // Check to see if this shared formula contains any tokens that Excel's shared formula cannot handle. - if (maBadTokens.count(pShrdScTokArr) > 0) + if (maBadTokens.contains(pShrdScTokArr)) // Already on the black list. Skip it. return xRec; diff --git a/sd/source/core/sdpage.cxx b/sd/source/core/sdpage.cxx index 6eb5138ca154..a5cea90e493f 100644 --- a/sd/source/core/sdpage.cxx +++ b/sd/source/core/sdpage.cxx @@ -1723,7 +1723,7 @@ void SdPage::SetAutoLayout(AutoLayout eLayout, bool bInit, bool bCreate ) rtl::Reference<SdrObject> pObj; while( (pObj = maPresentationShapeList.getNextShape()) ) { - if( aUsedPresentationObjects.count(pObj.get()) == 0 ) + if (!aUsedPresentationObjects.contains(pObj.get())) { if( pObj->IsEmptyPresObj() ) diff --git a/sw/source/core/access/accmap.cxx b/sw/source/core/access/accmap.cxx index 33f1e5b31d13..19c3e9d40421 100644 --- a/sw/source/core/access/accmap.cxx +++ b/sw/source/core/access/accmap.cxx @@ -1273,7 +1273,7 @@ void SwAccessibleMap::InvalidateShapeInParaSelection() { m_setParaAdd.insert(pAccPara); } - else if(m_setParaAdd.count(pAccPara) == 0) + else if (!m_setParaAdd.contains(pAccPara)) { m_setParaRemove.insert(pAccPara); } @@ -1531,7 +1531,7 @@ void SwAccessibleMap::DoInvalidateShapeSelection(bool bInvalidateFocusMode /*=fa || xParaContext->getAccessibleRole() == AccessibleRole::BLOCK_QUOTE)) { SwAccessibleParagraph* pAccPara = static_cast< SwAccessibleParagraph *>(xPara.get()); - if (m_setParaAdd.count(pAccPara) == 0 ) + if (!m_setParaAdd.contains(pAccPara)) { m_setParaRemove.insert(pAccPara); } diff --git a/sw/source/core/doc/docnew.cxx b/sw/source/core/doc/docnew.cxx index 5b8120ca973d..6df58032f473 100644 --- a/sw/source/core/doc/docnew.cxx +++ b/sw/source/core/doc/docnew.cxx @@ -977,7 +977,7 @@ static bool lcl_PageDescOrFollowContainsHeaderFooter(const SwPageDesc& rPageDesc // remember already checked page descs to avoid cycle o3tl::sorted_vector<const SwPageDesc*> aCheckedPageDescs; const SwPageDesc* pCurPageDesc = &rPageDesc; - while (aCheckedPageDescs.count(pCurPageDesc) == 0) + while (!aCheckedPageDescs.contains(pCurPageDesc)) { const SwFrameFormat& rMaster = pCurPageDesc->GetMaster(); if (rMaster.GetHeader().IsActive() || rMaster.GetFooter().IsActive()) diff --git a/sw/source/core/undo/rolbck.cxx b/sw/source/core/undo/rolbck.cxx index c961e6d539b6..7d10a2624ec0 100644 --- a/sw/source/core/undo/rolbck.cxx +++ b/sw/source/core/undo/rolbck.cxx @@ -857,7 +857,7 @@ SwHistorySetAttrSet::SwHistorySetAttrSet( for (SfxItemIter aIter(rSet); !aIter.IsAtEnd(); aIter.NextItem()) { // check if Item is intended to be contained - if (rSetArr.count(aIter.GetCurWhich())) + if (rSetArr.contains(aIter.GetCurWhich())) { // do include item, but take care of some 'special' cases switch (aIter.GetCurWhich()) @@ -1436,7 +1436,7 @@ void SwRegHistory::SwClientNotify(const SwModify&, const SfxHint& rHint) } else if (const SfxPoolItem* pItem = SfxItemIter(rSet).GetCurItem()) { - if ( m_WhichIdSet.count( pItem->Which() ) ) + if (m_WhichIdSet.contains(pItem->Which())) { pNewHstr.reset( new SwHistorySetFormat( pItem, m_nNodeIndex ) ); } diff --git a/sw/source/core/view/viewpg.cxx b/sw/source/core/view/viewpg.cxx index fd9b0969d88c..535fb40000d3 100644 --- a/sw/source/core/view/viewpg.cxx +++ b/sw/source/core/view/viewpg.cxx @@ -79,8 +79,8 @@ void SwViewShell::PrintProspect( std::pair< sal_Int32, sal_Int32 > rPagesToPrint = rPrintData.GetRenderData().GetPagePairsForProspectPrinting()[ nRenderer ]; - OSL_ENSURE( rPagesToPrint.first == -1 || rPrintData.GetRenderData().GetValidPagesSet().count( rPagesToPrint.first ) == 1, "first Page not valid" ); - OSL_ENSURE( rPagesToPrint.second == -1 || rPrintData.GetRenderData().GetValidPagesSet().count( rPagesToPrint.second ) == 1, "second Page not valid" ); + OSL_ENSURE( rPagesToPrint.first == -1 || rPrintData.GetRenderData().GetValidPagesSet().contains( rPagesToPrint.first ), "first Page not valid" ); + OSL_ENSURE( rPagesToPrint.second == -1 || rPrintData.GetRenderData().GetValidPagesSet().contains( rPagesToPrint.second ), "second Page not valid" ); // create a new shell for the printer SwViewShell aShell( *this, nullptr, pPrinter ); diff --git a/sw/source/core/view/vprint.cxx b/sw/source/core/view/vprint.cxx index ac4d85997fd0..337e6e3fbd37 100644 --- a/sw/source/core/view/vprint.cxx +++ b/sw/source/core/view/vprint.cxx @@ -490,7 +490,7 @@ bool SwViewShell::PrintOrPDFExport( const sal_Int32 nPage = rPrintData.GetRenderData().GetPagesToPrint()[ nRenderer ]; OSL_ENSURE( nPage < 0 || - rPrintData.GetRenderData().GetValidPagesSet().count( nPage ) == 1, + rPrintData.GetRenderData().GetValidPagesSet().contains(nPage), "SwViewShell::PrintOrPDFExport: nPage not valid" ); SwViewShell *const pViewSh2 = (nPage < 0) ? rPrintData.GetRenderData().m_pPostItShell.get()// post-it page diff --git a/vcl/jsdialog/enabled.cxx b/vcl/jsdialog/enabled.cxx index 369cef05218f..374ccc9fe309 100644 --- a/vcl/jsdialog/enabled.cxx +++ b/vcl/jsdialog/enabled.cxx @@ -636,7 +636,7 @@ bool completeWriterDialogList(const o3tl::sorted_vector<OUString>& entries) { for (const auto& entry : SwriterDialogList) { - if (entries.find(OUString(entry)) == entries.end()) + if (!entries.contains(OUString(entry))) return false; } return true; diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx index 7b07bc9b62f9..c2ec14eb68c3 100644 --- a/vcl/source/app/salvtables.cxx +++ b/vcl/source/app/salvtables.cxx @@ -3552,7 +3552,7 @@ void SalInstanceTreeView::set_font_color(SvTreeListEntry* pEntry, const Color& r void SalInstanceTreeView::AddStringItem(SvTreeListEntry* pEntry, const OUString& rStr, int nCol) { auto xCell = std::make_unique<SvLBoxString>(rStr); - if (m_aCustomRenders.count(nCol)) + if (m_aCustomRenders.contains(nCol)) xCell->SetCustomRender(); pEntry->AddItem(std::move(xCell)); } @@ -4674,7 +4674,7 @@ bool SalInstanceTreeView::get_row_expanded(const weld::TreeIter& rIter) const bool SalInstanceTreeView::get_children_on_demand(const weld::TreeIter& rIter) const { const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter); - if (m_aExpandingPlaceHolderParents.count(rVclIter.iter)) + if (m_aExpandingPlaceHolderParents.contains(rVclIter.iter)) return true; return GetPlaceHolderChild(rVclIter.iter) != nullptr; } diff --git a/vcl/unx/gtk3/gtkinst.cxx b/vcl/unx/gtk3/gtkinst.cxx index e44d8ef516f2..10aa23fe425d 100644 --- a/vcl/unx/gtk3/gtkinst.cxx +++ b/vcl/unx/gtk3/gtkinst.cxx @@ -14171,7 +14171,7 @@ private: bool child_is_placeholder(GtkInstanceTreeIter& rGtkIter) const { GtkTreePath* pPath = gtk_tree_model_get_path(m_pTreeModel, &rGtkIter.iter); - bool bExpanding = m_aExpandingPlaceHolderParents.count(pPath); + bool bExpanding = m_aExpandingPlaceHolderParents.contains(pPath); gtk_tree_path_free(pPath); if (bExpanding) return true; commit a5825a408754c739b4ee9b21d1ec54f043cc1523 Author: Caolán McNamara <[email protected]> AuthorDate: Tue Dec 2 08:21:17 2025 +0000 Commit: Andras Timar <[email protected]> CommitDate: Sat Jan 10 13:24:30 2026 +0100 optimize relative conditional formatting effort cache FormulaCells that the relative conditional formatting needs to avoid regenerating them constantly on scrolling. Use something size bounded (lru_map) to avoid potentially creating a massive spreadsheet-sized list of formula cells. Register the cache with the usual cache machinery so they can be dropped on memory pressure/idle. Change-Id: I38dca513791347558225432af0ceda94a7b2742e Reviewed-on: https://gerrit.libreoffice.org/c/core/+/195317 Tested-by: Jenkins Reviewed-by: Caolán McNamara <[email protected]> diff --git a/include/o3tl/lru_map.hxx b/include/o3tl/lru_map.hxx index 65268ea85b4d..64428d568f64 100644 --- a/include/o3tl/lru_map.hxx +++ b/include/o3tl/lru_map.hxx @@ -205,7 +205,7 @@ public: checkLRUMaxSize(); } - void insert(key_value_pair_t& rPair) + list_const_iterator_t insert(key_value_pair_t& rPair) { map_iterator_t i = mLruMap.find(rPair.first); @@ -230,9 +230,11 @@ public: mLruList.splice(mLruList.begin(), mLruList, i->second); checkLRUItemUpdate(); } + + return mLruList.cbegin(); } - void insert(key_value_pair_t&& rPair) + list_const_iterator_t insert(key_value_pair_t&& rPair) { map_iterator_t i = mLruMap.find(rPair.first); @@ -256,6 +258,8 @@ public: mLruList.splice(mLruList.begin(), mLruList, i->second); checkLRUItemUpdate(); } + + return mLruList.cbegin(); } list_const_iterator_t find(const Key& key) @@ -301,6 +305,12 @@ public: return mLruMap.size(); } + size_t empty() const + { + assert(mLruMap.empty() == mLruList.empty()); + return mLruMap.empty(); + } + // size_t total_size() const; - only if custom ValueSize void clear() diff --git a/sc/inc/conditio.hxx b/sc/inc/conditio.hxx index f38b81cc999e..35252a185067 100644 --- a/sc/inc/conditio.hxx +++ b/sc/inc/conditio.hxx @@ -34,6 +34,8 @@ #include <rtl/math.hxx> #include <tools/date.hxx> #include <tools/link.hxx> +#include <o3tl/lru_map.hxx> +#include <vcl/dropcache.hxx> #include <optional> #include <map> @@ -301,7 +303,7 @@ public: } }; -class SAL_DLLPUBLIC_RTTI ScConditionEntry : public ScFormatEntry +class SAL_DLLPUBLIC_RTTI ScConditionEntry : public ScFormatEntry, public CacheOwner { // stored data: ScConditionMode eOp; @@ -323,6 +325,9 @@ class SAL_DLLPUBLIC_RTTI ScConditionEntry : public ScFormatEntry OUString aSrcString; // formula source position as text during XML import std::unique_ptr<ScFormulaCell> pFCell1; std::unique_ptr<ScFormulaCell> pFCell2; + typedef o3tl::lru_map<ScAddress, std::unique_ptr<ScFormulaCell>> RelRefCells; + std::unique_ptr<RelRefCells> xRelRefCells1; + std::unique_ptr<RelRefCells> xRelRefCells2; bool bRelRef1; bool bRelRef2; bool bFirstRun; @@ -346,6 +351,8 @@ class SAL_DLLPUBLIC_RTTI ScConditionEntry : public ScFormatEntry bool IsValidStr( const OUString& rArg, const ScAddress& rPos ) const; void StartListening(); + static std::unique_ptr<RelRefCells> makeRelRefCells(); + public: ScConditionEntry( ScConditionMode eOper, const OUString& rExpr1, const OUString& rExpr2, @@ -401,6 +408,10 @@ public: virtual void UpdateDeleteTab( sc::RefUpdateDeleteTabContext& rCxt ) override; virtual void UpdateMoveTab( sc::RefUpdateMoveTabContext& rCxt ) override; + virtual bool dropCaches() override; + virtual void dumpState(rtl::OStringBuffer& rState) override; + virtual OUString getCacheName() const override; + bool MarkUsedExternalReferences() const; virtual Type GetType() const override { return eConditionType; } diff --git a/sc/source/core/data/conditio.cxx b/sc/source/core/data/conditio.cxx index 76afe0e67a30..58f2b09030ee 100644 --- a/sc/source/core/data/conditio.cxx +++ b/sc/source/core/data/conditio.cxx @@ -450,7 +450,9 @@ void ScConditionEntry::SetCaseSensitive(bool bSet) void ScConditionEntry::CompileAll() { pFCell1.reset(); + xRelRefCells1.reset(); pFCell2.reset(); + xRelRefCells2.reset(); } void ScConditionEntry::CompileXML() @@ -545,7 +547,11 @@ void ScConditionEntry::UpdateReference( sc::RefUpdateContext& rCxt ) } if (aRes.mbReferenceModified || bChangedPos) - pFCell1.reset(); // is created again in IsValid + { + // is created again in IsValid + pFCell1.reset(); + xRelRefCells1.reset(); + } } if (pFormula2) @@ -564,7 +570,11 @@ void ScConditionEntry::UpdateReference( sc::RefUpdateContext& rCxt ) } if (aRes.mbReferenceModified || bChangedPos) - pFCell2.reset(); // is created again in IsValid + { + // is created again in IsValid + pFCell2.reset(); + xRelRefCells2.reset(); + } } StartListening(); @@ -576,12 +586,14 @@ void ScConditionEntry::UpdateInsertTab( sc::RefUpdateInsertTabContext& rCxt ) { pFormula1->AdjustReferenceOnInsertedTab(rCxt, aSrcPos); pFCell1.reset(); + xRelRefCells1.reset(); } if (pFormula2) { pFormula2->AdjustReferenceOnInsertedTab(rCxt, aSrcPos); pFCell2.reset(); + xRelRefCells2.reset(); } ScRangeUpdater::UpdateInsertTab(aSrcPos, rCxt); @@ -593,12 +605,14 @@ void ScConditionEntry::UpdateDeleteTab( sc::RefUpdateDeleteTabContext& rCxt ) { pFormula1->AdjustReferenceOnDeletedTab(rCxt, aSrcPos); pFCell1.reset(); + xRelRefCells1.reset(); } if (pFormula2) { pFormula2->AdjustReferenceOnDeletedTab(rCxt, aSrcPos); pFCell2.reset(); + xRelRefCells2.reset(); } ScRangeUpdater::UpdateDeleteTab(aSrcPos, rCxt); @@ -615,6 +629,7 @@ void ScConditionEntry::UpdateMoveTab(sc::RefUpdateMoveTabContext& rCxt) if (aRes.mbValueChanged) aResFinal.mnTab = aRes.mnTab; pFCell1.reset(); + xRelRefCells1.reset(); } if (pFormula2) @@ -623,6 +638,7 @@ void ScConditionEntry::UpdateMoveTab(sc::RefUpdateMoveTabContext& rCxt) if (aRes.mbValueChanged) aResFinal.mnTab = aRes.mnTab; pFCell2.reset(); + xRelRefCells2.reset(); } if (aResFinal.mnTab != aSrcPos.Tab()) @@ -669,6 +685,12 @@ bool ScConditionEntry::IsEqual( const ScFormatEntry& rOther, bool bIgnoreSrcPos return true; } +//static +std::unique_ptr<ScConditionEntry::RelRefCells> ScConditionEntry::makeRelRefCells() +{ + return std::make_unique<RelRefCells>(0x9fff); +} + void ScConditionEntry::Interpret( const ScAddress& rPos ) { // Create formula cells @@ -679,16 +701,25 @@ void ScConditionEntry::Interpret( const ScAddress& rPos ) // Evaluate formulas bool bDirty = false; // 1 and 2 separate? - std::optional<ScFormulaCell> oTemp; ScFormulaCell* pEff1 = pFCell1.get(); if ( bRelRef1 ) { - if (pFormula1) - oTemp.emplace(mrDoc, rPos, *pFormula1); + if (!xRelRefCells1) + xRelRefCells1 = makeRelRefCells(); + auto iFind = xRelRefCells1->find(rPos); + if (iFind != xRelRefCells1->end()) + pEff1 = iFind->second.get(); else - oTemp.emplace(mrDoc, rPos); - pEff1 = &*oTemp; - pEff1->SetFreeFlying(true); + { + std::unique_ptr<ScFormulaCell> xCell; + if (pFormula1) + xCell = std::make_unique<ScFormulaCell>(mrDoc, rPos, *pFormula1); + else + xCell = std::make_unique<ScFormulaCell>(mrDoc, rPos); + xCell->SetFreeFlying(true); + xCell->StartListeningTo(mrDoc); + pEff1 = xRelRefCells1->insert(std::make_pair(rPos, std::move(xCell)))->second.get(); + } } if ( pEff1 ) { @@ -711,17 +742,26 @@ void ScConditionEntry::Interpret( const ScAddress& rPos ) } } } - oTemp.reset(); ScFormulaCell* pEff2 = pFCell2.get(); //@ 1!=2 if ( bRelRef2 ) { - if (pFormula2) - oTemp.emplace(mrDoc, rPos, *pFormula2); + if (!xRelRefCells2) + xRelRefCells2 = makeRelRefCells(); + auto iFind = xRelRefCells2->find(rPos); + if (iFind != xRelRefCells2->end()) + pEff2 = iFind->second.get(); else - oTemp.emplace(mrDoc, rPos); - pEff2 = &*oTemp; - pEff2->SetFreeFlying(true); + { + std::unique_ptr<ScFormulaCell> xCell; + if (pFormula2) + xCell = std::make_unique<ScFormulaCell>(mrDoc, rPos, *pFormula2); + else + xCell = std::make_unique<ScFormulaCell>(mrDoc, rPos); + xCell->SetFreeFlying(true); + xCell->StartListeningTo(mrDoc); + pEff2 = xRelRefCells2->insert(std::make_pair(rPos, std::move(xCell)))->second.get(); + } } if ( pEff2 ) { @@ -743,7 +783,6 @@ void ScConditionEntry::Interpret( const ScAddress& rPos ) } } } - oTemp.reset(); // If IsRunning, the last values remain if (bDirty && !bFirstRun) @@ -1558,16 +1597,47 @@ ScFormatEntry* ScCondFormatEntry::Clone( ScDocument& rDoc ) const void ScConditionEntry::CalcAll() { - if (pFCell1 || pFCell2) + if (pFCell1 || pFCell2 || xRelRefCells1 || !xRelRefCells2) { if (pFCell1) pFCell1->SetDirty(); + if (xRelRefCells1) + { + for (auto& rEntry : *xRelRefCells1) + rEntry.second->SetDirty(); + } if (pFCell2) pFCell2->SetDirty(); + if (xRelRefCells2) + { + for (auto& rEntry : *xRelRefCells2) + rEntry.second->SetDirty(); + } pCondFormat->DoRepaint(); } } +OUString ScConditionEntry::getCacheName() const +{ + return "ScConditionEntry"; +} + +bool ScConditionEntry::dropCaches() +{ + xRelRefCells1.reset(); + xRelRefCells2.reset(); + return true; +} + +void ScConditionEntry::dumpState(rtl::OStringBuffer& rState) +{ + rState.append(" ScConditionEntry:"); + rState.append(" rel ref cells1: "); + rState.append(xRelRefCells1 ? static_cast<sal_Int32>(xRelRefCells1->size()) : 0); + rState.append(" rel ref cells2: "); + rState.append(xRelRefCells2 ? static_cast<sal_Int32>(xRelRefCells2->size()) : 0); +} + ScCondDateFormatEntry::ScCondDateFormatEntry( ScDocument& rDoc ) : ScFormatEntry( rDoc ) , meType(condformat::TODAY) commit 6090f4fc52a8963dfcdfea4b8cede0d8cde914ae Author: Caolán McNamara <[email protected]> AuthorDate: Mon Dec 8 12:33:49 2025 +0000 Commit: Andras Timar <[email protected]> CommitDate: Sat Jan 10 13:24:30 2026 +0100 add writer dialog coverage report Change-Id: I5430d2272a623a4f2ae886ae009d70ca92ad1430 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/195227 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Miklos Vajna <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/195316 Tested-by: Jenkins Reviewed-by: Caolán McNamara <[email protected]> diff --git a/vcl/inc/jsdialog/enabled.hxx b/vcl/inc/jsdialog/enabled.hxx index 31dad161b48f..65ccc5b14897 100644 --- a/vcl/inc/jsdialog/enabled.hxx +++ b/vcl/inc/jsdialog/enabled.hxx @@ -10,6 +10,7 @@ #pragma once #include <string_view> +#include <o3tl/sorted_vector.hxx> namespace jsdialog { @@ -24,6 +25,8 @@ bool isBuilderEnabledForFormulabar(std::u16string_view rUIFile); bool isBuilderEnabledForNavigator(std::u16string_view rUIFile); bool isBuilderEnabledForQuickFind(std::u16string_view rUIFile); bool isInterimBuilderEnabledForNotebookbar(std::u16string_view rUIFile); + +bool completeWriterDialogList(const o3tl::sorted_vector<OUString>& entries); } /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/vcl/jsdialog/enabled.cxx b/vcl/jsdialog/enabled.cxx index ec5f451ee7e6..369cef05218f 100644 --- a/vcl/jsdialog/enabled.cxx +++ b/vcl/jsdialog/enabled.cxx @@ -631,6 +631,17 @@ bool isBuilderEnabledForFormulabar(std::u16string_view rUIFile) { return isInMap(FormulabarList, rUIFile); } + +bool completeWriterDialogList(const o3tl::sorted_vector<OUString>& entries) +{ + for (const auto& entry : SwriterDialogList) + { + if (entries.find(OUString(entry)) == entries.end()) + return false; + } + return true; +} + } // end of jsdialog /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/vcl/source/window/builder.cxx b/vcl/source/window/builder.cxx index 30e881eacb07..150f922faa26 100644 --- a/vcl/source/window/builder.cxx +++ b/vcl/source/window/builder.cxx @@ -204,6 +204,8 @@ void Application::UICoverageReport(tools::JsonWriter& rJson) for (const auto& entry : entries) rJson.putSimpleValue(entry); } + + rJson.put("CompleteWriterDialogCoverage", jsdialog::completeWriterDialogList(entries)); } std::unique_ptr<weld::Builder> Application::CreateBuilder(weld::Widget* pParent, const OUString &rUIFile, bool bMobile, sal_uInt64 nLOKWindowId) commit 8d1a3531e5972b2e146d8a769116ade72348cfcf Author: Caolán McNamara <[email protected]> AuthorDate: Mon Dec 8 12:11:41 2025 +0000 Commit: Andras Timar <[email protected]> CommitDate: Sat Jan 10 13:24:30 2026 +0100 put the uicoverage into the first level json i.e. don't put json into json Change-Id: I5606c0d280e7f8c3c08cc21e1bc62689de7422bf Reviewed-on: https://gerrit.libreoffice.org/c/core/+/195226 Reviewed-by: Miklos Vajna <[email protected]> Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/195315 Tested-by: Jenkins Reviewed-by: Caolán McNamara <[email protected]> diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx index ee43babf868e..009a57499e26 100644 --- a/desktop/source/lib/init.cxx +++ b/desktop/source/lib/init.cxx @@ -5634,7 +5634,7 @@ static void doc_postUnoCommand(LibreOfficeKitDocument* pThis, const char* pComma tools::JsonWriter aJson; aJson.put("commandName", aCommand); aJson.put("success", true); - aJson.put("result", Application::UICoverageReport()); + Application::UICoverageReport(aJson); pDocument->mpCallbackFlushHandlers[nView]->queue(LOK_CALLBACK_UNO_COMMAND_RESULT, aJson.finishAndGetAsOString()); } } diff --git a/include/vcl/svapp.hxx b/include/vcl/svapp.hxx index 2bfbc02a104f..5b4e079c958e 100644 --- a/include/vcl/svapp.hxx +++ b/include/vcl/svapp.hxx @@ -45,6 +45,7 @@ class Bitmap; +namespace tools { class JsonWriter; } namespace weld { class Builder; @@ -1241,7 +1242,7 @@ public: static void EnableUICoverage(bool bEnable); /** Report on what .ui files were used*/ - static OString UICoverageReport(); + static void UICoverageReport(tools::JsonWriter& rJson); ///@} diff --git a/vcl/source/window/builder.cxx b/vcl/source/window/builder.cxx index f73a8b444653..30e881eacb07 100644 --- a/vcl/source/window/builder.cxx +++ b/vcl/source/window/builder.cxx @@ -194,18 +194,16 @@ void Application::EnableUICoverage(bool bEnable) ImplGetSVData()->mpDefInst->getUsedUIList().clear(); } -OString Application::UICoverageReport() +void Application::UICoverageReport(tools::JsonWriter& rJson) { - tools::JsonWriter aJson; + auto resultNode = rJson.startNode("result"); const auto& entries = ImplGetSVData()->mpDefInst->getUsedUIList(); { - auto childrenNode = aJson.startArray("used"); + auto childrenNode = rJson.startArray("used"); for (const auto& entry : entries) - aJson.putSimpleValue(entry); + rJson.putSimpleValue(entry); } - - return aJson.finishAndGetAsOString(); } std::unique_ptr<weld::Builder> Application::CreateBuilder(weld::Widget* pParent, const OUString &rUIFile, bool bMobile, sal_uInt64 nLOKWindowId) commit f6e9c2dc1eb768494739dba456e35f573eeb33ca Author: Caolán McNamara <[email protected]> AuthorDate: Fri Dec 5 20:22:22 2025 +0000 Commit: Andras Timar <[email protected]> CommitDate: Sat Jan 10 13:24:30 2026 +0100 Collect .ui use coverage information bootstrap reporting of what .ui files were used in a session. Change-Id: I19b004482a3892898a9738e5e98ee084ab8cdcec Reviewed-on: https://gerrit.libreoffice.org/c/core/+/195113 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Miklos Vajna <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/195314 Tested-by: Jenkins Reviewed-by: Caolán McNamara <[email protected]> diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx index 765f144c5f5b..ee43babf868e 100644 --- a/desktop/source/lib/init.cxx +++ b/desktop/source/lib/init.cxx @@ -5621,6 +5621,33 @@ static void doc_postUnoCommand(LibreOfficeKitDocument* pThis, const char* pComma hideSidebar(); return; } + else if (gImpl && aCommand == ".uno:UICoverage") + { + for (const beans::PropertyValue& rPropValue : aPropertyValuesVector) + { + if (rPropValue.Name == "Report") + { + bool report(true); + rPropValue.Value >>= report; + if (report) + { + tools::JsonWriter aJson; + aJson.put("commandName", aCommand); + aJson.put("success", true); + aJson.put("result", Application::UICoverageReport()); + pDocument->mpCallbackFlushHandlers[nView]->queue(LOK_CALLBACK_UNO_COMMAND_RESULT, aJson.finishAndGetAsOString()); + } + } + else if (rPropValue.Name == "Track") + { + bool track(false); + rPropValue.Value >>= track; + Application::EnableUICoverage(track); + } + } + + return; + } if (aCommand != ".uno:Save") { diff --git a/include/vcl/svapp.hxx b/include/vcl/svapp.hxx index 43cb3f9535b0..2bfbc02a104f 100644 --- a/include/vcl/svapp.hxx +++ b/include/vcl/svapp.hxx @@ -1237,6 +1237,12 @@ public: /** Determines if safe mode is enabled */ static bool IsSafeModeEnabled(); + /** Collect what .ui files are used*/ + static void EnableUICoverage(bool bEnable); + + /** Report on what .ui files were used*/ + static OString UICoverageReport(); + ///@} /** Get the desktop environment the process is currently running in diff --git a/vcl/inc/salinst.hxx b/vcl/inc/salinst.hxx index 359cf21226be..65b64125697b 100644 --- a/vcl/inc/salinst.hxx +++ b/vcl/inc/salinst.hxx @@ -20,6 +20,7 @@ #pragma once #include <sal/types.h> +#include <o3tl/sorted_vector.hxx> #include <rtl/ref.hxx> #include <vcl/ColorDialog.hxx> #include <vcl/dllapi.h> @@ -81,6 +82,7 @@ private: rtl::Reference< vcl::DisplayConnectionDispatch > m_pEventInst; const std::unique_ptr<comphelper::SolarMutex> m_pYieldMutex; css::uno::Reference<css::datatransfer::clipboard::XClipboard> m_clipboard; + o3tl::sorted_vector<OUString> m_usedUI; protected: bool m_bSupportsOpenGL = false; @@ -95,6 +97,8 @@ public: bool supportsOpenGL() const { return m_bSupportsOpenGL; } + o3tl::sorted_vector<OUString>& getUsedUIList() { return m_usedUI; } + //called directly after Application::Init virtual void AfterAppInit() {} virtual bool SVMainHook(int*) { return false; } diff --git a/vcl/source/window/builder.cxx b/vcl/source/window/builder.cxx index df072d404ca3..f73a8b444653 100644 --- a/vcl/source/window/builder.cxx +++ b/vcl/source/window/builder.cxx @@ -185,8 +185,36 @@ namespace } +static bool bEnableUICoverage = false; + +void Application::EnableUICoverage(bool bEnable) +{ + bEnableUICoverage = bEnable; + if (!bEnableUICoverage) + ImplGetSVData()->mpDefInst->getUsedUIList().clear(); +} + +OString Application::UICoverageReport() +{ + tools::JsonWriter aJson; + + const auto& entries = ImplGetSVData()->mpDefInst->getUsedUIList(); + { + auto childrenNode = aJson.startArray("used"); + for (const auto& entry : entries) + aJson.putSimpleValue(entry); + } + + return aJson.finishAndGetAsOString(); +} + std::unique_ptr<weld::Builder> Application::CreateBuilder(weld::Widget* pParent, const OUString &rUIFile, bool bMobile, sal_uInt64 nLOKWindowId) { + ImplSVData* pSVData = ImplGetSVData(); + + if (bEnableUICoverage) + pSVData->mpDefInst->getUsedUIList().insert(rUIFile); + if (comphelper::LibreOfficeKit::isActive() && !jsdialog::isIgnored(rUIFile)) { if (jsdialog::isBuilderEnabledForSidebar(rUIFile)) @@ -208,11 +236,16 @@ std::unique_ptr<weld::Builder> Application::CreateBuilder(weld::Widget* pParent, SAL_WARN("vcl", "UI file not enabled for JSDialogs: " << rUIFile); } - return ImplGetSVData()->mpDefInst->CreateBuilder(pParent, AllSettings::GetUIRootDir(), rUIFile); + return pSVData->mpDefInst->CreateBuilder(pParent, AllSettings::GetUIRootDir(), rUIFile); } std::unique_ptr<weld::Builder> Application::CreateInterimBuilder(vcl::Window* pParent, const OUString &rUIFile, bool bAllowCycleFocusOut, sal_uInt64 nLOKWindowId) { + ImplSVData* pSVData = ImplGetSVData(); + + if (bEnableUICoverage) + pSVData->mpDefInst->getUsedUIList().insert(rUIFile); + if (comphelper::LibreOfficeKit::isActive() && !jsdialog::isIgnored(rUIFile)) { // Notebookbar sub controls @@ -228,7 +261,7 @@ std::unique_ptr<weld::Builder> Application::CreateInterimBuilder(vcl::Window* pP SAL_WARN("vcl", "UI file not enabled for JSDialogs: " << rUIFile); } - return ImplGetSVData()->mpDefInst->CreateInterimBuilder(pParent, AllSettings::GetUIRootDir(), rUIFile, bAllowCycleFocusOut, nLOKWindowId); + return pSVData->mpDefInst->CreateInterimBuilder(pParent, AllSettings::GetUIRootDir(), rUIFile, bAllowCycleFocusOut, nLOKWindowId); } weld::MessageDialog* Application::CreateMessageDialog(weld::Widget* pParent, VclMessageType eMessageType, commit e84269528bea938df52c49907d749d6fd11726f4 Author: Miklos Vajna <[email protected]> AuthorDate: Mon Dec 8 09:21:41 2025 +0100 Commit: Andras Timar <[email protected]> CommitDate: Sat Jan 10 13:24:30 2026 +0100 vcl: fix C4245 signed/unsigned mismatch vcl/unx/generic/print/prtsetup.cxx(357): warning C4245: 'return': conversion from 'int' to 'sal_uLong', signed/unsigned mismatch Seen on Windows with --enable-headless. Just silence it for now, assuming the actual behavior was there on Linux already without problems. Change-Id: I56ca85a4576e6505a46e23c661443a74d5d9d2ee Reviewed-on: https://gerrit.libreoffice.org/c/core/+/195222 Tested-by: Jenkins Reviewed-by: Miklos Vajna <[email protected]> diff --git a/vcl/unx/generic/print/prtsetup.cxx b/vcl/unx/generic/print/prtsetup.cxx index 630debb88444..7fbea31e7cec 100644 --- a/vcl/unx/generic/print/prtsetup.cxx +++ b/vcl/unx/generic/print/prtsetup.cxx @@ -354,7 +354,7 @@ sal_uLong RTSDevicePage::getColorDevice() const case 1: return 1; case 2: - return -1; + return static_cast<sal_uLong>(-1); } return 0; } commit 24f15b69eda8aca4e33e862117446465f83da68b Author: Szymon Kłos <[email protected]> AuthorDate: Tue Nov 25 08:39:33 2025 +0000 Commit: Andras Timar <[email protected]> CommitDate: Sat Jan 10 13:24:30 2026 +0100 sw: preserve status of qFormat on export - so far we don't have UI to change "favourite" setting - value from the import if it was explicitly set to false should be preserved Change-Id: I9a2ad637a70ea4c90233f157676d4c71e7ab0f86 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/194511 Reviewed-by: Szymon Kłos <[email protected]> Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/194807 Tested-by: Jenkins diff --git a/sw/qa/extras/ooxmlexport/data/nospacing_hidden.docx b/sw/qa/extras/ooxmlexport/data/nospacing_hidden.docx new file mode 100644 index 000000000000..43d2692e6807 Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/nospacing_hidden.docx differ diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport25.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport25.cxx index 94a07d25bd91..4240ccb96191 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport25.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport25.cxx @@ -360,6 +360,18 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf169274) assertXPath(pXmlDoc, sPath + "w:sdtContent/w:sdt", 0); } +CPPUNIT_TEST_FIXTURE(Test, testQFormatPreservation) +{ + createSwDoc("nospacing_hidden.docx"); + save(TestFilter::DOCX); + + xmlDocUniquePtr pXmlStyles = parseExport(u"word/styles.xml"_ustr); + + assertXPath(pXmlStyles, "//w:style[@w:styleId='Heading']/w:qFormat", 1); + // not used currently and had qFormat = 0 on import + assertXPath(pXmlStyles, "//w:style[@w:styleId='No spacing']/w:qFormat", 0); +} + } // end of anonymous namespace CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx index 5f2b3d2a0a01..cb80dddf479c 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -6919,7 +6919,10 @@ static bool lcl_guessQFormat(const OUString& rName, sal_uInt16 nWwId) void DocxAttributeOutput::StartStyle( const OUString& rName, StyleType eType, sal_uInt16 nBase, sal_uInt16 nNext, sal_uInt16 nLink, sal_uInt16 nWwId, sal_uInt16 nSlot, bool bAutoUpdate ) { - bool bQFormat = false, bUnhideWhenUsed = false, bSemiHidden = false, bLocked = false, bDefault = false, bCustomStyle = false; + bool bUnhideWhenUsed = false, bSemiHidden = false, bLocked = false, bDefault = false, bCustomStyle = false; + bool bQFormat = false; // DEPRECATED: from grab-bag + bool bRealQFormat = true; // from SwFormat + OUString aRsid, aUiPriority; rtl::Reference<FastAttributeList> pStyleAttributeList = FastSerializerHelper::createAttrList(); uno::Any aAny; @@ -6927,6 +6930,7 @@ void DocxAttributeOutput::StartStyle( const OUString& rName, StyleType eType, { const SwFormat* pFormat = m_rExport.m_pStyles->GetSwFormat(nSlot); pFormat->GetGrabBagItem(aAny); + bRealQFormat = pFormat->IsFavourite(); } else { @@ -7004,8 +7008,8 @@ void DocxAttributeOutput::StartStyle( const OUString& rName, StyleType eType, m_pSerializer->singleElementNS(XML_w, XML_semiHidden); if (bUnhideWhenUsed) m_pSerializer->singleElementNS(XML_w, XML_unhideWhenUsed); - - if (bQFormat || lcl_guessQFormat(rName, nWwId)) + // by default we use old quess, if user marks style as non-favourite -> do not export qFormat + if (bRealQFormat && (bQFormat || lcl_guessQFormat(rName, nWwId))) m_pSerializer->singleElementNS(XML_w, XML_qFormat); if (bLocked) m_pSerializer->singleElementNS(XML_w, XML_locked); commit 0804421b4ba6f5fa23d0d3a067040a7b210afd80 Author: Henry Castro <[email protected]> AuthorDate: Thu Nov 27 07:34:01 2025 -0400 Commit: Andras Timar <[email protected]> CommitDate: Sat Jan 10 13:24:30 2026 +0100 lok: add "can_focus" property dump Some UI controls should not receive focus on the client side. Change-Id: I1128d027f89455b6c48e52bcecd426d3c26212c7 Signed-off-by: Henry Castro <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/194700 Tested-by: Caolán McNamara <[email protected]> Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Caolán McNamara <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/195662 Tested-by: Jenkins diff --git a/vcl/source/window/window.cxx b/vcl/source/window/window.cxx index de3b96718527..b8af7b685dcb 100644 --- a/vcl/source/window/window.cxx +++ b/vcl/source/window/window.cxx @@ -3366,6 +3366,7 @@ void Window::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter) rJsonWriter.put("type", GetTypeName()); rJsonWriter.put("text", GetText()); rJsonWriter.put("enabled", IsEnabled()); + rJsonWriter.put("canFocus", bool(GetStyle() & WB_TABSTOP)); if (!IsVisible()) rJsonWriter.put("visible", false); commit e1e623b20fc9ea11d892f283e54636f60ec86dbc Author: Szymon Kłos <[email protected]> AuthorDate: Mon Nov 24 11:53:43 2025 +0000 Commit: Andras Timar <[email protected]> CommitDate: Sat Jan 10 13:24:29 2026 +0100 notebookbar: human-readable type for style entries - we use 2 strings as styles are identified by the name - in the UI we want to show translated string but to deduplicate standard styles we use common, English name Change-Id: I4046d54f67d0496bd7ec63e840491091dae39995 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/194437 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/196325 Reviewed-by: Szymon Kłos <[email protected]> Tested-by: Jenkins diff --git a/svx/source/inc/StylesPreviewWindow.hxx b/svx/source/inc/StylesPreviewWindow.hxx index 6f3ebd0dfa6b..27c97a127e14 100644 --- a/svx/source/inc/StylesPreviewWindow.hxx +++ b/svx/source/inc/StylesPreviewWindow.hxx @@ -27,7 +27,11 @@ #include <sfx2/sfxstatuslistener.hxx> // pair of id and name, name can be translated to other language -typedef std::pair<OUString, OUString> StylePreviewDescriptor; +struct StylePreviewDescriptor +{ + OUString commonName; // English: Heading 1 + OUString translatedName; // German: Überschrift 1 +}; typedef std::vector<StylePreviewDescriptor> StylePreviewList; class StylesPreviewWindow_Base; diff --git a/svx/source/tbxctrls/StylesPreviewToolBoxControl.cxx b/svx/source/tbxctrls/StylesPreviewToolBoxControl.cxx index c5a9cadc4cd2..11793e718156 100644 --- a/svx/source/tbxctrls/StylesPreviewToolBoxControl.cxx +++ b/svx/source/tbxctrls/StylesPreviewToolBoxControl.cxx @@ -73,10 +73,11 @@ void StylesPreviewToolBoxControl::InitializeStyles( { css::uno::Reference<css::beans::XPropertySet> xStyle; xParaStyles->getByName(rStyle) >>= xStyle; - OUString sName; - xStyle->getPropertyValue(u"DisplayName"_ustr) >>= sName; - if (!sName.isEmpty()) - m_aDefaultStyles.push_back(StylePreviewDescriptor(rStyle, sName)); + OUString sTranslatedName; + xStyle->getPropertyValue(u"DisplayName"_ustr) >>= sTranslatedName; + if (!sTranslatedName.isEmpty()) + m_aDefaultStyles.emplace_back<StylePreviewDescriptor>( + { rStyle, sTranslatedName }); } catch (const css::container::NoSuchElementException&) { @@ -104,12 +105,12 @@ void StylesPreviewToolBoxControl::InitializeStyles( xCellStyles->getByName(sStyleName), css::uno::UNO_QUERY); if (xStyle) { - OUString sName; - xStyle->getPropertyValue(u"DisplayName"_ustr) >>= sName; - if (!sName.isEmpty()) + OUString sTranslatedName; + xStyle->getPropertyValue(u"DisplayName"_ustr) >>= sTranslatedName; + if (!sTranslatedName.isEmpty()) { - m_aDefaultStyles.push_back( - StylePreviewDescriptor(sStyleName, sName)); + m_aDefaultStyles.emplace_back<StylePreviewDescriptor>( + { sStyleName, sTranslatedName }); } } } diff --git a/svx/source/tbxctrls/StylesPreviewWindow.cxx b/svx/source/tbxctrls/StylesPreviewWindow.cxx index 983228980851..f300d70b514c 100644 --- a/svx/source/tbxctrls/StylesPreviewWindow.cxx +++ b/svx/source/tbxctrls/StylesPreviewWindow.cxx @@ -315,8 +315,8 @@ void StyleItemController::DrawEntry(vcl::RenderContext& rRenderContext) return; pStyle = pPool->First(m_eStyleFamily); - while (pStyle && pStyle->GetName() != m_aStyleName.first - && pStyle->GetName() != m_aStyleName.second) + while (pStyle && pStyle->GetName() != m_aStyleName.commonName + && pStyle->GetName() != m_aStyleName.translatedName) pStyle = pPool->Next(); if (!pStyle) @@ -403,7 +403,7 @@ void StyleItemController::DrawContentBackground(vcl::RenderContext& rRenderConte void StyleItemController::DrawHighlight(vcl::RenderContext& rRenderContext, Color aFontBack) { tools::Rectangle aTextRect; - rRenderContext.GetTextBoundRect(aTextRect, m_aStyleName.second); + rRenderContext.GetTextBoundRect(aTextRect, m_aStyleName.translatedName); Size aSize = aTextRect.GetSize(); aSize.AdjustHeight(aSize.getHeight()); @@ -422,17 +422,18 @@ void StyleItemController::DrawHighlight(vcl::RenderContext& rRenderContext, Colo void StyleItemController::DrawText(vcl::RenderContext& rRenderContext) { - const SalLayoutGlyphs* layoutGlyphs - = SalLayoutGlyphsCache::self()->GetLayoutGlyphs(&rRenderContext, m_aStyleName.second); + const SalLayoutGlyphs* layoutGlyphs = SalLayoutGlyphsCache::self()->GetLayoutGlyphs( + &rRenderContext, m_aStyleName.translatedName); tools::Rectangle aTextRect; - rRenderContext.GetTextBoundRect(aTextRect, m_aStyleName.second, 0, 0, -1, 0, {}, {}, + rRenderContext.GetTextBoundRect(aTextRect, m_aStyleName.translatedName, 0, 0, -1, 0, {}, {}, layoutGlyphs); Point aPos(0, 0); aPos.AdjustX(LEFT_MARGIN); aPos.AdjustY((rRenderContext.GetOutputHeightPixel() - aTextRect.Bottom()) / 2); - rRenderContext.DrawText(aPos, m_aStyleName.second, 0, -1, nullptr, nullptr, layoutGlyphs); + rRenderContext.DrawText(aPos, m_aStyleName.translatedName, 0, -1, nullptr, nullptr, + layoutGlyphs); } StylesPreviewWindow_Base::StylesPreviewWindow_Base( @@ -525,7 +526,8 @@ void StylesPreviewWindow_Base::UpdateSelection() for (StylePreviewList::size_type i = 0; i < m_aAllStyles.size(); ++i) { - if (m_aAllStyles[i].first == m_sSelectedStyle || m_aAllStyles[i].second == m_sSelectedStyle) + if (m_aAllStyles[i].commonName == m_sSelectedStyle + || m_aAllStyles[i].translatedName == m_sSelectedStyle) { m_xStylesView->select(i); break; @@ -568,7 +570,7 @@ IMPL_LINK(StylesPreviewWindow_Base, GetPreviewImage, const weld::encoded_image_q const weld::TreeIter& rIter = std::get<1>(rQuery); OUString sStyleId(m_xStylesView->get_id(rIter)); OUString sStyleName(m_xStylesView->get_text(rIter)); - OString sBase64Png(GetCachedPreviewJson(StylePreviewDescriptor(sStyleId, sStyleName))); + OString sBase64Png(GetCachedPreviewJson({ sStyleId, sStyleName })); if (sBase64Png.isEmpty()) return false; @@ -580,9 +582,9 @@ IMPL_LINK(StylesPreviewWindow_Base, GetPreviewImage, const weld::encoded_image_q Bitmap StylesPreviewWindow_Base::GetCachedPreview(const StylePreviewDescriptor& rStyle) { - auto aFound = StylePreviewCache::Get().find(rStyle.second); + auto aFound = StylePreviewCache::Get().find(rStyle.translatedName); if (aFound != StylePreviewCache::Get().end()) - return StylePreviewCache::Get()[rStyle.second]; + return StylePreviewCache::Get()[rStyle.translatedName]; else { ScopedVclPtrInstance<VirtualDevice> pImg; @@ -592,7 +594,7 @@ Bitmap StylesPreviewWindow_Base::GetCachedPreview(const StylePreviewDescriptor& StyleItemController aStyleController(rStyle); aStyleController.Paint(*pImg); Bitmap aBitmap(pImg->GetBitmap(Point(0, 0), aSize)); - StylePreviewCache::Get()[rStyle.second] = aBitmap; + StylePreviewCache::Get()[rStyle.translatedName] = aBitmap; return aBitmap; } @@ -600,13 +602,13 @@ Bitmap StylesPreviewWindow_Base::GetCachedPreview(const StylePreviewDescriptor& OString StylesPreviewWindow_Base::GetCachedPreviewJson(const StylePreviewDescriptor& rStyle) { - auto aJsonFound = StylePreviewCache::GetJson().find(rStyle.second); + auto aJsonFound = StylePreviewCache::GetJson().find(rStyle.translatedName); if (aJsonFound != StylePreviewCache::GetJson().end()) - return StylePreviewCache::GetJson()[rStyle.second]; + return StylePreviewCache::GetJson()[rStyle.translatedName]; Bitmap aBitmap = GetCachedPreview(rStyle); OString sResult = extractPngString(aBitmap); - StylePreviewCache::GetJson()[rStyle.second] = sResult; + StylePreviewCache::GetJson()[rStyle.translatedName] = sResult; return sResult; } @@ -629,11 +631,11 @@ inline void lcl_AppendParaStyles(StylePreviewList& rAllStyles, SfxStyleSheetBase // do not duplicate const auto aFound = std::find_if( rAllStyles.begin(), rAllStyles.end(), [sName](const StylePreviewDescriptor& element) { - return element.first == sName || element.second == sName; + return element.commonName == sName || element.translatedName == sName; }); if (aFound == rAllStyles.end()) - rAllStyles.push_back(StylePreviewDescriptor(sName, sName)); + rAllStyles.emplace_back<StylePreviewDescriptor>({ sName, sName }); pStyle = xIter->Next(); } @@ -665,13 +667,9 @@ void StylesPreviewWindow_Base::UpdateStylesList() const bool bNeedInsertPreview = !comphelper::LibreOfficeKit::isActive(); for (const auto& rStyle : m_aAllStyles) { - if (bNeedInsertPreview) - { - Bitmap aPreview = GetCachedPreview(rStyle); - m_xStylesView->append(rStyle.first, rStyle.second, &aPreview); - } - else - m_xStylesView->append(rStyle.first, rStyle.second, nullptr); + Bitmap aPreview = GetCachedPreview(rStyle); + Bitmap* pPreview = bNeedInsertPreview ? &aPreview : nullptr; + m_xStylesView->append(rStyle.commonName, rStyle.translatedName, pPreview); } m_xStylesView->thaw(); } commit d0cc171073e54fc7e9940f6ae69c09355e42080c Author: Szymon Kłos <[email protected]> AuthorDate: Mon Nov 24 13:01:55 2025 +0000 Commit: Andras Timar <[email protected]> CommitDate: Sat Jan 10 13:24:29 2026 +0100 sw: setup favourite style once - the GrabBag values don't change after import much - better to parse qFormat once and setup favourite value we can cache and return quickly when requested - it is more efficient than checking grab bag every time we do iteration over styles Change-Id: I7b54831a84cd6528a40cf853f0d4f5061f05af82 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/194442 (cherry picked from commit 9fc06b81e954d91a63f80a54953d636139426ee2) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/194803 Reviewed-by: Szymon Kłos <[email protected]> Tested-by: Jenkins diff --git a/sw/inc/format.hxx b/sw/inc/format.hxx index 9933a98926c8..bc1ddda6b3ca 100644 --- a/sw/inc/format.hxx +++ b/sw/inc/format.hxx @@ -63,6 +63,7 @@ class SW_DLLPUBLIC SwFormat : public sw::BorderCacheOwner, public sw::Broadcasti bool m_bAutoUpdateOnDirectFormat : 1;/**< TRUE: Set attributes of a whole paragraph at format (UI-side!). */ bool m_bHidden : 1; + bool m_bIsFavourite : 1; ///< Show in the basic UI std::shared_ptr<SfxGrabBagItem> m_pGrabBagItem; ///< Style InteropGrabBag. virtual void InvalidateInSwFntCache(sal_uInt16) {}; virtual void InvalidateInSwFntCache() {}; @@ -73,6 +74,7 @@ protected: SwFormat( const SwFormat& rFormat ); virtual void SwClientNotify(const SwModify&, const SfxHint&) override; void Destr(); + void ParseFavourites(); public: @@ -179,7 +181,8 @@ public: bool IsAuto() const { return m_bAutoFormat; } void SetAuto( bool bNew ) { m_bAutoFormat = bNew; } - bool IsFavourite() const; + bool IsFavourite() const { return m_bIsFavourite; } + void SetFavourite(bool bValue) { m_bIsFavourite = bValue; } bool IsHidden() const { return m_bHidden; } void SetHidden( bool bValue ) { m_bHidden = bValue; } diff --git a/sw/qa/uitest/writer_tests4/tdf167956.py b/sw/qa/uitest/writer_tests4/tdf167956.py index 731808135ac9..ddf182ddc183 100644 --- a/sw/qa/uitest/writer_tests4/tdf167956.py +++ b/sw/qa/uitest/writer_tests4/tdf167956.py @@ -27,7 +27,7 @@ class tdf167956(UITestCase): xWriterDoc = self.xUITest.getTopFocusWindow() xStylesView = xWriterDoc.getChild("stylesview") self.wait_until_styles_are_displayed(xStylesView) - self.assertEqual("10", get_state_as_dict(xStylesView)["Children"]) + self.assertLessEqual("10", get_state_as_dict(xStylesView)["Children"]) self.assertEqual("Default Paragraph Style", get_state_as_dict(xStylesView)["SelectEntryText"]) with self.ui_test.load_file(get_url_for_data_file("tdf167956.docx")): diff --git a/sw/source/core/attr/format.cxx b/sw/source/core/attr/format.cxx index e985b0822a0f..58e0680d86da 100644 --- a/sw/source/core/attr/format.cxx +++ b/sw/source/core/attr/format.cxx @@ -49,6 +49,7 @@ SwFormat::SwFormat( SwAttrPool& rPool, const UIName& rFormatNm, m_bAutoUpdateOnDirectFormat = false; // LAYER_IMPL m_bAutoFormat = true; m_bFormatInDTOR = m_bHidden = false; + m_bIsFavourite = true; if( pDrvdFrame ) { @@ -69,6 +70,7 @@ SwFormat::SwFormat( const SwFormat& rFormat ) : m_bFormatInDTOR = false; // LAYER_IMPL m_bAutoFormat = rFormat.m_bAutoFormat; m_bHidden = rFormat.m_bHidden; + m_bIsFavourite = rFormat.m_bIsFavourite; m_bAutoUpdateOnDirectFormat = rFormat.m_bAutoUpdateOnDirectFormat; if( auto pDerived = rFormat.DerivedFrom() ) @@ -117,6 +119,7 @@ SwFormat &SwFormat::operator=(const SwFormat& rFormat) m_bAutoFormat = rFormat.m_bAutoFormat; m_bHidden = rFormat.m_bHidden; + m_bIsFavourite = rFormat.m_bIsFavourite; m_bAutoUpdateOnDirectFormat = rFormat.m_bAutoUpdateOnDirectFormat; return *this; } @@ -727,6 +730,29 @@ void SwFormat::SetGrabBagItem(const uno::Any& rVal) m_pGrabBagItem = std::make_shared<SfxGrabBagItem>(); m_pGrabBagItem->PutValue(rVal, 0); + + ParseFavourites(); +} + +void SwFormat::ParseFavourites() +{ + const auto& rItems = m_pGrabBagItem->GetGrabBag(); + const auto aIt = rItems.find(u"qFormat"_ustr); + if (aIt != rItems.end()) + { + sal_Int32 nVal = 0; + if (aIt->second >>= nVal) + { + if (nVal == 0) + SetFavourite(false); + else + SetFavourite(true); + } + } + else + { + SetFavourite(false); + } } std::unique_ptr<SvxBrushItem> SwFormat::makeBackgroundBrushItem(bool bInP) const @@ -756,25 +782,6 @@ void SwFormat::RemoveAllUnos() SwClientNotify(*this, aMsgHint); } -bool SwFormat::IsFavourite() const -{ - if (!m_pGrabBagItem) return false; - - const auto& rItems = m_pGrabBagItem->GetGrabBag(); - const auto aIt = rItems.find(u"qFormat"_ustr); - if (aIt != rItems.end()) - { - sal_Int32 nVal = 0; - if (aIt->second >>= nVal) - { - if (nVal == 1) - return true; - } - } - - return false; -} - bool SwFormat::IsUsed() const { bool isUsed = false; commit aefc79a5276b4662bcffc7ec0433cab561529f24 Author: Tor Lillqvist <[email protected]> AuthorDate: Fri Nov 7 15:53:16 2025 +0200 Commit: Andras Timar <[email protected]> CommitDate: Sat Jan 10 13:24:29 2026 +0100 Don't let the last translation act as a default Change-Id: Ia75743ad23ce651c9aab392098686d1978b49fe2 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/193629 Reviewed-by: Tor Lillqvist <[email protected]> Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/195194 Tested-by: Jenkins Reviewed-by: Caolán McNamara <[email protected]> diff --git a/xmloff/source/core/xmlimp.cxx b/xmloff/source/core/xmlimp.cxx index fd084ad77023..873aa8d69431 100644 --- a/xmloff/source/core/xmlimp.cxx +++ b/xmloff/source/core/xmlimp.cxx @@ -545,7 +545,9 @@ namespace { break; } } - if (aKeyString.isEmpty()) + if (aLocale.isEmpty()) + ; // Do nothing, we don't have a matching translation + else if (aKeyString.isEmpty()) aKeyString = aStr; else { commit f614687c9d253048f638318a8a2f646ae48094a6 Author: Rashesh Padia <[email protected]> AuthorDate: Thu Nov 6 13:26:53 2025 +0530 Commit: Andras Timar <[email protected]> CommitDate: Sat Jan 10 13:24:29 2026 +0100 l10nMapper: update cleanDomain to use "_" prefix Change-Id: I2c7a1393281768f89978f0090ac6e2e0b8866ad1 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/193628 Reviewed-by: Andras Timar <[email protected]> Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/195193 Reviewed-by: Caolán McNamara <[email protected]> Tested-by: Jenkins diff --git a/xmloff/source/core/xmlimp.cxx b/xmloff/source/core/xmlimp.cxx index dd0e21fa192f..fd084ad77023 100644 --- a/xmloff/source/core/xmlimp.cxx +++ b/xmloff/source/core/xmlimp.cxx @@ -589,8 +589,8 @@ namespace { static OUString cleanDomain(const OUString &str) { - sal_Int32 idx = str.indexOf('|'); - if (idx > 0) + sal_Int32 idx = str.indexOf('_'); + if (idx > -1) return str.copy(idx+1); else return str; commit 2cacc58e85988384f5c07734d140adf3354429ce Author: Michael Meeks <[email protected]> AuthorDate: Sat Jul 12 12:51:39 2025 +0100 Commit: Andras Timar <[email protected]> CommitDate: Sat Jan 10 13:24:29 2026 +0100 Implement translation mapper for XML content. Loads content from a stream with this syntax: # list of supported bcp47 lang tags en-US,de-DE,fr-FR,en-GB # then each string This is a string [en-US] This is stil a string [en-GB] I say old boy, what a string etc. Change-Id: Id6e3c0de03f57c68246fd3eee7b4912f9adc218e Signed-off-by: Michael Meeks <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/193627 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Andras Timar <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/195192 Tested-by: Jenkins Reviewed-by: Caolán McNamara <[email protected]> diff --git a/xmloff/source/core/xmlimp.cxx b/xmloff/source/core/xmlimp.cxx index 497e92890bc7..dd0e21fa192f 100644 --- a/xmloff/source/core/xmlimp.cxx +++ b/xmloff/source/core/xmlimp.cxx @@ -29,6 +29,7 @@ #include <utility> #include <vcl/embeddedfontsmanager.hxx> #include <vcl/graph.hxx> +#include <vcl/svapp.hxx> #include <xmloff/unointerfacetouniqueidentifiermapper.hxx> #include <xmloff/namespacemap.hxx> #include <xmloff/xmlgrhlp.hxx> @@ -66,10 +67,12 @@ #include <cppuhelper/implbase.hxx> #include <cppuhelper/supportsservice.hxx> #include <comphelper/extract.hxx> +#include <comphelper/processfactory.hxx> #include <comphelper/documentconstants.hxx> #include <comphelper/documentinfo.hxx> #include <comphelper/storagehelper.hxx> #include <comphelper/attributelist.hxx> +#include <comphelper/string.hxx> #include <unotools/fontcvt.hxx> #include <fasttokenhandler.hxx> #include <vcl/GraphicExternalLink.hxx> @@ -79,6 +82,18 @@ #include <com/sun/star/rdf/XRepositorySupplier.hpp> #include <RDFaImportHelper.hxx> +// L10nMapper bits to split out ... +#include <com/sun/star/uno/Type.hxx> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/io/XTextInputStream2.hpp> +#include <com/sun/star/io/TextInputStream.hpp> +#include <com/sun/star/container/XMap.hpp> +#include <cppuhelper/compbase.hxx> +#include <i18nlangtag/languagetag.hxx> +#include <comphelper/lok.hxx> +#include <com/sun/star/lang/XLocalizable.hpp> +#include <com/sun/star/configuration/theDefaultProvider.hpp> + using ::com::sun::star::beans::XPropertySetInfo; using namespace ::com::sun::star; @@ -457,6 +472,162 @@ void SvXMLImport::InitCtor_() } } +namespace { + + class L10nMapper : public cppu::WeakImplHelper<css::container::XMap> + { + std::unordered_map<OUString, OUString> maMap; + + L10nMapper() { } + virtual ~L10nMapper() override {} + + public: + static css::uno::Reference< XMap > load(const uno::Reference<css::embed::XStorage> &xStorage) + { + try { + OUString streamName = u"l10n"_ustr; + if (xStorage && xStorage->isStreamElement(streamName)) + { + auto xIn = xStorage->openStreamElement(streamName, css::embed::ElementModes::READ|css::embed::ElementModes::NOCREATE); + if (!xIn) + return css::uno::Reference< XMap >(); + + auto xInStrm = uno::Reference<css::io::XInputStream>(xIn, UNO_QUERY_THROW); + + rtl::Reference< L10nMapper > pMap = new L10nMapper(); + + auto xContext = comphelper::getProcessComponentContext(); + + Reference< XTextInputStream2 > xTextStrm; + xTextStrm = css::io::TextInputStream::create(xContext); + xTextStrm->setInputStream(xInStrm); + xTextStrm->setEncoding(u"utf8"_ustr); + + ::std::vector<OUString> aLocales; + if (comphelper::LibreOfficeKit::isActive()) + aLocales = comphelper::LibreOfficeKit::getLanguageTag().getFallbackStrings(true); + else + aLocales = LanguageTag(css::uno::Reference< css::lang::XLocalizable >( + css::configuration::theDefaultProvider::get(xContext), + css::uno::UNO_QUERY_THROW)->getLocale()).getFallbackStrings(true); + OUString aLocale; // cached best locale match + + // Format is <opt-prefix|string> locale <translated-string> <repeat> + OUString aKeyString; + size_t nLine = 0; + while (!xTextStrm->isEOF()) + { + OUString aStr = xTextStrm->readLine(); + nLine++; + if (aStr.getLength() < 1 || aStr[0] == '#') + { + aKeyString = ""; + continue; + } + + // Read ',' separated locale list at the start + if (aLocale.isEmpty()) + { + auto aFileLocales = comphelper::string::split(aStr, ','); + + // find and cache the best match + for (const auto &f : aFileLocales) + { + for (const auto &i : aLocales) + { + if (f == i) + { + aLocale = f + u" "_ustr; + break; + } + } + if (!aLocale.isEmpty()) + break; + } + } + if (aKeyString.isEmpty()) + aKeyString = aStr; + else + { + if (aStr.startsWith(aLocale)) + { + auto aValues = comphelper::string::split(aStr, ' '); + if (aValues.size() > 1) + pMap->maMap[aKeyString] = aValues[1]; + else + pMap->maMap[aKeyString] = OUString::Concat(u"invalid line "_ustr) + OUString::number(nLine); + } + } + } + + xTextStrm->closeInput(); + + auto xMap = css::uno::Reference< XMap >(pMap); + + return xMap; + } + } + catch (Exception const&) + { + DBG_UNHANDLED_EXCEPTION("xmloff.core", "exception getting BuildId"); + } + return css::uno::Reference< XMap >(); + } + + // XMap + virtual Type SAL_CALL getKeyType() override { return cppu::UnoType<OUString>::get(); }; + virtual Type SAL_CALL getValueType() override { return cppu::UnoType<OUString>::get(); }; + virtual void SAL_CALL clear() override { maMap.clear(); } + virtual sal_Bool SAL_CALL containsKey( const Any& ) override + { + throw css::uno::RuntimeException(u"not implemented"_ustr); + } + virtual sal_Bool SAL_CALL containsValue( const Any& ) override + { + throw css::uno::RuntimeException(u"not implemented"_ustr); + } + + static OUString cleanDomain(const OUString &str) + { + sal_Int32 idx = str.indexOf('|'); + if (idx > 0) + return str.copy(idx+1); + else + return str; + } + + virtual Any SAL_CALL get( const Any& key ) override + { + auto it = maMap.find(key.get<OUString>()); + if (it == maMap.end()) + { + SAL_WARN("xmloff", "Key '" << key << "' with no translation"); + return css::uno::Any(cleanDomain(key.get<OUString>())); + } + else + return css::uno::Any(it->second); + } + virtual Any SAL_CALL put( const Any&, const Any& ) override + { + throw css::uno::RuntimeException(u"not implemented"_ustr); + } + virtual Any SAL_CALL remove( const Any& ) override + { + throw css::uno::RuntimeException(u"not implemented"_ustr); + } + + // XElementAccess (base) + virtual Type SAL_CALL getElementType() override + { + throw css::uno::RuntimeException(u"not implemented"_ustr); + } + virtual sal_Bool SAL_CALL hasElements() override + { + return !maMap.empty(); + } +}; +} + SvXMLImport::SvXMLImport( const css::uno::Reference< css::uno::XComponentContext >& xContext, OUString const & implementationName, @@ -478,6 +649,7 @@ SvXMLImport::SvXMLImport( SAL_WARN_IF( !xContext.is(), "xmloff.core", "got no service manager" ); InitCtor_(); mxParser = xml::sax::FastParser::create( xContext ); + setNamespaceHandler( maNamespaceHandler ); setTokenHandler( xTokenHandler ); if ( !bIsNSMapsInitialized ) @@ -1085,7 +1257,12 @@ void SAL_CALL SvXMLImport::initialize( const uno::Sequence< uno::Any >& aArgumen } uno::Reference<lang::XInitialization> const xInit(mxParser, uno::UNO_QUERY_THROW); - xInit->initialize( { Any(u"IgnoreMissingNSDecl"_ustr) }); + + css::uno::Reference< XMap > xMap = L10nMapper::load(GetSourceStorage()); + css::uno::Sequence< css::uno::Any > args{ + css::uno::Any(u"IgnoreMissingNSDecl"_ustr), + css::uno::Any(xMap) }; + xInit->initialize(args); } // XServiceInfo commit 99e1130079efd2b97262fcc6ba2228bd94a5152f Author: Michael Meeks <[email protected]> AuthorDate: Sat Jul 12 12:03:15 2025 +0100 Commit: Andras Timar <[email protected]> CommitDate: Sat Jan 10 13:24:29 2026 +0100 Add content mapping into XFastParser. Ideally this gets done for free in the parsing thread. Change-Id: I2392fd51c8152c48cf03ac9ed26e6f62aa6ac4f8 Signed-off-by: Michael Meeks <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/193626 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Andras Timar <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/195191 Tested-by: Jenkins Reviewed-by: Caolán McNamara <[email protected]> diff --git a/sax/source/fastparser/fastparser.cxx b/sax/source/fastparser/fastparser.cxx index 744458972554..32dc46506617 100644 --- a/sax/source/fastparser/fastparser.cxx +++ b/sax/source/fastparser/fastparser.cxx @@ -26,6 +26,7 @@ #include <com/sun/star/lang/DisposedException.hpp> #include <com/sun/star/lang/IllegalArgumentException.hpp> #include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/container/XMap.hpp> #include <com/sun/star/xml/sax/FastToken.hpp> #include <com/sun/star/xml/sax/SAXParseException.hpp> #include <com/sun/star/xml/sax/XFastContextHandler.hpp> @@ -37,6 +38,7 @@ #include <sal/log.hxx> #include <salhelper/thread.hxx> #include <comphelper/diagnose_ex.hxx> +#include <comphelper/string.hxx> #include <o3tl/string_view.hxx> #include <queue> @@ -271,6 +273,7 @@ public: void produce( bool bForceFlush = false ); bool m_bIgnoreMissingNSDecl; bool m_bDisableThreadedParser; + css::uno::Reference<css::container::XMap> mxMap; /// _ prefix string mapper for translation private: bool consume(EventList&); @@ -1360,6 +1363,10 @@ void FastSaxParserImpl::sendPendingCharacters() { -e ... etc. - the rest is truncated
