summaryrefslogtreecommitdiffstats
path: root/svx/source/dialog
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--svx/source/dialog/ClassificationCommon.cxx125
-rw-r--r--svx/source/dialog/ClassificationDialog.cxx694
-rw-r--r--svx/source/dialog/ClassificationEditView.cxx82
-rw-r--r--svx/source/dialog/ClassificationEditView.hxx54
-rw-r--r--svx/source/dialog/FileExportedDialog.cxx42
-rw-r--r--svx/source/dialog/GenericCheckDialog.cxx70
-rw-r--r--svx/source/dialog/SafeModeDialog.cxx308
-rw-r--r--svx/source/dialog/SafeModeDialog.hxx66
-rw-r--r--svx/source/dialog/SafeModeUI.cxx79
-rw-r--r--svx/source/dialog/SpellDialogChildWindow.cxx90
-rw-r--r--svx/source/dialog/SvxNumOptionsTabPageHelper.cxx88
-rw-r--r--svx/source/dialog/ThemeColorEditDialog.cxx89
-rw-r--r--svx/source/dialog/ThemeColorValueSet.cxx98
-rw-r--r--svx/source/dialog/ThemeDialog.cxx132
-rw-r--r--svx/source/dialog/_bmpmask.cxx1055
-rw-r--r--svx/source/dialog/_contdlg.cxx675
-rw-r--r--svx/source/dialog/charmap.cxx1967
-rw-r--r--svx/source/dialog/compressgraphicdialog.cxx456
-rw-r--r--svx/source/dialog/connctrl.cxx304
-rw-r--r--svx/source/dialog/contimp.hxx132
-rw-r--r--svx/source/dialog/contwnd.cxx271
-rw-r--r--svx/source/dialog/contwnd.hxx70
-rw-r--r--svx/source/dialog/crashreportdlg.cxx124
-rw-r--r--svx/source/dialog/crashreportdlg.hxx42
-rw-r--r--svx/source/dialog/crashreportui.cxx81
-rw-r--r--svx/source/dialog/ctredlin.cxx1002
-rw-r--r--svx/source/dialog/databaseregistrationui.cxx45
-rw-r--r--svx/source/dialog/dialcontrol.cxx479
-rw-r--r--svx/source/dialog/dialmgr.cxx26
-rw-r--r--svx/source/dialog/dlgctl3d.cxx1165
-rw-r--r--svx/source/dialog/dlgctrl.cxx1464
-rw-r--r--svx/source/dialog/dlgunit.hxx55
-rw-r--r--svx/source/dialog/dlgutil.cxx74
-rw-r--r--svx/source/dialog/docrecovery.cxx1239
-rw-r--r--svx/source/dialog/fntctrl.cxx1085
-rw-r--r--svx/source/dialog/fontwork.cxx795
-rw-r--r--svx/source/dialog/framelink.cxx341
-rw-r--r--svx/source/dialog/framelinkarray.cxx1698
-rw-r--r--svx/source/dialog/frmdirlbox.cxx32
-rw-r--r--svx/source/dialog/frmsel.cxx1308
-rw-r--r--svx/source/dialog/graphctl.cxx850
-rw-r--r--svx/source/dialog/grfflt.cxx294
-rw-r--r--svx/source/dialog/hdft.cxx1046
-rw-r--r--svx/source/dialog/hexcolorcontrol.cxx111
-rw-r--r--svx/source/dialog/hyperdlg.cxx81
-rw-r--r--svx/source/dialog/imapdlg.cxx728
-rw-r--r--svx/source/dialog/imapimp.hxx51
-rw-r--r--svx/source/dialog/imapwnd.cxx738
-rw-r--r--svx/source/dialog/imapwnd.hxx142
-rw-r--r--svx/source/dialog/langbox.cxx553
-rw-r--r--svx/source/dialog/linkwarn.cxx61
-rw-r--r--svx/source/dialog/measctrl.cxx159
-rw-r--r--svx/source/dialog/optgrid.cxx472
-rw-r--r--svx/source/dialog/page.hrc104
-rw-r--r--svx/source/dialog/pagectrl.cxx397
-rw-r--r--svx/source/dialog/pagenumberlistbox.cxx52
-rw-r--r--svx/source/dialog/papersizelistbox.cxx74
-rw-r--r--svx/source/dialog/paraprev.cxx214
-rw-r--r--svx/source/dialog/passwd.cxx91
-rw-r--r--svx/source/dialog/relfld.cxx103
-rw-r--r--svx/source/dialog/rlrcitem.cxx148
-rw-r--r--svx/source/dialog/rlrcitem.hxx42
-rw-r--r--svx/source/dialog/rubydialog.cxx873
-rw-r--r--svx/source/dialog/rulritem.cxx735
-rw-r--r--svx/source/dialog/samecontentlistbox.cxx39
-rw-r--r--svx/source/dialog/searchcharmap.cxx323
-rw-r--r--svx/source/dialog/signaturelinehelper.cxx165
-rw-r--r--svx/source/dialog/spacinglistbox.cxx76
-rw-r--r--svx/source/dialog/srchctrl.cxx71
-rw-r--r--svx/source/dialog/srchctrl.hxx39
-rw-r--r--svx/source/dialog/srchdlg.cxx2475
-rw-r--r--svx/source/dialog/strarray.cxx88
-rw-r--r--svx/source/dialog/svxbmpnumvalueset.cxx533
-rw-r--r--svx/source/dialog/svxdlg.cxx29
-rw-r--r--svx/source/dialog/svxgraphicitem.cxx40
-rw-r--r--svx/source/dialog/svxruler.cxx3582
-rw-r--r--svx/source/dialog/swframeexample.cxx714
-rw-r--r--svx/source/dialog/swframeposstrings.cxx38
-rw-r--r--svx/source/dialog/txencbox.cxx266
-rw-r--r--svx/source/dialog/txenctab.cxx49
-rw-r--r--svx/source/dialog/weldeditview.cxx1719
81 files changed, 36367 insertions, 0 deletions
diff --git a/svx/source/dialog/ClassificationCommon.cxx b/svx/source/dialog/ClassificationCommon.cxx
new file mode 100644
index 0000000000..885dff644e
--- /dev/null
+++ b/svx/source/dialog/ClassificationCommon.cxx
@@ -0,0 +1,125 @@
+/* -*- 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 <svx/ClassificationCommon.hxx>
+#include <svx/ClassificationField.hxx>
+#include <rtl/ustrbuf.hxx>
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XPropertyContainer.hpp>
+
+using namespace css;
+
+namespace svx::classification
+{
+OUString convertClassificationResultToString(std::vector<svx::ClassificationResult> const& rResults)
+{
+ OUStringBuffer sRepresentation;
+
+ for (svx::ClassificationResult const& rResult : rResults)
+ {
+ switch (rResult.meType)
+ {
+ case svx::ClassificationType::CATEGORY:
+ case svx::ClassificationType::INTELLECTUAL_PROPERTY_PART:
+ case svx::ClassificationType::MARKING:
+ case svx::ClassificationType::TEXT:
+ sRepresentation.append(rResult.msName);
+ break;
+
+ case svx::ClassificationType::PARAGRAPH:
+ sRepresentation.append(" ");
+ break;
+ }
+ }
+ return sRepresentation.makeStringAndClear();
+}
+
+OUString getProperty(uno::Reference<beans::XPropertyContainer> const& rxPropertyContainer,
+ OUString const& rName)
+{
+ try
+ {
+ uno::Reference<beans::XPropertySet> xPropertySet(rxPropertyContainer, uno::UNO_QUERY);
+ return xPropertySet->getPropertyValue(rName).get<OUString>();
+ }
+ catch (const css::uno::Exception&)
+ {
+ }
+
+ return OUString();
+}
+
+bool containsProperty(uno::Sequence<beans::Property> const& rProperties, std::u16string_view rName)
+{
+ return std::any_of(rProperties.begin(), rProperties.end(),
+ [&](const beans::Property& rProperty) { return rProperty.Name == rName; });
+}
+
+void removeAllProperties(uno::Reference<beans::XPropertyContainer> const& rxPropertyContainer)
+{
+ uno::Reference<beans::XPropertySet> xPropertySet(rxPropertyContainer, uno::UNO_QUERY);
+ const uno::Sequence<beans::Property> aProperties
+ = xPropertySet->getPropertySetInfo()->getProperties();
+
+ for (const beans::Property& rProperty : aProperties)
+ {
+ rxPropertyContainer->removeProperty(rProperty.Name);
+ }
+}
+
+bool addOrInsertDocumentProperty(
+ uno::Reference<beans::XPropertyContainer> const& rxPropertyContainer, OUString const& rsKey,
+ OUString const& rsValue)
+{
+ uno::Reference<beans::XPropertySet> xPropertySet(rxPropertyContainer, uno::UNO_QUERY);
+
+ try
+ {
+ if (containsProperty(xPropertySet->getPropertySetInfo()->getProperties(), rsKey))
+ xPropertySet->setPropertyValue(rsKey, uno::Any(rsValue));
+ else
+ rxPropertyContainer->addProperty(rsKey, beans::PropertyAttribute::REMOVABLE,
+ uno::Any(rsValue));
+ }
+ catch (const uno::Exception& /*rException*/)
+ {
+ return false;
+ }
+ return true;
+}
+
+void insertFullTextualRepresentationAsDocumentProperty(
+ uno::Reference<beans::XPropertyContainer> const& rxPropertyContainer,
+ sfx::ClassificationKeyCreator const& rKeyCreator,
+ std::vector<svx::ClassificationResult> const& rResults)
+{
+ OUString sString = convertClassificationResultToString(rResults);
+ addOrInsertDocumentProperty(rxPropertyContainer, rKeyCreator.makeFullTextualRepresentationKey(),
+ sString);
+}
+
+void insertCreationOrigin(uno::Reference<beans::XPropertyContainer> const& rxPropertyContainer,
+ sfx::ClassificationKeyCreator const& rKeyCreator,
+ sfx::ClassificationCreationOrigin eOrigin)
+{
+ // Nothing to do if origin is "NONE"
+ if (eOrigin == sfx::ClassificationCreationOrigin::NONE)
+ return;
+
+ OUString sValue = (eOrigin == sfx::ClassificationCreationOrigin::BAF_POLICY)
+ ? OUString("BAF_POLICY")
+ : OUString("MANUAL");
+ addOrInsertDocumentProperty(rxPropertyContainer, rKeyCreator.makeCreationOriginKey(), sValue);
+}
+} // end svx::classification namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/ClassificationDialog.cxx b/svx/source/dialog/ClassificationDialog.cxx
new file mode 100644
index 0000000000..03f38bb2f3
--- /dev/null
+++ b/svx/source/dialog/ClassificationDialog.cxx
@@ -0,0 +1,694 @@
+/* -*- 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 <svx/ClassificationDialog.hxx>
+#include <svx/ClassificationCommon.hxx>
+
+#include <editeng/flditem.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/section.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/wghtitem.hxx>
+#include <svl/itemset.hxx>
+#include <osl/file.hxx>
+#include <rtl/bootstrap.hxx>
+#include <config_folders.h>
+#include <tools/stream.hxx>
+#include <tools/XmlWriter.hxx>
+#include <tools/XmlWalker.hxx>
+#include <utility>
+#include <vcl/customweld.hxx>
+#include <vcl/event.hxx>
+#include <vcl/svapp.hxx>
+#include <sfx2/objsh.hxx>
+
+#include <officecfg/Office/Common.hxx>
+
+#include "ClassificationEditView.hxx"
+
+namespace svx {
+
+IMPL_STATIC_LINK(ClassificationDialog, KeyInput, const KeyEvent&, rKeyEvent, bool)
+{
+ bool bTextIsFreeForm = officecfg::Office::Common::Classification::IntellectualPropertyTextInputIsFreeForm::get();
+
+ if (!bTextIsFreeForm)
+ {
+ // Ignore key combination with modifier keys
+ if (rKeyEvent.GetKeyCode().IsMod3()
+ || rKeyEvent.GetKeyCode().IsMod2()
+ || rKeyEvent.GetKeyCode().IsMod1())
+ {
+ return true;
+ }
+
+ switch (rKeyEvent.GetKeyCode().GetCode())
+ {
+ // Allowed characters
+ case KEY_BACKSPACE:
+ case KEY_DELETE:
+ case KEY_DIVIDE:
+ case KEY_SEMICOLON:
+ case KEY_SPACE:
+ return false;
+ // Anything else is ignored
+ default:
+ return true;
+ }
+ }
+
+ return false;
+}
+
+namespace {
+
+constexpr size_t RECENTLY_USED_LIMIT = 5;
+
+constexpr OUString constRecentlyUsedFileName(u"recentlyUsed.xml"_ustr);
+
+OUString lcl_getClassificationUserPath()
+{
+ OUString sPath("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}/user/classification/");
+ rtl::Bootstrap::expandMacros(sPath);
+ return sPath;
+}
+
+const SvxFieldItem* findField(editeng::Section const & rSection)
+{
+ for (SfxPoolItem const * pPool : rSection.maAttributes)
+ {
+ if (pPool->Which() == EE_FEATURE_FIELD)
+ return static_cast<const SvxFieldItem*>(pPool);
+ }
+ return nullptr;
+}
+
+bool fileExists(OUString const & sFilename)
+{
+ osl::File aFile(sFilename);
+ osl::FileBase::RC eRC = aFile.open(osl_File_OpenFlag_Read);
+ return osl::FileBase::E_None == eRC;
+}
+
+bool stringToClassificationType(std::string_view rsType, svx::ClassificationType & reType)
+{
+ if (rsType == "CATEGORY")
+ reType = svx::ClassificationType::CATEGORY;
+ else if (rsType == "INTELLECTUAL_PROPERTY_PART")
+ reType = svx::ClassificationType::INTELLECTUAL_PROPERTY_PART;
+ else if (rsType == "MARKING")
+ reType = svx::ClassificationType::MARKING;
+ else if (rsType == "PARAGRAPH")
+ reType = svx::ClassificationType::PARAGRAPH;
+ else if (rsType == "TEXT")
+ reType = svx::ClassificationType::TEXT;
+ else
+ return false;
+ return true;
+}
+
+OUString classificationTypeToString(svx::ClassificationType const & reType)
+{
+ switch(reType)
+ {
+ case svx::ClassificationType::CATEGORY:
+ return "CATEGORY"; break;
+ case svx::ClassificationType::MARKING:
+ return "MARKING"; break;
+ case svx::ClassificationType::TEXT:
+ return "TEXT"; break;
+ case svx::ClassificationType::INTELLECTUAL_PROPERTY_PART:
+ return "INTELLECTUAL_PROPERTY_PART"; break;
+ case svx::ClassificationType::PARAGRAPH:
+ return "PARAGRAPH"; break;
+ }
+ return OUString();
+}
+
+void writeResultToXml(tools::XmlWriter & rXmlWriter,
+ std::vector<ClassificationResult> const & rResultCollection)
+{
+ for (ClassificationResult const & rResult : rResultCollection)
+ {
+ rXmlWriter.startElement("element");
+ OUString sType = classificationTypeToString(rResult.meType);
+ rXmlWriter.attribute("type", sType);
+ rXmlWriter.startElement("string");
+ rXmlWriter.content(rResult.msName);
+ rXmlWriter.endElement();
+ rXmlWriter.startElement("abbreviatedString");
+ rXmlWriter.content(rResult.msAbbreviatedName);
+ rXmlWriter.endElement();
+ rXmlWriter.startElement("identifier");
+ rXmlWriter.content(rResult.msIdentifier);
+ rXmlWriter.endElement();
+ rXmlWriter.endElement();
+ }
+}
+
+} // end anonymous namespace
+
+ClassificationDialog::ClassificationDialog(weld::Window* pParent, const css::uno::Reference<css::document::XDocumentProperties>& rDocProps,
+ const bool bPerParagraph, std::function<void()> aParagraphSignHandler)
+ : GenericDialogController(pParent, "svx/ui/classificationdialog.ui", "AdvancedDocumentClassificationDialog")
+ , maHelper(rDocProps)
+ , maInternationalHelper(rDocProps, /*bUseLocalizedPolicy*/ false)
+ , m_bPerParagraph(bPerParagraph)
+ , m_aParagraphSignHandler(std::move(aParagraphSignHandler))
+ , m_nCurrentSelectedCategory(-1)
+ , m_xOkButton(m_xBuilder->weld_button("ok"))
+ , m_xSignButton(m_xBuilder->weld_button("signButton"))
+ , m_xToolBox(m_xBuilder->weld_toggle_button("toolbox"))
+ , m_xRecentlyUsedListBox(m_xBuilder->weld_combo_box("recentlyUsedCB"))
+ , m_xClassificationListBox(m_xBuilder->weld_combo_box("classificationCB"))
+ , m_xInternationalClassificationListBox(m_xBuilder->weld_combo_box("internationalClassificationCB"))
+ , m_xMarkingLabel(m_xBuilder->weld_label("markingLabel"))
+ , m_xMarkingListBox(m_xBuilder->weld_tree_view("markingLB"))
+ , m_xIntellectualPropertyPartListBox(m_xBuilder->weld_tree_view("intellectualPropertyPartLB"))
+ , m_xIntellectualPropertyPartNumberListBox(m_xBuilder->weld_tree_view("intellectualPropertyPartNumberLB"))
+ , m_xIntellectualPropertyPartAddButton(m_xBuilder->weld_button("intellectualPropertyPartAddButton"))
+ , m_xIntellectualPropertyPartEdit(m_xBuilder->weld_entry("intellectualPropertyPartEntry"))
+ , m_xIntellectualPropertyExpander(m_xBuilder->weld_expander("intellectualPropertyExpander"))
+ , m_xEditWindow(new ClassificationEditView)
+ , m_xEditWindowWeld(new weld::CustomWeld(*m_xBuilder, "classificationEditWindow", *m_xEditWindow))
+{
+ m_xOkButton->connect_clicked(LINK(this, ClassificationDialog, OkHdl));
+ m_xSignButton->connect_clicked(LINK(this, ClassificationDialog, ButtonClicked));
+ m_xSignButton->set_visible(m_bPerParagraph);
+
+ m_xIntellectualPropertyPartEdit->connect_key_press(LINK(this, ClassificationDialog, KeyInput));
+
+ // no need for BOLD if we do paragraph classification
+ if (m_bPerParagraph)
+ {
+ m_xToolBox->hide();
+ }
+ else
+ {
+ m_xToolBox->connect_toggled(LINK(this, ClassificationDialog, SelectToolboxHdl));
+ }
+
+ m_xIntellectualPropertyPartAddButton->connect_clicked(LINK(this, ClassificationDialog, ButtonClicked));
+
+ m_xClassificationListBox->set_size_request(m_xClassificationListBox->get_approximate_digit_width() * 20, -1);
+ m_xClassificationListBox->connect_changed(LINK(this, ClassificationDialog, SelectClassificationHdl));
+ for (const OUString& rName : maHelper.GetBACNames())
+ m_xClassificationListBox->append_text(rName);
+
+ m_xInternationalClassificationListBox->set_size_request(m_xInternationalClassificationListBox->get_approximate_digit_width() * 20, -1);
+ m_xInternationalClassificationListBox->connect_changed(LINK(this, ClassificationDialog, SelectClassificationHdl));
+ for (const OUString& rName : maInternationalHelper.GetBACNames())
+ m_xInternationalClassificationListBox->append_text(rName);
+
+ if (!maHelper.GetMarkings().empty())
+ {
+ m_xMarkingListBox->set_size_request(m_xMarkingListBox->get_approximate_digit_width() * 10,
+ m_xMarkingListBox->get_height_rows(4));
+ m_xMarkingListBox->connect_row_activated(LINK(this, ClassificationDialog, SelectMarkingHdl));
+
+ for (const OUString& rName : maHelper.GetMarkings())
+ m_xMarkingListBox->append_text(rName);
+ }
+ else
+ {
+ m_xMarkingListBox->hide();
+ m_xMarkingLabel->hide();
+ }
+
+ m_xIntellectualPropertyPartNumberListBox->set_size_request(m_xIntellectualPropertyPartNumberListBox->get_approximate_digit_width() * 10,
+ m_xIntellectualPropertyPartNumberListBox->get_height_rows(5));
+ m_xIntellectualPropertyPartNumberListBox->connect_row_activated(LINK(this, ClassificationDialog, SelectIPPartNumbersHdl));
+ for (const OUString& rName : maHelper.GetIntellectualPropertyPartNumbers())
+ m_xIntellectualPropertyPartNumberListBox->append_text(rName);
+
+ m_xIntellectualPropertyPartNumberListBox->set_size_request(m_xIntellectualPropertyPartNumberListBox->get_approximate_digit_width() * 20,
+ m_xIntellectualPropertyPartListBox->get_height_rows(5));
+ m_xIntellectualPropertyPartListBox->connect_row_activated(LINK(this, ClassificationDialog, SelectIPPartHdl));
+ for (const OUString& rName : maHelper.GetIntellectualPropertyParts())
+ m_xIntellectualPropertyPartListBox->append_text(rName);
+
+ m_xRecentlyUsedListBox->set_size_request(m_xRecentlyUsedListBox->get_approximate_digit_width() * 5, -1);
+ m_xRecentlyUsedListBox->connect_changed(LINK(this, ClassificationDialog, SelectRecentlyUsedHdl));
+
+ m_xIntellectualPropertyExpander->connect_expanded(LINK(this, ClassificationDialog, ExpandedHdl));
+ if (officecfg::Office::Common::Classification::IntellectualPropertySectionExpanded::get())
+ m_nAsyncExpandEvent = Application::PostUserEvent(LINK(this, ClassificationDialog, OnAsyncExpandHdl));
+ else
+ m_nAsyncExpandEvent = nullptr;
+
+ m_xEditWindow->SetModifyHdl(LINK(this, ClassificationDialog, EditWindowModifiedHdl));
+
+ readRecentlyUsed();
+ toggleWidgetsDependingOnCategory();
+
+ int nNumber = 1;
+ if (m_aRecentlyUsedValuesCollection.empty())
+ {
+ m_xRecentlyUsedListBox->set_sensitive(false);
+ }
+ else
+ {
+ for (std::vector<ClassificationResult> const & rResults : m_aRecentlyUsedValuesCollection)
+ {
+ OUString rContentRepresentation = svx::classification::convertClassificationResultToString(rResults);
+ OUString rDescription = OUString::number(nNumber) + ": " + rContentRepresentation;
+ nNumber++;
+
+ m_xRecentlyUsedListBox->append_text(rDescription);
+ }
+ }
+}
+
+//do it async so gtk has a chance to shrink it to best size, otherwise its larger than min
+IMPL_LINK_NOARG(ClassificationDialog, OnAsyncExpandHdl, void*, void)
+{
+ m_nAsyncExpandEvent = nullptr;
+ m_xIntellectualPropertyExpander->set_expanded(true);
+}
+
+ClassificationDialog::~ClassificationDialog()
+{
+ if (m_nAsyncExpandEvent)
+ Application::RemoveUserEvent(m_nAsyncExpandEvent);
+}
+
+void ClassificationDialog::insertCategoryField(sal_Int32 nID)
+{
+ const OUString aFullString = maHelper.GetBACNames()[nID];
+ const OUString aAbbreviatedString = maHelper.GetAbbreviatedBACNames()[nID];
+ const OUString aIdentifierString = maHelper.GetBACIdentifiers()[nID];
+ insertField(ClassificationType::CATEGORY, aAbbreviatedString, aFullString, aIdentifierString);
+}
+
+void ClassificationDialog::insertField(ClassificationType eType, OUString const & rString, OUString const & rFullString, OUString const & rIdentifier)
+{
+ ClassificationField aField(eType, rString, rFullString, rIdentifier);
+ m_xEditWindow->InsertField(SvxFieldItem(aField, EE_FEATURE_FIELD));
+}
+
+void ClassificationDialog::setupValues(std::vector<ClassificationResult> && rInput)
+{
+ m_aInitialValues = std::move(rInput);
+ readIn(m_aInitialValues);
+}
+
+void ClassificationDialog::readRecentlyUsed()
+{
+ OUString sPath = lcl_getClassificationUserPath();
+ OUString sFilePath(sPath + constRecentlyUsedFileName);
+
+ if (!fileExists(sFilePath))
+ return;
+
+ SvFileStream aFileStream(sFilePath, StreamMode::READ);
+ tools::XmlWalker aWalker;
+ if (!aWalker.open(&aFileStream))
+ return;
+
+ if (aWalker.name() != "recentlyUsedClassifications")
+ return;
+
+ aWalker.children();
+ while (aWalker.isValid())
+ {
+ if (aWalker.name() == "elementGroup")
+ {
+ std::vector<ClassificationResult> aResults;
+
+ aWalker.children();
+
+ while (aWalker.isValid())
+ {
+ if (aWalker.name() == "element")
+ {
+ svx::ClassificationType eType = svx::ClassificationType::TEXT;
+ OUString sString;
+ OUString sAbbreviatedString;
+ OUString sIdentifier;
+
+ // Convert string to classification type, but continue only if
+ // conversion was successful.
+ if (stringToClassificationType(aWalker.attribute("type"_ostr), eType))
+ {
+ aWalker.children();
+
+ while (aWalker.isValid())
+ {
+ if (aWalker.name() == "string")
+ {
+ sString = OStringToOUString(aWalker.content(), RTL_TEXTENCODING_UTF8);
+ }
+ else if (aWalker.name() == "abbreviatedString")
+ {
+ sAbbreviatedString = OStringToOUString(aWalker.content(), RTL_TEXTENCODING_UTF8);
+ }
+ else if (aWalker.name() == "identifier")
+ {
+ sIdentifier = OStringToOUString(aWalker.content(), RTL_TEXTENCODING_UTF8);
+ }
+ aWalker.next();
+ }
+ aWalker.parent();
+
+ aResults.push_back({ eType, sString, sAbbreviatedString, sIdentifier });
+ }
+ }
+ aWalker.next();
+ }
+ aWalker.parent();
+ m_aRecentlyUsedValuesCollection.push_back(aResults);
+ }
+ aWalker.next();
+ }
+ aWalker.parent();
+}
+
+void ClassificationDialog::writeRecentlyUsed()
+{
+ OUString sPath = lcl_getClassificationUserPath();
+ osl::Directory::createPath(sPath);
+ OUString sFilePath(sPath + constRecentlyUsedFileName);
+
+ std::unique_ptr<SvStream> pStream;
+ pStream.reset(new SvFileStream(sFilePath, StreamMode::STD_READWRITE | StreamMode::TRUNC));
+
+ tools::XmlWriter aXmlWriter(pStream.get());
+
+ if (!aXmlWriter.startDocument())
+ return;
+
+ aXmlWriter.startElement("recentlyUsedClassifications");
+
+ aXmlWriter.startElement("elementGroup");
+
+ writeResultToXml(aXmlWriter, getResult());
+
+ aXmlWriter.endElement();
+
+ if (m_aRecentlyUsedValuesCollection.size() >= RECENTLY_USED_LIMIT)
+ m_aRecentlyUsedValuesCollection.pop_back();
+
+ for (std::vector<ClassificationResult> const & rResultCollection : m_aRecentlyUsedValuesCollection)
+ {
+ aXmlWriter.startElement("elementGroup");
+
+ writeResultToXml(aXmlWriter, rResultCollection);
+
+ aXmlWriter.endElement();
+ }
+
+ aXmlWriter.endElement();
+
+ aXmlWriter.endDocument();
+}
+
+void ClassificationDialog::readIn(std::vector<ClassificationResult> const & rInput)
+{
+ sal_Int32 nParagraph = -1;
+
+ for (ClassificationResult const & rClassificationResult : rInput)
+ {
+
+ switch (rClassificationResult.meType)
+ {
+ case svx::ClassificationType::TEXT:
+ {
+ m_xEditWindow->getEditView().InsertText(rClassificationResult.msName);
+ }
+ break;
+
+ case svx::ClassificationType::CATEGORY:
+ {
+ OUString sName;
+ if (rClassificationResult.msName.isEmpty())
+ sName = maHelper.GetBACNameForIdentifier(rClassificationResult.msIdentifier);
+ else
+ sName = rClassificationResult.msName;
+
+ OUString sAbbreviatedName = rClassificationResult.msAbbreviatedName;
+ if (sAbbreviatedName.isEmpty())
+ sAbbreviatedName = maHelper.GetAbbreviatedBACName(sName);
+
+ m_xClassificationListBox->set_active_text(sName);
+ m_nCurrentSelectedCategory = m_xClassificationListBox->get_active();
+ m_xInternationalClassificationListBox->set_active(m_xClassificationListBox->get_active());
+
+ insertField(rClassificationResult.meType, sAbbreviatedName, sName, rClassificationResult.msIdentifier);
+ }
+ break;
+
+ case svx::ClassificationType::MARKING:
+ {
+ m_xMarkingListBox->select_text(rClassificationResult.msName);
+ insertField(rClassificationResult.meType, rClassificationResult.msName, rClassificationResult.msName, rClassificationResult.msIdentifier);
+ }
+ break;
+
+ case svx::ClassificationType::INTELLECTUAL_PROPERTY_PART:
+ {
+ insertField(rClassificationResult.meType, rClassificationResult.msName, rClassificationResult.msName, rClassificationResult.msIdentifier);
+ }
+ break;
+
+ case svx::ClassificationType::PARAGRAPH:
+ {
+ nParagraph++;
+
+ if (nParagraph != 0)
+ m_xEditWindow->getEditView().InsertParaBreak();
+
+ // Set paragraph font weight
+ FontWeight eWeight = (rClassificationResult.msName == "BOLD") ? WEIGHT_BOLD : WEIGHT_NORMAL;
+
+ ClassificationEditEngine& rEdEngine = m_xEditWindow->getEditEngine();
+ SfxItemSet aSet(rEdEngine.GetParaAttribs(nParagraph));
+ aSet.Put(SvxWeightItem(eWeight, EE_CHAR_WEIGHT));
+ rEdEngine.SetParaAttribs(nParagraph, aSet);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ toggleWidgetsDependingOnCategory();
+}
+
+void ClassificationDialog::toggleWidgetsDependingOnCategory()
+{
+ const EditEngine& rEditEngine = m_xEditWindow->getEditEngine();
+
+ for (sal_Int32 nParagraph = 0; nParagraph < rEditEngine.GetParagraphCount(); ++nParagraph)
+ {
+ sal_uInt16 nFieldCount = rEditEngine.GetFieldCount(nParagraph);
+ for (sal_uInt16 nField = 0; nField < nFieldCount; ++nField)
+ {
+ EFieldInfo aFieldInfo = rEditEngine.GetFieldInfo(nParagraph, nField);
+ if (aFieldInfo.pFieldItem)
+ {
+ const ClassificationField* pClassificationField = dynamic_cast<const ClassificationField*>(aFieldInfo.pFieldItem->GetField());
+ if (pClassificationField && pClassificationField->meType == ClassificationType::CATEGORY)
+ {
+ m_xOkButton->set_sensitive(true);
+ return;
+ }
+ }
+ }
+ }
+
+ // Category field in the text edit has been deleted, so reset the list boxes
+ m_xOkButton->set_sensitive(false);
+ m_xClassificationListBox->set_active(-1);
+ m_xInternationalClassificationListBox->set_active(-1);
+}
+
+std::vector<ClassificationResult> ClassificationDialog::getResult()
+{
+ std::vector<ClassificationResult> aClassificationResults;
+
+ ClassificationEditEngine& rEdEngine = m_xEditWindow->getEditEngine();
+ std::unique_ptr<EditTextObject> pEditText(rEdEngine.CreateTextObject());
+
+ sal_Int32 nCurrentParagraph = -1;
+
+ std::vector<editeng::Section> aSections;
+ pEditText->GetAllSections(aSections);
+ for (editeng::Section const & rSection : aSections)
+ {
+ while (nCurrentParagraph < rSection.mnParagraph)
+ {
+ nCurrentParagraph++;
+
+ // Get Weight of current paragraph
+ FontWeight eFontWeight = WEIGHT_NORMAL;
+ SfxItemSet aItemSet(rEdEngine.GetParaAttribs(nCurrentParagraph));
+ if (const SfxPoolItem* pItem = aItemSet.GetItem(EE_CHAR_WEIGHT, false))
+ {
+ const SvxWeightItem* pWeightItem = dynamic_cast<const SvxWeightItem*>(pItem);
+ if (pWeightItem && pWeightItem->GetWeight() == WEIGHT_BOLD)
+ eFontWeight = WEIGHT_BOLD;
+ }
+ // Font weight to string
+ OUString sWeightProperty = "NORMAL";
+ if (eFontWeight == WEIGHT_BOLD)
+ sWeightProperty = "BOLD";
+ // Insert into collection
+ OUString sBlank;
+ aClassificationResults.push_back({ ClassificationType::PARAGRAPH, sWeightProperty, sBlank, sBlank });
+ }
+
+ const SvxFieldItem* pFieldItem = findField(rSection);
+
+ ESelection aSelection(rSection.mnParagraph, rSection.mnStart, rSection.mnParagraph, rSection.mnEnd);
+ const OUString sDisplayString = rEdEngine.GetText(aSelection);
+ if (!sDisplayString.isEmpty())
+ {
+ const ClassificationField* pClassificationField = pFieldItem ? dynamic_cast<const ClassificationField*>(pFieldItem->GetField()) : nullptr;
+
+ if (pClassificationField)
+ {
+ aClassificationResults.push_back({ pClassificationField->meType, pClassificationField->msFullClassName,
+ pClassificationField->msDescription, pClassificationField->msIdentifier });
+ }
+ else
+ {
+ aClassificationResults.push_back({ ClassificationType::TEXT, sDisplayString, sDisplayString, OUString() });
+ }
+ }
+ }
+
+ return aClassificationResults;
+}
+
+IMPL_LINK(ClassificationDialog, SelectClassificationHdl, weld::ComboBox&, rBox, void)
+{
+ const sal_Int32 nSelected = rBox.get_active();
+ if (nSelected < 0 || m_nCurrentSelectedCategory == nSelected)
+ return;
+
+ std::unique_ptr<EditTextObject> pEditText(m_xEditWindow->getEditEngine().CreateTextObject());
+ std::vector<editeng::Section> aSections;
+ pEditText->GetAllSections(aSections);
+
+ // if we are replacing an existing field
+ bool bReplaceExisting = false;
+ // selection of the existing field, which will be replaced
+ ESelection aExistingFieldSelection;
+
+ for (editeng::Section const & rSection : aSections)
+ {
+ const SvxFieldItem* pFieldItem = findField(rSection);
+ if (pFieldItem)
+ {
+ const ClassificationField* pClassificationField = dynamic_cast<const ClassificationField*>(pFieldItem->GetField());
+ if (pClassificationField && pClassificationField->meType == ClassificationType::CATEGORY)
+ {
+ aExistingFieldSelection = ESelection(rSection.mnParagraph, rSection.mnStart,
+ rSection.mnParagraph, rSection.mnEnd);
+ bReplaceExisting = true;
+ }
+ }
+ }
+
+ if (bReplaceExisting)
+ m_xEditWindow->getEditView().SetSelection(aExistingFieldSelection);
+
+ insertCategoryField(nSelected);
+
+ // Change category to the new selection
+ m_xInternationalClassificationListBox->set_active(nSelected);
+ m_xClassificationListBox->set_active(nSelected);
+ m_nCurrentSelectedCategory = nSelected;
+}
+
+IMPL_LINK(ClassificationDialog, SelectMarkingHdl, weld::TreeView&, rBox, bool)
+{
+ sal_Int32 nSelected = rBox.get_selected_index();
+ if (nSelected >= 0)
+ {
+ const OUString aString = maHelper.GetMarkings()[nSelected];
+ insertField(ClassificationType::MARKING, aString, aString);
+ }
+ return true;
+}
+
+IMPL_LINK(ClassificationDialog, SelectIPPartNumbersHdl, weld::TreeView&, rBox, bool)
+{
+ sal_Int32 nSelected = rBox.get_selected_index();
+ if (nSelected >= 0)
+ {
+ OUString sString = maHelper.GetIntellectualPropertyPartNumbers()[nSelected];
+ m_xIntellectualPropertyPartEdit->replace_selection(sString);
+ m_xIntellectualPropertyPartEdit->grab_focus();
+ }
+ return true;
+}
+
+IMPL_LINK(ClassificationDialog, SelectRecentlyUsedHdl, weld::ComboBox&, rBox, void)
+{
+ sal_Int32 nSelected = rBox.get_active();
+ if (nSelected >= 0)
+ {
+ m_xEditWindow->getEditEngine().Clear();
+ readIn(m_aRecentlyUsedValuesCollection[nSelected]);
+ }
+}
+
+IMPL_LINK(ClassificationDialog, SelectIPPartHdl, weld::TreeView&, rBox, bool)
+{
+ const sal_Int32 nSelected = rBox.get_selected_index();
+ if (nSelected >= 0)
+ {
+ const OUString sString = maHelper.GetIntellectualPropertyParts()[nSelected];
+ m_xIntellectualPropertyPartEdit->replace_selection(sString);
+ m_xIntellectualPropertyPartEdit->grab_focus();
+ }
+ return true;
+}
+
+IMPL_LINK(ClassificationDialog, ButtonClicked, weld::Button&, rButton, void)
+{
+ if (&rButton == m_xSignButton.get())
+ {
+ m_aParagraphSignHandler();
+ }
+ else if (&rButton == m_xIntellectualPropertyPartAddButton.get())
+ {
+ const OUString sString = m_xIntellectualPropertyPartEdit->get_text();
+ insertField(ClassificationType::INTELLECTUAL_PROPERTY_PART, sString, sString);
+ }
+}
+
+IMPL_LINK_NOARG(ClassificationDialog, OkHdl, weld::Button&, void)
+{
+ writeRecentlyUsed();
+ m_xDialog->response(RET_OK);
+}
+
+IMPL_LINK_NOARG(ClassificationDialog, SelectToolboxHdl, weld::Toggleable&, void)
+{
+ m_xEditWindow->InvertSelectionWeight();
+}
+
+IMPL_LINK_NOARG(ClassificationDialog, EditWindowModifiedHdl, LinkParamNone*, void)
+{
+ toggleWidgetsDependingOnCategory();
+}
+
+IMPL_STATIC_LINK(ClassificationDialog, ExpandedHdl, weld::Expander&, rExpander, void)
+{
+ std::shared_ptr<comphelper::ConfigurationChanges> aConfigurationChanges(comphelper::ConfigurationChanges::create());
+ officecfg::Office::Common::Classification::IntellectualPropertySectionExpanded::set(rExpander.get_expanded(), aConfigurationChanges);
+ aConfigurationChanges->commit();
+}
+
+} // end svx
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/ClassificationEditView.cxx b/svx/source/dialog/ClassificationEditView.cxx
new file mode 100644
index 0000000000..fa4388017f
--- /dev/null
+++ b/svx/source/dialog/ClassificationEditView.cxx
@@ -0,0 +1,82 @@
+/* -*- 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 <svx/ClassificationField.hxx>
+
+#include <svl/itempool.hxx>
+#include <svl/itemset.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/eeitem.hxx>
+
+#include "ClassificationEditView.hxx"
+
+namespace svx {
+
+ClassificationEditEngine::ClassificationEditEngine(SfxItemPool* pItemPool)
+ : EditEngine(pItemPool)
+{}
+
+OUString ClassificationEditEngine::CalcFieldValue(const SvxFieldItem& rField, sal_Int32 /*nPara*/,
+ sal_Int32 /*nPos*/, std::optional<Color>& /*rTxtColor*/, std::optional<Color>& /*rFldColor*/, std::optional<FontLineStyle>& /*rFldLineStyle*/)
+{
+ OUString aString;
+ const ClassificationField* pClassificationField = dynamic_cast<const ClassificationField*>(rField.GetField());
+ if (pClassificationField)
+ aString = pClassificationField->msDescription;
+ else
+ aString = "Unknown";
+ return aString;
+}
+
+ClassificationEditView::ClassificationEditView()
+{
+}
+
+void ClassificationEditView::makeEditEngine()
+{
+ m_xEditEngine.reset(new ClassificationEditEngine(EditEngine::CreatePool().get()));
+}
+
+ClassificationEditView::~ClassificationEditView()
+{
+}
+
+void ClassificationEditView::InsertField(const SvxFieldItem& rFieldItem)
+{
+ m_xEditView->InsertField(rFieldItem);
+ m_xEditView->Invalidate();
+}
+
+void ClassificationEditView::InvertSelectionWeight()
+{
+ ESelection aSelection = m_xEditView->GetSelection();
+
+ for (sal_Int32 nParagraph = aSelection.nStartPara; nParagraph <= aSelection.nEndPara; ++nParagraph)
+ {
+ FontWeight eFontWeight = WEIGHT_BOLD;
+
+ SfxItemSet aSet(m_xEditEngine->GetParaAttribs(nParagraph));
+ if (const SfxPoolItem* pItem = aSet.GetItem(EE_CHAR_WEIGHT, false))
+ {
+ const SvxWeightItem* pWeightItem = dynamic_cast<const SvxWeightItem*>(pItem);
+ if (pWeightItem && pWeightItem->GetWeight() == WEIGHT_BOLD)
+ eFontWeight = WEIGHT_NORMAL;
+ }
+ SvxWeightItem aWeight(eFontWeight, EE_CHAR_WEIGHT);
+ aSet.Put(aWeight);
+ m_xEditEngine->SetParaAttribs(nParagraph, aSet);
+ }
+
+ m_xEditView->Invalidate();
+}
+
+} // end sfx2
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/ClassificationEditView.hxx b/svx/source/dialog/ClassificationEditView.hxx
new file mode 100644
index 0000000000..225efe1243
--- /dev/null
+++ b/svx/source/dialog/ClassificationEditView.hxx
@@ -0,0 +1,54 @@
+/* -*- 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/.
+ *
+ */
+
+#ifndef INCLUDED_SVX_CLASSIFICATIONEDITVIEW_HXX
+#define INCLUDED_SVX_CLASSIFICATIONEDITVIEW_HXX
+
+#include <sal/config.h>
+#include <svx/weldeditview.hxx>
+
+namespace svx {
+
+class ClassificationEditEngine final : public EditEngine
+{
+public:
+ ClassificationEditEngine(SfxItemPool* pItemPool);
+
+ virtual OUString CalcFieldValue(const SvxFieldItem& rField, sal_Int32 nPara, sal_Int32 nPos, std::optional<Color>& rTxtColor, std::optional<Color>& rFldColor, std::optional<FontLineStyle>& rFldLineStyle) override;
+};
+
+class ClassificationEditView final : public WeldEditView
+{
+public:
+ ClassificationEditView();
+ virtual ~ClassificationEditView() override;
+
+ virtual void makeEditEngine() override;
+
+ void InsertField(const SvxFieldItem& rField);
+
+ void InvertSelectionWeight();
+
+ ClassificationEditEngine& getEditEngine()
+ {
+ return *static_cast<ClassificationEditEngine*>(m_xEditEngine.get());
+ }
+
+ EditView& getEditView()
+ {
+ return *m_xEditView;
+ }
+};
+
+} // end svx namespace
+
+#endif // INCLUDED_SVX_CLASSIFICATIONEDITVIEW_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/FileExportedDialog.cxx b/svx/source/dialog/FileExportedDialog.cxx
new file mode 100644
index 0000000000..787e0a20d3
--- /dev/null
+++ b/svx/source/dialog/FileExportedDialog.cxx
@@ -0,0 +1,42 @@
+/* -*- 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 <svx/FileExportedDialog.hxx>
+
+#include <comphelper/diagnose_ex.hxx>
+#include <comphelper/backupfilehelper.hxx>
+#include <comphelper/processfactory.hxx>
+#include <com/sun/star/system/XSystemShellExecute.hpp>
+#include <com/sun/star/system/SystemShellExecuteFlags.hpp>
+#include <com/sun/star/system/SystemShellExecute.hpp>
+
+FileExportedDialog::FileExportedDialog(weld::Window* pParent, OUString atitle)
+ : GenericDialogController(pParent, "svx/ui/fileexporteddialog.ui", "FileExportedDialog")
+ , m_xFileLabel(m_xBuilder->weld_label("Filelabel"))
+ , m_xButton(m_xBuilder->weld_button("ok"))
+{
+ m_xFileLabel->set_label(atitle);
+ m_xButton->connect_clicked(LINK(this, FileExportedDialog, OpenHdl));
+}
+
+IMPL_LINK_NOARG(FileExportedDialog, OpenHdl, weld::Button&, void)
+{
+ const OUString uri(comphelper::BackupFileHelper::getUserProfileURL());
+ css::uno::Reference<css::system::XSystemShellExecute> exec(
+ css::system::SystemShellExecute::create(comphelper::getProcessComponentContext()));
+ try
+ {
+ exec->execute(uri, OUString(), css::system::SystemShellExecuteFlags::URIS_ONLY);
+ }
+ catch (const css::uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("svx.dialog", "opening <" << uri << "> failed:");
+ }
+ m_xDialog->response(RET_OK);
+} \ No newline at end of file
diff --git a/svx/source/dialog/GenericCheckDialog.cxx b/svx/source/dialog/GenericCheckDialog.cxx
new file mode 100644
index 0000000000..09fc3d6787
--- /dev/null
+++ b/svx/source/dialog/GenericCheckDialog.cxx
@@ -0,0 +1,70 @@
+/* -*- 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 <svx/GenericCheckDialog.hxx>
+#include <vcl/svapp.hxx>
+
+namespace svx
+{
+GenericCheckEntry::GenericCheckEntry(weld::Container* pParent,
+ std::unique_ptr<CheckData>& pCheckData)
+ : m_xBuilder(Application::CreateBuilder(pParent, "svx/ui/genericcheckentry.ui"))
+ , m_xContainer(m_xBuilder->weld_container("checkEntryBox"))
+ , m_xLabel(m_xBuilder->weld_label("label"))
+ , m_xMarkButton(m_xBuilder->weld_button("markButton"))
+ , m_xPropertiesButton(m_xBuilder->weld_button("propertiesButton"))
+ , m_pCheckData(pCheckData)
+{
+ m_xLabel->set_label(m_pCheckData->getText());
+ m_xMarkButton->set_visible(m_pCheckData->canMarkObject());
+ m_xMarkButton->connect_clicked(LINK(this, GenericCheckEntry, MarkButtonClicked));
+ m_xPropertiesButton->set_visible(m_pCheckData->hasProperties());
+ m_xPropertiesButton->connect_clicked(LINK(this, GenericCheckEntry, PropertiesButtonClicked));
+
+ m_xContainer->show();
+}
+
+IMPL_LINK_NOARG(GenericCheckEntry, MarkButtonClicked, weld::Button&, void)
+{
+ m_pCheckData->markObject();
+}
+
+IMPL_LINK_NOARG(GenericCheckEntry, PropertiesButtonClicked, weld::Button&, void)
+{
+ m_pCheckData->runProperties();
+}
+
+GenericCheckDialog::GenericCheckDialog(weld::Window* pParent,
+ CheckDataCollection& rCheckDataCollection)
+ : GenericDialogController(pParent, "svx/ui/genericcheckdialog.ui", "GenericCheckDialog")
+ , m_rCheckDataCollection(rCheckDataCollection)
+ , m_xCheckBox(m_xBuilder->weld_box("checkBox"))
+{
+ set_title(m_rCheckDataCollection.getTitle());
+}
+
+GenericCheckDialog::~GenericCheckDialog() {}
+
+short GenericCheckDialog::run()
+{
+ sal_Int32 i = 0;
+
+ for (std::unique_ptr<CheckData>& pCheckData : m_rCheckDataCollection.getCollection())
+ {
+ auto xEntry = std::make_unique<GenericCheckEntry>(m_xCheckBox.get(), pCheckData);
+ m_xCheckBox->reorder_child(xEntry->get_widget(), i++);
+ m_aCheckEntries.push_back(std::move(xEntry));
+ }
+ return GenericDialogController::run();
+}
+
+} // end svx namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/SafeModeDialog.cxx b/svx/source/dialog/SafeModeDialog.cxx
new file mode 100644
index 0000000000..5aaa30e437
--- /dev/null
+++ b/svx/source/dialog/SafeModeDialog.cxx
@@ -0,0 +1,308 @@
+/* -*- 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 "SafeModeDialog.hxx"
+
+#include <osl/file.hxx>
+#include <sfx2/safemode.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <comphelper/processfactory.hxx>
+#include <unotools/ZipPackageHelper.hxx>
+#include <unotools/configmgr.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+#include <svx/FileExportedDialog.hxx>
+#include <officecfg/Office/Common.hxx>
+
+#include <com/sun/star/task/OfficeRestartManager.hpp>
+#include <com/sun/star/task/XInteractionHandler.hpp>
+
+using namespace css;
+
+SafeModeDialog::SafeModeDialog(weld::Window* pParent)
+ : GenericDialogController(pParent, "svx/ui/safemodedialog.ui", "SafeModeDialog")
+ , mxBtnContinue(m_xBuilder->weld_button("btn_continue"))
+ , mxBtnRestart(m_xBuilder->weld_button("btn_restart"))
+ , mxBtnApply(m_xBuilder->weld_button("btn_apply"))
+ , mxBoxRestore(m_xBuilder->weld_container("group_restore"))
+ , mxBoxConfigure(m_xBuilder->weld_container("group_configure"))
+ , mxBoxDeinstall(m_xBuilder->weld_container("group_deinstall"))
+ , mxBoxReset(m_xBuilder->weld_container("group_reset"))
+ , mxRadioRestore(m_xBuilder->weld_radio_button("radio_restore"))
+ , mxRadioConfigure(m_xBuilder->weld_radio_button("radio_configure"))
+ , mxRadioExtensions(m_xBuilder->weld_radio_button("radio_extensions"))
+ , mxRadioReset(m_xBuilder->weld_radio_button("radio_reset"))
+ , mxCBCheckProfilesafeConfig(m_xBuilder->weld_check_button("check_profilesafe_config"))
+ , mxCBCheckProfilesafeExtensions(m_xBuilder->weld_check_button("check_profilesafe_extensions"))
+ , mxCBDisableAllExtensions(m_xBuilder->weld_check_button("check_disable_all_extensions"))
+ , mxCBDeinstallUserExtensions(m_xBuilder->weld_check_button("check_deinstall_user_extensions"))
+ , mxCBResetSharedExtensions(m_xBuilder->weld_check_button("check_reset_shared_extensions"))
+ , mxCBResetBundledExtensions(m_xBuilder->weld_check_button("check_reset_bundled_extensions"))
+ , mxCBDisableHWAcceleration(m_xBuilder->weld_check_button("check_disable_hw_acceleration"))
+ , mxCBResetCustomizations(m_xBuilder->weld_check_button("check_reset_customizations"))
+ , mxCBResetWholeUserProfile(m_xBuilder->weld_check_button("check_reset_whole_userprofile"))
+ , mxBugLink(m_xBuilder->weld_link_button("linkbutton_bugs"))
+ , mxUserProfileLink(m_xBuilder->weld_link_button("linkbutton_profile"))
+ , mxBtnCreateZip(m_xBuilder->weld_button("btn_create_zip"))
+{
+ m_xDialog->set_centered_on_parent(false);
+ mxRadioRestore->connect_toggled(LINK(this, SafeModeDialog, RadioBtnHdl));
+ mxRadioConfigure->connect_toggled(LINK(this, SafeModeDialog, RadioBtnHdl));
+ mxRadioExtensions->connect_toggled(LINK(this, SafeModeDialog, RadioBtnHdl));
+ mxRadioReset->connect_toggled(LINK(this, SafeModeDialog, RadioBtnHdl));
+
+ mxBtnContinue->connect_clicked(LINK(this, SafeModeDialog, DialogBtnHdl));
+ mxBtnRestart->connect_clicked(LINK(this, SafeModeDialog, DialogBtnHdl));
+ mxBtnApply->connect_clicked(LINK(this, SafeModeDialog, DialogBtnHdl));
+
+ mxCBCheckProfilesafeConfig->connect_toggled(LINK(this, SafeModeDialog, CheckBoxHdl));
+ mxCBCheckProfilesafeExtensions->connect_toggled(LINK(this, SafeModeDialog, CheckBoxHdl));
+ mxCBDisableAllExtensions->connect_toggled(LINK(this, SafeModeDialog, CheckBoxHdl));
+ mxCBDeinstallUserExtensions->connect_toggled(LINK(this, SafeModeDialog, CheckBoxHdl));
+ mxCBResetSharedExtensions->connect_toggled(LINK(this, SafeModeDialog, CheckBoxHdl));
+ mxCBResetBundledExtensions->connect_toggled(LINK(this, SafeModeDialog, CheckBoxHdl));
+ mxCBDisableHWAcceleration->connect_toggled(LINK(this, SafeModeDialog, CheckBoxHdl));
+ mxCBResetCustomizations->connect_toggled(LINK(this, SafeModeDialog, CheckBoxHdl));
+ mxCBResetWholeUserProfile->connect_toggled(LINK(this, SafeModeDialog, CheckBoxHdl));
+
+ mxBtnCreateZip->connect_clicked(LINK(this, SafeModeDialog, CreateZipBtnHdl));
+
+ // Disable restart btn until some checkbox is active
+ mxBtnApply->set_sensitive(false);
+
+ // Check the first radio button and call its handler,
+ // it'll disable the relevant parts
+ mxRadioRestore->set_active(true);
+ RadioBtnHdl(*mxRadioRestore);
+
+ // Set URL for help button (module=safemode)
+ OUString sURL(officecfg::Office::Common::Menus::SendFeedbackURL::get() //officecfg/registry/data/org/openoffice/Office/Common.xcu => https://hub.libreoffice.org/send-feedback/
+ + "?LOversion=" + utl::ConfigManager::getAboutBoxProductVersion() +
+ "&LOlocale=" + utl::ConfigManager::getUILocale() + "&LOmodule=safemode");
+ mxBugLink->set_uri(sURL);
+
+ mxUserProfileLink->set_uri(comphelper::BackupFileHelper::getUserProfileURL());
+}
+
+SafeModeDialog::~SafeModeDialog()
+{
+}
+
+void SafeModeDialog::enableDisableWidgets()
+{
+ mxCBCheckProfilesafeConfig->set_sensitive(maBackupFileHelper.isPopPossible());
+ mxCBCheckProfilesafeExtensions->set_sensitive(maBackupFileHelper.isPopPossibleExtensionInfo());
+ mxCBDisableAllExtensions->set_sensitive(comphelper::BackupFileHelper::isTryDisableAllExtensionsPossible());
+ mxCBDeinstallUserExtensions->set_sensitive(comphelper::BackupFileHelper::isTryDeinstallUserExtensionsPossible());
+ mxCBResetSharedExtensions->set_sensitive(comphelper::BackupFileHelper::isTryResetSharedExtensionsPossible());
+ mxCBResetBundledExtensions->set_sensitive(comphelper::BackupFileHelper::isTryResetBundledExtensionsPossible());
+ mxCBResetCustomizations->set_sensitive(comphelper::BackupFileHelper::isTryResetCustomizationsPossible());
+
+ // no disable of mxCBResetWholeUserProfile, always possible (as last choice)
+}
+
+short SafeModeDialog::run()
+{
+ short nRet = weld::GenericDialogController::run();
+ // Remove the safe mode flag before exiting this dialog
+ sfx2::SafeMode::removeFlag();
+ return nRet;
+}
+
+void SafeModeDialog::applyChanges()
+{
+ // Restore
+ if (mxRadioRestore->get_active())
+ {
+ if (mxCBCheckProfilesafeConfig->get_active())
+ {
+ // reset UserConfiguration to last known working state
+ // ProfileSafeMode/BackupFileHelper
+ maBackupFileHelper.tryPop();
+ }
+
+ if (mxCBCheckProfilesafeExtensions->get_active())
+ {
+ // reset State of installed Extensions to last known working state
+ // ProfileSafeMode/BackupFileHelper
+ maBackupFileHelper.tryPopExtensionInfo();
+ }
+ }
+
+ // Configure
+ if (mxRadioConfigure->get_active())
+ {
+ if (mxCBDisableAllExtensions->get_active())
+ {
+ // Disable all extensions
+ comphelper::BackupFileHelper::tryDisableAllExtensions();
+ }
+
+ if (mxCBDisableHWAcceleration->get_active())
+ {
+ comphelper::BackupFileHelper::tryDisableHWAcceleration();
+ }
+ }
+
+ // Deinstall
+ if (mxRadioExtensions->get_active())
+ {
+ if (mxCBDeinstallUserExtensions->get_active())
+ {
+ // Deinstall all User Extensions (installed for User only)
+ comphelper::BackupFileHelper::tryDeinstallUserExtensions();
+ }
+
+ if (mxCBResetSharedExtensions->get_active())
+ {
+ // Reset shared Extensions
+ comphelper::BackupFileHelper::tryResetSharedExtensions();
+ }
+ if (mxCBResetBundledExtensions->get_active())
+ {
+ // Reset bundled Extensions
+ comphelper::BackupFileHelper::tryResetBundledExtensions();
+ }
+ }
+
+ // Reset
+ if (mxRadioReset->get_active())
+ {
+ if (mxCBResetCustomizations->get_active())
+ {
+ // Reset customizations (Settings and UserInterface modifications)
+ comphelper::BackupFileHelper::tryResetCustomizations();
+ }
+
+ if (mxCBResetWholeUserProfile->get_active())
+ {
+ // Reset the whole UserProfile
+ comphelper::BackupFileHelper::tryResetUserProfile();
+ }
+ }
+
+ // finally, restart
+ css::task::OfficeRestartManager::get(comphelper::getProcessComponentContext())->requestRestart(
+ css::uno::Reference< css::task::XInteractionHandler >());
+}
+
+IMPL_LINK(SafeModeDialog, RadioBtnHdl, weld::Toggleable&, rButton, void)
+{
+ if (!rButton.get_active())
+ return;
+ if (mxRadioRestore->get_active())
+ {
+ // Enable the currently selected box
+ mxBoxRestore->set_sensitive(true);
+ // Make sure only possible choices are active
+ enableDisableWidgets();
+ // Disable the unselected boxes
+ mxBoxReset->set_sensitive(false);
+ mxBoxConfigure->set_sensitive(false);
+ mxBoxDeinstall->set_sensitive(false);
+ }
+ else if (mxRadioConfigure->get_active())
+ {
+ // Enable the currently selected box
+ mxBoxConfigure->set_sensitive(true);
+ // Make sure only possible choices are active
+ enableDisableWidgets();
+ // Disable the unselected boxes
+ mxBoxRestore->set_sensitive(false);
+ mxBoxReset->set_sensitive(false);
+ mxBoxDeinstall->set_sensitive(false);
+
+ }
+ else if (mxRadioExtensions->get_active())
+ {
+ // Enable the currently selected box
+ mxBoxDeinstall->set_sensitive(true);
+ // Make sure only possible choices are active
+ enableDisableWidgets();
+ // Disable the unselected boxes
+ mxBoxRestore->set_sensitive(false);
+ mxBoxConfigure->set_sensitive(false);
+ mxBoxReset->set_sensitive(false);
+ }
+ else if (mxRadioReset->get_active())
+ {
+ // Enable the currently selected box
+ mxBoxReset->set_sensitive(true);
+ // Make sure only possible choices are active
+ enableDisableWidgets();
+ // Disable the unselected boxes
+ mxBoxConfigure->set_sensitive(false);
+ mxBoxRestore->set_sensitive(false);
+ mxBoxDeinstall->set_sensitive(false);
+ }
+}
+
+IMPL_LINK(SafeModeDialog, DialogBtnHdl, weld::Button&, rBtn, void)
+{
+ if (&rBtn == mxBtnContinue.get())
+ {
+ m_xDialog->response(RET_CLOSE);
+ }
+ else if (&rBtn == mxBtnRestart.get())
+ {
+ sfx2::SafeMode::putRestartFlag();
+ m_xDialog->response(RET_CLOSE);
+ uno::Reference< uno::XComponentContext > xContext = comphelper::getProcessComponentContext();
+ css::task::OfficeRestartManager::get(xContext)->requestRestart(
+ css::uno::Reference< css::task::XInteractionHandler >());
+ }
+ else if (&rBtn == mxBtnApply.get())
+ {
+ sfx2::SafeMode::putRestartFlag();
+ m_xDialog->response(RET_CLOSE);
+ applyChanges();
+ }
+}
+
+IMPL_LINK(SafeModeDialog, CreateZipBtnHdl, weld::Button&, /*rBtn*/, void)
+{
+ const OUString zipFileURL(comphelper::BackupFileHelper::getUserProfileURL() + "/libreoffice-profile.zip");
+ osl::File::remove(zipFileURL); // Remove previous exports
+ try
+ {
+ utl::ZipPackageHelper aZipHelper(comphelper::getProcessComponentContext(), zipFileURL);
+ aZipHelper.addFolderWithContent(aZipHelper.getRootFolder(), comphelper::BackupFileHelper::getUserProfileWorkURL());
+ aZipHelper.savePackage();
+ }
+ catch (const uno::Exception &)
+ {
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Warning, VclButtonsType::Ok,
+ SvxResId(RID_SVXSTR_SAFEMODE_ZIP_FAILURE)));
+ xBox->run();
+ return;
+ }
+
+ FileExportedDialog aDialog(m_xDialog.get(), SvxResId(RID_SVXSTR_SAFEMODE_USER_PROFILE_EXPORTED));
+ aDialog.run();
+}
+
+IMPL_LINK(SafeModeDialog, CheckBoxHdl, weld::Toggleable&, /*pCheckBox*/, void)
+{
+ const bool bEnable(
+ mxCBCheckProfilesafeConfig->get_active() ||
+ mxCBCheckProfilesafeExtensions->get_active() ||
+ mxCBDisableAllExtensions->get_active() ||
+ mxCBDeinstallUserExtensions->get_active() ||
+ mxCBResetSharedExtensions->get_active() ||
+ mxCBResetBundledExtensions->get_active() ||
+ mxCBDisableHWAcceleration->get_active() ||
+ mxCBResetCustomizations->get_active() ||
+ mxCBResetWholeUserProfile->get_active());
+
+ mxBtnApply->set_sensitive(bEnable);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/SafeModeDialog.hxx b/svx/source/dialog/SafeModeDialog.hxx
new file mode 100644
index 0000000000..dd7db077e0
--- /dev/null
+++ b/svx/source/dialog/SafeModeDialog.hxx
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_DIALOG_SAFEMODEDIALOG_HXX
+#define INCLUDED_SVX_SOURCE_DIALOG_SAFEMODEDIALOG_HXX
+
+#include <comphelper/backupfilehelper.hxx>
+#include <vcl/weld.hxx>
+
+class SafeModeDialog : public weld::GenericDialogController
+{
+public:
+ explicit SafeModeDialog(weld::Window* pParent);
+ virtual short run() override;
+ virtual ~SafeModeDialog() override;
+
+private:
+ std::unique_ptr<weld::Button> mxBtnContinue;
+ std::unique_ptr<weld::Button> mxBtnRestart;
+ std::unique_ptr<weld::Button> mxBtnApply;
+
+ std::unique_ptr<weld::Container> mxBoxRestore;
+ std::unique_ptr<weld::Container> mxBoxConfigure;
+ std::unique_ptr<weld::Container> mxBoxDeinstall;
+ std::unique_ptr<weld::Container> mxBoxReset;
+
+ std::unique_ptr<weld::RadioButton> mxRadioRestore;
+ std::unique_ptr<weld::RadioButton> mxRadioConfigure;
+ std::unique_ptr<weld::RadioButton> mxRadioExtensions;
+ std::unique_ptr<weld::RadioButton> mxRadioReset;
+
+ std::unique_ptr<weld::CheckButton> mxCBCheckProfilesafeConfig;
+ std::unique_ptr<weld::CheckButton> mxCBCheckProfilesafeExtensions;
+ std::unique_ptr<weld::CheckButton> mxCBDisableAllExtensions;
+ std::unique_ptr<weld::CheckButton> mxCBDeinstallUserExtensions;
+ std::unique_ptr<weld::CheckButton> mxCBResetSharedExtensions;
+ std::unique_ptr<weld::CheckButton> mxCBResetBundledExtensions;
+ std::unique_ptr<weld::CheckButton> mxCBDisableHWAcceleration;
+ std::unique_ptr<weld::CheckButton> mxCBResetCustomizations;
+ std::unique_ptr<weld::CheckButton> mxCBResetWholeUserProfile;
+
+ std::unique_ptr<weld::LinkButton> mxBugLink;
+ std::unique_ptr<weld::LinkButton> mxUserProfileLink;
+ std::unique_ptr<weld::Button> mxBtnCreateZip;
+
+ // local BackupFileHelper for handling possible restores
+ comphelper::BackupFileHelper maBackupFileHelper;
+
+ void enableDisableWidgets();
+ void applyChanges();
+
+ DECL_LINK(RadioBtnHdl, weld::Toggleable&, void);
+ DECL_LINK(CheckBoxHdl, weld::Toggleable&, void);
+ DECL_LINK(CreateZipBtnHdl, weld::Button&, void);
+ DECL_LINK(DialogBtnHdl, weld::Button&, void);
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/SafeModeUI.cxx b/svx/source/dialog/SafeModeUI.cxx
new file mode 100644
index 0000000000..4e32669f02
--- /dev/null
+++ b/svx/source/dialog/SafeModeUI.cxx
@@ -0,0 +1,79 @@
+/* -*- 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 <cppuhelper/implbase.hxx>
+#include <com/sun/star/frame/XSynchronousDispatch.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+#include <cppuhelper/supportsservice.hxx>
+
+#include <vcl/svapp.hxx>
+
+#include "SafeModeDialog.hxx"
+
+namespace {
+
+class SafeModeUI : public ::cppu::WeakImplHelper< css::lang::XServiceInfo,
+ css::frame::XSynchronousDispatch > // => XDispatch!
+{
+public:
+ SafeModeUI();
+
+ // css.lang.XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+
+ virtual sal_Bool SAL_CALL supportsService(const OUString& sServiceName) override;
+
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+
+ virtual css::uno::Any SAL_CALL dispatchWithReturnValue(const css::util::URL& aURL,
+ const css::uno::Sequence< css::beans::PropertyValue >& lArguments ) override;
+};
+
+SafeModeUI::SafeModeUI()
+{
+}
+
+OUString SAL_CALL SafeModeUI::getImplementationName()
+{
+ return "com.sun.star.comp.svx.SafeModeUI";
+}
+
+sal_Bool SAL_CALL SafeModeUI::supportsService(const OUString& sServiceName)
+{
+ return cppu::supportsService(this, sServiceName);
+}
+
+css::uno::Sequence< OUString > SAL_CALL SafeModeUI::getSupportedServiceNames()
+{
+ return { "com.sun.star.dialog.SafeModeUI" };
+}
+
+css::uno::Any SAL_CALL SafeModeUI::dispatchWithReturnValue(const css::util::URL&,
+ const css::uno::Sequence< css::beans::PropertyValue >& )
+{
+ SolarMutexGuard aGuard;
+ css::uno::Any aRet;
+ SafeModeDialog aDialog(Application::GetDefDialogParent());
+ aDialog.run();
+ return aRet;
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_svx_SafeModeUI_get_implementation(
+ css::uno::XComponentContext * /*context*/,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new SafeModeUI);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/SpellDialogChildWindow.cxx b/svx/source/dialog/SpellDialogChildWindow.cxx
new file mode 100644
index 0000000000..ae82769dfb
--- /dev/null
+++ b/svx/source/dialog/SpellDialogChildWindow.cxx
@@ -0,0 +1,90 @@
+/* -*- 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 <svx/SpellDialogChildWindow.hxx>
+
+#include <svx/svxdlg.hxx>
+#include <osl/diagnose.h>
+
+namespace svx {
+
+
+SpellDialogChildWindow::SpellDialogChildWindow (
+ vcl::Window* _pParent,
+ sal_uInt16 nId,
+ SfxBindings* pBindings)
+ : SfxChildWindow (_pParent, nId)
+{
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ m_xAbstractSpellDialog = pFact->CreateSvxSpellDialog(_pParent->GetFrameWeld(),
+ pBindings,
+ this );
+ SetController(m_xAbstractSpellDialog->GetController());
+ SetHideNotDelete(true);
+}
+
+SpellDialogChildWindow::~SpellDialogChildWindow()
+{
+ m_xAbstractSpellDialog.disposeAndClear();
+}
+
+SfxBindings& SpellDialogChildWindow::GetBindings() const
+{
+ assert(m_xAbstractSpellDialog);
+ return m_xAbstractSpellDialog->GetBindings();
+}
+
+void SpellDialogChildWindow::InvalidateSpellDialog()
+{
+ OSL_ASSERT (m_xAbstractSpellDialog);
+ if (m_xAbstractSpellDialog)
+ m_xAbstractSpellDialog->InvalidateDialog();
+}
+
+bool SpellDialogChildWindow::HasAutoCorrection()
+{
+ return false;
+}
+
+void SpellDialogChildWindow::AddAutoCorrection(
+ const OUString& /*rOld*/,
+ const OUString& /*rNew*/,
+ LanguageType /*eLanguage*/)
+{
+ OSL_FAIL("AutoCorrection should have been overridden - if available");
+}
+
+bool SpellDialogChildWindow::HasGrammarChecking()
+{
+ return false;
+}
+
+bool SpellDialogChildWindow::IsGrammarChecking()
+{
+ OSL_FAIL("Grammar checking should have been overridden - if available");
+ return false;
+}
+
+void SpellDialogChildWindow::SetGrammarChecking(bool )
+{
+ OSL_FAIL("Grammar checking should have been overridden - if available");
+}
+} // end of namespace ::svx
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/SvxNumOptionsTabPageHelper.cxx b/svx/source/dialog/SvxNumOptionsTabPageHelper.cxx
new file mode 100644
index 0000000000..0236c88353
--- /dev/null
+++ b/svx/source/dialog/SvxNumOptionsTabPageHelper.cxx
@@ -0,0 +1,88 @@
+/* -*- 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 <svx/SvxNumOptionsTabPageHelper.hxx>
+#include <com/sun/star/style/NumberingType.hpp>
+#include <com/sun/star/text/DefaultNumberingProvider.hpp>
+#include <com/sun/star/text/XNumberingTypeInfo.hpp>
+#include <comphelper/processfactory.hxx>
+
+using namespace css;
+using namespace css::uno;
+using namespace css::text;
+using namespace css::style;
+
+Reference<XDefaultNumberingProvider> SvxNumOptionsTabPageHelper::GetNumberingProvider()
+{
+ Reference<XComponentContext> xContext(::comphelper::getProcessComponentContext());
+ Reference<XDefaultNumberingProvider> xRet = text::DefaultNumberingProvider::create(xContext);
+ return xRet;
+}
+
+void SvxNumOptionsTabPageHelper::GetI18nNumbering(weld::ComboBox& rFmtLB, sal_uInt16 nDoNotRemove)
+{
+ Reference<XDefaultNumberingProvider> xDefNum = GetNumberingProvider();
+ Reference<XNumberingTypeInfo> xInfo(xDefNum, UNO_QUERY);
+
+ // Extended numbering schemes present in the resource but not offered by
+ // the i18n framework per configuration must be removed from the listbox.
+ // Do not remove a special entry matching nDoNotRemove.
+ const sal_uInt16 nDontRemove = SAL_MAX_UINT16;
+ ::std::vector<sal_uInt16> aRemove(rFmtLB.get_count(), nDontRemove);
+ for (size_t i = 0; i < aRemove.size(); ++i)
+ {
+ sal_uInt16 nEntryData = rFmtLB.get_id(i).toInt32();
+ if (nEntryData > NumberingType::CHARS_LOWER_LETTER_N && nEntryData != nDoNotRemove)
+ aRemove[i] = nEntryData;
+ }
+ if (xInfo.is())
+ {
+ const Sequence<sal_Int16> aTypes = xInfo->getSupportedNumberingTypes();
+ for (const sal_Int16 nCurrent : aTypes)
+ {
+ if (nCurrent > NumberingType::CHARS_LOWER_LETTER_N)
+ {
+ bool bInsert = true;
+ for (int nEntry = 0; nEntry < rFmtLB.get_count(); ++nEntry)
+ {
+ sal_uInt16 nEntryData = rFmtLB.get_id(nEntry).toInt32();
+ if (nEntryData == static_cast<sal_uInt16>(nCurrent))
+ {
+ bInsert = false;
+ aRemove[nEntry] = nDontRemove;
+ break;
+ }
+ }
+ if (bInsert)
+ {
+ OUString aIdent = xInfo->getNumberingIdentifier(nCurrent);
+ rFmtLB.append(OUString::number(nCurrent), aIdent);
+ }
+ }
+ }
+ }
+ for (unsigned short i : aRemove)
+ {
+ if (i == nDontRemove)
+ continue;
+ rFmtLB.remove_id(OUString::number(i));
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/ThemeColorEditDialog.cxx b/svx/source/dialog/ThemeColorEditDialog.cxx
new file mode 100644
index 0000000000..4b5e60a8b2
--- /dev/null
+++ b/svx/source/dialog/ThemeColorEditDialog.cxx
@@ -0,0 +1,89 @@
+/* -*- 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 <svx/dialog/ThemeColorEditDialog.hxx>
+#include <vcl/svapp.hxx>
+#include <svx/colorbox.hxx>
+
+namespace svx
+{
+ThemeColorEditDialog::ThemeColorEditDialog(weld::Window* pParent, model::ColorSet& rColorSet)
+ : GenericDialogController(pParent, "svx/ui/themecoloreditdialog.ui", "ThemeColorEditDialog")
+ , maColorSet(rColorSet)
+ , mxThemeColorsNameEntry(m_xBuilder->weld_entry("entryThemeColorsName"))
+ , mxDark1(new ColorListBox(m_xBuilder->weld_menu_button("buttonDark1"),
+ [pParent] { return pParent; }))
+ , mxLight1(new ColorListBox(m_xBuilder->weld_menu_button("buttonLight1"),
+ [pParent] { return pParent; }))
+ , mxDark2(new ColorListBox(m_xBuilder->weld_menu_button("buttonDark2"),
+ [pParent] { return pParent; }))
+ , mxLight2(new ColorListBox(m_xBuilder->weld_menu_button("buttonLight2"),
+ [pParent] { return pParent; }))
+ , mxAccent1(new ColorListBox(m_xBuilder->weld_menu_button("buttonAccent1"),
+ [pParent] { return pParent; }))
+ , mxAccent2(new ColorListBox(m_xBuilder->weld_menu_button("buttonAccent2"),
+ [pParent] { return pParent; }))
+ , mxAccent3(new ColorListBox(m_xBuilder->weld_menu_button("buttonAccent3"),
+ [pParent] { return pParent; }))
+ , mxAccent4(new ColorListBox(m_xBuilder->weld_menu_button("buttonAccent4"),
+ [pParent] { return pParent; }))
+ , mxAccent5(new ColorListBox(m_xBuilder->weld_menu_button("buttonAccent5"),
+ [pParent] { return pParent; }))
+ , mxAccent6(new ColorListBox(m_xBuilder->weld_menu_button("buttonAccent6"),
+ [pParent] { return pParent; }))
+ , mxHyperlink(new ColorListBox(m_xBuilder->weld_menu_button("buttonHyperlink"),
+ [pParent] { return pParent; }))
+ , mxFollowHyperlink(new ColorListBox(m_xBuilder->weld_menu_button("buttonFollowHyperlink"),
+ [pParent] { return pParent; }))
+{
+ mxThemeColorsNameEntry->set_text(rColorSet.getName());
+ mxDark1->SelectEntry(rColorSet.getColor(model::ThemeColorType::Dark1));
+ mxLight1->SelectEntry(rColorSet.getColor(model::ThemeColorType::Light1));
+ mxDark2->SelectEntry(rColorSet.getColor(model::ThemeColorType::Dark2));
+ mxLight2->SelectEntry(rColorSet.getColor(model::ThemeColorType::Light2));
+ mxAccent1->SelectEntry(rColorSet.getColor(model::ThemeColorType::Accent1));
+ mxAccent2->SelectEntry(rColorSet.getColor(model::ThemeColorType::Accent2));
+ mxAccent3->SelectEntry(rColorSet.getColor(model::ThemeColorType::Accent3));
+ mxAccent4->SelectEntry(rColorSet.getColor(model::ThemeColorType::Accent4));
+ mxAccent5->SelectEntry(rColorSet.getColor(model::ThemeColorType::Accent5));
+ mxAccent6->SelectEntry(rColorSet.getColor(model::ThemeColorType::Accent6));
+ mxHyperlink->SelectEntry(rColorSet.getColor(model::ThemeColorType::Hyperlink));
+ mxFollowHyperlink->SelectEntry(rColorSet.getColor(model::ThemeColorType::FollowedHyperlink));
+}
+
+ThemeColorEditDialog::~ThemeColorEditDialog() = default;
+
+model::ColorSet ThemeColorEditDialog::getColorSet()
+{
+ OUString aName = mxThemeColorsNameEntry->get_text();
+
+ model::ColorSet aColorSet(aName);
+
+ if (!aName.isEmpty())
+ {
+ aColorSet.add(model::ThemeColorType::Dark1, mxDark1->GetSelectEntryColor());
+ aColorSet.add(model::ThemeColorType::Light1, mxLight1->GetSelectEntryColor());
+ aColorSet.add(model::ThemeColorType::Dark2, mxDark2->GetSelectEntryColor());
+ aColorSet.add(model::ThemeColorType::Light2, mxLight2->GetSelectEntryColor());
+ aColorSet.add(model::ThemeColorType::Accent1, mxAccent1->GetSelectEntryColor());
+ aColorSet.add(model::ThemeColorType::Accent2, mxAccent2->GetSelectEntryColor());
+ aColorSet.add(model::ThemeColorType::Accent3, mxAccent3->GetSelectEntryColor());
+ aColorSet.add(model::ThemeColorType::Accent4, mxAccent4->GetSelectEntryColor());
+ aColorSet.add(model::ThemeColorType::Accent5, mxAccent5->GetSelectEntryColor());
+ aColorSet.add(model::ThemeColorType::Accent6, mxAccent6->GetSelectEntryColor());
+ aColorSet.add(model::ThemeColorType::Hyperlink, mxHyperlink->GetSelectEntryColor());
+ aColorSet.add(model::ThemeColorType::FollowedHyperlink,
+ mxFollowHyperlink->GetSelectEntryColor());
+ }
+ return aColorSet;
+}
+
+} // end svx namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/ThemeColorValueSet.cxx b/svx/source/dialog/ThemeColorValueSet.cxx
new file mode 100644
index 0000000000..d33e2fbc85
--- /dev/null
+++ b/svx/source/dialog/ThemeColorValueSet.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/.
+ */
+
+#include <svx/dialog/ThemeColorValueSet.hxx>
+#include <docmodel/uno/UnoComplexColor.hxx>
+#include <vcl/event.hxx>
+
+namespace svx
+{
+constexpr tools::Long BORDER = 4;
+constexpr tools::Long SIZE = 16;
+constexpr tools::Long LABEL_HEIGHT = 16;
+constexpr tools::Long LABEL_TEXT_HEIGHT = 14;
+constexpr tools::Long constElementNumber = 8;
+
+void ThemeColorValueSet::insert(model::ColorSet const& rColorSet)
+{
+ maColorSets.push_back(std::cref(rColorSet));
+ InsertItem(maColorSets.size());
+}
+
+void ThemeColorValueSet::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ ValueSet::SetDrawingArea(pDrawingArea);
+ SetStyle(WB_TABSTOP | WB_ITEMBORDER | WB_DOUBLEBORDER);
+ Size aSize(BORDER * 7 + SIZE * 6 + BORDER * 2, BORDER * 3 + SIZE * 2 + LABEL_HEIGHT);
+ SetItemWidth(aSize.Width());
+ SetItemHeight(aSize.Height());
+}
+
+void ThemeColorValueSet::UserDraw(const UserDrawEvent& rUserDrawEvent)
+{
+ vcl::RenderContext* pDev = rUserDrawEvent.GetRenderContext();
+ tools::Rectangle aRect = rUserDrawEvent.GetRect();
+ const Point aPosition = aRect.GetPos();
+ const sal_uInt16 nItemId = rUserDrawEvent.GetItemId();
+ model::ColorSet const& rColorSet = maColorSets[nItemId - 1];
+
+ Size aSize = aRect.GetSize();
+ Size aMin(BORDER * 7 + SIZE * constElementNumber / 2 + BORDER * 2,
+ BORDER * 3 + SIZE * 2 + LABEL_HEIGHT);
+ tools::Long startX = (aSize.Width() / 2.0) - (aMin.Width() / 2.0);
+ tools::Long x = BORDER;
+ tools::Long y1 = BORDER + LABEL_HEIGHT;
+ tools::Long y2 = y1 + SIZE + BORDER;
+
+ pDev->SetLineColor(COL_LIGHTGRAY);
+ pDev->SetFillColor(COL_LIGHTGRAY);
+ tools::Rectangle aNameRect(aPosition, Size(aSize.Width(), LABEL_HEIGHT));
+ pDev->DrawRect(aNameRect);
+
+ vcl::Font aFont;
+ OUString aName = rColorSet.getName();
+ aFont.SetFontHeight(LABEL_TEXT_HEIGHT);
+ pDev->SetFont(aFont);
+
+ Size aTextSize(pDev->GetTextWidth(aName), pDev->GetTextHeight());
+
+ Point aPoint(aPosition.X() + (aNameRect.GetWidth() / 2.0) - (aTextSize.Width() / 2.0),
+ aPosition.Y() + (aNameRect.GetHeight() / 2.0) - (aTextSize.Height() / 2.0));
+
+ pDev->DrawText(aPoint, aName);
+
+ pDev->SetLineColor(COL_LIGHTGRAY);
+ pDev->SetFillColor();
+
+ for (sal_uInt32 i = 2; i < 10; i += 2)
+ {
+ pDev->SetFillColor(rColorSet.getColor(model::convertToThemeColorType(i)));
+ pDev->DrawRect(tools::Rectangle(Point(aPosition.X() + x + startX, aPosition.Y() + y1),
+ Size(SIZE, SIZE)));
+
+ pDev->SetFillColor(rColorSet.getColor(model::convertToThemeColorType(i + 1)));
+ pDev->DrawRect(tools::Rectangle(Point(aPosition.X() + x + startX, aPosition.Y() + y2),
+ Size(SIZE, SIZE)));
+
+ x += SIZE + BORDER;
+ if (i == 2 || i == 8)
+ x += BORDER;
+ }
+}
+
+void ThemeColorValueSet::StyleUpdated()
+{
+ SetFormat();
+ Invalidate();
+ ValueSet::StyleUpdated();
+}
+
+} // end svx namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/ThemeDialog.cxx b/svx/source/dialog/ThemeDialog.cxx
new file mode 100644
index 0000000000..e3a206be6c
--- /dev/null
+++ b/svx/source/dialog/ThemeDialog.cxx
@@ -0,0 +1,132 @@
+/* -*- 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 <svx/dialog/ThemeDialog.hxx>
+#include <docmodel/theme/ColorSet.hxx>
+#include <docmodel/theme/Theme.hxx>
+#include <svx/ColorSets.hxx>
+#include <vcl/svapp.hxx>
+#include <svx/colorbox.hxx>
+#include <comphelper/lok.hxx>
+
+namespace svx
+{
+ThemeDialog::ThemeDialog(weld::Window* pParent, model::Theme* pTheme)
+ : GenericDialogController(pParent, "svx/ui/themedialog.ui", "ThemeDialog")
+ , mpWindow(pParent)
+ , mpTheme(pTheme)
+ , mxValueSetThemeColors(new svx::ThemeColorValueSet)
+ , mxValueSetThemeColorsWindow(
+ new weld::CustomWeld(*m_xBuilder, "valueset_theme_colors", *mxValueSetThemeColors))
+ , mxAdd(m_xBuilder->weld_button("button_add"))
+{
+ mxValueSetThemeColors->SetColCount(3);
+ mxValueSetThemeColors->SetLineCount(4);
+ mxValueSetThemeColors->SetColor(Application::GetSettings().GetStyleSettings().GetFaceColor());
+ mxValueSetThemeColors->SetDoubleClickHdl(LINK(this, ThemeDialog, DoubleClickValueSetHdl));
+ mxValueSetThemeColors->SetSelectHdl(LINK(this, ThemeDialog, SelectItem));
+
+ mxAdd->connect_clicked(LINK(this, ThemeDialog, ButtonClicked));
+
+ initColorSets();
+
+ if (!maColorSets.empty())
+ {
+ mxValueSetThemeColors->SelectItem(1); // ItemId 1, position 0
+ mpCurrentColorSet = std::make_shared<model::ColorSet>(maColorSets[0]);
+ }
+}
+
+ThemeDialog::~ThemeDialog()
+{
+ if (mxSubDialog)
+ mxSubDialog->response(RET_CANCEL);
+}
+
+void ThemeDialog::initColorSets()
+{
+ if (mpTheme)
+ maColorSets.push_back(*mpTheme->getColorSet());
+
+ auto const& rColorSetVector = ColorSets::get().getColorSetVector();
+ maColorSets.insert(maColorSets.end(), rColorSetVector.begin(), rColorSetVector.end());
+
+ for (auto const& rColorSet : maColorSets)
+ {
+ mxValueSetThemeColors->insert(rColorSet);
+ }
+
+ mxValueSetThemeColors->SetOptimalSize();
+}
+
+IMPL_LINK_NOARG(ThemeDialog, DoubleClickValueSetHdl, ValueSet*, void)
+{
+ SelectItem(nullptr);
+ if (!comphelper::LibreOfficeKit::isActive())
+ m_xDialog->response(RET_OK);
+}
+
+IMPL_LINK_NOARG(ThemeDialog, SelectItem, ValueSet*, void)
+{
+ sal_uInt32 nItemId = mxValueSetThemeColors->GetSelectedItemId();
+ if (!nItemId)
+ return;
+
+ sal_uInt32 nIndex = nItemId - 1;
+
+ if (nIndex >= maColorSets.size())
+ return;
+
+ mpCurrentColorSet = std::make_shared<model::ColorSet>(maColorSets[nIndex]);
+}
+
+void ThemeDialog::runThemeColorEditDialog()
+{
+ if (mxSubDialog)
+ return;
+
+ mxSubDialog = std::make_shared<svx::ThemeColorEditDialog>(mpWindow, *mpCurrentColorSet);
+
+ weld::DialogController::runAsync(mxSubDialog, [this](sal_uInt32 nResult) {
+ if (nResult != RET_OK)
+ {
+ mxAdd->set_sensitive(true);
+ mxSubDialog = nullptr;
+ return;
+ }
+ auto aColorSet = mxSubDialog->getColorSet();
+ if (!aColorSet.getName().isEmpty())
+ {
+ ColorSets::get().insert(aColorSet, ColorSets::IdenticalNameAction::AutoRename);
+ maColorSets.clear();
+ mxValueSetThemeColors->Clear();
+
+ initColorSets();
+
+ mxValueSetThemeColors->SelectItem(maColorSets.size() - 1);
+ mpCurrentColorSet
+ = std::make_shared<model::ColorSet>(maColorSets[maColorSets.size() - 1]);
+ }
+ mxAdd->set_sensitive(true);
+ mxSubDialog = nullptr;
+ });
+}
+
+IMPL_LINK(ThemeDialog, ButtonClicked, weld::Button&, rButton, void)
+{
+ mxAdd->set_sensitive(false);
+ if (mpCurrentColorSet && mxAdd.get() == &rButton)
+ {
+ runThemeColorEditDialog();
+ }
+}
+
+} // end svx namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/_bmpmask.cxx b/svx/source/dialog/_bmpmask.cxx
new file mode 100644
index 0000000000..1385aea0c9
--- /dev/null
+++ b/svx/source/dialog/_bmpmask.cxx
@@ -0,0 +1,1055 @@
+/* -*- 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/event.hxx>
+#include <vcl/metaact.hxx>
+#include <vcl/virdev.hxx>
+#include <svtools/valueset.hxx>
+#include <svl/eitem.hxx>
+#include <svl/itemset.hxx>
+#include <sfx2/dispatch.hxx>
+#include <svtools/colrdlg.hxx>
+
+#include <svx/colorbox.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/bmpmask.hxx>
+#include <svx/strings.hrc>
+#include <svx/svxids.hrc>
+#include <memory>
+#include <helpids.h>
+
+#define OWN_CALLMODE SfxCallMode::ASYNCHRON | SfxCallMode::RECORD
+
+
+#define TEST_COLS() \
+{ \
+ nR = aCol.GetRed(); nG = aCol.GetGreen(); nB = aCol.GetBlue(); \
+ for( i = 0; i < nCount; i++ ) \
+ { \
+ if ( ( pMinR[i] <= nR ) && ( pMaxR[i] >= nR ) && \
+ ( pMinG[i] <= nG ) && ( pMaxG[i] >= nG ) && \
+ ( pMinB[i] <= nB ) && ( pMaxB[i] >= nB ) ) \
+ { \
+ aCol = pDstCols[i]; bReplace = true; break; \
+ } \
+ } \
+}
+
+SFX_IMPL_DOCKINGWINDOW_WITHID( SvxBmpMaskChildWindow, SID_BMPMASK )
+
+class BmpColorWindow : public weld::CustomWidgetController
+{
+ Color aColor;
+
+
+public:
+ explicit BmpColorWindow()
+ : aColor( COL_WHITE )
+ {
+ }
+
+ void SetColor( const Color& rColor )
+ {
+ aColor = rColor;
+ Invalidate();
+ }
+
+ virtual void Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect ) override;
+
+ virtual void SetDrawingArea(weld::DrawingArea* pArea) override
+ {
+ Size aSize(pArea->get_ref_device().LogicToPixel(Size(43, 14), MapMode(MapUnit::MapAppFont)));
+ CustomWidgetController::SetDrawingArea(pArea);
+ pArea->set_size_request(aSize.Width(), aSize.Height());
+ SetOutputSizePixel(aSize);
+ }
+};
+
+class MaskSet : public ValueSet
+{
+ VclPtr<SvxBmpMask> pSvxBmpMask;
+
+public:
+ MaskSet(SvxBmpMask* pMask);
+ virtual void Select() override;
+ virtual bool KeyInput( const KeyEvent& rKEvt ) override;
+ virtual void GetFocus() override;
+ virtual void SetDrawingArea(weld::DrawingArea* pArea) override
+ {
+ Size aSize(pArea->get_ref_device().LogicToPixel(Size(24, 12), MapMode(MapUnit::MapAppFont)));
+ ValueSet::SetDrawingArea(pArea);
+ pArea->set_size_request(aSize.Width(), aSize.Height());
+ SetOutputSizePixel(aSize);
+ SetHelpId(HID_BMPMASK_CTL_QCOL_1);
+ }
+ void onEditColor();
+};
+
+MaskSet::MaskSet(SvxBmpMask* pMask)
+ : ValueSet(nullptr)
+ , pSvxBmpMask(pMask)
+{
+}
+
+void MaskSet::Select()
+{
+ ValueSet::Select();
+
+ pSvxBmpMask->onSelect( this );
+}
+
+void MaskSet::GetFocus()
+{
+ ValueSet::GetFocus();
+ SelectItem( 1 );
+ pSvxBmpMask->onSelect( this );
+}
+
+bool MaskSet::KeyInput( const KeyEvent& rKEvt )
+{
+ bool bRet = false;
+
+ vcl::KeyCode aCode = rKEvt.GetKeyCode();
+
+ // if the key has a modifier we don't care
+ if( aCode.GetModifier() )
+ {
+ bRet = ValueSet::KeyInput( rKEvt );
+ }
+ else
+ {
+ // check for keys that interests us
+ switch ( aCode.GetCode() )
+ {
+ case KEY_SPACE:
+ onEditColor();
+ bRet = true;
+ break;
+ default:
+ bRet = ValueSet::KeyInput( rKEvt );
+ }
+ }
+ return bRet;
+}
+
+void MaskSet::onEditColor()
+{
+ SvColorDialog aColorDlg;
+
+ aColorDlg.SetColor(GetItemColor(1));
+
+ if (aColorDlg.Execute(pSvxBmpMask->GetFrameWeld()))
+ SetItemColor(1, aColorDlg.GetColor());
+}
+
+class MaskData
+{
+ VclPtr<SvxBmpMask> pMask;
+ bool bIsReady;
+ bool bExecState;
+ SfxBindings& rBindings;
+
+public:
+ MaskData( SvxBmpMask* pBmpMask, SfxBindings& rBind );
+
+ bool IsCbxReady() const { return bIsReady; }
+ void SetExecState( bool bState ) { bExecState = bState; }
+ bool IsExecReady() const { return bExecState; }
+
+ DECL_LINK( PipetteHdl, const OUString&, void );
+ DECL_LINK( CbxHdl, weld::Toggleable&, void);
+ DECL_LINK( CbxTransHdl, weld::Toggleable&, void );
+ DECL_LINK( FocusLbHdl, weld::Widget&, void );
+ DECL_LINK(ExecHdl, weld::Button&, void);
+};
+
+
+MaskData::MaskData( SvxBmpMask* pBmpMask, SfxBindings& rBind ) :
+
+ pMask ( pBmpMask ),
+ bIsReady ( false ),
+ bExecState ( false ),
+ rBindings ( rBind )
+
+{
+}
+
+IMPL_LINK( MaskData, PipetteHdl, const OUString&, rId, void )
+{
+ SfxBoolItem aBItem( SID_BMPMASK_PIPETTE,
+ pMask->m_xTbxPipette->get_item_active(rId) );
+
+ rBindings.GetDispatcher()->ExecuteList(SID_BMPMASK_PIPETTE, OWN_CALLMODE,
+ { &aBItem });
+}
+
+IMPL_LINK( MaskData, CbxHdl, weld::Toggleable&, rCbx, void )
+{
+ bIsReady = pMask->m_xCbx1->get_active() || pMask->m_xCbx2->get_active() ||
+ pMask->m_xCbx3->get_active() || pMask->m_xCbx4->get_active();
+
+ if ( bIsReady && IsExecReady() )
+ pMask->m_xBtnExec->set_sensitive(true);
+ else
+ pMask->m_xBtnExec->set_sensitive(false);
+
+ // When a checkbox is checked, the pipette is enabled
+ if ( !rCbx.get_active() )
+ return;
+
+ MaskSet* pSet = nullptr;
+
+ if (&rCbx == pMask->m_xCbx1.get())
+ pSet = pMask->m_xQSet1.get();
+ else if (&rCbx == pMask->m_xCbx2.get())
+ pSet = pMask->m_xQSet2.get();
+ else if (&rCbx == pMask->m_xCbx3.get())
+ pSet = pMask->m_xQSet3.get();
+ else // if ( &rCbx == pMask->m_xCbx4 )
+ pSet = pMask->m_xQSet4.get();
+
+ pSet->SelectItem( 1 );
+ pSet->Select();
+
+ pMask->m_xTbxPipette->set_item_active("pipette", true);
+ PipetteHdl("pipette");
+}
+
+IMPL_LINK( MaskData, CbxTransHdl, weld::Toggleable&, rCbx, void )
+{
+ bIsReady = rCbx.get_active();
+ if ( bIsReady )
+ {
+ pMask->m_xQSet1->Disable();
+ pMask->m_xQSet2->Disable();
+ pMask->m_xQSet3->Disable();
+ pMask->m_xQSet4->Disable();
+ pMask->m_xCtlPipette->Disable();
+ pMask->m_xCbx1->set_sensitive(false);
+ pMask->m_xSp1->set_sensitive(false);
+ pMask->m_xCbx2->set_sensitive(false);
+ pMask->m_xSp2->set_sensitive(false);
+ pMask->m_xCbx3->set_sensitive(false);
+ pMask->m_xSp3->set_sensitive(false);
+ pMask->m_xCbx4->set_sensitive(false);
+ pMask->m_xSp4->set_sensitive(false);
+ pMask->m_xTbxPipette->set_sensitive(false);
+
+ pMask->m_xLbColor1->set_sensitive(false);
+ pMask->m_xLbColor2->set_sensitive(false);
+ pMask->m_xLbColor3->set_sensitive(false);
+ pMask->m_xLbColor4->set_sensitive(false);
+ pMask->m_xLbColorTrans->set_sensitive(true);
+ }
+ else
+ {
+ pMask->m_xQSet1->Enable();
+ pMask->m_xQSet2->Enable();
+ pMask->m_xQSet3->Enable();
+ pMask->m_xQSet4->Enable();
+ pMask->m_xCtlPipette->Enable();
+ pMask->m_xCbx1->set_sensitive(true);
+ pMask->m_xSp1->set_sensitive(true);
+ pMask->m_xCbx2->set_sensitive(true);
+ pMask->m_xSp2->set_sensitive(true);
+ pMask->m_xCbx3->set_sensitive(true);
+ pMask->m_xSp3->set_sensitive(true);
+ pMask->m_xCbx4->set_sensitive(true);
+ pMask->m_xSp4->set_sensitive(true);
+ pMask->m_xTbxPipette->set_sensitive(true);
+
+ pMask->m_xLbColor1->set_sensitive(true);
+ pMask->m_xLbColor2->set_sensitive(true);
+ pMask->m_xLbColor3->set_sensitive(true);
+ pMask->m_xLbColor4->set_sensitive(true);
+ pMask->m_xLbColorTrans->set_sensitive(false);
+
+ bIsReady = pMask->m_xCbx1->get_active() || pMask->m_xCbx2->get_active() ||
+ pMask->m_xCbx3->get_active() || pMask->m_xCbx4->get_active();
+ }
+
+ if ( bIsReady && IsExecReady() )
+ pMask->m_xBtnExec->set_sensitive(true);
+ else
+ pMask->m_xBtnExec->set_sensitive(false);
+}
+
+IMPL_LINK( MaskData, FocusLbHdl, weld::Widget&, rLb, void )
+{
+ pMask->m_xQSet1->SelectItem( &rLb == &pMask->m_xLbColor1->get_widget() ? 1 : 0 /* , false */ );
+ pMask->m_xQSet2->SelectItem( &rLb == &pMask->m_xLbColor2->get_widget() ? 1 : 0 /* , false */ );
+ pMask->m_xQSet3->SelectItem( &rLb == &pMask->m_xLbColor3->get_widget() ? 1 : 0 /* , false */ );
+ pMask->m_xQSet4->SelectItem( &rLb == &pMask->m_xLbColor4->get_widget() ? 1 : 0 /* , false */ );
+}
+
+IMPL_LINK_NOARG(MaskData, ExecHdl, weld::Button&, void)
+{
+ SfxBoolItem aBItem( SID_BMPMASK_EXEC, true );
+ rBindings.GetDispatcher()->ExecuteList(SID_BMPMASK_EXEC, OWN_CALLMODE,
+ { &aBItem });
+}
+
+void BmpColorWindow::Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& /*Rect*/)
+{
+ rRenderContext.Push(vcl::PushFlags::LINECOLOR | vcl::PushFlags::FILLCOLOR);
+ rRenderContext.SetLineColor(aColor);
+ rRenderContext.SetFillColor(aColor);
+ rRenderContext.DrawRect(tools::Rectangle(Point(), GetOutputSizePixel()));
+ rRenderContext.Pop();
+}
+
+SvxBmpMaskSelectItem::SvxBmpMaskSelectItem( SvxBmpMask& rMask,
+ SfxBindings& rBindings ) :
+ SfxControllerItem ( SID_BMPMASK_EXEC, rBindings ),
+ rBmpMask ( rMask)
+{
+}
+
+void SvxBmpMaskSelectItem::StateChangedAtToolBoxControl( sal_uInt16 nSID, SfxItemState /*eState*/,
+ const SfxPoolItem* pItem )
+{
+ if ( ( nSID == SID_BMPMASK_EXEC ) && pItem )
+ {
+ const SfxBoolItem* pStateItem = dynamic_cast<const SfxBoolItem*>( pItem );
+ assert(pStateItem); // SfxBoolItem expected
+ if (pStateItem)
+ rBmpMask.SetExecState( pStateItem->GetValue() );
+ }
+}
+
+SvxBmpMaskChildWindow::SvxBmpMaskChildWindow(vcl::Window* pParent_, sal_uInt16 nId,
+ SfxBindings* pBindings,
+ SfxChildWinInfo* pInfo)
+ : SfxChildWindow(pParent_, nId)
+{
+ VclPtr<SvxBmpMask> pDlg = VclPtr<SvxBmpMask>::Create(pBindings, this, pParent_);
+
+ SetWindow( pDlg );
+
+ pDlg->Initialize( pInfo );
+}
+
+SvxBmpMask::SvxBmpMask(SfxBindings *pBindinx, SfxChildWindow *pCW, vcl::Window* pParent)
+ : SfxDockingWindow(pBindinx, pCW, pParent, "DockingColorReplace",
+ "svx/ui/dockingcolorreplace.ui")
+ , m_xTbxPipette(m_xBuilder->weld_toolbar("toolbar"))
+ , m_xCtlPipette(new BmpColorWindow)
+ , m_xCtlPipetteWin(new weld::CustomWeld(*m_xBuilder, "toolcolor", *m_xCtlPipette))
+ , m_xBtnExec(m_xBuilder->weld_button("replace"))
+ , m_xCbx1(m_xBuilder->weld_check_button("cbx1"))
+ , m_xQSet1(new MaskSet(this))
+ , m_xQSetWin1(new weld::CustomWeld(*m_xBuilder, "qset1", *m_xQSet1))
+ , m_xSp1(m_xBuilder->weld_metric_spin_button("tol1", FieldUnit::PERCENT))
+ , m_xLbColor1(new ColorListBox(m_xBuilder->weld_menu_button("color1"), [this]{ return GetFrameWeld(); }))
+ , m_xCbx2(m_xBuilder->weld_check_button("cbx2"))
+ , m_xQSet2(new MaskSet(this))
+ , m_xQSetWin2(new weld::CustomWeld(*m_xBuilder, "qset2", *m_xQSet2))
+ , m_xSp2(m_xBuilder->weld_metric_spin_button("tol2", FieldUnit::PERCENT))
+ , m_xLbColor2(new ColorListBox(m_xBuilder->weld_menu_button("color2"), [this]{ return GetFrameWeld(); }))
+ , m_xCbx3(m_xBuilder->weld_check_button("cbx3"))
+ , m_xQSet3(new MaskSet(this))
+ , m_xQSetWin3(new weld::CustomWeld(*m_xBuilder, "qset3", *m_xQSet3))
+ , m_xSp3(m_xBuilder->weld_metric_spin_button("tol3", FieldUnit::PERCENT))
+ , m_xLbColor3(new ColorListBox(m_xBuilder->weld_menu_button("color3"), [this]{ return GetFrameWeld(); }))
+ , m_xCbx4(m_xBuilder->weld_check_button("cbx4"))
+ , m_xQSet4(new MaskSet(this))
+ , m_xQSetWin4(new weld::CustomWeld(*m_xBuilder, "qset4", *m_xQSet4))
+ , m_xSp4(m_xBuilder->weld_metric_spin_button("tol4", FieldUnit::PERCENT))
+ , m_xLbColor4(new ColorListBox(m_xBuilder->weld_menu_button("color4"), [this]{ return GetFrameWeld(); }))
+ , m_xCbxTrans(m_xBuilder->weld_check_button("cbx5"))
+ , m_xLbColorTrans(new ColorListBox(m_xBuilder->weld_menu_button("color5"), [this]{ return GetFrameWeld(); }))
+ , m_xData(new MaskData(this, *pBindinx))
+ , aPipetteColor(COL_WHITE)
+ , aSelItem(*this, *pBindinx)
+{
+ SetText(SvxResId(RID_SVXDLG_BMPMASK_STR_TITLE));
+
+ m_xLbColor1->SetSlotId(SID_BMPMASK_COLOR);
+ m_xLbColor2->SetSlotId(SID_BMPMASK_COLOR);
+ m_xLbColor3->SetSlotId(SID_BMPMASK_COLOR);
+ m_xLbColor4->SetSlotId(SID_BMPMASK_COLOR);
+
+ m_xLbColorTrans->SelectEntry(COL_BLACK);
+ m_xLbColor1->SelectEntry(COL_TRANSPARENT);
+ m_xLbColor2->SelectEntry(COL_TRANSPARENT);
+ m_xLbColor3->SelectEntry(COL_TRANSPARENT);
+ m_xLbColor4->SelectEntry(COL_TRANSPARENT);
+
+ m_xTbxPipette->connect_clicked( LINK( m_xData.get(), MaskData, PipetteHdl ) );
+ m_xBtnExec->connect_clicked( LINK( m_xData.get(), MaskData, ExecHdl ) );
+
+ m_xCbx1->connect_toggled( LINK( m_xData.get(), MaskData, CbxHdl ) );
+ m_xCbx2->connect_toggled( LINK( m_xData.get(), MaskData, CbxHdl ) );
+ m_xCbx3->connect_toggled( LINK( m_xData.get(), MaskData, CbxHdl ) );
+ m_xCbx4->connect_toggled( LINK( m_xData.get(), MaskData, CbxHdl ) );
+ m_xCbxTrans->connect_toggled( LINK( m_xData.get(), MaskData, CbxTransHdl ) );
+
+ SetAccessibleNames ();
+
+ m_xLbColor1->connect_focus_in( LINK( m_xData.get(), MaskData, FocusLbHdl ) );
+ m_xLbColor2->connect_focus_in( LINK( m_xData.get(), MaskData, FocusLbHdl ) );
+ m_xLbColor3->connect_focus_in( LINK( m_xData.get(), MaskData, FocusLbHdl ) );
+ m_xLbColor4->connect_focus_in( LINK( m_xData.get(), MaskData, FocusLbHdl ) );
+ m_xLbColorTrans->set_sensitive(false);
+
+ OUString sColorPalette (SvxResId( RID_SVXDLG_BMPMASK_STR_PALETTE));
+ OUString sColorPaletteN;
+
+ m_xQSet1->SetStyle( m_xQSet1->GetStyle() | WB_DOUBLEBORDER | WB_ITEMBORDER );
+ m_xQSet1->SetColCount();
+ m_xQSet1->SetLineCount( 1 );
+ sColorPaletteN = sColorPalette + " 1";
+ m_xQSet1->InsertItem( 1, aPipetteColor, sColorPaletteN);
+ m_xQSet1->SelectItem( 1 );
+
+ m_xQSet2->SetStyle( m_xQSet2->GetStyle() | WB_DOUBLEBORDER | WB_ITEMBORDER );
+ m_xQSet2->SetColCount();
+ m_xQSet2->SetLineCount( 1 );
+ sColorPaletteN = sColorPalette + " 2";
+ m_xQSet2->InsertItem( 1, aPipetteColor, sColorPaletteN);
+ m_xQSet2->SelectItem( 0 );
+
+ m_xQSet3->SetStyle( m_xQSet3->GetStyle() | WB_DOUBLEBORDER | WB_ITEMBORDER );
+ m_xQSet3->SetColCount();
+ m_xQSet3->SetLineCount( 1 );
+ sColorPaletteN = sColorPalette + " 3";
+ m_xQSet3->InsertItem( 1, aPipetteColor, sColorPaletteN);
+ m_xQSet3->SelectItem( 0 );
+
+ m_xQSet4->SetStyle( m_xQSet4->GetStyle() | WB_DOUBLEBORDER | WB_ITEMBORDER );
+ m_xQSet4->SetColCount();
+ m_xQSet4->SetLineCount( 1 );
+ sColorPaletteN = sColorPalette + " 4";
+ m_xQSet4->InsertItem( 1, aPipetteColor, sColorPaletteN);
+ m_xQSet4->SelectItem( 0 );
+
+ m_xQSet1->Show();
+ m_xQSet2->Show();
+ m_xQSet3->Show();
+ m_xQSet4->Show();
+}
+
+SvxBmpMask::~SvxBmpMask()
+{
+ disposeOnce();
+}
+
+void SvxBmpMask::dispose()
+{
+ m_xQSetWin1.reset();
+ m_xQSet1.reset();
+ m_xQSetWin2.reset();
+ m_xQSet2.reset();
+ m_xQSetWin3.reset();
+ m_xQSet3.reset();
+ m_xQSetWin4.reset();
+ m_xQSet4.reset();
+ m_xCtlPipetteWin.reset();
+ m_xCtlPipette.reset();
+ m_xData.reset();
+ m_xTbxPipette.reset();
+ m_xBtnExec.reset();
+ m_xCbx1.reset();
+ m_xSp1.reset();
+ m_xLbColor1.reset();
+ m_xCbx2.reset();
+ m_xSp2.reset();
+ m_xLbColor2.reset();
+ m_xCbx3.reset();
+ m_xSp3.reset();
+ m_xLbColor3.reset();
+ m_xCbx4.reset();
+ m_xSp4.reset();
+ m_xLbColor4.reset();
+ m_xCbxTrans.reset();
+ m_xLbColorTrans.reset();
+ aSelItem.dispose();
+ SfxDockingWindow::dispose();
+}
+
+/** is called by a MaskSet when it is selected */
+void SvxBmpMask::onSelect( const MaskSet* pSet )
+{
+ // now deselect all other value sets
+ if( pSet != m_xQSet1.get() )
+ m_xQSet1->SelectItem( 0 );
+
+ if( pSet != m_xQSet2.get() )
+ m_xQSet2->SelectItem( 0 );
+
+ if( pSet != m_xQSet3.get() )
+ m_xQSet3->SelectItem( 0 );
+
+ if( pSet != m_xQSet4.get() )
+ m_xQSet4->SelectItem( 0 );
+}
+
+bool SvxBmpMask::Close()
+{
+ SfxBoolItem aItem2( SID_BMPMASK_PIPETTE, false );
+ GetBindings().GetDispatcher()->ExecuteList(SID_BMPMASK_PIPETTE,
+ OWN_CALLMODE, { &aItem2 });
+
+ return SfxDockingWindow::Close();
+}
+
+void SvxBmpMask::SetColor( const Color& rColor )
+{
+ aPipetteColor = rColor;
+ m_xCtlPipette->SetColor( aPipetteColor );
+}
+
+void SvxBmpMask::PipetteClicked()
+{
+ if( m_xQSet1->GetSelectedItemId() == 1 )
+ {
+ m_xCbx1->set_active(true);
+ m_xData->CbxHdl(*m_xCbx1);
+ m_xQSet1->SetItemColor( 1, aPipetteColor );
+ m_xQSet1->SetFormat();
+ }
+ else if( m_xQSet2->GetSelectedItemId() == 1 )
+ {
+ m_xCbx2->set_active(true);
+ m_xData->CbxHdl(*m_xCbx2);
+ m_xQSet2->SetItemColor( 1, aPipetteColor );
+ m_xQSet2->SetFormat();
+ }
+ else if( m_xQSet3->GetSelectedItemId() == 1 )
+ {
+ m_xCbx3->set_active(true);
+ m_xData->CbxHdl(*m_xCbx3);
+ m_xQSet3->SetItemColor( 1, aPipetteColor );
+ m_xQSet3->SetFormat();
+ }
+ else if( m_xQSet4->GetSelectedItemId() == 1 )
+ {
+ m_xCbx4->set_active(true);
+ m_xData->CbxHdl(*m_xCbx4);
+ m_xQSet4->SetItemColor( 1, aPipetteColor );
+ m_xQSet4->SetFormat();
+ }
+
+ m_xTbxPipette->set_item_active("pipette", false);
+ m_xData->PipetteHdl("pipette");
+}
+
+void SvxBmpMask::SetExecState( bool bEnable )
+{
+ m_xData->SetExecState( bEnable );
+
+ if ( m_xData->IsExecReady() && m_xData->IsCbxReady() )
+ m_xBtnExec->set_sensitive(true);
+ else
+ m_xBtnExec->set_sensitive(false);
+}
+
+
+sal_uInt16 SvxBmpMask::InitColorArrays( Color* pSrcCols, Color* pDstCols, sal_uInt8* pTols )
+{
+ sal_uInt16 nCount = 0;
+
+ if ( m_xCbx1->get_active() )
+ {
+ pSrcCols[nCount] = m_xQSet1->GetItemColor( 1 );
+ pDstCols[nCount] = m_xLbColor1->GetSelectEntryColor();
+ pTols[nCount++] = static_cast<sal_uInt8>(m_xSp1->get_value(FieldUnit::PERCENT));
+ }
+
+ if ( m_xCbx2->get_active() )
+ {
+ pSrcCols[nCount] = m_xQSet2->GetItemColor( 1 );
+ pDstCols[nCount] = m_xLbColor2->GetSelectEntryColor();
+ pTols[nCount++] = static_cast<sal_uInt8>(m_xSp2->get_value(FieldUnit::PERCENT));
+ }
+
+ if ( m_xCbx3->get_active() )
+ {
+ pSrcCols[nCount] = m_xQSet3->GetItemColor( 1 );
+ pDstCols[nCount] = m_xLbColor3->GetSelectEntryColor();
+ pTols[nCount++] = static_cast<sal_uInt8>(m_xSp3->get_value(FieldUnit::PERCENT));
+ }
+
+ if ( m_xCbx4->get_active() )
+ {
+ pSrcCols[nCount] = m_xQSet4->GetItemColor( 1 );
+ pDstCols[nCount] = m_xLbColor4->GetSelectEntryColor();
+ pTols[nCount++] = static_cast<sal_uInt8>(m_xSp4->get_value(FieldUnit::PERCENT));
+ }
+
+ return nCount;
+}
+
+void SvxBmpMask::ImpMask( BitmapEx& rBitmap )
+{
+ Color pSrcCols[4];
+ Color pDstCols[4];
+ sal_uInt8 pTols[4];
+ const sal_uInt16 nCount = InitColorArrays( pSrcCols, pDstCols, pTols );
+
+ EnterWait();
+ rBitmap.Replace( pSrcCols, pDstCols, nCount, pTols );
+ LeaveWait();
+}
+
+BitmapEx SvxBmpMask::ImpMaskTransparent( const BitmapEx& rBitmapEx, const Color& rColor, const sal_uInt8 nTol )
+{
+ EnterWait();
+
+ BitmapEx aBmpEx;
+ AlphaMask aMask( rBitmapEx.GetBitmap().CreateAlphaMask( rColor, nTol ) );
+
+ if( rBitmapEx.IsAlpha() )
+ aMask.AlphaCombineOr( rBitmapEx.GetAlphaMask() );
+
+ aBmpEx = BitmapEx( rBitmapEx.GetBitmap(), aMask );
+ LeaveWait();
+
+ return aBmpEx;
+}
+
+
+Animation SvxBmpMask::ImpMask( const Animation& rAnimation )
+{
+ Animation aAnimation( rAnimation );
+ Color pSrcCols[4];
+ Color pDstCols[4];
+ sal_uInt8 pTols[4];
+ InitColorArrays( pSrcCols, pDstCols, pTols );
+ sal_uInt16 nAnimationCount = aAnimation.Count();
+
+ for( sal_uInt16 i = 0; i < nAnimationCount; i++ )
+ {
+ AnimationFrame aAnimationFrame( aAnimation.Get( i ) );
+ aAnimationFrame.maBitmapEx = Mask(aAnimationFrame.maBitmapEx).GetBitmapEx();
+ aAnimation.Replace(aAnimationFrame, i);
+ }
+
+ return aAnimation;
+}
+
+
+GDIMetaFile SvxBmpMask::ImpMask( const GDIMetaFile& rMtf )
+{
+ GDIMetaFile aMtf;
+ Color pSrcCols[4];
+ Color pDstCols[4];
+ sal_uInt8 pTols[4];
+ sal_uInt16 nCount = InitColorArrays( pSrcCols, pDstCols, pTols );
+
+ // If no color is selected, we copy only the Mtf
+ if( !nCount )
+ aMtf = rMtf;
+ else
+ {
+ bool pTrans[4];
+ Color aCol;
+ tools::Long nR;
+ tools::Long nG;
+ tools::Long nB;
+ std::unique_ptr<tools::Long[]> pMinR(new tools::Long[nCount]);
+ std::unique_ptr<tools::Long[]> pMaxR(new tools::Long[nCount]);
+ std::unique_ptr<tools::Long[]> pMinG(new tools::Long[nCount]);
+ std::unique_ptr<tools::Long[]> pMaxG(new tools::Long[nCount]);
+ std::unique_ptr<tools::Long[]> pMinB(new tools::Long[nCount]);
+ std::unique_ptr<tools::Long[]> pMaxB(new tools::Long[nCount]);
+ sal_uInt16 i;
+
+ aMtf.SetPrefSize( rMtf.GetPrefSize() );
+ aMtf.SetPrefMapMode( rMtf.GetPrefMapMode() );
+
+ // Prepare Color comparison array
+ for( i = 0; i < nCount; i++ )
+ {
+ tools::Long nTol = ( pTols[i] * 255 ) / 100;
+
+ tools::Long nVal = static_cast<tools::Long>(pSrcCols[i].GetRed());
+ pMinR[i] = std::max( nVal - nTol, tools::Long(0) );
+ pMaxR[i] = std::min( nVal + nTol, tools::Long(255) );
+
+ nVal = static_cast<tools::Long>(pSrcCols[i].GetGreen());
+ pMinG[i] = std::max( nVal - nTol, tools::Long(0) );
+ pMaxG[i] = std::min( nVal + nTol, tools::Long(255) );
+
+ nVal = static_cast<tools::Long>(pSrcCols[i].GetBlue());
+ pMinB[i] = std::max( nVal - nTol, tools::Long(0) );
+ pMaxB[i] = std::min( nVal + nTol, tools::Long(255) );
+
+ pTrans[ i ] = (pDstCols[ i ] == COL_TRANSPARENT);
+ }
+
+ // Investigate actions and if necessary replace colors
+ for( size_t nAct = 0, nActCount = rMtf.GetActionSize(); nAct < nActCount; nAct++ )
+ {
+ MetaAction* pAction = rMtf.GetAction( nAct );
+
+ bool bReplace = false;
+
+ switch( pAction->GetType() )
+ {
+ case MetaActionType::PIXEL:
+ {
+ MetaPixelAction* pAct = static_cast<MetaPixelAction*>(pAction);
+
+ aCol = pAct->GetColor();
+ TEST_COLS();
+
+ if( bReplace )
+ pAct = new MetaPixelAction( pAct->GetPoint(), aCol );
+
+ aMtf.AddAction( pAct );
+ }
+ break;
+
+ case MetaActionType::LINECOLOR:
+ {
+ MetaLineColorAction* pAct = static_cast<MetaLineColorAction*>(pAction);
+
+ aCol = pAct->GetColor();
+ TEST_COLS();
+
+ if( bReplace )
+ pAct = new MetaLineColorAction( aCol, !pTrans[ i ] );
+
+ aMtf.AddAction( pAct );
+ }
+ break;
+
+ case MetaActionType::FILLCOLOR:
+ {
+ MetaFillColorAction* pAct = static_cast<MetaFillColorAction*>(pAction);
+
+ aCol = pAct->GetColor();
+ TEST_COLS();
+
+ if( bReplace )
+ pAct = new MetaFillColorAction( aCol, !pTrans[ i ] );
+
+ aMtf.AddAction( pAct );
+ }
+ break;
+
+ case MetaActionType::TEXTCOLOR:
+ {
+ MetaTextColorAction* pAct = static_cast<MetaTextColorAction*>(pAction);
+
+ aCol = pAct->GetColor();
+ TEST_COLS();
+
+ if( bReplace )
+ pAct = new MetaTextColorAction( aCol );
+
+ aMtf.AddAction( pAct );
+ }
+ break;
+
+ case MetaActionType::TEXTFILLCOLOR:
+ {
+ MetaTextFillColorAction* pAct = static_cast<MetaTextFillColorAction*>(pAction);
+
+ aCol = pAct->GetColor();
+ TEST_COLS();
+
+ if( bReplace )
+ pAct = new MetaTextFillColorAction( aCol, !pTrans[ i ] );
+
+ aMtf.AddAction( pAct );
+ }
+ break;
+
+ case MetaActionType::FONT:
+ {
+ MetaFontAction* pAct = static_cast<MetaFontAction*>(pAction);
+ vcl::Font aFont( pAct->GetFont() );
+
+ aCol = aFont.GetColor();
+ TEST_COLS();
+
+ if( bReplace )
+ {
+ aFont.SetColor( aCol );
+ pAct = new MetaFontAction( std::move(aFont) );
+ }
+
+ aMtf.AddAction( pAct );
+ }
+ break;
+
+ case MetaActionType::WALLPAPER:
+ {
+ MetaWallpaperAction* pAct = static_cast<MetaWallpaperAction*>(pAction);
+ Wallpaper aWall( pAct->GetWallpaper() );
+
+ aCol = aWall.GetColor();
+ TEST_COLS();
+
+ if( bReplace )
+ {
+ aWall.SetColor( aCol );
+ pAct = new MetaWallpaperAction( pAct->GetRect(), std::move(aWall) );
+ }
+
+ aMtf.AddAction( pAct );
+ }
+ break;
+
+ case MetaActionType::BMP:
+ {
+ MetaBmpAction* pAct = static_cast<MetaBmpAction*>(pAction);
+ const Bitmap aBmp( Mask(BitmapEx(pAct->GetBitmap())).GetBitmapEx().GetBitmap() );
+
+ pAct = new MetaBmpAction( pAct->GetPoint(), aBmp );
+ aMtf.AddAction( pAct );
+ }
+ break;
+
+ case MetaActionType::BMPSCALE:
+ {
+ MetaBmpScaleAction* pAct = static_cast<MetaBmpScaleAction*>(pAction);
+ const Bitmap aBmp( Mask(BitmapEx(pAct->GetBitmap())).GetBitmapEx().GetBitmap() );
+
+ pAct = new MetaBmpScaleAction( pAct->GetPoint(), pAct->GetSize(), aBmp );
+ aMtf.AddAction( pAct );
+ }
+ break;
+
+ case MetaActionType::BMPSCALEPART:
+ {
+ MetaBmpScalePartAction* pAct = static_cast<MetaBmpScalePartAction*>(pAction);
+ const Bitmap aBmp( Mask(BitmapEx(pAct->GetBitmap())).GetBitmapEx().GetBitmap() );
+
+ pAct = new MetaBmpScalePartAction( pAct->GetDestPoint(), pAct->GetDestSize(),
+ pAct->GetSrcPoint(), pAct->GetSrcSize(), aBmp );
+ aMtf.AddAction( pAct );
+ }
+ break;
+
+ case MetaActionType::BMPEX:
+ {
+ MetaBmpExAction* pAct = static_cast<MetaBmpExAction*>(pAction);
+ const BitmapEx aBmpEx( Mask( pAct->GetBitmapEx() ).GetBitmapEx() );
+
+ pAct = new MetaBmpExAction( pAct->GetPoint(), aBmpEx );
+ aMtf.AddAction( pAct );
+ }
+ break;
+
+ case MetaActionType::BMPEXSCALE:
+ {
+ MetaBmpExScaleAction* pAct = static_cast<MetaBmpExScaleAction*>(pAction);
+ const BitmapEx aBmpEx( Mask( pAct->GetBitmapEx() ).GetBitmapEx() );
+
+ pAct = new MetaBmpExScaleAction( pAct->GetPoint(), pAct->GetSize(), aBmpEx );
+ aMtf.AddAction( pAct );
+ }
+ break;
+
+ case MetaActionType::BMPEXSCALEPART:
+ {
+ MetaBmpExScalePartAction* pAct = static_cast<MetaBmpExScalePartAction*>(pAction);
+ const BitmapEx aBmpEx( Mask( pAct->GetBitmapEx() ).GetBitmapEx() );
+
+ pAct = new MetaBmpExScalePartAction( pAct->GetDestPoint(), pAct->GetDestSize(),
+ pAct->GetSrcPoint(), pAct->GetSrcSize(), aBmpEx );
+ aMtf.AddAction( pAct );
+ }
+ break;
+
+ default:
+ {
+ aMtf.AddAction( pAction );
+ }
+ break;
+ }
+ }
+ }
+
+ LeaveWait();
+
+ return aMtf;
+}
+
+
+Animation SvxBmpMask::ImpReplaceTransparency( const Animation& rAnim, const Color& rColor )
+{
+ Animation aAnimation( rAnim );
+ sal_uInt16 nAnimationCount = aAnimation.Count();
+
+ for( sal_uInt16 i = 0; i < nAnimationCount; i++ )
+ {
+ AnimationFrame aAnimationFrame(aAnimation.Get(i));
+ aAnimationFrame.maBitmapEx.ReplaceTransparency(rColor);
+ aAnimation.Replace(aAnimationFrame, i);
+ }
+
+ return aAnimation;
+}
+
+
+GDIMetaFile SvxBmpMask::ImpReplaceTransparency( const GDIMetaFile& rMtf, const Color& rColor )
+{
+ ScopedVclPtrInstance< VirtualDevice > pVDev;
+ GDIMetaFile aMtf;
+ const MapMode& rPrefMap = rMtf.GetPrefMapMode();
+ const Size& rPrefSize = rMtf.GetPrefSize();
+ const size_t nActionCount = rMtf.GetActionSize();
+
+ pVDev->EnableOutput( false );
+ aMtf.Record( pVDev );
+ aMtf.SetPrefSize( rPrefSize );
+ aMtf.SetPrefMapMode( rPrefMap );
+ pVDev->SetLineColor( rColor );
+ pVDev->SetFillColor( rColor );
+
+ // retrieve one action at the time; first
+ // set the whole area to the replacement color.
+ pVDev->DrawRect( tools::Rectangle( rPrefMap.GetOrigin(), rPrefSize ) );
+ for ( size_t i = 0; i < nActionCount; i++ )
+ {
+ MetaAction* pAct = rMtf.GetAction( i );
+ aMtf.AddAction( pAct );
+ }
+
+ aMtf.Stop();
+ aMtf.WindStart();
+
+ return aMtf;
+}
+
+GDIMetaFile SvxBmpMask::GetMetaFile(const Graphic& rGraphic)
+{
+ // Replace transparency?
+ if (m_xCbxTrans->get_active())
+ return ImpReplaceTransparency(rGraphic.GetGDIMetaFile(), m_xLbColorTrans->GetSelectEntryColor());
+ return ImpMask(rGraphic.GetGDIMetaFile());
+}
+
+Graphic SvxBmpMask::Mask( const Graphic& rGraphic )
+{
+ Graphic aGraphic( rGraphic );
+ const Color aReplColor( m_xLbColorTrans->GetSelectEntryColor() );
+
+ switch( rGraphic.GetType() )
+ {
+ case GraphicType::Bitmap:
+ {
+ if( rGraphic.IsAnimated() )
+ {
+ // Replace transparency?
+ if ( m_xCbxTrans->get_active() )
+ aGraphic = ImpReplaceTransparency( rGraphic.GetAnimation(), aReplColor );
+ else
+ aGraphic = ImpMask( rGraphic.GetAnimation() );
+ }
+ else
+ {
+ // Replace transparency?
+ if( m_xCbxTrans->get_active() )
+ {
+ BitmapEx aBmpEx = aGraphic.GetBitmapEx();
+ aBmpEx.ReplaceTransparency(aReplColor);
+ aGraphic = aBmpEx;
+ }
+ else
+ {
+ Color pSrcCols[4];
+ Color pDstCols[4];
+ sal_uInt8 pTols[4];
+ sal_uInt16 nCount = InitColorArrays( pSrcCols, pDstCols, pTols );
+
+ if( nCount )
+ {
+ // first set all transparent colors
+ for( sal_uInt16 i = 0; i < nCount; i++ )
+ {
+ // Do we have a transparent color?
+ if (pDstCols[i] == COL_TRANSPARENT)
+ {
+ BitmapEx aBmpEx( ImpMaskTransparent( aGraphic.GetBitmapEx(),
+ pSrcCols[ i ], pTols[ i ] ) );
+ const Size aSize( aBmpEx.GetSizePixel() );
+
+ if( aSize.Width() && aSize.Height() )
+ aGraphic = aBmpEx;
+ }
+ }
+
+ // now replace it again with the normal colors
+ BitmapEx aBitmapEx( aGraphic.GetBitmapEx() );
+ if ( aBitmapEx.GetSizePixel().Width() && aBitmapEx.GetSizePixel().Height() )
+ {
+ ImpMask( aBitmapEx );
+ aGraphic = Graphic( aBitmapEx );
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case GraphicType::GdiMetafile:
+ {
+ GDIMetaFile aMtf(GetMetaFile(rGraphic));
+ Size aSize( aMtf.GetPrefSize() );
+ if ( aSize.Width() && aSize.Height() )
+ aGraphic = Graphic( aMtf );
+ else
+ aGraphic = rGraphic;
+ }
+ break;
+
+ default:
+ aGraphic = rGraphic;
+ break;
+ }
+
+ if( aGraphic != rGraphic )
+ {
+ aGraphic.SetPrefSize( rGraphic.GetPrefSize() );
+ aGraphic.SetPrefMapMode( rGraphic.GetPrefMapMode() );
+ }
+
+ return aGraphic;
+}
+
+bool SvxBmpMask::IsEyedropping() const
+{
+ return m_xTbxPipette->get_item_active("pipette");
+}
+
+/** Set an accessible name for the source color check boxes. Without this
+ the lengthy description is read.
+*/
+void SvxBmpMask::SetAccessibleNames()
+{
+ // set the accessible name for valueset
+ OUString sColorPalette (SvxResId( RID_SVXDLG_BMPMASK_STR_PALETTE));
+ OUString sColorPaletteN;
+
+ sColorPaletteN = sColorPalette + " 1";
+ m_xQSet1->SetText (sColorPaletteN);
+ sColorPaletteN = sColorPalette + " 2";
+ m_xQSet2->SetText (sColorPaletteN);
+ sColorPaletteN = sColorPalette + " 3";
+ m_xQSet3->SetText (sColorPaletteN);
+ sColorPaletteN = sColorPalette + " 4";
+ m_xQSet4->SetText (sColorPaletteN);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/_contdlg.cxx b/svx/source/dialog/_contdlg.cxx
new file mode 100644
index 0000000000..da70779569
--- /dev/null
+++ b/svx/source/dialog/_contdlg.cxx
@@ -0,0 +1,675 @@
+/* -*- 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 <tools/helpers.hxx>
+#include <svl/eitem.hxx>
+#include <sfx2/ctrlitem.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/module.hxx>
+#include <unotools/localedatawrapper.hxx>
+
+#include <svx/svxids.hrc>
+#include <svx/contdlg.hxx>
+#include "contimp.hxx"
+#include "contwnd.hxx"
+#include <svx/svdopath.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/virdev.hxx>
+#include "dlgunit.hxx"
+#include <vcl/weld.hxx>
+
+SFX_IMPL_MODELESSDIALOGCONTOLLER_WITHID(SvxContourDlgChildWindow, SID_CONTOUR_DLG);
+
+SvxContourDlgItem::SvxContourDlgItem( SvxSuperContourDlg& rContourDlg, SfxBindings& rBindings ) :
+ SfxControllerItem ( SID_CONTOUR_EXEC, rBindings ),
+ rDlg ( rContourDlg )
+{
+}
+
+void SvxContourDlgItem::StateChangedAtToolBoxControl( sal_uInt16 nSID, SfxItemState /*eState*/, const SfxPoolItem* pItem )
+{
+ if ( pItem && ( SID_CONTOUR_EXEC == nSID ) )
+ {
+ const SfxBoolItem* pStateItem = dynamic_cast<const SfxBoolItem*>( pItem );
+ assert(pStateItem); //SfxBoolItem expected
+ if (pStateItem)
+ rDlg.SetExecState(!pStateItem->GetValue());
+ }
+}
+
+SvxContourDlgChildWindow::SvxContourDlgChildWindow(vcl::Window* _pParent, sal_uInt16 nId,
+ SfxBindings* pBindings, SfxChildWinInfo const * pInfo)
+ : SfxChildWindow( _pParent, nId )
+{
+ SetController(std::make_shared<SvxContourDlg>(pBindings, this, _pParent->GetFrameWeld()));
+ SvxContourDlg* pDlg = static_cast<SvxContourDlg*>(GetController().get());
+ pDlg->Initialize( pInfo );
+}
+
+SvxContourDlg::SvxContourDlg(SfxBindings* _pBindings, SfxChildWindow* pCW,
+ weld::Window* _pParent)
+ : SfxModelessDialogController(_pBindings, pCW, _pParent, "svx/ui/floatingcontour.ui", "FloatingContour")
+ , m_xImpl(std::make_unique<SvxSuperContourDlg>(*m_xBuilder, *m_xDialog, _pBindings))
+{
+}
+
+SvxContourDlg::~SvxContourDlg()
+{
+}
+
+tools::PolyPolygon SvxContourDlg::CreateAutoContour( const Graphic& rGraphic,
+ const tools::Rectangle* pRect )
+{
+ Bitmap aBmp;
+ bool bContourEdgeDetect = false;
+
+ if ( rGraphic.GetType() == GraphicType::Bitmap )
+ {
+ if( rGraphic.IsAnimated() )
+ {
+ ScopedVclPtrInstance< VirtualDevice > pVDev;
+ MapMode aTransMap;
+ const Animation aAnim( rGraphic.GetAnimation() );
+ const Size& rSizePix = aAnim.GetDisplaySizePixel();
+ const sal_uInt16 nCount = aAnim.Count();
+
+ if ( pVDev->SetOutputSizePixel( rSizePix ) )
+ {
+ pVDev->SetLineColor( COL_BLACK );
+ pVDev->SetFillColor( COL_BLACK );
+
+ for( sal_uInt16 i = 0; i < nCount; i++ )
+ {
+ const AnimationFrame& rStepBmp = aAnim.Get( i );
+
+ // Push Polygon output to the right place; this is the
+ // offset of the sub-image within the total animation
+ aTransMap.SetOrigin( Point( rStepBmp.maPositionPixel.X(), rStepBmp.maPositionPixel.Y() ) );
+ pVDev->SetMapMode( aTransMap );
+ pVDev->DrawPolyPolygon( CreateAutoContour( rStepBmp.maBitmapEx, pRect ) );
+ }
+
+ aTransMap.SetOrigin( Point() );
+ pVDev->SetMapMode( aTransMap );
+ aBmp = pVDev->GetBitmap( Point(), rSizePix );
+ aBmp.Convert( BmpConversion::N1BitThreshold );
+ }
+ }
+ else if( rGraphic.IsTransparent() )
+ aBmp = rGraphic.GetBitmapEx().GetAlphaMask().GetBitmap();
+ else
+ {
+ aBmp = rGraphic.GetBitmapEx().GetBitmap();
+ bContourEdgeDetect = true;
+ }
+ }
+ else if( rGraphic.GetType() != GraphicType::NONE )
+ {
+ const Graphic aTmpGrf( rGraphic.GetGDIMetaFile().GetMonochromeMtf( COL_BLACK ) );
+ ScopedVclPtrInstance< VirtualDevice > pVDev;
+ Size aSizePix( pVDev->LogicToPixel( aTmpGrf.GetPrefSize(), aTmpGrf.GetPrefMapMode() ) );
+
+ if( aSizePix.Width() && aSizePix.Height() && ( aSizePix.Width() > 512 || aSizePix.Height() > 512 ) )
+ {
+ double fWH = static_cast<double>(aSizePix.Width()) / aSizePix.Height();
+
+ if( fWH <= 1.0 )
+ {
+ aSizePix.setHeight(512);
+ aSizePix.setWidth( FRound( ( aSizePix.Height() ) * fWH ) );
+ }
+ else
+ {
+ aSizePix.setWidth(512);
+ aSizePix.setHeight( FRound( ( aSizePix.Width() ) / fWH ) );
+ }
+ }
+
+ if( pVDev->SetOutputSizePixel( aSizePix ) )
+ {
+ const Point aPt;
+ aTmpGrf.Draw(*pVDev, aPt, aSizePix);
+ aBmp = pVDev->GetBitmap( aPt, aSizePix );
+ }
+
+ bContourEdgeDetect = true;
+ }
+
+ aBmp.SetPrefSize( rGraphic.GetPrefSize() );
+ aBmp.SetPrefMapMode( rGraphic.GetPrefMapMode() );
+
+ return tools::PolyPolygon( BitmapEx(aBmp).GetContour( bContourEdgeDetect, pRect ) );
+}
+
+// Loop through to super class, no virtual Methods to not become incompatible
+// due to IF changes
+
+const Graphic& SvxContourDlg::GetGraphic() const
+{
+ return m_xImpl->GetGraphic();
+}
+
+bool SvxContourDlg::IsGraphicChanged() const
+{
+ return m_xImpl->IsGraphicChanged();
+}
+
+tools::PolyPolygon SvxContourDlg::GetPolyPolygon()
+{
+ return m_xImpl->GetPolyPolygon();
+}
+
+const void* SvxContourDlg::GetEditingObject() const
+{
+ return m_xImpl->GetEditingObject();
+}
+
+void SvxContourDlg::Update( const Graphic& rGraphic, bool bGraphicLinked,
+ const tools::PolyPolygon* pPolyPoly, void* pEditingObj )
+{
+ m_xImpl->UpdateGraphic( rGraphic, bGraphicLinked, pPolyPoly, pEditingObj );
+}
+
+SvxSuperContourDlg::SvxSuperContourDlg(weld::Builder& rBuilder,
+ weld::Dialog& rDialog, SfxBindings* pBindings)
+ : aUpdateIdle( "SvxSuperContourDlg UpdateIdle" )
+ , aCreateIdle( "SvxSuperContourDlg CreateIdle" )
+ , mpBindings(pBindings)
+ , pUpdateEditingObject( nullptr )
+ , pCheckObj( nullptr )
+ , aContourItem( *this, *pBindings )
+ , mnGrfChanged( 0 )
+ , bExecState( false )
+ , bUpdateGraphicLinked( false )
+ , bGraphicLinked( false )
+ , m_rDialog(rDialog)
+ , m_xContourWnd(new ContourWindow(&rDialog))
+ , m_xStbStatusColor(new StatusColor(*m_xContourWnd))
+ , m_xTbx1(rBuilder.weld_toolbar("toolbar"))
+ , m_xMtfTolerance(rBuilder.weld_metric_spin_button("spinbutton", FieldUnit::PERCENT))
+ , m_xStbStatus2(rBuilder.weld_label("statuspos"))
+ , m_xStbStatus3(rBuilder.weld_label("statussize"))
+ , m_xCancelBtn(rBuilder.weld_button("cancel"))
+ , m_xStbStatusColorWeld(new weld::CustomWeld(rBuilder, "statuscolor", *m_xStbStatusColor))
+ , m_xContourWndWeld(new weld::CustomWeld(rBuilder, "container", *m_xContourWnd))
+{
+ m_xCancelBtn->connect_clicked(LINK(this, SvxSuperContourDlg, CancelHdl));
+
+ m_xContourWnd->SetMousePosLink( LINK( this, SvxSuperContourDlg, MousePosHdl ) );
+ m_xContourWnd->SetGraphSizeLink( LINK( this, SvxSuperContourDlg, GraphSizeHdl ) );
+ m_xContourWnd->SetUpdateLink( LINK( this, SvxSuperContourDlg, StateHdl ) );
+ m_xContourWnd->SetPipetteHdl( LINK( this, SvxSuperContourDlg, PipetteHdl ) );
+ m_xContourWnd->SetPipetteClickHdl( LINK( this, SvxSuperContourDlg, PipetteClickHdl ) );
+ m_xContourWnd->SetWorkplaceClickHdl( LINK( this, SvxSuperContourDlg, WorkplaceClickHdl ) );
+
+ m_xTbx1->connect_clicked( LINK( this, SvxSuperContourDlg, Tbx1ClickHdl ) );
+
+ m_xMtfTolerance->set_value(10, FieldUnit::PERCENT);
+
+ aUpdateIdle.SetInvokeHandler( LINK( this, SvxSuperContourDlg, UpdateHdl ) );
+
+ aCreateIdle.SetPriority( TaskPriority::RESIZE );
+ aCreateIdle.SetInvokeHandler( LINK( this, SvxSuperContourDlg, CreateHdl ) );
+}
+
+SvxSuperContourDlg::~SvxSuperContourDlg()
+{
+ m_xContourWnd->SetUpdateLink( Link<GraphCtrl*,void>() );
+ m_xContourWnd.reset();
+}
+
+IMPL_LINK_NOARG(SvxSuperContourDlg, CancelHdl, weld::Button&, void)
+{
+ bool bRet = true;
+
+ if (m_xTbx1->get_item_sensitive("TBI_APPLY"))
+ {
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(&m_rDialog, "svx/ui/querysavecontchangesdialog.ui"));
+ std::unique_ptr<weld::MessageDialog> xQBox(xBuilder->weld_message_dialog("QuerySaveContourChangesDialog"));
+ const short nRet = xQBox->run();
+
+ if ( nRet == RET_YES )
+ {
+ SfxBoolItem aBoolItem( SID_CONTOUR_EXEC, true );
+ GetBindings().GetDispatcher()->ExecuteList(
+ SID_CONTOUR_EXEC, SfxCallMode::SYNCHRON | SfxCallMode::RECORD,
+ { &aBoolItem });
+ }
+ else if ( nRet == RET_CANCEL )
+ bRet = false;
+ }
+
+ if (bRet)
+ m_rDialog.response(RET_CANCEL);
+}
+
+// Enabled or disabled all Controls
+
+void SvxSuperContourDlg::SetExecState( bool bEnable )
+{
+ bExecState = bEnable;
+}
+
+void SvxSuperContourDlg::SetGraphic( const Graphic& rGraphic )
+{
+ aUndoGraphic = aRedoGraphic = Graphic();
+ aGraphic = rGraphic;
+ mnGrfChanged = 0;
+ m_xContourWnd->SetGraphic( aGraphic );
+}
+
+void SvxSuperContourDlg::SetPolyPolygon( const tools::PolyPolygon& rPolyPoly )
+{
+ DBG_ASSERT( m_xContourWnd->GetGraphic().GetType() != GraphicType::NONE, "Graphic must've been set first!" );
+
+ tools::PolyPolygon aPolyPoly( rPolyPoly );
+ const MapMode aMap100( MapUnit::Map100thMM );
+ const MapMode aGrfMap( aGraphic.GetPrefMapMode() );
+ OutputDevice* pOutDev = Application::GetDefaultDevice();
+ bool bPixelMap = aGrfMap.GetMapUnit() == MapUnit::MapPixel;
+
+ for ( sal_uInt16 j = 0, nPolyCount = aPolyPoly.Count(); j < nPolyCount; j++ )
+ {
+ tools::Polygon& rPoly = aPolyPoly[ j ];
+
+ for ( sal_uInt16 i = 0, nCount = rPoly.GetSize(); i < nCount; i++ )
+ {
+ Point& rPt = rPoly[ i ];
+
+ if ( !bPixelMap )
+ rPt = pOutDev->LogicToPixel( rPt, aGrfMap );
+
+ rPt = pOutDev->PixelToLogic( rPt, aMap100 );
+ }
+ }
+
+ m_xContourWnd->SetPolyPolygon( aPolyPoly );
+ m_xContourWnd->GetSdrModel()->SetChanged();
+}
+
+tools::PolyPolygon SvxSuperContourDlg::GetPolyPolygon()
+{
+ tools::PolyPolygon aRetPolyPoly( m_xContourWnd->GetPolyPolygon() );
+
+ const MapMode aMap100( MapUnit::Map100thMM );
+ const MapMode aGrfMap( aGraphic.GetPrefMapMode() );
+ OutputDevice* pOutDev = Application::GetDefaultDevice();
+ bool bPixelMap = aGrfMap.GetMapUnit() == MapUnit::MapPixel;
+
+ for ( sal_uInt16 j = 0, nPolyCount = aRetPolyPoly.Count(); j < nPolyCount; j++ )
+ {
+ tools::Polygon& rPoly = aRetPolyPoly[ j ];
+
+ for ( sal_uInt16 i = 0, nCount = rPoly.GetSize(); i < nCount; i++ )
+ {
+ Point& rPt = rPoly[ i ];
+
+ rPt = pOutDev->LogicToPixel( rPt, aMap100 );
+
+ if ( !bPixelMap )
+ rPt = pOutDev->PixelToLogic( rPt, aGrfMap );
+ }
+ }
+
+ return aRetPolyPoly;
+}
+
+void SvxSuperContourDlg::UpdateGraphic( const Graphic& rGraphic, bool _bGraphicLinked,
+ const tools::PolyPolygon* pPolyPoly, void* pEditingObj )
+{
+ aUpdateGraphic = rGraphic;
+ bUpdateGraphicLinked = _bGraphicLinked;
+ pUpdateEditingObject = pEditingObj;
+
+ if ( pPolyPoly )
+ aUpdatePolyPoly = *pPolyPoly;
+ else
+ aUpdatePolyPoly = tools::PolyPolygon();
+
+ aUpdateIdle.Start();
+}
+
+// Click handler for ToolBox
+
+IMPL_LINK(SvxSuperContourDlg, Tbx1ClickHdl, const OUString&, rId, void)
+{
+ if (rId == "TBI_APPLY")
+ {
+ SfxBoolItem aBoolItem( SID_CONTOUR_EXEC, true );
+ GetBindings().GetDispatcher()->ExecuteList(
+ SID_CONTOUR_EXEC, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
+ { &aBoolItem });
+ }
+ else if (rId == "TBI_WORKPLACE")
+ {
+ if (m_xTbx1->get_item_active("TBI_WORKPLACE"))
+ {
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(&m_rDialog, "svx/ui/querydeletecontourdialog.ui"));
+ std::unique_ptr<weld::MessageDialog> xQBox(xBuilder->weld_message_dialog("QueryDeleteContourDialog"));
+
+ if (!m_xContourWnd->IsContourChanged() || (xQBox->run() == RET_YES))
+ m_xContourWnd->SetWorkplaceMode( true );
+ else
+ m_xTbx1->set_item_active("TBI_WORKPLACE", false);
+ }
+ else
+ m_xContourWnd->SetWorkplaceMode( false );
+ }
+ else if (rId == "TBI_SELECT")
+ {
+ SetActiveTool(rId);
+ m_xContourWnd->SetEditMode( true );
+ }
+ else if (rId == "TBI_RECT")
+ {
+ SetActiveTool(rId);
+ m_xContourWnd->SetObjKind( SdrObjKind::Rectangle );
+ }
+ else if (rId == "TBI_CIRCLE")
+ {
+ SetActiveTool(rId);
+ m_xContourWnd->SetObjKind( SdrObjKind::CircleOrEllipse );
+ }
+ else if (rId == "TBI_POLY")
+ {
+ SetActiveTool(rId);
+ m_xContourWnd->SetObjKind( SdrObjKind::Polygon );
+ }
+ else if (rId == "TBI_POLYEDIT")
+ {
+ m_xContourWnd->SetPolyEditMode(m_xTbx1->get_item_active("TBI_POLYEDIT") ? SID_BEZIER_MOVE : 0);
+ }
+ else if (rId == "TBI_POLYMOVE")
+ {
+ SetActivePoly(rId);
+ m_xContourWnd->SetPolyEditMode( SID_BEZIER_MOVE );
+ }
+ else if (rId == "TBI_POLYINSERT")
+ {
+ SetActivePoly(rId);
+ m_xContourWnd->SetPolyEditMode( SID_BEZIER_INSERT );
+ }
+ else if (rId == "TBI_POLYDELETE")
+ {
+ m_xContourWnd->GetSdrView()->DeleteMarkedPoints();
+ }
+ else if (rId == "TBI_UNDO")
+ {
+ mnGrfChanged = mnGrfChanged ? mnGrfChanged - 1 : 0;
+ aRedoGraphic = aGraphic;
+ aGraphic = aUndoGraphic;
+ aUndoGraphic = Graphic();
+ m_xContourWnd->SetGraphic( aGraphic, false );
+ }
+ else if (rId == "TBI_REDO")
+ {
+ mnGrfChanged++;
+ aUndoGraphic = aGraphic;
+ aGraphic = aRedoGraphic;
+ aRedoGraphic = Graphic();
+ m_xContourWnd->SetGraphic( aGraphic, false );
+ }
+ else if (rId == "TBI_AUTOCONTOUR")
+ {
+ aCreateIdle.Start();
+ }
+ else if (rId == "TBI_PIPETTE")
+ {
+ bool bPipette = m_xTbx1->get_item_active("TBI_PIPETTE");
+
+ if ( !bPipette )
+ m_xStbStatusColor->Invalidate();
+ else if ( bGraphicLinked )
+ {
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(&m_rDialog, "svx/ui/queryunlinkgraphicsdialog.ui"));
+ std::unique_ptr<weld::MessageDialog> xQBox(xBuilder->weld_message_dialog("QueryUnlinkGraphicsDialog"));
+
+ if (xQBox->run() != RET_YES)
+ {
+ bPipette = false;
+ m_xTbx1->set_item_active("TBI_PIPETTE", bPipette);
+ m_xStbStatusColor->Invalidate();
+ }
+ }
+
+ m_xContourWnd->SetPipetteMode( bPipette );
+ }
+ m_xContourWnd->QueueIdleUpdate();
+}
+
+void SvxSuperContourDlg::SetActiveTool(std::u16string_view rId)
+{
+ m_xTbx1->set_item_active("TBI_SELECT", rId == u"TBI_SELECT");
+ m_xTbx1->set_item_active("TBI_RECT", rId == u"TBI_RECT");
+ m_xTbx1->set_item_active("TBI_CIRCLE", rId == u"TBI_CIRCLE");
+ m_xTbx1->set_item_active("TBI_POLY", rId == u"TBI_POLY");
+}
+
+void SvxSuperContourDlg::SetActivePoly(std::u16string_view rId)
+{
+ m_xTbx1->set_item_active("TBI_POLYMOVE", rId == u"TBI_POLYMOVE");
+ m_xTbx1->set_item_active("TBI_POLYINSERT", rId == u"TBI_POLYINSERT");
+}
+
+IMPL_LINK( SvxSuperContourDlg, MousePosHdl, GraphCtrl*, pWnd, void )
+{
+ OUString aStr;
+ const FieldUnit eFieldUnit = GetBindings().GetDispatcher()->GetModule()->GetFieldUnit();
+ const Point& rMousePos = pWnd->GetMousePos();
+ const LocaleDataWrapper& rLocaleWrapper( Application::GetSettings().GetLocaleDataWrapper() );
+ const sal_Unicode cSep = rLocaleWrapper.getNumDecimalSep()[0];
+
+ aStr = GetUnitString( rMousePos.X(), eFieldUnit, cSep )
+ + " / "
+ + GetUnitString( rMousePos.Y(), eFieldUnit, cSep );
+
+ m_xStbStatus2->set_label( aStr );
+}
+
+IMPL_LINK( SvxSuperContourDlg, GraphSizeHdl, GraphCtrl*, pWnd, void )
+{
+ OUString aStr;
+ const FieldUnit eFieldUnit = GetBindings().GetDispatcher()->GetModule()->GetFieldUnit();
+ const Size& rSize = pWnd->GetGraphicSize();
+ const LocaleDataWrapper& rLocaleWrapper( Application::GetSettings().GetLocaleDataWrapper() );
+ const sal_Unicode cSep = rLocaleWrapper.getNumDecimalSep()[0];
+
+ aStr = GetUnitString( rSize.Width(), eFieldUnit, cSep )
+ + " x "
+ + GetUnitString( rSize.Height(), eFieldUnit, cSep );
+
+ m_xStbStatus3->set_label( aStr );
+}
+
+IMPL_LINK_NOARG(SvxSuperContourDlg, UpdateHdl, Timer *, void)
+{
+ aUpdateIdle.Stop();
+
+ if ( pUpdateEditingObject != pCheckObj )
+ {
+ if( !GetEditingObject() )
+ m_xContourWnd->GrabFocus();
+
+ SetGraphic( aUpdateGraphic );
+ SetPolyPolygon( aUpdatePolyPoly );
+ pCheckObj = pUpdateEditingObject;
+ bGraphicLinked = bUpdateGraphicLinked;
+
+ aUpdateGraphic = Graphic();
+ aUpdatePolyPoly = tools::PolyPolygon();
+ bUpdateGraphicLinked = false;
+
+ m_xContourWnd->GetSdrModel()->SetChanged( false );
+ }
+
+ GetBindings().Invalidate( SID_CONTOUR_EXEC );
+ m_xContourWnd->QueueIdleUpdate();
+}
+
+IMPL_LINK_NOARG(SvxSuperContourDlg, CreateHdl, Timer *, void)
+{
+ aCreateIdle.Stop();
+
+ const tools::Rectangle aWorkRect = m_xContourWnd->GetDrawingArea()->get_ref_device().LogicToPixel(
+ m_xContourWnd->GetWorkRect(), MapMode( MapUnit::Map100thMM));
+
+ const Graphic& rGraphic = m_xContourWnd->GetGraphic();
+ const bool bValid = aWorkRect.Left() != aWorkRect.Right() && aWorkRect.Top() != aWorkRect.Bottom();
+
+ weld::WaitObject aWaitObj(&m_rDialog);
+ SetPolyPolygon( SvxContourDlg::CreateAutoContour( rGraphic, bValid ? &aWorkRect : nullptr ) );
+}
+
+IMPL_LINK( SvxSuperContourDlg, StateHdl, GraphCtrl*, pWnd, void )
+{
+ const SdrObject* pObj = pWnd->GetSelectedSdrObject();
+ const SdrView* pView = pWnd->GetSdrView();
+ const bool bPolyEdit = ( pObj != nullptr ) && dynamic_cast<const SdrPathObj*>( pObj) != nullptr;
+ const bool bDrawEnabled = !(bPolyEdit && m_xTbx1->get_item_active("TBI_POLYEDIT"));
+ const bool bPipette = m_xTbx1->get_item_active("TBI_PIPETTE");
+ const bool bWorkplace = m_xTbx1->get_item_active("TBI_WORKPLACE");
+ const bool bDontHide = !( bPipette || bWorkplace );
+ const bool bBitmap = pWnd->GetGraphic().GetType() == GraphicType::Bitmap;
+
+ m_xTbx1->set_item_sensitive("TBI_APPLY", bDontHide && bExecState && pWnd->IsChanged());
+
+ m_xTbx1->set_item_sensitive("TBI_WORKPLACE", !bPipette && bDrawEnabled);
+
+ m_xTbx1->set_item_sensitive("TBI_SELECT", bDontHide && bDrawEnabled);
+ m_xTbx1->set_item_sensitive("TBI_RECT", bDontHide && bDrawEnabled);
+ m_xTbx1->set_item_sensitive("TBI_CIRCLE", bDontHide && bDrawEnabled);
+ m_xTbx1->set_item_sensitive("TBI_POLY", bDontHide && bDrawEnabled);
+
+ m_xTbx1->set_item_sensitive("TBI_POLYEDIT", bDontHide && bPolyEdit);
+ m_xTbx1->set_item_sensitive("TBI_POLYMOVE", bDontHide && !bDrawEnabled);
+ m_xTbx1->set_item_sensitive("TBI_POLYINSERT", bDontHide && !bDrawEnabled);
+ m_xTbx1->set_item_sensitive("TBI_POLYDELETE", bDontHide && !bDrawEnabled && pView->IsDeleteMarkedPointsPossible());
+
+ m_xTbx1->set_item_sensitive("TBI_AUTOCONTOUR", bDontHide && bDrawEnabled);
+ m_xTbx1->set_item_sensitive("TBI_PIPETTE", !bWorkplace && bDrawEnabled && bBitmap);
+
+ m_xTbx1->set_item_sensitive("TBI_UNDO", bDontHide && aUndoGraphic.GetType() != GraphicType::NONE);
+ m_xTbx1->set_item_sensitive("TBI_REDO", bDontHide && aRedoGraphic.GetType() != GraphicType::NONE);
+
+ if ( bPolyEdit )
+ {
+ switch( pWnd->GetPolyEditMode() )
+ {
+ case SID_BEZIER_MOVE:
+ SetActivePoly(u"TBI_POLYMOVE");
+ break;
+ case SID_BEZIER_INSERT:
+ SetActivePoly(u"TBI_POLYINSERT");
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ m_xTbx1->set_item_active("TBI_POLYEDIT", false);
+ SetActivePoly(u"TBI_POLYMOVE");
+ pWnd->SetPolyEditMode( 0 );
+ }
+}
+
+IMPL_LINK_NOARG(SvxSuperContourDlg, PipetteHdl, ContourWindow&, void)
+{
+ m_xStbStatusColor->Invalidate();
+}
+
+void StatusColor::Paint(vcl::RenderContext& rDevice, const tools::Rectangle&)
+{
+ const Color& rOldLineColor = rDevice.GetLineColor();
+ const Color& rOldFillColor = rDevice.GetFillColor();
+
+ tools::Rectangle aRect(Point(), GetOutputSizePixel());
+ const Color& rColor = m_rWnd.GetPipetteColor();
+
+ rDevice.SetLineColor(rColor);
+ rDevice.SetFillColor(rColor);
+
+ aRect.AdjustLeft(4 );
+ aRect.AdjustTop(4 );
+ aRect.AdjustRight( -4 );
+ aRect.AdjustBottom( -4 );
+
+ rDevice.DrawRect( aRect );
+
+ rDevice.SetLineColor(rOldLineColor);
+ rDevice.SetFillColor(rOldFillColor);
+}
+
+IMPL_LINK( SvxSuperContourDlg, PipetteClickHdl, ContourWindow&, rWnd, void )
+{
+ if ( rWnd.IsClickValid() )
+ {
+ const Color& rColor = rWnd.GetPipetteColor();
+
+ weld::WaitObject aWaitObj(&m_rDialog);
+
+ if( aGraphic.GetType() == GraphicType::Bitmap )
+ {
+ const tools::Long nTol = static_cast<tools::Long>(m_xMtfTolerance->get_value(FieldUnit::PERCENT) * 255 / 100);
+
+ AlphaMask aMask = aGraphic.GetBitmapEx().GetBitmap().CreateAlphaMask( rColor, nTol );
+
+ if( aGraphic.IsTransparent() )
+ aMask.AlphaCombineOr( aGraphic.GetBitmapEx().GetAlphaMask() );
+
+ if( !aMask.IsEmpty() )
+ {
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(&m_rDialog, "svx/ui/querynewcontourdialog.ui"));
+ std::unique_ptr<weld::MessageDialog> xQBox(xBuilder->weld_message_dialog("QueryNewContourDialog"));
+
+ bool bNewContour;
+
+ aRedoGraphic = Graphic();
+ aUndoGraphic = aGraphic;
+ Bitmap aBmp = aGraphic.GetBitmapEx().GetBitmap();
+ aGraphic = Graphic( BitmapEx( aBmp, aMask ) );
+ mnGrfChanged++;
+
+ bNewContour = (xQBox->run() == RET_YES);
+ rWnd.SetGraphic( aGraphic, bNewContour );
+
+ if( bNewContour )
+ aCreateIdle.Start();
+ }
+ }
+ }
+
+ m_xTbx1->set_item_active("TBI_PIPETTE", false);
+ rWnd.SetPipetteMode( false );
+ m_xStbStatusColor->Invalidate();
+}
+
+IMPL_LINK( SvxSuperContourDlg, WorkplaceClickHdl, ContourWindow&, rWnd, void )
+{
+ m_xTbx1->set_item_active("TBI_WORKPLACE", false);
+ m_xTbx1->set_item_active("TBI_SELECT", true);
+ rWnd.SetWorkplaceMode( false );
+
+ m_xContourWnd->QueueIdleUpdate();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/charmap.cxx b/svx/source/dialog/charmap.cxx
new file mode 100644
index 0000000000..dcb1205584
--- /dev/null
+++ b/svx/source/dialog/charmap.cxx
@@ -0,0 +1,1967 @@
+/* -*- 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_wasm_strip.h>
+
+#include <utility>
+#include <vcl/commandevent.hxx>
+#include <vcl/event.hxx>
+#include <vcl/fontcharmap.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/virdev.hxx>
+
+#include <svx/ucsubset.hxx>
+
+
+#include <svx/strings.hrc>
+
+#include <svx/charmap.hxx>
+#include <svx/dialmgr.hxx>
+
+#include <charmapacc.hxx>
+#include <uiobject.hxx>
+
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/datatransfer/clipboard/XFlushableClipboard.hpp>
+#include <com/sun/star/datatransfer/clipboard/SystemClipboard.hpp>
+#include <officecfg/Office/Common.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/sequence.hxx>
+#include <unicode/uchar.h>
+#include <vcl/textview.hxx>
+#include <rtl/ustrbuf.hxx>
+
+using namespace ::com::sun::star::accessibility;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star;
+
+sal_uInt32& SvxShowCharSet::getSelectedChar()
+{
+ static sal_uInt32 cSelectedChar = ' '; // keeps selected character over app lifetime
+ return cSelectedChar;
+}
+
+FactoryFunction SvxShowCharSet::GetUITestFactory() const
+{
+ return SvxShowCharSetUIObject::create;
+}
+
+SvxShowCharSet::SvxShowCharSet(std::unique_ptr<weld::ScrolledWindow> pScrolledWindow, const VclPtr<VirtualDevice>& rVirDev)
+ : mxVirDev(rVirDev)
+ , mxScrollArea(std::move(pScrolledWindow))
+ , nX(0)
+ , nY(0)
+ , maFontSize(0, 0)
+ , mbRecalculateFont(true)
+ , mbUpdateForeground(true)
+ , mbUpdateBackground(true)
+{
+ init();
+}
+
+void SvxShowCharSet::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ CustomWidgetController::SetDrawingArea(pDrawingArea);
+
+ Size aSize(COLUMN_COUNT * pDrawingArea->get_approximate_digit_width() * 5.25,
+ ROW_COUNT * pDrawingArea->get_text_height() * 2);
+
+ nX = aSize.Width() / COLUMN_COUNT;
+ nY = aSize.Height() / ROW_COUNT;
+
+ // tdf#121232 set a size request that will result in a 0 m_nXGap by default
+ mxScrollArea->set_size_request(COLUMN_COUNT * nX + mxScrollArea->get_scroll_thickness() + 2,
+ ROW_COUNT * nY);
+}
+
+void SvxShowCharSet::init()
+{
+ nSelectedIndex = -1; // TODO: move into init list when it is no longer static
+ m_nXGap = 0;
+ m_nYGap = 0;
+
+ mxScrollArea->connect_vadjustment_changed(LINK(this, SvxShowCharSet, VscrollHdl));
+ getFavCharacterList();
+ // other settings depend on selected font => see RecalculateFont
+
+ bDrag = false;
+}
+
+void SvxShowCharSet::Resize()
+{
+ mbRecalculateFont = true;
+}
+
+void SvxShowCharSet::GetFocus()
+{
+ SelectIndex(nSelectedIndex, true);
+}
+
+void SvxShowCharSet::LoseFocus()
+{
+ SelectIndex(nSelectedIndex);
+}
+
+bool SvxShowCharSet::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ if ( rMEvt.IsLeft() )
+ {
+ if ( rMEvt.GetClicks() == 1 )
+ {
+ GrabFocus();
+ bDrag = true;
+ CaptureMouse();
+
+ int nIndex = PixelToMapIndex( rMEvt.GetPosPixel() );
+ // Fire the focus event
+ SelectIndex( nIndex, true);
+ }
+
+ if ( !(rMEvt.GetClicks() % 2) )
+ aDoubleClkHdl.Call( this );
+
+ return true;
+ }
+
+ return CustomWidgetController::MouseButtonDown(rMEvt);
+}
+
+bool SvxShowCharSet::MouseButtonUp(const MouseEvent& rMEvt)
+{
+ if ( bDrag && rMEvt.IsLeft() )
+ {
+ // released mouse over character map
+ if ( tools::Rectangle(Point(), GetOutputSizePixel()).Contains(rMEvt.GetPosPixel()))
+ aSelectHdl.Call( this );
+ ReleaseMouse();
+ bDrag = false;
+ }
+
+ return true;
+}
+
+bool SvxShowCharSet::MouseMove(const MouseEvent& rMEvt)
+{
+ if ( rMEvt.IsLeft() && bDrag )
+ {
+ Point aPos = rMEvt.GetPosPixel();
+ Size aSize = GetOutputSizePixel();
+
+ if ( aPos.X() < 0 )
+ aPos.setX( 0 );
+ else if ( aPos.X() > aSize.Width()-5 )
+ aPos.setX( aSize.Width()-5 );
+ if ( aPos.Y() < 0 )
+ aPos.setY( 0 );
+ else if ( aPos.Y() > aSize.Height()-5 )
+ aPos.setY( aSize.Height()-5 );
+
+ int nIndex = PixelToMapIndex( aPos );
+ // Fire the focus event.
+ SelectIndex( nIndex, true );
+ }
+
+ return true;
+}
+
+bool SvxShowCharSet::Command(const CommandEvent& rCEvt)
+{
+ if (rCEvt.GetCommand() == CommandEventId::ContextMenu)
+ {
+ Point aPosition;
+ if (rCEvt.IsMouseEvent())
+ {
+ aPosition = rCEvt.GetMousePosPixel();
+ int nIndex = PixelToMapIndex(aPosition);
+ // Fire the focus event
+ SelectIndex(nIndex, true);
+ }
+ else
+ {
+ svx::SvxShowCharSetItem* pItem = ImplGetItem(nSelectedIndex);
+ if (!pItem)
+ return true;
+
+ // position context menu at centre of currently selected item
+ aPosition = MapIndexToPixel(nSelectedIndex);
+ aPosition.AdjustX(pItem->maRect.GetWidth() / 2);
+ aPosition.AdjustY(pItem->maRect.GetHeight() / 2);
+ }
+ createContextMenu(aPosition);
+ return true;
+ }
+ return weld::CustomWidgetController::Command(rCEvt);
+}
+
+sal_uInt16 SvxShowCharSet::GetRowPos(sal_uInt16 _nPos)
+{
+ return _nPos / COLUMN_COUNT ;
+}
+
+void SvxShowCharSet::getFavCharacterList()
+{
+ maFavCharList.clear();
+ maFavCharFontList.clear();
+ //retrieve recent character list
+ css::uno::Sequence< OUString > rFavCharList( officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterList::get() );
+ comphelper::sequenceToContainer(maFavCharList, rFavCharList);
+
+ //retrieve recent character font list
+ css::uno::Sequence< OUString > rFavCharFontList( officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterFontList::get() );
+ comphelper::sequenceToContainer(maFavCharFontList, rFavCharFontList);
+}
+
+bool SvxShowCharSet::isFavChar(std::u16string_view sTitle, std::u16string_view rFont)
+{
+ assert(maFavCharList.size() == maFavCharFontList.size());
+ for (size_t i = 0; i < maFavCharList.size(); i++)
+ {
+ if (maFavCharList[i] == sTitle && maFavCharFontList[i] == rFont)
+ return true;
+ }
+ return false;
+}
+
+void SvxShowCharSet::createContextMenu(const Point& rPosition)
+{
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(GetDrawingArea(), "svx/ui/charsetmenu.ui"));
+ std::unique_ptr<weld::Menu> xItemMenu(xBuilder->weld_menu("charsetmenu"));
+
+ sal_UCS4 cChar = GetSelectCharacter();
+ OUString aOUStr( &cChar, 1 );
+ if (isFavChar(aOUStr, mxVirDev->GetFont().GetFamilyName()) || maFavCharList.size() >= 16)
+ xItemMenu->set_visible("add", false);
+ else
+ xItemMenu->set_visible("remove", false);
+
+ ContextMenuSelect(xItemMenu->popup_at_rect(GetDrawingArea(), tools::Rectangle(rPosition, Size(1,1))));
+ GrabFocus();
+ Invalidate();
+}
+
+void SvxShowCharSet::ContextMenuSelect(std::u16string_view rIdent)
+{
+ sal_UCS4 cChar = GetSelectCharacter();
+ OUString aOUStr(&cChar, 1);
+
+ if (rIdent == u"insert")
+ aDoubleClkHdl.Call(this);
+ else if (rIdent == u"add" || rIdent == u"remove")
+ {
+ updateFavCharacterList(aOUStr, mxVirDev->GetFont().GetFamilyName());
+ aFavClickHdl.Call(this);
+ }
+ else if (rIdent == u"copy")
+ CopyToClipboard(aOUStr);
+}
+
+void SvxShowCharSet::CopyToClipboard(const OUString& rOUStr)
+{
+ css::uno::Reference<css::datatransfer::clipboard::XClipboard> xClipboard =
+ css::datatransfer::clipboard::SystemClipboard::create(comphelper::getProcessComponentContext());
+
+ if (!xClipboard.is())
+ return;
+
+ rtl::Reference<TETextDataObject> pDataObj = new TETextDataObject(rOUStr);
+
+ try
+ {
+ xClipboard->setContents( pDataObj, nullptr );
+
+ css::uno::Reference<css::datatransfer::clipboard::XFlushableClipboard> xFlushableClipboard(xClipboard, css::uno::UNO_QUERY);
+ if( xFlushableClipboard.is() )
+ xFlushableClipboard->flushClipboard();
+ }
+ catch( const css::uno::Exception& )
+ {
+ }
+}
+
+void SvxShowCharSet::updateFavCharacterList(const OUString& sTitle, const OUString& rFont)
+{
+ if (isFavChar(sTitle, rFont))
+ {
+ assert(maFavCharList.size() == maFavCharFontList.size());
+ auto fontIt = maFavCharFontList.begin();
+ for (auto charIt = maFavCharList.begin(); charIt != maFavCharList.end(); charIt++)
+ {
+ if (*charIt == sTitle && *fontIt == rFont)
+ {
+ maFavCharList.erase(charIt);
+ maFavCharFontList.erase(fontIt);
+ break;
+ }
+ fontIt++;
+ }
+ }
+ else
+ {
+ if (maFavCharList.size() == 16)
+ {
+ maFavCharList.pop_back();
+ maFavCharFontList.pop_back();
+ }
+
+ maFavCharList.push_back(sTitle);
+ maFavCharFontList.push_back(rFont);
+ }
+
+ css::uno::Sequence< OUString > aFavCharList(maFavCharList.size());
+ auto aFavCharListRange = asNonConstRange(aFavCharList);
+ css::uno::Sequence< OUString > aFavCharFontList(maFavCharFontList.size());
+ auto aFavCharFontListRange = asNonConstRange(aFavCharFontList);
+
+ for (size_t i = 0; i < maFavCharList.size(); ++i)
+ {
+ aFavCharListRange[i] = maFavCharList[i];
+ aFavCharFontListRange[i] = maFavCharFontList[i];
+ }
+
+ std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
+ officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterList::set(aFavCharList, batch);
+ officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterFontList::set(aFavCharFontList, batch);
+ batch->commit();
+}
+
+sal_uInt16 SvxShowCharSet::GetColumnPos(sal_uInt16 _nPos)
+{
+ return _nPos % COLUMN_COUNT ;
+}
+
+int SvxShowCharSet::FirstInView() const
+{
+ return mxScrollArea->vadjustment_get_value() * COLUMN_COUNT;
+}
+
+int SvxShowCharSet::LastInView() const
+{
+ sal_uInt32 nIndex = FirstInView();
+ nIndex += ROW_COUNT * COLUMN_COUNT - 1;
+ sal_uInt32 nCompare = mxFontCharMap->GetCharCount() - 1;
+ if (nIndex > nCompare)
+ nIndex = nCompare;
+ return nIndex;
+}
+
+Point SvxShowCharSet::MapIndexToPixel( int nIndex ) const
+{
+ const int nBase = FirstInView();
+ int x = ((nIndex - nBase) % COLUMN_COUNT) * nX;
+ int y = ((nIndex - nBase) / COLUMN_COUNT) * nY;
+ return Point( x + m_nXGap, y + m_nYGap );
+}
+
+
+int SvxShowCharSet::PixelToMapIndex( const Point& point) const
+{
+ int nBase = FirstInView();
+ assert(nX != 0);
+ int x = nX == 0 ? 0 : (point.X() - m_nXGap)/nX;
+ assert(nY != 0);
+ int y = nY == 0 ? 0 : (point.Y() - m_nYGap)/nY;
+ return (nBase + x + y * COLUMN_COUNT);
+}
+
+bool SvxShowCharSet::KeyInput(const KeyEvent& rKEvt)
+{
+ vcl::KeyCode aCode = rKEvt.GetKeyCode();
+
+ if (aCode.GetModifier())
+ return false;
+
+ bool bRet = true;
+
+ int tmpSelected = nSelectedIndex;
+
+ switch (aCode.GetCode())
+ {
+ case KEY_RETURN:
+ m_aReturnKeypressHdl.Call(this);
+ return true;
+ case KEY_SPACE:
+ aDoubleClkHdl.Call(this);
+ return true;
+ case KEY_LEFT:
+ --tmpSelected;
+ break;
+ case KEY_RIGHT:
+ ++tmpSelected;
+ break;
+ case KEY_UP:
+ tmpSelected -= COLUMN_COUNT;
+ break;
+ case KEY_DOWN:
+ tmpSelected += COLUMN_COUNT;
+ break;
+ case KEY_PAGEUP:
+ tmpSelected -= ROW_COUNT * COLUMN_COUNT;
+ break;
+ case KEY_PAGEDOWN:
+ tmpSelected += ROW_COUNT * COLUMN_COUNT;
+ break;
+ case KEY_HOME:
+ tmpSelected = 0;
+ break;
+ case KEY_END:
+ tmpSelected = mxFontCharMap->GetCharCount() - 1;
+ break;
+ case KEY_TAB: // some fonts have a character at these unicode control codes
+ case KEY_ESCAPE:
+ tmpSelected = - 1; // mark as invalid
+ bRet = false;
+ break;
+ default:
+ {
+ sal_UCS4 cChar = rKEvt.GetCharCode();
+ sal_UCS4 cNext = mxFontCharMap->GetNextChar(cChar - 1);
+ tmpSelected = mxFontCharMap->GetIndexFromChar(cNext);
+ if (tmpSelected < 0 || (cChar != cNext))
+ {
+ tmpSelected = - 1; // mark as invalid
+ bRet = false;
+ }
+ break;
+ }
+ }
+
+ if ( tmpSelected >= 0 )
+ {
+ SelectIndex( tmpSelected, true );
+ aPreSelectHdl.Call( this );
+ }
+
+ return bRet;
+}
+
+void SvxShowCharSet::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ InitSettings(rRenderContext);
+ RecalculateFont(rRenderContext);
+ DrawChars_Impl(rRenderContext, FirstInView(), LastInView());
+}
+
+void SvxShowCharSet::SetFont( const vcl::Font& rFont )
+{
+ maFont = rFont;
+ mbRecalculateFont = true;
+ Invalidate();
+}
+
+void SvxShowCharSet::DeSelect()
+{
+ Invalidate();
+}
+
+// stretch a grid rectangle if it's at the edge to fill unused space
+tools::Rectangle SvxShowCharSet::getGridRectangle(const Point &rPointUL, const Size &rOutputSize) const
+{
+ tools::Long x = rPointUL.X() - 1;
+ tools::Long y = rPointUL.Y() - 1;
+ Point aPointUL(x+1, y+1);
+ Size aGridSize(nX-1, nY-1);
+
+ tools::Long nXDistFromLeft = x - m_nXGap;
+ if (nXDistFromLeft <= 1)
+ {
+ aPointUL.setX( 1 );
+ aGridSize.AdjustWidth(m_nXGap + nXDistFromLeft );
+ }
+ tools::Long nXDistFromRight = rOutputSize.Width() - m_nXGap - nX - x;
+ if (nXDistFromRight <= 1)
+ aGridSize.AdjustWidth(m_nXGap + nXDistFromRight );
+
+ tools::Long nXDistFromTop = y - m_nYGap;
+ if (nXDistFromTop <= 1)
+ {
+ aPointUL.setY( 1 );
+ aGridSize.AdjustHeight(m_nYGap + nXDistFromTop );
+ }
+ tools::Long nXDistFromBottom = rOutputSize.Height() - m_nYGap - nY - y;
+ if (nXDistFromBottom <= 1)
+ aGridSize.AdjustHeight(m_nYGap + nXDistFromBottom );
+
+ return tools::Rectangle(aPointUL, aGridSize);
+}
+
+void SvxShowCharSet::DrawChars_Impl(vcl::RenderContext& rRenderContext, int n1, int n2)
+{
+ if (n1 > LastInView() || n2 < FirstInView())
+ return;
+
+ Size aOutputSize(GetOutputSizePixel());
+
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ const Color aWindowTextColor(rStyleSettings.GetFieldTextColor());
+ Color aHighlightColor(rStyleSettings.GetHighlightColor());
+ Color aHighlightTextColor(rStyleSettings.GetHighlightTextColor());
+ Color aFaceColor(rStyleSettings.GetFaceColor());
+ Color aLightColor(rStyleSettings.GetLightColor());
+ Color aShadowColor(rStyleSettings.GetShadowColor());
+
+ int i;
+ rRenderContext.SetLineColor(aShadowColor);
+ for (i = 1; i < COLUMN_COUNT; ++i)
+ {
+ rRenderContext.DrawLine(Point(nX * i + m_nXGap, 0),
+ Point(nX * i + m_nXGap, aOutputSize.Height()));
+ }
+ for (i = 1; i < ROW_COUNT; ++i)
+ {
+ rRenderContext.DrawLine(Point(0, nY * i + m_nYGap),
+ Point(aOutputSize.Width(), nY * i + m_nYGap));
+ }
+
+ int nTextHeight = rRenderContext.GetTextHeight();
+ tools::Rectangle aBoundRect;
+ for (i = n1; i <= n2; ++i)
+ {
+ sal_UCS4 charValue = GetCharFromIndex(i);
+
+ if (charValue == 0)
+ continue;
+
+ OUString aCharStr(&charValue, 1);
+
+ Point pix = MapIndexToPixel(i);
+ int x = pix.X();
+ int y = pix.Y();
+
+ int nTextWidth = rRenderContext.GetTextWidth(aCharStr);
+ int tx = x + (nX - nTextWidth + 1) / 2;
+ int ty = y + (nY - nTextHeight + 1) / 2;
+ Point aPointTxTy(tx, ty);
+
+ // adjust position before it gets out of bounds
+ if (rRenderContext.GetTextBoundRect(aBoundRect, aCharStr) && !aBoundRect.IsEmpty())
+ {
+ // zero advance width => use ink width to center glyph
+ if (!nTextWidth)
+ {
+ aPointTxTy.setX( x - aBoundRect.Left() + (nX - aBoundRect.GetWidth() + 1) / 2 );
+ }
+
+ aBoundRect += aPointTxTy;
+
+ // shift back vertically if needed
+ int nYLDelta = aBoundRect.Top() - y;
+ int nYHDelta = (y + nY) - aBoundRect.Bottom();
+ if (nYLDelta <= 0)
+ aPointTxTy.AdjustY( -(nYLDelta - 1) );
+ else if (nYHDelta <= 0)
+ aPointTxTy.AdjustY(nYHDelta - 1 );
+
+ // shift back horizontally if needed
+ int nXLDelta = aBoundRect.Left() - x;
+ int nXHDelta = (x + nX) - aBoundRect.Right();
+ if (nXLDelta <= 0)
+ aPointTxTy.AdjustX( -(nXLDelta - 1) );
+ else if (nXHDelta <= 0)
+ aPointTxTy.AdjustX(nXHDelta - 1 );
+ }
+
+ // tdf#109214 - highlight the favorite characters
+ if (isFavChar(aCharStr, mxVirDev->GetFont().GetFamilyName()))
+ {
+ const Color aLineCol = rRenderContext.GetLineColor();
+ rRenderContext.SetLineColor(aHighlightColor);
+ rRenderContext.SetFillColor(COL_TRANSPARENT);
+ // Outer border
+ rRenderContext.DrawRect(tools::Rectangle(Point(x - 1, y - 1), Size(nX + 3, nY + 3)), 1, 1);
+ // Inner border
+ rRenderContext.DrawRect(tools::Rectangle(Point(x, y), Size(nX + 1, nY + 1)), 1, 1);
+ rRenderContext.SetLineColor(aLineCol);
+ }
+
+ Color aTextCol = rRenderContext.GetTextColor();
+ if (i != nSelectedIndex)
+ {
+ rRenderContext.SetTextColor(aWindowTextColor);
+ rRenderContext.DrawText(aPointTxTy, aCharStr);
+ }
+ else
+ {
+ Color aLineCol = rRenderContext.GetLineColor();
+ Color aFillCol = rRenderContext.GetFillColor();
+ rRenderContext.SetLineColor();
+ Point aPointUL(x + 1, y + 1);
+ if (HasFocus())
+ {
+ rRenderContext.SetFillColor(aHighlightColor);
+ rRenderContext.DrawRect(getGridRectangle(aPointUL, aOutputSize));
+
+ rRenderContext.SetTextColor(aHighlightTextColor);
+ rRenderContext.DrawText(aPointTxTy, aCharStr);
+ }
+ else
+ {
+ rRenderContext.SetFillColor(aFaceColor);
+ rRenderContext.DrawRect(getGridRectangle(aPointUL, aOutputSize));
+
+ rRenderContext.SetLineColor(aLightColor);
+ rRenderContext.DrawLine(aPointUL, Point(x + nX - 1, y + 1));
+ rRenderContext.DrawLine(aPointUL, Point(x + 1, y + nY - 1));
+
+ rRenderContext.SetLineColor(aShadowColor);
+ rRenderContext.DrawLine(Point(x + 1, y + nY - 1), Point(x + nX - 1, y + nY - 1));
+ rRenderContext.DrawLine(Point(x + nX - 1, y + nY - 1), Point(x + nX - 1, y + 1));
+
+ rRenderContext.DrawText(aPointTxTy, aCharStr);
+ }
+ rRenderContext.SetLineColor(aLineCol);
+ rRenderContext.SetFillColor(aFillCol);
+ }
+ rRenderContext.SetTextColor(aTextCol);
+ }
+
+ // tdf#141319 - mark empty/unused cells
+ if (n2 - n1 < ROW_COUNT * COLUMN_COUNT)
+ {
+ rRenderContext.SetFillColor(rStyleSettings.GetDisableColor());
+ for (i = n2 - n1 + 1; i < ROW_COUNT * COLUMN_COUNT; i++)
+ {
+ rRenderContext.DrawRect(
+ tools::Rectangle(MapIndexToPixel(i + n1), Size(nX + 2, nY + 2)));
+ }
+ }
+}
+
+
+void SvxShowCharSet::InitSettings(vcl::RenderContext& rRenderContext)
+{
+ const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
+
+ if (mbUpdateForeground)
+ {
+ rRenderContext.SetTextColor(rStyleSettings.GetDialogTextColor());
+ mbUpdateForeground = false;
+ }
+
+ if (mbUpdateBackground)
+ {
+ rRenderContext.SetBackground(rStyleSettings.GetWindowColor());
+ rRenderContext.Erase();
+ mbUpdateBackground = false;
+ }
+
+ vcl::Font aFont(maFont);
+ aFont.SetWeight(WEIGHT_LIGHT);
+ aFont.SetAlignment(ALIGN_TOP);
+ aFont.SetFontSize(maFontSize);
+ aFont.SetTransparent(true);
+ rRenderContext.SetFont(aFont);
+}
+
+sal_UCS4 SvxShowCharSet::GetSelectCharacter() const
+{
+ if( nSelectedIndex >= 0 )
+ getSelectedChar() = mxFontCharMap->GetCharFromIndex( nSelectedIndex );
+ return getSelectedChar();
+}
+
+sal_UCS4 SvxShowCharSet::GetCharFromIndex(int index) const
+{
+ return mxFontCharMap->GetCharFromIndex(index);
+}
+
+void SvxShowCharSet::RecalculateFont(vcl::RenderContext& rRenderContext)
+{
+ if (!mbRecalculateFont)
+ return;
+
+ // save last selected unicode
+ if (nSelectedIndex >= 0)
+ getSelectedChar() = mxFontCharMap->GetCharFromIndex(nSelectedIndex);
+
+ Size aSize(GetOutputSizePixel());
+
+ vcl::Font aFont = maFont;
+ aFont.SetWeight(WEIGHT_LIGHT);
+ aFont.SetAlignment(ALIGN_TOP);
+ int nFontHeight = (aSize.Height() - 5) * 2 / (3 * ROW_COUNT);
+ maFontSize = rRenderContext.PixelToLogic(Size(0, nFontHeight));
+ aFont.SetFontSize(maFontSize);
+ aFont.SetTransparent(true);
+ rRenderContext.SetFont(aFont);
+ rRenderContext.GetFontCharMap(mxFontCharMap);
+ m_aItems.clear();
+ getFavCharacterList();
+
+ nX = aSize.Width() / COLUMN_COUNT;
+ nY = aSize.Height() / ROW_COUNT;
+
+ const int nLastRow = (mxFontCharMap->GetCharCount() - 1 + COLUMN_COUNT) / COLUMN_COUNT;
+ mxScrollArea->vadjustment_configure(mxScrollArea->vadjustment_get_value(), 0, nLastRow, 1, ROW_COUNT - 1, ROW_COUNT);
+
+ // restore last selected unicode
+ int nMapIndex = mxFontCharMap->GetIndexFromChar(getSelectedChar());
+ if (nMapIndex != nSelectedIndex)
+ SelectIndex(nMapIndex);
+
+ // rearrange CharSet element in sync with nX- and nY-multiples
+ Size aDrawSize(nX * COLUMN_COUNT, nY * ROW_COUNT);
+ m_nXGap = (aSize.Width() - aDrawSize.Width()) / 2;
+ m_nYGap = (aSize.Height() - aDrawSize.Height()) / 2;
+
+ mbRecalculateFont = false;
+}
+
+void SvxShowCharSet::SelectIndex(int nNewIndex, bool bFocus)
+{
+ if (!mxFontCharMap.is())
+ RecalculateFont(*mxVirDev);
+
+ if( nNewIndex < 0 )
+ {
+ // need to scroll see closest unicode
+ sal_uInt32 cPrev = mxFontCharMap->GetPrevChar( getSelectedChar() );
+ int nMapIndex = mxFontCharMap->GetIndexFromChar( cPrev );
+ int nNewPos = nMapIndex / COLUMN_COUNT;
+ mxScrollArea->vadjustment_set_value(nNewPos);
+ nSelectedIndex = bFocus ? nMapIndex+1 : -1;
+ Invalidate();
+ }
+ else if( nNewIndex < FirstInView() )
+ {
+ // need to scroll up to see selected item
+ int nOldPos = mxScrollArea->vadjustment_get_value();
+ int nDelta = (FirstInView() - nNewIndex + COLUMN_COUNT-1) / COLUMN_COUNT;
+ mxScrollArea->vadjustment_set_value(nOldPos - nDelta);
+ nSelectedIndex = nNewIndex;
+ Invalidate();
+ }
+ else if( nNewIndex > LastInView() )
+ {
+ // need to scroll down to see selected item
+ int nOldPos = mxScrollArea->vadjustment_get_value();
+ int nDelta = (nNewIndex - LastInView() + COLUMN_COUNT) / COLUMN_COUNT;
+ mxScrollArea->vadjustment_set_value(nOldPos + nDelta);
+ if( nNewIndex < mxFontCharMap->GetCharCount() )
+ {
+ nSelectedIndex = nNewIndex;
+ Invalidate();
+ }
+ else if (nOldPos != mxScrollArea->vadjustment_get_value())
+ {
+ Invalidate();
+ }
+ }
+ else
+ {
+ nSelectedIndex = nNewIndex;
+ Invalidate();
+ }
+
+ if( nSelectedIndex >= 0 )
+ {
+ getSelectedChar() = mxFontCharMap->GetCharFromIndex( nSelectedIndex );
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ if( m_xAccessible.is() )
+ {
+ svx::SvxShowCharSetItem* pItem = ImplGetItem(nSelectedIndex);
+ rtl::Reference<svx::SvxShowCharSetItemAcc> xItemAcc = pItem->GetAccessible();
+ // Don't fire the focus event.
+ if ( bFocus )
+ m_xAccessible->fireEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, Any(),
+ Any(uno::Reference<XAccessible>(xItemAcc)) ); // this call assures that m_pItem is set
+ else
+ m_xAccessible->fireEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED_NOFOCUS, Any(),
+ Any(uno::Reference<XAccessible>(xItemAcc)) ); // this call assures that m_pItem is set
+
+ assert(pItem->m_xItem.is() && "No accessible created!");
+ Any aOldAny, aNewAny;
+ aNewAny <<= AccessibleStateType::FOCUSED;
+ // Don't fire the focus event.
+ if ( bFocus )
+ pItem->m_xItem->fireEvent( AccessibleEventId::STATE_CHANGED, aOldAny, aNewAny );
+
+ aNewAny <<= AccessibleStateType::SELECTED;
+ pItem->m_xItem->fireEvent( AccessibleEventId::STATE_CHANGED, aOldAny, aNewAny );
+ }
+ aSelectHdl.Call(this);
+#endif
+ }
+ aHighHdl.Call( this );
+}
+
+void SvxShowCharSet::OutputIndex( int nNewIndex )
+{
+ SelectIndex( nNewIndex, true );
+ aSelectHdl.Call( this );
+}
+
+
+void SvxShowCharSet::SelectCharacter( sal_UCS4 cNew )
+{
+ if ( !mxFontCharMap.is() )
+ RecalculateFont(*mxVirDev);
+
+ // get next available char of current font
+ sal_UCS4 cNext = mxFontCharMap->GetNextChar( (cNew > 0) ? cNew - 1 : cNew );
+
+ int nMapIndex = mxFontCharMap->GetIndexFromChar( cNext );
+ SelectIndex( nMapIndex );
+ // move selected item to top row if not in focus
+ mxScrollArea->vadjustment_set_value(nMapIndex / COLUMN_COUNT);
+ Invalidate();
+}
+
+IMPL_LINK_NOARG(SvxShowCharSet, VscrollHdl, weld::ScrolledWindow&, void)
+{
+ if( nSelectedIndex < FirstInView() )
+ {
+ SelectIndex( FirstInView() + (nSelectedIndex % COLUMN_COUNT) );
+ }
+ else if( nSelectedIndex > LastInView() )
+ {
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ if( m_xAccessible.is() )
+ {
+ css::uno::Any aOldAny, aNewAny;
+ int nLast = LastInView();
+ for ( ; nLast != nSelectedIndex; ++nLast)
+ {
+ aOldAny <<= uno::Reference<XAccessible>(ImplGetItem(nLast)->GetAccessible());
+ m_xAccessible ->fireEvent( AccessibleEventId::CHILD, aOldAny, aNewAny );
+ }
+ }
+#endif
+ SelectIndex( (LastInView() - COLUMN_COUNT + 1) + (nSelectedIndex % COLUMN_COUNT) );
+ }
+
+ Invalidate();
+}
+
+SvxShowCharSet::~SvxShowCharSet()
+{
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ if (m_xAccessible.is())
+ {
+ m_aItems.clear();
+ m_xAccessible->clearCharSetControl();
+ m_xAccessible.clear();
+ }
+#endif
+}
+
+css::uno::Reference< XAccessible > SvxShowCharSet::CreateAccessible()
+{
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ OSL_ENSURE(!m_xAccessible.is(),"Accessible already created!");
+ m_xAccessible = new svx::SvxShowCharSetAcc(this);
+#endif
+ return m_xAccessible;
+}
+
+svx::SvxShowCharSetItem* SvxShowCharSet::ImplGetItem( int _nPos )
+{
+ ItemsMap::iterator aFind = m_aItems.find(_nPos);
+ if ( aFind == m_aItems.end() )
+ {
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ OSL_ENSURE(m_xAccessible.is(), "Who wants to create a child of my table without a parent?");
+#endif
+ auto xItem = std::make_shared<svx::SvxShowCharSetItem>(*this,
+ m_xAccessible.get(), sal::static_int_cast< sal_uInt16 >(_nPos));
+ aFind = m_aItems.emplace(_nPos, xItem).first;
+ OUStringBuffer buf;
+ buf.appendUtf32( mxFontCharMap->GetCharFromIndex( _nPos ) );
+ aFind->second->maText = buf.makeStringAndClear();
+ Point pix = MapIndexToPixel( _nPos );
+ aFind->second->maRect = tools::Rectangle( Point( pix.X() + 1, pix.Y() + 1 ), Size(nX-1,nY-1) );
+ }
+
+ return aFind->second.get();
+}
+
+sal_Int32 SvxShowCharSet::getMaxCharCount() const
+{
+ return mxFontCharMap->GetCharCount();
+}
+
+FontCharMapRef const & SvxShowCharSet::GetFontCharMap()
+{
+ RecalculateFont(*mxVirDev);
+ return mxFontCharMap;
+}
+
+// TODO: should be moved into Font Attributes stuff
+// we let it mature here though because it is currently the only use
+
+SubsetMap::SubsetMap( const FontCharMapRef& rxFontCharMap )
+{
+ InitList();
+ ApplyCharMap(rxFontCharMap);
+}
+
+const SubsetVec& SubsetMap::GetSubsetMap() const
+{
+ return maSubsets;
+}
+
+const Subset* SubsetMap::GetSubsetByUnicode( sal_UCS4 cChar ) const
+{
+ for (auto const& subset : maSubsets)
+ if( (subset.GetRangeMin() <= cChar) && (cChar <= subset.GetRangeMax()) )
+ return &subset;
+ return nullptr;
+}
+
+inline Subset::Subset(sal_UCS4 nMin, sal_UCS4 nMax, OUString aName)
+: mnRangeMin(nMin), mnRangeMax(nMax), maRangeName(std::move(aName))
+{
+}
+
+void SubsetMap::InitList()
+{
+ static SubsetVec s_aAllSubsets = []()
+ {
+ SubsetVec aAllSubsets;
+ //I wish icu had a way to give me the block ranges
+ for (int i = UBLOCK_BASIC_LATIN; i < UBLOCK_COUNT; ++i)
+ {
+ UBlockCode eBlock = static_cast<UBlockCode>(i);
+ switch (eBlock)
+ {
+ case UBLOCK_NO_BLOCK:
+ case UBLOCK_INVALID_CODE:
+ case UBLOCK_COUNT:
+ case UBLOCK_HIGH_SURROGATES:
+ case UBLOCK_HIGH_PRIVATE_USE_SURROGATES:
+ case UBLOCK_LOW_SURROGATES:
+ break;
+ case UBLOCK_BASIC_LATIN:
+ aAllSubsets.emplace_back( 0x0000, 0x007F, SvxResId(RID_SUBSETSTR_BASIC_LATIN) );
+ break;
+ case UBLOCK_LATIN_1_SUPPLEMENT:
+ aAllSubsets.emplace_back( 0x0080, 0x00FF, SvxResId(RID_SUBSETSTR_LATIN_1) );
+ break;
+ case UBLOCK_LATIN_EXTENDED_A:
+ aAllSubsets.emplace_back( 0x0100, 0x017F, SvxResId(RID_SUBSETSTR_LATIN_EXTENDED_A) );
+ break;
+ case UBLOCK_LATIN_EXTENDED_B:
+ aAllSubsets.emplace_back( 0x0180, 0x024F, SvxResId(RID_SUBSETSTR_LATIN_EXTENDED_B) );
+ break;
+ case UBLOCK_IPA_EXTENSIONS:
+ aAllSubsets.emplace_back( 0x0250, 0x02AF, SvxResId(RID_SUBSETSTR_IPA_EXTENSIONS) );
+ break;
+ case UBLOCK_SPACING_MODIFIER_LETTERS:
+ aAllSubsets.emplace_back( 0x02B0, 0x02FF, SvxResId(RID_SUBSETSTR_SPACING_MODIFIERS) );
+ break;
+ case UBLOCK_COMBINING_DIACRITICAL_MARKS:
+ aAllSubsets.emplace_back( 0x0300, 0x036F, SvxResId(RID_SUBSETSTR_COMB_DIACRITICAL) );
+ break;
+ case UBLOCK_GREEK:
+ aAllSubsets.emplace_back( 0x0370, 0x03FF, SvxResId(RID_SUBSETSTR_BASIC_GREEK) );
+ break;
+ case UBLOCK_CYRILLIC:
+ aAllSubsets.emplace_back( 0x0400, 0x04FF, SvxResId(RID_SUBSETSTR_CYRILLIC) );
+ break;
+ case UBLOCK_ARMENIAN:
+ aAllSubsets.emplace_back( 0x0530, 0x058F, SvxResId(RID_SUBSETSTR_ARMENIAN) );
+ break;
+ case UBLOCK_HEBREW:
+ aAllSubsets.emplace_back( 0x0590, 0x05FF, SvxResId(RID_SUBSETSTR_BASIC_HEBREW) );
+ break;
+ case UBLOCK_ARABIC:
+ aAllSubsets.emplace_back( 0x0600, 0x065F, SvxResId(RID_SUBSETSTR_BASIC_ARABIC) );
+ break;
+ case UBLOCK_SYRIAC:
+ aAllSubsets.emplace_back( 0x0700, 0x074F, SvxResId(RID_SUBSETSTR_SYRIAC) );
+ break;
+ case UBLOCK_THAANA:
+ aAllSubsets.emplace_back( 0x0780, 0x07BF, SvxResId(RID_SUBSETSTR_THAANA) );
+ break;
+ case UBLOCK_DEVANAGARI:
+ aAllSubsets.emplace_back( 0x0900, 0x097F, SvxResId(RID_SUBSETSTR_DEVANAGARI) );
+ break;
+ case UBLOCK_BENGALI:
+ aAllSubsets.emplace_back( 0x0980, 0x09FF, SvxResId(RID_SUBSETSTR_BENGALI) );
+ break;
+ case UBLOCK_GURMUKHI:
+ aAllSubsets.emplace_back( 0x0A00, 0x0A7F, SvxResId(RID_SUBSETSTR_GURMUKHI) );
+ break;
+ case UBLOCK_GUJARATI:
+ aAllSubsets.emplace_back( 0x0A80, 0x0AFF, SvxResId(RID_SUBSETSTR_GUJARATI) );
+ break;
+ case UBLOCK_ORIYA:
+ aAllSubsets.emplace_back( 0x0B00, 0x0B7F, SvxResId(RID_SUBSETSTR_ODIA) );
+ break;
+ case UBLOCK_TAMIL:
+ aAllSubsets.emplace_back( 0x0B80, 0x0BFF, SvxResId(RID_SUBSETSTR_TAMIL) );
+ break;
+ case UBLOCK_TELUGU:
+ aAllSubsets.emplace_back( 0x0C00, 0x0C7F, SvxResId(RID_SUBSETSTR_TELUGU) );
+ break;
+ case UBLOCK_KANNADA:
+ aAllSubsets.emplace_back( 0x0C80, 0x0CFF, SvxResId(RID_SUBSETSTR_KANNADA) );
+ break;
+ case UBLOCK_MALAYALAM:
+ aAllSubsets.emplace_back( 0x0D00, 0x0D7F, SvxResId(RID_SUBSETSTR_MALAYALAM) );
+ break;
+ case UBLOCK_SINHALA:
+ aAllSubsets.emplace_back( 0x0D80, 0x0DFF, SvxResId(RID_SUBSETSTR_SINHALA) );
+ break;
+ case UBLOCK_THAI:
+ aAllSubsets.emplace_back( 0x0E00, 0x0E7F, SvxResId(RID_SUBSETSTR_THAI) );
+ break;
+ case UBLOCK_LAO:
+ aAllSubsets.emplace_back( 0x0E80, 0x0EFF, SvxResId(RID_SUBSETSTR_LAO) );
+ break;
+ case UBLOCK_TIBETAN:
+ aAllSubsets.emplace_back( 0x0F00, 0x0FBF, SvxResId(RID_SUBSETSTR_TIBETAN) );
+ break;
+ case UBLOCK_MYANMAR:
+ aAllSubsets.emplace_back( 0x1000, 0x109F, SvxResId(RID_SUBSETSTR_MYANMAR) );
+ break;
+ case UBLOCK_GEORGIAN:
+ aAllSubsets.emplace_back( 0x10A0, 0x10FF, SvxResId(RID_SUBSETSTR_BASIC_GEORGIAN) );
+ break;
+ case UBLOCK_HANGUL_JAMO:
+ aAllSubsets.emplace_back( 0x1100, 0x11FF, SvxResId(RID_SUBSETSTR_HANGUL_JAMO) );
+ break;
+ case UBLOCK_ETHIOPIC:
+ aAllSubsets.emplace_back( 0x1200, 0x137F, SvxResId(RID_SUBSETSTR_ETHIOPIC) );
+ break;
+ case UBLOCK_CHEROKEE:
+ aAllSubsets.emplace_back( 0x13A0, 0x13FF, SvxResId(RID_SUBSETSTR_CHEROKEE) );
+ break;
+ case UBLOCK_UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS:
+ aAllSubsets.emplace_back( 0x1400, 0x167F, SvxResId(RID_SUBSETSTR_CANADIAN_ABORIGINAL) );
+ break;
+ case UBLOCK_OGHAM:
+ aAllSubsets.emplace_back( 0x1680, 0x169F, SvxResId(RID_SUBSETSTR_OGHAM) );
+ break;
+ case UBLOCK_RUNIC:
+ aAllSubsets.emplace_back( 0x16A0, 0x16F0, SvxResId(RID_SUBSETSTR_RUNIC) );
+ break;
+ case UBLOCK_KHMER:
+ aAllSubsets.emplace_back( 0x1780, 0x17FF, SvxResId(RID_SUBSETSTR_KHMER) );
+ break;
+ case UBLOCK_MONGOLIAN:
+ aAllSubsets.emplace_back( 0x1800, 0x18AF, SvxResId(RID_SUBSETSTR_MONGOLIAN) );
+ break;
+ case UBLOCK_LATIN_EXTENDED_ADDITIONAL:
+ aAllSubsets.emplace_back( 0x1E00, 0x1EFF, SvxResId(RID_SUBSETSTR_LATIN_EXTENDED_ADDS) );
+ break;
+ case UBLOCK_GREEK_EXTENDED:
+ aAllSubsets.emplace_back( 0x1F00, 0x1FFF, SvxResId(RID_SUBSETSTR_GREEK_EXTENDED) );
+ break;
+ case UBLOCK_GENERAL_PUNCTUATION:
+ aAllSubsets.emplace_back( 0x2000, 0x206F, SvxResId(RID_SUBSETSTR_GENERAL_PUNCTUATION) );
+ break;
+ case UBLOCK_SUPERSCRIPTS_AND_SUBSCRIPTS:
+ aAllSubsets.emplace_back( 0x2070, 0x209F, SvxResId(RID_SUBSETSTR_SUB_SUPER_SCRIPTS) );
+ break;
+ case UBLOCK_CURRENCY_SYMBOLS:
+ aAllSubsets.emplace_back( 0x20A0, 0x20CF, SvxResId(RID_SUBSETSTR_CURRENCY_SYMBOLS) );
+ break;
+ case UBLOCK_COMBINING_MARKS_FOR_SYMBOLS:
+ aAllSubsets.emplace_back( 0x20D0, 0x20FF, SvxResId(RID_SUBSETSTR_COMB_DIACRITIC_SYMS) );
+ break;
+ case UBLOCK_LETTERLIKE_SYMBOLS:
+ aAllSubsets.emplace_back( 0x2100, 0x214F, SvxResId(RID_SUBSETSTR_LETTERLIKE_SYMBOLS) );
+ break;
+ case UBLOCK_NUMBER_FORMS:
+ aAllSubsets.emplace_back( 0x2150, 0x218F, SvxResId(RID_SUBSETSTR_NUMBER_FORMS) );
+ break;
+ case UBLOCK_ARROWS:
+ aAllSubsets.emplace_back( 0x2190, 0x21FF, SvxResId(RID_SUBSETSTR_ARROWS) );
+ break;
+ case UBLOCK_MATHEMATICAL_OPERATORS:
+ aAllSubsets.emplace_back( 0x2200, 0x22FF, SvxResId(RID_SUBSETSTR_MATH_OPERATORS) );
+ break;
+ case UBLOCK_MISCELLANEOUS_TECHNICAL:
+ aAllSubsets.emplace_back( 0x2300, 0x23FF, SvxResId(RID_SUBSETSTR_MISC_TECHNICAL) );
+ break;
+ case UBLOCK_CONTROL_PICTURES:
+ aAllSubsets.emplace_back( 0x2400, 0x243F, SvxResId(RID_SUBSETSTR_CONTROL_PICTURES) );
+ break;
+ case UBLOCK_OPTICAL_CHARACTER_RECOGNITION:
+ aAllSubsets.emplace_back( 0x2440, 0x245F, SvxResId(RID_SUBSETSTR_OPTICAL_CHAR_REC) );
+ break;
+ case UBLOCK_ENCLOSED_ALPHANUMERICS:
+ aAllSubsets.emplace_back( 0x2460, 0x24FF, SvxResId(RID_SUBSETSTR_ENCLOSED_ALPHANUM) );
+ break;
+ case UBLOCK_BOX_DRAWING:
+ aAllSubsets.emplace_back( 0x2500, 0x257F, SvxResId(RID_SUBSETSTR_BOX_DRAWING) );
+ break;
+ case UBLOCK_BLOCK_ELEMENTS:
+ aAllSubsets.emplace_back( 0x2580, 0x259F, SvxResId(RID_SUBSETSTR_BLOCK_ELEMENTS) );
+ break;
+ case UBLOCK_GEOMETRIC_SHAPES:
+ aAllSubsets.emplace_back( 0x25A0, 0x25FF, SvxResId(RID_SUBSETSTR_GEOMETRIC_SHAPES) );
+ break;
+ case UBLOCK_MISCELLANEOUS_SYMBOLS:
+ aAllSubsets.emplace_back( 0x2600, 0x26FF, SvxResId(RID_SUBSETSTR_MISC_DINGBATS) );
+ break;
+ case UBLOCK_DINGBATS:
+ aAllSubsets.emplace_back( 0x2700, 0x27BF, SvxResId(RID_SUBSETSTR_DINGBATS) );
+ break;
+ case UBLOCK_BRAILLE_PATTERNS:
+ aAllSubsets.emplace_back( 0x2800, 0x28FF, SvxResId(RID_SUBSETSTR_BRAILLE_PATTERNS) );
+ break;
+ case UBLOCK_CJK_RADICALS_SUPPLEMENT:
+ aAllSubsets.emplace_back( 0x2E80, 0x2EFF, SvxResId(RID_SUBSETSTR_CJK_RADICAL_SUPPL) );
+ break;
+ case UBLOCK_KANGXI_RADICALS:
+ aAllSubsets.emplace_back( 0x2F00, 0x2FDF, SvxResId(RID_SUBSETSTR_KANGXI_RADICALS) );
+ break;
+ case UBLOCK_IDEOGRAPHIC_DESCRIPTION_CHARACTERS:
+ aAllSubsets.emplace_back( 0x2FF0, 0x2FFF, SvxResId(RID_SUBSETSTR_IDEO_DESC_CHARS) );
+ break;
+ case UBLOCK_CJK_SYMBOLS_AND_PUNCTUATION:
+ aAllSubsets.emplace_back( 0x3000, 0x303F, SvxResId(RID_SUBSETSTR_CJK_SYMS_PUNCTUATION) );
+ break;
+ case UBLOCK_HIRAGANA:
+ aAllSubsets.emplace_back( 0x3040, 0x309F, SvxResId(RID_SUBSETSTR_HIRAGANA) );
+ break;
+ case UBLOCK_KATAKANA:
+ aAllSubsets.emplace_back( 0x30A0, 0x30FF, SvxResId(RID_SUBSETSTR_KATAKANA) );
+ break;
+ case UBLOCK_BOPOMOFO:
+ aAllSubsets.emplace_back( 0x3100, 0x312F, SvxResId(RID_SUBSETSTR_BOPOMOFO) );
+ break;
+ case UBLOCK_HANGUL_COMPATIBILITY_JAMO:
+ aAllSubsets.emplace_back( 0x3130, 0x318F, SvxResId(RID_SUBSETSTR_HANGUL_COMPAT_JAMO) );
+ break;
+ case UBLOCK_KANBUN:
+ aAllSubsets.emplace_back( 0x3190, 0x319F, SvxResId(RID_SUBSETSTR_KANBUN) );
+ break;
+ case UBLOCK_BOPOMOFO_EXTENDED:
+ aAllSubsets.emplace_back( 0x31A0, 0x31BF, SvxResId(RID_SUBSETSTR_BOPOMOFO_EXTENDED) );
+ break;
+ case UBLOCK_ENCLOSED_CJK_LETTERS_AND_MONTHS:
+ aAllSubsets.emplace_back( 0x3200, 0x32FF, SvxResId(RID_SUBSETSTR_ENCLOSED_CJK_LETTERS) );
+ break;
+ case UBLOCK_CJK_COMPATIBILITY:
+ aAllSubsets.emplace_back( 0x3300, 0x33FF, SvxResId(RID_SUBSETSTR_CJK_COMPATIBILITY) );
+ break;
+ case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A:
+ aAllSubsets.emplace_back( 0x3400, 0x4DBF, SvxResId(RID_SUBSETSTR_CJK_EXT_A_UNIFIED_IDGRAPH) );
+ break;
+ case UBLOCK_CJK_UNIFIED_IDEOGRAPHS:
+ aAllSubsets.emplace_back( 0x4E00, 0x9FA5, SvxResId(RID_SUBSETSTR_CJK_UNIFIED_IDGRAPH) );
+ break;
+ case UBLOCK_YI_SYLLABLES:
+ aAllSubsets.emplace_back( 0xA000, 0xA48F, SvxResId(RID_SUBSETSTR_YI_SYLLABLES) );
+ break;
+ case UBLOCK_YI_RADICALS:
+ aAllSubsets.emplace_back( 0xA490, 0xA4CF, SvxResId(RID_SUBSETSTR_YI_RADICALS) );
+ break;
+ case UBLOCK_HANGUL_SYLLABLES:
+ aAllSubsets.emplace_back( 0xAC00, 0xD7AF, SvxResId(RID_SUBSETSTR_HANGUL) );
+ break;
+ case UBLOCK_PRIVATE_USE_AREA:
+ aAllSubsets.emplace_back( 0xE000, 0xF8FF, SvxResId(RID_SUBSETSTR_PRIVATE_USE_AREA) );
+ break;
+ case UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS:
+ aAllSubsets.emplace_back( 0xF900, 0xFAFF, SvxResId(RID_SUBSETSTR_CJK_COMPAT_IDGRAPHS) );
+ break;
+ case UBLOCK_ALPHABETIC_PRESENTATION_FORMS:
+ aAllSubsets.emplace_back( 0xFB00, 0xFB4F, SvxResId(RID_SUBSETSTR_ALPHA_PRESENTATION) );
+ break;
+ case UBLOCK_ARABIC_PRESENTATION_FORMS_A:
+ aAllSubsets.emplace_back( 0xFB50, 0xFDFF, SvxResId(RID_SUBSETSTR_ARABIC_PRESENT_A) );
+ break;
+ case UBLOCK_COMBINING_HALF_MARKS:
+ aAllSubsets.emplace_back( 0xFE20, 0xFE2F, SvxResId(RID_SUBSETSTR_COMBINING_HALF_MARKS) );
+ break;
+ case UBLOCK_CJK_COMPATIBILITY_FORMS:
+ aAllSubsets.emplace_back( 0xFE30, 0xFE4F, SvxResId(RID_SUBSETSTR_CJK_COMPAT_FORMS) );
+ break;
+ case UBLOCK_SMALL_FORM_VARIANTS:
+ aAllSubsets.emplace_back( 0xFE50, 0xFE6F, SvxResId(RID_SUBSETSTR_SMALL_FORM_VARIANTS) );
+ break;
+ case UBLOCK_ARABIC_PRESENTATION_FORMS_B:
+ aAllSubsets.emplace_back( 0xFE70, 0xFEFF, SvxResId(RID_SUBSETSTR_ARABIC_PRESENT_B) );
+ break;
+ case UBLOCK_SPECIALS:
+ aAllSubsets.emplace_back( 0xFFF0, 0xFFFF, SvxResId(RID_SUBSETSTR_SPECIALS) );
+ break;
+ case UBLOCK_HALFWIDTH_AND_FULLWIDTH_FORMS:
+ aAllSubsets.emplace_back( 0xFF00, 0xFFEF, SvxResId(RID_SUBSETSTR_HALFW_FULLW_FORMS) );
+ break;
+ case UBLOCK_OLD_ITALIC:
+ aAllSubsets.emplace_back( 0x10300, 0x1032F, SvxResId(RID_SUBSETSTR_OLD_ITALIC) );
+ break;
+ case UBLOCK_GOTHIC:
+ aAllSubsets.emplace_back( 0x10330, 0x1034F, SvxResId(RID_SUBSETSTR_GOTHIC) );
+ break;
+ case UBLOCK_DESERET:
+ aAllSubsets.emplace_back( 0x10400, 0x1044F, SvxResId(RID_SUBSETSTR_DESERET) );
+ break;
+ case UBLOCK_BYZANTINE_MUSICAL_SYMBOLS:
+ aAllSubsets.emplace_back( 0x1D000, 0x1D0FF, SvxResId(RID_SUBSETSTR_BYZANTINE_MUSICAL_SYMBOLS) );
+ break;
+ case UBLOCK_MUSICAL_SYMBOLS:
+ aAllSubsets.emplace_back( 0x1D100, 0x1D1FF, SvxResId(RID_SUBSETSTR_MUSICAL_SYMBOLS) );
+ break;
+ case UBLOCK_MATHEMATICAL_ALPHANUMERIC_SYMBOLS:
+ aAllSubsets.emplace_back( 0x1D400, 0x1D7FF, SvxResId(RID_SUBSETSTR_MATHEMATICAL_ALPHANUMERIC_SYMBOLS) );
+ break;
+ case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B:
+ aAllSubsets.emplace_back( 0x20000, 0x2A6DF, SvxResId(RID_SUBSETSTR_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B) );
+ break;
+ case UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT:
+ aAllSubsets.emplace_back( 0x2F800, 0x2FA1F, SvxResId(RID_SUBSETSTR_CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT) );
+ break;
+ case UBLOCK_TAGS:
+ aAllSubsets.emplace_back( 0xE0000, 0xE007F, SvxResId(RID_SUBSETSTR_TAGS) );
+ break;
+ case UBLOCK_CYRILLIC_SUPPLEMENTARY:
+ aAllSubsets.emplace_back( 0x0500, 0x052F, SvxResId(RID_SUBSETSTR_CYRILLIC_SUPPLEMENTARY) );
+ break;
+ case UBLOCK_TAGALOG:
+ aAllSubsets.emplace_back( 0x1700, 0x171F, SvxResId(RID_SUBSETSTR_TAGALOG) );
+ break;
+ case UBLOCK_HANUNOO:
+ aAllSubsets.emplace_back( 0x1720, 0x173F, SvxResId(RID_SUBSETSTR_HANUNOO) );
+ break;
+ case UBLOCK_BUHID:
+ aAllSubsets.emplace_back( 0x1740, 0x175F, SvxResId(RID_SUBSETSTR_BUHID) );
+ break;
+ case UBLOCK_TAGBANWA:
+ aAllSubsets.emplace_back( 0x1760, 0x177F, SvxResId(RID_SUBSETSTR_TAGBANWA) );
+ break;
+ case UBLOCK_MISCELLANEOUS_MATHEMATICAL_SYMBOLS_A:
+ aAllSubsets.emplace_back( 0x27C0, 0x27EF, SvxResId(RID_SUBSETSTR_MISC_MATH_SYMS_A) );
+ break;
+ case UBLOCK_SUPPLEMENTAL_ARROWS_A:
+ aAllSubsets.emplace_back( 0x27F0, 0x27FF, SvxResId(RID_SUBSETSTR_SUPPL_ARROWS_A) );
+ break;
+ case UBLOCK_SUPPLEMENTAL_ARROWS_B:
+ aAllSubsets.emplace_back( 0x2900, 0x297F, SvxResId(RID_SUBSETSTR_SUPPL_ARROWS_B) );
+ break;
+ case UBLOCK_MISCELLANEOUS_MATHEMATICAL_SYMBOLS_B:
+ aAllSubsets.emplace_back( 0x2980, 0x29FF, SvxResId(RID_SUBSETSTR_MISC_MATH_SYMS_B) );
+ break;
+ case UBLOCK_SUPPLEMENTAL_MATHEMATICAL_OPERATORS:
+ aAllSubsets.emplace_back( 0x2A00, 0x2AFF, SvxResId(RID_SUBSETSTR_MISC_MATH_SYMS_B) );
+ break;
+ case UBLOCK_KATAKANA_PHONETIC_EXTENSIONS:
+ aAllSubsets.emplace_back( 0x31F0, 0x31FF, SvxResId(RID_SUBSETSTR_KATAKANA_PHONETIC) );
+ break;
+ case UBLOCK_VARIATION_SELECTORS:
+ aAllSubsets.emplace_back( 0xFE00, 0xFE0F, SvxResId(RID_SUBSETSTR_VARIATION_SELECTORS) );
+ break;
+ case UBLOCK_SUPPLEMENTARY_PRIVATE_USE_AREA_A:
+ aAllSubsets.emplace_back( 0xF0000, 0xFFFFF, SvxResId(RID_SUBSETSTR_SUPPLEMENTARY_PRIVATE_USE_AREA_A) );
+ break;
+ case UBLOCK_SUPPLEMENTARY_PRIVATE_USE_AREA_B:
+ aAllSubsets.emplace_back( 0x100000, 0x10FFFF, SvxResId(RID_SUBSETSTR_SUPPLEMENTARY_PRIVATE_USE_AREA_B) );
+ break;
+ case UBLOCK_LIMBU:
+ aAllSubsets.emplace_back( 0x1900, 0x194F, SvxResId(RID_SUBSETSTR_LIMBU) );
+ break;
+ case UBLOCK_TAI_LE:
+ aAllSubsets.emplace_back( 0x1950, 0x197F, SvxResId(RID_SUBSETSTR_TAI_LE) );
+ break;
+ case UBLOCK_KHMER_SYMBOLS:
+ aAllSubsets.emplace_back( 0x19E0, 0x19FF, SvxResId(RID_SUBSETSTR_KHMER_SYMBOLS) );
+ break;
+ case UBLOCK_PHONETIC_EXTENSIONS:
+ aAllSubsets.emplace_back( 0x1D00, 0x1D7F, SvxResId(RID_SUBSETSTR_PHONETIC_EXTENSIONS) );
+ break;
+ case UBLOCK_MISCELLANEOUS_SYMBOLS_AND_ARROWS:
+ aAllSubsets.emplace_back( 0x2B00, 0x2BFF, SvxResId(RID_SUBSETSTR_MISCELLANEOUS_SYMBOLS_AND_ARROWS) );
+ break;
+ case UBLOCK_YIJING_HEXAGRAM_SYMBOLS:
+ aAllSubsets.emplace_back( 0x4DC0, 0x4DFF, SvxResId(RID_SUBSETSTR_YIJING_HEXAGRAM_SYMBOLS) );
+ break;
+ case UBLOCK_LINEAR_B_SYLLABARY:
+ aAllSubsets.emplace_back( 0x10000, 0x1007F, SvxResId(RID_SUBSETSTR_LINEAR_B_SYLLABARY) );
+ break;
+ case UBLOCK_LINEAR_B_IDEOGRAMS:
+ aAllSubsets.emplace_back( 0x10080, 0x100FF, SvxResId(RID_SUBSETSTR_LINEAR_B_IDEOGRAMS) );
+ break;
+ case UBLOCK_AEGEAN_NUMBERS:
+ aAllSubsets.emplace_back( 0x10100, 0x1013F, SvxResId(RID_SUBSETSTR_AEGEAN_NUMBERS) );
+ break;
+ case UBLOCK_UGARITIC:
+ aAllSubsets.emplace_back( 0x10380, 0x1039F, SvxResId(RID_SUBSETSTR_UGARITIC) );
+ break;
+ case UBLOCK_SHAVIAN:
+ aAllSubsets.emplace_back( 0x10450, 0x1047F, SvxResId(RID_SUBSETSTR_SHAVIAN) );
+ break;
+ case UBLOCK_OSMANYA:
+ aAllSubsets.emplace_back( 0x10480, 0x104AF, SvxResId(RID_SUBSETSTR_OSMANYA) );
+ break;
+ case UBLOCK_CYPRIOT_SYLLABARY:
+ aAllSubsets.emplace_back( 0x10800, 0x1083F, SvxResId(RID_SUBSETSTR_CYPRIOT_SYLLABARY) );
+ break;
+ case UBLOCK_TAI_XUAN_JING_SYMBOLS:
+ aAllSubsets.emplace_back( 0x1D300, 0x1D35F, SvxResId(RID_SUBSETSTR_TAI_XUAN_JING_SYMBOLS) );
+ break;
+ case UBLOCK_VARIATION_SELECTORS_SUPPLEMENT:
+ aAllSubsets.emplace_back( 0xE0100, 0xE01EF, SvxResId(RID_SUBSETSTR_VARIATION_SELECTORS_SUPPLEMENT) );
+ break;
+ case UBLOCK_ANCIENT_GREEK_MUSICAL_NOTATION:
+ aAllSubsets.emplace_back(0x1D200, 0x1D24F, SvxResId(RID_SUBSETSTR_ANCIENT_GREEK_MUSICAL_NOTATION) );
+ break;
+ case UBLOCK_ANCIENT_GREEK_NUMBERS:
+ aAllSubsets.emplace_back(0x10140, 0x1018F , SvxResId(RID_SUBSETSTR_ANCIENT_GREEK_NUMBERS) );
+ break;
+ case UBLOCK_ARABIC_SUPPLEMENT:
+ aAllSubsets.emplace_back(0x0750, 0x077F , SvxResId(RID_SUBSETSTR_ARABIC_SUPPLEMENT) );
+ break;
+ case UBLOCK_BUGINESE:
+ aAllSubsets.emplace_back(0x1A00, 0x1A1F , SvxResId(RID_SUBSETSTR_BUGINESE) );
+ break;
+ case UBLOCK_CJK_STROKES:
+ aAllSubsets.emplace_back( 0x31C0, 0x31EF, SvxResId(RID_SUBSETSTR_CJK_STROKES) );
+ break;
+ case UBLOCK_COMBINING_DIACRITICAL_MARKS_SUPPLEMENT:
+ aAllSubsets.emplace_back( 0x1DC0, 0x1DFF , SvxResId(RID_SUBSETSTR_COMBINING_DIACRITICAL_MARKS_SUPPLEMENT) );
+ break;
+ case UBLOCK_COPTIC:
+ aAllSubsets.emplace_back( 0x2C80, 0x2CFF , SvxResId(RID_SUBSETSTR_COPTIC) );
+ break;
+ case UBLOCK_ETHIOPIC_EXTENDED:
+ aAllSubsets.emplace_back( 0x2D80, 0x2DDF , SvxResId(RID_SUBSETSTR_ETHIOPIC_EXTENDED) );
+ break;
+ case UBLOCK_ETHIOPIC_SUPPLEMENT:
+ aAllSubsets.emplace_back( 0x1380, 0x139F, SvxResId(RID_SUBSETSTR_ETHIOPIC_SUPPLEMENT) );
+ break;
+ case UBLOCK_GEORGIAN_SUPPLEMENT:
+ aAllSubsets.emplace_back( 0x2D00, 0x2D2F, SvxResId(RID_SUBSETSTR_GEORGIAN_SUPPLEMENT) );
+ break;
+ case UBLOCK_GLAGOLITIC:
+ aAllSubsets.emplace_back( 0x2C00, 0x2C5F, SvxResId(RID_SUBSETSTR_GLAGOLITIC) );
+ break;
+ case UBLOCK_KHAROSHTHI:
+ aAllSubsets.emplace_back( 0x10A00, 0x10A5F, SvxResId(RID_SUBSETSTR_KHAROSHTHI) );
+ break;
+ case UBLOCK_MODIFIER_TONE_LETTERS:
+ aAllSubsets.emplace_back( 0xA700, 0xA71F, SvxResId(RID_SUBSETSTR_MODIFIER_TONE_LETTERS) );
+ break;
+ case UBLOCK_NEW_TAI_LUE:
+ aAllSubsets.emplace_back( 0x1980, 0x19DF, SvxResId(RID_SUBSETSTR_NEW_TAI_LUE) );
+ break;
+ case UBLOCK_OLD_PERSIAN:
+ aAllSubsets.emplace_back( 0x103A0, 0x103DF, SvxResId(RID_SUBSETSTR_OLD_PERSIAN) );
+ break;
+ case UBLOCK_PHONETIC_EXTENSIONS_SUPPLEMENT:
+ aAllSubsets.emplace_back( 0x1D80, 0x1DBF, SvxResId(RID_SUBSETSTR_PHONETIC_EXTENSIONS_SUPPLEMENT) );
+ break;
+ case UBLOCK_SUPPLEMENTAL_PUNCTUATION:
+ aAllSubsets.emplace_back( 0x2E00, 0x2E7F, SvxResId(RID_SUBSETSTR_SUPPLEMENTAL_PUNCTUATION) );
+ break;
+ case UBLOCK_SYLOTI_NAGRI:
+ aAllSubsets.emplace_back( 0xA800, 0xA82F, SvxResId(RID_SUBSETSTR_SYLOTI_NAGRI) );
+ break;
+ case UBLOCK_TIFINAGH:
+ aAllSubsets.emplace_back( 0x2D30, 0x2D7F, SvxResId(RID_SUBSETSTR_TIFINAGH) );
+ break;
+ case UBLOCK_VERTICAL_FORMS:
+ aAllSubsets.emplace_back( 0xFE10, 0xFE1F, SvxResId(RID_SUBSETSTR_VERTICAL_FORMS) );
+ break;
+ case UBLOCK_NKO:
+ aAllSubsets.emplace_back( 0x07C0, 0x07FF, SvxResId(RID_SUBSETSTR_NKO) );
+ break;
+ case UBLOCK_BALINESE:
+ aAllSubsets.emplace_back( 0x1B00, 0x1B7F, SvxResId(RID_SUBSETSTR_BALINESE) );
+ break;
+ case UBLOCK_LATIN_EXTENDED_C:
+ aAllSubsets.emplace_back( 0x2C60, 0x2C7F, SvxResId(RID_SUBSETSTR_LATIN_EXTENDED_C) );
+ break;
+ case UBLOCK_LATIN_EXTENDED_D:
+ aAllSubsets.emplace_back( 0xA720, 0xA7FF, SvxResId(RID_SUBSETSTR_LATIN_EXTENDED_D) );
+ break;
+ case UBLOCK_PHAGS_PA:
+ aAllSubsets.emplace_back( 0xA840, 0xA87F, SvxResId(RID_SUBSETSTR_PHAGS_PA) );
+ break;
+ case UBLOCK_PHOENICIAN:
+ aAllSubsets.emplace_back( 0x10900, 0x1091F, SvxResId(RID_SUBSETSTR_PHOENICIAN) );
+ break;
+ case UBLOCK_CUNEIFORM:
+ aAllSubsets.emplace_back( 0x12000, 0x123FF, SvxResId(RID_SUBSETSTR_CUNEIFORM) );
+ break;
+ case UBLOCK_CUNEIFORM_NUMBERS_AND_PUNCTUATION:
+ aAllSubsets.emplace_back( 0x12400, 0x1247F, SvxResId(RID_SUBSETSTR_CUNEIFORM_NUMBERS_AND_PUNCTUATION) );
+ break;
+ case UBLOCK_COUNTING_ROD_NUMERALS:
+ aAllSubsets.emplace_back( 0x1D360, 0x1D37F, SvxResId(RID_SUBSETSTR_COUNTING_ROD_NUMERALS) );
+ break;
+ case UBLOCK_SUNDANESE:
+ aAllSubsets.emplace_back( 0x1B80, 0x1BBF, SvxResId(RID_SUBSETSTR_SUNDANESE) );
+ break;
+ case UBLOCK_LEPCHA:
+ aAllSubsets.emplace_back( 0x1C00, 0x1C4F, SvxResId(RID_SUBSETSTR_LEPCHA) );
+ break;
+ case UBLOCK_OL_CHIKI:
+ aAllSubsets.emplace_back( 0x1C50, 0x1C7F, SvxResId(RID_SUBSETSTR_OL_CHIKI) );
+ break;
+ case UBLOCK_CYRILLIC_EXTENDED_A:
+ aAllSubsets.emplace_back( 0x2DE0, 0x2DFF, SvxResId(RID_SUBSETSTR_CYRILLIC_EXTENDED_A) );
+ break;
+ case UBLOCK_VAI:
+ aAllSubsets.emplace_back( 0xA500, 0xA63F, SvxResId(RID_SUBSETSTR_VAI) );
+ break;
+ case UBLOCK_CYRILLIC_EXTENDED_B:
+ aAllSubsets.emplace_back( 0xA640, 0xA69F, SvxResId(RID_SUBSETSTR_CYRILLIC_EXTENDED_B) );
+ break;
+ case UBLOCK_SAURASHTRA:
+ aAllSubsets.emplace_back( 0xA880, 0xA8DF, SvxResId(RID_SUBSETSTR_SAURASHTRA) );
+ break;
+ case UBLOCK_KAYAH_LI:
+ aAllSubsets.emplace_back( 0xA900, 0xA92F, SvxResId(RID_SUBSETSTR_KAYAH_LI) );
+ break;
+ case UBLOCK_REJANG:
+ aAllSubsets.emplace_back( 0xA930, 0xA95F, SvxResId(RID_SUBSETSTR_REJANG) );
+ break;
+ case UBLOCK_CHAM:
+ aAllSubsets.emplace_back( 0xAA00, 0xAA5F, SvxResId(RID_SUBSETSTR_CHAM) );
+ break;
+ case UBLOCK_ANCIENT_SYMBOLS:
+ aAllSubsets.emplace_back( 0x10190, 0x101CF, SvxResId(RID_SUBSETSTR_ANCIENT_SYMBOLS) );
+ break;
+ case UBLOCK_PHAISTOS_DISC:
+ aAllSubsets.emplace_back( 0x101D0, 0x101FF, SvxResId(RID_SUBSETSTR_PHAISTOS_DISC) );
+ break;
+ case UBLOCK_LYCIAN:
+ aAllSubsets.emplace_back( 0x10280, 0x1029F, SvxResId(RID_SUBSETSTR_LYCIAN) );
+ break;
+ case UBLOCK_CARIAN:
+ aAllSubsets.emplace_back( 0x102A0, 0x102DF, SvxResId(RID_SUBSETSTR_CARIAN) );
+ break;
+ case UBLOCK_LYDIAN:
+ aAllSubsets.emplace_back( 0x10920, 0x1093F, SvxResId(RID_SUBSETSTR_LYDIAN) );
+ break;
+ case UBLOCK_MAHJONG_TILES:
+ aAllSubsets.emplace_back( 0x1F000, 0x1F02F, SvxResId(RID_SUBSETSTR_MAHJONG_TILES) );
+ break;
+ case UBLOCK_DOMINO_TILES:
+ aAllSubsets.emplace_back( 0x1F030, 0x1F09F, SvxResId(RID_SUBSETSTR_DOMINO_TILES) );
+ break;
+ case UBLOCK_SAMARITAN:
+ aAllSubsets.emplace_back( 0x0800, 0x083F, SvxResId(RID_SUBSETSTR_SAMARITAN) );
+ break;
+ case UBLOCK_UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS_EXTENDED:
+ aAllSubsets.emplace_back( 0x18B0, 0x18FF, SvxResId(RID_SUBSETSTR_UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS_EXTENDED) );
+ break;
+ case UBLOCK_TAI_THAM:
+ aAllSubsets.emplace_back( 0x1A20, 0x1AAF, SvxResId(RID_SUBSETSTR_TAI_THAM) );
+ break;
+ case UBLOCK_VEDIC_EXTENSIONS:
+ aAllSubsets.emplace_back( 0x1CD0, 0x1CFF, SvxResId(RID_SUBSETSTR_VEDIC_EXTENSIONS) );
+ break;
+ case UBLOCK_LISU:
+ aAllSubsets.emplace_back( 0xA4D0, 0xA4FF, SvxResId(RID_SUBSETSTR_LISU) );
+ break;
+ case UBLOCK_BAMUM:
+ aAllSubsets.emplace_back( 0xA6A0, 0xA6FF, SvxResId(RID_SUBSETSTR_BAMUM) );
+ break;
+ case UBLOCK_COMMON_INDIC_NUMBER_FORMS:
+ aAllSubsets.emplace_back( 0xA830, 0xA83F, SvxResId(RID_SUBSETSTR_COMMON_INDIC_NUMBER_FORMS) );
+ break;
+ case UBLOCK_DEVANAGARI_EXTENDED:
+ aAllSubsets.emplace_back( 0xA8E0, 0xA8FF, SvxResId(RID_SUBSETSTR_DEVANAGARI_EXTENDED) );
+ break;
+ case UBLOCK_HANGUL_JAMO_EXTENDED_A:
+ aAllSubsets.emplace_back( 0xA960, 0xA97F, SvxResId(RID_SUBSETSTR_HANGUL_JAMO_EXTENDED_A) );
+ break;
+ case UBLOCK_JAVANESE:
+ aAllSubsets.emplace_back( 0xA980, 0xA9DF, SvxResId(RID_SUBSETSTR_JAVANESE) );
+ break;
+ case UBLOCK_MYANMAR_EXTENDED_A:
+ aAllSubsets.emplace_back( 0xAA60, 0xAA7F, SvxResId(RID_SUBSETSTR_MYANMAR_EXTENDED_A) );
+ break;
+ case UBLOCK_TAI_VIET:
+ aAllSubsets.emplace_back( 0xAA80, 0xAADF, SvxResId(RID_SUBSETSTR_TAI_VIET) );
+ break;
+ case UBLOCK_MEETEI_MAYEK:
+ aAllSubsets.emplace_back( 0xABC0, 0xABFF, SvxResId(RID_SUBSETSTR_MEETEI_MAYEK) );
+ break;
+ case UBLOCK_HANGUL_JAMO_EXTENDED_B:
+ aAllSubsets.emplace_back( 0xD7B0, 0xD7FF, SvxResId(RID_SUBSETSTR_HANGUL_JAMO_EXTENDED_B) );
+ break;
+ case UBLOCK_IMPERIAL_ARAMAIC:
+ aAllSubsets.emplace_back( 0x10840, 0x1085F, SvxResId(RID_SUBSETSTR_IMPERIAL_ARAMAIC) );
+ break;
+ case UBLOCK_OLD_SOUTH_ARABIAN:
+ aAllSubsets.emplace_back( 0x10A60, 0x10A7F, SvxResId(RID_SUBSETSTR_OLD_SOUTH_ARABIAN) );
+ break;
+ case UBLOCK_AVESTAN:
+ aAllSubsets.emplace_back( 0x10B00, 0x10B3F, SvxResId(RID_SUBSETSTR_AVESTAN) );
+ break;
+ case UBLOCK_INSCRIPTIONAL_PARTHIAN:
+ aAllSubsets.emplace_back( 0x10B40, 0x10B5F, SvxResId(RID_SUBSETSTR_INSCRIPTIONAL_PARTHIAN) );
+ break;
+ case UBLOCK_INSCRIPTIONAL_PAHLAVI:
+ aAllSubsets.emplace_back( 0x10B60, 0x10B7F, SvxResId(RID_SUBSETSTR_INSCRIPTIONAL_PAHLAVI) );
+ break;
+ case UBLOCK_OLD_TURKIC:
+ aAllSubsets.emplace_back( 0x10C00, 0x10C4F, SvxResId(RID_SUBSETSTR_OLD_TURKIC) );
+ break;
+ case UBLOCK_RUMI_NUMERAL_SYMBOLS:
+ aAllSubsets.emplace_back( 0x10E60, 0x10E7F, SvxResId(RID_SUBSETSTR_RUMI_NUMERAL_SYMBOLS) );
+ break;
+ case UBLOCK_KAITHI:
+ aAllSubsets.emplace_back( 0x11080, 0x110CF, SvxResId(RID_SUBSETSTR_KAITHI) );
+ break;
+ case UBLOCK_EGYPTIAN_HIEROGLYPHS:
+ aAllSubsets.emplace_back( 0x13000, 0x1342F, SvxResId(RID_SUBSETSTR_EGYPTIAN_HIEROGLYPHS) );
+ break;
+ case UBLOCK_ENCLOSED_ALPHANUMERIC_SUPPLEMENT:
+ aAllSubsets.emplace_back( 0x1F100, 0x1F1FF, SvxResId(RID_SUBSETSTR_ENCLOSED_ALPHANUMERIC_SUPPLEMENT) );
+ break;
+ case UBLOCK_ENCLOSED_IDEOGRAPHIC_SUPPLEMENT:
+ aAllSubsets.emplace_back( 0x1F200, 0x1F2FF, SvxResId(RID_SUBSETSTR_ENCLOSED_IDEOGRAPHIC_SUPPLEMENT) );
+ break;
+ case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_C:
+ aAllSubsets.emplace_back( 0x2A700, 0x2B73F, SvxResId(RID_SUBSETSTR_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_C) );
+ break;
+ case UBLOCK_MANDAIC:
+ aAllSubsets.emplace_back( 0x0840, 0x085F, SvxResId(RID_SUBSETSTR_MANDAIC) );
+ break;
+ case UBLOCK_BATAK:
+ aAllSubsets.emplace_back( 0x1BC0, 0x1BFF, SvxResId(RID_SUBSETSTR_BATAK) );
+ break;
+ case UBLOCK_ETHIOPIC_EXTENDED_A:
+ aAllSubsets.emplace_back( 0xAB00, 0xAB2F, SvxResId(RID_SUBSETSTR_ETHIOPIC_EXTENDED_A) );
+ break;
+ case UBLOCK_BRAHMI:
+ aAllSubsets.emplace_back( 0x11000, 0x1107F, SvxResId(RID_SUBSETSTR_BRAHMI) );
+ break;
+ case UBLOCK_BAMUM_SUPPLEMENT:
+ aAllSubsets.emplace_back( 0x16800, 0x16A3F, SvxResId(RID_SUBSETSTR_BAMUM_SUPPLEMENT) );
+ break;
+ case UBLOCK_KANA_SUPPLEMENT:
+ aAllSubsets.emplace_back( 0x1B000, 0x1B0FF, SvxResId(RID_SUBSETSTR_KANA_SUPPLEMENT) );
+ break;
+ case UBLOCK_PLAYING_CARDS:
+ aAllSubsets.emplace_back( 0x1F0A0, 0x1F0FF, SvxResId(RID_SUBSETSTR_PLAYING_CARDS) );
+ break;
+ case UBLOCK_MISCELLANEOUS_SYMBOLS_AND_PICTOGRAPHS:
+ aAllSubsets.emplace_back( 0x1F300, 0x1F5FF, SvxResId(RID_SUBSETSTR_MISCELLANEOUS_SYMBOLS_AND_PICTOGRAPHS) );
+ break;
+ case UBLOCK_EMOTICONS:
+ aAllSubsets.emplace_back( 0x1F600, 0x1F64F, SvxResId(RID_SUBSETSTR_EMOTICONS) );
+ break;
+ case UBLOCK_TRANSPORT_AND_MAP_SYMBOLS:
+ aAllSubsets.emplace_back( 0x1F680, 0x1F6FF, SvxResId(RID_SUBSETSTR_TRANSPORT_AND_MAP_SYMBOLS) );
+ break;
+ case UBLOCK_ALCHEMICAL_SYMBOLS:
+ aAllSubsets.emplace_back( 0x1F700, 0x1F77F, SvxResId(RID_SUBSETSTR_ALCHEMICAL_SYMBOLS) );
+ break;
+ case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_D:
+ aAllSubsets.emplace_back( 0x2B740, 0x2B81F, SvxResId(RID_SUBSETSTR_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_D) );
+ break;
+ case UBLOCK_ARABIC_EXTENDED_A:
+ aAllSubsets.emplace_back( 0x08A0, 0x08FF, SvxResId(RID_SUBSETSTR_ARABIC_EXTENDED_A) );
+ break;
+ case UBLOCK_ARABIC_MATHEMATICAL_ALPHABETIC_SYMBOLS:
+ aAllSubsets.emplace_back( 0x1EE00, 0x1EEFF, SvxResId(RID_SUBSETSTR_ARABIC_MATHEMATICAL_ALPHABETIC_SYMBOLS) );
+ break;
+ case UBLOCK_CHAKMA:
+ aAllSubsets.emplace_back( 0x11100, 0x1114F, SvxResId(RID_SUBSETSTR_CHAKMA) );
+ break;
+ case UBLOCK_MEETEI_MAYEK_EXTENSIONS:
+ aAllSubsets.emplace_back( 0xAAE0, 0xAAFF, SvxResId(RID_SUBSETSTR_MEETEI_MAYEK_EXTENSIONS) );
+ break;
+ case UBLOCK_MEROITIC_CURSIVE:
+ aAllSubsets.emplace_back( 0x109A0, 0x109FF, SvxResId(RID_SUBSETSTR_MEROITIC_CURSIVE) );
+ break;
+ case UBLOCK_MEROITIC_HIEROGLYPHS:
+ aAllSubsets.emplace_back( 0x10980, 0x1099F, SvxResId(RID_SUBSETSTR_MEROITIC_HIEROGLYPHS) );
+ break;
+ case UBLOCK_MIAO:
+ aAllSubsets.emplace_back( 0x16F00, 0x16F9F, SvxResId(RID_SUBSETSTR_MIAO) );
+ break;
+ case UBLOCK_SHARADA:
+ aAllSubsets.emplace_back( 0x11180, 0x111DF, SvxResId(RID_SUBSETSTR_SHARADA) );
+ break;
+ case UBLOCK_SORA_SOMPENG:
+ aAllSubsets.emplace_back( 0x110D0, 0x110FF, SvxResId(RID_SUBSETSTR_SORA_SOMPENG) );
+ break;
+ case UBLOCK_SUNDANESE_SUPPLEMENT:
+ aAllSubsets.emplace_back( 0x1CC0, 0x1CCF, SvxResId(RID_SUBSETSTR_SUNDANESE_SUPPLEMENT) );
+ break;
+ case UBLOCK_TAKRI:
+ aAllSubsets.emplace_back( 0x11680, 0x116CF, SvxResId(RID_SUBSETSTR_TAKRI) );
+ break;
+ case UBLOCK_BASSA_VAH:
+ aAllSubsets.emplace_back( 0x16AD0, 0x16AFF, SvxResId(RID_SUBSETSTR_BASSA_VAH) );
+ break;
+ case UBLOCK_CAUCASIAN_ALBANIAN:
+ aAllSubsets.emplace_back( 0x10530, 0x1056F, SvxResId(RID_SUBSETSTR_CAUCASIAN_ALBANIAN) );
+ break;
+ case UBLOCK_COPTIC_EPACT_NUMBERS:
+ aAllSubsets.emplace_back( 0x102E0, 0x102FF, SvxResId(RID_SUBSETSTR_COPTIC_EPACT_NUMBERS) );
+ break;
+ case UBLOCK_COMBINING_DIACRITICAL_MARKS_EXTENDED:
+ aAllSubsets.emplace_back( 0x1AB0, 0x1AFF, SvxResId(RID_SUBSETSTR_COMBINING_DIACRITICAL_MARKS_EXTENDED) );
+ break;
+ case UBLOCK_DUPLOYAN:
+ aAllSubsets.emplace_back( 0x1BC00, 0x1BC9F, SvxResId(RID_SUBSETSTR_DUPLOYAN) );
+ break;
+ case UBLOCK_ELBASAN:
+ aAllSubsets.emplace_back( 0x10500, 0x1052F, SvxResId(RID_SUBSETSTR_ELBASAN) );
+ break;
+ case UBLOCK_GEOMETRIC_SHAPES_EXTENDED:
+ aAllSubsets.emplace_back( 0x1F780, 0x1F7FF, SvxResId(RID_SUBSETSTR_GEOMETRIC_SHAPES_EXTENDED) );
+ break;
+ case UBLOCK_GRANTHA:
+ aAllSubsets.emplace_back( 0x11300, 0x1137F, SvxResId(RID_SUBSETSTR_GRANTHA) );
+ break;
+ case UBLOCK_KHOJKI:
+ aAllSubsets.emplace_back( 0x11200, 0x1124F, SvxResId(RID_SUBSETSTR_KHOJKI) );
+ break;
+ case UBLOCK_KHUDAWADI:
+ aAllSubsets.emplace_back( 0x112B0, 0x112FF, SvxResId(RID_SUBSETSTR_KHUDAWADI) );
+ break;
+ case UBLOCK_LATIN_EXTENDED_E:
+ aAllSubsets.emplace_back( 0xAB30, 0xAB6F, SvxResId(RID_SUBSETSTR_LATIN_EXTENDED_E) );
+ break;
+ case UBLOCK_LINEAR_A:
+ aAllSubsets.emplace_back( 0x10600, 0x1077F, SvxResId(RID_SUBSETSTR_LINEAR_A) );
+ break;
+ case UBLOCK_MAHAJANI:
+ aAllSubsets.emplace_back( 0x11150, 0x1117F, SvxResId(RID_SUBSETSTR_MAHAJANI) );
+ break;
+ case UBLOCK_MANICHAEAN:
+ aAllSubsets.emplace_back( 0x10AC0, 0x10AFF, SvxResId(RID_SUBSETSTR_MANICHAEAN) );
+ break;
+ case UBLOCK_MENDE_KIKAKUI:
+ aAllSubsets.emplace_back( 0x1E800, 0x1E8DF, SvxResId(RID_SUBSETSTR_MENDE_KIKAKUI) );
+ break;
+ case UBLOCK_MODI:
+ aAllSubsets.emplace_back( 0x11600, 0x1165F, SvxResId(RID_SUBSETSTR_MODI) );
+ break;
+ case UBLOCK_MRO:
+ aAllSubsets.emplace_back( 0x16A40, 0x16A6F, SvxResId(RID_SUBSETSTR_MRO) );
+ break;
+ case UBLOCK_MYANMAR_EXTENDED_B:
+ aAllSubsets.emplace_back( 0xA9E0, 0xA9FF, SvxResId(RID_SUBSETSTR_MYANMAR_EXTENDED_B) );
+ break;
+ case UBLOCK_NABATAEAN:
+ aAllSubsets.emplace_back( 0x10880, 0x108AF, SvxResId(RID_SUBSETSTR_NABATAEAN) );
+ break;
+ case UBLOCK_OLD_NORTH_ARABIAN:
+ aAllSubsets.emplace_back( 0x10A80, 0x10A9F, SvxResId(RID_SUBSETSTR_OLD_NORTH_ARABIAN) );
+ break;
+ case UBLOCK_OLD_PERMIC:
+ aAllSubsets.emplace_back( 0x10350, 0x1037F, SvxResId(RID_SUBSETSTR_OLD_PERMIC) );
+ break;
+ case UBLOCK_ORNAMENTAL_DINGBATS:
+ aAllSubsets.emplace_back( 0x1F650, 0x1F67F, SvxResId(RID_SUBSETSTR_ORNAMENTAL_DINGBATS) );
+ break;
+ case UBLOCK_PAHAWH_HMONG:
+ aAllSubsets.emplace_back( 0x16B00, 0x16B8F, SvxResId(RID_SUBSETSTR_PAHAWH_HMONG) );
+ break;
+ case UBLOCK_PALMYRENE:
+ aAllSubsets.emplace_back( 0x10860, 0x1087F, SvxResId(RID_SUBSETSTR_PALMYRENE) );
+ break;
+ case UBLOCK_PAU_CIN_HAU:
+ aAllSubsets.emplace_back( 0x11AC0, 0x11AFF, SvxResId(RID_SUBSETSTR_PAU_CIN_HAU) );
+ break;
+ case UBLOCK_PSALTER_PAHLAVI:
+ aAllSubsets.emplace_back( 0x10B80, 0x10BAF, SvxResId(RID_SUBSETSTR_PSALTER_PAHLAVI) );
+ break;
+ case UBLOCK_SHORTHAND_FORMAT_CONTROLS:
+ aAllSubsets.emplace_back( 0x1BCA0, 0x1BCAF, SvxResId(RID_SUBSETSTR_SHORTHAND_FORMAT_CONTROLS) );
+ break;
+ case UBLOCK_SIDDHAM:
+ aAllSubsets.emplace_back( 0x11580, 0x115FF, SvxResId(RID_SUBSETSTR_SIDDHAM) );
+ break;
+ case UBLOCK_SINHALA_ARCHAIC_NUMBERS:
+ aAllSubsets.emplace_back( 0x111E0, 0x111FF, SvxResId(RID_SUBSETSTR_SINHALA_ARCHAIC_NUMBERS) );
+ break;
+ case UBLOCK_SUPPLEMENTAL_ARROWS_C:
+ aAllSubsets.emplace_back( 0x1F800, 0x1F8FF, SvxResId(RID_SUBSETSTR_SUPPLEMENTAL_ARROWS_C) );
+ break;
+ case UBLOCK_TIRHUTA:
+ aAllSubsets.emplace_back( 0x11480, 0x114DF, SvxResId(RID_SUBSETSTR_TIRHUTA) );
+ break;
+ case UBLOCK_WARANG_CITI:
+ aAllSubsets.emplace_back( 0x118A0, 0x118FF, SvxResId(RID_SUBSETSTR_WARANG_CITI) );
+ break;
+ case UBLOCK_AHOM:
+ aAllSubsets.emplace_back( 0x11700, 0x1173F, SvxResId(RID_SUBSETSTR_AHOM) );
+ break;
+ case UBLOCK_ANATOLIAN_HIEROGLYPHS:
+ aAllSubsets.emplace_back( 0x14400, 0x1467F, SvxResId(RID_SUBSETSTR_ANATOLIAN_HIEROGLYPHS) );
+ break;
+ case UBLOCK_CHEROKEE_SUPPLEMENT:
+ aAllSubsets.emplace_back( 0xAB70, 0xABBF, SvxResId(RID_SUBSETSTR_CHEROKEE_SUPPLEMENT) );
+ break;
+ case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_E:
+ aAllSubsets.emplace_back( 0x2B820, 0x2CEAF, SvxResId(RID_SUBSETSTR_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_E) );
+ break;
+ case UBLOCK_EARLY_DYNASTIC_CUNEIFORM:
+ aAllSubsets.emplace_back( 0x12480, 0x1254F, SvxResId(RID_SUBSETSTR_EARLY_DYNASTIC_CUNEIFORM) );
+ break;
+ case UBLOCK_HATRAN:
+ aAllSubsets.emplace_back( 0x108E0, 0x108FF, SvxResId(RID_SUBSETSTR_HATRAN) );
+ break;
+ case UBLOCK_MULTANI:
+ aAllSubsets.emplace_back( 0x11280, 0x112AF, SvxResId(RID_SUBSETSTR_MULTANI) );
+ break;
+ case UBLOCK_OLD_HUNGARIAN:
+ aAllSubsets.emplace_back( 0x10C80, 0x10CFF, SvxResId(RID_SUBSETSTR_OLD_HUNGARIAN) );
+ break;
+ case UBLOCK_SUPPLEMENTAL_SYMBOLS_AND_PICTOGRAPHS:
+ aAllSubsets.emplace_back( 0x1F900, 0x1F9FF, SvxResId(RID_SUBSETSTR_SUPPLEMENTAL_SYMBOLS_AND_PICTOGRAPHS) );
+ break;
+ case UBLOCK_SUTTON_SIGNWRITING:
+ aAllSubsets.emplace_back( 0x1D800, 0x1DAAF, SvxResId(RID_SUBSETSTR_SUTTON_SIGNWRITING) );
+ break;
+ case UBLOCK_ADLAM:
+ aAllSubsets.emplace_back( 0x1E900, 0x1E95F, SvxResId(RID_SUBSETSTR_ADLAM) );
+ break;
+ case UBLOCK_BHAIKSUKI:
+ aAllSubsets.emplace_back( 0x11C00, 0x11C6F, SvxResId(RID_SUBSETSTR_BHAIKSUKI) );
+ break;
+ case UBLOCK_CYRILLIC_EXTENDED_C:
+ aAllSubsets.emplace_back( 0x1C80, 0x1C8F, SvxResId(RID_SUBSETSTR_CYRILLIC_EXTENDED_C) );
+ break;
+ case UBLOCK_GLAGOLITIC_SUPPLEMENT:
+ aAllSubsets.emplace_back( 0x1E000, 0x1E02F, SvxResId(RID_SUBSETSTR_GLAGOLITIC_SUPPLEMENT) );
+ break;
+ case UBLOCK_IDEOGRAPHIC_SYMBOLS_AND_PUNCTUATION:
+ aAllSubsets.emplace_back( 0x16FE0, 0x16FFF, SvxResId(RID_SUBSETSTR_IDEOGRAPHIC_SYMBOLS_AND_PUNCTUATION) );
+ break;
+ case UBLOCK_MARCHEN:
+ aAllSubsets.emplace_back( 0x11C70, 0x11CBF, SvxResId(RID_SUBSETSTR_MARCHEN) );
+ break;
+ case UBLOCK_MONGOLIAN_SUPPLEMENT:
+ aAllSubsets.emplace_back( 0x11660, 0x1167F, SvxResId(RID_SUBSETSTR_MONGOLIAN_SUPPLEMENT) );
+ break;
+ case UBLOCK_NEWA:
+ aAllSubsets.emplace_back( 0x11400, 0x1147F, SvxResId(RID_SUBSETSTR_NEWA) );
+ break;
+ case UBLOCK_OSAGE:
+ aAllSubsets.emplace_back( 0x104B0, 0x104FF, SvxResId(RID_SUBSETSTR_OSAGE) );
+ break;
+ case UBLOCK_TANGUT:
+ aAllSubsets.emplace_back( 0x17000, 0x187FF, SvxResId(RID_SUBSETSTR_TANGUT) );
+ break;
+ case UBLOCK_TANGUT_COMPONENTS:
+ aAllSubsets.emplace_back( 0x18800, 0x18AFF, SvxResId(RID_SUBSETSTR_TANGUT_COMPONENTS) );
+ break;
+ case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_F:
+ aAllSubsets.emplace_back( 0x2CEB0, 0x2EBE0, SvxResId(RID_SUBSETSTR_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_F) );
+ break;
+ case UBLOCK_KANA_EXTENDED_A:
+ aAllSubsets.emplace_back( 0x1B100, 0x1B12F, SvxResId(RID_SUBSETSTR_KANA_EXTENDED_A) );
+ break;
+ case UBLOCK_MASARAM_GONDI:
+ aAllSubsets.emplace_back( 0x11D00, 0x11D5F, SvxResId(RID_SUBSETSTR_MASARAM_GONDI) );
+ break;
+ case UBLOCK_NUSHU:
+ aAllSubsets.emplace_back( 0x1B170, 0x1B2FF, SvxResId(RID_SUBSETSTR_NUSHU) );
+ break;
+ case UBLOCK_SOYOMBO:
+ aAllSubsets.emplace_back( 0x11A50, 0x11AAF, SvxResId(RID_SUBSETSTR_SOYOMBO) );
+ break;
+ case UBLOCK_SYRIAC_SUPPLEMENT:
+ aAllSubsets.emplace_back( 0x0860, 0x086f, SvxResId(RID_SUBSETSTR_SYRIAC_SUPPLEMENT) );
+ break;
+ case UBLOCK_ZANABAZAR_SQUARE:
+ aAllSubsets.emplace_back( 0x11A00, 0x11A4F, SvxResId(RID_SUBSETSTR_ZANABAZAR_SQUARE) );
+ break;
+ case UBLOCK_CHESS_SYMBOLS:
+ aAllSubsets.emplace_back( 0x1FA00, 0x1FA6F, SvxResId(RID_SUBSETSTR_CHESS_SYMBOLS) );
+ break;
+ case UBLOCK_DOGRA:
+ aAllSubsets.emplace_back( 0x11800, 0x1184F, SvxResId(RID_SUBSETSTR_DOGRA) );
+ break;
+ case UBLOCK_GEORGIAN_EXTENDED:
+ aAllSubsets.emplace_back( 0x1C90, 0x1CBF, SvxResId(RID_SUBSETSTR_GEORGIAN_EXTENDED) );
+ break;
+ case UBLOCK_GUNJALA_GONDI:
+ aAllSubsets.emplace_back( 0x11D60, 0x11DAF, SvxResId(RID_SUBSETSTR_GUNJALA_GONDI) );
+ break;
+ case UBLOCK_HANIFI_ROHINGYA:
+ aAllSubsets.emplace_back( 0x10D00, 0x10D3F, SvxResId(RID_SUBSETSTR_HANIFI_ROHINGYA) );
+ break;
+ case UBLOCK_INDIC_SIYAQ_NUMBERS:
+ aAllSubsets.emplace_back( 0x1EC70, 0x1ECBF, SvxResId(RID_SUBSETSTR_INDIC_SIYAQ_NUMBERS) );
+ break;
+ case UBLOCK_MAKASAR:
+ aAllSubsets.emplace_back( 0x11EE0, 0x11EFF, SvxResId(RID_SUBSETSTR_MAKASAR) );
+ break;
+ case UBLOCK_MAYAN_NUMERALS:
+ aAllSubsets.emplace_back( 0x1D2E0, 0x1D2FF, SvxResId(RID_SUBSETSTR_MAYAN_NUMERALS) );
+ break;
+ case UBLOCK_MEDEFAIDRIN:
+ aAllSubsets.emplace_back( 0x16E40, 0x16E9F, SvxResId(RID_SUBSETSTR_MEDEFAIDRIN) );
+ break;
+ case UBLOCK_OLD_SOGDIAN:
+ aAllSubsets.emplace_back( 0x10F00, 0x10F2F, SvxResId(RID_SUBSETSTR_OLD_SOGDIAN) );
+ break;
+ case UBLOCK_SOGDIAN:
+ aAllSubsets.emplace_back( 0x10F30, 0x10F6F, SvxResId(RID_SUBSETSTR_SOGDIAN) );
+ break;
+ case UBLOCK_EGYPTIAN_HIEROGLYPH_FORMAT_CONTROLS:
+ aAllSubsets.emplace_back( 0x13430, 0x1343F, SvxResId(RID_SUBSETSTR_EGYPTIAN_HIEROGLYPH_FORMAT_CONTROLS) );
+ break;
+ case UBLOCK_ELYMAIC:
+ aAllSubsets.emplace_back( 0x10FE0, 0x10FFF, SvxResId(RID_SUBSETSTR_ELYMAIC) );
+ break;
+ case UBLOCK_NANDINAGARI:
+ aAllSubsets.emplace_back( 0x119A0, 0x119FF, SvxResId(RID_SUBSETSTR_NANDINAGARI) );
+ break;
+ case UBLOCK_NYIAKENG_PUACHUE_HMONG:
+ aAllSubsets.emplace_back( 0x1E100, 0x1E14F, SvxResId(RID_SUBSETSTR_NYIAKENG_PUACHUE_HMONG) );
+ break;
+ case UBLOCK_OTTOMAN_SIYAQ_NUMBERS:
+ aAllSubsets.emplace_back( 0x1ED00, 0x1ED4F, SvxResId(RID_SUBSETSTR_OTTOMAN_SIYAQ_NUMBERS) );
+ break;
+ case UBLOCK_SMALL_KANA_EXTENSION:
+ aAllSubsets.emplace_back( 0x1B130, 0x1B16F, SvxResId(RID_SUBSETSTR_SMALL_KANA_EXTENSION) );
+ break;
+ case UBLOCK_SYMBOLS_AND_PICTOGRAPHS_EXTENDED_A:
+ aAllSubsets.emplace_back( 0x1FA70, 0x1FAFF, SvxResId(RID_SUBSETSTR_SYMBOLS_AND_PICTOGRAPHS_EXTENDED_A) );
+ break;
+ case UBLOCK_TAMIL_SUPPLEMENT:
+ aAllSubsets.emplace_back( 0x11FC0, 0x11FFF, SvxResId(RID_SUBSETSTR_TAMIL_SUPPLEMENT) );
+ break;
+ case UBLOCK_WANCHO:
+ aAllSubsets.emplace_back( 0x1E2C0, 0x1E2FF, SvxResId(RID_SUBSETSTR_WANCHO) );
+ break;
+ case UBLOCK_CHORASMIAN:
+ aAllSubsets.emplace_back( 0x10FB0, 0x10FDF, SvxResId(RID_SUBSETSTR_CHORASMIAN) );
+ break;
+ case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_G:
+ aAllSubsets.emplace_back( 0x30000, 0x3134F, SvxResId(RID_SUBSETSTR_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_G) );
+ break;
+ case UBLOCK_DIVES_AKURU:
+ aAllSubsets.emplace_back( 0x11900, 0x1195F, SvxResId(RID_SUBSETSTR_DIVES_AKURU) );
+ break;
+ case UBLOCK_KHITAN_SMALL_SCRIPT:
+ aAllSubsets.emplace_back( 0x18B00, 0x18CFF, SvxResId(RID_SUBSETSTR_KHITAN_SMALL_SCRIPT) );
+ break;
+ case UBLOCK_LISU_SUPPLEMENT:
+ aAllSubsets.emplace_back( 0x11FB0, 0x11FBF, SvxResId(RID_SUBSETSTR_LISU_SUPPLEMENT) );
+ break;
+ case UBLOCK_SYMBOLS_FOR_LEGACY_COMPUTING:
+ aAllSubsets.emplace_back( 0x1FB00, 0x1FBFF, SvxResId(RID_SUBSETSTR_SYMBOLS_FOR_LEGACY_COMPUTING) );
+ break;
+ case UBLOCK_TANGUT_SUPPLEMENT:
+ aAllSubsets.emplace_back( 0x18D00, 0x18D7F, SvxResId(RID_SUBSETSTR_TANGUT_SUPPLEMENT) );
+ break;
+ case UBLOCK_YEZIDI:
+ aAllSubsets.emplace_back( 0x10E80, 0x10EBF, SvxResId(RID_SUBSETSTR_YEZIDI) );
+ break;
+#if (U_ICU_VERSION_MAJOR_NUM >= 70)
+ case UBLOCK_ARABIC_EXTENDED_B:
+ aAllSubsets.emplace_back( 0x0870, 0x089F, SvxResId(RID_SUBSETSTR_ARABIC_EXTENDED_B) );
+ break;
+ case UBLOCK_CYPRO_MINOAN:
+ aAllSubsets.emplace_back( 0x12F90, 0x12FFF, SvxResId(RID_SUBSETSTR_CYPRO_MINOAN) );
+ break;
+ case UBLOCK_ETHIOPIC_EXTENDED_B:
+ aAllSubsets.emplace_back( 0x1E7E0, 0x1E7FF, SvxResId(RID_SUBSETSTR_ETHIOPIC_EXTENDED_B) );
+ break;
+ case UBLOCK_KANA_EXTENDED_B:
+ aAllSubsets.emplace_back( 0x1AFF0, 0x1AFFF, SvxResId(RID_SUBSETSTR_KANA_EXTENDED_B) );
+ break;
+ case UBLOCK_LATIN_EXTENDED_F:
+ aAllSubsets.emplace_back( 0x10780, 0x107BF, SvxResId(RID_SUBSETSTR_LATIN_EXTENDED_F) );
+ break;
+ case UBLOCK_LATIN_EXTENDED_G:
+ aAllSubsets.emplace_back( 0x1DF00, 0x1DFFF, SvxResId(RID_SUBSETSTR_LATIN_EXTENDED_G) );
+ break;
+ case UBLOCK_OLD_UYGHUR:
+ aAllSubsets.emplace_back( 0x10F70, 0x10FAF, SvxResId(RID_SUBSETSTR_OLD_UYGHUR) );
+ break;
+ case UBLOCK_TANGSA:
+ aAllSubsets.emplace_back( 0x16A70, 0x16ACF, SvxResId(RID_SUBSETSTR_TANGSA) );
+ break;
+ case UBLOCK_TOTO:
+ aAllSubsets.emplace_back( 0x1E290, 0x1E2BF, SvxResId(RID_SUBSETSTR_TOTO) );
+ break;
+ case UBLOCK_UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS_EXTENDED_A:
+ aAllSubsets.emplace_back( 0x11AB0, 0x11ABF, SvxResId(RID_SUBSETSTR_UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS_EXTENDED_A) );
+ break;
+ case UBLOCK_VITHKUQI:
+ aAllSubsets.emplace_back( 0x10570, 0x105BF, SvxResId(RID_SUBSETSTR_VITHKUQI) );
+ break;
+ case UBLOCK_ZNAMENNY_MUSICAL_NOTATION:
+ aAllSubsets.emplace_back( 0x1CF00, 0x1CFCF, SvxResId(RID_SUBSETSTR_ZNAMENNY_MUSICAL_NOTATION) );
+ break;
+#endif
+#if (U_ICU_VERSION_MAJOR_NUM >= 72)
+ case UBLOCK_ARABIC_EXTENDED_C:
+ aAllSubsets.emplace_back( 0x10EC0, 0x10EFF, SvxResId(RID_SUBSETSTR_ARABIC_EXTENDED_C) );
+ break;
+ case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_H:
+ aAllSubsets.emplace_back( 0x31350, 0x323AF, SvxResId(RID_SUBSETSTR_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_H) );
+ break;
+ case UBLOCK_CYRILLIC_EXTENDED_D:
+ aAllSubsets.emplace_back( 0x1E030, 0x1E08F, SvxResId(RID_SUBSETSTR_CYRILLIC_EXTENDED_D) );
+ break;
+ case UBLOCK_DEVANAGARI_EXTENDED_A:
+ aAllSubsets.emplace_back( 0x11B00, 0x11B5F, SvxResId(RID_SUBSETSTR_DEVANAGARI_EXTENDED_A) );
+ break;
+ case UBLOCK_KAKTOVIK_NUMERALS:
+ aAllSubsets.emplace_back( 0x1D2C0, 0x1D2DF, SvxResId(RID_SUBSETSTR_KAKTOVIK_NUMERALS) );
+ break;
+ case UBLOCK_KAWI:
+ aAllSubsets.emplace_back( 0x11F00, 0x11F5F, SvxResId(RID_SUBSETSTR_KAWI) );
+ break;
+ case UBLOCK_NAG_MUNDARI:
+ aAllSubsets.emplace_back( 0x1E4D0, 0x1E4FF, SvxResId(RID_SUBSETSTR_NAG_MUNDARI) );
+ break;
+#endif
+ }
+
+#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
+ if (eBlock != UBLOCK_NO_BLOCK &&
+ eBlock != UBLOCK_INVALID_CODE &&
+ eBlock != UBLOCK_COUNT &&
+ eBlock != UBLOCK_HIGH_SURROGATES &&
+ eBlock != UBLOCK_HIGH_PRIVATE_USE_SURROGATES &&
+ eBlock != UBLOCK_LOW_SURROGATES)
+
+ {
+ UBlockCode eBlockStart = ublock_getCode(aAllSubsets.back().GetRangeMin());
+ UBlockCode eBlockEnd = ublock_getCode(aAllSubsets.back().GetRangeMax());
+ assert(eBlockStart == eBlockEnd && eBlockStart == eBlock);
+ }
+#endif
+ }
+
+ std::stable_sort(aAllSubsets.begin(), aAllSubsets.end());
+ return aAllSubsets;
+ }();
+
+ maSubsets = s_aAllSubsets;
+}
+
+void SubsetMap::ApplyCharMap( const FontCharMapRef& rxFontCharMap )
+{
+ if( !rxFontCharMap.is() )
+ return;
+
+ // remove subsets that are not matched in any range
+ std::erase_if(maSubsets,
+ [&rxFontCharMap](const Subset& rSubset) {
+ sal_uInt32 cMin = rSubset.GetRangeMin();
+ sal_uInt32 cMax = rSubset.GetRangeMax();
+ int nCount = rxFontCharMap->CountCharsInRange( cMin, cMax );
+ return nCount <= 0;
+ });
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/compressgraphicdialog.cxx b/svx/source/dialog/compressgraphicdialog.cxx
new file mode 100644
index 0000000000..8fcf479d88
--- /dev/null
+++ b/svx/source/dialog/compressgraphicdialog.cxx
@@ -0,0 +1,456 @@
+/* -*- 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 "dlgunit.hxx"
+#include <utility>
+#include <vcl/fieldvalues.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/graphicfilter.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/weld.hxx>
+#include <svx/strings.hrc>
+#include <svx/svdograf.hxx>
+#include <svx/sdgcpitm.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/graphichelper.hxx>
+#include <svx/compressgraphicdialog.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/module.hxx>
+#include <comphelper/fileformat.h>
+#include <comphelper/propertyvalue.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <tools/stream.hxx>
+#include <unotools/localedatawrapper.hxx>
+
+// tdf#146929 - remember user settings within the current session
+// memp is filled in dtor and restored after initialization
+namespace
+{
+ struct memParam {
+ bool ReduceResolutionCB = false;
+ int MFNewWidth = 1;
+ int MFNewHeight = 1;
+ bool LosslessRB = true;
+ bool JpegCompRB = false;
+ int CompressionMF = 6;
+ int QualityMF = 80;
+ int InterpolationCombo = 3;
+ };
+ memParam memp;
+}
+
+using namespace com::sun::star::uno;
+using namespace com::sun::star::beans;
+
+CompressGraphicsDialog::CompressGraphicsDialog( weld::Window* pParent, SdrGrafObj* pGraphicObj, SfxBindings& rBindings ) :
+ GenericDialogController( pParent, "svx/ui/compressgraphicdialog.ui", "CompressGraphicDialog" ),
+ m_xGraphicObj ( pGraphicObj ),
+ m_aGraphic ( pGraphicObj->GetGraphicObject().GetGraphic() ),
+ m_aViewSize100mm ( pGraphicObj->GetLogicRect().GetSize() ),
+ m_rBindings ( rBindings ),
+ m_dResolution ( 300 )
+{
+ const SdrGrafCropItem& rCrop = m_xGraphicObj->GetMergedItem(SDRATTR_GRAFCROP);
+ m_aCropRectangle = tools::Rectangle(rCrop.GetLeft(), rCrop.GetTop(), rCrop.GetRight(), rCrop.GetBottom());
+
+ Initialize();
+ recallParameter();
+}
+
+CompressGraphicsDialog::CompressGraphicsDialog( weld::Window* pParent, Graphic aGraphic, Size rViewSize100mm, tools::Rectangle const & rCropRectangle, SfxBindings& rBindings ) :
+ GenericDialogController( pParent, "svx/ui/compressgraphicdialog.ui", "CompressGraphicDialog" ),
+ m_xGraphicObj ( nullptr ),
+ m_aGraphic (std::move( aGraphic )),
+ m_aViewSize100mm ( rViewSize100mm ),
+ m_aCropRectangle ( rCropRectangle ),
+ m_rBindings ( rBindings ),
+ m_dResolution ( 300 )
+{
+ Initialize();
+ recallParameter();
+}
+
+CompressGraphicsDialog::~CompressGraphicsDialog()
+{
+}
+
+void CompressGraphicsDialog::recallParameter()
+{
+ m_xReduceResolutionCB->set_active( memp.ReduceResolutionCB );
+ if (memp.ReduceResolutionCB && (memp.MFNewWidth > 1))
+ m_xMFNewWidth->set_value( memp.MFNewWidth );
+ if (memp.ReduceResolutionCB && (memp.MFNewHeight > 1))
+ m_xMFNewHeight->set_value( memp.MFNewHeight );
+
+ m_xLosslessRB->set_active( memp.LosslessRB );
+ m_xJpegCompRB->set_active( memp.JpegCompRB );
+ m_xCompressionMF->set_value( memp.CompressionMF );
+ m_xCompressionSlider->set_value( memp.CompressionMF );
+ m_xQualityMF->set_value( memp.QualityMF );
+ m_xQualitySlider->set_value( memp.QualityMF );
+
+ m_xInterpolationCombo->set_active( memp.InterpolationCombo );
+}
+
+void CompressGraphicsDialog::Initialize()
+{
+ m_xLabelGraphicType = m_xBuilder->weld_label("label-graphic-type");
+ m_xFixedText2 = m_xBuilder->weld_label("label-original-size");
+ m_xFixedText3 = m_xBuilder->weld_label("label-view-size");
+ m_xFixedText5 = m_xBuilder->weld_label("label-image-capacity");
+ m_xFixedText6 = m_xBuilder->weld_label("label-new-capacity");
+ m_xJpegCompRB = m_xBuilder->weld_radio_button("radio-jpeg");
+ m_xCompressionMF = m_xBuilder->weld_spin_button("spin-compression");
+ m_xCompressionSlider = m_xBuilder->weld_scale("scale-compression");
+ m_xLosslessRB = m_xBuilder->weld_radio_button("radio-lossless");
+ m_xQualityMF = m_xBuilder->weld_spin_button("spin-quality");
+ m_xQualitySlider = m_xBuilder->weld_scale("scale-quality");
+ m_xReduceResolutionCB = m_xBuilder->weld_check_button("checkbox-reduce-resolution");
+ m_xMFNewWidth = m_xBuilder->weld_spin_button("spin-new-width");
+ m_xMFNewHeight = m_xBuilder->weld_spin_button("spin-new-height");
+ m_xResolutionLB = m_xBuilder->weld_combo_box("combo-resolution");
+ m_xBtnCalculate = m_xBuilder->weld_button("calculate");
+ m_xInterpolationCombo = m_xBuilder->weld_combo_box("interpolation-method-combo");
+ m_xBtnOkay = m_xBuilder->weld_button("ok");
+
+ m_xInterpolationCombo->set_active_text("Lanczos");
+
+ m_xInterpolationCombo->connect_changed(LINK(this, CompressGraphicsDialog, NewInterpolationModifiedHdl));
+
+ m_xMFNewWidth->connect_value_changed( LINK( this, CompressGraphicsDialog, NewWidthModifiedHdl ));
+ m_xMFNewHeight->connect_value_changed( LINK( this, CompressGraphicsDialog, NewHeightModifiedHdl ));
+
+ m_xResolutionLB->connect_changed( LINK( this, CompressGraphicsDialog, ResolutionModifiedHdl ));
+ m_xBtnCalculate->connect_clicked( LINK( this, CompressGraphicsDialog, CalculateClickHdl ) );
+
+ m_xLosslessRB->connect_toggled( LINK( this, CompressGraphicsDialog, ToggleCompressionRB ) );
+ m_xJpegCompRB->connect_toggled( LINK( this, CompressGraphicsDialog, ToggleCompressionRB ) );
+
+ m_xReduceResolutionCB->connect_toggled( LINK( this, CompressGraphicsDialog, ToggleReduceResolutionRB ) );
+
+ m_xQualitySlider->connect_value_changed( LINK( this, CompressGraphicsDialog, SlideHdl ));
+ m_xCompressionSlider->connect_value_changed( LINK( this, CompressGraphicsDialog, SlideHdl ));
+ m_xQualityMF->connect_value_changed( LINK( this, CompressGraphicsDialog, NewQualityModifiedHdl ));
+ m_xCompressionMF->connect_value_changed( LINK( this, CompressGraphicsDialog, NewCompressionModifiedHdl ));
+
+ m_xJpegCompRB->set_active(true);
+ m_xReduceResolutionCB->set_active(true);
+
+ m_xBtnOkay->connect_clicked( LINK( this, CompressGraphicsDialog, OkayClickHdl ) );
+ UpdateNewWidthMF();
+ UpdateNewHeightMF();
+ UpdateResolutionLB();
+ Update();
+}
+
+void CompressGraphicsDialog::Update()
+{
+ auto pGfxLink = m_aGraphic.GetSharedGfxLink();
+
+ m_xLabelGraphicType->set_label(GraphicHelper::GetImageType(m_aGraphic));
+
+ const FieldUnit eFieldUnit = m_rBindings.GetDispatcher()->GetModule()->GetFieldUnit();
+ const LocaleDataWrapper& rLocaleWrapper( Application::GetSettings().GetLocaleDataWrapper() );
+ sal_Unicode cSeparator = rLocaleWrapper.getNumDecimalSep()[0];
+
+ ScopedVclPtrInstance<VirtualDevice> pDummyVDev;
+ pDummyVDev->EnableOutput( false );
+ pDummyVDev->SetMapMode( m_aGraphic.GetPrefMapMode() );
+
+ Size aPixelSize = m_aGraphic.GetSizePixel();
+ Size aOriginalSize100mm(pDummyVDev->PixelToLogic(m_aGraphic.GetSizePixel(), MapMode(MapUnit::Map100thMM)));
+
+ OUString aBitmapSizeString = SvxResId(STR_IMAGE_ORIGINAL_SIZE);
+ OUString aWidthString = GetUnitString( aOriginalSize100mm.Width(), eFieldUnit, cSeparator );
+ OUString aHeightString = GetUnitString( aOriginalSize100mm.Height(), eFieldUnit, cSeparator );
+ aBitmapSizeString = aBitmapSizeString.replaceAll("$(WIDTH)", aWidthString);
+ aBitmapSizeString = aBitmapSizeString.replaceAll("$(HEIGHT)", aHeightString);
+ aBitmapSizeString = aBitmapSizeString.replaceAll("$(WIDTH_IN_PX)", OUString::number(aPixelSize.Width()));
+ aBitmapSizeString = aBitmapSizeString.replaceAll("$(HEIGHT_IN_PX)", OUString::number(aPixelSize.Height()));
+ m_xFixedText2->set_label(aBitmapSizeString);
+
+ int aValX = static_cast<int>(aPixelSize.Width() / GetViewWidthInch());
+
+ OUString aViewSizeString = SvxResId(STR_IMAGE_VIEW_SIZE);
+
+ aWidthString = GetUnitString( m_aViewSize100mm.Width(), eFieldUnit, cSeparator );
+ aHeightString = GetUnitString( m_aViewSize100mm.Height(), eFieldUnit, cSeparator );
+ aViewSizeString = aViewSizeString.replaceAll("$(WIDTH)", aWidthString);
+ aViewSizeString = aViewSizeString.replaceAll("$(HEIGHT)", aHeightString);
+ aViewSizeString = aViewSizeString.replaceAll("$(DPI)", OUString::number(aValX));
+ m_xFixedText3->set_label(aViewSizeString);
+
+ m_aNativeSize = pGfxLink ? pGfxLink->GetDataSize() : 0;
+
+ OUString aNativeSizeString = SvxResId(STR_IMAGE_CAPACITY);
+ aNativeSizeString = aNativeSizeString.replaceAll("$(CAPACITY)", OUString::number( m_aNativeSize / 1024 ));
+ m_xFixedText5->set_label(aNativeSizeString);
+
+ m_xFixedText6->set_label("??");
+}
+
+void CompressGraphicsDialog::UpdateNewWidthMF()
+{
+ int nPixelX = static_cast<sal_Int32>( GetViewWidthInch() * m_dResolution );
+ m_xMFNewWidth->set_value(nPixelX);
+}
+
+void CompressGraphicsDialog::UpdateNewHeightMF()
+{
+ int nPixelY = static_cast<sal_Int32>( GetViewHeightInch() * m_dResolution );
+ m_xMFNewHeight->set_value(nPixelY);
+}
+
+void CompressGraphicsDialog::UpdateResolutionLB()
+{
+ m_xResolutionLB->set_entry_text( OUString::number( static_cast<sal_Int32>(m_dResolution) ) );
+}
+
+double CompressGraphicsDialog::GetViewWidthInch() const
+{
+ return static_cast<double>(vcl::ConvertValue(m_aViewSize100mm.Width(), 2, MapUnit::Map100thMM, FieldUnit::INCH)) / 100.0;
+}
+
+double CompressGraphicsDialog::GetViewHeightInch() const
+{
+ return static_cast<double>(vcl::ConvertValue(m_aViewSize100mm.Height(), 2, MapUnit::Map100thMM, FieldUnit::INCH)) / 100.0;
+}
+
+BmpScaleFlag CompressGraphicsDialog::GetSelectedInterpolationType() const
+{
+ OUString aSelectionText = m_xInterpolationCombo->get_active_text();
+
+ if( aSelectionText == "Lanczos" ) {
+ return BmpScaleFlag::Lanczos;
+ } else if( aSelectionText == "Bilinear" ) {
+ return BmpScaleFlag::BiLinear;
+ } else if( aSelectionText == "Bicubic" ) {
+ return BmpScaleFlag::BiCubic;
+ } else if ( aSelectionText == "None" ) {
+ return BmpScaleFlag::Fast;
+ }
+ return BmpScaleFlag::BestQuality;
+}
+
+void CompressGraphicsDialog::Compress(SvStream& aStream)
+{
+ BitmapEx aBitmap = m_aGraphic.GetBitmapEx();
+ if ( m_xReduceResolutionCB->get_active() )
+ {
+ tools::Long nPixelX = static_cast<tools::Long>( GetViewWidthInch() * m_dResolution );
+ tools::Long nPixelY = static_cast<tools::Long>( GetViewHeightInch() * m_dResolution );
+
+ aBitmap.Scale( Size( nPixelX, nPixelY ), GetSelectedInterpolationType() );
+ }
+ Graphic aScaledGraphic( aBitmap );
+ GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
+
+ Sequence< PropertyValue > aFilterData{
+ comphelper::makePropertyValue("Interlaced", sal_Int32(0)),
+ comphelper::makePropertyValue("Compression", static_cast<sal_Int32>(m_xCompressionMF->get_value())),
+ comphelper::makePropertyValue("Quality", static_cast<sal_Int32>(m_xQualityMF->get_value()))
+ };
+
+ OUString aGraphicFormatName = m_xLosslessRB->get_active() ? OUString( "png" ) : OUString( "jpg" );
+
+ sal_uInt16 nFilterFormat = rFilter.GetExportFormatNumberForShortName( aGraphicFormatName );
+ rFilter.ExportGraphic( aScaledGraphic, u"none", aStream, nFilterFormat, &aFilterData );
+}
+
+IMPL_LINK_NOARG( CompressGraphicsDialog, OkayClickHdl, weld::Button&, void )
+{
+ memp.ReduceResolutionCB = m_xReduceResolutionCB->get_active();
+ memp.MFNewWidth = m_xMFNewWidth->get_value();
+ memp.MFNewHeight = m_xMFNewHeight->get_value();
+ memp.LosslessRB = m_xLosslessRB->get_active();
+ memp.JpegCompRB = m_xJpegCompRB->get_active();
+ memp.CompressionMF = m_xCompressionMF->get_value();
+ memp.QualityMF = m_xQualityMF->get_value();
+ memp.InterpolationCombo = m_xInterpolationCombo->get_active();
+ CompressGraphicsDialog::response(RET_OK);
+}
+
+IMPL_LINK_NOARG( CompressGraphicsDialog, NewWidthModifiedHdl, weld::SpinButton&, void )
+{
+ m_dResolution = m_xMFNewWidth->get_value() / GetViewWidthInch();
+
+ UpdateNewHeightMF();
+ UpdateResolutionLB();
+ Update();
+}
+
+IMPL_LINK( CompressGraphicsDialog, SlideHdl, weld::Scale&, rScale, void )
+{
+ if (&rScale == m_xQualitySlider.get())
+ m_xQualityMF->set_value(m_xQualitySlider->get_value());
+ else
+ m_xCompressionMF->set_value(m_xCompressionSlider->get_value());
+ Update();
+}
+
+IMPL_LINK_NOARG( CompressGraphicsDialog, NewInterpolationModifiedHdl, weld::ComboBox&, void )
+{
+ Update();
+}
+
+IMPL_LINK_NOARG( CompressGraphicsDialog, NewQualityModifiedHdl, weld::SpinButton&, void )
+{
+ m_xQualitySlider->set_value(m_xQualityMF->get_value());
+ Update();
+}
+
+IMPL_LINK_NOARG( CompressGraphicsDialog, NewCompressionModifiedHdl, weld::SpinButton&, void )
+{
+ m_xCompressionSlider->set_value(m_xCompressionMF->get_value());
+ Update();
+}
+
+IMPL_LINK_NOARG( CompressGraphicsDialog, NewHeightModifiedHdl, weld::SpinButton&, void )
+{
+ m_dResolution = m_xMFNewHeight->get_value() / GetViewHeightInch();
+
+ UpdateNewWidthMF();
+ UpdateResolutionLB();
+ Update();
+}
+
+IMPL_LINK_NOARG( CompressGraphicsDialog, ResolutionModifiedHdl, weld::ComboBox&, void )
+{
+ m_dResolution = static_cast<double>(m_xResolutionLB->get_active_text().toInt32());
+
+ UpdateNewWidthMF();
+ UpdateNewHeightMF();
+ Update();
+}
+
+IMPL_LINK_NOARG( CompressGraphicsDialog, ToggleCompressionRB, weld::Toggleable&, void )
+{
+ bool choice = m_xLosslessRB->get_active();
+ m_xCompressionMF->set_sensitive(choice);
+ m_xCompressionSlider->set_sensitive(choice);
+ m_xQualityMF->set_sensitive(!choice);
+ m_xQualitySlider->set_sensitive(!choice);
+ Update();
+}
+
+IMPL_LINK_NOARG( CompressGraphicsDialog, ToggleReduceResolutionRB, weld::Toggleable&, void )
+{
+ bool choice = m_xReduceResolutionCB->get_active();
+ m_xMFNewWidth->set_sensitive(choice);
+ m_xMFNewHeight->set_sensitive(choice);
+ m_xResolutionLB->set_sensitive(choice);
+ m_xInterpolationCombo->set_sensitive(choice);
+ Update();
+}
+
+IMPL_LINK_NOARG( CompressGraphicsDialog, CalculateClickHdl, weld::Button&, void )
+{
+ sal_Int32 aSize = 0;
+
+ if ( m_dResolution > 0.0 )
+ {
+ SvMemoryStream aMemStream;
+ aMemStream.SetVersion( SOFFICE_FILEFORMAT_CURRENT );
+ Compress( aMemStream );
+ aSize = aMemStream.TellEnd();
+ }
+
+ if ( aSize > 0 )
+ {
+ OUString aSizeAsString = OUString::number(aSize / 1024);
+
+ OUString aReductionSizeAsString;
+ if (m_aNativeSize > 0 )
+ aReductionSizeAsString = OUString::number( static_cast<sal_Int32>((m_aNativeSize - aSize) * 100.0 / m_aNativeSize) );
+ else
+ aReductionSizeAsString = "0";
+
+ OUString aNewSizeString = SvxResId(STR_IMAGE_CAPACITY_WITH_REDUCTION);
+ aNewSizeString = aNewSizeString.replaceAll("$(CAPACITY)", aSizeAsString);
+ aNewSizeString = aNewSizeString.replaceAll("$(REDUCTION)", aReductionSizeAsString);
+ m_xFixedText6->set_label(aNewSizeString);
+ }
+}
+
+tools::Rectangle CompressGraphicsDialog::GetScaledCropRectangle() const
+{
+ if ( m_xReduceResolutionCB->get_active() )
+ {
+ tools::Long nPixelX = static_cast<tools::Long>( GetViewWidthInch() * m_dResolution );
+ tools::Long nPixelY = static_cast<tools::Long>( GetViewHeightInch() * m_dResolution );
+ Size aSize = m_aGraphic.GetBitmapEx().GetSizePixel();
+ double aScaleX = nPixelX / static_cast<double>(aSize.Width());
+ double aScaleY = nPixelY / static_cast<double>(aSize.Height());
+
+ return tools::Rectangle(
+ m_aCropRectangle.Left() * aScaleX,
+ m_aCropRectangle.Top() * aScaleY,
+ m_aCropRectangle.Right() * aScaleX,
+ m_aCropRectangle.Bottom()* aScaleY);
+ }
+ else
+ {
+ return m_aCropRectangle;
+ }
+}
+
+Graphic CompressGraphicsDialog::GetCompressedGraphic()
+{
+ if ( m_dResolution > 0.0 )
+ {
+ SvMemoryStream aMemStream;
+ aMemStream.SetVersion( SOFFICE_FILEFORMAT_CURRENT );
+ Compress( aMemStream );
+ aMemStream.Seek( STREAM_SEEK_TO_BEGIN );
+ Graphic aResultGraphic;
+ GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
+ rFilter.ImportGraphic( aResultGraphic, u"import", aMemStream );
+
+ return aResultGraphic;
+ }
+ return Graphic();
+}
+
+rtl::Reference<SdrGrafObj> CompressGraphicsDialog::GetCompressedSdrGrafObj()
+{
+ if ( m_dResolution > 0.0 )
+ {
+ rtl::Reference<SdrGrafObj> pNewObject = SdrObject::Clone(*m_xGraphicObj, m_xGraphicObj->getSdrModelFromSdrObject());
+
+ if ( m_xReduceResolutionCB->get_active() )
+ {
+ tools::Rectangle aScaledCropedRectangle = GetScaledCropRectangle();
+ SdrGrafCropItem aNewCrop(
+ aScaledCropedRectangle.Left(),
+ aScaledCropedRectangle.Top(),
+ aScaledCropedRectangle.Right(),
+ aScaledCropedRectangle.Bottom());
+
+ pNewObject->SetMergedItem(aNewCrop);
+ }
+ pNewObject->SetGraphic( GetCompressedGraphic() );
+
+ return pNewObject;
+ }
+ return nullptr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/connctrl.cxx b/svx/source/dialog/connctrl.cxx
new file mode 100644
index 0000000000..13677849fa
--- /dev/null
+++ b/svx/source/dialog/connctrl.cxx
@@ -0,0 +1,304 @@
+/* -*- 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 <svx/connctrl.hxx>
+#include <svx/dlgutil.hxx>
+
+#include <svx/sdr/contact/displayinfo.hxx>
+#include <sdr/contact/objectcontactofobjlistpainter.hxx>
+#include <svx/svdmark.hxx>
+#include <svx/svdoedge.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdview.hxx>
+#include <svx/sxelditm.hxx>
+
+#include <vcl/settings.hxx>
+#include <memory>
+
+SvxXConnectionPreview::SvxXConnectionPreview()
+ : pView(nullptr)
+{
+ SetMapMode(MapMode(MapUnit::Map100thMM));
+}
+
+void SvxXConnectionPreview::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ weld::CustomWidgetController::SetDrawingArea(pDrawingArea);
+ Size aSize(pDrawingArea->get_ref_device().LogicToPixel(Size(118 , 121), MapMode(MapUnit::MapAppFont)));
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+ SetOutputSizePixel(aSize);
+}
+
+SvxXConnectionPreview::~SvxXConnectionPreview()
+{
+}
+
+void SvxXConnectionPreview::Resize()
+{
+ AdaptSize();
+
+ Invalidate();
+}
+
+void SvxXConnectionPreview::AdaptSize()
+{
+ // Adapt size
+ if( !mxSdrPage )
+ return;
+
+ SetMapMode(MapMode(MapUnit::Map100thMM));
+
+ OutputDevice* pOD = pView->GetFirstOutputDevice(); // GetWin( 0 );
+ tools::Rectangle aRect = mxSdrPage->GetAllObjBoundRect();
+
+ MapMode aMapMode = GetMapMode();
+ aMapMode.SetMapUnit( pOD->GetMapMode().GetMapUnit() );
+ SetMapMode( aMapMode );
+
+ MapMode aDisplayMap( aMapMode );
+ Point aNewPos;
+ Size aNewSize;
+ const Size aWinSize = GetDrawingArea()->get_ref_device().PixelToLogic(GetOutputSizePixel(), aDisplayMap);
+ const tools::Long nWidth = aWinSize.Width();
+ const tools::Long nHeight = aWinSize.Height();
+ if (aRect.GetHeight() == 0)
+ return;
+ double fRectWH = static_cast<double>(aRect.GetWidth()) / aRect.GetHeight();
+ if (nHeight == 0)
+ return;
+ double fWinWH = static_cast<double>(nWidth) / nHeight;
+
+ // Adapt bitmap to Thumb size (not here!)
+ if ( fRectWH < fWinWH)
+ {
+ aNewSize.setWidth( static_cast<tools::Long>( static_cast<double>(nHeight) * fRectWH ) );
+ aNewSize.setHeight( nHeight );
+ }
+ else
+ {
+ aNewSize.setWidth( nWidth );
+ aNewSize.setHeight( static_cast<tools::Long>( static_cast<double>(nWidth) / fRectWH ) );
+ }
+
+ Fraction aFrac1( aWinSize.Width(), aRect.GetWidth() );
+ Fraction aFrac2( aWinSize.Height(), aRect.GetHeight() );
+ Fraction aMinFrac( aFrac1 <= aFrac2 ? aFrac1 : aFrac2 );
+
+ // Implement MapMode
+ aDisplayMap.SetScaleX( aMinFrac );
+ aDisplayMap.SetScaleY( aMinFrac );
+
+ // Centering
+ aNewPos.setX( ( nWidth - aNewSize.Width() ) >> 1 );
+ aNewPos.setY( ( nHeight - aNewSize.Height() ) >> 1 );
+
+ aDisplayMap.SetOrigin(OutputDevice::LogicToLogic(aNewPos, aMapMode, aDisplayMap));
+ SetMapMode( aDisplayMap );
+
+ // Origin
+ aNewPos = aDisplayMap.GetOrigin();
+ aNewPos -= Point( aRect.Left(), aRect.Top() );
+ aDisplayMap.SetOrigin( aNewPos );
+ SetMapMode( aDisplayMap );
+
+ MouseEvent aMEvt( Point(), 1, MouseEventModifiers::NONE, MOUSE_RIGHT );
+ MouseButtonDown( aMEvt );
+}
+
+void SvxXConnectionPreview::Construct()
+{
+ DBG_ASSERT( pView, "No valid view is passed on! ");
+
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+ const size_t nMarkCount = rMarkList.GetMarkCount();
+
+ if( nMarkCount >= 1 )
+ {
+ bool bFound = false;
+
+ for( size_t i = 0; i < nMarkCount && !bFound; ++i )
+ {
+ const SdrObject* pObj = rMarkList.GetMark( i )->GetMarkedSdrObj();
+ SdrInventor nInv = pObj->GetObjInventor();
+ SdrObjKind nId = pObj->GetObjIdentifier();
+ if( nInv == SdrInventor::Default && nId == SdrObjKind::Edge )
+ {
+ bFound = true;
+
+ // potential memory leak here (!). Create SdrObjList only when there is
+ // not yet one.
+ if(!mxSdrPage)
+ {
+ mxSdrPage = new SdrPage(
+ pView->getSdrModelFromSdrView(),
+ false);
+ }
+
+ const SdrEdgeObj* pTmpEdgeObj = static_cast<const SdrEdgeObj*>(pObj);
+ pEdgeObj = SdrObject::Clone(*pTmpEdgeObj, mxSdrPage->getSdrModelFromSdrPage());
+
+ SdrObjConnection& rConn1 = pEdgeObj->GetConnection( true );
+ SdrObjConnection& rConn2 = pEdgeObj->GetConnection( false );
+
+ rConn1 = pTmpEdgeObj->GetConnection( true );
+ rConn2 = pTmpEdgeObj->GetConnection( false );
+
+ SdrObject* pTmpObj1 = pTmpEdgeObj->GetConnectedNode( true );
+ SdrObject* pTmpObj2 = pTmpEdgeObj->GetConnectedNode( false );
+
+ if( pTmpObj1 )
+ {
+ rtl::Reference<SdrObject> pObj1 = pTmpObj1->CloneSdrObject(mxSdrPage->getSdrModelFromSdrPage());
+ mxSdrPage->InsertObject( pObj1.get() );
+ pEdgeObj->ConnectToNode( true, pObj1.get() );
+ }
+
+ if( pTmpObj2 )
+ {
+ rtl::Reference<SdrObject> pObj2 = pTmpObj2->CloneSdrObject(mxSdrPage->getSdrModelFromSdrPage());
+ mxSdrPage->InsertObject( pObj2.get() );
+ pEdgeObj->ConnectToNode( false, pObj2.get() );
+ }
+
+ mxSdrPage->InsertObject( pEdgeObj.get() );
+ }
+ }
+ }
+
+ if( !pEdgeObj )
+ {
+ pEdgeObj = new SdrEdgeObj(pView->getSdrModelFromSdrView());
+ }
+
+ AdaptSize();
+}
+
+void SvxXConnectionPreview::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ rRenderContext.Push(vcl::PushFlags::ALL);
+
+ rRenderContext.SetMapMode(GetMapMode());
+
+ const StyleSettings& rStyles = Application::GetSettings().GetStyleSettings();
+ rRenderContext.SetDrawMode(rStyles.GetHighContrastMode() ? OUTPUT_DRAWMODE_CONTRAST : OUTPUT_DRAWMODE_COLOR);
+ rRenderContext.SetBackground(Wallpaper(rStyles.GetFieldColor()));
+
+ if (mxSdrPage)
+ {
+ // This will not work anymore. To not start at Adam and Eve, i will
+ // ATM not try to change all this stuff to really using an own model
+ // and a view. I will just try to provide a mechanism to paint such
+ // objects without own model and without a page/view with the new
+ // mechanism.
+
+ // New stuff: Use an ObjectContactOfObjListPainter.
+ sdr::contact::SdrObjectVector aObjectVector;
+ aObjectVector.reserve(mxSdrPage->GetObjCount());
+ for (const rtl::Reference<SdrObject>& pObject : *mxSdrPage)
+ aObjectVector.push_back(pObject.get());
+
+ sdr::contact::ObjectContactOfObjListPainter aPainter(rRenderContext, std::move(aObjectVector), nullptr);
+ sdr::contact::DisplayInfo aDisplayInfo;
+
+ // do processing
+ aPainter.ProcessDisplay(aDisplayInfo);
+ }
+
+ rRenderContext.Pop();
+}
+
+void SvxXConnectionPreview::SetAttributes( const SfxItemSet& rInAttrs )
+{
+ pEdgeObj->SetMergedItemSetAndBroadcast(rInAttrs);
+
+ Invalidate();
+}
+
+// Get number of lines which are offset based on the preview object
+
+sal_uInt16 SvxXConnectionPreview::GetLineDeltaCount() const
+{
+ const SfxItemSet& rSet = pEdgeObj->GetMergedItemSet();
+ sal_uInt16 nCount(0);
+
+ if(SfxItemState::DONTCARE != rSet.GetItemState(SDRATTR_EDGELINEDELTACOUNT))
+ nCount = rSet.Get(SDRATTR_EDGELINEDELTACOUNT).GetValue();
+
+ return nCount;
+}
+
+bool SvxXConnectionPreview::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ bool bZoomIn = rMEvt.IsLeft() && !rMEvt.IsShift();
+ bool bZoomOut = rMEvt.IsRight() || rMEvt.IsShift();
+ bool bCtrl = rMEvt.IsMod1();
+
+ if( bZoomIn || bZoomOut )
+ {
+ MapMode aMapMode = GetMapMode();
+ Fraction aXFrac = aMapMode.GetScaleX();
+ Fraction aYFrac = aMapMode.GetScaleY();
+ std::unique_ptr<Fraction> pMultFrac;
+
+ if( bZoomIn )
+ {
+ if( bCtrl )
+ pMultFrac.reset(new Fraction( 3, 2 ));
+ else
+ pMultFrac.reset(new Fraction( 11, 10 ));
+ }
+ else
+ {
+ if( bCtrl )
+ pMultFrac.reset(new Fraction( 2, 3 ));
+ else
+ pMultFrac.reset(new Fraction( 10, 11 ));
+ }
+
+ aXFrac *= *pMultFrac;
+ aYFrac *= *pMultFrac;
+ if( static_cast<double>(aXFrac) > 0.001 && static_cast<double>(aXFrac) < 1000.0 &&
+ static_cast<double>(aYFrac) > 0.001 && static_cast<double>(aYFrac) < 1000.0 )
+ {
+ aMapMode.SetScaleX( aXFrac );
+ aMapMode.SetScaleY( aYFrac );
+ SetMapMode( aMapMode );
+
+ Size aOutSize(GetOutputSizePixel());
+ aOutSize = GetDrawingArea()->get_ref_device().PixelToLogic(aOutSize);
+
+ Point aPt( aMapMode.GetOrigin() );
+ tools::Long nX = static_cast<tools::Long>( ( static_cast<double>(aOutSize.Width()) - ( static_cast<double>(aOutSize.Width()) * static_cast<double>(*pMultFrac) ) ) / 2.0 + 0.5 );
+ tools::Long nY = static_cast<tools::Long>( ( static_cast<double>(aOutSize.Height()) - ( static_cast<double>(aOutSize.Height()) * static_cast<double>(*pMultFrac) ) ) / 2.0 + 0.5 );
+ aPt.AdjustX(nX );
+ aPt.AdjustY(nY );
+
+ aMapMode.SetOrigin( aPt );
+ SetMapMode( aMapMode );
+
+ Invalidate();
+ }
+ }
+
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/contimp.hxx b/svx/source/dialog/contimp.hxx
new file mode 100644
index 0000000000..2bf5aca4d1
--- /dev/null
+++ b/svx/source/dialog/contimp.hxx
@@ -0,0 +1,132 @@
+/* -*- 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 .
+ */
+#ifndef INCLUDED_SVX_SOURCE_DIALOG_CONTIMP_HXX
+#define INCLUDED_SVX_SOURCE_DIALOG_CONTIMP_HXX
+
+#include <sfx2/ctrlitem.hxx>
+#include "contwnd.hxx"
+#include <vcl/idle.hxx>
+
+class SvxSuperContourDlg;
+
+class SvxContourDlgItem : public SfxControllerItem
+{
+ SvxSuperContourDlg& rDlg;
+
+protected:
+
+ virtual void StateChangedAtToolBoxControl( sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState ) override;
+
+public:
+
+ SvxContourDlgItem( SvxSuperContourDlg& rDlg, SfxBindings& rBindings );
+};
+
+class ContourWindow;
+
+class StatusColor : public weld::CustomWidgetController
+{
+private:
+ ContourWindow& m_rWnd;
+public:
+ StatusColor(ContourWindow& rWnd)
+ : m_rWnd(rWnd)
+ {
+ }
+ virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override;
+ virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override
+ {
+ weld::CustomWidgetController::SetDrawingArea(pDrawingArea);
+ Size aSize(pDrawingArea->get_approximate_digit_width() * 3,
+ pDrawingArea->get_text_height());
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+ SetOutputSizePixel(aSize);
+ }
+};
+
+class SvxSuperContourDlg
+{
+ Graphic aGraphic;
+ Graphic aUndoGraphic;
+ Graphic aRedoGraphic;
+ Graphic aUpdateGraphic;
+ tools::PolyPolygon aUpdatePolyPoly;
+ Idle aUpdateIdle;
+ Idle aCreateIdle;
+ SfxBindings* mpBindings;
+ void* pUpdateEditingObject;
+ void* pCheckObj;
+ SvxContourDlgItem aContourItem;
+ sal_Int32 mnGrfChanged;
+ bool bExecState;
+ bool bUpdateGraphicLinked;
+ bool bGraphicLinked;
+
+ weld::Dialog& m_rDialog;
+ std::unique_ptr<ContourWindow> m_xContourWnd;
+ std::unique_ptr<StatusColor> m_xStbStatusColor;
+ std::unique_ptr<weld::Toolbar> m_xTbx1;
+ std::unique_ptr<weld::MetricSpinButton> m_xMtfTolerance;
+ std::unique_ptr<weld::Label> m_xStbStatus2;
+ std::unique_ptr<weld::Label> m_xStbStatus3;
+ std::unique_ptr<weld::Button> m_xCancelBtn;
+ std::unique_ptr<weld::CustomWeld> m_xStbStatusColorWeld;
+ std::unique_ptr<weld::CustomWeld> m_xContourWndWeld;
+
+ DECL_LINK( Tbx1ClickHdl, const OUString&, void );
+ DECL_LINK( MousePosHdl, GraphCtrl*, void );
+ DECL_LINK( GraphSizeHdl, GraphCtrl*, void );
+ DECL_LINK( UpdateHdl, Timer *, void );
+ DECL_LINK( CreateHdl, Timer *, void );
+ DECL_LINK( StateHdl, GraphCtrl*, void );
+ DECL_LINK( PipetteHdl, ContourWindow&, void );
+ DECL_LINK( PipetteClickHdl, ContourWindow&, void );
+ DECL_LINK( WorkplaceClickHdl, ContourWindow&, void );
+ DECL_LINK( CancelHdl, weld::Button&, void );
+
+ void SetActiveTool(std::u16string_view rId);
+ void SetActivePoly(std::u16string_view rId);
+
+ SfxBindings& GetBindings() { return *mpBindings; }
+
+public:
+
+ SvxSuperContourDlg(weld::Builder& rBuilder, weld::Dialog& rDialog, SfxBindings* pBindings);
+ ~SvxSuperContourDlg();
+
+ void SetExecState( bool bEnable );
+
+ void SetGraphic( const Graphic& rGraphic );
+ const Graphic& GetGraphic() const { return aGraphic; }
+ bool IsGraphicChanged() const { return mnGrfChanged > 0; }
+
+ void SetPolyPolygon( const tools::PolyPolygon& rPolyPoly );
+ tools::PolyPolygon GetPolyPolygon();
+
+ const void* GetEditingObject() const { return pCheckObj; }
+
+ void UpdateGraphic( const Graphic& rGraphic, bool bGraphicLinked,
+ const tools::PolyPolygon* pPolyPoly,
+ void* pEditingObj );
+};
+
+
+#endif // INCLUDED_SVX_SOURCE_DIALOG_CONTIMP_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/contwnd.cxx b/svx/source/dialog/contwnd.cxx
new file mode 100644
index 0000000000..976897b6ba
--- /dev/null
+++ b/svx/source/dialog/contwnd.cxx
@@ -0,0 +1,271 @@
+/* -*- 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 "contwnd.hxx"
+#include <svx/svdpage.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xfltrit.hxx>
+#include <svx/xflclit.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <svx/sdrpaintwindow.hxx>
+#include <vcl/ptrstyle.hxx>
+
+using namespace css;
+
+#define TRANSCOL COL_WHITE
+
+ContourWindow::ContourWindow(weld::Dialog* pDialog)
+ : GraphCtrl(pDialog)
+ , aWorkRect(0, 0, 0, 0)
+ , bPipetteMode(false)
+ , bWorkplaceMode(false)
+ , bClickValid(false)
+{
+}
+
+void ContourWindow::SetPolyPolygon(const tools::PolyPolygon& rPolyPoly)
+{
+ SdrPage* pPage = pModel->GetPage(0);
+ const sal_uInt16 nPolyCount = rPolyPoly.Count();
+
+ // First delete all drawing objects
+ aPolyPoly = rPolyPoly;
+
+ // To avoid to have destroyed objects which are still selected, it is necessary to deselect
+ // them first (!)
+ pView->UnmarkAllObj();
+
+ // clear SdrObjects with broadcasting
+ pPage->ClearSdrObjList();
+
+ for (sal_uInt16 i = 0; i < nPolyCount; i++)
+ {
+ basegfx::B2DPolyPolygon aPolyPolygon;
+ aPolyPolygon.append(aPolyPoly[ i ].getB2DPolygon());
+ rtl::Reference<SdrPathObj> pPathObj = new SdrPathObj(
+ *pModel,
+ SdrObjKind::PathFill,
+ std::move(aPolyPolygon));
+
+ SfxItemSet aSet(pModel->GetItemPool());
+
+ aSet.Put(XFillStyleItem(drawing::FillStyle_SOLID));
+ aSet.Put(XFillColorItem("", TRANSCOL));
+ aSet.Put(XFillTransparenceItem(50) );
+
+ pPathObj->SetMergedItemSetAndBroadcast(aSet);
+
+ pPage->InsertObject( pPathObj.get() );
+ }
+
+ if (nPolyCount)
+ {
+ pView->MarkAll();
+ pView->CombineMarkedObjects(false);
+ }
+
+ pModel->SetChanged(false);
+}
+
+const tools::PolyPolygon& ContourWindow::GetPolyPolygon()
+{
+ if ( pModel->IsChanged() )
+ {
+ SdrPage* pPage = pModel->GetPage( 0 );
+
+ aPolyPoly = tools::PolyPolygon();
+
+ if ( pPage && pPage->GetObjCount() )
+ {
+ SdrPathObj* pPathObj = static_cast<SdrPathObj*>(pPage->GetObj(0));
+ // Not sure if subdivision is needed for ContourWindow, but maybe it cannot handle
+ // curves at all. Keeping subdivision here for security
+ const basegfx::B2DPolyPolygon aB2DPolyPolygon(basegfx::utils::adaptiveSubdivideByAngle(pPathObj->GetPathPoly()));
+ aPolyPoly = tools::PolyPolygon(aB2DPolyPolygon);
+ }
+
+ pModel->SetChanged( false );
+ }
+
+ return aPolyPoly;
+}
+
+void ContourWindow::InitSdrModel()
+{
+ GraphCtrl::InitSdrModel();
+
+ SfxItemSet aSet( pModel->GetItemPool() );
+
+ aSet.Put( XFillColorItem( "", TRANSCOL ) );
+ aSet.Put( XFillTransparenceItem( 50 ) );
+ pView->SetAttributes( aSet );
+ pView->SetFrameDragSingles();
+}
+
+void ContourWindow::SdrObjCreated( const SdrObject& )
+{
+ pView->MarkAll();
+ pView->CombineMarkedObjects( false );
+}
+
+bool ContourWindow::IsContourChanged() const
+{
+ SdrPage* pPage = pModel->GetPage( 0 );
+ bool bRet = false;
+
+ if ( pPage && pPage->GetObjCount() )
+ bRet = static_cast<SdrPathObj*>( pPage->GetObj( 0 ) )->GetPathPoly().count() && pModel->IsChanged();
+
+ return bRet;
+}
+
+bool ContourWindow::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ if ( bWorkplaceMode )
+ {
+ const Point aLogPt(GetDrawingArea()->get_ref_device().PixelToLogic(rMEvt.GetPosPixel()));
+
+ SetPolyPolygon( tools::PolyPolygon() );
+ aWorkRect = tools::Rectangle( aLogPt, aLogPt );
+ Invalidate(tools::Rectangle(Point(), GetGraphicSize()));
+ SetEditMode( true );
+ }
+
+ if (!bPipetteMode)
+ return GraphCtrl::MouseButtonDown( rMEvt );
+
+ return true;
+}
+
+bool ContourWindow::MouseMove( const MouseEvent& rMEvt )
+{
+ bClickValid = false;
+
+ if ( bPipetteMode )
+ {
+ const Point aLogPt( GetDrawingArea()->get_ref_device().PixelToLogic( rMEvt.GetPosPixel() ) );
+
+ aPipetteColor = GetDrawingArea()->get_ref_device().GetPixel( aLogPt );
+ weld::CustomWidgetController::MouseMove( rMEvt );
+
+ if ( aPipetteLink.IsSet() && tools::Rectangle( Point(), GetGraphicSize() ).Contains( aLogPt ) )
+ {
+ SetPointer( PointerStyle::RefHand );
+ aPipetteLink.Call( *this );
+ }
+
+ return true;
+ }
+
+ return GraphCtrl::MouseMove( rMEvt );
+}
+
+bool ContourWindow::MouseButtonUp(const MouseEvent& rMEvt)
+{
+ const tools::Rectangle aGraphRect( Point(), GetGraphicSize() );
+ const Point aLogPt( GetDrawingArea()->get_ref_device().PixelToLogic( rMEvt.GetPosPixel() ) );
+
+ bClickValid = aGraphRect.Contains( aLogPt );
+ ReleaseMouse();
+
+ if ( bPipetteMode )
+ {
+ weld::CustomWidgetController::MouseButtonUp( rMEvt );
+
+ aPipetteClickLink.Call( *this );
+
+ return true;
+ }
+ else if ( bWorkplaceMode )
+ {
+ GraphCtrl::MouseButtonUp( rMEvt );
+
+ aWorkRect.SetRight( aLogPt.X() );
+ aWorkRect.SetBottom( aLogPt.Y() );
+ aWorkRect.Intersection( aGraphRect );
+ aWorkRect.Normalize();
+
+ if ( aWorkRect.Left() != aWorkRect.Right() && aWorkRect.Top() != aWorkRect.Bottom() )
+ {
+ tools::PolyPolygon _aPolyPoly( GetPolyPolygon() );
+
+ _aPolyPoly.Clip( aWorkRect );
+ SetPolyPolygon( _aPolyPoly );
+ pView->SetWorkArea( aWorkRect );
+ }
+ else
+ pView->SetWorkArea( aGraphRect );
+
+ Invalidate( aGraphRect );
+
+ aWorkplaceClickLink.Call( *this );
+
+ return false;
+ }
+
+ return GraphCtrl::MouseButtonUp( rMEvt );
+}
+
+void ContourWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
+{
+ // #i75482#
+ // encapsulate the redraw using Begin/End and use the returned
+ // data to get the target output device (e.g. when pre-rendering)
+ SdrPaintWindow* pPaintWindow = pView->BeginCompleteRedraw(&rRenderContext);
+ pPaintWindow->SetOutputToWindow(true);
+ OutputDevice& rTarget = pPaintWindow->GetTargetOutputDevice();
+
+ const Graphic& rGraphic = GetGraphic();
+ rTarget.Push(vcl::PushFlags::LINECOLOR |vcl::PushFlags::FILLCOLOR);
+ rTarget.SetLineColor(COL_BLACK);
+ rTarget.SetFillColor(COL_WHITE);
+ rTarget.DrawRect( tools::Rectangle( Point(), GetGraphicSize() ) );
+ rTarget.Pop();
+
+ if (rGraphic.GetType() != GraphicType::NONE)
+ rGraphic.Draw(rTarget, Point(), GetGraphicSize());
+
+ if (aWorkRect.Left() != aWorkRect.Right() && aWorkRect.Top() != aWorkRect.Bottom())
+ {
+ tools::PolyPolygon _aPolyPoly(2);
+ rTarget.Push(vcl::PushFlags::FILLCOLOR);
+ _aPolyPoly.Insert(tools::Polygon(tools::Rectangle(Point(), GetGraphicSize())));
+ _aPolyPoly.Insert(tools::Polygon(aWorkRect));
+ rTarget.SetFillColor(COL_LIGHTRED);
+ rTarget.DrawTransparent(_aPolyPoly, 50);
+ rTarget.Pop();
+ }
+
+ // #i75482#
+ const vcl::Region aRepaintRegion(rRect);
+ pView->DoCompleteRedraw(*pPaintWindow, aRepaintRegion);
+ pView->EndCompleteRedraw(*pPaintWindow, true);
+}
+
+void ContourWindow::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ GraphCtrl::SetDrawingArea(pDrawingArea);
+ Size aSize(pDrawingArea->get_ref_device().LogicToPixel(Size(270, 170), MapMode(MapUnit::MapAppFont)));
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+ SetOutputSizePixel(aSize);
+ SetSdrMode(true);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/contwnd.hxx b/svx/source/dialog/contwnd.hxx
new file mode 100644
index 0000000000..1bad623c05
--- /dev/null
+++ b/svx/source/dialog/contwnd.hxx
@@ -0,0 +1,70 @@
+/* -*- 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 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_DIALOG_CONTWND_HXX
+#define INCLUDED_SVX_SOURCE_DIALOG_CONTWND_HXX
+
+#include <tools/poly.hxx>
+#include <svx/graphctl.hxx>
+
+class ContourWindow final : public GraphCtrl
+{
+ tools::PolyPolygon aPolyPoly;
+ Color aPipetteColor;
+ tools::Rectangle aWorkRect;
+ Link<ContourWindow&,void> aPipetteLink;
+ Link<ContourWindow&,void> aPipetteClickLink;
+ Link<ContourWindow&,void> aWorkplaceClickLink;
+ bool bPipetteMode;
+ bool bWorkplaceMode;
+ bool bClickValid;
+
+ virtual bool MouseButtonDown(const MouseEvent& rMEvt) override;
+ virtual bool MouseMove(const MouseEvent& rMEvt) override;
+ virtual bool MouseButtonUp(const MouseEvent& rMEvt) override;
+ virtual void SdrObjCreated( const SdrObject& rObj ) override;
+ virtual void InitSdrModel() override;
+ virtual void Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect ) override;
+ virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override;
+
+public:
+
+ ContourWindow(weld::Dialog* pDialog);
+
+ void SetPolyPolygon( const tools::PolyPolygon& rPolyPoly );
+ const tools::PolyPolygon& GetPolyPolygon();
+
+ void SetPipetteMode( const bool bPipette ) { bPipetteMode = bPipette; }
+ const Color& GetPipetteColor() const { return aPipetteColor; }
+
+ bool IsClickValid() const { return bClickValid; }
+ bool IsContourChanged() const;
+
+ void SetWorkplaceMode( const bool bWorkplace ) { bWorkplaceMode = bWorkplace; }
+ const tools::Rectangle& GetWorkRect() const { return aWorkRect; }
+
+ void SetPipetteHdl( const Link<ContourWindow&,void>& rLink ) { aPipetteLink = rLink; }
+ void SetPipetteClickHdl( const Link<ContourWindow&,void>& rLink ) { aPipetteClickLink = rLink; }
+ void SetWorkplaceClickHdl( const Link<ContourWindow&,void>& rLink ) { aWorkplaceClickLink = rLink; }
+};
+
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/crashreportdlg.cxx b/svx/source/dialog/crashreportdlg.cxx
new file mode 100644
index 0000000000..aad28436ee
--- /dev/null
+++ b/svx/source/dialog/crashreportdlg.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/.
+ */
+
+#include "crashreportdlg.hxx"
+
+#include <desktop/crashreport.hxx>
+#include <sfx2/safemode.hxx>
+#include <comphelper/processfactory.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <unotools/configmgr.hxx>
+#include <officecfg/Office/Common.hxx>
+#include <vcl/svapp.hxx>
+
+#include <com/sun/star/task/OfficeRestartManager.hpp>
+#include <com/sun/star/task/XInteractionHandler.hpp>
+
+IMPL_STATIC_LINK_NOARG(CrashReportDialog, InstallLOKNotifierHdl, void*,
+ vcl::ILibreOfficeKitNotifier*)
+{
+ return GetpApp();
+}
+
+CrashReportDialog::CrashReportDialog(weld::Window* pParent)
+ : GenericDialogController(pParent, "svx/ui/crashreportdlg.ui", "CrashReportDialog")
+ , mxBtnSend(m_xBuilder->weld_button("btn_send"))
+ , mxBtnCancel(m_xBuilder->weld_button("btn_cancel"))
+ , mxBtnClose(m_xBuilder->weld_button("btn_close"))
+ , mxEditPreUpload(m_xBuilder->weld_label("ed_pre"))
+ , mxEditPostUpload(m_xBuilder->weld_label("ed_post"))
+ , mxLinkButton(m_xBuilder->weld_link_button("linkbutton"))
+ , mxFtBugReport(m_xBuilder->weld_label("ed_bugreport"))
+ , mxCBSafeMode(m_xBuilder->weld_check_button("check_safemode"))
+ , mxPrivacyPolicyButton(m_xBuilder->weld_link_button("btnPrivacyPolicy"))
+{
+ maLinkTemplate = mxLinkButton->get_uri();
+
+ auto nWidth = mxEditPreUpload->get_preferred_size().Width();
+ nWidth = std::max(nWidth, mxCBSafeMode->get_size_request().Width());
+ mxEditPreUpload->set_size_request(nWidth, -1);
+ mxCBSafeMode->set_size_request(nWidth, -1);
+
+ mxBtnSend->connect_clicked(LINK(this, CrashReportDialog, BtnHdl));
+ mxBtnCancel->connect_clicked(LINK(this, CrashReportDialog, BtnHdl));
+ mxBtnClose->connect_clicked(LINK(this, CrashReportDialog, BtnHdl));
+
+ mxPrivacyPolicyButton->set_uri(
+ officecfg::Office::Common::Menus::PrivacyPolicyURL::get()
+ + "?type=crashreport&LOvers=" + utl::ConfigManager::getProductVersion()
+ + "&LOlocale=" + LanguageTag(utl::ConfigManager::getUILocale()).getBcp47());
+
+ m_xDialog->SetInstallLOKNotifierHdl(LINK(this, CrashReportDialog, InstallLOKNotifierHdl));
+}
+
+CrashReportDialog::~CrashReportDialog() {}
+
+short CrashReportDialog::run()
+{
+ short nRet = GenericDialogController::run();
+
+ // Check whether to go to safe mode
+ if (mxCBSafeMode->get_active())
+ {
+ sfx2::SafeMode::putFlag();
+ css::task::OfficeRestartManager::get(comphelper::getProcessComponentContext())
+ ->requestRestart(css::uno::Reference<css::task::XInteractionHandler>());
+ }
+ return nRet;
+}
+
+IMPL_LINK(CrashReportDialog, BtnHdl, weld::Button&, rBtn, void)
+{
+ if (&rBtn == mxBtnSend.get())
+ {
+ std::string response;
+ bool bSuccess = CrashReporter::readSendConfig(response);
+
+ OUString aCrashID = OUString::createFromAscii(response);
+
+ if (bSuccess)
+ {
+ OUString aProcessedLink
+ = maLinkTemplate.replaceAll("%CRASHID", aCrashID.replaceAll("Crash-ID=", ""));
+
+ // vclbuilder seems to replace _ with ~ even in text
+ mxLinkButton->set_label(aProcessedLink.replaceAll("~", "_"));
+ mxLinkButton->set_uri(aProcessedLink);
+ }
+ else
+ {
+ mxEditPostUpload->set_label(aCrashID);
+ }
+
+ mxLinkButton->set_visible(bSuccess);
+
+ mxBtnClose->show();
+ mxFtBugReport->show();
+ mxEditPostUpload->show();
+ mxBtnSend->set_sensitive(false);
+ mxBtnCancel->set_sensitive(false);
+ mxBtnClose->grab_focus();
+
+ mxEditPreUpload->hide();
+ mxBtnSend->hide();
+ mxBtnCancel->hide();
+
+ m_xDialog->resize_to_request();
+ }
+ else if (&rBtn == mxBtnCancel.get())
+ {
+ m_xDialog->response(RET_CLOSE);
+ }
+ else if (&rBtn == mxBtnClose.get())
+ {
+ m_xDialog->response(RET_CLOSE);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/crashreportdlg.hxx b/svx/source/dialog/crashreportdlg.hxx
new file mode 100644
index 0000000000..3f2d9cb121
--- /dev/null
+++ b/svx/source/dialog/crashreportdlg.hxx
@@ -0,0 +1,42 @@
+/* -*- 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/.
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_DIALOG_CRASHREPORTDLG_HXX
+#define INCLUDED_SVX_SOURCE_DIALOG_CRASHREPORTDLG_HXX
+
+#include <vcl/weld.hxx>
+
+class CrashReportDialog : public weld::GenericDialogController
+{
+public:
+ explicit CrashReportDialog(weld::Window* pParent);
+ virtual short run() override;
+ virtual ~CrashReportDialog() override;
+
+private:
+ std::unique_ptr<weld::Button> mxBtnSend;
+ std::unique_ptr<weld::Button> mxBtnCancel;
+ std::unique_ptr<weld::Button> mxBtnClose;
+ std::unique_ptr<weld::Label> mxEditPreUpload;
+ std::unique_ptr<weld::Label> mxEditPostUpload;
+ std::unique_ptr<weld::LinkButton> mxLinkButton;
+ std::unique_ptr<weld::Label> mxFtBugReport;
+ std::unique_ptr<weld::CheckButton> mxCBSafeMode;
+ std::unique_ptr<weld::LinkButton> mxPrivacyPolicyButton;
+
+ OUString maLinkTemplate;
+
+ DECL_LINK(BtnHdl, weld::Button&, void);
+ DECL_STATIC_LINK(CrashReportDialog, InstallLOKNotifierHdl, void*,
+ vcl::ILibreOfficeKitNotifier*);
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/crashreportui.cxx b/svx/source/dialog/crashreportui.cxx
new file mode 100644
index 0000000000..5384e3c18c
--- /dev/null
+++ b/svx/source/dialog/crashreportui.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 <cppuhelper/implbase.hxx>
+#include <com/sun/star/frame/XSynchronousDispatch.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+#include <cppuhelper/supportsservice.hxx>
+
+#include <vcl/svapp.hxx>
+
+#include "crashreportdlg.hxx"
+
+namespace {
+
+class CrashReportUI : public ::cppu::WeakImplHelper< css::lang::XServiceInfo ,
+ css::frame::XSynchronousDispatch > // => XDispatch!
+{
+public:
+ explicit CrashReportUI();
+
+ // css.lang.XServiceInfo
+
+ virtual OUString SAL_CALL getImplementationName() override;
+
+ virtual sal_Bool SAL_CALL supportsService(const OUString& sServiceName) override;
+
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+
+ virtual css::uno::Any SAL_CALL dispatchWithReturnValue(const css::util::URL& aURL,
+ const css::uno::Sequence< css::beans::PropertyValue >& lArguments ) override;
+};
+
+CrashReportUI::CrashReportUI()
+{
+
+}
+
+OUString SAL_CALL CrashReportUI::getImplementationName()
+{
+ return "com.sun.star.comp.svx.CrashReportUI";
+}
+
+sal_Bool SAL_CALL CrashReportUI::supportsService(const OUString& sServiceName)
+{
+ return cppu::supportsService(this, sServiceName);
+}
+
+css::uno::Sequence< OUString > SAL_CALL CrashReportUI::getSupportedServiceNames()
+{
+ return { "com.sun.star.dialog.CrashReportUI" };
+}
+
+css::uno::Any SAL_CALL CrashReportUI::dispatchWithReturnValue(const css::util::URL&,
+ const css::uno::Sequence< css::beans::PropertyValue >& )
+{
+ SolarMutexGuard aGuard;
+ css::uno::Any aRet;
+ CrashReportDialog aDialog(nullptr);
+ aDialog.run();
+ return aRet;
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_svx_CrashReportUI_get_implementation(
+ css::uno::XComponentContext * /*context*/,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new CrashReportUI());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/ctredlin.cxx b/svx/source/dialog/ctredlin.cxx
new file mode 100644
index 0000000000..6df9dbd283
--- /dev/null
+++ b/svx/source/dialog/ctredlin.cxx
@@ -0,0 +1,1002 @@
+/* -*- 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/processfactory.hxx>
+#include <comphelper/string.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <o3tl/safeint.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/weldutils.hxx>
+#include <svtools/ctrlbox.hxx>
+#include <unotools/textsearch.hxx>
+
+#include <helpids.h>
+
+#include <svx/ctredlin.hxx>
+
+#define WRITER_DATE 2
+#define CALC_DATE 3
+
+RedlinData::RedlinData()
+ : aDateTime(DateTime::EMPTY)
+ , pData(nullptr)
+ , eType(RedlineType::Any)
+ , bDisabled(false)
+{
+}
+
+RedlinData::~RedlinData()
+{
+}
+
+SvxRedlinTable::SvxRedlinTable(std::unique_ptr<weld::TreeView> xWriterControl,
+ std::unique_ptr<weld::TreeView> xCalcControl)
+ : xSorter(new comphelper::string::NaturalStringSorter(::comphelper::getProcessComponentContext(),
+ Application::GetSettings().GetUILanguageTag().getLocale()))
+ , xWriterTreeView(std::move(xWriterControl))
+ , xCalcTreeView(std::move(xCalcControl))
+ , pTreeView(nullptr)
+ , nDatePos(WRITER_DATE)
+ , bAuthor(false)
+ , bDate(false)
+ , bComment(false)
+ , bSorted(false)
+ , nDaTiMode(SvxRedlinDateMode::BEFORE)
+ , aDaTiFirst( DateTime::EMPTY )
+ , aDaTiLast( DateTime::EMPTY )
+ , aDaTiFilterFirst( DateTime::EMPTY )
+ , aDaTiFilterLast( DateTime::EMPTY )
+{
+ if (xWriterTreeView)
+ {
+ xWriterTreeView->set_size_request(-1, xWriterTreeView->get_height_rows(8));
+ xWriterTreeView->connect_column_clicked(LINK(this, SvxRedlinTable, HeaderBarClick));
+ xWriterTreeView->set_sort_func([this](const weld::TreeIter& rLeft, const weld::TreeIter& rRight){
+ return ColCompare(rLeft, rRight);
+ });
+ pTreeView = xWriterTreeView.get();
+ }
+ if (xCalcTreeView)
+ {
+ xCalcTreeView->set_size_request(-1, xCalcTreeView->get_height_rows(8));
+ xCalcTreeView->connect_column_clicked(LINK(this, SvxRedlinTable, HeaderBarClick));
+ xCalcTreeView->set_sort_func([this](const weld::TreeIter& rLeft, const weld::TreeIter& rRight){
+ return ColCompare(rLeft, rRight);
+ });
+ pTreeView = xCalcTreeView.get();
+ }
+}
+
+SvxRedlinTable::~SvxRedlinTable()
+{
+}
+
+IMPL_LINK(SvxRedlinTable, HeaderBarClick, int, nColumn, void)
+{
+ if (!bSorted)
+ {
+ pTreeView->make_sorted();
+ bSorted = true;
+ }
+
+ bool bSortAtoZ = pTreeView->get_sort_order();
+
+ //set new arrow positions in headerbar
+ if (nColumn == pTreeView->get_sort_column())
+ {
+ bSortAtoZ = !bSortAtoZ;
+ pTreeView->set_sort_order(bSortAtoZ);
+ }
+ else
+ {
+ int nOldSortColumn = pTreeView->get_sort_column();
+ if (nOldSortColumn != -1)
+ pTreeView->set_sort_indicator(TRISTATE_INDET, nOldSortColumn);
+ pTreeView->set_sort_column(nColumn);
+ }
+
+ if (nColumn != -1)
+ {
+ //sort lists
+ pTreeView->set_sort_indicator(bSortAtoZ ? TRISTATE_TRUE : TRISTATE_FALSE, nColumn);
+ }
+}
+
+int SvxRedlinTable::ColCompare(const weld::TreeIter& rLeft, const weld::TreeIter& rRight)
+{
+ sal_Int32 nCompare = 0;
+
+ int nSortCol = pTreeView->get_sort_column();
+
+ if (pTreeView == xWriterTreeView.get() && nSortCol == 0)
+ {
+ RedlinData *pLeftData = weld::fromId<RedlinData*>(pTreeView->get_id(rLeft));
+ RedlinData *pRightData = weld::fromId<RedlinData*>(pTreeView->get_id(rRight));
+
+ if (pLeftData && pRightData)
+ {
+ if (pLeftData->eType < pRightData->eType)
+ nCompare = -1;
+ else if (pLeftData->eType > pRightData->eType)
+ nCompare = 1;
+ return nCompare;
+ }
+ }
+
+ if (nSortCol == nDatePos)
+ {
+ RedlinData *pLeftData = weld::fromId<RedlinData*>(pTreeView->get_id(rLeft));
+ RedlinData *pRightData = weld::fromId<RedlinData*>(pTreeView->get_id(rRight));
+
+ if (pLeftData && pRightData)
+ {
+ if (pLeftData->aDateTime < pRightData->aDateTime)
+ nCompare = -1;
+ else if (pLeftData->aDateTime > pRightData->aDateTime)
+ nCompare = 1;
+ return nCompare;
+ }
+ }
+
+ return xSorter->compare(pTreeView->get_text(rLeft, nSortCol),
+ pTreeView->get_text(rRight, nSortCol));
+}
+
+void SvxRedlinTable::UpdateFilterTest()
+{
+ Date aDateMax( Date::SYSTEM );
+ aDateMax.AddYears(100);
+ Date aDateMin(1,1,1989);
+ tools::Time aTMin(0);
+ tools::Time aTMax(23,59,59);
+
+ DateTime aDTMin(aDateMin);
+ DateTime aDTMax(aDateMax);
+
+ switch(nDaTiMode)
+ {
+ case SvxRedlinDateMode::BEFORE:
+ aDaTiFilterFirst=aDTMin;
+ aDaTiFilterLast=aDaTiFirst;
+ break;
+ case SvxRedlinDateMode::SAVE:
+ case SvxRedlinDateMode::SINCE:
+ aDaTiFilterFirst=aDaTiFirst;
+ aDaTiFilterLast=aDTMax;
+ break;
+ case SvxRedlinDateMode::EQUAL:
+ aDaTiFilterFirst=aDaTiFirst;
+ aDaTiFilterLast=aDaTiFirst;
+ aDaTiFilterFirst.SetTime(aTMin.GetTime());
+ aDaTiFilterLast.SetTime(aTMax.GetTime());
+ break;
+ case SvxRedlinDateMode::NOTEQUAL:
+ aDaTiFilterFirst=aDaTiFirst;
+ aDaTiFilterLast=aDaTiFirst;
+ aDaTiFilterFirst.SetTime(aTMin.GetTime());
+ aDaTiFilterLast.SetTime(aTMax.GetTime());
+ break;
+ case SvxRedlinDateMode::BETWEEN:
+ aDaTiFilterFirst=aDaTiFirst;
+ aDaTiFilterLast=aDaTiLast;
+ break;
+ case SvxRedlinDateMode::NONE:
+ break;
+ }
+}
+
+void SvxRedlinTable::SetFilterDate(bool bFlag)
+{
+ bDate=bFlag;
+}
+
+void SvxRedlinTable::SetDateTimeMode(SvxRedlinDateMode nMode)
+{
+ nDaTiMode=nMode;
+}
+
+void SvxRedlinTable::SetFirstDate(const Date& aDate)
+{
+ aDaTiFirst.SetDate(aDate.GetDate());
+}
+
+void SvxRedlinTable::SetLastDate(const Date& aDate)
+{
+ aDaTiLast.SetDate(aDate.GetDate());
+}
+
+void SvxRedlinTable::SetFirstTime(const tools::Time& aTime)
+{
+ aDaTiFirst.SetTime(aTime.GetTime());
+}
+
+void SvxRedlinTable::SetLastTime(const tools::Time& aTime)
+{
+ aDaTiLast.SetTime(aTime.GetTime());
+}
+
+void SvxRedlinTable::SetFilterAuthor(bool bFlag)
+{
+ bAuthor=bFlag;
+}
+
+void SvxRedlinTable::SetAuthor(const OUString &aString)
+{
+ aAuthor=aString;
+}
+
+void SvxRedlinTable::SetFilterComment(bool bFlag)
+{
+ bComment=bFlag;
+}
+
+void SvxRedlinTable::SetCommentParams( const utl::SearchParam* pSearchPara )
+{
+ if(pSearchPara!=nullptr)
+ {
+ pCommentSearcher.reset(new utl::TextSearch(*pSearchPara, LANGUAGE_SYSTEM ));
+ }
+}
+
+bool SvxRedlinTable::IsValidEntry(std::u16string_view rAuthorStr,
+ const DateTime &rDateTime,
+ const OUString &rCommentStr)
+{
+ return IsValidEntry(rAuthorStr, rDateTime) && IsValidComment(rCommentStr);
+}
+
+bool SvxRedlinTable::IsValidEntry(std::u16string_view rAuthorStr, const DateTime &rDateTime)
+{
+ if (bAuthor && aAuthor!=rAuthorStr)
+ return false;
+
+ if (!bDate)
+ return true;
+
+ const bool bRes = rDateTime.IsBetween(aDaTiFilterFirst, aDaTiFilterLast);
+ return nDaTiMode!=SvxRedlinDateMode::NOTEQUAL ? bRes : !bRes;
+}
+
+bool SvxRedlinTable::IsValidComment(const OUString &rCommentStr)
+{
+ if (!bComment)
+ return true;
+
+ sal_Int32 nStartPos = 0;
+ sal_Int32 nEndPos = rCommentStr.getLength();
+ return pCommentSearcher->SearchForward( rCommentStr, &nStartPos, &nEndPos);
+}
+
+SvxTPage::~SvxTPage()
+{
+}
+
+void SvxTPage::ActivatePage()
+{
+}
+
+SvxTPView::SvxTPView(weld::Container* pParent)
+ : SvxTPage(pParent, "svx/ui/redlineviewpage.ui", "RedlineViewPage")
+ , bEnableAccept(true)
+ , bEnableAcceptAll(true)
+ , bEnableReject(true)
+ , bEnableRejectAll(true)
+ , bEnableUndo(true)
+ , bEnableClearFormat(false)
+ , bEnableClearFormatAll(false)
+ , m_xAccept(m_xBuilder->weld_button("accept"))
+ , m_xReject(m_xBuilder->weld_button("reject"))
+ , m_xAcceptAll(m_xBuilder->weld_button("acceptall"))
+ , m_xRejectAll(m_xBuilder->weld_button("rejectall"))
+ , m_xUndo(m_xBuilder->weld_button("undo"))
+ , m_xViewData(new SvxRedlinTable(m_xBuilder->weld_tree_view("writerchanges"),
+ m_xBuilder->weld_tree_view("calcchanges")))
+{
+ Link<weld::Button&,void> aLink=LINK( this, SvxTPView, PbClickHdl);
+
+ m_xAccept->connect_clicked(aLink);
+ m_xAcceptAll->connect_clicked(aLink);
+ m_xReject->connect_clicked(aLink);
+ m_xRejectAll->connect_clicked(aLink);
+ m_xUndo->connect_clicked(aLink);
+}
+
+void SvxTPView::ActivatePage()
+{
+ m_xAccept->set_sensitive(bEnableAccept);
+ m_xReject->set_sensitive(bEnableReject);
+ m_xAcceptAll->set_sensitive(bEnableAcceptAll);
+ m_xRejectAll->set_sensitive(bEnableRejectAll);
+ m_xUndo->set_sensitive(bEnableUndo);
+}
+
+void SvxTPView::DeactivatePage()
+{
+ m_xAccept->set_sensitive(false);
+ m_xReject->set_sensitive(false);
+ m_xAcceptAll->set_sensitive(false);
+ m_xRejectAll->set_sensitive(false);
+ m_xUndo->set_sensitive(false);
+}
+
+SvxTPView::~SvxTPView()
+{
+}
+
+void SvxRedlinTable::SetWriterView()
+{
+ nDatePos = WRITER_DATE;
+ if (xCalcTreeView)
+ xCalcTreeView->hide();
+ xWriterTreeView->show();
+ pTreeView = xWriterTreeView.get();
+
+ auto nDigitWidth = pTreeView->get_approximate_digit_width();
+ std::vector<int> aWidths
+ {
+ o3tl::narrowing<int>(nDigitWidth * 10),
+ o3tl::narrowing<int>(nDigitWidth * 20),
+ o3tl::narrowing<int>(nDigitWidth * 20)
+ };
+ pTreeView->set_column_fixed_widths(aWidths);
+}
+
+void SvxRedlinTable::SetCalcView()
+{
+ nDatePos = CALC_DATE;
+ if (xWriterTreeView)
+ xWriterTreeView->hide();
+ xCalcTreeView->show();
+ pTreeView = xCalcTreeView.get();
+
+ auto nDigitWidth = pTreeView->get_approximate_digit_width();
+ std::vector<int> aWidths
+ {
+ o3tl::narrowing<int>(nDigitWidth * 20),
+ o3tl::narrowing<int>(nDigitWidth * 20),
+ o3tl::narrowing<int>(nDigitWidth * 20),
+ o3tl::narrowing<int>(nDigitWidth * 20)
+ };
+ pTreeView->set_column_fixed_widths(aWidths);
+}
+
+void SvxTPView::EnableAccept(bool bFlag)
+{
+ bEnableAccept = bFlag;
+ m_xAccept->set_sensitive(bFlag);
+}
+
+void SvxTPView::EnableAcceptAll(bool bFlag)
+{
+ bEnableAcceptAll = bFlag;
+ m_xAcceptAll->set_sensitive(bFlag);
+}
+
+void SvxTPView::EnableReject(bool bFlag)
+{
+ bEnableReject = bFlag;
+ m_xReject->set_sensitive(bFlag);
+}
+
+void SvxTPView::EnableRejectAll(bool bFlag)
+{
+ bEnableRejectAll = bFlag;
+ m_xRejectAll->set_sensitive(bFlag);
+}
+
+void SvxTPView::EnableClearFormat(bool bFlag)
+{
+ if (bEnableClearFormat == bFlag)
+ return;
+ bEnableClearFormat = bFlag;
+}
+
+void SvxTPView::EnableClearFormatAll(bool bFlag)
+{
+ if (bEnableClearFormatAll == bFlag)
+ return;
+ bEnableClearFormatAll = bFlag;
+}
+
+void SvxTPView::ShowUndo()
+{
+ m_xUndo->show();
+}
+
+void SvxTPView::EnableUndo(bool bFlag)
+{
+ bEnableUndo = bFlag;
+ m_xUndo->set_sensitive(bFlag);
+}
+
+IMPL_LINK( SvxTPView, PbClickHdl, weld::Button&, rPushB, void)
+{
+ if (&rPushB == m_xAccept.get())
+ {
+ AcceptClickLk.Call(this);
+ }
+ else if (&rPushB == m_xAcceptAll.get())
+ {
+ AcceptAllClickLk.Call(this);
+ }
+ else if (&rPushB == m_xReject.get())
+ {
+ RejectClickLk.Call(this);
+ }
+ else if (&rPushB == m_xRejectAll.get())
+ {
+ RejectAllClickLk.Call(this);
+ }
+ else if (&rPushB == m_xUndo.get())
+ {
+ UndoClickLk.Call(this);
+ }
+}
+
+SvxTPage::SvxTPage(weld::Container* pParent, const OUString& rUIXMLDescription, const OUString& rID)
+ : m_xBuilder(Application::CreateBuilder(pParent, rUIXMLDescription))
+ , m_xContainer(m_xBuilder->weld_container(rID))
+{
+}
+
+SvxTPFilter::SvxTPFilter(weld::Container* pParent)
+ : SvxTPage(pParent, "svx/ui/redlinefilterpage.ui", "RedlineFilterPage")
+ , bModified(false)
+ , m_pRedlinTable(nullptr)
+ , m_xCbDate(m_xBuilder->weld_check_button("date"))
+ , m_xLbDate(m_xBuilder->weld_combo_box("datecond"))
+ , m_xDfDate(new SvtCalendarBox(m_xBuilder->weld_menu_button("startdate")))
+ , m_xTfDate(m_xBuilder->weld_formatted_spin_button("starttime"))
+ , m_xTfDateFormatter(new weld::TimeFormatter(*m_xTfDate))
+ , m_xIbClock(m_xBuilder->weld_button("startclock"))
+ , m_xFtDate2(m_xBuilder->weld_label("and"))
+ , m_xDfDate2(new SvtCalendarBox(m_xBuilder->weld_menu_button("enddate")))
+ , m_xTfDate2(m_xBuilder->weld_formatted_spin_button("endtime"))
+ , m_xTfDate2Formatter(new weld::TimeFormatter(*m_xTfDate2))
+ , m_xIbClock2(m_xBuilder->weld_button("endclock"))
+ , m_xCbAuthor(m_xBuilder->weld_check_button("author"))
+ , m_xLbAuthor(m_xBuilder->weld_combo_box("authorlist"))
+ , m_xCbRange(m_xBuilder->weld_check_button("range"))
+ , m_xEdRange(m_xBuilder->weld_entry("rangeedit"))
+ , m_xBtnRange(m_xBuilder->weld_button("dotdotdot"))
+ , m_xCbAction(m_xBuilder->weld_check_button("action"))
+ , m_xLbAction(m_xBuilder->weld_combo_box("actionlist"))
+ , m_xCbComment(m_xBuilder->weld_check_button("comment"))
+ , m_xEdComment(m_xBuilder->weld_entry("commentedit"))
+{
+ m_xTfDateFormatter->EnableEmptyField(false);
+ m_xTfDate2Formatter->EnableEmptyField(false);
+
+ m_xLbDate->set_active(0);
+ m_xLbDate->connect_changed( LINK( this, SvxTPFilter, SelDateHdl ) );
+ m_xIbClock->connect_clicked( LINK( this, SvxTPFilter, TimeHdl) );
+ m_xIbClock2->connect_clicked( LINK( this, SvxTPFilter,TimeHdl) );
+ m_xBtnRange->connect_clicked( LINK( this, SvxTPFilter, RefHandle));
+
+ Link<weld::Toggleable&,void> aLink=LINK( this, SvxTPFilter, RowEnableHdl) ;
+ m_xCbDate->connect_toggled(aLink);
+ m_xCbAuthor->connect_toggled(aLink);
+ m_xCbRange->connect_toggled(aLink);
+ m_xCbAction->connect_toggled(aLink);
+ m_xCbComment->connect_toggled(aLink);
+
+ Link<SvtCalendarBox&,void> a2Link=LINK(this, SvxTPFilter, ModifyDate);
+ m_xDfDate->connect_activated(a2Link);
+ m_xDfDate2->connect_activated(a2Link);
+
+ Link<weld::FormattedSpinButton&,void> a3Link=LINK(this, SvxTPFilter, ModifyTime);
+ m_xTfDate->connect_value_changed(a3Link);
+ m_xTfDate2->connect_value_changed(a3Link);
+
+ Link<weld::Entry&,void> a4Link=LINK( this, SvxTPFilter, ModifyHdl);
+ m_xEdRange->connect_changed(a4Link);
+ m_xEdComment->connect_changed(a4Link);
+ m_xLbAction->connect_changed(LINK( this, SvxTPFilter, ModifyListBoxHdl));
+ m_xLbAuthor->connect_changed(LINK( this, SvxTPFilter, ModifyListBoxHdl));
+
+ RowEnableHdl(*m_xCbDate);
+ RowEnableHdl(*m_xCbAuthor);
+ RowEnableHdl(*m_xCbRange);
+ RowEnableHdl(*m_xCbAction);
+ RowEnableHdl(*m_xCbComment);
+
+ DateTime aDateTime(DateTime::SYSTEM);
+ SetFirstDate(aDateTime);
+ SetLastDate(aDateTime);
+ SetFirstTime(aDateTime);
+ SetLastTime(aDateTime);
+ HideRange();
+ ShowAction();
+ bModified=false;
+}
+
+SvxTPFilter::~SvxTPFilter()
+{
+}
+
+void SvxTPFilter::SetRedlinTable(SvxRedlinTable* pTable)
+{
+ m_pRedlinTable = pTable;
+}
+
+void SvxTPFilter::EnableDateLine1(bool bFlag)
+{
+ if(bFlag && m_xCbDate->get_active())
+ {
+ m_xDfDate->set_sensitive(true);
+ m_xTfDate->set_sensitive(true);
+ m_xIbClock->set_sensitive(true);
+ }
+ else
+ {
+ m_xDfDate->set_sensitive(false);
+ m_xTfDate->set_sensitive(false);
+ m_xIbClock->set_sensitive(false);
+ }
+}
+void SvxTPFilter::EnableDateLine2(bool bFlag)
+{
+ if(bFlag && m_xCbDate->get_active())
+ {
+ m_xFtDate2->set_sensitive(true);
+ m_xDfDate2->set_sensitive(true);
+ m_xTfDate2->set_sensitive(true);
+ m_xIbClock2->set_sensitive(true);
+ }
+ else
+ {
+ m_xFtDate2->set_sensitive(false);
+ m_xDfDate2->set_sensitive(false);
+ m_xDfDate2->set_label(OUString());
+ m_xTfDate2->set_sensitive(false);
+ m_xTfDate2->set_text(OUString());
+ m_xIbClock2->set_sensitive(false);
+ }
+}
+
+Date SvxTPFilter::GetFirstDate() const
+{
+ return m_xDfDate->get_date();
+}
+
+void SvxTPFilter::SetFirstDate(const Date &aDate)
+{
+ m_xDfDate->set_date(aDate);
+}
+
+tools::Time SvxTPFilter::GetFirstTime() const
+{
+ return m_xTfDateFormatter->GetTime();
+}
+
+void SvxTPFilter::SetFirstTime(const tools::Time &aTime)
+{
+ m_xTfDateFormatter->SetTime(aTime);
+}
+
+Date SvxTPFilter::GetLastDate() const
+{
+ return m_xDfDate2->get_date();
+}
+
+void SvxTPFilter::SetLastDate(const Date &aDate)
+{
+ m_xDfDate2->set_date(aDate);
+}
+
+tools::Time SvxTPFilter::GetLastTime() const
+{
+ return m_xTfDate2Formatter->GetTime();
+}
+
+void SvxTPFilter::SetLastTime(const tools::Time &aTime)
+{
+ m_xTfDate2Formatter->SetTime(aTime);
+}
+
+void SvxTPFilter::SetDateMode(sal_uInt16 nMode)
+{
+ m_xLbDate->set_active(nMode);
+ SelDateHdl(*m_xLbDate);
+}
+
+SvxRedlinDateMode SvxTPFilter::GetDateMode() const
+{
+ return static_cast<SvxRedlinDateMode>(m_xLbDate->get_active());
+}
+void SvxTPFilter::ClearAuthors()
+{
+ m_xLbAuthor->clear();
+}
+
+void SvxTPFilter::InsertAuthor( const OUString& rString)
+{
+ m_xLbAuthor->append_text(rString);
+}
+
+OUString SvxTPFilter::GetSelectedAuthor() const
+{
+ return m_xLbAuthor->get_active_text();
+}
+
+void SvxTPFilter::SelectedAuthorPos(sal_Int32 nPos)
+{
+ m_xLbAuthor->set_active(nPos);
+}
+
+sal_Int32 SvxTPFilter::SelectAuthor(const OUString& aString)
+{
+ m_xLbAuthor->set_active_text(aString);
+ return m_xLbAuthor->get_active();
+}
+
+void SvxTPFilter::SetRange(const OUString& rString)
+{
+ m_xEdRange->set_text(rString);
+}
+
+OUString SvxTPFilter::GetRange() const
+{
+ return m_xEdRange->get_text();
+}
+
+void SvxTPFilter::SetFocusToRange()
+{
+ m_xEdRange->grab_focus();
+}
+
+void SvxTPFilter::HideRange(bool bHide)
+{
+ if (bHide)
+ {
+ m_xCbRange->hide();
+ m_xEdRange->hide();
+ m_xBtnRange->hide();
+ }
+ else
+ {
+ ShowAction(false);
+ m_xCbRange->show();
+ m_xEdRange->show();
+ m_xBtnRange->show();
+ }
+}
+
+void SvxTPFilter::SetComment(const OUString &rComment)
+{
+ m_xEdComment->set_text(rComment);
+}
+
+OUString SvxTPFilter::GetComment()const
+{
+ return m_xEdComment->get_text();
+}
+
+bool SvxTPFilter::IsDate() const
+{
+ return m_xCbDate->get_active();
+}
+
+bool SvxTPFilter::IsAuthor() const
+{
+ return m_xCbAuthor->get_active();
+}
+
+bool SvxTPFilter::IsRange() const
+{
+ return m_xCbRange->get_active();
+}
+
+bool SvxTPFilter::IsAction() const
+{
+ return m_xCbAction->get_active();
+}
+
+bool SvxTPFilter::IsComment() const
+{
+ return m_xCbComment->get_active();
+}
+
+void SvxTPFilter::CheckDate(bool bFlag)
+{
+ m_xCbDate->set_active(bFlag);
+ RowEnableHdl(*m_xCbDate);
+ bModified=false;
+}
+
+void SvxTPFilter::CheckAuthor(bool bFlag)
+{
+ m_xCbAuthor->set_active(bFlag);
+ RowEnableHdl(*m_xCbAuthor);
+ bModified=false;
+}
+
+void SvxTPFilter::CheckRange(bool bFlag)
+{
+ m_xCbRange->set_active(bFlag);
+ RowEnableHdl(*m_xCbRange);
+ bModified=false;
+}
+
+void SvxTPFilter::CheckAction(bool bFlag)
+{
+ m_xCbAction->set_active(bFlag);
+ RowEnableHdl(*m_xCbAction);
+ bModified=false;
+}
+
+void SvxTPFilter::CheckComment(bool bFlag)
+{
+ m_xCbComment->set_active(bFlag);
+ RowEnableHdl(*m_xCbComment);
+ bModified=false;
+}
+
+void SvxTPFilter::ShowAction(bool bShow)
+{
+ if(!bShow)
+ {
+ m_xCbAction->hide();
+ m_xLbAction->hide();
+ }
+ else
+ {
+ HideRange();
+ m_xCbAction->show();
+ m_xLbAction->show();
+ }
+}
+
+IMPL_LINK_NOARG(SvxTPFilter, SelDateHdl, weld::ComboBox&, void)
+{
+ SvxRedlinDateMode nKind = static_cast<SvxRedlinDateMode>(m_xLbDate->get_active());
+ switch(nKind)
+ {
+ case SvxRedlinDateMode::BEFORE:
+ EnableDateLine1(true);
+ EnableDateLine2(false);
+ break;
+ case SvxRedlinDateMode::SINCE:
+ EnableDateLine1(true);
+ EnableDateLine2(false);
+ break;
+ case SvxRedlinDateMode::EQUAL:
+ EnableDateLine1(true);
+ m_xTfDate->set_sensitive(false);
+ m_xTfDate->set_text(OUString());
+ EnableDateLine2(false);
+ break;
+ case SvxRedlinDateMode::NOTEQUAL:
+ EnableDateLine1(true);
+ m_xTfDate->set_sensitive(false);
+ m_xTfDate->set_text(OUString());
+ EnableDateLine2(false);
+ break;
+ case SvxRedlinDateMode::BETWEEN:
+ EnableDateLine1(true);
+ EnableDateLine2(true);
+ break;
+ case SvxRedlinDateMode::SAVE:
+ EnableDateLine1(false);
+ EnableDateLine2(false);
+ break;
+ case SvxRedlinDateMode::NONE:
+ break;
+ }
+ bModified = true;
+}
+
+IMPL_LINK(SvxTPFilter, RowEnableHdl, weld::Toggleable&, rCB, void)
+{
+ if (&rCB == m_xCbDate.get())
+ {
+ m_xLbDate->set_sensitive(m_xCbDate->get_active());
+ EnableDateLine1(false);
+ EnableDateLine2(false);
+ if(m_xCbDate->get_active()) SelDateHdl(*m_xLbDate);
+ }
+ else if (&rCB == m_xCbAuthor.get())
+ {
+ m_xLbAuthor->set_sensitive(m_xCbAuthor->get_active());
+ }
+ else if (&rCB == m_xCbRange.get())
+ {
+ m_xEdRange->set_sensitive(m_xCbRange->get_active());
+ m_xBtnRange->set_sensitive(m_xCbRange->get_active());
+ }
+ else if (&rCB == m_xCbAction.get())
+ {
+ m_xLbAction->set_sensitive(m_xCbAction->get_active());
+ }
+ else if (&rCB == m_xCbComment.get())
+ {
+ m_xEdComment->set_sensitive(m_xCbComment->get_active());
+ }
+ bModified = true;
+}
+
+IMPL_LINK(SvxTPFilter, TimeHdl, weld::Button&, rIB, void)
+{
+ DateTime aDateTime( DateTime::SYSTEM );
+ if (&rIB == m_xIbClock.get())
+ {
+ SetFirstDate(aDateTime);
+ SetFirstTime(aDateTime);
+ }
+ else if (&rIB == m_xIbClock2.get())
+ {
+ SetLastDate(aDateTime);
+ SetLastTime(aDateTime);
+ }
+ bModified=true;
+}
+
+IMPL_LINK_NOARG(SvxTPFilter, ModifyHdl, weld::Entry&, void)
+{
+ bModified=true;
+}
+
+IMPL_LINK_NOARG(SvxTPFilter, ModifyListBoxHdl, weld::ComboBox&, void)
+{
+ bModified=true;
+}
+
+void SvxTPFilter::DeactivatePage()
+{
+ if(bModified)
+ {
+ if (m_pRedlinTable)
+ {
+ m_pRedlinTable->SetFilterDate(IsDate());
+ m_pRedlinTable->SetDateTimeMode(GetDateMode());
+ m_pRedlinTable->SetFirstDate(GetFirstDate());
+ m_pRedlinTable->SetLastDate(GetLastDate());
+ m_pRedlinTable->SetFirstTime(GetFirstTime());
+ m_pRedlinTable->SetLastTime(GetLastTime());
+ m_pRedlinTable->SetFilterAuthor(IsAuthor());
+ m_pRedlinTable->SetAuthor(GetSelectedAuthor());
+
+ m_pRedlinTable->SetFilterComment(IsComment());
+
+ utl::SearchParam aSearchParam( m_xEdComment->get_text(),
+ utl::SearchParam::SearchType::Regexp,false );
+
+ m_pRedlinTable->SetCommentParams(&aSearchParam);
+
+ m_pRedlinTable->UpdateFilterTest();
+ }
+
+ aReadyLink.Call(this);
+ }
+ bModified=false;
+}
+
+void SvxTPFilter::Enable(bool bEnable)
+{
+ m_xContainer->set_sensitive(bEnable);
+ if (m_xCbDate->get_sensitive())
+ {
+ RowEnableHdl(*m_xCbDate);
+ RowEnableHdl(*m_xCbAuthor);
+ RowEnableHdl(*m_xCbRange);
+ RowEnableHdl(*m_xCbComment);
+ }
+}
+
+IMPL_LINK(SvxTPFilter, ModifyDate, SvtCalendarBox&, rTF, void)
+{
+ Date aDate( Date::SYSTEM );
+ if (m_xDfDate.get() == &rTF)
+ {
+ if (m_xDfDate->get_label().isEmpty())
+ m_xDfDate->set_date(aDate);
+
+ if(m_pRedlinTable!=nullptr)
+ m_pRedlinTable->SetFirstDate(m_xDfDate->get_date());
+ }
+ else if (m_xDfDate2.get() == &rTF)
+ {
+ if (m_xDfDate2->get_label().isEmpty())
+ m_xDfDate2->set_date(aDate);
+
+ if (m_pRedlinTable)
+ m_pRedlinTable->SetLastDate(m_xDfDate2->get_date());
+ }
+ bModified=true;
+}
+
+IMPL_LINK(SvxTPFilter, ModifyTime, weld::FormattedSpinButton&, rTF, void)
+{
+ tools::Time aTime(0);
+ if (m_xTfDate.get() == &rTF)
+ {
+ if (m_xTfDate->get_text().isEmpty())
+ SetFirstTime(aTime);
+
+ if (m_pRedlinTable!=nullptr)
+ m_pRedlinTable->SetFirstTime(GetFirstTime());
+ }
+ else if (m_xTfDate2.get() == &rTF)
+ {
+ if (m_xTfDate2->get_text().isEmpty())
+ SetLastTime(aTime);
+
+ if (m_pRedlinTable!=nullptr)
+ m_pRedlinTable->SetLastTime(GetLastTime());
+
+ }
+ bModified=true;
+}
+
+IMPL_LINK_NOARG(SvxTPFilter, RefHandle, weld::Button&, void)
+{
+ aRefLink.Call(this);
+}
+
+SvxAcceptChgCtr::SvxAcceptChgCtr(weld::Container* pParent)
+ : m_xBuilder(Application::CreateBuilder(pParent, "svx/ui/redlinecontrol.ui"))
+ , m_xTabCtrl(m_xBuilder->weld_notebook("tabcontrol"))
+{
+ m_xTabCtrl->connect_enter_page(LINK(this, SvxAcceptChgCtr, ActivatePageHdl));
+ m_xTabCtrl->connect_leave_page(LINK(this, SvxAcceptChgCtr, DeactivatePageHdl));
+
+ m_xTPFilter.reset(new SvxTPFilter(m_xTabCtrl->get_page("filter")));
+ m_xTPView.reset(new SvxTPView(m_xTabCtrl->get_page("view")));
+ m_xTPFilter->SetRedlinTable(m_xTPView->GetTableControl());
+ m_xTabCtrl->set_current_page("view");
+ m_xTabCtrl->set_help_id(HID_REDLINE_CTRL_VIEW);
+ m_xTabCtrl->show();
+}
+
+SvxAcceptChgCtr::~SvxAcceptChgCtr()
+{
+ m_xTPFilter.reset();
+ m_xTPView.reset();
+}
+
+void SvxAcceptChgCtr::ShowFilterPage()
+{
+ m_xTabCtrl->set_current_page("filter");
+}
+
+IMPL_LINK(SvxAcceptChgCtr, ActivatePageHdl, const OUString&, rPage, void)
+{
+ if (rPage == "filter")
+ {
+ m_xTPFilter->ActivatePage();
+ m_xTabCtrl->set_help_id(HID_REDLINE_CTRL_FILTER);
+ }
+ else if (rPage == "view")
+ {
+ m_xTPView->ActivatePage();
+ m_xTabCtrl->set_help_id(HID_REDLINE_CTRL_VIEW);
+ }
+}
+
+IMPL_LINK(SvxAcceptChgCtr, DeactivatePageHdl, const OUString&, rPage, bool)
+{
+ if (rPage == "filter")
+ m_xTPFilter->DeactivatePage();
+ else if (rPage == "view")
+ m_xTPView->DeactivatePage();
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/databaseregistrationui.cxx b/svx/source/dialog/databaseregistrationui.cxx
new file mode 100644
index 0000000000..aa62b5b388
--- /dev/null
+++ b/svx/source/dialog/databaseregistrationui.cxx
@@ -0,0 +1,45 @@
+/* -*- 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 <svx/databaseregistrationui.hxx>
+
+#include <svx/svxdlg.hxx>
+#include <svx/dialogs.hrc>
+
+#include <sfx2/app.hxx>
+#include <svl/itemset.hxx>
+
+namespace svx
+{
+ sal_uInt16 administrateDatabaseRegistration(weld::Window* parentWindow)
+ {
+ sal_uInt16 nResult = RET_CANCEL;
+
+ SfxItemSetFixed<SID_SB_DB_REGISTER, SID_SB_DB_REGISTER> aRegistrationItems( SfxGetpApp()->GetPool() );
+
+ SvxAbstractDialogFactory* pDialogFactory = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<SfxAbstractDialog> pDialog(pDialogFactory->CreateSfxDialog(parentWindow, aRegistrationItems, nullptr, RID_SFXPAGE_DBREGISTER));
+ nResult = pDialog->Execute();
+
+ return nResult;
+ }
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/dialcontrol.cxx b/svx/source/dialog/dialcontrol.cxx
new file mode 100644
index 0000000000..adda37b22e
--- /dev/null
+++ b/svx/source/dialog/dialcontrol.cxx
@@ -0,0 +1,479 @@
+/* -*- 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 <svx/dialcontrol.hxx>
+#include <svx/svdtrans.hxx>
+#include <cmath>
+#include <vcl/virdev.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/bitmapex.hxx>
+#include <vcl/event.hxx>
+#include <vcl/settings.hxx>
+#include <i18nlangtag/languagetag.hxx>
+
+namespace svx {
+
+const tools::Long DIAL_OUTER_WIDTH = 8;
+
+DialControlBmp::DialControlBmp(OutputDevice& rReference)
+ : VirtualDevice(rReference, DeviceFormat::WITH_ALPHA)
+ , mbEnabled(true)
+ , mrParent(rReference)
+ , mnCenterX(0)
+ , mnCenterY(0)
+{
+ EnableRTL(false);
+}
+
+void DialControlBmp::InitBitmap(const vcl::Font& rFont)
+{
+ Init();
+ SetFont(rFont);
+}
+
+void DialControlBmp::CopyBackground( const DialControlBmp& rSrc )
+{
+ Init();
+ SetSize(rSrc.maRect.GetSize());
+ mbEnabled = rSrc.mbEnabled;
+ Point aPos;
+ DrawBitmapEx( aPos, rSrc.GetBitmapEx( aPos, maRect.GetSize() ) );
+}
+
+void DialControlBmp::DrawBackground( const Size& rSize, bool bEnabled )
+{
+ Init();
+ SetSize(rSize);
+ mbEnabled = bEnabled;
+ DrawBackground();
+}
+
+void DialControlBmp::DrawElements( const OUString& rText, Degree100 nAngle )
+{
+ double fAngle = toRadians(nAngle);
+ double fSin = sin( fAngle );
+ double fCos = cos( fAngle );
+ double fWidth = GetTextWidth( rText ) / 2.0;
+ double fHeight = GetTextHeight() / 2.0;
+
+ if ( !rText.isEmpty() )
+ {
+ // rotated text
+ vcl::Font aFont( GetFont() );
+ aFont.SetColor( GetTextColor() );
+ aFont.SetOrientation( to<Degree10>(nAngle) ); // Font uses 1/10 degrees
+ aFont.SetWeight( WEIGHT_BOLD );
+ SetFont( aFont );
+
+ tools::Long nX = static_cast< tools::Long >( mnCenterX - fWidth * fCos - fHeight * fSin );
+ tools::Long nY = static_cast< tools::Long >( mnCenterY + fWidth * fSin - fHeight * fCos );
+ tools::Rectangle aRect( nX, nY, 2 * mnCenterX - nX, 2 * mnCenterY - nY );
+ DrawText( aRect, rText, mbEnabled ? DrawTextFlags::NONE : DrawTextFlags::Disable );
+ }
+ else
+ {
+ // only a line
+ const sal_Int32 nDx (fCos * (maRect.GetWidth()-4) / 2);
+ const sal_Int32 nDy (-fSin * (maRect.GetHeight()-4) / 2);
+ Point pt1( maRect.Center() );
+ Point pt2( pt1.X() + nDx, pt1.Y() + nDy);
+
+ SetLineColor( GetTextColor() );
+ DrawLine( pt1, pt2 );
+ }
+
+ // *** drag button ***
+
+ bool bMain = (nAngle % 4500_deg100) != 0_deg100;
+ SetLineColor( GetButtonLineColor() );
+ SetFillColor( GetButtonFillColor( bMain ) );
+
+ tools::Long nX = mnCenterX - static_cast< tools::Long >( (DIAL_OUTER_WIDTH / 2 - mnCenterX) * fCos );
+ tools::Long nY = mnCenterY - static_cast< tools::Long >( (mnCenterY - DIAL_OUTER_WIDTH / 2) * fSin );
+ tools::Long nSize = bMain ? (DIAL_OUTER_WIDTH / 4) : (DIAL_OUTER_WIDTH / 2 - 1);
+ DrawEllipse( tools::Rectangle( nX - nSize, nY - nSize, nX + nSize, nY + nSize ) );
+}
+
+Color DialControlBmp::GetBackgroundColor() const
+{
+ return GetSettings().GetStyleSettings().GetDialogColor();
+}
+
+const Color& DialControlBmp::GetTextColor() const
+{
+ return GetSettings().GetStyleSettings().GetLabelTextColor();
+}
+
+const Color& DialControlBmp::GetScaleLineColor() const
+{
+ const StyleSettings& rSett = GetSettings().GetStyleSettings();
+ return mbEnabled ? rSett.GetButtonTextColor() : rSett.GetDisableColor();
+}
+
+const Color& DialControlBmp::GetButtonLineColor() const
+{
+ const StyleSettings& rSett = GetSettings().GetStyleSettings();
+ return mbEnabled ? rSett.GetButtonTextColor() : rSett.GetDisableColor();
+}
+
+const Color& DialControlBmp::GetButtonFillColor( bool bMain ) const
+{
+ const StyleSettings& rSett = GetSettings().GetStyleSettings();
+ return mbEnabled ? (bMain ? rSett.GetMenuColor() : rSett.GetHighlightColor()) : rSett.GetDisableColor();
+}
+
+void DialControlBmp::Init()
+{
+ SetSettings(mrParent.GetSettings());
+ SetBackground(GetBackgroundColor());
+}
+
+void DialControlBmp::SetSize( const Size& rSize )
+{
+ maRect.SetPos( Point( 0, 0 ) );
+ maRect.SetSize( rSize );
+ mnCenterX = rSize.Width() / 2;
+ mnCenterY = rSize.Height() / 2;
+ SetOutputSize( rSize );
+}
+
+void DialControlBmp::DrawBackground()
+{
+ // *** background with 3D effect ***
+
+ SetLineColor();
+ SetFillColor();
+ Erase();
+
+ EnableRTL(); // draw 3D effect in correct direction
+
+ sal_uInt8 nDiff = mbEnabled ? 0x18 : 0x10;
+ Color aColor;
+
+ aColor = GetBackgroundColor();
+ SetFillColor( aColor );
+ DrawPie( maRect, maRect.TopRight(), maRect.TopCenter() );
+ DrawPie( maRect, maRect.BottomLeft(), maRect.BottomCenter() );
+
+ aColor.DecreaseLuminance( nDiff );
+ SetFillColor( aColor );
+ DrawPie( maRect, maRect.BottomCenter(), maRect.TopRight() );
+
+ aColor.DecreaseLuminance( nDiff );
+ SetFillColor( aColor );
+ DrawPie( maRect, maRect.BottomRight(), maRect.RightCenter() );
+
+ aColor = GetBackgroundColor();
+ aColor.IncreaseLuminance( nDiff );
+ SetFillColor( aColor );
+ DrawPie( maRect, maRect.TopCenter(), maRect.BottomLeft() );
+
+ aColor.IncreaseLuminance( nDiff );
+ SetFillColor( aColor );
+ DrawPie( maRect, maRect.TopLeft(), maRect.LeftCenter() );
+
+ EnableRTL( false );
+
+ // *** calibration ***
+
+ Point aStartPos( mnCenterX, mnCenterY );
+ Color aFullColor( GetScaleLineColor() );
+ Color aLightColor( GetBackgroundColor() );
+ aLightColor.Merge( aFullColor, 128 );
+
+ for( int nAngle = 0; nAngle < 360; nAngle += 15 )
+ {
+ SetLineColor( (nAngle % 45) ? aLightColor : aFullColor );
+ double fAngle = basegfx::deg2rad(nAngle);
+ tools::Long nX = static_cast< tools::Long >( -mnCenterX * cos( fAngle ) );
+ tools::Long nY = static_cast< tools::Long >( mnCenterY * sin( fAngle ) );
+ DrawLine( aStartPos, Point( mnCenterX - nX, mnCenterY - nY ) );
+ }
+
+ // *** clear inner area ***
+
+ SetLineColor();
+ SetFillColor( GetBackgroundColor() );
+ tools::Rectangle aEllipseRect = maRect;
+ aEllipseRect.shrink(DIAL_OUTER_WIDTH);
+ DrawEllipse( aEllipseRect );
+}
+
+DialControl::DialControl_Impl::DialControl_Impl(OutputDevice& rReference) :
+ mxBmpEnabled(VclPtr<DialControlBmp>::Create(rReference)),
+ mxBmpDisabled(VclPtr<DialControlBmp>::Create(rReference)),
+ mxBmpBuffered(VclPtr<DialControlBmp>::Create(rReference)),
+ mpLinkField( nullptr ),
+ mnLinkedFieldValueMultiplyer( 0 ),
+ mnAngle( 0 ),
+ mnInitialAngle( 0 ),
+ mnOldAngle( 0 ),
+ mnCenterX( 0 ),
+ mnCenterY( 0 ),
+ mbNoRot( false )
+{
+}
+
+void DialControl::DialControl_Impl::Init( const Size& rWinSize, const vcl::Font& rWinFont )
+{
+ maWinFont = rWinFont;
+ maWinFont.SetTransparent(true);
+ mxBmpBuffered->InitBitmap(maWinFont);
+ SetSize(rWinSize);
+}
+
+void DialControl::DialControl_Impl::SetSize( const Size& rWinSize )
+{
+ // make the control squared, and adjusted so that we have a well-defined
+ // center ["(x - 1) | 1" creates odd value <= x]
+ tools::Long nMin = (std::min(rWinSize.Width(), rWinSize.Height()) - 1) | 1;
+
+ maWinSize = Size( nMin, nMin );
+
+ mnCenterX = maWinSize.Width() / 2;
+ mnCenterY = maWinSize.Height() / 2;
+
+ mxBmpEnabled->DrawBackground( maWinSize, true );
+ mxBmpDisabled->DrawBackground( maWinSize, false );
+ mxBmpBuffered->SetSize( maWinSize );
+}
+
+void DialControl::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ CustomWidgetController::SetDrawingArea(pDrawingArea);
+ //use same logic as DialControl_Impl::SetSize
+ int nDim = (std::min<int>(pDrawingArea->get_approximate_digit_width() * 12,
+ pDrawingArea->get_text_height() * 6) - 1) | 1;
+ Size aSize(nDim, nDim);
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+ mpImpl.reset(new DialControl_Impl(pDrawingArea->get_ref_device()));
+ //set size and use that
+ Init(aSize);
+}
+
+void DialControl::Resize()
+{
+ mpImpl->SetSize(GetOutputSizePixel());
+ InvalidateControl();
+}
+
+void DialControl::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ Point aPos;
+ rRenderContext.DrawBitmapEx(aPos, mpImpl->mxBmpBuffered->GetBitmapEx(aPos, mpImpl->maWinSize));
+}
+
+void DialControl::StyleUpdated()
+{
+ CustomWidgetController::StyleUpdated();
+ Init( mpImpl->maWinSize, mpImpl->maWinFont );
+ InvalidateControl();
+}
+
+bool DialControl::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ if( rMEvt.IsLeft() )
+ {
+ GrabFocus();
+ CaptureMouse();
+ mpImpl->mnOldAngle = mpImpl->mnAngle;
+ HandleMouseEvent( rMEvt.GetPosPixel(), true );
+ }
+ return true;
+}
+
+bool DialControl::MouseMove( const MouseEvent& rMEvt )
+{
+ if( IsMouseCaptured() && rMEvt.IsLeft() )
+ HandleMouseEvent( rMEvt.GetPosPixel(), false );
+ return true;
+}
+
+bool DialControl::MouseButtonUp(const MouseEvent&)
+{
+ if( IsMouseCaptured() )
+ {
+ ReleaseMouse();
+ if( mpImpl->mpLinkField )
+ mpImpl->mpLinkField->grab_focus();
+ }
+ return true;
+}
+
+bool DialControl::KeyInput( const KeyEvent& rKEvt )
+{
+ const vcl::KeyCode& rKCode = rKEvt.GetKeyCode();
+ if( !rKCode.GetModifier() && (rKCode.GetCode() == KEY_ESCAPE) )
+ {
+ HandleEscapeEvent();
+ return true;
+ }
+ return CustomWidgetController::KeyInput(rKEvt);
+}
+
+void DialControl::LoseFocus()
+{
+ // release captured mouse
+ HandleEscapeEvent();
+}
+
+bool DialControl::HasRotation() const
+{
+ return !mpImpl->mbNoRot;
+}
+
+void DialControl::SetNoRotation()
+{
+ if( !mpImpl->mbNoRot )
+ {
+ mpImpl->mbNoRot = true;
+ InvalidateControl();
+ if (mpImpl->mpLinkField)
+ mpImpl->mpLinkField->set_text("");
+ }
+}
+
+Degree100 DialControl::GetRotation() const
+{
+ return mpImpl->mnAngle;
+}
+
+void DialControl::SetRotation(Degree100 nAngle)
+{
+ SetRotation(nAngle, false);
+}
+
+void DialControl::SetLinkedField(weld::MetricSpinButton* pField, sal_Int32 nDecimalPlaces)
+{
+ mpImpl->mnLinkedFieldValueMultiplyer = 100 / std::pow(10.0, double(nDecimalPlaces));
+
+ // remove modify handler from old linked field
+ if( mpImpl->mpLinkField )
+ {
+ weld::MetricSpinButton& rField = *mpImpl->mpLinkField;
+ rField.connect_value_changed(Link<weld::MetricSpinButton&,void>());
+ }
+ // remember the new linked field
+ mpImpl->mpLinkField = pField;
+ // set modify handler at new linked field
+ if( mpImpl->mpLinkField )
+ {
+ weld::MetricSpinButton& rField = *mpImpl->mpLinkField;
+ rField.connect_value_changed(LINK(this, DialControl, LinkedFieldModifyHdl));
+ }
+}
+
+IMPL_LINK_NOARG(DialControl, LinkedFieldModifyHdl, weld::MetricSpinButton&, void)
+{
+ SetRotation(Degree100(mpImpl->mpLinkField->get_value(FieldUnit::DEGREE) * mpImpl->mnLinkedFieldValueMultiplyer), true);
+}
+
+void DialControl::SaveValue()
+{
+ mpImpl->mnInitialAngle = mpImpl->mnAngle;
+}
+
+bool DialControl::IsValueModified() const
+{
+ return mpImpl->mnInitialAngle != mpImpl->mnAngle;
+}
+
+void DialControl::Init( const Size& rWinSize, const vcl::Font& rWinFont )
+{
+ mpImpl->Init( rWinSize, rWinFont );
+ EnableRTL( false ); // don't mirror mouse handling
+ SetOutputSizePixel( mpImpl->maWinSize );
+}
+
+void DialControl::Init( const Size& rWinSize )
+{
+ //hidpi TODO: GetDefaultFont() picks a font size too small, so fix it here.
+ vcl::Font aDefaultSize = Application::GetSettings().GetStyleSettings().GetLabelFont();
+
+ vcl::Font aFont( OutputDevice::GetDefaultFont(
+ DefaultFontType::UI_SANS, Application::GetSettings().GetUILanguageTag().getLanguageType(), GetDefaultFontFlags::OnlyOne ) );
+
+ aFont.SetFontHeight(aDefaultSize.GetFontHeight());
+ Init( rWinSize, aFont );
+}
+
+void DialControl::InvalidateControl()
+{
+ mpImpl->mxBmpBuffered->CopyBackground( IsEnabled() ? *mpImpl->mxBmpEnabled : *mpImpl->mxBmpDisabled );
+ if( !mpImpl->mbNoRot )
+ mpImpl->mxBmpBuffered->DrawElements(GetText(), mpImpl->mnAngle);
+ Invalidate();
+}
+
+void DialControl::SetRotation(Degree100 nAngle, bool bBroadcast)
+{
+ bool bOldSel = mpImpl->mbNoRot;
+ mpImpl->mbNoRot = false;
+
+ nAngle = NormAngle36000(nAngle);
+
+ if (!bOldSel || (mpImpl->mnAngle != nAngle))
+ {
+ mpImpl->mnAngle = nAngle;
+ InvalidateControl();
+ if( mpImpl->mpLinkField )
+ mpImpl->mpLinkField->set_value(GetRotation().get() / mpImpl->mnLinkedFieldValueMultiplyer, FieldUnit::DEGREE);
+ if( bBroadcast )
+ mpImpl->maModifyHdl.Call(*this);
+ }
+}
+
+void DialControl::SetModifyHdl( const Link<DialControl&,void>& rLink )
+{
+ mpImpl->maModifyHdl = rLink;
+}
+
+void DialControl::HandleMouseEvent( const Point& rPos, bool bInitial )
+{
+ tools::Long nX = rPos.X() - mpImpl->mnCenterX;
+ tools::Long nY = mpImpl->mnCenterY - rPos.Y();
+ double fH = std::hypot( nX, nY );
+ if( fH != 0.0 )
+ {
+ double fAngle = acos( nX / fH );
+ sal_Int32 nAngle = basegfx::rad2deg<100>(fAngle);
+ if( nY < 0 )
+ nAngle = 36000 - nAngle;
+ if( bInitial ) // round to entire 15 degrees
+ nAngle = ((nAngle + 750) / 1500) * 1500;
+ // Round up to 1 degree
+ nAngle = (((nAngle + 50) / 100) * 100) % 36000;
+ SetRotation(Degree100(nAngle), true);
+ }
+}
+
+void DialControl::HandleEscapeEvent()
+{
+ if( IsMouseCaptured() )
+ {
+ ReleaseMouse();
+ SetRotation(mpImpl->mnOldAngle, true);
+ if( mpImpl->mpLinkField )
+ mpImpl->mpLinkField->grab_focus();
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/dialmgr.cxx b/svx/source/dialog/dialmgr.cxx
new file mode 100644
index 0000000000..9fdd50ddab
--- /dev/null
+++ b/svx/source/dialog/dialmgr.cxx
@@ -0,0 +1,26 @@
+/* -*- 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 <svx/dialmgr.hxx>
+
+std::locale SvxResLocale() { return Translate::Create("svx"); }
+
+OUString SvxResId(TranslateId aId) { return Translate::get(aId, SvxResLocale()); }
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/dlgctl3d.cxx b/svx/source/dialog/dlgctl3d.cxx
new file mode 100644
index 0000000000..e315819b06
--- /dev/null
+++ b/svx/source/dialog/dlgctl3d.cxx
@@ -0,0 +1,1165 @@
+/* -*- 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 <svx/dlgctl3d.hxx>
+#include <svx/strings.hrc>
+#include <svx/view3d.hxx>
+#include <svx/fmmodel.hxx>
+#include <svl/itempool.hxx>
+#include <svx/fmpage.hxx>
+#include <svx/sphere3d.hxx>
+#include <svx/cube3d.hxx>
+#include <svx/scene3d.hxx>
+#include <vcl/svapp.hxx>
+#include <svx/helperhittest3d.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <polygn3d.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xlnclit.hxx>
+#include <svx/xlnwtit.hxx>
+#include <helpids.h>
+#include <svx/dialmgr.hxx>
+#include <tools/helpers.hxx>
+#include <vcl/settings.hxx>
+
+using namespace com::sun::star;
+
+Svx3DPreviewControl::Svx3DPreviewControl()
+ : mnObjectType(SvxPreviewObjectType::SPHERE)
+{
+}
+
+void Svx3DPreviewControl::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ Size aSize(pDrawingArea->get_ref_device().LogicToPixel(Size(80, 100), MapMode(MapUnit::MapAppFont)));
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+ CustomWidgetController::SetDrawingArea(pDrawingArea);
+ SetOutputSizePixel(aSize);
+
+ Construct();
+}
+
+Svx3DPreviewControl::~Svx3DPreviewControl()
+{
+ mp3DObj.clear();
+ mxFmPage.clear();
+ mpScene.clear();
+ mp3DView.reset();
+ mpModel.reset();
+}
+
+void Svx3DPreviewControl::Construct()
+{
+ // Do never mirror the preview window. This explicitly includes right
+ // to left writing environments.
+ EnableRTL (false);
+ OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
+ rDevice.SetMapMode(MapMode(MapUnit::Map100thMM));
+
+ // Model
+ mpModel.reset(new FmFormModel());
+ mpModel->GetItemPool().FreezeIdRanges();
+
+ // Page
+ mxFmPage = new FmFormPage( *mpModel );
+ mpModel->InsertPage( mxFmPage.get(), 0 );
+
+ // 3D View
+ mp3DView.reset(new E3dView(*mpModel, &rDevice));
+ mp3DView->SetBufferedOutputAllowed(true);
+ mp3DView->SetBufferedOverlayAllowed(true);
+
+ // 3D Scene
+ mpScene = new E3dScene(*mpModel);
+
+ // initially create object
+ SetObjectType(SvxPreviewObjectType::SPHERE);
+
+ // camera and perspective
+ Camera3D rCamera = mpScene->GetCamera();
+ const basegfx::B3DRange& rVolume = mpScene->GetBoundVolume();
+ double fW = rVolume.getWidth();
+ double fH = rVolume.getHeight();
+ double fCamZ = rVolume.getMaxZ() + ((fW + fH) / 2.0);
+
+ rCamera.SetAutoAdjustProjection(false);
+ rCamera.SetViewWindow(- fW / 2, - fH / 2, fW, fH);
+ basegfx::B3DPoint aLookAt;
+ double fDefaultCamPosZ = mp3DView->GetDefaultCamPosZ();
+ basegfx::B3DPoint aCamPos(0.0, 0.0, fCamZ < fDefaultCamPosZ ? fDefaultCamPosZ : fCamZ);
+ rCamera.SetPosAndLookAt(aCamPos, aLookAt);
+ double fDefaultCamFocal = mp3DView->GetDefaultCamFocal();
+ rCamera.SetFocalLength(fDefaultCamFocal);
+
+ mpScene->SetCamera( rCamera );
+ mxFmPage->InsertObject( mpScene.get() );
+
+ basegfx::B3DHomMatrix aRotation;
+ aRotation.rotate(basegfx::deg2rad( 25 ), 0.0, 0.0);
+ aRotation.rotate(0.0, basegfx::deg2rad( 40 ), 0.0);
+ mpScene->SetTransform(aRotation * mpScene->GetTransform());
+
+ // invalidate SnapRects of objects
+ mpScene->SetBoundAndSnapRectsDirty();
+
+ SfxItemSetFixed<XATTR_LINESTYLE, XATTR_LINESTYLE,
+ XATTR_FILL_FIRST, XATTR_FILLBITMAP> aSet( mpModel->GetItemPool() );
+ aSet.Put( XLineStyleItem( drawing::LineStyle_NONE ) );
+ aSet.Put( XFillStyleItem( drawing::FillStyle_SOLID ) );
+ aSet.Put( XFillColorItem( "", COL_WHITE ) );
+
+ mpScene->SetMergedItemSet(aSet);
+
+ // PageView
+ SdrPageView* pPageView = mp3DView->ShowSdrPage( mxFmPage.get() );
+ mp3DView->hideMarkHandles();
+
+ // mark scene
+ mp3DView->MarkObj( mpScene.get(), pPageView );
+}
+
+void Svx3DPreviewControl::Resize()
+{
+ // size of page
+ Size aSize(GetOutputSizePixel());
+ aSize = GetDrawingArea()->get_ref_device().PixelToLogic(aSize);
+ mxFmPage->SetSize(aSize);
+
+ // set size
+ Size aObjSize( aSize.Width()*5/6, aSize.Height()*5/6 );
+ Point aObjPoint( (aSize.Width() - aObjSize.Width()) / 2,
+ (aSize.Height() - aObjSize.Height()) / 2);
+ tools::Rectangle aRect( aObjPoint, aObjSize);
+ mpScene->SetSnapRect( aRect );
+}
+
+void Svx3DPreviewControl::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
+{
+ mp3DView->CompleteRedraw(&rRenderContext, vcl::Region(rRect));
+}
+
+bool Svx3DPreviewControl::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ if (rMEvt.IsShift() && rMEvt.IsMod1())
+ {
+ if(SvxPreviewObjectType::SPHERE == GetObjectType())
+ {
+ SetObjectType(SvxPreviewObjectType::CUBE);
+ }
+ else
+ {
+ SetObjectType(SvxPreviewObjectType::SPHERE);
+ }
+ }
+ return false;
+}
+
+void Svx3DPreviewControl::SetObjectType(SvxPreviewObjectType nType)
+{
+ if(mnObjectType == nType && mp3DObj)
+ return;
+
+ SfxItemSetFixed<SDRATTR_START, SDRATTR_END> aSet(mpModel->GetItemPool());
+ mnObjectType = nType;
+
+ if( mp3DObj )
+ {
+ aSet.Put(mp3DObj->GetMergedItemSet());
+ mpScene->RemoveObject( mp3DObj->GetOrdNum() );
+ mp3DObj.clear();
+ }
+
+ switch( nType )
+ {
+ case SvxPreviewObjectType::SPHERE:
+ {
+ mp3DObj = new E3dSphereObj(
+ *mpModel,
+ mp3DView->Get3DDefaultAttributes(),
+ basegfx::B3DPoint( 0, 0, 0 ),
+ basegfx::B3DVector( 5000, 5000, 5000 ));
+ }
+ break;
+
+ case SvxPreviewObjectType::CUBE:
+ {
+ mp3DObj = new E3dCubeObj(
+ *mpModel,
+ mp3DView->Get3DDefaultAttributes(),
+ basegfx::B3DPoint( -2500, -2500, -2500 ),
+ basegfx::B3DVector( 5000, 5000, 5000 ));
+ }
+ break;
+ }
+
+ if (mp3DObj)
+ {
+ mpScene->InsertObject( mp3DObj.get() );
+ mp3DObj->SetMergedItemSet(aSet);
+ }
+
+ Invalidate();
+}
+
+SfxItemSet const & Svx3DPreviewControl::Get3DAttributes() const
+{
+ return mp3DObj->GetMergedItemSet();
+}
+
+void Svx3DPreviewControl::Set3DAttributes( const SfxItemSet& rAttr )
+{
+ mp3DObj->SetMergedItemSet(rAttr, true);
+ Resize();
+ Invalidate();
+}
+
+#define RADIUS_LAMP_PREVIEW_SIZE (4500.0)
+#define RADIUS_LAMP_SMALL (600.0)
+#define RADIUS_LAMP_BIG (1000.0)
+#define NO_LIGHT_SELECTED (0xffffffff)
+#define MAX_NUMBER_LIGHTS (8)
+
+const sal_Int32 g_nInteractionStartDistance = 5 * 5 * 2;
+
+Svx3DLightControl::Svx3DLightControl()
+: maSelectedLight(NO_LIGHT_SELECTED),
+ maLightObjects(MAX_NUMBER_LIGHTS, nullptr),
+ mfRotateX(-20.0),
+ mfRotateY(45.0),
+ mfRotateZ(0.0),
+ mfSaveActionStartHor(0.0),
+ mfSaveActionStartVer(0.0),
+ mfSaveActionStartRotZ(0.0),
+ mbMouseMoved(false),
+ mbMouseCaptured(false),
+ mbGeometrySelected(false)
+{
+}
+
+void Svx3DLightControl::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ Svx3DPreviewControl::SetDrawingArea(pDrawingArea);
+ Construct2();
+}
+
+void Svx3DLightControl::Construct2()
+{
+ {
+ // hide all page stuff, use control background (normally gray)
+ const Color aDialogColor(Application::GetSettings().GetStyleSettings().GetDialogColor());
+ mp3DView->SetPageVisible(false);
+ mp3DView->SetApplicationBackgroundColor(aDialogColor);
+ mp3DView->SetApplicationDocumentColor(aDialogColor);
+ }
+
+ {
+ // create invisible expansion object
+ const double fMaxExpansion(RADIUS_LAMP_BIG + RADIUS_LAMP_PREVIEW_SIZE);
+ mpExpansionObject = new E3dCubeObj(
+ *mpModel,
+ mp3DView->Get3DDefaultAttributes(),
+ basegfx::B3DPoint(-fMaxExpansion, -fMaxExpansion, -fMaxExpansion),
+ basegfx::B3DVector(2.0 * fMaxExpansion, 2.0 * fMaxExpansion, 2.0 * fMaxExpansion));
+ mpScene->InsertObject( mpExpansionObject.get() );
+ SfxItemSet aSet(mpModel->GetItemPool());
+ aSet.Put( XLineStyleItem( drawing::LineStyle_NONE ) );
+ aSet.Put( XFillStyleItem( drawing::FillStyle_NONE ) );
+ mpExpansionObject->SetMergedItemSet(aSet);
+ }
+
+ {
+ // create lamp control object (Yellow lined object)
+ // base circle
+ const basegfx::B2DPolygon a2DCircle(basegfx::utils::createPolygonFromCircle(basegfx::B2DPoint(0.0, 0.0), RADIUS_LAMP_PREVIEW_SIZE));
+ basegfx::B3DPolygon a3DCircle(basegfx::utils::createB3DPolygonFromB2DPolygon(a2DCircle));
+ basegfx::B3DHomMatrix aTransform;
+
+ aTransform.rotate(M_PI_2, 0.0, 0.0);
+ aTransform.translate(0.0, -RADIUS_LAMP_PREVIEW_SIZE, 0.0);
+ a3DCircle.transform(aTransform);
+
+ // create object for it
+ mpLampBottomObject = new E3dPolygonObj(
+ *mpModel,
+ basegfx::B3DPolyPolygon(a3DCircle));
+ mpScene->InsertObject( mpLampBottomObject.get() );
+
+ // half circle with stand
+ basegfx::B2DPolygon a2DHalfCircle;
+ a2DHalfCircle.append(basegfx::B2DPoint(RADIUS_LAMP_PREVIEW_SIZE, 0.0));
+ a2DHalfCircle.append(basegfx::B2DPoint(RADIUS_LAMP_PREVIEW_SIZE, -RADIUS_LAMP_PREVIEW_SIZE));
+ a2DHalfCircle.append(basegfx::utils::createPolygonFromEllipseSegment(
+ basegfx::B2DPoint(0.0, 0.0), RADIUS_LAMP_PREVIEW_SIZE, RADIUS_LAMP_PREVIEW_SIZE, 2 * M_PI - M_PI_2, M_PI_2));
+ basegfx::B3DPolygon a3DHalfCircle(basegfx::utils::createB3DPolygonFromB2DPolygon(a2DHalfCircle));
+
+ // create object for it
+ mpLampShaftObject = new E3dPolygonObj(
+ *mpModel,
+ basegfx::B3DPolyPolygon(a3DHalfCircle));
+ mpScene->InsertObject( mpLampShaftObject.get() );
+
+ // initially invisible
+ SfxItemSet aSet(mpModel->GetItemPool());
+ aSet.Put( XLineStyleItem( drawing::LineStyle_NONE ) );
+ aSet.Put( XFillStyleItem( drawing::FillStyle_NONE ) );
+
+ mpLampBottomObject->SetMergedItemSet(aSet);
+ mpLampShaftObject->SetMergedItemSet(aSet);
+ }
+
+ {
+ // change camera settings
+ Camera3D rCamera = mpScene->GetCamera();
+ const basegfx::B3DRange& rVolume = mpScene->GetBoundVolume();
+ double fW = rVolume.getWidth();
+ double fH = rVolume.getHeight();
+ double fCamZ = rVolume.getMaxZ() + ((fW + fH) / 2.0);
+
+ rCamera.SetAutoAdjustProjection(false);
+ rCamera.SetViewWindow(- fW / 2, - fH / 2, fW, fH);
+ basegfx::B3DPoint aLookAt;
+ double fDefaultCamPosZ = mp3DView->GetDefaultCamPosZ();
+ basegfx::B3DPoint aCamPos(0.0, 0.0, fCamZ < fDefaultCamPosZ ? fDefaultCamPosZ : fCamZ);
+ rCamera.SetPosAndLookAt(aCamPos, aLookAt);
+ double fDefaultCamFocal = mp3DView->GetDefaultCamFocal();
+ rCamera.SetFocalLength(fDefaultCamFocal);
+
+ mpScene->SetCamera( rCamera );
+
+ basegfx::B3DHomMatrix aNeutral;
+ mpScene->SetTransform(aNeutral);
+ }
+
+ // invalidate SnapRects of objects
+ mpScene->SetBoundAndSnapRectsDirty();
+}
+
+void Svx3DLightControl::ConstructLightObjects()
+{
+ for(sal_uInt32 a(0); a < MAX_NUMBER_LIGHTS; a++)
+ {
+ // get rid of possible existing light object
+ if(maLightObjects[a])
+ {
+ mpScene->RemoveObject(maLightObjects[a]->GetOrdNum());
+ maLightObjects[a] = nullptr;
+ }
+
+ if(GetLightOnOff(a))
+ {
+ const bool bIsSelectedLight(a == maSelectedLight);
+ basegfx::B3DVector aDirection(GetLightDirection(a));
+ aDirection.normalize();
+ aDirection *= RADIUS_LAMP_PREVIEW_SIZE;
+
+ const double fLampSize(bIsSelectedLight ? RADIUS_LAMP_BIG : RADIUS_LAMP_SMALL);
+ rtl::Reference<E3dObject> pNewLight = new E3dSphereObj(
+ *mpModel,
+ mp3DView->Get3DDefaultAttributes(),
+ basegfx::B3DPoint( 0, 0, 0 ),
+ basegfx::B3DVector( fLampSize, fLampSize, fLampSize));
+ mpScene->InsertObject(pNewLight.get());
+
+ basegfx::B3DHomMatrix aTransform;
+ aTransform.translate(aDirection.getX(), aDirection.getY(), aDirection.getZ());
+ pNewLight->SetTransform(aTransform);
+
+ SfxItemSet aSet(mpModel->GetItemPool());
+ aSet.Put( XLineStyleItem( drawing::LineStyle_NONE ) );
+ aSet.Put( XFillStyleItem( drawing::FillStyle_SOLID ) );
+ aSet.Put( XFillColorItem(OUString(), GetLightColor(a)));
+ pNewLight->SetMergedItemSet(aSet);
+
+ maLightObjects[a] = pNewLight.get();
+ }
+ }
+}
+
+void Svx3DLightControl::AdaptToSelectedLight()
+{
+ if(NO_LIGHT_SELECTED == maSelectedLight)
+ {
+ // make mpLampBottomObject/mpLampShaftObject invisible
+ SfxItemSet aSet(mpModel->GetItemPool());
+ aSet.Put( XLineStyleItem( drawing::LineStyle_NONE ) );
+ aSet.Put( XFillStyleItem( drawing::FillStyle_NONE ) );
+ mpLampBottomObject->SetMergedItemSet(aSet);
+ mpLampShaftObject->SetMergedItemSet(aSet);
+ }
+ else
+ {
+ basegfx::B3DVector aDirection(GetLightDirection(maSelectedLight));
+ aDirection.normalize();
+
+ // make mpLampBottomObject/mpLampShaftObject visible (yellow hairline)
+ SfxItemSet aSet(mpModel->GetItemPool());
+ aSet.Put( XLineStyleItem( drawing::LineStyle_SOLID ) );
+ aSet.Put( XLineColorItem(OUString(), COL_YELLOW));
+ aSet.Put( XLineWidthItem(0));
+ aSet.Put( XFillStyleItem( drawing::FillStyle_NONE ) );
+ mpLampBottomObject->SetMergedItemSet(aSet);
+ mpLampShaftObject->SetMergedItemSet(aSet);
+
+ // adapt transformation of mpLampShaftObject
+ basegfx::B3DHomMatrix aTransform;
+ double fRotateY(0.0);
+
+ if(!basegfx::fTools::equalZero(aDirection.getZ()) || !basegfx::fTools::equalZero(aDirection.getX()))
+ {
+ fRotateY = atan2(-aDirection.getZ(), aDirection.getX());
+ }
+
+ aTransform.rotate(0.0, fRotateY, 0.0);
+ mpLampShaftObject->SetTransform(aTransform);
+
+ // adapt transformation of selected light
+ E3dObject* pSelectedLight = maLightObjects[sal_Int32(maSelectedLight)];
+
+ if(pSelectedLight)
+ {
+ aTransform.identity();
+ aTransform.translate(
+ aDirection.getX() * RADIUS_LAMP_PREVIEW_SIZE,
+ aDirection.getY() * RADIUS_LAMP_PREVIEW_SIZE,
+ aDirection.getZ() * RADIUS_LAMP_PREVIEW_SIZE);
+ pSelectedLight->SetTransform(aTransform);
+ }
+ }
+}
+
+void Svx3DLightControl::TrySelection(Point aPosPixel)
+{
+ if(!mpScene)
+ return;
+
+ const Point aPosLogic(GetDrawingArea()->get_ref_device().PixelToLogic(aPosPixel));
+ const basegfx::B2DPoint aPoint(aPosLogic.X(), aPosLogic.Y());
+ std::vector< const E3dCompoundObject* > aResult;
+ getAllHit3DObjectsSortedFrontToBack(aPoint, *mpScene, aResult);
+
+ if(aResult.empty())
+ return;
+
+ // exclude expansion object which will be part of
+ // the hits. It's invisible, but for HitTest, it's included
+ const E3dCompoundObject* pResult = nullptr;
+
+ for(auto const & b: aResult)
+ {
+ if(b && b != mpExpansionObject.get())
+ {
+ pResult = b;
+ break;
+ }
+ }
+
+ if(pResult == mp3DObj.get())
+ {
+ if(!mbGeometrySelected)
+ {
+ mbGeometrySelected = true;
+ maSelectedLight = NO_LIGHT_SELECTED;
+ ConstructLightObjects();
+ AdaptToSelectedLight();
+ Invalidate();
+
+ if(maSelectionChangeCallback.IsSet())
+ {
+ maSelectionChangeCallback.Call(this);
+ }
+ }
+ }
+ else
+ {
+ sal_uInt32 aNewSelectedLight(NO_LIGHT_SELECTED);
+
+ for(sal_uInt32 a(0); a < MAX_NUMBER_LIGHTS; a++)
+ {
+ if(maLightObjects[a] && maLightObjects[a] == pResult)
+ {
+ aNewSelectedLight = a;
+ }
+ }
+
+ if(aNewSelectedLight != maSelectedLight)
+ {
+ SelectLight(aNewSelectedLight);
+
+ if(maSelectionChangeCallback.IsSet())
+ {
+ maSelectionChangeCallback.Call(this);
+ }
+ }
+ }
+}
+
+void Svx3DLightControl::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
+{
+ Svx3DPreviewControl::Paint(rRenderContext, rRect);
+}
+
+tools::Rectangle Svx3DLightControl::GetFocusRect()
+{
+ if (!HasFocus())
+ return tools::Rectangle();
+ Size aFocusSize = GetOutputSizePixel();
+ aFocusSize.AdjustWidth( -4 );
+ aFocusSize.AdjustHeight( -4 );
+ return tools::Rectangle(Point(2, 2), aFocusSize);
+}
+
+bool Svx3DLightControl::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ bool bCallParent(true);
+
+ // switch state
+ if(rMEvt.IsLeft())
+ {
+ if(IsSelectionValid() || mbGeometrySelected)
+ {
+ mbMouseMoved = false;
+ bCallParent = false;
+ maActionStartPoint = rMEvt.GetPosPixel();
+ CaptureMouse();
+ mbMouseCaptured = true;
+ }
+ else
+ {
+ // Single click without moving much trying to do a selection
+ TrySelection(rMEvt.GetPosPixel());
+ bCallParent = false;
+ }
+ }
+
+ // call parent
+ if (bCallParent)
+ return Svx3DPreviewControl::MouseButtonDown(rMEvt);
+ return true;
+}
+
+bool Svx3DLightControl::MouseMove(const MouseEvent& rMEvt)
+{
+ if (!mbMouseCaptured)
+ return false;
+
+ Point aDeltaPos = rMEvt.GetPosPixel() - maActionStartPoint;
+
+ if(!mbMouseMoved)
+ {
+ if(sal_Int32(aDeltaPos.X() * aDeltaPos.X() + aDeltaPos.Y() * aDeltaPos.Y()) > g_nInteractionStartDistance)
+ {
+ if(mbGeometrySelected)
+ {
+ GetRotation(mfSaveActionStartVer, mfSaveActionStartHor, mfSaveActionStartRotZ);
+ }
+ else
+ {
+ // interaction start, save values
+ GetPosition(mfSaveActionStartHor, mfSaveActionStartVer);
+ }
+
+ mbMouseMoved = true;
+ }
+ }
+
+ if(mbMouseMoved)
+ {
+ if(mbGeometrySelected)
+ {
+ double fNewRotX = mfSaveActionStartVer - basegfx::deg2rad(aDeltaPos.Y());
+ double fNewRotY = mfSaveActionStartHor + basegfx::deg2rad(aDeltaPos.X());
+
+ // cut horizontal
+ while(fNewRotY < 0.0)
+ {
+ fNewRotY += 2 * M_PI;
+ }
+
+ while(fNewRotY >= 2 * M_PI)
+ {
+ fNewRotY -= 2 * M_PI;
+ }
+
+ // cut vertical
+ if(fNewRotX < -M_PI_2)
+ {
+ fNewRotX = -M_PI_2;
+ }
+
+ if(fNewRotX > M_PI_2)
+ {
+ fNewRotX = M_PI_2;
+ }
+
+ SetRotation(fNewRotX, fNewRotY, mfSaveActionStartRotZ);
+
+ if(maChangeCallback.IsSet())
+ {
+ maChangeCallback.Call(this);
+ }
+ }
+ else
+ {
+ // interaction in progress
+ double fNewPosHor = mfSaveActionStartHor + static_cast<double>(aDeltaPos.X());
+ double fNewPosVer = mfSaveActionStartVer - static_cast<double>(aDeltaPos.Y());
+
+ // cut horizontal
+ fNewPosHor = NormAngle360(fNewPosHor);
+
+ // cut vertical
+ if(fNewPosVer < -90.0)
+ {
+ fNewPosVer = -90.0;
+ }
+
+ if(fNewPosVer > 90.0)
+ {
+ fNewPosVer = 90.0;
+ }
+
+ SetPosition(fNewPosHor, fNewPosVer);
+
+ if(maChangeCallback.IsSet())
+ {
+ maChangeCallback.Call(this);
+ }
+ }
+ }
+ return true;
+}
+
+bool Svx3DLightControl::MouseButtonUp(const MouseEvent& rMEvt)
+{
+ if (!mbMouseCaptured)
+ return false;
+ ReleaseMouse();
+ mbMouseCaptured = false;
+
+ if (mbMouseMoved)
+ {
+ // was change interactively
+ }
+ else
+ {
+ // simple click without much movement, try selection
+ TrySelection(rMEvt.GetPosPixel());
+ }
+
+ return true;
+}
+
+void Svx3DLightControl::Resize()
+{
+ // set size of page
+ const Size aSize(GetDrawingArea()->get_ref_device().PixelToLogic(GetOutputSizePixel()));
+ mxFmPage->SetSize(aSize);
+
+ // set position and size of scene
+ mpScene->SetSnapRect(tools::Rectangle(Point(0, 0), aSize));
+}
+
+void Svx3DLightControl::SetObjectType(SvxPreviewObjectType nType)
+{
+ // call parent
+ Svx3DPreviewControl::SetObjectType(nType);
+
+ // apply object rotation
+ if(mp3DObj)
+ {
+ basegfx::B3DHomMatrix aObjectRotation;
+ aObjectRotation.rotate(mfRotateX, mfRotateY, mfRotateZ);
+ mp3DObj->SetTransform(aObjectRotation);
+ }
+}
+
+bool Svx3DLightControl::IsSelectionValid()
+{
+ return (NO_LIGHT_SELECTED != maSelectedLight) && GetLightOnOff(maSelectedLight);
+}
+
+void Svx3DLightControl::GetPosition(double& rHor, double& rVer)
+{
+ if(IsSelectionValid())
+ {
+ basegfx::B3DVector aDirection(GetLightDirection(maSelectedLight));
+ aDirection.normalize();
+ rHor = basegfx::rad2deg(atan2(-aDirection.getX(), -aDirection.getZ()) + M_PI); // 0..360.0
+ rVer = basegfx::rad2deg(atan2(aDirection.getY(), aDirection.getXZLength())); // -90.0..90.0
+ }
+ if(IsGeometrySelected())
+ {
+ rHor = basegfx::rad2deg(mfRotateY); // 0..360.0
+ rVer = basegfx::rad2deg(mfRotateX); // -90.0..90.0
+ }
+}
+
+void Svx3DLightControl::SetPosition(double fHor, double fVer)
+{
+ if(IsSelectionValid())
+ {
+ // set selected light's direction
+ fHor = basegfx::deg2rad(fHor) - M_PI; // -PI..PI
+ fVer = basegfx::deg2rad(fVer); // -PI2..PI2
+ basegfx::B3DVector aDirection(cos(fVer) * -sin(fHor), sin(fVer), cos(fVer) * -cos(fHor));
+ aDirection.normalize();
+
+ if(!aDirection.equal(GetLightDirection(maSelectedLight)))
+ {
+ // set changed light direction at SdrScene
+ SfxItemSet aSet(mpModel->GetItemPool());
+
+ switch(maSelectedLight)
+ {
+ case 0: aSet.Put(makeSvx3DLightDirection1Item(aDirection)); break;
+ case 1: aSet.Put(makeSvx3DLightDirection2Item(aDirection)); break;
+ case 2: aSet.Put(makeSvx3DLightDirection3Item(aDirection)); break;
+ case 3: aSet.Put(makeSvx3DLightDirection4Item(aDirection)); break;
+ case 4: aSet.Put(makeSvx3DLightDirection5Item(aDirection)); break;
+ case 5: aSet.Put(makeSvx3DLightDirection6Item(aDirection)); break;
+ case 6: aSet.Put(makeSvx3DLightDirection7Item(aDirection)); break;
+ default:
+ case 7: aSet.Put(makeSvx3DLightDirection8Item(aDirection)); break;
+ }
+
+ mpScene->SetMergedItemSet(aSet);
+
+ // correct 3D light's and LampFrame's geometries
+ AdaptToSelectedLight();
+ Invalidate();
+ }
+ }
+ if(!IsGeometrySelected())
+ return;
+
+ if(mfRotateX == fVer && mfRotateY == fHor)
+ return;
+
+ mfRotateX = basegfx::deg2rad(fVer);
+ mfRotateY = basegfx::deg2rad(fHor);
+
+ if(mp3DObj)
+ {
+ basegfx::B3DHomMatrix aObjectRotation;
+ aObjectRotation.rotate(mfRotateX, mfRotateY, mfRotateZ);
+ mp3DObj->SetTransform(aObjectRotation);
+
+ Invalidate();
+ }
+}
+
+void Svx3DLightControl::SetRotation(double fRotX, double fRotY, double fRotZ)
+{
+ if(!IsGeometrySelected())
+ return;
+
+ if(fRotX == mfRotateX && fRotY == mfRotateY && fRotZ == mfRotateZ)
+ return;
+
+ mfRotateX = fRotX;
+ mfRotateY = fRotY;
+ mfRotateZ = fRotZ;
+
+ if(mp3DObj)
+ {
+ basegfx::B3DHomMatrix aObjectRotation;
+ aObjectRotation.rotate(mfRotateX, mfRotateY, mfRotateZ);
+ mp3DObj->SetTransform(aObjectRotation);
+
+ Invalidate();
+ }
+}
+
+void Svx3DLightControl::GetRotation(double& rRotX, double& rRotY, double& rRotZ)
+{
+ rRotX = mfRotateX;
+ rRotY = mfRotateY;
+ rRotZ = mfRotateZ;
+}
+
+void Svx3DLightControl::Set3DAttributes( const SfxItemSet& rAttr )
+{
+ // call parent
+ Svx3DPreviewControl::Set3DAttributes(rAttr);
+
+ if(maSelectedLight != NO_LIGHT_SELECTED && !GetLightOnOff(maSelectedLight))
+ {
+ // selected light is no more active, select new one
+ maSelectedLight = NO_LIGHT_SELECTED;
+ }
+
+ // local updates
+ ConstructLightObjects();
+ AdaptToSelectedLight();
+ Invalidate();
+}
+
+void Svx3DLightControl::SelectLight(sal_uInt32 nLightNumber)
+{
+ if(nLightNumber > 7)
+ {
+ nLightNumber = NO_LIGHT_SELECTED;
+ }
+
+ if(NO_LIGHT_SELECTED != nLightNumber)
+ {
+ if(!GetLightOnOff(nLightNumber))
+ {
+ nLightNumber = NO_LIGHT_SELECTED;
+ }
+ }
+
+ if(nLightNumber != maSelectedLight)
+ {
+ maSelectedLight = nLightNumber;
+ mbGeometrySelected = false;
+ ConstructLightObjects();
+ AdaptToSelectedLight();
+ Invalidate();
+ }
+}
+
+bool Svx3DLightControl::GetLightOnOff(sal_uInt32 nNum) const
+{
+ if(nNum <= 7)
+ {
+ const SfxItemSet aLightItemSet(Get3DAttributes());
+
+ switch(nNum)
+ {
+ case 0 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTON_1).GetValue();
+ case 1 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTON_2).GetValue();
+ case 2 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTON_3).GetValue();
+ case 3 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTON_4).GetValue();
+ case 4 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTON_5).GetValue();
+ case 5 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTON_6).GetValue();
+ case 6 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTON_7).GetValue();
+ case 7 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTON_8).GetValue();
+ }
+ }
+
+ return false;
+}
+
+Color Svx3DLightControl::GetLightColor(sal_uInt32 nNum) const
+{
+ if(nNum <= 7)
+ {
+ const SfxItemSet aLightItemSet(Get3DAttributes());
+
+ switch(nNum)
+ {
+ case 0 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_1).GetValue();
+ case 1 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_2).GetValue();
+ case 2 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_3).GetValue();
+ case 3 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_4).GetValue();
+ case 4 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_5).GetValue();
+ case 5 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_6).GetValue();
+ case 6 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_7).GetValue();
+ case 7 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_8).GetValue();
+ }
+ }
+
+ return COL_BLACK;
+}
+
+basegfx::B3DVector Svx3DLightControl::GetLightDirection(sal_uInt32 nNum) const
+{
+ if(nNum <= 7)
+ {
+ const SfxItemSet aLightItemSet(Get3DAttributes());
+
+ switch(nNum)
+ {
+ case 0 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_1).GetValue();
+ case 1 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_2).GetValue();
+ case 2 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_3).GetValue();
+ case 3 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_4).GetValue();
+ case 4 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_5).GetValue();
+ case 5 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_6).GetValue();
+ case 6 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_7).GetValue();
+ case 7 : return aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_8).GetValue();
+ }
+ }
+
+ return basegfx::B3DVector();
+}
+
+SvxLightCtl3D::SvxLightCtl3D(Svx3DLightControl& rLightControl, weld::Scale& rHori,
+ weld::Scale& rVert, weld::Button& rSwitcher)
+ : mrLightControl(rLightControl)
+ , mrHorScroller(rHori)
+ , mrVerScroller(rVert)
+ , mrSwitcher(rSwitcher)
+{
+ // init members
+ Init();
+}
+
+void SvxLightCtl3D::Init()
+{
+ Size aSize(mrLightControl.GetDrawingArea()->get_ref_device().LogicToPixel(Size(80, 100), MapMode(MapUnit::MapAppFont)));
+ mrLightControl.set_size_request(aSize.Width(), aSize.Height());
+
+ // #i58240# set HelpIDs for scrollbars and switcher
+ mrHorScroller.set_help_id(HID_CTRL3D_HSCROLL);
+ mrVerScroller.set_help_id(HID_CTRL3D_VSCROLL);
+ mrSwitcher.set_help_id(HID_CTRL3D_SWITCHER);
+ mrSwitcher.set_accessible_name(SvxResId(STR_SWITCH));
+
+ // Light preview
+ mrLightControl.Show();
+ mrLightControl.SetChangeCallback( LINK(this, SvxLightCtl3D, InternalInteractiveChange) );
+ mrLightControl.SetSelectionChangeCallback( LINK(this, SvxLightCtl3D, InternalSelectionChange) );
+
+ // Horiz Scrollbar
+ mrHorScroller.show();
+ mrHorScroller.set_range(0, 36000);
+ mrHorScroller.connect_value_changed( LINK(this, SvxLightCtl3D, ScrollBarMove) );
+
+ // Vert Scrollbar
+ mrVerScroller.show();
+ mrVerScroller.set_range(0, 18000);
+ mrVerScroller.connect_value_changed( LINK(this, SvxLightCtl3D, ScrollBarMove) );
+
+ // Switch Button
+ mrSwitcher.show();
+ mrSwitcher.connect_clicked( LINK(this, SvxLightCtl3D, ButtonPress) );
+
+ weld::DrawingArea* pArea = mrLightControl.GetDrawingArea();
+ pArea->connect_key_press(Link<const KeyEvent&, bool>()); //acknowledge we first remove the old one
+ pArea->connect_key_press(LINK(this, SvxLightCtl3D, KeyInput));
+
+ pArea->connect_focus_in(Link<weld::Widget&, void>()); //acknowledge we first remove the old one
+ pArea->connect_focus_in(LINK(this, SvxLightCtl3D, FocusIn));
+
+ // check selection
+ CheckSelection();
+}
+
+void SvxLightCtl3D::CheckSelection()
+{
+ const bool bSelectionValid(mrLightControl.IsSelectionValid() || mrLightControl.IsGeometrySelected());
+ mrHorScroller.set_sensitive(bSelectionValid);
+ mrVerScroller.set_sensitive(bSelectionValid);
+
+ if (bSelectionValid)
+ {
+ double fHor(0.0), fVer(0.0);
+ mrLightControl.GetPosition(fHor, fVer);
+ mrHorScroller.set_value( sal_Int32(fHor * 100.0) );
+ mrVerScroller.set_value( 18000 - sal_Int32((fVer + 90.0) * 100.0) );
+ }
+}
+
+void SvxLightCtl3D::move( double fDeltaHor, double fDeltaVer )
+{
+ double fHor(0.0), fVer(0.0);
+
+ mrLightControl.GetPosition(fHor, fVer);
+ fHor += fDeltaHor;
+ fVer += fDeltaVer;
+
+ if( fVer > 90.0 )
+ return;
+
+ if ( fVer < -90.0 )
+ return;
+
+ mrLightControl.SetPosition(fHor, fVer);
+ mrHorScroller.set_value( sal_Int32(fHor * 100.0) );
+ mrVerScroller.set_value( 18000 - sal_Int32((fVer + 90.0) * 100.0) );
+
+ if(maUserInteractiveChangeCallback.IsSet())
+ {
+ maUserInteractiveChangeCallback.Call(this);
+ }
+}
+
+IMPL_LINK(SvxLightCtl3D, KeyInput, const KeyEvent&, rKEvt, bool)
+{
+ const vcl::KeyCode aCode(rKEvt.GetKeyCode());
+
+ if (aCode.GetModifier())
+ return false;
+
+ bool bHandled = true;
+
+ switch ( aCode.GetCode() )
+ {
+ case KEY_SPACE:
+ {
+ break;
+ }
+ case KEY_LEFT:
+ {
+ move( -4.0, 0.0 ); // #i58242# changed move direction in X
+ break;
+ }
+ case KEY_RIGHT:
+ {
+ move( 4.0, 0.0 ); // #i58242# changed move direction in X
+ break;
+ }
+ case KEY_UP:
+ {
+ move( 0.0, 4.0 );
+ break;
+ }
+ case KEY_DOWN:
+ {
+ move( 0.0, -4.0 );
+ break;
+ }
+ case KEY_PAGEUP:
+ {
+ sal_Int32 nLight(mrLightControl.GetSelectedLight() - 1);
+
+ while((nLight >= 0) && !mrLightControl.GetLightOnOff(nLight))
+ {
+ nLight--;
+ }
+
+ if(nLight < 0)
+ {
+ nLight = 7;
+
+ while((nLight >= 0) && !mrLightControl.GetLightOnOff(nLight))
+ {
+ nLight--;
+ }
+ }
+
+ if(nLight >= 0)
+ {
+ mrLightControl.SelectLight(nLight);
+ CheckSelection();
+
+ if(maUserSelectionChangeCallback.IsSet())
+ {
+ maUserSelectionChangeCallback.Call(this);
+ }
+ }
+
+ break;
+ }
+ case KEY_PAGEDOWN:
+ {
+ sal_Int32 nLight(mrLightControl.GetSelectedLight() - 1);
+
+ while(nLight <= 7 && !mrLightControl.GetLightOnOff(nLight))
+ {
+ nLight++;
+ }
+
+ if(nLight > 7)
+ {
+ nLight = 0;
+
+ while(nLight <= 7 && !mrLightControl.GetLightOnOff(nLight))
+ {
+ nLight++;
+ }
+ }
+
+ if(nLight <= 7)
+ {
+ mrLightControl.SelectLight(nLight);
+ CheckSelection();
+
+ if(maUserSelectionChangeCallback.IsSet())
+ {
+ maUserSelectionChangeCallback.Call(this);
+ }
+ }
+
+ break;
+ }
+ default:
+ {
+ bHandled = false;
+ break;
+ }
+ }
+ return bHandled;
+}
+
+IMPL_LINK_NOARG(SvxLightCtl3D, FocusIn, weld::Widget&, void)
+{
+ if (mrLightControl.IsEnabled())
+ {
+ CheckSelection();
+ }
+}
+
+IMPL_LINK_NOARG(SvxLightCtl3D, ScrollBarMove, weld::Scale&, void)
+{
+ const sal_Int32 nHor(mrHorScroller.get_value());
+ const sal_Int32 nVer(mrVerScroller.get_value());
+
+ mrLightControl.SetPosition(
+ static_cast<double>(nHor) / 100.0,
+ static_cast<double>((18000 - nVer) - 9000) / 100.0);
+
+ if (maUserInteractiveChangeCallback.IsSet())
+ {
+ maUserInteractiveChangeCallback.Call(this);
+ }
+}
+
+IMPL_LINK_NOARG(SvxLightCtl3D, ButtonPress, weld::Button&, void)
+{
+ if(SvxPreviewObjectType::SPHERE == GetSvx3DLightControl().GetObjectType())
+ {
+ GetSvx3DLightControl().SetObjectType(SvxPreviewObjectType::CUBE);
+ }
+ else
+ {
+ GetSvx3DLightControl().SetObjectType(SvxPreviewObjectType::SPHERE);
+ }
+}
+
+IMPL_LINK_NOARG(SvxLightCtl3D, InternalInteractiveChange, Svx3DLightControl*, void)
+{
+ double fHor(0.0), fVer(0.0);
+
+ mrLightControl.GetPosition(fHor, fVer);
+ mrHorScroller.set_value( sal_Int32(fHor * 100.0) );
+ mrVerScroller.set_value( 18000 - sal_Int32((fVer + 90.0) * 100.0) );
+
+ if(maUserInteractiveChangeCallback.IsSet())
+ {
+ maUserInteractiveChangeCallback.Call(this);
+ }
+}
+
+IMPL_LINK_NOARG(SvxLightCtl3D, InternalSelectionChange, Svx3DLightControl*, void)
+{
+ CheckSelection();
+
+ if(maUserSelectionChangeCallback.IsSet())
+ {
+ maUserSelectionChangeCallback.Call(this);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/dlgctrl.cxx b/svx/source/dialog/dlgctrl.cxx
new file mode 100644
index 0000000000..df3d7b1c8b
--- /dev/null
+++ b/svx/source/dialog/dlgctrl.cxx
@@ -0,0 +1,1464 @@
+/* -*- 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_wasm_strip.h>
+
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/event.hxx>
+#include <sfx2/dialoghelper.hxx>
+#include <sfx2/weldutils.hxx>
+#include <svx/relfld.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xtable.hxx>
+#include <bitmaps.hlst>
+#include <svx/dlgctrl.hxx>
+#include <tools/debug.hxx>
+#include <svxpixelctlaccessiblecontext.hxx>
+#include <svtools/colorcfg.hxx>
+#include <svxrectctaccessiblecontext.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <svx/svdorect.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdopath.hxx>
+#include <sdr/contact/objectcontactofobjlistpainter.hxx>
+#include <svx/sdr/contact/displayinfo.hxx>
+#include <vcl/BitmapTools.hxx>
+
+#define OUTPUT_DRAWMODE_COLOR (DrawModeFlags::Default)
+#define OUTPUT_DRAWMODE_CONTRAST (DrawModeFlags::SettingsLine | DrawModeFlags::SettingsFill | DrawModeFlags::SettingsText | DrawModeFlags::SettingsGradient)
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::accessibility;
+
+// Control for display and selection of the corner points and
+// mid point of an object
+
+BitmapEx& SvxRectCtl::GetRectBitmap()
+{
+ if( !pBitmap )
+ InitRectBitmap();
+
+ return *pBitmap;
+}
+
+SvxRectCtl::SvxRectCtl(SvxTabPage* pPage)
+ : m_pPage(pPage)
+ , nBorderWidth(Application::GetDefaultDevice()->LogicToPixel(Size(200, 0), MapMode(MapUnit::Map100thMM)).Width())
+ , eRP(RectPoint::MM)
+ , eDefRP(RectPoint::MM)
+ , m_nState(CTL_STATE::NONE)
+ , mbCompleteDisable(false)
+{
+}
+
+void SvxRectCtl::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ CustomWidgetController::SetDrawingArea(pDrawingArea);
+ Size aSize(pDrawingArea->get_approximate_digit_width() * 25,
+ pDrawingArea->get_text_height() * 5);
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+ Resize_Impl(aSize);
+}
+
+void SvxRectCtl::SetControlSettings(RectPoint eRpt, sal_uInt16 nBorder)
+{
+ nBorderWidth = Application::GetDefaultDevice()->LogicToPixel(Size(nBorder, 0), MapMode(MapUnit::Map100thMM)).Width();
+ eDefRP = eRpt;
+ Resize();
+}
+
+SvxRectCtl::~SvxRectCtl()
+{
+ pBitmap.reset();
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ pAccContext.clear();
+#endif
+}
+
+void SvxRectCtl::Resize()
+{
+ Resize_Impl(GetOutputSizePixel());
+}
+
+void SvxRectCtl::Resize_Impl(const Size &rSize)
+{
+ aPtLT = Point( 0 + nBorderWidth, 0 + nBorderWidth );
+ aPtMT = Point( rSize.Width() / 2, 0 + nBorderWidth );
+ aPtRT = Point( rSize.Width() - nBorderWidth, 0 + nBorderWidth );
+
+ aPtLM = Point( 0 + nBorderWidth, rSize.Height() / 2 );
+ aPtMM = Point( rSize.Width() / 2, rSize.Height() / 2 );
+ aPtRM = Point( rSize.Width() - nBorderWidth, rSize.Height() / 2 );
+
+ aPtLB = Point( 0 + nBorderWidth, rSize.Height() - nBorderWidth );
+ aPtMB = Point( rSize.Width() / 2, rSize.Height() - nBorderWidth );
+ aPtRB = Point( rSize.Width() - nBorderWidth, rSize.Height() - nBorderWidth );
+
+ Reset();
+ StyleUpdated();
+}
+
+void SvxRectCtl::InitRectBitmap()
+{
+ pBitmap.reset();
+
+ const StyleSettings& rStyles = Application::GetSettings().GetStyleSettings();
+ svtools::ColorConfig aColorConfig;
+
+ pBitmap.reset(new BitmapEx(RID_SVXCTRL_RECTBTNS));
+
+ // set bitmap-colors
+ Color aColorAry1[7];
+ Color aColorAry2[7];
+ aColorAry1[0] = Color( 0xC0, 0xC0, 0xC0 ); // light-gray
+ aColorAry1[1] = Color( 0xFF, 0xFF, 0x00 ); // yellow
+ aColorAry1[2] = Color( 0xFF, 0xFF, 0xFF ); // white
+ aColorAry1[3] = Color( 0x80, 0x80, 0x80 ); // dark-gray
+ aColorAry1[4] = Color( 0x00, 0x00, 0x00 ); // black
+ aColorAry1[5] = Color( 0x00, 0xFF, 0x00 ); // green
+ aColorAry1[6] = Color( 0x00, 0x00, 0xFF ); // blue
+ aColorAry2[0] = rStyles.GetDialogColor(); // background
+ aColorAry2[1] = rStyles.GetWindowColor();
+ aColorAry2[2] = rStyles.GetLightColor();
+ aColorAry2[3] = rStyles.GetShadowColor();
+ aColorAry2[4] = rStyles.GetDarkShadowColor();
+ aColorAry2[5] = aColorConfig.GetColorValue( svtools::FONTCOLOR ).nColor;
+ aColorAry2[6] = rStyles.GetDialogColor();
+
+#ifdef DBG_UTIL
+ static bool bModify = false;
+ bool& rModify = bModify;
+ if( rModify )
+ {
+ static int n = 0;
+ static sal_uInt8 r = 0xFF;
+ static sal_uInt8 g = 0x00;
+ static sal_uInt8 b = 0xFF;
+ int& rn = n;
+ sal_uInt8& rr = r;
+ sal_uInt8& rg = g;
+ sal_uInt8& rb = b;
+ aColorAry2[ rn ] = Color( rr, rg, rb );
+ }
+#endif
+
+ pBitmap->Replace( aColorAry1, aColorAry2, 7 );
+}
+
+void SvxRectCtl::StyleUpdated()
+{
+ pBitmap.reset(); // forces new creating of bitmap
+ CustomWidgetController::StyleUpdated();
+}
+
+void SvxRectCtl::InitSettings(vcl::RenderContext& rRenderContext)
+{
+ svtools::ColorConfig aColorConfig;
+ Color aTextColor(aColorConfig.GetColorValue(svtools::FONTCOLOR).nColor);
+ rRenderContext.SetTextColor(aTextColor);
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ rRenderContext.SetBackground(rStyleSettings.GetWindowColor());
+}
+
+// The clicked rectangle (3 x 3) is determined and the parent (dialog)
+// is notified that the item was changed
+bool SvxRectCtl::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ // CompletelyDisabled() added to have a disabled state for SvxRectCtl
+ if(!IsCompletelyDisabled())
+ {
+ aPtNew = GetApproxLogPtFromPixPt( rMEvt.GetPosPixel() );
+ eRP = GetRPFromPoint( aPtNew );
+ SetActualRP( eRP );
+
+ if (m_pPage)
+ m_pPage->PointChanged(GetDrawingArea(), eRP);
+ }
+ return true;
+}
+
+bool SvxRectCtl::KeyInput(const KeyEvent& rKeyEvt)
+{
+ // CompletelyDisabled() added to have a disabled state for SvxRectCtl
+ if (IsCompletelyDisabled())
+ return false;
+
+ RectPoint eNewRP = eRP;
+
+ switch( rKeyEvt.GetKeyCode().GetCode() )
+ {
+ case KEY_DOWN:
+ {
+ if( !(m_nState & CTL_STATE::NOVERT) )
+ switch( eNewRP )
+ {
+ case RectPoint::LT: eNewRP = RectPoint::LM; break;
+ case RectPoint::MT: eNewRP = RectPoint::MM; break;
+ case RectPoint::RT: eNewRP = RectPoint::RM; break;
+ case RectPoint::LM: eNewRP = RectPoint::LB; break;
+ case RectPoint::MM: eNewRP = RectPoint::MB; break;
+ case RectPoint::RM: eNewRP = RectPoint::RB; break;
+ default: ; //prevent warning
+ }
+ }
+ break;
+ case KEY_UP:
+ {
+ if( !(m_nState & CTL_STATE::NOVERT) )
+ switch( eNewRP )
+ {
+ case RectPoint::LM: eNewRP = RectPoint::LT; break;
+ case RectPoint::MM: eNewRP = RectPoint::MT; break;
+ case RectPoint::RM: eNewRP = RectPoint::RT; break;
+ case RectPoint::LB: eNewRP = RectPoint::LM; break;
+ case RectPoint::MB: eNewRP = RectPoint::MM; break;
+ case RectPoint::RB: eNewRP = RectPoint::RM; break;
+ default: ; //prevent warning
+ }
+ }
+ break;
+ case KEY_LEFT:
+ {
+ if( !(m_nState & CTL_STATE::NOHORZ) )
+ switch( eNewRP )
+ {
+ case RectPoint::MT: eNewRP = RectPoint::LT; break;
+ case RectPoint::RT: eNewRP = RectPoint::MT; break;
+ case RectPoint::MM: eNewRP = RectPoint::LM; break;
+ case RectPoint::RM: eNewRP = RectPoint::MM; break;
+ case RectPoint::MB: eNewRP = RectPoint::LB; break;
+ case RectPoint::RB: eNewRP = RectPoint::MB; break;
+ default: ; //prevent warning
+ }
+ }
+ break;
+ case KEY_RIGHT:
+ {
+ if( !(m_nState & CTL_STATE::NOHORZ) )
+ switch( eNewRP )
+ {
+ case RectPoint::LT: eNewRP = RectPoint::MT; break;
+ case RectPoint::MT: eNewRP = RectPoint::RT; break;
+ case RectPoint::LM: eNewRP = RectPoint::MM; break;
+ case RectPoint::MM: eNewRP = RectPoint::RM; break;
+ case RectPoint::LB: eNewRP = RectPoint::MB; break;
+ case RectPoint::MB: eNewRP = RectPoint::RB; break;
+ default: ; //prevent warning
+ }
+ }
+ break;
+ default:
+ return false;
+ }
+ if( eNewRP != eRP )
+ {
+ SetActualRP( eNewRP );
+
+ if (m_pPage)
+ m_pPage->PointChanged(GetDrawingArea(), eRP);
+ }
+ return true;
+}
+
+// the control (rectangle with 9 circles)
+void SvxRectCtl::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ InitSettings(rRenderContext);
+
+ Point aPtDiff(1, 1);
+
+ const StyleSettings& rStyles = Application::GetSettings().GetStyleSettings();
+
+ rRenderContext.SetLineColor(rStyles.GetDialogColor());
+ rRenderContext.SetFillColor(rStyles.GetDialogColor());
+ rRenderContext.DrawRect(tools::Rectangle(Point(0,0), rRenderContext.GetOutputSize()));
+
+ if (IsEnabled())
+ rRenderContext.SetLineColor(rStyles.GetLabelTextColor());
+ else
+ rRenderContext.SetLineColor(rStyles.GetShadowColor());
+
+ rRenderContext.SetFillColor();
+
+ if (!IsEnabled())
+ {
+ Color aOldCol = rRenderContext.GetLineColor();
+ rRenderContext.SetLineColor(rStyles.GetLightColor());
+ rRenderContext.DrawRect(tools::Rectangle(aPtLT + aPtDiff, aPtRB + aPtDiff));
+ rRenderContext.SetLineColor(aOldCol);
+ }
+ rRenderContext.DrawRect(tools::Rectangle(aPtLT, aPtRB));
+
+ rRenderContext.SetFillColor(rRenderContext.GetBackground().GetColor());
+
+ Size aBtnSize(11, 11);
+ Size aDstBtnSize(aBtnSize);
+ Point aToCenter(aDstBtnSize.Width() >> 1, aDstBtnSize.Height() >> 1);
+ Point aBtnPnt1(IsEnabled() ? 0 : 22, 0);
+ Point aBtnPnt2(11, 0);
+ Point aBtnPnt3(22, 0);
+
+ bool bNoHorz = bool(m_nState & CTL_STATE::NOHORZ);
+ bool bNoVert = bool(m_nState & CTL_STATE::NOVERT);
+
+ BitmapEx& rBitmap = GetRectBitmap();
+
+ // CompletelyDisabled() added to have a disabled state for SvxRectCtl
+ if (IsCompletelyDisabled())
+ {
+ rRenderContext.DrawBitmapEx(aPtLT - aToCenter, aDstBtnSize, aBtnPnt3, aBtnSize, rBitmap);
+ rRenderContext.DrawBitmapEx(aPtMT - aToCenter, aDstBtnSize, aBtnPnt3, aBtnSize, rBitmap);
+ rRenderContext.DrawBitmapEx(aPtRT - aToCenter, aDstBtnSize, aBtnPnt3, aBtnSize, rBitmap);
+ rRenderContext.DrawBitmapEx(aPtLM - aToCenter, aDstBtnSize, aBtnPnt3, aBtnSize, rBitmap);
+ rRenderContext.DrawBitmapEx(aPtMM - aToCenter, aDstBtnSize, aBtnPnt3, aBtnSize, rBitmap);
+ rRenderContext.DrawBitmapEx(aPtRM - aToCenter, aDstBtnSize, aBtnPnt3, aBtnSize, rBitmap);
+ rRenderContext.DrawBitmapEx(aPtLB - aToCenter, aDstBtnSize, aBtnPnt3, aBtnSize, rBitmap);
+ rRenderContext.DrawBitmapEx(aPtMB - aToCenter, aDstBtnSize, aBtnPnt3, aBtnSize, rBitmap);
+ rRenderContext.DrawBitmapEx(aPtRB - aToCenter, aDstBtnSize, aBtnPnt3, aBtnSize, rBitmap);
+ }
+ else
+ {
+ rRenderContext.DrawBitmapEx(aPtLT - aToCenter, aDstBtnSize, (bNoHorz || bNoVert)?aBtnPnt3:aBtnPnt1, aBtnSize, rBitmap);
+ rRenderContext.DrawBitmapEx(aPtMT - aToCenter, aDstBtnSize, bNoVert?aBtnPnt3:aBtnPnt1, aBtnSize, rBitmap);
+ rRenderContext.DrawBitmapEx(aPtRT - aToCenter, aDstBtnSize, (bNoHorz || bNoVert)?aBtnPnt3:aBtnPnt1, aBtnSize, rBitmap);
+ rRenderContext.DrawBitmapEx(aPtLM - aToCenter, aDstBtnSize, bNoHorz?aBtnPnt3:aBtnPnt1, aBtnSize, rBitmap);
+
+ // Center for rectangle and line
+ rRenderContext.DrawBitmapEx(aPtMM - aToCenter, aDstBtnSize, aBtnPnt1, aBtnSize, rBitmap);
+
+ rRenderContext.DrawBitmapEx(aPtRM - aToCenter, aDstBtnSize, bNoHorz?aBtnPnt3:aBtnPnt1, aBtnSize, rBitmap);
+ rRenderContext.DrawBitmapEx(aPtLB - aToCenter, aDstBtnSize, (bNoHorz || bNoVert)?aBtnPnt3:aBtnPnt1, aBtnSize, rBitmap);
+ rRenderContext.DrawBitmapEx(aPtMB - aToCenter, aDstBtnSize, bNoVert?aBtnPnt3:aBtnPnt1, aBtnSize, rBitmap);
+ rRenderContext.DrawBitmapEx(aPtRB - aToCenter, aDstBtnSize, (bNoHorz || bNoVert)?aBtnPnt3:aBtnPnt1, aBtnSize, rBitmap);
+ }
+
+ // draw active button, avoid center pos for angle
+ // CompletelyDisabled() added to have a disabled state for SvxRectCtl
+ if (!IsCompletelyDisabled())
+ {
+ if (IsEnabled())
+ {
+ Point aCenterPt(aPtNew);
+ aCenterPt -= aToCenter;
+
+ rRenderContext.DrawBitmapEx(aCenterPt, aDstBtnSize, aBtnPnt2, aBtnSize, rBitmap);
+ }
+ }
+}
+
+tools::Rectangle SvxRectCtl::GetFocusRect()
+{
+ tools::Rectangle aRet;
+ if (HasFocus())
+ aRet = CalculateFocusRectangle();
+ return aRet;
+}
+
+// Convert RectPoint Point
+
+const Point& SvxRectCtl::GetPointFromRP( RectPoint _eRP) const
+{
+ switch( _eRP )
+ {
+ case RectPoint::LT: return aPtLT;
+ case RectPoint::MT: return aPtMT;
+ case RectPoint::RT: return aPtRT;
+ case RectPoint::LM: return aPtLM;
+ case RectPoint::MM: return aPtMM;
+ case RectPoint::RM: return aPtRM;
+ case RectPoint::LB: return aPtLB;
+ case RectPoint::MB: return aPtMB;
+ case RectPoint::RB: return aPtRB;
+ }
+ return aPtMM; // default
+}
+
+Point SvxRectCtl::SetActualRPWithoutInvalidate( RectPoint eNewRP )
+{
+ Point aPtLast = aPtNew;
+ aPtNew = GetPointFromRP( eNewRP );
+
+ if( m_nState & CTL_STATE::NOHORZ )
+ aPtNew.setX( aPtMM.X() );
+
+ if( m_nState & CTL_STATE::NOVERT )
+ aPtNew.setY( aPtMM.Y() );
+
+ // fdo#74751 this fix reverse base point on RTL UI.
+ bool bRTL = AllSettings::GetLayoutRTL();
+ eNewRP = GetRPFromPoint( aPtNew, bRTL );
+
+ eDefRP = eNewRP;
+ eRP = eNewRP;
+
+ return aPtLast;
+}
+
+void SvxRectCtl::GetFocus()
+{
+ Invalidate();
+
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ // Send accessibility event.
+ if (pAccContext.is())
+ {
+ pAccContext->FireChildFocus(GetActualRP());
+ }
+#endif
+}
+
+void SvxRectCtl::LoseFocus()
+{
+ Invalidate();
+}
+
+Point SvxRectCtl::GetApproxLogPtFromPixPt( const Point& rPt ) const
+{
+ Point aPt = rPt;
+ tools::Long x;
+ tools::Long y;
+
+ Size aSize(GetOutputSizePixel());
+
+ if( !( m_nState & CTL_STATE::NOHORZ ) )
+ {
+ if( aPt.X() < aSize.Width() / 3 )
+ x = aPtLT.X();
+ else if( aPt.X() < aSize.Width() * 2 / 3 )
+ x = aPtMM.X();
+ else
+ x = aPtRB.X();
+ }
+ else
+ x = aPtMM.X();
+
+ if( !( m_nState & CTL_STATE::NOVERT ) )
+ {
+ if( aPt.Y() < aSize.Height() / 3 )
+ y = aPtLT.Y();
+ else if( aPt.Y() < aSize.Height() * 2 / 3 )
+ y = aPtMM.Y();
+ else
+ y = aPtRB.Y();
+ }
+ else
+ y = aPtMM.Y();
+
+ return Point( x, y );
+}
+
+
+// Converts Point in RectPoint
+
+RectPoint SvxRectCtl::GetRPFromPoint( Point aPt, bool bRTL ) const
+{
+ RectPoint rPoint = RectPoint::MM; // default
+
+ if (aPt == aPtLT) rPoint = bRTL ? RectPoint::RT : RectPoint::LT;
+ else if( aPt == aPtMT) rPoint = RectPoint::MT;
+ else if( aPt == aPtRT) rPoint = bRTL ? RectPoint::LT : RectPoint::RT;
+ else if( aPt == aPtLM) rPoint = bRTL ? RectPoint::RM : RectPoint::LM;
+ else if( aPt == aPtRM) rPoint = bRTL ? RectPoint::LM : RectPoint::RM;
+ else if( aPt == aPtLB) rPoint = bRTL ? RectPoint::RB : RectPoint::LB;
+ else if( aPt == aPtMB) rPoint = RectPoint::MB;
+ else if( aPt == aPtRB) rPoint = bRTL ? RectPoint::LB : RectPoint::RB;
+
+ return rPoint;
+}
+
+// Resets to the original state of the control
+
+void SvxRectCtl::Reset()
+{
+ aPtNew = GetPointFromRP( eDefRP );
+ eRP = eDefRP;
+ Invalidate();
+}
+
+// Returns the currently selected RectPoint
+
+
+void SvxRectCtl::SetActualRP( RectPoint eNewRP )
+{
+ SetActualRPWithoutInvalidate(eNewRP);
+
+ Invalidate();
+
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ // notify accessibility object about change
+ if (pAccContext.is())
+ pAccContext->selectChild( eNewRP /* MT, bFireFocus */ );
+#endif
+}
+
+void SvxRectCtl::SetState( CTL_STATE nState )
+{
+ m_nState = nState;
+
+ Point aPtLast( GetPointFromRP( eRP ) );
+ Point _aPtNew( aPtLast );
+
+ if( m_nState & CTL_STATE::NOHORZ )
+ _aPtNew.setX( aPtMM.X() );
+
+ if( m_nState & CTL_STATE::NOVERT)
+ _aPtNew.setY( aPtMM.Y() );
+
+ eRP = GetRPFromPoint( _aPtNew );
+ Invalidate();
+
+ if (m_pPage)
+ m_pPage->PointChanged(GetDrawingArea(), eRP);
+}
+
+tools::Rectangle SvxRectCtl::CalculateFocusRectangle() const
+{
+ Size aDstBtnSize(15, 15);
+ return tools::Rectangle( aPtNew - Point( aDstBtnSize.Width() >> 1, aDstBtnSize.Height() >> 1 ), aDstBtnSize );
+}
+
+tools::Rectangle SvxRectCtl::CalculateFocusRectangle( RectPoint eRectPoint ) const
+{
+ tools::Rectangle aRet;
+ RectPoint eOldRectPoint = GetActualRP();
+
+ if( eOldRectPoint == eRectPoint )
+ aRet = CalculateFocusRectangle();
+ else
+ {
+ SvxRectCtl* pThis = const_cast<SvxRectCtl*>(this);
+
+ pThis->SetActualRPWithoutInvalidate( eRectPoint ); // no invalidation because it's only temporary!
+ aRet = CalculateFocusRectangle();
+
+ pThis->SetActualRPWithoutInvalidate( eOldRectPoint ); // no invalidation because nothing has changed!
+ }
+
+ return aRet;
+}
+
+Reference< XAccessible > SvxRectCtl::CreateAccessible()
+{
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ pAccContext = new SvxRectCtlAccessibleContext(this);
+#endif
+ return pAccContext;
+}
+
+RectPoint SvxRectCtl::GetApproxRPFromPixPt( const css::awt::Point& r ) const
+{
+ return GetRPFromPoint( GetApproxLogPtFromPixPt( Point( r.X, r.Y ) ) );
+}
+
+// CompletelyDisabled() added to have a disabled state for SvxRectCtl
+void SvxRectCtl::DoCompletelyDisable(bool bNew)
+{
+ mbCompleteDisable = bNew;
+ Invalidate();
+}
+
+// Control for editing bitmaps
+
+css::uno::Reference< css::accessibility::XAccessible > SvxPixelCtl::CreateAccessible()
+{
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ if (!m_xAccess.is())
+ m_xAccess = new SvxPixelCtlAccessible(this);
+#endif
+ return m_xAccess;
+}
+
+tools::Long SvxPixelCtl::PointToIndex(const Point &aPt) const
+{
+ tools::Long nX = aPt.X() * nLines / aRectSize.Width();
+ tools::Long nY = aPt.Y() * nLines / aRectSize.Height();
+
+ return nX + nY * nLines ;
+}
+
+Point SvxPixelCtl::IndexToPoint(tools::Long nIndex) const
+{
+ DBG_ASSERT(nIndex >= 0 && nIndex < nSquares ," Check Index");
+
+ sal_Int32 nXIndex = nIndex % nLines;
+ sal_Int32 nYIndex = nIndex / nLines;
+
+ Point aPtTl;
+ aPtTl.setY( aRectSize.Height() * nYIndex / nLines + 1 );
+ aPtTl.setX( aRectSize.Width() * nXIndex / nLines + 1 );
+
+ return aPtTl;
+}
+
+tools::Long SvxPixelCtl::GetFocusPosIndex() const
+{
+ return aFocusPosition.getX() + aFocusPosition.getY() * nLines ;
+}
+
+tools::Long SvxPixelCtl::ShowPosition( const Point &rPt)
+{
+ sal_Int32 nX = rPt.X() * nLines / aRectSize.Width();
+ sal_Int32 nY = rPt.Y() * nLines / aRectSize.Height();
+
+ ChangePixel( nX + nY * nLines );
+
+ //Solution:Set new focus position and repaint
+ aFocusPosition.setX(nX);
+ aFocusPosition.setY(nY);
+ Invalidate(tools::Rectangle(Point(0,0),aRectSize));
+
+ if (m_pPage)
+ m_pPage->PointChanged(GetDrawingArea(), RectPoint::MM ); // RectPoint is dummy
+
+ return GetFocusPosIndex();
+
+}
+
+SvxPixelCtl::SvxPixelCtl(SvxTabPage* pPage)
+ : m_pPage(pPage)
+ , bPaintable(true)
+ , aFocusPosition(0,0)
+{
+ maPixelData.fill(0);
+}
+
+void SvxPixelCtl::Resize()
+{
+ CustomWidgetController::Resize();
+ aRectSize = GetOutputSizePixel();
+}
+
+void SvxPixelCtl::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ CustomWidgetController::SetDrawingArea(pDrawingArea);
+ pDrawingArea->set_size_request(pDrawingArea->get_approximate_digit_width() * 25,
+ pDrawingArea->get_text_height() * 10);
+}
+
+SvxPixelCtl::~SvxPixelCtl()
+{
+}
+
+// Changes the foreground or Background color
+
+void SvxPixelCtl::ChangePixel( sal_uInt16 nPixel )
+{
+ if( maPixelData[nPixel] == 0 )
+ maPixelData[nPixel] = 1; // could be extended to more colors
+ else
+ maPixelData[nPixel] = 0;
+}
+
+// The clicked rectangle is identified, to change its color
+
+bool SvxPixelCtl::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ if (!aRectSize.Width() || !aRectSize.Height())
+ return true;
+
+ //Grab focus when click in window
+ if (!HasFocus())
+ {
+ GrabFocus();
+ }
+
+ tools::Long nIndex = ShowPosition(rMEvt.GetPosPixel());
+
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ if(m_xAccess.is())
+ {
+ m_xAccess->NotifyChild(nIndex,true, true);
+ }
+#else
+ (void)nIndex;
+#endif
+
+ return true;
+}
+
+tools::Rectangle SvxPixelCtl::GetFocusRect()
+{
+ tools::Rectangle aRet;
+ //Draw visual focus when has focus
+ if (HasFocus())
+ aRet = implCalFocusRect(aFocusPosition);
+ return aRet;
+}
+
+// Draws the Control (Rectangle with nine circles)
+void SvxPixelCtl::Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& )
+{
+ if (!aRectSize.Width() || !aRectSize.Height())
+ return;
+
+ sal_uInt16 i, j, nTmp;
+ Point aPtTl, aPtBr;
+
+ if (bPaintable)
+ {
+ // Draw lines
+ rRenderContext.SetLineColor(Color());
+ for (i = 1; i < nLines; i++)
+ {
+ // horizontal
+ nTmp = static_cast<sal_uInt16>(aRectSize.Height() * i / nLines);
+ rRenderContext.DrawLine(Point(0, nTmp), Point(aRectSize.Width(), nTmp));
+ // vertically
+ nTmp = static_cast<sal_uInt16>( aRectSize.Width() * i / nLines );
+ rRenderContext.DrawLine(Point(nTmp, 0), Point(nTmp, aRectSize.Height()));
+ }
+
+ //Draw Rectangles (squares)
+ rRenderContext.SetLineColor();
+ sal_uInt16 nLastPixel = maPixelData[0] ? 0 : 1;
+
+ for (i = 0; i < nLines; i++)
+ {
+ aPtTl.setY( aRectSize.Height() * i / nLines + 1 );
+ aPtBr.setY( aRectSize.Height() * (i + 1) / nLines - 1 );
+
+ for (j = 0; j < nLines; j++)
+ {
+ aPtTl.setX( aRectSize.Width() * j / nLines + 1 );
+ aPtBr.setX( aRectSize.Width() * (j + 1) / nLines - 1 );
+
+ if (maPixelData[i * nLines + j] != nLastPixel)
+ {
+ nLastPixel = maPixelData[i * nLines + j];
+ // Change color: 0 -> Background color
+ rRenderContext.SetFillColor(nLastPixel ? aPixelColor : aBackgroundColor);
+ }
+ rRenderContext.DrawRect(tools::Rectangle(aPtTl, aPtBr));
+ }
+ }
+ }
+ else
+ {
+ rRenderContext.SetBackground(Wallpaper(COL_LIGHTGRAY));
+ rRenderContext.SetLineColor(COL_LIGHTRED);
+ rRenderContext.DrawLine(Point(0, 0), Point(aRectSize.Width(), aRectSize.Height()));
+ rRenderContext.DrawLine(Point(0, aRectSize.Height()), Point(aRectSize.Width(), 0));
+ }
+}
+
+//Calculate visual focus rectangle via focus position
+tools::Rectangle SvxPixelCtl::implCalFocusRect( const Point& aPosition )
+{
+ tools::Long nLeft,nTop,nRight,nBottom;
+ tools::Long i,j;
+ i = aPosition.Y();
+ j = aPosition.X();
+ nLeft = aRectSize.Width() * j / nLines + 1;
+ nRight = aRectSize.Width() * (j + 1) / nLines - 1;
+ nTop = aRectSize.Height() * i / nLines + 1;
+ nBottom = aRectSize.Height() * (i + 1) / nLines - 1;
+ return tools::Rectangle(nLeft,nTop,nRight,nBottom);
+}
+
+//Solution:Keyboard function
+bool SvxPixelCtl::KeyInput( const KeyEvent& rKEvt )
+{
+ vcl::KeyCode aKeyCode = rKEvt.GetKeyCode();
+ sal_uInt16 nCode = aKeyCode.GetCode();
+ bool bIsMod = aKeyCode.IsShift() || aKeyCode.IsMod1() || aKeyCode.IsMod2();
+
+ if( !bIsMod )
+ {
+ Point aRepaintPoint( aRectSize.Width() *( aFocusPosition.getX() - 1)/ nLines - 1,
+ aRectSize.Height() *( aFocusPosition.getY() - 1)/ nLines -1
+ );
+ Size aRepaintSize( aRectSize.Width() *3/ nLines + 2,aRectSize.Height() *3/ nLines + 2);
+ tools::Rectangle aRepaintRect( aRepaintPoint, aRepaintSize );
+ bool bFocusPosChanged=false;
+ switch(nCode)
+ {
+ case KEY_LEFT:
+ if(aFocusPosition.getX() >= 1)
+ {
+ aFocusPosition.setX( aFocusPosition.getX() - 1 );
+ Invalidate(aRepaintRect);
+ bFocusPosChanged=true;
+ }
+ break;
+ case KEY_RIGHT:
+ if( aFocusPosition.getX() < (nLines - 1) )
+ {
+ aFocusPosition.setX( aFocusPosition.getX() + 1 );
+ Invalidate(aRepaintRect);
+ bFocusPosChanged=true;
+ }
+ break;
+ case KEY_UP:
+ if(aFocusPosition.getY() >= 1)
+ {
+ aFocusPosition.setY( aFocusPosition.getY() - 1 );
+ Invalidate(aRepaintRect);
+ bFocusPosChanged=true;
+ }
+ break;
+ case KEY_DOWN:
+ if( aFocusPosition.getY() < ( nLines - 1 ) )
+ {
+ aFocusPosition.setY( aFocusPosition.getY() + 1 );
+ Invalidate(aRepaintRect);
+ bFocusPosChanged=true;
+ }
+ break;
+ case KEY_SPACE:
+ ChangePixel( sal_uInt16(aFocusPosition.getX() + aFocusPosition.getY() * nLines) );
+ Invalidate( implCalFocusRect(aFocusPosition) );
+ break;
+ default:
+ return CustomWidgetController::KeyInput( rKEvt );
+ }
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ if(m_xAccess.is())
+ {
+ tools::Long nIndex = GetFocusPosIndex();
+ switch(nCode)
+ {
+ case KEY_LEFT:
+ case KEY_RIGHT:
+ case KEY_UP:
+ case KEY_DOWN:
+ if (bFocusPosChanged)
+ {
+ m_xAccess->NotifyChild(nIndex,false,false);
+ }
+ break;
+ case KEY_SPACE:
+ m_xAccess->NotifyChild(nIndex,false,true);
+ break;
+ default:
+ break;
+ }
+ }
+#else
+ (void)bFocusPosChanged;
+#endif
+ return true;
+ }
+ else
+ {
+ return CustomWidgetController::KeyInput( rKEvt );
+ }
+}
+
+//Draw focus when get focus
+void SvxPixelCtl::GetFocus()
+{
+ Invalidate(implCalFocusRect(aFocusPosition));
+
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ if (m_xAccess.is())
+ {
+ m_xAccess->NotifyChild(GetFocusPosIndex(),true,false);
+ }
+#endif
+}
+
+void SvxPixelCtl::LoseFocus()
+{
+ Invalidate();
+}
+
+void SvxPixelCtl::SetXBitmap(const BitmapEx& rBitmapEx)
+{
+ if (vcl::bitmap::isHistorical8x8(rBitmapEx, aBackgroundColor, aPixelColor))
+ {
+ for (sal_uInt16 i = 0; i < nSquares; i++)
+ {
+ Color aColor = rBitmapEx.GetPixelColor(i%8, i/8);
+ maPixelData[i] = (aColor == aBackgroundColor) ? 0 : 1;
+ }
+ }
+}
+
+// Returns a specific pixel
+
+sal_uInt8 SvxPixelCtl::GetBitmapPixel( const sal_uInt16 nPixel ) const
+{
+ return maPixelData[nPixel];
+}
+
+// Resets to the original state of the control
+
+void SvxPixelCtl::Reset()
+{
+ // clear pixel area
+ maPixelData.fill(0);
+ Invalidate();
+}
+
+SvxLineLB::SvxLineLB(std::unique_ptr<weld::ComboBox> pControl)
+ : m_xControl(std::move(pControl))
+ , mbAddStandardFields(true)
+{
+}
+
+void SvxLineLB::setAddStandardFields(bool bNew)
+{
+ if(getAddStandardFields() != bNew)
+ {
+ mbAddStandardFields = bNew;
+ }
+}
+
+// Fills the listbox (provisional) with strings
+
+void SvxLineLB::Fill( const XDashListRef &pList )
+{
+ m_xControl->clear();
+
+ if( !pList.is() )
+ return;
+
+ ScopedVclPtrInstance< VirtualDevice > pVD;
+
+ if(getAddStandardFields())
+ {
+ // entry for 'none'
+ m_xControl->append_text(pList->GetStringForUiNoLine());
+
+ // entry for solid line
+ const BitmapEx aBitmap = pList->GetBitmapForUISolidLine();
+ const Size aBmpSize(aBitmap.GetSizePixel());
+ pVD->SetOutputSizePixel(aBmpSize, false);
+ pVD->DrawBitmapEx(Point(), aBitmap);
+ m_xControl->append("", pList->GetStringForUiSolidLine(), *pVD);
+ }
+
+ // entries for dashed lines
+
+ tools::Long nCount = pList->Count();
+ m_xControl->freeze();
+
+ for( tools::Long i = 0; i < nCount; i++ )
+ {
+ const XDashEntry* pEntry = pList->GetDash(i);
+ const BitmapEx aBitmap = pList->GetUiBitmap( i );
+ if( !aBitmap.IsEmpty() )
+ {
+ const Size aBmpSize(aBitmap.GetSizePixel());
+ pVD->SetOutputSizePixel(aBmpSize, false);
+ pVD->DrawBitmapEx(Point(), aBitmap);
+ m_xControl->append("", pEntry->GetName(), *pVD);
+ }
+ else
+ {
+ m_xControl->append_text(pEntry->GetName());
+ }
+ }
+
+ m_xControl->thaw();
+}
+
+void SvxLineLB::Append( const XDashEntry& rEntry, const BitmapEx& rBitmap )
+{
+ if (!rBitmap.IsEmpty())
+ {
+ ScopedVclPtrInstance< VirtualDevice > pVD;
+
+ const Size aBmpSize(rBitmap.GetSizePixel());
+ pVD->SetOutputSizePixel(aBmpSize, false);
+ pVD->DrawBitmapEx(Point(), rBitmap);
+ m_xControl->append("", rEntry.GetName(), *pVD);
+ }
+ else
+ {
+ m_xControl->append_text(rEntry.GetName());
+ }
+}
+
+void SvxLineLB::Modify(const XDashEntry& rEntry, sal_Int32 nPos, const BitmapEx& rBitmap)
+{
+ m_xControl->remove(nPos);
+
+ if (!rBitmap.IsEmpty())
+ {
+ ScopedVclPtrInstance< VirtualDevice > pVD;
+
+ const Size aBmpSize(rBitmap.GetSizePixel());
+ pVD->SetOutputSizePixel(aBmpSize, false);
+ pVD->DrawBitmapEx(Point(), rBitmap);
+ m_xControl->insert(nPos, rEntry.GetName(), nullptr, nullptr, pVD);
+ }
+ else
+ {
+ m_xControl->insert_text(nPos, rEntry.GetName());
+ }
+}
+
+SvxLineEndLB::SvxLineEndLB(std::unique_ptr<weld::ComboBox> pControl)
+ : m_xControl(std::move(pControl))
+{
+}
+
+void SvxLineEndLB::Fill( const XLineEndListRef &pList, bool bStart )
+{
+ if( !pList.is() )
+ return;
+
+ tools::Long nCount = pList->Count();
+ ScopedVclPtrInstance< VirtualDevice > pVD;
+ m_xControl->freeze();
+
+ for( tools::Long i = 0; i < nCount; i++ )
+ {
+ const XLineEndEntry* pEntry = pList->GetLineEnd(i);
+ const BitmapEx aBitmap = pList->GetUiBitmap( i );
+ if( !aBitmap.IsEmpty() )
+ {
+ const Size aBmpSize(aBitmap.GetSizePixel());
+ pVD->SetOutputSizePixel(Size(aBmpSize.Width() / 2, aBmpSize.Height()), false);
+ pVD->DrawBitmapEx(bStart ? Point() : Point(-aBmpSize.Width() / 2, 0), aBitmap);
+ m_xControl->append("", pEntry->GetName(), *pVD);
+ }
+ else
+ m_xControl->append_text(pEntry->GetName());
+ }
+
+ m_xControl->thaw();
+}
+
+void SvxLineEndLB::Append( const XLineEndEntry& rEntry, const BitmapEx& rBitmap )
+{
+ if(!rBitmap.IsEmpty())
+ {
+ ScopedVclPtrInstance< VirtualDevice > pVD;
+
+ const Size aBmpSize(rBitmap.GetSizePixel());
+ pVD->SetOutputSizePixel(Size(aBmpSize.Width() / 2, aBmpSize.Height()), false);
+ pVD->DrawBitmapEx(Point(-aBmpSize.Width() / 2, 0), rBitmap);
+ m_xControl->append("", rEntry.GetName(), *pVD);
+ }
+ else
+ {
+ m_xControl->append_text(rEntry.GetName());
+ }
+}
+
+void SvxLineEndLB::Modify( const XLineEndEntry& rEntry, sal_Int32 nPos, const BitmapEx& rBitmap )
+{
+ m_xControl->remove(nPos);
+
+ if(!rBitmap.IsEmpty())
+ {
+ ScopedVclPtrInstance< VirtualDevice > pVD;
+
+ const Size aBmpSize(rBitmap.GetSizePixel());
+ pVD->SetOutputSizePixel(Size(aBmpSize.Width() / 2, aBmpSize.Height()), false);
+ pVD->DrawBitmapEx(Point(-aBmpSize.Width() / 2, 0), rBitmap);
+ m_xControl->insert(nPos, rEntry.GetName(), nullptr, nullptr, pVD);
+ }
+ else
+ {
+ m_xControl->insert_text(nPos, rEntry.GetName());
+ }
+}
+
+void SvxXLinePreview::Resize()
+{
+ SvxPreviewBase::Resize();
+
+ const Size aOutputSize(GetOutputSize());
+ const sal_Int32 nDistance(500);
+ const sal_Int32 nAvailableLength(aOutputSize.Width() - (4 * nDistance));
+
+ // create DrawObjectA
+ const sal_Int32 aYPosA(aOutputSize.Height() / 2);
+ const basegfx::B2DPoint aPointA1( nDistance, aYPosA);
+ const basegfx::B2DPoint aPointA2( aPointA1.getX() + ((nAvailableLength * 14) / 20), aYPosA );
+ basegfx::B2DPolygon aPolygonA;
+ aPolygonA.append(aPointA1);
+ aPolygonA.append(aPointA2);
+ mpLineObjA->SetPathPoly(basegfx::B2DPolyPolygon(aPolygonA));
+
+ // create DrawObjectB
+ const sal_Int32 aYPosB1((aOutputSize.Height() * 3) / 4);
+ const sal_Int32 aYPosB2((aOutputSize.Height() * 1) / 4);
+ const basegfx::B2DPoint aPointB1( aPointA2.getX() + nDistance, aYPosB1);
+ const basegfx::B2DPoint aPointB2( aPointB1.getX() + ((nAvailableLength * 2) / 20), aYPosB2 );
+ const basegfx::B2DPoint aPointB3( aPointB2.getX() + ((nAvailableLength * 2) / 20), aYPosB1 );
+ basegfx::B2DPolygon aPolygonB;
+ aPolygonB.append(aPointB1);
+ aPolygonB.append(aPointB2);
+ aPolygonB.append(aPointB3);
+ mpLineObjB->SetPathPoly(basegfx::B2DPolyPolygon(aPolygonB));
+
+ // create DrawObjectC
+ basegfx::B2DPolygon aPolygonC;
+ const basegfx::B2DPoint aPointC1( aPointB3.getX() + nDistance, aYPosB1);
+ const basegfx::B2DPoint aPointC2( aPointC1.getX() + ((nAvailableLength * 1) / 20), aYPosB2 );
+ const basegfx::B2DPoint aPointC3( aPointC2.getX() + ((nAvailableLength * 1) / 20), aYPosB1 );
+ aPolygonC.append(aPointC1);
+ aPolygonC.append(aPointC2);
+ aPolygonC.append(aPointC3);
+ mpLineObjC->SetPathPoly(basegfx::B2DPolyPolygon(aPolygonC));
+}
+
+SvxXLinePreview::SvxXLinePreview()
+ : mpGraphic(nullptr)
+ , mbWithSymbol(false)
+{
+}
+
+void SvxXLinePreview::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ SvxPreviewBase::SetDrawingArea(pDrawingArea);
+
+ mpLineObjA = new SdrPathObj(getModel(), SdrObjKind::Line);
+ mpLineObjB = new SdrPathObj(getModel(), SdrObjKind::PolyLine);
+ mpLineObjC = new SdrPathObj(getModel(), SdrObjKind::PolyLine);
+
+ Resize();
+ Invalidate();
+}
+
+SvxXLinePreview::~SvxXLinePreview()
+{
+}
+
+void SvxXLinePreview::SetSymbol(Graphic* p,const Size& s)
+{
+ mpGraphic = p;
+ maSymbolSize = s;
+}
+
+void SvxXLinePreview::ResizeSymbol(const Size& s)
+{
+ if ( s != maSymbolSize )
+ {
+ maSymbolSize = s;
+ Invalidate();
+ }
+}
+
+void SvxXLinePreview::SetLineAttributes(const SfxItemSet& rItemSet)
+{
+ // Set ItemSet at objects
+ mpLineObjA->SetMergedItemSet(rItemSet);
+
+ // At line joints, do not use arrows
+ SfxItemSet aTempSet(rItemSet);
+ aTempSet.ClearItem(XATTR_LINESTART);
+ aTempSet.ClearItem(XATTR_LINEEND);
+
+ mpLineObjB->SetMergedItemSet(aTempSet);
+ mpLineObjC->SetMergedItemSet(aTempSet);
+}
+
+void SvxXLinePreview::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ LocalPrePaint(rRenderContext);
+
+ // paint objects to buffer device
+ sdr::contact::SdrObjectVector aObjectVector;
+ aObjectVector.push_back(mpLineObjA.get());
+ aObjectVector.push_back(mpLineObjB.get());
+ aObjectVector.push_back(mpLineObjC.get());
+
+ sdr::contact::ObjectContactOfObjListPainter aPainter(getBufferDevice(), std::move(aObjectVector), nullptr);
+ sdr::contact::DisplayInfo aDisplayInfo;
+
+ // do processing
+ aPainter.ProcessDisplay(aDisplayInfo);
+
+ if ( mbWithSymbol && mpGraphic )
+ {
+ const Size aOutputSize(GetOutputSize());
+ Point aPos( aOutputSize.Width() / 3, aOutputSize.Height() / 2 );
+ aPos.AdjustX( -(maSymbolSize.Width() / 2) );
+ aPos.AdjustY( -(maSymbolSize.Height() / 2) );
+ mpGraphic->Draw(getBufferDevice(), aPos, maSymbolSize);
+ }
+
+ LocalPostPaint(rRenderContext);
+}
+
+SvxXShadowPreview::SvxXShadowPreview()
+{
+}
+
+void SvxXShadowPreview::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ SvxPreviewBase::SetDrawingArea(pDrawingArea);
+ InitSettings();
+
+ // prepare size
+ Size aSize = GetPreviewSize().GetSize();
+ aSize.setWidth( aSize.Width() / 3 );
+ aSize.setHeight( aSize.Height() / 3 );
+
+ // create RectangleObject
+ const tools::Rectangle aObjectSize( Point( aSize.Width(), aSize.Height() ), aSize );
+ mpRectangleObject = new SdrRectObj(
+ getModel(),
+ aObjectSize);
+
+ // create ShadowObject
+ const tools::Rectangle aShadowSize( Point( aSize.Width(), aSize.Height() ), aSize );
+ mpRectangleShadow = new SdrRectObj(
+ getModel(),
+ aShadowSize);
+}
+
+SvxXShadowPreview::~SvxXShadowPreview()
+{
+}
+
+void SvxXShadowPreview::SetRectangleAttributes(const SfxItemSet& rItemSet)
+{
+ mpRectangleObject->SetMergedItemSet(rItemSet, true);
+ mpRectangleObject->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE));
+}
+
+void SvxXShadowPreview::SetShadowAttributes(const SfxItemSet& rItemSet)
+{
+ mpRectangleShadow->SetMergedItemSet(rItemSet, true);
+ mpRectangleShadow->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE));
+}
+
+void SvxXShadowPreview::SetShadowPosition(const Point& rPos)
+{
+ maShadowOffset = rPos;
+}
+
+void SvxXShadowPreview::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ rRenderContext.Push(vcl::PushFlags::MAPMODE);
+ rRenderContext.SetMapMode(MapMode(MapUnit::Map100thMM));
+
+ LocalPrePaint(rRenderContext);
+
+ // prepare size
+ Size aSize = rRenderContext.GetOutputSize();
+ aSize.setWidth( aSize.Width() / 3 );
+ aSize.setHeight( aSize.Height() / 3 );
+
+ tools::Rectangle aObjectRect(Point(aSize.Width(), aSize.Height()), aSize);
+ mpRectangleObject->SetSnapRect(aObjectRect);
+ aObjectRect.Move(maShadowOffset.X(), maShadowOffset.Y());
+ mpRectangleShadow->SetSnapRect(aObjectRect);
+
+ sdr::contact::SdrObjectVector aObjectVector;
+
+ aObjectVector.push_back(mpRectangleShadow.get());
+ aObjectVector.push_back(mpRectangleObject.get());
+
+ sdr::contact::ObjectContactOfObjListPainter aPainter(getBufferDevice(), std::move(aObjectVector), nullptr);
+ sdr::contact::DisplayInfo aDisplayInfo;
+
+ aPainter.ProcessDisplay(aDisplayInfo);
+
+ LocalPostPaint(rRenderContext);
+
+ rRenderContext.Pop();
+}
+
+void SvxPreviewBase::InitSettings()
+{
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+
+ svtools::ColorConfig aColorConfig;
+ Color aTextColor(aColorConfig.GetColorValue(svtools::FONTCOLOR).nColor);
+ getBufferDevice().SetTextColor(aTextColor);
+
+ getBufferDevice().SetBackground(rStyleSettings.GetWindowColor());
+
+ getBufferDevice().SetDrawMode(rStyleSettings.GetHighContrastMode() ? OUTPUT_DRAWMODE_CONTRAST : OUTPUT_DRAWMODE_COLOR);
+
+ Invalidate();
+}
+
+SvxPreviewBase::SvxPreviewBase()
+ : mpModel(new SdrModel(nullptr, nullptr, true))
+{
+ // init model
+ mpModel->GetItemPool().FreezeIdRanges();
+}
+
+void SvxPreviewBase::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ CustomWidgetController::SetDrawingArea(pDrawingArea);
+ Size aSize(getPreviewStripSize(pDrawingArea->get_ref_device()));
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+ SetOutputSizePixel(aSize);
+
+ mpBufferDevice = VclPtr<VirtualDevice>::Create(pDrawingArea->get_ref_device());
+ mpBufferDevice->SetMapMode(MapMode(MapUnit::Map100thMM));
+}
+
+SvxPreviewBase::~SvxPreviewBase()
+{
+ mpModel.reset();
+ mpBufferDevice.disposeAndClear();
+}
+
+void SvxPreviewBase::LocalPrePaint(vcl::RenderContext const & rRenderContext)
+{
+ // init BufferDevice
+ if (mpBufferDevice->GetOutputSizePixel() != GetOutputSizePixel())
+ mpBufferDevice->SetOutputSizePixel(GetOutputSizePixel());
+ mpBufferDevice->SetAntialiasing(rRenderContext.GetAntialiasing());
+
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+
+ if (rStyleSettings.GetPreviewUsesCheckeredBackground())
+ {
+ const Point aNull(0, 0);
+ static const sal_uInt32 nLen(8);
+ static const Color aW(COL_WHITE);
+ static const Color aG(0xef, 0xef, 0xef);
+ const bool bWasEnabled(mpBufferDevice->IsMapModeEnabled());
+
+ mpBufferDevice->EnableMapMode(false);
+ mpBufferDevice->DrawCheckered(aNull, mpBufferDevice->GetOutputSizePixel(), nLen, aW, aG);
+ mpBufferDevice->EnableMapMode(bWasEnabled);
+ }
+ else
+ {
+ mpBufferDevice->Erase();
+ }
+}
+
+void SvxPreviewBase::LocalPostPaint(vcl::RenderContext& rRenderContext)
+{
+ // copy to front (in pixel mode)
+ const bool bWasEnabledSrc(mpBufferDevice->IsMapModeEnabled());
+ const bool bWasEnabledDst(rRenderContext.IsMapModeEnabled());
+ const Point aEmptyPoint;
+
+ mpBufferDevice->EnableMapMode(false);
+ rRenderContext.EnableMapMode(false);
+
+ rRenderContext.DrawOutDev(aEmptyPoint, GetOutputSizePixel(),
+ aEmptyPoint, GetOutputSizePixel(),
+ *mpBufferDevice);
+
+ mpBufferDevice->EnableMapMode(bWasEnabledSrc);
+ rRenderContext.EnableMapMode(bWasEnabledDst);
+}
+
+void SvxPreviewBase::StyleUpdated()
+{
+ InitSettings();
+ CustomWidgetController::StyleUpdated();
+}
+
+SvxXRectPreview::SvxXRectPreview()
+{
+}
+
+tools::Rectangle SvxPreviewBase::GetPreviewSize() const
+{
+ tools::Rectangle aObjectSize(Point(), getBufferDevice().PixelToLogic(GetOutputSizePixel()));
+ return aObjectSize;
+}
+
+void SvxXRectPreview::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ SvxPreviewBase::SetDrawingArea(pDrawingArea);
+ InitSettings();
+
+ // create RectangleObject
+ mpRectangleObject = new SdrRectObj(getModel(), GetPreviewSize());
+}
+
+void SvxXRectPreview::Resize()
+{
+ rtl::Reference<SdrObject> pOrigObject = mpRectangleObject;
+ if (pOrigObject)
+ {
+ mpRectangleObject = new SdrRectObj(getModel(), GetPreviewSize());
+ SetAttributes(pOrigObject->GetMergedItemSet());
+ pOrigObject.clear();
+ }
+ SvxPreviewBase::Resize();
+}
+
+SvxXRectPreview::~SvxXRectPreview()
+{
+}
+
+void SvxXRectPreview::SetAttributes(const SfxItemSet& rItemSet)
+{
+ mpRectangleObject->SetMergedItemSet(rItemSet, true);
+ mpRectangleObject->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE));
+}
+
+void SvxXRectPreview::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ rRenderContext.Push(vcl::PushFlags::MAPMODE);
+ rRenderContext.SetMapMode(MapMode(MapUnit::Map100thMM));
+ LocalPrePaint(rRenderContext);
+
+ sdr::contact::SdrObjectVector aObjectVector;
+
+ aObjectVector.push_back(mpRectangleObject.get());
+
+ sdr::contact::ObjectContactOfObjListPainter aPainter(getBufferDevice(), std::move(aObjectVector), nullptr);
+ sdr::contact::DisplayInfo aDisplayInfo;
+
+ aPainter.ProcessDisplay(aDisplayInfo);
+
+ LocalPostPaint(rRenderContext);
+ rRenderContext.Pop();
+}
+
+void limitWidthForSidebar(weld::SpinButton& rSpinButton)
+{
+ // space is limited in the sidebar, so limit MetricSpinButtons to a width of 4 digits
+ const int nMaxDigits = 4;
+ rSpinButton.set_width_chars(std::min(rSpinButton.get_width_chars(), nMaxDigits));
+}
+
+void limitWidthForSidebar(SvxRelativeField& rMetricSpinButton)
+{
+ weld::SpinButton& rSpinButton = rMetricSpinButton.get_widget();
+ limitWidthForSidebar(rSpinButton);
+}
+
+void padWidthForSidebar(weld::Toolbar& rToolbar, const css::uno::Reference<css::frame::XFrame>& rFrame)
+{
+ static int nColumnWidth = -1;
+ static vcl::ImageType eSize;
+ if (nColumnWidth != -1 && eSize != rToolbar.get_icon_size())
+ nColumnWidth = -1;
+ if (nColumnWidth == -1)
+ {
+ // use the, filled-in by dispatcher, width of measurewidth as the width
+ // of a "standard" column in a two column panel
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(&rToolbar, "svx/ui/measurewidthbar.ui"));
+ std::unique_ptr<weld::Toolbar> xToolbar1(xBuilder->weld_toolbar("measurewidth1"));
+ ToolbarUnoDispatcher aDispatcher1(*xToolbar1, *xBuilder, rFrame);
+ std::unique_ptr<weld::Toolbar> xToolbar2(xBuilder->weld_toolbar("measurewidth2"));
+ ToolbarUnoDispatcher aDispatcher2(*xToolbar2, *xBuilder, rFrame);
+ nColumnWidth = std::max(xToolbar1->get_preferred_size().Width(), xToolbar2->get_preferred_size().Width());
+ eSize = rToolbar.get_icon_size();
+ }
+ rToolbar.set_size_request(nColumnWidth, -1);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/dlgunit.hxx b/svx/source/dialog/dlgunit.hxx
new file mode 100644
index 0000000000..a1e79b1182
--- /dev/null
+++ b/svx/source/dialog/dlgunit.hxx
@@ -0,0 +1,55 @@
+/* -*- 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 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_DIALOG_DLGUNIT_HXX
+#define INCLUDED_SVX_SOURCE_DIALOG_DLGUNIT_HXX
+
+#include <rtl/ustrbuf.hxx>
+#include <svx/svdtrans.hxx>
+#include <vcl/fieldvalues.hxx>
+
+inline OUString GetUnitString(tools::Long nVal_100, FieldUnit eFieldUnit, sal_Unicode cSep)
+{
+ OUStringBuffer aVal
+ = OUString::number(vcl::ConvertValue(nVal_100, 2, MapUnit::Map100thMM, eFieldUnit));
+
+ while (aVal.getLength() < 3)
+ aVal.insert(0, "0");
+
+ aVal.insert(aVal.getLength() - 2, cSep);
+ OUString aSuffix = SdrFormatter::GetUnitStr(eFieldUnit);
+ if (eFieldUnit != FieldUnit::NONE && eFieldUnit != FieldUnit::DEGREE
+ && eFieldUnit != FieldUnit::INCH)
+ aVal.append(" ");
+ if (eFieldUnit == FieldUnit::INCH)
+ {
+ OUString sDoublePrime = u"\u2033"_ustr;
+ if (aSuffix != "\"" && aSuffix != sDoublePrime)
+ aVal.append(" ");
+ else
+ aSuffix = sDoublePrime;
+ }
+ aVal.append(aSuffix);
+
+ return aVal.makeStringAndClear();
+}
+
+#endif // INCLUDED_SVX_SOURCE_DIALOG_DLGUNIT_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/dlgutil.cxx b/svx/source/dialog/dlgutil.cxx
new file mode 100644
index 0000000000..a33e1ca947
--- /dev/null
+++ b/svx/source/dialog/dlgutil.cxx
@@ -0,0 +1,74 @@
+/* -*- 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 <svx/dlgutil.hxx>
+#include <svl/itemset.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <sfx2/module.hxx>
+#include <svl/intitem.hxx>
+#include <svl/eitem.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/objsh.hxx>
+#include <sal/log.hxx>
+
+
+FieldUnit GetModuleFieldUnit( const SfxItemSet& rSet )
+{
+ if (const SfxUInt16Item* pItem = rSet.GetItemIfSet(SID_ATTR_METRIC, false))
+ return static_cast<FieldUnit>(pItem->GetValue());
+
+ return SfxModule::GetCurrentFieldUnit();
+}
+
+bool GetApplyCharUnit( const SfxItemSet& rSet )
+{
+ bool bUseCharUnit = false;
+ if ( const SfxBoolItem* pItem = rSet.GetItemIfSet( SID_ATTR_APPLYCHARUNIT, false ) )
+ bUseCharUnit = pItem->GetValue();
+ else
+ {
+ // FIXME - this might be wrong, cf. the DEV300 changes in GetModuleFieldUnit()
+ SfxViewFrame* pFrame = SfxViewFrame::Current();
+ SfxObjectShell* pSh = nullptr;
+ if ( pFrame )
+ pSh = pFrame->GetObjectShell();
+ if ( pSh ) // the object shell is not always available during reload
+ {
+ SfxModule* pModule = pSh->GetModule();
+ if ( pModule )
+ {
+ pItem = pModule->GetItem( SID_ATTR_APPLYCHARUNIT );
+ if ( pItem )
+ bUseCharUnit = pItem->GetValue();
+ }
+ else
+ {
+ SAL_WARN( "svx.dialog", "GetApplyCharUnit(): no module found" );
+ }
+ }
+ }
+ return bUseCharUnit;
+}
+
+FieldUnit GetModuleFieldUnit()
+{
+ return SfxModule::GetCurrentFieldUnit();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/docrecovery.cxx b/svx/source/dialog/docrecovery.cxx
new file mode 100644
index 0000000000..1e40115270
--- /dev/null
+++ b/svx/source/dialog/docrecovery.cxx
@@ -0,0 +1,1239 @@
+/* -*- 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 <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+#include <bitmaps.hlst>
+#include <docrecovery.hxx>
+
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/sequenceashashmap.hxx>
+#include <comphelper/string.hxx>
+#include <o3tl/safeint.hxx>
+#include <svtools/imagemgr.hxx>
+#include <sfx2/filedlghelper.hxx>
+#include <tools/urlobj.hxx>
+#include <utility>
+#include <vcl/weld.hxx>
+#include <vcl/svapp.hxx>
+
+#include <com/sun/star/util/URL.hpp>
+#include <com/sun/star/util/XURLTransformer.hpp>
+#include <com/sun/star/frame/theAutoRecovery.hpp>
+#include <com/sun/star/ui/dialogs/XFolderPicker2.hpp>
+#include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
+#include <com/sun/star/util/URLTransformer.hpp>
+#include <osl/file.hxx>
+#include <unotools/pathoptions.hxx>
+
+namespace svx::DocRecovery
+{
+
+using namespace ::osl;
+
+#define COLUMN_STANDARDIMAGE -1
+#define COLUMN_DISPLAYNAME 0
+#define COLUMN_STATUSIMAGE 1
+#define COLUMN_STATUSTEXT 2
+
+RecoveryCore::RecoveryCore(css::uno::Reference< css::uno::XComponentContext > xContext,
+ bool bUsedForSaving)
+ : m_xContext (std::move( xContext ))
+ , m_pListener ( nullptr )
+ , m_bListenForSaving(bUsedForSaving)
+{
+ impl_startListening();
+}
+
+
+RecoveryCore::~RecoveryCore()
+{
+ impl_stopListening();
+}
+
+
+const css::uno::Reference< css::uno::XComponentContext >& RecoveryCore::getComponentContext() const
+{
+ return m_xContext;
+}
+
+
+TURLList& RecoveryCore::getURLListAccess()
+{
+ return m_lURLs;
+}
+
+
+bool RecoveryCore::isBrokenTempEntry(const TURLInfo& rInfo)
+{
+ if (rInfo.TempURL.isEmpty())
+ return false;
+
+ // Note: If the original files was recovery ... but a temp file
+ // exists ... an error inside the temp file exists!
+ if (
+ (rInfo.RecoveryState != E_RECOVERY_FAILED ) &&
+ (rInfo.RecoveryState != E_ORIGINAL_DOCUMENT_RECOVERED)
+ )
+ return false;
+
+ return true;
+}
+
+
+void RecoveryCore::saveBrokenTempEntries(const OUString& rPath)
+{
+ if (rPath.isEmpty())
+ return;
+
+ if (!m_xRealCore.is())
+ return;
+
+ // prepare all needed parameters for the following dispatch() request.
+ css::util::URL aCopyURL = impl_getParsedURL(RECOVERY_CMD_DO_ENTRY_BACKUP);
+ css::uno::Sequence< css::beans::PropertyValue > lCopyArgs(3);
+ auto plCopyArgs = lCopyArgs.getArray();
+ plCopyArgs[0].Name = PROP_DISPATCHASYNCHRON;
+ plCopyArgs[0].Value <<= false;
+ plCopyArgs[1].Name = PROP_SAVEPATH;
+ plCopyArgs[1].Value <<= rPath;
+ plCopyArgs[2].Name = PROP_ENTRYID;
+ // lCopyArgs[2].Value will be changed during next loop...
+
+ // work on a copied list only...
+ // Reason: We will get notifications from the core for every
+ // changed or removed element. And that will change our m_lURLs list.
+ // That's not a good idea, if we use a stl iterator inbetween .-)
+ TURLList lURLs = m_lURLs;
+ for (const TURLInfo& rInfo : lURLs)
+ {
+ if (!RecoveryCore::isBrokenTempEntry(rInfo))
+ continue;
+
+ plCopyArgs[2].Value <<= rInfo.ID;
+ m_xRealCore->dispatch(aCopyURL, lCopyArgs);
+ }
+}
+
+
+void RecoveryCore::saveAllTempEntries(const OUString& rPath)
+{
+ if (rPath.isEmpty())
+ return;
+
+ if (!m_xRealCore.is())
+ return;
+
+ // prepare all needed parameters for the following dispatch() request.
+ css::util::URL aCopyURL = impl_getParsedURL(RECOVERY_CMD_DO_ENTRY_BACKUP);
+ css::uno::Sequence< css::beans::PropertyValue > lCopyArgs(3);
+ auto plCopyArgs = lCopyArgs.getArray();
+ plCopyArgs[0].Name = PROP_DISPATCHASYNCHRON;
+ plCopyArgs[0].Value <<= false;
+ plCopyArgs[1].Name = PROP_SAVEPATH;
+ plCopyArgs[1].Value <<= rPath;
+ plCopyArgs[2].Name = PROP_ENTRYID;
+ // lCopyArgs[2].Value will be changed during next loop ...
+
+ // work on a copied list only ...
+ // Reason: We will get notifications from the core for every
+ // changed or removed element. And that will change our m_lURLs list.
+ // That's not a good idea, if we use a stl iterator inbetween .-)
+ TURLList lURLs = m_lURLs;
+ for (const TURLInfo& rInfo : lURLs)
+ {
+ if (rInfo.TempURL.isEmpty())
+ continue;
+
+ plCopyArgs[2].Value <<= rInfo.ID;
+ m_xRealCore->dispatch(aCopyURL, lCopyArgs);
+ }
+}
+
+
+void RecoveryCore::forgetBrokenTempEntries()
+{
+ if (!m_xRealCore.is())
+ return;
+
+ css::util::URL aRemoveURL = impl_getParsedURL(RECOVERY_CMD_DO_ENTRY_CLEANUP);
+ css::uno::Sequence< css::beans::PropertyValue > lRemoveArgs(2);
+ auto plRemoveArgs = lRemoveArgs.getArray();
+ plRemoveArgs[0].Name = PROP_DISPATCHASYNCHRON;
+ plRemoveArgs[0].Value <<= false;
+ plRemoveArgs[1].Name = PROP_ENTRYID;
+ // lRemoveArgs[1].Value will be changed during next loop ...
+
+ // work on a copied list only ...
+ // Reason: We will get notifications from the core for every
+ // changed or removed element. And that will change our m_lURLs list.
+ // That's not a good idea, if we use a stl iterator inbetween .-)
+ TURLList lURLs = m_lURLs;
+ for (const TURLInfo& rInfo : lURLs)
+ {
+ if (!RecoveryCore::isBrokenTempEntry(rInfo))
+ continue;
+
+ plRemoveArgs[1].Value <<= rInfo.ID;
+ m_xRealCore->dispatch(aRemoveURL, lRemoveArgs);
+ }
+}
+
+// should only be called with valid m_xRealCore
+void RecoveryCore::forgetAllRecoveryEntriesMarkedForDiscard()
+{
+ assert(m_xRealCore);
+
+ // potential to move in a separate function
+ css::util::URL aRemoveURL = impl_getParsedURL(RECOVERY_CMD_DO_ENTRY_CLEANUP);
+ css::uno::Sequence<css::beans::PropertyValue> lRemoveArgs(2);
+ auto plRemoveArgs = lRemoveArgs.getArray();
+ plRemoveArgs[0].Name = PROP_DISPATCHASYNCHRON;
+ plRemoveArgs[0].Value <<= false;
+ plRemoveArgs[1].Name = PROP_ENTRYID;
+
+ // work on a copied list only ...
+ // Reason: We will get notifications from the core for every
+ // changed or removed element. And that will change our m_lURLs list.
+ // That's not a good idea, if we use a stl iterator inbetween .-)
+ TURLList lURLs = m_lURLs;
+ for (const TURLInfo& rInfo : lURLs)
+ {
+ if (!rInfo.ShouldDiscard)
+ continue;
+
+ plRemoveArgs[1].Value <<= rInfo.ID;
+ m_xRealCore->dispatch(aRemoveURL, lRemoveArgs);
+ }
+}
+
+void RecoveryCore::forgetAllRecoveryEntries()
+{
+ if (!m_xRealCore.is())
+ return;
+
+ css::util::URL aRemoveURL = impl_getParsedURL(RECOVERY_CMD_DO_ENTRY_CLEANUP);
+ css::uno::Sequence< css::beans::PropertyValue > lRemoveArgs(2);
+ auto plRemoveArgs = lRemoveArgs.getArray();
+ plRemoveArgs[0].Name = PROP_DISPATCHASYNCHRON;
+ plRemoveArgs[0].Value <<= false;
+ plRemoveArgs[1].Name = PROP_ENTRYID;
+ // lRemoveArgs[1].Value will be changed during next loop ...
+
+ // work on a copied list only ...
+ // Reason: We will get notifications from the core for every
+ // changed or removed element. And that will change our m_lURLs list.
+ // That's not a good idea, if we use a stl iterator inbetween .-)
+ TURLList lURLs = m_lURLs;
+ for (const TURLInfo& rInfo : lURLs)
+ {
+ plRemoveArgs[1].Value <<= rInfo.ID;
+ m_xRealCore->dispatch(aRemoveURL, lRemoveArgs);
+ }
+}
+
+
+void RecoveryCore::forgetBrokenRecoveryEntries()
+{
+ if (!m_xRealCore.is())
+ return;
+
+ css::util::URL aRemoveURL = impl_getParsedURL(RECOVERY_CMD_DO_ENTRY_CLEANUP);
+ css::uno::Sequence< css::beans::PropertyValue > lRemoveArgs(2);
+ auto plRemoveArgs = lRemoveArgs.getArray();
+ plRemoveArgs[0].Name = PROP_DISPATCHASYNCHRON;
+ plRemoveArgs[0].Value <<= false;
+ plRemoveArgs[1].Name = PROP_ENTRYID;
+ // lRemoveArgs[1].Value will be changed during next loop ...
+
+ // work on a copied list only ...
+ // Reason: We will get notifications from the core for every
+ // changed or removed element. And that will change our m_lURLs list.
+ // That's not a good idea, if we use a stl iterator inbetween .-)
+ TURLList lURLs = m_lURLs;
+ for (const TURLInfo& rInfo : lURLs)
+ {
+ if (!RecoveryCore::isBrokenTempEntry(rInfo))
+ continue;
+
+ plRemoveArgs[1].Value <<= rInfo.ID;
+ m_xRealCore->dispatch(aRemoveURL, lRemoveArgs);
+ }
+}
+
+
+void RecoveryCore::setProgressHandler(const css::uno::Reference< css::task::XStatusIndicator >& xProgress)
+{
+ m_xProgress = xProgress;
+}
+
+
+void RecoveryCore::setUpdateListener(IRecoveryUpdateListener* pListener)
+{
+ m_pListener = pListener;
+}
+
+
+void RecoveryCore::doEmergencySavePrepare()
+{
+ if (!m_xRealCore.is())
+ return;
+
+ css::util::URL aURL = impl_getParsedURL(RECOVERY_CMD_DO_PREPARE_EMERGENCY_SAVE);
+
+ css::uno::Sequence< css::beans::PropertyValue > lArgs{ comphelper::makePropertyValue(
+ PROP_DISPATCHASYNCHRON, false) };
+
+ m_xRealCore->dispatch(aURL, lArgs);
+}
+
+
+void RecoveryCore::doEmergencySave()
+{
+ if (!m_xRealCore.is())
+ return;
+
+ css::util::URL aURL = impl_getParsedURL(RECOVERY_CMD_DO_EMERGENCY_SAVE);
+
+ css::uno::Sequence< css::beans::PropertyValue > lArgs{
+ comphelper::makePropertyValue(PROP_STATUSINDICATOR, m_xProgress),
+ comphelper::makePropertyValue(PROP_DISPATCHASYNCHRON, true)
+ };
+
+ m_xRealCore->dispatch(aURL, lArgs);
+}
+
+
+void RecoveryCore::doRecovery()
+{
+ if (!m_xRealCore.is())
+ return;
+
+ forgetAllRecoveryEntriesMarkedForDiscard();
+
+ css::util::URL aURL = impl_getParsedURL(RECOVERY_CMD_DO_RECOVERY);
+
+ css::uno::Sequence< css::beans::PropertyValue > lArgs{
+ comphelper::makePropertyValue(PROP_STATUSINDICATOR, m_xProgress),
+ comphelper::makePropertyValue(PROP_DISPATCHASYNCHRON, true)
+ };
+
+ m_xRealCore->dispatch(aURL, lArgs);
+}
+
+
+ERecoveryState RecoveryCore::mapDocState2RecoverState(EDocStates eDocState)
+{
+ // ???
+ ERecoveryState eRecState = E_NOT_RECOVERED_YET;
+
+ /* Attention:
+ Some of the following states can occur at the
+ same time. So we have to check for the "worst case" first!
+
+ DAMAGED -> INCOMPLETE -> HANDLED
+ */
+
+ // running ...
+ if (
+ (eDocState & EDocStates::TryLoadBackup ) ||
+ (eDocState & EDocStates::TryLoadOriginal)
+ )
+ eRecState = E_RECOVERY_IS_IN_PROGRESS;
+ // red
+ else if (eDocState & EDocStates::Damaged)
+ eRecState = E_RECOVERY_FAILED;
+ // yellow
+ else if (eDocState & EDocStates::Incomplete)
+ eRecState = E_ORIGINAL_DOCUMENT_RECOVERED;
+ // green
+ else if (eDocState & EDocStates::Succeeded)
+ eRecState = E_SUCCESSFULLY_RECOVERED;
+
+ return eRecState;
+}
+
+
+void SAL_CALL RecoveryCore::statusChanged(const css::frame::FeatureStateEvent& aEvent)
+{
+ // a) special notification about start/stop async dispatch!
+ // FeatureDescriptor = "start" || "stop"
+ if (aEvent.FeatureDescriptor == RECOVERY_OPERATIONSTATE_START)
+ {
+ return;
+ }
+
+ if (aEvent.FeatureDescriptor == RECOVERY_OPERATIONSTATE_STOP)
+ {
+ if (m_pListener)
+ m_pListener->end();
+ return;
+ }
+
+ // b) normal notification about changed items
+ // FeatureDescriptor = "Update"
+ // State = List of information [seq< NamedValue >]
+ if (aEvent.FeatureDescriptor != RECOVERY_OPERATIONSTATE_UPDATE)
+ return;
+
+ ::comphelper::SequenceAsHashMap lInfo(aEvent.State);
+ TURLInfo aNew;
+
+ aNew.ID = lInfo.getUnpackedValueOrDefault(STATEPROP_ID , sal_Int32(0) );
+ aNew.DocState = static_cast<EDocStates>(lInfo.getUnpackedValueOrDefault(STATEPROP_STATE , sal_Int32(0) ));
+ aNew.OrgURL = lInfo.getUnpackedValueOrDefault(STATEPROP_ORGURL , OUString());
+ aNew.TempURL = lInfo.getUnpackedValueOrDefault(STATEPROP_TEMPURL , OUString());
+ aNew.FactoryURL = lInfo.getUnpackedValueOrDefault(STATEPROP_FACTORYURL , OUString());
+ aNew.TemplateURL = lInfo.getUnpackedValueOrDefault(STATEPROP_TEMPLATEURL, OUString());
+ aNew.DisplayName = lInfo.getUnpackedValueOrDefault(STATEPROP_TITLE , OUString());
+ aNew.Module = lInfo.getUnpackedValueOrDefault(STATEPROP_MODULE , OUString());
+
+ if (aNew.OrgURL.isEmpty()) {
+ // If there is no file URL, the window title is used for the display name.
+ // Remove any unwanted elements such as " - LibreOffice Writer".
+ sal_Int32 i = aNew.DisplayName.indexOf(" - ");
+ if (i > 0)
+ aNew.DisplayName = aNew.DisplayName.copy(0, i);
+ } else {
+ // If there is a file URL, parse out the filename part as the display name.
+ INetURLObject aOrgURL(aNew.OrgURL);
+ aNew.DisplayName = aOrgURL.getName(INetURLObject::LAST_SEGMENT, true,
+ INetURLObject::DecodeMechanism::WithCharset);
+ }
+
+ // search for already existing items and update her nState value ...
+ for (TURLInfo& aOld : m_lURLs)
+ {
+ if (aOld.ID == aNew.ID)
+ {
+ // change existing
+ aOld.DocState = aNew.DocState;
+ aOld.RecoveryState = RecoveryCore::mapDocState2RecoverState(aOld.DocState);
+ if (m_pListener)
+ {
+ m_pListener->updateItems();
+ m_pListener->stepNext(&aOld);
+ }
+ return;
+ }
+ }
+
+ // append as new one
+ // TODO think about matching Module name to a corresponding icon
+ OUString sURL = aNew.OrgURL;
+ if (sURL.isEmpty())
+ sURL = aNew.FactoryURL;
+ if (sURL.isEmpty())
+ sURL = aNew.TempURL;
+ if (sURL.isEmpty())
+ sURL = aNew.TemplateURL;
+ INetURLObject aURL(sURL);
+ aNew.StandardImageId = SvFileInformationManager::GetFileImageId(aURL);
+
+ /* set the right UI state for this item to NOT_RECOVERED_YET... because nDocState shows the state of
+ the last emergency save operation before and is interesting for the used recovery core service only...
+ for now! But if there is a further notification for this item (see lines above!) we must
+ map the doc state to an UI state. */
+ aNew.RecoveryState = E_NOT_RECOVERED_YET;
+
+ m_lURLs.push_back(aNew);
+
+ if (m_pListener)
+ m_pListener->updateItems();
+}
+
+
+void SAL_CALL RecoveryCore::disposing(const css::lang::EventObject& /*aEvent*/)
+{
+ m_xRealCore.clear();
+}
+
+
+void RecoveryCore::impl_startListening()
+{
+ // listening already initialized ?
+ if (m_xRealCore.is())
+ return;
+ m_xRealCore = css::frame::theAutoRecovery::get(m_xContext);
+
+ css::util::URL aURL;
+ if (m_bListenForSaving)
+ aURL.Complete = RECOVERY_CMD_DO_EMERGENCY_SAVE;
+ else
+ aURL.Complete = RECOVERY_CMD_DO_RECOVERY;
+ css::uno::Reference< css::util::XURLTransformer > xParser(css::util::URLTransformer::create(m_xContext));
+ xParser->parseStrict(aURL);
+
+ /* Note: addStatusListener() call us synchronous back ... so we
+ will get the complete list of currently open documents! */
+ m_xRealCore->addStatusListener(static_cast< css::frame::XStatusListener* >(this), aURL);
+}
+
+
+void RecoveryCore::impl_stopListening()
+{
+ // Ignore it, if this instance doesn't listen currently
+ if (!m_xRealCore.is())
+ return;
+
+ css::util::URL aURL;
+ if (m_bListenForSaving)
+ aURL.Complete = RECOVERY_CMD_DO_EMERGENCY_SAVE;
+ else
+ aURL.Complete = RECOVERY_CMD_DO_RECOVERY;
+ css::uno::Reference< css::util::XURLTransformer > xParser(css::util::URLTransformer::create(m_xContext));
+ xParser->parseStrict(aURL);
+
+ m_xRealCore->removeStatusListener(static_cast< css::frame::XStatusListener* >(this), aURL);
+ m_xRealCore.clear();
+}
+
+
+css::util::URL RecoveryCore::impl_getParsedURL(const OUString& sURL)
+{
+ css::util::URL aURL;
+ aURL.Complete = sURL;
+
+ css::uno::Reference< css::util::XURLTransformer > xParser(css::util::URLTransformer::create(m_xContext));
+ xParser->parseStrict(aURL);
+
+ return aURL;
+}
+
+PluginProgress::PluginProgress(weld::ProgressBar* pProgressBar)
+ : m_pProgressBar(pProgressBar)
+ , m_nRange(100)
+{
+}
+
+PluginProgress::~PluginProgress()
+{
+}
+
+void SAL_CALL PluginProgress::dispose()
+{
+ m_pProgressBar = nullptr;
+}
+
+void SAL_CALL PluginProgress::addEventListener(const css::uno::Reference< css::lang::XEventListener >& )
+{
+}
+
+void SAL_CALL PluginProgress::removeEventListener( const css::uno::Reference< css::lang::XEventListener >& )
+{
+}
+
+void SAL_CALL PluginProgress::start(const OUString&, sal_Int32 nRange)
+{
+ m_nRange = nRange;
+ if (m_pProgressBar)
+ m_pProgressBar->set_percentage(0);
+}
+
+void SAL_CALL PluginProgress::end()
+{
+ if (m_pProgressBar)
+ m_pProgressBar->set_percentage(m_nRange);
+}
+
+void SAL_CALL PluginProgress::setText(const OUString& rText)
+{
+ if (m_pProgressBar)
+ m_pProgressBar->set_text(rText);
+}
+
+void SAL_CALL PluginProgress::setValue(sal_Int32 nValue)
+{
+ if (m_pProgressBar)
+ m_pProgressBar->set_percentage((nValue * 100) / m_nRange);
+}
+
+void SAL_CALL PluginProgress::reset()
+{
+ if (m_pProgressBar)
+ m_pProgressBar->set_percentage(0);
+}
+
+SaveDialog::SaveDialog(weld::Window* pParent, RecoveryCore* pCore)
+ : GenericDialogController(pParent, "svx/ui/docrecoverysavedialog.ui", "DocRecoverySaveDialog")
+ , m_pCore(pCore)
+ , m_xFileListLB(m_xBuilder->weld_tree_view("filelist"))
+ , m_xOkBtn(m_xBuilder->weld_button("ok"))
+{
+ m_xFileListLB->set_size_request(-1, m_xFileListLB->get_height_rows(10));
+
+ // Prepare the office for the following crash save step.
+ // E.g. hide all open windows so the user can't influence our
+ // operation .-)
+ m_pCore->doEmergencySavePrepare();
+
+ m_xOkBtn->connect_clicked(LINK(this, SaveDialog, OKButtonHdl));
+
+ // fill listbox with current open documents
+
+ TURLList& rURLs = m_pCore->getURLListAccess();
+
+ for (const TURLInfo& rInfo : rURLs)
+ {
+ m_xFileListLB->append("", rInfo.DisplayName, rInfo.StandardImageId);
+ }
+}
+
+SaveDialog::~SaveDialog()
+{
+}
+
+IMPL_LINK_NOARG(SaveDialog, OKButtonHdl, weld::Button&, void)
+{
+ // start crash-save with progress
+ std::unique_ptr<SaveProgressDialog> xProgress(new SaveProgressDialog(m_xDialog.get(), m_pCore));
+ short nResult = xProgress->run();
+ xProgress.reset();
+
+ // if "CANCEL" => return "CANCEL"
+ // if "OK" => request a restart always!
+ if (nResult == DLG_RET_OK)
+ nResult = DLG_RET_OK_AUTOLAUNCH;
+
+ m_xDialog->response(nResult);
+}
+
+SaveProgressDialog::SaveProgressDialog(weld::Window* pParent, RecoveryCore* pCore)
+ : GenericDialogController(pParent, "svx/ui/docrecoveryprogressdialog.ui", "DocRecoveryProgressDialog")
+ , m_pCore(pCore)
+ , m_xProgressBar(m_xBuilder->weld_progress_bar("progress"))
+{
+ m_xProgressBar->set_size_request(m_xProgressBar->get_approximate_digit_width() * 50, -1);
+ m_xProgress = new PluginProgress(m_xProgressBar.get());
+}
+
+SaveProgressDialog::~SaveProgressDialog()
+{
+ css::uno::Reference<css::lang::XComponent> xComp(m_xProgress, css::uno::UNO_QUERY);
+ if (xComp)
+ xComp->dispose();
+}
+
+short SaveProgressDialog::run()
+{
+ ::SolarMutexGuard aLock;
+
+ m_pCore->setProgressHandler(m_xProgress);
+ m_pCore->setUpdateListener(this);
+ m_pCore->doEmergencySave();
+ short nRet = DialogController::run();
+ m_pCore->setUpdateListener(nullptr);
+ return nRet;
+}
+
+void SaveProgressDialog::updateItems()
+{
+}
+
+void SaveProgressDialog::stepNext(TURLInfo* )
+{
+ /* TODO
+
+ if m_pCore would have a member m_mCurrentItem, you could see,
+ who is current, who is next ... You can show this information
+ in progress report FixText
+ */
+}
+
+void SaveProgressDialog::end()
+{
+ m_xDialog->response(DLG_RET_OK);
+}
+
+static short impl_askUserForWizardCancel(weld::Widget* pParent, TranslateId pRes)
+{
+ std::unique_ptr<weld::MessageDialog> xQuery(Application::CreateMessageDialog(pParent,
+ VclMessageType::Question, VclButtonsType::YesNo, SvxResId(pRes)));
+ if (xQuery->run() == RET_YES)
+ return DLG_RET_OK;
+ else
+ return DLG_RET_CANCEL;
+}
+
+RecoveryDialog::RecoveryDialog(weld::Window* pParent, RecoveryCore* pCore)
+ : GenericDialogController(pParent, "svx/ui/docrecoveryrecoverdialog.ui", "DocRecoveryRecoverDialog")
+ , m_aTitleRecoveryInProgress(SvxResId(RID_SVXSTR_RECOVERY_INPROGRESS))
+ , m_aRecoveryOnlyFinish (SvxResId(RID_SVXSTR_RECOVERYONLY_FINISH))
+ , m_aRecoveryOnlyFinishDescr(SvxResId(RID_SVXSTR_RECOVERYONLY_FINISH_DESCR))
+ , m_pCore(pCore)
+ , m_eRecoveryState(RecoveryDialog::E_RECOVERY_PREPARED)
+ , m_bWaitForCore(false)
+ , m_bWasRecoveryStarted(false)
+// , m_aColumnOffset(0)
+ , m_aToggleCount(0)
+ , m_aSuccessRecovStr(SvxResId(RID_SVXSTR_SUCCESSRECOV))
+ , m_aOrigDocRecovStr(SvxResId(RID_SVXSTR_ORIGDOCRECOV))
+ , m_aRecovFailedStr(SvxResId(RID_SVXSTR_RECOVFAILED))
+ , m_aRecovInProgrStr(SvxResId(RID_SVXSTR_RECOVINPROGR))
+ , m_aNotRecovYetStr(SvxResId(RID_SVXSTR_NOTRECOVYET))
+ , m_aWillBeDiscStr(SvxResId(RID_SVXSTR_WILLDISCARD))
+ , m_xDescrFT(m_xBuilder->weld_label("desc"))
+ , m_xProgressBar(m_xBuilder->weld_progress_bar("progress"))
+ , m_xFileListLB(m_xBuilder->weld_tree_view("filelist"))
+ , m_xNextBtn(m_xBuilder->weld_button("next"))
+ , m_xCancelBtn(m_xBuilder->weld_button("cancel"))
+{
+ const auto nWidth = m_xFileListLB->get_approximate_digit_width() * 80;
+ m_xFileListLB->set_size_request(nWidth, m_xFileListLB->get_height_rows(10));
+ m_xProgressBar->set_size_request(m_xProgressBar->get_approximate_digit_width() * 50, -1);
+ m_xProgress = new PluginProgress(m_xProgressBar.get());
+
+ std::vector<int> aWidths;
+ aWidths.push_back(60 * nWidth / 100);
+ aWidths.push_back(5 * nWidth / 100);
+ m_xFileListLB->set_column_fixed_widths(aWidths);
+ m_xFileListLB->enable_toggle_buttons(weld::ColumnToggleType::Check);
+ m_xFileListLB->connect_toggled( LINK(this, RecoveryDialog, ToggleRowHdl) );
+
+ m_xNextBtn->set_sensitive(true);
+ m_xNextBtn->connect_clicked( LINK( this, RecoveryDialog, NextButtonHdl ) );
+ m_xCancelBtn->connect_clicked( LINK( this, RecoveryDialog, CancelButtonHdl ) );
+
+ // fill list box first time
+ TURLList& rURLList = m_pCore->getURLListAccess();
+ for (size_t i = 0, nCount = rURLList.size(); i < nCount; ++i)
+ {
+ const TURLInfo& rInfo = rURLList[i];
+ m_xFileListLB->append();
+ m_xFileListLB->set_toggle(i, TRISTATE_TRUE);
+ m_xFileListLB->set_id(i, weld::toId(&rInfo));
+ m_xFileListLB->set_image(i, rInfo.StandardImageId, COLUMN_STANDARDIMAGE);
+ m_xFileListLB->set_text(i, rInfo.DisplayName, COLUMN_DISPLAYNAME);
+ m_xFileListLB->set_image(i, impl_getStatusImage(rInfo), COLUMN_STATUSIMAGE);
+ m_xFileListLB->set_text(i, impl_getStatusString(rInfo), COLUMN_STATUSTEXT);
+ m_aToggleCount++;
+ }
+
+ // mark first item
+ if (m_xFileListLB->n_children())
+ m_xFileListLB->set_cursor(0);
+}
+
+RecoveryDialog::~RecoveryDialog()
+{
+ css::uno::Reference<css::lang::XComponent> xComp(m_xProgress, css::uno::UNO_QUERY);
+ if (xComp)
+ xComp->dispose();
+}
+
+bool RecoveryDialog::allSuccessfullyRecovered()
+{
+ const int c = m_xFileListLB->n_children();
+ for (int i = 0; i < c; ++i)
+ {
+ TURLInfo* pInfo = weld::fromId<TURLInfo*>(m_xFileListLB->get_id(i));
+ if (!pInfo)
+ continue;
+
+ if (pInfo->RecoveryState != E_SUCCESSFULLY_RECOVERED)
+ return false;
+ }
+ return true;
+}
+
+short RecoveryDialog::execute()
+{
+ ::SolarMutexGuard aSolarLock;
+
+ switch (m_eRecoveryState)
+ {
+ case RecoveryDialog::E_RECOVERY_IN_PROGRESS :
+ {
+ // user decided to start recovery ...
+ m_bWasRecoveryStarted = true;
+ // do it asynchronous (to allow repaints)
+ // and wait for this asynchronous operation.
+ m_xDescrFT->set_label( m_aTitleRecoveryInProgress );
+ m_xNextBtn->set_sensitive(false);
+ m_xCancelBtn->set_sensitive(false);
+ m_pCore->setProgressHandler(m_xProgress);
+ m_pCore->setUpdateListener(this);
+ m_pCore->doRecovery();
+
+ m_bWaitForCore = true;
+ while(m_bWaitForCore && !Application::IsQuit())
+ Application::Yield();
+
+ m_pCore->setUpdateListener(nullptr);
+
+ // Skip FINISH button if everything was successfully recovered
+ if (allSuccessfullyRecovered())
+ m_eRecoveryState = RecoveryDialog::E_RECOVERY_DONE;
+ else
+ m_eRecoveryState = RecoveryDialog::E_RECOVERY_CORE_DONE;
+ return execute();
+ }
+
+ case RecoveryDialog::E_RECOVERY_CORE_DONE :
+ {
+ // the core finished it's task.
+ // let the user decide the next step.
+ m_xDescrFT->set_label(m_aRecoveryOnlyFinishDescr);
+ m_xNextBtn->set_label(m_aRecoveryOnlyFinish);
+ m_xNextBtn->set_sensitive(true);
+ m_xCancelBtn->set_sensitive(false);
+ return 0;
+ }
+
+ case RecoveryDialog::E_RECOVERY_DONE :
+ {
+ // All documents were recovered.
+ // User decided to step to the "next" wizard page.
+ // Do it ... but check first, if there exist some
+ // failed recovery documents. They must be saved to
+ // a user selected directory.
+ short nRet = DLG_RET_UNKNOWN;
+ BrokenRecoveryDialog aBrokenRecoveryDialog(m_xDialog.get(), m_pCore, !m_bWasRecoveryStarted);
+ OUString sSaveDir = aBrokenRecoveryDialog.getSaveDirURL(); // get the default dir
+ if (aBrokenRecoveryDialog.isExecutionNeeded())
+ {
+ nRet = aBrokenRecoveryDialog.run();
+ sSaveDir = aBrokenRecoveryDialog.getSaveDirURL();
+ }
+
+ switch(nRet)
+ {
+ // no broken temp files exists
+ // step to the next wizard page
+ case DLG_RET_UNKNOWN :
+ {
+ m_eRecoveryState = RecoveryDialog::E_RECOVERY_HANDLED;
+ return DLG_RET_OK;
+ }
+
+ // user decided to save the broken temp files
+ // do and forget it
+ // step to the next wizard page
+ case DLG_RET_OK :
+ {
+ m_pCore->saveBrokenTempEntries(sSaveDir);
+ m_pCore->forgetBrokenTempEntries();
+ m_eRecoveryState = RecoveryDialog::E_RECOVERY_HANDLED;
+ return DLG_RET_OK;
+ }
+
+ // user decided to ignore broken temp files.
+ // Ask it again ... may be this decision was wrong.
+ // Results:
+ // IGNORE => remove broken temp files
+ // => step to the next wizard page
+ // CANCEL => step back to the recovery page
+ case DLG_RET_CANCEL :
+ {
+ // TODO ask user ...
+ m_pCore->forgetBrokenTempEntries();
+ m_eRecoveryState = RecoveryDialog::E_RECOVERY_HANDLED;
+ return DLG_RET_OK;
+ }
+ }
+
+ m_eRecoveryState = RecoveryDialog::E_RECOVERY_HANDLED;
+ return DLG_RET_OK;
+ }
+
+ case RecoveryDialog::E_RECOVERY_CANCELED :
+ {
+ // "YES" => break recovery
+ // But there exist different states, where "cancel" can be called.
+ // Handle it different.
+ if (m_bWasRecoveryStarted)
+ m_eRecoveryState = RecoveryDialog::E_RECOVERY_CANCELED_AFTERWARDS;
+ else
+ m_eRecoveryState = RecoveryDialog::E_RECOVERY_CANCELED_BEFORE;
+ return execute();
+ }
+
+ case RecoveryDialog::E_RECOVERY_CANCELED_BEFORE :
+ case RecoveryDialog::E_RECOVERY_CANCELED_AFTERWARDS :
+ {
+ // We have to check if there exists some temp. files.
+ // They should be saved to a user defined location.
+ // If no temp files exists or user decided to ignore it ...
+ // we have to remove all recovery/session data anyway!
+ short nRet = DLG_RET_UNKNOWN;
+ BrokenRecoveryDialog aBrokenRecoveryDialog(m_xDialog.get(), m_pCore, !m_bWasRecoveryStarted);
+ OUString sSaveDir = aBrokenRecoveryDialog.getSaveDirURL(); // get the default save location
+
+ // dialog itself checks if there is a need to copy files for this mode.
+ // It uses the information m_bWasRecoveryStarted doing so.
+ if (aBrokenRecoveryDialog.isExecutionNeeded())
+ {
+ nRet = aBrokenRecoveryDialog.run();
+ sSaveDir = aBrokenRecoveryDialog.getSaveDirURL();
+ }
+
+ // Possible states:
+ // a) nRet == DLG_RET_UNKNOWN
+ // dialog was not shown ...
+ // because there exists no temp file for copy.
+ // => remove all recovery data
+ // b) nRet == DLG_RET_OK
+ // dialog was shown ...
+ // user decided to save temp files
+ // => save all OR broken temp files (depends from the time, where cancel was called)
+ // => remove all recovery data
+ // c) nRet == DLG_RET_CANCEL
+ // dialog was shown ...
+ // user decided to ignore temp files
+ // => remove all recovery data
+ // => a)/c) are the same ... b) has one additional operation
+
+ // b)
+ if (nRet == DLG_RET_OK)
+ {
+ if (m_bWasRecoveryStarted)
+ m_pCore->saveBrokenTempEntries(sSaveDir);
+ else
+ m_pCore->saveAllTempEntries(sSaveDir);
+ }
+
+ // a,b,c)
+ if (m_bWasRecoveryStarted)
+ m_pCore->forgetBrokenRecoveryEntries();
+ else
+ m_pCore->forgetAllRecoveryEntries();
+ m_eRecoveryState = RecoveryDialog::E_RECOVERY_HANDLED;
+
+ // THERE IS NO WAY BACK. see impl_askUserForWizardCancel()!
+ return DLG_RET_CANCEL;
+ }
+ }
+
+ // should never be reached .-)
+ OSL_FAIL("Should never be reached!");
+ return DLG_RET_OK;
+}
+
+void RecoveryDialog::updateItems()
+{
+ int c = m_xFileListLB->n_children();
+ for (int i = 0; i < c; ++i)
+ {
+ TURLInfo* pInfo = weld::fromId<TURLInfo*>(m_xFileListLB->get_id(i));
+ if ( !pInfo )
+ continue;
+
+ m_xFileListLB->set_image(i, impl_getStatusImage(*pInfo), COLUMN_STATUSIMAGE);
+ OUString sStatus = impl_getStatusString( *pInfo );
+ if (!sStatus.isEmpty())
+ m_xFileListLB->set_text(i, sStatus, COLUMN_STATUSTEXT);
+ }
+}
+
+void RecoveryDialog::stepNext(TURLInfo* pItem)
+{
+ int c = m_xFileListLB->n_children();
+ for (int i=0; i < c; ++i)
+ {
+ TURLInfo* pInfo = weld::fromId<TURLInfo*>(m_xFileListLB->get_id(i));
+ if (pInfo->ID != pItem->ID)
+ continue;
+
+ m_xFileListLB->set_cursor(i);
+ m_xFileListLB->scroll_to_row(i);
+ break;
+ }
+}
+
+void RecoveryDialog::end()
+{
+ m_bWaitForCore = false;
+}
+
+IMPL_LINK_NOARG(RecoveryDialog, NextButtonHdl, weld::Button&, void)
+{
+ switch (m_eRecoveryState)
+ {
+ case RecoveryDialog::E_RECOVERY_PREPARED:
+ m_eRecoveryState = RecoveryDialog::E_RECOVERY_IN_PROGRESS;
+ execute();
+ break;
+ case RecoveryDialog::E_RECOVERY_CORE_DONE:
+ m_eRecoveryState = RecoveryDialog::E_RECOVERY_DONE;
+ execute();
+ break;
+ }
+
+ if (m_eRecoveryState == RecoveryDialog::E_RECOVERY_HANDLED)
+ {
+ m_xDialog->response(DLG_RET_OK);
+ }
+}
+
+IMPL_LINK_NOARG(RecoveryDialog, CancelButtonHdl, weld::Button&, void)
+{
+ switch (m_eRecoveryState)
+ {
+ case RecoveryDialog::E_RECOVERY_PREPARED:
+ if (impl_askUserForWizardCancel(m_xDialog.get(), RID_SVXSTR_QUERY_EXIT_RECOVERY) != DLG_RET_CANCEL)
+ {
+ m_eRecoveryState = RecoveryDialog::E_RECOVERY_CANCELED;
+ execute();
+ }
+ break;
+ case RecoveryDialog::E_RECOVERY_CORE_DONE:
+ m_eRecoveryState = RecoveryDialog::E_RECOVERY_CANCELED;
+ execute();
+ break;
+ }
+
+ if (m_eRecoveryState == RecoveryDialog::E_RECOVERY_HANDLED)
+ {
+ m_xDialog->response(RET_CANCEL);
+ }
+}
+
+IMPL_LINK_NOARG(RecoveryDialog, ToggleRowHdl, const weld::TreeView::iter_col&, void)
+{
+ int aIndex = m_xFileListLB->get_selected_index();
+ TriState eState = m_xFileListLB->get_toggle(aIndex);
+
+ if (m_bWasRecoveryStarted)
+ {
+ switch (eState)
+ {
+ case TRISTATE_FALSE:
+ eState = TRISTATE_TRUE;
+ break;
+ case TRISTATE_TRUE:
+ eState = TRISTATE_FALSE;
+ break;
+ default:
+ // should never happen
+ assert(false);
+ break;
+ }
+
+ // revert toggle
+ m_xFileListLB->set_toggle(aIndex, eState);
+ }
+ else
+ {
+ impl_updateItemDescription(aIndex, eState);
+
+ switch (eState)
+ {
+ case TRISTATE_FALSE:
+ m_aToggleCount--;
+ break;
+ case TRISTATE_TRUE:
+ m_aToggleCount++;
+ break;
+ default:
+ // should never happen
+ assert(false);
+ break;
+ }
+
+ m_xNextBtn->set_sensitive(m_aToggleCount != 0);
+ }
+}
+
+OUString RecoveryDialog::impl_getStatusString( const TURLInfo& rInfo ) const
+{
+ OUString sStatus;
+ switch ( rInfo.RecoveryState )
+ {
+ case E_SUCCESSFULLY_RECOVERED :
+ sStatus = m_aSuccessRecovStr;
+ break;
+ case E_ORIGINAL_DOCUMENT_RECOVERED :
+ sStatus = m_aOrigDocRecovStr;
+ break;
+ case E_RECOVERY_FAILED :
+ sStatus = m_aRecovFailedStr;
+ break;
+ case E_RECOVERY_IS_IN_PROGRESS :
+ sStatus = m_aRecovInProgrStr;
+ break;
+ case E_NOT_RECOVERED_YET :
+ sStatus = m_aNotRecovYetStr;
+ break;
+ case E_WILL_BE_DISCARDED:
+ sStatus = m_aWillBeDiscStr;
+ break;
+ default:
+ break;
+ }
+ return sStatus;
+}
+
+OUString RecoveryDialog::impl_getStatusImage( const TURLInfo& rInfo )
+{
+ OUString sStatus;
+ switch ( rInfo.RecoveryState )
+ {
+ case E_SUCCESSFULLY_RECOVERED :
+ sStatus = RID_SVXBMP_GREENCHECK;
+ break;
+ case E_ORIGINAL_DOCUMENT_RECOVERED :
+ sStatus = RID_SVXBMP_YELLOWCHECK;
+ break;
+ case E_RECOVERY_FAILED :
+ sStatus = RID_SVXBMP_REDCROSS;
+ break;
+ default:
+ break;
+ }
+ return sStatus;
+}
+
+void RecoveryDialog::impl_updateItemDescription(int row, const TriState& rState)
+{
+ TURLInfo* pInfo = reinterpret_cast<TURLInfo*>(m_xFileListLB->get_id(row).toInt64());
+ if (!pInfo)
+ return;
+
+ switch (rState)
+ {
+ case TRISTATE_FALSE:
+ pInfo->RecoveryState = ERecoveryState::E_WILL_BE_DISCARDED;
+ pInfo->ShouldDiscard = true;
+ break;
+ case TRISTATE_TRUE:
+ pInfo->RecoveryState = ERecoveryState::E_NOT_RECOVERED_YET;
+ pInfo->ShouldDiscard = false;
+ break;
+ default:
+ // should never happen
+ assert(false);
+ break;
+ }
+
+ OUString sStatus = impl_getStatusString(*pInfo);
+ if (!sStatus.isEmpty())
+ m_xFileListLB->set_text(row, sStatus, COLUMN_STATUSTEXT);
+}
+
+BrokenRecoveryDialog::BrokenRecoveryDialog(weld::Window* pParent,
+ RecoveryCore* pCore,
+ bool bBeforeRecovery)
+ : GenericDialogController(pParent, "svx/ui/docrecoverybrokendialog.ui", "DocRecoveryBrokenDialog")
+ , m_pCore(pCore)
+ , m_bBeforeRecovery(bBeforeRecovery)
+ , m_bExecutionNeeded(false)
+ , m_xFileListLB(m_xBuilder->weld_tree_view("filelist"))
+ , m_xSaveDirED(m_xBuilder->weld_entry("savedir"))
+ , m_xSaveDirBtn(m_xBuilder->weld_button("change"))
+ , m_xOkBtn(m_xBuilder->weld_button("ok"))
+ , m_xCancelBtn(m_xBuilder->weld_button("cancel"))
+{
+ m_xSaveDirBtn->connect_clicked( LINK( this, BrokenRecoveryDialog, SaveButtonHdl ) );
+ m_xOkBtn->connect_clicked( LINK( this, BrokenRecoveryDialog, OkButtonHdl ) );
+ m_xCancelBtn->connect_clicked( LINK( this, BrokenRecoveryDialog, CancelButtonHdl ) );
+
+ m_sSavePath = SvtPathOptions().GetWorkPath();
+ INetURLObject aObj( m_sSavePath );
+ OUString sPath;
+ osl::FileBase::getSystemPathFromFileURL(aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), sPath);
+ m_xSaveDirED->set_text(sPath);
+
+ impl_refresh();
+}
+
+BrokenRecoveryDialog::~BrokenRecoveryDialog()
+{
+}
+
+void BrokenRecoveryDialog::impl_refresh()
+{
+ m_bExecutionNeeded = false;
+ TURLList& rURLList = m_pCore->getURLListAccess();
+ for (const TURLInfo& rInfo : rURLList)
+ {
+ if (m_bBeforeRecovery)
+ {
+ // "Cancel" before recovery ->
+ // search for any temp files!
+ if (rInfo.TempURL.isEmpty())
+ continue;
+ }
+ else
+ {
+ // "Cancel" after recovery ->
+ // search for broken temp files
+ if (!RecoveryCore::isBrokenTempEntry(rInfo))
+ continue;
+ }
+
+ m_bExecutionNeeded = true;
+
+ m_xFileListLB->append(weld::toId(&rInfo), rInfo.DisplayName, rInfo.StandardImageId);
+ }
+ m_sSavePath.clear();
+ m_xOkBtn->grab_focus();
+}
+
+bool BrokenRecoveryDialog::isExecutionNeeded() const
+{
+ return m_bExecutionNeeded;
+}
+
+const OUString& BrokenRecoveryDialog::getSaveDirURL() const
+{
+ return m_sSavePath;
+}
+
+IMPL_LINK_NOARG(BrokenRecoveryDialog, OkButtonHdl, weld::Button&, void)
+{
+ OUString sPhysicalPath = comphelper::string::strip(m_xSaveDirED->get_text(), ' ');
+ OUString sURL;
+ osl::FileBase::getFileURLFromSystemPath( sPhysicalPath, sURL );
+ m_sSavePath = sURL;
+ while (m_sSavePath.isEmpty())
+ impl_askForSavePath();
+
+ m_xDialog->response(DLG_RET_OK);
+}
+
+IMPL_LINK_NOARG(BrokenRecoveryDialog, CancelButtonHdl, weld::Button&, void)
+{
+ m_xDialog->response(RET_CANCEL);
+}
+
+IMPL_LINK_NOARG(BrokenRecoveryDialog, SaveButtonHdl, weld::Button&, void)
+{
+ impl_askForSavePath();
+}
+
+void BrokenRecoveryDialog::impl_askForSavePath()
+{
+ css::uno::Reference< css::ui::dialogs::XFolderPicker2 > xFolderPicker =
+ sfx2::createFolderPicker(m_pCore->getComponentContext(), m_xDialog.get());
+
+ INetURLObject aURL(m_sSavePath, INetProtocol::File);
+ xFolderPicker->setDisplayDirectory(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE));
+ short nRet = xFolderPicker->execute();
+ if (nRet == css::ui::dialogs::ExecutableDialogResults::OK)
+ {
+ m_sSavePath = xFolderPicker->getDirectory();
+ OUString sPath;
+ osl::FileBase::getSystemPathFromFileURL(m_sSavePath, sPath);
+ m_xSaveDirED->set_text(sPath);
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/fntctrl.cxx b/svx/source/dialog/fntctrl.cxx
new file mode 100644
index 0000000000..69cc901719
--- /dev/null
+++ b/svx/source/dialog/fntctrl.cxx
@@ -0,0 +1,1085 @@
+/* -*- 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 <sfx2/dialoghelper.hxx>
+#include <sfx2/viewsh.hxx>
+#include <sfx2/printer.hxx>
+#include <vcl/metric.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+
+#include <com/sun/star/i18n/ScriptType.hpp>
+
+#include <vector>
+#include <deque>
+#include <optional>
+#include <svtools/colorcfg.hxx>
+#include <svtools/sampletext.hxx>
+
+#include <svx/fntctrl.hxx>
+#include <svx/svxids.hrc>
+
+// Item set includes
+#include <svl/itemset.hxx>
+#include <svl/itempool.hxx>
+#include <svl/stritem.hxx>
+#include <svl/cjkoptions.hxx>
+#include <svl/ctloptions.hxx>
+
+#include <editeng/editeng.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/editids.hrc>
+#include <editeng/postitem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/crossedoutitem.hxx>
+#include <editeng/contouritem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/shdditem.hxx>
+#include <editeng/escapementitem.hxx>
+#include <editeng/wrlmitem.hxx>
+#include <editeng/cmapitem.hxx>
+#include <editeng/kernitem.hxx>
+#include <editeng/brushitem.hxx>
+#include <editeng/emphasismarkitem.hxx>
+#include <editeng/charreliefitem.hxx>
+#include <editeng/charscaleitem.hxx>
+#include <editeng/langitem.hxx>
+
+//TODO: remove this and calculate off the actual size of text, not
+//an arbitrary number of characters
+#define TEXT_WIDTH 80
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+
+
+// small helper functions to set fonts
+
+namespace
+{
+void scaleFontWidth(vcl::Font& rFont, vcl::RenderContext const & rRenderContext,tools::Long& n100PercentFont)
+{
+ rFont.SetAverageFontWidth(0);
+ n100PercentFont = rRenderContext.GetFontMetric(rFont).GetAverageFontWidth();
+}
+
+void initFont(vcl::Font& rFont)
+{
+ rFont.SetTransparent(true);
+ rFont.SetAlignment(ALIGN_BASELINE);
+}
+
+void setFontSize(vcl::Font& rFont)
+{
+ Size aSize(rFont.GetFontSize());
+ aSize.setHeight( (aSize.Height() * 3) / 5 );
+ aSize.setWidth( (aSize.Width() * 3) / 5 );
+ rFont.SetFontSize(aSize);
+}
+
+void calcFontHeightAnyAscent(vcl::RenderContext& rRenderContext, const vcl::Font& rFont, tools::Long& nHeight, tools::Long& nAscent)
+{
+ if (!nHeight)
+ {
+ rRenderContext.SetFont(rFont);
+ FontMetric aMetric(rRenderContext.GetFontMetric());
+ nHeight = aMetric.GetLineHeight();
+ nAscent = aMetric.GetAscent();
+ }
+}
+
+void setFont(const SvxFont& rNewFont, SvxFont& rImplFont)
+{
+ rImplFont = rNewFont;
+ rImplFont.SetTransparent(true);
+ rImplFont.SetAlignment(ALIGN_BASELINE);
+}
+
+/*
+ * removes line feeds and carriage returns from string
+ * returns if param is empty
+ */
+OUString removeCRLF(const OUString& rText)
+{
+ return rText.replace(0xa, ' ').replace(0xd, ' ').trim();
+}
+
+struct ScriptInfo
+{
+ tools::Long textWidth;
+ SvtScriptType scriptType;
+ sal_Int32 changePos;
+ ScriptInfo(SvtScriptType scrptType, sal_Int32 position)
+ : textWidth(0)
+ , scriptType(scrptType)
+ , changePos(position)
+ {
+ }
+};
+
+} // end anonymous namespace
+
+class FontPrevWin_Impl
+{
+ friend class SvxFontPrevWindow;
+
+ SvxFont maFont;
+ VclPtr<Printer> mpPrinter;
+ bool mbDelPrinter;
+
+ std::vector<ScriptInfo> maScriptChanges;
+ SvxFont maCJKFont;
+ SvxFont maCTLFont;
+ OUString maText;
+ OUString maScriptText;
+ std::optional<Color> mxColor;
+ std::optional<Color> mxBackColor;
+ std::optional<Color> mxTextLineColor;
+ std::optional<Color> mxOverlineColor;
+ tools::Long mnAscent;
+ sal_Unicode mcStartBracket;
+ sal_Unicode mcEndBracket;
+
+ tools::Long mn100PercentFontWidth; // initial -1 -> not set yet
+ tools::Long mn100PercentFontWidthCJK;
+ tools::Long mn100PercentFontWidthCTL;
+ sal_uInt16 mnFontWidthScale;
+
+ bool mbSelection : 1;
+ bool mbGetSelection : 1;
+ bool mbTwoLines : 1;
+ bool mbUseFontNameAsText : 1;
+ bool mbTextInited : 1;
+
+ bool m_bCJKEnabled;
+ bool m_bCTLEnabled;
+
+
+public:
+ FontPrevWin_Impl() :
+ mpPrinter(nullptr),
+ mbDelPrinter(false),
+ mnAscent(0),
+ mcStartBracket(0),
+ mcEndBracket(0),
+ mnFontWidthScale(100),
+ mbSelection(false),
+ mbGetSelection(false),
+ mbTwoLines(false),
+ mbUseFontNameAsText(false),
+ mbTextInited(false)
+ {
+ m_bCJKEnabled = SvtCJKOptions::IsAnyEnabled();
+ m_bCTLEnabled = SvtCTLOptions::IsCTLFontEnabled();
+ mxBackColor = svtools::ColorConfig().GetColorValue(svtools::DOCCOLOR).nColor;
+ Invalidate100PercentFontWidth();
+ }
+
+ ~FontPrevWin_Impl()
+ {
+ if (mbDelPrinter)
+ mpPrinter.disposeAndClear();
+ }
+
+ void CheckScript();
+ Size CalcTextSize(vcl::RenderContext& rRenderContext, OutputDevice const * pPrinter, const SvxFont& rFont);
+ void DrawPrev(vcl::RenderContext& rRenderContext, Printer* pPrinter, Point& rPt, const SvxFont& rFont);
+
+ bool SetFontWidthScale(sal_uInt16 nScaleInPercent);
+ inline void Invalidate100PercentFontWidth();
+ inline bool Is100PercentFontWidthValid() const;
+ void ScaleFontWidth(vcl::RenderContext const & rRenderContext);
+ // scales rNonCJKFont and aCJKFont depending on nFontWidthScale and
+ // sets the 100%-Font-Widths
+};
+
+inline void FontPrevWin_Impl::Invalidate100PercentFontWidth()
+{
+ mn100PercentFontWidth = mn100PercentFontWidthCJK = mn100PercentFontWidthCTL = -1;
+}
+
+inline bool FontPrevWin_Impl::Is100PercentFontWidthValid() const
+{
+ DBG_ASSERT( ( mn100PercentFontWidth == -1 && mn100PercentFontWidthCJK == -1 ) ||
+ ( mn100PercentFontWidth != -1 && mn100PercentFontWidthCJK != -1 ) ||
+ ( mn100PercentFontWidth == -1 && mn100PercentFontWidthCTL == -1 ) ||
+ ( mn100PercentFontWidth != -1 && mn100PercentFontWidthCTL != -1 ),
+ "*FontPrevWin_Impl::Is100PercentFontWidthValid(): 100PercentFontWidth's not synchronous" );
+ return mn100PercentFontWidth != -1;
+}
+
+/*
+ * evaluates the scripttypes of the actual string.
+ * Afterwards the positions of script change are notified in aScriptChg,
+ * the scripttypes in aScriptType.
+ * The aTextWidth array will be filled with zero.
+ */
+void FontPrevWin_Impl::CheckScript()
+{
+ assert(!maText.isEmpty()); // must have a preview text here!
+ if (maText == maScriptText)
+ {
+ return; // already initialized
+ }
+
+ maScriptText = maText;
+ maScriptChanges.clear();
+
+ auto aEditEngine = EditEngine(nullptr);
+ aEditEngine.SetText(maScriptText);
+
+ auto aScript = aEditEngine.GetScriptType({ 0, 0, 0, 0 });
+ for (sal_Int32 i = 1; i <= maScriptText.getLength(); i++)
+ {
+ auto aNextScript = aEditEngine.GetScriptType({ 0, i, 0, i });
+ if (aNextScript != aScript)
+ maScriptChanges.emplace_back(aScript, i - 1);
+ if (i == maScriptText.getLength())
+ maScriptChanges.emplace_back(aScript, i);
+ aScript = aNextScript;
+ }
+}
+
+/*
+ * Size FontPrevWin_Impl::CalcTextSize(..)
+ * fills the aTextWidth array with the text width of every part
+ * of the actual string without a script change inside.
+ * For Latin parts the given rFont will be used,
+ * for Asian parts the aCJKFont.
+ * The returned size contains the whole string.
+ * The member nAscent is calculated to the maximal ascent of all used fonts.
+ */
+
+Size FontPrevWin_Impl::CalcTextSize(vcl::RenderContext& rRenderContext, OutputDevice const * _pPrinter, const SvxFont& rInFont)
+{
+ SvtScriptType aScript;
+ sal_uInt16 nIdx = 0;
+ sal_Int32 nStart = 0;
+ sal_Int32 nEnd;
+ size_t nCnt = maScriptChanges.size();
+
+ if (nCnt)
+ {
+ nEnd = maScriptChanges[nIdx].changePos;
+ aScript = maScriptChanges[nIdx].scriptType;
+ }
+ else
+ {
+ nEnd = maText.getLength();
+ aScript = SvtScriptType::LATIN;
+ }
+ tools::Long nTxtWidth = 0;
+ tools::Long nCJKHeight = 0;
+ tools::Long nCTLHeight = 0;
+ tools::Long nHeight = 0;
+ mnAscent = 0;
+ tools::Long nCJKAscent = 0;
+ tools::Long nCTLAscent = 0;
+
+ do
+ {
+ const SvxFont& rFont = (aScript == SvtScriptType::ASIAN) ?
+ maCJKFont :
+ ((aScript == SvtScriptType::COMPLEX) ?
+ maCTLFont :
+ rInFont);
+ tools::Long nWidth = rFont.GetTextSize(*_pPrinter, maText, nStart, nEnd - nStart).Width();
+ if (nIdx >= maScriptChanges.size())
+ break;
+
+ maScriptChanges[nIdx++].textWidth = nWidth;
+ nTxtWidth += nWidth;
+
+ switch (aScript)
+ {
+ case SvtScriptType::ASIAN:
+ calcFontHeightAnyAscent(rRenderContext, maCJKFont, nCJKHeight, nCJKAscent);
+ break;
+ case SvtScriptType::COMPLEX:
+ calcFontHeightAnyAscent(rRenderContext, maCTLFont, nCTLHeight, nCTLAscent);
+ break;
+ default:
+ calcFontHeightAnyAscent(rRenderContext, rFont, nHeight, mnAscent);
+ }
+
+ if (nEnd < maText.getLength() && nIdx < nCnt)
+ {
+ nStart = nEnd;
+ nEnd = maScriptChanges[nIdx].changePos;
+ aScript = maScriptChanges[nIdx].scriptType;
+ }
+ else
+ break;
+ }
+ while(true);
+
+ nHeight -= mnAscent;
+ nCJKHeight -= nCJKAscent;
+ nCTLHeight -= nCTLAscent;
+
+ if (nHeight < nCJKHeight)
+ nHeight = nCJKHeight;
+
+ if (mnAscent < nCJKAscent)
+ mnAscent = nCJKAscent;
+
+ if (nHeight < nCTLHeight)
+ nHeight = nCTLHeight;
+
+ if (mnAscent < nCTLAscent)
+ mnAscent = nCTLAscent;
+
+ nHeight += mnAscent;
+
+ Size aTxtSize(nTxtWidth, nHeight);
+ return aTxtSize;
+}
+
+/*
+ * void FontPrevWin_Impl::DrawPrev(..)
+ * calls SvxFont::DrawPrev(..) for every part of the string without a script
+ * change inside, for Asian parts the aCJKFont will be used, otherwise the
+ * given rFont.
+ */
+
+void FontPrevWin_Impl::DrawPrev(vcl::RenderContext& rRenderContext, Printer* _pPrinter, Point &rPt, const SvxFont& rInFont)
+{
+ vcl::Font aOldFont = _pPrinter->GetFont();
+ SvtScriptType aScript;
+ sal_uInt16 nIdx = 0;
+ sal_Int32 nStart = 0;
+ sal_Int32 nEnd;
+ size_t nCnt = maScriptChanges.size();
+
+ if (nCnt)
+ {
+ nEnd = maScriptChanges[nIdx].changePos;
+ aScript = maScriptChanges[nIdx].scriptType;
+ }
+ else
+ {
+ nEnd = maText.getLength();
+ aScript = SvtScriptType::LATIN;
+ }
+ do
+ {
+ const SvxFont& rFont = (aScript == SvtScriptType::ASIAN)
+ ? maCJKFont
+ : ((aScript == SvtScriptType::COMPLEX)
+ ? maCTLFont
+ : rInFont);
+ _pPrinter->SetFont(rFont);
+
+ rFont.DrawPrev(&rRenderContext, _pPrinter, rPt, maText, nStart, nEnd - nStart);
+
+ rPt.AdjustX(maScriptChanges[nIdx++].textWidth);
+ if (nEnd < maText.getLength() && nIdx < nCnt)
+ {
+ nStart = nEnd;
+ nEnd = maScriptChanges[nIdx].changePos;
+ aScript = maScriptChanges[nIdx].scriptType;
+ }
+ else
+ break;
+ }
+ while(true);
+ _pPrinter->SetFont(aOldFont);
+}
+
+
+bool FontPrevWin_Impl::SetFontWidthScale(sal_uInt16 nScale)
+{
+ if (mnFontWidthScale != nScale)
+ {
+ mnFontWidthScale = nScale;
+ return true;
+ }
+
+ return false;
+}
+
+void FontPrevWin_Impl::ScaleFontWidth(vcl::RenderContext const & rOutDev)
+{
+ if (!Is100PercentFontWidthValid())
+ {
+ scaleFontWidth(maFont, rOutDev, mn100PercentFontWidth);
+ scaleFontWidth(maCJKFont, rOutDev, mn100PercentFontWidthCJK);
+ scaleFontWidth(maCTLFont, rOutDev, mn100PercentFontWidthCTL);
+ }
+
+ maFont.SetAverageFontWidth(mn100PercentFontWidth * mnFontWidthScale / 100);
+ maCJKFont.SetAverageFontWidth(mn100PercentFontWidthCJK * mnFontWidthScale / 100);
+ maCTLFont.SetAverageFontWidth(mn100PercentFontWidthCTL * mnFontWidthScale / 100);
+}
+
+static bool GetWhich (const SfxItemSet& rSet, sal_uInt16 nSlot, sal_uInt16& rWhich)
+{
+ rWhich = rSet.GetPool()->GetWhich(nSlot);
+ return rSet.GetItemState(rWhich) >= SfxItemState::DEFAULT;
+}
+
+static void SetPrevFont(const SfxItemSet& rSet, sal_uInt16 nSlot, SvxFont& rFont)
+{
+ sal_uInt16 nWhich;
+ if (GetWhich(rSet, nSlot, nWhich))
+ {
+ const SvxFontItem& rFontItem = static_cast<const SvxFontItem&>(rSet.Get(nWhich));
+ rFont.SetFamily(rFontItem.GetFamily());
+ rFont.SetFamilyName(rFontItem.GetFamilyName());
+ rFont.SetPitch(rFontItem.GetPitch());
+ rFont.SetCharSet(rFontItem.GetCharSet());
+ rFont.SetStyleName(rFontItem.GetStyleName());
+ }
+}
+
+static void SetPrevFontStyle( const SfxItemSet& rSet, sal_uInt16 nPosture, sal_uInt16 nWeight, SvxFont& rFont )
+{
+ sal_uInt16 nWhich;
+ if( GetWhich( rSet, nPosture, nWhich ) )
+ {
+ const SvxPostureItem& rItem = static_cast<const SvxPostureItem&>( rSet.Get( nWhich ) );
+ rFont.SetItalic( rItem.GetValue() != ITALIC_NONE ? ITALIC_NORMAL : ITALIC_NONE );
+ }
+
+ if( GetWhich( rSet, nWeight, nWhich ) )
+ {
+ const SvxWeightItem& rItem = static_cast<const SvxWeightItem&>( rSet.Get( nWhich ) );
+ rFont.SetWeight( rItem.GetValue() != WEIGHT_NORMAL ? WEIGHT_BOLD : WEIGHT_NORMAL );
+ }
+}
+
+static void SetPrevFontEscapement(SvxFont& rFont, sal_uInt8 nProp, sal_uInt8 nEscProp, short nEsc)
+{
+ rFont.SetPropr(nProp);
+ rFont.SetProprRel(nEscProp);
+ rFont.SetEscapement(nEsc);
+}
+
+void SvxFontPrevWindow::ApplySettings(vcl::RenderContext& rRenderContext)
+{
+ Color aBgColor = svtools::ColorConfig().GetColorValue(svtools::DOCCOLOR).nColor;
+ Color aFgColor = svtools::ColorConfig().GetColorValue(svtools::FONTCOLOR, false).nColor;
+ if (aFgColor == COL_AUTO)
+ aFgColor = aBgColor.IsDark() ? COL_WHITE : COL_BLACK;
+ rRenderContext.SetBackground(aBgColor);
+ rRenderContext.SetTextColor(aFgColor);
+}
+
+void SvxFontPrevWindow::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ CustomWidgetController::SetDrawingArea(pDrawingArea);
+ Size aPrefSize(getPreviewStripSize(pDrawingArea->get_ref_device()));
+ pDrawingArea->set_size_request(aPrefSize.Width(), aPrefSize.Height());
+
+ pImpl.reset(new FontPrevWin_Impl);
+ SfxViewShell* pSh = SfxViewShell::Current();
+
+ if (pSh)
+ pImpl->mpPrinter = pSh->GetPrinter();
+
+ if (!pImpl->mpPrinter)
+ {
+ pImpl->mpPrinter = VclPtr<Printer>::Create();
+ pImpl->mbDelPrinter = true;
+ }
+ initFont(pImpl->maFont);
+ initFont(pImpl->maCJKFont);
+ initFont(pImpl->maCTLFont);
+
+ Invalidate();
+}
+
+SvxFontPrevWindow::SvxFontPrevWindow()
+{
+}
+
+SvxFontPrevWindow::~SvxFontPrevWindow()
+{
+}
+
+SvxFont& SvxFontPrevWindow::GetCTLFont()
+{
+ return pImpl->maCTLFont;
+}
+
+SvxFont& SvxFontPrevWindow::GetCJKFont()
+{
+ return pImpl->maCJKFont;
+}
+
+SvxFont& SvxFontPrevWindow::GetFont()
+{
+ pImpl->Invalidate100PercentFontWidth(); // because the user might change the size
+ return pImpl->maFont;
+}
+
+const SvxFont& SvxFontPrevWindow::GetFont() const
+{
+ return pImpl->maFont;
+}
+
+void SvxFontPrevWindow::SetPreviewText( const OUString& rString )
+{
+ pImpl->maText = rString;
+ pImpl->mbTextInited = true;
+}
+
+void SvxFontPrevWindow::SetFontNameAsPreviewText()
+{
+ pImpl->mbUseFontNameAsText = true;
+}
+
+void SvxFontPrevWindow::SetFont( const SvxFont& rNormalOutFont, const SvxFont& rCJKOutFont, const SvxFont& rCTLFont )
+{
+ setFont(rNormalOutFont, pImpl->maFont);
+ setFont(rCJKOutFont, pImpl->maCJKFont);
+ setFont(rCTLFont, pImpl->maCTLFont);
+
+ pImpl->Invalidate100PercentFontWidth();
+ Invalidate();
+}
+
+void SvxFontPrevWindow::SetColor(const Color &rColor)
+{
+ pImpl->mxColor = rColor;
+ Invalidate();
+}
+
+void SvxFontPrevWindow::ResetColor()
+{
+ pImpl->mxColor.reset();
+ Invalidate();
+}
+
+void SvxFontPrevWindow::SetTextLineColor(const Color &rColor)
+{
+ pImpl->mxTextLineColor = rColor;
+ Invalidate();
+}
+
+void SvxFontPrevWindow::SetOverlineColor(const Color &rColor)
+{
+ pImpl->mxOverlineColor = rColor;
+ Invalidate();
+}
+
+void SvxFontPrevWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ rRenderContext.Push(vcl::PushFlags::ALL);
+ rRenderContext.SetMapMode(MapMode(MapUnit::MapTwip));
+
+ ApplySettings(rRenderContext);
+ rRenderContext.Erase();
+
+ Printer* pPrinter = pImpl->mpPrinter;
+ const SvxFont& rFont = pImpl->maFont;
+ const SvxFont& rCJKFont = pImpl->maCJKFont;
+ const SvxFont& rCTLFont = pImpl->maCTLFont;
+
+ if (!IsEnabled())
+ {
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ const Size aLogSize(rRenderContext.GetOutputSize());
+
+ tools::Rectangle aRect(Point(0, 0), aLogSize);
+ rRenderContext.SetLineColor();
+ rRenderContext.SetFillColor(rStyleSettings.GetWindowColor());
+ rRenderContext.DrawRect(aRect);
+ }
+ else
+ {
+ if (!pImpl->mbSelection && !pImpl->mbTextInited)
+ {
+ using namespace css::i18n::ScriptType;
+
+ SfxViewShell* pSh = SfxViewShell::Current();
+
+ if (pSh && !pImpl->mbGetSelection && !pImpl->mbUseFontNameAsText)
+ {
+ pImpl->maText = removeCRLF(pSh->GetSelectionText(/*bCompleteWords*/false, /*bOnlyASample*/true));
+ pImpl->mbGetSelection = true;
+ pImpl->mbSelection = !(pImpl->maText.isEmpty());
+ }
+
+ if (!pImpl->mbSelection || pImpl->mbUseFontNameAsText)
+ {
+ //If we're showing multiple sample texts, then they're all
+ //sample texts. If only showing Latin, continue to use
+ //the fontname as the preview
+ if ((pImpl->m_bCJKEnabled) || (pImpl->m_bCTLEnabled))
+ pImpl->maText = makeRepresentativeTextForFont(LATIN, rFont);
+ else
+ pImpl->maText = rFont.GetFamilyName();
+
+ if (pImpl->m_bCJKEnabled)
+ {
+ if (!pImpl->maText.isEmpty())
+ pImpl->maText += " ";
+ pImpl->maText += makeRepresentativeTextForFont(ASIAN, rCJKFont);
+
+ }
+ if (pImpl->m_bCTLEnabled)
+ {
+ if (!pImpl->maText.isEmpty())
+ pImpl->maText += " ";
+ pImpl->maText += makeRepresentativeTextForFont(COMPLEX, rCTLFont);
+ }
+ }
+
+ if (pImpl->maText.isEmpty())
+ { // fdo#58427: still no text? let's try that one...
+ pImpl->maText = makeRepresentativeTextForFont(LATIN, rFont);
+ }
+
+ pImpl->maText = removeCRLF(pImpl->maText);
+
+ if (pImpl->maText.getLength() > (TEXT_WIDTH - 1))
+ {
+ const sal_Int32 nSpaceIdx = pImpl->maText.indexOf(" ", TEXT_WIDTH);
+ if (nSpaceIdx != -1)
+ pImpl->maText = pImpl->maText.copy(0, nSpaceIdx);
+ else
+ pImpl->maText = pImpl->maText.copy(0, (TEXT_WIDTH - 1));
+ }
+ }
+
+ // calculate text width scaling
+ pImpl->ScaleFontWidth(rRenderContext);
+
+ pImpl->CheckScript();
+ Size aTxtSize = pImpl->CalcTextSize(rRenderContext, pPrinter, rFont);
+
+ const Size aLogSize(rRenderContext.GetOutputSize());
+
+ tools::Long nX = aLogSize.Width() / 2 - aTxtSize.Width() / 2;
+ tools::Long nY = aLogSize.Height() / 2 - aTxtSize.Height() / 2;
+
+ if (nY + pImpl->mnAscent > aLogSize.Height())
+ nY = aLogSize.Height() - pImpl->mnAscent;
+
+ if (pImpl->mxBackColor)
+ {
+ tools::Rectangle aRect(Point(0, 0), aLogSize);
+ Color aLineCol = rRenderContext.GetLineColor();
+ Color aFillCol = rRenderContext.GetFillColor();
+ rRenderContext.SetLineColor();
+ rRenderContext.SetFillColor(*pImpl->mxBackColor);
+ rRenderContext.DrawRect(aRect);
+ rRenderContext.SetLineColor(aLineCol);
+ rRenderContext.SetFillColor(aFillCol);
+ }
+ if (pImpl->mxColor)
+ {
+ tools::Rectangle aRect(Point(nX, nY), aTxtSize);
+ Color aLineCol = rRenderContext.GetLineColor();
+ Color aFillCol = rRenderContext.GetFillColor();
+ rRenderContext.SetLineColor();
+ rRenderContext.SetFillColor(*pImpl->mxColor);
+ rRenderContext.DrawRect(aRect);
+ rRenderContext.SetLineColor(aLineCol);
+ rRenderContext.SetFillColor(aFillCol);
+ }
+
+ if (pImpl->mxTextLineColor)
+ {
+ rRenderContext.SetTextLineColor(*pImpl->mxTextLineColor);
+ }
+
+ if (pImpl->mxOverlineColor)
+ {
+ rRenderContext.SetOverlineColor(*pImpl->mxOverlineColor);
+ }
+
+ tools::Long nStdAscent = pImpl->mnAscent;
+ nY += nStdAscent;
+
+ if (IsTwoLines())
+ {
+ SvxFont aSmallFont(rFont);
+ Size aOldSize = pImpl->maCJKFont.GetFontSize();
+ setFontSize(aSmallFont);
+ setFontSize(pImpl->maCJKFont);
+
+ tools::Long nStartBracketWidth = 0;
+ tools::Long nEndBracketWidth = 0;
+ tools::Long nTextWidth = 0;
+ if (pImpl->mcStartBracket)
+ {
+ OUString sBracket(pImpl->mcStartBracket);
+ nStartBracketWidth = rFont.GetTextSize(*pPrinter, sBracket).Width();
+ }
+ if (pImpl->mcEndBracket)
+ {
+ OUString sBracket(pImpl->mcEndBracket);
+ nEndBracketWidth = rFont.GetTextSize(*pPrinter, sBracket).Width();
+ }
+ nTextWidth = pImpl->CalcTextSize(rRenderContext, pPrinter, aSmallFont).Width();
+ tools::Long nResultWidth = nStartBracketWidth;
+ nResultWidth += nEndBracketWidth;
+ nResultWidth += nTextWidth;
+
+ tools::Long _nX = (aLogSize.Width() - nResultWidth) / 2;
+ rRenderContext.DrawLine(Point(0, nY), Point(_nX, nY));
+ rRenderContext.DrawLine(Point(_nX + nResultWidth, nY), Point(aLogSize.Width(), nY));
+
+ tools::Long nSmallAscent = pImpl->mnAscent;
+ tools::Long nOffset = (nStdAscent - nSmallAscent) / 2;
+
+ if (pImpl->mcStartBracket)
+ {
+ OUString sBracket(pImpl->mcStartBracket);
+ rFont.DrawPrev(&rRenderContext, pPrinter, Point(_nX, nY - nOffset - 4), sBracket);
+ _nX += nStartBracketWidth;
+ }
+
+ Point aTmpPoint1(_nX, nY - nSmallAscent - 2);
+ Point aTmpPoint2(_nX, nY);
+ pImpl->DrawPrev(rRenderContext, pPrinter, aTmpPoint1, aSmallFont);
+ pImpl->DrawPrev(rRenderContext, pPrinter, aTmpPoint2, aSmallFont);
+
+ _nX += nTextWidth;
+ if (pImpl->mcEndBracket)
+ {
+ Point aTmpPoint( _nX + 1, nY - nOffset - 4);
+ OUString sBracket(pImpl->mcEndBracket);
+ rFont.DrawPrev(&rRenderContext, pPrinter, aTmpPoint, sBracket);
+ }
+ pImpl->maCJKFont.SetFontSize(aOldSize);
+ }
+ else
+ {
+
+ Color aLineCol = rRenderContext.GetLineColor();
+
+ rRenderContext.SetLineColor(rFont.GetColor());
+ rRenderContext.DrawLine(Point(0, nY), Point(nX, nY));
+ rRenderContext.DrawLine(Point(nX + aTxtSize.Width(), nY), Point(aLogSize.Width(), nY));
+ rRenderContext.SetLineColor(aLineCol);
+
+ Point aTmpPoint(nX, nY);
+ pImpl->DrawPrev(rRenderContext, pPrinter, aTmpPoint, rFont);
+ }
+ }
+ rRenderContext.Pop();
+}
+
+bool SvxFontPrevWindow::IsTwoLines() const
+{
+ return pImpl->mbTwoLines;
+}
+
+void SvxFontPrevWindow::SetTwoLines(bool bSet)
+{
+ pImpl->mbTwoLines = bSet;
+}
+
+void SvxFontPrevWindow::SetBrackets(sal_Unicode cStart, sal_Unicode cEnd)
+{
+ pImpl->mcStartBracket = cStart;
+ pImpl->mcEndBracket = cEnd;
+}
+
+void SvxFontPrevWindow::SetFontWidthScale( sal_uInt16 n )
+{
+ if (pImpl->SetFontWidthScale(n))
+ Invalidate();
+}
+
+void SvxFontPrevWindow::AutoCorrectFontColor()
+{
+ Color aColor(COL_AUTO);
+ if ( pImpl->mxBackColor ) aColor = *pImpl->mxBackColor;
+ const bool bIsDark(aColor.IsDark());
+
+ aColor = pImpl->maFont.GetColor();
+ if (aColor == COL_AUTO)
+ pImpl->maFont.SetColor( bIsDark ? COL_WHITE : COL_BLACK );
+ aColor = pImpl->maCJKFont.GetColor();
+ if (aColor == COL_AUTO)
+ pImpl->maCJKFont.SetColor( bIsDark ? COL_WHITE : COL_BLACK );
+ aColor = pImpl->maCTLFont.GetColor();
+ if (aColor == COL_AUTO)
+ pImpl->maCTLFont.SetColor( bIsDark ? COL_WHITE : COL_BLACK );
+}
+
+void SvxFontPrevWindow::SetFontSize( const SfxItemSet& rSet, sal_uInt16 nSlot, SvxFont& rFont )
+{
+ sal_uInt16 nWhich;
+ tools::Long nH;
+ if (GetWhich(rSet, nSlot, nWhich))
+ {
+ nH = OutputDevice::LogicToLogic(static_cast<const SvxFontHeightItem&>(rSet.Get(nWhich)).GetHeight(),
+ rSet.GetPool()->GetMetric(nWhich),
+ MapUnit::MapTwip);
+ }
+ else
+ nH = 240;// as default 12pt
+
+ rFont.SetFontSize(Size(0, nH));
+}
+
+void SvxFontPrevWindow::SetFontLang(const SfxItemSet& rSet, sal_uInt16 nSlot, SvxFont& rFont)
+{
+ sal_uInt16 nWhich;
+ LanguageType nLang;
+ if( GetWhich( rSet, nSlot, nWhich ) )
+ nLang = static_cast<const SvxLanguageItem&>(rSet.Get(nWhich)).GetLanguage();
+ else
+ nLang = LANGUAGE_NONE;
+ rFont.SetLanguage(nLang);
+}
+
+void SvxFontPrevWindow::SetFromItemSet(const SfxItemSet &rSet, bool bPreviewBackgroundToCharacter)
+{
+ sal_uInt16 nWhich;
+ SvxFont& rFont = GetFont();
+ SvxFont& rCJKFont = GetCJKFont();
+ SvxFont& rCTLFont = GetCTLFont();
+
+ // Preview string
+ if( GetWhich( rSet, SID_CHAR_DLG_PREVIEW_STRING, nWhich ) )
+ {
+ const SfxStringItem& rItem = static_cast<const SfxStringItem&>( rSet.Get( nWhich ) );
+ const OUString& aString = rItem.GetValue();
+ if( !aString.isEmpty() )
+ SetPreviewText( aString );
+ else
+ SetFontNameAsPreviewText();
+ }
+
+ // Underline
+ FontLineStyle eUnderline;
+ if( GetWhich( rSet, SID_ATTR_CHAR_UNDERLINE, nWhich ) )
+ {
+ const SvxUnderlineItem& rItem = static_cast<const SvxUnderlineItem&>( rSet.Get( nWhich ) );
+ eUnderline = rItem.GetValue();
+ }
+ else
+ eUnderline = LINESTYLE_NONE;
+
+ rFont.SetUnderline( eUnderline );
+ rCJKFont.SetUnderline( eUnderline );
+ rCTLFont.SetUnderline( eUnderline );
+
+ // Overline
+ FontLineStyle eOverline;
+ if( GetWhich( rSet, SID_ATTR_CHAR_OVERLINE, nWhich ) )
+ {
+ const SvxOverlineItem& rItem = static_cast<const SvxOverlineItem&>( rSet.Get( nWhich ) );
+ eOverline = rItem.GetValue();
+ }
+ else
+ eOverline = LINESTYLE_NONE;
+
+ rFont.SetOverline( eOverline );
+ rCJKFont.SetOverline( eOverline );
+ rCTLFont.SetOverline( eOverline );
+
+ // Strikeout
+ FontStrikeout eStrikeout;
+ if( GetWhich( rSet, SID_ATTR_CHAR_STRIKEOUT, nWhich ) )
+ {
+ const SvxCrossedOutItem& rItem = static_cast<const SvxCrossedOutItem&>( rSet.Get( nWhich ) );
+ eStrikeout = rItem.GetValue();
+ }
+ else
+ eStrikeout = STRIKEOUT_NONE;
+
+ rFont.SetStrikeout( eStrikeout );
+ rCJKFont.SetStrikeout( eStrikeout );
+ rCTLFont.SetStrikeout( eStrikeout );
+
+ // WordLineMode
+ if( GetWhich( rSet, SID_ATTR_CHAR_WORDLINEMODE, nWhich ) )
+ {
+ const SvxWordLineModeItem& rItem = static_cast<const SvxWordLineModeItem&>( rSet.Get( nWhich ) );
+ rFont.SetWordLineMode( rItem.GetValue() );
+ rCJKFont.SetWordLineMode( rItem.GetValue() );
+ rCTLFont.SetWordLineMode( rItem.GetValue() );
+ }
+
+ // Emphasis
+ if( GetWhich( rSet, SID_ATTR_CHAR_EMPHASISMARK, nWhich ) )
+ {
+ const SvxEmphasisMarkItem& rItem = static_cast<const SvxEmphasisMarkItem&>( rSet.Get( nWhich ) );
+ FontEmphasisMark eMark = rItem.GetEmphasisMark();
+ rFont.SetEmphasisMark( eMark );
+ rCJKFont.SetEmphasisMark( eMark );
+ rCTLFont.SetEmphasisMark( eMark );
+ }
+
+ // Relief
+ if( GetWhich( rSet, SID_ATTR_CHAR_RELIEF, nWhich ) )
+ {
+ const SvxCharReliefItem& rItem = static_cast<const SvxCharReliefItem&>( rSet.Get( nWhich ) );
+ FontRelief eFontRelief = rItem.GetValue();
+ rFont.SetRelief( eFontRelief );
+ rCJKFont.SetRelief( eFontRelief );
+ rCTLFont.SetRelief( eFontRelief );
+ }
+
+ // Effects
+ if( GetWhich( rSet, SID_ATTR_CHAR_CASEMAP, nWhich ) )
+ {
+ const SvxCaseMapItem& rItem = static_cast<const SvxCaseMapItem&>( rSet.Get( nWhich ) );
+ SvxCaseMap eCaseMap = rItem.GetValue();
+ rFont.SetCaseMap( eCaseMap );
+ rCJKFont.SetCaseMap( eCaseMap );
+ // #i78474# small caps do not exist in CTL fonts
+ rCTLFont.SetCaseMap( eCaseMap == SvxCaseMap::SmallCaps ? SvxCaseMap::NotMapped : eCaseMap );
+ }
+
+ // Outline
+ if( GetWhich( rSet, SID_ATTR_CHAR_CONTOUR, nWhich ) )
+ {
+ const SvxContourItem& rItem = static_cast<const SvxContourItem&>( rSet.Get( nWhich ) );
+ bool bOutline = rItem.GetValue();
+ rFont.SetOutline( bOutline );
+ rCJKFont.SetOutline( bOutline );
+ rCTLFont.SetOutline( bOutline );
+ }
+
+ // Shadow
+ if( GetWhich( rSet, SID_ATTR_CHAR_SHADOWED, nWhich ) )
+ {
+ const SvxShadowedItem& rItem = static_cast<const SvxShadowedItem&>( rSet.Get( nWhich ) );
+ bool bShadow = rItem.GetValue();
+ rFont.SetShadow( bShadow );
+ rCJKFont.SetShadow( bShadow );
+ rCTLFont.SetShadow( bShadow );
+ }
+
+ // Background
+ bool bTransparent;
+ if( GetWhich( rSet, bPreviewBackgroundToCharacter ? SID_ATTR_BRUSH : SID_ATTR_BRUSH_CHAR, nWhich ) )
+ {
+ const SvxBrushItem& rBrush = static_cast<const SvxBrushItem&>( rSet.Get( nWhich ) );
+ const Color& rColor = rBrush.GetColor();
+ bTransparent = rColor.IsTransparent();
+ rFont.SetFillColor( rColor );
+ rCJKFont.SetFillColor( rColor );
+ rCTLFont.SetFillColor( rColor );
+ }
+ else
+ bTransparent = true;
+
+ rFont.SetTransparent( bTransparent );
+ rCJKFont.SetTransparent( bTransparent );
+ rCTLFont.SetTransparent( bTransparent );
+
+ if( !bPreviewBackgroundToCharacter )
+ {
+ bool bBackColorFound = false;
+ if( GetWhich( rSet, SID_ATTR_BRUSH, nWhich ) )
+ {
+ const SvxBrushItem& rBrush = static_cast<const SvxBrushItem&>( rSet.Get( nWhich ) );
+ if (GPOS_NONE == rBrush.GetGraphicPos())
+ {
+ const Color& rBrushColor = rBrush.GetColor();
+ if (rBrushColor != COL_TRANSPARENT)
+ {
+ pImpl->mxBackColor = rBrush.GetColor();
+ bBackColorFound = true;
+ }
+ }
+ }
+ if (!bBackColorFound)
+ pImpl->mxBackColor = svtools::ColorConfig().GetColorValue(svtools::DOCCOLOR).nColor;
+ }
+
+ // Font
+ SetPrevFont( rSet, SID_ATTR_CHAR_FONT, rFont );
+ SetPrevFont( rSet, SID_ATTR_CHAR_CJK_FONT, rCJKFont );
+ SetPrevFont( rSet, SID_ATTR_CHAR_CTL_FONT, rCTLFont );
+
+ // Style
+ SetPrevFontStyle( rSet, SID_ATTR_CHAR_POSTURE, SID_ATTR_CHAR_WEIGHT, rFont );
+ SetPrevFontStyle( rSet, SID_ATTR_CHAR_CJK_POSTURE, SID_ATTR_CHAR_CJK_WEIGHT, rCJKFont );
+ SetPrevFontStyle( rSet, SID_ATTR_CHAR_CTL_POSTURE, SID_ATTR_CHAR_CTL_WEIGHT, rCTLFont );
+
+ // Size
+ SetFontSize( rSet, SID_ATTR_CHAR_FONTHEIGHT, rFont );
+ SetFontSize( rSet, SID_ATTR_CHAR_CJK_FONTHEIGHT, rCJKFont );
+ SetFontSize( rSet, SID_ATTR_CHAR_CTL_FONTHEIGHT, rCTLFont );
+
+ // Language
+ SetFontLang( rSet, SID_ATTR_CHAR_LANGUAGE, rFont );
+ SetFontLang( rSet, SID_ATTR_CHAR_CJK_LANGUAGE, rCJKFont );
+ SetFontLang( rSet, SID_ATTR_CHAR_CTL_LANGUAGE, rCTLFont );
+
+ // Color
+ if( GetWhich( rSet, SID_ATTR_CHAR_COLOR, nWhich ) )
+ {
+ const SvxColorItem& rItem = static_cast<const SvxColorItem&>( rSet.Get( nWhich ) );
+ Color aCol( rItem.GetValue() );
+ rFont.SetColor( aCol );
+
+ rCJKFont.SetColor( aCol );
+ rCTLFont.SetColor( aCol );
+
+ AutoCorrectFontColor(); // handle color COL_AUTO
+ }
+
+ // Kerning
+ if( GetWhich( rSet, SID_ATTR_CHAR_KERNING, nWhich ) )
+ {
+ const SvxKerningItem& rItem = static_cast<const SvxKerningItem&>( rSet.Get( nWhich ) );
+ short nKern = static_cast<short>(OutputDevice::LogicToLogic(rItem.GetValue(), rSet.GetPool()->GetMetric(nWhich), MapUnit::MapTwip));
+ rFont.SetFixKerning( nKern );
+ rCJKFont.SetFixKerning( nKern );
+ rCTLFont.SetFixKerning( nKern );
+ }
+
+ // Escapement
+ const sal_uInt8 nProp = 100;
+ short nEsc;
+ sal_uInt8 nEscProp;
+ if( GetWhich( rSet, SID_ATTR_CHAR_ESCAPEMENT, nWhich ) )
+ {
+ const SvxEscapementItem& rItem = static_cast<const SvxEscapementItem&>( rSet.Get( nWhich ) );
+ nEsc = rItem.GetEsc();
+ nEscProp = rItem.GetProportionalHeight();
+
+ if( nEsc == DFLT_ESC_AUTO_SUPER )
+ nEsc = DFLT_ESC_SUPER;
+ else if( nEsc == DFLT_ESC_AUTO_SUB )
+ nEsc = DFLT_ESC_SUB;
+ }
+ else
+ {
+ nEsc = 0;
+ nEscProp = 100;
+ }
+ SetPrevFontEscapement( rFont, nProp, nEscProp, nEsc );
+ SetPrevFontEscapement( rCJKFont, nProp, nEscProp, nEsc );
+ SetPrevFontEscapement( rCTLFont, nProp, nEscProp, nEsc );
+
+ // Font width scale
+ if( GetWhich( rSet, SID_ATTR_CHAR_SCALEWIDTH, nWhich ) )
+ {
+ const SvxCharScaleWidthItem&rItem = static_cast<const SvxCharScaleWidthItem&>( rSet.Get( nWhich ) );
+ SetFontWidthScale( rItem.GetValue() );
+ }
+
+ Invalidate();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/fontwork.cxx b/svx/source/dialog/fontwork.cxx
new file mode 100644
index 0000000000..5f9b681b02
--- /dev/null
+++ b/svx/source/dialog/fontwork.cxx
@@ -0,0 +1,795 @@
+/* -*- 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 <sfx2/module.hxx>
+#include <sfx2/dispatch.hxx>
+
+#include <svx/colorbox.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+#include <svx/xftadit.hxx>
+#include <svx/xftdiit.hxx>
+#include <svx/xftstit.hxx>
+#include <svx/xftmrit.hxx>
+#include <svx/xftouit.hxx>
+#include <svx/xftshit.hxx>
+#include <svx/xftshcit.hxx>
+#include <svx/xftshxy.hxx>
+#include <svx/xtextit0.hxx>
+
+#include <svtools/unitconv.hxx>
+#include <svx/svxids.hrc>
+#include <bitmaps.hlst>
+#include <svx/fontwork.hxx>
+#include <svl/itemset.hxx>
+
+#define WIDTH_CHARS 10
+
+SFX_IMPL_DOCKINGWINDOW_WITHID( SvxFontWorkChildWindow, SID_FONTWORK );
+
+// ControllerItem for Fontwork
+
+SvxFontWorkControllerItem::SvxFontWorkControllerItem
+(
+ sal_uInt16 _nId,
+ SvxFontWorkDialog& rDlg,
+ SfxBindings& rBindings
+) :
+
+ SfxControllerItem( _nId, rBindings ),
+
+ rFontWorkDlg( rDlg )
+{
+}
+
+// StateChanged method for FontWork items
+
+void SvxFontWorkControllerItem::StateChangedAtToolBoxControl( sal_uInt16 /*nSID*/, SfxItemState /*eState*/,
+ const SfxPoolItem* pItem )
+{
+ switch ( GetId() )
+ {
+ case SID_FORMTEXT_STYLE:
+ {
+ const XFormTextStyleItem* pStateItem =
+ dynamic_cast<const XFormTextStyleItem*>( pItem );
+ DBG_ASSERT(pStateItem || pItem == nullptr, "XFormTextStyleItem expected");
+ rFontWorkDlg.SetStyle_Impl(pStateItem);
+ break;
+ }
+ case SID_FORMTEXT_ADJUST:
+ {
+ const XFormTextAdjustItem* pStateItem =
+ dynamic_cast<const XFormTextAdjustItem*>( pItem );
+ DBG_ASSERT(pStateItem || pItem == nullptr, "XFormTextAdjustItem expected");
+ rFontWorkDlg.SetAdjust_Impl(pStateItem);
+ break;
+ }
+ case SID_FORMTEXT_DISTANCE:
+ {
+ const XFormTextDistanceItem* pStateItem =
+ dynamic_cast<const XFormTextDistanceItem*>( pItem );
+ DBG_ASSERT(pStateItem || pItem == nullptr, "XFormTextDistanceItem expected");
+ rFontWorkDlg.SetDistance_Impl(pStateItem);
+ break;
+ }
+ case SID_FORMTEXT_START:
+ {
+ const XFormTextStartItem* pStateItem =
+ dynamic_cast<const XFormTextStartItem*>( pItem );
+ DBG_ASSERT(pStateItem || pItem == nullptr, "XFormTextStartItem expected");
+ rFontWorkDlg.SetStart_Impl(pStateItem);
+ break;
+ }
+ case SID_FORMTEXT_MIRROR:
+ {
+ const XFormTextMirrorItem* pStateItem =
+ dynamic_cast<const XFormTextMirrorItem*>( pItem );
+ DBG_ASSERT(pStateItem || pItem == nullptr, "XFormTextMirrorItem expected");
+ rFontWorkDlg.SetMirror_Impl(pStateItem);
+ break;
+ }
+ case SID_FORMTEXT_HIDEFORM:
+ {
+ const XFormTextHideFormItem* pStateItem =
+ dynamic_cast<const XFormTextHideFormItem*>( pItem );
+ DBG_ASSERT(pStateItem || pItem == nullptr, "XFormTextHideFormItem expected");
+ rFontWorkDlg.SetShowForm_Impl(pStateItem);
+ break;
+ }
+ case SID_FORMTEXT_OUTLINE:
+ {
+ const XFormTextOutlineItem* pStateItem =
+ dynamic_cast<const XFormTextOutlineItem*>( pItem );
+ DBG_ASSERT(pStateItem || pItem == nullptr, "XFormTextOutlineItem expected");
+ rFontWorkDlg.SetOutline_Impl(pStateItem);
+ break;
+ }
+ case SID_FORMTEXT_SHADOW:
+ {
+ const XFormTextShadowItem* pStateItem =
+ dynamic_cast<const XFormTextShadowItem*>( pItem );
+ DBG_ASSERT(pStateItem || pItem == nullptr, "XFormTextShadowItem expected");
+ rFontWorkDlg.SetShadow_Impl(pStateItem);
+ break;
+ }
+ case SID_FORMTEXT_SHDWCOLOR:
+ {
+ const XFormTextShadowColorItem* pStateItem =
+ dynamic_cast<const XFormTextShadowColorItem*>( pItem );
+ DBG_ASSERT(pStateItem || pItem == nullptr, "XFormTextShadowColorItem expected");
+ rFontWorkDlg.SetShadowColor_Impl(pStateItem);
+ break;
+ }
+ case SID_FORMTEXT_SHDWXVAL:
+ {
+ const XFormTextShadowXValItem* pStateItem =
+ dynamic_cast<const XFormTextShadowXValItem*>( pItem );
+ DBG_ASSERT(pStateItem || pItem == nullptr, "XFormTextShadowXValItem expected");
+ rFontWorkDlg.SetShadowXVal_Impl(pStateItem);
+ break;
+ }
+ case SID_FORMTEXT_SHDWYVAL:
+ {
+ const XFormTextShadowYValItem* pStateItem =
+ dynamic_cast<const XFormTextShadowYValItem*>( pItem );
+ DBG_ASSERT(pStateItem || pItem == nullptr, "XFormTextShadowYValItem expected");
+ rFontWorkDlg.SetShadowYVal_Impl(pStateItem);
+ break;
+ }
+ }
+}
+
+// Derivation from SfxChildWindow as "containers" for Fontwork dialog
+
+SvxFontWorkChildWindow::SvxFontWorkChildWindow
+(
+ vcl::Window* _pParent,
+ sal_uInt16 nId,
+ SfxBindings* pBindings,
+ SfxChildWinInfo* pInfo
+) :
+ SfxChildWindow( _pParent, nId )
+{
+ VclPtrInstance<SvxFontWorkDialog> pDlg(pBindings, this, _pParent);
+ SetWindow(pDlg);
+
+ pDlg->Initialize( pInfo );
+}
+
+// Floating Window to the attribution of text effects
+SvxFontWorkDialog::SvxFontWorkDialog(SfxBindings *pBindinx,
+ SfxChildWindow *pCW,
+ vcl::Window* _pParent)
+ : SfxDockingWindow(pBindinx, pCW, _pParent, "DockingFontwork", "svx/ui/dockingfontwork.ui")
+ , rBindings(*pBindinx)
+ , aInputIdle("SvxFontWorkDialog Input")
+ , nSaveShadowX(0)
+ , nSaveShadowY(0)
+ , nSaveShadowAngle(450)
+ , nSaveShadowSize (100)
+ , m_xTbxStyle(m_xBuilder->weld_toolbar("style"))
+ , m_xTbxAdjust(m_xBuilder->weld_toolbar("adjust"))
+ , m_xMtrFldDistance(m_xBuilder->weld_metric_spin_button("distance", FieldUnit::CM))
+ , m_xMtrFldTextStart(m_xBuilder->weld_metric_spin_button("indent", FieldUnit::CM))
+ , m_xTbxShadow(m_xBuilder->weld_toolbar("shadow"))
+ , m_xFbShadowX(m_xBuilder->weld_image("shadowx"))
+ , m_xMtrFldShadowX(m_xBuilder->weld_metric_spin_button("distancex", FieldUnit::CM))
+ , m_xFbShadowY(m_xBuilder->weld_image("shadowy"))
+ , m_xMtrFldShadowY(m_xBuilder->weld_metric_spin_button("distancey", FieldUnit::CM))
+ , m_xShadowColorLB(new ColorListBox(m_xBuilder->weld_menu_button("color"), [this]{ return GetFrameWeld(); } ))
+{
+ SetText(SvxResId(RID_SVXSTR_FONTWORK));
+
+ ApplyImageList();
+
+ pCtrlItems[0] = new SvxFontWorkControllerItem(SID_FORMTEXT_STYLE, *this, rBindings);
+ pCtrlItems[1] = new SvxFontWorkControllerItem(SID_FORMTEXT_ADJUST, *this, rBindings);
+ pCtrlItems[2] = new SvxFontWorkControllerItem(SID_FORMTEXT_DISTANCE, *this, rBindings);
+ pCtrlItems[3] = new SvxFontWorkControllerItem(SID_FORMTEXT_START, *this, rBindings);
+ pCtrlItems[4] = new SvxFontWorkControllerItem(SID_FORMTEXT_MIRROR, *this, rBindings);
+ pCtrlItems[5] = new SvxFontWorkControllerItem(SID_FORMTEXT_HIDEFORM, *this, rBindings);
+ pCtrlItems[6] = new SvxFontWorkControllerItem(SID_FORMTEXT_OUTLINE, *this, rBindings);
+ pCtrlItems[7] = new SvxFontWorkControllerItem(SID_FORMTEXT_SHADOW, *this, rBindings);
+ pCtrlItems[8] = new SvxFontWorkControllerItem(SID_FORMTEXT_SHDWCOLOR, *this, rBindings);
+ pCtrlItems[9] = new SvxFontWorkControllerItem(SID_FORMTEXT_SHDWXVAL, *this, rBindings);
+ pCtrlItems[10] = new SvxFontWorkControllerItem(SID_FORMTEXT_SHDWYVAL, *this, rBindings);
+
+ m_xTbxStyle->connect_clicked(LINK(this, SvxFontWorkDialog, SelectStyleHdl_Impl));
+ m_xTbxAdjust->connect_clicked(LINK(this, SvxFontWorkDialog, SelectAdjustHdl_Impl));
+ m_xTbxShadow->connect_clicked(LINK(this, SvxFontWorkDialog, SelectShadowHdl_Impl));
+
+ Link<weld::MetricSpinButton&,void> aLink = LINK(this, SvxFontWorkDialog, ModifyInputHdl_Impl);
+ m_xMtrFldDistance->connect_value_changed( aLink );
+ m_xMtrFldTextStart->connect_value_changed( aLink );
+ m_xMtrFldShadowX->connect_value_changed( aLink );
+ m_xMtrFldShadowY->connect_value_changed( aLink );
+
+ // Set System metric
+ const FieldUnit eDlgUnit = rBindings.GetDispatcher()->GetModule()->GetFieldUnit();
+ SetFieldUnit(*m_xMtrFldDistance, eDlgUnit, true);
+ SetFieldUnit(*m_xMtrFldTextStart, eDlgUnit, true);
+ SetFieldUnit(*m_xMtrFldShadowX, eDlgUnit, true);
+ SetFieldUnit(*m_xMtrFldShadowY, eDlgUnit, true);
+ if( eDlgUnit == FieldUnit::MM )
+ {
+ m_xMtrFldDistance->set_increments(50, 500, FieldUnit::NONE);
+ m_xMtrFldTextStart->set_increments(50, 500, FieldUnit::NONE);
+ m_xMtrFldShadowX->set_increments(50, 500, FieldUnit::NONE);
+ m_xMtrFldShadowY->set_increments(50, 500, FieldUnit::NONE);
+ }
+ else
+ {
+ m_xMtrFldDistance->set_increments(10, 100, FieldUnit::NONE);
+ m_xMtrFldTextStart->set_increments(10, 100, FieldUnit::NONE);
+ m_xMtrFldShadowX->set_increments(10, 100, FieldUnit::NONE);
+ m_xMtrFldShadowY->set_increments(10, 100, FieldUnit::NONE);
+ }
+ m_xMtrFldShadowX->set_width_chars(WIDTH_CHARS);
+ m_xMtrFldShadowY->set_width_chars(WIDTH_CHARS);
+
+ m_xShadowColorLB->SetSelectHdl( LINK(this, SvxFontWorkDialog, ColorSelectHdl_Impl) );
+
+ aInputIdle.SetPriority(TaskPriority::LOWEST);
+ aInputIdle.SetInvokeHandler(LINK(this, SvxFontWorkDialog, InputTimeoutHdl_Impl));
+}
+
+SvxFontWorkDialog::~SvxFontWorkDialog()
+{
+ disposeOnce();
+}
+
+void SvxFontWorkDialog::dispose()
+{
+ for (SvxFontWorkControllerItem* pCtrlItem : pCtrlItems)
+ pCtrlItem->dispose();
+ m_xTbxStyle.reset();
+ m_xTbxAdjust.reset();
+ m_xMtrFldDistance.reset();
+ m_xMtrFldTextStart.reset();
+ m_xTbxShadow.reset();
+ m_xFbShadowX.reset();
+ m_xMtrFldShadowX.reset();
+ m_xFbShadowY.reset();
+ m_xMtrFldShadowY.reset();
+ m_xShadowColorLB.reset();
+ SfxDockingWindow::dispose();
+}
+
+SfxChildAlignment SvxFontWorkDialog::CheckAlignment( SfxChildAlignment eActAlign,
+ SfxChildAlignment eAlign )
+{
+ SfxChildAlignment eAlignment;
+
+ switch ( eAlign )
+ {
+ case SfxChildAlignment::TOP:
+ case SfxChildAlignment::HIGHESTTOP:
+ case SfxChildAlignment::LOWESTTOP:
+ case SfxChildAlignment::BOTTOM:
+ case SfxChildAlignment::LOWESTBOTTOM:
+ case SfxChildAlignment::HIGHESTBOTTOM:
+ {
+ eAlignment = eActAlign;
+ }
+ break;
+
+ case SfxChildAlignment::LEFT:
+ case SfxChildAlignment::RIGHT:
+ case SfxChildAlignment::FIRSTLEFT:
+ case SfxChildAlignment::LASTLEFT:
+ case SfxChildAlignment::FIRSTRIGHT:
+ case SfxChildAlignment::LASTRIGHT:
+ {
+ eAlignment = eAlign;
+ }
+ break;
+
+ default:
+ {
+ eAlignment = eAlign;
+ }
+ break;
+ }
+
+ return eAlignment;
+}
+
+// Set style buttons
+void SvxFontWorkDialog::SetStyle_Impl(const XFormTextStyleItem* pItem)
+{
+ if ( pItem )
+ {
+ OUString sId = "off";
+
+ switch ( pItem->GetValue() )
+ {
+ case XFormTextStyle::Rotate : sId = "rotate"; break;
+ case XFormTextStyle::Upright: sId = "upright"; break;
+ case XFormTextStyle::SlantX : sId = "hori"; break;
+ case XFormTextStyle::SlantY : sId = "vert"; break;
+ default: ;//prevent warning
+ }
+ m_xTbxStyle->set_sensitive(true);
+
+ // Make sure that there is always exactly one checked toolbox item.
+ if ( pItem->GetValue() == XFormTextStyle::NONE )
+ {
+ m_xTbxStyle->set_item_active("rotate", false);
+ m_xTbxStyle->set_item_active("upright", false);
+ m_xTbxStyle->set_item_active("hori", false);
+ m_xTbxStyle->set_item_active("vert", false);
+
+ m_xTbxStyle->set_item_active("off", true);
+ }
+ else
+ {
+ m_xTbxStyle->set_item_active("off", false);
+ m_xTbxStyle->set_item_active(sId, true);
+ }
+
+ m_sLastStyleTbxId = sId;
+ }
+ else
+ m_xTbxStyle->set_sensitive(false);
+}
+
+// Set adjust buttons
+
+void SvxFontWorkDialog::SetAdjust_Impl(const XFormTextAdjustItem* pItem)
+{
+ if ( pItem )
+ {
+ OUString sId;
+
+ m_xTbxAdjust->set_sensitive(true);
+ m_xMtrFldDistance->set_sensitive(true);
+
+ if ( pItem->GetValue() == XFormTextAdjust::Left || pItem->GetValue() == XFormTextAdjust::Right )
+ {
+ if (pItem->GetValue() == XFormTextAdjust::Left)
+ sId = "left";
+ else
+ sId = "right";
+ m_xMtrFldTextStart->set_sensitive(true);
+ }
+ else
+ {
+ if (pItem->GetValue() == XFormTextAdjust::Center)
+ sId = "center";
+ else
+ sId = "autosize";
+ m_xMtrFldTextStart->set_sensitive(false);
+ }
+
+ if (!m_xTbxAdjust->get_item_active(sId))
+ m_xTbxAdjust->set_item_active(sId, true);
+
+ m_sLastAdjustTbxId = sId;
+ }
+ else
+ {
+ m_xTbxAdjust->set_sensitive(false);
+ m_xMtrFldTextStart->set_sensitive(false);
+ m_xMtrFldDistance->set_sensitive(false);
+ }
+}
+
+// Enter Distance value in the edit field
+
+void SvxFontWorkDialog::SetDistance_Impl(const XFormTextDistanceItem* pItem)
+{
+ if (pItem && !m_xMtrFldDistance->has_focus())
+ {
+ SetMetricValue(*m_xMtrFldDistance, pItem->GetValue(), MapUnit::Map100thMM);
+ }
+}
+
+// Enter indent value in the edit field
+
+void SvxFontWorkDialog::SetStart_Impl(const XFormTextStartItem* pItem)
+{
+ if (pItem && !m_xMtrFldTextStart->has_focus())
+ {
+ SetMetricValue(*m_xMtrFldTextStart, pItem->GetValue(), MapUnit::Map100thMM);
+ }
+}
+
+// Set button for reversing the direction of text
+
+void SvxFontWorkDialog::SetMirror_Impl(const XFormTextMirrorItem* pItem)
+{
+ if ( pItem )
+ m_xTbxAdjust->set_item_active("orientation", pItem->GetValue());
+}
+
+// Set button for contour display
+
+void SvxFontWorkDialog::SetShowForm_Impl(const XFormTextHideFormItem* pItem)
+{
+ if ( pItem )
+ m_xTbxShadow->set_item_active("contour", !pItem->GetValue());
+}
+
+// Set button for text border
+
+void SvxFontWorkDialog::SetOutline_Impl(const XFormTextOutlineItem* pItem)
+{
+ if ( pItem )
+ m_xTbxShadow->set_item_active("textcontour", pItem->GetValue());
+}
+
+// Set shadow buttons
+
+void SvxFontWorkDialog::SetShadow_Impl(const XFormTextShadowItem* pItem,
+ bool bRestoreValues)
+{
+ if ( pItem )
+ {
+ OUString sId;
+
+ m_xTbxShadow->set_sensitive(true);
+
+ if ( pItem->GetValue() == XFormTextShadow::NONE )
+ {
+ sId = "noshadow";
+ m_xFbShadowX->hide();
+ m_xFbShadowY->hide();
+ m_xMtrFldShadowX->set_sensitive(false);
+ m_xMtrFldShadowY->set_sensitive(false);
+ m_xShadowColorLB->set_sensitive(false);
+ }
+ else
+ {
+ m_xFbShadowX->show();
+ m_xFbShadowY->show();
+ m_xMtrFldShadowX->set_sensitive(true);
+ m_xMtrFldShadowY->set_sensitive(true);
+ m_xShadowColorLB->set_sensitive(true);
+
+ if ( pItem->GetValue() == XFormTextShadow::Normal )
+ {
+ sId = "vertical";
+ const FieldUnit eDlgUnit = rBindings.GetDispatcher()->GetModule()->GetFieldUnit();
+
+ m_xMtrFldShadowX->set_unit( eDlgUnit );
+ m_xMtrFldShadowX->set_digits(2);
+ m_xMtrFldShadowX->set_range(INT_MIN, INT_MAX, FieldUnit::NONE);
+ if( eDlgUnit == FieldUnit::MM )
+ m_xMtrFldShadowX->set_increments(50, 500, FieldUnit::NONE);
+ else
+ m_xMtrFldShadowX->set_increments(10, 100, FieldUnit::NONE);
+ m_xMtrFldShadowX->set_width_chars(WIDTH_CHARS);
+
+ m_xMtrFldShadowY->set_unit( eDlgUnit );
+ m_xMtrFldShadowY->set_digits(2);
+ m_xMtrFldShadowY->set_range(INT_MIN, INT_MAX, FieldUnit::NONE);
+ if( eDlgUnit == FieldUnit::MM )
+ m_xMtrFldShadowY->set_increments(50, 500, FieldUnit::NONE);
+ else
+ m_xMtrFldShadowY->set_increments(10, 100, FieldUnit::NONE);
+ m_xMtrFldShadowY->set_width_chars(WIDTH_CHARS);
+
+ if ( bRestoreValues )
+ {
+ SetMetricValue(*m_xMtrFldShadowX, nSaveShadowX, MapUnit::Map100thMM);
+ SetMetricValue(*m_xMtrFldShadowY, nSaveShadowY, MapUnit::Map100thMM);
+
+ XFormTextShadowXValItem aXItem( nSaveShadowX );
+ XFormTextShadowYValItem aYItem( nSaveShadowY );
+
+ GetBindings().GetDispatcher()->ExecuteList(
+ SID_FORMTEXT_SHDWXVAL, SfxCallMode::RECORD,
+ { &aXItem, &aYItem });
+ }
+ }
+ else
+ {
+ sId = "slant";
+
+ m_xMtrFldShadowX->set_unit(FieldUnit::DEGREE);
+ m_xMtrFldShadowX->set_digits(1);
+ m_xMtrFldShadowX->set_range(-1800, 1800, FieldUnit::NONE);
+ m_xMtrFldShadowX->set_increments(10, 100, FieldUnit::NONE);
+ m_xMtrFldShadowX->set_width_chars(WIDTH_CHARS);
+
+ m_xMtrFldShadowY->set_unit(FieldUnit::PERCENT);
+ m_xMtrFldShadowY->set_digits(0);
+ m_xMtrFldShadowY->set_range(-999, 999, FieldUnit::NONE);
+ m_xMtrFldShadowY->set_increments(10, 100, FieldUnit::NONE);
+ m_xMtrFldShadowY->set_width_chars(WIDTH_CHARS);
+
+ if ( bRestoreValues )
+ {
+ m_xMtrFldShadowX->set_value(nSaveShadowAngle, FieldUnit::NONE);
+ m_xMtrFldShadowY->set_value(nSaveShadowSize, FieldUnit::NONE);
+ XFormTextShadowXValItem aXItem(nSaveShadowAngle);
+ XFormTextShadowYValItem aYItem(nSaveShadowSize);
+ GetBindings().GetDispatcher()->ExecuteList(
+ SID_FORMTEXT_SHDWXVAL, SfxCallMode::RECORD,
+ { &aXItem, &aYItem });
+ }
+ }
+ }
+
+ if (!m_xTbxShadow->get_item_active(sId))
+ m_xTbxShadow->set_item_active(sId, true);
+ m_sLastShadowTbxId = sId;
+
+ ApplyImageList();
+ }
+ else
+ {
+ m_xTbxShadow->set_sensitive(false);
+ m_xMtrFldShadowX->set_sensitive(false);
+ m_xMtrFldShadowY->set_sensitive(false);
+ m_xShadowColorLB->set_sensitive(false);
+ }
+}
+
+// Insert shadow color in listbox
+
+void SvxFontWorkDialog::SetShadowColor_Impl(const XFormTextShadowColorItem* pItem)
+{
+ if ( pItem )
+ m_xShadowColorLB->SelectEntry(pItem->GetColorValue());
+}
+
+// Enter X-value for shadow in edit field
+void SvxFontWorkDialog::SetShadowXVal_Impl(const XFormTextShadowXValItem* pItem)
+{
+ if (!pItem || m_xMtrFldShadowX->has_focus())
+ return;
+
+ // #i19251#
+ // sal_Int32 nValue = pItem->GetValue();
+
+ // #i19251#
+ // The two involved fields/items are used double and contain/give different
+ // values regarding to the access method. Thus, here we need to separate the access
+ // methods regarding to the kind of value accessed.
+ if (m_xTbxShadow->get_item_active("slant"))
+ {
+ // #i19251#
+ // There is no value correction necessary at all, i think this
+ // was only tried to be done without understanding that the two
+ // involved fields/items are used double and contain/give different
+ // values regarding to the access method.
+ // nValue = nValue - ( int( float( nValue ) / 360.0 ) * 360 );
+ m_xMtrFldShadowX->set_value(pItem->GetValue(), FieldUnit::NONE);
+ }
+ else
+ {
+ SetMetricValue(*m_xMtrFldShadowX, pItem->GetValue(), MapUnit::Map100thMM);
+ }
+}
+
+// Enter Y-value for shadow in edit field
+void SvxFontWorkDialog::SetShadowYVal_Impl(const XFormTextShadowYValItem* pItem)
+{
+ if (!pItem || m_xMtrFldShadowY->has_focus())
+ return;
+
+ // #i19251#
+ // The two involved fields/items are used double and contain/give different
+ // values regarding to the access method. Thus, here we need to separate the access
+ // methods regarding to the kind of value accessed.
+ if (m_xTbxShadow->get_item_active("slant"))
+ {
+ m_xMtrFldShadowY->set_value(pItem->GetValue(), FieldUnit::NONE);
+ }
+ else
+ {
+ SetMetricValue(*m_xMtrFldShadowY, pItem->GetValue(), MapUnit::Map100thMM);
+ }
+}
+
+IMPL_LINK(SvxFontWorkDialog, SelectStyleHdl_Impl, const OUString&, rId, void)
+{
+ // Execute this block when a different toolbox item has been clicked or
+ // when the off item has been clicked. The later is necessary to
+ // override the toolbox behaviour of unchecking the item after second
+ // click on it: One of the items has to be checked at all times (when
+ // enabled that is.)
+ if (rId != "off" && rId == m_sLastStyleTbxId)
+ return;
+
+ XFormTextStyle eStyle = XFormTextStyle::NONE;
+
+ if (rId == "rotate")
+ eStyle = XFormTextStyle::Rotate;
+ else if (rId == "upright")
+ eStyle = XFormTextStyle::Upright;
+ else if (rId == "hori")
+ eStyle = XFormTextStyle::SlantX;
+ else if (rId == "vert")
+ eStyle = XFormTextStyle::SlantY;
+
+ XFormTextStyleItem aItem( eStyle );
+ GetBindings().GetDispatcher()->ExecuteList(SID_FORMTEXT_STYLE,
+ SfxCallMode::RECORD, { &aItem });
+ SetStyle_Impl( &aItem );
+ m_sLastStyleTbxId = rId;
+}
+
+IMPL_LINK(SvxFontWorkDialog, SelectAdjustHdl_Impl, const OUString&, rId, void)
+{
+ if (rId == "orientation")
+ {
+ XFormTextMirrorItem aItem(m_xTbxAdjust->get_item_active(rId));
+ GetBindings().GetDispatcher()->ExecuteList(SID_FORMTEXT_MIRROR,
+ SfxCallMode::SLOT, { &aItem });
+ }
+ else if (rId != m_sLastAdjustTbxId)
+ {
+ XFormTextAdjust eAdjust = XFormTextAdjust::AutoSize;
+
+ if (rId == "left")
+ eAdjust = XFormTextAdjust::Left;
+ else if (rId == "center")
+ eAdjust = XFormTextAdjust::Center;
+ else if (rId == "right")
+ eAdjust = XFormTextAdjust::Right;
+
+ XFormTextAdjustItem aItem(eAdjust);
+ GetBindings().GetDispatcher()->ExecuteList(SID_FORMTEXT_ADJUST,
+ SfxCallMode::RECORD, { &aItem });
+ SetAdjust_Impl(&aItem);
+ m_sLastAdjustTbxId = rId;
+ }
+}
+
+IMPL_LINK(SvxFontWorkDialog, SelectShadowHdl_Impl, const OUString&, rId, void)
+{
+ if (rId == "contour")
+ {
+ XFormTextHideFormItem aItem(!m_xTbxShadow->get_item_active(rId));
+ GetBindings().GetDispatcher()->ExecuteList(SID_FORMTEXT_HIDEFORM,
+ SfxCallMode::RECORD, { &aItem });
+ }
+ else if (rId == "textcontour")
+ {
+ XFormTextOutlineItem aItem(m_xTbxShadow->get_item_active(rId));
+ GetBindings().GetDispatcher()->ExecuteList(SID_FORMTEXT_OUTLINE,
+ SfxCallMode::RECORD, { &aItem });
+ }
+ else if (rId != m_sLastShadowTbxId)
+ {
+ XFormTextShadow eShadow = XFormTextShadow::NONE;
+
+ if (m_sLastShadowTbxId == "vertical")
+ {
+ nSaveShadowX = GetCoreValue(*m_xMtrFldShadowX, MapUnit::Map100thMM);
+ nSaveShadowY = GetCoreValue(*m_xMtrFldShadowY, MapUnit::Map100thMM);
+ }
+ else if (m_sLastShadowTbxId == "slant")
+ {
+ nSaveShadowAngle = m_xMtrFldShadowX->get_value(FieldUnit::NONE);
+ nSaveShadowSize = m_xMtrFldShadowY->get_value(FieldUnit::NONE);
+ }
+ m_sLastShadowTbxId = rId;
+
+ if ( rId == "vertical") eShadow = XFormTextShadow::Normal;
+ else if (rId == "slant") eShadow = XFormTextShadow::Slant;
+
+ XFormTextShadowItem aItem(eShadow);
+ GetBindings().GetDispatcher()->ExecuteList(SID_FORMTEXT_SHADOW,
+ SfxCallMode::RECORD, { &aItem });
+ SetShadow_Impl(&aItem, true);
+ }
+}
+
+IMPL_LINK_NOARG(SvxFontWorkDialog, ModifyInputHdl_Impl, weld::MetricSpinButton&, void)
+{
+ aInputIdle.Start();
+}
+
+IMPL_LINK_NOARG(SvxFontWorkDialog, InputTimeoutHdl_Impl, Timer*, void)
+{
+ // Possibly set the Metric system again. This should be done with a
+ // listen, this is however not possible at the moment due to compatibility
+ // issues.
+ const FieldUnit eDlgUnit = rBindings.GetDispatcher()->GetModule()->GetFieldUnit();
+ if( eDlgUnit != m_xMtrFldDistance->get_unit() )
+ {
+ SetFieldUnit(*m_xMtrFldDistance, eDlgUnit, true);
+ SetFieldUnit(*m_xMtrFldTextStart, eDlgUnit, true);
+ if (eDlgUnit == FieldUnit::MM)
+ {
+ m_xMtrFldDistance->set_increments(50, 500, FieldUnit::NONE);
+ m_xMtrFldTextStart->set_increments(50, 500, FieldUnit::NONE);
+ }
+ else
+ {
+ m_xMtrFldDistance->set_increments(10, 100, FieldUnit::NONE);
+ m_xMtrFldTextStart->set_increments(10, 100, FieldUnit::NONE);
+ }
+ }
+ if( eDlgUnit != m_xMtrFldShadowX->get_unit() &&
+ m_xTbxShadow->get_item_active("vertical") )
+ {
+ SetFieldUnit(*m_xMtrFldShadowX, eDlgUnit, true);
+ SetFieldUnit(*m_xMtrFldShadowY, eDlgUnit, true);
+
+ if (eDlgUnit == FieldUnit::MM)
+ {
+ m_xMtrFldShadowX->set_increments(50, 500, FieldUnit::NONE);
+ m_xMtrFldShadowY->set_increments(50, 500, FieldUnit::NONE);
+ }
+ else
+ {
+ m_xMtrFldShadowX->set_increments(10, 100, FieldUnit::NONE);
+ m_xMtrFldShadowY->set_increments(10, 100, FieldUnit::NONE);
+ }
+ }
+
+ tools::Long nValue = GetCoreValue(*m_xMtrFldDistance, MapUnit::Map100thMM);
+ XFormTextDistanceItem aDistItem( nValue );
+ nValue = GetCoreValue(*m_xMtrFldTextStart, MapUnit::Map100thMM);
+ XFormTextStartItem aStartItem( nValue );
+
+ sal_Int32 nValueX(0);
+ sal_Int32 nValueY(0);
+
+ // #i19251#
+ // The two involved fields/items are used double and contain/give different
+ // values regarding to the access method. Thus, here we need to separate the access
+ // method regarding to the kind of value accessed.
+ if (m_sLastShadowTbxId == "vertical")
+ {
+ nValueX = GetCoreValue(*m_xMtrFldShadowX, MapUnit::Map100thMM);
+ nValueY = GetCoreValue(*m_xMtrFldShadowY, MapUnit::Map100thMM);
+ }
+ else if (m_sLastShadowTbxId == "slant")
+ {
+ nValueX = m_xMtrFldShadowX->get_value(FieldUnit::NONE);
+ nValueY = m_xMtrFldShadowY->get_value(FieldUnit::NONE);
+ }
+
+ XFormTextShadowXValItem aShadowXItem( nValueX );
+ XFormTextShadowYValItem aShadowYItem( nValueY );
+
+ // Slot-ID does not matter, the Exec method evaluates the entire item set
+ GetBindings().GetDispatcher()->ExecuteList(SID_FORMTEXT_DISTANCE,
+ SfxCallMode::RECORD,
+ { &aDistItem, &aStartItem, &aShadowXItem, &aShadowYItem });
+}
+
+IMPL_LINK_NOARG(SvxFontWorkDialog, ColorSelectHdl_Impl, ColorListBox&, void)
+{
+ XFormTextShadowColorItem aItem( "", m_xShadowColorLB->GetSelectEntryColor() );
+ GetBindings().GetDispatcher()->ExecuteList(SID_FORMTEXT_SHDWCOLOR,
+ SfxCallMode::RECORD, { &aItem });
+}
+
+void SvxFontWorkDialog::ApplyImageList()
+{
+ if (m_sLastShadowTbxId == "slant")
+ {
+ m_xFbShadowX->set_from_icon_name(RID_SVXBMP_SHADOW_ANGLE);
+ m_xFbShadowY->set_from_icon_name(RID_SVXBMP_SHADOW_SIZE);
+ }
+ else
+ {
+ m_xFbShadowX->set_from_icon_name(RID_SVXBMP_SHADOW_XDIST);
+ m_xFbShadowY->set_from_icon_name(RID_SVXBMP_SHADOW_YDIST);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/framelink.cxx b/svx/source/dialog/framelink.cxx
new file mode 100644
index 0000000000..887fc445dc
--- /dev/null
+++ b/svx/source/dialog/framelink.cxx
@@ -0,0 +1,341 @@
+/* -*- 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 <rtl/math.hxx>
+#include <svx/framelink.hxx>
+
+#include <editeng/borderline.hxx>
+#include <o3tl/hash_combine.hxx>
+
+
+using namespace ::com::sun::star;
+using namespace editeng;
+
+namespace svx::frame
+{
+
+Style::Style( double nP, double nD, double nS, SvxBorderLineStyle nType, double fScale )
+{
+ Clear();
+ mnType = nType;
+ mfPatternScale = fScale;
+ Set( nP, nD, nS );
+}
+
+Style::Style( const Color& rColorPrim, const Color& rColorSecn, const Color& rColorGap, bool bUseGapColor, double nP, double nD, double nS, SvxBorderLineStyle nType, double fScale )
+{
+ Clear();
+ mnType = nType;
+ mfPatternScale = fScale;
+ Set( rColorPrim, rColorSecn, rColorGap, bUseGapColor, nP, nD, nS );
+}
+
+Style::Style( const editeng::SvxBorderLine* pBorder, double fScale )
+{
+ Clear();
+ if(nullptr != pBorder)
+ {
+ mfPatternScale = fScale;
+ Set( pBorder, fScale );
+ }
+}
+
+void Style::Clear()
+{
+ maColorPrim = Color();
+ maColorSecn = Color();
+ maColorGap = Color();
+ mbUseGapColor = false;
+ meRefMode = RefMode::Centered;
+ mfPrim = 0.0;
+ mfDist = 0.0;
+ mfSecn = 0.0;
+ mfPatternScale = 1.0;
+ mnType = SvxBorderLineStyle::SOLID;
+ mbWordTableCell = false;
+}
+
+void Style::Set( double nP, double nD, double nS )
+{
+ /* nP nD nS -> mfPrim mfDist mfSecn
+ --------------------------------------
+ any any 0 nP 0 0
+ 0 any >0 nS 0 0
+ >0 0 >0 nP 0 0
+ >0 >0 >0 nP nD nS
+ */
+ mfPrim = rtl::math::round(nP ? nP : nS, 2);
+ mfDist = rtl::math::round((nP && nS) ? nD : 0, 2);
+ mfSecn = rtl::math::round((nP && nD) ? nS : 0, 2);
+}
+
+void Style::Set( const Color& rColorPrim, const Color& rColorSecn, const Color& rColorGap, bool bUseGapColor, double nP, double nD, double nS )
+{
+ maColorPrim = rColorPrim;
+ maColorSecn = rColorSecn;
+ maColorGap = rColorGap;
+ mbUseGapColor = bUseGapColor;
+ Set( nP, nD, nS );
+}
+
+void Style::Set( const SvxBorderLine* pBorder, double fScale, sal_uInt16 nMaxWidth )
+{
+ if(nullptr == pBorder)
+ {
+ Clear();
+ return;
+ }
+
+ maColorPrim = pBorder->GetColorOut();
+ maColorSecn = pBorder->GetColorIn();
+ maColorGap = pBorder->GetColorGap();
+ mbUseGapColor = pBorder->HasGapColor();
+
+ const sal_uInt16 nPrim(pBorder->GetOutWidth());
+ const sal_uInt16 nDist(pBorder->GetDistance());
+ const sal_uInt16 nSecn(pBorder->GetInWidth());
+
+ mnType = pBorder->GetBorderLineStyle();
+ mfPatternScale = fScale;
+
+ if( !nSecn ) // no or single frame border
+ {
+ Set( std::min<double>(nPrim * fScale, nMaxWidth), 0, 0 );
+ }
+ else
+ {
+ Set(std::min<double>(nPrim * fScale, nMaxWidth), std::min<double>(nDist * fScale, nMaxWidth), std::min<double>(nSecn * fScale, nMaxWidth));
+ // Enlarge the style if distance is too small due to rounding losses.
+ double nPixWidth = std::min<double>((nPrim + nDist + nSecn) * fScale, nMaxWidth);
+
+ if( nPixWidth > GetWidth() )
+ {
+ mfDist = nPixWidth - mfPrim - mfSecn;
+ }
+
+ // Shrink the style if it is too thick for the control.
+ while( GetWidth() > nMaxWidth )
+ {
+ // First decrease space between lines.
+ if (mfDist)
+ {
+ --mfDist;
+ continue;
+ }
+
+ // Still too thick? Decrease the line widths.
+ if (mfPrim != 0.0 && rtl::math::approxEqual(mfPrim, mfSecn))
+ {
+ // Both lines equal - decrease both to keep symmetry.
+ --mfPrim;
+ --mfSecn;
+ continue;
+ }
+
+ // Decrease each line for itself
+ if (mfPrim)
+ --mfPrim;
+
+ if ((GetWidth() > nMaxWidth) && mfSecn != 0.0)
+ --mfSecn;
+ }
+ }
+}
+
+Style& Style::MirrorSelf()
+{
+ if (mfSecn)
+ {
+ std::swap( mfPrim, mfSecn );
+ // also need to swap colors
+ std::swap( maColorPrim, maColorSecn );
+ }
+
+ if( meRefMode != RefMode::Centered )
+ {
+ meRefMode = (meRefMode == RefMode::Begin) ? RefMode::End : RefMode::Begin;
+ }
+
+ return *this;
+}
+
+bool Style::operator==( const Style& rOther) const
+{
+ if (this == &rOther)
+ // ptr compare (same instance)
+ return true;
+
+ return (Prim() == rOther.Prim()
+ && Dist() == rOther.Dist()
+ && Secn() == rOther.Secn()
+ && GetColorPrim() == rOther.GetColorPrim()
+ && GetColorSecn() == rOther.GetColorSecn()
+ && GetColorGap() == rOther.GetColorGap()
+ && GetRefMode() == rOther.GetRefMode()
+ && UseGapColor() == rOther.UseGapColor()
+ && Type() == rOther.Type());
+}
+
+size_t Style::hashCode() const
+{
+ std::size_t seed = 0;
+ o3tl::hash_combine(seed, Prim());
+ o3tl::hash_combine(seed, Dist());
+ o3tl::hash_combine(seed, Secn());
+ o3tl::hash_combine(seed, static_cast<sal_Int32>(GetColorPrim()));
+ o3tl::hash_combine(seed, static_cast<sal_Int32>(GetColorSecn()));
+ o3tl::hash_combine(seed, static_cast<sal_Int32>(GetColorGap()));
+ o3tl::hash_combine(seed, GetRefMode());
+ o3tl::hash_combine(seed, UseGapColor());
+ o3tl::hash_combine(seed, Type());
+ return seed;
+}
+
+
+namespace
+{
+/**
+ * Gets the weight of rStyle, according to [MS-OI29500] v20171130, 2.1.168 Part 1 Section 17.4.66,
+ * tcBorders (Table Cell Borders).
+ */
+double GetWordTableCellBorderWeight(const Style& rStyle)
+{
+ double fWidth = rStyle.GetWidth();
+ int nBorderNumber = 0;
+
+ // See lcl_convertBorderStyleFromToken() in writerfilter/ and ConvertBorderStyleFromWord() in
+ // editeng/, this is the opposite of the combination of those functions.
+ switch (rStyle.Type())
+ {
+ case SvxBorderLineStyle::NONE:
+ return 0.0;
+ case SvxBorderLineStyle::DOTTED:
+ case SvxBorderLineStyle::DASHED:
+ return 1.0;
+ case SvxBorderLineStyle::SOLID:
+ // single = 1
+ // thick = 2
+ // wave = 20
+ nBorderNumber = 1;
+ break;
+ case SvxBorderLineStyle::DOUBLE:
+ case SvxBorderLineStyle::DOUBLE_THIN:
+ // double = 3
+ // triple = 10
+ // doubleWave = 21
+ // dashDotStroked = 23
+ nBorderNumber = 3;
+ break;
+ case SvxBorderLineStyle::DASH_DOT:
+ // dotDash = 8
+ nBorderNumber = 8;
+ break;
+ case SvxBorderLineStyle::DASH_DOT_DOT:
+ // dotDotDash = 9
+ nBorderNumber = 9;
+ break;
+ case SvxBorderLineStyle::THINTHICK_SMALLGAP:
+ // thinThickSmallGap = 11
+ nBorderNumber = 11;
+ break;
+ case SvxBorderLineStyle::THICKTHIN_SMALLGAP:
+ // thickThinSmallGap = 12
+ // thinThickThinSmallGap = 13
+ nBorderNumber = 12;
+ break;
+ case SvxBorderLineStyle::THINTHICK_MEDIUMGAP:
+ // thinThickMediumGap = 14
+ nBorderNumber = 14;
+ break;
+ case SvxBorderLineStyle::THICKTHIN_MEDIUMGAP:
+ // thickThinMediumGap = 15
+ // thinThickThinMediumGap = 16
+ nBorderNumber = 15;
+ break;
+ case SvxBorderLineStyle::THINTHICK_LARGEGAP:
+ // thinThickLargeGap = 17
+ nBorderNumber = 17;
+ break;
+ case SvxBorderLineStyle::THICKTHIN_LARGEGAP:
+ // thickThinLargeGap = 18
+ // thinThickThinLargeGap = 19
+ nBorderNumber = 18;
+ break;
+ case SvxBorderLineStyle::FINE_DASHED:
+ // dashSmallGap = 22
+ nBorderNumber = 22;
+ break;
+ case SvxBorderLineStyle::EMBOSSED:
+ // threeDEmboss = 24
+ nBorderNumber = 24;
+ break;
+ case SvxBorderLineStyle::ENGRAVED:
+ // threeDEngrave = 25
+ nBorderNumber = 25;
+ break;
+ case SvxBorderLineStyle::OUTSET:
+ // outset = 26
+ nBorderNumber = 25;
+ break;
+ case SvxBorderLineStyle::INSET:
+ // inset = 27
+ nBorderNumber = 27;
+ break;
+ }
+
+ return nBorderNumber * fWidth;
+}
+}
+
+bool Style::operator<( const Style& rOther) const
+{
+ if (mbWordTableCell)
+ {
+ // The below code would first compare based on the border width, Word compares based on its
+ // calculated weight, do that in the compat case.
+ double fLW = GetWordTableCellBorderWeight(*this);
+ double fRW = GetWordTableCellBorderWeight(rOther);
+ if (!rtl::math::approxEqual(fLW, fRW))
+ {
+ return fLW < fRW;
+ }
+ }
+
+ // different total widths -> this<rOther, if this is thinner
+ double nLW = GetWidth();
+ double nRW = rOther.GetWidth();
+ if( !rtl::math::approxEqual(nLW, nRW) ) return nLW < nRW;
+
+ // one line double, the other single -> this<rOther, if this is single
+ if( (Secn() == 0) != (rOther.Secn() == 0) ) return Secn() == 0;
+
+ // both lines double with different distances -> this<rOther, if distance of this greater
+ if( (Secn() && rOther.Secn()) && !rtl::math::approxEqual(Dist(), rOther.Dist()) ) return Dist() > rOther.Dist();
+
+ // both lines single and 1 unit thick, only one is dotted -> this<rOther, if this is dotted
+ if ((nLW == 1) && !Secn() && !rOther.Secn() && (Type() != rOther.Type())) return Type() > rOther.Type();
+
+ // seem to be equal
+ return false;
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/framelinkarray.cxx b/svx/source/dialog/framelinkarray.cxx
new file mode 100644
index 0000000000..fa58294386
--- /dev/null
+++ b/svx/source/dialog/framelinkarray.cxx
@@ -0,0 +1,1698 @@
+/* -*- 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 <svx/framelinkarray.hxx>
+
+#include <math.h>
+#include <vector>
+#include <set>
+#include <unordered_set>
+#include <algorithm>
+#include <o3tl/hash_combine.hxx>
+#include <tools/debug.hxx>
+#include <tools/gen.hxx>
+#include <vcl/canvastools.hxx>
+#include <svx/sdr/primitive2d/sdrframeborderprimitive2d.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <basegfx/polygon/b2dpolygonclipper.hxx>
+
+//#define OPTICAL_CHECK_CLIPRANGE_FOR_MERGED_CELL
+#ifdef OPTICAL_CHECK_CLIPRANGE_FOR_MERGED_CELL
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <drawinglayer/primitive2d/PolygonHairlinePrimitive2D.hxx>
+#endif
+
+namespace svx::frame {
+
+namespace {
+
+class Cell final
+{
+private:
+ Style maLeft;
+ Style maRight;
+ Style maTop;
+ Style maBottom;
+ Style maTLBR;
+ Style maBLTR;
+
+ basegfx::B2DHomMatrix HelperCreateB2DHomMatrixFromB2DRange(
+ const basegfx::B2DRange& rRange ) const;
+
+public:
+ sal_Int32 mnAddLeft;
+ sal_Int32 mnAddRight;
+ sal_Int32 mnAddTop;
+ sal_Int32 mnAddBottom;
+
+ SvxRotateMode meRotMode;
+ double mfOrientation;
+
+ bool mbMergeOrig;
+ bool mbOverlapX;
+ bool mbOverlapY;
+
+public:
+ explicit Cell();
+ explicit Cell(const Cell&) = default;
+
+ bool operator==( const Cell& ) const;
+ size_t hashCode() const;
+
+ void SetStyleLeft(const Style& rStyle) { maLeft = rStyle; }
+ void SetStyleRight(const Style& rStyle) { maRight = rStyle; }
+ void SetStyleTop(const Style& rStyle) { maTop = rStyle; }
+ void SetStyleBottom(const Style& rStyle) { maBottom = rStyle; }
+ void SetStyleTLBR(const Style& rStyle) { maTLBR = rStyle; }
+ void SetStyleBLTR(const Style& rStyle) { maBLTR = rStyle; }
+
+ const Style& GetStyleLeft() const { return maLeft; }
+ const Style& GetStyleRight() const { return maRight; }
+ const Style& GetStyleTop() const { return maTop; }
+ const Style& GetStyleBottom() const { return maBottom; }
+ const Style& GetStyleTLBR() const { return maTLBR; }
+ const Style& GetStyleBLTR() const { return maBLTR; }
+
+ bool IsMerged() const { return mbMergeOrig || mbOverlapX || mbOverlapY; }
+ bool IsRotated() const { return mfOrientation != 0.0; }
+
+ void MirrorSelfX();
+
+ basegfx::B2DHomMatrix CreateCoordinateSystemSingleCell(
+ const Array& rArray, sal_Int32 nCol, sal_Int32 nRow ) const;
+ basegfx::B2DHomMatrix CreateCoordinateSystemMergedCell(
+ const Array& rArray, sal_Int32 nColLeft, sal_Int32 nRowTop, sal_Int32 nColRight, sal_Int32 nRowBottom ) const;
+};
+
+}
+
+typedef std::vector< const Cell* > CellVec;
+
+basegfx::B2DHomMatrix Cell::HelperCreateB2DHomMatrixFromB2DRange(
+ const basegfx::B2DRange& rRange ) const
+{
+ if( rRange.isEmpty() )
+ return basegfx::B2DHomMatrix();
+
+ basegfx::B2DPoint aOrigin(rRange.getMinimum());
+ basegfx::B2DVector aX(rRange.getWidth(), 0.0);
+ basegfx::B2DVector aY(0.0, rRange.getHeight());
+
+ if (IsRotated() && SvxRotateMode::SVX_ROTATE_MODE_STANDARD != meRotMode )
+ {
+ // tdf#143377 We need to limit applying Skew to geometry since the closer
+ // we get to 0.0 or PI the more sin(mfOrientation) will get to zero and the
+ // huger the Skew effect will be. For that, use an epsilon-radius of 1/2
+ // degree around the dangerous points 0.0 and PI.
+
+ // Snap to modulo to [0.0 .. 2PI[ to make compare easier
+ const double fSnapped(::basegfx::snapToZeroRange(mfOrientation, M_PI * 2.0));
+
+ // As a compromise, allow up to 1/2 degree
+ static const double fMinAng(M_PI/360.0);
+
+ // Check if Skew makes sense or would be too huge
+ const bool bForbidSkew(
+ fSnapped < fMinAng || // range [0.0 .. fMinAng]
+ fSnapped > (M_PI * 2.0) - fMinAng || // range [PI-fMinAng .. 2PI[
+ fabs(fSnapped - M_PI) < fMinAng); // range [PI-fMinAng .. PI+fMinAng]
+
+ if(!bForbidSkew)
+ {
+ // when rotated, adapt values. Get Skew (cos/sin == 1/tan)
+ const double fSkew(aY.getY() * (cos(mfOrientation) / sin(mfOrientation)));
+
+ switch (meRotMode)
+ {
+ case SvxRotateMode::SVX_ROTATE_MODE_TOP:
+ // shear Y-Axis
+ aY.setX(-fSkew);
+ break;
+ case SvxRotateMode::SVX_ROTATE_MODE_CENTER:
+ // shear origin half, Y full
+ aOrigin.setX(aOrigin.getX() + (fSkew * 0.5));
+ aY.setX(-fSkew);
+ break;
+ case SvxRotateMode::SVX_ROTATE_MODE_BOTTOM:
+ // shear origin full, Y full
+ aOrigin.setX(aOrigin.getX() + fSkew);
+ aY.setX(-fSkew);
+ break;
+ default: // SvxRotateMode::SVX_ROTATE_MODE_STANDARD, already excluded above
+ break;
+ }
+ }
+ }
+
+ // use column vectors as coordinate axes, homogen column for translation
+ return basegfx::utils::createCoordinateSystemTransform( aOrigin, aX, aY );
+}
+
+basegfx::B2DHomMatrix Cell::CreateCoordinateSystemSingleCell(
+ const Array& rArray, sal_Int32 nCol, sal_Int32 nRow) const
+{
+ const Point aPoint( rArray.GetColPosition( nCol ), rArray.GetRowPosition( nRow ) );
+ const Size aSize( rArray.GetColWidth( nCol, nCol ) + 1, rArray.GetRowHeight( nRow, nRow ) + 1 );
+ const basegfx::B2DRange aRange( vcl::unotools::b2DRectangleFromRectangle( tools::Rectangle( aPoint, aSize ) ) );
+
+ return HelperCreateB2DHomMatrixFromB2DRange( aRange );
+}
+
+basegfx::B2DHomMatrix Cell::CreateCoordinateSystemMergedCell(
+ const Array& rArray, sal_Int32 nColLeft, sal_Int32 nRowTop, sal_Int32 nColRight, sal_Int32 nRowBottom) const
+{
+ basegfx::B2DRange aRange( rArray.GetB2DRange(
+ nColLeft, nRowTop, nColRight, nRowBottom ) );
+
+ // adjust rectangle for partly visible merged cells
+ if( IsMerged() )
+ {
+ // not *sure* what exactly this is good for,
+ // it is just a hard set extension at merged cells,
+ // probably *should* be included in the above extended
+ // GetColPosition/GetColWidth already. This might be
+ // added due to GetColPosition/GetColWidth not working
+ // correctly over PageChanges (if used), but not sure.
+ aRange.expand(
+ basegfx::B2DRange(
+ aRange.getMinX() - mnAddLeft,
+ aRange.getMinY() - mnAddTop,
+ aRange.getMaxX() + mnAddRight,
+ aRange.getMaxY() + mnAddBottom ) );
+ }
+
+ return HelperCreateB2DHomMatrixFromB2DRange( aRange );
+}
+
+Cell::Cell() :
+ mnAddLeft( 0 ),
+ mnAddRight( 0 ),
+ mnAddTop( 0 ),
+ mnAddBottom( 0 ),
+ meRotMode(SvxRotateMode::SVX_ROTATE_MODE_STANDARD ),
+ mfOrientation( 0.0 ),
+ mbMergeOrig( false ),
+ mbOverlapX( false ),
+ mbOverlapY( false )
+{
+}
+
+bool Cell::operator==(const Cell& rOther) const
+{
+ if (this == &rOther)
+ // ptr compare (same instance)
+ return true;
+
+ return maLeft == rOther.maLeft
+ && maRight == rOther.maRight
+ && maTop == rOther.maTop
+ && maBottom == rOther.maBottom
+ && maTLBR == rOther.maTLBR
+ && maBLTR == rOther.maBLTR
+ && mnAddLeft == rOther.mnAddLeft
+ && mnAddRight == rOther.mnAddRight
+ && mnAddTop == rOther.mnAddTop
+ && mnAddBottom == rOther.mnAddBottom
+ && meRotMode == rOther.meRotMode
+ && mfOrientation == rOther.mfOrientation
+ && mbMergeOrig == rOther.mbMergeOrig
+ && mbOverlapX == rOther.mbOverlapX
+ && mbOverlapY == rOther.mbOverlapY;
+}
+
+size_t Cell::hashCode() const
+{
+ std::size_t seed = 0;
+ o3tl::hash_combine(seed, maLeft.hashCode());
+ o3tl::hash_combine(seed, maRight.hashCode());
+ o3tl::hash_combine(seed, maTop.hashCode());
+ o3tl::hash_combine(seed, maBottom.hashCode());
+ o3tl::hash_combine(seed, maTLBR.hashCode());
+ o3tl::hash_combine(seed, maBLTR.hashCode());
+ o3tl::hash_combine(seed, mnAddLeft);
+ o3tl::hash_combine(seed, mnAddRight);
+ o3tl::hash_combine(seed, mnAddTop);
+ o3tl::hash_combine(seed, mnAddBottom);
+ o3tl::hash_combine(seed, meRotMode);
+ o3tl::hash_combine(seed, mfOrientation);
+ o3tl::hash_combine(seed, mbMergeOrig);
+ o3tl::hash_combine(seed, mbOverlapX);
+ o3tl::hash_combine(seed, mbOverlapY);
+ return seed;
+}
+
+void Cell::MirrorSelfX()
+{
+ std::swap( maLeft, maRight );
+ std::swap( mnAddLeft, mnAddRight );
+ maLeft.MirrorSelf();
+ maRight.MirrorSelf();
+ mfOrientation = -mfOrientation;
+}
+
+
+static void lclRecalcCoordVec( std::vector<sal_Int32>& rCoords, const std::vector<sal_Int32>& rSizes )
+{
+ DBG_ASSERT( rCoords.size() == rSizes.size() + 1, "lclRecalcCoordVec - inconsistent vectors" );
+ auto aCIt = rCoords.begin();
+ for( const auto& rSize : rSizes )
+ {
+ *(aCIt + 1) = *aCIt + rSize;
+ ++aCIt;
+ }
+}
+
+const Style OBJ_STYLE_NONE;
+const Cell OBJ_CELL_NONE;
+
+/** use hashing to speed up finding duplicates */
+namespace
+{
+struct RegisteredCellHash
+{
+ size_t operator()(Cell* const pCell) const
+ {
+ return pCell->hashCode();
+ }
+};
+
+struct RegisteredCellEquals
+{
+ bool operator()(Cell* const pCell1, Cell* const pCell2) const
+ {
+ return *pCell1 == *pCell2;
+ }
+};
+}
+
+struct ArrayImpl
+{
+ std::unordered_set<Cell*, RegisteredCellHash, RegisteredCellEquals> maRegisteredCells;
+ CellVec maCells;
+ std::vector<sal_Int32> maWidths;
+ std::vector<sal_Int32> maHeights;
+ mutable std::vector<sal_Int32> maXCoords;
+ mutable std::vector<sal_Int32> maYCoords;
+ sal_Int32 mnWidth;
+ sal_Int32 mnHeight;
+ sal_Int32 mnFirstClipCol;
+ sal_Int32 mnFirstClipRow;
+ sal_Int32 mnLastClipCol;
+ sal_Int32 mnLastClipRow;
+ mutable bool mbXCoordsDirty;
+ mutable bool mbYCoordsDirty;
+ bool mbMayHaveCellRotation;
+
+ explicit ArrayImpl( sal_Int32 nWidth, sal_Int32 nHeight );
+ ~ArrayImpl();
+
+ bool IsValidPos( sal_Int32 nCol, sal_Int32 nRow ) const
+ { return (nCol < mnWidth) && (nRow < mnHeight); }
+ sal_Int32 GetIndex( sal_Int32 nCol, sal_Int32 nRow ) const
+ { return nRow * mnWidth + nCol; }
+
+ const Cell* GetCell( sal_Int32 nCol, sal_Int32 nRow ) const;
+ void PutCell( sal_Int32 nCol, sal_Int32 nRow, const Cell& );
+
+ sal_Int32 GetMergedFirstCol( sal_Int32 nCol, sal_Int32 nRow ) const;
+ sal_Int32 GetMergedFirstRow( sal_Int32 nCol, sal_Int32 nRow ) const;
+ sal_Int32 GetMergedLastCol( sal_Int32 nCol, sal_Int32 nRow ) const;
+ sal_Int32 GetMergedLastRow( sal_Int32 nCol, sal_Int32 nRow ) const;
+
+ const Cell* GetMergedOriginCell( sal_Int32 nCol, sal_Int32 nRow ) const;
+ const Cell* GetMergedLastCell( sal_Int32 nCol, sal_Int32 nRow ) const;
+
+ bool IsMergedOverlappedLeft( sal_Int32 nCol, sal_Int32 nRow ) const;
+ bool IsMergedOverlappedRight( sal_Int32 nCol, sal_Int32 nRow ) const;
+ bool IsMergedOverlappedTop( sal_Int32 nCol, sal_Int32 nRow ) const;
+ bool IsMergedOverlappedBottom( sal_Int32 nCol, sal_Int32 nRow ) const;
+
+ bool IsInClipRange( sal_Int32 nCol, sal_Int32 nRow ) const;
+ bool IsColInClipRange( sal_Int32 nCol ) const;
+ bool IsRowInClipRange( sal_Int32 nRow ) const;
+
+ bool OverlapsClipRange( sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow ) const;
+
+ sal_Int32 GetMirrorCol( sal_Int32 nCol ) const { return mnWidth - nCol - 1; }
+
+ sal_Int32 GetColPosition( sal_Int32 nCol ) const;
+ sal_Int32 GetRowPosition( sal_Int32 nRow ) const;
+
+ bool HasCellRotation() const;
+
+ const Cell* createOrFind(const Cell& rCell);
+};
+
+static void lclSetMergedRange( ArrayImpl& rImpl, CellVec& rCells, sal_Int32 nWidth, sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow )
+{
+ for( sal_Int32 nCol = nFirstCol; nCol <= nLastCol; ++nCol )
+ {
+ for( sal_Int32 nRow = nFirstRow; nRow <= nLastRow; ++nRow )
+ {
+ const Cell* pCell = rCells[ nRow * nWidth + nCol ];
+ Cell aTempCell(*pCell);
+ aTempCell.mbMergeOrig = false;
+ aTempCell.mbOverlapX = nCol > nFirstCol;
+ aTempCell.mbOverlapY = nRow > nFirstRow;
+ rCells[ nRow * nWidth + nCol ] = rImpl.createOrFind(aTempCell);
+ }
+ }
+ Cell aTempCell(*rCells[ nFirstRow * nWidth + nFirstCol ]);
+ aTempCell.mbMergeOrig = true;
+ rCells[ nFirstRow * nWidth + nFirstCol ] = rImpl.createOrFind(aTempCell);
+}
+
+ArrayImpl::ArrayImpl( sal_Int32 nWidth, sal_Int32 nHeight ) :
+ maRegisteredCells(),
+ mnWidth( nWidth ),
+ mnHeight( nHeight ),
+ mnFirstClipCol( 0 ),
+ mnFirstClipRow( 0 ),
+ mnLastClipCol( nWidth - 1 ),
+ mnLastClipRow( nHeight - 1 ),
+ mbXCoordsDirty( false ),
+ mbYCoordsDirty( false ),
+ mbMayHaveCellRotation( false )
+{
+ const Cell* pDefaultCell = createOrFind(Cell());
+ // default-construct all vectors
+ maCells.resize( mnWidth * mnHeight, pDefaultCell );
+ maWidths.resize( mnWidth, 0 );
+ maHeights.resize( mnHeight, 0 );
+ maXCoords.resize( mnWidth + 1, 0 );
+ maYCoords.resize( mnHeight + 1, 0 );
+}
+
+ArrayImpl::~ArrayImpl()
+{
+ for (auto* pCell : maRegisteredCells)
+ delete pCell;
+}
+
+const Cell* ArrayImpl::createOrFind(const Cell& rCell)
+{
+ auto it = maRegisteredCells.find(const_cast<Cell*>(&rCell));
+ if (it != maRegisteredCells.end())
+ return *it;
+
+ Cell* pRetval(new Cell(rCell));
+ maRegisteredCells.insert(pRetval);
+ return pRetval;
+}
+
+const Cell* ArrayImpl::GetCell( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ return IsValidPos( nCol, nRow ) ? maCells[ GetIndex( nCol, nRow ) ] : &OBJ_CELL_NONE;
+}
+
+void ArrayImpl::PutCell( sal_Int32 nCol, sal_Int32 nRow, const Cell & rCell )
+{
+ if (IsValidPos( nCol, nRow ))
+ maCells[ GetIndex( nCol, nRow ) ] = createOrFind(rCell);
+}
+
+sal_Int32 ArrayImpl::GetMergedFirstCol( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ sal_Int32 nFirstCol = nCol;
+ while( (nFirstCol > 0) && GetCell( nFirstCol, nRow )->mbOverlapX ) --nFirstCol;
+ return nFirstCol;
+}
+
+sal_Int32 ArrayImpl::GetMergedFirstRow( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ sal_Int32 nFirstRow = nRow;
+ while( (nFirstRow > 0) && GetCell( nCol, nFirstRow )->mbOverlapY ) --nFirstRow;
+ return nFirstRow;
+}
+
+sal_Int32 ArrayImpl::GetMergedLastCol( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ sal_Int32 nLastCol = nCol + 1;
+ while( (nLastCol < mnWidth) && GetCell( nLastCol, nRow )->mbOverlapX ) ++nLastCol;
+ return nLastCol - 1;
+}
+
+sal_Int32 ArrayImpl::GetMergedLastRow( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ sal_Int32 nLastRow = nRow + 1;
+ while( (nLastRow < mnHeight) && GetCell( nCol, nLastRow )->mbOverlapY ) ++nLastRow;
+ return nLastRow - 1;
+}
+
+const Cell* ArrayImpl::GetMergedOriginCell( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ return GetCell( GetMergedFirstCol( nCol, nRow ), GetMergedFirstRow( nCol, nRow ) );
+}
+
+const Cell* ArrayImpl::GetMergedLastCell( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ return GetCell( GetMergedLastCol( nCol, nRow ), GetMergedLastRow( nCol, nRow ) );
+}
+
+bool ArrayImpl::IsMergedOverlappedLeft( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ const Cell* pCell(GetCell( nCol, nRow ));
+ return pCell->mbOverlapX || (pCell->mnAddLeft > 0);
+}
+
+bool ArrayImpl::IsMergedOverlappedRight( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ return GetCell( nCol + 1, nRow )->mbOverlapX || (GetCell( nCol, nRow )->mnAddRight > 0);
+}
+
+bool ArrayImpl::IsMergedOverlappedTop( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ const Cell* pCell(GetCell( nCol, nRow ));
+ return pCell->mbOverlapY || (pCell->mnAddTop > 0);
+}
+
+bool ArrayImpl::IsMergedOverlappedBottom( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ return GetCell( nCol, nRow + 1 )->mbOverlapY || (GetCell( nCol, nRow )->mnAddBottom > 0);
+}
+
+bool ArrayImpl::IsColInClipRange( sal_Int32 nCol ) const
+{
+ return (mnFirstClipCol <= nCol) && (nCol <= mnLastClipCol);
+}
+
+bool ArrayImpl::IsRowInClipRange( sal_Int32 nRow ) const
+{
+ return (mnFirstClipRow <= nRow) && (nRow <= mnLastClipRow);
+}
+
+bool ArrayImpl::OverlapsClipRange( sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow ) const
+{
+ if(nLastCol < mnFirstClipCol)
+ return false;
+
+ if(nFirstCol > mnLastClipCol)
+ return false;
+
+ if(nLastRow < mnFirstClipRow)
+ return false;
+
+ if(nFirstRow > mnLastClipRow)
+ return false;
+
+ return true;
+}
+
+bool ArrayImpl::IsInClipRange( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ return IsColInClipRange( nCol ) && IsRowInClipRange( nRow );
+}
+
+sal_Int32 ArrayImpl::GetColPosition( sal_Int32 nCol ) const
+{
+ if( mbXCoordsDirty )
+ {
+ lclRecalcCoordVec( maXCoords, maWidths );
+ mbXCoordsDirty = false;
+ }
+ return maXCoords[ nCol ];
+}
+
+sal_Int32 ArrayImpl::GetRowPosition( sal_Int32 nRow ) const
+{
+ if( mbYCoordsDirty )
+ {
+ lclRecalcCoordVec( maYCoords, maHeights );
+ mbYCoordsDirty = false;
+ }
+ return maYCoords[ nRow ];
+}
+
+bool ArrayImpl::HasCellRotation() const
+{
+ // check cell array
+ for (const auto& aCell : maCells)
+ {
+ if (aCell->IsRotated())
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+namespace {
+
+class MergedCellIterator
+{
+public:
+ explicit MergedCellIterator( const Array& rArray, sal_Int32 nCol, sal_Int32 nRow );
+
+ bool Is() const { return (mnCol <= mnLastCol) && (mnRow <= mnLastRow); }
+ sal_Int32 Col() const { return mnCol; }
+ sal_Int32 Row() const { return mnRow; }
+
+ MergedCellIterator& operator++();
+
+private:
+ sal_Int32 mnFirstCol;
+ sal_Int32 mnFirstRow;
+ sal_Int32 mnLastCol;
+ sal_Int32 mnLastRow;
+ sal_Int32 mnCol;
+ sal_Int32 mnRow;
+};
+
+}
+
+MergedCellIterator::MergedCellIterator( const Array& rArray, sal_Int32 nCol, sal_Int32 nRow )
+{
+ rArray.GetMergedRange( mnFirstCol, mnFirstRow, mnLastCol, mnLastRow, nCol, nRow );
+ mnCol = mnFirstCol;
+ mnRow = mnFirstRow;
+}
+
+MergedCellIterator& MergedCellIterator::operator++()
+{
+ DBG_ASSERT( Is(), "svx::frame::MergedCellIterator::operator++() - already invalid" );
+ if( ++mnCol > mnLastCol )
+ {
+ mnCol = mnFirstCol;
+ ++mnRow;
+ }
+ return *this;
+}
+
+#define DBG_FRAME_CHECK( cond, funcname, error ) DBG_ASSERT( cond, "svx::frame::Array::" funcname " - " error )
+#define DBG_FRAME_CHECK_COL( col, funcname ) DBG_FRAME_CHECK( (col) < GetColCount(), funcname, "invalid column index" )
+#define DBG_FRAME_CHECK_ROW( row, funcname ) DBG_FRAME_CHECK( (row) < GetRowCount(), funcname, "invalid row index" )
+#define DBG_FRAME_CHECK_COLROW( col, row, funcname ) DBG_FRAME_CHECK( ((col) < GetColCount()) && ((row) < GetRowCount()), funcname, "invalid cell index" )
+#define DBG_FRAME_CHECK_COL_1( col, funcname ) DBG_FRAME_CHECK( (col) <= GetColCount(), funcname, "invalid column index" )
+#define DBG_FRAME_CHECK_ROW_1( row, funcname ) DBG_FRAME_CHECK( (row) <= GetRowCount(), funcname, "invalid row index" )
+
+Array::Array()
+{
+ Initialize( 0, 0 );
+}
+
+Array::~Array()
+{
+}
+
+// array size and column/row indexes
+void Array::Initialize( sal_Int32 nWidth, sal_Int32 nHeight )
+{
+ mxImpl.reset( new ArrayImpl( nWidth, nHeight ) );
+}
+
+sal_Int32 Array::GetColCount() const
+{
+ return mxImpl->mnWidth;
+}
+
+sal_Int32 Array::GetRowCount() const
+{
+ return mxImpl->mnHeight;
+}
+
+sal_Int32 Array::GetCellCount() const
+{
+ return mxImpl->maCells.size();
+}
+
+sal_Int32 Array::GetCellIndex( sal_Int32 nCol, sal_Int32 nRow, bool bRTL ) const
+{
+ DBG_FRAME_CHECK_COLROW( nCol, nRow, "GetCellIndex" );
+ if (bRTL)
+ nCol = mxImpl->GetMirrorCol(nCol);
+ return mxImpl->GetIndex( nCol, nRow );
+}
+
+// cell border styles
+void Array::SetCellStyleLeft( sal_Int32 nCol, sal_Int32 nRow, const Style& rStyle )
+{
+ DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleLeft" );
+ const Cell* pTempCell(mxImpl->GetCell(nCol, nRow));
+ if (pTempCell->GetStyleLeft() == rStyle)
+ return;
+ Cell aTempCell(*pTempCell);
+ aTempCell.SetStyleLeft(rStyle);
+ mxImpl->PutCell( nCol, nRow, aTempCell );
+}
+
+void Array::SetCellStyleRight( sal_Int32 nCol, sal_Int32 nRow, const Style& rStyle )
+{
+ DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleRight" );
+ const Cell* pTempCell(mxImpl->GetCell(nCol, nRow));
+ if (pTempCell->GetStyleRight() == rStyle)
+ return;
+ Cell aTempCell(*pTempCell);
+ aTempCell.SetStyleRight(rStyle);
+ mxImpl->PutCell( nCol, nRow, aTempCell );
+}
+
+void Array::SetCellStyleTop( sal_Int32 nCol, sal_Int32 nRow, const Style& rStyle )
+{
+ DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleTop" );
+ const Cell* pTempCell(mxImpl->GetCell(nCol, nRow));
+ if (pTempCell->GetStyleTop() == rStyle)
+ return;
+ Cell aTempCell(*pTempCell);
+ aTempCell.SetStyleTop(rStyle);
+ mxImpl->PutCell( nCol, nRow, aTempCell );
+}
+
+void Array::SetCellStyleBottom( sal_Int32 nCol, sal_Int32 nRow, const Style& rStyle )
+{
+ DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleBottom" );
+ const Cell* pTempCell(mxImpl->GetCell(nCol, nRow));
+ if (pTempCell->GetStyleBottom() == rStyle)
+ return;
+ Cell aTempCell(*pTempCell);
+ aTempCell.SetStyleBottom(rStyle);
+ mxImpl->PutCell( nCol, nRow, aTempCell );
+}
+
+void Array::SetCellStyleTLBR( sal_Int32 nCol, sal_Int32 nRow, const Style& rStyle )
+{
+ DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleTLBR" );
+ const Cell* pTempCell(mxImpl->GetCell(nCol, nRow));
+ if (pTempCell->GetStyleTLBR() == rStyle)
+ return;
+ Cell aTempCell(*pTempCell);
+ aTempCell.SetStyleTLBR(rStyle);
+ mxImpl->PutCell( nCol, nRow, aTempCell );
+}
+
+void Array::SetCellStyleBLTR( sal_Int32 nCol, sal_Int32 nRow, const Style& rStyle )
+{
+ DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleBLTR" );
+ const Cell* pTempCell(mxImpl->GetCell(nCol, nRow));
+ if (pTempCell->GetStyleBLTR() == rStyle)
+ return;
+ Cell aTempCell(*pTempCell);
+ aTempCell.SetStyleBLTR(rStyle);
+ mxImpl->PutCell( nCol, nRow, aTempCell );
+}
+
+void Array::SetCellStyleDiag( sal_Int32 nCol, sal_Int32 nRow, const Style& rTLBR, const Style& rBLTR )
+{
+ DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleDiag" );
+ const Cell* pTempCell(mxImpl->GetCell(nCol, nRow));
+ if (pTempCell->GetStyleTLBR() == rTLBR && pTempCell->GetStyleBLTR() == rBLTR)
+ return;
+ Cell aTempCell(*pTempCell);
+ aTempCell.SetStyleTLBR(rTLBR);
+ aTempCell.SetStyleBLTR(rBLTR);
+ mxImpl->PutCell( nCol, nRow, aTempCell );
+}
+
+void Array::SetColumnStyleLeft( sal_Int32 nCol, const Style& rStyle )
+{
+ DBG_FRAME_CHECK_COL( nCol, "SetColumnStyleLeft" );
+ for( sal_Int32 nRow = 0; nRow < mxImpl->mnHeight; ++nRow )
+ SetCellStyleLeft( nCol, nRow, rStyle );
+}
+
+void Array::SetColumnStyleRight( sal_Int32 nCol, const Style& rStyle )
+{
+ DBG_FRAME_CHECK_COL( nCol, "SetColumnStyleRight" );
+ for( sal_Int32 nRow = 0; nRow < mxImpl->mnHeight; ++nRow )
+ SetCellStyleRight( nCol, nRow, rStyle );
+}
+
+void Array::SetRowStyleTop( sal_Int32 nRow, const Style& rStyle )
+{
+ DBG_FRAME_CHECK_ROW( nRow, "SetRowStyleTop" );
+ for( sal_Int32 nCol = 0; nCol < mxImpl->mnWidth; ++nCol )
+ SetCellStyleTop( nCol, nRow, rStyle );
+}
+
+void Array::SetRowStyleBottom( sal_Int32 nRow, const Style& rStyle )
+{
+ DBG_FRAME_CHECK_ROW( nRow, "SetRowStyleBottom" );
+ for( sal_Int32 nCol = 0; nCol < mxImpl->mnWidth; ++nCol )
+ SetCellStyleBottom( nCol, nRow, rStyle );
+}
+
+void Array::SetCellRotation(sal_Int32 nCol, sal_Int32 nRow, SvxRotateMode eRotMode, double fOrientation)
+{
+ DBG_FRAME_CHECK_COLROW(nCol, nRow, "SetCellRotation");
+ const Cell* pTempCell(mxImpl->GetCell(nCol, nRow));
+ if (pTempCell->meRotMode == eRotMode && pTempCell->mfOrientation == fOrientation)
+ return;
+ Cell aTempCell(*pTempCell);
+ aTempCell.meRotMode = eRotMode;
+ aTempCell.mfOrientation = fOrientation;
+ mxImpl->PutCell( nCol, nRow, aTempCell );
+
+ if (!mxImpl->mbMayHaveCellRotation)
+ {
+ // activate once when a cell gets actually rotated to allow fast
+ // answering HasCellRotation() calls
+ mxImpl->mbMayHaveCellRotation = aTempCell.IsRotated();
+ }
+}
+
+bool Array::HasCellRotation() const
+{
+ if (!mxImpl->mbMayHaveCellRotation)
+ {
+ // never set, no need to check
+ return false;
+ }
+
+ return mxImpl->HasCellRotation();
+}
+
+const Style& Array::GetCellStyleLeft( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ // outside clipping rows or overlapped in merged cells: invisible
+ if( !mxImpl->IsRowInClipRange( nRow ) || mxImpl->IsMergedOverlappedLeft( nCol, nRow ) )
+ return OBJ_STYLE_NONE;
+ // left clipping border: always own left style
+ if( nCol == mxImpl->mnFirstClipCol )
+ return mxImpl->GetMergedOriginCell( nCol, nRow )->GetStyleLeft();
+ // right clipping border: always right style of left neighbor cell
+ if( nCol == mxImpl->mnLastClipCol + 1 )
+ return mxImpl->GetMergedOriginCell( nCol - 1, nRow )->GetStyleRight();
+ // outside clipping columns: invisible
+ if( !mxImpl->IsColInClipRange( nCol ) )
+ return OBJ_STYLE_NONE;
+ // inside clipping range: maximum of own left style and right style of left neighbor cell
+ return std::max( mxImpl->GetMergedOriginCell( nCol, nRow )->GetStyleLeft(), mxImpl->GetMergedOriginCell( nCol - 1, nRow )->GetStyleRight() );
+}
+
+const Style& Array::GetCellStyleRight( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ // outside clipping rows or overlapped in merged cells: invisible
+ if( !mxImpl->IsRowInClipRange( nRow ) || mxImpl->IsMergedOverlappedRight( nCol, nRow ) )
+ return OBJ_STYLE_NONE;
+ // left clipping border: always left style of right neighbor cell
+ if( nCol + 1 == mxImpl->mnFirstClipCol )
+ return mxImpl->GetMergedOriginCell( nCol + 1, nRow )->GetStyleLeft();
+ // right clipping border: always own right style
+ if( nCol == mxImpl->mnLastClipCol )
+ return mxImpl->GetMergedLastCell( nCol, nRow )->GetStyleRight();
+ // outside clipping columns: invisible
+ if( !mxImpl->IsColInClipRange( nCol ) )
+ return OBJ_STYLE_NONE;
+ // inside clipping range: maximum of own right style and left style of right neighbor cell
+ return std::max( mxImpl->GetMergedOriginCell( nCol, nRow )->GetStyleRight(), mxImpl->GetMergedOriginCell( nCol + 1, nRow )->GetStyleLeft() );
+}
+
+const Style& Array::GetCellStyleTop( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ // outside clipping columns or overlapped in merged cells: invisible
+ if( !mxImpl->IsColInClipRange( nCol ) || mxImpl->IsMergedOverlappedTop( nCol, nRow ) )
+ return OBJ_STYLE_NONE;
+ // top clipping border: always own top style
+ if( nRow == mxImpl->mnFirstClipRow )
+ return mxImpl->GetMergedOriginCell( nCol, nRow )->GetStyleTop();
+ // bottom clipping border: always bottom style of top neighbor cell
+ if( nRow == mxImpl->mnLastClipRow + 1 )
+ return mxImpl->GetMergedOriginCell( nCol, nRow - 1 )->GetStyleBottom();
+ // outside clipping rows: invisible
+ if( !mxImpl->IsRowInClipRange( nRow ) )
+ return OBJ_STYLE_NONE;
+ // inside clipping range: maximum of own top style and bottom style of top neighbor cell
+ return std::max( mxImpl->GetMergedOriginCell( nCol, nRow )->GetStyleTop(), mxImpl->GetMergedOriginCell( nCol, nRow - 1 )->GetStyleBottom() );
+}
+
+const Style& Array::GetCellStyleBottom( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ // outside clipping columns or overlapped in merged cells: invisible
+ if( !mxImpl->IsColInClipRange( nCol ) || mxImpl->IsMergedOverlappedBottom( nCol, nRow ) )
+ return OBJ_STYLE_NONE;
+ // top clipping border: always top style of bottom neighbor cell
+ if( nRow + 1 == mxImpl->mnFirstClipRow )
+ return mxImpl->GetMergedOriginCell( nCol, nRow + 1 )->GetStyleTop();
+ // bottom clipping border: always own bottom style
+ if( nRow == mxImpl->mnLastClipRow )
+ return mxImpl->GetMergedLastCell( nCol, nRow )->GetStyleBottom();
+ // outside clipping rows: invisible
+ if( !mxImpl->IsRowInClipRange( nRow ) )
+ return OBJ_STYLE_NONE;
+ // inside clipping range: maximum of own bottom style and top style of bottom neighbor cell
+ return std::max( mxImpl->GetMergedOriginCell( nCol, nRow )->GetStyleBottom(), mxImpl->GetMergedOriginCell( nCol, nRow + 1 )->GetStyleTop() );
+}
+
+const Style& Array::GetCellStyleTLBR( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ return mxImpl->GetCell( nCol, nRow )->GetStyleTLBR();
+}
+
+const Style& Array::GetCellStyleBLTR( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ return mxImpl->GetCell( nCol, nRow )->GetStyleBLTR();
+}
+
+const Style& Array::GetCellStyleTL( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ // not in clipping range: always invisible
+ if( !mxImpl->IsInClipRange( nCol, nRow ) )
+ return OBJ_STYLE_NONE;
+ // return style only for top-left cell
+ sal_Int32 nFirstCol = mxImpl->GetMergedFirstCol( nCol, nRow );
+ sal_Int32 nFirstRow = mxImpl->GetMergedFirstRow( nCol, nRow );
+ return ((nCol == nFirstCol) && (nRow == nFirstRow)) ?
+ mxImpl->GetCell( nFirstCol, nFirstRow )->GetStyleTLBR() : OBJ_STYLE_NONE;
+}
+
+const Style& Array::GetCellStyleBR( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ // not in clipping range: always invisible
+ if( !mxImpl->IsInClipRange( nCol, nRow ) )
+ return OBJ_STYLE_NONE;
+ // return style only for bottom-right cell
+ sal_Int32 nLastCol = mxImpl->GetMergedLastCol( nCol, nRow );
+ sal_Int32 nLastRow = mxImpl->GetMergedLastRow( nCol, nRow );
+ return ((nCol == nLastCol) && (nRow == nLastRow)) ?
+ mxImpl->GetCell( mxImpl->GetMergedFirstCol( nCol, nRow ), mxImpl->GetMergedFirstRow( nCol, nRow ) )->GetStyleTLBR() : OBJ_STYLE_NONE;
+}
+
+const Style& Array::GetCellStyleBL( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ // not in clipping range: always invisible
+ if( !mxImpl->IsInClipRange( nCol, nRow ) )
+ return OBJ_STYLE_NONE;
+ // return style only for bottom-left cell
+ sal_Int32 nFirstCol = mxImpl->GetMergedFirstCol( nCol, nRow );
+ sal_Int32 nLastRow = mxImpl->GetMergedLastRow( nCol, nRow );
+ return ((nCol == nFirstCol) && (nRow == nLastRow)) ?
+ mxImpl->GetCell( nFirstCol, mxImpl->GetMergedFirstRow( nCol, nRow ) )->GetStyleBLTR() : OBJ_STYLE_NONE;
+}
+
+const Style& Array::GetCellStyleTR( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ // not in clipping range: always invisible
+ if( !mxImpl->IsInClipRange( nCol, nRow ) )
+ return OBJ_STYLE_NONE;
+ // return style only for top-right cell
+ sal_Int32 nFirstRow = mxImpl->GetMergedFirstRow( nCol, nRow );
+ sal_Int32 nLastCol = mxImpl->GetMergedLastCol( nCol, nRow );
+ return ((nCol == nLastCol) && (nRow == nFirstRow)) ?
+ mxImpl->GetCell( mxImpl->GetMergedFirstCol( nCol, nRow ), nFirstRow )->GetStyleBLTR() : OBJ_STYLE_NONE;
+}
+
+// cell merging
+void Array::SetMergedRange( sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow )
+{
+ DBG_FRAME_CHECK_COLROW( nFirstCol, nFirstRow, "SetMergedRange" );
+ DBG_FRAME_CHECK_COLROW( nLastCol, nLastRow, "SetMergedRange" );
+#if OSL_DEBUG_LEVEL >= 2
+ {
+ bool bFound = false;
+ for( sal_Int32 nCurrCol = nFirstCol; !bFound && (nCurrCol <= nLastCol); ++nCurrCol )
+ for( sal_Int32 nCurrRow = nFirstRow; !bFound && (nCurrRow <= nLastRow); ++nCurrRow )
+ bFound = mxImpl->GetCell( nCurrCol, nCurrRow )->IsMerged();
+ DBG_FRAME_CHECK( !bFound, "SetMergedRange", "overlapping merged ranges" );
+ }
+#endif
+ if( mxImpl->IsValidPos( nFirstCol, nFirstRow ) && mxImpl->IsValidPos( nLastCol, nLastRow ) )
+ lclSetMergedRange( *mxImpl, mxImpl->maCells, mxImpl->mnWidth, nFirstCol, nFirstRow, nLastCol, nLastRow );
+}
+
+void Array::SetAddMergedLeftSize( sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nAddSize )
+{
+ DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetAddMergedLeftSize" );
+ DBG_FRAME_CHECK( mxImpl->GetMergedFirstCol( nCol, nRow ) == 0, "SetAddMergedLeftSize", "additional border inside array" );
+ for( MergedCellIterator aIt( *this, nCol, nRow ); aIt.Is(); ++aIt )
+ {
+ const Cell* pTempCell(mxImpl->GetCell(aIt.Col(), aIt.Row()));
+ if (pTempCell->mnAddLeft == nAddSize)
+ return;
+ Cell aTempCell(*pTempCell);
+ aTempCell.mnAddLeft = nAddSize;
+ mxImpl->PutCell( nCol, nRow, aTempCell );
+ }
+}
+
+void Array::SetAddMergedRightSize( sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nAddSize )
+{
+ DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetAddMergedRightSize" );
+ DBG_FRAME_CHECK( mxImpl->GetMergedLastCol( nCol, nRow ) + 1 == mxImpl->mnWidth, "SetAddMergedRightSize", "additional border inside array" );
+ for( MergedCellIterator aIt( *this, nCol, nRow ); aIt.Is(); ++aIt )
+ {
+ const Cell* pTempCell(mxImpl->GetCell(aIt.Col(), aIt.Row()));
+ if (pTempCell->mnAddRight == nAddSize)
+ return;
+ Cell aTempCell(*pTempCell);
+ aTempCell.mnAddRight = nAddSize;
+ mxImpl->PutCell( nCol, nRow, aTempCell );
+ }
+}
+
+void Array::SetAddMergedTopSize( sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nAddSize )
+{
+ DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetAddMergedTopSize" );
+ DBG_FRAME_CHECK( mxImpl->GetMergedFirstRow( nCol, nRow ) == 0, "SetAddMergedTopSize", "additional border inside array" );
+ for( MergedCellIterator aIt( *this, nCol, nRow ); aIt.Is(); ++aIt )
+ {
+ const Cell* pTempCell(mxImpl->GetCell(aIt.Col(), aIt.Row()));
+ if (pTempCell->mnAddTop == nAddSize)
+ return;
+ Cell aTempCell(*pTempCell);
+ aTempCell.mnAddTop = nAddSize;
+ mxImpl->PutCell( nCol, nRow, aTempCell );
+ }
+}
+
+void Array::SetAddMergedBottomSize( sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nAddSize )
+{
+ DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetAddMergedBottomSize" );
+ DBG_FRAME_CHECK( mxImpl->GetMergedLastRow( nCol, nRow ) + 1 == mxImpl->mnHeight, "SetAddMergedBottomSize", "additional border inside array" );
+ for( MergedCellIterator aIt( *this, nCol, nRow ); aIt.Is(); ++aIt )
+ {
+ const Cell* pTempCell(mxImpl->GetCell(aIt.Col(), aIt.Row()));
+ if (pTempCell->mnAddBottom == nAddSize)
+ return;
+ Cell aTempCell(*pTempCell);
+ aTempCell.mnAddBottom = nAddSize;
+ mxImpl->PutCell( nCol, nRow, aTempCell );
+ }
+}
+
+bool Array::IsMerged( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ DBG_FRAME_CHECK_COLROW( nCol, nRow, "IsMerged" );
+ return mxImpl->GetCell( nCol, nRow )->IsMerged();
+}
+
+void Array::GetMergedOrigin( sal_Int32& rnFirstCol, sal_Int32& rnFirstRow, sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ DBG_FRAME_CHECK_COLROW( nCol, nRow, "GetMergedOrigin" );
+ rnFirstCol = mxImpl->GetMergedFirstCol( nCol, nRow );
+ rnFirstRow = mxImpl->GetMergedFirstRow( nCol, nRow );
+}
+
+void Array::GetMergedRange( sal_Int32& rnFirstCol, sal_Int32& rnFirstRow,
+ sal_Int32& rnLastCol, sal_Int32& rnLastRow, sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ GetMergedOrigin( rnFirstCol, rnFirstRow, nCol, nRow );
+ rnLastCol = mxImpl->GetMergedLastCol( nCol, nRow );
+ rnLastRow = mxImpl->GetMergedLastRow( nCol, nRow );
+}
+
+// clipping
+void Array::SetClipRange( sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow )
+{
+ DBG_FRAME_CHECK_COLROW( nFirstCol, nFirstRow, "SetClipRange" );
+ DBG_FRAME_CHECK_COLROW( nLastCol, nLastRow, "SetClipRange" );
+ mxImpl->mnFirstClipCol = nFirstCol;
+ mxImpl->mnFirstClipRow = nFirstRow;
+ mxImpl->mnLastClipCol = nLastCol;
+ mxImpl->mnLastClipRow = nLastRow;
+}
+
+// cell coordinates
+void Array::SetXOffset( sal_Int32 nXOffset )
+{
+ mxImpl->maXCoords[ 0 ] = nXOffset;
+ mxImpl->mbXCoordsDirty = true;
+}
+
+void Array::SetYOffset( sal_Int32 nYOffset )
+{
+ mxImpl->maYCoords[ 0 ] = nYOffset;
+ mxImpl->mbYCoordsDirty = true;
+}
+
+void Array::SetColWidth( sal_Int32 nCol, sal_Int32 nWidth )
+{
+ DBG_FRAME_CHECK_COL( nCol, "SetColWidth" );
+ mxImpl->maWidths[ nCol ] = nWidth;
+ mxImpl->mbXCoordsDirty = true;
+}
+
+void Array::SetRowHeight( sal_Int32 nRow, sal_Int32 nHeight )
+{
+ DBG_FRAME_CHECK_ROW( nRow, "SetRowHeight" );
+ mxImpl->maHeights[ nRow ] = nHeight;
+ mxImpl->mbYCoordsDirty = true;
+}
+
+void Array::SetAllColWidths( sal_Int32 nWidth )
+{
+ std::fill( mxImpl->maWidths.begin(), mxImpl->maWidths.end(), nWidth );
+ mxImpl->mbXCoordsDirty = true;
+}
+
+void Array::SetAllRowHeights( sal_Int32 nHeight )
+{
+ std::fill( mxImpl->maHeights.begin(), mxImpl->maHeights.end(), nHeight );
+ mxImpl->mbYCoordsDirty = true;
+}
+
+sal_Int32 Array::GetColPosition( sal_Int32 nCol ) const
+{
+ DBG_FRAME_CHECK_COL_1( nCol, "GetColPosition" );
+ return mxImpl->GetColPosition( nCol );
+}
+
+sal_Int32 Array::GetRowPosition( sal_Int32 nRow ) const
+{
+ DBG_FRAME_CHECK_ROW_1( nRow, "GetRowPosition" );
+ return mxImpl->GetRowPosition( nRow );
+}
+
+sal_Int32 Array::GetColWidth( sal_Int32 nFirstCol, sal_Int32 nLastCol ) const
+{
+ DBG_FRAME_CHECK_COL( nFirstCol, "GetColWidth" );
+ DBG_FRAME_CHECK_COL( nLastCol, "GetColWidth" );
+ return GetColPosition( nLastCol + 1 ) - GetColPosition( nFirstCol );
+}
+
+sal_Int32 Array::GetRowHeight( sal_Int32 nFirstRow, sal_Int32 nLastRow ) const
+{
+ DBG_FRAME_CHECK_ROW( nFirstRow, "GetRowHeight" );
+ DBG_FRAME_CHECK_ROW( nLastRow, "GetRowHeight" );
+ return GetRowPosition( nLastRow + 1 ) - GetRowPosition( nFirstRow );
+}
+
+sal_Int32 Array::GetWidth() const
+{
+ return GetColPosition( mxImpl->mnWidth ) - GetColPosition( 0 );
+}
+
+sal_Int32 Array::GetHeight() const
+{
+ return GetRowPosition( mxImpl->mnHeight ) - GetRowPosition( 0 );
+}
+
+basegfx::B2DRange Array::GetCellRange( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ // get the Range of the fully expanded cell (if merged)
+ const sal_Int32 nFirstCol(mxImpl->GetMergedFirstCol( nCol, nRow ));
+ const sal_Int32 nFirstRow(mxImpl->GetMergedFirstRow( nCol, nRow ));
+ const sal_Int32 nLastCol(mxImpl->GetMergedLastCol( nCol, nRow ));
+ const sal_Int32 nLastRow(mxImpl->GetMergedLastRow( nCol, nRow ));
+ const Point aPoint( GetColPosition( nFirstCol ), GetRowPosition( nFirstRow ) );
+ const Size aSize( GetColWidth( nFirstCol, nLastCol ) + 1, GetRowHeight( nFirstRow, nLastRow ) + 1 );
+ tools::Rectangle aRect(aPoint, aSize);
+
+ // adjust rectangle for partly visible merged cells
+ const Cell* pCell(mxImpl->GetCell( nCol, nRow ));
+
+ if( pCell->IsMerged() )
+ {
+ // not *sure* what exactly this is good for,
+ // it is just a hard set extension at merged cells,
+ // probably *should* be included in the above extended
+ // GetColPosition/GetColWidth already. This might be
+ // added due to GetColPosition/GetColWidth not working
+ // correctly over PageChanges (if used), but not sure.
+ aRect.AdjustLeft( -(pCell->mnAddLeft) );
+ aRect.AdjustRight(pCell->mnAddRight );
+ aRect.AdjustTop( -(pCell->mnAddTop) );
+ aRect.AdjustBottom(pCell->mnAddBottom );
+ }
+
+ return vcl::unotools::b2DRectangleFromRectangle(aRect);
+}
+
+// return output range of given row/col range in logical coordinates
+basegfx::B2DRange Array::GetB2DRange(sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow) const
+{
+ const Point aPoint( GetColPosition( nFirstCol ), GetRowPosition( nFirstRow ) );
+ const Size aSize( GetColWidth( nFirstCol, nLastCol ) + 1, GetRowHeight( nFirstRow, nLastRow ) + 1 );
+
+ return vcl::unotools::b2DRectangleFromRectangle(tools::Rectangle(aPoint, aSize));
+}
+
+// mirroring
+void Array::MirrorSelfX()
+{
+ CellVec aNewCells;
+ aNewCells.reserve( GetCellCount() );
+
+ sal_Int32 nCol, nRow;
+ for( nRow = 0; nRow < mxImpl->mnHeight; ++nRow )
+ {
+ for( nCol = 0; nCol < mxImpl->mnWidth; ++nCol )
+ {
+ Cell aTempCell(*mxImpl->GetCell(mxImpl->GetMirrorCol( nCol ), nRow));
+ aTempCell.MirrorSelfX();
+ aNewCells.push_back( mxImpl->createOrFind(aTempCell) );
+ }
+ }
+ for( nRow = 0; nRow < mxImpl->mnHeight; ++nRow )
+ {
+ for( nCol = 0; nCol < mxImpl->mnWidth; ++nCol )
+ {
+ if( mxImpl->GetCell( nCol, nRow )->mbMergeOrig )
+ {
+ sal_Int32 nLastCol = mxImpl->GetMergedLastCol( nCol, nRow );
+ sal_Int32 nLastRow = mxImpl->GetMergedLastRow( nCol, nRow );
+ lclSetMergedRange( *mxImpl, aNewCells, mxImpl->mnWidth,
+ mxImpl->GetMirrorCol( nLastCol ), nRow,
+ mxImpl->GetMirrorCol( nCol ), nLastRow );
+ }
+ }
+ }
+ mxImpl->maCells.swap( aNewCells );
+
+ std::reverse( mxImpl->maWidths.begin(), mxImpl->maWidths.end() );
+ mxImpl->mbXCoordsDirty = true;
+}
+
+// drawing
+static void HelperCreateHorizontalEntry(
+ const Array& rArray,
+ const Style& rStyle,
+ sal_Int32 col,
+ sal_Int32 row,
+ const basegfx::B2DPoint& rOrigin,
+ const basegfx::B2DVector& rX,
+ const basegfx::B2DVector& rY,
+ drawinglayer::primitive2d::SdrFrameBorderDataVector& rData,
+ bool bUpper,
+ const Color* pForceColor)
+{
+ // prepare SdrFrameBorderData
+ rData.emplace_back(
+ bUpper ? rOrigin : basegfx::B2DPoint(rOrigin + rY),
+ rX,
+ rStyle,
+ pForceColor);
+ drawinglayer::primitive2d::SdrFrameBorderData& rInstance(rData.back());
+
+ // get involved styles at start
+ const Style& rStartFromTR(rArray.GetCellStyleBL( col, row - 1 ));
+ const Style& rStartLFromT(rArray.GetCellStyleLeft( col, row - 1 ));
+ const Style& rStartLFromL(rArray.GetCellStyleTop( col - 1, row ));
+ const Style& rStartLFromB(rArray.GetCellStyleLeft( col, row ));
+ const Style& rStartFromBR(rArray.GetCellStyleTL( col, row ));
+
+ rInstance.addSdrConnectStyleData(true, rStartFromTR, rX - rY, false);
+ rInstance.addSdrConnectStyleData(true, rStartLFromT, -rY, true);
+ rInstance.addSdrConnectStyleData(true, rStartLFromL, -rX, true);
+ rInstance.addSdrConnectStyleData(true, rStartLFromB, rY, false);
+ rInstance.addSdrConnectStyleData(true, rStartFromBR, rX + rY, false);
+
+ // get involved styles at end
+ const Style& rEndFromTL(rArray.GetCellStyleBR( col, row - 1 ));
+ const Style& rEndRFromT(rArray.GetCellStyleRight( col, row - 1 ));
+ const Style& rEndRFromR(rArray.GetCellStyleTop( col + 1, row ));
+ const Style& rEndRFromB(rArray.GetCellStyleRight( col, row ));
+ const Style& rEndFromBL(rArray.GetCellStyleTR( col, row ));
+
+ rInstance.addSdrConnectStyleData(false, rEndFromTL, -rX - rY, true);
+ rInstance.addSdrConnectStyleData(false, rEndRFromT, -rY, true);
+ rInstance.addSdrConnectStyleData(false, rEndRFromR, rX, false);
+ rInstance.addSdrConnectStyleData(false, rEndRFromB, rY, false);
+ rInstance.addSdrConnectStyleData(false, rEndFromBL, rY - rX, true);
+}
+
+static void HelperCreateVerticalEntry(
+ const Array& rArray,
+ const Style& rStyle,
+ sal_Int32 col,
+ sal_Int32 row,
+ const basegfx::B2DPoint& rOrigin,
+ const basegfx::B2DVector& rX,
+ const basegfx::B2DVector& rY,
+ drawinglayer::primitive2d::SdrFrameBorderDataVector& rData,
+ bool bLeft,
+ const Color* pForceColor)
+{
+ // prepare SdrFrameBorderData
+ rData.emplace_back(
+ bLeft ? rOrigin : basegfx::B2DPoint(rOrigin + rX),
+ rY,
+ rStyle,
+ pForceColor);
+ drawinglayer::primitive2d::SdrFrameBorderData& rInstance(rData.back());
+
+ // get involved styles at start
+ const Style& rStartFromBL(rArray.GetCellStyleTR( col - 1, row ));
+ const Style& rStartTFromL(rArray.GetCellStyleTop( col - 1, row ));
+ const Style& rStartTFromT(rArray.GetCellStyleLeft( col, row - 1 ));
+ const Style& rStartTFromR(rArray.GetCellStyleTop( col, row ));
+ const Style& rStartFromBR(rArray.GetCellStyleTL( col, row ));
+
+ rInstance.addSdrConnectStyleData(true, rStartFromBR, rX + rY, false);
+ rInstance.addSdrConnectStyleData(true, rStartTFromR, rX, false);
+ rInstance.addSdrConnectStyleData(true, rStartTFromT, -rY, true);
+ rInstance.addSdrConnectStyleData(true, rStartTFromL, -rX, true);
+ rInstance.addSdrConnectStyleData(true, rStartFromBL, rY - rX, true);
+
+ // get involved styles at end
+ const Style& rEndFromTL(rArray.GetCellStyleBR( col - 1, row ));
+ const Style& rEndBFromL(rArray.GetCellStyleBottom( col - 1, row ));
+ const Style& rEndBFromB(rArray.GetCellStyleLeft( col, row + 1 ));
+ const Style& rEndBFromR(rArray.GetCellStyleBottom( col, row ));
+ const Style& rEndFromTR(rArray.GetCellStyleBL( col, row ));
+
+ rInstance.addSdrConnectStyleData(false, rEndFromTR, rX - rY, false);
+ rInstance.addSdrConnectStyleData(false, rEndBFromR, rX, false);
+ rInstance.addSdrConnectStyleData(false, rEndBFromB, rY, false);
+ rInstance.addSdrConnectStyleData(false, rEndBFromL, -rX, true);
+ rInstance.addSdrConnectStyleData(false, rEndFromTL, -rY - rX, true);
+}
+
+static void HelperClipLine(
+ basegfx::B2DPoint& rStart,
+ basegfx::B2DVector& rDirection,
+ const basegfx::B2DRange& rClipRange)
+{
+ basegfx::B2DPolygon aLine({rStart, rStart + rDirection});
+ const basegfx::B2DPolyPolygon aResultPP(
+ basegfx::utils::clipPolygonOnRange(
+ aLine,
+ rClipRange,
+ true, // bInside
+ true)); // bStroke
+
+ if(aResultPP.count() > 0)
+ {
+ const basegfx::B2DPolygon aResultP(aResultPP.getB2DPolygon(0));
+
+ if(aResultP.count() > 0)
+ {
+ const basegfx::B2DPoint aResultStart(aResultP.getB2DPoint(0));
+ const basegfx::B2DPoint aResultEnd(aResultP.getB2DPoint(aResultP.count() - 1));
+
+ if(aResultStart != aResultEnd)
+ {
+ rStart = aResultStart;
+ rDirection = aResultEnd - aResultStart;
+ }
+ }
+ }
+}
+
+static void HelperCreateTLBREntry(
+ const Array& rArray,
+ const Style& rStyle,
+ drawinglayer::primitive2d::SdrFrameBorderDataVector& rData,
+ const basegfx::B2DPoint& rOrigin,
+ const basegfx::B2DVector& rX,
+ const basegfx::B2DVector& rY,
+ sal_Int32 nColLeft,
+ sal_Int32 nColRight,
+ sal_Int32 nRowTop,
+ sal_Int32 nRowBottom,
+ const Color* pForceColor,
+ const basegfx::B2DRange* pClipRange)
+{
+ if(rStyle.IsUsed())
+ {
+ /// prepare geometry line data
+ basegfx::B2DPoint aStart(rOrigin);
+ basegfx::B2DVector aDirection(rX + rY);
+
+ /// check if we need to clip geometry line data and do it
+ if(nullptr != pClipRange)
+ {
+ HelperClipLine(aStart, aDirection, *pClipRange);
+ }
+
+ /// top-left and bottom-right Style Tables
+ rData.emplace_back(
+ aStart,
+ aDirection,
+ rStyle,
+ pForceColor);
+ drawinglayer::primitive2d::SdrFrameBorderData& rInstance(rData.back());
+
+ /// Fill top-left Style Table
+ const Style& rTLFromRight(rArray.GetCellStyleTop(nColLeft, nRowTop));
+ const Style& rTLFromBottom(rArray.GetCellStyleLeft(nColLeft, nRowTop));
+
+ rInstance.addSdrConnectStyleData(true, rTLFromRight, rX, false);
+ rInstance.addSdrConnectStyleData(true, rTLFromBottom, rY, false);
+
+ /// Fill bottom-right Style Table
+ const Style& rBRFromBottom(rArray.GetCellStyleRight(nColRight, nRowBottom));
+ const Style& rBRFromLeft(rArray.GetCellStyleBottom(nColRight, nRowBottom));
+
+ rInstance.addSdrConnectStyleData(false, rBRFromBottom, -rY, true);
+ rInstance.addSdrConnectStyleData(false, rBRFromLeft, -rX, true);
+ }
+}
+
+static void HelperCreateBLTREntry(
+ const Array& rArray,
+ const Style& rStyle,
+ drawinglayer::primitive2d::SdrFrameBorderDataVector& rData,
+ const basegfx::B2DPoint& rOrigin,
+ const basegfx::B2DVector& rX,
+ const basegfx::B2DVector& rY,
+ sal_Int32 nColLeft,
+ sal_Int32 nColRight,
+ sal_Int32 nRowTop,
+ sal_Int32 nRowBottom,
+ const Color* pForceColor,
+ const basegfx::B2DRange* pClipRange)
+{
+ if(rStyle.IsUsed())
+ {
+ /// prepare geometry line data
+ basegfx::B2DPoint aStart(rOrigin + rY);
+ basegfx::B2DVector aDirection(rX - rY);
+
+ /// check if we need to clip geometry line data and do it
+ if(nullptr != pClipRange)
+ {
+ HelperClipLine(aStart, aDirection, *pClipRange);
+ }
+
+ /// bottom-left and top-right Style Tables
+ rData.emplace_back(
+ aStart,
+ aDirection,
+ rStyle,
+ pForceColor);
+ drawinglayer::primitive2d::SdrFrameBorderData& rInstance(rData.back());
+
+ /// Fill bottom-left Style Table
+ const Style& rBLFromTop(rArray.GetCellStyleLeft(nColLeft, nRowBottom));
+ const Style& rBLFromBottom(rArray.GetCellStyleBottom(nColLeft, nRowBottom));
+
+ rInstance.addSdrConnectStyleData(true, rBLFromTop, -rY, true);
+ rInstance.addSdrConnectStyleData(true, rBLFromBottom, rX, false);
+
+ /// Fill top-right Style Table
+ const Style& rTRFromLeft(rArray.GetCellStyleTop(nColRight, nRowTop));
+ const Style& rTRFromBottom(rArray.GetCellStyleRight(nColRight, nRowTop));
+
+ rInstance.addSdrConnectStyleData(false, rTRFromLeft, -rX, true);
+ rInstance.addSdrConnectStyleData(false, rTRFromBottom, rY, false);
+ }
+}
+
+drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange(
+ sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow,
+ const Color* pForceColor ) const
+{
+ DBG_FRAME_CHECK_COLROW( nFirstCol, nFirstRow, "CreateB2DPrimitiveRange" );
+ DBG_FRAME_CHECK_COLROW( nLastCol, nLastRow, "CreateB2DPrimitiveRange" );
+
+#ifdef OPTICAL_CHECK_CLIPRANGE_FOR_MERGED_CELL
+ std::vector<basegfx::B2DRange> aClipRanges;
+#endif
+
+ // It may be necessary to extend the loop ranges by one cell to the outside,
+ // when possible. This is needed e.g. when there is in Calc a Cell with an
+ // upper CellBorder using DoubleLine and that is right/left connected upwards
+ // to also DoubleLine. These upper DoubleLines will be extended to meet the
+ // lower of the upper CellBorder and thus have graphical parts that are
+ // displayed one cell below and right/left of the target cell - analog to
+ // other examples in all other directions.
+ // It would be possible to explicitly test this (if possible by indices at all)
+ // looping and testing the styles in the outer cells to detect this, but since
+ // for other usages (e.g. UI) usually nFirstRow==0 and nLastRow==GetRowCount()-1
+ // (and analog for Col) it is okay to just expand the range when available.
+ // Do *not* change nFirstRow/nLastRow due to these needed to the boolean tests
+ // below (!)
+ // Checked usages, this method is used in Calc EditView/Print/Export stuff and
+ // in UI (Dialog), not for Writer Tables and Draw/Impress tables. All usages
+ // seem okay with this change, so I will add it.
+ const sal_Int32 nStartRow(nFirstRow > 0 ? nFirstRow - 1 : nFirstRow);
+ const sal_Int32 nEndRow(nLastRow < GetRowCount() - 1 ? nLastRow + 1 : nLastRow);
+ const sal_Int32 nStartCol(nFirstCol > 0 ? nFirstCol - 1 : nFirstCol);
+ const sal_Int32 nEndCol(nLastCol < GetColCount() - 1 ? nLastCol + 1 : nLastCol);
+
+ // prepare SdrFrameBorderDataVector
+ drawinglayer::primitive2d::SdrFrameBorderDataVector aData;
+
+ // remember for which merged cells crossed lines were already created. To
+ // do so, hold the sal_Int32 cell index in a set for fast check
+ std::unordered_set< sal_Int32 > aMergedCells;
+
+ for (sal_Int32 nRow(nStartRow); nRow <= nEndRow; ++nRow)
+ {
+ for (sal_Int32 nCol(nStartCol); nCol <= nEndCol; ++nCol)
+ {
+ // get Cell and CoordinateSystem (*only* for this Cell, do *not* expand for
+ // merged cells (!)), check if used (non-empty vectors)
+ const Cell* pCell(mxImpl->GetCell(nCol, nRow));
+ basegfx::B2DHomMatrix aCoordinateSystem(pCell->CreateCoordinateSystemSingleCell(*this, nCol, nRow));
+ basegfx::B2DVector aX(basegfx::utils::getColumn(aCoordinateSystem, 0));
+ basegfx::B2DVector aY(basegfx::utils::getColumn(aCoordinateSystem, 1));
+
+ // get needed local values
+ basegfx::B2DPoint aOrigin(basegfx::utils::getColumn(aCoordinateSystem, 2));
+ const bool bOverlapX(pCell->mbOverlapX);
+ const bool bFirstCol(nCol == nFirstCol);
+
+ // handle rotation: If cell is rotated, handle lower/right edge inside
+ // this local geometry due to the created CoordinateSystem already representing
+ // the needed transformations.
+ const bool bRotated(pCell->IsRotated());
+
+ // Additionally avoid double-handling by suppressing handling when self not rotated,
+ // but above/left is rotated and thus already handled. Two directly connected
+ // rotated will paint/create both edges, they might be rotated differently.
+ const bool bSuppressLeft(!bRotated && nCol > nFirstCol && mxImpl->GetCell(nCol - 1, nRow)->IsRotated());
+ const bool bSuppressAbove(!bRotated && nRow > nFirstRow && mxImpl->GetCell(nCol, nRow - 1)->IsRotated());
+
+ if(!aX.equalZero() && !aY.equalZero())
+ {
+ // additionally needed local values
+ const bool bOverlapY(pCell->mbOverlapY);
+ const bool bLastCol(nCol == nLastCol);
+ const bool bFirstRow(nRow == nFirstRow);
+ const bool bLastRow(nRow == nLastRow);
+
+ // create upper line for this Cell
+ if ((!bOverlapY // true for first line in merged cells or cells
+ || bFirstRow) // true for non_Calc usages of this tooling
+ && !bSuppressAbove) // true when above is not rotated, so edge is already handled (see bRotated)
+ {
+ // get CellStyle - method will take care to get the correct one, e.g.
+ // for merged cells (it uses mxImpl->GetMergedOriginCell that works with topLeft's of these)
+ const Style& rTop(GetCellStyleTop(nCol, nRow));
+
+ if(rTop.IsUsed())
+ {
+ HelperCreateHorizontalEntry(*this, rTop, nCol, nRow, aOrigin, aX, aY, aData, true, pForceColor);
+ }
+ }
+
+ // create lower line for this Cell
+ if (bLastRow // true for non_Calc usages of this tooling
+ || bRotated) // true if cell is rotated, handle lower edge in local geometry
+ {
+ const Style& rBottom(GetCellStyleBottom(nCol, nRow));
+
+ if(rBottom.IsUsed())
+ {
+ HelperCreateHorizontalEntry(*this, rBottom, nCol, nRow + 1, aOrigin, aX, aY, aData, false, pForceColor);
+ }
+ }
+
+ // create left line for this Cell
+ if ((!bOverlapX // true for first column in merged cells or cells
+ || bFirstCol) // true for non_Calc usages of this tooling
+ && !bSuppressLeft) // true when left is not rotated, so edge is already handled (see bRotated)
+ {
+ const Style& rLeft(GetCellStyleLeft(nCol, nRow));
+
+ if(rLeft.IsUsed())
+ {
+ HelperCreateVerticalEntry(*this, rLeft, nCol, nRow, aOrigin, aX, aY, aData, true, pForceColor);
+ }
+ }
+
+ // create right line for this Cell
+ if (bLastCol // true for non_Calc usages of this tooling
+ || bRotated) // true if cell is rotated, handle right edge in local geometry
+ {
+ const Style& rRight(GetCellStyleRight(nCol, nRow));
+
+ if(rRight.IsUsed())
+ {
+ HelperCreateVerticalEntry(*this, rRight, nCol + 1, nRow, aOrigin, aX, aY, aData, false, pForceColor);
+ }
+ }
+
+ // tdf#126269 check for crossed lines, these need special treatment, especially
+ // for merged cells (see comments in task). Separate treatment of merged and
+ // non-merged cells to allow better handling of both types
+ if(pCell->IsMerged())
+ {
+ // first check if this merged cell was already handled. To do so,
+ // calculate and use the index of the TopLeft cell
+ sal_Int32 nColLeft(nCol), nRowTop(nRow), nColRight(nCol), nRowBottom(nRow);
+ GetMergedRange(nColLeft, nRowTop, nColRight, nRowBottom, nCol, nRow);
+ const sal_Int32 nIndexOfMergedCell(mxImpl->GetIndex(nColLeft, nRowTop));
+
+ auto aItInsertedPair = aMergedCells.insert(nIndexOfMergedCell);
+ if(aItInsertedPair.second)
+ {
+ // not found, so not yet handled.
+
+ // Get and check if diagonal styles are used
+ // Note: For GetCellStyleBLTR below I tried to use nRowBottom
+ // as Y-value what seemed more logical, but that
+ // is wrong. Despite defining a line starting at
+ // bottom-left, the Style is defined in the cell at top-left
+ const Style& rTLBR(GetCellStyleTLBR(nColLeft, nRowTop));
+ const Style& rBLTR(GetCellStyleBLTR(nColLeft, nRowTop));
+
+ if(rTLBR.IsUsed() || rBLTR.IsUsed())
+ {
+ // test if merged cell overlaps ClipRange at all (needs visualization)
+ if(mxImpl->OverlapsClipRange(nColLeft, nRowTop, nColRight, nRowBottom))
+ {
+ // when merged, get extended coordinate system and derived values
+ // for the full range of this merged cell. Only work with rMergedCell
+ // (which is the top-left single cell of the merged cell) from here on
+ aCoordinateSystem = mxImpl->GetCell(nColLeft, nRowTop)->CreateCoordinateSystemMergedCell(
+ *this, nColLeft, nRowTop, nColRight, nRowBottom);
+ aX = basegfx::utils::getColumn(aCoordinateSystem, 0);
+ aY = basegfx::utils::getColumn(aCoordinateSystem, 1);
+ aOrigin = basegfx::utils::getColumn(aCoordinateSystem, 2);
+
+ // check if clip is needed
+ basegfx::B2DRange aClipRange;
+
+ // first use row/col ClipTest for raw check
+ bool bNeedToClip(
+ !mxImpl->IsColInClipRange(nColLeft) ||
+ !mxImpl->IsRowInClipRange(nRowTop) ||
+ !mxImpl->IsColInClipRange(nColRight) ||
+ !mxImpl->IsRowInClipRange(nRowBottom));
+
+ if(bNeedToClip)
+ {
+ // now get ClipRange and CellRange in logical coordinates
+ aClipRange = GetB2DRange(
+ mxImpl->mnFirstClipCol, mxImpl->mnFirstClipRow,
+ mxImpl->mnLastClipCol, mxImpl->mnLastClipRow);
+
+ basegfx::B2DRange aCellRange(
+ GetB2DRange(
+ nColLeft, nRowTop,
+ nColRight, nRowBottom));
+
+ // intersect these to get the target ClipRange, ensure
+ // that clip is needed
+ aClipRange.intersect(aCellRange);
+ bNeedToClip = !aClipRange.isEmpty();
+
+#ifdef OPTICAL_CHECK_CLIPRANGE_FOR_MERGED_CELL
+ aClipRanges.push_back(aClipRange);
+#endif
+ }
+
+ // create top-left to bottom-right geometry
+ HelperCreateTLBREntry(*this, rTLBR, aData, aOrigin, aX, aY,
+ nColLeft, nRowTop, nColRight, nRowBottom, pForceColor,
+ bNeedToClip ? &aClipRange : nullptr);
+
+ // create bottom-left to top-right geometry
+ HelperCreateBLTREntry(*this, rBLTR, aData, aOrigin, aX, aY,
+ nColLeft, nRowTop, nColRight, nRowBottom, pForceColor,
+ bNeedToClip ? &aClipRange : nullptr);
+ }
+ }
+ }
+ }
+ else
+ {
+ // must be in clipping range: else not visible. This
+ // already clips completely for non-merged cells
+ if( mxImpl->IsInClipRange( nCol, nRow ) )
+ {
+ // get and check if diagonal styles are used
+ const Style& rTLBR(GetCellStyleTLBR(nCol, nRow));
+ const Style& rBLTR(GetCellStyleBLTR(nCol, nRow));
+
+ if(rTLBR.IsUsed() || rBLTR.IsUsed())
+ {
+ HelperCreateTLBREntry(*this, rTLBR, aData, aOrigin, aX, aY,
+ nCol, nRow, nCol, nRow, pForceColor, nullptr);
+
+ HelperCreateBLTREntry(*this, rBLTR, aData, aOrigin, aX, aY,
+ nCol, nRow, nCol, nRow, pForceColor, nullptr);
+ }
+ }
+ }
+ }
+ else if(!aY.equalZero())
+ {
+ // cell has height, but no width. Create left vertical line for this Cell
+ if ((!bOverlapX // true for first column in merged cells or cells
+ || bFirstCol) // true for non_Calc usages of this tooling
+ && !bSuppressLeft) // true when left is not rotated, so edge is already handled (see bRotated)
+ {
+ const Style& rLeft(GetCellStyleLeft(nCol, nRow));
+
+ if (rLeft.IsUsed())
+ {
+ HelperCreateVerticalEntry(*this, rLeft, nCol, nRow, aOrigin, aX, aY, aData, true, pForceColor);
+ }
+ }
+ }
+ else
+ {
+ // Cell has *no* size, thus no visualization
+ }
+ }
+ }
+
+ // create instance of SdrFrameBorderPrimitive2D if
+ // SdrFrameBorderDataVector is used
+ drawinglayer::primitive2d::Primitive2DContainer aSequence;
+
+ if(!aData.empty())
+ {
+ aSequence.append(
+ drawinglayer::primitive2d::Primitive2DReference(
+ new drawinglayer::primitive2d::SdrFrameBorderPrimitive2D(
+ std::move(aData),
+ true))); // force visualization to minimal one discrete unit (pixel)
+ }
+
+#ifdef OPTICAL_CHECK_CLIPRANGE_FOR_MERGED_CELL
+ for(auto const& rClipRange : aClipRanges)
+ {
+ // draw ClipRange in yellow to allow simple interactive optical control in office
+ aSequence.append(
+ drawinglayer::primitive2d::Primitive2DReference(
+ new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
+ basegfx::utils::createPolygonFromRect(rClipRange),
+ basegfx::BColor(1.0, 1.0, 0.0))));
+ }
+#endif
+
+ return aSequence;
+}
+
+drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveArray() const
+{
+ drawinglayer::primitive2d::Primitive2DContainer aPrimitives;
+
+ if (mxImpl->mnWidth && mxImpl->mnHeight)
+ {
+ aPrimitives = CreateB2DPrimitiveRange(0, 0, mxImpl->mnWidth - 1, mxImpl->mnHeight - 1, nullptr);
+ }
+
+ return aPrimitives;
+}
+
+#undef DBG_FRAME_CHECK_ROW_1
+#undef DBG_FRAME_CHECK_COL_1
+#undef DBG_FRAME_CHECK_COLROW
+#undef DBG_FRAME_CHECK_ROW
+#undef DBG_FRAME_CHECK_COL
+#undef DBG_FRAME_CHECK
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/frmdirlbox.cxx b/svx/source/dialog/frmdirlbox.cxx
new file mode 100644
index 0000000000..375a418671
--- /dev/null
+++ b/svx/source/dialog/frmdirlbox.cxx
@@ -0,0 +1,32 @@
+/* -*- 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 <svx/frmdirlbox.hxx>
+
+namespace svx
+{
+FrameDirectionListBox::FrameDirectionListBox(std::unique_ptr<weld::ComboBox> pControl)
+ : m_xControl(std::move(pControl))
+{
+}
+
+FrameDirectionListBox::~FrameDirectionListBox() {}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/frmsel.cxx b/svx/source/dialog/frmsel.cxx
new file mode 100644
index 0000000000..337013e55d
--- /dev/null
+++ b/svx/source/dialog/frmsel.cxx
@@ -0,0 +1,1308 @@
+/* -*- 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_wasm_strip.h>
+
+#include <sal/config.h>
+
+#include <o3tl/safeint.hxx>
+#include <svx/frmsel.hxx>
+#include <vcl/event.hxx>
+#include <sal/log.hxx>
+#include <tools/debug.hxx>
+#include <svtools/colorcfg.hxx>
+
+#include <algorithm>
+#include <math.h>
+
+#include <frmselimpl.hxx>
+#include <AccessibleFrameSelector.hxx>
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <drawinglayer/processor2d/processor2dtools.hxx>
+#include <drawinglayer/processor2d/baseprocessor2d.hxx>
+
+#include <bitmaps.hlst>
+
+using namespace ::com::sun::star;
+using namespace ::editeng;
+
+namespace svx {
+
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::accessibility::XAccessible;
+using namespace ::com::sun::star::accessibility;
+
+// global functions from framebordertype.hxx
+
+FrameBorderType GetFrameBorderTypeFromIndex( size_t nIndex )
+{
+ DBG_ASSERT( nIndex < o3tl::make_unsigned(FRAMEBORDERTYPE_COUNT),
+ "svx::GetFrameBorderTypeFromIndex - invalid index" );
+ return static_cast< FrameBorderType >( nIndex + 1 );
+}
+
+size_t GetIndexFromFrameBorderType( FrameBorderType eBorder )
+{
+ DBG_ASSERT( eBorder != FrameBorderType::NONE,
+ "svx::GetIndexFromFrameBorderType - invalid frame border type" );
+ return static_cast< size_t >( eBorder ) - 1;
+}
+
+namespace
+{
+
+/** Space between outer control border and any graphical element of the control. */
+const tools::Long FRAMESEL_GEOM_OUTER = 2;
+
+/** Space between arrows and usable inner area. */
+const tools::Long FRAMESEL_GEOM_INNER = 3;
+
+/** Maximum width to draw a frame border style. */
+const tools::Long FRAMESEL_GEOM_WIDTH = 9;
+
+/** Additional margin for click area of outer lines. */
+const tools::Long FRAMESEL_GEOM_ADD_CLICK_OUTER = 5;
+
+/** Additional margin for click area of inner lines. */
+const tools::Long FRAMESEL_GEOM_ADD_CLICK_INNER = 2;
+
+
+/** Returns the corresponding flag for a frame border. */
+FrameSelFlags lclGetFlagFromType( FrameBorderType eBorder )
+{
+ switch( eBorder )
+ {
+ case FrameBorderType::Left: return FrameSelFlags::Left;
+ case FrameBorderType::Right: return FrameSelFlags::Right;
+ case FrameBorderType::Top: return FrameSelFlags::Top;
+ case FrameBorderType::Bottom: return FrameSelFlags::Bottom;
+ case FrameBorderType::Horizontal: return FrameSelFlags::InnerHorizontal;
+ case FrameBorderType::Vertical: return FrameSelFlags::InnerVertical;
+ case FrameBorderType::TLBR: return FrameSelFlags::DiagonalTLBR;
+ case FrameBorderType::BLTR: return FrameSelFlags::DiagonalBLTR;
+ case FrameBorderType::NONE : break;
+ }
+ return FrameSelFlags::NONE;
+}
+
+/** Merges the rSource polypolygon into the rDest polypolygon. */
+void lclPolyPolyUnion( tools::PolyPolygon& rDest, const tools::PolyPolygon& rSource )
+{
+ const tools::PolyPolygon aTmp( rDest );
+ aTmp.GetUnion( rSource, rDest );
+}
+
+} // namespace
+
+FrameBorder::FrameBorder( FrameBorderType eType ) :
+ meType( eType ),
+ meState( FrameBorderState::Hide ),
+ meKeyLeft( FrameBorderType::NONE ),
+ meKeyRight( FrameBorderType::NONE ),
+ meKeyTop( FrameBorderType::NONE ),
+ meKeyBottom( FrameBorderType::NONE ),
+ mbEnabled( false ),
+ mbSelected( false )
+{
+}
+
+void FrameBorder::Enable( FrameSelFlags nFlags )
+{
+ mbEnabled = bool(nFlags & lclGetFlagFromType( meType ));
+ if( !mbEnabled )
+ SetState( FrameBorderState::Hide );
+}
+
+void FrameBorder::SetCoreStyle( const SvxBorderLine* pStyle )
+{
+ if( pStyle )
+ maCoreStyle = *pStyle;
+ else
+ maCoreStyle = SvxBorderLine();
+
+ // from twips to points
+ maUIStyle.Set( &maCoreStyle, FrameBorder::GetDefaultPatternScale(), FRAMESEL_GEOM_WIDTH );
+ meState = maUIStyle.IsUsed() ? FrameBorderState::Show : FrameBorderState::Hide;
+}
+
+void FrameBorder::SetState( FrameBorderState eState )
+{
+ meState = eState;
+ switch( meState )
+ {
+ case FrameBorderState::Show:
+ SAL_WARN( "svx.dialog", "svx::FrameBorder::SetState - use SetCoreStyle to make border visible" );
+ break;
+ case FrameBorderState::Hide:
+ maCoreStyle = SvxBorderLine();
+ maUIStyle.Clear();
+ break;
+ case FrameBorderState::DontCare:
+ maCoreStyle = SvxBorderLine();
+ maUIStyle = frame::Style(3, 0, 0, SvxBorderLineStyle::SOLID, FrameBorder::GetDefaultPatternScale()); //OBJ_FRAMESTYLE_DONTCARE
+ break;
+ }
+}
+
+void FrameBorder::AddFocusPolygon( const tools::Polygon& rFocus )
+{
+ lclPolyPolyUnion( maFocusArea, tools::PolyPolygon(rFocus) );
+}
+
+void FrameBorder::MergeFocusToPolyPolygon( tools::PolyPolygon& rPPoly ) const
+{
+ lclPolyPolyUnion( rPPoly, maFocusArea );
+}
+
+void FrameBorder::AddClickRect( const tools::Rectangle& rRect )
+{
+ lclPolyPolyUnion( maClickArea, tools::PolyPolygon( rRect ) );
+}
+
+bool FrameBorder::ContainsClickPoint( const Point& rPos ) const
+{
+ return vcl::Region( maClickArea ).Contains( rPos );
+}
+
+tools::Rectangle FrameBorder::GetClickBoundRect() const
+{
+ return maClickArea.GetBoundRect();
+}
+
+void FrameBorder::SetKeyboardNeighbors(
+ FrameBorderType eLeft, FrameBorderType eRight, FrameBorderType eTop, FrameBorderType eBottom )
+{
+ meKeyLeft = eLeft;
+ meKeyRight = eRight;
+ meKeyTop = eTop;
+ meKeyBottom = eBottom;
+}
+
+FrameBorderType FrameBorder::GetKeyboardNeighbor( sal_uInt16 nKeyCode ) const
+{
+ FrameBorderType eBorder = FrameBorderType::NONE;
+ switch( nKeyCode )
+ {
+ case KEY_LEFT: eBorder = meKeyLeft; break;
+ case KEY_RIGHT: eBorder = meKeyRight; break;
+ case KEY_UP: eBorder = meKeyTop; break;
+ case KEY_DOWN: eBorder = meKeyBottom; break;
+ default: SAL_WARN( "svx.dialog", "svx::FrameBorder::GetKeyboardNeighbor - unknown key code" );
+ }
+ return eBorder;
+}
+
+FrameSelectorImpl::FrameSelectorImpl( FrameSelector& rFrameSel ) :
+ mrFrameSel( rFrameSel ),
+ mpVirDev( VclPtr<VirtualDevice>::Create() ),
+ maLeft( FrameBorderType::Left ),
+ maRight( FrameBorderType::Right ),
+ maTop( FrameBorderType::Top ),
+ maBottom( FrameBorderType::Bottom ),
+ maHor( FrameBorderType::Horizontal ),
+ maVer( FrameBorderType::Vertical ),
+ maTLBR( FrameBorderType::TLBR ),
+ maBLTR( FrameBorderType::BLTR ),
+ mnFlags( FrameSelFlags::Outer ),
+ mnCtrlSize( 0 ),
+ mnArrowSize( 0 ),
+ mnLine1( 0 ),
+ mnLine2( 0 ),
+ mnLine3( 0 ),
+ mnFocusOffs( 0 ),
+ mbHor( false ),
+ mbVer( false ),
+ mbTLBR( false ),
+ mbBLTR( false ),
+ mbFullRepaint( true ),
+ mbAutoSelect( true ),
+ mbHCMode( false )
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ ,maChildVec(FRAMEBORDERTYPE_COUNT)
+#endif
+{
+ maAllBorders.resize( FRAMEBORDERTYPE_COUNT, nullptr );
+ maAllBorders[ GetIndexFromFrameBorderType( FrameBorderType::Left ) ] = &maLeft;
+ maAllBorders[ GetIndexFromFrameBorderType( FrameBorderType::Right ) ] = &maRight;
+ maAllBorders[ GetIndexFromFrameBorderType( FrameBorderType::Top ) ] = &maTop;
+ maAllBorders[ GetIndexFromFrameBorderType( FrameBorderType::Bottom ) ] = &maBottom;
+ maAllBorders[ GetIndexFromFrameBorderType( FrameBorderType::Horizontal ) ] = &maHor;
+ maAllBorders[ GetIndexFromFrameBorderType( FrameBorderType::Vertical ) ] = &maVer;
+ maAllBorders[ GetIndexFromFrameBorderType( FrameBorderType::TLBR ) ] = &maTLBR;
+ maAllBorders[ GetIndexFromFrameBorderType( FrameBorderType::BLTR ) ] = &maBLTR;
+#if OSL_DEBUG_LEVEL >= 2
+ {
+ bool bOk = true;
+ for( FrameBorderCIter aIt( maAllBorders ); bOk && aIt.Is(); bOk = (*aIt != 0), ++aIt );
+ DBG_ASSERT( bOk, "svx::FrameSelectorImpl::FrameSelectorImpl - missing entry in maAllBorders" );
+ }
+#endif
+ // left neighbor right neighbor upper neighbor lower neighbor
+ maLeft.SetKeyboardNeighbors( FrameBorderType::NONE, FrameBorderType::TLBR, FrameBorderType::Top, FrameBorderType::Bottom );
+ maRight.SetKeyboardNeighbors( FrameBorderType::BLTR, FrameBorderType::NONE, FrameBorderType::Top, FrameBorderType::Bottom );
+ maTop.SetKeyboardNeighbors( FrameBorderType::Left, FrameBorderType::Right, FrameBorderType::NONE, FrameBorderType::TLBR );
+ maBottom.SetKeyboardNeighbors( FrameBorderType::Left, FrameBorderType::Right, FrameBorderType::BLTR, FrameBorderType::NONE );
+ maHor.SetKeyboardNeighbors( FrameBorderType::Left, FrameBorderType::Right, FrameBorderType::TLBR, FrameBorderType::BLTR );
+ maVer.SetKeyboardNeighbors( FrameBorderType::TLBR, FrameBorderType::BLTR, FrameBorderType::Top, FrameBorderType::Bottom );
+ maTLBR.SetKeyboardNeighbors( FrameBorderType::Left, FrameBorderType::Vertical, FrameBorderType::Top, FrameBorderType::Horizontal );
+ maBLTR.SetKeyboardNeighbors( FrameBorderType::Vertical, FrameBorderType::Right, FrameBorderType::Horizontal, FrameBorderType::Bottom );
+
+ Initialize(mnFlags);
+}
+
+FrameSelectorImpl::~FrameSelectorImpl()
+{
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ for( auto& rpChild : maChildVec )
+ if( rpChild.is() )
+ {
+ rpChild->Invalidate();
+ rpChild->dispose();
+ }
+#endif
+}
+
+// initialization
+void FrameSelectorImpl::Initialize( FrameSelFlags nFlags )
+{
+ mnFlags = nFlags;
+
+ maEnabBorders.clear();
+ for( FrameBorderIter aIt( maAllBorders ); aIt.Is(); ++aIt )
+ {
+ (*aIt)->Enable( mnFlags );
+ if( (*aIt)->IsEnabled() )
+ maEnabBorders.push_back( *aIt );
+ }
+ mbHor = maHor.IsEnabled();
+ mbVer = maVer.IsEnabled();
+ mbTLBR = maTLBR.IsEnabled();
+ mbBLTR = maBLTR.IsEnabled();
+
+ InitVirtualDevice();
+}
+
+void FrameSelectorImpl::InitColors()
+{
+ const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
+ svtools::ColorConfig aColorConfig;
+ maBackCol = aColorConfig.GetColorValue(svtools::DOCCOLOR).nColor;
+ mbHCMode = rSettings.GetHighContrastMode();
+ maArrowCol = aColorConfig.GetColorValue(svtools::DOCBOUNDARIES).nColor;
+ maMarkCol = aColorConfig.GetColorValue(svtools::TABLEBOUNDARIES).nColor;
+ maHCLineCol = COL_BLACK;
+}
+
+constexpr OUString aImageIds[] =
+{
+ RID_SVXBMP_FRMSEL_ARROW1,
+ RID_SVXBMP_FRMSEL_ARROW2,
+ RID_SVXBMP_FRMSEL_ARROW3,
+ RID_SVXBMP_FRMSEL_ARROW4,
+ RID_SVXBMP_FRMSEL_ARROW5,
+ RID_SVXBMP_FRMSEL_ARROW6,
+ RID_SVXBMP_FRMSEL_ARROW7,
+ RID_SVXBMP_FRMSEL_ARROW8,
+ RID_SVXBMP_FRMSEL_ARROW9,
+ RID_SVXBMP_FRMSEL_ARROW10,
+ RID_SVXBMP_FRMSEL_ARROW11,
+ RID_SVXBMP_FRMSEL_ARROW12,
+ RID_SVXBMP_FRMSEL_ARROW13,
+ RID_SVXBMP_FRMSEL_ARROW14,
+ RID_SVXBMP_FRMSEL_ARROW15,
+ RID_SVXBMP_FRMSEL_ARROW16
+};
+
+void FrameSelectorImpl::InitArrowImageList()
+{
+ maArrows.clear();
+
+ /* Build the arrow images bitmap with current colors. */
+ Color pColorAry1[3];
+ Color pColorAry2[3];
+ pColorAry1[0] = Color( 0, 0, 0 );
+ pColorAry2[0] = maArrowCol; // black -> arrow color
+ pColorAry1[1] = Color( 0, 255, 0 );
+ pColorAry2[1] = maMarkCol; // green -> marker color
+ pColorAry1[2] = Color( 255, 0, 255 );
+ pColorAry2[2] = maBackCol; // magenta -> background
+
+ assert(SAL_N_ELEMENTS(aImageIds) == 16);
+ for (size_t i = 0; i < SAL_N_ELEMENTS(aImageIds); ++i)
+ {
+ BitmapEx aBmpEx { aImageIds[i] };
+ aBmpEx.Replace(pColorAry1, pColorAry2, 3);
+ maArrows.emplace_back(aBmpEx);
+ }
+ assert(maArrows.size() == 16);
+
+ mnArrowSize = maArrows[0].GetSizePixel().Height();
+}
+
+void FrameSelectorImpl::InitGlobalGeometry()
+{
+ Size aCtrlSize(mrFrameSel.GetOutputSizePixel());
+ /* nMinSize is the lower of width and height (control will always be squarish).
+ FRAMESEL_GEOM_OUTER is the minimal distance between inner control border
+ and any element. */
+ tools::Long nMinSize = std::min( aCtrlSize.Width(), aCtrlSize.Height() ) - 2 * FRAMESEL_GEOM_OUTER;
+ /* nFixedSize is the size all existing elements need in one direction:
+ the diag. arrow, space betw. arrow and frame border, outer frame border,
+ inner frame border, other outer frame border, space betw. frame border
+ and arrow, the other arrow. */
+ tools::Long nFixedSize = 2 * mnArrowSize + 2 * FRAMESEL_GEOM_INNER + 3 * FRAMESEL_GEOM_WIDTH;
+ /* nBetwBordersSize contains the size between an outer and inner frame border (made odd). */
+ tools::Long nBetwBordersSize = (((nMinSize - nFixedSize) / 2) - 1) | 1;
+
+ /* The final size of the usable area. At least do not get negative */
+ mnCtrlSize = 2 * nBetwBordersSize + nFixedSize;
+ mnCtrlSize = std::max(mnCtrlSize, static_cast<tools::Long>(0));
+ mpVirDev->SetOutputSizePixel( Size( mnCtrlSize, mnCtrlSize ) );
+
+ /* Center the virtual device in the control. */
+ maVirDevPos = Point( (aCtrlSize.Width() - mnCtrlSize) / 2, (aCtrlSize.Height() - mnCtrlSize) / 2 );
+}
+
+void FrameSelectorImpl::InitBorderGeometry()
+{
+ size_t nCol, nCols, nRow, nRows;
+
+ // Global border geometry values
+ /* mnLine* is the middle point inside a frame border (i.e. mnLine1 is mid X inside left border). */
+ mnLine1 = mnArrowSize + FRAMESEL_GEOM_INNER + FRAMESEL_GEOM_WIDTH / 2;
+ mnLine2 = mnCtrlSize / 2;
+ mnLine3 = 2 * mnLine2 - mnLine1;
+
+ // Frame helper array
+ maArray.Initialize( mbVer ? 2 : 1, mbHor ? 2 : 1 );
+
+ maArray.SetXOffset( mnLine1 );
+ maArray.SetAllColWidths( (mbVer ? mnLine2 : mnLine3) - mnLine1 );
+
+ maArray.SetYOffset( mnLine1 );
+ maArray.SetAllRowHeights( (mbHor ? mnLine2 : mnLine3) - mnLine1 );
+
+ // Focus polygons
+ /* Width for focus rectangles from center of frame borders. */
+ mnFocusOffs = FRAMESEL_GEOM_WIDTH / 2 + 1;
+
+ maLeft.ClearFocusArea();
+ maVer.ClearFocusArea();
+ maRight.ClearFocusArea();
+ maTop.ClearFocusArea();
+ maHor.ClearFocusArea();
+ maBottom.ClearFocusArea();
+
+ maLeft.AddFocusPolygon( tools::Polygon(tools::Rectangle( mnLine1 - mnFocusOffs, mnLine1 - mnFocusOffs, mnLine1 + mnFocusOffs, mnLine3 + mnFocusOffs )) );
+ maVer.AddFocusPolygon( tools::Polygon(tools::Rectangle( mnLine2 - mnFocusOffs, mnLine1 - mnFocusOffs, mnLine2 + mnFocusOffs, mnLine3 + mnFocusOffs )) );
+ maRight.AddFocusPolygon( tools::Polygon(tools::Rectangle( mnLine3 - mnFocusOffs, mnLine1 - mnFocusOffs, mnLine3 + mnFocusOffs, mnLine3 + mnFocusOffs )) );
+ maTop.AddFocusPolygon( tools::Polygon(tools::Rectangle( mnLine1 - mnFocusOffs, mnLine1 - mnFocusOffs, mnLine3 + mnFocusOffs, mnLine1 + mnFocusOffs )) );
+ maHor.AddFocusPolygon( tools::Polygon(tools::Rectangle( mnLine1 - mnFocusOffs, mnLine2 - mnFocusOffs, mnLine3 + mnFocusOffs, mnLine2 + mnFocusOffs )) );
+ maBottom.AddFocusPolygon( tools::Polygon(tools::Rectangle( mnLine1 - mnFocusOffs, mnLine3 - mnFocusOffs, mnLine3 + mnFocusOffs, mnLine3 + mnFocusOffs )) );
+
+ maTLBR.ClearFocusArea();
+ maBLTR.ClearFocusArea();
+
+ for( nCol = 0, nCols = maArray.GetColCount(); nCol < nCols; ++nCol )
+ {
+ for( nRow = 0, nRows = maArray.GetRowCount(); nRow < nRows; ++nRow )
+ {
+ const basegfx::B2DRange aCellRange(maArray.GetCellRange( nCol, nRow ));
+ const tools::Rectangle aRect(
+ basegfx::fround(aCellRange.getMinX()), basegfx::fround(aCellRange.getMinY()),
+ basegfx::fround(aCellRange.getMaxX()), basegfx::fround(aCellRange.getMaxY()));
+ const double fHorDiagAngle(atan2(fabs(aCellRange.getHeight()), fabs(aCellRange.getWidth())));
+ const double fVerDiagAngle(fHorDiagAngle > 0.0 ? M_PI_2 - fHorDiagAngle : 0.0);
+ const tools::Long nDiagFocusOffsX(basegfx::fround(-mnFocusOffs / tan(fHorDiagAngle) + mnFocusOffs / sin(fHorDiagAngle)));
+ const tools::Long nDiagFocusOffsY(basegfx::fround(-mnFocusOffs / tan(fVerDiagAngle) + mnFocusOffs / sin(fVerDiagAngle)));
+
+ std::vector< Point > aFocusVec;
+ aFocusVec.emplace_back( aRect.Left() - mnFocusOffs, aRect.Top() + nDiagFocusOffsY );
+ aFocusVec.emplace_back( aRect.Left() - mnFocusOffs, aRect.Top() - mnFocusOffs );
+ aFocusVec.emplace_back( aRect.Left() + nDiagFocusOffsX, aRect.Top() - mnFocusOffs );
+ aFocusVec.emplace_back( aRect.Right() + mnFocusOffs, aRect.Bottom() - nDiagFocusOffsY );
+ aFocusVec.emplace_back( aRect.Right() + mnFocusOffs, aRect.Bottom() + mnFocusOffs );
+ aFocusVec.emplace_back( aRect.Right() - nDiagFocusOffsX, aRect.Bottom() + mnFocusOffs );
+ maTLBR.AddFocusPolygon( tools::Polygon( static_cast< sal_uInt16 >( aFocusVec.size() ), aFocusVec.data() ) );
+
+ aFocusVec.clear();
+ aFocusVec.emplace_back( aRect.Right() + mnFocusOffs, aRect.Top() + nDiagFocusOffsY );
+ aFocusVec.emplace_back( aRect.Right() + mnFocusOffs, aRect.Top() - mnFocusOffs );
+ aFocusVec.emplace_back( aRect.Right() - nDiagFocusOffsX, aRect.Top() - mnFocusOffs );
+ aFocusVec.emplace_back( aRect.Left() - mnFocusOffs, aRect.Bottom() - nDiagFocusOffsY );
+ aFocusVec.emplace_back( aRect.Left() - mnFocusOffs, aRect.Bottom() + mnFocusOffs );
+ aFocusVec.emplace_back( aRect.Left() + nDiagFocusOffsX, aRect.Bottom() + mnFocusOffs );
+ maBLTR.AddFocusPolygon( tools::Polygon( static_cast< sal_uInt16 >( aFocusVec.size() ), aFocusVec.data() ) );
+ }
+ }
+
+ // Click areas
+ for( FrameBorderIter aIt( maAllBorders ); aIt.Is(); ++aIt )
+ (*aIt)->ClearClickArea();
+
+ /* Additional space for click area: is added to the space available to draw
+ the frame borders. For instance left frame border:
+ - To left, top, and bottom always big additional space (outer area).
+ - To right: Dependent on existence of inner vertical frame border
+ (if enabled, use less space).
+ */
+ tools::Long nClO = FRAMESEL_GEOM_WIDTH / 2 + FRAMESEL_GEOM_ADD_CLICK_OUTER;
+ tools::Long nClI = (mbTLBR && mbBLTR) ? (FRAMESEL_GEOM_WIDTH / 2 + FRAMESEL_GEOM_ADD_CLICK_INNER) : nClO;
+ tools::Long nClH = mbHor ? nClI : nClO; // additional space dependent of horizontal inner border
+ tools::Long nClV = mbVer ? nClI : nClO; // additional space dependent of vertical inner border
+
+ maLeft.AddClickRect( tools::Rectangle( mnLine1 - nClO, mnLine1 - nClO, mnLine1 + nClV, mnLine3 + nClO ) );
+ maVer.AddClickRect( tools::Rectangle( mnLine2 - nClI, mnLine1 - nClO, mnLine2 + nClI, mnLine3 + nClO ) );
+ maRight.AddClickRect( tools::Rectangle( mnLine3 - nClV, mnLine1 - nClO, mnLine3 + nClO, mnLine3 + nClO ) );
+ maTop.AddClickRect( tools::Rectangle( mnLine1 - nClO, mnLine1 - nClO, mnLine3 + nClO, mnLine1 + nClH ) );
+ maHor.AddClickRect( tools::Rectangle( mnLine1 - nClO, mnLine2 - nClI, mnLine3 + nClO, mnLine2 + nClI ) );
+ maBottom.AddClickRect( tools::Rectangle( mnLine1 - nClO, mnLine3 - nClH, mnLine3 + nClO, mnLine3 + nClO ) );
+
+ /* Diagonal frame borders use the remaining space between outer and inner frame borders. */
+ if( !(mbTLBR || mbBLTR) )
+ return;
+
+ for( nCol = 0, nCols = maArray.GetColCount(); nCol < nCols; ++nCol )
+ {
+ for( nRow = 0, nRows = maArray.GetRowCount(); nRow < nRows; ++nRow )
+ {
+ // the usable area between horizontal/vertical frame borders of current quadrant
+ const basegfx::B2DRange aCellRange(maArray.GetCellRange( nCol, nRow ));
+ const tools::Rectangle aRect(
+ basegfx::fround(aCellRange.getMinX()) + nClV + 1, basegfx::fround(aCellRange.getMinY()) + nClH + 1,
+ basegfx::fround(aCellRange.getMaxX()) - nClV + 1, basegfx::fround(aCellRange.getMaxY()) - nClH + 1);
+
+ /* Both diagonal frame borders enabled. */
+ if( mbTLBR && mbBLTR )
+ {
+ // single areas
+ Point aMid( aRect.Center() );
+ maTLBR.AddClickRect( tools::Rectangle( aRect.TopLeft(), aMid ) );
+ maTLBR.AddClickRect( tools::Rectangle( aMid + Point( 1, 1 ), aRect.BottomRight() ) );
+ maBLTR.AddClickRect( tools::Rectangle( aRect.Left(), aMid.Y() + 1, aMid.X(), aRect.Bottom() ) );
+ maBLTR.AddClickRect( tools::Rectangle( aMid.X() + 1, aRect.Top(), aRect.Right(), aMid.Y() ) );
+ // centered rectangle for both frame borders
+ tools::Rectangle aMidRect( aRect.TopLeft(), Size( aRect.GetWidth() / 3, aRect.GetHeight() / 3 ) );
+ aMidRect.Move( (aRect.GetWidth() - aMidRect.GetWidth()) / 2, (aRect.GetHeight() - aMidRect.GetHeight()) / 2 );
+ maTLBR.AddClickRect( aMidRect );
+ maBLTR.AddClickRect( aMidRect );
+ }
+ /* One of the diagonal frame borders enabled - use entire rectangle. */
+ else if( mbTLBR && !mbBLTR ) // top-left to bottom-right only
+ maTLBR.AddClickRect( aRect );
+ else if( !mbTLBR && mbBLTR ) // bottom-left to top-right only
+ maBLTR.AddClickRect( aRect );
+ }
+ }
+}
+
+void FrameSelectorImpl::InitVirtualDevice()
+{
+ // initialize resources
+ InitColors();
+ InitArrowImageList();
+
+ sizeChanged();
+}
+
+void FrameSelectorImpl::sizeChanged()
+{
+ // initialize geometry
+ InitGlobalGeometry();
+ InitBorderGeometry();
+
+ DoInvalidate( true );
+}
+
+// frame border access
+const FrameBorder& FrameSelectorImpl::GetBorder( FrameBorderType eBorder ) const
+{
+ size_t nIndex = GetIndexFromFrameBorderType( eBorder );
+ if( nIndex < maAllBorders.size() )
+ return *maAllBorders[ nIndex ];
+ SAL_WARN( "svx.dialog", "svx::FrameSelectorImpl::GetBorder - unknown border type" );
+ return maTop;
+}
+
+FrameBorder& FrameSelectorImpl::GetBorderAccess( FrameBorderType eBorder )
+{
+ return const_cast< FrameBorder& >( GetBorder( eBorder ) );
+}
+
+// drawing
+void FrameSelectorImpl::DrawBackground()
+{
+ // clear the area
+ mpVirDev->SetLineColor();
+ mpVirDev->SetFillColor( maBackCol );
+ mpVirDev->DrawRect( tools::Rectangle( Point( 0, 0 ), mpVirDev->GetOutputSizePixel() ) );
+
+ // draw the inner gray (or whatever color) rectangle
+ mpVirDev->SetLineColor();
+ mpVirDev->SetFillColor( maMarkCol );
+ mpVirDev->DrawRect( tools::Rectangle(
+ mnLine1 - mnFocusOffs, mnLine1 - mnFocusOffs, mnLine3 + mnFocusOffs, mnLine3 + mnFocusOffs ) );
+
+ // draw the white space for enabled frame borders
+ tools::PolyPolygon aPPoly;
+ for( FrameBorderCIter aIt( maEnabBorders ); aIt.Is(); ++aIt )
+ (*aIt)->MergeFocusToPolyPolygon( aPPoly );
+ aPPoly.Optimize( PolyOptimizeFlags::CLOSE );
+ mpVirDev->SetLineColor( maBackCol );
+ mpVirDev->SetFillColor( maBackCol );
+ mpVirDev->DrawPolyPolygon( aPPoly );
+}
+
+void FrameSelectorImpl::DrawArrows( const FrameBorder& rBorder )
+{
+ DBG_ASSERT( rBorder.IsEnabled(), "svx::FrameSelectorImpl::DrawArrows - access to disabled border" );
+
+ tools::Long nLinePos = 0;
+ switch( rBorder.GetType() )
+ {
+ case FrameBorderType::Left:
+ case FrameBorderType::Top: nLinePos = mnLine1; break;
+ case FrameBorderType::Vertical:
+ case FrameBorderType::Horizontal: nLinePos = mnLine2; break;
+ case FrameBorderType::Right:
+ case FrameBorderType::Bottom: nLinePos = mnLine3; break;
+ default: ; //prevent warning
+ }
+ nLinePos -= mnArrowSize / 2;
+
+ tools::Long nTLPos = 0;
+ tools::Long nBRPos = mnCtrlSize - mnArrowSize;
+ Point aPos1, aPos2;
+ int nImgIndex1 = -1, nImgIndex2 = -1;
+ switch( rBorder.GetType() )
+ {
+ case FrameBorderType::Left:
+ case FrameBorderType::Right:
+ case FrameBorderType::Vertical:
+ aPos1 = Point( nLinePos, nTLPos ); nImgIndex1 = 0;
+ aPos2 = Point( nLinePos, nBRPos ); nImgIndex2 = 1;
+ break;
+
+ case FrameBorderType::Top:
+ case FrameBorderType::Bottom:
+ case FrameBorderType::Horizontal:
+ aPos1 = Point( nTLPos, nLinePos ); nImgIndex1 = 2;
+ aPos2 = Point( nBRPos, nLinePos ); nImgIndex2 = 3;
+ break;
+
+ case FrameBorderType::TLBR:
+ aPos1 = Point( nTLPos, nTLPos ); nImgIndex1 = 4;
+ aPos2 = Point( nBRPos, nBRPos ); nImgIndex2 = 5;
+ break;
+ case FrameBorderType::BLTR:
+ aPos1 = Point( nTLPos, nBRPos ); nImgIndex1 = 6;
+ aPos2 = Point( nBRPos, nTLPos ); nImgIndex2 = 7;
+ break;
+ default: ; //prevent warning
+ }
+
+ // Arrow or marker? Do not draw arrows into disabled control.
+ sal_uInt16 nSelectAdd = (mrFrameSel.IsEnabled() && rBorder.IsSelected()) ? 0 : 8;
+ if (nImgIndex1 >= 0)
+ mpVirDev->DrawImage(aPos1, maArrows[nImgIndex1 + nSelectAdd]);
+ if (nImgIndex2 >= 0)
+ mpVirDev->DrawImage(aPos2, maArrows[nImgIndex2 + nSelectAdd]);
+}
+
+Color FrameSelectorImpl::GetDrawLineColor( const Color& rColor ) const
+{
+ Color aColor( mbHCMode ? maHCLineCol : rColor );
+ if( aColor == maBackCol )
+ aColor.Invert();
+ return aColor;
+}
+
+void FrameSelectorImpl::DrawAllFrameBorders()
+{
+ // Translate core colors to current UI colors (regards current background and HC mode).
+ for( FrameBorderIter aIt( maEnabBorders ); aIt.Is(); ++aIt )
+ {
+ Color aCoreColorPrim = ((*aIt)->GetState() == FrameBorderState::DontCare) ? maMarkCol : (*aIt)->GetCoreStyle().GetColorOut();
+ Color aCoreColorSecn = ((*aIt)->GetState() == FrameBorderState::DontCare) ? maMarkCol : (*aIt)->GetCoreStyle().GetColorIn();
+ (*aIt)->SetUIColorPrim( GetDrawLineColor( aCoreColorPrim ) );
+ (*aIt)->SetUIColorSecn( GetDrawLineColor( aCoreColorSecn ) );
+ }
+
+ // Copy all frame border styles to the helper array
+ maArray.SetColumnStyleLeft( 0, maLeft.GetUIStyle() );
+ if( mbVer ) maArray.SetColumnStyleLeft( 1, maVer.GetUIStyle() );
+
+ // Invert the style for the right line
+ const frame::Style rRightStyle = maRight.GetUIStyle( );
+ frame::Style rInvertedRight( rRightStyle.GetColorPrim(),
+ rRightStyle.GetColorSecn(), rRightStyle.GetColorGap(),
+ rRightStyle.UseGapColor(),
+ rRightStyle.Secn(), rRightStyle.Dist(), rRightStyle.Prim( ),
+ rRightStyle.Type( ), rRightStyle.PatternScale() );
+ maArray.SetColumnStyleRight( mbVer ? 1 : 0, rInvertedRight );
+
+ maArray.SetRowStyleTop( 0, maTop.GetUIStyle() );
+ if( mbHor )
+ {
+ // Invert the style for the hor line to match the real borders
+ const frame::Style rHorStyle = maHor.GetUIStyle();
+ frame::Style rInvertedHor( rHorStyle.GetColorPrim(),
+ rHorStyle.GetColorSecn(), rHorStyle.GetColorGap(),
+ rHorStyle.UseGapColor(),
+ rHorStyle.Secn(), rHorStyle.Dist(), rHorStyle.Prim( ),
+ rHorStyle.Type(), rHorStyle.PatternScale() );
+ maArray.SetRowStyleTop( 1, rInvertedHor );
+ }
+
+ // Invert the style for the bottom line
+ const frame::Style rBottomStyle = maBottom.GetUIStyle( );
+ frame::Style rInvertedBottom( rBottomStyle.GetColorPrim(),
+ rBottomStyle.GetColorSecn(), rBottomStyle.GetColorGap(),
+ rBottomStyle.UseGapColor(),
+ rBottomStyle.Secn(), rBottomStyle.Dist(), rBottomStyle.Prim( ),
+ rBottomStyle.Type(), rBottomStyle.PatternScale() );
+ maArray.SetRowStyleBottom( mbHor ? 1 : 0, rInvertedBottom );
+
+ for( sal_Int32 nCol = 0; nCol < maArray.GetColCount(); ++nCol )
+ for( sal_Int32 nRow = 0; nRow < maArray.GetRowCount(); ++nRow )
+ maArray.SetCellStyleDiag( nCol, nRow, maTLBR.GetUIStyle(), maBLTR.GetUIStyle() );
+
+ // This is used in the dialog/control for 'Border' attributes. When using
+ // the original paint below instead of primitives, the advantage currently
+ // is the correct visualization of diagonal line(s) including overlaying,
+ // but the rest is bad. Since the edit views use primitives and the preview
+ // should be 'real' I opt for also changing this to primitives. I will
+ // keep the old solution and add a switch (above) based on a static bool so
+ // that interested people may test this out in the debugger.
+ // This is one more hint to enhance the primitive visualization further to
+ // support diagonals better - that's the way to go.
+ const drawinglayer::geometry::ViewInformation2D aNewViewInformation2D;
+ std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor2D(
+ drawinglayer::processor2d::createPixelProcessor2DFromOutputDevice(
+ *mpVirDev,
+ aNewViewInformation2D));
+
+ pProcessor2D->process(maArray.CreateB2DPrimitiveArray());
+ pProcessor2D.reset();
+}
+
+void FrameSelectorImpl::DrawVirtualDevice()
+{
+ DrawBackground();
+ for(FrameBorderCIter aIt(maEnabBorders); aIt.Is(); ++aIt)
+ DrawArrows(**aIt);
+ DrawAllFrameBorders();
+ mbFullRepaint = false;
+}
+
+void FrameSelectorImpl::CopyVirDevToControl(vcl::RenderContext& rRenderContext)
+{
+ if (mbFullRepaint)
+ DrawVirtualDevice();
+ rRenderContext.DrawBitmapEx(maVirDevPos, mpVirDev->GetBitmapEx(Point(0, 0), mpVirDev->GetOutputSizePixel()));
+}
+
+void FrameSelectorImpl::DrawAllTrackingRects(vcl::RenderContext& rRenderContext)
+{
+ tools::PolyPolygon aPPoly;
+ if (mrFrameSel.IsAnyBorderSelected())
+ {
+ for(SelFrameBorderCIter aIt( maEnabBorders ); aIt.Is(); ++aIt)
+ (*aIt)->MergeFocusToPolyPolygon(aPPoly);
+ aPPoly.Move(maVirDevPos.X(), maVirDevPos.Y());
+ }
+ else
+ // no frame border selected -> draw tracking rectangle around entire control
+ aPPoly.Insert( tools::Polygon(tools::Rectangle(maVirDevPos, mpVirDev->GetOutputSizePixel())));
+
+ aPPoly.Optimize(PolyOptimizeFlags::CLOSE);
+
+ for(sal_uInt16 nIdx = 0, nCount = aPPoly.Count(); nIdx < nCount; ++nIdx)
+ rRenderContext.Invert(aPPoly.GetObject(nIdx), InvertFlags::TrackFrame);
+}
+
+Point FrameSelectorImpl::GetDevPosFromMousePos( const Point& rMousePos ) const
+{
+ return rMousePos - maVirDevPos;
+}
+
+void FrameSelectorImpl::DoInvalidate( bool bFullRepaint )
+{
+ mbFullRepaint |= bFullRepaint;
+ mrFrameSel.Invalidate();
+}
+
+// frame border state and style
+void FrameSelectorImpl::SetBorderState( FrameBorder& rBorder, FrameBorderState eState )
+{
+ DBG_ASSERT( rBorder.IsEnabled(), "svx::FrameSelectorImpl::SetBorderState - access to disabled border" );
+ Any aOld;
+ Any aNew;
+ Any& rMod = eState == FrameBorderState::Show ? aNew : aOld;
+ rMod <<= AccessibleStateType::CHECKED;
+
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ rtl::Reference< a11y::AccFrameSelectorChild > xRet;
+ size_t nVecIdx = static_cast< size_t >( rBorder.GetType() );
+ if( GetBorder(rBorder.GetType()).IsEnabled() && (1 <= nVecIdx) && (nVecIdx <= maChildVec.size()) )
+ xRet = maChildVec[ --nVecIdx ].get();
+#endif
+
+ if( eState == FrameBorderState::Show )
+ SetBorderCoreStyle( rBorder, &maCurrStyle );
+ else
+ rBorder.SetState( eState );
+
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ if (xRet.is())
+ xRet->NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOld, aNew );
+#endif
+
+ DoInvalidate( true );
+}
+
+void FrameSelectorImpl::SetBorderCoreStyle( FrameBorder& rBorder, const SvxBorderLine* pStyle )
+{
+ DBG_ASSERT( rBorder.IsEnabled(), "svx::FrameSelectorImpl::SetBorderCoreStyle - access to disabled border" );
+ rBorder.SetCoreStyle( pStyle );
+ DoInvalidate( true );
+}
+
+void FrameSelectorImpl::ToggleBorderState( FrameBorder& rBorder )
+{
+ bool bDontCare = mrFrameSel.SupportsDontCareState();
+ switch( rBorder.GetState() )
+ {
+ // same order as tristate check box: visible -> don't care -> hidden
+ case FrameBorderState::Show:
+ SetBorderState( rBorder, bDontCare ? FrameBorderState::DontCare : FrameBorderState::Hide );
+ break;
+ case FrameBorderState::Hide:
+ SetBorderState( rBorder, FrameBorderState::Show );
+ break;
+ case FrameBorderState::DontCare:
+ SetBorderState( rBorder, FrameBorderState::Hide );
+ break;
+ }
+}
+
+// frame border selection
+void FrameSelectorImpl::SelectBorder( FrameBorder& rBorder, bool bSelect )
+{
+ DBG_ASSERT( rBorder.IsEnabled(), "svx::FrameSelectorImpl::SelectBorder - access to disabled border" );
+ rBorder.Select( bSelect );
+ DrawArrows( rBorder );
+ DoInvalidate( false );
+}
+
+void FrameSelectorImpl::SilentGrabFocus()
+{
+ bool bOldAuto = mbAutoSelect;
+ mbAutoSelect = false;
+ mrFrameSel.GrabFocus();
+ mbAutoSelect = bOldAuto;
+}
+
+bool FrameSelectorImpl::SelectedBordersEqual() const
+{
+ bool bEqual = true;
+ SelFrameBorderCIter aIt( maEnabBorders );
+ if( aIt.Is() )
+ {
+ const SvxBorderLine& rFirstStyle = (*aIt)->GetCoreStyle();
+ for( ++aIt; bEqual && aIt.Is(); ++aIt )
+ bEqual = ((*aIt)->GetCoreStyle() == rFirstStyle);
+ }
+ return bEqual;
+}
+
+FrameSelector::FrameSelector()
+{
+}
+
+void FrameSelector::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ CustomWidgetController::SetDrawingArea(pDrawingArea);
+ mxImpl.reset( new FrameSelectorImpl( *this ) );
+ Size aPrefSize = pDrawingArea->get_ref_device().LogicToPixel(Size(61, 65), MapMode(MapUnit::MapAppFont));
+ pDrawingArea->set_size_request(aPrefSize.Width(), aPrefSize.Height());
+ EnableRTL( false ); // #107808# don't mirror the mouse handling
+}
+
+FrameSelector::~FrameSelector()
+{
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ if( mxAccess.is() )
+ mxAccess->Invalidate();
+#endif
+}
+
+void FrameSelector::Initialize( FrameSelFlags nFlags )
+{
+ mxImpl->Initialize( nFlags );
+ Show();
+}
+
+// enabled frame borders
+bool FrameSelector::IsBorderEnabled( FrameBorderType eBorder ) const
+{
+ return mxImpl->GetBorder( eBorder ).IsEnabled();
+}
+
+sal_Int32 FrameSelector::GetEnabledBorderCount() const
+{
+ return static_cast< sal_Int32 >( mxImpl->maEnabBorders.size() );
+}
+
+FrameBorderType FrameSelector::GetEnabledBorderType( sal_Int32 nIndex ) const
+{
+ FrameBorderType eBorder = FrameBorderType::NONE;
+ if( nIndex >= 0 )
+ {
+ size_t nVecIdx = static_cast< size_t >( nIndex );
+ if( nVecIdx < mxImpl->maEnabBorders.size() )
+ eBorder = mxImpl->maEnabBorders[ nVecIdx ]->GetType();
+ }
+ return eBorder;
+}
+
+// frame border state and style
+bool FrameSelector::SupportsDontCareState() const
+{
+ return bool(mxImpl->mnFlags & FrameSelFlags::DontCare);
+}
+
+FrameBorderState FrameSelector::GetFrameBorderState( FrameBorderType eBorder ) const
+{
+ return mxImpl->GetBorder( eBorder ).GetState();
+}
+
+const SvxBorderLine* FrameSelector::GetFrameBorderStyle( FrameBorderType eBorder ) const
+{
+ const SvxBorderLine& rStyle = mxImpl->GetBorder( eBorder ).GetCoreStyle();
+ // rest of the world uses null pointer for invisible frame border
+ return rStyle.GetOutWidth() ? &rStyle : nullptr;
+}
+
+void FrameSelector::ShowBorder( FrameBorderType eBorder, const SvxBorderLine* pStyle )
+{
+ mxImpl->SetBorderCoreStyle( mxImpl->GetBorderAccess( eBorder ), pStyle );
+}
+
+void FrameSelector::SetBorderDontCare( FrameBorderType eBorder )
+{
+ mxImpl->SetBorderState( mxImpl->GetBorderAccess( eBorder ), FrameBorderState::DontCare );
+}
+
+bool FrameSelector::IsAnyBorderVisible() const
+{
+ bool bIsSet = false;
+ for( FrameBorderCIter aIt( mxImpl->maEnabBorders ); !bIsSet && aIt.Is(); ++aIt )
+ bIsSet = ((*aIt)->GetState() == FrameBorderState::Show);
+ return bIsSet;
+}
+
+void FrameSelector::HideAllBorders()
+{
+ for( FrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
+ mxImpl->SetBorderState( **aIt, FrameBorderState::Hide );
+}
+
+bool FrameSelector::GetVisibleWidth( tools::Long& rnWidth, SvxBorderLineStyle& rnStyle ) const
+{
+ VisFrameBorderCIter aIt( mxImpl->maEnabBorders );
+ if( !aIt.Is() )
+ return false;
+
+ const SvxBorderLine& rStyle = (*aIt)->GetCoreStyle();
+ bool bFound = true;
+ for( ++aIt; bFound && aIt.Is(); ++aIt )
+ {
+ bFound =
+ (rStyle.GetWidth() == (*aIt)->GetCoreStyle().GetWidth()) &&
+ (rStyle.GetBorderLineStyle() ==
+ (*aIt)->GetCoreStyle().GetBorderLineStyle());
+ }
+
+ if( bFound )
+ {
+ rnWidth = rStyle.GetWidth();
+ rnStyle = rStyle.GetBorderLineStyle();
+ }
+ return bFound;
+}
+
+bool FrameSelector::GetVisibleColor( Color& rColor ) const
+{
+ VisFrameBorderCIter aIt( mxImpl->maEnabBorders );
+ if( !aIt.Is() )
+ return false;
+
+ const SvxBorderLine& rStyle = (*aIt)->GetCoreStyle();
+ bool bFound = true;
+ for( ++aIt; bFound && aIt.Is(); ++aIt )
+ bFound = (rStyle.GetColor() == (*aIt)->GetCoreStyle().GetColor());
+
+ if( bFound )
+ rColor = rStyle.GetColor();
+ return bFound;
+}
+
+// frame border selection
+const Link<LinkParamNone*,void>& FrameSelector::GetSelectHdl() const
+{
+ return mxImpl->maSelectHdl;
+}
+
+void FrameSelector::SetSelectHdl( const Link<LinkParamNone*,void>& rHdl )
+{
+ mxImpl->maSelectHdl = rHdl;
+}
+
+bool FrameSelector::IsBorderSelected( FrameBorderType eBorder ) const
+{
+ return mxImpl->GetBorder( eBorder ).IsSelected();
+}
+
+void FrameSelector::SelectBorder( FrameBorderType eBorder )
+{
+ mxImpl->SelectBorder( mxImpl->GetBorderAccess( eBorder ), true/*bSelect*/ );
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ // MT: bFireFox as API parameter is ugly...
+ // if (bFocus)
+ {
+ rtl::Reference< a11y::AccFrameSelectorChild > xRet = GetChildAccessible(eBorder);
+ if (xRet.is())
+ {
+ Any aOldValue, aNewValue;
+ aNewValue <<= AccessibleStateType::FOCUSED;
+ xRet->NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
+ }
+ }
+#endif
+}
+
+bool FrameSelector::IsAnyBorderSelected() const
+{
+ // Construct an iterator for selected borders. If it is valid, there is a selected border.
+ return SelFrameBorderCIter( mxImpl->maEnabBorders ).Is();
+}
+
+void FrameSelector::SelectAllBorders( bool bSelect )
+{
+ for( FrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
+ mxImpl->SelectBorder( **aIt, bSelect );
+}
+
+void FrameSelector::SelectAllVisibleBorders()
+{
+ for( VisFrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
+ mxImpl->SelectBorder( **aIt, true/*bSelect*/ );
+}
+
+void FrameSelector::SetStyleToSelection( tools::Long nWidth, SvxBorderLineStyle nStyle )
+{
+ mxImpl->maCurrStyle.SetBorderLineStyle( nStyle );
+ mxImpl->maCurrStyle.SetWidth( nWidth );
+ for( SelFrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
+ mxImpl->SetBorderState( **aIt, FrameBorderState::Show );
+}
+
+void FrameSelector::SetColorToSelection(const Color& rColor, model::ComplexColor const& rComplexColor)
+{
+ mxImpl->maCurrStyle.SetColor(rColor);
+ mxImpl->maCurrStyle.setComplexColor(rComplexColor);
+
+ for( SelFrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
+ mxImpl->SetBorderState( **aIt, FrameBorderState::Show );
+}
+
+SvxBorderLineStyle FrameSelector::getCurrentStyleLineStyle() const
+{
+ return mxImpl->maCurrStyle.GetBorderLineStyle();
+}
+
+// accessibility
+Reference< XAccessible > FrameSelector::CreateAccessible()
+{
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ if( !mxAccess.is() )
+ mxAccess = new a11y::AccFrameSelector(*this);
+#endif
+ return mxAccess;
+}
+
+rtl::Reference< a11y::AccFrameSelectorChild > FrameSelector::GetChildAccessible( FrameBorderType eBorder )
+{
+ rtl::Reference< a11y::AccFrameSelectorChild > xRet;
+ size_t nVecIdx = static_cast< size_t >( eBorder );
+ if( IsBorderEnabled( eBorder ) && (1 <= nVecIdx) && (nVecIdx <= mxImpl->maChildVec.size()) )
+ {
+ --nVecIdx;
+ if( !mxImpl->maChildVec[ nVecIdx ].is() )
+ mxImpl->maChildVec[ nVecIdx ] = new a11y::AccFrameSelectorChild( *this, eBorder );
+ xRet = mxImpl->maChildVec[ nVecIdx ].get();
+ }
+ return xRet;
+}
+
+Reference< XAccessible > FrameSelector::GetChildAccessible( sal_Int32 nIndex )
+{
+ return GetChildAccessible( GetEnabledBorderType( nIndex ) );
+}
+
+Reference< XAccessible > FrameSelector::GetChildAccessible( const Point& rPos )
+{
+ Reference< XAccessible > xRet;
+ for( FrameBorderCIter aIt( mxImpl->maEnabBorders ); !xRet.is() && aIt.Is(); ++aIt )
+ if( (*aIt)->ContainsClickPoint( rPos ) )
+ xRet = GetChildAccessible( (*aIt)->GetType() ).get();
+ return xRet;
+}
+
+tools::Rectangle FrameSelector::GetClickBoundRect( FrameBorderType eBorder ) const
+{
+ tools::Rectangle aRect;
+ const FrameBorder& rBorder = mxImpl->GetBorder( eBorder );
+ if( rBorder.IsEnabled() )
+ aRect = rBorder.GetClickBoundRect();
+ return aRect;
+}
+
+// virtual functions from base class
+void FrameSelector::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ mxImpl->CopyVirDevToControl(rRenderContext);
+ if (HasFocus())
+ mxImpl->DrawAllTrackingRects(rRenderContext);
+}
+
+bool FrameSelector::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ /* Mouse handling:
+ * Click on an unselected frame border:
+ Set current style/color, make frame border visible, deselect all
+ other frame borders.
+ * Click on a selected frame border:
+ Toggle state of the frame border (visible -> don't care -> hidden),
+ deselect all other frame borders.
+ * SHIFT+Click or CTRL+Click on an unselected frame border:
+ Extend selection, set current style/color to all selected frame
+ borders independent of the state/style/color of the borders.
+ * SHIFT+Click or CTRL+Click on a selected frame border:
+ If all frame borders have same style/color, toggle state of all
+ borders (see above), otherwise set current style/color to all
+ borders.
+ * Click on unused area: Do not modify selection and selected frame
+ borders.
+ */
+
+ // #107394# do not auto-select a frame border
+ mxImpl->SilentGrabFocus();
+
+ if( rMEvt.IsLeft() )
+ {
+ Point aPos( mxImpl->GetDevPosFromMousePos( rMEvt.GetPosPixel() ) );
+ FrameBorderPtrVec aDeselectBorders;
+
+ bool bAnyClicked = false; // Any frame border clicked?
+ bool bNewSelected = false; // Any unselected frame border selected?
+
+ /* If frame borders are set to "don't care" and the control does not
+ support this state, hide them on first mouse click.
+ DR 2004-01-30: Why are the borders set to "don't care" then?!? */
+ bool bHideDontCare = !SupportsDontCareState();
+
+ for( FrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
+ {
+ if( (*aIt)->ContainsClickPoint( aPos ) )
+ {
+ // frame border is clicked
+ bAnyClicked = true;
+ if( !(*aIt)->IsSelected() )
+ {
+ bNewSelected = true;
+ //mxImpl->SelectBorder( **aIt, true );
+ SelectBorder((**aIt).GetType());
+ }
+ }
+ else
+ {
+ // hide a "don't care" frame border only if it is not clicked
+ if( bHideDontCare && ((*aIt)->GetState() == FrameBorderState::DontCare) )
+ mxImpl->SetBorderState( **aIt, FrameBorderState::Hide );
+
+ // deselect frame borders not clicked (if SHIFT or CTRL are not pressed)
+ if( !rMEvt.IsShift() && !rMEvt.IsMod1() )
+ aDeselectBorders.push_back( *aIt );
+ }
+ }
+
+ if( bAnyClicked )
+ {
+ // any valid frame border clicked? -> deselect other frame borders
+ for( FrameBorderIter aIt( aDeselectBorders ); aIt.Is(); ++aIt )
+ mxImpl->SelectBorder( **aIt, false );
+
+ if( bNewSelected || !mxImpl->SelectedBordersEqual() )
+ {
+ // new frame border selected, selection extended, or selected borders different? -> show
+ for( SelFrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
+ // SetBorderState() sets current style and color to the frame border
+ mxImpl->SetBorderState( **aIt, FrameBorderState::Show );
+ }
+ else
+ {
+ // all selected frame borders are equal -> toggle state
+ for( SelFrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
+ mxImpl->ToggleBorderState( **aIt );
+ }
+
+ GetSelectHdl().Call( nullptr );
+ }
+ }
+
+ return true;
+}
+
+bool FrameSelector::KeyInput( const KeyEvent& rKEvt )
+{
+ bool bHandled = false;
+ vcl::KeyCode aKeyCode = rKEvt.GetKeyCode();
+ if( !aKeyCode.GetModifier() )
+ {
+ sal_uInt16 nCode = aKeyCode.GetCode();
+ switch( nCode )
+ {
+ case KEY_SPACE:
+ {
+ for( SelFrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
+ mxImpl->ToggleBorderState( **aIt );
+ bHandled = true;
+ }
+ break;
+
+ case KEY_UP:
+ case KEY_DOWN:
+ case KEY_LEFT:
+ case KEY_RIGHT:
+ {
+ if( !mxImpl->maEnabBorders.empty() )
+ {
+ // start from first selected frame border
+ SelFrameBorderCIter aIt( mxImpl->maEnabBorders );
+ FrameBorderType eBorder = aIt.Is() ? (*aIt)->GetType() : mxImpl->maEnabBorders.front()->GetType();
+
+ // search for next enabled frame border
+ do
+ {
+ eBorder = mxImpl->GetBorder( eBorder ).GetKeyboardNeighbor( nCode );
+ }
+ while( (eBorder != FrameBorderType::NONE) && !IsBorderEnabled( eBorder ) );
+
+ // select the frame border
+ if( eBorder != FrameBorderType::NONE )
+ {
+ DeselectAllBorders();
+ SelectBorder( eBorder );
+ }
+ bHandled = true;
+ }
+ }
+ break;
+ }
+ }
+ if (bHandled)
+ return true;
+ return CustomWidgetController::KeyInput(rKEvt);
+}
+
+void FrameSelector::GetFocus()
+{
+ // auto-selection of a frame border, if focus reaches control, and nothing is selected
+ if( mxImpl->mbAutoSelect && !IsAnyBorderSelected() && !mxImpl->maEnabBorders.empty() )
+ mxImpl->SelectBorder( *mxImpl->maEnabBorders.front(), true );
+
+ mxImpl->DoInvalidate( false );
+ if (IsAnyBorderSelected())
+ {
+ FrameBorderType borderType = FrameBorderType::NONE;
+ if (mxImpl->maLeft.IsSelected())
+ borderType = FrameBorderType::Left;
+ else if (mxImpl->maRight.IsSelected())
+ borderType = FrameBorderType::Right;
+ else if (mxImpl->maTop.IsSelected())
+ borderType = FrameBorderType::Top;
+ else if (mxImpl->maBottom.IsSelected())
+ borderType = FrameBorderType::Bottom;
+ else if (mxImpl->maHor.IsSelected())
+ borderType = FrameBorderType::Horizontal;
+ else if (mxImpl->maVer.IsSelected())
+ borderType = FrameBorderType::Vertical;
+ else if (mxImpl->maTLBR.IsSelected())
+ borderType = FrameBorderType::TLBR;
+ else if (mxImpl->maBLTR.IsSelected())
+ borderType = FrameBorderType::BLTR;
+ SelectBorder(borderType);
+ }
+ for( SelFrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
+ mxImpl->SetBorderState( **aIt, FrameBorderState::Show );
+ CustomWidgetController::GetFocus();
+}
+
+void FrameSelector::LoseFocus()
+{
+ mxImpl->DoInvalidate( false );
+ CustomWidgetController::LoseFocus();
+}
+
+void FrameSelector::StyleUpdated()
+{
+ mxImpl->InitVirtualDevice();
+ CustomWidgetController::StyleUpdated();
+}
+
+void FrameSelector::Resize()
+{
+ CustomWidgetController::Resize();
+ mxImpl->sizeChanged();
+}
+
+template< typename Cont, typename Iter, typename Pred >
+FrameBorderIterBase< Cont, Iter, Pred >::FrameBorderIterBase( container_type& rCont ) :
+ maIt( rCont.begin() ),
+ maEnd( rCont.end() )
+{
+ while( Is() && !maPred( *maIt ) ) ++maIt;
+}
+
+template< typename Cont, typename Iter, typename Pred >
+FrameBorderIterBase< Cont, Iter, Pred >& FrameBorderIterBase< Cont, Iter, Pred >::operator++()
+{
+ do { ++maIt; } while( Is() && !maPred( *maIt ) );
+ return *this;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/graphctl.cxx b/svx/source/dialog/graphctl.cxx
new file mode 100644
index 0000000000..cf127d670a
--- /dev/null
+++ b/svx/source/dialog/graphctl.cxx
@@ -0,0 +1,850 @@
+/* -*- 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_wasm_strip.h>
+
+#include <svl/itempool.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/ptrstyle.hxx>
+#include <vcl/svapp.hxx>
+
+#include <svx/graphctl.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+#include <GraphCtlAccessibleContext.hxx>
+#include <svx/svxids.hrc>
+#include <svx/svdpage.hxx>
+#include <svx/sdrpaintwindow.hxx>
+
+void GraphCtrlUserCall::Changed( const SdrObject& rObj, SdrUserCallType eType, const tools::Rectangle& /*rOldBoundRect*/ )
+{
+ switch( eType )
+ {
+ case SdrUserCallType::MoveOnly:
+ case SdrUserCallType::Resize:
+ rWin.SdrObjChanged( rObj );
+ break;
+
+ case SdrUserCallType::Inserted:
+ rWin.SdrObjCreated( rObj );
+ break;
+
+ default:
+ break;
+ }
+ rWin.QueueIdleUpdate();
+}
+
+GraphCtrl::GraphCtrl(weld::Dialog* pDialog)
+ : aUpdateIdle("svx GraphCtrl Update")
+ , aMap100(MapUnit::Map100thMM)
+ , eObjKind(SdrObjKind::NONE)
+ , nPolyEdit(0)
+ , bEditMode(false)
+ , mbSdrMode(false)
+ , mbInIdleUpdate(false)
+ , mpDialog(pDialog)
+{
+ pUserCall.reset(new GraphCtrlUserCall( *this ));
+ aUpdateIdle.SetPriority( TaskPriority::LOWEST );
+ aUpdateIdle.SetInvokeHandler( LINK( this, GraphCtrl, UpdateHdl ) );
+ aUpdateIdle.Start();
+}
+
+void GraphCtrl::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ weld::CustomWidgetController::SetDrawingArea(pDrawingArea);
+ EnableRTL(false);
+}
+
+GraphCtrl::~GraphCtrl()
+{
+ aUpdateIdle.Stop();
+
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ if( mpAccContext.is() )
+ {
+ mpAccContext->disposing();
+ mpAccContext.clear();
+ }
+#endif
+
+ pView.reset();
+ pModel.reset();
+ pUserCall.reset();
+}
+
+void GraphCtrl::SetSdrMode(bool bSdrMode)
+{
+ mbSdrMode = bSdrMode;
+
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
+ rDevice.SetBackground( Wallpaper( rStyleSettings.GetWindowColor() ) );
+ xVD->SetBackground( Wallpaper( rStyleSettings.GetWindowColor() ) );
+ rDevice.SetMapMode( aMap100 );
+ xVD->SetMapMode( aMap100 );
+
+ pView.reset();
+ pModel.reset();
+
+ if ( mbSdrMode )
+ InitSdrModel();
+
+ QueueIdleUpdate();
+}
+
+void GraphCtrl::InitSdrModel()
+{
+ SolarMutexGuard aGuard;
+
+ rtl::Reference<SdrPage> pPage;
+
+ // destroy old junk
+ pView.reset();
+ pModel.reset();
+
+ // Creating a Model
+ pModel.reset(new SdrModel(nullptr, nullptr, true));
+ pModel->GetItemPool().FreezeIdRanges();
+ pModel->SetScaleUnit(aMap100.GetMapUnit());
+ pModel->SetDefaultFontHeight( 500 );
+
+ pPage = new SdrPage( *pModel );
+
+ pPage->SetSize( aGraphSize );
+ pPage->SetBorder( 0, 0, 0, 0 );
+ pModel->InsertPage( pPage.get() );
+ pModel->SetChanged( false );
+
+ // Creating a View
+ pView.reset(new GraphCtrlView(*pModel, this));
+ pView->SetWorkArea( tools::Rectangle( Point(), aGraphSize ) );
+ pView->EnableExtendedMouseEventDispatcher( true );
+ pView->ShowSdrPage(pView->GetModel().GetPage(0));
+ pView->SetFrameDragSingles();
+ pView->SetMarkedPointsSmooth( SdrPathSmoothKind::Symmetric );
+ pView->SetEditMode();
+
+ // #i72889# set needed flags
+ pView->SetPageDecorationAllowed(false);
+ pView->SetMasterPageVisualizationAllowed(false);
+ pView->SetBufferedOutputAllowed(true);
+ pView->SetBufferedOverlayAllowed(true);
+
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ // Tell the accessibility object about the changes.
+ if (mpAccContext.is())
+ mpAccContext->setModelAndView (pModel.get(), pView.get());
+#endif
+}
+
+void GraphCtrl::SetGraphic( const Graphic& rGraphic, bool bNewModel )
+{
+ aGraphic = rGraphic;
+ xVD->SetOutputSizePixel(Size(0, 0)); //force redraw
+
+ if ( aGraphic.GetPrefMapMode().GetMapUnit() == MapUnit::MapPixel )
+ aGraphSize = Application::GetDefaultDevice()->PixelToLogic( aGraphic.GetPrefSize(), aMap100 );
+ else
+ aGraphSize = OutputDevice::LogicToLogic( aGraphic.GetPrefSize(), aGraphic.GetPrefMapMode(), aMap100 );
+
+ if ( mbSdrMode && bNewModel )
+ InitSdrModel();
+
+ aGraphSizeLink.Call( this );
+
+ Resize();
+
+ Invalidate();
+ QueueIdleUpdate();
+}
+
+void GraphCtrl::GraphicToVD()
+{
+ OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
+ xVD->SetOutputSizePixel(GetOutputSizePixel());
+ xVD->SetBackground(rDevice.GetBackground());
+ xVD->Erase();
+ const bool bGraphicValid(GraphicType::NONE != aGraphic.GetType());
+ if (bGraphicValid)
+ aGraphic.Draw(*xVD, Point(), aGraphSize);
+}
+
+void GraphCtrl::Resize()
+{
+ weld::CustomWidgetController::Resize();
+
+ if (aGraphSize.Width() && aGraphSize.Height())
+ {
+ MapMode aDisplayMap( aMap100 );
+ Point aNewPos;
+ Size aNewSize;
+ OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
+ const Size aWinSize = rDevice.PixelToLogic( GetOutputSizePixel(), aDisplayMap );
+ const tools::Long nWidth = aWinSize.Width();
+ const tools::Long nHeight = aWinSize.Height();
+ double fGrfWH = static_cast<double>(aGraphSize.Width()) / aGraphSize.Height();
+ double fWinWH = static_cast<double>(nWidth) / nHeight;
+
+ // Adapt Bitmap to Thumb size
+ if ( fGrfWH < fWinWH)
+ {
+ aNewSize.setWidth( static_cast<tools::Long>( static_cast<double>(nHeight) * fGrfWH ) );
+ aNewSize.setHeight( nHeight );
+ }
+ else
+ {
+ aNewSize.setWidth( nWidth );
+ aNewSize.setHeight( static_cast<tools::Long>( static_cast<double>(nWidth) / fGrfWH ) );
+ }
+
+ aNewPos.setX( ( nWidth - aNewSize.Width() ) >> 1 );
+ aNewPos.setY( ( nHeight - aNewSize.Height() ) >> 1 );
+
+ // Implementing MapMode for Engine
+ aDisplayMap.SetScaleX( Fraction( aNewSize.Width(), aGraphSize.Width() ) );
+ aDisplayMap.SetScaleY( Fraction( aNewSize.Height(), aGraphSize.Height() ) );
+
+ aDisplayMap.SetOrigin( OutputDevice::LogicToLogic( aNewPos, aMap100, aDisplayMap ) );
+ rDevice.SetMapMode( aDisplayMap );
+ xVD->SetMapMode( aDisplayMap );
+ }
+
+ Invalidate();
+}
+
+void GraphCtrl::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
+{
+ // #i72889# used split repaint to be able to paint an own background
+ // even to the buffered view
+ const bool bGraphicValid(GraphicType::NONE != aGraphic.GetType());
+
+ if (GetOutputSizePixel() != xVD->GetOutputSizePixel())
+ GraphicToVD();
+
+ if (mbSdrMode)
+ {
+ SdrPaintWindow* pPaintWindow = pView->BeginCompleteRedraw(&rRenderContext);
+ pPaintWindow->SetOutputToWindow(true);
+
+ if (bGraphicValid)
+ {
+ vcl::RenderContext& rTarget = pPaintWindow->GetTargetOutputDevice();
+
+ OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
+ rTarget.SetBackground(rDevice.GetBackground());
+ rTarget.Erase();
+
+ rTarget.DrawOutDev(Point(), xVD->GetOutputSize(), Point(), xVD->GetOutputSize(), *xVD);
+ }
+
+ const vcl::Region aRepaintRegion(rRect);
+ pView->DoCompleteRedraw(*pPaintWindow, aRepaintRegion);
+ pView->EndCompleteRedraw(*pPaintWindow, true);
+ }
+ else
+ {
+ // #i73381# in non-SdrMode, paint to local directly
+ rRenderContext.DrawOutDev(rRect.TopLeft(), rRect.GetSize(),
+ rRect.TopLeft(), rRect.GetSize(),
+ *xVD);
+ }
+}
+
+void GraphCtrl::SdrObjChanged( const SdrObject& )
+{
+ QueueIdleUpdate();
+}
+
+void GraphCtrl::SdrObjCreated( const SdrObject& )
+{
+ QueueIdleUpdate();
+}
+
+void GraphCtrl::MarkListHasChanged()
+{
+ QueueIdleUpdate();
+}
+
+bool GraphCtrl::KeyInput( const KeyEvent& rKEvt )
+{
+ vcl::KeyCode aCode( rKEvt.GetKeyCode() );
+ bool bProc = false;
+
+ OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
+
+ switch ( aCode.GetCode() )
+ {
+ case KEY_DELETE:
+ case KEY_BACKSPACE:
+ {
+ if ( mbSdrMode )
+ {
+ pView->DeleteMarked();
+ bProc = true;
+ }
+ }
+ break;
+
+ case KEY_ESCAPE:
+ {
+ if ( mbSdrMode )
+ {
+ if ( pView->IsAction() )
+ {
+ pView->BrkAction();
+ bProc = true;
+ }
+ else if ( pView->AreObjectsMarked() )
+ {
+ pView->UnmarkAllObj();
+ bProc = true;
+ }
+ }
+ }
+ break;
+
+ case KEY_F11:
+ case KEY_TAB:
+ {
+ if( mbSdrMode )
+ {
+ if( !aCode.IsMod1() && !aCode.IsMod2() )
+ {
+ bool bForward = !aCode.IsShift();
+ // select next object
+ if ( ! pView->MarkNextObj( bForward ))
+ {
+ // At first or last object. Cycle to the other end
+ // of the list.
+ pView->UnmarkAllObj();
+ pView->MarkNextObj (bForward);
+ }
+ bProc = true;
+ }
+ else if(aCode.IsMod1())
+ {
+ // select next handle
+ const SdrHdlList& rHdlList = pView->GetHdlList();
+ bool bForward(!aCode.IsShift());
+
+ const_cast<SdrHdlList&>(rHdlList).TravelFocusHdl(bForward);
+
+ bProc = true;
+ }
+ }
+ }
+ break;
+
+ case KEY_END:
+ {
+
+ if ( aCode.IsMod1() )
+ {
+ // mark last object
+ pView->UnmarkAllObj();
+ pView->MarkNextObj();
+
+ bProc = true;
+ }
+ }
+ break;
+
+ case KEY_HOME:
+ {
+ if ( aCode.IsMod1() )
+ {
+ pView->UnmarkAllObj();
+ pView->MarkNextObj(true);
+
+ bProc = true;
+ }
+ }
+ break;
+
+ case KEY_UP:
+ case KEY_DOWN:
+ case KEY_LEFT:
+ case KEY_RIGHT:
+ {
+ tools::Long nX = 0;
+ tools::Long nY = 0;
+
+ if (aCode.GetCode() == KEY_UP)
+ {
+ // Scroll up
+ nX = 0;
+ nY =-1;
+ }
+ else if (aCode.GetCode() == KEY_DOWN)
+ {
+ // Scroll down
+ nX = 0;
+ nY = 1;
+ }
+ else if (aCode.GetCode() == KEY_LEFT)
+ {
+ // Scroll left
+ nX =-1;
+ nY = 0;
+ }
+ else if (aCode.GetCode() == KEY_RIGHT)
+ {
+ // Scroll right
+ nX = 1;
+ nY = 0;
+ }
+
+ if (pView->AreObjectsMarked() && !aCode.IsMod1() )
+ {
+ if(aCode.IsMod2())
+ {
+ // move in 1 pixel distance
+ Size aLogicSizeOnePixel = rDevice.PixelToLogic(Size(1,1));
+ nX *= aLogicSizeOnePixel.Width();
+ nY *= aLogicSizeOnePixel.Height();
+ }
+ else
+ {
+ // old, fixed move distance
+ nX *= 100;
+ nY *= 100;
+ }
+
+ // II
+ const SdrHdlList& rHdlList = pView->GetHdlList();
+ SdrHdl* pHdl = rHdlList.GetFocusHdl();
+
+ if(nullptr == pHdl)
+ {
+ // restrict movement to WorkArea
+ const tools::Rectangle& rWorkArea = pView->GetWorkArea();
+
+ if(!rWorkArea.IsEmpty())
+ {
+ tools::Rectangle aMarkRect(pView->GetMarkedObjRect());
+ aMarkRect.Move(nX, nY);
+
+ if(!aMarkRect.Contains(rWorkArea))
+ {
+ if(aMarkRect.Left() < rWorkArea.Left())
+ {
+ nX += rWorkArea.Left() - aMarkRect.Left();
+ }
+
+ if(aMarkRect.Right() > rWorkArea.Right())
+ {
+ nX -= aMarkRect.Right() - rWorkArea.Right();
+ }
+
+ if(aMarkRect.Top() < rWorkArea.Top())
+ {
+ nY += rWorkArea.Top() - aMarkRect.Top();
+ }
+
+ if(aMarkRect.Bottom() > rWorkArea.Bottom())
+ {
+ nY -= aMarkRect.Bottom() - rWorkArea.Bottom();
+ }
+ }
+ }
+
+ // no handle selected
+ if(0 != nX || 0 != nY)
+ {
+ pView->MoveAllMarked(Size(nX, nY));
+ }
+ }
+ else
+ {
+ // move handle with index nHandleIndex
+ if (nX || nY)
+ {
+ // now move the Handle (nX, nY)
+ Point aStartPoint(pHdl->GetPos());
+ Point aEndPoint(pHdl->GetPos() + Point(nX, nY));
+ const SdrDragStat& rDragStat = pView->GetDragStat();
+
+ // start dragging
+ pView->BegDragObj(aStartPoint, nullptr, pHdl, 0);
+
+ if(pView->IsDragObj())
+ {
+ bool bWasNoSnap = rDragStat.IsNoSnap();
+ bool bWasSnapEnabled = pView->IsSnapEnabled();
+
+ // switch snapping off
+ if(!bWasNoSnap)
+ const_cast<SdrDragStat&>(rDragStat).SetNoSnap();
+ if(bWasSnapEnabled)
+ pView->SetSnapEnabled(false);
+
+ pView->MovAction(aEndPoint);
+ pView->EndDragObj();
+
+ // restore snap
+ if(!bWasNoSnap)
+ const_cast<SdrDragStat&>(rDragStat).SetNoSnap(bWasNoSnap);
+ if(bWasSnapEnabled)
+ pView->SetSnapEnabled(bWasSnapEnabled);
+ }
+ }
+ }
+
+ bProc = true;
+ }
+ }
+ break;
+
+ case KEY_SPACE:
+ {
+ const SdrHdlList& rHdlList = pView->GetHdlList();
+ SdrHdl* pHdl = rHdlList.GetFocusHdl();
+
+ if(pHdl)
+ {
+ if(pHdl->GetKind() == SdrHdlKind::Poly)
+ {
+ // rescue ID of point with focus
+ sal_uInt32 nPol(pHdl->GetPolyNum());
+ sal_uInt32 nPnt(pHdl->GetPointNum());
+
+ if(pView->IsPointMarked(*pHdl))
+ {
+ if(rKEvt.GetKeyCode().IsShift())
+ {
+ pView->UnmarkPoint(*pHdl);
+ }
+ }
+ else
+ {
+ if(!rKEvt.GetKeyCode().IsShift())
+ {
+ pView->UnmarkAllPoints();
+ }
+
+ pView->MarkPoint(*pHdl);
+ }
+
+ if(nullptr == rHdlList.GetFocusHdl())
+ {
+ // restore point with focus
+ SdrHdl* pNewOne = nullptr;
+
+ for(size_t a = 0; !pNewOne && a < rHdlList.GetHdlCount(); ++a)
+ {
+ SdrHdl* pAct = rHdlList.GetHdl(a);
+
+ if(pAct
+ && pAct->GetKind() == SdrHdlKind::Poly
+ && pAct->GetPolyNum() == nPol
+ && pAct->GetPointNum() == nPnt)
+ {
+ pNewOne = pAct;
+ }
+ }
+
+ if(pNewOne)
+ {
+ const_cast<SdrHdlList&>(rHdlList).SetFocusHdl(pNewOne);
+ }
+ }
+
+ bProc = true;
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (bProc)
+ ReleaseMouse();
+
+ QueueIdleUpdate();
+
+ return bProc;
+}
+
+bool GraphCtrl::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ if ( mbSdrMode && ( rMEvt.GetClicks() < 2 ) )
+ {
+ OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
+
+ const Point aLogPt( rDevice.PixelToLogic( rMEvt.GetPosPixel() ) );
+
+ if ( !tools::Rectangle( Point(), aGraphSize ).Contains( aLogPt ) && !pView->IsEditMode() )
+ weld::CustomWidgetController::MouseButtonDown( rMEvt );
+ else
+ {
+ // Get Focus for key inputs
+ GrabFocus();
+
+ if ( nPolyEdit )
+ {
+ SdrViewEvent aVEvt;
+ SdrHitKind eHit = pView->PickAnything( rMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt );
+
+ if ( nPolyEdit == SID_BEZIER_INSERT && eHit == SdrHitKind::MarkedObject )
+ pView->BegInsObjPoint( aLogPt, rMEvt.IsMod1());
+ else
+ pView->MouseButtonDown( rMEvt, &rDevice );
+ }
+ else
+ pView->MouseButtonDown( rMEvt, &rDevice );
+ }
+
+ SdrObject* pCreateObj = pView->GetCreateObj();
+
+ // We want to realize the insert
+ if ( pCreateObj && !pCreateObj->GetUserCall() )
+ pCreateObj->SetUserCall( pUserCall.get() );
+
+ SetPointer( pView->GetPreferredPointer( aLogPt, &rDevice ) );
+ }
+ else
+ weld::CustomWidgetController::MouseButtonDown( rMEvt );
+
+ QueueIdleUpdate();
+
+ return false;
+}
+
+bool GraphCtrl::MouseMove(const MouseEvent& rMEvt)
+{
+ OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
+ const Point aLogPos( rDevice.PixelToLogic( rMEvt.GetPosPixel() ) );
+
+ if ( mbSdrMode )
+ {
+ pView->MouseMove( rMEvt, &rDevice );
+
+ if( ( SID_BEZIER_INSERT == nPolyEdit ) &&
+ !pView->PickHandle( aLogPos ) &&
+ !pView->IsInsObjPoint() )
+ {
+ SetPointer( PointerStyle::Cross );
+ }
+ else
+ SetPointer( pView->GetPreferredPointer( aLogPos, &rDevice ) );
+ }
+ else
+ weld::CustomWidgetController::MouseButtonUp( rMEvt );
+
+ if ( aMousePosLink.IsSet() )
+ {
+ if ( tools::Rectangle( Point(), aGraphSize ).Contains( aLogPos ) )
+ aMousePos = aLogPos;
+ else
+ aMousePos = Point();
+
+ aMousePosLink.Call( this );
+ }
+
+ QueueIdleUpdate();
+
+ return false;
+}
+
+bool GraphCtrl::MouseButtonUp(const MouseEvent& rMEvt)
+{
+ if ( mbSdrMode )
+ {
+ OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
+
+ if ( pView->IsInsObjPoint() )
+ pView->EndInsObjPoint( SdrCreateCmd::ForceEnd );
+ else
+ pView->MouseButtonUp( rMEvt, &rDevice );
+
+ ReleaseMouse();
+ SetPointer( pView->GetPreferredPointer( rDevice.PixelToLogic( rMEvt.GetPosPixel() ), &rDevice ) );
+ }
+ else
+ weld::CustomWidgetController::MouseButtonUp( rMEvt );
+
+ QueueIdleUpdate();
+
+ return false;
+}
+
+SdrObject* GraphCtrl::GetSelectedSdrObject() const
+{
+ SdrObject* pSdrObj = nullptr;
+
+ if ( mbSdrMode )
+ {
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+
+ if ( rMarkList.GetMarkCount() == 1 )
+ pSdrObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj();
+ }
+
+ return pSdrObj;
+}
+
+void GraphCtrl::SetEditMode( const bool _bEditMode )
+{
+ if ( mbSdrMode )
+ {
+ bEditMode = _bEditMode;
+ pView->SetEditMode( bEditMode );
+ eObjKind = SdrObjKind::NONE;
+ pView->SetCurrentObj(eObjKind);
+ }
+ else
+ bEditMode = false;
+
+ QueueIdleUpdate();
+}
+
+void GraphCtrl::SetPolyEditMode( const sal_uInt16 _nPolyEdit )
+{
+ if ( mbSdrMode && ( _nPolyEdit != nPolyEdit ) )
+ {
+ nPolyEdit = _nPolyEdit;
+ pView->SetFrameDragSingles( nPolyEdit == 0 );
+ }
+ else
+ nPolyEdit = 0;
+
+ QueueIdleUpdate();
+}
+
+void GraphCtrl::SetObjKind( const SdrObjKind _eObjKind )
+{
+ if ( mbSdrMode )
+ {
+ bEditMode = false;
+ pView->SetEditMode( bEditMode );
+ eObjKind = _eObjKind;
+ pView->SetCurrentObj(eObjKind);
+ }
+ else
+ eObjKind = SdrObjKind::NONE;
+
+ QueueIdleUpdate();
+}
+
+IMPL_LINK_NOARG(GraphCtrl, UpdateHdl, Timer *, void)
+{
+ mbInIdleUpdate = true;
+ aUpdateLink.Call( this );
+ mbInIdleUpdate = false;
+}
+
+void GraphCtrl::QueueIdleUpdate()
+{
+ if (!mbInIdleUpdate)
+ aUpdateIdle.Start();
+}
+
+namespace
+{
+ class WeldOverlayManager final : public sdr::overlay::OverlayManager
+ {
+ weld::CustomWidgetController& m_rGraphCtrl;
+
+ public:
+ WeldOverlayManager(weld::CustomWidgetController& rGraphCtrl, OutputDevice& rDevice)
+ : OverlayManager(rDevice)
+ , m_rGraphCtrl(rGraphCtrl)
+ {
+ }
+
+ // invalidate the given range at local OutputDevice
+ virtual void invalidateRange(const basegfx::B2DRange& rRange) override
+ {
+ tools::Rectangle aInvalidateRectangle(RangeToInvalidateRectangle(rRange));
+ m_rGraphCtrl.Invalidate(aInvalidateRectangle);
+ }
+ };
+}
+
+rtl::Reference<sdr::overlay::OverlayManager> GraphCtrlView::CreateOverlayManager(OutputDevice& rDevice) const
+{
+ assert(&rDevice == &rGraphCtrl.GetDrawingArea()->get_ref_device());
+ if (rDevice.GetOutDevType() == OUTDEV_VIRDEV)
+ {
+ rtl::Reference<sdr::overlay::OverlayManager> xOverlayManager(new WeldOverlayManager(rGraphCtrl, rDevice));
+ InitOverlayManager(xOverlayManager);
+ return xOverlayManager;
+ }
+ return SdrView::CreateOverlayManager(rDevice);
+}
+
+void GraphCtrlView::InvalidateOneWin(OutputDevice& rDevice)
+{
+ assert(&rDevice == &rGraphCtrl.GetDrawingArea()->get_ref_device());
+ if (rDevice.GetOutDevType() == OUTDEV_VIRDEV)
+ {
+ rGraphCtrl.Invalidate();
+ return;
+ }
+ SdrView::InvalidateOneWin(rDevice);
+}
+
+void GraphCtrlView::InvalidateOneWin(OutputDevice& rDevice, const tools::Rectangle& rArea)
+{
+ assert(&rDevice == &rGraphCtrl.GetDrawingArea()->get_ref_device());
+ if (rDevice.GetOutDevType() == OUTDEV_VIRDEV)
+ {
+ rGraphCtrl.Invalidate(rArea);
+ return;
+ }
+ SdrView::InvalidateOneWin(rDevice, rArea);
+}
+
+GraphCtrlView::~GraphCtrlView()
+{
+ // turn SetOutputToWindow back off again before
+ // turning back into our baseclass during dtoring
+ const sal_uInt32 nWindowCount(PaintWindowCount());
+ for (sal_uInt32 nWinNum(0); nWinNum < nWindowCount; nWinNum++)
+ {
+ SdrPaintWindow* pPaintWindow = GetPaintWindow(nWinNum);
+ pPaintWindow->SetOutputToWindow(false);
+ }
+}
+
+Point GraphCtrl::GetPositionInDialog() const
+{
+ int x, y, width, height;
+ if (GetDrawingArea()->get_extents_relative_to(*mpDialog, x, y, width, height))
+ return Point(x, y);
+ return Point();
+}
+
+css::uno::Reference< css::accessibility::XAccessible > GraphCtrl::CreateAccessible()
+{
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ if(mpAccContext == nullptr )
+ {
+ // Disable accessibility if no model/view data available
+ if (pView && pModel)
+ mpAccContext = new SvxGraphCtrlAccessibleContext(*this);
+ }
+#endif
+ return mpAccContext;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/grfflt.cxx b/svx/source/dialog/grfflt.cxx
new file mode 100644
index 0000000000..81b9289009
--- /dev/null
+++ b/svx/source/dialog/grfflt.cxx
@@ -0,0 +1,294 @@
+/* -*- 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/BitmapSharpenFilter.hxx>
+#include <vcl/BitmapMedianFilter.hxx>
+#include <vcl/BitmapSobelGreyFilter.hxx>
+#include <vcl/BitmapPopArtFilter.hxx>
+
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/viewsh.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/request.hxx>
+
+#include <osl/diagnose.h>
+#include <svx/grfflt.hxx>
+#include <svx/svxids.hrc>
+#include <svx/svxdlg.hxx>
+
+
+SvxGraphicFilterResult SvxGraphicFilter::ExecuteGrfFilterSlot( SfxRequest const & rReq, GraphicObject& rFilterObject )
+{
+ const Graphic& rGraphic = rFilterObject.GetGraphic();
+ SvxGraphicFilterResult nRet = SvxGraphicFilterResult::UnsupportedGraphicType;
+
+ if( rGraphic.GetType() == GraphicType::Bitmap )
+ {
+ SfxViewFrame* pViewFrame = SfxViewFrame::Current();
+ SfxObjectShell* pShell = pViewFrame ? pViewFrame->GetObjectShell() : nullptr;
+ weld::Window* pFrameWeld = (pViewFrame && pViewFrame->GetViewShell()) ? pViewFrame->GetViewShell()->GetFrameWeld() : nullptr;
+ Graphic aGraphic;
+
+ switch( rReq.GetSlot() )
+ {
+ case SID_GRFFILTER_INVERT:
+ {
+ if( pShell )
+ pShell->SetWaitCursor( true );
+
+ if( rGraphic.IsAnimated() )
+ {
+ Animation aAnimation( rGraphic.GetAnimation() );
+
+ if( aAnimation.Invert() )
+ aGraphic = aAnimation;
+ }
+ else
+ {
+ BitmapEx aBmpEx( rGraphic.GetBitmapEx() );
+
+ if( aBmpEx.Invert() )
+ aGraphic = aBmpEx;
+ }
+
+ if( pShell )
+ pShell->SetWaitCursor( false );
+ }
+ break;
+
+ case SID_GRFFILTER_SMOOTH:
+ {
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractGraphicFilterDialog> aDlg(pFact->CreateGraphicFilterSmooth(pFrameWeld, rGraphic, 0.7));
+ if( aDlg->Execute() == RET_OK )
+ aGraphic = aDlg->GetFilteredGraphic( rGraphic, 1.0, 1.0 );
+ }
+ break;
+
+ case SID_GRFFILTER_SHARPEN:
+ {
+ if( pShell )
+ pShell->SetWaitCursor( true );
+
+ if( rGraphic.IsAnimated() )
+ {
+ Animation aAnimation( rGraphic.GetAnimation() );
+
+ if (BitmapFilter::Filter(aAnimation, BitmapSharpenFilter()))
+ aGraphic = aAnimation;
+ }
+ else
+ {
+ BitmapEx aBmpEx( rGraphic.GetBitmapEx() );
+
+ if (BitmapFilter::Filter(aBmpEx, BitmapSharpenFilter()))
+ aGraphic = aBmpEx;
+ }
+
+ if( pShell )
+ pShell->SetWaitCursor( false );
+ }
+ break;
+
+ case SID_GRFFILTER_REMOVENOISE:
+ {
+ if( pShell )
+ pShell->SetWaitCursor( true );
+
+ if( rGraphic.IsAnimated() )
+ {
+ Animation aAnimation( rGraphic.GetAnimation() );
+
+ if (BitmapFilter::Filter(aAnimation, BitmapMedianFilter()))
+ aGraphic = aAnimation;
+ }
+ else
+ {
+ BitmapEx aBmpEx( rGraphic.GetBitmapEx() );
+
+ if (BitmapFilter::Filter(aBmpEx, BitmapMedianFilter()))
+ aGraphic = aBmpEx;
+ }
+
+ if( pShell )
+ pShell->SetWaitCursor( false );
+ }
+ break;
+
+ case SID_GRFFILTER_SOBEL:
+ {
+ if( pShell )
+ pShell->SetWaitCursor( true );
+
+ if( rGraphic.IsAnimated() )
+ {
+ Animation aAnimation( rGraphic.GetAnimation() );
+
+ if (BitmapFilter::Filter(aAnimation, BitmapSobelGreyFilter()))
+ aGraphic = aAnimation;
+ }
+ else
+ {
+ BitmapEx aBmpEx( rGraphic.GetBitmapEx() );
+
+ if (BitmapFilter::Filter(aBmpEx, BitmapSobelGreyFilter()))
+ aGraphic = aBmpEx;
+ }
+
+ if( pShell )
+ pShell->SetWaitCursor( false );
+ }
+ break;
+
+ case SID_GRFFILTER_MOSAIC:
+ {
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractGraphicFilterDialog> aDlg(pFact->CreateGraphicFilterMosaic(pFrameWeld, rGraphic));
+ if( aDlg->Execute() == RET_OK )
+ aGraphic = aDlg->GetFilteredGraphic( rGraphic, 1.0, 1.0 );
+ }
+ break;
+
+ case SID_GRFFILTER_EMBOSS:
+ {
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractGraphicFilterDialog> aDlg(pFact->CreateGraphicFilterEmboss(pFrameWeld, rGraphic));
+ if( aDlg->Execute() == RET_OK )
+ aGraphic = aDlg->GetFilteredGraphic( rGraphic, 1.0, 1.0 );
+ }
+ break;
+
+ case SID_GRFFILTER_POSTER:
+ {
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractGraphicFilterDialog> aDlg(pFact->CreateGraphicFilterPoster(pFrameWeld, rGraphic));
+ if( aDlg->Execute() == RET_OK )
+ aGraphic = aDlg->GetFilteredGraphic( rGraphic, 1.0, 1.0 );
+ }
+ break;
+
+ case SID_GRFFILTER_POPART:
+ {
+ if( pShell )
+ pShell->SetWaitCursor( true );
+
+ if( rGraphic.IsAnimated() )
+ {
+ Animation aAnimation( rGraphic.GetAnimation() );
+
+ if (BitmapFilter::Filter(aAnimation, BitmapPopArtFilter()))
+ aGraphic = aAnimation;
+ }
+ else
+ {
+ BitmapEx aBmpEx( rGraphic.GetBitmapEx() );
+
+ if (BitmapFilter::Filter(aBmpEx, BitmapPopArtFilter()))
+ aGraphic = aBmpEx;
+ }
+
+ if( pShell )
+ pShell->SetWaitCursor( false );
+ }
+ break;
+
+ case SID_GRFFILTER_SEPIA:
+ {
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractGraphicFilterDialog> aDlg(pFact->CreateGraphicFilterSepia(pFrameWeld, rGraphic));
+ if( aDlg->Execute() == RET_OK )
+ aGraphic = aDlg->GetFilteredGraphic( rGraphic, 1.0, 1.0 );
+ }
+ break;
+
+ case SID_GRFFILTER_SOLARIZE:
+ {
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractGraphicFilterDialog> aDlg(pFact->CreateGraphicFilterSolarize(pFrameWeld, rGraphic));
+ if( aDlg->Execute() == RET_OK )
+ aGraphic = aDlg->GetFilteredGraphic( rGraphic, 1.0, 1.0 );
+ }
+ break;
+
+ case SID_GRFFILTER :
+ {
+ // do nothing; no error
+ nRet = SvxGraphicFilterResult::NONE;
+ break;
+ }
+
+ default:
+ {
+ OSL_FAIL( "SvxGraphicFilter: selected filter slot not yet implemented" );
+ nRet = SvxGraphicFilterResult::UnsupportedSlot;
+ }
+ break;
+ }
+
+ if( aGraphic.GetType() != GraphicType::NONE )
+ {
+ rFilterObject.SetGraphic( aGraphic );
+ nRet = SvxGraphicFilterResult::NONE;
+ }
+ }
+
+ return nRet;
+}
+
+
+void SvxGraphicFilter::DisableGraphicFilterSlots( SfxItemSet& rSet )
+{
+ if( SfxItemState::DEFAULT <= rSet.GetItemState( SID_GRFFILTER ) )
+ rSet.DisableItem( SID_GRFFILTER );
+
+ if( SfxItemState::DEFAULT <= rSet.GetItemState( SID_GRFFILTER_INVERT ) )
+ rSet.DisableItem( SID_GRFFILTER_INVERT );
+
+ if( SfxItemState::DEFAULT <= rSet.GetItemState( SID_GRFFILTER_SMOOTH ) )
+ rSet.DisableItem( SID_GRFFILTER_SMOOTH );
+
+ if( SfxItemState::DEFAULT <= rSet.GetItemState( SID_GRFFILTER_SHARPEN ) )
+ rSet.DisableItem( SID_GRFFILTER_SHARPEN );
+
+ if( SfxItemState::DEFAULT <= rSet.GetItemState( SID_GRFFILTER_REMOVENOISE ) )
+ rSet.DisableItem( SID_GRFFILTER_REMOVENOISE );
+
+ if( SfxItemState::DEFAULT <= rSet.GetItemState( SID_GRFFILTER_SOBEL ) )
+ rSet.DisableItem( SID_GRFFILTER_SOBEL );
+
+ if( SfxItemState::DEFAULT <= rSet.GetItemState( SID_GRFFILTER_MOSAIC ) )
+ rSet.DisableItem( SID_GRFFILTER_MOSAIC );
+
+ if( SfxItemState::DEFAULT <= rSet.GetItemState( SID_GRFFILTER_EMBOSS ) )
+ rSet.DisableItem( SID_GRFFILTER_EMBOSS );
+
+ if( SfxItemState::DEFAULT <= rSet.GetItemState( SID_GRFFILTER_POSTER ) )
+ rSet.DisableItem( SID_GRFFILTER_POSTER );
+
+ if( SfxItemState::DEFAULT <= rSet.GetItemState( SID_GRFFILTER_POPART ) )
+ rSet.DisableItem( SID_GRFFILTER_POPART );
+
+ if( SfxItemState::DEFAULT <= rSet.GetItemState( SID_GRFFILTER_SEPIA ) )
+ rSet.DisableItem( SID_GRFFILTER_SEPIA );
+
+ if( SfxItemState::DEFAULT <= rSet.GetItemState( SID_GRFFILTER_SOLARIZE ) )
+ rSet.DisableItem( SID_GRFFILTER_SOLARIZE );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/hdft.cxx b/svx/source/dialog/hdft.cxx
new file mode 100644
index 0000000000..2052a072c0
--- /dev/null
+++ b/svx/source/dialog/hdft.cxx
@@ -0,0 +1,1046 @@
+/* -*- 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 <o3tl/unit_conversion.hxx>
+#include <svl/itemiter.hxx>
+#include <sfx2/objsh.hxx>
+#include <svx/svxids.hrc>
+
+#include <svl/intitem.hxx>
+#include <svtools/unitconv.hxx>
+
+#include <svx/hdft.hxx>
+#include <svx/pageitem.hxx>
+
+#include <svx/dlgutil.hxx>
+#include <sfx2/htmlmode.hxx>
+#include <osl/diagnose.h>
+
+#include <editeng/brushitem.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/ulspitem.hxx>
+#include <editeng/sizeitem.hxx>
+#include <editeng/boxitem.hxx>
+
+#include <svx/svxdlg.hxx>
+#include <memory>
+
+#include <svx/xdef.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/unobrushitemhelper.hxx>
+
+using namespace com::sun::star;
+
+// Word 97 incompatibility (#i19922#)
+// #i19922# - tdf#126051 see cui/source/tabpages/page.cxx and sw/source/uibase/sidebar/PageMarginControl.hxx
+constexpr tools::Long MINBODY = o3tl::toTwips(1, o3tl::Length::mm); // 1mm in twips rounded
+
+// default distance to Header or footer
+const tools::Long DEF_DIST_WRITER = 500; // 5mm (Writer)
+const tools::Long DEF_DIST_CALC = 250; // 2.5mm (Calc)
+
+const WhichRangesContainer SvxHFPage::pRanges(svl::Items<
+ // Support DrawingLayer FillStyles (no real call to below GetRanges()
+ // detected, still do the complete transition)
+ XATTR_FILL_FIRST, XATTR_FILL_LAST,
+
+ SID_ATTR_BRUSH, SID_ATTR_BRUSH,
+ SID_ATTR_BORDER_INNER, SID_ATTR_BORDER_INNER,
+ SID_ATTR_BORDER_OUTER, SID_ATTR_BORDER_OUTER,
+ SID_ATTR_BORDER_SHADOW, SID_ATTR_BORDER_SHADOW,
+ SID_ATTR_LRSPACE, SID_ATTR_LRSPACE,
+ SID_ATTR_ULSPACE, SID_ATTR_ULSPACE,
+ SID_ATTR_PAGE_SIZE, SID_ATTR_PAGE_SIZE,
+ SID_ATTR_PAGE_HEADERSET, SID_ATTR_PAGE_HEADERSET,
+ SID_ATTR_PAGE_FOOTERSET, SID_ATTR_PAGE_FOOTERSET,
+ SID_ATTR_PAGE_ON, SID_ATTR_PAGE_ON,
+ SID_ATTR_PAGE_DYNAMIC, SID_ATTR_PAGE_DYNAMIC,
+ SID_ATTR_PAGE_SHARED, SID_ATTR_PAGE_SHARED,
+ SID_ATTR_HDFT_DYNAMIC_SPACING, SID_ATTR_HDFT_DYNAMIC_SPACING,
+ SID_ATTR_PAGE_SHARED_FIRST, SID_ATTR_PAGE_SHARED_FIRST
+>);
+
+namespace svx {
+
+ bool ShowBorderBackgroundDlg(weld::Window* pParent, SfxItemSet* pBBSet)
+ {
+ bool bRes = false;
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<SfxAbstractTabDialog> pDlg(pFact->CreateSvxBorderBackgroundDlg(pParent, *pBBSet, true /*bEnableDrawingLayerFillStyles*/));
+ if ( pDlg->Execute() == RET_OK && pDlg->GetOutputItemSet() )
+ {
+ SfxItemIter aIter( *pDlg->GetOutputItemSet() );
+
+ for (const SfxPoolItem* pItem = aIter.GetCurItem(); pItem; pItem = aIter.NextItem())
+ {
+ if ( !IsInvalidItem( pItem ) )
+ pBBSet->Put( *pItem );
+ }
+ bRes = true;
+ }
+ return bRes;
+ }
+}
+
+std::unique_ptr<SfxTabPage> SvxHeaderPage::Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet )
+{
+ return std::make_unique<SvxHeaderPage>( pPage, pController, *rSet );
+}
+
+std::unique_ptr<SfxTabPage> SvxFooterPage::Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet )
+{
+ return std::make_unique<SvxFooterPage>( pPage, pController, *rSet );
+}
+
+SvxHeaderPage::SvxHeaderPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rAttr)
+ : SvxHFPage( pPage, pController, rAttr, SID_ATTR_PAGE_HEADERSET )
+{
+}
+
+SvxFooterPage::SvxFooterPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rAttr)
+ : SvxHFPage( pPage, pController, rAttr, SID_ATTR_PAGE_FOOTERSET )
+{
+}
+
+SvxHFPage::SvxHFPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet, sal_uInt16 nSetId)
+ : SfxTabPage(pPage, pController, "svx/ui/headfootformatpage.ui", "HFFormatPage", &rSet)
+ , nId(nSetId)
+ , mbDisableQueryBox(false)
+ , mbEnableDrawingLayerFillStyles(false)
+ , m_xCntSharedBox(m_xBuilder->weld_check_button("checkSameLR"))
+ , m_xCntSharedFirstBox(m_xBuilder->weld_check_button("checkSameFP"))
+ , m_xLMLbl(m_xBuilder->weld_label("labelLeftMarg"))
+ , m_xLMEdit(m_xBuilder->weld_metric_spin_button("spinMargLeft", FieldUnit::CM))
+ , m_xRMLbl(m_xBuilder->weld_label("labelRightMarg"))
+ , m_xRMEdit(m_xBuilder->weld_metric_spin_button("spinMargRight", FieldUnit::CM))
+ , m_xDistFT(m_xBuilder->weld_label("labelSpacing"))
+ , m_xDistEdit(m_xBuilder->weld_metric_spin_button("spinSpacing", FieldUnit::CM))
+ , m_xDynSpacingCB(m_xBuilder->weld_check_button("checkDynSpacing"))
+ , m_xHeightFT(m_xBuilder->weld_label("labelHeight"))
+ , m_xHeightEdit(m_xBuilder->weld_metric_spin_button("spinHeight", FieldUnit::CM))
+ , m_xHeightDynBtn(m_xBuilder->weld_check_button("checkAutofit"))
+ , m_xBackgroundBtn(m_xBuilder->weld_button("buttonMore"))
+ , m_xBspWin(new weld::CustomWeld(*m_xBuilder, "drawingareaPageHF", m_aBspWin))
+{
+ //swap header <-> footer in UI
+ if (nId == SID_ATTR_PAGE_FOOTERSET)
+ {
+ m_xContainer->set_help_id("svx/ui/headfootformatpage/FFormatPage");
+ m_xPageLbl = m_xBuilder->weld_label("labelFooterFormat");
+ m_xTurnOnBox = m_xBuilder->weld_check_button("checkFooterOn");
+
+ /* Set custom HIDs for the Footer help page (shared/01/05040400.xhp)
+ otherwise it would display the same extended help
+ on both the Header and Footer tabs */
+ m_xCntSharedBox->set_help_id( "SVX_HID_FOOTER_CHECKSAMELR" );
+ m_xCntSharedFirstBox->set_help_id( "SVX_HID_FOOTER_CHECKSAMEFP" );
+ m_xLMEdit->set_help_id( "SVX_HID_FOOTER_SPINMARGLEFT" );
+ m_xRMEdit->set_help_id( "SVX_HID_FOOTER_SPINMARGRIGHT" );
+ m_xDistEdit->set_help_id( "SVX_HID_FOOTER_SPINSPACING" );
+ m_xDynSpacingCB->set_help_id( "SVX_HID_FOOTER_CHECKDYNSPACING" );
+ m_xHeightEdit->set_help_id( "SVX_HID_FOOTER_SPINHEIGHT" );
+ m_xHeightDynBtn->set_help_id( "SVX_HID_FOOTER_CHECKAUTOFIT" );
+ m_xBackgroundBtn->set_help_id( "SVX_HID_FOOTER_BUTTONMORE" );
+ }
+ else //Header
+ {
+ m_xContainer->set_help_id("svx/ui/headfootformatpage/HFormatPage");
+ m_xPageLbl = m_xBuilder->weld_label("labelHeaderFormat");
+ m_xTurnOnBox = m_xBuilder->weld_check_button("checkHeaderOn");
+ }
+ m_xTurnOnBox->show();
+ m_xPageLbl->show();
+
+ InitHandler();
+ m_aBspWin.EnableRTL(false);
+
+ // This Page needs ExchangeSupport
+ SetExchangeSupport();
+
+ // Set metrics
+ FieldUnit eFUnit = GetModuleFieldUnit( rSet );
+ SetFieldUnit( *m_xDistEdit, eFUnit );
+ SetFieldUnit( *m_xHeightEdit, eFUnit );
+ SetFieldUnit( *m_xLMEdit, eFUnit );
+ SetFieldUnit( *m_xRMEdit, eFUnit );
+}
+
+SvxHFPage::~SvxHFPage()
+{
+}
+
+bool SvxHFPage::FillItemSet( SfxItemSet* rSet )
+{
+ const sal_uInt16 nWSize = GetWhich(SID_ATTR_PAGE_SIZE);
+ const sal_uInt16 nWLRSpace = GetWhich(SID_ATTR_LRSPACE);
+ const sal_uInt16 nWULSpace = GetWhich(SID_ATTR_ULSPACE);
+ const sal_uInt16 nWOn = GetWhich(SID_ATTR_PAGE_ON);
+ const sal_uInt16 nWDynamic = GetWhich(SID_ATTR_PAGE_DYNAMIC);
+ const sal_uInt16 nWDynSpacing = GetWhich(SID_ATTR_HDFT_DYNAMIC_SPACING);
+ const sal_uInt16 nWShared = GetWhich(SID_ATTR_PAGE_SHARED);
+ const sal_uInt16 nWSharedFirst = GetWhich( SID_ATTR_PAGE_SHARED_FIRST );
+ const sal_uInt16 nWBrush = GetWhich(SID_ATTR_BRUSH);
+ const sal_uInt16 nWBox = GetWhich(SID_ATTR_BORDER_OUTER);
+ const sal_uInt16 nWBoxInfo = GetWhich(SID_ATTR_BORDER_INNER);
+ const sal_uInt16 nWShadow = GetWhich(SID_ATTR_BORDER_SHADOW);
+
+ const SfxItemSet& rOldSet = GetItemSet();
+ SfxItemPool* pPool = rOldSet.GetPool();
+ DBG_ASSERT(pPool,"no pool :-(");
+ MapUnit eUnit = pPool->GetMetric(nWSize);
+ // take over DrawingLayer FillStyles
+ SfxItemSetFixed<XATTR_FILL_FIRST, XATTR_FILL_LAST> aSet(*pPool);
+ // Keep it valid
+ aSet.MergeRange(nWSize, nWSize);
+ aSet.MergeRange(nWLRSpace, nWLRSpace);
+ aSet.MergeRange(nWULSpace, nWULSpace);
+ aSet.MergeRange(nWOn, nWOn);
+ aSet.MergeRange(nWDynamic, nWDynamic);
+ aSet.MergeRange(nWShared, nWShared);
+ aSet.MergeRange(nWSharedFirst, nWSharedFirst);
+ aSet.MergeRange(nWBrush, nWBrush);
+ aSet.MergeRange(nWBoxInfo, nWBoxInfo);
+ aSet.MergeRange(nWBox, nWBox);
+ aSet.MergeRange(nWShadow, nWShadow);
+ aSet.MergeRange(nWDynSpacing, nWDynSpacing);
+
+ if(mbEnableDrawingLayerFillStyles)
+ {
+ // When using the XATTR_FILLSTYLE DrawingLayer FillStyle definition
+ // extra action has to be done here since the pool default is drawing::FillStyle_SOLID
+ // instead of drawing::FillStyle_NONE (to have the default blue fill color at start).
+ aSet.Put(XFillStyleItem(drawing::FillStyle_NONE));
+ }
+
+ aSet.Put( SfxBoolItem( nWOn, m_xTurnOnBox->get_active() ) );
+ aSet.Put( SfxBoolItem( nWDynamic, m_xHeightDynBtn->get_active() ) );
+ aSet.Put( SfxBoolItem( nWShared, m_xCntSharedBox->get_active() ) );
+ if(m_xCntSharedFirstBox->get_visible())
+ aSet.Put(SfxBoolItem(nWSharedFirst, m_xCntSharedFirstBox->get_active()));
+ if (m_xDynSpacingCB->get_visible() && SfxItemPool::IsWhich(nWDynSpacing))
+ {
+ std::unique_ptr<SfxBoolItem> pBoolItem(static_cast<SfxBoolItem*>(pPool->GetDefaultItem(nWDynSpacing).Clone()));
+ pBoolItem->SetValue(m_xDynSpacingCB->get_active());
+ aSet.Put(std::move(pBoolItem));
+ }
+
+ // Size
+ SvxSizeItem aSizeItem( static_cast<const SvxSizeItem&>(rOldSet.Get( nWSize )) );
+ Size aSize( aSizeItem.GetSize() );
+ tools::Long nDist = GetCoreValue( *m_xDistEdit, eUnit );
+ tools::Long nH = GetCoreValue( *m_xHeightEdit, eUnit );
+
+ nH += nDist; // add distance
+ aSize.setHeight( nH );
+ aSizeItem.SetSize( aSize );
+ aSet.Put( aSizeItem );
+
+ // Margins
+ SvxLRSpaceItem aLR( nWLRSpace );
+ aLR.SetLeft( static_cast<sal_uInt16>(GetCoreValue( *m_xLMEdit, eUnit )) );
+ aLR.SetRight( static_cast<sal_uInt16>(GetCoreValue( *m_xRMEdit, eUnit )) );
+ aSet.Put( aLR );
+
+ SvxULSpaceItem aUL( nWULSpace );
+ if ( nId == SID_ATTR_PAGE_HEADERSET )
+ aUL.SetLower( static_cast<sal_uInt16>(nDist) );
+ else
+ aUL.SetUpper( static_cast<sal_uInt16>(nDist) );
+ aSet.Put( aUL );
+
+ // Background and border?
+ if (pBBSet)
+ {
+ aSet.Put(*pBBSet);
+ }
+ else
+ {
+ const SfxPoolItem* pItem;
+
+ if(SfxItemState::SET == GetItemSet().GetItemState(GetWhich(nId), false, &pItem))
+ {
+ const SfxItemSet* _pSet = &(static_cast< const SvxSetItem* >(pItem)->GetItemSet());
+
+ if(_pSet->GetItemState(nWBrush) == SfxItemState::SET)
+ {
+ aSet.Put(_pSet->Get(nWBrush));
+ }
+
+ if(_pSet->GetItemState(nWBoxInfo) == SfxItemState::SET)
+ {
+ aSet.Put(_pSet->Get(nWBoxInfo));
+ }
+
+ if(_pSet->GetItemState(nWBox) == SfxItemState::SET)
+ {
+ aSet.Put(_pSet->Get(nWBox));
+ }
+
+ if(_pSet->GetItemState(nWShadow) == SfxItemState::SET)
+ {
+ aSet.Put(_pSet->Get(nWShadow));
+ }
+
+ // take care of [XATTR_XATTR_FILL_FIRST .. XATTR_FILL_LAST]
+ for(sal_uInt16 nFillStyleId(XATTR_FILL_FIRST); nFillStyleId <= XATTR_FILL_LAST; nFillStyleId++)
+ {
+ if(_pSet->GetItemState(nFillStyleId) == SfxItemState::SET)
+ {
+ aSet.Put(_pSet->Get(nFillStyleId));
+ }
+ }
+ }
+ }
+
+ // Flush the SetItem
+ SvxSetItem aSetItem( TypedWhichId<SvxSetItem>(GetWhich( nId )), aSet );
+ rSet->Put( aSetItem );
+
+ return true;
+}
+
+
+void SvxHFPage::Reset( const SfxItemSet* rSet )
+{
+ ActivatePage( *rSet );
+ ResetBackground_Impl( *rSet );
+
+ SfxItemPool* pPool = GetItemSet().GetPool();
+ DBG_ASSERT( pPool, "Where is the pool" );
+ MapUnit eUnit = pPool->GetMetric( GetWhich( SID_ATTR_PAGE_SIZE ) );
+
+ // Evaluate header-/footer- attributes
+ const SvxSetItem* pSetItem = nullptr;
+
+ if ( SfxItemState::SET == rSet->GetItemState( GetWhich(nId), false,
+ reinterpret_cast<const SfxPoolItem**>(&pSetItem) ) )
+ {
+ const SfxItemSet& rHeaderSet = pSetItem->GetItemSet();
+ const SfxBoolItem& rHeaderOn =
+ rHeaderSet.Get(GetWhich(SID_ATTR_PAGE_ON));
+
+ m_xTurnOnBox->set_active(rHeaderOn.GetValue());
+
+ if ( rHeaderOn.GetValue() )
+ {
+ const SfxBoolItem& rDynamic =
+ rHeaderSet.Get( GetWhich( SID_ATTR_PAGE_DYNAMIC ) );
+ const SfxBoolItem& rShared =
+ rHeaderSet.Get( GetWhich( SID_ATTR_PAGE_SHARED ) );
+ const SfxBoolItem* pSharedFirst = nullptr;
+ if (rHeaderSet.HasItem(GetWhich(SID_ATTR_PAGE_SHARED_FIRST)))
+ pSharedFirst = static_cast<const SfxBoolItem*>(&rHeaderSet.Get( GetWhich( SID_ATTR_PAGE_SHARED_FIRST ) ));
+ const SvxSizeItem& rSize =
+ rHeaderSet.Get( GetWhich( SID_ATTR_PAGE_SIZE ) );
+ const SvxULSpaceItem& rUL = rHeaderSet.Get( GetWhich( SID_ATTR_ULSPACE ) );
+ const SvxLRSpaceItem& rLR = rHeaderSet.Get( GetWhich( SID_ATTR_LRSPACE ) );
+ if (m_xDynSpacingCB->get_visible())
+ {
+ const SfxBoolItem& rDynSpacing =
+ static_cast<const SfxBoolItem&>(rHeaderSet.Get(GetWhich(SID_ATTR_HDFT_DYNAMIC_SPACING)));
+ m_xDynSpacingCB->set_active(rDynSpacing.GetValue());
+ }
+
+
+ if ( nId == SID_ATTR_PAGE_HEADERSET )
+ { // Header
+ SetMetricValue( *m_xDistEdit, rUL.GetLower(), eUnit );
+ SetMetricValue( *m_xHeightEdit, rSize.GetSize().Height() - rUL.GetLower(), eUnit );
+ }
+ else
+ { // Footer
+ SetMetricValue( *m_xDistEdit, rUL.GetUpper(), eUnit );
+ SetMetricValue( *m_xHeightEdit, rSize.GetSize().Height() - rUL.GetUpper(), eUnit );
+ }
+
+ m_xHeightDynBtn->set_active(rDynamic.GetValue());
+ SetMetricValue( *m_xLMEdit, rLR.GetLeft(), eUnit );
+ SetMetricValue( *m_xRMEdit, rLR.GetRight(), eUnit );
+ m_xCntSharedBox->set_active(rShared.GetValue());
+ if (pSharedFirst)
+ m_xCntSharedFirstBox->set_active(pSharedFirst->GetValue());
+ }
+ else
+ pSetItem = nullptr;
+ }
+ else
+ {
+ bool bIsCalc = false;
+ const SfxPoolItem* pExt1 = GetItem(*rSet, SID_ATTR_PAGE_EXT1);
+ const SfxPoolItem* pExt2 = GetItem(*rSet, SID_ATTR_PAGE_EXT2);
+ if (dynamic_cast<const SfxBoolItem*>(pExt1) && dynamic_cast<const SfxBoolItem*>(pExt2) )
+ bIsCalc = true;
+
+ // defaults for distance and height
+ tools::Long nDefaultDist = bIsCalc ? DEF_DIST_CALC : DEF_DIST_WRITER;
+ SetMetricValue( *m_xDistEdit, nDefaultDist, MapUnit::Map100thMM );
+ SetMetricValue( *m_xHeightEdit, 500, MapUnit::Map100thMM );
+ }
+
+ if ( !pSetItem )
+ {
+ m_xTurnOnBox->set_active(false);
+ m_xHeightDynBtn->set_active(true);
+ m_xCntSharedBox->set_active(true);
+ m_xCntSharedFirstBox->set_active(true);
+ }
+
+ TurnOn(nullptr);
+
+ m_xTurnOnBox->save_state();
+ m_xDistEdit->save_value();
+ m_xHeightEdit->save_value();
+ m_xHeightDynBtn->save_state();
+ m_xLMEdit->save_value();
+ m_xRMEdit->save_value();
+ m_xCntSharedBox->save_state();
+ RangeHdl();
+
+ SfxObjectShell* pShell;
+ const SfxUInt16Item* pItem = rSet->GetItemIfSet(SID_HTML_MODE, false);
+ if(pItem ||
+ ( nullptr != (pShell = SfxObjectShell::Current()) &&
+ nullptr != (pItem = pShell->GetItem(SID_HTML_MODE))))
+ {
+ sal_uInt16 nHtmlMode = pItem->GetValue();
+ if (nHtmlMode & HTMLMODE_ON)
+ {
+ m_xCntSharedBox->hide();
+ m_xBackgroundBtn->hide();
+ }
+ }
+
+}
+
+void SvxHFPage::InitHandler()
+{
+ m_xTurnOnBox->connect_toggled(LINK(this, SvxHFPage, TurnOnHdl));
+ m_xDistEdit->connect_value_changed(LINK(this, SvxHFPage, ValueChangeHdl));
+ m_xHeightEdit->connect_value_changed(LINK(this,SvxHFPage,ValueChangeHdl));
+
+ m_xLMEdit->connect_value_changed(LINK(this, SvxHFPage, ValueChangeHdl));
+ m_xRMEdit->connect_value_changed(LINK(this, SvxHFPage, ValueChangeHdl));
+ m_xBackgroundBtn->connect_clicked(LINK(this,SvxHFPage, BackgroundHdl));
+}
+
+void SvxHFPage::TurnOn(const weld::Toggleable* pBox)
+{
+ if (m_xTurnOnBox->get_active())
+ {
+ m_xDistFT->set_sensitive(true);
+ m_xDistEdit->set_sensitive(true);
+ m_xDynSpacingCB->set_sensitive(true);
+ m_xHeightFT->set_sensitive(true);
+ m_xHeightEdit->set_sensitive(true);
+ m_xHeightDynBtn->set_sensitive(true);
+ m_xLMLbl->set_sensitive(true);
+ m_xLMEdit->set_sensitive(true);
+ m_xRMLbl->set_sensitive(true);
+ m_xRMEdit->set_sensitive(true);
+
+ SvxPageUsage nUsage = m_aBspWin.GetUsage();
+
+ if( nUsage == SvxPageUsage::Right || nUsage == SvxPageUsage::Left )
+ m_xCntSharedBox->set_sensitive(false);
+ else
+ {
+ m_xCntSharedBox->set_sensitive(true);
+ m_xCntSharedFirstBox->set_sensitive(true);
+ }
+ m_xBackgroundBtn->set_sensitive(true);
+ }
+ else
+ {
+ bool bDelete = true;
+
+ if (!mbDisableQueryBox && pBox && m_xTurnOnBox->get_saved_state() == TRISTATE_TRUE)
+ {
+ short nResult;
+ if (nId == SID_ATTR_PAGE_HEADERSET)
+ {
+ DeleteHeaderDialog aDlg(GetFrameWeld());
+ nResult = aDlg.run();
+ }
+ else
+ {
+ DeleteFooterDialog aDlg(GetFrameWeld());
+ nResult = aDlg.run();
+ }
+ bDelete = nResult == RET_YES;
+ }
+
+ if ( bDelete )
+ {
+ m_xDistFT->set_sensitive(false);
+ m_xDistEdit->set_sensitive(false);
+ m_xDynSpacingCB->set_sensitive(false);
+ m_xHeightFT->set_sensitive(false);
+ m_xHeightEdit->set_sensitive(false);
+ m_xHeightDynBtn->set_sensitive(false);
+
+ m_xLMLbl->set_sensitive(false);
+ m_xLMEdit->set_sensitive(false);
+ m_xRMLbl->set_sensitive(false);
+ m_xRMEdit->set_sensitive(false);
+
+ m_xCntSharedBox->set_sensitive(false);
+ m_xBackgroundBtn->set_sensitive(false);
+ m_xCntSharedFirstBox->set_sensitive(false);
+ }
+ else
+ m_xTurnOnBox->set_active(true);
+ }
+ UpdateExample();
+}
+
+IMPL_LINK(SvxHFPage, TurnOnHdl, weld::Toggleable&, rBox, void)
+{
+ TurnOn(&rBox);
+}
+
+IMPL_LINK_NOARG(SvxHFPage, BackgroundHdl, weld::Button&, void)
+{
+ if(!pBBSet)
+ {
+ // Use only the necessary items for border and background
+ const sal_uInt16 nOuter(GetWhich(SID_ATTR_BORDER_OUTER));
+ const sal_uInt16 nInner(GetWhich(SID_ATTR_BORDER_INNER, false));
+ const sal_uInt16 nShadow(GetWhich(SID_ATTR_BORDER_SHADOW));
+
+ if(mbEnableDrawingLayerFillStyles)
+ {
+ pBBSet.reset(new SfxItemSetFixed
+ <XATTR_FILL_FIRST, XATTR_FILL_LAST, // DrawingLayer FillStyle definitions
+ SID_COLOR_TABLE, SID_PATTERN_LIST> // XPropertyLists for Color, Gradient, Hatch and Graphic fills
+ (*GetItemSet().GetPool()));
+ // Keep it valid
+ pBBSet->MergeRange(nOuter, nOuter);
+ pBBSet->MergeRange(nInner, nInner);
+ pBBSet->MergeRange(nShadow, nShadow);
+
+ // copy items for XPropertyList entries from the DrawModel so that
+ // the Area TabPage can access them
+ static const sal_uInt16 nCopyFlags[] = {
+ SID_COLOR_TABLE,
+ SID_GRADIENT_LIST,
+ SID_HATCH_LIST,
+ SID_BITMAP_LIST,
+ SID_PATTERN_LIST,
+ 0
+ };
+
+ for(sal_uInt16 a(0); nCopyFlags[a]; a++)
+ {
+ const SfxPoolItem* pItem = GetItemSet().GetItem(nCopyFlags[a]);
+
+ if(pItem)
+ {
+ pBBSet->Put(*pItem);
+ }
+ else
+ {
+ OSL_ENSURE(false, "XPropertyList missing (!)");
+ }
+ }
+ }
+ else
+ {
+ const sal_uInt16 nBrush(GetWhich(SID_ATTR_BRUSH));
+
+ pBBSet.reset( new SfxItemSetFixed<XATTR_FILL_FIRST, XATTR_FILL_LAST>
+ (*GetItemSet().GetPool()) );
+ // Keep it valid
+ pBBSet->MergeRange(nBrush, nBrush);
+ pBBSet->MergeRange(nOuter, nOuter);
+ pBBSet->MergeRange(nInner, nInner);
+ pBBSet->MergeRange(nShadow, nShadow);
+ }
+
+ const SfxPoolItem* pItem;
+
+ if(SfxItemState::SET == GetItemSet().GetItemState(GetWhich(nId), false, &pItem))
+ {
+ // If a SfxItemSet from the SetItem for SID_ATTR_PAGE_HEADERSET or
+ // SID_ATTR_PAGE_FOOTERSET exists, use its content
+ pBBSet->Put(static_cast<const SvxSetItem*>(pItem)->GetItemSet());
+ }
+ else
+ {
+ if(mbEnableDrawingLayerFillStyles)
+ {
+ // The style for header/footer is not yet created, need to reset
+ // XFillStyleItem to drawing::FillStyle_NONE which is the same as in the style
+ // initialization. This needs to be done since the pool default for
+ // XFillStyleItem is drawing::FillStyle_SOLID
+ pBBSet->Put(XFillStyleItem(drawing::FillStyle_NONE));
+ }
+ }
+
+ if(SfxItemState::SET == GetItemSet().GetItemState(nInner, false, &pItem))
+ {
+ // The set InfoItem is always required
+ pBBSet->Put(*pItem);
+ }
+ }
+
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+
+ VclPtr<SfxAbstractTabDialog> pDlg(pFact->CreateSvxBorderBackgroundDlg(
+ GetFrameWeld(),
+ *pBBSet,
+ mbEnableDrawingLayerFillStyles));
+
+ pDlg->StartExecuteAsync([pDlg, this](sal_Int32 nResult) {
+ if (nResult == RET_OK && pDlg->GetOutputItemSet())
+ {
+ SfxItemIter aIter(*pDlg->GetOutputItemSet());
+
+ for (const SfxPoolItem* pItem = aIter.GetCurItem(); pItem; pItem = aIter.NextItem())
+ {
+ if(!IsInvalidItem(pItem))
+ {
+ pBBSet->Put(*pItem);
+ }
+ }
+
+ {
+ drawinglayer::attribute::SdrAllFillAttributesHelperPtr aFillAttributes;
+
+ if (mbEnableDrawingLayerFillStyles)
+ {
+ // create FillAttributes directly from DrawingLayer FillStyle entries
+ aFillAttributes =
+ std::make_shared<drawinglayer::attribute::SdrAllFillAttributesHelper>(*pBBSet);
+ }
+ else
+ {
+ const sal_uInt16 nWhich = GetWhich(SID_ATTR_BRUSH);
+
+ if (pBBSet->GetItemState(nWhich) == SfxItemState::SET)
+ {
+ // create FillAttributes from SvxBrushItem
+ const SvxBrushItem& rItem
+ = static_cast<const SvxBrushItem&>(pBBSet->Get(nWhich));
+ SfxItemSetFixed<XATTR_FILL_FIRST, XATTR_FILL_LAST> aTempSet(*pBBSet->GetPool());
+
+ setSvxBrushItemAsFillAttributesToTargetSet(rItem, aTempSet);
+ aFillAttributes =
+ std::make_shared<drawinglayer::attribute::SdrAllFillAttributesHelper>(aTempSet);
+ }
+ }
+
+ if (SID_ATTR_PAGE_HEADERSET == nId)
+ {
+ //m_aBspWin.SetHdColor(rItem.GetColor());
+ m_aBspWin.setHeaderFillAttributes(aFillAttributes);
+ }
+ else
+ {
+ //m_aBspWin.SetFtColor(rItem.GetColor());
+ m_aBspWin.setFooterFillAttributes(aFillAttributes);
+ }
+ }
+ }
+ pDlg->disposeOnce();
+ });
+
+ UpdateExample();
+}
+
+void SvxHFPage::UpdateExample()
+{
+ if ( nId == SID_ATTR_PAGE_HEADERSET )
+ {
+ m_aBspWin.SetHeader( m_xTurnOnBox->get_active() );
+ m_aBspWin.SetHdHeight( GetCoreValue( *m_xHeightEdit, MapUnit::MapTwip ) );
+ m_aBspWin.SetHdDist( GetCoreValue( *m_xDistEdit, MapUnit::MapTwip ) );
+ m_aBspWin.SetHdLeft( GetCoreValue( *m_xLMEdit, MapUnit::MapTwip ) );
+ m_aBspWin.SetHdRight( GetCoreValue( *m_xRMEdit, MapUnit::MapTwip ) );
+ }
+ else
+ {
+ m_aBspWin.SetFooter( m_xTurnOnBox->get_active() );
+ m_aBspWin.SetFtHeight( GetCoreValue( *m_xHeightEdit, MapUnit::MapTwip ) );
+ m_aBspWin.SetFtDist( GetCoreValue( *m_xDistEdit, MapUnit::MapTwip ) );
+ m_aBspWin.SetFtLeft( GetCoreValue( *m_xLMEdit, MapUnit::MapTwip ) );
+ m_aBspWin.SetFtRight( GetCoreValue( *m_xRMEdit, MapUnit::MapTwip ) );
+ }
+ m_aBspWin.Invalidate();
+}
+
+void SvxHFPage::ResetBackground_Impl( const SfxItemSet& rSet )
+{
+ sal_uInt16 nWhich(GetWhich(SID_ATTR_PAGE_HEADERSET));
+
+ if (SfxItemState::SET == rSet.GetItemState(nWhich, false))
+ {
+ const SvxSetItem& rSetItem = static_cast< const SvxSetItem& >(rSet.Get(nWhich, false));
+ const SfxItemSet& rTmpSet = rSetItem.GetItemSet();
+ const SfxBoolItem& rOn = rTmpSet.Get(GetWhich(SID_ATTR_PAGE_ON));
+
+ if(rOn.GetValue())
+ {
+ drawinglayer::attribute::SdrAllFillAttributesHelperPtr aHeaderFillAttributes;
+
+ if(mbEnableDrawingLayerFillStyles)
+ {
+ // create FillAttributes directly from DrawingLayer FillStyle entries
+ aHeaderFillAttributes = std::make_shared<drawinglayer::attribute::SdrAllFillAttributesHelper>(rTmpSet);
+ }
+ else
+ {
+ nWhich = GetWhich(SID_ATTR_BRUSH);
+
+ if(SfxItemState::SET == rTmpSet.GetItemState(nWhich))
+ {
+ // create FillAttributes from SvxBrushItem
+ const SvxBrushItem& rItem = static_cast< const SvxBrushItem& >(rTmpSet.Get(nWhich));
+ SfxItemSetFixed<XATTR_FILL_FIRST, XATTR_FILL_LAST> aTempSet(*rTmpSet.GetPool());
+
+ setSvxBrushItemAsFillAttributesToTargetSet(rItem, aTempSet);
+ aHeaderFillAttributes = std::make_shared<drawinglayer::attribute::SdrAllFillAttributesHelper>(aTempSet);
+ }
+ }
+
+ m_aBspWin.setHeaderFillAttributes(aHeaderFillAttributes);
+ }
+ }
+
+ nWhich = GetWhich(SID_ATTR_PAGE_FOOTERSET);
+
+ if (SfxItemState::SET == rSet.GetItemState(nWhich, false))
+ {
+ const SvxSetItem& rSetItem = static_cast< const SvxSetItem& >(rSet.Get(nWhich, false));
+ const SfxItemSet& rTmpSet = rSetItem.GetItemSet();
+ const SfxBoolItem& rOn = rTmpSet.Get(GetWhich(SID_ATTR_PAGE_ON));
+
+ if(rOn.GetValue())
+ {
+ drawinglayer::attribute::SdrAllFillAttributesHelperPtr aFooterFillAttributes;
+
+ if(mbEnableDrawingLayerFillStyles)
+ {
+ // create FillAttributes directly from DrawingLayer FillStyle entries
+ aFooterFillAttributes = std::make_shared<drawinglayer::attribute::SdrAllFillAttributesHelper>(rTmpSet);
+ }
+ else
+ {
+ nWhich = GetWhich(SID_ATTR_BRUSH);
+
+ if(SfxItemState::SET == rTmpSet.GetItemState(nWhich))
+ {
+ // create FillAttributes from SvxBrushItem
+ const SvxBrushItem& rItem = static_cast< const SvxBrushItem& >(rTmpSet.Get(nWhich));
+ SfxItemSetFixed<XATTR_FILL_FIRST, XATTR_FILL_LAST> aTempSet(*rTmpSet.GetPool());
+
+ setSvxBrushItemAsFillAttributesToTargetSet(rItem, aTempSet);
+ aFooterFillAttributes = std::make_shared<drawinglayer::attribute::SdrAllFillAttributesHelper>(aTempSet);
+ }
+ }
+
+ m_aBspWin.setFooterFillAttributes(aFooterFillAttributes);
+ }
+ }
+
+ drawinglayer::attribute::SdrAllFillAttributesHelperPtr aPageFillAttributes;
+
+ if(mbEnableDrawingLayerFillStyles)
+ {
+ // create FillAttributes directly from DrawingLayer FillStyle entries
+ aPageFillAttributes = std::make_shared<drawinglayer::attribute::SdrAllFillAttributesHelper>(rSet);
+ }
+ else
+ {
+ nWhich = GetWhich(SID_ATTR_BRUSH);
+
+ if(rSet.GetItemState(nWhich) >= SfxItemState::DEFAULT)
+ {
+ // create FillAttributes from SvxBrushItem
+ const SvxBrushItem& rItem = static_cast< const SvxBrushItem& >(rSet.Get(nWhich));
+ SfxItemSetFixed<XATTR_FILL_FIRST, XATTR_FILL_LAST> aTempSet(*rSet.GetPool());
+
+ setSvxBrushItemAsFillAttributesToTargetSet(rItem, aTempSet);
+ aPageFillAttributes = std::make_shared<drawinglayer::attribute::SdrAllFillAttributesHelper>(aTempSet);
+ }
+ }
+
+ m_aBspWin.setPageFillAttributes(aPageFillAttributes);
+}
+
+void SvxHFPage::ActivatePage( const SfxItemSet& rSet )
+{
+ const SfxPoolItem* pItem = GetItem( rSet, SID_ATTR_LRSPACE );
+
+ if ( pItem )
+ {
+ // Set left and right margins
+ const SvxLRSpaceItem& rLRSpace = static_cast<const SvxLRSpaceItem&>(*pItem);
+
+ m_aBspWin.SetLeft( rLRSpace.GetLeft() );
+ m_aBspWin.SetRight( rLRSpace.GetRight() );
+ }
+ else
+ {
+ m_aBspWin.SetLeft( 0 );
+ m_aBspWin.SetRight( 0 );
+ }
+
+ pItem = GetItem( rSet, SID_ATTR_ULSPACE );
+
+ if ( pItem )
+ {
+ // Set top and bottom margins
+ const SvxULSpaceItem& rULSpace = static_cast<const SvxULSpaceItem&>(*pItem);
+
+ m_aBspWin.SetTop( rULSpace.GetUpper() );
+ m_aBspWin.SetBottom( rULSpace.GetLower() );
+ }
+ else
+ {
+ m_aBspWin.SetTop( 0 );
+ m_aBspWin.SetBottom( 0 );
+ }
+
+ SvxPageUsage nUsage = SvxPageUsage::All;
+ pItem = GetItem( rSet, SID_ATTR_PAGE );
+
+ if ( pItem )
+ nUsage = static_cast<const SvxPageItem*>(pItem)->GetPageUsage();
+
+ m_aBspWin.SetUsage( nUsage );
+
+ if ( SvxPageUsage::Right == nUsage || SvxPageUsage::Left == nUsage )
+ m_xCntSharedBox->set_sensitive(false);
+ else
+ {
+ m_xCntSharedBox->set_sensitive(true);
+ m_xCntSharedFirstBox->set_sensitive(true);
+ }
+ pItem = GetItem( rSet, SID_ATTR_PAGE_SIZE );
+
+ if ( pItem )
+ {
+ // Orientation and Size from the PageItem
+ const SvxSizeItem& rSize = static_cast<const SvxSizeItem&>(*pItem);
+ // if the size is already swapped (Landscape)
+ m_aBspWin.SetSize( rSize.GetSize() );
+ }
+
+ // Evaluate Header attribute
+ const SvxSetItem* pSetItem = nullptr;
+
+ if ( SfxItemState::SET == rSet.GetItemState( GetWhich( SID_ATTR_PAGE_HEADERSET ),
+ false,
+ reinterpret_cast<const SfxPoolItem**>(&pSetItem) ) )
+ {
+ const SfxItemSet& rHeaderSet = pSetItem->GetItemSet();
+ const SfxBoolItem& rHeaderOn =
+ rHeaderSet.Get( GetWhich( SID_ATTR_PAGE_ON ) );
+
+ if ( rHeaderOn.GetValue() )
+ {
+ const SvxSizeItem& rSize =
+ rHeaderSet.Get( GetWhich( SID_ATTR_PAGE_SIZE ) );
+ const SvxULSpaceItem& rUL = rHeaderSet.Get( GetWhich(SID_ATTR_ULSPACE ) );
+ const SvxLRSpaceItem& rLR = rHeaderSet.Get( GetWhich( SID_ATTR_LRSPACE ) );
+ tools::Long nDist = rUL.GetLower();
+
+ m_aBspWin.SetHdHeight( rSize.GetSize().Height() - nDist );
+ m_aBspWin.SetHdDist( nDist );
+ m_aBspWin.SetHdLeft( rLR.GetLeft() );
+ m_aBspWin.SetHdRight( rLR.GetRight() );
+ m_aBspWin.SetHeader( true );
+ }
+ else
+ pSetItem = nullptr;
+ }
+
+ if ( !pSetItem )
+ {
+ m_aBspWin.SetHeader( false );
+
+ if ( SID_ATTR_PAGE_HEADERSET == nId )
+ {
+ m_xCntSharedBox->set_sensitive(false);
+ m_xCntSharedFirstBox->set_sensitive(false);
+ }
+ }
+ pSetItem = nullptr;
+
+ if ( SfxItemState::SET == rSet.GetItemState( GetWhich( SID_ATTR_PAGE_FOOTERSET ),
+ false,
+ reinterpret_cast<const SfxPoolItem**>(&pSetItem) ) )
+ {
+ const SfxItemSet& rFooterSet = pSetItem->GetItemSet();
+ const SfxBoolItem& rFooterOn =
+ rFooterSet.Get( GetWhich( SID_ATTR_PAGE_ON ) );
+
+ if ( rFooterOn.GetValue() )
+ {
+ const SvxSizeItem& rSize =
+ rFooterSet.Get( GetWhich( SID_ATTR_PAGE_SIZE ) );
+ const SvxULSpaceItem& rUL = rFooterSet.Get( GetWhich( SID_ATTR_ULSPACE ) );
+ const SvxLRSpaceItem& rLR = rFooterSet.Get( GetWhich( SID_ATTR_LRSPACE ) );
+ tools::Long nDist = rUL.GetUpper();
+
+ m_aBspWin.SetFtHeight( rSize.GetSize().Height() - nDist );
+ m_aBspWin.SetFtDist( nDist );
+ m_aBspWin.SetFtLeft( rLR.GetLeft() );
+ m_aBspWin.SetFtRight( rLR.GetRight() );
+ m_aBspWin.SetFooter( true );
+ }
+ else
+ pSetItem = nullptr;
+ }
+
+ if ( !pSetItem )
+ {
+ m_aBspWin.SetFooter( false );
+
+ if ( SID_ATTR_PAGE_FOOTERSET == nId )
+ {
+ m_xCntSharedBox->set_sensitive(false);
+ m_xCntSharedFirstBox->set_sensitive(false);
+ }
+ }
+
+ pItem = GetItem( rSet, SID_ATTR_PAGE_EXT1 );
+
+ if ( auto pBoolItem = dynamic_cast<const SfxBoolItem*>( pItem) )
+ {
+ m_aBspWin.SetTable( true );
+ m_aBspWin.SetHorz( pBoolItem->GetValue() );
+ }
+
+ pItem = GetItem( rSet, SID_ATTR_PAGE_EXT2 );
+
+ if ( auto pBoolItem = dynamic_cast<const SfxBoolItem*>( pItem) )
+ {
+ m_aBspWin.SetTable( true );
+ m_aBspWin.SetVert( pBoolItem->GetValue() );
+ }
+ ResetBackground_Impl( rSet );
+ RangeHdl();
+}
+
+DeactivateRC SvxHFPage::DeactivatePage( SfxItemSet* _pSet )
+{
+ if ( _pSet )
+ FillItemSet( _pSet );
+ return DeactivateRC::LeavePage;
+}
+
+IMPL_LINK_NOARG(SvxHFPage, ValueChangeHdl, weld::MetricSpinButton&, void)
+{
+ UpdateExample();
+ RangeHdl();
+}
+
+void SvxHFPage::RangeHdl()
+{
+ tools::Long nHHeight = m_aBspWin.GetHdHeight();
+ tools::Long nHDist = m_aBspWin.GetHdDist();
+
+ tools::Long nFHeight = m_aBspWin.GetFtHeight();
+ tools::Long nFDist = m_aBspWin.GetFtDist();
+
+ tools::Long nHeight = std::max(tools::Long(MINBODY),
+ static_cast<tools::Long>(m_xHeightEdit->denormalize(m_xHeightEdit->get_value(FieldUnit::TWIP))));
+ tools::Long nDist = m_xTurnOnBox->get_active() ?
+ static_cast<tools::Long>(m_xDistEdit->denormalize(m_xDistEdit->get_value(FieldUnit::TWIP))) : 0;
+
+ tools::Long nMin;
+ tools::Long nMax;
+
+ if ( nId == SID_ATTR_PAGE_HEADERSET )
+ {
+ nHHeight = nHeight;
+ nHDist = nDist;
+ }
+ else
+ {
+ nFHeight = nHeight;
+ nFDist = nDist;
+ }
+
+ // Current values of the side edges
+ tools::Long nBT = m_aBspWin.GetTop();
+ tools::Long nBB = m_aBspWin.GetBottom();
+ tools::Long nBL = m_aBspWin.GetLeft();
+ tools::Long nBR = m_aBspWin.GetRight();
+
+ tools::Long nH = m_aBspWin.GetSize().Height();
+ tools::Long nW = m_aBspWin.GetSize().Width();
+
+ // Borders
+ if ( nId == SID_ATTR_PAGE_HEADERSET )
+ {
+ // Header
+ nMin = ( nH - nBB - nBT ) / 5; // 20%
+ nMax = std::max( nH - nMin - nHDist - nFDist - nFHeight - nBB - nBT,
+ nMin );
+ m_xHeightEdit->set_max(m_xHeightEdit->normalize(nMax), FieldUnit::TWIP);
+ nMin = ( nH - nBB - nBT ) / 5; // 20%
+ nDist = std::max( nH - nMin - nHHeight - nFDist - nFHeight - nBB - nBT,
+ tools::Long(0) );
+ m_xDistEdit->set_max(m_xDistEdit->normalize(nDist), FieldUnit::TWIP);
+ }
+ else
+ {
+ // Footer
+ nMin = ( nH - nBT - nBB ) / 5; // 20%
+ nMax = std::max( nH - nMin - nFDist - nHDist - nHHeight - nBT - nBB,
+ nMin );
+ m_xHeightEdit->set_max(m_xHeightEdit->normalize(nMax), FieldUnit::TWIP);
+ nMin = ( nH - nBT - nBB ) / 5; // 20%
+ nDist = std::max( nH - nMin - nFHeight - nHDist - nHHeight - nBT - nBB,
+ tools::Long(0) );
+ m_xDistEdit->set_max(m_xDistEdit->normalize(nDist), FieldUnit::TWIP);
+ }
+
+ // Limit Indentation
+ nMax = nW - nBL - nBR -
+ static_cast<tools::Long>(m_xRMEdit->denormalize(m_xRMEdit->get_value(FieldUnit::TWIP))) - MINBODY;
+ m_xLMEdit->set_max(m_xLMEdit->normalize(nMax), FieldUnit::TWIP);
+
+ nMax = nW - nBL - nBR -
+ static_cast<tools::Long>(m_xLMEdit->denormalize(m_xLMEdit->get_value(FieldUnit::TWIP))) - MINBODY;
+ m_xRMEdit->set_max(m_xLMEdit->normalize(nMax), FieldUnit::TWIP);
+}
+
+void SvxHFPage::EnableDynamicSpacing()
+{
+ m_xDynSpacingCB->show();
+}
+
+void SvxHFPage::PageCreated(const SfxAllItemSet &rSet)
+{
+ const SfxBoolItem* pSupportDrawingLayerFillStyleItem = rSet.GetItem<SfxBoolItem>(SID_DRAWINGLAYER_FILLSTYLES, false);
+
+ if (pSupportDrawingLayerFillStyleItem)
+ {
+ const bool bNew(pSupportDrawingLayerFillStyleItem->GetValue());
+
+ mbEnableDrawingLayerFillStyles = bNew;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/hexcolorcontrol.cxx b/svx/source/dialog/hexcolorcontrol.cxx
new file mode 100644
index 0000000000..fbf6b9ea66
--- /dev/null
+++ b/svx/source/dialog/hexcolorcontrol.cxx
@@ -0,0 +1,111 @@
+/* -*- 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 <sax/tools/converter.hxx>
+#include <svx/hexcolorcontrol.hxx>
+#include <rtl/character.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+
+namespace weld
+{
+HexColorControl::HexColorControl(std::unique_ptr<weld::Entry> pEntry)
+ : m_xEntry(std::move(pEntry))
+ , m_nAsyncModifyEvent(nullptr)
+{
+ m_xEntry->set_max_length(6);
+ m_xEntry->set_width_chars(6);
+ m_xEntry->connect_insert_text(LINK(this, HexColorControl, ImplProcessInputHdl));
+ m_xEntry->connect_changed(LINK(this, HexColorControl, ImplProcessModifyHdl));
+}
+
+HexColorControl::~HexColorControl()
+{
+ if (m_nAsyncModifyEvent)
+ Application::RemoveUserEvent(m_nAsyncModifyEvent);
+}
+
+IMPL_LINK_NOARG(HexColorControl, OnAsyncModifyHdl, void*, void)
+{
+ m_nAsyncModifyEvent = nullptr;
+ m_aModifyHdl.Call(*m_xEntry);
+}
+
+// tdf#123291 resend it async so it arrives after ImplProcessInputHdl has been
+// processed
+IMPL_LINK_NOARG(HexColorControl, ImplProcessModifyHdl, weld::Entry&, void)
+{
+ if (m_nAsyncModifyEvent)
+ Application::RemoveUserEvent(m_nAsyncModifyEvent);
+ m_nAsyncModifyEvent = Application::PostUserEvent(LINK(this, HexColorControl, OnAsyncModifyHdl));
+}
+
+void HexColorControl::SetColor(Color nColor)
+{
+ OUStringBuffer aBuffer;
+ sax::Converter::convertColor(aBuffer, nColor);
+ OUString sColor = aBuffer.makeStringAndClear().copy(1);
+ if (sColor == m_xEntry->get_text())
+ return;
+ int nStartPos, nEndPos;
+ m_xEntry->get_selection_bounds(nStartPos, nEndPos);
+ m_xEntry->set_text(sColor);
+ m_xEntry->select_region(nStartPos, nEndPos);
+}
+
+Color HexColorControl::GetColor() const
+{
+ sal_Int32 nColor = -1;
+
+ OUString aStr = "#" + m_xEntry->get_text();
+ sal_Int32 nLen = aStr.getLength();
+
+ if (nLen < 7)
+ {
+ static const char* const pNullStr = "000000";
+ aStr += OUString::createFromAscii(&pNullStr[nLen - 1]);
+ }
+
+ sax::Converter::convertColor(nColor, aStr);
+
+ m_xEntry->set_message_type(nColor != -1 ? weld::EntryMessageType::Normal
+ : weld::EntryMessageType::Error);
+
+ return Color(ColorTransparency, nColor);
+}
+
+IMPL_STATIC_LINK(HexColorControl, ImplProcessInputHdl, OUString&, rTest, bool)
+{
+ const sal_Unicode* pTest = rTest.getStr();
+ sal_Int32 nLen = rTest.getLength();
+
+ OUStringBuffer aFilter(nLen);
+ for (sal_Int32 i = 0; i < nLen; ++i)
+ {
+ if (rtl::isAsciiHexDigit(*pTest))
+ aFilter.append(*pTest);
+ ++pTest;
+ }
+
+ rTest = aFilter.makeStringAndClear();
+ return true;
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/hyperdlg.cxx b/svx/source/dialog/hyperdlg.cxx
new file mode 100644
index 0000000000..6d94d8add6
--- /dev/null
+++ b/svx/source/dialog/hyperdlg.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/.
+ *
+ * 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 <svx/hyperdlg.hxx>
+#include <svx/svxdlg.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/sfxsids.hrc>
+
+//# #
+//# Childwindow-Wrapper-Class #
+//# #
+SFX_IMPL_CHILDWINDOW_WITHID(SvxHlinkDlgWrapper, SID_HYPERLINK_DIALOG)
+
+SvxHlinkDlgWrapper::SvxHlinkDlgWrapper( vcl::Window* _pParent, sal_uInt16 nId,
+ SfxBindings* pBindings,
+ SfxChildWinInfo* pInfo ) :
+ SfxChildWindow( _pParent, nId ),
+
+ mpDlg( nullptr )
+
+{
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ mpDlg = pFact->CreateSvxHpLinkDlg(this, pBindings, _pParent->GetFrameWeld());
+ SetController( mpDlg->GetController() );
+ SetVisible_Impl(false);
+
+ if ( !pInfo->aSize.IsEmpty() )
+ {
+ weld::Window* pTopWindow = SfxGetpApp()->GetTopWindow();
+ if (pTopWindow)
+ {
+ weld::Dialog* pDialog = GetController()->getDialog();
+
+ Size aParentSize(pTopWindow->get_size());
+ Size aDlgSize(pDialog->get_size());
+
+ if( aParentSize.Width() < pInfo->aPos.X() )
+ pInfo->aPos.setX( aParentSize.Width()-aDlgSize.Width() < tools::Long(0.1*aParentSize.Width()) ?
+ tools::Long(0.1*aParentSize.Width()) : aParentSize.Width()-aDlgSize.Width() );
+ if( aParentSize.Height() < pInfo->aPos. Y() )
+ pInfo->aPos.setY( aParentSize.Height()-aDlgSize.Height() < tools::Long(0.1*aParentSize.Height()) ?
+ tools::Long(0.1*aParentSize.Height()) : aParentSize.Height()-aDlgSize.Height() );
+
+ pDialog->window_move(pInfo->aPos.X(), pInfo->aPos.Y());
+ }
+ }
+ SetHideNotDelete( true );
+}
+
+SfxChildWinInfo SvxHlinkDlgWrapper::GetInfo() const
+{
+ return SfxChildWindow::GetInfo();
+}
+
+bool SvxHlinkDlgWrapper::QueryClose()
+{
+ return !mpDlg || mpDlg->QueryClose();
+}
+
+SvxHlinkDlgWrapper::~SvxHlinkDlgWrapper()
+{
+ mpDlg.disposeAndClear();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/imapdlg.cxx b/svx/source/dialog/imapdlg.cxx
new file mode 100644
index 0000000000..1efe3c8f4f
--- /dev/null
+++ b/svx/source/dialog/imapdlg.cxx
@@ -0,0 +1,728 @@
+/* -*- 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/errinf.hxx>
+#include <tools/urlobj.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <svl/eitem.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/module.hxx>
+#include <sfx2/filedlghelper.hxx>
+#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
+#include <svl/urihelper.hxx>
+#include <svtools/ehdl.hxx>
+#include <svtools/inettbc.hxx>
+#include <svtools/sfxecode.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/docfile.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <vcl/weld.hxx>
+#include <svx/imapdlg.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+#include <svx/svxids.hrc>
+#include "imapwnd.hxx"
+#include "imapimp.hxx"
+#include <svx/svdopath.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <osl/diagnose.h>
+#include "dlgunit.hxx"
+#include <memory>
+
+constexpr OUString SELF_TARGET = u"_self"_ustr;
+constexpr OUString IMAP_CERN_FILTER = u"MAP - CERN"_ustr;
+constexpr OUString IMAP_NCSA_FILTER = u"MAP - NCSA"_ustr;
+constexpr OUString IMAP_BINARY_FILTER = u"SIP - StarView ImageMap"_ustr;
+constexpr OUStringLiteral IMAP_ALL_TYPE = u"*.*";
+constexpr OUString IMAP_BINARY_TYPE = u"*.sip"_ustr;
+constexpr OUString IMAP_CERN_TYPE = u"*.map"_ustr;
+constexpr OUString IMAP_NCSA_TYPE = u"*.map"_ustr;
+
+SFX_IMPL_MODELESSDIALOGCONTOLLER_WITHID( SvxIMapDlgChildWindow, SID_IMAP );
+
+// ControllerItem
+
+SvxIMapDlgItem::SvxIMapDlgItem( SvxIMapDlg& rIMapDlg, SfxBindings& rBindings ) :
+ SfxControllerItem ( SID_IMAP_EXEC, rBindings ),
+ rIMap ( rIMapDlg )
+{
+}
+
+void SvxIMapDlgItem::StateChangedAtToolBoxControl( sal_uInt16 nSID, SfxItemState /*eState*/,
+ const SfxPoolItem* pItem )
+{
+ if ( ( nSID == SID_IMAP_EXEC ) && pItem )
+ {
+ const SfxBoolItem* pStateItem = dynamic_cast<const SfxBoolItem*>( pItem );
+ assert(pStateItem); //SfxBoolItem expected
+ if (pStateItem)
+ {
+ // Disable Float if possible
+ rIMap.SetExecState( !pStateItem->GetValue() );
+ }
+ }
+}
+
+SvxIMapDlgChildWindow::SvxIMapDlgChildWindow(vcl::Window* _pParent, sal_uInt16 nId,
+ SfxBindings* pBindings,
+ SfxChildWinInfo const * pInfo)
+ : SfxChildWindow( _pParent, nId )
+{
+ SetController(std::make_shared<SvxIMapDlg>(pBindings, this, _pParent->GetFrameWeld()));
+ SvxIMapDlg* pDlg = static_cast<SvxIMapDlg*>(GetController().get());
+ pDlg->Initialize( pInfo );
+}
+
+void SvxIMapDlgChildWindow::UpdateIMapDlg( const Graphic& rGraphic, const ImageMap* pImageMap,
+ const TargetList* pTargetList, void* pEditingObj )
+{
+ SvxIMapDlg* pDlg = GetIMapDlg();
+ if (pDlg)
+ pDlg->UpdateLink(rGraphic, pImageMap, pTargetList, pEditingObj);
+}
+
+SvxIMapDlg::SvxIMapDlg(SfxBindings *_pBindings, SfxChildWindow *pCW, weld::Window* _pParent)
+ : SfxModelessDialogController(_pBindings, pCW, _pParent, "svx/ui/imapdialog.ui", "ImapDialog")
+ , pCheckObj(nullptr)
+ , aIMapItem(*this, *_pBindings)
+ , m_xIMapWnd(new IMapWindow(_pBindings->GetActiveFrame(), m_xDialog.get()))
+ , m_xTbxIMapDlg1(m_xBuilder->weld_toolbar("toolbar"))
+ , m_xFtURL(m_xBuilder->weld_label("urlft"))
+ , m_xURLBox(new SvtURLBox(m_xBuilder->weld_combo_box("url")))
+ , m_xFtText(m_xBuilder->weld_label("textft"))
+ , m_xEdtText(m_xBuilder->weld_entry("text"))
+ , m_xFtTarget(m_xBuilder->weld_label("targetft"))
+ , m_xCbbTarget(m_xBuilder->weld_combo_box("target"))
+ , m_xCancelBtn(m_xBuilder->weld_button("cancel"))
+ , m_xStbStatus1(m_xBuilder->weld_label("statusurl"))
+ , m_xStbStatus2(m_xBuilder->weld_label("statuspos"))
+ , m_xStbStatus3(m_xBuilder->weld_label("statussize"))
+ , m_xIMapWndWeld(new weld::CustomWeld(*m_xBuilder, "container", *m_xIMapWnd))
+
+{
+ m_xTbxIMapDlg1->insert_separator(4, "sep1");
+ m_xTbxIMapDlg1->insert_separator(10, "sep2");
+ m_xTbxIMapDlg1->insert_separator(15, "sep3");
+ m_xTbxIMapDlg1->insert_separator(18, "sel4");
+
+ //lock this down so it doesn't jump around in size
+ //as entries are added later on
+ TargetList aTmpList;
+ SfxFrame::GetDefaultTargetList(aTmpList);
+ for (const OUString & s : aTmpList)
+ m_xCbbTarget->append_text(s);
+ Size aPrefSize(m_xCbbTarget->get_preferred_size());
+ m_xCbbTarget->set_size_request(aPrefSize.Width(), -1);
+ m_xCbbTarget->clear();
+
+ m_xIMapWnd->Show();
+
+ pOwnData.reset(new IMapOwnData);
+
+ m_xIMapWnd->SetInfoLink( LINK( this, SvxIMapDlg, InfoHdl ) );
+ m_xIMapWnd->SetMousePosLink( LINK( this, SvxIMapDlg, MousePosHdl ) );
+ m_xIMapWnd->SetGraphSizeLink( LINK( this, SvxIMapDlg, GraphSizeHdl ) );
+ m_xIMapWnd->SetUpdateLink( LINK( this, SvxIMapDlg, StateHdl ) );
+
+ m_xURLBox->connect_changed( LINK( this, SvxIMapDlg, URLModifyHdl ) );
+ m_xURLBox->connect_focus_out( LINK( this, SvxIMapDlg, URLLoseFocusHdl ) );
+ m_xEdtText->connect_changed( LINK( this, SvxIMapDlg, EntryModifyHdl ) );
+ m_xCbbTarget->connect_focus_out( LINK( this, SvxIMapDlg, URLLoseFocusHdl ) );
+
+ m_xTbxIMapDlg1->connect_clicked( LINK( this, SvxIMapDlg, TbxClickHdl ) );
+ OUString sSelect("TBI_SELECT");
+ m_xTbxIMapDlg1->set_item_active(sSelect, true);
+ TbxClickHdl(sSelect);
+
+ m_xStbStatus1->set_size_request(120, -1);
+ const int nWidth = m_xStbStatus1->get_pixel_size(" 9999,99 cm / 9999,99 cm ").Width();
+ m_xStbStatus2->set_size_request(nWidth, -1);
+ m_xStbStatus3->set_size_request(nWidth, -1);
+
+ m_xFtURL->set_sensitive(false);
+ m_xURLBox->set_sensitive(false);
+ m_xFtText->set_sensitive(false);
+ m_xEdtText->set_sensitive(false);
+ m_xFtTarget->set_sensitive(false);
+ m_xCbbTarget->set_sensitive(false);
+ pOwnData->bExecState = false;
+
+ pOwnData->aIdle.SetInvokeHandler( LINK( this, SvxIMapDlg, UpdateHdl ) );
+
+ m_xTbxIMapDlg1->set_item_sensitive("TBI_ACTIVE", false);
+ m_xTbxIMapDlg1->set_item_sensitive("TBI_MACRO", false );
+ m_xTbxIMapDlg1->set_item_sensitive("TBI_PROPERTY", false );
+
+ m_xCancelBtn->connect_clicked(LINK(this, SvxIMapDlg, CancelHdl));
+}
+
+SvxIMapDlg::~SvxIMapDlg()
+{
+ m_xIMapWnd->SetUpdateLink( Link<GraphCtrl*,void>() );
+ m_xIMapWnd.reset();
+}
+
+IMPL_LINK_NOARG(SvxIMapDlg, CancelHdl, weld::Button&, void)
+{
+ bool bRet = true;
+
+ if ( m_xTbxIMapDlg1->get_item_sensitive("TBI_APPLY") )
+ {
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(m_xDialog.get(), "svx/ui/querymodifyimagemapchangesdialog.ui"));
+ std::unique_ptr<weld::MessageDialog> xQBox(xBuilder->weld_message_dialog("QueryModifyImageMapChangesDialog"));
+ const tools::Long nRet = xQBox->run();
+
+ if( nRet == RET_YES )
+ {
+ SfxBoolItem aBoolItem( SID_IMAP_EXEC, true );
+ GetBindings().GetDispatcher()->ExecuteList(SID_IMAP_EXEC,
+ SfxCallMode::SYNCHRON | SfxCallMode::RECORD,
+ { &aBoolItem });
+ }
+ else if( nRet == RET_CANCEL )
+ bRet = false;
+ }
+ else if( m_xIMapWnd->IsChanged() )
+ {
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(m_xDialog.get(), "svx/ui/querysaveimagemapchangesdialog.ui"));
+ std::unique_ptr<weld::MessageDialog> xQBox(xBuilder->weld_message_dialog("QuerySaveImageMapChangesDialog"));
+ const tools::Long nRet = xQBox->run();
+
+ if( nRet == RET_YES )
+ bRet = DoSave();
+ else if( nRet == RET_CANCEL )
+ bRet = false;
+ }
+
+ if (bRet)
+ m_xDialog->response(RET_CANCEL);
+}
+
+// Enabled or disable all Controls
+
+void SvxIMapDlg::SetExecState( bool bEnable )
+{
+ pOwnData->bExecState = bEnable;
+}
+
+const ImageMap& SvxIMapDlg::GetImageMap() const
+{
+ return m_xIMapWnd->GetImageMap();
+}
+
+void SvxIMapDlg::SetTargetList( const TargetList& rTargetList )
+{
+ m_xIMapWnd->SetTargetList( rTargetList );
+
+ m_xCbbTarget->clear();
+
+ for (const OUString & s : rTargetList)
+ m_xCbbTarget->append_text(s);
+}
+
+void SvxIMapDlg::UpdateLink( const Graphic& rGraphic, const ImageMap* pImageMap,
+ const TargetList* pTargetList, void* pEditingObj )
+{
+ pOwnData->aUpdateGraphic = rGraphic;
+
+ if ( pImageMap )
+ pOwnData->aUpdateImageMap = *pImageMap;
+ else
+ pOwnData->aUpdateImageMap.ClearImageMap();
+
+ pOwnData->pUpdateEditingObject = pEditingObj;
+
+ // Delete UpdateTargetList, because this method can still be called several
+ // times before the update timer is turned on
+
+ // TargetList must be copied, since it is owned by the caller and can be
+ // deleted immediately after this call the copied list will be deleted
+ // again in the handler
+ if( pTargetList )
+ pOwnData->aUpdateTargetList = *pTargetList;
+ else
+ pOwnData->aUpdateTargetList.clear();
+
+ pOwnData->aIdle.Start();
+}
+
+
+// Click-handler for ToolBox
+
+IMPL_LINK(SvxIMapDlg, TbxClickHdl, const OUString&, rNewItemId, void)
+{
+ if (rNewItemId == "TBI_APPLY")
+ {
+ URLLoseFocusHdl(*m_xCbbTarget);
+ SfxBoolItem aBoolItem( SID_IMAP_EXEC, true );
+ GetBindings().GetDispatcher()->ExecuteList(SID_IMAP_EXEC,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
+ { &aBoolItem });
+ }
+ else if (rNewItemId == "TBI_OPEN")
+ DoOpen();
+ else if (rNewItemId == "TBI_SAVEAS")
+ DoSave();
+ else if (rNewItemId == "TBI_CLOSE")
+ CancelHdl(*m_xCancelBtn);
+ else if (rNewItemId == "TBI_SELECT")
+ {
+ SetActiveTool( rNewItemId );
+ m_xIMapWnd->SetEditMode( true );
+ }
+ else if (rNewItemId == "TBI_RECT")
+ {
+ SetActiveTool( rNewItemId );
+ m_xIMapWnd->SetObjKind( SdrObjKind::Rectangle );
+ }
+ else if (rNewItemId == "TBI_CIRCLE")
+ {
+ SetActiveTool( rNewItemId );
+ m_xIMapWnd->SetObjKind( SdrObjKind::CircleOrEllipse );
+ }
+ else if (rNewItemId == "TBI_POLY")
+ {
+ SetActiveTool( rNewItemId );
+ m_xIMapWnd->SetObjKind( SdrObjKind::Polygon );
+ }
+ else if (rNewItemId == "TBI_FREEPOLY")
+ {
+ SetActiveTool( rNewItemId );
+ m_xIMapWnd->SetObjKind( SdrObjKind::FreehandFill );
+ }
+ else if (rNewItemId == "TBI_ACTIVE")
+ {
+ URLLoseFocusHdl(*m_xCbbTarget);
+ bool bNewState = !m_xTbxIMapDlg1->get_item_active(rNewItemId);
+ m_xTbxIMapDlg1->set_item_active(rNewItemId, bNewState);
+ m_xIMapWnd->SetCurrentObjState( !bNewState );
+ }
+ else if (rNewItemId == "TBI_MACRO")
+ m_xIMapWnd->DoMacroAssign();
+ else if (rNewItemId == "TBI_PROPERTY")
+ m_xIMapWnd->DoPropertyDialog();
+ else if (rNewItemId == "TBI_POLYEDIT")
+ {
+ SetActiveTool( rNewItemId );
+ m_xIMapWnd->SetPolyEditMode( m_xTbxIMapDlg1->get_item_active(rNewItemId) ? SID_BEZIER_MOVE : 0 );
+ }
+ else if (rNewItemId == "TBI_POLYMOVE")
+ {
+ SetActiveTool( rNewItemId );
+ m_xIMapWnd->SetPolyEditMode( SID_BEZIER_MOVE );
+ }
+ else if (rNewItemId == "TBI_POLYINSERT")
+ {
+ SetActiveTool( rNewItemId );
+ m_xIMapWnd->SetPolyEditMode( SID_BEZIER_INSERT );
+ }
+ else if (rNewItemId == "TBI_POLYDELETE")
+ {
+ SetActiveTool( rNewItemId );
+ m_xIMapWnd->GetSdrView()->DeleteMarkedPoints();
+ }
+ else if (rNewItemId == "TBI_UNDO")
+ {
+ URLLoseFocusHdl(*m_xCbbTarget);
+ m_xIMapWnd->GetSdrModel()->Undo();
+ }
+ else if (rNewItemId == "TBI_REDO")
+ {
+ URLLoseFocusHdl(*m_xCbbTarget);
+ m_xIMapWnd->GetSdrModel()->Redo();
+ }
+}
+
+void SvxIMapDlg::DoOpen()
+{
+ ::sfx2::FileDialogHelper aDlg(
+ css::ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE,
+ FileDialogFlags::NONE, m_xDialog.get());
+
+ ImageMap aLoadIMap;
+ const OUString aFilter(SvxResId(RID_SVXSTR_IMAP_ALL_FILTER));
+
+ aDlg.AddFilter( aFilter, IMAP_ALL_TYPE );
+ aDlg.AddFilter( IMAP_CERN_FILTER, IMAP_CERN_TYPE );
+ aDlg.AddFilter( IMAP_NCSA_FILTER, IMAP_NCSA_TYPE );
+ aDlg.AddFilter( IMAP_BINARY_FILTER, IMAP_BINARY_TYPE );
+
+ aDlg.SetCurrentFilter( aFilter );
+ aDlg.SetContext(sfx2::FileDialogHelper::ImageMap);
+
+ if( aDlg.Execute() != ERRCODE_NONE )
+ return;
+
+ INetURLObject aURL( aDlg.GetPath() );
+ DBG_ASSERT( aURL.GetProtocol() != INetProtocol::NotValid, "invalid URL" );
+ std::unique_ptr<SvStream> pIStm(::utl::UcbStreamHelper::CreateStream( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::READ ));
+
+ if( pIStm )
+ {
+ aLoadIMap.Read( *pIStm, IMapFormat::Detect );
+
+ if( pIStm->GetError() )
+ {
+ SfxErrorContext eEC(ERRCTX_ERROR, m_xDialog.get());
+ ErrorHandler::HandleError( ERRCODE_IO_GENERAL );
+ }
+ else
+ m_xIMapWnd->SetImageMap( aLoadIMap );
+ }
+
+ m_xIMapWnd->Invalidate();
+}
+
+bool SvxIMapDlg::DoSave()
+{
+ ::sfx2::FileDialogHelper aDlg(
+ css::ui::dialogs::TemplateDescription::FILESAVE_SIMPLE,
+ FileDialogFlags::NONE, m_xDialog.get());
+
+ const OUString aBinFilter( IMAP_BINARY_FILTER );
+ const OUString aCERNFilter( IMAP_CERN_FILTER );
+ const OUString aNCSAFilter( IMAP_NCSA_FILTER );
+ SdrModel* pModel = m_xIMapWnd->GetSdrModel();
+ const bool bChanged = pModel->IsChanged();
+ bool bRet = false;
+
+ aDlg.AddFilter( aCERNFilter, IMAP_CERN_TYPE );
+ aDlg.AddFilter( aNCSAFilter, IMAP_NCSA_TYPE );
+ aDlg.AddFilter( aBinFilter, IMAP_BINARY_TYPE );
+
+ aDlg.SetCurrentFilter( aCERNFilter );
+ aDlg.SetContext(sfx2::FileDialogHelper::ImageMap);
+
+ if( aDlg.Execute() == ERRCODE_NONE )
+ {
+ const OUString aFilter( aDlg.GetCurrentFilter() );
+ OUString aExt;
+ IMapFormat nFormat;
+
+ if ( aFilter == aBinFilter )
+ {
+ nFormat = IMapFormat::Binary;
+ aExt = "sip";
+ }
+ else if ( aFilter == aCERNFilter )
+ {
+ nFormat = IMapFormat::CERN;
+ aExt = "map";
+ }
+ else if ( aFilter == aNCSAFilter )
+ {
+ nFormat = IMapFormat::NCSA;
+ aExt = "map";
+ }
+ else
+ {
+ return false;
+ }
+
+ INetURLObject aURL( aDlg.GetPath() );
+
+ if( aURL.GetProtocol() == INetProtocol::NotValid )
+ {
+ OSL_FAIL( "invalid URL" );
+ }
+ else
+ {
+ if( aURL.getExtension().isEmpty() )
+ aURL.setExtension( aExt );
+
+ std::unique_ptr<SvStream> pOStm(::utl::UcbStreamHelper::CreateStream( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::WRITE | StreamMode::TRUNC ));
+ if( pOStm )
+ {
+ m_xIMapWnd->GetImageMap().Write( *pOStm, nFormat );
+
+ if( pOStm->GetError() )
+ ErrorHandler::HandleError( ERRCODE_IO_GENERAL );
+
+ pOStm.reset();
+ pModel->SetChanged( bChanged );
+ bRet = true;
+ }
+ }
+ }
+
+ return bRet;
+}
+
+void SvxIMapDlg::SetActiveTool(std::u16string_view rId)
+{
+ m_xTbxIMapDlg1->set_item_active("TBI_SELECT", rId == u"TBI_SELECT");
+ m_xTbxIMapDlg1->set_item_active("TBI_RECT", rId == u"TBI_RECT");
+ m_xTbxIMapDlg1->set_item_active("TBI_CIRCLE", rId == u"TBI_CIRCLE");
+ m_xTbxIMapDlg1->set_item_active("TBI_POLY", rId == u"TBI_POLY");
+ m_xTbxIMapDlg1->set_item_active("TBI_FREEPOLY", rId == u"TBI_FREEPOLY");
+
+ m_xTbxIMapDlg1->set_item_active("TBI_POLYINSERT", rId == u"TBI_POLYINSERT");
+ m_xTbxIMapDlg1->set_item_active("TBI_POLYDELETE", false);
+
+ bool bMove = rId == u"TBI_POLYMOVE"
+ || ( rId == u"TBI_POLYEDIT"
+ && !m_xTbxIMapDlg1->get_item_active("TBI_POLYINSERT")
+ && !m_xTbxIMapDlg1->get_item_active("TBI_POLYDELETE") );
+
+ m_xTbxIMapDlg1->set_item_active("TBI_POLYMOVE", bMove );
+
+ bool bEditMode = ( rId == u"TBI_POLYEDIT" )
+ || ( rId == u"TBI_POLYMOVE")
+ || ( rId == u"TBI_POLYINSERT")
+ || ( rId == u"TBI_POLYDELETE" );
+
+ m_xTbxIMapDlg1->set_item_active("TBI_POLYEDIT", bEditMode);
+}
+
+IMPL_LINK( SvxIMapDlg, InfoHdl, IMapWindow&, rWnd, void )
+{
+ const NotifyInfo& rInfo = rWnd.GetInfo();
+
+ if ( rInfo.bNewObj )
+ {
+ if (!rInfo.aMarkURL.isEmpty() && ( m_xURLBox->find_text(rInfo.aMarkURL) == -1))
+ m_xURLBox->append_text(rInfo.aMarkURL);
+
+ m_xURLBox->set_entry_text(rInfo.aMarkURL);
+ m_xEdtText->set_text(rInfo.aMarkAltText);
+
+ if ( rInfo.aMarkTarget.isEmpty() )
+ m_xCbbTarget->set_entry_text( SELF_TARGET );
+ else
+ m_xCbbTarget->set_entry_text( rInfo.aMarkTarget );
+ }
+
+ if ( !rInfo.bOneMarked )
+ {
+ m_xTbxIMapDlg1->set_item_active("TBI_ACTIVE", false);
+ m_xTbxIMapDlg1->set_item_sensitive("TBI_ACTIVE", false);
+ m_xTbxIMapDlg1->set_item_sensitive("TBI_MACRO", false);
+ m_xTbxIMapDlg1->set_item_sensitive("TBI_PROPERTY", false);
+ m_xStbStatus1->set_label(OUString());
+
+ m_xFtURL->set_sensitive(false);
+ m_xURLBox->set_sensitive(false);
+ m_xFtText->set_sensitive(false);
+ m_xEdtText->set_sensitive(false);
+ m_xFtTarget->set_sensitive(false);
+ m_xCbbTarget->set_sensitive(false);
+
+ m_xURLBox->set_entry_text( "" );
+ m_xEdtText->set_text( "" );
+ }
+ else
+ {
+ m_xTbxIMapDlg1->set_item_sensitive("TBI_ACTIVE", true);
+ m_xTbxIMapDlg1->set_item_active("TBI_ACTIVE", !rInfo.bActivated );
+ m_xTbxIMapDlg1->set_item_sensitive("TBI_MACRO", true);
+ m_xTbxIMapDlg1->set_item_sensitive("TBI_PROPERTY", true);
+
+ m_xFtURL->set_sensitive(true);
+ m_xURLBox->set_sensitive(true);
+ m_xFtText->set_sensitive(true);
+ m_xEdtText->set_sensitive(true);
+ m_xFtTarget->set_sensitive(true);
+ m_xCbbTarget->set_sensitive(true);
+
+ m_xStbStatus1->set_label(rInfo.aMarkURL);
+
+ if ( m_xURLBox->get_active_text() != rInfo.aMarkURL )
+ m_xURLBox->set_entry_text( rInfo.aMarkURL );
+
+ if ( m_xEdtText->get_text() != rInfo.aMarkAltText )
+ m_xEdtText->set_text( rInfo.aMarkAltText );
+
+ if ( rInfo.aMarkTarget.isEmpty() )
+ m_xCbbTarget->set_entry_text( SELF_TARGET );
+ else
+ m_xCbbTarget->set_entry_text( rInfo.aMarkTarget );
+ }
+}
+
+IMPL_LINK( SvxIMapDlg, MousePosHdl, GraphCtrl*, pWnd, void )
+{
+ const FieldUnit eFieldUnit = GetBindings().GetDispatcher()->GetModule()->GetFieldUnit();
+ const Point& rMousePos = pWnd->GetMousePos();
+ const LocaleDataWrapper& rLocaleWrapper( Application::GetSettings().GetLocaleDataWrapper() );
+ const sal_Unicode cSep = rLocaleWrapper.getNumDecimalSep()[0];
+
+ OUString aStr = GetUnitString( rMousePos.X(), eFieldUnit, cSep ) +
+ " / " + GetUnitString( rMousePos.Y(), eFieldUnit, cSep );
+
+ m_xStbStatus2->set_label(aStr);
+}
+
+IMPL_LINK( SvxIMapDlg, GraphSizeHdl, GraphCtrl*, pWnd, void )
+{
+ const FieldUnit eFieldUnit = GetBindings().GetDispatcher()->GetModule()->GetFieldUnit();
+ const Size& rSize = pWnd->GetGraphicSize();
+ const LocaleDataWrapper& rLocaleWrapper( Application::GetSettings().GetLocaleDataWrapper() );
+ const sal_Unicode cSep = rLocaleWrapper.getNumDecimalSep()[0];
+
+ OUString aStr = GetUnitString( rSize.Width(), eFieldUnit, cSep ) +
+ " x " + GetUnitString( rSize.Height(), eFieldUnit, cSep );
+
+ m_xStbStatus3->set_label(aStr);
+}
+
+void SvxIMapDlg::URLModify()
+{
+ NotifyInfo aNewInfo;
+
+ aNewInfo.aMarkURL = m_xURLBox->get_active_text();
+ aNewInfo.aMarkAltText = m_xEdtText->get_text();
+ aNewInfo.aMarkTarget = m_xCbbTarget->get_active_text();
+
+ m_xIMapWnd->ReplaceActualIMapInfo( aNewInfo );
+}
+
+IMPL_LINK_NOARG(SvxIMapDlg, URLModifyHdl, weld::ComboBox&, void)
+{
+ URLModify();
+}
+
+IMPL_LINK_NOARG(SvxIMapDlg, EntryModifyHdl, weld::Entry&, void)
+{
+ URLModify();
+}
+
+IMPL_LINK_NOARG(SvxIMapDlg, URLLoseFocusHdl, weld::Widget&, void)
+{
+ NotifyInfo aNewInfo;
+ const OUString aURLText( m_xURLBox->get_active_text() );
+ const OUString aTargetText( m_xCbbTarget->get_active_text() );
+
+ if ( !aURLText.isEmpty() )
+ {
+ OUString aBase = GetBindings().GetDispatcher()->GetFrame()->GetObjectShell()->GetMedium()->GetBaseURL();
+ aNewInfo.aMarkURL = ::URIHelper::SmartRel2Abs( INetURLObject(aBase), aURLText, URIHelper::GetMaybeFileHdl(), true, false,
+ INetURLObject::EncodeMechanism::WasEncoded,
+ INetURLObject::DecodeMechanism::Unambiguous );
+ }
+ else
+ aNewInfo.aMarkURL = aURLText;
+
+ aNewInfo.aMarkAltText = m_xEdtText->get_text();
+
+ if ( aTargetText.isEmpty() )
+ aNewInfo.aMarkTarget = SELF_TARGET;
+ else
+ aNewInfo.aMarkTarget = aTargetText;
+
+ m_xIMapWnd->ReplaceActualIMapInfo( aNewInfo );
+}
+
+IMPL_LINK_NOARG(SvxIMapDlg, UpdateHdl, Timer *, void)
+{
+ pOwnData->aIdle.Stop();
+
+ if ( pOwnData->pUpdateEditingObject != pCheckObj )
+ {
+ if (m_xIMapWnd->IsChanged())
+ {
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(m_xDialog.get(), "svx/ui/querysaveimagemapchangesdialog.ui"));
+ std::unique_ptr<weld::MessageDialog> xQBox(xBuilder->weld_message_dialog("QuerySaveImageMapChangesDialog"));
+ if (xQBox->run() == RET_YES)
+ {
+ DoSave();
+ }
+ }
+
+ m_xIMapWnd->SetGraphic( pOwnData->aUpdateGraphic );
+ m_xIMapWnd->SetImageMap( pOwnData->aUpdateImageMap );
+ SetTargetList( pOwnData->aUpdateTargetList );
+ pCheckObj = pOwnData->pUpdateEditingObject;
+
+ // After changes => default selection
+ m_xTbxIMapDlg1->set_item_active("TBI_SELECT", true);
+ m_xIMapWnd->SetEditMode( true );
+ }
+
+ // Delete the copied list again in the Update method
+ pOwnData->aUpdateTargetList.clear();
+
+ GetBindings().Invalidate( SID_IMAP_EXEC );
+ m_xIMapWnd->QueueIdleUpdate();
+}
+
+IMPL_LINK( SvxIMapDlg, StateHdl, GraphCtrl*, pWnd, void )
+{
+ const SdrObject* pObj = pWnd->GetSelectedSdrObject();
+ const SdrModel* pModel = pWnd->GetSdrModel();
+ const SdrView* pView = pWnd->GetSdrView();
+ const bool bPolyEdit = ( pObj != nullptr ) && dynamic_cast<const SdrPathObj*>( pObj) != nullptr;
+ const bool bDrawEnabled = !( bPolyEdit && m_xTbxIMapDlg1->get_item_active("TBI_POLYEDIT") );
+
+ m_xTbxIMapDlg1->set_item_sensitive("TBI_APPLY", pOwnData->bExecState && pWnd->IsChanged() );
+
+ m_xTbxIMapDlg1->set_item_sensitive("TBI_SELECT", bDrawEnabled);
+ m_xTbxIMapDlg1->set_item_sensitive("TBI_RECT", bDrawEnabled);
+ m_xTbxIMapDlg1->set_item_sensitive("TBI_CIRCLE", bDrawEnabled);
+ m_xTbxIMapDlg1->set_item_sensitive("TBI_POLY", bDrawEnabled);
+ m_xTbxIMapDlg1->set_item_sensitive("TBI_FREEPOLY", bDrawEnabled);
+
+ // BezierEditor State
+ m_xTbxIMapDlg1->set_item_sensitive( "TBI_POLYEDIT", bPolyEdit );
+ m_xTbxIMapDlg1->set_item_sensitive( "TBI_POLYMOVE", !bDrawEnabled );
+ m_xTbxIMapDlg1->set_item_sensitive( "TBI_POLYINSERT", !bDrawEnabled );
+ m_xTbxIMapDlg1->set_item_sensitive( "TBI_POLYDELETE", !bDrawEnabled && pView->IsDeleteMarkedPointsPossible() );
+
+ // Undo/Redo
+ m_xTbxIMapDlg1->set_item_sensitive( "TBI_UNDO", pModel->HasUndoActions() );
+ m_xTbxIMapDlg1->set_item_sensitive( "TBI_REDO", pModel->HasRedoActions() );
+
+ if ( bPolyEdit )
+ {
+ switch( pWnd->GetPolyEditMode() )
+ {
+ case SID_BEZIER_MOVE:
+ m_xTbxIMapDlg1->set_item_active("TBI_POLYMOVE", true);
+ m_xTbxIMapDlg1->set_item_active("TBI_POLYINSERT", false);
+ break;
+ case SID_BEZIER_INSERT:
+ m_xTbxIMapDlg1->set_item_active("TBI_POLYINSERT", true);
+ m_xTbxIMapDlg1->set_item_active("TBI_POLYMOVE", false);
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ m_xTbxIMapDlg1->set_item_active( "TBI_POLYEDIT", false );
+ m_xTbxIMapDlg1->set_item_active( "TBI_POLYMOVE", true);
+ m_xTbxIMapDlg1->set_item_active( "TBI_POLYINSERT", false );
+ pWnd->SetPolyEditMode( 0 );
+ }
+
+ m_xIMapWnd->QueueIdleUpdate();
+}
+
+SvxIMapDlg* GetIMapDlg()
+{
+ SfxChildWindow* pWnd = nullptr;
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ if (pViewFrm && pViewFrm->HasChildWindow(SvxIMapDlgChildWindow::GetChildWindowId()))
+ pWnd = pViewFrm->GetChildWindow(SvxIMapDlgChildWindow::GetChildWindowId());
+ return pWnd ? static_cast<SvxIMapDlg*>(pWnd->GetController().get()) : nullptr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/imapimp.hxx b/svx/source/dialog/imapimp.hxx
new file mode 100644
index 0000000000..50862f625f
--- /dev/null
+++ b/svx/source/dialog/imapimp.hxx
@@ -0,0 +1,51 @@
+/* -*- 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 .
+ */
+
+
+#ifndef INCLUDED_SVX_SOURCE_DIALOG_IMAPIMP_HXX
+#define INCLUDED_SVX_SOURCE_DIALOG_IMAPIMP_HXX
+
+#include <svx/imapdlg.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/idle.hxx>
+#include <vcl/imap.hxx>
+
+class IMapOwnData
+{
+public:
+
+ Idle aIdle;
+ Graphic aUpdateGraphic;
+ ImageMap aUpdateImageMap;
+ TargetList aUpdateTargetList;
+ void* pUpdateEditingObject;
+ bool bExecState;
+
+ IMapOwnData()
+ : aIdle("svx IMapOwnData")
+ , pUpdateEditingObject(nullptr)
+ , bExecState(false)
+ {
+ }
+};
+
+
+#endif // _IMAPIMP_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/imapwnd.cxx b/svx/source/dialog/imapwnd.cxx
new file mode 100644
index 0000000000..45ad2a9e9e
--- /dev/null
+++ b/svx/source/dialog/imapwnd.cxx
@@ -0,0 +1,738 @@
+/* -*- 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 <tools/urlobj.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/imaprect.hxx>
+#include <vcl/imapcirc.hxx>
+#include <vcl/imappoly.hxx>
+#include <vcl/svapp.hxx>
+#include <svl/urlbmk.hxx>
+
+#include <svx/svxids.hrc>
+#include "imapwnd.hxx"
+#include <svx/svdpage.hxx>
+#include <svx/svdorect.hxx>
+#include <svx/svdocirc.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/xfltrit.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xlnclit.hxx>
+
+#include <sfx2/evntconf.hxx>
+
+#include <sot/formats.hxx>
+
+#include <svx/svxdlg.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <memory>
+
+using namespace com::sun::star;
+using ::com::sun::star::frame::XFrame;
+using ::com::sun::star::uno::Reference;
+
+#define TRANSCOL COL_WHITE
+
+IMapWindow::IMapWindow(const Reference< XFrame >& rxDocumentFrame, weld::Dialog* pDialog)
+ : GraphCtrl(pDialog)
+ , mxDocumentFrame(rxDocumentFrame)
+{
+ pIMapPool = new SfxItemPool( "IMapItemPool",
+ SID_ATTR_MACROITEM, SID_ATTR_MACROITEM, maItemInfos );
+ pIMapPool->FreezeIdRanges();
+}
+
+IMapWindow::~IMapWindow()
+{
+}
+
+void IMapWindow::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ Size aSize(pDrawingArea->get_ref_device().LogicToPixel(Size(270, 170), MapMode(MapUnit::MapAppFont)));
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+ SetOutputSizePixel(aSize);
+ weld::CustomWidgetController::SetDrawingArea(pDrawingArea);
+
+ SetSdrMode(true);
+
+ mxDropTargetHelper.reset(new IMapDropTargetHelper(*this));
+}
+
+void IMapWindow::SetImageMap( const ImageMap& rImageMap )
+{
+ ReplaceImageMap( rImageMap );
+}
+
+void IMapWindow::ReplaceImageMap( const ImageMap& rImageMap )
+{
+ SdrPage* pPage = nullptr;
+ aIMap = rImageMap;
+
+ if(GetSdrModel())
+ {
+ // try to access page
+ pPage = GetSdrModel()->GetPage(0);
+ }
+
+ if(pPage)
+ {
+ // clear SdrObjects with broadcasting
+ pPage->ClearSdrObjList();
+ }
+
+ if(GetSdrView())
+ {
+ // #i63762# reset selection at view
+ GetSdrView()->UnmarkAllObj();
+ }
+
+ // create new drawing objects
+ const sal_uInt16 nCount(rImageMap.GetIMapObjectCount());
+
+ for ( sal_uInt16 i(nCount); i > 0; i-- )
+ {
+ rtl::Reference<SdrObject> pNewObj = CreateObj( rImageMap.GetIMapObject( i - 1 ) );
+
+ if (pNewObj && pPage)
+ {
+ pPage->InsertObject( pNewObj.get() );
+ }
+ }
+}
+
+void IMapWindow::ReplaceActualIMapInfo( const NotifyInfo& rNewInfo )
+{
+ const SdrObject* pSdrObj = GetSelectedSdrObject();
+
+ if ( pSdrObj )
+ {
+ IMapObject* pIMapObj = GetIMapObj( pSdrObj );
+ if (pIMapObj)
+ {
+ pIMapObj->SetURL( rNewInfo.aMarkURL );
+ pIMapObj->SetAltText( rNewInfo.aMarkAltText );
+ pIMapObj->SetTarget( rNewInfo.aMarkTarget );
+ pModel->SetChanged();
+ UpdateInfo( false );
+ }
+ }
+}
+
+const ImageMap& IMapWindow::GetImageMap()
+{
+ if ( pModel->IsChanged() )
+ {
+ SdrPage* pPage = pModel->GetPage( 0 );
+
+ if ( pPage )
+ {
+ const size_t nCount = pPage->GetObjCount();
+
+ aIMap.ClearImageMap();
+
+ for ( size_t i = nCount; i; )
+ {
+ --i;
+ aIMap.InsertIMapObject( *( static_cast<IMapUserData*>( pPage->GetObj( i )->GetUserData( 0 ) )->GetObject() ) );
+ }
+ }
+
+ pModel->SetChanged( false );
+ }
+
+ return aIMap;
+}
+
+void IMapWindow::SetTargetList( const TargetList& rTargetList )
+{
+ // Delete old List
+ // Fill with the provided list
+ aTargetList = rTargetList;
+
+ pModel->SetChanged( false );
+}
+
+rtl::Reference<SdrObject> IMapWindow::CreateObj( const IMapObject* pIMapObj )
+{
+ tools::Rectangle aClipRect( Point(), GetGraphicSize() );
+ rtl::Reference<SdrObject> pSdrObj;
+ IMapObjectPtr pCloneIMapObj;
+
+ switch( pIMapObj->GetType() )
+ {
+ case IMapObjectType::Rectangle:
+ {
+ const IMapRectangleObject* pIMapRectObj = static_cast<const IMapRectangleObject*>(pIMapObj);
+ tools::Rectangle aDrawRect( pIMapRectObj->GetRectangle( false ) );
+
+ // clipped on CanvasPane
+ aDrawRect.Intersection( aClipRect );
+
+ pSdrObj = new SdrRectObj(*pModel, aDrawRect);
+ pCloneIMapObj.reset(static_cast<IMapObject*>(new IMapRectangleObject( *pIMapRectObj )));
+ }
+ break;
+
+ case IMapObjectType::Circle:
+ {
+ const IMapCircleObject* pIMapCircleObj = static_cast<const IMapCircleObject*>(pIMapObj);
+ const Point aCenter( pIMapCircleObj->GetCenter( false ) );
+ const tools::Long nRadius = pIMapCircleObj->GetRadius( false );
+ const Point aOffset( nRadius, nRadius );
+ tools::Rectangle aCircle( aCenter - aOffset, aCenter + aOffset );
+
+ // limited to CanvasPane
+ aCircle.Intersection( aClipRect );
+
+ pSdrObj = new SdrCircObj(
+ *pModel,
+ SdrCircKind::Full,
+ aCircle,
+ 0_deg100,
+ 36000_deg100);
+ pCloneIMapObj.reset(static_cast<IMapObject*>(new IMapCircleObject( *pIMapCircleObj )));
+ }
+ break;
+
+ case IMapObjectType::Polygon:
+ {
+ const IMapPolygonObject* pIMapPolyObj = static_cast<const IMapPolygonObject*>(pIMapObj);
+
+ // If it actually is an ellipse, then another ellipse is created again
+ if ( pIMapPolyObj->HasExtraEllipse() )
+ {
+ tools::Rectangle aDrawRect( pIMapPolyObj->GetExtraEllipse() );
+
+ // clipped on CanvasPane
+ aDrawRect.Intersection( aClipRect );
+
+ pSdrObj = new SdrCircObj(
+ *pModel,
+ SdrCircKind::Full,
+ aDrawRect,
+ 0_deg100,
+ 36000_deg100);
+ }
+ else
+ {
+ const tools::Polygon& rPoly = pIMapPolyObj->GetPolygon( false );
+ tools::Polygon aDrawPoly( rPoly );
+
+ // clipped on CanvasPane
+ aDrawPoly.Clip( aClipRect );
+
+ basegfx::B2DPolygon aPolygon;
+ aPolygon.append(aDrawPoly.getB2DPolygon());
+ pSdrObj = new SdrPathObj(
+ *pModel,
+ SdrObjKind::Polygon,
+ basegfx::B2DPolyPolygon(aPolygon));
+ }
+
+ pCloneIMapObj.reset(static_cast<IMapObject*>(new IMapPolygonObject( *pIMapPolyObj )));
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if ( pSdrObj )
+ {
+ SfxItemSet aSet( pModel->GetItemPool() );
+
+ aSet.Put( XFillStyleItem( drawing::FillStyle_SOLID ) );
+ aSet.Put( XFillColorItem( "", TRANSCOL ) );
+
+ if ( !pIMapObj->IsActive() )
+ {
+ aSet.Put( XFillTransparenceItem( 100 ) );
+ aSet.Put( XLineColorItem( "", COL_RED ) );
+ }
+ else
+ {
+ aSet.Put( XFillTransparenceItem( 50 ) );
+ aSet.Put( XLineColorItem( "", COL_BLACK ) );
+ }
+
+ pSdrObj->SetMergedItemSetAndBroadcast(aSet);
+
+ pSdrObj->AppendUserData( std::unique_ptr<SdrObjUserData>(new IMapUserData( pCloneIMapObj )) );
+ pSdrObj->SetUserCall( GetSdrUserCall() );
+ }
+
+ return pSdrObj;
+}
+
+void IMapWindow::InitSdrModel()
+{
+ GraphCtrl::InitSdrModel();
+
+ SfxItemSet aSet( pModel->GetItemPool() );
+
+ aSet.Put( XFillColorItem( "", TRANSCOL ) );
+ aSet.Put( XFillTransparenceItem( 50 ) );
+ pView->SetAttributes( aSet );
+ pView->SetFrameDragSingles();
+}
+
+void IMapWindow::SdrObjCreated( const SdrObject& rObj )
+{
+ switch( rObj.GetObjIdentifier() )
+ {
+ case SdrObjKind::Rectangle:
+ {
+ SdrRectObj* pRectObj = const_cast<SdrRectObj*>(static_cast<const SdrRectObj*>(&rObj));
+ auto pObj = std::make_shared<IMapRectangleObject>( pRectObj->GetLogicRect(), "", "", "", "", "", true, false );
+
+ pRectObj->AppendUserData( std::unique_ptr<SdrObjUserData>(new IMapUserData( pObj )) );
+ }
+ break;
+
+ case SdrObjKind::CircleOrEllipse:
+ {
+ SdrCircObj* pCircObj = const_cast<SdrCircObj*>( static_cast<const SdrCircObj*>(&rObj) );
+ rtl::Reference<SdrPathObj> pPathObj = static_cast<SdrPathObj*>( pCircObj->ConvertToPolyObj( false, false ).get() );
+ tools::Polygon aPoly(pPathObj->GetPathPoly().getB2DPolygon(0));
+
+ pPathObj.clear();
+
+ auto pObj = std::make_shared<IMapPolygonObject>( aPoly, "", "", "", "", "", true, false );
+ pObj->SetExtraEllipse( aPoly.GetBoundRect() );
+ pCircObj->AppendUserData( std::unique_ptr<SdrObjUserData>(new IMapUserData( pObj )) );
+ }
+ break;
+
+ case SdrObjKind::Polygon:
+ case SdrObjKind::FreehandFill:
+ case SdrObjKind::PathPoly:
+ case SdrObjKind::PathFill:
+ {
+ SdrPathObj* pPathObj = const_cast<SdrPathObj*>( static_cast<const SdrPathObj*>(&rObj) );
+ const basegfx::B2DPolyPolygon& rXPolyPoly = pPathObj->GetPathPoly();
+
+ if ( rXPolyPoly.count() )
+ {
+ tools::Polygon aPoly(rXPolyPoly.getB2DPolygon(0));
+ auto pObj = std::make_shared<IMapPolygonObject>( aPoly, "", "", "", "", "", true, false );
+ pPathObj->AppendUserData( std::unique_ptr<SdrObjUserData>(new IMapUserData( pObj )) );
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void IMapWindow::SdrObjChanged( const SdrObject& rObj )
+{
+ IMapUserData* pUserData = static_cast<IMapUserData*>( rObj.GetUserData( 0 ) );
+
+ if ( !pUserData )
+ return;
+
+ OUString aURL;
+ OUString aAltText;
+ OUString aDesc;
+ OUString aTarget;
+ IMapObjectPtr pIMapObj = pUserData->GetObject();
+ bool bActive = true;
+
+ if ( pIMapObj )
+ {
+ aURL = pIMapObj->GetURL();
+ aAltText = pIMapObj->GetAltText();
+ aDesc = pIMapObj->GetDesc();
+ aTarget = pIMapObj->GetTarget();
+ bActive = pIMapObj->IsActive();
+ }
+
+ switch( rObj.GetObjIdentifier() )
+ {
+ case SdrObjKind::Rectangle:
+ {
+ pUserData->ReplaceObject( std::make_shared<IMapRectangleObject>( static_cast<const SdrRectObj&>(rObj).GetLogicRect(),
+ aURL, aAltText, aDesc, aTarget, "", bActive, false ) );
+ }
+ break;
+
+ case SdrObjKind::CircleOrEllipse:
+ {
+ const SdrCircObj& rCircObj = static_cast<const SdrCircObj&>(rObj);
+ rtl::Reference<SdrPathObj> pPathObj = static_cast<SdrPathObj*>( rCircObj.ConvertToPolyObj( false, false ).get() );
+ tools::Polygon aPoly(pPathObj->GetPathPoly().getB2DPolygon(0));
+
+ auto pObj = std::make_shared<IMapPolygonObject>( aPoly, aURL, aAltText, aDesc, aTarget, "", bActive, false );
+ pObj->SetExtraEllipse( aPoly.GetBoundRect() );
+
+ pPathObj.clear();
+
+ pUserData->ReplaceObject( pObj );
+ }
+ break;
+
+ case SdrObjKind::Polygon:
+ case SdrObjKind::FreehandFill:
+ case SdrObjKind::PathPoly:
+ case SdrObjKind::PathFill:
+ {
+ const SdrPathObj& rPathObj = static_cast<const SdrPathObj&>(rObj);
+ const basegfx::B2DPolyPolygon& rXPolyPoly = rPathObj.GetPathPoly();
+
+ if ( rXPolyPoly.count() )
+ {
+ tools::Polygon aPoly(rPathObj.GetPathPoly().getB2DPolygon(0));
+ auto pObj = std::make_shared<IMapPolygonObject>( aPoly, aURL, aAltText, aDesc, aTarget, "", bActive, false );
+ pUserData->ReplaceObject( pObj );
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+bool IMapWindow::MouseButtonUp(const MouseEvent& rMEvt)
+{
+ bool bRet = GraphCtrl::MouseButtonUp( rMEvt );
+ UpdateInfo( true );
+ return bRet;
+}
+
+void IMapWindow::MarkListHasChanged()
+{
+ GraphCtrl::MarkListHasChanged();
+ UpdateInfo( false );
+}
+
+SdrObject* IMapWindow::GetHitSdrObj( const Point& rPosPixel ) const
+{
+ OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
+
+ SdrObject* pObj = nullptr;
+ Point aPt = rDevice.PixelToLogic( rPosPixel );
+
+ if ( tools::Rectangle( Point(), GetGraphicSize() ).Contains( aPt ) )
+ {
+ SdrPage* pPage = pModel->GetPage( 0 );
+ if ( pPage )
+ {
+ for ( size_t i = pPage->GetObjCount(); i > 0; )
+ {
+ --i;
+ SdrObject* pTestObj = pPage->GetObj( i );
+ IMapObject* pIMapObj = GetIMapObj( pTestObj );
+
+ if ( pIMapObj && pIMapObj->IsHit( aPt ) )
+ {
+ pObj = pTestObj;
+ break;
+ }
+ }
+ }
+ }
+
+ return pObj;
+}
+
+IMapObject* IMapWindow::GetIMapObj( const SdrObject* pSdrObj )
+{
+ IMapObject* pIMapObj = nullptr;
+
+ if ( pSdrObj )
+ {
+ IMapUserData* pUserData = static_cast<IMapUserData*>( pSdrObj->GetUserData( 0 ) );
+
+ if ( pUserData )
+ pIMapObj = pUserData->GetObject().get();
+ }
+
+ return pIMapObj;
+}
+
+bool IMapWindow::Command(const CommandEvent& rCEvt)
+{
+ if ( rCEvt.GetCommand() == CommandEventId::ContextMenu )
+ {
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(GetDrawingArea(), "svx/ui/imapmenu.ui"));
+ mxPopupMenu = xBuilder->weld_menu("menu");
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+ const size_t nMarked = rMarkList.GetMarkCount();
+
+ mxPopupMenu->set_sensitive("url", false);
+ mxPopupMenu->set_sensitive("active", false);
+ mxPopupMenu->set_sensitive("macro", false);
+ mxPopupMenu->set_sensitive("selectall", pModel->GetPage(0)->GetObjCount() != pView->GetMarkedObjectCount());
+
+ if ( !nMarked )
+ {
+ mxPopupMenu->set_sensitive("arrange", false);
+ mxPopupMenu->set_sensitive("delete", false);
+ }
+ else
+ {
+ if ( nMarked == 1 )
+ {
+ SdrObject* pSdrObj = GetSelectedSdrObject();
+
+ mxPopupMenu->set_sensitive("url", true);
+ mxPopupMenu->set_sensitive("active", true);
+ mxPopupMenu->set_sensitive("macro", true);
+ mxPopupMenu->set_active("active", GetIMapObj(pSdrObj)->IsActive());
+ }
+
+ mxPopupMenu->set_sensitive("arrange", true);
+ mxPopupMenu->set_sensitive("delete", true);
+ }
+
+ MenuSelectHdl(mxPopupMenu->popup_at_rect(GetDrawingArea(), tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1,1))));
+
+ mxPopupMenu.reset();
+
+ return true;
+ }
+ return CustomWidgetController::Command(rCEvt);
+}
+
+IMapDropTargetHelper::IMapDropTargetHelper(IMapWindow& rImapWindow)
+ : DropTargetHelper(rImapWindow.GetDrawingArea()->get_drop_target())
+ , m_rImapWindow(rImapWindow)
+{
+}
+
+sal_Int8 IMapDropTargetHelper::AcceptDrop( const AcceptDropEvent& rEvt )
+{
+ return m_rImapWindow.AcceptDrop(rEvt);
+}
+
+sal_Int8 IMapDropTargetHelper::ExecuteDrop( const ExecuteDropEvent& rEvt )
+{
+ return m_rImapWindow.ExecuteDrop(rEvt);
+}
+
+sal_Int8 IMapWindow::AcceptDrop( const AcceptDropEvent& rEvt )
+{
+ return( ( GetHitSdrObj( rEvt.maPosPixel ) != nullptr ) ? rEvt.mnAction : DND_ACTION_NONE );
+}
+
+sal_Int8 IMapWindow::ExecuteDrop( const ExecuteDropEvent& rEvt )
+{
+ sal_Int8 nRet = DND_ACTION_NONE;
+
+ if (mxDropTargetHelper->IsDropFormatSupported(SotClipboardFormatId::NETSCAPE_BOOKMARK))
+ {
+ INetBookmark aBookMark( "", "" );
+ SdrObject* pSdrObj = GetHitSdrObj( rEvt.maPosPixel );
+
+ if( pSdrObj && TransferableDataHelper( rEvt.maDropEvent.Transferable ).GetINetBookmark( SotClipboardFormatId::NETSCAPE_BOOKMARK, aBookMark ) )
+ {
+ IMapObject* pIMapObj = GetIMapObj( pSdrObj );
+
+ pIMapObj->SetURL( aBookMark.GetURL() );
+ pIMapObj->SetAltText( aBookMark.GetDescription() );
+ pModel->SetChanged();
+ pView->UnmarkAll();
+ pView->MarkObj( pSdrObj, pView->GetSdrPageView() );
+ UpdateInfo( true );
+ nRet = rEvt.mnAction;
+ }
+ }
+
+ return nRet;
+}
+
+OUString IMapWindow::RequestHelp(tools::Rectangle& rHelpArea)
+{
+ OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
+
+ Point aPos = rDevice.PixelToLogic(rHelpArea.TopLeft());
+
+ SdrPageView* pPageView = nullptr;
+ SdrObject* pSdrObj = pView->PickObj(aPos, pView->getHitTolLog(), pPageView);
+ if (pSdrObj)
+ {
+ const IMapObject* pIMapObj = GetIMapObj( pSdrObj );
+ if ( pIMapObj )
+ {
+ OUString aStr = pIMapObj->GetURL();
+ if ( !aStr.isEmpty() )
+ {
+ rHelpArea = rDevice.LogicToPixel(tools::Rectangle( Point(), GetGraphicSize()));
+ return aStr;
+ }
+ }
+ }
+
+ return OUString();
+}
+
+void IMapWindow::SetCurrentObjState( bool bActive )
+{
+ SdrObject* pObj = GetSelectedSdrObject();
+
+ if ( !pObj )
+ return;
+
+ SfxItemSet aSet( pModel->GetItemPool() );
+
+ GetIMapObj( pObj )->SetActive( bActive );
+
+ aSet.Put( XFillColorItem( "", TRANSCOL ) );
+
+ if ( !bActive )
+ {
+ aSet.Put( XFillTransparenceItem( 100 ) );
+ aSet.Put( XLineColorItem( "", COL_RED ) );
+ }
+ else
+ {
+ aSet.Put( XFillTransparenceItem( 50 ) );
+ aSet.Put( XLineColorItem( "", COL_BLACK ) );
+ }
+
+ pView->SetAttributes( aSet );
+}
+
+void IMapWindow::UpdateInfo( bool bNewObj )
+{
+ if ( !aInfoLink.IsSet() )
+ return;
+
+ const SdrObject* pSdrObj = GetSelectedSdrObject();
+ const IMapObject* pIMapObj = pSdrObj ? GetIMapObj( pSdrObj ) : nullptr;
+
+ aInfo.bNewObj = bNewObj;
+
+ if ( pIMapObj )
+ {
+ aInfo.bOneMarked = true;
+ aInfo.aMarkURL = pIMapObj->GetURL();
+ aInfo.aMarkAltText = pIMapObj->GetAltText();
+ aInfo.aMarkTarget = pIMapObj->GetTarget();
+ aInfo.bActivated = pIMapObj->IsActive();
+ aInfoLink.Call( *this );
+ }
+ else
+ {
+ aInfo.aMarkURL.clear();
+ aInfo.aMarkAltText.clear();
+ aInfo.aMarkTarget.clear();
+ aInfo.bOneMarked = false;
+ aInfo.bActivated = false;
+ }
+
+ aInfoLink.Call( *this );
+}
+
+void IMapWindow::DoMacroAssign()
+{
+ SdrObject* pSdrObj = GetSelectedSdrObject();
+
+ if ( !pSdrObj )
+ return;
+
+ SfxItemSetFixed<SID_ATTR_MACROITEM, SID_ATTR_MACROITEM, SID_EVENTCONFIG, SID_EVENTCONFIG>
+ aSet(*pIMapPool);
+
+ SfxEventNamesItem aNamesItem(SID_EVENTCONFIG);
+ aNamesItem.AddEvent( "MouseOver", "", SvMacroItemId::OnMouseOver );
+ aNamesItem.AddEvent( "MouseOut", "", SvMacroItemId::OnMouseOut );
+ aSet.Put( aNamesItem );
+
+ SvxMacroItem aMacroItem(SID_ATTR_MACROITEM);
+ IMapObject* pIMapObj = GetIMapObj( pSdrObj );
+ aMacroItem.SetMacroTable( pIMapObj->GetMacroTable() );
+ aSet.Put( aMacroItem );
+
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<SfxAbstractDialog> pMacroDlg(pFact->CreateEventConfigDialog(GetDrawingArea(), aSet, mxDocumentFrame));
+
+ if ( pMacroDlg->Execute() == RET_OK )
+ {
+ const SfxItemSet* pOutSet = pMacroDlg->GetOutputItemSet();
+ pIMapObj->SetMacroTable( pOutSet->Get( SID_ATTR_MACROITEM ).GetMacroTable() );
+ pModel->SetChanged();
+ UpdateInfo( false );
+ }
+}
+
+void IMapWindow::DoPropertyDialog()
+{
+ SdrObject* pSdrObj = GetSelectedSdrObject();
+
+ if ( !pSdrObj )
+ return;
+
+ IMapObject* pIMapObj = GetIMapObj( pSdrObj );
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractURLDlg> aDlg(pFact->CreateURLDialog(GetDrawingArea(), pIMapObj->GetURL(), pIMapObj->GetAltText(), pIMapObj->GetDesc(),
+ pIMapObj->GetTarget(), pIMapObj->GetName(), aTargetList));
+ if ( aDlg->Execute() != RET_OK )
+ return;
+
+ const OUString aURLText( aDlg->GetURL() );
+
+ if ( !aURLText.isEmpty() )
+ {
+ INetURLObject aObj( aURLText, INetProtocol::File );
+ DBG_ASSERT( aObj.GetProtocol() != INetProtocol::NotValid, "Invalid URL" );
+ pIMapObj->SetURL( aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
+ }
+ else
+ pIMapObj->SetURL( aURLText );
+
+ pIMapObj->SetAltText( aDlg->GetAltText() );
+ pIMapObj->SetDesc( aDlg->GetDesc() );
+ pIMapObj->SetTarget( aDlg->GetTarget() );
+ pIMapObj->SetName( aDlg->GetName() );
+ pModel->SetChanged();
+ UpdateInfo( true );
+}
+
+void IMapWindow::MenuSelectHdl(const OUString& rId)
+{
+ if (rId == "url")
+ DoPropertyDialog();
+ else if (rId == "macro")
+ DoMacroAssign();
+ else if (rId == "active")
+ {
+ const bool bNewState = !mxPopupMenu->get_active(rId);
+ SetCurrentObjState(bNewState);
+ UpdateInfo( false );
+ }
+ else if (rId == "front")
+ pView->PutMarkedToTop();
+ else if (rId == "forward")
+ pView->MovMarkedToTop();
+ else if (rId == "backward")
+ pView->MovMarkedToBtm();
+ else if (rId == "back")
+ pView->PutMarkedToBtm();
+ else if (rId == "selectall")
+ pView->MarkAll();
+ else if (rId == "delete")
+ pView->DeleteMarked();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/imapwnd.hxx b/svx/source/dialog/imapwnd.hxx
new file mode 100644
index 0000000000..fee372a25f
--- /dev/null
+++ b/svx/source/dialog/imapwnd.hxx
@@ -0,0 +1,142 @@
+/* -*- 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 .
+ */
+#ifndef INCLUDED_SVX_SOURCE_DIALOG_IMAPWND_HXX
+#define INCLUDED_SVX_SOURCE_DIALOG_IMAPWND_HXX
+
+#include <utility>
+#include <vcl/imapobj.hxx>
+#include <vcl/transfer.hxx>
+#include <vcl/imap.hxx>
+#include <sfx2/frame.hxx>
+#include <svx/graphctl.hxx>
+#include <svl/itempool.hxx>
+
+#include <com/sun/star/frame/XFrame.hpp>
+
+struct NotifyInfo
+{
+ OUString aMarkURL;
+ OUString aMarkAltText;
+ OUString aMarkTarget;
+ bool bNewObj;
+ bool bOneMarked;
+ bool bActivated;
+};
+
+
+#define SVD_IMAP_USERDATA 0x0001
+
+typedef std::shared_ptr< IMapObject > IMapObjectPtr;
+
+class IMapUserData : public SdrObjUserData
+{
+ // #i98386# use std::shared_ptr here due to cloning possibilities
+ IMapObjectPtr mpObj;
+
+public:
+
+ explicit IMapUserData( IMapObjectPtr xIMapObj ) :
+ SdrObjUserData ( SdrInventor::IMap, SVD_IMAP_USERDATA ),
+ mpObj (std::move( xIMapObj )) {}
+
+ IMapUserData( const IMapUserData& rIMapUserData ) :
+ SdrObjUserData ( SdrInventor::IMap, SVD_IMAP_USERDATA ),
+ mpObj ( rIMapUserData.mpObj ) {}
+
+ virtual std::unique_ptr<SdrObjUserData> Clone( SdrObject * ) const override { return std::unique_ptr<SdrObjUserData>(new IMapUserData( *this )); }
+
+ const IMapObjectPtr& GetObject() const { return mpObj; }
+ void ReplaceObject( const IMapObjectPtr& pNewIMapObject ) { mpObj = pNewIMapObject; }
+};
+
+class IMapWindow;
+
+class IMapDropTargetHelper final : public DropTargetHelper
+{
+ IMapWindow& m_rImapWindow;
+public:
+ IMapDropTargetHelper(IMapWindow& rImapWindow);
+
+ // DropTargetHelper
+ virtual sal_Int8 AcceptDrop( const AcceptDropEvent& rEvt ) override;
+ virtual sal_Int8 ExecuteDrop( const ExecuteDropEvent& rEvt ) override;
+};
+
+class IMapWindow final : public GraphCtrl
+{
+ NotifyInfo aInfo;
+ ImageMap aIMap;
+ TargetList aTargetList;
+ Link<IMapWindow&,void> aInfoLink;
+ rtl::Reference<SfxItemPool> pIMapPool;
+ SfxItemInfo maItemInfos[1] = {};
+ css::uno::Reference< css::frame::XFrame >
+ mxDocumentFrame;
+ std::unique_ptr<IMapDropTargetHelper> mxDropTargetHelper;
+ std::unique_ptr<weld::Menu> mxPopupMenu;
+
+ void MenuSelectHdl(const OUString& rId);
+
+ // GraphCtrl
+ virtual bool MouseButtonUp(const MouseEvent& rMEvt) override;
+ virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override;
+ virtual bool Command(const CommandEvent& rCEvt) override;
+ virtual OUString RequestHelp(tools::Rectangle& rHelpArea) override;
+ virtual void SdrObjCreated( const SdrObject& rObj ) override;
+ virtual void SdrObjChanged( const SdrObject& rObj ) override;
+ virtual void MarkListHasChanged() override;
+ virtual void InitSdrModel() override;
+
+ void ReplaceImageMap( const ImageMap& rNewImageMap );
+
+ rtl::Reference<SdrObject> CreateObj( const IMapObject* pIMapObj );
+ static IMapObject* GetIMapObj( const SdrObject* pSdrObj );
+ SdrObject* GetHitSdrObj( const Point& rPosPixel ) const;
+
+ void UpdateInfo( bool bNewObj );
+
+public:
+
+ IMapWindow(const css::uno::Reference< css::frame::XFrame >& rxDocumentFrame,
+ weld::Dialog* pDialog);
+ virtual ~IMapWindow() override;
+
+ sal_Int8 AcceptDrop( const AcceptDropEvent& rEvt );
+ sal_Int8 ExecuteDrop( const ExecuteDropEvent& rEvt );
+
+ void ReplaceActualIMapInfo( const NotifyInfo& rNewInfo );
+
+ void SetImageMap( const ImageMap& rImageMap );
+ const ImageMap& GetImageMap();
+
+ void SetCurrentObjState( bool bActive );
+ void DoMacroAssign();
+ void DoPropertyDialog();
+
+ void SetInfoLink( const Link<IMapWindow&,void>& rLink ) { aInfoLink = rLink; }
+
+ void SetTargetList( const TargetList& rTargetList );
+
+ const NotifyInfo& GetInfo() const { return aInfo; }
+};
+
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/langbox.cxx b/svx/source/dialog/langbox.cxx
new file mode 100644
index 0000000000..713bf0d34b
--- /dev/null
+++ b/svx/source/dialog/langbox.cxx
@@ -0,0 +1,553 @@
+/* -*- 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/linguistic2/XAvailableLocales.hpp>
+#include <com/sun/star/linguistic2/XLinguServiceManager2.hpp>
+#include <com/sun/star/linguistic2/XSpellChecker1.hpp>
+#include <linguistic/misc.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <tools/urlobj.hxx>
+#include <svtools/langtab.hxx>
+#include <i18nlangtag/mslangid.hxx>
+#include <i18nlangtag/lang.h>
+#include <editeng/unolingu.hxx>
+#include <svl/languageoptions.hxx>
+#include <svx/langbox.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+#include <bitmaps.hlst>
+
+#include <comphelper/string.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/scopeguard.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::linguistic2;
+using namespace ::com::sun::star::uno;
+
+OUString GetDicInfoStr( std::u16string_view rName, const LanguageType nLang, bool bNeg )
+{
+ INetURLObject aURLObj;
+ aURLObj.SetSmartProtocol( INetProtocol::File );
+ aURLObj.SetSmartURL( rName, INetURLObject::EncodeMechanism::All );
+ OUString aTmp( aURLObj.GetBase() + " " );
+
+ if ( bNeg )
+ {
+ aTmp += " (-) ";
+ }
+
+ if ( LANGUAGE_NONE == nLang )
+ aTmp += SvxResId(RID_SVXSTR_LANGUAGE_ALL);
+ else
+ {
+ aTmp += "[" + SvtLanguageTable::GetLanguageString( nLang ) + "]";
+ }
+
+ return aTmp;
+}
+
+// misc local helper functions
+static void appendLocaleSeqToLangs(Sequence<css::lang::Locale> const& rSeq,
+ std::vector<LanguageType>& aLangs)
+{
+ sal_Int32 nCount = rSeq.getLength();
+
+ aLangs.reserve(aLangs.size() + nCount);
+
+ std::transform(rSeq.begin(), rSeq.end(), std::back_inserter(aLangs),
+ [](const css::lang::Locale& rLocale) -> LanguageType {
+ return LanguageTag::convertToLanguageType(rLocale); });
+}
+
+static bool lcl_SeqHasLang( const Sequence< sal_Int16 > & rLangSeq, sal_Int16 nLang )
+{
+ return rLangSeq.hasElements()
+ && std::find(rLangSeq.begin(), rLangSeq.end(), nLang) != rLangSeq.end();
+}
+
+namespace {
+
+bool lcl_isPrerequisite(LanguageType nLangType, bool requireSublang)
+{
+ return
+ nLangType != LANGUAGE_DONTKNOW &&
+ nLangType != LANGUAGE_SYSTEM &&
+ nLangType != LANGUAGE_NONE &&
+ nLangType != LANGUAGE_USER_KEYID &&
+ !MsLangId::isLegacy( nLangType) &&
+ (!requireSublang || MsLangId::getSubLanguage( nLangType));
+}
+
+bool lcl_isScriptTypeRequested( LanguageType nLangType, SvxLanguageListFlags nLangList )
+{
+ return
+ bool(nLangList & SvxLanguageListFlags::ALL) ||
+ (bool(nLangList & SvxLanguageListFlags::WESTERN) &&
+ (SvtLanguageOptions::GetScriptTypeOfLanguage(nLangType) == SvtScriptType::LATIN)) ||
+ (bool(nLangList & SvxLanguageListFlags::CTL) &&
+ (SvtLanguageOptions::GetScriptTypeOfLanguage(nLangType) == SvtScriptType::COMPLEX)) ||
+ (bool(nLangList & SvxLanguageListFlags::CJK) &&
+ (SvtLanguageOptions::GetScriptTypeOfLanguage(nLangType) == SvtScriptType::ASIAN));
+}
+
+}
+
+
+LanguageType SvxLanguageBox::get_active_id() const
+{
+ OUString sLang = m_xControl->get_active_id();
+ if (!sLang.isEmpty())
+ return LanguageType(sLang.toInt32());
+ else
+ return LANGUAGE_DONTKNOW;
+}
+
+int SvxLanguageBox::find_id(const LanguageType eLangType) const
+{
+ return m_xControl->find_id(OUString::number(static_cast<sal_uInt16>(eLangType)));
+}
+
+void SvxLanguageBox::set_id(int pos, const LanguageType eLangType)
+{
+ m_xControl->set_id(pos, OUString::number(static_cast<sal_uInt16>(eLangType)));
+}
+
+LanguageType SvxLanguageBox::get_id(int pos) const
+{
+ return LanguageType(m_xControl->get_id(pos).toInt32());
+}
+
+void SvxLanguageBox::remove_id(const LanguageType eLangType)
+{
+ m_xControl->remove_id(OUString::number(static_cast<sal_uInt16>(eLangType)));
+}
+
+void SvxLanguageBox::append(const LanguageType eLangType, const OUString& rStr)
+{
+ m_xControl->append(OUString::number(static_cast<sal_uInt16>(eLangType)), rStr);
+}
+
+void SvxLanguageBox::set_active_id(const LanguageType eLangType)
+{
+ // If the core uses a LangID of an imported MS document and wants to select
+ // a language that is replaced, we need to select the replacement instead.
+ LanguageType nLang = MsLangId::getReplacementForObsoleteLanguage( eLangType);
+
+ sal_Int32 nAt = find_id( nLang );
+
+ if (nAt == -1)
+ {
+ InsertLanguage( nLang ); // on-the-fly-ID
+ nAt = find_id( nLang );
+ }
+
+ if (nAt != -1)
+ m_xControl->set_active(nAt);
+}
+
+void SvxLanguageBox::AddLanguages(const std::vector< LanguageType >& rLanguageTypes,
+ SvxLanguageListFlags nLangList, std::vector<weld::ComboBoxEntry>& rEntries, bool requireSublang)
+{
+ for ( auto const & nLangType : rLanguageTypes )
+ {
+ if (lcl_isPrerequisite(nLangType, requireSublang))
+ {
+ LanguageType nLang = MsLangId::getReplacementForObsoleteLanguage( nLangType );
+ if (lcl_isScriptTypeRequested( nLang, nLangList))
+ {
+ int nAt = find_id(nLang);
+ if (nAt != -1)
+ continue;
+ weld::ComboBoxEntry aNewEntry(BuildEntry(nLang));
+ if (aNewEntry.sString.isEmpty())
+ continue;
+ rEntries.push_back(aNewEntry);
+ }
+ }
+ }
+}
+
+static void SortLanguages(std::vector<weld::ComboBoxEntry>& rEntries)
+{
+ auto langLess = [](const weld::ComboBoxEntry& e1, const weld::ComboBoxEntry& e2)
+ {
+ if (e1.sId == e2.sId)
+ return false; // shortcut
+ // Make sure that e.g. generic 'Spanish {es}' goes before 'Spanish (Argentina)'.
+ // We can't depend on MsLangId::getPrimaryLanguage/getSubLanguage, because e.g.
+ // for generic Bosnian {bs}, the MS-LCID is 0x781A, and getSubLanguage is not 0.
+ // So we have to do the expensive LanguageTag construction.
+ LanguageTag lt1(LanguageType(e1.sId.toInt32())), lt2(LanguageType(e2.sId.toInt32()));
+ if (lt1.getLanguage() == lt2.getLanguage())
+ {
+ const bool isLangOnly1 = lt1.isIsoLocale() && lt1.getCountry().isEmpty();
+ const bool isLangOnly2 = lt2.isIsoLocale() && lt2.getCountry().isEmpty();
+
+ if (isLangOnly1)
+ {
+ // lt1 is a generic language-only tag
+ if (!isLangOnly2)
+ return true; // lt2 is not
+ }
+ else if (isLangOnly2)
+ {
+ // lt2 is a generic language-only tag, lt1 is not
+ return false;
+ }
+ }
+ // Do a normal string comparison for other cases
+ static const auto aSorter = comphelper::string::NaturalStringSorter(
+ comphelper::getProcessComponentContext(),
+ Application::GetSettings().GetUILanguageTag().getLocale());
+ return aSorter.compare(e1.sString, e2.sString) < 0;
+ };
+
+ std::sort(rEntries.begin(), rEntries.end(), langLess);
+ rEntries.erase(std::unique(rEntries.begin(), rEntries.end(),
+ [](const weld::ComboBoxEntry& e1, const weld::ComboBoxEntry& e2)
+ { return e1.sId == e2.sId; }),
+ rEntries.end());
+}
+
+void SvxLanguageBox::SetLanguageList(SvxLanguageListFlags nLangList, bool bHasLangNone,
+ bool bLangNoneIsLangAll, bool bCheckSpellAvail,
+ bool bDefaultLangExist, LanguageType eDefaultLangType,
+ sal_Int16 nDefaultType)
+{
+ m_bHasLangNone = bHasLangNone;
+ m_bLangNoneIsLangAll = bLangNoneIsLangAll;
+ m_bWithCheckmark = bCheckSpellAvail;
+
+ m_xControl->freeze();
+ comphelper::ScopeGuard aThawGuard([this]() { m_xControl->thaw(); });
+ m_xControl->clear();
+
+ if (SvxLanguageListFlags::EMPTY == nLangList)
+ return;
+
+ bool bAddSeparator = false;
+
+ if (bHasLangNone)
+ {
+ m_xControl->append(BuildEntry(LANGUAGE_NONE));
+ bAddSeparator = true;
+ }
+
+ if (bDefaultLangExist)
+ {
+ m_xControl->append(BuildEntry(eDefaultLangType, nDefaultType));
+ bAddSeparator = true;
+ }
+
+ if (bAddSeparator)
+ m_xControl->append_separator("");
+
+ bool bAddAvailable = (!(nLangList & SvxLanguageListFlags::ONLY_KNOWN) &&
+ ((nLangList & SvxLanguageListFlags::ALL) ||
+ (nLangList & SvxLanguageListFlags::WESTERN) ||
+ (nLangList & SvxLanguageListFlags::CTL) ||
+ (nLangList & SvxLanguageListFlags::CJK)));
+ std::vector< LanguageType > aAvailLang;
+ Sequence< sal_Int16 > aSpellUsedLang;
+ if (bAddAvailable)
+ {
+ if (auto xAvail = LinguMgr::GetLngSvcMgr())
+ {
+ appendLocaleSeqToLangs(xAvail->getAvailableLocales(SN_SPELLCHECKER), aAvailLang);
+ appendLocaleSeqToLangs(xAvail->getAvailableLocales(SN_HYPHENATOR), aAvailLang);
+ appendLocaleSeqToLangs(xAvail->getAvailableLocales(SN_THESAURUS), aAvailLang);
+ }
+ }
+ if (SvxLanguageListFlags::SPELL_USED & nLangList)
+ {
+ Reference< XSpellChecker1 > xTmp1 = LinguMgr::GetSpellChecker();
+ if (xTmp1.is())
+ aSpellUsedLang = xTmp1->getLanguages();
+ }
+
+ std::vector<LanguageType> aKnown;
+ sal_uInt32 nCount;
+ if ( nLangList & SvxLanguageListFlags::ONLY_KNOWN )
+ {
+ aKnown = LocaleDataWrapper::getInstalledLanguageTypes();
+ nCount = aKnown.size();
+ }
+ else
+ {
+ nCount = SvtLanguageTable::GetLanguageEntryCount();
+ }
+
+ std::vector<weld::ComboBoxEntry> aEntries;
+ for ( sal_uInt32 i = 0; i < nCount; i++ )
+ {
+ LanguageType nLangType;
+ if ( nLangList & SvxLanguageListFlags::ONLY_KNOWN )
+ nLangType = aKnown[i];
+ else
+ nLangType = SvtLanguageTable::GetLanguageTypeAtIndex( i );
+ if ( lcl_isPrerequisite( nLangType, true ) &&
+ (lcl_isScriptTypeRequested( nLangType, nLangList) ||
+ (bool(nLangList & SvxLanguageListFlags::FBD_CHARS) &&
+ MsLangId::hasForbiddenCharacters(nLangType)) ||
+ (bool(nLangList & SvxLanguageListFlags::SPELL_USED) &&
+ lcl_SeqHasLang(aSpellUsedLang, static_cast<sal_uInt16>(nLangType)))
+ ) )
+ {
+ aEntries.push_back(BuildEntry(nLangType));
+ if (aEntries.back().sString.isEmpty())
+ aEntries.pop_back();
+ }
+ }
+
+ if (bAddAvailable)
+ {
+ // Spell checkers, hyphenators and thesauri may add language tags
+ // unknown so far.
+ AddLanguages(aAvailLang, nLangList, aEntries, true);
+ }
+
+ SortLanguages(aEntries);
+ m_xControl->insert_vector(aEntries, true);
+}
+
+void SvxLanguageBox::InsertLanguage(const LanguageType nLangType)
+{
+ if (find_id(nLangType) != -1)
+ return;
+ weld::ComboBoxEntry aEntry = BuildEntry(nLangType);
+ if (aEntry.sString.isEmpty())
+ return;
+ m_xControl->append(aEntry);
+}
+
+void SvxLanguageBox::InsertLanguages(const std::vector<LanguageType>& rLanguageTypes)
+{
+ std::vector<weld::ComboBoxEntry> entries;
+ AddLanguages(rLanguageTypes, SvxLanguageListFlags::ALL, entries, false);
+ SortLanguages(entries);
+ m_xControl->insert_vector(entries, true);
+}
+
+weld::ComboBoxEntry SvxLanguageBox::BuildEntry(const LanguageType nLangType, sal_Int16 nType)
+{
+ LanguageType nLang = MsLangId::getReplacementForObsoleteLanguage(nLangType);
+ // For obsolete and to be replaced languages check whether an entry of the
+ // replacement already exists and if so don't add an entry with identical
+ // string as would be returned by SvtLanguageTable::GetString().
+ if (nLang != nLangType)
+ {
+ int nAt = find_id( nLang );
+ if (nAt != -1)
+ return weld::ComboBoxEntry("");
+ }
+
+ OUString aStrEntry = (LANGUAGE_NONE == nLang && m_bHasLangNone && m_bLangNoneIsLangAll)
+ ? SvxResId(RID_SVXSTR_LANGUAGE_ALL)
+ : SvtLanguageTable::GetLanguageString(nLang);
+
+ LanguageType nRealLang = nLang;
+ if (nRealLang == LANGUAGE_SYSTEM)
+ {
+ nRealLang = MsLangId::resolveSystemLanguageByScriptType(nRealLang, nType);
+ aStrEntry += " - " + SvtLanguageTable::GetLanguageString( nRealLang );
+ }
+ else if (nRealLang == LANGUAGE_USER_SYSTEM_CONFIG)
+ {
+ nRealLang = MsLangId::getSystemLanguage();
+ // Whatever we obtained, ensure a known supported locale.
+ nRealLang = LanguageTag(nRealLang).makeFallback().getLanguageType();
+ aStrEntry += " - " + SvtLanguageTable::GetLanguageString( nRealLang );
+ }
+
+ if (m_bWithCheckmark)
+ {
+ if (!m_xSpellUsedLang)
+ {
+ Reference<XSpellChecker1> xSpell = LinguMgr::GetSpellChecker();
+ if (xSpell.is())
+ m_xSpellUsedLang.reset(new Sequence<sal_Int16>(xSpell->getLanguages()));
+ }
+
+ bool bFound = m_xSpellUsedLang && lcl_SeqHasLang(*m_xSpellUsedLang, static_cast<sal_uInt16>(nRealLang));
+
+ return weld::ComboBoxEntry(aStrEntry, OUString::number(static_cast<sal_uInt16>(nLang)), bFound ? RID_SVXBMP_CHECKED : RID_SVXBMP_NOTCHECKED);
+ }
+ else
+ return weld::ComboBoxEntry(aStrEntry, OUString::number(static_cast<sal_uInt16>(nLang)));
+}
+
+IMPL_LINK(SvxLanguageBox, ChangeHdl, weld::ComboBox&, rControl, void)
+{
+ if (rControl.has_entry())
+ {
+ EditedAndValid eOldState = m_eEditedAndValid;
+ OUString aStr(rControl.get_active_text());
+ if (aStr.isEmpty())
+ m_eEditedAndValid = EditedAndValid::Invalid;
+ else
+ {
+ const int nPos = rControl.find_text(aStr);
+ if (nPos != -1)
+ {
+ int nStartSelectPos, nEndSelectPos;
+ rControl.get_entry_selection_bounds(nStartSelectPos, nEndSelectPos);
+
+ // Select the corresponding listbox entry if not current. This
+ // invalidates the Edit Selection thus has to happen between
+ // obtaining the Selection and setting the new Selection.
+ int nSelPos = m_xControl->get_active();
+ bool bSetEditSelection;
+ if (nSelPos == nPos)
+ bSetEditSelection = false;
+ else
+ {
+ m_xControl->set_active(nPos);
+ bSetEditSelection = true;
+ }
+
+ // If typing into the Edit control led us here, advance start of a
+ // full selection by one so the next character will already
+ // continue the string instead of having to type the same character
+ // again to start a new string. The selection is in reverse
+ // when obtained from the Edit control.
+ if (nEndSelectPos == 0)
+ {
+ OUString aText(m_xControl->get_active_text());
+ if (nStartSelectPos == aText.getLength())
+ {
+ ++nEndSelectPos;
+ bSetEditSelection = true;
+ }
+ }
+
+ if (bSetEditSelection)
+ rControl.select_entry_region(nStartSelectPos, nEndSelectPos);
+
+ m_eEditedAndValid = EditedAndValid::No;
+ }
+ else
+ {
+ OUString aCanonicalized;
+ bool bValid = LanguageTag::isValidBcp47( aStr, &aCanonicalized, LanguageTag::PrivateUse::ALLOW_ART_X);
+ m_eEditedAndValid = (bValid ? EditedAndValid::Valid : EditedAndValid::Invalid);
+ if (bValid && aCanonicalized != aStr)
+ {
+ m_xControl->set_entry_text(aCanonicalized);
+ const auto nCursorPos = aCanonicalized.getLength();
+ m_xControl->select_entry_region(nCursorPos, nCursorPos);
+ }
+ }
+ }
+ if (eOldState != m_eEditedAndValid)
+ {
+ if (m_eEditedAndValid == EditedAndValid::Invalid)
+ rControl.set_entry_message_type(weld::EntryMessageType::Error);
+ else
+ rControl.set_entry_message_type(weld::EntryMessageType::Normal);
+ }
+ }
+ m_aChangeHdl.Call(rControl);
+}
+
+SvxLanguageBox::SvxLanguageBox(std::unique_ptr<weld::ComboBox> pControl)
+ : m_xControl(std::move(pControl))
+ , m_eSavedLanguage(LANGUAGE_DONTKNOW)
+ , m_eEditedAndValid(EditedAndValid::No)
+ , m_bHasLangNone(false)
+ , m_bLangNoneIsLangAll(false)
+ , m_bWithCheckmark(false)
+{
+ m_xControl->connect_changed(LINK(this, SvxLanguageBox, ChangeHdl));
+}
+
+SvxLanguageBox* SvxLanguageBox::SaveEditedAsEntry(SvxLanguageBox* ppBoxes[3])
+{
+ if (m_eEditedAndValid != EditedAndValid::Valid)
+ return this;
+
+ LanguageTag aLanguageTag(m_xControl->get_active_text());
+ LanguageType nLang = aLanguageTag.getLanguageType();
+ if (nLang == LANGUAGE_DONTKNOW)
+ {
+ SAL_WARN( "svx.dialog", "SvxLanguageBox::SaveEditedAsEntry: unknown tag");
+ return this;
+ }
+
+ for (size_t i = 0; i < 3; ++i)
+ {
+ SvxLanguageBox* pBox = ppBoxes[i];
+ if (!pBox)
+ continue;
+
+ const int nPos = pBox->find_id( nLang);
+ if (nPos != -1)
+ {
+ // Already present but with a different string or in another list.
+ pBox->m_xControl->set_active(nPos);
+ return pBox;
+ }
+ }
+
+ if (SvtLanguageTable::HasLanguageType( nLang))
+ {
+ // In SvtLanguageTable but not in SvxLanguageBox. On purpose? This
+ // may be an entry with different settings.
+ SAL_WARN( "svx.dialog", "SvxLanguageBox::SaveEditedAsEntry: already in SvtLanguageTable: " <<
+ SvtLanguageTable::GetLanguageString( nLang) << ", " << nLang);
+ }
+ else
+ {
+ // Add to SvtLanguageTable first. This at an on-the-fly LanguageTag
+ // also sets the ScriptType needed below.
+ SvtLanguageTable::AddLanguageTag( aLanguageTag );
+ }
+
+ // Add to the proper list.
+ SvxLanguageBox* pBox = nullptr;
+ switch (MsLangId::getScriptType(nLang))
+ {
+ default:
+ case css::i18n::ScriptType::LATIN:
+ pBox = ppBoxes[0];
+ break;
+ case css::i18n::ScriptType::ASIAN:
+ pBox = ppBoxes[1];
+ break;
+ case css::i18n::ScriptType::COMPLEX:
+ pBox = ppBoxes[2];
+ break;
+ }
+ if (!pBox)
+ pBox = this;
+ pBox->InsertLanguage(nLang);
+
+ // Select it.
+ const int nPos = pBox->find_id(nLang);
+ if (nPos != -1)
+ pBox->m_xControl->set_active(nPos);
+
+ return pBox;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/linkwarn.cxx b/svx/source/dialog/linkwarn.cxx
new file mode 100644
index 0000000000..852c92af10
--- /dev/null
+++ b/svx/source/dialog/linkwarn.cxx
@@ -0,0 +1,61 @@
+/* -*- 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/file.hxx>
+#include <svx/linkwarn.hxx>
+#include <officecfg/Office/Common.hxx>
+
+SvxLinkWarningDialog::SvxLinkWarningDialog(weld::Widget* pParent, const OUString& _rFileName)
+ : MessageDialogController(pParent, "svx/ui/linkwarndialog.ui", "LinkWarnDialog", "ask")
+ , m_xWarningOnBox(m_xBuilder->weld_check_button("ask"))
+{
+ // replace filename
+ OUString sInfoText = m_xDialog->get_primary_text();
+ OUString aPath;
+ if (osl::FileBase::E_None != osl::FileBase::getSystemPathFromFileURL(_rFileName, aPath))
+ aPath = _rFileName;
+ sInfoText = sInfoText.replaceAll("%FILENAME", aPath);
+ m_xDialog->set_primary_text(sInfoText);
+
+ // load state of "warning on" checkbox from misc options
+ m_xWarningOnBox->set_active(officecfg::Office::Common::Misc::ShowLinkWarningDialog::get());
+ m_xWarningOnBox->set_sensitive(
+ !officecfg::Office::Common::Misc::ShowLinkWarningDialog::isReadOnly());
+}
+
+SvxLinkWarningDialog::~SvxLinkWarningDialog()
+{
+ try
+ {
+ // save value of "warning off" checkbox, if necessary
+ bool bChecked = m_xWarningOnBox->get_active();
+ if (officecfg::Office::Common::Misc::ShowLinkWarningDialog::get() != bChecked)
+ {
+ std::shared_ptr<comphelper::ConfigurationChanges> xChanges(
+ comphelper::ConfigurationChanges::create());
+ officecfg::Office::Common::Misc::ShowLinkWarningDialog::set(bChecked, xChanges);
+ xChanges->commit();
+ }
+ }
+ catch (...)
+ {
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/measctrl.cxx b/svx/source/dialog/measctrl.cxx
new file mode 100644
index 0000000000..9539d2f68c
--- /dev/null
+++ b/svx/source/dialog/measctrl.cxx
@@ -0,0 +1,159 @@
+/* -*- 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 <sfx2/dialoghelper.hxx>
+#include <svx/svdomeas.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/measctrl.hxx>
+#include <svx/dlgutil.hxx>
+#include <vcl/event.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <memory>
+
+SvxXMeasurePreview::SvxXMeasurePreview()
+ : m_aMapMode(MapUnit::Map100thMM)
+{
+ // Scale: 1:2
+ m_aMapMode.SetScaleX(Fraction(1, 2));
+ m_aMapMode.SetScaleY(Fraction(1, 2));
+}
+
+void SvxXMeasurePreview::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ CustomWidgetController::SetDrawingArea(pDrawingArea);
+ Size aSize(getPreviewStripSize(pDrawingArea->get_ref_device()));
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+
+ pModel.reset(new SdrModel(nullptr, nullptr, true));
+ pMeasureObj = new SdrMeasureObj(*pModel, Point(), Point());
+
+ ResizeImpl(aSize);
+ Invalidate();
+}
+
+void SvxXMeasurePreview::ResizeImpl(const Size& rSize)
+{
+ OutputDevice& rRefDevice = GetDrawingArea()->get_ref_device();
+ rRefDevice.Push(vcl::PushFlags::MAPMODE);
+
+ rRefDevice.SetMapMode(m_aMapMode);
+
+ Size aSize = rRefDevice.PixelToLogic(rSize);
+ Point aPt1(aSize.Width() / 5, static_cast<tools::Long>(aSize.Height() / 2));
+ pMeasureObj->SetPoint(aPt1, 0);
+ Point aPt2(aSize.Width() * 4 / 5, static_cast<tools::Long>(aSize.Height() / 2));
+ pMeasureObj->SetPoint(aPt2, 1);
+
+ rRefDevice.Pop();
+}
+
+void SvxXMeasurePreview::Resize()
+{
+ CustomWidgetController::Resize();
+ ResizeImpl(GetOutputSizePixel());
+ Invalidate();
+}
+
+SvxXMeasurePreview::~SvxXMeasurePreview() {}
+
+void SvxXMeasurePreview::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ rRenderContext.SetBackground(rRenderContext.GetSettings().GetStyleSettings().GetWindowColor());
+ rRenderContext.Erase();
+
+ rRenderContext.Push(vcl::PushFlags::MAPMODE);
+ rRenderContext.SetMapMode(m_aMapMode);
+
+ bool bHighContrast = Application::GetSettings().GetStyleSettings().GetHighContrastMode();
+ rRenderContext.SetDrawMode(bHighContrast ? OUTPUT_DRAWMODE_CONTRAST : OUTPUT_DRAWMODE_COLOR);
+ pMeasureObj->SingleObjectPainter(rRenderContext);
+
+ rRenderContext.Pop();
+}
+
+void SvxXMeasurePreview::SetAttributes(const SfxItemSet& rInAttrs)
+{
+ pMeasureObj->SetMergedItemSetAndBroadcast(rInAttrs);
+
+ Invalidate();
+}
+
+bool SvxXMeasurePreview::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ bool bZoomIn = rMEvt.IsLeft() && !rMEvt.IsShift();
+ bool bZoomOut = rMEvt.IsRight() || rMEvt.IsShift();
+ bool bCtrl = rMEvt.IsMod1();
+
+ if (bZoomIn || bZoomOut)
+ {
+ Fraction aXFrac = m_aMapMode.GetScaleX();
+ Fraction aYFrac = m_aMapMode.GetScaleY();
+ std::unique_ptr<Fraction> pMultFrac;
+
+ if (bZoomIn)
+ {
+ if (bCtrl)
+ pMultFrac.reset(new Fraction(3, 2));
+ else
+ pMultFrac.reset(new Fraction(11, 10));
+ }
+ else
+ {
+ if (bCtrl)
+ pMultFrac.reset(new Fraction(2, 3));
+ else
+ pMultFrac.reset(new Fraction(10, 11));
+ }
+
+ aXFrac *= *pMultFrac;
+ aYFrac *= *pMultFrac;
+
+ if (double(aXFrac) > 0.001 && double(aXFrac) < 1000.0 && double(aYFrac) > 0.001
+ && double(aYFrac) < 1000.0)
+ {
+ m_aMapMode.SetScaleX(aXFrac);
+ m_aMapMode.SetScaleY(aYFrac);
+
+ OutputDevice& rRefDevice = GetDrawingArea()->get_ref_device();
+ rRefDevice.Push(vcl::PushFlags::MAPMODE);
+ rRefDevice.SetMapMode(m_aMapMode);
+ Size aOutSize(rRefDevice.PixelToLogic(GetOutputSizePixel()));
+ rRefDevice.Pop();
+
+ Point aPt(m_aMapMode.GetOrigin());
+ tools::Long nX = tools::Long(
+ (double(aOutSize.Width()) - (double(aOutSize.Width()) * double(*pMultFrac))) / 2.0
+ + 0.5);
+ tools::Long nY = tools::Long(
+ (double(aOutSize.Height()) - (double(aOutSize.Height()) * double(*pMultFrac))) / 2.0
+ + 0.5);
+ aPt.AdjustX(nX);
+ aPt.AdjustY(nY);
+
+ m_aMapMode.SetOrigin(aPt);
+
+ Invalidate();
+ }
+ }
+
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/optgrid.cxx b/svx/source/dialog/optgrid.cxx
new file mode 100644
index 0000000000..2226eaa4e2
--- /dev/null
+++ b/svx/source/dialog/optgrid.cxx
@@ -0,0 +1,472 @@
+/* -*- 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 <svl/intitem.hxx>
+#include <svtools/unitconv.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <unotools/syslocale.hxx>
+#include <officecfg/Office/Writer.hxx>
+#include <officecfg/Office/WriterWeb.hxx>
+#include <officecfg/Office/Impress.hxx>
+#include <officecfg/Office/Draw.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <vcl/commandinfoprovider.hxx>
+
+#include <svx/svxids.hrc>
+#include <svx/optgrid.hxx>
+#include <svx/dlgutil.hxx>
+
+// local functions
+static void lcl_GetMinMax(weld::MetricSpinButton const& rField, sal_Int64& nMin, sal_Int64& nMax)
+{
+ rField.get_range(nMin, nMax, FieldUnit::TWIP);
+ nMin = rField.denormalize(nMin);
+ nMax = rField.denormalize(nMax);
+}
+
+static void lcl_SetMinMax(weld::MetricSpinButton& rField, sal_Int64 nMin, sal_Int64 nMax)
+{
+ rField.set_range(rField.normalize(nMin), rField.normalize(nMax), FieldUnit::TWIP);
+}
+
+static bool lcl_IsMetricSystem()
+{
+ SvtSysLocale aSysLocale;
+ MeasurementSystem eSys = aSysLocale.GetLocaleData().getMeasurementSystemEnum();
+
+ return (eSys == MeasurementSystem::Metric);
+}
+
+SvxOptionsGrid::SvxOptionsGrid() :
+ nFldDrawX ( 100 ),
+ nFldDivisionX ( 0 ),
+ nFldDrawY ( 100 ),
+ nFldDivisionY ( 0 ),
+ bUseGridsnap ( false ),
+ bSynchronize ( true ),
+ bGridVisible ( false ),
+ bEqualGrid ( true )
+{
+}
+
+SvxGridItem* SvxGridItem::Clone( SfxItemPool* ) const
+{
+ return new SvxGridItem( *this );
+}
+
+bool SvxGridItem::operator==( const SfxPoolItem& rAttr ) const
+{
+ assert(SfxPoolItem::operator==(rAttr));
+
+ const SvxGridItem& rItem = static_cast<const SvxGridItem&>(rAttr);
+
+ return ( bUseGridsnap == rItem.bUseGridsnap &&
+ bSynchronize == rItem.bSynchronize &&
+ bGridVisible == rItem.bGridVisible &&
+ bEqualGrid == rItem.bEqualGrid &&
+ nFldDrawX == rItem.nFldDrawX &&
+ nFldDivisionX== rItem.nFldDivisionX&&
+ nFldDrawY == rItem.nFldDrawY &&
+ nFldDivisionY== rItem.nFldDivisionY );
+}
+
+bool SvxGridItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText, const IntlWrapper&
+) const
+{
+ rText = "SvxGridItem";
+ return true;
+}
+
+// TabPage Screen Settings
+SvxGridTabPage::SvxGridTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreSet)
+ : SfxTabPage(pPage, pController, "svx/ui/optgridpage.ui", "OptGridPage", &rCoreSet)
+ , bAttrModified(false)
+ , m_Emode(WRITER_MODE)
+ , m_xCbxUseGridsnap(m_xBuilder->weld_check_button("usegridsnap"))
+ , m_xCbxUseGridsnapImg(m_xBuilder->weld_widget("lockusegridsnap"))
+ , m_xCbxGridVisible(m_xBuilder->weld_check_button("gridvisible"))
+ , m_xCbxGridVisibleImg(m_xBuilder->weld_widget("lockgridvisible"))
+ , m_xMtrFldDrawX(m_xBuilder->weld_metric_spin_button("mtrflddrawx", FieldUnit::CM))
+ , m_xMtrFldDrawXImg(m_xBuilder->weld_widget("lockmtrflddrawx"))
+ , m_xMtrFldDrawY(m_xBuilder->weld_metric_spin_button("mtrflddrawy", FieldUnit::CM))
+ , m_xMtrFldDrawYImg(m_xBuilder->weld_widget("lockmtrflddrawy"))
+ , m_xNumFldDivisionX(m_xBuilder->weld_spin_button("numflddivisionx"))
+ , m_xNumFldDivisionXImg(m_xBuilder->weld_widget("locknumflddivisionx"))
+ , m_xNumFldDivisionY(m_xBuilder->weld_spin_button("numflddivisiony"))
+ , m_xNumFldDivisionYImg(m_xBuilder->weld_widget("locknumflddivisiony"))
+ , m_xCbxSynchronize(m_xBuilder->weld_check_button("synchronize"))
+ , m_xCbxSynchronizeImg(m_xBuilder->weld_widget("locksynchronize"))
+ , m_xSnapFrames(m_xBuilder->weld_widget("snapframes"))
+ , m_xCbxSnapHelplines(m_xBuilder->weld_check_button("snaphelplines"))
+ , m_xCbxSnapHelplinesImg(m_xBuilder->weld_widget("locksnaphelplines"))
+ , m_xCbxSnapBorder(m_xBuilder->weld_check_button("snapborder"))
+ , m_xCbxSnapBorderImg(m_xBuilder->weld_widget("locksnapborder"))
+ , m_xCbxSnapFrame(m_xBuilder->weld_check_button("snapframe"))
+ , m_xCbxSnapFrameImg(m_xBuilder->weld_widget("locksnapframe"))
+ , m_xCbxSnapPoints(m_xBuilder->weld_check_button("snappoints"))
+ , m_xCbxSnapPointsImg(m_xBuilder->weld_widget("locksnappoints"))
+ , m_xMtrFldSnapArea(m_xBuilder->weld_metric_spin_button("mtrfldsnaparea", FieldUnit::PIXEL))
+ , m_xMtrFldSnapAreaImg(m_xBuilder->weld_widget("lockmtrfldsnaparea"))
+ , m_xCbxOrtho(m_xBuilder->weld_check_button("ortho"))
+ , m_xCbxOrthoImg(m_xBuilder->weld_widget("lockortho"))
+ , m_xCbxBigOrtho(m_xBuilder->weld_check_button("bigortho"))
+ , m_xCbxBigOrthoImg(m_xBuilder->weld_widget("lockbigortho"))
+ , m_xCbxRotate(m_xBuilder->weld_check_button("rotate"))
+ , m_xCbxRotateImg(m_xBuilder->weld_widget("lockrotate"))
+ , m_xMtrFldAngle(m_xBuilder->weld_metric_spin_button("mtrfldangle", FieldUnit::DEGREE))
+ , m_xMtrFldBezAngle(m_xBuilder->weld_metric_spin_button("mtrfldbezangle", FieldUnit::DEGREE))
+ , m_xMtrFldBezAngleImg(m_xBuilder->weld_widget("lockmtrfldbezangle"))
+{
+ // This page requires exchange Support
+ SetExchangeSupport();
+
+ // Set Metrics
+ FieldUnit eFUnit = GetModuleFieldUnit( rCoreSet );
+ sal_Int64 nMin, nMax;
+
+ lcl_GetMinMax(*m_xMtrFldDrawX, nMin, nMax);
+ SetFieldUnit( *m_xMtrFldDrawX, eFUnit, true );
+ lcl_SetMinMax(*m_xMtrFldDrawX, nMin, nMax);
+
+ lcl_GetMinMax(*m_xMtrFldDrawY, nMin, nMax);
+ SetFieldUnit( *m_xMtrFldDrawY, eFUnit, true );
+ lcl_SetMinMax(*m_xMtrFldDrawY, nMin, nMax);
+
+ if (const SfxUInt16Item* pItem = rCoreSet.GetItemIfSet(SID_HTML_MODE, false))
+ {
+ if (0 != (pItem->GetValue() & HTMLMODE_ON))
+ m_Emode = HTML_MODE;
+ }
+
+ if (m_Emode != HTML_MODE)
+ {
+ SfxViewFrame* pCurrent = SfxViewFrame::Current();
+ OUString aModuleName = vcl::CommandInfoProvider::GetModuleIdentifier(pCurrent->GetFrame().GetFrameInterface());
+ std::u16string_view sModulename = aModuleName.subView(aModuleName.lastIndexOf('.') + 1);
+ if (sModulename.starts_with(u"Text"))
+ m_Emode = WRITER_MODE;
+ else if (sModulename.starts_with(u"Spreadsheet"))
+ m_Emode = CALC_MODE;
+ else if (sModulename.starts_with(u"Presentation"))
+ m_Emode = IMPRESS_MODE;
+ else if (sModulename.starts_with(u"Drawing"))
+ m_Emode = DRAW_MODE;
+ }
+
+ m_xCbxRotate->connect_toggled(LINK(this, SvxGridTabPage, ClickRotateHdl_Impl));
+ Link<weld::Toggleable&,void> aLink = LINK(this, SvxGridTabPage, ChangeGridsnapHdl_Impl);
+ m_xCbxUseGridsnap->connect_toggled(aLink);
+ m_xCbxSynchronize->connect_toggled(aLink);
+ m_xCbxGridVisible->connect_toggled(aLink);
+ m_xMtrFldDrawX->connect_value_changed(
+ LINK( this, SvxGridTabPage, ChangeDrawHdl_Impl ) );
+ m_xMtrFldDrawY->connect_value_changed(
+ LINK( this, SvxGridTabPage, ChangeDrawHdl_Impl ) );
+ m_xNumFldDivisionX->connect_value_changed(
+ LINK( this, SvxGridTabPage, ChangeDivisionHdl_Impl ) );
+ m_xNumFldDivisionY->connect_value_changed(
+ LINK( this, SvxGridTabPage, ChangeDivisionHdl_Impl ) );
+}
+
+SvxGridTabPage::~SvxGridTabPage()
+{
+}
+
+std::unique_ptr<SfxTabPage> SvxGridTabPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rAttrSet)
+{
+ return std::make_unique<SvxGridTabPage>(pPage, pController, rAttrSet);
+}
+
+OUString SvxGridTabPage::GetAllStrings()
+{
+ OUString sAllStrings;
+ OUString labels[]
+ = { "label1", "label2", "flddrawx", "flddrawy", "label6", "label7", "label3",
+ "divisionx", "label4", "divisiony", "label5", "label8", "label9" };
+
+ for (const auto& label : labels)
+ {
+ if (const auto& pString = m_xBuilder->weld_label(label))
+ sAllStrings += pString->get_label() + " ";
+ }
+
+ OUString checkButton[]
+ = { "usegridsnap", "gridvisible", "synchronize", "snaphelplines", "snapborder",
+ "snapframe", "snappoints", "ortho", "bigortho", "rotate" };
+
+ for (const auto& check : checkButton)
+ {
+ if (const auto& pString = m_xBuilder->weld_check_button(check))
+ sAllStrings += pString->get_label() + " ";
+ }
+
+ return sAllStrings.replaceAll("_", "");
+}
+
+bool SvxGridTabPage::FillItemSet( SfxItemSet* rCoreSet )
+{
+ if ( bAttrModified )
+ {
+ SvxGridItem aGridItem( SID_ATTR_GRID_OPTIONS );
+
+ aGridItem.bUseGridsnap = m_xCbxUseGridsnap->get_active();
+ aGridItem.bSynchronize = m_xCbxSynchronize->get_active();
+ aGridItem.bGridVisible = m_xCbxGridVisible->get_active();
+
+ MapUnit eUnit = rCoreSet->GetPool()->GetMetric( SID_ATTR_GRID_OPTIONS );
+ tools::Long nX = GetCoreValue( *m_xMtrFldDrawX, eUnit );
+ tools::Long nY = GetCoreValue( *m_xMtrFldDrawY, eUnit );
+
+ aGridItem.nFldDrawX = static_cast<sal_uInt32>(nX);
+ aGridItem.nFldDrawY = static_cast<sal_uInt32>(nY);
+ aGridItem.nFldDivisionX = static_cast<tools::Long>(m_xNumFldDivisionX->get_value() - 1);
+ aGridItem.nFldDivisionY = static_cast<tools::Long>(m_xNumFldDivisionY->get_value() - 1);
+
+ rCoreSet->Put( aGridItem );
+ }
+ return bAttrModified;
+}
+
+void SvxGridTabPage::Reset( const SfxItemSet* rSet )
+{
+ const SvxGridItem* pGridAttr = nullptr;
+
+ if( (pGridAttr = rSet->GetItemIfSet( SID_ATTR_GRID_OPTIONS , false )) )
+ {
+ bool bReadOnly = false;
+ switch (m_Emode)
+ {
+ case WRITER_MODE: bReadOnly = officecfg::Office::Writer::Grid::Option::SnapToGrid::isReadOnly(); break;
+ case HTML_MODE: bReadOnly = officecfg::Office::WriterWeb::Grid::Option::SnapToGrid::isReadOnly(); break;
+ case IMPRESS_MODE: bReadOnly = officecfg::Office::Impress::Grid::Option::SnapToGrid::isReadOnly(); break;
+ case DRAW_MODE: bReadOnly = officecfg::Office::Draw::Grid::Option::SnapToGrid::isReadOnly(); break;
+ default: //TODO Calc
+ break;
+ }
+ m_xCbxUseGridsnap->set_active(pGridAttr->bUseGridsnap);
+ m_xCbxUseGridsnap->set_sensitive(!bReadOnly);
+ m_xCbxUseGridsnapImg->set_visible(bReadOnly);
+
+ switch (m_Emode)
+ {
+ case WRITER_MODE: bReadOnly = officecfg::Office::Writer::Grid::Option::Synchronize::isReadOnly(); break;
+ case HTML_MODE: bReadOnly = officecfg::Office::WriterWeb::Grid::Option::Synchronize::isReadOnly(); break;
+ case IMPRESS_MODE: bReadOnly = officecfg::Office::Impress::Grid::Option::Synchronize::isReadOnly(); break;
+ case DRAW_MODE: bReadOnly = officecfg::Office::Draw::Grid::Option::Synchronize::isReadOnly(); break;
+ default: //TODO Calc
+ break;
+ }
+ m_xCbxSynchronize->set_active(pGridAttr->bSynchronize);
+ m_xCbxSynchronize->set_sensitive(!bReadOnly);
+ m_xCbxSynchronizeImg->set_visible(bReadOnly);
+
+ switch (m_Emode)
+ {
+ case WRITER_MODE: bReadOnly = officecfg::Office::Writer::Grid::Option::VisibleGrid::isReadOnly(); break;
+ case HTML_MODE: bReadOnly = officecfg::Office::WriterWeb::Grid::Option::VisibleGrid::isReadOnly(); break;
+ case IMPRESS_MODE: bReadOnly = officecfg::Office::Impress::Grid::Option::VisibleGrid::isReadOnly(); break;
+ case DRAW_MODE: bReadOnly = officecfg::Office::Draw::Grid::Option::VisibleGrid::isReadOnly(); break;
+ default: //TODO Calc
+ break;
+ }
+ m_xCbxGridVisible->set_active(pGridAttr->bGridVisible);
+ m_xCbxGridVisible->set_sensitive(!bReadOnly);
+ m_xCbxGridVisibleImg->set_visible(bReadOnly);
+
+ MapUnit eUnit = rSet->GetPool()->GetMetric( SID_ATTR_GRID_OPTIONS );
+ SetMetricValue( *m_xMtrFldDrawX , pGridAttr->nFldDrawX, eUnit );
+ SetMetricValue( *m_xMtrFldDrawY , pGridAttr->nFldDrawY, eUnit );
+
+ switch (m_Emode)
+ {
+ case WRITER_MODE: bReadOnly = officecfg::Office::Writer::Grid::Resolution::XAxis::isReadOnly(); break;
+ case HTML_MODE: bReadOnly = officecfg::Office::WriterWeb::Grid::Resolution::XAxis::isReadOnly(); break;
+ case IMPRESS_MODE:
+ {
+ if (lcl_IsMetricSystem())
+ bReadOnly = officecfg::Office::Impress::Grid::Resolution::XAxis::Metric::isReadOnly();
+ else
+ bReadOnly = officecfg::Office::Impress::Grid::Resolution::XAxis::NonMetric::isReadOnly();
+ }
+ break;
+ case DRAW_MODE:
+ {
+ if (lcl_IsMetricSystem())
+ bReadOnly = officecfg::Office::Draw::Grid::Resolution::XAxis::Metric::isReadOnly();
+ else
+ bReadOnly = officecfg::Office::Draw::Grid::Resolution::XAxis::NonMetric::isReadOnly();
+ }
+ break;
+ default: //TODO Calc
+ break;
+ }
+ m_xMtrFldDrawX->set_sensitive(!bReadOnly);
+ m_xMtrFldDrawXImg->set_visible(bReadOnly);
+
+ switch (m_Emode)
+ {
+ case WRITER_MODE: bReadOnly = officecfg::Office::Writer::Grid::Resolution::YAxis::isReadOnly(); break;
+ case HTML_MODE: bReadOnly = officecfg::Office::WriterWeb::Grid::Resolution::YAxis::isReadOnly(); break;
+ case IMPRESS_MODE:
+ {
+ if (lcl_IsMetricSystem())
+ bReadOnly = officecfg::Office::Impress::Grid::Resolution::YAxis::Metric::isReadOnly();
+ else
+ bReadOnly = officecfg::Office::Impress::Grid::Resolution::YAxis::NonMetric::isReadOnly();
+ }
+ break;
+ case DRAW_MODE:
+ {
+ if (lcl_IsMetricSystem())
+ bReadOnly = officecfg::Office::Draw::Grid::Resolution::YAxis::Metric::isReadOnly();
+ else
+ bReadOnly = officecfg::Office::Draw::Grid::Resolution::YAxis::NonMetric::isReadOnly();
+ }
+ break;
+ default: //TODO Calc
+ break;
+ }
+ m_xMtrFldDrawY->set_sensitive(!bReadOnly);
+ m_xMtrFldDrawYImg->set_visible(bReadOnly);
+
+ m_xNumFldDivisionX->set_value(pGridAttr->nFldDivisionX + 1);
+ m_xNumFldDivisionY->set_value(pGridAttr->nFldDivisionY + 1);
+
+ switch (m_Emode)
+ {
+ case WRITER_MODE: bReadOnly = officecfg::Office::Writer::Grid::Subdivision::XAxis::isReadOnly(); break;
+ case HTML_MODE: bReadOnly = officecfg::Office::WriterWeb::Grid::Subdivision::XAxis::isReadOnly(); break;
+ case IMPRESS_MODE: bReadOnly = officecfg::Office::Impress::Grid::Subdivision::XAxis::isReadOnly(); break;
+ case DRAW_MODE: bReadOnly = officecfg::Office::Draw::Grid::Subdivision::XAxis::isReadOnly(); break;
+ default: //TODO Calc
+ break;
+ }
+ m_xNumFldDivisionX->set_sensitive(!bReadOnly);
+ m_xNumFldDivisionXImg->set_visible(bReadOnly);
+
+ switch (m_Emode)
+ {
+ case WRITER_MODE: bReadOnly = officecfg::Office::Writer::Grid::Subdivision::YAxis::isReadOnly(); break;
+ case HTML_MODE: bReadOnly = officecfg::Office::WriterWeb::Grid::Subdivision::YAxis::isReadOnly(); break;
+ case IMPRESS_MODE: bReadOnly = officecfg::Office::Impress::Grid::Subdivision::YAxis::isReadOnly(); break;
+ case DRAW_MODE: bReadOnly = officecfg::Office::Draw::Grid::Subdivision::YAxis::isReadOnly(); break;
+ default: //TODO Calc
+ break;
+ }
+ m_xNumFldDivisionY->set_sensitive(!bReadOnly);
+ m_xNumFldDivisionYImg->set_visible(bReadOnly);
+ }
+
+ ChangeGridsnapHdl_Impl(*m_xCbxUseGridsnap);
+ bAttrModified = false;
+}
+
+void SvxGridTabPage::ActivatePage( const SfxItemSet& rSet )
+{
+ const SvxGridItem* pGridAttr = nullptr;
+ if( (pGridAttr = rSet.GetItemIfSet( SID_ATTR_GRID_OPTIONS , false )) )
+ {
+ m_xCbxUseGridsnap->set_active(pGridAttr->bUseGridsnap);
+
+ ChangeGridsnapHdl_Impl(*m_xCbxUseGridsnap);
+ }
+
+ // Metric Change if necessary (as TabPage is in the dialog, where the
+ // metric can be set
+ const SfxUInt16Item* pItem = rSet.GetItemIfSet( SID_ATTR_METRIC , false );
+ if( !pItem )
+ return;
+
+
+ FieldUnit eFUnit = static_cast<FieldUnit>(static_cast<tools::Long>(pItem->GetValue()));
+
+ if (eFUnit == m_xMtrFldDrawX->get_unit())
+ return;
+
+ // Set Metrics
+ sal_Int64 nMin, nMax;
+ int nVal = m_xMtrFldDrawX->denormalize(m_xMtrFldDrawX->get_value(FieldUnit::TWIP));
+
+ lcl_GetMinMax(*m_xMtrFldDrawX, nMin, nMax);
+ SetFieldUnit(*m_xMtrFldDrawX, eFUnit, true);
+ lcl_SetMinMax(*m_xMtrFldDrawX, nMin, nMax);
+
+ m_xMtrFldDrawX->set_value(m_xMtrFldDrawX->normalize(nVal), FieldUnit::TWIP);
+
+ nVal = m_xMtrFldDrawY->denormalize(m_xMtrFldDrawY->get_value(FieldUnit::TWIP));
+ lcl_GetMinMax(*m_xMtrFldDrawY, nMin, nMax);
+ SetFieldUnit(*m_xMtrFldDrawY, eFUnit, true);
+ lcl_SetMinMax(*m_xMtrFldDrawY, nMin, nMax);
+ m_xMtrFldDrawY->set_value(m_xMtrFldDrawY->normalize(nVal), FieldUnit::TWIP);
+}
+
+DeactivateRC SvxGridTabPage::DeactivatePage( SfxItemSet* _pSet )
+{
+ if ( _pSet )
+ FillItemSet( _pSet );
+ return DeactivateRC::LeavePage;
+}
+
+IMPL_LINK(SvxGridTabPage, ChangeDrawHdl_Impl, weld::MetricSpinButton&, rField, void)
+{
+ bAttrModified = true;
+ if (m_xCbxSynchronize->get_active())
+ {
+ if (&rField == m_xMtrFldDrawX.get())
+ m_xMtrFldDrawY->set_value(m_xMtrFldDrawX->get_value(FieldUnit::NONE), FieldUnit::NONE);
+ else
+ m_xMtrFldDrawX->set_value(m_xMtrFldDrawY->get_value(FieldUnit::NONE), FieldUnit::NONE);
+ }
+}
+
+IMPL_LINK_NOARG(SvxGridTabPage, ClickRotateHdl_Impl, weld::Toggleable&, void)
+{
+ if (m_xCbxRotate->get_active())
+ {
+ m_xMtrFldAngle->set_sensitive(m_Emode == DRAW_MODE ?
+ !officecfg::Office::Draw::Snap::Position::RotatingValue::isReadOnly() :
+ !officecfg::Office::Impress::Snap::Position::RotatingValue::isReadOnly());
+ }
+ else
+ m_xMtrFldAngle->set_sensitive(false);
+}
+
+IMPL_LINK(SvxGridTabPage, ChangeDivisionHdl_Impl, weld::SpinButton&, rField, void)
+{
+ bAttrModified = true;
+ if (m_xCbxSynchronize->get_active())
+ {
+ if (m_xNumFldDivisionX.get() == &rField)
+ m_xNumFldDivisionY->set_value(m_xNumFldDivisionX->get_value());
+ else
+ m_xNumFldDivisionX->set_value(m_xNumFldDivisionY->get_value());
+ }
+}
+
+IMPL_LINK_NOARG(SvxGridTabPage, ChangeGridsnapHdl_Impl, weld::Toggleable&, void)
+{
+ bAttrModified = true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/page.hrc b/svx/source/dialog/page.hrc
new file mode 100644
index 0000000000..9252e2e68b
--- /dev/null
+++ b/svx/source/dialog/page.hrc
@@ -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 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_DIALOG_PAGE_HRC
+#define INCLUDED_SVX_SOURCE_DIALOG_PAGE_HRC
+
+#include <i18nutil/paper.hxx>
+#include <unotools/resmgr.hxx>
+#include <utility>
+
+#define NC_(Context, String) TranslateId(Context, u8##String)
+
+const std::pair<TranslateId, int> RID_SVXSTRARY_PAPERSIZE_STD[] =
+{
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "A6") , PAPER_A6 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "A5") , PAPER_A5 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "A4") , PAPER_A4 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "A3") , PAPER_A3 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "B6 (ISO)") , PAPER_B6_ISO },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "B5 (ISO)") , PAPER_B5_ISO },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "B4 (ISO)") , PAPER_B4_ISO },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "Letter") , PAPER_LETTER },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "Legal") , PAPER_LEGAL },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "Long Bond") , PAPER_FANFOLD_LEGAL_DE },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "Tabloid") , PAPER_TABLOID },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "B6 (JIS)") , PAPER_B6_JIS },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "B5 (JIS)") , PAPER_B5_JIS },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "B4 (JIS)") , PAPER_B4_JIS },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "16 Kai") , PAPER_KAI16},
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "32 Kai") , PAPER_KAI32},
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "Big 32 Kai") , PAPER_KAI32BIG},
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "User") , PAPER_USER },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "DL Envelope") , PAPER_ENV_DL },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "C6 Envelope") , PAPER_ENV_C6 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "C6/5 Envelope") , PAPER_ENV_C65 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "C5 Envelope") , PAPER_ENV_C5 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "C4 Envelope") , PAPER_ENV_C4 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "#6¾ Envelope") , PAPER_ENV_PERSONAL},
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "#7¾ (Monarch) Envelope") , PAPER_ENV_MONARCH},
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "#9 Envelope") , PAPER_ENV_9},
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "#10 Envelope") , PAPER_ENV_10},
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "#11 Envelope") , PAPER_ENV_11},
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "#12 Envelope") , PAPER_ENV_12},
+ { NC_("RID_SVXSTRARY_PAPERSIZE_STD", "Japanese Postcard") , PAPER_POSTCARD_JP}
+};
+
+const std::pair<TranslateId, int> RID_SVXSTRARY_PAPERSIZE_DRAW[] =
+{
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "A6") , PAPER_A6 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "A5") , PAPER_A5 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "A4") , PAPER_A4 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "A3") , PAPER_A3 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "A2") , PAPER_A2 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "A1") , PAPER_A1 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "A0") , PAPER_A0 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "B6 (ISO)") , PAPER_B6_ISO },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "B5 (ISO)") , PAPER_B5_ISO },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "B4 (ISO)") , PAPER_B4_ISO },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "Letter") , PAPER_LETTER },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "Legal") , PAPER_LEGAL },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "Long Bond") , PAPER_FANFOLD_LEGAL_DE },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "Tabloid") , PAPER_TABLOID },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "B6 (JIS)") , PAPER_B6_JIS },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "B5 (JIS)") , PAPER_B5_JIS },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "B4 (JIS)") , PAPER_B4_JIS },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "16 Kai") , PAPER_KAI16},
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "32 Kai") , PAPER_KAI32},
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "Big 32 Kai") , PAPER_KAI32BIG},
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "User") , PAPER_USER },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "DL Envelope") , PAPER_ENV_DL },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "C6 Envelope") , PAPER_ENV_C6 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "C6/5 Envelope") , PAPER_ENV_C65 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "C5 Envelope") , PAPER_ENV_C5 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "C4 Envelope") , PAPER_ENV_C4 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "Dia Slide") , PAPER_SLIDE_DIA },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "Screen 4:3") , PAPER_SCREEN_4_3 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "Screen 16:9") , PAPER_SCREEN_16_9 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "Screen 16:10") , PAPER_SCREEN_16_10 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "Widescreen") , PAPER_WIDESCREEN },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "On-screen Show (4:3)") , PAPER_ONSCREENSHOW_4_3 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "On-screen Show (16:9)") , PAPER_ONSCREENSHOW_16_9 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "On-screen Show (16:10)") , PAPER_ONSCREENSHOW_16_10 },
+ { NC_("RID_SVXSTRARY_PAPERSIZE_DRAW", "Japanese Postcard") , PAPER_POSTCARD_JP}
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/pagectrl.cxx b/svx/source/dialog/pagectrl.cxx
new file mode 100644
index 0000000000..fe44562ff2
--- /dev/null
+++ b/svx/source/dialog/pagectrl.cxx
@@ -0,0 +1,397 @@
+/* -*- 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 <editeng/frmdir.hxx>
+#include <vcl/canvastools.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/settings.hxx>
+#include <tools/fract.hxx>
+#include <svx/pageitem.hxx>
+#include <svx/pagectrl.hxx>
+#include <algorithm>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+#include <drawinglayer/processor2d/baseprocessor2d.hxx>
+#include <drawinglayer/primitive2d/PolygonHairlinePrimitive2D.hxx>
+#include <drawinglayer/processor2d/processor2dtools.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+
+#define CELL_WIDTH 1600L
+#define CELL_HEIGHT 800L
+
+SvxPageWindow::SvxPageWindow() :
+ nTop(0),
+ nBottom(0),
+ nLeft(0),
+ nRight(0),
+ bResetBackground(false),
+ bFrameDirection(false),
+ nFrameDirection(SvxFrameDirection::Horizontal_LR_TB),
+ nHdLeft(0),
+ nHdRight(0),
+ nHdDist(0),
+ nHdHeight(0),
+ nFtLeft(0),
+ nFtRight(0),
+ nFtDist(0),
+ nFtHeight(0),
+ bFooter(false),
+ bHeader(false),
+ bTable(false),
+ bHorz(false),
+ bVert(false),
+ eUsage(SvxPageUsage::All)
+{
+}
+
+SvxPageWindow::~SvxPageWindow()
+{
+}
+
+void SvxPageWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ rRenderContext.Push(vcl::PushFlags::MAPMODE);
+ rRenderContext.SetMapMode(MapMode(MapUnit::MapTwip));
+
+ Fraction aXScale(aWinSize.Width(), std::max(aSize.Width() * 2 + aSize.Width() / 8, tools::Long(1)));
+ Fraction aYScale(aWinSize.Height(), std::max(aSize.Height(), tools::Long(1)));
+ MapMode aMapMode(rRenderContext.GetMapMode());
+
+ if(aYScale < aXScale)
+ {
+ aMapMode.SetScaleX(aYScale);
+ aMapMode.SetScaleY(aYScale);
+ }
+ else
+ {
+ aMapMode.SetScaleX(aXScale);
+ aMapMode.SetScaleY(aXScale);
+ }
+ rRenderContext.SetMapMode(aMapMode);
+ Size aSz(rRenderContext.PixelToLogic(GetOutputSizePixel()));
+ tools::Long nYPos = (aSz.Height() - aSize.Height()) / 2;
+
+ if (eUsage == SvxPageUsage::All)
+ {
+ // all pages are equal -> draw one page
+ if (aSize.Width() > aSize.Height())
+ {
+ // Draw Landscape page of the same size
+ Fraction aX = aMapMode.GetScaleX();
+ Fraction aY = aMapMode.GetScaleY();
+ Fraction a2(1.5);
+ aX *= a2;
+ aY *= a2;
+ aMapMode.SetScaleX(aX);
+ aMapMode.SetScaleY(aY);
+ rRenderContext.SetMapMode(aMapMode);
+ aSz = rRenderContext.PixelToLogic(GetOutputSizePixel());
+ nYPos = (aSz.Height() - aSize.Height()) / 2;
+ tools::Long nXPos = (aSz.Width() - aSize.Width()) / 2;
+ DrawPage(rRenderContext, Point(nXPos,nYPos),true,true);
+ }
+ else
+ // Portrait
+ DrawPage(rRenderContext, Point((aSz.Width() - aSize.Width()) / 2,nYPos),true,true);
+ }
+ else
+ {
+ // Left and right page are different -> draw two pages if possible
+ DrawPage(rRenderContext, Point(0, nYPos), false,
+ eUsage == SvxPageUsage::Left || eUsage == SvxPageUsage::All || eUsage == SvxPageUsage::Mirror);
+ DrawPage(rRenderContext, Point(aSize.Width() + aSize.Width() / 8, nYPos), true,
+ eUsage == SvxPageUsage::Right || eUsage == SvxPageUsage::All || eUsage == SvxPageUsage::Mirror);
+ }
+ rRenderContext.Pop();
+}
+
+void SvxPageWindow::DrawPage(vcl::RenderContext& rRenderContext, const Point& rOrg, const bool bSecond, const bool bEnabled)
+{
+ const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
+ const Color& rFieldColor = rStyleSettings.GetFieldColor();
+ const Color& rFieldTextColor = rStyleSettings.GetFieldTextColor();
+ const Color& rDisableColor = rStyleSettings.GetDisableColor();
+ const Color& rDlgColor = rStyleSettings.GetDialogColor();
+
+ // background
+ if (!bSecond || bResetBackground)
+ {
+ rRenderContext.SetLineColor(COL_TRANSPARENT);
+ rRenderContext.SetFillColor(rDlgColor);
+ Size winSize(rRenderContext.GetOutputSize());
+ rRenderContext.DrawRect(tools::Rectangle(Point(0,0), winSize));
+
+ if (bResetBackground)
+ bResetBackground = false;
+ }
+ rRenderContext.SetLineColor(rFieldTextColor);
+
+ // Shadow
+ Size aTempSize = aSize;
+
+ // Page
+ if (!bEnabled)
+ {
+ rRenderContext.SetFillColor(rDisableColor);
+ rRenderContext.DrawRect(tools::Rectangle(rOrg, aTempSize));
+ return;
+ }
+ rRenderContext.SetFillColor(rFieldColor);
+ rRenderContext.DrawRect(tools::Rectangle(rOrg, aTempSize));
+
+ tools::Long nL = nLeft;
+ tools::Long nR = nRight;
+
+ if (eUsage == SvxPageUsage::Mirror && !bSecond)
+ {
+ // turn for mirrored
+ nL = nRight;
+ nR = nLeft;
+ }
+
+ tools::Rectangle aRect;
+
+ aRect.SetLeft( rOrg.X() + nL );
+ aRect.SetRight( rOrg.X() + aTempSize.Width() - nR );
+ aRect.SetTop( rOrg.Y() + nTop );
+ aRect.SetBottom( rOrg.Y() + aTempSize.Height() - nBottom );
+
+ tools::Rectangle aHdRect(aRect);
+ tools::Rectangle aFtRect(aRect);
+
+ if (bHeader || bFooter)
+ {
+ // Header and/or footer used
+ const Color aLineColor(rRenderContext.GetLineColor());
+
+ // draw PageFill first and on the whole page, no outline
+ rRenderContext.SetLineColor();
+ drawFillAttributes(rRenderContext, maPageFillAttributes, aRect, aRect);
+ rRenderContext.SetLineColor(aLineColor);
+
+ if (bHeader)
+ {
+ // show headers if possible
+ aHdRect.AdjustLeft(nHdLeft );
+ aHdRect.AdjustRight( -nHdRight );
+ aHdRect.SetBottom( aRect.Top() + nHdHeight );
+ aRect.AdjustTop(nHdHeight + nHdDist );
+
+ // draw header over PageFill, plus outline
+ drawFillAttributes(rRenderContext, maHeaderFillAttributes, aHdRect, aHdRect);
+ }
+
+ if (bFooter)
+ {
+ // show footer if possible
+ aFtRect.AdjustLeft(nFtLeft );
+ aFtRect.AdjustRight( -nFtRight );
+ aFtRect.SetTop( aRect.Bottom() - nFtHeight );
+ aRect.AdjustBottom( -(nFtHeight + nFtDist) );
+
+ // draw footer over PageFill, plus outline
+ drawFillAttributes(rRenderContext, maFooterFillAttributes, aFtRect, aFtRect);
+ }
+
+ // draw page's reduced outline, only outline
+ drawFillAttributes(rRenderContext, drawinglayer::attribute::SdrAllFillAttributesHelperPtr(), aRect, aRect);
+ }
+ else
+ {
+ // draw PageFill and outline
+ drawFillAttributes(rRenderContext, maPageFillAttributes, aRect, aRect);
+ }
+
+ if (bFrameDirection && !bTable)
+ {
+ Point aPos;
+ vcl::Font aFont(rRenderContext.GetFont());
+ const Size aSaveSize = aFont.GetFontSize();
+ Size aDrawSize(0,aRect.GetHeight() / 6);
+ aFont.SetFontSize(aDrawSize);
+ rRenderContext.SetFont(aFont);
+ OUString sText("ABC");
+ Point aMove(1, rRenderContext.GetTextHeight());
+ sal_Unicode cArrow = 0x2193;
+ tools::Long nAWidth = rRenderContext.GetTextWidth(sText.copy(0,1));
+ switch (nFrameDirection)
+ {
+ case SvxFrameDirection::Horizontal_LR_TB:
+ aPos = aRect.TopLeft();
+ aPos.AdjustX(rRenderContext.PixelToLogic(Point(1,1)).X() );
+ aMove.setY( 0 );
+ cArrow = 0x2192;
+ break;
+ case SvxFrameDirection::Horizontal_RL_TB:
+ aPos = aRect.TopRight();
+ aPos.AdjustX( -nAWidth );
+ aMove.setY( 0 );
+ aMove.setX( aMove.X() * -1 );
+ cArrow = 0x2190;
+ break;
+ case SvxFrameDirection::Vertical_LR_TB:
+ aPos = aRect.TopLeft();
+ aPos.AdjustX(rRenderContext.PixelToLogic(Point(1,1)).X() );
+ aMove.setX( 0 );
+ break;
+ case SvxFrameDirection::Vertical_RL_TB:
+ aPos = aRect.TopRight();
+ aPos.AdjustX( -nAWidth );
+ aMove.setX( 0 );
+ break;
+ default: break;
+ }
+ sText += OUStringChar(cArrow);
+ for (sal_Int32 i = 0; i < sText.getLength(); i++)
+ {
+ OUString sDraw(sText.copy(i,1));
+ tools::Long nHDiff = 0;
+ tools::Long nCharWidth = rRenderContext.GetTextWidth(sDraw);
+ bool bHorizontal = 0 == aMove.Y();
+ if (!bHorizontal)
+ {
+ nHDiff = (nAWidth - nCharWidth) / 2;
+ aPos.AdjustX(nHDiff );
+ }
+ rRenderContext.DrawText(aPos,sDraw);
+ if (bHorizontal)
+ {
+ aPos.AdjustX(aMove.X() < 0 ? -nCharWidth : nCharWidth );
+ }
+ else
+ {
+ aPos.AdjustX( -nHDiff );
+ aPos.AdjustY(aMove.Y() );
+ }
+ }
+ aFont.SetFontSize(aSaveSize);
+ rRenderContext.SetFont(aFont);
+
+ }
+ if (!bTable)
+ return;
+
+ // Paint Table, if necessary center it
+ rRenderContext.SetLineColor(COL_LIGHTGRAY);
+
+ tools::Long nW = aRect.GetWidth();
+ tools::Long nH = aRect.GetHeight();
+ tools::Long const nTW = CELL_WIDTH * 3;
+ tools::Long const nTH = CELL_HEIGHT * 3;
+ tools::Long _nLeft = bHorz ? aRect.Left() + ((nW - nTW) / 2) : aRect.Left();
+ tools::Long _nTop = bVert ? aRect.Top() + ((nH - nTH) / 2) : aRect.Top();
+ tools::Rectangle aCellRect(Point(_nLeft, _nTop),Size(CELL_WIDTH, CELL_HEIGHT));
+
+ for (sal_uInt16 i = 0; i < 3; ++i)
+ {
+ aCellRect.SetLeft( _nLeft );
+ aCellRect.SetRight( _nLeft + CELL_WIDTH );
+ if(i > 0)
+ aCellRect.Move(0,CELL_HEIGHT);
+
+ for (sal_uInt16 j = 0; j < 3; ++j)
+ {
+ if (j > 0)
+ aCellRect.Move(CELL_WIDTH,0);
+ rRenderContext.DrawRect(aCellRect);
+ }
+ }
+}
+
+void SvxPageWindow::drawFillAttributes(vcl::RenderContext& rRenderContext,
+ const drawinglayer::attribute::SdrAllFillAttributesHelperPtr& rFillAttributes,
+ const tools::Rectangle& rPaintRange,
+ const tools::Rectangle& rDefineRange)
+{
+ const basegfx::B2DRange aPaintRange = vcl::unotools::b2DRectangleFromRectangle(rPaintRange);
+
+ if(aPaintRange.isEmpty() ||
+ basegfx::fTools::equalZero(aPaintRange.getWidth()) ||
+ basegfx::fTools::equalZero(aPaintRange.getHeight()))
+ return;
+
+ const basegfx::B2DRange aDefineRange = vcl::unotools::b2DRectangleFromRectangle(rDefineRange);
+
+ // prepare primitive sequence
+ drawinglayer::primitive2d::Primitive2DContainer aSequence;
+
+ // create fill geometry if there is something to fill
+ if (rFillAttributes && rFillAttributes->isUsed())
+ {
+ aSequence = rFillAttributes->getPrimitive2DSequence(aPaintRange, aDefineRange);
+ }
+
+ // create line geometry if a LineColor is set at the target device
+ if (rRenderContext.IsLineColor())
+ {
+ const drawinglayer::primitive2d::Primitive2DReference xOutline(
+ new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
+ basegfx::utils::createPolygonFromRect(aPaintRange), rRenderContext.GetLineColor().getBColor()));
+
+ aSequence.push_back(xOutline);
+ }
+
+ // draw that if we have something to draw
+ if (aSequence.empty())
+ return;
+
+ drawinglayer::geometry::ViewInformation2D aViewInformation2D;
+ aViewInformation2D.setViewTransformation(rRenderContext.GetViewTransformation());
+ aViewInformation2D.setViewport(aPaintRange);
+
+ std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor(
+ drawinglayer::processor2d::createProcessor2DFromOutputDevice(rRenderContext, aViewInformation2D));
+ pProcessor->process(aSequence);
+}
+
+void SvxPageWindow::EnableFrameDirection(bool bEnable)
+{
+ bFrameDirection = bEnable;
+}
+
+void SvxPageWindow::SetFrameDirection(SvxFrameDirection nDirection)
+{
+ nFrameDirection = nDirection;
+}
+
+void SvxPageWindow::ResetBackground()
+{
+ bResetBackground = true;
+}
+
+void SvxPageWindow::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ CustomWidgetController::SetDrawingArea(pDrawingArea);
+
+ OutputDevice& rRefDevice = pDrawingArea->get_ref_device();
+ // Count in Twips by default
+ rRefDevice.Push(vcl::PushFlags::MAPMODE);
+ rRefDevice.SetMapMode(MapMode(MapUnit::MapTwip));
+ aWinSize = rRefDevice.LogicToPixel(Size(75, 46), MapMode(MapUnit::MapAppFont));
+ pDrawingArea->set_size_request(aWinSize.Width(), aWinSize.Height());
+
+ aWinSize.AdjustHeight( -4 );
+ aWinSize.AdjustWidth( -4 );
+
+ aWinSize = rRefDevice.PixelToLogic(aWinSize);
+ rRefDevice.Pop();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/pagenumberlistbox.cxx b/svx/source/dialog/pagenumberlistbox.cxx
new file mode 100644
index 0000000000..076da12e12
--- /dev/null
+++ b/svx/source/dialog/pagenumberlistbox.cxx
@@ -0,0 +1,52 @@
+/* -*- 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 <svx/dialmgr.hxx>
+#include <svx/pagenumberlistbox.hxx>
+#include <editeng/numitem.hxx>
+#include <com/sun/star/style/NumberingType.hpp>
+#include <numberingtype.hrc>
+
+SvxPageNumberListBox::SvxPageNumberListBox(std::unique_ptr<weld::ComboBox> pControl)
+ : m_xControl(std::move(pControl))
+{
+ m_xControl->set_size_request(150, -1);
+
+ for (size_t i = 0; i < SAL_N_ELEMENTS(RID_SVXSTRARY_NUMBERINGTYPE); ++i)
+ {
+ sal_uInt16 nData = RID_SVXSTRARY_NUMBERINGTYPE[i].second;
+ switch (nData)
+ {
+ // String list array is also used in Writer and contains strings
+ // for Bullet and Graphics, ignore those here.
+ case css::style::NumberingType::CHAR_SPECIAL:
+ case css::style::NumberingType::BITMAP:
+ case css::style::NumberingType::BITMAP | LINK_TOKEN:
+ break;
+ default:
+ {
+ OUString aStr = SvxResId(RID_SVXSTRARY_NUMBERINGTYPE[i].first);
+ m_xControl->append(OUString::number(nData), aStr);
+ break;
+ }
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/papersizelistbox.cxx b/svx/source/dialog/papersizelistbox.cxx
new file mode 100644
index 0000000000..fc0211a8ba
--- /dev/null
+++ b/svx/source/dialog/papersizelistbox.cxx
@@ -0,0 +1,74 @@
+/* -*- 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 <svx/dialmgr.hxx>
+#include <svx/papersizelistbox.hxx>
+#include "page.hrc"
+
+SvxPaperSizeListBox::SvxPaperSizeListBox(std::unique_ptr<weld::ComboBox> pControl)
+ : m_xControl(std::move(pControl))
+{
+ m_xControl->set_size_request(150, -1);
+}
+
+void SvxPaperSizeListBox::FillPaperSizeEntries( PaperSizeApp eApp )
+{
+ const std::pair<TranslateId, int>* pPaperAry = eApp == PaperSizeApp::Std ?
+ RID_SVXSTRARY_PAPERSIZE_STD : RID_SVXSTRARY_PAPERSIZE_DRAW;
+ sal_uInt32 nCnt = eApp == PaperSizeApp::Std ?
+ SAL_N_ELEMENTS(RID_SVXSTRARY_PAPERSIZE_STD) : SAL_N_ELEMENTS(RID_SVXSTRARY_PAPERSIZE_DRAW);
+
+ for ( sal_uInt32 i = 0; i < nCnt; ++i )
+ {
+ OUString aStr = SvxResId(pPaperAry[i].first);
+ Paper eSize = static_cast<Paper>(pPaperAry[i].second);
+ m_xControl->append(OUString::number(static_cast<sal_Int32>(eSize)), aStr);
+ }
+}
+
+void SvxPaperSizeListBox::set_active_id( Paper ePreselectPaper )
+{
+ int nEntryCount = m_xControl->get_count();
+ int nSelPos = -1;
+ int nUserPos = -1;
+
+ for (int i = 0; i < nEntryCount; ++i)
+ {
+ Paper eTmp = static_cast<Paper>(m_xControl->get_id(i).toInt32());
+ if (eTmp == ePreselectPaper)
+ {
+ nSelPos = i;
+ break;
+ }
+
+ if (eTmp == PAPER_USER)
+ nUserPos = i;
+ }
+
+ // preselect current paper format - #115915#: ePaper might not be in aPaperSizeBox so use PAPER_USER instead
+ m_xControl->set_active((nSelPos != -1) ? nSelPos : nUserPos);
+}
+
+Paper SvxPaperSizeListBox::get_active_id() const
+{
+ return static_cast<Paper>(m_xControl->get_active_id().toInt32());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+
diff --git a/svx/source/dialog/paraprev.cxx b/svx/source/dialog/paraprev.cxx
new file mode 100644
index 0000000000..27dccbfd9f
--- /dev/null
+++ b/svx/source/dialog/paraprev.cxx
@@ -0,0 +1,214 @@
+/* -*- 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 <sfx2/dialoghelper.hxx>
+#include <svx/paraprev.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/settings.hxx>
+
+SvxParaPrevWindow::SvxParaPrevWindow() :
+ nLeftMargin ( 0 ),
+ nRightMargin ( 0 ),
+ nFirstLineOffset ( 0 ),
+ nUpper ( 0 ),
+ nLower ( 0 ),
+ eAdjust ( SvxAdjust::Left ),
+ eLastLine ( SvxAdjust::Left ),
+ eLine ( SvxPrevLineSpace::N1 )
+{
+ aSize = Size(11905, 16837);
+}
+
+void SvxParaPrevWindow::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ CustomWidgetController::SetDrawingArea(pDrawingArea);
+ Size aOptimalSize(getParagraphPreviewOptimalSize(pDrawingArea->get_ref_device()));
+ pDrawingArea->set_size_request(aOptimalSize.Width(), aOptimalSize.Height());
+}
+
+void SvxParaPrevWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ DrawParagraph(rRenderContext);
+}
+
+#define DEF_MARGIN 120
+
+void SvxParaPrevWindow::DrawParagraph(vcl::RenderContext& rRenderContext)
+{
+ // Count in Twips by default
+ rRenderContext.Push(vcl::PushFlags::MAPMODE);
+ rRenderContext.SetMapMode(MapMode(MapUnit::MapTwip));
+
+ Size aWinSize(GetOutputSizePixel());
+ aWinSize = rRenderContext.PixelToLogic(aWinSize);
+ Size aTmp(1, 1);
+ aTmp = rRenderContext.PixelToLogic(aTmp);
+ aWinSize.AdjustWidth( -(aTmp.Width() /2) );
+ aWinSize.AdjustHeight( -(aTmp.Height() /2) );
+
+ const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
+ const Color& rWinColor = rStyleSettings.GetWindowColor();
+ Color aGrayColor(COL_LIGHTGRAY);
+
+ rRenderContext.SetFillColor(rWinColor);
+ rRenderContext.DrawRect(tools::Rectangle(Point(), aWinSize));
+
+ rRenderContext.SetLineColor();
+
+ tools::Long nH = aWinSize.Height() / 19;
+ Size aLineSiz(aWinSize.Width() - DEF_MARGIN, nH);
+ Size aSiz = aLineSiz;
+ Point aPnt;
+ aPnt.setX( DEF_MARGIN / 2 );
+ rRenderContext.SetFillColor(aGrayColor);
+
+ for (sal_uInt16 i = 0; i < 9; ++i)
+ {
+ if (i == 3)
+ {
+ rRenderContext.SetFillColor(COL_GRAY);
+ auto nTop = nUpper * aLineSiz.Height() / aSize.Height();
+ aPnt.AdjustY(nTop * 2 );
+ }
+
+ if (i == 6 )
+ rRenderContext.SetFillColor(aGrayColor);
+
+ if (3 <= i && 6 > i)
+ {
+ tools::Long nLeft = nLeftMargin * aLineSiz.Width() / aSize.Width();
+ tools::Long nFirst = nFirstLineOffset * aLineSiz.Width() / aSize.Width();
+ tools::Long nTmp = nLeft + nFirst;
+
+ if (i == 3)
+ {
+ aPnt.AdjustX(nTmp );
+ aSiz.AdjustWidth( -nTmp );
+ }
+ else
+ {
+ aPnt.AdjustX(nLeft );
+ aSiz.AdjustWidth( -nLeft );
+ }
+ tools::Long nRight = nRightMargin * aLineSiz.Width() / aSize.Width();
+ aSiz.AdjustWidth( -nRight );
+ }
+
+ if (4 == i || 5 == i || 6 == i)
+ {
+ switch (eLine)
+ {
+ case SvxPrevLineSpace::N1:
+ break;
+ case SvxPrevLineSpace::N115:
+ aPnt.AdjustY(nH / 6.67 ); // 1/.15 = 6.(6)
+ break;
+ case SvxPrevLineSpace::N15:
+ aPnt.AdjustY(nH / 2 );
+ break;
+ case SvxPrevLineSpace::N2:
+ aPnt.AdjustY(nH );
+ break;
+ case SvxPrevLineSpace::Prop:
+ case SvxPrevLineSpace::Min:
+ case SvxPrevLineSpace::Leading:
+ break;
+ }
+ }
+
+ aPnt.AdjustY(nH );
+
+ if (3 <= i && 5 >= i)
+ {
+ tools::Long nLW = tools::Long();
+ switch (i)
+ {
+ case 3:
+ nLW = aLineSiz.Width() * 8 / 10;
+ break;
+ case 4:
+ nLW = aLineSiz.Width() * 9 / 10;
+ break;
+ case 5:
+ nLW = aLineSiz.Width() / 2;
+ break;
+ }
+
+ if (nLW > aSiz.Width())
+ nLW = aSiz.Width();
+
+ switch (eAdjust)
+ {
+ case SvxAdjust::Left:
+ break;
+ case SvxAdjust::Right:
+ aPnt.AdjustX( aSiz.Width() - nLW );
+ break;
+ case SvxAdjust::Center:
+ aPnt.AdjustX(( aSiz.Width() - nLW ) / 2 );
+ break;
+ default: ; //prevent warning
+ }
+ if (SvxAdjust::Block == eAdjust)
+ {
+ if(5 == i)
+ {
+ switch( eLastLine )
+ {
+ case SvxAdjust::Left:
+ break;
+ case SvxAdjust::Right:
+ aPnt.AdjustX( aSiz.Width() - nLW );
+ break;
+ case SvxAdjust::Center:
+ aPnt.AdjustX(( aSiz.Width() - nLW ) / 2 );
+ break;
+ case SvxAdjust::Block:
+ nLW = aSiz.Width();
+ break;
+ default: ; //prevent warning
+ }
+ }
+ else
+ nLW = aSiz.Width();
+ }
+ aSiz.setWidth( nLW );
+ }
+
+ tools::Rectangle aRect(aPnt, aSiz);
+
+ rRenderContext.DrawRect( aRect );
+
+ if (5 == i)
+ {
+ auto nBottom = nLower * aLineSiz.Height() / aSize.Height();
+ aPnt.AdjustY(nBottom * 2 );
+ }
+
+ aPnt.AdjustY(nH );
+ // Reset, recalculate for each line
+ aPnt.setX( DEF_MARGIN / 2 );
+ aSiz = aLineSiz;
+ }
+ rRenderContext.Pop();
+}
+
+#undef DEF_MARGIN
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/passwd.cxx b/svx/source/dialog/passwd.cxx
new file mode 100644
index 0000000000..cb7793c3de
--- /dev/null
+++ b/svx/source/dialog/passwd.cxx
@@ -0,0 +1,91 @@
+/* -*- 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/weld.hxx>
+#include <svx/passwd.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+
+IMPL_LINK_NOARG(SvxPasswordDialog, ButtonHdl, weld::Button&, void)
+{
+ bool bOK = true;
+
+ if (m_xNewPasswdED->get_text() != m_xRepeatPasswdED->get_text())
+ {
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Warning, VclButtonsType::Ok,
+ m_aRepeatPasswdErrStr));
+ xBox->run();
+ m_xNewPasswdED->set_text("");
+ m_xRepeatPasswdED->set_text("");
+ m_xNewPasswdED->grab_focus();
+ bOK = false;
+ }
+
+ if (bOK && m_aCheckPasswordHdl.IsSet() && !m_aCheckPasswordHdl.Call(this))
+ {
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Warning, VclButtonsType::Ok,
+ m_aOldPasswdErrStr));
+ xBox->run();
+ m_xOldPasswdED->set_text("");
+ m_xOldPasswdED->grab_focus();
+ bOK = false;
+ }
+
+ if (bOK)
+ m_xDialog->response(RET_OK);
+}
+
+IMPL_LINK_NOARG(SvxPasswordDialog, EditModifyHdl, weld::Entry&, void)
+{
+ if (!m_xOKBtn->get_sensitive())
+ m_xOKBtn->set_sensitive(true);
+}
+
+SvxPasswordDialog::SvxPasswordDialog(weld::Window* pParent, bool bDisableOldPassword)
+ : SfxDialogController(pParent, "svx/ui/passwd.ui", "PasswordDialog")
+ , m_aOldPasswdErrStr(SvxResId(RID_SVXSTR_ERR_OLD_PASSWD))
+ , m_aRepeatPasswdErrStr(SvxResId(RID_SVXSTR_ERR_REPEAT_PASSWD ))
+ , m_xOldFL(m_xBuilder->weld_label("oldpass"))
+ , m_xOldPasswdFT(m_xBuilder->weld_label("oldpassL"))
+ , m_xOldPasswdED(m_xBuilder->weld_entry("oldpassEntry"))
+ , m_xNewPasswdED(m_xBuilder->weld_entry("newpassEntry"))
+ , m_xRepeatPasswdED(m_xBuilder->weld_entry("confirmpassEntry"))
+ , m_xOKBtn(m_xBuilder->weld_button("ok"))
+{
+ m_xOKBtn->connect_clicked(LINK(this, SvxPasswordDialog, ButtonHdl));
+ m_xRepeatPasswdED->connect_changed(LINK(this, SvxPasswordDialog, EditModifyHdl));
+ EditModifyHdl(*m_xRepeatPasswdED);
+
+ if (bDisableOldPassword)
+ {
+ m_xOldFL->set_sensitive(false);
+ m_xOldPasswdFT->set_sensitive(false);
+ m_xOldPasswdED->set_sensitive(false);
+ m_xNewPasswdED->grab_focus();
+ }
+}
+
+SvxPasswordDialog::~SvxPasswordDialog()
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/relfld.cxx b/svx/source/dialog/relfld.cxx
new file mode 100644
index 0000000000..3929e4fcf7
--- /dev/null
+++ b/svx/source/dialog/relfld.cxx
@@ -0,0 +1,103 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/relfld.hxx>
+
+SvxRelativeField::SvxRelativeField(std::unique_ptr<weld::MetricSpinButton> pControl)
+ : m_xSpinButton(std::move(pControl))
+ , nRelMin(0)
+ , nRelMax(0)
+ , bRelativeMode(false)
+ , bRelative(false)
+ , bNegativeEnabled(false)
+
+{
+ weld::SpinButton& rSpinButton = m_xSpinButton->get_widget();
+ rSpinButton.connect_changed(LINK(this, SvxRelativeField, ModifyHdl));
+}
+
+IMPL_LINK_NOARG(SvxRelativeField, ModifyHdl, weld::Entry&, void)
+{
+ if (!bRelativeMode)
+ return;
+
+ OUString aStr = m_xSpinButton->get_text();
+ bool bNewMode = bRelative;
+
+ if ( bRelative )
+ {
+ const sal_Unicode* pStr = aStr.getStr();
+
+ while ( *pStr )
+ {
+ if( ( ( *pStr < '0' ) || ( *pStr > '9' ) ) &&
+ ( *pStr != '%' ) )
+ {
+ bNewMode = false;
+ break;
+ }
+ pStr++;
+ }
+ }
+ else
+ {
+ if ( aStr.indexOf( "%" ) != -1 )
+ bNewMode = true;
+ }
+
+ if ( bNewMode != bRelative )
+ SetRelative( bNewMode );
+}
+
+void SvxRelativeField::EnableRelativeMode(sal_uInt16 nMin, sal_uInt16 nMax)
+{
+ bRelativeMode = true;
+ nRelMin = nMin;
+ nRelMax = nMax;
+ m_xSpinButton->set_unit(FieldUnit::CM);
+}
+
+void SvxRelativeField::SetRelative( bool bNewRelative )
+{
+ weld::SpinButton& rSpinButton = m_xSpinButton->get_widget();
+
+ int nStartPos, nEndPos;
+ rSpinButton.get_selection_bounds(nStartPos, nEndPos);
+ OUString aStr = rSpinButton.get_text();
+
+ if ( bNewRelative )
+ {
+ bRelative = true;
+ m_xSpinButton->set_digits(0);
+ m_xSpinButton->set_range(nRelMin, nRelMax, FieldUnit::NONE);
+ m_xSpinButton->set_unit(FieldUnit::PERCENT);
+ }
+ else
+ {
+ bRelative = false;
+ m_xSpinButton->set_digits(2);
+ m_xSpinButton->set_range(bNegativeEnabled ? -9999 : 0, 9999, FieldUnit::NONE);
+ m_xSpinButton->set_unit(FieldUnit::CM);
+ }
+
+ rSpinButton.set_text(aStr);
+ rSpinButton.select_region(nStartPos, nEndPos);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/rlrcitem.cxx b/svx/source/dialog/rlrcitem.cxx
new file mode 100644
index 0000000000..a73cd00bda
--- /dev/null
+++ b/svx/source/dialog/rlrcitem.cxx
@@ -0,0 +1,148 @@
+/* -*- 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 <svl/rectitem.hxx>
+#include <sal/log.hxx>
+#include <osl/diagnose.h>
+
+#include <svx/svxids.hrc>
+
+#include <svx/ruler.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/tstpitem.hxx>
+#include <editeng/protitem.hxx>
+#include "rlrcitem.hxx"
+#include <svx/rulritem.hxx>
+#include <svl/eitem.hxx>
+
+SvxRulerItem::SvxRulerItem(sal_uInt16 _nId, SvxRuler &rRul, SfxBindings &rBindings)
+: SfxControllerItem(_nId, rBindings),
+ rRuler(rRul)
+{
+}
+
+
+void SvxRulerItem::StateChangedAtToolBoxControl( sal_uInt16 nSID, SfxItemState eState,
+ const SfxPoolItem* pState)
+{
+ // SfxItemState::DONTCARE => pState == -1 => PTR_CAST buff
+ if ( eState != SfxItemState::DEFAULT )
+ pState = nullptr;
+
+ switch(nSID)
+ {
+ // Left / right margin
+ case SID_RULER_LR_MIN_MAX:
+ {
+ const SfxRectangleItem *pItem = dynamic_cast<const SfxRectangleItem*>( pState );
+ rRuler.UpdateFrameMinMax(pItem);
+ break;
+ }
+ case SID_ATTR_LONG_LRSPACE:
+ {
+ const SvxLongLRSpaceItem *pItem = dynamic_cast<const SvxLongLRSpaceItem*>( pState );
+ SAL_WARN_IF(pState != nullptr && pItem == nullptr, "svx.dialog", "SvxLRSpaceItem expected");
+ rRuler.UpdateFrame(pItem);
+ break;
+ }
+ case SID_ATTR_LONG_ULSPACE:
+ {
+ const SvxLongULSpaceItem *pItem = dynamic_cast<const SvxLongULSpaceItem*>( pState );
+ SAL_WARN_IF(pState != nullptr && pItem == nullptr, "svx.dialog", "SvxULSpaceItem expected");
+ rRuler.UpdateFrame(pItem);
+ break;
+ }
+ case SID_ATTR_TABSTOP_VERTICAL:
+ case SID_ATTR_TABSTOP:
+ {
+ const SvxTabStopItem *pItem = dynamic_cast<const SvxTabStopItem*>( pState );
+ SAL_WARN_IF(pState != nullptr && pItem == nullptr, "svx.dialog", "SvxTabStopItem expected");
+ rRuler.Update(pItem);
+ break;
+ }
+ case SID_ATTR_PARA_LRSPACE_VERTICAL:
+ case SID_ATTR_PARA_LRSPACE:
+ {
+ const SvxLRSpaceItem *pItem = dynamic_cast<const SvxLRSpaceItem*>( pState );
+ SAL_WARN_IF(pState != nullptr && pItem == nullptr, "svx.dialog", "SvxLRSpaceItem expected");
+ rRuler.UpdatePara(pItem);
+ break;
+ }
+ case SID_RULER_BORDERS_VERTICAL:
+ case SID_RULER_BORDERS:
+ case SID_RULER_ROWS:
+ case SID_RULER_ROWS_VERTICAL:
+ {
+ const SvxColumnItem *pItem = dynamic_cast<const SvxColumnItem*>( pState );
+ SAL_WARN_IF(pState != nullptr && pItem == nullptr, "svx.dialog", "SvxColumnItem expected");
+#ifdef DBG_UTIL
+ if(pItem)
+ {
+ if(pItem->IsConsistent())
+ rRuler.Update(pItem, nSID);
+ else
+ OSL_FAIL("Column item corrupted");
+ }
+ else
+ rRuler.Update(pItem, nSID);
+#else
+ rRuler.Update(pItem, nSID);
+#endif
+ break;
+ }
+ case SID_RULER_PAGE_POS:
+ { // Position page, page width
+ const SvxPagePosSizeItem *pItem = dynamic_cast<const SvxPagePosSizeItem*>( pState );
+ SAL_WARN_IF(pState != nullptr && pItem == nullptr, "svx.dialog", "SvxPagePosSizeItem expected");
+ rRuler.Update(pItem);
+ break;
+ }
+ case SID_RULER_OBJECT:
+ { // Object selection
+ const SvxObjectItem *pItem = dynamic_cast<const SvxObjectItem*>( pState );
+ SAL_WARN_IF(pState != nullptr && pItem == nullptr, "svx.dialog", "SvxObjectItem expected");
+ rRuler.Update(pItem);
+ break;
+ }
+ case SID_RULER_PROTECT:
+ {
+ const SvxProtectItem *pItem = dynamic_cast<const SvxProtectItem*>( pState );
+ SAL_WARN_IF(pState != nullptr && pItem == nullptr, "svx.dialog", "SvxProtectItem expected");
+ rRuler.Update(pItem);
+ break;
+ }
+ case SID_RULER_BORDER_DISTANCE:
+ {
+ const SvxLRSpaceItem *pItem = dynamic_cast<const SvxLRSpaceItem*>( pState );
+ SAL_WARN_IF(pState != nullptr && pItem == nullptr, "svx.dialog", "SvxLRSpaceItem expected");
+ rRuler.UpdateBorder(pItem);
+ }
+ break;
+ case SID_RULER_TEXT_RIGHT_TO_LEFT :
+ {
+ const SfxBoolItem *pItem = dynamic_cast<const SfxBoolItem*>( pState );
+ SAL_WARN_IF(pState != nullptr && pItem == nullptr, "svx.dialog", "SfxBoolItem expected");
+ rRuler.UpdateTextRTL(pItem);
+ }
+ break;
+ }
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/rlrcitem.hxx b/svx/source/dialog/rlrcitem.hxx
new file mode 100644
index 0000000000..0fde86f0ca
--- /dev/null
+++ b/svx/source/dialog/rlrcitem.hxx
@@ -0,0 +1,42 @@
+/* -*- 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 .
+ */
+#ifndef INCLUDED_SVX_SOURCE_DIALOG_RLRCITEM_HXX
+#define INCLUDED_SVX_SOURCE_DIALOG_RLRCITEM_HXX
+
+#include <sfx2/ctrlitem.hxx>
+
+class SvxRuler;
+
+class SvxRulerItem : public SfxControllerItem
+{
+private:
+ SvxRuler& rRuler;
+
+protected:
+ virtual void StateChangedAtToolBoxControl( sal_uInt16,
+ SfxItemState, const SfxPoolItem* pState ) override;
+
+public:
+ SvxRulerItem( sal_uInt16 nId, SvxRuler&, SfxBindings& );
+};
+
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/rubydialog.cxx b/svx/source/dialog/rubydialog.cxx
new file mode 100644
index 0000000000..83cfe3052c
--- /dev/null
+++ b/svx/source/dialog/rubydialog.cxx
@@ -0,0 +1,873 @@
+/*
+ * 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 <tools/debug.hxx>
+#include <comphelper/diagnose_ex.hxx>
+
+#include <svx/rubydialog.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/viewsh.hxx>
+#include <svl/eitem.hxx>
+#include <com/sun/star/frame/XController.hpp>
+#include <com/sun/star/style/XStyle.hpp>
+#include <com/sun/star/text/XRubySelection.hpp>
+#include <com/sun/star/beans/PropertyValues.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XPropertySetInfo.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
+#include <com/sun/star/text/RubyAdjust.hpp>
+#include <com/sun/star/view/XSelectionChangeListener.hpp>
+#include <com/sun/star/view/XSelectionSupplier.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <svtools/colorcfg.hxx>
+#include <vcl/event.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <svl/itemset.hxx>
+
+using namespace css::uno;
+using namespace css::frame;
+using namespace css::text;
+using namespace css::beans;
+using namespace css::style;
+using namespace css::view;
+using namespace css::lang;
+using namespace css::container;
+
+SFX_IMPL_CHILDWINDOW(SvxRubyChildWindow, SID_RUBY_DIALOG);
+
+namespace
+{
+constexpr OUString cRubyBaseText = u"RubyBaseText"_ustr;
+constexpr OUString cRubyText = u"RubyText"_ustr;
+constexpr OUString cRubyAdjust = u"RubyAdjust"_ustr;
+constexpr OUString cRubyPosition = u"RubyPosition"_ustr;
+constexpr OUString cRubyCharStyleName = u"RubyCharStyleName"_ustr;
+
+} // end anonymous namespace
+
+SvxRubyChildWindow::SvxRubyChildWindow(vcl::Window* _pParent, sal_uInt16 nId,
+ SfxBindings* pBindings, SfxChildWinInfo const* pInfo)
+ : SfxChildWindow(_pParent, nId)
+{
+ auto xDlg = std::make_shared<SvxRubyDialog>(pBindings, this, _pParent->GetFrameWeld());
+ SetController(xDlg);
+ xDlg->Initialize(pInfo);
+}
+
+SfxChildWinInfo SvxRubyChildWindow::GetInfo() const { return SfxChildWindow::GetInfo(); }
+
+class SvxRubyData_Impl : public cppu::WeakImplHelper<css::view::XSelectionChangeListener>
+{
+ Reference<XModel> xModel;
+ Reference<XRubySelection> xSelection;
+ Sequence<PropertyValues> aRubyValues;
+ Reference<XController> xController;
+ bool bHasSelectionChanged;
+ bool bDisposing;
+
+public:
+ SvxRubyData_Impl();
+ virtual ~SvxRubyData_Impl() override;
+
+ void SetController(const Reference<XController>& xCtrl);
+ Reference<XModel> const& GetModel()
+ {
+ if (!xController.is())
+ xModel = nullptr;
+ else
+ xModel = xController->getModel();
+ return xModel;
+ }
+ bool HasSelectionChanged() const { return bHasSelectionChanged; }
+ bool IsDisposing() const { return bDisposing; }
+ Reference<XRubySelection> const& GetRubySelection()
+ {
+ xSelection.set(xController, UNO_QUERY);
+ return xSelection;
+ }
+ void UpdateRubyValues()
+ {
+ if (!xSelection.is())
+ aRubyValues.realloc(0);
+ else
+ aRubyValues = xSelection->getRubyList(false);
+ bHasSelectionChanged = false;
+ }
+ Sequence<PropertyValues>& GetRubyValues() { return aRubyValues; }
+ void AssertOneEntry();
+
+ virtual void SAL_CALL selectionChanged(const css::lang::EventObject& aEvent) override;
+ virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override;
+};
+
+SvxRubyData_Impl::SvxRubyData_Impl()
+ : bHasSelectionChanged(false)
+ , bDisposing(false)
+{
+}
+
+SvxRubyData_Impl::~SvxRubyData_Impl() {}
+
+void SvxRubyData_Impl::SetController(const Reference<XController>& xCtrl)
+{
+ if (xCtrl.get() == xController.get())
+ return;
+
+ try
+ {
+ Reference<XSelectionSupplier> xSelSupp(xController, UNO_QUERY);
+ if (xSelSupp.is())
+ xSelSupp->removeSelectionChangeListener(this);
+
+ bHasSelectionChanged = true;
+ xController = xCtrl;
+ xSelSupp.set(xController, UNO_QUERY);
+ if (xSelSupp.is())
+ xSelSupp->addSelectionChangeListener(this);
+ }
+ catch (const Exception&)
+ {
+ }
+}
+
+void SvxRubyData_Impl::selectionChanged(const EventObject&) { bHasSelectionChanged = true; }
+
+void SvxRubyData_Impl::disposing(const EventObject&)
+{
+ try
+ {
+ Reference<XSelectionSupplier> xSelSupp(xController, UNO_QUERY);
+ if (xSelSupp.is())
+ xSelSupp->removeSelectionChangeListener(this);
+ }
+ catch (const Exception&)
+ {
+ }
+ xController = nullptr;
+ bDisposing = true;
+}
+
+void SvxRubyData_Impl::AssertOneEntry()
+{
+ //create one entry
+ if (!aRubyValues.hasElements())
+ {
+ aRubyValues.realloc(1);
+ Sequence<PropertyValue>& rValues = aRubyValues.getArray()[0];
+ rValues.realloc(5);
+ PropertyValue* pValues = rValues.getArray();
+ pValues[0].Name = cRubyBaseText;
+ pValues[1].Name = cRubyText;
+ pValues[2].Name = cRubyAdjust;
+ pValues[3].Name = cRubyPosition;
+ pValues[4].Name = cRubyCharStyleName;
+ }
+}
+
+SvxRubyDialog::SvxRubyDialog(SfxBindings* pBind, SfxChildWindow* pCW, weld::Window* pParent)
+ : SfxModelessDialogController(pBind, pCW, pParent, "svx/ui/asianphoneticguidedialog.ui",
+ "AsianPhoneticGuideDialog")
+ , nLastPos(0)
+ , nCurrentEdit(0)
+ , bModified(false)
+ , pBindings(pBind)
+ , m_pImpl(new SvxRubyData_Impl)
+ , m_xLeft1ED(m_xBuilder->weld_entry("Left1ED"))
+ , m_xRight1ED(m_xBuilder->weld_entry("Right1ED"))
+ , m_xLeft2ED(m_xBuilder->weld_entry("Left2ED"))
+ , m_xRight2ED(m_xBuilder->weld_entry("Right2ED"))
+ , m_xLeft3ED(m_xBuilder->weld_entry("Left3ED"))
+ , m_xRight3ED(m_xBuilder->weld_entry("Right3ED"))
+ , m_xLeft4ED(m_xBuilder->weld_entry("Left4ED"))
+ , m_xRight4ED(m_xBuilder->weld_entry("Right4ED"))
+ , m_xScrolledWindow(m_xBuilder->weld_scrolled_window("scrolledwindow", true))
+ , m_xAdjustLB(m_xBuilder->weld_combo_box("adjustlb"))
+ , m_xPositionLB(m_xBuilder->weld_combo_box("positionlb"))
+ , m_xCharStyleFT(m_xBuilder->weld_label("styleft"))
+ , m_xCharStyleLB(m_xBuilder->weld_combo_box("stylelb"))
+ , m_xStylistPB(m_xBuilder->weld_button("styles"))
+ , m_xApplyPB(m_xBuilder->weld_button("ok"))
+ , m_xClosePB(m_xBuilder->weld_button("close"))
+ , m_xContentArea(m_xDialog->weld_content_area())
+ , m_xGrid(m_xBuilder->weld_widget("grid"))
+ , m_xPreviewWin(new RubyPreview)
+ , m_xPreview(new weld::CustomWeld(*m_xBuilder, "preview", *m_xPreviewWin))
+{
+ m_xCharStyleLB->make_sorted();
+ m_xPreviewWin->setRubyDialog(this);
+ m_xScrolledWindow->set_size_request(-1, m_xGrid->get_preferred_size().Height());
+ m_xScrolledWindow->set_vpolicy(VclPolicyType::NEVER);
+
+ aEditArr[0] = m_xLeft1ED.get();
+ aEditArr[1] = m_xRight1ED.get();
+ aEditArr[2] = m_xLeft2ED.get();
+ aEditArr[3] = m_xRight2ED.get();
+ aEditArr[4] = m_xLeft3ED.get();
+ aEditArr[5] = m_xRight3ED.get();
+ aEditArr[6] = m_xLeft4ED.get();
+ aEditArr[7] = m_xRight4ED.get();
+
+ m_xApplyPB->connect_clicked(LINK(this, SvxRubyDialog, ApplyHdl_Impl));
+ m_xClosePB->connect_clicked(LINK(this, SvxRubyDialog, CloseHdl_Impl));
+ m_xStylistPB->connect_clicked(LINK(this, SvxRubyDialog, StylistHdl_Impl));
+ m_xAdjustLB->connect_changed(LINK(this, SvxRubyDialog, AdjustHdl_Impl));
+ m_xPositionLB->connect_changed(LINK(this, SvxRubyDialog, PositionHdl_Impl));
+ m_xCharStyleLB->connect_changed(LINK(this, SvxRubyDialog, CharStyleHdl_Impl));
+
+ Link<weld::ScrolledWindow&, void> aScrLk(LINK(this, SvxRubyDialog, ScrollHdl_Impl));
+ m_xScrolledWindow->connect_vadjustment_changed(aScrLk);
+
+ Link<weld::Entry&, void> aEditLk(LINK(this, SvxRubyDialog, EditModifyHdl_Impl));
+ Link<weld::Widget&, void> aFocusLk(LINK(this, SvxRubyDialog, EditFocusHdl_Impl));
+ Link<const KeyEvent&, bool> aKeyUpDownLk(LINK(this, SvxRubyDialog, KeyUpDownHdl_Impl));
+ Link<const KeyEvent&, bool> aKeyTabUpDownLk(LINK(this, SvxRubyDialog, KeyUpDownTabHdl_Impl));
+ for (sal_uInt16 i = 0; i < 8; i++)
+ {
+ aEditArr[i]->connect_changed(aEditLk);
+ aEditArr[i]->connect_focus_in(aFocusLk);
+ if (!i || 7 == i)
+ aEditArr[i]->connect_key_press(aKeyTabUpDownLk);
+ else
+ aEditArr[i]->connect_key_press(aKeyUpDownLk);
+ }
+}
+
+SvxRubyDialog::~SvxRubyDialog()
+{
+ ClearCharStyleList();
+ EventObject aEvent;
+ m_pImpl->disposing(aEvent);
+}
+
+void SvxRubyDialog::ClearCharStyleList() { m_xCharStyleLB->clear(); }
+
+void SvxRubyDialog::Close()
+{
+ if (IsClosing())
+ return;
+ SfxViewFrame* pViewFrame = SfxViewFrame::Current();
+ if (pViewFrame)
+ pViewFrame->ToggleChildWindow(SID_RUBY_DIALOG);
+}
+
+void SvxRubyDialog::Activate()
+{
+ SfxModelessDialogController::Activate();
+ if (m_pImpl->IsDisposing())
+ {
+ // tdf#141967/tdf#152495 if Activate is called during tear down bail early
+ return;
+ }
+
+ //get selection from current view frame
+ SfxViewFrame* pCurFrm = SfxViewFrame::Current();
+ Reference<XController> xCtrl(pCurFrm ? pCurFrm->GetFrame().GetController() : nullptr);
+ m_pImpl->SetController(xCtrl);
+ if (!m_pImpl->HasSelectionChanged())
+ return;
+
+ Reference<XRubySelection> xRubySel = m_pImpl->GetRubySelection();
+ m_pImpl->UpdateRubyValues();
+ EnableControls(xRubySel.is());
+ if (xRubySel.is())
+ {
+ Reference<XModel> xModel = m_pImpl->GetModel();
+ const OUString sCharStyleSelect = m_xCharStyleLB->get_active_text();
+ ClearCharStyleList();
+ Reference<XStyleFamiliesSupplier> xSupplier(xModel, UNO_QUERY);
+ if (xSupplier.is())
+ {
+ try
+ {
+ Reference<XNameAccess> xFam = xSupplier->getStyleFamilies();
+ Any aChar = xFam->getByName("CharacterStyles");
+ Reference<XNameContainer> xChar;
+ aChar >>= xChar;
+ Reference<XIndexAccess> xCharIdx(xChar, UNO_QUERY);
+ if (xCharIdx.is())
+ {
+ OUString sUIName("DisplayName");
+ for (sal_Int32 nStyle = 0; nStyle < xCharIdx->getCount(); nStyle++)
+ {
+ Any aStyle = xCharIdx->getByIndex(nStyle);
+ Reference<XStyle> xStyle;
+ aStyle >>= xStyle;
+ Reference<XPropertySet> xPrSet(xStyle, UNO_QUERY);
+ OUString sName, sCoreName;
+ if (xPrSet.is())
+ {
+ Reference<XPropertySetInfo> xInfo = xPrSet->getPropertySetInfo();
+ if (xInfo->hasPropertyByName(sUIName))
+ {
+ Any aName = xPrSet->getPropertyValue(sUIName);
+ aName >>= sName;
+ }
+ }
+ if (xStyle.is())
+ {
+ sCoreName = xStyle->getName();
+ if (sName.isEmpty())
+ sName = sCoreName;
+ }
+ if (!sName.isEmpty())
+ {
+ m_xCharStyleLB->append(sCoreName, sName);
+ }
+ }
+ }
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("svx.dialog", "exception in style access");
+ }
+ if (!sCharStyleSelect.isEmpty())
+ m_xCharStyleLB->set_active_text(sCharStyleSelect);
+ }
+ m_xCharStyleLB->set_sensitive(xSupplier.is());
+ m_xCharStyleFT->set_sensitive(xSupplier.is());
+ }
+ Update();
+ m_xPreviewWin->Invalidate();
+}
+
+void SvxRubyDialog::SetRubyText(sal_Int32 nPos, weld::Entry& rLeft, weld::Entry& rRight)
+{
+ OUString sLeft, sRight;
+ const Sequence<PropertyValues>& aRubyValues = m_pImpl->GetRubyValues();
+ bool bEnable = aRubyValues.getLength() > nPos;
+ if (bEnable)
+ {
+ const Sequence<PropertyValue> aProps = aRubyValues.getConstArray()[nPos];
+ for (const PropertyValue& rProp : aProps)
+ {
+ if (rProp.Name == cRubyBaseText)
+ rProp.Value >>= sLeft;
+ else if (rProp.Name == cRubyText)
+ rProp.Value >>= sRight;
+ }
+ }
+ else if (!nPos)
+ {
+ bEnable = true;
+ }
+ rLeft.set_sensitive(bEnable);
+ rRight.set_sensitive(bEnable);
+ rLeft.set_text(sLeft);
+ rRight.set_text(sRight);
+ rLeft.save_value();
+ rRight.save_value();
+}
+
+void SvxRubyDialog::GetRubyText()
+{
+ tools::Long nTempLastPos = GetLastPos();
+ Sequence<PropertyValues>& aRubyValues = m_pImpl->GetRubyValues();
+ auto aRubyValuesRange = asNonConstRange(aRubyValues);
+ for (int i = 0; i < 8; i += 2)
+ {
+ if (aEditArr[i]->get_sensitive()
+ && (aEditArr[i]->get_value_changed_from_saved()
+ || aEditArr[i + 1]->get_value_changed_from_saved()))
+ {
+ DBG_ASSERT(aRubyValues.getLength() > (i / 2 + nTempLastPos), "wrong index");
+ SetModified(true);
+ for (PropertyValue& propVal : asNonConstRange(aRubyValuesRange[i / 2 + nTempLastPos]))
+ {
+ if (propVal.Name == cRubyBaseText)
+ propVal.Value <<= aEditArr[i]->get_text();
+ else if (propVal.Name == cRubyText)
+ propVal.Value <<= aEditArr[i + 1]->get_text();
+ }
+ }
+ }
+}
+
+void SvxRubyDialog::Update()
+{
+ const Sequence<PropertyValues>& aRubyValues = m_pImpl->GetRubyValues();
+ sal_Int32 nLen = aRubyValues.getLength();
+ m_xScrolledWindow->vadjustment_configure(0, 0, !nLen ? 1 : nLen, 1, 4, 4);
+ if (nLen > 4)
+ m_xScrolledWindow->set_vpolicy(VclPolicyType::ALWAYS);
+ else
+ m_xScrolledWindow->set_vpolicy(VclPolicyType::NEVER);
+ SetLastPos(0);
+ SetModified(false);
+
+ sal_Int16 nAdjust = -1;
+ sal_Int16 nPosition = -1;
+ OUString sCharStyleName, sTmp;
+ bool bCharStyleEqual = true;
+ for (sal_Int32 nRuby = 0; nRuby < nLen; nRuby++)
+ {
+ const Sequence<PropertyValue>& rProps = aRubyValues.getConstArray()[nRuby];
+ for (const PropertyValue& rProp : rProps)
+ {
+ if (nAdjust > -2 && rProp.Name == cRubyAdjust)
+ {
+ sal_Int16 nTmp = sal_Int16();
+ rProp.Value >>= nTmp;
+ if (!nRuby)
+ nAdjust = nTmp;
+ else if (nAdjust != nTmp)
+ nAdjust = -2;
+ }
+ if (nPosition > -2 && rProp.Name == cRubyPosition)
+ {
+ sal_Int16 nTmp = sal_Int16();
+ rProp.Value >>= nTmp;
+ if (!nRuby)
+ nPosition = nTmp;
+ else if (nPosition != nTmp)
+ nPosition = -2;
+ }
+ if (bCharStyleEqual && rProp.Name == cRubyCharStyleName)
+ {
+ rProp.Value >>= sTmp;
+ if (!nRuby)
+ sCharStyleName = sTmp;
+ else if (sCharStyleName != sTmp)
+ bCharStyleEqual = false;
+ }
+ }
+ }
+ if (!nLen)
+ {
+ //enable selection if the ruby list is empty
+ nAdjust = 0;
+ nPosition = 0;
+ }
+ if (nAdjust > -1)
+ m_xAdjustLB->set_active(nAdjust);
+ else
+ m_xAdjustLB->set_active(-1);
+ if (nPosition > -1)
+ m_xPositionLB->set_active(nPosition);
+ if (!nLen || (bCharStyleEqual && sCharStyleName.isEmpty()))
+ sCharStyleName = "Rubies";
+ if (!sCharStyleName.isEmpty())
+ {
+ for (int i = 0, nEntryCount = m_xCharStyleLB->get_count(); i < nEntryCount; i++)
+ {
+ OUString sCoreName = m_xCharStyleLB->get_id(i);
+ if (sCharStyleName == sCoreName)
+ {
+ m_xCharStyleLB->set_active(i);
+ break;
+ }
+ }
+ }
+ else
+ m_xCharStyleLB->set_active(-1);
+
+ ScrollHdl_Impl(*m_xScrolledWindow);
+}
+
+void SvxRubyDialog::GetCurrentText(OUString& rBase, OUString& rRuby)
+{
+ rBase = aEditArr[nCurrentEdit * 2]->get_text();
+ rRuby = aEditArr[nCurrentEdit * 2 + 1]->get_text();
+}
+
+IMPL_LINK(SvxRubyDialog, ScrollHdl_Impl, weld::ScrolledWindow&, rScroll, void)
+{
+ int nPos = rScroll.vadjustment_get_value();
+ if (GetLastPos() != nPos)
+ {
+ GetRubyText();
+ }
+ SetRubyText(nPos++, *m_xLeft1ED, *m_xRight1ED);
+ SetRubyText(nPos++, *m_xLeft2ED, *m_xRight2ED);
+ SetRubyText(nPos++, *m_xLeft3ED, *m_xRight3ED);
+ SetRubyText(nPos, *m_xLeft4ED, *m_xRight4ED);
+ SetLastPos(nPos - 3);
+ m_xPreviewWin->Invalidate();
+}
+
+IMPL_LINK_NOARG(SvxRubyDialog, ApplyHdl_Impl, weld::Button&, void)
+{
+ const Sequence<PropertyValues>& aRubyValues = m_pImpl->GetRubyValues();
+ if (!aRubyValues.hasElements())
+ {
+ AssertOneEntry();
+ PositionHdl_Impl(*m_xPositionLB);
+ AdjustHdl_Impl(*m_xAdjustLB);
+ CharStyleHdl_Impl(*m_xCharStyleLB);
+ }
+ GetRubyText();
+ //reset all edit fields - SaveValue is called
+ ScrollHdl_Impl(*m_xScrolledWindow);
+
+ Reference<XRubySelection> xSelection = m_pImpl->GetRubySelection();
+ if (IsModified() && xSelection.is())
+ {
+ try
+ {
+ xSelection->setRubyList(aRubyValues, false);
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("svx.dialog", "");
+ }
+ }
+}
+
+IMPL_LINK_NOARG(SvxRubyDialog, CloseHdl_Impl, weld::Button&, void) { Close(); }
+
+IMPL_LINK_NOARG(SvxRubyDialog, StylistHdl_Impl, weld::Button&, void)
+{
+ std::unique_ptr<SfxBoolItem> pState;
+ SfxItemState eState = pBindings->QueryState(SID_STYLE_DESIGNER, pState);
+ if (eState <= SfxItemState::SET || !pState || !pState->GetValue())
+ {
+ pBindings->GetDispatcher()->Execute(SID_STYLE_DESIGNER,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD);
+ }
+}
+
+IMPL_LINK(SvxRubyDialog, AdjustHdl_Impl, weld::ComboBox&, rBox, void)
+{
+ AssertOneEntry();
+ sal_Int16 nAdjust = rBox.get_active();
+ for (PropertyValues& rProps : asNonConstRange(m_pImpl->GetRubyValues()))
+ {
+ for (PropertyValue& propVal : asNonConstRange(rProps))
+ {
+ if (propVal.Name == cRubyAdjust)
+ propVal.Value <<= nAdjust;
+ }
+ SetModified(true);
+ }
+ m_xPreviewWin->Invalidate();
+}
+
+IMPL_LINK(SvxRubyDialog, PositionHdl_Impl, weld::ComboBox&, rBox, void)
+{
+ AssertOneEntry();
+ sal_Int16 nPosition = rBox.get_active();
+ for (PropertyValues& rProps : asNonConstRange(m_pImpl->GetRubyValues()))
+ {
+ for (PropertyValue& propVal : asNonConstRange(rProps))
+ {
+ if (propVal.Name == cRubyPosition)
+ propVal.Value <<= nPosition;
+ }
+ SetModified(true);
+ }
+ m_xPreviewWin->Invalidate();
+}
+
+IMPL_LINK_NOARG(SvxRubyDialog, CharStyleHdl_Impl, weld::ComboBox&, void)
+{
+ AssertOneEntry();
+ OUString sStyleName;
+ if (m_xCharStyleLB->get_active() != -1)
+ sStyleName = m_xCharStyleLB->get_active_id();
+ for (PropertyValues& rProps : asNonConstRange(m_pImpl->GetRubyValues()))
+ {
+ for (PropertyValue& propVal : asNonConstRange(rProps))
+ {
+ if (propVal.Name == cRubyCharStyleName)
+ {
+ propVal.Value <<= sStyleName;
+ }
+ }
+ SetModified(true);
+ }
+}
+
+IMPL_LINK(SvxRubyDialog, EditFocusHdl_Impl, weld::Widget&, rEdit, void)
+{
+ for (sal_uInt16 i = 0; i < 8; i++)
+ {
+ if (&rEdit == aEditArr[i])
+ {
+ nCurrentEdit = i / 2;
+ break;
+ }
+ }
+ m_xPreviewWin->Invalidate();
+}
+
+IMPL_LINK(SvxRubyDialog, EditModifyHdl_Impl, weld::Entry&, rEdit, void)
+{
+ EditFocusHdl_Impl(rEdit);
+}
+
+bool SvxRubyDialog::EditScrollHdl_Impl(sal_Int32 nParam)
+{
+ bool bRet = false;
+ //scroll forward
+ if (nParam > 0 && (aEditArr[7]->has_focus() || aEditArr[6]->has_focus()))
+ {
+ if (m_xScrolledWindow->vadjustment_get_upper()
+ > m_xScrolledWindow->vadjustment_get_value()
+ + m_xScrolledWindow->vadjustment_get_page_size())
+ {
+ m_xScrolledWindow->vadjustment_set_value(m_xScrolledWindow->vadjustment_get_value()
+ + 1);
+ aEditArr[6]->grab_focus();
+ bRet = true;
+ }
+ }
+ //scroll backward
+ else if (m_xScrolledWindow->vadjustment_get_value()
+ && (aEditArr[0]->has_focus() || aEditArr[1]->has_focus()))
+ {
+ m_xScrolledWindow->vadjustment_set_value(m_xScrolledWindow->vadjustment_get_value() - 1);
+ aEditArr[1]->grab_focus();
+ bRet = true;
+ }
+ if (bRet)
+ ScrollHdl_Impl(*m_xScrolledWindow);
+ return bRet;
+}
+
+bool SvxRubyDialog::EditJumpHdl_Impl(sal_Int32 nParam)
+{
+ bool bHandled = false;
+ sal_uInt16 nIndex = USHRT_MAX;
+ for (sal_uInt16 i = 0; i < 8; i++)
+ {
+ if (aEditArr[i]->has_focus())
+ nIndex = i;
+ }
+ if (nIndex < 8)
+ {
+ if (nParam > 0)
+ {
+ if (nIndex < 6)
+ aEditArr[nIndex + 2]->grab_focus();
+ else if (EditScrollHdl_Impl(nParam))
+ aEditArr[nIndex]->grab_focus();
+ }
+ else
+ {
+ if (nIndex > 1)
+ aEditArr[nIndex - 2]->grab_focus();
+ else if (EditScrollHdl_Impl(nParam))
+ aEditArr[nIndex]->grab_focus();
+ }
+ bHandled = true;
+ }
+ return bHandled;
+}
+
+void SvxRubyDialog::AssertOneEntry() { m_pImpl->AssertOneEntry(); }
+
+void SvxRubyDialog::EnableControls(bool bEnable)
+{
+ m_xContentArea->set_sensitive(bEnable);
+ m_xApplyPB->set_sensitive(bEnable);
+}
+
+RubyPreview::RubyPreview()
+ : m_pParentDlg(nullptr)
+{
+}
+
+RubyPreview::~RubyPreview() {}
+
+void RubyPreview::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& /*rRect*/)
+{
+ rRenderContext.Push(vcl::PushFlags::ALL);
+
+ rRenderContext.SetMapMode(MapMode(MapUnit::MapTwip));
+
+ Size aWinSize = rRenderContext.GetOutputSize();
+
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ svtools::ColorConfig aColorConfig;
+
+ Color aNewTextColor(aColorConfig.GetColorValue(svtools::FONTCOLOR).nColor);
+ Color aNewFillColor(rStyleSettings.GetWindowColor());
+
+ vcl::Font aFont = rRenderContext.GetFont();
+ aFont.SetFontHeight(aWinSize.Height() / 4);
+ aFont.SetFillColor(aNewFillColor);
+ aFont.SetColor(aNewTextColor);
+ rRenderContext.SetFont(aFont);
+
+ tools::Rectangle aRect(Point(0, 0), aWinSize);
+ rRenderContext.SetLineColor();
+ rRenderContext.SetFillColor(aFont.GetFillColor());
+ rRenderContext.DrawRect(aRect);
+
+ OUString sBaseText, sRubyText;
+ m_pParentDlg->GetCurrentText(sBaseText, sRubyText);
+
+ tools::Long nTextHeight = rRenderContext.GetTextHeight();
+ tools::Long nBaseWidth = rRenderContext.GetTextWidth(sBaseText);
+
+ vcl::Font aRubyFont(aFont);
+ aRubyFont.SetFontHeight(aRubyFont.GetFontHeight() * 70 / 100);
+ rRenderContext.SetFont(aRubyFont);
+ tools::Long nRubyWidth = rRenderContext.GetTextWidth(sRubyText);
+ rRenderContext.SetFont(aFont);
+
+ RubyAdjust nAdjust = static_cast<RubyAdjust>(m_pParentDlg->m_xAdjustLB->get_active());
+ //use center if no adjustment is available
+ if (nAdjust > RubyAdjust_INDENT_BLOCK)
+ nAdjust = RubyAdjust_CENTER;
+
+ //which part is stretched ?
+ bool bRubyStretch = nBaseWidth >= nRubyWidth;
+
+ tools::Long nCenter = aWinSize.Width() / 2;
+ tools::Long nHalfWidth = std::max(nBaseWidth, nRubyWidth) / 2;
+ tools::Long nLeftStart = nCenter - nHalfWidth;
+ tools::Long nRightEnd = nCenter + nHalfWidth;
+
+ // Default values for TOP or no selection
+ tools::Long nYRuby = aWinSize.Height() / 4 - nTextHeight / 2;
+ tools::Long nYBase = aWinSize.Height() * 3 / 4 - nTextHeight / 2;
+
+ sal_Int16 nRubyPos = m_pParentDlg->m_xPositionLB->get_active();
+ if (nRubyPos == 1) // BOTTOM
+ std::swap(nYRuby, nYBase);
+ else if (nRubyPos == 2) // RIGHT ( vertically )
+ {
+ // Align the ruby text and base text to the vertical center.
+ nYBase = (aWinSize.Height() - nTextHeight) / 2;
+ nYRuby = (aWinSize.Height() - nRubyWidth) / 2;
+
+ // Align the ruby text at the right side of the base text
+ nAdjust = RubyAdjust_RIGHT;
+ nHalfWidth = nBaseWidth / 2;
+ nLeftStart = nCenter - nHalfWidth;
+ nRightEnd = nCenter + nHalfWidth + nRubyWidth + nTextHeight;
+ // Render base text first, then render ruby text on the right.
+ bRubyStretch = true;
+
+ aRubyFont.SetVertical(true);
+ aRubyFont.SetOrientation(2700_deg10);
+ }
+
+ tools::Long nYOutput;
+ tools::Long nOutTextWidth;
+ OUString sOutputText;
+
+ if (bRubyStretch)
+ {
+ rRenderContext.DrawText(Point(nLeftStart, nYBase), sBaseText);
+ nYOutput = nYRuby;
+ sOutputText = sRubyText;
+ nOutTextWidth = nRubyWidth;
+ rRenderContext.SetFont(aRubyFont);
+ }
+ else
+ {
+ rRenderContext.SetFont(aRubyFont);
+ rRenderContext.DrawText(Point(nLeftStart, nYRuby), sRubyText);
+ nYOutput = nYBase;
+ sOutputText = sBaseText;
+ nOutTextWidth = nBaseWidth;
+ rRenderContext.SetFont(aFont);
+ }
+
+ switch (nAdjust)
+ {
+ case RubyAdjust_LEFT:
+ rRenderContext.DrawText(Point(nLeftStart, nYOutput), sOutputText);
+ break;
+ case RubyAdjust_RIGHT:
+ rRenderContext.DrawText(Point(nRightEnd - nOutTextWidth, nYOutput), sOutputText);
+ break;
+ case RubyAdjust_INDENT_BLOCK:
+ {
+ tools::Long nCharWidth = rRenderContext.GetTextWidth("X");
+ if (nOutTextWidth < (nRightEnd - nLeftStart - nCharWidth))
+ {
+ nCharWidth /= 2;
+ nLeftStart += nCharWidth;
+ nRightEnd -= nCharWidth;
+ }
+ [[fallthrough]];
+ }
+ case RubyAdjust_BLOCK:
+ {
+ if (sOutputText.getLength() > 1)
+ {
+ sal_Int32 nCount = sOutputText.getLength();
+ tools::Long nSpace
+ = ((nRightEnd - nLeftStart) - rRenderContext.GetTextWidth(sOutputText))
+ / (nCount - 1);
+ for (sal_Int32 i = 0; i < nCount; i++)
+ {
+ OUString sChar(sOutputText[i]);
+ rRenderContext.DrawText(Point(nLeftStart, nYOutput), sChar);
+ tools::Long nCharWidth = rRenderContext.GetTextWidth(sChar);
+ nLeftStart += nCharWidth + nSpace;
+ }
+ break;
+ }
+ [[fallthrough]];
+ }
+ case RubyAdjust_CENTER:
+ rRenderContext.DrawText(Point(nCenter - nOutTextWidth / 2, nYOutput), sOutputText);
+ break;
+ default:
+ break;
+ }
+ rRenderContext.Pop();
+}
+
+void RubyPreview::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ pDrawingArea->set_size_request(pDrawingArea->get_approximate_digit_width() * 40,
+ pDrawingArea->get_text_height() * 7);
+ CustomWidgetController::SetDrawingArea(pDrawingArea);
+}
+
+IMPL_LINK(SvxRubyDialog, KeyUpDownHdl_Impl, const KeyEvent&, rKEvt, bool)
+{
+ bool bHandled = false;
+ const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode();
+ sal_uInt16 nCode = rKeyCode.GetCode();
+ if (KEY_UP == nCode || KEY_DOWN == nCode)
+ {
+ sal_Int32 nParam = KEY_UP == nCode ? -1 : 1;
+ bHandled = EditJumpHdl_Impl(nParam);
+ }
+ return bHandled;
+}
+
+IMPL_LINK(SvxRubyDialog, KeyUpDownTabHdl_Impl, const KeyEvent&, rKEvt, bool)
+{
+ bool bHandled = false;
+ const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode();
+ sal_uInt16 nMod = rKeyCode.GetModifier();
+ sal_uInt16 nCode = rKeyCode.GetCode();
+ if (nCode == KEY_TAB && (!nMod || KEY_SHIFT == nMod))
+ {
+ sal_Int32 nParam = KEY_SHIFT == nMod ? -1 : 1;
+ if (EditScrollHdl_Impl(nParam))
+ bHandled = true;
+ }
+ if (!bHandled)
+ bHandled = KeyUpDownHdl_Impl(rKEvt);
+ return bHandled;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/rulritem.cxx b/svx/source/dialog/rulritem.cxx
new file mode 100644
index 0000000000..8e61bf381c
--- /dev/null
+++ b/svx/source/dialog/rulritem.cxx
@@ -0,0 +1,735 @@
+/* -*- 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 <svx/svxids.hrc>
+#include <svx/rulritem.hxx>
+#include <svx/unomid.hxx>
+#include <tools/debug.hxx>
+#include <tools/mapunit.hxx>
+#include <tools/UnitConversion.hxx>
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+#include <com/sun/star/awt/Rectangle.hpp>
+#include <com/sun/star/frame/status/LeftRightMargin.hpp>
+#include <com/sun/star/frame/status/UpperLowerMargin.hpp>
+
+SfxPoolItem* SvxPagePosSizeItem::CreateDefault() { return new SvxPagePosSizeItem; }
+SfxPoolItem* SvxLongLRSpaceItem::CreateDefault() { return new SvxLongLRSpaceItem; }
+SfxPoolItem* SvxLongULSpaceItem::CreateDefault() { return new SvxLongULSpaceItem; }
+SfxPoolItem* SvxColumnItem::CreateDefault() { return new SvxColumnItem; }
+SfxPoolItem* SvxObjectItem::CreateDefault() { SAL_WARN( "svx", "No SvxObjectItem factory available"); return nullptr; }
+
+/* SvxLongLRSpaceItem */
+
+bool SvxLongLRSpaceItem::operator==( const SfxPoolItem& rCmp) const
+{
+ return SfxPoolItem::operator==(rCmp) &&
+ mlLeft == static_cast<const SvxLongLRSpaceItem &>(rCmp).mlLeft &&
+ mlRight == static_cast<const SvxLongLRSpaceItem &>(rCmp).mlRight;
+}
+
+bool SvxLongLRSpaceItem::QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId ) const
+{
+ bool bConvert = 0!=(nMemberId&CONVERT_TWIPS);
+ nMemberId &= ~CONVERT_TWIPS;
+
+ sal_Int32 nVal;
+ switch( nMemberId )
+ {
+ case 0:
+ {
+ css::frame::status::LeftRightMargin aLeftRightMargin;
+ aLeftRightMargin.Left = bConvert ? convertTwipToMm100( mlLeft ) : mlLeft;
+ aLeftRightMargin.Right = bConvert ? convertTwipToMm100( mlRight ) : mlRight;
+ rVal <<= aLeftRightMargin;
+ return true;
+ }
+
+ case MID_LEFT:
+ nVal = mlLeft;
+ break;
+ case MID_RIGHT:
+ nVal = mlRight;
+ break;
+ default:
+ OSL_FAIL("Wrong MemberId!");
+ return false;
+ }
+
+ if ( bConvert )
+ nVal = convertTwipToMm100( nVal );
+
+ rVal <<= nVal;
+ return true;
+}
+
+bool SvxLongLRSpaceItem::PutValue( const css::uno::Any& rVal, sal_uInt8 nMemberId )
+{
+ bool bConvert = 0!=(nMemberId&CONVERT_TWIPS);
+ nMemberId &= ~CONVERT_TWIPS;
+
+ sal_Int32 nVal = 0;
+ if ( nMemberId == 0 )
+ {
+ css::frame::status::LeftRightMargin aLeftRightMargin;
+ if ( rVal >>= aLeftRightMargin )
+ {
+ mlLeft = bConvert ? o3tl::toTwips(aLeftRightMargin.Left, o3tl::Length::mm100) : aLeftRightMargin.Left;
+ mlRight = bConvert ? o3tl::toTwips(aLeftRightMargin.Right, o3tl::Length::mm100) : aLeftRightMargin.Right;
+ return true;
+ }
+ }
+ else if ( rVal >>= nVal )
+ {
+ if ( bConvert )
+ nVal = o3tl::toTwips(nVal, o3tl::Length::mm100);
+
+ switch( nMemberId )
+ {
+ case MID_LEFT:
+ mlLeft = nVal;
+ break;
+ case MID_RIGHT:
+ mlRight = nVal;
+ break;
+ default:
+ OSL_FAIL("Wrong MemberId!");
+ return false;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+bool SvxLongLRSpaceItem::GetPresentation(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& /*rText*/,
+ const IntlWrapper& /*rWrapper*/) const
+{
+ return false;
+}
+
+SvxLongLRSpaceItem* SvxLongLRSpaceItem::Clone(SfxItemPool *) const
+{
+ return new SvxLongLRSpaceItem(*this);
+}
+
+SvxLongLRSpaceItem::SvxLongLRSpaceItem(tools::Long lLeft, tools::Long lRight, TypedWhichId<SvxLongLRSpaceItem> nId) :
+ SfxPoolItem (nId),
+ mlLeft (lLeft),
+ mlRight (lRight)
+{}
+
+SvxLongLRSpaceItem::SvxLongLRSpaceItem() :
+ SfxPoolItem (0),
+ mlLeft (0),
+ mlRight (0)
+{}
+
+void SvxLongLRSpaceItem::SetLeft(tools::Long lArgLeft)
+{
+ mlLeft = lArgLeft;
+}
+
+void SvxLongLRSpaceItem::SetRight(tools::Long lArgRight)
+{
+ mlRight = lArgRight;
+}
+
+/* SvxLongULSpaceItem */
+
+bool SvxLongULSpaceItem::operator==( const SfxPoolItem& rCmp) const
+{
+ return SfxPoolItem::operator==(rCmp) &&
+ mlLeft == static_cast<const SvxLongULSpaceItem&>(rCmp).mlLeft &&
+ mlRight == static_cast<const SvxLongULSpaceItem&>(rCmp).mlRight;
+}
+
+bool SvxLongULSpaceItem::QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId ) const
+{
+ bool bConvert = 0!=(nMemberId&CONVERT_TWIPS);
+ nMemberId &= ~CONVERT_TWIPS;
+
+ sal_Int32 nVal;
+ switch( nMemberId )
+ {
+ case 0:
+ {
+ css::frame::status::UpperLowerMargin aUpperLowerMargin;
+ aUpperLowerMargin.Upper = bConvert ? convertTwipToMm100( mlLeft ) : mlLeft;
+ aUpperLowerMargin.Lower = bConvert ? convertTwipToMm100( mlRight ) : mlRight;
+ rVal <<= aUpperLowerMargin;
+ return true;
+ }
+
+ case MID_UPPER:
+ nVal = mlLeft;
+ break;
+ case MID_LOWER:
+ nVal = mlRight;
+ break;
+ default: OSL_FAIL("Wrong MemberId!"); return false;
+ }
+
+ if ( bConvert )
+ nVal = convertTwipToMm100( nVal );
+
+ rVal <<= nVal;
+ return true;
+}
+
+bool SvxLongULSpaceItem::PutValue( const css::uno::Any& rVal, sal_uInt8 nMemberId )
+{
+ bool bConvert = 0!=(nMemberId&CONVERT_TWIPS);
+ nMemberId &= ~CONVERT_TWIPS;
+
+ sal_Int32 nVal = 0;
+ if ( nMemberId == 0 )
+ {
+ css::frame::status::UpperLowerMargin aUpperLowerMargin;
+ if ( rVal >>= aUpperLowerMargin )
+ {
+ mlLeft = bConvert ? o3tl::toTwips(aUpperLowerMargin.Upper, o3tl::Length::mm100) : aUpperLowerMargin.Upper;
+ mlRight = bConvert ? o3tl::toTwips(aUpperLowerMargin.Lower, o3tl::Length::mm100) : aUpperLowerMargin.Lower;
+ return true;
+ }
+ }
+ else if ( rVal >>= nVal )
+ {
+ if ( bConvert )
+ nVal = o3tl::toTwips(nVal, o3tl::Length::mm100);
+
+ switch( nMemberId )
+ {
+ case MID_UPPER:
+ mlLeft = nVal;
+ break;
+ case MID_LOWER:
+ mlRight = nVal;
+ break;
+ default:
+ OSL_FAIL("Wrong MemberId!");
+ return false;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+bool SvxLongULSpaceItem::GetPresentation(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& /*rText*/,
+ const IntlWrapper& /*rWrapper*/ ) const
+{
+ return false;
+}
+
+SvxLongULSpaceItem* SvxLongULSpaceItem::Clone(SfxItemPool *) const
+{
+ return new SvxLongULSpaceItem(*this);
+}
+
+SvxLongULSpaceItem::SvxLongULSpaceItem(tools::Long lLeft, tools::Long lRight, TypedWhichId<SvxLongULSpaceItem> nId) :
+ SfxPoolItem (nId),
+ mlLeft (lLeft),
+ mlRight (lRight)
+{}
+
+SvxLongULSpaceItem::SvxLongULSpaceItem() :
+ SfxPoolItem (0),
+ mlLeft (0),
+ mlRight (0)
+{}
+
+
+void SvxLongULSpaceItem::SetUpper(tools::Long lArgLeft)
+{
+ mlLeft = lArgLeft;
+}
+
+void SvxLongULSpaceItem::SetLower(tools::Long lArgRight)
+{
+ mlRight = lArgRight;
+}
+
+/* SvxPagePosSizeItem */
+
+bool SvxPagePosSizeItem::operator==( const SfxPoolItem& rCmp) const
+{
+ return SfxPoolItem::operator==(rCmp) &&
+ aPos == static_cast<const SvxPagePosSizeItem &>(rCmp).aPos &&
+ lWidth == static_cast<const SvxPagePosSizeItem &>(rCmp).lWidth &&
+ lHeight == static_cast<const SvxPagePosSizeItem &>(rCmp).lHeight;
+}
+
+bool SvxPagePosSizeItem::QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId ) const
+{
+ nMemberId &= ~CONVERT_TWIPS;
+
+ sal_Int32 nVal;
+ switch ( nMemberId )
+ {
+ case 0 :
+ {
+ css::awt::Rectangle aPagePosSize;
+ aPagePosSize.X = aPos.X();
+ aPagePosSize.Y = aPos.Y();
+ aPagePosSize.Width = lWidth;
+ aPagePosSize.Height = lHeight;
+ rVal <<= aPagePosSize;
+ return true;
+ }
+
+ case MID_X: nVal = aPos.X(); break;
+ case MID_Y: nVal = aPos.Y(); break;
+ case MID_WIDTH: nVal = lWidth; break;
+ case MID_HEIGHT: nVal = lHeight; break;
+
+ default: OSL_FAIL("Wrong MemberId!"); return false;
+ }
+
+ rVal <<= nVal;
+ return true;
+}
+
+bool SvxPagePosSizeItem::PutValue( const css::uno::Any& rVal, sal_uInt8 nMemberId )
+{
+ nMemberId &= ~CONVERT_TWIPS;
+
+ sal_Int32 nVal = 0;
+ if ( nMemberId == 0 )
+ {
+ css::awt::Rectangle aPagePosSize;
+ if ( rVal >>= aPagePosSize )
+ {
+ aPos.setX( aPagePosSize.X );
+ aPos.setY( aPagePosSize.Y );
+ lWidth = aPagePosSize.Width;
+ lHeight = aPagePosSize.Height;
+ return true;
+ }
+ else
+ return false;
+ }
+ else if ( rVal >>= nVal )
+ {
+ switch ( nMemberId )
+ {
+ case MID_X: aPos.setX( nVal ); break;
+ case MID_Y: aPos.setY( nVal ); break;
+ case MID_WIDTH: lWidth = nVal; break;
+ case MID_HEIGHT: lHeight = nVal; break;
+
+ default: OSL_FAIL("Wrong MemberId!"); return false;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+bool SvxPagePosSizeItem::GetPresentation(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& /*rText*/,
+ const IntlWrapper& /*rWrapper*/ ) const
+{
+ return false;
+}
+
+SvxPagePosSizeItem* SvxPagePosSizeItem::Clone(SfxItemPool *) const
+{
+ return new SvxPagePosSizeItem(*this);
+}
+
+SvxPagePosSizeItem::SvxPagePosSizeItem(const Point &rP, tools::Long lW, tools::Long lH) :
+ SfxPoolItem (SID_RULER_PAGE_POS),
+ aPos (rP),
+ lWidth (lW),
+ lHeight (lH)
+{}
+
+SvxPagePosSizeItem::SvxPagePosSizeItem() :
+ SfxPoolItem (0),
+ aPos (0, 0),
+ lWidth (0),
+ lHeight (0)
+{}
+
+/* SvxColumnItem */
+
+bool SvxColumnItem::operator==(const SfxPoolItem& rCmp) const
+{
+ if(!SfxPoolItem::operator==(rCmp) ||
+ nActColumn != static_cast<const SvxColumnItem&>(rCmp).nActColumn ||
+ nLeft != static_cast<const SvxColumnItem&>(rCmp).nLeft ||
+ nRight != static_cast<const SvxColumnItem&>(rCmp).nRight ||
+ bTable != static_cast<const SvxColumnItem&>(rCmp).bTable ||
+ Count() != static_cast<const SvxColumnItem&>(rCmp).Count())
+ return false;
+
+ const sal_uInt16 nCount = static_cast<const SvxColumnItem&>(rCmp).Count();
+ for(sal_uInt16 i = 0; i < nCount;++i)
+ {
+ if( (*this)[i] != static_cast<const SvxColumnItem&>(rCmp)[i] )
+ return false;
+ }
+ return true;
+}
+
+SvxColumnItem::SvxColumnItem( sal_uInt16 nAct ) :
+ SfxPoolItem (SID_RULER_BORDERS),
+ nLeft (0),
+ nRight (0),
+ nActColumn (nAct),
+ bTable (false),
+ bOrtho (true)
+
+{}
+
+SvxColumnItem::SvxColumnItem( sal_uInt16 nActCol, sal_uInt16 left, sal_uInt16 right ) :
+ SfxPoolItem (SID_RULER_BORDERS),
+ nLeft (left),
+ nRight (right),
+ nActColumn (nActCol),
+ bTable (true),
+ bOrtho (true)
+{}
+
+bool SvxColumnItem::GetPresentation(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& /*rText*/,
+ const IntlWrapper& /*rWrapper*/ ) const
+{
+ return false;
+}
+
+SvxColumnItem* SvxColumnItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new SvxColumnItem(*this);
+}
+
+bool SvxColumnItem::CalcOrtho() const
+{
+ const sal_uInt16 nCount = Count();
+ DBG_ASSERT(nCount >= 2, "no columns");
+ if(nCount < 2)
+ return false;
+
+ tools::Long nColWidth = (*this)[0].GetWidth();
+ for(sal_uInt16 i = 1; i < nCount; ++i) {
+ if( (*this)[i].GetWidth() != nColWidth)
+ return false;
+ }
+ //!! Wide divider
+ return true;
+}
+
+bool SvxColumnItem::QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId ) const
+{
+ nMemberId &= ~CONVERT_TWIPS;
+ switch ( nMemberId )
+ {
+ case 0:
+ // SfxDispatchController_Impl::StateChanged calls this with hardcoded 0 triggering this;
+ SAL_INFO("svx", "SvxColumnItem::QueryValue with nMemberId of 0");
+ return false;
+ case MID_COLUMNARRAY:
+ return false;
+ case MID_RIGHT:
+ rVal <<= nRight;
+ break;
+ case MID_LEFT:
+ rVal <<= nLeft;
+ break;
+ case MID_ORTHO:
+ rVal <<= bOrtho;
+ break;
+ case MID_ACTUAL:
+ rVal <<= static_cast<sal_Int32>(nActColumn);
+ break;
+ case MID_TABLE:
+ rVal <<= bTable;
+ break;
+ default:
+ SAL_WARN("svx", "Wrong MemberId!");
+ return false;
+ }
+
+ return true;
+}
+
+bool SvxColumnItem::PutValue( const css::uno::Any& rVal, sal_uInt8 nMemberId )
+{
+ nMemberId &= ~CONVERT_TWIPS;
+ sal_Int32 nVal = 0;
+ switch ( nMemberId )
+ {
+ case MID_COLUMNARRAY:
+ {
+ return false;
+ }
+ case MID_RIGHT:
+ rVal >>= nRight;
+ break;
+ case MID_LEFT:
+ rVal >>= nLeft;
+ break;
+ case MID_ORTHO:
+ rVal >>= nVal;
+ bOrtho = static_cast<bool>(nVal);
+ break;
+ case MID_ACTUAL:
+ rVal >>= nVal;
+ nActColumn = static_cast<sal_uInt16>(nVal);
+ break;
+ case MID_TABLE:
+ rVal >>= nVal;
+ bTable = static_cast<bool>(nVal);
+ break;
+ default:
+ OSL_FAIL("Wrong MemberId!");
+ return false;
+ }
+
+ return true;
+}
+
+sal_uInt16 SvxColumnItem::Count() const
+{
+ return aColumns.size();
+}
+
+SvxColumnDescription& SvxColumnItem::At(sal_uInt16 index)
+{
+ return aColumns[index];
+}
+
+SvxColumnDescription& SvxColumnItem::GetActiveColumnDescription()
+{
+ return aColumns[GetActColumn()];
+}
+
+SvxColumnDescription& SvxColumnItem::operator[](sal_uInt16 index)
+{
+ return aColumns[index];
+}
+
+const SvxColumnDescription& SvxColumnItem::operator[](sal_uInt16 index) const
+{
+ return aColumns[index];
+}
+
+void SvxColumnItem::Append(const SvxColumnDescription &rDesc)
+{
+ aColumns.push_back(rDesc);
+}
+
+void SvxColumnItem::SetLeft(tools::Long left)
+{
+ nLeft = left;
+}
+
+void SvxColumnItem::SetRight(tools::Long right)
+{
+ nRight = right;
+}
+
+
+bool SvxColumnItem::IsFirstAct() const
+{
+ return nActColumn == 0;
+}
+
+bool SvxColumnItem::IsLastAct() const
+{
+ return nActColumn == Count() - 1;
+}
+
+SvxColumnDescription::SvxColumnDescription(tools::Long start, tools::Long end, bool bVis) :
+ nStart (start),
+ nEnd (end),
+ bVisible (bVis),
+ nEndMin (0),
+ nEndMax (0)
+{}
+
+SvxColumnDescription::SvxColumnDescription(tools::Long start, tools::Long end, tools::Long endMin, tools::Long endMax, bool bVis) :
+ nStart (start),
+ nEnd (end),
+ bVisible (bVis),
+ // fdo#85858 hack: clamp these to smaller value to prevent overflow
+ nEndMin(std::min<tools::Long>(endMin, std::numeric_limits<unsigned short>::max())),
+ nEndMax(std::min<tools::Long>(endMax, std::numeric_limits<unsigned short>::max()))
+{}
+
+bool SvxColumnDescription::operator==(const SvxColumnDescription& rCmp) const
+{
+ return nStart == rCmp.nStart
+ && bVisible == rCmp.bVisible
+ && nEnd == rCmp.nEnd
+ && nEndMin == rCmp.nEndMin
+ && nEndMax == rCmp.nEndMax;
+}
+
+bool SvxColumnDescription::operator!=(const SvxColumnDescription& rCmp) const
+{
+ return !operator==(rCmp);
+}
+
+tools::Long SvxColumnDescription::GetWidth() const
+{
+ return nEnd - nStart;
+}
+
+/* SvxColumnItem */
+void SvxColumnItem::SetOrtho(bool bVal)
+{
+ bOrtho = bVal;
+}
+
+bool SvxColumnItem::IsConsistent() const
+{
+ return nActColumn < aColumns.size();
+}
+
+bool SvxObjectItem::operator==( const SfxPoolItem& rCmp ) const
+{
+ return SfxPoolItem::operator==(rCmp) &&
+ nStartX == static_cast<const SvxObjectItem&>(rCmp).nStartX &&
+ nEndX == static_cast<const SvxObjectItem&>(rCmp).nEndX &&
+ nStartY == static_cast<const SvxObjectItem&>(rCmp).nStartY &&
+ nEndY == static_cast<const SvxObjectItem&>(rCmp).nEndY &&
+ bLimits == static_cast<const SvxObjectItem&>(rCmp).bLimits;
+}
+
+bool SvxObjectItem::GetPresentation(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& /*rText*/,
+ const IntlWrapper& /*rWrapper*/ ) const
+{
+ return false;
+}
+
+SvxObjectItem* SvxObjectItem::Clone(SfxItemPool *) const
+{
+ return new SvxObjectItem(*this);
+}
+
+SvxObjectItem::SvxObjectItem( tools::Long nSX, tools::Long nEX,
+ tools::Long nSY, tools::Long nEY ) :
+ SfxPoolItem (SID_RULER_OBJECT),
+ nStartX (nSX),
+ nEndX (nEX),
+ nStartY (nSY),
+ nEndY (nEY),
+ bLimits (false)
+{}
+
+bool SvxObjectItem::QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId ) const
+{
+ nMemberId &= ~CONVERT_TWIPS;
+ switch (nMemberId)
+ {
+ case MID_START_X:
+ rVal <<= nStartX;
+ break;
+ case MID_START_Y:
+ rVal <<= nStartY;
+ break;
+ case MID_END_X:
+ rVal <<= nEndX;
+ break;
+ case MID_END_Y:
+ rVal <<= nEndY;
+ break;
+ case MID_LIMIT:
+ rVal <<= bLimits;
+ break;
+ default:
+ OSL_FAIL( "Wrong MemberId" );
+ return false;
+ }
+
+ return true;
+}
+
+bool SvxObjectItem::PutValue( const css::uno::Any& rVal, sal_uInt8 nMemberId )
+{
+ nMemberId &= ~CONVERT_TWIPS;
+ bool bRet = false;
+ switch (nMemberId)
+ {
+ case MID_START_X:
+ bRet = (rVal >>= nStartX);
+ break;
+ case MID_START_Y:
+ bRet = (rVal >>= nStartY);
+ break;
+ case MID_END_X:
+ bRet = (rVal >>= nEndX);
+ break;
+ case MID_END_Y:
+ bRet = (rVal >>= nEndY);
+ break;
+ case MID_LIMIT:
+ bRet = (rVal >>= bLimits);
+ break;
+ default: OSL_FAIL( "Wrong MemberId" );
+ }
+
+ return bRet;
+}
+
+
+void SvxObjectItem::SetStartX(tools::Long lValue)
+{
+ nStartX = lValue;
+}
+
+void SvxObjectItem::SetEndX(tools::Long lValue)
+{
+ nEndX = lValue;
+}
+
+void SvxObjectItem::SetStartY(tools::Long lValue)
+{
+ nStartY = lValue;
+}
+
+void SvxObjectItem::SetEndY(tools::Long lValue)
+{
+ nEndY = lValue;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/samecontentlistbox.cxx b/svx/source/dialog/samecontentlistbox.cxx
new file mode 100644
index 0000000000..66c628a1e7
--- /dev/null
+++ b/svx/source/dialog/samecontentlistbox.cxx
@@ -0,0 +1,39 @@
+/* -*- 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 <svx/dialmgr.hxx>
+#include <svx/samecontentlistbox.hxx>
+#include <samecontent.hrc>
+
+namespace SameContentListBox
+{
+ void Fill(weld::ComboBox& rComboBox)
+ {
+ rComboBox.clear();
+ for (size_t i = 0; i < SAL_N_ELEMENTS(RID_SVXSTRARY_SAMECONTENT); ++i)
+ {
+ OUString aStr = SvxResId(RID_SVXSTRARY_SAMECONTENT[i].first);
+ sal_uInt32 nData = RID_SVXSTRARY_SAMECONTENT[i].second;
+ rComboBox.append(OUString::number(nData), aStr);
+ }
+ rComboBox.set_active(0);
+ rComboBox.set_size_request(150, -1);
+ }
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/searchcharmap.cxx b/svx/source/dialog/searchcharmap.cxx
new file mode 100644
index 0000000000..2a770eac57
--- /dev/null
+++ b/svx/source/dialog/searchcharmap.cxx
@@ -0,0 +1,323 @@
+/* -*- 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_wasm_strip.h>
+
+#include <vcl/event.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/virdev.hxx>
+
+#include <svx/ucsubset.hxx>
+#include <unordered_map>
+
+#include <svx/searchcharmap.hxx>
+
+#include <charmapacc.hxx>
+
+#include <rtl/ustrbuf.hxx>
+
+using namespace ::com::sun::star::accessibility;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star;
+
+
+SvxSearchCharSet::SvxSearchCharSet(std::unique_ptr<weld::ScrolledWindow> pScrolledWindow, const VclPtr<VirtualDevice>& rVirDev)
+ : SvxShowCharSet(std::move(pScrolledWindow), rVirDev)
+{
+}
+
+int SvxSearchCharSet::LastInView() const
+{
+ int nIndex = FirstInView();
+ nIndex += ROW_COUNT * COLUMN_COUNT - 1;
+ return std::min<int>(nIndex, getMaxCharCount() -1);
+}
+
+bool SvxSearchCharSet::KeyInput(const KeyEvent& rKEvt)
+{
+ vcl::KeyCode aCode = rKEvt.GetKeyCode();
+
+ if (aCode.GetModifier())
+ return false;
+
+ int tmpSelected = nSelectedIndex;
+
+ bool bRet = true;
+
+ switch (aCode.GetCode())
+ {
+ case KEY_RETURN:
+ return SvxShowCharSet::KeyInput(rKEvt);
+ case KEY_SPACE:
+ aDoubleClkHdl.Call(this);
+ return true;
+ case KEY_LEFT:
+ --tmpSelected;
+ break;
+ case KEY_RIGHT:
+ ++tmpSelected;
+ break;
+ case KEY_UP:
+ tmpSelected -= COLUMN_COUNT;
+ break;
+ case KEY_DOWN:
+ tmpSelected += COLUMN_COUNT;
+ break;
+ case KEY_PAGEUP:
+ tmpSelected -= ROW_COUNT * COLUMN_COUNT;
+ break;
+ case KEY_PAGEDOWN:
+ tmpSelected += ROW_COUNT * COLUMN_COUNT;
+ break;
+ case KEY_HOME:
+ tmpSelected = 0;
+ break;
+ case KEY_END:
+ tmpSelected = getMaxCharCount() - 1;
+ break;
+ case KEY_TAB: // some fonts have a character at these unicode control codes
+ case KEY_ESCAPE:
+ bRet = false;
+ tmpSelected = - 1; // mark as invalid
+ break;
+ default:
+ tmpSelected = -1;
+ bRet = false;
+ break;
+ }
+
+ if ( tmpSelected >= 0 )
+ {
+ SelectIndex( tmpSelected, true );
+ aPreSelectHdl.Call( this );
+ }
+
+ return bRet;
+}
+
+void SvxSearchCharSet::SelectCharacter( const Subset* sub )
+{
+ if (!mxFontCharMap.is())
+ RecalculateFont(*mxVirDev);
+
+ // get next available char of current font
+ sal_UCS4 cChar = sub->GetRangeMin();
+ int nMapIndex = 0;
+
+ while(cChar <= sub->GetRangeMax() && nMapIndex == 0)
+ {
+ auto it = std::find_if(m_aItemList.begin(), m_aItemList.end(),
+ [&cChar](const std::pair<const sal_Int32, sal_UCS4>& rItem) { return rItem.second == cChar; });
+ if (it != m_aItemList.end())
+ nMapIndex = it->first;
+ cChar++;
+ }
+
+ if(nMapIndex == 0)
+ SelectIndex( 0 );
+ else
+ SelectIndex( nMapIndex );
+ aHighHdl.Call(this);
+ // move selected item to top row if not in focus
+ //TO.DO aVscrollSB->SetThumbPos( nMapIndex / COLUMN_COUNT );
+ Invalidate();
+}
+
+sal_UCS4 SvxSearchCharSet::GetCharFromIndex(int index) const
+{
+ std::unordered_map<sal_Int32, sal_UCS4>::const_iterator got = m_aItemList.find(index);
+ return (got != m_aItemList.end()) ? got->second : 0;
+}
+
+void SvxSearchCharSet::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ InitSettings(rRenderContext);
+ RecalculateFont(rRenderContext);
+ DrawChars_Impl(rRenderContext, FirstInView(), LastInView());
+}
+
+sal_UCS4 SvxSearchCharSet::GetSelectCharacter() const
+{
+ if( nSelectedIndex >= 0 )
+ {
+ std::unordered_map<sal_Int32,sal_UCS4>::const_iterator got = m_aItemList.find (nSelectedIndex);
+
+ if(got == m_aItemList.end())
+ return 1;
+ else
+ return got->second;
+ }
+ return 1;
+}
+
+void SvxSearchCharSet::RecalculateFont(vcl::RenderContext& rRenderContext)
+{
+ if (!mbRecalculateFont)
+ return;
+
+ Size aSize(GetOutputSizePixel());
+
+ vcl::Font aFont = rRenderContext.GetFont();
+ aFont.SetWeight(WEIGHT_LIGHT);
+ aFont.SetAlignment(ALIGN_TOP);
+ int nFontHeight = (aSize.Height() - 5) * 2 / (3 * ROW_COUNT);
+ maFontSize = rRenderContext.PixelToLogic(Size(0, nFontHeight));
+ aFont.SetFontSize(maFontSize);
+ aFont.SetTransparent(true);
+ rRenderContext.SetFont(aFont);
+ rRenderContext.GetFontCharMap(mxFontCharMap);
+ m_aItems.clear();
+ getFavCharacterList();
+
+ nX = aSize.Width() / COLUMN_COUNT;
+ nY = aSize.Height() / ROW_COUNT;
+
+ UpdateScrollRange();
+
+ // rearrange CharSet element in sync with nX- and nY-multiples
+ Size aDrawSize(nX * COLUMN_COUNT, nY * ROW_COUNT);
+ m_nXGap = (aSize.Width() - aDrawSize.Width()) / 2;
+ m_nYGap = (aSize.Height() - aDrawSize.Height()) / 2;
+
+ mbRecalculateFont = false;
+}
+
+void SvxSearchCharSet::UpdateScrollRange()
+{
+ //scrollbar settings
+ int nLastRow = (getMaxCharCount() - 1 + COLUMN_COUNT) / COLUMN_COUNT;
+ mxScrollArea->vadjustment_configure(mxScrollArea->vadjustment_get_value(), 0, nLastRow, 1, ROW_COUNT - 1, ROW_COUNT);
+}
+
+void SvxSearchCharSet::SelectIndex(int nNewIndex, bool bFocus)
+{
+ if (!mxFontCharMap.is())
+ RecalculateFont(*mxVirDev);
+
+ if( nNewIndex < 0 )
+ {
+ mxScrollArea->vadjustment_set_value(0);
+ nSelectedIndex = bFocus ? 0 : -1;
+ Invalidate();
+ }
+ else if( nNewIndex < FirstInView() )
+ {
+ // need to scroll up to see selected item
+ int nOldPos = mxScrollArea->vadjustment_get_value();
+ int nDelta = (FirstInView() - nNewIndex + COLUMN_COUNT-1) / COLUMN_COUNT;
+ mxScrollArea->vadjustment_set_value(nOldPos - nDelta);
+ nSelectedIndex = nNewIndex;
+ Invalidate();
+ }
+ else if( nNewIndex > LastInView() )
+ {
+ // need to scroll down to see selected item
+ int nOldPos = mxScrollArea->vadjustment_get_value();
+ int nDelta = (nNewIndex - LastInView() + COLUMN_COUNT) / COLUMN_COUNT;
+ mxScrollArea->vadjustment_set_value(nOldPos + nDelta);
+
+ if (nNewIndex < getMaxCharCount())
+ {
+ nSelectedIndex = nNewIndex;
+ Invalidate();
+ }
+ else if (nOldPos != mxScrollArea->vadjustment_get_value())
+ {
+ Invalidate();
+ }
+ }
+ else
+ {
+ nSelectedIndex = nNewIndex;
+ Invalidate();
+ }
+
+ if( nSelectedIndex >= 0 )
+ {
+#if 0
+ if( m_xAccessible.is() )
+ {
+ svx::SvxShowCharSetItem* pItem = ImplGetItem(nSelectedIndex);
+ // Don't fire the focus event.
+ if ( bFocus )
+ m_xAccessible->fireEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, Any(), makeAny(pItem->GetAccessible()) ); // this call assures that m_pItem is set
+ else
+ m_xAccessible->fireEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED_NOFOCUS, Any(), makeAny(pItem->GetAccessible()) ); // this call assures that m_pItem is set
+
+ assert(pItem->m_xItem.is() && "No accessible created!");
+ Any aOldAny, aNewAny;
+ aNewAny <<= AccessibleStateType::FOCUSED;
+ // Don't fire the focus event.
+ if ( bFocus )
+ pItem->m_xItem->fireEvent( AccessibleEventId::STATE_CHANGED, aOldAny, aNewAny );
+
+ aNewAny <<= AccessibleStateType::SELECTED;
+ pItem->m_xItem->fireEvent( AccessibleEventId::STATE_CHANGED, aOldAny, aNewAny );
+ }
+#endif
+ aSelectHdl.Call(this);
+ }
+ aHighHdl.Call( this );
+}
+
+SvxSearchCharSet::~SvxSearchCharSet()
+{
+}
+
+svx::SvxShowCharSetItem* SvxSearchCharSet::ImplGetItem( int _nPos )
+{
+ ItemsMap::iterator aFind = m_aItems.find(_nPos);
+ if ( aFind == m_aItems.end() )
+ {
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ OSL_ENSURE(m_xAccessible.is(), "Who wants to create a child of my table without a parent?");
+#endif
+ auto xItem = std::make_shared<svx::SvxShowCharSetItem>(*this,
+ m_xAccessible.get(), sal::static_int_cast< sal_uInt16 >(_nPos));
+ aFind = m_aItems.emplace(_nPos, xItem).first;
+ OUStringBuffer buf;
+ std::unordered_map<sal_Int32,sal_UCS4>::const_iterator got = m_aItemList.find (_nPos);
+ if (got != m_aItemList.end())
+ buf.appendUtf32(got->second);
+ aFind->second->maText = buf.makeStringAndClear();
+ Point pix = MapIndexToPixel( _nPos );
+ aFind->second->maRect = tools::Rectangle( Point( pix.X() + 1, pix.Y() + 1 ), Size(nX-1,nY-1) );
+ }
+
+ return aFind->second.get();
+}
+
+sal_Int32 SvxSearchCharSet::getMaxCharCount() const
+{
+ return m_aItemList.size();
+}
+
+void SvxSearchCharSet::ClearPreviousData()
+{
+ m_aItemList.clear();
+ Invalidate();
+}
+
+void SvxSearchCharSet::AppendCharToList(sal_UCS4 sChar)
+{
+ m_aItemList.insert(std::make_pair(m_aItemList.size(), sChar));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/signaturelinehelper.cxx b/svx/source/dialog/signaturelinehelper.cxx
new file mode 100644
index 0000000000..2c055e84db
--- /dev/null
+++ b/svx/source/dialog/signaturelinehelper.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 <svx/signaturelinehelper.hxx>
+
+#include <com/sun/star/drawing/XShape.hpp>
+#include <com/sun/star/graphic/GraphicProvider.hpp>
+#include <com/sun/star/security/DocumentDigitalSignatures.hpp>
+
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/sequenceashashmap.hxx>
+#include <comphelper/storagehelper.hxx>
+#include <comphelper/xmlsechelper.hxx>
+#include <config_folders.h>
+#include <rtl/bootstrap.hxx>
+#include <sal/log.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/docfilt.hxx>
+#include <sfx2/objsh.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+#include <svx/svdmark.hxx>
+#include <svx/svdview.hxx>
+#include <tools/stream.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <unotools/streamwrap.hxx>
+#include <unotools/syslocale.hxx>
+#include <vcl/weld.hxx>
+
+using namespace com::sun::star;
+
+namespace svx::SignatureLineHelper
+{
+OUString getSignatureImage(const OUString& rType)
+{
+ OUString aType = rType;
+ if (aType.isEmpty())
+ {
+ aType = "signature-line.svg";
+ }
+ OUString aPath("$BRAND_BASE_DIR/" LIBO_SHARE_FOLDER "/filter/" + aType);
+ rtl::Bootstrap::expandMacros(aPath);
+ SvFileStream aStream(aPath, StreamMode::READ);
+ if (aStream.GetError() != ERRCODE_NONE)
+ {
+ SAL_WARN("cui.dialogs", "failed to open " << aType);
+ }
+
+ OString const svg = read_uInt8s_ToOString(aStream, aStream.remainingSize());
+ return OUString::fromUtf8(svg);
+}
+
+uno::Reference<security::XCertificate> getSignatureCertificate(SfxObjectShell* pShell,
+ weld::Window* pParent)
+{
+ if (!pShell)
+ {
+ return {};
+ }
+
+ if (!pParent)
+ {
+ return {};
+ }
+
+ uno::Reference<security::XDocumentDigitalSignatures> xSigner;
+ if (pShell->GetMedium()->GetFilter()->IsAlienFormat())
+ {
+ xSigner = security::DocumentDigitalSignatures::createDefault(
+ comphelper::getProcessComponentContext());
+ }
+ else
+ {
+ OUString const aODFVersion(
+ comphelper::OStorageHelper::GetODFVersionFromStorage(pShell->GetStorage()));
+ xSigner = security::DocumentDigitalSignatures::createWithVersion(
+ comphelper::getProcessComponentContext(), aODFVersion);
+ }
+ xSigner->setParentWindow(pParent->GetXWindow());
+ OUString aDescription;
+ security::CertificateKind certificateKind = security::CertificateKind_NONE;
+ // When signing ooxml, we only want X.509 certificates
+ if (pShell->GetMedium()->GetFilter()->IsAlienFormat())
+ {
+ certificateKind = security::CertificateKind_X509;
+ }
+ uno::Reference<security::XCertificate> xSignCertificate
+ = xSigner->selectSigningCertificateWithType(certificateKind, aDescription);
+ return xSignCertificate;
+}
+
+OUString getSignerName(const css::uno::Reference<css::security::XCertificate>& xCertificate)
+{
+ return comphelper::xmlsec::GetContentPart(xCertificate->getSubjectName(),
+ xCertificate->getCertificateKind());
+}
+
+OUString getLocalizedDate()
+{
+ const SvtSysLocale aSysLocale;
+ const LocaleDataWrapper& rLocaleData = aSysLocale.GetLocaleData();
+ Date aDateTime(Date::SYSTEM);
+ return rLocaleData.getDate(aDateTime);
+}
+
+uno::Reference<graphic::XGraphic> importSVG(std::u16string_view rSVG)
+{
+ SvMemoryStream aSvgStream(4096, 4096);
+ aSvgStream.WriteOString(OUStringToOString(rSVG, RTL_TEXTENCODING_UTF8));
+ uno::Reference<io::XInputStream> xInputStream(new utl::OSeekableInputStreamWrapper(aSvgStream));
+ uno::Reference<uno::XComponentContext> xContext(comphelper::getProcessComponentContext());
+ uno::Reference<graphic::XGraphicProvider> xProvider
+ = graphic::GraphicProvider::create(xContext);
+
+ uno::Sequence<beans::PropertyValue> aMediaProperties{ comphelper::makePropertyValue(
+ "InputStream", xInputStream) };
+ uno::Reference<graphic::XGraphic> xGraphic(xProvider->queryGraphic(aMediaProperties));
+ return xGraphic;
+}
+
+void setShapeCertificate(const SdrView* pView,
+ const css::uno::Reference<css::security::XCertificate>& xCertificate)
+{
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+ if (rMarkList.GetMarkCount() < 1)
+ {
+ return;
+ }
+
+ const SdrMark* pMark = rMarkList.GetMark(0);
+ SdrObject* pSignatureLine = pMark->GetMarkedSdrObj();
+ if (!pSignatureLine)
+ {
+ return;
+ }
+
+ // Remember the selected certificate.
+ uno::Reference<drawing::XShape> xShape = pSignatureLine->getUnoShape();
+ uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
+ comphelper::SequenceAsHashMap aMap(xShapeProps->getPropertyValue("InteropGrabBag"));
+ aMap["SignatureCertificate"] <<= xCertificate;
+ xShapeProps->setPropertyValue("InteropGrabBag", uno::Any(aMap.getAsConstPropertyValueList()));
+
+ // Read svg and replace placeholder texts.
+ OUString aSvgImage(svx::SignatureLineHelper::getSignatureImage("signature-line-draw.svg"));
+ aSvgImage = aSvgImage.replaceAll("[SIGNED_BY]", SvxResId(RID_SVXSTR_SIGNATURELINE_DSIGNED_BY));
+ OUString aSignerName = svx::SignatureLineHelper::getSignerName(xCertificate);
+ aSvgImage = aSvgImage.replaceAll("[SIGNER_NAME]", aSignerName);
+ OUString aDate = svx::SignatureLineHelper::getLocalizedDate();
+ aDate = SvxResId(RID_SVXSTR_SIGNATURELINE_DATE).replaceFirst("%1", aDate);
+ aSvgImage = aSvgImage.replaceAll("[DATE]", aDate);
+
+ uno::Reference<graphic::XGraphic> xGraphic = svx::SignatureLineHelper::importSVG(aSvgImage);
+ xShapeProps->setPropertyValue("Graphic", uno::Any(xGraphic));
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/spacinglistbox.cxx b/svx/source/dialog/spacinglistbox.cxx
new file mode 100644
index 0000000000..90cc689ccc
--- /dev/null
+++ b/svx/source/dialog/spacinglistbox.cxx
@@ -0,0 +1,76 @@
+/* -*- 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 <svx/dialmgr.hxx>
+#include <svx/spacinglistbox.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <spacing.hrc>
+
+namespace SpacingListBox
+{
+ void Fill(SpacingType eType, weld::ComboBox& rComboBox)
+ {
+ auto nSelected = rComboBox.get_active();
+ if (nSelected == -1)
+ nSelected = 0;
+ rComboBox.clear();
+
+ const LocaleDataWrapper& rLocaleData = Application::GetSettings().GetLocaleDataWrapper();
+ OUString sSuffix;
+
+ const measurement* pResources;
+ switch (eType)
+ {
+ case SpacingType::SPACING_INCH:
+ pResources = RID_SVXSTRARY_SPACING_INCH;
+ sSuffix = weld::MetricSpinButton::MetricToString(FieldUnit::INCH);
+ break;
+ case SpacingType::MARGINS_INCH:
+ pResources = RID_SVXSTRARY_MARGINS_INCH;
+ sSuffix = weld::MetricSpinButton::MetricToString(FieldUnit::INCH);
+ break;
+ case SpacingType::SPACING_CM:
+ pResources = RID_SVXSTRARY_SPACING_CM;
+ sSuffix = " " + weld::MetricSpinButton::MetricToString(FieldUnit::CM);
+ break;
+ default:
+ case SpacingType::MARGINS_CM:
+ sSuffix = " " + weld::MetricSpinButton::MetricToString(FieldUnit::CM);
+ pResources = RID_SVXSTRARY_MARGINS_CM;
+ break;
+ }
+
+ while (pResources->key)
+ {
+ OUString sMeasurement = rLocaleData.getNum(pResources->human, 2, true, false) + sSuffix;
+ OUString aStr = SvxResId(pResources->key).replaceFirst("%1", sMeasurement);
+ sal_uInt32 nData = pResources->twips;
+ rComboBox.append(OUString::number(nData), aStr);
+ ++pResources;
+ }
+
+ rComboBox.set_active(nSelected);
+
+ rComboBox.set_size_request(150, -1);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/srchctrl.cxx b/svx/source/dialog/srchctrl.cxx
new file mode 100644
index 0000000000..51c8d03337
--- /dev/null
+++ b/svx/source/dialog/srchctrl.cxx
@@ -0,0 +1,71 @@
+/* -*- 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 <svl/intitem.hxx>
+#include <sfx2/objsh.hxx>
+
+#include <svx/svxids.hrc>
+
+#include "srchctrl.hxx"
+#include <svx/srchdlg.hxx>
+#include <svl/srchitem.hxx>
+
+SvxSearchController::SvxSearchController
+(
+ sal_uInt16 _nId,
+ SfxBindings& rBind,
+ SvxSearchDialog& rDlg
+) :
+ SfxControllerItem( _nId, rBind ),
+
+ rSrchDlg( rDlg )
+{
+}
+
+
+void SvxSearchController::StateChangedAtToolBoxControl( sal_uInt16 nSID, SfxItemState eState,
+ const SfxPoolItem* pState )
+{
+ if ( SfxItemState::DEFAULT == eState )
+ {
+ if ( SID_STYLE_FAMILY1 <= nSID && nSID <= SID_STYLE_FAMILY4 )
+ {
+ SfxObjectShell* pShell = SfxObjectShell::Current();
+
+ if ( pShell && pShell->GetStyleSheetPool() )
+ rSrchDlg.TemplatesChanged_Impl( *pShell->GetStyleSheetPool() );
+ }
+ else if ( SID_SEARCH_OPTIONS == nSID )
+ {
+ DBG_ASSERT( dynamic_cast<const SfxUInt16Item* >(pState) != nullptr, "wrong item type" );
+ SearchOptionFlags nFlags = static_cast<SearchOptionFlags>(static_cast<const SfxUInt16Item*>(pState)->GetValue());
+ rSrchDlg.EnableControls_Impl( nFlags );
+ }
+ else if ( SID_SEARCH_ITEM == nSID )
+ {
+ DBG_ASSERT( dynamic_cast<const SvxSearchItem*>( pState) != nullptr, "wrong item type" );
+ rSrchDlg.SetItem_Impl( static_cast<const SvxSearchItem*>(pState) );
+ }
+ }
+ else if ( SID_SEARCH_OPTIONS == nSID || SID_SEARCH_ITEM == nSID )
+ rSrchDlg.EnableControls_Impl( SearchOptionFlags::NONE );
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/srchctrl.hxx b/svx/source/dialog/srchctrl.hxx
new file mode 100644
index 0000000000..0427575377
--- /dev/null
+++ b/svx/source/dialog/srchctrl.hxx
@@ -0,0 +1,39 @@
+/* -*- 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 .
+ */
+#ifndef INCLUDED_SVX_SOURCE_DIALOG_SRCHCTRL_HXX
+#define INCLUDED_SVX_SOURCE_DIALOG_SRCHCTRL_HXX
+
+#include <sfx2/ctrlitem.hxx>
+class SvxSearchDialog;
+
+class SvxSearchController : public SfxControllerItem
+{
+ SvxSearchDialog& rSrchDlg;
+
+protected:
+ virtual void StateChangedAtToolBoxControl(sal_uInt16, SfxItemState,
+ const SfxPoolItem* pState) override;
+
+public:
+ SvxSearchController(sal_uInt16 nId, SfxBindings& rBnd, SvxSearchDialog& rDlg);
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/srchdlg.cxx b/svx/source/dialog/srchdlg.cxx
new file mode 100644
index 0000000000..f06822ceaf
--- /dev/null
+++ b/svx/source/dialog/srchdlg.cxx
@@ -0,0 +1,2475 @@
+/* -*- 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/diagnose.h>
+#include <vcl/timer.hxx>
+#include <svl/slstitm.hxx>
+#include <svl/itemiter.hxx>
+#include <svl/style.hxx>
+#include <unotools/intlwrapper.hxx>
+#include <unotools/moduleoptions.hxx>
+#include <unotools/searchopt.hxx>
+#include <unotools/syslocale.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/module.hxx>
+#include <sfx2/viewsh.hxx>
+#include <sfx2/basedlgs.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svl/cjkoptions.hxx>
+#include <svl/ctloptions.hxx>
+#include <com/sun/star/awt/XWindow.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/frame/XDispatch.hpp>
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+#include <com/sun/star/frame/XLayoutManager.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/configuration/theDefaultProvider.hpp>
+#include <com/sun/star/frame/ModuleManager.hpp>
+#include <com/sun/star/ui/XUIElement.hpp>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/scopeguard.hxx>
+#include <svl/itempool.hxx>
+
+#include <sfx2/app.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+
+#include <svx/srchdlg.hxx>
+#include <svx/strarray.hxx>
+
+#include <svx/strings.hrc>
+#include <svx/svxids.hrc>
+
+#include <svl/srchitem.hxx>
+#include <svx/pageitem.hxx>
+#include "srchctrl.hxx"
+#include <svx/dialmgr.hxx>
+#include <editeng/brushitem.hxx>
+#include <tools/resary.hxx>
+#include <svx/svxdlg.hxx>
+#include <vcl/toolbox.hxx>
+#include <o3tl/typed_flags_set.hxx>
+#include <comphelper/lok.hxx>
+
+#include <cstdlib>
+#include <memory>
+
+#include <findtextfield.hxx>
+
+#include <svx/labelitemwindow.hxx>
+#include <svx/xdef.hxx>
+#include <officecfg/Office/Common.hxx>
+
+using namespace com::sun::star::i18n;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::accessibility;
+using namespace com::sun::star;
+using namespace comphelper;
+
+
+#define IS_MOBILE (comphelper::LibreOfficeKit::isActive() && SfxViewShell::Current() && SfxViewShell::Current()->isLOKMobilePhone())
+
+enum class ModifyFlags {
+ NONE = 0x000000,
+ Search = 0x000001,
+ Replace = 0x000002,
+ Word = 0x000004,
+ Exact = 0x000008,
+ Backwards = 0x000010,
+ Selection = 0x000020,
+ Regexp = 0x000040,
+ Layout = 0x000080,
+ Similarity = 0x000100,
+ Formulas = 0x000200,
+ Values = 0x000400,
+ CalcNotes = 0x000800,
+ Rows = 0x001000,
+ Columns = 0x002000,
+ AllTables = 0x004000,
+ Notes = 0x008000,
+ Wildcard = 0x010000
+};
+namespace o3tl {
+ template<> struct typed_flags<ModifyFlags> : is_typed_flags<ModifyFlags, 0x01ffff> {};
+}
+
+namespace
+{
+ bool GetCheckBoxValue(const weld::CheckButton& rBox)
+ {
+ return rBox.get_sensitive() && rBox.get_active();
+ }
+
+ bool GetNegatedCheckBoxValue(const weld::CheckButton& rBox)
+ {
+ return rBox.get_sensitive() && !rBox.get_active();
+ }
+}
+
+struct SearchDlg_Impl
+{
+ bool bSaveToModule : 1,
+ bFocusOnSearch : 1;
+ WhichRangesContainer pRanges;
+ Timer aSelectionTimer { "svx SearchDlg_Impl aSelectionTimer" };
+
+ uno::Reference< frame::XDispatch > xCommand1Dispatch;
+ uno::Reference< frame::XDispatch > xCommand2Dispatch;
+ util::URL aCommand1URL;
+ util::URL aCommand2URL;
+
+ SearchDlg_Impl()
+ : bSaveToModule(true)
+ , bFocusOnSearch(true)
+ {
+ aCommand1URL.Complete = aCommand1URL.Main = "vnd.sun.search:SearchViaComponent1";
+ aCommand1URL.Protocol = "vnd.sun.search:";
+ aCommand1URL.Path = "SearchViaComponent1";
+ aCommand2URL.Complete = aCommand2URL.Main = "vnd.sun.search:SearchViaComponent2";
+ aCommand2URL.Protocol = "vnd.sun.search:";
+ aCommand2URL.Path = "SearchViaComponent2";
+ }
+};
+
+static void ListToStrArr_Impl(sal_uInt16 nId, std::vector<OUString>& rStrLst, weld::ComboBox& rCBox, sal_uInt16 nRememberSize)
+{
+ const SfxStringListItem* pSrchItem =
+ static_cast<const SfxStringListItem*>(SfxGetpApp()->GetItem( nId ));
+
+ if (!pSrchItem)
+ return;
+
+ std::vector<OUString> aLst = pSrchItem->GetList();
+
+ if (aLst.size() > nRememberSize)
+ aLst.resize(nRememberSize);
+
+ for (const OUString & s : aLst)
+ {
+ rStrLst.push_back(s);
+ rCBox.append_text(s);
+ }
+}
+
+static void StrArrToList_Impl( TypedWhichId<SfxStringListItem> nId, const std::vector<OUString>& rStrLst )
+{
+ DBG_ASSERT( !rStrLst.empty(), "check in advance");
+ SfxGetpApp()->PutItem( SfxStringListItem( nId, &rStrLst ) );
+}
+
+SearchAttrItemList::SearchAttrItemList( SearchAttrItemList&& rList ) :
+ SrchAttrInfoList(std::move(rList))
+{
+ for ( size_t i = 0; i < size(); ++i )
+ if ( !IsInvalidItem( (*this)[i].pItemPtr ) )
+ (*this)[i].pItemPtr = (*this)[i].pItemPtr->Clone();
+}
+
+SearchAttrItemList::SearchAttrItemList( const SearchAttrItemList& rList ) :
+ SrchAttrInfoList(rList)
+{
+ for ( size_t i = 0; i < size(); ++i )
+ if ( !IsInvalidItem( (*this)[i].pItemPtr ) )
+ (*this)[i].pItemPtr = (*this)[i].pItemPtr->Clone();
+}
+
+SearchAttrItemList::~SearchAttrItemList()
+{
+ Clear();
+}
+
+void SearchAttrItemList::Put( const SfxItemSet& rSet )
+{
+ if ( !rSet.Count() )
+ return;
+
+ SfxItemPool* pPool = rSet.GetPool();
+ SfxItemIter aIter( rSet );
+ SearchAttrInfo aItem;
+ const SfxPoolItem* pItem = aIter.GetCurItem();
+ sal_uInt16 nWhich;
+
+ do
+ {
+ // only test that it is available?
+ if( IsInvalidItem( pItem ) )
+ {
+ nWhich = rSet.GetWhichByOffset( aIter.GetCurPos() );
+ aItem.pItemPtr = pItem;
+ }
+ else
+ {
+ nWhich = pItem->Which();
+ aItem.pItemPtr = pItem->Clone();
+ }
+
+ aItem.nSlot = pPool->GetSlotId( nWhich );
+ Insert( aItem );
+
+ pItem = aIter.NextItem();
+ } while (pItem);
+}
+
+
+SfxItemSet& SearchAttrItemList::Get( SfxItemSet& rSet )
+{
+ SfxItemPool* pPool = rSet.GetPool();
+
+ for ( size_t i = 0; i < size(); ++i )
+ if ( IsInvalidItem( (*this)[i].pItemPtr ) )
+ rSet.InvalidateItem( pPool->GetWhich( (*this)[i].nSlot ) );
+ else
+ rSet.Put( *(*this)[i].pItemPtr );
+ return rSet;
+}
+
+
+void SearchAttrItemList::Clear()
+{
+ for ( size_t i = 0; i < size(); ++i )
+ if ( !IsInvalidItem( (*this)[i].pItemPtr ) )
+ delete (*this)[i].pItemPtr;
+ SrchAttrInfoList::clear();
+}
+
+
+// Deletes the pointer to the items
+void SearchAttrItemList::Remove(size_t nPos)
+{
+ size_t nLen = 1;
+ if ( nPos + nLen > size() )
+ nLen = size() - nPos;
+
+ for ( size_t i = nPos; i < nPos + nLen; ++i )
+ if ( !IsInvalidItem( (*this)[i].pItemPtr ) )
+ delete (*this)[i].pItemPtr;
+
+ SrchAttrInfoList::erase( begin() + nPos, begin() + nPos + nLen );
+}
+
+SvxSearchDialog::SvxSearchDialog(weld::Window* pParent, SfxChildWindow* pChildWin, SfxBindings& rBind)
+ : SfxModelessDialogController(&rBind, pChildWin, pParent,
+ IS_MOBILE ? OUString("svx/ui/findreplacedialog-mobile.ui") : OUString("svx/ui/findreplacedialog.ui"),
+ "FindReplaceDialog")
+ , rBindings(rBind)
+ , m_aPresentIdle("Bring SvxSearchDialog to Foreground")
+ , bWriter(false)
+ , bSearch(true)
+ , bFormat(false)
+ , bReplaceBackwards(false)
+ , nOptions(SearchOptionFlags::ALL)
+ , bSet(false)
+ , bConstruct(true)
+ , nModifyFlag(ModifyFlags::NONE)
+ , pReplaceList(new SearchAttrItemList)
+ , nTransliterationFlags(TransliterationFlags::NONE)
+ , m_xSearchFrame(m_xBuilder->weld_frame("searchframe"))
+ , m_xSearchLB(m_xBuilder->weld_combo_box("searchterm"))
+ , m_xSearchTmplLB(m_xBuilder->weld_combo_box("searchlist"))
+ , m_xSearchAttrText(m_xBuilder->weld_label("searchdesc"))
+ , m_xSearchLabel(m_xBuilder->weld_label("searchlabel"))
+ , m_xSearchIcon(m_xBuilder->weld_image("searchicon"))
+ , m_xSearchBox(m_xBuilder->weld_box("searchbox"))
+ , m_xReplaceFrame(m_xBuilder->weld_frame("replaceframe"))
+ , m_xReplaceLB(m_xBuilder->weld_combo_box("replaceterm"))
+ , m_xReplaceTmplLB(m_xBuilder->weld_combo_box("replacelist"))
+ , m_xReplaceAttrText(m_xBuilder->weld_label("replacedesc"))
+ , m_xSearchBtn(m_xBuilder->weld_button("search"))
+ , m_xBackSearchBtn(m_xBuilder->weld_button("backsearch"))
+ , m_xSearchAllBtn(m_xBuilder->weld_button("searchall"))
+ , m_xReplaceBtn(m_xBuilder->weld_button("replace"))
+ , m_xReplaceAllBtn(m_xBuilder->weld_button("replaceall"))
+ , m_xComponentFrame(m_xBuilder->weld_frame("componentframe"))
+ , m_xSearchComponent1PB(m_xBuilder->weld_button("component1"))
+ , m_xSearchComponent2PB(m_xBuilder->weld_button("component2"))
+ , m_xMatchCaseCB(m_xBuilder->weld_check_button("matchcase"))
+ , m_xSearchFormattedCB(m_xBuilder->weld_check_button("searchformatted"))
+ , m_xWordBtn(m_xBuilder->weld_check_button("wholewords"))
+ , m_xCloseBtn(m_xBuilder->weld_button("close"))
+ , m_xHelpBtn(m_xBuilder->weld_button("help"))
+ , m_xIncludeDiacritics(m_xBuilder->weld_check_button("includediacritics"))
+ , m_xIncludeKashida(m_xBuilder->weld_check_button("includekashida"))
+ , m_xOtherOptionsExpander(m_xBuilder->weld_expander("OptionsExpander"))
+ , m_xSelectionBtn(m_xBuilder->weld_check_button("selection"))
+ , m_xRegExpBtn(m_xBuilder->weld_check_button("regexp"))
+ , m_xWildcardBtn(m_xBuilder->weld_check_button("wildcard"))
+ , m_xSimilarityBox(m_xBuilder->weld_check_button("similarity"))
+ , m_xSimilarityBtn(m_xBuilder->weld_button("similaritybtn"))
+ , m_xLayoutBtn(m_xBuilder->weld_check_button("layout"))
+ , m_xNotesBtn(m_xBuilder->weld_check_button("notes"))
+ , m_xJapMatchFullHalfWidthCB(m_xBuilder->weld_check_button("matchcharwidth"))
+ , m_xJapOptionsCB(m_xBuilder->weld_check_button("soundslike"))
+ , m_xReplaceBackwardsCB(m_xBuilder->weld_check_button("replace_backwards"))
+ , m_xJapOptionsBtn(m_xBuilder->weld_button("soundslikebtn"))
+ , m_xAttributeBtn(m_xBuilder->weld_button("attributes"))
+ , m_xFormatBtn(m_xBuilder->weld_button("format"))
+ , m_xNoFormatBtn(m_xBuilder->weld_button("noformat"))
+ , m_xCalcGrid(m_xBuilder->weld_widget("calcgrid"))
+ , m_xCalcSearchInFT(m_xBuilder->weld_label("searchinlabel"))
+ , m_xCalcSearchInLB(m_xBuilder->weld_combo_box("calcsearchin"))
+ , m_xCalcSearchDirFT(m_xBuilder->weld_label("searchdir"))
+ , m_xRowsBtn(m_xBuilder->weld_radio_button("rows"))
+ , m_xColumnsBtn(m_xBuilder->weld_radio_button("cols"))
+ , m_xAllSheetsCB(m_xBuilder->weld_check_button("allsheets"))
+ , m_xCalcStrFT(m_xBuilder->weld_label("entirecells"))
+{
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ m_xCloseBtn->hide();
+ m_xHelpBtn->hide();
+ }
+
+ m_aPresentIdle.SetTimeout(50);
+ m_aPresentIdle.SetInvokeHandler(LINK(this, SvxSearchDialog, PresentTimeoutHdl_Impl));
+
+ m_xSearchTmplLB->make_sorted();
+ m_xSearchAttrText->hide();
+
+ m_xSearchLabel->set_font_color(Color(0x00, 0x47, 0x85));
+ this->SetSearchLabel(""); // hide the message but keep the box height
+ m_xSearchIcon->set_size_request(24, 24); // vcl/res/infobar.png is 32x32 - too large here
+
+ m_xReplaceTmplLB->make_sorted();
+ m_xReplaceAttrText->hide();
+
+ aCalcStr = m_xCalcStrFT->get_label();
+
+ // m_xSimilarityBtn->set_height_request(m_xSimilarityBox->get_preferred_size().Height());
+ // m_xJapOptionsBtn->set_height_request(m_xJapOptionsCB->get_preferred_size().Height());
+
+ //tdf#122322
+ nRememberSize = officecfg::Office::Common::Misc::FindReplaceRememberedSearches::get();
+ if (nRememberSize<1)
+ nRememberSize = 1; //0 crashes with no results found
+
+ auto nTermWidth = m_xSearchLB->get_approximate_digit_width() * 28;
+ m_xSearchLB->set_size_request(nTermWidth, -1);
+ m_xSearchTmplLB->set_size_request(nTermWidth, -1);
+ m_xReplaceLB->set_size_request(nTermWidth, -1);
+ m_xReplaceTmplLB->set_size_request(nTermWidth, -1);
+
+ Construct_Impl();
+}
+
+IMPL_LINK_NOARG(SvxSearchDialog, PresentTimeoutHdl_Impl, Timer*, void)
+{
+ getDialog()->present();
+}
+
+void SvxSearchDialog::Present()
+{
+ PresentTimeoutHdl_Impl(nullptr);
+ // tdf#133807 try again in a short timeout
+ m_aPresentIdle.Start();
+}
+
+void SvxSearchDialog::ChildWinDispose()
+{
+ rBindings.EnterRegistrations();
+ pSearchController.reset();
+ pOptionsController.reset();
+ pFamilyController.reset();
+ rBindings.LeaveRegistrations();
+ SfxModelessDialogController::ChildWinDispose();
+}
+
+SvxSearchDialog::~SvxSearchDialog()
+{
+ m_aPresentIdle.Stop();
+ pSearchItem.reset();
+ pImpl.reset();
+}
+
+void SvxSearchDialog::Construct_Impl()
+{
+ pImpl.reset( new SearchDlg_Impl() );
+ pImpl->aSelectionTimer.SetTimeout( 500 );
+ pImpl->aSelectionTimer.SetInvokeHandler(
+ LINK( this, SvxSearchDialog, TimeoutHdl_Impl ) );
+ EnableControls_Impl( SearchOptionFlags::NONE );
+
+ // Store old Text from m_xWordBtn
+ aCalcStr += "#";
+ aCalcStr += m_xWordBtn->get_label();
+
+ aLayoutStr = SvxResId( RID_SVXSTR_SEARCH_STYLES );
+ aLayoutWriterStr = SvxResId( RID_SVXSTR_WRITER_STYLES );
+ aLayoutCalcStr = SvxResId( RID_SVXSTR_CALC_STYLES );
+ aStylesStr = m_xLayoutBtn->get_label();
+
+ // Get stored search-strings from the application
+ ListToStrArr_Impl(SID_SEARCHDLG_SEARCHSTRINGS,
+ aSearchStrings, *m_xSearchLB, nRememberSize);
+ ListToStrArr_Impl(SID_SEARCHDLG_REPLACESTRINGS,
+ aReplaceStrings, *m_xReplaceLB, nRememberSize);
+
+ InitControls_Impl();
+
+ // Get attribute sets only once in constructor()
+ const SfxPoolItem* ppArgs[] = { pSearchItem.get(), nullptr };
+ SfxPoolItemHolder aResult(rBindings.GetDispatcher()->Execute(FID_SEARCH_SEARCHSET, SfxCallMode::SLOT, ppArgs));
+ const SvxSetItem* pSrchSetItem(static_cast<const SvxSetItem*>(aResult.getItem()));
+
+ if ( pSrchSetItem )
+ InitAttrList_Impl( &pSrchSetItem->GetItemSet(), nullptr );
+
+ aResult = rBindings.GetDispatcher()->Execute(FID_SEARCH_REPLACESET, SfxCallMode::SLOT, ppArgs);
+ const SvxSetItem* pReplSetItem(static_cast<const SvxSetItem*>(aResult.getItem()));
+
+ if ( pReplSetItem )
+ InitAttrList_Impl( nullptr, &pReplSetItem->GetItemSet() );
+
+ // Create controller and update at once
+ rBindings.EnterRegistrations();
+ pSearchController.reset(
+ new SvxSearchController( SID_SEARCH_ITEM, rBindings, *this ) );
+ pOptionsController.reset(
+ new SvxSearchController( SID_SEARCH_OPTIONS, rBindings, *this ) );
+ rBindings.LeaveRegistrations();
+ rBindings.GetDispatcher()->Execute( FID_SEARCH_ON, SfxCallMode::SLOT, ppArgs );
+ pImpl->aSelectionTimer.Start();
+
+
+ if(!SvtCJKOptions::IsJapaneseFindEnabled())
+ {
+ m_xJapOptionsCB->set_active( false );
+ m_xJapOptionsCB->hide();
+ m_xJapOptionsBtn->hide();
+ }
+ if(!SvtCJKOptions::IsCJKFontEnabled())
+ {
+ m_xJapMatchFullHalfWidthCB->hide();
+ }
+ // Do not disable and hide the m_xIncludeDiacritics button.
+ // Include Diacritics == Not Ignore Diacritics => A does not match A-Umlaut (Diaeresis).
+ // Confusingly these have negated names (following the UI) but the actual
+ // transliteration is to *ignore* diacritics if "included" (sensitive) is
+ // _not_ checked.
+ if(!SvtCTLOptions::IsCTLFontEnabled())
+ {
+ m_xIncludeDiacritics->set_active( true );
+ m_xIncludeKashida->set_active( true );
+ m_xIncludeKashida->hide();
+ }
+ //component extension - show component search buttons if the commands
+ // vnd.sun.star::SearchViaComponent1 and 2 are supported
+ const uno::Reference< frame::XFrame >xFrame = rBindings.GetActiveFrame();
+ const uno::Reference< frame::XDispatchProvider > xDispatchProv(xFrame, uno::UNO_QUERY);
+
+ bool bSearchComponent1 = false;
+ bool bSearchComponent2 = false;
+ if(xDispatchProv.is())
+ {
+ OUString sTarget("_self");
+ pImpl->xCommand1Dispatch = xDispatchProv->queryDispatch(pImpl->aCommand1URL, sTarget, 0);
+ if (pImpl->xCommand1Dispatch.is())
+ bSearchComponent1 = true;
+ pImpl->xCommand2Dispatch = xDispatchProv->queryDispatch(pImpl->aCommand2URL, sTarget, 0);
+ if (pImpl->xCommand2Dispatch.is())
+ bSearchComponent2 = true;
+ }
+
+ if( !(bSearchComponent1 || bSearchComponent2) )
+ return;
+
+ try
+ {
+ uno::Reference< lang::XMultiServiceFactory > xConfigurationProvider =
+ configuration::theDefaultProvider::get( comphelper::getProcessComponentContext() );
+ uno::Sequence< uno::Any > aArgs {
+ Any(OUString( "/org.openoffice.Office.Common/SearchOptions/")) };
+
+ uno::Reference< uno::XInterface > xIFace = xConfigurationProvider->createInstanceWithArguments(
+ "com.sun.star.configuration.ConfigurationUpdateAccess",
+ aArgs);
+ uno::Reference< container::XNameAccess> xDirectAccess(xIFace, uno::UNO_QUERY);
+ if(xDirectAccess.is())
+ {
+ OUString sTemp;
+ uno::Any aRet = xDirectAccess->getByName("ComponentSearchGroupLabel");
+ aRet >>= sTemp;
+ m_xComponentFrame->set_label(sTemp);
+ aRet = xDirectAccess->getByName("ComponentSearchCommandLabel1");
+ aRet >>= sTemp;
+ m_xSearchComponent1PB->set_label( sTemp );
+ aRet = xDirectAccess->getByName("ComponentSearchCommandLabel2");
+ aRet >>= sTemp;
+ m_xSearchComponent2PB->set_label( sTemp );
+ }
+ }
+ catch(uno::Exception&){}
+
+ if(!m_xSearchComponent1PB->get_label().isEmpty() && bSearchComponent1 )
+ {
+ m_xComponentFrame->show();
+ m_xSearchComponent1PB->show();
+ }
+ if( !m_xSearchComponent2PB->get_label().isEmpty() )
+ {
+ m_xComponentFrame->show();
+ m_xSearchComponent2PB->show();
+ }
+}
+
+void SvxSearchDialog::Close()
+{
+ // remember strings
+ if (!aSearchStrings.empty())
+ StrArrToList_Impl( SID_SEARCHDLG_SEARCHSTRINGS, aSearchStrings );
+
+ if (!aReplaceStrings.empty())
+ StrArrToList_Impl( SID_SEARCHDLG_REPLACESTRINGS, aReplaceStrings );
+
+ // save settings to configuration
+ SvtSearchOptions aOpt;
+ aOpt.SetWholeWordsOnly ( m_xWordBtn->get_active() );
+ aOpt.SetBackwards ( m_xReplaceBackwardsCB->get_active() );
+ aOpt.SetUseRegularExpression ( m_xRegExpBtn->get_active() );
+ aOpt.SetUseWildcard ( m_xWildcardBtn->get_active() );
+ aOpt.SetSearchForStyles ( m_xLayoutBtn->get_active() );
+ aOpt.SetSimilaritySearch ( m_xSimilarityBox->get_active() );
+ aOpt.SetUseAsianOptions ( m_xJapOptionsCB->get_active() );
+ aOpt.SetNotes ( m_xNotesBtn->get_active() );
+ aOpt.SetIgnoreDiacritics_CTL ( !m_xIncludeDiacritics->get_active() );
+ aOpt.SetIgnoreKashida_CTL ( !m_xIncludeKashida->get_active() );
+ aOpt.SetSearchFormatted ( m_xSearchFormattedCB->get_active() );
+ aOpt.Commit();
+
+ if (IsClosing())
+ return;
+
+ const SfxPoolItem* ppArgs[] = { pSearchItem.get(), nullptr };
+ rBindings.GetDispatcher()->Execute( FID_SEARCH_OFF, SfxCallMode::SLOT, ppArgs );
+ rBindings.Invalidate(SID_SEARCH_DLG);
+
+ SfxViewFrame* pViewFrame = SfxViewFrame::Current();
+ if (pViewFrame)
+ pViewFrame->ToggleChildWindow(SID_SEARCH_DLG);
+}
+
+TransliterationFlags SvxSearchDialog::GetTransliterationFlags() const
+{
+ if (!m_xMatchCaseCB->get_active())
+ nTransliterationFlags |= TransliterationFlags::IGNORE_CASE;
+ else
+ nTransliterationFlags &= ~TransliterationFlags::IGNORE_CASE;
+ if ( !m_xJapMatchFullHalfWidthCB->get_active())
+ nTransliterationFlags |= TransliterationFlags::IGNORE_WIDTH;
+ else
+ nTransliterationFlags &= ~TransliterationFlags::IGNORE_WIDTH;
+ return nTransliterationFlags;
+}
+
+void SvxSearchDialog::SetSaveToModule(bool b)
+{
+ pImpl->bSaveToModule = b;
+}
+
+void SvxSearchDialog::SetSearchLabel(const OUString& rStr)
+{
+ m_xSearchLabel->set_label(rStr);
+ if (!rStr.isEmpty())
+ {
+ m_xSearchLabel->show();
+ m_xSearchIcon->show();
+ m_xSearchBox->set_background(Color(0xBD, 0xE5, 0xF8)); // same as InfobarType::INFO
+ }
+ else
+ {
+ const Size aSize = m_xSearchBox->get_preferred_size();
+ m_xSearchLabel->hide();
+ m_xSearchIcon->hide();
+ m_xSearchBox->set_size_request(-1, aSize.Height());
+ m_xSearchBox->set_background(COL_TRANSPARENT);
+ }
+}
+
+void SvxSearchDialog::ApplyTransliterationFlags_Impl( TransliterationFlags nSettings )
+{
+ nTransliterationFlags = nSettings;
+ bool bVal(nSettings & TransliterationFlags::IGNORE_CASE);
+ m_xMatchCaseCB->set_active( !bVal );
+ bVal = bool(nSettings & TransliterationFlags::IGNORE_WIDTH);
+ m_xJapMatchFullHalfWidthCB->set_active( !bVal );
+}
+
+
+bool SvxSearchDialog::IsOtherOptionsExpanded() const
+{
+ return m_xReplaceBackwardsCB->get_active() ||
+ m_xSelectionBtn->get_active() ||
+ m_xRegExpBtn->get_active() ||
+ m_xLayoutBtn->get_active() ||
+ m_xSimilarityBox->get_active() ||
+ m_xJapMatchFullHalfWidthCB->get_active() ||
+ m_xJapOptionsCB->get_active() ||
+ m_xWildcardBtn->get_active() ||
+ m_xNotesBtn->get_active() ||
+ m_xIncludeKashida->get_active() ||
+ !m_xIncludeDiacritics->get_active();//tdf#138173
+}
+
+void SvxSearchDialog::Activate()
+{
+ // apply possible transliteration changes of the SvxSearchItem member
+ if (pSearchItem)
+ {
+ m_xMatchCaseCB->set_active( pSearchItem->GetExact() );
+ m_xJapMatchFullHalfWidthCB->set_active( !pSearchItem->IsMatchFullHalfWidthForms() );
+ }
+
+ SfxModelessDialogController::Activate();
+}
+
+void SvxSearchDialog::InitControls_Impl()
+{
+ // CaseSensitives AutoComplete
+ m_xSearchLB->set_entry_completion( true, true );
+ m_xSearchLB->show();
+ m_xReplaceLB->set_entry_completion( true, true );
+ m_xReplaceLB->show();
+
+ m_xFormatBtn->set_sensitive(false);
+ m_xAttributeBtn->set_sensitive(false);
+
+ m_xSearchLB->connect_changed( LINK( this, SvxSearchDialog, ModifyHdl_Impl ) );
+ m_xReplaceLB->connect_changed( LINK( this, SvxSearchDialog, ModifyHdl_Impl ) );
+
+ Link<weld::Widget&,void> aLink = LINK( this, SvxSearchDialog, FocusHdl_Impl );
+ m_xSearchLB->connect_focus_in( aLink );
+ m_xReplaceLB->connect_focus_in( aLink );
+
+ aLink = LINK( this, SvxSearchDialog, LoseFocusHdl_Impl );
+ m_xSearchLB->connect_focus_out( aLink );
+ m_xReplaceLB->connect_focus_out( aLink );
+
+ m_xSearchTmplLB->connect_focus_out( aLink );
+ m_xReplaceTmplLB->connect_focus_out( aLink );
+
+ Link<weld::Button&,void> aLink2 = LINK( this, SvxSearchDialog, CommandHdl_Impl );
+ m_xSearchBtn->connect_clicked( aLink2 );
+ m_xBackSearchBtn->connect_clicked( aLink2 );
+ m_xSearchAllBtn->connect_clicked( aLink2 );
+ m_xReplaceBtn->connect_clicked( aLink2 );
+ m_xReplaceAllBtn->connect_clicked( aLink2 );
+ m_xCloseBtn->connect_clicked( aLink2 );
+ m_xSimilarityBtn->connect_clicked( aLink2 );
+ m_xJapOptionsBtn->connect_clicked( aLink2 );
+ m_xSearchComponent1PB->connect_clicked( aLink2 );
+ m_xSearchComponent2PB->connect_clicked( aLink2 );
+
+ Link<weld::Toggleable&,void> aLink3 = LINK( this, SvxSearchDialog, FlagHdl_Impl );
+ m_xReplaceBackwardsCB->connect_toggled( aLink3 );
+ m_xWordBtn->connect_toggled( aLink3 );
+ m_xSelectionBtn->connect_toggled( aLink3 );
+ m_xMatchCaseCB->connect_toggled( aLink3 );
+ m_xRegExpBtn->connect_toggled( aLink3 );
+ m_xWildcardBtn->connect_toggled( aLink3 );
+ m_xNotesBtn->connect_toggled( aLink3 );
+ m_xSimilarityBox->connect_toggled( aLink3 );
+ m_xJapOptionsCB->connect_toggled( aLink3 );
+ m_xJapMatchFullHalfWidthCB->connect_toggled( aLink3 );
+ m_xIncludeDiacritics->connect_toggled( aLink3 );
+ m_xIncludeKashida->connect_toggled( aLink3 );
+ m_xLayoutBtn->connect_toggled( LINK( this, SvxSearchDialog, TemplateHdl_Impl ) );
+ m_xFormatBtn->connect_clicked( LINK( this, SvxSearchDialog, FormatHdl_Impl ) );
+ m_xNoFormatBtn->connect_clicked(
+ LINK( this, SvxSearchDialog, NoFormatHdl_Impl ) );
+ m_xAttributeBtn->connect_clicked(
+ LINK( this, SvxSearchDialog, AttributeHdl_Impl ) );
+}
+
+namespace
+{
+ SvtModuleOptions::EFactory getModule(SfxBindings const & rBindings)
+ {
+ SvtModuleOptions::EFactory eFactory(SvtModuleOptions::EFactory::UNKNOWN_FACTORY);
+ try
+ {
+ const uno::Reference< frame::XFrame > xFrame =
+ rBindings.GetActiveFrame();
+ uno::Reference< frame::XModuleManager2 > xModuleManager(
+ frame::ModuleManager::create(::comphelper::getProcessComponentContext()));
+
+ OUString aModuleIdentifier = xModuleManager->identify( xFrame );
+ eFactory = SvtModuleOptions::ClassifyFactoryByServiceName(aModuleIdentifier);
+ }
+ catch (const uno::Exception&)
+ {
+ }
+ return eFactory;
+ }
+}
+
+void SvxSearchDialog::ShowOptionalControls_Impl()
+{
+ DBG_ASSERT( pSearchItem, "no search item" );
+
+ SvtModuleOptions::EFactory eFactory = getModule(rBindings);
+ bool bDrawApp = eFactory == SvtModuleOptions::EFactory::DRAW;
+ bool bWriterApp =
+ eFactory == SvtModuleOptions::EFactory::WRITER ||
+ eFactory == SvtModuleOptions::EFactory::WRITERWEB ||
+ eFactory == SvtModuleOptions::EFactory::WRITERGLOBAL;
+ bool bCalcApp = eFactory == SvtModuleOptions::EFactory::CALC;
+
+ m_xLayoutBtn->set_visible(!bDrawApp);
+ m_xNotesBtn->set_visible(bWriterApp);
+ m_xRegExpBtn->set_visible(!bDrawApp);
+ m_xWildcardBtn->set_visible(bCalcApp); /* TODO:WILDCARD enable for other apps if hey handle it */
+ m_xReplaceBackwardsCB->show();
+ m_xSimilarityBox->show();
+ m_xSimilarityBtn->show();
+ m_xSelectionBtn->show();
+ m_xIncludeDiacritics->show();
+ m_xIncludeKashida->set_visible(SvtCTLOptions::IsCTLFontEnabled());
+ m_xJapMatchFullHalfWidthCB->set_visible(SvtCJKOptions::IsCJKFontEnabled());
+ m_xJapOptionsCB->set_visible(SvtCJKOptions::IsJapaneseFindEnabled());
+ m_xJapOptionsBtn->set_visible(SvtCJKOptions::IsJapaneseFindEnabled());
+
+ if (bWriter)
+ {
+ m_xAttributeBtn->show();
+ m_xFormatBtn->show();
+ m_xNoFormatBtn->show();
+ }
+
+ if (bCalcApp)
+ {
+ m_xCalcSearchInFT->show();
+ m_xCalcSearchInLB->show();
+ m_xCalcSearchDirFT->show();
+ m_xRowsBtn->show();
+ m_xColumnsBtn->show();
+ m_xAllSheetsCB->show();
+ m_xSearchFormattedCB->show();
+ }
+}
+
+
+namespace {
+
+class ToggleSaveToModule
+{
+public:
+ ToggleSaveToModule(SvxSearchDialog& rDialog, bool bValue) :
+ mrDialog(rDialog), mbValue(bValue)
+ {
+ mrDialog.SetSaveToModule(mbValue);
+ }
+
+ ~ToggleSaveToModule()
+ {
+ mrDialog.SetSaveToModule(!mbValue);
+ }
+private:
+ SvxSearchDialog& mrDialog;
+ bool mbValue;
+};
+
+}
+
+void SvxSearchDialog::Init_Impl( bool bSearchPattern )
+{
+ DBG_ASSERT( pSearchItem, "SearchItem == 0" );
+
+ // We don't want to save any intermediate state to the module while the
+ // dialog is being initialized.
+ ToggleSaveToModule aNoModuleSave(*this, false);
+ SvtSearchOptions aOpt;
+
+ bWriter = ( pSearchItem->GetAppFlag() == SvxSearchApp::WRITER );
+
+ if ( !( nModifyFlag & ModifyFlags::Word ) )
+ m_xWordBtn->set_active( pSearchItem->GetWordOnly() );
+ if ( !( nModifyFlag & ModifyFlags::Exact ) )
+ m_xMatchCaseCB->set_active( pSearchItem->GetExact() );
+ if ( !( nModifyFlag & ModifyFlags::Backwards ) )
+ m_xReplaceBackwardsCB->set_active( bReplaceBackwards ); //adjustment to replace backwards
+ if ( !( nModifyFlag & ModifyFlags::Notes ) )
+ m_xNotesBtn->set_active( pSearchItem->GetNotes() );
+ if ( !( nModifyFlag & ModifyFlags::Selection ) )
+ m_xSelectionBtn->set_active( pSearchItem->GetSelection() );
+ if ( !( nModifyFlag & ModifyFlags::Regexp ) )
+ m_xRegExpBtn->set_active( pSearchItem->GetRegExp() );
+ if ( !( nModifyFlag & ModifyFlags::Wildcard ) )
+ m_xWildcardBtn->set_active( pSearchItem->GetWildcard() );
+ if ( !( nModifyFlag & ModifyFlags::Layout ) )
+ m_xLayoutBtn->set_active( pSearchItem->GetPattern() );
+ if (m_xNotesBtn->get_active())
+ m_xLayoutBtn->set_sensitive(false);
+ m_xSimilarityBox->set_active( pSearchItem->IsLevenshtein() );
+ if ( m_xJapOptionsCB->get_visible() )
+ m_xJapOptionsCB->set_active( pSearchItem->IsUseAsianOptions() );
+ m_xIncludeDiacritics->set_active( !aOpt.IsIgnoreDiacritics_CTL() );
+ if ( m_xIncludeKashida->get_visible() )
+ m_xIncludeKashida->set_active( !aOpt.IsIgnoreKashida_CTL() );
+ ApplyTransliterationFlags_Impl( pSearchItem->GetTransliterationFlags() );
+
+ ShowOptionalControls_Impl();
+
+ if ( pSearchItem->GetAppFlag() == SvxSearchApp::CALC )
+ {
+ m_xCalcGrid->show();
+ m_xSearchFormattedCB->set_active( aOpt.IsSearchFormatted() );
+ Link<weld::Toggleable&,void> aLink = LINK( this, SvxSearchDialog, FlagHdl_Impl );
+ m_xCalcSearchInLB->connect_changed( LINK( this, SvxSearchDialog, LBSelectHdl_Impl ) );
+ m_xRowsBtn->connect_toggled( aLink );
+ m_xColumnsBtn->connect_toggled( aLink );
+ m_xAllSheetsCB->connect_toggled( aLink );
+ m_xSearchFormattedCB->connect_toggled( aLink );
+
+ ModifyFlags nModifyFlagCheck;
+ switch ( pSearchItem->GetCellType() )
+ {
+ case SvxSearchCellType::FORMULA:
+ nModifyFlagCheck = ModifyFlags::Formulas;
+ break;
+
+ case SvxSearchCellType::VALUE:
+ nModifyFlagCheck = ModifyFlags::Values;
+ break;
+
+ case SvxSearchCellType::NOTE:
+ nModifyFlagCheck = ModifyFlags::CalcNotes;
+ break;
+
+ default:
+ std::abort(); // cannot happen
+ }
+ if ( !(nModifyFlag & nModifyFlagCheck) )
+ m_xCalcSearchInLB->set_active( static_cast<sal_Int32>(pSearchItem->GetCellType()) );
+
+ m_xWordBtn->set_label( aCalcStr.getToken( 0, '#' ) );
+
+ if ( pSearchItem->GetRowDirection() &&
+ !( nModifyFlag & ModifyFlags::Rows ) )
+ m_xRowsBtn->set_active(true);
+ else if ( !pSearchItem->GetRowDirection() &&
+ !( nModifyFlag & ModifyFlags::Columns ) )
+ m_xColumnsBtn->set_active(true);
+
+ if ( !( nModifyFlag & ModifyFlags::AllTables ) )
+ m_xAllSheetsCB->set_active( pSearchItem->IsAllTables() );
+
+ // only look for formatting in Writer
+ m_xFormatBtn->hide();
+ m_xNoFormatBtn->hide();
+ m_xAttributeBtn->hide();
+ }
+ else
+ {
+ m_xSearchFormattedCB->hide();
+ m_xWordBtn->set_label( aCalcStr.getToken( 1, '#' ) );
+
+ if ( pSearchItem->GetAppFlag() == SvxSearchApp::DRAW )
+ {
+ m_xSearchAllBtn->hide();
+
+ m_xRegExpBtn->hide();
+ m_xWildcardBtn->hide();
+ m_xLayoutBtn->hide();
+
+ // only look for formatting in Writer
+ m_xFormatBtn->hide();
+ m_xNoFormatBtn->hide();
+ m_xAttributeBtn->hide();
+ }
+ else
+ {
+ m_xWildcardBtn->hide(); /* TODO:WILDCARD do not hide for other apps if they handle it */
+
+ if ( !pSearchList )
+ {
+ // Get attribute sets, if it not has been done already
+ const SfxPoolItem* ppArgs[] = { pSearchItem.get(), nullptr };
+ SfxPoolItemHolder aResult(rBindings.GetDispatcher()->Execute(FID_SEARCH_SEARCHSET, SfxCallMode::SLOT, ppArgs));
+ const SvxSetItem* pSrchSetItem(static_cast<const SvxSetItem*>(aResult.getItem()));
+
+ if ( pSrchSetItem )
+ InitAttrList_Impl( &pSrchSetItem->GetItemSet(), nullptr );
+
+ aResult = rBindings.GetDispatcher()->Execute(FID_SEARCH_REPLACESET, SfxCallMode::SLOT, ppArgs);
+ const SvxSetItem* pReplSetItem(static_cast<const SvxSetItem*>(aResult.getItem()));
+
+ if ( pReplSetItem )
+ InitAttrList_Impl( nullptr, &pReplSetItem->GetItemSet() );
+ }
+ }
+ }
+
+ // similarity search?
+ if ( !( nModifyFlag & ModifyFlags::Similarity ) )
+ m_xSimilarityBox->set_active( pSearchItem->IsLevenshtein() );
+ bSet = true;
+
+ FlagHdl_Impl(*m_xSimilarityBox);
+ FlagHdl_Impl(*m_xJapOptionsCB);
+
+ bool bDisableSearch = false;
+ SfxViewShell* pViewShell = SfxViewShell::Current();
+
+ if ( pViewShell )
+ {
+ bool bText = !bSearchPattern;
+
+ if ( pViewShell->HasSelection( bText ) )
+ EnableControl_Impl(*m_xSelectionBtn);
+ else
+ {
+ m_xSelectionBtn->set_active( false );
+ m_xSelectionBtn->set_sensitive(false);
+ }
+ }
+
+ // Pattern Search and there were no AttrSets given
+ if ( bSearchPattern )
+ {
+ SfxObjectShell* pShell = SfxObjectShell::Current();
+
+ if ( pShell && pShell->GetStyleSheetPool() )
+ {
+ // Templates designed
+ m_xSearchTmplLB->clear();
+ m_xReplaceTmplLB->clear();
+ SfxStyleSheetBasePool* pStylePool = pShell->GetStyleSheetPool();
+ SfxStyleSheetBase* pBase = pStylePool->First(pSearchItem->GetFamily());
+
+ while ( pBase )
+ {
+ if ( pBase->IsUsed() )
+ m_xSearchTmplLB->append_text( pBase->GetName() );
+ m_xReplaceTmplLB->append_text( pBase->GetName() );
+ pBase = pStylePool->Next();
+ }
+ m_xSearchTmplLB->set_active_text( pSearchItem->GetSearchString() );
+ m_xReplaceTmplLB->set_active_text( pSearchItem->GetReplaceString() );
+
+ }
+ m_xSearchTmplLB->show();
+
+ if ( bConstruct )
+ // Grab focus only after creating
+ m_xSearchTmplLB->grab_focus();
+ m_xReplaceTmplLB->show();
+ m_xSearchLB->hide();
+ m_xReplaceLB->hide();
+
+ m_xWordBtn->set_sensitive(false);
+ m_xRegExpBtn->set_sensitive(false);
+ m_xWildcardBtn->set_sensitive(false);
+ m_xMatchCaseCB->set_sensitive(false);
+
+ bDisableSearch = !m_xSearchTmplLB->get_count();
+ }
+ else
+ {
+ bool bSetSearch = !( nModifyFlag & ModifyFlags::Search );
+ bool bSetReplace = !( nModifyFlag & ModifyFlags::Replace );
+
+ if ( !(pSearchItem->GetSearchString().isEmpty()) && bSetSearch )
+ m_xSearchLB->set_entry_text( pSearchItem->GetSearchString() );
+ else if (!aSearchStrings.empty())
+ {
+ bool bAttributes =
+ ( ( pSearchList && pSearchList->Count() ) ||
+ ( pReplaceList && pReplaceList->Count() ) );
+
+ if ( bSetSearch && !bAttributes )
+ m_xSearchLB->set_entry_text(aSearchStrings[0]);
+
+ OUString aReplaceTxt = pSearchItem->GetReplaceString();
+
+ if (!aReplaceStrings.empty())
+ aReplaceTxt = aReplaceStrings[0];
+
+ if ( bSetReplace && !bAttributes )
+ m_xReplaceLB->set_entry_text( aReplaceTxt );
+ }
+ m_xSearchLB->show();
+
+ if ( bConstruct )
+ // Grab focus only after creating
+ m_xSearchLB->grab_focus();
+ m_xReplaceLB->show();
+ m_xSearchTmplLB->hide();
+ m_xReplaceTmplLB->hide();
+
+ EnableControl_Impl(*m_xRegExpBtn);
+ EnableControl_Impl(*m_xWildcardBtn);
+ EnableControl_Impl(*m_xMatchCaseCB);
+
+ if ( m_xRegExpBtn->get_active() )
+ m_xWordBtn->set_sensitive(false);
+ else
+ EnableControl_Impl(*m_xWordBtn);
+
+ bDisableSearch = m_xSearchLB->get_active_text().isEmpty() &&
+ m_xSearchAttrText->get_label().isEmpty();
+ }
+ FocusHdl_Impl(*m_xSearchLB);
+
+ if ( bDisableSearch )
+ {
+ m_xSearchBtn->set_sensitive(false);
+ m_xBackSearchBtn->set_sensitive(false);
+ m_xSearchAllBtn->set_sensitive(false);
+ m_xReplaceBtn->set_sensitive(false);
+ m_xReplaceAllBtn->set_sensitive(false);
+ m_xComponentFrame->set_sensitive(false);
+ }
+ else
+ {
+ EnableControl_Impl(*m_xSearchBtn);
+ EnableControl_Impl(*m_xBackSearchBtn);
+ EnableControl_Impl(*m_xReplaceBtn);
+ if (!bWriter || !m_xNotesBtn->get_active())
+ {
+ EnableControl_Impl(*m_xSearchAllBtn);
+ EnableControl_Impl(*m_xReplaceAllBtn);
+ }
+ if (bWriter && pSearchItem->GetNotes())
+ {
+ m_xSearchAllBtn->set_sensitive(false);
+ m_xReplaceAllBtn->set_sensitive(false);
+ }
+ }
+
+ if (!m_xSearchAttrText->get_label().isEmpty())
+ EnableControl_Impl(*m_xNoFormatBtn);
+ else
+ m_xNoFormatBtn->set_sensitive(false);
+
+ if ( !pSearchList )
+ {
+ m_xAttributeBtn->set_sensitive(false);
+ m_xFormatBtn->set_sensitive(false);
+ }
+
+ if ( m_xLayoutBtn->get_active() )
+ {
+ pImpl->bSaveToModule = false;
+ TemplateHdl_Impl(*m_xLayoutBtn);
+ pImpl->bSaveToModule = true;
+ }
+}
+
+
+void SvxSearchDialog::InitAttrList_Impl( const SfxItemSet* pSSet,
+ const SfxItemSet* pRSet )
+{
+ if ( !pSSet && !pRSet )
+ return;
+
+ if ( pImpl->pRanges.empty() && pSSet )
+ pImpl->pRanges = pSSet->GetRanges();
+
+ bool bSetOptimalLayoutSize = false;
+
+ // See to it that are the texts of the attributes are correct
+ OUString aDesc;
+
+ if ( pSSet )
+ {
+ pSearchList.reset(new SearchAttrItemList);
+
+ if ( pSSet->Count() )
+ {
+ pSearchList->Put( *pSSet );
+
+ m_xSearchAttrText->set_label( BuildAttrText_Impl( aDesc, true ) );
+
+ if ( !aDesc.isEmpty() )
+ {
+ if (!m_xSearchAttrText->get_visible())
+ {
+ m_xSearchAttrText->show();
+ bSetOptimalLayoutSize = true;
+ }
+ bFormat |= true;
+ }
+ }
+ }
+
+ if ( pRSet )
+ {
+ pReplaceList.reset(new SearchAttrItemList);
+
+ if ( pRSet->Count() )
+ {
+ pReplaceList->Put( *pRSet );
+
+ m_xReplaceAttrText->set_label( BuildAttrText_Impl( aDesc, false ) );
+
+ if ( !aDesc.isEmpty() )
+ {
+ if (!m_xReplaceAttrText->get_visible())
+ {
+ m_xReplaceAttrText->show();
+ bSetOptimalLayoutSize = true;
+ }
+ bFormat |= true;
+ }
+ }
+ }
+
+ if (bSetOptimalLayoutSize)
+ m_xDialog->resize_to_request();
+}
+
+IMPL_LINK( SvxSearchDialog, LBSelectHdl_Impl, weld::ComboBox&, rCtrl, void )
+{
+ ClickHdl_Impl(&rCtrl);
+}
+
+IMPL_LINK( SvxSearchDialog, FlagHdl_Impl, weld::Toggleable&, rCtrl, void )
+{
+ ClickHdl_Impl(&rCtrl);
+}
+
+void SvxSearchDialog::ClickHdl_Impl(const weld::Widget* pCtrl)
+{
+ if ( pCtrl && !bSet )
+ SetModifyFlag_Impl(pCtrl);
+ else
+ bSet = false;
+
+ if (pCtrl == m_xSimilarityBox.get())
+ {
+ bool bIsChecked = m_xSimilarityBox->get_active();
+
+ if ( bIsChecked )
+ {
+ m_xSimilarityBtn->set_sensitive(true);
+ m_xRegExpBtn->set_active( false );
+ m_xRegExpBtn->set_sensitive(false);
+ m_xWildcardBtn->set_active( false );
+ m_xWildcardBtn->set_sensitive(false);
+ EnableControl_Impl(*m_xWordBtn);
+
+ if ( m_xLayoutBtn->get_active() )
+ {
+ EnableControl_Impl(*m_xMatchCaseCB);
+ m_xLayoutBtn->set_active( false );
+ }
+ m_xRegExpBtn->set_sensitive(false);
+ m_xWildcardBtn->set_sensitive(false);
+ m_xLayoutBtn->set_sensitive(false);
+ m_xFormatBtn->set_sensitive(false);
+ m_xNoFormatBtn->set_sensitive(false);
+ m_xAttributeBtn->set_sensitive(false);
+ }
+ else
+ {
+ EnableControl_Impl(*m_xRegExpBtn);
+ EnableControl_Impl(*m_xWildcardBtn);
+ if (!m_xNotesBtn->get_active())
+ EnableControl_Impl(*m_xLayoutBtn);
+ EnableControl_Impl(*m_xFormatBtn);
+ EnableControl_Impl(*m_xAttributeBtn);
+ m_xSimilarityBtn->set_sensitive(false);
+ }
+ pSearchItem->SetLevenshtein( bIsChecked );
+ }
+ else if (pCtrl == m_xNotesBtn.get())
+ {
+ if (m_xNotesBtn->get_active())
+ {
+ m_xLayoutBtn->set_sensitive(false);
+ m_xSearchAllBtn->set_sensitive(false);
+ m_xReplaceAllBtn->set_sensitive(false);
+ }
+ else
+ {
+ EnableControl_Impl(*m_xLayoutBtn);
+ ModifyHdl_Impl(*m_xSearchLB);
+ }
+ }
+ else
+ {
+ if ( m_xLayoutBtn->get_active() && !bFormat )
+ {
+ m_xWordBtn->set_active( false );
+ m_xWordBtn->set_sensitive(false);
+ m_xRegExpBtn->set_active( false );
+ m_xRegExpBtn->set_sensitive(false);
+ m_xWildcardBtn->set_active( false );
+ m_xWildcardBtn->set_sensitive(false);
+ m_xMatchCaseCB->set_active( false );
+ m_xMatchCaseCB->set_sensitive(false);
+ m_xNotesBtn->set_sensitive(false);
+
+ if ( m_xSearchTmplLB->get_count() )
+ {
+ EnableControl_Impl(*m_xSearchBtn);
+ EnableControl_Impl(*m_xBackSearchBtn);
+ EnableControl_Impl(*m_xSearchAllBtn);
+ EnableControl_Impl(*m_xReplaceBtn);
+ EnableControl_Impl(*m_xReplaceAllBtn);
+ }
+ }
+ else
+ {
+ EnableControl_Impl(*m_xRegExpBtn);
+ EnableControl_Impl(*m_xWildcardBtn);
+ EnableControl_Impl(*m_xMatchCaseCB);
+ EnableControl_Impl(*m_xNotesBtn);
+
+ if ( m_xRegExpBtn->get_active() )
+ {
+ m_xWordBtn->set_active( false );
+ m_xWordBtn->set_sensitive(false);
+ m_xWildcardBtn->set_active( false );
+ m_xWildcardBtn->set_sensitive(false);
+ m_xSimilarityBox->set_active( false );
+ m_xSimilarityBox->set_sensitive(false);
+ m_xSimilarityBtn->set_sensitive(false);
+ }
+ else if ( m_xWildcardBtn->get_active() )
+ {
+ m_xRegExpBtn->set_active( false );
+ m_xRegExpBtn->set_sensitive(false);
+ m_xSimilarityBox->set_active( false );
+ m_xSimilarityBox->set_sensitive(false);
+ m_xSimilarityBtn->set_sensitive(false);
+ }
+ else
+ {
+ EnableControl_Impl(*m_xWordBtn);
+ EnableControl_Impl(*m_xSimilarityBox);
+ }
+
+ // Search-string in place? then enable Buttons
+ bSet = true;
+ ModifyHdl_Impl(*m_xSearchLB);
+ }
+ }
+
+ if (pCtrl == m_xAllSheetsCB.get())
+ {
+ bSet = true;
+ ModifyHdl_Impl(*m_xSearchLB);
+ }
+
+ if (pCtrl == m_xJapOptionsCB.get())
+ {
+ bool bEnableJapOpt = m_xJapOptionsCB->get_active();
+ m_xMatchCaseCB->set_sensitive(!bEnableJapOpt );
+ m_xJapMatchFullHalfWidthCB->set_sensitive(!bEnableJapOpt );
+ m_xJapOptionsBtn->set_sensitive( bEnableJapOpt );
+ }
+
+ if ( pImpl->bSaveToModule )
+ SaveToModule_Impl();
+}
+
+IMPL_LINK(SvxSearchDialog, CommandHdl_Impl, weld::Button&, rBtn, void)
+{
+ bool bInclusive = ( m_xLayoutBtn->get_label() == aLayoutStr );
+
+ if ( ( &rBtn == m_xSearchBtn.get() ) ||
+ (&rBtn == m_xBackSearchBtn.get()) ||
+ ( &rBtn == m_xSearchAllBtn.get() )||
+ ( &rBtn == m_xReplaceBtn.get() ) ||
+ ( &rBtn == m_xReplaceAllBtn.get() ) )
+ {
+ if ( m_xLayoutBtn->get_active() && !bInclusive )
+ {
+ pSearchItem->SetSearchString ( m_xSearchTmplLB->get_active_text() );
+ pSearchItem->SetReplaceString( m_xReplaceTmplLB->get_active_text() );
+ }
+ else
+ {
+ pSearchItem->SetSearchString ( m_xSearchLB->get_active_text() );
+ pSearchItem->SetReplaceString( m_xReplaceLB->get_active_text() );
+
+ if ( &rBtn == m_xReplaceBtn.get() )
+ Remember_Impl( m_xReplaceLB->get_active_text(), false );
+ else
+ {
+ Remember_Impl( m_xSearchLB->get_active_text(), true );
+
+ if ( &rBtn == m_xReplaceAllBtn.get() )
+ Remember_Impl( m_xReplaceLB->get_active_text(), false );
+ }
+ }
+
+ pSearchItem->SetRegExp( false );
+ pSearchItem->SetWildcard( false );
+ pSearchItem->SetLevenshtein( false );
+ if (GetCheckBoxValue(*m_xRegExpBtn))
+ pSearchItem->SetRegExp( true );
+ else if (GetCheckBoxValue(*m_xWildcardBtn))
+ pSearchItem->SetWildcard( true );
+ else if (GetCheckBoxValue(*m_xSimilarityBox))
+ pSearchItem->SetLevenshtein( true );
+
+ pSearchItem->SetWordOnly(GetCheckBoxValue(*m_xWordBtn));
+
+ bool bSetBackwards = false;
+ if( &rBtn == m_xBackSearchBtn.get())
+ {
+ bSetBackwards = true;
+ }
+ else if( &rBtn == m_xReplaceBtn.get())
+ {
+ bSetBackwards = GetCheckBoxValue(*m_xReplaceBackwardsCB);
+ bReplaceBackwards = GetCheckBoxValue(*m_xReplaceBackwardsCB);
+ }
+
+ pSearchItem->SetBackward(bSetBackwards);
+
+ pSearchItem->SetNotes(GetCheckBoxValue(*m_xNotesBtn));
+ pSearchItem->SetPattern(GetCheckBoxValue(*m_xLayoutBtn));
+ pSearchItem->SetSelection(GetCheckBoxValue(*m_xSelectionBtn));
+ pSearchItem->SetUseAsianOptions(GetCheckBoxValue(*m_xJapOptionsCB));
+ TransliterationFlags nFlags = GetTransliterationFlags();
+ if( !pSearchItem->IsUseAsianOptions())
+ nFlags &= TransliterationFlags::IGNORE_CASE |
+ TransliterationFlags::IGNORE_WIDTH;
+ if (GetNegatedCheckBoxValue(*m_xIncludeDiacritics))
+ nFlags |= TransliterationFlags::IGNORE_DIACRITICS_CTL;
+ if (GetNegatedCheckBoxValue(*m_xIncludeKashida))
+ nFlags |= TransliterationFlags::IGNORE_KASHIDA_CTL;
+ pSearchItem->SetTransliterationFlags( nFlags );
+
+ if ( !bWriter )
+ {
+ if ( m_xCalcSearchInLB->get_active() != -1)
+ pSearchItem->SetCellType( static_cast<SvxSearchCellType>(m_xCalcSearchInLB->get_active()) );
+
+ pSearchItem->SetRowDirection( m_xRowsBtn->get_active() );
+ pSearchItem->SetAllTables( m_xAllSheetsCB->get_active() );
+ pSearchItem->SetSearchFormatted( m_xSearchFormattedCB->get_active() );
+ }
+
+ if ((&rBtn == m_xSearchBtn.get()) || (&rBtn == m_xBackSearchBtn.get()))
+ pSearchItem->SetCommand( SvxSearchCmd::FIND );
+ else if ( &rBtn == m_xSearchAllBtn.get() )
+ pSearchItem->SetCommand( SvxSearchCmd::FIND_ALL );
+ else if ( &rBtn == m_xReplaceBtn.get() )
+ pSearchItem->SetCommand( SvxSearchCmd::REPLACE );
+ else if ( &rBtn == m_xReplaceAllBtn.get() )
+ pSearchItem->SetCommand( SvxSearchCmd::REPLACE_ALL );
+
+ // when looking for templates, delete format lists
+ if ( !bFormat && pSearchItem->GetPattern() )
+ {
+ if ( pSearchList )
+ pSearchList->Clear();
+
+ if ( pReplaceList )
+ pReplaceList->Clear();
+ }
+ nModifyFlag = ModifyFlags::NONE;
+ const SfxPoolItem* ppArgs[] = { pSearchItem.get(), nullptr };
+ rBindings.ExecuteSynchron( FID_SEARCH_NOW, ppArgs );
+ }
+ else if ( &rBtn == m_xCloseBtn.get() )
+ {
+ if ( !m_xLayoutBtn->get_active() || bInclusive )
+ {
+ OUString aStr( m_xSearchLB->get_active_text() );
+
+ if ( !aStr.isEmpty() )
+ Remember_Impl( aStr, true );
+ aStr = m_xReplaceLB->get_active_text();
+
+ if ( !aStr.isEmpty() )
+ Remember_Impl( aStr, false );
+ }
+ SaveToModule_Impl();
+ Close();
+ }
+ else if (&rBtn == m_xSimilarityBtn.get())
+ {
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractSvxSearchSimilarityDialog> pDlg(pFact->CreateSvxSearchSimilarityDialog(m_xDialog.get(),
+ pSearchItem->IsLEVRelaxed(),
+ pSearchItem->GetLEVOther(),
+ pSearchItem->GetLEVShorter(),
+ pSearchItem->GetLEVLonger() ));
+ if ( executeSubDialog(pDlg.get()) == RET_OK )
+ {
+ pSearchItem->SetLEVRelaxed( pDlg->IsRelaxed() );
+ pSearchItem->SetLEVOther( pDlg->GetOther() );
+ pSearchItem->SetLEVShorter( pDlg->GetShorter() );
+ pSearchItem->SetLEVLonger( pDlg->GetLonger() );
+ SaveToModule_Impl();
+ }
+ }
+ else if (&rBtn == m_xJapOptionsBtn.get())
+ {
+ SfxItemSet aSet( SfxGetpApp()->GetPool() );
+ pSearchItem->SetTransliterationFlags( GetTransliterationFlags() );
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractSvxJSearchOptionsDialog> aDlg(pFact->CreateSvxJSearchOptionsDialog(m_xDialog.get(), aSet,
+ pSearchItem->GetTransliterationFlags() ));
+ int nRet = executeSubDialog(aDlg.get());
+ if (RET_OK == nRet) //! true only if FillItemSet of SvxJSearchOptionsPage returns true
+ {
+ TransliterationFlags nFlags = aDlg->GetTransliterationFlags();
+ pSearchItem->SetTransliterationFlags( nFlags );
+ ApplyTransliterationFlags_Impl( nFlags );
+ }
+ }
+ else if (&rBtn == m_xSearchComponent1PB.get() || &rBtn == m_xSearchComponent2PB.get())
+ {
+ uno::Sequence < beans::PropertyValue > aArgs(2);
+ beans::PropertyValue* pArgs = aArgs.getArray();
+ pArgs[0].Name = "SearchString";
+ pArgs[0].Value <<= m_xSearchLB->get_active_text();
+ pArgs[1].Name = "ParentWindow";
+ pArgs[1].Value <<= m_xDialog->GetXWindow();
+ if (&rBtn == m_xSearchComponent1PB.get())
+ {
+ if ( pImpl->xCommand1Dispatch.is() )
+ pImpl->xCommand1Dispatch->dispatch(pImpl->aCommand1URL, aArgs);
+ }
+ else
+ {
+ if ( pImpl->xCommand2Dispatch.is() )
+ pImpl->xCommand2Dispatch->dispatch(pImpl->aCommand2URL, aArgs);
+ }
+ }
+}
+
+
+IMPL_LINK( SvxSearchDialog, ModifyHdl_Impl, weld::ComboBox&, rEd, void )
+{
+ if ( !bSet )
+ SetModifyFlag_Impl( &rEd );
+ else
+ bSet = false;
+
+ // Calc allows searching for empty cells.
+ bool bAllowEmptySearch = (pSearchItem->GetAppFlag() == SvxSearchApp::CALC);
+
+ if (&rEd != m_xSearchLB.get() && &rEd != m_xReplaceLB.get())
+ return;
+
+ sal_Int32 nSrchTxtLen = m_xSearchLB->get_active_text().getLength();
+ sal_Int32 nReplTxtLen = 0;
+ if (bAllowEmptySearch)
+ nReplTxtLen = m_xReplaceLB->get_active_text().getLength();
+ sal_Int32 nAttrTxtLen = m_xSearchAttrText->get_label().getLength();
+
+ if (nSrchTxtLen || nReplTxtLen || nAttrTxtLen)
+ {
+ EnableControl_Impl(*m_xSearchBtn);
+ EnableControl_Impl(*m_xBackSearchBtn);
+ EnableControl_Impl(*m_xReplaceBtn);
+ if (!bWriter || !m_xNotesBtn->get_active())
+ {
+ EnableControl_Impl(*m_xSearchAllBtn);
+ EnableControl_Impl(*m_xReplaceAllBtn);
+ }
+ }
+ else
+ {
+ m_xComponentFrame->set_sensitive(false);
+ m_xSearchBtn->set_sensitive(false);
+ m_xBackSearchBtn->set_sensitive(false);
+ m_xSearchAllBtn->set_sensitive(false);
+ m_xReplaceBtn->set_sensitive(false);
+ m_xReplaceAllBtn->set_sensitive(false);
+ }
+}
+
+IMPL_LINK_NOARG(SvxSearchDialog, TemplateHdl_Impl, weld::Toggleable&, void)
+{
+ if ( pImpl->bSaveToModule )
+ SaveToModule_Impl();
+
+ if ( bFormat )
+ return;
+ OUString sDesc;
+
+ if ( m_xLayoutBtn->get_active() )
+ {
+ if ( !pFamilyController )
+ {
+ sal_uInt16 nId = 0;
+
+ // Enable templates controller
+ switch ( pSearchItem->GetFamily() )
+ {
+ case SfxStyleFamily::Char:
+ nId = SID_STYLE_FAMILY1; break;
+
+ case SfxStyleFamily::Para:
+ nId = SID_STYLE_FAMILY2; break;
+
+ case SfxStyleFamily::Frame:
+ nId = SID_STYLE_FAMILY3; break;
+
+ case SfxStyleFamily::Page:
+ nId = SID_STYLE_FAMILY4; break;
+
+ case SfxStyleFamily::All:
+ break;
+
+ default:
+ OSL_FAIL( "StyleSheetFamily was changed?" );
+ }
+
+ rBindings.EnterRegistrations();
+ pFamilyController.reset(
+ new SvxSearchController( nId, rBindings, *this ) );
+ rBindings.LeaveRegistrations();
+ m_xSearchTmplLB->clear();
+ m_xReplaceTmplLB->clear();
+
+ m_xSearchTmplLB->show();
+ m_xReplaceTmplLB->show();
+ m_xSearchLB->hide();
+ m_xReplaceLB->hide();
+
+ m_xSearchAttrText->set_label( sDesc );
+ m_xReplaceAttrText->set_label( sDesc );
+
+ if(!sDesc.isEmpty())
+ {
+ if (!m_xReplaceAttrText->get_visible() || !m_xReplaceAttrText->get_visible())
+ {
+ m_xSearchAttrText->show();
+ m_xReplaceAttrText->show();
+ m_xDialog->resize_to_request();
+ }
+ }
+ }
+ m_xFormatBtn->set_sensitive(false);
+ m_xNoFormatBtn->set_sensitive(false);
+ m_xAttributeBtn->set_sensitive(false);
+ m_xSimilarityBox->set_sensitive(false);
+ m_xSimilarityBtn->set_sensitive(false);
+ }
+ else
+ {
+ // Disable templates controller
+ rBindings.EnterRegistrations();
+ pFamilyController.reset();
+ rBindings.LeaveRegistrations();
+
+ m_xSearchLB->show();
+ m_xReplaceLB->show();
+ m_xSearchTmplLB->hide();
+ m_xReplaceTmplLB->hide();
+
+ m_xSearchAttrText->set_label( BuildAttrText_Impl( sDesc, true ) );
+ m_xReplaceAttrText->set_label( BuildAttrText_Impl( sDesc, false ) );
+
+ if(!sDesc.isEmpty())
+ {
+ if (!m_xReplaceAttrText->get_visible() || !m_xReplaceAttrText->get_visible())
+ {
+ m_xSearchAttrText->show();
+ m_xReplaceAttrText->show();
+ m_xDialog->resize_to_request();
+ }
+ }
+
+ EnableControl_Impl(*m_xFormatBtn);
+ EnableControl_Impl(*m_xAttributeBtn);
+ EnableControl_Impl(*m_xSimilarityBox);
+
+ FocusHdl_Impl( bSearch ? *m_xSearchLB : *m_xReplaceLB );
+ }
+ bSet = true;
+ pImpl->bSaveToModule = false;
+ FlagHdl_Impl(*m_xLayoutBtn);
+ pImpl->bSaveToModule = true;
+}
+
+void SvxSearchDialog::Remember_Impl( const OUString &rStr, bool _bSearch )
+{
+ if ( rStr.isEmpty() )
+ return;
+
+ std::vector<OUString>* pArr = _bSearch ? &aSearchStrings : &aReplaceStrings;
+ weld::ComboBox* pListBox = _bSearch ? m_xSearchLB.get() : m_xReplaceLB.get();
+
+ // tdf#154818 - rearrange the search items
+ const auto nPos = pListBox->find_text(rStr);
+ if (nPos != -1)
+ {
+ pListBox->remove(nPos);
+ pArr->erase(pArr->begin() + nPos);
+ }
+ else if (pListBox->get_count() >= nRememberSize)
+ {
+ // delete oldest entry at maximum occupancy (ListBox and Array)
+ pListBox->remove(nRememberSize - 1);
+ pArr->erase(pArr->begin() + nRememberSize - 1);
+ }
+
+ pArr->insert(pArr->begin(), rStr);
+ pListBox->insert_text(0, rStr);
+}
+
+void SvxSearchDialog::TemplatesChanged_Impl( SfxStyleSheetBasePool& rPool )
+{
+ OUString aOldSrch( m_xSearchTmplLB->get_active_text() );
+ OUString aOldRepl( m_xReplaceTmplLB->get_active_text() );
+ m_xSearchTmplLB->clear();
+ m_xReplaceTmplLB->clear();
+ m_xSearchTmplLB->freeze();
+ m_xReplaceTmplLB->freeze();
+ SfxStyleSheetBase* pBase = rPool.First(pSearchItem->GetFamily());
+
+ while ( pBase )
+ {
+ if ( pBase->IsUsed() )
+ m_xSearchTmplLB->append_text( pBase->GetName() );
+ m_xReplaceTmplLB->append_text( pBase->GetName() );
+ pBase = rPool.Next();
+ }
+ m_xSearchTmplLB->thaw();
+ m_xReplaceTmplLB->thaw();
+ m_xSearchTmplLB->set_active(0);
+
+ if ( !aOldSrch.isEmpty() )
+ m_xSearchTmplLB->set_active_text( aOldSrch );
+ m_xReplaceTmplLB->set_active(0);
+
+ if ( !aOldRepl.isEmpty() )
+ m_xReplaceTmplLB->set_active_text( aOldRepl );
+
+ if ( m_xSearchTmplLB->get_count() )
+ {
+ EnableControl_Impl(*m_xSearchBtn);
+ EnableControl_Impl(*m_xBackSearchBtn);
+ EnableControl_Impl(*m_xSearchAllBtn);
+ EnableControl_Impl(*m_xReplaceBtn);
+ EnableControl_Impl(*m_xReplaceAllBtn);
+ }
+}
+
+
+void SvxSearchDialog::EnableControls_Impl( const SearchOptionFlags nFlags )
+{
+ if ( nFlags == nOptions )
+ return;
+ else
+ nOptions = nFlags;
+
+ bool bNoSearch = true;
+
+ bool bEnableSearch = bool( SearchOptionFlags::SEARCH & nOptions );
+ m_xSearchBtn->set_sensitive(bEnableSearch);
+ m_xBackSearchBtn->set_sensitive(bEnableSearch);
+
+ if( bEnableSearch )
+ bNoSearch = false;
+
+
+ if ( SearchOptionFlags::SEARCHALL & nOptions )
+ {
+ m_xSearchAllBtn->set_sensitive(true);
+ bNoSearch = false;
+ }
+ else
+ m_xSearchAllBtn->set_sensitive(false);
+ if ( SearchOptionFlags::REPLACE & nOptions )
+ {
+ m_xReplaceBtn->set_sensitive(true);
+ m_xReplaceFrame->set_sensitive(true);
+ m_xReplaceLB->set_sensitive(true);
+ m_xReplaceTmplLB->set_sensitive(true);
+ bNoSearch = false;
+ }
+ else
+ {
+ m_xReplaceBtn->set_sensitive(false);
+ m_xReplaceFrame->set_sensitive(false);
+ m_xReplaceLB->set_sensitive(false);
+ m_xReplaceTmplLB->set_sensitive(false);
+ }
+ if ( SearchOptionFlags::REPLACE_ALL & nOptions )
+ {
+ m_xReplaceAllBtn->set_sensitive(true);
+ bNoSearch = false;
+ }
+ else
+ m_xReplaceAllBtn->set_sensitive(false);
+ m_xComponentFrame->set_sensitive(!bNoSearch);
+ m_xSearchBtn->set_sensitive( !bNoSearch );
+ m_xBackSearchBtn->set_sensitive( !bNoSearch );
+ m_xSearchFrame->set_sensitive( !bNoSearch );
+ m_xSearchLB->set_sensitive( !bNoSearch );
+ m_xNotesBtn->set_sensitive(true);
+
+ if ( SearchOptionFlags::WHOLE_WORDS & nOptions )
+ m_xWordBtn->set_sensitive(true);
+ else
+ m_xWordBtn->set_sensitive(false);
+ if ( SearchOptionFlags::BACKWARDS & nOptions )
+ {
+ m_xBackSearchBtn->set_sensitive(true);
+ m_xReplaceBackwardsCB->set_sensitive(true);
+ }
+ else
+ {
+ m_xBackSearchBtn->set_sensitive(false);
+ m_xReplaceBackwardsCB->set_sensitive(false);
+ }
+ if ( SearchOptionFlags::REG_EXP & nOptions )
+ m_xRegExpBtn->set_sensitive(true);
+ else
+ m_xRegExpBtn->set_sensitive(false);
+ if ( SearchOptionFlags::WILDCARD & nOptions )
+ m_xWildcardBtn->set_sensitive(true);
+ else
+ m_xWildcardBtn->set_sensitive(false);
+ if ( SearchOptionFlags::EXACT & nOptions )
+ m_xMatchCaseCB->set_sensitive(true);
+ else
+ m_xMatchCaseCB->set_sensitive(false);
+ if ( SearchOptionFlags::SELECTION & nOptions )
+ m_xSelectionBtn->set_sensitive(true);
+ else
+ m_xSelectionBtn->set_sensitive(false);
+ if ( SearchOptionFlags::FAMILIES & nOptions )
+ m_xLayoutBtn->set_sensitive(true);
+ else
+ m_xLayoutBtn->set_sensitive(false);
+ if ( SearchOptionFlags::FORMAT & nOptions )
+ {
+ m_xAttributeBtn->set_sensitive(true);
+ m_xFormatBtn->set_sensitive(true);
+ m_xNoFormatBtn->set_sensitive(true);
+ }
+ else
+ {
+ m_xAttributeBtn->set_sensitive(false);
+ m_xFormatBtn->set_sensitive(false);
+ m_xNoFormatBtn->set_sensitive(false);
+ }
+
+ if ( SearchOptionFlags::SIMILARITY & nOptions )
+ {
+ m_xSimilarityBox->set_sensitive(true);
+ m_xSimilarityBtn->set_sensitive(true);
+ }
+ else
+ {
+ m_xSimilarityBox->set_sensitive(false);
+ m_xSimilarityBtn->set_sensitive(false);
+ }
+
+ if ( pSearchItem )
+ {
+ Init_Impl( pSearchItem->GetPattern() &&
+ ( !pSearchList || !pSearchList->Count() ) );
+ if (SvxSearchDialog::IsOtherOptionsExpanded())
+ m_xOtherOptionsExpander->set_expanded(true);
+ }
+}
+
+void SvxSearchDialog::EnableControl_Impl(const weld::Widget& rCtrl)
+{
+ if (m_xSearchBtn.get() == &rCtrl && ( SearchOptionFlags::SEARCH & nOptions ) )
+ {
+ m_xComponentFrame->set_sensitive(true);
+ m_xSearchBtn->set_sensitive(true);
+ return;
+ }
+ if ( m_xSearchAllBtn.get() == &rCtrl &&
+ ( SearchOptionFlags::SEARCHALL & nOptions ) )
+ {
+ m_xSearchAllBtn->set_sensitive(true);
+ return;
+ }
+ if ( m_xReplaceBtn.get() == &rCtrl && ( SearchOptionFlags::REPLACE & nOptions ) )
+ {
+ m_xReplaceBtn->set_sensitive(true);
+ return;
+ }
+ if ( m_xReplaceAllBtn.get() == &rCtrl &&
+ ( SearchOptionFlags::REPLACE_ALL & nOptions ) )
+ {
+ m_xReplaceAllBtn->set_sensitive(true);
+ return;
+ }
+ if ( m_xWordBtn.get() == &rCtrl && ( SearchOptionFlags::WHOLE_WORDS & nOptions ) )
+ {
+ m_xWordBtn->set_sensitive(true);
+ return;
+ }
+ if ( SearchOptionFlags::BACKWARDS & nOptions )
+ {
+ if( m_xBackSearchBtn.get() == &rCtrl )
+ {
+ m_xBackSearchBtn->set_sensitive(true);
+ return;
+ }
+ else if ( m_xReplaceBackwardsCB.get() == &rCtrl )
+ {
+ m_xReplaceBackwardsCB->set_sensitive(true);
+ return;
+ }
+ }
+ if (m_xNotesBtn.get() == &rCtrl)
+ {
+ m_xNotesBtn->set_sensitive(true);
+ return;
+ }
+ if ( m_xRegExpBtn.get() == &rCtrl && ( SearchOptionFlags::REG_EXP & nOptions )
+ && !m_xSimilarityBox->get_active() && !m_xWildcardBtn->get_active())
+ {
+ m_xRegExpBtn->set_sensitive(true);
+ return;
+ }
+ if ( m_xWildcardBtn.get() == &rCtrl && ( SearchOptionFlags::WILDCARD & nOptions )
+ && !m_xSimilarityBox->get_active() && !m_xRegExpBtn->get_active())
+ {
+ m_xWildcardBtn->set_sensitive(true);
+ return;
+ }
+ if ( m_xMatchCaseCB.get() == &rCtrl && ( SearchOptionFlags::EXACT & nOptions ) )
+ {
+ if (!m_xJapOptionsCB->get_active())
+ m_xMatchCaseCB->set_sensitive(true);
+ return;
+ }
+ if ( m_xSelectionBtn.get() == &rCtrl && ( SearchOptionFlags::SELECTION & nOptions ) )
+ {
+ m_xSelectionBtn->set_sensitive(true);
+ return;
+ }
+ if ( m_xLayoutBtn.get() == &rCtrl && ( SearchOptionFlags::FAMILIES & nOptions ) )
+ {
+ m_xLayoutBtn->set_sensitive(true);
+ return;
+ }
+ if ( m_xAttributeBtn.get() == &rCtrl
+ && ( SearchOptionFlags::FORMAT & nOptions )
+ && pSearchList )
+ {
+ m_xAttributeBtn->set_sensitive( pImpl->bFocusOnSearch );
+ }
+ if ( m_xFormatBtn.get() == &rCtrl && ( SearchOptionFlags::FORMAT & nOptions ) )
+ {
+ m_xFormatBtn->set_sensitive(true);
+ return;
+ }
+ if ( m_xNoFormatBtn.get() == &rCtrl && ( SearchOptionFlags::FORMAT & nOptions ) )
+ {
+ m_xNoFormatBtn->set_sensitive(true);
+ return;
+ }
+ if ( m_xSimilarityBox.get() == &rCtrl && ( SearchOptionFlags::SIMILARITY & nOptions )
+ && !m_xRegExpBtn->get_active() && !m_xWildcardBtn->get_active())
+ {
+ m_xSimilarityBox->set_sensitive(true);
+
+ if ( m_xSimilarityBox->get_active() )
+ m_xSimilarityBtn->set_sensitive(true);
+ }
+}
+
+void SvxSearchDialog::SetItem_Impl( const SvxSearchItem* pItem )
+{
+ //TODO: save pItem and process later if m_executingSubDialog?
+ if ( pItem && !m_executingSubDialog )
+ {
+ pSearchItem.reset(pItem->Clone());
+ Init_Impl( pSearchItem->GetPattern() &&
+ ( !pSearchList || !pSearchList->Count() ) );
+ }
+}
+
+IMPL_LINK(SvxSearchDialog, FocusHdl_Impl, weld::Widget&, rControl, void)
+{
+ sal_Int32 nTxtLen = m_xSearchAttrText->get_label().getLength();
+ weld::Widget* pCtrl = &rControl;
+ if (pCtrl == m_xSearchLB.get())
+ {
+ if (pCtrl->has_focus())
+ pImpl->bFocusOnSearch = true;
+ pCtrl = m_xSearchLB.get();
+ bSearch = true;
+
+ if( nTxtLen )
+ EnableControl_Impl(*m_xNoFormatBtn);
+ else
+ m_xNoFormatBtn->set_sensitive(false);
+ EnableControl_Impl(*m_xAttributeBtn);
+ }
+ else
+ {
+ pImpl->bFocusOnSearch = false;
+ pCtrl = m_xReplaceLB.get();
+ bSearch = false;
+
+ if (!m_xReplaceAttrText->get_label().isEmpty())
+ EnableControl_Impl(*m_xNoFormatBtn);
+ else
+ m_xNoFormatBtn->set_sensitive(false);
+ m_xAttributeBtn->set_sensitive(false);
+ }
+ bSet = true;
+
+ weld::ComboBox &rComboBox = dynamic_cast<weld::ComboBox&>(*pCtrl);
+ rComboBox.select_entry_region(0, -1);
+ ModifyHdl_Impl(rComboBox);
+
+ if (bFormat && nTxtLen)
+ m_xLayoutBtn->set_label(aLayoutStr);
+ else
+ {
+ SvtModuleOptions::EFactory eFactory = getModule(rBindings);
+ bool bWriterApp =
+ eFactory == SvtModuleOptions::EFactory::WRITER ||
+ eFactory == SvtModuleOptions::EFactory::WRITERWEB ||
+ eFactory == SvtModuleOptions::EFactory::WRITERGLOBAL;
+ bool bCalcApp = eFactory == SvtModuleOptions::EFactory::CALC;
+
+ if (bWriterApp)
+ m_xLayoutBtn->set_label(aLayoutWriterStr);
+ else
+ {
+ if (bCalcApp)
+ m_xLayoutBtn->set_label(aLayoutCalcStr);
+ else
+ m_xLayoutBtn->set_label(aStylesStr);
+ }
+ }
+}
+
+IMPL_LINK_NOARG(SvxSearchDialog, LoseFocusHdl_Impl, weld::Widget&, void)
+{
+ SaveToModule_Impl();
+}
+
+IMPL_LINK_NOARG(SvxSearchDialog, FormatHdl_Impl, weld::Button&, void)
+{
+ SfxObjectShell* pSh = SfxObjectShell::Current();
+
+ DBG_ASSERT( pSh, "no DocShell" );
+
+ if ( !pSh || pImpl->pRanges.empty() )
+ return;
+
+ SfxItemPool& rPool = pSh->GetPool();
+ SfxItemSet aSet(rPool, pImpl->pRanges);
+
+ aSet.MergeRange(SID_ATTR_PARA_MODEL, SID_ATTR_PARA_MODEL);
+
+ sal_uInt16 nBrushWhich = pSh->GetPool().GetWhich(SID_ATTR_BRUSH);
+ aSet.MergeRange(nBrushWhich, nBrushWhich);
+
+ aSet.MergeRange(XATTR_FILL_FIRST, XATTR_FILL_LAST);
+
+ OUString aTxt;
+
+ aSet.InvalidateAllItems();
+ aSet.Put(SvxBrushItem(nBrushWhich));
+
+ if ( bSearch )
+ {
+ aTxt = SvxResId( RID_SVXSTR_SEARCH );
+ pSearchList->Get( aSet );
+ }
+ else
+ {
+ aTxt = SvxResId( RID_SVXSTR_REPLACE );
+ pReplaceList->Get( aSet );
+ }
+ aSet.DisableItem(SID_ATTR_PARA_MODEL);
+ aSet.DisableItem(rPool.GetWhich(SID_ATTR_PARA_PAGEBREAK));
+ aSet.DisableItem(rPool.GetWhich(SID_ATTR_PARA_KEEP));
+
+
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<SfxAbstractTabDialog> pDlg(pFact->CreateTabItemDialog(m_xDialog.get(), aSet));
+ pDlg->SetText( aTxt );
+
+ if ( executeSubDialog(pDlg.get()) != RET_OK )
+ return;
+
+ DBG_ASSERT( pDlg->GetOutputItemSet(), "invalid Output-Set" );
+ SfxItemSet aOutSet( *pDlg->GetOutputItemSet() );
+
+ SearchAttrItemList* pList = bSearch ? pSearchList.get() : pReplaceList.get();
+
+ const SfxPoolItem* pItem;
+ for( sal_uInt16 n = 0; n < pList->Count(); ++n )
+ {
+ SearchAttrInfo* pAItem = &pList->GetObject(n);
+ if( !IsInvalidItem( pAItem->pItemPtr ) &&
+ SfxItemState::SET == aOutSet.GetItemState(
+ pAItem->pItemPtr->Which(), false, &pItem ) )
+ {
+ delete pAItem->pItemPtr;
+ pAItem->pItemPtr = pItem->Clone();
+ aOutSet.ClearItem( pAItem->pItemPtr->Which() );
+ }
+ }
+
+ if( aOutSet.Count() )
+ pList->Put( aOutSet );
+
+ PaintAttrText_Impl(); // Set AttributeText in GroupBox
+}
+
+IMPL_LINK_NOARG(SvxSearchDialog, NoFormatHdl_Impl, weld::Button&, void)
+{
+ SvtModuleOptions::EFactory eFactory = getModule(rBindings);
+ bool bWriterApp =
+ eFactory == SvtModuleOptions::EFactory::WRITER ||
+ eFactory == SvtModuleOptions::EFactory::WRITERWEB ||
+ eFactory == SvtModuleOptions::EFactory::WRITERGLOBAL;
+ bool bCalcApp = eFactory == SvtModuleOptions::EFactory::CALC;
+
+ if (bCalcApp)
+ m_xLayoutBtn->set_label( aLayoutCalcStr );
+ else
+ {
+ if (bWriterApp)
+ m_xLayoutBtn->set_label( aLayoutWriterStr);
+ else
+ m_xLayoutBtn->set_label( aStylesStr );
+ }
+
+ bFormat = false;
+ m_xLayoutBtn->set_active( false );
+
+ bool bSetOptimalLayoutSize = false;
+
+ if ( bSearch )
+ {
+ pSearchList->Clear();
+ m_xSearchAttrText->set_label( "" );
+ if (m_xSearchAttrText->get_visible())
+ {
+ m_xSearchAttrText->hide();
+ bSetOptimalLayoutSize = true;
+ }
+ }
+ else
+ {
+ pReplaceList->Clear();
+ m_xReplaceAttrText->set_label( "" );
+ if (m_xReplaceAttrText->get_visible())
+ {
+ m_xReplaceAttrText->hide();
+ bSetOptimalLayoutSize = true;
+ }
+ }
+
+ if (bSetOptimalLayoutSize)
+ m_xDialog->resize_to_request();
+
+ pImpl->bSaveToModule = false;
+ TemplateHdl_Impl(*m_xLayoutBtn);
+ pImpl->bSaveToModule = true;
+ m_xNoFormatBtn->set_sensitive(false);
+}
+
+IMPL_LINK_NOARG(SvxSearchDialog, AttributeHdl_Impl, weld::Button&, void)
+{
+ if ( !pSearchList || pImpl->pRanges.empty() )
+ return;
+
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<VclAbstractDialog> pDlg(pFact->CreateSvxSearchAttributeDialog(m_xDialog.get(), *pSearchList, pImpl->pRanges));
+ executeSubDialog(pDlg.get());
+ PaintAttrText_Impl();
+}
+
+IMPL_LINK( SvxSearchDialog, TimeoutHdl_Impl, Timer *, pTimer, void )
+{
+ SfxViewShell* pViewShell = SfxViewShell::Current();
+
+ if ( pViewShell )
+ {
+ if ( pViewShell->HasSelection( m_xSearchLB->get_visible() ) )
+ EnableControl_Impl(*m_xSelectionBtn);
+ else
+ {
+ m_xSelectionBtn->set_active( false );
+ m_xSelectionBtn->set_sensitive(false);
+ }
+ }
+
+ pTimer->Start();
+}
+
+OUString& SvxSearchDialog::BuildAttrText_Impl( OUString& rStr,
+ bool bSrchFlag ) const
+{
+ rStr.clear();
+
+ SfxObjectShell* pSh = SfxObjectShell::Current();
+ DBG_ASSERT( pSh, "no DocShell" );
+
+ if ( !pSh )
+ return rStr;
+
+ SfxItemPool& rPool = pSh->GetPool();
+ SearchAttrItemList* pList = bSrchFlag ? pSearchList.get() : pReplaceList.get();
+
+ if ( !pList )
+ return rStr;
+
+ // Metric query
+ MapUnit eMapUnit = MapUnit::MapCM;
+ FieldUnit eFieldUnit = pSh->GetModule()->GetFieldUnit();
+ switch ( eFieldUnit )
+ {
+ case FieldUnit::MM: eMapUnit = MapUnit::MapMM; break;
+ case FieldUnit::CM:
+ case FieldUnit::M:
+ case FieldUnit::KM: eMapUnit = MapUnit::MapCM; break;
+ case FieldUnit::TWIP: eMapUnit = MapUnit::MapTwip; break;
+ case FieldUnit::POINT:
+ case FieldUnit::PICA: eMapUnit = MapUnit::MapPoint; break;
+ case FieldUnit::INCH:
+ case FieldUnit::FOOT:
+ case FieldUnit::MILE: eMapUnit = MapUnit::MapInch; break;
+ case FieldUnit::MM_100TH: eMapUnit = MapUnit::Map100thMM; break;
+ default: ;//prevent warning
+ }
+
+ IntlWrapper aIntlWrapper(SvtSysLocale().GetUILanguageTag());
+ for ( sal_uInt16 i = 0; i < pList->Count(); ++i )
+ {
+ const SearchAttrInfo& rItem = pList->GetObject(i);
+
+ if ( !rStr.isEmpty() )
+ rStr += ", ";
+
+ if ( !IsInvalidItem( rItem.pItemPtr ) )
+ {
+ OUString aStr;
+ rPool.GetPresentation(*rItem.pItemPtr, eMapUnit, aStr, aIntlWrapper);
+ if (aStr.isEmpty())
+ {
+ if (rStr.endsWith(", "))
+ rStr = rStr.copy(0, rStr.lastIndexOf(","));
+ }
+ else
+ rStr += aStr;
+ }
+ else if ( rItem.nSlot == SID_ATTR_BRUSH_CHAR )
+ {
+ // Special treatment for text background
+ rStr += SvxResId( RID_SVXITEMS_BRUSH_CHAR );
+ }
+ else
+ {
+ sal_uInt32 nId = SvxAttrNameTable::FindIndex(rItem.nSlot);
+ if ( RESARRAY_INDEX_NOTFOUND != nId )
+ rStr += SvxAttrNameTable::GetString(nId);
+ }
+ }
+ return rStr;
+}
+
+
+void SvxSearchDialog::PaintAttrText_Impl()
+{
+ OUString aDesc;
+ BuildAttrText_Impl( aDesc, bSearch );
+
+ if ( !bFormat && !aDesc.isEmpty() )
+ bFormat = true;
+
+ bool bSetOptimalLayoutSize = false;
+
+ if ( bSearch )
+ {
+ m_xSearchAttrText->set_label( aDesc );
+ if (!aDesc.isEmpty() && !m_xSearchAttrText->get_visible())
+ {
+ m_xSearchAttrText->show();
+ bSetOptimalLayoutSize = true;
+ }
+
+ FocusHdl_Impl(*m_xSearchLB);
+ }
+ else
+ {
+ m_xReplaceAttrText->set_label( aDesc );
+ if (!aDesc.isEmpty() && !m_xReplaceAttrText->get_visible())
+ {
+ m_xReplaceAttrText->show();
+ bSetOptimalLayoutSize = true;
+ }
+
+ FocusHdl_Impl(*m_xReplaceLB);
+ }
+
+ if (bSetOptimalLayoutSize)
+ m_xDialog->resize_to_request();
+}
+
+void SvxSearchDialog::SetModifyFlag_Impl( const weld::Widget* pCtrl )
+{
+ if (m_xSearchLB.get() == pCtrl)
+ {
+ nModifyFlag |= ModifyFlags::Search;
+ m_xSearchLB->set_entry_message_type(weld::EntryMessageType::Normal);
+ if (!SvxSearchDialogWrapper::GetSearchLabel().isEmpty())
+ SvxSearchDialogWrapper::SetSearchLabel("");
+ }
+ else if ( m_xReplaceLB.get() == pCtrl )
+ nModifyFlag |= ModifyFlags::Replace;
+ else if ( m_xWordBtn.get() == pCtrl )
+ nModifyFlag |= ModifyFlags::Word;
+ else if ( m_xMatchCaseCB.get() == pCtrl )
+ nModifyFlag |= ModifyFlags::Exact;
+ else if ( m_xReplaceBackwardsCB.get() == pCtrl )
+ nModifyFlag |= ModifyFlags::Backwards;
+ else if ( m_xNotesBtn.get() == pCtrl )
+ nModifyFlag |= ModifyFlags::Notes;
+ else if ( m_xSelectionBtn.get() == pCtrl )
+ nModifyFlag |= ModifyFlags::Selection;
+ else if ( m_xRegExpBtn.get() == pCtrl )
+ nModifyFlag |= ModifyFlags::Regexp;
+ else if ( m_xWildcardBtn.get() == pCtrl )
+ nModifyFlag |= ModifyFlags::Wildcard;
+ else if ( m_xLayoutBtn.get() == pCtrl )
+ nModifyFlag |= ModifyFlags::Layout;
+ else if ( m_xSimilarityBox.get() == pCtrl )
+ nModifyFlag |= ModifyFlags::Similarity;
+ else if ( m_xCalcSearchInLB.get() == pCtrl )
+ {
+ nModifyFlag |= ModifyFlags::Formulas;
+ nModifyFlag |= ModifyFlags::Values;
+ nModifyFlag |= ModifyFlags::CalcNotes;
+ }
+ else if ( m_xRowsBtn.get() == pCtrl )
+ nModifyFlag |= ModifyFlags::Rows;
+ else if ( m_xColumnsBtn.get() == pCtrl )
+ nModifyFlag |= ModifyFlags::Columns;
+ else if ( m_xAllSheetsCB.get() == pCtrl )
+ nModifyFlag |= ModifyFlags::AllTables;
+}
+
+void SvxSearchDialog::SaveToModule_Impl()
+{
+ if ( !pSearchItem )
+ return;
+
+ if ( m_xLayoutBtn->get_active() )
+ {
+ pSearchItem->SetSearchString ( m_xSearchTmplLB->get_active_text() );
+ pSearchItem->SetReplaceString( m_xReplaceTmplLB->get_active_text() );
+ }
+ else
+ {
+ pSearchItem->SetSearchString ( m_xSearchLB->get_active_text() );
+ pSearchItem->SetReplaceString( m_xReplaceLB->get_active_text() );
+ Remember_Impl( m_xSearchLB->get_active_text(), true );
+ }
+
+ pSearchItem->SetRegExp( false );
+ pSearchItem->SetWildcard( false );
+ pSearchItem->SetLevenshtein( false );
+ if (GetCheckBoxValue(*m_xRegExpBtn))
+ pSearchItem->SetRegExp( true );
+ else if (GetCheckBoxValue(*m_xWildcardBtn))
+ pSearchItem->SetWildcard( true );
+ else if (GetCheckBoxValue(*m_xSimilarityBox))
+ pSearchItem->SetLevenshtein( true );
+
+ pSearchItem->SetWordOnly(GetCheckBoxValue(*m_xWordBtn));
+ pSearchItem->SetBackward(GetCheckBoxValue(*m_xReplaceBackwardsCB));
+ pSearchItem->SetNotes(GetCheckBoxValue(*m_xNotesBtn));
+ pSearchItem->SetPattern(GetCheckBoxValue(*m_xLayoutBtn));
+ pSearchItem->SetSelection(GetCheckBoxValue(*m_xSelectionBtn));
+ pSearchItem->SetUseAsianOptions(GetCheckBoxValue(*m_xJapOptionsCB));
+
+ SvtSearchOptions aOpt;
+ aOpt.SetIgnoreDiacritics_CTL(GetNegatedCheckBoxValue(*m_xIncludeDiacritics));
+ aOpt.SetIgnoreKashida_CTL(GetNegatedCheckBoxValue(*m_xIncludeKashida));
+ aOpt.Commit();
+
+ TransliterationFlags nFlags = GetTransliterationFlags();
+ if( !pSearchItem->IsUseAsianOptions())
+ nFlags &= TransliterationFlags::IGNORE_CASE |
+ TransliterationFlags::IGNORE_WIDTH;
+ if (GetNegatedCheckBoxValue(*m_xIncludeDiacritics))
+ nFlags |= TransliterationFlags::IGNORE_DIACRITICS_CTL;
+ if (GetNegatedCheckBoxValue(*m_xIncludeKashida))
+ nFlags |= TransliterationFlags::IGNORE_KASHIDA_CTL;
+ pSearchItem->SetTransliterationFlags( nFlags );
+
+ if ( !bWriter )
+ {
+ if (m_xCalcSearchInLB->get_active() != -1)
+ pSearchItem->SetCellType( static_cast<SvxSearchCellType>(m_xCalcSearchInLB->get_active()) );
+
+ pSearchItem->SetRowDirection( m_xRowsBtn->get_active() );
+ pSearchItem->SetAllTables( m_xAllSheetsCB->get_active() );
+ pSearchItem->SetSearchFormatted( m_xSearchFormattedCB->get_active() );
+ }
+
+ pSearchItem->SetCommand( SvxSearchCmd::FIND );
+ nModifyFlag = ModifyFlags::NONE;
+ const SfxPoolItem* ppArgs[] = { pSearchItem.get(), nullptr };
+ rBindings.GetDispatcher()->Execute( SID_SEARCH_ITEM, SfxCallMode::SLOT, ppArgs );
+}
+
+short SvxSearchDialog::executeSubDialog(VclAbstractDialog * dialog) {
+ assert(!m_executingSubDialog);
+ comphelper::ScopeGuard g([this] { m_executingSubDialog = false; });
+ m_executingSubDialog = true;
+ return dialog->Execute();
+}
+
+SFX_IMPL_CHILDWINDOW_WITHID(SvxSearchDialogWrapper, SID_SEARCH_DLG);
+
+
+SvxSearchDialogWrapper::SvxSearchDialogWrapper( vcl::Window* _pParent, sal_uInt16 nId,
+ SfxBindings* pBindings,
+ SfxChildWinInfo const * pInfo )
+ : SfxChildWindow( _pParent, nId )
+ , dialog(std::make_shared<SvxSearchDialog>(_pParent->GetFrameWeld(), this, *pBindings))
+{
+ SetController(dialog);
+ dialog->Initialize( pInfo );
+
+ pBindings->Update( SID_SEARCH_ITEM );
+ pBindings->Update( SID_SEARCH_OPTIONS );
+ pBindings->Update( SID_SEARCH_SEARCHSET );
+ pBindings->Update( SID_SEARCH_REPLACESET );
+ dialog->bConstruct = false;
+}
+
+SvxSearchDialogWrapper::~SvxSearchDialogWrapper ()
+{
+}
+
+
+SfxChildWinInfo SvxSearchDialogWrapper::GetInfo() const
+{
+ SfxChildWinInfo aInfo = SfxChildWindow::GetInfo();
+ aInfo.bVisible = false;
+ return aInfo;
+}
+
+static void lcl_SetSearchLabelWindow(const OUString& rStr, SfxViewFrame& rViewFrame)
+{
+ css::uno::Reference< css::beans::XPropertySet > xPropSet(
+ rViewFrame.GetFrame().GetFrameInterface(), css::uno::UNO_QUERY_THROW);
+ css::uno::Reference< css::frame::XLayoutManager > xLayoutManager;
+ xPropSet->getPropertyValue("LayoutManager") >>= xLayoutManager;
+ css::uno::Reference< css::ui::XUIElement > xUIElement =
+ xLayoutManager->getElement("private:resource/toolbar/findbar");
+ if (!xUIElement.is())
+ return;
+ css::uno::Reference< css::awt::XWindow > xWindow(
+ xUIElement->getRealInterface(), css::uno::UNO_QUERY_THROW);
+ VclPtr< ToolBox > pToolBox = static_cast<ToolBox*>( VCLUnoHelper::GetWindow(xWindow) );
+ for (ToolBox::ImplToolItems::size_type i = 0; pToolBox && i < pToolBox->GetItemCount(); ++i)
+ {
+ ToolBoxItemId id = pToolBox->GetItemId(i);
+ if (pToolBox->GetItemCommand(id) == ".uno:SearchLabel")
+ {
+ LabelItemWindow* pSearchLabel = dynamic_cast<LabelItemWindow*>(pToolBox->GetItemWindow(id));
+ assert(pSearchLabel);
+ pSearchLabel->set_label(rStr, LabelItemWindowType::Info);
+ pSearchLabel->SetOptimalSize();
+ }
+ }
+ xLayoutManager->doLayout();
+ pToolBox->Resize();
+}
+
+OUString SvxSearchDialogWrapper::GetSearchLabel()
+{
+ SfxViewFrame* pViewFrame = SfxViewFrame::Current();
+ if (!pViewFrame)
+ return OUString();
+
+ css::uno::Reference< css::beans::XPropertySet > xPropSet(
+ pViewFrame->GetFrame().GetFrameInterface(), css::uno::UNO_QUERY_THROW);
+ css::uno::Reference< css::frame::XLayoutManager > xLayoutManager;
+ xPropSet->getPropertyValue("LayoutManager") >>= xLayoutManager;
+ if (!xLayoutManager.is())
+ return OUString();
+ css::uno::Reference< css::ui::XUIElement > xUIElement =
+ xLayoutManager->getElement("private:resource/toolbar/findbar");
+ if (!xUIElement.is())
+ return OUString();
+ css::uno::Reference< css::awt::XWindow > xWindow(
+ xUIElement->getRealInterface(), css::uno::UNO_QUERY_THROW);
+ VclPtr< ToolBox > pToolBox = static_cast<ToolBox*>( VCLUnoHelper::GetWindow(xWindow) );
+ for (ToolBox::ImplToolItems::size_type i = 0; pToolBox && i < pToolBox->GetItemCount(); ++i)
+ {
+ ToolBoxItemId id = pToolBox->GetItemId(i);
+ if (pToolBox->GetItemCommand(id) == ".uno:SearchLabel")
+ {
+ LabelItemWindow* pSearchLabel = dynamic_cast<LabelItemWindow*>(pToolBox->GetItemWindow(id));
+ return pSearchLabel ? pSearchLabel->get_label() : OUString();
+ }
+ }
+ return OUString();
+}
+
+void SvxSearchDialogWrapper::SetSearchLabel(const SearchLabel& rSL)
+{
+ SfxViewFrame* pViewFrame = SfxViewFrame::Current();
+ if (!pViewFrame)
+ return;
+
+ OUString sStr;
+ if (rSL == SearchLabel::End)
+ sStr = SvxResId(RID_SVXSTR_SEARCH_END);
+ else if (rSL == SearchLabel::Start)
+ sStr = SvxResId(RID_SVXSTR_SEARCH_START);
+ else if (rSL == SearchLabel::EndWrapped)
+ sStr = SvxResId(RID_SVXSTR_SEARCH_END_WRAPPED);
+ else if (rSL == SearchLabel::StartWrapped)
+ sStr = SvxResId(RID_SVXSTR_SEARCH_START_WRAPPED);
+ else if (rSL == SearchLabel::EndSheet)
+ sStr = SvxResId(RID_SVXSTR_SEARCH_END_SHEET);
+ else if (rSL == SearchLabel::NotFound)
+ sStr = SvxResId(RID_SVXSTR_SEARCH_NOT_FOUND);
+ else if (rSL == SearchLabel::NavElementNotFound)
+ sStr = SvxResId(RID_SVXSTR_SEARCH_NAV_ELEMENT_NOT_FOUND);
+ else if (rSL == SearchLabel::ReminderEndWrapped)
+ sStr = SvxResId(RID_SVXSTR_SEARCH_REMINDER_END_WRAPPED);
+ else if (rSL == SearchLabel::ReminderStartWrapped)
+ sStr = SvxResId(RID_SVXSTR_SEARCH_REMINDER_START_WRAPPED);
+
+ lcl_SetSearchLabelWindow(sStr, *pViewFrame);
+
+ if (SvxSearchDialogWrapper *pWrp = static_cast<SvxSearchDialogWrapper*>( pViewFrame->
+ GetChildWindow( SvxSearchDialogWrapper::GetChildWindowId() )))
+ pWrp->getDialog()->SetSearchLabel(sStr);
+}
+
+void SvxSearchDialogWrapper::SetSearchLabel(const OUString& sStr)
+{
+ SfxViewFrame* pViewFrame = SfxViewFrame::Current();
+ if (!pViewFrame)
+ return;
+
+ lcl_SetSearchLabelWindow(sStr, *pViewFrame);
+ if (SvxSearchDialogWrapper *pWrp = static_cast<SvxSearchDialogWrapper*>( pViewFrame->
+ GetChildWindow( SvxSearchDialogWrapper::GetChildWindowId() )))
+ pWrp->getDialog()->SetSearchLabel(sStr);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/strarray.cxx b/svx/source/dialog/strarray.cxx
new file mode 100644
index 0000000000..28bf16a435
--- /dev/null
+++ b/svx/source/dialog/strarray.cxx
@@ -0,0 +1,88 @@
+/* -*- 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 <svx/dialmgr.hxx>
+#include <svx/strarray.hxx>
+#include <tools/resary.hxx>
+#include <svx/svxitems.hrc>
+#include <fieldunit.hrc>
+#include <numberingtype.hrc>
+
+sal_uInt32 SvxFieldUnitTable::Count() { return std::size(RID_SVXSTR_FIELDUNIT_TABLE); }
+
+OUString SvxFieldUnitTable::GetString(sal_uInt32 nPos)
+{
+ if (RESARRAY_INDEX_NOTFOUND != nPos && nPos < Count())
+ return SvxResId(RID_SVXSTR_FIELDUNIT_TABLE[nPos].first);
+ return OUString();
+}
+
+FieldUnit SvxFieldUnitTable::GetValue(sal_uInt32 nPos)
+{
+ if (RESARRAY_INDEX_NOTFOUND != nPos && nPos < Count())
+ return RID_SVXSTR_FIELDUNIT_TABLE[nPos].second;
+ return FieldUnit::NONE;
+}
+
+OUString SvxAttrNameTable::GetString(sal_uInt32 nPos)
+{
+ if (RESARRAY_INDEX_NOTFOUND != nPos && nPos < Count())
+ return SvxResId(RID_ATTR_NAMES[nPos].first);
+ return OUString();
+}
+
+sal_uInt32 SvxAttrNameTable::Count() { return std::size(RID_ATTR_NAMES); }
+
+sal_uInt32 SvxAttrNameTable::FindIndex(int nValue)
+{
+ for (size_t i = 0; i < std::size(RID_ATTR_NAMES); ++i)
+ {
+ if (nValue == RID_ATTR_NAMES[i].second)
+ return i;
+ }
+ return RESARRAY_INDEX_NOTFOUND;
+}
+
+OUString SvxNumberingTypeTable::GetString(sal_uInt32 nPos)
+{
+ if (RESARRAY_INDEX_NOTFOUND != nPos && nPos < Count())
+ return SvxResId(RID_SVXSTRARY_NUMBERINGTYPE[nPos].first);
+ return OUString();
+}
+
+sal_uInt32 SvxNumberingTypeTable::Count() { return std::size(RID_SVXSTRARY_NUMBERINGTYPE); }
+
+int SvxNumberingTypeTable::GetValue(sal_uInt32 nPos)
+{
+ if (RESARRAY_INDEX_NOTFOUND != nPos && nPos < Count())
+ return RID_SVXSTRARY_NUMBERINGTYPE[nPos].second;
+ return 0;
+}
+
+sal_uInt32 SvxNumberingTypeTable::FindIndex(int nValue)
+{
+ for (size_t i = 0; i < std::size(RID_SVXSTRARY_NUMBERINGTYPE); ++i)
+ {
+ if (nValue == RID_SVXSTRARY_NUMBERINGTYPE[i].second)
+ return i;
+ }
+ return RESARRAY_INDEX_NOTFOUND;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/svxbmpnumvalueset.cxx b/svx/source/dialog/svxbmpnumvalueset.cxx
new file mode 100644
index 0000000000..63a5e5dce8
--- /dev/null
+++ b/svx/source/dialog/svxbmpnumvalueset.cxx
@@ -0,0 +1,533 @@
+/* -*- 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 <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+#include <comphelper/diagnose_ex.hxx>
+#include <i18nlangtag/mslangid.hxx>
+#include <svtools/valueset.hxx>
+#include <editeng/numitem.hxx>
+#include <svx/gallery.hxx>
+#include <vcl/event.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/virdev.hxx>
+#include <svx/numvset.hxx>
+#include <com/sun/star/style/NumberingType.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/text/XNumberingFormatter.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+#include <algorithm>
+
+#include <uiobject.hxx>
+
+using namespace com::sun::star::uno;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::text;
+using namespace com::sun::star::container;
+using namespace com::sun::star::style;
+
+
+// The selection of bullets from the star symbol
+const sal_Unicode aBulletTypes[] =
+{
+ 0x2022,
+ 0x25cf,
+ 0xe00c,
+ 0xe00a,
+ 0x2794,
+ 0x27a2,
+ 0x2717,
+ 0x2714
+};
+
+static vcl::Font& lcl_GetDefaultBulletFont()
+{
+ static vcl::Font aDefBulletFont = []()
+ {
+ static vcl::Font tmp("OpenSymbol", "", Size(0, 14));
+ tmp.SetCharSet( RTL_TEXTENCODING_SYMBOL );
+ tmp.SetFamily( FAMILY_DONTKNOW );
+ tmp.SetPitch( PITCH_DONTKNOW );
+ tmp.SetWeight( WEIGHT_DONTKNOW );
+ tmp.SetTransparent( true );
+ return tmp;
+ }();
+ return aDefBulletFont;
+}
+
+static void lcl_PaintLevel(OutputDevice* pVDev, sal_Int16 nNumberingType,
+ const OUString& rBulletChar, const OUString& rText, const OUString& rFontName,
+ Point& rLeft, vcl::Font& rRuleFont, const vcl::Font& rTextFont)
+{
+
+ if(NumberingType::CHAR_SPECIAL == nNumberingType )
+ {
+ rRuleFont.SetStyleName(rFontName);
+ pVDev->SetFont(rRuleFont);
+ pVDev->DrawText(rLeft, rBulletChar);
+ rLeft.AdjustX(pVDev->GetTextWidth(rBulletChar) );
+ }
+ else
+ {
+ pVDev->SetFont(rTextFont);
+ pVDev->DrawText(rLeft, rText);
+ rLeft.AdjustX(pVDev->GetTextWidth(rText) );
+ }
+}
+
+ const TranslateId RID_SVXSTR_BULLET_DESCRIPTIONS[] =
+{
+ RID_SVXSTR_BULLET_DESCRIPTION_0,
+ RID_SVXSTR_BULLET_DESCRIPTION_1,
+ RID_SVXSTR_BULLET_DESCRIPTION_2,
+ RID_SVXSTR_BULLET_DESCRIPTION_3,
+ RID_SVXSTR_BULLET_DESCRIPTION_4,
+ RID_SVXSTR_BULLET_DESCRIPTION_5,
+ RID_SVXSTR_BULLET_DESCRIPTION_6,
+ RID_SVXSTR_BULLET_DESCRIPTION_7
+};
+
+const TranslateId RID_SVXSTR_SINGLENUM_DESCRIPTIONS[] =
+{
+ RID_SVXSTR_SINGLENUM_DESCRIPTION_0,
+ RID_SVXSTR_SINGLENUM_DESCRIPTION_1,
+ RID_SVXSTR_SINGLENUM_DESCRIPTION_2,
+ RID_SVXSTR_SINGLENUM_DESCRIPTION_3,
+ RID_SVXSTR_SINGLENUM_DESCRIPTION_4,
+ RID_SVXSTR_SINGLENUM_DESCRIPTION_5,
+ RID_SVXSTR_SINGLENUM_DESCRIPTION_6,
+ RID_SVXSTR_SINGLENUM_DESCRIPTION_7
+};
+
+const TranslateId RID_SVXSTR_OUTLINENUM_DESCRIPTIONS[] =
+{
+ RID_SVXSTR_OUTLINENUM_DESCRIPTION_0,
+ RID_SVXSTR_OUTLINENUM_DESCRIPTION_1,
+ RID_SVXSTR_OUTLINENUM_DESCRIPTION_2,
+ RID_SVXSTR_OUTLINENUM_DESCRIPTION_3,
+ RID_SVXSTR_OUTLINENUM_DESCRIPTION_4,
+ RID_SVXSTR_OUTLINENUM_DESCRIPTION_5,
+ RID_SVXSTR_OUTLINENUM_DESCRIPTION_6,
+ RID_SVXSTR_OUTLINENUM_DESCRIPTION_7
+};
+
+void SvxNumValueSet::UserDraw( const UserDrawEvent& rUDEvt )
+{
+ static const sal_uInt16 aLinesArr[] =
+ {
+ 15, 10,
+ 20, 30,
+ 25, 50,
+ 30, 70,
+ 35, 90, // up to here line positions
+ 5, 10, // character positions
+ 10, 30,
+ 15, 50,
+ 20, 70,
+ 25, 90,
+ };
+
+ const Color aBackColor(COL_WHITE);
+ const Color aTextColor(COL_BLACK);
+
+ vcl::RenderContext* pDev = rUDEvt.GetRenderContext();
+ tools::Rectangle aRect = rUDEvt.GetRect();
+ sal_uInt16 nItemId = rUDEvt.GetItemId();
+
+ tools::Long nRectWidth = aRect.GetWidth();
+ tools::Long nRectHeight = aRect.GetHeight();
+ Size aRectSize(nRectWidth, aRect.GetHeight());
+ Point aBLPos = aRect.TopLeft();
+ vcl::Font aOldFont = pDev->GetFont();
+ Color aOldColor = pDev->GetLineColor();
+ pDev->SetLineColor(aTextColor);
+ vcl::Font aFont(OutputDevice::GetDefaultFont(
+ DefaultFontType::UI_SANS, MsLangId::getConfiguredSystemLanguage(), GetDefaultFontFlags::OnlyOne));
+
+ Size aSize = aFont.GetFontSize();
+
+ vcl::Font aRuleFont( lcl_GetDefaultBulletFont() );
+ aSize.setHeight( nRectHeight/6 );
+ aRuleFont.SetFontSize(aSize);
+ aRuleFont.SetColor(aTextColor);
+ aRuleFont.SetFillColor(aBackColor);
+ if(ePageType == NumberingPageType::BULLET)
+ aFont = aRuleFont;
+ else if(ePageType == NumberingPageType::OUTLINE)
+ {
+ aSize.setHeight( nRectHeight/8 );
+ }
+ aFont.SetColor(aTextColor);
+ aFont.SetFillColor(aBackColor);
+ aFont.SetFontSize( aSize );
+ pDev->SetFont(aFont);
+
+ if(!pVDev)
+ {
+ // The lines are only one time in the virtual device, only the outline
+ // page is currently done
+ pVDev = VclPtr<VirtualDevice>::Create(*pDev);
+ pVDev->SetMapMode(pDev->GetMapMode());
+ pVDev->EnableRTL( IsRTLEnabled() );
+ pVDev->SetOutputSize( aRectSize );
+ aOrgRect = aRect;
+ pVDev->SetFillColor( aBackColor );
+ pVDev->SetLineColor(COL_LIGHTGRAY);
+ // Draw line only once
+ if(ePageType != NumberingPageType::OUTLINE)
+ {
+ Point aStart(aBLPos.X() + nRectWidth *25 / 100,0);
+ Point aEnd(aBLPos.X() + nRectWidth * 9 / 10,0);
+ for( sal_uInt16 i = 11; i < 100; i += 33)
+ {
+ aStart.setY( aBLPos.Y() + nRectHeight * i / 100 );
+ aEnd.setY( aStart.Y() );
+ pVDev->DrawLine(aStart, aEnd);
+ aStart.setY( aBLPos.Y() + nRectHeight * (i + 11) / 100 );
+ aEnd.setY( aStart.Y() );
+ pVDev->DrawLine(aStart, aEnd);
+ }
+ }
+ }
+ pDev->DrawOutDev( aRect.TopLeft(), aRectSize,
+ aOrgRect.TopLeft(), aRectSize,
+ *pVDev );
+ // Now comes the text
+ static constexpr OUStringLiteral sValue(u"Value");
+ if( NumberingPageType::SINGLENUM == ePageType ||
+ NumberingPageType::BULLET == ePageType )
+ {
+ Point aStart(aBLPos.X() + nRectWidth / 9,0);
+ for( sal_uInt16 i = 0; i < 3; i++ )
+ {
+ sal_uInt16 nY = 11 + i * 33;
+ aStart.setY( aBLPos.Y() + nRectHeight * nY / 100 );
+ OUString sText;
+ if(ePageType == NumberingPageType::BULLET)
+ {
+ sText = OUString( aBulletTypes[nItemId - 1] );
+ aStart.AdjustY( -(pDev->GetTextHeight()/2) );
+ aStart.setX( aBLPos.X() + 5 );
+ }
+ else
+ {
+ if(xFormatter.is() && aNumSettings.getLength() > nItemId - 1)
+ {
+ Sequence<PropertyValue> aLevel = aNumSettings.getConstArray()[nItemId - 1];
+ try
+ {
+ aLevel.realloc(aLevel.getLength() + 1);
+ PropertyValue& rValue = aLevel.getArray()[aLevel.getLength() - 1];
+ rValue.Name = sValue;
+ rValue.Value <<= static_cast<sal_Int32>(i + 1);
+ sText = xFormatter->makeNumberingString( aLevel, aLocale );
+ }
+ catch(Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("svx.dialog", "");
+ }
+ }
+ // start just next to the left edge
+ aStart.setX( aBLPos.X() + 2 );
+ aStart.AdjustY( -(pDev->GetTextHeight()/2) );
+ }
+ pDev->DrawText(aStart, sText);
+ }
+ }
+ else if(NumberingPageType::OUTLINE == ePageType )
+ {
+ // Outline numbering has to be painted into the virtual device
+ // to get correct lines
+ // has to be made again
+ pVDev->SetLineColor(aBackColor);
+ pVDev->DrawRect(aOrgRect);
+ tools::Long nStartX = aOrgRect.Left();
+ tools::Long nStartY = aOrgRect.Top();
+
+ if(xFormatter.is() && aOutlineSettings.getLength() > nItemId - 1)
+ {
+ Reference<XIndexAccess> xLevel = aOutlineSettings.getArray()[nItemId - 1];
+ try
+ {
+ OUString sLevelTexts[5];
+ OUString sFontNames[5];
+ OUString sBulletChars[5];
+ sal_Int16 aNumberingTypes[5];
+ OUString sPrefixes[5];
+ OUString sSuffixes[5];
+ sal_Int16 aParentNumberings[5];
+
+ sal_Int32 nLevelCount = xLevel->getCount();
+ if(nLevelCount > 5)
+ nLevelCount = 5;
+ for( sal_Int32 i = 0; i < nLevelCount; i++)
+ {
+ tools::Long nTop = nStartY + nRectHeight * (aLinesArr[2 * i + 11])/100 ;
+ Point aLeft(nStartX + nRectWidth * (aLinesArr[2 * i + 10])/ 100, nTop );
+
+ Any aLevelAny = xLevel->getByIndex(i);
+ Sequence<PropertyValue> aLevel;
+ aLevelAny >>= aLevel;
+ aNumberingTypes[i] = 0;
+ aParentNumberings[i] = 0;
+ for(const PropertyValue& rProp : std::as_const(aLevel))
+ {
+ if ( rProp.Name == "NumberingType" )
+ rProp.Value >>= aNumberingTypes[i];
+ else if ( rProp.Name == "BulletFontName" )
+ rProp.Value >>= sFontNames[i];
+ else if ( rProp.Name == "BulletChar" )
+ rProp.Value >>= sBulletChars[i];
+ else if ( rProp.Name == "Prefix" )
+ rProp.Value >>= sPrefixes[i];
+ else if ( rProp.Name == "Suffix" )
+ rProp.Value >>= sSuffixes[i];
+ else if ( rProp.Name == "ParentNumbering" )
+ rProp.Value >>= aParentNumberings[i];
+ }
+ Sequence< PropertyValue > aProperties(2);
+ PropertyValue* pProperties = aProperties.getArray();
+ pProperties[0].Name = "NumberingType";
+ pProperties[0].Value <<= aNumberingTypes[i];
+ pProperties[1].Name = "Value";
+ pProperties[1].Value <<= sal_Int32(1);
+ try
+ {
+ sLevelTexts[i] = xFormatter->makeNumberingString( aProperties, aLocale );
+ }
+ catch(Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("svx.dialog", "");
+ }
+
+ aLeft.AdjustY( -(pDev->GetTextHeight()/2) );
+ if(!sPrefixes[i].isEmpty() &&
+ sPrefixes[i] != " ")
+ {
+ pVDev->SetFont(aFont);
+ pVDev->DrawText(aLeft, sPrefixes[i]);
+ aLeft.AdjustX(pDev->GetTextWidth(sPrefixes[i]) );
+ }
+ if(aParentNumberings[i])
+ {
+ //insert old numberings here
+ sal_Int32 nStartLevel = std::min(static_cast<sal_Int32>(aParentNumberings[i]), i);
+ for(sal_Int32 nParentLevel = i - nStartLevel; nParentLevel < i; nParentLevel++)
+ {
+ OUString sTmp = sLevelTexts[nParentLevel] + ".";
+ lcl_PaintLevel(pVDev,
+ aNumberingTypes[nParentLevel],
+ sBulletChars[nParentLevel],
+ sTmp,
+ sFontNames[nParentLevel],
+ aLeft,
+ aRuleFont,
+ aFont);
+ }
+ }
+ lcl_PaintLevel(pVDev,
+ aNumberingTypes[i],
+ sBulletChars[i],
+ sLevelTexts[i],
+ sFontNames[i],
+ aLeft,
+ aRuleFont,
+ aFont);
+ if(!sSuffixes[i].isEmpty() &&
+ !sSuffixes[i].startsWith(" "))
+ {
+ pVDev->SetFont(aFont);
+ pVDev->DrawText(aLeft, sSuffixes[i]);
+ aLeft.AdjustX(pDev->GetTextWidth(sSuffixes[i]) );
+ }
+
+ tools::Long nLineTop = nStartY + nRectHeight * aLinesArr[2 * i + 1]/100 ;
+ Point aLineLeft(aLeft.X(), nLineTop );
+ Point aLineRight(nStartX + nRectWidth * 90 /100, nLineTop );
+ pVDev->SetLineColor(COL_LIGHTGRAY);
+ pVDev->DrawLine(aLineLeft, aLineRight);
+ }
+
+ }
+#ifdef DBG_UTIL
+ catch(Exception&)
+ {
+ static bool bAssert = false;
+ if(!bAssert)
+ {
+ TOOLS_WARN_EXCEPTION("svx.dialog", "");
+ bAssert = true;
+ }
+ }
+#else
+ catch(Exception&)
+ {
+ }
+#endif
+ }
+ pDev->DrawOutDev( aRect.TopLeft(), aRectSize,
+ aOrgRect.TopLeft(), aRectSize,
+ *pVDev );
+ }
+
+ pDev->SetFont(aOldFont);
+ pDev->SetLineColor(aOldColor);
+}
+
+SvxNumValueSet::SvxNumValueSet(std::unique_ptr<weld::ScrolledWindow> pScrolledWindow)
+ : ValueSet(std::move(pScrolledWindow))
+ , ePageType(NumberingPageType::BULLET)
+ , pVDev(nullptr)
+{
+}
+
+FactoryFunction SvxNumValueSet::GetUITestFactory() const
+{
+ return SvxNumValueSetUIObject::create;
+}
+
+void SvxNumValueSet::init(NumberingPageType eType)
+{
+ ePageType = eType;
+ pVDev = nullptr;
+
+ SetColCount( 4 );
+ SetLineCount( 2 );
+ SetStyle( GetStyle() | WB_ITEMBORDER | WB_DOUBLEBORDER );
+ if(NumberingPageType::BULLET == eType)
+ {
+ for ( sal_uInt16 i = 0; i < 8; i++ )
+ {
+ InsertItem( i + 1, i );
+ SetItemText(i + 1, SvxResId(RID_SVXSTR_BULLET_DESCRIPTIONS[i]));
+ }
+ }
+}
+
+SvxNumValueSet::~SvxNumValueSet()
+{
+}
+
+void SvxNumValueSet::SetNumberingSettings(
+ const Sequence<Sequence<PropertyValue> >& aNum,
+ Reference<XNumberingFormatter> const & xFormat,
+ const Locale& rLocale )
+{
+ aNumSettings = aNum;
+ xFormatter = xFormat;
+ aLocale = rLocale;
+ if(aNum.getLength() > 8)
+ SetStyle( GetStyle()|WB_VSCROLL);
+ for ( sal_Int32 i = 0; i < aNum.getLength(); i++ )
+ {
+ InsertItem( i + 1, i );
+ if( i < 8 )
+ SetItemText(i + 1, SvxResId(RID_SVXSTR_SINGLENUM_DESCRIPTIONS[i]));
+ }
+}
+
+void SvxNumValueSet::SetOutlineNumberingSettings(
+ Sequence<Reference<XIndexAccess> > const & rOutline,
+ Reference<XNumberingFormatter> const & xFormat,
+ const Locale& rLocale)
+{
+ aOutlineSettings = rOutline;
+ xFormatter = xFormat;
+ aLocale = rLocale;
+ if(aOutlineSettings.getLength() > 8)
+ SetStyle( GetStyle() | WB_VSCROLL );
+ for ( sal_Int32 i = 0; i < aOutlineSettings.getLength(); i++ )
+ {
+ InsertItem( i + 1, i );
+ if( i < 8 )
+ SetItemText(i + 1, SvxResId(RID_SVXSTR_OUTLINENUM_DESCRIPTIONS[i]));
+ }
+}
+
+SvxBmpNumValueSet::SvxBmpNumValueSet(std::unique_ptr<weld::ScrolledWindow> pScrolledWindow)
+ : SvxNumValueSet(std::move(pScrolledWindow))
+ , aFormatIdle("SvxBmpNumValueSet FormatIdle")
+ , bGrfNotFound(false)
+{
+}
+
+void SvxBmpNumValueSet::init()
+{
+ SvxNumValueSet::init(NumberingPageType::BITMAP);
+ bGrfNotFound = false;
+ GalleryExplorer::BeginLocking(GALLERY_THEME_BULLETS);
+ SetStyle( GetStyle() | WB_VSCROLL );
+ SetLineCount( 3 );
+ aFormatIdle.SetPriority(TaskPriority::LOWEST);
+ aFormatIdle.SetInvokeHandler(LINK(this, SvxBmpNumValueSet, FormatHdl_Impl));
+}
+
+
+SvxBmpNumValueSet::~SvxBmpNumValueSet()
+{
+ GalleryExplorer::EndLocking(GALLERY_THEME_BULLETS);
+ aFormatIdle.Stop();
+}
+
+void SvxBmpNumValueSet::UserDraw(const UserDrawEvent& rUDEvt)
+{
+ SvxNumValueSet::UserDraw(rUDEvt);
+
+ tools::Rectangle aRect = rUDEvt.GetRect();
+ vcl::RenderContext* pDev = rUDEvt.GetRenderContext();
+ sal_uInt16 nItemId = rUDEvt.GetItemId();
+ Point aBLPos = aRect.TopLeft();
+
+ tools::Long nRectHeight = aRect.GetHeight();
+ Size aSize(nRectHeight/8, nRectHeight/8);
+
+ Graphic aGraphic;
+ if(!GalleryExplorer::GetGraphicObj( GALLERY_THEME_BULLETS, nItemId - 1,
+ &aGraphic))
+ {
+ bGrfNotFound = true;
+ }
+ else
+ {
+ Point aPos(aBLPos.X() + 5, 0);
+ for( sal_uInt16 i = 0; i < 3; i++ )
+ {
+ sal_uInt16 nY = 11 + i * 33;
+ aPos.setY( aBLPos.Y() + nRectHeight * nY / 100 );
+ aGraphic.Draw(*pDev, aPos, aSize);
+ }
+ }
+}
+
+IMPL_LINK_NOARG(SvxBmpNumValueSet, FormatHdl_Impl, Timer *, void)
+{
+ // only when a graphics was not there, it needs to be formatted
+ if (bGrfNotFound)
+ {
+ SetFormat();
+ bGrfNotFound = false;
+ }
+ Invalidate();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/svxdlg.cxx b/svx/source/dialog/svxdlg.cxx
new file mode 100644
index 0000000000..c073fb241f
--- /dev/null
+++ b/svx/source/dialog/svxdlg.cxx
@@ -0,0 +1,29 @@
+/* -*- 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 <svx/svxdlg.hxx>
+
+SvxAbstractDialogFactory* SvxAbstractDialogFactory::Create()
+{
+ return dynamic_cast<SvxAbstractDialogFactory*>(VclAbstractDialogFactory::Create());
+}
+
+SvxAbstractDialogFactory::~SvxAbstractDialogFactory() {}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/svxgraphicitem.cxx b/svx/source/dialog/svxgraphicitem.cxx
new file mode 100644
index 0000000000..940941b605
--- /dev/null
+++ b/svx/source/dialog/svxgraphicitem.cxx
@@ -0,0 +1,40 @@
+/* -*- 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 <svx/svxgraphicitem.hxx>
+#include <svx/svxids.hrc>
+#include <utility>
+
+SvxGraphicItem::SvxGraphicItem( Graphic _aGraphic )
+ : SfxPoolItem( SID_GRAPHIC ), aGraphic(std::move( _aGraphic ))
+{
+
+}
+
+bool SvxGraphicItem::operator==( const SfxPoolItem& rItem) const
+{
+ return SfxPoolItem::operator==(rItem) && static_cast<const SvxGraphicItem&>(rItem).aGraphic == aGraphic;
+}
+
+SvxGraphicItem* SvxGraphicItem::Clone( SfxItemPool * ) const
+{
+ return new SvxGraphicItem( *this );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/svxruler.cxx b/svx/source/dialog/svxruler.cxx
new file mode 100644
index 0000000000..6323583fd2
--- /dev/null
+++ b/svx/source/dialog/svxruler.cxx
@@ -0,0 +1,3582 @@
+/* -*- 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 <cstring>
+#include <climits>
+
+#include <vcl/commandevent.hxx>
+#include <vcl/event.hxx>
+#include <vcl/fieldvalues.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/weldutils.hxx>
+#include <svl/eitem.hxx>
+#include <svl/rectitem.hxx>
+#include <svl/hint.hxx>
+#include <sfx2/dispatch.hxx>
+#include <svx/strings.hrc>
+#include <svx/svxids.hrc>
+#include <svx/dialmgr.hxx>
+#include <svx/ruler.hxx>
+#include <svx/rulritem.hxx>
+#include <editeng/editids.hrc>
+#include <editeng/tstpitem.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/protitem.hxx>
+#include <osl/diagnose.h>
+#include <rtl/math.hxx>
+#include <o3tl/string_view.hxx>
+#include <svl/itemset.hxx>
+
+#include "rlrcitem.hxx"
+#include <memory>
+
+#define CTRL_ITEM_COUNT 14
+#define GAP 10
+#define OBJECT_BORDER_COUNT 4
+#define TAB_GAP 1
+#define INDENT_GAP 2
+#define INDENT_FIRST_LINE 2
+#define INDENT_LEFT_MARGIN 3
+#define INDENT_RIGHT_MARGIN 4
+#define INDENT_COUNT 3 //without the first two old values
+
+struct SvxRuler_Impl {
+ std::unique_ptr<sal_uInt16[]> pPercBuf;
+ std::unique_ptr<sal_uInt16[]> pBlockBuf;
+ sal_uInt16 nPercSize;
+ tools::Long nTotalDist;
+ tools::Long lOldWinPos;
+ tools::Long lMaxLeftLogic;
+ tools::Long lMaxRightLogic;
+ tools::Long lLastLMargin;
+ tools::Long lLastRMargin;
+ std::unique_ptr<SvxProtectItem> aProtectItem;
+ std::unique_ptr<SfxBoolItem> pTextRTLItem;
+ sal_uInt16 nControllerItems;
+ sal_uInt16 nIdx;
+ sal_uInt16 nColLeftPix;
+ sal_uInt16 nColRightPix; // Pixel values for left / right edge
+ // For columns; buffered to prevent
+ // recalculation errors
+ // May be has to be widen for future values
+ bool bIsTableRows : 1; // mxColumnItem contains table rows instead of columns
+ //#i24363# tab stops relative to indent
+ bool bIsTabsRelativeToIndent : 1; // Tab stops relative to paragraph indent?
+ // false means relative to SvxRuler::GetLeftFrameMargin()
+
+ SvxRuler_Impl() :
+ nPercSize(0), nTotalDist(0),
+ lOldWinPos(0), lMaxLeftLogic(0), lMaxRightLogic(0),
+ lLastLMargin(0), lLastRMargin(0),
+ aProtectItem(std::make_unique<SvxProtectItem>(SID_RULER_PROTECT)),
+ nControllerItems(0), nIdx(0),
+ nColLeftPix(0), nColRightPix(0),
+ bIsTableRows(false),
+ bIsTabsRelativeToIndent(true)
+ {
+ }
+
+ void SetPercSize(sal_uInt16 nSize);
+
+};
+
+static RulerTabData ruler_tab_svx =
+{
+ 0, // DPIScaleFactor to be set
+ 7, // ruler_tab_width
+ 6, // ruler_tab_height
+ 0, // ruler_tab_height2
+ 0, // ruler_tab_width2
+ 0, // ruler_tab_cwidth
+ 0, // ruler_tab_cwidth2
+ 0, // ruler_tab_cwidth3
+ 0, // ruler_tab_cwidth4
+ 0, // ruler_tab_dheight
+ 0, // ruler_tab_dheight2
+ 0, // ruler_tab_dwidth
+ 0, // ruler_tab_dwidth2
+ 0, // ruler_tab_dwidth3
+ 0, // ruler_tab_dwidth4
+ 0 // ruler_tab_textoff
+};
+
+void SvxRuler_Impl::SetPercSize(sal_uInt16 nSize)
+{
+ if(nSize > nPercSize)
+ {
+ nPercSize = nSize;
+ pPercBuf.reset( new sal_uInt16[nPercSize] );
+ pBlockBuf.reset( new sal_uInt16[nPercSize] );
+ }
+ size_t nSize2 = sizeof(sal_uInt16) * nPercSize;
+ memset(pPercBuf.get(), 0, nSize2);
+ memset(pBlockBuf.get(), 0, nSize2);
+}
+
+// Constructor of the ruler
+
+// SID_ATTR_ULSPACE, SID_ATTR_LRSPACE
+// expects as parameter SvxULSpaceItem for page edge
+// (either left/right or top/bottom)
+// Ruler: SetMargin1, SetMargin2
+
+// SID_RULER_PAGE_POS
+// expects as parameter the initial value of the page and page width
+// Ruler: SetPagePos
+
+// SID_ATTR_TABSTOP
+// expects: SvxTabStopItem
+// Ruler: SetTabs
+
+// SID_ATTR_PARA_LRSPACE
+// left, right paragraph edge in H-ruler
+// Ruler: SetIndents
+
+// SID_RULER_BORDERS
+// Table borders, columns
+// expects: something like SwTabCols
+// Ruler: SetBorders
+
+constexpr tools::Long glMinFrame = 5; // minimal frame width in pixels
+
+SvxRuler::SvxRuler(
+ vcl::Window* pParent, // StarView Parent
+ vcl::Window* pWin, // Output window: is used for conversion
+ // logical units <-> pixels
+ SvxRulerSupportFlags flags, // Display flags, see ruler.hxx
+ SfxBindings &rBindings, // associated Bindings
+ WinBits nWinStyle) : // StarView WinBits
+ Ruler(pParent, nWinStyle),
+ pCtrlItems(CTRL_ITEM_COUNT),
+ pEditWin(pWin),
+ mxRulerImpl(new SvxRuler_Impl),
+ bAppSetNullOffset(false), // Is the 0-offset of the ruler set by the application?
+ lLogicNullOffset(0),
+ lAppNullOffset(LONG_MAX),
+ lInitialDragPos(0),
+ nFlags(flags),
+ nDragType(SvxRulerDragFlags::NONE),
+ nDefTabType(RULER_TAB_LEFT),
+ nTabCount(0),
+ nTabBufSize(0),
+ lDefTabDist(50),
+ lTabPos(-1),
+ mpBorders(1), // due to one column tables
+ pBindings(&rBindings),
+ nDragOffset(0),
+ nMaxLeft(0),
+ nMaxRight(0),
+ bValid(false),
+ bListening(false),
+ bActive(true),
+ mbCoarseSnapping(false),
+ mbSnapping(true)
+
+{
+ /* Constructor; Initialize data buffer; controller items are created */
+
+ rBindings.EnterRegistrations();
+
+ // Create Supported Items
+ sal_uInt16 i = 0;
+
+ // Page edges
+ pCtrlItems[i++].reset(new SvxRulerItem(SID_RULER_LR_MIN_MAX, *this, rBindings));
+ if((nWinStyle & WB_VSCROLL) == WB_VSCROLL)
+ {
+ bHorz = false;
+ pCtrlItems[i++].reset(new SvxRulerItem(SID_ATTR_LONG_ULSPACE, *this, rBindings));
+ }
+ else
+ {
+ bHorz = true;
+ pCtrlItems[i++].reset(new SvxRulerItem(SID_ATTR_LONG_LRSPACE, *this, rBindings));
+ }
+
+ // Page Position
+ pCtrlItems[i++].reset(new SvxRulerItem(SID_RULER_PAGE_POS, *this, rBindings));
+
+ if(nFlags & SvxRulerSupportFlags::TABS)
+ {
+ sal_uInt16 nTabStopId = bHorz ? SID_ATTR_TABSTOP : SID_ATTR_TABSTOP_VERTICAL;
+ pCtrlItems[i++].reset(new SvxRulerItem(nTabStopId, *this, rBindings));
+ SetExtraType(RulerExtra::Tab, nDefTabType);
+ }
+
+ if(nFlags & (SvxRulerSupportFlags::PARAGRAPH_MARGINS |SvxRulerSupportFlags::PARAGRAPH_MARGINS_VERTICAL))
+ {
+ if(bHorz)
+ pCtrlItems[i++].reset(new SvxRulerItem(SID_ATTR_PARA_LRSPACE, *this, rBindings));
+ else
+ pCtrlItems[i++].reset(new SvxRulerItem(SID_ATTR_PARA_LRSPACE_VERTICAL, *this, rBindings));
+
+ mpIndents.resize(5 + INDENT_GAP);
+
+ for(RulerIndent & rIndent : mpIndents)
+ {
+ rIndent.nPos = 0;
+ rIndent.nStyle = RulerIndentStyle::Top;
+ }
+
+ mpIndents[0].nStyle = RulerIndentStyle::Top;
+ mpIndents[1].nStyle = RulerIndentStyle::Top;
+ mpIndents[INDENT_FIRST_LINE].nStyle = RulerIndentStyle::Top;
+ mpIndents[INDENT_LEFT_MARGIN].nStyle = RulerIndentStyle::Bottom;
+ mpIndents[INDENT_RIGHT_MARGIN].nStyle = RulerIndentStyle::Bottom;
+ }
+
+ if( (nFlags & SvxRulerSupportFlags::BORDERS) == SvxRulerSupportFlags::BORDERS )
+ {
+ pCtrlItems[i++].reset(new SvxRulerItem(bHorz ? SID_RULER_BORDERS : SID_RULER_BORDERS_VERTICAL, *this, rBindings));
+ pCtrlItems[i++].reset(new SvxRulerItem(bHorz ? SID_RULER_ROWS : SID_RULER_ROWS_VERTICAL, *this, rBindings));
+ }
+
+ pCtrlItems[i++].reset(new SvxRulerItem(SID_RULER_TEXT_RIGHT_TO_LEFT, *this, rBindings));
+
+ if( (nFlags & SvxRulerSupportFlags::OBJECT) == SvxRulerSupportFlags::OBJECT )
+ {
+ pCtrlItems[i++].reset(new SvxRulerItem(SID_RULER_OBJECT, *this, rBindings));
+ mpObjectBorders.resize(OBJECT_BORDER_COUNT);
+ for(sal_uInt16 nBorder = 0; nBorder < OBJECT_BORDER_COUNT; ++nBorder)
+ {
+ mpObjectBorders[nBorder].nPos = 0;
+ mpObjectBorders[nBorder].nWidth = 0;
+ mpObjectBorders[nBorder].nStyle = RulerBorderStyle::Moveable;
+ }
+ }
+
+ pCtrlItems[i++].reset(new SvxRulerItem(SID_RULER_PROTECT, *this, rBindings));
+ pCtrlItems[i++].reset(new SvxRulerItem(SID_RULER_BORDER_DISTANCE, *this, rBindings));
+ mxRulerImpl->nControllerItems=i;
+
+ if( (nFlags & SvxRulerSupportFlags::SET_NULLOFFSET) == SvxRulerSupportFlags::SET_NULLOFFSET )
+ SetExtraType(RulerExtra::NullOffset);
+
+ rBindings.LeaveRegistrations();
+
+ ruler_tab_svx.DPIScaleFactor = pParent->GetDPIScaleFactor();
+ ruler_tab_svx.height *= ruler_tab_svx.DPIScaleFactor;
+ ruler_tab_svx.width *= ruler_tab_svx.DPIScaleFactor;
+
+}
+
+SvxRuler::~SvxRuler()
+{
+ disposeOnce();
+}
+
+void SvxRuler::dispose()
+{
+ /* Destructor ruler; release internal buffer */
+ if(bListening)
+ EndListening(*pBindings);
+
+ pBindings->EnterRegistrations();
+
+ pCtrlItems.clear();
+
+ pBindings->LeaveRegistrations();
+
+ pEditWin.clear();
+ Ruler::dispose();
+}
+
+tools::Long SvxRuler::MakePositionSticky(tools::Long aPosition, tools::Long aPointOfReference, bool aSnapToFrameMargin) const
+{
+ tools::Long aPointOfReferencePixel = ConvertHPosPixel(aPointOfReference);
+ tools::Long aLeftFramePosition = ConvertHPosPixel(GetLeftFrameMargin());
+ tools::Long aRightFramePosition = ConvertHPosPixel(GetRightFrameMargin());
+
+ double aTick = GetCurrentRulerUnit().nTick1;
+
+ if (mbCoarseSnapping)
+ aTick = GetCurrentRulerUnit().nTick2;
+
+ tools::Long aTickPixel = pEditWin->LogicToPixel(Size(aTick, 0), GetCurrentMapMode()).Width();
+
+ double aHalfTick = aTick / 2.0;
+ double aHalfTickPixel = aTickPixel / 2.0;
+
+ if (aSnapToFrameMargin)
+ {
+ if (aPosition > aLeftFramePosition - aHalfTickPixel && aPosition < aLeftFramePosition + aHalfTickPixel)
+ return aLeftFramePosition;
+
+ if (aPosition > aRightFramePosition - aHalfTickPixel && aPosition < aRightFramePosition + aHalfTickPixel)
+ return aRightFramePosition;
+ }
+
+ if (!mbSnapping)
+ return aPosition;
+
+ // Move "coordinate system" to frame position so ticks are calculated correctly
+ tools::Long aTranslatedPosition = aPosition - aPointOfReferencePixel;
+ // Convert position to current selected map mode
+ tools::Long aPositionLogic = pEditWin->PixelToLogic(Size(aTranslatedPosition, 0), GetCurrentMapMode()).Width();
+ // Normalize -- snap to nearest tick
+ aPositionLogic = rtl::math::round((aPositionLogic + aHalfTick) / aTick) * aTick;
+ // Convert back to pixels
+ aPosition = pEditWin->LogicToPixel(Size(aPositionLogic, 0), GetCurrentMapMode()).Width();
+ // Move "coordinate system" back to original position
+ return aPosition + aPointOfReferencePixel;
+}
+
+tools::Long SvxRuler::ConvertHPosPixel(tools::Long nVal) const
+{
+ return pEditWin->LogicToPixel(Size(nVal, 0)).Width();
+}
+
+tools::Long SvxRuler::ConvertVPosPixel(tools::Long nVal) const
+{
+ return pEditWin->LogicToPixel(Size(0, nVal)).Height();
+}
+
+tools::Long SvxRuler::ConvertHSizePixel(tools::Long nVal) const
+{
+ return pEditWin->LogicToPixel(Size(nVal, 0)).Width();
+}
+
+tools::Long SvxRuler::ConvertVSizePixel(tools::Long nVal) const
+{
+ return pEditWin->LogicToPixel(Size(0, nVal)).Height();
+}
+
+tools::Long SvxRuler::ConvertPosPixel(tools::Long nVal) const
+{
+ return bHorz ? ConvertHPosPixel(nVal): ConvertVPosPixel(nVal);
+}
+
+tools::Long SvxRuler::ConvertSizePixel(tools::Long nVal) const
+{
+ return bHorz? ConvertHSizePixel(nVal): ConvertVSizePixel(nVal);
+}
+
+inline tools::Long SvxRuler::ConvertHPosLogic(tools::Long nVal) const
+{
+ return pEditWin->PixelToLogic(Size(nVal, 0)).Width();
+}
+
+inline tools::Long SvxRuler::ConvertVPosLogic(tools::Long nVal) const
+{
+ return pEditWin->PixelToLogic(Size(0, nVal)).Height();
+}
+
+inline tools::Long SvxRuler::ConvertHSizeLogic(tools::Long nVal) const
+{
+ return pEditWin->PixelToLogic(Size(nVal, 0)).Width();
+}
+
+inline tools::Long SvxRuler::ConvertVSizeLogic(tools::Long nVal) const
+{
+ return pEditWin->PixelToLogic(Size(0, nVal)).Height();
+}
+
+inline tools::Long SvxRuler::ConvertPosLogic(tools::Long nVal) const
+{
+ return bHorz? ConvertHPosLogic(nVal): ConvertVPosLogic(nVal);
+}
+
+inline tools::Long SvxRuler::ConvertSizeLogic(tools::Long nVal) const
+{
+ return bHorz? ConvertHSizeLogic(nVal): ConvertVSizeLogic(nVal);
+}
+
+tools::Long SvxRuler::PixelHAdjust(tools::Long nVal, tools::Long nValOld) const
+{
+ if(ConvertHSizePixel(nVal) != ConvertHSizePixel(nValOld))
+ return nVal;
+ else
+ return nValOld;
+}
+
+tools::Long SvxRuler::PixelVAdjust(tools::Long nVal, tools::Long nValOld) const
+{
+ if(ConvertVSizePixel(nVal) != ConvertVSizePixel(nValOld))
+ return nVal;
+ else
+ return nValOld;
+}
+
+tools::Long SvxRuler::PixelAdjust(tools::Long nVal, tools::Long nValOld) const
+{
+ if(ConvertSizePixel(nVal) != ConvertSizePixel(nValOld))
+ return nVal;
+ else
+ return nValOld;
+}
+
+inline sal_uInt16 SvxRuler::GetObjectBordersOff(sal_uInt16 nIdx) const
+{
+ return bHorz ? nIdx : nIdx + 2;
+}
+
+/*
+ Update Upper Left edge.
+ Items are translated into the representation of the ruler.
+*/
+void SvxRuler::UpdateFrame()
+{
+ const RulerMarginStyle nMarginStyle =
+ ( mxRulerImpl->aProtectItem->IsSizeProtected() ||
+ mxRulerImpl->aProtectItem->IsPosProtected() ) ?
+ RulerMarginStyle::NONE : RulerMarginStyle::Sizeable;
+
+ if(mxLRSpaceItem && mxPagePosItem)
+ {
+ // if no initialization by default app behavior
+ const tools::Long nOld = lLogicNullOffset;
+ lLogicNullOffset = mxColumnItem ? mxColumnItem->GetLeft() : mxLRSpaceItem->GetLeft();
+
+ if(bAppSetNullOffset)
+ {
+ lAppNullOffset += lLogicNullOffset - nOld;
+ }
+
+ if(!bAppSetNullOffset || lAppNullOffset == LONG_MAX)
+ {
+ Ruler::SetNullOffset(ConvertHPosPixel(lLogicNullOffset));
+ SetMargin1(0, nMarginStyle);
+ lAppNullOffset = 0;
+ }
+ else
+ {
+ SetMargin1(ConvertHPosPixel(lAppNullOffset), nMarginStyle);
+ }
+
+ tools::Long lRight = 0;
+
+ // evaluate the table right edge of the table
+ if(mxColumnItem && mxColumnItem->IsTable())
+ lRight = mxColumnItem->GetRight();
+ else
+ lRight = mxLRSpaceItem->GetRight();
+
+ tools::Long aWidth = mxPagePosItem->GetWidth() - lRight - lLogicNullOffset + lAppNullOffset;
+ tools::Long aWidthPixel = ConvertHPosPixel(aWidth);
+
+ SetMargin2(aWidthPixel, nMarginStyle);
+ }
+ else if(mxULSpaceItem && mxPagePosItem)
+ {
+ // relative the upper edge of the surrounding frame
+ const tools::Long nOld = lLogicNullOffset;
+ lLogicNullOffset = mxColumnItem ? mxColumnItem->GetLeft() : mxULSpaceItem->GetUpper();
+
+ if(bAppSetNullOffset)
+ {
+ lAppNullOffset += lLogicNullOffset - nOld;
+ }
+
+ if(!bAppSetNullOffset || lAppNullOffset == LONG_MAX)
+ {
+ Ruler::SetNullOffset(ConvertVPosPixel(lLogicNullOffset));
+ lAppNullOffset = 0;
+ SetMargin1(0, nMarginStyle);
+ }
+ else
+ {
+ SetMargin1(ConvertVPosPixel(lAppNullOffset), nMarginStyle);
+ }
+
+ tools::Long lLower = mxColumnItem ? mxColumnItem->GetRight() : mxULSpaceItem->GetLower();
+ tools::Long nMargin2 = mxPagePosItem->GetHeight() - lLower - lLogicNullOffset + lAppNullOffset;
+ tools::Long nMargin2Pixel = ConvertVPosPixel(nMargin2);
+
+ SetMargin2(nMargin2Pixel, nMarginStyle);
+ }
+ else
+ {
+ // turns off the view
+ SetMargin1();
+ SetMargin2();
+ }
+
+ if (mxColumnItem)
+ {
+ mxRulerImpl->nColLeftPix = static_cast<sal_uInt16>(ConvertSizePixel(mxColumnItem->GetLeft()));
+ mxRulerImpl->nColRightPix = static_cast<sal_uInt16>(ConvertSizePixel(mxColumnItem->GetRight()));
+ }
+}
+
+void SvxRuler::MouseMove( const MouseEvent& rMEvt )
+{
+ if( bActive )
+ {
+ pBindings->Update( SID_RULER_LR_MIN_MAX );
+ pBindings->Update( SID_ATTR_LONG_ULSPACE );
+ pBindings->Update( SID_ATTR_LONG_LRSPACE );
+ pBindings->Update( SID_RULER_PAGE_POS );
+ pBindings->Update( bHorz ? SID_ATTR_TABSTOP : SID_ATTR_TABSTOP_VERTICAL);
+ pBindings->Update( bHorz ? SID_ATTR_PARA_LRSPACE : SID_ATTR_PARA_LRSPACE_VERTICAL);
+ pBindings->Update( bHorz ? SID_RULER_BORDERS : SID_RULER_BORDERS_VERTICAL);
+ pBindings->Update( bHorz ? SID_RULER_ROWS : SID_RULER_ROWS_VERTICAL);
+ pBindings->Update( SID_RULER_OBJECT );
+ pBindings->Update( SID_RULER_PROTECT );
+ }
+
+ Ruler::MouseMove( rMEvt );
+
+ RulerSelection aSelection = GetHoverSelection();
+
+ if (aSelection.eType == RulerType::DontKnow)
+ {
+ SetQuickHelpText("");
+ return;
+ }
+
+ RulerUnitData aUnitData = GetCurrentRulerUnit();
+ double aRoundingFactor = aUnitData.nTickUnit / aUnitData.nTick1;
+ sal_Int32 aNoDecimalPlaces = 1 + std::ceil(std::log10(aRoundingFactor));
+ OUString sUnit = OUString::createFromAscii(aUnitData.aUnitStr);
+
+ switch (aSelection.eType)
+ {
+ case RulerType::Indent:
+ {
+ if (!mxParaItem)
+ break;
+
+ tools::Long nIndex = aSelection.nAryPos + INDENT_GAP;
+
+ tools::Long nIndentValue = 0.0;
+ if (nIndex == INDENT_LEFT_MARGIN)
+ nIndentValue = mxParaItem->GetTextLeft();
+ else if (nIndex == INDENT_FIRST_LINE)
+ nIndentValue = mxParaItem->GetTextFirstLineOffset();
+ else if (nIndex == INDENT_RIGHT_MARGIN)
+ nIndentValue = mxParaItem->GetRight();
+
+ double fValue = OutputDevice::LogicToLogic(Size(nIndentValue, 0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width();
+ fValue = rtl::math::round(fValue / aUnitData.nTickUnit, aNoDecimalPlaces);
+
+ SetQuickHelpText(OUString::number(fValue) + " " + sUnit);
+ break;
+ }
+ case RulerType::Border:
+ {
+ if (mxColumnItem == nullptr)
+ break;
+
+ SvxColumnItem& aColumnItem = *mxColumnItem;
+
+ if (aSelection.nAryPos + 1 >= aColumnItem.Count())
+ break;
+
+ double fStart = OutputDevice::LogicToLogic(Size(aColumnItem[aSelection.nAryPos].nEnd, 0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width();
+ fStart = rtl::math::round(fStart / aUnitData.nTickUnit, aNoDecimalPlaces);
+ double fEnd = OutputDevice::LogicToLogic(Size(aColumnItem[aSelection.nAryPos + 1].nStart, 0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width();
+ fEnd = rtl::math::round(fEnd / aUnitData.nTickUnit, aNoDecimalPlaces);
+
+ SetQuickHelpText(
+ OUString::number(fStart) + " " + sUnit + " - " +
+ OUString::number(fEnd) + " " + sUnit );
+ break;
+ }
+ case RulerType::Margin1:
+ {
+ tools::Long nLeft = 0.0;
+ if (mxLRSpaceItem)
+ nLeft = mxLRSpaceItem->GetLeft();
+ else if (mxULSpaceItem)
+ nLeft = mxULSpaceItem->GetUpper();
+ else
+ break;
+
+ double fValue = OutputDevice::LogicToLogic(Size(nLeft, 0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width();
+ fValue = rtl::math::round(fValue / aUnitData.nTickUnit, aNoDecimalPlaces);
+ SetQuickHelpText(OUString::number(fValue) + " " + sUnit);
+
+ break;
+ }
+ case RulerType::Margin2:
+ {
+ tools::Long nRight = 0.0;
+ if (mxLRSpaceItem)
+ nRight = mxLRSpaceItem->GetRight();
+ else if (mxULSpaceItem)
+ nRight = mxULSpaceItem->GetLower();
+ else
+ break;
+
+ double fValue = OutputDevice::LogicToLogic(Size(nRight, 0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width();
+ fValue = rtl::math::round(fValue / aUnitData.nTickUnit, aNoDecimalPlaces);
+ SetQuickHelpText(OUString::number(fValue) + " " + sUnit);
+
+ break;
+ }
+ default:
+ {
+ SetQuickHelpText("");
+ break;
+ }
+ }
+}
+
+void SvxRuler::StartListening_Impl()
+{
+ if(!bListening)
+ {
+ bValid = false;
+ StartListening(*pBindings);
+ bListening = true;
+ }
+}
+
+void SvxRuler::UpdateFrame(const SvxLongLRSpaceItem *pItem) // new value LRSpace
+{
+ /* Store new value LRSpace; delete old ones if possible */
+ if(bActive)
+ {
+ if(pItem)
+ mxLRSpaceItem.reset(new SvxLongLRSpaceItem(*pItem));
+ else
+ mxLRSpaceItem.reset();
+ StartListening_Impl();
+ }
+}
+
+void SvxRuler::UpdateFrameMinMax(const SfxRectangleItem *pItem) // value for MinMax
+{
+ /* Set new value for MinMax; delete old ones if possible */
+ if(bActive)
+ {
+ if(pItem)
+ mxMinMaxItem.reset(new SfxRectangleItem(*pItem));
+ else
+ mxMinMaxItem.reset();
+ }
+}
+
+
+void SvxRuler::UpdateFrame(const SvxLongULSpaceItem *pItem) // new value
+{
+ /* Update Right/bottom margin */
+ if(bActive && !bHorz)
+ {
+ if(pItem)
+ mxULSpaceItem.reset(new SvxLongULSpaceItem(*pItem));
+ else
+ mxULSpaceItem.reset();
+ StartListening_Impl();
+ }
+}
+
+void SvxRuler::Update( const SvxProtectItem* pItem )
+{
+ if( pItem )
+ mxRulerImpl->aProtectItem.reset(pItem->Clone());
+}
+
+void SvxRuler::UpdateTextRTL(const SfxBoolItem* pItem)
+{
+ if(bActive && bHorz)
+ {
+ mxRulerImpl->pTextRTLItem.reset();
+ if(pItem)
+ mxRulerImpl->pTextRTLItem.reset(new SfxBoolItem(*pItem));
+ SetTextRTL(mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue());
+ StartListening_Impl();
+ }
+}
+
+void SvxRuler::Update(
+ const SvxColumnItem *pItem, // new value
+ sal_uInt16 nSID) //Slot Id to identify NULL items
+{
+ /* Set new value for column view */
+ if(!bActive)
+ return;
+
+ if(pItem)
+ {
+ mxColumnItem.reset(new SvxColumnItem(*pItem));
+ mxRulerImpl->bIsTableRows = (pItem->Which() == SID_RULER_ROWS || pItem->Which() == SID_RULER_ROWS_VERTICAL);
+ if(!bHorz && !mxRulerImpl->bIsTableRows)
+ mxColumnItem->SetWhich(SID_RULER_BORDERS_VERTICAL);
+ }
+ else if(mxColumnItem && mxColumnItem->Which() == nSID)
+ //there are two groups of column items table/frame columns and table rows
+ //both can occur in vertical or horizontal mode
+ //the horizontal ruler handles the SID_RULER_BORDERS and SID_RULER_ROWS_VERTICAL
+ //and the vertical handles SID_RULER_BORDERS_VERTICAL and SID_RULER_ROWS
+ //if mxColumnItem is already set with one of the ids then a NULL pItem argument
+ //must not delete it
+ {
+ mxColumnItem.reset();
+ mxRulerImpl->bIsTableRows = false;
+ }
+ StartListening_Impl();
+}
+
+
+void SvxRuler::UpdateColumns()
+{
+ /* Update column view */
+ if(mxColumnItem && mxColumnItem->Count() > 1)
+ {
+ mpBorders.resize(mxColumnItem->Count());
+
+ RulerBorderStyle nStyleFlags = RulerBorderStyle::Variable;
+
+ bool bProtectColumns =
+ mxRulerImpl->aProtectItem->IsSizeProtected() ||
+ mxRulerImpl->aProtectItem->IsPosProtected();
+
+ if( !bProtectColumns )
+ {
+ nStyleFlags |= RulerBorderStyle::Moveable;
+ if( !mxColumnItem->IsTable() )
+ nStyleFlags |= RulerBorderStyle::Sizeable;
+ }
+
+ sal_uInt16 nBorders = mxColumnItem->Count();
+
+ if(!mxRulerImpl->bIsTableRows)
+ --nBorders;
+
+ for(sal_uInt16 i = 0; i < nBorders; ++i)
+ {
+ mpBorders[i].nStyle = nStyleFlags;
+ if(!mxColumnItem->At(i).bVisible)
+ mpBorders[i].nStyle |= RulerBorderStyle::Invisible;
+
+ mpBorders[i].nPos = ConvertPosPixel(mxColumnItem->At(i).nEnd + lAppNullOffset);
+
+ if(mxColumnItem->Count() == i + 1)
+ {
+ //with table rows the end of the table is contained in the
+ //column item but it has no width!
+ mpBorders[i].nWidth = 0;
+ }
+ else
+ {
+ mpBorders[i].nWidth = ConvertSizePixel(mxColumnItem->At(i + 1).nStart - mxColumnItem->At(i).nEnd);
+ }
+ mpBorders[i].nMinPos = ConvertPosPixel(mxColumnItem->At(i).nEndMin + lAppNullOffset);
+ mpBorders[i].nMaxPos = ConvertPosPixel(mxColumnItem->At(i).nEndMax + lAppNullOffset);
+ }
+ SetBorders(mxColumnItem->Count() - 1, mpBorders.data());
+ }
+ else
+ {
+ SetBorders();
+ }
+}
+
+void SvxRuler::UpdateObject()
+{
+ /* Update view of object representation */
+ if (mxObjectItem)
+ {
+ DBG_ASSERT(!mpObjectBorders.empty(), "no Buffer");
+ // !! to the page margin
+ tools::Long nMargin = mxLRSpaceItem ? mxLRSpaceItem->GetLeft() : 0;
+ mpObjectBorders[0].nPos =
+ ConvertPosPixel(mxObjectItem->GetStartX() -
+ nMargin + lAppNullOffset);
+ mpObjectBorders[1].nPos =
+ ConvertPosPixel(mxObjectItem->GetEndX() - nMargin + lAppNullOffset);
+ nMargin = mxULSpaceItem ? mxULSpaceItem->GetUpper() : 0;
+ mpObjectBorders[2].nPos =
+ ConvertPosPixel(mxObjectItem->GetStartY() -
+ nMargin + lAppNullOffset);
+ mpObjectBorders[3].nPos =
+ ConvertPosPixel(mxObjectItem->GetEndY() - nMargin + lAppNullOffset);
+
+ const sal_uInt16 nOffset = GetObjectBordersOff(0);
+ SetBorders(2, mpObjectBorders.data() + nOffset);
+ }
+ else
+ {
+ SetBorders();
+ }
+}
+
+void SvxRuler::UpdatePara()
+{
+
+ /* Update the view for paragraph indents:
+ Left margin, first line indent, right margin paragraph update
+ mpIndents[0] = Buffer for old intent
+ mpIndents[1] = Buffer for old intent
+ mpIndents[INDENT_FIRST_LINE] = first line indent
+ mpIndents[INDENT_LEFT_MARGIN] = left margin
+ mpIndents[INDENT_RIGHT_MARGIN] = right margin
+ */
+
+ // Dependence on PagePosItem
+ if (mxParaItem && mxPagePosItem && !mxObjectItem)
+ {
+ bool bRTLText = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
+ // First-line indent is negative to the left paragraph margin
+ tools::Long nLeftFrameMargin = GetLeftFrameMargin();
+ tools::Long nRightFrameMargin = GetRightFrameMargin();
+ SetLeftFrameMargin(ConvertHPosPixel(nLeftFrameMargin));
+ SetRightFrameMargin(ConvertHPosPixel(nRightFrameMargin));
+
+ tools::Long leftMargin;
+ tools::Long leftFirstLine;
+ tools::Long rightMargin;
+
+ if(bRTLText)
+ {
+ leftMargin = nRightFrameMargin - mxParaItem->GetTextLeft() + lAppNullOffset;
+ leftFirstLine = leftMargin - mxParaItem->GetTextFirstLineOffset();
+ rightMargin = nLeftFrameMargin + mxParaItem->GetRight() + lAppNullOffset;
+ }
+ else
+ {
+ leftMargin = nLeftFrameMargin + mxParaItem->GetTextLeft() + lAppNullOffset;
+ leftFirstLine = leftMargin + mxParaItem->GetTextFirstLineOffset();
+ rightMargin = nRightFrameMargin - mxParaItem->GetRight() + lAppNullOffset;
+ }
+
+ mpIndents[INDENT_LEFT_MARGIN].nPos = ConvertHPosPixel(leftMargin);
+ mpIndents[INDENT_FIRST_LINE].nPos = ConvertHPosPixel(leftFirstLine);
+ mpIndents[INDENT_RIGHT_MARGIN].nPos = ConvertHPosPixel(rightMargin);
+
+ mpIndents[INDENT_FIRST_LINE].bInvisible = mxParaItem->IsAutoFirst();
+
+ SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
+ }
+ else
+ {
+ if(!mpIndents.empty())
+ {
+ mpIndents[INDENT_FIRST_LINE].nPos = 0;
+ mpIndents[INDENT_LEFT_MARGIN].nPos = 0;
+ mpIndents[INDENT_RIGHT_MARGIN].nPos = 0;
+ }
+ SetIndents(); // turn off
+ }
+}
+
+void SvxRuler::UpdatePara(const SvxLRSpaceItem *pItem) // new value of paragraph indents
+{
+ /* Store new value of paragraph indents */
+ if(bActive)
+ {
+ if(pItem)
+ mxParaItem.reset(new SvxLRSpaceItem(*pItem));
+ else
+ mxParaItem.reset();
+ StartListening_Impl();
+ }
+}
+
+void SvxRuler::UpdateBorder(const SvxLRSpaceItem * pItem)
+{
+ /* Border distance */
+ if(bActive)
+ {
+ if (pItem)
+ mxBorderItem.reset(new SvxLRSpaceItem(*pItem));
+ else
+ mxBorderItem.reset();
+
+ StartListening_Impl();
+ }
+}
+
+void SvxRuler::UpdatePage()
+{
+ /* Update view of position and width of page */
+ if (mxPagePosItem)
+ {
+ // all objects are automatically adjusted
+ if(bHorz)
+ {
+ SetPagePos(
+ pEditWin->LogicToPixel(mxPagePosItem->GetPos()).X(),
+ pEditWin->LogicToPixel(Size(mxPagePosItem->GetWidth(), 0)).
+ Width());
+ }
+ else
+ {
+ SetPagePos(
+ pEditWin->LogicToPixel(mxPagePosItem->GetPos()).Y(),
+ pEditWin->LogicToPixel(Size(0, mxPagePosItem->GetHeight())).
+ Height());
+ }
+ if(bAppSetNullOffset)
+ SetNullOffset(ConvertSizePixel(-lAppNullOffset + lLogicNullOffset));
+ }
+ else
+ {
+ SetPagePos();
+ }
+
+ tools::Long lPos = 0;
+ Point aOwnPos = GetPosPixel();
+ Point aEdtWinPos = pEditWin->GetPosPixel();
+ if( AllSettings::GetLayoutRTL() && bHorz )
+ {
+ //#i73321# in RTL the window and the ruler is not mirrored but the
+ // influence of the vertical ruler is inverted
+ Size aOwnSize = GetSizePixel();
+ Size aEdtWinSize = pEditWin->GetSizePixel();
+ lPos = aOwnSize.Width() - aEdtWinSize.Width();
+ lPos -= (aEdtWinPos - aOwnPos).X();
+ }
+ else
+ {
+ Point aPos(aEdtWinPos - aOwnPos);
+ lPos = bHorz ? aPos.X() : aPos.Y();
+ }
+
+ // Unfortunately, we get the offset of the edit window to the ruler never
+ // through a status message. So we set it ourselves if necessary.
+ if(lPos != mxRulerImpl->lOldWinPos)
+ {
+ mxRulerImpl->lOldWinPos=lPos;
+ SetWinPos(lPos);
+ }
+}
+
+void SvxRuler::Update(const SvxPagePosSizeItem *pItem) // new value of page attributes
+{
+ /* Store new value of page attributes */
+ if(bActive)
+ {
+ if(pItem)
+ mxPagePosItem.reset(new SvxPagePosSizeItem(*pItem));
+ else
+ mxPagePosItem.reset();
+ StartListening_Impl();
+ }
+}
+
+void SvxRuler::SetDefTabDist(tools::Long inDefTabDist) // New distance for DefaultTabs in App-Metrics
+{
+ if (lAppNullOffset == LONG_MAX)
+ UpdateFrame(); // hack: try to get lAppNullOffset initialized
+ /* New distance is set for DefaultTabs */
+ lDefTabDist = inDefTabDist;
+ if( !lDefTabDist )
+ lDefTabDist = 1;
+
+ UpdateTabs();
+}
+
+static sal_uInt16 ToSvTab_Impl(SvxTabAdjust eAdj)
+{
+ /* Internal conversion routine between SV-Tab.-Enum and Svx */
+ switch(eAdj) {
+ case SvxTabAdjust::Left: return RULER_TAB_LEFT;
+ case SvxTabAdjust::Right: return RULER_TAB_RIGHT;
+ case SvxTabAdjust::Decimal: return RULER_TAB_DECIMAL;
+ case SvxTabAdjust::Center: return RULER_TAB_CENTER;
+ case SvxTabAdjust::Default: return RULER_TAB_DEFAULT;
+ default: ; //prevent warning
+ }
+ return 0;
+}
+
+static SvxTabAdjust ToAttrTab_Impl(sal_uInt16 eAdj)
+{
+ switch(eAdj) {
+ case RULER_TAB_LEFT: return SvxTabAdjust::Left ;
+ case RULER_TAB_RIGHT: return SvxTabAdjust::Right ;
+ case RULER_TAB_DECIMAL: return SvxTabAdjust::Decimal ;
+ case RULER_TAB_CENTER: return SvxTabAdjust::Center ;
+ case RULER_TAB_DEFAULT: return SvxTabAdjust::Default ;
+ }
+ return SvxTabAdjust::Left;
+}
+
+void SvxRuler::UpdateTabs()
+{
+ if(IsDrag())
+ return;
+
+ if (mxPagePosItem && mxParaItem && mxTabStopItem && !mxObjectItem)
+ {
+ // buffer for DefaultTabStop
+ // Distance last Tab <-> Right paragraph margin / DefaultTabDist
+ bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
+
+ const tools::Long nLeftFrameMargin = GetLeftFrameMargin();
+ const tools::Long nRightFrameMargin = GetRightFrameMargin();
+
+ //#i24363# tab stops relative to indent
+ const tools::Long nParaItemTxtLeft = mxParaItem->GetTextLeft();
+
+ const tools::Long lParaIndent = nLeftFrameMargin + nParaItemTxtLeft;
+ const tools::Long lRightMargin = nRightFrameMargin - nParaItemTxtLeft;
+
+ const tools::Long lLastTab = mxTabStopItem->Count()
+ ? ConvertHPosPixel(mxTabStopItem->At(mxTabStopItem->Count() - 1).GetTabPos())
+ : 0;
+ const tools::Long lPosPixel = ConvertHPosPixel(lParaIndent) + lLastTab;
+ const tools::Long lRightIndent = ConvertHPosPixel(nRightFrameMargin - mxParaItem->GetRight());
+
+ tools::Long lCurrentDefTabDist = lDefTabDist;
+ if(mxTabStopItem->GetDefaultDistance())
+ lCurrentDefTabDist = mxTabStopItem->GetDefaultDistance();
+ tools::Long nDefTabDist = ConvertHPosPixel(lCurrentDefTabDist);
+
+ const sal_uInt16 nDefTabBuf = lPosPixel > lRightIndent || lLastTab > lRightIndent
+ ? 0
+ : static_cast<sal_uInt16>( (lRightIndent - lPosPixel) / nDefTabDist );
+
+ if(mxTabStopItem->Count() + TAB_GAP + nDefTabBuf > nTabBufSize)
+ {
+ // 10 (GAP) in stock
+ nTabBufSize = mxTabStopItem->Count() + TAB_GAP + nDefTabBuf + GAP;
+ mpTabs.resize(nTabBufSize);
+ }
+
+ nTabCount = 0;
+ sal_uInt16 j;
+
+ const tools::Long lParaIndentPix = ConvertSizePixel(lParaIndent);
+
+ tools::Long lTabStartLogic = (mxRulerImpl->bIsTabsRelativeToIndent ? lParaIndent : nLeftFrameMargin)
+ + lAppNullOffset;
+ if (bRTL)
+ {
+ lTabStartLogic = lParaIndent + lRightMargin - lTabStartLogic;
+ }
+ tools::Long lLastTabOffsetLogic = 0;
+ for(j = 0; j < mxTabStopItem->Count(); ++j)
+ {
+ const SvxTabStop* pTab = &mxTabStopItem->At(j);
+ lLastTabOffsetLogic = pTab->GetTabPos();
+ tools::Long lPos = lTabStartLogic + (bRTL ? -lLastTabOffsetLogic : lLastTabOffsetLogic);
+ mpTabs[nTabCount + TAB_GAP].nPos = ConvertHPosPixel(lPos);
+ mpTabs[nTabCount + TAB_GAP].nStyle = ToSvTab_Impl(pTab->GetAdjustment());
+ ++nTabCount;
+ }
+
+ // Adjust to previous-to-first default tab stop
+ lLastTabOffsetLogic -= lLastTabOffsetLogic % lCurrentDefTabDist;
+
+ // fill the rest with default Tabs
+ for (j = 0; j < nDefTabBuf; ++j)
+ {
+ //simply add the default distance to the last position
+ lLastTabOffsetLogic += lCurrentDefTabDist;
+ if (bRTL)
+ {
+ mpTabs[nTabCount + TAB_GAP].nPos =
+ ConvertHPosPixel(lTabStartLogic - lLastTabOffsetLogic);
+ if (mpTabs[nTabCount + TAB_GAP].nPos <= lParaIndentPix)
+ break;
+ }
+ else
+ {
+ mpTabs[nTabCount + TAB_GAP].nPos =
+ ConvertHPosPixel(lTabStartLogic + lLastTabOffsetLogic);
+ if (mpTabs[nTabCount + TAB_GAP].nPos >= lRightIndent)
+ break;
+ }
+
+ mpTabs[nTabCount + TAB_GAP].nStyle = RULER_TAB_DEFAULT;
+ ++nTabCount;
+ }
+ SetTabs(nTabCount, mpTabs.data() + TAB_GAP);
+ DBG_ASSERT(nTabCount + TAB_GAP <= nTabBufSize, "BufferSize too small");
+ }
+ else
+ {
+ SetTabs();
+ }
+}
+
+void SvxRuler::Update(const SvxTabStopItem *pItem) // new value for tabs
+{
+ /* Store new value for tabs; delete old ones if possible */
+ if(!bActive)
+ return;
+
+ if(pItem)
+ {
+ mxTabStopItem.reset(new SvxTabStopItem(*pItem));
+ if(!bHorz)
+ mxTabStopItem->SetWhich(SID_ATTR_TABSTOP_VERTICAL);
+ }
+ else
+ {
+ mxTabStopItem.reset();
+ }
+ StartListening_Impl();
+}
+
+void SvxRuler::Update(const SvxObjectItem *pItem) // new value for objects
+{
+ /* Store new value for objects */
+ if(bActive)
+ {
+ if(pItem)
+ mxObjectItem.reset(new SvxObjectItem(*pItem));
+ else
+ mxObjectItem.reset();
+ StartListening_Impl();
+ }
+}
+
+void SvxRuler::SetNullOffsetLogic(tools::Long lVal) // Setting of the logic NullOffsets
+{
+ lAppNullOffset = lLogicNullOffset - lVal;
+ bAppSetNullOffset = true;
+ Ruler::SetNullOffset(ConvertSizePixel(lVal));
+ Update();
+}
+
+void SvxRuler::Update()
+{
+ /* Perform update of view */
+ if(IsDrag())
+ return;
+
+ UpdatePage();
+ UpdateFrame();
+ if(nFlags & SvxRulerSupportFlags::OBJECT)
+ UpdateObject();
+ else
+ UpdateColumns();
+
+ if(nFlags & (SvxRulerSupportFlags::PARAGRAPH_MARGINS | SvxRulerSupportFlags::PARAGRAPH_MARGINS_VERTICAL))
+ UpdatePara();
+
+ if(nFlags & SvxRulerSupportFlags::TABS)
+ UpdateTabs();
+}
+
+tools::Long SvxRuler::GetPageWidth() const
+{
+ if (!mxPagePosItem)
+ return 0;
+ return bHorz ? mxPagePosItem->GetWidth() : mxPagePosItem->GetHeight();
+}
+
+inline tools::Long SvxRuler::GetFrameLeft() const
+{
+ /* Get Left margin in Pixels */
+ return bAppSetNullOffset ?
+ GetMargin1() + ConvertSizePixel(lLogicNullOffset) :
+ Ruler::GetNullOffset();
+}
+
+tools::Long SvxRuler::GetFirstLineIndent() const
+{
+ /* Get First-line indent in pixels */
+ return mxParaItem ? mpIndents[INDENT_FIRST_LINE].nPos : GetMargin1();
+}
+
+tools::Long SvxRuler::GetLeftIndent() const
+{
+ /* Get Left paragraph margin in Pixels */
+ return mxParaItem ? mpIndents[INDENT_LEFT_MARGIN].nPos : GetMargin1();
+}
+
+tools::Long SvxRuler::GetRightIndent() const
+{
+ /* Get Right paragraph margin in Pixels */
+ return mxParaItem ? mpIndents[INDENT_RIGHT_MARGIN].nPos : GetMargin2();
+}
+
+tools::Long SvxRuler::GetLogicRightIndent() const
+{
+ /* Get Right paragraph margin in Logic */
+ return mxParaItem ? GetRightFrameMargin() - mxParaItem->GetRight() : GetRightFrameMargin();
+}
+
+// Left margin in App values, is either the margin (= 0) or the left edge of
+// the column that is set in the column attribute as current column.
+tools::Long SvxRuler::GetLeftFrameMargin() const
+{
+ // #126721# for some unknown reason the current column is set to 0xffff
+ DBG_ASSERT(!mxColumnItem || mxColumnItem->GetActColumn() < mxColumnItem->Count(),
+ "issue #126721# - invalid current column!");
+ tools::Long nLeft = 0;
+ if (mxColumnItem &&
+ mxColumnItem->Count() &&
+ mxColumnItem->IsConsistent())
+ {
+ nLeft = mxColumnItem->GetActiveColumnDescription().nStart;
+ }
+
+ if (mxBorderItem && (!mxColumnItem || mxColumnItem->IsTable()))
+ nLeft += mxBorderItem->GetLeft();
+
+ return nLeft;
+}
+
+inline tools::Long SvxRuler::GetLeftMin() const
+{
+ DBG_ASSERT(mxMinMaxItem, "no MinMax value set");
+ if (mxMinMaxItem)
+ {
+ if (bHorz)
+ return mxMinMaxItem->GetValue().Left();
+ else
+ return mxMinMaxItem->GetValue().Top();
+ }
+ return 0;
+}
+
+inline tools::Long SvxRuler::GetRightMax() const
+{
+ DBG_ASSERT(mxMinMaxItem, "no MinMax value set");
+ if (mxMinMaxItem)
+ {
+ if (bHorz)
+ return mxMinMaxItem->GetValue().Right();
+ else
+ return mxMinMaxItem->GetValue().Bottom();
+ }
+ return 0;
+}
+
+
+tools::Long SvxRuler::GetRightFrameMargin() const
+{
+ /* Get right frame margin (in logical units) */
+ if (mxColumnItem)
+ {
+ if (!IsActLastColumn(true))
+ {
+ return mxColumnItem->At(GetActRightColumn(true)).nEnd;
+ }
+ }
+
+ tools::Long lResult = lLogicNullOffset;
+
+ // If possible deduct right table entry
+ if(mxColumnItem && mxColumnItem->IsTable())
+ lResult += mxColumnItem->GetRight();
+ else if(bHorz && mxLRSpaceItem)
+ lResult += mxLRSpaceItem->GetRight();
+ else if(!bHorz && mxULSpaceItem)
+ lResult += mxULSpaceItem->GetLower();
+
+ if (bHorz && mxBorderItem && (!mxColumnItem || mxColumnItem->IsTable()))
+ lResult += mxBorderItem->GetRight();
+
+ if(bHorz)
+ lResult = mxPagePosItem->GetWidth() - lResult;
+ else
+ lResult = mxPagePosItem->GetHeight() - lResult;
+
+ return lResult;
+}
+
+#define NEG_FLAG ( (nFlags & SvxRulerSupportFlags::NEGATIVE_MARGINS) == \
+ SvxRulerSupportFlags::NEGATIVE_MARGINS )
+#define TAB_FLAG ( mxColumnItem && mxColumnItem->IsTable() )
+
+tools::Long SvxRuler::GetCorrectedDragPos( bool bLeft, bool bRight )
+{
+ /*
+ Corrects the position within the calculated limits. The limit values are in
+ pixels relative to the page edge.
+ */
+
+ const tools::Long lNullPix = Ruler::GetNullOffset();
+ tools::Long lDragPos = GetDragPos() + lNullPix;
+ bool bHoriRows = bHorz && mxRulerImpl->bIsTableRows;
+ if((bLeft || bHoriRows) && lDragPos < nMaxLeft)
+ lDragPos = nMaxLeft;
+ else if((bRight||bHoriRows) && lDragPos > nMaxRight)
+ lDragPos = nMaxRight;
+ return lDragPos - lNullPix;
+}
+
+static void ModifyTabs_Impl( sal_uInt16 nCount, // Number of Tabs
+ RulerTab* pTabs, // Tab buffer
+ tools::Long lDiff) // difference to be added
+{
+ /* Helper function, move all the tabs by a fixed value */
+ if( pTabs )
+ {
+ for(sal_uInt16 i = 0; i < nCount; ++i)
+ {
+ pTabs[i].nPos += lDiff;
+ }
+ }
+}
+
+void SvxRuler::DragMargin1()
+{
+ /* Dragging the left edge of frame */
+ tools::Long aDragPosition = GetCorrectedDragPos( !TAB_FLAG || !NEG_FLAG );
+
+ aDragPosition = MakePositionSticky(aDragPosition, GetRightFrameMargin(), false);
+
+ // Check if position changed
+ if (aDragPosition == 0)
+ return;
+
+ DrawLine_Impl(lTabPos, ( TAB_FLAG && NEG_FLAG ) ? 3 : 7, bHorz);
+ if (mxColumnItem && (nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL))
+ DragBorders();
+ AdjustMargin1(aDragPosition);
+}
+
+void SvxRuler::AdjustMargin1(tools::Long lInputDiff)
+{
+ const tools::Long nOld = bAppSetNullOffset? GetMargin1(): GetNullOffset();
+ const tools::Long lDragPos = lInputDiff;
+
+ bool bProtectColumns =
+ mxRulerImpl->aProtectItem->IsSizeProtected() ||
+ mxRulerImpl->aProtectItem->IsPosProtected();
+
+ const RulerMarginStyle nMarginStyle =
+ bProtectColumns ? RulerMarginStyle::NONE : RulerMarginStyle::Sizeable;
+
+ if(!bAppSetNullOffset)
+ {
+ tools::Long lDiff = lDragPos;
+ SetNullOffset(nOld + lDiff);
+ if (!mxColumnItem || !(nDragType & SvxRulerDragFlags::OBJECT_SIZE_LINEAR))
+ {
+ SetMargin2( GetMargin2() - lDiff, nMarginStyle );
+
+ if (!mxColumnItem && !mxObjectItem && mxParaItem)
+ {
+ // Right indent of the old position
+ mpIndents[INDENT_RIGHT_MARGIN].nPos -= lDiff;
+ SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
+ }
+ if (mxObjectItem)
+ {
+ mpObjectBorders[GetObjectBordersOff(0)].nPos -= lDiff;
+ mpObjectBorders[GetObjectBordersOff(1)].nPos -= lDiff;
+ SetBorders(2, mpObjectBorders.data() + GetObjectBordersOff(0));
+ }
+ if (mxColumnItem)
+ {
+ for(sal_uInt16 i = 0; i < mxColumnItem->Count()-1; ++i)
+ mpBorders[i].nPos -= lDiff;
+ SetBorders(mxColumnItem->Count()-1, mpBorders.data());
+ if(mxColumnItem->IsFirstAct())
+ {
+ // Right indent of the old position
+ if (mxParaItem)
+ {
+ mpIndents[INDENT_RIGHT_MARGIN].nPos -= lDiff;
+ SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
+ }
+ }
+ else
+ {
+ if (mxParaItem)
+ {
+ mpIndents[INDENT_FIRST_LINE].nPos -= lDiff;
+ mpIndents[INDENT_LEFT_MARGIN].nPos -= lDiff;
+ mpIndents[INDENT_RIGHT_MARGIN].nPos -= lDiff;
+ SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
+ }
+ }
+ if(mxTabStopItem && (nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)
+ &&!IsActFirstColumn())
+ {
+ ModifyTabs_Impl(nTabCount + TAB_GAP, mpTabs.data(), -lDiff);
+ SetTabs(nTabCount, mpTabs.data() + TAB_GAP);
+ }
+ }
+ }
+ }
+ else
+ {
+ tools::Long lDiff = lDragPos - nOld;
+ SetMargin1(nOld + lDiff, nMarginStyle);
+
+ if (!mxColumnItem
+ || !(nDragType
+ & (SvxRulerDragFlags::OBJECT_SIZE_LINEAR
+ | SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)))
+ {
+ if (!mxColumnItem && !mxObjectItem && mxParaItem)
+ {
+ // Left indent of the old position
+ mpIndents[INDENT_FIRST_LINE].nPos += lDiff;
+ mpIndents[INDENT_LEFT_MARGIN].nPos += lDiff;
+ SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
+ }
+
+ if (mxColumnItem)
+ {
+ for(sal_uInt16 i = 0; i < mxColumnItem->Count() - 1; ++i)
+ mpBorders[i].nPos += lDiff;
+ SetBorders(mxColumnItem->Count() - 1, mpBorders.data());
+ if (mxColumnItem->IsFirstAct())
+ {
+ // Left indent of the old position
+ if (mxParaItem)
+ {
+ mpIndents[INDENT_FIRST_LINE].nPos += lDiff;
+ mpIndents[INDENT_LEFT_MARGIN].nPos += lDiff;
+ SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
+ }
+ }
+ else
+ {
+ if (mxParaItem)
+ {
+ mpIndents[INDENT_FIRST_LINE].nPos += lDiff;
+ mpIndents[INDENT_LEFT_MARGIN].nPos += lDiff;
+ mpIndents[INDENT_RIGHT_MARGIN].nPos += lDiff;
+ SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
+ }
+ }
+ }
+ if (mxTabStopItem)
+ {
+ ModifyTabs_Impl(nTabCount + TAB_GAP, mpTabs.data(), lDiff);
+ SetTabs(nTabCount, mpTabs.data() + TAB_GAP);
+ }
+ }
+ }
+}
+
+void SvxRuler::DragMargin2()
+{
+ /* Dragging the right edge of frame */
+ tools::Long aDragPosition = GetCorrectedDragPos( true, !TAB_FLAG || !NEG_FLAG);
+ aDragPosition = MakePositionSticky(aDragPosition, GetLeftFrameMargin(), false);
+ tools::Long lDiff = aDragPosition - GetMargin2();
+
+ // Check if position changed
+ if (lDiff == 0)
+ return;
+
+ if( mxRulerImpl->bIsTableRows &&
+ !bHorz &&
+ mxColumnItem &&
+ (nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL))
+ {
+ DragBorders();
+ }
+
+ bool bProtectColumns =
+ mxRulerImpl->aProtectItem->IsSizeProtected() ||
+ mxRulerImpl->aProtectItem->IsPosProtected();
+
+ const RulerMarginStyle nMarginStyle = bProtectColumns ? RulerMarginStyle::NONE : RulerMarginStyle::Sizeable;
+
+ SetMargin2( aDragPosition, nMarginStyle );
+
+ // Right indent of the old position
+ if ((!mxColumnItem || IsActLastColumn()) && mxParaItem)
+ {
+ mpIndents[INDENT_FIRST_LINE].nPos += lDiff;
+ SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
+ }
+
+ DrawLine_Impl(lTabPos, ( TAB_FLAG && NEG_FLAG ) ? 5 : 7, bHorz);
+}
+
+void SvxRuler::DragIndents()
+{
+ /* Dragging the paragraph indents */
+ tools::Long aDragPosition = NEG_FLAG ? GetDragPos() : GetCorrectedDragPos();
+ const sal_uInt16 nIndex = GetDragAryPos() + INDENT_GAP;
+
+ bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
+
+ if(nIndex == INDENT_RIGHT_MARGIN)
+ aDragPosition = MakePositionSticky(aDragPosition, bRTL ? GetLeftFrameMargin() : GetRightFrameMargin());
+ else
+ aDragPosition = MakePositionSticky(aDragPosition, bRTL ? GetRightFrameMargin() : GetLeftFrameMargin());
+
+ const tools::Long lDiff = mpIndents[nIndex].nPos - aDragPosition;
+
+ // Check if position changed
+ if (lDiff == 0)
+ return;
+
+ if((nIndex == INDENT_FIRST_LINE || nIndex == INDENT_LEFT_MARGIN ) &&
+ !(nDragType & SvxRulerDragFlags::OBJECT_LEFT_INDENT_ONLY))
+ {
+ mpIndents[INDENT_FIRST_LINE].nPos -= lDiff;
+ }
+
+ mpIndents[nIndex].nPos = aDragPosition;
+
+ SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
+ DrawLine_Impl(lTabPos, 1, bHorz);
+}
+
+void SvxRuler::DrawLine_Impl(tools::Long& lTabPosition, int nNew, bool bHorizontal)
+{
+ /*
+ Output routine for the ledger line when moving tabs, tables and other
+ columns
+ */
+ if(bHorizontal)
+ {
+ const tools::Long nHeight = pEditWin->GetOutDev()->GetOutputSize().Height();
+ Point aZero = pEditWin->GetMapMode().GetOrigin();
+ if(lTabPosition != -1)
+ {
+ pEditWin->InvertTracking(
+ tools::Rectangle( Point(lTabPosition, -aZero.Y()),
+ Point(lTabPosition, -aZero.Y() + nHeight)),
+ ShowTrackFlags::Split | ShowTrackFlags::Clip );
+ }
+ if( nNew & 1 )
+ {
+ tools::Long nDrapPosition = GetCorrectedDragPos( ( nNew & 4 ) != 0, ( nNew & 2 ) != 0 );
+ nDrapPosition = MakePositionSticky(nDrapPosition, GetLeftFrameMargin());
+ lTabPosition = ConvertHSizeLogic( nDrapPosition + GetNullOffset() );
+ if (mxPagePosItem)
+ lTabPosition += mxPagePosItem->GetPos().X();
+ pEditWin->InvertTracking(
+ tools::Rectangle( Point(lTabPosition, -aZero.Y()),
+ Point(lTabPosition, -aZero.Y() + nHeight) ),
+ ShowTrackFlags::Clip | ShowTrackFlags::Split );
+ }
+ }
+ else
+ {
+ const tools::Long nWidth = pEditWin->GetOutDev()->GetOutputSize().Width();
+ Point aZero = pEditWin->GetMapMode().GetOrigin();
+ if(lTabPosition != -1)
+ {
+ pEditWin->InvertTracking(
+ tools::Rectangle( Point(-aZero.X(), lTabPosition),
+ Point(-aZero.X() + nWidth, lTabPosition)),
+ ShowTrackFlags::Split | ShowTrackFlags::Clip );
+ }
+
+ if(nNew & 1)
+ {
+ tools::Long nDrapPosition = GetCorrectedDragPos();
+ nDrapPosition = MakePositionSticky(nDrapPosition, GetLeftFrameMargin());
+ lTabPosition = ConvertVSizeLogic(nDrapPosition + GetNullOffset());
+ if (mxPagePosItem)
+ lTabPosition += mxPagePosItem->GetPos().Y();
+ pEditWin->InvertTracking(
+ tools::Rectangle( Point(-aZero.X(), lTabPosition),
+ Point(-aZero.X()+nWidth, lTabPosition)),
+ ShowTrackFlags::Clip | ShowTrackFlags::Split );
+ }
+ }
+}
+
+void SvxRuler::DragTabs()
+{
+ /* Dragging of Tabs */
+ tools::Long aDragPosition = GetCorrectedDragPos(true, false);
+ aDragPosition = MakePositionSticky(aDragPosition, GetLeftFrameMargin());
+
+ sal_uInt16 nIdx = GetDragAryPos() + TAB_GAP;
+ tools::Long nDiff = aDragPosition - mpTabs[nIdx].nPos;
+ if (nDiff == 0)
+ return;
+
+ DrawLine_Impl(lTabPos, 7, bHorz);
+
+ if(nDragType & SvxRulerDragFlags::OBJECT_SIZE_LINEAR)
+ {
+
+ for(sal_uInt16 i = nIdx; i < nTabCount; ++i)
+ {
+ mpTabs[i].nPos += nDiff;
+ // limit on maximum
+ if(mpTabs[i].nPos > GetMargin2())
+ mpTabs[nIdx].nStyle |= RULER_STYLE_INVISIBLE;
+ else
+ mpTabs[nIdx].nStyle &= ~RULER_STYLE_INVISIBLE;
+ }
+ }
+ else if(nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)
+ {
+ mxRulerImpl->nTotalDist -= nDiff;
+ mpTabs[nIdx].nPos = aDragPosition;
+ for(sal_uInt16 i = nIdx+1; i < nTabCount; ++i)
+ {
+ if(mpTabs[i].nStyle & RULER_TAB_DEFAULT)
+ // can be canceled at the DefaultTabs
+ break;
+ tools::Long nDelta = mxRulerImpl->nTotalDist * mxRulerImpl->pPercBuf[i];
+ nDelta /= 1000;
+ mpTabs[i].nPos = mpTabs[nIdx].nPos + nDelta;
+ if(mpTabs[i].nPos + GetNullOffset() > nMaxRight)
+ mpTabs[i].nStyle |= RULER_STYLE_INVISIBLE;
+ else
+ mpTabs[i].nStyle &= ~RULER_STYLE_INVISIBLE;
+ }
+ }
+ else
+ {
+ mpTabs[nIdx].nPos = aDragPosition;
+ }
+
+ if(IsDragDelete())
+ mpTabs[nIdx].nStyle |= RULER_STYLE_INVISIBLE;
+ else
+ mpTabs[nIdx].nStyle &= ~RULER_STYLE_INVISIBLE;
+ SetTabs(nTabCount, mpTabs.data() + TAB_GAP);
+}
+
+void SvxRuler::SetActive(bool bOn)
+{
+ if(bOn)
+ {
+ Activate();
+ }
+ else
+ Deactivate();
+ if(bActive!=bOn)
+ {
+ pBindings->EnterRegistrations();
+ if(bOn)
+ for(sal_uInt16 i=0;i<mxRulerImpl->nControllerItems;i++)
+ pCtrlItems[i]->ReBind();
+ else
+ for(sal_uInt16 j=0;j<mxRulerImpl->nControllerItems;j++)
+ pCtrlItems[j]->UnBind();
+ pBindings->LeaveRegistrations();
+ }
+ bActive = bOn;
+}
+
+void SvxRuler::UpdateParaContents_Impl(
+ tools::Long lDifference,
+ UpdateType eType) // Art (all, left or right)
+{
+ /* Helper function; carry Tabs and Paragraph Margins */
+ switch(eType)
+ {
+ case UpdateType::MoveRight:
+ mpIndents[INDENT_RIGHT_MARGIN].nPos += lDifference;
+ break;
+ case UpdateType::MoveLeft:
+ {
+ mpIndents[INDENT_FIRST_LINE].nPos += lDifference;
+ mpIndents[INDENT_LEFT_MARGIN].nPos += lDifference;
+ if (!mpTabs.empty())
+ {
+ for(sal_uInt16 i = 0; i < nTabCount+TAB_GAP; ++i)
+ {
+ mpTabs[i].nPos += lDifference;
+ }
+ SetTabs(nTabCount, mpTabs.data() + TAB_GAP);
+ }
+ break;
+ }
+ }
+ SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
+}
+
+void SvxRuler::DragBorders()
+{
+ /* Dragging of Borders (Tables and other columns) */
+ bool bLeftIndentsCorrected = false;
+ bool bRightIndentsCorrected = false;
+ int nIndex;
+
+ if(GetDragType() == RulerType::Border)
+ {
+ DrawLine_Impl(lTabPos, 7, bHorz);
+ nIndex = GetDragAryPos();
+ }
+ else
+ {
+ nIndex = 0;
+ }
+
+ RulerDragSize nDragSize = GetDragSize();
+ tools::Long lDiff = 0;
+
+ // the drag position has to be corrected to be able to prevent borders from passing each other
+ tools::Long lPos = MakePositionSticky(GetCorrectedDragPos(), GetLeftFrameMargin());
+
+ switch(nDragSize)
+ {
+ case RulerDragSize::Move:
+ {
+ if(GetDragType() == RulerType::Border)
+ lDiff = lPos - nDragOffset - mpBorders[nIndex].nPos;
+ else
+ lDiff = GetDragType() == RulerType::Margin1 ? lPos - mxRulerImpl->lLastLMargin : lPos - mxRulerImpl->lLastRMargin;
+
+ if(nDragType & SvxRulerDragFlags::OBJECT_SIZE_LINEAR)
+ {
+ tools::Long nRight = GetMargin2() - glMinFrame; // Right limiters
+ for(int i = mpBorders.size() - 2; i >= nIndex; --i)
+ {
+ tools::Long l = mpBorders[i].nPos;
+ mpBorders[i].nPos += lDiff;
+ mpBorders[i].nPos = std::min(mpBorders[i].nPos, nRight - mpBorders[i].nWidth);
+ nRight = mpBorders[i].nPos - glMinFrame;
+ // RR update the column
+ if(i == GetActRightColumn())
+ {
+ UpdateParaContents_Impl(mpBorders[i].nPos - l, UpdateType::MoveRight);
+ bRightIndentsCorrected = true;
+ }
+ // LAR, EZE update the column
+ else if(i == GetActLeftColumn())
+ {
+ UpdateParaContents_Impl(mpBorders[i].nPos - l, UpdateType::MoveLeft);
+ bLeftIndentsCorrected = true;
+ }
+ }
+ }
+ else if(nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)
+ {
+ int nLimit;
+ tools::Long lLeft;
+ int nStartLimit = mpBorders.size() - 2;
+ switch(GetDragType())
+ {
+ default: ;//prevent warning
+ OSL_FAIL("svx::SvxRuler::DragBorders(), unknown drag type!" );
+ [[fallthrough]];
+ case RulerType::Border:
+ if(mxRulerImpl->bIsTableRows)
+ {
+ mpBorders[nIndex].nPos += lDiff;
+ if(bHorz)
+ {
+ lLeft = mpBorders[nIndex].nPos;
+ mxRulerImpl->nTotalDist -= lDiff;
+ nLimit = nIndex + 1;
+ }
+ else
+ {
+ lLeft = 0;
+ nStartLimit = nIndex - 1;
+ mxRulerImpl->nTotalDist += lDiff;
+ nLimit = 0;
+ }
+ }
+ else
+ {
+ nLimit = nIndex + 1;
+ mpBorders[nIndex].nPos += lDiff;
+ lLeft = mpBorders[nIndex].nPos;
+ mxRulerImpl->nTotalDist -= lDiff;
+ }
+ break;
+ case RulerType::Margin1:
+ nLimit = 0;
+ lLeft = mxRulerImpl->lLastLMargin + lDiff;
+ mxRulerImpl->nTotalDist -= lDiff;
+ break;
+ case RulerType::Margin2:
+ nLimit = 0;
+ lLeft= 0;
+ nStartLimit = mpBorders.size() - 2;
+ mxRulerImpl->nTotalDist += lDiff;
+ break;
+ }
+
+ for(int i = nStartLimit; i >= nLimit; --i)
+ {
+
+ tools::Long l = mpBorders[i].nPos;
+ mpBorders[i].nPos =
+ lLeft +
+ (mxRulerImpl->nTotalDist * mxRulerImpl->pPercBuf[i]) / 1000 +
+ mxRulerImpl->pBlockBuf[i];
+
+ // RR update the column
+ if(!mxRulerImpl->bIsTableRows)
+ {
+ if(i == GetActRightColumn())
+ {
+ UpdateParaContents_Impl(mpBorders[i].nPos - l, UpdateType::MoveRight);
+ bRightIndentsCorrected = true;
+ }
+ // LAR, EZE update the column
+ else if(i == GetActLeftColumn())
+ {
+ UpdateParaContents_Impl(mpBorders[i].nPos - l, UpdateType::MoveLeft);
+ bLeftIndentsCorrected = true;
+ }
+ }
+ }
+ if(mxRulerImpl->bIsTableRows)
+ {
+ //in vertical tables the left borders have to be moved
+ if(bHorz)
+ {
+ for(int i = 0; i < nIndex; ++i)
+ mpBorders[i].nPos += lDiff;
+ AdjustMargin1(lDiff);
+ }
+ else
+ {
+ //otherwise the right borders are moved
+ for(int i = mxColumnItem->Count() - 1; i > nIndex; --i)
+ mpBorders[i].nPos += lDiff;
+ SetMargin2( GetMargin2() + lDiff, RulerMarginStyle::NONE );
+ }
+ }
+ }
+ else if(mxRulerImpl->bIsTableRows)
+ {
+ //moving rows: if a row is resized all following rows
+ //have to be moved by the same amount.
+ //This includes the left border when the table is not limited
+ //to a lower frame border.
+ int nLimit;
+ if(GetDragType()==RulerType::Border)
+ {
+ nLimit = nIndex + 1;
+ mpBorders[nIndex].nPos += lDiff;
+ }
+ else
+ {
+ nLimit=0;
+ }
+ //in vertical tables the left borders have to be moved
+ if(bHorz)
+ {
+ for(int i = 0; i < nIndex; ++i)
+ {
+ mpBorders[i].nPos += lDiff;
+ }
+ AdjustMargin1(lDiff);
+ }
+ else
+ {
+ //otherwise the right borders are moved
+ for(int i = mpBorders.size() - 2; i >= nLimit; --i)
+ {
+ mpBorders[i].nPos += lDiff;
+ }
+ SetMargin2( GetMargin2() + lDiff, RulerMarginStyle::NONE );
+ }
+ }
+ else
+ mpBorders[nIndex].nPos += lDiff;
+ break;
+ }
+ case RulerDragSize::N1:
+ {
+ lDiff = lPos - mpBorders[nIndex].nPos;
+ mpBorders[nIndex].nWidth += mpBorders[nIndex].nPos - lPos;
+ mpBorders[nIndex].nPos = lPos;
+ break;
+ }
+ case RulerDragSize::N2:
+ {
+ const tools::Long nOld = mpBorders[nIndex].nWidth;
+ mpBorders[nIndex].nWidth = lPos - mpBorders[nIndex].nPos;
+ lDiff = mpBorders[nIndex].nWidth - nOld;
+ break;
+ }
+ }
+ if(!bRightIndentsCorrected &&
+ GetActRightColumn() == nIndex &&
+ nDragSize != RulerDragSize::N2 &&
+ !mpIndents.empty() &&
+ !mxRulerImpl->bIsTableRows)
+ {
+ UpdateParaContents_Impl(lDiff, UpdateType::MoveRight);
+ }
+ else if(!bLeftIndentsCorrected &&
+ GetActLeftColumn() == nIndex &&
+ nDragSize != RulerDragSize::N1 &&
+ !mpIndents.empty())
+ {
+ UpdateParaContents_Impl(lDiff, UpdateType::MoveLeft);
+ }
+ SetBorders(mxColumnItem->Count() - 1, mpBorders.data());
+}
+
+void SvxRuler::DragObjectBorder()
+{
+ /* Dragging of object edges */
+ if(RulerDragSize::Move == GetDragSize())
+ {
+ const tools::Long lPosition = MakePositionSticky(GetCorrectedDragPos(), GetLeftFrameMargin());
+
+ const sal_uInt16 nIdx = GetDragAryPos();
+ mpObjectBorders[GetObjectBordersOff(nIdx)].nPos = lPosition;
+ SetBorders(2, mpObjectBorders.data() + GetObjectBordersOff(0));
+ DrawLine_Impl(lTabPos, 7, bHorz);
+
+ }
+}
+
+void SvxRuler::ApplyMargins()
+{
+ /* Applying margins; changed by dragging. */
+ const SfxPoolItem* pItem = nullptr;
+ sal_uInt16 nId = SID_ATTR_LONG_LRSPACE;
+
+ if(bHorz)
+ {
+ const tools::Long lOldNull = lLogicNullOffset;
+ if(mxRulerImpl->lMaxLeftLogic != -1 && nMaxLeft == GetMargin1() + Ruler::GetNullOffset())
+ {
+ lLogicNullOffset = mxRulerImpl->lMaxLeftLogic;
+ mxLRSpaceItem->SetLeft(lLogicNullOffset);
+ }
+ else
+ {
+ lLogicNullOffset = ConvertHPosLogic(GetFrameLeft()) - lAppNullOffset;
+ mxLRSpaceItem->SetLeft(PixelHAdjust(lLogicNullOffset, mxLRSpaceItem->GetLeft()));
+ }
+
+ if(bAppSetNullOffset)
+ {
+ lAppNullOffset += lLogicNullOffset - lOldNull;
+ }
+
+ tools::Long nRight;
+ if(mxRulerImpl->lMaxRightLogic != -1
+ && nMaxRight == GetMargin2() + Ruler::GetNullOffset())
+ {
+ nRight = GetPageWidth() - mxRulerImpl->lMaxRightLogic;
+ }
+ else
+ {
+ nRight = std::max(tools::Long(0),
+ mxPagePosItem->GetWidth() - mxLRSpaceItem->GetLeft() -
+ (ConvertHPosLogic(GetMargin2()) - lAppNullOffset));
+
+ nRight = PixelHAdjust( nRight, mxLRSpaceItem->GetRight());
+ }
+ mxLRSpaceItem->SetRight(nRight);
+
+ pItem = mxLRSpaceItem.get();
+
+#ifdef DEBUGLIN
+ Debug_Impl(pEditWin, *mxLRSpaceItem);
+#endif // DEBUGLIN
+
+ }
+ else
+ {
+ const tools::Long lOldNull = lLogicNullOffset;
+ lLogicNullOffset =
+ ConvertVPosLogic(GetFrameLeft()) -
+ lAppNullOffset;
+ mxULSpaceItem->SetUpper(
+ PixelVAdjust(lLogicNullOffset, mxULSpaceItem->GetUpper()));
+ if(bAppSetNullOffset)
+ {
+ lAppNullOffset += lLogicNullOffset - lOldNull;
+ }
+ mxULSpaceItem->SetLower(
+ PixelVAdjust(
+ std::max(tools::Long(0), mxPagePosItem->GetHeight() -
+ mxULSpaceItem->GetUpper() -
+ (ConvertVPosLogic(GetMargin2()) -
+ lAppNullOffset)), mxULSpaceItem->GetLower()));
+ pItem = mxULSpaceItem.get();
+ nId = SID_ATTR_LONG_ULSPACE;
+
+#ifdef DEBUGLIN
+ Debug_Impl(pEditWin,*mxULSpaceItem);
+#endif // DEBUGLIN
+
+ }
+ pBindings->GetDispatcher()->ExecuteList(nId, SfxCallMode::RECORD, { pItem });
+ if (mxTabStopItem)
+ UpdateTabs();
+}
+
+tools::Long SvxRuler::RoundToCurrentMapMode(tools::Long lValue) const
+{
+ RulerUnitData aUnitData = GetCurrentRulerUnit();
+ double aRoundingFactor = aUnitData.nTickUnit / aUnitData.nTick1;
+
+ tools::Long lNewValue = OutputDevice::LogicToLogic(Size(lValue, 0), pEditWin->GetMapMode(), GetCurrentMapMode()).Width();
+ lNewValue = (rtl::math::round(lNewValue / static_cast<double>(aUnitData.nTickUnit) * aRoundingFactor) / aRoundingFactor) * aUnitData.nTickUnit;
+ return OutputDevice::LogicToLogic(Size(lNewValue, 0), GetCurrentMapMode(), pEditWin->GetMapMode()).Width();
+}
+
+void SvxRuler::ApplyIndents()
+{
+ /* Applying paragraph settings; changed by dragging. */
+
+ tools::Long nLeftFrameMargin = GetLeftFrameMargin();
+
+ bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
+
+ tools::Long nNewTxtLeft;
+ tools::Long nNewFirstLineOffset;
+ tools::Long nNewRight;
+
+ tools::Long nFirstLine = ConvertPosLogic(mpIndents[INDENT_FIRST_LINE].nPos);
+ tools::Long nLeftMargin = ConvertPosLogic(mpIndents[INDENT_LEFT_MARGIN].nPos);
+ tools::Long nRightMargin = ConvertPosLogic(mpIndents[INDENT_RIGHT_MARGIN].nPos);
+
+ if(mxColumnItem && ((bRTL && !IsActLastColumn(true)) || (!bRTL && !IsActFirstColumn(true))))
+ {
+ if(bRTL)
+ {
+ tools::Long nRightColumn = GetActRightColumn(true);
+ tools::Long nRightBorder = ConvertPosLogic(mpBorders[nRightColumn].nPos);
+ nNewTxtLeft = nRightBorder - nLeftMargin - lAppNullOffset;
+ }
+ else
+ {
+ tools::Long nLeftColumn = GetActLeftColumn(true);
+ tools::Long nLeftBorder = ConvertPosLogic(mpBorders[nLeftColumn].nPos + mpBorders[nLeftColumn].nWidth);
+ nNewTxtLeft = nLeftMargin - nLeftBorder - lAppNullOffset;
+ }
+ }
+ else
+ {
+ if(bRTL)
+ {
+ tools::Long nRightBorder = ConvertPosLogic(GetMargin2());
+ nNewTxtLeft = nRightBorder - nLeftMargin - lAppNullOffset;
+ }
+ else
+ {
+ tools::Long nLeftBorder = ConvertPosLogic(GetMargin1());
+ nNewTxtLeft = nLeftBorder + nLeftMargin - nLeftFrameMargin - lAppNullOffset;
+ }
+ }
+
+ if(bRTL)
+ nNewFirstLineOffset = nLeftMargin - nFirstLine - lAppNullOffset;
+ else
+ nNewFirstLineOffset = nFirstLine - nLeftMargin - lAppNullOffset;
+
+ if(mxColumnItem && ((!bRTL && !IsActLastColumn(true)) || (bRTL && !IsActFirstColumn(true))))
+ {
+ if(bRTL)
+ {
+ tools::Long nLeftColumn = GetActLeftColumn(true);
+ tools::Long nLeftBorder = ConvertPosLogic(mpBorders[nLeftColumn].nPos + mpBorders[nLeftColumn].nWidth);
+ nNewRight = nRightMargin - nLeftBorder - lAppNullOffset;
+ }
+ else
+ {
+ tools::Long nRightColumn = GetActRightColumn(true);
+ tools::Long nRightBorder = ConvertPosLogic(mpBorders[nRightColumn].nPos);
+ nNewRight = nRightBorder - nRightMargin - lAppNullOffset;
+ }
+ }
+ else
+ {
+ if(bRTL)
+ {
+ tools::Long nLeftBorder = ConvertPosLogic(GetMargin1());
+ nNewRight = nLeftBorder + nRightMargin - nLeftFrameMargin - lAppNullOffset;
+ }
+ else
+ {
+ tools::Long nRightBorder = ConvertPosLogic(GetMargin2());
+ nNewRight = nRightBorder - nRightMargin - lAppNullOffset;
+ }
+ }
+
+ if (mbSnapping)
+ {
+ nNewTxtLeft = RoundToCurrentMapMode(nNewTxtLeft);
+ nNewFirstLineOffset = RoundToCurrentMapMode(nNewFirstLineOffset);
+ nNewRight = RoundToCurrentMapMode(nNewRight);
+ }
+
+ mxParaItem->SetTextFirstLineOffset(sal::static_int_cast<short>(nNewFirstLineOffset));
+ mxParaItem->SetTextLeft(nNewTxtLeft);
+ mxParaItem->SetRight(nNewRight);
+
+ sal_uInt16 nParagraphId = bHorz ? SID_ATTR_PARA_LRSPACE : SID_ATTR_PARA_LRSPACE_VERTICAL;
+ pBindings->GetDispatcher()->ExecuteList(nParagraphId, SfxCallMode::RECORD,
+ { mxParaItem.get() });
+ UpdateTabs();
+}
+
+void SvxRuler::ApplyTabs()
+{
+ /* Apply tab settings, changed by dragging. */
+ bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
+ const sal_uInt16 nCoreIdx = GetDragAryPos();
+ if(IsDragDelete())
+ {
+ mxTabStopItem->Remove(nCoreIdx);
+ }
+ else if(SvxRulerDragFlags::OBJECT_SIZE_LINEAR & nDragType ||
+ SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL & nDragType)
+ {
+ SvxTabStopItem *pItem = new SvxTabStopItem(mxTabStopItem->Which());
+ //remove default tab stops
+ for ( sal_uInt16 i = 0; i < pItem->Count(); )
+ {
+ if ( SvxTabAdjust::Default == (*pItem)[i].GetAdjustment() )
+ {
+ pItem->Remove(i);
+ continue;
+ }
+ ++i;
+ }
+
+ sal_uInt16 j;
+ for(j = 0; j < nCoreIdx; ++j)
+ {
+ pItem->Insert(mxTabStopItem->At(j));
+ }
+ for(; j < mxTabStopItem->Count(); ++j)
+ {
+ SvxTabStop aTabStop = mxTabStopItem->At(j);
+ aTabStop.GetTabPos() = PixelHAdjust(
+ ConvertHPosLogic(
+ mpTabs[j + TAB_GAP].nPos - GetLeftIndent()) - lAppNullOffset,
+ aTabStop.GetTabPos());
+ pItem->Insert(aTabStop);
+ }
+ mxTabStopItem.reset(pItem);
+ }
+ else if( mxTabStopItem->Count() == 0 )
+ return;
+ else
+ {
+ SvxTabStop aTabStop = mxTabStopItem->At(nCoreIdx);
+ if( mxRulerImpl->lMaxRightLogic != -1 &&
+ mpTabs[nCoreIdx + TAB_GAP].nPos + Ruler::GetNullOffset() == nMaxRight )
+ {
+ // Set tab pos exactly at the right indent
+ tools::Long nTmpLeftIndentLogic
+ = lAppNullOffset + (bRTL ? GetRightFrameMargin() : GetLeftFrameMargin());
+ if (mxRulerImpl->bIsTabsRelativeToIndent && mxParaItem)
+ {
+ nTmpLeftIndentLogic += bRTL ? mxParaItem->GetRight() : mxParaItem->GetTextLeft();
+ }
+ aTabStop.GetTabPos()
+ = mxRulerImpl->lMaxRightLogic - lLogicNullOffset - nTmpLeftIndentLogic;
+ }
+ else
+ {
+ if(bRTL)
+ {
+ //#i24363# tab stops relative to indent
+ const tools::Long nTmpLeftIndent = mxRulerImpl->bIsTabsRelativeToIndent ?
+ GetLeftIndent() :
+ ConvertHPosPixel( GetRightFrameMargin() + lAppNullOffset );
+
+ tools::Long nNewPosition = ConvertHPosLogic(nTmpLeftIndent - mpTabs[nCoreIdx + TAB_GAP].nPos);
+ aTabStop.GetTabPos() = PixelHAdjust(nNewPosition - lAppNullOffset, aTabStop.GetTabPos());
+ }
+ else
+ {
+ //#i24363# tab stops relative to indent
+ const tools::Long nTmpLeftIndent = mxRulerImpl->bIsTabsRelativeToIndent ?
+ GetLeftIndent() :
+ ConvertHPosPixel( GetLeftFrameMargin() + lAppNullOffset );
+
+ tools::Long nNewPosition = ConvertHPosLogic(mpTabs[nCoreIdx + TAB_GAP].nPos - nTmpLeftIndent);
+ aTabStop.GetTabPos() = PixelHAdjust(nNewPosition - lAppNullOffset, aTabStop.GetTabPos());
+ }
+ }
+ mxTabStopItem->Remove(nCoreIdx);
+ mxTabStopItem->Insert(aTabStop);
+ }
+ sal_uInt16 nTabStopId = bHorz ? SID_ATTR_TABSTOP : SID_ATTR_TABSTOP_VERTICAL;
+ pBindings->GetDispatcher()->ExecuteList(nTabStopId, SfxCallMode::RECORD,
+ { mxTabStopItem.get() });
+ UpdateTabs();
+}
+
+void SvxRuler::ApplyBorders()
+{
+ /* Applying (table) column settings; changed by dragging. */
+ if(mxColumnItem->IsTable())
+ {
+ tools::Long lValue = GetFrameLeft();
+ if(lValue != mxRulerImpl->nColLeftPix)
+ {
+ tools::Long nLeft = PixelHAdjust(
+ ConvertHPosLogic(lValue) -
+ lAppNullOffset,
+ mxColumnItem->GetLeft());
+ mxColumnItem->SetLeft(nLeft);
+ }
+
+ lValue = GetMargin2();
+
+ if(lValue != mxRulerImpl->nColRightPix)
+ {
+ tools::Long nWidthOrHeight = bHorz ? mxPagePosItem->GetWidth() : mxPagePosItem->GetHeight();
+ tools::Long nRight = PixelHAdjust(
+ nWidthOrHeight -
+ mxColumnItem->GetLeft() -
+ ConvertHPosLogic(lValue) -
+ lAppNullOffset,
+ mxColumnItem->GetRight() );
+ mxColumnItem->SetRight(nRight);
+ }
+ }
+
+ for(sal_uInt16 i = 0; i < mxColumnItem->Count() - 1; ++i)
+ {
+ tools::Long& nEnd = mxColumnItem->At(i).nEnd;
+ nEnd = PixelHAdjust(
+ ConvertPosLogic(mpBorders[i].nPos),
+ mxColumnItem->At(i).nEnd);
+ tools::Long& nStart = mxColumnItem->At(i + 1).nStart;
+ nStart = PixelHAdjust(
+ ConvertSizeLogic(mpBorders[i].nPos +
+ mpBorders[i].nWidth) -
+ lAppNullOffset,
+ mxColumnItem->At(i + 1).nStart);
+ // It may be that, due to the PixelHAdjust readjustment to old values,
+ // the width becomes < 0. This we readjust.
+ if( nEnd > nStart )
+ nStart = nEnd;
+ }
+
+#ifdef DEBUGLIN
+ Debug_Impl(pEditWin,*mxColumnItem);
+#endif // DEBUGLIN
+
+ SfxBoolItem aFlag(SID_RULER_ACT_LINE_ONLY,
+ bool(nDragType & SvxRulerDragFlags::OBJECT_ACTLINE_ONLY));
+
+ sal_uInt16 nColId = mxRulerImpl->bIsTableRows ? (bHorz ? SID_RULER_ROWS : SID_RULER_ROWS_VERTICAL) :
+ (bHorz ? SID_RULER_BORDERS : SID_RULER_BORDERS_VERTICAL);
+
+ pBindings->GetDispatcher()->ExecuteList(nColId, SfxCallMode::RECORD,
+ { mxColumnItem.get(), &aFlag });
+}
+
+void SvxRuler::ApplyObject()
+{
+ /* Applying object settings, changed by dragging. */
+
+ // to the page margin
+ tools::Long nMargin = mxLRSpaceItem ? mxLRSpaceItem->GetLeft() : 0;
+ tools::Long nStartX = PixelAdjust(
+ ConvertPosLogic(mpObjectBorders[0].nPos) +
+ nMargin -
+ lAppNullOffset,
+ mxObjectItem->GetStartX());
+ mxObjectItem->SetStartX(nStartX);
+
+ tools::Long nEndX = PixelAdjust(
+ ConvertPosLogic(mpObjectBorders[1].nPos) +
+ nMargin -
+ lAppNullOffset,
+ mxObjectItem->GetEndX());
+ mxObjectItem->SetEndX(nEndX);
+
+ nMargin = mxULSpaceItem ? mxULSpaceItem->GetUpper() : 0;
+ tools::Long nStartY = PixelAdjust(
+ ConvertPosLogic(mpObjectBorders[2].nPos) +
+ nMargin -
+ lAppNullOffset,
+ mxObjectItem->GetStartY());
+ mxObjectItem->SetStartY(nStartY);
+
+ tools::Long nEndY = PixelAdjust(
+ ConvertPosLogic(mpObjectBorders[3].nPos) +
+ nMargin -
+ lAppNullOffset,
+ mxObjectItem->GetEndY());
+ mxObjectItem->SetEndY(nEndY);
+
+ pBindings->GetDispatcher()->ExecuteList(SID_RULER_OBJECT,
+ SfxCallMode::RECORD, { mxObjectItem.get() });
+}
+
+void SvxRuler::PrepareProportional_Impl(RulerType eType)
+{
+ /*
+ Preparation proportional dragging, and it is calculated based on the
+ proportional share of the total width in parts per thousand.
+ */
+ mxRulerImpl->nTotalDist = GetMargin2();
+ switch(eType)
+ {
+ case RulerType::Margin2:
+ case RulerType::Margin1:
+ case RulerType::Border:
+ {
+ DBG_ASSERT(mxColumnItem, "no ColumnItem");
+
+ mxRulerImpl->SetPercSize(mxColumnItem->Count());
+
+ tools::Long lPos;
+ tools::Long lWidth=0;
+ sal_uInt16 nStart;
+ sal_uInt16 nIdx=GetDragAryPos();
+ tools::Long lActWidth=0;
+ tools::Long lActBorderSum;
+ tools::Long lOrigLPos;
+
+ if(eType != RulerType::Border)
+ {
+ lOrigLPos = GetMargin1();
+ nStart = 0;
+ lActBorderSum = 0;
+ }
+ else
+ {
+ if(mxRulerImpl->bIsTableRows &&!bHorz)
+ {
+ lOrigLPos = GetMargin1();
+ nStart = 0;
+ }
+ else
+ {
+ lOrigLPos = mpBorders[nIdx].nPos + mpBorders[nIdx].nWidth;
+ nStart = 1;
+ }
+ lActBorderSum = mpBorders[nIdx].nWidth;
+ }
+
+ //in horizontal mode the percentage value has to be
+ //calculated on a "current change" position base
+ //because the height of the table changes while dragging
+ if(mxRulerImpl->bIsTableRows && RulerType::Border == eType)
+ {
+ sal_uInt16 nStartBorder;
+ sal_uInt16 nEndBorder;
+ if(bHorz)
+ {
+ nStartBorder = nIdx + 1;
+ nEndBorder = mxColumnItem->Count() - 1;
+ }
+ else
+ {
+ nStartBorder = 0;
+ nEndBorder = nIdx;
+ }
+
+ lWidth = mpBorders[nIdx].nPos;
+ if(bHorz)
+ lWidth = GetMargin2() - lWidth;
+ mxRulerImpl->nTotalDist = lWidth;
+ lPos = mpBorders[nIdx].nPos;
+
+ for(sal_uInt16 i = nStartBorder; i < nEndBorder; ++i)
+ {
+ if(bHorz)
+ {
+ lActWidth += mpBorders[i].nPos - lPos;
+ lPos = mpBorders[i].nPos + mpBorders[i].nWidth;
+ }
+ else
+ lActWidth = mpBorders[i].nPos;
+ mxRulerImpl->pPercBuf[i] = static_cast<sal_uInt16>((lActWidth * 1000)
+ / mxRulerImpl->nTotalDist);
+ mxRulerImpl->pBlockBuf[i] = static_cast<sal_uInt16>(lActBorderSum);
+ lActBorderSum += mpBorders[i].nWidth;
+ }
+ }
+ else
+ {
+ lPos = lOrigLPos;
+ for(sal_uInt16 ii = nStart; ii < mxColumnItem->Count() - 1; ++ii)
+ {
+ lWidth += mpBorders[ii].nPos - lPos;
+ lPos = mpBorders[ii].nPos + mpBorders[ii].nWidth;
+ }
+
+ lWidth += GetMargin2() - lPos;
+ mxRulerImpl->nTotalDist = lWidth;
+ lPos = lOrigLPos;
+
+ for(sal_uInt16 i = nStart; i < mxColumnItem->Count() - 1; ++i)
+ {
+ lActWidth += mpBorders[i].nPos - lPos;
+ lPos = mpBorders[i].nPos + mpBorders[i].nWidth;
+ mxRulerImpl->pPercBuf[i] = static_cast<sal_uInt16>((lActWidth * 1000)
+ / mxRulerImpl->nTotalDist);
+ mxRulerImpl->pBlockBuf[i] = static_cast<sal_uInt16>(lActBorderSum);
+ lActBorderSum += mpBorders[i].nWidth;
+ }
+ }
+ }
+ break;
+ case RulerType::Tab:
+ {
+ const sal_uInt16 nIdx = GetDragAryPos()+TAB_GAP;
+ mxRulerImpl->nTotalDist -= mpTabs[nIdx].nPos;
+ mxRulerImpl->SetPercSize(nTabCount);
+ for(sal_uInt16 n=0;n<=nIdx;mxRulerImpl->pPercBuf[n++]=0) ;
+ for(sal_uInt16 i = nIdx+1; i < nTabCount; ++i)
+ {
+ const tools::Long nDelta = mpTabs[i].nPos - mpTabs[nIdx].nPos;
+ mxRulerImpl->pPercBuf[i] = static_cast<sal_uInt16>((nDelta * 1000) / mxRulerImpl->nTotalDist);
+ }
+ break;
+ }
+ default: break;
+ }
+}
+
+void SvxRuler::EvalModifier()
+{
+ /*
+ Eval Drag Modifier
+ Shift: move linear
+ Control: move proportional
+ Shift + Control: Table: only current line
+ Alt: disable snapping
+ Alt + Shift: coarse snapping
+ */
+
+ sal_uInt16 nModifier = GetDragModifier();
+ if(mxRulerImpl->bIsTableRows)
+ {
+ //rows can only be moved in one way, additionally current column is possible
+ if(nModifier == KEY_SHIFT)
+ nModifier = 0;
+ }
+
+ switch(nModifier)
+ {
+ case KEY_SHIFT:
+ nDragType = SvxRulerDragFlags::OBJECT_SIZE_LINEAR;
+ break;
+ case KEY_MOD2 | KEY_SHIFT:
+ mbCoarseSnapping = true;
+ break;
+ case KEY_MOD2:
+ mbSnapping = false;
+ break;
+ case KEY_MOD1:
+ {
+ const RulerType eType = GetDragType();
+ nDragType = SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL;
+ if( RulerType::Tab == eType ||
+ ( ( RulerType::Border == eType ||
+ RulerType::Margin1 == eType ||
+ RulerType::Margin2 == eType ) &&
+ mxColumnItem ) )
+ {
+ PrepareProportional_Impl(eType);
+ }
+ }
+ break;
+ case KEY_MOD1 | KEY_SHIFT:
+ if( GetDragType() != RulerType::Margin1 &&
+ GetDragType() != RulerType::Margin2 )
+ {
+ nDragType = SvxRulerDragFlags::OBJECT_ACTLINE_ONLY;
+ }
+ break;
+ }
+}
+
+void SvxRuler::Click()
+{
+ /* Override handler SV; sets Tab per dispatcher call */
+ Ruler::Click();
+ if( bActive )
+ {
+ pBindings->Update( SID_RULER_LR_MIN_MAX );
+ pBindings->Update( SID_ATTR_LONG_ULSPACE );
+ pBindings->Update( SID_ATTR_LONG_LRSPACE );
+ pBindings->Update( SID_RULER_PAGE_POS );
+ pBindings->Update( bHorz ? SID_ATTR_TABSTOP : SID_ATTR_TABSTOP_VERTICAL);
+ pBindings->Update( bHorz ? SID_ATTR_PARA_LRSPACE : SID_ATTR_PARA_LRSPACE_VERTICAL);
+ pBindings->Update( bHorz ? SID_RULER_BORDERS : SID_RULER_BORDERS_VERTICAL);
+ pBindings->Update( bHorz ? SID_RULER_ROWS : SID_RULER_ROWS_VERTICAL);
+ pBindings->Update( SID_RULER_OBJECT );
+ pBindings->Update( SID_RULER_PROTECT );
+ pBindings->Update( SID_ATTR_PARA_LRSPACE_VERTICAL );
+ }
+ bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
+ if(!(mxTabStopItem &&
+ (nFlags & SvxRulerSupportFlags::TABS) == SvxRulerSupportFlags::TABS))
+ return;
+
+ bool bContentProtected = mxRulerImpl->aProtectItem->IsContentProtected();
+ if( bContentProtected ) return;
+ const tools::Long lPos = GetClickPos();
+ if(!((bRTL && lPos < std::min(GetFirstLineIndent(), GetLeftIndent()) && lPos > GetRightIndent()) ||
+ (!bRTL && lPos > std::min(GetFirstLineIndent(), GetLeftIndent()) && lPos < GetRightIndent())))
+ return;
+
+ //convert position in left-to-right text
+ tools::Long nTabPos;
+//#i24363# tab stops relative to indent
+ if(bRTL)
+ nTabPos = ( mxRulerImpl->bIsTabsRelativeToIndent ?
+ GetLeftIndent() :
+ ConvertHPosPixel( GetRightFrameMargin() + lAppNullOffset ) ) -
+ lPos;
+ else
+ nTabPos = lPos -
+ ( mxRulerImpl->bIsTabsRelativeToIndent ?
+ GetLeftIndent() :
+ ConvertHPosPixel( GetLeftFrameMargin() + lAppNullOffset ));
+
+ SvxTabStop aTabStop(ConvertHPosLogic(nTabPos),
+ ToAttrTab_Impl(nDefTabType));
+ mxTabStopItem->Insert(aTabStop);
+ UpdateTabs();
+}
+
+void SvxRuler::CalcMinMax()
+{
+ /*
+ Calculates the limits for dragging; which are in pixels relative to the
+ page edge
+ */
+ bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
+ const tools::Long lNullPix = ConvertPosPixel(lLogicNullOffset);
+ mxRulerImpl->lMaxLeftLogic=mxRulerImpl->lMaxRightLogic=-1;
+ switch(GetDragType())
+ {
+ case RulerType::Margin1:
+ { // left edge of the surrounding Frame
+ // DragPos - NOf between left - right
+ mxRulerImpl->lMaxLeftLogic = GetLeftMin();
+ nMaxLeft=ConvertSizePixel(mxRulerImpl->lMaxLeftLogic);
+
+ if (!mxColumnItem || mxColumnItem->Count() == 1)
+ {
+ if(bRTL)
+ {
+ nMaxRight = lNullPix - GetRightIndent() +
+ std::max(GetFirstLineIndent(), GetLeftIndent()) -
+ glMinFrame;
+ }
+ else
+ {
+ nMaxRight = lNullPix + GetRightIndent() -
+ std::max(GetFirstLineIndent(), GetLeftIndent()) -
+ glMinFrame;
+ }
+ }
+ else if(mxRulerImpl->bIsTableRows)
+ {
+ //top border is not moveable when table rows are displayed
+ // protection of content means the margin is not moveable
+ if(bHorz && !mxRulerImpl->aProtectItem->IsContentProtected())
+ {
+ nMaxLeft = mpBorders[0].nMinPos + lNullPix;
+ if(nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)
+ nMaxRight = GetRightIndent() + lNullPix -
+ (mxColumnItem->Count() - 1 ) * glMinFrame;
+ else
+ nMaxRight = mpBorders[0].nPos - glMinFrame + lNullPix;
+ }
+ else
+ nMaxLeft = nMaxRight = lNullPix;
+ }
+ else
+ {
+ if (nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)
+ {
+ nMaxRight=lNullPix+CalcPropMaxRight();
+ }
+ else if (nDragType & SvxRulerDragFlags::OBJECT_SIZE_LINEAR)
+ {
+ nMaxRight = ConvertPosPixel(
+ GetPageWidth() - (
+ (mxColumnItem->IsTable() && mxLRSpaceItem)
+ ? mxLRSpaceItem->GetRight() : 0))
+ - GetMargin2() + GetMargin1();
+ }
+ else
+ {
+ nMaxRight = lNullPix - glMinFrame;
+ if (mxColumnItem->IsFirstAct())
+ {
+ if(bRTL)
+ {
+ nMaxRight += std::min(
+ mpBorders[0].nPos,
+ std::max(GetFirstLineIndent(), GetLeftIndent()) - GetRightIndent());
+ }
+ else
+ {
+ nMaxRight += std::min(
+ mpBorders[0].nPos, GetRightIndent() -
+ std::max(GetFirstLineIndent(), GetLeftIndent()));
+ }
+ }
+ else if ( mxColumnItem->Count() > 1 )
+ {
+ nMaxRight += mpBorders[0].nPos;
+ }
+ else
+ {
+ nMaxRight += GetRightIndent() - std::max(GetFirstLineIndent(), GetLeftIndent());
+ }
+ // Do not drag the left table edge over the edge of the page
+ if(mxLRSpaceItem && mxColumnItem->IsTable())
+ {
+ tools::Long nTmp=ConvertSizePixel(mxLRSpaceItem->GetLeft());
+ if(nTmp>nMaxLeft)
+ nMaxLeft=nTmp;
+ }
+ }
+ }
+ break;
+ }
+ case RulerType::Margin2:
+ { // right edge of the surrounding Frame
+ mxRulerImpl->lMaxRightLogic
+ = mxMinMaxItem ? GetPageWidth() - GetRightMax() : GetPageWidth();
+ nMaxRight = ConvertSizePixel(mxRulerImpl->lMaxRightLogic);
+
+ if (!mxColumnItem)
+ {
+ if(bRTL)
+ {
+ nMaxLeft = GetMargin2() + GetRightIndent() -
+ std::max(GetFirstLineIndent(),GetLeftIndent()) - GetMargin1()+
+ glMinFrame + lNullPix;
+ }
+ else
+ {
+ nMaxLeft = GetMargin2() - GetRightIndent() +
+ std::max(GetFirstLineIndent(),GetLeftIndent()) - GetMargin1()+
+ glMinFrame + lNullPix;
+ }
+ }
+ else if(mxRulerImpl->bIsTableRows)
+ {
+ // get the bottom move range from the last border position - only available for rows!
+ // protection of content means the margin is not moveable
+ if(bHorz || mxRulerImpl->aProtectItem->IsContentProtected())
+ {
+ nMaxLeft = nMaxRight = mpBorders[mxColumnItem->Count() - 1].nMaxPos + lNullPix;
+ }
+ else
+ {
+ if(nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)
+ {
+ nMaxLeft = (mxColumnItem->Count()) * glMinFrame + lNullPix;
+ }
+ else
+ {
+ if(mxColumnItem->Count() > 1)
+ nMaxLeft = mpBorders[mxColumnItem->Count() - 2].nPos + glMinFrame + lNullPix;
+ else
+ nMaxLeft = glMinFrame + lNullPix;
+ }
+ if(mxColumnItem->Count() > 1)
+ nMaxRight = mpBorders[mxColumnItem->Count() - 2].nMaxPos + lNullPix;
+ else
+ nMaxRight -= GetRightIndent() - lNullPix;
+ }
+ }
+ else
+ {
+ nMaxLeft = glMinFrame + lNullPix;
+ if(IsActLastColumn() || mxColumnItem->Count() < 2 ) //If last active column
+ {
+ if(bRTL)
+ {
+ nMaxLeft = glMinFrame + lNullPix + GetMargin2() +
+ GetRightIndent() - std::max(GetFirstLineIndent(),
+ GetLeftIndent());
+ }
+ else
+ {
+ nMaxLeft = glMinFrame + lNullPix + GetMargin2() -
+ GetRightIndent() + std::max(GetFirstLineIndent(),
+ GetLeftIndent());
+ }
+ }
+ if( mxColumnItem->Count() >= 2 )
+ {
+ tools::Long nNewMaxLeft =
+ glMinFrame + lNullPix +
+ mpBorders[mxColumnItem->Count() - 2].nPos +
+ mpBorders[mxColumnItem->Count() - 2].nWidth;
+ nMaxLeft = std::max(nMaxLeft, nNewMaxLeft);
+ }
+
+ }
+ break;
+ }
+ case RulerType::Border:
+ { // Table, column (Modifier)
+ const sal_uInt16 nIdx = GetDragAryPos();
+ switch(GetDragSize())
+ {
+ case RulerDragSize::N1 :
+ {
+ nMaxRight = mpBorders[nIdx].nPos +
+ mpBorders[nIdx].nWidth + lNullPix;
+
+ if(0 == nIdx)
+ nMaxLeft = lNullPix;
+ else
+ nMaxLeft = mpBorders[nIdx - 1].nPos + mpBorders[nIdx - 1].nWidth + lNullPix;
+ if (mxColumnItem && nIdx == mxColumnItem->GetActColumn())
+ {
+ if(bRTL)
+ {
+ nMaxLeft += mpBorders[nIdx].nPos +
+ GetRightIndent() - std::max(GetFirstLineIndent(),
+ GetLeftIndent());
+ }
+ else
+ {
+ nMaxLeft += mpBorders[nIdx].nPos -
+ GetRightIndent() + std::max(GetFirstLineIndent(),
+ GetLeftIndent());
+ }
+ if(0 != nIdx)
+ nMaxLeft -= mpBorders[nIdx-1].nPos +
+ mpBorders[nIdx-1].nWidth;
+ }
+ nMaxLeft += glMinFrame;
+ nMaxLeft += nDragOffset;
+ break;
+ }
+ case RulerDragSize::Move:
+ {
+ if (mxColumnItem)
+ {
+ //nIdx contains the position of the currently moved item
+ //next visible separator on the left
+ sal_uInt16 nLeftCol=GetActLeftColumn(false, nIdx);
+ //next visible separator on the right
+ sal_uInt16 nRightCol=GetActRightColumn(false, nIdx);
+ //next separator on the left - regardless if visible or not
+ sal_uInt16 nActLeftCol=GetActLeftColumn();
+ //next separator on the right - regardless if visible or not
+ sal_uInt16 nActRightCol=GetActRightColumn();
+ if(mxColumnItem->IsTable())
+ {
+ if(nDragType & SvxRulerDragFlags::OBJECT_ACTLINE_ONLY)
+ {
+ //the current row/column should be modified only
+ //then the next/previous visible border position
+ //marks the min/max positions
+ nMaxLeft = nLeftCol == USHRT_MAX ?
+ 0 :
+ mpBorders[nLeftCol].nPos;
+ //rows can always be increased without a limit
+ if(mxRulerImpl->bIsTableRows)
+ nMaxRight = mpBorders[nIdx].nMaxPos;
+ else
+ nMaxRight = nRightCol == USHRT_MAX ?
+ GetMargin2():
+ mpBorders[nRightCol].nPos;
+ nMaxLeft += lNullPix;
+ nMaxRight += lNullPix;
+ }
+ else
+ {
+ if(SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL & nDragType && !bHorz && mxRulerImpl->bIsTableRows)
+ nMaxLeft = (nIdx + 1) * glMinFrame + lNullPix;
+ else
+ nMaxLeft = mpBorders[nIdx].nMinPos + lNullPix;
+ if((SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL & nDragType) ||
+ (SvxRulerDragFlags::OBJECT_SIZE_LINEAR & nDragType) )
+ {
+ if(mxRulerImpl->bIsTableRows)
+ {
+ if(bHorz)
+ nMaxRight = GetRightIndent() + lNullPix -
+ (mxColumnItem->Count() - nIdx - 1) * glMinFrame;
+ else
+ nMaxRight = mpBorders[nIdx].nMaxPos + lNullPix;
+ }
+ else
+ nMaxRight=lNullPix+CalcPropMaxRight(nIdx);
+ }
+ else
+ nMaxRight = mpBorders[nIdx].nMaxPos + lNullPix;
+ }
+ nMaxLeft += glMinFrame;
+ nMaxRight -= glMinFrame;
+
+ }
+ else
+ {
+ if(nLeftCol==USHRT_MAX)
+ nMaxLeft=lNullPix;
+ else
+ nMaxLeft = mpBorders[nLeftCol].nPos +
+ mpBorders[nLeftCol].nWidth + lNullPix;
+
+ if(nActRightCol == nIdx)
+ {
+ if(bRTL)
+ {
+ nMaxLeft += mpBorders[nIdx].nPos +
+ GetRightIndent() - std::max(GetFirstLineIndent(),
+ GetLeftIndent());
+ if(nActLeftCol!=USHRT_MAX)
+ nMaxLeft -= mpBorders[nActLeftCol].nPos +
+ mpBorders[nActLeftCol].nWidth;
+ }
+ else
+ {
+ nMaxLeft += mpBorders[nIdx].nPos -
+ GetRightIndent() + std::max(GetFirstLineIndent(),
+ GetLeftIndent());
+ if(nActLeftCol!=USHRT_MAX)
+ nMaxLeft -= mpBorders[nActLeftCol].nPos +
+ mpBorders[nActLeftCol].nWidth;
+ }
+ }
+ nMaxLeft += glMinFrame;
+ nMaxLeft += nDragOffset;
+
+ // nMaxRight
+ // linear / proportional move
+ if((SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL & nDragType) ||
+ (SvxRulerDragFlags::OBJECT_SIZE_LINEAR & nDragType) )
+ {
+ nMaxRight=lNullPix+CalcPropMaxRight(nIdx);
+ }
+ else if(SvxRulerDragFlags::OBJECT_SIZE_LINEAR & nDragType)
+ {
+ nMaxRight = lNullPix + GetMargin2() - GetMargin1() +
+ (mpBorders.size() - nIdx - 1) * glMinFrame;
+ }
+ else
+ {
+ if(nRightCol==USHRT_MAX)
+ { // last column
+ nMaxRight = GetMargin2() + lNullPix;
+ if(IsActLastColumn())
+ {
+ if(bRTL)
+ {
+ nMaxRight -=
+ GetMargin2() + GetRightIndent() -
+ std::max(GetFirstLineIndent(),
+ GetLeftIndent());
+ }
+ else
+ {
+ nMaxRight -=
+ GetMargin2() - GetRightIndent() +
+ std::max(GetFirstLineIndent(),
+ GetLeftIndent());
+ }
+ nMaxRight += mpBorders[nIdx].nPos +
+ mpBorders[nIdx].nWidth;
+ }
+ }
+ else
+ {
+ nMaxRight = lNullPix + mpBorders[nRightCol].nPos;
+ sal_uInt16 nNotHiddenRightCol =
+ GetActRightColumn(true, nIdx);
+
+ if( nActLeftCol == nIdx )
+ {
+ tools::Long nBorder = nNotHiddenRightCol ==
+ USHRT_MAX ?
+ GetMargin2() :
+ mpBorders[nNotHiddenRightCol].nPos;
+ if(bRTL)
+ {
+ nMaxRight -= nBorder + GetRightIndent() -
+ std::max(GetFirstLineIndent(),
+ GetLeftIndent());
+ }
+ else
+ {
+ nMaxRight -= nBorder - GetRightIndent() +
+ std::max(GetFirstLineIndent(),
+ GetLeftIndent());
+ }
+ nMaxRight += mpBorders[nIdx].nPos +
+ mpBorders[nIdx].nWidth;
+ }
+ }
+ nMaxRight -= glMinFrame;
+ nMaxRight -= mpBorders[nIdx].nWidth;
+ }
+ }
+ }
+ // ObjectItem
+ else
+ {
+ nMaxLeft = LONG_MIN;
+ nMaxRight = LONG_MAX;
+ }
+ break;
+ }
+ case RulerDragSize::N2:
+ if (mxColumnItem)
+ {
+ nMaxLeft = lNullPix + mpBorders[nIdx].nPos;
+ if(nIdx == mxColumnItem->Count()-2) { // last column
+ nMaxRight = GetMargin2() + lNullPix;
+ if(mxColumnItem->IsLastAct()) {
+ nMaxRight -=
+ GetMargin2() - GetRightIndent() +
+ std::max(GetFirstLineIndent(),
+ GetLeftIndent());
+ nMaxRight += mpBorders[nIdx].nPos +
+ mpBorders[nIdx].nWidth;
+ }
+ }
+ else {
+ nMaxRight = lNullPix + mpBorders[nIdx+1].nPos;
+ if(mxColumnItem->GetActColumn()-1 == nIdx) {
+ nMaxRight -= mpBorders[nIdx+1].nPos - GetRightIndent() +
+ std::max(GetFirstLineIndent(),
+ GetLeftIndent());
+ nMaxRight += mpBorders[nIdx].nPos +
+ mpBorders[nIdx].nWidth;
+ }
+ }
+ nMaxRight -= glMinFrame;
+ nMaxRight -= mpBorders[nIdx].nWidth;
+ break;
+ }
+ }
+ nMaxRight += nDragOffset;
+ break;
+ }
+ case RulerType::Indent:
+ {
+ const sal_uInt16 nIdx = GetDragAryPos();
+ switch(nIdx) {
+ case INDENT_FIRST_LINE - INDENT_GAP:
+ case INDENT_LEFT_MARGIN - INDENT_GAP:
+ {
+ if(bRTL)
+ {
+ nMaxLeft = lNullPix + GetRightIndent();
+
+ if(mxColumnItem && !mxColumnItem->IsFirstAct())
+ nMaxLeft += mpBorders[mxColumnItem->GetActColumn()-1].nPos +
+ mpBorders[mxColumnItem->GetActColumn()-1].nWidth;
+ nMaxRight = lNullPix + GetMargin2();
+
+ // Dragging along
+ if((INDENT_FIRST_LINE - INDENT_GAP) != nIdx &&
+ !(nDragType & SvxRulerDragFlags::OBJECT_LEFT_INDENT_ONLY))
+ {
+ if(GetLeftIndent() > GetFirstLineIndent())
+ nMaxLeft += GetLeftIndent() - GetFirstLineIndent();
+ else
+ nMaxRight -= GetFirstLineIndent() - GetLeftIndent();
+ }
+ }
+ else
+ {
+ nMaxLeft = lNullPix;
+
+ if(mxColumnItem && !mxColumnItem->IsFirstAct())
+ nMaxLeft += mpBorders[mxColumnItem->GetActColumn()-1].nPos +
+ mpBorders[mxColumnItem->GetActColumn()-1].nWidth;
+ nMaxRight = lNullPix + GetRightIndent() - glMinFrame;
+
+ // Dragging along
+ if((INDENT_FIRST_LINE - INDENT_GAP) != nIdx &&
+ !(nDragType & SvxRulerDragFlags::OBJECT_LEFT_INDENT_ONLY))
+ {
+ if(GetLeftIndent() > GetFirstLineIndent())
+ nMaxLeft += GetLeftIndent() - GetFirstLineIndent();
+ else
+ nMaxRight -= GetFirstLineIndent() - GetLeftIndent();
+ }
+ }
+ }
+ break;
+ case INDENT_RIGHT_MARGIN - INDENT_GAP:
+ {
+ if(bRTL)
+ {
+ nMaxLeft = lNullPix;
+ nMaxRight = lNullPix + std::min(GetFirstLineIndent(), GetLeftIndent()) - glMinFrame;
+ if (mxColumnItem)
+ {
+ sal_uInt16 nRightCol=GetActRightColumn( true );
+ if(!IsActLastColumn( true ))
+ nMaxRight += mpBorders[nRightCol].nPos;
+ else
+ nMaxRight += GetMargin2();
+ }
+ else
+ {
+ nMaxLeft += GetMargin1();
+ }
+ nMaxLeft += glMinFrame;
+ }
+ else
+ {
+ nMaxLeft = lNullPix +
+ std::max(GetFirstLineIndent(), GetLeftIndent());
+ nMaxRight = lNullPix;
+ if (mxColumnItem)
+ {
+ sal_uInt16 nRightCol=GetActRightColumn( true );
+ if(!IsActLastColumn( true ))
+ nMaxRight += mpBorders[nRightCol].nPos;
+ else
+ nMaxRight += GetMargin2();
+ }
+ else
+ nMaxRight += GetMargin2();
+ nMaxLeft += glMinFrame;
+ }
+ }
+ break;
+ }
+ break;
+ }
+ case RulerType::Tab: // Tabs (Modifier)
+ /* left = NOf + Max(LAR, EZ)
+ right = NOf + RAR */
+
+ if (bRTL)
+ nMaxLeft = lNullPix + GetRightIndent();
+ else
+ nMaxLeft = lNullPix + std::min(GetFirstLineIndent(), GetLeftIndent());
+
+ mxRulerImpl->lMaxRightLogic = GetLogicRightIndent() + lLogicNullOffset;
+ nMaxRight = ConvertSizePixel(mxRulerImpl->lMaxRightLogic);
+ break;
+ default: ; //prevent warning
+ }
+}
+
+bool SvxRuler::StartDrag()
+{
+ /*
+ Beginning of a drag operation (SV-handler) evaluates modifier and
+ calculated values
+
+ [Cross-reference]
+
+ <SvxRuler::EvalModifier()>
+ <SvxRuler::CalcMinMax()>
+ <SvxRuler::EndDrag()>
+ */
+ bool bContentProtected = mxRulerImpl->aProtectItem->IsContentProtected();
+
+ if(!bValid)
+ return false;
+
+ mxRulerImpl->lLastLMargin = GetMargin1();
+ mxRulerImpl->lLastRMargin = GetMargin2();
+
+ bool bOk = true;
+
+ lInitialDragPos = GetDragPos();
+ switch(GetDragType())
+ {
+ case RulerType::Margin1: // left edge of the surrounding Frame
+ case RulerType::Margin2: // right edge of the surrounding Frame
+ if((bHorz && mxLRSpaceItem) || (!bHorz && mxULSpaceItem))
+ {
+ if (!mxColumnItem)
+ EvalModifier();
+ else
+ nDragType = SvxRulerDragFlags::OBJECT;
+ }
+ else
+ {
+ bOk = false;
+ }
+ break;
+ case RulerType::Border: // Table, column (Modifier)
+ if (mxColumnItem)
+ {
+ nDragOffset = 0;
+ if (!mxColumnItem->IsTable())
+ nDragOffset = GetDragPos() - mpBorders[GetDragAryPos()].nPos;
+ EvalModifier();
+ }
+ else
+ nDragOffset = 0;
+ break;
+ case RulerType::Indent: // Paragraph indents (Modifier)
+ {
+ if( bContentProtected )
+ return false;
+ if(INDENT_LEFT_MARGIN == GetDragAryPos() + INDENT_GAP) { // Left paragraph indent
+ mpIndents[0] = mpIndents[INDENT_FIRST_LINE];
+ EvalModifier();
+ }
+ else
+ {
+ nDragType = SvxRulerDragFlags::OBJECT;
+ }
+ mpIndents[1] = mpIndents[GetDragAryPos() + INDENT_GAP];
+ break;
+ }
+ case RulerType::Tab: // Tabs (Modifier)
+ if( bContentProtected )
+ return false;
+ EvalModifier();
+ mpTabs[0] = mpTabs[GetDragAryPos() + 1];
+ mpTabs[0].nStyle |= RULER_STYLE_DONTKNOW;
+ break;
+ default:
+ nDragType = SvxRulerDragFlags::NONE;
+ }
+
+ if(bOk)
+ CalcMinMax();
+
+ return bOk;
+}
+
+void SvxRuler::Drag()
+{
+ /* SV-Draghandler */
+ if(IsDragCanceled())
+ {
+ Ruler::Drag();
+ return;
+ }
+ switch(GetDragType()) {
+ case RulerType::Margin1: // left edge of the surrounding Frame
+ DragMargin1();
+ mxRulerImpl->lLastLMargin = GetMargin1();
+ break;
+ case RulerType::Margin2: // right edge of the surrounding Frame
+ DragMargin2();
+ mxRulerImpl->lLastRMargin = GetMargin2();
+ break;
+ case RulerType::Indent: // Paragraph indents
+ DragIndents();
+ break;
+ case RulerType::Border: // Table, columns
+ if (mxColumnItem)
+ DragBorders();
+ else if (mxObjectItem)
+ DragObjectBorder();
+ break;
+ case RulerType::Tab: // Tabs
+ DragTabs();
+ break;
+ default:
+ break; //prevent warning
+ }
+ Ruler::Drag();
+}
+
+void SvxRuler::EndDrag()
+{
+ /*
+ SV-handler; is called when ending the dragging. Triggers the updating of data
+ on the application, by calling the respective Apply...() methods to send the
+ data to the application.
+ */
+ const bool bUndo = IsDragCanceled();
+ const tools::Long lPos = GetDragPos();
+ DrawLine_Impl(lTabPos, 6, bHorz);
+ lTabPos = -1;
+
+ if(!bUndo)
+ {
+ switch(GetDragType())
+ {
+ case RulerType::Margin1: // upper left edge of the surrounding Frame
+ case RulerType::Margin2: // lower right edge of the surrounding Frame
+ {
+ if (!mxColumnItem || !mxColumnItem->IsTable())
+ ApplyMargins();
+
+ if(mxColumnItem &&
+ (mxColumnItem->IsTable() ||
+ (nDragType & SvxRulerDragFlags::OBJECT_SIZE_PROPORTIONAL)))
+ ApplyBorders();
+
+ }
+ break;
+ case RulerType::Border: // Table, columns
+ if(lInitialDragPos != lPos ||
+ (mxRulerImpl->bIsTableRows && bHorz)) //special case - the null offset is changed here
+ {
+ if (mxColumnItem)
+ {
+ ApplyBorders();
+ if(bHorz)
+ UpdateTabs();
+ }
+ else if (mxObjectItem)
+ ApplyObject();
+ }
+ break;
+ case RulerType::Indent: // Paragraph indents
+ if(lInitialDragPos != lPos)
+ ApplyIndents();
+ SetIndents(INDENT_COUNT, mpIndents.data() + INDENT_GAP);
+ break;
+ case RulerType::Tab: // Tabs
+ {
+ ApplyTabs();
+ mpTabs[GetDragAryPos()].nStyle &= ~RULER_STYLE_INVISIBLE;
+ SetTabs(nTabCount, mpTabs.data() + TAB_GAP);
+ }
+ break;
+ default:
+ break; //prevent warning
+ }
+ }
+ nDragType = SvxRulerDragFlags::NONE;
+
+ mbCoarseSnapping = false;
+ mbSnapping = true;
+
+ Ruler::EndDrag();
+ if(bUndo)
+ {
+ for(sal_uInt16 i = 0; i < mxRulerImpl->nControllerItems; i++)
+ {
+ pCtrlItems[i]->ClearCache();
+ pCtrlItems[i]->GetBindings().Invalidate(pCtrlItems[i]->GetId());
+ }
+ }
+}
+
+void SvxRuler::ExtraDown()
+{
+ /* Override SV method, sets the new type for the Default tab. */
+
+ // Switch Tab Type
+ if(mxTabStopItem &&
+ (nFlags & SvxRulerSupportFlags::TABS) == SvxRulerSupportFlags::TABS)
+ {
+ ++nDefTabType;
+ if(RULER_TAB_DEFAULT == nDefTabType)
+ nDefTabType = RULER_TAB_LEFT;
+ SetExtraType(RulerExtra::Tab, nDefTabType);
+ }
+ Ruler::ExtraDown();
+}
+
+void SvxRuler::Notify(SfxBroadcaster&, const SfxHint& rHint)
+{
+ /*
+ Report through the bindings that the status update is completed. The ruler
+ updates its appearance and gets registered again in the bindings.
+ */
+
+ // start update
+ if (bActive && rHint.GetId() == SfxHintId::UpdateDone)
+ {
+ Update();
+ EndListening(*pBindings);
+ bValid = true;
+ bListening = false;
+ }
+}
+
+void SvxRuler::MenuSelect(std::u16string_view ident)
+{
+ if (ident.empty())
+ return;
+ /* Handler of the context menus for switching the unit of measurement */
+ SetUnit(vcl::EnglishStringToMetric(ident));
+}
+
+void SvxRuler::TabMenuSelect(std::u16string_view rIdent)
+{
+ if (rIdent.empty())
+ return;
+ sal_Int32 nId = o3tl::toInt32(rIdent);
+ /* Handler of the tab menu for setting the type */
+ if (mxTabStopItem && mxTabStopItem->Count() > mxRulerImpl->nIdx)
+ {
+ SvxTabStop aTabStop = mxTabStopItem->At(mxRulerImpl->nIdx);
+ aTabStop.GetAdjustment() = ToAttrTab_Impl(nId - 1);
+ mxTabStopItem->Remove(mxRulerImpl->nIdx);
+ mxTabStopItem->Insert(aTabStop);
+ sal_uInt16 nTabStopId = bHorz ? SID_ATTR_TABSTOP : SID_ATTR_TABSTOP_VERTICAL;
+ pBindings->GetDispatcher()->ExecuteList(nTabStopId,
+ SfxCallMode::RECORD, { mxTabStopItem.get() });
+ UpdateTabs();
+ mxRulerImpl->nIdx = 0;
+ }
+}
+
+const TranslateId RID_SVXSTR_RULER_TAB[] =
+{
+ RID_SVXSTR_RULER_TAB_LEFT,
+ RID_SVXSTR_RULER_TAB_RIGHT,
+ RID_SVXSTR_RULER_TAB_CENTER,
+ RID_SVXSTR_RULER_TAB_DECIMAL
+};
+
+void SvxRuler::Command( const CommandEvent& rCommandEvent )
+{
+ /* Mouse context menu for switching the unit of measurement */
+ if ( CommandEventId::ContextMenu == rCommandEvent.GetCommand() )
+ {
+ CancelDrag();
+
+ tools::Rectangle aRect(rCommandEvent.GetMousePosPixel(), Size(1, 1));
+ weld::Window* pPopupParent = weld::GetPopupParent(*this, aRect);
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, "svx/ui/rulermenu.ui"));
+ std::unique_ptr<weld::Menu> xMenu(xBuilder->weld_menu("menu"));
+
+ bool bRTL = mxRulerImpl->pTextRTLItem && mxRulerImpl->pTextRTLItem->GetValue();
+ if ( !mpTabs.empty() &&
+ RulerType::Tab ==
+ GetRulerType( rCommandEvent.GetMousePosPixel(), &mxRulerImpl->nIdx ) &&
+ mpTabs[mxRulerImpl->nIdx + TAB_GAP].nStyle < RULER_TAB_DEFAULT )
+ {
+ xMenu->clear();
+
+ const Size aSz(ruler_tab_svx.width + 2, ruler_tab_svx.height + 2);
+ const Point aPt(aSz.Width() / 2, aSz.Height() / 2);
+
+ for ( sal_uInt16 i = RULER_TAB_LEFT; i < RULER_TAB_DEFAULT; ++i )
+ {
+ ScopedVclPtr<VirtualDevice> xDev(pPopupParent->create_virtual_device());
+ xDev->SetOutputSize(aSz);
+
+ sal_uInt16 nStyle = bRTL ? i|RULER_TAB_RTL : i;
+ nStyle |= static_cast<sal_uInt16>(bHorz ? WB_HORZ : WB_VERT);
+
+ Color aFillColor(xDev->GetSettings().GetStyleSettings().GetShadowColor());
+ DrawTab(*xDev, aFillColor, aPt, nStyle);
+
+ OUString sId(OUString::number(i + 1));
+ xMenu->insert(-1, sId, SvxResId(RID_SVXSTR_RULER_TAB[i]),
+ nullptr, xDev.get(), nullptr, TRISTATE_TRUE);
+ xMenu->set_active(sId, i == mpTabs[mxRulerImpl->nIdx + TAB_GAP].nStyle);
+ }
+ TabMenuSelect(xMenu->popup_at_rect(pPopupParent, aRect));
+ }
+ else
+ {
+ FieldUnit eUnit = GetUnit();
+ const int nCount = xMenu->n_children();
+
+ bool bReduceMetric = bool(nFlags & SvxRulerSupportFlags::REDUCED_METRIC);
+ for ( sal_uInt16 i = nCount; i; --i )
+ {
+ OUString sIdent = xMenu->get_id(i - 1);
+ FieldUnit eMenuUnit = vcl::EnglishStringToMetric(sIdent);
+ xMenu->set_active(sIdent, eMenuUnit == eUnit);
+ if( bReduceMetric )
+ {
+ if (eMenuUnit == FieldUnit::M ||
+ eMenuUnit == FieldUnit::KM ||
+ eMenuUnit == FieldUnit::FOOT ||
+ eMenuUnit == FieldUnit::MILE)
+ {
+ xMenu->remove(sIdent);
+ }
+ else if (( eMenuUnit == FieldUnit::CHAR ) && !bHorz )
+ {
+ xMenu->remove(sIdent);
+ }
+ else if (( eMenuUnit == FieldUnit::LINE ) && bHorz )
+ {
+ xMenu->remove(sIdent);
+ }
+ }
+ }
+ MenuSelect(xMenu->popup_at_rect(pPopupParent, aRect));
+ }
+ }
+ else
+ {
+ Ruler::Command( rCommandEvent );
+ }
+}
+
+sal_uInt16 SvxRuler::GetActRightColumn(
+ bool bForceDontConsiderHidden,
+ sal_uInt16 nAct ) const
+{
+ if( nAct == USHRT_MAX )
+ nAct = mxColumnItem->GetActColumn();
+ else
+ nAct++; //To be able to pass on the ActDrag
+
+ bool bConsiderHidden = !bForceDontConsiderHidden &&
+ !(nDragType & SvxRulerDragFlags::OBJECT_ACTLINE_ONLY);
+
+ while( nAct < mxColumnItem->Count() - 1 )
+ {
+ if (mxColumnItem->At(nAct).bVisible || bConsiderHidden)
+ return nAct;
+ else
+ nAct++;
+ }
+ return USHRT_MAX;
+}
+
+sal_uInt16 SvxRuler::GetActLeftColumn(
+ bool bForceDontConsiderHidden,
+ sal_uInt16 nAct ) const
+{
+ if(nAct == USHRT_MAX)
+ nAct = mxColumnItem->GetActColumn();
+
+ sal_uInt16 nLeftOffset = 1;
+
+ bool bConsiderHidden = !bForceDontConsiderHidden &&
+ !(nDragType & SvxRulerDragFlags::OBJECT_ACTLINE_ONLY);
+
+ while(nAct >= nLeftOffset)
+ {
+ if (mxColumnItem->At(nAct - nLeftOffset).bVisible || bConsiderHidden)
+ return nAct - nLeftOffset;
+ else
+ nLeftOffset++;
+ }
+ return USHRT_MAX;
+}
+
+bool SvxRuler::IsActLastColumn(
+ bool bForceDontConsiderHidden,
+ sal_uInt16 nAct) const
+{
+ return GetActRightColumn(bForceDontConsiderHidden, nAct) == USHRT_MAX;
+}
+
+bool SvxRuler::IsActFirstColumn(
+ bool bForceDontConsiderHidden,
+ sal_uInt16 nAct) const
+{
+ return GetActLeftColumn(bForceDontConsiderHidden, nAct) == USHRT_MAX;
+}
+
+tools::Long SvxRuler::CalcPropMaxRight(sal_uInt16 nCol) const
+{
+
+ if(!(nDragType & SvxRulerDragFlags::OBJECT_SIZE_LINEAR))
+ {
+ // Remove the minimum width for all affected columns
+ // starting from the right edge
+ tools::Long _nMaxRight = GetMargin2() - GetMargin1();
+
+ tools::Long lFences = 0;
+ tools::Long lMinSpace = USHRT_MAX;
+ tools::Long lOldPos;
+ tools::Long lColumns = 0;
+
+ sal_uInt16 nStart;
+ if(!mxColumnItem->IsTable())
+ {
+ if(nCol == USHRT_MAX)
+ {
+ lOldPos = GetMargin1();
+ nStart = 0;
+ }
+ else
+ {
+ lOldPos = mpBorders[nCol].nPos + mpBorders[nCol].nWidth;
+ nStart = nCol + 1;
+ lFences = mpBorders[nCol].nWidth;
+ }
+
+ for(size_t i = nStart; i < mpBorders.size() - 1; ++i)
+ {
+ tools::Long lWidth = mpBorders[i].nPos - lOldPos;
+ lColumns += lWidth;
+ if(lWidth < lMinSpace)
+ lMinSpace = lWidth;
+ lOldPos = mpBorders[i].nPos + mpBorders[i].nWidth;
+ lFences += mpBorders[i].nWidth;
+ }
+ tools::Long lWidth = GetMargin2() - lOldPos;
+ lColumns += lWidth;
+ if(lWidth < lMinSpace)
+ lMinSpace = lWidth;
+ }
+ else
+ {
+ sal_uInt16 nActCol;
+ if(nCol == USHRT_MAX) //CalcMinMax for LeftMargin
+ {
+ lOldPos = GetMargin1();
+ }
+ else
+ {
+ lOldPos = mpBorders[nCol].nPos;
+ }
+ lColumns = GetMargin2()-lOldPos;
+ nActCol = nCol;
+ lFences = 0;
+ while(nActCol < mpBorders.size() || nActCol == USHRT_MAX)
+ {
+ sal_uInt16 nRight;
+ if(nActCol == USHRT_MAX)
+ {
+ nRight = 0;
+ while (!(*mxColumnItem)[nRight].bVisible)
+ {
+ nRight++;
+ }
+ }
+ else
+ {
+ nRight = GetActRightColumn(false, nActCol);
+ }
+
+ tools::Long lWidth;
+ if(nRight != USHRT_MAX)
+ {
+ lWidth = mpBorders[nRight].nPos - lOldPos;
+ lOldPos = mpBorders[nRight].nPos;
+ }
+ else
+ {
+ lWidth=GetMargin2() - lOldPos;
+ }
+ nActCol = nRight;
+ if(lWidth < lMinSpace)
+ lMinSpace = lWidth;
+ if(nActCol == USHRT_MAX)
+ break;
+ }
+ }
+
+ _nMaxRight -= static_cast<tools::Long>(lFences + glMinFrame / static_cast<float>(lMinSpace) * lColumns);
+ return _nMaxRight;
+ }
+ else
+ {
+ if(mxColumnItem->IsTable())
+ {
+ sal_uInt16 nVisCols = 0;
+ for(size_t i = GetActRightColumn(false, nCol); i < mpBorders.size();)
+ {
+ if ((*mxColumnItem)[i].bVisible)
+ nVisCols++;
+ i = GetActRightColumn(false, i);
+ }
+ return GetMargin2() - GetMargin1() - (nVisCols + 1) * glMinFrame;
+ }
+ else
+ {
+ tools::Long lWidth = 0;
+ for(size_t i = nCol; i < mpBorders.size() - 1; i++)
+ {
+ lWidth += glMinFrame + mpBorders[i].nWidth;
+ }
+ return GetMargin2() - GetMargin1() - lWidth;
+ }
+ }
+}
+
+// Tab stops relative to indent (#i24363#)
+void SvxRuler::SetTabsRelativeToIndent( bool bRel )
+{
+ mxRulerImpl->bIsTabsRelativeToIndent = bRel;
+}
+
+void SvxRuler::SetValues(RulerChangeType type, tools::Long diffValue)
+{
+ if (diffValue == 0)
+ return;
+
+ if (type == RulerChangeType::MARGIN1)
+ AdjustMargin1(diffValue);
+ else if (type == RulerChangeType::MARGIN2)
+ SetMargin2( GetMargin2() - diffValue);
+ ApplyMargins();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/svx/source/dialog/swframeexample.cxx b/svx/source/dialog/swframeexample.cxx
new file mode 100644
index 0000000000..29475f6f39
--- /dev/null
+++ b/svx/source/dialog/swframeexample.cxx
@@ -0,0 +1,714 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vcl/metric.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <svtools/colorcfg.hxx>
+#include <svx/swframeexample.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <com/sun/star/text/HoriOrientation.hpp>
+#include <com/sun/star/text/VertOrientation.hpp>
+#include <com/sun/star/text/RelOrientation.hpp>
+
+using namespace ::com::sun::star::text;
+
+#define FLYINFLY_BORDER 3
+constexpr OUString DEMOTEXT = u"Ij"_ustr;
+
+namespace {
+
+void DrawRect_Impl(vcl::RenderContext& rRenderContext, const tools::Rectangle &rRect,
+ const Color &rFillColor, const Color &rLineColor)
+{
+ rRenderContext.SetFillColor(rFillColor);
+ rRenderContext.SetLineColor(rLineColor);
+ rRenderContext.DrawRect(rRect);
+}
+
+}
+
+SwFrameExample::SwFrameExample()
+ : nHAlign(HoriOrientation::CENTER)
+ , nHRel(RelOrientation::FRAME)
+ , nVAlign(VertOrientation::TOP)
+ , nVRel(RelOrientation::PRINT_AREA)
+ , nWrap(WrapTextMode_NONE)
+ , nAnchor(RndStdIds::FLY_AT_PAGE)
+ , bTrans(false)
+ , aRelPos(Point(0,0))
+{
+ InitColors_Impl();
+}
+
+void SwFrameExample::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ CustomWidgetController::SetDrawingArea(pDrawingArea);
+ pDrawingArea->set_size_request(pDrawingArea->get_approximate_digit_width() * 16,
+ pDrawingArea->get_text_height() * 12);
+}
+
+void SwFrameExample::InitColors_Impl()
+{
+ const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
+ m_aBgCol = rSettings.GetWindowColor();
+
+ bool bHC = rSettings.GetHighContrastMode();
+
+ m_aFrameColor = COL_LIGHTGREEN;
+ m_aAlignColor = COL_LIGHTRED;
+ m_aTransColor = COL_TRANSPARENT;
+
+ m_aTxtCol = bHC?
+ svtools::ColorConfig().GetColorValue(svtools::FONTCOLOR).nColor :
+ COL_GRAY;
+ m_aPrintAreaCol = bHC? m_aTxtCol : COL_GRAY;
+ m_aBorderCol = m_aTxtCol;
+ m_aBlankCol = bHC? m_aTxtCol : COL_LIGHTGRAY;
+ m_aBlankFrameCol = bHC? m_aTxtCol : COL_GRAY;
+}
+
+void SwFrameExample::StyleUpdated()
+{
+ InitColors_Impl();
+ CustomWidgetController::StyleUpdated();
+}
+
+void SwFrameExample::InitAllRects_Impl(vcl::RenderContext& rRenderContext)
+{
+ aPage.SetSize(GetOutputSizePixel());
+
+ sal_uInt32 nOutWPix = aPage.GetWidth();
+ sal_uInt32 nOutHPix = aPage.GetHeight();
+
+ // PrintArea
+ sal_uInt32 nLBorder;
+ sal_uInt32 nRBorder;
+ sal_uInt32 nTBorder;
+ sal_uInt32 nBBorder;
+
+ sal_uInt32 nLTxtBorder;
+ sal_uInt32 nRTxtBorder;
+ sal_uInt32 nTTxtBorder;
+ sal_uInt32 nBTxtBorder;
+
+ if (nAnchor != RndStdIds::FLY_AS_CHAR)
+ {
+ nLBorder = 14;
+ nRBorder = 10;
+ nTBorder = 10;
+ nBBorder = 15;
+
+ nLTxtBorder = 8;
+ nRTxtBorder = 4;
+ nTTxtBorder = 2;
+ nBTxtBorder = 2;
+ }
+ else
+ {
+ nLBorder = 2;
+ nRBorder = 2;
+ nTBorder = 2;
+ nBBorder = 2;
+
+ nLTxtBorder = 2;
+ nRTxtBorder = 2;
+ nTTxtBorder = 2;
+ nBTxtBorder = 2;
+ }
+ aPagePrtArea = tools::Rectangle(Point(nLBorder, nTBorder), Point((nOutWPix - 1) - nRBorder, (nOutHPix - 1) - nBBorder));
+
+ // Example text: Preparing for the text output
+ // A line of text
+ aTextLine = aPagePrtArea;
+ aTextLine.SetSize(Size(aTextLine.GetWidth(), 2));
+ aTextLine.AdjustLeft(nLTxtBorder );
+ aTextLine.AdjustRight( -sal_Int32(nRTxtBorder) );
+ aTextLine.Move(0, nTTxtBorder);
+
+ // Rectangle to edges including paragraph
+ sal_uInt16 nLines = static_cast<sal_uInt16>((aPagePrtArea.GetHeight() / 2 - nTTxtBorder - nBTxtBorder)
+ / (aTextLine.GetHeight() + 2));
+ aPara = aPagePrtArea;
+ aPara.SetSize(Size(aPara.GetWidth(),
+ (aTextLine.GetHeight() + 2) * nLines + nTTxtBorder + nBTxtBorder));
+
+ // Rectangle around paragraph without borders
+ aParaPrtArea = aPara;
+ aParaPrtArea.AdjustLeft(nLTxtBorder );
+ aParaPrtArea.AdjustRight( -sal_Int32(nRTxtBorder) );
+ aParaPrtArea.AdjustTop(nTTxtBorder );
+ aParaPrtArea.AdjustBottom( -sal_Int32(nBTxtBorder) );
+
+ if (nAnchor == RndStdIds::FLY_AS_CHAR || nAnchor == RndStdIds::FLY_AT_CHAR)
+ {
+ vcl::Font aFont = OutputDevice::GetDefaultFont(
+ DefaultFontType::LATIN_TEXT, Application::GetSettings().GetLanguageTag().getLanguageType(),
+ GetDefaultFontFlags::OnlyOne, &rRenderContext );
+ aFont.SetColor( m_aTxtCol );
+ aFont.SetFillColor( m_aBgCol );
+ aFont.SetWeight(WEIGHT_NORMAL);
+
+ if (nAnchor == RndStdIds::FLY_AS_CHAR)
+ {
+ aFont.SetFontSize(Size(0, aParaPrtArea.GetHeight() - 2));
+ rRenderContext.SetFont(aFont);
+ aParaPrtArea.SetSize(Size(rRenderContext.GetTextWidth(DEMOTEXT), rRenderContext.GetTextHeight()));
+ }
+ else
+ {
+ aFont.SetFontSize(Size(0, aParaPrtArea.GetHeight() / 2));
+ rRenderContext.SetFont(aFont);
+ aAutoCharFrame.SetSize(Size(rRenderContext.GetTextWidth(OUString('A')), GetTextHeight()));
+ aAutoCharFrame.SetPos(Point(aParaPrtArea.Left() + (aParaPrtArea.GetWidth() - aAutoCharFrame.GetWidth()) / 2,
+ aParaPrtArea.Top() + (aParaPrtArea.GetHeight() - aAutoCharFrame.GetHeight()) / 2));
+ }
+ }
+
+ // Inner Frame anchored at the Frame
+ aFrameAtFrame = aPara;
+ aFrameAtFrame.AdjustLeft(9 );
+ aFrameAtFrame.AdjustRight( -5 );
+ aFrameAtFrame.AdjustBottom(5 );
+ aFrameAtFrame.SetPos(Point(aFrameAtFrame.Left() + 2, (aPagePrtArea.Bottom() - aFrameAtFrame.GetHeight()) / 2 + 5));
+
+ // Size of the frame to be positioned
+ if (nAnchor != RndStdIds::FLY_AS_CHAR)
+ {
+ sal_uInt32 nLFBorder = nAnchor == RndStdIds::FLY_AT_PAGE ? nLBorder : nLTxtBorder;
+ sal_uInt32 nRFBorder = nAnchor == RndStdIds::FLY_AT_PAGE ? nRBorder : nRTxtBorder;
+
+ switch (nHRel)
+ {
+ case RelOrientation::PAGE_LEFT:
+ case RelOrientation::FRAME_LEFT:
+ aFrmSize = Size(nLFBorder - 4, (aTextLine.GetHeight() + 2) * 3);
+ break;
+
+ case RelOrientation::PAGE_RIGHT:
+ case RelOrientation::FRAME_RIGHT:
+ aFrmSize = Size(nRFBorder - 4, (aTextLine.GetHeight() + 2) * 3);
+ break;
+
+ default:
+ aFrmSize = Size(nLBorder - 3, (aTextLine.GetHeight() + 2) * 3);
+ break;
+ }
+ aFrmSize.setWidth( std::max(tools::Long(5), aFrmSize.Width()) );
+ aFrmSize.setHeight( std::max(tools::Long(5), aFrmSize.Height()) );
+ }
+ else
+ {
+ sal_uInt32 nFreeWidth = aPagePrtArea.GetWidth() - rRenderContext.GetTextWidth(DEMOTEXT);
+
+ aFrmSize = Size(nFreeWidth / 2, (aTextLine.GetHeight() + 2) * 3);
+ aDrawObj.SetSize(Size(std::max(tools::Long(5), tools::Long(nFreeWidth / 3)), std::max(tools::Long(5), aFrmSize.Height() * 3)));
+ aDrawObj.SetPos(Point(aParaPrtArea.Right() + 1, aParaPrtArea.Bottom() / 2));
+ aParaPrtArea.SetRight( aDrawObj.Right() );
+ }
+}
+
+void SwFrameExample::CalcBoundRect_Impl(const vcl::RenderContext& rRenderContext, tools::Rectangle &rRect)
+{
+ switch (nAnchor)
+ {
+ case RndStdIds::FLY_AT_PAGE:
+ {
+ switch (nHRel)
+ {
+ case RelOrientation::FRAME:
+ case RelOrientation::PAGE_FRAME:
+ rRect.SetLeft( aPage.Left() );
+ rRect.SetRight( aPage.Right() );
+ break;
+
+ case RelOrientation::PRINT_AREA:
+ case RelOrientation::PAGE_PRINT_AREA:
+ rRect.SetLeft( aPagePrtArea.Left() );
+ rRect.SetRight( aPagePrtArea.Right() );
+ break;
+
+ case RelOrientation::PAGE_LEFT:
+ rRect.SetLeft( aPage.Left() );
+ rRect.SetRight( aPagePrtArea.Left() );
+ break;
+
+ case RelOrientation::PAGE_RIGHT:
+ rRect.SetLeft( aPagePrtArea.Right() );
+ rRect.SetRight( aPage.Right() );
+ break;
+ }
+
+ switch (nVRel)
+ {
+ case RelOrientation::PRINT_AREA:
+ case RelOrientation::PAGE_PRINT_AREA:
+ rRect.SetTop( aPagePrtArea.Top() );
+ rRect.SetBottom( aPagePrtArea.Bottom() );
+ break;
+
+ case RelOrientation::FRAME:
+ case RelOrientation::PAGE_FRAME:
+ rRect.SetTop( aPage.Top() );
+ rRect.SetBottom( aPage.Bottom() );
+ break;
+ }
+ }
+ break;
+
+ case RndStdIds::FLY_AT_FLY:
+ {
+ switch (nHRel)
+ {
+ case RelOrientation::FRAME:
+ case RelOrientation::PAGE_FRAME:
+ rRect.SetLeft( aFrameAtFrame.Left() );
+ rRect.SetRight( aFrameAtFrame.Right() );
+ break;
+
+ case RelOrientation::PRINT_AREA:
+ case RelOrientation::PAGE_PRINT_AREA:
+ rRect.SetLeft( aFrameAtFrame.Left() + FLYINFLY_BORDER );
+ rRect.SetRight( aFrameAtFrame.Right() - FLYINFLY_BORDER );
+ break;
+
+ case RelOrientation::PAGE_LEFT:
+ rRect.SetLeft( aFrameAtFrame.Left() );
+ rRect.SetRight( aFrameAtFrame.Left() + FLYINFLY_BORDER );
+ break;
+
+ case RelOrientation::PAGE_RIGHT:
+ rRect.SetLeft( aFrameAtFrame.Right() );
+ rRect.SetRight( aFrameAtFrame.Right() - FLYINFLY_BORDER );
+ break;
+ }
+
+ switch (nVRel)
+ {
+ case RelOrientation::FRAME:
+ case RelOrientation::PAGE_FRAME:
+ rRect.SetTop( aFrameAtFrame.Top() );
+ rRect.SetBottom( aFrameAtFrame.Bottom() );
+ break;
+
+ case RelOrientation::PRINT_AREA:
+ case RelOrientation::PAGE_PRINT_AREA:
+ rRect.SetTop( aFrameAtFrame.Top() + FLYINFLY_BORDER );
+ rRect.SetBottom( aFrameAtFrame.Bottom() - FLYINFLY_BORDER );
+ break;
+ }
+ }
+ break;
+ case RndStdIds::FLY_AT_PARA:
+ case RndStdIds::FLY_AT_CHAR:
+ {
+ switch (nHRel)
+ {
+ case RelOrientation::FRAME:
+ rRect.SetLeft( aPara.Left() );
+ rRect.SetRight( aPara.Right() );
+ break;
+
+ case RelOrientation::PRINT_AREA:
+ rRect.SetLeft( aParaPrtArea.Left() );
+ rRect.SetRight( aParaPrtArea.Right() );
+ break;
+
+ case RelOrientation::PAGE_LEFT:
+ rRect.SetLeft( aPage.Left() );
+ rRect.SetRight( aPagePrtArea.Left() );
+ break;
+
+ case RelOrientation::PAGE_RIGHT:
+ rRect.SetLeft( aPagePrtArea.Right() );
+ rRect.SetRight( aPage.Right() );
+ break;
+
+ case RelOrientation::PAGE_FRAME:
+ rRect.SetLeft( aPage.Left() );
+ rRect.SetRight( aPage.Right() );
+ break;
+
+ case RelOrientation::PAGE_PRINT_AREA:
+ rRect.SetLeft( aPagePrtArea.Left() );
+ rRect.SetRight( aPagePrtArea.Right() );
+ break;
+
+ case RelOrientation::FRAME_LEFT:
+ rRect.SetLeft( aPara.Left() );
+ rRect.SetRight( aParaPrtArea.Left() );
+ break;
+
+ case RelOrientation::FRAME_RIGHT:
+ rRect.SetLeft( aParaPrtArea.Right() );
+ rRect.SetRight( aPara.Right() );
+ break;
+
+ case RelOrientation::CHAR:
+ rRect.SetLeft( aAutoCharFrame.Left() );
+ rRect.SetRight( aAutoCharFrame.Left() );
+ break;
+ }
+
+ switch (nVRel)
+ {
+ case RelOrientation::FRAME:
+ rRect.SetTop( aPara.Top() );
+ rRect.SetBottom( aPara.Bottom() );
+ break;
+
+ case RelOrientation::PRINT_AREA:
+ rRect.SetTop( aParaPrtArea.Top() );
+ rRect.SetBottom( aParaPrtArea.Bottom() );
+ break;
+
+ case RelOrientation::CHAR:
+ if (nVAlign != VertOrientation::NONE &&
+ nVAlign != VertOrientation::CHAR_BOTTOM)
+ rRect.SetTop( aAutoCharFrame.Top() );
+ else
+ rRect.SetTop( aAutoCharFrame.Bottom() );
+ rRect.SetBottom( aAutoCharFrame.Bottom() );
+ break;
+ // OD 12.11.2003 #i22341#
+ case RelOrientation::TEXT_LINE:
+ rRect.SetTop( aAutoCharFrame.Top() );
+ rRect.SetBottom( aAutoCharFrame.Top() );
+ break;
+ }
+ }
+ break;
+
+ case RndStdIds::FLY_AS_CHAR:
+ rRect.SetLeft( aParaPrtArea.Left() );
+ rRect.SetRight( aParaPrtArea.Right() );
+
+ switch (nVAlign)
+ {
+ case VertOrientation::NONE:
+ case VertOrientation::TOP:
+ case VertOrientation::CENTER:
+ case VertOrientation::BOTTOM:
+ {
+ FontMetric aMetric(rRenderContext.GetFontMetric());
+
+ rRect.SetTop( aParaPrtArea.Bottom() - aMetric.GetDescent() );
+ rRect.SetBottom( rRect.Top() );
+ }
+ break;
+
+ default:
+
+ case VertOrientation::LINE_TOP:
+ case VertOrientation::LINE_CENTER:
+ case VertOrientation::LINE_BOTTOM:
+ rRect.SetTop( aParaPrtArea.Top() );
+ rRect.SetBottom( aDrawObj.Bottom() );
+ break;
+
+ case VertOrientation::CHAR_TOP:
+ case VertOrientation::CHAR_CENTER:
+ case VertOrientation::CHAR_BOTTOM:
+ rRect.SetTop( aParaPrtArea.Top() );
+ rRect.SetBottom( aParaPrtArea.Bottom() );
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+tools::Rectangle SwFrameExample::DrawInnerFrame_Impl(vcl::RenderContext& rRenderContext, const tools::Rectangle &rRect,
+ const Color &rFillColor, const Color &rBorderColor)
+{
+ DrawRect_Impl(rRenderContext, rRect, rFillColor, rBorderColor);
+
+ // determine the area relative to which the positioning happens
+ tools::Rectangle aRect(rRect); // aPagePrtArea = Default
+ CalcBoundRect_Impl(rRenderContext, aRect);
+
+ if (nAnchor == RndStdIds::FLY_AT_FLY && &rRect == &aPagePrtArea)
+ {
+ // draw text paragraph
+ tools::Rectangle aTxt(aTextLine);
+ sal_Int32 nStep = aTxt.GetHeight() + 2;
+ sal_uInt16 nLines = static_cast<sal_uInt16>(aParaPrtArea.GetHeight() / (aTextLine.GetHeight() + 2));
+
+ for (sal_uInt16 i = 0; i < nLines; i++)
+ {
+ if (i == nLines - 1)
+ aTxt.SetSize(Size(aTxt.GetWidth() / 2, aTxt.GetHeight()));
+ DrawRect_Impl(rRenderContext, aTxt, m_aTxtCol, m_aTransColor);
+ aTxt.Move(0, nStep);
+ }
+ }
+
+ return aRect;
+}
+
+void SwFrameExample::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ rRenderContext.SetMapMode(MapMode(MapUnit::MapPixel));
+
+ InitAllRects_Impl(rRenderContext);
+
+ // Draw page
+ DrawRect_Impl(rRenderContext, aPage, m_aBgCol, m_aBorderCol);
+
+ // Draw PrintArea
+ tools::Rectangle aRect = DrawInnerFrame_Impl(rRenderContext, aPagePrtArea, m_aTransColor, m_aPrintAreaCol);
+
+ if (nAnchor == RndStdIds::FLY_AT_FLY)
+ aRect = DrawInnerFrame_Impl(rRenderContext, aFrameAtFrame, m_aBgCol, m_aBorderCol);
+
+ tools::Long lXPos = 0;
+ tools::Long lYPos = 0;
+
+ // Horizontal alignment
+ if (nAnchor != RndStdIds::FLY_AS_CHAR)
+ {
+ switch (nHAlign)
+ {
+ case HoriOrientation::RIGHT:
+ {
+ lXPos = aRect.Right() - aFrmSize.Width() + 1;
+ break;
+ }
+ case HoriOrientation::CENTER:
+ {
+ lXPos = aRect.Left() + (aRect.GetWidth() - aFrmSize.Width()) / 2;
+ break;
+ }
+ case HoriOrientation::NONE:
+ {
+ lXPos = aRect.Left() + aRelPos.X();
+ break;
+ }
+
+ default: // HoriOrientation::LEFT
+ lXPos = aRect.Left();
+ break;
+ }
+ }
+ else
+ {
+ lXPos = aRect.Right() + 2;
+ }
+
+ // Vertical Alignment
+ if (nAnchor != RndStdIds::FLY_AS_CHAR)
+ {
+ switch (nVAlign)
+ {
+ case VertOrientation::BOTTOM:
+ case VertOrientation::LINE_BOTTOM:
+ {
+ // #i22341#
+ if ( nVRel != RelOrientation::TEXT_LINE )
+ {
+ lYPos = aRect.Bottom() - aFrmSize.Height() + 1;
+ }
+ else
+ {
+ lYPos = aRect.Top();
+ }
+ break;
+ }
+ case VertOrientation::CENTER:
+ case VertOrientation::LINE_CENTER:
+ {
+ lYPos = aRect.Top() + (aRect.GetHeight() - aFrmSize.Height()) / 2;
+ break;
+ }
+ case VertOrientation::NONE:
+ {
+ // #i22341#
+ if ( nVRel != RelOrientation::CHAR && nVRel != RelOrientation::TEXT_LINE )
+ lYPos = aRect.Top() + aRelPos.Y();
+ else
+ lYPos = aRect.Top() - aRelPos.Y();
+ break;
+ }
+ default:
+ // #i22341#
+ if ( nVRel != RelOrientation::TEXT_LINE )
+ {
+ lYPos = aRect.Top();
+ }
+ else
+ {
+ lYPos = aRect.Bottom() - aFrmSize.Height() + 1;
+ }
+ break;
+ }
+ }
+ else
+ {
+ switch(nVAlign)
+ {
+ case VertOrientation::CENTER:
+ case VertOrientation::CHAR_CENTER:
+ case VertOrientation::LINE_CENTER:
+ lYPos = aRect.Top() + (aRect.GetHeight() - aFrmSize.Height()) / 2;
+ break;
+
+ case VertOrientation::TOP:
+ case VertOrientation::CHAR_BOTTOM:
+ case VertOrientation::LINE_BOTTOM:
+ lYPos = aRect.Bottom() - aFrmSize.Height() + 1;
+ break;
+
+ default:
+ lYPos = aRect.Top() - aRelPos.Y();
+ break;
+ }
+ }
+
+ tools::Rectangle aFrmRect(Point(lXPos, lYPos), aFrmSize);
+
+ tools::Rectangle* pOuterFrame = &aPage;
+
+ if (nAnchor == RndStdIds::FLY_AT_FLY)
+ pOuterFrame = &aFrameAtFrame;
+
+ if (aFrmRect.Left() < pOuterFrame->Left())
+ aFrmRect.Move(pOuterFrame->Left() - aFrmRect.Left(), 0);
+ if (aFrmRect.Right() > pOuterFrame->Right())
+ aFrmRect.Move(pOuterFrame->Right() - aFrmRect.Right(), 0);
+
+ if (aFrmRect.Top() < pOuterFrame->Top())
+ aFrmRect.Move(0, pOuterFrame->Top() - aFrmRect.Top());
+ if (aFrmRect.Bottom() > pOuterFrame->Bottom())
+ aFrmRect.Move(0, pOuterFrame->Bottom() - aFrmRect.Bottom());
+
+ // Draw Test paragraph
+ const tools::Long nTxtLineHeight = aTextLine.GetHeight();
+ tools::Rectangle aTxt(aTextLine);
+ sal_Int32 nStep;
+ sal_uInt16 nLines;
+
+ if (nAnchor == RndStdIds::FLY_AT_FLY)
+ {
+ aTxt.SetLeft( aFrameAtFrame.Left() + FLYINFLY_BORDER );
+ aTxt.SetRight( aFrameAtFrame.Right() - FLYINFLY_BORDER );
+ aTxt.SetTop( aFrameAtFrame.Top() + FLYINFLY_BORDER );
+ aTxt.SetBottom( aTxt.Top() + aTextLine.GetHeight() - 1 );
+
+ nStep = aTxt.GetHeight() + 2;
+ nLines = static_cast<sal_uInt16>(((aFrameAtFrame.GetHeight() - 2 * FLYINFLY_BORDER) * 2 / 3)
+ / (aTxt.GetHeight() + 2));
+ }
+ else
+ {
+ nStep = aTxt.GetHeight() + 2;
+ nLines = static_cast<sal_uInt16>(aParaPrtArea.GetHeight() / (aTextLine.GetHeight() + 2));
+ }
+
+ if (nAnchor != RndStdIds::FLY_AS_CHAR)
+ {
+ // Simulate text
+ const tools::Long nOldR = aTxt.Right();
+ const tools::Long nOldL = aTxt.Left();
+
+ // #i22341#
+ const bool bIgnoreWrap = nAnchor == RndStdIds::FLY_AT_CHAR &&
+ ( nHRel == RelOrientation::CHAR || nVRel == RelOrientation::CHAR ||
+ nVRel == RelOrientation::TEXT_LINE );
+
+ for (sal_uInt16 i = 0; i < nLines; ++i)
+ {
+ if (i == (nLines - 1))
+ aTxt.SetSize(Size(aTxt.GetWidth() / 2, aTxt.GetHeight()));
+
+ if (aTxt.Overlaps(aFrmRect) && nAnchor != RndStdIds::FLY_AS_CHAR && !bIgnoreWrap)
+ {
+ switch(nWrap)
+ {
+ case WrapTextMode_NONE:
+ aTxt.SetTop( aFrmRect.Bottom() + nTxtLineHeight );
+ aTxt.SetBottom( aTxt.Top() + nTxtLineHeight - 1 );
+ break;
+
+ case WrapTextMode_LEFT:
+ aTxt.SetRight( aFrmRect.Left() );
+ break;
+
+ case WrapTextMode_RIGHT:
+ aTxt.SetLeft( aFrmRect.Right() );
+ break;
+ default: break;
+ }
+ }
+ if (pOuterFrame->Contains(aTxt))
+ DrawRect_Impl(rRenderContext, aTxt, m_aTxtCol, m_aTransColor );
+
+ aTxt.Move(0, nStep);
+ aTxt.SetRight( nOldR );
+ aTxt.SetLeft( nOldL );
+ }
+ aTxt.Move(0, -nStep);
+
+ if (nAnchor != RndStdIds::FLY_AT_FLY && aTxt.Bottom() > aParaPrtArea.Bottom())
+ {
+ // Text has been replaced by frame, so adjust parameters height
+ sal_Int32 nDiff = aTxt.Bottom() - aParaPrtArea.Bottom();
+ aParaPrtArea.AdjustBottom(nDiff );
+ aPara.AdjustBottom(nDiff );
+
+ CalcBoundRect_Impl(rRenderContext, aRect);
+
+ aParaPrtArea.AdjustBottom( -nDiff );
+ aPara.AdjustBottom( -nDiff );
+ }
+ if (nAnchor == RndStdIds::FLY_AT_CHAR && bIgnoreWrap)
+ rRenderContext.DrawText(aAutoCharFrame, OUString('A'));
+ }
+ else
+ {
+ rRenderContext.DrawText(aParaPrtArea, DEMOTEXT);
+ DrawRect_Impl(rRenderContext, aDrawObj, m_aBlankCol, m_aBlankFrameCol );
+ }
+
+ // Draw rectangle on which the frame is aligned:
+ DrawRect_Impl(rRenderContext, aRect, m_aTransColor, m_aAlignColor);
+
+ // Frame View
+ bool bDontFill = (nAnchor == RndStdIds::FLY_AT_CHAR && aFrmRect.Overlaps(aAutoCharFrame)) || bTrans;
+ DrawRect_Impl(rRenderContext, aFrmRect, bDontFill? m_aTransColor : m_aBgCol, m_aFrameColor);
+}
+
+void SwFrameExample::SetRelPos(const Point& rP)
+{
+ aRelPos = rP;
+
+ if (aRelPos.X() > 0)
+ aRelPos.setX( 5 );
+ if (aRelPos.X() < 0)
+ aRelPos.setX( -5 );
+
+ if (aRelPos.Y() > 0)
+ aRelPos.setY( 5 );
+ if (aRelPos.Y() < 0)
+ aRelPos.setY( -5 );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/swframeposstrings.cxx b/svx/source/dialog/swframeposstrings.cxx
new file mode 100644
index 0000000000..29b9243f8c
--- /dev/null
+++ b/svx/source/dialog/swframeposstrings.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 <sal/config.h>
+
+#include <cassert>
+
+#include <svx/swframeposstrings.hxx>
+#include <svx/dialmgr.hxx>
+#include <swframeposstrings.hrc>
+
+OUString SvxSwFramePosString::GetString(StringId eId)
+{
+ static_assert(
+ (SAL_N_ELEMENTS(RID_SVXSW_FRAMEPOSITIONS)
+ == SvxSwFramePosString::STR_MAX),
+ "RID_SVXSW_FRAMEPOSITIONS too small");
+ assert(eId >= 0 && eId < STR_MAX);
+ return SvxResId(RID_SVXSW_FRAMEPOSITIONS[eId]);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/txencbox.cxx b/svx/source/dialog/txencbox.cxx
new file mode 100644
index 0000000000..f6bc5fa729
--- /dev/null
+++ b/svx/source/dialog/txencbox.cxx
@@ -0,0 +1,266 @@
+/* -*- 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 <svx/txencbox.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/txenctab.hxx>
+#if HAVE_FEATURE_DBCONNECTIVITY
+#include <dbcharsethelper.hxx>
+#endif
+#include <unotools/syslocale.hxx>
+#include <rtl/tencinfo.h>
+#include <sal/log.hxx>
+#include <txenctab.hrc>
+
+namespace
+{
+ std::vector<rtl_TextEncoding> FillFromDbTextEncodingMap(bool bExcludeImportSubsets, sal_uInt32 nExcludeInfoFlags)
+ {
+ std::vector<rtl_TextEncoding> aRet;
+#if !HAVE_FEATURE_DBCONNECTIVITY
+ (void)bExcludeImportSubsets;
+ (void)nExcludeInfoFlags;
+#else
+ rtl_TextEncodingInfo aInfo;
+ aInfo.StructSize = sizeof(rtl_TextEncodingInfo);
+ ::std::vector< rtl_TextEncoding > aEncs;
+ sal_Int32 nCount = svxform::charset_helper::getSupportedTextEncodings( aEncs );
+ for ( sal_Int32 j=0; j<nCount; j++ )
+ {
+ bool bInsert = true;
+ rtl_TextEncoding nEnc = rtl_TextEncoding( aEncs[j] );
+ if ( nExcludeInfoFlags )
+ {
+ if ( !rtl_getTextEncodingInfo( nEnc, &aInfo ) )
+ bInsert = false;
+ else
+ {
+ if ( (aInfo.Flags & nExcludeInfoFlags) == 0 )
+ {
+ if ( (nExcludeInfoFlags & RTL_TEXTENCODING_INFO_UNICODE) &&
+ ((nEnc == RTL_TEXTENCODING_UCS2) ||
+ nEnc == RTL_TEXTENCODING_UCS4) )
+ bInsert = false; // InfoFlags don't work for Unicode :-(
+ }
+ else
+ bInsert = false;
+ }
+ }
+ if ( bInsert )
+ {
+ if ( bExcludeImportSubsets )
+ {
+ switch ( nEnc )
+ {
+ // subsets of RTL_TEXTENCODING_GB_18030
+ case RTL_TEXTENCODING_GB_2312 :
+ case RTL_TEXTENCODING_GBK :
+ case RTL_TEXTENCODING_MS_936 :
+ bInsert = false;
+ break;
+ }
+ }
+ // CharsetMap offers a RTL_TEXTENCODING_DONTKNOW for internal use,
+ // makes no sense here and would result in an empty string as list
+ // entry.
+ if ( bInsert && nEnc != RTL_TEXTENCODING_DONTKNOW )
+ aRet.push_back(nEnc);
+ }
+ }
+#endif
+ return aRet;
+ }
+}
+
+void SvxTextEncodingBox::FillFromDbTextEncodingMap(
+ bool bExcludeImportSubsets, sal_uInt32 nExcludeInfoFlags )
+{
+ m_xControl->freeze();
+ auto aEncs = ::FillFromDbTextEncodingMap(bExcludeImportSubsets, nExcludeInfoFlags);
+ for (auto nEnc : aEncs)
+ InsertTextEncoding(nEnc);
+ m_xControl->thaw();
+}
+
+void SvxTextEncodingTreeView::FillFromDbTextEncodingMap(
+ bool bExcludeImportSubsets, sal_uInt32 nExcludeInfoFlags )
+{
+ m_xControl->freeze();
+ auto aEncs = ::FillFromDbTextEncodingMap(bExcludeImportSubsets, nExcludeInfoFlags);
+ for (auto nEnc : aEncs)
+ InsertTextEncoding(nEnc);
+ m_xControl->thaw();
+}
+
+SvxTextEncodingBox::SvxTextEncodingBox(std::unique_ptr<weld::ComboBox> pControl)
+ : m_xControl(std::move(pControl))
+{
+ m_xControl->make_sorted();
+}
+
+SvxTextEncodingTreeView::SvxTextEncodingTreeView(std::unique_ptr<weld::TreeView> pControl)
+ : m_xControl(std::move(pControl))
+{
+ m_xControl->make_sorted();
+}
+
+SvxTextEncodingBox::~SvxTextEncodingBox()
+{
+}
+
+SvxTextEncodingTreeView::~SvxTextEncodingTreeView()
+{
+}
+
+namespace
+{
+ std::vector<int> FillFromTextEncodingTable(bool bExcludeImportSubsets, sal_uInt32 nExcludeInfoFlags)
+ {
+ std::vector<int> aRet;
+
+ rtl_TextEncodingInfo aInfo;
+ aInfo.StructSize = sizeof(rtl_TextEncodingInfo);
+ const sal_uInt32 nCount = SAL_N_ELEMENTS(RID_SVXSTR_TEXTENCODING_TABLE);
+ for (sal_uInt32 j = 0; j < nCount; ++j)
+ {
+ bool bInsert = true;
+ rtl_TextEncoding nEnc = RID_SVXSTR_TEXTENCODING_TABLE[j].second;
+ if ( nExcludeInfoFlags )
+ {
+ if ( !rtl_getTextEncodingInfo( nEnc, &aInfo ) )
+ bInsert = false;
+ else
+ {
+ if ( (aInfo.Flags & nExcludeInfoFlags) == 0 )
+ {
+ if ( (nExcludeInfoFlags & RTL_TEXTENCODING_INFO_UNICODE) &&
+ ((nEnc == RTL_TEXTENCODING_UCS2) ||
+ nEnc == RTL_TEXTENCODING_UCS4) )
+ bInsert = false; // InfoFlags don't work for Unicode :-(
+ }
+ else
+ bInsert = false;
+ }
+ }
+ if ( bExcludeImportSubsets )
+ {
+ switch ( nEnc )
+ {
+ // subsets of RTL_TEXTENCODING_GB_18030
+ case RTL_TEXTENCODING_GB_2312 :
+ case RTL_TEXTENCODING_GBK :
+ case RTL_TEXTENCODING_MS_936 :
+ bInsert = false;
+ break;
+ }
+ }
+ if ( bInsert )
+ aRet.push_back(j);
+ }
+ return aRet;
+ }
+}
+
+void SvxTextEncodingBox::FillFromTextEncodingTable(
+ bool bExcludeImportSubsets, sal_uInt32 nExcludeInfoFlags )
+{
+ std::vector<int> aRet(::FillFromTextEncodingTable(bExcludeImportSubsets, nExcludeInfoFlags));
+ m_xControl->freeze();
+ for (auto j : aRet)
+ {
+ rtl_TextEncoding nEnc = RID_SVXSTR_TEXTENCODING_TABLE[j].second;
+ InsertTextEncoding(nEnc, SvxResId(RID_SVXSTR_TEXTENCODING_TABLE[j].first));
+ }
+ m_xControl->thaw();
+}
+
+void SvxTextEncodingTreeView::FillFromTextEncodingTable(
+ bool bExcludeImportSubsets, sal_uInt32 nExcludeInfoFlags )
+{
+ std::vector<int> aRet(::FillFromTextEncodingTable(bExcludeImportSubsets, nExcludeInfoFlags));
+ m_xControl->freeze();
+ for (auto j : aRet)
+ {
+ rtl_TextEncoding nEnc = RID_SVXSTR_TEXTENCODING_TABLE[j].second;
+ InsertTextEncoding(nEnc, SvxResId(RID_SVXSTR_TEXTENCODING_TABLE[j].first));
+ }
+ m_xControl->thaw();
+}
+
+void SvxTextEncodingBox::InsertTextEncoding( const rtl_TextEncoding nEnc,
+ const OUString& rEntry )
+{
+ m_xControl->append(OUString::number(nEnc), rEntry);
+}
+
+void SvxTextEncodingTreeView::InsertTextEncoding( const rtl_TextEncoding nEnc,
+ const OUString& rEntry )
+{
+ m_xControl->append(OUString::number(nEnc), rEntry);
+}
+
+void SvxTextEncodingBox::InsertTextEncoding( const rtl_TextEncoding nEnc )
+{
+ const OUString& rEntry = SvxTextEncodingTable::GetTextString(nEnc);
+ if (!rEntry.isEmpty())
+ InsertTextEncoding( nEnc, rEntry );
+ else
+ SAL_WARN( "svx.dialog", "SvxTextEncodingBox::InsertTextEncoding: no resource string for text encoding: " << static_cast<sal_Int32>( nEnc ) );
+}
+
+void SvxTextEncodingTreeView::InsertTextEncoding( const rtl_TextEncoding nEnc )
+{
+ const OUString& rEntry = SvxTextEncodingTable::GetTextString(nEnc);
+ if (!rEntry.isEmpty())
+ InsertTextEncoding( nEnc, rEntry );
+ else
+ SAL_WARN( "svx.dialog", "SvxTextEncodingTreeView::InsertTextEncoding: no resource string for text encoding: " << static_cast<sal_Int32>( nEnc ) );
+}
+
+rtl_TextEncoding SvxTextEncodingBox::GetSelectTextEncoding() const
+{
+ OUString sId(m_xControl->get_active_id());
+ if (!sId.isEmpty())
+ return rtl_TextEncoding(sId.toInt32());
+ else
+ return RTL_TEXTENCODING_DONTKNOW;
+}
+
+rtl_TextEncoding SvxTextEncodingTreeView::GetSelectTextEncoding() const
+{
+ OUString sId(m_xControl->get_selected_id());
+ if (!sId.isEmpty())
+ return rtl_TextEncoding(sId.toInt32());
+ else
+ return RTL_TEXTENCODING_DONTKNOW;
+}
+
+void SvxTextEncodingBox::SelectTextEncoding( const rtl_TextEncoding nEnc )
+{
+ m_xControl->set_active_id(OUString::number(nEnc));
+}
+
+void SvxTextEncodingTreeView::SelectTextEncoding( const rtl_TextEncoding nEnc )
+{
+ m_xControl->select_id(OUString::number(nEnc));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/txenctab.cxx b/svx/source/dialog/txenctab.cxx
new file mode 100644
index 0000000000..791b8f735f
--- /dev/null
+++ b/svx/source/dialog/txenctab.cxx
@@ -0,0 +1,49 @@
+/* -*- 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 <svx/dialmgr.hxx>
+#include <svx/txenctab.hxx>
+#include <txenctab.hrc>
+
+OUString SvxTextEncodingTable::GetTextString(const rtl_TextEncoding nEnc)
+{
+ const size_t nCount = SAL_N_ELEMENTS(RID_SVXSTR_TEXTENCODING_TABLE);
+
+ for (size_t i = 0; i < nCount; ++i)
+ {
+ if (RID_SVXSTR_TEXTENCODING_TABLE[i].second == nEnc)
+ return SvxResId(RID_SVXSTR_TEXTENCODING_TABLE[i].first);
+ }
+
+ return OUString();
+}
+
+rtl_TextEncoding SvxTextEncodingTable::GetTextEncoding(const OUString& rStr)
+{
+ const size_t nCount = SAL_N_ELEMENTS(RID_SVXSTR_TEXTENCODING_TABLE);
+
+ for (size_t i = 0; i < nCount; ++i)
+ {
+ if (SvxResId(RID_SVXSTR_TEXTENCODING_TABLE[i].first).equals(rStr))
+ return RID_SVXSTR_TEXTENCODING_TABLE[i].second;
+ }
+ return RTL_TEXTENCODING_DONTKNOW;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/weldeditview.cxx b/svx/source/dialog/weldeditview.cxx
new file mode 100644
index 0000000000..46ab95eb9a
--- /dev/null
+++ b/svx/source/dialog/weldeditview.cxx
@@ -0,0 +1,1719 @@
+/* -*- 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_wasm_strip.h>
+
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/accessibility/XAccessible.hpp>
+#include <com/sun/star/accessibility/XAccessibleComponent.hpp>
+#include <com/sun/star/accessibility/XAccessibleContext.hpp>
+#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <drawinglayer/processor2d/baseprocessor2d.hxx>
+#include <drawinglayer/processor2d/processor2dtools.hxx>
+#include <comphelper/lok.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/outliner.hxx>
+#include <editeng/unoedhlp.hxx>
+#include <editeng/unoedsrc.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <osl/diagnose.h>
+#include <svl/itempool.hxx>
+#include <svl/itemset.hxx>
+#include <sal/log.hxx>
+#include <svx/sdr/overlay/overlayselection.hxx>
+#include <svtools/optionsdrawinglayer.hxx>
+#include <svx/AccessibleTextHelper.hxx>
+#include <svx/weldeditview.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <vcl/canvastools.hxx>
+#include <vcl/cursor.hxx>
+#include <vcl/event.hxx>
+#include <vcl/ptrstyle.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/window.hxx>
+#include <vcl/uitest/uiobject.hxx>
+
+void WeldEditView::SetText(const OUString& rStr) { GetEditEngine()->SetText(rStr); }
+
+OUString WeldEditView::GetText() const { return GetEditEngine()->GetText(); }
+
+void WeldEditView::SetModifyHdl(const Link<LinkParamNone*, void>& rLink)
+{
+ GetEditEngine()->SetModifyHdl(rLink);
+}
+
+EditView* WeldEditView::GetEditView() const { return m_xEditView.get(); }
+
+EditEngine* WeldEditView::GetEditEngine() const { return m_xEditEngine.get(); }
+
+bool WeldEditView::HasSelection() const
+{
+ EditView* pEditView = GetEditView();
+ return pEditView && pEditView->HasSelection();
+}
+
+void WeldEditView::Delete()
+{
+ if (EditView* pEditView = GetEditView())
+ pEditView->DeleteSelected();
+}
+
+void WeldEditView::Cut()
+{
+ if (EditView* pEditView = GetEditView())
+ pEditView->Cut();
+}
+
+void WeldEditView::Copy()
+{
+ if (EditView* pEditView = GetEditView())
+ pEditView->Copy();
+}
+
+void WeldEditView::Paste()
+{
+ if (EditView* pEditView = GetEditView())
+ pEditView->Paste();
+}
+
+WeldEditView::WeldEditView()
+ : m_bAcceptsTab(false)
+{
+}
+
+// tdf#127033 want to use UI font so override makeEditEngine to enable that
+void WeldEditView::makeEditEngine()
+{
+ rtl::Reference<SfxItemPool> pItemPool = EditEngine::CreatePool();
+
+ vcl::Font aAppFont(Application::GetSettings().GetStyleSettings().GetAppFont());
+
+ pItemPool->SetPoolDefaultItem(SvxFontItem(aAppFont.GetFamilyType(), aAppFont.GetFamilyName(),
+ "", PITCH_DONTKNOW, RTL_TEXTENCODING_DONTKNOW,
+ EE_CHAR_FONTINFO));
+ pItemPool->SetPoolDefaultItem(SvxFontItem(aAppFont.GetFamilyType(), aAppFont.GetFamilyName(),
+ "", PITCH_DONTKNOW, RTL_TEXTENCODING_DONTKNOW,
+ EE_CHAR_FONTINFO_CJK));
+ pItemPool->SetPoolDefaultItem(SvxFontItem(aAppFont.GetFamilyType(), aAppFont.GetFamilyName(),
+ "", PITCH_DONTKNOW, RTL_TEXTENCODING_DONTKNOW,
+ EE_CHAR_FONTINFO_CTL));
+
+ pItemPool->SetPoolDefaultItem(
+ SvxFontHeightItem(aAppFont.GetFontHeight() * 20, 100, EE_CHAR_FONTHEIGHT));
+ pItemPool->SetPoolDefaultItem(
+ SvxFontHeightItem(aAppFont.GetFontHeight() * 20, 100, EE_CHAR_FONTHEIGHT_CJK));
+ pItemPool->SetPoolDefaultItem(
+ SvxFontHeightItem(aAppFont.GetFontHeight() * 20, 100, EE_CHAR_FONTHEIGHT_CTL));
+
+ m_xEditEngine.reset(new EditEngine(pItemPool.get()));
+}
+
+void WeldEditView::Resize()
+{
+ if (EditView* pEditView = GetEditView())
+ {
+ OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
+ Size aOutputSize(rDevice.PixelToLogic(GetOutputSizePixel()));
+ // Resizes the edit engine to adjust to the size of the output area
+ pEditView->SetOutputArea(tools::Rectangle(Point(0, 0), aOutputSize));
+ GetEditEngine()->SetPaperSize(aOutputSize);
+ pEditView->ShowCursor();
+
+ const tools::Long nMaxVisAreaStart
+ = pEditView->GetEditEngine()->GetTextHeight() - aOutputSize.Height();
+ tools::Rectangle aVisArea(pEditView->GetVisArea());
+ if (aVisArea.Top() > nMaxVisAreaStart)
+ {
+ aVisArea.SetTop(std::max<tools::Long>(nMaxVisAreaStart, 0));
+ aVisArea.SetSize(aOutputSize);
+ pEditView->SetVisArea(aVisArea);
+ pEditView->ShowCursor();
+ }
+
+ EditViewScrollStateChange();
+ }
+ weld::CustomWidgetController::Resize();
+}
+
+void WeldEditView::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
+{
+ DoPaint(rRenderContext, rRect);
+}
+
+void WeldEditView::DoPaint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
+{
+ rRenderContext.Push(vcl::PushFlags::ALL);
+ rRenderContext.SetClipRegion();
+
+ std::vector<tools::Rectangle> aLogicRects;
+
+ if (EditView* pEditView = GetEditView())
+ {
+ pEditView->Paint(comphelper::LibreOfficeKit::isActive() ? rRenderContext.PixelToLogic(rRect)
+ : rRect,
+ &rRenderContext);
+
+ if (HasFocus())
+ {
+ pEditView->ShowCursor(false);
+ vcl::Cursor* pCursor = pEditView->GetCursor();
+ pCursor->DrawToDevice(rRenderContext);
+ }
+
+ // get logic selection
+ pEditView->GetSelectionRectangles(aLogicRects);
+ }
+
+ if (!aLogicRects.empty())
+ {
+ std::vector<basegfx::B2DRange> aLogicRanges;
+ aLogicRanges.reserve(aLogicRects.size());
+
+ tools::Long nMinX(LONG_MAX), nMaxX(0), nMinY(LONG_MAX), nMaxY(0);
+ for (const auto& aRect : aLogicRects)
+ {
+ nMinX = std::min(nMinX, aRect.Left());
+ nMinY = std::min(nMinY, aRect.Top());
+ nMaxX = std::max(nMaxX, aRect.Right());
+ nMaxY = std::max(nMaxY, aRect.Bottom());
+ }
+
+ const Size aLogicPixel(rRenderContext.PixelToLogic(Size(1, 1)));
+ for (const auto& aRect : aLogicRects)
+ {
+ // Extend each range by one pixel so multiple lines touch each
+ // other if adjacent, so the whole set is drawn with a single
+ // border around the lot. But keep the selection within the
+ // original max extents.
+ auto nTop = aRect.Top();
+ if (nTop > nMinY)
+ nTop -= aLogicPixel.Height();
+ auto nBottom = aRect.Bottom();
+ if (nBottom < nMaxY)
+ nBottom += aLogicPixel.Height();
+ auto nLeft = aRect.Left();
+ if (nLeft > nMinX)
+ nLeft -= aLogicPixel.Width();
+ auto nRight = aRect.Right();
+ if (nRight < nMaxX)
+ nRight += aLogicPixel.Width();
+
+ aLogicRanges.emplace_back(nLeft, nTop, nRight, nBottom);
+ }
+
+ // get the system's highlight color
+ const Color aHighlight(SvtOptionsDrawinglayer::getHilightColor());
+
+ sdr::overlay::OverlaySelection aCursorOverlay(sdr::overlay::OverlayType::Transparent,
+ aHighlight, std::move(aLogicRanges), true);
+
+ drawinglayer::geometry::ViewInformation2D aViewInformation2D;
+ aViewInformation2D.setViewTransformation(rRenderContext.GetViewTransformation());
+ aViewInformation2D.setViewport(vcl::unotools::b2DRectangleFromRectangle(rRect));
+
+ std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> xProcessor(
+ drawinglayer::processor2d::createProcessor2DFromOutputDevice(rRenderContext,
+ aViewInformation2D));
+
+ xProcessor->process(aCursorOverlay.getOverlayObjectPrimitive2DSequence());
+ }
+
+ rRenderContext.Pop();
+}
+
+bool WeldEditView::MouseMove(const MouseEvent& rMEvt)
+{
+ EditView* pEditView = GetEditView();
+ return pEditView && pEditView->MouseMove(rMEvt);
+}
+
+bool WeldEditView::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ if (!IsMouseCaptured())
+ CaptureMouse();
+
+ if (!HasFocus() && CanFocus())
+ GrabFocus();
+
+ EditView* pEditView = GetEditView();
+ return pEditView && pEditView->MouseButtonDown(rMEvt);
+}
+
+bool WeldEditView::MouseButtonUp(const MouseEvent& rMEvt)
+{
+ if (IsMouseCaptured())
+ ReleaseMouse();
+ EditView* pEditView = GetEditView();
+ return pEditView && pEditView->MouseButtonUp(rMEvt);
+}
+
+bool WeldEditView::KeyInput(const KeyEvent& rKEvt)
+{
+ EditView* pEditView = GetEditView();
+
+ sal_uInt16 nKey = rKEvt.GetKeyCode().GetCode();
+
+ if (nKey == KEY_TAB && !GetAcceptsTab())
+ {
+ return false;
+ }
+ else if (pEditView && !pEditView->PostKeyEvent(rKEvt))
+ {
+ if (rKEvt.GetKeyCode().IsMod1() && !rKEvt.GetKeyCode().IsMod2())
+ {
+ if (nKey == KEY_A)
+ {
+ EditEngine* pEditEngine = GetEditEngine();
+ sal_Int32 nPar = pEditEngine->GetParagraphCount();
+ if (nPar)
+ {
+ sal_Int32 nLen = pEditEngine->GetTextLen(nPar - 1);
+ pEditView->SetSelection(ESelection(0, 0, nPar - 1, nLen));
+ }
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ return true;
+}
+
+bool WeldEditView::Command(const CommandEvent& rCEvt)
+{
+ EditView* pEditView = GetEditView();
+ if (!pEditView)
+ return false;
+ return pEditView->Command(rCEvt);
+}
+
+Point WeldEditView::EditViewPointerPosPixel() const
+{
+ return GetDrawingArea()->get_pointer_position();
+}
+
+class WeldEditAccessible;
+
+namespace
+{
+class WeldViewForwarder : public SvxViewForwarder
+{
+ WeldEditAccessible& m_rEditAcc;
+
+ WeldViewForwarder(const WeldViewForwarder&) = delete;
+ WeldViewForwarder& operator=(const WeldViewForwarder&) = delete;
+
+public:
+ explicit WeldViewForwarder(WeldEditAccessible& rAcc)
+ : m_rEditAcc(rAcc)
+ {
+ }
+
+ virtual bool IsValid() const override;
+ virtual Point LogicToPixel(const Point& rPoint, const MapMode& rMapMode) const override;
+ virtual Point PixelToLogic(const Point& rPoint, const MapMode& rMapMode) const override;
+};
+}
+
+class WeldEditAccessible;
+
+namespace
+{
+class WeldEditSource;
+
+/* analog to SvxEditEngineForwarder */
+class WeldTextForwarder : public SvxTextForwarder
+{
+ WeldEditAccessible& m_rEditAcc;
+ WeldEditSource& m_rEditSource;
+
+ DECL_LINK(NotifyHdl, EENotify&, void);
+
+ WeldTextForwarder(const WeldTextForwarder&) = delete;
+ WeldTextForwarder& operator=(const WeldTextForwarder&) = delete;
+
+public:
+ WeldTextForwarder(WeldEditAccessible& rAcc, WeldEditSource& rSource);
+ virtual ~WeldTextForwarder() override;
+
+ virtual sal_Int32 GetParagraphCount() const override;
+ virtual sal_Int32 GetTextLen(sal_Int32 nParagraph) const override;
+ virtual OUString GetText(const ESelection& rSel) const override;
+ virtual SfxItemSet GetAttribs(const ESelection& rSel, EditEngineAttribs nOnlyHardAttrib
+ = EditEngineAttribs::All) const override;
+ virtual SfxItemSet GetParaAttribs(sal_Int32 nPara) const override;
+ virtual void SetParaAttribs(sal_Int32 nPara, const SfxItemSet& rSet) override;
+ virtual void RemoveAttribs(const ESelection& rSelection) override;
+ virtual void GetPortions(sal_Int32 nPara, std::vector<sal_Int32>& rList) const override;
+
+ virtual OUString GetStyleSheet(sal_Int32 nPara) const override;
+ virtual void SetStyleSheet(sal_Int32 nPara, const OUString& rStyleName) override;
+
+ virtual SfxItemState GetItemState(const ESelection& rSel, sal_uInt16 nWhich) const override;
+ virtual SfxItemState GetItemState(sal_Int32 nPara, sal_uInt16 nWhich) const override;
+
+ virtual void QuickInsertText(const OUString& rText, const ESelection& rSel) override;
+ virtual void QuickInsertField(const SvxFieldItem& rFld, const ESelection& rSel) override;
+ virtual void QuickSetAttribs(const SfxItemSet& rSet, const ESelection& rSel) override;
+ virtual void QuickInsertLineBreak(const ESelection& rSel) override;
+
+ virtual SfxItemPool* GetPool() const override;
+
+ virtual OUString CalcFieldValue(const SvxFieldItem& rField, sal_Int32 nPara, sal_Int32 nPos,
+ std::optional<Color>& rpTxtColor,
+ std::optional<Color>& rpFldColor,
+ std::optional<FontLineStyle>& rpFldLineStyle) override;
+ virtual void FieldClicked(const SvxFieldItem&) override;
+ virtual bool IsValid() const override;
+
+ virtual LanguageType GetLanguage(sal_Int32, sal_Int32) const override;
+ virtual sal_Int32 GetFieldCount(sal_Int32 nPara) const override;
+ virtual EFieldInfo GetFieldInfo(sal_Int32 nPara, sal_uInt16 nField) const override;
+ virtual EBulletInfo GetBulletInfo(sal_Int32 nPara) const override;
+ virtual tools::Rectangle GetCharBounds(sal_Int32 nPara, sal_Int32 nIndex) const override;
+ virtual tools::Rectangle GetParaBounds(sal_Int32 nPara) const override;
+ virtual MapMode GetMapMode() const override;
+ virtual OutputDevice* GetRefDevice() const override;
+ virtual bool GetIndexAtPoint(const Point&, sal_Int32& nPara, sal_Int32& nIndex) const override;
+ virtual bool GetWordIndices(sal_Int32 nPara, sal_Int32 nIndex, sal_Int32& nStart,
+ sal_Int32& nEnd) const override;
+ virtual bool GetAttributeRun(sal_Int32& nStartIndex, sal_Int32& nEndIndex, sal_Int32 nPara,
+ sal_Int32 nIndex, bool bInCell = false) const override;
+ virtual sal_Int32 GetLineCount(sal_Int32 nPara) const override;
+ virtual sal_Int32 GetLineLen(sal_Int32 nPara, sal_Int32 nLine) const override;
+ virtual void GetLineBoundaries(/*out*/ sal_Int32& rStart, /*out*/ sal_Int32& rEnd,
+ sal_Int32 nParagraph, sal_Int32 nLine) const override;
+ virtual sal_Int32 GetLineNumberAtIndex(sal_Int32 nPara, sal_Int32 nLine) const override;
+ virtual bool Delete(const ESelection&) override;
+ virtual bool InsertText(const OUString&, const ESelection&) override;
+ virtual bool QuickFormatDoc(bool bFull = false) override;
+
+ virtual sal_Int16 GetDepth(sal_Int32 nPara) const override;
+ virtual bool SetDepth(sal_Int32 nPara, sal_Int16 nNewDepth) override;
+
+ virtual const SfxItemSet* GetEmptyItemSetPtr() override;
+ // implementation functions for XParagraphAppend and XTextPortionAppend
+ virtual void AppendParagraph() override;
+ virtual sal_Int32 AppendTextPortion(sal_Int32 nPara, const OUString& rText,
+ const SfxItemSet& rSet) override;
+
+ virtual void CopyText(const SvxTextForwarder& rSource) override;
+};
+
+/* analog to SvxEditEngineViewForwarder */
+class WeldEditViewForwarder : public SvxEditViewForwarder
+{
+ WeldEditAccessible& m_rEditAcc;
+
+ WeldEditViewForwarder(const WeldEditViewForwarder&) = delete;
+ WeldEditViewForwarder& operator=(const WeldEditViewForwarder&) = delete;
+
+public:
+ explicit WeldEditViewForwarder(WeldEditAccessible& rAcc);
+
+ virtual bool IsValid() const override;
+
+ virtual Point LogicToPixel(const Point& rPoint, const MapMode& rMapMode) const override;
+ virtual Point PixelToLogic(const Point& rPoint, const MapMode& rMapMode) const override;
+
+ virtual bool GetSelection(ESelection& rSelection) const override;
+ virtual bool SetSelection(const ESelection& rSelection) override;
+ virtual bool Copy() override;
+ virtual bool Cut() override;
+ virtual bool Paste() override;
+};
+
+class WeldEditSource : public SvxEditSource
+{
+ SfxBroadcaster m_aBroadCaster;
+ WeldViewForwarder m_aViewFwd;
+ WeldTextForwarder m_aTextFwd;
+ WeldEditViewForwarder m_aEditViewFwd;
+ WeldEditAccessible& m_rEditAcc;
+
+ WeldEditSource(const WeldEditSource& rSrc)
+ : SvxEditSource()
+ , m_aViewFwd(rSrc.m_rEditAcc)
+ , m_aTextFwd(rSrc.m_rEditAcc, *this)
+ , m_aEditViewFwd(rSrc.m_rEditAcc)
+ , m_rEditAcc(rSrc.m_rEditAcc)
+ {
+ }
+
+ WeldEditSource& operator=(const WeldEditSource&) = delete;
+
+public:
+ WeldEditSource(WeldEditAccessible& rAcc)
+ : m_aViewFwd(rAcc)
+ , m_aTextFwd(rAcc, *this)
+ , m_aEditViewFwd(rAcc)
+ , m_rEditAcc(rAcc)
+ {
+ }
+
+ virtual std::unique_ptr<SvxEditSource> Clone() const override
+ {
+ return std::unique_ptr<SvxEditSource>(new WeldEditSource(*this));
+ }
+
+ virtual SvxTextForwarder* GetTextForwarder() override { return &m_aTextFwd; }
+
+ virtual SvxViewForwarder* GetViewForwarder() override { return &m_aViewFwd; }
+
+ virtual SvxEditViewForwarder* GetEditViewForwarder(bool /*bCreate*/) override
+ {
+ return &m_aEditViewFwd;
+ }
+
+ virtual void UpdateData() override
+ {
+ // would possibly only by needed if the XText interface is implemented
+ // and its text needs to be updated.
+ }
+ virtual SfxBroadcaster& GetBroadcaster() const override
+ {
+ return const_cast<WeldEditSource*>(this)->m_aBroadCaster;
+ }
+};
+}
+
+typedef cppu::WeakImplHelper<css::lang::XServiceInfo, css::accessibility::XAccessible,
+ css::accessibility::XAccessibleComponent,
+ css::accessibility::XAccessibleContext,
+ css::accessibility::XAccessibleEventBroadcaster>
+ WeldEditAccessibleBaseClass;
+
+class WeldEditAccessible : public WeldEditAccessibleBaseClass
+{
+ weld::CustomWidgetController* m_pController;
+ EditEngine* m_pEditEngine;
+ EditView* m_pEditView;
+ std::unique_ptr<::accessibility::AccessibleTextHelper> m_xTextHelper;
+
+public:
+ WeldEditAccessible(weld::CustomWidgetController* pController)
+ : m_pController(pController)
+ , m_pEditEngine(nullptr)
+ , m_pEditView(nullptr)
+ {
+ }
+
+ ::accessibility::AccessibleTextHelper* GetTextHelper() { return m_xTextHelper.get(); }
+
+ void Init(EditEngine* pEditEngine, EditView* pEditView)
+ {
+ m_pEditEngine = pEditEngine;
+ m_pEditView = pEditView;
+ m_xTextHelper.reset(
+ new ::accessibility::AccessibleTextHelper(std::make_unique<WeldEditSource>(*this)));
+ m_xTextHelper->SetEventSource(this);
+ }
+
+ EditEngine* GetEditEngine() { return m_pEditEngine; }
+ EditView* GetEditView() { return m_pEditView; }
+
+ void ClearWin()
+ {
+ // remove handler before current object gets destroyed
+ // (avoid handler being called for already dead object)
+ m_pEditEngine->SetNotifyHdl(Link<EENotify&, void>());
+
+ m_pEditEngine = nullptr;
+ m_pEditView = nullptr;
+ m_pController = nullptr; // implicitly results in AccessibleStateType::DEFUNC set
+
+ //! make TextHelper implicitly release C++ references to some core objects
+ m_xTextHelper->SetEditSource(::std::unique_ptr<SvxEditSource>());
+
+ //! make TextHelper release references
+ //! (e.g. the one set by the 'SetEventSource' call)
+ m_xTextHelper->Dispose();
+ m_xTextHelper.reset();
+ }
+
+ // XAccessible
+ virtual css::uno::Reference<css::accessibility::XAccessibleContext>
+ SAL_CALL getAccessibleContext() override
+ {
+ return this;
+ }
+
+ // XAccessibleComponent
+ virtual sal_Bool SAL_CALL containsPoint(const css::awt::Point& rPoint) override
+ {
+ //! the arguments coordinates are relative to the current window !
+ //! Thus the top left-point is (0, 0)
+ SolarMutexGuard aGuard;
+ if (!m_pController)
+ throw css::uno::RuntimeException();
+
+ Size aSz(m_pController->GetOutputSizePixel());
+ return rPoint.X >= 0 && rPoint.Y >= 0 && rPoint.X < aSz.Width() && rPoint.Y < aSz.Height();
+ }
+
+ virtual css::uno::Reference<css::accessibility::XAccessible>
+ SAL_CALL getAccessibleAtPoint(const css::awt::Point& rPoint) override
+ {
+ SolarMutexGuard aGuard;
+ if (!m_xTextHelper)
+ throw css::uno::RuntimeException();
+
+ return m_xTextHelper->GetAt(rPoint);
+ }
+
+ virtual css::awt::Rectangle SAL_CALL getBounds() override
+ {
+ SolarMutexGuard aGuard;
+ if (!m_pController)
+ throw css::uno::RuntimeException();
+
+ const Point aOutPos;
+ const Size aOutSize(m_pController->GetOutputSizePixel());
+ css::awt::Rectangle aRet;
+
+ aRet.X = aOutPos.X();
+ aRet.Y = aOutPos.Y();
+ aRet.Width = aOutSize.Width();
+ aRet.Height = aOutSize.Height();
+
+ return aRet;
+ }
+
+ virtual css::awt::Point SAL_CALL getLocation() override
+ {
+ SolarMutexGuard aGuard;
+ if (!m_pController)
+ throw css::uno::RuntimeException();
+
+ const css::awt::Rectangle aRect(getBounds());
+ css::awt::Point aRet;
+
+ aRet.X = aRect.X;
+ aRet.Y = aRect.Y;
+
+ return aRet;
+ }
+
+ virtual css::awt::Point SAL_CALL getLocationOnScreen() override
+ {
+ SolarMutexGuard aGuard;
+ if (!m_pController)
+ throw css::uno::RuntimeException();
+
+ css::awt::Point aScreenLoc(0, 0);
+
+ if (weld::DrawingArea* pDrawingArea = m_pController->GetDrawingArea())
+ {
+ AbsoluteScreenPixelPoint aPos = pDrawingArea->get_accessible_location_on_screen();
+ aScreenLoc.X = aPos.X();
+ aScreenLoc.Y = aPos.Y();
+ }
+
+ return aScreenLoc;
+ }
+
+ virtual css::awt::Size SAL_CALL getSize() override
+ {
+ SolarMutexGuard aGuard;
+ if (!m_pController)
+ throw css::uno::RuntimeException();
+
+ Size aSz(m_pController->GetOutputSizePixel());
+ return css::awt::Size(aSz.Width(), aSz.Height());
+ }
+
+ virtual void SAL_CALL grabFocus() override { m_pController->GrabFocus(); }
+
+ virtual sal_Int32 SAL_CALL getForeground() override
+ {
+ SolarMutexGuard aGuard;
+ if (!m_pController)
+ throw css::uno::RuntimeException();
+
+ Color nCol = m_pEditEngine->GetAutoColor();
+ return static_cast<sal_Int32>(nCol);
+ }
+
+ virtual sal_Int32 SAL_CALL getBackground() override
+ {
+ SolarMutexGuard aGuard;
+ if (!m_pController)
+ throw css::uno::RuntimeException();
+
+ Color nCol = m_pEditEngine->GetBackgroundColor();
+ return static_cast<sal_Int32>(nCol);
+ }
+
+ // XAccessibleContext
+ virtual sal_Int64 SAL_CALL getAccessibleChildCount() override
+ {
+ if (m_xTextHelper)
+ return m_xTextHelper->GetChildCount();
+ return 0;
+ }
+
+ virtual css::uno::Reference<css::accessibility::XAccessible>
+ SAL_CALL getAccessibleChild(sal_Int64 i) override
+ {
+ if (m_xTextHelper)
+ return m_xTextHelper->GetChild(i);
+ throw css::lang::IndexOutOfBoundsException(); // there is no child...
+ }
+
+ virtual css::uno::Reference<css::accessibility::XAccessible>
+ SAL_CALL getAccessibleParent() override
+ {
+ SolarMutexGuard aGuard;
+ if (!m_pController)
+ throw css::uno::RuntimeException();
+
+ return m_pController->GetDrawingArea()->get_accessible_parent();
+ }
+
+ virtual sal_Int64 SAL_CALL getAccessibleIndexInParent() override
+ {
+ SolarMutexGuard aGuard;
+ if (!m_pController)
+ throw css::uno::RuntimeException();
+
+ // -1 for child not found/no parent (according to specification)
+ sal_Int64 nRet = -1;
+
+ css::uno::Reference<css::accessibility::XAccessible> xParent(getAccessibleParent());
+ if (!xParent)
+ return nRet;
+
+ try
+ {
+ css::uno::Reference<css::accessibility::XAccessibleContext> xParentContext(
+ xParent->getAccessibleContext());
+
+ // iterate over parent's children and search for this object
+ if (xParentContext.is())
+ {
+ sal_Int64 nChildCount = xParentContext->getAccessibleChildCount();
+ for (sal_Int64 nChild = 0; (nChild < nChildCount) && (-1 == nRet); ++nChild)
+ {
+ css::uno::Reference<css::accessibility::XAccessible> xChild(
+ xParentContext->getAccessibleChild(nChild));
+ if (xChild.get() == this)
+ nRet = nChild;
+ }
+ }
+ }
+ catch (const css::uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("svx", "WeldEditAccessible::getAccessibleIndexInParent");
+ }
+
+ return nRet;
+ }
+
+ virtual sal_Int16 SAL_CALL getAccessibleRole() override
+ {
+ return css::accessibility::AccessibleRole::TEXT_FRAME;
+ }
+
+ virtual OUString SAL_CALL getAccessibleDescription() override
+ {
+ SolarMutexGuard aGuard;
+
+ OUString aRet;
+
+ if (m_pController)
+ {
+ aRet = m_pController->GetAccessibleDescription();
+ }
+
+ return aRet;
+ }
+
+ virtual OUString SAL_CALL getAccessibleName() override
+ {
+ SolarMutexGuard aGuard;
+
+ OUString aRet;
+
+ if (m_pController)
+ {
+ aRet = m_pController->GetAccessibleName();
+ }
+
+ return aRet;
+ }
+
+ virtual css::uno::Reference<css::accessibility::XAccessibleRelationSet>
+ SAL_CALL getAccessibleRelationSet() override
+ {
+ SolarMutexGuard aGuard;
+ if (!m_pController)
+ throw css::uno::RuntimeException();
+
+ return m_pController->GetDrawingArea()->get_accessible_relation_set();
+ }
+
+ virtual sal_Int64 SAL_CALL getAccessibleStateSet() override
+ {
+ SolarMutexGuard aGuard;
+ sal_Int64 nStateSet = 0;
+
+ if (!m_pController || !m_xTextHelper)
+ nStateSet |= css::accessibility::AccessibleStateType::DEFUNC;
+ else
+ {
+ nStateSet |= css::accessibility::AccessibleStateType::MULTI_LINE;
+ nStateSet |= css::accessibility::AccessibleStateType::ENABLED;
+ nStateSet |= css::accessibility::AccessibleStateType::EDITABLE;
+ nStateSet |= css::accessibility::AccessibleStateType::FOCUSABLE;
+ nStateSet |= css::accessibility::AccessibleStateType::SELECTABLE;
+ if (m_pController->HasFocus())
+ nStateSet |= css::accessibility::AccessibleStateType::FOCUSED;
+ if (m_pController->IsActive())
+ nStateSet |= css::accessibility::AccessibleStateType::ACTIVE;
+ if (m_pController->IsVisible())
+ nStateSet |= css::accessibility::AccessibleStateType::SHOWING;
+ if (m_pController->IsReallyVisible())
+ nStateSet |= css::accessibility::AccessibleStateType::VISIBLE;
+ if (COL_TRANSPARENT != m_pEditEngine->GetBackgroundColor())
+ nStateSet |= css::accessibility::AccessibleStateType::OPAQUE;
+ }
+
+ return nStateSet;
+ }
+
+ virtual css::lang::Locale SAL_CALL getLocale() override
+ {
+ SolarMutexGuard aGuard;
+ return LanguageTag(m_pEditEngine->GetDefaultLanguage()).getLocale();
+ }
+
+ // XAccessibleEventBroadcaster
+ virtual void SAL_CALL addAccessibleEventListener(
+ const css::uno::Reference<css::accessibility::XAccessibleEventListener>& rListener) override
+ {
+ if (!m_xTextHelper) // not disposing (about to destroy view shell)
+ return;
+ m_xTextHelper->AddEventListener(rListener);
+ }
+
+ virtual void SAL_CALL removeAccessibleEventListener(
+ const css::uno::Reference<css::accessibility::XAccessibleEventListener>& rListener) override
+ {
+ if (!m_xTextHelper) // not disposing (about to destroy view shell)
+ return;
+ m_xTextHelper->RemoveEventListener(rListener);
+ }
+
+ virtual OUString SAL_CALL getImplementationName() override { return "WeldEditAccessible"; }
+
+ virtual sal_Bool SAL_CALL supportsService(const OUString& rServiceName) override
+ {
+ return cppu::supportsService(this, rServiceName);
+ }
+
+ virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override
+ {
+ return { "css::accessibility::Accessible", "css::accessibility::AccessibleComponent",
+ "css::accessibility::AccessibleContext" };
+ }
+};
+
+css::uno::Reference<css::accessibility::XAccessible> WeldEditView::CreateAccessible()
+{
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ if (!m_xAccessible.is())
+ m_xAccessible.set(new WeldEditAccessible(this));
+#endif
+ return m_xAccessible;
+}
+
+WeldEditView::~WeldEditView()
+{
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ if (m_xAccessible.is())
+ {
+ m_xAccessible->ClearWin(); // make Accessible nonfunctional
+ m_xAccessible.clear();
+ }
+#endif
+}
+
+bool WeldViewForwarder::IsValid() const { return m_rEditAcc.GetEditView() != nullptr; }
+
+Point WeldViewForwarder::LogicToPixel(const Point& rPoint, const MapMode& rMapMode) const
+{
+ EditView* pEditView = m_rEditAcc.GetEditView();
+ if (!pEditView)
+ return Point();
+ OutputDevice& rOutDev = pEditView->GetOutputDevice();
+ MapMode aMapMode(rOutDev.GetMapMode());
+ Point aPoint(OutputDevice::LogicToLogic(rPoint, rMapMode, MapMode(aMapMode.GetMapUnit())));
+ aMapMode.SetOrigin(Point());
+ return rOutDev.LogicToPixel(aPoint, aMapMode);
+}
+
+Point WeldViewForwarder::PixelToLogic(const Point& rPoint, const MapMode& rMapMode) const
+{
+ EditView* pEditView = m_rEditAcc.GetEditView();
+ if (!pEditView)
+ return Point();
+ OutputDevice& rOutDev = pEditView->GetOutputDevice();
+ MapMode aMapMode(rOutDev.GetMapMode());
+ aMapMode.SetOrigin(Point());
+ Point aPoint(rOutDev.PixelToLogic(rPoint, aMapMode));
+ return OutputDevice::LogicToLogic(aPoint, MapMode(aMapMode.GetMapUnit()), rMapMode);
+}
+
+WeldTextForwarder::WeldTextForwarder(WeldEditAccessible& rAcc, WeldEditSource& rSource)
+ : m_rEditAcc(rAcc)
+ , m_rEditSource(rSource)
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (pEditEngine)
+ pEditEngine->SetNotifyHdl(LINK(this, WeldTextForwarder, NotifyHdl));
+}
+
+WeldTextForwarder::~WeldTextForwarder()
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (pEditEngine)
+ pEditEngine->SetNotifyHdl(Link<EENotify&, void>());
+}
+
+IMPL_LINK(WeldTextForwarder, NotifyHdl, EENotify&, rNotify, void)
+{
+ if (EditEngine* pEditEngine = m_rEditAcc.GetEditEngine())
+ {
+ if (rNotify.eNotificationType == EE_NOTIFY_PROCESSNOTIFICATIONS
+ && !pEditEngine->IsUpdateLayout())
+ {
+ // tdf#143088 an UpdateMode of false will just to on to cause
+ // AccessibleTextHelper_Impl::GetTextForwarder to throw an
+ // exception as a Frozen EditEngine is considered Invalid so return
+ // early instead
+ return;
+ }
+ }
+
+ ::std::unique_ptr<SfxHint> aHint = SvxEditSourceHelper::EENotification2Hint(&rNotify);
+ if (aHint)
+ m_rEditSource.GetBroadcaster().Broadcast(*aHint);
+}
+
+sal_Int32 WeldTextForwarder::GetParagraphCount() const
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ return pEditEngine ? pEditEngine->GetParagraphCount() : 0;
+}
+
+sal_Int32 WeldTextForwarder::GetTextLen(sal_Int32 nParagraph) const
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ return pEditEngine ? pEditEngine->GetTextLen(nParagraph) : 0;
+}
+
+OUString WeldTextForwarder::GetText(const ESelection& rSel) const
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ OUString aRet;
+ if (pEditEngine)
+ aRet = pEditEngine->GetText(rSel);
+ return convertLineEnd(aRet, GetSystemLineEnd());
+}
+
+SfxItemSet WeldTextForwarder::GetAttribs(const ESelection& rSel,
+ EditEngineAttribs nOnlyHardAttrib) const
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ assert(pEditEngine && "EditEngine missing");
+ if (rSel.nStartPara == rSel.nEndPara)
+ {
+ GetAttribsFlags nFlags = GetAttribsFlags::NONE;
+ switch (nOnlyHardAttrib)
+ {
+ case EditEngineAttribs::All:
+ nFlags = GetAttribsFlags::ALL;
+ break;
+ case EditEngineAttribs::OnlyHard:
+ nFlags = GetAttribsFlags::CHARATTRIBS;
+ break;
+ default:
+ SAL_WARN("svx", "unknown flags for WeldTextForwarder::GetAttribs");
+ }
+
+ return pEditEngine->GetAttribs(rSel.nStartPara, rSel.nStartPos, rSel.nEndPos, nFlags);
+ }
+ else
+ {
+ return pEditEngine->GetAttribs(rSel, nOnlyHardAttrib);
+ }
+}
+
+SfxItemSet WeldTextForwarder::GetParaAttribs(sal_Int32 nPara) const
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ assert(pEditEngine && "EditEngine missing");
+
+ SfxItemSet aSet(pEditEngine->GetParaAttribs(nPara));
+
+ sal_uInt16 nWhich = EE_PARA_START;
+ while (nWhich <= EE_PARA_END)
+ {
+ if (aSet.GetItemState(nWhich) != SfxItemState::SET)
+ {
+ if (pEditEngine->HasParaAttrib(nPara, nWhich))
+ aSet.Put(pEditEngine->GetParaAttrib(nPara, nWhich));
+ }
+ nWhich++;
+ }
+
+ return aSet;
+}
+
+void WeldTextForwarder::SetParaAttribs(sal_Int32 nPara, const SfxItemSet& rSet)
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (pEditEngine)
+ pEditEngine->SetParaAttribs(nPara, rSet);
+}
+
+SfxItemPool* WeldTextForwarder::GetPool() const
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ return pEditEngine ? pEditEngine->GetEmptyItemSet().GetPool() : nullptr;
+}
+
+void WeldTextForwarder::RemoveAttribs(const ESelection& rSelection)
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (pEditEngine)
+ pEditEngine->RemoveAttribs(rSelection, false /*bRemoveParaAttribs*/, 0);
+}
+
+void WeldTextForwarder::GetPortions(sal_Int32 nPara, std::vector<sal_Int32>& rList) const
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (pEditEngine)
+ pEditEngine->GetPortions(nPara, rList);
+}
+
+OUString WeldTextForwarder::GetStyleSheet(sal_Int32 nPara) const
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (auto pStyle = pEditEngine ? pEditEngine->GetStyleSheet(nPara) : nullptr)
+ return pStyle->GetName();
+ return OUString();
+}
+
+void WeldTextForwarder::SetStyleSheet(sal_Int32 nPara, const OUString& rStyleName)
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ auto pStyleSheetPool = pEditEngine ? pEditEngine->GetStyleSheetPool() : nullptr;
+ if (auto pStyle
+ = pStyleSheetPool ? pStyleSheetPool->Find(rStyleName, SfxStyleFamily::Para) : nullptr)
+ pEditEngine->SetStyleSheet(nPara, static_cast<SfxStyleSheet*>(pStyle));
+}
+
+void WeldTextForwarder::QuickInsertText(const OUString& rText, const ESelection& rSel)
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (pEditEngine)
+ pEditEngine->QuickInsertText(rText, rSel);
+}
+
+void WeldTextForwarder::QuickInsertLineBreak(const ESelection& rSel)
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (pEditEngine)
+ pEditEngine->QuickInsertLineBreak(rSel);
+}
+
+void WeldTextForwarder::QuickInsertField(const SvxFieldItem& rFld, const ESelection& rSel)
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (pEditEngine)
+ pEditEngine->QuickInsertField(rFld, rSel);
+}
+
+void WeldTextForwarder::QuickSetAttribs(const SfxItemSet& rSet, const ESelection& rSel)
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (pEditEngine)
+ pEditEngine->QuickSetAttribs(rSet, rSel);
+}
+
+bool WeldTextForwarder::IsValid() const
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ // cannot reliably query EditEngine state
+ // while in the middle of an update
+ return pEditEngine && pEditEngine->IsUpdateLayout();
+}
+
+OUString WeldTextForwarder::CalcFieldValue(const SvxFieldItem& rField, sal_Int32 nPara,
+ sal_Int32 nPos, std::optional<Color>& rpTxtColor,
+ std::optional<Color>& rpFldColor,
+ std::optional<FontLineStyle>& rpFldLineStyle)
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ return pEditEngine ? pEditEngine->CalcFieldValue(rField, nPara, nPos, rpTxtColor, rpFldColor,
+ rpFldLineStyle)
+ : OUString();
+}
+
+void WeldTextForwarder::FieldClicked(const SvxFieldItem&) {}
+
+static SfxItemState GetSvxEditEngineItemState(EditEngine const& rEditEngine, const ESelection& rSel,
+ sal_uInt16 nWhich)
+{
+ std::vector<EECharAttrib> aAttribs;
+
+ const SfxPoolItem* pLastItem = nullptr;
+
+ SfxItemState eState = SfxItemState::DEFAULT;
+
+ // check all paragraphs inside the selection
+ for (sal_Int32 nPara = rSel.nStartPara; nPara <= rSel.nEndPara; nPara++)
+ {
+ SfxItemState eParaState = SfxItemState::DEFAULT;
+
+ // calculate start and endpos for this paragraph
+ sal_Int32 nPos = 0;
+ if (rSel.nStartPara == nPara)
+ nPos = rSel.nStartPos;
+
+ sal_Int32 nEndPos = rSel.nEndPos;
+ if (rSel.nEndPara != nPara)
+ nEndPos = rEditEngine.GetTextLen(nPara);
+
+ // get list of char attribs
+ rEditEngine.GetCharAttribs(nPara, aAttribs);
+
+ bool bEmpty = true; // we found no item inside the selection of this paragraph
+ bool bGaps = false; // we found items but there are gaps between them
+ sal_Int32 nLastEnd = nPos;
+
+ const SfxPoolItem* pParaItem = nullptr;
+
+ for (const auto& rAttrib : aAttribs)
+ {
+ OSL_ENSURE(rAttrib.pAttr, "GetCharAttribs gives corrupt data");
+
+ const bool bEmptyPortion = (rAttrib.nStart == rAttrib.nEnd);
+ if ((!bEmptyPortion && (rAttrib.nStart >= nEndPos))
+ || (bEmptyPortion && (rAttrib.nStart > nEndPos)))
+ break; // break if we are already behind our selection
+
+ if ((!bEmptyPortion && (rAttrib.nEnd <= nPos))
+ || (bEmptyPortion && (rAttrib.nEnd < nPos)))
+ continue; // or if the attribute ends before our selection
+
+ if (rAttrib.pAttr->Which() != nWhich)
+ continue; // skip if is not the searched item
+
+ // if we already found an item
+ if (pParaItem)
+ {
+ // ... and its different to this one than the state is don't care
+ if (*pParaItem != *(rAttrib.pAttr))
+ return SfxItemState::DONTCARE;
+ }
+ else
+ {
+ pParaItem = rAttrib.pAttr;
+ }
+
+ if (bEmpty)
+ bEmpty = false;
+
+ if (!bGaps && rAttrib.nStart > nLastEnd)
+ bGaps = true;
+
+ nLastEnd = rAttrib.nEnd;
+ }
+
+ if (!bEmpty && !bGaps && nLastEnd < (nEndPos - 1))
+ bGaps = true;
+ if (bEmpty)
+ eParaState = SfxItemState::DEFAULT;
+ else if (bGaps)
+ eParaState = SfxItemState::DONTCARE;
+ else
+ eParaState = SfxItemState::SET;
+
+ // if we already found an item check if we found the same
+ if (pLastItem)
+ {
+ if ((pParaItem == nullptr) || (*pLastItem != *pParaItem))
+ return SfxItemState::DONTCARE;
+ }
+ else
+ {
+ pLastItem = pParaItem;
+ eState = eParaState;
+ }
+ }
+
+ return eState;
+}
+
+SfxItemState WeldTextForwarder::GetItemState(const ESelection& rSel, sal_uInt16 nWhich) const
+{
+ SfxItemState nState = SfxItemState::DISABLED;
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (pEditEngine)
+ nState = GetSvxEditEngineItemState(*pEditEngine, rSel, nWhich);
+ return nState;
+}
+
+SfxItemState WeldTextForwarder::GetItemState(sal_Int32 nPara, sal_uInt16 nWhich) const
+{
+ SfxItemState nState = SfxItemState::DISABLED;
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (pEditEngine)
+ {
+ const SfxItemSet& rSet = pEditEngine->GetParaAttribs(nPara);
+ nState = rSet.GetItemState(nWhich);
+ }
+ return nState;
+}
+
+LanguageType WeldTextForwarder::GetLanguage(sal_Int32 nPara, sal_Int32 nIndex) const
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ return pEditEngine ? pEditEngine->GetLanguage(nPara, nIndex).nLang : LANGUAGE_NONE;
+}
+
+sal_Int32 WeldTextForwarder::GetFieldCount(sal_Int32 nPara) const
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ return pEditEngine ? pEditEngine->GetFieldCount(nPara) : 0;
+}
+
+EFieldInfo WeldTextForwarder::GetFieldInfo(sal_Int32 nPara, sal_uInt16 nField) const
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ return pEditEngine ? pEditEngine->GetFieldInfo(nPara, nField) : EFieldInfo();
+}
+
+EBulletInfo WeldTextForwarder::GetBulletInfo(sal_Int32 /*nPara*/) const { return EBulletInfo(); }
+
+tools::Rectangle WeldTextForwarder::GetCharBounds(sal_Int32 nPara, sal_Int32 nIndex) const
+{
+ tools::Rectangle aRect(0, 0, 0, 0);
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+
+ if (pEditEngine)
+ {
+ // Handle virtual position one-past-the end of the string
+ if (nIndex >= pEditEngine->GetTextLen(nPara))
+ {
+ if (nIndex)
+ aRect = pEditEngine->GetCharacterBounds(EPosition(nPara, nIndex - 1));
+
+ aRect.Move(aRect.Right() - aRect.Left(), 0);
+ aRect.SetSize(Size(1, pEditEngine->GetTextHeight()));
+ }
+ else
+ {
+ aRect = pEditEngine->GetCharacterBounds(EPosition(nPara, nIndex));
+ }
+ }
+ return aRect;
+}
+
+tools::Rectangle WeldTextForwarder::GetParaBounds(sal_Int32 nPara) const
+{
+ tools::Rectangle aRect(0, 0, 0, 0);
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+
+ if (pEditEngine)
+ {
+ const Point aPnt = pEditEngine->GetDocPosTopLeft(nPara);
+ const sal_Int32 nWidth = pEditEngine->CalcTextWidth();
+ const sal_Int32 nHeight = pEditEngine->GetTextHeight(nPara);
+ aRect = tools::Rectangle(aPnt.X(), aPnt.Y(), aPnt.X() + nWidth, aPnt.Y() + nHeight);
+ }
+
+ return aRect;
+}
+
+MapMode WeldTextForwarder::GetMapMode() const
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ return pEditEngine ? pEditEngine->GetRefMapMode() : MapMode(MapUnit::Map100thMM);
+}
+
+OutputDevice* WeldTextForwarder::GetRefDevice() const
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ return pEditEngine ? pEditEngine->GetRefDevice() : nullptr;
+}
+
+bool WeldTextForwarder::GetIndexAtPoint(const Point& rPos, sal_Int32& nPara,
+ sal_Int32& nIndex) const
+{
+ bool bRes = false;
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (pEditEngine)
+ {
+ EPosition aDocPos = pEditEngine->FindDocPosition(rPos);
+ nPara = aDocPos.nPara;
+ nIndex = aDocPos.nIndex;
+ bRes = true;
+ }
+ return bRes;
+}
+
+bool WeldTextForwarder::GetWordIndices(sal_Int32 nPara, sal_Int32 nIndex, sal_Int32& nStart,
+ sal_Int32& nEnd) const
+{
+ bool bRes = false;
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (pEditEngine)
+ {
+ ESelection aRes = pEditEngine->GetWord(ESelection(nPara, nIndex, nPara, nIndex),
+ css::i18n::WordType::DICTIONARY_WORD);
+
+ if (aRes.nStartPara == nPara && aRes.nStartPara == aRes.nEndPara)
+ {
+ nStart = aRes.nStartPos;
+ nEnd = aRes.nEndPos;
+
+ bRes = true;
+ }
+ }
+
+ return bRes;
+}
+
+bool WeldTextForwarder::GetAttributeRun(sal_Int32& nStartIndex, sal_Int32& nEndIndex,
+ sal_Int32 nPara, sal_Int32 nIndex, bool bInCell) const
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (!pEditEngine)
+ return false;
+ SvxEditSourceHelper::GetAttributeRun(nStartIndex, nEndIndex, *pEditEngine, nPara, nIndex,
+ bInCell);
+ return true;
+}
+
+sal_Int32 WeldTextForwarder::GetLineCount(sal_Int32 nPara) const
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ return pEditEngine ? pEditEngine->GetLineCount(nPara) : 0;
+}
+
+sal_Int32 WeldTextForwarder::GetLineLen(sal_Int32 nPara, sal_Int32 nLine) const
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ return pEditEngine ? pEditEngine->GetLineLen(nPara, nLine) : 0;
+}
+
+void WeldTextForwarder::GetLineBoundaries(/*out*/ sal_Int32& rStart, /*out*/ sal_Int32& rEnd,
+ sal_Int32 nPara, sal_Int32 nLine) const
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (pEditEngine)
+ pEditEngine->GetLineBoundaries(rStart, rEnd, nPara, nLine);
+ else
+ rStart = rEnd = 0;
+}
+
+sal_Int32 WeldTextForwarder::GetLineNumberAtIndex(sal_Int32 nPara, sal_Int32 nIndex) const
+{
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ return pEditEngine ? pEditEngine->GetLineNumberAtIndex(nPara, nIndex) : 0;
+}
+
+bool WeldTextForwarder::QuickFormatDoc(bool /*bFull*/)
+{
+ bool bRes = false;
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (pEditEngine)
+ {
+ pEditEngine->QuickFormatDoc();
+ bRes = true;
+ }
+ return bRes;
+}
+
+sal_Int16 WeldTextForwarder::GetDepth(sal_Int32 /*nPara*/) const
+{
+ // math has no outliner...
+ return -1;
+}
+
+bool WeldTextForwarder::SetDepth(sal_Int32 /*nPara*/, sal_Int16 nNewDepth)
+{
+ // math has no outliner...
+ return -1 == nNewDepth; // is it the value from 'GetDepth' ?
+}
+
+bool WeldTextForwarder::Delete(const ESelection& rSelection)
+{
+ bool bRes = false;
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (pEditEngine)
+ {
+ pEditEngine->QuickDelete(rSelection);
+ pEditEngine->QuickFormatDoc();
+ bRes = true;
+ }
+ return bRes;
+}
+
+bool WeldTextForwarder::InsertText(const OUString& rStr, const ESelection& rSelection)
+{
+ bool bRes = false;
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (pEditEngine)
+ {
+ pEditEngine->QuickInsertText(rStr, rSelection);
+ pEditEngine->QuickFormatDoc();
+ bRes = true;
+ }
+ return bRes;
+}
+
+const SfxItemSet* WeldTextForwarder::GetEmptyItemSetPtr()
+{
+ const SfxItemSet* pItemSet = nullptr;
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (pEditEngine)
+ {
+ pItemSet = &pEditEngine->GetEmptyItemSet();
+ }
+ return pItemSet;
+}
+
+void WeldTextForwarder::AppendParagraph()
+{
+ // append an empty paragraph
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (pEditEngine)
+ {
+ sal_Int32 nParaCount = pEditEngine->GetParagraphCount();
+ pEditEngine->InsertParagraph(nParaCount, OUString());
+ }
+}
+
+sal_Int32 WeldTextForwarder::AppendTextPortion(sal_Int32 nPara, const OUString& rText,
+ const SfxItemSet& rSet)
+{
+ sal_uInt16 nRes = 0;
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (pEditEngine && nPara < pEditEngine->GetParagraphCount())
+ {
+ // append text
+ ESelection aSel(nPara, pEditEngine->GetTextLen(nPara));
+ pEditEngine->QuickInsertText(rText, aSel);
+
+ // set attributes for new appended text
+ nRes = aSel.nEndPos = pEditEngine->GetTextLen(nPara);
+ pEditEngine->QuickSetAttribs(rSet, aSel);
+ }
+ return nRes;
+}
+
+void WeldTextForwarder::CopyText(const SvxTextForwarder& rSource)
+{
+ const WeldTextForwarder* pSourceForwarder = dynamic_cast<const WeldTextForwarder*>(&rSource);
+ if (!pSourceForwarder)
+ return;
+ EditEngine* pSourceEditEngine = pSourceForwarder->m_rEditAcc.GetEditEngine();
+ EditEngine* pEditEngine = m_rEditAcc.GetEditEngine();
+ if (pEditEngine && pSourceEditEngine)
+ {
+ std::unique_ptr<EditTextObject> pNewTextObject = pSourceEditEngine->CreateTextObject();
+ pEditEngine->SetText(*pNewTextObject);
+ }
+}
+
+WeldEditViewForwarder::WeldEditViewForwarder(WeldEditAccessible& rAcc)
+ : m_rEditAcc(rAcc)
+{
+}
+
+bool WeldEditViewForwarder::IsValid() const { return m_rEditAcc.GetEditView() != nullptr; }
+
+Point WeldEditViewForwarder::LogicToPixel(const Point& rPoint, const MapMode& rMapMode) const
+{
+ EditView* pEditView = m_rEditAcc.GetEditView();
+ if (!pEditView)
+ return Point();
+ OutputDevice& rOutDev = pEditView->GetOutputDevice();
+ MapMode aMapMode(rOutDev.GetMapMode());
+ Point aPoint(OutputDevice::LogicToLogic(rPoint, rMapMode, MapMode(aMapMode.GetMapUnit())));
+ aMapMode.SetOrigin(Point());
+ return rOutDev.LogicToPixel(aPoint, aMapMode);
+}
+
+Point WeldEditViewForwarder::PixelToLogic(const Point& rPoint, const MapMode& rMapMode) const
+{
+ EditView* pEditView = m_rEditAcc.GetEditView();
+ if (!pEditView)
+ return Point();
+ OutputDevice& rOutDev = pEditView->GetOutputDevice();
+ MapMode aMapMode(rOutDev.GetMapMode());
+ aMapMode.SetOrigin(Point());
+ Point aPoint(rOutDev.PixelToLogic(rPoint, aMapMode));
+ return OutputDevice::LogicToLogic(aPoint, MapMode(aMapMode.GetMapUnit()), rMapMode);
+}
+
+bool WeldEditViewForwarder::GetSelection(ESelection& rSelection) const
+{
+ bool bRes = false;
+ EditView* pEditView = m_rEditAcc.GetEditView();
+ if (pEditView)
+ {
+ rSelection = pEditView->GetSelection();
+ bRes = true;
+ }
+ return bRes;
+}
+
+bool WeldEditViewForwarder::SetSelection(const ESelection& rSelection)
+{
+ bool bRes = false;
+ EditView* pEditView = m_rEditAcc.GetEditView();
+ if (pEditView)
+ {
+ pEditView->SetSelection(rSelection);
+ bRes = true;
+ }
+ return bRes;
+}
+
+bool WeldEditViewForwarder::Copy()
+{
+ bool bRes = false;
+ EditView* pEditView = m_rEditAcc.GetEditView();
+ if (pEditView)
+ {
+ pEditView->Copy();
+ bRes = true;
+ }
+ return bRes;
+}
+
+bool WeldEditViewForwarder::Cut()
+{
+ bool bRes = false;
+ EditView* pEditView = m_rEditAcc.GetEditView();
+ if (pEditView)
+ {
+ pEditView->Cut();
+ bRes = true;
+ }
+ return bRes;
+}
+
+bool WeldEditViewForwarder::Paste()
+{
+ bool bRes = false;
+ EditView* pEditView = m_rEditAcc.GetEditView();
+ if (pEditView)
+ {
+ pEditView->Paste();
+ bRes = true;
+ }
+ return bRes;
+}
+
+void WeldEditView::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ Size aSize(pDrawingArea->get_size_request());
+ if (aSize.Width() == -1)
+ aSize.setWidth(500);
+ if (aSize.Height() == -1)
+ aSize.setHeight(100);
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+
+ SetOutputSizePixel(aSize);
+
+ weld::CustomWidgetController::SetDrawingArea(pDrawingArea);
+
+ EnableRTL(false);
+
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ Color aBgColor = rStyleSettings.GetWindowColor();
+
+ OutputDevice& rDevice = pDrawingArea->get_ref_device();
+
+ rDevice.SetMapMode(MapMode(MapUnit::MapTwip));
+ rDevice.SetBackground(aBgColor);
+
+ Size aOutputSize(rDevice.PixelToLogic(aSize));
+
+ makeEditEngine();
+ m_xEditEngine->SetPaperSize(aOutputSize);
+ m_xEditEngine->SetRefDevice(&rDevice);
+
+ m_xEditEngine->SetControlWord(m_xEditEngine->GetControlWord() | EEControlBits::MARKFIELDS);
+
+ m_xEditView.reset(new EditView(m_xEditEngine.get(), nullptr));
+ m_xEditView->setEditViewCallbacks(this);
+ m_xEditView->SetOutputArea(tools::Rectangle(Point(0, 0), aOutputSize));
+
+ m_xEditView->SetBackgroundColor(aBgColor);
+ m_xEditEngine->SetBackgroundColor(aBgColor);
+ m_xEditEngine->InsertView(m_xEditView.get());
+
+ pDrawingArea->set_cursor(PointerStyle::Text);
+
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ InitAccessible();
+#endif
+}
+
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+void WeldEditView::InitAccessible()
+{
+ if (m_xAccessible.is())
+ m_xAccessible->Init(GetEditEngine(), GetEditView());
+}
+#endif
+
+int WeldEditView::GetSurroundingText(OUString& rSurrounding)
+{
+ EditView* pEditView = GetEditView();
+ if (!pEditView)
+ return -1;
+ rSurrounding = pEditView->GetSurroundingText();
+ return pEditView->GetSurroundingTextSelection().Min();
+}
+
+bool WeldEditView::DeleteSurroundingText(const Selection& rRange)
+{
+ EditView* pEditView = GetEditView();
+ if (!pEditView)
+ return false;
+ return pEditView->DeleteSurroundingText(rRange);
+}
+
+void WeldEditView::GetFocus()
+{
+ EditView* pEditView = GetEditView();
+ if (pEditView)
+ {
+ pEditView->ShowCursor(false);
+ Invalidate(); // redraw with cursor
+ }
+
+ weld::CustomWidgetController::GetFocus();
+
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ if (m_xAccessible.is())
+ {
+ // Note: will implicitly send the AccessibleStateType::FOCUSED event
+ ::accessibility::AccessibleTextHelper* pHelper = m_xAccessible->GetTextHelper();
+ if (pHelper)
+ pHelper->SetFocus();
+ }
+#endif
+}
+
+void WeldEditView::LoseFocus()
+{
+ weld::CustomWidgetController::LoseFocus();
+ Invalidate(); // redraw without cursor
+
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ if (m_xAccessible.is())
+ {
+ // Note: will implicitly send the AccessibleStateType::FOCUSED event
+ ::accessibility::AccessibleTextHelper* pHelper = m_xAccessible->GetTextHelper();
+ if (pHelper)
+ pHelper->SetFocus(false);
+ }
+#endif
+}
+
+bool WeldEditView::CanFocus() const { return true; }
+
+css::uno::Reference<css::datatransfer::dnd::XDropTarget> WeldEditView::GetDropTarget()
+{
+ if (!m_xDropTarget)
+ m_xDropTarget = weld::CustomWidgetController::GetDropTarget();
+ return m_xDropTarget;
+}
+
+css::uno::Reference<css::datatransfer::clipboard::XClipboard> WeldEditView::GetClipboard() const
+{
+ return weld::CustomWidgetController::GetClipboard();
+}
+
+void WeldEditView::EditViewSelectionChange()
+{
+ Invalidate();
+
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ if (m_xAccessible.is())
+ {
+ ::accessibility::AccessibleTextHelper* pHelper = m_xAccessible->GetTextHelper();
+ if (pHelper)
+ pHelper->UpdateSelection();
+ }
+#endif
+}
+
+namespace
+{
+class WeldEditViewUIObject final : public DrawingAreaUIObject
+{
+private:
+ WeldEditView* mpEditView;
+
+public:
+ WeldEditViewUIObject(const VclPtr<vcl::Window>& rDrawingArea)
+ : DrawingAreaUIObject(rDrawingArea)
+ , mpEditView(static_cast<WeldEditView*>(mpController))
+ {
+ }
+
+ static std::unique_ptr<UIObject> create(vcl::Window* pWindow)
+ {
+ return std::unique_ptr<UIObject>(new WeldEditViewUIObject(pWindow));
+ }
+
+ virtual StringMap get_state() override
+ {
+ StringMap aMap = WindowUIObject::get_state();
+ aMap["Text"] = mpEditView->GetText();
+ return aMap;
+ }
+
+private:
+ virtual OUString get_name() const override { return "WeldEditViewUIObject"; }
+};
+}
+
+FactoryFunction WeldEditView::GetUITestFactory() const { return WeldEditViewUIObject::create; }
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */