desktop/source/lib/init.cxx | 27 +++++++++++++++++++++++++++ include/vcl/svapp.hxx | 6 ++++++ vcl/inc/salinst.hxx | 4 ++++ vcl/source/window/builder.cxx | 37 +++++++++++++++++++++++++++++++++++-- 4 files changed, 72 insertions(+), 2 deletions(-)
New commits: commit 836ff0a0ffb70c7cafd61b3da0bfa2170d1d442f Author: Caolán McNamara <[email protected]> AuthorDate: Fri Dec 5 20:22:22 2025 +0000 Commit: Miklos Vajna <[email protected]> CommitDate: Mon Dec 8 10:43:58 2025 +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]> diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx index ab956e1ffc89..fdf7477db984 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 8f8a86f7e67b..829edf7f5251 100644 --- a/include/vcl/svapp.hxx +++ b/include/vcl/svapp.hxx @@ -1234,6 +1234,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 f3af5cf3794d..20d5d2ba3f46 100644 --- a/vcl/inc/salinst.hxx +++ b/vcl/inc/salinst.hxx @@ -21,6 +21,7 @@ #define INCLUDED_VCL_INC_SALINST_HXX #include <sal/types.h> +#include <o3tl/sorted_vector.hxx> #include <rtl/ref.hxx> #include <vcl/dllapi.h> #include <vcl/salgtype.hxx> @@ -78,6 +79,7 @@ private: rtl::Reference< vcl::DisplayConnectionDispatch > m_pEventInst; const std::unique_ptr<comphelper::SolarMutex> m_pYieldMutex; css::uno::Reference<css::uno::XInterface> m_clipboard; + o3tl::sorted_vector<OUString> m_usedUI; protected: bool m_bSupportsBitmap32 = false; @@ -94,6 +96,8 @@ public: bool supportsBitmap32() const { return m_bSupportsBitmap32; } 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 6a04071705ed..080e0b4c4d86 100644 --- a/vcl/source/window/builder.cxx +++ b/vcl/source/window/builder.cxx @@ -183,8 +183,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)) @@ -206,11 +234,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 @@ -226,7 +259,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,
