include/sfx2/bindings.hxx | 1 sc/qa/unit/tiledrendering/tiledrendering.cxx | 56 +++++++++++++++++++++++++++ sfx2/source/control/bindings.cxx | 28 +++++++++++++ sfx2/source/control/unoctitm.cxx | 21 +++++++++- 4 files changed, 105 insertions(+), 1 deletion(-)
New commits: commit 51d8a2ef54751403fa707816e27ddb4e7faa8231 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Fri Jan 5 16:51:42 2024 +0100 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Mon Jan 8 08:27:18 2024 +0100 cool#7492 sfx2 lok: fix bad view id / statusbar string on async binding update With two Calc views (first is an English one, second is a German one), type in the English view and in parallel to that, create a cell selection in the German view. Sometimes the status bar update about the selected cells arrives in English, in the German view. The root of the problem is that SfxBindings has a timer that does the expensive update of all the UNO commands only after a delay, but by the time this timer runs, possibly the current view is no longer the German one, which leads to English strings in the German view. Fix the problem somewhat similar to what commit ee7ca8e4ea8ed93655f99e77a9e77032ac830c46 (cool#7865 sfx2 lok: fix bad view id on async command dispatch, 2023-12-20) did in SfxHintPoster::DoEvent_Impl() by restoring the original view for the duration of the timer job execution. The test works even in case '--with-lang=en-US de' is not used, because it asserts the locale, which is not downgraded to English when translations are not available. This required turning the payload of the .uno:RowColSelCount status update into JSON, which is meant to be mostly backwards-compatible, given that we already have a mix of plain text and JSON for the various UNO commands. Another trouble is that the SfxBindings lazy update is a timer, so processing idles won't help and sleeping in test code is not ideal, either. Solve that by exposing the timer of SfxBindings, so test code can explicitly invoke the timer without waiting. Change-Id: Iacf17f81c28b95ce41a0ee29ad25eb576db0d62a Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161691 Tested-by: Jenkins Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/include/sfx2/bindings.hxx b/include/sfx2/bindings.hxx index 8cd92a24108d..2b85b4dbd065 100644 --- a/include/sfx2/bindings.hxx +++ b/include/sfx2/bindings.hxx @@ -188,6 +188,7 @@ public: SAL_DLLPRIVATE void SetRecorder_Impl( css::uno::Reference< css::frame::XDispatchRecorder > const & ); SAL_DLLPRIVATE void InvalidateSlotsInMap_Impl(); SAL_DLLPRIVATE void AddSlotToInvalidateSlotsMap_Impl( sal_uInt16 nId ); + Timer& GetTimer(); }; #ifdef DBG_UTIL diff --git a/sc/qa/unit/tiledrendering/tiledrendering.cxx b/sc/qa/unit/tiledrendering/tiledrendering.cxx index 5548dc06fbdf..25d1258c21d3 100644 --- a/sc/qa/unit/tiledrendering/tiledrendering.cxx +++ b/sc/qa/unit/tiledrendering/tiledrendering.cxx @@ -16,6 +16,7 @@ #include <com/sun/star/frame/DispatchHelper.hpp> #include <com/sun/star/datatransfer/clipboard/LokClipboard.hpp> #include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp> +#include <com/sun/star/util/URLTransformer.hpp> #include <comphelper/processfactory.hxx> #include <comphelper/propertysequence.hxx> #include <comphelper/servicehelper.hxx> @@ -26,6 +27,8 @@ #include <comphelper/lok.hxx> #include <comphelper/propertyvalue.hxx> +#include <comphelper/dispatchcommand.hxx> +#include <sfx2/msgpool.hxx> #include <sfx2/childwin.hxx> #include <sfx2/lokhelper.hxx> #include <svx/svdpage.hxx> @@ -437,6 +440,7 @@ public: OString m_sInvalidateSheetGeometry; OString m_aHyperlinkClicked; OString m_ShapeSelection; + std::map<std::string, boost::property_tree::ptree> m_aStateChanges; TestLokCallbackWrapper m_callbackWrapper; ViewCallback(bool bDeleteListenerOnDestruct=true) @@ -581,6 +585,16 @@ public: { m_aTextSelectionResult.parseMessage(pPayload); } + break; + case LOK_CALLBACK_STATE_CHANGED: + { + std::stringstream aStream(pPayload); + boost::property_tree::ptree aTree; + boost::property_tree::read_json(aStream, aTree); + std::string aCommandName = aTree.get<std::string>("commandName"); + m_aStateChanges[aCommandName] = aTree; + } + break; } } }; @@ -3184,6 +3198,48 @@ CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest, testInvalidateForSplitPanes) CPPUNIT_ASSERT_MESSAGE("The cell visible in the bottom left pane should be redrawn", bFoundBottomLeftPane); } +CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest, testStatusBarLocale) +{ + // Given 2 views, the second's locale is set to German: + createDoc("empty.ods"); + int nView1 = SfxLokHelper::getView(); + ViewCallback aView1; + SfxLokHelper::createView(); + ViewCallback aView2; + SfxViewShell* pView2 = SfxViewShell::Current(); + pView2->SetLOKLocale("de-DE"); + { + SfxViewFrame& rFrame = pView2->GetViewFrame(); + SfxSlotPool& rSlotPool = SfxSlotPool::GetSlotPool(&rFrame); + uno::Reference<util::XURLTransformer> xParser(util::URLTransformer::create(m_xContext)); + util::URL aCommandURL; + aCommandURL.Complete = ".uno:RowColSelCount"; + xParser->parseStrict(aCommandURL); + const SfxSlot* pSlot = rSlotPool.GetUnoSlot(aCommandURL.Path); + rFrame.GetBindings().GetDispatch(pSlot, aCommandURL, false); + } + aView2.m_aStateChanges.clear(); + + // When creating a cell selection in the 2nd view and processing jobs with the 1st view set to + // active: + comphelper::dispatchCommand(".uno:GoDownSel", {}); + SfxLokHelper::setView(nView1); + pView2->GetViewFrame().GetBindings().GetTimer().Invoke(); + // Once more to hit the pImpl->bMsgDirty = false case in SfxBindings::NextJob_Impl(). + pView2->GetViewFrame().GetBindings().GetTimer().Invoke(); + + // Then make sure that the locale is taken into account while producing the state changed + // callback: + auto it = aView2.m_aStateChanges.find(".uno:RowColSelCount"); + CPPUNIT_ASSERT(it != aView2.m_aStateChanges.end()); + std::string aLocale = it->second.get<std::string>("locale"); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: de-DE + // - Actual : en-US + // i.e. the 2nd view got its callback with the locale of the first view, which is buggy. + CPPUNIT_ASSERT_EQUAL(std::string("de-DE"), aLocale); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sfx2/source/control/bindings.cxx b/sfx2/source/control/bindings.cxx index 40e44ff8b5a3..95823f8bde4d 100644 --- a/sfx2/source/control/bindings.cxx +++ b/sfx2/source/control/bindings.cxx @@ -50,6 +50,8 @@ #include <sfx2/viewfrm.hxx> #include <sfx2/objsh.hxx> #include <sfx2/msgpool.hxx> +#include <sfx2/lokhelper.hxx> +#include <comphelper/lok.hxx> #include <cstddef> #include <memory> @@ -1212,7 +1214,28 @@ void SfxBindings::UpdateControllers_Impl IMPL_LINK( SfxBindings, NextJob, Timer *, pTimer, void ) { + bool bSetView = false; + int nOldId = -1; + if (comphelper::LibreOfficeKit::isActive() && pDispatcher) + { + SfxViewFrame* pFrame = pDispatcher->GetFrame(); + SfxViewShell* pShell = pFrame ? pFrame->GetViewShell() : nullptr; + int nNewId = SfxLokHelper::getView(pShell); + nOldId = SfxLokHelper::getView(); + if (nNewId != -1 && nNewId != nOldId) + { + // The current view ID is not the one that belongs to this frame, switch to it. + SfxLokHelper::setView(nNewId); + bSetView = true; + } + } + NextJob_Impl(pTimer); + + if (bSetView) + { + SfxLokHelper::setView(nOldId); + } } bool SfxBindings::NextJob_Impl(Timer const * pTimer) @@ -1771,4 +1794,9 @@ uno::Reference < frame::XDispatch > SfxBindings::GetDispatch( const SfxSlot* pSl return xRet; } +Timer& SfxBindings::GetTimer() +{ + return pImpl->aAutoTimer; +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sfx2/source/control/unoctitm.cxx b/sfx2/source/control/unoctitm.cxx index d9eb3ea78745..cd50e70231e7 100644 --- a/sfx2/source/control/unoctitm.cxx +++ b/sfx2/source/control/unoctitm.cxx @@ -1151,7 +1151,6 @@ static void InterceptLOKStateChangeEvent(sal_uInt16 nSID, SfxViewFrame* pViewFra } } else if (aEvent.FeatureURL.Path == "StatusDocPos" || - aEvent.FeatureURL.Path == "RowColSelCount" || aEvent.FeatureURL.Path == "StatusPageStyle" || aEvent.FeatureURL.Path == "StateWordCount" || aEvent.FeatureURL.Path == "PageStyleName" || @@ -1167,6 +1166,26 @@ static void InterceptLOKStateChangeEvent(sal_uInt16 nSID, SfxViewFrame* pViewFra aBuffer.append(aString); } } + else if (aEvent.FeatureURL.Path == "RowColSelCount") + { + OUString aString; + if (aEvent.IsEnabled) + { + aEvent.State >>= aString; + } + boost::property_tree::ptree aTree; + aTree.put("commandName", aEvent.FeatureURL.Complete); + aTree.put("locale", comphelper::LibreOfficeKit::getLocale().getBcp47()); + aTree.put("state", aString); + std::stringstream aStream; + boost::property_tree::write_json(aStream, aTree); + const SfxViewShell* pShell = pViewFrame->GetViewShell(); + if (pShell) + { + pShell->libreOfficeKitViewCallback(LOK_CALLBACK_STATE_CHANGED, OString(aStream.str())); + } + return; + } else if (aEvent.FeatureURL.Path == "StateTableCell") { if (aEvent.IsEnabled)