summaryrefslogtreecommitdiffstats
path: root/vcl/source/app
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
commit267c6f2ac71f92999e969232431ba04678e7437e (patch)
tree358c9467650e1d0a1d7227a21dac2e3d08b622b2 /vcl/source/app
parentInitial commit. (diff)
downloadlibreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz
libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vcl/source/app')
-rw-r--r--vcl/source/app/ITiledRenderable.cxx77
-rw-r--r--vcl/source/app/IconThemeInfo.cxx180
-rw-r--r--vcl/source/app/IconThemeScanner.cxx216
-rw-r--r--vcl/source/app/IconThemeSelector.cxx203
-rw-r--r--vcl/source/app/brand.cxx78
-rw-r--r--vcl/source/app/customweld.cxx112
-rw-r--r--vcl/source/app/dbggui.cxx50
-rw-r--r--vcl/source/app/dndhelp.cxx167
-rw-r--r--vcl/source/app/help.cxx686
-rw-r--r--vcl/source/app/htmltransferable.cxx78
-rw-r--r--vcl/source/app/i18nhelp.cxx156
-rw-r--r--vcl/source/app/idle.cxx66
-rw-r--r--vcl/source/app/salplug.cxx478
-rw-r--r--vcl/source/app/salusereventlist.cxx164
-rw-r--r--vcl/source/app/salvtables.cxx7618
-rw-r--r--vcl/source/app/scheduler.cxx667
-rw-r--r--vcl/source/app/session.cxx416
-rw-r--r--vcl/source/app/settings.cxx3378
-rw-r--r--vcl/source/app/sound.cxx38
-rw-r--r--vcl/source/app/stdtext.cxx124
-rw-r--r--vcl/source/app/svapp.cxx1786
-rw-r--r--vcl/source/app/svdata.cxx534
-rw-r--r--vcl/source/app/svmain.cxx714
-rw-r--r--vcl/source/app/timer.cxx103
-rw-r--r--vcl/source/app/unohelp.cxx213
-rw-r--r--vcl/source/app/unohelp2.cxx113
-rw-r--r--vcl/source/app/vclevent.cxx94
-rw-r--r--vcl/source/app/watchdog.cxx168
-rw-r--r--vcl/source/app/weldutils.cxx662
-rw-r--r--vcl/source/app/winscheduler.cxx46
30 files changed, 19385 insertions, 0 deletions
diff --git a/vcl/source/app/ITiledRenderable.cxx b/vcl/source/app/ITiledRenderable.cxx
new file mode 100644
index 0000000000..52a4ab0f50
--- /dev/null
+++ b/vcl/source/app/ITiledRenderable.cxx
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <vcl/ITiledRenderable.hxx>
+
+namespace vcl
+{
+/*
+ * Map directly to css cursor styles to avoid further mapping in the client.
+ * Gtk (via gdk_cursor_new_from_name) also supports the same css cursor styles.
+ *
+ * This was created partially with help of the mappings in gtkdata.cxx.
+ * The list is incomplete as some cursor style simply aren't supported
+ * by css, it might turn out to be worth mapping some of these missing cursors
+ * to available cursors?
+ */
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4592)
+#endif
+const std::map<PointerStyle, OString> gaLOKPointerMap{
+ { PointerStyle::Arrow, "default" },
+ // PointerStyle::Null ?
+ { PointerStyle::Wait, "wait" },
+ { PointerStyle::Text, "text" },
+ { PointerStyle::Help, "help" },
+ { PointerStyle::Cross, "crosshair" },
+ { PointerStyle::Fill, "fill" },
+ { PointerStyle::Move, "move" },
+ { PointerStyle::NSize, "n-resize" },
+ { PointerStyle::SSize, "s-resize" },
+ { PointerStyle::WSize, "w-resize" },
+ { PointerStyle::ESize, "e-resize" },
+ { PointerStyle::NWSize, "ne-resize" },
+ { PointerStyle::NESize, "ne-resize" },
+ { PointerStyle::SWSize, "sw-resize" },
+ { PointerStyle::SESize, "se-resize" },
+ // WindowNSize through WindowSESize
+ { PointerStyle::HSplit, "col-resize" },
+ { PointerStyle::VSplit, "row-resize" },
+ { PointerStyle::HSizeBar, "col-resize" },
+ { PointerStyle::VSizeBar, "row-resize" },
+ { PointerStyle::Hand, "grab" },
+ { PointerStyle::RefHand, "pointer" },
+ // Pen, Magnify, Fill, Rotate
+ // HShear, VShear
+ // Mirror, Crook, Crop, MovePoint, MoveBezierWeight
+ // MoveData
+ { PointerStyle::CopyData, "copy" },
+ { PointerStyle::LinkData, "alias" },
+ // MoveDataLink, CopyDataLink
+ //MoveFile, CopyFile, LinkFile
+ // MoveFileLink, CopyFileLink, MoveFiless, CopyFiles
+ { PointerStyle::NotAllowed, "not-allowed" },
+ // DrawLine through DrawCaption
+ // Chart, Detective, PivotCol, PivotRow, PivotField, Chain, ChainNotAllowed
+ // TimeEventMove, TimeEventSize
+ // AutoScrollN through AutoScrollNSWE
+ // Airbrush
+ { PointerStyle::TextVertical, "vertical-text" }
+ // Pivot Delete, TabSelectS through TabSelectSW
+ // PaintBrush, HideWhiteSpace, ShowWhiteSpace
+};
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+ITiledRenderable::~ITiledRenderable() {}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/app/IconThemeInfo.cxx b/vcl/source/app/IconThemeInfo.cxx
new file mode 100644
index 0000000000..4166ae0845
--- /dev/null
+++ b/vcl/source/app/IconThemeInfo.cxx
@@ -0,0 +1,180 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <vcl/IconThemeInfo.hxx>
+#include <rtl/character.hxx>
+
+#include <stdexcept>
+#include <algorithm>
+
+// constants for theme ids and display names. (The theme id for high contrast is used
+// outside of this class and hence made public in IconThemeInfo.)
+
+namespace {
+
+constexpr OUStringLiteral HELPIMG_FAKE_THEME(u"helpimg");
+
+OUString
+filename_from_url(std::u16string_view url)
+{
+ size_t slashPosition = url.rfind( '/' );
+ if (slashPosition == std::u16string_view::npos) {
+ return OUString();
+ }
+ OUString filename( url.substr( slashPosition+1 ) );
+ return filename;
+}
+
+} // end anonymous namespace
+
+namespace vcl {
+
+const sal_Unicode ICON_THEME_PACKAGE_PREFIX[] = u"images_";
+
+const sal_Unicode EXTENSION_FOR_ICON_PACKAGES[] = u".zip";
+
+IconThemeInfo::IconThemeInfo()
+{
+}
+
+IconThemeInfo::IconThemeInfo(const OUString& urlToFile)
+: mUrlToFile(urlToFile)
+{
+ OUString filename = filename_from_url(urlToFile);
+ if (filename.isEmpty()) {
+ throw std::runtime_error("invalid URL passed to IconThemeInfo()");
+ }
+
+ mThemeId = FileNameToThemeId(filename);
+ mDisplayName = ThemeIdToDisplayName(mThemeId);
+
+}
+
+/*static*/ Size
+IconThemeInfo::SizeByThemeName(std::u16string_view themeName)
+{
+ if (themeName == u"galaxy") { //kept for compiler because of unused parameter 'themeName'
+ return Size( 26, 26 );
+ }
+ else {
+ return Size( 24, 24 );
+ }
+}
+
+/*static*/ bool
+IconThemeInfo::UrlCanBeParsed(std::u16string_view url)
+{
+ OUString fname = filename_from_url(url);
+ if (fname.isEmpty()) {
+ return false;
+ }
+
+ if (!fname.startsWithIgnoreAsciiCase(ICON_THEME_PACKAGE_PREFIX)) {
+ return false;
+ }
+
+ if (!fname.endsWithIgnoreAsciiCase(EXTENSION_FOR_ICON_PACKAGES)) {
+ return false;
+ }
+
+ if (fname.indexOf(HELPIMG_FAKE_THEME) != -1 ) {
+ return false;
+ }
+
+ return true;
+}
+
+/*static*/ OUString
+IconThemeInfo::FileNameToThemeId(std::u16string_view filename)
+{
+ OUString r;
+ size_t positionOfLastDot = filename.rfind(EXTENSION_FOR_ICON_PACKAGES);
+ if (positionOfLastDot == std::u16string_view::npos) { // means index not found
+ throw std::runtime_error("IconThemeInfo::FileNameToThemeId() called with invalid filename.");
+ }
+ size_t positionOfFirstUnderscore = filename.find(ICON_THEME_PACKAGE_PREFIX);
+ if (positionOfFirstUnderscore == std::u16string_view::npos) { // means index not found. Use the whole name instead
+ throw std::runtime_error("IconThemeInfo::FileNameToThemeId() called with invalid filename.");
+ }
+ positionOfFirstUnderscore += RTL_CONSTASCII_LENGTH(ICON_THEME_PACKAGE_PREFIX);
+ r = filename.substr(positionOfFirstUnderscore, positionOfLastDot - positionOfFirstUnderscore);
+ return r;
+}
+
+/*static*/ OUString
+IconThemeInfo::ThemeIdToDisplayName(const OUString& themeId)
+{
+ if (themeId.isEmpty()) {
+ throw std::runtime_error("IconThemeInfo::ThemeIdToDisplayName() called with invalid id.");
+ }
+
+ // Strip _svg and _dark filename "extensions"
+ OUString aDisplayName = themeId;
+
+ bool bIsSvg = aDisplayName.endsWith("_svg", &aDisplayName);
+ bool bIsDark = aDisplayName.endsWith("_dark", &aDisplayName);
+ if (!bIsSvg && bIsDark)
+ bIsSvg = aDisplayName.endsWith("_svg", &aDisplayName);
+
+ // make the first letter uppercase
+ sal_Unicode firstLetter = aDisplayName[0];
+ if (rtl::isAsciiLowerCase(firstLetter))
+ {
+ aDisplayName = OUStringChar(sal_Unicode(rtl::toAsciiUpperCase(firstLetter))) + aDisplayName.subView(1);
+ }
+
+ // replacing underscores with spaces of multi words pack name.
+ aDisplayName = aDisplayName.replace('_', ' ');
+
+ if (bIsSvg && bIsDark)
+ aDisplayName += " (SVG + dark)";
+ else if (bIsSvg)
+ aDisplayName += " (SVG)";
+ else if (bIsDark)
+ aDisplayName += " (dark)";
+
+ return aDisplayName;
+}
+
+namespace
+{
+ class SameTheme
+ {
+ private:
+ const OUString& m_rThemeId;
+ public:
+ explicit SameTheme(const OUString &rThemeId) : m_rThemeId(rThemeId) {}
+ bool operator()(const vcl::IconThemeInfo &rInfo)
+ {
+ return m_rThemeId == rInfo.GetThemeId();
+ }
+ };
+}
+
+/*static*/ const vcl::IconThemeInfo&
+IconThemeInfo::FindIconThemeById(const std::vector<vcl::IconThemeInfo>& themes, const OUString& themeId)
+{
+ std::vector<vcl::IconThemeInfo>::const_iterator it = std::find_if(themes.begin(), themes.end(),
+ SameTheme(themeId));
+ if (it == themes.end())
+ {
+ throw std::runtime_error("Could not find theme id in theme vector.");
+ }
+ return *it;
+}
+
+/*static*/ bool
+IconThemeInfo::IconThemeIsInVector(const std::vector<vcl::IconThemeInfo>& themes, const OUString& themeId)
+{
+ return std::any_of(themes.begin(), themes.end(), SameTheme(themeId));
+}
+
+} // end namespace vcl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/app/IconThemeScanner.cxx b/vcl/source/app/IconThemeScanner.cxx
new file mode 100644
index 0000000000..c8f6a1ac7e
--- /dev/null
+++ b/vcl/source/app/IconThemeScanner.cxx
@@ -0,0 +1,216 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <sal/config.h>
+#include <sal/log.hxx>
+
+#include <deque>
+
+#include <IconThemeScanner.hxx>
+
+#include <osl/file.hxx>
+#include <salhelper/linkhelper.hxx>
+#include <unotools/pathoptions.hxx>
+#include <vcl/IconThemeInfo.hxx>
+#include <o3tl/string_view.hxx>
+
+namespace vcl {
+
+namespace {
+
+// set the status of a file. Returns false if the status could not be determined.
+bool set_file_status(osl::FileStatus& status, const OUString& file)
+{
+ osl::DirectoryItem dirItem;
+ osl::FileBase::RC retvalGet = osl::DirectoryItem::get(file, dirItem);
+ if (retvalGet != osl::FileBase::E_None) {
+ SAL_WARN("vcl.app", "Could not determine status for file '" << file << "'.");
+ return false;
+ }
+ osl::FileBase::RC retvalStatus = dirItem.getFileStatus(status);
+ if (retvalStatus != osl::FileBase::E_None) {
+ SAL_WARN("vcl.app", "Could not determine status for file '" << file << "'.");
+ return false;
+ }
+ return true;
+}
+
+OUString convert_to_absolute_path(const OUString& path)
+{
+ salhelper::LinkResolver resolver(0);
+ osl::FileBase::RC rc = resolver.fetchFileStatus(path);
+ if (rc != osl::FileBase::E_None) {
+ SAL_WARN("vcl.app", "Could not resolve path '" << path << "' to search for icon themes.");
+ if (rc == osl::FileBase::E_MULTIHOP)
+ {
+ throw std::runtime_error("Provided a recursive symlink to an icon theme directory that could not be resolved.");
+ }
+ }
+ return resolver.m_aStatus.getFileURL();
+}
+
+}
+
+IconThemeScanner::IconThemeScanner()
+{}
+
+void IconThemeScanner::ScanDirectoryForIconThemes(std::u16string_view paths)
+{
+ mFoundIconThemes.clear();
+
+ std::deque<OUString> aPaths;
+
+ sal_Int32 nIndex = 0;
+ do
+ {
+ aPaths.push_front(OUString(o3tl::getToken(paths, 0, ';', nIndex)));
+ }
+ while (nIndex >= 0);
+
+ for (const auto& path : aPaths)
+ {
+ osl::FileStatus fileStatus(osl_FileStatus_Mask_Type);
+ bool couldSetFileStatus = set_file_status(fileStatus, path);
+ if (!couldSetFileStatus) {
+ continue;
+ }
+
+ if (!fileStatus.isDirectory()) {
+ SAL_INFO("vcl.app", "Cannot search for icon themes in '"<< path << "'. It is not a directory.");
+ continue;
+ }
+
+ std::vector<OUString> iconThemePaths = ReadIconThemesFromPath(path);
+ if (iconThemePaths.empty()) {
+ SAL_WARN("vcl.app", "Could not find any icon themes in the provided directory ('" <<path<<"'.");
+ continue;
+ }
+ for (auto const& iconThemePath : iconThemePaths)
+ {
+ AddIconThemeByPath(iconThemePath);
+ }
+ }
+}
+
+bool
+IconThemeScanner::AddIconThemeByPath(const OUString &url)
+{
+ if (!IconThemeInfo::UrlCanBeParsed(url)) {
+ return false;
+ }
+ SAL_INFO("vcl.app", "Found a file that seems to be an icon theme: '" << url << "'" );
+ IconThemeInfo newTheme(url);
+ mFoundIconThemes.push_back(newTheme);
+ SAL_INFO("vcl.app", "Adding the file as '" << newTheme.GetDisplayName() <<
+ "' with id '" << newTheme.GetThemeId() << "'.");
+ return true;
+}
+
+/*static*/ std::vector<OUString>
+IconThemeScanner::ReadIconThemesFromPath(const OUString& dir)
+{
+ std::vector<OUString> found;
+ SAL_INFO("vcl.app", "Scanning directory '" << dir << " for icon themes.");
+
+ osl::Directory dirToScan(dir);
+ osl::FileBase::RC retvalOpen = dirToScan.open();
+ if (retvalOpen != osl::FileBase::E_None) {
+ return found;
+ }
+
+ osl::DirectoryItem directoryItem;
+ while (dirToScan.getNextItem(directoryItem) == osl::FileBase::E_None) {
+ osl::FileStatus status(osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileURL | osl_FileStatus_Mask_FileName);
+ osl::FileBase::RC retvalStatus = directoryItem.getFileStatus(status);
+ if (retvalStatus != osl::FileBase::E_None) {
+ continue;
+ }
+
+ OUString filename = convert_to_absolute_path(status.getFileURL());
+ if (!FileIsValidIconTheme(filename)) {
+ continue;
+ }
+ found.push_back(filename);
+ }
+ return found;
+}
+
+/*static*/ bool
+IconThemeScanner::FileIsValidIconTheme(const OUString& filename)
+{
+ // check whether we can construct an IconThemeInfo from it
+ if (!IconThemeInfo::UrlCanBeParsed(filename)) {
+ SAL_INFO("vcl.app", "File '" << filename << "' does not seem to be an icon theme.");
+ return false;
+ }
+
+ osl::FileStatus fileStatus(osl_FileStatus_Mask_Type);
+ bool couldSetFileStatus = set_file_status(fileStatus, filename);
+ if (!couldSetFileStatus) {
+ return false;
+ }
+
+ if (!fileStatus.isRegular()) {
+ return false;
+ }
+ return true;
+}
+
+bool
+IconThemeScanner::IconThemeIsInstalled(const OUString& themeId) const
+{
+ return IconThemeInfo::IconThemeIsInVector(mFoundIconThemes, themeId);
+}
+
+/*static*/ std::shared_ptr<IconThemeScanner>
+IconThemeScanner::Create(std::u16string_view path)
+{
+ std::shared_ptr<IconThemeScanner> retval(new IconThemeScanner);
+ retval->ScanDirectoryForIconThemes(path);
+ return retval;
+}
+
+/*static*/ OUString
+IconThemeScanner::GetStandardIconThemePath()
+{
+ SvtPathOptions aPathOptions;
+ return aPathOptions.GetIconsetPath();
+}
+
+namespace
+{
+ class SameTheme
+ {
+ private:
+ const OUString& m_rThemeId;
+ public:
+ explicit SameTheme(const OUString &rThemeId) : m_rThemeId(rThemeId) {}
+ bool operator()(const vcl::IconThemeInfo &rInfo)
+ {
+ return m_rThemeId == rInfo.GetThemeId();
+ }
+ };
+}
+
+const vcl::IconThemeInfo&
+IconThemeScanner::GetIconThemeInfo(const OUString& themeId)
+{
+ std::vector<IconThemeInfo>::iterator info = std::find_if(mFoundIconThemes.begin(), mFoundIconThemes.end(),
+ SameTheme(themeId));
+ if (info == mFoundIconThemes.end()) {
+ SAL_WARN("vcl.app", "Requested information for icon theme with id '" << themeId
+ << "' which does not exist.");
+ throw std::runtime_error("Requested information on not-installed icon theme");
+ }
+ return *info;
+}
+
+} // end namespace vcl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/app/IconThemeSelector.cxx b/vcl/source/app/IconThemeSelector.cxx
new file mode 100644
index 0000000000..eb79752beb
--- /dev/null
+++ b/vcl/source/app/IconThemeSelector.cxx
@@ -0,0 +1,203 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <comphelper/lok.hxx>
+
+#include <IconThemeSelector.hxx>
+
+#include <tools/color.hxx>
+#include <vcl/IconThemeInfo.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <config_mpl.h>
+
+#include <algorithm>
+
+namespace vcl {
+
+namespace {
+
+ class SameTheme
+ {
+ private:
+ const OUString& m_rThemeId;
+ public:
+ explicit SameTheme(const OUString &rThemeId) : m_rThemeId(rThemeId) {}
+ bool operator()(const vcl::IconThemeInfo &rInfo)
+ {
+ return m_rThemeId == rInfo.GetThemeId();
+ }
+ };
+
+bool icon_theme_is_in_installed_themes(const OUString& theme,
+ const std::vector<IconThemeInfo>& installedThemes)
+{
+ return std::any_of(installedThemes.begin(), installedThemes.end(),
+ SameTheme(theme));
+}
+
+} // end anonymous namespace
+
+IconThemeSelector::IconThemeSelector()
+ : mUseHighContrastTheme(false)
+ , mPreferDarkIconTheme(false)
+{
+}
+
+/*static*/ OUString
+IconThemeSelector::GetIconThemeForDesktopEnvironment(const OUString& desktopEnvironment, bool bPreferDarkIconTheme)
+{
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ if (!bPreferDarkIconTheme)
+ return "colibre";
+ else
+ return "colibre_dark";
+ }
+
+#ifdef _WIN32
+ (void)desktopEnvironment;
+ if (!bPreferDarkIconTheme)
+ return "colibre";
+ else
+ return "colibre_dark";
+#else
+ OUString r;
+ if ( desktopEnvironment.equalsIgnoreAsciiCase("plasma5") ||
+ desktopEnvironment.equalsIgnoreAsciiCase("plasma6") ||
+ desktopEnvironment.equalsIgnoreAsciiCase("lxqt") ) {
+ if (!bPreferDarkIconTheme)
+ r = "breeze";
+ else
+ r = "breeze_dark";
+ }
+ else if ( desktopEnvironment.equalsIgnoreAsciiCase("macosx") ) {
+ if (!bPreferDarkIconTheme)
+ r = "sukapura";
+ else
+ r = "sukapura_dark";
+ }
+ else if ( desktopEnvironment.equalsIgnoreAsciiCase("gnome") ||
+ desktopEnvironment.equalsIgnoreAsciiCase("mate") ||
+ desktopEnvironment.equalsIgnoreAsciiCase("unity") ) {
+ if (!bPreferDarkIconTheme)
+ r = "elementary";
+ else
+ r = "sifr_dark";
+ } else
+ {
+ if (!bPreferDarkIconTheme)
+ r = FALLBACK_LIGHT_ICON_THEME_ID;
+ else
+ r = FALLBACK_DARK_ICON_THEME_ID;
+ }
+ return r;
+#endif // _WIN32
+}
+
+OUString
+IconThemeSelector::SelectIconThemeForDesktopEnvironment(
+ const std::vector<IconThemeInfo>& installedThemes,
+ const OUString& desktopEnvironment) const
+{
+ if (!mPreferredIconTheme.isEmpty()) {
+ if (icon_theme_is_in_installed_themes(mPreferredIconTheme, installedThemes)) {
+ return mPreferredIconTheme;
+ }
+ }
+
+ OUString themeForDesktop = GetIconThemeForDesktopEnvironment(desktopEnvironment, mPreferDarkIconTheme);
+ if (icon_theme_is_in_installed_themes(themeForDesktop, installedThemes)) {
+ return themeForDesktop;
+ }
+
+ return ReturnFallback(installedThemes);
+}
+
+OUString
+IconThemeSelector::SelectIconTheme(
+ const std::vector<IconThemeInfo>& installedThemes,
+ const OUString& theme) const
+{
+ if (mUseHighContrastTheme) {
+ const Color aCol(Application::GetSettings().GetStyleSettings().GetWindowColor());
+ const OUString name(aCol.IsDark() ? IconThemeInfo::HIGH_CONTRAST_ID_DARK
+ : IconThemeInfo::HIGH_CONTRAST_ID_BRIGHT);
+ if (icon_theme_is_in_installed_themes(name, installedThemes)) {
+ return name;
+ }
+ }
+
+ if (icon_theme_is_in_installed_themes(theme, installedThemes)) {
+ return theme;
+ }
+
+ return ReturnFallback(installedThemes);
+}
+
+void
+IconThemeSelector::SetUseHighContrastTheme(bool v)
+{
+ mUseHighContrastTheme = v;
+}
+
+bool
+IconThemeSelector::SetPreferredIconTheme(const OUString& theme, bool bDarkIconTheme)
+{
+ // lower case theme name, and (tdf#120175) replace - with _
+ // see icon-themes/README
+ OUString sIconTheme = theme.toAsciiLowerCase().replace('-','_');
+
+ const bool bChanged = mPreferredIconTheme != sIconTheme || mPreferDarkIconTheme != bDarkIconTheme;
+ if (bChanged)
+ {
+ mPreferredIconTheme = sIconTheme;
+ mPreferDarkIconTheme = bDarkIconTheme;
+ }
+ return bChanged;
+}
+
+bool
+IconThemeSelector::operator==(const vcl::IconThemeSelector& other) const
+{
+ if (this == &other) {
+ return true;
+ }
+ if (mPreferredIconTheme != other.mPreferredIconTheme) {
+ return false;
+ }
+ if (mPreferDarkIconTheme != other.mPreferDarkIconTheme) {
+ return false;
+ }
+ if (mUseHighContrastTheme != other.mUseHighContrastTheme) {
+ return false;
+ }
+ return true;
+}
+
+bool
+IconThemeSelector::operator!=(const vcl::IconThemeSelector& other) const
+{
+ return !(*this == other);
+}
+
+/*static*/ OUString
+IconThemeSelector::ReturnFallback(const std::vector<IconThemeInfo>& installedThemes)
+{
+ if (!installedThemes.empty()) {
+ return installedThemes.front().GetThemeId();
+ }
+ else {
+ return FALLBACK_LIGHT_ICON_THEME_ID;
+ }
+}
+
+} /* namespace vcl */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/app/brand.cxx b/vcl/source/app/brand.cxx
new file mode 100644
index 0000000000..4ab1608d53
--- /dev/null
+++ b/vcl/source/app/brand.cxx
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <config_folders.h>
+
+#include <rtl/ustring.hxx>
+#include <rtl/bootstrap.hxx>
+#include <osl/process.h>
+#include <tools/urlobj.hxx>
+#include <tools/stream.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <vcl/filter/PngImageReader.hxx>
+#include <vcl/bitmapex.hxx>
+#include <vcl/svapp.hxx>
+
+namespace {
+ bool loadPng( std::u16string_view rPath, BitmapEx &rBitmap)
+ {
+ INetURLObject aObj( rPath );
+ SvFileStream aStrm( aObj.PathToFileName(), StreamMode::STD_READ );
+ if ( !aStrm.GetError() ) {
+ vcl::PngImageReader aReader( aStrm );
+ rBitmap = aReader.read();
+ return !rBitmap.IsEmpty();
+ }
+ else
+ return false;
+ }
+ bool tryLoadPng( std::u16string_view rBaseDir, std::u16string_view rName, BitmapEx& rBitmap )
+ {
+ return loadPng( rtl::Concat2View(OUString::Concat(rBaseDir) + "/" LIBO_ETC_FOLDER + rName), rBitmap);
+ }
+}
+
+bool Application::LoadBrandBitmap (std::u16string_view pName, BitmapEx &rBitmap)
+{
+ // TODO - if we want more flexibility we could add a branding path
+ // in an rc file perhaps fallback to "about.bmp"
+ OUString aBaseDir( "$BRAND_BASE_DIR");
+ rtl::Bootstrap::expandMacros( aBaseDir );
+ OUString aBaseName(OUStringChar('/') + pName);
+ OUString aPng( ".png" );
+
+ rtl_Locale *pLoc = nullptr;
+ osl_getProcessLocale (&pLoc);
+ LanguageTag aLanguageTag( *pLoc);
+
+ ::std::vector< OUString > aFallbacks( aLanguageTag.getFallbackStrings( true));
+ for (const OUString & aFallback : aFallbacks)
+ {
+ if (tryLoadPng( aBaseDir, Concat2View(aBaseName + "-" + aFallback + aPng), rBitmap))
+ return true;
+ }
+
+ return tryLoadPng( aBaseDir, Concat2View(aBaseName + aPng), rBitmap);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/app/customweld.cxx b/vcl/source/app/customweld.cxx
new file mode 100644
index 0000000000..675373aa5f
--- /dev/null
+++ b/vcl/source/app/customweld.cxx
@@ -0,0 +1,112 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <vcl/customweld.hxx>
+
+namespace weld
+{
+CustomWidgetController::~CustomWidgetController() {}
+
+IMPL_LINK_NOARG(CustomWidgetController, DragBeginHdl, weld::DrawingArea&, bool)
+{
+ return StartDrag();
+}
+
+CustomWeld::CustomWeld(weld::Builder& rBuilder, const OUString& rDrawingId,
+ CustomWidgetController& rWidgetController)
+ : m_rWidgetController(rWidgetController)
+ , m_xDrawingArea(rBuilder.weld_drawing_area(rDrawingId, rWidgetController.CreateAccessible(),
+ rWidgetController.GetUITestFactory(),
+ &rWidgetController))
+{
+ m_rWidgetController.SetDrawingArea(m_xDrawingArea.get());
+ m_xDrawingArea->connect_size_allocate(LINK(this, CustomWeld, DoResize));
+ m_xDrawingArea->connect_draw(LINK(this, CustomWeld, DoPaint));
+ m_xDrawingArea->connect_mouse_press(LINK(this, CustomWeld, DoMouseButtonDown));
+ m_xDrawingArea->connect_mouse_move(LINK(this, CustomWeld, DoMouseMove));
+ m_xDrawingArea->connect_mouse_release(LINK(this, CustomWeld, DoMouseButtonUp));
+ m_xDrawingArea->connect_focus_in(LINK(this, CustomWeld, DoGetFocus));
+ m_xDrawingArea->connect_focus_out(LINK(this, CustomWeld, DoLoseFocus));
+ m_xDrawingArea->connect_key_press(LINK(this, CustomWeld, DoKeyPress));
+ m_xDrawingArea->connect_focus_rect(LINK(this, CustomWeld, DoFocusRect));
+ m_xDrawingArea->connect_style_updated(LINK(this, CustomWeld, DoStyleUpdated));
+ m_xDrawingArea->connect_command(LINK(this, CustomWeld, DoCommand));
+ m_xDrawingArea->connect_query_tooltip(LINK(this, CustomWeld, DoRequestHelp));
+ m_xDrawingArea->connect_im_context_get_surrounding(LINK(this, CustomWeld, DoGetSurrounding));
+ m_xDrawingArea->connect_im_context_delete_surrounding(
+ LINK(this, CustomWeld, DoDeleteSurrounding));
+}
+
+IMPL_LINK(CustomWeld, DoResize, const Size&, rSize, void)
+{
+ m_rWidgetController.SetOutputSizePixel(rSize);
+ m_rWidgetController.Resize();
+}
+
+IMPL_LINK(CustomWeld, DoPaint, weld::DrawingArea::draw_args, aPayload, void)
+{
+ m_rWidgetController.Paint(aPayload.first, aPayload.second);
+}
+
+IMPL_LINK(CustomWeld, DoMouseButtonDown, const MouseEvent&, rMEvt, bool)
+{
+ return m_rWidgetController.MouseButtonDown(rMEvt);
+}
+
+IMPL_LINK(CustomWeld, DoMouseMove, const MouseEvent&, rMEvt, bool)
+{
+ return m_rWidgetController.MouseMove(rMEvt);
+}
+
+IMPL_LINK(CustomWeld, DoMouseButtonUp, const MouseEvent&, rMEvt, bool)
+{
+ return m_rWidgetController.MouseButtonUp(rMEvt);
+}
+
+IMPL_LINK_NOARG(CustomWeld, DoGetFocus, weld::Widget&, void) { m_rWidgetController.GetFocus(); }
+
+IMPL_LINK_NOARG(CustomWeld, DoLoseFocus, weld::Widget&, void) { m_rWidgetController.LoseFocus(); }
+
+IMPL_LINK(CustomWeld, DoKeyPress, const KeyEvent&, rKEvt, bool)
+{
+ return m_rWidgetController.KeyInput(rKEvt);
+}
+
+IMPL_LINK_NOARG(CustomWeld, DoFocusRect, weld::Widget&, tools::Rectangle)
+{
+ return m_rWidgetController.GetFocusRect();
+}
+
+IMPL_LINK_NOARG(CustomWeld, DoStyleUpdated, weld::Widget&, void)
+{
+ m_rWidgetController.StyleUpdated();
+}
+
+IMPL_LINK(CustomWeld, DoCommand, const CommandEvent&, rPos, bool)
+{
+ return m_rWidgetController.Command(rPos);
+}
+
+IMPL_LINK(CustomWeld, DoRequestHelp, tools::Rectangle&, rHelpArea, OUString)
+{
+ return m_rWidgetController.RequestHelp(rHelpArea);
+}
+
+IMPL_LINK(CustomWeld, DoGetSurrounding, OUString&, rSurrounding, int)
+{
+ return m_rWidgetController.GetSurroundingText(rSurrounding);
+}
+
+IMPL_LINK(CustomWeld, DoDeleteSurrounding, const Selection&, rSelection, bool)
+{
+ return m_rWidgetController.DeleteSurroundingText(rSelection);
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/app/dbggui.cxx b/vcl/source/app/dbggui.cxx
new file mode 100644
index 0000000000..cfeeeaf5d9
--- /dev/null
+++ b/vcl/source/app/dbggui.cxx
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#ifndef NDEBUG
+
+#include <tools/debug.hxx>
+
+#include <svdata.hxx>
+#include <dbggui.hxx>
+
+#include <salinst.hxx>
+
+using namespace ::com::sun::star;
+
+static void ImplDbgTestSolarMutex()
+{
+ assert(ImplGetSVData()->mpDefInst->GetYieldMutex()->IsCurrentThread() && "SolarMutex not owned!");
+}
+
+void DbgGUIInitSolarMutexCheck()
+{
+ DbgSetTestSolarMutex( ImplDbgTestSolarMutex );
+}
+
+void DbgGUIDeInitSolarMutexCheck()
+{
+ DbgSetTestSolarMutex( nullptr );
+}
+
+#endif // NDEBUG
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/app/dndhelp.cxx b/vcl/source/app/dndhelp.cxx
new file mode 100644
index 0000000000..bf0e897dfc
--- /dev/null
+++ b/vcl/source/app/dndhelp.cxx
@@ -0,0 +1,167 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vcl/dndhelp.hxx>
+
+#include <vcl/svapp.hxx>
+#include <dndhelper.hxx>
+
+#include <cppuhelper/queryinterface.hxx>
+
+#include <com/sun/star/awt/XDisplayConnection.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+
+using namespace ::com::sun::star;
+
+vcl::unohelper::DragAndDropClient::~DragAndDropClient() COVERITY_NOEXCEPT_FALSE {}
+
+void vcl::unohelper::DragAndDropClient::dragGestureRecognized( const css::datatransfer::dnd::DragGestureEvent& /*dge*/ )
+{
+}
+
+void vcl::unohelper::DragAndDropClient::dragDropEnd( const css::datatransfer::dnd::DragSourceDropEvent& /*dsde*/ )
+{
+}
+
+void vcl::unohelper::DragAndDropClient::drop( const css::datatransfer::dnd::DropTargetDropEvent& /*dtde*/ )
+{
+}
+
+void vcl::unohelper::DragAndDropClient::dragEnter( const css::datatransfer::dnd::DropTargetDragEnterEvent& /*dtdee*/ )
+{
+}
+
+void vcl::unohelper::DragAndDropClient::dragExit( const css::datatransfer::dnd::DropTargetEvent& /*dte*/ )
+{
+}
+
+void vcl::unohelper::DragAndDropClient::dragOver( const css::datatransfer::dnd::DropTargetDragEvent& /*dtde*/ )
+{
+}
+
+vcl::unohelper::DragAndDropWrapper::DragAndDropWrapper( DragAndDropClient* pClient )
+{
+ mpClient = pClient;
+}
+
+vcl::unohelper::DragAndDropWrapper::~DragAndDropWrapper()
+{
+}
+
+// uno::XInterface
+uno::Any vcl::unohelper::DragAndDropWrapper::queryInterface( const uno::Type & rType )
+{
+ uno::Any aRet = ::cppu::queryInterface( rType,
+ static_cast< css::lang::XEventListener* >( static_cast<css::datatransfer::dnd::XDragGestureListener*>(this) ),
+ static_cast< css::datatransfer::dnd::XDragGestureListener* >(this),
+ static_cast< css::datatransfer::dnd::XDragSourceListener* >(this),
+ static_cast< css::datatransfer::dnd::XDropTargetListener* >(this) );
+ return (aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType ));
+}
+
+// css::lang::XEventListener
+void vcl::unohelper::DragAndDropWrapper::disposing( const css::lang::EventObject& rEvent )
+{
+ // Empty Source means it's the client, because the client is not a XInterface
+ if ( !rEvent.Source.is() )
+ mpClient = nullptr;
+}
+
+// css::datatransfer::dnd::XDragGestureListener
+void vcl::unohelper::DragAndDropWrapper::dragGestureRecognized( const css::datatransfer::dnd::DragGestureEvent& rDGE )
+{
+ if ( mpClient )
+ mpClient->dragGestureRecognized( rDGE );
+}
+
+// css::datatransfer::dnd::XDragSourceListener
+void vcl::unohelper::DragAndDropWrapper::dragDropEnd( const css::datatransfer::dnd::DragSourceDropEvent& rDSDE )
+{
+ if ( mpClient )
+ mpClient->dragDropEnd( rDSDE );
+}
+
+void vcl::unohelper::DragAndDropWrapper::dragEnter( const css::datatransfer::dnd::DragSourceDragEvent& )
+{
+}
+
+void vcl::unohelper::DragAndDropWrapper::dragExit( const css::datatransfer::dnd::DragSourceEvent& )
+{
+}
+
+void vcl::unohelper::DragAndDropWrapper::dragOver( const css::datatransfer::dnd::DragSourceDragEvent& )
+{
+}
+
+void vcl::unohelper::DragAndDropWrapper::dropActionChanged( const css::datatransfer::dnd::DragSourceDragEvent& )
+{
+}
+
+// css::datatransfer::dnd::XDropTargetListener
+void vcl::unohelper::DragAndDropWrapper::drop( const css::datatransfer::dnd::DropTargetDropEvent& rDTDE )
+{
+ if ( mpClient )
+ mpClient->drop( rDTDE );
+}
+
+void vcl::unohelper::DragAndDropWrapper::dragEnter( const css::datatransfer::dnd::DropTargetDragEnterEvent& rDTDEE )
+{
+ if ( mpClient )
+ mpClient->dragEnter( rDTDEE );
+}
+
+void vcl::unohelper::DragAndDropWrapper::dragExit( const css::datatransfer::dnd::DropTargetEvent& dte )
+{
+ if ( mpClient )
+ mpClient->dragExit( dte );
+}
+
+void vcl::unohelper::DragAndDropWrapper::dragOver( const css::datatransfer::dnd::DropTargetDragEvent& rDTDE )
+{
+ if ( mpClient )
+ mpClient->dragOver( rDTDE );
+}
+
+void vcl::unohelper::DragAndDropWrapper::dropActionChanged( const css::datatransfer::dnd::DropTargetDragEvent& )
+{
+}
+
+css::uno::Reference<css::uno::XInterface>
+vcl::OleDnDHelper(const css::uno::Reference<css::lang::XInitialization>& xDnD, const sal_IntPtr pWin, DragOrDrop eDoD)
+{
+ if (pWin && xDnD)
+ {
+ if (eDoD == vcl::DragOrDrop::Drag)
+ xDnD->initialize({ uno::Any(), uno::Any(static_cast<sal_uInt64>(pWin)) });
+ else
+ xDnD->initialize({ uno::Any(static_cast<sal_uInt64>(pWin)), uno::Any() });
+ }
+ return xDnD;
+}
+
+css::uno::Reference<css::uno::XInterface>
+vcl::X11DnDHelper(const css::uno::Reference<css::lang::XInitialization>& xDnD, const sal_IntPtr pWin)
+{
+ if (pWin && xDnD)
+ xDnD->initialize({ uno::Any(Application::GetDisplayConnection()),
+ uno::Any(static_cast<sal_uInt64>(pWin)) });
+ return xDnD;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/app/help.cxx b/vcl/source/app/help.cxx
new file mode 100644
index 0000000000..bbdb0ea3c6
--- /dev/null
+++ b/vcl/source/app/help.cxx
@@ -0,0 +1,686 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <comphelper/string.hxx>
+#include <sal/log.hxx>
+
+#include <comphelper/diagnose_ex.hxx>
+#include <tools/time.hxx>
+
+#include <vcl/window.hxx>
+#include <vcl/event.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/wrkwin.hxx>
+#include <vcl/help.hxx>
+#include <vcl/settings.hxx>
+
+#include <helpwin.hxx>
+#include <salframe.hxx>
+#include <svdata.hxx>
+
+#define HELPWINSTYLE_QUICK 0
+#define HELPWINSTYLE_BALLOON 1
+
+#define HELPTEXTMARGIN_QUICK 3
+#define HELPTEXTMARGIN_BALLOON 6
+
+#define HELPTEXTMAXLEN 150
+
+Help::Help()
+{
+}
+
+Help::~Help()
+{
+}
+
+bool Help::Start( const OUString&, const vcl::Window* )
+{
+ return false;
+}
+
+bool Help::Start(const OUString&, weld::Widget*)
+{
+ return false;
+}
+
+void Help::SearchKeyword( const OUString& )
+{
+}
+
+OUString Help::GetHelpText( const OUString&, const vcl::Window* )
+{
+ return OUString();
+}
+
+OUString Help::GetHelpText( const OUString&, const weld::Widget* )
+{
+ return OUString();
+}
+
+void Help::EnableContextHelp()
+{
+ ImplGetSVHelpData().mbContextHelp = true;
+}
+
+void Help::DisableContextHelp()
+{
+ ImplGetSVHelpData().mbContextHelp = false;
+}
+
+bool Help::IsContextHelpEnabled()
+{
+ return ImplGetSVHelpData().mbContextHelp;
+}
+
+void Help::EnableExtHelp()
+{
+ ImplGetSVHelpData().mbExtHelp = true;
+}
+
+void Help::DisableExtHelp()
+{
+ ImplGetSVHelpData().mbExtHelp = false;
+}
+
+bool Help::IsExtHelpEnabled()
+{
+ return ImplGetSVHelpData().mbExtHelp;
+}
+
+bool Help::StartExtHelp()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ ImplSVHelpData& aHelpData = ImplGetSVHelpData();
+
+ if ( aHelpData.mbExtHelp && !aHelpData.mbExtHelpMode )
+ {
+ aHelpData.mbExtHelpMode = true;
+ aHelpData.mbOldBalloonMode = aHelpData.mbBalloonHelp;
+ aHelpData.mbBalloonHelp = true;
+ if (pSVData->maFrameData.mpAppWin)
+ pSVData->maFrameData.mpAppWin->ImplGenerateMouseMove();
+ return true;
+ }
+
+ return false;
+}
+
+bool Help::EndExtHelp()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ ImplSVHelpData& aHelpData = ImplGetSVHelpData();
+
+ if ( aHelpData.mbExtHelp && aHelpData.mbExtHelpMode )
+ {
+ aHelpData.mbExtHelpMode = false;
+ aHelpData.mbBalloonHelp = aHelpData.mbOldBalloonMode;
+ if (pSVData->maFrameData.mpAppWin)
+ pSVData->maFrameData.mpAppWin->ImplGenerateMouseMove();
+ return true;
+ }
+
+ return false;
+}
+
+void Help::EnableBalloonHelp()
+{
+ ImplGetSVHelpData().mbBalloonHelp = true;
+}
+
+void Help::DisableBalloonHelp()
+{
+ ImplGetSVHelpData().mbBalloonHelp = false;
+}
+
+bool Help::IsBalloonHelpEnabled()
+{
+ return ImplGetSVHelpData().mbBalloonHelp;
+}
+
+void Help::ShowBalloon( vcl::Window* pParent,
+ const Point& rScreenPos, const tools::Rectangle& rRect,
+ const OUString& rHelpText )
+{
+ ImplShowHelpWindow( pParent, HELPWINSTYLE_BALLOON, QuickHelpFlags::NONE,
+ rHelpText, rScreenPos, rRect );
+}
+
+void Help::EnableQuickHelp()
+{
+ ImplGetSVHelpData().mbQuickHelp = true;
+}
+
+void Help::DisableQuickHelp()
+{
+ ImplGetSVHelpData().mbQuickHelp = false;
+}
+
+bool Help::IsQuickHelpEnabled()
+{
+ return ImplGetSVHelpData().mbQuickHelp;
+}
+
+void Help::ShowQuickHelp( vcl::Window* pParent,
+ const tools::Rectangle& rScreenRect,
+ const OUString& rHelpText,
+ QuickHelpFlags nStyle )
+{
+ sal_uInt16 nHelpWinStyle = ( nStyle & QuickHelpFlags::TipStyleBalloon ) ? HELPWINSTYLE_BALLOON : HELPWINSTYLE_QUICK;
+ Point aScreenPos = nStyle & QuickHelpFlags::NoAutoPos
+ ? Point()
+ : pParent->OutputToScreenPixel(pParent->GetPointerPosPixel());
+ ImplShowHelpWindow( pParent, nHelpWinStyle, nStyle,
+ rHelpText, aScreenPos, rScreenRect );
+}
+
+void Help::HideBalloonAndQuickHelp()
+{
+ HelpTextWindow const * pHelpWin = ImplGetSVHelpData().mpHelpWin;
+ bool const bIsVisible = ( pHelpWin != nullptr ) && pHelpWin->IsVisible();
+ ImplDestroyHelpWindow( bIsVisible );
+}
+
+void* Help::ShowPopover(vcl::Window* pParent, const tools::Rectangle& rScreenRect,
+ const OUString& rText, QuickHelpFlags nStyle)
+{
+ void* nId = pParent->ImplGetFrame()->ShowPopover(rText, pParent, rScreenRect, nStyle);
+ if (nId)
+ {
+ //popovers are handled natively, return early
+ return nId;
+ }
+
+ sal_uInt16 nHelpWinStyle = ( nStyle & QuickHelpFlags::TipStyleBalloon ) ? HELPWINSTYLE_BALLOON : HELPWINSTYLE_QUICK;
+ VclPtrInstance<HelpTextWindow> pHelpWin( pParent, rText, nHelpWinStyle, nStyle );
+
+ nId = pHelpWin.get();
+ UpdatePopover(nId, pParent, rScreenRect, rText);
+
+ pHelpWin->ShowHelp(true);
+ return nId;
+}
+
+void Help::UpdatePopover(void* nId, vcl::Window* pParent, const tools::Rectangle& rScreenRect,
+ const OUString& rText)
+{
+ if (pParent->ImplGetFrame()->UpdatePopover(nId, rText, pParent, rScreenRect))
+ {
+ //popovers are handled natively, return early
+ return;
+ }
+
+ HelpTextWindow* pHelpWin = static_cast< HelpTextWindow* >( nId );
+ ENSURE_OR_RETURN_VOID( pHelpWin != nullptr, "Help::UpdatePopover: invalid ID!" );
+
+ Size aSz = pHelpWin->CalcOutSize();
+ pHelpWin->SetOutputSizePixel( aSz );
+ ImplSetHelpWindowPos( pHelpWin, pHelpWin->GetWinStyle(), pHelpWin->GetStyle(),
+ pParent->OutputToScreenPixel( pParent->GetPointerPosPixel() ), rScreenRect );
+
+ pHelpWin->SetHelpText( rText );
+ pHelpWin->Invalidate();
+}
+
+void Help::HidePopover(vcl::Window const * pParent, void* nId)
+{
+ if (pParent->ImplGetFrame()->HidePopover(nId))
+ {
+ //popovers are handled natively, return early
+ return;
+ }
+
+ VclPtr<HelpTextWindow> pHelpWin = static_cast<HelpTextWindow*>(nId);
+ vcl::Window* pFrameWindow = pHelpWin->ImplGetFrameWindow();
+ pHelpWin->Hide();
+ // trigger update, so that a Paint is instantly triggered since we do not save the background
+ pFrameWindow->ImplUpdateAll();
+ pHelpWin.disposeAndClear();
+ ImplGetSVHelpData().mnLastHelpHideTime = tools::Time::GetSystemTicks();
+}
+
+HelpTextWindow::HelpTextWindow( vcl::Window* pParent, const OUString& rText, sal_uInt16 nHelpWinStyle, QuickHelpFlags nStyle ) :
+ FloatingWindow( pParent, WB_SYSTEMWINDOW|WB_TOOLTIPWIN ), // #105827# if we change the parent, mirroring will not work correctly when positioning this window
+ maHelpText( rText ),
+ maShowTimer( "vcl::HelpTextWindow maShowTimer" ),
+ maHideTimer( "vcl::HelpTextWindow maHideTimer" )
+{
+ SetType( WindowType::HELPTEXTWINDOW );
+ ImplSetMouseTransparent( true );
+ mnHelpWinStyle = nHelpWinStyle;
+ mnStyle = nStyle;
+
+ if( mnStyle & QuickHelpFlags::BiDiRtl )
+ {
+ vcl::text::ComplexTextLayoutFlags nLayoutMode = GetOutDev()->GetLayoutMode();
+ nLayoutMode |= vcl::text::ComplexTextLayoutFlags::BiDiRtl | vcl::text::ComplexTextLayoutFlags::TextOriginLeft;
+ GetOutDev()->SetLayoutMode( nLayoutMode );
+ }
+ SetHelpText( rText );
+ Window::SetHelpText( rText );
+
+ if ( ImplGetSVHelpData().mbSetKeyboardHelp )
+ ImplGetSVHelpData().mbKeyboardHelp = true;
+
+
+ maShowTimer.SetInvokeHandler( LINK( this, HelpTextWindow, TimerHdl ) );
+
+ const HelpSettings& rHelpSettings = pParent->GetSettings().GetHelpSettings();
+ maHideTimer.SetTimeout( rHelpSettings.GetTipTimeout() );
+ maHideTimer.SetInvokeHandler( LINK( this, HelpTextWindow, TimerHdl ) );
+}
+
+void HelpTextWindow::ApplySettings(vcl::RenderContext& rRenderContext)
+{
+ const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
+ SetPointFont(rRenderContext, rStyleSettings.GetHelpFont());
+ rRenderContext.SetTextColor(rStyleSettings.GetHelpTextColor());
+ rRenderContext.SetTextAlign(ALIGN_TOP);
+
+ if (rRenderContext.IsNativeControlSupported(ControlType::Tooltip, ControlPart::Entire))
+ {
+ EnableChildTransparentMode();
+ SetParentClipMode(ParentClipMode::NoClip);
+ SetPaintTransparent(true);
+ rRenderContext.SetBackground();
+ }
+ else
+ rRenderContext.SetBackground(Wallpaper(rStyleSettings.GetHelpColor()));
+
+ if (rStyleSettings.GetHelpColor().IsDark())
+ rRenderContext.SetLineColor(COL_WHITE);
+ else
+ rRenderContext.SetLineColor(COL_BLACK);
+ rRenderContext.SetFillColor();
+}
+
+HelpTextWindow::~HelpTextWindow()
+{
+ disposeOnce();
+}
+
+void HelpTextWindow::dispose()
+{
+ maShowTimer.Stop();
+ maHideTimer.Stop();
+
+ if( this == ImplGetSVHelpData().mpHelpWin )
+ ImplGetSVHelpData().mpHelpWin = nullptr;
+ FloatingWindow::dispose();
+}
+
+void HelpTextWindow::SetHelpText( const OUString& rHelpText )
+{
+ maHelpText = rHelpText;
+ ApplySettings(*GetOutDev());
+ if ( mnHelpWinStyle == HELPWINSTYLE_QUICK && maHelpText.getLength() < HELPTEXTMAXLEN && maHelpText.indexOf('\n') < 0)
+ {
+ Size aSize;
+ aSize.setHeight( GetTextHeight() );
+ if ( mnStyle & QuickHelpFlags::CtrlText )
+ aSize.setWidth( GetOutDev()->GetCtrlTextWidth( maHelpText ) );
+ else
+ aSize.setWidth( GetTextWidth( maHelpText ) );
+ maTextRect = tools::Rectangle( Point( HELPTEXTMARGIN_QUICK, HELPTEXTMARGIN_QUICK ), aSize );
+ }
+ else // HELPWINSTYLE_BALLOON
+ {
+ sal_Int32 nCharsInLine = 35 + ((maHelpText.getLength()/100)*5);
+ // average width to have all windows consistent
+ OUStringBuffer aBuf(nCharsInLine);
+ comphelper::string::padToLength(aBuf, nCharsInLine, 'x');
+ tools::Long nWidth = GetTextWidth( OUString::unacquired(aBuf) );
+ Size aTmpSize( nWidth, 0x7FFFFFFF );
+ tools::Rectangle aTry1( Point(), aTmpSize );
+ DrawTextFlags nDrawFlags = DrawTextFlags::MultiLine | DrawTextFlags::WordBreak |
+ DrawTextFlags::Left | DrawTextFlags::Top;
+ if ( mnStyle & QuickHelpFlags::CtrlText )
+ nDrawFlags |= DrawTextFlags::Mnemonic;
+ tools::Rectangle aTextRect = GetTextRect( aTry1, maHelpText, nDrawFlags );
+
+ // get a better width later...
+ maTextRect = aTextRect;
+
+ // safety distance...
+ maTextRect.SetPos( Point( HELPTEXTMARGIN_BALLOON, HELPTEXTMARGIN_BALLOON ) );
+ }
+
+ Size aSize( CalcOutSize() );
+ SetOutputSizePixel( aSize );
+ if (IsVisible())
+ PaintImmediately();
+}
+
+void HelpTextWindow::ImplShow()
+{
+ VclPtr<HelpTextWindow> xWindow( this );
+ Show( true, ShowFlags::NoActivate );
+ if( !xWindow->isDisposed() )
+ PaintImmediately();
+}
+
+void HelpTextWindow::Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& )
+{
+ // paint native background
+ bool bNativeOK = false;
+ if (rRenderContext.IsNativeControlSupported(ControlType::Tooltip, ControlPart::Entire))
+ {
+ tools::Rectangle aCtrlRegion(Point(0, 0), GetOutputSizePixel());
+ ImplControlValue aControlValue;
+ bNativeOK = rRenderContext.DrawNativeControl(ControlType::Tooltip, ControlPart::Entire, aCtrlRegion,
+ ControlState::NONE, aControlValue, OUString());
+ }
+
+ // paint text
+ if (mnHelpWinStyle == HELPWINSTYLE_QUICK && maHelpText.getLength() < HELPTEXTMAXLEN && maHelpText.indexOf('\n') < 0)
+ {
+ if ( mnStyle & QuickHelpFlags::CtrlText )
+ rRenderContext.DrawCtrlText(maTextRect.TopLeft(), maHelpText);
+ else
+ rRenderContext.DrawText(maTextRect.TopLeft(), maHelpText);
+ }
+ else // HELPWINSTYLE_BALLOON
+ {
+ DrawTextFlags nDrawFlags = DrawTextFlags::MultiLine|DrawTextFlags::WordBreak|
+ DrawTextFlags::Left|DrawTextFlags::Top;
+ if (mnStyle & QuickHelpFlags::CtrlText)
+ nDrawFlags |= DrawTextFlags::Mnemonic;
+ rRenderContext.DrawText(maTextRect, maHelpText, nDrawFlags);
+ }
+
+ // border
+ if (bNativeOK)
+ return;
+
+ Size aSz = GetOutputSizePixel();
+ rRenderContext.DrawRect(tools::Rectangle(Point(), aSz));
+ if (mnHelpWinStyle == HELPWINSTYLE_BALLOON)
+ {
+ aSz.AdjustWidth( -2 );
+ aSz.AdjustHeight( -2 );
+ Color aColor(rRenderContext.GetLineColor());
+ rRenderContext.SetLineColor(COL_GRAY);
+ rRenderContext.DrawRect(tools::Rectangle(Point(1, 1), aSz));
+ rRenderContext.SetLineColor(aColor);
+ }
+}
+
+void HelpTextWindow::ShowHelp(bool bNoDelay)
+{
+ sal_uLong nTimeout = 0;
+ if (!bNoDelay)
+ {
+ // In case of ExtendedHelp display help sooner
+ if ( ImplGetSVHelpData().mbExtHelpMode )
+ nTimeout = 15;
+ else
+ {
+ if ( mnHelpWinStyle == HELPWINSTYLE_QUICK )
+ nTimeout = HelpSettings::GetTipDelay();
+ else
+ nTimeout = HelpSettings::GetBalloonDelay();
+ }
+ }
+
+ maShowTimer.SetTimeout( nTimeout );
+ maShowTimer.Start();
+}
+
+IMPL_LINK( HelpTextWindow, TimerHdl, Timer*, pTimer, void)
+{
+ if ( pTimer == &maShowTimer )
+ {
+ ResetHideTimer();
+ ImplShow();
+ }
+ else
+ {
+ SAL_WARN_IF( pTimer != &maHideTimer, "vcl", "HelpTextWindow::TimerHdl with bad Timer" );
+ ImplDestroyHelpWindow( true );
+ }
+}
+
+Size HelpTextWindow::CalcOutSize() const
+{
+ Size aSz = maTextRect.GetSize();
+ aSz.AdjustWidth(2*maTextRect.Left() );
+ aSz.AdjustHeight(2*maTextRect.Top() );
+ return aSz;
+}
+
+void HelpTextWindow::RequestHelp( const HelpEvent& /*rHEvt*/ )
+{
+ // Just to assure that Window::RequestHelp() is not called by
+ // ShowQuickHelp/ShowBalloonHelp in the HelpTextWindow.
+}
+
+OUString HelpTextWindow::GetText() const
+{
+ return maHelpText;
+}
+
+void HelpTextWindow::ResetHideTimer()
+{
+ if (mnHelpWinStyle == HELPWINSTYLE_QUICK)
+ {
+ // start auto-hide-timer for non-ShowTip windows
+ if (this == ImplGetSVHelpData().mpHelpWin)
+ maHideTimer.Start();
+ }
+}
+
+void ImplShowHelpWindow( vcl::Window* pParent, sal_uInt16 nHelpWinStyle, QuickHelpFlags nStyle,
+ const OUString& rHelpText,
+ const Point& rScreenPos, const tools::Rectangle& rHelpArea )
+{
+ if (pParent->ImplGetFrame()->ShowTooltip(rHelpText, rHelpArea))
+ {
+ //tooltips are handled natively, return early
+ return;
+ }
+
+ ImplSVHelpData& aHelpData = ImplGetSVHelpData();
+
+ if (rHelpText.isEmpty() && !aHelpData.mbRequestingHelp)
+ return;
+
+ bool bNoDelay = false;
+ if (VclPtr<HelpTextWindow> pHelpWin = aHelpData.mpHelpWin)
+ {
+ SAL_WARN_IF( pHelpWin == pParent, "vcl", "HelpInHelp ?!" );
+
+ bool bRemoveHelp = (rHelpText.isEmpty() || (pHelpWin->GetWinStyle() != nHelpWinStyle))
+ && aHelpData.mbRequestingHelp;
+
+ if (!bRemoveHelp && pHelpWin->GetParent() == pParent)
+ {
+ bool const bUpdate = (pHelpWin->GetHelpText() != rHelpText) ||
+ ((pHelpWin->GetHelpArea() != rHelpArea) && aHelpData.mbRequestingHelp);
+ if (bUpdate)
+ {
+ pHelpWin->SetHelpText( rHelpText );
+ // approach mouse position
+ ImplSetHelpWindowPos( pHelpWin, nHelpWinStyle, nStyle, rScreenPos, rHelpArea );
+ if( pHelpWin->IsVisible() )
+ pHelpWin->Invalidate();
+ }
+ pHelpWin->ResetHideTimer(); // It is shown anew, so prolongate the hide timeout
+ return;
+ }
+
+ // remove help window if no HelpText or
+ // other help mode. but keep it if we are scrolling, ie not requesting help
+ bool bWasVisible = pHelpWin->IsVisible();
+ if ( bWasVisible )
+ bNoDelay = true; // display it quickly if we were already in quick help mode
+ ImplDestroyHelpWindow( bWasVisible );
+ }
+
+ if (rHelpText.isEmpty())
+ return;
+
+ VclPtr<HelpTextWindow> pHelpWin = VclPtr<HelpTextWindow>::Create( pParent, rHelpText, nHelpWinStyle, nStyle );
+ aHelpData.mpHelpWin = pHelpWin;
+ pHelpWin->SetHelpArea( rHelpArea );
+
+ // positioning
+ Size aSz = pHelpWin->CalcOutSize();
+ pHelpWin->SetOutputSizePixel( aSz );
+ ImplSetHelpWindowPos( pHelpWin, nHelpWinStyle, nStyle, rScreenPos, rHelpArea );
+ // if not called from Window::RequestHelp, then without delay...
+ if (!bNoDelay)
+ {
+ if ( !aHelpData.mbRequestingHelp )
+ {
+ bNoDelay = true;
+ }
+ else
+ {
+ sal_uInt64 nCurTime = tools::Time::GetSystemTicks();
+ if ( ( nCurTime - aHelpData.mnLastHelpHideTime ) < o3tl::make_unsigned(HelpSettings::GetTipDelay()) )
+ bNoDelay = true;
+ }
+ }
+ pHelpWin->ShowHelp(bNoDelay);
+}
+
+void ImplDestroyHelpWindow( bool bUpdateHideTime )
+{
+ ImplDestroyHelpWindow(ImplGetSVHelpData(), bUpdateHideTime);
+}
+
+void ImplDestroyHelpWindow(ImplSVHelpData& rHelpData, bool bUpdateHideTime)
+{
+ VclPtr<HelpTextWindow> pHelpWin = rHelpData.mpHelpWin;
+ if( pHelpWin )
+ {
+ rHelpData.mpHelpWin = nullptr;
+ rHelpData.mbKeyboardHelp = false;
+ pHelpWin->Hide();
+ pHelpWin.disposeAndClear();
+ if( bUpdateHideTime )
+ rHelpData.mnLastHelpHideTime = tools::Time::GetSystemTicks();
+ }
+}
+
+void ImplSetHelpWindowPos( vcl::Window* pHelpWin, sal_uInt16 nHelpWinStyle, QuickHelpFlags nStyle,
+ const Point& rPos, const tools::Rectangle& rHelpArea )
+{
+ AbsoluteScreenPixelPoint aPos;
+ AbsoluteScreenPixelSize aSz( pHelpWin->GetSizePixel() );
+ AbsoluteScreenPixelRectangle aScreenRect = pHelpWin->ImplGetFrameWindow()->GetDesktopRectPixel();
+ vcl::Window* pWindow = pHelpWin->GetParent()->ImplGetFrameWindow();
+ // get mouse screen coords
+ AbsoluteScreenPixelPoint aMousePos(pWindow->OutputToAbsoluteScreenPixel(pWindow->GetPointerPosPixel()));
+
+ if ( nStyle & QuickHelpFlags::NoAutoPos )
+ {
+ // convert help area to screen coords
+ AbsoluteScreenPixelRectangle devHelpArea(
+ pWindow->OutputToAbsoluteScreenPixel( rHelpArea.TopLeft() ),
+ pWindow->OutputToAbsoluteScreenPixel( rHelpArea.BottomRight() ) );
+
+ // which position of the rectangle?
+ aPos = devHelpArea.Center();
+
+ if ( nStyle & QuickHelpFlags::Left )
+ aPos.setX( devHelpArea.Left() );
+ else if ( nStyle & QuickHelpFlags::Right )
+ aPos.setX( devHelpArea.Right() );
+
+ if ( nStyle & QuickHelpFlags::Top )
+ aPos.setY( devHelpArea.Top() );
+ else if ( nStyle & QuickHelpFlags::Bottom )
+ aPos.setY( devHelpArea.Bottom() );
+
+ // which direction?
+ if ( nStyle & QuickHelpFlags::Left )
+ ;
+ else if ( nStyle & QuickHelpFlags::Right )
+ aPos.AdjustX( -(aSz.Width()) );
+ else
+ aPos.AdjustX( -(aSz.Width()/2) );
+
+ if ( nStyle & QuickHelpFlags::Top )
+ ;
+ else if ( nStyle & QuickHelpFlags::Bottom )
+ aPos.AdjustY( -(aSz.Height()) );
+ else
+ aPos.AdjustY( -(aSz.Height()/2) );
+ }
+ else
+ {
+ aPos = pWindow->OutputToAbsoluteScreenPixel(rPos);
+ if ( nHelpWinStyle == HELPWINSTYLE_QUICK )
+ {
+ tools::Long nScreenHeight = aScreenRect.GetHeight();
+ aPos.AdjustX( -4 );
+ if ( aPos.Y() > aScreenRect.Top()+nScreenHeight-(nScreenHeight/4) )
+ aPos.AdjustY( -(aSz.Height()+4) );
+ else
+ aPos.AdjustY(21 );
+ }
+ else
+ {
+ // If it's the mouse position, move the window slightly
+ // so the mouse pointer does not cover it
+ if ( aPos == aMousePos )
+ {
+ aPos.AdjustX(12 );
+ aPos.AdjustY(16 );
+ }
+ }
+ }
+
+ if ( aPos.X() < aScreenRect.Left() )
+ aPos.setX( aScreenRect.Left() );
+ else if ( ( aPos.X() + aSz.Width() ) > aScreenRect.Right() )
+ aPos.setX( aScreenRect.Right() - aSz.Width() );
+ if ( aPos.Y() < aScreenRect.Top() )
+ aPos.setY( aScreenRect.Top() );
+ else if ( ( aPos.Y() + aSz.Height() ) > aScreenRect.Bottom() )
+ aPos.setY( aScreenRect.Bottom() - aSz.Height() );
+
+ if( ! (nStyle & QuickHelpFlags::NoEvadePointer) )
+ {
+ /* the remark below should be obsolete by now as the helpwindow should
+ not be focusable, leaving it as a hint. However it is sensible in most
+ conditions to evade the mouse pointer so the content window is fully visible.
+
+ // the popup must not appear under the mouse
+ // otherwise it would directly be closed due to a focus change...
+ */
+ AbsoluteScreenPixelRectangle aHelpRect( aPos, aSz );
+ if( aHelpRect.Contains( aMousePos ) )
+ {
+ AbsoluteScreenPixelPoint delta(2,2);
+ AbsoluteScreenPixelPoint aSize( aSz.Width(), aSz.Height() );
+ AbsoluteScreenPixelPoint aTest( aMousePos - aSize - delta );
+ if( aTest.X() > aScreenRect.Left() && aTest.Y() > aScreenRect.Top() )
+ aPos = aTest;
+ else
+ aPos = aMousePos + delta;
+ }
+ }
+
+ Point aPosOut = pWindow->AbsoluteScreenToOutputPixel( aPos );
+ pHelpWin->SetPosPixel( aPosOut );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/app/htmltransferable.cxx b/vcl/source/app/htmltransferable.cxx
new file mode 100644
index 0000000000..24f65fe929
--- /dev/null
+++ b/vcl/source/app/htmltransferable.cxx
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vcl/htmltransferable.hxx>
+#include <sot/exchange.hxx>
+#include <sot/formats.hxx>
+#include <vcl/svapp.hxx>
+#include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp>
+#include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
+#include <com/sun/star/datatransfer/clipboard/XFlushableClipboard.hpp>
+#include <cppuhelper/queryinterface.hxx>
+#include <boost/property_tree/json_parser.hpp>
+
+using namespace ::com::sun::star;
+
+namespace vcl::unohelper
+{
+HtmlTransferable::HtmlTransferable(OString sData)
+ : data(sData)
+{
+}
+
+HtmlTransferable::~HtmlTransferable() {}
+
+// css::uno::XInterface
+uno::Any HtmlTransferable::queryInterface(const uno::Type& rType)
+{
+ uno::Any aRet = ::cppu::queryInterface(rType, static_cast<datatransfer::XTransferable*>(this));
+ return (aRet.hasValue() ? aRet : OWeakObject::queryInterface(rType));
+}
+
+// css::datatransfer::XTransferable
+uno::Any HtmlTransferable::getTransferData(const datatransfer::DataFlavor& rFlavor)
+{
+ SotClipboardFormatId nT = SotExchange::GetFormat(rFlavor);
+ if (nT != SotClipboardFormatId::HTML)
+ {
+ throw datatransfer::UnsupportedFlavorException();
+ }
+ size_t size = data.getLength();
+ uno::Sequence<sal_Int8> sData(size);
+ std::memcpy(sData.getArray(), data.getStr(), size);
+ return uno::Any(sData);
+}
+
+uno::Sequence<datatransfer::DataFlavor> HtmlTransferable::getTransferDataFlavors()
+{
+ uno::Sequence<datatransfer::DataFlavor> aDataFlavors(1);
+ auto ref = aDataFlavors.getArray()[0];
+ ref.MimeType = "text/html";
+ ref.DataType = cppu::UnoType<uno::Sequence<sal_Int8>>::get();
+ SotExchange::GetFormatDataFlavor(SotClipboardFormatId::HTML, aDataFlavors.getArray()[0]);
+ return aDataFlavors;
+}
+
+sal_Bool HtmlTransferable::isDataFlavorSupported(const datatransfer::DataFlavor& rFlavor)
+{
+ SotClipboardFormatId nT = SotExchange::GetFormat(rFlavor);
+ return (nT == SotClipboardFormatId::HTML);
+}
+
+} // namespace vcl::unohelper
diff --git a/vcl/source/app/i18nhelp.cxx b/vcl/source/app/i18nhelp.cxx
new file mode 100644
index 0000000000..d497cdba4f
--- /dev/null
+++ b/vcl/source/app/i18nhelp.cxx
@@ -0,0 +1,156 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <unotools/localedatawrapper.hxx>
+#include <unotools/transliterationwrapper.hxx>
+
+#include <i18nlangtag/languagetag.hxx>
+#include <i18nutil/transliteration.hxx>
+
+#include <rtl/ustrbuf.hxx>
+
+#include <utility>
+#include <vcl/i18nhelp.hxx>
+
+using namespace ::com::sun::star;
+
+vcl::I18nHelper::I18nHelper( const css::uno::Reference< css::uno::XComponentContext >& rxContext, LanguageTag aLanguageTag )
+ :
+ maLanguageTag(std::move( aLanguageTag))
+{
+ m_xContext = rxContext;
+ mpLocaleDataWrapper = nullptr;
+ mpTransliterationWrapper= nullptr;
+ mbTransliterateIgnoreCase = false;
+}
+
+vcl::I18nHelper::~I18nHelper()
+{
+ ImplDestroyWrappers();
+}
+
+void vcl::I18nHelper::ImplDestroyWrappers()
+{
+ mpLocaleDataWrapper.reset();
+ mpTransliterationWrapper.reset();
+}
+
+utl::TransliterationWrapper& vcl::I18nHelper::ImplGetTransliterationWrapper() const
+{
+ if ( !mpTransliterationWrapper )
+ {
+ TransliterationFlags nModules = TransliterationFlags::IGNORE_WIDTH;
+ if ( mbTransliterateIgnoreCase )
+ nModules |= TransliterationFlags::IGNORE_CASE;
+
+ const_cast<vcl::I18nHelper*>(this)->mpTransliterationWrapper.reset(new utl::TransliterationWrapper( m_xContext, nModules ));
+ const_cast<vcl::I18nHelper*>(this)->mpTransliterationWrapper->loadModuleIfNeeded( maLanguageTag.getLanguageType() );
+ }
+ return *mpTransliterationWrapper;
+}
+
+LocaleDataWrapper& vcl::I18nHelper::ImplGetLocaleDataWrapper() const
+{
+ if ( !mpLocaleDataWrapper )
+ {
+ const_cast<vcl::I18nHelper*>(this)->mpLocaleDataWrapper.reset(new LocaleDataWrapper( m_xContext, maLanguageTag ));
+ }
+ return *mpLocaleDataWrapper;
+}
+
+static bool is_formatting_mark( sal_Unicode c )
+{
+ if( (c >= 0x200B) && (c <= 0x200F) ) // BiDi and zero-width-markers
+ return true;
+ if( (c >= 0x2028) && (c <= 0x202E) ) // BiDi and paragraph-markers
+ return true;
+ return false;
+}
+
+/* #i100057# filter formatting marks out of strings before passing them to
+ the transliteration. The real solution would have been an additional TransliterationModule
+ to ignore these marks during transliteration; however changing the code in i18npool that actually
+ implements this could produce unwanted side effects.
+
+ Of course this copying around is not really good, but looking at i18npool, one more time
+ will not hurt.
+*/
+OUString vcl::I18nHelper::filterFormattingChars( const OUString& rStr )
+{
+ sal_Int32 nLength = rStr.getLength();
+ OUStringBuffer aBuf( nLength );
+ const sal_Unicode* pStr = rStr.getStr();
+ while( nLength-- )
+ {
+ if( ! is_formatting_mark( *pStr ) )
+ aBuf.append( *pStr );
+ pStr++;
+ }
+ return aBuf.makeStringAndClear();
+}
+
+sal_Int32 vcl::I18nHelper::CompareString( const OUString& rStr1, const OUString& rStr2 ) const
+{
+ std::unique_lock aGuard( maMutex );
+
+ if ( mbTransliterateIgnoreCase )
+ {
+ // Change mbTransliterateIgnoreCase and destroy the wrapper, next call to
+ // ImplGetTransliterationWrapper() will create a wrapper with the correct bIgnoreCase
+ const_cast<vcl::I18nHelper*>(this)->mbTransliterateIgnoreCase = false;
+ const_cast<vcl::I18nHelper*>(this)->mpTransliterationWrapper.reset();
+ }
+
+ OUString aStr1( filterFormattingChars(rStr1) );
+ OUString aStr2( filterFormattingChars(rStr2) );
+ return ImplGetTransliterationWrapper().compareString( aStr1, aStr2 );
+}
+
+bool vcl::I18nHelper::MatchString( const OUString& rStr1, const OUString& rStr2 ) const
+{
+ std::unique_lock aGuard( maMutex );
+
+ if ( !mbTransliterateIgnoreCase )
+ {
+ // Change mbTransliterateIgnoreCase and destroy the wrapper, next call to
+ // ImplGetTransliterationWrapper() will create a wrapper with the correct bIgnoreCase
+ const_cast<vcl::I18nHelper*>(this)->mbTransliterateIgnoreCase = true;
+ const_cast<vcl::I18nHelper*>(this)->mpTransliterationWrapper.reset();
+ }
+
+ OUString aStr1( filterFormattingChars(rStr1) );
+ OUString aStr2( filterFormattingChars(rStr2) );
+ return ImplGetTransliterationWrapper().isMatch( aStr1, aStr2 );
+}
+
+bool vcl::I18nHelper::MatchMnemonic( std::u16string_view rString, sal_Unicode cMnemonicChar ) const
+{
+ size_t n = rString.find( '~' );
+ if ( n == std::u16string_view::npos )
+ return false;
+ OUString aMatchStr( rString.substr( n+1 ) ); // not only one char, because of transliteration...
+ return MatchString( OUString(cMnemonicChar), aMatchStr );
+}
+
+OUString vcl::I18nHelper::GetNum( tools::Long nNumber, sal_uInt16 nDecimals, bool bUseThousandSep, bool bTrailingZeros ) const
+{
+ return ImplGetLocaleDataWrapper().getNum( nNumber, nDecimals, bUseThousandSep, bTrailingZeros );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/app/idle.cxx b/vcl/source/app/idle.cxx
new file mode 100644
index 0000000000..7e57565371
--- /dev/null
+++ b/vcl/source/app/idle.cxx
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vcl/idle.hxx>
+#include <vcl/scheduler.hxx>
+
+Idle::Idle( bool bAuto, const char *pDebugName )
+ : Timer( bAuto, pDebugName )
+{
+ SetPriority( TaskPriority::DEFAULT_IDLE );
+}
+
+Idle::Idle( const char *pDebugName )
+ : Idle( false, pDebugName )
+{
+}
+
+void Idle::Start(const bool bStartTimer)
+{
+ Task::Start(false);
+
+ sal_uInt64 nPeriod = Scheduler::ImmediateTimeoutMs;
+ if (Scheduler::GetDeterministicMode())
+ {
+ switch ( GetPriority() )
+ {
+ case TaskPriority::DEFAULT_IDLE:
+ case TaskPriority::LOWEST:
+ nPeriod = Scheduler::InfiniteTimeoutMs;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (bStartTimer)
+ Task::StartTimer(nPeriod);
+}
+
+sal_uInt64 Idle::UpdateMinPeriod( sal_uInt64 /* nTimeNow */ ) const
+{
+ return Scheduler::ImmediateTimeoutMs;
+}
+
+AutoIdle::AutoIdle( const char *pDebugName )
+ : Idle( true, pDebugName )
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/app/salplug.cxx b/vcl/source/app/salplug.cxx
new file mode 100644
index 0000000000..026867e99b
--- /dev/null
+++ b/vcl/source/app/salplug.cxx
@@ -0,0 +1,478 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+// Th current high-level preprocessor structure is:
+//
+// if !HAVE_FEATURE_UI
+// => STATIC_SAL_INSTANCE
+// else
+// ? !STATIC_SAL_INSTANCE
+// ? UNIX_DESKTOP_DETECT
+// endif
+//
+// ENABLE_HEADLESS just signifies the use of the SVP plugin!
+
+#include <config_features.h>
+#include <config_vclplug.h>
+
+#include <cstdio>
+#include <desktop/crashreport.hxx>
+#include <rtl/bootstrap.hxx>
+#include <rtl/process.h>
+#include <salinst.hxx>
+#include <sal/log.hxx>
+#include <svdata.hxx>
+#include <vcl/svapp.hxx>
+
+#if HAVE_FEATURE_UI
+#if USING_X11
+#define UNIX_DESKTOP_DETECT 1
+#include <unx/desktops.hxx>
+#else
+#define UNIX_DESKTOP_DETECT 0
+#endif
+#endif
+
+#if defined(DISABLE_DYNLOADING) || !HAVE_FEATURE_UI
+#define STATIC_SAL_INSTANCE 1
+extern "C" SalInstance* create_SalInstance();
+#else
+#define STATIC_SAL_INSTANCE 0
+#include <osl/module.hxx>
+#endif
+
+#if defined(iOS)
+#include <premac.h>
+#include <UIKit/UIKit.h>
+#include <postmac.h>
+
+#elif defined(ANDROID)
+#include <android/androidinst.hxx>
+#endif
+
+#if defined(_WIN32)
+#include <o3tl/char16_t2wchar_t.hxx>
+#include <salframe.hxx>
+#include <Windows.h>
+#else
+#include <unistd.h>
+#endif
+
+#if ENABLE_HEADLESS
+#include <headless/svpdata.hxx>
+#include <headless/svpinst.hxx>
+#endif
+
+namespace {
+
+#if ENABLE_HEADLESS
+SalInstance* svp_create_SalInstance()
+{
+ SvpSalInstance* pInstance = new SvpSalInstance(std::make_unique<SvpSalYieldMutex>());
+ new SvpSalData();
+ return pInstance;
+}
+#endif
+
+#if HAVE_FEATURE_UI
+
+#if !STATIC_SAL_INSTANCE
+oslModule pCloseModule = nullptr;
+
+extern "C" typedef SalInstance* (*salFactoryProc)();
+
+SalInstance* tryInstance( const OUString& rModuleBase, bool bForce = false )
+{
+#if ENABLE_HEADLESS
+ if (rModuleBase == "svp")
+ return svp_create_SalInstance();
+#endif
+
+ SalInstance* pInst = nullptr;
+ OUString aUsedModuleBase(rModuleBase);
+ if (aUsedModuleBase == "kde5")
+ aUsedModuleBase = "kf5";
+ OUString aModule(
+#ifdef SAL_DLLPREFIX
+ SAL_DLLPREFIX
+#endif
+ "vclplug_" + aUsedModuleBase + "lo" SAL_DLLEXTENSION );
+
+ osl::Module aMod;
+ if (aMod.loadRelative(reinterpret_cast<oslGenericFunction>(&tryInstance), aModule, SAL_LOADMODULE_GLOBAL))
+ {
+ salFactoryProc aProc = reinterpret_cast<salFactoryProc>(aMod.getFunctionSymbol("create_SalInstance"));
+ if (aProc)
+ {
+ pInst = aProc();
+ SAL_INFO(
+ "vcl.plugadapt",
+ "sal plugin " << aModule << " produced instance " << pInst);
+ if (pInst)
+ {
+ pCloseModule = static_cast<oslModule>(aMod);
+ aMod.release();
+
+ /*
+ * Recent GTK+ versions load their modules with RTLD_LOCAL, so we can
+ * not access the 'gnome_accessibility_module_shutdown' anymore.
+ * So make sure libgtk+ & co are still mapped into memory when
+ * atk-bridge's atexit handler gets called.
+ */
+ if (aUsedModuleBase == "gtk4" || aUsedModuleBase == "gtk3" ||
+ aUsedModuleBase == "gtk3_kde5" || aUsedModuleBase == "kf5" ||
+ aUsedModuleBase == "kf6" ||
+ aUsedModuleBase == "qt5" || aUsedModuleBase == "qt6" ||
+ aUsedModuleBase == "win")
+ {
+ pCloseModule = nullptr;
+ }
+ }
+ }
+ else
+ {
+ SAL_WARN(
+ "vcl.plugadapt",
+ "could not load symbol create_SalInstance from shared object "
+ << aModule);
+ }
+ }
+ else if (bForce)
+ {
+ SAL_WARN("vcl.plugadapt", "could not load shared object " << aModule);
+ }
+ else
+ {
+ SAL_INFO("vcl.plugadapt", "could not load shared object " << aModule);
+ }
+
+ // coverity[leaked_storage] - this is on purpose
+ return pInst;
+}
+#endif // !STATIC_SAL_INSTANCE
+
+#if UNIX_DESKTOP_DETECT
+#ifndef DISABLE_DYNLOADING
+extern "C" typedef DesktopType Fn_get_desktop_environment();
+#else
+extern "C" DesktopType get_desktop_environment();
+#endif
+
+DesktopType lcl_get_desktop_environment()
+{
+ DesktopType ret = DESKTOP_UNKNOWN;
+#ifdef DISABLE_DYNLOADING
+ ret = get_desktop_environment();
+#else
+ OUString aModule(DESKTOP_DETECTOR_DLL_NAME);
+ oslModule aMod = osl_loadModuleRelative(
+ reinterpret_cast< oslGenericFunction >( &tryInstance ), aModule.pData,
+ SAL_LOADMODULE_DEFAULT );
+ if( aMod )
+ {
+ Fn_get_desktop_environment * pSym
+ = reinterpret_cast<Fn_get_desktop_environment *>(
+ osl_getAsciiFunctionSymbol(aMod, "get_desktop_environment"));
+ if( pSym )
+ ret = pSym();
+ }
+ osl_unloadModule( aMod );
+#endif
+ return ret;
+}
+
+#if !STATIC_SAL_INSTANCE
+const char* const* autodetect_plugin_list()
+{
+ static const char* const pKDEFallbackList[] =
+ {
+#if ENABLE_KF5
+ "kf5",
+#endif
+#if ENABLE_GTK3_KDE5
+ "gtk3_kde5",
+#endif
+#if ENABLE_GTK3
+ "gtk3",
+#endif
+#if ENABLE_GEN
+ "gen",
+#endif
+ nullptr
+ };
+
+ static const char* const pPlasma6FallbackList[] =
+ {
+#if ENABLE_KF6
+ "kf6",
+#endif
+#if ENABLE_KF5
+ "kf5",
+#endif
+#if ENABLE_GTK3_KDE5
+ "gtk3_kde5",
+#endif
+#if ENABLE_GTK3
+ "gtk3",
+#endif
+#if ENABLE_GEN
+ "gen",
+#endif
+ nullptr
+ };
+
+ static const char* const pStandardFallbackList[] =
+ {
+#if ENABLE_GTK3
+ "gtk3",
+#endif
+#if ENABLE_GEN
+ "gen",
+#endif
+ nullptr
+ };
+
+#if ENABLE_HEADLESS
+ static const char* const pHeadlessFallbackList[] =
+ {
+ "svp",
+ nullptr
+ };
+#endif
+
+ DesktopType desktop = lcl_get_desktop_environment();
+ const char * const * pList = pStandardFallbackList;
+
+#if ENABLE_HEADLESS
+ // no server at all: dummy plugin
+ if ( desktop == DESKTOP_NONE )
+ pList = pHeadlessFallbackList;
+ else
+#endif
+ if ( desktop == DESKTOP_GNOME ||
+ desktop == DESKTOP_UNITY ||
+ desktop == DESKTOP_XFCE ||
+ desktop == DESKTOP_MATE )
+ pList = pStandardFallbackList;
+ else if (desktop == DESKTOP_PLASMA5 || desktop == DESKTOP_LXQT)
+ pList = pKDEFallbackList;
+ else if (desktop == DESKTOP_PLASMA6)
+ pList = pPlasma6FallbackList;
+
+ return pList;
+}
+#endif // !STATIC_SAL_INSTANCE
+#endif // UNIX_DESKTOP_DETECT
+
+#endif // HAVE_FEATURE_UI
+
+// HACK to obtain Application::IsHeadlessModeEnabled early on, before
+// Application::EnableHeadlessMode has potentially been called:
+bool IsHeadlessModeRequested()
+{
+ if (Application::IsHeadlessModeEnabled()) {
+ return true;
+ }
+ sal_uInt32 n = rtl_getAppCommandArgCount();
+ for (sal_uInt32 i = 0; i < n; ++i) {
+ OUString arg;
+ rtl_getAppCommandArg(i, &arg.pData);
+ if ( arg == "--headless" || arg == "-headless" ) {
+ return true;
+ }
+ }
+ return false;
+}
+
+} // anonymous namespace
+
+SalInstance *CreateSalInstance()
+{
+ OUString aUsePlugin;
+ rtl::Bootstrap::get("SAL_USE_VCLPLUGIN", aUsePlugin);
+ SAL_INFO_IF(!aUsePlugin.isEmpty(), "vcl.plugadapt", "Requested VCL plugin: " << aUsePlugin);
+
+ if (Application::IsBitmapRendering() || (aUsePlugin.isEmpty() && IsHeadlessModeRequested()))
+ aUsePlugin = "svp";
+
+ if (aUsePlugin == "svp")
+ {
+ Application::EnableBitmapRendering();
+#if ENABLE_HEADLESS
+ return svp_create_SalInstance();
+#else
+ aUsePlugin.clear();
+#endif
+ }
+
+#if STATIC_SAL_INSTANCE
+ return create_SalInstance();
+
+#else // !STATIC_SAL_INSTANCE
+ SalInstance *pInst = nullptr;
+
+ if( !aUsePlugin.isEmpty() )
+ pInst = tryInstance( aUsePlugin, true );
+
+#if UNIX_DESKTOP_DETECT
+ const char* const* pPluginList = pInst ? nullptr : autodetect_plugin_list();
+ for (int i = 0; !pInst && pPluginList[i]; ++i)
+ {
+ pInst = tryInstance(OUString::createFromAscii(pPluginList[i]));
+ SAL_INFO_IF(pInst, "vcl.plugadapt", "plugin autodetection: " << pPluginList[i]);
+ }
+#endif
+
+ // fallback, try everything
+ static const char* const pPlugin[] = {
+#ifdef _WIN32
+ "win",
+#elif defined(MACOSX)
+ "osx",
+#else // !_WIN32 && !MACOSX
+#if ENABLE_GTK3
+ "gtk3",
+#endif
+#if ENABLE_KF5
+ "kf5",
+#endif
+#if ENABLE_GTK3_KDE5
+ "gtk3_kde5",
+#endif
+#if ENABLE_GEN
+ "gen",
+#endif
+#if ENABLE_QT5
+ "qt5",
+#endif
+#if ENABLE_KF6
+ "kf6",
+#endif
+#if ENABLE_QT6
+ "qt6",
+#endif
+#endif // !_WIN32 && !MACOSX
+ nullptr
+ };
+
+ for (int i = 0; !pInst && pPlugin[i]; ++i)
+ pInst = tryInstance( OUString::createFromAscii( pPlugin[ i ] ) );
+
+ if( ! pInst )
+ {
+ std::fprintf( stderr, "no suitable windowing system found, exiting.\n" );
+ _exit( 1 );
+ }
+
+ return pInst;
+#endif // !STATIC_SAL_INSTANCE
+}
+
+void DestroySalInstance( SalInstance *pInst )
+{
+ delete pInst;
+#if !STATIC_SAL_INSTANCE
+ if( pCloseModule )
+ osl_unloadModule( pCloseModule );
+#endif
+}
+
+void SalAbort( const OUString& rErrorText, bool bDumpCore )
+{
+ if (GetSalInstance())
+ GetSalInstance()->BeforeAbort(rErrorText, bDumpCore);
+
+#if defined _WIN32
+ if( rErrorText.isEmpty() )
+ {
+ // make sure crash reporter is triggered
+ RaiseException( 0, EXCEPTION_NONCONTINUABLE, 0, nullptr );
+ FatalAppExitW( 0, L"Application Error" );
+ }
+ else
+ {
+ CrashReporter::addKeyValue("AbortMessage", rErrorText, CrashReporter::Write);
+ // make sure crash reporter is triggered
+ RaiseException( 0, EXCEPTION_NONCONTINUABLE, 0, nullptr );
+ FatalAppExitW( 0, o3tl::toW(rErrorText.getStr()) );
+ }
+#else // !_WIN32
+#if defined ANDROID
+ OUString aError(rErrorText.isEmpty() ? "Unspecified application error" : rErrorText);
+ LOGE("SalAbort: '%s'", OUStringToOString(aError, osl_getThreadTextEncoding()).getStr());
+#elif defined(iOS)
+ NSLog(@"SalAbort: %s", OUStringToOString(rErrorText, osl_getThreadTextEncoding()).getStr());
+#else
+ if( rErrorText.isEmpty() )
+ std::fprintf( stderr, "Unspecified Application Error\n" );
+ else
+ {
+ CrashReporter::addKeyValue("AbortMessage", rErrorText, CrashReporter::Write);
+ std::fprintf( stderr, "%s\n", OUStringToOString(rErrorText, osl_getThreadTextEncoding()).getStr() );
+ }
+#endif
+ if( bDumpCore )
+ abort();
+ else
+ _exit(1);
+#endif // !_WIN32
+}
+
+const OUString& SalGetDesktopEnvironment()
+{
+#if !HAVE_FEATURE_UI
+ static OUString aDesktopEnvironment("headless");
+#elif defined(_WIN32)
+ static OUString aDesktopEnvironment( "Windows" );
+#elif defined(MACOSX)
+ static OUString aDesktopEnvironment( "MacOSX" );
+#elif defined(EMSCRIPTEN)
+ static OUString aDesktopEnvironment("WASM");
+#elif defined(ANDROID)
+ static OUString aDesktopEnvironment("android");
+#elif defined(iOS)
+ static OUString aDesktopEnvironment("iOS");
+#elif UNIX_DESKTOP_DETECT
+ // Order to match desktops.hxx' DesktopType
+ static const char * const desktop_strings[] = {
+ "none", "unknown", "GNOME", "UNITY",
+ "XFCE", "MATE", "PLASMA5", "PLASMA6", "LXQT" };
+ static OUString aDesktopEnvironment;
+ if( aDesktopEnvironment.isEmpty())
+ {
+ aDesktopEnvironment = OUString::createFromAscii(
+ desktop_strings[lcl_get_desktop_environment()]);
+ }
+#else
+ static OUString aDesktopEnvironment("unknown");
+#endif
+ return aDesktopEnvironment;
+}
+
+#ifdef _WIN32
+bool HasAtHook()
+{
+ BOOL bIsRunning = FALSE;
+ // pvParam must be BOOL
+ return SystemParametersInfoW(SPI_GETSCREENREADER, 0, &bIsRunning, 0)
+ && bIsRunning;
+}
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/app/salusereventlist.cxx b/vcl/source/app/salusereventlist.cxx
new file mode 100644
index 0000000000..c677ff56a4
--- /dev/null
+++ b/vcl/source/app/salusereventlist.cxx
@@ -0,0 +1,164 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <salusereventlist.hxx>
+#include <salwtype.hxx>
+
+#include <algorithm>
+#include <cstdlib>
+#include <exception>
+#include <typeinfo>
+
+#include <com/sun/star/uno/Exception.hpp>
+#include <tools/debug.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <sal/log.hxx>
+#include <sal/types.h>
+#include <svdata.hxx>
+
+SalUserEventList::SalUserEventList()
+ : m_bAllUserEventProcessedSignaled( true )
+ , m_aProcessingThread(0)
+{
+}
+
+SalUserEventList::~SalUserEventList() COVERITY_NOEXCEPT_FALSE
+{
+}
+
+void SalUserEventList::insertFrame( SalFrame* pFrame )
+{
+ auto aPair = m_aFrames.insert( pFrame );
+ assert( aPair.second ); (void) aPair;
+}
+
+void SalUserEventList::eraseFrame( SalFrame* pFrame )
+{
+ auto it = m_aFrames.find( pFrame );
+ assert( it != m_aFrames.end() );
+ if ( it != m_aFrames.end() )
+ m_aFrames.erase( it );
+}
+
+bool SalUserEventList::DispatchUserEvents( bool bHandleAllCurrentEvents )
+{
+ bool bWasEvent = false;
+ oslThreadIdentifier aCurId = osl::Thread::getCurrentIdentifier();
+
+ DBG_TESTSOLARMUTEX();
+ std::unique_lock aResettableListGuard(m_aUserEventsMutex);
+
+ if (!m_aUserEvents.empty())
+ {
+ if (bHandleAllCurrentEvents)
+ {
+ if (m_aProcessingUserEvents.empty())
+ m_aProcessingUserEvents.swap(m_aUserEvents);
+ else
+ m_aProcessingUserEvents.splice(m_aProcessingUserEvents.end(), m_aUserEvents);
+ }
+ else if (m_aProcessingUserEvents.empty())
+ {
+ m_aProcessingUserEvents.push_back( m_aUserEvents.front() );
+ m_aUserEvents.pop_front();
+ }
+ }
+
+ if (HasUserEvents_NoLock())
+ {
+ bWasEvent = true;
+ m_aProcessingThread = aCurId;
+
+ SalUserEvent aEvent( nullptr, nullptr, SalEvent::NONE );
+ do {
+ if (m_aProcessingUserEvents.empty() || aCurId != m_aProcessingThread)
+ break;
+ aEvent = m_aProcessingUserEvents.front();
+ m_aProcessingUserEvents.pop_front();
+
+ // remember to reset the guard before break or continue the loop
+ aResettableListGuard.unlock();
+
+ if ( !isFrameAlive( aEvent.m_pFrame ) )
+ {
+ if ( aEvent.m_nEvent == SalEvent::UserEvent )
+ delete static_cast< ImplSVEvent* >( aEvent.m_pData );
+ aResettableListGuard.lock();
+ continue;
+ }
+
+ /*
+ * Current policy is that scheduler tasks aren't allowed to throw an exception.
+ * Because otherwise the exception is caught somewhere totally unrelated.
+ * TODO Ideally we could capture a proper backtrace and feed this into breakpad,
+ * which is do-able, but requires writing some assembly.
+ * See also Scheduler::CallbackTaskScheduling
+ */
+#ifdef IOS
+ ProcessEvent( aEvent );
+#else
+ // the noexcept here means that (a) we abort and (b) debuggers will
+ // likely trigger at the throw site instead of here, making the debugging
+ // experience better when something goes wrong.
+ auto process = [&aEvent, this] () noexcept { ProcessEvent(aEvent); };
+ process();
+#endif
+ aResettableListGuard.lock();
+ if (!bHandleAllCurrentEvents)
+ break;
+ }
+ while( true );
+ }
+
+ if ( !m_bAllUserEventProcessedSignaled && !HasUserEvents_NoLock() )
+ {
+ m_bAllUserEventProcessedSignaled = true;
+ TriggerAllUserEventsProcessed();
+ }
+
+ return bWasEvent;
+}
+
+void SalUserEventList::RemoveEvent( SalFrame* pFrame, void* pData, SalEvent nEvent )
+{
+ SalUserEvent aEvent( pFrame, pData, nEvent );
+
+ std::unique_lock aGuard( m_aUserEventsMutex );
+ auto it = std::find( m_aUserEvents.begin(), m_aUserEvents.end(), aEvent );
+ if ( it != m_aUserEvents.end() )
+ {
+ m_aUserEvents.erase( it );
+ }
+ else
+ {
+ it = std::find( m_aProcessingUserEvents.begin(), m_aProcessingUserEvents.end(), aEvent );
+ if ( it != m_aProcessingUserEvents.end() )
+ {
+ m_aProcessingUserEvents.erase( it );
+ }
+ }
+
+ if ( !m_bAllUserEventProcessedSignaled && !HasUserEvents_NoLock() )
+ {
+ m_bAllUserEventProcessedSignaled = true;
+ TriggerAllUserEventsProcessed();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx
new file mode 100644
index 0000000000..95beb907f6
--- /dev/null
+++ b/vcl/source/app/salvtables.cxx
@@ -0,0 +1,7618 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <limits>
+#include <string_view>
+
+#include <com/sun/star/accessibility/AccessibleRelationType.hpp>
+#include <com/sun/star/awt/XWindow.hpp>
+#include <com/sun/star/awt/XVclWindowPeer.hpp>
+#include <o3tl/safeint.hxx>
+#include <o3tl/sorted_vector.hxx>
+#include <o3tl/string_view.hxx>
+#include <officecfg/Office/Common.hxx>
+#include <salframe.hxx>
+#include <salinst.hxx>
+#include <salvd.hxx>
+#include <salprn.hxx>
+#include <saltimer.hxx>
+#include <salsession.hxx>
+#include <salsys.hxx>
+#include <salbmp.hxx>
+#include <salobj.hxx>
+#include <salmenu.hxx>
+#include <strings.hrc>
+#include <svdata.hxx>
+#include <svimpbox.hxx>
+#include <messagedialog.hxx>
+#include <treeglue.hxx>
+#include <unotools/accessiblerelationsethelper.hxx>
+#include <unotools/configmgr.hxx>
+#include <utility>
+#include <tools/helpers.hxx>
+#include <vcl/abstdlg.hxx>
+#include <vcl/builder.hxx>
+#include <vcl/toolkit/combobox.hxx>
+#include <vcl/toolkit/dialog.hxx>
+#include <vcl/toolkit/fixed.hxx>
+#include <vcl/toolkit/fmtfield.hxx>
+#include <vcl/headbar.hxx>
+#include <vcl/toolkit/ivctrl.hxx>
+#include <vcl/layout.hxx>
+#include <vcl/toolkit/menubtn.hxx>
+#include <vcl/toolkit/prgsbar.hxx>
+#include <vcl/ptrstyle.hxx>
+#include <slider.hxx>
+#include <vcl/sysdata.hxx>
+#include <vcl/toolkit/svlbitm.hxx>
+#include <vcl/toolkit/svtabbx.hxx>
+#include <vcl/tabctrl.hxx>
+#include <vcl/tabpage.hxx>
+#include <vcl/toolbox.hxx>
+#include <vcl/toolkit/treelistentry.hxx>
+#include <vcl/toolkit/throbber.hxx>
+#include <vcl/toolkit/unowrap.hxx>
+#include <vcl/weld.hxx>
+#include <vcl/weldutils.hxx>
+#include <vcl/toolkit/vclmedit.hxx>
+#include <vcl/toolkit/viewdataentry.hxx>
+#include <vcl/virdev.hxx>
+#include <bitmaps.hlst>
+#include <listbox.hxx>
+#include <menutogglebutton.hxx>
+#include <window.h>
+#include <wizdlg.hxx>
+#include <salvtables.hxx>
+#include <comphelper/lok.hxx>
+
+SalFrame::SalFrame()
+ : m_pWindow(nullptr)
+ , m_pProc(nullptr)
+{
+}
+
+// this file contains the virtual destructors of the sal interface
+// compilers usually put their vtables where the destructor is
+
+SalFrame::~SalFrame() {}
+
+void SalFrame::SetCallback(vcl::Window* pWindow, SALFRAMEPROC pProc)
+{
+ m_pWindow = pWindow;
+ m_pProc = pProc;
+}
+
+// default to full-frame flushes
+// on ports where partial-flushes are much cheaper this method should be overridden
+void SalFrame::Flush(const tools::Rectangle&) { Flush(); }
+
+void SalFrame::SetRepresentedURL(const OUString&)
+{
+ // currently this is Mac only functionality
+}
+
+OUString SalFrame::DumpSetPosSize(tools::Long nX, tools::Long nY, tools::Long nWidth,
+ tools::Long nHeight, sal_uInt16 nFlags)
+{
+ // assuming the 4 integers normally don't have more than 4 digits, but might be negative
+ OUStringBuffer aBuffer(4 * 5 + 5);
+ if (nFlags & SAL_FRAME_POSSIZE_WIDTH)
+ aBuffer << nWidth << "x";
+ else
+ aBuffer << "?x";
+ if (nFlags & SAL_FRAME_POSSIZE_HEIGHT)
+ aBuffer << nHeight << "@(";
+ else
+ aBuffer << "?@(";
+ if (nFlags & SAL_FRAME_POSSIZE_X)
+ aBuffer << nX << ",";
+ else
+ aBuffer << "?,";
+ if (nFlags & SAL_FRAME_POSSIZE_Y)
+ aBuffer << nY << ")";
+ else
+ aBuffer << "?)";
+ return aBuffer.makeStringAndClear();
+}
+
+SalInstance::SalInstance(std::unique_ptr<comphelper::SolarMutex> pMutex)
+ : m_pYieldMutex(std::move(pMutex))
+{
+}
+
+SalInstance::~SalInstance() {}
+
+comphelper::SolarMutex* SalInstance::GetYieldMutex() { return m_pYieldMutex.get(); }
+
+sal_uInt32 SalInstance::ReleaseYieldMutexAll() { return m_pYieldMutex->release(true); }
+
+void SalInstance::AcquireYieldMutex(sal_uInt32 nCount) { m_pYieldMutex->acquire(nCount); }
+
+std::unique_ptr<SalSession> SalInstance::CreateSalSession() { return nullptr; }
+
+OpenGLContext* SalInstance::CreateOpenGLContext()
+{
+ assert(!m_bSupportsOpenGL);
+ std::abort();
+}
+
+std::unique_ptr<SalMenu> SalInstance::CreateMenu(bool, Menu*)
+{
+ // default: no native menus
+ return nullptr;
+}
+
+std::unique_ptr<SalMenuItem> SalInstance::CreateMenuItem(const SalItemParams&) { return nullptr; }
+
+bool SalInstance::CallEventCallback(void const* pEvent, int nBytes)
+{
+ return m_pEventInst.is() && m_pEventInst->dispatchEvent(pEvent, nBytes);
+}
+
+bool SalInstance::DoExecute(int&)
+{
+ // can't run on system event loop without implementing DoExecute and DoQuit
+ if (Application::IsOnSystemEventLoop())
+ std::abort();
+ return false;
+}
+
+void SalInstance::DoQuit()
+{
+ if (Application::IsOnSystemEventLoop())
+ std::abort();
+}
+
+SalTimer::~SalTimer() COVERITY_NOEXCEPT_FALSE {}
+
+void SalBitmap::DropScaledCache()
+{
+ if (ImplSVData* pSVData = ImplGetSVData())
+ {
+ auto& rCache = pSVData->maGDIData.maScaleCache;
+
+ rCache.remove_if([this](const lru_scale_cache::key_value_pair_t& rKeyValuePair) {
+ return rKeyValuePair.first.mpBitmap == this;
+ });
+ }
+}
+
+SalBitmap::~SalBitmap() { DropScaledCache(); }
+
+SalSystem::~SalSystem() {}
+
+SalPrinter::~SalPrinter() {}
+
+bool SalPrinter::StartJob(const OUString*, const OUString&, const OUString&, ImplJobSetup*,
+ vcl::PrinterController&)
+{
+ return false;
+}
+
+SalInfoPrinter::~SalInfoPrinter() {}
+
+SalVirtualDevice::~SalVirtualDevice() {}
+
+SalObject::~SalObject() {}
+
+SalMenu::~SalMenu() {}
+
+bool SalMenu::ShowNativePopupMenu(FloatingWindow*, const tools::Rectangle&, FloatWinPopupFlags)
+{
+ return false;
+}
+
+void SalMenu::ShowCloseButton(bool) {}
+
+bool SalMenu::AddMenuBarButton(const SalMenuButtonItem&) { return false; }
+
+void SalMenu::RemoveMenuBarButton(sal_uInt16) {}
+
+tools::Rectangle SalMenu::GetMenuBarButtonRectPixel(sal_uInt16, SalFrame*)
+{
+ return tools::Rectangle();
+}
+
+int SalMenu::GetMenuBarHeight() const { return 0; }
+
+void SalMenu::ApplyPersona() {}
+
+SalMenuItem::~SalMenuItem() {}
+
+class SalFlashAttention
+{
+private:
+ VclPtr<vcl::Window> m_xWidget;
+ Timer m_aFlashTimer;
+ Color m_aOrigControlBackground;
+ Wallpaper m_aOrigBackground;
+ bool m_bOrigControlBackground;
+ int m_nFlashCount;
+
+ void SetFlash()
+ {
+ Color aColor(Application::GetSettings().GetStyleSettings().GetHighlightColor());
+ m_xWidget->SetControlBackground(aColor);
+ }
+
+ void ClearFlash()
+ {
+ if (m_bOrigControlBackground)
+ m_xWidget->SetControlBackground(m_aOrigControlBackground);
+ else
+ m_xWidget->SetControlBackground();
+ }
+
+ void Flash()
+ {
+ constexpr int FlashesWanted = 1;
+
+ if (m_nFlashCount % 2 == 0)
+ ClearFlash();
+ else
+ SetFlash();
+
+ if (m_nFlashCount == FlashesWanted * 2)
+ return;
+
+ ++m_nFlashCount;
+
+ m_aFlashTimer.Start();
+ }
+
+ DECL_LINK(FlashTimeout, Timer*, void);
+
+public:
+ SalFlashAttention(VclPtr<vcl::Window> xWidget)
+ : m_xWidget(std::move(xWidget))
+ , m_aFlashTimer("SalFlashAttention")
+ , m_bOrigControlBackground(false)
+ , m_nFlashCount(1)
+ {
+ m_aFlashTimer.SetTimeout(150);
+ m_aFlashTimer.SetInvokeHandler(LINK(this, SalFlashAttention, FlashTimeout));
+ }
+
+ void Start()
+ {
+ m_bOrigControlBackground = m_xWidget->IsControlBackground();
+ if (m_bOrigControlBackground)
+ m_aOrigControlBackground = m_xWidget->GetControlBackground();
+ m_aFlashTimer.Start();
+ }
+
+ ~SalFlashAttention() { ClearFlash(); }
+};
+
+IMPL_LINK_NOARG(SalFlashAttention, FlashTimeout, Timer*, void) { Flash(); }
+
+void SalInstanceWidget::ensure_event_listener()
+{
+ if (!m_bEventListener)
+ {
+ m_xWidget->AddEventListener(LINK(this, SalInstanceWidget, EventListener));
+ m_bEventListener = true;
+ }
+}
+
+// we want the ability to mark key events as handled, so use this variant
+// for those, we get all keystrokes in this case, so we will need to filter
+// them later
+void SalInstanceWidget::ensure_key_listener()
+{
+ if (!m_bKeyEventListener)
+ {
+ Application::AddKeyListener(LINK(this, SalInstanceWidget, KeyEventListener));
+ m_bKeyEventListener = true;
+ }
+}
+
+// we want the ability to know about mouse events that happen in our children
+// so use this variant, we will need to filter them later
+void SalInstanceWidget::ensure_mouse_listener()
+{
+ if (!m_bMouseEventListener)
+ {
+ m_xWidget->AddChildEventListener(LINK(this, SalInstanceWidget, MouseEventListener));
+ m_bMouseEventListener = true;
+ }
+}
+
+void SalInstanceWidget::set_background(const Color& rColor)
+{
+ m_xWidget->SetControlBackground(rColor);
+ m_xWidget->SetBackground(m_xWidget->GetControlBackground());
+ if (m_xWidget->GetStyle() & WB_CLIPCHILDREN)
+ {
+ // turn off WB_CLIPCHILDREN otherwise the bg won't extend "under"
+ // transparent children of the widget e.g. expander in sidebar panel header
+ m_xWidget->SetStyle(m_xWidget->GetStyle() & ~WB_CLIPCHILDREN);
+ // and toggle mbClipChildren on instead otherwise the bg won't fill e.g.
+ // deck titlebar header when its width is stretched
+ WindowImpl* pImpl = m_xWidget->ImplGetWindowImpl();
+ pImpl->mbClipChildren = true;
+ }
+}
+
+SalInstanceWidget::SalInstanceWidget(vcl::Window* pWidget, SalInstanceBuilder* pBuilder,
+ bool bTakeOwnership)
+ : m_xWidget(pWidget)
+ , m_pBuilder(pBuilder)
+ , m_bTakeOwnership(bTakeOwnership)
+ , m_bEventListener(false)
+ , m_bKeyEventListener(false)
+ , m_bMouseEventListener(false)
+ , m_nBlockNotify(0)
+ , m_nFreezeCount(0)
+{
+}
+
+void SalInstanceWidget::set_sensitive(bool sensitive) { m_xWidget->Enable(sensitive); }
+
+bool SalInstanceWidget::get_sensitive() const { return m_xWidget->IsEnabled(); }
+
+bool SalInstanceWidget::get_visible() const { return m_xWidget->IsVisible(); }
+
+bool SalInstanceWidget::is_visible() const { return m_xWidget->IsReallyVisible(); }
+
+void SalInstanceWidget::set_can_focus(bool bCanFocus)
+{
+ auto nStyle = m_xWidget->GetStyle() & ~(WB_TABSTOP | WB_NOTABSTOP);
+ if (bCanFocus)
+ nStyle |= WB_TABSTOP;
+ else
+ nStyle |= WB_NOTABSTOP;
+ m_xWidget->SetStyle(nStyle);
+}
+
+void SalInstanceWidget::grab_focus()
+{
+ if (has_focus())
+ return;
+ m_xWidget->GrabFocus();
+}
+
+bool SalInstanceWidget::has_focus() const { return m_xWidget->HasFocus(); }
+
+bool SalInstanceWidget::is_active() const { return m_xWidget->IsActive(); }
+
+bool SalInstanceWidget::has_child_focus() const { return m_xWidget->HasChildPathFocus(true); }
+
+void SalInstanceWidget::show() { m_xWidget->Show(); }
+
+void SalInstanceWidget::hide() { m_xWidget->Hide(); }
+
+void SalInstanceWidget::set_size_request(int nWidth, int nHeight)
+{
+ m_xWidget->set_width_request(nWidth);
+ m_xWidget->set_height_request(nHeight);
+}
+
+Size SalInstanceWidget::get_size_request() const
+{
+ return Size(m_xWidget->get_width_request(), m_xWidget->get_height_request());
+}
+
+Size SalInstanceWidget::get_preferred_size() const { return m_xWidget->get_preferred_size(); }
+
+float SalInstanceWidget::get_approximate_digit_width() const
+{
+ return m_xWidget->approximate_digit_width();
+}
+
+int SalInstanceWidget::get_text_height() const { return m_xWidget->GetTextHeight(); }
+
+Size SalInstanceWidget::get_pixel_size(const OUString& rText) const
+{
+ //TODO, or do I want GetTextBoundRect ?, just using width at the moment anyway
+ return Size(m_xWidget->GetTextWidth(rText), m_xWidget->GetTextHeight());
+}
+
+vcl::Font SalInstanceWidget::get_font() { return m_xWidget->GetPointFont(*m_xWidget->GetOutDev()); }
+
+OUString SalInstanceWidget::get_buildable_name() const { return m_xWidget->get_id(); }
+
+void SalInstanceWidget::set_buildable_name(const OUString& rId) { return m_xWidget->set_id(rId); }
+
+void SalInstanceWidget::set_help_id(const OUString& rId) { return m_xWidget->SetHelpId(rId); }
+
+OUString SalInstanceWidget::get_help_id() const { return m_xWidget->GetHelpId(); }
+
+void SalInstanceWidget::set_grid_left_attach(int nAttach)
+{
+ m_xWidget->set_grid_left_attach(nAttach);
+}
+
+int SalInstanceWidget::get_grid_left_attach() const { return m_xWidget->get_grid_left_attach(); }
+
+void SalInstanceWidget::set_grid_width(int nCols) { m_xWidget->set_grid_width(nCols); }
+
+void SalInstanceWidget::set_grid_top_attach(int nAttach)
+{
+ m_xWidget->set_grid_top_attach(nAttach);
+}
+
+int SalInstanceWidget::get_grid_top_attach() const { return m_xWidget->get_grid_top_attach(); }
+
+void SalInstanceWidget::set_hexpand(bool bExpand) { m_xWidget->set_hexpand(bExpand); }
+
+bool SalInstanceWidget::get_hexpand() const { return m_xWidget->get_hexpand(); }
+
+void SalInstanceWidget::set_vexpand(bool bExpand) { m_xWidget->set_vexpand(bExpand); }
+
+bool SalInstanceWidget::get_vexpand() const { return m_xWidget->get_vexpand(); }
+
+void SalInstanceWidget::set_margin_top(int nMargin) { m_xWidget->set_margin_top(nMargin); }
+
+void SalInstanceWidget::set_margin_bottom(int nMargin) { m_xWidget->set_margin_bottom(nMargin); }
+
+void SalInstanceWidget::set_margin_start(int nMargin) { m_xWidget->set_margin_start(nMargin); }
+
+void SalInstanceWidget::set_margin_end(int nMargin) { m_xWidget->set_margin_end(nMargin); }
+
+int SalInstanceWidget::get_margin_top() const { return m_xWidget->get_margin_top(); }
+
+int SalInstanceWidget::get_margin_bottom() const { return m_xWidget->get_margin_bottom(); }
+
+int SalInstanceWidget::get_margin_start() const { return m_xWidget->get_margin_start(); }
+
+int SalInstanceWidget::get_margin_end() const { return m_xWidget->get_margin_end(); }
+
+void SalInstanceWidget::set_accessible_name(const OUString& rName)
+{
+ m_xWidget->SetAccessibleName(rName);
+}
+
+void SalInstanceWidget::set_accessible_description(const OUString& rDescription)
+{
+ m_xWidget->SetAccessibleDescription(rDescription);
+}
+
+OUString SalInstanceWidget::get_accessible_name() const { return m_xWidget->GetAccessibleName(); }
+
+OUString SalInstanceWidget::get_accessible_description() const
+{
+ return m_xWidget->GetAccessibleDescription();
+}
+
+void SalInstanceWidget::set_accessible_relation_labeled_by(weld::Widget* pLabel)
+{
+ if (vcl::Window* pOldLabel = m_xWidget->GetAccessibleRelationLabeledBy())
+ pOldLabel->SetAccessibleRelationLabelFor(nullptr);
+ vcl::Window* pA11yLabel
+ = pLabel ? dynamic_cast<SalInstanceWidget&>(*pLabel).getWidget() : nullptr;
+ m_xWidget->SetAccessibleRelationLabeledBy(pA11yLabel);
+ if (pA11yLabel)
+ pA11yLabel->SetAccessibleRelationLabelFor(m_xWidget);
+}
+
+void SalInstanceWidget::set_tooltip_text(const OUString& rTip)
+{
+ m_xWidget->SetQuickHelpText(rTip);
+}
+
+OUString SalInstanceWidget::get_tooltip_text() const { return m_xWidget->GetQuickHelpText(); }
+
+void SalInstanceWidget::set_cursor_data(void* pData)
+{
+ vcl::Cursor* pCursor = static_cast<vcl::Cursor*>(pData);
+ if (!pCursor)
+ return;
+
+ m_xWidget->SetCursor(pCursor);
+}
+
+void SalInstanceWidget::connect_focus_in(const Link<Widget&, void>& rLink)
+{
+ ensure_event_listener();
+ weld::Widget::connect_focus_in(rLink);
+}
+
+void SalInstanceWidget::connect_mnemonic_activate(const Link<Widget&, bool>& rLink)
+{
+ m_xWidget->SetMnemonicActivateHdl(LINK(this, SalInstanceWidget, MnemonicActivateHdl));
+ weld::Widget::connect_mnemonic_activate(rLink);
+}
+
+void SalInstanceWidget::connect_focus_out(const Link<Widget&, void>& rLink)
+{
+ ensure_event_listener();
+ weld::Widget::connect_focus_out(rLink);
+}
+
+void SalInstanceWidget::connect_size_allocate(const Link<const Size&, void>& rLink)
+{
+ ensure_event_listener();
+ weld::Widget::connect_size_allocate(rLink);
+}
+
+void SalInstanceWidget::connect_mouse_press(const Link<const MouseEvent&, bool>& rLink)
+{
+ ensure_mouse_listener();
+ weld::Widget::connect_mouse_press(rLink);
+}
+
+void SalInstanceWidget::connect_mouse_move(const Link<const MouseEvent&, bool>& rLink)
+{
+ ensure_mouse_listener();
+ weld::Widget::connect_mouse_move(rLink);
+}
+
+void SalInstanceWidget::connect_mouse_release(const Link<const MouseEvent&, bool>& rLink)
+{
+ ensure_mouse_listener();
+ weld::Widget::connect_mouse_release(rLink);
+}
+
+void SalInstanceWidget::connect_key_press(const Link<const KeyEvent&, bool>& rLink)
+{
+ ensure_key_listener();
+ weld::Widget::connect_key_press(rLink);
+}
+
+void SalInstanceWidget::connect_key_release(const Link<const KeyEvent&, bool>& rLink)
+{
+ ensure_key_listener();
+ weld::Widget::connect_key_release(rLink);
+}
+
+IMPL_LINK(SalInstanceWidget, SettingsChangedHdl, VclWindowEvent&, rEvent, void)
+{
+ if (rEvent.GetId() != VclEventId::WindowDataChanged)
+ return;
+
+ DataChangedEvent* pData = static_cast<DataChangedEvent*>(rEvent.GetData());
+ if (pData->GetType() == DataChangedEventType::SETTINGS)
+ m_aStyleUpdatedHdl.Call(*this);
+}
+
+void SalInstanceWidget::connect_style_updated(const Link<Widget&, void>& rLink)
+{
+ if (m_aStyleUpdatedHdl.IsSet())
+ m_xWidget->RemoveEventListener(LINK(this, SalInstanceWidget, SettingsChangedHdl));
+ weld::Widget::connect_style_updated(rLink);
+ if (m_aStyleUpdatedHdl.IsSet())
+ m_xWidget->AddEventListener(LINK(this, SalInstanceWidget, SettingsChangedHdl));
+}
+
+bool SalInstanceWidget::get_extents_relative_to(const Widget& rRelative, int& x, int& y, int& width,
+ int& height) const
+{
+ tools::Rectangle aRect(m_xWidget->GetWindowExtentsRelative(
+ *dynamic_cast<const SalInstanceWidget&>(rRelative).getWidget()));
+ x = aRect.Left();
+ y = aRect.Top();
+ width = aRect.GetWidth();
+ height = aRect.GetHeight();
+ return true;
+}
+
+void SalInstanceWidget::grab_add() { m_xWidget->CaptureMouse(); }
+
+bool SalInstanceWidget::has_grab() const { return m_xWidget->IsMouseCaptured(); }
+
+void SalInstanceWidget::grab_remove() { m_xWidget->ReleaseMouse(); }
+
+bool SalInstanceWidget::get_direction() const { return m_xWidget->IsRTLEnabled(); }
+
+void SalInstanceWidget::set_direction(bool bRTL) { m_xWidget->EnableRTL(bRTL); }
+
+void SalInstanceWidget::freeze()
+{
+ if (m_nFreezeCount == 0)
+ m_xWidget->SetUpdateMode(false);
+ ++m_nFreezeCount;
+}
+
+void SalInstanceWidget::thaw()
+{
+ --m_nFreezeCount;
+ if (m_nFreezeCount == 0)
+ m_xWidget->SetUpdateMode(true);
+}
+
+void SalInstanceWidget::set_busy_cursor(bool bBusy)
+{
+ if (!m_xWidget)
+ {
+ return;
+ }
+
+ if (bBusy)
+ m_xWidget->EnterWait();
+ else
+ m_xWidget->LeaveWait();
+}
+
+void SalInstanceWidget::queue_resize() { m_xWidget->queue_resize(); }
+
+SalInstanceWidget::~SalInstanceWidget()
+{
+ if (m_aStyleUpdatedHdl.IsSet())
+ m_xWidget->RemoveEventListener(LINK(this, SalInstanceWidget, SettingsChangedHdl));
+ if (m_aMnemonicActivateHdl.IsSet())
+ m_xWidget->SetMnemonicActivateHdl(Link<vcl::Window&, bool>());
+ if (m_bMouseEventListener)
+ m_xWidget->RemoveChildEventListener(LINK(this, SalInstanceWidget, MouseEventListener));
+ if (m_bKeyEventListener)
+ Application::RemoveKeyListener(LINK(this, SalInstanceWidget, KeyEventListener));
+ if (m_bEventListener)
+ m_xWidget->RemoveEventListener(LINK(this, SalInstanceWidget, EventListener));
+ if (m_bTakeOwnership)
+ m_xWidget.disposeAndClear();
+}
+
+vcl::Window* SalInstanceWidget::getWidget() const { return m_xWidget; }
+
+void SalInstanceWidget::disable_notify_events() { ++m_nBlockNotify; }
+
+bool SalInstanceWidget::notify_events_disabled() const { return m_nBlockNotify != 0; }
+
+void SalInstanceWidget::enable_notify_events() { --m_nBlockNotify; }
+
+OUString SalInstanceWidget::strip_mnemonic(const OUString& rLabel) const
+{
+ return rLabel.replaceFirst("~", "");
+}
+
+VclPtr<VirtualDevice> SalInstanceWidget::create_virtual_device() const
+{
+ // create with (annoying) separate alpha layer that LibreOffice itself uses
+ return VclPtr<VirtualDevice>::Create(*Application::GetDefaultDevice(),
+ DeviceFormat::WITH_ALPHA);
+}
+
+void SalInstanceWidget::call_attention_to()
+{
+ m_xFlashAttention.reset(new SalFlashAttention(m_xWidget));
+ m_xFlashAttention->Start();
+}
+
+css::uno::Reference<css::datatransfer::dnd::XDropTarget> SalInstanceWidget::get_drop_target()
+{
+ return m_xWidget->GetDropTarget();
+}
+
+css::uno::Reference<css::datatransfer::clipboard::XClipboard>
+SalInstanceWidget::get_clipboard() const
+{
+ return m_xWidget->GetClipboard();
+}
+
+void SalInstanceWidget::connect_get_property_tree(const Link<tools::JsonWriter&, void>& rLink)
+{
+ m_xWidget->SetDumpAsPropertyTreeHdl(rLink);
+}
+
+void SalInstanceWidget::get_property_tree(tools::JsonWriter& rJsonWriter)
+{
+ m_xWidget->DumpAsPropertyTree(rJsonWriter);
+}
+
+void SalInstanceWidget::set_stack_background()
+{
+ set_background(m_xWidget->GetSettings().GetStyleSettings().GetWindowColor());
+}
+
+void SalInstanceWidget::set_title_background()
+{
+ set_background(m_xWidget->GetSettings().GetStyleSettings().GetShadowColor());
+}
+
+void SalInstanceWidget::set_toolbar_background()
+{
+ m_xWidget->SetBackground();
+ m_xWidget->SetPaintTransparent(true);
+}
+
+void SalInstanceWidget::set_highlight_background()
+{
+ set_background(m_xWidget->GetSettings().GetStyleSettings().GetHighlightColor());
+}
+
+SystemWindow* SalInstanceWidget::getSystemWindow() { return m_xWidget->GetSystemWindow(); }
+
+void SalInstanceWidget::HandleEventListener(VclWindowEvent& rEvent)
+{
+ if (rEvent.GetId() == VclEventId::WindowGetFocus)
+ m_aFocusInHdl.Call(*this);
+ else if (rEvent.GetId() == VclEventId::WindowLoseFocus)
+ m_aFocusOutHdl.Call(*this);
+ else if (rEvent.GetId() == VclEventId::WindowResize)
+ m_aSizeAllocateHdl.Call(m_xWidget->GetSizePixel());
+}
+
+namespace
+{
+MouseEvent TransformEvent(const MouseEvent& rEvent, const vcl::Window* pParent,
+ const vcl::Window* pChild)
+{
+ return MouseEvent(
+ pParent->ScreenToOutputPixel(pChild->OutputToScreenPixel(rEvent.GetPosPixel())),
+ rEvent.GetClicks(), rEvent.GetMode(), rEvent.GetButtons(), rEvent.GetModifier());
+}
+}
+
+void SalInstanceWidget::HandleMouseEventListener(VclWindowEvent& rWinEvent)
+{
+ if (rWinEvent.GetId() == VclEventId::WindowMouseButtonDown)
+ {
+ if (m_xWidget == rWinEvent.GetWindow())
+ {
+ const MouseEvent* pMouseEvent = static_cast<const MouseEvent*>(rWinEvent.GetData());
+ m_aMousePressHdl.Call(*pMouseEvent);
+ }
+ else if (m_xWidget->ImplIsChild(rWinEvent.GetWindow()))
+ {
+ const MouseEvent* pMouseEvent = static_cast<const MouseEvent*>(rWinEvent.GetData());
+ const MouseEvent aTransformedEvent(
+ TransformEvent(*pMouseEvent, m_xWidget, rWinEvent.GetWindow()));
+ m_aMousePressHdl.Call(aTransformedEvent);
+ }
+ }
+ else if (rWinEvent.GetId() == VclEventId::WindowMouseButtonUp)
+ {
+ if (m_xWidget == rWinEvent.GetWindow())
+ {
+ const MouseEvent* pMouseEvent = static_cast<const MouseEvent*>(rWinEvent.GetData());
+ m_aMouseReleaseHdl.Call(*pMouseEvent);
+ }
+ else if (m_xWidget->ImplIsChild(rWinEvent.GetWindow()))
+ {
+ const MouseEvent* pMouseEvent = static_cast<const MouseEvent*>(rWinEvent.GetData());
+ const MouseEvent aTransformedEvent(
+ TransformEvent(*pMouseEvent, m_xWidget, rWinEvent.GetWindow()));
+ m_aMouseReleaseHdl.Call(aTransformedEvent);
+ }
+ }
+ else if (rWinEvent.GetId() == VclEventId::WindowMouseMove)
+ {
+ if (m_xWidget == rWinEvent.GetWindow())
+ {
+ const MouseEvent* pMouseEvent = static_cast<const MouseEvent*>(rWinEvent.GetData());
+ m_aMouseMotionHdl.Call(*pMouseEvent);
+ }
+ else if (m_xWidget->ImplIsChild(rWinEvent.GetWindow()))
+ {
+ const MouseEvent* pMouseEvent = static_cast<const MouseEvent*>(rWinEvent.GetData());
+ const MouseEvent aTransformedEvent(
+ TransformEvent(*pMouseEvent, m_xWidget, rWinEvent.GetWindow()));
+ m_aMouseMotionHdl.Call(aTransformedEvent);
+ }
+ }
+}
+
+bool SalInstanceWidget::HandleKeyEventListener(VclWindowEvent& rEvent)
+{
+ // we get all key events here, ignore them unless we have focus
+ if (!m_xWidget->HasChildPathFocus())
+ return false;
+ if (rEvent.GetId() == VclEventId::WindowKeyInput)
+ {
+ const KeyEvent* pKeyEvent = static_cast<const KeyEvent*>(rEvent.GetData());
+ return m_aKeyPressHdl.Call(*pKeyEvent);
+ }
+ else if (rEvent.GetId() == VclEventId::WindowKeyUp)
+ {
+ const KeyEvent* pKeyEvent = static_cast<const KeyEvent*>(rEvent.GetData());
+ return m_aKeyReleaseHdl.Call(*pKeyEvent);
+ }
+ return false;
+}
+
+IMPL_LINK(SalInstanceWidget, EventListener, VclWindowEvent&, rEvent, void)
+{
+ HandleEventListener(rEvent);
+}
+
+IMPL_LINK(SalInstanceWidget, KeyEventListener, VclWindowEvent&, rEvent, bool)
+{
+ return HandleKeyEventListener(rEvent);
+}
+
+IMPL_LINK(SalInstanceWidget, MouseEventListener, VclWindowEvent&, rEvent, void)
+{
+ HandleMouseEventListener(rEvent);
+}
+
+IMPL_LINK_NOARG(SalInstanceWidget, MnemonicActivateHdl, vcl::Window&, bool)
+{
+ return m_aMnemonicActivateHdl.Call(*this);
+}
+
+namespace
+{
+Image createImage(const OUString& rImage)
+{
+ if (rImage.isEmpty())
+ return Image();
+ if (rImage.lastIndexOf('.') != rImage.getLength() - 4)
+ {
+ assert((rImage == "dialog-warning" || rImage == "dialog-error"
+ || rImage == "dialog-information")
+ && "unknown stock image");
+ if (rImage == "dialog-warning")
+ return Image(StockImage::Yes, IMG_WARN);
+ else if (rImage == "dialog-error")
+ return Image(StockImage::Yes, IMG_ERROR);
+ else if (rImage == "dialog-information")
+ return Image(StockImage::Yes, IMG_INFO);
+ }
+ return Image(StockImage::Yes, rImage);
+}
+
+Image createImage(const VirtualDevice& rDevice)
+{
+ return Image(rDevice.GetBitmapEx(Point(), rDevice.GetOutputSizePixel()));
+}
+
+sal_uInt16 insert_to_menu(sal_uInt16 nLastId, PopupMenu* pMenu, int pos, const OUString& rId,
+ const OUString& rStr, const OUString* pIconName,
+ const VirtualDevice* pImageSurface,
+ const css::uno::Reference<css::graphic::XGraphic>& rImage,
+ TriState eCheckRadioFalse)
+{
+ const sal_uInt16 nNewid = nLastId + 1;
+
+ MenuItemBits nBits;
+ if (eCheckRadioFalse == TRISTATE_TRUE)
+ nBits = MenuItemBits::CHECKABLE;
+ else if (eCheckRadioFalse == TRISTATE_FALSE)
+ nBits = MenuItemBits::CHECKABLE | MenuItemBits::RADIOCHECK;
+ else
+ nBits = MenuItemBits::NONE;
+
+ pMenu->InsertItem(nNewid, rStr, nBits, rId, pos == -1 ? MENU_APPEND : pos);
+ if (pIconName)
+ {
+ pMenu->SetItemImage(nNewid, createImage(*pIconName));
+ }
+ else if (pImageSurface)
+ {
+ pMenu->SetItemImage(nNewid, createImage(*pImageSurface));
+ }
+ else if (rImage)
+ {
+ pMenu->SetItemImage(nNewid, Image(rImage));
+ }
+ return nNewid;
+}
+}
+
+SalInstanceMenu::SalInstanceMenu(PopupMenu* pMenu, bool bTakeOwnership)
+ : m_xMenu(pMenu)
+ , m_bTakeOwnership(bTakeOwnership)
+{
+ const auto nCount = m_xMenu->GetItemCount();
+ m_nLastId = nCount ? pMenu->GetItemId(nCount - 1) : 0;
+ m_xMenu->SetSelectHdl(LINK(this, SalInstanceMenu, SelectMenuHdl));
+}
+OUString SalInstanceMenu::popup_at_rect(weld::Widget* pParent, const tools::Rectangle& rRect,
+ weld::Placement ePlace)
+{
+ SalInstanceWidget* pVclWidget = dynamic_cast<SalInstanceWidget*>(pParent);
+ assert(pVclWidget);
+ PopupMenuFlags eFlags = PopupMenuFlags::NoMouseUpClose;
+ if (ePlace == weld::Placement::Under)
+ eFlags = eFlags | PopupMenuFlags::ExecuteDown;
+ else
+ eFlags = eFlags | PopupMenuFlags::ExecuteRight;
+ m_xMenu->Execute(pVclWidget->getWidget(), rRect, eFlags);
+ return m_xMenu->GetCurItemIdent();
+}
+void SalInstanceMenu::set_sensitive(const OUString& rIdent, bool bSensitive)
+{
+ m_xMenu->EnableItem(rIdent, bSensitive);
+}
+bool SalInstanceMenu::get_sensitive(const OUString& rIdent) const
+{
+ return m_xMenu->IsItemEnabled(m_xMenu->GetItemId(rIdent));
+}
+void SalInstanceMenu::set_active(const OUString& rIdent, bool bActive)
+{
+ m_xMenu->CheckItem(rIdent, bActive);
+}
+bool SalInstanceMenu::get_active(const OUString& rIdent) const
+{
+ return m_xMenu->IsItemChecked(m_xMenu->GetItemId(rIdent));
+}
+void SalInstanceMenu::set_label(const OUString& rIdent, const OUString& rLabel)
+{
+ m_xMenu->SetItemText(m_xMenu->GetItemId(rIdent), rLabel);
+}
+OUString SalInstanceMenu::get_label(const OUString& rIdent) const
+{
+ return m_xMenu->GetItemText(m_xMenu->GetItemId(rIdent));
+}
+void SalInstanceMenu::set_visible(const OUString& rIdent, bool bShow)
+{
+ m_xMenu->ShowItem(m_xMenu->GetItemId(rIdent), bShow);
+}
+void SalInstanceMenu::clear() { m_xMenu->Clear(); }
+void SalInstanceMenu::insert(int pos, const OUString& rId, const OUString& rStr,
+ const OUString* pIconName, VirtualDevice* pImageSurface,
+ const css::uno::Reference<css::graphic::XGraphic>& rImage,
+ TriState eCheckRadioFalse)
+{
+ m_nLastId = insert_to_menu(m_nLastId, m_xMenu, pos, rId, rStr, pIconName, pImageSurface, rImage,
+ eCheckRadioFalse);
+}
+void SalInstanceMenu::insert_separator(int pos, const OUString& rId)
+{
+ auto nInsertPos = pos == -1 ? MENU_APPEND : pos;
+ m_xMenu->InsertSeparator(rId, nInsertPos);
+}
+
+// Defines the help id of the item in a given position
+void SalInstanceMenu::set_item_help_id(const OUString& rIdent, const OUString& rHelpId)
+{
+ m_xMenu->SetHelpId(m_xMenu->GetItemId(rIdent), rHelpId);
+}
+
+void SalInstanceMenu::remove(const OUString& rId)
+{
+ m_xMenu->RemoveItem(m_xMenu->GetItemPos(m_xMenu->GetItemId(rId)));
+}
+int SalInstanceMenu::n_children() const { return m_xMenu->GetItemCount(); }
+OUString SalInstanceMenu::get_id(int pos) const
+{
+ return m_xMenu->GetItemIdent(m_xMenu->GetItemId(pos));
+}
+PopupMenu* SalInstanceMenu::getMenu() const { return m_xMenu.get(); }
+SalInstanceMenu::~SalInstanceMenu()
+{
+ m_xMenu->SetSelectHdl(Link<::Menu*, bool>());
+ if (m_bTakeOwnership)
+ m_xMenu.disposeAndClear();
+}
+
+IMPL_LINK_NOARG(SalInstanceMenu, SelectMenuHdl, ::Menu*, bool)
+{
+ signal_activate(m_xMenu->GetCurItemIdent());
+ /* tdf#131333 Menu::Select depends on a false here to allow
+ propagating a submens's selected id to its parent menu to become its
+ selected id.
+
+ without this, while gen menus already have propagated this to its parent
+ in MenuFloatingWindow::EndExecute, SalMenus as used under kf5/macOS
+ won't propagate the selected id
+ */
+ return false;
+}
+
+SalInstanceToolbar::SalInstanceToolbar(ToolBox* pToolBox, SalInstanceBuilder* pBuilder,
+ bool bTakeOwnership)
+ : SalInstanceWidget(pToolBox, pBuilder, bTakeOwnership)
+ , m_xToolBox(pToolBox)
+{
+ m_xToolBox->SetSelectHdl(LINK(this, SalInstanceToolbar, ClickHdl));
+ m_xToolBox->SetDropdownClickHdl(LINK(this, SalInstanceToolbar, DropdownClick));
+}
+
+void SalInstanceToolbar::set_item_sensitive(const OUString& rIdent, bool bSensitive)
+{
+ m_xToolBox->EnableItem(m_xToolBox->GetItemId(rIdent), bSensitive);
+}
+
+bool SalInstanceToolbar::get_item_sensitive(const OUString& rIdent) const
+{
+ return m_xToolBox->IsItemEnabled(m_xToolBox->GetItemId(rIdent));
+}
+
+void SalInstanceToolbar::set_item_visible(const OUString& rIdent, bool bVisible)
+{
+ m_xToolBox->ShowItem(m_xToolBox->GetItemId(rIdent), bVisible);
+}
+
+void SalInstanceToolbar::set_item_help_id(const OUString& rIdent, const OUString& rHelpId)
+{
+ m_xToolBox->SetHelpId(m_xToolBox->GetItemId(rIdent), rHelpId);
+}
+
+bool SalInstanceToolbar::get_item_visible(const OUString& rIdent) const
+{
+ return m_xToolBox->IsItemVisible(m_xToolBox->GetItemId(rIdent));
+}
+
+void SalInstanceToolbar::set_item_active(const OUString& rIdent, bool bActive)
+{
+ ToolBoxItemId nItemId = m_xToolBox->GetItemId(rIdent);
+ m_xToolBox->CheckItem(nItemId, bActive);
+}
+
+bool SalInstanceToolbar::get_item_active(const OUString& rIdent) const
+{
+ return m_xToolBox->IsItemChecked(m_xToolBox->GetItemId(rIdent));
+}
+
+void SalInstanceToolbar::set_menu_item_active(const OUString& rIdent, bool bActive)
+{
+ ToolBoxItemId nItemId = m_xToolBox->GetItemId(rIdent);
+ assert(m_xToolBox->GetItemBits(nItemId) & ToolBoxItemBits::DROPDOWN);
+
+ if (bActive)
+ {
+ m_sStartShowIdent = m_xToolBox->GetItemCommand(nItemId);
+ signal_toggle_menu(m_sStartShowIdent);
+ }
+
+ auto pFloat = m_aFloats[nItemId];
+ if (pFloat)
+ {
+ if (bActive)
+ vcl::Window::GetDockingManager()->StartPopupMode(m_xToolBox, pFloat,
+ FloatWinPopupFlags::GrabFocus);
+ else
+ vcl::Window::GetDockingManager()->EndPopupMode(pFloat);
+ }
+ auto pPopup = m_aMenus[nItemId];
+ if (pPopup)
+ {
+ if (bActive)
+ {
+ tools::Rectangle aRect = m_xToolBox->GetItemRect(nItemId);
+ pPopup->Execute(m_xToolBox, aRect, PopupMenuFlags::ExecuteDown);
+ }
+ else
+ pPopup->EndExecute();
+ }
+
+ m_sStartShowIdent.clear();
+}
+
+bool SalInstanceToolbar::get_menu_item_active(const OUString& rIdent) const
+{
+ ToolBoxItemId nItemId = m_xToolBox->GetItemId(rIdent);
+ assert(m_xToolBox->GetItemBits(nItemId) & ToolBoxItemBits::DROPDOWN);
+
+ if (rIdent == m_sStartShowIdent)
+ return true;
+
+ auto aFloat = m_aFloats.find(nItemId);
+ if (aFloat != m_aFloats.end())
+ {
+ return vcl::Window::GetDockingManager()->IsInPopupMode(aFloat->second);
+ }
+
+ auto aPopup = m_aMenus.find(nItemId);
+ if (aPopup != m_aMenus.end())
+ {
+ return PopupMenu::GetActivePopupMenu() == aPopup->second;
+ }
+
+ return false;
+}
+
+void SalInstanceToolbar::set_item_popover(const OUString& rIdent, weld::Widget* pPopover)
+{
+ SalInstanceWidget* pPopoverWidget = dynamic_cast<SalInstanceWidget*>(pPopover);
+
+ vcl::Window* pFloat = pPopoverWidget ? pPopoverWidget->getWidget() : nullptr;
+ if (pFloat)
+ {
+ pFloat->AddEventListener(LINK(this, SalInstanceToolbar, MenuToggleListener));
+ pFloat->EnableDocking();
+ }
+
+ ToolBoxItemId nId = m_xToolBox->GetItemId(rIdent);
+ auto xOldFloat = m_aFloats[nId];
+ if (xOldFloat)
+ {
+ xOldFloat->RemoveEventListener(LINK(this, SalInstanceToolbar, MenuToggleListener));
+ }
+ m_aFloats[nId] = pFloat;
+ m_aMenus[nId] = nullptr;
+}
+
+void SalInstanceToolbar::set_item_menu(const OUString& rIdent, weld::Menu* pMenu)
+{
+ SalInstanceMenu* pInstanceMenu = dynamic_cast<SalInstanceMenu*>(pMenu);
+
+ PopupMenu* pPopup = pInstanceMenu ? pInstanceMenu->getMenu() : nullptr;
+
+ ToolBoxItemId nId = m_xToolBox->GetItemId(rIdent);
+ m_aMenus[nId] = pPopup;
+ m_aFloats[nId] = nullptr;
+}
+
+void SalInstanceToolbar::insert_item(int pos, const OUString& rId)
+{
+ ToolBoxItemId nId(pos);
+ m_xToolBox->InsertItem(nId, OUString(), rId, ToolBoxItemBits::ICON_ONLY);
+}
+
+void SalInstanceToolbar::insert_separator(int pos, const OUString& /*rId*/)
+{
+ auto nInsertPos = pos == -1 ? ToolBox::APPEND : pos;
+ m_xToolBox->InsertSeparator(nInsertPos, 5);
+}
+
+int SalInstanceToolbar::get_n_items() const { return m_xToolBox->GetItemCount(); }
+
+OUString SalInstanceToolbar::get_item_ident(int nIndex) const
+{
+ return m_xToolBox->GetItemCommand(m_xToolBox->GetItemId(nIndex));
+}
+
+void SalInstanceToolbar::set_item_ident(int nIndex, const OUString& rIdent)
+{
+ return m_xToolBox->SetItemCommand(m_xToolBox->GetItemId(nIndex), rIdent);
+}
+
+void SalInstanceToolbar::set_item_label(int nIndex, const OUString& rLabel)
+{
+ m_xToolBox->SetItemText(m_xToolBox->GetItemId(nIndex), rLabel);
+}
+
+OUString SalInstanceToolbar::get_item_label(const OUString& rIdent) const
+{
+ return m_xToolBox->GetItemText(m_xToolBox->GetItemId(rIdent));
+}
+
+void SalInstanceToolbar::set_item_label(const OUString& rIdent, const OUString& rLabel)
+{
+ m_xToolBox->SetItemText(m_xToolBox->GetItemId(rIdent), rLabel);
+}
+
+void SalInstanceToolbar::set_item_icon_name(const OUString& rIdent, const OUString& rIconName)
+{
+ m_xToolBox->SetItemImage(m_xToolBox->GetItemId(rIdent), Image(StockImage::Yes, rIconName));
+}
+
+void SalInstanceToolbar::set_item_image_mirrored(const OUString& rIdent, bool bMirrored)
+{
+ m_xToolBox->SetItemImageMirrorMode(m_xToolBox->GetItemId(rIdent), bMirrored);
+}
+
+void SalInstanceToolbar::set_item_image(const OUString& rIdent,
+ const css::uno::Reference<css::graphic::XGraphic>& rIcon)
+{
+ m_xToolBox->SetItemImage(m_xToolBox->GetItemId(rIdent), Image(rIcon));
+}
+
+void SalInstanceToolbar::set_item_image(const OUString& rIdent, VirtualDevice* pDevice)
+{
+ if (pDevice)
+ m_xToolBox->SetItemImage(m_xToolBox->GetItemId(rIdent), createImage(*pDevice));
+ else
+ m_xToolBox->SetItemImage(m_xToolBox->GetItemId(rIdent), Image());
+}
+
+void SalInstanceToolbar::set_item_image(int nIndex,
+ const css::uno::Reference<css::graphic::XGraphic>& rIcon)
+{
+ m_xToolBox->SetItemImage(m_xToolBox->GetItemId(nIndex), Image(rIcon));
+}
+
+void SalInstanceToolbar::set_item_tooltip_text(int nIndex, const OUString& rTip)
+{
+ m_xToolBox->SetQuickHelpText(m_xToolBox->GetItemId(nIndex), rTip);
+}
+
+void SalInstanceToolbar::set_item_tooltip_text(const OUString& rIdent, const OUString& rTip)
+{
+ m_xToolBox->SetQuickHelpText(m_xToolBox->GetItemId(rIdent), rTip);
+}
+
+OUString SalInstanceToolbar::get_item_tooltip_text(const OUString& rIdent) const
+{
+ return m_xToolBox->GetQuickHelpText(m_xToolBox->GetItemId(rIdent));
+}
+
+vcl::ImageType SalInstanceToolbar::get_icon_size() const { return m_xToolBox->GetImageSize(); }
+
+void SalInstanceToolbar::set_icon_size(vcl::ImageType eType)
+{
+ ToolBoxButtonSize eButtonSize = ToolBoxButtonSize::DontCare;
+ switch (eType)
+ {
+ case vcl::ImageType::Size16:
+ eButtonSize = ToolBoxButtonSize::Small;
+ break;
+ case vcl::ImageType::Size26:
+ eButtonSize = ToolBoxButtonSize::Large;
+ break;
+ case vcl::ImageType::Size32:
+ eButtonSize = ToolBoxButtonSize::Size32;
+ break;
+ }
+ if (m_xToolBox->GetToolboxButtonSize() != eButtonSize)
+ {
+ m_xToolBox->SetToolboxButtonSize(eButtonSize);
+ m_xToolBox->queue_resize();
+ }
+}
+
+sal_uInt16 SalInstanceToolbar::get_modifier_state() const { return m_xToolBox->GetModifier(); }
+
+int SalInstanceToolbar::get_drop_index(const Point& rPoint) const
+{
+ auto nRet = m_xToolBox->GetItemPos(rPoint);
+ if (nRet == ToolBox::ITEM_NOTFOUND)
+ return 0;
+ return nRet;
+}
+
+SalInstanceToolbar::~SalInstanceToolbar()
+{
+ m_xToolBox->SetDropdownClickHdl(Link<ToolBox*, void>());
+ m_xToolBox->SetSelectHdl(Link<ToolBox*, void>());
+}
+
+IMPL_LINK_NOARG(SalInstanceToolbar, ClickHdl, ToolBox*, void)
+{
+ ToolBoxItemId nItemId = m_xToolBox->GetCurItemId();
+ signal_clicked(m_xToolBox->GetItemCommand(nItemId));
+}
+
+IMPL_LINK_NOARG(SalInstanceToolbar, DropdownClick, ToolBox*, void)
+{
+ ToolBoxItemId nItemId = m_xToolBox->GetCurItemId();
+ set_menu_item_active(m_xToolBox->GetItemCommand(nItemId), true);
+}
+
+IMPL_LINK(SalInstanceToolbar, MenuToggleListener, VclWindowEvent&, rEvent, void)
+{
+ if (rEvent.GetId() == VclEventId::WindowEndPopupMode)
+ {
+ for (const auto& rFloat : m_aFloats)
+ {
+ if (rEvent.GetWindow() == rFloat.second)
+ {
+ ToolBoxItemId nItemId = rFloat.first;
+ signal_toggle_menu(m_xToolBox->GetItemCommand(nItemId));
+ break;
+ }
+ }
+ }
+}
+
+namespace
+{
+class SalInstanceSizeGroup : public weld::SizeGroup
+{
+private:
+ std::shared_ptr<VclSizeGroup> m_xGroup;
+
+public:
+ SalInstanceSizeGroup()
+ : m_xGroup(std::make_shared<VclSizeGroup>())
+ {
+ }
+ virtual void add_widget(weld::Widget* pWidget) override
+ {
+ SalInstanceWidget* pVclWidget = dynamic_cast<SalInstanceWidget*>(pWidget);
+ assert(pVclWidget && pVclWidget->getWidget());
+ pVclWidget->getWidget()->add_to_size_group(m_xGroup);
+ }
+ virtual void set_mode(VclSizeGroupMode eMode) override { m_xGroup->set_mode(eMode); }
+};
+}
+
+void SalInstanceContainer::connect_container_focus_changed(const Link<Container&, void>& rLink)
+{
+ ensure_event_listener();
+ weld::Container::connect_container_focus_changed(rLink);
+}
+
+void SalInstanceContainer::HandleEventListener(VclWindowEvent& rEvent)
+{
+ if (rEvent.GetId() == VclEventId::WindowActivate
+ || rEvent.GetId() == VclEventId::WindowDeactivate)
+ {
+ signal_container_focus_changed();
+ return;
+ }
+ SalInstanceWidget::HandleEventListener(rEvent);
+}
+
+SalInstanceContainer::SalInstanceContainer(vcl::Window* pContainer, SalInstanceBuilder* pBuilder,
+ bool bTakeOwnership)
+ : SalInstanceWidget(pContainer, pBuilder, bTakeOwnership)
+ , m_xContainer(pContainer)
+{
+}
+
+void SalInstanceContainer::move(weld::Widget* pWidget, weld::Container* pNewParent)
+{
+ SalInstanceWidget* pVclWidget = dynamic_cast<SalInstanceWidget*>(pWidget);
+ assert(pVclWidget);
+ SalInstanceContainer* pNewVclParent = dynamic_cast<SalInstanceContainer*>(pNewParent);
+ assert(!pNewParent || pNewVclParent);
+ vcl::Window* pVclWindow = pVclWidget->getWidget();
+ if (pNewVclParent)
+ {
+ vcl::Window* pNew = pNewVclParent->getWidget();
+ if (!pNew->isDisposed())
+ pVclWindow->SetParent(pNewVclParent->getWidget());
+ else
+ SAL_WARN("vcl", "ignoring move because new parent is already disposed");
+ }
+ else
+ {
+ pVclWindow->Hide();
+ pVclWindow->SetParent(ImplGetDefaultWindow());
+ }
+}
+
+void SalInstanceContainer::child_grab_focus()
+{
+ m_xContainer->GrabFocus();
+ if (vcl::Window* pFirstChild = m_xContainer->ImplGetDlgWindow(0, GetDlgWindowType::First))
+ pFirstChild->ImplControlFocus();
+}
+
+css::uno::Reference<css::awt::XWindow> SalInstanceContainer::CreateChildFrame()
+{
+ auto xPage = VclPtr<VclBin>::Create(m_xContainer.get());
+ xPage->set_expand(true);
+ xPage->Show();
+ return css::uno::Reference<css::awt::XWindow>(xPage->GetComponentInterface(),
+ css::uno::UNO_QUERY);
+}
+
+std::unique_ptr<weld::Container> SalInstanceWidget::weld_parent() const
+{
+ vcl::Window* pParent = m_xWidget->GetParent();
+ if (!pParent)
+ return nullptr;
+ return std::make_unique<SalInstanceContainer>(pParent, m_pBuilder, false);
+}
+
+void SalInstanceWidget::DoRecursivePaint(vcl::Window* pWindow, const Point& rRenderLogicPos,
+ OutputDevice& rOutput)
+{
+ rOutput.Push();
+ bool bOldMapModeEnabled = pWindow->IsMapModeEnabled();
+
+ if (pWindow->GetMapMode().GetMapUnit() != rOutput.GetMapMode().GetMapUnit())
+ {
+ // This is needed for e.g. the scrollbar in writer comments in margins that has its map unit in pixels
+ // as seen with bin/run gtktiledviewer --enable-tiled-annotations on a document containing a comment
+ // long enough to need a scrollbar
+ pWindow->EnableMapMode();
+ MapMode aMapMode = pWindow->GetMapMode();
+ aMapMode.SetMapUnit(rOutput.GetMapMode().GetMapUnit());
+ aMapMode.SetScaleX(rOutput.GetMapMode().GetScaleX());
+ aMapMode.SetScaleY(rOutput.GetMapMode().GetScaleY());
+ pWindow->SetMapMode(aMapMode);
+ }
+
+ VclPtr<VirtualDevice> xOutput(VclPtr<VirtualDevice>::Create(DeviceFormat::WITHOUT_ALPHA));
+ Size aChildSizePixel(pWindow->GetSizePixel());
+ xOutput->SetOutputSizePixel(aChildSizePixel);
+
+ MapMode aMapMode(xOutput->GetMapMode());
+ aMapMode.SetMapUnit(rOutput.GetMapMode().GetMapUnit());
+ aMapMode.SetScaleX(rOutput.GetMapMode().GetScaleX());
+ aMapMode.SetScaleY(rOutput.GetMapMode().GetScaleY());
+ xOutput->SetMapMode(aMapMode);
+
+ Size aTempLogicSize(xOutput->PixelToLogic(aChildSizePixel));
+ Size aRenderLogicSize(rOutput.PixelToLogic(aChildSizePixel));
+
+ switch (rOutput.GetOutDevType())
+ {
+ case OUTDEV_WINDOW:
+ case OUTDEV_VIRDEV:
+ xOutput->DrawOutDev(Point(), aTempLogicSize, rRenderLogicPos, aRenderLogicSize,
+ rOutput);
+ break;
+ case OUTDEV_PRINTER:
+ case OUTDEV_PDF:
+ xOutput->SetBackground(rOutput.GetBackground());
+ xOutput->Erase();
+ break;
+ }
+
+ //set ReallyVisible to match Visible, we restore the original state after Paint
+ WindowImpl* pImpl = pWindow->ImplGetWindowImpl();
+ bool bRVisible = pImpl->mbReallyVisible;
+ pImpl->mbReallyVisible = pWindow->IsVisible();
+
+ pWindow->ApplySettings(*xOutput);
+ pWindow->Paint(*xOutput, tools::Rectangle(Point(), pWindow->PixelToLogic(aChildSizePixel)));
+
+ pImpl->mbReallyVisible = bRVisible;
+
+ switch (rOutput.GetOutDevType())
+ {
+ case OUTDEV_WINDOW:
+ case OUTDEV_VIRDEV:
+ rOutput.DrawOutDev(rRenderLogicPos, aRenderLogicSize, Point(), aTempLogicSize,
+ *xOutput);
+ break;
+ case OUTDEV_PRINTER:
+ case OUTDEV_PDF:
+ rOutput.DrawBitmapEx(rRenderLogicPos, aRenderLogicSize,
+ xOutput->GetBitmapEx(Point(), aTempLogicSize));
+ break;
+ }
+
+ bool bHasMirroredGraphics = pWindow->GetOutDev()->HasMirroredGraphics();
+
+ xOutput.disposeAndClear();
+
+ pWindow->EnableMapMode(bOldMapModeEnabled);
+ rOutput.Pop();
+
+ for (vcl::Window* pChild = pWindow->GetWindow(GetWindowType::FirstChild); pChild;
+ pChild = pChild->GetWindow(GetWindowType::Next))
+ {
+ if (!pChild->IsVisible())
+ continue;
+
+ tools::Long nDeltaX
+ = pChild->GetOutDev()->GetOutOffXPixel() - pWindow->GetOutDev()->GetOutOffXPixel();
+ if (bHasMirroredGraphics)
+ nDeltaX = pWindow->GetOutDev()->GetOutputWidthPixel() - nDeltaX
+ - pChild->GetOutDev()->GetOutputWidthPixel();
+
+ tools::Long nDeltaY
+ = pChild->GetOutDev()->GetOutOffYPixel() - pWindow->GetOutDev()->GetOutOffYPixel();
+
+ Point aPos(rRenderLogicPos);
+ aPos += Point(nDeltaX, nDeltaY);
+
+ DoRecursivePaint(pChild, aPos, rOutput);
+ }
+}
+
+void SalInstanceWidget::draw(OutputDevice& rOutput, const Point& rPos, const Size& rSizePixel)
+{
+ Size aOrigSize(m_xWidget->GetSizePixel());
+ bool bChangeSize = aOrigSize != rSizePixel;
+ if (bChangeSize)
+ m_xWidget->SetSizePixel(rSizePixel);
+
+ DoRecursivePaint(m_xWidget, rPos, rOutput);
+
+ if (bChangeSize)
+ m_xWidget->SetSizePixel(aOrigSize);
+}
+
+SalInstanceBox::SalInstanceBox(VclBox* pContainer, SalInstanceBuilder* pBuilder,
+ bool bTakeOwnership)
+ : SalInstanceContainer(pContainer, pBuilder, bTakeOwnership)
+ , m_xBox(pContainer)
+{
+}
+void SalInstanceBox::reorder_child(weld::Widget* pWidget, int nNewPosition)
+{
+ SalInstanceWidget* pVclWidget = dynamic_cast<SalInstanceWidget*>(pWidget);
+ assert(pVclWidget);
+ pVclWidget->getWidget()->reorderWithinParent(nNewPosition);
+}
+
+void SalInstanceBox::sort_native_button_order() { ::sort_native_button_order(*m_xBox); }
+
+namespace
+{
+void CollectChildren(const vcl::Window& rCurrent, const basegfx::B2IPoint& rTopLeft,
+ weld::ScreenShotCollection& rControlDataCollection)
+{
+ if (!rCurrent.IsVisible())
+ return;
+
+ const Point aCurrentPos(rCurrent.GetPosPixel());
+ const Size aCurrentSize(rCurrent.GetSizePixel());
+ const basegfx::B2IPoint aCurrentTopLeft(rTopLeft.getX() + aCurrentPos.X(),
+ rTopLeft.getY() + aCurrentPos.Y());
+ const basegfx::B2IRange aCurrentRange(
+ aCurrentTopLeft,
+ aCurrentTopLeft + basegfx::B2IPoint(aCurrentSize.Width(), aCurrentSize.Height()));
+
+ if (!aCurrentRange.isEmpty())
+ {
+ rControlDataCollection.emplace_back(rCurrent.GetHelpId(), aCurrentRange);
+ }
+
+ for (sal_uInt16 a(0); a < rCurrent.GetChildCount(); a++)
+ {
+ vcl::Window* pChild = rCurrent.GetChild(a);
+ if (nullptr != pChild)
+ {
+ CollectChildren(*pChild, aCurrentTopLeft, rControlDataCollection);
+ }
+ }
+}
+}
+
+void SalInstanceWindow::override_child_help(vcl::Window* pParent)
+{
+ for (vcl::Window* pChild = pParent->GetWindow(GetWindowType::FirstChild); pChild;
+ pChild = pChild->GetWindow(GetWindowType::Next))
+ override_child_help(pChild);
+ pParent->SetHelpHdl(LINK(this, SalInstanceWindow, HelpHdl));
+}
+
+void SalInstanceWindow::clear_child_help(vcl::Window* pParent)
+{
+ for (vcl::Window* pChild = pParent->GetWindow(GetWindowType::FirstChild); pChild;
+ pChild = pChild->GetWindow(GetWindowType::Next))
+ clear_child_help(pChild);
+ pParent->SetHelpHdl(Link<vcl::Window&, bool>());
+}
+
+SalInstanceWindow::SalInstanceWindow(vcl::Window* pWindow, SalInstanceBuilder* pBuilder,
+ bool bTakeOwnership)
+ : SalInstanceContainer(pWindow, pBuilder, bTakeOwnership)
+ , m_xWindow(pWindow)
+{
+ // tdf#129745 only override child help for the normal case, not for
+ // m_pBuilder of null which is the toplevel application frame case.
+ if (m_pBuilder)
+ override_child_help(m_xWindow);
+}
+
+void SalInstanceWindow::set_title(const OUString& rTitle) { m_xWindow->SetText(rTitle); }
+
+OUString SalInstanceWindow::get_title() const { return m_xWindow->GetText(); }
+
+css::uno::Reference<css::awt::XWindow> SalInstanceWindow::GetXWindow()
+{
+ css::uno::Reference<css::awt::XWindow> xWindow(m_xWindow->GetComponentInterface(),
+ css::uno::UNO_QUERY);
+ return xWindow;
+}
+
+namespace
+{
+void resize_to_request(vcl::Window* pWindow)
+{
+ if (SystemWindow* pSysWin = dynamic_cast<SystemWindow*>(pWindow))
+ {
+ pSysWin->setOptimalLayoutSize(true);
+ return;
+ }
+ if (DockingWindow* pDockWin = dynamic_cast<DockingWindow*>(pWindow))
+ {
+ pDockWin->setOptimalLayoutSize();
+ return;
+ }
+ assert(false && "must be system or docking window");
+}
+}
+
+void SalInstanceWindow::resize_to_request() { ::resize_to_request(m_xWindow.get()); }
+
+void SalInstanceWindow::set_modal(bool bModal) { m_xWindow->ImplGetFrame()->SetModal(bModal); }
+
+bool SalInstanceWindow::get_modal() const { return m_xWindow->ImplGetFrame()->GetModal(); }
+
+void SalInstanceWindow::window_move(int x, int y) { m_xWindow->SetPosPixel(Point(x, y)); }
+
+Size SalInstanceWindow::get_size() const { return m_xWindow->GetSizePixel(); }
+
+Point SalInstanceWindow::get_position() const { return m_xWindow->GetPosPixel(); }
+
+AbsoluteScreenPixelRectangle SalInstanceWindow::get_monitor_workarea() const
+{
+ return m_xWindow->GetDesktopRectPixel();
+}
+
+void SalInstanceWindow::set_centered_on_parent(bool /*bTrackGeometryRequests*/)
+{
+ if (vcl::Window* pParent = m_xWidget->GetParent())
+ {
+ Size aParentGeometry(pParent->GetSizePixel());
+ Size aGeometry(m_xWidget->get_preferred_size());
+ auto nX = (aParentGeometry.Width() - aGeometry.Width()) / 2;
+ auto nY = (aParentGeometry.Height() - aGeometry.Height()) / 2;
+ m_xWidget->SetPosPixel(Point(nX, nY));
+ }
+}
+
+bool SalInstanceWindow::get_resizable() const { return m_xWindow->GetStyle() & WB_SIZEABLE; }
+
+bool SalInstanceWindow::has_toplevel_focus() const { return m_xWindow->HasChildPathFocus(); }
+
+void SalInstanceWindow::present()
+{
+ m_xWindow->ToTop(ToTopFlags::RestoreWhenMin | ToTopFlags::ForegroundTask);
+}
+
+void SalInstanceWindow::implResetDefault(const vcl::Window* _pWindow)
+{
+ vcl::Window* pChildLoop = _pWindow->GetWindow(GetWindowType::FirstChild);
+ while (pChildLoop)
+ {
+ // does the window participate in the tabbing order?
+ if (pChildLoop->GetStyle() & WB_DIALOGCONTROL)
+ implResetDefault(pChildLoop);
+
+ // is it a button?
+ WindowType eType = pChildLoop->GetType();
+ if ((WindowType::PUSHBUTTON == eType) || (WindowType::OKBUTTON == eType)
+ || (WindowType::CANCELBUTTON == eType) || (WindowType::HELPBUTTON == eType)
+ || (WindowType::IMAGEBUTTON == eType) || (WindowType::MENUBUTTON == eType)
+ || (WindowType::MOREBUTTON == eType))
+ {
+ pChildLoop->SetStyle(pChildLoop->GetStyle() & ~WB_DEFBUTTON);
+ }
+
+ // the next one ...
+ pChildLoop = pChildLoop->GetWindow(GetWindowType::Next);
+ }
+}
+
+void SalInstanceWindow::recursively_unset_default_buttons() { implResetDefault(m_xWindow.get()); }
+
+void SalInstanceWindow::change_default_widget(weld::Widget* pOld, weld::Widget* pNew)
+{
+ SalInstanceWidget* pVclNew = dynamic_cast<SalInstanceWidget*>(pNew);
+ vcl::Window* pWidgetNew = pVclNew ? pVclNew->getWidget() : nullptr;
+ SalInstanceWidget* pVclOld = dynamic_cast<SalInstanceWidget*>(pOld);
+ vcl::Window* pWidgetOld = pVclOld ? pVclOld->getWidget() : nullptr;
+ if (pWidgetOld)
+ pWidgetOld->set_property("has-default", OUString::boolean(false));
+ else
+ recursively_unset_default_buttons();
+ if (pWidgetNew)
+ pWidgetNew->set_property("has-default", OUString::boolean(true));
+}
+
+bool SalInstanceWindow::is_default_widget(const weld::Widget* pCandidate) const
+{
+ const SalInstanceWidget* pVclCandidate = dynamic_cast<const SalInstanceWidget*>(pCandidate);
+ vcl::Window* pWidget = pVclCandidate ? pVclCandidate->getWidget() : nullptr;
+ return pWidget && pWidget->GetStyle() & WB_DEFBUTTON;
+}
+
+void SalInstanceWindow::set_window_state(const OUString& rStr)
+{
+ SystemWindow* pSysWin = dynamic_cast<SystemWindow*>(m_xWindow.get());
+ assert(pSysWin);
+ pSysWin->SetWindowState(rStr);
+}
+
+OUString SalInstanceWindow::get_window_state(vcl::WindowDataMask nMask) const
+{
+ SystemWindow* pSysWin = dynamic_cast<SystemWindow*>(m_xWindow.get());
+ assert(pSysWin);
+ return pSysWin->GetWindowState(nMask);
+}
+
+SystemEnvData SalInstanceWindow::get_system_data() const { return *m_xWindow->GetSystemData(); }
+
+VclPtr<VirtualDevice> SalInstanceWindow::screenshot()
+{
+ SystemWindow* pSysWin = dynamic_cast<SystemWindow*>(m_xWindow.get());
+ assert(pSysWin);
+ return pSysWin->createScreenshot();
+}
+
+weld::ScreenShotCollection SalInstanceWindow::collect_screenshot_data()
+{
+ weld::ScreenShotCollection aRet;
+
+ // collect all children. Choose start pos to be negative
+ // of target dialog's position to get all positions relative to (0,0)
+ const Point aParentPos(m_xWindow->GetPosPixel());
+ const basegfx::B2IPoint aTopLeft(-aParentPos.X(), -aParentPos.Y());
+ CollectChildren(*m_xWindow, aTopLeft, aRet);
+
+ return aRet;
+}
+
+const vcl::ILibreOfficeKitNotifier* SalInstanceWindow::GetLOKNotifier()
+{
+ return m_xWindow ? m_xWindow->GetLOKNotifier() : nullptr;
+}
+
+SalInstanceWindow::~SalInstanceWindow()
+{
+ // tdf#129745 only undo overriding child help for the normal case, not for
+ // m_pBuilder of null which is the toplevel application frame case.
+ if (m_pBuilder)
+ clear_child_help(m_xWindow);
+}
+
+IMPL_LINK_NOARG(SalInstanceWindow, HelpHdl, vcl::Window&, bool)
+{
+ help();
+ return false;
+}
+
+typedef std::set<VclPtr<vcl::Window>> winset;
+
+namespace
+{
+void hideUnless(const vcl::Window* pTop, const winset& rVisibleWidgets,
+ std::vector<VclPtr<vcl::Window>>& rWasVisibleWidgets)
+{
+ for (vcl::Window* pChild = pTop->GetWindow(GetWindowType::FirstChild); pChild;
+ pChild = pChild->GetWindow(GetWindowType::Next))
+ {
+ if (!pChild->IsVisible())
+ continue;
+ if (rVisibleWidgets.find(pChild) == rVisibleWidgets.end())
+ {
+ rWasVisibleWidgets.emplace_back(pChild);
+ pChild->Hide();
+ }
+ else if (isContainerWindow(pChild))
+ {
+ hideUnless(pChild, rVisibleWidgets, rWasVisibleWidgets);
+ }
+ }
+}
+}
+
+SalInstanceDialog::SalInstanceDialog(::Dialog* pDialog, SalInstanceBuilder* pBuilder,
+ bool bTakeOwnership)
+ : SalInstanceWindow(pDialog, pBuilder, bTakeOwnership)
+ , m_xDialog(pDialog)
+ , m_nOldEditWidthReq(0)
+ , m_nOldBorderWidth(0)
+{
+ const bool bScreenshotMode(officecfg::Office::Common::Misc::ScreenshotMode::get());
+ if (bScreenshotMode)
+ {
+ m_xDialog->SetPopupMenuHdl(LINK(this, SalInstanceDialog, PopupScreenShotMenuHdl));
+ }
+}
+
+bool SalInstanceDialog::runAsync(std::shared_ptr<weld::DialogController> aOwner,
+ const std::function<void(sal_Int32)>& rEndDialogFn)
+{
+ VclAbstractDialog::AsyncContext aCtx;
+ aCtx.mxOwnerDialogController = aOwner;
+ aCtx.maEndDialogFn = rEndDialogFn;
+ VclButtonBox* pActionArea = m_xDialog->get_action_area();
+ if (pActionArea)
+ sort_native_button_order(*pActionArea);
+ return m_xDialog->StartExecuteAsync(aCtx);
+}
+
+bool SalInstanceDialog::runAsync(std::shared_ptr<Dialog> const& rxSelf,
+ const std::function<void(sal_Int32)>& rEndDialogFn)
+{
+ assert(rxSelf.get() == this);
+ VclAbstractDialog::AsyncContext aCtx;
+ // In order to store a shared_ptr to ourself, we have to have been constructed by make_shared,
+ // which is that rxSelf enforces.
+ aCtx.mxOwnerSelf = rxSelf;
+ aCtx.maEndDialogFn = rEndDialogFn;
+ VclButtonBox* pActionArea = m_xDialog->get_action_area();
+ if (pActionArea)
+ sort_native_button_order(*pActionArea);
+ return m_xDialog->StartExecuteAsync(aCtx);
+}
+
+void SalInstanceDialog::collapse(weld::Widget* pEdit, weld::Widget* pButton)
+{
+ SalInstanceWidget* pVclEdit = dynamic_cast<SalInstanceWidget*>(pEdit);
+ assert(pVclEdit);
+ SalInstanceWidget* pVclButton = dynamic_cast<SalInstanceWidget*>(pButton);
+
+ vcl::Window* pRefEdit = pVclEdit->getWidget();
+ vcl::Window* pRefBtn = pVclButton ? pVclButton->getWidget() : nullptr;
+
+ auto nOldEditWidth = pRefEdit->GetSizePixel().Width();
+ m_nOldEditWidthReq = pRefEdit->get_width_request();
+
+ //We want just pRefBtn and pRefEdit to be shown
+ //mark widgets we want to be visible, starting with pRefEdit
+ //and all its direct parents.
+ winset aVisibleWidgets;
+ vcl::Window* pContentArea = m_xDialog->get_content_area();
+ for (vcl::Window* pCandidate = pRefEdit;
+ pCandidate && (pCandidate != pContentArea && pCandidate->IsVisible());
+ pCandidate = pCandidate->GetWindow(GetWindowType::RealParent))
+ {
+ aVisibleWidgets.insert(pCandidate);
+ }
+ //same again with pRefBtn, except stop if there's a
+ //shared parent in the existing widgets
+ for (vcl::Window* pCandidate = pRefBtn;
+ pCandidate && (pCandidate != pContentArea && pCandidate->IsVisible());
+ pCandidate = pCandidate->GetWindow(GetWindowType::RealParent))
+ {
+ if (aVisibleWidgets.insert(pCandidate).second)
+ break;
+ }
+
+ //hide everything except the aVisibleWidgets
+ hideUnless(pContentArea, aVisibleWidgets, m_aHiddenWidgets);
+
+ // the insert function case has an initially hidden edit widget, so it has
+ // not start size, so take larger of actual size and size request
+ pRefEdit->set_width_request(std::max(nOldEditWidth, m_nOldEditWidthReq));
+ m_nOldBorderWidth = m_xDialog->get_border_width();
+ m_xDialog->set_border_width(0);
+ if (vcl::Window* pActionArea = m_xDialog->get_action_area())
+ pActionArea->Hide();
+ m_xDialog->setOptimalLayoutSize(true);
+ m_xRefEdit = pRefEdit;
+}
+
+void SalInstanceDialog::undo_collapse()
+{
+ // All others: Show();
+ for (VclPtr<vcl::Window> const& pWindow : m_aHiddenWidgets)
+ {
+ pWindow->Show();
+ }
+ m_aHiddenWidgets.clear();
+
+ m_xRefEdit->set_width_request(m_nOldEditWidthReq);
+ m_xRefEdit.clear();
+ m_xDialog->set_border_width(m_nOldBorderWidth);
+ if (vcl::Window* pActionArea = m_xDialog->get_action_area())
+ pActionArea->Show();
+ m_xDialog->setOptimalLayoutSize(true);
+}
+
+void SalInstanceDialog::SetInstallLOKNotifierHdl(
+ const Link<void*, vcl::ILibreOfficeKitNotifier*>& rLink)
+{
+ m_xDialog->SetInstallLOKNotifierHdl(rLink);
+}
+
+int SalInstanceDialog::run()
+{
+ VclButtonBox* pActionArea = m_xDialog->get_action_area();
+ if (pActionArea)
+ sort_native_button_order(*pActionArea);
+ return m_xDialog->Execute();
+}
+
+void SalInstanceDialog::response(int nResponse) { m_xDialog->EndDialog(nResponse); }
+
+void SalInstanceDialog::add_button(const OUString& rText, int nResponse, const OUString& rHelpId)
+{
+ VclButtonBox* pBox = m_xDialog->get_action_area();
+ VclPtr<PushButton> xButton(
+ VclPtr<PushButton>::Create(pBox, WB_CLIPCHILDREN | WB_CENTER | WB_VCENTER));
+ xButton->SetText(rText);
+ xButton->SetHelpId(rHelpId);
+
+ switch (nResponse)
+ {
+ case RET_OK:
+ xButton->set_id("ok");
+ break;
+ case RET_CLOSE:
+ xButton->set_id("close");
+ break;
+ case RET_CANCEL:
+ xButton->set_id("cancel");
+ break;
+ case RET_YES:
+ xButton->set_id("yes");
+ break;
+ case RET_NO:
+ xButton->set_id("no");
+ break;
+ }
+
+ xButton->Show();
+ m_xDialog->add_button(xButton, nResponse, true);
+}
+
+void SalInstanceDialog::set_modal(bool bModal)
+{
+ if (get_modal() == bModal)
+ return;
+ m_xDialog->SetModalInputMode(bModal);
+}
+
+bool SalInstanceDialog::get_modal() const { return m_xDialog->IsModalInputMode(); }
+
+void SalInstanceDialog::set_default_response(int nResponse)
+{
+ m_xDialog->set_default_response(nResponse);
+}
+
+weld::Container* SalInstanceDialog::weld_content_area()
+{
+ return new SalInstanceContainer(m_xDialog->get_content_area(), m_pBuilder, false);
+}
+
+IMPL_LINK(SalInstanceDialog, PopupScreenShotMenuHdl, const CommandEvent&, rCEvt, bool)
+{
+ if (CommandEventId::ContextMenu == rCEvt.GetCommand())
+ {
+ const Point aMenuPos(rCEvt.GetMousePosPixel());
+ ScopedVclPtrInstance<PopupMenu> aMenu;
+ sal_uInt16 nLocalID(1);
+
+ aMenu->InsertItem(nLocalID, VclResId(SV_BUTTONTEXT_SCREENSHOT));
+ aMenu->SetHelpText(nLocalID, VclResId(SV_HELPTEXT_SCREENSHOT));
+ aMenu->SetHelpId(nLocalID, "InteractiveScreenshotMode");
+ aMenu->EnableItem(nLocalID);
+
+ const sal_uInt16 nId(aMenu->Execute(m_xDialog, aMenuPos));
+
+ // 0 == no selection (so not usable as ID)
+ if (0 != nId)
+ {
+ // open screenshot annotation dialog
+ VclAbstractDialogFactory* pFact = VclAbstractDialogFactory::Create();
+ VclPtr<AbstractScreenshotAnnotationDlg> pTmp
+ = pFact->CreateScreenshotAnnotationDlg(*this);
+ ScopedVclPtr<AbstractScreenshotAnnotationDlg> pDialog(pTmp);
+
+ if (pDialog)
+ {
+ // currently just execute the dialog, no need to do
+ // different things for ok/cancel. This may change later,
+ // for that case use 'if (pDlg->Execute() == RET_OK)'
+ pDialog->Execute();
+ }
+ }
+
+ // consume event when:
+ // - CommandEventId::ContextMenu
+ // - bScreenshotMode
+ return true;
+ }
+
+ return false;
+}
+
+SalInstanceMessageDialog::SalInstanceMessageDialog(::MessageDialog* pDialog,
+ SalInstanceBuilder* pBuilder,
+ bool bTakeOwnership)
+ : SalInstanceDialog(pDialog, pBuilder, bTakeOwnership)
+ , m_xMessageDialog(pDialog)
+{
+}
+
+void SalInstanceMessageDialog::set_primary_text(const OUString& rText)
+{
+ m_xMessageDialog->set_primary_text(rText);
+}
+
+OUString SalInstanceMessageDialog::get_primary_text() const
+{
+ return m_xMessageDialog->get_primary_text();
+}
+
+void SalInstanceMessageDialog::set_secondary_text(const OUString& rText)
+{
+ m_xMessageDialog->set_secondary_text(rText);
+}
+
+OUString SalInstanceMessageDialog::get_secondary_text() const
+{
+ return m_xMessageDialog->get_secondary_text();
+}
+
+weld::Container* SalInstanceMessageDialog::weld_message_area()
+{
+ return new SalInstanceContainer(m_xMessageDialog->get_message_area(), m_pBuilder, false);
+}
+
+int SalInstanceAssistant::find_page(std::u16string_view rIdent) const
+{
+ for (size_t i = 0; i < m_aAddedPages.size(); ++i)
+ {
+ if (m_aAddedPages[i]->get_id() == rIdent)
+ return i;
+ }
+ return -1;
+}
+
+int SalInstanceAssistant::find_id(int nId) const
+{
+ for (size_t i = 0; i < m_aIds.size(); ++i)
+ {
+ if (nId == m_aIds[i])
+ return i;
+ }
+ return -1;
+}
+
+SalInstanceAssistant::SalInstanceAssistant(vcl::RoadmapWizard* pDialog,
+ SalInstanceBuilder* pBuilder, bool bTakeOwnership)
+ : SalInstanceDialog(pDialog, pBuilder, bTakeOwnership)
+ , m_xWizard(pDialog)
+ , m_aUpdateRoadmapIdle("SalInstanceAssistant m_aUpdateRoadmapIdle")
+{
+ m_xWizard->SetItemSelectHdl(LINK(this, SalInstanceAssistant, OnRoadmapItemSelected));
+
+ m_aUpdateRoadmapIdle.SetInvokeHandler(LINK(this, SalInstanceAssistant, UpdateRoadmap_Hdl));
+ m_aUpdateRoadmapIdle.SetPriority(TaskPriority::HIGHEST);
+}
+
+int SalInstanceAssistant::get_current_page() const { return find_id(m_xWizard->GetCurLevel()); }
+
+int SalInstanceAssistant::get_n_pages() const { return m_aAddedPages.size(); }
+
+OUString SalInstanceAssistant::get_page_ident(int nPage) const
+{
+ return m_aAddedPages[nPage]->get_id();
+}
+
+OUString SalInstanceAssistant::get_current_page_ident() const
+{
+ return get_page_ident(get_current_page());
+}
+
+void SalInstanceAssistant::set_current_page(int nPage)
+{
+ disable_notify_events();
+
+ // take the first shown page as the size for all pages
+ if (m_xWizard->GetPageSizePixel().Width() == 0)
+ {
+ Size aFinalSize;
+ for (int i = 0, nPages = get_n_pages(); i < nPages; ++i)
+ {
+ TabPage* pPage = m_xWizard->GetPage(m_aIds[i]);
+ assert(pPage);
+ Size aPageSize(pPage->get_preferred_size());
+ if (aPageSize.Width() > aFinalSize.Width())
+ aFinalSize.setWidth(aPageSize.Width());
+ if (aPageSize.Height() > aFinalSize.Height())
+ aFinalSize.setHeight(aPageSize.Height());
+ }
+ m_xWizard->SetPageSizePixel(aFinalSize);
+ }
+
+ (void)m_xWizard->ShowPage(m_aIds[nPage]);
+ enable_notify_events();
+}
+
+void SalInstanceAssistant::set_current_page(const OUString& rIdent)
+{
+ int nIndex = find_page(rIdent);
+ if (nIndex == -1)
+ return;
+ set_current_page(nIndex);
+}
+
+void SalInstanceAssistant::set_page_index(const OUString& rIdent, int nNewIndex)
+{
+ int nOldIndex = find_page(rIdent);
+
+ if (nOldIndex == -1)
+ return;
+
+ if (nOldIndex == nNewIndex)
+ return;
+
+ disable_notify_events();
+
+ auto entry = std::move(m_aAddedPages[nOldIndex]);
+ m_aAddedPages.erase(m_aAddedPages.begin() + nOldIndex);
+ m_aAddedPages.insert(m_aAddedPages.begin() + nNewIndex, std::move(entry));
+
+ int nId = m_aIds[nOldIndex];
+ m_aIds.erase(m_aIds.begin() + nOldIndex);
+ m_aIds.insert(m_aIds.begin() + nNewIndex, nId);
+
+ m_aUpdateRoadmapIdle.Start();
+
+ enable_notify_events();
+}
+
+weld::Container* SalInstanceAssistant::append_page(const OUString& rIdent)
+{
+ VclPtrInstance<TabPage> xPage(m_xWizard);
+ VclPtrInstance<VclGrid> xGrid(xPage);
+ xPage->set_id(rIdent);
+ xPage->Show();
+ xGrid->set_hexpand(true);
+ xGrid->set_vexpand(true);
+ xGrid->Show();
+ m_xWizard->AddPage(xPage);
+ m_aIds.push_back(m_aAddedPages.size());
+ m_xWizard->SetPage(m_aIds.back(), xPage);
+ m_aAddedPages.push_back(xPage);
+ m_aAddedGrids.push_back(xGrid);
+
+ m_aUpdateRoadmapIdle.Start();
+
+ m_aPages.emplace_back(new SalInstanceContainer(xGrid, m_pBuilder, false));
+ return m_aPages.back().get();
+}
+
+OUString SalInstanceAssistant::get_page_title(const OUString& rIdent) const
+{
+ int nIndex = find_page(rIdent);
+ if (nIndex == -1)
+ return OUString();
+ return m_aAddedPages[nIndex]->GetText();
+}
+
+void SalInstanceAssistant::set_page_title(const OUString& rIdent, const OUString& rTitle)
+{
+ int nIndex = find_page(rIdent);
+ if (nIndex == -1)
+ return;
+ if (m_aAddedPages[nIndex]->GetText() != rTitle)
+ {
+ disable_notify_events();
+ m_aAddedPages[nIndex]->SetText(rTitle);
+ m_aUpdateRoadmapIdle.Start();
+ enable_notify_events();
+ }
+}
+
+void SalInstanceAssistant::set_page_sensitive(const OUString& rIdent, bool bSensitive)
+{
+ int nIndex = find_page(rIdent);
+ if (nIndex == -1)
+ return;
+ if (m_aAddedPages[nIndex]->IsEnabled() != bSensitive)
+ {
+ disable_notify_events();
+ m_aAddedPages[nIndex]->Enable(bSensitive);
+ m_aUpdateRoadmapIdle.Start();
+ enable_notify_events();
+ }
+}
+
+void SalInstanceAssistant::set_page_side_help_id(const OUString& rHelpId)
+{
+ m_xWizard->SetRoadmapHelpId(rHelpId);
+}
+
+void SalInstanceAssistant::set_page_side_image(const OUString& rImage)
+{
+ m_xWizard->SetRoadmapBitmap(createImage(rImage).GetBitmapEx());
+}
+
+SalInstanceAssistant::~SalInstanceAssistant()
+{
+ for (auto& rGrid : m_aAddedGrids)
+ rGrid.disposeAndClear();
+ for (auto& rPage : m_aAddedPages)
+ rPage.disposeAndClear();
+}
+
+IMPL_LINK_NOARG(SalInstanceAssistant, OnRoadmapItemSelected, LinkParamNone*, void)
+{
+ if (notify_events_disabled())
+ return;
+ auto nCurItemId = m_xWizard->GetCurrentRoadmapItemID();
+ int nPageIndex(find_id(nCurItemId));
+ if (!signal_jump_page(get_page_ident(nPageIndex)) && nCurItemId != m_xWizard->GetCurLevel())
+ m_xWizard->SelectRoadmapItemByID(m_xWizard->GetCurLevel());
+}
+
+IMPL_LINK_NOARG(SalInstanceAssistant, UpdateRoadmap_Hdl, Timer*, void)
+{
+ disable_notify_events();
+
+ m_xWizard->DeleteRoadmapItems();
+
+ int nPos = 0;
+ for (size_t i = 0; i < m_aAddedPages.size(); ++i)
+ {
+ const OUString& rLabel = m_aAddedPages[i]->GetText();
+ bool bSensitive = m_aAddedPages[i]->IsEnabled();
+ if (rLabel.isEmpty())
+ continue;
+ m_xWizard->InsertRoadmapItem(nPos++, rLabel, m_aIds[i], bSensitive);
+ }
+
+ m_xWizard->SelectRoadmapItemByID(m_aIds[get_current_page()], false);
+
+ m_xWizard->ShowRoadmap(nPos != 0);
+
+ enable_notify_events();
+}
+
+SalInstanceFrame::SalInstanceFrame(VclFrame* pFrame, SalInstanceBuilder* pBuilder,
+ bool bTakeOwnership)
+ : SalInstanceContainer(pFrame, pBuilder, bTakeOwnership)
+ , m_xFrame(pFrame)
+{
+}
+
+void SalInstanceFrame::set_label(const OUString& rText) { m_xFrame->set_label(rText); }
+
+OUString SalInstanceFrame::get_label() const { return m_xFrame->get_label(); }
+
+namespace
+{
+class SalInstancePaned : public SalInstanceContainer, public virtual weld::Paned
+{
+private:
+ VclPtr<VclPaned> m_xPaned;
+
+public:
+ SalInstancePaned(VclPaned* pPaned, SalInstanceBuilder* pBuilder, bool bTakeOwnership)
+ : SalInstanceContainer(pPaned, pBuilder, bTakeOwnership)
+ , m_xPaned(pPaned)
+ {
+ }
+
+ virtual void set_position(int nPos) override { m_xPaned->set_position(nPos); }
+
+ virtual int get_position() const override { return m_xPaned->get_position(); }
+};
+}
+
+void SalInstanceScrolledWindow::customize_scrollbars(ScrollBar& rScrollBar,
+ const Color& rButtonTextColor,
+ const Color& rBackgroundColor,
+ const Color& rShadowColor,
+ const Color& rFaceColor)
+{
+ rScrollBar.EnableNativeWidget(false);
+ AllSettings aSettings = rScrollBar.GetSettings();
+ StyleSettings aStyleSettings = aSettings.GetStyleSettings();
+ aStyleSettings.SetButtonTextColor(rButtonTextColor);
+ aStyleSettings.SetCheckedColor(rBackgroundColor); // background
+ aStyleSettings.SetShadowColor(rShadowColor);
+ aStyleSettings.SetFaceColor(rFaceColor);
+ aSettings.SetStyleSettings(aStyleSettings);
+ rScrollBar.SetSettings(aSettings);
+}
+
+SalInstanceScrolledWindow::SalInstanceScrolledWindow(VclScrolledWindow* pScrolledWindow,
+ SalInstanceBuilder* pBuilder,
+ bool bTakeOwnership,
+ bool bUserManagedScrolling)
+ : SalInstanceContainer(pScrolledWindow, pBuilder, bTakeOwnership)
+ , m_xScrolledWindow(pScrolledWindow)
+ , m_bUserManagedScrolling(bUserManagedScrolling)
+{
+ ScrollBar& rVertScrollBar = m_xScrolledWindow->getVertScrollBar();
+ m_aOrigVScrollHdl = rVertScrollBar.GetScrollHdl();
+ rVertScrollBar.SetScrollHdl(LINK(this, SalInstanceScrolledWindow, VscrollHdl));
+ ScrollBar& rHorzScrollBar = m_xScrolledWindow->getHorzScrollBar();
+ m_aOrigHScrollHdl = rHorzScrollBar.GetScrollHdl();
+ rHorzScrollBar.SetScrollHdl(LINK(this, SalInstanceScrolledWindow, HscrollHdl));
+ m_xScrolledWindow->setUserManagedScrolling(m_bUserManagedScrolling);
+}
+
+void SalInstanceScrolledWindow::hadjustment_configure(int value, int lower, int upper,
+ int step_increment, int page_increment,
+ int page_size)
+{
+ ScrollBar& rHorzScrollBar = m_xScrolledWindow->getHorzScrollBar();
+ rHorzScrollBar.SetRangeMin(lower);
+ rHorzScrollBar.SetRangeMax(upper);
+ rHorzScrollBar.SetLineSize(step_increment);
+ rHorzScrollBar.SetPageSize(page_increment);
+ rHorzScrollBar.SetThumbPos(value);
+ rHorzScrollBar.SetVisibleSize(page_size);
+}
+
+int SalInstanceScrolledWindow::hadjustment_get_value() const
+{
+ ScrollBar& rHorzScrollBar = m_xScrolledWindow->getHorzScrollBar();
+ return rHorzScrollBar.GetThumbPos();
+}
+
+void SalInstanceScrolledWindow::hadjustment_set_value(int value)
+{
+ ScrollBar& rHorzScrollBar = m_xScrolledWindow->getHorzScrollBar();
+ rHorzScrollBar.SetThumbPos(value);
+ if (!m_bUserManagedScrolling)
+ m_aOrigHScrollHdl.Call(&rHorzScrollBar);
+}
+
+int SalInstanceScrolledWindow::hadjustment_get_upper() const
+{
+ ScrollBar& rHorzScrollBar = m_xScrolledWindow->getHorzScrollBar();
+ return rHorzScrollBar.GetRangeMax();
+}
+
+void SalInstanceScrolledWindow::hadjustment_set_upper(int upper)
+{
+ ScrollBar& rHorzScrollBar = m_xScrolledWindow->getHorzScrollBar();
+ rHorzScrollBar.SetRangeMax(upper);
+}
+
+int SalInstanceScrolledWindow::hadjustment_get_page_size() const
+{
+ ScrollBar& rHorzScrollBar = m_xScrolledWindow->getHorzScrollBar();
+ return rHorzScrollBar.GetVisibleSize();
+}
+
+void SalInstanceScrolledWindow::hadjustment_set_page_size(int size)
+{
+ ScrollBar& rHorzScrollBar = m_xScrolledWindow->getHorzScrollBar();
+ return rHorzScrollBar.SetVisibleSize(size);
+}
+
+void SalInstanceScrolledWindow::hadjustment_set_page_increment(int size)
+{
+ ScrollBar& rHorzScrollBar = m_xScrolledWindow->getHorzScrollBar();
+ return rHorzScrollBar.SetPageSize(size);
+}
+
+void SalInstanceScrolledWindow::hadjustment_set_step_increment(int size)
+{
+ ScrollBar& rHorzScrollBar = m_xScrolledWindow->getHorzScrollBar();
+ return rHorzScrollBar.SetLineSize(size);
+}
+
+void SalInstanceScrolledWindow::set_hpolicy(VclPolicyType eHPolicy)
+{
+ WinBits nWinBits = m_xScrolledWindow->GetStyle() & ~(WB_AUTOHSCROLL | WB_HSCROLL);
+ if (eHPolicy == VclPolicyType::ALWAYS)
+ nWinBits |= WB_HSCROLL;
+ else if (eHPolicy == VclPolicyType::AUTOMATIC)
+ nWinBits |= WB_AUTOHSCROLL;
+ m_xScrolledWindow->SetStyle(nWinBits);
+ m_xScrolledWindow->queue_resize();
+}
+
+VclPolicyType SalInstanceScrolledWindow::get_hpolicy() const
+{
+ WinBits nWinBits = m_xScrolledWindow->GetStyle();
+ if (nWinBits & WB_AUTOHSCROLL)
+ return VclPolicyType::AUTOMATIC;
+ else if (nWinBits & WB_HSCROLL)
+ return VclPolicyType::ALWAYS;
+ return VclPolicyType::NEVER;
+}
+
+void SalInstanceScrolledWindow::vadjustment_configure(int value, int lower, int upper,
+ int step_increment, int page_increment,
+ int page_size)
+{
+ ScrollBar& rVertScrollBar = m_xScrolledWindow->getVertScrollBar();
+ rVertScrollBar.SetRangeMin(lower);
+ rVertScrollBar.SetRangeMax(upper);
+ rVertScrollBar.SetLineSize(step_increment);
+ rVertScrollBar.SetPageSize(page_increment);
+ rVertScrollBar.SetThumbPos(value);
+ rVertScrollBar.SetVisibleSize(page_size);
+}
+
+int SalInstanceScrolledWindow::vadjustment_get_value() const
+{
+ ScrollBar& rVertScrollBar = m_xScrolledWindow->getVertScrollBar();
+ return rVertScrollBar.GetThumbPos();
+}
+
+void SalInstanceScrolledWindow::vadjustment_set_value(int value)
+{
+ ScrollBar& rVertScrollBar = m_xScrolledWindow->getVertScrollBar();
+ rVertScrollBar.SetThumbPos(value);
+ if (!m_bUserManagedScrolling)
+ m_aOrigVScrollHdl.Call(&rVertScrollBar);
+}
+
+int SalInstanceScrolledWindow::vadjustment_get_upper() const
+{
+ ScrollBar& rVertScrollBar = m_xScrolledWindow->getVertScrollBar();
+ return rVertScrollBar.GetRangeMax();
+}
+
+void SalInstanceScrolledWindow::vadjustment_set_upper(int upper)
+{
+ ScrollBar& rVertScrollBar = m_xScrolledWindow->getVertScrollBar();
+ rVertScrollBar.SetRangeMax(upper);
+}
+
+int SalInstanceScrolledWindow::vadjustment_get_lower() const
+{
+ ScrollBar& rVertScrollBar = m_xScrolledWindow->getVertScrollBar();
+ return rVertScrollBar.GetRangeMin();
+}
+
+void SalInstanceScrolledWindow::vadjustment_set_lower(int lower)
+{
+ ScrollBar& rVertScrollBar = m_xScrolledWindow->getVertScrollBar();
+ rVertScrollBar.SetRangeMin(lower);
+}
+
+int SalInstanceScrolledWindow::vadjustment_get_page_size() const
+{
+ ScrollBar& rVertScrollBar = m_xScrolledWindow->getVertScrollBar();
+ return rVertScrollBar.GetVisibleSize();
+}
+
+void SalInstanceScrolledWindow::vadjustment_set_page_size(int size)
+{
+ ScrollBar& rVertScrollBar = m_xScrolledWindow->getVertScrollBar();
+ return rVertScrollBar.SetVisibleSize(size);
+}
+
+void SalInstanceScrolledWindow::vadjustment_set_page_increment(int size)
+{
+ ScrollBar& rVertScrollBar = m_xScrolledWindow->getVertScrollBar();
+ return rVertScrollBar.SetPageSize(size);
+}
+
+void SalInstanceScrolledWindow::vadjustment_set_step_increment(int size)
+{
+ ScrollBar& rVertScrollBar = m_xScrolledWindow->getVertScrollBar();
+ return rVertScrollBar.SetLineSize(size);
+}
+
+void SalInstanceScrolledWindow::set_vpolicy(VclPolicyType eVPolicy)
+{
+ WinBits nWinBits = m_xScrolledWindow->GetStyle() & ~(WB_AUTOVSCROLL | WB_VSCROLL);
+ if (eVPolicy == VclPolicyType::ALWAYS)
+ nWinBits |= WB_VSCROLL;
+ else if (eVPolicy == VclPolicyType::AUTOMATIC)
+ nWinBits |= WB_AUTOVSCROLL;
+ m_xScrolledWindow->SetStyle(nWinBits);
+ m_xScrolledWindow->queue_resize();
+}
+
+VclPolicyType SalInstanceScrolledWindow::get_vpolicy() const
+{
+ WinBits nWinBits = m_xScrolledWindow->GetStyle();
+ if (nWinBits & WB_AUTOVSCROLL)
+ return VclPolicyType::AUTOMATIC;
+ else if (nWinBits & WB_VSCROLL)
+ return VclPolicyType::ALWAYS;
+ return VclPolicyType::NEVER;
+}
+
+int SalInstanceScrolledWindow::get_scroll_thickness() const
+{
+ return m_xScrolledWindow->getVertScrollBar().get_preferred_size().Width();
+}
+
+void SalInstanceScrolledWindow::set_scroll_thickness(int nThickness)
+{
+ ScrollBar& rHorzScrollBar = m_xScrolledWindow->getHorzScrollBar();
+ ScrollBar& rVertScrollBar = m_xScrolledWindow->getVertScrollBar();
+ rHorzScrollBar.set_height_request(nThickness);
+ rVertScrollBar.set_width_request(nThickness);
+}
+
+void SalInstanceScrolledWindow::customize_scrollbars(const Color& rBackgroundColor,
+ const Color& rShadowColor,
+ const Color& rFaceColor)
+{
+ ScrollBar& rHorzScrollBar = m_xScrolledWindow->getHorzScrollBar();
+ ScrollBar& rVertScrollBar = m_xScrolledWindow->getVertScrollBar();
+ customize_scrollbars(rHorzScrollBar, Color(0, 0, 0), rBackgroundColor, rShadowColor,
+ rFaceColor);
+ customize_scrollbars(rVertScrollBar, Color(0, 0, 0), rBackgroundColor, rShadowColor,
+ rFaceColor);
+}
+
+SalInstanceScrolledWindow::~SalInstanceScrolledWindow()
+{
+ ScrollBar& rVertScrollBar = m_xScrolledWindow->getVertScrollBar();
+ rVertScrollBar.SetScrollHdl(m_aOrigVScrollHdl);
+}
+
+IMPL_LINK(SalInstanceScrolledWindow, VscrollHdl, ScrollBar*, pScrollBar, void)
+{
+ signal_vadjustment_changed();
+ if (!m_bUserManagedScrolling)
+ m_aOrigVScrollHdl.Call(pScrollBar);
+}
+
+IMPL_LINK_NOARG(SalInstanceScrolledWindow, HscrollHdl, ScrollBar*, void)
+{
+ signal_hadjustment_changed();
+ if (!m_bUserManagedScrolling)
+ m_aOrigHScrollHdl.Call(&m_xScrolledWindow->getHorzScrollBar());
+}
+
+namespace
+{
+class SalInstanceScrollbar : public SalInstanceWidget, public virtual weld::Scrollbar
+{
+private:
+ VclPtr<ScrollBar> m_xScrollBar;
+
+ DECL_LINK(ScrollHdl, ScrollBar*, void);
+
+public:
+ SalInstanceScrollbar(ScrollBar* pScrollbar, SalInstanceBuilder* pBuilder, bool bTakeOwnership)
+ : SalInstanceWidget(pScrollbar, pBuilder, bTakeOwnership)
+ , m_xScrollBar(pScrollbar)
+ {
+ m_xScrollBar->SetScrollHdl(LINK(this, SalInstanceScrollbar, ScrollHdl));
+ m_xScrollBar->EnableDrag();
+ }
+
+ virtual void adjustment_configure(int value, int lower, int upper, int step_increment,
+ int page_increment, int page_size) override
+ {
+ m_xScrollBar->SetRangeMin(lower);
+ m_xScrollBar->SetRangeMax(upper);
+ m_xScrollBar->SetLineSize(step_increment);
+ m_xScrollBar->SetPageSize(page_increment);
+ m_xScrollBar->SetThumbPos(value);
+ m_xScrollBar->SetVisibleSize(page_size);
+ }
+
+ virtual int adjustment_get_value() const override { return m_xScrollBar->GetThumbPos(); }
+
+ virtual void adjustment_set_value(int value) override { m_xScrollBar->SetThumbPos(value); }
+
+ virtual int adjustment_get_upper() const override { return m_xScrollBar->GetRangeMax(); }
+
+ virtual void adjustment_set_upper(int upper) override { m_xScrollBar->SetRangeMax(upper); }
+
+ virtual int adjustment_get_lower() const override { return m_xScrollBar->GetRangeMin(); }
+
+ virtual void adjustment_set_lower(int lower) override { m_xScrollBar->SetRangeMin(lower); }
+
+ virtual int adjustment_get_page_size() const override { return m_xScrollBar->GetVisibleSize(); }
+
+ virtual void adjustment_set_page_size(int size) override { m_xScrollBar->SetVisibleSize(size); }
+
+ virtual int adjustment_get_page_increment() const override
+ {
+ return m_xScrollBar->GetPageSize();
+ }
+
+ virtual void adjustment_set_page_increment(int size) override
+ {
+ m_xScrollBar->SetPageSize(size);
+ }
+
+ virtual int adjustment_get_step_increment() const override
+ {
+ return m_xScrollBar->GetLineSize();
+ }
+
+ virtual void adjustment_set_step_increment(int size) override
+ {
+ m_xScrollBar->SetLineSize(size);
+ }
+
+ virtual ScrollType get_scroll_type() const override { return m_xScrollBar->GetType(); }
+
+ virtual int get_scroll_thickness() const override
+ {
+ if (m_xScrollBar->GetStyle() & WB_HORZ)
+ return m_xScrollBar->get_preferred_size().Height();
+ return m_xScrollBar->get_preferred_size().Width();
+ }
+
+ virtual void set_scroll_thickness(int nThickness) override
+ {
+ if (m_xScrollBar->GetStyle() & WB_HORZ)
+ m_xScrollBar->set_height_request(nThickness);
+ else
+ m_xScrollBar->set_width_request(nThickness);
+ }
+};
+}
+
+IMPL_LINK_NOARG(SalInstanceScrollbar, ScrollHdl, ScrollBar*, void) { signal_adjustment_changed(); }
+
+SalInstanceNotebook::SalInstanceNotebook(TabControl* pNotebook, SalInstanceBuilder* pBuilder,
+ bool bTakeOwnership)
+ : SalInstanceWidget(pNotebook, pBuilder, bTakeOwnership)
+ , m_xNotebook(pNotebook)
+{
+ m_xNotebook->SetActivatePageHdl(LINK(this, SalInstanceNotebook, ActivatePageHdl));
+ m_xNotebook->SetDeactivatePageHdl(LINK(this, SalInstanceNotebook, DeactivatePageHdl));
+}
+
+int SalInstanceNotebook::get_current_page() const
+{
+ return m_xNotebook->GetPagePos(m_xNotebook->GetCurPageId());
+}
+
+OUString SalInstanceNotebook::get_page_ident(int nPage) const
+{
+ return m_xNotebook->GetPageName(m_xNotebook->GetPageId(nPage));
+}
+
+OUString SalInstanceNotebook::get_current_page_ident() const
+{
+ return m_xNotebook->GetPageName(m_xNotebook->GetCurPageId());
+}
+
+int SalInstanceNotebook::get_page_index(const OUString& rIdent) const
+{
+ sal_uInt16 nPageId = m_xNotebook->GetPageId(rIdent);
+ sal_uInt16 nPageIndex = m_xNotebook->GetPagePos(nPageId);
+ if (nPageIndex == TAB_PAGE_NOTFOUND)
+ return -1;
+ return nPageIndex;
+}
+
+weld::Container* SalInstanceNotebook::get_page(const OUString& rIdent) const
+{
+ int nPageIndex = get_page_index(rIdent);
+ if (nPageIndex == -1)
+ return nullptr;
+ sal_uInt16 nPageId = m_xNotebook->GetPageId(rIdent);
+ TabPage* pPage = m_xNotebook->GetTabPage(nPageId);
+ vcl::Window* pChild = pPage->GetChild(0);
+ if (m_aPages.size() < nPageIndex + 1U)
+ m_aPages.resize(nPageIndex + 1U);
+ if (!m_aPages[nPageIndex])
+ m_aPages[nPageIndex] = std::make_shared<SalInstanceContainer>(pChild, m_pBuilder, false);
+ return m_aPages[nPageIndex].get();
+}
+
+void SalInstanceNotebook::set_current_page(int nPage)
+{
+ m_xNotebook->SetCurPageId(m_xNotebook->GetPageId(nPage));
+}
+
+void SalInstanceNotebook::set_current_page(const OUString& rIdent)
+{
+ m_xNotebook->SetCurPageId(m_xNotebook->GetPageId(rIdent));
+}
+
+void SalInstanceNotebook::remove_page(const OUString& rIdent)
+{
+ sal_uInt16 nPageId = m_xNotebook->GetPageId(rIdent);
+ sal_uInt16 nPageIndex = m_xNotebook->GetPagePos(nPageId);
+ if (nPageIndex == TAB_PAGE_NOTFOUND)
+ return;
+
+ m_xNotebook->RemovePage(nPageId);
+ if (nPageIndex < m_aPages.size())
+ m_aPages.erase(m_aPages.begin() + nPageIndex);
+
+ auto iter = m_aAddedPages.find(rIdent);
+ if (iter != m_aAddedPages.end())
+ {
+ iter->second.second.disposeAndClear();
+ iter->second.first.disposeAndClear();
+ m_aAddedPages.erase(iter);
+ }
+}
+
+void SalInstanceNotebook::insert_page(const OUString& rIdent, const OUString& rLabel, int nPos)
+{
+ sal_uInt16 nPageCount = m_xNotebook->GetPageCount();
+ sal_uInt16 nLastPageId = nPageCount ? m_xNotebook->GetPageId(nPageCount - 1) : 0;
+ sal_uInt16 nNewPageId = nLastPageId + 1;
+ while (m_xNotebook->GetPagePos(nNewPageId) != TAB_PAGE_NOTFOUND)
+ ++nNewPageId;
+ m_xNotebook->InsertPage(nNewPageId, rLabel, nPos == -1 ? TAB_APPEND : nPos);
+ VclPtrInstance<TabPage> xPage(m_xNotebook);
+ VclPtrInstance<VclGrid> xGrid(xPage);
+ xPage->Show();
+ xGrid->set_hexpand(true);
+ xGrid->set_vexpand(true);
+ xGrid->Show();
+ m_xNotebook->SetTabPage(nNewPageId, xPage);
+ m_xNotebook->SetPageName(nNewPageId, rIdent);
+ m_aAddedPages.try_emplace(rIdent, xPage, xGrid);
+
+ if (nPos != -1)
+ {
+ unsigned int nPageIndex = static_cast<unsigned int>(nPos);
+ if (nPageIndex < m_aPages.size())
+ m_aPages.insert(m_aPages.begin() + nPageIndex, nullptr);
+ }
+}
+
+int SalInstanceNotebook::get_n_pages() const { return m_xNotebook->GetPageCount(); }
+
+OUString SalInstanceNotebook::get_tab_label_text(const OUString& rIdent) const
+{
+ return m_xNotebook->GetPageText(m_xNotebook->GetPageId(rIdent));
+}
+
+void SalInstanceNotebook::set_tab_label_text(const OUString& rIdent, const OUString& rText)
+{
+ return m_xNotebook->SetPageText(m_xNotebook->GetPageId(rIdent), rText);
+}
+
+void SalInstanceNotebook::set_show_tabs(bool bShow)
+{
+ m_xNotebook->set_property("show-tabs", OUString::boolean(bShow));
+}
+
+SalInstanceNotebook::~SalInstanceNotebook()
+{
+ for (auto& rItem : m_aAddedPages)
+ {
+ rItem.second.second.disposeAndClear();
+ rItem.second.first.disposeAndClear();
+ }
+ m_xNotebook->SetActivatePageHdl(Link<TabControl*, void>());
+ m_xNotebook->SetDeactivatePageHdl(Link<TabControl*, bool>());
+}
+
+IMPL_LINK_NOARG(SalInstanceNotebook, DeactivatePageHdl, TabControl*, bool)
+{
+ return !m_aLeavePageHdl.IsSet() || m_aLeavePageHdl.Call(get_current_page_ident());
+}
+
+IMPL_LINK_NOARG(SalInstanceNotebook, ActivatePageHdl, TabControl*, void)
+{
+ m_aEnterPageHdl.Call(get_current_page_ident());
+}
+
+SalInstanceVerticalNotebook::SalInstanceVerticalNotebook(VerticalTabControl* pNotebook,
+ SalInstanceBuilder* pBuilder,
+ bool bTakeOwnership)
+ : SalInstanceWidget(pNotebook, pBuilder, bTakeOwnership)
+ , m_xNotebook(pNotebook)
+{
+ m_xNotebook->SetActivatePageHdl(LINK(this, SalInstanceVerticalNotebook, ActivatePageHdl));
+ m_xNotebook->SetDeactivatePageHdl(LINK(this, SalInstanceVerticalNotebook, DeactivatePageHdl));
+}
+
+int SalInstanceVerticalNotebook::get_current_page() const
+{
+ return m_xNotebook->GetPagePos(m_xNotebook->GetCurPageId());
+}
+
+OUString SalInstanceVerticalNotebook::get_page_ident(int nPage) const
+{
+ return m_xNotebook->GetPageId(nPage);
+}
+
+OUString SalInstanceVerticalNotebook::get_current_page_ident() const
+{
+ return m_xNotebook->GetCurPageId();
+}
+
+int SalInstanceVerticalNotebook::get_page_index(const OUString& rIdent) const
+{
+ sal_uInt16 nPageIndex = m_xNotebook->GetPagePos(rIdent);
+ if (nPageIndex == TAB_PAGE_NOTFOUND)
+ return -1;
+ return nPageIndex;
+}
+
+weld::Container* SalInstanceVerticalNotebook::get_page(const OUString& rIdent) const
+{
+ int nPageIndex = get_page_index(rIdent);
+ if (nPageIndex == -1)
+ return nullptr;
+ auto pChild = m_xNotebook->GetPage(rIdent);
+ if (m_aPages.size() < nPageIndex + 1U)
+ m_aPages.resize(nPageIndex + 1U);
+ if (!m_aPages[nPageIndex])
+ m_aPages[nPageIndex].reset(new SalInstanceContainer(pChild, m_pBuilder, false));
+ return m_aPages[nPageIndex].get();
+}
+
+void SalInstanceVerticalNotebook::set_current_page(int nPage)
+{
+ m_xNotebook->SetCurPageId(m_xNotebook->GetPageId(nPage));
+}
+
+void SalInstanceVerticalNotebook::set_current_page(const OUString& rIdent)
+{
+ m_xNotebook->SetCurPageId(rIdent);
+}
+
+void SalInstanceVerticalNotebook::remove_page(const OUString& rIdent)
+{
+ sal_uInt16 nPageIndex = m_xNotebook->GetPagePos(rIdent);
+ if (nPageIndex == TAB_PAGE_NOTFOUND)
+ return;
+ m_xNotebook->RemovePage(rIdent);
+ if (nPageIndex < m_aPages.size())
+ m_aPages.erase(m_aPages.begin() + nPageIndex);
+}
+
+void SalInstanceVerticalNotebook::insert_page(const OUString& rIdent, const OUString& rLabel,
+ int nPos)
+{
+ VclPtrInstance<VclGrid> xGrid(m_xNotebook->GetPageParent());
+ xGrid->set_hexpand(true);
+ xGrid->set_vexpand(true);
+ m_xNotebook->InsertPage(rIdent, rLabel, Image(), "", xGrid, nPos);
+
+ if (nPos != -1)
+ {
+ unsigned int nPageIndex = static_cast<unsigned int>(nPos);
+ if (nPageIndex < m_aPages.size())
+ m_aPages.insert(m_aPages.begin() + nPageIndex, nullptr);
+ }
+}
+
+int SalInstanceVerticalNotebook::get_n_pages() const { return m_xNotebook->GetPageCount(); }
+
+void SalInstanceVerticalNotebook::set_tab_label_text(const OUString& rIdent, const OUString& rText)
+{
+ return m_xNotebook->SetPageText(rIdent, rText);
+}
+
+OUString SalInstanceVerticalNotebook::get_tab_label_text(const OUString& rIdent) const
+{
+ return m_xNotebook->GetPageText(rIdent);
+}
+
+void SalInstanceVerticalNotebook::set_show_tabs(bool /*bShow*/)
+{
+ // if someone needs this they will have to implement it in VerticalTabControl
+ assert(false && "not implemented");
+}
+
+SalInstanceVerticalNotebook::~SalInstanceVerticalNotebook()
+{
+ m_xNotebook->SetActivatePageHdl(Link<VerticalTabControl*, void>());
+ m_xNotebook->SetDeactivatePageHdl(Link<VerticalTabControl*, bool>());
+}
+
+IMPL_LINK_NOARG(SalInstanceVerticalNotebook, DeactivatePageHdl, VerticalTabControl*, bool)
+{
+ return !m_aLeavePageHdl.IsSet() || m_aLeavePageHdl.Call(get_current_page_ident());
+}
+
+IMPL_LINK_NOARG(SalInstanceVerticalNotebook, ActivatePageHdl, VerticalTabControl*, void)
+{
+ m_aEnterPageHdl.Call(get_current_page_ident());
+}
+
+SalInstanceButton::SalInstanceButton(::Button* pButton, SalInstanceBuilder* pBuilder,
+ bool bTakeOwnership)
+ : SalInstanceWidget(pButton, pBuilder, bTakeOwnership)
+ , m_xButton(pButton)
+ , m_aOldClickHdl(pButton->GetClickHdl())
+{
+ m_xButton->SetClickHdl(LINK(this, SalInstanceButton, ClickHdl));
+}
+
+void SalInstanceButton::set_label(const OUString& rText) { m_xButton->SetText(rText); }
+
+void SalInstanceButton::set_image(VirtualDevice* pDevice)
+{
+ m_xButton->SetImageAlign(ImageAlign::Left);
+ if (pDevice)
+ m_xButton->SetModeImage(createImage(*pDevice));
+ else
+ m_xButton->SetModeImage(Image());
+}
+
+void SalInstanceButton::set_image(const css::uno::Reference<css::graphic::XGraphic>& rImage)
+{
+ m_xButton->SetImageAlign(ImageAlign::Left);
+ m_xButton->SetModeImage(Image(rImage));
+}
+
+void SalInstanceButton::set_from_icon_name(const OUString& rIconName)
+{
+ m_xButton->SetModeImage(Image(StockImage::Yes, rIconName));
+}
+
+static void set_label_wrap(Control& rWidget, bool wrap)
+{
+ WinBits nBits = rWidget.GetStyle();
+ nBits &= ~WB_WORDBREAK;
+ if (wrap)
+ nBits |= WB_WORDBREAK;
+ rWidget.SetStyle(nBits);
+ rWidget.queue_resize();
+}
+
+void SalInstanceButton::set_font(const vcl::Font& rFont)
+{
+ m_xButton->SetControlFont(rFont);
+ m_xButton->Invalidate();
+}
+
+void SalInstanceButton::set_custom_button(VirtualDevice* pDevice)
+{
+ if (pDevice)
+ m_xButton->SetCustomButtonImage(createImage(*pDevice));
+ else
+ m_xButton->SetCustomButtonImage(Image());
+ m_xButton->Invalidate();
+}
+
+OUString SalInstanceButton::get_label() const { return m_xButton->GetText(); }
+
+SalInstanceButton::~SalInstanceButton() { m_xButton->SetClickHdl(Link<::Button*, void>()); }
+
+IMPL_LINK(SalInstanceButton, ClickHdl, ::Button*, pButton, void)
+{
+ //if there's no handler set, disengage our intercept and
+ //run the click again to get default behaviour for cancel/ok
+ //etc buttons.
+ if (!m_aClickHdl.IsSet())
+ {
+ pButton->SetClickHdl(m_aOldClickHdl);
+ pButton->Click();
+ pButton->SetClickHdl(LINK(this, SalInstanceButton, ClickHdl));
+ return;
+ }
+ signal_clicked();
+}
+
+weld::Button* SalInstanceDialog::weld_widget_for_response(int nResponse)
+{
+ PushButton* pButton = dynamic_cast<PushButton*>(m_xDialog->get_widget_for_response(nResponse));
+ return pButton ? new SalInstanceButton(pButton, nullptr, false) : nullptr;
+}
+
+weld::Button* SalInstanceAssistant::weld_widget_for_response(int nResponse)
+{
+ PushButton* pButton = nullptr;
+ if (nResponse == RET_YES)
+ pButton = m_xWizard->m_pNextPage;
+ else if (nResponse == RET_NO)
+ pButton = m_xWizard->m_pPrevPage;
+ else if (nResponse == RET_OK)
+ pButton = m_xWizard->m_pFinish;
+ else if (nResponse == RET_CANCEL)
+ pButton = m_xWizard->m_pCancel;
+ else if (nResponse == RET_HELP)
+ pButton = m_xWizard->m_pHelp;
+ if (pButton)
+ return new SalInstanceButton(pButton, nullptr, false);
+ return nullptr;
+}
+
+SalInstanceMenuButton::SalInstanceMenuButton(::MenuButton* pButton, SalInstanceBuilder* pBuilder,
+ bool bTakeOwnership)
+ : SalInstanceButton(pButton, pBuilder, bTakeOwnership)
+ , m_xMenuButton(pButton)
+ , m_nLastId(0)
+{
+ m_xMenuButton->SetActivateHdl(LINK(this, SalInstanceMenuButton, ActivateHdl));
+ m_xMenuButton->SetSelectHdl(LINK(this, SalInstanceMenuButton, MenuSelectHdl));
+ if (PopupMenu* pMenu = m_xMenuButton->GetPopupMenu())
+ {
+ pMenu->SetMenuFlags(MenuFlags::NoAutoMnemonics);
+ const auto nCount = pMenu->GetItemCount();
+ m_nLastId = nCount ? pMenu->GetItemId(nCount - 1) : 0;
+ }
+}
+
+void SalInstanceMenuButton::set_active(bool active)
+{
+ if (active == get_active())
+ return;
+ if (active)
+ m_xMenuButton->ExecuteMenu();
+ else
+ m_xMenuButton->CancelMenu();
+}
+
+bool SalInstanceMenuButton::get_active() const { return m_xMenuButton->InPopupMode(); }
+
+void SalInstanceMenuButton::set_inconsistent(bool /*inconsistent*/)
+{
+ //not available
+}
+
+bool SalInstanceMenuButton::get_inconsistent() const { return false; }
+
+void SalInstanceMenuButton::insert_item(int pos, const OUString& rId, const OUString& rStr,
+ const OUString* pIconName, VirtualDevice* pImageSurface,
+ TriState eCheckRadioFalse)
+{
+ m_nLastId = insert_to_menu(m_nLastId, m_xMenuButton->GetPopupMenu(), pos, rId, rStr, pIconName,
+ pImageSurface, nullptr, eCheckRadioFalse);
+}
+
+void SalInstanceMenuButton::insert_separator(int pos, const OUString& rId)
+{
+ auto nInsertPos = pos == -1 ? MENU_APPEND : pos;
+ m_xMenuButton->GetPopupMenu()->InsertSeparator(rId, nInsertPos);
+}
+
+void SalInstanceMenuButton::set_item_sensitive(const OUString& rIdent, bool bSensitive)
+{
+ PopupMenu* pMenu = m_xMenuButton->GetPopupMenu();
+ pMenu->EnableItem(rIdent, bSensitive);
+}
+
+void SalInstanceMenuButton::remove_item(const OUString& rId)
+{
+ PopupMenu* pMenu = m_xMenuButton->GetPopupMenu();
+ pMenu->RemoveItem(pMenu->GetItemPos(pMenu->GetItemId(rId)));
+}
+
+void SalInstanceMenuButton::clear()
+{
+ PopupMenu* pMenu = m_xMenuButton->GetPopupMenu();
+ pMenu->Clear();
+}
+
+void SalInstanceMenuButton::set_item_active(const OUString& rIdent, bool bActive)
+{
+ PopupMenu* pMenu = m_xMenuButton->GetPopupMenu();
+ pMenu->CheckItem(rIdent, bActive);
+}
+
+void SalInstanceMenuButton::set_item_label(const OUString& rIdent, const OUString& rText)
+{
+ PopupMenu* pMenu = m_xMenuButton->GetPopupMenu();
+ pMenu->SetItemText(pMenu->GetItemId(rIdent), rText);
+}
+
+OUString SalInstanceMenuButton::get_item_label(const OUString& rIdent) const
+{
+ PopupMenu* pMenu = m_xMenuButton->GetPopupMenu();
+ return pMenu->GetItemText(pMenu->GetItemId(rIdent));
+}
+
+void SalInstanceMenuButton::set_item_visible(const OUString& rIdent, bool bShow)
+{
+ PopupMenu* pMenu = m_xMenuButton->GetPopupMenu();
+ pMenu->ShowItem(pMenu->GetItemId(rIdent), bShow);
+}
+
+void SalInstanceMenuButton::set_popover(weld::Widget* pPopover)
+{
+ SalInstanceWidget* pPopoverWidget = dynamic_cast<SalInstanceWidget*>(pPopover);
+ m_xMenuButton->SetPopover(pPopoverWidget ? pPopoverWidget->getWidget() : nullptr);
+}
+
+SalInstanceMenuButton::~SalInstanceMenuButton()
+{
+ m_xMenuButton->SetSelectHdl(Link<::MenuButton*, void>());
+ m_xMenuButton->SetActivateHdl(Link<::MenuButton*, void>());
+}
+
+IMPL_LINK_NOARG(SalInstanceMenuButton, MenuSelectHdl, ::MenuButton*, void)
+{
+ signal_selected(m_xMenuButton->GetCurItemIdent());
+}
+
+IMPL_LINK_NOARG(SalInstanceMenuButton, ActivateHdl, ::MenuButton*, void)
+{
+ if (notify_events_disabled())
+ return;
+ signal_toggled();
+}
+
+namespace
+{
+class SalInstanceMenuToggleButton : public SalInstanceMenuButton,
+ public virtual weld::MenuToggleButton
+{
+private:
+ VclPtr<::MenuToggleButton> m_xMenuToggleButton;
+
+public:
+ SalInstanceMenuToggleButton(::MenuToggleButton* pButton, SalInstanceBuilder* pBuilder,
+ bool bTakeOwnership)
+ : SalInstanceMenuButton(pButton, pBuilder, bTakeOwnership)
+ , m_xMenuToggleButton(pButton)
+ {
+ m_xMenuToggleButton->SetDelayMenu(true);
+ m_xMenuToggleButton->SetDropDown(PushButtonDropdownStyle::SplitMenuButton);
+ }
+
+ virtual void set_active(bool active) override
+ {
+ disable_notify_events();
+ m_xMenuToggleButton->SetActive(active);
+ enable_notify_events();
+ }
+
+ virtual bool get_active() const override { return m_xMenuToggleButton->GetActive(); }
+};
+}
+
+IMPL_LINK(SalInstanceLinkButton, ClickHdl, FixedHyperlink&, rButton, void)
+{
+ bool bConsumed = signal_activate_link();
+ if (!bConsumed)
+ m_aOrigClickHdl.Call(rButton);
+}
+
+void SalInstanceLinkButton::set_label_wrap(bool bWrap) { ::set_label_wrap(*m_xButton, bWrap); }
+
+SalInstanceRadioButton::SalInstanceRadioButton(::RadioButton* pButton, SalInstanceBuilder* pBuilder,
+ bool bTakeOwnership)
+ : SalInstanceButton(pButton, pBuilder, bTakeOwnership)
+ , m_xRadioButton(pButton)
+{
+ m_xRadioButton->SetToggleHdl(LINK(this, SalInstanceRadioButton, ToggleHdl));
+}
+
+void SalInstanceRadioButton::set_active(bool active)
+{
+ disable_notify_events();
+ m_xRadioButton->Check(active);
+ enable_notify_events();
+}
+
+bool SalInstanceRadioButton::get_active() const { return m_xRadioButton->IsChecked(); }
+
+void SalInstanceRadioButton::set_image(VirtualDevice* pDevice)
+{
+ m_xRadioButton->SetImageAlign(ImageAlign::Center);
+ if (pDevice)
+ m_xRadioButton->SetModeImage(createImage(*pDevice));
+ else
+ m_xRadioButton->SetModeImage(Image());
+}
+
+void SalInstanceRadioButton::set_image(const css::uno::Reference<css::graphic::XGraphic>& rImage)
+{
+ m_xRadioButton->SetImageAlign(ImageAlign::Center);
+ m_xRadioButton->SetModeImage(Image(rImage));
+}
+
+void SalInstanceRadioButton::set_from_icon_name(const OUString& rIconName)
+{
+ m_xRadioButton->SetModeRadioImage(Image(StockImage::Yes, rIconName));
+}
+
+void SalInstanceRadioButton::set_inconsistent(bool /*inconsistent*/)
+{
+ //not available
+}
+
+bool SalInstanceRadioButton::get_inconsistent() const { return false; }
+
+void SalInstanceRadioButton::set_label_wrap(bool bWrap)
+{
+ ::set_label_wrap(*m_xRadioButton, bWrap);
+}
+
+SalInstanceRadioButton::~SalInstanceRadioButton()
+{
+ m_xRadioButton->SetToggleHdl(Link<::RadioButton&, void>());
+}
+
+IMPL_LINK_NOARG(SalInstanceRadioButton, ToggleHdl, ::RadioButton&, void)
+{
+ if (notify_events_disabled())
+ return;
+ signal_toggled();
+}
+
+IMPL_LINK(SalInstanceToggleButton, ToggleListener, VclWindowEvent&, rEvent, void)
+{
+ if (notify_events_disabled())
+ return;
+ if (rEvent.GetId() == VclEventId::PushbuttonToggle)
+ signal_toggled();
+}
+
+SalInstanceCheckButton::SalInstanceCheckButton(CheckBox* pButton, SalInstanceBuilder* pBuilder,
+ bool bTakeOwnership)
+ : SalInstanceButton(pButton, pBuilder, bTakeOwnership)
+ , m_xCheckButton(pButton)
+{
+ m_xCheckButton->SetToggleHdl(LINK(this, SalInstanceCheckButton, ToggleHdl));
+}
+
+void SalInstanceCheckButton::set_active(bool active)
+{
+ disable_notify_events();
+ m_xCheckButton->EnableTriState(false);
+ m_xCheckButton->Check(active);
+ enable_notify_events();
+}
+
+bool SalInstanceCheckButton::get_active() const { return m_xCheckButton->IsChecked(); }
+
+void SalInstanceCheckButton::set_inconsistent(bool inconsistent)
+{
+ disable_notify_events();
+ m_xCheckButton->EnableTriState(true);
+ m_xCheckButton->SetState(inconsistent ? TRISTATE_INDET : TRISTATE_FALSE);
+ enable_notify_events();
+}
+
+bool SalInstanceCheckButton::get_inconsistent() const
+{
+ return m_xCheckButton->GetState() == TRISTATE_INDET;
+}
+
+void SalInstanceCheckButton::set_label_wrap(bool bWrap)
+{
+ ::set_label_wrap(*m_xCheckButton, bWrap);
+}
+
+SalInstanceCheckButton::~SalInstanceCheckButton()
+{
+ m_xCheckButton->SetToggleHdl(Link<CheckBox&, void>());
+}
+
+IMPL_LINK_NOARG(SalInstanceCheckButton, ToggleHdl, CheckBox&, void)
+{
+ if (notify_events_disabled())
+ return;
+ m_xCheckButton->EnableTriState(false);
+ signal_toggled();
+}
+
+namespace
+{
+class SalInstanceScale : public SalInstanceWidget, public virtual weld::Scale
+{
+private:
+ VclPtr<Slider> m_xScale;
+
+ DECL_LINK(SlideHdl, Slider*, void);
+
+public:
+ SalInstanceScale(Slider* pScale, SalInstanceBuilder* pBuilder, bool bTakeOwnership)
+ : SalInstanceWidget(pScale, pBuilder, bTakeOwnership)
+ , m_xScale(pScale)
+ {
+ m_xScale->SetSlideHdl(LINK(this, SalInstanceScale, SlideHdl));
+ }
+
+ virtual void set_value(int value) override { m_xScale->SetThumbPos(value); }
+
+ virtual void set_range(int min, int max) override
+ {
+ m_xScale->SetRangeMin(min);
+ m_xScale->SetRangeMax(max);
+ }
+
+ virtual int get_value() const override { return m_xScale->GetThumbPos(); }
+
+ virtual void set_increments(int step, int page) override
+ {
+ m_xScale->SetLineSize(step);
+ m_xScale->SetPageSize(page);
+ }
+
+ virtual void get_increments(int& step, int& page) const override
+ {
+ step = m_xScale->GetLineSize();
+ page = m_xScale->GetPageSize();
+ }
+
+ virtual ~SalInstanceScale() override { m_xScale->SetSlideHdl(Link<Slider*, void>()); }
+};
+}
+
+IMPL_LINK_NOARG(SalInstanceScale, SlideHdl, Slider*, void) { signal_value_changed(); }
+
+namespace
+{
+class SalInstanceSpinner : public SalInstanceWidget, public virtual weld::Spinner
+{
+private:
+ VclPtr<Throbber> m_xThrobber;
+
+public:
+ SalInstanceSpinner(Throbber* pThrobber, SalInstanceBuilder* pBuilder, bool bTakeOwnership)
+ : SalInstanceWidget(pThrobber, pBuilder, bTakeOwnership)
+ , m_xThrobber(pThrobber)
+ {
+ }
+
+ virtual void start() override { m_xThrobber->start(); }
+
+ virtual void stop() override { m_xThrobber->stop(); }
+};
+
+class SalInstanceProgressBar : public SalInstanceWidget, public virtual weld::ProgressBar
+{
+private:
+ VclPtr<::ProgressBar> m_xProgressBar;
+
+public:
+ SalInstanceProgressBar(::ProgressBar* pProgressBar, SalInstanceBuilder* pBuilder,
+ bool bTakeOwnership)
+ : SalInstanceWidget(pProgressBar, pBuilder, bTakeOwnership)
+ , m_xProgressBar(pProgressBar)
+ {
+ }
+
+ virtual void set_percentage(int value) override { m_xProgressBar->SetValue(value); }
+
+ virtual OUString get_text() const override { return m_xProgressBar->GetText(); }
+
+ virtual void set_text(const OUString& rText) override { m_xProgressBar->SetText(rText); }
+};
+
+class SalInstanceLevelBar : public SalInstanceWidget, public virtual weld::LevelBar
+{
+private:
+ VclPtr<::ProgressBar> m_xLevelBar;
+
+public:
+ SalInstanceLevelBar(::ProgressBar* pLevelBar, SalInstanceBuilder* pBuilder, bool bTakeOwnership)
+ : SalInstanceWidget(pLevelBar, pBuilder, bTakeOwnership)
+ , m_xLevelBar(pLevelBar)
+ {
+ }
+
+ virtual void set_percentage(double fPercentage) override
+ {
+ m_xLevelBar->SetValue(static_cast<sal_uInt16>(fPercentage));
+ }
+};
+}
+
+IMPL_LINK_NOARG(SalInstanceCalendar, SelectHdl, ::Calendar*, void)
+{
+ if (notify_events_disabled())
+ return;
+ signal_selected();
+}
+
+IMPL_LINK_NOARG(SalInstanceCalendar, ActivateHdl, ::Calendar*, void)
+{
+ if (notify_events_disabled())
+ return;
+ signal_activated();
+}
+
+SalInstanceImage::SalInstanceImage(FixedImage* pImage, SalInstanceBuilder* pBuilder,
+ bool bTakeOwnership)
+ : SalInstanceWidget(pImage, pBuilder, bTakeOwnership)
+ , m_xImage(pImage)
+{
+}
+
+void SalInstanceImage::set_from_icon_name(const OUString& rIconName)
+{
+ m_xImage->SetImage(::Image(StockImage::Yes, rIconName));
+}
+
+void SalInstanceImage::set_image(VirtualDevice* pDevice)
+{
+ if (pDevice)
+ m_xImage->SetImage(createImage(*pDevice));
+ else
+ m_xImage->SetImage(::Image());
+}
+
+void SalInstanceImage::set_image(const css::uno::Reference<css::graphic::XGraphic>& rImage)
+{
+ m_xImage->SetImage(::Image(rImage));
+}
+
+WeldTextFilter::WeldTextFilter(Link<OUString&, bool>& rInsertTextHdl)
+ : TextFilter(OUString())
+ , m_rInsertTextHdl(rInsertTextHdl)
+{
+}
+
+OUString WeldTextFilter::filter(const OUString& rText)
+{
+ if (!m_rInsertTextHdl.IsSet())
+ return rText;
+ OUString sText(rText);
+ const bool bContinue = m_rInsertTextHdl.Call(sText);
+ if (!bContinue)
+ return OUString();
+ return sText;
+}
+
+SalInstanceEntry::SalInstanceEntry(Edit* pEntry, SalInstanceBuilder* pBuilder, bool bTakeOwnership)
+ : SalInstanceWidget(pEntry, pBuilder, bTakeOwnership)
+ , m_xEntry(pEntry)
+ , m_aTextFilter(m_aInsertTextHdl)
+{
+ m_xEntry->SetModifyHdl(LINK(this, SalInstanceEntry, ChangeHdl));
+ m_xEntry->SetActivateHdl(LINK(this, SalInstanceEntry, ActivateHdl));
+ m_xEntry->SetTextFilter(&m_aTextFilter);
+}
+
+void SalInstanceEntry::set_text(const OUString& rText)
+{
+ disable_notify_events();
+ m_xEntry->SetText(rText);
+ enable_notify_events();
+}
+
+OUString SalInstanceEntry::get_text() const { return m_xEntry->GetText(); }
+
+void SalInstanceEntry::set_width_chars(int nChars) { m_xEntry->SetWidthInChars(nChars); }
+
+int SalInstanceEntry::get_width_chars() const { return m_xEntry->GetWidthInChars(); }
+
+void SalInstanceEntry::set_max_length(int nChars) { m_xEntry->SetMaxTextLen(nChars); }
+
+void SalInstanceEntry::select_region(int nStartPos, int nEndPos)
+{
+ disable_notify_events();
+ tools::Long nStart = nStartPos < 0 ? SELECTION_MAX : nStartPos;
+ tools::Long nEnd = nEndPos < 0 ? SELECTION_MAX : nEndPos;
+ m_xEntry->SetSelection(Selection(nStart, nEnd));
+ enable_notify_events();
+}
+
+bool SalInstanceEntry::get_selection_bounds(int& rStartPos, int& rEndPos)
+{
+ const Selection& rSelection = m_xEntry->GetSelection();
+ rStartPos = rSelection.Min();
+ rEndPos = rSelection.Max();
+ return rSelection.Len();
+}
+
+void SalInstanceEntry::replace_selection(const OUString& rText)
+{
+ m_xEntry->ReplaceSelected(rText);
+}
+
+void SalInstanceEntry::set_position(int nCursorPos)
+{
+ disable_notify_events();
+ if (nCursorPos < 0)
+ m_xEntry->SetCursorAtLast();
+ else
+ m_xEntry->SetSelection(Selection(nCursorPos, nCursorPos));
+ enable_notify_events();
+}
+
+int SalInstanceEntry::get_position() const { return m_xEntry->GetSelection().Max(); }
+
+void SalInstanceEntry::set_editable(bool bEditable) { m_xEntry->SetReadOnly(!bEditable); }
+
+bool SalInstanceEntry::get_editable() const { return !m_xEntry->IsReadOnly(); }
+
+void SalInstanceEntry::set_overwrite_mode(bool bOn) { m_xEntry->SetInsertMode(!bOn); }
+
+bool SalInstanceEntry::get_overwrite_mode() const { return !m_xEntry->IsInsertMode(); }
+
+namespace
+{
+void set_message_type(Edit* pEntry, weld::EntryMessageType eType)
+{
+ switch (eType)
+ {
+ case weld::EntryMessageType::Normal:
+ pEntry->SetForceControlBackground(false);
+ pEntry->SetControlForeground();
+ pEntry->SetControlBackground();
+ break;
+ case weld::EntryMessageType::Warning:
+ // tdf#114603: enable setting the background to a different color;
+ // relevant for GTK; see also #i75179#
+ pEntry->SetForceControlBackground(true);
+ pEntry->SetControlForeground(COL_BLACK);
+ pEntry->SetControlBackground(0xffff38); // "light yellow 1"
+ break;
+ case weld::EntryMessageType::Error:
+ // tdf#114603: enable setting the background to a different color;
+ // relevant for GTK; see also #i75179#
+ pEntry->SetForceControlBackground(true);
+ pEntry->SetControlForeground(COL_BLACK); // contrast of 5.87 to the red background
+ pEntry->SetControlBackground(0xff3838); // "light red 1"
+ break;
+ }
+}
+}
+
+void SalInstanceEntry::set_message_type(weld::EntryMessageType eType)
+{
+ ::set_message_type(m_xEntry, eType);
+}
+
+void SalInstanceEntry::set_font(const vcl::Font& rFont)
+{
+ m_xEntry->SetControlFont(rFont);
+ m_xEntry->Invalidate();
+}
+
+void SalInstanceEntry::set_font_color(const Color& rColor)
+{
+ if (rColor == COL_AUTO)
+ m_xEntry->SetControlForeground();
+ else
+ m_xEntry->SetControlForeground(rColor);
+}
+
+void SalInstanceEntry::connect_cursor_position(const Link<Entry&, void>& rLink)
+{
+ assert(!m_aCursorPositionHdl.IsSet());
+ m_xEntry->AddEventListener(LINK(this, SalInstanceEntry, CursorListener));
+ weld::Entry::connect_cursor_position(rLink);
+}
+
+void SalInstanceEntry::set_placeholder_text(const OUString& rText)
+{
+ m_xEntry->SetPlaceholderText(rText);
+}
+
+Edit& SalInstanceEntry::getEntry() { return *m_xEntry; }
+
+void SalInstanceEntry::fire_signal_changed() { signal_changed(); }
+
+void SalInstanceEntry::cut_clipboard()
+{
+ m_xEntry->Cut();
+ m_xEntry->Modify();
+}
+
+void SalInstanceEntry::copy_clipboard() { m_xEntry->Copy(); }
+
+void SalInstanceEntry::paste_clipboard()
+{
+ m_xEntry->Paste();
+ m_xEntry->Modify();
+}
+
+namespace
+{
+void set_alignment(Edit& rEntry, TxtAlign eXAlign)
+{
+ WinBits nAlign(0);
+ switch (eXAlign)
+ {
+ case TxtAlign::Left:
+ nAlign = WB_LEFT;
+ break;
+ case TxtAlign::Center:
+ nAlign = WB_CENTER;
+ break;
+ case TxtAlign::Right:
+ nAlign = WB_RIGHT;
+ break;
+ }
+ WinBits nBits = rEntry.GetStyle();
+ nBits &= ~(WB_LEFT | WB_CENTER | WB_RIGHT);
+ rEntry.SetStyle(nBits | nAlign);
+}
+}
+
+void SalInstanceEntry::set_alignment(TxtAlign eXAlign) { ::set_alignment(*m_xEntry, eXAlign); }
+
+SalInstanceEntry::~SalInstanceEntry()
+{
+ if (m_aCursorPositionHdl.IsSet())
+ m_xEntry->RemoveEventListener(LINK(this, SalInstanceEntry, CursorListener));
+ m_xEntry->SetTextFilter(nullptr);
+ m_xEntry->SetActivateHdl(Link<Edit&, bool>());
+ m_xEntry->SetModifyHdl(Link<Edit&, void>());
+}
+
+IMPL_LINK_NOARG(SalInstanceEntry, ChangeHdl, Edit&, void) { signal_changed(); }
+
+IMPL_LINK(SalInstanceEntry, CursorListener, VclWindowEvent&, rEvent, void)
+{
+ if (notify_events_disabled())
+ return;
+ if (rEvent.GetId() == VclEventId::EditSelectionChanged
+ || rEvent.GetId() == VclEventId::EditCaretChanged)
+ signal_cursor_position();
+}
+
+IMPL_LINK_NOARG(SalInstanceEntry, ActivateHdl, Edit&, bool) { return m_aActivateHdl.Call(*this); }
+
+class SalInstanceTreeView;
+
+static SalInstanceTreeView* g_DragSource;
+
+namespace
+{
+// tdf#131581 if the TreeView is hidden then there are possibly additional
+// optimizations available
+class UpdateGuardIfHidden
+{
+private:
+ SvTabListBox& m_rTreeView;
+ bool m_bOrigUpdate;
+ bool m_bOrigEnableInvalidate;
+
+public:
+ UpdateGuardIfHidden(SvTabListBox& rTreeView)
+ : m_rTreeView(rTreeView)
+ // tdf#136962 only do SetUpdateMode(false) optimization if the widget is currently hidden
+ , m_bOrigUpdate(!m_rTreeView.IsVisible() && m_rTreeView.IsUpdateMode())
+ // tdf#137432 only do EnableInvalidate(false) optimization if the widget is currently hidden
+ , m_bOrigEnableInvalidate(!m_rTreeView.IsVisible()
+ && m_rTreeView.GetModel()->IsEnableInvalidate())
+ {
+ if (m_bOrigUpdate)
+ m_rTreeView.SetUpdateMode(false);
+ if (m_bOrigEnableInvalidate)
+ m_rTreeView.GetModel()->EnableInvalidate(false);
+ }
+
+ ~UpdateGuardIfHidden()
+ {
+ if (m_bOrigEnableInvalidate)
+ m_rTreeView.GetModel()->EnableInvalidate(true);
+ if (m_bOrigUpdate)
+ m_rTreeView.SetUpdateMode(true);
+ }
+};
+}
+
+// Each row has a cell for the expander image, (and an optional cell for a
+// checkbutton if enable_toggle_buttons has been called) which precede
+// index 0
+int SalInstanceTreeView::to_internal_model(int col) const
+{
+ if (m_xTreeView->nTreeFlags & SvTreeFlags::CHKBTN)
+ ++col; // skip checkbutton column
+ ++col; //skip expander column
+ return col;
+}
+
+int SalInstanceTreeView::to_external_model(int col) const
+{
+ if (m_xTreeView->nTreeFlags & SvTreeFlags::CHKBTN)
+ --col; // skip checkbutton column
+ --col; //skip expander column
+ return col;
+}
+
+bool SalInstanceTreeView::IsDummyEntry(SvTreeListEntry* pEntry) const
+{
+ return o3tl::trim(m_xTreeView->GetEntryText(pEntry)) == u"<dummy>";
+}
+
+SvTreeListEntry* SalInstanceTreeView::GetPlaceHolderChild(SvTreeListEntry* pEntry) const
+{
+ if (pEntry->HasChildren())
+ {
+ auto pChild = m_xTreeView->FirstChild(pEntry);
+ assert(pChild);
+ if (IsDummyEntry(pChild))
+ return pChild;
+ }
+ return nullptr;
+}
+
+void SalInstanceTreeView::set_font_color(SvTreeListEntry* pEntry, const Color& rColor)
+{
+ if (rColor == COL_AUTO)
+ pEntry->SetTextColor(std::optional<Color>());
+ else
+ pEntry->SetTextColor(rColor);
+}
+
+void SalInstanceTreeView::AddStringItem(SvTreeListEntry* pEntry, const OUString& rStr, int nCol)
+{
+ auto xCell = std::make_unique<SvLBoxString>(rStr);
+ if (m_aCustomRenders.count(nCol))
+ xCell->SetCustomRender();
+ pEntry->AddItem(std::move(xCell));
+}
+
+void SalInstanceTreeView::do_insert(const weld::TreeIter* pParent, int pos, const OUString* pStr,
+ const OUString* pId, const OUString* pIconName,
+ const VirtualDevice* pImageSurface, bool bChildrenOnDemand,
+ weld::TreeIter* pRet, bool bIsSeparator)
+{
+ disable_notify_events();
+ const SalInstanceTreeIter* pVclIter = static_cast<const SalInstanceTreeIter*>(pParent);
+ SvTreeListEntry* iter = pVclIter ? pVclIter->iter : nullptr;
+ auto nInsertPos = pos == -1 ? TREELIST_APPEND : pos;
+ void* pUserData;
+ if (pId)
+ {
+ m_aUserData.emplace_back(std::make_unique<OUString>(*pId));
+ pUserData = m_aUserData.back().get();
+ }
+ else
+ pUserData = nullptr;
+
+ SvTreeListEntry* pEntry = new SvTreeListEntry;
+ if (bIsSeparator)
+ pEntry->SetFlags(pEntry->GetFlags() | SvTLEntryFlags::IS_SEPARATOR);
+
+ if (m_xTreeView->nTreeFlags & SvTreeFlags::CHKBTN)
+ AddStringItem(pEntry, "", -1);
+
+ if (pIconName || pImageSurface)
+ {
+ Image aImage(pIconName ? createImage(*pIconName) : createImage(*pImageSurface));
+ pEntry->AddItem(std::make_unique<SvLBoxContextBmp>(aImage, aImage, false));
+ }
+ else
+ {
+ Image aDummy;
+ pEntry->AddItem(std::make_unique<SvLBoxContextBmp>(aDummy, aDummy, false));
+ }
+ if (pStr)
+ AddStringItem(pEntry, *pStr, pEntry->ItemCount());
+ pEntry->SetUserData(pUserData);
+ m_xTreeView->Insert(pEntry, iter, nInsertPos);
+
+ if (pRet)
+ {
+ SalInstanceTreeIter* pVclRetIter = static_cast<SalInstanceTreeIter*>(pRet);
+ pVclRetIter->iter = pEntry;
+ }
+
+ if (bChildrenOnDemand)
+ {
+ SvTreeListEntry* pPlaceHolder
+ = m_xTreeView->InsertEntry("<dummy>", pEntry, false, 0, nullptr);
+ SvViewDataEntry* pViewData = m_xTreeView->GetViewDataEntry(pPlaceHolder);
+ pViewData->SetSelectable(false);
+ }
+
+ if (bIsSeparator)
+ {
+ SvViewDataEntry* pViewData = m_xTreeView->GetViewDataEntry(pEntry);
+ pViewData->SetSelectable(false);
+ }
+
+ enable_notify_events();
+}
+
+void SalInstanceTreeView::update_checkbutton_column_width(SvTreeListEntry* pEntry)
+{
+ SvViewDataEntry* pViewData = m_xTreeView->GetViewDataEntry(pEntry);
+ m_xTreeView->InitViewData(pViewData, pEntry);
+ m_xTreeView->CheckBoxInserted(pEntry);
+}
+
+void SalInstanceTreeView::InvalidateModelEntry(SvTreeListEntry* pEntry)
+{
+ if (!m_xTreeView->GetModel()->IsEnableInvalidate())
+ return;
+ m_xTreeView->ModelHasEntryInvalidated(pEntry);
+}
+
+void SalInstanceTreeView::do_set_toggle(SvTreeListEntry* pEntry, TriState eState, int col)
+{
+ assert(col >= 0 && o3tl::make_unsigned(col) < pEntry->ItemCount());
+ // if it's the placeholder to allow a blank column, replace it now
+ if (pEntry->GetItem(col).GetType() != SvLBoxItemType::Button)
+ {
+ SvLBoxButtonData* pData = m_bTogglesAsRadio ? &m_aRadioButtonData : &m_aCheckButtonData;
+ pEntry->ReplaceItem(std::make_unique<SvLBoxButton>(pData), 0);
+ update_checkbutton_column_width(pEntry);
+ }
+ SvLBoxItem& rItem = pEntry->GetItem(col);
+ assert(dynamic_cast<SvLBoxButton*>(&rItem));
+ switch (eState)
+ {
+ case TRISTATE_TRUE:
+ static_cast<SvLBoxButton&>(rItem).SetStateChecked();
+ break;
+ case TRISTATE_FALSE:
+ static_cast<SvLBoxButton&>(rItem).SetStateUnchecked();
+ break;
+ case TRISTATE_INDET:
+ static_cast<SvLBoxButton&>(rItem).SetStateTristate();
+ break;
+ }
+
+ InvalidateModelEntry(pEntry);
+}
+
+TriState SalInstanceTreeView::do_get_toggle(SvTreeListEntry* pEntry, int col)
+{
+ if (static_cast<size_t>(col) == pEntry->ItemCount())
+ return TRISTATE_FALSE;
+
+ assert(col >= 0 && o3tl::make_unsigned(col) < pEntry->ItemCount());
+ SvLBoxItem& rItem = pEntry->GetItem(col);
+ assert(dynamic_cast<SvLBoxButton*>(&rItem));
+ SvLBoxButton& rToggle = static_cast<SvLBoxButton&>(rItem);
+ if (rToggle.IsStateTristate())
+ return TRISTATE_INDET;
+ else if (rToggle.IsStateChecked())
+ return TRISTATE_TRUE;
+ return TRISTATE_FALSE;
+}
+
+TriState SalInstanceTreeView::get_toggle(SvTreeListEntry* pEntry, int col) const
+{
+ if (col == -1)
+ {
+ assert(m_xTreeView->nTreeFlags & SvTreeFlags::CHKBTN);
+ return do_get_toggle(pEntry, 0);
+ }
+ col = to_internal_model(col);
+ return do_get_toggle(pEntry, col);
+}
+
+void SalInstanceTreeView::set_toggle(SvTreeListEntry* pEntry, TriState eState, int col)
+{
+ if (col == -1)
+ {
+ assert(m_xTreeView->nTreeFlags & SvTreeFlags::CHKBTN);
+ do_set_toggle(pEntry, eState, 0);
+ return;
+ }
+
+ col = to_internal_model(col);
+
+ // blank out missing entries
+ for (int i = pEntry->ItemCount(); i < col; ++i)
+ AddStringItem(pEntry, "", i - 1);
+
+ if (static_cast<size_t>(col) == pEntry->ItemCount())
+ {
+ SvLBoxButtonData* pData = m_bTogglesAsRadio ? &m_aRadioButtonData : &m_aCheckButtonData;
+ pEntry->AddItem(std::make_unique<SvLBoxButton>(pData));
+ update_checkbutton_column_width(pEntry);
+ }
+
+ do_set_toggle(pEntry, eState, col);
+}
+
+bool SalInstanceTreeView::get_text_emphasis(SvTreeListEntry* pEntry, int col) const
+{
+ col = to_internal_model(col);
+
+ assert(col >= 0 && o3tl::make_unsigned(col) < pEntry->ItemCount());
+ SvLBoxItem& rItem = pEntry->GetItem(col);
+ assert(dynamic_cast<SvLBoxString*>(&rItem));
+ return static_cast<SvLBoxString&>(rItem).IsEmphasized();
+}
+
+void SalInstanceTreeView::set_header_item_width(const std::vector<int>& rWidths)
+{
+ LclHeaderTabListBox* pHeaderBox = dynamic_cast<LclHeaderTabListBox*>(m_xTreeView.get());
+ if (HeaderBar* pHeaderBar = pHeaderBox ? pHeaderBox->GetHeaderBar() : nullptr)
+ {
+ for (size_t i = 0; i < rWidths.size(); ++i)
+ pHeaderBar->SetItemSize(pHeaderBar->GetItemId(i), rWidths[i]);
+ }
+}
+
+SalInstanceTreeView::SalInstanceTreeView(SvTabListBox* pTreeView, SalInstanceBuilder* pBuilder,
+ bool bTakeOwnership)
+ : SalInstanceWidget(pTreeView, pBuilder, bTakeOwnership)
+ , m_xTreeView(pTreeView)
+ , m_aCheckButtonData(pTreeView, false)
+ , m_aRadioButtonData(pTreeView, true)
+ , m_bTogglesAsRadio(false)
+ , m_nSortColumn(-1)
+{
+ m_xTreeView->SetNodeDefaultImages();
+ m_xTreeView->SetForceMakeVisible(true);
+ m_xTreeView->SetSelectHdl(LINK(this, SalInstanceTreeView, SelectHdl));
+ m_xTreeView->SetDeselectHdl(LINK(this, SalInstanceTreeView, DeSelectHdl));
+ m_xTreeView->SetDoubleClickHdl(LINK(this, SalInstanceTreeView, DoubleClickHdl));
+ m_xTreeView->SetExpandingHdl(LINK(this, SalInstanceTreeView, ExpandingHdl));
+ m_xTreeView->SetPopupMenuHdl(LINK(this, SalInstanceTreeView, PopupMenuHdl));
+ m_xTreeView->SetCustomRenderHdl(LINK(this, SalInstanceTreeView, CustomRenderHdl));
+ m_xTreeView->SetCustomMeasureHdl(LINK(this, SalInstanceTreeView, CustomMeasureHdl));
+ const tools::Long aTabPositions[] = { 0 };
+ m_xTreeView->SetTabs(SAL_N_ELEMENTS(aTabPositions), aTabPositions);
+ LclHeaderTabListBox* pHeaderBox = dynamic_cast<LclHeaderTabListBox*>(m_xTreeView.get());
+
+ if (pHeaderBox)
+ {
+ if (HeaderBar* pHeaderBar = pHeaderBox->GetHeaderBar())
+ {
+ //make the last entry fill available space
+ pHeaderBar->SetItemSize(pHeaderBar->GetItemId(pHeaderBar->GetItemCount() - 1),
+ HEADERBAR_FULLSIZE);
+ pHeaderBar->SetEndDragHdl(LINK(this, SalInstanceTreeView, EndDragHdl));
+ pHeaderBar->SetSelectHdl(LINK(this, SalInstanceTreeView, HeaderBarClickedHdl));
+ }
+ pHeaderBox->SetEditingEntryHdl(LINK(this, SalInstanceTreeView, EditingEntryHdl));
+ pHeaderBox->SetEditedEntryHdl(LINK(this, SalInstanceTreeView, EditedEntryHdl));
+ }
+ else
+ {
+ static_cast<LclTabListBox&>(*m_xTreeView)
+ .SetModelChangedHdl(LINK(this, SalInstanceTreeView, ModelChangedHdl));
+ static_cast<LclTabListBox&>(*m_xTreeView)
+ .SetStartDragHdl(LINK(this, SalInstanceTreeView, StartDragHdl));
+ static_cast<LclTabListBox&>(*m_xTreeView)
+ .SetEndDragHdl(LINK(this, SalInstanceTreeView, FinishDragHdl));
+ static_cast<LclTabListBox&>(*m_xTreeView)
+ .SetEditingEntryHdl(LINK(this, SalInstanceTreeView, EditingEntryHdl));
+ static_cast<LclTabListBox&>(*m_xTreeView)
+ .SetEditedEntryHdl(LINK(this, SalInstanceTreeView, EditedEntryHdl));
+ }
+ m_aCheckButtonData.SetLink(LINK(this, SalInstanceTreeView, ToggleHdl));
+ m_aRadioButtonData.SetLink(LINK(this, SalInstanceTreeView, ToggleHdl));
+}
+
+void SalInstanceTreeView::connect_query_tooltip(const Link<const weld::TreeIter&, OUString>& rLink)
+{
+ weld::TreeView::connect_query_tooltip(rLink);
+ m_xTreeView->SetTooltipHdl(LINK(this, SalInstanceTreeView, TooltipHdl));
+}
+
+void SalInstanceTreeView::columns_autosize()
+{
+ std::vector<tools::Long> aWidths;
+ m_xTreeView->getPreferredDimensions(aWidths);
+ if (aWidths.size() > 2)
+ {
+ std::vector<int> aColWidths;
+ for (size_t i = 1; i < aWidths.size() - 1; ++i)
+ aColWidths.push_back(aWidths[i] - aWidths[i - 1]);
+ set_column_fixed_widths(aColWidths);
+ }
+}
+
+void SalInstanceTreeView::freeze()
+{
+ bool bIsFirstFreeze = IsFirstFreeze();
+ SalInstanceWidget::freeze();
+ if (bIsFirstFreeze)
+ {
+ m_xTreeView->SetUpdateMode(false);
+ m_xTreeView->GetModel()->EnableInvalidate(false);
+ }
+}
+
+void SalInstanceTreeView::thaw()
+{
+ bool bIsLastThaw = IsLastThaw();
+ if (bIsLastThaw)
+ {
+ m_xTreeView->GetModel()->EnableInvalidate(true);
+ m_xTreeView->SetUpdateMode(true);
+ }
+ SalInstanceWidget::thaw();
+}
+
+void SalInstanceTreeView::set_column_fixed_widths(const std::vector<int>& rWidths)
+{
+ std::vector<tools::Long> aTabPositions{ 0 };
+ for (size_t i = 0; i < rWidths.size(); ++i)
+ aTabPositions.push_back(aTabPositions[i] + rWidths[i]);
+ m_xTreeView->SetTabs(aTabPositions.size(), aTabPositions.data(), MapUnit::MapPixel);
+ set_header_item_width(rWidths);
+ // call Resize to recalculate based on the new tabs
+ m_xTreeView->Resize();
+}
+
+void SalInstanceTreeView::set_column_editables(const std::vector<bool>& rEditables)
+{
+ size_t nTabCount = rEditables.size();
+ for (size_t i = 0; i < nTabCount; ++i)
+ m_xTreeView->SetTabEditable(i, rEditables[i]);
+}
+
+void SalInstanceTreeView::set_centered_column(int nCol)
+{
+ m_xTreeView->SetTabJustify(nCol, SvTabJustify::AdjustCenter);
+}
+
+int SalInstanceTreeView::get_column_width(int nColumn) const
+{
+ LclHeaderTabListBox* pHeaderBox = dynamic_cast<LclHeaderTabListBox*>(m_xTreeView.get());
+ if (HeaderBar* pHeaderBar = pHeaderBox ? pHeaderBox->GetHeaderBar() : nullptr)
+ return pHeaderBar->GetItemSize(pHeaderBar->GetItemId(nColumn));
+ // GetTab(0) gives the position of the bitmap which is automatically inserted by the TabListBox.
+ // So the first text column's width is Tab(2)-Tab(1).
+ auto nWidthPixel
+ = m_xTreeView->GetLogicTab(nColumn + 2) - m_xTreeView->GetLogicTab(nColumn + 1);
+ nWidthPixel -= SV_TAB_BORDER;
+ return nWidthPixel;
+}
+
+OUString SalInstanceTreeView::get_column_title(int nColumn) const
+{
+ LclHeaderTabListBox* pHeaderBox = dynamic_cast<LclHeaderTabListBox*>(m_xTreeView.get());
+ if (HeaderBar* pHeaderBar = pHeaderBox ? pHeaderBox->GetHeaderBar() : nullptr)
+ {
+ return pHeaderBar->GetItemText(pHeaderBar->GetItemId(nColumn));
+ }
+ return OUString();
+}
+
+void SalInstanceTreeView::set_column_title(int nColumn, const OUString& rTitle)
+{
+ LclHeaderTabListBox* pHeaderBox = dynamic_cast<LclHeaderTabListBox*>(m_xTreeView.get());
+ if (HeaderBar* pHeaderBar = pHeaderBox ? pHeaderBox->GetHeaderBar() : nullptr)
+ {
+ return pHeaderBar->SetItemText(pHeaderBar->GetItemId(nColumn), rTitle);
+ }
+}
+
+void SalInstanceTreeView::set_column_custom_renderer(int nColumn, bool bEnable)
+{
+ assert(n_children() == 0 && "tree must be empty");
+ if (bEnable)
+ m_aCustomRenders.insert(nColumn);
+ else
+ m_aCustomRenders.erase(nColumn);
+}
+
+void SalInstanceTreeView::queue_draw()
+{
+ // invalidate the entries
+ SvTreeList* pModel = m_xTreeView->GetModel();
+ for (SvTreeListEntry* pEntry = m_xTreeView->First(); pEntry; pEntry = m_xTreeView->Next(pEntry))
+ pModel->InvalidateEntry(pEntry);
+}
+
+void SalInstanceTreeView::show()
+{
+ if (LclHeaderTabListBox* pHeaderBox = dynamic_cast<LclHeaderTabListBox*>(m_xTreeView.get()))
+ pHeaderBox->GetParent()->Show();
+ SalInstanceWidget::show();
+}
+
+void SalInstanceTreeView::hide()
+{
+ if (LclHeaderTabListBox* pHeaderBox = dynamic_cast<LclHeaderTabListBox*>(m_xTreeView.get()))
+ pHeaderBox->GetParent()->Hide();
+ SalInstanceWidget::hide();
+}
+
+void SalInstanceTreeView::insert(const weld::TreeIter* pParent, int pos, const OUString* pStr,
+ const OUString* pId, const OUString* pIconName,
+ VirtualDevice* pImageSurface, bool bChildrenOnDemand,
+ weld::TreeIter* pRet)
+{
+ do_insert(pParent, pos, pStr, pId, pIconName, pImageSurface, bChildrenOnDemand, pRet, false);
+}
+
+void SalInstanceTreeView::insert_separator(int pos, const OUString& /*rId*/)
+{
+ OUString sSep(VclResId(STR_SEPARATOR));
+ do_insert(nullptr, pos, &sSep, nullptr, nullptr, nullptr, false, nullptr, true);
+}
+
+void SalInstanceTreeView::bulk_insert_for_each(
+ int nSourceCount, const std::function<void(weld::TreeIter&, int nSourceIndex)>& func,
+ const weld::TreeIter* pParent, const std::vector<int>* pFixedWidths)
+{
+ const SalInstanceTreeIter* pVclIter = static_cast<const SalInstanceTreeIter*>(pParent);
+ SvTreeListEntry* pVclParent = pVclIter ? pVclIter->iter : nullptr;
+
+ freeze();
+ if (!pVclParent)
+ clear();
+ else
+ {
+ while (SvTreeListEntry* pChild = m_xTreeView->FirstChild(pVclParent))
+ m_xTreeView->RemoveEntry(pChild);
+ }
+ SalInstanceTreeIter aVclIter(static_cast<SvTreeListEntry*>(nullptr));
+
+ m_xTreeView->nTreeFlags |= SvTreeFlags::MANINS;
+
+ if (pFixedWidths)
+ set_header_item_width(*pFixedWidths);
+
+ bool bHasAutoCheckButton(m_xTreeView->nTreeFlags & SvTreeFlags::CHKBTN);
+ size_t nExtraCols = bHasAutoCheckButton ? 2 : 1;
+
+ Image aDummy;
+ for (int i = 0; i < nSourceCount; ++i)
+ {
+ aVclIter.iter = new SvTreeListEntry;
+ if (bHasAutoCheckButton)
+ AddStringItem(aVclIter.iter, "", -1);
+ aVclIter.iter->AddItem(std::make_unique<SvLBoxContextBmp>(aDummy, aDummy, false));
+ m_xTreeView->Insert(aVclIter.iter, pVclParent, TREELIST_APPEND);
+ func(aVclIter, i);
+
+ if (!pFixedWidths)
+ continue;
+
+ size_t nFixedWidths = std::min(pFixedWidths->size(), aVclIter.iter->ItemCount());
+ for (size_t j = 0; j < nFixedWidths; ++j)
+ {
+ SvLBoxItem& rItem = aVclIter.iter->GetItem(j + nExtraCols);
+ SvViewDataItem* pViewDataItem = m_xTreeView->GetViewDataItem(aVclIter.iter, &rItem);
+ pViewDataItem->mnWidth = (*pFixedWidths)[j];
+ }
+ }
+
+ m_xTreeView->nTreeFlags &= ~SvTreeFlags::MANINS;
+
+ thaw();
+}
+
+void SalInstanceTreeView::set_font_color(int pos, const Color& rColor)
+{
+ SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos);
+ set_font_color(pEntry, rColor);
+}
+
+void SalInstanceTreeView::set_font_color(const weld::TreeIter& rIter, const Color& rColor)
+{
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ set_font_color(rVclIter.iter, rColor);
+}
+
+void SalInstanceTreeView::remove(int pos)
+{
+ disable_notify_events();
+ SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos);
+ m_xTreeView->RemoveEntry(pEntry);
+ enable_notify_events();
+}
+
+int SalInstanceTreeView::find_text(const OUString& rText) const
+{
+ for (SvTreeListEntry* pEntry = m_xTreeView->First(); pEntry; pEntry = m_xTreeView->Next(pEntry))
+ {
+ if (SvTabListBox::GetEntryText(pEntry, 0) == rText)
+ return SvTreeList::GetRelPos(pEntry);
+ }
+ return -1;
+}
+
+int SalInstanceTreeView::find_id(const OUString& rId) const
+{
+ for (SvTreeListEntry* pEntry = m_xTreeView->First(); pEntry; pEntry = m_xTreeView->Next(pEntry))
+ {
+ const OUString* pId = static_cast<const OUString*>(pEntry->GetUserData());
+ if (!pId)
+ continue;
+ if (rId == *pId)
+ return SvTreeList::GetRelPos(pEntry);
+ }
+ return -1;
+}
+
+void SalInstanceTreeView::swap(int pos1, int pos2)
+{
+ int min = std::min(pos1, pos2);
+ int max = std::max(pos1, pos2);
+ SvTreeList* pModel = m_xTreeView->GetModel();
+ SvTreeListEntry* pEntry1 = pModel->GetEntry(nullptr, min);
+ SvTreeListEntry* pEntry2 = pModel->GetEntry(nullptr, max);
+ pModel->Move(pEntry1, pEntry2);
+}
+
+void SalInstanceTreeView::clear()
+{
+ disable_notify_events();
+ m_xTreeView->Clear();
+ m_aUserData.clear();
+ enable_notify_events();
+}
+
+int SalInstanceTreeView::n_children() const
+{
+ return m_xTreeView->GetModel()->GetChildList(nullptr).size();
+}
+
+int SalInstanceTreeView::iter_n_children(const weld::TreeIter& rIter) const
+{
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ return m_xTreeView->GetModel()->GetChildList(rVclIter.iter).size();
+}
+
+void SalInstanceTreeView::select(int pos)
+{
+ assert(m_xTreeView->IsUpdateMode()
+ && "don't select when frozen, select after thaw. Note selection doesn't survive a "
+ "freeze");
+ disable_notify_events();
+ if (pos == -1 || (pos == 0 && n_children() == 0))
+ m_xTreeView->SelectAll(false);
+ else
+ {
+ SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos);
+ assert(pEntry && "bad pos?");
+ m_xTreeView->Select(pEntry, true);
+ m_xTreeView->MakeVisible(pEntry);
+ }
+ enable_notify_events();
+}
+
+int SalInstanceTreeView::get_cursor_index() const
+{
+ SvTreeListEntry* pEntry = m_xTreeView->GetCurEntry();
+ if (!pEntry)
+ return -1;
+ return SvTreeList::GetRelPos(pEntry);
+}
+
+void SalInstanceTreeView::set_cursor(int pos)
+{
+ disable_notify_events();
+ if (pos == -1)
+ m_xTreeView->SetCurEntry(nullptr);
+ else
+ {
+ SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos);
+ m_xTreeView->SetCurEntry(pEntry);
+ }
+ enable_notify_events();
+}
+
+void SalInstanceTreeView::scroll_to_row(int pos)
+{
+ assert(m_xTreeView->IsUpdateMode()
+ && "don't select when frozen, select after thaw. Note selection doesn't survive a "
+ "freeze");
+ disable_notify_events();
+ SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos);
+ m_xTreeView->MakeVisible(pEntry);
+ enable_notify_events();
+}
+
+bool SalInstanceTreeView::is_selected(int pos) const
+{
+ SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos);
+ return m_xTreeView->IsSelected(pEntry);
+}
+
+void SalInstanceTreeView::unselect(int pos)
+{
+ assert(m_xTreeView->IsUpdateMode()
+ && "don't select when frozen, select after thaw. Note selection doesn't survive a "
+ "freeze");
+ disable_notify_events();
+ if (pos == -1)
+ m_xTreeView->SelectAll(true);
+ else
+ {
+ SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos);
+ m_xTreeView->Select(pEntry, false);
+ }
+ enable_notify_events();
+}
+
+std::vector<int> SalInstanceTreeView::get_selected_rows() const
+{
+ std::vector<int> aRows;
+
+ aRows.reserve(m_xTreeView->GetSelectionCount());
+ for (SvTreeListEntry* pEntry = m_xTreeView->FirstSelected(); pEntry;
+ pEntry = m_xTreeView->NextSelected(pEntry))
+ aRows.push_back(SvTreeList::GetRelPos(pEntry));
+
+ return aRows;
+}
+
+OUString SalInstanceTreeView::get_text(SvTreeListEntry* pEntry, int col) const
+{
+ if (col == -1)
+ return SvTabListBox::GetEntryText(pEntry, 0);
+
+ col = to_internal_model(col);
+
+ if (static_cast<size_t>(col) == pEntry->ItemCount())
+ return OUString();
+
+ assert(col >= 0 && o3tl::make_unsigned(col) < pEntry->ItemCount());
+ SvLBoxItem& rItem = pEntry->GetItem(col);
+ assert(dynamic_cast<SvLBoxString*>(&rItem));
+ return static_cast<SvLBoxString&>(rItem).GetText();
+}
+
+OUString SalInstanceTreeView::get_text(int pos, int col) const
+{
+ SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos);
+ return get_text(pEntry, col);
+}
+
+void SalInstanceTreeView::set_text(SvTreeListEntry* pEntry, const OUString& rText, int col)
+{
+ if (col == -1)
+ {
+ m_xTreeView->SetEntryText(pEntry, rText);
+ return;
+ }
+
+ col = to_internal_model(col);
+
+ // blank out missing entries
+ for (int i = pEntry->ItemCount(); i < col; ++i)
+ AddStringItem(pEntry, "", i - 1);
+
+ if (static_cast<size_t>(col) == pEntry->ItemCount())
+ {
+ AddStringItem(pEntry, rText, col - 1);
+ SvViewDataEntry* pViewData = m_xTreeView->GetViewDataEntry(pEntry);
+ m_xTreeView->InitViewData(pViewData, pEntry);
+ }
+ else
+ {
+ assert(col >= 0 && o3tl::make_unsigned(col) < pEntry->ItemCount());
+ SvLBoxItem& rItem = pEntry->GetItem(col);
+ assert(dynamic_cast<SvLBoxString*>(&rItem));
+ static_cast<SvLBoxString&>(rItem).SetText(rText);
+ }
+
+ InvalidateModelEntry(pEntry);
+}
+
+void SalInstanceTreeView::set_text(int pos, const OUString& rText, int col)
+{
+ SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos);
+ set_text(pEntry, rText, col);
+}
+
+void SalInstanceTreeView::set_sensitive(SvTreeListEntry* pEntry, bool bSensitive, int col)
+{
+ if (col == -1)
+ {
+ auto nFlags = pEntry->GetFlags() & ~SvTLEntryFlags::SEMITRANSPARENT;
+ if (!bSensitive)
+ nFlags = nFlags | SvTLEntryFlags::SEMITRANSPARENT;
+ pEntry->SetFlags(nFlags);
+ const sal_uInt16 nCount = pEntry->ItemCount();
+ for (sal_uInt16 nCur = 0; nCur < nCount; ++nCur)
+ {
+ SvLBoxItem& rItem = pEntry->GetItem(nCur);
+ if (rItem.GetType() == SvLBoxItemType::String
+ || rItem.GetType() == SvLBoxItemType::Button
+ || rItem.GetType() == SvLBoxItemType::ContextBmp)
+ {
+ rItem.Enable(bSensitive);
+ InvalidateModelEntry(pEntry);
+ }
+ }
+ return;
+ }
+
+ col = to_internal_model(col);
+
+ assert(col >= 0 && o3tl::make_unsigned(col) < pEntry->ItemCount());
+ SvLBoxItem& rItem = pEntry->GetItem(col);
+ rItem.Enable(bSensitive);
+
+ InvalidateModelEntry(pEntry);
+}
+
+bool SalInstanceTreeView::do_get_sensitive(SvTreeListEntry* pEntry, int col)
+{
+ if (static_cast<size_t>(col) == pEntry->ItemCount())
+ return false;
+
+ assert(col >= 0 && o3tl::make_unsigned(col) < pEntry->ItemCount());
+ SvLBoxItem& rItem = pEntry->GetItem(col);
+ return rItem.isEnable();
+}
+
+bool SalInstanceTreeView::get_sensitive(SvTreeListEntry* pEntry, int col) const
+{
+ col = to_internal_model(col);
+ return do_get_sensitive(pEntry, col);
+}
+
+void SalInstanceTreeView::set_sensitive(int pos, bool bSensitive, int col)
+{
+ SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos);
+ set_sensitive(pEntry, bSensitive, col);
+}
+
+bool SalInstanceTreeView::get_sensitive(int pos, int col) const
+{
+ SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos);
+ return get_sensitive(pEntry, col);
+}
+
+void SalInstanceTreeView::set_sensitive(const weld::TreeIter& rIter, bool bSensitive, int col)
+{
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ set_sensitive(rVclIter.iter, bSensitive, col);
+}
+
+bool SalInstanceTreeView::get_sensitive(const weld::TreeIter& rIter, int col) const
+{
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ return get_sensitive(rVclIter.iter, col);
+}
+
+TriState SalInstanceTreeView::get_toggle(int pos, int col) const
+{
+ SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos);
+ return get_toggle(pEntry, col);
+}
+
+TriState SalInstanceTreeView::get_toggle(const weld::TreeIter& rIter, int col) const
+{
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ return get_toggle(rVclIter.iter, col);
+}
+
+void SalInstanceTreeView::enable_toggle_buttons(weld::ColumnToggleType eType)
+{
+ assert(n_children() == 0 && "tree must be empty");
+ m_bTogglesAsRadio = eType == weld::ColumnToggleType::Radio;
+
+ SvLBoxButtonData* pData = m_bTogglesAsRadio ? &m_aRadioButtonData : &m_aCheckButtonData;
+ m_xTreeView->EnableCheckButton(pData);
+ // EnableCheckButton clobbered this, restore it
+ pData->SetLink(LINK(this, SalInstanceTreeView, ToggleHdl));
+}
+
+void SalInstanceTreeView::set_toggle(int pos, TriState eState, int col)
+{
+ SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos);
+ set_toggle(pEntry, eState, col);
+}
+
+void SalInstanceTreeView::set_toggle(const weld::TreeIter& rIter, TriState eState, int col)
+{
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ set_toggle(rVclIter.iter, eState, col);
+}
+
+void SalInstanceTreeView::set_clicks_to_toggle(int nToggleBehavior)
+{
+ m_xTreeView->SetClicksToToggle(nToggleBehavior);
+}
+
+void SalInstanceTreeView::set_extra_row_indent(const weld::TreeIter& rIter, int nIndentLevel)
+{
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ rVclIter.iter->SetExtraIndent(nIndentLevel);
+}
+
+void SalInstanceTreeView::set_text_emphasis(SvTreeListEntry* pEntry, bool bOn, int col)
+{
+ if (col == -1)
+ {
+ for (size_t nCur = 0; nCur < pEntry->ItemCount(); ++nCur)
+ {
+ SvLBoxItem& rItem = pEntry->GetItem(nCur);
+ if (rItem.GetType() == SvLBoxItemType::String)
+ {
+ static_cast<SvLBoxString&>(rItem).Emphasize(bOn);
+ InvalidateModelEntry(pEntry);
+ }
+ }
+ return;
+ }
+
+ col = to_internal_model(col);
+ assert(col >= 0 && o3tl::make_unsigned(col) < pEntry->ItemCount());
+ SvLBoxItem& rItem = pEntry->GetItem(col);
+ assert(dynamic_cast<SvLBoxString*>(&rItem));
+ static_cast<SvLBoxString&>(rItem).Emphasize(bOn);
+
+ InvalidateModelEntry(pEntry);
+}
+
+void SalInstanceTreeView::set_text_emphasis(const weld::TreeIter& rIter, bool bOn, int col)
+{
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ set_text_emphasis(rVclIter.iter, bOn, col);
+}
+
+void SalInstanceTreeView::set_text_emphasis(int pos, bool bOn, int col)
+{
+ SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos);
+ set_text_emphasis(pEntry, bOn, col);
+}
+
+bool SalInstanceTreeView::get_text_emphasis(const weld::TreeIter& rIter, int col) const
+{
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ return get_text_emphasis(rVclIter.iter, col);
+}
+
+bool SalInstanceTreeView::get_text_emphasis(int pos, int col) const
+{
+ SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos);
+ return get_text_emphasis(pEntry, col);
+}
+
+void SalInstanceTreeView::set_text_align(SvTreeListEntry* pEntry, double fAlign, int col)
+{
+ col = to_internal_model(col);
+
+ assert(col >= 0 && o3tl::make_unsigned(col) < pEntry->ItemCount());
+ SvLBoxItem& rItem = pEntry->GetItem(col);
+ assert(dynamic_cast<SvLBoxString*>(&rItem));
+ static_cast<SvLBoxString&>(rItem).Align(fAlign);
+
+ InvalidateModelEntry(pEntry);
+}
+
+void SalInstanceTreeView::set_text_align(const weld::TreeIter& rIter, double fAlign, int col)
+{
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ set_text_align(rVclIter.iter, fAlign, col);
+}
+
+void SalInstanceTreeView::set_text_align(int pos, double fAlign, int col)
+{
+ SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos);
+ set_text_align(pEntry, fAlign, col);
+}
+
+void SalInstanceTreeView::connect_editing(const Link<const weld::TreeIter&, bool>& rStartLink,
+ const Link<const iter_string&, bool>& rEndLink)
+{
+ m_xTreeView->EnableInplaceEditing(rStartLink.IsSet() || rEndLink.IsSet());
+ weld::TreeView::connect_editing(rStartLink, rEndLink);
+}
+
+void SalInstanceTreeView::start_editing(const weld::TreeIter& rIter)
+{
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ m_xTreeView->EditEntry(rVclIter.iter);
+}
+
+void SalInstanceTreeView::end_editing() { m_xTreeView->EndEditing(); }
+
+void SalInstanceTreeView::set_image(SvTreeListEntry* pEntry, const Image& rImage, int col)
+{
+ if (col == -1)
+ {
+ m_xTreeView->SetExpandedEntryBmp(pEntry, rImage);
+ m_xTreeView->SetCollapsedEntryBmp(pEntry, rImage);
+ return;
+ }
+
+ col = to_internal_model(col);
+
+ // blank out missing entries
+ for (int i = pEntry->ItemCount(); i < col; ++i)
+ AddStringItem(pEntry, "", i - 1);
+
+ if (static_cast<size_t>(col) == pEntry->ItemCount())
+ {
+ pEntry->AddItem(std::make_unique<SvLBoxContextBmp>(rImage, rImage, false));
+ SvViewDataEntry* pViewData = m_xTreeView->GetViewDataEntry(pEntry);
+ m_xTreeView->InitViewData(pViewData, pEntry);
+ }
+ else
+ {
+ assert(col >= 0 && o3tl::make_unsigned(col) < pEntry->ItemCount());
+ SvLBoxItem& rItem = pEntry->GetItem(col);
+ assert(dynamic_cast<SvLBoxContextBmp*>(&rItem));
+ static_cast<SvLBoxContextBmp&>(rItem).SetBitmap1(rImage);
+ static_cast<SvLBoxContextBmp&>(rItem).SetBitmap2(rImage);
+ }
+
+ m_xTreeView->CalcEntryHeight(pEntry);
+ InvalidateModelEntry(pEntry);
+}
+
+void SalInstanceTreeView::set_image(int pos, const OUString& rImage, int col)
+{
+ set_image(m_xTreeView->GetEntry(nullptr, pos), createImage(rImage), col);
+}
+
+void SalInstanceTreeView::set_image(int pos,
+ const css::uno::Reference<css::graphic::XGraphic>& rImage,
+ int col)
+{
+ set_image(m_xTreeView->GetEntry(nullptr, pos), Image(rImage), col);
+}
+
+void SalInstanceTreeView::set_image(int pos, VirtualDevice& rImage, int col)
+{
+ set_image(m_xTreeView->GetEntry(nullptr, pos), createImage(rImage), col);
+}
+
+void SalInstanceTreeView::set_image(const weld::TreeIter& rIter, const OUString& rImage, int col)
+{
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ set_image(rVclIter.iter, createImage(rImage), col);
+}
+
+void SalInstanceTreeView::set_image(const weld::TreeIter& rIter,
+ const css::uno::Reference<css::graphic::XGraphic>& rImage,
+ int col)
+{
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ set_image(rVclIter.iter, Image(rImage), col);
+}
+
+void SalInstanceTreeView::set_image(const weld::TreeIter& rIter, VirtualDevice& rImage, int col)
+{
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ set_image(rVclIter.iter, createImage(rImage), col);
+}
+
+const OUString* SalInstanceTreeView::getEntryData(int index) const
+{
+ SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, index);
+ return pEntry ? static_cast<const OUString*>(pEntry->GetUserData()) : nullptr;
+}
+
+OUString SalInstanceTreeView::get_id(int pos) const
+{
+ const OUString* pRet = getEntryData(pos);
+ if (!pRet)
+ return OUString();
+ return *pRet;
+}
+
+void SalInstanceTreeView::set_id(SvTreeListEntry* pEntry, const OUString& rId)
+{
+ m_aUserData.emplace_back(std::make_unique<OUString>(rId));
+ pEntry->SetUserData(m_aUserData.back().get());
+}
+
+void SalInstanceTreeView::set_id(int pos, const OUString& rId)
+{
+ SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos);
+ set_id(pEntry, rId);
+}
+
+int SalInstanceTreeView::get_selected_index() const
+{
+ assert(m_xTreeView->IsUpdateMode() && "don't request selection when frozen");
+ SvTreeListEntry* pEntry = m_xTreeView->FirstSelected();
+ if (!pEntry)
+ return -1;
+ return SvTreeList::GetRelPos(pEntry);
+}
+
+OUString SalInstanceTreeView::get_selected_text() const
+{
+ assert(m_xTreeView->IsUpdateMode() && "don't request selection when frozen");
+ if (SvTreeListEntry* pEntry = m_xTreeView->FirstSelected())
+ return SvTabListBox::GetEntryText(pEntry, 0);
+ return OUString();
+}
+
+OUString SalInstanceTreeView::get_selected_id() const
+{
+ assert(m_xTreeView->IsUpdateMode() && "don't request selection when frozen");
+ if (SvTreeListEntry* pEntry = m_xTreeView->FirstSelected())
+ {
+ if (const OUString* pStr = static_cast<const OUString*>(pEntry->GetUserData()))
+ return *pStr;
+ }
+ return OUString();
+}
+
+std::unique_ptr<weld::TreeIter>
+SalInstanceTreeView::make_iterator(const weld::TreeIter* pOrig) const
+{
+ return std::unique_ptr<weld::TreeIter>(
+ new SalInstanceTreeIter(static_cast<const SalInstanceTreeIter*>(pOrig)));
+}
+
+void SalInstanceTreeView::copy_iterator(const weld::TreeIter& rSource, weld::TreeIter& rDest) const
+{
+ const SalInstanceTreeIter& rVclSource(static_cast<const SalInstanceTreeIter&>(rSource));
+ SalInstanceTreeIter& rVclDest(static_cast<SalInstanceTreeIter&>(rDest));
+ rVclDest.iter = rVclSource.iter;
+}
+
+bool SalInstanceTreeView::get_selected(weld::TreeIter* pIter) const
+{
+ SvTreeListEntry* pEntry = m_xTreeView->FirstSelected();
+ auto pVclIter = static_cast<SalInstanceTreeIter*>(pIter);
+ if (pVclIter)
+ pVclIter->iter = pEntry;
+ return pEntry != nullptr;
+}
+
+bool SalInstanceTreeView::get_cursor(weld::TreeIter* pIter) const
+{
+ SvTreeListEntry* pEntry = m_xTreeView->GetCurEntry();
+ auto pVclIter = static_cast<SalInstanceTreeIter*>(pIter);
+ if (pVclIter)
+ pVclIter->iter = pEntry;
+ return pEntry != nullptr;
+}
+
+void SalInstanceTreeView::set_cursor(const weld::TreeIter& rIter)
+{
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ disable_notify_events();
+ m_xTreeView->SetCurEntry(rVclIter.iter);
+ enable_notify_events();
+}
+
+bool SalInstanceTreeView::get_iter_first(weld::TreeIter& rIter) const
+{
+ SalInstanceTreeIter& rVclIter = static_cast<SalInstanceTreeIter&>(rIter);
+ rVclIter.iter = m_xTreeView->GetEntry(0);
+ return rVclIter.iter != nullptr;
+}
+
+bool SalInstanceTreeView::get_iter_abs_pos(weld::TreeIter& rIter, int nAbsPos) const
+{
+ SalInstanceTreeIter& rVclIter = static_cast<SalInstanceTreeIter&>(rIter);
+ rVclIter.iter = m_xTreeView->GetEntryAtAbsPos(nAbsPos);
+ return rVclIter.iter != nullptr;
+}
+
+bool SalInstanceTreeView::iter_next_sibling(weld::TreeIter& rIter) const
+{
+ SalInstanceTreeIter& rVclIter = static_cast<SalInstanceTreeIter&>(rIter);
+ rVclIter.iter = rVclIter.iter->NextSibling();
+ return rVclIter.iter != nullptr;
+}
+
+bool SalInstanceTreeView::iter_previous_sibling(weld::TreeIter& rIter) const
+{
+ SalInstanceTreeIter& rVclIter = static_cast<SalInstanceTreeIter&>(rIter);
+ rVclIter.iter = rVclIter.iter->PrevSibling();
+ return rVclIter.iter != nullptr;
+}
+
+bool SalInstanceTreeView::iter_next(weld::TreeIter& rIter) const
+{
+ SalInstanceTreeIter& rVclIter = static_cast<SalInstanceTreeIter&>(rIter);
+ rVclIter.iter = m_xTreeView->Next(rVclIter.iter);
+ if (rVclIter.iter && IsDummyEntry(rVclIter.iter))
+ return iter_next(rVclIter);
+ return rVclIter.iter != nullptr;
+}
+
+bool SalInstanceTreeView::iter_previous(weld::TreeIter& rIter) const
+{
+ SalInstanceTreeIter& rVclIter = static_cast<SalInstanceTreeIter&>(rIter);
+ rVclIter.iter = m_xTreeView->Prev(rVclIter.iter);
+ if (rVclIter.iter && IsDummyEntry(rVclIter.iter))
+ return iter_previous(rVclIter);
+ return rVclIter.iter != nullptr;
+}
+
+bool SalInstanceTreeView::iter_children(weld::TreeIter& rIter) const
+{
+ SalInstanceTreeIter& rVclIter = static_cast<SalInstanceTreeIter&>(rIter);
+ rVclIter.iter = m_xTreeView->FirstChild(rVclIter.iter);
+ bool bRet = rVclIter.iter != nullptr;
+ if (bRet)
+ {
+ //on-demand dummy entry doesn't count
+ return !IsDummyEntry(rVclIter.iter);
+ }
+ return bRet;
+}
+
+bool SalInstanceTreeView::iter_parent(weld::TreeIter& rIter) const
+{
+ SalInstanceTreeIter& rVclIter = static_cast<SalInstanceTreeIter&>(rIter);
+ rVclIter.iter = m_xTreeView->GetParent(rVclIter.iter);
+ return rVclIter.iter != nullptr;
+}
+
+void SalInstanceTreeView::remove(const weld::TreeIter& rIter)
+{
+ disable_notify_events();
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ m_xTreeView->RemoveEntry(rVclIter.iter);
+ enable_notify_events();
+}
+
+void SalInstanceTreeView::select(const weld::TreeIter& rIter)
+{
+ assert(m_xTreeView->IsUpdateMode()
+ && "don't select when frozen, select after thaw. Note selection doesn't survive a "
+ "freeze");
+ disable_notify_events();
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ m_xTreeView->Select(rVclIter.iter, true);
+ enable_notify_events();
+}
+
+void SalInstanceTreeView::scroll_to_row(const weld::TreeIter& rIter)
+{
+ assert(m_xTreeView->IsUpdateMode()
+ && "don't select when frozen, select after thaw. Note selection doesn't survive a "
+ "freeze");
+ disable_notify_events();
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ m_xTreeView->MakeVisible(rVclIter.iter);
+ enable_notify_events();
+}
+
+void SalInstanceTreeView::unselect(const weld::TreeIter& rIter)
+{
+ assert(m_xTreeView->IsUpdateMode() && "don't unselect when frozen");
+ disable_notify_events();
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ m_xTreeView->Select(rVclIter.iter, false);
+ enable_notify_events();
+}
+
+int SalInstanceTreeView::get_iter_depth(const weld::TreeIter& rIter) const
+{
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ return m_xTreeView->GetModel()->GetDepth(rVclIter.iter);
+}
+
+bool SalInstanceTreeView::iter_has_child(const weld::TreeIter& rIter) const
+{
+ SalInstanceTreeIter aTempCopy(static_cast<const SalInstanceTreeIter*>(&rIter));
+ return iter_children(aTempCopy);
+}
+
+bool SalInstanceTreeView::get_row_expanded(const weld::TreeIter& rIter) const
+{
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ return m_xTreeView->IsExpanded(rVclIter.iter);
+}
+
+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))
+ return true;
+ return GetPlaceHolderChild(rVclIter.iter) != nullptr;
+}
+
+void SalInstanceTreeView::set_children_on_demand(const weld::TreeIter& rIter,
+ bool bChildrenOnDemand)
+{
+ disable_notify_events();
+
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+
+ SvTreeListEntry* pPlaceHolder = GetPlaceHolderChild(rVclIter.iter);
+
+ if (bChildrenOnDemand && !pPlaceHolder)
+ {
+ pPlaceHolder = m_xTreeView->InsertEntry("<dummy>", rVclIter.iter, false, 0, nullptr);
+ SvViewDataEntry* pViewData = m_xTreeView->GetViewDataEntry(pPlaceHolder);
+ pViewData->SetSelectable(false);
+ }
+ else if (!bChildrenOnDemand && pPlaceHolder)
+ m_xTreeView->RemoveEntry(pPlaceHolder);
+
+ enable_notify_events();
+}
+
+void SalInstanceTreeView::expand_row(const weld::TreeIter& rIter)
+{
+ assert(m_xTreeView->IsUpdateMode() && "don't expand when frozen");
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ if (!m_xTreeView->IsExpanded(rVclIter.iter) && ExpandRow(rVclIter))
+ m_xTreeView->Expand(rVclIter.iter);
+}
+
+void SalInstanceTreeView::collapse_row(const weld::TreeIter& rIter)
+{
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ if (m_xTreeView->IsExpanded(rVclIter.iter) && signal_collapsing(rIter))
+ m_xTreeView->Collapse(rVclIter.iter);
+}
+
+OUString SalInstanceTreeView::get_text(const weld::TreeIter& rIter, int col) const
+{
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ return get_text(rVclIter.iter, col);
+}
+
+void SalInstanceTreeView::set_text(const weld::TreeIter& rIter, const OUString& rText, int col)
+{
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ set_text(rVclIter.iter, rText, col);
+}
+
+OUString SalInstanceTreeView::get_id(const weld::TreeIter& rIter) const
+{
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ const OUString* pStr = static_cast<const OUString*>(rVclIter.iter->GetUserData());
+ if (pStr)
+ return *pStr;
+ return OUString();
+}
+
+void SalInstanceTreeView::set_id(const weld::TreeIter& rIter, const OUString& rId)
+{
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ set_id(rVclIter.iter, rId);
+}
+
+void SalInstanceTreeView::enable_drag_source(rtl::Reference<TransferDataContainer>& rHelper,
+ sal_uInt8 eDNDConstants)
+{
+ m_xTreeView->SetDragHelper(rHelper, eDNDConstants);
+}
+
+void SalInstanceTreeView::set_selection_mode(SelectionMode eMode)
+{
+ m_xTreeView->SetSelectionMode(eMode);
+}
+
+void SalInstanceTreeView::all_foreach(const std::function<bool(weld::TreeIter&)>& func)
+{
+ UpdateGuardIfHidden aGuard(*m_xTreeView);
+
+ SalInstanceTreeIter aVclIter(m_xTreeView->First());
+ while (aVclIter.iter)
+ {
+ if (func(aVclIter))
+ return;
+ iter_next(aVclIter);
+ }
+}
+
+void SalInstanceTreeView::selected_foreach(const std::function<bool(weld::TreeIter&)>& func)
+{
+ UpdateGuardIfHidden aGuard(*m_xTreeView);
+
+ SalInstanceTreeIter aVclIter(m_xTreeView->FirstSelected());
+ while (aVclIter.iter)
+ {
+ if (func(aVclIter))
+ return;
+ aVclIter.iter = m_xTreeView->NextSelected(aVclIter.iter);
+ }
+}
+
+void SalInstanceTreeView::visible_foreach(const std::function<bool(weld::TreeIter&)>& func)
+{
+ UpdateGuardIfHidden aGuard(*m_xTreeView);
+
+ SalInstanceTreeIter aVclIter(m_xTreeView->GetFirstEntryInView());
+ while (aVclIter.iter)
+ {
+ if (func(aVclIter))
+ return;
+ aVclIter.iter = m_xTreeView->GetNextEntryInView(aVclIter.iter);
+ }
+}
+
+void SalInstanceTreeView::connect_visible_range_changed(const Link<weld::TreeView&, void>& rLink)
+{
+ weld::TreeView::connect_visible_range_changed(rLink);
+ m_xTreeView->SetScrolledHdl(LINK(this, SalInstanceTreeView, VisibleRangeChangedHdl));
+}
+
+void SalInstanceTreeView::remove_selection()
+{
+ disable_notify_events();
+ SvTreeListEntry* pSelected = m_xTreeView->FirstSelected();
+ while (pSelected)
+ {
+ SvTreeListEntry* pNextSelected = m_xTreeView->NextSelected(pSelected);
+ m_xTreeView->RemoveEntry(pSelected);
+ pSelected = pNextSelected;
+ }
+ enable_notify_events();
+}
+
+bool SalInstanceTreeView::is_selected(const weld::TreeIter& rIter) const
+{
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ return m_xTreeView->IsSelected(rVclIter.iter);
+}
+
+int SalInstanceTreeView::get_iter_index_in_parent(const weld::TreeIter& rIter) const
+{
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ return SvTreeList::GetRelPos(rVclIter.iter);
+}
+
+int SalInstanceTreeView::iter_compare(const weld::TreeIter& a, const weld::TreeIter& b) const
+{
+ const SalInstanceTreeIter& rVclIterA = static_cast<const SalInstanceTreeIter&>(a);
+ const SalInstanceTreeIter& rVclIterB = static_cast<const SalInstanceTreeIter&>(b);
+ const SvTreeList* pModel = m_xTreeView->GetModel();
+ auto nAbsPosA = pModel->GetAbsPos(rVclIterA.iter);
+ auto nAbsPosB = pModel->GetAbsPos(rVclIterB.iter);
+ if (nAbsPosA < nAbsPosB)
+ return -1;
+ if (nAbsPosA > nAbsPosB)
+ return 1;
+ return 0;
+}
+
+void SalInstanceTreeView::move_subtree(weld::TreeIter& rNode, const weld::TreeIter* pNewParent,
+ int nIndexInNewParent)
+{
+ SalInstanceTreeIter& rVclIter = static_cast<SalInstanceTreeIter&>(rNode);
+ const SalInstanceTreeIter* pVclParentIter = static_cast<const SalInstanceTreeIter*>(pNewParent);
+ m_xTreeView->GetModel()->Move(rVclIter.iter, pVclParentIter ? pVclParentIter->iter : nullptr,
+ nIndexInNewParent);
+}
+
+int SalInstanceTreeView::count_selected_rows() const { return m_xTreeView->GetSelectionCount(); }
+
+int SalInstanceTreeView::get_height_rows(int nRows) const
+{
+ int nHeight = m_xTreeView->GetEntryHeight() * nRows;
+
+ sal_Int32 nLeftBorder(0), nTopBorder(0), nRightBorder(0), nBottomBorder(0);
+ m_xTreeView->GetBorder(nLeftBorder, nTopBorder, nRightBorder, nBottomBorder);
+ nHeight += nTopBorder + nBottomBorder;
+
+ return nHeight;
+}
+
+void SalInstanceTreeView::make_sorted()
+{
+ assert(m_xTreeView->IsUpdateMode() && "don't sort when frozen");
+ m_xTreeView->SetStyle(m_xTreeView->GetStyle() | WB_SORT);
+ m_xTreeView->GetModel()->SetCompareHdl(LINK(this, SalInstanceTreeView, CompareHdl));
+ set_sort_order(true);
+}
+
+void SalInstanceTreeView::set_sort_func(
+ const std::function<int(const weld::TreeIter&, const weld::TreeIter&)>& func)
+{
+ weld::TreeView::set_sort_func(func);
+ SvTreeList* pListModel = m_xTreeView->GetModel();
+ pListModel->Resort();
+}
+
+void SalInstanceTreeView::make_unsorted()
+{
+ m_xTreeView->SetStyle(m_xTreeView->GetStyle() & ~WB_SORT);
+}
+
+void SalInstanceTreeView::set_sort_order(bool bAscending)
+{
+ SvTreeList* pListModel = m_xTreeView->GetModel();
+ pListModel->SetSortMode(bAscending ? SvSortMode::Ascending : SvSortMode::Descending);
+ pListModel->Resort();
+}
+
+bool SalInstanceTreeView::get_sort_order() const
+{
+ return m_xTreeView->GetModel()->GetSortMode() == SvSortMode::Ascending;
+}
+
+void SalInstanceTreeView::set_sort_indicator(TriState eState, int col)
+{
+ assert(col >= 0 && "cannot sort on expander column");
+
+ LclHeaderTabListBox* pHeaderBox = dynamic_cast<LclHeaderTabListBox*>(m_xTreeView.get());
+ HeaderBar* pHeaderBar = pHeaderBox ? pHeaderBox->GetHeaderBar() : nullptr;
+ if (!pHeaderBar)
+ return;
+
+ sal_uInt16 nTextId = pHeaderBar->GetItemId(col);
+ HeaderBarItemBits nBits = pHeaderBar->GetItemBits(nTextId);
+ nBits &= ~HeaderBarItemBits::UPARROW;
+ nBits &= ~HeaderBarItemBits::DOWNARROW;
+ if (eState != TRISTATE_INDET)
+ {
+ if (eState == TRISTATE_TRUE)
+ nBits |= HeaderBarItemBits::DOWNARROW;
+ else
+ nBits |= HeaderBarItemBits::UPARROW;
+ }
+ pHeaderBar->SetItemBits(nTextId, nBits);
+}
+
+TriState SalInstanceTreeView::get_sort_indicator(int col) const
+{
+ assert(col >= 0 && "cannot sort on expander column");
+
+ LclHeaderTabListBox* pHeaderBox = dynamic_cast<LclHeaderTabListBox*>(m_xTreeView.get());
+ if (HeaderBar* pHeaderBar = pHeaderBox ? pHeaderBox->GetHeaderBar() : nullptr)
+ {
+ sal_uInt16 nTextId = pHeaderBar->GetItemId(col);
+ HeaderBarItemBits nBits = pHeaderBar->GetItemBits(nTextId);
+ if (nBits & HeaderBarItemBits::DOWNARROW)
+ return TRISTATE_TRUE;
+ if (nBits & HeaderBarItemBits::UPARROW)
+ return TRISTATE_FALSE;
+ }
+
+ return TRISTATE_INDET;
+}
+
+int SalInstanceTreeView::get_sort_column() const { return m_nSortColumn; }
+
+void SalInstanceTreeView::set_sort_column(int nColumn)
+{
+ if (nColumn == -1)
+ {
+ make_unsorted();
+ m_nSortColumn = -1;
+ return;
+ }
+
+ if (nColumn != m_nSortColumn)
+ {
+ m_nSortColumn = nColumn;
+ m_xTreeView->GetModel()->Resort();
+ }
+}
+
+SvTabListBox& SalInstanceTreeView::getTreeView() { return *m_xTreeView; }
+
+bool SalInstanceTreeView::get_dest_row_at_pos(const Point& rPos, weld::TreeIter* pResult,
+ bool bDnDMode, bool bAutoScroll)
+{
+ LclTabListBox* pTreeView
+ = !bDnDMode ? dynamic_cast<LclTabListBox*>(m_xTreeView.get()) : nullptr;
+ SvTreeListEntry* pTarget = pTreeView ? pTreeView->GetTargetAtPoint(rPos, false, bAutoScroll)
+ : m_xTreeView->GetDropTarget(rPos);
+
+ if (pTarget && pResult)
+ {
+ SalInstanceTreeIter& rSalIter = static_cast<SalInstanceTreeIter&>(*pResult);
+ rSalIter.iter = pTarget;
+ }
+
+ return pTarget != nullptr;
+}
+
+void SalInstanceTreeView::unset_drag_dest_row() { m_xTreeView->UnsetDropTarget(); }
+
+tools::Rectangle SalInstanceTreeView::get_row_area(const weld::TreeIter& rIter) const
+{
+ return m_xTreeView->GetBoundingRect(static_cast<const SalInstanceTreeIter&>(rIter).iter);
+}
+
+weld::TreeView* SalInstanceTreeView::get_drag_source() const { return g_DragSource; }
+
+int SalInstanceTreeView::vadjustment_get_value() const
+{
+ int nValue = -1;
+ const SvTreeListEntry* pEntry = m_xTreeView->GetFirstEntryInView();
+ if (pEntry)
+ nValue = m_xTreeView->GetAbsPos(pEntry);
+ return nValue;
+}
+
+void SalInstanceTreeView::vadjustment_set_value(int nValue)
+{
+ if (nValue == -1)
+ return;
+ bool bUpdate = m_xTreeView->IsUpdateMode();
+ if (bUpdate)
+ m_xTreeView->SetUpdateMode(false);
+ m_xTreeView->ScrollToAbsPos(nValue);
+ if (bUpdate)
+ m_xTreeView->SetUpdateMode(true);
+}
+
+void SalInstanceTreeView::set_show_expanders(bool bShow)
+{
+ m_xTreeView->set_property("show-expanders", OUString::boolean(bShow));
+}
+
+bool SalInstanceTreeView::changed_by_hover() const { return m_xTreeView->IsSelectDueToHover(); }
+
+SalInstanceTreeView::~SalInstanceTreeView()
+{
+ LclHeaderTabListBox* pHeaderBox = dynamic_cast<LclHeaderTabListBox*>(m_xTreeView.get());
+ if (pHeaderBox)
+ {
+ if (HeaderBar* pHeaderBar = pHeaderBox->GetHeaderBar())
+ {
+ pHeaderBar->SetSelectHdl(Link<HeaderBar*, void>());
+ pHeaderBar->SetEndDragHdl(Link<HeaderBar*, void>());
+ }
+ }
+ else
+ {
+ static_cast<LclTabListBox&>(*m_xTreeView).SetEndDragHdl(Link<SvTreeListBox*, void>());
+ static_cast<LclTabListBox&>(*m_xTreeView).SetStartDragHdl(Link<SvTreeListBox*, bool>());
+ static_cast<LclTabListBox&>(*m_xTreeView).SetModelChangedHdl(Link<SvTreeListBox*, void>());
+ }
+ if (g_DragSource == this)
+ g_DragSource = nullptr;
+ m_xTreeView->SetPopupMenuHdl(Link<const CommandEvent&, bool>());
+ m_xTreeView->SetExpandingHdl(Link<SvTreeListBox*, bool>());
+ m_xTreeView->SetDoubleClickHdl(Link<SvTreeListBox*, bool>());
+ m_xTreeView->SetSelectHdl(Link<SvTreeListBox*, void>());
+ m_xTreeView->SetDeselectHdl(Link<SvTreeListBox*, void>());
+ m_xTreeView->SetScrolledHdl(Link<SvTreeListBox*, void>());
+ m_xTreeView->SetTooltipHdl({});
+ m_xTreeView->SetCustomRenderHdl(Link<svtree_render_args, void>());
+ m_xTreeView->SetCustomMeasureHdl(Link<svtree_measure_args, Size>());
+}
+
+IMPL_LINK(SalInstanceTreeView, TooltipHdl, SvTreeListEntry*, pEntry, OUString)
+{
+ if (pEntry && !notify_events_disabled())
+ return signal_query_tooltip(SalInstanceTreeIter(pEntry));
+
+ return {};
+}
+
+IMPL_LINK(SalInstanceTreeView, CustomRenderHdl, svtree_render_args, payload, void)
+{
+ vcl::RenderContext& rRenderDevice = std::get<0>(payload);
+ const tools::Rectangle& rRect = std::get<1>(payload);
+ const SvTreeListEntry& rEntry = std::get<2>(payload);
+ const OUString* pId = static_cast<const OUString*>(rEntry.GetUserData());
+ if (!pId)
+ return;
+ signal_custom_render(rRenderDevice, rRect, m_xTreeView->IsSelected(&rEntry), *pId);
+}
+
+IMPL_LINK(SalInstanceTreeView, CustomMeasureHdl, svtree_measure_args, payload, Size)
+{
+ vcl::RenderContext& rRenderDevice = payload.first;
+ const SvTreeListEntry& rEntry = payload.second;
+ const OUString* pId = static_cast<const OUString*>(rEntry.GetUserData());
+ if (!pId)
+ return Size();
+ return signal_custom_get_size(rRenderDevice, *pId);
+}
+
+IMPL_LINK(SalInstanceTreeView, CompareHdl, const SvSortData&, rSortData, sal_Int32)
+{
+ const SvTreeListEntry* pLHS = rSortData.pLeft;
+ const SvTreeListEntry* pRHS = rSortData.pRight;
+ assert(pLHS && pRHS);
+
+ if (m_aCustomSort)
+ return m_aCustomSort(SalInstanceTreeIter(const_cast<SvTreeListEntry*>(pLHS)),
+ SalInstanceTreeIter(const_cast<SvTreeListEntry*>(pRHS)));
+
+ const SvLBoxString* pLeftTextItem;
+ const SvLBoxString* pRightTextItem;
+
+ if (m_nSortColumn != -1)
+ {
+ size_t col = to_internal_model(m_nSortColumn);
+
+ if (col < pLHS->ItemCount())
+ {
+ const SvLBoxString& rLeftTextItem
+ = static_cast<const SvLBoxString&>(pLHS->GetItem(col));
+ pLeftTextItem = &rLeftTextItem;
+ }
+ else
+ pLeftTextItem = nullptr;
+ if (col < pRHS->ItemCount())
+ {
+ const SvLBoxString& rRightTextItem
+ = static_cast<const SvLBoxString&>(pRHS->GetItem(col));
+ pRightTextItem = &rRightTextItem;
+ }
+ else
+ pRightTextItem = nullptr;
+ }
+ else
+ {
+ pLeftTextItem
+ = static_cast<const SvLBoxString*>(pLHS->GetFirstItem(SvLBoxItemType::String));
+ pRightTextItem
+ = static_cast<const SvLBoxString*>(pRHS->GetFirstItem(SvLBoxItemType::String));
+ }
+
+ return m_xTreeView->DefaultCompare(pLeftTextItem, pRightTextItem);
+}
+
+IMPL_LINK_NOARG(SalInstanceTreeView, VisibleRangeChangedHdl, SvTreeListBox*, void)
+{
+ if (notify_events_disabled())
+ return;
+ signal_visible_range_changed();
+}
+
+IMPL_LINK_NOARG(SalInstanceTreeView, ModelChangedHdl, SvTreeListBox*, void)
+{
+ if (notify_events_disabled())
+ return;
+ signal_model_changed();
+}
+
+IMPL_LINK_NOARG(SalInstanceTreeView, StartDragHdl, SvTreeListBox*, bool)
+{
+ bool bUnsetDragIcon(false); // ignored for vcl
+ if (m_aDragBeginHdl.Call(bUnsetDragIcon))
+ return true;
+ g_DragSource = this;
+ return false;
+}
+
+IMPL_STATIC_LINK_NOARG(SalInstanceTreeView, FinishDragHdl, SvTreeListBox*, void)
+{
+ g_DragSource = nullptr;
+}
+
+IMPL_LINK(SalInstanceTreeView, ToggleHdl, SvLBoxButtonData*, pData, void)
+{
+ SvTreeListEntry* pEntry = pData->GetActEntry();
+ SvLBoxButton* pBox = pData->GetActBox();
+
+ // tdf#122874 Select the row, calling SelectHdl, before handling
+ // the toggle
+ if (!m_xTreeView->IsSelected(pEntry))
+ {
+ m_xTreeView->SelectAll(false);
+ m_xTreeView->Select(pEntry, true);
+ }
+
+ // additionally set the cursor into the row the toggled element is in
+ m_xTreeView->pImpl->m_pCursor = pEntry;
+
+ for (int i = 0, nCount = pEntry->ItemCount(); i < nCount; ++i)
+ {
+ SvLBoxItem& rItem = pEntry->GetItem(i);
+ if (&rItem == pBox)
+ {
+ int nCol = to_external_model(i);
+ signal_toggled(iter_col(SalInstanceTreeIter(pEntry), nCol));
+ break;
+ }
+ }
+}
+
+IMPL_LINK_NOARG(SalInstanceTreeView, SelectHdl, SvTreeListBox*, void)
+{
+ if (notify_events_disabled())
+ return;
+ signal_changed();
+}
+
+IMPL_LINK_NOARG(SalInstanceTreeView, DeSelectHdl, SvTreeListBox*, void)
+{
+ if (notify_events_disabled())
+ return;
+ if (m_xTreeView->GetSelectionMode() == SelectionMode::Single
+ && !m_xTreeView->GetHoverSelection())
+ return;
+ signal_changed();
+}
+
+IMPL_LINK_NOARG(SalInstanceTreeView, DoubleClickHdl, SvTreeListBox*, bool)
+{
+ if (notify_events_disabled())
+ return false;
+ return !signal_row_activated();
+}
+
+IMPL_LINK(SalInstanceTreeView, EndDragHdl, HeaderBar*, pHeaderBar, void)
+{
+ std::vector<tools::Long> aTabPositions{ 0 };
+ for (int i = 0; i < pHeaderBar->GetItemCount() - 1; ++i)
+ aTabPositions.push_back(aTabPositions[i]
+ + pHeaderBar->GetItemSize(pHeaderBar->GetItemId(i)));
+ m_xTreeView->SetTabs(aTabPositions.size(), aTabPositions.data(), MapUnit::MapPixel);
+}
+
+IMPL_LINK(SalInstanceTreeView, HeaderBarClickedHdl, HeaderBar*, pHeaderBar, void)
+{
+ sal_uInt16 nId = pHeaderBar->GetCurItemId();
+ if (!(pHeaderBar->GetItemBits(nId) & HeaderBarItemBits::CLICKABLE))
+ return;
+ signal_column_clicked(pHeaderBar->GetItemPos(nId));
+}
+
+IMPL_LINK_NOARG(SalInstanceTreeView, ExpandingHdl, SvTreeListBox*, bool)
+{
+ SvTreeListEntry* pEntry = m_xTreeView->GetHdlEntry();
+ SalInstanceTreeIter aIter(pEntry);
+
+ if (m_xTreeView->IsExpanded(pEntry))
+ {
+ //collapsing;
+ return signal_collapsing(aIter);
+ }
+
+ // expanding
+ return ExpandRow(aIter);
+}
+
+bool SalInstanceTreeView::ExpandRow(const SalInstanceTreeIter& rIter)
+{
+ SvTreeListEntry* pEntry = rIter.iter;
+ // if there's a preexisting placeholder child, required to make this
+ // potentially expandable in the first place, now we remove it
+ SvTreeListEntry* pPlaceHolder = GetPlaceHolderChild(pEntry);
+ if (pPlaceHolder)
+ {
+ m_aExpandingPlaceHolderParents.insert(pEntry);
+ m_xTreeView->RemoveEntry(pPlaceHolder);
+ }
+
+ bool bRet = signal_expanding(rIter);
+
+ if (pPlaceHolder)
+ {
+ //expand disallowed, restore placeholder
+ if (!bRet)
+ {
+ pPlaceHolder = m_xTreeView->InsertEntry("<dummy>", pEntry, false, 0, nullptr);
+ SvViewDataEntry* pViewData = m_xTreeView->GetViewDataEntry(pPlaceHolder);
+ pViewData->SetSelectable(false);
+ }
+ m_aExpandingPlaceHolderParents.erase(pEntry);
+ }
+
+ return bRet;
+}
+
+IMPL_LINK(SalInstanceTreeView, PopupMenuHdl, const CommandEvent&, rEvent, bool)
+{
+ return m_aPopupMenuHdl.Call(rEvent);
+}
+
+IMPL_LINK(SalInstanceTreeView, EditingEntryHdl, SvTreeListEntry*, pEntry, bool)
+{
+ return signal_editing_started(SalInstanceTreeIter(pEntry));
+}
+
+IMPL_LINK(SalInstanceTreeView, EditedEntryHdl, IterString, rIterString, bool)
+{
+ return signal_editing_done(
+ iter_string(SalInstanceTreeIter(rIterString.first), rIterString.second));
+}
+
+SalInstanceIconView::SalInstanceIconView(::IconView* pIconView, SalInstanceBuilder* pBuilder,
+ bool bTakeOwnership)
+ : SalInstanceWidget(pIconView, pBuilder, bTakeOwnership)
+ , m_xIconView(pIconView)
+{
+ m_xIconView->SetSelectHdl(LINK(this, SalInstanceIconView, SelectHdl));
+ m_xIconView->SetDeselectHdl(LINK(this, SalInstanceIconView, DeSelectHdl));
+ m_xIconView->SetDoubleClickHdl(LINK(this, SalInstanceIconView, DoubleClickHdl));
+ m_xIconView->SetPopupMenuHdl(LINK(this, SalInstanceIconView, CommandHdl));
+
+ m_xIconView->SetEntryAccessibleDescriptionHdl(
+ LINK(this, SalInstanceIconView, EntryAccessibleDescriptionHdl));
+ m_xIconView->SetAccessible(m_xIconView->CreateAccessible());
+}
+
+int SalInstanceIconView::get_item_width() const { return m_xIconView->GetEntryWidth(); }
+void SalInstanceIconView::set_item_width(int width)
+{
+ m_xIconView->SetEntryWidth(width);
+ m_xIconView->Resize();
+}
+
+void SalInstanceIconView::freeze()
+{
+ bool bIsFirstFreeze = IsFirstFreeze();
+ SalInstanceWidget::freeze();
+ if (bIsFirstFreeze)
+ m_xIconView->SetUpdateMode(false);
+}
+
+void SalInstanceIconView::thaw()
+{
+ bool bIsLastThaw = IsLastThaw();
+ if (bIsLastThaw)
+ m_xIconView->SetUpdateMode(true);
+ SalInstanceWidget::thaw();
+}
+
+void SalInstanceIconView::insert(int pos, const OUString* pStr, const OUString* pId,
+ const OUString* pIconName, weld::TreeIter* pRet)
+{
+ disable_notify_events();
+ auto nInsertPos = pos == -1 ? TREELIST_APPEND : pos;
+ void* pUserData;
+ if (pId)
+ {
+ m_aUserData.emplace_back(std::make_unique<OUString>(*pId));
+ pUserData = m_aUserData.back().get();
+ }
+ else
+ pUserData = nullptr;
+
+ SvTreeListEntry* pEntry = new SvTreeListEntry;
+ if (pIconName)
+ {
+ Image aImage(createImage(*pIconName));
+ pEntry->AddItem(std::make_unique<SvLBoxContextBmp>(aImage, aImage, false));
+ }
+ else
+ {
+ Image aDummy;
+ pEntry->AddItem(std::make_unique<SvLBoxContextBmp>(aDummy, aDummy, false));
+ }
+ if (pStr)
+ pEntry->AddItem(std::make_unique<SvLBoxString>(*pStr));
+ pEntry->SetUserData(pUserData);
+ m_xIconView->Insert(pEntry, nullptr, nInsertPos);
+
+ if (pRet)
+ {
+ SalInstanceTreeIter* pVclRetIter = static_cast<SalInstanceTreeIter*>(pRet);
+ pVclRetIter->iter = pEntry;
+ }
+
+ enable_notify_events();
+}
+
+void SalInstanceIconView::insert(int pos, const OUString* pStr, const OUString* pId,
+ const VirtualDevice* pIcon, weld::TreeIter* pRet)
+{
+ disable_notify_events();
+ auto nInsertPos = pos == -1 ? TREELIST_APPEND : pos;
+ void* pUserData;
+ if (pId)
+ {
+ m_aUserData.emplace_back(std::make_unique<OUString>(*pId));
+ pUserData = m_aUserData.back().get();
+ }
+ else
+ pUserData = nullptr;
+
+ SvTreeListEntry* pEntry = new SvTreeListEntry;
+ if (pIcon)
+ {
+ const Point aNull(0, 0);
+ const Size aSize = pIcon->GetOutputSize();
+ Image aImage(pIcon->GetBitmapEx(aNull, aSize));
+ pEntry->AddItem(std::make_unique<SvLBoxContextBmp>(aImage, aImage, false));
+ }
+ else
+ {
+ Image aDummy;
+ pEntry->AddItem(std::make_unique<SvLBoxContextBmp>(aDummy, aDummy, false));
+ }
+ if (pStr)
+ pEntry->AddItem(std::make_unique<SvLBoxString>(*pStr));
+ pEntry->SetUserData(pUserData);
+ m_xIconView->Insert(pEntry, nullptr, nInsertPos);
+
+ if (pRet)
+ {
+ SalInstanceTreeIter* pVclRetIter = static_cast<SalInstanceTreeIter*>(pRet);
+ pVclRetIter->iter = pEntry;
+ }
+
+ enable_notify_events();
+}
+
+void SalInstanceIconView::insert_separator(int pos, const OUString* /* pId */)
+{
+ const auto nInsertPos = pos == -1 ? TREELIST_APPEND : pos;
+ const OUString sSep(VclResId(STR_SEPARATOR));
+ SvTreeListEntry* pEntry = new SvTreeListEntry;
+ pEntry->SetFlags(pEntry->GetFlags() | SvTLEntryFlags::IS_SEPARATOR);
+ const Image aDummy;
+ pEntry->AddItem(std::make_unique<SvLBoxContextBmp>(aDummy, aDummy, false));
+ pEntry->AddItem(std::make_unique<SvLBoxString>(sSep));
+ pEntry->SetUserData(nullptr);
+ m_xIconView->Insert(pEntry, nullptr, nInsertPos);
+ SvViewDataEntry* pViewData = m_xIconView->GetViewDataEntry(pEntry);
+ pViewData->SetSelectable(false);
+}
+
+IMPL_LINK(SalInstanceIconView, TooltipHdl, SvTreeListEntry*, pEntry, OUString)
+{
+ if (pEntry && !notify_events_disabled())
+ return signal_query_tooltip(SalInstanceTreeIter(pEntry));
+
+ return {};
+}
+
+IMPL_LINK(SalInstanceIconView, EntryAccessibleDescriptionHdl, SvTreeListEntry*, pEntry, OUString)
+{
+ OUString s = SvTreeListBox::SearchEntryTextWithHeadTitle(pEntry);
+ if (s.isEmpty())
+ s = signal_query_tooltip(SalInstanceTreeIter(pEntry));
+ return s;
+}
+
+void SalInstanceIconView::connect_query_tooltip(const Link<const weld::TreeIter&, OUString>& rLink)
+{
+ weld::IconView::connect_query_tooltip(rLink);
+ m_xIconView->SetTooltipHdl(LINK(this, SalInstanceIconView, TooltipHdl));
+}
+
+IMPL_LINK(SalInstanceIconView, DumpElemToPropertyTreeHdl, const ::IconView::json_prop_query&,
+ rQuery, bool)
+{
+ SvTreeListEntry* pEntry = std::get<1>(rQuery);
+ return m_aGetPropertyTreeElemHdl.Call(weld::json_prop_query(
+ std::get<0>(rQuery), SalInstanceTreeIter(pEntry), std::get<2>(rQuery)));
+}
+
+void SalInstanceIconView::connect_get_property_tree_elem(
+ const Link<const weld::json_prop_query&, bool>& rLink)
+{
+ weld::IconView::connect_get_property_tree_elem(rLink);
+ m_xIconView->SetDumpElemToPropertyTreeHdl(
+ LINK(this, SalInstanceIconView, DumpElemToPropertyTreeHdl));
+}
+
+OUString SalInstanceIconView::get_selected_id() const
+{
+ assert(m_xIconView->IsUpdateMode() && "don't request selection when frozen");
+ if (SvTreeListEntry* pEntry = m_xIconView->FirstSelected())
+ {
+ if (const OUString* pStr = static_cast<const OUString*>(pEntry->GetUserData()))
+ return *pStr;
+ }
+ return OUString();
+}
+
+OUString SalInstanceIconView::get_selected_text() const
+{
+ assert(m_xIconView->IsUpdateMode() && "don't request selection when frozen");
+ if (SvTreeListEntry* pEntry = m_xIconView->FirstSelected())
+ return m_xIconView->GetEntryText(pEntry);
+ return OUString();
+}
+
+int SalInstanceIconView::count_selected_items() const { return m_xIconView->GetSelectionCount(); }
+
+void SalInstanceIconView::select(int pos)
+{
+ assert(m_xIconView->IsUpdateMode()
+ && "don't select when frozen, select after thaw. Note selection doesn't survive a "
+ "freeze");
+ disable_notify_events();
+ if (pos == -1 || (pos == 0 && n_children() == 0))
+ m_xIconView->SelectAll(false);
+ else
+ {
+ SvTreeListEntry* pEntry = m_xIconView->GetEntry(nullptr, pos);
+ m_xIconView->Select(pEntry, true);
+ m_xIconView->MakeVisible(pEntry);
+ }
+ enable_notify_events();
+}
+
+void SalInstanceIconView::unselect(int pos)
+{
+ assert(m_xIconView->IsUpdateMode()
+ && "don't select when frozen, select after thaw. Note selection doesn't survive a "
+ "freeze");
+ disable_notify_events();
+ if (pos == -1)
+ m_xIconView->SelectAll(true);
+ else
+ {
+ SvTreeListEntry* pEntry = m_xIconView->GetEntry(nullptr, pos);
+ m_xIconView->Select(pEntry, false);
+ }
+ enable_notify_events();
+}
+
+int SalInstanceIconView::n_children() const
+{
+ return m_xIconView->GetModel()->GetChildList(nullptr).size();
+}
+
+std::unique_ptr<weld::TreeIter>
+SalInstanceIconView::make_iterator(const weld::TreeIter* pOrig) const
+{
+ return std::unique_ptr<weld::TreeIter>(
+ new SalInstanceTreeIter(static_cast<const SalInstanceTreeIter*>(pOrig)));
+}
+
+bool SalInstanceIconView::get_selected(weld::TreeIter* pIter) const
+{
+ SvTreeListEntry* pEntry = m_xIconView->FirstSelected();
+ auto pVclIter = static_cast<SalInstanceTreeIter*>(pIter);
+ if (pVclIter)
+ pVclIter->iter = pEntry;
+ return pEntry != nullptr;
+}
+
+bool SalInstanceIconView::get_cursor(weld::TreeIter* pIter) const
+{
+ SvTreeListEntry* pEntry = m_xIconView->GetCurEntry();
+ auto pVclIter = static_cast<SalInstanceTreeIter*>(pIter);
+ if (pVclIter)
+ pVclIter->iter = pEntry;
+ return pEntry != nullptr;
+}
+
+void SalInstanceIconView::set_cursor(const weld::TreeIter& rIter)
+{
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ disable_notify_events();
+ m_xIconView->SetCurEntry(rVclIter.iter);
+ enable_notify_events();
+}
+
+bool SalInstanceIconView::get_iter_first(weld::TreeIter& rIter) const
+{
+ SalInstanceTreeIter& rVclIter = static_cast<SalInstanceTreeIter&>(rIter);
+ rVclIter.iter = m_xIconView->GetEntry(0);
+ return rVclIter.iter != nullptr;
+}
+
+void SalInstanceIconView::scroll_to_item(const weld::TreeIter& rIter)
+{
+ assert(m_xIconView->IsUpdateMode()
+ && "don't select when frozen, select after thaw. Note selection doesn't survive a "
+ "freeze");
+ disable_notify_events();
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ m_xIconView->MakeVisible(rVclIter.iter);
+ enable_notify_events();
+}
+
+void SalInstanceIconView::selected_foreach(const std::function<bool(weld::TreeIter&)>& func)
+{
+ SalInstanceTreeIter aVclIter(m_xIconView->FirstSelected());
+ while (aVclIter.iter)
+ {
+ if (func(aVclIter))
+ return;
+ aVclIter.iter = m_xIconView->NextSelected(aVclIter.iter);
+ }
+}
+
+OUString SalInstanceIconView::get_id(const weld::TreeIter& rIter) const
+{
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ const OUString* pStr = static_cast<const OUString*>(rVclIter.iter->GetUserData());
+ if (pStr)
+ return *pStr;
+ return OUString();
+}
+
+OUString SalInstanceIconView::get_text(const weld::TreeIter& rIter) const
+{
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ return SvTabListBox::GetEntryText(rVclIter.iter, 0);
+}
+
+void SalInstanceIconView::clear()
+{
+ disable_notify_events();
+ m_xIconView->Clear();
+ m_aUserData.clear();
+ enable_notify_events();
+}
+
+SalInstanceIconView::~SalInstanceIconView()
+{
+ m_xIconView->SetDoubleClickHdl(Link<SvTreeListBox*, bool>());
+ m_xIconView->SetSelectHdl(Link<SvTreeListBox*, void>());
+ m_xIconView->SetDeselectHdl(Link<SvTreeListBox*, void>());
+}
+
+IMPL_LINK_NOARG(SalInstanceIconView, SelectHdl, SvTreeListBox*, void)
+{
+ if (notify_events_disabled())
+ return;
+ signal_selection_changed();
+}
+
+IMPL_LINK_NOARG(SalInstanceIconView, DeSelectHdl, SvTreeListBox*, void)
+{
+ if (notify_events_disabled())
+ return;
+ if (m_xIconView->GetSelectionMode() == SelectionMode::Single)
+ return;
+ signal_selection_changed();
+}
+
+IMPL_LINK_NOARG(SalInstanceIconView, DoubleClickHdl, SvTreeListBox*, bool)
+{
+ if (notify_events_disabled())
+ return false;
+ return !signal_item_activated();
+}
+
+IMPL_LINK(SalInstanceIconView, CommandHdl, const CommandEvent&, rEvent, bool)
+{
+ return m_aCommandHdl.Call(rEvent);
+}
+
+double SalInstanceSpinButton::toField(sal_Int64 nValue) const
+{
+ return static_cast<double>(nValue) / Power10(get_digits());
+}
+
+sal_Int64 SalInstanceSpinButton::fromField(double fValue) const
+{
+ auto const x = fValue * Power10(get_digits());
+ return x == double(std::numeric_limits<sal_Int64>::max())
+ ? std::numeric_limits<sal_Int64>::max()
+ : sal_Int64(std::round(x));
+}
+
+SalInstanceSpinButton::SalInstanceSpinButton(FormattedField* pButton, SalInstanceBuilder* pBuilder,
+ bool bTakeOwnership)
+ : SalInstanceEntry(pButton, pBuilder, bTakeOwnership)
+ , m_xButton(pButton)
+ , m_rFormatter(m_xButton->GetFormatter())
+{
+ m_rFormatter.SetThousandsSep(false); //off by default, MetricSpinButton enables it
+ m_xButton->SetUpHdl(LINK(this, SalInstanceSpinButton, UpDownHdl));
+ m_xButton->SetDownHdl(LINK(this, SalInstanceSpinButton, UpDownHdl));
+ m_xButton->SetLoseFocusHdl(LINK(this, SalInstanceSpinButton, LoseFocusHdl));
+ m_rFormatter.SetOutputHdl(LINK(this, SalInstanceSpinButton, OutputHdl));
+ m_rFormatter.SetInputHdl(LINK(this, SalInstanceSpinButton, InputHdl));
+ if (Edit* pEdit = m_xButton->GetSubEdit())
+ pEdit->SetActivateHdl(LINK(this, SalInstanceSpinButton, ActivateHdl));
+ else
+ m_xButton->SetActivateHdl(LINK(this, SalInstanceSpinButton, ActivateHdl));
+}
+
+sal_Int64 SalInstanceSpinButton::get_value() const { return fromField(m_rFormatter.GetValue()); }
+
+void SalInstanceSpinButton::set_value(sal_Int64 value) { m_rFormatter.SetValue(toField(value)); }
+
+void SalInstanceSpinButton::set_range(sal_Int64 min, sal_Int64 max)
+{
+ m_rFormatter.SetMinValue(toField(min));
+ m_rFormatter.SetMaxValue(toField(max));
+}
+
+void SalInstanceSpinButton::get_range(sal_Int64& min, sal_Int64& max) const
+{
+ min = fromField(m_rFormatter.GetMinValue());
+ max = fromField(m_rFormatter.GetMaxValue());
+}
+
+void SalInstanceSpinButton::set_increments(int step, int /*page*/)
+{
+ m_rFormatter.SetSpinSize(toField(step));
+}
+
+void SalInstanceSpinButton::get_increments(int& step, int& page) const
+{
+ step = fromField(m_rFormatter.GetSpinSize());
+ page = fromField(m_rFormatter.GetSpinSize());
+}
+
+void SalInstanceSpinButton::set_digits(unsigned int digits)
+{
+ m_rFormatter.SetDecimalDigits(digits);
+}
+
+// SpinButton may be comprised of multiple subwidgets, consider the lot as
+// one thing for focus
+bool SalInstanceSpinButton::has_focus() const { return m_xWidget->HasChildPathFocus(); }
+
+//off by default for direct SpinButtons, MetricSpinButton enables it
+void SalInstanceSpinButton::SetUseThousandSep() { m_rFormatter.SetThousandsSep(true); }
+
+unsigned int SalInstanceSpinButton::get_digits() const { return m_rFormatter.GetDecimalDigits(); }
+
+SalInstanceSpinButton::~SalInstanceSpinButton()
+{
+ if (Edit* pEdit = m_xButton->GetSubEdit())
+ pEdit->SetActivateHdl(Link<Edit&, bool>());
+ else
+ m_xButton->SetActivateHdl(Link<Edit&, bool>());
+ m_rFormatter.SetInputHdl(Link<sal_Int64*, TriState>());
+ m_rFormatter.SetOutputHdl(Link<LinkParamNone*, bool>());
+ m_xButton->SetLoseFocusHdl(Link<Control&, void>());
+ m_xButton->SetDownHdl(Link<SpinField&, void>());
+ m_xButton->SetUpHdl(Link<SpinField&, void>());
+}
+
+IMPL_LINK_NOARG(SalInstanceSpinButton, ActivateHdl, Edit&, bool)
+{
+ // tdf#122348 return pressed to end dialog
+ signal_value_changed();
+ return m_aActivateHdl.Call(*this);
+}
+
+IMPL_LINK_NOARG(SalInstanceSpinButton, UpDownHdl, SpinField&, void) { signal_value_changed(); }
+
+IMPL_LINK_NOARG(SalInstanceSpinButton, LoseFocusHdl, Control&, void) { signal_value_changed(); }
+
+IMPL_LINK_NOARG(SalInstanceSpinButton, OutputHdl, LinkParamNone*, bool) { return signal_output(); }
+
+IMPL_LINK(SalInstanceSpinButton, InputHdl, sal_Int64*, pResult, TriState)
+{
+ int nResult;
+ TriState eRet = signal_input(&nResult);
+ if (eRet == TRISTATE_TRUE)
+ *pResult = nResult;
+ return eRet;
+}
+
+SalInstanceFormattedSpinButton::SalInstanceFormattedSpinButton(FormattedField* pButton,
+ SalInstanceBuilder* pBuilder,
+ bool bTakeOwnership)
+ : SalInstanceEntry(pButton, pBuilder, bTakeOwnership)
+ , m_xButton(pButton)
+ , m_pFormatter(nullptr)
+{
+ m_xButton->SetUpHdl(LINK(this, SalInstanceFormattedSpinButton, UpDownHdl));
+ m_xButton->SetDownHdl(LINK(this, SalInstanceFormattedSpinButton, UpDownHdl));
+ m_xButton->SetLoseFocusHdl(LINK(this, SalInstanceFormattedSpinButton, LoseFocusHdl));
+}
+
+void SalInstanceFormattedSpinButton::set_text(const OUString& rText)
+{
+ disable_notify_events();
+ m_xButton->SpinField::SetText(rText);
+ enable_notify_events();
+}
+
+void SalInstanceFormattedSpinButton::connect_changed(const Link<weld::Entry&, void>& rLink)
+{
+ if (!m_pFormatter) // once a formatter is set, it takes over "changed"
+ {
+ SalInstanceEntry::connect_changed(rLink);
+ return;
+ }
+ m_pFormatter->connect_changed(rLink);
+}
+
+void SalInstanceFormattedSpinButton::connect_focus_out(const Link<weld::Widget&, void>& rLink)
+{
+ if (!m_pFormatter) // once a formatter is set, it takes over "focus-out"
+ {
+ m_aLoseFocusHdl = rLink;
+ return;
+ }
+ m_pFormatter->connect_focus_out(rLink);
+}
+
+void SalInstanceFormattedSpinButton::SetFormatter(weld::EntryFormatter* pFormatter)
+{
+ m_pFormatter = pFormatter;
+ m_xButton->SetFormatter(pFormatter);
+}
+
+Formatter& SalInstanceFormattedSpinButton::GetFormatter() { return m_xButton->GetFormatter(); }
+
+SalInstanceFormattedSpinButton::~SalInstanceFormattedSpinButton()
+{
+ m_xButton->SetLoseFocusHdl(Link<Control&, void>());
+ m_xButton->SetDownHdl(Link<SpinField&, void>());
+ m_xButton->SetUpHdl(Link<SpinField&, void>());
+}
+
+IMPL_LINK_NOARG(SalInstanceFormattedSpinButton, UpDownHdl, SpinField&, void)
+{
+ signal_value_changed();
+}
+
+IMPL_LINK_NOARG(SalInstanceFormattedSpinButton, LoseFocusHdl, Control&, void)
+{
+ if (!m_pFormatter)
+ signal_value_changed();
+ m_aLoseFocusHdl.Call(*this);
+}
+
+SalInstanceLabel::SalInstanceLabel(Control* pLabel, SalInstanceBuilder* pBuilder,
+ bool bTakeOwnership)
+ : SalInstanceWidget(pLabel, pBuilder, bTakeOwnership)
+ , m_xLabel(pLabel)
+{
+}
+
+void SalInstanceLabel::set_label(const OUString& rText) { m_xLabel->SetText(rText); }
+
+OUString SalInstanceLabel::get_label() const { return m_xLabel->GetText(); }
+
+void SalInstanceLabel::set_mnemonic_widget(Widget* pTarget)
+{
+ FixedText* pLabel = dynamic_cast<FixedText*>(m_xLabel.get());
+ assert(pLabel && "can't use set_mnemonic_widget on SelectableFixedText");
+ SalInstanceWidget* pTargetWidget = dynamic_cast<SalInstanceWidget*>(pTarget);
+ pLabel->set_mnemonic_widget(pTargetWidget ? pTargetWidget->getWidget() : nullptr);
+}
+
+void SalInstanceLabel::set_label_type(weld::LabelType eType)
+{
+ switch (eType)
+ {
+ case weld::LabelType::Normal:
+ m_xLabel->SetControlForeground();
+ m_xLabel->SetControlBackground();
+ break;
+ case weld::LabelType::Warning:
+ m_xLabel->SetControlForeground();
+ m_xLabel->SetControlBackground(
+ m_xLabel->GetSettings().GetStyleSettings().GetWarningColor());
+ break;
+ case weld::LabelType::Error:
+ m_xLabel->SetControlForeground();
+ m_xLabel->SetControlBackground(
+ m_xLabel->GetSettings().GetStyleSettings().GetHighlightColor());
+ break;
+ case weld::LabelType::Title:
+ m_xLabel->SetControlForeground(
+ m_xLabel->GetSettings().GetStyleSettings().GetLightColor());
+ m_xLabel->SetControlBackground();
+ break;
+ }
+}
+
+void SalInstanceLabel::set_font_color(const Color& rColor)
+{
+ if (rColor != COL_AUTO)
+ m_xLabel->SetControlForeground(rColor);
+ else
+ m_xLabel->SetControlForeground();
+}
+
+void SalInstanceLabel::set_font(const vcl::Font& rFont)
+{
+ m_xLabel->SetControlFont(rFont);
+ m_xLabel->Invalidate();
+}
+
+std::unique_ptr<weld::Label> SalInstanceFrame::weld_label_widget() const
+{
+ FixedText* pLabel = dynamic_cast<FixedText*>(m_xFrame->get_label_widget());
+ if (!pLabel)
+ return nullptr;
+ return std::make_unique<SalInstanceLabel>(pLabel, m_pBuilder, false);
+}
+
+SalInstanceTextView::SalInstanceTextView(VclMultiLineEdit* pTextView, SalInstanceBuilder* pBuilder,
+ bool bTakeOwnership)
+ : SalInstanceWidget(pTextView, pBuilder, bTakeOwnership)
+ , m_xTextView(pTextView)
+{
+ m_xTextView->SetModifyHdl(LINK(this, SalInstanceTextView, ChangeHdl));
+ ScrollBar& rVertScrollBar = m_xTextView->GetVScrollBar();
+ m_aOrigVScrollHdl = rVertScrollBar.GetScrollHdl();
+ rVertScrollBar.SetScrollHdl(LINK(this, SalInstanceTextView, VscrollHdl));
+}
+
+void SalInstanceTextView::set_text(const OUString& rText)
+{
+ disable_notify_events();
+ m_xTextView->SetText(rText);
+ enable_notify_events();
+}
+
+void SalInstanceTextView::replace_selection(const OUString& rText)
+{
+ disable_notify_events();
+ m_xTextView->ReplaceSelected(rText);
+ enable_notify_events();
+}
+
+OUString SalInstanceTextView::get_text() const { return m_xTextView->GetText(); }
+
+bool SalInstanceTextView::get_selection_bounds(int& rStartPos, int& rEndPos)
+{
+ const Selection& rSelection = m_xTextView->GetSelection();
+ rStartPos = rSelection.Min();
+ rEndPos = rSelection.Max();
+ return rSelection.Len();
+}
+
+void SalInstanceTextView::select_region(int nStartPos, int nEndPos)
+{
+ disable_notify_events();
+ tools::Long nStart = nStartPos < 0 ? SELECTION_MAX : nStartPos;
+ tools::Long nEnd = nEndPos < 0 ? SELECTION_MAX : nEndPos;
+ m_xTextView->SetSelection(Selection(nStart, nEnd));
+ enable_notify_events();
+}
+
+void SalInstanceTextView::set_editable(bool bEditable) { m_xTextView->SetReadOnly(!bEditable); }
+bool SalInstanceTextView::get_editable() const { return !m_xTextView->IsReadOnly(); }
+void SalInstanceTextView::set_max_length(int nChars) { m_xTextView->SetMaxTextLen(nChars); }
+
+void SalInstanceTextView::set_monospace(bool bMonospace)
+{
+ vcl::Font aOrigFont = m_xTextView->GetControlFont();
+ vcl::Font aFont;
+ if (bMonospace)
+ aFont
+ = OutputDevice::GetDefaultFont(DefaultFontType::UI_FIXED, LANGUAGE_DONTKNOW,
+ GetDefaultFontFlags::OnlyOne, m_xTextView->GetOutDev());
+ else
+ aFont = Application::GetSettings().GetStyleSettings().GetFieldFont();
+ aFont.SetFontHeight(aOrigFont.GetFontHeight());
+ set_font(aFont);
+}
+
+void SalInstanceTextView::set_font_color(const Color& rColor)
+{
+ if (rColor != COL_AUTO)
+ m_xTextView->SetControlForeground(rColor);
+ else
+ m_xTextView->SetControlForeground();
+}
+
+void SalInstanceTextView::set_font(const vcl::Font& rFont)
+{
+ m_xTextView->SetFont(rFont);
+ m_xTextView->SetControlFont(rFont);
+ m_xTextView->Invalidate();
+}
+
+void SalInstanceTextView::connect_cursor_position(const Link<TextView&, void>& rLink)
+{
+ assert(!m_aCursorPositionHdl.IsSet());
+ m_xTextView->AddEventListener(LINK(this, SalInstanceTextView, CursorListener));
+ weld::TextView::connect_cursor_position(rLink);
+}
+
+bool SalInstanceTextView::can_move_cursor_with_up() const
+{
+ bool bNoSelection = !m_xTextView->GetSelection();
+ return !bNoSelection || m_xTextView->CanUp();
+}
+
+bool SalInstanceTextView::can_move_cursor_with_down() const
+{
+ bool bNoSelection = !m_xTextView->GetSelection();
+ return !bNoSelection || m_xTextView->CanDown();
+}
+
+void SalInstanceTextView::cut_clipboard() { m_xTextView->Cut(); }
+
+void SalInstanceTextView::copy_clipboard() { m_xTextView->Copy(); }
+
+void SalInstanceTextView::paste_clipboard() { m_xTextView->Paste(); }
+
+void SalInstanceTextView::set_alignment(TxtAlign eXAlign)
+{
+ ::set_alignment(*m_xTextView, eXAlign);
+}
+
+int SalInstanceTextView::vadjustment_get_value() const
+{
+ ScrollBar& rVertScrollBar = m_xTextView->GetVScrollBar();
+ return rVertScrollBar.GetThumbPos();
+}
+
+void SalInstanceTextView::vadjustment_set_value(int value)
+{
+ ScrollBar& rVertScrollBar = m_xTextView->GetVScrollBar();
+ rVertScrollBar.SetThumbPos(value);
+ m_aOrigVScrollHdl.Call(&rVertScrollBar);
+}
+
+int SalInstanceTextView::vadjustment_get_upper() const
+{
+ ScrollBar& rVertScrollBar = m_xTextView->GetVScrollBar();
+ return rVertScrollBar.GetRangeMax();
+}
+
+int SalInstanceTextView::vadjustment_get_lower() const
+{
+ ScrollBar& rVertScrollBar = m_xTextView->GetVScrollBar();
+ return rVertScrollBar.GetRangeMin();
+}
+
+int SalInstanceTextView::vadjustment_get_page_size() const
+{
+ ScrollBar& rVertScrollBar = m_xTextView->GetVScrollBar();
+ return rVertScrollBar.GetVisibleSize();
+}
+
+bool SalInstanceTextView::has_focus() const { return m_xTextView->HasChildPathFocus(); }
+
+SalInstanceTextView::~SalInstanceTextView()
+{
+ if (!m_xTextView->isDisposed())
+ {
+ if (m_aCursorPositionHdl.IsSet())
+ m_xTextView->RemoveEventListener(LINK(this, SalInstanceTextView, CursorListener));
+ m_xTextView->SetModifyHdl(Link<Edit&, void>());
+ ScrollBar& rVertScrollBar = m_xTextView->GetVScrollBar();
+ rVertScrollBar.SetScrollHdl(m_aOrigVScrollHdl);
+ }
+}
+
+IMPL_LINK(SalInstanceTextView, VscrollHdl, ScrollBar*, pScrollBar, void)
+{
+ signal_vadjustment_changed();
+ m_aOrigVScrollHdl.Call(pScrollBar);
+}
+
+IMPL_LINK_NOARG(SalInstanceTextView, ChangeHdl, Edit&, void) { signal_changed(); }
+
+IMPL_LINK(SalInstanceTextView, CursorListener, VclWindowEvent&, rEvent, void)
+{
+ if (notify_events_disabled())
+ return;
+ if (rEvent.GetId() == VclEventId::EditSelectionChanged
+ || rEvent.GetId() == VclEventId::EditCaretChanged)
+ signal_cursor_position();
+}
+
+SalInstanceExpander::SalInstanceExpander(VclExpander* pExpander, SalInstanceBuilder* pBuilder,
+ bool bTakeOwnership)
+ : SalInstanceWidget(pExpander, pBuilder, bTakeOwnership)
+ , m_xExpander(pExpander)
+{
+ m_xExpander->SetExpandedHdl(LINK(this, SalInstanceExpander, ExpandedHdl));
+}
+
+void SalInstanceExpander::set_label(const OUString& rText) { m_xExpander->set_label(rText); }
+
+OUString SalInstanceExpander::get_label() const { return m_xExpander->get_label(); }
+
+bool SalInstanceExpander::get_expanded() const { return m_xExpander->get_expanded(); }
+
+void SalInstanceExpander::set_expanded(bool bExpand) { m_xExpander->set_expanded(bExpand); }
+
+bool SalInstanceExpander::has_focus() const
+{
+ return m_xExpander->get_label_widget()->HasFocus() || SalInstanceWidget::has_focus();
+}
+
+void SalInstanceExpander::grab_focus() { return m_xExpander->get_label_widget()->GrabFocus(); }
+
+SalInstanceExpander::~SalInstanceExpander()
+{
+ m_xExpander->SetExpandedHdl(Link<VclExpander&, void>());
+}
+
+IMPL_LINK_NOARG(SalInstanceExpander, ExpandedHdl, VclExpander&, void) { signal_expanded(); }
+
+// SalInstanceWidget has a generic listener for all these
+// events, ignore the ones we have specializations for
+// in VclDrawingArea
+void SalInstanceDrawingArea::HandleEventListener(VclWindowEvent& rEvent)
+{
+ if (rEvent.GetId() == VclEventId::WindowResize)
+ return;
+ SalInstanceWidget::HandleEventListener(rEvent);
+}
+
+void SalInstanceDrawingArea::HandleMouseEventListener(VclWindowEvent& rEvent)
+{
+ if (rEvent.GetId() == VclEventId::WindowMouseButtonDown
+ || rEvent.GetId() == VclEventId::WindowMouseButtonUp
+ || rEvent.GetId() == VclEventId::WindowMouseMove)
+ {
+ return;
+ }
+ SalInstanceWidget::HandleMouseEventListener(rEvent);
+}
+
+bool SalInstanceDrawingArea::HandleKeyEventListener(VclWindowEvent& /*rEvent*/) { return false; }
+
+SalInstanceDrawingArea::SalInstanceDrawingArea(VclDrawingArea* pDrawingArea,
+ SalInstanceBuilder* pBuilder, const a11yref& rAlly,
+ FactoryFunction pUITestFactoryFunction,
+ void* pUserData, bool bTakeOwnership)
+ : SalInstanceWidget(pDrawingArea, pBuilder, bTakeOwnership)
+ , m_xDrawingArea(pDrawingArea)
+{
+ m_xDrawingArea->SetAccessible(rAlly);
+ m_xDrawingArea->SetUITestFactory(std::move(pUITestFactoryFunction), pUserData);
+ m_xDrawingArea->SetPaintHdl(LINK(this, SalInstanceDrawingArea, PaintHdl));
+ m_xDrawingArea->SetResizeHdl(LINK(this, SalInstanceDrawingArea, ResizeHdl));
+ m_xDrawingArea->SetMousePressHdl(LINK(this, SalInstanceDrawingArea, MousePressHdl));
+ m_xDrawingArea->SetMouseMoveHdl(LINK(this, SalInstanceDrawingArea, MouseMoveHdl));
+ m_xDrawingArea->SetMouseReleaseHdl(LINK(this, SalInstanceDrawingArea, MouseReleaseHdl));
+ m_xDrawingArea->SetKeyPressHdl(LINK(this, SalInstanceDrawingArea, KeyPressHdl));
+ m_xDrawingArea->SetKeyReleaseHdl(LINK(this, SalInstanceDrawingArea, KeyReleaseHdl));
+ m_xDrawingArea->SetStyleUpdatedHdl(LINK(this, SalInstanceDrawingArea, StyleUpdatedHdl));
+ m_xDrawingArea->SetCommandHdl(LINK(this, SalInstanceDrawingArea, CommandHdl));
+ m_xDrawingArea->SetQueryTooltipHdl(LINK(this, SalInstanceDrawingArea, QueryTooltipHdl));
+ m_xDrawingArea->SetGetSurroundingHdl(LINK(this, SalInstanceDrawingArea, GetSurroundingHdl));
+ m_xDrawingArea->SetDeleteSurroundingHdl(
+ LINK(this, SalInstanceDrawingArea, DeleteSurroundingHdl));
+ m_xDrawingArea->SetStartDragHdl(LINK(this, SalInstanceDrawingArea, StartDragHdl));
+}
+
+void SalInstanceDrawingArea::queue_draw() { m_xDrawingArea->Invalidate(); }
+
+void SalInstanceDrawingArea::queue_draw_area(int x, int y, int width, int height)
+{
+ m_xDrawingArea->Invalidate(tools::Rectangle(Point(x, y), Size(width, height)));
+}
+
+void SalInstanceDrawingArea::connect_size_allocate(const Link<const Size&, void>& rLink)
+{
+ weld::Widget::connect_size_allocate(rLink);
+}
+
+void SalInstanceDrawingArea::connect_key_press(const Link<const KeyEvent&, bool>& rLink)
+{
+ weld::Widget::connect_key_press(rLink);
+}
+
+void SalInstanceDrawingArea::connect_key_release(const Link<const KeyEvent&, bool>& rLink)
+{
+ weld::Widget::connect_key_release(rLink);
+}
+
+void SalInstanceDrawingArea::connect_style_updated(const Link<Widget&, void>& rLink)
+{
+ weld::Widget::connect_style_updated(rLink);
+}
+
+void SalInstanceDrawingArea::set_cursor(PointerStyle ePointerStyle)
+{
+ m_xDrawingArea->SetPointer(ePointerStyle);
+}
+
+void SalInstanceDrawingArea::set_input_context(const InputContext& rInputContext)
+{
+ m_xDrawingArea->SetInputContext(rInputContext);
+}
+
+void SalInstanceDrawingArea::im_context_set_cursor_location(const tools::Rectangle& rCursorRect,
+ int nExtTextInputWidth)
+{
+ tools::Rectangle aCursorRect = m_xDrawingArea->PixelToLogic(rCursorRect);
+ m_xDrawingArea->SetCursorRect(
+ &aCursorRect, m_xDrawingArea->PixelToLogic(Size(nExtTextInputWidth, 0)).Width());
+}
+
+a11yref SalInstanceDrawingArea::get_accessible_parent()
+{
+ vcl::Window* pParent = m_xDrawingArea->GetParent();
+ if (pParent)
+ return pParent->GetAccessible();
+ return css::uno::Reference<css::accessibility::XAccessible>();
+}
+
+a11yrelationset SalInstanceDrawingArea::get_accessible_relation_set()
+{
+ rtl::Reference<utl::AccessibleRelationSetHelper> pRelationSetHelper
+ = new utl::AccessibleRelationSetHelper;
+ vcl::Window* pWindow = m_xDrawingArea.get();
+ if (pWindow)
+ {
+ vcl::Window* pLabeledBy = pWindow->GetAccessibleRelationLabeledBy();
+ if (pLabeledBy && pLabeledBy != pWindow)
+ {
+ css::uno::Sequence<css::uno::Reference<css::uno::XInterface>> aSequence{
+ pLabeledBy->GetAccessible()
+ };
+ pRelationSetHelper->AddRelation(css::accessibility::AccessibleRelation(
+ css::accessibility::AccessibleRelationType::LABELED_BY, aSequence));
+ }
+ vcl::Window* pMemberOf = pWindow->GetAccessibleRelationMemberOf();
+ if (pMemberOf && pMemberOf != pWindow)
+ {
+ css::uno::Sequence<css::uno::Reference<css::uno::XInterface>> aSequence{
+ pMemberOf->GetAccessible()
+ };
+ pRelationSetHelper->AddRelation(css::accessibility::AccessibleRelation(
+ css::accessibility::AccessibleRelationType::MEMBER_OF, aSequence));
+ }
+ }
+ return pRelationSetHelper;
+}
+
+AbsoluteScreenPixelPoint SalInstanceDrawingArea::get_accessible_location_on_screen()
+{
+ return m_xDrawingArea->OutputToAbsoluteScreenPixel(Point());
+}
+
+Point SalInstanceDrawingArea::get_pointer_position() const
+{
+ return m_xDrawingArea->GetPointerPosPixel();
+}
+
+void SalInstanceDrawingArea::enable_drag_source(rtl::Reference<TransferDataContainer>& rHelper,
+ sal_uInt8 eDNDConstants)
+{
+ m_xDrawingArea->SetDragHelper(rHelper, eDNDConstants);
+}
+
+SalInstanceDrawingArea::~SalInstanceDrawingArea()
+{
+ m_xDrawingArea->SetDeleteSurroundingHdl(Link<const Selection&, bool>());
+ m_xDrawingArea->SetGetSurroundingHdl(Link<OUString&, int>());
+ m_xDrawingArea->SetQueryTooltipHdl(Link<tools::Rectangle&, OUString>());
+ m_xDrawingArea->SetCommandHdl(Link<const CommandEvent&, bool>());
+ m_xDrawingArea->SetStyleUpdatedHdl(Link<VclDrawingArea&, void>());
+ m_xDrawingArea->SetMousePressHdl(Link<const MouseEvent&, bool>());
+ m_xDrawingArea->SetMouseMoveHdl(Link<const MouseEvent&, bool>());
+ m_xDrawingArea->SetMouseReleaseHdl(Link<const MouseEvent&, bool>());
+ m_xDrawingArea->SetKeyPressHdl(Link<const KeyEvent&, bool>());
+ m_xDrawingArea->SetKeyReleaseHdl(Link<const KeyEvent&, bool>());
+ m_xDrawingArea->SetResizeHdl(Link<const Size&, void>());
+ m_xDrawingArea->SetPaintHdl(
+ Link<std::pair<vcl::RenderContext&, const tools::Rectangle&>, void>());
+
+ // tdf#159089 dispose custom accessible here and unset for `m_xDrawingArea`
+ // rather than waiting for `m_xDrawingArea` to get disposed, to prevent
+ // unsafe use of the now potentially non-functional accessible until it
+ // gets disposed with the VclDrawingArea
+ css::uno::Reference<css::accessibility::XAccessible> xAccessible
+ = m_xDrawingArea->GetAccessible();
+ css::uno::Reference<css::lang::XComponent> xComp(xAccessible, css::uno::UNO_QUERY);
+ if (xComp.is())
+ {
+ xComp->dispose();
+ m_xDrawingArea->SetAccessible(nullptr);
+ }
+}
+
+OutputDevice& SalInstanceDrawingArea::get_ref_device() { return *m_xDrawingArea->GetOutDev(); }
+
+void SalInstanceDrawingArea::click(const Point& rPos)
+{
+ MouseEvent aEvent(rPos, 1, MouseEventModifiers::NONE, MOUSE_LEFT, 0);
+ VclPtr<VclDrawingArea> xDrawingArea(m_xDrawingArea);
+ xDrawingArea->MouseButtonDown(aEvent);
+ xDrawingArea->MouseButtonUp(aEvent);
+}
+
+void SalInstanceDrawingArea::dblclick(const Point& rPos)
+{
+ MouseEvent aEvent(rPos, 2, MouseEventModifiers::NONE, MOUSE_LEFT, 0);
+ VclPtr<VclDrawingArea> xDrawingArea(m_xDrawingArea);
+ xDrawingArea->MouseButtonDown(aEvent);
+ xDrawingArea->MouseButtonUp(aEvent);
+}
+
+void SalInstanceDrawingArea::mouse_up(const Point& rPos)
+{
+ MouseEvent aEvent(rPos, 0, MouseEventModifiers::NONE, MOUSE_LEFT, 0);
+ m_xDrawingArea->MouseButtonUp(aEvent);
+}
+
+void SalInstanceDrawingArea::mouse_down(const Point& rPos)
+{
+ MouseEvent aEvent(rPos, 0, MouseEventModifiers::NONE, MOUSE_LEFT, 0);
+ m_xDrawingArea->MouseButtonDown(aEvent);
+}
+
+void SalInstanceDrawingArea::mouse_move(const Point& rPos)
+{
+ MouseEvent aEvent(rPos, 0, MouseEventModifiers::NONE, MOUSE_LEFT, 0);
+ m_xDrawingArea->MouseMove(aEvent);
+}
+
+IMPL_LINK(SalInstanceDrawingArea, PaintHdl, target_and_area, aPayload, void)
+{
+ m_aDrawHdl.Call(aPayload);
+ tools::Rectangle aFocusRect(m_aGetFocusRectHdl.Call(*this));
+ if (!aFocusRect.IsEmpty())
+ InvertFocusRect(aPayload.first, aFocusRect);
+}
+
+IMPL_LINK(SalInstanceDrawingArea, ResizeHdl, const Size&, rSize, void)
+{
+ m_aSizeAllocateHdl.Call(rSize);
+}
+
+IMPL_LINK(SalInstanceDrawingArea, MousePressHdl, const MouseEvent&, rEvent, bool)
+{
+ return m_aMousePressHdl.Call(rEvent);
+}
+
+IMPL_LINK(SalInstanceDrawingArea, MouseMoveHdl, const MouseEvent&, rEvent, bool)
+{
+ return m_aMouseMotionHdl.Call(rEvent);
+}
+
+IMPL_LINK(SalInstanceDrawingArea, MouseReleaseHdl, const MouseEvent&, rEvent, bool)
+{
+ return m_aMouseReleaseHdl.Call(rEvent);
+}
+
+IMPL_LINK(SalInstanceDrawingArea, KeyPressHdl, const KeyEvent&, rEvent, bool)
+{
+ return m_aKeyPressHdl.Call(rEvent);
+}
+
+IMPL_LINK(SalInstanceDrawingArea, KeyReleaseHdl, const KeyEvent&, rEvent, bool)
+{
+ return m_aKeyReleaseHdl.Call(rEvent);
+}
+
+IMPL_LINK_NOARG(SalInstanceDrawingArea, StyleUpdatedHdl, VclDrawingArea&, void)
+{
+ m_aStyleUpdatedHdl.Call(*this);
+}
+
+IMPL_LINK(SalInstanceDrawingArea, CommandHdl, const CommandEvent&, rEvent, bool)
+{
+ return m_aCommandHdl.Call(rEvent);
+}
+
+IMPL_LINK(SalInstanceDrawingArea, GetSurroundingHdl, OUString&, rSurrounding, int)
+{
+ return m_aGetSurroundingHdl.Call(rSurrounding);
+}
+
+IMPL_LINK(SalInstanceDrawingArea, DeleteSurroundingHdl, const Selection&, rSelection, bool)
+{
+ return m_aDeleteSurroundingHdl.Call(rSelection);
+}
+
+IMPL_LINK(SalInstanceDrawingArea, QueryTooltipHdl, tools::Rectangle&, rHelpArea, OUString)
+{
+ return m_aQueryTooltipHdl.Call(rHelpArea);
+}
+
+IMPL_LINK_NOARG(SalInstanceDrawingArea, StartDragHdl, VclDrawingArea*, bool)
+{
+ if (m_aDragBeginHdl.Call(*this))
+ return true;
+ return false;
+}
+
+SalInstanceComboBoxWithoutEdit::SalInstanceComboBoxWithoutEdit(ListBox* pListBox,
+ SalInstanceBuilder* pBuilder,
+ bool bTakeOwnership)
+ : SalInstanceComboBox<ListBox>(pListBox, pBuilder, bTakeOwnership)
+{
+ m_xComboBox->SetSelectHdl(LINK(this, SalInstanceComboBoxWithoutEdit, SelectHdl));
+}
+
+OUString SalInstanceComboBoxWithoutEdit::get_active_text() const
+{
+ return m_xComboBox->GetSelectedEntry();
+}
+
+void SalInstanceComboBoxWithoutEdit::remove(int pos) { m_xComboBox->RemoveEntry(pos); }
+
+void SalInstanceComboBoxWithoutEdit::insert(int pos, const OUString& rStr, const OUString* pId,
+ const OUString* pIconName, VirtualDevice* pImageSurface)
+{
+ auto nInsertPos = pos == -1 ? COMBOBOX_APPEND : pos;
+ sal_Int32 nInsertedAt;
+ if (!pIconName && !pImageSurface)
+ nInsertedAt = m_xComboBox->InsertEntry(rStr, nInsertPos);
+ else if (pIconName)
+ nInsertedAt = m_xComboBox->InsertEntry(rStr, createImage(*pIconName), nInsertPos);
+ else
+ nInsertedAt = m_xComboBox->InsertEntry(rStr, createImage(*pImageSurface), nInsertPos);
+ if (pId)
+ {
+ m_aUserData.emplace_back(std::make_unique<OUString>(*pId));
+ m_xComboBox->SetEntryData(nInsertedAt, m_aUserData.back().get());
+ }
+}
+
+void SalInstanceComboBoxWithoutEdit::insert_separator(int pos, const OUString& /*rId*/)
+{
+ auto nInsertPos = pos == -1 ? m_xComboBox->GetEntryCount() : pos;
+ m_xComboBox->AddSeparator(nInsertPos - 1);
+}
+
+bool SalInstanceComboBoxWithoutEdit::has_entry() const { return false; }
+
+bool SalInstanceComboBoxWithoutEdit::changed_by_direct_pick() const { return true; }
+
+void SalInstanceComboBoxWithoutEdit::set_entry_message_type(weld::EntryMessageType /*eType*/)
+{
+ assert(false);
+}
+
+void SalInstanceComboBoxWithoutEdit::set_entry_text(const OUString& /*rText*/) { assert(false); }
+
+void SalInstanceComboBoxWithoutEdit::select_entry_region(int /*nStartPos*/, int /*nEndPos*/)
+{
+ assert(false);
+}
+
+bool SalInstanceComboBoxWithoutEdit::get_entry_selection_bounds(int& /*rStartPos*/,
+ int& /*rEndPos*/)
+{
+ assert(false);
+ return false;
+}
+
+void SalInstanceComboBoxWithoutEdit::set_entry_width_chars(int /*nChars*/) { assert(false); }
+
+void SalInstanceComboBoxWithoutEdit::set_entry_max_length(int /*nChars*/) { assert(false); }
+
+void SalInstanceComboBoxWithoutEdit::set_entry_completion(bool, bool) { assert(false); }
+
+void SalInstanceComboBoxWithoutEdit::set_entry_placeholder_text(const OUString&) { assert(false); }
+
+void SalInstanceComboBoxWithoutEdit::set_entry_editable(bool /*bEditable*/) { assert(false); }
+
+void SalInstanceComboBoxWithoutEdit::cut_entry_clipboard() { assert(false); }
+
+void SalInstanceComboBoxWithoutEdit::copy_entry_clipboard() { assert(false); }
+
+void SalInstanceComboBoxWithoutEdit::paste_entry_clipboard() { assert(false); }
+
+void SalInstanceComboBoxWithoutEdit::set_font(const vcl::Font& rFont)
+{
+ m_xComboBox->SetControlFont(rFont);
+ m_xComboBox->Invalidate();
+}
+
+void SalInstanceComboBoxWithoutEdit::set_entry_font(const vcl::Font&) { assert(false); }
+
+vcl::Font SalInstanceComboBoxWithoutEdit::get_entry_font()
+{
+ assert(false);
+ return vcl::Font();
+}
+
+void SalInstanceComboBoxWithoutEdit::set_custom_renderer(bool /*bOn*/)
+{
+ assert(false && "not implemented");
+}
+
+int SalInstanceComboBoxWithoutEdit::get_max_mru_count() const
+{
+ assert(false && "not implemented");
+ return 0;
+}
+
+void SalInstanceComboBoxWithoutEdit::set_max_mru_count(int) { assert(false && "not implemented"); }
+
+OUString SalInstanceComboBoxWithoutEdit::get_mru_entries() const
+{
+ assert(false && "not implemented");
+ return OUString();
+}
+
+void SalInstanceComboBoxWithoutEdit::set_mru_entries(const OUString&)
+{
+ assert(false && "not implemented");
+}
+
+void SalInstanceComboBoxWithoutEdit::HandleEventListener(VclWindowEvent& rEvent)
+{
+ CallHandleEventListener(rEvent);
+}
+
+SalInstanceComboBoxWithoutEdit::~SalInstanceComboBoxWithoutEdit()
+{
+ m_xComboBox->SetSelectHdl(Link<ListBox&, void>());
+}
+
+IMPL_LINK_NOARG(SalInstanceComboBoxWithoutEdit, SelectHdl, ListBox&, void)
+{
+ return signal_changed();
+}
+
+SalInstanceComboBoxWithEdit::SalInstanceComboBoxWithEdit(::ComboBox* pComboBox,
+ SalInstanceBuilder* pBuilder,
+ bool bTakeOwnership)
+ : SalInstanceComboBox<::ComboBox>(pComboBox, pBuilder, bTakeOwnership)
+ , m_aTextFilter(m_aEntryInsertTextHdl)
+ , m_bInSelect(false)
+{
+ m_xComboBox->SetModifyHdl(LINK(this, SalInstanceComboBoxWithEdit, ChangeHdl));
+ m_xComboBox->SetSelectHdl(LINK(this, SalInstanceComboBoxWithEdit, SelectHdl));
+ m_xComboBox->SetEntryActivateHdl(LINK(this, SalInstanceComboBoxWithEdit, EntryActivateHdl));
+ m_xComboBox->SetTextFilter(&m_aTextFilter);
+}
+
+bool SalInstanceComboBoxWithEdit::has_entry() const { return true; }
+
+void SalInstanceComboBoxWithEdit::call_attention_to()
+{
+ Edit* pEdit = m_xComboBox->GetSubEdit();
+ assert(pEdit);
+ m_xFlashAttention.reset(new SalFlashAttention(pEdit));
+ m_xFlashAttention->Start();
+}
+
+bool SalInstanceComboBoxWithEdit::changed_by_direct_pick() const
+{
+ return m_bInSelect && !m_xComboBox->IsModifyByKeyboard() && !m_xComboBox->IsTravelSelect();
+}
+
+void SalInstanceComboBoxWithEdit::set_entry_message_type(weld::EntryMessageType eType)
+{
+ Edit* pEdit = m_xComboBox->GetSubEdit();
+ assert(pEdit);
+ ::set_message_type(pEdit, eType);
+}
+
+OUString SalInstanceComboBoxWithEdit::get_active_text() const { return m_xComboBox->GetText(); }
+
+void SalInstanceComboBoxWithEdit::remove(int pos) { m_xComboBox->RemoveEntryAt(pos); }
+
+void SalInstanceComboBoxWithEdit::insert(int pos, const OUString& rStr, const OUString* pId,
+ const OUString* pIconName, VirtualDevice* pImageSurface)
+{
+ auto nInsertPos = pos == -1 ? COMBOBOX_APPEND : pos;
+ sal_Int32 nInsertedAt;
+ if (!pIconName && !pImageSurface)
+ nInsertedAt = m_xComboBox->InsertEntry(rStr, nInsertPos);
+ else if (pIconName)
+ nInsertedAt = m_xComboBox->InsertEntryWithImage(rStr, createImage(*pIconName), nInsertPos);
+ else
+ nInsertedAt
+ = m_xComboBox->InsertEntryWithImage(rStr, createImage(*pImageSurface), nInsertPos);
+ if (pId)
+ {
+ m_aUserData.emplace_back(std::make_unique<OUString>(*pId));
+ m_xComboBox->SetEntryData(nInsertedAt, m_aUserData.back().get());
+ }
+}
+
+void SalInstanceComboBoxWithEdit::insert_separator(int pos, const OUString& /*rId*/)
+{
+ auto nInsertPos = pos == -1 ? m_xComboBox->GetEntryCount() : pos;
+ m_xComboBox->AddSeparator(nInsertPos - 1);
+}
+
+void SalInstanceComboBoxWithEdit::set_entry_text(const OUString& rText)
+{
+ m_xComboBox->SetText(rText);
+}
+
+void SalInstanceComboBoxWithEdit::set_entry_width_chars(int nChars)
+{
+ m_xComboBox->SetWidthInChars(nChars);
+}
+
+void SalInstanceComboBoxWithEdit::set_entry_max_length(int nChars)
+{
+ m_xComboBox->SetMaxTextLen(nChars);
+}
+
+void SalInstanceComboBoxWithEdit::set_entry_completion(bool bEnable, bool bCaseSensitive)
+{
+ m_xComboBox->EnableAutocomplete(bEnable, bCaseSensitive);
+}
+
+void SalInstanceComboBoxWithEdit::set_entry_placeholder_text(const OUString& rText)
+{
+ m_xComboBox->SetPlaceholderText(rText);
+}
+
+void SalInstanceComboBoxWithEdit::set_entry_editable(bool bEditable)
+{
+ m_xComboBox->SetReadOnly(!bEditable);
+}
+
+void SalInstanceComboBoxWithEdit::cut_entry_clipboard() { m_xComboBox->Cut(); }
+
+void SalInstanceComboBoxWithEdit::copy_entry_clipboard() { m_xComboBox->Copy(); }
+
+void SalInstanceComboBoxWithEdit::paste_entry_clipboard() { m_xComboBox->Paste(); }
+
+void SalInstanceComboBoxWithEdit::select_entry_region(int nStartPos, int nEndPos)
+{
+ m_xComboBox->SetSelection(Selection(nStartPos, nEndPos < 0 ? SELECTION_MAX : nEndPos));
+}
+
+bool SalInstanceComboBoxWithEdit::get_entry_selection_bounds(int& rStartPos, int& rEndPos)
+{
+ const Selection& rSelection = m_xComboBox->GetSelection();
+ rStartPos = rSelection.Min();
+ rEndPos = rSelection.Max();
+ return rSelection.Len();
+}
+
+void SalInstanceComboBoxWithEdit::set_font(const vcl::Font& rFont)
+{
+ m_xComboBox->SetControlFont(rFont);
+ m_xComboBox->Invalidate();
+}
+
+void SalInstanceComboBoxWithEdit::set_entry_font(const vcl::Font& rFont)
+{
+ Edit* pEdit = m_xComboBox->GetSubEdit();
+ assert(pEdit);
+ pEdit->SetControlFont(rFont); // tdf#134601 set it as control font to take effect properly
+ pEdit->Invalidate();
+}
+
+vcl::Font SalInstanceComboBoxWithEdit::get_entry_font()
+{
+ Edit* pEdit = m_xComboBox->GetSubEdit();
+ assert(pEdit);
+ return pEdit->GetPointFont(*pEdit->GetOutDev());
+}
+
+void SalInstanceComboBoxWithEdit::set_custom_renderer(bool bOn)
+{
+ if (m_xComboBox->IsUserDrawEnabled() == bOn)
+ return;
+
+ auto nOldEntryHeight = m_xComboBox->GetDropDownEntryHeight();
+ auto nDropDownLineCount = m_xComboBox->GetDropDownLineCount();
+
+ m_xComboBox->EnableUserDraw(bOn);
+ if (bOn)
+ m_xComboBox->SetUserDrawHdl(LINK(this, SalInstanceComboBoxWithEdit, UserDrawHdl));
+ else
+ m_xComboBox->SetUserDrawHdl(Link<UserDrawEvent*, void>());
+
+ // adjust the line count to fit approx the height it would have been before
+ // changing the renderer
+ auto nNewEntryHeight = m_xComboBox->GetDropDownEntryHeight();
+ double fRatio = nOldEntryHeight / static_cast<double>(nNewEntryHeight);
+ m_xComboBox->SetDropDownLineCount(nDropDownLineCount * fRatio);
+}
+
+int SalInstanceComboBoxWithEdit::get_max_mru_count() const { return m_xComboBox->GetMaxMRUCount(); }
+
+void SalInstanceComboBoxWithEdit::set_max_mru_count(int nCount)
+{
+ return m_xComboBox->SetMaxMRUCount(nCount);
+}
+
+OUString SalInstanceComboBoxWithEdit::get_mru_entries() const
+{
+ return m_xComboBox->GetMRUEntries();
+}
+
+void SalInstanceComboBoxWithEdit::set_mru_entries(const OUString& rEntries)
+{
+ m_xComboBox->SetMRUEntries(rEntries);
+}
+
+void SalInstanceComboBoxWithEdit::HandleEventListener(VclWindowEvent& rEvent)
+{
+ if (rEvent.GetId() == VclEventId::DropdownPreOpen)
+ {
+ Size aRowSize(signal_custom_get_size(*m_xComboBox->GetOutDev()));
+ m_xComboBox->SetUserItemSize(aRowSize);
+ }
+ CallHandleEventListener(rEvent);
+}
+
+SalInstanceComboBoxWithEdit::~SalInstanceComboBoxWithEdit()
+{
+ m_xComboBox->SetTextFilter(nullptr);
+ m_xComboBox->SetEntryActivateHdl(Link<Edit&, bool>());
+ m_xComboBox->SetModifyHdl(Link<Edit&, void>());
+ m_xComboBox->SetSelectHdl(Link<::ComboBox&, void>());
+}
+
+IMPL_LINK_NOARG(SalInstanceComboBoxWithEdit, ChangeHdl, Edit&, void)
+{
+ if (!m_xComboBox->IsSyntheticModify()) // SelectHdl will be called
+ signal_changed();
+}
+
+IMPL_LINK_NOARG(SalInstanceComboBoxWithEdit, SelectHdl, ::ComboBox&, void)
+{
+ m_bInSelect = true;
+ signal_changed();
+ m_bInSelect = false;
+}
+
+IMPL_LINK_NOARG(SalInstanceComboBoxWithEdit, EntryActivateHdl, Edit&, bool)
+{
+ return m_aEntryActivateHdl.Call(*this);
+}
+
+IMPL_LINK(SalInstanceComboBoxWithEdit, UserDrawHdl, UserDrawEvent*, pEvent, void)
+{
+ call_signal_custom_render(pEvent);
+}
+
+class SalInstanceEntryTreeView : public SalInstanceContainer, public virtual weld::EntryTreeView
+{
+private:
+ DECL_LINK(AutocompleteHdl, Edit&, void);
+ DECL_LINK(KeyPressListener, VclWindowEvent&, void);
+ SalInstanceEntry* m_pEntry;
+ SalInstanceTreeView* m_pTreeView;
+ bool m_bTreeChange;
+
+public:
+ SalInstanceEntryTreeView(vcl::Window* pContainer, SalInstanceBuilder* pBuilder,
+ bool bTakeOwnership, std::unique_ptr<weld::Entry> xEntry,
+ std::unique_ptr<weld::TreeView> xTreeView)
+ : EntryTreeView(std::move(xEntry), std::move(xTreeView))
+ , SalInstanceContainer(pContainer, pBuilder, bTakeOwnership)
+ , m_pEntry(dynamic_cast<SalInstanceEntry*>(m_xEntry.get()))
+ , m_pTreeView(dynamic_cast<SalInstanceTreeView*>(m_xTreeView.get()))
+ , m_bTreeChange(false)
+ {
+ assert(m_pEntry && m_pTreeView);
+
+ Edit& rEntry = m_pEntry->getEntry();
+ rEntry.SetAutocompleteHdl(LINK(this, SalInstanceEntryTreeView, AutocompleteHdl));
+ rEntry.AddEventListener(LINK(this, SalInstanceEntryTreeView, KeyPressListener));
+ }
+
+ virtual void insert_separator(int /*pos*/, const OUString& /*rId*/) override { assert(false); }
+
+ virtual void make_sorted() override
+ {
+ vcl::Window* pTreeView = m_pTreeView->getWidget();
+ pTreeView->SetStyle(pTreeView->GetStyle() | WB_SORT);
+ }
+
+ virtual void set_entry_completion(bool bEnable, bool /*bCaseSensitive*/) override
+ {
+ assert(!bEnable && "not implemented yet");
+ (void)bEnable;
+ Edit& rEntry = m_pEntry->getEntry();
+ rEntry.SetAutocompleteHdl(Link<Edit&, void>());
+ }
+
+ virtual void set_font(const vcl::Font&) override { assert(false && "not implemented"); }
+
+ virtual void set_entry_font(const vcl::Font& rFont) override { m_pEntry->set_font(rFont); }
+
+ virtual vcl::Font get_entry_font() override
+ {
+ Edit& rEntry = m_pEntry->getEntry();
+ return rEntry.GetPointFont(*rEntry.GetOutDev());
+ }
+
+ virtual void set_entry_placeholder_text(const OUString& rText) override
+ {
+ Edit& rEntry = m_pEntry->getEntry();
+ rEntry.SetPlaceholderText(rText);
+ }
+
+ virtual void set_entry_editable(bool bEditable) override
+ {
+ Edit& rEntry = m_pEntry->getEntry();
+ rEntry.SetReadOnly(!bEditable);
+ }
+
+ virtual void cut_entry_clipboard() override
+ {
+ Edit& rEntry = m_pEntry->getEntry();
+ rEntry.Cut();
+ }
+
+ virtual void copy_entry_clipboard() override
+ {
+ Edit& rEntry = m_pEntry->getEntry();
+ rEntry.Copy();
+ }
+
+ virtual void paste_entry_clipboard() override
+ {
+ Edit& rEntry = m_pEntry->getEntry();
+ rEntry.Paste();
+ }
+
+ virtual void grab_focus() override { m_xEntry->grab_focus(); }
+
+ virtual void connect_focus_in(const Link<Widget&, void>& rLink) override
+ {
+ m_xEntry->connect_focus_in(rLink);
+ }
+
+ virtual void connect_focus_out(const Link<Widget&, void>& rLink) override
+ {
+ m_xEntry->connect_focus_out(rLink);
+ }
+
+ virtual bool changed_by_direct_pick() const override { return m_bTreeChange; }
+
+ virtual void set_custom_renderer(bool /*bOn*/) override { assert(false && "not implemented"); }
+
+ virtual int get_max_mru_count() const override
+ {
+ assert(false && "not implemented");
+ return 0;
+ }
+
+ virtual void set_max_mru_count(int) override { assert(false && "not implemented"); }
+
+ virtual OUString get_mru_entries() const override
+ {
+ assert(false && "not implemented");
+ return OUString();
+ }
+
+ virtual void set_mru_entries(const OUString&) override { assert(false && "not implemented"); }
+
+ virtual void set_item_menu(const OUString&, weld::Menu*) override
+ {
+ assert(false && "not implemented");
+ }
+
+ int get_menu_button_width() const override
+ {
+ assert(false && "not implemented");
+ return 0;
+ }
+
+ VclPtr<VirtualDevice> create_render_virtual_device() const override
+ {
+ return VclPtr<VirtualDevice>::Create();
+ }
+
+ virtual ~SalInstanceEntryTreeView() override
+ {
+ Edit& rEntry = m_pEntry->getEntry();
+ rEntry.RemoveEventListener(LINK(this, SalInstanceEntryTreeView, KeyPressListener));
+ rEntry.SetAutocompleteHdl(Link<Edit&, void>());
+ }
+};
+
+IMPL_LINK(SalInstanceEntryTreeView, KeyPressListener, VclWindowEvent&, rEvent, void)
+{
+ if (rEvent.GetId() != VclEventId::WindowKeyInput)
+ return;
+ const KeyEvent& rKeyEvent = *static_cast<KeyEvent*>(rEvent.GetData());
+ sal_uInt16 nKeyCode = rKeyEvent.GetKeyCode().GetCode();
+ if (!(nKeyCode == KEY_UP || nKeyCode == KEY_DOWN || nKeyCode == KEY_PAGEUP
+ || nKeyCode == KEY_PAGEDOWN))
+ return;
+
+ m_pTreeView->disable_notify_events();
+ auto& rListBox = m_pTreeView->getTreeView();
+ if (!rListBox.FirstSelected())
+ {
+ if (SvTreeListEntry* pEntry = rListBox.First())
+ rListBox.Select(pEntry, true);
+ }
+ else
+ rListBox.KeyInput(rKeyEvent);
+ m_xEntry->set_text(m_xTreeView->get_selected_text());
+ m_xEntry->select_region(0, -1);
+ m_pTreeView->enable_notify_events();
+ m_bTreeChange = true;
+ m_pEntry->fire_signal_changed();
+ m_bTreeChange = false;
+}
+
+IMPL_LINK(SalInstanceEntryTreeView, AutocompleteHdl, Edit&, rEdit, void)
+{
+ Selection aSel = rEdit.GetSelection();
+
+ OUString aFullText = rEdit.GetText();
+ OUString aStartText = aFullText.copy(0, static_cast<sal_Int32>(aSel.Max()));
+
+ int nPos = -1;
+ int nCount = m_xTreeView->n_children();
+ for (int i = 0; i < nCount; ++i)
+ {
+ if (m_xTreeView->get_text(i).startsWithIgnoreAsciiCase(aStartText))
+ {
+ nPos = i;
+ break;
+ }
+ }
+
+ m_xTreeView->select(nPos);
+
+ if (nPos != -1)
+ {
+ OUString aText = m_xTreeView->get_text(nPos);
+ Selection aSelection(aText.getLength(), aStartText.getLength());
+ rEdit.SetText(aText, aSelection);
+ }
+}
+
+SalInstancePopover::SalInstancePopover(DockingWindow* pPopover, SalInstanceBuilder* pBuilder,
+ bool bTakeOwnership)
+ : SalInstanceContainer(pPopover, pBuilder, bTakeOwnership)
+ , m_xPopover(pPopover)
+{
+}
+
+SalInstancePopover::~SalInstancePopover()
+{
+ DockingManager* pDockingManager = vcl::Window::GetDockingManager();
+ if (pDockingManager->IsInPopupMode(m_xPopover))
+ ImplPopDown();
+}
+
+void SalInstancePopover::popup_at_rect(weld::Widget* pParent, const tools::Rectangle& rRect,
+ weld::Placement ePlace)
+{
+ SalInstanceWidget* pVclWidget = dynamic_cast<SalInstanceWidget*>(pParent);
+ assert(pVclWidget);
+ vcl::Window* pWidget = pVclWidget->getWidget();
+
+ tools::Rectangle aRect;
+ Point aPt = pWidget->OutputToScreenPixel(rRect.TopLeft());
+ aRect.SetLeft(aPt.X());
+ aRect.SetTop(aPt.Y());
+ aPt = pWidget->OutputToScreenPixel(rRect.BottomRight());
+ aRect.SetRight(aPt.X());
+ aRect.SetBottom(aPt.Y());
+
+ FloatWinPopupFlags nFlags = FloatWinPopupFlags::GrabFocus | FloatWinPopupFlags::NoMouseUpClose;
+ if (ePlace == weld::Placement::Under)
+ nFlags = nFlags | FloatWinPopupFlags::Down;
+ else
+ nFlags = nFlags | FloatWinPopupFlags::Right;
+
+ m_xPopover->EnableDocking();
+ DockingManager* pDockingManager = vcl::Window::GetDockingManager();
+ pDockingManager->SetPopupModeEndHdl(m_xPopover,
+ LINK(this, SalInstancePopover, PopupModeEndHdl));
+ pDockingManager->StartPopupMode(m_xPopover, aRect, nFlags);
+}
+
+void SalInstancePopover::ImplPopDown()
+{
+ vcl::Window::GetDockingManager()->EndPopupMode(m_xPopover);
+ m_xPopover->EnableDocking(false);
+ signal_closed();
+}
+
+void SalInstancePopover::popdown() { ImplPopDown(); }
+
+void SalInstancePopover::resize_to_request()
+{
+ ::resize_to_request(m_xPopover.get());
+
+ DockingManager* pDockingManager = vcl::Window::GetDockingManager();
+ if (pDockingManager->IsInPopupMode(m_xPopover.get()))
+ {
+ Size aSize = m_xPopover->get_preferred_size();
+ tools::Rectangle aRect = pDockingManager->GetPosSizePixel(m_xPopover.get());
+ pDockingManager->SetPosSizePixel(m_xPopover.get(), aRect.Left(), aRect.Top(), aSize.Width(),
+ aSize.Height(), PosSizeFlags::Size);
+ }
+}
+
+IMPL_LINK_NOARG(SalInstancePopover, PopupModeEndHdl, FloatingWindow*, void) { signal_closed(); }
+
+SalInstanceBuilder::SalInstanceBuilder(vcl::Window* pParent, const OUString& rUIRoot,
+ const OUString& rUIFile,
+ const css::uno::Reference<css::frame::XFrame>& rFrame)
+ : weld::Builder()
+ , m_xBuilder(new VclBuilder(pParent, rUIRoot, rUIFile, {}, rFrame, false))
+{
+}
+
+std::unique_ptr<weld::MessageDialog> SalInstanceBuilder::weld_message_dialog(const OUString& id)
+{
+ MessageDialog* pMessageDialog = m_xBuilder->get<MessageDialog>(id);
+ std::unique_ptr<weld::MessageDialog> pRet(
+ pMessageDialog ? new SalInstanceMessageDialog(pMessageDialog, this, false) : nullptr);
+ if (pMessageDialog)
+ {
+ assert(!m_aOwnedToplevel && "only one toplevel per .ui allowed");
+ m_aOwnedToplevel.set(pMessageDialog);
+ m_xBuilder->drop_ownership(pMessageDialog);
+ }
+ return pRet;
+}
+
+std::unique_ptr<weld::Dialog> SalInstanceBuilder::weld_dialog(const OUString& id)
+{
+ Dialog* pDialog = m_xBuilder->get<Dialog>(id);
+ std::unique_ptr<weld::Dialog> pRet(pDialog ? new SalInstanceDialog(pDialog, this, false)
+ : nullptr);
+ if (pDialog)
+ {
+ assert(!m_aOwnedToplevel && "only one toplevel per .ui allowed");
+ m_aOwnedToplevel.set(pDialog);
+ m_xBuilder->drop_ownership(pDialog);
+ }
+ return pRet;
+}
+
+std::unique_ptr<weld::Assistant> SalInstanceBuilder::weld_assistant(const OUString& id)
+{
+ vcl::RoadmapWizard* pDialog = m_xBuilder->get<vcl::RoadmapWizard>(id);
+ std::unique_ptr<weld::Assistant> pRet(pDialog ? new SalInstanceAssistant(pDialog, this, false)
+ : nullptr);
+ if (pDialog)
+ {
+ assert(!m_aOwnedToplevel && "only one toplevel per .ui allowed");
+ m_aOwnedToplevel.set(pDialog);
+ m_xBuilder->drop_ownership(pDialog);
+ }
+ return pRet;
+}
+
+std::unique_ptr<weld::Window> SalInstanceBuilder::create_screenshot_window()
+{
+ assert(!m_aOwnedToplevel && "only one toplevel per .ui allowed");
+
+ vcl::Window* pRoot = m_xBuilder->get_widget_root();
+ if (SystemWindow* pWindow = dynamic_cast<SystemWindow*>(pRoot))
+ {
+ std::unique_ptr<weld::Window> xRet(new SalInstanceWindow(pWindow, this, false));
+ m_aOwnedToplevel.set(pWindow);
+ m_xBuilder->drop_ownership(pWindow);
+ return xRet;
+ }
+
+ VclPtrInstance<Dialog> xDialog(nullptr, WB_HIDE | WB_STDDIALOG | WB_SIZEABLE | WB_CLOSEABLE,
+ Dialog::InitFlag::NoParent);
+ xDialog->SetText(utl::ConfigManager::getProductName());
+
+ auto xContentArea = VclPtr<VclVBox>::Create(xDialog, false, 12);
+ pRoot->SetParent(xContentArea);
+ assert(pRoot == xContentArea->GetWindow(GetWindowType::FirstChild));
+ xContentArea->Show();
+ pRoot->Show();
+ xDialog->SetHelpId(pRoot->GetHelpId());
+
+ m_aOwnedToplevel.set(xDialog);
+
+ return std::unique_ptr<weld::Dialog>(new SalInstanceDialog(xDialog, this, false));
+}
+
+std::unique_ptr<weld::Widget> SalInstanceBuilder::weld_widget(const OUString& id)
+{
+ vcl::Window* pWidget = m_xBuilder->get(id);
+ return pWidget ? std::make_unique<SalInstanceWidget>(pWidget, this, false) : nullptr;
+}
+
+std::unique_ptr<weld::Container> SalInstanceBuilder::weld_container(const OUString& id)
+{
+ vcl::Window* pContainer = m_xBuilder->get(id);
+ return pContainer ? std::make_unique<SalInstanceContainer>(pContainer, this, false) : nullptr;
+}
+
+std::unique_ptr<weld::Box> SalInstanceBuilder::weld_box(const OUString& id)
+{
+ VclBox* pContainer = m_xBuilder->get<VclBox>(id);
+ return pContainer ? std::make_unique<SalInstanceBox>(pContainer, this, false) : nullptr;
+}
+
+std::unique_ptr<weld::Paned> SalInstanceBuilder::weld_paned(const OUString& id)
+{
+ VclPaned* pPaned = m_xBuilder->get<VclPaned>(id);
+ return pPaned ? std::make_unique<SalInstancePaned>(pPaned, this, false) : nullptr;
+}
+
+std::unique_ptr<weld::Frame> SalInstanceBuilder::weld_frame(const OUString& id)
+{
+ VclFrame* pFrame = m_xBuilder->get<VclFrame>(id);
+ std::unique_ptr<weld::Frame> pRet(pFrame ? new SalInstanceFrame(pFrame, this, false) : nullptr);
+ return pRet;
+}
+
+std::unique_ptr<weld::ScrolledWindow>
+SalInstanceBuilder::weld_scrolled_window(const OUString& id, bool bUserManagedScrolling)
+{
+ VclScrolledWindow* pScrolledWindow = m_xBuilder->get<VclScrolledWindow>(id);
+ return pScrolledWindow ? std::make_unique<SalInstanceScrolledWindow>(
+ pScrolledWindow, this, false, bUserManagedScrolling)
+ : nullptr;
+}
+
+std::unique_ptr<weld::Notebook> SalInstanceBuilder::weld_notebook(const OUString& id)
+{
+ vcl::Window* pNotebook = m_xBuilder->get(id);
+ if (!pNotebook)
+ return nullptr;
+ if (pNotebook->GetType() == WindowType::TABCONTROL)
+ return std::make_unique<SalInstanceNotebook>(static_cast<TabControl*>(pNotebook), this,
+ false);
+ if (pNotebook->GetType() == WindowType::VERTICALTABCONTROL)
+ return std::make_unique<SalInstanceVerticalNotebook>(
+ static_cast<VerticalTabControl*>(pNotebook), this, false);
+ return nullptr;
+}
+
+std::unique_ptr<weld::Button> SalInstanceBuilder::weld_button(const OUString& id)
+{
+ Button* pButton = m_xBuilder->get<Button>(id);
+ return pButton ? std::make_unique<SalInstanceButton>(pButton, this, false) : nullptr;
+}
+
+std::unique_ptr<weld::MenuButton> SalInstanceBuilder::weld_menu_button(const OUString& id)
+{
+ MenuButton* pButton = m_xBuilder->get<MenuButton>(id);
+ return pButton ? std::make_unique<SalInstanceMenuButton>(pButton, this, false) : nullptr;
+}
+
+std::unique_ptr<weld::MenuToggleButton>
+SalInstanceBuilder::weld_menu_toggle_button(const OUString& id)
+{
+ MenuToggleButton* pButton = m_xBuilder->get<MenuToggleButton>(id);
+ return pButton ? std::make_unique<SalInstanceMenuToggleButton>(pButton, this, false) : nullptr;
+}
+
+std::unique_ptr<weld::LinkButton> SalInstanceBuilder::weld_link_button(const OUString& id)
+{
+ FixedHyperlink* pButton = m_xBuilder->get<FixedHyperlink>(id);
+ return pButton ? std::make_unique<SalInstanceLinkButton>(pButton, this, false) : nullptr;
+}
+
+std::unique_ptr<weld::ToggleButton> SalInstanceBuilder::weld_toggle_button(const OUString& id)
+{
+ PushButton* pToggleButton = m_xBuilder->get<PushButton>(id);
+ return pToggleButton ? std::make_unique<SalInstanceToggleButton>(pToggleButton, this, false)
+ : nullptr;
+}
+
+std::unique_ptr<weld::RadioButton> SalInstanceBuilder::weld_radio_button(const OUString& id)
+{
+ RadioButton* pRadioButton = m_xBuilder->get<RadioButton>(id);
+ return pRadioButton ? std::make_unique<SalInstanceRadioButton>(pRadioButton, this, false)
+ : nullptr;
+}
+
+std::unique_ptr<weld::CheckButton> SalInstanceBuilder::weld_check_button(const OUString& id)
+{
+ CheckBox* pCheckButton = m_xBuilder->get<CheckBox>(id);
+ return pCheckButton ? std::make_unique<SalInstanceCheckButton>(pCheckButton, this, false)
+ : nullptr;
+}
+
+std::unique_ptr<weld::Scale> SalInstanceBuilder::weld_scale(const OUString& id)
+{
+ Slider* pSlider = m_xBuilder->get<Slider>(id);
+ return pSlider ? std::make_unique<SalInstanceScale>(pSlider, this, false) : nullptr;
+}
+
+std::unique_ptr<weld::ProgressBar> SalInstanceBuilder::weld_progress_bar(const OUString& id)
+{
+ ::ProgressBar* pProgress = m_xBuilder->get<::ProgressBar>(id);
+ return pProgress ? std::make_unique<SalInstanceProgressBar>(pProgress, this, false) : nullptr;
+}
+
+std::unique_ptr<weld::LevelBar> SalInstanceBuilder::weld_level_bar(const OUString& id)
+{
+ ::ProgressBar* pLevel = m_xBuilder->get<::ProgressBar>(id);
+ return pLevel ? std::make_unique<SalInstanceLevelBar>(pLevel, this, false) : nullptr;
+}
+
+std::unique_ptr<weld::Spinner> SalInstanceBuilder::weld_spinner(const OUString& id)
+{
+ Throbber* pThrobber = m_xBuilder->get<Throbber>(id);
+ return pThrobber ? std::make_unique<SalInstanceSpinner>(pThrobber, this, false) : nullptr;
+}
+
+std::unique_ptr<weld::Image> SalInstanceBuilder::weld_image(const OUString& id)
+{
+ FixedImage* pImage = m_xBuilder->get<FixedImage>(id);
+ return pImage ? std::make_unique<SalInstanceImage>(pImage, this, false) : nullptr;
+}
+
+std::unique_ptr<weld::Calendar> SalInstanceBuilder::weld_calendar(const OUString& id)
+{
+ Calendar* pCalendar = m_xBuilder->get<Calendar>(id);
+ return pCalendar ? std::make_unique<SalInstanceCalendar>(pCalendar, this, false) : nullptr;
+}
+
+std::unique_ptr<weld::Entry> SalInstanceBuilder::weld_entry(const OUString& id)
+{
+ Edit* pEntry = m_xBuilder->get<Edit>(id);
+ return pEntry ? std::make_unique<SalInstanceEntry>(pEntry, this, false) : nullptr;
+}
+
+std::unique_ptr<weld::SpinButton> SalInstanceBuilder::weld_spin_button(const OUString& id)
+{
+ FormattedField* pSpinButton = m_xBuilder->get<FormattedField>(id);
+ return pSpinButton ? std::make_unique<SalInstanceSpinButton>(pSpinButton, this, false)
+ : nullptr;
+}
+
+std::unique_ptr<weld::MetricSpinButton>
+SalInstanceBuilder::weld_metric_spin_button(const OUString& id, FieldUnit eUnit)
+{
+ std::unique_ptr<weld::SpinButton> xButton(weld_spin_button(id));
+ if (xButton)
+ {
+ SalInstanceSpinButton& rButton = dynamic_cast<SalInstanceSpinButton&>(*xButton);
+ rButton.SetUseThousandSep();
+ }
+ return std::make_unique<weld::MetricSpinButton>(std::move(xButton), eUnit);
+}
+
+std::unique_ptr<weld::FormattedSpinButton>
+SalInstanceBuilder::weld_formatted_spin_button(const OUString& id)
+{
+ FormattedField* pSpinButton = m_xBuilder->get<FormattedField>(id);
+ return pSpinButton ? std::make_unique<SalInstanceFormattedSpinButton>(pSpinButton, this, false)
+ : nullptr;
+}
+
+std::unique_ptr<weld::ComboBox> SalInstanceBuilder::weld_combo_box(const OUString& id)
+{
+ vcl::Window* pWidget = m_xBuilder->get(id);
+ ::ComboBox* pComboBox = dynamic_cast<::ComboBox*>(pWidget);
+ if (pComboBox)
+ return std::make_unique<SalInstanceComboBoxWithEdit>(pComboBox, this, false);
+ ListBox* pListBox = dynamic_cast<ListBox*>(pWidget);
+ return pListBox ? std::make_unique<SalInstanceComboBoxWithoutEdit>(pListBox, this, false)
+ : nullptr;
+}
+
+std::unique_ptr<weld::EntryTreeView>
+SalInstanceBuilder::weld_entry_tree_view(const OUString& containerid, const OUString& entryid,
+ const OUString& treeviewid)
+{
+ vcl::Window* pContainer = m_xBuilder->get(containerid);
+ return pContainer ? std::make_unique<SalInstanceEntryTreeView>(pContainer, this, false,
+ weld_entry(entryid),
+ weld_tree_view(treeviewid))
+ : nullptr;
+}
+
+std::unique_ptr<weld::TreeView> SalInstanceBuilder::weld_tree_view(const OUString& id)
+{
+ SvTabListBox* pTreeView = m_xBuilder->get<SvTabListBox>(id);
+ return pTreeView ? std::make_unique<SalInstanceTreeView>(pTreeView, this, false) : nullptr;
+}
+
+std::unique_ptr<weld::IconView> SalInstanceBuilder::weld_icon_view(const OUString& id)
+{
+ IconView* pIconView = m_xBuilder->get<IconView>(id);
+ return pIconView ? std::make_unique<SalInstanceIconView>(pIconView, this, false) : nullptr;
+}
+
+std::unique_ptr<weld::Label> SalInstanceBuilder::weld_label(const OUString& id)
+{
+ Control* pLabel = m_xBuilder->get<Control>(id);
+ return pLabel ? std::make_unique<SalInstanceLabel>(pLabel, this, false) : nullptr;
+}
+
+std::unique_ptr<weld::TextView> SalInstanceBuilder::weld_text_view(const OUString& id)
+{
+ VclMultiLineEdit* pTextView = m_xBuilder->get<VclMultiLineEdit>(id);
+ return pTextView ? std::make_unique<SalInstanceTextView>(pTextView, this, false) : nullptr;
+}
+
+std::unique_ptr<weld::Expander> SalInstanceBuilder::weld_expander(const OUString& id)
+{
+ VclExpander* pExpander = m_xBuilder->get<VclExpander>(id);
+ return pExpander ? std::make_unique<SalInstanceExpander>(pExpander, this, false) : nullptr;
+}
+
+std::unique_ptr<weld::DrawingArea>
+SalInstanceBuilder::weld_drawing_area(const OUString& id, const a11yref& rA11yImpl,
+ FactoryFunction pUITestFactoryFunction, void* pUserData)
+{
+ VclDrawingArea* pDrawingArea = m_xBuilder->get<VclDrawingArea>(id);
+ return pDrawingArea
+ ? std::make_unique<SalInstanceDrawingArea>(pDrawingArea, this, rA11yImpl,
+ pUITestFactoryFunction, pUserData, false)
+ : nullptr;
+}
+
+std::unique_ptr<weld::Menu> SalInstanceBuilder::weld_menu(const OUString& id)
+{
+ PopupMenu* pMenu = m_xBuilder->get_menu(id);
+ return pMenu ? std::make_unique<SalInstanceMenu>(pMenu, true) : nullptr;
+}
+
+std::unique_ptr<weld::Popover> SalInstanceBuilder::weld_popover(const OUString& id)
+{
+ DockingWindow* pDockingWindow = m_xBuilder->get<DockingWindow>(id);
+ std::unique_ptr<weld::Popover> pRet(
+ pDockingWindow ? new SalInstancePopover(pDockingWindow, this, false) : nullptr);
+ if (pDockingWindow)
+ {
+ assert(!m_aOwnedToplevel && "only one toplevel per .ui allowed");
+ m_aOwnedToplevel.set(pDockingWindow);
+ m_xBuilder->drop_ownership(pDockingWindow);
+ }
+ return pRet;
+}
+
+std::unique_ptr<weld::Toolbar> SalInstanceBuilder::weld_toolbar(const OUString& id)
+{
+ ToolBox* pToolBox = m_xBuilder->get<ToolBox>(id);
+ return pToolBox ? std::make_unique<SalInstanceToolbar>(pToolBox, this, false) : nullptr;
+}
+
+std::unique_ptr<weld::Scrollbar> SalInstanceBuilder::weld_scrollbar(const OUString& id)
+{
+ ScrollBar* pScrollbar = m_xBuilder->get<ScrollBar>(id);
+ return pScrollbar ? std::make_unique<SalInstanceScrollbar>(pScrollbar, this, false) : nullptr;
+}
+
+std::unique_ptr<weld::SizeGroup> SalInstanceBuilder::create_size_group()
+{
+ return std::make_unique<SalInstanceSizeGroup>();
+}
+
+OUString SalInstanceBuilder::get_current_page_help_id() const
+{
+ vcl::Window* pCtrl = m_xBuilder->get("tabcontrol");
+ if (!pCtrl)
+ return {};
+ VclPtr<vcl::Window> xTabPage;
+ if (pCtrl->GetType() == WindowType::TABCONTROL)
+ {
+ TabControl* pTabCtrl = static_cast<TabControl*>(pCtrl);
+ xTabPage = pTabCtrl->GetTabPage(pTabCtrl->GetCurPageId());
+ }
+ else if (pCtrl->GetType() == WindowType::VERTICALTABCONTROL)
+ {
+ VerticalTabControl* pTabCtrl = static_cast<VerticalTabControl*>(pCtrl);
+ xTabPage = pTabCtrl->GetPage(pTabCtrl->GetCurPageId());
+ }
+ vcl::Window* pTabChild = xTabPage ? xTabPage->GetWindow(GetWindowType::FirstChild) : nullptr;
+ pTabChild = pTabChild ? pTabChild->GetWindow(GetWindowType::FirstChild) : nullptr;
+ if (pTabChild)
+ return pTabChild->GetHelpId();
+ return {};
+}
+
+SalInstanceBuilder::~SalInstanceBuilder()
+{
+ if (VclBuilderContainer* pOwnedToplevel
+ = dynamic_cast<VclBuilderContainer*>(m_aOwnedToplevel.get()))
+ pOwnedToplevel->m_pUIBuilder = std::move(m_xBuilder);
+ else
+ m_xBuilder.reset();
+ m_aOwnedToplevel.disposeAndClear();
+}
+
+std::unique_ptr<weld::Builder>
+SalInstance::CreateBuilder(weld::Widget* pParent, const OUString& rUIRoot, const OUString& rUIFile)
+{
+ SalInstanceWidget* pParentInstance = dynamic_cast<SalInstanceWidget*>(pParent);
+ vcl::Window* pParentWidget = pParentInstance ? pParentInstance->getWidget() : nullptr;
+ return std::make_unique<SalInstanceBuilder>(pParentWidget, rUIRoot, rUIFile);
+}
+
+std::unique_ptr<weld::Builder> SalInstance::CreateInterimBuilder(vcl::Window* pParent,
+ const OUString& rUIRoot,
+ const OUString& rUIFile, bool,
+ sal_uInt64)
+{
+ return std::make_unique<SalInstanceBuilder>(pParent, rUIRoot, rUIFile);
+}
+
+void SalInstanceWindow::help()
+{
+ //show help for widget with keyboard focus
+ vcl::Window* pWidget = ImplGetSVData()->mpWinData->mpFocusWin;
+ if (!pWidget)
+ pWidget = m_xWindow;
+ if (comphelper::LibreOfficeKit::isActive() && m_xWindow->GetFocusedWindow())
+ pWidget = m_xWindow->GetFocusedWindow().get();
+ OUString sHelpId = pWidget->GetHelpId();
+ while (sHelpId.isEmpty())
+ {
+ pWidget = pWidget->GetParent();
+ if (!pWidget)
+ break;
+ sHelpId = pWidget->GetHelpId();
+ }
+ std::unique_ptr<weld::Widget> xTemp(
+ pWidget != m_xWindow ? new SalInstanceWidget(pWidget, m_pBuilder, false) : nullptr);
+ weld::Widget* pSource = xTemp ? xTemp.get() : this;
+ bool bRunNormalHelpRequest = !m_aHelpRequestHdl.IsSet() || m_aHelpRequestHdl.Call(*pSource);
+ Help* pHelp = bRunNormalHelpRequest ? Application::GetHelp() : nullptr;
+ if (!pHelp)
+ return;
+
+ // tdf#126007, there's a nice fallback route for offline help where
+ // the current page of a notebook will get checked when the help
+ // button is pressed and there was no help for the dialog found.
+ //
+ // But for online help that route doesn't get taken, so bodge this here
+ // by using the page help id if available and if the help button itself
+ // was the original id
+ if (m_pBuilder && sHelpId.endsWith("/help"))
+ {
+ OUString sPageId = m_pBuilder->get_current_page_help_id();
+ if (!sPageId.isEmpty())
+ sHelpId = sPageId;
+ else
+ {
+ // tdf#129068 likewise the help for the wrapping dialog is less
+ // helpful than the help for the content area could be
+ vcl::Window* pContentArea = nullptr;
+ if (::Dialog* pDialog = dynamic_cast<::Dialog*>(m_xWindow.get()))
+ pContentArea = pDialog->get_content_area();
+ if (pContentArea)
+ {
+ vcl::Window* pContentWidget = pContentArea->GetWindow(GetWindowType::LastChild);
+ if (pContentWidget)
+ sHelpId = pContentWidget->GetHelpId();
+ }
+ }
+ }
+ pHelp->Start(sHelpId, pSource);
+}
+
+//iterate upwards through the hierarchy from this widgets through its parents
+//calling func with their helpid until func returns true or we run out of parents
+void SalInstanceWidget::help_hierarchy_foreach(const std::function<bool(const OUString&)>& func)
+{
+ vcl::Window* pParent = m_xWidget;
+ while ((pParent = pParent->GetParent()))
+ {
+ if (func(pParent->GetHelpId()))
+ return;
+ }
+}
+
+weld::MessageDialog* SalInstance::CreateMessageDialog(weld::Widget* pParent,
+ VclMessageType eMessageType,
+ VclButtonsType eButtonsType,
+ const OUString& rPrimaryMessage)
+{
+ SalInstanceWidget* pParentInstance = dynamic_cast<SalInstanceWidget*>(pParent);
+ SystemWindow* pParentWidget = pParentInstance ? pParentInstance->getSystemWindow() : nullptr;
+ VclPtrInstance<MessageDialog> xMessageDialog(pParentWidget, rPrimaryMessage, eMessageType,
+ eButtonsType);
+ return new SalInstanceMessageDialog(xMessageDialog, nullptr, true);
+}
+
+weld::Window* SalInstance::GetFrameWeld(const css::uno::Reference<css::awt::XWindow>& rWindow)
+{
+ UnoWrapperBase* pWrapper = UnoWrapperBase::GetUnoWrapper();
+ if (!pWrapper)
+ return nullptr;
+ VclPtr<vcl::Window> xWindow = pWrapper->GetWindow(rWindow);
+ if (!xWindow)
+ return nullptr;
+ return xWindow->GetFrameWeld();
+}
+
+weld::Window* SalFrame::GetFrameWeld() const
+{
+ if (!m_xFrameWeld)
+ {
+ vcl::Window* pWindow = GetWindow();
+ if (pWindow)
+ {
+ assert(pWindow == pWindow->GetFrameWindow());
+ m_xFrameWeld.reset(new SalInstanceWindow(pWindow, nullptr, false));
+ }
+ }
+ return m_xFrameWeld.get();
+}
+
+Selection SalFrame::CalcDeleteSurroundingSelection(const OUString& rSurroundingText,
+ sal_Int32 nCursorIndex, int nOffset, int nChars)
+{
+ Selection aInvalid(SAL_MAX_UINT32, SAL_MAX_UINT32);
+
+ if (nCursorIndex == -1)
+ return aInvalid;
+
+ if (nOffset > 0)
+ {
+ while (nOffset && nCursorIndex < rSurroundingText.getLength())
+ {
+ rSurroundingText.iterateCodePoints(&nCursorIndex, 1);
+ --nOffset;
+ }
+ }
+ else if (nOffset < 0)
+ {
+ while (nOffset && nCursorIndex > 0)
+ {
+ rSurroundingText.iterateCodePoints(&nCursorIndex, -1);
+ ++nOffset;
+ }
+ }
+
+ if (nOffset)
+ {
+ SAL_WARN("vcl",
+ "SalFrame::CalcDeleteSurroundingSelection, unable to move to offset: " << nOffset);
+ return aInvalid;
+ }
+
+ sal_Int32 nCursorEndIndex(nCursorIndex);
+ sal_Int32 nCount(0);
+ while (nCount < nChars && nCursorEndIndex < rSurroundingText.getLength())
+ {
+ rSurroundingText.iterateCodePoints(&nCursorEndIndex, 1);
+ ++nCount;
+ }
+
+ if (nCount != nChars)
+ {
+ SAL_WARN("vcl", "SalFrame::CalcDeleteSurroundingSelection, unable to select: "
+ << nChars << " characters");
+ return aInvalid;
+ }
+
+ return Selection(nCursorIndex, nCursorEndIndex);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/app/scheduler.cxx b/vcl/source/app/scheduler.cxx
new file mode 100644
index 0000000000..e6893055f6
--- /dev/null
+++ b/vcl/source/app/scheduler.cxx
@@ -0,0 +1,667 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cassert>
+#include <cstdlib>
+#include <exception>
+#include <typeinfo>
+
+#include <com/sun/star/uno/Exception.hpp>
+#include <sal/log.hxx>
+#include <sal/types.h>
+#include <svdata.hxx>
+#include <tools/time.hxx>
+#include <tools/debug.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <unotools/configmgr.hxx>
+#include <vcl/TaskStopwatch.hxx>
+#include <vcl/scheduler.hxx>
+#include <vcl/idle.hxx>
+#include <saltimer.hxx>
+#include <salinst.hxx>
+#include <comphelper/profilezone.hxx>
+#include <schedulerimpl.hxx>
+
+namespace {
+
+template< typename charT, typename traits >
+std::basic_ostream<charT, traits> & operator <<(
+ std::basic_ostream<charT, traits> & stream, const Task& task )
+{
+ stream << "a: " << task.IsActive() << " p: " << static_cast<int>(task.GetPriority());
+ const char *name = task.GetDebugName();
+ if( nullptr == name )
+ return stream << " (nullptr)";
+ else
+ return stream << " " << name;
+}
+
+/**
+ * clang won't compile this in the Timer.hxx header, even with a class Idle
+ * forward definition, due to the incomplete Idle type in the template.
+ * Currently the code is just used in the Scheduler, so we keep it local.
+ *
+ * @see http://clang.llvm.org/compatibility.html#undep_incomplete
+ */
+template< typename charT, typename traits >
+std::basic_ostream<charT, traits> & operator <<(
+ std::basic_ostream<charT, traits> & stream, const Timer& timer )
+{
+ bool bIsIdle = (dynamic_cast<const Idle*>( &timer ) != nullptr);
+ stream << (bIsIdle ? "Idle " : "Timer")
+ << " a: " << timer.IsActive() << " p: " << static_cast<int>(timer.GetPriority());
+ const char *name = timer.GetDebugName();
+ if ( nullptr == name )
+ stream << " (nullptr)";
+ else
+ stream << " " << name;
+ if ( !bIsIdle )
+ stream << " " << timer.GetTimeout() << "ms";
+ stream << " (" << &timer << ")";
+ return stream;
+}
+
+template< typename charT, typename traits >
+std::basic_ostream<charT, traits> & operator <<(
+ std::basic_ostream<charT, traits> & stream, const Idle& idle )
+{
+ return stream << static_cast<const Timer*>( &idle );
+}
+
+template< typename charT, typename traits >
+std::basic_ostream<charT, traits> & operator <<(
+ std::basic_ostream<charT, traits> & stream, const ImplSchedulerData& data )
+{
+ stream << " i: " << data.mbInScheduler;
+ return stream;
+}
+
+} // end anonymous namespace
+
+unsigned int TaskStopwatch::m_nTimeSlice = TaskStopwatch::nDefaultTimeSlice;
+
+void Scheduler::ImplDeInitScheduler()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ assert( pSVData != nullptr );
+ ImplSchedulerContext &rSchedCtx = pSVData->maSchedCtx;
+
+ DBG_TESTSOLARMUTEX();
+
+ SchedulerGuard aSchedulerGuard;
+
+ int nTaskPriority = 0;
+#if OSL_DEBUG_LEVEL > 0
+ sal_uInt32 nTasks = 0;
+ for (nTaskPriority = 0; nTaskPriority < PRIO_COUNT; ++nTaskPriority)
+ {
+ ImplSchedulerData* pSchedulerData = rSchedCtx.mpFirstSchedulerData[nTaskPriority];
+ while ( pSchedulerData )
+ {
+ ++nTasks;
+ pSchedulerData = pSchedulerData->mpNext;
+ }
+ }
+ SAL_INFO( "vcl.schedule.deinit",
+ "DeInit the scheduler - pending tasks: " << nTasks );
+
+ // clean up all the sfx::SfxItemDisruptor_Impl Idles
+ Unlock();
+ ProcessEventsToIdle();
+ Lock();
+#endif
+ rSchedCtx.mbActive = false;
+
+ assert( nullptr == rSchedCtx.mpSchedulerStack || (!rSchedCtx.mpSchedulerStack->mpTask && !rSchedCtx.mpSchedulerStack->mpNext) );
+
+ if (rSchedCtx.mpSalTimer) rSchedCtx.mpSalTimer->Stop();
+ delete rSchedCtx.mpSalTimer;
+ rSchedCtx.mpSalTimer = nullptr;
+
+#if OSL_DEBUG_LEVEL > 0
+ sal_uInt32 nActiveTasks = 0, nIgnoredTasks = 0;
+#endif
+ nTaskPriority = 0;
+ ImplSchedulerData* pSchedulerData = nullptr;
+
+next_priority:
+ pSchedulerData = rSchedCtx.mpFirstSchedulerData[nTaskPriority];
+ while ( pSchedulerData )
+ {
+ Task *pTask = pSchedulerData->mpTask;
+ if ( pTask )
+ {
+ if ( pTask->mbActive )
+ {
+#if OSL_DEBUG_LEVEL > 0
+ const char *sIgnored = "";
+ ++nActiveTasks;
+ // TODO: shutdown these timers before Scheduler de-init
+ // TODO: remove Task from static object
+ if ( pTask->GetDebugName() && ( false
+ || !strcmp( pTask->GetDebugName(), "desktop::Desktop m_firstRunTimer" )
+ || !strcmp( pTask->GetDebugName(), "DrawWorkStartupTimer" )
+ || !strcmp( pTask->GetDebugName(), "editeng::ImpEditEngine aOnlineSpellTimer" )
+ || !strcmp( pTask->GetDebugName(), "sc ScModule IdleTimer" )
+ || !strcmp( pTask->GetDebugName(), "sd::CacheConfiguration maReleaseTimer" )
+ || !strcmp( pTask->GetDebugName(), "svtools::GraphicCache maReleaseTimer" )
+ || !strcmp( pTask->GetDebugName(), "svtools::GraphicObject mpSwapOutTimer" )
+ || !strcmp( pTask->GetDebugName(), "svx OLEObjCache pTimer UnloadCheck" )
+ || !strcmp( pTask->GetDebugName(), "vcl SystemDependentDataBuffer aSystemDependentDataBuffer" )
+ ))
+ {
+ sIgnored = " (ignored)";
+ ++nIgnoredTasks;
+ }
+ const Timer *timer = dynamic_cast<Timer*>( pTask );
+ if ( timer )
+ SAL_WARN( "vcl.schedule.deinit", "DeInit task: " << *timer << sIgnored );
+ else
+ SAL_WARN( "vcl.schedule.deinit", "DeInit task: " << *pTask << sIgnored );
+#endif
+ pTask->mbActive = false;
+ }
+ pTask->mpSchedulerData = nullptr;
+ pTask->SetStatic();
+ }
+ ImplSchedulerData* pDeleteSchedulerData = pSchedulerData;
+ pSchedulerData = pSchedulerData->mpNext;
+ delete pDeleteSchedulerData;
+ }
+
+ ++nTaskPriority;
+ if (nTaskPriority < PRIO_COUNT)
+ goto next_priority;
+
+#if OSL_DEBUG_LEVEL > 0
+ SAL_INFO( "vcl.schedule.deinit", "DeInit the scheduler - finished" );
+ SAL_WARN_IF( 0 != nActiveTasks, "vcl.schedule.deinit", "DeInit active tasks: "
+ << nActiveTasks << " (ignored: " << nIgnoredTasks << ")" );
+// assert( nIgnoredTasks == nActiveTasks );
+#endif
+
+ for (nTaskPriority = 0; nTaskPriority < PRIO_COUNT; ++nTaskPriority)
+ {
+ rSchedCtx.mpFirstSchedulerData[nTaskPriority] = nullptr;
+ rSchedCtx.mpLastSchedulerData[nTaskPriority] = nullptr;
+ }
+ rSchedCtx.mnTimerPeriod = InfiniteTimeoutMs;
+}
+
+void Scheduler::Lock()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ assert( pSVData != nullptr );
+ pSVData->maSchedCtx.maMutex.lock();
+}
+
+void Scheduler::Unlock()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ assert( pSVData != nullptr );
+ pSVData->maSchedCtx.maMutex.unlock();
+}
+
+/**
+ * Start a new timer if we need to for nMS duration.
+ *
+ * if this is longer than the existing duration we're
+ * waiting for, do nothing - unless bForce - which means
+ * to reset the minimum period; used by the scheduled itself.
+ */
+void Scheduler::ImplStartTimer(sal_uInt64 nMS, bool bForce, sal_uInt64 nTime)
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ ImplSchedulerContext &rSchedCtx = pSVData->maSchedCtx;
+ if ( !rSchedCtx.mbActive )
+ return;
+
+ if (!rSchedCtx.mpSalTimer)
+ {
+ rSchedCtx.mnTimerStart = 0;
+ rSchedCtx.mnTimerPeriod = InfiniteTimeoutMs;
+ rSchedCtx.mpSalTimer = pSVData->mpDefInst->CreateSalTimer();
+ rSchedCtx.mpSalTimer->SetCallback(Scheduler::CallbackTaskScheduling);
+ }
+
+ assert(SAL_MAX_UINT64 - nMS >= nTime);
+
+ sal_uInt64 nProposedTimeout = nTime + nMS;
+ sal_uInt64 nCurTimeout = ( rSchedCtx.mnTimerPeriod == InfiniteTimeoutMs )
+ ? SAL_MAX_UINT64 : rSchedCtx.mnTimerStart + rSchedCtx.mnTimerPeriod;
+
+ // Only if smaller timeout, to avoid skipping.
+ // Force instant wakeup on 0ms, if the previous period was not 0ms
+ if (bForce || nProposedTimeout < nCurTimeout || (!nMS && rSchedCtx.mnTimerPeriod))
+ {
+ SAL_INFO( "vcl.schedule", " Starting scheduler system timer (" << nMS << "ms)" );
+ rSchedCtx.mnTimerStart = nTime;
+ rSchedCtx.mnTimerPeriod = nMS;
+ rSchedCtx.mpSalTimer->Start( nMS );
+ }
+}
+
+static bool g_bDeterministicMode = false;
+
+void Scheduler::SetDeterministicMode(bool bDeterministic)
+{
+ g_bDeterministicMode = bDeterministic;
+}
+
+bool Scheduler::GetDeterministicMode()
+{
+ return g_bDeterministicMode;
+}
+
+inline void Scheduler::UpdateSystemTimer( ImplSchedulerContext &rSchedCtx,
+ const sal_uInt64 nMinPeriod,
+ const bool bForce, const sal_uInt64 nTime )
+{
+ if ( InfiniteTimeoutMs == nMinPeriod )
+ {
+ SAL_INFO("vcl.schedule", " Stopping system timer");
+ if ( rSchedCtx.mpSalTimer )
+ rSchedCtx.mpSalTimer->Stop();
+ rSchedCtx.mnTimerPeriod = nMinPeriod;
+ }
+ else
+ Scheduler::ImplStartTimer( nMinPeriod, bForce, nTime );
+}
+
+static void AppendSchedulerData( ImplSchedulerContext &rSchedCtx,
+ ImplSchedulerData * const pSchedulerData)
+{
+ assert(pSchedulerData->mpTask);
+ pSchedulerData->mePriority = pSchedulerData->mpTask->GetPriority();
+ pSchedulerData->mpNext = nullptr;
+
+ const int nTaskPriority = static_cast<int>(pSchedulerData->mePriority);
+ if (!rSchedCtx.mpLastSchedulerData[nTaskPriority])
+ {
+ rSchedCtx.mpFirstSchedulerData[nTaskPriority] = pSchedulerData;
+ rSchedCtx.mpLastSchedulerData[nTaskPriority] = pSchedulerData;
+ }
+ else
+ {
+ rSchedCtx.mpLastSchedulerData[nTaskPriority]->mpNext = pSchedulerData;
+ rSchedCtx.mpLastSchedulerData[nTaskPriority] = pSchedulerData;
+ }
+}
+
+static ImplSchedulerData* DropSchedulerData(
+ ImplSchedulerContext &rSchedCtx, ImplSchedulerData * const pPrevSchedulerData,
+ const ImplSchedulerData * const pSchedulerData, const int nTaskPriority)
+{
+ assert( pSchedulerData );
+ if ( pPrevSchedulerData )
+ assert( pPrevSchedulerData->mpNext == pSchedulerData );
+ else
+ assert(rSchedCtx.mpFirstSchedulerData[nTaskPriority] == pSchedulerData);
+
+ ImplSchedulerData * const pSchedulerDataNext = pSchedulerData->mpNext;
+ if ( pPrevSchedulerData )
+ pPrevSchedulerData->mpNext = pSchedulerDataNext;
+ else
+ rSchedCtx.mpFirstSchedulerData[nTaskPriority] = pSchedulerDataNext;
+ if ( !pSchedulerDataNext )
+ rSchedCtx.mpLastSchedulerData[nTaskPriority] = pPrevSchedulerData;
+ return pSchedulerDataNext;
+}
+
+void Scheduler::CallbackTaskScheduling()
+{
+ ImplSVData *pSVData = ImplGetSVData();
+ ImplSchedulerContext &rSchedCtx = pSVData->maSchedCtx;
+
+ DBG_TESTSOLARMUTEX();
+
+ SchedulerGuard aSchedulerGuard;
+ if ( !rSchedCtx.mbActive || InfiniteTimeoutMs == rSchedCtx.mnTimerPeriod )
+ return;
+
+ sal_uInt64 nTime = tools::Time::GetSystemTicks();
+ // Allow for decimals, so subtract in the compare (needed at least on iOS)
+ if ( nTime < rSchedCtx.mnTimerStart + rSchedCtx.mnTimerPeriod -1)
+ {
+ int nSleep = rSchedCtx.mnTimerStart + rSchedCtx.mnTimerPeriod - nTime;
+ UpdateSystemTimer(rSchedCtx, nSleep, true, nTime);
+ return;
+ }
+
+ ImplSchedulerData* pSchedulerData = nullptr;
+ ImplSchedulerData* pPrevSchedulerData = nullptr;
+ ImplSchedulerData *pMostUrgent = nullptr;
+ ImplSchedulerData *pPrevMostUrgent = nullptr;
+ int nMostUrgentPriority = 0;
+ sal_uInt64 nMinPeriod = InfiniteTimeoutMs;
+ sal_uInt64 nReadyPeriod = InfiniteTimeoutMs;
+ unsigned nTasks = 0;
+ int nTaskPriority = 0;
+
+ for (; nTaskPriority < PRIO_COUNT; ++nTaskPriority)
+ {
+ // Related: tdf#152703 Eliminate potential blocking during live resize
+ // Only higher priority tasks need to be fired to redraw the window
+ // so skip firing potentially long-running tasks, such as the Writer
+ // idle layout timer, when a window is in live resize
+ if ( ImplGetSVData()->mpWinData->mbIsLiveResize && nTaskPriority == static_cast<int>(TaskPriority::LOWEST) )
+ continue;
+
+ pSchedulerData = rSchedCtx.mpFirstSchedulerData[nTaskPriority];
+ pPrevSchedulerData = nullptr;
+ while (pSchedulerData)
+ {
+ ++nTasks;
+ const Timer *timer = dynamic_cast<Timer*>( pSchedulerData->mpTask );
+ if ( timer )
+ SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks() << " "
+ << pSchedulerData << " " << *pSchedulerData << " " << *timer );
+ else if ( pSchedulerData->mpTask )
+ SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks() << " "
+ << pSchedulerData << " " << *pSchedulerData
+ << " " << *pSchedulerData->mpTask );
+ else
+ SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks() << " "
+ << pSchedulerData << " " << *pSchedulerData << " (to be deleted)" );
+
+ // Should the Task be released from scheduling?
+ assert(!pSchedulerData->mbInScheduler);
+ if (!pSchedulerData->mpTask || !pSchedulerData->mpTask->IsActive())
+ {
+ ImplSchedulerData * const pSchedulerDataNext =
+ DropSchedulerData(rSchedCtx, pPrevSchedulerData, pSchedulerData, nTaskPriority);
+ if ( pSchedulerData->mpTask )
+ pSchedulerData->mpTask->mpSchedulerData = nullptr;
+ delete pSchedulerData;
+ pSchedulerData = pSchedulerDataNext;
+ continue;
+ }
+
+ assert(pSchedulerData->mpTask);
+ if (pSchedulerData->mpTask->IsActive())
+ {
+ nReadyPeriod = pSchedulerData->mpTask->UpdateMinPeriod( nTime );
+ if (ImmediateTimeoutMs == nReadyPeriod)
+ {
+ if (!pMostUrgent)
+ {
+ pPrevMostUrgent = pPrevSchedulerData;
+ pMostUrgent = pSchedulerData;
+ nMostUrgentPriority = nTaskPriority;
+ }
+ else
+ {
+ nMinPeriod = ImmediateTimeoutMs;
+ break;
+ }
+ }
+ else if (nMinPeriod > nReadyPeriod)
+ nMinPeriod = nReadyPeriod;
+ }
+
+ pPrevSchedulerData = pSchedulerData;
+ pSchedulerData = pSchedulerData->mpNext;
+ }
+
+ if (ImmediateTimeoutMs == nMinPeriod)
+ break;
+ }
+
+ if (InfiniteTimeoutMs != nMinPeriod)
+ SAL_INFO("vcl.schedule",
+ "Calculated minimum timeout as " << nMinPeriod << " of " << nTasks << " tasks");
+ UpdateSystemTimer(rSchedCtx, nMinPeriod, true, nTime);
+
+ if ( !pMostUrgent )
+ return;
+
+ SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks() << " "
+ << pMostUrgent << " invoke-in " << *pMostUrgent->mpTask );
+
+ Task *pTask = pMostUrgent->mpTask;
+
+ comphelper::ProfileZone aZone( pTask->GetDebugName() );
+
+ assert(!pMostUrgent->mbInScheduler);
+ pMostUrgent->mbInScheduler = true;
+
+ // always push the stack, as we don't traverse the whole list to push later
+ DropSchedulerData(rSchedCtx, pPrevMostUrgent, pMostUrgent, nMostUrgentPriority);
+ pMostUrgent->mpNext = rSchedCtx.mpSchedulerStack;
+ rSchedCtx.mpSchedulerStack = pMostUrgent;
+ rSchedCtx.mpSchedulerStackTop = pMostUrgent;
+
+ bool bIsHighPriorityIdle = pMostUrgent->mePriority >= TaskPriority::HIGH_IDLE;
+
+ // invoke the task
+ Unlock();
+
+ // Delay invoking tasks with idle priorities as long as there are user input or repaint events
+ // in the OS event queue. This will often effectively compress such events and repaint only
+ // once at the end, improving performance in cases such as repeated zooming with a complex document.
+ bool bDelayInvoking = bIsHighPriorityIdle &&
+ Application::AnyInput( VclInputFlags::MOUSE | VclInputFlags::KEYBOARD | VclInputFlags::PAINT );
+
+ /*
+ * Current policy is that scheduler tasks aren't allowed to throw an exception.
+ * Because otherwise the exception is caught somewhere totally unrelated.
+ * TODO Ideally we could capture a proper backtrace and feed this into breakpad,
+ * which is do-able, but requires writing some assembly.
+ * See also SalUserEventList::DispatchUserEvents
+ */
+ try
+ {
+ if (bDelayInvoking)
+ SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks()
+ << " idle priority task " << pTask->GetDebugName()
+ << " delayed, system events pending" );
+ else
+ {
+ // prepare Scheduler object for deletion after handling
+ pTask->SetDeletionFlags();
+ pTask->Invoke();
+ }
+ }
+ catch (css::uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("vcl.schedule", "Uncaught");
+ std::abort();
+ }
+ catch (std::exception& e)
+ {
+ SAL_WARN("vcl.schedule", "Uncaught " << typeid(e).name() << " " << e.what());
+ std::abort();
+ }
+ catch (...)
+ {
+ SAL_WARN("vcl.schedule", "Uncaught exception during Task::Invoke()!");
+ std::abort();
+ }
+ Lock();
+
+ assert(pMostUrgent->mbInScheduler);
+ pMostUrgent->mbInScheduler = false;
+
+ SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks() << " "
+ << pMostUrgent << " invoke-out" );
+
+ // pop the scheduler stack
+ pSchedulerData = rSchedCtx.mpSchedulerStack;
+ assert(pSchedulerData == pMostUrgent);
+ rSchedCtx.mpSchedulerStack = pSchedulerData->mpNext;
+
+ // coverity[check_after_deref : FALSE] - pMostUrgent->mpTask is initially pMostUrgent->mpTask, but Task::Invoke can clear it
+ const bool bTaskAlive = pMostUrgent->mpTask && pMostUrgent->mpTask->IsActive();
+ if (!bTaskAlive)
+ {
+ if (pMostUrgent->mpTask)
+ pMostUrgent->mpTask->mpSchedulerData = nullptr;
+ delete pMostUrgent;
+ }
+ else
+ AppendSchedulerData(rSchedCtx, pMostUrgent);
+
+ // this just happens for nested calls, which renders all accounting
+ // invalid, so we just enforce a rescheduling!
+ if (rSchedCtx.mpSchedulerStackTop != pSchedulerData)
+ {
+ UpdateSystemTimer( rSchedCtx, ImmediateTimeoutMs, true,
+ tools::Time::GetSystemTicks() );
+ }
+ else if (bTaskAlive)
+ {
+ pMostUrgent->mnUpdateTime = nTime;
+ nReadyPeriod = pMostUrgent->mpTask->UpdateMinPeriod( nTime );
+ if ( nMinPeriod > nReadyPeriod )
+ nMinPeriod = nReadyPeriod;
+ UpdateSystemTimer( rSchedCtx, nMinPeriod, false, nTime );
+ }
+}
+
+void Scheduler::Wakeup()
+{
+ Scheduler::ImplStartTimer( 0, false, tools::Time::GetSystemTicks() );
+}
+
+void Task::StartTimer( sal_uInt64 nMS )
+{
+ Scheduler::ImplStartTimer( nMS, false, tools::Time::GetSystemTicks() );
+}
+
+void Task::SetDeletionFlags()
+{
+ mbActive = false;
+}
+
+void Task::Start(const bool bStartTimer)
+{
+ ImplSVData *const pSVData = ImplGetSVData();
+ ImplSchedulerContext &rSchedCtx = pSVData->maSchedCtx;
+
+ SchedulerGuard aSchedulerGuard;
+ if ( !rSchedCtx.mbActive )
+ return;
+
+ // is the task scheduled in the correct priority queue?
+ // if not we have to get a new data object, as we don't want to traverse
+ // the whole list to move the data to the correct list, as the task list
+ // is just single linked.
+ // Task priority doesn't change that often AFAIK, or we might need to
+ // start caching ImplSchedulerData objects.
+ if (mpSchedulerData && mpSchedulerData->mePriority != mePriority)
+ {
+ mpSchedulerData->mpTask = nullptr;
+ mpSchedulerData = nullptr;
+ }
+ mbActive = true;
+
+ if ( !mpSchedulerData )
+ {
+ // insert Task
+ ImplSchedulerData* pSchedulerData = new ImplSchedulerData;
+ pSchedulerData->mpTask = this;
+ pSchedulerData->mbInScheduler = false;
+ // mePriority is set in AppendSchedulerData
+ mpSchedulerData = pSchedulerData;
+
+ AppendSchedulerData( rSchedCtx, pSchedulerData );
+ SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks()
+ << " " << mpSchedulerData << " added " << *this );
+ }
+ else
+ SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks()
+ << " " << mpSchedulerData << " restarted " << *this );
+
+ mpSchedulerData->mnUpdateTime = tools::Time::GetSystemTicks();
+
+ if (bStartTimer)
+ Task::StartTimer(0);
+}
+
+void Task::Stop()
+{
+ SAL_INFO_IF( mbActive, "vcl.schedule", tools::Time::GetSystemTicks()
+ << " " << mpSchedulerData << " stopped " << *this );
+ mbActive = false;
+}
+
+void Task::SetPriority(TaskPriority ePriority)
+{
+ // you don't actually need to call Stop() before but Start() after, but we
+ // can't check that and don't know when Start() should be called.
+ SAL_WARN_IF(mpSchedulerData && mbActive, "vcl.schedule",
+ "Stop the task before changing the priority, as it will just "
+ "change after the task was scheduled with the old prio!");
+ mePriority = ePriority;
+}
+
+Task& Task::operator=( const Task& rTask )
+{
+ if(this == &rTask)
+ return *this;
+
+ if ( IsActive() )
+ Stop();
+
+ mbActive = false;
+ mePriority = rTask.mePriority;
+
+ if ( rTask.IsActive() )
+ Start();
+
+ return *this;
+}
+
+Task::Task( const char *pDebugName )
+ : mpSchedulerData( nullptr )
+ , mpDebugName( pDebugName )
+ , mePriority( TaskPriority::DEFAULT )
+ , mbActive( false )
+ , mbStatic( false )
+{
+ assert(mpDebugName);
+}
+
+Task::Task( const Task& rTask )
+ : mpSchedulerData( nullptr )
+ , mpDebugName( rTask.mpDebugName )
+ , mePriority( rTask.mePriority )
+ , mbActive( false )
+ , mbStatic( false )
+{
+ assert(mpDebugName);
+ if ( rTask.IsActive() )
+ Start();
+}
+
+Task::~Task() COVERITY_NOEXCEPT_FALSE
+{
+ if ( !IsStatic() )
+ {
+ SchedulerGuard aSchedulerGuard;
+ if ( mpSchedulerData )
+ mpSchedulerData->mpTask = nullptr;
+ }
+ else
+ assert(nullptr == mpSchedulerData || utl::ConfigManager::IsFuzzing());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/app/session.cxx b/vcl/source/app/session.cxx
new file mode 100644
index 0000000000..d61902fcf6
--- /dev/null
+++ b/vcl/source/app/session.cxx
@@ -0,0 +1,416 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include <sal/config.h>
+#include <sal/log.hxx>
+
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+#include <comphelper/diagnose_ex.hxx>
+#include <utility>
+#include <vcl/svapp.hxx>
+
+#include <factory.hxx>
+#include <svdata.hxx>
+#include <salinst.hxx>
+#include <salsession.hxx>
+
+#include <com/sun/star/frame/XSessionManagerClient.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/frame/XSessionManagerListener2.hpp>
+
+#include <vector>
+
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::frame;
+
+SalSession::~SalSession()
+{
+}
+
+namespace {
+
+class VCLSession:
+ private cppu::BaseMutex,
+ public cppu::WeakComponentImplHelper < XSessionManagerClient, css::lang::XServiceInfo >
+{
+ struct Listener
+ {
+ css::uno::Reference< XSessionManagerListener > m_xListener;
+ bool m_bInteractionRequested;
+ bool m_bInteractionDone;
+ bool m_bSaveDone;
+
+ explicit Listener( css::uno::Reference< XSessionManagerListener > xListener )
+ : m_xListener(std::move( xListener )),
+ m_bInteractionRequested( false ),
+ m_bInteractionDone( false ),
+ m_bSaveDone( false )
+ {}
+ };
+
+ std::vector< Listener > m_aListeners;
+ std::unique_ptr< SalSession > m_xSession;
+ bool m_bInteractionRequested;
+ bool m_bInteractionGranted;
+ bool m_bInteractionDone;
+ bool m_bSaveDone;
+
+ static void SalSessionEventProc( void* pData, SalSessionEvent* pEvent );
+
+ virtual ~VCLSession() override {}
+
+ virtual void SAL_CALL addSessionManagerListener( const css::uno::Reference< XSessionManagerListener >& xListener ) override;
+ virtual void SAL_CALL removeSessionManagerListener( const css::uno::Reference< XSessionManagerListener>& xListener ) override;
+ virtual void SAL_CALL queryInteraction( const css::uno::Reference< XSessionManagerListener >& xListener ) override;
+ virtual void SAL_CALL interactionDone( const css::uno::Reference< XSessionManagerListener >& xListener ) override;
+ virtual void SAL_CALL saveDone( const css::uno::Reference< XSessionManagerListener >& xListener ) override;
+ virtual sal_Bool SAL_CALL cancelShutdown() override;
+
+ OUString SAL_CALL getImplementationName() override {
+ return "com.sun.star.frame.VCLSessionManagerClient";
+ }
+
+ sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override {
+ return cppu::supportsService(this, ServiceName);
+ }
+
+ css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override {
+ return {"com.sun.star.frame.SessionManagerClient"};
+ }
+
+ void SAL_CALL disposing() override;
+
+ void callSaveRequested( bool bShutdown );
+ void callShutdownCancelled();
+ void callInteractionGranted( bool bGranted );
+ void callQuit();
+
+public:
+ VCLSession();
+};
+
+}
+
+VCLSession::VCLSession()
+ : WeakComponentImplHelper( m_aMutex ),
+ m_xSession( ImplGetSVData()->mpDefInst->CreateSalSession() ),
+ m_bInteractionRequested( false ),
+ m_bInteractionGranted( false ),
+ m_bInteractionDone( false ),
+ m_bSaveDone( false )
+{
+ SAL_INFO("vcl.se", "VCLSession::VCLSession" );
+
+ if (m_xSession)
+ m_xSession->SetCallback( SalSessionEventProc, this );
+}
+
+void VCLSession::callSaveRequested( bool bShutdown )
+{
+ SAL_INFO("vcl.se", "VCLSession::callSaveRequested" );
+
+ std::vector< Listener > aListeners;
+ {
+ osl::MutexGuard aGuard( m_aMutex );
+ // reset listener states
+ for (auto & listener : m_aListeners) {
+ listener.m_bSaveDone = listener.m_bInteractionRequested = listener.m_bInteractionDone = false;
+ }
+
+ // copy listener vector since calling a listener may remove it.
+ aListeners = m_aListeners;
+ // set back interaction state
+ m_bSaveDone = false;
+ m_bInteractionDone = false;
+ // without session we assume UI is always possible,
+ // so it was requested and granted
+ m_bInteractionRequested = m_bInteractionGranted = !m_xSession;
+
+ // answer the session manager even if no listeners available anymore
+ SAL_WARN_IF( aListeners.empty(), "vcl.se", "saveRequested but no listeners !" );
+
+ SAL_INFO("vcl.se.debug", " aListeners.empty() = " << (aListeners.empty() ? "true" : "false") <<
+ ", bShutdown = " << (bShutdown ? "true" : "false"));
+ if( aListeners.empty() )
+ {
+ if (m_xSession)
+ m_xSession->saveDone();
+ return;
+ }
+ }
+
+ SolarMutexReleaser aReleaser;
+ for (auto const & listener: aListeners)
+ listener.m_xListener->doSave( bShutdown, false/*bCancelable*/ );
+}
+
+void VCLSession::callInteractionGranted( bool bInteractionGranted )
+{
+ SAL_INFO("vcl.se", "VCLSession::callInteractionGranted" );
+
+ std::vector< Listener > aListeners;
+ {
+ osl::MutexGuard aGuard( m_aMutex );
+ // copy listener vector since calling a listener may remove it.
+ for (auto const & listener: m_aListeners)
+ if( listener.m_bInteractionRequested )
+ aListeners.push_back( listener );
+
+ m_bInteractionGranted = bInteractionGranted;
+
+ // answer the session manager even if no listeners available anymore
+ SAL_WARN_IF( aListeners.empty(), "vcl.se", "interactionGranted but no listeners !" );
+
+ SAL_INFO("vcl.se.debug", " aListeners.empty() = " << (aListeners.empty() ? "true" : "false") <<
+ ", bInteractionGranted = " << (bInteractionGranted ? "true" : "false"));
+ if( aListeners.empty() )
+ {
+ if (m_xSession)
+ m_xSession->interactionDone();
+ return;
+ }
+ }
+
+ SolarMutexReleaser aReleaser;
+ for (auto const & listener: aListeners)
+ listener.m_xListener->approveInteraction( bInteractionGranted );
+}
+
+void VCLSession::callShutdownCancelled()
+{
+ SAL_INFO("vcl.se", "VCLSession::callShutdownCancelled");
+
+ std::vector< Listener > aListeners;
+ {
+ osl::MutexGuard aGuard( m_aMutex );
+ // copy listener vector since calling a listener may remove it.
+ aListeners = m_aListeners;
+ // set back interaction state
+ m_bInteractionRequested = m_bInteractionDone = m_bInteractionGranted = false;
+ }
+
+ SolarMutexReleaser aReleaser;
+ for (auto const & listener: aListeners)
+ listener.m_xListener->shutdownCanceled();
+}
+
+void VCLSession::callQuit()
+{
+ SAL_INFO("vcl.se", "VCLSession::callQuit");
+
+ std::vector< Listener > aListeners;
+ {
+ osl::MutexGuard aGuard( m_aMutex );
+ // copy listener vector since calling a listener may remove it.
+ aListeners = m_aListeners;
+ // set back interaction state
+ m_bInteractionRequested = m_bInteractionDone = m_bInteractionGranted = false;
+ }
+
+ SolarMutexReleaser aReleaser;
+ for (auto const & listener: aListeners)
+ {
+ css::uno::Reference< XSessionManagerListener2 > xListener2( listener.m_xListener, UNO_QUERY );
+ if( xListener2.is() )
+ xListener2->doQuit();
+ }
+}
+
+void VCLSession::SalSessionEventProc( void* pData, SalSessionEvent* pEvent )
+{
+ SAL_INFO("vcl.se", "VCLSession::SalSessionEventProc");
+
+ VCLSession * pThis = static_cast< VCLSession * >( pData );
+ switch( pEvent->m_eType )
+ {
+ case Interaction:
+ {
+ SAL_INFO("vcl.se.debug", " EventProcType = Interaction");
+ SalSessionInteractionEvent* pIEv = static_cast<SalSessionInteractionEvent*>(pEvent);
+ pThis->callInteractionGranted( pIEv->m_bInteractionGranted );
+ }
+ break;
+ case SaveRequest:
+ {
+ SAL_INFO("vcl.se.debug", " EventProcType = SaveRequest");
+ SalSessionSaveRequestEvent* pSEv = static_cast<SalSessionSaveRequestEvent*>(pEvent);
+ pThis->callSaveRequested( pSEv->m_bShutdown );
+ }
+ break;
+ case ShutdownCancel:
+ SAL_INFO("vcl.se.debug", " EventProcType = ShutdownCancel");
+ pThis->callShutdownCancelled();
+ break;
+ case Quit:
+ SAL_INFO("vcl.se.debug", " EventProcType = Quit");
+ pThis->callQuit();
+ break;
+ }
+}
+
+void SAL_CALL VCLSession::addSessionManagerListener( const css::uno::Reference<XSessionManagerListener>& xListener )
+{
+ SAL_INFO("vcl.se", "VCLSession::addSessionManagerListener" );
+
+ osl::MutexGuard aGuard( m_aMutex );
+
+ SAL_INFO("vcl.se.debug", " m_aListeners.size() = " << m_aListeners.size() );
+ m_aListeners.emplace_back( xListener );
+}
+
+void SAL_CALL VCLSession::removeSessionManagerListener( const css::uno::Reference<XSessionManagerListener>& xListener )
+{
+ SAL_INFO("vcl.se", "VCLSession::removeSessionManagerListener" );
+
+ osl::MutexGuard aGuard( m_aMutex );
+
+ SAL_INFO("vcl.se.debug", " m_aListeners.size() = " << m_aListeners.size() );
+
+ std::erase_if(m_aListeners, [&](Listener& listener) {return xListener == listener.m_xListener;});
+}
+
+void SAL_CALL VCLSession::queryInteraction( const css::uno::Reference<XSessionManagerListener>& xListener )
+{
+ SAL_INFO("vcl.se", "VCLSession::queryInteraction");
+
+ SAL_INFO("vcl.se.debug", " m_bInteractionGranted = " << (m_bInteractionGranted ? "true" : "false") <<
+ ", m_bInteractionRequested = "<< (m_bInteractionRequested ? "true" : "false"));
+ if( m_bInteractionGranted )
+ {
+ if( m_bInteractionDone )
+ xListener->approveInteraction( false );
+ else
+ xListener->approveInteraction( true );
+ return;
+ }
+
+ osl::MutexGuard aGuard( m_aMutex );
+ if( ! m_bInteractionRequested )
+ {
+ if (m_xSession)
+ m_xSession->queryInteraction();
+
+ m_bInteractionRequested = true;
+ }
+ for (auto & listener: m_aListeners)
+ {
+ if( listener.m_xListener == xListener )
+ {
+ SAL_INFO("vcl.se.debug", " listener.m_xListener == xListener");
+ listener.m_bInteractionRequested = true;
+ listener.m_bInteractionDone = false;
+ }
+ }
+}
+
+void SAL_CALL VCLSession::interactionDone( const css::uno::Reference< XSessionManagerListener >& xListener )
+{
+ SAL_INFO("vcl.se", "VCLSession::interactionDone");
+
+ osl::MutexGuard aGuard( m_aMutex );
+ int nRequested = 0, nDone = 0;
+ for (auto & listener: m_aListeners)
+ {
+ if( listener.m_bInteractionRequested )
+ {
+ nRequested++;
+ if( xListener == listener.m_xListener )
+ listener.m_bInteractionDone = true;
+ }
+ if( listener.m_bInteractionDone )
+ nDone++;
+ }
+
+ SAL_INFO("vcl.se.debug", " nDone = " << nDone <<
+ ", nRequested =" << nRequested);
+ if( nDone == nRequested && nDone > 0 )
+ {
+ m_bInteractionDone = true;
+ if (m_xSession)
+ m_xSession->interactionDone();
+ }
+}
+
+void SAL_CALL VCLSession::saveDone( const css::uno::Reference< XSessionManagerListener >& xListener )
+{
+ SAL_INFO("vcl.se", "VCLSession::saveDone");
+
+ osl::MutexGuard aGuard( m_aMutex );
+
+ bool bSaveDone = true;
+ for (auto & listener: m_aListeners)
+ {
+ if( listener.m_xListener == xListener )
+ listener.m_bSaveDone = true;
+ if( ! listener.m_bSaveDone )
+ bSaveDone = false;
+ }
+
+ SAL_INFO("vcl.se.debug", " bSaveDone = " << (bSaveDone ? "true" : "false"));
+
+ if( bSaveDone && !m_bSaveDone )
+ {
+ m_bSaveDone = true;
+ if (m_xSession)
+ m_xSession->saveDone();
+ }
+}
+
+sal_Bool SAL_CALL VCLSession::cancelShutdown()
+{
+ SAL_INFO("vcl.se", "VCLSession::cancelShutdown");
+
+ return m_xSession && m_xSession->cancelShutdown();
+}
+
+void VCLSession::disposing() {
+ SAL_INFO("vcl.se", "VCLSession::disposing");
+
+ std::vector<Listener> vector;
+ {
+ osl::MutexGuard g(m_aMutex);
+ vector.swap(m_aListeners);
+ }
+ css::lang::EventObject src(getXWeak());
+ for (auto const & listener: vector) {
+ try {
+ listener.m_xListener->disposing(src);
+ SAL_INFO("vcl.se.debug", " call Listener disposing");
+ } catch (css::uno::RuntimeException &) {
+ TOOLS_WARN_EXCEPTION("vcl.se", "ignoring");
+ }
+ }
+}
+
+// service implementation
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_frame_VCLSessionManagerClient_get_implementation(
+ css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new VCLSession);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/app/settings.cxx b/vcl/source/app/settings.cxx
new file mode 100644
index 0000000000..a1138de24c
--- /dev/null
+++ b/vcl/source/app/settings.cxx
@@ -0,0 +1,3378 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_folders.h>
+
+#include <officecfg/Office/Common.hxx>
+
+#ifdef _WIN32
+#include <win/svsys.h>
+#endif
+
+#include <comphelper/processfactory.hxx>
+#include <rtl/bootstrap.hxx>
+
+#include <i18nlangtag/mslangid.hxx>
+#include <i18nlangtag/languagetag.hxx>
+
+#include <comphelper/lok.hxx>
+
+#include <vcl/graphicfilter.hxx>
+#include <IconThemeScanner.hxx>
+#include <IconThemeSelector.hxx>
+#include <vcl/IconThemeInfo.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/event.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/i18nhelp.hxx>
+#include <configsettings.hxx>
+#include <vcl/outdev.hxx>
+
+#include <unotools/fontcfg.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <unotools/confignode.hxx>
+#include <unotools/configmgr.hxx>
+#include <unotools/syslocale.hxx>
+#include <unotools/syslocaleoptions.hxx>
+
+#include <salframe.hxx>
+#include <svdata.hxx>
+
+using namespace ::com::sun::star;
+
+struct ImplMouseData
+{
+ MouseSettingsOptions mnOptions = MouseSettingsOptions::NONE;
+ sal_uInt64 mnDoubleClkTime = 500;
+ sal_Int32 mnDoubleClkWidth = 2;
+ sal_Int32 mnDoubleClkHeight = 2;
+ sal_Int32 mnStartDragWidth = 2 ;
+ sal_Int32 mnStartDragHeight = 2;
+ sal_Int32 mnButtonRepeat = 90;
+ sal_Int32 mnMenuDelay = 150;
+ MouseFollowFlags mnFollow = MouseFollowFlags::Menu;
+ MouseMiddleButtonAction mnMiddleButtonAction= MouseMiddleButtonAction::AutoScroll;
+ MouseWheelBehaviour mnWheelBehavior = MouseWheelBehaviour::FocusOnly;
+};
+
+struct ImplStyleData
+{
+ ImplStyleData();
+ ImplStyleData( const ImplStyleData& rData );
+
+ void SetStandardStyles();
+
+ Color maActiveBorderColor;
+ Color maActiveColor;
+ Color maActiveTextColor;
+ Color maAlternatingRowColor;
+ Color maDefaultButtonTextColor;
+ Color maButtonTextColor;
+ Color maDefaultActionButtonTextColor;
+ Color maActionButtonTextColor;
+ Color maFlatButtonTextColor;
+ Color maDefaultButtonRolloverTextColor;
+ Color maButtonRolloverTextColor;
+ Color maDefaultActionButtonRolloverTextColor;
+ Color maActionButtonRolloverTextColor;
+ Color maFlatButtonRolloverTextColor;
+ Color maDefaultButtonPressedRolloverTextColor;
+ Color maButtonPressedRolloverTextColor;
+ Color maDefaultActionButtonPressedRolloverTextColor;
+ Color maActionButtonPressedRolloverTextColor;
+ Color maFlatButtonPressedRolloverTextColor;
+ Color maCheckedColor;
+ Color maDarkShadowColor;
+ Color maDeactiveBorderColor;
+ Color maDeactiveColor;
+ Color maDeactiveTextColor;
+ Color maDialogColor;
+ Color maDialogTextColor;
+ Color maDisableColor;
+ Color maFaceColor;
+ Color maFieldColor;
+ Color maFieldTextColor;
+ Color maFieldRolloverTextColor;
+ Color maGroupTextColor;
+ Color maHelpColor;
+ Color maHelpTextColor;
+ Color maAccentColor;
+ Color maHighlightColor;
+ Color maHighlightTextColor;
+ Color maLabelTextColor;
+ Color maLightBorderColor;
+ Color maLightColor;
+ Color maLinkColor;
+ Color maMenuBarColor;
+ Color maMenuBarRolloverColor;
+ Color maMenuBorderColor;
+ Color maMenuColor;
+ Color maMenuHighlightColor;
+ Color maMenuHighlightTextColor;
+ Color maMenuTextColor;
+ Color maListBoxWindowBackgroundColor;
+ Color maListBoxWindowTextColor;
+ Color maListBoxWindowHighlightColor;
+ Color maListBoxWindowHighlightTextColor;
+ Color maMenuBarTextColor;
+ Color maMenuBarRolloverTextColor;
+ Color maMenuBarHighlightTextColor;
+ Color maMonoColor;
+ Color maRadioCheckTextColor;
+ Color maShadowColor;
+ Color maWarningColor;
+ Color maVisitedLinkColor;
+ Color maToolTextColor;
+ Color maWindowColor;
+ Color maWindowTextColor;
+ Color maWorkspaceColor;
+ Color maActiveTabColor;
+ Color maInactiveTabColor;
+ Color maTabTextColor;
+ Color maTabRolloverTextColor;
+ Color maTabHighlightTextColor;
+ vcl::Font maAppFont;
+ vcl::Font maHelpFont;
+ vcl::Font maTitleFont;
+ vcl::Font maFloatTitleFont;
+ vcl::Font maMenuFont;
+ vcl::Font maToolFont;
+ vcl::Font maLabelFont;
+ vcl::Font maRadioCheckFont;
+ vcl::Font maPushButtonFont;
+ vcl::Font maFieldFont;
+ vcl::Font maIconFont;
+ vcl::Font maTabFont;
+ vcl::Font maGroupFont;
+ sal_Int32 mnTitleHeight;
+ sal_Int32 mnFloatTitleHeight;
+ sal_Int32 mnScrollBarSize;
+ sal_Int32 mnSpinSize;
+ sal_Int32 mnCursorSize;
+ sal_Int32 mnAntialiasedMin;
+ sal_uInt64 mnCursorBlinkTime;
+ DragFullOptions mnDragFullOptions;
+ SelectionOptions mnSelectionOptions;
+ DisplayOptions mnDisplayOptions;
+ ToolbarIconSize mnToolbarIconSize;
+ bool mnUseFlatMenus;
+ StyleSettingsOptions mnOptions;
+ bool mbHighContrast;
+ bool mbUseSystemUIFonts;
+ /**
+ * Disabling AA doesn't actually disable AA of fonts, instead it is taken
+ * from system settings.
+ */
+ bool mbUseFontAAFromSystem;
+ bool mbAutoMnemonic;
+ TriState meUseImagesInMenus;
+ bool mnUseFlatBorders;
+ bool mbPreferredUseImagesInMenus;
+ sal_Int32 mnMinThumbSize;
+ std::shared_ptr<vcl::IconThemeScanner>
+ mIconThemeScanner;
+ std::shared_ptr<vcl::IconThemeSelector>
+ mIconThemeSelector;
+
+ OUString mIconTheme;
+ bool mbSkipDisabledInMenus;
+ bool mbHideDisabledMenuItems;
+ bool mbPreferredContextMenuShortcuts;
+ TriState meContextMenuShortcuts;
+ //mbPrimaryButtonWarpsSlider == true for "jump to here" behavior for primary button, otherwise
+ //primary means scroll by single page. Secondary button takes the alternative behaviour
+ bool mbPrimaryButtonWarpsSlider;
+ DialogStyle maDialogStyle;
+
+ sal_uInt16 mnEdgeBlending;
+ Color maEdgeBlendingTopLeftColor;
+ Color maEdgeBlendingBottomRightColor;
+ sal_uInt16 mnListBoxMaximumLineCount;
+ sal_uInt16 mnColorValueSetColumnCount;
+ Size maListBoxPreviewDefaultLogicSize;
+ Size maListBoxPreviewDefaultPixelSize;
+ bool mbPreviewUsesCheckeredBackground;
+
+ OUString maPersonaHeaderFooter; ///< Cache the settings to detect changes.
+
+ BitmapEx maPersonaHeaderBitmap; ///< Cache the header bitmap.
+ BitmapEx maPersonaFooterBitmap; ///< Cache the footer bitmap.
+ std::optional<Color> maPersonaMenuBarTextColor; ///< Cache the menubar color.
+};
+
+struct ImplMiscData
+{
+ ImplMiscData();
+ TriState mnEnableATT;
+ bool mbEnableLocalizedDecimalSep;
+ TriState mnDisablePrinting;
+};
+
+struct ImplHelpData
+{
+ sal_Int32 mnTipTimeout = 3000;
+};
+
+struct ImplAllSettingsData
+{
+ ImplAllSettingsData();
+ ImplAllSettingsData( const ImplAllSettingsData& rData );
+ ~ImplAllSettingsData();
+
+ MouseSettings maMouseSettings;
+ StyleSettings maStyleSettings;
+ MiscSettings maMiscSettings;
+ HelpSettings maHelpSettings;
+ LanguageTag maLocale;
+ LanguageTag maUILocale;
+ std::unique_ptr<LocaleDataWrapper> mpLocaleDataWrapper;
+ std::unique_ptr<LocaleDataWrapper> mpUILocaleDataWrapper;
+ std::unique_ptr<LocaleDataWrapper> mpNeutralLocaleDataWrapper;
+ std::unique_ptr<vcl::I18nHelper> mpI18nHelper;
+ std::unique_ptr<vcl::I18nHelper> mpUII18nHelper;
+ SvtSysLocale maSysLocale;
+};
+
+void
+MouseSettings::SetOptions(MouseSettingsOptions nOptions)
+{
+ CopyData();
+ mxData->mnOptions = nOptions;
+}
+
+MouseSettingsOptions
+MouseSettings::GetOptions() const
+{
+ return mxData->mnOptions;
+}
+
+void
+MouseSettings::SetDoubleClickTime( sal_uInt64 nDoubleClkTime )
+{
+ CopyData();
+ mxData->mnDoubleClkTime = nDoubleClkTime;
+}
+
+sal_uInt64
+MouseSettings::GetDoubleClickTime() const
+{
+ return mxData->mnDoubleClkTime;
+}
+
+void
+MouseSettings::SetDoubleClickWidth( sal_Int32 nDoubleClkWidth )
+{
+ CopyData();
+ mxData->mnDoubleClkWidth = nDoubleClkWidth;
+}
+
+sal_Int32
+MouseSettings::GetDoubleClickWidth() const
+{
+ return mxData->mnDoubleClkWidth;
+}
+
+void
+MouseSettings::SetDoubleClickHeight( sal_Int32 nDoubleClkHeight )
+{
+ CopyData();
+ mxData->mnDoubleClkHeight = nDoubleClkHeight;
+}
+
+sal_Int32
+MouseSettings::GetDoubleClickHeight() const
+{
+ return mxData->mnDoubleClkHeight;
+}
+
+void
+MouseSettings::SetStartDragWidth( sal_Int32 nDragWidth )
+{
+ CopyData();
+ mxData->mnStartDragWidth = nDragWidth;
+}
+
+sal_Int32
+MouseSettings::GetStartDragWidth() const
+{
+ return mxData->mnStartDragWidth;
+}
+
+void
+MouseSettings::SetStartDragHeight( sal_Int32 nDragHeight )
+{
+ CopyData();
+ mxData->mnStartDragHeight = nDragHeight;
+}
+
+sal_Int32
+MouseSettings::GetStartDragHeight() const
+{
+ return mxData->mnStartDragHeight;
+}
+
+sal_uInt16
+MouseSettings::GetStartDragCode()
+{
+ return MOUSE_LEFT;
+}
+
+sal_uInt16
+MouseSettings::GetContextMenuCode()
+{
+ return MOUSE_RIGHT;
+}
+
+sal_uInt16
+MouseSettings::GetContextMenuClicks()
+{
+ return 1;
+}
+
+sal_Int32
+MouseSettings::GetScrollRepeat()
+{
+ return 100;
+}
+
+sal_Int32
+MouseSettings::GetButtonStartRepeat()
+{
+ return 370;
+}
+
+void
+MouseSettings::SetButtonRepeat( sal_Int32 nRepeat )
+{
+ CopyData();
+ mxData->mnButtonRepeat = nRepeat;
+}
+
+sal_Int32
+MouseSettings::GetButtonRepeat() const
+{
+ return mxData->mnButtonRepeat;
+}
+
+sal_Int32
+MouseSettings::GetActionDelay()
+{
+ return 250;
+}
+
+void
+MouseSettings::SetMenuDelay( sal_Int32 nDelay )
+{
+ CopyData();
+ mxData->mnMenuDelay = nDelay;
+}
+
+sal_Int32
+MouseSettings::GetMenuDelay() const
+{
+ return mxData->mnMenuDelay;
+}
+
+void
+MouseSettings::SetFollow( MouseFollowFlags nFollow )
+{
+ CopyData();
+ mxData->mnFollow = nFollow;
+}
+
+MouseFollowFlags
+MouseSettings::GetFollow() const
+{
+ return mxData->mnFollow;
+}
+
+void
+MouseSettings::SetMiddleButtonAction( MouseMiddleButtonAction nAction )
+{
+ CopyData();
+ mxData->mnMiddleButtonAction = nAction;
+}
+
+MouseMiddleButtonAction
+MouseSettings::GetMiddleButtonAction() const
+{
+ return mxData->mnMiddleButtonAction;
+}
+
+void
+MouseSettings::SetWheelBehavior( MouseWheelBehaviour nBehavior )
+{
+ CopyData();
+ mxData->mnWheelBehavior = nBehavior;
+}
+
+MouseWheelBehaviour
+MouseSettings::GetWheelBehavior() const
+{
+ return mxData->mnWheelBehavior;
+}
+
+bool
+MouseSettings::operator !=( const MouseSettings& rSet ) const
+{
+ return !(*this == rSet);
+}
+
+MouseSettings::MouseSettings()
+ : mxData(std::make_shared<ImplMouseData>())
+{
+}
+
+void MouseSettings::CopyData()
+{
+ // copy if other references exist
+ if (mxData.use_count() > 1)
+ {
+ mxData = std::make_shared<ImplMouseData>(*mxData);
+ }
+}
+
+bool MouseSettings::operator ==( const MouseSettings& rSet ) const
+{
+ if ( mxData == rSet.mxData )
+ return true;
+
+ return
+ (mxData->mnOptions == rSet.mxData->mnOptions) &&
+ (mxData->mnDoubleClkTime == rSet.mxData->mnDoubleClkTime) &&
+ (mxData->mnDoubleClkWidth == rSet.mxData->mnDoubleClkWidth) &&
+ (mxData->mnDoubleClkHeight == rSet.mxData->mnDoubleClkHeight) &&
+ (mxData->mnStartDragWidth == rSet.mxData->mnStartDragWidth) &&
+ (mxData->mnStartDragHeight == rSet.mxData->mnStartDragHeight) &&
+ (mxData->mnMiddleButtonAction == rSet.mxData->mnMiddleButtonAction) &&
+ (mxData->mnButtonRepeat == rSet.mxData->mnButtonRepeat) &&
+ (mxData->mnMenuDelay == rSet.mxData->mnMenuDelay) &&
+ (mxData->mnFollow == rSet.mxData->mnFollow) &&
+ (mxData->mnWheelBehavior == rSet.mxData->mnWheelBehavior );
+}
+
+ImplStyleData::ImplStyleData() :
+ mnScrollBarSize(16),
+ mnSpinSize(16),
+ mnCursorSize(2),
+ mnAntialiasedMin(0),
+ mnCursorBlinkTime(STYLE_CURSOR_NOBLINKTIME),
+ mnDragFullOptions(DragFullOptions::All),
+ mnSelectionOptions(SelectionOptions::NONE),
+ mnDisplayOptions(DisplayOptions::NONE),
+ mnToolbarIconSize(ToolbarIconSize::Unknown),
+ mnOptions(StyleSettingsOptions::NONE),
+ mbAutoMnemonic(true),
+ meUseImagesInMenus(TRISTATE_INDET),
+ mnMinThumbSize(16),
+ mIconThemeSelector(std::make_shared<vcl::IconThemeSelector>()),
+ meContextMenuShortcuts(TRISTATE_INDET),
+ mnEdgeBlending(35),
+ maEdgeBlendingTopLeftColor(Color(0xC0, 0xC0, 0xC0)),
+ maEdgeBlendingBottomRightColor(Color(0x40, 0x40, 0x40)),
+ mnListBoxMaximumLineCount(25),
+ // For some reason this isn't actually the column count that gets used, at least on iOS, but
+ // instead what SvtAccessibilityOptions_Impl::GetColorValueSetColumnCount() in
+ // svtools/source/config/accessibilityoptions.cxx returns.
+ mnColorValueSetColumnCount(12),
+#ifdef IOS
+ maListBoxPreviewDefaultLogicSize(Size(30, 30)),
+#else
+ maListBoxPreviewDefaultLogicSize(Size(15, 7)),
+#endif
+ maListBoxPreviewDefaultPixelSize(Size(0, 0)), // on-demand calculated in GetListBoxPreviewDefaultPixelSize(),
+ mbPreviewUsesCheckeredBackground(true)
+{
+ SetStandardStyles();
+}
+
+ImplStyleData::ImplStyleData( const ImplStyleData& rData ) :
+ maActiveBorderColor( rData.maActiveBorderColor ),
+ maActiveColor( rData.maActiveColor ),
+ maActiveTextColor( rData.maActiveTextColor ),
+ maAlternatingRowColor( rData.maAlternatingRowColor ),
+ maDefaultButtonTextColor( rData.maDefaultButtonTextColor ),
+ maButtonTextColor( rData.maButtonTextColor ),
+ maDefaultActionButtonTextColor( rData.maDefaultActionButtonTextColor ),
+ maActionButtonTextColor( rData.maActionButtonTextColor ),
+ maFlatButtonTextColor( rData.maFlatButtonTextColor ),
+ maDefaultButtonRolloverTextColor( rData.maDefaultButtonRolloverTextColor ),
+ maButtonRolloverTextColor( rData.maButtonRolloverTextColor ),
+ maDefaultActionButtonRolloverTextColor( rData.maDefaultActionButtonRolloverTextColor ),
+ maActionButtonRolloverTextColor( rData.maActionButtonRolloverTextColor ),
+ maFlatButtonRolloverTextColor( rData.maFlatButtonRolloverTextColor ),
+ maDefaultButtonPressedRolloverTextColor( rData.maDefaultButtonPressedRolloverTextColor ),
+ maButtonPressedRolloverTextColor( rData.maButtonPressedRolloverTextColor ),
+ maDefaultActionButtonPressedRolloverTextColor( rData.maDefaultActionButtonPressedRolloverTextColor ),
+ maActionButtonPressedRolloverTextColor( rData.maActionButtonPressedRolloverTextColor ),
+ maFlatButtonPressedRolloverTextColor( rData.maFlatButtonPressedRolloverTextColor ),
+ maCheckedColor( rData.maCheckedColor ),
+ maDarkShadowColor( rData.maDarkShadowColor ),
+ maDeactiveBorderColor( rData.maDeactiveBorderColor ),
+ maDeactiveColor( rData.maDeactiveColor ),
+ maDeactiveTextColor( rData.maDeactiveTextColor ),
+ maDialogColor( rData.maDialogColor ),
+ maDialogTextColor( rData.maDialogTextColor ),
+ maDisableColor( rData.maDisableColor ),
+ maFaceColor( rData.maFaceColor ),
+ maFieldColor( rData.maFieldColor ),
+ maFieldTextColor( rData.maFieldTextColor ),
+ maFieldRolloverTextColor( rData.maFieldRolloverTextColor ),
+ maGroupTextColor( rData.maGroupTextColor ),
+ maHelpColor( rData.maHelpColor ),
+ maHelpTextColor( rData.maHelpTextColor ),
+ maAccentColor( rData.maAccentColor ),
+ maHighlightColor( rData.maHighlightColor ),
+ maHighlightTextColor( rData.maHighlightTextColor ),
+ maLabelTextColor( rData.maLabelTextColor ),
+ maLightBorderColor( rData.maLightBorderColor ),
+ maLightColor( rData.maLightColor ),
+ maLinkColor( rData.maLinkColor ),
+ maMenuBarColor( rData.maMenuBarColor ),
+ maMenuBarRolloverColor( rData.maMenuBarRolloverColor ),
+ maMenuBorderColor( rData.maMenuBorderColor ),
+ maMenuColor( rData.maMenuColor ),
+ maMenuHighlightColor( rData.maMenuHighlightColor ),
+ maMenuHighlightTextColor( rData.maMenuHighlightTextColor ),
+ maMenuTextColor( rData.maMenuTextColor ),
+ maListBoxWindowBackgroundColor( rData.maListBoxWindowBackgroundColor ),
+ maListBoxWindowTextColor( rData.maListBoxWindowTextColor ),
+ maListBoxWindowHighlightColor( rData.maListBoxWindowHighlightColor ),
+ maListBoxWindowHighlightTextColor( rData.maListBoxWindowHighlightTextColor ),
+ maMenuBarTextColor( rData.maMenuBarTextColor ),
+ maMenuBarRolloverTextColor( rData.maMenuBarRolloverTextColor ),
+ maMenuBarHighlightTextColor( rData.maMenuBarHighlightTextColor ),
+ maMonoColor( rData.maMonoColor ),
+ maRadioCheckTextColor( rData.maRadioCheckTextColor ),
+ maShadowColor( rData.maShadowColor ),
+ maWarningColor( rData.maWarningColor ),
+ maVisitedLinkColor( rData.maVisitedLinkColor ),
+ maToolTextColor( rData.maToolTextColor ),
+ maWindowColor( rData.maWindowColor ),
+ maWindowTextColor( rData.maWindowTextColor ),
+ maWorkspaceColor( rData.maWorkspaceColor ),
+ maActiveTabColor( rData.maActiveTabColor ),
+ maInactiveTabColor( rData.maInactiveTabColor ),
+ maTabTextColor( rData.maTabTextColor ),
+ maTabRolloverTextColor( rData.maTabRolloverTextColor ),
+ maTabHighlightTextColor( rData.maTabHighlightTextColor ),
+ maAppFont( rData.maAppFont ),
+ maHelpFont( rData.maAppFont ),
+ maTitleFont( rData.maTitleFont ),
+ maFloatTitleFont( rData.maFloatTitleFont ),
+ maMenuFont( rData.maMenuFont ),
+ maToolFont( rData.maToolFont ),
+ maLabelFont( rData.maLabelFont ),
+ maRadioCheckFont( rData.maRadioCheckFont ),
+ maPushButtonFont( rData.maPushButtonFont ),
+ maFieldFont( rData.maFieldFont ),
+ maIconFont( rData.maIconFont ),
+ maTabFont( rData.maTabFont ),
+ maGroupFont( rData.maGroupFont ),
+ mnTitleHeight(rData.mnTitleHeight),
+ mnFloatTitleHeight(rData.mnFloatTitleHeight),
+ mnScrollBarSize(rData.mnScrollBarSize),
+ mnSpinSize(rData.mnSpinSize),
+ mnCursorSize(rData.mnCursorSize),
+ mnAntialiasedMin(rData.mnAntialiasedMin),
+ mnCursorBlinkTime(rData.mnCursorBlinkTime),
+ mnDragFullOptions(rData.mnDragFullOptions),
+ mnSelectionOptions(rData.mnSelectionOptions),
+ mnDisplayOptions(rData.mnDisplayOptions),
+ mnToolbarIconSize(rData.mnToolbarIconSize),
+ mnUseFlatMenus(rData.mnUseFlatMenus),
+ mnOptions(rData.mnOptions),
+ mbHighContrast(rData.mbHighContrast),
+ mbUseSystemUIFonts(rData.mbUseSystemUIFonts),
+ mbUseFontAAFromSystem(rData.mbUseFontAAFromSystem),
+ mbAutoMnemonic(rData.mbAutoMnemonic),
+ meUseImagesInMenus(rData.meUseImagesInMenus),
+ mnUseFlatBorders(rData.mnUseFlatBorders),
+ mbPreferredUseImagesInMenus(rData.mbPreferredUseImagesInMenus),
+ mnMinThumbSize(rData.mnMinThumbSize),
+ mIconThemeSelector(std::make_shared<vcl::IconThemeSelector>(*rData.mIconThemeSelector)),
+ mIconTheme(rData.mIconTheme),
+ mbSkipDisabledInMenus(rData.mbSkipDisabledInMenus),
+ mbHideDisabledMenuItems(rData.mbHideDisabledMenuItems),
+ mbPreferredContextMenuShortcuts(rData.mbPreferredContextMenuShortcuts),
+ meContextMenuShortcuts(rData.meContextMenuShortcuts),
+ mbPrimaryButtonWarpsSlider(rData.mbPrimaryButtonWarpsSlider),
+ maDialogStyle( rData.maDialogStyle ),
+ mnEdgeBlending(rData.mnEdgeBlending),
+ maEdgeBlendingTopLeftColor(rData.maEdgeBlendingTopLeftColor),
+ maEdgeBlendingBottomRightColor(rData.maEdgeBlendingBottomRightColor),
+ mnListBoxMaximumLineCount(rData.mnListBoxMaximumLineCount),
+ mnColorValueSetColumnCount(rData.mnColorValueSetColumnCount),
+ maListBoxPreviewDefaultLogicSize(rData.maListBoxPreviewDefaultLogicSize),
+ maListBoxPreviewDefaultPixelSize(rData.maListBoxPreviewDefaultPixelSize),
+ mbPreviewUsesCheckeredBackground(rData.mbPreviewUsesCheckeredBackground),
+ maPersonaHeaderFooter( rData.maPersonaHeaderFooter ),
+ maPersonaHeaderBitmap( rData.maPersonaHeaderBitmap ),
+ maPersonaFooterBitmap( rData.maPersonaFooterBitmap ),
+ maPersonaMenuBarTextColor( rData.maPersonaMenuBarTextColor )
+{
+ if (rData.mIconThemeScanner)
+ mIconThemeScanner = std::make_shared<vcl::IconThemeScanner>(*rData.mIconThemeScanner);
+}
+
+void ImplStyleData::SetStandardStyles()
+{
+ vcl::Font aStdFont( FAMILY_SWISS, Size( 0, 8 ) );
+ aStdFont.SetCharSet( osl_getThreadTextEncoding() );
+ aStdFont.SetWeight( WEIGHT_NORMAL );
+ if (!utl::ConfigManager::IsFuzzing())
+ aStdFont.SetFamilyName(utl::DefaultFontConfiguration::get().getUserInterfaceFont(LanguageTag("en")));
+ else
+ aStdFont.SetFamilyName("Liberation Sans");
+ maAppFont = aStdFont;
+ maHelpFont = aStdFont;
+ maMenuFont = aStdFont;
+ maToolFont = aStdFont;
+ maGroupFont = aStdFont;
+ maLabelFont = aStdFont;
+ maRadioCheckFont = aStdFont;
+ maPushButtonFont = aStdFont;
+ maFieldFont = aStdFont;
+ maIconFont = aStdFont;
+ maTabFont = aStdFont;
+ aStdFont.SetWeight( WEIGHT_BOLD );
+ maFloatTitleFont = aStdFont;
+ maTitleFont = aStdFont;
+
+ maFaceColor = COL_LIGHTGRAY;
+ maCheckedColor = Color( 0xCC, 0xCC, 0xCC );
+ maLightColor = COL_WHITE;
+ maLightBorderColor = COL_LIGHTGRAY;
+ maShadowColor = COL_GRAY;
+ maDarkShadowColor = COL_BLACK;
+
+ maWarningColor = COL_YELLOW;
+
+ maDefaultButtonTextColor = COL_BLACK;
+ maButtonTextColor = COL_BLACK;
+ maDefaultActionButtonTextColor = COL_BLACK;
+ maActionButtonTextColor = COL_BLACK;
+ maFlatButtonTextColor = COL_BLACK;
+ maDefaultButtonRolloverTextColor = COL_BLACK;
+ maButtonRolloverTextColor = COL_BLACK;
+ maDefaultActionButtonRolloverTextColor = COL_BLACK;
+ maActionButtonRolloverTextColor = COL_BLACK;
+ maFlatButtonRolloverTextColor = COL_BLACK;
+ maDefaultButtonPressedRolloverTextColor = COL_BLACK;
+ maButtonPressedRolloverTextColor = COL_BLACK;
+ maDefaultActionButtonPressedRolloverTextColor = COL_BLACK;
+ maActionButtonPressedRolloverTextColor = COL_BLACK;
+ maFlatButtonPressedRolloverTextColor = COL_BLACK;
+
+ maRadioCheckTextColor = COL_BLACK;
+ maGroupTextColor = COL_BLACK;
+ maLabelTextColor = COL_BLACK;
+ maWindowColor = COL_WHITE;
+ maWindowTextColor = COL_BLACK;
+ maDialogColor = COL_LIGHTGRAY;
+ maDialogTextColor = COL_BLACK;
+ maWorkspaceColor = Color( 0xDF, 0xDF, 0xDE );
+ maMonoColor = COL_BLACK;
+ maFieldColor = COL_WHITE;
+ maFieldTextColor = COL_BLACK;
+ maFieldRolloverTextColor = COL_BLACK;
+ maActiveBorderColor = COL_LIGHTGRAY;
+ maDeactiveColor = COL_GRAY;
+ maDeactiveTextColor = COL_LIGHTGRAY;
+ maDeactiveBorderColor = COL_LIGHTGRAY;
+ maMenuColor = COL_LIGHTGRAY;
+ maMenuBarColor = COL_LIGHTGRAY;
+ maMenuBarRolloverColor = COL_BLUE;
+ maMenuBorderColor = COL_LIGHTGRAY;
+ maMenuTextColor = COL_BLACK;
+ maListBoxWindowBackgroundColor = COL_WHITE;
+ maListBoxWindowTextColor = COL_BLACK;
+ maListBoxWindowHighlightColor = COL_BLUE;
+ maListBoxWindowHighlightTextColor = COL_WHITE;
+ maMenuBarTextColor = COL_BLACK;
+ maMenuBarRolloverTextColor = COL_WHITE;
+ maMenuBarHighlightTextColor = COL_WHITE;
+ maMenuHighlightColor = COL_BLUE;
+ maMenuHighlightTextColor = COL_WHITE;
+ maAccentColor = COL_RED;
+ maHighlightColor = COL_BLUE;
+ maHighlightTextColor = COL_WHITE;
+ // make active like highlight, except with a small contrast
+ maActiveColor = maHighlightColor;
+ maActiveColor.IncreaseLuminance(32);
+ maActiveTextColor = maHighlightTextColor;
+ maActiveTabColor = COL_WHITE;
+ maInactiveTabColor = COL_LIGHTGRAY;
+ maTabTextColor = COL_BLACK;
+ maTabRolloverTextColor = COL_BLACK;
+ maTabHighlightTextColor = COL_BLACK;
+ maDisableColor = COL_GRAY;
+ maHelpColor = Color( 0xFF, 0xFF, 0xE0 );
+ maHelpTextColor = COL_BLACK;
+ maLinkColor = COL_BLUE;
+ maVisitedLinkColor = Color( 0x00, 0x00, 0xCC );
+ maToolTextColor = COL_BLACK;
+ maAlternatingRowColor = Color( 0xEE, 0xEE, 0xEE );
+
+ mnTitleHeight = 18;
+ mnFloatTitleHeight = 13;
+ mbHighContrast = false;
+ mbUseSystemUIFonts = true;
+ mbUseFontAAFromSystem = true;
+ mnUseFlatBorders = false;
+ mnUseFlatMenus = false;
+ mbPreferredUseImagesInMenus = true;
+ mbSkipDisabledInMenus = false;
+ mbHideDisabledMenuItems = false;
+ mbPreferredContextMenuShortcuts = true;
+ mbPrimaryButtonWarpsSlider = false;
+}
+
+StyleSettings::StyleSettings()
+ : mxData(std::make_shared<ImplStyleData>())
+{
+}
+
+void
+StyleSettings::SetFaceColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maFaceColor = rColor;
+}
+
+const Color&
+StyleSettings::GetFaceColor() const
+{
+ return mxData->maFaceColor;
+}
+
+void
+StyleSettings::SetCheckedColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maCheckedColor = rColor;
+}
+
+const Color&
+StyleSettings::GetCheckedColor() const
+{
+ return mxData->maCheckedColor;
+}
+
+void
+StyleSettings::SetLightColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maLightColor = rColor;
+}
+
+const Color&
+StyleSettings::GetLightColor() const
+{
+ return mxData->maLightColor;
+}
+
+void
+StyleSettings::SetLightBorderColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maLightBorderColor = rColor;
+}
+
+const Color&
+StyleSettings::GetLightBorderColor() const
+{
+ return mxData->maLightBorderColor;
+}
+
+void
+StyleSettings::SetWarningColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maWarningColor = rColor;
+}
+
+const Color&
+StyleSettings::GetWarningColor() const
+{
+ return mxData->maWarningColor;
+}
+
+void
+StyleSettings::SetShadowColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maShadowColor = rColor;
+}
+
+const Color&
+StyleSettings::GetShadowColor() const
+{
+ return mxData->maShadowColor;
+}
+
+void
+StyleSettings::SetDarkShadowColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maDarkShadowColor = rColor;
+}
+
+const Color&
+StyleSettings::GetDarkShadowColor() const
+{
+ return mxData->maDarkShadowColor;
+}
+
+void
+StyleSettings::SetDefaultButtonTextColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maDefaultButtonTextColor = rColor;
+}
+
+const Color&
+StyleSettings::GetDefaultButtonTextColor() const
+{
+ return mxData->maDefaultButtonTextColor;
+}
+
+void
+StyleSettings::SetButtonTextColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maButtonTextColor = rColor;
+}
+
+const Color&
+StyleSettings::GetButtonTextColor() const
+{
+ return mxData->maButtonTextColor;
+}
+
+void
+StyleSettings::SetDefaultActionButtonTextColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maDefaultActionButtonTextColor = rColor;
+}
+
+const Color&
+StyleSettings::GetDefaultActionButtonTextColor() const
+{
+ return mxData->maDefaultActionButtonTextColor;
+}
+
+void
+StyleSettings::SetActionButtonTextColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maActionButtonTextColor = rColor;
+}
+
+const Color&
+StyleSettings::GetActionButtonTextColor() const
+{
+ return mxData->maActionButtonTextColor;
+}
+
+void
+StyleSettings::SetFlatButtonTextColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maFlatButtonTextColor = rColor;
+}
+
+const Color&
+StyleSettings::GetFlatButtonTextColor() const
+{
+ return mxData->maFlatButtonTextColor;
+}
+
+void
+StyleSettings::SetDefaultButtonRolloverTextColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maDefaultButtonRolloverTextColor = rColor;
+}
+
+const Color&
+StyleSettings::GetDefaultButtonRolloverTextColor() const
+{
+ return mxData->maDefaultButtonRolloverTextColor;
+}
+
+void
+StyleSettings::SetButtonRolloverTextColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maButtonRolloverTextColor = rColor;
+}
+
+const Color&
+StyleSettings::GetButtonRolloverTextColor() const
+{
+ return mxData->maButtonRolloverTextColor;
+}
+
+void
+StyleSettings::SetDefaultActionButtonRolloverTextColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maDefaultActionButtonRolloverTextColor = rColor;
+}
+
+const Color&
+StyleSettings::GetDefaultActionButtonRolloverTextColor() const
+{
+ return mxData->maDefaultActionButtonRolloverTextColor;
+}
+
+void
+StyleSettings::SetActionButtonRolloverTextColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maActionButtonRolloverTextColor = rColor;
+}
+
+const Color&
+StyleSettings::GetActionButtonRolloverTextColor() const
+{
+ return mxData->maActionButtonRolloverTextColor;
+}
+
+void
+StyleSettings::SetFlatButtonRolloverTextColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maFlatButtonRolloverTextColor = rColor;
+}
+
+const Color&
+StyleSettings::GetFlatButtonRolloverTextColor() const
+{
+ return mxData->maFlatButtonRolloverTextColor;
+}
+
+void
+StyleSettings::SetDefaultButtonPressedRolloverTextColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maDefaultButtonPressedRolloverTextColor = rColor;
+}
+
+const Color&
+StyleSettings::GetDefaultButtonPressedRolloverTextColor() const
+{
+ return mxData->maDefaultButtonPressedRolloverTextColor;
+}
+
+void
+StyleSettings::SetButtonPressedRolloverTextColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maButtonPressedRolloverTextColor = rColor;
+}
+
+const Color&
+StyleSettings::GetButtonPressedRolloverTextColor() const
+{
+ return mxData->maButtonPressedRolloverTextColor;
+}
+
+void
+StyleSettings::SetDefaultActionButtonPressedRolloverTextColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maDefaultActionButtonPressedRolloverTextColor = rColor;
+}
+
+const Color&
+StyleSettings::GetDefaultActionButtonPressedRolloverTextColor() const
+{
+ return mxData->maDefaultActionButtonPressedRolloverTextColor;
+}
+
+void
+StyleSettings::SetActionButtonPressedRolloverTextColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maActionButtonPressedRolloverTextColor = rColor;
+}
+
+const Color&
+StyleSettings::GetActionButtonPressedRolloverTextColor() const
+{
+ return mxData->maActionButtonPressedRolloverTextColor;
+}
+
+void
+StyleSettings::SetFlatButtonPressedRolloverTextColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maFlatButtonPressedRolloverTextColor = rColor;
+}
+
+const Color&
+StyleSettings::GetFlatButtonPressedRolloverTextColor() const
+{
+ return mxData->maFlatButtonPressedRolloverTextColor;
+}
+
+void
+StyleSettings::SetRadioCheckTextColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maRadioCheckTextColor = rColor;
+}
+
+const Color&
+StyleSettings::GetRadioCheckTextColor() const
+{
+ return mxData->maRadioCheckTextColor;
+}
+
+void
+StyleSettings::SetGroupTextColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maGroupTextColor = rColor;
+}
+
+const Color&
+StyleSettings::GetGroupTextColor() const
+{
+ return mxData->maGroupTextColor;
+}
+
+void
+StyleSettings::SetLabelTextColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maLabelTextColor = rColor;
+}
+
+const Color&
+StyleSettings::GetLabelTextColor() const
+{
+ return mxData->maLabelTextColor;
+}
+
+void
+StyleSettings::SetWindowColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maWindowColor = rColor;
+}
+
+const Color&
+StyleSettings::GetWindowColor() const
+{
+ return mxData->maWindowColor;
+}
+
+void
+StyleSettings::SetWindowTextColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maWindowTextColor = rColor;
+}
+
+const Color&
+StyleSettings::GetWindowTextColor() const
+{
+ return mxData->maWindowTextColor;
+}
+
+void
+StyleSettings::SetDialogColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maDialogColor = rColor;
+}
+
+const Color&
+StyleSettings::GetDialogColor() const
+{
+ return mxData->maDialogColor;
+}
+
+void
+StyleSettings::SetDialogTextColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maDialogTextColor = rColor;
+}
+
+const Color&
+StyleSettings::GetDialogTextColor() const
+{
+ return mxData->maDialogTextColor;
+}
+
+void
+StyleSettings::SetWorkspaceColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maWorkspaceColor = rColor;
+}
+
+const Color&
+StyleSettings::GetWorkspaceColor() const
+{
+ return mxData->maWorkspaceColor;
+}
+
+void
+StyleSettings::SetFieldColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maFieldColor = rColor;
+}
+
+const Color&
+StyleSettings::GetFieldColor() const
+{
+ return mxData->maFieldColor;
+}
+
+void
+StyleSettings::SetFieldTextColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maFieldTextColor = rColor;
+}
+
+const Color&
+StyleSettings::GetFieldTextColor() const
+{
+ return mxData->maFieldTextColor;
+}
+
+void
+StyleSettings::SetFieldRolloverTextColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maFieldRolloverTextColor = rColor;
+}
+
+const Color&
+StyleSettings::GetFieldRolloverTextColor() const
+{
+ return mxData->maFieldRolloverTextColor;
+}
+
+void
+StyleSettings::SetActiveColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maActiveColor = rColor;
+}
+
+const Color&
+StyleSettings::GetActiveColor() const
+{
+ return mxData->maActiveColor;
+}
+
+void
+StyleSettings::SetActiveTextColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maActiveTextColor = rColor;
+}
+
+const Color&
+StyleSettings::GetActiveTextColor() const
+{
+ return mxData->maActiveTextColor;
+}
+
+void
+StyleSettings::SetActiveBorderColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maActiveBorderColor = rColor;
+}
+
+const Color&
+StyleSettings::GetActiveBorderColor() const
+{
+ return mxData->maActiveBorderColor;
+}
+
+void
+StyleSettings::SetDeactiveColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maDeactiveColor = rColor;
+}
+
+const Color&
+StyleSettings::GetDeactiveColor() const
+{
+ return mxData->maDeactiveColor;
+}
+
+void
+StyleSettings::SetDeactiveTextColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maDeactiveTextColor = rColor;
+}
+
+const Color&
+StyleSettings::GetDeactiveTextColor() const
+{
+ return mxData->maDeactiveTextColor;
+}
+
+void
+StyleSettings::SetDeactiveBorderColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maDeactiveBorderColor = rColor;
+}
+
+const Color&
+StyleSettings::GetDeactiveBorderColor() const
+{
+ return mxData->maDeactiveBorderColor;
+}
+
+void
+StyleSettings::SetAccentColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maAccentColor = rColor;
+}
+
+const Color&
+StyleSettings::GetAccentColor() const
+{
+ return mxData->maAccentColor;
+}
+
+void
+StyleSettings::SetHighlightColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maHighlightColor = rColor;
+}
+
+const Color&
+StyleSettings::GetHighlightColor() const
+{
+ return mxData->maHighlightColor;
+}
+
+void
+StyleSettings::SetHighlightTextColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maHighlightTextColor = rColor;
+}
+
+const Color&
+StyleSettings::GetHighlightTextColor() const
+{
+ return mxData->maHighlightTextColor;
+}
+
+void
+StyleSettings::SetDisableColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maDisableColor = rColor;
+}
+
+const Color&
+StyleSettings::GetDisableColor() const
+{
+ return mxData->maDisableColor;
+}
+
+void
+StyleSettings::SetHelpColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maHelpColor = rColor;
+}
+
+const Color&
+StyleSettings::GetHelpColor() const
+{
+ return mxData->maHelpColor;
+}
+
+void
+StyleSettings::SetHelpTextColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maHelpTextColor = rColor;
+}
+
+const Color&
+StyleSettings::GetHelpTextColor() const
+{
+ return mxData->maHelpTextColor;
+}
+
+void
+StyleSettings::SetMenuColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maMenuColor = rColor;
+}
+
+const Color&
+StyleSettings::GetMenuColor() const
+{
+ return mxData->maMenuColor;
+}
+
+void
+StyleSettings::SetMenuBarColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maMenuBarColor = rColor;
+}
+
+const Color&
+StyleSettings::GetMenuBarColor() const
+{
+ return mxData->maMenuBarColor;
+}
+
+void
+StyleSettings::SetMenuBarRolloverColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maMenuBarRolloverColor = rColor;
+}
+
+const Color&
+StyleSettings::GetMenuBarRolloverColor() const
+{
+ return mxData->maMenuBarRolloverColor;
+}
+
+void
+StyleSettings::SetMenuBorderColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maMenuBorderColor = rColor;
+}
+
+const Color&
+StyleSettings::GetMenuBorderColor() const
+{
+ return mxData->maMenuBorderColor;
+}
+
+void
+StyleSettings::SetMenuTextColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maMenuTextColor = rColor;
+}
+
+const Color&
+StyleSettings::GetMenuTextColor() const
+{
+ return mxData->maMenuTextColor;
+}
+
+void
+StyleSettings::SetMenuBarTextColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maMenuBarTextColor = rColor;
+}
+
+const Color&
+StyleSettings::GetMenuBarTextColor() const
+{
+ return mxData->maMenuBarTextColor;
+}
+
+void
+StyleSettings::SetMenuBarRolloverTextColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maMenuBarRolloverTextColor = rColor;
+}
+
+const Color&
+StyleSettings::GetMenuBarRolloverTextColor() const
+{
+ return mxData->maMenuBarRolloverTextColor;
+}
+
+void
+StyleSettings::SetMenuBarHighlightTextColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maMenuBarHighlightTextColor = rColor;
+}
+
+const Color&
+StyleSettings::GetMenuBarHighlightTextColor() const
+{
+ return mxData->maMenuBarHighlightTextColor;
+}
+
+void
+StyleSettings::SetMenuHighlightColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maMenuHighlightColor = rColor;
+}
+
+const Color&
+StyleSettings::GetMenuHighlightColor() const
+{
+ return mxData->maMenuHighlightColor;
+}
+
+void
+StyleSettings::SetMenuHighlightTextColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maMenuHighlightTextColor = rColor;
+}
+
+const Color&
+StyleSettings::GetMenuHighlightTextColor() const
+{
+ return mxData->maMenuHighlightTextColor;
+}
+
+void
+StyleSettings::SetListBoxWindowBackgroundColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maListBoxWindowBackgroundColor = rColor;
+}
+
+const Color&
+StyleSettings::GetListBoxWindowBackgroundColor() const
+{
+ return mxData->maListBoxWindowBackgroundColor;
+}
+
+void
+StyleSettings::SetListBoxWindowTextColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maListBoxWindowTextColor = rColor;
+}
+
+const Color&
+StyleSettings::GetListBoxWindowTextColor() const
+{
+ return mxData->maListBoxWindowTextColor;
+}
+
+void
+StyleSettings::SetListBoxWindowHighlightColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maListBoxWindowHighlightColor = rColor;
+}
+
+const Color&
+StyleSettings::GetListBoxWindowHighlightColor() const
+{
+ return mxData->maListBoxWindowHighlightColor;
+}
+
+void
+StyleSettings::SetListBoxWindowHighlightTextColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maListBoxWindowHighlightTextColor = rColor;
+}
+
+const Color&
+StyleSettings::GetListBoxWindowHighlightTextColor() const
+{
+ return mxData->maListBoxWindowHighlightTextColor;
+}
+
+void
+StyleSettings::SetTabTextColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maTabTextColor = rColor;
+}
+
+const Color&
+StyleSettings::GetTabTextColor() const
+{
+ return mxData->maTabTextColor;
+}
+
+void
+StyleSettings::SetTabRolloverTextColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maTabRolloverTextColor = rColor;
+}
+
+const Color&
+StyleSettings::GetTabRolloverTextColor() const
+{
+ return mxData->maTabRolloverTextColor;
+}
+
+void
+StyleSettings::SetTabHighlightTextColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maTabHighlightTextColor = rColor;
+}
+
+const Color&
+StyleSettings::GetTabHighlightTextColor() const
+{
+ return mxData->maTabHighlightTextColor;
+}
+
+void
+StyleSettings::SetLinkColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maLinkColor = rColor;
+}
+
+const Color&
+StyleSettings::GetLinkColor() const
+{
+ return mxData->maLinkColor;
+}
+
+void
+StyleSettings::SetVisitedLinkColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maVisitedLinkColor = rColor;
+}
+
+const Color&
+StyleSettings::GetVisitedLinkColor() const
+{
+ return mxData->maVisitedLinkColor;
+}
+
+void
+StyleSettings::SetToolTextColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maToolTextColor = rColor;
+}
+
+const Color&
+StyleSettings::GetToolTextColor() const
+{
+ return mxData->maToolTextColor;
+}
+
+void
+StyleSettings::SetMonoColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maMonoColor = rColor;
+}
+
+const Color&
+StyleSettings::GetMonoColor() const
+{
+ return mxData->maMonoColor;
+}
+
+void
+StyleSettings::SetActiveTabColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maActiveTabColor = rColor;
+}
+
+const Color&
+StyleSettings::GetActiveTabColor() const
+{
+ return mxData->maActiveTabColor;
+}
+
+void
+StyleSettings::SetInactiveTabColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maInactiveTabColor = rColor;
+}
+
+const Color&
+StyleSettings::GetInactiveTabColor() const
+{
+ return mxData->maInactiveTabColor;
+}
+
+void StyleSettings::SetAlternatingRowColor(const Color& rColor)
+{
+ CopyData();
+ mxData->maAlternatingRowColor = rColor;
+}
+
+const Color&
+StyleSettings::GetAlternatingRowColor() const
+{
+ return mxData->maAlternatingRowColor;
+}
+
+void
+StyleSettings::SetUseSystemUIFonts( bool bUseSystemUIFonts )
+{
+ CopyData();
+ mxData->mbUseSystemUIFonts = bUseSystemUIFonts;
+}
+
+bool
+StyleSettings::GetUseSystemUIFonts() const
+{
+ return mxData->mbUseSystemUIFonts;
+}
+
+void StyleSettings::SetUseFontAAFromSystem(bool bUseFontAAFromSystem)
+{
+ CopyData();
+ mxData->mbUseFontAAFromSystem = bUseFontAAFromSystem;
+}
+
+bool StyleSettings::GetUseFontAAFromSystem() const
+{
+ return mxData->mbUseFontAAFromSystem;
+}
+
+void
+StyleSettings::SetUseFlatBorders( bool bUseFlatBorders )
+{
+ CopyData();
+ mxData->mnUseFlatBorders = bUseFlatBorders;
+}
+
+bool
+StyleSettings::GetUseFlatBorders() const
+{
+ return mxData->mnUseFlatBorders;
+}
+
+void
+StyleSettings::SetUseFlatMenus( bool bUseFlatMenus )
+{
+ CopyData();
+ mxData->mnUseFlatMenus = bUseFlatMenus;
+}
+
+bool
+StyleSettings::GetUseFlatMenus() const
+{
+ return mxData->mnUseFlatMenus;
+}
+
+void
+StyleSettings::SetUseImagesInMenus( TriState eUseImagesInMenus )
+{
+ CopyData();
+ mxData->meUseImagesInMenus = eUseImagesInMenus;
+}
+
+void
+StyleSettings::SetPreferredUseImagesInMenus( bool bPreferredUseImagesInMenus )
+{
+ CopyData();
+ mxData->mbPreferredUseImagesInMenus = bPreferredUseImagesInMenus;
+}
+
+bool
+StyleSettings::GetPreferredUseImagesInMenus() const
+{
+ return mxData->mbPreferredUseImagesInMenus;
+}
+
+void
+StyleSettings::SetSkipDisabledInMenus( bool bSkipDisabledInMenus )
+{
+ CopyData();
+ mxData->mbSkipDisabledInMenus = bSkipDisabledInMenus;
+}
+
+bool
+StyleSettings::GetSkipDisabledInMenus() const
+{
+ return mxData->mbSkipDisabledInMenus;
+}
+
+void
+StyleSettings::SetHideDisabledMenuItems( bool bHideDisabledMenuItems )
+{
+ CopyData();
+ mxData->mbHideDisabledMenuItems = bHideDisabledMenuItems;
+}
+
+bool
+StyleSettings::GetHideDisabledMenuItems() const
+{
+ return mxData->mbHideDisabledMenuItems;
+}
+
+void
+StyleSettings::SetContextMenuShortcuts( TriState eContextMenuShortcuts )
+{
+ CopyData();
+ mxData->meContextMenuShortcuts = eContextMenuShortcuts;
+}
+
+bool
+StyleSettings::GetContextMenuShortcuts() const
+{
+ switch (mxData->meContextMenuShortcuts)
+ {
+ case TRISTATE_FALSE:
+ return false;
+ case TRISTATE_TRUE:
+ return true;
+ default: // TRISTATE_INDET:
+ return GetPreferredContextMenuShortcuts();
+ }
+}
+
+void
+StyleSettings::SetPreferredContextMenuShortcuts( bool bContextMenuShortcuts )
+{
+ CopyData();
+ mxData->mbPreferredContextMenuShortcuts = bContextMenuShortcuts;
+}
+
+bool
+StyleSettings::GetPreferredContextMenuShortcuts() const
+{
+ return mxData->mbPreferredContextMenuShortcuts;
+}
+
+void
+StyleSettings::SetPrimaryButtonWarpsSlider( bool bPrimaryButtonWarpsSlider )
+{
+ CopyData();
+ mxData->mbPrimaryButtonWarpsSlider = bPrimaryButtonWarpsSlider;
+}
+
+bool
+StyleSettings::GetPrimaryButtonWarpsSlider() const
+{
+ return mxData->mbPrimaryButtonWarpsSlider;
+}
+
+void
+StyleSettings::SetAppFont( const vcl::Font& rFont )
+{
+ CopyData();
+ mxData->maAppFont = rFont;
+}
+
+const vcl::Font&
+StyleSettings::GetAppFont() const
+{
+ return mxData->maAppFont;
+}
+
+void
+StyleSettings::SetHelpFont( const vcl::Font& rFont )
+{
+ CopyData();
+ mxData->maHelpFont = rFont;
+}
+
+const vcl::Font&
+StyleSettings::GetHelpFont() const
+{
+ return mxData->maHelpFont;
+}
+
+void
+StyleSettings::SetTitleFont( const vcl::Font& rFont )
+{
+ CopyData();
+ mxData->maTitleFont = rFont;
+}
+
+const vcl::Font&
+StyleSettings::GetTitleFont() const
+{
+ return mxData->maTitleFont;
+}
+
+void
+StyleSettings::SetFloatTitleFont( const vcl::Font& rFont )
+{
+ CopyData();
+ mxData->maFloatTitleFont = rFont;
+}
+
+const vcl::Font&
+StyleSettings::GetFloatTitleFont() const
+{
+ return mxData->maFloatTitleFont;
+}
+
+void
+StyleSettings::SetMenuFont( const vcl::Font& rFont )
+{
+ CopyData();
+ mxData->maMenuFont = rFont;
+}
+
+const vcl::Font&
+StyleSettings::GetMenuFont() const
+{
+ return mxData->maMenuFont;
+}
+
+void
+StyleSettings::SetToolFont( const vcl::Font& rFont )
+{
+ CopyData();
+ mxData->maToolFont = rFont;
+}
+
+const vcl::Font&
+StyleSettings::GetToolFont() const
+{
+ return mxData->maToolFont;
+}
+
+void
+StyleSettings::SetGroupFont( const vcl::Font& rFont )
+{
+ CopyData();
+ mxData->maGroupFont = rFont;
+}
+
+const vcl::Font&
+StyleSettings::GetGroupFont() const
+{
+ return mxData->maGroupFont;
+}
+
+void
+StyleSettings::SetLabelFont( const vcl::Font& rFont )
+{
+ CopyData();
+ mxData->maLabelFont = rFont;
+}
+
+const vcl::Font&
+StyleSettings::GetLabelFont() const
+{
+ return mxData->maLabelFont;
+}
+
+void
+StyleSettings::SetRadioCheckFont( const vcl::Font& rFont )
+{
+ CopyData();
+ mxData->maRadioCheckFont = rFont;
+}
+
+const vcl::Font&
+StyleSettings::GetRadioCheckFont() const
+{
+ return mxData->maRadioCheckFont;
+}
+
+void
+StyleSettings::SetPushButtonFont( const vcl::Font& rFont )
+{
+ CopyData();
+ mxData->maPushButtonFont = rFont;
+}
+
+const vcl::Font&
+StyleSettings::GetPushButtonFont() const
+{
+ return mxData->maPushButtonFont;
+}
+
+void
+StyleSettings::SetFieldFont( const vcl::Font& rFont )
+{
+ CopyData();
+ mxData->maFieldFont = rFont;
+}
+
+const vcl::Font&
+StyleSettings::GetFieldFont() const
+{
+ return mxData->maFieldFont;
+}
+
+void
+StyleSettings::SetIconFont( const vcl::Font& rFont )
+{
+ CopyData();
+ mxData->maIconFont = rFont;
+}
+
+const vcl::Font&
+StyleSettings::GetIconFont() const
+{
+ return mxData->maIconFont;
+}
+
+void
+StyleSettings::SetTabFont( const vcl::Font& rFont )
+{
+ CopyData();
+ mxData->maTabFont = rFont;
+}
+
+const vcl::Font&
+StyleSettings::GetTabFont() const
+{
+ return mxData->maTabFont;
+}
+
+sal_Int32
+StyleSettings::GetBorderSize()
+{
+ return 1;
+}
+
+void
+StyleSettings::SetTitleHeight( sal_Int32 nSize )
+{
+ CopyData();
+ mxData->mnTitleHeight = nSize;
+}
+
+sal_Int32
+StyleSettings::GetTitleHeight() const
+{
+ return mxData->mnTitleHeight;
+}
+
+void
+StyleSettings::SetFloatTitleHeight( sal_Int32 nSize )
+{
+ CopyData();
+ mxData->mnFloatTitleHeight = nSize;
+}
+
+sal_Int32
+StyleSettings::GetFloatTitleHeight() const
+{
+ return mxData->mnFloatTitleHeight;
+}
+
+void
+StyleSettings::SetScrollBarSize( sal_Int32 nSize )
+{
+ CopyData();
+ mxData->mnScrollBarSize = nSize;
+}
+
+sal_Int32
+StyleSettings::GetScrollBarSize() const
+{
+ return mxData->mnScrollBarSize;
+}
+
+void
+StyleSettings::SetMinThumbSize( sal_Int32 nSize )
+{
+ CopyData();
+ mxData->mnMinThumbSize = nSize;
+}
+
+sal_Int32
+StyleSettings::GetMinThumbSize() const
+{
+ return mxData->mnMinThumbSize;
+}
+
+void
+StyleSettings::SetSpinSize( sal_Int32 nSize )
+{
+ CopyData();
+ mxData->mnSpinSize = nSize;
+}
+
+sal_Int32
+StyleSettings::GetSpinSize() const
+{
+ return mxData->mnSpinSize;
+}
+
+sal_Int32
+StyleSettings::GetSplitSize()
+{
+ return 3;
+}
+
+void
+StyleSettings::SetCursorSize( sal_Int32 nSize )
+{
+ CopyData();
+ mxData->mnCursorSize = nSize;
+}
+
+sal_Int32
+StyleSettings::GetCursorSize() const
+{
+ return mxData->mnCursorSize;
+}
+
+void
+StyleSettings::SetCursorBlinkTime( sal_uInt64 nBlinkTime )
+{
+ CopyData();
+ mxData->mnCursorBlinkTime = nBlinkTime;
+}
+
+sal_uInt64
+StyleSettings::GetCursorBlinkTime() const
+{
+ return mxData->mnCursorBlinkTime;
+}
+
+void
+StyleSettings::SetDragFullOptions( DragFullOptions nOptions )
+{
+ CopyData();
+ mxData->mnDragFullOptions = nOptions;
+}
+
+DragFullOptions
+StyleSettings::GetDragFullOptions() const
+{
+ return mxData->mnDragFullOptions;
+}
+
+void
+StyleSettings::SetSelectionOptions( SelectionOptions nOptions )
+{
+ CopyData();
+ mxData->mnSelectionOptions = nOptions;
+}
+
+SelectionOptions
+StyleSettings::GetSelectionOptions() const
+{
+ return mxData->mnSelectionOptions;
+}
+
+void
+StyleSettings::SetDisplayOptions( DisplayOptions nOptions )
+{
+ CopyData();
+ mxData->mnDisplayOptions = nOptions;
+}
+
+DisplayOptions
+StyleSettings::GetDisplayOptions() const
+{
+ return mxData->mnDisplayOptions;
+}
+
+void
+StyleSettings::SetAntialiasingMinPixelHeight( sal_Int32 nMinPixel )
+{
+ CopyData();
+ mxData->mnAntialiasedMin = nMinPixel;
+}
+
+sal_Int32
+StyleSettings::GetAntialiasingMinPixelHeight() const
+{
+ return mxData->mnAntialiasedMin;
+}
+
+void
+StyleSettings::SetOptions( StyleSettingsOptions nOptions )
+{
+ CopyData();
+ mxData->mnOptions = nOptions;
+}
+
+void
+StyleSettings::SetAutoMnemonic( bool bAutoMnemonic )
+{
+ CopyData();
+ mxData->mbAutoMnemonic = bAutoMnemonic;
+}
+
+bool
+StyleSettings::GetAutoMnemonic() const
+{
+ return mxData->mbAutoMnemonic;
+}
+
+bool
+StyleSettings::GetDockingFloatsSupported()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ return pSVData->maNWFData.mbCanDetermineWindowPosition;
+}
+
+void
+StyleSettings::SetToolbarIconSize( ToolbarIconSize nSize )
+{
+ CopyData();
+ mxData->mnToolbarIconSize = nSize;
+}
+
+ToolbarIconSize
+StyleSettings::GetToolbarIconSize() const
+{
+ return mxData->mnToolbarIconSize;
+}
+
+Size StyleSettings::GetToolbarIconSizePixel() const
+{
+ switch (GetToolbarIconSize())
+ {
+ case ToolbarIconSize::Large:
+ return Size(24, 24);
+ case ToolbarIconSize::Size32:
+ return Size(32, 32);
+ case ToolbarIconSize::Small:
+ default:
+ return Size(16, 16);
+ }
+}
+
+const DialogStyle&
+StyleSettings::GetDialogStyle() const
+{
+ return mxData->maDialogStyle;
+}
+
+void
+StyleSettings::SetEdgeBlending(sal_uInt16 nCount)
+{
+ CopyData();
+ mxData->mnEdgeBlending = nCount;
+}
+
+sal_uInt16
+StyleSettings::GetEdgeBlending() const
+{
+ return mxData->mnEdgeBlending;
+}
+
+const Color&
+StyleSettings::GetEdgeBlendingTopLeftColor() const
+{
+ return mxData->maEdgeBlendingTopLeftColor;
+}
+
+const Color&
+StyleSettings::GetEdgeBlendingBottomRightColor() const
+{
+ return mxData->maEdgeBlendingBottomRightColor;
+}
+
+void
+StyleSettings::SetListBoxMaximumLineCount(sal_uInt16 nCount)
+{
+ CopyData();
+ mxData->mnListBoxMaximumLineCount = nCount;
+}
+
+sal_uInt16
+StyleSettings::GetListBoxMaximumLineCount() const
+{
+ return mxData->mnListBoxMaximumLineCount;
+}
+
+void
+StyleSettings::SetColorValueSetColumnCount(sal_uInt16 nCount)
+{
+ CopyData();
+ mxData->mnColorValueSetColumnCount = nCount;
+}
+
+sal_uInt16
+StyleSettings::GetColorValueSetColumnCount() const
+{
+ return mxData->mnColorValueSetColumnCount;
+}
+
+sal_uInt16
+StyleSettings::GetListBoxPreviewDefaultLineWidth()
+{
+ return 1;
+}
+
+void
+StyleSettings::SetPreviewUsesCheckeredBackground(bool bNew)
+{
+ CopyData();
+ mxData->mbPreviewUsesCheckeredBackground = bNew;
+}
+
+bool
+StyleSettings::GetPreviewUsesCheckeredBackground() const
+{
+ return mxData->mbPreviewUsesCheckeredBackground;
+}
+
+bool
+StyleSettings::operator !=( const StyleSettings& rSet ) const
+{
+ return !(*this == rSet);
+}
+
+void StyleSettings::SetListBoxPreviewDefaultLogicSize(Size const& rSize)
+{
+ mxData->maListBoxPreviewDefaultLogicSize = rSize;
+}
+
+const Size& StyleSettings::GetListBoxPreviewDefaultPixelSize() const
+{
+ if(0 == mxData->maListBoxPreviewDefaultPixelSize.Width() || 0 == mxData->maListBoxPreviewDefaultPixelSize.Height())
+ {
+ const_cast< StyleSettings* >(this)->mxData->maListBoxPreviewDefaultPixelSize =
+ Application::GetDefaultDevice()->LogicToPixel(mxData->maListBoxPreviewDefaultLogicSize, MapMode(MapUnit::MapAppFont));
+ }
+
+ return mxData->maListBoxPreviewDefaultPixelSize;
+}
+
+void StyleSettings::Set3DColors( const Color& rColor )
+{
+ CopyData();
+ mxData->maFaceColor = rColor;
+ mxData->maLightBorderColor = rColor;
+ mxData->maMenuBorderColor = rColor;
+ mxData->maDarkShadowColor = COL_BLACK;
+ if ( rColor != COL_LIGHTGRAY )
+ {
+ mxData->maLightColor = rColor;
+ mxData->maShadowColor = rColor;
+ mxData->maDarkShadowColor = rColor;
+
+ if (!rColor.IsDark())
+ {
+ mxData->maLightColor.IncreaseLuminance(64);
+ mxData->maShadowColor.DecreaseLuminance(64);
+ mxData->maDarkShadowColor.DecreaseLuminance(100);
+ }
+ else
+ {
+ mxData->maLightColor.DecreaseLuminance(64);
+ mxData->maShadowColor.IncreaseLuminance(64);
+ mxData->maDarkShadowColor.IncreaseLuminance(100);
+ }
+
+ sal_uInt8 nRed = (mxData->maLightColor.GetRed() + mxData->maShadowColor.GetRed()) / 2;
+ sal_uInt8 nGreen = (mxData->maLightColor.GetGreen() + mxData->maShadowColor.GetGreen()) / 2;
+ sal_uInt8 nBlue = (mxData->maLightColor.GetBlue() + mxData->maShadowColor.GetBlue()) / 2;
+ mxData->maCheckedColor = Color(nRed, nGreen, nBlue);
+ }
+ else
+ {
+ mxData->maCheckedColor = Color( 0x99, 0x99, 0x99 );
+ mxData->maLightColor = COL_WHITE;
+ mxData->maShadowColor = COL_GRAY;
+ }
+}
+
+void StyleSettings::SetCheckedColorSpecialCase( )
+{
+ CopyData();
+ // Light gray checked color special case
+ if ( GetFaceColor() == COL_LIGHTGRAY )
+ mxData->maCheckedColor = Color( 0xCC, 0xCC, 0xCC );
+ else
+ {
+ sal_uInt8 nRed = static_cast<sal_uInt8>((static_cast<sal_uInt16>(mxData->maFaceColor.GetRed()) + static_cast<sal_uInt16>(mxData->maLightColor.GetRed()))/2);
+ sal_uInt8 nGreen = static_cast<sal_uInt8>((static_cast<sal_uInt16>(mxData->maFaceColor.GetGreen()) + static_cast<sal_uInt16>(mxData->maLightColor.GetGreen()))/2);
+ sal_uInt8 nBlue = static_cast<sal_uInt8>((static_cast<sal_uInt16>(mxData->maFaceColor.GetBlue()) + static_cast<sal_uInt16>(mxData->maLightColor.GetBlue()))/2);
+ mxData->maCheckedColor = Color( nRed, nGreen, nBlue );
+ }
+}
+
+bool StyleSettings::GetUseImagesInMenus() const
+{
+ // icon mode selected in Tools -> Options... -> OpenOffice.org -> View
+ switch (mxData->meUseImagesInMenus) {
+ case TRISTATE_FALSE:
+ return false;
+ case TRISTATE_TRUE:
+ return true;
+ default: // TRISTATE_INDET:
+ return GetPreferredUseImagesInMenus();
+ }
+}
+
+static BitmapEx readBitmapEx( const OUString& rPath )
+{
+ OUString aPath( rPath );
+ rtl::Bootstrap::expandMacros( aPath );
+
+ // import the image
+ Graphic aGraphic;
+ if ( GraphicFilter::LoadGraphic( aPath, OUString(), aGraphic ) != ERRCODE_NONE )
+ return BitmapEx();
+ return aGraphic.GetBitmapEx();
+}
+
+namespace {
+
+enum WhichPersona { PERSONA_HEADER, PERSONA_FOOTER };
+
+}
+
+/** Update the setting of the Persona header / footer in ImplStyleData */
+static void setupPersonaHeaderFooter( WhichPersona eWhich, OUString& rHeaderFooter, BitmapEx& rHeaderFooterBitmap, std::optional<Color>& rMenuBarTextColor )
+{
+ // don't burn time loading images we don't need.
+ if ( Application::IsHeadlessModeEnabled() )
+ return;
+
+ // read from the configuration
+ OUString aPersona( officecfg::Office::Common::Misc::Persona::get() );
+ OUString aPersonaSettings( officecfg::Office::Common::Misc::PersonaSettings::get() );
+
+ // have the settings changed? marks if header /footer prepared before
+ //should maybe extended to a flag that marks if header /footer /both are loaded
+ OUString aOldValue= eWhich==PERSONA_HEADER?OUString(aPersona + ";" + aPersonaSettings+";h" ):OUString(aPersona + ";" + aPersonaSettings+";f" );
+ if ( rHeaderFooter == aOldValue )
+ return;
+
+ rHeaderFooter = aOldValue;
+ rHeaderFooterBitmap = BitmapEx();
+ rMenuBarTextColor.reset();
+
+ // now read the new values and setup bitmaps
+ OUString aHeader, aFooter;
+ if ( aPersona == "own" || aPersona == "default" )
+ {
+ sal_Int32 nIndex = 0;
+
+ // Skip the persona slug, name, and preview
+ aHeader = aPersonaSettings.getToken( 3, ';', nIndex );
+
+ if ( nIndex > 0 )
+ aFooter = aPersonaSettings.getToken( 0, ';', nIndex );
+
+ // change menu text color, advance nIndex to skip the '#'
+ if ( nIndex > 0 )
+ {
+ OUString aColor = aPersonaSettings.getToken( 0, ';', ++nIndex );
+ rMenuBarTextColor = Color( ColorTransparency, aColor.toUInt32( 16 ) );
+ }
+ }
+
+ OUString aName;
+ switch ( eWhich ) {
+ case PERSONA_HEADER: aName = aHeader; break;
+ case PERSONA_FOOTER: aName = aFooter; break;
+ }
+
+ if ( !aName.isEmpty() )
+ {
+ OUString gallery("");
+ // try the gallery first, then the program path:
+ if ( aPersona == "own" && !aPersonaSettings.startsWith( "vnd.sun.star.expand" ) )
+ {
+ gallery = "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE( "bootstrap") "::UserInstallation}";
+ rtl::Bootstrap::expandMacros( gallery );
+ gallery += "/user/gallery/personas/";
+ }
+ else if ( aPersona == "default" )
+ {
+ gallery = "$BRAND_BASE_DIR/" LIBO_SHARE_FOLDER "/gallery/personas/";
+ }
+ rHeaderFooterBitmap = readBitmapEx( gallery + aName );
+
+ if ( rHeaderFooterBitmap.IsEmpty() )
+ rHeaderFooterBitmap = readBitmapEx( "$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" + aName );
+ }
+
+ // Something went wrong. Probably, the images are missing. Clear the persona properties in the registry.
+
+ if( rHeaderFooterBitmap.IsEmpty() )
+ {
+ std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
+ officecfg::Office::Common::Misc::Persona::set( "no", batch );
+ officecfg::Office::Common::Misc::PersonaSettings::set( "", batch );
+ batch->commit();
+ }
+}
+
+BitmapEx const & StyleSettings::GetPersonaHeader() const
+{
+ setupPersonaHeaderFooter( PERSONA_HEADER, mxData->maPersonaHeaderFooter, mxData->maPersonaHeaderBitmap, mxData->maPersonaMenuBarTextColor );
+ return mxData->maPersonaHeaderBitmap;
+}
+
+BitmapEx const & StyleSettings::GetPersonaFooter() const
+{
+ setupPersonaHeaderFooter( PERSONA_FOOTER, mxData->maPersonaHeaderFooter, mxData->maPersonaFooterBitmap, mxData->maPersonaMenuBarTextColor );
+ return mxData->maPersonaFooterBitmap;
+}
+
+const std::optional<Color>& StyleSettings::GetPersonaMenuBarTextColor() const
+{
+ GetPersonaHeader();
+ return mxData->maPersonaMenuBarTextColor;
+}
+
+void StyleSettings::SetStandardStyles()
+{
+ CopyData();
+ mxData->SetStandardStyles();
+}
+
+Color StyleSettings::GetFaceGradientColor() const
+{
+ // compute a brighter face color that can be used in gradients
+ // for a convex look (eg toolbars)
+
+ sal_uInt16 h, s, b;
+ GetFaceColor().RGBtoHSB( h, s, b );
+ if( s > 1) s=1;
+ if( b < 98) b=98;
+ return Color::HSBtoRGB( h, s, b );
+}
+
+Color StyleSettings::GetSeparatorColor() const
+{
+ // compute a brighter shadow color for separators (used in toolbars or between menubar and toolbars on Windows XP)
+ sal_uInt16 h, s, b;
+ GetShadowColor().RGBtoHSB( h, s, b );
+ b += b/4;
+ s -= s/4;
+ return Color::HSBtoRGB( h, s, b );
+}
+
+void StyleSettings::CopyData()
+{
+ // copy if other references exist
+ if (mxData.use_count() > 1)
+ {
+ mxData = std::make_shared<ImplStyleData>(*mxData);
+ }
+}
+
+bool StyleSettings::operator ==( const StyleSettings& rSet ) const
+{
+ if ( mxData == rSet.mxData )
+ return true;
+
+ if (mxData->mIconTheme != rSet.mxData->mIconTheme) {
+ return false;
+ }
+
+ if (*mxData->mIconThemeSelector != *rSet.mxData->mIconThemeSelector) {
+ return false;
+ }
+
+ return (mxData->mnOptions == rSet.mxData->mnOptions) &&
+ (mxData->mbAutoMnemonic == rSet.mxData->mbAutoMnemonic) &&
+ (mxData->mnDragFullOptions == rSet.mxData->mnDragFullOptions) &&
+ (mxData->mnSelectionOptions == rSet.mxData->mnSelectionOptions) &&
+ (mxData->mnDisplayOptions == rSet.mxData->mnDisplayOptions) &&
+ (mxData->mnCursorSize == rSet.mxData->mnCursorSize) &&
+ (mxData->mnCursorBlinkTime == rSet.mxData->mnCursorBlinkTime) &&
+ (mxData->mnTitleHeight == rSet.mxData->mnTitleHeight) &&
+ (mxData->mnFloatTitleHeight == rSet.mxData->mnFloatTitleHeight) &&
+ (mxData->mnScrollBarSize == rSet.mxData->mnScrollBarSize) &&
+ (mxData->mnMinThumbSize == rSet.mxData->mnMinThumbSize) &&
+ (mxData->mnSpinSize == rSet.mxData->mnSpinSize) &&
+ (mxData->mnAntialiasedMin == rSet.mxData->mnAntialiasedMin) &&
+ (mxData->mbHighContrast == rSet.mxData->mbHighContrast) &&
+ (mxData->mbUseSystemUIFonts == rSet.mxData->mbUseSystemUIFonts) &&
+ (mxData->mbUseFontAAFromSystem == rSet.mxData->mbUseFontAAFromSystem) &&
+ (mxData->mnUseFlatBorders == rSet.mxData->mnUseFlatBorders) &&
+ (mxData->mnUseFlatMenus == rSet.mxData->mnUseFlatMenus) &&
+ (mxData->maFaceColor == rSet.mxData->maFaceColor) &&
+ (mxData->maCheckedColor == rSet.mxData->maCheckedColor) &&
+ (mxData->maLightColor == rSet.mxData->maLightColor) &&
+ (mxData->maLightBorderColor == rSet.mxData->maLightBorderColor) &&
+ (mxData->maShadowColor == rSet.mxData->maShadowColor) &&
+ (mxData->maDarkShadowColor == rSet.mxData->maDarkShadowColor) &&
+ (mxData->maWarningColor == rSet.mxData->maWarningColor) &&
+ (mxData->maButtonTextColor == rSet.mxData->maButtonTextColor) &&
+ (mxData->maDefaultActionButtonTextColor == rSet.mxData->maDefaultActionButtonTextColor) &&
+ (mxData->maActionButtonTextColor == rSet.mxData->maActionButtonTextColor) &&
+ (mxData->maButtonRolloverTextColor == rSet.mxData->maButtonRolloverTextColor) &&
+ (mxData->maActionButtonRolloverTextColor == rSet.mxData->maActionButtonRolloverTextColor) &&
+ (mxData->maRadioCheckTextColor == rSet.mxData->maRadioCheckTextColor) &&
+ (mxData->maGroupTextColor == rSet.mxData->maGroupTextColor) &&
+ (mxData->maLabelTextColor == rSet.mxData->maLabelTextColor) &&
+ (mxData->maWindowColor == rSet.mxData->maWindowColor) &&
+ (mxData->maWindowTextColor == rSet.mxData->maWindowTextColor) &&
+ (mxData->maDialogColor == rSet.mxData->maDialogColor) &&
+ (mxData->maDialogTextColor == rSet.mxData->maDialogTextColor) &&
+ (mxData->maWorkspaceColor == rSet.mxData->maWorkspaceColor) &&
+ (mxData->maMonoColor == rSet.mxData->maMonoColor) &&
+ (mxData->maFieldColor == rSet.mxData->maFieldColor) &&
+ (mxData->maFieldTextColor == rSet.mxData->maFieldTextColor) &&
+ (mxData->maActiveColor == rSet.mxData->maActiveColor) &&
+ (mxData->maActiveTextColor == rSet.mxData->maActiveTextColor) &&
+ (mxData->maActiveBorderColor == rSet.mxData->maActiveBorderColor) &&
+ (mxData->maDeactiveColor == rSet.mxData->maDeactiveColor) &&
+ (mxData->maDeactiveTextColor == rSet.mxData->maDeactiveTextColor) &&
+ (mxData->maDeactiveBorderColor == rSet.mxData->maDeactiveBorderColor) &&
+ (mxData->maMenuColor == rSet.mxData->maMenuColor) &&
+ (mxData->maMenuBarColor == rSet.mxData->maMenuBarColor) &&
+ (mxData->maMenuBarRolloverColor == rSet.mxData->maMenuBarRolloverColor) &&
+ (mxData->maMenuBorderColor == rSet.mxData->maMenuBorderColor) &&
+ (mxData->maMenuTextColor == rSet.mxData->maMenuTextColor) &&
+ (mxData->maListBoxWindowBackgroundColor == rSet.mxData->maListBoxWindowBackgroundColor) &&
+ (mxData->maListBoxWindowTextColor == rSet.mxData->maListBoxWindowTextColor) &&
+ (mxData->maListBoxWindowHighlightColor == rSet.mxData->maListBoxWindowHighlightColor) &&
+ (mxData->maListBoxWindowHighlightTextColor == rSet.mxData->maListBoxWindowHighlightTextColor) &&
+ (mxData->maMenuBarTextColor == rSet.mxData->maMenuBarTextColor) &&
+ (mxData->maMenuBarRolloverTextColor == rSet.mxData->maMenuBarRolloverTextColor) &&
+ (mxData->maMenuHighlightColor == rSet.mxData->maMenuHighlightColor) &&
+ (mxData->maMenuHighlightTextColor == rSet.mxData->maMenuHighlightTextColor) &&
+ (mxData->maAccentColor == rSet.mxData->maAccentColor) &&
+ (mxData->maHighlightColor == rSet.mxData->maHighlightColor) &&
+ (mxData->maHighlightTextColor == rSet.mxData->maHighlightTextColor) &&
+ (mxData->maTabTextColor == rSet.mxData->maTabTextColor) &&
+ (mxData->maTabRolloverTextColor == rSet.mxData->maTabRolloverTextColor) &&
+ (mxData->maTabHighlightTextColor == rSet.mxData->maTabHighlightTextColor) &&
+ (mxData->maActiveTabColor == rSet.mxData->maActiveTabColor) &&
+ (mxData->maInactiveTabColor == rSet.mxData->maInactiveTabColor) &&
+ (mxData->maDisableColor == rSet.mxData->maDisableColor) &&
+ (mxData->maHelpColor == rSet.mxData->maHelpColor) &&
+ (mxData->maHelpTextColor == rSet.mxData->maHelpTextColor) &&
+ (mxData->maLinkColor == rSet.mxData->maLinkColor) &&
+ (mxData->maVisitedLinkColor == rSet.mxData->maVisitedLinkColor) &&
+ (mxData->maToolTextColor == rSet.mxData->maToolTextColor) &&
+ (mxData->maAppFont == rSet.mxData->maAppFont) &&
+ (mxData->maHelpFont == rSet.mxData->maHelpFont) &&
+ (mxData->maTitleFont == rSet.mxData->maTitleFont) &&
+ (mxData->maFloatTitleFont == rSet.mxData->maFloatTitleFont) &&
+ (mxData->maMenuFont == rSet.mxData->maMenuFont) &&
+ (mxData->maToolFont == rSet.mxData->maToolFont) &&
+ (mxData->maGroupFont == rSet.mxData->maGroupFont) &&
+ (mxData->maLabelFont == rSet.mxData->maLabelFont) &&
+ (mxData->maRadioCheckFont == rSet.mxData->maRadioCheckFont) &&
+ (mxData->maPushButtonFont == rSet.mxData->maPushButtonFont) &&
+ (mxData->maFieldFont == rSet.mxData->maFieldFont) &&
+ (mxData->maIconFont == rSet.mxData->maIconFont) &&
+ (mxData->maTabFont == rSet.mxData->maTabFont) &&
+ (mxData->meUseImagesInMenus == rSet.mxData->meUseImagesInMenus) &&
+ (mxData->mbPreferredUseImagesInMenus == rSet.mxData->mbPreferredUseImagesInMenus) &&
+ (mxData->mbSkipDisabledInMenus == rSet.mxData->mbSkipDisabledInMenus) &&
+ (mxData->mbHideDisabledMenuItems == rSet.mxData->mbHideDisabledMenuItems) &&
+ (mxData->mbPreferredContextMenuShortcuts == rSet.mxData->mbPreferredContextMenuShortcuts)&&
+ (mxData->meContextMenuShortcuts == rSet.mxData->meContextMenuShortcuts) &&
+ (mxData->mbPrimaryButtonWarpsSlider == rSet.mxData->mbPrimaryButtonWarpsSlider) &&
+ (mxData->mnEdgeBlending == rSet.mxData->mnEdgeBlending) &&
+ (mxData->maEdgeBlendingTopLeftColor == rSet.mxData->maEdgeBlendingTopLeftColor) &&
+ (mxData->maEdgeBlendingBottomRightColor == rSet.mxData->maEdgeBlendingBottomRightColor) &&
+ (mxData->mnListBoxMaximumLineCount == rSet.mxData->mnListBoxMaximumLineCount) &&
+ (mxData->mnColorValueSetColumnCount == rSet.mxData->mnColorValueSetColumnCount) &&
+ (mxData->maListBoxPreviewDefaultLogicSize == rSet.mxData->maListBoxPreviewDefaultLogicSize) &&
+ (mxData->maListBoxPreviewDefaultPixelSize == rSet.mxData->maListBoxPreviewDefaultPixelSize) &&
+ (mxData->mbPreviewUsesCheckeredBackground == rSet.mxData->mbPreviewUsesCheckeredBackground);
+}
+
+ImplMiscData::ImplMiscData() :
+ mnEnableATT(TRISTATE_INDET),
+ mnDisablePrinting(TRISTATE_INDET)
+{
+ static const char* pEnv = getenv("SAL_DECIMALSEP_ENABLED" ); // set default without UI
+ mbEnableLocalizedDecimalSep = (pEnv != nullptr);
+}
+
+MiscSettings::MiscSettings()
+ : mxData(std::make_shared<ImplMiscData>())
+{
+}
+
+bool MiscSettings::operator ==( const MiscSettings& rSet ) const
+{
+ if ( mxData == rSet.mxData )
+ return true;
+
+ return (mxData->mnEnableATT == rSet.mxData->mnEnableATT ) &&
+ (mxData->mnDisablePrinting == rSet.mxData->mnDisablePrinting ) &&
+ (mxData->mbEnableLocalizedDecimalSep == rSet.mxData->mbEnableLocalizedDecimalSep );
+}
+
+bool
+MiscSettings::operator !=( const MiscSettings& rSet ) const
+{
+ return !(*this == rSet);
+}
+
+bool MiscSettings::GetDisablePrinting() const
+{
+ if( mxData->mnDisablePrinting == TRISTATE_INDET )
+ {
+ OUString aEnable =
+ vcl::SettingsConfigItem::get()->
+ getValue( "DesktopManagement",
+ "DisablePrinting" );
+ mxData->mnDisablePrinting = aEnable.equalsIgnoreAsciiCase("true") ? TRISTATE_TRUE : TRISTATE_FALSE;
+ }
+
+ return mxData->mnDisablePrinting != TRISTATE_FALSE;
+}
+
+bool MiscSettings::GetEnableATToolSupport() const
+{
+
+#ifdef _WIN32
+ if( mxData->mnEnableATT == TRISTATE_INDET )
+ {
+ // Check in the Windows registry if an AT tool wants Accessibility support to
+ // be activated ..
+ HKEY hkey;
+
+ if( ERROR_SUCCESS == RegOpenKeyW(HKEY_CURRENT_USER,
+ L"Software\\LibreOffice\\Accessibility\\AtToolSupport",
+ &hkey) )
+ {
+ DWORD dwType;
+ wchar_t Data[6]; // possible values: "true", "false", "1", "0", DWORD
+ DWORD cbData = sizeof(Data);
+
+ if( ERROR_SUCCESS == RegQueryValueExW(hkey, L"SupportAssistiveTechnology",
+ nullptr, &dwType, reinterpret_cast<LPBYTE>(Data), &cbData) )
+ {
+ switch (dwType)
+ {
+ case REG_SZ:
+ mxData->mnEnableATT = ((0 == wcsicmp(Data, L"1")) || (0 == wcsicmp(Data, L"true"))) ? TRISTATE_TRUE : TRISTATE_FALSE;
+ break;
+ case REG_DWORD:
+ switch (reinterpret_cast<DWORD *>(Data)[0]) {
+ case 0:
+ mxData->mnEnableATT = TRISTATE_FALSE;
+ break;
+ case 1:
+ mxData->mnEnableATT = TRISTATE_TRUE;
+ break;
+ default:
+ mxData->mnEnableATT = TRISTATE_INDET;
+ //TODO: or TRISTATE_TRUE?
+ break;
+ }
+ break;
+ default:
+ // Unsupported registry type
+ break;
+ }
+ }
+
+ RegCloseKey(hkey);
+ }
+ }
+#endif
+
+ if( mxData->mnEnableATT == TRISTATE_INDET )
+ {
+ static const char* pEnv = getenv("SAL_ACCESSIBILITY_ENABLED" );
+ if( !pEnv || !*pEnv )
+ {
+ OUString aEnable =
+ vcl::SettingsConfigItem::get()->
+ getValue( "Accessibility",
+ "EnableATToolSupport" );
+ mxData->mnEnableATT = aEnable.equalsIgnoreAsciiCase("true") ? TRISTATE_TRUE : TRISTATE_FALSE;
+ }
+ else
+ {
+ mxData->mnEnableATT = TRISTATE_TRUE;
+ }
+ }
+
+ return mxData->mnEnableATT != TRISTATE_FALSE;
+}
+
+#ifdef _WIN32
+void MiscSettings::SetEnableATToolSupport( bool bEnable )
+{
+ if ( (bEnable ? TRISTATE_TRUE : TRISTATE_FALSE) != mxData->mnEnableATT )
+ {
+ if( bEnable && !ImplInitAccessBridge() )
+ return;
+
+ mxData->mnEnableATT = bEnable ? TRISTATE_TRUE : TRISTATE_FALSE;
+
+ if (getenv("LO_TESTNAME") != nullptr)
+ return; // No registry changing; no SettingsConfigItem modification
+
+ HKEY hkey;
+
+ // If the accessibility key in the Windows registry exists, change it synchronously
+ if( ERROR_SUCCESS == RegOpenKeyW(HKEY_CURRENT_USER,
+ L"Software\\LibreOffice\\Accessibility\\AtToolSupport",
+ &hkey) )
+ {
+ DWORD dwType;
+ wchar_t Data[6]; // possible values: "true", "false", 1, 0
+ DWORD cbData = sizeof(Data);
+
+ if( ERROR_SUCCESS == RegQueryValueExW(hkey, L"SupportAssistiveTechnology",
+ nullptr, &dwType, reinterpret_cast<LPBYTE>(Data), &cbData) )
+ {
+ switch (dwType)
+ {
+ case REG_SZ:
+ RegSetValueExW(hkey, L"SupportAssistiveTechnology",
+ 0, dwType,
+ reinterpret_cast<const BYTE*>(bEnable ? L"true" : L"false"),
+ bEnable ? sizeof(L"true") : sizeof(L"false"));
+ break;
+ case REG_DWORD:
+ reinterpret_cast<DWORD *>(Data)[0] = bEnable ? 1 : 0;
+ RegSetValueExW(hkey, L"SupportAssistiveTechnology",
+ 0, dwType, reinterpret_cast<const BYTE*>(Data), sizeof(DWORD));
+ break;
+ default:
+ // Unsupported registry type
+ break;
+ }
+ }
+
+ RegCloseKey(hkey);
+ }
+
+ vcl::SettingsConfigItem::get()->
+ setValue( "Accessibility",
+ "EnableATToolSupport",
+ bEnable ? OUString("true") : OUString("false" ) );
+ }
+}
+#endif
+
+void MiscSettings::SetEnableLocalizedDecimalSep( bool bEnable )
+{
+ // copy if other references exist
+ if (mxData.use_count() > 1)
+ {
+ mxData = std::make_shared<ImplMiscData>(*mxData);
+ }
+ mxData->mbEnableLocalizedDecimalSep = bEnable;
+}
+
+bool MiscSettings::GetEnableLocalizedDecimalSep() const
+{
+ return mxData->mbEnableLocalizedDecimalSep;
+}
+
+int MiscSettings::GetDarkMode()
+{
+ return officecfg::Office::Common::Misc::Appearance::get();
+}
+
+void MiscSettings::SetDarkMode(int nMode)
+{
+ std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
+ officecfg::Office::Common::Misc::Appearance::set(nMode, batch);
+ batch->commit();
+
+ vcl::Window *pWin = Application::GetFirstTopLevelWindow();
+ while (pWin)
+ {
+ pWin->ImplGetFrame()->UpdateDarkMode();
+ pWin = Application::GetNextTopLevelWindow(pWin);
+ }
+}
+
+bool MiscSettings::GetUseDarkMode()
+{
+ vcl::Window* pDefWindow = ImplGetDefaultWindow();
+ if (pDefWindow == nullptr)
+ return false;
+ return pDefWindow->ImplGetFrame()->GetUseDarkMode();
+}
+
+int MiscSettings::GetAppColorMode()
+{
+ if (utl::ConfigManager::IsFuzzing())
+ return 0;
+ return officecfg::Office::Common::Misc::ApplicationAppearance::get();
+}
+
+void MiscSettings::SetAppColorMode(int nMode)
+{
+ std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
+ officecfg::Office::Common::Misc::ApplicationAppearance::set(nMode, batch);
+ batch->commit();
+}
+
+bool MiscSettings::GetUseReducedAnimation()
+{
+ vcl::Window* pDefWindow = ImplGetDefaultWindow();
+ if (pDefWindow == nullptr)
+ return false;
+ return pDefWindow->ImplGetFrame()->GetUseReducedAnimation();
+}
+
+HelpSettings::HelpSettings()
+ : mxData(std::make_shared<ImplHelpData>())
+{
+}
+
+bool HelpSettings::operator ==( const HelpSettings& rSet ) const
+{
+ if ( mxData == rSet.mxData )
+ return true;
+
+ return (mxData->mnTipTimeout == rSet.mxData->mnTipTimeout );
+}
+
+sal_Int32
+HelpSettings::GetTipDelay()
+{
+ return 500;
+}
+
+void
+HelpSettings::SetTipTimeout( sal_Int32 nTipTimeout )
+{
+ // copy if other references exist
+ if (mxData.use_count() > 1)
+ {
+ mxData = std::make_shared<ImplHelpData>(*mxData);
+ }
+ mxData->mnTipTimeout = nTipTimeout;
+}
+
+sal_Int32
+HelpSettings::GetTipTimeout() const
+{
+ return mxData->mnTipTimeout;
+}
+
+sal_Int32
+HelpSettings::GetBalloonDelay()
+{
+ return 1500;
+}
+
+bool
+HelpSettings::operator !=( const HelpSettings& rSet ) const
+{
+ return !(*this == rSet);
+}
+
+ImplAllSettingsData::ImplAllSettingsData()
+ :
+ maLocale( LANGUAGE_SYSTEM ),
+ maUILocale( LANGUAGE_SYSTEM )
+{
+ if (!utl::ConfigManager::IsFuzzing())
+ maMiscSettings.SetEnableLocalizedDecimalSep( maSysLocale.GetOptions().IsDecimalSeparatorAsLocale() );
+}
+
+ImplAllSettingsData::ImplAllSettingsData( const ImplAllSettingsData& rData ) :
+ maMouseSettings( rData.maMouseSettings ),
+ maStyleSettings( rData.maStyleSettings ),
+ maMiscSettings( rData.maMiscSettings ),
+ maHelpSettings( rData.maHelpSettings ),
+ maLocale( rData.maLocale ),
+ maUILocale( rData.maUILocale )
+{
+ // Create the cache objects new when their getter is called.
+}
+
+ImplAllSettingsData::~ImplAllSettingsData()
+{
+ mpLocaleDataWrapper.reset();
+ mpUILocaleDataWrapper.reset();
+ mpNeutralLocaleDataWrapper.reset();
+ mpI18nHelper.reset();
+ mpUII18nHelper.reset();
+}
+
+AllSettings::AllSettings()
+ : mxData(std::make_shared<ImplAllSettingsData>())
+{
+}
+
+void AllSettings::CopyData()
+{
+ // copy if other references exist
+ if (mxData.use_count() > 1)
+ {
+ mxData = std::make_shared<ImplAllSettingsData>(*mxData);
+ }
+
+}
+
+AllSettingsFlags AllSettings::Update( AllSettingsFlags nFlags, const AllSettings& rSet )
+{
+
+ AllSettingsFlags nChangeFlags = AllSettingsFlags::NONE;
+
+ if ( nFlags & AllSettingsFlags::MOUSE )
+ {
+ if ( mxData->maMouseSettings != rSet.mxData->maMouseSettings )
+ {
+ CopyData();
+ mxData->maMouseSettings = rSet.mxData->maMouseSettings;
+ nChangeFlags |= AllSettingsFlags::MOUSE;
+ }
+ }
+
+ if ( nFlags & AllSettingsFlags::STYLE )
+ {
+ if ( mxData->maStyleSettings != rSet.mxData->maStyleSettings )
+ {
+ CopyData();
+ mxData->maStyleSettings = rSet.mxData->maStyleSettings;
+ nChangeFlags |= AllSettingsFlags::STYLE;
+ }
+ }
+
+ if ( nFlags & AllSettingsFlags::MISC )
+ {
+ if ( mxData->maMiscSettings != rSet.mxData->maMiscSettings )
+ {
+ CopyData();
+ mxData->maMiscSettings = rSet.mxData->maMiscSettings;
+ nChangeFlags |= AllSettingsFlags::MISC;
+ }
+ }
+
+ if ( nFlags & AllSettingsFlags::LOCALE )
+ {
+ if ( mxData->maLocale != rSet.mxData->maLocale )
+ {
+ SetLanguageTag( rSet.mxData->maLocale );
+ nChangeFlags |= AllSettingsFlags::LOCALE;
+ }
+ }
+
+ return nChangeFlags;
+}
+
+AllSettingsFlags AllSettings::GetChangeFlags( const AllSettings& rSet ) const
+{
+
+ AllSettingsFlags nChangeFlags = AllSettingsFlags::NONE;
+
+ if ( mxData->maStyleSettings != rSet.mxData->maStyleSettings )
+ nChangeFlags |= AllSettingsFlags::STYLE;
+
+ if ( mxData->maMiscSettings != rSet.mxData->maMiscSettings )
+ nChangeFlags |= AllSettingsFlags::MISC;
+
+ if ( mxData->maLocale != rSet.mxData->maLocale )
+ nChangeFlags |= AllSettingsFlags::LOCALE;
+
+ return nChangeFlags;
+}
+
+bool AllSettings::operator ==( const AllSettings& rSet ) const
+{
+ if ( mxData == rSet.mxData )
+ return true;
+
+ if ( (mxData->maMouseSettings == rSet.mxData->maMouseSettings) &&
+ (mxData->maStyleSettings == rSet.mxData->maStyleSettings) &&
+ (mxData->maMiscSettings == rSet.mxData->maMiscSettings) &&
+ (mxData->maHelpSettings == rSet.mxData->maHelpSettings) &&
+ (mxData->maLocale == rSet.mxData->maLocale) )
+ {
+ return true;
+ }
+
+ return false;
+}
+
+void AllSettings::SetLanguageTag(const OUString& rLanguage, bool bCanonicalize)
+{
+ SetLanguageTag(LanguageTag(rLanguage, bCanonicalize));
+}
+
+void AllSettings::SetLanguageTag( const LanguageTag& rLanguageTag )
+{
+ if (mxData->maLocale == rLanguageTag)
+ return;
+
+ CopyData();
+
+ mxData->maLocale = rLanguageTag;
+
+ if ( mxData->mpLocaleDataWrapper )
+ {
+ mxData->mpLocaleDataWrapper.reset();
+ }
+ if ( mxData->mpI18nHelper )
+ {
+ mxData->mpI18nHelper.reset();
+ }
+}
+
+namespace
+{
+ bool GetConfigLayoutRTL(bool bMath)
+ {
+ static const char* pEnv = getenv("SAL_RTL_ENABLED" );
+ static int nUIMirroring = -1; // -1: undef, 0: auto, 1: on 2: off
+
+ // environment always overrides
+ if( pEnv )
+ return true;
+
+ bool bRTL = false;
+
+ if( nUIMirroring == -1 )
+ {
+ nUIMirroring = 0; // ask configuration only once
+ utl::OConfigurationNode aNode = utl::OConfigurationTreeRoot::tryCreateWithComponentContext(
+ comphelper::getProcessComponentContext(),
+ "org.openoffice.Office.Common/I18N/CTL" ); // note: case sensitive !
+ if ( aNode.isValid() )
+ {
+ bool bTmp = bool();
+ css::uno::Any aValue = aNode.getNodeValue( "UIMirroring" );
+ if( aValue >>= bTmp )
+ {
+ // found true or false; if it was nil, nothing is changed
+ nUIMirroring = bTmp ? 1 : 2;
+ }
+ }
+ }
+
+ if( nUIMirroring == 0 ) // no config found (eg, setup) or default (nil) was set: check language
+ {
+ LanguageType aLang = SvtSysLocaleOptions().GetRealUILanguageTag().getLanguageType();
+ if (bMath)
+ bRTL = MsLangId::isRightToLeftMath( aLang );
+ else
+ bRTL = MsLangId::isRightToLeft( aLang );
+ }
+ else
+ bRTL = (nUIMirroring == 1);
+
+ return bRTL;
+ }
+}
+
+bool AllSettings::GetLayoutRTL()
+{
+ if (utl::ConfigManager::IsFuzzing())
+ return false;
+ return GetConfigLayoutRTL(false);
+}
+
+bool AllSettings::GetMathLayoutRTL()
+{
+ if (utl::ConfigManager::IsFuzzing())
+ return false;
+ return GetConfigLayoutRTL(true);
+}
+
+const LanguageTag& AllSettings::GetLanguageTag() const
+{
+ if (utl::ConfigManager::IsFuzzing())
+ {
+ static LanguageTag aRet("en-US");
+ return aRet;
+ }
+
+ if (comphelper::LibreOfficeKit::isActive())
+ return comphelper::LibreOfficeKit::getLanguageTag();
+
+ // SYSTEM locale means: use settings from SvtSysLocale that is resolved
+ if ( mxData->maLocale.isSystemLocale() )
+ mxData->maLocale = mxData->maSysLocale.GetLanguageTag();
+
+ return mxData->maLocale;
+}
+
+const LanguageTag& AllSettings::GetUILanguageTag() const
+{
+ if (utl::ConfigManager::IsFuzzing())
+ {
+ static LanguageTag aRet("en-US");
+ return aRet;
+ }
+
+ if (comphelper::LibreOfficeKit::isActive())
+ return comphelper::LibreOfficeKit::getLanguageTag();
+
+ // the UILocale is never changed
+ if ( mxData->maUILocale.isSystemLocale() )
+ mxData->maUILocale = mxData->maSysLocale.GetUILanguageTag();
+
+ return mxData->maUILocale;
+}
+
+const LocaleDataWrapper& AllSettings::GetLocaleDataWrapper() const
+{
+ if ( !mxData->mpLocaleDataWrapper )
+ const_cast<AllSettings*>(this)->mxData->mpLocaleDataWrapper.reset( new LocaleDataWrapper(
+ comphelper::getProcessComponentContext(), GetLanguageTag() ) );
+ return *mxData->mpLocaleDataWrapper;
+}
+
+const LocaleDataWrapper& AllSettings::GetUILocaleDataWrapper() const
+{
+ if ( !mxData->mpUILocaleDataWrapper )
+ const_cast<AllSettings*>(this)->mxData->mpUILocaleDataWrapper.reset( new LocaleDataWrapper(
+ comphelper::getProcessComponentContext(), GetUILanguageTag() ) );
+ return *mxData->mpUILocaleDataWrapper;
+}
+
+const LocaleDataWrapper& AllSettings::GetNeutralLocaleDataWrapper() const
+{
+ if ( !mxData->mpNeutralLocaleDataWrapper )
+ const_cast<AllSettings*>(this)->mxData->mpNeutralLocaleDataWrapper.reset( new LocaleDataWrapper(
+ comphelper::getProcessComponentContext(), LanguageTag("en-US") ) );
+ return *mxData->mpNeutralLocaleDataWrapper;
+}
+
+const vcl::I18nHelper& AllSettings::GetLocaleI18nHelper() const
+{
+ if ( !mxData->mpI18nHelper ) {
+ const_cast<AllSettings*>(this)->mxData->mpI18nHelper.reset( new vcl::I18nHelper(
+ comphelper::getProcessComponentContext(), GetLanguageTag() ) );
+ }
+ return *mxData->mpI18nHelper;
+}
+
+const vcl::I18nHelper& AllSettings::GetUILocaleI18nHelper() const
+{
+ if ( !mxData->mpUII18nHelper ) {
+ const_cast<AllSettings*>(this)->mxData->mpUII18nHelper.reset( new vcl::I18nHelper(
+ comphelper::getProcessComponentContext(), GetUILanguageTag() ) );
+ }
+ return *mxData->mpUII18nHelper;
+}
+
+void AllSettings::LocaleSettingsChanged( ConfigurationHints nHint )
+{
+ AllSettings aAllSettings( Application::GetSettings() );
+ if ( nHint & ConfigurationHints::DecSep )
+ {
+ MiscSettings aMiscSettings = aAllSettings.GetMiscSettings();
+ bool bIsDecSepAsLocale = aAllSettings.mxData->maSysLocale.GetOptions().IsDecimalSeparatorAsLocale();
+ if ( aMiscSettings.GetEnableLocalizedDecimalSep() != bIsDecSepAsLocale )
+ {
+ aMiscSettings.SetEnableLocalizedDecimalSep( bIsDecSepAsLocale );
+ aAllSettings.SetMiscSettings( aMiscSettings );
+ }
+ }
+
+ if ( nHint & ConfigurationHints::Locale )
+ aAllSettings.SetLanguageTag( aAllSettings.mxData->maSysLocale.GetOptions().GetLanguageTag() );
+
+ Application::SetSettings( aAllSettings );
+}
+
+const StyleSettings&
+AllSettings::GetStyleSettings() const
+{
+ return mxData->maStyleSettings;
+}
+
+StyleSettingsOptions
+StyleSettings::GetOptions() const
+{
+ return mxData->mnOptions;
+}
+
+std::vector<vcl::IconThemeInfo> const &
+StyleSettings::GetInstalledIconThemes() const
+{
+ if (!mxData->mIconThemeScanner) {
+ const_cast<StyleSettings*>(this)->mxData->mIconThemeScanner = vcl::IconThemeScanner::Create(vcl::IconThemeScanner::GetStandardIconThemePath());
+ }
+ return mxData->mIconThemeScanner->GetFoundIconThemes();
+}
+
+/*static*/ OUString
+StyleSettings::GetAutomaticallyChosenIconTheme() const
+{
+ OUString desktopEnvironment = Application::GetDesktopEnvironment();
+ if (!mxData->mIconThemeScanner) {
+ const_cast<StyleSettings*>(this)->mxData->mIconThemeScanner = vcl::IconThemeScanner::Create(vcl::IconThemeScanner::GetStandardIconThemePath());
+ }
+ OUString themeName = mxData->mIconThemeSelector->SelectIconThemeForDesktopEnvironment(
+ mxData->mIconThemeScanner->GetFoundIconThemes(),
+ desktopEnvironment
+ );
+ return themeName;
+}
+
+void
+StyleSettings::SetIconTheme(const OUString& theme)
+{
+ CopyData();
+ mxData->mIconTheme = theme;
+}
+
+OUString
+StyleSettings::DetermineIconTheme() const
+{
+ OUString sTheme(mxData->mIconTheme);
+ if (sTheme.isEmpty())
+ {
+ if (utl::ConfigManager::IsFuzzing())
+ sTheme = "colibre";
+ else
+ {
+ // read from the configuration, or fallback to what the desktop wants
+ sTheme = officecfg::Office::Common::Misc::SymbolStyle::get();
+
+ if (sTheme.isEmpty() || sTheme == "auto")
+ sTheme = GetAutomaticallyChosenIconTheme();
+ }
+ }
+
+ if (!mxData->mIconThemeScanner) {
+ const_cast<StyleSettings*>(this)->mxData->mIconThemeScanner = vcl::IconThemeScanner::Create(vcl::IconThemeScanner::GetStandardIconThemePath());
+ }
+ OUString r = mxData->mIconThemeSelector->SelectIconTheme(
+ mxData->mIconThemeScanner->GetFoundIconThemes(),
+ sTheme);
+ return r;
+}
+
+void
+StyleSettings::SetHighContrastMode(bool bHighContrast )
+{
+ if (mxData->mbHighContrast == bHighContrast) {
+ return;
+ }
+
+ CopyData();
+ mxData->mbHighContrast = bHighContrast;
+ mxData->mIconThemeSelector->SetUseHighContrastTheme(bHighContrast);
+}
+
+bool
+StyleSettings::GetHighContrastMode() const
+{
+ return mxData->mbHighContrast;
+}
+
+void
+StyleSettings::SetPreferredIconTheme(const OUString& theme, bool bDarkIconTheme)
+{
+ const bool bChanged = mxData->mIconThemeSelector->SetPreferredIconTheme(theme, bDarkIconTheme);
+ if (bChanged)
+ {
+ // clear this so it is recalculated if it was selected as the automatic theme
+ mxData->mIconTheme.clear();
+ }
+}
+
+void
+AllSettings::SetMouseSettings( const MouseSettings& rSet )
+{
+ CopyData();
+ mxData->maMouseSettings = rSet;
+}
+
+const MouseSettings&
+AllSettings::GetMouseSettings() const
+{
+ return mxData->maMouseSettings;
+}
+
+void
+AllSettings::SetStyleSettings( const StyleSettings& rSet )
+{
+ CopyData();
+ mxData->maStyleSettings = rSet;
+}
+
+void
+AllSettings::SetMiscSettings( const MiscSettings& rSet )
+{
+ CopyData();
+ mxData->maMiscSettings = rSet;
+}
+
+const MiscSettings&
+AllSettings::GetMiscSettings() const
+{
+ return mxData->maMiscSettings;
+}
+
+void
+AllSettings::SetHelpSettings( const HelpSettings& rSet )
+{
+ CopyData();
+ mxData->maHelpSettings = rSet;
+}
+
+const HelpSettings&
+AllSettings::GetHelpSettings() const
+{
+ return mxData->maHelpSettings;
+}
+
+bool
+AllSettings::operator !=( const AllSettings& rSet ) const
+{
+ return !(*this == rSet);
+}
+
+SvtSysLocale&
+AllSettings::GetSysLocale()
+{
+ return mxData->maSysLocale;
+}
+
+
+void StyleSettings::BatchSetBackgrounds( const Color &aBackColor,
+ bool bCheckedColorSpecialCase )
+{
+ Set3DColors( aBackColor );
+ SetFaceColor( aBackColor );
+ SetDialogColor( aBackColor );
+ SetWorkspaceColor( aBackColor );
+
+ if (bCheckedColorSpecialCase)
+ SetCheckedColorSpecialCase();
+}
+
+void StyleSettings::BatchSetFonts( const vcl::Font& aAppFont,
+ const vcl::Font& aLabelFont )
+{
+ SetAppFont( aAppFont );
+ SetPushButtonFont( aAppFont );
+ SetToolFont( aAppFont );
+ SetHelpFont( aAppFont );
+
+ SetMenuFont( aLabelFont );
+ SetTabFont( aLabelFont );
+ SetLabelFont( aLabelFont );
+ SetRadioCheckFont( aLabelFont );
+ SetFieldFont( aLabelFont );
+ SetGroupFont( aLabelFont );
+ SetIconFont( aLabelFont );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/app/sound.cxx b/vcl/source/app/sound.cxx
new file mode 100644
index 0000000000..024ba9ebcd
--- /dev/null
+++ b/vcl/source/app/sound.cxx
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vcl/svapp.hxx>
+#include <vcl/window.hxx>
+#include <vcl/sound.hxx>
+
+#include <salframe.hxx>
+#include <svdata.hxx>
+
+void Sound::Beep()
+{
+ // #i91990#
+ if (Application::IsHeadlessModeEnabled())
+ return;
+
+ vcl::Window* pWindow = ImplGetDefaultWindow();
+
+ pWindow->ImplGetFrame()->Beep();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/app/stdtext.cxx b/vcl/source/app/stdtext.cxx
new file mode 100644
index 0000000000..bef130dc7d
--- /dev/null
+++ b/vcl/source/app/stdtext.cxx
@@ -0,0 +1,124 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vcl/stdtext.hxx>
+#include <vcl/image.hxx>
+#include <vcl/weld.hxx>
+#include <bitmaps.hlst>
+#include <strings.hrc>
+#include <svdata.hxx>
+
+void ShowServiceNotAvailableError(weld::Widget* pParent,
+ std::u16string_view rServiceName, bool bError)
+{
+ OUString aText = VclResId(SV_STDTEXT_SERVICENOTAVAILABLE).replaceAll("%s", rServiceName);
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(pParent,
+ bError ? VclMessageType::Error : VclMessageType::Warning, VclButtonsType::Ok, aText));
+ xBox->run();
+}
+
+static void ImplInitMsgBoxImageList()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ std::vector<Image> &rImages = pSVData->mpWinData->maMsgBoxImgList;
+ if (rImages.empty())
+ {
+ rImages.emplace_back(StockImage::Yes, SV_RESID_BITMAP_ERRORBOX);
+ rImages.emplace_back(StockImage::Yes, SV_RESID_BITMAP_QUERYBOX);
+ rImages.emplace_back(StockImage::Yes, SV_RESID_BITMAP_WARNINGBOX);
+ rImages.emplace_back(StockImage::Yes, SV_RESID_BITMAP_INFOBOX);
+ }
+}
+
+Image const & GetStandardInfoBoxImage()
+{
+ ImplInitMsgBoxImageList();
+ return ImplGetSVData()->mpWinData->maMsgBoxImgList[3];
+}
+
+OUString GetStandardInfoBoxText()
+{
+ return VclResId(SV_MSGBOX_INFO);
+}
+
+Image const & GetStandardWarningBoxImage()
+{
+ ImplInitMsgBoxImageList();
+ return ImplGetSVData()->mpWinData->maMsgBoxImgList[2];
+}
+
+OUString GetStandardWarningBoxText()
+{
+ return VclResId(SV_MSGBOX_WARNING);
+}
+
+Image const & GetStandardErrorBoxImage()
+{
+ ImplInitMsgBoxImageList();
+ return ImplGetSVData()->mpWinData->maMsgBoxImgList[0];
+}
+
+OUString GetStandardErrorBoxText()
+{
+ return VclResId(SV_MSGBOX_ERROR);
+}
+
+Image const & GetStandardQueryBoxImage()
+{
+ ImplInitMsgBoxImageList();
+ return ImplGetSVData()->mpWinData->maMsgBoxImgList[1];
+}
+
+OUString GetStandardQueryBoxText()
+{
+ return VclResId(SV_MSGBOX_QUERY);
+}
+
+OUString GetStandardText(StandardButtonType eButton)
+{
+ static TranslateId aResIdAry[static_cast<int>(StandardButtonType::Count)] =
+ {
+ // http://lists.freedesktop.org/archives/libreoffice/2013-January/044513.html
+ // Under windows we don't want accelerators on ok/cancel but do on other
+ // buttons
+#ifdef _WIN32
+ SV_BUTTONTEXT_OK_NOMNEMONIC,
+ SV_BUTTONTEXT_CANCEL_NOMNEMONIC,
+#else
+ SV_BUTTONTEXT_OK,
+ SV_BUTTONTEXT_CANCEL,
+#endif
+ SV_BUTTONTEXT_YES,
+ SV_BUTTONTEXT_NO,
+ SV_BUTTONTEXT_RETRY,
+ SV_BUTTONTEXT_HELP,
+ SV_BUTTONTEXT_CLOSE,
+ SV_BUTTONTEXT_MORE,
+ SV_BUTTONTEXT_IGNORE,
+ SV_BUTTONTEXT_ABORT,
+ SV_BUTTONTEXT_LESS,
+ STR_WIZDLG_PREVIOUS,
+ STR_WIZDLG_NEXT,
+ STR_WIZDLG_FINISH,
+ };
+
+ return VclResId(aResIdAry[static_cast<sal_uInt16>(eButton)]);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/app/svapp.cxx b/vcl/source/app/svapp.cxx
new file mode 100644
index 0000000000..e1e12dbc3e
--- /dev/null
+++ b/vcl/source/app/svapp.cxx
@@ -0,0 +1,1786 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_features.h>
+#include <config_version.h>
+
+#include <osl/file.hxx>
+#include <osl/thread.hxx>
+#include <osl/module.hxx>
+#include <rtl/ustrbuf.hxx>
+
+#include <sal/log.hxx>
+
+#include <tools/debug.hxx>
+#include <tools/time.hxx>
+#include <tools/stream.hxx>
+#include <tools/json_writer.hxx>
+
+#include <unotools/configmgr.hxx>
+#include <unotools/resmgr.hxx>
+#include <unotools/syslocale.hxx>
+#include <unotools/syslocaleoptions.hxx>
+
+#include <vcl/toolkit/dialog.hxx>
+#include <vcl/dialoghelper.hxx>
+#include <vcl/lok.hxx>
+#include <vcl/toolkit/floatwin.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/keycod.hxx>
+#include <vcl/event.hxx>
+#include <vcl/vclevent.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/wrkwin.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/cvtgrf.hxx>
+#include <vcl/toolkit/unowrap.hxx>
+#include <vcl/timer.hxx>
+#include <vcl/scheduler.hxx>
+#include <vcl/skia/SkiaHelper.hxx>
+
+#include <salinst.hxx>
+#include <graphic/Manager.hxx>
+#include <salframe.hxx>
+#include <salsys.hxx>
+#include <svdata.hxx>
+#include <displayconnectiondispatch.hxx>
+#include <window.h>
+#include <accmgr.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+#if OSL_DEBUG_LEVEL > 0
+#include <schedulerimpl.hxx>
+#endif
+
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/awt/XToolkit.hpp>
+#include <comphelper/lok.hxx>
+#include <comphelper/threadpool.hxx>
+#include <comphelper/solarmutex.hxx>
+#include <osl/process.h>
+
+#ifdef DBG_UTIL
+#include <svl/poolitem.hxx>
+#include <svl/itemset.hxx>
+#include <svl/itempool.hxx>
+#endif
+
+#include <cassert>
+#include <limits>
+#include <string_view>
+#include <utility>
+#include <thread>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace {
+void InitSettings(ImplSVData* pSVData);
+}
+
+// keycodes handled internally by VCL
+vcl::KeyCode const ReservedKeys[]
+{
+ vcl::KeyCode(KEY_F1,0) ,
+ vcl::KeyCode(KEY_F1,KEY_SHIFT) ,
+ vcl::KeyCode(KEY_F1,KEY_MOD1) ,
+ vcl::KeyCode(KEY_F2,KEY_SHIFT) ,
+ vcl::KeyCode(KEY_F4,KEY_MOD1) ,
+ vcl::KeyCode(KEY_F4,KEY_MOD2) ,
+ vcl::KeyCode(KEY_F4,KEY_MOD1|KEY_MOD2) ,
+ vcl::KeyCode(KEY_F6,0) ,
+ vcl::KeyCode(KEY_F6,KEY_MOD1) ,
+ vcl::KeyCode(KEY_F6,KEY_SHIFT) ,
+ vcl::KeyCode(KEY_F6,KEY_MOD1|KEY_SHIFT) ,
+ vcl::KeyCode(KEY_F10,0)
+#ifdef UNX
+ ,
+ vcl::KeyCode(KEY_1,KEY_SHIFT|KEY_MOD1),
+ vcl::KeyCode(KEY_2,KEY_SHIFT|KEY_MOD1),
+ vcl::KeyCode(KEY_3,KEY_SHIFT|KEY_MOD1),
+ vcl::KeyCode(KEY_4,KEY_SHIFT|KEY_MOD1),
+ vcl::KeyCode(KEY_5,KEY_SHIFT|KEY_MOD1),
+ vcl::KeyCode(KEY_6,KEY_SHIFT|KEY_MOD1),
+ vcl::KeyCode(KEY_7,KEY_SHIFT|KEY_MOD1),
+ vcl::KeyCode(KEY_8,KEY_SHIFT|KEY_MOD1),
+ vcl::KeyCode(KEY_9,KEY_SHIFT|KEY_MOD1),
+ vcl::KeyCode(KEY_0,KEY_SHIFT|KEY_MOD1),
+ vcl::KeyCode(KEY_ADD,KEY_SHIFT|KEY_MOD1)
+#endif
+};
+
+extern "C" {
+ typedef UnoWrapperBase* (*FN_TkCreateUnoWrapper)();
+}
+
+struct ImplPostEventData
+{
+ VclPtr<vcl::Window> mpWin;
+ ImplSVEvent * mnEventId;
+ MouseEvent maMouseEvent;
+ VclEventId mnEvent;
+ KeyEvent maKeyEvent;
+ GestureEventPan maGestureEvent;
+
+ ImplPostEventData(VclEventId nEvent, vcl::Window* pWin, const KeyEvent& rKeyEvent)
+ : mpWin(pWin)
+ , mnEventId(nullptr)
+ , mnEvent(nEvent)
+ , maKeyEvent(rKeyEvent)
+ {}
+ ImplPostEventData(VclEventId nEvent, vcl::Window* pWin, const MouseEvent& rMouseEvent)
+ : mpWin(pWin)
+ , mnEventId(nullptr)
+ , maMouseEvent(rMouseEvent)
+ , mnEvent(nEvent)
+ {}
+ ImplPostEventData(VclEventId nEvent, vcl::Window* pWin, const GestureEventPan& rGestureEvent)
+ : mpWin(pWin)
+ , mnEventId(nullptr)
+ , mnEvent(nEvent)
+ , maGestureEvent(rGestureEvent)
+ {}
+};
+
+Application* GetpApp()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( !pSVData )
+ return nullptr;
+ return pSVData->mpApp;
+}
+
+Application::Application()
+{
+ // useful for themes at least, perhaps extensions too
+ OUString aVar("LIBO_VERSION"), aValue(LIBO_VERSION_DOTTED);
+ osl_setEnvironment(aVar.pData, aValue.pData);
+
+ ImplGetSVData()->mpApp = this;
+ m_pCallbackData = nullptr;
+ m_pCallback = nullptr;
+}
+
+Application::~Application()
+{
+ ImplDeInitSVData();
+ ImplGetSVData()->mpApp = nullptr;
+#ifdef DBG_UTIL
+ // Due to
+ // svx/source/dialog/framelinkarray.cxx
+ // class Cell final : public SfxPoolItem
+ // const Cell OBJ_CELL_NONE;
+ // being a static held SfxPoolItem which is not yet de-initialized here
+ // number often is (1), even higher with other modules loaded (like 5).
+ // These get de-allocated reliably in module-deinitializations, so this
+ // is no memory loss. These counters are more to be able to have an eye
+ // on amounts of SfxPoolItems used during office usage and to be able to
+ // detect if an error in future changes may lead to memory losses - these
+ // would show in dramatically higher numbers then immediately
+ SAL_INFO("vcl.items", "ITEM: " << getAllocatedSfxPoolItemCount() << " SfxPoolItems still allocated at shutdown");
+ SAL_INFO("vcl.items", "ITEM: " << getUsedSfxPoolItemCount() << " SfxPoolItems were incarnated during runtime");
+
+ // Same mechanism for SfxItemSet(s)
+ SAL_INFO("vcl.items", "ITEM: " << getAllocatedSfxItemSetCount() << " SfxItemSets still allocated at shutdown");
+ SAL_INFO("vcl.items", "ITEM: " << getUsedSfxItemSetCount() << " SfxItemSets were incarnated during runtime");
+
+ // Same mechanism for PoolItemHolder(s)
+ SAL_INFO("vcl.items", "ITEM: " << getAllocatedSfxPoolItemHolderCount() << " SfxPoolItemHolders still allocated at shutdown");
+ SAL_INFO("vcl.items", "ITEM: " << getUsedSfxPoolItemHolderCount() << " SfxPoolItemHolders were incarnated during runtime");
+
+ // Same mechanism for SfxPoolItem(s)directly put to a Pool
+ SAL_INFO("vcl.items", "ITEM: " << getRemainingDirectlyPooledSfxPoolItemCount() << " SfxPoolItems still directly put in Pool at shutdown (deleted @Pool destruction)");
+ SAL_INFO("vcl.items", "ITEM: " << getAllDirectlyPooledSfxPoolItemCount() << " SfxPoolItems directly put in Pool");
+
+ // Additional call to list still incarnated SfxPoolItems (under 'svl.items')
+ listAllocatedSfxPoolItems();
+
+#endif
+}
+
+int Application::Main()
+{
+ SAL_WARN("vcl", "Application is a base class and should be overridden.");
+ return EXIT_SUCCESS;
+}
+
+bool Application::QueryExit()
+{
+ WorkWindow* pAppWin = ImplGetSVData()->maFrameData.mpAppWin;
+
+ // call the close handler of the application window
+ if ( pAppWin )
+ return pAppWin->Close();
+ else
+ return true;
+}
+
+void Application::Shutdown()
+{
+}
+
+void Application::Init()
+{
+}
+
+void Application::InitFinished()
+{
+}
+
+void Application::DeInit()
+{
+}
+
+sal_uInt16 Application::GetCommandLineParamCount()
+{
+ return static_cast<sal_uInt16>(osl_getCommandArgCount());
+}
+
+OUString Application::GetCommandLineParam( sal_uInt16 nParam )
+{
+ OUString aParam;
+ osl_getCommandArg( nParam, &aParam.pData );
+ return aParam;
+}
+
+OUString Application::GetAppFileName()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ SAL_WARN_IF( !pSVData->maAppData.mxAppFileName, "vcl", "AppFileName should be set to something after SVMain!" );
+ if ( pSVData->maAppData.mxAppFileName )
+ return *pSVData->maAppData.mxAppFileName;
+
+ /*
+ * provide a fallback for people without initialized vcl here (like setup
+ * in responsefile mode)
+ */
+ OUString aAppFileName;
+ OUString aExeFileName;
+ osl_getExecutableFile(&aExeFileName.pData);
+
+ // convert path to native file format
+ osl::FileBase::getSystemPathFromFileURL(aExeFileName, aAppFileName);
+
+ return aAppFileName;
+}
+
+void Application::Exception( ExceptionCategory nCategory )
+{
+ switch ( nCategory )
+ {
+ // System has precedence (so do nothing)
+ case ExceptionCategory::System:
+ case ExceptionCategory::UserInterface:
+ break;
+ default:
+ Abort("Unknown Error");
+ break;
+ }
+}
+
+void Application::Abort( const OUString& rErrorText )
+{
+ //HACK: Dump core iff --norestore command line argument is given (assuming
+ // this process is run by developers who are interested in cores, vs. end
+ // users who are not):
+#if OSL_DEBUG_LEVEL > 0
+ bool dumpCore = true;
+#else
+ bool dumpCore = false;
+ sal_uInt16 n = GetCommandLineParamCount();
+ for (sal_uInt16 i = 0; i != n; ++i) {
+ if (GetCommandLineParam(i) == "--norestore") {
+ dumpCore = true;
+ break;
+ }
+ }
+#endif
+
+ SalAbort( rErrorText, dumpCore );
+}
+
+size_t Application::GetReservedKeyCodeCount()
+{
+ return SAL_N_ELEMENTS(ReservedKeys);
+}
+
+const vcl::KeyCode* Application::GetReservedKeyCode( size_t i )
+{
+ if( i >= GetReservedKeyCodeCount() )
+ return nullptr;
+ else
+ return &ReservedKeys[i];
+}
+
+void Application::notifyWindow(vcl::LOKWindowId /*nLOKWindowId*/,
+ const OUString& /*rAction*/,
+ const std::vector<vcl::LOKPayloadItem>& /*rPayload = std::vector<LOKPayloadItem>()*/) const
+{
+ SAL_WARN("vcl", "Invoked not implemented method: Application::notifyWindow");
+}
+
+void Application::libreOfficeKitViewCallback(int nType, const OString& pPayload) const
+{
+ if (!comphelper::LibreOfficeKit::isActive())
+ return;
+
+ if (m_pCallback)
+ {
+ m_pCallback(nType, pPayload.getStr(), m_pCallbackData);
+ }
+}
+
+void Application::notifyInvalidation(tools::Rectangle const* /*pRect*/) const
+{
+}
+
+void Application::Execute()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ pSVData->maAppData.mbInAppExecute = true;
+ pSVData->maAppData.mbAppQuit = false;
+
+ int nExitCode = 0;
+ if (!pSVData->mpDefInst->DoExecute(nExitCode))
+ {
+ if (Application::IsOnSystemEventLoop())
+ {
+ SAL_WARN("vcl.schedule", "Can't omit DoExecute when running on system event loop!");
+ std::abort();
+ }
+ while (!pSVData->maAppData.mbAppQuit)
+ Application::Yield();
+ }
+
+ pSVData->maAppData.mbInAppExecute = false;
+
+ GetpApp()->Shutdown();
+}
+
+static bool ImplYield(bool i_bWait, bool i_bAllEvents)
+{
+ ImplSVData* pSVData = ImplGetSVData();
+
+ SAL_INFO("vcl.schedule", "Enter ImplYield: " << (i_bWait ? "wait" : "no wait") <<
+ ": " << (i_bAllEvents ? "all events" : "one event"));
+
+ // there's a data race here on WNT only because ImplYield may be
+ // called without SolarMutex; but the only remaining use of mnDispatchLevel
+ // is in OSX specific code
+ pSVData->maAppData.mnDispatchLevel++;
+
+ // do not wait for events if application was already quit; in that
+ // case only dispatch events already available
+ bool bProcessedEvent = pSVData->mpDefInst->DoYield(
+ i_bWait && !pSVData->maAppData.mbAppQuit, i_bAllEvents );
+
+ pSVData->maAppData.mnDispatchLevel--;
+
+ DBG_TESTSOLARMUTEX(); // must be locked on return from Yield
+
+ SAL_INFO("vcl.schedule", "Leave ImplYield with return " << bProcessedEvent );
+ return bProcessedEvent;
+}
+
+bool Application::Reschedule( bool i_bAllEvents )
+{
+ static const bool bAbort = Application::IsOnSystemEventLoop();
+ if (bAbort)
+ {
+ SAL_WARN("vcl.schedule", "Application::Reschedule(" << i_bAllEvents << ")");
+ std::abort();
+ }
+ return ImplYield(false, i_bAllEvents);
+}
+
+bool Application::IsOnSystemEventLoop()
+{
+ return ImplGetSVData()->maAppData.m_bUseSystemLoop;
+}
+
+void Scheduler::ProcessEventsToIdle()
+{
+ int nSanity = 1;
+ while (ImplYield(false, true))
+ {
+ if (0 == ++nSanity % 1000)
+ {
+ SAL_WARN("vcl.schedule", "ProcessEventsToIdle: " << nSanity);
+ }
+ }
+#if OSL_DEBUG_LEVEL > 0
+ // If we yield from a non-main thread we just can guarantee that all idle
+ // events were processed at some point, but our check can't prevent further
+ // processing in the main thread, which may add new events, so skip it.
+ const ImplSVData* pSVData = ImplGetSVData();
+ if ( !pSVData->mpDefInst->IsMainThread() )
+ return;
+ for (int nTaskPriority = 0; nTaskPriority < PRIO_COUNT; ++nTaskPriority)
+ {
+ const ImplSchedulerData* pSchedulerData = pSVData->maSchedCtx.mpFirstSchedulerData[nTaskPriority];
+ while (pSchedulerData)
+ {
+ assert(!pSchedulerData->mbInScheduler);
+ if (pSchedulerData->mpTask)
+ {
+ Idle *pIdle = dynamic_cast<Idle*>(pSchedulerData->mpTask);
+ if (pIdle && pIdle->IsActive())
+ {
+ SAL_WARN("vcl.schedule",
+ "Unprocessed Idle: "
+ << pIdle << " "
+ << (pIdle->GetDebugName() ? pIdle->GetDebugName() : "(nullptr)"));
+ }
+ }
+ pSchedulerData = pSchedulerData->mpNext;
+ }
+ }
+#endif
+}
+
+extern "C" {
+/// used by unit tests that test only via the LOK API
+SAL_DLLPUBLIC_EXPORT void unit_lok_process_events_to_idle()
+{
+ const SolarMutexGuard aGuard;
+ Scheduler::ProcessEventsToIdle();
+}
+}
+
+void Application::Yield()
+{
+ static const bool bAbort = Application::IsOnSystemEventLoop();
+ if (bAbort)
+ {
+ SAL_WARN("vcl.schedule", "Application::Yield()");
+ std::abort();
+ }
+ ImplYield(true, false);
+}
+
+IMPL_STATIC_LINK_NOARG( ImplSVAppData, ImplQuitMsg, void*, void )
+{
+ assert(ImplGetSVData()->maAppData.mbAppQuit);
+ ImplGetSVData()->mpDefInst->DoQuit();
+}
+
+void Application::Quit()
+{
+ ImplGetSVData()->maAppData.mbAppQuit = true;
+ Application::PostUserEvent( LINK( nullptr, ImplSVAppData, ImplQuitMsg ) );
+}
+
+comphelper::SolarMutex& Application::GetSolarMutex()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ return *(pSVData->mpDefInst->GetYieldMutex());
+}
+
+bool Application::IsMainThread()
+{
+ return ImplGetSVData()->mnMainThreadId == osl::Thread::getCurrentIdentifier();
+}
+
+sal_uInt32 Application::ReleaseSolarMutex()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ return pSVData->mpDefInst->ReleaseYieldMutexAll();
+}
+
+void Application::AcquireSolarMutex( sal_uInt32 nCount )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ pSVData->mpDefInst->AcquireYieldMutex( nCount );
+}
+
+bool Application::IsInMain()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ return pSVData && pSVData->maAppData.mbInAppMain;
+}
+
+bool Application::IsInExecute()
+{
+ return ImplGetSVData()->maAppData.mbInAppExecute;
+}
+
+bool Application::IsQuit()
+{
+ return ImplGetSVData()->maAppData.mbAppQuit;
+}
+
+bool Application::IsInModalMode()
+{
+ return (ImplGetSVData()->maAppData.mnModalMode != 0);
+}
+
+sal_uInt16 Application::GetDispatchLevel()
+{
+ return ImplGetSVData()->maAppData.mnDispatchLevel;
+}
+
+bool Application::AnyInput( VclInputFlags nType )
+{
+ return ImplGetSVData()->mpDefInst->AnyInput( nType );
+}
+
+sal_uInt64 Application::GetLastInputInterval()
+{
+ return (tools::Time::GetSystemTicks()-ImplGetSVData()->maAppData.mnLastInputTime);
+}
+
+bool Application::IsUICaptured()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+
+ // If mouse was captured, or if in tracking- or in select-mode of a floatingwindow (e.g. menus
+ // or pulldown toolboxes) another window should be created
+ // D&D active !!!
+ return pSVData->mpWinData->mpCaptureWin || pSVData->mpWinData->mpTrackWin
+ || pSVData->mpWinData->mpFirstFloat || nImplSysDialog;
+}
+
+void Application::OverrideSystemSettings( AllSettings& /*rSettings*/ )
+{
+}
+
+void Application::MergeSystemSettings( AllSettings& rSettings )
+{
+ vcl::Window* pWindow = ImplGetSVData()->maFrameData.mpFirstFrame;
+ if( ! pWindow )
+ pWindow = ImplGetDefaultWindow();
+ if( pWindow )
+ {
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( !pSVData->maAppData.mbSettingsInit )
+ {
+ // side effect: ImplUpdateGlobalSettings does an ImplGetFrame()->UpdateSettings
+ pWindow->ImplUpdateGlobalSettings( *pSVData->maAppData.mxSettings );
+ pSVData->maAppData.mbSettingsInit = true;
+ }
+ // side effect: ImplUpdateGlobalSettings does an ImplGetFrame()->UpdateSettings
+ pWindow->ImplUpdateGlobalSettings( rSettings, false );
+ }
+}
+
+void Application::SetSettings( const AllSettings& rSettings )
+{
+ const SolarMutexGuard aGuard;
+
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( !pSVData->maAppData.mxSettings )
+ {
+ InitSettings(pSVData);
+ *pSVData->maAppData.mxSettings = rSettings;
+ }
+ else
+ {
+ AllSettings aOldSettings = *pSVData->maAppData.mxSettings;
+ if (aOldSettings.GetUILanguageTag().getLanguageType() != rSettings.GetUILanguageTag().getLanguageType() &&
+ pSVData->mbResLocaleSet)
+ {
+ pSVData->mbResLocaleSet = false;
+ }
+ *pSVData->maAppData.mxSettings = rSettings;
+ AllSettingsFlags nChangeFlags = aOldSettings.GetChangeFlags( *pSVData->maAppData.mxSettings );
+ if ( bool(nChangeFlags) )
+ {
+ DataChangedEvent aDCEvt( DataChangedEventType::SETTINGS, &aOldSettings, nChangeFlags );
+
+ // notify data change handler
+ ImplCallEventListenersApplicationDataChanged( &aDCEvt);
+
+ // Update all windows
+ vcl::Window* pFirstFrame = pSVData->maFrameData.mpFirstFrame;
+ // Reset data that needs to be re-calculated
+ tools::Long nOldDPIX = 0;
+ tools::Long nOldDPIY = 0;
+ if ( pFirstFrame )
+ {
+ nOldDPIX = pFirstFrame->GetOutDev()->GetDPIX();
+ nOldDPIY = pFirstFrame->GetOutDev()->GetDPIY();
+ vcl::Window::ImplInitAppFontData(pFirstFrame);
+ }
+ vcl::Window* pFrame = pFirstFrame;
+ while ( pFrame )
+ {
+ // call UpdateSettings from ClientWindow in order to prevent updating data twice
+ vcl::Window* pClientWin = pFrame;
+ while ( pClientWin->ImplGetClientWindow() )
+ pClientWin = pClientWin->ImplGetClientWindow();
+ pClientWin->UpdateSettings( rSettings, true );
+
+ vcl::Window* pTempWin = pFrame->mpWindowImpl->mpFrameData->mpFirstOverlap;
+ while ( pTempWin )
+ {
+ // call UpdateSettings from ClientWindow in order to prevent updating data twice
+ pClientWin = pTempWin;
+ while ( pClientWin->ImplGetClientWindow() )
+ pClientWin = pClientWin->ImplGetClientWindow();
+ pClientWin->UpdateSettings( rSettings, true );
+ pTempWin = pTempWin->mpWindowImpl->mpNextOverlap;
+ }
+
+ pFrame = pFrame->mpWindowImpl->mpFrameData->mpNextFrame;
+ }
+
+ // if DPI resolution for screen output was changed set the new resolution for all
+ // screen compatible VirDev's
+ pFirstFrame = pSVData->maFrameData.mpFirstFrame;
+ if ( pFirstFrame )
+ {
+ if ( (pFirstFrame->GetOutDev()->GetDPIX() != nOldDPIX) ||
+ (pFirstFrame->GetOutDev()->GetDPIY() != nOldDPIY) )
+ {
+ VirtualDevice* pVirDev = pSVData->maGDIData.mpFirstVirDev;
+ while ( pVirDev )
+ {
+ if ( pVirDev->mbScreenComp &&
+ (pVirDev->GetDPIX() == nOldDPIX) &&
+ (pVirDev->GetDPIY() == nOldDPIY) )
+ {
+ pVirDev->SetDPIX( pFirstFrame->GetOutDev()->GetDPIX() );
+ pVirDev->SetDPIY( pFirstFrame->GetOutDev()->GetDPIY() );
+ if ( pVirDev->IsMapModeEnabled() )
+ {
+ MapMode aMapMode = pVirDev->GetMapMode();
+ pVirDev->SetMapMode();
+ pVirDev->SetMapMode( aMapMode );
+ }
+ }
+
+ pVirDev = pVirDev->mpNext;
+ }
+ }
+ }
+ }
+ }
+}
+
+const AllSettings& Application::GetSettings()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( !pSVData->maAppData.mxSettings )
+ {
+ InitSettings(pSVData);
+ }
+
+ return *(pSVData->maAppData.mxSettings);
+}
+
+namespace {
+
+void InitSettings(ImplSVData* pSVData)
+{
+ assert(!pSVData->maAppData.mxSettings && "initialization should not happen twice!");
+
+ pSVData->maAppData.mxSettings.emplace();
+ if (!utl::ConfigManager::IsFuzzing())
+ {
+ pSVData->maAppData.mpCfgListener = new LocaleConfigurationListener;
+ pSVData->maAppData.mxSettings->GetSysLocale().GetOptions().AddListener( pSVData->maAppData.mpCfgListener );
+ }
+}
+
+}
+
+void Application::NotifyAllWindows( DataChangedEvent& rDCEvt )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ vcl::Window* pFrame = pSVData->maFrameData.mpFirstFrame;
+ while ( pFrame )
+ {
+ pFrame->NotifyAllChildren( rDCEvt );
+
+ vcl::Window* pSysWin = pFrame->mpWindowImpl->mpFrameData->mpFirstOverlap;
+ while ( pSysWin )
+ {
+ pSysWin->NotifyAllChildren( rDCEvt );
+ pSysWin = pSysWin->mpWindowImpl->mpNextOverlap;
+ }
+
+ pFrame = pFrame->mpWindowImpl->mpFrameData->mpNextFrame;
+ }
+}
+
+void Application::ImplCallEventListenersApplicationDataChanged( void* pData )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ VclWindowEvent aEvent( nullptr, VclEventId::ApplicationDataChanged, pData );
+
+ pSVData->maAppData.maEventListeners.Call( aEvent );
+}
+
+void Application::ImplCallEventListeners( VclSimpleEvent& rEvent )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ pSVData->maAppData.maEventListeners.Call( rEvent );
+}
+
+void Application::AddEventListener( const Link<VclSimpleEvent&,void>& rEventListener )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ pSVData->maAppData.maEventListeners.addListener( rEventListener );
+}
+
+void Application::RemoveEventListener( const Link<VclSimpleEvent&,void>& rEventListener )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ pSVData->maAppData.maEventListeners.removeListener( rEventListener );
+}
+
+void Application::AddKeyListener( const Link<VclWindowEvent&,bool>& rKeyListener )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ pSVData->maAppData.maKeyListeners.push_back( rKeyListener );
+}
+
+void Application::RemoveKeyListener( const Link<VclWindowEvent&,bool>& rKeyListener )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ auto & rVec = pSVData->maAppData.maKeyListeners;
+ std::erase(rVec, rKeyListener);
+}
+
+bool Application::HandleKey( VclEventId nEvent, vcl::Window *pWin, KeyEvent* pKeyEvent )
+{
+ // let listeners process the key event
+ VclWindowEvent aEvent( pWin, nEvent, static_cast<void *>(pKeyEvent) );
+
+ ImplSVData* pSVData = ImplGetSVData();
+
+ if ( pSVData->maAppData.maKeyListeners.empty() )
+ return false;
+
+ bool bProcessed = false;
+ // Copy the list, because this can be destroyed when calling a Link...
+ std::vector<Link<VclWindowEvent&,bool>> aCopy( pSVData->maAppData.maKeyListeners );
+ for ( const Link<VclWindowEvent&,bool>& rLink : aCopy )
+ {
+ if( rLink.Call( aEvent ) )
+ {
+ bProcessed = true;
+ break;
+ }
+ }
+ return bProcessed;
+}
+
+ImplSVEvent * Application::PostKeyEvent( VclEventId nEvent, vcl::Window *pWin, KeyEvent const * pKeyEvent )
+{
+ const SolarMutexGuard aGuard;
+ ImplSVEvent * nEventId = nullptr;
+
+ if( pWin && pKeyEvent )
+ {
+ std::unique_ptr<ImplPostEventData> pPostEventData(new ImplPostEventData( nEvent, pWin, *pKeyEvent ));
+
+ nEventId = PostUserEvent(
+ LINK( nullptr, Application, PostEventHandler ),
+ pPostEventData.get() );
+
+ if( nEventId )
+ {
+ pPostEventData->mnEventId = nEventId;
+ ImplGetSVData()->maAppData.maPostedEventList.emplace_back( pWin, pPostEventData.release() );
+ }
+ }
+
+ return nEventId;
+}
+
+ImplSVEvent* Application::PostGestureEvent(VclEventId nEvent, vcl::Window* pWin,
+ GestureEventPan const * pGestureEvent)
+{
+ const SolarMutexGuard aGuard;
+ ImplSVEvent * nEventId = nullptr;
+
+ if (pWin && pGestureEvent)
+ {
+ Point aTransformedPosition(pGestureEvent->mnX, pGestureEvent->mnY);
+
+ aTransformedPosition.AdjustX(pWin->GetOutOffXPixel());
+ aTransformedPosition.AdjustY(pWin->GetOutOffYPixel());
+
+ const GestureEventPan aGestureEvent(
+ sal_Int32(aTransformedPosition.X()),
+ sal_Int32(aTransformedPosition.Y()),
+ pGestureEvent->meEventType,
+ pGestureEvent->mnOffset,
+ pGestureEvent->meOrientation
+ );
+
+ std::unique_ptr<ImplPostEventData> pPostEventData(new ImplPostEventData(nEvent, pWin, aGestureEvent));
+
+ nEventId = PostUserEvent(
+ LINK( nullptr, Application, PostEventHandler ),
+ pPostEventData.get());
+
+ if (nEventId)
+ {
+ pPostEventData->mnEventId = nEventId;
+ ImplGetSVData()->maAppData.maPostedEventList.emplace_back(pWin, pPostEventData.release());
+ }
+ }
+
+ return nEventId;
+}
+
+bool Application::LOKHandleMouseEvent(VclEventId nEvent, vcl::Window* pWindow, const MouseEvent* pEvent)
+{
+ bool bSuccess = false;
+ SalMouseEvent aMouseEvent;
+
+ if (!pWindow)
+ return false;
+
+ if (!pEvent)
+ return false;
+
+ aMouseEvent.mnTime = tools::Time::GetSystemTicks();
+ aMouseEvent.mnX = pEvent->GetPosPixel().X();
+ aMouseEvent.mnY = pEvent->GetPosPixel().Y();
+ aMouseEvent.mnCode = pEvent->GetButtons() | pEvent->GetModifier();
+
+ switch (nEvent)
+ {
+ case VclEventId::WindowMouseMove:
+ aMouseEvent.mnButton = 0;
+ bSuccess = ImplLOKHandleMouseEvent(pWindow, NotifyEventType::MOUSEMOVE, false,
+ aMouseEvent.mnX, aMouseEvent.mnY,
+ aMouseEvent.mnTime, aMouseEvent.mnCode,
+ ImplGetMouseMoveMode(&aMouseEvent),
+ pEvent->GetClicks());
+ break;
+
+ case VclEventId::WindowMouseButtonDown:
+ aMouseEvent.mnButton = pEvent->GetButtons();
+ bSuccess = ImplLOKHandleMouseEvent(pWindow, NotifyEventType::MOUSEBUTTONDOWN, false,
+ aMouseEvent.mnX, aMouseEvent.mnY,
+ aMouseEvent.mnTime,
+#ifdef MACOSX
+ aMouseEvent.mnButton |
+ (aMouseEvent.mnCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2 | KEY_MOD3)),
+#else
+ aMouseEvent.mnButton |
+ (aMouseEvent.mnCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2)),
+#endif
+ ImplGetMouseButtonMode(&aMouseEvent),
+ pEvent->GetClicks());
+ break;
+
+ case VclEventId::WindowMouseButtonUp:
+ aMouseEvent.mnButton = pEvent->GetButtons();
+ bSuccess = ImplLOKHandleMouseEvent(pWindow, NotifyEventType::MOUSEBUTTONUP, false,
+ aMouseEvent.mnX, aMouseEvent.mnY,
+ aMouseEvent.mnTime,
+#ifdef MACOSX
+ aMouseEvent.mnButton |
+ (aMouseEvent.mnCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2 | KEY_MOD3)),
+#else
+ aMouseEvent.mnButton |
+ (aMouseEvent.mnCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2)),
+#endif
+ ImplGetMouseButtonMode(&aMouseEvent),
+ pEvent->GetClicks());
+ break;
+
+ default:
+ SAL_WARN( "vcl.layout", "Application::HandleMouseEvent unknown event (" << static_cast<int>(nEvent) << ")" );
+ break;
+ }
+
+ return bSuccess;
+}
+
+
+ImplSVEvent* Application::PostMouseEvent( VclEventId nEvent, vcl::Window *pWin, MouseEvent const * pMouseEvent )
+{
+ const SolarMutexGuard aGuard;
+ ImplSVEvent * nEventId = nullptr;
+
+ if( pWin && pMouseEvent )
+ {
+ Point aTransformedPos( pMouseEvent->GetPosPixel() );
+
+ // LOK uses (0, 0) as the origin of all windows; don't offset.
+ if (!comphelper::LibreOfficeKit::isActive())
+ {
+ aTransformedPos.AdjustX(pWin->GetOutOffXPixel());
+ aTransformedPos.AdjustY(pWin->GetOutOffYPixel());
+ }
+
+ const MouseEvent aTransformedEvent( aTransformedPos, pMouseEvent->GetClicks(), pMouseEvent->GetMode(),
+ pMouseEvent->GetButtons(), pMouseEvent->GetModifier() );
+
+ std::unique_ptr<ImplPostEventData> pPostEventData(new ImplPostEventData( nEvent, pWin, aTransformedEvent ));
+
+ nEventId = PostUserEvent(
+ LINK( nullptr, Application, PostEventHandler ),
+ pPostEventData.get() );
+
+ if( nEventId )
+ {
+ pPostEventData->mnEventId = nEventId;
+ ImplGetSVData()->maAppData.maPostedEventList.emplace_back( pWin, pPostEventData.release() );
+ }
+ }
+
+ return nEventId;
+}
+
+
+IMPL_STATIC_LINK( Application, PostEventHandler, void*, pCallData, void )
+{
+ const SolarMutexGuard aGuard;
+ ImplPostEventData* pData = static_cast< ImplPostEventData * >( pCallData );
+ const void* pEventData;
+ SalEvent nEvent;
+ ImplSVEvent * const nEventId = pData->mnEventId;
+
+ switch( pData->mnEvent )
+ {
+ case VclEventId::WindowMouseMove:
+ nEvent = SalEvent::ExternalMouseMove;
+ pEventData = &pData->maMouseEvent;
+ break;
+
+ case VclEventId::WindowMouseButtonDown:
+ nEvent = SalEvent::ExternalMouseButtonDown;
+ pEventData = &pData->maMouseEvent;
+ break;
+
+ case VclEventId::WindowMouseButtonUp:
+ nEvent = SalEvent::ExternalMouseButtonUp;
+ pEventData = &pData->maMouseEvent;
+ break;
+
+ case VclEventId::WindowKeyInput:
+ nEvent = SalEvent::ExternalKeyInput;
+ pEventData = &pData->maKeyEvent;
+ break;
+
+ case VclEventId::WindowKeyUp:
+ nEvent = SalEvent::ExternalKeyUp;
+ pEventData = &pData->maKeyEvent;
+ break;
+
+ case VclEventId::WindowGestureEvent:
+ nEvent = SalEvent::ExternalGesture;
+ pEventData = &pData->maGestureEvent;
+ break;
+
+ default:
+ nEvent = SalEvent::NONE;
+ pEventData = nullptr;
+ break;
+ }
+
+ if( pData->mpWin && pData->mpWin->mpWindowImpl->mpFrameWindow && pEventData )
+ ImplWindowFrameProc( pData->mpWin->mpWindowImpl->mpFrameWindow.get(), nEvent, pEventData );
+
+ // remove this event from list of posted events, watch for destruction of internal data
+ auto svdata = ImplGetSVData();
+ ::std::vector< ImplPostEventPair >::iterator aIter( svdata->maAppData.maPostedEventList.begin() );
+
+ while( aIter != svdata->maAppData.maPostedEventList.end() )
+ {
+ if( nEventId == (*aIter).second->mnEventId )
+ {
+ delete (*aIter).second;
+ aIter = svdata->maAppData.maPostedEventList.erase( aIter );
+ }
+ else
+ ++aIter;
+ }
+}
+
+void Application::RemoveMouseAndKeyEvents( vcl::Window* pWin )
+{
+ const SolarMutexGuard aGuard;
+
+ // remove all events for specific window, watch for destruction of internal data
+ auto svdata = ImplGetSVData();
+ ::std::vector< ImplPostEventPair >::iterator aIter( svdata->maAppData.maPostedEventList.begin() );
+
+ while( aIter != svdata->maAppData.maPostedEventList.end() )
+ {
+ if( pWin == (*aIter).first )
+ {
+ if( (*aIter).second->mnEventId )
+ RemoveUserEvent( (*aIter).second->mnEventId );
+
+ delete (*aIter).second;
+ aIter = svdata->maAppData.maPostedEventList.erase( aIter );
+ }
+ else
+ ++aIter;
+ }
+}
+
+ImplSVEvent * Application::PostUserEvent( const Link<void*,void>& rLink, void* pCaller,
+ bool bReferenceLink )
+{
+ vcl::Window* pDefWindow = ImplGetDefaultWindow();
+ if ( pDefWindow == nullptr )
+ return nullptr;
+
+ std::unique_ptr<ImplSVEvent> pSVEvent(new ImplSVEvent);
+ pSVEvent->mpData = pCaller;
+ pSVEvent->maLink = rLink;
+ pSVEvent->mpWindow = nullptr;
+ pSVEvent->mbCall = true;
+ if (bReferenceLink)
+ {
+ SolarMutexGuard aGuard;
+ pSVEvent->mpInstanceRef = static_cast<vcl::Window *>(rLink.GetInstance());
+ }
+
+ auto pTmpEvent = pSVEvent.get();
+ if (!pDefWindow->ImplGetFrame()->PostEvent( std::move(pSVEvent) ))
+ return nullptr;
+ return pTmpEvent;
+}
+
+void Application::RemoveUserEvent( ImplSVEvent * nUserEvent )
+{
+ if(nUserEvent)
+ {
+ SAL_WARN_IF( nUserEvent->mpWindow, "vcl",
+ "Application::RemoveUserEvent(): Event is send to a window" );
+ SAL_WARN_IF( !nUserEvent->mbCall, "vcl",
+ "Application::RemoveUserEvent(): Event is already removed" );
+
+ nUserEvent->mpWindow.clear();
+ nUserEvent->mpInstanceRef.clear();
+ nUserEvent->mbCall = false;
+ }
+}
+
+vcl::Window* Application::GetFocusWindow()
+{
+ return ImplGetSVData()->mpWinData->mpFocusWin;
+}
+
+OutputDevice* Application::GetDefaultDevice()
+{
+ vcl::Window* pWindow = ImplGetDefaultWindow();
+ if (pWindow != nullptr)
+ {
+ return pWindow->GetOutDev();
+ }
+ else
+ {
+ return nullptr;
+ }
+}
+
+basegfx::SystemDependentDataManager& Application::GetSystemDependentDataManager()
+{
+ return ImplGetSystemDependentDataManager();
+}
+
+vcl::Window* Application::GetFirstTopLevelWindow()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ return pSVData->maFrameData.mpFirstFrame;
+}
+
+vcl::Window* Application::GetNextTopLevelWindow( vcl::Window const * pWindow )
+{
+ return pWindow->mpWindowImpl->mpFrameData->mpNextFrame;
+}
+
+tools::Long Application::GetTopWindowCount()
+{
+ tools::Long nRet = 0;
+ ImplSVData* pSVData = ImplGetSVData();
+ vcl::Window *pWin = pSVData ? pSVData->maFrameData.mpFirstFrame.get() : nullptr;
+ while( pWin )
+ {
+ if( pWin->ImplGetWindow()->IsTopWindow() )
+ nRet++;
+ pWin = pWin->mpWindowImpl->mpFrameData->mpNextFrame;
+ }
+ return nRet;
+}
+
+vcl::Window* Application::GetTopWindow( tools::Long nIndex )
+{
+ tools::Long nIdx = 0;
+ ImplSVData* pSVData = ImplGetSVData();
+ vcl::Window *pWin = pSVData ? pSVData->maFrameData.mpFirstFrame.get() : nullptr;
+ while( pWin )
+ {
+ if( pWin->ImplGetWindow()->IsTopWindow() )
+ {
+ if( nIdx == nIndex )
+ return pWin->ImplGetWindow();
+ else
+ nIdx++;
+ }
+ pWin = pWin->mpWindowImpl->mpFrameData->mpNextFrame;
+ }
+ return nullptr;
+}
+
+vcl::Window* Application::GetActiveTopWindow()
+{
+ vcl::Window *pWin = ImplGetSVData()->mpWinData->mpFocusWin;
+ while( pWin )
+ {
+ if( pWin->IsTopWindow() )
+ return pWin;
+ pWin = pWin->mpWindowImpl->mpParent;
+ }
+ return nullptr;
+}
+
+void Application::SetAppName( const OUString& rUniqueName )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ pSVData->maAppData.mxAppName = rUniqueName;
+}
+
+OUString Application::GetAppName()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( pSVData->maAppData.mxAppName )
+ return *(pSVData->maAppData.mxAppName);
+ else
+ return OUString();
+}
+
+enum {hwAll=0, hwEnv=1, hwUI=2};
+
+static OUString Localize(TranslateId aId, const bool bLocalize)
+{
+ if (bLocalize)
+ return VclResId(aId);
+ else
+ return Translate::get(aId, Translate::Create("vcl", LanguageTag("en-US")));
+}
+
+OUString Application::GetOSVersion()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ OUString aVersion;
+ if (pSVData && pSVData->mpDefInst)
+ aVersion = pSVData->mpDefInst->getOSVersion();
+ else
+ aVersion = "-";
+ return aVersion;
+}
+
+OUString Application::GetHWOSConfInfo(const int bSelection, const bool bLocalize)
+{
+ OUStringBuffer aDetails;
+
+ const auto appendDetails = [&aDetails](std::u16string_view sep, auto&& val) {
+ if (!aDetails.isEmpty() && !sep.empty())
+ aDetails.append(sep);
+ aDetails.append(std::move(val));
+ };
+
+ if (bSelection != hwUI) {
+ appendDetails(u"; ", Localize(SV_APP_CPUTHREADS, bLocalize)
+ + OUString::number(std::thread::hardware_concurrency()));
+
+ OUString aVersion = GetOSVersion();
+
+ appendDetails(u"; ", Localize(SV_APP_OSVERSION, bLocalize) + aVersion);
+ }
+
+ if (bSelection != hwEnv) {
+ appendDetails(u"; ", Localize(SV_APP_UIRENDER, bLocalize));
+#if HAVE_FEATURE_SKIA
+ if ( SkiaHelper::isVCLSkiaEnabled() )
+ {
+ switch(SkiaHelper::renderMethodToUse())
+ {
+ case SkiaHelper::RenderVulkan:
+ appendDetails(u"", Localize(SV_APP_SKIA_VULKAN, bLocalize));
+ break;
+ case SkiaHelper::RenderMetal:
+ appendDetails(u"", Localize(SV_APP_SKIA_METAL, bLocalize));
+ break;
+ case SkiaHelper::RenderRaster:
+ appendDetails(u"", Localize(SV_APP_SKIA_RASTER, bLocalize));
+ break;
+ }
+ }
+ else
+#endif
+ appendDetails(u"", Localize(SV_APP_DEFAULT, bLocalize));
+
+#if (defined LINUX || defined _WIN32 || defined MACOSX || defined __FreeBSD__ || defined EMSCRIPTEN)
+ appendDetails(u"; ", SV_APP_VCLBACKEND + GetToolkitName());
+#endif
+ }
+
+ return aDetails.makeStringAndClear();
+}
+
+void Application::SetDisplayName( const OUString& rName )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ pSVData->maAppData.mxDisplayName = rName;
+}
+
+OUString Application::GetDisplayName()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( pSVData->maAppData.mxDisplayName )
+ return *(pSVData->maAppData.mxDisplayName);
+ else if (pSVData->maFrameData.mpAppWin)
+ return pSVData->maFrameData.mpAppWin->GetText();
+ else
+ return OUString();
+}
+
+unsigned int Application::GetScreenCount()
+{
+ SalSystem* pSys = ImplGetSalSystem();
+ return pSys ? pSys->GetDisplayScreenCount() : 0;
+}
+
+unsigned int Application::GetDisplayBuiltInScreen()
+{
+ SalSystem* pSys = ImplGetSalSystem();
+ return pSys ? pSys->GetDisplayBuiltInScreen() : 0;
+}
+
+unsigned int Application::GetDisplayExternalScreen()
+{
+ // This is really unpleasant, in theory we could have multiple
+ // external displays etc.
+ int nExternal(0);
+ switch (GetDisplayBuiltInScreen())
+ {
+ case 0:
+ nExternal = 1;
+ break;
+ case 1:
+ nExternal = 0;
+ break;
+ default:
+ // When the built-in display is neither 0 nor 1
+ // then place the full-screen presentation on the
+ // first available screen.
+ nExternal = 0;
+ break;
+ }
+ return nExternal;
+}
+
+AbsoluteScreenPixelRectangle Application::GetScreenPosSizePixel( unsigned int nScreen )
+{
+ SalSystem* pSys = ImplGetSalSystem();
+ if (!pSys)
+ {
+ SAL_WARN("vcl", "Requesting screen size/pos for screen #" << nScreen << " failed");
+ assert(false);
+ return AbsoluteScreenPixelRectangle();
+ }
+ AbsoluteScreenPixelRectangle aRect = pSys->GetDisplayScreenPosSizePixel(nScreen);
+ if (aRect.GetHeight() == 0)
+ SAL_WARN("vcl", "Requesting screen size/pos for screen #" << nScreen << " returned 0 height.");
+ return aRect;
+}
+
+namespace {
+tools::Long calcDistSquare( const AbsoluteScreenPixelPoint& i_rPoint, const AbsoluteScreenPixelRectangle& i_rRect )
+{
+ const AbsoluteScreenPixelPoint aRectCenter( (i_rRect.Left() + i_rRect.Right())/2,
+ (i_rRect.Top() + i_rRect.Bottom())/ 2 );
+ const tools::Long nDX = aRectCenter.X() - i_rPoint.X();
+ const tools::Long nDY = aRectCenter.Y() - i_rPoint.Y();
+ return nDX*nDX + nDY*nDY;
+}
+}
+
+unsigned int Application::GetBestScreen( const AbsoluteScreenPixelRectangle& i_rRect )
+{
+ const unsigned int nScreens = GetScreenCount();
+ unsigned int nBestMatchScreen = 0;
+ unsigned long nOverlap = 0;
+ for( unsigned int i = 0; i < nScreens; i++ )
+ {
+ const AbsoluteScreenPixelRectangle aCurScreenRect( GetScreenPosSizePixel( i ) );
+ // if a screen contains the rectangle completely it is obviously the best screen
+ if( aCurScreenRect.Contains( i_rRect ) )
+ return i;
+ // next the screen which contains most of the area of the rect is the best
+ AbsoluteScreenPixelRectangle aIntersection( aCurScreenRect.GetIntersection( i_rRect ) );
+ if( ! aIntersection.IsEmpty() )
+ {
+ const unsigned long nCurOverlap( aIntersection.GetWidth() * aIntersection.GetHeight() );
+ if( nCurOverlap > nOverlap )
+ {
+ nOverlap = nCurOverlap;
+ nBestMatchScreen = i;
+ }
+ }
+ }
+ if( nOverlap > 0 )
+ return nBestMatchScreen;
+
+ // finally the screen which center is nearest to the rect is the best
+ const AbsoluteScreenPixelPoint aCenter( (i_rRect.Left() + i_rRect.Right())/2,
+ (i_rRect.Top() + i_rRect.Bottom())/2 );
+ tools::Long nDist = std::numeric_limits<tools::Long>::max();
+ for( unsigned int i = 0; i < nScreens; i++ )
+ {
+ const AbsoluteScreenPixelRectangle aCurScreenRect( GetScreenPosSizePixel( i ) );
+ const tools::Long nCurDist( calcDistSquare( aCenter, aCurScreenRect ) );
+ if( nCurDist < nDist )
+ {
+ nBestMatchScreen = i;
+ nDist = nCurDist;
+ }
+ }
+ return nBestMatchScreen;
+}
+
+bool Application::InsertAccel( Accelerator* pAccel )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+
+ if ( !pSVData->maAppData.mpAccelMgr )
+ pSVData->maAppData.mpAccelMgr = new ImplAccelManager();
+ return pSVData->maAppData.mpAccelMgr->InsertAccel( pAccel );
+}
+
+void Application::RemoveAccel( Accelerator const * pAccel )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+
+ if ( pSVData->maAppData.mpAccelMgr )
+ pSVData->maAppData.mpAccelMgr->RemoveAccel( pAccel );
+}
+
+void Application::SetHelp( Help* pHelp )
+{
+ ImplGetSVData()->maAppData.mpHelp = pHelp;
+}
+
+void Application::UpdateMainThread()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if (pSVData && pSVData->mpDefInst)
+ pSVData->mpDefInst->updateMainThread();
+}
+
+Help* Application::GetHelp()
+{
+ return ImplGetSVData()->maAppData.mpHelp;
+}
+
+OUString Application::GetToolkitName()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( pSVData->maAppData.mxToolkitName )
+ return *(pSVData->maAppData.mxToolkitName);
+ else
+ return OUString();
+}
+
+vcl::Window* Dialog::GetDefDialogParent()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ // find some useful dialog parent
+
+ // always use the topmost parent of the candidate
+ // window to avoid using dialogs or floaters
+ // as DefDialogParent
+
+ // current focus frame
+ vcl::Window *pWin = pSVData->mpWinData->mpFocusWin;
+ if (pWin && !pWin->IsMenuFloatingWindow())
+ {
+ while (pWin->mpWindowImpl && pWin->mpWindowImpl->mpParent)
+ pWin = pWin->mpWindowImpl->mpParent;
+
+ // check for corrupted window hierarchy, #122232#, may be we now crash somewhere else
+ if (!pWin->mpWindowImpl)
+ {
+ OSL_FAIL( "Window hierarchy corrupted!" );
+ pSVData->mpWinData->mpFocusWin = nullptr; // avoid further access
+ return nullptr;
+ }
+
+ if ((pWin->mpWindowImpl->mnStyle & WB_INTROWIN) == 0)
+ {
+ return pWin->mpWindowImpl->mpFrameWindow->ImplGetWindow();
+ }
+ }
+
+ // last active application frame
+ pWin = pSVData->maFrameData.mpActiveApplicationFrame;
+ if (pWin)
+ {
+ return pWin->mpWindowImpl->mpFrameWindow->ImplGetWindow();
+ }
+
+ // first visible top window (may be totally wrong...)
+ pWin = pSVData->maFrameData.mpFirstFrame;
+ while (pWin)
+ {
+ if( pWin->ImplGetWindow()->IsTopWindow() &&
+ pWin->mpWindowImpl->mbReallyVisible &&
+ (pWin->mpWindowImpl->mnStyle & WB_INTROWIN) == 0
+ )
+ {
+ while( pWin->mpWindowImpl->mpParent )
+ pWin = pWin->mpWindowImpl->mpParent;
+ return pWin->mpWindowImpl->mpFrameWindow->ImplGetWindow();
+ }
+ pWin = pWin->mpWindowImpl->mpFrameData->mpNextFrame;
+ }
+
+ // use the desktop
+ return nullptr;
+}
+
+weld::Window* Application::GetDefDialogParent()
+{
+ vcl::Window* pWindow = Dialog::GetDefDialogParent();
+ return pWindow ? pWindow->GetFrameWeld() : nullptr;
+}
+
+DialogCancelMode Application::GetDialogCancelMode()
+{
+ return ImplGetSVData()->maAppData.meDialogCancel;
+}
+
+void Application::SetDialogCancelMode( DialogCancelMode mode )
+{
+ ImplGetSVData()->maAppData.meDialogCancel = mode;
+}
+
+bool Application::IsDialogCancelEnabled()
+{
+ return ImplGetSVData()->maAppData.meDialogCancel != DialogCancelMode::Off;
+}
+
+void Application::SetSystemWindowMode( SystemWindowFlags nMode )
+{
+ ImplGetSVData()->maAppData.mnSysWinMode = nMode;
+}
+
+SystemWindowFlags Application::GetSystemWindowMode()
+{
+ return ImplGetSVData()->maAppData.mnSysWinMode;
+}
+
+css::uno::Reference< css::awt::XToolkit > Application::GetVCLToolkit()
+{
+ css::uno::Reference< css::awt::XToolkit > xT;
+ UnoWrapperBase* pWrapper = UnoWrapperBase::GetUnoWrapper();
+ if ( pWrapper )
+ xT = pWrapper->GetVCLToolkit();
+ return xT;
+}
+
+#ifdef DISABLE_DYNLOADING
+
+extern "C" { UnoWrapperBase* CreateUnoWrapper(); }
+
+#else
+
+extern "C" { static void thisModule() {} }
+
+#endif
+
+UnoWrapperBase* UnoWrapperBase::GetUnoWrapper( bool bCreateIfNotExist )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ static bool bAlreadyTriedToCreate = false;
+ if ( !pSVData->mpUnoWrapper && bCreateIfNotExist && !bAlreadyTriedToCreate )
+ {
+#ifndef DISABLE_DYNLOADING
+ osl::Module aTkLib;
+ aTkLib.loadRelative(&thisModule, TK_DLL_NAME);
+ if (aTkLib.is())
+ {
+ FN_TkCreateUnoWrapper fnCreateWrapper = reinterpret_cast<FN_TkCreateUnoWrapper>(aTkLib.getFunctionSymbol("CreateUnoWrapper"));
+ if ( fnCreateWrapper )
+ {
+ pSVData->mpUnoWrapper = fnCreateWrapper();
+ }
+ aTkLib.release();
+ }
+ SAL_WARN_IF( !pSVData->mpUnoWrapper, "vcl", "UnoWrapper could not be created!" );
+#else
+ pSVData->mpUnoWrapper = CreateUnoWrapper();
+#endif
+ bAlreadyTriedToCreate = true;
+ }
+ return pSVData->mpUnoWrapper;
+}
+
+void UnoWrapperBase::SetUnoWrapper( UnoWrapperBase* pWrapper )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ SAL_WARN_IF( pSVData->mpUnoWrapper, "vcl", "SetUnoWrapper: Wrapper already exists" );
+ pSVData->mpUnoWrapper = pWrapper;
+}
+
+css::uno::Reference< css::awt::XDisplayConnection > Application::GetDisplayConnection()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+
+ if( !pSVData->mxDisplayConnection.is() )
+ {
+ pSVData->mxDisplayConnection.set( new vcl::DisplayConnectionDispatch );
+ pSVData->mxDisplayConnection->start();
+ }
+
+ return pSVData->mxDisplayConnection;
+}
+
+void Application::SetFilterHdl( const Link<ConvertData&,bool>& rLink )
+{
+ ImplGetSVData()->maGDIData.mxGrfConverter->SetFilterHdl( rLink );
+}
+
+const LocaleDataWrapper& Application::GetAppLocaleDataWrapper()
+{
+ return GetSettings().GetLocaleDataWrapper();
+}
+
+void Application::EnableHeadlessMode( bool dialogsAreFatal )
+{
+ DialogCancelMode eNewMode = dialogsAreFatal ? DialogCancelMode::Fatal : DialogCancelMode::Silent;
+ DialogCancelMode eOldMode = GetDialogCancelMode();
+ assert(eOldMode == DialogCancelMode::Off || GetDialogCancelMode() == eNewMode);
+ if (eOldMode != eNewMode)
+ SetDialogCancelMode( eNewMode );
+}
+
+bool Application::IsHeadlessModeEnabled()
+{
+ return IsDialogCancelEnabled() || comphelper::LibreOfficeKit::isActive();
+}
+
+void Application::EnableBitmapRendering()
+{
+ ImplGetSVData()->maAppData.mbRenderToBitmaps = true;
+}
+
+bool Application::IsBitmapRendering()
+{
+ return ImplGetSVData()->maAppData.mbRenderToBitmaps;
+}
+
+void Application::EnableConsoleOnly()
+{
+ EnableHeadlessMode(true);
+ EnableBitmapRendering();
+}
+
+static bool bSafeMode = false;
+
+bool Application::IsSafeModeEnabled()
+{
+ return bSafeMode;
+}
+
+void Application::EnableSafeMode()
+{
+ bSafeMode = true;
+}
+
+void Application::ShowNativeErrorBox(const OUString& sTitle ,
+ const OUString& sMessage)
+{
+ int btn = ImplGetSalSystem()->ShowNativeMessageBox(
+ sTitle,
+ sMessage);
+ if (btn != SALSYSTEM_SHOWNATIVEMSGBOX_BTN_OK) {
+ SAL_WARN( "vcl", "ShowNativeMessageBox returned " << btn);
+ }
+}
+
+const OUString& Application::GetDesktopEnvironment()
+{
+ if (IsHeadlessModeEnabled())
+ {
+ static constexpr OUString aNone(u"none"_ustr);
+ return aNone;
+ }
+ else
+ return SalGetDesktopEnvironment();
+}
+
+void Application::AddToRecentDocumentList(const OUString& rFileUrl, const OUString& rMimeType, const OUString& rDocumentService)
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ pSVData->mpDefInst->AddToRecentDocumentList(rFileUrl, rMimeType, rDocumentService);
+}
+
+bool InitAccessBridge()
+{
+// Disable MSAA bridge on UNIX
+#if defined UNX
+ return true;
+#else
+ bool bRet = ImplInitAccessBridge();
+
+ if( !bRet )
+ {
+ // disable accessibility if the user chooses to continue
+ AllSettings aSettings = Application::GetSettings();
+ MiscSettings aMisc = aSettings.GetMiscSettings();
+ aMisc.SetEnableATToolSupport( false );
+ aSettings.SetMiscSettings( aMisc );
+ Application::SetSettings( aSettings );
+ }
+ return bRet;
+#endif // !UNX
+}
+
+// MT: AppEvent was in oldsv.cxx, but is still needed...
+void Application::AppEvent( const ApplicationEvent& /*rAppEvent*/ )
+{
+}
+
+bool Application::hasNativeFileSelection()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ return pSVData->mpDefInst->hasNativeFileSelection();
+}
+
+Reference< ui::dialogs::XFilePicker2 >
+Application::createFilePicker( const Reference< uno::XComponentContext >& xSM )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ return pSVData->mpDefInst->createFilePicker( xSM );
+}
+
+Reference< ui::dialogs::XFolderPicker2 >
+Application::createFolderPicker( const Reference< uno::XComponentContext >& xSM )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ return pSVData->mpDefInst->createFolderPicker( xSM );
+}
+
+void Application::setDeInitHook(Link<LinkParamNone*,void> const & hook) {
+ ImplSVData * pSVData = ImplGetSVData();
+ assert(!pSVData->maDeInitHook.IsSet());
+ pSVData->maDeInitHook = hook;
+ // Fake this for VCLXToolkit ctor instantiated from
+ // postprocess/CppunitTest_services.mk:
+ pSVData->maAppData.mbInAppMain = true;
+}
+
+namespace vcl::lok {
+
+void registerPollCallbacks(
+ LibreOfficeKitPollCallback pPollCallback,
+ LibreOfficeKitWakeCallback pWakeCallback,
+ void *pData) {
+
+ ImplSVData * pSVData = ImplGetSVData();
+ if (pSVData)
+ {
+ pSVData->mpPollCallback = pPollCallback;
+ pSVData->mpWakeCallback = pWakeCallback;
+ pSVData->mpPollClosure = pData;
+ }
+}
+
+void unregisterPollCallbacks()
+{
+ ImplSVData * pSVData = ImplGetSVData();
+ if (!pSVData)
+ return;
+
+ // Not hyper-elegant - but in the case of Android & unipoll we need to detach
+ // this thread from the JVM's clutches to avoid a crash closing document
+ if (pSVData->mpPollClosure && pSVData->mpDefInst)
+ pSVData->mpDefInst->releaseMainThread();
+
+ // Just set mpPollClosure to null as that is what calling this means, that the callback data
+ // points to an object that no longer exists. In particular, don't set
+ // pSVData->mpPollCallback to nullptr as that is used to detect whether Unipoll is in use in
+ // isUnipoll().
+ pSVData->mpPollClosure = nullptr;
+}
+
+bool isUnipoll()
+{
+ ImplSVData * pSVData = ImplGetSVData();
+ return pSVData && pSVData->mpPollCallback != nullptr;
+}
+
+void numberOfViewsChanged(int count)
+{
+ if (count == 0)
+ return;
+ ImplSVData * pSVData = ImplGetSVData();
+ auto& rCache = pSVData->maGDIData.maScaleCache;
+ // Normally the cache size is set to 10, scale according to the number of users.
+ rCache.setMaxSize(count * 10);
+}
+
+void dumpState(rtl::OStringBuffer &rState)
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if (!pSVData)
+ return;
+
+ rState.append("\nWindows:\t");
+ rState.append(static_cast<sal_Int32>(Application::GetTopWindowCount()));
+
+ vcl::Window *pWin = Application::GetFirstTopLevelWindow();
+ while (pWin)
+ {
+ tools::JsonWriter props;
+ pWin->DumpAsPropertyTree(props);
+
+ rState.append("\n\tWindow: ");
+ rState.append(props.finishAndGetAsOString());
+
+ pWin = Application::GetNextTopLevelWindow( pWin );
+ }
+
+ vcl::graphic::Manager::get().dumpState(rState);
+
+ pSVData->dumpState(rState);
+}
+
+void trimMemory(int nTarget)
+{
+ if (nTarget >= 1000)
+ {
+ ImplSVData* pSVData = ImplGetSVData();
+ if (!pSVData) // shutting down
+ return;
+ pSVData->dropCaches();
+ vcl::graphic::Manager::get().dropCache();
+ // TODO: ideally - free up any deeper dirtied thread stacks.
+ // comphelper::ThreadPool::getSharedOptimalPool().shutdown();
+ }
+ // else for now caches re-fill themselves as/when used.
+}
+
+} // namespace lok, namespace vcl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/app/svdata.cxx b/vcl/source/app/svdata.cxx
new file mode 100644
index 0000000000..e919bfda7c
--- /dev/null
+++ b/vcl/source/app/svdata.cxx
@@ -0,0 +1,534 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <string.h>
+
+#include <comphelper/lok.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <o3tl/string_view.hxx>
+#include <unotools/resmgr.hxx>
+#include <sal/log.hxx>
+
+#include <configsettings.hxx>
+#include <vcl/QueueInfo.hxx>
+#include <vcl/cvtgrf.hxx>
+#include <vcl/dockwin.hxx>
+#include <vcl/fieldvalues.hxx>
+#include <vcl/menu.hxx>
+#include <vcl/print.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/wrkwin.hxx>
+#include <vcl/uitest/logger.hxx>
+#include <salframe.hxx>
+#include <scrwnd.hxx>
+#include <helpwin.hxx>
+#include <vcl/toolkit/dialog.hxx>
+#include <salinst.hxx>
+#include <salgdi.hxx>
+#include <svdata.hxx>
+#include <salsys.hxx>
+#include <windowdev.hxx>
+#include <units.hrc>
+#include <print.h>
+
+#include <com/sun/star/accessibility/MSAAService.hpp>
+
+#include <config_features.h>
+#include <basegfx/utils/systemdependentdata.hxx>
+#include <mutex>
+
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::awt;
+
+namespace
+{
+ struct private_aImplSVData :
+ public rtl::Static<ImplSVData, private_aImplSVData> {};
+ /// Default instance ensures that ImplSVData::mpHelpData is never null.
+ struct private_aImplSVHelpData :
+ public rtl::Static<ImplSVHelpData, private_aImplSVHelpData> {};
+
+ /// Default instance ensures that ImplSVData::mpWinData is never null.
+ struct private_aImplSVWinData :
+ public rtl::Static<ImplSVWinData, private_aImplSVWinData> {};
+
+}
+
+ImplSVData* ImplGetSVData() {
+ return &private_aImplSVData::get();
+}
+
+SalSystem* ImplGetSalSystem()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if( ! pSVData->mpSalSystem )
+ pSVData->mpSalSystem.reset( pSVData->mpDefInst->CreateSalSystem() );
+ return pSVData->mpSalSystem.get();
+}
+
+void ImplDeInitSVData()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+
+ // delete global instance data
+ pSVData->mpSettingsConfigItem.reset();
+
+ pSVData->mpDockingManager.reset();
+
+ pSVData->maCtrlData.maFieldUnitStrings.clear();
+ pSVData->maCtrlData.maCleanUnitStrings.clear();
+ pSVData->maPaperNames.clear();
+}
+
+namespace
+{
+ typedef ::std::map< basegfx::SystemDependentData_SharedPtr, sal_uInt32 > EntryMap;
+
+ class SystemDependentDataBuffer final : public basegfx::SystemDependentDataManager
+ {
+ private:
+ std::mutex m_aMutex;
+ std::unique_ptr<AutoTimer> maTimer;
+ EntryMap maEntries;
+
+ DECL_LINK(implTimeoutHdl, Timer *, void);
+
+ public:
+ SystemDependentDataBuffer(const char* pDebugName)
+ : maTimer(std::make_unique<AutoTimer>(pDebugName))
+ {
+ maTimer->SetTimeout(1000);
+ maTimer->SetInvokeHandler(LINK(this, SystemDependentDataBuffer, implTimeoutHdl));
+ }
+
+ virtual ~SystemDependentDataBuffer() override
+ {
+ flushAll();
+ }
+
+ void startUsage(basegfx::SystemDependentData_SharedPtr& rData) override
+ {
+ std::unique_lock aGuard(m_aMutex);
+ EntryMap::iterator aFound(maEntries.find(rData));
+
+ if(aFound == maEntries.end())
+ {
+ if(maTimer && !maTimer->IsActive())
+ {
+ maTimer->Start();
+ }
+
+ maEntries[rData] = rData->calculateCombinedHoldCyclesInSeconds();
+ }
+ }
+
+ void endUsage(basegfx::SystemDependentData_SharedPtr& rData) override
+ {
+ std::unique_lock aGuard(m_aMutex);
+ EntryMap::iterator aFound(maEntries.find(rData));
+
+ if(aFound != maEntries.end())
+ {
+ maEntries.erase(aFound);
+ }
+ }
+
+ void touchUsage(basegfx::SystemDependentData_SharedPtr& rData) override
+ {
+ std::unique_lock aGuard(m_aMutex);
+ EntryMap::iterator aFound(maEntries.find(rData));
+
+ if(aFound != maEntries.end())
+ {
+ aFound->second = rData->calculateCombinedHoldCyclesInSeconds();
+ }
+ }
+
+ void flushAll() override
+ {
+ std::unique_lock aGuard(m_aMutex);
+
+ if(maTimer)
+ {
+ maTimer->Stop();
+ maTimer.reset();
+ }
+
+ maEntries.clear();
+ }
+ };
+
+ IMPL_LINK_NOARG(SystemDependentDataBuffer, implTimeoutHdl, Timer *, void)
+ {
+ std::unique_lock aGuard(m_aMutex);
+ EntryMap::iterator aIter(maEntries.begin());
+
+ while(aIter != maEntries.end())
+ {
+ if(aIter->second)
+ {
+ aIter->second--;
+ ++aIter;
+ }
+ else
+ {
+ aIter = maEntries.erase(aIter);
+ }
+ }
+
+ if (maEntries.empty())
+ maTimer->Stop();
+ }
+}
+
+basegfx::SystemDependentDataManager& ImplGetSystemDependentDataManager()
+{
+ static SystemDependentDataBuffer aSystemDependentDataBuffer("vcl SystemDependentDataBuffer aSystemDependentDataBuffer");
+
+ return aSystemDependentDataBuffer;
+}
+
+/// Returns either the application window, or the default GL context window
+vcl::Window* ImplGetDefaultWindow()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if (pSVData->maFrameData.mpAppWin)
+ return pSVData->maFrameData.mpAppWin;
+ else
+ return ImplGetDefaultContextWindow();
+}
+
+/// returns the default window created to hold the persistent VCL GL context.
+vcl::Window *ImplGetDefaultContextWindow()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+
+ // Double check locking on mpDefaultWin.
+ if ( !pSVData->mpDefaultWin )
+ {
+ SolarMutexGuard aGuard;
+
+ if (!pSVData->mpDefaultWin && !pSVData->mbDeInit)
+ {
+ try
+ {
+ SAL_INFO( "vcl", "ImplGetDefaultWindow(): No AppWindow" );
+
+ pSVData->mpDefaultWin = VclPtr<WorkWindow>::Create(nullptr, WB_DEFAULTWIN);
+ pSVData->mpDefaultWin->SetText( "VCL ImplGetDefaultWindow" );
+ }
+ catch (const css::uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("vcl", "unable to create Default Window");
+ }
+ }
+ }
+
+ return pSVData->mpDefaultWin;
+}
+
+const std::locale& ImplGetResLocale()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if (!pSVData->mbResLocaleSet || comphelper::LibreOfficeKit::isActive())
+ {
+ pSVData->maResLocale = Translate::Create("vcl");
+ pSVData->mbResLocaleSet = true;
+ }
+ return pSVData->maResLocale;
+}
+
+OUString VclResId(TranslateId aId)
+{
+ return Translate::get(aId, ImplGetResLocale());
+}
+
+const FieldUnitStringList& ImplGetFieldUnits()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if( pSVData->maCtrlData.maFieldUnitStrings.empty() )
+ {
+ sal_uInt32 nUnits = std::size(SV_FUNIT_STRINGS);
+ pSVData->maCtrlData.maFieldUnitStrings.reserve( nUnits );
+ for (sal_uInt32 i = 0; i < nUnits; i++)
+ {
+ std::pair<OUString, FieldUnit> aElement(VclResId(SV_FUNIT_STRINGS[i].first), SV_FUNIT_STRINGS[i].second);
+ pSVData->maCtrlData.maFieldUnitStrings.push_back( aElement );
+ }
+ }
+ return pSVData->maCtrlData.maFieldUnitStrings;
+}
+
+namespace vcl
+{
+ FieldUnit EnglishStringToMetric(std::u16string_view rEnglishMetricString)
+ {
+ sal_uInt32 nUnits = std::size(SV_FUNIT_STRINGS);
+ for (sal_uInt32 i = 0; i < nUnits; ++i)
+ {
+ if (o3tl::equalsAscii(rEnglishMetricString, SV_FUNIT_STRINGS[i].first.getId()))
+ return SV_FUNIT_STRINGS[i].second;
+ }
+ return FieldUnit::NONE;
+ }
+}
+
+const FieldUnitStringList& ImplGetCleanedFieldUnits()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if( pSVData->maCtrlData.maCleanUnitStrings.empty() )
+ {
+ const FieldUnitStringList& rUnits = ImplGetFieldUnits();
+ size_t nUnits = rUnits.size();
+ pSVData->maCtrlData.maCleanUnitStrings.reserve(nUnits);
+ for (size_t i = 0; i < nUnits; ++i)
+ {
+ OUString aUnit(rUnits[i].first);
+ aUnit = aUnit.replaceAll(" ", "");
+ aUnit = aUnit.toAsciiLowerCase();
+ std::pair<OUString, FieldUnit> aElement(aUnit, rUnits[i].second);
+ pSVData->maCtrlData.maCleanUnitStrings.push_back(aElement);
+ }
+ }
+ return pSVData->maCtrlData.maCleanUnitStrings;
+}
+
+DockingManager* ImplGetDockingManager()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( !pSVData->mpDockingManager )
+ pSVData->mpDockingManager.reset(new DockingManager());
+
+ return pSVData->mpDockingManager.get();
+}
+
+BlendFrameCache* ImplGetBlendFrameCache()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( !pSVData->mpBlendFrameCache)
+ pSVData->mpBlendFrameCache.reset( new BlendFrameCache() );
+
+ return pSVData->mpBlendFrameCache.get();
+}
+
+#ifdef _WIN32
+bool ImplInitAccessBridge()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if( ! pSVData->mxAccessBridge.is() )
+ {
+ css::uno::Reference< XComponentContext > xContext(comphelper::getProcessComponentContext());
+
+ if (!HasAtHook() && !getenv("SAL_FORCE_IACCESSIBLE2"))
+ {
+ SAL_INFO("vcl", "Apparently no running AT -> "
+ "not enabling IAccessible2 integration");
+ }
+ else
+ {
+ try {
+ pSVData->mxAccessBridge
+ = css::accessibility::MSAAService::create(xContext);
+ SAL_INFO("vcl", "got IAccessible2 bridge");
+ return true;
+ } catch (css::uno::DeploymentException &) {
+ TOOLS_WARN_EXCEPTION(
+ "vcl",
+ "got no IAccessible2 bridge");
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+#endif
+
+void LocaleConfigurationListener::ConfigurationChanged( utl::ConfigurationBroadcaster*, ConfigurationHints nHint )
+{
+ AllSettings::LocaleSettingsChanged( nHint );
+}
+
+ImplSVWinData* CreateSVWinData()
+{
+ if (!comphelper::LibreOfficeKit::isActive())
+ return nullptr;
+
+ ImplSVWinData* p = new ImplSVWinData;
+
+ ImplSVData* pSVData = ImplGetSVData();
+ assert(pSVData && pSVData->mpWinData);
+
+ p->mpFocusWin = pSVData->mpWinData->mpFocusWin;
+ return p;
+}
+
+void DestroySVWinData(ImplSVWinData* pData)
+{
+ delete pData;
+}
+
+void SetSVWinData(ImplSVWinData* pSVWinData)
+{
+ if (!comphelper::LibreOfficeKit::isActive())
+ return;
+
+ ImplSVData* pSVData = ImplGetSVData();
+ assert(pSVData != nullptr);
+
+ if (pSVData->mpWinData == pSVWinData)
+ return;
+
+ // If current one is the static, clean it up to avoid having lingering references.
+ if (pSVData->mpWinData == &private_aImplSVWinData::get())
+ {
+ pSVData->mpWinData->mpFocusWin.reset();
+ }
+
+ pSVData->mpWinData = pSVWinData;
+ if (pSVData->mpWinData == nullptr)
+ {
+ pSVData->mpWinData = &private_aImplSVWinData::get(); // Never leave it null.
+ }
+}
+
+ImplSVData::ImplSVData()
+{
+ mpHelpData = &private_aImplSVHelpData::get();
+ mpWinData = &private_aImplSVWinData::get();
+}
+
+void ImplSVData::dropCaches()
+{
+ // we are iterating over a map and doing erase while inside a loop which is doing erase
+ // hence we can't use clear() here
+ maGDIData.maScaleCache.remove_if([](const lru_scale_cache::key_value_pair_t&)
+ { return true; });
+
+ maGDIData.maThemeDrawCommandsCache.clear();
+ maGDIData.maThemeImageCache.clear();
+}
+
+void ImplSVData::dumpState(rtl::OStringBuffer &rState)
+{
+ rState.append("\nScaleCache:\t");
+ rState.append(static_cast<sal_Int32>(maGDIData.maScaleCache.size()));
+ rState.append("\t items:");
+
+ for (auto it = maGDIData.maScaleCache.begin();
+ it != maGDIData.maScaleCache.begin(); ++it)
+ {
+ rState.append("\n\t");
+ rState.append(static_cast<sal_Int32>(it->first.maDestSize.Width()));
+ rState.append("x");
+ rState.append(static_cast<sal_Int32>(it->first.maDestSize.Height()));
+ }
+}
+
+ImplSVHelpData* CreateSVHelpData()
+{
+ if (!comphelper::LibreOfficeKit::isActive())
+ return nullptr;
+
+ ImplSVHelpData* pNewData = new ImplSVHelpData;
+
+ // Set options set globally
+ ImplSVHelpData& aStaticHelpData = private_aImplSVHelpData::get();
+ pNewData->mbContextHelp = aStaticHelpData.mbContextHelp;
+ pNewData->mbExtHelp = aStaticHelpData.mbExtHelp;
+ pNewData->mbExtHelpMode = aStaticHelpData.mbExtHelpMode;
+ pNewData->mbOldBalloonMode = aStaticHelpData.mbOldBalloonMode;
+ pNewData->mbBalloonHelp = aStaticHelpData.mbBalloonHelp;
+ pNewData->mbQuickHelp = aStaticHelpData.mbQuickHelp;
+
+ return pNewData;
+}
+
+void DestroySVHelpData(ImplSVHelpData* pSVHelpData)
+{
+ if (!comphelper::LibreOfficeKit::isActive())
+ return;
+
+ // Change the SVData's help date if necessary
+ if(ImplGetSVData()->mpHelpData == pSVHelpData)
+ {
+ ImplGetSVData()->mpHelpData = &private_aImplSVHelpData::get();
+ }
+
+ if(pSVHelpData)
+ {
+ ImplDestroyHelpWindow(*pSVHelpData, false);
+ delete pSVHelpData;
+ }
+}
+
+void SetSVHelpData(ImplSVHelpData* pSVHelpData)
+{
+ if (!comphelper::LibreOfficeKit::isActive())
+ return;
+
+ ImplSVData* pSVData = ImplGetSVData();
+ if (pSVData->mpHelpData == pSVHelpData)
+ return;
+
+ // If current one is the static, clean it up to avoid having lingering references.
+ if (pSVData->mpHelpData == &private_aImplSVHelpData::get())
+ {
+ pSVData->mpHelpData->mpHelpWin.reset();
+ }
+
+ pSVData->mpHelpData = pSVHelpData;
+ if (pSVData->mpHelpData == nullptr)
+ {
+ pSVData->mpHelpData = &private_aImplSVHelpData::get(); // Never leave it null.
+ }
+}
+
+ImplSVHelpData& ImplGetSVHelpData()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if(pSVData->mpHelpData)
+ {
+ return *pSVData->mpHelpData;
+ }
+ else
+ {
+ return private_aImplSVHelpData::get();
+ }
+}
+
+ImplSVData::~ImplSVData() {}
+
+ImplSVAppData::ImplSVAppData()
+{
+ m_bUseSystemLoop = getenv("SAL_USE_SYSTEM_LOOP") != nullptr;
+ SAL_WARN_IF(m_bUseSystemLoop, "vcl.schedule", "Overriding to run LO on system event loop!");
+}
+
+ImplSVAppData::~ImplSVAppData() {}
+ImplSVGDIData::~ImplSVGDIData() {}
+ImplSVFrameData::~ImplSVFrameData() {}
+ImplSVWinData::~ImplSVWinData() {}
+ImplSVHelpData::~ImplSVHelpData() {}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/app/svmain.cxx b/vcl/source/app/svmain.cxx
new file mode 100644
index 0000000000..3aa2cecf4e
--- /dev/null
+++ b/vcl/source/app/svmain.cxx
@@ -0,0 +1,714 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+#include <sal/log.hxx>
+
+#include <cassert>
+
+#include <osl/file.hxx>
+#include <osl/signal.h>
+
+#include <desktop/exithelper.h>
+
+#include <comphelper/accessibleeventnotifier.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/asyncnotification.hxx>
+#include <i18nlangtag/mslangid.hxx>
+#include <unotools/syslocale.hxx>
+#include <unotools/syslocaleoptions.hxx>
+#include <utility>
+#include <vcl/QueueInfo.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/vclmain.hxx>
+#include <vcl/wrkwin.hxx>
+#include <vcl/cvtgrf.hxx>
+#include <vcl/scheduler.hxx>
+#include <vcl/image.hxx>
+#include <vcl/ImageTree.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/toolkit/unowrap.hxx>
+#include <configsettings.hxx>
+#include <vcl/lazydelete.hxx>
+#include <vcl/embeddedfontshelper.hxx>
+#include <vcl/toolkit/dialog.hxx>
+#include <vcl/menu.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/print.hxx>
+#include <debugevent.hxx>
+#include <scrwnd.hxx>
+#include <windowdev.hxx>
+#include <svdata.hxx>
+
+#ifdef _WIN32
+#include <svsys.h>
+#include <process.h>
+#include <ole2.h>
+#else
+#include <stdlib.h>
+#endif
+
+#ifdef ANDROID
+#include <cppuhelper/bootstrap.hxx>
+#include <jni.h>
+#endif
+
+#include <impfontcache.hxx>
+#include <salinst.hxx>
+#include <vcl/svmain.hxx>
+#include <dbggui.hxx>
+#include <accmgr.hxx>
+#include <font/PhysicalFontCollection.hxx>
+#include <print.h>
+#include <salsys.hxx>
+#include <saltimer.hxx>
+#include <displayconnectiondispatch.hxx>
+
+#include <config_features.h>
+#include <config_feature_opencl.h>
+#include <systools/opensslinit.hxx>
+
+#include <osl/process.h>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+
+#ifdef _WIN32
+#include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
+#endif
+
+#include <comphelper/lok.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <uno/current_context.hxx>
+
+#include <opencl/OpenCLZone.hxx>
+#include <opengl/zone.hxx>
+#include <skia/zone.hxx>
+#include <watchdog.hxx>
+
+#include <basegfx/utils/systemdependentdata.hxx>
+#include <comphelper/diagnose_ex.hxx>
+
+#if OSL_DEBUG_LEVEL > 0
+#include <typeinfo>
+#include <rtl/strbuf.hxx>
+#endif
+
+#ifdef LINUX
+#include <unx/gendata.hxx>
+#endif
+
+using namespace ::com::sun::star;
+
+static bool g_bIsLeanException;
+
+static oslSignalAction VCLExceptionSignal_impl( void* /*pData*/, oslSignalInfo* pInfo)
+{
+ static volatile bool bIn = false;
+
+ // if we crash again, bail out immediately
+ if ( bIn || g_bIsLeanException)
+ return osl_Signal_ActCallNextHdl;
+
+ ExceptionCategory nVCLException = ExceptionCategory::NONE;
+
+ // UAE
+ if ( (pInfo->Signal == osl_Signal_AccessViolation) ||
+ (pInfo->Signal == osl_Signal_IntegerDivideByZero) ||
+ (pInfo->Signal == osl_Signal_FloatDivideByZero) ||
+ (pInfo->Signal == osl_Signal_DebugBreak) )
+ {
+ nVCLException = ExceptionCategory::System;
+#if HAVE_FEATURE_OPENGL
+ if (OpenGLZone::isInZone())
+ OpenGLZone::hardDisable();
+#endif
+#if HAVE_FEATURE_SKIA
+ if (SkiaZone::isInZone())
+ SkiaZone::hardDisable();
+#endif
+#if HAVE_FEATURE_OPENCL
+ if (OpenCLZone::isInZone())
+ {
+ OpenCLZone::hardDisable();
+#ifdef _WIN32
+ if (OpenCLInitialZone::isInZone())
+ TerminateProcess(GetCurrentProcess(), EXITHELPER_NORMAL_RESTART);
+#endif
+ }
+#endif
+ }
+
+ // DISPLAY-Unix
+ if ((pInfo->Signal == osl_Signal_User) &&
+ (pInfo->UserSignal == OSL_SIGNAL_USER_X11SUBSYSTEMERROR) )
+ nVCLException = ExceptionCategory::UserInterface;
+
+ if ( nVCLException != ExceptionCategory::NONE )
+ {
+ bIn = true;
+
+ vcl::SolarMutexTryAndBuyGuard aLock;
+ if( aLock.isAcquired())
+ {
+ // do not stop timer because otherwise the UAE-Box will not be painted as well
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( pSVData->mpApp )
+ {
+ SystemWindowFlags nOldMode = Application::GetSystemWindowMode();
+ Application::SetSystemWindowMode( nOldMode & ~SystemWindowFlags::NOAUTOMODE );
+ pSVData->mpApp->Exception( nVCLException );
+ Application::SetSystemWindowMode( nOldMode );
+ }
+ }
+ bIn = false;
+ }
+
+ return osl_Signal_ActCallNextHdl;
+
+}
+
+int ImplSVMain()
+{
+ // The 'real' SVMain()
+ ImplSVData* pSVData = ImplGetSVData();
+
+ SAL_WARN_IF( !pSVData->mpApp, "vcl", "no instance of class Application" );
+
+ int nReturn = EXIT_FAILURE;
+
+ const bool bWasInitVCL = IsVCLInit();
+
+#if defined(LINUX) && !defined(SYSTEM_OPENSSL)
+ if (!bWasInitVCL)
+ {
+ OUString constexpr name(u"SSL_CERT_FILE"_ustr);
+ OUString temp;
+ if (osl_getEnvironment(name.pData, &temp.pData) == osl_Process_E_NotFound)
+ {
+ try // to point bundled OpenSSL to some system certificate file
+ { // ... this only works if the client actually calls
+ // SSL_CTX_set_default_verify_paths() or similar; e.g. python ssl.
+ char const*const path = GetCABundleFile();
+ OUString const filepath(::rtl::OStringToOUString(
+ ::std::string_view(path), osl_getThreadTextEncoding()));
+ osl_setEnvironment(name.pData, filepath.pData);
+ }
+ catch (uno::RuntimeException const& e)
+ {
+ SAL_WARN("vcl", e.Message);
+ }
+ }
+ }
+#endif
+
+ const bool bInit = bWasInitVCL || InitVCL();
+ int nRet = 0;
+ if (!bWasInitVCL && bInit && pSVData->mpDefInst->SVMainHook(&nRet))
+ return nRet;
+
+ if( bInit )
+ {
+ // call application main
+ pSVData->maAppData.mbInAppMain = true;
+ nReturn = pSVData->mpApp->Main();
+ pSVData->maAppData.mbInAppMain = false;
+ }
+
+ if( pSVData->mxDisplayConnection.is() )
+ {
+ pSVData->mxDisplayConnection->terminate();
+ pSVData->mxDisplayConnection.clear();
+ }
+
+ // This is a hack to work around the problem of the asynchronous nature
+ // of bridging accessibility through Java: on shutdown there might still
+ // be some events in the AWT EventQueue, which need the SolarMutex which
+ // - on the other hand - is destroyed in DeInitVCL(). So empty the queue
+ // here ..
+ if( pSVData->mxAccessBridge.is() )
+ {
+ {
+ SolarMutexReleaser aReleaser;
+ pSVData->mxAccessBridge->dispose();
+ }
+ pSVData->mxAccessBridge.clear();
+ }
+
+ WatchdogThread::stop();
+ DeInitVCL();
+
+ return nReturn;
+}
+
+int SVMain()
+{
+ return ImplSVMain();
+}
+
+// This variable is set when no Application object has been instantiated
+// before InitVCL is called
+static Application * pOwnSvApp = nullptr;
+
+// Exception handler. pExceptionHandler != NULL => VCL already inited
+static oslSignalHandler pExceptionHandler = nullptr;
+
+namespace {
+
+class DesktopEnvironmentContext: public cppu::WeakImplHelper< css::uno::XCurrentContext >
+{
+public:
+ explicit DesktopEnvironmentContext( css::uno::Reference< css::uno::XCurrentContext > ctx)
+ : m_xNextContext(std::move( ctx )) {}
+
+ // XCurrentContext
+ virtual css::uno::Any SAL_CALL getValueByName( const OUString& Name ) override;
+
+private:
+ css::uno::Reference< css::uno::XCurrentContext > m_xNextContext;
+};
+
+}
+
+uno::Any SAL_CALL DesktopEnvironmentContext::getValueByName( const OUString& Name)
+{
+ uno::Any retVal;
+
+ if ( Name == "system.desktop-environment" )
+ {
+ retVal <<= Application::GetDesktopEnvironment();
+ }
+ else if( m_xNextContext.is() )
+ {
+ // Call next context in chain if found
+ retVal = m_xNextContext->getValueByName( Name );
+ }
+ return retVal;
+}
+
+bool IsVCLInit()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ return pExceptionHandler != nullptr &&
+ pSVData->mpApp != nullptr &&
+ pSVData->mpDefInst != nullptr;
+}
+
+#ifdef DBG_UTIL
+namespace vclmain
+{
+ bool isAlive()
+ {
+ return ImplGetSVData()->mpDefInst;
+ }
+}
+#endif
+
+
+bool InitVCL()
+{
+ if (IsVCLInit())
+ {
+ SAL_INFO("vcl.app", "Double initialization of vcl");
+ return true;
+ }
+
+ if( pExceptionHandler != nullptr )
+ return false;
+
+ EmbeddedFontsHelper::clearTemporaryFontFiles();
+
+ if( !ImplGetSVData()->mpApp )
+ {
+ pOwnSvApp = new Application();
+ }
+
+ ImplSVData* pSVData = ImplGetSVData();
+
+ // remember Main-Thread-Id
+ pSVData->mnMainThreadId = ::osl::Thread::getCurrentIdentifier();
+
+ // Initialize Sal
+ pSVData->mpDefInst = CreateSalInstance();
+ if ( !pSVData->mpDefInst )
+ return false;
+ pSVData->mpDefInst->AcquireYieldMutex();
+
+ // Desktop Environment context (to be able to get value of "system.desktop-environment" as soon as possible)
+ css::uno::setCurrentContext(
+ new DesktopEnvironmentContext( css::uno::getCurrentContext() ) );
+
+ // Initialize application instance (should be done after initialization of VCL SAL part)
+ if (pSVData->mpApp)
+ {
+ // call init to initialize application class
+ // soffice/sfx implementation creates the global service manager
+ pSVData->mpApp->Init();
+ }
+
+ try
+ {
+ //Now that uno has been bootstrapped we can ask the config what the UI language is so that we can
+ //force that in as $LANGUAGE. That way we can get gtk to render widgets RTL
+ //if we have a RTL UI in an otherwise LTR locale and get gettext using externals (e.g. python)
+ //to match their translations to our preferred UI language
+ OUString aLocaleString(SvtSysLocaleOptions().GetRealUILanguageTag().getGlibcLocaleString(u".UTF-8"));
+ if (!aLocaleString.isEmpty())
+ {
+ MsLangId::getSystemUILanguage(); //call this now to pin what the system UI really was
+ OUString envVar("LANGUAGE");
+ osl_setEnvironment(envVar.pData, aLocaleString.pData);
+ }
+ }
+ catch (const uno::Exception &)
+ {
+ TOOLS_INFO_EXCEPTION("vcl.app", "Unable to get ui language:");
+ }
+
+ pSVData->mpDefInst->AfterAppInit();
+
+ // Fetch AppFileName and make it absolute before the workdir changes...
+ OUString aExeFileName;
+ osl_getExecutableFile( &aExeFileName.pData );
+
+ // convert path to native file format
+ OUString aNativeFileName;
+ osl::FileBase::getSystemPathFromFileURL( aExeFileName, aNativeFileName );
+ pSVData->maAppData.mxAppFileName = aNativeFileName;
+
+ // Initialize global data
+ pSVData->maGDIData.mxScreenFontList = std::make_shared<vcl::font::PhysicalFontCollection>();
+ pSVData->maGDIData.mxScreenFontCache = std::make_shared<ImplFontCache>();
+ pSVData->maGDIData.mxGrfConverter.reset(new GraphicConverter);
+
+ g_bIsLeanException = getenv("LO_LEAN_EXCEPTION") != nullptr;
+ // Set exception handler
+ pExceptionHandler = osl_addSignalHandler(VCLExceptionSignal_impl, nullptr);
+
+#ifndef NDEBUG
+ DbgGUIInitSolarMutexCheck();
+#endif
+
+#if OSL_DEBUG_LEVEL > 0
+ DebugEventInjector::getCreate();
+#endif
+
+#ifndef _WIN32
+ // Clear startup notification details for child processes
+ // See https://bugs.freedesktop.org/show_bug.cgi?id=11375 for discussion
+ unsetenv("DESKTOP_STARTUP_ID");
+#endif
+
+ return true;
+}
+
+namespace
+{
+
+/** Serves for destroying the VCL UNO wrapper as late as possible. This avoids
+ crash at exit in some special cases when a11y is enabled (e.g., when
+ a bundled extension is registered/deregistered during startup, forcing exit
+ while the app is still in splash screen.)
+ */
+class VCLUnoWrapperDeleter : public cppu::WeakImplHelper<css::lang::XEventListener>
+{
+ virtual void SAL_CALL disposing(lang::EventObject const& rSource) override;
+};
+
+void
+VCLUnoWrapperDeleter::disposing(lang::EventObject const& /* rSource */)
+{
+ ImplSVData* const pSVData = ImplGetSVData();
+ if (pSVData && pSVData->mpUnoWrapper)
+ {
+ pSVData->mpUnoWrapper->Destroy();
+ pSVData->mpUnoWrapper = nullptr;
+ }
+}
+
+}
+
+void DeInitVCL()
+{
+ // The LOK Windows map container should be empty
+ assert(vcl::Window::IsLOKWindowsEmpty());
+
+ //rhbz#1444437, when using LibreOffice like a library you can't realistically
+ //tear everything down and recreate them on the next call, there's too many
+ //(c++) singletons that point to stuff that gets deleted during shutdown
+ //which won't be recreated on restart.
+ if (comphelper::LibreOfficeKit::isActive())
+ return;
+
+ {
+ SolarMutexReleaser r; // unblock threads blocked on that so we can join
+ ::comphelper::JoinAsyncEventNotifiers();
+ }
+ ImplSVData* pSVData = ImplGetSVData();
+
+ // lp#1560328: clear cache before disposing rest of VCL
+ if(pSVData->mpBlendFrameCache)
+ pSVData->mpBlendFrameCache->m_aLastResult.Clear();
+ pSVData->mbDeInit = true;
+
+ vcl::DeleteOnDeinitBase::ImplDeleteOnDeInit();
+
+#if OSL_DEBUG_LEVEL > 0
+ OStringBuffer aBuf( 256 );
+ aBuf.append( "DeInitVCL: some top Windows are still alive\n" );
+ tools::Long nTopWindowCount = Application::GetTopWindowCount();
+ tools::Long nBadTopWindows = nTopWindowCount;
+ for( tools::Long i = 0; i < nTopWindowCount; i++ )
+ {
+ vcl::Window* pWin = Application::GetTopWindow( i );
+ // default window will be destroyed further down
+ // but may still be useful during deinit up to that point
+ if( pWin == pSVData->mpDefaultWin )
+ nBadTopWindows--;
+ else
+ {
+ aBuf.append( "text = \""
+ + OUStringToOString( pWin->GetText(), osl_getThreadTextEncoding() )
+ + "\" type = \""
+ + typeid(*pWin).name()
+ + "\", ptr = 0x"
+ + OString::number(reinterpret_cast<sal_Int64>( pWin ), 16 )
+ + "\n" );
+ }
+ }
+ SAL_WARN_IF( nBadTopWindows!=0, "vcl", aBuf.getStr() );
+#endif
+
+ ImageTree::get().shutdown();
+
+ osl_removeSignalHandler( pExceptionHandler);
+ pExceptionHandler = nullptr;
+
+ // free global data
+ pSVData->maGDIData.mxGrfConverter.reset();
+ pSVData->mpSettingsConfigItem.reset();
+
+ // prevent unnecessary painting during Scheduler shutdown
+ // as this processes all pending events in debug builds.
+ ImplGetSystemDependentDataManager().flushAll();
+
+#if defined _WIN32
+ // See GetSystemClipboard (vcl/source/treelist/transfer2.cxx):
+ if (auto const comp = css::uno::Reference<css::lang::XComponent>(
+ pSVData->m_xSystemClipboard, css::uno::UNO_QUERY))
+ {
+ SolarMutexReleaser r; // unblock pending "clipboard content changed" notifications
+ comp->dispose(); // will use s_aClipboardSingletonMutex for CWinClipboard
+ }
+ pSVData->m_xSystemClipboard.clear();
+#endif
+
+ Scheduler::ImplDeInitScheduler();
+
+ pSVData->mpWinData->maMsgBoxImgList.clear();
+ pSVData->maCtrlData.maCheckImgList.clear();
+ pSVData->maCtrlData.maRadioImgList.clear();
+ pSVData->maCtrlData.moDisclosurePlus.reset();
+ pSVData->maCtrlData.moDisclosureMinus.reset();
+ pSVData->mpDefaultWin.disposeAndClear();
+
+#ifndef NDEBUG
+ DbgGUIDeInitSolarMutexCheck();
+#endif
+
+ if ( pSVData->mpUnoWrapper )
+ {
+ try
+ {
+ uno::Reference<frame::XDesktop2> const xDesktop = frame::Desktop::create(
+ comphelper::getProcessComponentContext() );
+ xDesktop->addEventListener(new VCLUnoWrapperDeleter);
+ }
+ catch (uno::Exception const&)
+ {
+ // ignore
+ }
+ }
+
+ if( pSVData->mpApp || pSVData->maDeInitHook.IsSet() )
+ {
+ SolarMutexReleaser aReleaser;
+ // call deinit to deinitialize application class
+ // soffice/sfx implementation disposes the global service manager
+ // Warning: After this call you can't call uno services
+ if( pSVData->mpApp )
+ {
+ pSVData->mpApp->DeInit();
+ }
+ if( pSVData->maDeInitHook.IsSet() )
+ {
+ pSVData->maDeInitHook.Call(nullptr);
+ }
+ }
+
+ if ( pSVData->maAppData.mxSettings )
+ {
+ if ( pSVData->maAppData.mpCfgListener )
+ {
+ pSVData->maAppData.mxSettings->GetSysLocale().GetOptions().RemoveListener( pSVData->maAppData.mpCfgListener );
+ delete pSVData->maAppData.mpCfgListener;
+ }
+
+ pSVData->maAppData.mxSettings.reset();
+ }
+ if ( pSVData->maAppData.mpAccelMgr )
+ {
+ delete pSVData->maAppData.mpAccelMgr;
+ pSVData->maAppData.mpAccelMgr = nullptr;
+ }
+ pSVData->maAppData.maKeyListeners.clear();
+ pSVData->mpBlendFrameCache.reset();
+
+ ImplDeletePrnQueueList();
+
+ // destroy all Sal interfaces before destroying the instance
+ // and thereby unloading the plugin
+ pSVData->mpSalSystem.reset();
+ assert( !pSVData->maSchedCtx.mpSalTimer );
+ delete pSVData->maSchedCtx.mpSalTimer;
+ pSVData->maSchedCtx.mpSalTimer = nullptr;
+
+ pSVData->mpDefaultWin = nullptr;
+ pSVData->mpIntroWindow = nullptr;
+ pSVData->maAppData.mpActivePopupMenu = nullptr;
+ pSVData->maAppData.mpWheelWindow = nullptr;
+ pSVData->maGDIData.mpFirstWinGraphics = nullptr;
+ pSVData->maGDIData.mpLastWinGraphics = nullptr;
+ pSVData->maGDIData.mpFirstVirGraphics = nullptr;
+ pSVData->maGDIData.mpLastVirGraphics = nullptr;
+ pSVData->maGDIData.mpFirstPrnGraphics = nullptr;
+ pSVData->maGDIData.mpLastPrnGraphics = nullptr;
+ pSVData->maGDIData.mpFirstVirDev = nullptr;
+ pSVData->maGDIData.mpFirstPrinter = nullptr;
+ pSVData->maFrameData.mpFirstFrame = nullptr;
+ pSVData->maFrameData.mpAppWin = nullptr;
+ pSVData->maFrameData.mpActiveApplicationFrame = nullptr;
+ pSVData->mpWinData->mpCaptureWin = nullptr;
+ pSVData->mpWinData->mpLastDeacWin = nullptr;
+ pSVData->mpWinData->mpFirstFloat = nullptr;
+ pSVData->mpWinData->mpExecuteDialogs.clear();
+ pSVData->mpWinData->mpExtTextInputWin = nullptr;
+ pSVData->mpWinData->mpTrackWin = nullptr;
+ pSVData->mpWinData->mpAutoScrollWin = nullptr;
+ pSVData->mpWinData->mpLastWheelWindow = nullptr;
+
+ pSVData->maGDIData.mxScreenFontList.reset();
+ pSVData->maGDIData.mxScreenFontCache.reset();
+ pSVData->dropCaches();
+
+ comphelper::AccessibleEventNotifier::shutdown();
+
+ // Deinit Sal
+ if (pSVData->mpDefInst)
+ {
+ pSVData->mpDefInst->ReleaseYieldMutexAll();
+ DestroySalInstance( pSVData->mpDefInst );
+ pSVData->mpDefInst = nullptr;
+ }
+
+ // This only works on Linux. On Mac and Windows I get very
+ // weird segment violations.
+#if defined LINUX
+ delete pSVData->mpSalData;
+#endif
+
+ if( pOwnSvApp )
+ {
+ delete pOwnSvApp;
+ pOwnSvApp = nullptr;
+ }
+
+ EmbeddedFontsHelper::clearTemporaryFontFiles();
+}
+
+namespace {
+
+// only one call is allowed
+struct WorkerThreadData
+{
+ oslWorkerFunction pWorker;
+ void * pThreadData;
+ WorkerThreadData( oslWorkerFunction pWorker_, void * pThreadData_ )
+ : pWorker( pWorker_ )
+ , pThreadData( pThreadData_ )
+ {
+ }
+};
+
+}
+
+#ifdef _WIN32
+static HANDLE hThreadID = nullptr;
+static unsigned __stdcall threadmain(void* pArgs)
+{
+ OleInitialize( nullptr );
+ static_cast<WorkerThreadData*>(pArgs)->pWorker( static_cast<WorkerThreadData*>(pArgs)->pThreadData );
+ delete static_cast<WorkerThreadData*>(pArgs);
+ OleUninitialize();
+ hThreadID = nullptr;
+ return 0;
+}
+#else
+static oslThread hThreadID = nullptr;
+extern "C"
+{
+static void MainWorkerFunction( void* pArgs )
+{
+ static_cast<WorkerThreadData*>(pArgs)->pWorker( static_cast<WorkerThreadData*>(pArgs)->pThreadData );
+ delete static_cast<WorkerThreadData*>(pArgs);
+ hThreadID = nullptr;
+}
+} // extern "C"
+#endif
+
+void CreateMainLoopThread( oslWorkerFunction pWorker, void * pThreadData )
+{
+#ifdef _WIN32
+ // sal thread always call CoInitializeEx, so a system dependent implementation is necessary
+
+ hThreadID = reinterpret_cast<HANDLE>(_beginthreadex(
+ nullptr, // no security handle
+ 0, // stacksize 0 means default
+ threadmain, // thread worker function
+ new WorkerThreadData( pWorker, pThreadData ), // arguments for worker function
+ 0, // 0 means: create immediately otherwise use CREATE_SUSPENDED
+ nullptr )); // thread id to fill
+#else
+ hThreadID = osl_createThread( MainWorkerFunction, new WorkerThreadData( pWorker, pThreadData ) );
+#endif
+}
+
+void JoinMainLoopThread()
+{
+ if( hThreadID )
+ {
+#ifdef _WIN32
+ WaitForSingleObject(hThreadID, INFINITE);
+#else
+ osl_joinWithThread(hThreadID);
+ osl_destroyThread( hThreadID );
+#endif
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/app/timer.cxx b/vcl/source/app/timer.cxx
new file mode 100644
index 0000000000..183cd41a4e
--- /dev/null
+++ b/vcl/source/app/timer.cxx
@@ -0,0 +1,103 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/log.hxx>
+#include <vcl/timer.hxx>
+#include <vcl/scheduler.hxx>
+#include <schedulerimpl.hxx>
+
+void Timer::SetDeletionFlags()
+{
+ // If no AutoTimer, then stop.
+ if ( !mbAuto )
+ Task::SetDeletionFlags();
+}
+
+sal_uInt64 Timer::UpdateMinPeriod( sal_uInt64 nTimeNow ) const
+{
+ sal_uInt64 nWakeupTime = GetSchedulerData()->mnUpdateTime + mnTimeout;
+ return ( nWakeupTime <= nTimeNow )
+ ? Scheduler::ImmediateTimeoutMs : nWakeupTime - nTimeNow;
+}
+
+Timer::Timer( bool bAuto, const char *pDebugName )
+ : Task( pDebugName )
+ , mnTimeout( Scheduler::ImmediateTimeoutMs )
+ , mbAuto( bAuto )
+{
+ SetPriority( TaskPriority::DEFAULT );
+}
+
+Timer::Timer( const char *pDebugName )
+ : Timer( false, pDebugName )
+{
+}
+
+Timer::Timer( const Timer& rTimer )
+ : Timer( rTimer.mbAuto, rTimer.GetDebugName() )
+{
+ maInvokeHandler = rTimer.maInvokeHandler;
+ mnTimeout = rTimer.mnTimeout;
+}
+
+Timer::~Timer()
+{
+}
+
+Timer& Timer::operator=( const Timer& rTimer )
+{
+ Task::operator=( rTimer );
+ maInvokeHandler = rTimer.maInvokeHandler;
+ mnTimeout = rTimer.mnTimeout;
+ SAL_WARN_IF( mbAuto != rTimer.mbAuto, "vcl.schedule",
+ "Copying Timer with different mbAuto value!" );
+ return *this;
+}
+
+void Timer::Invoke()
+{
+ maInvokeHandler.Call( this );
+}
+
+void Timer::Invoke( Timer *arg )
+{
+ maInvokeHandler.Call( arg );
+}
+
+void Timer::Start(const bool bStartTimer)
+{
+ Task::Start(false);
+ if (bStartTimer)
+ Task::StartTimer(mnTimeout);
+}
+
+void Timer::SetTimeout( sal_uInt64 nNewTimeout )
+{
+ mnTimeout = nNewTimeout;
+ // If timer is active, then renew clock.
+ if ( IsActive() )
+ StartTimer( mnTimeout );
+}
+
+AutoTimer::AutoTimer( const char *pDebugName )
+ : Timer( true, pDebugName )
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/app/unohelp.cxx b/vcl/source/app/unohelp.cxx
new file mode 100644
index 0000000000..89b526c91f
--- /dev/null
+++ b/vcl/source/app/unohelp.cxx
@@ -0,0 +1,213 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vcl/svapp.hxx>
+#include <vcl/unohelp.hxx>
+
+#include <osl/diagnose.h>
+
+#include <comphelper/processfactory.hxx>
+
+#include <com/sun/star/i18n/BreakIterator.hpp>
+#include <com/sun/star/i18n/CharacterClassification.hpp>
+#include <com/sun/star/awt/FontWeight.hpp>
+#include <com/sun/star/awt/FontWidth.hpp>
+#include <com/sun/star/awt/XExtendedToolkit.hpp>
+#include <com/sun/star/accessibility/AccessibleEventObject.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+
+using namespace ::com::sun::star;
+
+uno::Reference < i18n::XBreakIterator > vcl::unohelper::CreateBreakIterator()
+{
+ uno::Reference< uno::XComponentContext > xContext = comphelper::getProcessComponentContext();
+ return i18n::BreakIterator::create(xContext);
+}
+
+uno::Reference < i18n::XCharacterClassification > vcl::unohelper::CreateCharacterClassification()
+{
+ return i18n::CharacterClassification::create( comphelper::getProcessComponentContext() );
+}
+
+float vcl::unohelper::ConvertFontWidth( FontWidth eWidth )
+{
+ if( eWidth == WIDTH_DONTKNOW )
+ return css::awt::FontWidth::DONTKNOW;
+ else if( eWidth == WIDTH_ULTRA_CONDENSED )
+ return css::awt::FontWidth::ULTRACONDENSED;
+ else if( eWidth == WIDTH_EXTRA_CONDENSED )
+ return css::awt::FontWidth::EXTRACONDENSED;
+ else if( eWidth == WIDTH_CONDENSED )
+ return css::awt::FontWidth::CONDENSED;
+ else if( eWidth == WIDTH_SEMI_CONDENSED )
+ return css::awt::FontWidth::SEMICONDENSED;
+ else if( eWidth == WIDTH_NORMAL )
+ return css::awt::FontWidth::NORMAL;
+ else if( eWidth == WIDTH_SEMI_EXPANDED )
+ return css::awt::FontWidth::SEMIEXPANDED;
+ else if( eWidth == WIDTH_EXPANDED )
+ return css::awt::FontWidth::EXPANDED;
+ else if( eWidth == WIDTH_EXTRA_EXPANDED )
+ return css::awt::FontWidth::EXTRAEXPANDED;
+ else if( eWidth == WIDTH_ULTRA_EXPANDED )
+ return css::awt::FontWidth::ULTRAEXPANDED;
+
+ OSL_FAIL( "Unknown FontWidth" );
+ return css::awt::FontWidth::DONTKNOW;
+}
+
+FontWidth vcl::unohelper::ConvertFontWidth( float f )
+{
+ if( f <= css::awt::FontWidth::DONTKNOW )
+ return WIDTH_DONTKNOW;
+ else if( f <= css::awt::FontWidth::ULTRACONDENSED )
+ return WIDTH_ULTRA_CONDENSED;
+ else if( f <= css::awt::FontWidth::EXTRACONDENSED )
+ return WIDTH_EXTRA_CONDENSED;
+ else if( f <= css::awt::FontWidth::CONDENSED )
+ return WIDTH_CONDENSED;
+ else if( f <= css::awt::FontWidth::SEMICONDENSED )
+ return WIDTH_SEMI_CONDENSED;
+ else if( f <= css::awt::FontWidth::NORMAL )
+ return WIDTH_NORMAL;
+ else if( f <= css::awt::FontWidth::SEMIEXPANDED )
+ return WIDTH_SEMI_EXPANDED;
+ else if( f <= css::awt::FontWidth::EXPANDED )
+ return WIDTH_EXPANDED;
+ else if( f <= css::awt::FontWidth::EXTRAEXPANDED )
+ return WIDTH_EXTRA_EXPANDED;
+ else if( f <= css::awt::FontWidth::ULTRAEXPANDED )
+ return WIDTH_ULTRA_EXPANDED;
+
+ OSL_FAIL( "Unknown FontWidth" );
+ return WIDTH_DONTKNOW;
+}
+
+float vcl::unohelper::ConvertFontWeight( FontWeight eWeight )
+{
+ if( eWeight == WEIGHT_DONTKNOW )
+ return css::awt::FontWeight::DONTKNOW;
+ else if( eWeight == WEIGHT_THIN )
+ return css::awt::FontWeight::THIN;
+ else if( eWeight == WEIGHT_ULTRALIGHT )
+ return css::awt::FontWeight::ULTRALIGHT;
+ else if( eWeight == WEIGHT_LIGHT )
+ return css::awt::FontWeight::LIGHT;
+ else if( eWeight == WEIGHT_SEMILIGHT )
+ return css::awt::FontWeight::SEMILIGHT;
+ else if( ( eWeight == WEIGHT_NORMAL ) || ( eWeight == WEIGHT_MEDIUM ) )
+ return css::awt::FontWeight::NORMAL;
+ else if( eWeight == WEIGHT_SEMIBOLD )
+ return css::awt::FontWeight::SEMIBOLD;
+ else if( eWeight == WEIGHT_BOLD )
+ return css::awt::FontWeight::BOLD;
+ else if( eWeight == WEIGHT_ULTRABOLD )
+ return css::awt::FontWeight::ULTRABOLD;
+ else if( eWeight == WEIGHT_BLACK )
+ return css::awt::FontWeight::BLACK;
+
+ OSL_FAIL( "Unknown FontWeight" );
+ return css::awt::FontWeight::DONTKNOW;
+}
+
+FontWeight vcl::unohelper::ConvertFontWeight( float f )
+{
+ if( f <= css::awt::FontWeight::DONTKNOW )
+ return WEIGHT_DONTKNOW;
+ else if( f <= css::awt::FontWeight::THIN )
+ return WEIGHT_THIN;
+ else if( f <= css::awt::FontWeight::ULTRALIGHT )
+ return WEIGHT_ULTRALIGHT;
+ else if( f <= css::awt::FontWeight::LIGHT )
+ return WEIGHT_LIGHT;
+ else if( f <= css::awt::FontWeight::SEMILIGHT )
+ return WEIGHT_SEMILIGHT;
+ else if( f <= css::awt::FontWeight::NORMAL )
+ return WEIGHT_NORMAL;
+ else if( f <= css::awt::FontWeight::SEMIBOLD )
+ return WEIGHT_SEMIBOLD;
+ else if( f <= css::awt::FontWeight::BOLD )
+ return WEIGHT_BOLD;
+ else if( f <= css::awt::FontWeight::ULTRABOLD )
+ return WEIGHT_ULTRABOLD;
+ else if( f <= css::awt::FontWeight::BLACK )
+ return WEIGHT_BLACK;
+
+ OSL_FAIL( "Unknown FontWeight" );
+ return WEIGHT_DONTKNOW;
+}
+
+css::awt::FontSlant vcl::unohelper::ConvertFontSlant(FontItalic eItalic)
+{
+ css::awt::FontSlant eRet(css::awt::FontSlant_DONTKNOW);
+ switch (eItalic)
+ {
+ case ITALIC_NONE:
+ eRet = css::awt::FontSlant_NONE;
+ break;
+ case ITALIC_OBLIQUE:
+ eRet = css::awt::FontSlant_OBLIQUE;
+ break;
+ case ITALIC_NORMAL:
+ eRet = css::awt::FontSlant_ITALIC;
+ break;
+ case ITALIC_DONTKNOW:
+ eRet = css::awt::FontSlant_DONTKNOW;
+ break;
+ case FontItalic_FORCE_EQUAL_SIZE:
+ eRet = css::awt::FontSlant::FontSlant_MAKE_FIXED_SIZE;
+ break;
+ }
+ return eRet;
+}
+
+FontItalic vcl::unohelper::ConvertFontSlant(css::awt::FontSlant eSlant)
+{
+ FontItalic eRet = ITALIC_DONTKNOW;
+ switch (eSlant)
+ {
+ case css::awt::FontSlant_NONE:
+ eRet = ITALIC_NONE;
+ break;
+ case css::awt::FontSlant_OBLIQUE:
+ eRet = ITALIC_OBLIQUE;
+ break;
+ case css::awt::FontSlant_ITALIC:
+ eRet = ITALIC_NORMAL;
+ break;
+ case css::awt::FontSlant_DONTKNOW:
+ eRet = ITALIC_DONTKNOW;
+ break;
+ case css::awt::FontSlant_REVERSE_OBLIQUE:
+ //there is no vcl reverse oblique
+ eRet = ITALIC_OBLIQUE;
+ break;
+ case css::awt::FontSlant_REVERSE_ITALIC:
+ //there is no vcl reverse normal
+ eRet = ITALIC_NORMAL;
+ break;
+ case css::awt::FontSlant::FontSlant_MAKE_FIXED_SIZE:
+ eRet = FontItalic_FORCE_EQUAL_SIZE;
+ break;
+ }
+ return eRet;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/app/unohelp2.cxx b/vcl/source/app/unohelp2.cxx
new file mode 100644
index 0000000000..575b9c7441
--- /dev/null
+++ b/vcl/source/app/unohelp2.cxx
@@ -0,0 +1,113 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/log.hxx>
+#include <utility>
+#include <vcl/unohelp2.hxx>
+#include <sot/exchange.hxx>
+#include <sot/formats.hxx>
+#include <vcl/svapp.hxx>
+#include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp>
+#include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
+#include <com/sun/star/datatransfer/clipboard/XFlushableClipboard.hpp>
+#include <cppuhelper/queryinterface.hxx>
+#include <boost/property_tree/json_parser.hpp>
+#include <comphelper/lok.hxx>
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+
+using namespace ::com::sun::star;
+
+namespace vcl::unohelper {
+
+ TextDataObject::TextDataObject( OUString aText ) : maText(std::move( aText ))
+ {
+ }
+
+ TextDataObject::~TextDataObject()
+ {
+ }
+
+ void TextDataObject::CopyStringTo( const OUString& rContent,
+ const uno::Reference< datatransfer::clipboard::XClipboard >& rxClipboard,
+ const vcl::ILibreOfficeKitNotifier* pNotifier)
+ {
+ SAL_WARN_IF( !rxClipboard.is(), "vcl", "TextDataObject::CopyStringTo: invalid clipboard!" );
+ if ( !rxClipboard.is() )
+ return;
+
+ rtl::Reference<TextDataObject> pDataObj = new TextDataObject( rContent );
+
+ SolarMutexReleaser aReleaser;
+ try
+ {
+ rxClipboard->setContents( pDataObj, nullptr );
+
+ uno::Reference< datatransfer::clipboard::XFlushableClipboard > xFlushableClipboard( rxClipboard, uno::UNO_QUERY );
+ if( xFlushableClipboard.is() )
+ xFlushableClipboard->flushClipboard();
+
+ if (pNotifier != nullptr && comphelper::LibreOfficeKit::isActive())
+ {
+ boost::property_tree::ptree aTree;
+ aTree.put("content", rContent);
+ aTree.put("mimeType", "text/plain");
+ std::stringstream aStream;
+ boost::property_tree::write_json(aStream, aTree);
+ pNotifier->libreOfficeKitViewCallback(LOK_CALLBACK_CLIPBOARD_CHANGED, OString(aStream.str()));
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ }
+ }
+
+ // css::uno::XInterface
+ uno::Any TextDataObject::queryInterface( const uno::Type & rType )
+ {
+ uno::Any aRet = ::cppu::queryInterface( rType, static_cast< datatransfer::XTransferable* >(this) );
+ return (aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType ));
+ }
+
+ // css::datatransfer::XTransferable
+ uno::Any TextDataObject::getTransferData( const datatransfer::DataFlavor& rFlavor )
+ {
+ SotClipboardFormatId nT = SotExchange::GetFormat( rFlavor );
+ if ( nT != SotClipboardFormatId::STRING )
+ {
+ throw datatransfer::UnsupportedFlavorException();
+ }
+ return uno::Any(maText);
+ }
+
+ uno::Sequence< datatransfer::DataFlavor > TextDataObject::getTransferDataFlavors( )
+ {
+ uno::Sequence< datatransfer::DataFlavor > aDataFlavors(1);
+ SotExchange::GetFormatDataFlavor( SotClipboardFormatId::STRING, aDataFlavors.getArray()[0] );
+ return aDataFlavors;
+ }
+
+ sal_Bool TextDataObject::isDataFlavorSupported( const datatransfer::DataFlavor& rFlavor )
+ {
+ SotClipboardFormatId nT = SotExchange::GetFormat( rFlavor );
+ return ( nT == SotClipboardFormatId::STRING );
+ }
+
+} // namespace vcl::unohelper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/app/vclevent.cxx b/vcl/source/app/vclevent.cxx
new file mode 100644
index 0000000000..9e8bdb7d1e
--- /dev/null
+++ b/vcl/source/app/vclevent.cxx
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vcl/vclevent.hxx>
+#include <vcl/window.hxx>
+#include <vcl/menu.hxx>
+
+#include <vcleventlisteners.hxx>
+
+void VclEventListeners::Call( VclSimpleEvent& rEvent ) const
+{
+ if ( m_aListeners.empty() )
+ return;
+
+ // Copy the list, because this can be destroyed when calling a Link...
+ std::vector<Link<VclSimpleEvent&,void>> aCopy( m_aListeners );
+ std::vector<Link<VclSimpleEvent&,void>>::iterator aIter( aCopy.begin() );
+ std::vector<Link<VclSimpleEvent&,void>>::const_iterator aEnd( aCopy.end() );
+ m_updated = false;
+ if (VclWindowEvent* pWindowEvent = dynamic_cast<VclWindowEvent*>(&rEvent))
+ {
+ VclPtr<vcl::Window> xWin(pWindowEvent->GetWindow());
+ // checking mpWindowImpl to see if disposal is complete yet
+ while ( aIter != aEnd && (!xWin || xWin->mpWindowImpl) )
+ {
+ Link<VclSimpleEvent&,void> &rLink = *aIter;
+ // check this hasn't been removed in some re-enterancy scenario fdo#47368
+ // But only check if the list actually has been changed.
+ if( !m_updated || std::find(m_aListeners.begin(), m_aListeners.end(), rLink) != m_aListeners.end() )
+ rLink.Call( rEvent );
+ ++aIter;
+ }
+ }
+ else
+ {
+ while ( aIter != aEnd )
+ {
+ Link<VclSimpleEvent&,void> &rLink = *aIter;
+ if( !m_updated || std::find(m_aListeners.begin(), m_aListeners.end(), rLink) != m_aListeners.end() )
+ rLink.Call( rEvent );
+ ++aIter;
+ }
+ }
+}
+
+void VclEventListeners::addListener( const Link<VclSimpleEvent&,void>& rListener )
+{
+ m_aListeners.push_back( rListener );
+ m_updated = true;
+}
+
+void VclEventListeners::removeListener( const Link<VclSimpleEvent&,void>& rListener )
+{
+ std::erase(m_aListeners, rListener);
+ m_updated = true;
+}
+
+VclWindowEvent::VclWindowEvent( vcl::Window* pWin, VclEventId n, void* pDat ) : VclSimpleEvent(n)
+{
+ pWindow = pWin; pData = pDat;
+}
+
+VclWindowEvent::~VclWindowEvent() {}
+
+VclMenuEvent::VclMenuEvent( Menu* pM, VclEventId n, sal_uInt16 nPos )
+ : VclSimpleEvent(n), pMenu(pM), mnPos(nPos)
+{}
+
+VclMenuEvent::~VclMenuEvent()
+{}
+
+Menu* VclMenuEvent::GetMenu() const
+{
+ return pMenu;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/app/watchdog.cxx b/vcl/source/app/watchdog.cxx
new file mode 100644
index 0000000000..dc2153e639
--- /dev/null
+++ b/vcl/source/app/watchdog.cxx
@@ -0,0 +1,168 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <watchdog.hxx>
+
+#include <config_features.h>
+
+#include <osl/conditn.hxx>
+#include <rtl/ref.hxx>
+#include <rtl/string.hxx>
+#include <sal/log.hxx>
+#include <comphelper/debuggerinfo.hxx>
+#include <opengl/zone.hxx>
+#include <skia/zone.hxx>
+
+#include <stdlib.h>
+
+#if defined HAVE_VALGRIND_HEADERS
+#include <valgrind/memcheck.h>
+#endif
+
+#include <atomic>
+
+namespace
+{
+std::atomic<bool> gbWatchdogFiring = false;
+osl::Condition* gpWatchdogExit = nullptr;
+rtl::Reference<WatchdogThread> gxWatchdog;
+
+template <typename Zone> struct WatchdogHelper
+{
+ static inline sal_uInt64 nLastEnters = 0;
+ static inline int nUnchanged = 0; // how many unchanged nEnters
+ static inline bool bFired = false;
+ static inline bool bAbortFired = false;
+ static void setLastEnters() { nLastEnters = Zone::enterCount(); }
+ static void check()
+ {
+ if (Zone::isInZone())
+ {
+ const CrashWatchdogTimingsValues& aTimingValues = Zone::getCrashWatchdogTimingsValues();
+
+ if (nLastEnters == Zone::enterCount())
+ nUnchanged++;
+ else
+ nUnchanged = 0;
+ Zone::checkDebug(nUnchanged, aTimingValues);
+
+ // Not making progress
+ if (nUnchanged >= aTimingValues.mnDisableEntries)
+ {
+ if (!bFired)
+ {
+ gbWatchdogFiring = true;
+ SAL_WARN("vcl.watchdog", "Watchdog triggered: hard disable " << Zone::name());
+#ifdef DBG_UTIL
+ std::abort();
+#else
+ Zone::hardDisable();
+ gbWatchdogFiring = false;
+#endif
+ }
+ bFired = true;
+
+ // we can hang using VCL in the abort handling -> be impatient
+ if (bAbortFired)
+ {
+ SAL_WARN("vcl.watchdog", "Watchdog gave up: hard exiting " << Zone::name());
+ _Exit(1);
+ }
+ }
+
+ // Not making even more progress
+ if (nUnchanged >= aTimingValues.mnAbortAfter)
+ {
+ if (!bAbortFired)
+ {
+ SAL_WARN("vcl.watchdog", "Watchdog gave up: aborting " << Zone::name());
+ gbWatchdogFiring = true;
+ std::abort();
+ }
+ // coverity[dead_error_line] - we might have caught SIGABRT and failed to exit yet
+ bAbortFired = true;
+ }
+ }
+ else
+ {
+ nUnchanged = 0;
+ }
+ }
+};
+
+} // namespace
+
+WatchdogThread::WatchdogThread()
+ : salhelper::Thread("Crash Watchdog")
+{
+}
+
+void WatchdogThread::execute()
+{
+ TimeValue aQuarterSecond(0, 1000 * 1000 * 1000 * 0.25);
+ do
+ {
+#if HAVE_FEATURE_OPENGL
+ WatchdogHelper<OpenGLZone>::setLastEnters();
+#endif
+#if HAVE_FEATURE_SKIA
+ WatchdogHelper<SkiaZone>::setLastEnters();
+#endif
+
+ gpWatchdogExit->wait(&aQuarterSecond);
+
+#if defined HAVE_VALGRIND_HEADERS
+ if (RUNNING_ON_VALGRIND)
+ continue;
+#endif
+#if defined DBG_UTIL
+ if (comphelper::isDebuggerAttached())
+ continue;
+#endif
+
+#if HAVE_FEATURE_OPENGL
+ WatchdogHelper<OpenGLZone>::check();
+#endif
+#if HAVE_FEATURE_SKIA
+ WatchdogHelper<SkiaZone>::check();
+#endif
+
+ } while (!gpWatchdogExit->check());
+}
+
+void WatchdogThread::start()
+{
+ if (gxWatchdog != nullptr)
+ return; // already running
+ if (getenv("SAL_DISABLE_WATCHDOG"))
+ return;
+ gpWatchdogExit = new osl::Condition();
+ gxWatchdog.set(new WatchdogThread());
+ gxWatchdog->launch();
+}
+
+void WatchdogThread::stop()
+{
+ if (gbWatchdogFiring)
+ return; // in watchdog thread
+
+ if (gpWatchdogExit)
+ gpWatchdogExit->set();
+
+ if (gxWatchdog.is())
+ {
+ gxWatchdog->join();
+ gxWatchdog.clear();
+ }
+
+ delete gpWatchdogExit;
+ gpWatchdogExit = nullptr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/app/weldutils.cxx b/vcl/source/app/weldutils.cxx
new file mode 100644
index 0000000000..235e3140ad
--- /dev/null
+++ b/vcl/source/app/weldutils.cxx
@@ -0,0 +1,662 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <com/sun/star/util/URLTransformer.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <comphelper/processfactory.hxx>
+#include <svl/numformat.hxx>
+#include <svl/zforlist.hxx>
+#include <svl/zformat.hxx>
+#include <vcl/builderpage.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/commandinfoprovider.hxx>
+#include <vcl/event.hxx>
+#include <vcl/toolkit/floatwin.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weldutils.hxx>
+
+BuilderPage::BuilderPage(weld::Widget* pParent, weld::DialogController* pController,
+ const OUString& rUIXMLDescription, const OUString& rID, bool bIsMobile)
+ : m_pDialogController(pController)
+ , m_xBuilder(Application::CreateBuilder(pParent, rUIXMLDescription, bIsMobile))
+ , m_xContainer(m_xBuilder->weld_container(rID))
+{
+}
+
+void BuilderPage::Activate() {}
+
+void BuilderPage::Deactivate() {}
+
+BuilderPage::~BuilderPage() COVERITY_NOEXCEPT_FALSE {}
+
+namespace weld
+{
+bool DialogController::runAsync(const std::shared_ptr<DialogController>& rController,
+ const std::function<void(sal_Int32)>& func)
+{
+ return rController->getDialog()->runAsync(rController, func);
+}
+
+DialogController::~DialogController() COVERITY_NOEXCEPT_FALSE {}
+
+Dialog* GenericDialogController::getDialog() { return m_xDialog.get(); }
+
+GenericDialogController::GenericDialogController(weld::Widget* pParent, const OUString& rUIFile,
+ const OUString& rDialogId, bool bMobile)
+ : m_xBuilder(Application::CreateBuilder(pParent, rUIFile, bMobile))
+ , m_xDialog(m_xBuilder->weld_dialog(rDialogId))
+{
+}
+
+GenericDialogController::~GenericDialogController() COVERITY_NOEXCEPT_FALSE {}
+
+Dialog* MessageDialogController::getDialog() { return m_xDialog.get(); }
+
+MessageDialogController::MessageDialogController(weld::Widget* pParent, const OUString& rUIFile,
+ const OUString& rDialogId,
+ const OUString& rRelocateId)
+ : m_xBuilder(Application::CreateBuilder(pParent, rUIFile))
+ , m_xDialog(m_xBuilder->weld_message_dialog(rDialogId))
+ , m_xContentArea(m_xDialog->weld_message_area())
+{
+ if (!rRelocateId.isEmpty())
+ {
+ m_xRelocate = m_xBuilder->weld_container(rRelocateId);
+ m_xOrigParent = m_xRelocate->weld_parent();
+ //fdo#75121, a bit tricky because the widgets we want to align with
+ //don't actually exist in the ui description, they're implied
+ m_xOrigParent->move(m_xRelocate.get(), m_xContentArea.get());
+ }
+}
+
+MessageDialogController::~MessageDialogController()
+{
+ if (m_xRelocate)
+ {
+ m_xContentArea->move(m_xRelocate.get(), m_xOrigParent.get());
+ }
+}
+
+AssistantController::AssistantController(weld::Widget* pParent, const OUString& rUIFile,
+ const OUString& rDialogId)
+ : m_xBuilder(Application::CreateBuilder(pParent, rUIFile))
+ , m_xAssistant(m_xBuilder->weld_assistant(rDialogId))
+{
+}
+
+Dialog* AssistantController::getDialog() { return m_xAssistant.get(); }
+
+AssistantController::~AssistantController() {}
+
+void TriStateEnabled::ButtonToggled(weld::Toggleable& rToggle)
+{
+ if (bTriStateEnabled)
+ {
+ switch (eState)
+ {
+ case TRISTATE_INDET:
+ rToggle.set_state(TRISTATE_FALSE);
+ break;
+ case TRISTATE_TRUE:
+ rToggle.set_state(TRISTATE_INDET);
+ break;
+ case TRISTATE_FALSE:
+ rToggle.set_state(TRISTATE_TRUE);
+ break;
+ }
+ }
+ eState = rToggle.get_state();
+}
+
+void RemoveParentKeepChildren(weld::TreeView& rTreeView, const weld::TreeIter& rParent)
+{
+ if (rTreeView.iter_has_child(rParent))
+ {
+ std::unique_ptr<weld::TreeIter> xNewParent(rTreeView.make_iterator(&rParent));
+ if (!rTreeView.iter_parent(*xNewParent))
+ xNewParent.reset();
+
+ while (true)
+ {
+ std::unique_ptr<weld::TreeIter> xChild(rTreeView.make_iterator(&rParent));
+ if (!rTreeView.iter_children(*xChild))
+ break;
+ rTreeView.move_subtree(*xChild, xNewParent.get(), -1);
+ }
+ }
+ rTreeView.remove(rParent);
+}
+
+EntryFormatter::EntryFormatter(weld::FormattedSpinButton& rSpinButton)
+ : m_rEntry(rSpinButton)
+ , m_pSpinButton(&rSpinButton)
+ , m_eOptions(Application::GetSettings().GetStyleSettings().GetSelectionOptions())
+{
+ Init();
+}
+
+EntryFormatter::EntryFormatter(weld::Entry& rEntry)
+ : m_rEntry(rEntry)
+ , m_pSpinButton(nullptr)
+ , m_eOptions(Application::GetSettings().GetStyleSettings().GetSelectionOptions())
+{
+ Init();
+}
+
+EntryFormatter::~EntryFormatter()
+{
+ m_rEntry.connect_changed(Link<weld::Entry&, void>());
+ m_rEntry.connect_focus_out(Link<weld::Widget&, void>());
+ if (m_pSpinButton)
+ m_pSpinButton->SetFormatter(nullptr);
+}
+
+void EntryFormatter::Init()
+{
+ m_rEntry.connect_changed(LINK(this, EntryFormatter, ModifyHdl));
+ m_rEntry.connect_focus_out(LINK(this, EntryFormatter, FocusOutHdl));
+ if (m_pSpinButton)
+ m_pSpinButton->SetFormatter(this);
+}
+
+Selection EntryFormatter::GetEntrySelection() const
+{
+ int nStartPos, nEndPos;
+ m_rEntry.get_selection_bounds(nStartPos, nEndPos);
+ return Selection(nStartPos, nEndPos);
+}
+
+OUString EntryFormatter::GetEntryText() const { return m_rEntry.get_text(); }
+
+void EntryFormatter::SetEntryText(const OUString& rText, const Selection& rSel)
+{
+ m_rEntry.set_text(rText);
+ auto nMin = rSel.Min();
+ auto nMax = rSel.Max();
+ m_rEntry.select_region(nMin < 0 ? 0 : nMin, nMax == SELECTION_MAX ? -1 : nMax);
+}
+
+void EntryFormatter::SetEntryTextColor(const Color* pColor)
+{
+ m_rEntry.set_font_color(pColor ? *pColor : COL_AUTO);
+}
+
+void EntryFormatter::UpdateCurrentValue(double dCurrentValue)
+{
+ Formatter::UpdateCurrentValue(dCurrentValue);
+ if (m_pSpinButton)
+ m_pSpinButton->sync_value_from_formatter();
+}
+
+void EntryFormatter::ClearMinValue()
+{
+ Formatter::ClearMinValue();
+ if (m_pSpinButton)
+ m_pSpinButton->sync_range_from_formatter();
+}
+
+void EntryFormatter::SetMinValue(double dMin)
+{
+ Formatter::SetMinValue(dMin);
+ if (m_pSpinButton)
+ m_pSpinButton->sync_range_from_formatter();
+}
+
+void EntryFormatter::ClearMaxValue()
+{
+ Formatter::ClearMaxValue();
+ if (m_pSpinButton)
+ m_pSpinButton->sync_range_from_formatter();
+}
+
+void EntryFormatter::SetMaxValue(double dMin)
+{
+ Formatter::SetMaxValue(dMin);
+ if (m_pSpinButton)
+ m_pSpinButton->sync_range_from_formatter();
+}
+
+void EntryFormatter::SetSpinSize(double dStep)
+{
+ Formatter::SetSpinSize(dStep);
+ if (m_pSpinButton)
+ m_pSpinButton->sync_increments_from_formatter();
+}
+
+SelectionOptions EntryFormatter::GetEntrySelectionOptions() const { return m_eOptions; }
+
+void EntryFormatter::FieldModified() { m_aModifyHdl.Call(m_rEntry); }
+
+IMPL_LINK_NOARG(EntryFormatter, ModifyHdl, weld::Entry&, void)
+{
+ // This leads to FieldModified getting called at the end of Modify() and
+ // FieldModified then calls any modification callback
+ Modify();
+}
+
+IMPL_LINK_NOARG(EntryFormatter, FocusOutHdl, weld::Widget&, void)
+{
+ EntryLostFocus();
+ if (m_pSpinButton)
+ m_pSpinButton->signal_value_changed();
+ m_aFocusOutHdl.Call(m_rEntry);
+}
+
+DoubleNumericFormatter::DoubleNumericFormatter(weld::Entry& rEntry)
+ : EntryFormatter(rEntry)
+{
+ ResetConformanceTester();
+}
+
+DoubleNumericFormatter::DoubleNumericFormatter(weld::FormattedSpinButton& rSpinButton)
+ : EntryFormatter(rSpinButton)
+{
+ ResetConformanceTester();
+}
+
+DoubleNumericFormatter::~DoubleNumericFormatter() = default;
+
+void DoubleNumericFormatter::FormatChanged(FORMAT_CHANGE_TYPE nWhat)
+{
+ ResetConformanceTester();
+ EntryFormatter::FormatChanged(nWhat);
+}
+
+bool DoubleNumericFormatter::CheckText(const OUString& sText) const
+{
+ // We'd like to implement this using the NumberFormatter::IsNumberFormat, but unfortunately, this doesn't
+ // recognize fragments of numbers (like, for instance "1e", which happens during entering e.g. "1e10")
+ // Thus, the roundabout way via a regular expression
+ return m_pNumberValidator->isValidNumericFragment(sText);
+}
+
+void DoubleNumericFormatter::ResetConformanceTester()
+{
+ // the thousands and the decimal separator are language dependent
+ const SvNumberformat* pFormatEntry = GetOrCreateFormatter()->GetEntry(m_nFormatKey);
+
+ sal_Unicode cSeparatorThousand = ',';
+ sal_Unicode cSeparatorDecimal = '.';
+ if (pFormatEntry)
+ {
+ LocaleDataWrapper aLocaleInfo(LanguageTag(pFormatEntry->GetLanguage()));
+
+ OUString sSeparator = aLocaleInfo.getNumThousandSep();
+ if (!sSeparator.isEmpty())
+ cSeparatorThousand = sSeparator[0];
+
+ sSeparator = aLocaleInfo.getNumDecimalSep();
+ if (!sSeparator.isEmpty())
+ cSeparatorDecimal = sSeparator[0];
+ }
+
+ m_pNumberValidator.reset(
+ new validation::NumberValidator(cSeparatorThousand, cSeparatorDecimal));
+}
+
+LongCurrencyFormatter::LongCurrencyFormatter(weld::Entry& rEntry)
+ : EntryFormatter(rEntry)
+ , m_bThousandSep(true)
+{
+ Init();
+}
+
+LongCurrencyFormatter::LongCurrencyFormatter(weld::FormattedSpinButton& rSpinButton)
+ : EntryFormatter(rSpinButton)
+ , m_bThousandSep(true)
+{
+ Init();
+}
+
+void LongCurrencyFormatter::Init()
+{
+ SetOutputHdl(LINK(this, LongCurrencyFormatter, FormatOutputHdl));
+ SetInputHdl(LINK(this, LongCurrencyFormatter, ParseInputHdl));
+}
+
+void LongCurrencyFormatter::SetUseThousandSep(bool b)
+{
+ m_bThousandSep = b;
+ ReFormat();
+}
+
+void LongCurrencyFormatter::SetCurrencySymbol(const OUString& rStr)
+{
+ m_aCurrencySymbol = rStr;
+ ReFormat();
+}
+
+LongCurrencyFormatter::~LongCurrencyFormatter() = default;
+
+TimeFormatter::TimeFormatter(weld::Entry& rEntry)
+ : EntryFormatter(rEntry)
+ , m_eFormat(TimeFieldFormat::F_NONE)
+ , m_eTimeFormat(TimeFormat::Hour24)
+ , m_bDuration(false)
+{
+ Init();
+}
+
+TimeFormatter::TimeFormatter(weld::FormattedSpinButton& rSpinButton)
+ : EntryFormatter(rSpinButton)
+ , m_eFormat(TimeFieldFormat::F_NONE)
+ , m_eTimeFormat(TimeFormat::Hour24)
+ , m_bDuration(false)
+{
+ Init();
+}
+
+void TimeFormatter::Init()
+{
+ DisableRemainderFactor(); //so with hh::mm::ss, incrementing mm will not reset ss
+
+ SetOutputHdl(LINK(this, TimeFormatter, FormatOutputHdl));
+ SetInputHdl(LINK(this, TimeFormatter, ParseInputHdl));
+
+ SetMin(tools::Time(0, 0));
+ SetMax(tools::Time(23, 59, 59, 999999999));
+
+ // so the spin size can depend on which zone the cursor is in
+ get_widget().connect_cursor_position(LINK(this, TimeFormatter, CursorChangedHdl));
+ // and set the initial spin size
+ CursorChangedHdl(get_widget());
+}
+
+void TimeFormatter::SetExtFormat(ExtTimeFieldFormat eFormat)
+{
+ switch (eFormat)
+ {
+ case ExtTimeFieldFormat::Short24H:
+ {
+ m_eTimeFormat = TimeFormat::Hour24;
+ m_bDuration = false;
+ m_eFormat = TimeFieldFormat::F_NONE;
+ }
+ break;
+ case ExtTimeFieldFormat::Long24H:
+ {
+ m_eTimeFormat = TimeFormat::Hour24;
+ m_bDuration = false;
+ m_eFormat = TimeFieldFormat::F_SEC;
+ }
+ break;
+ case ExtTimeFieldFormat::Short12H:
+ {
+ m_eTimeFormat = TimeFormat::Hour12;
+ m_bDuration = false;
+ m_eFormat = TimeFieldFormat::F_NONE;
+ }
+ break;
+ case ExtTimeFieldFormat::Long12H:
+ {
+ m_eTimeFormat = TimeFormat::Hour12;
+ m_bDuration = false;
+ m_eFormat = TimeFieldFormat::F_SEC;
+ }
+ break;
+ case ExtTimeFieldFormat::ShortDuration:
+ {
+ m_bDuration = true;
+ m_eFormat = TimeFieldFormat::F_NONE;
+ }
+ break;
+ case ExtTimeFieldFormat::LongDuration:
+ {
+ m_bDuration = true;
+ m_eFormat = TimeFieldFormat::F_SEC;
+ }
+ break;
+ }
+
+ ReFormat();
+}
+
+void TimeFormatter::SetDuration(bool bDuration)
+{
+ m_bDuration = bDuration;
+ ReFormat();
+}
+
+void TimeFormatter::SetTimeFormat(TimeFieldFormat eTimeFormat)
+{
+ m_eFormat = eTimeFormat;
+ ReFormat();
+}
+
+TimeFormatter::~TimeFormatter() = default;
+
+DateFormatter::DateFormatter(weld::Entry& rEntry)
+ : EntryFormatter(rEntry)
+ , m_eFormat(ExtDateFieldFormat::SystemShort)
+{
+ Init();
+}
+
+void DateFormatter::Init()
+{
+ SetOutputHdl(LINK(this, DateFormatter, FormatOutputHdl));
+ SetInputHdl(LINK(this, DateFormatter, ParseInputHdl));
+
+ SetMin(Date(1, 1, 1900));
+ SetMax(Date(31, 12, 2200));
+}
+
+void DateFormatter::SetExtDateFormat(ExtDateFieldFormat eFormat)
+{
+ m_eFormat = eFormat;
+ ReFormat();
+}
+
+DateFormatter::~DateFormatter() = default;
+
+PatternFormatter::PatternFormatter(weld::Entry& rEntry)
+ : m_rEntry(rEntry)
+ , m_bStrictFormat(false)
+ , m_bSameMask(true)
+ , m_bReformat(false)
+ , m_bInPattKeyInput(false)
+{
+ m_rEntry.connect_changed(LINK(this, PatternFormatter, ModifyHdl));
+ m_rEntry.connect_focus_in(LINK(this, PatternFormatter, FocusInHdl));
+ m_rEntry.connect_focus_out(LINK(this, PatternFormatter, FocusOutHdl));
+ m_rEntry.connect_key_press(LINK(this, PatternFormatter, KeyInputHdl));
+}
+
+IMPL_LINK_NOARG(PatternFormatter, ModifyHdl, weld::Entry&, void) { Modify(); }
+
+IMPL_LINK_NOARG(PatternFormatter, FocusOutHdl, weld::Widget&, void)
+{
+ EntryLostFocus();
+ m_aFocusOutHdl.Call(m_rEntry);
+}
+
+IMPL_LINK_NOARG(PatternFormatter, FocusInHdl, weld::Widget&, void)
+{
+ EntryGainFocus();
+ m_aFocusInHdl.Call(m_rEntry);
+}
+
+PatternFormatter::~PatternFormatter()
+{
+ m_rEntry.connect_changed(Link<weld::Entry&, void>());
+ m_rEntry.connect_focus_out(Link<weld::Widget&, void>());
+}
+
+int GetMinimumEditHeight()
+{
+ // load this little .ui just to measure the height of an Entry
+ std::unique_ptr<weld::Builder> xBuilder(
+ Application::CreateBuilder(nullptr, "cui/ui/namedialog.ui"));
+ std::unique_ptr<weld::Entry> xEntry(xBuilder->weld_entry("name_entry"));
+ return xEntry->get_preferred_size().Height();
+}
+
+WidgetStatusListener::WidgetStatusListener(weld::Widget* widget, const OUString& aCommand)
+ : mWidget(widget)
+{
+ css::uno::Reference<css::uno::XComponentContext> xContext
+ = ::comphelper::getProcessComponentContext();
+ css::uno::Reference<css::frame::XDesktop2> xDesktop = css::frame::Desktop::create(xContext);
+
+ css::uno::Reference<css::frame::XFrame> xFrame(xDesktop->getActiveFrame());
+ if (!xFrame.is())
+ xFrame = xDesktop;
+
+ mxFrame = xFrame;
+
+ maCommandURL.Complete = aCommand;
+ css::uno::Reference<css::util::XURLTransformer> xParser
+ = css::util::URLTransformer::create(xContext);
+ xParser->parseStrict(maCommandURL);
+}
+
+void WidgetStatusListener::startListening()
+{
+ if (mxDispatch.is())
+ mxDispatch->removeStatusListener(this, maCommandURL);
+
+ css::uno::Reference<css::frame::XDispatchProvider> xDispatchProvider(mxFrame,
+ css::uno::UNO_QUERY);
+ if (!xDispatchProvider.is())
+ return;
+
+ mxDispatch = xDispatchProvider->queryDispatch(maCommandURL, "", 0);
+ if (mxDispatch.is())
+ mxDispatch->addStatusListener(this, maCommandURL);
+}
+
+void WidgetStatusListener::statusChanged(const css::frame::FeatureStateEvent& rEvent)
+{
+ mWidget->set_sensitive(rEvent.IsEnabled);
+}
+
+void WidgetStatusListener::disposing(const css::lang::EventObject& /*Source*/)
+{
+ mxDispatch.clear();
+}
+
+void WidgetStatusListener::dispose()
+{
+ if (mxDispatch.is())
+ {
+ mxDispatch->removeStatusListener(this, maCommandURL);
+ mxDispatch.clear();
+ }
+ mxFrame.clear();
+ mWidget = nullptr;
+}
+
+ButtonPressRepeater::ButtonPressRepeater(weld::Button& rButton, const Link<Button&, void>& rLink,
+ const Link<const CommandEvent&, void>& rContextLink)
+ : m_rButton(rButton)
+ , m_aRepeat("vcl ButtonPressRepeater m_aRepeat")
+ , m_aLink(rLink)
+ , m_aContextLink(rContextLink)
+ , m_bModKey(false)
+{
+ // instead of connect_clicked because we want a button held down to
+ // repeat the next/prev
+ m_rButton.connect_mouse_press(LINK(this, ButtonPressRepeater, MousePressHdl));
+ m_rButton.connect_mouse_release(LINK(this, ButtonPressRepeater, MouseReleaseHdl));
+
+ m_aRepeat.SetInvokeHandler(LINK(this, ButtonPressRepeater, RepeatTimerHdl));
+}
+
+IMPL_LINK(ButtonPressRepeater, MousePressHdl, const MouseEvent&, rMouseEvent, bool)
+{
+ if (rMouseEvent.IsRight())
+ {
+ m_aContextLink.Call(
+ CommandEvent(rMouseEvent.GetPosPixel(), CommandEventId::ContextMenu, true));
+ return false;
+ }
+ m_bModKey = rMouseEvent.IsMod1();
+ if (!m_rButton.get_sensitive())
+ return false;
+ auto self = weak_from_this();
+ RepeatTimerHdl(nullptr);
+ if (!self.lock())
+ return false;
+ if (!m_rButton.get_sensitive())
+ return false;
+ m_aRepeat.SetTimeout(MouseSettings::GetButtonStartRepeat());
+ m_aRepeat.Start();
+ return true;
+}
+
+IMPL_LINK_NOARG(ButtonPressRepeater, MouseReleaseHdl, const MouseEvent&, bool)
+{
+ m_bModKey = false;
+ m_aRepeat.Stop();
+ return true;
+}
+
+IMPL_LINK_NOARG(ButtonPressRepeater, RepeatTimerHdl, Timer*, void)
+{
+ m_aRepeat.SetTimeout(Application::GetSettings().GetMouseSettings().GetButtonRepeat());
+ m_aLink.Call(m_rButton);
+}
+
+weld::Window* GetPopupParent(vcl::Window& rOutWin, tools::Rectangle& rRect)
+{
+ rRect.SetPos(rOutWin.OutputToScreenPixel(rRect.TopLeft()));
+ AbsoluteScreenPixelRectangle aRectAbs = FloatingWindow::ImplConvertToAbsPos(&rOutWin, rRect);
+
+ vcl::Window* pWin = rOutWin.GetFrameWindow();
+
+ rRect = FloatingWindow::ImplConvertToRelPos(pWin, aRectAbs);
+ rRect.SetPos(pWin->ScreenToOutputPixel(rRect.TopLeft()));
+
+ return rOutWin.GetFrameWeld();
+}
+
+void SetPointFont(OutputDevice& rDevice, const vcl::Font& rFont, bool bUseDeviceDPI)
+{
+ auto pDefaultDevice = Application::GetDefaultDevice();
+ if (pDefaultDevice)
+ if (vcl::Window* pDefaultWindow = pDefaultDevice->GetOwnerWindow())
+ pDefaultWindow->SetPointFont(rDevice, rFont, bUseDeviceDPI);
+}
+
+ReorderingDropTarget::ReorderingDropTarget(weld::TreeView& rTreeView)
+ : DropTargetHelper(rTreeView.get_drop_target())
+ , m_rTreeView(rTreeView)
+{
+}
+
+sal_Int8 ReorderingDropTarget::AcceptDrop(const AcceptDropEvent& rEvt)
+{
+ // to enable the autoscroll when we're close to the edges
+ m_rTreeView.get_dest_row_at_pos(rEvt.maPosPixel, nullptr, true);
+ return DND_ACTION_MOVE;
+}
+
+sal_Int8 ReorderingDropTarget::ExecuteDrop(const ExecuteDropEvent& rEvt)
+{
+ weld::TreeView* pSource = m_rTreeView.get_drag_source();
+ // only dragging within the same widget allowed
+ if (!pSource || pSource != &m_rTreeView)
+ return DND_ACTION_NONE;
+
+ std::unique_ptr<weld::TreeIter> xSource(m_rTreeView.make_iterator());
+ if (!m_rTreeView.get_selected(xSource.get()))
+ return DND_ACTION_NONE;
+
+ std::unique_ptr<weld::TreeIter> xTarget(m_rTreeView.make_iterator());
+ int nTargetPos = -1;
+ if (m_rTreeView.get_dest_row_at_pos(rEvt.maPosPixel, xTarget.get(), true))
+ nTargetPos = m_rTreeView.get_iter_index_in_parent(*xTarget);
+ m_rTreeView.move_subtree(*xSource, nullptr, nTargetPos);
+
+ return DND_ACTION_NONE;
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/app/winscheduler.cxx b/vcl/source/app/winscheduler.cxx
new file mode 100644
index 0000000000..0398faaa49
--- /dev/null
+++ b/vcl/source/app/winscheduler.cxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifdef _WIN32
+
+#include <sal/config.h>
+
+#include <sal/log.hxx>
+#include <vcl/winscheduler.hxx>
+
+#include <svsys.h>
+#include <win/saldata.hxx>
+#include <win/salinst.h>
+
+namespace
+{
+void PostMessageToComWnd(UINT nMsg)
+{
+ bool const ret = PostMessageW(GetSalData()->mpInstance->mhComWnd, nMsg, 0, 0);
+ SAL_WARN_IF(!ret, "vcl.schedule", "ERROR: PostMessage() failed!");
+}
+}
+
+void WinScheduler::SetForceRealTimer() { PostMessageToComWnd(SAL_MSG_FORCE_REAL_TIMER); }
+
+void WinScheduler::PostDummyMessage() { PostMessageToComWnd(SAL_MSG_DUMMY); }
+
+#endif // _WIN32
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */