summaryrefslogtreecommitdiffstats
path: root/vcl/source/app
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--vcl/source/app/ITiledRenderable.cxx81
-rw-r--r--vcl/source/app/IconThemeInfo.cxx188
-rw-r--r--vcl/source/app/IconThemeScanner.cxx215
-rw-r--r--vcl/source/app/IconThemeSelector.cxx175
-rw-r--r--vcl/source/app/brand.cxx73
-rw-r--r--vcl/source/app/customweld.cxx105
-rw-r--r--vcl/source/app/dbggui.cxx50
-rw-r--r--vcl/source/app/dndhelp.cxx139
-rw-r--r--vcl/source/app/help.cxx677
-rw-r--r--vcl/source/app/i18nhelp.cxx160
-rw-r--r--vcl/source/app/idle.cxx65
-rw-r--r--vcl/source/app/salplug.cxx355
-rw-r--r--vcl/source/app/salusereventlist.cxx171
-rw-r--r--vcl/source/app/salvtables.cxx6777
-rw-r--r--vcl/source/app/scheduler.cxx659
-rw-r--r--vcl/source/app/session.cxx414
-rw-r--r--vcl/source/app/settings.cxx3233
-rw-r--r--vcl/source/app/sound.cxx38
-rw-r--r--vcl/source/app/stdtext.cxx124
-rw-r--r--vcl/source/app/svapp.cxx1707
-rw-r--r--vcl/source/app/svdata.cxx491
-rw-r--r--vcl/source/app/svmain.cxx684
-rw-r--r--vcl/source/app/timer.cxx102
-rw-r--r--vcl/source/app/unohelp.cxx233
-rw-r--r--vcl/source/app/unohelp2.cxx98
-rw-r--r--vcl/source/app/vclevent.cxx104
-rw-r--r--vcl/source/app/watchdog.cxx165
-rw-r--r--vcl/source/app/weldutils.cxx129
-rw-r--r--vcl/source/app/winscheduler.cxx46
29 files changed, 17458 insertions, 0 deletions
diff --git a/vcl/source/app/ITiledRenderable.cxx b/vcl/source/app/ITiledRenderable.cxx
new file mode 100644
index 000000000..e2a639dec
--- /dev/null
+++ b/vcl/source/app/ITiledRenderable.cxx
@@ -0,0 +1,81 @@
+/* -*- 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 000000000..84d85883b
--- /dev/null
+++ b/vcl/source/app/IconThemeInfo.cxx
@@ -0,0 +1,188 @@
+/* -*- 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. Only the theme id for high contrast is used
+// outside of this class and hence made public.
+
+const OUStringLiteral vcl::IconThemeInfo::HIGH_CONTRAST_ID("sifr");
+
+namespace {
+
+static const OUStringLiteral KARASA_JAGA_ID("karasa_jaga");
+static const OUStringLiteral KARASA_JAGA_DISPLAY_NAME("Karasa Jaga");
+static const OUStringLiteral HELPIMG_FAKE_THEME("helpimg");
+
+OUString
+filename_from_url(const OUString& url)
+{
+ sal_Int32 slashPosition = url.lastIndexOf( '/' );
+ if (slashPosition < 0) {
+ return OUString();
+ }
+ OUString filename = url.copy( slashPosition+1 );
+ return filename;
+}
+
+} // end anonymous namespace
+
+namespace vcl {
+
+static const char ICON_THEME_PACKAGE_PREFIX[] = "images_";
+
+static const char EXTENSION_FOR_ICON_PACKAGES[] = ".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(const OUString& themeName)
+{
+ if (themeName == "galaxy") { //kept for compiler because of unused parameter 'themeName'
+ return Size( 26, 26 );
+ }
+ else {
+ return Size( 24, 24 );
+ }
+}
+
+/*static*/ bool
+IconThemeInfo::UrlCanBeParsed(const OUString& 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(const OUString& filename)
+{
+ OUString r;
+ sal_Int32 positionOfLastDot = filename.lastIndexOf(EXTENSION_FOR_ICON_PACKAGES);
+ if (positionOfLastDot < 0) { // -1 means index not found
+ throw std::runtime_error("IconThemeInfo::FileNameToThemeId() called with invalid filename.");
+ }
+ sal_Int32 positionOfFirstUnderscore = filename.indexOf(ICON_THEME_PACKAGE_PREFIX);
+ if (positionOfFirstUnderscore < 0) { // -1 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.copy(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);
+
+ // special cases
+ if (aDisplayName.equalsIgnoreAsciiCase(KARASA_JAGA_ID)) {
+ aDisplayName = KARASA_JAGA_DISPLAY_NAME;
+ }
+ else
+ {
+ // make the first letter uppercase
+ sal_Unicode firstLetter = aDisplayName[0];
+ if (rtl::isAsciiLowerCase(firstLetter))
+ {
+ aDisplayName = OUStringChar(sal_Unicode(rtl::toAsciiUpperCase(firstLetter))) + aDisplayName.copy(1);
+ }
+ }
+
+ 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 000000000..a9163af3c
--- /dev/null
+++ b/vcl/source/app/IconThemeScanner.cxx
@@ -0,0 +1,215 @@
+/* -*- 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>
+
+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(const OUString& paths)
+{
+ mFoundIconThemes.clear();
+
+ std::deque<OUString> aPaths;
+
+ sal_Int32 nIndex = 0;
+ do
+ {
+ aPaths.push_front(paths.getToken(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(const OUString &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 000000000..e98d63657
--- /dev/null
+++ b/vcl/source/app/IconThemeSelector.cxx
@@ -0,0 +1,175 @@
+/* -*- 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 <vcl/IconThemeInfo.hxx>
+#include <config_mpl.h>
+
+#include <algorithm>
+
+namespace vcl {
+
+/*static*/ const OUStringLiteral IconThemeSelector::FALLBACK_ICON_THEME_ID("colibre");
+
+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)
+{
+ if (comphelper::LibreOfficeKit::isActive())
+ return "colibre";
+
+#ifdef _WIN32
+ (void)desktopEnvironment;
+ return "colibre";
+#else
+ OUString r;
+ if ( desktopEnvironment.equalsIgnoreAsciiCase("plasma5") ||
+ desktopEnvironment.equalsIgnoreAsciiCase("lxqt") ) {
+ r = "breeze";
+ }
+ else if ( desktopEnvironment.equalsIgnoreAsciiCase("macosx") ) {
+ r = "sukapura";
+ }
+ else if ( desktopEnvironment.equalsIgnoreAsciiCase("gnome") ||
+ desktopEnvironment.equalsIgnoreAsciiCase("mate") ||
+ desktopEnvironment.equalsIgnoreAsciiCase("unity") ) {
+ r = "elementary";
+ } else
+ {
+ r = FALLBACK_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;
+ }
+ //if a dark variant is preferred, and we didn't have an exact match, then try our one and only dark theme
+ if (mPreferDarkIconTheme && icon_theme_is_in_installed_themes("breeze_dark", installedThemes)) {
+ return "breeze_dark";
+ }
+ }
+
+ OUString themeForDesktop = GetIconThemeForDesktopEnvironment(desktopEnvironment);
+ 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) {
+ if (icon_theme_is_in_installed_themes(IconThemeInfo::HIGH_CONTRAST_ID, installedThemes)) {
+ return IconThemeInfo::HIGH_CONTRAST_ID;
+ }
+ }
+
+ if (icon_theme_is_in_installed_themes(theme, installedThemes)) {
+ return theme;
+ }
+
+ return ReturnFallback(installedThemes);
+}
+
+void
+IconThemeSelector::SetUseHighContrastTheme(bool v)
+{
+ mUseHighContrastTheme = v;
+}
+
+void
+IconThemeSelector::SetPreferredIconTheme(const OUString& theme, bool bDarkIconTheme)
+{
+ // lower case theme name, and (tdf#120175) replace - with _
+ // see icon-themes/README
+ mPreferredIconTheme = theme.toAsciiLowerCase().replace('-','_');
+ mPreferDarkIconTheme = bDarkIconTheme;
+}
+
+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_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 000000000..290606106
--- /dev/null
+++ b/vcl/source/app/brand.cxx
@@ -0,0 +1,73 @@
+/* -*- 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_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/pngread.hxx>
+#include <vcl/svapp.hxx>
+
+namespace {
+ bool loadPng( const OUString & rPath, BitmapEx &rBitmap)
+ {
+ INetURLObject aObj( rPath );
+ SvFileStream aStrm( aObj.PathToFileName(), StreamMode::STD_READ );
+ if ( !aStrm.GetError() ) {
+ vcl::PNGReader aReader( aStrm );
+ rBitmap = aReader.Read();
+ return !rBitmap.IsEmpty();
+ }
+ else
+ return false;
+ }
+ bool tryLoadPng( const OUString& rBaseDir, const OUString& rName, BitmapEx& rBitmap )
+ {
+ return loadPng( rBaseDir + "/" LIBO_ETC_FOLDER + rName, rBitmap);
+ }
+}
+
+bool Application::LoadBrandBitmap (const char* 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( "/" + OUString::createFromAscii( 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, aBaseName + "-" + aFallback + aPng, rBitmap))
+ return true;
+ }
+
+ return tryLoadPng( aBaseDir, 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 000000000..c08a38208
--- /dev/null
+++ b/vcl/source/app/customweld.cxx
@@ -0,0 +1,105 @@
+/* -*- 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 OString& rDrawingId,
+ CustomWidgetController& rWidgetController)
+ : m_rWidgetController(rWidgetController)
+ , m_xDrawingArea(rBuilder.weld_drawing_area(rDrawingId, rWidgetController.CreateAccessible(),
+ rWidgetController.GetUITestFactory(),
+ &rWidgetController))
+{
+ 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_rWidgetController.SetDrawingArea(m_xDrawingArea.get());
+}
+
+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);
+}
+}
+
+/* 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 000000000..cfeeeaf5d
--- /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 000000000..ff4beb789
--- /dev/null
+++ b/vcl/source/app/dndhelp.cxx
@@ -0,0 +1,139 @@
+/* -*- 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 <cppuhelper/queryinterface.hxx>
+
+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& )
+{
+}
+
+/* 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 000000000..ebe7588c5
--- /dev/null
+++ b/vcl/source/app/help.cxx
@@ -0,0 +1,677 @@
+/* -*- 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 <tools/diagnose_ex.h>
+#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;
+ ImplShowHelpWindow( pParent, nHelpWinStyle, nStyle,
+ rHelpText,
+ pParent->OutputToScreenPixel( pParent->GetPointerPosPixel() ), 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 )
+{
+ SetType( WindowType::HELPTEXTWINDOW );
+ ImplSetMouseTransparent( true );
+ mnHelpWinStyle = nHelpWinStyle;
+ mnStyle = nStyle;
+
+ if( mnStyle & QuickHelpFlags::BiDiRtl )
+ {
+ ComplexTextLayoutFlags nLayoutMode = GetLayoutMode();
+ nLayoutMode |= ComplexTextLayoutFlags::BiDiRtl | ComplexTextLayoutFlags::TextOriginLeft;
+ SetLayoutMode( nLayoutMode );
+ }
+ SetHelpText( rText );
+ Window::SetHelpText( rText );
+
+ if ( ImplGetSVHelpData().mbSetKeyboardHelp )
+ ImplGetSVHelpData().mbKeyboardHelp = true;
+
+
+ maShowTimer.SetInvokeHandler( LINK( this, HelpTextWindow, TimerHdl ) );
+ maShowTimer.SetDebugName( "vcl::HelpTextWindow maShowTimer" );
+
+ const HelpSettings& rHelpSettings = pParent->GetSettings().GetHelpSettings();
+ maHideTimer.SetTimeout( rHelpSettings.GetTipTimeout() );
+ maHideTimer.SetInvokeHandler( LINK( this, HelpTextWindow, TimerHdl ) );
+ maHideTimer.SetDebugName( "vcl::HelpTextWindow maHideTimer" );
+}
+
+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(*this);
+ if ( mnHelpWinStyle == HELPWINSTYLE_QUICK && maHelpText.getLength() < HELPTEXTMAXLEN && maHelpText.indexOf('\n') < 0)
+ {
+ Size aSize;
+ aSize.setHeight( GetTextHeight() );
+ if ( mnStyle & QuickHelpFlags::CtrlText )
+ aSize.setWidth( 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;
+ comphelper::string::padToLength(aBuf, nCharsInLine, 'x');
+ OUString aXXX = aBuf.makeStringAndClear();
+ long nWidth = GetTextWidth( aXXX );
+ 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 );
+}
+
+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)
+ {
+ 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 )
+ {
+ if ( mnHelpWinStyle == HELPWINSTYLE_QUICK )
+ {
+ // start auto-hide-timer for non-ShowTip windows
+ if ( this == ImplGetSVHelpData().mpHelpWin )
+ maHideTimer.Start();
+ }
+ 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 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;
+
+ VclPtr<HelpTextWindow> pHelpWin = aHelpData.mpHelpWin;
+ bool bNoDelay = false;
+ if ( pHelpWin )
+ {
+ SAL_WARN_IF( pHelpWin == pParent, "vcl", "HelpInHelp ?!" );
+
+ if ( ( rHelpText.isEmpty()
+ || ( pHelpWin->GetWinStyle() != nHelpWinStyle )
+ )
+ && aHelpData.mbRequestingHelp
+ )
+ {
+ // 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
+ pHelpWin = nullptr;
+ ImplDestroyHelpWindow( bWasVisible );
+ }
+ else
+ {
+ 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();
+ }
+ }
+ }
+
+ if (pHelpWin || rHelpText.isEmpty())
+ return;
+
+ sal_uInt64 nCurTime = tools::Time::GetSystemTicks();
+ if ( ( nCurTime - aHelpData.mnLastHelpHideTime ) < HelpSettings::GetTipDelay() )
+ bNoDelay = true;
+
+ 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 ( !aHelpData.mbRequestingHelp )
+ 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 )
+{
+ Point aPos = rPos;
+ Size aSz = pHelpWin->GetSizePixel();
+ tools::Rectangle aScreenRect = pHelpWin->ImplGetFrameWindow()->GetDesktopRectPixel();
+ aPos = pHelpWin->GetParent()->ImplGetFrameWindow()->OutputToAbsoluteScreenPixel( aPos );
+ // get mouse screen coords
+ Point aMousePos( pHelpWin->GetParent()->ImplGetFrameWindow()->GetPointerPosPixel() );
+ aMousePos = pHelpWin->GetParent()->ImplGetFrameWindow()->OutputToAbsoluteScreenPixel( aMousePos );
+
+ if ( nHelpWinStyle == HELPWINSTYLE_QUICK )
+ {
+ if ( !(nStyle & QuickHelpFlags::NoAutoPos) )
+ {
+ 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 ( nStyle & QuickHelpFlags::NoAutoPos )
+ {
+ // convert help area to screen coords
+ tools::Rectangle devHelpArea(
+ pHelpWin->GetParent()->ImplGetFrameWindow()->OutputToAbsoluteScreenPixel( rHelpArea.TopLeft() ),
+ pHelpWin->GetParent()->ImplGetFrameWindow()->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) );
+ }
+
+ 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...
+ */
+ tools::Rectangle aHelpRect( aPos, aSz );
+ if( aHelpRect.IsInside( aMousePos ) )
+ {
+ Point delta(2,2);
+ Point aSize( aSz.Width(), aSz.Height() );
+ Point aTest( aMousePos - aSize - delta );
+ if( aTest.X() > aScreenRect.Left() && aTest.Y() > aScreenRect.Top() )
+ aPos = aTest;
+ else
+ aPos = aMousePos + delta;
+ }
+ }
+
+ vcl::Window* pWindow = pHelpWin->GetParent()->ImplGetFrameWindow();
+ aPos = pWindow->AbsoluteScreenToOutputPixel( aPos );
+ pHelpWin->SetPosPixel( aPos );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/app/i18nhelp.cxx b/vcl/source/app/i18nhelp.cxx
new file mode 100644
index 000000000..ae7eed0e2
--- /dev/null
+++ b/vcl/source/app/i18nhelp.cxx
@@ -0,0 +1,160 @@
+/* -*- 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 <vcl/i18nhelp.hxx>
+
+using namespace ::com::sun::star;
+
+vcl::I18nHelper::I18nHelper( const css::uno::Reference< css::uno::XComponentContext >& rxContext, const LanguageTag& rLanguageTag )
+ :
+ maLanguageTag( rLanguageTag)
+{
+ 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
+{
+ ::osl::Guard< ::osl::Mutex > aGuard( const_cast<vcl::I18nHelper*>(this)->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
+{
+ ::osl::Guard< ::osl::Mutex > aGuard( const_cast<vcl::I18nHelper*>(this)->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( const OUString& rString, sal_Unicode cMnemonicChar ) const
+{
+ ::osl::Guard< ::osl::Mutex > aGuard( const_cast<vcl::I18nHelper*>(this)->maMutex );
+
+ bool bEqual = false;
+ sal_Int32 n = rString.indexOf( '~' );
+ if ( n != -1 )
+ {
+ OUString aMatchStr = rString.copy( n+1 ); // not only one char, because of transliteration...
+ bEqual = MatchString( OUString(cMnemonicChar), aMatchStr );
+ }
+ return bEqual;
+}
+
+OUString vcl::I18nHelper::GetNum( 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 000000000..26e1e5f22
--- /dev/null
+++ b/vcl/source/app/idle.cxx
@@ -0,0 +1,65 @@
+/* -*- 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()
+{
+ Task::Start();
+
+ sal_uInt64 nPeriod = Scheduler::ImmediateTimeoutMs;
+ if (Scheduler::GetDeterministicMode())
+ {
+ switch ( GetPriority() )
+ {
+ case TaskPriority::DEFAULT_IDLE:
+ case TaskPriority::LOWEST:
+ nPeriod = Scheduler::InfiniteTimeoutMs;
+ break;
+ default:
+ break;
+ }
+ }
+
+ 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 000000000..1868853e9
--- /dev/null
+++ b/vcl/source/app/salplug.cxx
@@ -0,0 +1,355 @@
+/* -*- 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 <osl/module.hxx>
+
+#include <rtl/bootstrap.hxx>
+#include <rtl/process.h>
+#include <sal/log.hxx>
+
+#include <salframe.hxx>
+#include <salinst.hxx>
+#include <config_vclplug.h>
+#include <desktop/crashreport.hxx>
+
+#ifndef _WIN32
+#include <headless/svpinst.hxx>
+#include <printerinfomanager.hxx>
+#include <unx/desktops.hxx>
+
+#include <unistd.h>
+#else
+#include <saldatabasic.hxx>
+#include <Windows.h>
+#endif
+
+#include <cstdio>
+
+#ifdef ANDROID
+#error "Android has no plugin infrastructure!"
+#endif
+
+#if !(defined _WIN32 || defined MACOSX)
+#define DESKTOPDETECT
+#define HEADLESS_VCLPLUG
+#endif
+
+extern "C" {
+typedef SalInstance*(*salFactoryProc)();
+}
+
+namespace {
+
+oslModule pCloseModule = nullptr;
+
+SalInstance* tryInstance( const OUString& rModuleBase, bool bForce = false )
+{
+#ifdef HEADLESS_VCLPLUG
+ 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 == "gtk3" || aUsedModuleBase == "gtk3_kde5" || 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;
+}
+
+#ifdef DESKTOPDETECT
+extern "C" typedef DesktopType Fn_get_desktop_environment();
+
+DesktopType get_desktop_environment()
+{
+ OUString aModule(DESKTOP_DETECTOR_DLL_NAME);
+ oslModule aMod = osl_loadModuleRelative(
+ reinterpret_cast< oslGenericFunction >( &tryInstance ), aModule.pData,
+ SAL_LOADMODULE_DEFAULT );
+ DesktopType ret = DESKTOP_UNKNOWN;
+ 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 );
+ return ret;
+}
+
+SalInstance* autodetect_plugin()
+{
+ static const char* const pKDEFallbackList[] =
+ {
+#if ENABLE_KF5
+ "kf5",
+#endif
+#if ENABLE_GTK3_KDE5
+ "gtk3_kde5",
+#endif
+ "gtk3", "gen", nullptr
+ };
+
+ static const char* const pStandardFallbackList[] =
+ {
+ "gtk3", "gen", nullptr
+ };
+
+#ifdef HEADLESS_VCLPLUG
+ static const char* const pHeadlessFallbackList[] =
+ {
+ "svp", nullptr
+ };
+#endif
+
+ DesktopType desktop = get_desktop_environment();
+ const char * const * pList = pStandardFallbackList;
+ int nListEntry = 0;
+
+#ifdef HEADLESS_VCLPLUG
+ // 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;
+
+ SalInstance* pInst = nullptr;
+ while( pList[nListEntry] && pInst == nullptr )
+ {
+ OUString aTry( OUString::createFromAscii( pList[nListEntry] ) );
+ pInst = tryInstance( aTry );
+ SAL_INFO_IF(
+ pInst, "vcl.plugadapt",
+ "plugin autodetection: " << pList[nListEntry]);
+ nListEntry++;
+ }
+
+ return pInst;
+}
+#endif // DESKTOPDETECT
+
+#ifdef HEADLESS_VCLPLUG
+// 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;
+}
+#endif
+
+} // anonymous namespace
+
+SalInstance *CreateSalInstance()
+{
+ SalInstance *pInst = nullptr;
+
+ OUString aUsePlugin;
+ rtl::Bootstrap::get("SAL_USE_VCLPLUGIN", aUsePlugin);
+ SAL_INFO_IF(!aUsePlugin.isEmpty(), "vcl", "Requested VCL plugin: " << aUsePlugin);
+#ifdef HEADLESS_VCLPLUG
+ if (Application::IsBitmapRendering() || (aUsePlugin.isEmpty() && IsHeadlessModeRequested()))
+ aUsePlugin = "svp";
+#endif
+
+ if (aUsePlugin == "svp")
+ {
+ Application::EnableBitmapRendering();
+#ifndef HEADLESS_VCLPLUG
+ aUsePlugin.clear();
+#endif
+ }
+ if( !aUsePlugin.isEmpty() )
+ pInst = tryInstance( aUsePlugin, true );
+
+#ifdef DESKTOPDETECT
+ if( ! pInst )
+ pInst = autodetect_plugin();
+#endif
+
+ // fallback, try everything
+ static const char* const pPlugin[] = {
+#ifdef _WIN32
+ "win"
+#else
+#ifdef MACOSX
+ "osx"
+#else
+ "gtk3", "kf5", "gen"
+#endif
+#endif
+ };
+
+ for ( int i = 0; !pInst && i != SAL_N_ELEMENTS(pPlugin); ++i )
+ pInst = tryInstance( OUString::createFromAscii( pPlugin[ i ] ) );
+
+ if( ! pInst )
+ {
+ std::fprintf( stderr, "no suitable windowing system found, exiting.\n" );
+ _exit( 1 );
+ }
+
+ // acquire SolarMutex
+ pInst->AcquireYieldMutex();
+
+ return pInst;
+}
+
+void DestroySalInstance( SalInstance *pInst )
+{
+ // release SolarMutex
+ pInst->ReleaseYieldMutexAll();
+
+ delete pInst;
+ if( pCloseModule )
+ osl_unloadModule( pCloseModule );
+}
+
+void SalAbort( const OUString& rErrorText, bool bDumpCore )
+{
+ if( rErrorText.isEmpty() )
+ std::fprintf( stderr, "Application Error\n" );
+ else
+ {
+ CrashReporter::addKeyValue("AbortMessage", rErrorText, CrashReporter::Write);
+ std::fprintf( stderr, "%s\n", OUStringToOString(rErrorText, osl_getThreadTextEncoding()).getStr() );
+ }
+ if( bDumpCore )
+ abort();
+ else
+ _exit(1);
+}
+
+const OUString& SalGetDesktopEnvironment()
+{
+#ifdef _WIN32
+ static OUString aDesktopEnvironment( "Windows" );
+
+#else
+#ifdef MACOSX
+ static OUString aDesktopEnvironment( "MacOSX" );
+#else
+ // Order to match desktops.hxx' DesktopType
+ static const char * const desktop_strings[] = {
+ "none", "unknown", "GNOME", "UNITY",
+ "XFCE", "MATE", "PLASMA5", "LXQT" };
+ static OUString aDesktopEnvironment;
+ if( aDesktopEnvironment.isEmpty())
+ {
+ aDesktopEnvironment = OUString::createFromAscii(
+ desktop_strings[get_desktop_environment()]);
+ }
+#endif
+#endif
+ return aDesktopEnvironment;
+}
+
+SalData::SalData() :
+ m_pInstance(nullptr),
+ m_pPIManager(nullptr)
+{
+}
+
+SalData::~SalData() COVERITY_NOEXCEPT_FALSE
+{
+#if (defined UNX && !defined MACOSX)
+ psp::PrinterInfoManager::release();
+#endif
+}
+
+#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 000000000..088bc141f
--- /dev/null
+++ b/vcl/source/app/salusereventlist.cxx
@@ -0,0 +1,171 @@
+/* -*- 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 <tools/diagnose_ex.h>
+#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();
+ osl::ResettableMutexGuard 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())
+ {
+ 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.clear();
+
+ if ( !isFrameAlive( aEvent.m_pFrame ) )
+ {
+ if ( aEvent.m_nEvent == SalEvent::UserEvent )
+ delete static_cast< ImplSVEvent* >( aEvent.m_pData );
+ aResettableListGuard.reset();
+ continue;
+ }
+
+#ifndef IOS
+ try
+#endif
+ {
+ ProcessEvent( aEvent );
+ }
+#ifndef IOS
+ catch (css::uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("vcl", "Uncaught");
+ std::abort();
+ }
+ catch (std::exception& e)
+ {
+ SAL_WARN("vcl", "Uncaught " << typeid(e).name() << " " << e.what());
+ std::abort();
+ }
+ catch (...)
+ {
+ SAL_WARN("vcl", "Uncaught exception during DispatchUserEvents!");
+ std::abort();
+ }
+#endif
+ aResettableListGuard.reset();
+ if (!bHandleAllCurrentEvents)
+ break;
+ }
+ while( true );
+ }
+
+ if ( !m_bAllUserEventProcessedSignaled && !HasUserEvents() )
+ {
+ m_bAllUserEventProcessedSignaled = true;
+ TriggerAllUserEventsProcessed();
+ }
+
+ return bWasEvent;
+}
+
+void SalUserEventList::RemoveEvent( SalFrame* pFrame, void* pData, SalEvent nEvent )
+{
+ SalUserEvent aEvent( pFrame, pData, nEvent );
+
+ osl::MutexGuard 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() )
+ {
+ 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 000000000..d7c93164a
--- /dev/null
+++ b/vcl/source/app/salvtables.cxx
@@ -0,0 +1,6777 @@
+/* -*- 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 <com/sun/star/accessibility/AccessibleRelationType.hpp>
+#include <com/sun/star/awt/XWindow.hpp>
+#include <com/sun/star/awt/XWindowPeer.hpp>
+#include <o3tl/sorted_vector.hxx>
+#include <officecfg/Office/Common.hxx>
+#include <iconview.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/calendar.hxx>
+#include <vcl/toolkit/combobox.hxx>
+#include <vcl/toolkit/dialog.hxx>
+#include <vcl/fixed.hxx>
+#include <vcl/toolkit/fixedhyper.hxx>
+#include <vcl/fmtfield.hxx>
+#include <vcl/headbar.hxx>
+#include <vcl/ivctrl.hxx>
+#include <vcl/layout.hxx>
+#include <vcl/menubtn.hxx>
+#include <vcl/toolkit/prgsbar.hxx>
+#include <vcl/ptrstyle.hxx>
+#include <slider.hxx>
+#include <vcl/sysdata.hxx>
+#include <vcl/svlbitm.hxx>
+#include <vcl/toolkit/svtabbx.hxx>
+#include <vcl/tabctrl.hxx>
+#include <vcl/tabpage.hxx>
+#include <vcl/treelistentry.hxx>
+#include <vcl/toolkit/throbber.hxx>
+#include <vcl/toolkit/unowrap.hxx>
+#include <vcl/weld.hxx>
+#include <vcl/vclmedit.hxx>
+#include <vcl/viewdataentry.hxx>
+#include <vcl/virdev.hxx>
+#include <bitmaps.hlst>
+#include <wizdlg.hxx>
+#include <salvtables.hxx>
+
+#include <boost/property_tree/ptree.hpp>
+
+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
+}
+
+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; }
+
+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);
+}
+
+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() {}
+
+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)
+ {
+ Application::AddEventListener(LINK(this, SalInstanceWidget, MouseEventListener));
+ m_bMouseEventListener = true;
+ }
+}
+
+void SalInstanceWidget::set_background(const Color& rColor)
+{
+ m_xWidget->SetControlBackground(rColor);
+ m_xWidget->SetBackground(m_xWidget->GetControlBackground());
+ // turn off WB_CLIPCHILDREN otherwise the bg won't extend "under"
+ // transparent children of the widget
+ m_xWidget->SetStyle(m_xWidget->GetStyle() & ~WB_CLIPCHILDREN);
+}
+
+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)
+{
+}
+
+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() { m_xWidget->GrabFocus(); }
+
+bool SalInstanceWidget::has_focus() const { return m_xWidget->HasFocus(); }
+
+bool SalInstanceWidget::is_active() const { return m_xWidget->IsActive(); }
+
+void SalInstanceWidget::set_has_default(bool has_default)
+{
+ m_xWidget->set_property("has-default", OUString::boolean(has_default));
+}
+
+bool SalInstanceWidget::get_has_default() const { return m_xWidget->GetStyle() & WB_DEFBUTTON; }
+
+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); }
+
+OString SalInstanceWidget::get_buildable_name() const { return m_xWidget->get_id().toUtf8(); }
+
+void SalInstanceWidget::set_help_id(const OString& rId) { return m_xWidget->SetHelpId(rId); }
+
+OString 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_secondary(bool bSecondary) { m_xWidget->set_secondary(bSecondary); }
+
+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_left(int nMargin) { m_xWidget->set_margin_left(nMargin); }
+
+void SalInstanceWidget::set_margin_right(int nMargin) { m_xWidget->set_margin_bottom(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_left() const { return m_xWidget->get_margin_left(); }
+
+int SalInstanceWidget::get_margin_right() const { return m_xWidget->get_margin_bottom(); }
+
+void SalInstanceWidget::set_accessible_name(const OUString& rName)
+{
+ m_xWidget->SetAccessibleName(rName);
+}
+
+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)
+{
+ vcl::Window* pAtkLabel
+ = pLabel ? dynamic_cast<SalInstanceWidget&>(*pLabel).getWidget() : nullptr;
+ m_xWidget->SetAccessibleRelationLabeledBy(pAtkLabel);
+}
+
+void SalInstanceWidget::set_accessible_relation_label_for(weld::Widget* pLabeled)
+{
+ vcl::Window* pAtkLabeled
+ = pLabeled ? dynamic_cast<SalInstanceWidget&>(*pLabeled).getWidget() : nullptr;
+ m_xWidget->SetAccessibleRelationLabelFor(pAtkLabeled);
+}
+
+void SalInstanceWidget::set_tooltip_text(const OUString& rTip)
+{
+ m_xWidget->SetQuickHelpText(rTip);
+}
+
+OUString SalInstanceWidget::get_tooltip_text() const { return m_xWidget->GetQuickHelpText(); }
+
+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);
+}
+
+bool SalInstanceWidget::get_extents_relative_to(Widget& rRelative, int& x, int& y, int& width,
+ int& height)
+{
+ tools::Rectangle aRect(m_xWidget->GetWindowExtentsRelative(
+ dynamic_cast<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() { m_xWidget->SetUpdateMode(false); }
+
+void SalInstanceWidget::thaw() { m_xWidget->SetUpdateMode(true); }
+
+SalInstanceWidget::~SalInstanceWidget()
+{
+ if (m_aMnemonicActivateHdl.IsSet())
+ m_xWidget->SetMnemonicActivateHdl(Link<vcl::Window&, bool>());
+ if (m_bMouseEventListener)
+ Application::RemoveEventListener(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() { return m_xWidget; }
+
+void SalInstanceWidget::disable_notify_events() { ++m_nBlockNotify; }
+
+bool SalInstanceWidget::notify_events_disabled() { 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::DEFAULT,
+ DeviceFormat::DEFAULT);
+}
+
+css::uno::Reference<css::datatransfer::dnd::XDropTarget> SalInstanceWidget::get_drop_target()
+{
+ return m_xWidget->GetDropTarget();
+}
+
+void SalInstanceWidget::connect_get_property_tree(
+ const Link<boost::property_tree::ptree&, void>& rLink)
+{
+ m_xWidget->SetDumpAsPropertyTreeHdl(rLink);
+}
+
+void SalInstanceWidget::set_stack_background()
+{
+ set_background(m_xWidget->GetSettings().GetStyleSettings().GetWindowColor());
+}
+
+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());
+}
+
+void SalInstanceWidget::HandleMouseEventListener(VclSimpleEvent& rEvent)
+{
+ if (rEvent.GetId() == VclEventId::WindowMouseButtonDown)
+ {
+ auto& rWinEvent = static_cast<VclWindowEvent&>(rEvent);
+ if (m_xWidget->IsWindowOrChild(rWinEvent.GetWindow()))
+ {
+ const MouseEvent* pMouseEvent = static_cast<const MouseEvent*>(rWinEvent.GetData());
+ m_aMousePressHdl.Call(*pMouseEvent);
+ }
+ }
+ else if (rEvent.GetId() == VclEventId::WindowMouseButtonUp)
+ {
+ auto& rWinEvent = static_cast<VclWindowEvent&>(rEvent);
+ if (m_xWidget->IsWindowOrChild(rWinEvent.GetWindow()))
+ {
+ const MouseEvent* pMouseEvent = static_cast<const MouseEvent*>(rWinEvent.GetData());
+ m_aMouseReleaseHdl.Call(*pMouseEvent);
+ }
+ }
+ else if (rEvent.GetId() == VclEventId::WindowMouseMove)
+ {
+ auto& rWinEvent = static_cast<VclWindowEvent&>(rEvent);
+ if (m_xWidget->IsWindowOrChild(rWinEvent.GetWindow()))
+ {
+ const MouseEvent* pMouseEvent = static_cast<const MouseEvent*>(rWinEvent.GetData());
+ m_aMouseMotionHdl.Call(*pMouseEvent);
+ }
+ }
+}
+
+bool SalInstanceWidget::HandleKeyEventListener(VclWindowEvent& rEvent)
+{
+ // we get all key events here, ignore them unless we have focus
+ if (!has_focus())
+ 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, VclSimpleEvent&, 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, 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,
+ OUStringToOString(rId, RTL_TEXTENCODING_UTF8), pos == -1 ? MENU_APPEND : pos);
+ if (pIconName)
+ {
+ pMenu->SetItemImage(nNewid, createImage(*pIconName));
+ }
+ else if (pImageSurface)
+ {
+ pMenu->SetItemImage(nNewid, createImage(*pImageSurface));
+ }
+ 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));
+}
+OString SalInstanceMenu::popup_at_rect(weld::Widget* pParent, const tools::Rectangle& rRect)
+{
+ SalInstanceWidget* pVclWidget = dynamic_cast<SalInstanceWidget*>(pParent);
+ assert(pVclWidget);
+ m_xMenu->Execute(pVclWidget->getWidget(), rRect,
+ PopupMenuFlags::ExecuteDown | PopupMenuFlags::NoMouseUpClose);
+ return m_xMenu->GetCurItemIdent();
+}
+void SalInstanceMenu::set_sensitive(const OString& rIdent, bool bSensitive)
+{
+ m_xMenu->EnableItem(rIdent, bSensitive);
+}
+void SalInstanceMenu::set_active(const OString& rIdent, bool bActive)
+{
+ m_xMenu->CheckItem(rIdent, bActive);
+}
+bool SalInstanceMenu::get_active(const OString& rIdent) const
+{
+ return m_xMenu->IsItemChecked(m_xMenu->GetItemId(rIdent));
+}
+void SalInstanceMenu::set_label(const OString& rIdent, const OUString& rLabel)
+{
+ m_xMenu->SetItemText(m_xMenu->GetItemId(rIdent), rLabel);
+}
+OUString SalInstanceMenu::get_label(const OString& rIdent) const
+{
+ return m_xMenu->GetItemText(m_xMenu->GetItemId(rIdent));
+}
+void SalInstanceMenu::set_visible(const OString& 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,
+ TriState eCheckRadioFalse)
+{
+ m_nLastId
+ = insert_to_menu(m_nLastId, m_xMenu, pos, rId, rStr, pIconName, pImageSurface, eCheckRadioFalse);
+}
+void SalInstanceMenu::insert_separator(int pos, const OUString& rId)
+{
+ auto nInsertPos = pos == -1 ? MENU_APPEND : pos;
+ m_xMenu->InsertSeparator(rId.toUtf8(), nInsertPos);
+}
+void SalInstanceMenu::remove(const OString& rId)
+{
+ m_xMenu->RemoveItem(m_xMenu->GetItemPos(m_xMenu->GetItemId(rId)));
+}
+int SalInstanceMenu::n_children() const { return m_xMenu->GetItemCount(); }
+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;
+}
+
+namespace
+{
+class SalInstanceToolbar : public SalInstanceWidget, public virtual weld::Toolbar
+{
+private:
+ VclPtr<ToolBox> m_xToolBox;
+ std::map<sal_uInt16, VclPtr<vcl::Window>> m_aFloats;
+ std::map<sal_uInt16, VclPtr<PopupMenu>> m_aMenus;
+
+ OString m_sStartShowIdent;
+
+ DECL_LINK(ClickHdl, ToolBox*, void);
+ DECL_LINK(DropdownClick, ToolBox*, void);
+ DECL_LINK(MenuToggleListener, VclWindowEvent&, void);
+
+public:
+ 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));
+ }
+
+ virtual void set_item_sensitive(const OString& rIdent, bool bSensitive) override
+ {
+ m_xToolBox->EnableItem(m_xToolBox->GetItemId(OUString::fromUtf8(rIdent)), bSensitive);
+ }
+
+ virtual bool get_item_sensitive(const OString& rIdent) const override
+ {
+ return m_xToolBox->IsItemEnabled(m_xToolBox->GetItemId(OUString::fromUtf8(rIdent)));
+ }
+
+ virtual void set_item_visible(const OString& rIdent, bool bVisible) override
+ {
+ m_xToolBox->ShowItem(m_xToolBox->GetItemId(OUString::fromUtf8(rIdent)), bVisible);
+ }
+
+ virtual void set_item_help_id(const OString& rIdent, const OString& rHelpId) override
+ {
+ m_xToolBox->SetHelpId(m_xToolBox->GetItemId(OUString::fromUtf8(rIdent)), rHelpId);
+ }
+
+ virtual bool get_item_visible(const OString& rIdent) const override
+ {
+ return m_xToolBox->IsItemVisible(m_xToolBox->GetItemId(OUString::fromUtf8(rIdent)));
+ }
+
+ virtual void set_item_active(const OString& rIdent, bool bActive) override
+ {
+ sal_uInt16 nItemId = m_xToolBox->GetItemId(OUString::fromUtf8(rIdent));
+ m_xToolBox->CheckItem(nItemId, bActive);
+ }
+
+ virtual bool get_item_active(const OString& rIdent) const override
+ {
+ return m_xToolBox->IsItemChecked(m_xToolBox->GetItemId(OUString::fromUtf8(rIdent)));
+ }
+
+ void set_menu_item_active(const OString& rIdent, bool bActive) override
+ {
+ sal_uInt16 nItemId = m_xToolBox->GetItemId(OUString::fromUtf8(rIdent));
+ assert(m_xToolBox->GetItemBits(nItemId) & ToolBoxItemBits::DROPDOWN);
+
+ if (bActive)
+ {
+ m_sStartShowIdent = m_xToolBox->GetItemCommand(nItemId).toUtf8();
+ 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 get_menu_item_active(const OString& rIdent) const override
+ {
+ sal_uInt16 nItemId = m_xToolBox->GetItemId(OUString::fromUtf8(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;
+ }
+
+ virtual void set_item_popover(const OString& rIdent, weld::Widget* pPopover) override
+ {
+ SalInstanceWidget* pPopoverWidget = dynamic_cast<SalInstanceWidget*>(pPopover);
+
+ vcl::Window* pFloat = pPopoverWidget ? pPopoverWidget->getWidget() : nullptr;
+ if (pFloat)
+ {
+ pFloat->AddEventListener(LINK(this, SalInstanceToolbar, MenuToggleListener));
+ pFloat->EnableDocking();
+ }
+
+ sal_uInt16 nId = m_xToolBox->GetItemId(OUString::fromUtf8(rIdent));
+ auto xOldFloat = m_aFloats[nId];
+ if (xOldFloat)
+ {
+ xOldFloat->RemoveEventListener(LINK(this, SalInstanceToolbar, MenuToggleListener));
+ }
+ m_aFloats[nId] = pFloat;
+ m_aMenus[nId] = nullptr;
+ }
+
+ virtual void set_item_menu(const OString& rIdent, weld::Menu* pMenu) override
+ {
+ SalInstanceMenu* pInstanceMenu = dynamic_cast<SalInstanceMenu*>(pMenu);
+
+ PopupMenu* pPopup = pInstanceMenu ? pInstanceMenu->getMenu() : nullptr;
+
+ sal_uInt16 nId = m_xToolBox->GetItemId(OUString::fromUtf8(rIdent));
+ m_aMenus[nId] = pPopup;
+ m_aFloats[nId] = nullptr;
+ }
+
+ virtual void insert_separator(int pos, const OUString& /*rId*/) override
+ {
+ auto nInsertPos = pos == -1 ? ToolBox::APPEND : pos;
+ m_xToolBox->InsertSeparator(nInsertPos, 5);
+ }
+
+ virtual int get_n_items() const override { return m_xToolBox->GetItemCount(); }
+
+ virtual OString get_item_ident(int nIndex) const override
+ {
+ return m_xToolBox->GetItemCommand(m_xToolBox->GetItemId(nIndex)).toUtf8();
+ }
+
+ virtual void set_item_ident(int nIndex, const OString& rIdent) override
+ {
+ return m_xToolBox->SetItemCommand(m_xToolBox->GetItemId(nIndex),
+ OUString::fromUtf8(rIdent));
+ }
+
+ virtual void set_item_label(int nIndex, const OUString& rLabel) override
+ {
+ m_xToolBox->SetItemText(m_xToolBox->GetItemId(nIndex), rLabel);
+ }
+
+ virtual OUString get_item_label(const OString& rIdent) const override
+ {
+ return m_xToolBox->GetItemText(m_xToolBox->GetItemId(OUString::fromUtf8(rIdent)));
+ }
+
+ virtual void set_item_label(const OString& rIdent, const OUString& rLabel) override
+ {
+ m_xToolBox->SetItemText(m_xToolBox->GetItemId(OUString::fromUtf8(rIdent)), rLabel);
+ }
+
+ virtual void set_item_icon_name(const OString& rIdent, const OUString& rIconName) override
+ {
+ m_xToolBox->SetItemImage(m_xToolBox->GetItemId(OUString::fromUtf8(rIdent)),
+ Image(StockImage::Yes, rIconName));
+ }
+
+ virtual void set_item_image(const OString& rIdent,
+ const css::uno::Reference<css::graphic::XGraphic>& rIcon) override
+ {
+ m_xToolBox->SetItemImage(m_xToolBox->GetItemId(OUString::fromUtf8(rIdent)), Image(rIcon));
+ }
+
+ virtual void set_item_image(const OString& rIdent, VirtualDevice* pDevice) override
+ {
+ if (pDevice)
+ m_xToolBox->SetItemImage(m_xToolBox->GetItemId(OUString::fromUtf8(rIdent)),
+ createImage(*pDevice));
+ else
+ m_xToolBox->SetItemImage(m_xToolBox->GetItemId(OUString::fromUtf8(rIdent)), Image());
+ }
+
+ virtual void set_item_image(int nIndex,
+ const css::uno::Reference<css::graphic::XGraphic>& rIcon) override
+ {
+ m_xToolBox->SetItemImage(m_xToolBox->GetItemId(nIndex), Image(rIcon));
+ }
+
+ virtual void set_item_tooltip_text(int nIndex, const OUString& rTip) override
+ {
+ m_xToolBox->SetQuickHelpText(m_xToolBox->GetItemId(nIndex), rTip);
+ }
+
+ virtual void set_item_tooltip_text(const OString& rIdent, const OUString& rTip) override
+ {
+ m_xToolBox->SetQuickHelpText(m_xToolBox->GetItemId(OUString::fromUtf8(rIdent)), rTip);
+ }
+
+ virtual OUString get_item_tooltip_text(const OString& rIdent) const override
+ {
+ return m_xToolBox->GetQuickHelpText(m_xToolBox->GetItemId(OUString::fromUtf8(rIdent)));
+ }
+
+ virtual vcl::ImageType get_icon_size() const override { return m_xToolBox->GetImageSize(); }
+
+ virtual void set_icon_size(vcl::ImageType eType) override
+ {
+ 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();
+ }
+ }
+
+ virtual sal_uInt16 get_modifier_state() const override
+ {
+ return m_xToolBox->GetModifier();
+ }
+
+ int get_drop_index(const Point& rPoint) const override
+ {
+ auto nRet = m_xToolBox->GetItemPos(rPoint);
+ if (nRet == ToolBox::ITEM_NOTFOUND)
+ return 0;
+ return nRet;
+ }
+
+ virtual ~SalInstanceToolbar() override
+ {
+ m_xToolBox->SetDropdownClickHdl(Link<ToolBox*, void>());
+ m_xToolBox->SetSelectHdl(Link<ToolBox*, void>());
+ }
+};
+
+}
+
+IMPL_LINK_NOARG(SalInstanceToolbar, ClickHdl, ToolBox*, void)
+{
+ sal_uInt16 nItemId = m_xToolBox->GetCurItemId();
+ signal_clicked(m_xToolBox->GetItemCommand(nItemId).toUtf8());
+}
+
+IMPL_LINK_NOARG(SalInstanceToolbar, DropdownClick, ToolBox*, void)
+{
+ sal_uInt16 nItemId = m_xToolBox->GetCurItemId();
+ set_menu_item_active(m_xToolBox->GetItemCommand(nItemId).toUtf8(), true);
+}
+
+IMPL_LINK(SalInstanceToolbar, MenuToggleListener, VclWindowEvent&, rEvent, void)
+{
+ if (rEvent.GetId() == VclEventId::WindowEndPopupMode)
+ {
+ for (auto& rFloat : m_aFloats)
+ {
+ if (rEvent.GetWindow() == rFloat.second)
+ {
+ sal_uInt16 nItemId = rFloat.first;
+ signal_toggle_menu(m_xToolBox->GetItemCommand(nItemId).toUtf8());
+ 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::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);
+ }
+}
+
+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);
+ if (pNewVclParent)
+ pVclWidget->getWidget()->SetParent(pNewVclParent->getWidget());
+ else
+ pVclWidget->getWidget()->SetParentToDefaultWindow();
+}
+
+void SalInstanceContainer::recursively_unset_default_buttons()
+{
+ implResetDefault(m_xContainer.get());
+}
+
+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::draw(VirtualDevice& rOutput)
+{
+ rOutput.SetOutputSizePixel(m_xWidget->GetSizePixel());
+ m_xWidget->PaintToDevice(&rOutput, Point());
+}
+
+namespace
+{
+class SalInstanceBox : public SalInstanceContainer, public virtual weld::Box
+{
+public:
+ SalInstanceBox(vcl::Window* pContainer, SalInstanceBuilder* pBuilder, bool bTakeOwnership)
+ : SalInstanceContainer(pContainer, pBuilder, bTakeOwnership)
+ {
+ }
+ virtual void reorder_child(weld::Widget* pWidget, int nNewPosition) override
+ {
+ SalInstanceWidget* pVclWidget = dynamic_cast<SalInstanceWidget*>(pWidget);
+ assert(pVclWidget);
+ pVclWidget->getWidget()->reorderWithinParent(nNewPosition);
+ }
+};
+
+void CollectChildren(const vcl::Window& rCurrent, const basegfx::B2IPoint& rTopLeft,
+ weld::ScreenShotCollection& rControlDataCollection)
+{
+ if (rCurrent.IsVisible())
+ {
+ 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)
+{
+ 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(); }
+
+void SalInstanceWindow::set_busy_cursor(bool bBusy)
+{
+ if (bBusy)
+ m_xWindow->EnterWait();
+ else
+ m_xWindow->LeaveWait();
+}
+
+css::uno::Reference<css::awt::XWindow> SalInstanceWindow::GetXWindow()
+{
+ css::uno::Reference<css::awt::XWindow> xWindow(m_xWindow->GetComponentInterface(),
+ css::uno::UNO_QUERY);
+ return xWindow;
+}
+
+void SalInstanceWindow::resize_to_request()
+{
+ if (SystemWindow* pSysWin = dynamic_cast<SystemWindow*>(m_xWindow.get()))
+ {
+ pSysWin->setOptimalLayoutSize();
+ return;
+ }
+ if (DockingWindow* pDockWin = dynamic_cast<DockingWindow*>(m_xWindow.get()))
+ {
+ pDockWin->setOptimalLayoutSize();
+ return;
+ }
+ assert(false && "must be system or docking window");
+}
+
+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(); }
+
+tools::Rectangle 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::set_window_state(const OString& rStr)
+{
+ SystemWindow* pSysWin = dynamic_cast<SystemWindow*>(m_xWindow.get());
+ assert(pSysWin);
+ pSysWin->SetWindowState(rStr);
+}
+
+OString SalInstanceWindow::get_window_state(WindowStateMask 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(); }
+
+void SalInstanceWindow::connect_toplevel_focus_changed(const Link<weld::Widget&, void>& rLink)
+{
+ ensure_event_listener();
+ weld::Window::connect_toplevel_focus_changed(rLink);
+}
+
+void SalInstanceWindow::HandleEventListener(VclWindowEvent& rEvent)
+{
+ if (rEvent.GetId() == VclEventId::WindowActivate
+ || rEvent.GetId() == VclEventId::WindowDeactivate)
+ {
+ signal_toplevel_focus_changed();
+ return;
+ }
+ SalInstanceContainer::HandleEventListener(rEvent);
+}
+
+void SalInstanceWindow::draw(VirtualDevice& rOutput)
+{
+ SystemWindow* pSysWin = dynamic_cast<SystemWindow*>(m_xWindow.get());
+ assert(pSysWin);
+ pSysWin->createScreenshot(rOutput);
+}
+
+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;
+}
+
+SalInstanceWindow::~SalInstanceWindow() { 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)
+ pActionArea->sort_native_button_order();
+ 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)
+ pActionArea->sort_native_button_order();
+ 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();
+ 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();
+}
+
+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)
+ pActionArea->sort_native_button_order();
+ return m_xDialog->Execute();
+}
+
+void SalInstanceDialog::response(int nResponse) { m_xDialog->EndDialog(nResponse); }
+
+void SalInstanceDialog::add_button(const OUString& rText, int nResponse, const OString& 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);
+}
+
+namespace
+{
+
+class SalInstanceAssistant : public SalInstanceDialog, public virtual weld::Assistant
+{
+private:
+ VclPtr<vcl::RoadmapWizard> m_xWizard;
+ std::vector<std::unique_ptr<SalInstanceContainer>> m_aPages;
+ std::vector<VclPtr<TabPage>> m_aAddedPages;
+ std::vector<int> m_aIds;
+ std::vector<VclPtr<VclGrid>> m_aAddedGrids;
+ Idle m_aUpdateRoadmapIdle;
+
+ int find_page(const OString& rIdent) const
+ {
+ for (size_t i = 0; i < m_aAddedPages.size(); ++i)
+ {
+ if (m_aAddedPages[i]->get_id().toUtf8() == rIdent)
+ return i;
+ }
+ return -1;
+ }
+
+ int find_id(int nId) const
+ {
+ for (size_t i = 0; i < m_aIds.size(); ++i)
+ {
+ if (nId == m_aIds[i])
+ return i;
+ }
+ return -1;
+ }
+
+ DECL_LINK(OnRoadmapItemSelected, LinkParamNone*, void);
+ DECL_LINK(UpdateRoadmap_Hdl, Timer*, void);
+
+public:
+ SalInstanceAssistant(vcl::RoadmapWizard* pDialog, SalInstanceBuilder* pBuilder,
+ bool bTakeOwnership)
+ : SalInstanceDialog(pDialog, pBuilder, bTakeOwnership)
+ , m_xWizard(pDialog)
+ {
+ m_xWizard->SetItemSelectHdl(LINK(this, SalInstanceAssistant, OnRoadmapItemSelected));
+
+ m_aUpdateRoadmapIdle.SetInvokeHandler(LINK(this, SalInstanceAssistant, UpdateRoadmap_Hdl));
+ m_aUpdateRoadmapIdle.SetPriority(TaskPriority::HIGHEST);
+ }
+
+ virtual int get_current_page() const override { return find_id(m_xWizard->GetCurLevel()); }
+
+ virtual int get_n_pages() const override { return m_aAddedPages.size(); }
+
+ virtual OString get_page_ident(int nPage) const override
+ {
+ return m_aAddedPages[nPage]->get_id().toUtf8();
+ }
+
+ virtual OString get_current_page_ident() const override
+ {
+ return get_page_ident(get_current_page());
+ }
+
+ virtual void set_current_page(int nPage) override
+ {
+ 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();
+ }
+
+ virtual void set_current_page(const OString& rIdent) override
+ {
+ int nIndex = find_page(rIdent);
+ if (nIndex == -1)
+ return;
+ set_current_page(nIndex);
+ }
+
+ virtual void set_page_index(const OString& rIdent, int nNewIndex) override
+ {
+ 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();
+ }
+
+ virtual weld::Container* append_page(const OString& rIdent) override
+ {
+ VclPtrInstance<TabPage> xPage(m_xWizard);
+ VclPtrInstance<VclGrid> xGrid(xPage);
+ xPage->set_id(OUString::fromUtf8(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();
+ }
+
+ virtual OUString get_page_title(const OString& rIdent) const override
+ {
+ int nIndex = find_page(rIdent);
+ if (nIndex == -1)
+ return OUString();
+ return m_aAddedPages[nIndex]->GetText();
+ }
+
+ virtual void set_page_title(const OString& rIdent, const OUString& rTitle) override
+ {
+ 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();
+ }
+ }
+
+ virtual void set_page_sensitive(const OString& rIdent, bool bSensitive) override
+ {
+ 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();
+ }
+ }
+
+ virtual void set_page_side_help_id(const OString& rHelpId) override
+ {
+ m_xWizard->SetRoadmapHelpId(rHelpId);
+ }
+
+ weld::Button* weld_widget_for_response(int nResponse) override;
+
+ virtual ~SalInstanceAssistant() override
+ {
+ 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()]);
+
+ m_xWizard->ShowRoadmap(nPos != 0);
+
+ enable_notify_events();
+}
+
+namespace
+{
+class SalInstanceFrame : public SalInstanceContainer, public virtual weld::Frame
+{
+private:
+ VclPtr<VclFrame> m_xFrame;
+
+public:
+ SalInstanceFrame(VclFrame* pFrame, SalInstanceBuilder* pBuilder, bool bTakeOwnership)
+ : SalInstanceContainer(pFrame, pBuilder, bTakeOwnership)
+ , m_xFrame(pFrame)
+ {
+ }
+
+ virtual void set_label(const OUString& rText) override { m_xFrame->set_label(rText); }
+
+ virtual OUString get_label() const override { return m_xFrame->get_label(); }
+
+ virtual std::unique_ptr<weld::Label> weld_label_widget() const override;
+};
+
+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();
+ }
+};
+
+class SalInstanceScrolledWindow : public SalInstanceContainer, public virtual weld::ScrolledWindow
+{
+private:
+ VclPtr<VclScrolledWindow> m_xScrolledWindow;
+ Link<ScrollBar*, void> m_aOrigVScrollHdl;
+ Link<ScrollBar*, void> m_aOrigHScrollHdl;
+ bool m_bUserManagedScrolling;
+
+ DECL_LINK(VscrollHdl, ScrollBar*, void);
+ DECL_LINK(HscrollHdl, ScrollBar*, void);
+
+public:
+ SalInstanceScrolledWindow(VclScrolledWindow* pScrolledWindow, SalInstanceBuilder* pBuilder,
+ bool bTakeOwnership)
+ : SalInstanceContainer(pScrolledWindow, pBuilder, bTakeOwnership)
+ , m_xScrolledWindow(pScrolledWindow)
+ , m_bUserManagedScrolling(false)
+ {
+ 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));
+ }
+
+ virtual void hadjustment_configure(int value, int lower, int upper, int step_increment,
+ int page_increment, int page_size) override
+ {
+ 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);
+ }
+
+ virtual int hadjustment_get_value() const override
+ {
+ ScrollBar& rHorzScrollBar = m_xScrolledWindow->getHorzScrollBar();
+ return rHorzScrollBar.GetThumbPos();
+ }
+
+ virtual void hadjustment_set_value(int value) override
+ {
+ ScrollBar& rHorzScrollBar = m_xScrolledWindow->getHorzScrollBar();
+ rHorzScrollBar.SetThumbPos(value);
+ if (!m_bUserManagedScrolling)
+ m_aOrigHScrollHdl.Call(&rHorzScrollBar);
+ }
+
+ virtual int hadjustment_get_upper() const override
+ {
+ ScrollBar& rHorzScrollBar = m_xScrolledWindow->getHorzScrollBar();
+ return rHorzScrollBar.GetRangeMax();
+ }
+
+ virtual void hadjustment_set_upper(int upper) override
+ {
+ ScrollBar& rHorzScrollBar = m_xScrolledWindow->getHorzScrollBar();
+ rHorzScrollBar.SetRangeMax(upper);
+ }
+
+ virtual int hadjustment_get_page_size() const override
+ {
+ ScrollBar& rHorzScrollBar = m_xScrolledWindow->getHorzScrollBar();
+ return rHorzScrollBar.GetVisibleSize();
+ }
+
+ virtual void hadjustment_set_page_size(int size) override
+ {
+ ScrollBar& rHorzScrollBar = m_xScrolledWindow->getHorzScrollBar();
+ return rHorzScrollBar.SetVisibleSize(size);
+ }
+
+ virtual void hadjustment_set_page_increment(int size) override
+ {
+ ScrollBar& rHorzScrollBar = m_xScrolledWindow->getHorzScrollBar();
+ return rHorzScrollBar.SetPageSize(size);
+ }
+
+ virtual void hadjustment_set_step_increment(int size) override
+ {
+ ScrollBar& rHorzScrollBar = m_xScrolledWindow->getHorzScrollBar();
+ return rHorzScrollBar.SetLineSize(size);
+ }
+
+ virtual void set_hpolicy(VclPolicyType eHPolicy) override
+ {
+ 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();
+ }
+
+ virtual VclPolicyType get_hpolicy() const override
+ {
+ WinBits nWinBits = m_xScrolledWindow->GetStyle();
+ if (nWinBits & WB_AUTOHSCROLL)
+ return VclPolicyType::AUTOMATIC;
+ else if (nWinBits & WB_HSCROLL)
+ return VclPolicyType::ALWAYS;
+ return VclPolicyType::NEVER;
+ }
+
+ virtual int get_hscroll_height() const override
+ {
+ return m_xScrolledWindow->getHorzScrollBar().get_preferred_size().Height();
+ }
+
+ virtual void vadjustment_configure(int value, int lower, int upper, int step_increment,
+ int page_increment, int page_size) override
+ {
+ 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);
+ }
+
+ virtual int vadjustment_get_value() const override
+ {
+ ScrollBar& rVertScrollBar = m_xScrolledWindow->getVertScrollBar();
+ return rVertScrollBar.GetThumbPos();
+ }
+
+ virtual void vadjustment_set_value(int value) override
+ {
+ ScrollBar& rVertScrollBar = m_xScrolledWindow->getVertScrollBar();
+ rVertScrollBar.SetThumbPos(value);
+ if (!m_bUserManagedScrolling)
+ m_aOrigVScrollHdl.Call(&rVertScrollBar);
+ }
+
+ virtual int vadjustment_get_upper() const override
+ {
+ ScrollBar& rVertScrollBar = m_xScrolledWindow->getVertScrollBar();
+ return rVertScrollBar.GetRangeMax();
+ }
+
+ virtual void vadjustment_set_upper(int upper) override
+ {
+ ScrollBar& rVertScrollBar = m_xScrolledWindow->getVertScrollBar();
+ rVertScrollBar.SetRangeMax(upper);
+ }
+
+ virtual int vadjustment_get_lower() const override
+ {
+ ScrollBar& rVertScrollBar = m_xScrolledWindow->getVertScrollBar();
+ return rVertScrollBar.GetRangeMin();
+ }
+
+ virtual void vadjustment_set_lower(int lower) override
+ {
+ ScrollBar& rVertScrollBar = m_xScrolledWindow->getVertScrollBar();
+ rVertScrollBar.SetRangeMin(lower);
+ }
+
+ virtual int vadjustment_get_page_size() const override
+ {
+ ScrollBar& rVertScrollBar = m_xScrolledWindow->getVertScrollBar();
+ return rVertScrollBar.GetVisibleSize();
+ }
+
+ virtual void vadjustment_set_page_size(int size) override
+ {
+ ScrollBar& rVertScrollBar = m_xScrolledWindow->getVertScrollBar();
+ return rVertScrollBar.SetVisibleSize(size);
+ }
+
+ virtual void vadjustment_set_page_increment(int size) override
+ {
+ ScrollBar& rVertScrollBar = m_xScrolledWindow->getVertScrollBar();
+ return rVertScrollBar.SetPageSize(size);
+ }
+
+ virtual void vadjustment_set_step_increment(int size) override
+ {
+ ScrollBar& rVertScrollBar = m_xScrolledWindow->getVertScrollBar();
+ return rVertScrollBar.SetLineSize(size);
+ }
+
+ virtual void set_vpolicy(VclPolicyType eVPolicy) override
+ {
+ 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();
+ }
+
+ virtual VclPolicyType get_vpolicy() const override
+ {
+ WinBits nWinBits = m_xScrolledWindow->GetStyle();
+ if (nWinBits & WB_AUTOVSCROLL)
+ return VclPolicyType::AUTOMATIC;
+ else if (nWinBits & WB_VSCROLL)
+ return VclPolicyType::ALWAYS;
+ return VclPolicyType::NEVER;
+ }
+
+ virtual int get_vscroll_width() const override
+ {
+ return m_xScrolledWindow->getVertScrollBar().get_preferred_size().Width();
+ }
+
+ virtual void set_user_managed_scrolling() override
+ {
+ m_bUserManagedScrolling = true;
+ m_xScrolledWindow->setUserManagedScrolling(true);
+ }
+
+ virtual ~SalInstanceScrolledWindow() override
+ {
+ 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());
+}
+
+SalInstanceNotebook::SalInstanceNotebook(TabControl* pNotebook, SalInstanceBuilder* pBuilder, bool bTakeOwnership)
+ : SalInstanceContainer(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());
+}
+
+OString SalInstanceNotebook::get_page_ident(int nPage) const
+{
+ return m_xNotebook->GetPageName(m_xNotebook->GetPageId(nPage));
+}
+
+OString SalInstanceNotebook::get_current_page_ident() const
+{
+ return m_xNotebook->GetPageName(m_xNotebook->GetCurPageId());
+}
+
+weld::Container* SalInstanceNotebook::get_page(const OString& rIdent) const
+{
+ sal_uInt16 nPageId = m_xNotebook->GetPageId(rIdent);
+ sal_uInt16 nPageIndex = m_xNotebook->GetPagePos(nPageId);
+ if (nPageIndex == TAB_PAGE_NOTFOUND)
+ return nullptr;
+ 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 OString& rIdent)
+{
+ m_xNotebook->SetCurPageId(m_xNotebook->GetPageId(rIdent));
+}
+
+void SalInstanceNotebook::remove_page(const OString& 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 OString& 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;
+ 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);
+}
+
+int SalInstanceNotebook::get_n_pages() const { return m_xNotebook->GetPageCount(); }
+
+OUString SalInstanceNotebook::get_tab_label_text(const OString& rIdent) const
+{
+ return m_xNotebook->GetPageText(m_xNotebook->GetPageId(rIdent));
+}
+
+void SalInstanceNotebook::set_tab_label_text(const OString& rIdent, const OUString& rText)
+{
+ return m_xNotebook->SetPageText(m_xNotebook->GetPageId(rIdent), rText);
+}
+
+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());
+}
+
+namespace
+{
+class SalInstanceVerticalNotebook : public SalInstanceContainer, public virtual weld::Notebook
+{
+private:
+ VclPtr<VerticalTabControl> m_xNotebook;
+ mutable std::vector<std::unique_ptr<SalInstanceContainer>> m_aPages;
+
+ DECL_LINK(DeactivatePageHdl, VerticalTabControl*, bool);
+ DECL_LINK(ActivatePageHdl, VerticalTabControl*, void);
+
+public:
+ SalInstanceVerticalNotebook(VerticalTabControl* pNotebook, SalInstanceBuilder* pBuilder,
+ bool bTakeOwnership)
+ : SalInstanceContainer(pNotebook, pBuilder, bTakeOwnership)
+ , m_xNotebook(pNotebook)
+ {
+ m_xNotebook->SetActivatePageHdl(LINK(this, SalInstanceVerticalNotebook, ActivatePageHdl));
+ m_xNotebook->SetDeactivatePageHdl(
+ LINK(this, SalInstanceVerticalNotebook, DeactivatePageHdl));
+ }
+
+ virtual int get_current_page() const override
+ {
+ return m_xNotebook->GetPagePos(m_xNotebook->GetCurPageId());
+ }
+
+ virtual OString get_page_ident(int nPage) const override
+ {
+ return m_xNotebook->GetPageId(nPage);
+ }
+
+ virtual OString get_current_page_ident() const override { return m_xNotebook->GetCurPageId(); }
+
+ virtual weld::Container* get_page(const OString& rIdent) const override
+ {
+ sal_uInt16 nPageIndex = m_xNotebook->GetPagePos(rIdent);
+ if (nPageIndex == TAB_PAGE_NOTFOUND)
+ 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();
+ }
+
+ virtual void set_current_page(int nPage) override
+ {
+ m_xNotebook->SetCurPageId(m_xNotebook->GetPageId(nPage));
+ }
+
+ virtual void set_current_page(const OString& rIdent) override
+ {
+ m_xNotebook->SetCurPageId(rIdent);
+ }
+
+ virtual void remove_page(const OString& rIdent) override
+ {
+ 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);
+ }
+
+ virtual void insert_page(const OString& rIdent, const OUString& rLabel, int nPos) override
+ {
+ VclPtrInstance<VclGrid> xGrid(m_xNotebook->GetPageParent());
+ xGrid->set_hexpand(true);
+ xGrid->set_vexpand(true);
+ m_xNotebook->InsertPage(rIdent, rLabel, Image(), "", xGrid, nPos);
+ }
+
+ virtual int get_n_pages() const override { return m_xNotebook->GetPageCount(); }
+
+ virtual void set_tab_label_text(const OString& rIdent, const OUString& rText) override
+ {
+ return m_xNotebook->SetPageText(rIdent, rText);
+ }
+
+ virtual OUString get_tab_label_text(const OString& rIdent) const override
+ {
+ return m_xNotebook->GetPageText(rIdent);
+ }
+
+ virtual ~SalInstanceVerticalNotebook() override
+ {
+ 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)
+ : SalInstanceContainer(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));
+}
+
+void SalInstanceButton::set_label_line_wrap(bool wrap)
+{
+ WinBits nBits = m_xButton->GetStyle();
+ nBits &= ~WB_WORDBREAK;
+ if (wrap)
+ nBits |= WB_WORDBREAK;
+ m_xButton->SetStyle(nBits);
+ m_xButton->queue_resize();
+}
+
+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;
+}
+
+namespace
+{
+class SalInstanceMenuButton : public SalInstanceButton, public virtual weld::MenuButton
+{
+private:
+ VclPtr<::MenuButton> m_xMenuButton;
+ sal_uInt16 m_nLastId;
+
+ DECL_LINK(MenuSelectHdl, ::MenuButton*, void);
+ DECL_LINK(ActivateHdl, ::MenuButton*, void);
+
+public:
+ 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;
+ }
+ }
+
+ virtual void set_active(bool active) override
+ {
+ if (active == get_active())
+ return;
+ if (active)
+ m_xMenuButton->ExecuteMenu();
+ else
+ m_xMenuButton->CancelMenu();
+ }
+
+ virtual bool get_active() const override { return m_xMenuButton->InPopupMode(); }
+
+ virtual void set_inconsistent(bool /*inconsistent*/) override
+ {
+ //not available
+ }
+
+ virtual bool get_inconsistent() const override { return false; }
+
+ virtual void insert_item(int pos, const OUString& rId, const OUString& rStr,
+ const OUString* pIconName, VirtualDevice* pImageSurface,
+ TriState eCheckRadioFalse) override
+ {
+ m_nLastId = insert_to_menu(m_nLastId, m_xMenuButton->GetPopupMenu(), pos, rId, rStr,
+ pIconName, pImageSurface, eCheckRadioFalse);
+ }
+
+ virtual void insert_separator(int pos, const OUString& rId) override
+ {
+ auto nInsertPos = pos == -1 ? MENU_APPEND : pos;
+ m_xMenuButton->GetPopupMenu()->InsertSeparator(rId.toUtf8(), nInsertPos);
+ }
+
+ virtual void set_item_sensitive(const OString& rIdent, bool bSensitive) override
+ {
+ PopupMenu* pMenu = m_xMenuButton->GetPopupMenu();
+ pMenu->EnableItem(rIdent, bSensitive);
+ }
+
+ virtual void remove_item(const OString& rId) override
+ {
+ PopupMenu* pMenu = m_xMenuButton->GetPopupMenu();
+ pMenu->RemoveItem(pMenu->GetItemPos(pMenu->GetItemId(rId)));
+ }
+
+ virtual void clear() override
+ {
+ PopupMenu* pMenu = m_xMenuButton->GetPopupMenu();
+ pMenu->Clear();
+ }
+
+ virtual void set_item_active(const OString& rIdent, bool bActive) override
+ {
+ PopupMenu* pMenu = m_xMenuButton->GetPopupMenu();
+ pMenu->CheckItem(rIdent, bActive);
+ }
+
+ virtual void set_item_label(const OString& rIdent, const OUString& rText) override
+ {
+ PopupMenu* pMenu = m_xMenuButton->GetPopupMenu();
+ pMenu->SetItemText(pMenu->GetItemId(rIdent), rText);
+ }
+
+ virtual OUString get_item_label(const OString& rIdent) const override
+ {
+ PopupMenu* pMenu = m_xMenuButton->GetPopupMenu();
+ return pMenu->GetItemText(pMenu->GetItemId(rIdent));
+ }
+
+ virtual void set_item_visible(const OString& rIdent, bool bShow) override
+ {
+ PopupMenu* pMenu = m_xMenuButton->GetPopupMenu();
+ pMenu->ShowItem(pMenu->GetItemId(rIdent), bShow);
+ }
+
+ virtual void set_item_help_id(const OString& rIdent, const OString& rHelpId) override
+ {
+ PopupMenu* pMenu = m_xMenuButton->GetPopupMenu();
+ pMenu->SetHelpId(pMenu->GetItemId(rIdent), rHelpId);
+ }
+
+ virtual OString get_item_help_id(const OString& rIdent) const override
+ {
+ PopupMenu* pMenu = m_xMenuButton->GetPopupMenu();
+ return pMenu->GetHelpId(pMenu->GetItemId(rIdent));
+ }
+
+ virtual void set_popover(weld::Widget* pPopover) override
+ {
+ SalInstanceWidget* pPopoverWidget = dynamic_cast<SalInstanceWidget*>(pPopover);
+ m_xMenuButton->SetPopover(pPopoverWidget ? pPopoverWidget->getWidget() : nullptr);
+ }
+
+ virtual ~SalInstanceMenuButton() override
+ {
+ 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 SalInstanceLinkButton : public SalInstanceContainer, public virtual weld::LinkButton
+{
+private:
+ VclPtr<FixedHyperlink> m_xButton;
+ Link<FixedHyperlink&, void> m_aOrigClickHdl;
+
+ DECL_LINK(ClickHdl, FixedHyperlink&, void);
+
+public:
+ SalInstanceLinkButton(FixedHyperlink* pButton, SalInstanceBuilder* pBuilder,
+ bool bTakeOwnership)
+ : SalInstanceContainer(pButton, pBuilder, bTakeOwnership)
+ , m_xButton(pButton)
+ {
+ m_aOrigClickHdl = m_xButton->GetClickHdl();
+ m_xButton->SetClickHdl(LINK(this, SalInstanceLinkButton, ClickHdl));
+ }
+
+ virtual void set_label(const OUString& rText) override { m_xButton->SetText(rText); }
+
+ virtual OUString get_label() const override { return m_xButton->GetText(); }
+
+ virtual void set_uri(const OUString& rUri) override { m_xButton->SetURL(rUri); }
+
+ virtual OUString get_uri() const override { return m_xButton->GetURL(); }
+
+ virtual ~SalInstanceLinkButton() override { m_xButton->SetClickHdl(m_aOrigClickHdl); }
+};
+
+}
+
+IMPL_LINK(SalInstanceLinkButton, ClickHdl, FixedHyperlink&, rButton, void)
+{
+ bool bConsumed = signal_activate_link();
+ if (!bConsumed)
+ m_aOrigClickHdl.Call(rButton);
+}
+
+namespace
+{
+class SalInstanceRadioButton : public SalInstanceButton, public virtual weld::RadioButton
+{
+private:
+ VclPtr<::RadioButton> m_xRadioButton;
+
+ DECL_LINK(ToggleHdl, ::RadioButton&, void);
+
+public:
+ SalInstanceRadioButton(::RadioButton* pButton, SalInstanceBuilder* pBuilder,
+ bool bTakeOwnership)
+ : SalInstanceButton(pButton, pBuilder, bTakeOwnership)
+ , m_xRadioButton(pButton)
+ {
+ m_xRadioButton->SetToggleHdl(LINK(this, SalInstanceRadioButton, ToggleHdl));
+ }
+
+ virtual void set_active(bool active) override
+ {
+ disable_notify_events();
+ m_xRadioButton->Check(active);
+ enable_notify_events();
+ }
+
+ virtual bool get_active() const override { return m_xRadioButton->IsChecked(); }
+
+ virtual void set_image(VirtualDevice* pDevice) override
+ {
+ m_xRadioButton->SetImageAlign(ImageAlign::Center);
+ if (pDevice)
+ m_xRadioButton->SetModeImage(createImage(*pDevice));
+ else
+ m_xRadioButton->SetModeImage(Image());
+ }
+
+ virtual void set_image(const css::uno::Reference<css::graphic::XGraphic>& rImage) override
+ {
+ m_xRadioButton->SetImageAlign(ImageAlign::Center);
+ m_xRadioButton->SetModeImage(Image(rImage));
+ }
+
+ virtual void set_from_icon_name(const OUString& rIconName) override
+ {
+ m_xRadioButton->SetModeRadioImage(Image(StockImage::Yes, rIconName));
+ }
+
+ virtual void set_inconsistent(bool /*inconsistent*/) override
+ {
+ //not available
+ }
+
+ virtual bool get_inconsistent() const override { return false; }
+
+ virtual ~SalInstanceRadioButton() override
+ {
+ m_xRadioButton->SetToggleHdl(Link<::RadioButton&, void>());
+ }
+};
+
+}
+
+IMPL_LINK_NOARG(SalInstanceRadioButton, ToggleHdl, ::RadioButton&, void)
+{
+ if (notify_events_disabled())
+ return;
+ signal_toggled();
+}
+
+namespace
+{
+class SalInstanceToggleButton : public SalInstanceButton, public virtual weld::ToggleButton
+{
+private:
+ VclPtr<PushButton> m_xToggleButton;
+
+ DECL_LINK(ToggleListener, VclWindowEvent&, void);
+
+public:
+ SalInstanceToggleButton(PushButton* pButton, SalInstanceBuilder* pBuilder, bool bTakeOwnership)
+ : SalInstanceButton(pButton, pBuilder, bTakeOwnership)
+ , m_xToggleButton(pButton)
+ {
+ }
+
+ virtual void connect_toggled(const Link<ToggleButton&, void>& rLink) override
+ {
+ assert(!m_aToggleHdl.IsSet());
+ m_xToggleButton->AddEventListener(LINK(this, SalInstanceToggleButton, ToggleListener));
+ weld::ToggleButton::connect_toggled(rLink);
+ }
+
+ virtual void set_active(bool active) override
+ {
+ disable_notify_events();
+ m_xToggleButton->Check(active);
+ enable_notify_events();
+ }
+
+ virtual bool get_active() const override { return m_xToggleButton->IsChecked(); }
+
+ virtual void set_inconsistent(bool inconsistent) override
+ {
+ disable_notify_events();
+ m_xToggleButton->SetState(inconsistent ? TRISTATE_INDET : TRISTATE_FALSE);
+ enable_notify_events();
+ }
+
+ virtual bool get_inconsistent() const override
+ {
+ return m_xToggleButton->GetState() == TRISTATE_INDET;
+ }
+
+ virtual ~SalInstanceToggleButton() override
+ {
+ if (m_aToggleHdl.IsSet())
+ m_xToggleButton->RemoveEventListener(
+ LINK(this, SalInstanceToggleButton, ToggleListener));
+ }
+};
+
+}
+
+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;
+}
+
+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 SalInstanceImage : public SalInstanceWidget, public virtual weld::Image
+{
+private:
+ VclPtr<FixedImage> m_xImage;
+
+public:
+ SalInstanceImage(FixedImage* pImage, SalInstanceBuilder* pBuilder, bool bTakeOwnership)
+ : SalInstanceWidget(pImage, pBuilder, bTakeOwnership)
+ , m_xImage(pImage)
+ {
+ }
+
+ virtual void set_from_icon_name(const OUString& rIconName) override
+ {
+ m_xImage->SetImage(::Image(StockImage::Yes, rIconName));
+ }
+
+ virtual void set_image(VirtualDevice* pDevice) override
+ {
+ if (pDevice)
+ m_xImage->SetImage(createImage(*pDevice));
+ else
+ m_xImage->SetImage(::Image());
+ }
+
+ virtual void set_image(const css::uno::Reference<css::graphic::XGraphic>& rImage) override
+ {
+ m_xImage->SetImage(::Image(rImage));
+ }
+};
+
+class SalInstanceCalendar : public SalInstanceWidget, public virtual weld::Calendar
+{
+private:
+ VclPtr<::Calendar> m_xCalendar;
+
+ DECL_LINK(SelectHdl, ::Calendar*, void);
+ DECL_LINK(ActivateHdl, ::Calendar*, void);
+
+public:
+ SalInstanceCalendar(::Calendar* pCalendar, SalInstanceBuilder* pBuilder, bool bTakeOwnership)
+ : SalInstanceWidget(pCalendar, pBuilder, bTakeOwnership)
+ , m_xCalendar(pCalendar)
+ {
+ m_xCalendar->SetSelectHdl(LINK(this, SalInstanceCalendar, SelectHdl));
+ m_xCalendar->SetActivateHdl(LINK(this, SalInstanceCalendar, ActivateHdl));
+ }
+
+ virtual void set_date(const Date& rDate) override { m_xCalendar->SetCurDate(rDate); }
+
+ virtual Date get_date() const override { return m_xCalendar->GetFirstSelectedDate(); }
+
+ virtual ~SalInstanceCalendar() override
+ {
+ m_xCalendar->SetSelectHdl(Link<::Calendar*, void>());
+ m_xCalendar->SetActivateHdl(Link<::Calendar*, void>());
+ }
+};
+
+}
+
+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();
+}
+
+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();
+ m_xEntry->SetSelection(Selection(nStartPos, nEndPos < 0 ? SELECTION_MAX : nEndPos));
+ 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_message_type(weld::EntryMessageType eType)
+{
+ if (eType == weld::EntryMessageType::Error)
+ {
+ // tdf#114603: enable setting the background to a different color;
+ // relevant for GTK; see also #i75179#
+ m_xEntry->SetForceControlBackground(true);
+ m_xEntry->SetControlForeground(COL_WHITE);
+ m_xEntry->SetControlBackground(0xff6563);
+ }
+ else if (eType == weld::EntryMessageType::Warning)
+ {
+ // tdf#114603: enable setting the background to a different color;
+ // relevant for GTK; see also #i75179#
+ m_xEntry->SetForceControlBackground(true);
+ m_xEntry->SetControlForeground();
+ m_xEntry->SetControlBackground(COL_YELLOW);
+ }
+ else
+ {
+ m_xEntry->SetForceControlBackground(false);
+ m_xEntry->SetControlForeground();
+ m_xEntry->SetControlBackground();
+ }
+}
+
+void SalInstanceEntry::set_font(const vcl::Font& rFont)
+{
+ m_xEntry->SetPointFont(*m_xEntry, rFont);
+ m_xEntry->Invalidate();
+}
+
+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();
+}
+
+void SalInstanceEntry::copy_clipboard()
+{
+ m_xEntry->Copy();
+}
+
+void SalInstanceEntry::paste_clipboard()
+{
+ m_xEntry->Paste();
+}
+
+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); }
+
+namespace
+{
+struct SalInstanceTreeIter : public weld::TreeIter
+{
+ SalInstanceTreeIter(const SalInstanceTreeIter* pOrig)
+ : iter(pOrig ? pOrig->iter : nullptr)
+ {
+ }
+ SalInstanceTreeIter(SvTreeListEntry* pIter)
+ : iter(pIter)
+ {
+ }
+ virtual bool equal(const TreeIter& rOther) const override
+ {
+ return iter == static_cast<const SalInstanceTreeIter&>(rOther).iter;
+ }
+ SvTreeListEntry* iter;
+};
+
+TriState get_toggle(SvTreeListEntry* pEntry, int col)
+{
+ ++col; //skip dummy/expander column
+
+ 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;
+}
+
+bool get_text_emphasis(SvTreeListEntry* pEntry, int col)
+{
+ ++col; //skip dummy/expander column
+
+ 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();
+}
+}
+
+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);
+ }
+ };
+}
+
+class SalInstanceTreeView : public SalInstanceContainer, public virtual weld::TreeView
+{
+private:
+ // owner for UserData
+ std::vector<std::unique_ptr<OUString>> m_aUserData;
+ VclPtr<SvTabListBox> m_xTreeView;
+ SvLBoxButtonData m_aCheckButtonData;
+ SvLBoxButtonData m_aRadioButtonData;
+ // currently expanding parent that logically, but not currently physically,
+ // contain placeholders
+ o3tl::sorted_vector<SvTreeListEntry*> m_aExpandingPlaceHolderParents;
+ // which columns should be custom rendered
+ o3tl::sorted_vector<int> m_aCustomRenders;
+ bool m_bDisableCheckBoxAutoWidth;
+ int m_nSortColumn;
+
+ DECL_LINK(SelectHdl, SvTreeListBox*, void);
+ DECL_LINK(DeSelectHdl, SvTreeListBox*, void);
+ DECL_LINK(DoubleClickHdl, SvTreeListBox*, bool);
+ DECL_LINK(ExpandingHdl, SvTreeListBox*, bool);
+ DECL_LINK(EndDragHdl, HeaderBar*, void);
+ DECL_LINK(HeaderBarClickedHdl, HeaderBar*, void);
+ DECL_LINK(ToggleHdl, SvLBoxButtonData*, void);
+ DECL_LINK(ModelChangedHdl, SvTreeListBox*, void);
+ DECL_LINK(StartDragHdl, SvTreeListBox*, bool);
+ DECL_STATIC_LINK(SalInstanceTreeView, FinishDragHdl, SvTreeListBox*, void);
+ DECL_LINK(EditingEntryHdl, SvTreeListEntry*, bool);
+ typedef std::pair<SvTreeListEntry*, OUString> IterString;
+ DECL_LINK(EditedEntryHdl, IterString, bool);
+ DECL_LINK(VisibleRangeChangedHdl, SvTreeListBox*, void);
+ DECL_LINK(CompareHdl, const SvSortData&, sal_Int32);
+ DECL_LINK(PopupMenuHdl, const CommandEvent&, bool);
+ DECL_LINK(TooltipHdl, const HelpEvent&, bool);
+ DECL_LINK(CustomRenderHdl, svtree_render_args, void);
+ DECL_LINK(CustomMeasureHdl, svtree_measure_args, Size);
+
+ bool IsDummyEntry(SvTreeListEntry* pEntry) const
+ {
+ return m_xTreeView->GetEntryText(pEntry).trim() == "<dummy>";
+ }
+
+ SvTreeListEntry* GetPlaceHolderChild(SvTreeListEntry* pEntry) const
+ {
+ if (pEntry->HasChildren())
+ {
+ auto pChild = m_xTreeView->FirstChild(pEntry);
+ assert(pChild);
+ if (IsDummyEntry(pChild))
+ return pChild;
+ }
+ return nullptr;
+ }
+
+ static void set_font_color(SvTreeListEntry* pEntry, const Color& rColor)
+ {
+ if (rColor == COL_AUTO)
+ pEntry->SetTextColor(std::optional<Color>());
+ else
+ pEntry->SetTextColor(rColor);
+ }
+
+ void 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 InvalidateModelEntry(SvTreeListEntry* pEntry)
+ {
+ if (!m_xTreeView->GetModel()->IsEnableInvalidate())
+ return;
+ m_xTreeView->ModelHasEntryInvalidated(pEntry);
+ }
+
+public:
+ SalInstanceTreeView(SvTabListBox* pTreeView, SalInstanceBuilder* pBuilder, bool bTakeOwnership)
+ : SalInstanceContainer(pTreeView, pBuilder, bTakeOwnership)
+ , m_xTreeView(pTreeView)
+ , m_aCheckButtonData(pTreeView, false)
+ , m_aRadioButtonData(pTreeView, true)
+ , m_bDisableCheckBoxAutoWidth(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 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));
+ }
+
+ virtual void connect_query_tooltip(const Link<const weld::TreeIter&, OUString>& rLink) override
+ {
+ weld::TreeView::connect_query_tooltip(rLink);
+ m_xTreeView->SetTooltipHdl(LINK(this, SalInstanceTreeView, TooltipHdl));
+ }
+
+ virtual void columns_autosize() override
+ {
+ std::vector<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);
+ }
+ }
+
+ virtual void freeze() override
+ {
+ SalInstanceWidget::freeze();
+ m_xTreeView->SetUpdateMode(false);
+ }
+
+ virtual void thaw() override
+ {
+ m_xTreeView->SetUpdateMode(true);
+ SalInstanceWidget::thaw();
+ }
+
+ virtual void set_column_fixed_widths(const std::vector<int>& rWidths) override
+ {
+ m_bDisableCheckBoxAutoWidth = true;
+ std::vector<long> aTabPositions;
+ aTabPositions.push_back(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);
+ 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]);
+ }
+ // call Resize to recalculate based on the new tabs
+ m_xTreeView->Resize();
+ }
+
+ virtual void set_column_editables(const std::vector<bool>& rEditables) override
+ {
+ size_t nTabCount = rEditables.size();
+ for (size_t i = 0 ; i < nTabCount; ++i)
+ m_xTreeView->SetTabEditable(i, rEditables[i]);
+ }
+
+ virtual void set_centered_column(int nCol) override
+ {
+ m_xTreeView->SetTabJustify(nCol, SvTabJustify::AdjustCenter);
+ }
+
+ virtual int get_column_width(int nColumn) const override
+ {
+ 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;
+ }
+
+ virtual OUString get_column_title(int nColumn) const override
+ {
+ LclHeaderTabListBox* pHeaderBox = dynamic_cast<LclHeaderTabListBox*>(m_xTreeView.get());
+ if (HeaderBar* pHeaderBar = pHeaderBox ? pHeaderBox->GetHeaderBar() : nullptr)
+ {
+ return pHeaderBar->GetItemText(pHeaderBar->GetItemId(nColumn));
+ }
+ return OUString();
+ }
+
+ virtual void set_column_title(int nColumn, const OUString& rTitle) override
+ {
+ LclHeaderTabListBox* pHeaderBox = dynamic_cast<LclHeaderTabListBox*>(m_xTreeView.get());
+ if (HeaderBar* pHeaderBar = pHeaderBox ? pHeaderBox->GetHeaderBar() : nullptr)
+ {
+ return pHeaderBar->SetItemText(pHeaderBar->GetItemId(nColumn), rTitle);
+ }
+ }
+
+ virtual void set_column_custom_renderer(int nColumn, bool bEnable) override
+ {
+ assert(n_children() == 0 && "tree must be empty");
+ if (bEnable)
+ m_aCustomRenders.insert(nColumn);
+ else
+ m_aCustomRenders.erase(nColumn);
+ }
+
+ virtual void show() override
+ {
+ if (LclHeaderTabListBox* pHeaderBox = dynamic_cast<LclHeaderTabListBox*>(m_xTreeView.get()))
+ pHeaderBox->GetParent()->Show();
+ SalInstanceContainer::show();
+ }
+
+ virtual void hide() override
+ {
+ if (LclHeaderTabListBox* pHeaderBox = dynamic_cast<LclHeaderTabListBox*>(m_xTreeView.get()))
+ pHeaderBox->GetParent()->Hide();
+ SalInstanceContainer::hide();
+ }
+
+ virtual void insert(const weld::TreeIter* pParent, int pos, const OUString* pStr,
+ const OUString* pId, const OUString* pIconName,
+ VirtualDevice* pImageSurface, const OUString* pExpanderName,
+ bool bChildrenOnDemand, weld::TreeIter* pRet) override
+ {
+ 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 (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, 0);
+ pEntry->SetUserData(pUserData);
+ m_xTreeView->Insert(pEntry, iter, nInsertPos);
+
+ if (pExpanderName)
+ {
+ Image aImage(createImage(*pExpanderName));
+ m_xTreeView->SetExpandedEntryBmp(pEntry, aImage);
+ m_xTreeView->SetCollapsedEntryBmp(pEntry, aImage);
+ }
+
+ 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);
+ }
+ enable_notify_events();
+ }
+
+ virtual void
+ bulk_insert_for_each(int nSourceCount,
+ const std::function<void(weld::TreeIter&, int nSourceIndex)>& func,
+ const std::vector<int>* pFixedWidths) override
+ {
+ freeze();
+ clear();
+ SalInstanceTreeIter aVclIter(static_cast<SvTreeListEntry*>(nullptr));
+
+ m_xTreeView->nTreeFlags |= SvTreeFlags::MANINS;
+
+ if (pFixedWidths)
+ set_column_fixed_widths(*pFixedWidths);
+
+ Image aDummy;
+ for (int i = 0; i < nSourceCount; ++i)
+ {
+ aVclIter.iter = new SvTreeListEntry;
+ aVclIter.iter->AddItem(std::make_unique<SvLBoxContextBmp>(aDummy, aDummy, false));
+ m_xTreeView->Insert(aVclIter.iter, nullptr, 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);
+ SvViewDataItem* pViewDataItem = m_xTreeView->GetViewDataItem(aVclIter.iter, &rItem);
+ pViewDataItem->mnWidth = (*pFixedWidths)[j];
+ }
+ }
+
+ m_xTreeView->nTreeFlags &= ~SvTreeFlags::MANINS;
+
+ thaw();
+ }
+
+ virtual void set_font_color(int pos, const Color& rColor) override
+ {
+ SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos);
+ set_font_color(pEntry, rColor);
+ }
+
+ virtual void set_font_color(const weld::TreeIter& rIter, const Color& rColor) override
+ {
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ set_font_color(rVclIter.iter, rColor);
+ }
+
+ virtual void remove(int pos) override
+ {
+ disable_notify_events();
+ SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos);
+ m_xTreeView->RemoveEntry(pEntry);
+ enable_notify_events();
+ }
+
+ virtual int find_text(const OUString& rText) const override
+ {
+ for (SvTreeListEntry* pEntry = m_xTreeView->First(); pEntry;
+ pEntry = m_xTreeView->Next(pEntry))
+ {
+ if (SvTabListBox::GetEntryText(pEntry, 0) == rText)
+ return SvTreeList::GetRelPos(pEntry);
+ }
+ return -1;
+ }
+
+ virtual int find_id(const OUString& rId) const override
+ {
+ 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;
+ }
+
+ virtual void swap(int pos1, int pos2) override
+ {
+ 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);
+ }
+
+ virtual void clear() override
+ {
+ disable_notify_events();
+ m_xTreeView->Clear();
+ m_aUserData.clear();
+ enable_notify_events();
+ }
+
+ virtual int n_children() const override
+ {
+ return m_xTreeView->GetModel()->GetChildList(nullptr).size();
+ }
+
+ virtual int iter_n_children(const weld::TreeIter& rIter) const override
+ {
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ return m_xTreeView->GetModel()->GetChildList(rVclIter.iter).size();
+ }
+
+ virtual void select(int pos) override
+ {
+ 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);
+ m_xTreeView->Select(pEntry, true);
+ m_xTreeView->MakeVisible(pEntry);
+ }
+ enable_notify_events();
+ }
+
+ virtual int get_cursor_index() const override
+ {
+ SvTreeListEntry* pEntry = m_xTreeView->GetCurEntry();
+ if (!pEntry)
+ return -1;
+ return SvTreeList::GetRelPos(pEntry);
+ }
+
+ virtual void set_cursor(int pos) override
+ {
+ 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();
+ }
+
+ virtual void scroll_to_row(int pos) override
+ {
+ 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();
+ }
+
+ virtual bool is_selected(int pos) const override
+ {
+ SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos);
+ return m_xTreeView->IsSelected(pEntry);
+ }
+
+ virtual void unselect(int pos) override
+ {
+ 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();
+ }
+
+ virtual std::vector<int> get_selected_rows() const override
+ {
+ 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;
+ }
+
+ static OUString get_text(SvTreeListEntry* pEntry, int col)
+ {
+ if (col == -1)
+ return SvTabListBox::GetEntryText(pEntry, 0);
+
+ ++col; //skip dummy/expander column
+
+ 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();
+ }
+
+ virtual OUString get_text(int pos, int col) const override
+ {
+ SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos);
+ return get_text(pEntry, col);
+ }
+
+ void set_text(SvTreeListEntry* pEntry, const OUString& rText, int col)
+ {
+ if (col == -1)
+ {
+ m_xTreeView->SetEntryText(pEntry, rText);
+ return;
+ }
+
+ ++col; //skip dummy/expander column
+
+ // 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);
+ }
+
+ virtual void set_text(int pos, const OUString& rText, int col) override
+ {
+ SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos);
+ set_text(pEntry, rText, col);
+ }
+
+ void 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.Enable(bSensitive);
+ InvalidateModelEntry(pEntry);
+ break;
+ }
+ }
+ return;
+ }
+
+ ++col; //skip dummy/expander column
+
+ assert(col >= 0 && o3tl::make_unsigned(col) < pEntry->ItemCount());
+ SvLBoxItem& rItem = pEntry->GetItem(col);
+ rItem.Enable(bSensitive);
+
+ InvalidateModelEntry(pEntry);
+ }
+
+ using SalInstanceWidget::set_sensitive;
+
+ virtual void set_sensitive(int pos, bool bSensitive, int col) override
+ {
+ SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos);
+ set_sensitive(pEntry, bSensitive, col);
+ }
+
+ virtual void set_sensitive(const weld::TreeIter& rIter, bool bSensitive, int col) override
+ {
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ set_sensitive(rVclIter.iter, bSensitive, col);
+ }
+
+ virtual TriState get_toggle(int pos, int col) const override
+ {
+ SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos);
+ return ::get_toggle(pEntry, col);
+ }
+
+ virtual TriState get_toggle(const weld::TreeIter& rIter, int col) const override
+ {
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ return ::get_toggle(rVclIter.iter, col);
+ }
+
+ void set_toggle(SvTreeListEntry* pEntry, TriState eState, int col)
+ {
+ bool bRadio = std::find(m_aRadioIndexes.begin(), m_aRadioIndexes.end(), col)
+ != m_aRadioIndexes.end();
+ ++col; //skip dummy/expander column
+
+ // 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 = bRadio ? &m_aRadioButtonData : &m_aCheckButtonData;
+
+ // if we want to have the implicit auto-sizing of the checkbox
+ // column we need to call EnableCheckButton and CheckBoxInserted to
+ // let it figure out that width. But we don't want to override any
+ // explicitly set column width, so disable this if we've set
+ // explicit column widths
+ if (!m_bDisableCheckBoxAutoWidth)
+ {
+ if (!(m_xTreeView->GetTreeFlags() & SvTreeFlags::CHKBTN))
+ {
+ m_xTreeView->EnableCheckButton(pData);
+ // EnableCheckButton clobbered this, restore it
+ pData->SetLink(LINK(this, SalInstanceTreeView, ToggleHdl));
+ }
+ }
+
+ pEntry->AddItem(std::make_unique<SvLBoxButton>(pData));
+ SvViewDataEntry* pViewData = m_xTreeView->GetViewDataEntry(pEntry);
+ m_xTreeView->InitViewData(pViewData, pEntry);
+
+ if (!m_bDisableCheckBoxAutoWidth)
+ m_xTreeView->CheckBoxInserted(pEntry);
+ }
+
+ assert(col >= 0 && o3tl::make_unsigned(col) < pEntry->ItemCount());
+ 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);
+ }
+
+ virtual void set_toggle(int pos, TriState eState, int col) override
+ {
+ SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos);
+ set_toggle(pEntry, eState, col);
+ }
+
+ virtual void set_toggle(const weld::TreeIter& rIter, TriState eState, int col) override
+ {
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ set_toggle(rVclIter.iter, eState, col);
+ }
+
+ virtual void set_extra_row_indent(const weld::TreeIter& rIter, int nIndentLevel) override
+ {
+ weld::TreeIter& rNonConstIter = const_cast<weld::TreeIter&>(rIter);
+ SalInstanceTreeIter& rVclIter = static_cast<SalInstanceTreeIter&>(rNonConstIter);
+ rVclIter.iter->SetExtraIndent(nIndentLevel);
+ }
+
+ void set_text_emphasis(SvTreeListEntry* pEntry, bool bOn, int col)
+ {
+ ++col; //skip dummy/expander column
+
+ 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);
+ }
+
+ virtual void set_text_emphasis(const weld::TreeIter& rIter, bool bOn, int col) override
+ {
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ set_text_emphasis(rVclIter.iter, bOn, col);
+ }
+
+ virtual void set_text_emphasis(int pos, bool bOn, int col) override
+ {
+ SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos);
+ set_text_emphasis(pEntry, bOn, col);
+ }
+
+ virtual bool get_text_emphasis(const weld::TreeIter& rIter, int col) const override
+ {
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ return ::get_text_emphasis(rVclIter.iter, col);
+ }
+
+ virtual bool get_text_emphasis(int pos, int col) const override
+ {
+ SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos);
+ return ::get_text_emphasis(pEntry, col);
+ }
+
+ void set_text_align(SvTreeListEntry* pEntry, double fAlign, int col)
+ {
+ ++col; //skip dummy/expander column
+
+ 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);
+ }
+
+ virtual void set_text_align(const weld::TreeIter& rIter, double fAlign, int col) override
+ {
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ set_text_align(rVclIter.iter, fAlign, col);
+ }
+
+ virtual void set_text_align(int pos, double fAlign, int col) override
+ {
+ SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos);
+ set_text_align(pEntry, fAlign, col);
+ }
+
+ virtual void connect_editing(
+ const Link<const weld::TreeIter&, bool>& rStartLink,
+ const Link<const std::pair<const weld::TreeIter&, OUString>&, bool>& rEndLink) override
+ {
+ m_xTreeView->EnableInplaceEditing(rStartLink.IsSet() || rEndLink.IsSet());
+ weld::TreeView::connect_editing(rStartLink, rEndLink);
+ }
+
+ virtual void start_editing(const weld::TreeIter& rIter) override
+ {
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ m_xTreeView->EditEntry(rVclIter.iter);
+ }
+
+ virtual void end_editing() override { m_xTreeView->EndEditing(); }
+
+ void set_image(SvTreeListEntry* pEntry, const Image& rImage, int col)
+ {
+ if (col == -1)
+ {
+ m_xTreeView->SetExpandedEntryBmp(pEntry, rImage);
+ m_xTreeView->SetCollapsedEntryBmp(pEntry, rImage);
+ return;
+ }
+
+ ++col; //skip dummy/expander column
+
+ // 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->SetEntryHeight(pEntry);
+ InvalidateModelEntry(pEntry);
+ }
+
+ virtual void set_image(int pos, const OUString& rImage, int col) override
+ {
+ set_image(m_xTreeView->GetEntry(nullptr, pos), createImage(rImage), col);
+ }
+
+ virtual void set_image(int pos, const css::uno::Reference<css::graphic::XGraphic>& rImage,
+ int col) override
+ {
+ set_image(m_xTreeView->GetEntry(nullptr, pos), Image(rImage), col);
+ }
+
+ virtual void set_image(int pos, VirtualDevice& rImage, int col) override
+ {
+ set_image(m_xTreeView->GetEntry(nullptr, pos), createImage(rImage), col);
+ }
+
+ virtual void set_image(const weld::TreeIter& rIter, const OUString& rImage, int col) override
+ {
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ set_image(rVclIter.iter, createImage(rImage), col);
+ }
+
+ virtual void set_image(const weld::TreeIter& rIter,
+ const css::uno::Reference<css::graphic::XGraphic>& rImage,
+ int col) override
+ {
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ set_image(rVclIter.iter, Image(rImage), col);
+ }
+
+ virtual void set_image(const weld::TreeIter& rIter, VirtualDevice& rImage, int col) override
+ {
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ set_image(rVclIter.iter, createImage(rImage), col);
+ }
+
+ const OUString* getEntryData(int index) const
+ {
+ SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, index);
+ return pEntry ? static_cast<const OUString*>(pEntry->GetUserData()) : nullptr;
+ }
+
+ virtual OUString get_id(int pos) const override
+ {
+ const OUString* pRet = getEntryData(pos);
+ if (!pRet)
+ return OUString();
+ return *pRet;
+ }
+
+ void set_id(SvTreeListEntry* pEntry, const OUString& rId)
+ {
+ m_aUserData.emplace_back(std::make_unique<OUString>(rId));
+ pEntry->SetUserData(m_aUserData.back().get());
+ }
+
+ virtual void set_id(int pos, const OUString& rId) override
+ {
+ SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos);
+ set_id(pEntry, rId);
+ }
+
+ virtual int get_selected_index() const override
+ {
+ assert(m_xTreeView->IsUpdateMode() && "don't request selection when frozen");
+ SvTreeListEntry* pEntry = m_xTreeView->FirstSelected();
+ if (!pEntry)
+ return -1;
+ return SvTreeList::GetRelPos(pEntry);
+ }
+
+ virtual OUString get_selected_text() const override
+ {
+ assert(m_xTreeView->IsUpdateMode() && "don't request selection when frozen");
+ if (SvTreeListEntry* pEntry = m_xTreeView->FirstSelected())
+ return m_xTreeView->GetEntryText(pEntry);
+ return OUString();
+ }
+
+ virtual OUString get_selected_id() const override
+ {
+ 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();
+ }
+
+ virtual std::unique_ptr<weld::TreeIter>
+ make_iterator(const weld::TreeIter* pOrig) const override
+ {
+ return std::unique_ptr<weld::TreeIter>(
+ new SalInstanceTreeIter(static_cast<const SalInstanceTreeIter*>(pOrig)));
+ }
+
+ virtual void copy_iterator(const weld::TreeIter& rSource, weld::TreeIter& rDest) const override
+ {
+ const SalInstanceTreeIter& rVclSource(static_cast<const SalInstanceTreeIter&>(rSource));
+ SalInstanceTreeIter& rVclDest(static_cast<SalInstanceTreeIter&>(rDest));
+ rVclDest.iter = rVclSource.iter;
+ }
+
+ virtual bool get_selected(weld::TreeIter* pIter) const override
+ {
+ SvTreeListEntry* pEntry = m_xTreeView->FirstSelected();
+ auto pVclIter = static_cast<SalInstanceTreeIter*>(pIter);
+ if (pVclIter)
+ pVclIter->iter = pEntry;
+ return pEntry != nullptr;
+ }
+
+ virtual bool get_cursor(weld::TreeIter* pIter) const override
+ {
+ SvTreeListEntry* pEntry = m_xTreeView->GetCurEntry();
+ auto pVclIter = static_cast<SalInstanceTreeIter*>(pIter);
+ if (pVclIter)
+ pVclIter->iter = pEntry;
+ return pEntry != nullptr;
+ }
+
+ virtual void set_cursor(const weld::TreeIter& rIter) override
+ {
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ disable_notify_events();
+ m_xTreeView->SetCurEntry(rVclIter.iter);
+ enable_notify_events();
+ }
+
+ virtual bool get_iter_first(weld::TreeIter& rIter) const override
+ {
+ SalInstanceTreeIter& rVclIter = static_cast<SalInstanceTreeIter&>(rIter);
+ rVclIter.iter = m_xTreeView->GetEntry(0);
+ return rVclIter.iter != nullptr;
+ }
+
+ virtual bool iter_next_sibling(weld::TreeIter& rIter) const override
+ {
+ SalInstanceTreeIter& rVclIter = static_cast<SalInstanceTreeIter&>(rIter);
+ rVclIter.iter = rVclIter.iter->NextSibling();
+ return rVclIter.iter != nullptr;
+ }
+
+ virtual bool iter_previous_sibling(weld::TreeIter& rIter) const override
+ {
+ SalInstanceTreeIter& rVclIter = static_cast<SalInstanceTreeIter&>(rIter);
+ rVclIter.iter = rVclIter.iter->PrevSibling();
+ return rVclIter.iter != nullptr;
+ }
+
+ virtual bool iter_next(weld::TreeIter& rIter) const override
+ {
+ 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;
+ }
+
+ virtual bool iter_previous(weld::TreeIter& rIter) const override
+ {
+ 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;
+ }
+
+ virtual bool iter_next_visible(weld::TreeIter& rIter) const override
+ {
+ SalInstanceTreeIter& rVclIter = static_cast<SalInstanceTreeIter&>(rIter);
+ rVclIter.iter = m_xTreeView->NextVisible(rVclIter.iter);
+ if (rVclIter.iter && IsDummyEntry(rVclIter.iter))
+ return iter_next_visible(rVclIter);
+ return rVclIter.iter != nullptr;
+ }
+
+ virtual bool iter_children(weld::TreeIter& rIter) const override
+ {
+ 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;
+ }
+
+ virtual bool iter_parent(weld::TreeIter& rIter) const override
+ {
+ SalInstanceTreeIter& rVclIter = static_cast<SalInstanceTreeIter&>(rIter);
+ rVclIter.iter = m_xTreeView->GetParent(rVclIter.iter);
+ return rVclIter.iter != nullptr;
+ }
+
+ virtual void remove(const weld::TreeIter& rIter) override
+ {
+ disable_notify_events();
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ m_xTreeView->RemoveEntry(rVclIter.iter);
+ enable_notify_events();
+ }
+
+ virtual void select(const weld::TreeIter& rIter) override
+ {
+ 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();
+ }
+
+ virtual void scroll_to_row(const weld::TreeIter& rIter) override
+ {
+ 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();
+ }
+
+ virtual void unselect(const weld::TreeIter& rIter) override
+ {
+ 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();
+ }
+
+ virtual int get_iter_depth(const weld::TreeIter& rIter) const override
+ {
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ return m_xTreeView->GetModel()->GetDepth(rVclIter.iter);
+ }
+
+ virtual bool iter_has_child(const weld::TreeIter& rIter) const override
+ {
+ weld::TreeIter& rNonConstIter = const_cast<weld::TreeIter&>(rIter);
+ SalInstanceTreeIter& rVclIter = static_cast<SalInstanceTreeIter&>(rNonConstIter);
+ SvTreeListEntry* restore(rVclIter.iter);
+ bool ret = iter_children(rNonConstIter);
+ rVclIter.iter = restore;
+ return ret;
+ }
+
+ virtual bool get_row_expanded(const weld::TreeIter& rIter) const override
+ {
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ return m_xTreeView->IsExpanded(rVclIter.iter);
+ }
+
+ virtual bool get_children_on_demand(const weld::TreeIter& rIter) const override
+ {
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ if (m_aExpandingPlaceHolderParents.count(rVclIter.iter))
+ return true;
+ return GetPlaceHolderChild(rVclIter.iter) != nullptr;
+ }
+
+ virtual void set_children_on_demand(const weld::TreeIter& rIter, bool bChildrenOnDemand) override
+ {
+ 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();
+ }
+
+ virtual void expand_row(const weld::TreeIter& rIter) override
+ {
+ assert(m_xTreeView->IsUpdateMode() && "don't expand when frozen");
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ if (!m_xTreeView->IsExpanded(rVclIter.iter) && signal_expanding(rIter))
+ m_xTreeView->Expand(rVclIter.iter);
+ }
+
+ virtual void collapse_row(const weld::TreeIter& rIter) override
+ {
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ if (m_xTreeView->IsExpanded(rVclIter.iter) && signal_collapsing(rIter))
+ m_xTreeView->Collapse(rVclIter.iter);
+ }
+
+ virtual OUString get_text(const weld::TreeIter& rIter, int col) const override
+ {
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ return get_text(rVclIter.iter, col);
+ }
+
+ virtual void set_text(const weld::TreeIter& rIter, const OUString& rText, int col) override
+ {
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ set_text(rVclIter.iter, rText, col);
+ }
+
+ virtual OUString get_id(const weld::TreeIter& rIter) const override
+ {
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ const OUString* pStr = static_cast<const OUString*>(rVclIter.iter->GetUserData());
+ if (pStr)
+ return *pStr;
+ return OUString();
+ }
+
+ virtual void set_id(const weld::TreeIter& rIter, const OUString& rId) override
+ {
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ set_id(rVclIter.iter, rId);
+ }
+
+ virtual void enable_drag_source(rtl::Reference<TransferDataContainer>& rHelper,
+ sal_uInt8 eDNDConstants) override
+ {
+ m_xTreeView->SetDragHelper(rHelper, eDNDConstants);
+ }
+
+ virtual void set_selection_mode(SelectionMode eMode) override
+ {
+ m_xTreeView->SetSelectionMode(eMode);
+ }
+
+ virtual void all_foreach(const std::function<bool(weld::TreeIter&)>& func) override
+ {
+ UpdateGuardIfHidden aGuard(*m_xTreeView);
+
+ SalInstanceTreeIter aVclIter(m_xTreeView->First());
+ while (aVclIter.iter)
+ {
+ if (func(aVclIter))
+ return;
+ iter_next(aVclIter);
+ }
+ }
+
+ virtual void selected_foreach(const std::function<bool(weld::TreeIter&)>& func) override
+ {
+ SalInstanceTreeIter aVclIter(m_xTreeView->FirstSelected());
+ while (aVclIter.iter)
+ {
+ if (func(aVclIter))
+ return;
+ aVclIter.iter = m_xTreeView->NextSelected(aVclIter.iter);
+ }
+ }
+
+ virtual void visible_foreach(const std::function<bool(weld::TreeIter&)>& func) override
+ {
+ SalInstanceTreeIter aVclIter(m_xTreeView->GetFirstEntryInView());
+ while (aVclIter.iter)
+ {
+ if (func(aVclIter))
+ return;
+ aVclIter.iter = m_xTreeView->GetNextEntryInView(aVclIter.iter);
+ }
+ }
+
+ virtual void connect_visible_range_changed(const Link<weld::TreeView&, void>& rLink) override
+ {
+ weld::TreeView::connect_visible_range_changed(rLink);
+ m_xTreeView->SetScrolledHdl(LINK(this, SalInstanceTreeView, VisibleRangeChangedHdl));
+ }
+
+ virtual void remove_selection() override
+ {
+ 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();
+ }
+
+ virtual bool is_selected(const weld::TreeIter& rIter) const override
+ {
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ return m_xTreeView->IsSelected(rVclIter.iter);
+ }
+
+ virtual int get_iter_index_in_parent(const weld::TreeIter& rIter) const override
+ {
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ return SvTreeList::GetRelPos(rVclIter.iter);
+ }
+
+ virtual int iter_compare(const weld::TreeIter& a, const weld::TreeIter& b) const override
+ {
+ 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;
+ }
+
+ virtual void move_subtree(weld::TreeIter& rNode, const weld::TreeIter* pNewParent,
+ int nIndexInNewParent) override
+ {
+ 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);
+ }
+
+ virtual int count_selected_rows() const override { return m_xTreeView->GetSelectionCount(); }
+
+ virtual int get_height_rows(int nRows) const override
+ {
+ return m_xTreeView->GetEntryHeight() * nRows;
+ }
+
+ virtual void make_sorted() override
+ {
+ 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);
+ }
+
+ virtual void set_sort_func(
+ const std::function<int(const weld::TreeIter&, const weld::TreeIter&)>& func) override
+ {
+ weld::TreeView::set_sort_func(func);
+ SvTreeList* pListModel = m_xTreeView->GetModel();
+ pListModel->Resort();
+ }
+
+ virtual void make_unsorted() override
+ {
+ m_xTreeView->SetStyle(m_xTreeView->GetStyle() & ~WB_SORT);
+ }
+
+ virtual void set_sort_order(bool bAscending) override
+ {
+ SvTreeList* pListModel = m_xTreeView->GetModel();
+ pListModel->SetSortMode(bAscending ? SortAscending : SortDescending);
+ pListModel->Resort();
+ }
+
+ virtual bool get_sort_order() const override
+ {
+ return m_xTreeView->GetModel()->GetSortMode() == SortAscending;
+ }
+
+ virtual void set_sort_indicator(TriState eState, int col) override
+ {
+ if (col == -1)
+ col = 0;
+
+ 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);
+ 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);
+ }
+ }
+
+ virtual TriState get_sort_indicator(int col) const override
+ {
+ if (col == -1)
+ col = 0;
+
+ 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;
+ }
+
+ virtual int get_sort_column() const override { return m_nSortColumn; }
+
+ virtual void set_sort_column(int nColumn) override
+ {
+ if (nColumn == -1)
+ {
+ make_unsorted();
+ m_nSortColumn = -1;
+ return;
+ }
+
+ if (nColumn != m_nSortColumn)
+ {
+ m_nSortColumn = nColumn;
+ m_xTreeView->GetModel()->Resort();
+ }
+ }
+
+ SvTabListBox& getTreeView() { return *m_xTreeView; }
+
+ virtual bool get_dest_row_at_pos(const Point& rPos, weld::TreeIter* pResult, bool bHighLightTarget) override
+ {
+ LclTabListBox* pTreeView = !bHighLightTarget ? dynamic_cast<LclTabListBox*>(m_xTreeView.get()) : nullptr;
+ SvTreeListEntry* pTarget = pTreeView ? pTreeView->GetTargetAtPoint(rPos, false) : m_xTreeView->GetDropTarget(rPos);
+
+ if (pTarget && pResult)
+ {
+ SalInstanceTreeIter& rSalIter = static_cast<SalInstanceTreeIter&>(*pResult);
+ rSalIter.iter = pTarget;
+ }
+
+ return pTarget != nullptr;
+ }
+
+ virtual void unset_drag_dest_row() override
+ {
+ m_xTreeView->UnsetDropTarget();
+ }
+
+ virtual tools::Rectangle get_row_area(const weld::TreeIter& rIter) const override
+ {
+ return m_xTreeView->GetBoundingRect(static_cast<const SalInstanceTreeIter&>(rIter).iter);
+ }
+
+ virtual TreeView* get_drag_source() const override { return g_DragSource; }
+
+ virtual int vadjustment_get_value() const override
+ {
+ int nValue = -1;
+ const SvTreeListEntry* pEntry = m_xTreeView->GetFirstEntryInView();
+ if (pEntry)
+ nValue = m_xTreeView->GetAbsPos(pEntry);
+ return nValue;
+ }
+
+ virtual void vadjustment_set_value(int nValue) override
+ {
+ 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);
+ }
+
+ virtual ~SalInstanceTreeView() override
+ {
+ 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>());
+ }
+ 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(Link<const HelpEvent&, bool>());
+ m_xTreeView->SetCustomRenderHdl(Link<svtree_render_args, void>());
+ m_xTreeView->SetCustomMeasureHdl(Link<svtree_measure_args, Size>());
+ }
+};
+
+IMPL_LINK(SalInstanceTreeView, TooltipHdl, const HelpEvent&, rHEvt, bool)
+{
+ if (notify_events_disabled())
+ return false;
+ Point aPos(m_xTreeView->ScreenToOutputPixel(rHEvt.GetMousePosPixel()));
+ SvTreeListEntry* pEntry = m_xTreeView->GetEntry(aPos);
+ if (pEntry)
+ {
+ SalInstanceTreeIter aIter(pEntry);
+ OUString aTooltip = signal_query_tooltip(aIter);
+ if (aTooltip.isEmpty())
+ return false;
+ Size aSize(m_xTreeView->GetOutputSizePixel().Width(), m_xTreeView->GetEntryHeight());
+ tools::Rectangle aScreenRect(
+ m_xTreeView->OutputToScreenPixel(m_xTreeView->GetEntryPosition(pEntry)), aSize);
+ Help::ShowQuickHelp(m_xTreeView, aScreenRect, aTooltip);
+ }
+ return true;
+}
+
+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 = m_nSortColumn;
+
+ ++col; //skip dummy/expander column
+
+ 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);
+ }
+
+ // toggled signal handlers can query get_cursor to get which
+ // node was clicked
+ m_xTreeView->pImpl->m_pCursor = pEntry;
+
+ for (int i = 1, nCount = pEntry->ItemCount(); i < nCount; ++i)
+ {
+ SvLBoxItem& rItem = pEntry->GetItem(i);
+ if (&rItem == pBox)
+ {
+ int nRow = SvTreeList::GetRelPos(pEntry);
+ int nCol = i - 1; // less dummy/expander column
+ signal_toggled(std::make_pair(nRow, 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)
+ 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<long> aTabPositions;
+ aTabPositions.push_back(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
+
+ // 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(aIter);
+
+ 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(std::pair<const weld::TreeIter&, OUString>(
+ SalInstanceTreeIter(rIterString.first), rIterString.second));
+}
+
+class SalInstanceIconView : public SalInstanceContainer, public virtual weld::IconView
+{
+private:
+ // owner for UserData
+ std::vector<std::unique_ptr<OUString>> m_aUserData;
+ VclPtr<::IconView> m_xIconView;
+
+ DECL_LINK(SelectHdl, SvTreeListBox*, void);
+ DECL_LINK(DeSelectHdl, SvTreeListBox*, void);
+ DECL_LINK(DoubleClickHdl, SvTreeListBox*, bool);
+
+public:
+ SalInstanceIconView(::IconView* pIconView, SalInstanceBuilder* pBuilder, bool bTakeOwnership)
+ : SalInstanceContainer(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));
+ }
+
+ virtual void freeze() override
+ {
+ SalInstanceWidget::freeze();
+ m_xIconView->SetUpdateMode(false);
+ }
+
+ virtual void thaw() override
+ {
+ m_xIconView->SetUpdateMode(true);
+ SalInstanceWidget::thaw();
+ }
+
+ virtual void insert(int pos, const OUString* pStr, const OUString* pId,
+ const OUString* pIconName, weld::TreeIter* pRet) override
+ {
+ 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();
+ }
+
+ virtual OUString get_selected_id() const override
+ {
+ 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();
+ }
+
+ virtual OUString get_selected_text() const override
+ {
+ assert(m_xIconView->IsUpdateMode() && "don't request selection when frozen");
+ if (SvTreeListEntry* pEntry = m_xIconView->FirstSelected())
+ return m_xIconView->GetEntryText(pEntry);
+ return OUString();
+ }
+
+ virtual int count_selected_items() const override { return m_xIconView->GetSelectionCount(); }
+
+ virtual void select(int pos) override
+ {
+ 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();
+ }
+
+ virtual void unselect(int pos) override
+ {
+ 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();
+ }
+
+ virtual int n_children() const override
+ {
+ return m_xIconView->GetModel()->GetChildList(nullptr).size();
+ }
+
+ virtual std::unique_ptr<weld::TreeIter>
+ make_iterator(const weld::TreeIter* pOrig) const override
+ {
+ return std::unique_ptr<weld::TreeIter>(
+ new SalInstanceTreeIter(static_cast<const SalInstanceTreeIter*>(pOrig)));
+ }
+
+ virtual bool get_selected(weld::TreeIter* pIter) const override
+ {
+ SvTreeListEntry* pEntry = m_xIconView->FirstSelected();
+ auto pVclIter = static_cast<SalInstanceTreeIter*>(pIter);
+ if (pVclIter)
+ pVclIter->iter = pEntry;
+ return pEntry != nullptr;
+ }
+
+ virtual bool get_cursor(weld::TreeIter* pIter) const override
+ {
+ SvTreeListEntry* pEntry = m_xIconView->GetCurEntry();
+ auto pVclIter = static_cast<SalInstanceTreeIter*>(pIter);
+ if (pVclIter)
+ pVclIter->iter = pEntry;
+ return pEntry != nullptr;
+ }
+
+ virtual void set_cursor(const weld::TreeIter& rIter) override
+ {
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ disable_notify_events();
+ m_xIconView->SetCurEntry(rVclIter.iter);
+ enable_notify_events();
+ }
+
+ virtual bool get_iter_first(weld::TreeIter& rIter) const override
+ {
+ SalInstanceTreeIter& rVclIter = static_cast<SalInstanceTreeIter&>(rIter);
+ rVclIter.iter = m_xIconView->GetEntry(0);
+ return rVclIter.iter != nullptr;
+ }
+
+ virtual void scroll_to_item(const weld::TreeIter& rIter) override
+ {
+ 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();
+ }
+
+ virtual void selected_foreach(const std::function<bool(weld::TreeIter&)>& func) override
+ {
+ SalInstanceTreeIter aVclIter(m_xIconView->FirstSelected());
+ while (aVclIter.iter)
+ {
+ if (func(aVclIter))
+ return;
+ aVclIter.iter = m_xIconView->NextSelected(aVclIter.iter);
+ }
+ }
+
+ virtual OUString get_id(const weld::TreeIter& rIter) const override
+ {
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ const OUString* pStr = static_cast<const OUString*>(rVclIter.iter->GetUserData());
+ if (pStr)
+ return *pStr;
+ return OUString();
+ }
+
+ virtual void clear() override
+ {
+ disable_notify_events();
+ m_xIconView->Clear();
+ m_aUserData.clear();
+ enable_notify_events();
+ }
+
+ virtual ~SalInstanceIconView() override
+ {
+ 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();
+}
+
+double SalInstanceSpinButton::toField(int nValue) const
+{
+ return static_cast<double>(nValue) / Power10(get_digits());
+ }
+
+int SalInstanceSpinButton::fromField(double fValue) const
+{
+ return FRound(fValue * Power10(get_digits()));
+}
+
+SalInstanceSpinButton::SalInstanceSpinButton(FormattedField* pButton, SalInstanceBuilder* pBuilder,
+ bool bTakeOwnership)
+ : SalInstanceEntry(pButton, pBuilder, bTakeOwnership)
+ , m_xButton(pButton)
+{
+ m_xButton->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_xButton->SetOutputHdl(LINK(this, SalInstanceSpinButton, OutputHdl));
+ m_xButton->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));
+}
+
+int SalInstanceSpinButton::get_value() const
+{
+ return fromField(m_xButton->GetValue());
+ }
+
+void SalInstanceSpinButton::set_value(int value)
+{
+ m_xButton->SetValue(toField(value));
+ }
+
+void SalInstanceSpinButton::set_range(int min, int max)
+{
+ m_xButton->SetMinValue(toField(min));
+ m_xButton->SetMaxValue(toField(max));
+}
+
+void SalInstanceSpinButton::get_range(int& min, int& max) const
+{
+ min = fromField(m_xButton->GetMinValue());
+ max = fromField(m_xButton->GetMaxValue());
+}
+
+void SalInstanceSpinButton::set_increments(int step, int /*page*/)
+{
+ m_xButton->SetSpinSize(toField(step));
+}
+
+void SalInstanceSpinButton::get_increments(int& step, int& page) const
+{
+ step = fromField(m_xButton->GetSpinSize());
+ page = fromField(m_xButton->GetSpinSize());
+}
+
+void SalInstanceSpinButton::set_digits(unsigned int digits)
+{
+ m_xButton->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();
+}
+
+//so with hh::mm::ss, incrementing mm will not reset ss
+void SalInstanceSpinButton::DisableRemainderFactor()
+{
+ m_xButton->DisableRemainderFactor();
+}
+
+//off by default for direct SpinButtons, MetricSpinButton enables it
+void SalInstanceSpinButton::SetUseThousandSep()
+{
+ m_xButton->SetThousandsSep(true);
+}
+
+unsigned int SalInstanceSpinButton::get_digits() const
+{
+ return m_xButton->GetDecimalDigits();
+}
+
+SalInstanceSpinButton::~SalInstanceSpinButton()
+{
+ if (Edit* pEdit = m_xButton->GetSubEdit())
+ pEdit->SetActivateHdl(Link<Edit&, bool>());
+ else
+ m_xButton->SetActivateHdl(Link<Edit&, bool>());
+ m_xButton->SetInputHdl(Link<sal_Int64*, TriState>());
+ m_xButton->SetOutputHdl(Link<Edit&, 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, Edit&, 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;
+}
+
+namespace
+{
+class SalInstanceFormattedSpinButton : public SalInstanceEntry,
+ public virtual weld::FormattedSpinButton
+{
+private:
+ VclPtr<FormattedField> m_xButton;
+
+public:
+ SalInstanceFormattedSpinButton(FormattedField* pButton, SalInstanceBuilder* pBuilder,
+ bool bTakeOwnership)
+ : SalInstanceEntry(pButton, pBuilder, bTakeOwnership)
+ , m_xButton(pButton)
+ {
+ // #i6278# allow more decimal places than the output format. As
+ // the numbers shown in the edit fields are used for input, it makes more
+ // sense to display the values in the input format rather than the output
+ // format.
+ m_xButton->UseInputStringForFormatting();
+ }
+
+ virtual double get_value() const override { return m_xButton->GetValue(); }
+
+ virtual void set_value(double value) override { m_xButton->SetValue(value); }
+
+ virtual void set_range(double min, double max) override
+ {
+ m_xButton->SetMinValue(min);
+ m_xButton->SetMaxValue(max);
+ }
+
+ virtual void get_range(double& min, double& max) const override
+ {
+ min = m_xButton->GetMinValue();
+ max = m_xButton->GetMaxValue();
+ }
+
+ virtual void set_formatter(SvNumberFormatter* pFormatter) override
+ {
+ m_xButton->SetFormatter(pFormatter);
+ }
+
+ virtual SvNumberFormatter* get_formatter() override { return m_xButton->GetFormatter(); }
+
+ virtual sal_Int32 get_format_key() const override { return m_xButton->GetFormatKey(); }
+
+ virtual void set_format_key(sal_Int32 nFormatKey) override
+ {
+ m_xButton->SetFormatKey(nFormatKey);
+ }
+
+ virtual void treat_as_number(bool bSet) override { m_xButton->TreatAsNumber(bSet); }
+
+ virtual void set_digits(unsigned int digits) override { m_xButton->SetDecimalDigits(digits); }
+};
+
+}
+
+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_message_type(weld::EntryMessageType eType)
+{
+ if (eType == weld::EntryMessageType::Error)
+ m_xLabel->SetControlBackground(
+ m_xLabel->GetSettings().GetStyleSettings().GetHighlightColor());
+ else if (eType == weld::EntryMessageType::Warning)
+ m_xLabel->SetControlBackground(COL_YELLOW);
+ else
+ m_xLabel->SetControlBackground();
+}
+
+void SalInstanceLabel::set_font(const vcl::Font& rFont)
+{
+ m_xLabel->SetPointFont(*m_xLabel, 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);
+}
+
+namespace
+{
+class SalInstanceTextView : public SalInstanceContainer, public virtual weld::TextView
+{
+private:
+ VclPtr<VclMultiLineEdit> m_xTextView;
+ Link<ScrollBar*, void> m_aOrigVScrollHdl;
+
+ DECL_LINK(ChangeHdl, Edit&, void);
+ DECL_LINK(VscrollHdl, ScrollBar*, void);
+ DECL_LINK(CursorListener, VclWindowEvent&, void);
+
+public:
+ SalInstanceTextView(VclMultiLineEdit* pTextView, SalInstanceBuilder* pBuilder,
+ bool bTakeOwnership)
+ : SalInstanceContainer(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));
+ }
+
+ virtual void set_text(const OUString& rText) override
+ {
+ disable_notify_events();
+ m_xTextView->SetText(rText);
+ enable_notify_events();
+ }
+
+ virtual void replace_selection(const OUString& rText) override
+ {
+ disable_notify_events();
+ m_xTextView->ReplaceSelected(rText);
+ enable_notify_events();
+ }
+
+ virtual OUString get_text() const override { return m_xTextView->GetText(); }
+
+ bool get_selection_bounds(int& rStartPos, int& rEndPos) override
+ {
+ const Selection& rSelection = m_xTextView->GetSelection();
+ rStartPos = rSelection.Min();
+ rEndPos = rSelection.Max();
+ return rSelection.Len();
+ }
+
+ virtual void select_region(int nStartPos, int nEndPos) override
+ {
+ disable_notify_events();
+ m_xTextView->SetSelection(Selection(nStartPos, nEndPos < 0 ? SELECTION_MAX : nEndPos));
+ enable_notify_events();
+ }
+
+ virtual void set_editable(bool bEditable) override { m_xTextView->SetReadOnly(!bEditable); }
+
+ virtual void set_monospace(bool bMonospace) override
+ {
+ vcl::Font aOrigFont = m_xTextView->GetControlFont();
+ vcl::Font aFont;
+ if (bMonospace)
+ aFont = OutputDevice::GetDefaultFont(DefaultFontType::UI_FIXED, LANGUAGE_DONTKNOW,
+ GetDefaultFontFlags::OnlyOne, m_xTextView);
+ else
+ aFont = Application::GetSettings().GetStyleSettings().GetFieldFont();
+ aFont.SetFontHeight(aOrigFont.GetFontHeight());
+ m_xTextView->SetFont(aFont);
+ m_xTextView->SetControlFont(aFont);
+ }
+
+ virtual void connect_cursor_position(const Link<TextView&, void>& rLink) override
+ {
+ assert(!m_aCursorPositionHdl.IsSet());
+ m_xTextView->AddEventListener(LINK(this, SalInstanceTextView, CursorListener));
+ weld::TextView::connect_cursor_position(rLink);
+ }
+
+ virtual int vadjustment_get_value() const override
+ {
+ ScrollBar& rVertScrollBar = m_xTextView->GetVScrollBar();
+ return rVertScrollBar.GetThumbPos();
+ }
+
+ virtual void vadjustment_set_value(int value) override
+ {
+ ScrollBar& rVertScrollBar = m_xTextView->GetVScrollBar();
+ rVertScrollBar.SetThumbPos(value);
+ m_aOrigVScrollHdl.Call(&rVertScrollBar);
+ }
+
+ virtual int vadjustment_get_upper() const override
+ {
+ ScrollBar& rVertScrollBar = m_xTextView->GetVScrollBar();
+ return rVertScrollBar.GetRangeMax();
+ }
+
+ virtual int vadjustment_get_lower() const override
+ {
+ ScrollBar& rVertScrollBar = m_xTextView->GetVScrollBar();
+ return rVertScrollBar.GetRangeMin();
+ }
+
+ virtual int vadjustment_get_page_size() const override
+ {
+ ScrollBar& rVertScrollBar = m_xTextView->GetVScrollBar();
+ return rVertScrollBar.GetVisibleSize();
+ }
+
+ virtual ~SalInstanceTextView() override
+ {
+ 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();
+}
+
+namespace
+{
+class SalInstanceExpander : public SalInstanceContainer, public virtual weld::Expander
+{
+private:
+ VclPtr<VclExpander> m_xExpander;
+
+ DECL_LINK(ExpandedHdl, VclExpander&, void);
+
+public:
+ SalInstanceExpander(VclExpander* pExpander, SalInstanceBuilder* pBuilder, bool bTakeOwnership)
+ : SalInstanceContainer(pExpander, pBuilder, bTakeOwnership)
+ , m_xExpander(pExpander)
+ {
+ m_xExpander->SetExpandedHdl(LINK(this, SalInstanceExpander, ExpandedHdl));
+ }
+
+ virtual bool get_expanded() const override { return m_xExpander->get_expanded(); }
+
+ virtual void set_expanded(bool bExpand) override { m_xExpander->set_expanded(bExpand); }
+
+ virtual ~SalInstanceExpander() override
+ {
+ m_xExpander->SetExpandedHdl(Link<VclExpander&, void>());
+ }
+};
+
+}
+
+IMPL_LINK_NOARG(SalInstanceExpander, ExpandedHdl, VclExpander&, void) { signal_expanded(); }
+
+namespace
+{
+class SalInstanceDrawingArea : public SalInstanceWidget, public virtual weld::DrawingArea
+{
+private:
+ VclPtr<VclDrawingArea> m_xDrawingArea;
+
+ typedef std::pair<vcl::RenderContext&, const tools::Rectangle&> target_and_area;
+ DECL_LINK(PaintHdl, target_and_area, void);
+ DECL_LINK(ResizeHdl, const Size&, void);
+ DECL_LINK(MousePressHdl, const MouseEvent&, bool);
+ DECL_LINK(MouseMoveHdl, const MouseEvent&, bool);
+ DECL_LINK(MouseReleaseHdl, const MouseEvent&, bool);
+ DECL_LINK(KeyPressHdl, const KeyEvent&, bool);
+ DECL_LINK(KeyReleaseHdl, const KeyEvent&, bool);
+ DECL_LINK(StyleUpdatedHdl, VclDrawingArea&, void);
+ DECL_LINK(CommandHdl, const CommandEvent&, bool);
+ DECL_LINK(QueryTooltipHdl, tools::Rectangle&, OUString);
+ DECL_LINK(GetSurroundingHdl, OUString&, int);
+ DECL_LINK(StartDragHdl, VclDrawingArea*, bool);
+
+ // SalInstanceWidget has a generic listener for all these
+ // events, ignore the ones we have specializations for
+ // in VclDrawingArea
+ virtual void HandleEventListener(VclWindowEvent& rEvent) override
+ {
+ if (rEvent.GetId() == VclEventId::WindowResize)
+ return;
+ SalInstanceWidget::HandleEventListener(rEvent);
+ }
+
+ virtual void HandleMouseEventListener(VclSimpleEvent& rEvent) override
+ {
+ if (rEvent.GetId() == VclEventId::WindowMouseButtonDown
+ || rEvent.GetId() == VclEventId::WindowMouseButtonUp
+ || rEvent.GetId() == VclEventId::WindowMouseMove)
+ {
+ return;
+ }
+ SalInstanceWidget::HandleMouseEventListener(rEvent);
+ }
+
+ virtual bool HandleKeyEventListener(VclWindowEvent& /*rEvent*/) override { return false; }
+
+public:
+ 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->SetStartDragHdl(LINK(this, SalInstanceDrawingArea, StartDragHdl));
+ }
+
+ virtual void queue_draw() override { m_xDrawingArea->Invalidate(); }
+
+ virtual void queue_draw_area(int x, int y, int width, int height) override
+ {
+ m_xDrawingArea->Invalidate(tools::Rectangle(Point(x, y), Size(width, height)));
+ }
+
+ virtual void queue_resize() override { m_xDrawingArea->queue_resize(); }
+
+ virtual void connect_size_allocate(const Link<const Size&, void>& rLink) override
+ {
+ weld::Widget::connect_size_allocate(rLink);
+ }
+
+ virtual void connect_key_press(const Link<const KeyEvent&, bool>& rLink) override
+ {
+ weld::Widget::connect_key_press(rLink);
+ }
+
+ virtual void connect_key_release(const Link<const KeyEvent&, bool>& rLink) override
+ {
+ weld::Widget::connect_key_release(rLink);
+ }
+
+ virtual void set_cursor(PointerStyle ePointerStyle) override
+ {
+ m_xDrawingArea->SetPointer(ePointerStyle);
+ }
+
+ virtual void set_input_context(const InputContext& rInputContext) override
+ {
+ m_xDrawingArea->SetInputContext(rInputContext);
+ }
+
+ virtual void im_context_set_cursor_location(const tools::Rectangle& rCursorRect, int nExtTextInputWidth) override
+ {
+ tools::Rectangle aCursorRect = m_xDrawingArea->PixelToLogic(rCursorRect);
+ m_xDrawingArea->SetCursorRect(&aCursorRect, m_xDrawingArea->PixelToLogic(Size(nExtTextInputWidth, 0)).Width());
+ }
+
+ virtual a11yref get_accessible_parent() override
+ {
+ vcl::Window* pParent = m_xDrawingArea->GetParent();
+ if (pParent)
+ return pParent->GetAccessible();
+ return css::uno::Reference<css::accessibility::XAccessible>();
+ }
+
+ virtual a11yrelationset get_accessible_relation_set() override
+ {
+ utl::AccessibleRelationSetHelper* pRelationSetHelper = new utl::AccessibleRelationSetHelper;
+ css::uno::Reference<css::accessibility::XAccessibleRelationSet> xSet = pRelationSetHelper;
+ 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 xSet;
+ }
+
+ virtual Point get_accessible_location() override
+ {
+ return m_xDrawingArea->OutputToAbsoluteScreenPixel(Point());
+ }
+
+ virtual void enable_drag_source(rtl::Reference<TransferDataContainer>& rHelper,
+ sal_uInt8 eDNDConstants) override
+ {
+ m_xDrawingArea->SetDragHelper(rHelper, eDNDConstants);
+ }
+
+ virtual ~SalInstanceDrawingArea() override
+ {
+ 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>());
+ }
+
+ virtual OutputDevice& get_ref_device() override { return *m_xDrawingArea; }
+};
+
+}
+
+IMPL_LINK(SalInstanceDrawingArea, PaintHdl, target_and_area, aPayload, void)
+{
+ m_aDrawHdl.Call(aPayload);
+ tools::Rectangle aFocusRect(m_aGetFocusRectHdl.Call(*this));
+ if (!aFocusRect.IsEmpty())
+ DrawFocusRect(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, 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_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; }
+
+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)
+{
+ if (eType == weld::EntryMessageType::Error)
+ m_xComboBox->SetControlForeground(Color(0xf0, 0, 0));
+ else if (eType == weld::EntryMessageType::Warning)
+ m_xComboBox->SetControlForeground(COL_YELLOW);
+ else
+ m_xComboBox->SetControlForeground();
+}
+
+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_entry_font(const vcl::Font& rFont)
+{
+ Edit* pEdit = m_xComboBox->GetSubEdit();
+ assert(pEdit);
+ pEdit->SetPointFont(*pEdit, rFont);
+ m_xComboBox->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);
+}
+
+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));
+ 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_entry_font(const vcl::Font& rFont) override
+ {
+ Edit& rEntry = m_pEntry->getEntry();
+ rEntry.SetPointFont(rEntry, rFont);
+ rEntry.Invalidate();
+ }
+
+ virtual vcl::Font get_entry_font() override
+ {
+ Edit& rEntry = m_pEntry->getEntry();
+ return rEntry.GetPointFont(rEntry);
+ }
+
+ 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 OString&, 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)
+ {
+ 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);
+ }
+}
+
+SalInstanceBuilder::SalInstanceBuilder(vcl::Window* pParent, const OUString& rUIRoot,
+ const OUString& rUIFile)
+ : weld::Builder()
+ , m_xBuilder(new VclBuilder(pParent, rUIRoot, rUIFile, OString(),
+ css::uno::Reference<css::frame::XFrame>(), false))
+{
+}
+
+std::unique_ptr<weld::MessageDialog> SalInstanceBuilder::weld_message_dialog(const OString& id,
+ bool bTakeOwnership)
+{
+ MessageDialog* pMessageDialog = m_xBuilder->get<MessageDialog>(id);
+ std::unique_ptr<weld::MessageDialog> pRet(
+ pMessageDialog ? new SalInstanceMessageDialog(pMessageDialog, this, false) : nullptr);
+ if (bTakeOwnership && 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 OString& id,
+ bool bTakeOwnership)
+{
+ Dialog* pDialog = m_xBuilder->get<Dialog>(id);
+ std::unique_ptr<weld::Dialog> pRet(pDialog ? new SalInstanceDialog(pDialog, this, false)
+ : nullptr);
+ if (bTakeOwnership && 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 OString& id,
+ bool bTakeOwnership)
+{
+ vcl::RoadmapWizard* pDialog = m_xBuilder->get<vcl::RoadmapWizard>(id);
+ std::unique_ptr<weld::Assistant> pRet(pDialog ? new SalInstanceAssistant(pDialog, this, false)
+ : nullptr);
+ if (bTakeOwnership && 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::Window> SalInstanceBuilder::weld_window(const OString& id,
+ bool bTakeOwnership)
+{
+ SystemWindow* pWindow = m_xBuilder->get<SystemWindow>(id);
+ return pWindow ? std::make_unique<SalInstanceWindow>(pWindow, this, bTakeOwnership) : nullptr;
+}
+
+std::unique_ptr<weld::Widget> SalInstanceBuilder::weld_widget(const OString& id,
+ bool bTakeOwnership)
+{
+ vcl::Window* pWidget = m_xBuilder->get(id);
+ return pWidget ? std::make_unique<SalInstanceWidget>(pWidget, this, bTakeOwnership) : nullptr;
+}
+
+std::unique_ptr<weld::Container> SalInstanceBuilder::weld_container(const OString& id,
+ bool bTakeOwnership)
+{
+ vcl::Window* pContainer = m_xBuilder->get(id);
+ return pContainer ? std::make_unique<SalInstanceContainer>(pContainer, this, bTakeOwnership)
+ : nullptr;
+}
+
+std::unique_ptr<weld::Box> SalInstanceBuilder::weld_box(const OString& id, bool bTakeOwnership)
+{
+ vcl::Window* pContainer = m_xBuilder->get(id);
+ return pContainer ? std::make_unique<SalInstanceBox>(pContainer, this, bTakeOwnership)
+ : nullptr;
+}
+
+std::unique_ptr<weld::Paned> SalInstanceBuilder::weld_paned(const OString& id,
+ bool bTakeOwnership)
+{
+ VclPaned* pPaned = m_xBuilder->get<VclPaned>(id);
+ return pPaned ? std::make_unique<SalInstancePaned>(pPaned, this, bTakeOwnership)
+ : nullptr;
+}
+
+std::unique_ptr<weld::Frame> SalInstanceBuilder::weld_frame(const OString& id, bool bTakeOwnership)
+{
+ VclFrame* pFrame = m_xBuilder->get<VclFrame>(id);
+ std::unique_ptr<weld::Frame> pRet(pFrame ? new SalInstanceFrame(pFrame, this, false) : nullptr);
+ if (bTakeOwnership && pFrame)
+ {
+ assert(!m_aOwnedToplevel && "only one toplevel per .ui allowed");
+ m_aOwnedToplevel.set(pFrame);
+ m_xBuilder->drop_ownership(pFrame);
+ }
+ return pRet;
+}
+
+std::unique_ptr<weld::ScrolledWindow> SalInstanceBuilder::weld_scrolled_window(const OString& id,
+ bool bTakeOwnership)
+{
+ VclScrolledWindow* pScrolledWindow = m_xBuilder->get<VclScrolledWindow>(id);
+ return pScrolledWindow
+ ? std::make_unique<SalInstanceScrolledWindow>(pScrolledWindow, this, bTakeOwnership)
+ : nullptr;
+}
+
+std::unique_ptr<weld::Notebook> SalInstanceBuilder::weld_notebook(const OString& id,
+ bool bTakeOwnership)
+{
+ 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,
+ bTakeOwnership);
+ if (pNotebook->GetType() == WindowType::VERTICALTABCONTROL)
+ return std::make_unique<SalInstanceVerticalNotebook>(
+ static_cast<VerticalTabControl*>(pNotebook), this, bTakeOwnership);
+ return nullptr;
+}
+
+std::unique_ptr<weld::Button> SalInstanceBuilder::weld_button(const OString& id,
+ bool bTakeOwnership)
+{
+ Button* pButton = m_xBuilder->get<Button>(id);
+ return pButton ? std::make_unique<SalInstanceButton>(pButton, this, bTakeOwnership) : nullptr;
+}
+
+std::unique_ptr<weld::MenuButton> SalInstanceBuilder::weld_menu_button(const OString& id,
+ bool bTakeOwnership)
+{
+ MenuButton* pButton = m_xBuilder->get<MenuButton>(id);
+ return pButton ? std::make_unique<SalInstanceMenuButton>(pButton, this, bTakeOwnership)
+ : nullptr;
+}
+
+std::unique_ptr<weld::LinkButton> SalInstanceBuilder::weld_link_button(const OString& id,
+ bool bTakeOwnership)
+{
+ FixedHyperlink* pButton = m_xBuilder->get<FixedHyperlink>(id);
+ return pButton ? std::make_unique<SalInstanceLinkButton>(pButton, this, bTakeOwnership)
+ : nullptr;
+}
+
+std::unique_ptr<weld::ToggleButton> SalInstanceBuilder::weld_toggle_button(const OString& id,
+ bool bTakeOwnership)
+{
+ PushButton* pToggleButton = m_xBuilder->get<PushButton>(id);
+ return pToggleButton
+ ? std::make_unique<SalInstanceToggleButton>(pToggleButton, this, bTakeOwnership)
+ : nullptr;
+}
+
+std::unique_ptr<weld::RadioButton> SalInstanceBuilder::weld_radio_button(const OString& id,
+ bool bTakeOwnership)
+{
+ RadioButton* pRadioButton = m_xBuilder->get<RadioButton>(id);
+ return pRadioButton
+ ? std::make_unique<SalInstanceRadioButton>(pRadioButton, this, bTakeOwnership)
+ : nullptr;
+}
+
+std::unique_ptr<weld::CheckButton> SalInstanceBuilder::weld_check_button(const OString& id,
+ bool bTakeOwnership)
+{
+ CheckBox* pCheckButton = m_xBuilder->get<CheckBox>(id);
+ return pCheckButton
+ ? std::make_unique<SalInstanceCheckButton>(pCheckButton, this, bTakeOwnership)
+ : nullptr;
+}
+
+std::unique_ptr<weld::Scale> SalInstanceBuilder::weld_scale(const OString& id, bool bTakeOwnership)
+{
+ Slider* pSlider = m_xBuilder->get<Slider>(id);
+ return pSlider ? std::make_unique<SalInstanceScale>(pSlider, this, bTakeOwnership) : nullptr;
+}
+
+std::unique_ptr<weld::ProgressBar> SalInstanceBuilder::weld_progress_bar(const OString& id,
+ bool bTakeOwnership)
+{
+ ::ProgressBar* pProgress = m_xBuilder->get<::ProgressBar>(id);
+ return pProgress ? std::make_unique<SalInstanceProgressBar>(pProgress, this, bTakeOwnership)
+ : nullptr;
+}
+
+std::unique_ptr<weld::Spinner> SalInstanceBuilder::weld_spinner(const OString& id,
+ bool bTakeOwnership)
+{
+ Throbber* pThrobber = m_xBuilder->get<Throbber>(id);
+ return pThrobber ? std::make_unique<SalInstanceSpinner>(pThrobber, this, bTakeOwnership)
+ : nullptr;
+}
+
+std::unique_ptr<weld::Image> SalInstanceBuilder::weld_image(const OString& id, bool bTakeOwnership)
+{
+ FixedImage* pImage = m_xBuilder->get<FixedImage>(id);
+ return pImage ? std::make_unique<SalInstanceImage>(pImage, this, bTakeOwnership) : nullptr;
+}
+
+std::unique_ptr<weld::Calendar> SalInstanceBuilder::weld_calendar(const OString& id,
+ bool bTakeOwnership)
+{
+ Calendar* pCalendar = m_xBuilder->get<Calendar>(id);
+ return pCalendar ? std::make_unique<SalInstanceCalendar>(pCalendar, this, bTakeOwnership)
+ : nullptr;
+}
+
+std::unique_ptr<weld::Entry> SalInstanceBuilder::weld_entry(const OString& id, bool bTakeOwnership)
+{
+ Edit* pEntry = m_xBuilder->get<Edit>(id);
+ return pEntry ? std::make_unique<SalInstanceEntry>(pEntry, this, bTakeOwnership) : nullptr;
+}
+
+std::unique_ptr<weld::SpinButton> SalInstanceBuilder::weld_spin_button(const OString& id,
+ bool bTakeOwnership)
+{
+ FormattedField* pSpinButton = m_xBuilder->get<FormattedField>(id);
+ return pSpinButton ? std::make_unique<SalInstanceSpinButton>(pSpinButton, this, bTakeOwnership)
+ : nullptr;
+}
+
+std::unique_ptr<weld::MetricSpinButton>
+SalInstanceBuilder::weld_metric_spin_button(const OString& id, FieldUnit eUnit, bool bTakeOwnership)
+{
+ std::unique_ptr<weld::SpinButton> xButton(weld_spin_button(id, bTakeOwnership));
+ 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 OString& id, bool bTakeOwnership)
+{
+ FormattedField* pSpinButton = m_xBuilder->get<FormattedField>(id);
+ return pSpinButton
+ ? std::make_unique<SalInstanceFormattedSpinButton>(pSpinButton, this, bTakeOwnership)
+ : nullptr;
+}
+
+std::unique_ptr<weld::TimeSpinButton>
+SalInstanceBuilder::weld_time_spin_button(const OString& id, TimeFieldFormat eFormat,
+ bool bTakeOwnership)
+{
+ std::unique_ptr<weld::TimeSpinButton> pRet(
+ new weld::TimeSpinButton(weld_spin_button(id, bTakeOwnership), eFormat));
+ SalInstanceSpinButton& rButton = dynamic_cast<SalInstanceSpinButton&>(pRet->get_widget());
+ rButton.DisableRemainderFactor(); //so with hh::mm::ss, incrementing mm will not reset ss
+ return pRet;
+}
+
+std::unique_ptr<weld::ComboBox> SalInstanceBuilder::weld_combo_box(const OString& id,
+ bool bTakeOwnership)
+{
+ vcl::Window* pWidget = m_xBuilder->get(id);
+ ::ComboBox* pComboBox = dynamic_cast<::ComboBox*>(pWidget);
+ if (pComboBox)
+ return std::make_unique<SalInstanceComboBoxWithEdit>(pComboBox, this, bTakeOwnership);
+ ListBox* pListBox = dynamic_cast<ListBox*>(pWidget);
+ return pListBox
+ ? std::make_unique<SalInstanceComboBoxWithoutEdit>(pListBox, this, bTakeOwnership)
+ : nullptr;
+}
+
+std::unique_ptr<weld::EntryTreeView>
+SalInstanceBuilder::weld_entry_tree_view(const OString& containerid, const OString& entryid,
+ const OString& treeviewid, bool bTakeOwnership)
+{
+ vcl::Window* pContainer = m_xBuilder->get(containerid);
+ return pContainer ? std::make_unique<SalInstanceEntryTreeView>(
+ pContainer, this, bTakeOwnership, weld_entry(entryid, bTakeOwnership),
+ weld_tree_view(treeviewid, bTakeOwnership))
+ : nullptr;
+}
+
+std::unique_ptr<weld::TreeView> SalInstanceBuilder::weld_tree_view(const OString& id,
+ bool bTakeOwnership)
+{
+ SvTabListBox* pTreeView = m_xBuilder->get<SvTabListBox>(id);
+ return pTreeView ? std::make_unique<SalInstanceTreeView>(pTreeView, this, bTakeOwnership)
+ : nullptr;
+}
+
+std::unique_ptr<weld::IconView> SalInstanceBuilder::weld_icon_view(const OString& id,
+ bool bTakeOwnership)
+{
+ IconView* pIconView = m_xBuilder->get<IconView>(id);
+ return pIconView ? std::make_unique<SalInstanceIconView>(pIconView, this, bTakeOwnership)
+ : nullptr;
+}
+
+std::unique_ptr<weld::Label> SalInstanceBuilder::weld_label(const OString& id, bool bTakeOwnership)
+{
+ Control* pLabel = m_xBuilder->get<Control>(id);
+ return pLabel ? std::make_unique<SalInstanceLabel>(pLabel, this, bTakeOwnership) : nullptr;
+}
+
+std::unique_ptr<weld::TextView> SalInstanceBuilder::weld_text_view(const OString& id,
+ bool bTakeOwnership)
+{
+ VclMultiLineEdit* pTextView = m_xBuilder->get<VclMultiLineEdit>(id);
+ return pTextView ? std::make_unique<SalInstanceTextView>(pTextView, this, bTakeOwnership)
+ : nullptr;
+}
+
+std::unique_ptr<weld::Expander> SalInstanceBuilder::weld_expander(const OString& id,
+ bool bTakeOwnership)
+{
+ VclExpander* pExpander = m_xBuilder->get<VclExpander>(id);
+ return pExpander ? std::make_unique<SalInstanceExpander>(pExpander, this, bTakeOwnership)
+ : nullptr;
+}
+
+std::unique_ptr<weld::DrawingArea>
+SalInstanceBuilder::weld_drawing_area(const OString& id, const a11yref& rA11yImpl,
+ FactoryFunction pUITestFactoryFunction, void* pUserData,
+ bool bTakeOwnership)
+{
+ VclDrawingArea* pDrawingArea = m_xBuilder->get<VclDrawingArea>(id);
+ return pDrawingArea ? std::make_unique<SalInstanceDrawingArea>(pDrawingArea, this, rA11yImpl,
+ pUITestFactoryFunction,
+ pUserData, bTakeOwnership)
+ : nullptr;
+}
+
+std::unique_ptr<weld::Menu> SalInstanceBuilder::weld_menu(const OString& id, bool bTakeOwnership)
+{
+ PopupMenu* pMenu = m_xBuilder->get_menu(id);
+ return pMenu ? std::make_unique<SalInstanceMenu>(pMenu, bTakeOwnership) : nullptr;
+}
+
+std::unique_ptr<weld::Toolbar> SalInstanceBuilder::weld_toolbar(const OString& id,
+ bool bTakeOwnership)
+{
+ ToolBox* pToolBox = m_xBuilder->get<ToolBox>(id);
+ return pToolBox ? std::make_unique<SalInstanceToolbar>(pToolBox, this, bTakeOwnership)
+ : nullptr;
+}
+
+std::unique_ptr<weld::SizeGroup> SalInstanceBuilder::create_size_group()
+{
+ return std::make_unique<SalInstanceSizeGroup>();
+}
+
+OString SalInstanceBuilder::get_current_page_help_id() const
+{
+ TabControl* pCtrl = m_xBuilder->get<TabControl>("tabcontrol");
+ TabPage* pTabPage = pCtrl ? pCtrl->GetTabPage(pCtrl->GetCurPageId()) : nullptr;
+ vcl::Window* pTabChild = pTabPage ? pTabPage->GetWindow(GetWindowType::FirstChild) : nullptr;
+ pTabChild = pTabChild ? pTabChild->GetWindow(GetWindowType::FirstChild) : nullptr;
+ if (pTabChild)
+ return pTabChild->GetHelpId();
+ return OString();
+}
+
+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();
+}
+
+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 new SalInstanceBuilder(pParentWidget, rUIRoot, rUIFile);
+}
+
+weld::Builder* SalInstance::CreateInterimBuilder(vcl::Window* pParent, const OUString& rUIRoot,
+ const OUString& rUIFile)
+{
+ return new 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;
+ OString 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)
+ {
+ // 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"))
+ {
+ OString 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(OStringToOUString(sHelpId, RTL_TEXTENCODING_UTF8), 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 OString&)>& 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();
+ pWindow = pWindow ? pWindow->ImplGetWindow() : nullptr;
+ assert(!pWindow || (pWindow->IsSystemWindow() || pWindow->IsDockingWindow()));
+ if (pWindow)
+ m_xFrameWeld.reset(new SalInstanceWindow(pWindow, nullptr, false));
+ }
+ return m_xFrameWeld.get();
+}
+
+/* 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 000000000..aa716f88b
--- /dev/null
+++ b/vcl/source/app/scheduler.cxx
@@ -0,0 +1,659 @@
+/* -*- 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 <tools/diagnose_ex.h>
+#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
+ ProcessEventsToIdle();
+#endif
+ rSchedCtx.mbActive = false;
+
+ assert( nullptr == rSchedCtx.mpSchedulerStack );
+ assert( 1 == rSchedCtx.maMutex.lockDepth() );
+
+ if (rSchedCtx.mpSalTimer) rSchedCtx.mpSalTimer->Stop();
+ DELETEZ( rSchedCtx.mpSalTimer );
+
+#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(), "ImplHandleMouseMsg SalData::mpMouseLeaveTimer" )
+ || !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 SchedulerMutex::acquire( sal_uInt32 nLockCount )
+{
+ assert(nLockCount > 0);
+ for (sal_uInt32 i = 0; i != nLockCount; ++i) {
+ if (!maMutex.acquire())
+ abort();
+ }
+ mnLockDepth += nLockCount;
+}
+
+sal_uInt32 SchedulerMutex::release( bool bUnlockAll )
+{
+ assert(mnLockDepth > 0);
+ const sal_uInt32 nLockCount =
+ (bUnlockAll || 0 == mnLockDepth) ? mnLockDepth : 1;
+ mnLockDepth -= nLockCount;
+ for (sal_uInt32 i = 0; i != nLockCount; ++i) {
+ if (!maMutex.release())
+ abort();
+ }
+ return nLockCount;
+}
+
+void Scheduler::Lock( sal_uInt32 nLockCount )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ assert( pSVData != nullptr );
+ pSVData->maSchedCtx.maMutex.acquire( nLockCount );
+}
+
+sal_uInt32 Scheduler::Unlock( bool bUnlockAll )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ assert( pSVData != nullptr );
+ return pSVData->maSchedCtx.maMutex.release( bUnlockAll );
+}
+
+/**
+ * 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 );
+ }
+}
+
+void Scheduler::CallbackTaskScheduling()
+{
+ // this function is for the saltimer callback
+ Scheduler::ProcessTaskScheduling();
+}
+
+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;
+}
+
+bool Scheduler::ProcessTaskScheduling()
+{
+ ImplSVData *pSVData = ImplGetSVData();
+ ImplSchedulerContext &rSchedCtx = pSVData->maSchedCtx;
+
+ DBG_TESTSOLARMUTEX();
+
+ SchedulerGuard aSchedulerGuard;
+ if ( !rSchedCtx.mbActive || InfiniteTimeoutMs == rSchedCtx.mnTimerPeriod )
+ return false;
+
+ 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 false;
+ }
+
+ 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)
+ {
+ 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 )
+ {
+ SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks() << " "
+ << pMostUrgent << " invoke-in " << *pMostUrgent->mpTask );
+
+ Task *pTask = pMostUrgent->mpTask;
+
+ comphelper::ProfileZone aZone( pTask->GetDebugName() );
+
+ // prepare Scheduler object for deletion after handling
+ pTask->SetDeletionFlags();
+
+ 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;
+
+ // invoke the task
+ sal_uInt32 nLockCount = Unlock( true );
+ try
+ {
+ 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( nLockCount );
+ 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;
+
+ 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 );
+ }
+ }
+
+ return !!pMostUrgent;
+}
+
+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()
+{
+ 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();
+}
+
+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 )
+{
+}
+
+Task::Task( const Task& rTask )
+ : mpSchedulerData( nullptr )
+ , mpDebugName( rTask.mpDebugName )
+ , mePriority( rTask.mePriority )
+ , mbActive( false )
+ , mbStatic( false )
+{
+ 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 000000000..98cad6bba
--- /dev/null
+++ b/vcl/source/app/session.cxx
@@ -0,0 +1,414 @@
+/* -*- 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 <tools/diagnose_ex.h>
+#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/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 >
+{
+ struct Listener
+ {
+ css::uno::Reference< XSessionManagerListener > m_xListener;
+ bool m_bInteractionRequested;
+ bool m_bInteractionDone;
+ bool m_bSaveDone;
+
+ explicit Listener( const css::uno::Reference< XSessionManagerListener >& xListener )
+ : m_xListener( 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;
+
+ void SAL_CALL disposing() override;
+
+ void callSaveRequested( bool bShutdown );
+ void callShutdownCancelled();
+ void callInteractionGranted( bool bGranted );
+ void callQuit();
+
+public:
+ VCLSession();
+};
+
+}
+
+VCLSession::VCLSession()
+ : cppu::WeakComponentImplHelper< XSessionManagerClient >( 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() );
+
+ m_aListeners.erase(std::remove_if(m_aListeners.begin(), m_aListeners.end(), [&](Listener& listener) {return xListener == listener.m_xListener;}), m_aListeners.end());
+}
+
+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 )
+ {
+ 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(static_cast<OWeakObject *>(this));
+ 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
+
+OUString vcl_session_getImplementationName()
+{
+ SAL_INFO("vcl.se", "vcl_session_getImplementationName");
+
+ return "com.sun.star.frame.VCLSessionManagerClient";
+}
+
+Sequence< OUString > vcl_session_getSupportedServiceNames()
+{
+ SAL_INFO("vcl.se", "vcl_session_getSupportedServiceNames");
+
+ Sequence< OUString > aRet { "com.sun.star.frame.SessionManagerClient" };
+ return aRet;
+}
+
+css::uno::Reference< XInterface > vcl_session_createInstance( SAL_UNUSED_PARAMETER const css::uno::Reference< XMultiServiceFactory > & )
+{
+ SAL_INFO("vcl.se", "vcl_session_createInstance");
+
+ return static_cast< cppu::OWeakObject * >(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 000000000..c2ca35835
--- /dev/null
+++ b/vcl/source/app/settings.cxx
@@ -0,0 +1,3233 @@
+/* -*- 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>
+
+using namespace ::com::sun::star;
+
+#include <svdata.hxx>
+
+struct ImplMouseData
+{
+ MouseSettingsOptions mnOptions = MouseSettingsOptions::NONE;
+ sal_uInt64 mnDoubleClkTime = 500;
+ long mnDoubleClkWidth = 2;
+ long mnDoubleClkHeight = 2;
+ long mnStartDragWidth = 2 ;
+ long mnStartDragHeight = 2;
+ sal_uLong mnButtonRepeat = 90;
+ sal_uLong mnMenuDelay = 150;
+ MouseFollowFlags mnFollow = MouseFollowFlags::Menu | MouseFollowFlags::DDList;
+ MouseMiddleButtonAction mnMiddleButtonAction= MouseMiddleButtonAction::AutoScroll;
+ MouseWheelBehaviour mnWheelBehavior = MouseWheelBehaviour::ALWAYS;
+};
+
+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 maFontColor;
+ Color maGroupTextColor;
+ Color maHelpColor;
+ Color maHelpTextColor;
+ Color maHighlightColor;
+ Color maHighlightLinkColor;
+ 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 maMenuBarTextColor;
+ Color maMenuBarRolloverTextColor;
+ Color maMenuBarHighlightTextColor;
+ Color maMonoColor;
+ Color maRadioCheckTextColor;
+ Color maShadowColor;
+ 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;
+ long mnTitleHeight;
+ long mnFloatTitleHeight;
+ long mnScrollBarSize;
+ long mnSpinSize;
+ long mnCursorSize;
+ long 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;
+ long 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_uLong 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( long nDoubleClkWidth )
+{
+ CopyData();
+ mxData->mnDoubleClkWidth = nDoubleClkWidth;
+}
+
+long
+MouseSettings::GetDoubleClickWidth() const
+{
+ return mxData->mnDoubleClkWidth;
+}
+
+void
+MouseSettings::SetDoubleClickHeight( long nDoubleClkHeight )
+{
+ CopyData();
+ mxData->mnDoubleClkHeight = nDoubleClkHeight;
+}
+
+long
+MouseSettings::GetDoubleClickHeight() const
+{
+ return mxData->mnDoubleClkHeight;
+}
+
+void
+MouseSettings::SetStartDragWidth( long nDragWidth )
+{
+ CopyData();
+ mxData->mnStartDragWidth = nDragWidth;
+}
+
+long
+MouseSettings::GetStartDragWidth() const
+{
+ return mxData->mnStartDragWidth;
+}
+
+void
+MouseSettings::SetStartDragHeight( long nDragHeight )
+{
+ CopyData();
+ mxData->mnStartDragHeight = nDragHeight;
+}
+
+long
+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_uLong
+MouseSettings::GetScrollRepeat()
+{
+ return 100;
+}
+
+sal_uLong
+MouseSettings::GetButtonStartRepeat()
+{
+ return 370;
+}
+
+void
+MouseSettings::SetButtonRepeat( sal_uLong nRepeat )
+{
+ CopyData();
+ mxData->mnButtonRepeat = nRepeat;
+}
+
+sal_uLong
+MouseSettings::GetButtonRepeat() const
+{
+ return mxData->mnButtonRepeat;
+}
+
+sal_uLong
+MouseSettings::GetActionDelay()
+{
+ return 250;
+}
+
+void
+MouseSettings::SetMenuDelay( sal_uLong nDelay )
+{
+ CopyData();
+ mxData->mnMenuDelay = nDelay;
+}
+
+sal_uLong
+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 ),
+ maFontColor( rData.maFontColor ),
+ maGroupTextColor( rData.maGroupTextColor ),
+ maHelpColor( rData.maHelpColor ),
+ maHelpTextColor( rData.maHelpTextColor ),
+ maHighlightColor( rData.maHighlightColor ),
+ maHighlightLinkColor( rData.maHighlightLinkColor ),
+ 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 ),
+ maMenuBarTextColor( rData.maMenuBarTextColor ),
+ maMenuBarRolloverTextColor( rData.maMenuBarRolloverTextColor ),
+ maMenuBarHighlightTextColor( rData.maMenuBarHighlightTextColor ),
+ maMonoColor( rData.maMonoColor ),
+ maRadioCheckTextColor( rData.maRadioCheckTextColor ),
+ maShadowColor( rData.maShadowColor ),
+ 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;
+
+ 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;
+ maActiveColor = COL_BLUE;
+ maActiveTextColor = COL_WHITE;
+ 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;
+ maMenuBarTextColor = COL_BLACK;
+ maMenuBarRolloverTextColor = COL_WHITE;
+ maMenuBarHighlightTextColor = COL_WHITE;
+ maMenuHighlightColor = COL_BLUE;
+ maMenuHighlightTextColor = COL_WHITE;
+ maHighlightColor = COL_BLUE;
+ maHighlightTextColor = COL_WHITE;
+ 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;
+ maHighlightLinkColor = COL_LIGHTBLUE;
+ maFontColor = 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::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::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::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;
+}
+
+const Color&
+StyleSettings::GetHighlightLinkColor() const
+{
+ return mxData->maHighlightLinkColor;
+}
+
+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;
+}
+
+long
+StyleSettings::GetBorderSize()
+{
+ return 1;
+}
+
+void
+StyleSettings::SetTitleHeight( long nSize )
+{
+ CopyData();
+ mxData->mnTitleHeight = nSize;
+}
+
+long
+StyleSettings::GetTitleHeight() const
+{
+ return mxData->mnTitleHeight;
+}
+
+void
+StyleSettings::SetFloatTitleHeight( long nSize )
+{
+ CopyData();
+ mxData->mnFloatTitleHeight = nSize;
+}
+
+long
+StyleSettings::GetFloatTitleHeight() const
+{
+ return mxData->mnFloatTitleHeight;
+}
+
+void
+StyleSettings::SetScrollBarSize( long nSize )
+{
+ CopyData();
+ mxData->mnScrollBarSize = nSize;
+}
+
+long
+StyleSettings::GetScrollBarSize() const
+{
+ return mxData->mnScrollBarSize;
+}
+
+void
+StyleSettings::SetMinThumbSize( long nSize )
+{
+ CopyData();
+ mxData->mnMinThumbSize = nSize;
+}
+
+long
+StyleSettings::GetMinThumbSize() const
+{
+ return mxData->mnMinThumbSize;
+}
+
+void
+StyleSettings::SetSpinSize( long nSize )
+{
+ CopyData();
+ mxData->mnSpinSize = nSize;
+}
+
+long
+StyleSettings::GetSpinSize() const
+{
+ return mxData->mnSpinSize;
+}
+
+long
+StyleSettings::GetSplitSize()
+{
+ return 3;
+}
+
+void
+StyleSettings::SetCursorSize( long nSize )
+{
+ CopyData();
+ mxData->mnCursorSize = nSize;
+}
+
+long
+StyleSettings::GetCursorSize() const
+{
+ return mxData->mnCursorSize;
+}
+
+void
+StyleSettings::SetCursorBlinkTime( sal_uInt64 nBlinkTime )
+{
+ CopyData();
+ mxData->mnCursorBlinkTime = nBlinkTime;
+}
+
+sal_uInt64
+StyleSettings::GetCursorBlinkTime() const
+{
+ return static_cast<long>(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( long nMinPixel )
+{
+ CopyData();
+ mxData->mnAntialiasedMin = nMinPixel;
+}
+
+sal_uLong
+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::SetFontColor( const Color& rColor )
+{
+ CopyData();
+ mxData->maFontColor = rColor;
+}
+
+const Color&
+StyleSettings::GetFontColor() const
+{
+ return mxData->maFontColor;
+}
+
+void
+StyleSettings::SetToolbarIconSize( ToolbarIconSize nSize )
+{
+ CopyData();
+ mxData->mnToolbarIconSize = nSize;
+}
+
+ToolbarIconSize
+StyleSettings::GetToolbarIconSize() const
+{
+ return mxData->mnToolbarIconSize;
+}
+
+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::GetColorValueSetMaximumRowCount()
+{
+ return 10;
+}
+
+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;
+ mxData->maLightColor.IncreaseLuminance( 64 );
+ mxData->maShadowColor.DecreaseLuminance( 64 );
+ mxData->maDarkShadowColor.DecreaseLuminance( 100 );
+ sal_uLong nRed = mxData->maLightColor.GetRed();
+ sal_uLong nGreen = mxData->maLightColor.GetGreen();
+ sal_uLong nBlue = mxData->maLightColor.GetBlue();
+ nRed += static_cast<sal_uLong>(mxData->maShadowColor.GetRed());
+ nGreen += static_cast<sal_uLong>(mxData->maShadowColor.GetGreen());
+ nBlue += static_cast<sal_uLong>(mxData->maShadowColor.GetBlue());
+ mxData->maCheckedColor = Color( static_cast<sal_uInt8>(nRed/2), static_cast<sal_uInt8>(nGreen/2), static_cast<sal_uInt8>(nBlue/2) );
+ }
+ 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 )
+{
+ uno::Reference< uno::XComponentContext > xContext( comphelper::getProcessComponentContext() );
+ if ( !xContext.is() )
+ return;
+
+ // 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( xContext ) );
+ OUString aPersonaSettings( officecfg::Office::Common::Misc::PersonaSettings::get( xContext ) );
+
+ // 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( 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->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->maMenuBarTextColor == rSet.mxData->maMenuBarTextColor) &&
+ (mxData->maMenuBarRolloverTextColor == rSet.mxData->maMenuBarRolloverTextColor) &&
+ (mxData->maMenuHighlightColor == rSet.mxData->maMenuHighlightColor) &&
+ (mxData->maMenuHighlightTextColor == rSet.mxData->maMenuHighlightTextColor) &&
+ (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->maHighlightLinkColor == rSet.mxData->maHighlightLinkColor) &&
+ (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->maFontColor == rSet.mxData->maFontColor) &&
+ (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;
+
+ 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" ) );
+ mxData->mnEnableATT = bEnable ? TRISTATE_TRUE : TRISTATE_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;
+}
+
+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_uLong
+HelpSettings::GetTipDelay()
+{
+ return 500;
+}
+
+void
+HelpSettings::SetTipTimeout( sal_uLong nTipTimeout )
+{
+ // copy if other references exist
+ if (mxData.use_count() > 1)
+ {
+ mxData = std::make_shared<ImplHelpData>(*mxData);
+ }
+ mxData->mnTipTimeout = nTipTimeout;
+}
+
+sal_uLong
+HelpSettings::GetTipTimeout() const
+{
+ return mxData->mnTipTimeout;
+}
+
+sal_uLong
+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)
+ {
+ 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
+ uno::Reference<uno::XComponentContext> xContext(comphelper::getProcessComponentContext());
+ if (xContext.is())
+ {
+ sTheme = officecfg::Office::Common::Misc::SymbolStyle::get(xContext);
+
+ 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)
+{
+ mxData->mIconThemeSelector->SetPreferredIconTheme(theme, bDarkIconTheme);
+}
+
+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 000000000..5d1c28e20
--- /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 000000000..7d6bae820
--- /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,
+ const OUString& 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(Image(StockImage::Yes, SV_RESID_BITMAP_ERRORBOX));
+ rImages.emplace_back(Image(StockImage::Yes, SV_RESID_BITMAP_QUERYBOX));
+ rImages.emplace_back(Image(StockImage::Yes, SV_RESID_BITMAP_WARNINGBOX));
+ rImages.emplace_back(Image(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 const char* 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 000000000..720fb32d4
--- /dev/null
+++ b/vcl/source/app/svapp.cxx
@@ -0,0 +1,1707 @@
+/* -*- 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 <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 <unotools/configmgr.hxx>
+#include <unotools/syslocaleoptions.hxx>
+
+#include <vcl/toolkit/dialog.hxx>
+#include <vcl/dialoghelper.hxx>
+#include <vcl/lok.hxx>
+#include <vcl/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>
+#if HAVE_FEATURE_OPENGL
+#include <vcl/opengl/OpenGLWrapper.hxx>
+#endif
+#include <vcl/skia/SkiaHelper.hxx>
+
+#include <salinst.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/solarmutex.hxx>
+#include <osl/process.h>
+
+#include <cassert>
+#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
+static 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
+{
+ VclEventId mnEvent;
+ VclPtr<vcl::Window> mpWin;
+ ImplSVEvent * mnEventId;
+ KeyEvent maKeyEvent;
+ MouseEvent maMouseEvent;
+ GestureEvent maGestureEvent;
+
+ ImplPostEventData(VclEventId nEvent, vcl::Window* pWin, const KeyEvent& rKeyEvent)
+ : mnEvent(nEvent)
+ , mpWin(pWin)
+ , mnEventId(nullptr)
+ , maKeyEvent(rKeyEvent)
+ {}
+ ImplPostEventData(VclEventId nEvent, vcl::Window* pWin, const MouseEvent& rMouseEvent)
+ : mnEvent(nEvent)
+ , mpWin(pWin)
+ , mnEventId(nullptr)
+ , maMouseEvent(rMouseEvent)
+ {}
+ ImplPostEventData(VclEventId nEvent, vcl::Window* pWin, const GestureEvent& rGestureEvent)
+ : mnEvent(nEvent)
+ , mpWin(pWin)
+ , mnEventId(nullptr)
+ , 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;
+}
+
+Application::~Application()
+{
+ ImplDeInitSVData();
+ ImplGetSVData()->mpApp = nullptr;
+}
+
+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;
+
+#ifdef DBG_UTIL
+ case ExceptionCategory::ResourceNotLoaded:
+ Abort("Resource not loaded");
+ break;
+ default:
+ Abort("Unknown Error");
+ break;
+#else
+ default:
+ Abort(OUString());
+ break;
+#endif
+ }
+}
+
+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];
+}
+
+IMPL_STATIC_LINK_NOARG( ImplSVAppData, ImplEndAllPopupsMsg, void*, void )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ while (pSVData->mpWinData->mpFirstFloat)
+ pSVData->mpWinData->mpFirstFloat->EndPopupMode(FloatWinPopupEndFlags::Cancel);
+}
+
+IMPL_STATIC_LINK_NOARG( ImplSVAppData, ImplEndAllDialogsMsg, void*, void )
+{
+ vcl::Window* pAppWindow = Application::GetFirstTopLevelWindow();
+ while (pAppWindow)
+ {
+ vcl::EndAllDialogs(pAppWindow);
+ pAppWindow = Application::GetNextTopLevelWindow(pAppWindow);
+ }
+}
+
+void Application::EndAllDialogs()
+{
+ Application::PostUserEvent( LINK( nullptr, ImplSVAppData, ImplEndAllDialogsMsg ) );
+}
+
+void Application::EndAllPopups()
+{
+ Application::PostUserEvent( LINK( nullptr, ImplSVAppData, ImplEndAllPopupsMsg ) );
+}
+
+
+namespace
+{
+ VclPtr<vcl::Window> GetEventWindow()
+ {
+ VclPtr<vcl::Window> xWin(Application::GetFirstTopLevelWindow());
+ while (xWin)
+ {
+ if (xWin->IsVisible())
+ break;
+ xWin.reset(Application::GetNextTopLevelWindow(xWin));
+ }
+ return xWin;
+ }
+
+ bool InjectKeyEvent(SvStream& rStream)
+ {
+ VclPtr<vcl::Window> xWin(GetEventWindow());
+ if (!xWin)
+ return false;
+
+ // skip the first available cycle and insert on the next one when we
+ // are trying the initial event, flagged by a triggered but undeleted
+ // mpEventTestingIdle
+ ImplSVData* pSVData = ImplGetSVData();
+ if (pSVData->maAppData.mpEventTestingIdle)
+ {
+ delete pSVData->maAppData.mpEventTestingIdle;
+ pSVData->maAppData.mpEventTestingIdle = nullptr;
+ return false;
+ }
+
+ sal_uInt16 nCode, nCharCode;
+ rStream.ReadUInt16(nCode);
+ rStream.ReadUInt16(nCharCode);
+ if (!rStream.good())
+ return false;
+
+ KeyEvent aVCLKeyEvt(nCharCode, nCode);
+ Application::PostKeyEvent(VclEventId::WindowKeyInput, xWin.get(), &aVCLKeyEvt);
+ Application::PostKeyEvent(VclEventId::WindowKeyUp, xWin.get(), &aVCLKeyEvt);
+ return true;
+ }
+
+ void CloseDialogsAndQuit()
+ {
+ Application::EndAllPopups();
+ Application::EndAllDialogs();
+ Application::PostUserEvent( LINK( nullptr, ImplSVAppData, ImplPrepareExitMsg ) );
+ }
+}
+
+IMPL_LINK_NOARG(ImplSVAppData, VclEventTestingHdl, Timer *, void)
+{
+ if (Application::AnyInput())
+ {
+ mpEventTestingIdle->Start();
+ }
+ else
+ {
+ Application::PostUserEvent( LINK( nullptr, ImplSVAppData, ImplVclEventTestingHdl ) );
+ }
+}
+
+IMPL_STATIC_LINK_NOARG( ImplSVAppData, ImplVclEventTestingHdl, void*, void )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ SAL_INFO("vcl.eventtesting", "EventTestLimit is " << pSVData->maAppData.mnEventTestLimit);
+ if (pSVData->maAppData.mnEventTestLimit == 0)
+ {
+ delete pSVData->maAppData.mpEventTestInput;
+ SAL_INFO("vcl.eventtesting", "Event Limit reached, exiting" << pSVData->maAppData.mnEventTestLimit);
+ CloseDialogsAndQuit();
+ }
+ else
+ {
+ if (InjectKeyEvent(*pSVData->maAppData.mpEventTestInput))
+ --pSVData->maAppData.mnEventTestLimit;
+ if (!pSVData->maAppData.mpEventTestInput->good())
+ {
+ SAL_INFO("vcl.eventtesting", "Event Input exhausted, exit next cycle");
+ pSVData->maAppData.mnEventTestLimit = 0;
+ }
+ Application::PostUserEvent( LINK( nullptr, ImplSVAppData, ImplVclEventTestingHdl ) );
+ }
+}
+
+IMPL_STATIC_LINK_NOARG( ImplSVAppData, ImplPrepareExitMsg, void*, void )
+{
+ //now close top level frames
+ (void)GetpApp()->QueryExit();
+}
+
+void Application::Execute()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ pSVData->maAppData.mbInAppExecute = true;
+ pSVData->maAppData.mbAppQuit = false;
+
+ if (Application::IsEventTestingModeEnabled())
+ {
+ pSVData->maAppData.mnEventTestLimit = 50;
+ pSVData->maAppData.mpEventTestingIdle = new Idle("eventtesting");
+ pSVData->maAppData.mpEventTestingIdle->SetInvokeHandler(LINK(&(pSVData->maAppData), ImplSVAppData, VclEventTestingHdl));
+ pSVData->maAppData.mpEventTestingIdle->SetPriority(TaskPriority::HIGH_IDLE);
+ pSVData->maAppData.mpEventTestInput = new SvFileStream("eventtesting", StreamMode::READ);
+ pSVData->maAppData.mpEventTestingIdle->Start();
+ }
+
+ 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 )
+{
+ return ImplYield(false, i_bAllEvents);
+}
+
+void Scheduler::ProcessEventsToIdle()
+{
+ int nSanity = 1;
+ while( Application::Reschedule( 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)
+ {
+ if (pSchedulerData->mpTask && !pSchedulerData->mbInScheduler)
+ {
+ Idle *pIdle = dynamic_cast<Idle*>(pSchedulerData->mpTask);
+ if (pIdle && pIdle->IsActive())
+ {
+ SAL_WARN("vcl.schedule", "Unprocessed Idle: "
+ << pIdle << " " << pIdle->GetDebugName());
+ }
+ }
+ 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()
+{
+ ImplYield(true, false);
+}
+
+IMPL_STATIC_LINK_NOARG( ImplSVAppData, ImplQuitMsg, void*, void )
+{
+ assert(ImplGetSVData()->maAppData.mbAppQuit);
+}
+
+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::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.mpSettings );
+ 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.mpSettings )
+ {
+ InitSettings(pSVData);
+ *pSVData->maAppData.mpSettings = rSettings;
+ }
+ else
+ {
+ AllSettings aOldSettings = *pSVData->maAppData.mpSettings;
+ if (aOldSettings.GetUILanguageTag().getLanguageType() != rSettings.GetUILanguageTag().getLanguageType() &&
+ pSVData->mbResLocaleSet)
+ {
+ pSVData->mbResLocaleSet = false;
+ }
+ *pSVData->maAppData.mpSettings = rSettings;
+ AllSettingsFlags nChangeFlags = aOldSettings.GetChangeFlags( *pSVData->maAppData.mpSettings );
+ 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
+ long nOldDPIX = 0;
+ long nOldDPIY = 0;
+ if ( pFirstFrame )
+ {
+ nOldDPIX = pFirstFrame->GetDPIX();
+ nOldDPIY = pFirstFrame->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->GetDPIX() != nOldDPIX) ||
+ (pFirstFrame->GetDPIY() != nOldDPIY) )
+ {
+ VirtualDevice* pVirDev = pSVData->maGDIData.mpFirstVirDev;
+ while ( pVirDev )
+ {
+ if ( pVirDev->mbScreenComp &&
+ (pVirDev->GetDPIX() == nOldDPIX) &&
+ (pVirDev->GetDPIY() == nOldDPIY) )
+ {
+ pVirDev->SetDPIX( pFirstFrame->GetDPIX() );
+ pVirDev->SetDPIY( pFirstFrame->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.mpSettings )
+ {
+ InitSettings(pSVData);
+ }
+
+ return *(pSVData->maAppData.mpSettings);
+}
+
+namespace {
+
+void InitSettings(ImplSVData* pSVData)
+{
+ assert(!pSVData->maAppData.mpSettings && "initialization should not happen twice!");
+
+ pSVData->maAppData.mpSettings.reset(new AllSettings());
+ if (!utl::ConfigManager::IsFuzzing())
+ {
+ pSVData->maAppData.mpCfgListener = new LocaleConfigurationListener;
+ pSVData->maAppData.mpSettings->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;
+ rVec.erase( std::remove(rVec.begin(), rVec.end(), rKeyListener ), rVec.end() );
+}
+
+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, GestureEvent 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 GestureEvent 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;
+}
+
+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;
+ // Double check that this is indeed a vcl::Window instance.
+ assert(dynamic_cast<vcl::Window *>(
+ static_cast<OutputDevice *>(rLink.GetInstance())) ==
+ static_cast<vcl::Window *>(rLink.GetInstance()));
+ 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()
+{
+ return ImplGetDefaultWindow();
+}
+
+vcl::Window* Application::GetFirstTopLevelWindow()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ return pSVData->maFrameData.mpFirstFrame;
+}
+
+vcl::Window* Application::GetNextTopLevelWindow( vcl::Window const * pWindow )
+{
+ return pWindow->mpWindowImpl->mpFrameData->mpNextFrame;
+}
+
+long Application::GetTopWindowCount()
+{
+ 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( long nIndex )
+{
+ 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(const char *pId, const bool bLocalize)
+{
+ if (bLocalize)
+ return VclResId(pId);
+ else
+ return Translate::get(pId, Translate::Create("vcl", LanguageTag("en-US")));
+}
+
+OUString Application::GetHWOSConfInfo(const int bSelection, const bool bLocalize)
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ OUStringBuffer aDetails;
+
+ const auto appendDetails = [&aDetails](const OUStringLiteral& sep, auto&& val) {
+ if (!aDetails.isEmpty() && sep.getLength())
+ aDetails.append(sep);
+ aDetails.append(std::move(val));
+ };
+
+ if (bSelection != hwUI) {
+ appendDetails("; ", Localize(SV_APP_CPUTHREADS, bLocalize)
+ + OUString::number(std::thread::hardware_concurrency()));
+
+ OUString aVersion;
+ if ( pSVData && pSVData->mpDefInst )
+ aVersion = pSVData->mpDefInst->getOSVersion();
+ else
+ aVersion = "-";
+
+ appendDetails("; ", Localize(SV_APP_OSVERSION, bLocalize) + aVersion);
+ }
+
+ if (bSelection != hwEnv) {
+ appendDetails("; ", Localize(SV_APP_UIRENDER, bLocalize));
+#if HAVE_FEATURE_SKIA
+ if ( SkiaHelper::isVCLSkiaEnabled() )
+ {
+ switch(SkiaHelper::renderMethodToUse())
+ {
+ case SkiaHelper::RenderVulkan:
+ appendDetails("", Localize(SV_APP_SKIA_VULKAN, bLocalize));
+ break;
+ case SkiaHelper::RenderRaster:
+ appendDetails("", Localize(SV_APP_SKIA_RASTER, bLocalize));
+ break;
+ }
+ }
+ else
+#endif
+#if HAVE_FEATURE_OPENGL
+ if ( OpenGLWrapper::isVCLOpenGLEnabled() )
+ appendDetails("", Localize(SV_APP_GL, bLocalize));
+ else
+#endif
+ appendDetails("", Localize(SV_APP_DEFAULT, bLocalize));
+
+#if (defined LINUX || defined _WIN32 || defined MACOSX)
+ appendDetails("; ", 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;
+}
+
+bool Application::IsUnifiedDisplay()
+{
+ SalSystem* pSys = ImplGetSalSystem();
+ return pSys == nullptr || pSys->IsUnifiedDisplay();
+}
+
+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;
+}
+
+tools::Rectangle Application::GetScreenPosSizePixel( unsigned int nScreen )
+{
+ SalSystem* pSys = ImplGetSalSystem();
+ if (!pSys)
+ {
+ SAL_WARN("vcl", "Requesting screen size/pos for screen #" << nScreen << " failed");
+ assert(false);
+ return tools::Rectangle();
+ }
+ tools::Rectangle aRect = pSys->GetDisplayScreenPosSizePixel(nScreen);
+ if (aRect.getHeight() == 0)
+ SAL_WARN("vcl", "Requesting screen size/pos for screen #" << nScreen << " returned 0 height.");
+ return aRect;
+}
+
+namespace {
+unsigned long calcDistSquare( const Point& i_rPoint, const tools::Rectangle& i_rRect )
+{
+ const Point aRectCenter( (i_rRect.Left() + i_rRect.Right())/2,
+ (i_rRect.Top() + i_rRect.Bottom())/ 2 );
+ const long nDX = aRectCenter.X() - i_rPoint.X();
+ const long nDY = aRectCenter.Y() - i_rPoint.Y();
+ return nDX*nDX + nDY*nDY;
+}
+}
+
+unsigned int Application::GetBestScreen( const tools::Rectangle& i_rRect )
+{
+ if( !IsUnifiedDisplay() )
+ return GetDisplayBuiltInScreen();
+
+ const unsigned int nScreens = GetScreenCount();
+ unsigned int nBestMatchScreen = 0;
+ unsigned long nOverlap = 0;
+ for( unsigned int i = 0; i < nScreens; i++ )
+ {
+ const tools::Rectangle aCurScreenRect( GetScreenPosSizePixel( i ) );
+ // if a screen contains the rectangle completely it is obviously the best screen
+ if( aCurScreenRect.IsInside( i_rRect ) )
+ return i;
+ // next the screen which contains most of the area of the rect is the best
+ tools::Rectangle 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 Point aCenter( (i_rRect.Left() + i_rRect.Right())/2,
+ (i_rRect.Top() + i_rRect.Bottom())/2 );
+ unsigned long nDist = ULONG_MAX;
+ for( unsigned int i = 0; i < nScreens; i++ )
+ {
+ const tools::Rectangle aCurScreenRect( GetScreenPosSizePixel( i ) );
+ const unsigned 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* Application::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;
+}
+
+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.get();
+}
+
+void Application::SetFilterHdl( const Link<ConvertData&,bool>& rLink )
+{
+ ImplGetSVData()->maGDIData.mpGrfConverter->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 bEventTestingMode = false;
+
+bool Application::IsEventTestingModeEnabled()
+{
+ return bEventTestingMode;
+}
+
+void Application::EnableEventTestingMode()
+{
+ bEventTestingMode = true;
+}
+
+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 const OUString aNone("none");
+ 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)
+ {
+ // 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;
+}
+
+} // 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 000000000..05d53060b
--- /dev/null
+++ b/vcl/source/app/svdata.cxx
@@ -0,0 +1,491 @@
+/* -*- 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 <tools/diagnose_ex.h>
+#include <unotools/resmgr.hxx>
+#include <sal/log.hxx>
+
+#include <configsettings.hxx>
+#include <vcl/dockwin.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 <units.hrc>
+#include <print.h>
+
+#include <com/sun/star/accessibility/MSAAService.hpp>
+
+#include <config_features.h>
+#if HAVE_FEATURE_OPENGL
+#include <vcl/opengl/OpenGLContext.hxx>
+#endif
+#include <basegfx/utils/systemdependentdata.hxx>
+#include <cppuhelper/basemutex.hxx>
+
+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, protected cppu::BaseMutex
+ {
+ private:
+ std::unique_ptr<AutoTimer> maTimer;
+ EntryMap maEntries;
+
+ DECL_LINK(implTimeoutHdl, Timer *, void);
+
+ public:
+ SystemDependentDataBuffer(const char* pDebugName)
+ : basegfx::SystemDependentDataManager(),
+ 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
+ {
+ ::osl::MutexGuard 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
+ {
+ ::osl::MutexGuard aGuard(m_aMutex);
+ EntryMap::iterator aFound(maEntries.find(rData));
+
+ if(aFound != maEntries.end())
+ {
+ maEntries.erase(aFound);
+ }
+ }
+
+ void touchUsage(basegfx::SystemDependentData_SharedPtr& rData) override
+ {
+ ::osl::MutexGuard aGuard(m_aMutex);
+ EntryMap::iterator aFound(maEntries.find(rData));
+
+ if(aFound != maEntries.end())
+ {
+ aFound->second = rData->calculateCombinedHoldCyclesInSeconds();
+ }
+ }
+
+ void flushAll() override
+ {
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ if(maTimer)
+ {
+ maTimer->Stop();
+ maTimer.reset();
+ }
+
+ maEntries.clear();
+ }
+ };
+
+ IMPL_LINK_NOARG(SystemDependentDataBuffer, implTimeoutHdl, Timer *, void)
+ {
+ ::osl::MutexGuard 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" );
+
+#if HAVE_FEATURE_OPENGL
+ // Add a reference to the default context so it never gets deleted
+ rtl::Reference<OpenGLContext> pContext = pSVData->mpDefaultWin->GetGraphics()->GetOpenGLContext();
+ if( pContext.is() )
+ pContext->acquire();
+#endif
+ }
+ 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(const char* pId)
+{
+ return Translate::get(pId, ImplGetResLocale());
+}
+
+const FieldUnitStringList& ImplGetFieldUnits()
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if( pSVData->maCtrlData.maFieldUnitStrings.empty() )
+ {
+ sal_uInt32 nUnits = SAL_N_ELEMENTS(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;
+}
+
+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)
+ {
+ // 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();
+}
+
+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)
+ {
+ // 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() {}
+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 000000000..e571c2f26
--- /dev/null
+++ b/vcl/source/app/svmain.cxx
@@ -0,0 +1,684 @@
+/* -*- 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/processfactory.hxx>
+#include <comphelper/asyncnotification.hxx>
+#include <i18nlangtag/mslangid.hxx>
+#include <unotools/syslocaleoptions.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>
+
+#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 <svdata.hxx>
+#include <vcl/svmain.hxx>
+#include <dbggui.hxx>
+#include <accmgr.hxx>
+#include <PhysicalFontCollection.hxx>
+#include <print.h>
+#include <salsys.hxx>
+#include <saltimer.hxx>
+#include <displayconnectiondispatch.hxx>
+
+#include <config_features.h>
+#include <config_feature_opencl.h>
+
+#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 <tools/diagnose_ex.h>
+
+#if OSL_DEBUG_LEVEL > 0
+#include <typeinfo>
+#include <rtl/strbuf.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
+ }
+
+ // RC
+ if ((pInfo->Signal == osl_Signal_User) &&
+ (pInfo->UserSignal == OSL_SIGNAL_USER_RESOURCEFAILURE) )
+ nVCLException = ExceptionCategory::ResourceNotLoaded;
+
+ // 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();
+ 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( const css::uno::Reference< css::uno::XCurrentContext > & ctx)
+ : m_xNextContext( 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;
+
+ // 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(".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<PhysicalFontCollection>();
+ pSVData->maGDIData.mxScreenFontCache = std::make_shared<ImplFontCache>();
+ pSVData->maGDIData.mpGrfConverter = 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" );
+ long nTopWindowCount = Application::GetTopWindowCount();
+ long nBadTopWindows = nTopWindowCount;
+ for( 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 = \"" );
+ aBuf.append( OUStringToOString( pWin->GetText(), osl_getThreadTextEncoding() ) );
+ aBuf.append( "\" type = \"" );
+ aBuf.append( typeid(*pWin).name() );
+ aBuf.append( "\", ptr = 0x" );
+ aBuf.append( reinterpret_cast<sal_Int64>( pWin ), 16 );
+ aBuf.append( "\n" );
+ }
+ }
+ SAL_WARN_IF( nBadTopWindows!=0, "vcl", aBuf.getStr() );
+#endif
+
+ ImageTree::get().shutdown();
+
+ osl_removeSignalHandler( pExceptionHandler);
+ pExceptionHandler = nullptr;
+
+ // free global data
+ if (pSVData->maGDIData.mpGrfConverter)
+ {
+ delete pSVData->maGDIData.mpGrfConverter;
+ pSVData->maGDIData.mpGrfConverter = nullptr;
+ }
+
+ pSVData->mpSettingsConfigItem.reset();
+
+ // prevent unnecessary painting during Scheduler shutdown
+ // as this processes all pending events in debug builds.
+ ImplGetSystemDependentDataManager().flushAll();
+
+ Scheduler::ImplDeInitScheduler();
+
+ pSVData->mpWinData->maMsgBoxImgList.clear();
+ pSVData->maCtrlData.maCheckImgList.clear();
+ pSVData->maCtrlData.maRadioImgList.clear();
+ pSVData->maCtrlData.mpDisclosurePlus.reset();
+ pSVData->maCtrlData.mpDisclosureMinus.reset();
+ pSVData->mpDefaultWin.disposeAndClear();
+
+#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 CWinClipbImpl::s_aMutex
+ }
+#endif
+
+#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.mpSettings )
+ {
+ if ( pSVData->maAppData.mpCfgListener )
+ {
+ pSVData->maAppData.mpSettings->GetSysLocale().GetOptions().RemoveListener( pSVData->maAppData.mpCfgListener );
+ delete pSVData->maAppData.mpCfgListener;
+ }
+
+ pSVData->maAppData.mpSettings.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->maGDIData.maScaleCache.remove_if([](const lru_scale_cache::key_value_pair_t&)
+ { return true; });
+
+ pSVData->maGDIData.maThemeDrawCommandsCache.clear();
+ pSVData->maGDIData.maThemeImageCache.clear();
+
+ // Deinit Sal
+ if (pSVData->mpDefInst)
+ {
+ DestroySalInstance( pSVData->mpDefInst );
+ pSVData->mpDefInst = nullptr;
+ }
+
+ 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
+
+ unsigned uThreadID;
+ 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
+ &uThreadID )); // 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 000000000..75a97d867
--- /dev/null
+++ b/vcl/source/app/timer.cxx
@@ -0,0 +1,102 @@
+/* -*- 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()
+{
+ Task::Start();
+ 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 000000000..6d9e6f31a
--- /dev/null
+++ b/vcl/source/app/unohelp.cxx
@@ -0,0 +1,233 @@
+/* -*- 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() );
+}
+
+void vcl::unohelper::NotifyAccessibleStateEventGlobally( const css::accessibility::AccessibleEventObject& rEventObject )
+{
+ css::uno::Reference< css::awt::XExtendedToolkit > xExtToolkit( Application::GetVCLToolkit(), uno::UNO_QUERY );
+ if ( xExtToolkit.is() )
+ {
+ // Only for focus events
+ sal_Int16 nType = css::accessibility::AccessibleStateType::INVALID;
+ rEventObject.NewValue >>= nType;
+ if ( nType == css::accessibility::AccessibleStateType::FOCUSED )
+ xExtToolkit->fireFocusGained( rEventObject.Source );
+ else
+ {
+ rEventObject.OldValue >>= nType;
+ if ( nType == css::accessibility::AccessibleStateType::FOCUSED )
+ xExtToolkit->fireFocusLost( rEventObject.Source );
+ }
+
+ }
+}
+
+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 000000000..9005467d9
--- /dev/null
+++ b/vcl/source/app/unohelp2.cxx
@@ -0,0 +1,98 @@
+/* -*- 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/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>
+
+using namespace ::com::sun::star;
+
+namespace vcl::unohelper {
+
+ TextDataObject::TextDataObject( const OUString& rText ) : maText( rText )
+ {
+ }
+
+ TextDataObject::~TextDataObject()
+ {
+ }
+
+ void TextDataObject::CopyStringTo( const OUString& rContent,
+ const uno::Reference< datatransfer::clipboard::XClipboard >& rxClipboard )
+ {
+ SAL_WARN_IF( !rxClipboard.is(), "vcl", "TextDataObject::CopyStringTo: invalid clipboard!" );
+ if ( !rxClipboard.is() )
+ return;
+
+ 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();
+ }
+ 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 000000000..3dfad4a4c
--- /dev/null
+++ b/vcl/source/app/vclevent.cxx
@@ -0,0 +1,104 @@
+/* -*- 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>
+
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::accessibility::XAccessible;
+
+
+VclAccessibleEvent::VclAccessibleEvent( VclEventId n, const Reference<XAccessible>& rxAccessible ) :
+ VclSimpleEvent(n),
+ mxAccessible(rxAccessible)
+{
+}
+
+VclAccessibleEvent::~VclAccessibleEvent()
+{
+}
+
+
+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() );
+ if (VclWindowEvent* pWindowEvent = dynamic_cast<VclWindowEvent*>(&rEvent))
+ {
+ VclPtr<vcl::Window> xWin(pWindowEvent->GetWindow());
+ while ( aIter != aEnd && (!xWin || !xWin->IsDisposed()) )
+ {
+ Link<VclSimpleEvent&,void> &rLink = *aIter;
+ // check this hasn't been removed in some re-enterancy scenario fdo#47368
+ if( 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( 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 );
+}
+
+void VclEventListeners::removeListener( const Link<VclSimpleEvent&,void>& rListener )
+{
+ m_aListeners.erase( std::remove(m_aListeners.begin(), m_aListeners.end(), rListener ), m_aListeners.end() );
+}
+
+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 000000000..c45e51c04
--- /dev/null
+++ b/vcl/source/app/watchdog.cxx
@@ -0,0 +1,165 @@
+/* -*- 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
+
+namespace
+{
+static volatile bool gbWatchdogFiring = false;
+static osl::Condition* gpWatchdogExit = nullptr;
+static 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",
+ OStringLiteral("Watchdog triggered: hard disable ") + Zone::name());
+ Zone::hardDisable();
+ gbWatchdogFiring = false;
+ }
+ bFired = true;
+
+ // we can hang using VCL in the abort handling -> be impatient
+ if (bAbortFired)
+ {
+ SAL_WARN("vcl.watchdog",
+ OStringLiteral("Watchdog gave up: hard exiting ") + Zone::name());
+ _Exit(1);
+ }
+ }
+
+ // Not making even more progress
+ if (nUnchanged >= aTimingValues.mnAbortAfter)
+ {
+ if (!bAbortFired)
+ {
+ SAL_WARN("vcl.watchdog",
+ OStringLiteral("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 000000000..69562cf0d
--- /dev/null
+++ b/vcl/source/app/weldutils.cxx
@@ -0,0 +1,129 @@
+/* -*- 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/builderpage.hxx>
+#include <vcl/commandinfoprovider.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 OString& rID)
+ : m_pDialogController(pController)
+ , m_xBuilder(Application::CreateBuilder(pParent, rUIXMLDescription))
+ , 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 OString& 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 OString& rDialogId,
+ const OString& 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 OString& 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::ToggleButton& 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, 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);
+}
+}
+
+/* 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 000000000..0398faaa4
--- /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: */