desktop/inc/lib/init.hxx | 13 + desktop/source/lib/init.cxx | 36 ++++ editeng/source/editeng/impedit3.cxx | 44 +++-- filter/source/xsltfilter/XSLTFilter.cxx | 3 forms/source/component/FormComponent.cxx | 5 include/oox/core/xmlfilterbase.hxx | 11 + include/oox/export/drawingml.hxx | 10 - include/oox/export/shapes.hxx | 3 include/sfx2/lokhelper.hxx | 2 include/sfx2/viewsh.hxx | 2 include/vcl/IDialogRenderable.hxx | 2 include/vcl/svapp.hxx | 2 include/vcl/weld.hxx | 11 + include/vcl/window.hxx | 3 oox/source/export/chartexport.cxx | 2 oox/source/export/drawingml.cxx | 12 - oox/source/export/shapes.cxx | 5 sc/qa/unit/data/xls/tdf170285_controlsInGroupShape.xls |binary sc/qa/unit/subsequent_export_test2.cxx | 12 + sc/source/filter/excel/xeescher.cxx | 6 sc/source/filter/excel/xestream.cxx | 18 ++ sc/source/filter/xcl97/xcl97rec.cxx | 15 + sc/source/ui/navipi/content.cxx | 19 +- sd/qa/unit/data/odp/tdf169952.odp |binary sd/qa/unit/export-tests-ooxml3.cxx | 10 + sd/source/core/drawdoc2.cxx | 2 sd/source/filter/eppt/pptx-epptooxml.cxx | 1 sfx2/source/view/lokhelper.cxx | 6 sfx2/source/view/viewsh.cxx | 4 svx/source/svdraw/svdedxv.cxx | 57 ++----- svx/source/svdraw/svdpdf.cxx | 20 ++ svx/uiconfig/ui/findreplacedialog.ui | 10 + sw/source/uibase/inc/QuickFindPanel.hxx | 10 + sw/source/uibase/sidebar/QuickFindPanel.cxx | 135 ++++++++++++++--- sw/source/uibase/uiview/view2.cxx | 17 ++ sw/uiconfig/swriter/ui/sidebarquickfind.ui | 71 ++++++++ vcl/jsdialog/enabled.cxx | 1 vcl/source/app/svapp.cxx | 2 vcl/source/window/cursor.cxx | 6 vcl/source/window/window.cxx | 18 +- vcl/unx/generic/glyphs/freetype_glyphcache.cxx | 3 41 files changed, 466 insertions(+), 143 deletions(-)
New commits: commit 6cd91187bfc910c4560a24eac522eec0be5d3397 Author: Henry Castro <[email protected]> AuthorDate: Fri Jan 9 07:32:21 2026 -0400 Commit: Andras Timar <[email protected]> CommitDate: Tue Jan 13 19:49:06 2026 +0100 ui: set accessible role to PAGE_TAB_LIST for GtkButton Signed-off-by: Henry Castro <[email protected]> Change-Id: I2cd320db34bfc5754b38859fbecf54c58990a602 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/196919 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Caolán McNamara <[email protected]> diff --git a/svx/uiconfig/ui/findreplacedialog.ui b/svx/uiconfig/ui/findreplacedialog.ui index 1c9952ea111c..d10bae595e4e 100644 --- a/svx/uiconfig/ui/findreplacedialog.ui +++ b/svx/uiconfig/ui/findreplacedialog.ui @@ -68,6 +68,11 @@ <property name="visible">True</property> <property name="can-focus">True</property> <property name="receives-default">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="find_tab_btn-atkobject"> + <property name="AtkObject::accessible-role">page tab list</property> + </object> + </child> </object> <packing> <property name="expand">False</property> @@ -81,6 +86,11 @@ <property name="visible">True</property> <property name="can-focus">True</property> <property name="receives-default">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="replace_tab_btn-atkobject"> + <property name="AtkObject::accessible-role">page tab list</property> + </object> + </child> </object> <packing> <property name="expand">False</property> commit 75abbc6e1fdedc90d3e4c50025cedcb63c7138b0 Author: Mohit Marathe <[email protected]> AuthorDate: Tue Jan 6 11:37:24 2026 +0530 Commit: Andras Timar <[email protected]> CommitDate: Tue Jan 13 19:48:56 2026 +0100 sd: delete the master page when canvas page is deleted since it is not shared by any other page. Signed-off-by: Mohit Marathe <[email protected]> Change-Id: I9564dc2dadc5d78b8fca31700cc0f44967c753c3 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/196589 Reviewed-by: Michael Stahl <[email protected]> Tested-by: Jenkins CollaboraOffice <[email protected]> diff --git a/sd/source/core/drawdoc2.cxx b/sd/source/core/drawdoc2.cxx index 88612cc7e640..23b216a6afb7 100644 --- a/sd/source/core/drawdoc2.cxx +++ b/sd/source/core/drawdoc2.cxx @@ -516,6 +516,8 @@ rtl::Reference<SdrPage> SdDrawDocument::RemovePage(sal_uInt16 nPgNum) auto pSdPage = static_cast<SdPage*>(pPage.get()); if (pSdPage->IsCanvasPage()) { + SdrPage* pMPage = &pPage->TRG_GetMasterPage(); + RemoveMasterPage(pMPage->GetPageNum()); if (comphelper::LibreOfficeKit::isActive()) { DrawViewShell* pDrawViewSh = dynamic_cast<DrawViewShell*>(mpDocSh->GetViewShell()); commit 47046c40a715890ab369b8a42690521937a9d095 Author: Michael Stahl <[email protected]> AuthorDate: Mon Jan 12 17:35:32 2026 +0100 Commit: Andras Timar <[email protected]> CommitDate: Tue Jan 13 19:48:44 2026 +0100 filter: XSLTFilter: unbreak XSLT2Transformer Creating the service fails: java.lang.ClassCastException: class com.sun.star.beans.NamedValue cannot be cast to class [Ljava.lang.Object; (com.sun.star.beans.NamedValue is in unnamed module of loader com.sun.star.lib.unoloader.UnoClassLoader @6ff3c5b5; [Ljava.lang.Object; is in module java.base of loader 'bootstrap') at com.sun.star.comp.xsltfilter.XSLTransformer.initialize(XSLTransformer.java:143) at com.sun.star.comp.loader.FactoryHelper$Factory.createInstanceWithArgumentsAndContext(FactoryHelper.java:271) because initialize gets a sequence<any> where the anys are NamedValues, but it expects a sequence<any> where the any is sequence<any> where the anys are NamedValues. (regression from commit d22f3b8c787b93c38925adf92af542362dbda3e6) Change-Id: I4fd13f3e04d79f7646e6bb31c8f0d35efd42ae69 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/197132 Tested-by: Jenkins Reviewed-by: Michael Stahl <[email protected]> (cherry picked from commit d92905f099992c48fc7ec0a6d0be5675d123b833) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/197172 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Stephan Bergmann <[email protected]> diff --git a/filter/source/xsltfilter/XSLTFilter.cxx b/filter/source/xsltfilter/XSLTFilter.cxx index 00f1bd3629f3..c955d7e6b98b 100644 --- a/filter/source/xsltfilter/XSLTFilter.cxx +++ b/filter/source/xsltfilter/XSLTFilter.cxx @@ -234,7 +234,8 @@ namespace XSLT { xTransformer.set( m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext( - u"com.sun.star.xml.xslt.XSLT2Transformer"_ustr, rArgs, m_xContext), + u"com.sun.star.xml.xslt.XSLT2Transformer"_ustr, + {Any{rArgs}}, m_xContext), css::uno::UNO_QUERY_THROW); } catch (const Exception&) commit 2e72ce51db399b6344439688472f21c79790be05 Author: Caolán McNamara <[email protected]> AuthorDate: Mon Jan 12 13:26:04 2026 +0000 Commit: Andras Timar <[email protected]> CommitDate: Tue Jan 13 19:48:32 2026 +0100 a chart using automatic font color renders text black on black in dark mode when there is no chart background and the document mode is to use a dark color for the document color. The intent of this function is to get a color that can be seen against the background. So: a) Always get the background the text is to be rendered on. b) We can consult svtools::FONTCOLOR as a potential foreground color, but reject it if it will not contrast against the background Change-Id: If441050423750fdf0a12f07dd686daf8f7e8b165 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/197108 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Miklos Vajna <[email protected]> diff --git a/editeng/source/editeng/impedit3.cxx b/editeng/source/editeng/impedit3.cxx index 6b087304c6fa..2b5e056a831e 100644 --- a/editeng/source/editeng/impedit3.cxx +++ b/editeng/source/editeng/impedit3.cxx @@ -4742,39 +4742,47 @@ Reference < i18n::XExtendedInputSequenceChecker > const & ImpEditEngine::ImplGet return mxISC; } +static bool hasColorContrast(const Color& rColor, const Color& rBackgroundColor) +{ + if (rColor.IsDark() && !rBackgroundColor.IsDark()) + return true; + if (rColor.IsBright() && !rBackgroundColor.IsBright()) + return true; + return false; +} + Color ImpEditEngine::GetAutoColor(const SvxFont* pFont) const { Color aColor; + Color aBackgroundColor; + if (pFont) //check for char background color + aBackgroundColor = pFont->GetFillColor(); + if (aBackgroundColor == COL_AUTO) // check for aother background (i.e: cell color) + aBackgroundColor = GetBackgroundColor(); + const SfxViewShell* pKitSh = comphelper::LibreOfficeKit::isActive() ? SfxViewShell::Current() : nullptr; if (pKitSh) { - Color aBackgroundColor; - if (pFont) //check for char backgound color - aBackgroundColor = pFont->GetFillColor(); - if (aBackgroundColor == COL_AUTO) // check for aother backgound (i.e: cell color) - aBackgroundColor = GetBackgroundColor(); - if (aBackgroundColor == COL_AUTO) // if everything is auto/transperent then use doc color + if (aBackgroundColor == COL_AUTO) // if everything is auto/transparent then use doc color aBackgroundColor = pKitSh->GetColorConfigColor(svtools::DOCCOLOR); - - if (aBackgroundColor.IsDark()) - aColor = COL_WHITE; - else - aColor = COL_BLACK; } else { + if (aBackgroundColor == COL_AUTO) // if everything is auto/transparent then use doc color + aBackgroundColor = GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor; aColor = GetColorConfig().GetColorValue(svtools::FONTCOLOR, false).nColor; - if ( aColor == COL_AUTO ) - { - if ( GetBackgroundColor().IsDark() ) - aColor = COL_WHITE; - else - aColor = COL_BLACK; - } + // allow using FONTCOLOR if it provides contrast to the current background color + if (aColor != COL_AUTO && hasColorContrast(aColor, aBackgroundColor)) + return aColor; } + if (aBackgroundColor.IsDark()) + aColor = COL_WHITE; + else + aColor = COL_BLACK; + return aColor; } commit d3f266c7d7b6b93420653cff6226742c445c0807 Author: Caolán McNamara <[email protected]> AuthorDate: Thu Oct 23 19:48:31 2025 +0100 Commit: Andras Timar <[email protected]> CommitDate: Tue Jan 13 19:48:14 2026 +0100 handle multiple glyphs mapped to the same unicode character Just use the first seen and drop the other in the absense of a better idea. Change-Id: I591ba777be56cec5f4c14f850b00715920b73d94 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/192923 Reviewed-by: Mike Kaganski <[email protected]> Tested-by: Jenkins CollaboraOffice <[email protected]> diff --git a/svx/source/svdraw/svdpdf.cxx b/svx/source/svdraw/svdpdf.cxx index 90d354b1176e..d798882e5988 100644 --- a/svx/source/svdraw/svdpdf.cxx +++ b/svx/source/svdraw/svdpdf.cxx @@ -77,6 +77,7 @@ #include <osl/diagnose.h> #include <osl/file.hxx> #include <unicode/normalizer2.h> +#include <set> using namespace com::sun::star; @@ -1369,8 +1370,8 @@ static void buildCMapAndFeatures(const OUString& CMapUrl, SvFileStream& Features if (!tud.bfcharlines.empty()) { - OString beginline = OString::number(tud.bfcharlines.size()) + " begincidchar"; - CMap.WriteLine(beginline); + std::set<OString> usedCodes; + std::vector<OString> outputlines; for (const auto& charline : tud.bfcharlines) { assert(charline[0] == '<'); @@ -1392,12 +1393,25 @@ static void buildCMapAndFeatures(const OUString& CMapUrl, SvFileStream& Features if (!sLegacy.isEmpty()) ligatureGlyphToChars[nGlyphIndex] = sLegacy; } + if (usedCodes.insert(sChars).second == false) + { + // This can happen with e.g. unicode '1' mapped to from two variants of that glyph, + // in the absense of a better idea, prefer the first one seen + SAL_INFO("sd.filter", "code: " << sChars << " for glyph " << nGlyphIndex + << " already used earlier"); + continue; + } OString cidcharline = sChars + " " + OString::number(nGlyphIndex); glyphs.push_back(nGlyphIndex); rSubSetInfo.aComponents.back().glyphToChars[nGlyphIndex] = sContents; rSubSetInfo.aComponents.back().charsToGlyph[sContents] = nGlyphIndex; - CMap.WriteLine(cidcharline); + outputlines.push_back(cidcharline); } + + OString beginline = OString::number(outputlines.size()) + " begincidchar"; + CMap.WriteLine(beginline); + for (const auto& cidcharline : outputlines) + CMap.WriteLine(cidcharline); CMap.WriteLine("endcidchar"); rSubSetInfo.aComponents.back().nGlyphCount = tud.bfcharlines.size(); commit d7fe45bdb20ce2257c17848d8426c9a45748461d Author: Justin Luth <[email protected]> AuthorDate: Fri Jan 9 20:49:19 2026 -0500 Commit: Andras Timar <[email protected]> CommitDate: Tue Jan 13 19:47:32 2026 +0100 tdf#170285 xlsx export: don't skip groupshapes of unknown shape type The problem was that Microsoft Excel was unable to cleanly open some round-tripped XLS -> XLSX files. 7.4.4 commit c4d7b9c3ec6e44b96134fdfb036be7f9fcf39f9 skipped grouped shapes because ShapeExport::WriteGroupShape has a loop for all contained shapes [xGroupShape->getCount()] that calls WriteShape(xChild); However, it can only write ShapeExport::IsShapeTypeKnown and com.sun.star.drawing.ControlShape is not known. make CppunitTest_sc_subsequent_export_test2 \ CPPUNIT_TEST_NAME=testTdf170285_controlsInGroupShape Change-Id: I1c281f85a986836389ce5b1d13a84fcbe8640995 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/196948 Reviewed-by: Justin Luth <[email protected]> Tested-by: Jenkins (cherry picked from commit 1efe51bb6d335064b0bdf2c55eb37b417d5af134) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/196978 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Miklos Vajna <[email protected]> diff --git a/sc/qa/unit/data/xls/tdf170285_controlsInGroupShape.xls b/sc/qa/unit/data/xls/tdf170285_controlsInGroupShape.xls new file mode 100644 index 000000000000..f1e186dee53c Binary files /dev/null and b/sc/qa/unit/data/xls/tdf170285_controlsInGroupShape.xls differ diff --git a/sc/qa/unit/subsequent_export_test2.cxx b/sc/qa/unit/subsequent_export_test2.cxx index b298a8dbc6c8..9c6400375cd9 100644 --- a/sc/qa/unit/subsequent_export_test2.cxx +++ b/sc/qa/unit/subsequent_export_test2.cxx @@ -61,6 +61,18 @@ CPPUNIT_TEST_FIXTURE(ScExportTest2, testGroupShape) assertXPath(pDoc, "/xdr:wsDr/xdr:twoCellAnchor/xdr:grpSp/xdr:grpSpPr"); } +CPPUNIT_TEST_FIXTURE(ScExportTest2, testTdf170285_controlsInGroupShape) +{ + createScDoc("xls/tdf170285_controlsInGroupShape.xls"); + + save(TestFilter::XLSM); + xmlDocUniquePtr pDoc = parseExport(u"xl/worksheets/sheet1.xml"_ustr); + // without the fix, this was 0 + assertXPath(pDoc, "//mc:AlternateContent[1]/mc:Choice/x:control", "shapeId", u"1001"); + // without the fix, this was also 0 + assertXPath(pDoc, "//mc:AlternateContent[2]/mc:Choice/x:control", "shapeId", u"1002"); +} + CPPUNIT_TEST_FIXTURE(ScExportTest2, testTdf166724_cellAnchor) { // given a hand-modified document where the checkbox position was changed to not match anchor diff --git a/sc/source/filter/xcl97/xcl97rec.cxx b/sc/source/filter/xcl97/xcl97rec.cxx index 8e6fcb633898..e8518fc540ff 100644 --- a/sc/source/filter/xcl97/xcl97rec.cxx +++ b/sc/source/filter/xcl97/xcl97rec.cxx @@ -236,15 +236,18 @@ void SaveDrawingMLObjects( XclExpObjList& rList, XclExpXmlStream& rStrm ) if (IsVmlObject(rxObj.get()) || !IsValidObject(*rxObj)) continue; + const auto pObj = dynamic_cast<XclObjAny*>(rxObj.get()); if (nSkipObj == 0) aList.push_back(rxObj.get()); else + { --nSkipObj; + // Don't skip objects that GroupShape doesn't know how to export + if (!pObj || !ShapeExport::IsShapeTypeKnown(pObj->GetShape())) + aList.push_back(rxObj.get()); + } - XclObjAny* pObj = nullptr; - if (rxObj->GetObjType() == 0) // group (it can be a subgroup) - pObj = dynamic_cast<XclObjAny*>(rxObj.get()); - if (pObj) + if (pObj && rxObj->GetObjType() == EXC_OBJTYPE_GROUP) // (it can be a subgroup) { css::uno::Reference<css::drawing::XShapes> xShapes(pObj->GetShape(), UNO_QUERY); if (xShapes) commit dec882ed75c23d55760db8397d81d12ff091d2db Author: Karthik Godha <[email protected]> AuthorDate: Sat Jan 10 17:15:47 2026 +0530 Commit: Andras Timar <[email protected]> CommitDate: Tue Jan 13 19:47:16 2026 +0100 tdf#170287: XLS->XLSX Limit font-name length to 31 Change-Id: I4bb731afaf2f741181ee525af473d6bf4dfac5c2 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/196963 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Michael Stahl <[email protected]> diff --git a/sc/source/filter/excel/xestream.cxx b/sc/source/filter/excel/xestream.cxx index 16446d32ebbe..d1650cfc1c41 100644 --- a/sc/source/filter/excel/xestream.cxx +++ b/sc/source/filter/excel/xestream.cxx @@ -901,7 +901,22 @@ sax_fastparser::FSHelperPtr XclXmlUtils::WriteFontData( sax_fastparser::FSHelper } assert(!rFontData.maName.isEmpty() && "Font Name can't be empty"); - pStream->singleElement(nFontId, XML_val, rFontData.maName); + + constexpr sal_Int32 MAX_FONT_LENGTH = 31; + OUString sFont = rFontData.maName; + if (sFont.getLength() > MAX_FONT_LENGTH) + { + sFont = sFont.copy(0, MAX_FONT_LENGTH); + // Truncate till last semi-colon + if (rFontData.maName[MAX_FONT_LENGTH] != ';') + { + sal_Int32 nIndex = sFont.lastIndexOf(';'); + if (nIndex != -1) + sFont = sFont.copy(0, nIndex); + } + } + + pStream->singleElement(nFontId, XML_val, sFont); pStream->singleElement(XML_family, XML_val, OString::number( rFontData.mnFamily )); if (rFontData.mnCharSet != 0) pStream->singleElement(XML_charset, XML_val, OString::number(rFontData.mnCharSet)); commit 361a8a10365b12d3f62d0bcb9263be14b8f9b0d4 Author: Miklos Vajna <[email protected]> AuthorDate: Mon Jan 12 08:45:38 2026 +0100 Commit: Andras Timar <[email protected]> CommitDate: Tue Jan 13 19:47:02 2026 +0100 cool#13988 sw doc compare: fix handling of ephemeral URLs Try to dispatch .uno:CompareDocuments with URL=https://example.com/old.docx, notice that the document gets downloaded multiple times. This is a problem if the URL is set up in a way that the content can be downloaded only once. It seems the problem is in SwView::InsertDoc(), where we access the stream data at least twice: once during file detection and once during actual file import. Fix the problem by reading the remote stream data only once, somewhat similar to what GraphicFilter::LoadGraphic() does for non-file URLs. In practice this fixes doc compare when the URL is generated by the Nextcloud file picker, where doc compare didn't work, but image insertion did work. No testcase, that would require setting up some HTTP server which does more than serving static files. Change-Id: I2cae56db9d6c10f411770f23f1d0b66b24e63440 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/197166 Tested-by: Jenkins Reviewed-by: Miklos Vajna <[email protected]> diff --git a/sw/source/uibase/uiview/view2.cxx b/sw/source/uibase/uiview/view2.cxx index a25b93c468cc..0e5d4b928d8a 100644 --- a/sw/source/uibase/uiview/view2.cxx +++ b/sw/source/uibase/uiview/view2.cxx @@ -163,6 +163,7 @@ #include <o3tl/string_view.hxx> #include <svx/dialog/gotodlg.hxx> +#include <unotools/tempfile.hxx> const char sStatusDelim[] = " : "; @@ -2810,6 +2811,7 @@ void SwView::ExecuteInsertDoc( SfxRequest& rRequest, const SfxPoolItem* pItem ) tools::Long SwView::InsertDoc( sal_uInt16 nSlotId, const OUString& rFileName, const OUString& rFilterName, sal_Int16 nVersion ) { + std::unique_ptr<utl::TempFileNamed> pTempFile; std::unique_ptr<SfxMedium> pMed; SwDocShell* pDocSh = GetDocShell(); @@ -2819,7 +2821,20 @@ tools::Long SwView::InsertDoc( sal_uInt16 nSlotId, const OUString& rFileName, co std::shared_ptr<const SfxFilter> pFilter = rFact.GetFilterContainer()->GetFilter4FilterName( rFilterName ); if ( !pFilter ) { - pMed.reset(new SfxMedium(rFileName, StreamMode::READ, nullptr, nullptr )); + INetURLObject aURL(rFileName); + OUString aFileName = rFileName; + if (aURL.GetProtocol() != INetProtocol::File) + { + // Fetch the remote data only once, since it's possible it gets deleted after the + // first access. + std::unique_ptr<SvStream> pStream + = utl::UcbStreamHelper::CreateStream(rFileName, StreamMode::READ); + pTempFile.reset(new utl::TempFileNamed()); + pTempFile->GetStream(StreamMode::READWRITE)->WriteStream(*pStream); + aFileName = pTempFile->GetURL(); + } + pMed.reset(new SfxMedium(aFileName, StreamMode::READ, nullptr, nullptr)); + SfxFilterMatcher aMatcher( rFact.GetFilterContainer()->GetName() ); pMed->UseInteractionHandler( true ); ErrCode nErr = aMatcher.GuessFilter(*pMed, pFilter, SfxFilterFlags::NONE); commit 326551979ee8a425005d48846a0e197e3a429f42 Author: Karthik Godha <[email protected]> AuthorDate: Mon Jan 12 14:22:33 2026 +0530 Commit: Andras Timar <[email protected]> CommitDate: Tue Jan 13 19:46:36 2026 +0100 tdf#169952: Convert static counters to member variables Move static counters of `DrawingML` and `ShapeExport` to `XmlFilterBase` and make them member variables. Change-Id: I5ede57f04324630107ee179e58b9183fc62ee5ff Reviewed-on: https://gerrit.libreoffice.org/c/core/+/197079 Reviewed-by: Michael Stahl <[email protected]> Tested-by: Jenkins CollaboraOffice <[email protected]> diff --git a/include/oox/core/xmlfilterbase.hxx b/include/oox/core/xmlfilterbase.hxx index fe69eb7f3c10..3a0c35ffd638 100644 --- a/include/oox/core/xmlfilterbase.hxx +++ b/include/oox/core/xmlfilterbase.hxx @@ -257,6 +257,11 @@ public: OUString getNamespaceURL(sal_Int32 nNSID) const; + sal_Int32 getNewDrawingUniqueId() { return ++mnDrawingMLCount; } + sal_Int32 getNewVMLUniqueId() { return ++mnVmlCount; } + sal_Int32 getNewChartUniqueId() { return ++mnChartCount; } + sal_Int32 getNewOLEUniqueId() { return ++mnOLECount; } + protected: virtual css::uno::Reference< css::io::XInputStream > implGetInputStream( utl::MediaDescriptor& rMediaDesc ) const override; @@ -280,6 +285,12 @@ private: sal_Int32 mnMaxDocId; bool mbMSO2007; bool mbMSO; + + sal_Int32 mnDrawingMLCount = 0; + sal_Int32 mnVmlCount = 0; + sal_Int32 mnChartCount = 0; + sal_Int32 mnOLECount = 0; + protected: bool mbMissingExtDrawing; }; diff --git a/include/oox/export/drawingml.hxx b/include/oox/export/drawingml.hxx index 027a7817a4a2..2c54d1f9ef00 100644 --- a/include/oox/export/drawingml.hxx +++ b/include/oox/export/drawingml.hxx @@ -294,9 +294,6 @@ class DrawingML { private: - OOX_DLLPUBLIC static sal_Int32 mnDrawingMLCount; - OOX_DLLPUBLIC static sal_Int32 mnVmlCount; - /// To specify where write eg. the images to (like 'ppt', or 'word' - according to the OPC). DocumentType meDocumentType; /// Parent exporter, used for text callback. @@ -312,7 +309,6 @@ protected: /// If set, this is the parent of the currently handled shape. css::uno::Reference<css::drawing::XShape> m_xParent; bool mbIsBackgroundDark; - OOX_DLLPUBLIC static sal_Int32 mnChartCount; /// True when exporting presentation placeholder shape. bool mbPlaceholder; @@ -530,12 +526,6 @@ public: static bool IsGroupShape( const css::uno::Reference< css::drawing::XShape >& rXShape ); sal_Int32 getBulletMarginIndentation (const css::uno::Reference< css::beans::XPropertySet >& rXPropSet,sal_Int16 nLevel, std::u16string_view propName); - OOX_DLLPUBLIC static void ResetMlCounters(); - - static sal_Int32 getNewDrawingUniqueId() { return ++mnDrawingMLCount; } - static sal_Int32 getNewVMLUniqueId() { return ++mnVmlCount; } - static sal_Int32 getNewChartUniqueId() { return ++mnChartCount; } - // A Helper to decide the script type for given text in order to call WriteRunProperties. static sal_Int16 GetScriptType(const OUString& rStr); diff --git a/include/oox/export/shapes.hxx b/include/oox/export/shapes.hxx index f5b88f04724c..d05d0438a4e6 100644 --- a/include/oox/export/shapes.hxx +++ b/include/oox/export/shapes.hxx @@ -77,9 +77,6 @@ namespace oox::drawingml { class OOX_DLLPUBLIC ShapeExport : public DrawingML { -private: - int m_nEmbeddedObjects; - public: typedef std::unordered_map< css::uno::Reference< css::drawing::XShape>, sal_Int32> ShapeHashMap; diff --git a/oox/source/export/chartexport.cxx b/oox/source/export/chartexport.cxx index 1d44dd413a57..f7ac1f78fb51 100644 --- a/oox/source/export/chartexport.cxx +++ b/oox/source/export/chartexport.cxx @@ -1888,7 +1888,7 @@ void ChartExport::exportAdditionalShapes( const Reference< css::chart::XChartDoc OUString sId; const char* sFullPath = nullptr; const char* sRelativePath = nullptr; - sal_Int32 nDrawing = getNewDrawingUniqueId(); + sal_Int32 nDrawing = GetFB()->getNewDrawingUniqueId(); switch (GetDocumentType()) { diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx index d96551868793..6dfb8357c6aa 100644 --- a/oox/source/export/drawingml.cxx +++ b/oox/source/export/drawingml.cxx @@ -249,11 +249,6 @@ void WriteGradientPath(const basegfx::BGradient& rBGradient, const FSHelperPtr& } } -// not thread safe -sal_Int32 DrawingML::mnDrawingMLCount = 0; -sal_Int32 DrawingML::mnVmlCount = 0; -sal_Int32 DrawingML::mnChartCount = 0; - DrawingML::DrawingML(::sax_fastparser::FSHelperPtr pFS, ::oox::core::XmlFilterBase* pFB, DocumentType eDocumentType, DMLTextExport* pTextExport) : meDocumentType(eDocumentType) , mpTextExport(pTextExport) @@ -299,13 +294,6 @@ sal_Int16 DrawingML::GetScriptType(const OUString& rStr) return css::i18n::ScriptType::LATIN; } -void DrawingML::ResetMlCounters() -{ - mnDrawingMLCount = 0; - mnVmlCount = 0; - mnChartCount = 0; -} - bool DrawingML::GetProperty( const Reference< XPropertySet >& rXPropertySet, const OUString& aName ) { try diff --git a/oox/source/export/shapes.cxx b/oox/source/export/shapes.cxx index 30e08d2a9720..3ddf1c3fbd7f 100644 --- a/oox/source/export/shapes.cxx +++ b/oox/source/export/shapes.cxx @@ -326,7 +326,6 @@ namespace oox::drawingml { ShapeExport::ShapeExport( sal_Int32 nXmlNamespace, FSHelperPtr pFS, ShapeHashMap* pShapeMap, XmlFilterBase* pFB, DocumentType eDocumentType, DMLTextExport* pTextExport, bool bUserShapes ) : DrawingML( std::move(pFS), pFB, eDocumentType, pTextExport ) - , m_nEmbeddedObjects(0) , mnShapeIdMax( 1 ) , mbUserShapes( bUserShapes ) , mnXmlNamespace( nXmlNamespace ) @@ -2846,7 +2845,7 @@ ShapeExport& ShapeExport::WriteOLE2Shape( const Reference< XShape >& xShape ) // TODO: With Chart extracted this cannot really happen since // no Chart could've been added at all ChartExport aChartExport( mnXmlNamespace, GetFS(), xChartDoc, GetFB(), GetDocumentType() ); - aChartExport.WriteChartObj( xShape, GetNewShapeID( xShape ), ++mnChartCount ); + aChartExport.WriteChartObj(xShape, GetNewShapeID(xShape), mpFB->getNewChartUniqueId()); #endif return *this; } @@ -2964,7 +2963,7 @@ ShapeExport& ShapeExport::WriteOLE2Shape( const Reference< XShape >& xShape ) assert(!sRelationType.isEmpty()); assert(!sSuffix.isEmpty()); - OUString sNumber = OUString::number(++m_nEmbeddedObjects); + OUString sNumber = OUString::number(mpFB->getNewOLEUniqueId()); OUString sFileName = u"embeddings/oleObject"_ustr + sNumber + u"."_ustr + sSuffix; OUString sFilePath = GetComponentDir() + u"/"_ustr + sFileName; uno::Reference<io::XOutputStream> const xOutStream(mpFB->openFragmentStream(sFilePath, sMediaType)); diff --git a/sc/source/filter/excel/xeescher.cxx b/sc/source/filter/excel/xeescher.cxx index 5daf880b1a5a..b2ce7ac4f7e7 100644 --- a/sc/source/filter/excel/xeescher.cxx +++ b/sc/source/filter/excel/xeescher.cxx @@ -1413,7 +1413,7 @@ OUString XclExpTbxControlObj::SaveControlPropertiesXml(XclExpXmlStream& rStrm) c { case EXC_OBJTYPE_CHECKBOX: { - const sal_Int32 nDrawing = DrawingML::getNewDrawingUniqueId(); + const sal_Int32 nDrawing = rStrm.getNewDrawingUniqueId(); sax_fastparser::FSHelperPtr pFormControl = rStrm.CreateOutputStream( XclXmlUtils::GetStreamName( "xl/", "ctrlProps/ctrlProps", nDrawing ), XclXmlUtils::GetStreamName( "../", "ctrlProps/ctrlProps", nDrawing ), @@ -1463,7 +1463,7 @@ OUString XclExpTbxControlObj::SaveControlPropertiesXml(XclExpXmlStream& rStrm) c } case EXC_OBJTYPE_BUTTON: { - sal_Int32 nDrawing = DrawingML::getNewDrawingUniqueId(); + sal_Int32 nDrawing = rStrm.getNewDrawingUniqueId(); sax_fastparser::FSHelperPtr pFormControl = rStrm.CreateOutputStream( XclXmlUtils::GetStreamName("xl/", "ctrlProps/ctrlProps", nDrawing), XclXmlUtils::GetStreamName("../", "ctrlProps/ctrlProps", nDrawing), @@ -1641,7 +1641,7 @@ void XclExpChartObj::SaveXml( XclExpXmlStream& rStrm ) ChartExport aChartExport(XML_xdr, pDrawing, GetChartDoc(), &rStrm, drawingml::DOCUMENT_XLSX); auto pURLTransformer = std::make_shared<ScURLTransformer>(*mpDoc); aChartExport.SetURLTranslator(pURLTransformer); - sal_Int32 nChartCount = oox::drawingml::DrawingML::getNewChartUniqueId(); + sal_Int32 nChartCount = rStrm.getNewChartUniqueId(); sal_Int32 nID = rStrm.GetUniqueId(); aChartExport.WriteChartObj( mxShape, nID, nChartCount ); // TODO: get the correcto chart number diff --git a/sc/source/filter/excel/xestream.cxx b/sc/source/filter/excel/xestream.cxx index db04d2d6812c..16446d32ebbe 100644 --- a/sc/source/filter/excel/xestream.cxx +++ b/sc/source/filter/excel/xestream.cxx @@ -1038,7 +1038,6 @@ bool XclExpXmlStream::exportDocument() // SfxMedium::GetOutStream() anywhere in the xlsx export filter code! // Instead, write via XOutputStream instance. rtl::Reference<SotStorage> rStorage; - drawingml::DrawingML::ResetMlCounters(); auto& rGraphicExportCache = drawingml::GraphicExportCache::get(); diff --git a/sc/source/filter/xcl97/xcl97rec.cxx b/sc/source/filter/xcl97/xcl97rec.cxx index e07e84c5e39d..8e6fcb633898 100644 --- a/sc/source/filter/xcl97/xcl97rec.cxx +++ b/sc/source/filter/xcl97/xcl97rec.cxx @@ -258,7 +258,7 @@ void SaveDrawingMLObjects( XclExpObjList& rList, XclExpXmlStream& rStrm ) if (aList.empty()) return; - sal_Int32 nDrawing = drawingml::DrawingML::getNewDrawingUniqueId(); + sal_Int32 nDrawing = rStrm.getNewDrawingUniqueId(); OUString sId; // export in [Content_Types].xml sax_fastparser::FSHelperPtr pDrawing = rStrm.CreateOutputStream( @@ -345,7 +345,7 @@ void SaveVmlObjects( XclExpObjList& rList, XclExpXmlStream& rStrm ) if( GetVmlObjectCount( rList ) == 0 ) return; - sal_Int32 nDrawing = drawingml::DrawingML::getNewVMLUniqueId(); + sal_Int32 nDrawing = rStrm.getNewVMLUniqueId(); OUString sId; sax_fastparser::FSHelperPtr pVmlDrawing = rStrm.CreateOutputStream( XclXmlUtils::GetStreamName( "xl/", "drawings/vmlDrawing", nDrawing ), diff --git a/sd/qa/unit/data/odp/tdf169952.odp b/sd/qa/unit/data/odp/tdf169952.odp new file mode 100644 index 000000000000..0888486ab21c Binary files /dev/null and b/sd/qa/unit/data/odp/tdf169952.odp differ diff --git a/sd/qa/unit/export-tests-ooxml3.cxx b/sd/qa/unit/export-tests-ooxml3.cxx index ea66d313e482..3053439ab59a 100644 --- a/sd/qa/unit/export-tests-ooxml3.cxx +++ b/sd/qa/unit/export-tests-ooxml3.cxx @@ -1142,6 +1142,16 @@ CPPUNIT_TEST_FIXTURE(SdOOXMLExportTest3, testTdf169524) pXmlDoc, "/p:sldMaster/p:cSld/p:spTree/p:sp[2]/p:txBody/a:lstStyle/a:lvl1pPr", "marL"); } +CPPUNIT_TEST_FIXTURE(SdOOXMLExportTest3, testTdf169952) +{ + createSdImpressDoc("odp/tdf169952.odp"); + save(u"Impress Office Open XML"_ustr); + + xmlDocUniquePtr pXmlDoc = parseExport(u"ppt/charts/chart2.xml"_ustr); + + CPPUNIT_ASSERT_MESSAGE("Without the fix chart2.xml is not exported", pXmlDoc); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/filter/eppt/pptx-epptooxml.cxx b/sd/source/filter/eppt/pptx-epptooxml.cxx index af2168caf0a5..f9b3faab3b69 100644 --- a/sd/source/filter/eppt/pptx-epptooxml.cxx +++ b/sd/source/filter/eppt/pptx-epptooxml.cxx @@ -441,7 +441,6 @@ bool PowerPointExport::importDocument() noexcept bool PowerPointExport::exportDocument() { - drawingml::DrawingML::ResetMlCounters(); auto& rGraphicExportCache = drawingml::GraphicExportCache::get(); rGraphicExportCache.push(); commit 0b9dae52f051d12286e81250b6d70290b703aa1f Author: Caolán McNamara <[email protected]> AuthorDate: Mon Jan 12 08:42:08 2026 +0000 Commit: Andras Timar <[email protected]> CommitDate: Tue Jan 13 19:46:13 2026 +0100 cid#1680326 Uninitialized scalar field Change-Id: I6f50ecc2973700553692589c88538b190dbc5cf5 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/197071 Tested-by: Jenkins Reviewed-by: Caolán McNamara <[email protected]> diff --git a/vcl/unx/generic/glyphs/freetype_glyphcache.cxx b/vcl/unx/generic/glyphs/freetype_glyphcache.cxx index 8ebff2ada0a5..26b0f4d72d83 100644 --- a/vcl/unx/generic/glyphs/freetype_glyphcache.cxx +++ b/vcl/unx/generic/glyphs/freetype_glyphcache.cxx @@ -78,7 +78,8 @@ FreetypeFontFile::FreetypeFontFile( OString aNativeFileName ) mpFileMap( nullptr ), mnFileSize( 0 ), mnRefCount( 0 ), - mnLangBoost( 0 ) + mnLangBoost( 0 ), + mnHandle( 0 ) { // boost font preference if UI language is mentioned in filename int nPos = maNativeFileName.lastIndexOf( '_' ); commit 96d3a9a6a98cb129d1c27d846825e050eec67975 Author: Caolán McNamara <[email protected]> AuthorDate: Fri Jan 9 09:59:46 2026 +0000 Commit: Andras Timar <[email protected]> CommitDate: Tue Jan 13 19:45:55 2026 +0100 add something to report to kit when core is idle Change-Id: Idf5e1659d111a9351e4833114d4f1cb899cc6f17 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/196911 Reviewed-by: Miklos Vajna <[email protected]> Tested-by: Jenkins CollaboraOffice <[email protected]> (cherry picked from commit ea6534827d708f24d4b9d7e176dee738e5d24598) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/197075 Tested-by: Jenkins Reviewed-by: Caolán McNamara <[email protected]> diff --git a/desktop/inc/lib/init.hxx b/desktop/inc/lib/init.hxx index f556dbf5515a..54e6a1b27535 100644 --- a/desktop/inc/lib/init.hxx +++ b/desktop/inc/lib/init.hxx @@ -30,6 +30,7 @@ #include <tools/gen.hxx> #include <sfx2/lokcallback.hxx> #include <sfx2/lokhelper.hxx> +#include <vcl/idle.hxx> #include <desktop/dllapi.h> @@ -254,12 +255,24 @@ namespace desktop { DECL_LINK(FlushQueue, void*, void); }; + struct WaitUntilIdle + { + WaitUntilIdle(); + + Idle maIdle; + OUString msIdleId; + std::shared_ptr<CallbackFlushHandler> mpCallbackFlushHandler; + + DECL_LINK(IdleHdl, Timer*, void); + }; + struct DESKTOP_DLLPUBLIC LibLODocument_Impl : public LibreOfficeKitDocument { css::uno::Reference<css::lang::XComponent> mxComponent; std::shared_ptr< LibreOfficeKitDocumentClass > m_pDocumentClass; std::map<size_t, std::shared_ptr<CallbackFlushHandler>> mpCallbackFlushHandlers; const int mnDocumentId; + WaitUntilIdle maIdleHelper; std::set<OUString> maFontsMissing; explicit LibLODocument_Impl(css::uno::Reference<css::lang::XComponent> xComponent, diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx index a7acdc10905b..b1ea4870ca37 100644 --- a/desktop/source/lib/init.cxx +++ b/desktop/source/lib/init.cxx @@ -67,6 +67,7 @@ #include <utility> #include <vcl/commandinfoprovider.hxx> #include <vcl/errinf.hxx> +#include <vcl/idletask.hxx> #include <vcl/lok.hxx> #include <o3tl/any.hxx> #include <o3tl/unit_conversion.hxx> @@ -1451,6 +1452,23 @@ int getDocumentType (LibreOfficeKitDocument* pThis) } // anonymous namespace +WaitUntilIdle::WaitUntilIdle() + : maIdle{"LibLODocument IdleTask"} +{ + maIdle.SetPriority(TaskPriority::TOOLKIT_DEBUG); + maIdle.SetInvokeHandler(LINK(this, WaitUntilIdle, IdleHdl)); +} + +IMPL_LINK_NOARG(WaitUntilIdle, IdleHdl, Timer*, void) +{ + tools::JsonWriter aJson; + aJson.put("commandName", ".uno:ReportWhenIdle"); + aJson.put("idleID", msIdleId); + mpCallbackFlushHandler->queue(LOK_CALLBACK_UNO_COMMAND_RESULT, aJson.finishAndGetAsOString()); + mpCallbackFlushHandler.reset(); + msIdleId.clear(); +} + LibLODocument_Impl::LibLODocument_Impl(uno::Reference <css::lang::XComponent> xComponent, int nDocumentId) : mxComponent(std::move(xComponent)) , mnDocumentId(nDocumentId) @@ -5648,6 +5666,24 @@ static void doc_postUnoCommand(LibreOfficeKitDocument* pThis, const char* pComma return; } + else if (gImpl && aCommand == ".uno:ReportWhenIdle") + { + assert(pDocument->maIdleHelper.msIdleId.isEmpty() && "idle id should be uset"); + pDocument->maIdleHelper.mpCallbackFlushHandler = pDocument->mpCallbackFlushHandlers[nView]; + + for (const beans::PropertyValue& rPropValue : aPropertyValuesVector) + { + if (rPropValue.Name == "idleID") + { + rPropValue.Value >>= pDocument->maIdleHelper.msIdleId; + } + } + + assert(!pDocument->maIdleHelper.msIdleId.isEmpty() && "idle id should be set"); + + pDocument->maIdleHelper.maIdle.Start(); + return; + } if (aCommand != ".uno:Save") { commit 0e67ce64c2108312d87f6b73ed37b0135fecf73b Author: Caolán McNamara <[email protected]> AuthorDate: Mon Jan 5 09:20:24 2026 +0000 Commit: Andras Timar <[email protected]> CommitDate: Tue Jan 13 19:45:34 2026 +0100 flatten SdrObjEditView::TextEditDrawing no logic change intended Change-Id: Ied15e90341d4e7e8f0228354dfadec2342138162 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/196603 Reviewed-by: Caolán McNamara <[email protected]> Tested-by: Jenkins diff --git a/svx/source/svdraw/svdedxv.cxx b/svx/source/svdraw/svdedxv.cxx index 3692e875c898..6cd139c86e6f 100644 --- a/svx/source/svdraw/svdedxv.cxx +++ b/svx/source/svdraw/svdedxv.cxx @@ -929,31 +929,28 @@ void SdrObjEditView::TextEditDrawing(SdrPaintWindow& rPaintWindow) // to update accordingly (will update selection, too). Suppress new // stuff when LibreOfficeKit is active EditViewInvalidate(tools::Rectangle()); + return; } - else - { - // draw old text edit stuff - if (IsTextEdit()) - { - const SdrOutliner* pActiveOutliner = GetTextEditOutliner(); - if (pActiveOutliner) - { - const sal_uInt32 nViewCount(pActiveOutliner->GetViewCount()); + // draw old text edit stuff + if (!IsTextEdit()) + return; - if (nViewCount) - { - const vcl::Region& rRedrawRegion = rPaintWindow.GetRedrawRegion(); - const tools::Rectangle aCheckRect(rRedrawRegion.GetBoundRect()); + const SdrOutliner* pActiveOutliner = GetTextEditOutliner(); + if (!pActiveOutliner) + return; - OutlinerView* pOLV = pActiveOutliner->GetView(0); - SdrPage* pPage = GetSdrPageView()->GetPage(); - pOLV->SetBackgroundColor(pPage->GetPageBackgroundColor(GetSdrPageView(), true)); - ImpPaintOutlinerView(*pOLV, aCheckRect, rPaintWindow.GetTargetOutputDevice()); - } - } - } - } + const sal_uInt32 nViewCount(pActiveOutliner->GetViewCount()); + if (!nViewCount) + return; + + const vcl::Region& rRedrawRegion = rPaintWindow.GetRedrawRegion(); + const tools::Rectangle aCheckRect(rRedrawRegion.GetBoundRect()); + + OutlinerView* pOLV = pActiveOutliner->GetView(0); + SdrPage* pPage = GetSdrPageView()->GetPage(); + pOLV->SetBackgroundColor(pPage->GetPageBackgroundColor(GetSdrPageView(), true)); + ImpPaintOutlinerView(*pOLV, aCheckRect, rPaintWindow.GetTargetOutputDevice()); } void SdrObjEditView::ImpPaintOutlinerView(OutlinerView& rOutlView, const tools::Rectangle& rRect, commit e4e05682d47e13116a535ad6a8606bca9a3ffbca Author: Caolán McNamara <[email protected]> AuthorDate: Mon Jan 5 09:18:18 2026 +0000 Commit: Andras Timar <[email protected]> CommitDate: Tue Jan 13 19:45:14 2026 +0100 nViewCount is always > 0 here so simplify Change-Id: Ie0e34d1c58e4a6e7b4c2fce5793b41e8f88e142d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/196602 Reviewed-by: Caolán McNamara <[email protected]> Tested-by: Caolán McNamara <[email protected]> diff --git a/svx/source/svdraw/svdedxv.cxx b/svx/source/svdraw/svdedxv.cxx index 6fa858a881a5..3692e875c898 100644 --- a/svx/source/svdraw/svdedxv.cxx +++ b/svx/source/svdraw/svdedxv.cxx @@ -946,16 +946,10 @@ void SdrObjEditView::TextEditDrawing(SdrPaintWindow& rPaintWindow) const vcl::Region& rRedrawRegion = rPaintWindow.GetRedrawRegion(); const tools::Rectangle aCheckRect(rRedrawRegion.GetBoundRect()); - if (sal_uInt32 i(0); i < nViewCount) - { - OutlinerView* pOLV = pActiveOutliner->GetView(i); - SdrPage* pPage = GetSdrPageView()->GetPage(); - pOLV->SetBackgroundColor( - pPage->GetPageBackgroundColor(GetSdrPageView(), true)); - ImpPaintOutlinerView(*pOLV, aCheckRect, - rPaintWindow.GetTargetOutputDevice()); - return; - } + OutlinerView* pOLV = pActiveOutliner->GetView(0); + SdrPage* pPage = GetSdrPageView()->GetPage(); + pOLV->SetBackgroundColor(pPage->GetPageBackgroundColor(GetSdrPageView(), true)); + ImpPaintOutlinerView(*pOLV, aCheckRect, rPaintWindow.GetTargetOutputDevice()); } } } commit 6446627ffc4b8b9f51bfe1446f7bf877c5c960e0 Author: Caolán McNamara <[email protected]> AuthorDate: Mon Jan 5 09:14:23 2026 +0000 Commit: Andras Timar <[email protected]> CommitDate: Tue Jan 13 19:44:58 2026 +0100 comphelper::LibreOfficeKit::isActive() is always true in this branch given the earlier !comphelper::LibreOfficeKit::isActive() check, so simplify here Change-Id: I5f95035cce6d2d4e763bd1dc4be2eae2bcd35a39 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/196536 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Miklos Vajna <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/196601 Tested-by: Jenkins Reviewed-by: Caolán McNamara <[email protected]> diff --git a/svx/source/svdraw/svdedxv.cxx b/svx/source/svdraw/svdedxv.cxx index bc7a121c4565..6fa858a881a5 100644 --- a/svx/source/svdraw/svdedxv.cxx +++ b/svx/source/svdraw/svdedxv.cxx @@ -946,27 +946,15 @@ void SdrObjEditView::TextEditDrawing(SdrPaintWindow& rPaintWindow) const vcl::Region& rRedrawRegion = rPaintWindow.GetRedrawRegion(); const tools::Rectangle aCheckRect(rRedrawRegion.GetBoundRect()); - for (sal_uInt32 i(0); i < nViewCount; i++) + if (sal_uInt32 i(0); i < nViewCount) { OutlinerView* pOLV = pActiveOutliner->GetView(i); - - // If rPaintWindow knows that the output device is a render - // context and is aware of the underlying vcl::Window, - // compare against that; that's how double-buffering can - // still find the matching OutlinerView. - OutputDevice* pOutputDevice = rPaintWindow.GetWindow() - ? rPaintWindow.GetWindow()->GetOutDev() - : &rPaintWindow.GetOutputDevice(); - if (pOLV->GetWindow()->GetOutDev() == pOutputDevice - || comphelper::LibreOfficeKit::isActive()) - { - SdrPage* pPage = GetSdrPageView()->GetPage(); - pOLV->SetBackgroundColor( - pPage->GetPageBackgroundColor(GetSdrPageView(), true)); - ImpPaintOutlinerView(*pOLV, aCheckRect, - rPaintWindow.GetTargetOutputDevice()); - return; - } + SdrPage* pPage = GetSdrPageView()->GetPage(); + pOLV->SetBackgroundColor( + pPage->GetPageBackgroundColor(GetSdrPageView(), true)); + ImpPaintOutlinerView(*pOLV, aCheckRect, + rPaintWindow.GetTargetOutputDevice()); + return; } } } commit 1c2f9e5e3e088e2e78ee438f3b8b9e79820ebdcc Author: Shardul Vikram Singh <[email protected]> AuthorDate: Sun Nov 2 11:15:51 2025 +0530 Commit: Andras Timar <[email protected]> CommitDate: Tue Jan 13 19:37:01 2026 +0100 Convert Overwrite tunneled dialog to JSDialog Change-Id: I713d3a845558dfbb69bc0175f7770f94e7ba396c Reviewed-on: https://gerrit.libreoffice.org/c/core/+/193297 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Szymon Kłos <[email protected]> diff --git a/vcl/jsdialog/enabled.cxx b/vcl/jsdialog/enabled.cxx index 603186c807d6..1cea2ac404a7 100644 --- a/vcl/jsdialog/enabled.cxx +++ b/vcl/jsdialog/enabled.cxx @@ -111,6 +111,7 @@ constexpr auto CuiDialogList { u"cui/ui/slantcornertabpage.ui" }, { u"cui/ui/spinbox.ui" }, { u"cui/ui/queryduplicatedialog.ui" }, + { u"cui/ui/querysetinsmodedialog.ui" }, { u"cui/ui/similaritysearchdialog.ui" }, { u"cui/ui/specialcharacters.ui" }, { u"cui/ui/spellingdialog.ui" }, commit e498ba98e31171c32067ade5fdd0eb041b952e63 Author: NickWingate <[email protected]> AuthorDate: Wed Sep 10 12:59:28 2025 +0100 Commit: Andras Timar <[email protected]> CommitDate: Tue Jan 13 19:35:41 2026 +0100 QuickFindPanel: Add navigation (up, down) buttons We add `iter_nth_from_start` to `weld::TreeView` to access the last entry in the treeview. Signed-off-by: NickWingate <[email protected]> Change-Id: Ib2f71719a84ab6f1a73fb1c844e68c3907d69c0c Reviewed-on: https://gerrit.libreoffice.org/c/core/+/190754 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Szymon Kłos <[email protected]> diff --git a/include/vcl/weld.hxx b/include/vcl/weld.hxx index f6042b723602..1aa0ebf9e55a 100644 --- a/include/vcl/weld.hxx +++ b/include/vcl/weld.hxx @@ -1361,6 +1361,17 @@ public: return false; return iter_nth_sibling(rIter, nChild); } + bool iter_nth_from_start(TreeIter& rIter, int nIndex) const + { + if (!get_iter_first(rIter)) + return false; + for (int i = 0; i < nIndex; ++i) + { + if (!iter_next(rIter)) + return false; + } + return true; + } virtual bool iter_parent(TreeIter& rIter) const = 0; virtual int get_iter_depth(const TreeIter& rIter) const = 0; virtual int get_iter_index_in_parent(const TreeIter& rIter) const = 0; diff --git a/sw/source/uibase/inc/QuickFindPanel.hxx b/sw/source/uibase/inc/QuickFindPanel.hxx index 6dcc9cfe913d..310710e8af9e 100644 --- a/sw/source/uibase/inc/QuickFindPanel.hxx +++ b/sw/source/uibase/inc/QuickFindPanel.hxx @@ -65,8 +65,11 @@ private: std::unique_ptr<weld::Toolbar> m_xFindAndReplaceToolbar; std::unique_ptr<ToolbarUnoDispatcher> m_xFindAndReplaceToolbarDispatch; std::unique_ptr<weld::Box> m_xTopbar; + std::unique_ptr<weld::Box> m_xQuickFindControls; std::unique_ptr<weld::TreeView> m_xSearchFindsList; std::unique_ptr<weld::Label> m_xSearchFindFoundTimesLabel; + std::unique_ptr<weld::Button> m_xFindNextButton; + std::unique_ptr<weld::Button> m_xFindPreviousButton; SwWrtShell* m_pWrtShell; std::unique_ptr<svt::AcceleratorExecute> m_xAcceleratorExecute; @@ -94,7 +97,10 @@ private: DECL_LINK(SearchFindsListMousePressHandler, const MouseEvent&, bool); DECL_LINK(SearchOptionsToolbarClickedHandler, const OUString&, void); DECL_LINK(FindAndReplaceToolbarClickedHandler, const OUString&, void); + DECL_LINK(FindNextClickedHandler, weld::Button&, void); + DECL_LINK(FindPreviousClickedHandler, weld::Button&, void); + void NavigateSearchFinds(bool bNext); void FillSearchFindsList(); static OUString CreatePageEntry(sal_Int32 nPageNum); bool IsPageEntry(const weld::TreeIter& rEntry); diff --git a/sw/source/uibase/sidebar/QuickFindPanel.cxx b/sw/source/uibase/sidebar/QuickFindPanel.cxx index 254623ac86f5..c0d0378435fc 100644 --- a/sw/source/uibase/sidebar/QuickFindPanel.cxx +++ b/sw/source/uibase/sidebar/QuickFindPanel.cxx @@ -149,8 +149,11 @@ QuickFindPanel::QuickFindPanel(weld::Widget* pParent, const uno::Reference<frame , m_xFindAndReplaceToolbarDispatch( new ToolbarUnoDispatcher(*m_xFindAndReplaceToolbar, *m_xBuilder, rxFrame)) , m_xTopbar(m_xBuilder->weld_box(u"topbar"_ustr)) + , m_xQuickFindControls(m_xBuilder->weld_box(u"quickfindcontrols"_ustr)) , m_xSearchFindsList(m_xBuilder->weld_tree_view(u"searchfinds"_ustr)) , m_xSearchFindFoundTimesLabel(m_xBuilder->weld_label("numberofsearchfinds")) + , m_xFindNextButton(m_xBuilder->weld_button(u"findnext"_ustr)) + , m_xFindPreviousButton(m_xBuilder->weld_button(u"findprevious"_ustr)) , m_pWrtShell(::GetActiveWrtShell()) , m_xAcceleratorExecute(svt::AcceleratorExecute::createAcceleratorHelper()) , m_pBindings(pBindings) @@ -198,6 +201,11 @@ QuickFindPanel::QuickFindPanel(weld::Widget* pParent, const uno::Reference<frame LINK(this, QuickFindPanel, SearchFindsListRowActivatedHandler)); m_xSearchFindsList->connect_mouse_press( LINK(this, QuickFindPanel, SearchFindsListMousePressHandler)); + + m_xQuickFindControls->set_visible(false); + + m_xFindNextButton->connect_clicked(LINK(this, QuickFindPanel, FindNextClickedHandler)); + m_xFindPreviousButton->connect_clicked(LINK(this, QuickFindPanel, FindPreviousClickedHandler)); } IMPL_LINK_NOARG(QuickFindPanel, SearchOptionsToolbarClickedHandler, const OUString&, void) @@ -288,6 +296,7 @@ IMPL_LINK_NOARG(QuickFindPanel, SearchFindEntryChangedHandler, weld::Entry&, voi m_xSearchFindEntry->set_message_type(weld::EntryMessageType::Normal); m_xSearchFindsList->clear(); m_xSearchFindFoundTimesLabel->set_label(OUString()); + m_xQuickFindControls->set_visible(false); } IMPL_LINK_NOARG(QuickFindPanel, SearchFindEntryActivateHandler, weld::Entry&, bool) @@ -467,6 +476,8 @@ IMPL_LINK_NOARG(QuickFindPanel, SearchFindsListSelectionChangedHandler, weld::Tr sText = sText.replaceFirst("%1", OUString::number(sId.toUInt32() + 1)); sText = sText.replaceFirst("%2", OUString::number(nSearchFindFoundTimes)); m_xSearchFindFoundTimesLabel->set_label(sText); + if (nSearchFindFoundTimes > 1) + m_xQuickFindControls->set_visible(true); SwShellCursor* pShellCursor = m_pWrtShell->GetCursor_(); std::vector<basegfx::B2DRange> vRanges; @@ -492,11 +503,73 @@ IMPL_LINK_NOARG(QuickFindPanel, SearchFindsListRowActivatedHandler, weld::TreeVi return true; } +IMPL_LINK_NOARG(QuickFindPanel, FindNextClickedHandler, weld::Button&, void) +{ + NavigateSearchFinds(true); // true = next/down +} + +IMPL_LINK_NOARG(QuickFindPanel, FindPreviousClickedHandler, weld::Button&, void) +{ + NavigateSearchFinds(false); // false = previous/up +} + +void QuickFindPanel::NavigateSearchFinds(bool bNext) +{ + if (!m_xSearchFindsList || m_xSearchFindsList->n_children() == 0) + return; + + std::unique_ptr<weld::TreeIter> xEntry(m_xSearchFindsList->make_iterator()); + + bool bMoved = false; + + // no current selection, select first/last entry + if (!m_xSearchFindsList->get_cursor(xEntry.get())) + { + bMoved = m_xSearchFindsList->iter_nth_from_start( + *xEntry, bNext ? 0 : m_xSearchFindsList->n_children() - 1); + } + else + { + if (bNext) + bMoved = m_xSearchFindsList->iter_next(*xEntry); + else + bMoved = m_xSearchFindsList->iter_previous(*xEntry); + } + + if (!bMoved) + { + bMoved = m_xSearchFindsList->iter_nth_from_start( + *xEntry, bNext ? 0 : m_xSearchFindsList->n_children() - 1); + } + + // Keep going until we find a non-page entry + while (IsPageEntry(*xEntry)) + { + // skip page entry + if (bNext) + bMoved = m_xSearchFindsList->iter_next(*xEntry); + else + bMoved = m_xSearchFindsList->iter_previous(*xEntry); + + if (!bMoved) + { + bMoved = m_xSearchFindsList->iter_nth_from_start( + *xEntry, bNext ? 0 : m_xSearchFindsList->n_children() - 1); + } + } + m_xSearchFindsList->set_cursor(*xEntry); + + // todo: ideally we dont need to manually call this handler, but select disables event propagation see SalInstanceTreeView::select(const weld::TreeIter& rIter) + m_xSearchFindsList->select(*xEntry); + SearchFindsListSelectionChangedHandler(*m_xSearchFindsList); +} + void QuickFindPanel::FillSearchFindsList() { m_vPaMs.clear(); m_xSearchFindsList->clear(); m_xSearchFindFoundTimesLabel->set_label(OUString()); + m_xQuickFindControls->set_visible(false); const OUString sFindEntry = m_xSearchFindEntry->get_text(); if (sFindEntry.isEmpty()) @@ -685,6 +758,8 @@ void QuickFindPanel::FillSearchFindsList() OUString sText(SwResId(STR_SEARCH_KEY_FOUND_TIMES, nSearchFindFoundTimes)); sText = sText.replaceFirst("%1", OUString::number(nSearchFindFoundTimes)); m_xSearchFindFoundTimesLabel->set_label(sText); + if (nSearchFindFoundTimes > 1) + m_xQuickFindControls->set_visible(true); } OUString QuickFindPanel::CreatePageEntry(sal_Int32 nPageNum) diff --git a/sw/uiconfig/swriter/ui/sidebarquickfind.ui b/sw/uiconfig/swriter/ui/sidebarquickfind.ui index 189efbe8a3a5..f3abb091acd3 100644 --- a/sw/uiconfig/swriter/ui/sidebarquickfind.ui +++ b/sw/uiconfig/swriter/ui/sidebarquickfind.ui @@ -10,6 +10,18 @@ <column type="gchararray"/> </columns> </object> + <object class="GtkImage" id="prevImage"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="icon-name">pan-up-symbolic</property> + <property name="icon_size">2</property> + </object> + <object class="GtkImage" id="nextImage"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="icon-name">pan-down-symbolic</property> + <property name="icon_size">2</property> + </object> <!-- n-columns=1 n-rows=1 --> <object class="GtkGrid" id="QuickFindPanel"> <property name="visible">True</property> @@ -164,16 +176,71 @@ </packing> </child> <child> - <object class="GtkLabel" id="numberofsearchfinds"> + <object class="GtkBox" id="searchresultscontainer"> <property name="visible">True</property> <property name="can-focus">False</property> + <property name="spacing">6</property> + <child> + <object class="GtkLabel" id="numberofsearchfinds"> + <property name="visible">True</property> + <property name="can-focus">False</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkBox" id="quickfindcontrols"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="spacing">3</property> + <child> + <object class="GtkButton" id="findprevious"> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + <property name="tooltip-text">Previous Result</property> <!-- TODO: add translatable --> + <property name="image">prevImage</property> + <property name="always-show-image">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="findnext"> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + <property name="tooltip-text">Next Result</property> <!-- TODO: add translatable --> + <property name="image">nextImage</property> + <property name="always-show-image">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> - <property name="position">3</property> + <property name="position">2</property> </packing> </child> + </object> <packing> <property name="left-attach">0</property> commit 9fa0ebbe022ce4c2e86c04633c881c4ba85af5ba Author: NickWingate <[email protected]> AuthorDate: Wed Sep 10 12:50:03 2025 +0100 Commit: Andras Timar <[email protected]> CommitDate: Tue Jan 13 19:34:54 2026 +0100 QuickFindPanel: Improve how we handle page entries We have two different 'markers' for page entries: '-' for desktop and '-$#~ ... ~#$-'. Minimize the number of places these are hard coded. Signed-off-by: NickWingate <[email protected]> Change-Id: I9bbffb2dca72c25bef40495152b67c7d2455917b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/190753 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Szymon Kłos <[email protected]> diff --git a/sw/source/uibase/inc/QuickFindPanel.hxx b/sw/source/uibase/inc/QuickFindPanel.hxx index 63bbf09ca449..6dcc9cfe913d 100644 --- a/sw/source/uibase/inc/QuickFindPanel.hxx +++ b/sw/source/uibase/inc/QuickFindPanel.hxx @@ -96,6 +96,10 @@ private: DECL_LINK(FindAndReplaceToolbarClickedHandler, const OUString&, void); void FillSearchFindsList(); + static OUString CreatePageEntry(sal_Int32 nPageNum); + bool IsPageEntry(const weld::TreeIter& rEntry); + static bool IsPageEntry(std::u16string_view sEntryId); + static OUString ParsePageEntry(const OUString& sEntryId); bool UpgradeSearchToSearchDialog(); }; diff --git a/sw/source/uibase/sidebar/QuickFindPanel.cxx b/sw/source/uibase/sidebar/QuickFindPanel.cxx index a975c5e17cd0..254623ac86f5 100644 --- a/sw/source/uibase/sidebar/QuickFindPanel.cxx +++ b/sw/source/uibase/sidebar/QuickFindPanel.cxx @@ -38,6 +38,8 @@ #include <comphelper/processfactory.hxx> const int CharactersBeforeAndAfter = 40; +const OUString LOKPageEntryPrefix = u"-$#~"_ustr; +const OUString LOKPageEntrySuffix = u"~#$-"_ustr; namespace { @@ -299,7 +301,7 @@ IMPL_LINK(QuickFindPanel, SearchFindsListMousePressHandler, const MouseEvent&, r if (std::unique_ptr<weld::TreeIter> xEntry(m_xSearchFindsList->make_iterator()); m_xSearchFindsList->get_dest_row_at_pos(rMEvt.GetPosPixel(), xEntry.get(), false, false)) { - return m_xSearchFindsList->get_id(*xEntry)[0] == '-'; + return IsPageEntry(*xEntry); } return false; } @@ -310,7 +312,7 @@ IMPL_LINK(QuickFindPanel, SearchFindsListCustomGetSizeHandler, weld::TreeView::g vcl::RenderContext& rRenderContext = std::get<0>(aPayload); const OUString& rId = std::get<1>(aPayload); - const bool bPageEntry = rId[0] == '-'; + const bool bPageEntry = IsPageEntry(rId); OUString aEntry(rId); if (!bPageEntry) @@ -361,7 +363,7 @@ IMPL_LINK(QuickFindPanel, SearchFindsListRender, weld::TreeView::render_args, aP const ::tools::Rectangle& rRect = std::get<1>(aPayload); const OUString& rId = std::get<3>(aPayload); - const bool bPageEntry = rId[0] == '-'; + const bool bPageEntry = IsPageEntry(rId); OUString aEntry(rId); @@ -407,7 +409,7 @@ IMPL_LINK(QuickFindPanel, SearchFindsListRender, weld::TreeView::render_args, aP } else { - aEntry = aEntry.copy(1); // remove '-' + aEntry = ParsePageEntry(aEntry); // remove '-' or LOKPageEntryPrefix and LOKPageEntrySuffix tools::Long aTextWidth = rRenderContext.GetTextWidth(aEntry); tools::Long aTextHeight = rRenderContext.GetTextHeight(); @@ -435,7 +437,7 @@ IMPL_LINK_NOARG(QuickFindPanel, SearchFindsListSelectionChangedHandler, weld::Tr OUString sId = m_xSearchFindsList->get_id(*xEntry); // check for page number entry - if (sId[0] == '-') + if (IsPageEntry(sId)) return; std::unique_ptr<SwPaM>& rxPaM = m_vPaMs[sId.toUInt64()]; @@ -483,7 +485,7 @@ IMPL_LINK_NOARG(QuickFindPanel, SearchFindsListRowActivatedHandler, weld::TreeVi return false; // check for page number entry - if (m_xSearchFindsList->get_id(*xEntry)[0] == '-') + if (IsPageEntry(*xEntry)) return false; m_pWrtShell->GetView().GetEditWin().GrabFocus(); @@ -653,16 +655,7 @@ void QuickFindPanel::FillSearchFindsList() if (xPaM->GetPageNum() != nPage) { nPage = xPaM->GetPageNum(); - OUString sPageEntry; - if (comphelper::LibreOfficeKit::isActive()) - { - sPageEntry = u"-$#~"_ustr + SwResId(ST_PGE) + u" "_ustr - + OUString::number(nPage) + u"~#$-"_ustr; - } - else - { - sPageEntry = u"-"_ustr + SwResId(ST_PGE) + u" "_ustr + OUString::number(nPage); - } + OUString sPageEntry = CreatePageEntry(nPage); m_xSearchFindsList->append(sPageEntry, sPageEntry); } @@ -693,6 +686,41 @@ void QuickFindPanel::FillSearchFindsList() sText = sText.replaceFirst("%1", OUString::number(nSearchFindFoundTimes)); m_xSearchFindFoundTimesLabel->set_label(sText); } + +OUString QuickFindPanel::CreatePageEntry(sal_Int32 nPageNum) +{ + if (comphelper::LibreOfficeKit::isActive()) + { + return LOKPageEntryPrefix + SwResId(ST_PGE) + u" "_ustr + OUString::number(nPageNum) + + LOKPageEntrySuffix; + } + return u"-"_ustr + SwResId(ST_PGE) + u" "_ustr + OUString::number(nPageNum); +} + +bool QuickFindPanel::IsPageEntry(const weld::TreeIter& rEntry) +{ + return IsPageEntry(m_xSearchFindsList->get_id(rEntry)); +} + +bool QuickFindPanel::IsPageEntry(std::u16string_view sEntryId) +{ + if (comphelper::LibreOfficeKit::isActive()) + { + return sEntryId.starts_with(LOKPageEntryPrefix) && sEntryId.ends_with(LOKPageEntrySuffix); + } + return sEntryId[0] == '-'; +} + +OUString QuickFindPanel::ParsePageEntry(const OUString& sEntryId) +{ + if (comphelper::LibreOfficeKit::isActive()) + { + return sEntryId.copy(LOKPageEntryPrefix.getLength(), + sEntryId.getLength() + - LOKPageEntrySuffix.getLength()); // remove '-$#~' and '~#$-' + } + return sEntryId.copy(1); // remove '-' +} } // end of namespace ::sw::sidebar /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ commit 0de350e5e6c4a17d17c6612f96e0df4ab25ac4cb Author: Banobe Pascal <[email protected]> AuthorDate: Thu Oct 16 12:44:40 2025 +0300 Commit: Andras Timar <[email protected]> CommitDate: Tue Jan 13 19:27:44 2026 +0100 Calc: Only trigger note edit for desktop mode -When a user selects a comment from the Navigator, Calc was automatically opening the Note widget in edit mode, even inside COOL. This change adds a simple check to make sure that behavior only happens on the desktop version. Signed-off-by: Banobe Pascal <[email protected]> Change-Id: Iff1c6129c794a2b4f30aa1d841c63989fc014e34 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/192484 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Szymon Kłos <[email protected]> diff --git a/sc/source/ui/navipi/content.cxx b/sc/source/ui/navipi/content.cxx index 8d9433d84115..92c589f7412c 100644 --- a/sc/source/ui/navipi/content.cxx +++ b/sc/source/ui/navipi/content.cxx @@ -387,15 +387,18 @@ IMPL_LINK_NOARG(ScContentTree, ContentDoubleClickHdl, weld::TreeView&, bool) pParentWindow->SetCurrentTable( aPos.Tab() ); pParentWindow->SetCurrentCell( aPos.Col(), aPos.Row() ); // Check whether the comment is currently visible and toggle its visibility - ScDocument* pSrcDoc = GetSourceDocument(); - if (ScPostIt* pNote = pSrcDoc ? pSrcDoc->GetNote(aPos.Col(), aPos.Row(), aPos.Tab()) : nullptr) + if (!comphelper::LibreOfficeKit::isActive()) { - bool bVisible = pNote->IsCaptionShown(); - // Effectivelly set the visibility of the comment - GetManualOrCurrent()->GetDocFunc().ShowNote(aPos, !bVisible); - // Put the note in edit mode - ScTabViewShell* pScTabViewShell = ScNavigatorDlg::GetTabViewShell(); - pScTabViewShell->EditNote(); + ScDocument* pSrcDoc = GetSourceDocument(); + if (ScPostIt* pNote = pSrcDoc ? pSrcDoc->GetNote(aPos.Col(), aPos.Row(), aPos.Tab()) : nullptr) + { + bool bVisible = pNote->IsCaptionShown(); + // Effectivelly set the visibility of the comment + GetManualOrCurrent()->GetDocFunc().ShowNote(aPos, !bVisible); + // Put the note in edit mode + ScTabViewShell* pScTabViewShell = ScNavigatorDlg::GetTabViewShell(); + pScTabViewShell->EditNote(); + } } } break; commit 3b3f34f150b0038748e5258687de0395c4624ab4 Author: Gökay Şatır <[email protected]> AuthorDate: Mon Sep 1 17:04:12 2025 +0300 Commit: Andras Timar <[email protected]> CommitDate: Tue Jan 13 19:13:09 2026 +0100 Add windowId to "notifyCursorInvalidation". Online side has special handling for backspace and delete chars. Online side calls a function for these chars along with windowId. We need to know the windowIds of the form controls when calling removeTextContent function. Signed-off-by: Gökay Şatır <[email protected]> Change-Id: I3ed6cea3ffe81769c7f95da95636ad6d630059ec Reviewed-on: https://gerrit.libreoffice.org/c/core/+/190487 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Tomaž Vajngerl <[email protected]> diff --git a/forms/source/component/FormComponent.cxx b/forms/source/component/FormComponent.cxx index 8ccec384f410..7cef8b5c588f 100644 --- a/forms/source/component/FormComponent.cxx +++ b/forms/source/component/FormComponent.cxx @@ -56,6 +56,8 @@ #include <algorithm> #include <vcl/window.hxx> #include <toolkit/helper/vclunohelper.hxx> + +#include <comphelper/lok.hxx> namespace frm { using namespace ::com::sun::star::uno; @@ -275,6 +277,9 @@ void SAL_CALL OControl::createPeer(const Reference<XToolkit>& _rxToolkit, const VclPtr<vcl::Window> pVclPeer = VCLUnoHelper::GetWindow(getPeer()); pVclPeer->SetFormControl(true); + + if (comphelper::LibreOfficeKit::isActive()) + pVclPeer->SetLOKWindowId(); } } diff --git a/include/sfx2/lokhelper.hxx b/include/sfx2/lokhelper.hxx index 7ee2c87a9521..74e2992bef07 100644 --- a/include/sfx2/lokhelper.hxx +++ b/include/sfx2/lokhelper.hxx @@ -192,7 +192,7 @@ public: /// Emits a LOK_CALLBACK_DOCUMENT_SIZE_CHANGED for all views of the same document with the same part static void notifyPartSizeChangedAllViews(vcl::ITiledRenderable* pDoc, int nPart); /// Emits a LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR - static void notifyCursorInvalidation(SfxViewShell const* pThisView, tools::Rectangle const * pRect, bool bControlEvent); + static void notifyCursorInvalidation(SfxViewShell const* pThisView, tools::Rectangle const * pRect, bool bControlEvent, int windowID); /// Emits a LOK_CALLBACK_INVALIDATE_TILES, but tweaks it according to setOptionalFeatures() if needed. static void notifyInvalidation(SfxViewShell const* pThisView, int nPart, tools::Rectangle const *); /// Emits a LOK_CALLBACK_INVALIDATE_TILES, but tweaks it according to setOptionalFeatures() if needed diff --git a/include/sfx2/viewsh.hxx b/include/sfx2/viewsh.hxx index e3ff20a7bfce..046e3580899e 100644 --- a/include/sfx2/viewsh.hxx +++ b/include/sfx2/viewsh.hxx @@ -426,7 +426,7 @@ public: /// ILibreOfficeKitNotifier. Emits a LOK_CALLBACK_INVALIDATE_TILES. virtual void notifyInvalidation(tools::Rectangle const *) const override; /// ILibreOfficeKitNotifier. - virtual void notifyCursorInvalidation(tools::Rectangle const *, bool bControlEvent) const override; + virtual void notifyCursorInvalidation(tools::Rectangle const *, bool bControlEvent, int windowID) const override; /// See OutlinerViewShell::NotifyOtherViews(). void NotifyOtherViews(int nType, const OString& rKey, const OString& rPayload) override; diff --git a/include/vcl/IDialogRenderable.hxx b/include/vcl/IDialogRenderable.hxx index aaa17cd7991c..64f9ed984d73 100644 --- a/include/vcl/IDialogRenderable.hxx +++ b/include/vcl/IDialogRenderable.hxx @@ -41,7 +41,7 @@ public: virtual void notifyInvalidation(tools::Rectangle const *) const = 0; /// Emits a LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR. - virtual void notifyCursorInvalidation(tools::Rectangle const *, bool bControlEvent) const = 0; + virtual void notifyCursorInvalidation(tools::Rectangle const *, bool bControlEvent, int windowID) const = 0; /// Debugging virtual OString dumpNotifyState() const = 0; diff --git a/include/vcl/svapp.hxx b/include/vcl/svapp.hxx index 5b4e079c958e..6b909e7e7a17 100644 --- a/include/vcl/svapp.hxx +++ b/include/vcl/svapp.hxx @@ -1339,7 +1339,7 @@ public: const std::vector<vcl::LOKPayloadItem>& rPayload = std::vector<vcl::LOKPayloadItem>()) const override; virtual void libreOfficeKitViewCallback(int nType, const OString& pPayload) const override; virtual void notifyInvalidation(tools::Rectangle const* pRect) const override; - virtual void notifyCursorInvalidation(tools::Rectangle const* pRect, bool bControlEvent) const override; + virtual void notifyCursorInvalidation(tools::Rectangle const* pRect, bool bControlEvent, int windowID) const override; virtual OString dumpNotifyState() const override; private: diff --git a/include/vcl/window.hxx b/include/vcl/window.hxx index 8369693dd05f..bb793d71ea51 100644 --- a/include/vcl/window.hxx +++ b/include/vcl/window.hxx @@ -1099,6 +1099,9 @@ public: const vcl::ILibreOfficeKitNotifier* GetLOKNotifier() const; vcl::LOKWindowId GetLOKWindowId() const; + /// This sets the lokWindowId without setting a notifier. + void SetLOKWindowId(); + /// Find the nearest parent with LOK Notifier; can be itself if this Window has LOK notifier set. VclPtr<vcl::Window> GetParentWithLOKNotifier(); diff --git a/sfx2/source/view/lokhelper.cxx b/sfx2/source/view/lokhelper.cxx index 603331236c85..f8d663211984 100644 --- a/sfx2/source/view/lokhelper.cxx +++ b/sfx2/source/view/lokhelper.cxx @@ -726,12 +726,14 @@ void SfxLokHelper::notifyWindow(const SfxViewShell* pThisView, pThisView->libreOfficeKitViewCallback(LOK_CALLBACK_WINDOW, s); } -void SfxLokHelper::notifyCursorInvalidation(SfxViewShell const* pThisView, tools::Rectangle const* pRect, bool bControlEvent) +void SfxLokHelper::notifyCursorInvalidation(SfxViewShell const* pThisView, tools::Rectangle const* pRect, bool bControlEvent, int windowID) { int nViewId = SfxLokHelper::getView(*pThisView); OString sPayload = OString::Concat("{ \"viewId\": \"") + OString::number(nViewId) + "\", \"rectangle\": \"" + pRect->toString(); if (bControlEvent) - sPayload += "\", \"controlEvent\": true"; + { + sPayload += "\", \"controlEvent\": true, \"windowId\": \"" + OString::number(windowID) + "\""; + } sPayload += " }"; pThisView->libreOfficeKitViewCallback(LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR, sPayload); } diff --git a/sfx2/source/view/viewsh.cxx b/sfx2/source/view/viewsh.cxx index 0111e25335af..06eb1f0a2ebd 100644 --- a/sfx2/source/view/viewsh.cxx +++ b/sfx2/source/view/viewsh.cxx @@ -3588,9 +3588,9 @@ void SfxViewShell::notifyInvalidation(tools::Rectangle const* pRect) const SfxLokHelper::notifyInvalidation(this, pRect); } -void SfxViewShell::notifyCursorInvalidation(tools::Rectangle const* pRect, bool bControlEvent) const +void SfxViewShell::notifyCursorInvalidation(tools::Rectangle const* pRect, bool bControlEvent, int windowID) const { - SfxLokHelper::notifyCursorInvalidation(this, pRect, bControlEvent); + SfxLokHelper::notifyCursorInvalidation(this, pRect, bControlEvent, windowID); } void SfxViewShell::NotifyOtherViews(int nType, const OString& rKey, const OString& rPayload) diff --git a/vcl/source/app/svapp.cxx b/vcl/source/app/svapp.cxx index fded2b515571..5eed765ad9e7 100644 --- a/vcl/source/app/svapp.cxx +++ b/vcl/source/app/svapp.cxx @@ -341,7 +341,7 @@ void Application::notifyInvalidation(tools::Rectangle const* /*pRect*/) const { } -void Application::notifyCursorInvalidation(tools::Rectangle const* /*pRect*/, bool /*bControlEvent*/) const +void Application::notifyCursorInvalidation(tools::Rectangle const* /*pRect*/, bool /*bControlEvent*/, int /*windowID*/) const { } diff --git a/vcl/source/window/cursor.cxx b/vcl/source/window/cursor.cxx index 2437fc321348..535a0bde2a46 100644 --- a/vcl/source/window/cursor.cxx +++ b/vcl/source/window/cursor.cxx @@ -296,7 +296,11 @@ void vcl::Cursor::LOKNotify(vcl::Window* pWindow, const OUString& rAction) OutputDevice* pDevice = mpData->mpWindow->GetOutDev(); const tools::Rectangle aRectTwip = pDevice->PixelToLogic(aRect, MapMode(MapUnit::MapTwip)); - pNotifier->notifyCursorInvalidation(&aRectTwip, true); + + if (pWindow->IsFormControl()) + pNotifier->notifyCursorInvalidation(&aRectTwip, true, pWindow->GetLOKWindowId()); + else + pNotifier->notifyCursorInvalidation(&aRectTwip, true, pWindow->GetParent()->GetLOKWindowId()); } } else diff --git a/vcl/source/window/window.cxx b/vcl/source/window/window.cxx index ae5641b8f8be..fedfc1b8eff7 100644 --- a/vcl/source/window/window.cxx +++ b/vcl/source/window/window.cxx @@ -3173,6 +3173,9 @@ LOKWindowsMap& GetLOKWindowsMap() } +// Counter to be able to have unique id's for each window. +static vcl::LOKWindowId sLastLOKWindowId = 1; + void Window::SetLOKNotifier(const vcl::ILibreOfficeKitNotifier* pNotifier, bool bParent) { // don't allow setting this twice @@ -3183,9 +3186,6 @@ void Window::SetLOKNotifier(const vcl::ILibreOfficeKitNotifier* pNotifier, bool if (!bParent) { - // Counter to be able to have unique id's for each window. - static vcl::LOKWindowId sLastLOKWindowId = 1; - // assign the LOK window id assert(mpWindowImpl->mnLOKWindowId == 0); mpWindowImpl->mnLOKWindowId = sLastLOKWindowId++; @@ -3195,6 +3195,17 @@ void Window::SetLOKNotifier(const vcl::ILibreOfficeKitNotifier* pNotifier, bool mpWindowImpl->mpLOKNotifier = pNotifier; } +void Window::SetLOKWindowId() +{ + // never use this in the desktop case + assert(comphelper::LibreOfficeKit::isActive()); + + // assign the LOK window id + assert(mpWindowImpl->mnLOKWindowId == 0); + mpWindowImpl->mnLOKWindowId = sLastLOKWindowId++; + GetLOKWindowsMap().emplace(mpWindowImpl->mnLOKWindowId, this); +} + VclPtr<Window> Window::FindLOKWindow(vcl::LOKWindowId nWindowId) { const auto it = GetLOKWindowsMap().find(nWindowId); @@ -3367,6 +3378,7 @@ void Window::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter) rJsonWriter.put("text", GetText()); rJsonWriter.put("enabled", IsEnabled()); rJsonWriter.put("canFocus", bool(GetStyle() & WB_TABSTOP)); + rJsonWriter.put("lokWindowId", GetLOKWindowId()); if (!IsVisible()) rJsonWriter.put("visible", false);
