summaryrefslogtreecommitdiffstats
path: root/cui/source/dialogs
diff options
context:
space:
mode:
Diffstat (limited to 'cui/source/dialogs')
-rw-r--r--cui/source/dialogs/DiagramDialog.cxx81
-rw-r--r--cui/source/dialogs/FontFeaturesDialog.cxx227
-rw-r--r--cui/source/dialogs/QrCodeGenDialog.cxx341
-rw-r--r--cui/source/dialogs/SignSignatureLineDialog.cxx293
-rw-r--r--cui/source/dialogs/SignatureLineDialog.cxx210
-rw-r--r--cui/source/dialogs/SignatureLineDialogBase.cxx221
-rw-r--r--cui/source/dialogs/SpellAttrib.hxx118
-rw-r--r--cui/source/dialogs/SpellDialog.cxx2092
-rw-r--r--cui/source/dialogs/about.cxx260
-rw-r--r--cui/source/dialogs/colorpicker.cxx1334
-rw-r--r--cui/source/dialogs/cuicharmap.cxx1250
-rw-r--r--cui/source/dialogs/cuifmsearch.cxx754
-rw-r--r--cui/source/dialogs/cuigaldlg.cxx1011
-rw-r--r--cui/source/dialogs/cuigrfflt.cxx468
-rw-r--r--cui/source/dialogs/cuihyperdlg.cxx293
-rw-r--r--cui/source/dialogs/cuiimapwnd.cxx59
-rw-r--r--cui/source/dialogs/cuitbxform.cxx33
-rw-r--r--cui/source/dialogs/dlgname.cxx104
-rw-r--r--cui/source/dialogs/hangulhanjadlg.cxx1505
-rw-r--r--cui/source/dialogs/hldocntp.cxx479
-rw-r--r--cui/source/dialogs/hldoctp.cxx318
-rw-r--r--cui/source/dialogs/hlinettp.cxx393
-rw-r--r--cui/source/dialogs/hlmailtp.cxx228
-rw-r--r--cui/source/dialogs/hlmarkwn.cxx473
-rw-r--r--cui/source/dialogs/hltpbase.cxx545
-rw-r--r--cui/source/dialogs/hyphen.cxx471
-rw-r--r--cui/source/dialogs/iconcdlg.cxx311
-rw-r--r--cui/source/dialogs/insdlg.cxx583
-rw-r--r--cui/source/dialogs/insrc.cxx59
-rw-r--r--cui/source/dialogs/linkdlg.cxx636
-rw-r--r--cui/source/dialogs/multipat.cxx320
-rw-r--r--cui/source/dialogs/newtabledlg.cxx39
-rw-r--r--cui/source/dialogs/passwdomdlg.cxx171
-rw-r--r--cui/source/dialogs/pastedlg.cxx339
-rw-r--r--cui/source/dialogs/postdlg.cxx180
-rw-r--r--cui/source/dialogs/screenshotannotationdlg.cxx583
-rw-r--r--cui/source/dialogs/scriptdlg.cxx1351
-rw-r--r--cui/source/dialogs/sdrcelldlg.cxx62
-rw-r--r--cui/source/dialogs/showcols.cxx107
-rw-r--r--cui/source/dialogs/splitcelldlg.cxx88
-rw-r--r--cui/source/dialogs/srchxtra.cxx235
-rw-r--r--cui/source/dialogs/thesdlg.cxx343
-rw-r--r--cui/source/dialogs/tipofthedaydlg.cxx168
-rw-r--r--cui/source/dialogs/zoom.cxx406
44 files changed, 19542 insertions, 0 deletions
diff --git a/cui/source/dialogs/DiagramDialog.cxx b/cui/source/dialogs/DiagramDialog.cxx
new file mode 100644
index 000000000..f3a4a069a
--- /dev/null
+++ b/cui/source/dialogs/DiagramDialog.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 <DiagramDialog.hxx>
+
+#include <comphelper/dispatchcommand.hxx>
+#include <svx/DiagramDataInterface.hxx>
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+DiagramDialog::DiagramDialog(weld::Window* pWindow,
+ std::shared_ptr<DiagramDataInterface> pDiagramData)
+ : GenericDialogController(pWindow, "cui/ui/diagramdialog.ui", "DiagramDialog")
+ , mpDiagramData(pDiagramData)
+ , mpBtnOk(m_xBuilder->weld_button("btnOk"))
+ , mpBtnCancel(m_xBuilder->weld_button("btnCancel"))
+ , mpBtnAdd(m_xBuilder->weld_button("btnAdd"))
+ , mpBtnRemove(m_xBuilder->weld_button("btnRemove"))
+ , mpTreeDiagram(m_xBuilder->weld_tree_view("treeDiagram"))
+ , mpTextAdd(m_xBuilder->weld_text_view("textAdd"))
+{
+ mpBtnAdd->connect_clicked(LINK(this, DiagramDialog, OnAddClick));
+ mpBtnRemove->connect_clicked(LINK(this, DiagramDialog, OnRemoveClick));
+
+ populateTree(nullptr, OUString());
+
+ // expand all items
+ weld::TreeView* pTreeDiagram = mpTreeDiagram.get();
+ pTreeDiagram->all_foreach([pTreeDiagram](weld::TreeIter& rEntry) {
+ pTreeDiagram->expand_row(rEntry);
+ return false;
+ });
+}
+
+IMPL_LINK_NOARG(DiagramDialog, OnAddClick, weld::Button&, void)
+{
+ OUString sText = mpTextAdd->get_text();
+ if (!sText.isEmpty())
+ {
+ OUString sNodeId = mpDiagramData->addNode(sText);
+ std::unique_ptr<weld::TreeIter> pEntry(mpTreeDiagram->make_iterator());
+ mpTreeDiagram->insert(nullptr, -1, &sText, &sNodeId, nullptr, nullptr, nullptr, false,
+ pEntry.get());
+ mpTreeDiagram->select(*pEntry);
+ comphelper::dispatchCommand(".uno:RegenerateDiagram", {});
+ }
+}
+
+IMPL_LINK_NOARG(DiagramDialog, OnRemoveClick, weld::Button&, void)
+{
+ std::unique_ptr<weld::TreeIter> pEntry(mpTreeDiagram->make_iterator());
+ if (mpTreeDiagram->get_selected(pEntry.get()))
+ {
+ if (mpDiagramData->removeNode(mpTreeDiagram->get_id(*pEntry)))
+ {
+ mpTreeDiagram->remove(*pEntry);
+ comphelper::dispatchCommand(".uno:RegenerateDiagram", {});
+ }
+ }
+}
+
+void DiagramDialog::populateTree(const weld::TreeIter* pParent, const OUString& rParentId)
+{
+ auto aItems = mpDiagramData->getChildren(rParentId);
+ for (auto& aItem : aItems)
+ {
+ std::unique_ptr<weld::TreeIter> pEntry(mpTreeDiagram->make_iterator());
+ mpTreeDiagram->insert(pParent, -1, &aItem.second, &aItem.first, nullptr, nullptr, nullptr,
+ false, pEntry.get());
+ populateTree(pEntry.get(), aItem.first);
+ }
+}
+
+DiagramDialog::~DiagramDialog() {}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/dialogs/FontFeaturesDialog.cxx b/cui/source/dialogs/FontFeaturesDialog.cxx
new file mode 100644
index 000000000..a34912d5d
--- /dev/null
+++ b/cui/source/dialogs/FontFeaturesDialog.cxx
@@ -0,0 +1,227 @@
+/* -*- 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 <FontFeaturesDialog.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <vcl/font/FeatureParser.hxx>
+#include <vcl/virdev.hxx>
+#include <svtools/colorcfg.hxx>
+#include <unordered_set>
+
+using namespace css;
+
+namespace cui
+{
+FontFeaturesDialog::FontFeaturesDialog(weld::Window* pParent, OUString const& rFontName)
+ : GenericDialogController(pParent, "cui/ui/fontfeaturesdialog.ui", "FontFeaturesDialog")
+ , m_sFontName(rFontName)
+ , m_xContentWindow(m_xBuilder->weld_scrolled_window("contentWindow"))
+ , m_xContentGrid(m_xBuilder->weld_container("contentGrid"))
+ , m_xPreviewWindow(new weld::CustomWeld(*m_xBuilder, "preview", m_aPreviewWindow))
+{
+ svtools::ColorConfig aColorConfig;
+ Color aFillColor(aColorConfig.GetColorValue(svtools::DOCCOLOR).nColor);
+ m_aPreviewWindow.SetBackColor(aFillColor);
+ initialize();
+}
+
+FontFeaturesDialog::~FontFeaturesDialog() {}
+
+static sal_Int32 makeEnumComboBox(weld::ComboBox& rNameBox,
+ vcl::font::FeatureDefinition const& rFeatureDefinition,
+ uint32_t nDefault)
+{
+ sal_Int32 nRes = 0;
+ int count = 0;
+ for (vcl::font::FeatureParameter const& rParameter : rFeatureDefinition.getEnumParameters())
+ {
+ rNameBox.append(OUString::number(rParameter.getCode()), rParameter.getDescription());
+ if (rParameter.getCode() == nDefault)
+ nRes = count;
+ ++count;
+ }
+ return nRes;
+}
+
+void FontFeaturesDialog::initialize()
+{
+ ScopedVclPtrInstance<VirtualDevice> aVDev(*Application::GetDefaultDevice(),
+ DeviceFormat::DEFAULT, DeviceFormat::DEFAULT);
+ aVDev->SetOutputSizePixel(Size(10, 10));
+
+ vcl::Font aFont = aVDev->GetFont();
+ aFont.SetFamilyName(m_sFontName);
+ aVDev->SetFont(aFont);
+
+ std::vector<vcl::font::Feature> rFontFeatures;
+
+ if (!aVDev->GetFontFeatures(rFontFeatures))
+ return;
+
+ std::unordered_set<sal_uInt32> aDoneFeatures;
+ std::vector<vcl::font::Feature> rFilteredFontFeatures;
+
+ for (vcl::font::Feature const& rFontFeature : rFontFeatures)
+ {
+ sal_uInt32 nFontFeatureCode = rFontFeature.m_aID.m_aFeatureCode;
+ if (!aDoneFeatures.insert(nFontFeatureCode).second)
+ continue;
+ rFilteredFontFeatures.push_back(rFontFeature);
+ }
+
+ fillGrid(rFilteredFontFeatures);
+
+ updateFontPreview();
+}
+
+void FontFeaturesDialog::fillGrid(std::vector<vcl::font::Feature> const& rFontFeatures)
+{
+ vcl::font::FeatureParser aParser(m_sFontName);
+ auto aExistingFeatures = aParser.getFeaturesMap();
+
+ sal_Int32 i = 0;
+ for (vcl::font::Feature const& rFontFeature : rFontFeatures)
+ {
+ sal_uInt32 nFontFeatureCode = rFontFeature.m_aID.m_aFeatureCode;
+
+ vcl::font::FeatureDefinition aDefinition;
+ if (rFontFeature.m_aDefinition)
+ aDefinition = rFontFeature.m_aDefinition;
+ if (!aDefinition)
+ aDefinition = { nFontFeatureCode, nullptr };
+
+ m_aFeatureItems.emplace_back(m_xContentGrid.get());
+
+ uint32_t nValue = 0;
+ if (aExistingFeatures.find(nFontFeatureCode) != aExistingFeatures.end())
+ nValue = aExistingFeatures.at(nFontFeatureCode);
+ else
+ nValue = aDefinition.getDefault();
+
+ FontFeatureItem& aCurrentItem = m_aFeatureItems.back();
+ aCurrentItem.m_aFeatureCode = nFontFeatureCode;
+ aCurrentItem.m_nDefault = aDefinition.getDefault();
+
+ sal_Int32 nGridPositionX = (i % 2) * 2;
+ sal_Int32 nGridPositionY = i / 2;
+ aCurrentItem.m_xContainer->set_grid_left_attach(nGridPositionX);
+ aCurrentItem.m_xContainer->set_grid_top_attach(nGridPositionY);
+
+ Link<weld::ComboBox&, void> aComboBoxSelectHandler
+ = LINK(this, FontFeaturesDialog, ComboBoxSelectedHdl);
+ Link<weld::ToggleButton&, void> aCheckBoxToggleHandler
+ = LINK(this, FontFeaturesDialog, CheckBoxToggledHdl);
+
+ if (aDefinition.getType() == vcl::font::FeatureParameterType::ENUM)
+ {
+ aCurrentItem.m_xText->set_label(aDefinition.getDescription());
+ aCurrentItem.m_xText->show();
+
+ sal_Int32 nInit = makeEnumComboBox(*aCurrentItem.m_xCombo, aDefinition, nValue);
+
+ aCurrentItem.m_xCombo->set_active(nInit);
+ aCurrentItem.m_xCombo->connect_changed(aComboBoxSelectHandler);
+ aCurrentItem.m_xCombo->show();
+ }
+ else
+ {
+ aCurrentItem.m_xCheck->set_active(nValue > 0);
+ aCurrentItem.m_xCheck->set_label(aDefinition.getDescription());
+ aCurrentItem.m_xCheck->connect_toggled(aCheckBoxToggleHandler);
+ aCurrentItem.m_xCheck->show();
+ }
+
+ i++;
+ }
+}
+
+void FontFeaturesDialog::updateFontPreview()
+{
+ vcl::Font rPreviewFont = m_aPreviewWindow.GetFont();
+ vcl::Font rPreviewFontCJK = m_aPreviewWindow.GetCJKFont();
+ vcl::Font rPreviewFontCTL = m_aPreviewWindow.GetCTLFont();
+
+ OUString sNewFontName = createFontNameWithFeatures();
+
+ rPreviewFont.SetFamilyName(sNewFontName);
+ rPreviewFontCJK.SetFamilyName(sNewFontName);
+ rPreviewFontCTL.SetFamilyName(sNewFontName);
+
+ m_aPreviewWindow.SetFont(rPreviewFont, rPreviewFontCJK, rPreviewFontCTL);
+}
+
+IMPL_LINK_NOARG(FontFeaturesDialog, CheckBoxToggledHdl, weld::ToggleButton&, void)
+{
+ updateFontPreview();
+}
+
+IMPL_LINK_NOARG(FontFeaturesDialog, ComboBoxSelectedHdl, weld::ComboBox&, void)
+{
+ updateFontPreview();
+}
+
+OUString FontFeaturesDialog::createFontNameWithFeatures()
+{
+ OUString sResultFontName;
+ OUStringBuffer sNameSuffix;
+ bool bFirst = true;
+
+ for (const FontFeatureItem& rItem : m_aFeatureItems)
+ {
+ if (rItem.m_xCheck->get_visible())
+ {
+ if (sal_uInt32(rItem.m_xCheck->get_active()) != rItem.m_nDefault)
+ {
+ if (!bFirst)
+ sNameSuffix.append(OUString(vcl::font::FeatureSeparator));
+ else
+ bFirst = false;
+
+ sNameSuffix.append(vcl::font::featureCodeAsString(rItem.m_aFeatureCode));
+ if (!rItem.m_xCheck->get_active())
+ sNameSuffix.append("=0");
+ }
+ }
+ else if (rItem.m_xCombo->get_visible() && rItem.m_xText->get_visible())
+ {
+ sal_Int32 nSelection = rItem.m_xCombo->get_active_id().toInt32();
+ if (nSelection != int(rItem.m_nDefault))
+ {
+ if (!bFirst)
+ sNameSuffix.append(OUString(vcl::font::FeatureSeparator));
+ else
+ bFirst = false;
+
+ sNameSuffix.append(vcl::font::featureCodeAsString(rItem.m_aFeatureCode));
+ sNameSuffix.append("=");
+ sNameSuffix.append(OUString::number(nSelection));
+ }
+ }
+ }
+ sResultFontName = vcl::font::trimFontNameFeatures(m_sFontName);
+ if (!sNameSuffix.isEmpty())
+ sResultFontName
+ += OUStringChar(vcl::font::FeaturePrefix) + sNameSuffix.makeStringAndClear();
+ return sResultFontName;
+}
+
+short FontFeaturesDialog::run()
+{
+ short nResult = GenericDialogController::run();
+ if (nResult == RET_OK)
+ {
+ m_sResultFontName = createFontNameWithFeatures();
+ }
+ return nResult;
+}
+
+} // end svx namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/dialogs/QrCodeGenDialog.cxx b/cui/source/dialogs/QrCodeGenDialog.cxx
new file mode 100644
index 000000000..7f3f6a806
--- /dev/null
+++ b/cui/source/dialogs/QrCodeGenDialog.cxx
@@ -0,0 +1,341 @@
+/* -*- 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/.
+ */
+
+#include <QrCodeGenDialog.hxx>
+
+#include <comphelper/processfactory.hxx>
+#include <tools/stream.hxx>
+#include <dialmgr.hxx>
+#include <strings.hrc>
+#include <unotools/streamwrap.hxx>
+#include <utility>
+#include <vcl/svapp.hxx>
+
+#if ENABLE_QRCODEGEN
+#if defined(SYSTEM_QRCODEGEN)
+#include <qrcodegen/QrCode.hpp>
+#else
+#include <QrCode.hpp>
+#endif
+#endif
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <com/sun/star/drawing/XShape.hpp>
+#include <com/sun/star/graphic/GraphicProvider.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+#include <com/sun/star/drawing/QRCode.hpp>
+#include <com/sun/star/drawing/QRCodeErrorCorrection.hpp>
+#include <com/sun/star/graphic/XGraphicProvider.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/sheet/XSpreadsheet.hpp>
+#include <com/sun/star/sheet/XSpreadsheetView.hpp>
+#include <com/sun/star/text/TextContentAnchorType.hpp>
+#include <com/sun/star/text/XTextContent.hpp>
+#include <com/sun/star/text/XTextViewCursor.hpp>
+#include <com/sun/star/text/XTextViewCursorSupplier.hpp>
+#include <config_fuzzers.h>
+#include <com/sun/star/drawing/XDrawView.hpp>
+#include <com/sun/star/drawing/XDrawPage.hpp>
+
+using namespace css;
+using namespace css::uno;
+using namespace css::beans;
+using namespace css::container;
+using namespace css::frame;
+using namespace css::io;
+using namespace css::lang;
+using namespace css::frame;
+using namespace css::sheet;
+using namespace css::text;
+using namespace css::drawing;
+using namespace css::graphic;
+#if ENABLE_QRCODEGEN
+using namespace qrcodegen;
+#endif
+
+QrCodeGenDialog::QrCodeGenDialog(weld::Widget* pParent, Reference<XModel> xModel,
+ bool bEditExisting)
+ : GenericDialogController(pParent, "cui/ui/qrcodegen.ui", "QrCodeGenDialog")
+ , m_xModel(std::move(xModel))
+ , m_xEdittext(m_xBuilder->weld_entry("edit_text"))
+ , m_xECC{ m_xBuilder->weld_radio_button("button_low"),
+ m_xBuilder->weld_radio_button("button_medium"),
+ m_xBuilder->weld_radio_button("button_quartile"),
+ m_xBuilder->weld_radio_button("button_high") }
+ , m_xSpinBorder(m_xBuilder->weld_spin_button("edit_border"))
+#if ENABLE_QRCODEGEN
+ , mpParent(pParent)
+#endif
+{
+ if (!bEditExisting)
+ {
+ // TODO: This only works in Writer doc. Should also work in shapes
+ Reference<XIndexAccess> xSelections(m_xModel->getCurrentSelection(), UNO_QUERY);
+ if (xSelections.is())
+ {
+ Reference<XTextRange> xSelection(xSelections->getByIndex(0), UNO_QUERY);
+ if (xSelection.is())
+ m_xEdittext->set_text(xSelection->getString());
+ }
+ return;
+ }
+
+ Reference<container::XIndexAccess> xIndexAccess(m_xModel->getCurrentSelection(),
+ UNO_QUERY_THROW);
+ Reference<XPropertySet> xProps(xIndexAccess->getByIndex(0), UNO_QUERY_THROW);
+
+ // Read properties from selected QR Code
+ css::drawing::QRCode aQRCode;
+ xProps->getPropertyValue("QRCodeProperties") >>= aQRCode;
+
+ m_xEdittext->set_text(aQRCode.Payload);
+
+ //Get Error Correction Constant from selected QR Code
+ GetErrorCorrection(aQRCode.ErrorCorrection);
+
+ m_xSpinBorder->set_value(aQRCode.Border);
+
+ // Mark this as existing shape
+ m_xExistingShapeProperties = xProps;
+}
+
+short QrCodeGenDialog::run()
+{
+#if ENABLE_QRCODEGEN
+ short nRet;
+ while (true)
+ {
+ nRet = GenericDialogController::run();
+ if (nRet == RET_OK)
+ {
+ try
+ {
+ Apply();
+ break;
+ }
+ catch (const qrcodegen::data_too_long&)
+ {
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(
+ mpParent, VclMessageType::Warning, VclButtonsType::Ok,
+ CuiResId(RID_SVXSTR_QRCODEDATALONG)));
+ xBox->run();
+ }
+ }
+ else
+ break;
+ }
+ return nRet;
+#else
+ return RET_CANCEL;
+#endif
+}
+
+void QrCodeGenDialog::Apply()
+{
+#if ENABLE_QRCODEGEN
+ css::drawing::QRCode aQRCode;
+ aQRCode.Payload = m_xEdittext->get_text();
+
+ bool bLowECCActive(m_xECC[0]->get_active());
+ bool bMediumECCActive(m_xECC[1]->get_active());
+ bool bQuartileECCActive(m_xECC[2]->get_active());
+
+ if (bLowECCActive)
+ {
+ aQRCode.ErrorCorrection = css::drawing::QRCodeErrorCorrection::LOW;
+ }
+ else if (bMediumECCActive)
+ {
+ aQRCode.ErrorCorrection = css::drawing::QRCodeErrorCorrection::MEDIUM;
+ }
+ else if (bQuartileECCActive)
+ {
+ aQRCode.ErrorCorrection = css::drawing::QRCodeErrorCorrection::QUARTILE;
+ }
+ else
+ {
+ aQRCode.ErrorCorrection = css::drawing::QRCodeErrorCorrection::HIGH;
+ }
+
+ aQRCode.Border = m_xSpinBorder->get_value();
+
+ // Read svg and replace placeholder texts
+ OUString aSvgImage = GenerateQRCode(aQRCode.Payload, aQRCode.ErrorCorrection, aQRCode.Border);
+
+ // Insert/Update graphic
+ SvMemoryStream aSvgStream(4096, 4096);
+ aSvgStream.WriteOString(OUStringToOString(aSvgImage, RTL_TEXTENCODING_UTF8));
+ Reference<XInputStream> xInputStream(new utl::OSeekableInputStreamWrapper(aSvgStream));
+ Reference<XComponentContext> xContext(comphelper::getProcessComponentContext());
+ Reference<XGraphicProvider> xProvider = css::graphic::GraphicProvider::create(xContext);
+
+ Sequence<PropertyValue> aMediaProperties(1);
+ aMediaProperties[0].Name = "InputStream";
+ aMediaProperties[0].Value <<= xInputStream;
+ Reference<XGraphic> xGraphic(xProvider->queryGraphic(aMediaProperties));
+
+ bool bIsExistingQRCode = m_xExistingShapeProperties.is();
+ Reference<XPropertySet> xShapeProps;
+ if (bIsExistingQRCode)
+ xShapeProps = m_xExistingShapeProperties;
+ else
+ xShapeProps.set(Reference<lang::XMultiServiceFactory>(m_xModel, UNO_QUERY_THROW)
+ ->createInstance("com.sun.star.drawing.GraphicObjectShape"),
+ UNO_QUERY);
+
+ xShapeProps->setPropertyValue("Graphic", Any(xGraphic));
+
+ // Set QRCode properties
+ xShapeProps->setPropertyValue("QRCodeProperties", Any(aQRCode));
+
+ if (bIsExistingQRCode)
+ return;
+
+ // Default size
+ Reference<XShape> xShape(xShapeProps, UNO_QUERY);
+ awt::Size aShapeSize;
+ aShapeSize.Height = 4000;
+ aShapeSize.Width = 4000;
+ xShape->setSize(aShapeSize);
+
+ // Default anchoring
+ xShapeProps->setPropertyValue("AnchorType", Any(TextContentAnchorType_AT_PARAGRAPH));
+
+ const Reference<XServiceInfo> xServiceInfo(m_xModel, UNO_QUERY_THROW);
+
+ // Writer
+ if (xServiceInfo->supportsService("com.sun.star.text.TextDocument"))
+ {
+ Reference<XTextContent> xTextContent(xShape, UNO_QUERY_THROW);
+ Reference<XTextViewCursorSupplier> xViewCursorSupplier(m_xModel->getCurrentController(),
+ UNO_QUERY_THROW);
+ Reference<XTextViewCursor> xCursor = xViewCursorSupplier->getViewCursor();
+ // use cursor's XText - it might be in table cell, frame, ...
+ Reference<XText> const xText(xCursor->getText());
+ assert(xText.is());
+ xText->insertTextContent(xCursor, xTextContent, true);
+ return;
+ }
+
+ // Calc
+ else if (xServiceInfo->supportsService("com.sun.star.sheet.SpreadsheetDocument"))
+ {
+ Reference<XPropertySet> xSheetCell(m_xModel->getCurrentSelection(), UNO_QUERY_THROW);
+ awt::Point aCellPosition;
+ xSheetCell->getPropertyValue("Position") >>= aCellPosition;
+ xShape->setPosition(aCellPosition);
+
+ Reference<XSpreadsheetView> xView(m_xModel->getCurrentController(), UNO_QUERY_THROW);
+ Reference<XSpreadsheet> xSheet(xView->getActiveSheet(), UNO_SET_THROW);
+ Reference<XDrawPageSupplier> xDrawPageSupplier(xSheet, UNO_QUERY_THROW);
+ Reference<XDrawPage> xDrawPage(xDrawPageSupplier->getDrawPage(), UNO_SET_THROW);
+ Reference<XShapes> xShapes(xDrawPage, UNO_QUERY_THROW);
+
+ xShapes->add(xShape);
+ return;
+ }
+
+ //Impress and Draw
+ else if (xServiceInfo->supportsService("com.sun.star.presentation.PresentationDocument")
+ || xServiceInfo->supportsService("com.sun.star.drawing.DrawingDocument"))
+ {
+ Reference<XDrawView> xView(m_xModel->getCurrentController(), UNO_QUERY_THROW);
+ Reference<XDrawPage> xPage(xView->getCurrentPage(), UNO_SET_THROW);
+ Reference<XShapes> xShapes(xPage, UNO_QUERY_THROW);
+
+ xShapes->add(xShape);
+ return;
+ }
+
+ else
+ {
+ //Not implemented for math,base and other apps.
+ throw uno::RuntimeException("Not implemented");
+ }
+#endif
+}
+
+OUString QrCodeGenDialog::GenerateQRCode(OUString aQRText, long aQRECC, int aQRBorder)
+{
+#if ENABLE_QRCODEGEN
+ //Select ECC:: value from aQrECC
+ qrcodegen::QrCode::Ecc bqrEcc = qrcodegen::QrCode::Ecc::LOW;
+
+ switch (aQRECC)
+ {
+ case 1:
+ {
+ bqrEcc = qrcodegen::QrCode::Ecc::LOW;
+ break;
+ }
+ case 2:
+ {
+ bqrEcc = qrcodegen::QrCode::Ecc::MEDIUM;
+ break;
+ }
+ case 3:
+ {
+ bqrEcc = qrcodegen::QrCode::Ecc::QUARTILE;
+ break;
+ }
+ case 4:
+ {
+ bqrEcc = qrcodegen::QrCode::Ecc::HIGH;
+ break;
+ }
+ }
+
+ //OuString to char* qrtext
+ OString o = OUStringToOString(aQRText, RTL_TEXTENCODING_UTF8);
+ const char* qrtext = o.pData->buffer;
+
+ // From QR Code library
+ qrcodegen::QrCode qr0 = qrcodegen::QrCode::encodeText(qrtext, bqrEcc);
+ std::string svg = qr0.toSvgString(aQRBorder);
+ //cstring to OUString
+ return OUString::createFromAscii(svg.c_str());
+#else
+ (void)aQRText;
+ (void)aQRECC;
+ (void)aQRBorder;
+ return OUString();
+#endif
+}
+
+void QrCodeGenDialog::GetErrorCorrection(long ErrorCorrection)
+{
+ switch (ErrorCorrection)
+ {
+ case css::drawing::QRCodeErrorCorrection::LOW:
+ {
+ m_xECC[0]->set_active(true);
+ break;
+ }
+ case css::drawing::QRCodeErrorCorrection::MEDIUM:
+ {
+ m_xECC[1]->set_active(true);
+ break;
+ }
+ case css::drawing::QRCodeErrorCorrection::QUARTILE:
+ {
+ m_xECC[2]->set_active(true);
+ break;
+ }
+ case css::drawing::QRCodeErrorCorrection::HIGH:
+ {
+ m_xECC[3]->set_active(true);
+ break;
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/cui/source/dialogs/SignSignatureLineDialog.cxx b/cui/source/dialogs/SignSignatureLineDialog.cxx
new file mode 100644
index 000000000..10f80f729
--- /dev/null
+++ b/cui/source/dialogs/SignSignatureLineDialog.cxx
@@ -0,0 +1,293 @@
+/* -*- 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/.
+ */
+
+#include <SignSignatureLineDialog.hxx>
+
+#include <sal/log.hxx>
+#include <sal/types.h>
+
+#include <dialmgr.hxx>
+#include <strings.hrc>
+
+#include <comphelper/graphicmimetype.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/xmlsechelper.hxx>
+#include <comphelper/storagehelper.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/docfilt.hxx>
+#include <sfx2/objsh.hxx>
+#include <svx/xoutbmp.hxx>
+#include <tools/date.hxx>
+#include <tools/stream.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <unotools/streamwrap.hxx>
+#include <unotools/syslocale.hxx>
+#include <utility>
+#include <vcl/graph.hxx>
+#include <vcl/weld.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/graphic/GraphicProvider.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+#include <com/sun/star/graphic/XGraphicProvider.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/security/CertificateKind.hpp>
+#include <com/sun/star/security/DocumentDigitalSignatures.hpp>
+#include <com/sun/star/security/XCertificate.hpp>
+#include <com/sun/star/security/XDocumentDigitalSignatures.hpp>
+#include <com/sun/star/ui/dialogs/FilePicker.hpp>
+#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
+#include <com/sun/star/ui/dialogs/XFilePicker3.hpp>
+
+using namespace comphelper;
+using namespace css;
+using namespace css::uno;
+using namespace css::beans;
+using namespace css::frame;
+using namespace css::io;
+using namespace css::lang;
+using namespace css::frame;
+using namespace css::text;
+using namespace css::graphic;
+using namespace css::security;
+using namespace css::ui::dialogs;
+
+SignSignatureLineDialog::SignSignatureLineDialog(weld::Widget* pParent, Reference<XModel> xModel)
+ : SignatureLineDialogBase(pParent, std::move(xModel), "cui/ui/signsignatureline.ui",
+ "SignSignatureLineDialog")
+ , m_xEditName(m_xBuilder->weld_entry("edit_name"))
+ , m_xEditComment(m_xBuilder->weld_text_view("edit_comment"))
+ , m_xBtnLoadImage(m_xBuilder->weld_button("btn_load_image"))
+ , m_xBtnClearImage(m_xBuilder->weld_button("btn_clear_image"))
+ , m_xBtnChooseCertificate(m_xBuilder->weld_button("btn_select_certificate"))
+ , m_xBtnSign(m_xBuilder->weld_button("ok"))
+ , m_xLabelHint(m_xBuilder->weld_label("label_hint"))
+ , m_xLabelHintText(m_xBuilder->weld_label("label_hint_text"))
+ , m_xLabelAddComment(m_xBuilder->weld_label("label_add_comment"))
+ , m_bShowSignDate(false)
+{
+ Reference<container::XIndexAccess> xIndexAccess(m_xModel->getCurrentSelection(),
+ UNO_QUERY_THROW);
+ m_xShapeProperties.set(xIndexAccess->getByIndex(0), UNO_QUERY_THROW);
+
+ bool bIsSignatureLine(false);
+ m_xShapeProperties->getPropertyValue("IsSignatureLine") >>= bIsSignatureLine;
+ if (!bIsSignatureLine)
+ {
+ SAL_WARN("cui.dialogs", "No signature line selected!");
+ return;
+ }
+
+ m_xBtnLoadImage->connect_clicked(LINK(this, SignSignatureLineDialog, loadImage));
+ m_xBtnClearImage->connect_clicked(LINK(this, SignSignatureLineDialog, clearImage));
+ m_xBtnChooseCertificate->connect_clicked(
+ LINK(this, SignSignatureLineDialog, chooseCertificate));
+ m_xEditName->connect_changed(LINK(this, SignSignatureLineDialog, entryChanged));
+
+ // Read properties from selected signature line
+ m_xShapeProperties->getPropertyValue("SignatureLineId") >>= m_aSignatureLineId;
+ m_xShapeProperties->getPropertyValue("SignatureLineSuggestedSignerName")
+ >>= m_aSuggestedSignerName;
+ m_xShapeProperties->getPropertyValue("SignatureLineSuggestedSignerTitle")
+ >>= m_aSuggestedSignerTitle;
+ OUString aSigningInstructions;
+ m_xShapeProperties->getPropertyValue("SignatureLineSigningInstructions")
+ >>= aSigningInstructions;
+ m_xShapeProperties->getPropertyValue("SignatureLineShowSignDate") >>= m_bShowSignDate;
+ bool bCanAddComment(false);
+ m_xShapeProperties->getPropertyValue("SignatureLineCanAddComment") >>= bCanAddComment;
+
+ if (aSigningInstructions.isEmpty())
+ {
+ m_xLabelHint->hide();
+ m_xLabelHintText->hide();
+ }
+ else
+ {
+ m_xLabelHintText->set_label(aSigningInstructions);
+ }
+
+ if (bCanAddComment)
+ {
+ m_xEditComment->set_size_request(m_xEditComment->get_approximate_digit_width() * 48,
+ m_xEditComment->get_text_height() * 5);
+ }
+ else
+ {
+ m_xLabelAddComment->hide();
+ m_xEditComment->hide();
+ m_xEditComment->set_size_request(0, 0);
+ }
+
+ ValidateFields();
+}
+
+IMPL_LINK_NOARG(SignSignatureLineDialog, loadImage, weld::Button&, void)
+{
+ Reference<XComponentContext> xContext = comphelper::getProcessComponentContext();
+ Reference<XFilePicker3> xFilePicker
+ = FilePicker::createWithMode(xContext, TemplateDescription::FILEOPEN_PREVIEW);
+ if (!xFilePicker->execute())
+ return;
+
+ Sequence<OUString> aSelectedFiles = xFilePicker->getSelectedFiles();
+ if (!aSelectedFiles.hasElements())
+ return;
+
+ Reference<XGraphicProvider> xProvider = GraphicProvider::create(xContext);
+ Sequence<PropertyValue> aMediaProperties(1);
+ aMediaProperties[0].Name = "URL";
+ aMediaProperties[0].Value <<= aSelectedFiles[0];
+ m_xSignatureImage = xProvider->queryGraphic(aMediaProperties);
+ m_sOriginalImageBtnLabel = m_xBtnLoadImage->get_label();
+
+ INetURLObject aObj(aSelectedFiles[0]);
+ m_xBtnLoadImage->set_label(aObj.GetLastName());
+
+ ValidateFields();
+}
+
+IMPL_LINK_NOARG(SignSignatureLineDialog, clearImage, weld::Button&, void)
+{
+ m_xSignatureImage.set(nullptr);
+ m_xBtnLoadImage->set_label(m_sOriginalImageBtnLabel);
+ ValidateFields();
+}
+
+IMPL_LINK_NOARG(SignSignatureLineDialog, chooseCertificate, weld::Button&, void)
+{
+ // Document needs to be saved before selecting a certificate
+ SfxObjectShell* pShell = SfxObjectShell::Current();
+ if (!pShell->PrepareForSigning(m_xDialog.get()))
+ return;
+
+ Reference<XDocumentDigitalSignatures> xSigner;
+ if (pShell->GetMedium()->GetFilter()->IsAlienFormat())
+ {
+ xSigner
+ = DocumentDigitalSignatures::createDefault(comphelper::getProcessComponentContext());
+ }
+ else
+ {
+ OUString const aODFVersion(
+ comphelper::OStorageHelper::GetODFVersionFromStorage(pShell->GetStorage()));
+ xSigner = DocumentDigitalSignatures::createWithVersion(
+ comphelper::getProcessComponentContext(), aODFVersion);
+ }
+ xSigner->setParentWindow(m_xDialog->GetXWindow());
+ OUString aDescription;
+ CertificateKind certificateKind = CertificateKind_NONE;
+ // When signing ooxml, we only want X.509 certificates
+ if (pShell->GetMedium()->GetFilter()->IsAlienFormat())
+ certificateKind = CertificateKind_X509;
+ Reference<XCertificate> xSignCertificate
+ = xSigner->selectSigningCertificateWithType(certificateKind, aDescription);
+
+ if (xSignCertificate.is())
+ {
+ m_xSelectedCertifate = xSignCertificate;
+ m_xBtnChooseCertificate->set_label(xmlsec::GetContentPart(
+ xSignCertificate->getSubjectName(), xSignCertificate->getCertificateKind()));
+ }
+ ValidateFields();
+}
+
+IMPL_LINK_NOARG(SignSignatureLineDialog, entryChanged, weld::Entry&, void) { ValidateFields(); }
+
+void SignSignatureLineDialog::ValidateFields()
+{
+ bool bEnableSignBtn = m_xSelectedCertifate.is()
+ && (!m_xEditName->get_text().isEmpty() || m_xSignatureImage.is());
+ m_xBtnSign->set_sensitive(bEnableSignBtn);
+
+ m_xEditName->set_sensitive(!m_xSignatureImage.is());
+ m_xBtnLoadImage->set_sensitive(m_xEditName->get_text().isEmpty());
+ m_xBtnClearImage->set_sensitive(m_xSignatureImage.is());
+}
+
+void SignSignatureLineDialog::Apply()
+{
+ if (!m_xSelectedCertifate.is())
+ {
+ SAL_WARN("cui.dialogs", "No certificate selected!");
+ return;
+ }
+
+ SfxObjectShell* pShell = SfxObjectShell::Current();
+ Reference<XGraphic> xValidGraphic = getSignedGraphic(true);
+ Reference<XGraphic> xInvalidGraphic = getSignedGraphic(false);
+ pShell->SignSignatureLine(m_xDialog.get(), m_aSignatureLineId, m_xSelectedCertifate,
+ xValidGraphic, xInvalidGraphic, m_xEditComment->get_text());
+}
+
+css::uno::Reference<css::graphic::XGraphic> SignSignatureLineDialog::getSignedGraphic(bool bValid)
+{
+ // Read svg and replace placeholder texts
+ OUString aSvgImage(getSignatureImage());
+ aSvgImage = aSvgImage.replaceAll("[SIGNER_NAME]", getCDataString(m_aSuggestedSignerName));
+ aSvgImage = aSvgImage.replaceAll("[SIGNER_TITLE]", getCDataString(m_aSuggestedSignerTitle));
+
+ OUString aIssuerLine
+ = CuiResId(RID_SVXSTR_SIGNATURELINE_SIGNED_BY)
+ .replaceFirst("%1",
+ xmlsec::GetContentPart(m_xSelectedCertifate->getSubjectName(),
+ m_xSelectedCertifate->getCertificateKind()));
+ aSvgImage = aSvgImage.replaceAll("[SIGNED_BY]", getCDataString(aIssuerLine));
+ if (bValid)
+ aSvgImage = aSvgImage.replaceAll("[INVALID_SIGNATURE]", "");
+
+ OUString aDate;
+ if (m_bShowSignDate && bValid)
+ {
+ const SvtSysLocale aSysLocale;
+ const LocaleDataWrapper& rLocaleData = aSysLocale.GetLocaleData();
+ Date aDateTime(Date::SYSTEM);
+ aDate = rLocaleData.getDate(aDateTime);
+ }
+ aSvgImage = aSvgImage.replaceAll("[DATE]", aDate);
+
+ // Custom signature image
+ if (m_xSignatureImage.is())
+ {
+ OUString aGraphicInBase64;
+ Graphic aGraphic(m_xSignatureImage);
+ if (!XOutBitmap::GraphicToBase64(aGraphic, aGraphicInBase64, false))
+ SAL_WARN("cui.dialogs", "Could not convert graphic to base64");
+
+ OUString aImagePart = "<image y=\"825\" x=\"1300\" "
+ "xlink:href=\"data:[MIMETYPE];base64,[BASE64_IMG]>\" "
+ "preserveAspectRatio=\"xMidYMid\" height=\"1520\" "
+ "width=\"7600\" />";
+ aImagePart = aImagePart.replaceAll(
+ "[MIMETYPE]", GraphicMimeTypeHelper::GetMimeTypeForXGraphic(m_xSignatureImage));
+ aImagePart = aImagePart.replaceAll("[BASE64_IMG]", aGraphicInBase64);
+ aSvgImage = aSvgImage.replaceAll("[SIGNATURE_IMAGE]", aImagePart);
+
+ aSvgImage = aSvgImage.replaceAll("[SIGNATURE]", "");
+ }
+ else
+ {
+ aSvgImage = aSvgImage.replaceAll("[SIGNATURE_IMAGE]", "");
+ aSvgImage = aSvgImage.replaceAll("[SIGNATURE]", getCDataString(m_xEditName->get_text()));
+ }
+
+ // Create graphic
+ SvMemoryStream aSvgStream(4096, 4096);
+ aSvgStream.WriteOString(OUStringToOString(aSvgImage, RTL_TEXTENCODING_UTF8));
+ Reference<XInputStream> xInputStream(new utl::OSeekableInputStreamWrapper(aSvgStream));
+ Reference<XComponentContext> xContext(comphelper::getProcessComponentContext());
+ Reference<XGraphicProvider> xProvider = css::graphic::GraphicProvider::create(xContext);
+
+ Sequence<PropertyValue> aMediaProperties(1);
+ aMediaProperties[0].Name = "InputStream";
+ aMediaProperties[0].Value <<= xInputStream;
+ return xProvider->queryGraphic(aMediaProperties);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/cui/source/dialogs/SignatureLineDialog.cxx b/cui/source/dialogs/SignatureLineDialog.cxx
new file mode 100644
index 000000000..e295e288e
--- /dev/null
+++ b/cui/source/dialogs/SignatureLineDialog.cxx
@@ -0,0 +1,210 @@
+/* -*- 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/.
+ */
+
+#include <SignatureLineDialog.hxx>
+
+#include <comphelper/processfactory.hxx>
+#include <comphelper/xmltools.hxx>
+#include <tools/stream.hxx>
+#include <unotools/streamwrap.hxx>
+#include <utility>
+#include <vcl/weld.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <com/sun/star/drawing/XShape.hpp>
+#include <com/sun/star/graphic/GraphicProvider.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+#include <com/sun/star/graphic/XGraphicProvider.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/sheet/XSpreadsheet.hpp>
+#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
+#include <com/sun/star/sheet/XSpreadsheetView.hpp>
+#include <com/sun/star/text/TextContentAnchorType.hpp>
+#include <com/sun/star/text/XTextContent.hpp>
+#include <com/sun/star/text/XTextDocument.hpp>
+#include <com/sun/star/text/XTextViewCursor.hpp>
+#include <com/sun/star/text/XTextViewCursorSupplier.hpp>
+
+using namespace css;
+using namespace css::uno;
+using namespace css::beans;
+using namespace css::container;
+using namespace css::frame;
+using namespace css::io;
+using namespace css::lang;
+using namespace css::frame;
+using namespace css::sheet;
+using namespace css::text;
+using namespace css::drawing;
+using namespace css::graphic;
+
+SignatureLineDialog::SignatureLineDialog(weld::Widget* pParent, Reference<XModel> xModel,
+ bool bEditExisting)
+ : SignatureLineDialogBase(pParent, std::move(xModel), "cui/ui/signatureline.ui",
+ "SignatureLineDialog")
+ , m_xEditName(m_xBuilder->weld_entry("edit_name"))
+ , m_xEditTitle(m_xBuilder->weld_entry("edit_title"))
+ , m_xEditEmail(m_xBuilder->weld_entry("edit_email"))
+ , m_xEditInstructions(m_xBuilder->weld_text_view("edit_instructions"))
+ , m_xCheckboxCanAddComments(m_xBuilder->weld_check_button("checkbox_can_add_comments"))
+ , m_xCheckboxShowSignDate(m_xBuilder->weld_check_button("checkbox_show_sign_date"))
+{
+ m_xEditInstructions->set_size_request(m_xEditInstructions->get_approximate_digit_width() * 48,
+ m_xEditInstructions->get_text_height() * 5);
+
+ // No signature line selected - start with empty dialog and set some default values
+ if (!bEditExisting)
+ {
+ m_xCheckboxCanAddComments->set_active(true);
+ m_xCheckboxShowSignDate->set_active(true);
+ return;
+ }
+
+ Reference<container::XIndexAccess> xIndexAccess(m_xModel->getCurrentSelection(),
+ UNO_QUERY_THROW);
+ Reference<XPropertySet> xProps(xIndexAccess->getByIndex(0), UNO_QUERY_THROW);
+
+ // Read properties from selected signature line
+ xProps->getPropertyValue("SignatureLineId") >>= m_aSignatureLineId;
+ OUString aSuggestedSignerName;
+ xProps->getPropertyValue("SignatureLineSuggestedSignerName") >>= aSuggestedSignerName;
+ m_xEditName->set_text(aSuggestedSignerName);
+ OUString aSuggestedSignerTitle;
+ xProps->getPropertyValue("SignatureLineSuggestedSignerTitle") >>= aSuggestedSignerTitle;
+ m_xEditTitle->set_text(aSuggestedSignerTitle);
+ OUString aSuggestedSignerEmail;
+ xProps->getPropertyValue("SignatureLineSuggestedSignerEmail") >>= aSuggestedSignerEmail;
+ m_xEditEmail->set_text(aSuggestedSignerEmail);
+ OUString aSigningInstructions;
+ xProps->getPropertyValue("SignatureLineSigningInstructions") >>= aSigningInstructions;
+ m_xEditInstructions->set_text(aSigningInstructions);
+ bool bCanAddComments = false;
+ xProps->getPropertyValue("SignatureLineCanAddComment") >>= bCanAddComments;
+ m_xCheckboxCanAddComments->set_active(bCanAddComments);
+ bool bShowSignDate = false;
+ xProps->getPropertyValue("SignatureLineShowSignDate") >>= bShowSignDate;
+ m_xCheckboxShowSignDate->set_active(bShowSignDate);
+
+ // Mark this as existing shape
+ m_xExistingShapeProperties = xProps;
+}
+
+void SignatureLineDialog::Apply()
+{
+ if (m_aSignatureLineId.isEmpty())
+ m_aSignatureLineId
+ = OStringToOUString(comphelper::xml::generateGUIDString(), RTL_TEXTENCODING_ASCII_US);
+ OUString aSignerName(m_xEditName->get_text());
+ OUString aSignerTitle(m_xEditTitle->get_text());
+ OUString aSignerEmail(m_xEditEmail->get_text());
+ OUString aSigningInstructions(m_xEditInstructions->get_text());
+ bool bCanAddComments(m_xCheckboxCanAddComments->get_active());
+ bool bShowSignDate(m_xCheckboxShowSignDate->get_active());
+
+ // Read svg and replace placeholder texts
+ OUString aSvgImage(getSignatureImage());
+ aSvgImage = aSvgImage.replaceAll("[SIGNER_NAME]", getCDataString(aSignerName));
+ aSvgImage = aSvgImage.replaceAll("[SIGNER_TITLE]", getCDataString(aSignerTitle));
+
+ // These are only filled if the signature line is signed.
+ aSvgImage = aSvgImage.replaceAll("[SIGNATURE]", "");
+ aSvgImage = aSvgImage.replaceAll("[SIGNED_BY]", "");
+ aSvgImage = aSvgImage.replaceAll("[INVALID_SIGNATURE]", "");
+ aSvgImage = aSvgImage.replaceAll("[DATE]", "");
+
+ // Insert/Update graphic
+ SvMemoryStream aSvgStream(4096, 4096);
+ aSvgStream.WriteOString(OUStringToOString(aSvgImage, RTL_TEXTENCODING_UTF8));
+ Reference<XInputStream> xInputStream(new utl::OSeekableInputStreamWrapper(aSvgStream));
+ Reference<XComponentContext> xContext(comphelper::getProcessComponentContext());
+ Reference<XGraphicProvider> xProvider = css::graphic::GraphicProvider::create(xContext);
+
+ Sequence<PropertyValue> aMediaProperties(1);
+ aMediaProperties[0].Name = "InputStream";
+ aMediaProperties[0].Value <<= xInputStream;
+ Reference<XGraphic> xGraphic(xProvider->queryGraphic(aMediaProperties));
+
+ bool bIsExistingSignatureLine = m_xExistingShapeProperties.is();
+ Reference<XPropertySet> xShapeProps;
+ if (bIsExistingSignatureLine)
+ xShapeProps = m_xExistingShapeProperties;
+ else
+ xShapeProps.set(Reference<lang::XMultiServiceFactory>(m_xModel, UNO_QUERY_THROW)
+ ->createInstance("com.sun.star.drawing.GraphicObjectShape"),
+ UNO_QUERY);
+
+ xShapeProps->setPropertyValue("Graphic", Any(xGraphic));
+ xShapeProps->setPropertyValue("SignatureLineUnsignedImage", Any(xGraphic));
+
+ // Set signature line properties
+ xShapeProps->setPropertyValue("IsSignatureLine", Any(true));
+ xShapeProps->setPropertyValue("SignatureLineId", Any(m_aSignatureLineId));
+ if (!aSignerName.isEmpty())
+ xShapeProps->setPropertyValue("SignatureLineSuggestedSignerName", Any(aSignerName));
+ if (!aSignerTitle.isEmpty())
+ xShapeProps->setPropertyValue("SignatureLineSuggestedSignerTitle", Any(aSignerTitle));
+ if (!aSignerEmail.isEmpty())
+ xShapeProps->setPropertyValue("SignatureLineSuggestedSignerEmail", Any(aSignerEmail));
+ if (!aSigningInstructions.isEmpty())
+ xShapeProps->setPropertyValue("SignatureLineSigningInstructions",
+ Any(aSigningInstructions));
+ xShapeProps->setPropertyValue("SignatureLineShowSignDate", Any(bShowSignDate));
+ xShapeProps->setPropertyValue("SignatureLineCanAddComment", Any(bCanAddComments));
+
+ if (bIsExistingSignatureLine)
+ return;
+
+ // Default size
+ Reference<XShape> xShape(xShapeProps, UNO_QUERY);
+ awt::Size aShapeSize;
+ aShapeSize.Height = 3000;
+ aShapeSize.Width = 6000;
+ xShape->setSize(aShapeSize);
+
+ // Default anchoring
+ xShapeProps->setPropertyValue("AnchorType", Any(TextContentAnchorType_AT_PARAGRAPH));
+
+ // Writer
+ const Reference<XTextDocument> xTextDocument(m_xModel, UNO_QUERY);
+ if (xTextDocument.is())
+ {
+ Reference<XTextContent> xTextContent(xShape, UNO_QUERY_THROW);
+ Reference<XTextViewCursorSupplier> xViewCursorSupplier(m_xModel->getCurrentController(),
+ UNO_QUERY_THROW);
+ Reference<XTextViewCursor> xCursor = xViewCursorSupplier->getViewCursor();
+ // use cursor's XText - it might be in table cell, frame, ...
+ Reference<XText> const xText(xCursor->getText());
+ assert(xText.is());
+ xText->insertTextContent(xCursor, xTextContent, true);
+ return;
+ }
+
+ // Calc
+ const Reference<XSpreadsheetDocument> xSpreadsheetDocument(m_xModel, UNO_QUERY);
+ if (!xSpreadsheetDocument.is())
+ return;
+
+ Reference<XPropertySet> xSheetCell(m_xModel->getCurrentSelection(), UNO_QUERY_THROW);
+ awt::Point aCellPosition;
+ xSheetCell->getPropertyValue("Position") >>= aCellPosition;
+ xShape->setPosition(aCellPosition);
+
+ Reference<XSpreadsheetView> xView(m_xModel->getCurrentController(), UNO_QUERY_THROW);
+ Reference<XSpreadsheet> xSheet(xView->getActiveSheet(), UNO_SET_THROW);
+ Reference<XDrawPageSupplier> xDrawPageSupplier(xSheet, UNO_QUERY_THROW);
+ Reference<XDrawPage> xDrawPage(xDrawPageSupplier->getDrawPage(), UNO_SET_THROW);
+ Reference<XShapes> xShapes(xDrawPage, UNO_QUERY_THROW);
+
+ xShapes->add(xShape);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/cui/source/dialogs/SignatureLineDialogBase.cxx b/cui/source/dialogs/SignatureLineDialogBase.cxx
new file mode 100644
index 000000000..4dadbf68e
--- /dev/null
+++ b/cui/source/dialogs/SignatureLineDialogBase.cxx
@@ -0,0 +1,221 @@
+/* -*- 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/.
+ */
+
+#include <SignatureLineDialogBase.hxx>
+
+#include <utility>
+#include <vcl/weld.hxx>
+
+using namespace css;
+using namespace css::uno;
+using namespace css::frame;
+
+SignatureLineDialogBase::SignatureLineDialogBase(weld::Widget* pParent, Reference<XModel> xModel,
+ const OUString& rUIFile, const OString& rDialogId)
+ : GenericDialogController(pParent, rUIFile, rDialogId)
+ , m_xModel(std::move(xModel))
+{
+}
+
+short SignatureLineDialogBase::run()
+{
+ short nRet = GenericDialogController::run();
+ if (nRet == RET_OK)
+ Apply();
+ return nRet;
+}
+
+OUString SignatureLineDialogBase::getCDataString(const OUString& rString)
+{
+ return "<![CDATA[" + rString + "]]>";
+}
+
+OUString SignatureLineDialogBase::getSignatureImage()
+{
+ OUString const svg(
+ "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?><svg "
+ "xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:cc=\"http://creativecommons.org/ns#\" "
+ "xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\" "
+ "xmlns:svg=\"http://www.w3.org/2000/svg\" xmlns=\"http://www.w3.org/2000/svg\" "
+ "xmlns:sodipodi=\"http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd\" "
+ "xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" version=\"1.2\" "
+ "width=\"90mm\" height=\"45mm\" viewBox=\"0 0 9000 4500\" preserveAspectRatio=\"xMidYMid\" "
+ "fill-rule=\"evenodd\" stroke-width=\"28.222\" stroke-linejoin=\"round\" "
+ "xml:space=\"preserve\" id=\"svg577\" inkscape:version=\"0.92.2 (5c3e80d, "
+ "2017-08-06)\"><metadata id=\"metadata581\"><rdf:RDF><cc:Work "
+ "rdf:about=\"\"><dc:format>image/svg+xml</dc:format><dc:type "
+ "rdf:resource=\"http://purl.org/dc/dcmitype/StillImage\" /><dc:title "
+ "/></cc:Work></rdf:RDF></metadata><sodipodi:namedview pagecolor=\"#ffffff\" "
+ "bordercolor=\"#666666\" borderopacity=\"1\" objecttolerance=\"10\" gridtolerance=\"10\" "
+ "guidetolerance=\"10\" inkscape:pageopacity=\"0\" inkscape:pageshadow=\"2\" "
+ "inkscape:window-width=\"1865\" inkscape:window-height=\"1145\" id=\"namedview579\" "
+ "showgrid=\"false\" inkscape:zoom=\"3.6100926\" inkscape:cx=\"231.72208\" "
+ "inkscape:cy=\"122.80267\" inkscape:window-x=\"55\" inkscape:window-y=\"27\" "
+ "inkscape:window-maximized=\"1\" inkscape:current-layer=\"g575\" "
+ "inkscape:pagecheckerboard=\"false\" /><defs class=\"ClipPathGroup\" "
+ "id=\"defs8\"><clipPath id=\"presentation_clip_path\" "
+ "clipPathUnits=\"userSpaceOnUse\"><rect x=\"0\" y=\"0\" width=\"9000\" height=\"4500\" "
+ "id=\"rect2\" /></clipPath></defs><defs id=\"defs49\" /><defs id=\"defs86\" /><defs "
+ "class=\"TextShapeIndex\" id=\"defs90\" /><defs class=\"EmbeddedBulletChars\" "
+ "id=\"defs122\" /><defs class=\"TextEmbeddedBitmaps\" id=\"defs124\" /><g id=\"g129\"><g "
+ "id=\"id2\" class=\"Master_Slide\"><g id=\"bg-id2\" class=\"Background\" /><g "
+ "id=\"bo-id2\" class=\"BackgroundObjects\" /></g></g><g class=\"SlideGroup\" "
+ "id=\"g575\"><g id=\"g573\"><g id=\"container-id1\"><g id=\"id1\" class=\"Slide\" "
+ "clip-path=\"url(#presentation_clip_path)\"><g class=\"Page\" id=\"g569\"><g "
+ "class=\"com.sun.star.drawing.LineShape\" id=\"g154\"><g id=\"id3\"><rect "
+ "class=\"BoundingBox\" stroke=\"none\" fill=\"none\" x=\"-27\" y=\"2373\" width=\"9055\" "
+ "height=\"55\" id=\"rect131\" /><desc id=\"desc133\">150</desc><desc "
+ "id=\"desc135\">139</desc><desc id=\"desc137\">132</desc><desc id=\"desc139\">512: "
+ "XPATHSTROKE_SEQ_BEGIN</desc><desc id=\"desc141\">132</desc><desc "
+ "id=\"desc143\">133</desc><desc id=\"desc145\">109</desc><path fill=\"none\" "
+ "stroke=\"rgb(0,0,0)\" stroke-width=\"53\" stroke-linejoin=\"round\" d=\"M 0,2400 L "
+ "9000,2400\" id=\"path147\" /><desc id=\"desc149\">512: XPATHSTROKE_SEQ_END</desc><desc "
+ "id=\"desc151\">140</desc></g></g><g class=\"com.sun.star.drawing.ClosedBezierShape\" "
+ "id=\"g173\"><g id=\"id4\"><rect class=\"BoundingBox\" stroke=\"none\" fill=\"none\" "
+ "x=\"301\" y=\"1400\" width=\"801\" height=\"801\" id=\"rect156\" /><desc "
+ "id=\"desc158\">150</desc><desc id=\"desc160\">139</desc><desc "
+ "id=\"desc162\">133</desc><desc id=\"desc164\">132</desc><desc "
+ "id=\"desc166\">111</desc><path fill=\"rgb(0,0,0)\" stroke=\"none\" d=\"M 969,2200 C "
+ "880,2083 792,1967 704,1850 614,1967 523,2083 433,2200 389,2200 345,2200 301,2200 413,2061 "
+ "525,1923 637,1784 533,1656 430,1528 327,1400 371,1400 415,1400 459,1400 541,1505 623,1609 "
+ "704,1714 784,1609 863,1505 943,1400 987,1400 1031,1400 1075,1400 975,1527 874,1653 "
+ "773,1780 882,1920 992,2060 1101,2200 1057,2200 1013,2200 969,2200 Z\" id=\"path168\" "
+ "/><desc id=\"desc170\">140</desc></g></g><g class=\"com.sun.star.drawing.TextShape\" "
+ "id=\"g236\"><g id=\"id5\"><rect class=\"BoundingBox\" stroke=\"none\" fill=\"none\" "
+ "x=\"1300\" y=\"1500\" width=\"8001\" height=\"925\" id=\"rect175\" /><desc "
+ "id=\"desc177\">150</desc><desc id=\"desc179\">512: XTEXT_PAINTSHAPE_BEGIN</desc><text "
+ "class=\"TextShape\" id=\"text233\"><desc class=\"Paragraph\" id=\"desc181\" /><tspan "
+ "class=\"TextParagraph\" font-family=\"Liberation Sans, sans-serif\" font-size=\"600px\" "
+ "font-weight=\"400\" id=\"tspan231\"><desc id=\"desc183\">138</desc><desc "
+ "id=\"desc185\">136</desc><desc id=\"desc187\">135</desc><desc "
+ "id=\"desc189\">134</desc><desc id=\"desc191\">113</desc><desc class=\"TextPortion\" "
+ "id=\"desc193\">type: Text; content: [SIGNATURE]; </desc><tspan class=\"TextPosition\" "
+ "x=\"1550\" y=\"2171\" id=\"tspan229\"><tspan fill=\"rgb(0,0,0)\" stroke=\"none\" "
+ "id=\"tspan195\">[SIGNATURE]</tspan><desc id=\"desc197\">512: XTEXT_EOC</desc><desc "
+ "id=\"desc199\">512: XTEXT_EOC</desc><desc id=\"desc201\">512: XTEXT_EOW</desc><desc "
+ "id=\"desc203\">512: XTEXT_EOC</desc><desc id=\"desc205\">512: XTEXT_EOC</desc><desc "
+ "id=\"desc207\">512: XTEXT_EOC</desc><desc id=\"desc209\">512: XTEXT_EOC</desc><desc "
+ "id=\"desc211\">512: XTEXT_EOC</desc><desc id=\"desc213\">512: XTEXT_EOC</desc><desc "
+ "id=\"desc215\">512: XTEXT_EOC</desc><desc id=\"desc217\">512: XTEXT_EOC</desc><desc "
+ "id=\"desc219\">512: XTEXT_EOC</desc><desc id=\"desc221\">512: XTEXT_EOW</desc><desc "
+ "id=\"desc223\">512: XTEXT_EOL</desc><desc id=\"desc225\">512: XTEXT_EOP</desc><desc "
+ "id=\"desc227\">512: XTEXT_PAINTSHAPE_END</desc></tspan></tspan></text></g></g><g "
+ "class=\"com.sun.star.drawing.TextShape\" id=\"g303\"><g id=\"id6\"><rect "
+ "class=\"BoundingBox\" stroke=\"none\" fill=\"none\" x=\"100\" y=\"2500\" width=\"8901\" "
+ "height=\"726\" id=\"rect238\" /><desc id=\"desc240\">150</desc><desc id=\"desc242\">512: "
+ "XTEXT_PAINTSHAPE_BEGIN</desc><text class=\"TextShape\" id=\"text300\"><desc "
+ "class=\"Paragraph\" id=\"desc244\" /><tspan class=\"TextParagraph\" "
+ "font-family=\"Liberation Sans, sans-serif\" font-size=\"423px\" font-weight=\"400\" "
+ "id=\"tspan298\"><desc id=\"desc246\">138</desc><desc id=\"desc248\">136</desc><desc "
+ "id=\"desc250\">135</desc><desc id=\"desc252\">134</desc><desc "
+ "id=\"desc254\">113</desc><desc class=\"TextPortion\" id=\"desc256\">type: Text; content: "
+ "[SIGNER_NAME]; </desc><tspan class=\"TextPosition\" x=\"350\" y=\"3010\" "
+ "id=\"tspan296\"><tspan fill=\"rgb(0,0,0)\" stroke=\"none\" "
+ "id=\"tspan258\">[SIGNER_NAME]</tspan><desc id=\"desc260\">512: XTEXT_EOC</desc><desc "
+ "id=\"desc262\">512: XTEXT_EOC</desc><desc id=\"desc264\">512: XTEXT_EOW</desc><desc "
+ "id=\"desc266\">512: XTEXT_EOC</desc><desc id=\"desc268\">512: XTEXT_EOC</desc><desc "
+ "id=\"desc270\">512: XTEXT_EOC</desc><desc id=\"desc272\">512: XTEXT_EOC</desc><desc "
+ "id=\"desc274\">512: XTEXT_EOC</desc><desc id=\"desc276\">512: XTEXT_EOC</desc><desc "
+ "id=\"desc278\">512: XTEXT_EOC</desc><desc id=\"desc280\">512: XTEXT_EOC</desc><desc "
+ "id=\"desc282\">512: XTEXT_EOC</desc><desc id=\"desc284\">512: XTEXT_EOC</desc><desc "
+ "id=\"desc286\">512: XTEXT_EOC</desc><desc id=\"desc288\">512: XTEXT_EOW</desc><desc "
+ "id=\"desc290\">512: XTEXT_EOL</desc><desc id=\"desc292\">512: XTEXT_EOP</desc><desc "
+ "id=\"desc294\">512: XTEXT_PAINTSHAPE_END</desc></tspan></tspan></text></g></g><g "
+ "class=\"com.sun.star.drawing.TextShape\" id=\"g372\"><g id=\"id7\"><rect "
+ "class=\"BoundingBox\" stroke=\"none\" fill=\"none\" x=\"100\" y=\"3075\" width=\"8901\" "
+ "height=\"726\" id=\"rect305\" /><desc id=\"desc307\">150</desc><desc id=\"desc309\">512: "
+ "XTEXT_PAINTSHAPE_BEGIN</desc><text class=\"TextShape\" id=\"text369\"><desc "
+ "class=\"Paragraph\" id=\"desc311\" /><tspan class=\"TextParagraph\" "
+ "font-family=\"Liberation Sans, sans-serif\" font-size=\"423px\" font-weight=\"400\" "
+ "id=\"tspan367\"><desc id=\"desc313\">138</desc><desc id=\"desc315\">136</desc><desc "
+ "id=\"desc317\">135</desc><desc id=\"desc319\">134</desc><desc "
+ "id=\"desc321\">113</desc><desc class=\"TextPortion\" id=\"desc323\">type: Text; content: "
+ "[SIGNER_TITLE]; </desc><tspan class=\"TextPosition\" x=\"350\" y=\"3585\" "
+ "id=\"tspan365\"><tspan fill=\"rgb(0,0,0)\" stroke=\"none\" "
+ "id=\"tspan325\">[SIGNER_TITLE]</tspan><desc id=\"desc327\">512: XTEXT_EOC</desc><desc "
+ "id=\"desc329\">512: XTEXT_EOC</desc><desc id=\"desc331\">512: XTEXT_EOW</desc><desc "
+ "id=\"desc333\">512: XTEXT_EOC</desc><desc id=\"desc335\">512: XTEXT_EOC</desc><desc "
+ "id=\"desc337\">512: XTEXT_EOC</desc><desc id=\"desc339\">512: XTEXT_EOC</desc><desc "
+ "id=\"desc341\">512: XTEXT_EOC</desc><desc id=\"desc343\">512: XTEXT_EOC</desc><desc "
+ "id=\"desc345\">512: XTEXT_EOC</desc><desc id=\"desc347\">512: XTEXT_EOC</desc><desc "
+ "id=\"desc349\">512: XTEXT_EOC</desc><desc id=\"desc351\">512: XTEXT_EOC</desc><desc "
+ "id=\"desc353\">512: XTEXT_EOC</desc><desc id=\"desc355\">512: XTEXT_EOC</desc><desc "
+ "id=\"desc357\">512: XTEXT_EOW</desc><desc id=\"desc359\">512: XTEXT_EOL</desc><desc "
+ "id=\"desc361\">512: XTEXT_EOP</desc><desc id=\"desc363\">512: "
+ "XTEXT_PAINTSHAPE_END</desc></tspan></tspan></text></g></g><g "
+ "class=\"com.sun.star.drawing.TextShape\" id=\"g435\"><g id=\"id8\"><rect "
+ "class=\"BoundingBox\" stroke=\"none\" fill=\"none\" x=\"100\" y=\"3660\" width=\"8901\" "
+ "height=\"726\" id=\"rect374\" /><desc id=\"desc376\">150</desc><desc id=\"desc378\">512: "
+ "XTEXT_PAINTSHAPE_BEGIN</desc><text class=\"TextShape\" id=\"text432\"><desc "
+ "class=\"Paragraph\" id=\"desc380\" /><tspan class=\"TextParagraph\" "
+ "font-family=\"Liberation Sans, sans-serif\" font-size=\"423px\" font-weight=\"400\" "
+ "id=\"tspan430\"><desc id=\"desc382\">138</desc><desc id=\"desc384\">136</desc><desc "
+ "id=\"desc386\">135</desc><desc id=\"desc388\">134</desc><desc "
+ "id=\"desc390\">113</desc><desc class=\"TextPortion\" id=\"desc392\">type: Text; content: "
+ "[SIGNED_BY]; </desc><tspan class=\"TextPosition\" x=\"350\" y=\"4170\" "
+ "id=\"tspan428\"><tspan fill=\"rgb(0,0,0)\" stroke=\"none\" "
+ "id=\"tspan394\">[SIGNED_BY]</tspan><desc id=\"desc396\">512: XTEXT_EOC</desc><desc "
+ "id=\"desc398\">512: XTEXT_EOC</desc><desc id=\"desc400\">512: XTEXT_EOW</desc><desc "
+ "id=\"desc402\">512: XTEXT_EOC</desc><desc id=\"desc404\">512: XTEXT_EOC</desc><desc "
+ "id=\"desc406\">512: XTEXT_EOC</desc><desc id=\"desc408\">512: XTEXT_EOC</desc><desc "
+ "id=\"desc410\">512: XTEXT_EOC</desc><desc id=\"desc412\">512: XTEXT_EOC</desc><desc "
+ "id=\"desc414\">512: XTEXT_EOC</desc><desc id=\"desc416\">512: XTEXT_EOC</desc><desc "
+ "id=\"desc418\">512: XTEXT_EOC</desc><desc id=\"desc420\">512: XTEXT_EOW</desc><desc "
+ "id=\"desc422\">512: XTEXT_EOL</desc><desc id=\"desc424\">512: XTEXT_EOP</desc><desc "
+ "id=\"desc426\">512: XTEXT_PAINTSHAPE_END</desc></tspan></tspan></text></g></g><g "
+ "class=\"com.sun.star.drawing.TextShape\" id=\"g488\"><g id=\"id9\"><rect "
+ "class=\"BoundingBox\" stroke=\"none\" fill=\"none\" x=\"4800\" y=\"0\" width=\"4201\" "
+ "height=\"726\" id=\"rect437\" /><desc id=\"desc439\">150</desc><desc id=\"desc441\">512: "
+ "XTEXT_PAINTSHAPE_BEGIN</desc><text class=\"TextShape\" id=\"text485\" x=\"2648.345\" "
+ "y=\"0\" style=\"text-align:end;text-anchor:end\"><desc class=\"Paragraph\" id=\"desc443\" "
+ "/><tspan class=\"TextParagraph\" font-size=\"423px\" font-weight=\"400\" id=\"tspan483\" "
+ "style=\"font-weight:400;font-size:423px;font-family:'Liberation Sans', "
+ "sans-serif;text-align:end;text-anchor:end\"><desc id=\"desc445\">138</desc><desc "
+ "id=\"desc447\">136</desc><desc id=\"desc449\">135</desc><desc "
+ "id=\"desc451\">134</desc><desc id=\"desc453\">113</desc><desc class=\"TextPortion\" "
+ "id=\"desc455\">type: Text; content: [DATE]; </desc><tspan class=\"TextPosition\" "
+ "x=\"8792.835\" y=\"510\" id=\"tspan481\" style=\"text-align:end;text-anchor:end\"><tspan "
+ "id=\"tspan457\" "
+ "style=\"text-align:end;text-anchor:end;fill:#000000;stroke:none\">[DATE]</tspan><desc "
+ "id=\"desc459\">512: XTEXT_EOC</desc><desc id=\"desc461\">512: XTEXT_EOC</desc><desc "
+ "id=\"desc463\">512: XTEXT_EOW</desc><desc id=\"desc465\">512: XTEXT_EOC</desc><desc "
+ "id=\"desc467\">512: XTEXT_EOC</desc><desc id=\"desc469\">512: XTEXT_EOC</desc><desc "
+ "id=\"desc471\">512: XTEXT_EOC</desc><desc id=\"desc473\">512: XTEXT_EOW</desc><desc "
+ "id=\"desc475\">512: XTEXT_EOL</desc><desc id=\"desc477\">512: XTEXT_EOP</desc><desc "
+ "id=\"desc479\">512: XTEXT_PAINTSHAPE_END</desc></tspan></tspan></text></g></g><g "
+ "class=\"com.sun.star.drawing.TextShape\" id=\"g567\"><g id=\"id10\"><rect "
+ "class=\"BoundingBox\" stroke=\"none\" fill=\"none\" x=\"0\" y=\"1\" width=\"9001\" "
+ "height=\"726\" id=\"rect490\" /><desc id=\"desc492\">150</desc><desc id=\"desc494\">512: "
+ "XTEXT_PAINTSHAPE_BEGIN</desc><text class=\"TextShape\" id=\"text564\"><desc "
+ "class=\"Paragraph\" id=\"desc496\" /><tspan class=\"TextParagraph\" "
+ "font-family=\"Liberation Sans, sans-serif\" font-size=\"423px\" font-weight=\"700\" "
+ "id=\"tspan562\"><desc id=\"desc498\">138</desc><desc id=\"desc500\">136</desc><desc "
+ "id=\"desc502\">135</desc><desc id=\"desc504\">134</desc><desc "
+ "id=\"desc506\">113</desc><desc class=\"TextPortion\" id=\"desc508\">type: Text; content: "
+ "[INVALID_SIGNATURE]; </desc><tspan class=\"TextPosition\" x=\"2180\" y=\"511\" "
+ "id=\"tspan560\"><tspan fill=\"rgb(239,65,61)\" stroke=\"none\" "
+ "id=\"tspan510\">[INVALID_SIGNATURE]</tspan><desc id=\"desc512\">512: "
+ "XTEXT_EOC</desc><desc id=\"desc514\">512: XTEXT_EOC</desc><desc id=\"desc516\">512: "
+ "XTEXT_EOW</desc><desc id=\"desc518\">512: XTEXT_EOC</desc><desc id=\"desc520\">512: "
+ "XTEXT_EOC</desc><desc id=\"desc522\">512: XTEXT_EOC</desc><desc id=\"desc524\">512: "
+ "XTEXT_EOC</desc><desc id=\"desc526\">512: XTEXT_EOC</desc><desc id=\"desc528\">512: "
+ "XTEXT_EOC</desc><desc id=\"desc530\">512: XTEXT_EOC</desc><desc id=\"desc532\">512: "
+ "XTEXT_EOC</desc><desc id=\"desc534\">512: XTEXT_EOC</desc><desc id=\"desc536\">512: "
+ "XTEXT_EOC</desc><desc id=\"desc538\">512: XTEXT_EOC</desc><desc id=\"desc540\">512: "
+ "XTEXT_EOC</desc><desc id=\"desc542\">512: XTEXT_EOC</desc><desc id=\"desc544\">512: "
+ "XTEXT_EOC</desc><desc id=\"desc546\">512: XTEXT_EOC</desc><desc id=\"desc548\">512: "
+ "XTEXT_EOC</desc><desc id=\"desc550\">512: XTEXT_EOC</desc><desc id=\"desc552\">512: "
+ "XTEXT_EOW</desc><desc id=\"desc554\">512: XTEXT_EOL</desc><desc id=\"desc556\">512: "
+ "XTEXT_EOP</desc><desc id=\"desc558\">512: "
+ "XTEXT_PAINTSHAPE_END</desc></tspan></tspan></text></g></g></g></g></g></"
+ "g>[SIGNATURE_IMAGE]</g></svg>");
+ return svg;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/cui/source/dialogs/SpellAttrib.hxx b/cui/source/dialogs/SpellAttrib.hxx
new file mode 100644
index 000000000..c086fe3d0
--- /dev/null
+++ b/cui/source/dialogs/SpellAttrib.hxx
@@ -0,0 +1,118 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/uno/Sequence.h>
+#include <com/sun/star/lang/Locale.hpp>
+#include <com/sun/star/linguistic2/XProofreader.hpp>
+
+namespace svx{
+struct SpellErrorDescription
+{
+ bool bIsGrammarError;
+ OUString sErrorText;
+ OUString sDialogTitle;
+ OUString sExplanation;
+ OUString sExplanationURL;
+ css::lang::Locale aLocale;
+ css::uno::Reference< css::linguistic2::XProofreader > xGrammarChecker;
+ css::uno::Sequence< OUString > aSuggestions;
+ OUString sRuleId;
+
+ SpellErrorDescription( bool bGrammar,
+ const OUString& rText,
+ const css::lang::Locale& rLocale,
+ const css::uno::Sequence< OUString >& rSuggestions,
+ css::uno::Reference< css::linguistic2::XProofreader > const & rxGrammarChecker,
+ const OUString* pDialogTitle = nullptr,
+ const OUString* pExplanation = nullptr,
+ const OUString* pRuleId = nullptr,
+ const OUString* pExplanationURL = nullptr ) :
+ bIsGrammarError( bGrammar ),
+ sErrorText( rText ),
+ sDialogTitle( ),
+ sExplanation( ),
+ sExplanationURL( ),
+ aLocale( rLocale ),
+ xGrammarChecker( rxGrammarChecker ),
+ aSuggestions( rSuggestions )
+ {
+ if( pDialogTitle )
+ sDialogTitle = *pDialogTitle;
+ if( pExplanation )
+ sExplanation = *pExplanation;
+ if( pExplanationURL )
+ sExplanationURL = *pExplanationURL;
+ if( pRuleId )
+ sRuleId = *pRuleId;
+ };
+
+ SpellErrorDescription()
+ : bIsGrammarError(false)
+ {
+ }
+
+ bool operator==( const SpellErrorDescription& rDesc ) const
+ {
+ return bIsGrammarError == rDesc.bIsGrammarError &&
+ sErrorText == rDesc.sErrorText &&
+ aLocale.Language == rDesc.aLocale.Language &&
+ aLocale.Country == rDesc.aLocale.Country &&
+ aLocale.Variant == rDesc.aLocale.Variant &&
+ aSuggestions == rDesc.aSuggestions &&
+ xGrammarChecker == rDesc.xGrammarChecker &&
+ sDialogTitle == rDesc.sDialogTitle &&
+ sExplanation == rDesc.sExplanation &&
+ sExplanationURL == rDesc.sExplanationURL &&
+ sRuleId == rDesc.sRuleId;
+ }
+
+ css::uno::Sequence<css::uno::Any> toSequence() const
+ {
+ css::uno::Sequence<css::uno::Any> aEntries(9);
+ aEntries[0] <<= bIsGrammarError;
+ aEntries[1] <<= sErrorText;
+ aEntries[2] <<= sDialogTitle;
+ aEntries[3] <<= sExplanation;
+ aEntries[4] <<= sExplanationURL;
+ aEntries[5] <<= aLocale;
+ aEntries[6] <<= xGrammarChecker;
+ aEntries[7] <<= aSuggestions;
+ aEntries[8] <<= sRuleId;
+ return aEntries;
+ }
+
+ void fromSequence(const css::uno::Sequence<css::uno::Any>& rEntries)
+ {
+ rEntries[0] >>= bIsGrammarError;
+ rEntries[1] >>= sErrorText;
+ rEntries[2] >>= sDialogTitle;
+ rEntries[3] >>= sExplanation;
+ rEntries[4] >>= sExplanationURL;
+ rEntries[5] >>= aLocale;
+ rEntries[6] >>= xGrammarChecker;
+ rEntries[7] >>= aSuggestions;
+ rEntries[8] >>= sRuleId;
+ }
+};
+
+}//namespace svx
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/dialogs/SpellDialog.cxx b/cui/source/dialogs/SpellDialog.cxx
new file mode 100644
index 000000000..b3b66d9e6
--- /dev/null
+++ b/cui/source/dialogs/SpellDialog.cxx
@@ -0,0 +1,2092 @@
+/* -*- 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 "SpellAttrib.hxx"
+#include <sfx2/bindings.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <sfx2/viewfrm.hxx>
+#include <svl/grabbagitem.hxx>
+#include <svl/undo.hxx>
+#include <tools/debug.hxx>
+#include <unotools/lingucfg.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/langitem.hxx>
+#include <editeng/splwrap.hxx>
+#include <editeng/unolingu.hxx>
+#include <editeng/wghtitem.hxx>
+#include <linguistic/misc.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/frame/XStorable.hpp>
+#include <com/sun/star/linguistic2/XDictionary.hpp>
+#include <com/sun/star/linguistic2/XSpellAlternatives.hpp>
+#include <com/sun/star/linguistic2/XSearchableDictionaryList.hpp>
+#include <com/sun/star/linguistic2/XSpellChecker1.hpp>
+#include <sfx2/app.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <vcl/specialchars.hxx>
+#include <vcl/event.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/texteng.hxx>
+#include <vcl/weld.hxx>
+#include <svx/SpellDialogChildWindow.hxx>
+#include <SpellDialog.hxx>
+#include <optlingu.hxx>
+#include <treeopt.hxx>
+#include <svtools/langtab.hxx>
+#include <sal/log.hxx>
+#include <i18nlangtag/languagetag.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::linguistic2;
+using namespace linguistic;
+
+
+// struct SpellDialog_Impl ---------------------------------------------
+
+struct SpellDialog_Impl
+{
+ Sequence< Reference< XDictionary > > aDics;
+};
+
+
+#define SPELLUNDO_START 200
+
+#define SPELLUNDO_CHANGE_LANGUAGE (SPELLUNDO_START + 1)
+#define SPELLUNDO_CHANGE_TEXTENGINE (SPELLUNDO_START + 2)
+#define SPELLUNDO_CHANGE_NEXTERROR (SPELLUNDO_START + 3)
+#define SPELLUNDO_CHANGE_ADD_TO_DICTIONARY (SPELLUNDO_START + 4)
+#define SPELLUNDO_CHANGE_GROUP (SPELLUNDO_START + 5) //undo list
+#define SPELLUNDO_MOVE_ERROREND (SPELLUNDO_START + 6)
+#define SPELLUNDO_UNDO_EDIT_MODE (SPELLUNDO_START + 7)
+#define SPELLUNDO_ADD_IGNORE_RULE (SPELLUNDO_START + 8)
+
+namespace svx{
+class SpellUndoAction_Impl : public SfxUndoAction
+{
+ sal_uInt16 m_nId;
+ const Link<SpellUndoAction_Impl&,void>& m_rActionLink;
+ //undo of button enabling
+ bool m_bEnableChangePB;
+ bool m_bEnableChangeAllPB;
+ //undo of MarkNextError - used in change and change all, ignore and ignore all
+ long m_nOldErrorStart;
+ long m_nOldErrorEnd;
+ bool m_bIsErrorLanguageSelected;
+ //undo of AddToDictionary
+ Reference<XDictionary> m_xDictionary;
+ OUString m_sAddedWord;
+ //move end of error - ::ChangeMarkedWord()
+ long m_nOffset;
+
+public:
+ SpellUndoAction_Impl(sal_uInt16 nId, const Link<SpellUndoAction_Impl&,void>& rActionLink) :
+ m_nId(nId),
+ m_rActionLink( rActionLink),
+ m_bEnableChangePB(false),
+ m_bEnableChangeAllPB(false),
+ m_nOldErrorStart(-1),
+ m_nOldErrorEnd(-1),
+ m_bIsErrorLanguageSelected(false),
+ m_nOffset(0)
+ {}
+
+ virtual void Undo() override;
+ sal_uInt16 GetId() const;
+
+ void SetEnableChangePB(){m_bEnableChangePB = true;}
+ bool IsEnableChangePB() const {return m_bEnableChangePB;}
+
+ void SetEnableChangeAllPB(){m_bEnableChangeAllPB = true;}
+ bool IsEnableChangeAllPB() const {return m_bEnableChangeAllPB;}
+
+ void SetErrorMove(long nOldStart, long nOldEnd)
+ {
+ m_nOldErrorStart = nOldStart;
+ m_nOldErrorEnd = nOldEnd;
+ }
+ long GetOldErrorStart() const { return m_nOldErrorStart;}
+ long GetOldErrorEnd() const { return m_nOldErrorEnd;}
+
+ void SetErrorLanguageSelected(bool bSet){ m_bIsErrorLanguageSelected = bSet;}
+ bool IsErrorLanguageSelected() const {return m_bIsErrorLanguageSelected;}
+
+ void SetDictionary(const Reference<XDictionary>& xDict) { m_xDictionary = xDict; }
+ const Reference<XDictionary>& GetDictionary() const { return m_xDictionary; }
+ void SetAddedWord(const OUString& rWord) {m_sAddedWord = rWord;}
+ const OUString& GetAddedWord() const { return m_sAddedWord;}
+
+ void SetOffset(long nSet) {m_nOffset = nSet;}
+ long GetOffset() const {return m_nOffset;}
+};
+}//namespace svx
+using namespace ::svx;
+
+void SpellUndoAction_Impl::Undo()
+{
+ m_rActionLink.Call(*this);
+}
+
+
+sal_uInt16 SpellUndoAction_Impl::GetId()const
+{
+ return m_nId;
+}
+
+// class SvxSpellCheckDialog ---------------------------------------------
+
+SpellDialog::SpellDialog(SpellDialogChildWindow* pChildWindow,
+ weld::Window * pParent, SfxBindings* _pBindings)
+ : SfxModelessDialogController (_pBindings, pChildWindow,
+ pParent, "cui/ui/spellingdialog.ui", "SpellingDialog")
+ , aDialogUndoLink(LINK (this, SpellDialog, DialogUndoHdl))
+ , bFocusLocked(true)
+ , rParent(*pChildWindow)
+ , pImpl( new SpellDialog_Impl )
+ , m_xAltTitle(m_xBuilder->weld_label("alttitleft"))
+ , m_xResumeFT(m_xBuilder->weld_label("resumeft"))
+ , m_xNoSuggestionsFT(m_xBuilder->weld_label("nosuggestionsft"))
+ , m_xLanguageFT(m_xBuilder->weld_label("languageft"))
+ , m_xLanguageLB(new SvxLanguageBox(m_xBuilder->weld_combo_box("languagelb")))
+ , m_xExplainFT(m_xBuilder->weld_label("explain"))
+ , m_xExplainLink(m_xBuilder->weld_link_button("explainlink"))
+ , m_xNotInDictFT(m_xBuilder->weld_label("notindictft"))
+ , m_xSentenceED(new SentenceEditWindow_Impl)
+ , m_xSuggestionFT(m_xBuilder->weld_label("suggestionsft"))
+ , m_xSuggestionLB(m_xBuilder->weld_tree_view("suggestionslb"))
+ , m_xIgnorePB(m_xBuilder->weld_button("ignore"))
+ , m_xIgnoreAllPB(m_xBuilder->weld_button("ignoreall"))
+ , m_xIgnoreRulePB(m_xBuilder->weld_button("ignorerule"))
+ , m_xAddToDictPB(m_xBuilder->weld_button("add"))
+ , m_xAddToDictMB(m_xBuilder->weld_menu_button("addmb"))
+ , m_xChangePB(m_xBuilder->weld_button("change"))
+ , m_xChangeAllPB(m_xBuilder->weld_button("changeall"))
+ , m_xAutoCorrPB(m_xBuilder->weld_button("autocorrect"))
+ , m_xCheckGrammarCB(m_xBuilder->weld_check_button("checkgrammar"))
+ , m_xOptionsPB(m_xBuilder->weld_button("options"))
+ , m_xUndoPB(m_xBuilder->weld_button("undo"))
+ , m_xClosePB(m_xBuilder->weld_button("close"))
+ , m_xToolbar(m_xBuilder->weld_toolbar("toolbar"))
+ , m_xSentenceEDWeld(new weld::CustomWeld(*m_xBuilder, "sentence", *m_xSentenceED))
+{
+ m_xSentenceED->SetSpellDialog(this);
+ m_xSentenceED->Init(m_xToolbar.get());
+
+ m_sTitleSpellingGrammar = m_xDialog->get_title();
+ m_sTitleSpelling = m_xAltTitle->get_label();
+
+ // fdo#68794 set initial title for cases where no text has been processed
+ // yet to show its language attributes
+ OUString sTitle = rParent.HasGrammarChecking() ? m_sTitleSpellingGrammar : m_sTitleSpelling;
+ m_xDialog->set_title(m_xDialog->strip_mnemonic(sTitle.replaceFirst("$LANGUAGE ($LOCATION)", "")));
+
+ m_sResumeST = m_xResumeFT->get_label();
+ m_sNoSuggestionsST = m_xNoSuggestionsFT->strip_mnemonic(m_xNoSuggestionsFT->get_label());
+
+ Size aEdSize(m_xSuggestionLB->get_approximate_digit_width() * 60,
+ m_xSuggestionLB->get_height_rows(6));
+ m_xSuggestionLB->set_size_request(aEdSize.Width(), -1);
+ m_sIgnoreOnceST = m_xIgnorePB->get_label();
+ m_xAddToDictMB->set_help_id(m_xAddToDictPB->get_help_id());
+ xSpell = LinguMgr::GetSpellChecker();
+
+ Init_Impl();
+
+ // disable controls if service is missing
+ m_xDialog->set_sensitive(xSpell.is());
+
+ //InitHdl wants to use virtual methods, so it
+ //can't be called during the ctor, so init
+ //it on next event cycle post-ctor
+ Application::PostUserEvent(LINK(this, SpellDialog, InitHdl));
+}
+
+SpellDialog::~SpellDialog()
+{
+ if (pImpl)
+ {
+ // save possibly modified user-dictionaries
+ Reference< XSearchableDictionaryList > xDicList( LinguMgr::GetDictionaryList() );
+ if (xDicList.is())
+ SaveDictionaries( xDicList );
+
+ pImpl.reset();
+ }
+}
+
+void SpellDialog::Init_Impl()
+{
+ // initialize handler
+ m_xClosePB->connect_clicked(LINK( this, SpellDialog, CancelHdl ) );
+ m_xChangePB->connect_clicked(LINK( this, SpellDialog, ChangeHdl ) );
+ m_xChangeAllPB->connect_clicked(LINK( this, SpellDialog, ChangeAllHdl ) );
+ m_xIgnorePB->connect_clicked(LINK( this, SpellDialog, IgnoreHdl ) );
+ m_xIgnoreAllPB->connect_clicked(LINK( this, SpellDialog, IgnoreAllHdl ) );
+ m_xIgnoreRulePB->connect_clicked(LINK( this, SpellDialog, IgnoreAllHdl ) );
+ m_xUndoPB->connect_clicked(LINK( this, SpellDialog, UndoHdl ) );
+
+ m_xAutoCorrPB->connect_clicked( LINK( this, SpellDialog, ExtClickHdl ) );
+ m_xCheckGrammarCB->connect_clicked( LINK( this, SpellDialog, CheckGrammarHdl ));
+ m_xOptionsPB->connect_clicked( LINK( this, SpellDialog, ExtClickHdl ) );
+
+ m_xSuggestionLB->connect_row_activated( LINK( this, SpellDialog, DoubleClickChangeHdl ) );
+
+ m_xSentenceED->SetModifyHdl(LINK ( this, SpellDialog, ModifyHdl) );
+
+ m_xAddToDictMB->connect_selected(LINK ( this, SpellDialog, AddToDictSelectHdl ) );
+ m_xAddToDictPB->connect_clicked(LINK ( this, SpellDialog, AddToDictClickHdl ) );
+
+ m_xLanguageLB->connect_changed(LINK( this, SpellDialog, LanguageSelectHdl ) );
+
+ // initialize language ListBox
+ m_xLanguageLB->SetLanguageList(SvxLanguageListFlags::SPELL_USED, false, false, true);
+
+ m_xSentenceED->ClearModifyFlag();
+ LinguMgr::GetChangeAllList()->clear();
+}
+
+void SpellDialog::UpdateBoxes_Impl(bool bCallFromSelectHdl)
+{
+ sal_Int32 i;
+ m_xSuggestionLB->clear();
+
+ SpellErrorDescription aSpellErrorDescription;
+ bool bSpellErrorDescription = m_xSentenceED->GetAlternatives(aSpellErrorDescription);
+
+ LanguageType nAltLanguage = LANGUAGE_NONE;
+ Sequence< OUString > aNewWords;
+ bool bIsGrammarError = false;
+ if( bSpellErrorDescription )
+ {
+ nAltLanguage = LanguageTag::convertToLanguageType( aSpellErrorDescription.aLocale );
+ aNewWords = aSpellErrorDescription.aSuggestions;
+ bIsGrammarError = aSpellErrorDescription.bIsGrammarError;
+ m_xExplainLink->set_uri( aSpellErrorDescription.sExplanationURL );
+ m_xExplainFT->set_label( aSpellErrorDescription.sExplanation );
+ }
+ if( bSpellErrorDescription && !aSpellErrorDescription.sDialogTitle.isEmpty() )
+ {
+ // use this function to apply the correct image to be used...
+ SetTitle_Impl( nAltLanguage );
+ // then change the title to the one to be actually used
+ m_xDialog->set_title(m_xDialog->strip_mnemonic(aSpellErrorDescription.sDialogTitle));
+ }
+ else
+ SetTitle_Impl( nAltLanguage );
+ if( !bCallFromSelectHdl )
+ m_xLanguageLB->set_active_id( nAltLanguage );
+ int nDicts = InitUserDicts();
+
+ // enter alternatives
+ const OUString *pNewWords = aNewWords.getConstArray();
+ const sal_Int32 nSize = aNewWords.getLength();
+ for ( i = 0; i < nSize; ++i )
+ {
+ OUString aTmp( pNewWords[i] );
+ if (m_xSuggestionLB->find_text(aTmp) == -1)
+ m_xSuggestionLB->append_text(aTmp);
+ }
+ if(!nSize)
+ m_xSuggestionLB->append_text(m_sNoSuggestionsST);
+ m_xAutoCorrPB->set_sensitive( nSize > 0 );
+
+ m_xSuggestionFT->set_sensitive(nSize > 0);
+ m_xSuggestionLB->set_sensitive(nSize > 0);
+ if( nSize )
+ {
+ m_xSuggestionLB->select(0);
+ }
+ m_xChangePB->set_sensitive( nSize > 0);
+ m_xChangeAllPB->set_sensitive(nSize > 0);
+ bool bShowChangeAll = !bIsGrammarError;
+ m_xChangeAllPB->set_visible( bShowChangeAll );
+ m_xExplainFT->set_visible( !bShowChangeAll );
+ m_xLanguageLB->set_sensitive( bShowChangeAll );
+ m_xIgnoreAllPB->set_visible( bShowChangeAll );
+
+ m_xAddToDictMB->set_visible( bShowChangeAll && nDicts > 1);
+ m_xAddToDictPB->set_visible( bShowChangeAll && nDicts <= 1);
+ m_xIgnoreRulePB->set_visible( !bShowChangeAll );
+ m_xIgnoreRulePB->set_sensitive(bSpellErrorDescription && !aSpellErrorDescription.sRuleId.isEmpty());
+ m_xAutoCorrPB->set_visible( bShowChangeAll && rParent.HasAutoCorrection() );
+
+ bool bOldShowGrammar = m_xCheckGrammarCB->get_visible();
+ bool bOldShowExplain = m_xExplainLink->get_visible();
+
+ m_xCheckGrammarCB->set_visible(rParent.HasGrammarChecking());
+ m_xExplainLink->set_visible(!m_xExplainLink->get_uri().isEmpty());
+ if (m_xExplainFT->get_label().isEmpty())
+ {
+ m_xExplainFT->hide();
+ m_xExplainLink->hide();
+ }
+
+ if (bOldShowExplain != m_xExplainLink->get_visible() || bOldShowGrammar != m_xCheckGrammarCB->get_visible())
+ m_xDialog->resize_to_request();
+}
+
+void SpellDialog::SpellContinue_Impl(std::unique_ptr<UndoChangeGroupGuard>* pGuard, bool bUseSavedSentence, bool bIgnoreCurrentError)
+{
+ //initially or after the last error of a sentence MarkNextError will fail
+ //then GetNextSentence() has to be called followed again by MarkNextError()
+ //MarkNextError is not initially called if the UndoEdit mode is active
+ bool bNextSentence = false;
+ if(!((!m_xSentenceED->IsUndoEditMode() && m_xSentenceED->MarkNextError( bIgnoreCurrentError, xSpell )) ||
+ ( bNextSentence = GetNextSentence_Impl(pGuard, bUseSavedSentence, m_xSentenceED->IsUndoEditMode()) && m_xSentenceED->MarkNextError( false, xSpell ))))
+ return;
+
+ SpellErrorDescription aSpellErrorDescription;
+ bool bSpellErrorDescription = m_xSentenceED->GetAlternatives(aSpellErrorDescription);
+ if (bSpellErrorDescription)
+ {
+ UpdateBoxes_Impl();
+ weld::Widget* aControls[] =
+ {
+ m_xNotInDictFT.get(),
+ m_xSentenceED->GetDrawingArea(),
+ m_xLanguageFT.get(),
+ nullptr
+ };
+ sal_Int32 nIdx = 0;
+ do
+ {
+ aControls[nIdx]->set_sensitive(true);
+ }
+ while(aControls[++nIdx]);
+
+ }
+ if( bNextSentence )
+ {
+ //remove undo if a new sentence is active
+ m_xSentenceED->ResetUndo();
+ m_xUndoPB->set_sensitive(false);
+ }
+}
+/* Initialize, asynchronous to prevent virtual calls
+ from a constructor
+ */
+IMPL_LINK_NOARG( SpellDialog, InitHdl, void*, void)
+{
+ m_xDialog->freeze();
+ //show or hide AutoCorrect depending on the modules abilities
+ m_xAutoCorrPB->set_visible(rParent.HasAutoCorrection());
+ SpellContinue_Impl(nullptr);
+ m_xSentenceED->ResetUndo();
+ m_xUndoPB->set_sensitive(false);
+
+ // get current language
+ UpdateBoxes_Impl();
+
+ // fill dictionary PopupMenu
+ InitUserDicts();
+
+ LockFocusChanges(true);
+ if( m_xChangePB->get_sensitive() )
+ m_xChangePB->grab_focus();
+ else if( m_xIgnorePB->get_sensitive() )
+ m_xIgnorePB->grab_focus();
+ else if( m_xClosePB->get_sensitive() )
+ m_xClosePB->grab_focus();
+ LockFocusChanges(false);
+ //show grammar CheckBox depending on the modules abilities
+ m_xCheckGrammarCB->set_active(rParent.IsGrammarChecking());
+ m_xDialog->thaw();
+};
+
+IMPL_LINK( SpellDialog, ExtClickHdl, weld::Button&, rBtn, void )
+{
+ if (m_xOptionsPB.get() == &rBtn)
+ StartSpellOptDlg_Impl();
+ else if (m_xAutoCorrPB.get() == &rBtn)
+ {
+ //get the currently selected wrong word
+ OUString sCurrentErrorText = m_xSentenceED->GetErrorText();
+ //get the wrong word from the XSpellAlternative
+ SpellErrorDescription aSpellErrorDescription;
+ bool bSpellErrorDescription = m_xSentenceED->GetAlternatives(aSpellErrorDescription);
+ if (bSpellErrorDescription)
+ {
+ OUString sWrong(aSpellErrorDescription.sErrorText);
+ //if the word has not been edited in the MultiLineEdit then
+ //the current suggestion should be used
+ //if it's not the 'no suggestions' entry
+ if(sWrong == sCurrentErrorText &&
+ m_xSuggestionLB->get_sensitive() && m_xSuggestionLB->get_selected_index() != -1 &&
+ m_sNoSuggestionsST != m_xSuggestionLB->get_selected_text())
+ {
+ sCurrentErrorText = m_xSuggestionLB->get_selected_text();
+ }
+ if(sWrong != sCurrentErrorText)
+ {
+ SvxPrepareAutoCorrect( sWrong, sCurrentErrorText );
+ LanguageType eLang = GetSelectedLang_Impl();
+ rParent.AddAutoCorrection( sWrong, sCurrentErrorText, eLang );
+ }
+ }
+ }
+}
+
+IMPL_LINK_NOARG(SpellDialog, CheckGrammarHdl, weld::Button&, void)
+{
+ rParent.SetGrammarChecking(m_xCheckGrammarCB->get_active());
+ Impl_Restore(true);
+}
+
+void SpellDialog::StartSpellOptDlg_Impl()
+{
+ SfxItemSet aSet( SfxGetpApp()->GetPool(), svl::Items<SID_AUTOSPELL_CHECK,SID_AUTOSPELL_CHECK>{});
+ SfxSingleTabDialogController aDlg(m_xDialog.get(), &aSet, "cui/ui/spelloptionsdialog.ui", "SpellOptionsDialog");
+
+ std::unique_ptr<SfxTabPage> xPage = SvxLinguTabPage::Create(aDlg.get_content_area(), &aDlg, &aSet);
+ static_cast<SvxLinguTabPage*>(xPage.get())->HideGroups( GROUP_MODULES );
+ aDlg.SetTabPage(std::move(xPage));
+ if (RET_OK == aDlg.run())
+ {
+ InitUserDicts();
+ const SfxItemSet* pOutSet = aDlg.GetOutputItemSet();
+ if(pOutSet)
+ OfaTreeOptionsDialog::ApplyLanguageOptions(*pOutSet);
+ }
+}
+
+namespace
+{
+ OUString getDotReplacementString(const OUString &rErrorText, const OUString &rSuggestedReplacement)
+ {
+ OUString aString = rErrorText;
+
+ //dots are sometimes part of the spelled word but they are not necessarily part of the replacement
+ bool bDot = aString.endsWith(".");
+
+ aString = rSuggestedReplacement;
+
+ if(bDot && (aString.isEmpty() || !aString.endsWith(".")))
+ aString += ".";
+
+ return aString;
+ }
+}
+
+OUString SpellDialog::getReplacementString() const
+{
+ OUString sOrigString = m_xSentenceED->GetErrorText();
+
+ OUString sReplacement(sOrigString);
+
+ if(m_xSuggestionLB->get_sensitive() &&
+ m_xSuggestionLB->get_selected_index() != -1 &&
+ m_sNoSuggestionsST != m_xSuggestionLB->get_selected_text())
+ sReplacement = m_xSuggestionLB->get_selected_text();
+
+ return getDotReplacementString(sOrigString, sReplacement);
+}
+
+IMPL_LINK_NOARG(SpellDialog, DoubleClickChangeHdl, weld::TreeView&, bool)
+{
+ ChangeHdl(*m_xChangePB);
+ return true;
+}
+
+/* tdf#132822 start an undo group in ctor and close it in the dtor. This can
+ then be passed to SpellContinue_Impl which can delete it in advance of its
+ natural scope to force closing the undo group if SpellContinue_Impl needs to
+ fetch a new paragraph and discard all undo information which can only be
+ done properly if there are no open undo groups */
+class UndoChangeGroupGuard
+{
+private:
+ SentenceEditWindow_Impl& m_rSentenceED;
+public:
+ UndoChangeGroupGuard(SentenceEditWindow_Impl& rSentenceED)
+ : m_rSentenceED(rSentenceED)
+ {
+ m_rSentenceED.UndoActionStart(SPELLUNDO_CHANGE_GROUP);
+ }
+ ~UndoChangeGroupGuard()
+ {
+ m_rSentenceED.UndoActionEnd();
+ }
+};
+
+IMPL_LINK_NOARG(SpellDialog, ChangeHdl, weld::Button&, void)
+{
+ if (m_xSentenceED->IsUndoEditMode())
+ {
+ SpellContinue_Impl();
+ }
+ else
+ {
+ auto xGuard(std::make_unique<UndoChangeGroupGuard>(*m_xSentenceED));
+ OUString aString = getReplacementString();
+ m_xSentenceED->ChangeMarkedWord(aString, GetSelectedLang_Impl());
+ SpellContinue_Impl(&xGuard);
+ }
+ if(!m_xChangePB->get_sensitive())
+ m_xIgnorePB->grab_focus();
+}
+
+IMPL_LINK_NOARG(SpellDialog, ChangeAllHdl, weld::Button&, void)
+{
+ auto xGuard(std::make_unique<UndoChangeGroupGuard>(*m_xSentenceED));
+ OUString aString = getReplacementString();
+ LanguageType eLang = GetSelectedLang_Impl();
+
+ // add new word to ChangeAll list
+ OUString aOldWord( m_xSentenceED->GetErrorText() );
+ SvxPrepareAutoCorrect( aOldWord, aString );
+ Reference<XDictionary> aXDictionary = LinguMgr::GetChangeAllList();
+ DictionaryError nAdded = AddEntryToDic( aXDictionary,
+ aOldWord, true,
+ aString );
+
+ if(nAdded == DictionaryError::NONE)
+ {
+ std::unique_ptr<SpellUndoAction_Impl> pAction(new SpellUndoAction_Impl(
+ SPELLUNDO_CHANGE_ADD_TO_DICTIONARY, aDialogUndoLink));
+ pAction->SetDictionary(aXDictionary);
+ pAction->SetAddedWord(aOldWord);
+ m_xSentenceED->AddUndoAction(std::move(pAction));
+ }
+
+ m_xSentenceED->ChangeMarkedWord(aString, eLang);
+ SpellContinue_Impl(&xGuard);
+}
+
+IMPL_LINK( SpellDialog, IgnoreAllHdl, weld::Button&, rButton, void )
+{
+ auto xGuard(std::make_unique<UndoChangeGroupGuard>(*m_xSentenceED));
+ // add word to IgnoreAll list
+ Reference< XDictionary > aXDictionary = LinguMgr::GetIgnoreAllList();
+ //in case the error has been changed manually it has to be restored
+ m_xSentenceED->RestoreCurrentError();
+ if (&rButton == m_xIgnoreRulePB.get())
+ {
+ SpellErrorDescription aSpellErrorDescription;
+ bool bSpellErrorDescription = m_xSentenceED->GetAlternatives(aSpellErrorDescription);
+ try
+ {
+ if( bSpellErrorDescription && aSpellErrorDescription.xGrammarChecker.is() )
+ {
+ aSpellErrorDescription.xGrammarChecker->ignoreRule(aSpellErrorDescription.sRuleId,
+ aSpellErrorDescription.aLocale);
+ // refresh the layout (workaround to launch a dictionary event)
+ aXDictionary->setActive(false);
+ aXDictionary->setActive(true);
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ }
+ }
+ else
+ {
+ OUString sErrorText(m_xSentenceED->GetErrorText());
+ DictionaryError nAdded = AddEntryToDic( aXDictionary,
+ sErrorText, false,
+ OUString() );
+ if (nAdded == DictionaryError::NONE)
+ {
+ std::unique_ptr<SpellUndoAction_Impl> pAction(new SpellUndoAction_Impl(
+ SPELLUNDO_CHANGE_ADD_TO_DICTIONARY, aDialogUndoLink));
+ pAction->SetDictionary(aXDictionary);
+ pAction->SetAddedWord(sErrorText);
+ m_xSentenceED->AddUndoAction(std::move(pAction));
+ }
+ }
+
+ SpellContinue_Impl(&xGuard);
+}
+
+IMPL_LINK_NOARG(SpellDialog, UndoHdl, weld::Button&, void)
+{
+ m_xSentenceED->Undo();
+ if(!m_xSentenceED->GetUndoActionCount())
+ m_xUndoPB->set_sensitive(false);
+}
+
+
+IMPL_LINK( SpellDialog, DialogUndoHdl, SpellUndoAction_Impl&, rAction, void )
+{
+ switch(rAction.GetId())
+ {
+ case SPELLUNDO_CHANGE_TEXTENGINE:
+ {
+ if(rAction.IsEnableChangePB())
+ m_xChangePB->set_sensitive(false);
+ if(rAction.IsEnableChangeAllPB())
+ m_xChangeAllPB->set_sensitive(false);
+ }
+ break;
+ case SPELLUNDO_CHANGE_NEXTERROR:
+ {
+ m_xSentenceED->MoveErrorMarkTo(static_cast<sal_Int32>(rAction.GetOldErrorStart()),
+ static_cast<sal_Int32>(rAction.GetOldErrorEnd()),
+ false);
+ if(rAction.IsErrorLanguageSelected())
+ {
+ UpdateBoxes_Impl();
+ }
+ }
+ break;
+ case SPELLUNDO_CHANGE_ADD_TO_DICTIONARY:
+ {
+ if(rAction.GetDictionary().is())
+ rAction.GetDictionary()->remove(rAction.GetAddedWord());
+ }
+ break;
+ case SPELLUNDO_MOVE_ERROREND :
+ {
+ if(rAction.GetOffset() != 0)
+ m_xSentenceED->MoveErrorEnd(rAction.GetOffset());
+ }
+ break;
+ case SPELLUNDO_UNDO_EDIT_MODE :
+ {
+ //refill the dialog with the currently spelled sentence - throw away all changes
+ SpellContinue_Impl(nullptr, true);
+ }
+ break;
+ case SPELLUNDO_ADD_IGNORE_RULE:
+ //undo of ignored rules is not supported
+ break;
+ }
+}
+
+void SpellDialog::Impl_Restore(bool bUseSavedSentence)
+{
+ //clear the "ChangeAllList"
+ LinguMgr::GetChangeAllList()->clear();
+ //get a new sentence
+ m_xSentenceED->SetText(OUString());
+ m_xSentenceED->ResetModified();
+ //Resolves: fdo#39348 refill the dialog with the currently spelled sentence
+ SpellContinue_Impl(nullptr, bUseSavedSentence);
+ m_xIgnorePB->set_label(m_sIgnoreOnceST);
+}
+
+IMPL_LINK_NOARG(SpellDialog, IgnoreHdl, weld::Button&, void)
+{
+ if (m_sResumeST == m_xIgnorePB->get_label())
+ {
+ Impl_Restore(false);
+ }
+ else
+ {
+ //in case the error has been changed manually it has to be restored,
+ // since the users choice now was to ignore the error
+ m_xSentenceED->RestoreCurrentError();
+
+ // the word is being ignored
+ SpellContinue_Impl(nullptr, false, true);
+ }
+}
+
+void SpellDialog::Close()
+{
+ if (IsClosing())
+ return;
+
+ // We have to call ToggleChildWindow directly; calling SfxDispatcher's
+ // Execute() does not work here when we are in a document with protected
+ // section - in that case, the cursor can move from the editable field to
+ // the protected area, and the slots get disabled because of
+ // SfxDisableFlags::SwOnProtectedCursor (see FN_SPELL_GRAMMAR_DIALOG in .sdi).
+ SfxViewFrame* pViewFrame = SfxViewFrame::Current();
+ if (pViewFrame)
+ pViewFrame->ToggleChildWindow(rParent.GetType());
+}
+
+LanguageType SpellDialog::GetSelectedLang_Impl() const
+{
+ LanguageType nLang = m_xLanguageLB->get_active_id();
+ return nLang;
+}
+
+IMPL_LINK_NOARG(SpellDialog, LanguageSelectHdl, weld::ComboBox&, void)
+{
+ //If selected language changes, then add->list should be regenerated to
+ //match
+ InitUserDicts();
+
+ //if currently an error is selected then search for alternatives for
+ //this word and fill the alternatives ListBox accordingly
+ OUString sError = m_xSentenceED->GetErrorText();
+ m_xSuggestionLB->clear();
+ if (!sError.isEmpty())
+ {
+ LanguageType eLanguage = m_xLanguageLB->get_active_id();
+ Reference <XSpellAlternatives> xAlt = xSpell->spell( sError, static_cast<sal_uInt16>(eLanguage),
+ Sequence< PropertyValue >() );
+ if( xAlt.is() )
+ m_xSentenceED->SetAlternatives( xAlt );
+ else
+ {
+ m_xSentenceED->ChangeMarkedWord( sError, eLanguage );
+ SpellContinue_Impl();
+ }
+
+ m_xSentenceED->AddUndoAction(std::make_unique<SpellUndoAction_Impl>(SPELLUNDO_CHANGE_LANGUAGE, aDialogUndoLink));
+ }
+ SpellDialog::UpdateBoxes_Impl(true);
+}
+
+void SpellDialog::SetTitle_Impl(LanguageType nLang)
+{
+ OUString sTitle = rParent.HasGrammarChecking() ? m_sTitleSpellingGrammar : m_sTitleSpelling;
+ sTitle = sTitle.replaceFirst( "$LANGUAGE ($LOCATION)", SvtLanguageTable::GetLanguageString(nLang) );
+ m_xDialog->set_title(m_xDialog->strip_mnemonic(sTitle));
+}
+
+int SpellDialog::InitUserDicts()
+{
+ const LanguageType nLang = m_xLanguageLB->get_active_id();
+
+ const Reference< XDictionary > *pDic = nullptr;
+
+ // get list of dictionaries
+ Reference< XSearchableDictionaryList > xDicList( LinguMgr::GetDictionaryList() );
+ if (xDicList.is())
+ {
+ // add active, positive dictionary to dic-list (if not already done).
+ // This is to ensure that there is at least on dictionary to which
+ // words could be added.
+ Reference< XDictionary > xDic( LinguMgr::GetStandardDic() );
+ if (xDic.is())
+ xDic->setActive( true );
+
+ pImpl->aDics = xDicList->getDictionaries();
+ }
+
+ SvtLinguConfig aCfg;
+
+ // list suitable dictionaries
+ bool bEnable = false;
+ const sal_Int32 nSize = pImpl->aDics.getLength();
+ pDic = pImpl->aDics.getConstArray();
+ m_xAddToDictMB->clear();
+ sal_uInt16 nItemId = 1; // menu items should be enumerated from 1 and not 0
+ for (sal_Int32 i = 0; i < nSize; ++i)
+ {
+ uno::Reference< linguistic2::XDictionary > xDicTmp = pDic[i];
+ if (!xDicTmp.is() || LinguMgr::GetIgnoreAllList() == xDicTmp)
+ continue;
+
+ uno::Reference< frame::XStorable > xStor( xDicTmp, uno::UNO_QUERY );
+ LanguageType nActLanguage = LanguageTag( xDicTmp->getLocale() ).getLanguageType();
+ if( xDicTmp->isActive()
+ && xDicTmp->getDictionaryType() != linguistic2::DictionaryType_NEGATIVE
+ && (nLang == nActLanguage || LANGUAGE_NONE == nActLanguage )
+ && (!xStor.is() || !xStor->isReadonly()) )
+ {
+ bEnable = true;
+
+ OUString aDictionaryImageUrl;
+ uno::Reference< lang::XServiceInfo > xSvcInfo( xDicTmp, uno::UNO_QUERY );
+ if (xSvcInfo.is())
+ {
+ aDictionaryImageUrl = aCfg.GetSpellAndGrammarContextDictionaryImage(
+ xSvcInfo->getImplementationName());
+ }
+
+ m_xAddToDictMB->append_item(OUString::number(nItemId), xDicTmp->getName(), aDictionaryImageUrl);
+
+ ++nItemId;
+ }
+ }
+ m_xAddToDictMB->set_sensitive( bEnable );
+ m_xAddToDictPB->set_sensitive( bEnable );
+
+ int nDicts = nItemId-1;
+
+ m_xAddToDictMB->set_visible( nDicts > 1 );
+ m_xAddToDictPB->set_visible( nDicts <= 1 );
+
+ return nDicts;
+}
+
+IMPL_LINK_NOARG(SpellDialog, AddToDictClickHdl, weld::Button&, void)
+{
+ AddToDictionaryExecute(OString::number(1));
+}
+
+IMPL_LINK(SpellDialog, AddToDictSelectHdl, const OString&, rIdent, void)
+{
+ AddToDictionaryExecute(rIdent);
+}
+
+void SpellDialog::AddToDictionaryExecute(const OString& rItemId)
+{
+ auto xGuard(std::make_unique<UndoChangeGroupGuard>(*m_xSentenceED));
+
+ //GetErrorText() returns the current error even if the text is already
+ //manually changed
+ const OUString aNewWord = m_xSentenceED->GetErrorText();
+
+ OUString aDicName(m_xAddToDictMB->get_item_label(rItemId));
+
+ uno::Reference< linguistic2::XDictionary > xDic;
+ uno::Reference< linguistic2::XSearchableDictionaryList > xDicList( LinguMgr::GetDictionaryList() );
+ if (xDicList.is())
+ xDic = xDicList->getDictionaryByName( aDicName );
+
+ DictionaryError nAddRes = DictionaryError::UNKNOWN;
+ if (xDic.is())
+ {
+ nAddRes = AddEntryToDic( xDic, aNewWord, false, OUString() );
+ // save modified user-dictionary if it is persistent
+ uno::Reference< frame::XStorable > xSavDic( xDic, uno::UNO_QUERY );
+ if (xSavDic.is())
+ xSavDic->store();
+
+ if (nAddRes == DictionaryError::NONE)
+ {
+ std::unique_ptr<SpellUndoAction_Impl> pAction(new SpellUndoAction_Impl(
+ SPELLUNDO_CHANGE_ADD_TO_DICTIONARY, aDialogUndoLink));
+ pAction->SetDictionary( xDic );
+ pAction->SetAddedWord( aNewWord );
+ m_xSentenceED->AddUndoAction( std::move(pAction) );
+ }
+ // failed because there is already an entry?
+ if (DictionaryError::NONE != nAddRes && xDic->getEntry( aNewWord ).is())
+ nAddRes = DictionaryError::NONE;
+ }
+ if (DictionaryError::NONE != nAddRes)
+ {
+ SvxDicError(m_xDialog.get(), nAddRes);
+ return; // don't continue
+ }
+
+ // go on
+ SpellContinue_Impl(&xGuard);
+}
+
+IMPL_LINK_NOARG(SpellDialog, ModifyHdl, LinkParamNone*, void)
+{
+ m_xSuggestionLB->unselect_all();
+ m_xSuggestionLB->set_sensitive(false);
+ m_xAutoCorrPB->set_sensitive(false);
+ std::unique_ptr<SpellUndoAction_Impl> pSpellAction(new SpellUndoAction_Impl(SPELLUNDO_CHANGE_TEXTENGINE, aDialogUndoLink));
+ if(!m_xChangeAllPB->get_sensitive())
+ {
+ m_xChangeAllPB->set_sensitive(true);
+ pSpellAction->SetEnableChangeAllPB();
+ }
+ if(!m_xChangePB->get_sensitive())
+ {
+ m_xChangePB->set_sensitive(true);
+ pSpellAction->SetEnableChangePB();
+ }
+ m_xSentenceED->AddUndoAction(std::move(pSpellAction));
+}
+
+IMPL_LINK_NOARG(SpellDialog, CancelHdl, weld::Button&, void)
+{
+ //apply changes and ignored text parts first - if there are any
+ rParent.ApplyChangedSentence(m_xSentenceED->CreateSpellPortions(), false);
+ Close();
+}
+
+void SpellDialog::ToplevelFocusChanged()
+{
+ /* #i38338#
+ * FIXME: LoseFocus and GetFocus are signals from vcl that
+ * a window actually got/lost the focus, it never should be
+ * forwarded from another window, that is simply wrong.
+ * FIXME: overriding the virtual methods GetFocus and LoseFocus
+ * in SpellDialogChildWindow by making them pure is at least questionable.
+ * The only sensible thing would be to call the new Method differently,
+ * e.g. DialogGot/LostFocus or so.
+ */
+ if (!(m_xDialog->get_visible() && !bFocusLocked))
+ return;
+
+ if (m_xDialog->has_toplevel_focus())
+ {
+ //notify the child window of the focus change
+ rParent.GetFocus();
+ }
+ else
+ {
+ //notify the child window of the focus change
+ rParent.LoseFocus();
+ }
+}
+
+void SpellDialog::Activate()
+{
+ SfxModelessDialogController::Activate();
+ ToplevelFocusChanged();
+}
+
+void SpellDialog::Deactivate()
+{
+ SfxModelessDialogController::Activate();
+ ToplevelFocusChanged();
+}
+
+void SpellDialog::InvalidateDialog()
+{
+ if( bFocusLocked )
+ return;
+ m_xIgnorePB->set_label(m_sResumeST);
+ weld::Widget* aDisableArr[] =
+ {
+ m_xNotInDictFT.get(),
+ m_xSentenceED->GetDrawingArea(),
+ m_xSuggestionFT.get(),
+ m_xSuggestionLB.get(),
+ m_xLanguageFT.get(),
+ m_xLanguageLB->get_widget(),
+ m_xIgnoreAllPB.get(),
+ m_xIgnoreRulePB.get(),
+ m_xAddToDictMB.get(),
+ m_xAddToDictPB.get(),
+ m_xChangePB.get(),
+ m_xChangeAllPB.get(),
+ m_xAutoCorrPB.get(),
+ m_xUndoPB.get(),
+ nullptr
+ };
+ sal_Int16 i = 0;
+ while(aDisableArr[i])
+ {
+ aDisableArr[i]->set_sensitive(false);
+ i++;
+ }
+ SfxModelessDialogController::Deactivate();
+}
+
+bool SpellDialog::GetNextSentence_Impl(std::unique_ptr<UndoChangeGroupGuard>* pGuard, bool bUseSavedSentence, bool bRecheck)
+{
+ bool bRet = false;
+ if(!bUseSavedSentence)
+ {
+ //apply changes and ignored text parts
+ rParent.ApplyChangedSentence(m_xSentenceED->CreateSpellPortions(), bRecheck);
+ }
+ m_xSentenceED->ResetIgnoreErrorsAt();
+ m_xSentenceED->ResetModified();
+ SpellPortions aSentence = bUseSavedSentence ? m_aSavedSentence : rParent.GetNextWrongSentence( bRecheck );
+ if(!bUseSavedSentence)
+ m_aSavedSentence = aSentence;
+ bool bHasReplaced = false;
+ while(!aSentence.empty())
+ {
+ //apply all changes that are already part of the "ChangeAllList"
+ //returns true if the list still contains errors after the changes have been applied
+
+ if(!ApplyChangeAllList_Impl(aSentence, bHasReplaced))
+ {
+ rParent.ApplyChangedSentence(aSentence, bRecheck);
+ aSentence = rParent.GetNextWrongSentence( bRecheck );
+ }
+ else
+ break;
+ }
+
+ if(!aSentence.empty())
+ {
+ OUStringBuffer sText;
+ for (auto const& elem : aSentence)
+ {
+ // hidden text has to be ignored
+ if(!elem.bIsHidden)
+ sText.append(elem.sText);
+ }
+ // tdf#132822 fire undo-stack UndoActionEnd to close undo stack because we're about to throw away the paragraph entirely
+ if (pGuard)
+ pGuard->reset();
+ m_xSentenceED->SetText(sText.makeStringAndClear());
+ sal_Int32 nStartPosition = 0;
+ sal_Int32 nEndPosition = 0;
+
+ for (auto const& elem : aSentence)
+ {
+ // hidden text has to be ignored
+ if(!elem.bIsHidden)
+ {
+ nEndPosition += elem.sText.getLength();
+ if(elem.xAlternatives.is())
+ {
+ uno::Reference< container::XNamed > xNamed( elem.xAlternatives, uno::UNO_QUERY );
+ OUString sServiceName;
+ if( xNamed.is() )
+ sServiceName = xNamed->getName();
+ SpellErrorDescription aDesc( false, elem.xAlternatives->getWord(),
+ elem.xAlternatives->getLocale(), elem.xAlternatives->getAlternatives(), nullptr);
+ SfxGrabBagItem aSpellErrorDescription(EE_CHAR_GRABBAG);
+ aSpellErrorDescription.GetGrabBag()["SpellErrorDescription"] <<= aDesc.toSequence();
+ m_xSentenceED->SetAttrib(aSpellErrorDescription, nStartPosition, nEndPosition);
+ }
+ else if(elem.bIsGrammarError )
+ {
+ beans::PropertyValues aProperties = elem.aGrammarError.aProperties;
+ OUString sFullCommentURL;
+ sal_Int32 i = 0;
+ while ( sFullCommentURL.isEmpty() && i < aProperties.getLength() )
+ {
+ if ( aProperties[i].Name == "FullCommentURL" )
+ {
+ uno::Any aValue = aProperties[i].Value;
+ aValue >>= sFullCommentURL;
+ }
+ ++i;
+ }
+
+ SpellErrorDescription aDesc( true,
+ elem.sText,
+ LanguageTag::convertToLocale( elem.eLanguage ),
+ elem.aGrammarError.aSuggestions,
+ elem.xGrammarChecker,
+ &elem.sDialogTitle,
+ &elem.aGrammarError.aFullComment,
+ &elem.aGrammarError.aRuleIdentifier,
+ &sFullCommentURL );
+
+ SfxGrabBagItem aSpellErrorDescriptionItem(EE_CHAR_GRABBAG);
+ aSpellErrorDescriptionItem.GetGrabBag()["SpellErrorDescription"] <<= aDesc.toSequence();
+ m_xSentenceED->SetAttrib(aSpellErrorDescriptionItem, nStartPosition, nEndPosition);
+ }
+
+ if (elem.bIsField)
+ m_xSentenceED->SetAttrib(SvxBackgroundColorItem(COL_LIGHTGRAY, EE_CHAR_BKGCOLOR), nStartPosition, nEndPosition);
+ m_xSentenceED->SetAttrib(SvxLanguageItem(elem.eLanguage, EE_CHAR_LANGUAGE), nStartPosition, nEndPosition);
+ nStartPosition = nEndPosition;
+ }
+ }
+ //the edit field needs to be modified to apply the change from the ApplyChangeAllList
+ if(!bHasReplaced)
+ m_xSentenceED->ClearModifyFlag();
+ m_xSentenceED->ResetUndo();
+ m_xUndoPB->set_sensitive(false);
+ bRet = nStartPosition > 0;
+ }
+ return bRet;
+}
+/*-------------------------------------------------------------------------
+ replace errors that have a replacement in the ChangeAllList
+ returns false if the result doesn't contain errors after the replacement
+ -----------------------------------------------------------------------*/
+bool SpellDialog::ApplyChangeAllList_Impl(SpellPortions& rSentence, bool &bHasReplaced)
+{
+ bHasReplaced = false;
+ bool bRet = true;
+ Reference<XDictionary> xChangeAll = LinguMgr::GetChangeAllList();
+ if(!xChangeAll->getCount())
+ return bRet;
+ bRet = false;
+ for (auto & elem : rSentence)
+ {
+ if(elem.xAlternatives.is())
+ {
+ const OUString &rString = elem.sText;
+
+ Reference<XDictionaryEntry> xEntry = xChangeAll->getEntry(rString);
+
+ if(xEntry.is())
+ {
+ elem.sText = getDotReplacementString(rString, xEntry->getReplacementText());
+ elem.xAlternatives = nullptr;
+ bHasReplaced = true;
+ }
+ else
+ bRet = true;
+ }
+ else if( elem.bIsGrammarError )
+ bRet = true;
+ }
+ return bRet;
+}
+
+SentenceEditWindow_Impl::SentenceEditWindow_Impl()
+ : m_pSpellDialog(nullptr)
+ , m_pToolbar(nullptr)
+ , m_nErrorStart(0)
+ , m_nErrorEnd(0)
+ , m_bIsUndoEditMode(false)
+{
+}
+
+void SentenceEditWindow_Impl::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ Size aSize(pDrawingArea->get_approximate_digit_width() * 60,
+ pDrawingArea->get_text_height() * 6);
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+ WeldEditView::SetDrawingArea(pDrawingArea);
+ // tdf#132288 don't merge equal adjacent attributes
+ m_xEditEngine->DisableAttributeExpanding();
+}
+
+SentenceEditWindow_Impl::~SentenceEditWindow_Impl()
+{
+}
+
+namespace
+{
+ const EECharAttrib* FindCharAttrib(int nPosition, sal_uInt16 nWhich, std::vector<EECharAttrib>& rAttribList)
+ {
+ for (auto it = rAttribList.rbegin(); it != rAttribList.rend(); ++it)
+ {
+ const auto& rTextAtr = *it;
+ if (rTextAtr.pAttr->Which() != nWhich)
+ continue;
+ if (rTextAtr.nStart <= nPosition && rTextAtr.nEnd >= nPosition)
+ {
+ return &rTextAtr;
+ }
+ }
+
+ return nullptr;
+ }
+
+ void ExtractErrorDescription(const EECharAttrib& rEECharAttrib, SpellErrorDescription& rSpellErrorDescription)
+ {
+ css::uno::Sequence<css::uno::Any> aSequence;
+ static_cast<const SfxGrabBagItem*>(rEECharAttrib.pAttr)->GetGrabBag().find("SpellErrorDescription")->second >>= aSequence;
+ rSpellErrorDescription.fromSequence(aSequence);
+ }
+}
+
+/*-------------------------------------------------------------------------
+ The selection before inputting a key may have a range or not
+ and it may be inside or outside of field or error attributes.
+ A range may include the attribute partially, completely or together
+ with surrounding text. It may also contain more than one attribute
+ or no attribute at all.
+ Depending on this starting conditions some actions are necessary:
+ Attempts to delete a field are only allowed if the selection is the same
+ as the field's selection. Otherwise the field has to be selected and the key
+ input action has to be skipped.
+ Input of text at the start of the field requires the field attribute to be
+ corrected - it is not allowed to grow.
+
+ In case of errors the appending of text should grow the error attribute because
+ that is what the user usually wants to do.
+
+ Backspace at the start of the attribute requires to find out if a field ends
+ directly in front of the cursor position. In case of a field this attribute has to be
+ selected otherwise the key input method is allowed.
+
+ All changes outside of the error attributes switch the dialog mode to a "Undo edit" state that
+ removes all visible attributes and switches off further attribute checks.
+ Undo in this restarts the dialog with a current sentence newly presented.
+ All changes to the sentence are undone including the ones before the "Undo edit state" has been reached
+
+ We end up with 9 types of selection
+ 1 (LEFT_NO) - no range, start of attribute - can also be 3 at the same time
+ 2 (INSIDE_NO) - no range, inside of attribute
+ 3 (RIGHT_NO) - no range, end of attribute - can also be 1 at the same time
+ 4 (FULL) - range, same as attribute
+ 5 (INSIDE_YES) - range, inside of the attribute
+ 6 (BRACE)- range, from outside of the attribute to the inside or
+ including the complete attribute and something outside,
+ maybe more than one attribute
+ 7 (OUTSIDE_NO) - no range, not at an attribute
+ 8 (OUTSIDE_YES) - range, completely outside of all attributes
+
+ What has to be done depending on the attribute type involved
+ possible actions: UE - Undo edit mode
+ CO - Continue, no additional action is required
+ FS - Field has to be completely selected
+ EX - The attribute has to be expanded to include the added text
+
+ 1 - backspace delete any other
+ UE on field FS on error CO on field FS on error CO
+
+ 2 - on field FS on error C
+ 3 - backspace delete any other
+ on field FS on error CO UE on field UE on error EX
+
+ if 1 and 3 happen to apply both then backspace and other handling is 1 delete is 3
+
+ 4 - on field UE and on error CO
+ 5 - on field FS and on error CO
+ 6 - on field FS and on error UE
+ 7 - UE
+ 8 - UE
+ -----------------------------------------------------------------------*/
+#define INVALID 0
+#define LEFT_NO 1
+#define INSIDE_NO 2
+#define RIGHT_NO 3
+#define FULL 4
+#define INSIDE_YES 5
+#define BRACE 6
+#define OUTSIDE_NO 7
+#define OUTSIDE_YES 8
+
+#define ACTION_UNDOEDIT 0
+#define ACTION_CONTINUE 1
+#define ACTION_SELECTFIELD 2
+#define ACTION_EXPAND 3
+
+bool SentenceEditWindow_Impl::KeyInput(const KeyEvent& rKeyEvt)
+{
+ if (rKeyEvt.GetKeyCode().GetCode() == KEY_TAB)
+ return false;
+
+ bool bConsumed = false;
+
+ bool bChange = TextEngine::DoesKeyChangeText( rKeyEvt );
+ if (bChange && !IsUndoEditMode())
+ {
+ bConsumed = true;
+
+ ESelection aCurrentSelection(m_xEditView->GetSelection());
+ aCurrentSelection.Adjust();
+
+ //determine if the selection contains a field
+ bool bHasFieldLeft = false;
+ bool bHasErrorLeft = false;
+
+ bool bHasRange = aCurrentSelection.HasRange();
+ sal_uInt8 nSelectionType = 0; // invalid type!
+
+ std::vector<EECharAttrib> aAttribList;
+ m_xEditEngine->GetCharAttribs(0, aAttribList);
+
+ auto nCursor = aCurrentSelection.nStartPos;
+ const EECharAttrib* pBackAttr = FindCharAttrib(nCursor, EE_CHAR_BKGCOLOR, aAttribList);
+ const EECharAttrib* pErrorAttr = FindCharAttrib(nCursor, EE_CHAR_GRABBAG, aAttribList);
+ const EECharAttrib* pBackAttrLeft = nullptr;
+ const EECharAttrib* pErrorAttrLeft = nullptr;
+
+ bool bHasField = pBackAttr != nullptr && (bHasRange || pBackAttr->nEnd > nCursor);
+ bool bHasError = pErrorAttr != nullptr && (bHasRange || pErrorAttr->nEnd > nCursor);
+ if (bHasRange)
+ {
+ if (pBackAttr &&
+ pBackAttr->nStart == aCurrentSelection.nStartPos &&
+ pBackAttr->nEnd == aCurrentSelection.nEndPos)
+ {
+ nSelectionType = FULL;
+ }
+ else if (pErrorAttr &&
+ pErrorAttr->nStart <= aCurrentSelection.nStartPos &&
+ pErrorAttr->nEnd >= aCurrentSelection.nEndPos)
+ {
+ nSelectionType = INSIDE_YES;
+ }
+ else
+ {
+ nSelectionType = bHasField||bHasError ? BRACE : OUTSIDE_NO;
+ while (nCursor < aCurrentSelection.nEndPos)
+ {
+ ++nCursor;
+ const EECharAttrib* pIntBackAttr = FindCharAttrib(nCursor, EE_CHAR_BKGCOLOR, aAttribList);
+ const EECharAttrib* pIntErrorAttr = FindCharAttrib(nCursor, EE_CHAR_GRABBAG, aAttribList);
+ //if any attr has been found then BRACE
+ if (pIntBackAttr || pIntErrorAttr)
+ nSelectionType = BRACE;
+ //the field has to be selected
+ if (pIntBackAttr && !pBackAttr)
+ pBackAttr = pIntBackAttr;
+ bHasField |= pIntBackAttr != nullptr;
+ }
+ }
+ }
+ else
+ {
+ //no range selection: then 1 2 3 and 8 are possible
+ const EECharAttrib* pCurAttr = pBackAttr ? pBackAttr : pErrorAttr;
+ if (pCurAttr)
+ {
+ nSelectionType = pCurAttr->nStart == aCurrentSelection.nStartPos ?
+ LEFT_NO : pCurAttr->nEnd == aCurrentSelection.nEndPos ? RIGHT_NO : INSIDE_NO;
+ }
+ else
+ nSelectionType = OUTSIDE_NO;
+
+ bHasFieldLeft = pBackAttr && pBackAttr->nEnd == nCursor;
+ if(bHasFieldLeft)
+ {
+ pBackAttrLeft = pBackAttr;
+ pBackAttr = nullptr;
+ }
+ bHasErrorLeft = pErrorAttr && pErrorAttr->nEnd == nCursor;
+ if(bHasErrorLeft)
+ {
+ pErrorAttrLeft = pErrorAttr;
+ pErrorAttr = nullptr;
+ }
+
+ //check previous position if this exists
+ //that is a redundant in the case the attribute found above already is on the left cursor side
+ //but it's o.k. for two errors/fields side by side
+ if (nCursor)
+ {
+ --nCursor;
+ pBackAttrLeft = FindCharAttrib(nCursor, EE_CHAR_BKGCOLOR, aAttribList);
+ pErrorAttrLeft = FindCharAttrib(nCursor, EE_CHAR_GRABBAG, aAttribList);
+ bHasFieldLeft = pBackAttrLeft !=nullptr;
+ bHasErrorLeft = pErrorAttrLeft != nullptr;
+ ++nCursor;
+ }
+ }
+ //Here we have to determine if the error found is the one currently active
+ bool bIsErrorActive = (pErrorAttr && pErrorAttr->nStart == m_nErrorStart) ||
+ (pErrorAttrLeft && pErrorAttrLeft->nStart == m_nErrorStart);
+
+ SAL_WARN_IF(
+ nSelectionType == INVALID, "cui.dialogs",
+ "selection type not set");
+
+ const vcl::KeyCode& rKeyCode = rKeyEvt.GetKeyCode();
+ bool bDelete = rKeyCode.GetCode() == KEY_DELETE;
+ bool bBackspace = rKeyCode.GetCode() == KEY_BACKSPACE;
+
+ sal_Int8 nAction = ACTION_CONTINUE;
+ switch(nSelectionType)
+ {
+// 1 - backspace delete any other
+// UE on field FS on error CO on field FS on error CO
+ case LEFT_NO :
+ if(bBackspace)
+ {
+ nAction = bHasFieldLeft ? ACTION_SELECTFIELD : ACTION_UNDOEDIT;
+ //to force the use of pBackAttrLeft
+ pBackAttr = nullptr;
+ }
+ else if(bDelete)
+ nAction = bHasField ? ACTION_SELECTFIELD : ACTION_CONTINUE;
+ else
+ nAction = bHasError && !nCursor ? ACTION_CONTINUE :
+ bHasError ? ACTION_EXPAND : bHasErrorLeft ? ACTION_CONTINUE : ACTION_UNDOEDIT;
+ break;
+// 2 - on field FS on error C
+ case INSIDE_NO :
+ nAction = bHasField ? ACTION_SELECTFIELD :
+ bIsErrorActive ? ACTION_CONTINUE : ACTION_UNDOEDIT;
+ break;
+// 3 - backspace delete any other
+// on field FS on error CO UE on field UE on error EX
+ case RIGHT_NO :
+ if(bBackspace)
+ nAction = bHasFieldLeft ? ACTION_SELECTFIELD : ACTION_CONTINUE;
+ else if(bDelete)
+ nAction = bHasFieldLeft && bHasError ? ACTION_CONTINUE : ACTION_UNDOEDIT;
+ else
+ nAction = bHasFieldLeft && bHasError ? ACTION_EXPAND :
+ bHasError ? ACTION_CONTINUE : bHasErrorLeft ? ACTION_EXPAND :ACTION_UNDOEDIT;
+ break;
+// 4 - on field UE and on error CO
+ case FULL :
+ nAction = ACTION_UNDOEDIT;
+ break;
+// 5 - on field FS and on error CO
+ case INSIDE_YES :
+ nAction = bHasField ? ACTION_SELECTFIELD : ACTION_CONTINUE;
+ break;
+// 6 - on field FS and on error UE
+ case BRACE :
+ nAction = bHasField ? ACTION_SELECTFIELD : ACTION_UNDOEDIT;
+ break;
+// 7 - UE
+// 8 - UE
+ case OUTSIDE_NO :
+ case OUTSIDE_YES:
+ nAction = ACTION_UNDOEDIT;
+ break;
+ }
+ //save the current paragraph
+ sal_Int32 nCurrentLen = m_xEditEngine->GetText().getLength();
+ if (nAction != ACTION_SELECTFIELD)
+ {
+ m_xEditView->PostKeyEvent(rKeyEvt);
+ }
+ else
+ {
+ const EECharAttrib* pCharAttr = pBackAttr ? pBackAttr : pBackAttrLeft;
+ if (pCharAttr)
+ m_xEditView->SetSelection(ESelection(0, pCharAttr->nStart, 0, pCharAttr->nEnd));
+ }
+ if(nAction == ACTION_EXPAND)
+ {
+ DBG_ASSERT(pErrorAttrLeft || pErrorAttr, "where is the error");
+ //text has been added on the right and only the 'error attribute has to be corrected
+ if (pErrorAttrLeft)
+ {
+ SpellErrorDescription aSpellErrorDescription;
+ ExtractErrorDescription(*pErrorAttrLeft, aSpellErrorDescription);
+
+ std::unique_ptr<SfxPoolItem> xNewError(pErrorAttrLeft->pAttr->Clone());
+ sal_Int32 nStart = pErrorAttrLeft->nStart;
+ sal_Int32 nEnd = pErrorAttrLeft->nEnd + 1;
+ m_xEditEngine->RemoveAttribs(ESelection(0, nStart, 0, nEnd), false, EE_CHAR_GRABBAG);
+ SetAttrib(*xNewError, nStart, nEnd);
+ //only active errors move the mark
+ if (bIsErrorActive)
+ {
+ bool bGrammar = aSpellErrorDescription.bIsGrammarError;
+ MoveErrorMarkTo(nStart, nEnd, bGrammar);
+ }
+ }
+ //text has been added on the left then the error attribute has to be expanded and the
+ //field attribute on the right - if any - has to be contracted
+ else if (pErrorAttr)
+ {
+ SpellErrorDescription aSpellErrorDescription;
+ ExtractErrorDescription(*pErrorAttr, aSpellErrorDescription);
+
+ //determine the change
+ sal_Int32 nAddedChars = m_xEditEngine->GetText().getLength() - nCurrentLen;
+
+ std::unique_ptr<SfxPoolItem> xNewError(pErrorAttr->pAttr->Clone());
+ sal_Int32 nStart = pErrorAttr->nStart + nAddedChars;
+ sal_Int32 nEnd = pErrorAttr->nEnd + nAddedChars;
+ m_xEditEngine->RemoveAttribs(ESelection(0, nStart, 0, nEnd), false, EE_CHAR_GRABBAG);
+ nStart = pErrorAttr->nStart;
+ SetAttrib(*xNewError, nStart, nEnd);
+ //only if the error is active the mark is moved here
+ if (bIsErrorActive)
+ {
+ bool bGrammar = aSpellErrorDescription.bIsGrammarError;
+ MoveErrorMarkTo(nStart, nEnd, bGrammar);
+ }
+ xNewError.reset();
+
+ if (pBackAttrLeft)
+ {
+ std::unique_ptr<SfxPoolItem> xNewBack(pBackAttrLeft->pAttr->Clone());
+ sal_Int32 _nStart = pBackAttrLeft->nStart + nAddedChars;
+ sal_Int32 _nEnd = pBackAttrLeft->nEnd + nAddedChars;
+ m_xEditEngine->RemoveAttribs(ESelection(0, _nStart, 0, _nEnd), false, EE_CHAR_BKGCOLOR);
+ _nStart = pBackAttrLeft->nStart;
+ SetAttrib(*xNewBack, _nStart, _nEnd);
+ }
+ }
+ }
+ else if(nAction == ACTION_UNDOEDIT)
+ {
+ SetUndoEditMode(true);
+ }
+ //make sure the error positions are correct after text changes
+ //the old attribute may have been deleted
+ //all changes inside of the current error leave the error attribute at the current
+ //start position
+ if (!IsUndoEditMode() && bIsErrorActive)
+ {
+ const EECharAttrib* pFontColor = FindCharAttrib(nCursor, EE_CHAR_COLOR, aAttribList);
+ const EECharAttrib* pErrorAttrib = FindCharAttrib(m_nErrorStart, EE_CHAR_GRABBAG, aAttribList);
+ if (pFontColor && pErrorAttrib)
+ {
+ m_nErrorStart = pFontColor->nStart;
+ m_nErrorEnd = pFontColor->nEnd;
+ if (pErrorAttrib->nStart != m_nErrorStart || pErrorAttrib->nEnd != m_nErrorEnd)
+ {
+ std::unique_ptr<SfxPoolItem> xNewError(pErrorAttrib->pAttr->Clone());
+ assert(pErrorAttr);
+ m_xEditEngine->RemoveAttribs(ESelection(0, pErrorAttr->nStart, 0, pErrorAttr->nEnd), false, EE_CHAR_GRABBAG);
+ SetAttrib(*xNewError, m_nErrorStart, m_nErrorEnd);
+ }
+ }
+ }
+ //this is not a modification anymore
+ if(nAction != ACTION_SELECTFIELD && !m_bIsUndoEditMode)
+ CallModifyLink();
+ }
+ else
+ bConsumed = m_xEditView->PostKeyEvent(rKeyEvt);
+
+ return bConsumed;
+}
+
+void SentenceEditWindow_Impl::Init(weld::Toolbar* pToolbar)
+{
+ m_pToolbar = pToolbar;
+ m_pToolbar->connect_clicked(LINK(this,SentenceEditWindow_Impl,ToolbarHdl));
+}
+
+IMPL_LINK(SentenceEditWindow_Impl, ToolbarHdl, const OString&, rCurItemId, void)
+{
+ if (rCurItemId == "paste")
+ {
+ m_xEditView->Paste();
+ CallModifyLink();
+ }
+ else if (rCurItemId == "insert")
+ {
+ if (vcl::GetGetSpecialCharsFunction())
+ {
+ OUString aChars = vcl::GetGetSpecialCharsFunction()(GetDrawingArea(), m_xEditEngine->GetStandardFont(0));
+ if (!aChars.isEmpty())
+ {
+ ESelection aCurrentSelection(m_xEditView->GetSelection());
+ m_xEditEngine->QuickInsertText(aChars, aCurrentSelection);
+ CallModifyLink();
+ }
+ }
+ }
+}
+
+bool SentenceEditWindow_Impl::MarkNextError( bool bIgnoreCurrentError, const css::uno::Reference<css::linguistic2::XSpellChecker1>& xSpell )
+{
+ if (bIgnoreCurrentError)
+ m_aIgnoreErrorsAt.insert( m_nErrorStart );
+
+ const sal_Int32 nTextLen = m_xEditEngine->GetTextLen(0);
+
+ if (m_nErrorEnd >= nTextLen - 1)
+ return false;
+ //if it's not already modified the modified flag has to be reset at the end of the marking
+ bool bModified = IsModified();
+ bool bRet = false;
+ const sal_Int32 nOldErrorStart = m_nErrorStart;
+ const sal_Int32 nOldErrorEnd = m_nErrorEnd;
+
+ //create a cursor behind the end of the last error
+ //- or at 0 at the start of the sentence
+ sal_Int32 nCursor(m_nErrorEnd ? m_nErrorEnd + 1 : 0);
+
+ //search for SpellErrorDescription
+ SpellErrorDescription aSpellErrorDescription;
+
+ std::vector<EECharAttrib> aAttribList;
+ m_xEditEngine->GetCharAttribs(0, aAttribList);
+
+ //iterate over the text and search for the next error that maybe has
+ //to be replace by a ChangeAllList replacement
+ bool bGrammarError = false;
+ while (nCursor < nTextLen)
+ {
+ const SpellErrorDescription* pSpellErrorDescription = nullptr;
+ const EECharAttrib* pEECharAttrib = nullptr;
+
+ sal_Int32 nMinPos = nTextLen + 1;
+ for (const auto& rTextAtr : aAttribList)
+ {
+ if (rTextAtr.pAttr->Which() != EE_CHAR_GRABBAG)
+ continue;
+ if (rTextAtr.nEnd > nCursor && rTextAtr.nStart < nMinPos)
+ {
+ nMinPos = rTextAtr.nStart;
+ pEECharAttrib = &rTextAtr;
+ }
+ }
+
+ if (pEECharAttrib)
+ {
+ ExtractErrorDescription(*pEECharAttrib, aSpellErrorDescription);
+
+ bGrammarError = aSpellErrorDescription.bIsGrammarError;
+ m_nErrorStart = pEECharAttrib->nStart;
+ m_nErrorEnd = pEECharAttrib->nEnd;
+
+ pSpellErrorDescription = &aSpellErrorDescription;
+ }
+
+ nCursor = std::max(nCursor, nMinPos); // move forward if possible
+
+ // maybe the error found here is already in the ChangeAllList and has to be replaced
+ Reference<XDictionary> xChangeAll = LinguMgr::GetChangeAllList();
+ Reference<XDictionaryEntry> xEntry;
+
+ if (xChangeAll->getCount() && pSpellErrorDescription &&
+ (xEntry = xChangeAll->getEntry( pSpellErrorDescription->sErrorText )).is())
+ {
+ OUString sReplacement(getDotReplacementString(GetErrorText(), xEntry->getReplacementText()));
+
+ int nLenChange = ChangeMarkedWord(sReplacement, LanguageTag::convertToLanguageType(pSpellErrorDescription->aLocale));
+
+ nCursor += sReplacement.getLength();
+
+ if (nLenChange)
+ m_xEditEngine->GetCharAttribs(0, aAttribList);
+ // maybe the error found here is already added to the dictionary and has to be ignored
+ }
+ else if(pSpellErrorDescription && !bGrammarError &&
+ xSpell->isValid(GetErrorText(),
+ static_cast<sal_uInt16>(LanguageTag::convertToLanguageType( pSpellErrorDescription->aLocale )),
+ Sequence< PropertyValue >() ))
+ {
+ ++nCursor;
+ }
+ else
+ break;
+ }
+
+ //if an attrib has been found search for the end of the error string
+ if (nCursor < nTextLen)
+ {
+ MoveErrorMarkTo(nCursor, m_nErrorEnd, bGrammarError);
+ bRet = true;
+ //add an undo action
+ std::unique_ptr<SpellUndoAction_Impl> pAction(new SpellUndoAction_Impl(
+ SPELLUNDO_CHANGE_NEXTERROR, GetSpellDialog()->aDialogUndoLink));
+ pAction->SetErrorMove(nOldErrorStart, nOldErrorEnd);
+
+ if (GetErrorDescription(aSpellErrorDescription, nOldErrorStart))
+ {
+ pAction->SetErrorLanguageSelected(aSpellErrorDescription.aSuggestions.hasElements() &&
+ LanguageTag(aSpellErrorDescription.aLocale).getLanguageType() == GetSpellDialog()->m_xLanguageLB->get_active_id());
+ }
+ else
+ pAction->SetErrorLanguageSelected(false);
+
+ AddUndoAction(std::move(pAction));
+ }
+ else
+ m_nErrorStart = m_nErrorEnd = nTextLen;
+ if( !bModified )
+ ClearModifyFlag();
+ SpellDialog* pSpellDialog = GetSpellDialog();
+ pSpellDialog->m_xIgnorePB->set_sensitive(bRet);
+ pSpellDialog->m_xIgnoreAllPB->set_sensitive(bRet);
+ pSpellDialog->m_xAutoCorrPB->set_sensitive(bRet);
+ pSpellDialog->m_xAddToDictMB->set_sensitive(bRet);
+ pSpellDialog->m_xAddToDictPB->set_sensitive(bRet);
+ return bRet;
+}
+
+void SentenceEditWindow_Impl::MoveErrorMarkTo(sal_Int32 nStart, sal_Int32 nEnd, bool bGrammarError)
+{
+ ESelection aAll(0, 0, 0, EE_TEXTPOS_ALL);
+ m_xEditEngine->RemoveAttribs(aAll, false, EE_CHAR_COLOR);
+ m_xEditEngine->RemoveAttribs(aAll, false, EE_CHAR_WEIGHT);
+ m_xEditEngine->RemoveAttribs(aAll, false, EE_CHAR_WEIGHT_CJK);
+ m_xEditEngine->RemoveAttribs(aAll, false, EE_CHAR_WEIGHT_CTL);
+
+ SfxItemSet aSet(m_xEditEngine->GetEmptyItemSet());
+ aSet.Put(SvxColorItem(bGrammarError ? COL_LIGHTBLUE : COL_LIGHTRED, EE_CHAR_COLOR));
+ aSet.Put(SvxWeightItem(WEIGHT_BOLD, EE_CHAR_WEIGHT));
+ aSet.Put(SvxWeightItem(WEIGHT_BOLD, EE_CHAR_WEIGHT_CJK));
+ aSet.Put(SvxWeightItem(WEIGHT_BOLD, EE_CHAR_WEIGHT_CTL));
+
+ m_xEditEngine->QuickSetAttribs(aSet, ESelection(0, nStart, 0, nEnd));
+
+ // Set the selection so the editview will autoscroll to make this visible
+ // unless (tdf#133958) the selection already overlaps this range
+ ESelection aCurrentSelection = m_xEditView->GetSelection();
+ aCurrentSelection.Adjust();
+ bool bCurrentSelectionInRange = nStart <= aCurrentSelection.nEndPos && aCurrentSelection.nStartPos <= nEnd;
+ if (!bCurrentSelectionInRange)
+ {
+ m_xEditView->SetSelection(ESelection(0, nStart));
+ }
+
+ Invalidate();
+
+ m_nErrorStart = nStart;
+ m_nErrorEnd = nEnd;
+}
+
+int SentenceEditWindow_Impl::ChangeMarkedWord(const OUString& rNewWord, LanguageType eLanguage)
+{
+ std::vector<EECharAttrib> aAttribList;
+ m_xEditEngine->GetCharAttribs(0, aAttribList);
+
+ //calculate length changes
+ auto nDiffLen = rNewWord.getLength() - m_nErrorEnd + m_nErrorStart;
+ //Remove spell error attribute
+ m_xEditEngine->UndoActionStart(SPELLUNDO_MOVE_ERROREND);
+ const EECharAttrib* pErrorAttrib = FindCharAttrib(m_nErrorStart, EE_CHAR_GRABBAG, aAttribList);
+ DBG_ASSERT(pErrorAttrib, "no error attribute found");
+ bool bSpellErrorDescription = false;
+ SpellErrorDescription aSpellErrorDescription;
+ if (pErrorAttrib)
+ {
+ ExtractErrorDescription(*pErrorAttrib, aSpellErrorDescription);
+ m_xEditEngine->RemoveAttribs(ESelection(0, pErrorAttrib->nStart, 0, pErrorAttrib->nEnd), false, EE_CHAR_GRABBAG);
+ bSpellErrorDescription = true;
+ }
+
+ const EECharAttrib* pBackAttrib = FindCharAttrib(m_nErrorStart, EE_CHAR_BKGCOLOR, aAttribList);
+
+ ESelection aSel(0, m_nErrorStart, 0, m_nErrorEnd);
+ m_xEditEngine->QuickInsertText(rNewWord, aSel);
+
+ const sal_Int32 nTextLen = m_xEditEngine->GetTextLen(0);
+
+ if (nDiffLen)
+ m_xEditEngine->GetCharAttribs(0, aAttribList);
+
+ if (!m_nErrorStart)
+ {
+ //attributes following an error at the start of the text are not moved but expanded from the
+ //text engine - this is done to keep full-paragraph-attributes
+ //in the current case that handling is not desired
+ const EECharAttrib* pLangAttrib = FindCharAttrib(m_nErrorEnd, EE_CHAR_LANGUAGE, aAttribList);
+
+ if (pLangAttrib && !pLangAttrib->nStart && pLangAttrib->nEnd == nTextLen)
+ {
+ LanguageType eNewLanguage = static_cast<const SvxLanguageItem*>(pLangAttrib->pAttr)->GetLanguage();
+ m_xEditEngine->RemoveAttribs(ESelection(0, pLangAttrib->nStart, 0, pLangAttrib->nEnd), false, EE_CHAR_LANGUAGE);
+ SetAttrib(SvxLanguageItem(eNewLanguage, EE_CHAR_LANGUAGE), m_nErrorEnd + nDiffLen, nTextLen);
+ }
+ }
+
+ // undo expanded attributes!
+ if (pBackAttrib && pBackAttrib->nStart < m_nErrorStart && pBackAttrib->nEnd == m_nErrorEnd + nDiffLen)
+ {
+ std::unique_ptr<SfxPoolItem> xNewBackground(pBackAttrib->pAttr->Clone());
+ const sal_Int32 nStart = pBackAttrib->nStart;
+
+ m_xEditEngine->RemoveAttribs(ESelection(0, pBackAttrib->nStart, 0, pBackAttrib->nEnd), false, EE_CHAR_BKGCOLOR);
+
+ SetAttrib(*xNewBackground, nStart, m_nErrorStart);
+ }
+ m_xEditEngine->SetModified();
+
+ //adjust end position
+ long nEndTemp = m_nErrorEnd;
+ nEndTemp += nDiffLen;
+ m_nErrorEnd = static_cast<sal_Int32>(nEndTemp);
+
+ std::unique_ptr<SpellUndoAction_Impl> pAction(new SpellUndoAction_Impl(
+ SPELLUNDO_MOVE_ERROREND, GetSpellDialog()->aDialogUndoLink));
+ pAction->SetOffset(nDiffLen);
+ AddUndoAction(std::move(pAction));
+ if (bSpellErrorDescription)
+ {
+ SfxGrabBagItem aSpellErrorDescriptionItem(EE_CHAR_GRABBAG);
+ aSpellErrorDescriptionItem.GetGrabBag()["SpellErrorDescription"] <<= aSpellErrorDescription.toSequence();
+ SetAttrib(aSpellErrorDescriptionItem, m_nErrorStart, m_nErrorEnd);
+ }
+ SetAttrib(SvxLanguageItem(eLanguage, EE_CHAR_LANGUAGE), m_nErrorStart, m_nErrorEnd);
+ m_xEditEngine->UndoActionEnd();
+
+ Invalidate();
+
+ return nDiffLen;
+}
+
+OUString SentenceEditWindow_Impl::GetErrorText() const
+{
+ return m_xEditEngine->GetText(ESelection(0, m_nErrorStart, 0, m_nErrorEnd));
+}
+
+bool SentenceEditWindow_Impl::GetErrorDescription(SpellErrorDescription& rSpellErrorDescription, sal_Int32 nPosition)
+{
+ std::vector<EECharAttrib> aAttribList;
+ m_xEditEngine->GetCharAttribs(0, aAttribList);
+
+ if (const EECharAttrib* pEECharAttrib = FindCharAttrib(nPosition, EE_CHAR_GRABBAG, aAttribList))
+ {
+ ExtractErrorDescription(*pEECharAttrib, rSpellErrorDescription);
+ return true;
+ }
+
+ return false;
+}
+
+bool SentenceEditWindow_Impl::GetAlternatives(SpellErrorDescription& rSpellErrorDescription)
+{
+ return GetErrorDescription(rSpellErrorDescription, m_nErrorStart);
+}
+
+void SentenceEditWindow_Impl::RestoreCurrentError()
+{
+ SpellErrorDescription aSpellErrorDescription;
+ if (GetErrorDescription(aSpellErrorDescription, m_nErrorStart))
+ {
+ if (aSpellErrorDescription.sErrorText != GetErrorText() )
+ ChangeMarkedWord(aSpellErrorDescription.sErrorText, LanguageTag::convertToLanguageType(aSpellErrorDescription.aLocale));
+ }
+}
+
+void SentenceEditWindow_Impl::SetAlternatives( const Reference< XSpellAlternatives>& xAlt )
+{
+ OUString aWord;
+ lang::Locale aLocale;
+ uno::Sequence< OUString > aAlts;
+ OUString sServiceName;
+ if (xAlt.is())
+ {
+ aWord = xAlt->getWord();
+ aLocale = xAlt->getLocale();
+ aAlts = xAlt->getAlternatives();
+ uno::Reference< container::XNamed > xNamed( xAlt, uno::UNO_QUERY );
+ if (xNamed.is())
+ sServiceName = xNamed->getName();
+ }
+ SpellErrorDescription aDesc( false, aWord, aLocale, aAlts, nullptr);
+ SfxGrabBagItem aSpellErrorDescription(EE_CHAR_GRABBAG);
+ aSpellErrorDescription.GetGrabBag()["SpellErrorDescription"] <<= aDesc.toSequence();
+ SetAttrib(aSpellErrorDescription, m_nErrorStart, m_nErrorEnd);
+}
+
+void SentenceEditWindow_Impl::SetAttrib(const SfxPoolItem& rItem, sal_Int32 nStart, sal_Int32 nEnd)
+{
+ SfxItemSet aSet(m_xEditEngine->GetEmptyItemSet());
+ aSet.Put(rItem);
+ m_xEditEngine->QuickSetAttribs(aSet, ESelection(0, nStart, 0, nEnd));
+ Invalidate();
+}
+
+void SentenceEditWindow_Impl::SetText( const OUString& rStr )
+{
+ m_nErrorStart = m_nErrorEnd = 0;
+ m_xEditEngine->SetText(rStr);
+}
+
+namespace {
+
+struct LanguagePosition_Impl
+{
+ sal_Int32 nPosition;
+ LanguageType eLanguage;
+
+ LanguagePosition_Impl(sal_Int32 nPos, LanguageType eLang) :
+ nPosition(nPos),
+ eLanguage(eLang)
+ {}
+};
+
+}
+
+typedef std::vector<LanguagePosition_Impl> LanguagePositions_Impl;
+
+static void lcl_InsertBreakPosition_Impl(
+ LanguagePositions_Impl& rBreakPositions, sal_Int32 nInsert, LanguageType eLanguage)
+{
+ LanguagePositions_Impl::iterator aStart = rBreakPositions.begin();
+ while(aStart != rBreakPositions.end())
+ {
+ if(aStart->nPosition == nInsert)
+ {
+ //the language of following starts has to overwrite
+ //the one of previous ends
+ aStart->eLanguage = eLanguage;
+ return;
+ }
+ else if(aStart->nPosition > nInsert)
+ {
+
+ rBreakPositions.insert(aStart, LanguagePosition_Impl(nInsert, eLanguage));
+ return;
+ }
+ else
+ ++aStart;
+ }
+ rBreakPositions.emplace_back(nInsert, eLanguage);
+}
+
+/*-------------------------------------------------------------------------
+ Returns the text in spell portions. Each portion contains text with an
+ equal language and attribute. The spell alternatives are empty.
+ -----------------------------------------------------------------------*/
+svx::SpellPortions SentenceEditWindow_Impl::CreateSpellPortions() const
+{
+ svx::SpellPortions aRet;
+
+ const sal_Int32 nTextLen = m_xEditEngine->GetTextLen(0);
+
+ std::vector<EECharAttrib> aAttribList;
+ m_xEditEngine->GetCharAttribs(0, aAttribList);
+
+ if (nTextLen)
+ {
+ int nCursor(0);
+ LanguagePositions_Impl aBreakPositions;
+ const EECharAttrib* pLastLang = nullptr;
+ const EECharAttrib* pLastError = nullptr;
+ LanguageType eLang = LANGUAGE_DONTKNOW;
+ const EECharAttrib* pError = nullptr;
+ while (nCursor < nTextLen)
+ {
+ const EECharAttrib* pLang = FindCharAttrib(nCursor, EE_CHAR_LANGUAGE, aAttribList);
+ if(pLang && pLang != pLastLang)
+ {
+ eLang = static_cast<const SvxLanguageItem*>(pLang->pAttr)->GetLanguage();
+ lcl_InsertBreakPosition_Impl(aBreakPositions, pLang->nStart, eLang);
+ lcl_InsertBreakPosition_Impl(aBreakPositions, pLang->nEnd, eLang);
+ pLastLang = pLang;
+ }
+ pError = FindCharAttrib(nCursor, EE_CHAR_GRABBAG, aAttribList);
+ if (pError && pLastError != pError)
+ {
+ lcl_InsertBreakPosition_Impl(aBreakPositions, pError->nStart, eLang);
+ lcl_InsertBreakPosition_Impl(aBreakPositions, pError->nEnd, eLang);
+ pLastError = pError;
+
+ }
+ ++nCursor;
+ }
+
+ if (aBreakPositions.empty())
+ {
+ //if all content has been overwritten the attributes may have been removed, too
+ svx::SpellPortion aPortion1;
+ aPortion1.eLanguage = GetSpellDialog()->GetSelectedLang_Impl();
+
+ aPortion1.sText = m_xEditEngine->GetText(ESelection(0, 0, 0, nTextLen));
+
+ aRet.push_back(aPortion1);
+ }
+ else
+ {
+ LanguagePositions_Impl::iterator aStart = aBreakPositions.begin();
+ //start should always be Null
+ eLang = aStart->eLanguage;
+ sal_Int32 nStart = aStart->nPosition;
+ DBG_ASSERT(!nStart, "invalid start position - language attribute missing?");
+ ++aStart;
+
+ while(aStart != aBreakPositions.end())
+ {
+ svx::SpellPortion aPortion1;
+ aPortion1.eLanguage = eLang;
+
+ aPortion1.sText = m_xEditEngine->GetText(ESelection(0, nStart, 0, aStart->nPosition));
+
+ bool bIsIgnoreError = m_aIgnoreErrorsAt.find( nStart ) != m_aIgnoreErrorsAt.end();
+ if( bIsIgnoreError )
+ {
+ aPortion1.bIgnoreThisError = true;
+ }
+ aRet.push_back(aPortion1);
+ nStart = aStart->nPosition;
+ eLang = aStart->eLanguage;
+ ++aStart;
+ }
+ }
+
+ // quick partly fix of #i71318. Correct fix needs to patch the EditEngine itself...
+ // this one will only prevent text from disappearing. It may to not have the
+ // correct language and will probably not spell checked...
+ const sal_uInt32 nPara = m_xEditEngine->GetParagraphCount();
+ if (nPara > 1)
+ {
+ OUStringBuffer aLeftOverText;
+ for (sal_uInt32 i = 1; i < nPara; ++i)
+ {
+ aLeftOverText.append("\x0a"); // the manual line break...
+ aLeftOverText.append(m_xEditEngine->GetText(i));
+ }
+ if (pError)
+ { // we need to add a new portion containing the left-over text
+ svx::SpellPortion aPortion2;
+ aPortion2.eLanguage = eLang;
+ aPortion2.sText = aLeftOverText.makeStringAndClear();
+ aRet.push_back( aPortion2 );
+ }
+ else
+ { // we just need to append the left-over text to the last portion (which had no errors)
+ aRet[ aRet.size() - 1 ].sText += aLeftOverText;
+ }
+ }
+ }
+
+ return aRet;
+}
+
+void SentenceEditWindow_Impl::Undo()
+{
+ SfxUndoManager& rUndoMgr = m_xEditEngine->GetUndoManager();
+ DBG_ASSERT(GetUndoActionCount(), "no undo actions available" );
+ if(!GetUndoActionCount())
+ return;
+ bool bSaveUndoEdit = IsUndoEditMode();
+ SpellUndoAction_Impl* pUndoAction;
+ //if the undo edit mode is active then undo all changes until the UNDO_EDIT_MODE action has been found
+ do
+ {
+ pUndoAction = static_cast<SpellUndoAction_Impl*>(rUndoMgr.GetUndoAction());
+ rUndoMgr.Undo();
+ }while(bSaveUndoEdit && SPELLUNDO_UNDO_EDIT_MODE != pUndoAction->GetId() && GetUndoActionCount());
+
+ if(bSaveUndoEdit || SPELLUNDO_CHANGE_GROUP == pUndoAction->GetId())
+ GetSpellDialog()->UpdateBoxes_Impl();
+}
+
+void SentenceEditWindow_Impl::ResetUndo()
+{
+ SfxUndoManager& rUndo = m_xEditEngine->GetUndoManager();
+ rUndo.Clear();
+}
+
+void SentenceEditWindow_Impl::AddUndoAction( std::unique_ptr<SfxUndoAction> pAction )
+{
+ SfxUndoManager& rUndoMgr = m_xEditEngine->GetUndoManager();
+ rUndoMgr.AddUndoAction(std::move(pAction));
+ GetSpellDialog()->m_xUndoPB->set_sensitive(true);
+}
+
+size_t SentenceEditWindow_Impl::GetUndoActionCount() const
+{
+ return m_xEditEngine->GetUndoManager().GetUndoActionCount();
+}
+
+void SentenceEditWindow_Impl::UndoActionStart( sal_uInt16 nId )
+{
+ m_xEditEngine->UndoActionStart(nId);
+}
+
+void SentenceEditWindow_Impl::UndoActionEnd()
+{
+ m_xEditEngine->UndoActionEnd();
+}
+
+void SentenceEditWindow_Impl::MoveErrorEnd(long nOffset)
+{
+ // Shouldn't we always add the real signed value instead???
+ if(nOffset > 0)
+ m_nErrorEnd = m_nErrorEnd - static_cast<sal_Int32>(nOffset);
+ else
+ m_nErrorEnd = m_nErrorEnd - static_cast<sal_Int32>(-nOffset);
+}
+
+
+void SentenceEditWindow_Impl::SetUndoEditMode(bool bSet)
+{
+ DBG_ASSERT(!bSet || m_bIsUndoEditMode != bSet, "SetUndoEditMode with equal values?");
+ m_bIsUndoEditMode = bSet;
+ //disable all buttons except the Change
+ SpellDialog* pSpellDialog = GetSpellDialog();
+ weld::Widget* aControls[] =
+ {
+ pSpellDialog->m_xChangeAllPB.get(),
+ pSpellDialog->m_xExplainFT.get(),
+ pSpellDialog->m_xIgnoreAllPB.get(),
+ pSpellDialog->m_xIgnoreRulePB.get(),
+ pSpellDialog->m_xIgnorePB.get(),
+ pSpellDialog->m_xSuggestionLB.get(),
+ pSpellDialog->m_xSuggestionFT.get(),
+ pSpellDialog->m_xLanguageFT.get(),
+ pSpellDialog->m_xLanguageLB->get_widget(),
+ pSpellDialog->m_xAddToDictMB.get(),
+ pSpellDialog->m_xAddToDictPB.get(),
+ pSpellDialog->m_xAutoCorrPB.get(),
+ nullptr
+ };
+ sal_Int32 nIdx = 0;
+ do
+ {
+ aControls[nIdx]->set_sensitive(false);
+ }
+ while(aControls[++nIdx]);
+
+ //remove error marks
+ ESelection aAll(0, 0, 0, EE_TEXTPOS_ALL);
+ m_xEditEngine->RemoveAttribs(aAll, false, EE_CHAR_COLOR);
+ m_xEditEngine->RemoveAttribs(aAll, false, EE_CHAR_WEIGHT);
+ m_xEditEngine->RemoveAttribs(aAll, false, EE_CHAR_WEIGHT_CJK);
+ m_xEditEngine->RemoveAttribs(aAll, false, EE_CHAR_WEIGHT_CTL);
+ Invalidate();
+
+ //put the appropriate action on the Undo-stack
+ AddUndoAction( std::make_unique<SpellUndoAction_Impl>(
+ SPELLUNDO_UNDO_EDIT_MODE, GetSpellDialog()->aDialogUndoLink) );
+ pSpellDialog->m_xChangePB->set_sensitive(true);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/dialogs/about.cxx b/cui/source/dialogs/about.cxx
new file mode 100644
index 000000000..99245b94b
--- /dev/null
+++ b/cui/source/dialogs/about.cxx
@@ -0,0 +1,260 @@
+/* -*- 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 <about.hxx>
+
+#include <osl/process.h> //osl_getProcessLocale
+#include <rtl/character.hxx> //rtl::isAsciiHexDigit
+#include <sal/log.hxx> //SAL_WARN
+#include <vcl/settings.hxx> //GetSettings
+#include <vcl/svapp.hxx> //Application::
+#include <vcl/virdev.hxx> //VirtualDevice
+#include <vcl/weld.hxx>
+
+#include <config_buildid.h> //EXTRA_BUILDID
+#include <dialmgr.hxx> //CuiResId
+#include <i18nlangtag/languagetag.hxx>
+#include <sfx2/app.hxx> //SfxApplication::loadBrandSvg
+#include <strings.hrc>
+#include <svtools/langhelp.hxx>
+#include <unotools/bootstrap.hxx> //utl::Bootstrap::getBuildIdData
+#include <unotools/configmgr.hxx> //ConfigManager::
+
+#include <com/sun/star/datatransfer/clipboard/SystemClipboard.hpp>
+#include <vcl/unohelp2.hxx>
+
+#include <config_feature_opencl.h>
+#if HAVE_FEATURE_OPENCL
+#include <opencl/openclwrapper.hxx>
+#endif
+#include <officecfg/Office/Calc.hxx>
+#include <officecfg/Office/Common.hxx>
+
+using namespace ::com::sun::star::uno;
+
+AboutDialog::AboutDialog(weld::Window *pParent)
+ : GenericDialogController(pParent, "cui/ui/aboutdialog.ui", "AboutDialog"),
+ m_pCreditsButton(m_xBuilder->weld_link_button("btnCredits")),
+ m_pWebsiteButton(m_xBuilder->weld_link_button("btnWebsite")),
+ m_pReleaseNotesButton(m_xBuilder->weld_link_button("btnReleaseNotes")),
+ m_pCloseButton(m_xBuilder->weld_button("btnClose")),
+ m_pCopyButton(m_xBuilder->weld_button("btnCopyVersion")),
+ m_pBrandImage(m_xBuilder->weld_image("imBrand")),
+ m_pAboutImage(m_xBuilder->weld_image("imAbout")),
+ m_pVersionLabel(m_xBuilder->weld_label("lbVersionString")),
+ m_pBuildCaption(m_xBuilder->weld_label("lbBuild")),
+ m_pBuildLabel(m_xBuilder->weld_link_button("lbBuildString")),
+ m_pEnvLabel(m_xBuilder->weld_label("lbEnvString")),
+ m_pUILabel(m_xBuilder->weld_label("lbUIString")),
+ m_pLocaleLabel(m_xBuilder->weld_label("lbLocaleString")),
+ m_pMiscLabel(m_xBuilder->weld_label("lbMiscString")),
+ m_pCopyrightLabel(m_xBuilder->weld_label("lbCopyright")) {
+
+ // Labels
+ m_pVersionLabel->set_label(GetVersionString());
+
+ OUString sbuildId = GetBuildString();
+ const long nMaxChar = 25;
+ if (IsStringValidGitHash(sbuildId)) {
+ m_pBuildLabel->set_uri("https://gerrit.libreoffice.org/gitweb?p=core.git;a=log;h="
+ + sbuildId);
+ m_pBuildLabel->set_label(sbuildId.getLength() > nMaxChar ? sbuildId.replaceAt(
+ nMaxChar, sbuildId.getLength() - nMaxChar, "...")
+ : sbuildId);
+ } else {
+ m_pBuildCaption->hide();
+ m_pBuildLabel->hide();
+ }
+
+ m_pEnvLabel->set_label(Application::GetHWOSConfInfo(1));
+ m_pUILabel->set_label(Application::GetHWOSConfInfo(2));
+ m_pLocaleLabel->set_label(GetLocaleString());
+ m_pMiscLabel->set_label(GetMiscString());
+ m_pCopyrightLabel->set_label(GetCopyrightString());
+
+ // Images
+ const long nWidth(m_pCopyrightLabel->get_preferred_size().getWidth());
+ BitmapEx aBackgroundBitmap;
+
+ if (SfxApplication::loadBrandSvg(Application::GetSettings()
+ .GetStyleSettings()
+ .GetDialogColor()
+ .IsDark()
+ ? "shell/logo_inverted"
+ : "shell/logo",
+ aBackgroundBitmap, nWidth * 0.8)) {
+ ScopedVclPtr<VirtualDevice> m_pVirDev =
+ m_pBrandImage->create_virtual_device();
+ m_pVirDev->SetOutputSizePixel(aBackgroundBitmap.GetSizePixel());
+ m_pVirDev->DrawBitmapEx(Point(0, 0), aBackgroundBitmap);
+ m_pBrandImage->set_image(m_pVirDev.get());
+ m_pVirDev.disposeAndClear();
+ }
+ if (SfxApplication::loadBrandSvg("shell/about", aBackgroundBitmap, nWidth * 0.9)) {
+ ScopedVclPtr<VirtualDevice> m_pVirDev =
+ m_pAboutImage->create_virtual_device();
+ m_pVirDev->SetOutputSizePixel(aBackgroundBitmap.GetSizePixel());
+ m_pVirDev->DrawBitmapEx(Point(0, 0), aBackgroundBitmap);
+ m_pAboutImage->set_image(m_pVirDev.get());
+ m_pVirDev.disposeAndClear();
+ }
+
+ // Links
+ m_pCreditsButton->set_uri(CuiResId(RID_SVXSTR_ABOUT_CREDITS_URL));
+
+ OUString sURL(officecfg::Office::Common::Help::StartCenter::InfoURL::get());
+ localizeWebserviceURI(sURL);
+ m_pWebsiteButton->set_uri(sURL);
+
+ sURL = officecfg::Office::Common::Menus::ReleaseNotesURL::get() +
+ "?LOvers=" + utl::ConfigManager::getProductVersion() + "&LOlocale=" +
+ LanguageTag(utl::ConfigManager::getUILocale()).getLanguage();
+ m_pReleaseNotesButton->set_uri(sURL);
+
+ // Handler
+ m_pCopyButton->connect_clicked(LINK(this, AboutDialog, HandleClick));
+ m_pCloseButton->grab_focus();
+}
+
+AboutDialog::~AboutDialog() {}
+
+bool AboutDialog::IsStringValidGitHash(const OUString &hash) {
+ for (int i = 0; i < hash.getLength(); i++) {
+ if (!std::isxdigit(hash[i])) {
+ return false;
+ }
+ }
+ return true;
+}
+
+OUString AboutDialog::GetVersionString() {
+ OUString sVersion = CuiResId("%ABOUTBOXPRODUCTVERSION%ABOUTBOXPRODUCTVERSIONSUFFIX");
+
+#ifdef _WIN64
+ sVersion += " (x64)";
+#elif defined(_WIN32)
+ sVersion += " (x86)";
+#endif
+ return sVersion;
+}
+
+OUString AboutDialog::GetBuildString()
+{
+ OUString sBuildId(utl::Bootstrap::getBuildIdData(""));
+ SAL_WARN_IF(sBuildId.isEmpty(), "cui.dialogs", "No BUILDID in bootstrap file");
+
+ return sBuildId;
+}
+
+OUString AboutDialog::GetLocaleString() {
+
+ OUString sLocaleStr;
+
+ rtl_Locale *pLocale;
+ osl_getProcessLocale(&pLocale);
+ if (pLocale && pLocale->Language) {
+ if (pLocale->Country && rtl_uString_getLength(pLocale->Country) > 0)
+ sLocaleStr = OUString::unacquired(&pLocale->Language) + "_" +
+ OUString::unacquired(&pLocale->Country);
+ else
+ sLocaleStr = OUString(pLocale->Language);
+ if (pLocale->Variant && rtl_uString_getLength(pLocale->Variant) > 0)
+ sLocaleStr += OUString(pLocale->Variant);
+ }
+
+ sLocaleStr = Application::GetSettings().GetLanguageTag().getBcp47() + " (" +
+ sLocaleStr + ")";
+
+ OUString aUILocaleStr =
+ Application::GetSettings().GetUILanguageTag().getBcp47();
+ OUString sUILocaleStr(CuiResId(RID_SVXSTR_ABOUT_UILOCALE));
+ if (sUILocaleStr.indexOf("$LOCALE") == -1) {
+ SAL_WARN("cui.dialogs", "translated uilocale string in translations "
+ "doesn't contain $LOCALE placeholder");
+ sUILocaleStr += " $LOCALE";
+ }
+ sUILocaleStr = sUILocaleStr.replaceAll("$LOCALE", aUILocaleStr);
+
+ return sLocaleStr + "; " + sUILocaleStr;
+}
+
+OUString AboutDialog::GetMiscString() {
+
+ OUString sMisc;
+
+ bool const extra = EXTRA_BUILDID[0] != '\0';
+ // extracted from the 'if' to avoid Clang -Wunreachable-code
+ if (extra) {
+ sMisc = EXTRA_BUILDID "\n";
+ }
+
+ OUString aCalcMode = "Calc: "; // Calc calculation mode
+
+#if HAVE_FEATURE_OPENCL
+ bool bOpenCL = openclwrapper::GPUEnv::isOpenCLEnabled();
+ if (bOpenCL)
+ aCalcMode += "CL";
+#else
+ const bool bOpenCL = false;
+#endif
+
+ static const bool bThreadingProhibited =
+ std::getenv("SC_NO_THREADED_CALCULATION");
+ bool bThreadedCalc = officecfg::Office::Calc::Formula::Calculation::
+ UseThreadedCalculationForFormulaGroups::get();
+
+ if (!bThreadingProhibited && !bOpenCL && bThreadedCalc) {
+ if (!aCalcMode.endsWith(" "))
+ aCalcMode += " ";
+ aCalcMode += "threaded";
+ }
+
+ sMisc += aCalcMode;
+
+ return sMisc;
+}
+
+OUString AboutDialog::GetCopyrightString() {
+ OUString sVendorTextStr(CuiResId(RID_SVXSTR_ABOUT_VENDOR));
+ OUString aCopyrightString =
+ sVendorTextStr + "\n" + CuiResId(RID_SVXSTR_ABOUT_COPYRIGHT) + "\n";
+
+ if (utl::ConfigManager::getProductName() == "LibreOffice")
+ aCopyrightString += CuiResId(RID_SVXSTR_ABOUT_BASED_ON);
+ else
+ aCopyrightString += CuiResId(RID_SVXSTR_ABOUT_DERIVED);
+
+ return aCopyrightString;
+}
+
+//special labels to comply with previous version info
+IMPL_LINK_NOARG(AboutDialog, HandleClick, weld::Button &, void) {
+ css::uno::Reference<css::datatransfer::clipboard::XClipboard> xClipboard =
+ css::datatransfer::clipboard::SystemClipboard::create(
+ comphelper::getProcessComponentContext());
+
+ OUString sInfo = "Version: " + m_pVersionLabel->get_label() + "\n" // version
+ "Build ID: " + GetBuildString() + "\n" + // build id
+ Application::GetHWOSConfInfo(0,false) + "\n" // env+UI
+ "Locale: " + m_pLocaleLabel->get_label() + "\n" + // locale
+ m_pMiscLabel->get_label(); // misc
+
+ vcl::unohelper::TextDataObject::CopyStringTo(sInfo, xClipboard);
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ \ No newline at end of file
diff --git a/cui/source/dialogs/colorpicker.cxx b/cui/source/dialogs/colorpicker.cxx
new file mode 100644
index 000000000..65f03fb3a
--- /dev/null
+++ b/cui/source/dialogs/colorpicker.cxx
@@ -0,0 +1,1334 @@
+/* -*- 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/uno/XComponentContext.hpp>
+#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
+#include <com/sun/star/beans/XPropertyAccess.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/awt/XWindow.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <vcl/customweld.hxx>
+#include <vcl/event.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/weld.hxx>
+#include <svx/hexcolorcontrol.hxx>
+#include <basegfx/color/bcolortools.hxx>
+#include <colorpicker.hxx>
+#include <cmath>
+#include <o3tl/typed_flags_set.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::ui::dialogs;
+using namespace ::com::sun::star::beans;
+using namespace ::basegfx;
+
+namespace {
+
+enum class UpdateFlags
+{
+ NONE = 0x00,
+ RGB = 0x01,
+ CMYK = 0x02,
+ HSB = 0x04,
+ ColorChooser = 0x08,
+ ColorSlider = 0x10,
+ Hex = 0x20,
+ All = 0x3f,
+};
+
+}
+
+namespace o3tl {
+ template<> struct typed_flags<UpdateFlags> : is_typed_flags<UpdateFlags, 0x3f> {};
+}
+
+
+namespace cui
+{
+
+namespace {
+
+enum class ColorComponent {
+ Red,
+ Green,
+ Blue,
+ Hue,
+ Saturation,
+ Brightness,
+ Cyan,
+ Yellow,
+ Magenta,
+ Key,
+};
+
+}
+
+// color space conversion helpers
+
+static void RGBtoHSV( double dR, double dG, double dB, double& dH, double& dS, double& dV )
+{
+ BColor result = basegfx::utils::rgb2hsv( BColor( dR, dG, dB ) );
+
+ dH = result.getX();
+ dS = result.getY();
+ dV = result.getZ();
+}
+
+static void HSVtoRGB(double dH, double dS, double dV, double& dR, double& dG, double& dB )
+{
+ BColor result = basegfx::utils::hsv2rgb( BColor( dH, dS, dV ) );
+
+ dR = result.getRed();
+ dG = result.getGreen();
+ dB = result.getBlue();
+}
+
+// CMYK values from 0 to 1
+static void CMYKtoRGB( double fCyan, double fMagenta, double fYellow, double fKey, double& dR, double& dG, double& dB )
+{
+ fCyan = (fCyan * ( 1.0 - fKey )) + fKey;
+ fMagenta = (fMagenta * ( 1.0 - fKey )) + fKey;
+ fYellow = (fYellow * ( 1.0 - fKey )) + fKey;
+
+ dR = std::max( std::min( ( 1.0 - fCyan ), 1.0), 0.0 );
+ dG = std::max( std::min( ( 1.0 - fMagenta ), 1.0), 0.0 );
+ dB = std::max( std::min( ( 1.0 - fYellow ), 1.0), 0.0 );
+}
+
+// CMY results from 0 to 1
+static void RGBtoCMYK( double dR, double dG, double dB, double& fCyan, double& fMagenta, double& fYellow, double& fKey )
+{
+ fCyan = 1 - dR;
+ fMagenta = 1 - dG;
+ fYellow = 1 - dB;
+
+ //CMYK and CMY values from 0 to 1
+ fKey = 1.0;
+ if( fCyan < fKey ) fKey = fCyan;
+ if( fMagenta < fKey ) fKey = fMagenta;
+ if( fYellow < fKey ) fKey = fYellow;
+
+ if( fKey >= 1.0 )
+ {
+ //Black
+ fCyan = 0.0;
+ fMagenta = 0.0;
+ fYellow = 0.0;
+ }
+ else
+ {
+ fCyan = ( fCyan - fKey ) / ( 1.0 - fKey );
+ fMagenta = ( fMagenta - fKey ) / ( 1.0 - fKey );
+ fYellow = ( fYellow - fKey ) / ( 1.0 - fKey );
+ }
+}
+
+namespace {
+
+class ColorPreviewControl : public weld::CustomWidgetController
+{
+private:
+ Color m_aColor;
+
+ virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) override;
+public:
+ ColorPreviewControl()
+ {
+ }
+
+ virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override
+ {
+ CustomWidgetController::SetDrawingArea(pDrawingArea);
+ pDrawingArea->set_size_request(pDrawingArea->get_approximate_digit_width() * 10,
+ pDrawingArea->get_text_height() * 2);
+ }
+
+ void SetColor(const Color& rCol)
+ {
+ if (rCol != m_aColor)
+ {
+ m_aColor = rCol;
+ Invalidate();
+ }
+ }
+};
+
+}
+
+void ColorPreviewControl::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ rRenderContext.SetFillColor(m_aColor);
+ rRenderContext.SetLineColor(m_aColor);
+ rRenderContext.DrawRect(tools::Rectangle(Point(0, 0), GetOutputSizePixel()));
+}
+
+namespace {
+
+enum ColorMode { HUE, SATURATION, BRIGHTNESS, RED, GREEN, BLUE };
+
+}
+
+const ColorMode DefaultMode = HUE;
+
+namespace {
+
+class ColorFieldControl : public weld::CustomWidgetController
+{
+public:
+ ColorFieldControl()
+ : meMode( DefaultMode )
+ , mdX( -1.0 )
+ , mdY( -1.0 )
+ , mbMouseCaptured(false)
+ {
+ }
+
+ virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override
+ {
+ CustomWidgetController::SetDrawingArea(pDrawingArea);
+ pDrawingArea->set_size_request(pDrawingArea->get_approximate_digit_width() * 40,
+ pDrawingArea->get_text_height() * 10);
+ }
+
+ virtual ~ColorFieldControl() override
+ {
+ mxBitmap.disposeAndClear();
+ }
+
+ virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override;
+ virtual void Resize() override;
+ virtual bool MouseButtonDown(const MouseEvent& rMEvt) override;
+ virtual bool MouseMove(const MouseEvent& rMEvt) override;
+ virtual bool MouseButtonUp(const MouseEvent& rMEvt) override;
+
+ void UpdateBitmap();
+ void ShowPosition( const Point& rPos, bool bUpdate );
+ void UpdatePosition();
+ void Modify();
+
+ void SetValues(Color aColor, ColorMode eMode, double x, double y);
+ double GetX() const { return mdX;}
+ double GetY() const { return mdY;}
+
+ void SetModifyHdl(const Link<ColorFieldControl&,void>& rLink) { maModifyHdl = rLink; }
+
+private:
+ ColorMode meMode;
+ Color maColor;
+ double mdX;
+ double mdY;
+ bool mbMouseCaptured;
+ Point maPosition;
+ VclPtr<VirtualDevice> mxBitmap;
+ Link<ColorFieldControl&,void> maModifyHdl;
+ std::vector<sal_uInt8> maRGB_Horiz;
+ std::vector<sal_uInt16> maGrad_Horiz;
+ std::vector<sal_uInt16> maPercent_Horiz;
+ std::vector<sal_uInt8> maRGB_Vert;
+ std::vector<sal_uInt16> maPercent_Vert;
+};
+
+}
+
+void ColorFieldControl::UpdateBitmap()
+{
+ const Size aSize(GetOutputSizePixel());
+
+ if (mxBitmap && mxBitmap->GetOutputSizePixel() != aSize)
+ mxBitmap.disposeAndClear();
+
+ const sal_Int32 nWidth = aSize.Width();
+ const sal_Int32 nHeight = aSize.Height();
+
+ if (nWidth == 0 || nHeight == 0)
+ return;
+
+ if (!mxBitmap)
+ {
+ mxBitmap = VclPtr<VirtualDevice>::Create();
+ mxBitmap->SetOutputSizePixel(aSize);
+
+ maRGB_Horiz.resize( nWidth );
+ maGrad_Horiz.resize( nWidth );
+ maPercent_Horiz.resize( nWidth );
+
+ sal_uInt8* pRGB = maRGB_Horiz.data();
+ sal_uInt16* pGrad = maGrad_Horiz.data();
+ sal_uInt16* pPercent = maPercent_Horiz.data();
+
+ for( sal_Int32 x = 0; x < nWidth; x++ )
+ {
+ *pRGB++ = static_cast<sal_uInt8>((x * 256) / nWidth);
+ *pGrad++ = static_cast<sal_uInt16>((x * 359) / nWidth);
+ *pPercent++ = static_cast<sal_uInt16>((x * 100) / nWidth);
+ }
+
+ maRGB_Vert.resize(nHeight);
+ maPercent_Vert.resize(nHeight);
+
+ pRGB = maRGB_Vert.data();
+ pPercent = maPercent_Vert.data();
+
+ sal_Int32 y = nHeight;
+ while (y--)
+ {
+ *pRGB++ = static_cast<sal_uInt8>((y * 256) / nHeight);
+ *pPercent++ = static_cast<sal_uInt16>((y * 100) / nHeight);
+ }
+ }
+
+ sal_uInt8* pRGB_Horiz = maRGB_Horiz.data();
+ sal_uInt16* pGrad_Horiz = maGrad_Horiz.data();
+ sal_uInt16* pPercent_Horiz = maPercent_Horiz.data();
+ sal_uInt8* pRGB_Vert = maRGB_Vert.data();
+ sal_uInt16* pPercent_Vert = maPercent_Vert.data();
+
+ Color aBitmapColor(maColor);
+
+ sal_uInt16 nHue, nSat, nBri;
+ maColor.RGBtoHSB(nHue, nSat, nBri);
+
+ // this has been unlooped for performance reason, please do not merge back!
+
+ sal_uInt16 y = nHeight,x;
+
+ switch(meMode)
+ {
+ case HUE:
+ while (y--)
+ {
+ nBri = pPercent_Vert[y];
+ x = nWidth;
+ while (x--)
+ {
+ nSat = pPercent_Horiz[x];
+ mxBitmap->DrawPixel(Point(x,y), Color::HSBtoRGB(nHue, nSat, nBri));
+ }
+ }
+ break;
+ case SATURATION:
+ while (y--)
+ {
+ nBri = pPercent_Vert[y];
+ x = nWidth;
+ while (x--)
+ {
+ nHue = pGrad_Horiz[x];
+ mxBitmap->DrawPixel(Point(x,y), Color::HSBtoRGB(nHue, nSat, nBri));
+ }
+ }
+ break;
+ case BRIGHTNESS:
+ while (y--)
+ {
+ nSat = pPercent_Vert[y];
+ x = nWidth;
+ while (x--)
+ {
+ nHue = pGrad_Horiz[x];
+ mxBitmap->DrawPixel(Point(x,y), Color::HSBtoRGB(nHue, nSat, nBri));
+ }
+ }
+ break;
+ case RED:
+ while (y--)
+ {
+ aBitmapColor.SetGreen(pRGB_Vert[y]);
+ x = nWidth;
+ while (x--)
+ {
+ aBitmapColor.SetBlue(pRGB_Horiz[x]);
+ mxBitmap->DrawPixel(Point(x,y), aBitmapColor);
+ }
+ }
+ break;
+ case GREEN:
+ while (y--)
+ {
+ aBitmapColor.SetRed(pRGB_Vert[y]);
+ x = nWidth;
+ while (x--)
+ {
+ aBitmapColor.SetBlue(pRGB_Horiz[x]);
+ mxBitmap->DrawPixel(Point(x,y), aBitmapColor);
+ }
+ }
+ break;
+ case BLUE:
+ while (y--)
+ {
+ aBitmapColor.SetGreen(pRGB_Vert[y]);
+ x = nWidth;
+ while (x--)
+ {
+ aBitmapColor.SetRed(pRGB_Horiz[x]);
+ mxBitmap->DrawPixel(Point(x,y), aBitmapColor);
+ }
+ }
+ break;
+ }
+}
+
+void ColorFieldControl::ShowPosition( const Point& rPos, bool bUpdate )
+{
+ if (!mxBitmap)
+ {
+ UpdateBitmap();
+ Invalidate();
+ }
+
+ if (!mxBitmap)
+ return;
+
+ const Size aSize(mxBitmap->GetOutputSizePixel());
+
+ long nX = rPos.X();
+ long nY = rPos.Y();
+ if (nX < 0)
+ nX = 0;
+ else if (nX >= aSize.Width())
+ nX = aSize.Width() - 1;
+
+ if (nY < 0)
+ nY = 0;
+ else if (nY >= aSize.Height())
+ nY = aSize.Height() - 1;
+
+ Point aPos = maPosition;
+ maPosition.setX( nX - 5 );
+ maPosition.setY( nY - 5 );
+ Invalidate(tools::Rectangle(aPos, Size(11, 11)));
+ Invalidate(tools::Rectangle(maPosition, Size(11, 11)));
+
+ if (bUpdate)
+ {
+ mdX = double(nX) / double(aSize.Width() - 1.0);
+ mdY = double(aSize.Height() - 1.0 - nY) / double(aSize.Height() - 1.0);
+
+ maColor = mxBitmap->GetPixel(Point(nX, nY));
+ }
+}
+
+bool ColorFieldControl::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ CaptureMouse();
+ mbMouseCaptured = true;
+ ShowPosition(rMEvt.GetPosPixel(), true);
+ Modify();
+ return true;
+}
+
+bool ColorFieldControl::MouseMove(const MouseEvent& rMEvt)
+{
+ if (mbMouseCaptured)
+ {
+ ShowPosition(rMEvt.GetPosPixel(), true);
+ Modify();
+ }
+ return true;
+}
+
+bool ColorFieldControl::MouseButtonUp(const MouseEvent&)
+{
+ ReleaseMouse();
+ mbMouseCaptured = false;
+ return true;
+}
+
+void ColorFieldControl::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ if (!mxBitmap)
+ UpdateBitmap();
+
+ if (mxBitmap)
+ {
+ Size aSize(GetOutputSizePixel());
+ rRenderContext.DrawOutDev(Point(0, 0), aSize, Point(0, 0), aSize, *mxBitmap);
+ }
+
+ // draw circle around current color
+ if (maColor.IsDark())
+ rRenderContext.SetLineColor( COL_WHITE );
+ else
+ rRenderContext.SetLineColor( COL_BLACK );
+
+ rRenderContext.SetFillColor();
+
+ rRenderContext.DrawEllipse(::tools::Rectangle(maPosition, Size(11, 11)));
+}
+
+void ColorFieldControl::Resize()
+{
+ CustomWidgetController::Resize();
+ UpdateBitmap();
+ UpdatePosition();
+}
+
+void ColorFieldControl::Modify()
+{
+ maModifyHdl.Call( *this );
+}
+
+void ColorFieldControl::SetValues( Color aColor, ColorMode eMode, double x, double y )
+{
+ bool bUpdateBitmap = (maColor!= aColor) || (meMode != eMode);
+ if( !(bUpdateBitmap || (mdX != x) || (mdY != y)) )
+ return;
+
+ maColor = aColor;
+ meMode = eMode;
+ mdX = x;
+ mdY = y;
+
+ if (bUpdateBitmap)
+ UpdateBitmap();
+ UpdatePosition();
+ if (bUpdateBitmap)
+ Invalidate();
+}
+
+void ColorFieldControl::UpdatePosition()
+{
+ Size aSize(GetOutputSizePixel());
+ ShowPosition(Point(static_cast<long>(mdX * aSize.Width()), static_cast<long>((1.0 - mdY) * aSize.Height())), false);
+}
+
+namespace {
+
+class ColorSliderControl : public weld::CustomWidgetController
+{
+public:
+ ColorSliderControl();
+ virtual ~ColorSliderControl() override;
+
+ virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override;
+
+ virtual bool MouseButtonDown(const MouseEvent& rMEvt) override;
+ virtual bool MouseMove(const MouseEvent& rMEvt) override;
+ virtual bool MouseButtonUp(const MouseEvent& rMEvt) override;
+ virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) override;
+ virtual void Resize() override;
+
+ void UpdateBitmap();
+ void ChangePosition( long nY );
+ void Modify();
+
+ void SetValue( const Color& rColor, ColorMode eMode, double dValue );
+ double GetValue() const { return mdValue; }
+
+ void SetModifyHdl( const Link<ColorSliderControl&,void>& rLink ) { maModifyHdl = rLink; }
+
+ sal_Int16 GetLevel() const { return mnLevel; }
+
+private:
+ Link<ColorSliderControl&,void> maModifyHdl;
+ Color maColor;
+ ColorMode meMode;
+ VclPtr<VirtualDevice> mxBitmap;
+ sal_Int16 mnLevel;
+ double mdValue;
+};
+
+}
+
+ColorSliderControl::ColorSliderControl()
+ : meMode( DefaultMode )
+ , mnLevel( 0 )
+ , mdValue( -1.0 )
+{
+}
+
+void ColorSliderControl::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ CustomWidgetController::SetDrawingArea(pDrawingArea);
+ pDrawingArea->set_size_request(pDrawingArea->get_approximate_digit_width() * 3, -1);
+}
+
+ColorSliderControl::~ColorSliderControl()
+{
+ mxBitmap.disposeAndClear();
+}
+
+void ColorSliderControl::UpdateBitmap()
+{
+ Size aSize(1, GetOutputSizePixel().Height());
+
+ if (mxBitmap && mxBitmap->GetOutputSizePixel() != aSize)
+ mxBitmap.disposeAndClear();
+
+ if (!mxBitmap)
+ {
+ mxBitmap = VclPtr<VirtualDevice>::Create();
+ mxBitmap->SetOutputSizePixel(aSize);
+ }
+
+ const long nY = aSize.Height() - 1;
+
+ Color aBitmapColor(maColor);
+
+ sal_uInt16 nHue, nSat, nBri;
+ maColor.RGBtoHSB(nHue, nSat, nBri);
+
+ // this has been unlooped for performance reason, please do not merge back!
+
+ switch (meMode)
+ {
+ case HUE:
+ nSat = 100;
+ nBri = 100;
+ for (long y = 0; y <= nY; y++)
+ {
+ nHue = static_cast<sal_uInt16>((359 * y) / nY);
+ mxBitmap->DrawPixel(Point(0, nY - y), Color::HSBtoRGB(nHue, nSat, nBri));
+ }
+ break;
+
+ case SATURATION:
+ nBri = std::max(sal_uInt16(32), nBri);
+ for (long y = 0; y <= nY; y++)
+ {
+ nSat = static_cast<sal_uInt16>((100 * y) / nY);
+ mxBitmap->DrawPixel(Point(0, nY - y), Color::HSBtoRGB(nHue, nSat, nBri));
+ }
+ break;
+
+ case BRIGHTNESS:
+ for (long y = 0; y <= nY; y++)
+ {
+ nBri = static_cast<sal_uInt16>((100 * y) / nY);
+ mxBitmap->DrawPixel(Point(0, nY - y), Color::HSBtoRGB(nHue, nSat, nBri));
+ }
+ break;
+
+ case RED:
+ for (long y = 0; y <= nY; y++)
+ {
+ aBitmapColor.SetRed(sal_uInt8((long(255) * y) / nY));
+ mxBitmap->DrawPixel(Point(0, nY - y), aBitmapColor);
+ }
+ break;
+
+ case GREEN:
+ for (long y = 0; y <= nY; y++)
+ {
+ aBitmapColor.SetGreen(sal_uInt8((long(255) * y) / nY));
+ mxBitmap->DrawPixel(Point(0, nY - y), aBitmapColor);
+ }
+ break;
+
+ case BLUE:
+ for (long y = 0; y <= nY; y++)
+ {
+ aBitmapColor.SetBlue(sal_uInt8((long(255) * y) / nY));
+ mxBitmap->DrawPixel(Point(0, nY - y), aBitmapColor);
+ }
+ break;
+ }
+}
+
+void ColorSliderControl::ChangePosition(long nY)
+{
+ const long nHeight = GetOutputSizePixel().Height() - 1;
+
+ if (nY < 0)
+ nY = 0;
+ else if (nY > nHeight)
+ nY = nHeight;
+
+ mnLevel = nY;
+ mdValue = double(nHeight - nY) / double(nHeight);
+}
+
+bool ColorSliderControl::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ CaptureMouse();
+ ChangePosition(rMEvt.GetPosPixel().Y());
+ Modify();
+ return true;
+}
+
+bool ColorSliderControl::MouseMove(const MouseEvent& rMEvt)
+{
+ if (IsMouseCaptured())
+ {
+ ChangePosition(rMEvt.GetPosPixel().Y());
+ Modify();
+ }
+ return true;
+}
+
+bool ColorSliderControl::MouseButtonUp(const MouseEvent&)
+{
+ ReleaseMouse();
+ return true;
+}
+
+void ColorSliderControl::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ if (!mxBitmap)
+ UpdateBitmap();
+
+ const Size aSize(GetOutputSizePixel());
+
+ Point aPos;
+ int x = aSize.Width();
+ while (x--)
+ {
+ rRenderContext.DrawOutDev(aPos, aSize, Point(0,0), aSize, *mxBitmap);
+ aPos.AdjustX(1);
+ }
+}
+
+void ColorSliderControl::Resize()
+{
+ CustomWidgetController::Resize();
+ UpdateBitmap();
+}
+
+void ColorSliderControl::Modify()
+{
+ maModifyHdl.Call(*this);
+}
+
+void ColorSliderControl::SetValue(const Color& rColor, ColorMode eMode, double dValue)
+{
+ bool bUpdateBitmap = (rColor != maColor) || (eMode != meMode);
+ if( bUpdateBitmap || (mdValue != dValue))
+ {
+ maColor = rColor;
+ mdValue = dValue;
+ mnLevel = static_cast<sal_Int16>((1.0-dValue) * GetOutputSizePixel().Height());
+ meMode = eMode;
+ if (bUpdateBitmap)
+ UpdateBitmap();
+ Invalidate();
+ }
+}
+
+namespace {
+
+class ColorPickerDialog : public weld::GenericDialogController
+{
+private:
+ ColorFieldControl m_aColorField;
+ ColorSliderControl m_aColorSlider;
+ ColorPreviewControl m_aColorPreview;
+ ColorPreviewControl m_aColorPrevious;
+
+ std::unique_ptr<weld::CustomWeld> m_xColorField;
+ std::unique_ptr<weld::CustomWeld> m_xColorSlider;
+ std::unique_ptr<weld::CustomWeld> m_xColorPreview;
+ std::unique_ptr<weld::CustomWeld> m_xColorPrevious;
+
+ std::unique_ptr<weld::Widget> m_xFISliderLeft;
+ std::unique_ptr<weld::Widget> m_xFISliderRight;
+ std::unique_ptr<weld::RadioButton> m_xRBRed;
+ std::unique_ptr<weld::RadioButton> m_xRBGreen;
+ std::unique_ptr<weld::RadioButton> m_xRBBlue;
+ std::unique_ptr<weld::RadioButton> m_xRBHue;
+ std::unique_ptr<weld::RadioButton> m_xRBSaturation;
+ std::unique_ptr<weld::RadioButton> m_xRBBrightness;
+
+ std::unique_ptr<weld::SpinButton> m_xMFRed;
+ std::unique_ptr<weld::SpinButton> m_xMFGreen;
+ std::unique_ptr<weld::SpinButton> m_xMFBlue;
+ std::unique_ptr<weld::HexColorControl> m_xEDHex;
+
+ std::unique_ptr<weld::MetricSpinButton> m_xMFHue;
+ std::unique_ptr<weld::MetricSpinButton> m_xMFSaturation;
+ std::unique_ptr<weld::MetricSpinButton> m_xMFBrightness;
+
+ std::unique_ptr<weld::MetricSpinButton> m_xMFCyan;
+ std::unique_ptr<weld::MetricSpinButton> m_xMFMagenta;
+ std::unique_ptr<weld::MetricSpinButton> m_xMFYellow;
+ std::unique_ptr<weld::MetricSpinButton> m_xMFKey;
+
+public:
+ ColorPickerDialog(weld::Window* pParent, Color nColor, sal_Int16 nMode);
+
+ void update_color(UpdateFlags n = UpdateFlags::All);
+
+ DECL_LINK(ColorFieldControlModifydl, ColorFieldControl&, void);
+ DECL_LINK(ColorSliderControlModifyHdl, ColorSliderControl&, void);
+ DECL_LINK(ColorModifyMetricHdl, weld::MetricSpinButton&, void);
+ DECL_LINK(ColorModifySpinHdl, weld::SpinButton&, void);
+ DECL_LINK(ColorModifyEditHdl, weld::Entry&, void);
+ DECL_LINK(ModeModifyHdl, weld::ToggleButton&, void);
+
+ Color GetColor() const;
+
+ void setColorComponent(ColorComponent nComp, double dValue);
+
+private:
+ ColorMode meMode;
+
+ double mdRed, mdGreen, mdBlue;
+ double mdHue, mdSat, mdBri;
+ double mdCyan, mdMagenta, mdYellow, mdKey;
+};
+
+}
+
+ColorPickerDialog::ColorPickerDialog(weld::Window* pParent, Color nColor, sal_Int16 nDialogMode)
+ : GenericDialogController(pParent, "cui/ui/colorpickerdialog.ui", "ColorPicker")
+ , m_xColorField(new weld::CustomWeld(*m_xBuilder, "colorField", m_aColorField))
+ , m_xColorSlider(new weld::CustomWeld(*m_xBuilder, "colorSlider", m_aColorSlider))
+ , m_xColorPreview(new weld::CustomWeld(*m_xBuilder, "preview", m_aColorPreview))
+ , m_xColorPrevious(new weld::CustomWeld(*m_xBuilder, "previous", m_aColorPrevious))
+ , m_xFISliderLeft(m_xBuilder->weld_widget("leftImage"))
+ , m_xFISliderRight(m_xBuilder->weld_widget("rightImage"))
+ , m_xRBRed(m_xBuilder->weld_radio_button("redRadiobutton"))
+ , m_xRBGreen(m_xBuilder->weld_radio_button("greenRadiobutton"))
+ , m_xRBBlue(m_xBuilder->weld_radio_button("blueRadiobutton"))
+ , m_xRBHue(m_xBuilder->weld_radio_button("hueRadiobutton"))
+ , m_xRBSaturation(m_xBuilder->weld_radio_button("satRadiobutton"))
+ , m_xRBBrightness(m_xBuilder->weld_radio_button("brightRadiobutton"))
+ , m_xMFRed(m_xBuilder->weld_spin_button("redSpinbutton"))
+ , m_xMFGreen(m_xBuilder->weld_spin_button("greenSpinbutton"))
+ , m_xMFBlue(m_xBuilder->weld_spin_button("blueSpinbutton"))
+ , m_xEDHex(new weld::HexColorControl(m_xBuilder->weld_entry("hexEntry")))
+ , m_xMFHue(m_xBuilder->weld_metric_spin_button("hueSpinbutton", FieldUnit::DEGREE))
+ , m_xMFSaturation(m_xBuilder->weld_metric_spin_button("satSpinbutton", FieldUnit::PERCENT))
+ , m_xMFBrightness(m_xBuilder->weld_metric_spin_button("brightSpinbutton", FieldUnit::PERCENT))
+ , m_xMFCyan(m_xBuilder->weld_metric_spin_button("cyanSpinbutton", FieldUnit::PERCENT))
+ , m_xMFMagenta(m_xBuilder->weld_metric_spin_button("magSpinbutton", FieldUnit::PERCENT))
+ , m_xMFYellow(m_xBuilder->weld_metric_spin_button("yellowSpinbutton", FieldUnit::PERCENT))
+ , m_xMFKey(m_xBuilder->weld_metric_spin_button("keySpinbutton", FieldUnit::PERCENT))
+ , meMode( DefaultMode )
+{
+ m_aColorField.SetModifyHdl( LINK( this, ColorPickerDialog, ColorFieldControlModifydl ) );
+ m_aColorSlider.SetModifyHdl( LINK( this, ColorPickerDialog, ColorSliderControlModifyHdl ) );
+
+ int nMargin = (m_xFISliderLeft->get_preferred_size().Height() + 1) / 2;
+ m_xColorSlider->set_margin_top(nMargin);
+ m_xColorSlider->set_margin_bottom(nMargin);
+
+ Link<weld::MetricSpinButton&,void> aLink3( LINK( this, ColorPickerDialog, ColorModifyMetricHdl ) );
+ m_xMFCyan->connect_value_changed( aLink3 );
+ m_xMFMagenta->connect_value_changed( aLink3 );
+ m_xMFYellow->connect_value_changed( aLink3 );
+ m_xMFKey->connect_value_changed( aLink3 );
+
+ m_xMFHue->connect_value_changed( aLink3 );
+ m_xMFSaturation->connect_value_changed( aLink3 );
+ m_xMFBrightness->connect_value_changed( aLink3 );
+
+ Link<weld::SpinButton&,void> aLink4(LINK(this, ColorPickerDialog, ColorModifySpinHdl));
+ m_xMFRed->connect_value_changed(aLink4);
+ m_xMFGreen->connect_value_changed(aLink4);
+ m_xMFBlue->connect_value_changed(aLink4);
+
+ m_xEDHex->connect_changed(LINK(this, ColorPickerDialog, ColorModifyEditHdl));
+
+ Link<weld::ToggleButton&,void> aLink2 = LINK( this, ColorPickerDialog, ModeModifyHdl );
+ m_xRBRed->connect_toggled( aLink2 );
+ m_xRBGreen->connect_toggled( aLink2 );
+ m_xRBBlue->connect_toggled( aLink2 );
+ m_xRBHue->connect_toggled( aLink2 );
+ m_xRBSaturation->connect_toggled( aLink2 );
+ m_xRBBrightness->connect_toggled( aLink2 );
+
+ Color aColor(nColor);
+
+ // modify
+ if (nDialogMode == 2)
+ {
+ m_aColorPrevious.SetColor(aColor);
+ m_xColorPrevious->show();
+ }
+
+ mdRed = static_cast<double>(aColor.GetRed()) / 255.0;
+ mdGreen = static_cast<double>(aColor.GetGreen()) / 255.0;
+ mdBlue = static_cast<double>(aColor.GetBlue()) / 255.0;
+
+ RGBtoHSV( mdRed, mdGreen, mdBlue, mdHue, mdSat, mdBri );
+ RGBtoCMYK( mdRed, mdGreen, mdBlue, mdCyan, mdMagenta, mdYellow, mdKey );
+
+ update_color();
+}
+
+static int toInt( double dValue, double dRange )
+{
+ return static_cast< int >( std::floor((dValue * dRange) + 0.5 ) );
+}
+
+Color ColorPickerDialog::GetColor() const
+{
+ return Color( toInt(mdRed,255.0), toInt(mdGreen,255.0), toInt(mdBlue,255.0) );
+}
+
+void ColorPickerDialog::update_color( UpdateFlags n )
+{
+ sal_uInt8 nRed = toInt(mdRed,255.0);
+ sal_uInt8 nGreen = toInt(mdGreen,255.0);
+ sal_uInt8 nBlue = toInt(mdBlue,255.0);
+
+ Color aColor(nRed, nGreen, nBlue);
+
+ if (n & UpdateFlags::RGB) // update RGB
+ {
+ m_xMFRed->set_value(nRed);
+ m_xMFGreen->set_value(nGreen);
+ m_xMFBlue->set_value(nBlue);
+ }
+
+ if (n & UpdateFlags::CMYK) // update CMYK
+ {
+ m_xMFCyan->set_value(toInt(mdCyan, 100.0), FieldUnit::PERCENT);
+ m_xMFMagenta->set_value(toInt(mdMagenta, 100.0), FieldUnit::PERCENT);
+ m_xMFYellow->set_value(toInt(mdYellow, 100.0), FieldUnit::PERCENT);
+ m_xMFKey->set_value(toInt(mdKey, 100.0), FieldUnit::PERCENT);
+ }
+
+ if (n & UpdateFlags::HSB ) // update HSB
+ {
+ m_xMFHue->set_value(toInt(mdHue, 1.0), FieldUnit::DEGREE);
+ m_xMFSaturation->set_value(toInt( mdSat, 100.0), FieldUnit::PERCENT);
+ m_xMFBrightness->set_value(toInt( mdBri, 100.0), FieldUnit::PERCENT);
+ }
+
+ if (n & UpdateFlags::ColorChooser ) // update Color Chooser 1
+ {
+ switch( meMode )
+ {
+ case HUE:
+ m_aColorField.SetValues(aColor, meMode, mdSat, mdBri);
+ break;
+ case SATURATION:
+ m_aColorField.SetValues(aColor, meMode, mdHue / 360.0, mdBri);
+ break;
+ case BRIGHTNESS:
+ m_aColorField.SetValues(aColor, meMode, mdHue / 360.0, mdSat);
+ break;
+ case RED:
+ m_aColorField.SetValues(aColor, meMode, mdBlue, mdGreen);
+ break;
+ case GREEN:
+ m_aColorField.SetValues(aColor, meMode, mdBlue, mdRed);
+ break;
+ case BLUE:
+ m_aColorField.SetValues(aColor, meMode, mdRed, mdGreen);
+ break;
+ }
+ }
+
+ if (n & UpdateFlags::ColorSlider) // update Color Chooser 2
+ {
+ switch (meMode)
+ {
+ case HUE:
+ m_aColorSlider.SetValue(aColor, meMode, mdHue / 360.0);
+ break;
+ case SATURATION:
+ m_aColorSlider.SetValue(aColor, meMode, mdSat);
+ break;
+ case BRIGHTNESS:
+ m_aColorSlider.SetValue(aColor, meMode, mdBri);
+ break;
+ case RED:
+ m_aColorSlider.SetValue(aColor, meMode, mdRed);
+ break;
+ case GREEN:
+ m_aColorSlider.SetValue(aColor, meMode, mdGreen);
+ break;
+ case BLUE:
+ m_aColorSlider.SetValue(aColor, meMode, mdBlue);
+ break;
+ }
+ }
+
+ if (n & UpdateFlags::Hex) // update hex
+ {
+ m_xFISliderLeft->set_margin_top(m_aColorSlider.GetLevel());
+ m_xFISliderRight->set_margin_top(m_aColorSlider.GetLevel());
+ m_xEDHex->SetColor(aColor);
+ }
+ m_aColorPreview.SetColor(aColor);
+}
+
+IMPL_LINK_NOARG(ColorPickerDialog, ColorFieldControlModifydl, ColorFieldControl&, void)
+{
+ double x = m_aColorField.GetX();
+ double y = m_aColorField.GetY();
+
+ switch( meMode )
+ {
+ case HUE:
+ mdSat = x;
+ setColorComponent( ColorComponent::Brightness, y );
+ break;
+ case SATURATION:
+ mdHue = x * 360.0;
+ setColorComponent( ColorComponent::Brightness, y );
+ break;
+ case BRIGHTNESS:
+ mdHue = x * 360.0;
+ setColorComponent( ColorComponent::Saturation, y );
+ break;
+ case RED:
+ mdBlue = x;
+ setColorComponent( ColorComponent::Green, y );
+ break;
+ case GREEN:
+ mdBlue = x;
+ setColorComponent( ColorComponent::Red, y );
+ break;
+ case BLUE:
+ mdRed = x;
+ setColorComponent( ColorComponent::Green, y );
+ break;
+ }
+
+ update_color(UpdateFlags::All & ~UpdateFlags::ColorChooser);
+}
+
+IMPL_LINK_NOARG(ColorPickerDialog, ColorSliderControlModifyHdl, ColorSliderControl&, void)
+{
+ double dValue = m_aColorSlider.GetValue();
+ switch (meMode)
+ {
+ case HUE:
+ setColorComponent( ColorComponent::Hue, dValue * 360.0 );
+ break;
+ case SATURATION:
+ setColorComponent( ColorComponent::Saturation, dValue );
+ break;
+ case BRIGHTNESS:
+ setColorComponent( ColorComponent::Brightness, dValue );
+ break;
+ case RED:
+ setColorComponent( ColorComponent::Red, dValue );
+ break;
+ case GREEN:
+ setColorComponent( ColorComponent::Green, dValue );
+ break;
+ case BLUE:
+ setColorComponent( ColorComponent::Blue, dValue );
+ break;
+ }
+
+ update_color(UpdateFlags::All & ~UpdateFlags::ColorSlider);
+}
+
+IMPL_LINK(ColorPickerDialog, ColorModifyMetricHdl, weld::MetricSpinButton&, rEdit, void)
+{
+ UpdateFlags n = UpdateFlags::NONE;
+
+ if (&rEdit == m_xMFHue.get())
+ {
+ setColorComponent( ColorComponent::Hue, static_cast<double>(m_xMFHue->get_value(FieldUnit::DEGREE)) );
+ n = UpdateFlags::All & ~UpdateFlags::HSB;
+ }
+ else if (&rEdit == m_xMFSaturation.get())
+ {
+ setColorComponent( ColorComponent::Saturation, static_cast<double>(m_xMFSaturation->get_value(FieldUnit::PERCENT)) / 100.0 );
+ n = UpdateFlags::All & ~UpdateFlags::HSB;
+ }
+ else if (&rEdit == m_xMFBrightness.get())
+ {
+ setColorComponent( ColorComponent::Brightness, static_cast<double>(m_xMFBrightness->get_value(FieldUnit::PERCENT)) / 100.0 );
+ n = UpdateFlags::All & ~UpdateFlags::HSB;
+ }
+ else if (&rEdit == m_xMFCyan.get())
+ {
+ setColorComponent( ColorComponent::Cyan, static_cast<double>(m_xMFCyan->get_value(FieldUnit::PERCENT)) / 100.0 );
+ n = UpdateFlags::All & ~UpdateFlags::CMYK;
+ }
+ else if (&rEdit == m_xMFMagenta.get())
+ {
+ setColorComponent( ColorComponent::Magenta, static_cast<double>(m_xMFMagenta->get_value(FieldUnit::PERCENT)) / 100.0 );
+ n = UpdateFlags::All & ~UpdateFlags::CMYK;
+ }
+ else if (&rEdit == m_xMFYellow.get())
+ {
+ setColorComponent( ColorComponent::Yellow, static_cast<double>(m_xMFYellow->get_value(FieldUnit::PERCENT)) / 100.0 );
+ n = UpdateFlags::All & ~UpdateFlags::CMYK;
+ }
+ else if (&rEdit == m_xMFKey.get())
+ {
+ setColorComponent( ColorComponent::Key, static_cast<double>(m_xMFKey->get_value(FieldUnit::PERCENT)) / 100.0 );
+ n = UpdateFlags::All & ~UpdateFlags::CMYK;
+ }
+
+ if (n != UpdateFlags::NONE)
+ update_color(n);
+}
+
+IMPL_LINK_NOARG(ColorPickerDialog, ColorModifyEditHdl, weld::Entry&, void)
+{
+ UpdateFlags n = UpdateFlags::NONE;
+
+ Color aColor = m_xEDHex->GetColor();
+
+ if (aColor != Color(0xffffffff) && aColor != GetColor())
+ {
+ mdRed = static_cast<double>(aColor.GetRed()) / 255.0;
+ mdGreen = static_cast<double>(aColor.GetGreen()) / 255.0;
+ mdBlue = static_cast<double>(aColor.GetBlue()) / 255.0;
+
+ RGBtoHSV( mdRed, mdGreen, mdBlue, mdHue, mdSat, mdBri );
+ RGBtoCMYK( mdRed, mdGreen, mdBlue, mdCyan, mdMagenta, mdYellow, mdKey );
+ n = UpdateFlags::All & ~UpdateFlags::Hex;
+ }
+
+ if (n != UpdateFlags::NONE)
+ update_color(n);
+}
+
+IMPL_LINK(ColorPickerDialog, ColorModifySpinHdl, weld::SpinButton&, rEdit, void)
+{
+ UpdateFlags n = UpdateFlags::NONE;
+
+ if (&rEdit == m_xMFRed.get())
+ {
+ setColorComponent( ColorComponent::Red, static_cast<double>(m_xMFRed->get_value()) / 255.0 );
+ n = UpdateFlags::All & ~UpdateFlags::RGB;
+ }
+ else if (&rEdit == m_xMFGreen.get())
+ {
+ setColorComponent( ColorComponent::Green, static_cast<double>(m_xMFGreen->get_value()) / 255.0 );
+ n = UpdateFlags::All & ~UpdateFlags::RGB;
+ }
+ else if (&rEdit == m_xMFBlue.get())
+ {
+ setColorComponent( ColorComponent::Blue, static_cast<double>(m_xMFBlue->get_value()) / 255.0 );
+ n = UpdateFlags::All & ~UpdateFlags::RGB;
+ }
+
+ if (n != UpdateFlags::NONE)
+ update_color(n);
+}
+
+
+IMPL_LINK_NOARG(ColorPickerDialog, ModeModifyHdl, weld::ToggleButton&, void)
+{
+ ColorMode eMode = HUE;
+
+ if (m_xRBRed->get_active())
+ {
+ eMode = RED;
+ }
+ else if (m_xRBGreen->get_active())
+ {
+ eMode = GREEN;
+ }
+ else if (m_xRBBlue->get_active())
+ {
+ eMode = BLUE;
+ }
+ else if (m_xRBSaturation->get_active())
+ {
+ eMode = SATURATION;
+ }
+ else if (m_xRBBrightness->get_active())
+ {
+ eMode = BRIGHTNESS;
+ }
+
+ if (meMode != eMode)
+ {
+ meMode = eMode;
+ update_color(UpdateFlags::ColorChooser | UpdateFlags::ColorSlider);
+ }
+}
+
+void ColorPickerDialog::setColorComponent( ColorComponent nComp, double dValue )
+{
+ switch( nComp )
+ {
+ case ColorComponent::Red:
+ mdRed = dValue;
+ break;
+ case ColorComponent::Green:
+ mdGreen = dValue;
+ break;
+ case ColorComponent::Blue:
+ mdBlue = dValue;
+ break;
+ case ColorComponent::Hue:
+ mdHue = dValue;
+ break;
+ case ColorComponent::Saturation:
+ mdSat = dValue;
+ break;
+ case ColorComponent::Brightness:
+ mdBri = dValue;
+ break;
+ case ColorComponent::Cyan:
+ mdCyan = dValue;
+ break;
+ case ColorComponent::Yellow:
+ mdYellow = dValue;
+ break;
+ case ColorComponent::Magenta:
+ mdMagenta = dValue;
+ break;
+ case ColorComponent::Key:
+ mdKey = dValue;
+ break;
+ }
+
+ if (nComp == ColorComponent::Red || nComp == ColorComponent::Green || nComp == ColorComponent::Blue)
+ {
+ RGBtoHSV( mdRed, mdGreen, mdBlue, mdHue, mdSat, mdBri );
+ RGBtoCMYK( mdRed, mdGreen, mdBlue, mdCyan, mdMagenta, mdYellow, mdKey );
+ }
+ else if (nComp == ColorComponent::Hue || nComp == ColorComponent::Saturation || nComp == ColorComponent::Brightness)
+ {
+ HSVtoRGB( mdHue, mdSat, mdBri, mdRed, mdGreen, mdBlue );
+ RGBtoCMYK( mdRed, mdGreen, mdBlue, mdCyan, mdMagenta, mdYellow, mdKey );
+ }
+ else
+ {
+ CMYKtoRGB( mdCyan, mdMagenta, mdYellow, mdKey, mdRed, mdGreen, mdBlue );
+ RGBtoHSV( mdRed, mdGreen, mdBlue, mdHue, mdSat, mdBri );
+ }
+}
+
+typedef ::cppu::WeakComponentImplHelper< XServiceInfo, XExecutableDialog, XInitialization, XPropertyAccess > ColorPickerBase;
+
+namespace {
+
+class ColorPicker : protected ::cppu::BaseMutex, // Struct for right initialization of mutex member! Must be first of baseclasses.
+ public ColorPickerBase
+{
+public:
+ explicit ColorPicker();
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) override;
+
+ // XInitialization
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XPropertyAccess
+ virtual Sequence< PropertyValue > SAL_CALL getPropertyValues( ) override;
+ virtual void SAL_CALL setPropertyValues( const Sequence< PropertyValue >& aProps ) override;
+
+ // XExecutableDialog
+ virtual void SAL_CALL setTitle( const OUString& aTitle ) override;
+ virtual sal_Int16 SAL_CALL execute( ) override;
+
+private:
+ Color mnColor;
+ sal_Int16 mnMode;
+ Reference<css::awt::XWindow> mxParent;
+};
+
+}
+
+OUString ColorPicker_getImplementationName()
+{
+ return "com.sun.star.cui.ColorPicker";
+}
+
+Reference< XInterface > ColorPicker_createInstance( Reference< XComponentContext > const & )
+{
+ return static_cast<XWeak*>( new ColorPicker );
+}
+
+Sequence< OUString > ColorPicker_getSupportedServiceNames()
+{
+ Sequence< OUString > seq { "com.sun.star.ui.dialogs.ColorPicker" };
+ return seq;
+}
+
+static const OUStringLiteral gsColorKey( "Color" );
+static const OUStringLiteral gsModeKey( "Mode" );
+
+ColorPicker::ColorPicker()
+ : ColorPickerBase( m_aMutex )
+ , mnColor( 0 )
+ , mnMode( 0 )
+{
+}
+
+// XInitialization
+void SAL_CALL ColorPicker::initialize( const Sequence< Any >& aArguments )
+{
+ if( aArguments.getLength() == 1 )
+ {
+ aArguments[0] >>= mxParent;
+ }
+}
+
+// XInitialization
+OUString SAL_CALL ColorPicker::getImplementationName( )
+{
+ return ColorPicker_getImplementationName();
+}
+
+sal_Bool SAL_CALL ColorPicker::supportsService( const OUString& sServiceName )
+{
+ return cppu::supportsService(this, sServiceName);
+}
+
+Sequence< OUString > SAL_CALL ColorPicker::getSupportedServiceNames( )
+{
+ return ColorPicker_getSupportedServiceNames();
+}
+
+// XPropertyAccess
+Sequence< PropertyValue > SAL_CALL ColorPicker::getPropertyValues( )
+{
+ Sequence< PropertyValue > props(1);
+ props[0].Name = gsColorKey;
+ props[0].Value <<= mnColor;
+ return props;
+}
+
+void SAL_CALL ColorPicker::setPropertyValues( const Sequence< PropertyValue >& aProps )
+{
+ for ( const PropertyValue& rProp : aProps )
+ {
+ if( rProp.Name == gsColorKey )
+ {
+ rProp.Value >>= mnColor;
+ }
+ else if( rProp.Name == gsModeKey )
+ {
+ rProp.Value >>= mnMode;
+ }
+ }
+}
+
+// XExecutableDialog
+void SAL_CALL ColorPicker::setTitle( const OUString& )
+{
+}
+
+sal_Int16 SAL_CALL ColorPicker::execute()
+{
+ std::unique_ptr<ColorPickerDialog> xDlg(new ColorPickerDialog(Application::GetFrameWeld(mxParent), mnColor, mnMode));
+ sal_Int16 ret = xDlg->run();
+ if (ret)
+ mnColor = xDlg->GetColor();
+ return ret;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/dialogs/cuicharmap.cxx b/cui/source/dialogs/cuicharmap.cxx
new file mode 100644
index 000000000..bcc1dd16a
--- /dev/null
+++ b/cui/source/dialogs/cuicharmap.cxx
@@ -0,0 +1,1250 @@
+/* -*- 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 <stdio.h>
+
+#include <vcl/svapp.hxx>
+#include <svl/eitem.hxx>
+#include <svl/intitem.hxx>
+#include <svl/itempool.hxx>
+
+#include <rtl/textenc.h>
+#include <svx/ucsubset.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/fontcharmap.hxx>
+#include <vcl/virdev.hxx>
+#include <svl/stritem.hxx>
+#include <officecfg/Office/Common.hxx>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/dispatchcommand.hxx>
+
+#include <dialmgr.hxx>
+#include <cui/cuicharmap.hxx>
+#include <sfx2/app.hxx>
+#include <svx/svxids.hrc>
+#include <editeng/editids.hrc>
+#include <editeng/fontitem.hxx>
+#include <strings.hrc>
+#include <unicode/uchar.h>
+#include <unicode/utypes.h>
+
+using namespace css;
+
+SvxCharacterMap::SvxCharacterMap(weld::Widget* pParent, const SfxItemSet* pSet,
+ const css::uno::Reference<css::frame::XFrame>& rFrame)
+ : SfxDialogController(pParent, "cui/ui/specialcharacters.ui", "SpecialCharactersDialog")
+ , m_xVirDev(VclPtr<VirtualDevice>::Create())
+ , isSearchMode(true)
+ , m_xFrame(rFrame)
+ , mxContext(comphelper::getProcessComponentContext())
+ , m_aRecentCharView{SvxCharView(m_xVirDev),
+ SvxCharView(m_xVirDev),
+ SvxCharView(m_xVirDev),
+ SvxCharView(m_xVirDev),
+ SvxCharView(m_xVirDev),
+ SvxCharView(m_xVirDev),
+ SvxCharView(m_xVirDev),
+ SvxCharView(m_xVirDev),
+ SvxCharView(m_xVirDev),
+ SvxCharView(m_xVirDev),
+ SvxCharView(m_xVirDev),
+ SvxCharView(m_xVirDev),
+ SvxCharView(m_xVirDev),
+ SvxCharView(m_xVirDev),
+ SvxCharView(m_xVirDev),
+ SvxCharView(m_xVirDev)}
+ , m_aFavCharView{SvxCharView(m_xVirDev),
+ SvxCharView(m_xVirDev),
+ SvxCharView(m_xVirDev),
+ SvxCharView(m_xVirDev),
+ SvxCharView(m_xVirDev),
+ SvxCharView(m_xVirDev),
+ SvxCharView(m_xVirDev),
+ SvxCharView(m_xVirDev),
+ SvxCharView(m_xVirDev),
+ SvxCharView(m_xVirDev),
+ SvxCharView(m_xVirDev),
+ SvxCharView(m_xVirDev),
+ SvxCharView(m_xVirDev),
+ SvxCharView(m_xVirDev),
+ SvxCharView(m_xVirDev),
+ SvxCharView(m_xVirDev)}
+ , m_aShowChar(m_xVirDev)
+ , m_xOKBtn(m_xFrame.is() ? m_xBuilder->weld_button("insert") : m_xBuilder->weld_button("ok"))
+ , m_xFontText(m_xBuilder->weld_label("fontft"))
+ , m_xFontLB(m_xBuilder->weld_combo_box("fontlb"))
+ , m_xSubsetText(m_xBuilder->weld_label("subsetft"))
+ , m_xSubsetLB(m_xBuilder->weld_combo_box("subsetlb"))
+ , m_xSearchText(m_xBuilder->weld_entry("search"))
+ , m_xHexCodeText(m_xBuilder->weld_entry("hexvalue"))
+ , m_xDecimalCodeText(m_xBuilder->weld_entry("decimalvalue"))
+ , m_xFavouritesBtn(m_xBuilder->weld_button("favbtn"))
+ , m_xCharName(m_xBuilder->weld_label("charname"))
+ , m_xRecentGrid(m_xBuilder->weld_widget("viewgrid"))
+ , m_xFavGrid(m_xBuilder->weld_widget("favgrid"))
+ , m_xShowChar(new weld::CustomWeld(*m_xBuilder, "showchar", m_aShowChar))
+ , m_xRecentCharView{std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar1", m_aRecentCharView[0]),
+ std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar2", m_aRecentCharView[1]),
+ std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar3", m_aRecentCharView[2]),
+ std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar4", m_aRecentCharView[3]),
+ std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar5", m_aRecentCharView[4]),
+ std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar6", m_aRecentCharView[5]),
+ std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar7", m_aRecentCharView[6]),
+ std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar8", m_aRecentCharView[7]),
+ std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar9", m_aRecentCharView[8]),
+ std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar10", m_aRecentCharView[9]),
+ std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar11", m_aRecentCharView[10]),
+ std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar12", m_aRecentCharView[11]),
+ std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar13", m_aRecentCharView[12]),
+ std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar14", m_aRecentCharView[13]),
+ std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar15", m_aRecentCharView[14]),
+ std::make_unique<weld::CustomWeld>(*m_xBuilder, "viewchar16", m_aRecentCharView[15])}
+ , m_xFavCharView{std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar1", m_aFavCharView[0]),
+ std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar2", m_aFavCharView[1]),
+ std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar3", m_aFavCharView[2]),
+ std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar4", m_aFavCharView[3]),
+ std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar5", m_aFavCharView[4]),
+ std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar6", m_aFavCharView[5]),
+ std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar7", m_aFavCharView[6]),
+ std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar8", m_aFavCharView[7]),
+ std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar9", m_aFavCharView[8]),
+ std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar10", m_aFavCharView[9]),
+ std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar11", m_aFavCharView[10]),
+ std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar12", m_aFavCharView[11]),
+ std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar13", m_aFavCharView[12]),
+ std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar14", m_aFavCharView[13]),
+ std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar15", m_aFavCharView[14]),
+ std::make_unique<weld::CustomWeld>(*m_xBuilder, "favchar16", m_aFavCharView[15])}
+ , m_xShowSet(new SvxShowCharSet(m_xBuilder->weld_scrolled_window("showscroll"), m_xVirDev))
+ , m_xShowSetArea(new weld::CustomWeld(*m_xBuilder, "showcharset", *m_xShowSet))
+ , m_xSearchSet(new SvxSearchCharSet(m_xBuilder->weld_scrolled_window("searchscroll"), m_xVirDev))
+ , m_xSearchSetArea(new weld::CustomWeld(*m_xBuilder, "searchcharset", *m_xSearchSet))
+{
+ m_aShowChar.SetCentered(true);
+ m_xFontLB->make_sorted();
+ //lock the size request of this widget to the width of all possible entries
+ fillAllSubsets(*m_xSubsetLB);
+ m_xSubsetLB->set_size_request(m_xSubsetLB->get_preferred_size().Width(), -1);
+ m_xCharName->set_size_request(m_aShowChar.get_preferred_size().Width(), m_xCharName->get_text_height() * 4);
+ //lock the size request of this widget to the width of the original .ui string
+ m_xHexCodeText->set_size_request(m_xHexCodeText->get_preferred_size().Width(), -1);
+ //so things don't jump around if all the children are hidden
+ m_xRecentGrid->set_size_request(-1, m_aRecentCharView[0].get_preferred_size().Height());
+ m_xFavGrid->set_size_request(-1, m_aFavCharView[0].get_preferred_size().Height());
+
+ init();
+
+ const SfxInt32Item* pCharItem = SfxItemSet::GetItem<SfxInt32Item>(pSet, SID_ATTR_CHAR, false);
+ if ( pCharItem )
+ SetChar( pCharItem->GetValue() );
+
+ const SfxBoolItem* pDisableItem = SfxItemSet::GetItem<SfxBoolItem>(pSet, FN_PARAM_2, false);
+ if ( pDisableItem && pDisableItem->GetValue() )
+ DisableFontSelection();
+
+ const SvxFontItem* pFontItem = SfxItemSet::GetItem<SvxFontItem>(pSet, SID_ATTR_CHAR_FONT, false);
+ const SfxStringItem* pFontNameItem = SfxItemSet::GetItem<SfxStringItem>(pSet, SID_FONT_NAME, false);
+ if ( pFontItem )
+ {
+ vcl::Font aTmpFont( pFontItem->GetFamilyName(), pFontItem->GetStyleName(), GetCharFont().GetFontSize() );
+ aTmpFont.SetCharSet( pFontItem->GetCharSet() );
+ aTmpFont.SetPitch( pFontItem->GetPitch() );
+ SetCharFont( aTmpFont );
+ }
+ else if ( pFontNameItem )
+ {
+ vcl::Font aTmpFont( GetCharFont() );
+ aTmpFont.SetFamilyName( pFontNameItem->GetValue() );
+ SetCharFont( aTmpFont );
+ }
+
+ m_xOutputSet.reset(new SfxAllItemSet(pSet ? *pSet->GetPool() : SfxGetpApp()->GetPool()));
+ m_xShowSet->Show();
+ m_xSearchSet->Hide();
+}
+
+short SvxCharacterMap::run()
+{
+ if( SvxShowCharSet::getSelectedChar() == ' ')
+ {
+ m_xOKBtn->set_sensitive(false);
+ setFavButtonState(OUString(), OUString());
+ }
+ else
+ {
+ sal_UCS4 cChar = m_xShowSet->GetSelectCharacter();
+ // using the new UCS4 constructor
+ OUString aOUStr( &cChar, 1 );
+ m_aShowChar.SetText(aOUStr);
+
+ setFavButtonState(aOUStr, m_aShowChar.GetFont().GetFamilyName());
+ m_xOKBtn->set_sensitive(true);
+ }
+
+ return SfxDialogController::run();
+}
+
+void SvxCharacterMap::SetChar( sal_UCS4 c )
+{
+ m_xShowSet->SelectCharacter( c );
+ setFavButtonState(OUString(&c, 1), aFont.GetFamilyName());
+}
+
+sal_UCS4 SvxCharacterMap::GetChar() const
+{
+ return m_aShowChar.GetText().toChar();
+}
+
+void SvxCharacterMap::DisableFontSelection()
+{
+ m_xFontText->set_sensitive(false);
+ m_xFontLB->set_sensitive(false);
+}
+
+
+void SvxCharacterMap::getRecentCharacterList()
+{
+ //retrieve recent character list
+ const css::uno::Sequence< OUString > rRecentCharList( officecfg::Office::Common::RecentCharacters::RecentCharacterList::get() );
+ for (OUString const & s : rRecentCharList)
+ {
+ maRecentCharList.push_back(s);
+ }
+
+ //retrieve recent character font list
+ const css::uno::Sequence< OUString > rRecentCharFontList( officecfg::Office::Common::RecentCharacters::RecentCharacterFontList::get() );
+ for (OUString const & s : rRecentCharFontList)
+ {
+ maRecentCharFontList.push_back(s);
+ }
+}
+
+
+void SvxCharacterMap::getFavCharacterList()
+{
+ maFavCharList.clear();
+ maFavCharFontList.clear();
+ //retrieve recent character list
+ const css::uno::Sequence< OUString > rFavCharList( officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterList::get() );
+ for (const OUString& s : rFavCharList)
+ {
+ maFavCharList.push_back(s);
+ }
+
+ //retrieve recent character font list
+ const css::uno::Sequence< OUString > rFavCharFontList( officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterFontList::get() );
+ for (const OUString& s : rFavCharFontList)
+ {
+ maFavCharFontList.push_back(s);
+ }
+}
+
+
+void SvxCharacterMap::updateRecentCharControl()
+{
+ int i = 0;
+ for ( std::deque< OUString >::iterator it = maRecentCharList.begin(), it2 = maRecentCharFontList.begin();
+ it != maRecentCharList.end() && it2 != maRecentCharFontList.end();
+ ++it, ++it2, i++)
+ {
+ m_aRecentCharView[i].SetText(*it);
+ vcl::Font rFont = m_aRecentCharView[i].GetFont();
+ rFont.SetFamilyName( *it2 );
+ m_aRecentCharView[i].SetFont(rFont);
+ m_aRecentCharView[i].Show();
+ }
+
+ for(; i < 16 ; i++)
+ {
+ m_aRecentCharView[i].SetText(OUString());
+ m_aRecentCharView[i].Hide();
+ }
+}
+
+void SvxCharacterMap::updateRecentCharacterList(const OUString& sTitle, const OUString& rFont)
+{
+ auto itChar = std::find(maRecentCharList.begin(), maRecentCharList.end(), sTitle);
+
+ auto itChar2 = std::find(maRecentCharFontList.begin(), maRecentCharFontList.end(), rFont);
+
+ // if recent char to be added is already in list, remove it
+ if( itChar != maRecentCharList.end() && itChar2 != maRecentCharFontList.end() )
+ {
+ maRecentCharList.erase( itChar );
+ maRecentCharFontList.erase( itChar2);
+ }
+
+ if (maRecentCharList.size() == 16)
+ {
+ maRecentCharList.pop_back();
+ maRecentCharFontList.pop_back();
+ }
+
+ maRecentCharList.push_front(sTitle);
+ maRecentCharFontList.push_front(rFont);
+
+ css::uno::Sequence< OUString > aRecentCharList(maRecentCharList.size());
+ css::uno::Sequence< OUString > aRecentCharFontList(maRecentCharFontList.size());
+
+ for (size_t i = 0; i < maRecentCharList.size(); ++i)
+ {
+ aRecentCharList[i] = maRecentCharList[i];
+ aRecentCharFontList[i] = maRecentCharFontList[i];
+ }
+
+ std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create(mxContext));
+ officecfg::Office::Common::RecentCharacters::RecentCharacterList::set(aRecentCharList, batch);
+ officecfg::Office::Common::RecentCharacters::RecentCharacterFontList::set(aRecentCharFontList, batch);
+ batch->commit();
+
+ updateRecentCharControl();
+}
+
+
+void SvxCharacterMap::updateFavCharacterList(const OUString& sTitle, const OUString& rFont)
+{
+ auto itChar = std::find(maFavCharList.begin(), maFavCharList.end(), sTitle);
+
+ auto itChar2 = std::find(maFavCharFontList.begin(), maFavCharFontList.end(), rFont);
+
+ // if Fav char to be added is already in list, remove it
+ if( itChar != maFavCharList.end() && itChar2 != maFavCharFontList.end() )
+ {
+ maFavCharList.erase( itChar );
+ maFavCharFontList.erase( itChar2);
+ }
+
+ 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());
+ css::uno::Sequence< OUString > aFavCharFontList(maFavCharFontList.size());
+
+ for (size_t i = 0; i < maFavCharList.size(); ++i)
+ {
+ aFavCharList[i] = maFavCharList[i];
+ aFavCharFontList[i] = maFavCharFontList[i];
+ }
+
+ std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create(mxContext));
+ officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterList::set(aFavCharList, batch);
+ officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterFontList::set(aFavCharFontList, batch);
+ batch->commit();
+}
+
+
+void SvxCharacterMap::updateFavCharControl()
+{
+ int i = 0;
+ for ( std::deque< OUString >::iterator it = maFavCharList.begin(), it2 = maFavCharFontList.begin();
+ it != maFavCharList.end() && it2 != maFavCharFontList.end();
+ ++it, ++it2, i++)
+ {
+ m_aFavCharView[i].SetText(*it);
+ vcl::Font rFont = m_aFavCharView[i].GetFont();
+ rFont.SetFamilyName( *it2 );
+ m_aFavCharView[i].SetFont(rFont);
+ m_aFavCharView[i].Show();
+ }
+
+ for(; i < 16 ; i++)
+ {
+ m_aFavCharView[i].SetText(OUString());
+ m_aFavCharView[i].Hide();
+ }
+ m_xShowSet->getFavCharacterList();
+ m_xSearchSet->getFavCharacterList();
+}
+
+void SvxCharacterMap::deleteFavCharacterFromList(const OUString& sTitle, const OUString& rFont)
+{
+ auto itChar = std::find(maFavCharList.begin(), maFavCharList.end(), sTitle);
+
+ auto itChar2 = std::find(maFavCharFontList.begin(), maFavCharFontList.end(), rFont);
+
+ // if Fav char to be added is already in list, remove it
+ if( itChar != maFavCharList.end() && itChar2 != maFavCharFontList.end() )
+ {
+ maFavCharList.erase( itChar );
+ maFavCharFontList.erase( itChar2);
+ }
+
+ css::uno::Sequence< OUString > aFavCharList(maFavCharList.size());
+ css::uno::Sequence< OUString > aFavCharFontList(maFavCharFontList.size());
+
+ for (size_t i = 0; i < maFavCharList.size(); ++i)
+ {
+ aFavCharList[i] = maFavCharList[i];
+ aFavCharFontList[i] = maFavCharFontList[i];
+ }
+
+ std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create(mxContext));
+ officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterList::set(aFavCharList, batch);
+ officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterFontList::set(aFavCharFontList, batch);
+ batch->commit();
+}
+
+void SvxCharacterMap::init()
+{
+ aFont = m_xVirDev->GetFont();
+ aFont.SetTransparent( true );
+ aFont.SetFamily( FAMILY_DONTKNOW );
+ aFont.SetPitch( PITCH_DONTKNOW );
+ aFont.SetCharSet( RTL_TEXTENCODING_DONTKNOW );
+
+ OUString aDefStr( aFont.GetFamilyName() );
+ OUString aLastName;
+ int nCount = m_xVirDev->GetDevFontCount();
+ std::vector<weld::ComboBoxEntry> aEntries;
+ aEntries.reserve(nCount);
+ for (int i = 0; i < nCount; ++i)
+ {
+ OUString aFontName( m_xVirDev->GetDevFont( i ).GetFamilyName() );
+ if (aFontName != aLastName)
+ {
+ aLastName = aFontName;
+ aEntries.emplace_back(aFontName, OUString::number(i));
+ }
+ }
+ m_xFontLB->insert_vector(aEntries, true);
+ // the font may not be in the list =>
+ // try to find a font name token in list and select found font,
+ // else select topmost entry
+ bool bFound = (m_xFontLB->find_text(aDefStr) == -1);
+ if (!bFound)
+ {
+ sal_Int32 nIndex = 0;
+ do
+ {
+ OUString aToken = aDefStr.getToken(0, ';', nIndex);
+ if (m_xFontLB->find_text(aToken) != -1)
+ {
+ aDefStr = aToken;
+ bFound = true;
+ break;
+ }
+ }
+ while ( nIndex >= 0 );
+ }
+
+ if (bFound)
+ m_xFontLB->set_active_text(aDefStr);
+ else if (m_xFontLB->get_count() )
+ m_xFontLB->set_active(0);
+ FontSelectHdl(*m_xFontLB);
+ if (m_xSubsetLB->get_count())
+ m_xSubsetLB->set_active(0);
+
+ m_xFontLB->connect_changed(LINK( this, SvxCharacterMap, FontSelectHdl));
+ m_xSubsetLB->connect_changed(LINK( this, SvxCharacterMap, SubsetSelectHdl));
+ m_xOKBtn->connect_clicked(LINK(this, SvxCharacterMap, InsertClickHdl));
+ m_xOKBtn->show();
+
+ m_xShowSet->SetDoubleClickHdl( LINK( this, SvxCharacterMap, CharDoubleClickHdl ) );
+ m_xShowSet->SetSelectHdl( LINK( this, SvxCharacterMap, CharSelectHdl ) );
+ m_xShowSet->SetHighlightHdl( LINK( this, SvxCharacterMap, CharHighlightHdl ) );
+ m_xShowSet->SetPreSelectHdl( LINK( this, SvxCharacterMap, CharPreSelectHdl ) );
+ m_xShowSet->SetFavClickHdl( LINK( this, SvxCharacterMap, FavClickHdl ) );
+
+ m_xSearchSet->SetDoubleClickHdl( LINK( this, SvxCharacterMap, SearchCharDoubleClickHdl ) );
+ m_xSearchSet->SetSelectHdl( LINK( this, SvxCharacterMap, SearchCharSelectHdl ) );
+ m_xSearchSet->SetHighlightHdl( LINK( this, SvxCharacterMap, SearchCharHighlightHdl ) );
+ m_xSearchSet->SetPreSelectHdl( LINK( this, SvxCharacterMap, SearchCharPreSelectHdl ) );
+ m_xSearchSet->SetFavClickHdl( LINK( this, SvxCharacterMap, FavClickHdl ) );
+
+ m_xDecimalCodeText->connect_changed( LINK( this, SvxCharacterMap, DecimalCodeChangeHdl ) );
+ m_xHexCodeText->connect_changed( LINK( this, SvxCharacterMap, HexCodeChangeHdl ) );
+ m_xFavouritesBtn->connect_clicked( LINK(this, SvxCharacterMap, FavSelectHdl));
+
+ // tdf#117038 set the buttons width to its max possible width so it doesn't
+ // make layout change when the label changes
+ m_xFavouritesBtn->set_label(CuiResId(RID_SVXSTR_REMOVE_FAVORITES));
+ auto nMaxWidth = m_xFavouritesBtn->get_preferred_size().Width();
+ m_xFavouritesBtn->set_label(CuiResId(RID_SVXSTR_ADD_FAVORITES));
+ nMaxWidth = std::max(nMaxWidth, m_xFavouritesBtn->get_preferred_size().Width());
+ m_xFavouritesBtn->set_size_request(nMaxWidth, -1);
+
+ if( SvxShowCharSet::getSelectedChar() == ' ')
+ {
+ m_xOKBtn->set_sensitive(false);
+ }
+ else
+ {
+ sal_UCS4 cChar = m_xShowSet->GetSelectCharacter();
+ // using the new UCS4 constructor
+ OUString aOUStr( &cChar, 1 );
+ m_aShowChar.SetText(aOUStr);
+
+ setFavButtonState(aOUStr, aDefStr);
+ m_xOKBtn->set_sensitive(true);
+ }
+
+ getRecentCharacterList();
+ updateRecentCharControl();
+
+ getFavCharacterList();
+ updateFavCharControl();
+
+ bool bHasInsert = m_xFrame.is();
+
+ for(int i = 0; i < 16; i++)
+ {
+ m_aRecentCharView[i].SetHasInsert(bHasInsert);
+ m_aRecentCharView[i].setMouseClickHdl(LINK(this,SvxCharacterMap, CharClickHdl));
+ m_aRecentCharView[i].setClearClickHdl(LINK(this,SvxCharacterMap, RecentClearClickHdl));
+ m_aRecentCharView[i].setClearAllClickHdl(LINK(this,SvxCharacterMap, RecentClearAllClickHdl));
+ m_aFavCharView[i].SetHasInsert(bHasInsert);
+ m_aFavCharView[i].setMouseClickHdl(LINK(this,SvxCharacterMap, CharClickHdl));
+ m_aFavCharView[i].setClearClickHdl(LINK(this,SvxCharacterMap, FavClearClickHdl));
+ m_aFavCharView[i].setClearAllClickHdl(LINK(this,SvxCharacterMap, FavClearAllClickHdl));
+ }
+
+ setCharName(90);
+
+ m_xSearchText->connect_focus_in(LINK( this, SvxCharacterMap, SearchFieldGetFocusHdl ));
+ m_xSearchText->connect_changed(LINK(this, SvxCharacterMap, SearchUpdateHdl));
+}
+
+bool SvxCharacterMap::isFavChar(const OUString& sTitle, const OUString& rFont)
+{
+ auto isFavCharTitleExists = std::any_of(maFavCharList.begin(),
+ maFavCharList.end(),
+ [sTitle] (const OUString & a) { return a == sTitle; });
+
+ auto isFavCharFontExists = std::any_of(maFavCharFontList.begin(),
+ maFavCharFontList.end(),
+ [rFont] (const OUString & a) { return a == rFont; });
+
+ // if Fav char to be added is already in list, remove it
+ return isFavCharTitleExists && isFavCharFontExists;
+}
+
+
+void SvxCharacterMap::setFavButtonState(const OUString& sTitle, const OUString& rFont)
+{
+ if(sTitle.isEmpty() || rFont.isEmpty())
+ {
+ m_xFavouritesBtn->set_sensitive(false);
+ return;
+ }
+ else
+ m_xFavouritesBtn->set_sensitive(true);
+
+ if (isFavChar(sTitle, rFont))
+ {
+ m_xFavouritesBtn->set_label(CuiResId(RID_SVXSTR_REMOVE_FAVORITES));
+ }
+ else
+ {
+ if(maFavCharList.size() == 16)
+ {
+ m_xFavouritesBtn->set_sensitive(false);
+ }
+
+ m_xFavouritesBtn->set_label(CuiResId(RID_SVXSTR_ADD_FAVORITES));
+ }
+}
+
+
+void SvxCharacterMap::SetCharFont( const vcl::Font& rFont )
+{
+ // first get the underlying info in order to get font names
+ // like "Times New Roman;Times" resolved
+ vcl::Font aTmp(m_xVirDev->GetFontMetric(rFont));
+
+ if (aTmp.GetFamilyName() == "StarSymbol" && m_xFontLB->find_text(aTmp.GetFamilyName()) == -1)
+ {
+ //if for some reason, like font in an old document, StarSymbol is requested and it's not available, then
+ //try OpenSymbol instead
+ aTmp.SetFamilyName("OpenSymbol");
+ }
+
+ if (m_xFontLB->find_text(aTmp.GetFamilyName()) == -1)
+ return;
+
+ m_xFontLB->set_active_text(aTmp.GetFamilyName());
+ aFont = aTmp;
+ FontSelectHdl(*m_xFontLB);
+ if (m_xSubsetLB->get_count())
+ m_xSubsetLB->set_active(0);
+}
+
+void SvxCharacterMap::fillAllSubsets(weld::ComboBox& rListBox)
+{
+ SubsetMap aAll(nullptr);
+ std::vector<weld::ComboBoxEntry> aEntries;
+ for (auto & subset : aAll.GetSubsetMap())
+ aEntries.emplace_back(subset.GetName());
+ rListBox.insert_vector(aEntries, true);
+}
+
+void SvxCharacterMap::insertCharToDoc(const OUString& sGlyph)
+{
+ if(sGlyph.isEmpty())
+ return;
+
+ if (m_xFrame.is()) {
+ uno::Sequence<beans::PropertyValue> aArgs(2);
+ aArgs[0].Name = "Symbols";
+ aArgs[0].Value <<= sGlyph;
+
+ aArgs[1].Name = "FontName";
+ aArgs[1].Value <<= aFont.GetFamilyName();
+ comphelper::dispatchCommand(".uno:InsertSymbol", m_xFrame, aArgs);
+
+ updateRecentCharacterList(sGlyph, aFont.GetFamilyName());
+
+ } else {
+ sal_Int32 tmp = 0;
+ sal_UCS4 cChar = sGlyph.iterateCodePoints(&tmp);
+ const SfxItemPool* pPool = m_xOutputSet->GetPool();
+ m_xOutputSet->Put( SfxStringItem( pPool->GetWhich(SID_CHARMAP), sGlyph ) );
+ m_xOutputSet->Put( SvxFontItem( aFont.GetFamilyType(), aFont.GetFamilyName(),
+ aFont.GetStyleName(), aFont.GetPitch(), aFont.GetCharSet(), pPool->GetWhich(SID_ATTR_CHAR_FONT) ) );
+ m_xOutputSet->Put( SfxStringItem( pPool->GetWhich(SID_FONT_NAME), aFont.GetFamilyName() ) );
+ m_xOutputSet->Put( SfxInt32Item( pPool->GetWhich(SID_ATTR_CHAR), cChar ) );
+ }
+}
+
+IMPL_LINK_NOARG(SvxCharacterMap, FontSelectHdl, weld::ComboBox&, void)
+{
+ const sal_uInt32 nFont = m_xFontLB->get_active_id().toUInt32();
+ aFont = m_xVirDev->GetDevFont(nFont);
+ aFont.SetWeight( WEIGHT_DONTKNOW );
+ aFont.SetItalic( ITALIC_NONE );
+ aFont.SetWidthType( WIDTH_DONTKNOW );
+ aFont.SetPitch( PITCH_DONTKNOW );
+ aFont.SetFamily( FAMILY_DONTKNOW );
+
+ // notify children using this font
+ m_xShowSet->SetFont( aFont );
+ m_xSearchSet->SetFont( aFont );
+ m_aShowChar.SetFont( aFont );
+
+ // setup unicode subset listbar with font specific subsets,
+ // hide unicode subset listbar for symbol fonts
+ // TODO: get info from the Font once it provides it
+ pSubsetMap.reset();
+ m_xSubsetLB->clear();
+
+ bool bNeedSubset = (aFont.GetCharSet() != RTL_TEXTENCODING_SYMBOL);
+ if (bNeedSubset)
+ {
+ FontCharMapRef xFontCharMap = m_xShowSet->GetFontCharMap();
+ pSubsetMap.reset(new SubsetMap( xFontCharMap ));
+
+ // update subset listbox for new font's unicode subsets
+ for (auto const& subset : pSubsetMap->GetSubsetMap())
+ {
+ m_xSubsetLB->append(OUString::number(reinterpret_cast<sal_uInt64>(&subset)), subset.GetName());
+ // NOTE: subset must live at least as long as the selected font
+ }
+
+ if (m_xSubsetLB->get_count() <= 1)
+ bNeedSubset = false;
+ }
+
+ m_xSubsetText->set_sensitive(bNeedSubset);
+ m_xSubsetLB->set_sensitive(bNeedSubset);
+
+ if (isSearchMode)
+ {
+ // tdf#137294 do this after modifying m_xSubsetLB sensitivity to
+ // restore insensitive for the search case
+ SearchUpdateHdl(*m_xSearchText);
+ SearchCharHighlightHdl(m_xSearchSet.get());
+ }
+
+ // tdf#118304 reselect current glyph to see if its still there in new font
+ selectCharByCode(Radix::hexadecimal);
+}
+
+void SvxCharacterMap::toggleSearchView(bool state)
+{
+ isSearchMode = state;
+ m_xHexCodeText->set_editable(!state);
+ m_xDecimalCodeText->set_editable(!state);
+ m_xSubsetLB->set_sensitive(!state);
+
+ if(state)
+ {
+ m_xSearchSet->Show();
+ m_xShowSet->Hide();
+ }
+ else
+ {
+ m_xSearchSet->Hide();
+ m_xShowSet->Show();
+ }
+}
+
+void SvxCharacterMap::setCharName(sal_UCS4 nDecimalValue)
+{
+ /* get the character name */
+ UErrorCode errorCode = U_ZERO_ERROR;
+ // icu has a private uprv_getMaxCharNameLength function which returns the max possible
+ // length of this property. Unicode 3.2 max char name length was 83
+ char buffer[100];
+ u_charName(nDecimalValue, U_UNICODE_CHAR_NAME, buffer, sizeof(buffer), &errorCode);
+ if (U_SUCCESS(errorCode))
+ m_xCharName->set_label(OUString::createFromAscii(buffer));
+}
+
+IMPL_LINK_NOARG(SvxCharacterMap, SubsetSelectHdl, weld::ComboBox&, void)
+{
+ const sal_Int32 nPos = m_xSubsetLB->get_active();
+ const Subset* pSubset = reinterpret_cast<const Subset*>(m_xSubsetLB->get_active_id().toUInt64());
+
+ if( pSubset && !isSearchMode)
+ {
+ sal_UCS4 cFirst = pSubset->GetRangeMin();
+ m_xShowSet->SelectCharacter( cFirst );
+
+ setFavButtonState(OUString(&cFirst, 1), aFont.GetFamilyName());
+ m_xSubsetLB->set_active(nPos);
+ }
+ else if( pSubset && isSearchMode)
+ {
+ m_xSearchSet->SelectCharacter( pSubset );
+
+ const Subset* curSubset = nullptr;
+ if( pSubsetMap )
+ curSubset = pSubsetMap->GetSubsetByUnicode( m_xSearchSet->GetSelectCharacter() );
+ if( curSubset )
+ m_xSubsetLB->set_active_text(curSubset->GetName());
+ else
+ m_xSubsetLB->set_active(-1);
+
+ sal_UCS4 sChar = m_xSearchSet->GetSelectCharacter();
+ setFavButtonState(OUString(&sChar, 1), aFont.GetFamilyName());
+ }
+}
+
+IMPL_LINK(SvxCharacterMap, RecentClearClickHdl, SvxCharView*, rView, void)
+{
+ const OUString& sTitle = rView->GetText();
+ auto itChar = std::find(maRecentCharList.begin(), maRecentCharList.end(), sTitle);
+
+ OUString sFont = rView->GetFont().GetFamilyName();
+ auto itChar2 = std::find(maRecentCharFontList.begin(), maRecentCharFontList.end(), sFont);
+
+ // if recent char to be added is already in list, remove it
+ if( itChar != maRecentCharList.end() && itChar2 != maRecentCharFontList.end() )
+ {
+ maRecentCharList.erase( itChar );
+ maRecentCharFontList.erase( itChar2);
+ }
+
+ css::uno::Sequence< OUString > aRecentCharList(maRecentCharList.size());
+ css::uno::Sequence< OUString > aRecentCharFontList(maRecentCharFontList.size());
+
+ for (size_t i = 0; i < maRecentCharList.size(); ++i)
+ {
+ aRecentCharList[i] = maRecentCharList[i];
+ aRecentCharFontList[i] = maRecentCharFontList[i];
+ }
+
+ std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create(mxContext));
+ officecfg::Office::Common::RecentCharacters::RecentCharacterList::set(aRecentCharList, batch);
+ officecfg::Office::Common::RecentCharacters::RecentCharacterFontList::set(aRecentCharFontList, batch);
+ batch->commit();
+
+ updateRecentCharControl();
+}
+
+IMPL_LINK_NOARG(SvxCharacterMap, RecentClearAllClickHdl, SvxCharView*, void)
+{
+ css::uno::Sequence< OUString > aRecentCharList(0);
+ css::uno::Sequence< OUString > aRecentCharFontList(0);
+
+ maRecentCharList.clear();
+ maRecentCharFontList.clear();
+
+ std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create(mxContext));
+ officecfg::Office::Common::RecentCharacters::RecentCharacterList::set(aRecentCharList, batch);
+ officecfg::Office::Common::RecentCharacters::RecentCharacterFontList::set(aRecentCharFontList, batch);
+ batch->commit();
+
+ updateRecentCharControl();
+}
+
+IMPL_LINK(SvxCharacterMap, FavClearClickHdl, SvxCharView*, rView, void)
+{
+ deleteFavCharacterFromList(rView->GetText(), rView->GetFont().GetFamilyName());
+ updateFavCharControl();
+}
+
+IMPL_LINK_NOARG(SvxCharacterMap, FavClearAllClickHdl, SvxCharView*, void)
+{
+ css::uno::Sequence< OUString > aFavCharList(0);
+ css::uno::Sequence< OUString > aFavCharFontList(0);
+
+ maFavCharList.clear();
+ maFavCharFontList.clear();
+
+ std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create(mxContext));
+ officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterList::set(aFavCharList, batch);
+ officecfg::Office::Common::FavoriteCharacters::FavoriteCharacterFontList::set(aFavCharFontList, batch);
+ batch->commit();
+
+ updateFavCharControl();
+}
+
+IMPL_LINK_NOARG(SvxCharacterMap, SearchFieldGetFocusHdl, weld::Widget&, void)
+{
+ m_xOKBtn->set_sensitive(false);
+}
+
+IMPL_LINK_NOARG(SvxCharacterMap, SearchUpdateHdl, weld::Entry&, void)
+{
+ if (!m_xSearchText->get_text().isEmpty())
+ {
+ m_xSearchSet->ClearPreviousData();
+ OUString aKeyword = m_xSearchText->get_text();
+
+ toggleSearchView(true);
+
+ FontCharMapRef xFontCharMap = m_xSearchSet->GetFontCharMap();
+
+ sal_UCS4 sChar = xFontCharMap->GetFirstChar();
+ while(sChar != xFontCharMap->GetLastChar())
+ {
+ UErrorCode errorCode = U_ZERO_ERROR;
+ char buffer[100];
+ u_charName(sChar, U_UNICODE_CHAR_NAME, buffer, sizeof(buffer), &errorCode);
+ if (U_SUCCESS(errorCode))
+ {
+ OUString sName = OUString::createFromAscii(buffer);
+ if(!sName.isEmpty() && sName.toAsciiLowerCase().indexOf(aKeyword.toAsciiLowerCase()) >= 0)
+ m_xSearchSet->AppendCharToList(sChar);
+ }
+ sChar = xFontCharMap->GetNextChar(sChar);
+ }
+ //for last char
+ UErrorCode errorCode = U_ZERO_ERROR;
+ char buffer[100];
+ u_charName(sChar, U_UNICODE_CHAR_NAME, buffer, sizeof(buffer), &errorCode);
+ if (U_SUCCESS(errorCode))
+ {
+ OUString sName = OUString::createFromAscii(buffer);
+ if(!sName.isEmpty() && sName.toAsciiLowerCase().indexOf(aKeyword.toAsciiLowerCase()) >= 0)
+ m_xSearchSet->AppendCharToList(sChar);
+ }
+ }
+ else
+ {
+ toggleSearchView(false);
+ }
+}
+
+
+IMPL_LINK(SvxCharacterMap, CharClickHdl, SvxCharView*, rView, void)
+{
+ rView->GrabFocus();
+
+ m_aShowChar.SetText( rView->GetText() );
+ m_aShowChar.SetFont(rView->GetFont());
+ m_aShowChar.Invalidate();
+
+ setFavButtonState(rView->GetText(), rView->GetFont().GetFamilyName());//check state
+
+ // Get the hexadecimal code
+ OUString charValue = rView->GetText();
+ sal_Int32 tmp = 1;
+ sal_UCS4 cChar = charValue.iterateCodePoints(&tmp, -1);
+ OUString aHexText = OUString::number(cChar, 16).toAsciiUpperCase();
+
+ // Get the decimal code
+ OUString aDecimalText = OUString::number(cChar);
+
+ m_xHexCodeText->set_text(aHexText);
+ m_xDecimalCodeText->set_text(aDecimalText);
+ setCharName(cChar);
+
+ rView->Invalidate();
+ m_xOKBtn->set_sensitive(true);
+}
+
+IMPL_LINK_NOARG(SvxCharacterMap, CharDoubleClickHdl, SvxShowCharSet*, void)
+{
+ sal_UCS4 cChar = m_xShowSet->GetSelectCharacter();
+ // using the new UCS4 constructor
+ OUString aOUStr( &cChar, 1 );
+ setFavButtonState(aOUStr, aFont.GetFamilyName());
+ insertCharToDoc(aOUStr);
+}
+
+IMPL_LINK_NOARG(SvxCharacterMap, SearchCharDoubleClickHdl, SvxShowCharSet*, void)
+{
+ sal_UCS4 cChar = m_xSearchSet->GetSelectCharacter();
+ // using the new UCS4 constructor
+ OUString aOUStr( &cChar, 1 );
+ setFavButtonState(aOUStr, aFont.GetFamilyName());
+ insertCharToDoc(aOUStr);
+}
+
+IMPL_LINK_NOARG(SvxCharacterMap, CharSelectHdl, SvxShowCharSet*, void)
+{
+ m_xOKBtn->set_sensitive(true);
+}
+
+IMPL_LINK_NOARG(SvxCharacterMap, SearchCharSelectHdl, SvxShowCharSet*, void)
+{
+ m_xOKBtn->set_sensitive(true);
+}
+
+IMPL_LINK_NOARG(SvxCharacterMap, InsertClickHdl, weld::Button&, void)
+{
+ OUString sChar = m_aShowChar.GetText();
+ insertCharToDoc(sChar);
+ // Need to update recent character list, when OK button does not insert
+ if(!m_xFrame.is())
+ updateRecentCharacterList(sChar, aFont.GetFamilyName());
+ m_xDialog->response(RET_OK);
+}
+
+IMPL_LINK_NOARG(SvxCharacterMap, FavSelectHdl, weld::Button&, void)
+{
+ if (m_xFavouritesBtn->get_label().match(CuiResId(RID_SVXSTR_ADD_FAVORITES)))
+ {
+ updateFavCharacterList(m_aShowChar.GetText(), m_aShowChar.GetFont().GetFamilyName());
+ setFavButtonState(m_aShowChar.GetText(), m_aShowChar.GetFont().GetFamilyName());
+ }
+ else
+ {
+ deleteFavCharacterFromList(m_aShowChar.GetText(), m_aShowChar.GetFont().GetFamilyName());
+ m_xFavouritesBtn->set_label(CuiResId(RID_SVXSTR_ADD_FAVORITES));
+ m_xFavouritesBtn->set_sensitive(false);
+ }
+
+ updateFavCharControl();
+}
+
+IMPL_LINK_NOARG(SvxCharacterMap, FavClickHdl, SvxShowCharSet*, void)
+{
+ getFavCharacterList();
+ updateFavCharControl();
+}
+
+IMPL_LINK_NOARG(SvxCharacterMap, CharHighlightHdl, SvxShowCharSet*, void)
+{
+ OUString aText;
+ OUString aHexText;
+ OUString aDecimalText;
+ sal_UCS4 cChar = m_xShowSet->GetSelectCharacter();
+ bool bSelect = (cChar > 0);
+
+ // show char sample
+ if ( bSelect )
+ {
+ // using the new UCS4 constructor
+ aText = OUString( &cChar, 1 );
+ // Get the hexadecimal code
+ aHexText = OUString::number(cChar, 16).toAsciiUpperCase();
+ // Get the decimal code
+ aDecimalText = OUString::number(cChar);
+ setCharName(cChar);
+
+ // Update the hex and decimal codes only if necessary
+ if (!m_xHexCodeText->get_text().equalsIgnoreAsciiCase(aHexText))
+ m_xHexCodeText->set_text(aHexText);
+ if (m_xDecimalCodeText->get_text() != aDecimalText)
+ m_xDecimalCodeText->set_text( aDecimalText );
+
+ const Subset* pSubset = nullptr;
+ if( pSubsetMap )
+ pSubset = pSubsetMap->GetSubsetByUnicode( cChar );
+ if( pSubset )
+ m_xSubsetLB->set_active_text(pSubset->GetName());
+ else
+ m_xSubsetLB->set_active(-1);
+ }
+
+ m_aShowChar.SetText( aText );
+ m_aShowChar.SetFont( aFont );
+ m_aShowChar.Invalidate();
+
+ setFavButtonState(aText, aFont.GetFamilyName());
+}
+
+IMPL_LINK_NOARG(SvxCharacterMap, SearchCharHighlightHdl, SvxShowCharSet*, void)
+{
+ OUString aText;
+ OUString aHexText;
+ OUString aDecimalText;
+ sal_UCS4 cChar = m_xSearchSet->GetSelectCharacter();
+ bool bSelect = (cChar > 0);
+
+ // show char sample
+ if ( bSelect )
+ {
+ aText = OUString( &cChar, 1 );
+ // Get the hexadecimal code
+ aHexText = OUString::number(cChar, 16).toAsciiUpperCase();
+ // Get the decimal code
+ aDecimalText = OUString::number(cChar);
+ setCharName(cChar);
+
+ // Update the hex and decimal codes only if necessary
+ if (!m_xHexCodeText->get_text().equalsIgnoreAsciiCase(aHexText))
+ m_xHexCodeText->set_text(aHexText);
+ if (m_xDecimalCodeText->get_text() != aDecimalText)
+ m_xDecimalCodeText->set_text( aDecimalText );
+
+ const Subset* pSubset = nullptr;
+ if( pSubsetMap )
+ pSubset = pSubsetMap->GetSubsetByUnicode( cChar );
+ if( pSubset )
+ m_xSubsetLB->set_active_text(pSubset->GetName());
+ else
+ m_xSubsetLB->set_active(-1);
+ }
+
+ if(m_xSearchSet->HasFocus())
+ {
+ m_aShowChar.SetText( aText );
+ m_aShowChar.SetFont( aFont );
+ m_aShowChar.Invalidate();
+
+ setFavButtonState(aText, aFont.GetFamilyName());
+ }
+}
+
+void SvxCharacterMap::selectCharByCode(Radix radix)
+{
+ OUString aCodeString;
+ switch(radix)
+ {
+ case Radix::decimal:
+ aCodeString = m_xDecimalCodeText->get_text();
+ break;
+ case Radix::hexadecimal:
+ aCodeString = m_xHexCodeText->get_text();
+ break;
+ }
+ // Convert the code back to a character using the appropriate radix
+ sal_UCS4 cChar = aCodeString.toUInt32(static_cast<sal_Int16> (radix));
+ // Use FontCharMap::HasChar(sal_UCS4 cChar) to see if the desired character is in the font
+ FontCharMapRef xFontCharMap = m_xShowSet->GetFontCharMap();
+ if (xFontCharMap->HasChar(cChar))
+ // Select the corresponding character
+ SetChar(cChar);
+ else {
+ m_xCharName->set_label(CuiResId(RID_SVXSTR_MISSING_CHAR));
+ m_aShowChar.SetText(" ");
+ switch(radix)
+ {
+ case Radix::decimal:
+ m_xHexCodeText->set_text(OUString::number(cChar, 16));
+ break;
+ case Radix::hexadecimal:
+ m_xDecimalCodeText->set_text(OUString::number(cChar));
+ break;
+ }
+ }
+}
+
+IMPL_LINK_NOARG(SvxCharacterMap, DecimalCodeChangeHdl, weld::Entry&, void)
+{
+ selectCharByCode(Radix::decimal);
+}
+
+IMPL_LINK_NOARG(SvxCharacterMap, HexCodeChangeHdl, weld::Entry&, void)
+{
+ selectCharByCode(Radix::hexadecimal);
+}
+
+IMPL_LINK_NOARG(SvxCharacterMap, CharPreSelectHdl, SvxShowCharSet*, void)
+{
+ // adjust subset selection
+ if( pSubsetMap )
+ {
+ sal_UCS4 cChar = m_xShowSet->GetSelectCharacter();
+
+ setFavButtonState(OUString(&cChar, 1), aFont.GetFamilyName());
+ const Subset* pSubset = pSubsetMap->GetSubsetByUnicode( cChar );
+ if( pSubset )
+ m_xSubsetLB->set_active_text(pSubset->GetName());
+ }
+
+ m_xOKBtn->set_sensitive(true);
+}
+
+IMPL_LINK_NOARG(SvxCharacterMap, SearchCharPreSelectHdl, SvxShowCharSet*, void)
+{
+ // adjust subset selection
+ if( pSubsetMap )
+ {
+ sal_UCS4 cChar = m_xSearchSet->GetSelectCharacter();
+
+ setFavButtonState(OUString(&cChar, 1), aFont.GetFamilyName());
+ const Subset* pSubset = pSubsetMap->GetSubsetByUnicode( cChar );
+ if( pSubset )
+ m_xSubsetLB->set_active_text(pSubset->GetName());
+ }
+
+ m_xOKBtn->set_sensitive(true);
+}
+
+// class SvxShowText =====================================================
+SvxShowText::SvxShowText(const VclPtr<VirtualDevice>& rVirDev)
+ : m_xVirDev(rVirDev)
+ , mnY(0)
+ , mbCenter(false)
+{
+}
+
+void SvxShowText::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ CustomWidgetController::SetDrawingArea(pDrawingArea);
+ vcl::Font aFont = m_xVirDev->GetFont();
+ Size aFontSize(aFont.GetFontSize().Width() * 5, aFont.GetFontSize().Height() * 5);
+ aFont.SetFontSize(aFontSize);
+ m_xVirDev->Push(PUSH_ALLFONT);
+ m_xVirDev->SetFont(aFont);
+ pDrawingArea->set_size_request(m_xVirDev->approximate_digit_width() + 2 * 12,
+ m_xVirDev->LogicToPixel(aFontSize).Height() * 2);
+ m_xVirDev->Pop();
+}
+
+void SvxShowText::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ rRenderContext.SetFont(m_aFont);
+
+ Color aTextCol = rRenderContext.GetTextColor();
+ Color aFillCol = rRenderContext.GetFillColor();
+
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ const Color aWindowTextColor(rStyleSettings.GetDialogTextColor());
+ const Color aWindowColor(rStyleSettings.GetWindowColor());
+ rRenderContext.SetTextColor(aWindowTextColor);
+ rRenderContext.SetFillColor(aWindowColor);
+
+ const OUString aText = GetText();
+
+ Size aSize(GetOutputSizePixel());
+ long nAvailWidth = aSize.Width();
+ long nWinHeight = aSize.Height();
+
+ bool bGotBoundary = true;
+ bool bShrankFont = false;
+ vcl::Font aOrigFont(rRenderContext.GetFont());
+ Size aFontSize(aOrigFont.GetFontSize());
+ ::tools::Rectangle aBoundRect;
+
+ for (long nFontHeight = aFontSize.Height(); nFontHeight > 0; nFontHeight -= 5)
+ {
+ if (!rRenderContext.GetTextBoundRect( aBoundRect, aText ) || aBoundRect.IsEmpty())
+ {
+ bGotBoundary = false;
+ break;
+ }
+ if (!mbCenter)
+ break;
+ //only shrink in the single glyph large view mode
+ long nTextWidth = aBoundRect.GetWidth();
+ if (nAvailWidth > nTextWidth)
+ break;
+ vcl::Font aFont(aOrigFont);
+ aFontSize.setHeight( nFontHeight );
+ aFont.SetFontSize(aFontSize);
+ rRenderContext.SetFont(aFont);
+ mnY = (nWinHeight - rRenderContext.GetTextHeight()) / 2;
+ bShrankFont = true;
+ }
+
+ Point aPoint(2, mnY);
+ // adjust position using ink boundary if possible
+ if (!bGotBoundary)
+ aPoint.setX( (aSize.Width() - rRenderContext.GetTextWidth(aText)) / 2 );
+ else
+ {
+ // adjust position before it gets out of bounds
+ aBoundRect += aPoint;
+
+ // shift back vertically if needed
+ int nYLDelta = aBoundRect.Top();
+ int nYHDelta = aSize.Height() - aBoundRect.Bottom();
+ if( nYLDelta <= 0 )
+ aPoint.AdjustY( -(nYLDelta - 1) );
+ else if( nYHDelta <= 0 )
+ aPoint.AdjustY(nYHDelta - 1 );
+
+ if (mbCenter)
+ {
+ // move glyph to middle of cell
+ aPoint.setX( -aBoundRect.Left() + (aSize.Width() - aBoundRect.GetWidth()) / 2 );
+ }
+ else
+ {
+ // shift back horizontally if needed
+ int nXLDelta = aBoundRect.Left();
+ int nXHDelta = aSize.Width() - aBoundRect.Right();
+ if( nXLDelta <= 0 )
+ aPoint.AdjustX( -(nXLDelta - 1) );
+ else if( nXHDelta <= 0 )
+ aPoint.AdjustX(nXHDelta - 1 );
+ }
+ }
+
+ rRenderContext.DrawRect(tools::Rectangle(Point(0, 0), aSize));
+ rRenderContext.DrawText(aPoint, aText);
+ rRenderContext.SetTextColor(aTextCol);
+ rRenderContext.SetFillColor(aFillCol);
+ if (bShrankFont)
+ rRenderContext.SetFont(aOrigFont);
+}
+
+void SvxShowText::SetFont( const vcl::Font& rFont )
+{
+ long nWinHeight = GetOutputSizePixel().Height();
+
+ m_aFont = rFont;
+ m_aFont.SetWeight(WEIGHT_NORMAL);
+ m_aFont.SetAlignment(ALIGN_TOP);
+ m_aFont.SetFontSize(m_xVirDev->PixelToLogic(Size(0, nWinHeight / 2)));
+ m_aFont.SetTransparent(true);
+
+ m_xVirDev->Push(PUSH_ALLFONT);
+ m_xVirDev->SetFont(m_aFont);
+ mnY = (nWinHeight - m_xVirDev->GetTextHeight()) / 2;
+ m_xVirDev->Pop();
+
+ Invalidate();
+}
+
+void SvxShowText::Resize()
+{
+ SetFont(GetFont()); //force recalculation of size
+}
+
+void SvxShowText::SetText(const OUString& rText)
+{
+ m_sText = rText;
+ Invalidate();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/dialogs/cuifmsearch.cxx b/cui/source/dialogs/cuifmsearch.cxx
new file mode 100644
index 000000000..de7681fa7
--- /dev/null
+++ b/cui/source/dialogs/cuifmsearch.cxx
@@ -0,0 +1,754 @@
+/* -*- 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/debug.hxx>
+#include <vcl/stdtext.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <dialmgr.hxx>
+#include <sfx2/app.hxx>
+#include <svx/fmsrccfg.hxx>
+#include <svx/fmsrcimp.hxx>
+#include <strings.hrc>
+#include <cuifmsearch.hxx>
+#include <svl/cjkoptions.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/string.hxx>
+#include <svx/svxdlg.hxx>
+
+using namespace css::uno;
+using namespace css::i18n;
+using namespace ::svxform;
+using namespace css::sdbc;
+using namespace css::util;
+
+#define MAX_HISTORY_ENTRIES 50
+
+void FmSearchDialog::initCommon( const Reference< XResultSet >& _rxCursor )
+{
+ // init the engine
+ DBG_ASSERT( m_pSearchEngine, "FmSearchDialog::initCommon: have no engine!" );
+ m_pSearchEngine->SetProgressHandler(LINK(this, FmSearchDialog, OnSearchProgress));
+
+ // some layout changes according to available CJK options
+ SvtCJKOptions aCJKOptions;
+ if (!aCJKOptions.IsJapaneseFindEnabled())
+ {
+ // hide the options for the japanese search
+ m_pSoundsLikeCJK->hide();
+ m_pSoundsLikeCJKSettings->hide();
+ }
+
+ if (!aCJKOptions.IsCJKFontEnabled())
+ {
+ m_pHalfFullFormsCJK->hide();
+
+ // never ignore the width (ignoring is expensive) if the option is not available at all
+ m_pSearchEngine->SetIgnoreWidthCJK( false );
+ }
+
+ // some initial record texts
+ m_pftRecord->set_label( OUString::number(_rxCursor->getRow()) );
+ m_pbClose->set_tooltip_text(OUString());
+}
+
+FmSearchDialog::FmSearchDialog(weld::Window* pParent, const OUString& sInitialText, const std::vector< OUString >& _rContexts, sal_Int16 nInitialContext,
+ const Link<FmSearchContext&,sal_uInt32>& lnkContextSupplier)
+ : GenericDialogController(pParent, "cui/ui/fmsearchdialog.ui", "RecordSearchDialog")
+ , m_sCancel( GetStandardText( StandardButtonType::Cancel ) )
+ , m_lnkContextSupplier(lnkContextSupplier)
+ , m_prbSearchForText(m_xBuilder->weld_radio_button("rbSearchForText"))
+ , m_prbSearchForNull(m_xBuilder->weld_radio_button("rbSearchForNull"))
+ , m_prbSearchForNotNull(m_xBuilder->weld_radio_button("rbSearchForNotNull"))
+ , m_pcmbSearchText(m_xBuilder->weld_combo_box("cmbSearchText"))
+ , m_pftForm(m_xBuilder->weld_label("ftForm"))
+ , m_plbForm(m_xBuilder->weld_combo_box("lbForm"))
+ , m_prbAllFields(m_xBuilder->weld_radio_button("rbAllFields"))
+ , m_prbSingleField(m_xBuilder->weld_radio_button("rbSingleField"))
+ , m_plbField(m_xBuilder->weld_combo_box("lbField"))
+ , m_pftPosition(m_xBuilder->weld_label("ftPosition"))
+ , m_plbPosition(m_xBuilder->weld_combo_box("lbPosition"))
+ , m_pcbUseFormat(m_xBuilder->weld_check_button("cbUseFormat"))
+ , m_pcbCase(m_xBuilder->weld_check_button("cbCase"))
+ , m_pcbBackwards(m_xBuilder->weld_check_button("cbBackwards"))
+ , m_pcbStartOver(m_xBuilder->weld_check_button("cbStartOver"))
+ , m_pcbWildCard(m_xBuilder->weld_check_button("cbWildCard"))
+ , m_pcbRegular(m_xBuilder->weld_check_button("cbRegular"))
+ , m_pcbApprox(m_xBuilder->weld_check_button("cbApprox"))
+ , m_ppbApproxSettings(m_xBuilder->weld_button("pbApproxSettings"))
+ , m_pHalfFullFormsCJK(m_xBuilder->weld_check_button("HalfFullFormsCJK"))
+ , m_pSoundsLikeCJK(m_xBuilder->weld_check_button("SoundsLikeCJK"))
+ , m_pSoundsLikeCJKSettings(m_xBuilder->weld_button("SoundsLikeCJKSettings"))
+ , m_pftRecord(m_xBuilder->weld_label("ftRecord"))
+ , m_pftHint(m_xBuilder->weld_label("ftHint"))
+ , m_pbSearchAgain(m_xBuilder->weld_button("pbSearchAgain"))
+ , m_pbClose(m_xBuilder->weld_button("close"))
+{
+ m_pcmbSearchText->set_size_request(m_pcmbSearchText->get_approximate_digit_width() * 38, -1);
+ m_plbForm->set_size_request(m_plbForm->get_approximate_digit_width() * 38, -1);
+ m_sSearch = m_pbSearchAgain->get_label();
+
+ DBG_ASSERT(m_lnkContextSupplier.IsSet(), "FmSearchDialog::FmSearchDialog : have no ContextSupplier !");
+
+ FmSearchContext fmscInitial;
+ fmscInitial.nContext = nInitialContext;
+ m_lnkContextSupplier.Call(fmscInitial);
+ DBG_ASSERT(fmscInitial.xCursor.is(), "FmSearchDialog::FmSearchDialog : invalid data supplied by ContextSupplier !");
+ DBG_ASSERT(comphelper::string::getTokenCount(fmscInitial.strUsedFields, ';') == static_cast<sal_Int32>(fmscInitial.arrFields.size()),
+ "FmSearchDialog::FmSearchDialog : invalid data supplied by ContextSupplied !");
+#if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL
+ for (const Reference<XInterface> & arrField : fmscInitial.arrFields)
+ {
+ DBG_ASSERT(arrField.is(), "FmSearchDialog::FmSearchDialog : invalid data supplied by ContextSupplier !");
+ }
+#endif // (OSL_DEBUG_LEVEL > 1) || DBG_UTIL
+
+ for ( std::vector< OUString >::const_iterator context = _rContexts.begin();
+ context != _rContexts.end();
+ ++context
+ )
+ {
+ m_arrContextFields.emplace_back();
+ m_plbForm->append_text(*context);
+ }
+ m_plbForm->set_active(nInitialContext);
+
+ m_plbForm->connect_changed(LINK(this, FmSearchDialog, OnContextSelection));
+
+ if (m_arrContextFields.size() == 1)
+ {
+ // hide dispensable controls
+ m_pftForm->hide();
+ m_plbForm->hide();
+ }
+
+ m_pSearchEngine.reset( new FmSearchEngine(
+ ::comphelper::getProcessComponentContext(), fmscInitial.xCursor, fmscInitial.strUsedFields, fmscInitial.arrFields ) );
+ initCommon( fmscInitial.xCursor );
+
+ if ( !fmscInitial.sFieldDisplayNames.isEmpty() )
+ { // use the display names if supplied
+ DBG_ASSERT(comphelper::string::getTokenCount(fmscInitial.sFieldDisplayNames, ';') == comphelper::string::getTokenCount(fmscInitial.strUsedFields, ';'),
+ "FmSearchDialog::FmSearchDialog : invalid initial context description !");
+ Init(fmscInitial.sFieldDisplayNames, sInitialText);
+ }
+ else
+ Init(fmscInitial.strUsedFields, sInitialText);
+}
+
+FmSearchDialog::~FmSearchDialog()
+{
+ SaveParams();
+
+ m_pConfig.reset();
+ m_pSearchEngine.reset();
+}
+
+void FmSearchDialog::Init(const OUString& strVisibleFields, const OUString& sInitialText)
+{
+ //the initialization of all the Controls
+ m_prbSearchForText->connect_clicked(LINK(this, FmSearchDialog, OnClickedFieldRadios));
+ m_prbSearchForNull->connect_clicked(LINK(this, FmSearchDialog, OnClickedFieldRadios));
+ m_prbSearchForNotNull->connect_clicked(LINK(this, FmSearchDialog, OnClickedFieldRadios));
+
+ m_prbAllFields->connect_clicked(LINK(this, FmSearchDialog, OnClickedFieldRadios));
+ m_prbSingleField->connect_clicked(LINK(this, FmSearchDialog, OnClickedFieldRadios));
+
+ m_pbSearchAgain->connect_clicked(LINK(this, FmSearchDialog, OnClickedSearchAgain));
+ m_ppbApproxSettings->connect_clicked(LINK(this, FmSearchDialog, OnClickedSpecialSettings));
+ m_pSoundsLikeCJKSettings->connect_clicked(LINK(this, FmSearchDialog, OnClickedSpecialSettings));
+
+ m_plbPosition->connect_changed(LINK(this, FmSearchDialog, OnPositionSelected));
+ m_plbField->connect_changed(LINK(this, FmSearchDialog, OnFieldSelected));
+
+ m_pcmbSearchText->connect_changed(LINK(this, FmSearchDialog, OnSearchTextModified));
+ m_pcmbSearchText->set_entry_completion(false);
+ m_pcmbSearchText->connect_focus_in(LINK(this, FmSearchDialog, OnFocusGrabbed));
+
+ m_pcbUseFormat->connect_toggled(LINK(this, FmSearchDialog, OnCheckBoxToggled));
+ m_pcbBackwards->connect_toggled(LINK(this, FmSearchDialog, OnCheckBoxToggled));
+ m_pcbStartOver->connect_toggled(LINK(this, FmSearchDialog, OnCheckBoxToggled));
+ m_pcbCase->connect_toggled(LINK(this, FmSearchDialog, OnCheckBoxToggled));
+ m_pcbWildCard->connect_toggled(LINK(this, FmSearchDialog, OnCheckBoxToggled));
+ m_pcbRegular->connect_toggled(LINK(this, FmSearchDialog, OnCheckBoxToggled));
+ m_pcbApprox->connect_toggled(LINK(this, FmSearchDialog, OnCheckBoxToggled));
+ m_pHalfFullFormsCJK->connect_toggled(LINK(this, FmSearchDialog, OnCheckBoxToggled));
+ m_pSoundsLikeCJK->connect_toggled(LINK(this, FmSearchDialog, OnCheckBoxToggled));
+
+ // fill the listboxes
+ // method of field comparison
+ const char* const aResIds[] = {
+ RID_STR_SEARCH_ANYWHERE,
+ RID_STR_SEARCH_BEGINNING,
+ RID_STR_SEARCH_END,
+ RID_STR_SEARCH_WHOLE
+ };
+ for (auto pResId : aResIds)
+ m_plbPosition->append_text(CuiResId(pResId));
+ m_plbPosition->set_active(MATCHING_ANYWHERE);
+
+ // the field listbox
+ if (!strVisibleFields.isEmpty())
+ {
+ sal_Int32 nPos {0};
+ do {
+ m_plbField->append_text(strVisibleFields.getToken(0, ';', nPos));
+ } while (nPos>=0);
+ }
+
+
+ m_pConfig.reset( new FmSearchConfigItem );
+ LoadParams();
+
+ m_pcmbSearchText->set_entry_text(sInitialText);
+ // if the Edit-line has changed the text (e.g. because it contains
+ // control characters, as can be the case with memo fields), I use
+ // an empty OUString.
+ OUString sRealSetText = m_pcmbSearchText->get_active_text();
+ if (sRealSetText != sInitialText)
+ m_pcmbSearchText->set_entry_text(OUString());
+ OnSearchTextModified(*m_pcmbSearchText);
+
+ // initial
+ EnableSearchUI(true);
+
+ if ( m_prbSearchForText->get_active() )
+ m_pcmbSearchText->grab_focus();
+
+}
+
+short FmSearchDialog::run()
+{
+ short nRet = weld::GenericDialogController::run();
+ m_pSearchEngine->CancelSearch();
+ return nRet;
+}
+
+IMPL_LINK(FmSearchDialog, OnClickedFieldRadios, weld::Button&, rButton, void)
+{
+ if ((&rButton == m_prbSearchForText.get()) || (&rButton == m_prbSearchForNull.get()) || (&rButton == m_prbSearchForNotNull.get()))
+ {
+ EnableSearchForDependees(true);
+ }
+ else
+ // en- or disable field list box accordingly
+ if (&rButton == m_prbSingleField.get())
+ {
+ m_plbField->set_sensitive(true);
+ m_pSearchEngine->RebuildUsedFields(m_plbField->get_active());
+ }
+ else
+ {
+ m_plbField->set_sensitive(false);
+ m_pSearchEngine->RebuildUsedFields(-1);
+ }
+}
+
+IMPL_LINK_NOARG(FmSearchDialog, OnClickedSearchAgain, weld::Button&, void)
+{
+ if (m_pbClose->get_sensitive())
+ { // the button has the function 'search'
+ OUString strThisRoundText = m_pcmbSearchText->get_active_text();
+ // to history
+ m_pcmbSearchText->remove_text(strThisRoundText);
+ m_pcmbSearchText->insert_text(0, strThisRoundText);
+ // the remove/insert makes sure that a) the OUString does not appear twice and
+ // that b) the last searched strings are at the beginning and limit the list length
+ while (m_pcmbSearchText->get_count() > MAX_HISTORY_ENTRIES)
+ m_pcmbSearchText->remove(m_pcmbSearchText->get_count()-1);
+
+ // take out the 'overflow' hint
+ m_pftHint->set_label(OUString());
+
+ if (m_pcbStartOver->get_active())
+ {
+ m_pcbStartOver->set_active(false);
+ EnableSearchUI(false);
+ if (m_prbSearchForText->get_active())
+ m_pSearchEngine->StartOver(strThisRoundText);
+ else
+ m_pSearchEngine->StartOverSpecial(m_prbSearchForNull->get_active());
+ }
+ else
+ {
+ EnableSearchUI(false);
+ if (m_prbSearchForText->get_active())
+ m_pSearchEngine->SearchNext(strThisRoundText);
+ else
+ m_pSearchEngine->SearchNextSpecial(m_prbSearchForNull->get_active());
+ }
+ }
+ else
+ { // the button has the function 'cancel'
+ // the CancelButton is usually only disabled, when working in a thread or with reschedule
+ m_pSearchEngine->CancelSearch();
+ // the ProgressHandler is called when it's really finished, here it's only a demand
+ }
+}
+
+IMPL_LINK(FmSearchDialog, OnClickedSpecialSettings, weld::Button&, rButton, void)
+{
+ if (m_ppbApproxSettings.get() == &rButton)
+ {
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractSvxSearchSimilarityDialog> pDlg(pFact->CreateSvxSearchSimilarityDialog(m_xDialog.get(), m_pSearchEngine->GetLevRelaxed(), m_pSearchEngine->GetLevOther(),
+ m_pSearchEngine->GetLevShorter(), m_pSearchEngine->GetLevLonger() ));
+ if (pDlg->Execute() == RET_OK)
+ {
+ m_pSearchEngine->SetLevRelaxed( pDlg->IsRelaxed() );
+ m_pSearchEngine->SetLevOther( pDlg->GetOther() );
+ m_pSearchEngine->SetLevShorter(pDlg->GetShorter() );
+ m_pSearchEngine->SetLevLonger( pDlg->GetLonger() );
+ }
+ }
+ else if (m_pSoundsLikeCJKSettings.get() == &rButton)
+ {
+ SfxItemSet aSet( SfxGetpApp()->GetPool() );
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractSvxJSearchOptionsDialog> aDlg(pFact->CreateSvxJSearchOptionsDialog(m_xDialog.get(), aSet, m_pSearchEngine->GetTransliterationFlags() ));
+ aDlg->Execute();
+
+ TransliterationFlags nFlags = aDlg->GetTransliterationFlags();
+ m_pSearchEngine->SetTransliterationFlags(nFlags);
+
+ m_pcbCase->set_active(m_pSearchEngine->GetCaseSensitive());
+ OnCheckBoxToggled( *m_pcbCase );
+ m_pHalfFullFormsCJK->set_active( !m_pSearchEngine->GetIgnoreWidthCJK() );
+ OnCheckBoxToggled( *m_pHalfFullFormsCJK );
+ }
+}
+
+IMPL_LINK_NOARG(FmSearchDialog, OnSearchTextModified, weld::ComboBox&, void)
+{
+ if ((!m_pcmbSearchText->get_active_text().isEmpty()) || !m_prbSearchForText->get_active())
+ m_pbSearchAgain->set_sensitive(true);
+ else
+ m_pbSearchAgain->set_sensitive(false);
+
+ m_pSearchEngine->InvalidatePreviousLoc();
+}
+
+IMPL_LINK_NOARG(FmSearchDialog, OnFocusGrabbed, weld::Widget&, void)
+{
+ m_pcmbSearchText->select_entry_region(0, -1);
+}
+
+IMPL_LINK_NOARG(FmSearchDialog, OnPositionSelected, weld::ComboBox&, void)
+{
+ m_pSearchEngine->SetPosition(m_plbPosition->get_active());
+}
+
+IMPL_LINK_NOARG(FmSearchDialog, OnFieldSelected, weld::ComboBox&, void)
+{
+ m_pSearchEngine->RebuildUsedFields(m_prbAllFields->get_active() ? -1 : m_plbField->get_active());
+ // calls m_pSearchEngine->InvalidatePreviousLoc too
+
+ int nCurrentContext = m_plbForm->get_active();
+ if (nCurrentContext != -1)
+ m_arrContextFields[nCurrentContext] = m_plbField->get_active_text();
+}
+
+IMPL_LINK(FmSearchDialog, OnCheckBoxToggled, weld::ToggleButton&, rBox, void)
+{
+ bool bChecked = rBox.get_active();
+
+ // formatter or case -> pass on to the engine
+ if (&rBox == m_pcbUseFormat.get())
+ m_pSearchEngine->SetFormatterUsing(bChecked);
+ else if (&rBox == m_pcbCase.get())
+ m_pSearchEngine->SetCaseSensitive(bChecked);
+ // direction -> pass on and reset the checkbox-text for StartOver
+ else if (&rBox == m_pcbBackwards.get())
+ {
+ m_pcbStartOver->set_label( CuiResId( bChecked ? RID_STR_FROM_BOTTOM : RID_STR_FROM_TOP ) );
+ m_pSearchEngine->SetDirection(!bChecked);
+ }
+ // similarity-search or regular expression
+ else if ((&rBox == m_pcbApprox.get()) || (&rBox == m_pcbRegular.get()) || (&rBox == m_pcbWildCard.get()))
+ {
+ weld::CheckButton* pBoxes[] = { m_pcbWildCard.get(), m_pcbRegular.get(), m_pcbApprox.get() };
+ for (weld::CheckButton* pBoxe : pBoxes)
+ {
+ if (pBoxe != &rBox)
+ {
+ if (bChecked)
+ pBoxe->set_sensitive(false);
+ else
+ pBoxe->set_sensitive(true);
+ }
+ }
+
+ // pass on to the engine
+ m_pSearchEngine->SetWildcard(m_pcbWildCard->get_sensitive() && m_pcbWildCard->get_active());
+ m_pSearchEngine->SetRegular(m_pcbRegular->get_sensitive() && m_pcbRegular->get_active());
+ m_pSearchEngine->SetLevenshtein(m_pcbApprox->get_sensitive() && m_pcbApprox->get_active());
+ // (disabled boxes have to be passed to the engine as sal_False)
+
+ // adjust the Position-Listbox (which is not allowed during Wildcard-search)
+ if (&rBox == m_pcbWildCard.get())
+ {
+ if (bChecked)
+ {
+ m_pftPosition->set_sensitive(false);
+ m_plbPosition->set_sensitive(false);
+ }
+ else
+ {
+ m_pftPosition->set_sensitive(true);
+ m_plbPosition->set_sensitive(true);
+ }
+ }
+
+ // and the button for similarity-search
+ if (&rBox == m_pcbApprox.get())
+ {
+ if (bChecked)
+ m_ppbApproxSettings->set_sensitive(true);
+ else
+ m_ppbApproxSettings->set_sensitive(false);
+ }
+ }
+ else if (&rBox == m_pHalfFullFormsCJK.get())
+ {
+ // forward to the search engine
+ m_pSearchEngine->SetIgnoreWidthCJK( !bChecked );
+ }
+ else if (&rBox == m_pSoundsLikeCJK.get())
+ {
+ m_pSoundsLikeCJKSettings->set_sensitive(bChecked);
+
+ // two other buttons which depend on this one
+ bool bEnable = ( m_prbSearchForText->get_active()
+ && !m_pSoundsLikeCJK->get_active()
+ )
+ || !SvtCJKOptions().IsJapaneseFindEnabled();
+ m_pcbCase->set_sensitive(bEnable);
+ m_pHalfFullFormsCJK->set_sensitive(bEnable);
+
+ // forward to the search engine
+ m_pSearchEngine->SetTransliteration( bChecked );
+ }
+}
+
+void FmSearchDialog::InitContext(sal_Int16 nContext)
+{
+ FmSearchContext fmscContext;
+ fmscContext.nContext = nContext;
+
+ sal_uInt32 nResult = m_lnkContextSupplier.Call(fmscContext);
+ DBG_ASSERT(nResult > 0, "FmSearchDialog::InitContext : ContextSupplier didn't give me any controls !");
+
+ // put the field names into the respective listbox
+ m_plbField->clear();
+
+ if (!fmscContext.sFieldDisplayNames.isEmpty())
+ {
+ // use the display names if supplied
+ DBG_ASSERT(comphelper::string::getTokenCount(fmscContext.sFieldDisplayNames, ';') == comphelper::string::getTokenCount(fmscContext.strUsedFields, ';'),
+ "FmSearchDialog::InitContext : invalid context description supplied !");
+ sal_Int32 nPos {0};
+ do {
+ m_plbField->append_text(fmscContext.sFieldDisplayNames.getToken(0, ';', nPos));
+ } while (nPos>=0);
+ }
+ else if (!fmscContext.strUsedFields.isEmpty())
+ {
+ // else use the field names
+ sal_Int32 nPos {0};
+ do {
+ m_plbField->append_text(fmscContext.strUsedFields.getToken(0, ';', nPos));
+ } while (nPos>=0);
+ }
+
+ if (nContext < static_cast<sal_Int32>(m_arrContextFields.size()) && !m_arrContextFields[nContext].isEmpty())
+ {
+ m_plbField->set_active_text(m_arrContextFields[nContext]);
+ }
+ else
+ {
+ m_plbField->set_active(0);
+ if (m_prbSingleField->get_active() && (m_plbField->get_count() > 1))
+ m_plbField->grab_focus();
+ }
+
+ m_pSearchEngine->SwitchToContext(fmscContext.xCursor, fmscContext.strUsedFields, fmscContext.arrFields,
+ m_prbAllFields->get_active() ? -1 : 0);
+
+ m_pftRecord->set_label(OUString::number(fmscContext.xCursor->getRow()));
+}
+
+IMPL_LINK(FmSearchDialog, OnContextSelection, weld::ComboBox&, rBox, void)
+{
+ InitContext(rBox.get_active());
+}
+
+void FmSearchDialog::EnableSearchUI(bool bEnable)
+{
+ // the search button has two functions -> adjust its text accordingly
+ OUString sButtonText( bEnable ? m_sSearch : m_sCancel );
+ m_pbSearchAgain->set_label(sButtonText);
+
+ m_prbSearchForText->set_sensitive(bEnable);
+ m_prbSearchForNull->set_sensitive(bEnable);
+ m_prbSearchForNotNull->set_sensitive(bEnable);
+ m_plbForm->set_sensitive(bEnable);
+ m_prbAllFields->set_sensitive(bEnable);
+ m_prbSingleField->set_sensitive(bEnable);
+ m_plbField->set_sensitive(bEnable && m_prbSingleField->get_active());
+ m_pcbBackwards->set_sensitive(bEnable);
+ m_pcbStartOver->set_sensitive(bEnable);
+ m_pbClose->set_sensitive(bEnable);
+ EnableSearchForDependees(bEnable);
+
+ if ( !bEnable )
+ { // this means we're preparing for starting a search
+ // In this case, EnableSearchForDependees disabled the search button
+ // But as we're about to use it for cancelling the search, we really need to enable it, again
+ m_pbSearchAgain->set_sensitive(true);
+ }
+}
+
+void FmSearchDialog::EnableSearchForDependees(bool bEnable)
+{
+ bool bSearchingForText = m_prbSearchForText->get_active();
+ m_pbSearchAgain->set_sensitive(bEnable && (!bSearchingForText || (!m_pcmbSearchText->get_active_text().isEmpty())));
+
+ bEnable = bEnable && bSearchingForText;
+
+ bool bEnableRedundants = !m_pSoundsLikeCJK->get_active() || !SvtCJKOptions().IsJapaneseFindEnabled();
+
+ m_pcmbSearchText->set_sensitive(bEnable);
+ m_pftPosition->set_sensitive(bEnable && !m_pcbWildCard->get_active());
+ m_pcbWildCard->set_sensitive(bEnable && !m_pcbRegular->get_active() && !m_pcbApprox->get_active());
+ m_pcbRegular->set_sensitive(bEnable && !m_pcbWildCard->get_active() && !m_pcbApprox->get_active());
+ m_pcbApprox->set_sensitive(bEnable && !m_pcbWildCard->get_active() && !m_pcbRegular->get_active());
+ m_ppbApproxSettings->set_sensitive(bEnable && m_pcbApprox->get_active());
+ m_pHalfFullFormsCJK->set_sensitive(bEnable && bEnableRedundants);
+ m_pSoundsLikeCJK->set_sensitive(bEnable);
+ m_pSoundsLikeCJKSettings->set_sensitive(bEnable && m_pSoundsLikeCJK->get_active());
+ m_plbPosition->set_sensitive(bEnable && !m_pcbWildCard->get_active());
+ m_pcbUseFormat->set_sensitive(bEnable);
+ m_pcbCase->set_sensitive(bEnable && bEnableRedundants);
+}
+
+void FmSearchDialog::OnFound(const css::uno::Any& aCursorPos, sal_Int16 nFieldPos)
+{
+ FmFoundRecordInformation friInfo;
+ friInfo.nContext = m_plbForm->get_active();
+ // if I don't do a search in a context, this has an invalid value - but then it doesn't matter anyway
+ friInfo.aPosition = aCursorPos;
+ if (m_prbAllFields->get_active())
+ friInfo.nFieldPos = nFieldPos;
+ else
+ friInfo.nFieldPos = m_plbField->get_active();
+ // this of course implies that I have really searched in the field that is selected in the listbox,
+ // which is made sure in RebuildUsedFields
+
+ m_lnkFoundHandler.Call(friInfo);
+
+ m_pcmbSearchText->grab_focus();
+}
+
+IMPL_LINK(FmSearchDialog, OnSearchProgress, const FmSearchProgress*, pProgress, void)
+{
+ SolarMutexGuard aGuard;
+ // make this single method thread-safe (it's an overkill to block the whole application for this,
+ // but we don't have another safety concept at the moment)
+
+ switch (pProgress->aSearchState)
+ {
+ case FmSearchProgress::State::Progress:
+ if (pProgress->bOverflow)
+ {
+ OUString sHint( CuiResId( m_pcbBackwards->get_active() ? RID_STR_OVERFLOW_BACKWARD : RID_STR_OVERFLOW_FORWARD ) );
+ m_pftHint->set_label( sHint );
+ }
+
+ m_pftRecord->set_label(OUString::number(1 + pProgress->nCurrentRecord));
+ break;
+
+ case FmSearchProgress::State::ProgressCounting:
+ m_pftHint->set_label(CuiResId(RID_STR_SEARCH_COUNTING));
+ m_pftRecord->set_label(OUString::number(pProgress->nCurrentRecord));
+ break;
+
+ case FmSearchProgress::State::Successful:
+ OnFound(pProgress->aBookmark, static_cast<sal_Int16>(pProgress->nFieldIndex));
+ EnableSearchUI(true);
+ break;
+
+ case FmSearchProgress::State::Error:
+ case FmSearchProgress::State::NothingFound:
+ {
+ const char* pErrorId = (FmSearchProgress::State::Error == pProgress->aSearchState)
+ ? RID_STR_SEARCH_GENERAL_ERROR
+ : RID_STR_SEARCH_NORECORD;
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Warning, VclButtonsType::Ok, CuiResId(pErrorId)));
+ xBox->run();
+ [[fallthrough]];
+ }
+ case FmSearchProgress::State::Canceled:
+ EnableSearchUI(true);
+ if (m_lnkCanceledNotFoundHdl.IsSet())
+ {
+ FmFoundRecordInformation friInfo;
+ friInfo.nContext = m_plbForm->get_active();
+ // if I don't do a search in a context, this has an invalid value - but then it doesn't matter anyway
+ friInfo.aPosition = pProgress->aBookmark;
+ m_lnkCanceledNotFoundHdl.Call(friInfo);
+ }
+ break;
+ }
+
+ m_pftRecord->set_label(OUString::number(1 + pProgress->nCurrentRecord));
+}
+
+void FmSearchDialog::LoadParams()
+{
+ FmSearchParams aParams(m_pConfig->getParams());
+
+ const OUString* pHistory = aParams.aHistory.getConstArray();
+ const OUString* pHistoryEnd = pHistory + aParams.aHistory.getLength();
+ for (; pHistory != pHistoryEnd; ++pHistory)
+ m_pcmbSearchText->append_text( *pHistory );
+
+ // I do the settings at my UI-elements and then I simply call the respective change-handler,
+ // that way the data is handed on to the SearchEngine and all dependent settings are done
+
+ // current field
+ int nInitialField = m_plbField->find_text( aParams.sSingleSearchField );
+ if (nInitialField == -1)
+ nInitialField = 0;
+ m_plbField->set_active(nInitialField);
+ OnFieldSelected(*m_plbField);
+ // all fields/single field (AFTER selecting the field because OnClickedFieldRadios expects a valid value there)
+ if (aParams.bAllFields)
+ {
+ m_prbSingleField->set_active(false);
+ m_prbAllFields->set_active(true);
+ OnClickedFieldRadios(*m_prbAllFields);
+ // OnClickedFieldRadios also calls to RebuildUsedFields
+ }
+ else
+ {
+ m_prbAllFields->set_active(false);
+ m_prbSingleField->set_active(true);
+ OnClickedFieldRadios(*m_prbSingleField);
+ }
+
+ m_plbPosition->set_active(aParams.nPosition);
+ OnPositionSelected(*m_plbPosition);
+
+ // field formatting/case sensitivity/direction
+ m_pcbUseFormat->set_active(aParams.bUseFormatter);
+ m_pcbCase->set_active( aParams.isCaseSensitive() );
+ m_pcbBackwards->set_active(aParams.bBackwards);
+ OnCheckBoxToggled(*m_pcbUseFormat);
+ OnCheckBoxToggled(*m_pcbCase);
+ OnCheckBoxToggled(*m_pcbBackwards);
+
+ m_pHalfFullFormsCJK->set_active( !aParams.isIgnoreWidthCJK( ) ); // BEWARE: this checkbox has an inverse semantics!
+ m_pSoundsLikeCJK->set_active( aParams.bSoundsLikeCJK );
+ OnCheckBoxToggled(*m_pHalfFullFormsCJK);
+ OnCheckBoxToggled(*m_pSoundsLikeCJK);
+
+ m_pcbWildCard->set_active(false);
+ m_pcbRegular->set_active(false);
+ m_pcbApprox->set_active(false);
+ OnCheckBoxToggled(*m_pcbWildCard);
+ OnCheckBoxToggled(*m_pcbRegular);
+ OnCheckBoxToggled(*m_pcbApprox);
+
+ weld::CheckButton* pToCheck = nullptr;
+ if (aParams.bWildcard)
+ pToCheck = m_pcbWildCard.get();
+ if (aParams.bRegular)
+ pToCheck = m_pcbRegular.get();
+ if (aParams.bApproxSearch)
+ pToCheck = m_pcbApprox.get();
+ if (aParams.bSoundsLikeCJK)
+ pToCheck = m_pSoundsLikeCJK.get();
+ if (pToCheck)
+ {
+ pToCheck->set_active(true);
+ OnCheckBoxToggled(*pToCheck);
+ }
+
+ // set Levenshtein-parameters directly at the SearchEngine
+ m_pSearchEngine->SetLevRelaxed(aParams.bLevRelaxed);
+ m_pSearchEngine->SetLevOther(aParams.nLevOther);
+ m_pSearchEngine->SetLevShorter(aParams.nLevShorter);
+ m_pSearchEngine->SetLevLonger(aParams.nLevLonger);
+
+ m_pSearchEngine->SetTransliterationFlags( aParams.getTransliterationFlags( ) );
+
+ m_prbSearchForText->set_active(false);
+ m_prbSearchForNull->set_active(false);
+ m_prbSearchForNotNull->set_active(false);
+ switch (aParams.nSearchForType)
+ {
+ case 1: m_prbSearchForNull->set_active(true); break;
+ case 2: m_prbSearchForNotNull->set_active(true); break;
+ default: m_prbSearchForText->set_active(true); break;
+ }
+ OnClickedFieldRadios(*m_prbSearchForText);
+}
+
+void FmSearchDialog::SaveParams() const
+{
+ if (!m_pConfig)
+ return;
+
+ FmSearchParams aCurrentSettings;
+
+ int nCount = m_pcmbSearchText->get_count();
+ aCurrentSettings.aHistory.realloc(nCount);
+ OUString* pHistory = aCurrentSettings.aHistory.getArray();
+ for (int i = 0; i < nCount; ++i, ++pHistory)
+ *pHistory = m_pcmbSearchText->get_text(i);
+
+ aCurrentSettings.sSingleSearchField = m_plbField->get_active_text();
+ aCurrentSettings.bAllFields = m_prbAllFields->get_active();
+ aCurrentSettings.nPosition = m_pSearchEngine->GetPosition();
+ aCurrentSettings.bUseFormatter = m_pSearchEngine->GetFormatterUsing();
+ aCurrentSettings.setCaseSensitive ( m_pSearchEngine->GetCaseSensitive() );
+ aCurrentSettings.bBackwards = !m_pSearchEngine->GetDirection();
+ aCurrentSettings.bWildcard = m_pSearchEngine->GetWildcard();
+ aCurrentSettings.bRegular = m_pSearchEngine->GetRegular();
+ aCurrentSettings.bApproxSearch = m_pSearchEngine->GetLevenshtein();
+ aCurrentSettings.bLevRelaxed = m_pSearchEngine->GetLevRelaxed();
+ aCurrentSettings.nLevOther = m_pSearchEngine->GetLevOther();
+ aCurrentSettings.nLevShorter = m_pSearchEngine->GetLevShorter();
+ aCurrentSettings.nLevLonger = m_pSearchEngine->GetLevLonger();
+
+ aCurrentSettings.bSoundsLikeCJK = m_pSearchEngine->GetTransliteration();
+ aCurrentSettings.setTransliterationFlags ( m_pSearchEngine->GetTransliterationFlags() );
+
+ if (m_prbSearchForNull->get_active())
+ aCurrentSettings.nSearchForType = 1;
+ else if (m_prbSearchForNotNull->get_active())
+ aCurrentSettings.nSearchForType = 2;
+ else
+ aCurrentSettings.nSearchForType = 0;
+
+ m_pConfig->setParams( aCurrentSettings );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/dialogs/cuigaldlg.cxx b/cui/source/dialogs/cuigaldlg.cxx
new file mode 100644
index 000000000..de0b0c166
--- /dev/null
+++ b/cui/source/dialogs/cuigaldlg.cxx
@@ -0,0 +1,1011 @@
+/* -*- 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 <sal/config.h>
+
+#include <algorithm>
+#include <cassert>
+
+#include <vcl/errinf.hxx>
+#include <ucbhelper/content.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <avmedia/mediawindow.hxx>
+#include <unotools/pathoptions.hxx>
+#include <sfx2/opengrf.hxx>
+#include <vcl/graphicfilter.hxx>
+#include <svx/gallery1.hxx>
+#include <svx/galtheme.hxx>
+#include <cuigaldlg.hxx>
+#include <bitmaps.hlst>
+#include <unotools/localedatawrapper.hxx>
+#include <unotools/syslocale.hxx>
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <comphelper/processfactory.hxx>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/ucb/ContentCreationException.hpp>
+#include <com/sun/star/ucb/XContentAccess.hpp>
+#include <com/sun/star/ui/dialogs/FolderPicker.hpp>
+#include <com/sun/star/ui/dialogs/XAsynchronousExecutableDialog.hpp>
+#include <dialmgr.hxx>
+#include <strings.hrc>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+
+using namespace ::ucbhelper;
+using namespace ::cppu;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::ucb;
+using namespace ::com::sun::star::ui::dialogs;
+using namespace ::com::sun::star::uno;
+
+
+SearchThread::SearchThread(SearchProgress* pProgress,
+ TPGalleryThemeProperties* pBrowser,
+ const INetURLObject& rStartURL)
+ : Thread("cuiSearchThread")
+ , mpProgress(pProgress)
+ , mpBrowser(pBrowser)
+ , maStartURL(rStartURL)
+{
+}
+
+SearchThread::~SearchThread()
+{
+}
+
+void SearchThread::execute()
+{
+ const OUString aFileType(mpBrowser->m_xCbbFileType->get_active_text());
+
+ if (!aFileType.isEmpty())
+ {
+ const int nFileNumber = mpBrowser->m_xCbbFileType->find_text(aFileType);
+ sal_Int32 nBeginFormat, nEndFormat;
+ std::vector< OUString > aFormats;
+
+ if( !nFileNumber || nFileNumber == -1)
+ {
+ nBeginFormat = 1;
+ nEndFormat = mpBrowser->m_xCbbFileType->get_count() - 1;
+ }
+ else
+ nBeginFormat = nEndFormat = nFileNumber;
+
+ for (sal_Int32 i = nBeginFormat; i <= nEndFormat; ++i)
+ aFormats.push_back( mpBrowser->aFilterEntryList[ i ]->aFilterName.toAsciiLowerCase() );
+
+ ImplSearch( maStartURL, aFormats, mpBrowser->bSearchRecursive );
+ }
+
+ Application::PostUserEvent(LINK(mpProgress, SearchProgress, CleanUpHdl));
+}
+
+
+void SearchThread::ImplSearch( const INetURLObject& rStartURL,
+ const std::vector< OUString >& rFormats,
+ bool bRecursive )
+{
+ {
+ SolarMutexGuard aGuard;
+
+ mpProgress->SetDirectory( rStartURL );
+ }
+
+ try
+ {
+ css::uno::Reference< XCommandEnvironment > xEnv;
+ Content aCnt( rStartURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), xEnv, comphelper::getProcessComponentContext() );
+ Sequence< OUString > aProps( 2 );
+
+ aProps.getArray()[ 0 ] = "IsFolder";
+ aProps.getArray()[ 1 ] = "IsDocument";
+ css::uno::Reference< XResultSet > xResultSet(
+ aCnt.createCursor( aProps ) );
+
+ if( xResultSet.is() )
+ {
+ css::uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY_THROW );
+ css::uno::Reference< XRow > xRow( xResultSet, UNO_QUERY_THROW );
+
+ while( xResultSet->next() && schedule() )
+ {
+ INetURLObject aFoundURL( xContentAccess->queryContentIdentifierString() );
+ DBG_ASSERT( aFoundURL.GetProtocol() != INetProtocol::NotValid, "invalid URL" );
+
+ bool bFolder = xRow->getBoolean( 1 ); // property "IsFolder"
+ if ( xRow->wasNull() )
+ bFolder = false;
+
+ if( bRecursive && bFolder )
+ ImplSearch( aFoundURL, rFormats, true );
+ else
+ {
+ bool bDocument = xRow->getBoolean( 2 ); // property "IsDocument"
+ if ( xRow->wasNull() )
+ bDocument = false;
+
+ if( bDocument )
+ {
+ GraphicDescriptor aDesc( aFoundURL );
+
+ if( ( aDesc.Detect() &&
+ std::find( rFormats.begin(),
+ rFormats.end(),
+ GraphicDescriptor::GetImportFormatShortName(
+ aDesc.GetFileFormat() ).toAsciiLowerCase() )
+ != rFormats.end() ) ||
+ std::find( rFormats.begin(),
+ rFormats.end(),
+ aFoundURL.GetFileExtension().toAsciiLowerCase())
+ != rFormats.end() )
+ {
+ SolarMutexGuard aGuard;
+
+ mpBrowser->aFoundList.push_back(
+ aFoundURL.GetMainURL( INetURLObject::DecodeMechanism::NONE )
+ );
+ mpBrowser->m_xLbxFound->insert_text(
+ mpBrowser->aFoundList.size() - 1,
+ GetReducedString(aFoundURL, 50));
+ }
+ }
+ }
+ }
+ }
+ }
+ catch (const ContentCreationException&)
+ {
+ }
+ catch (const css::uno::RuntimeException&)
+ {
+ }
+ catch (const css::uno::Exception&)
+ {
+ }
+}
+
+SearchProgress::SearchProgress(weld::Window* pParent, TPGalleryThemeProperties* pTabPage, const INetURLObject& rStartURL)
+ : GenericDialogController(pParent, "cui/ui/gallerysearchprogress.ui", "GallerySearchProgress")
+ , startUrl_(rStartURL)
+ , m_pTabPage(pTabPage)
+ , m_xFtSearchDir(m_xBuilder->weld_label("dir"))
+ , m_xFtSearchType(m_xBuilder->weld_label("file"))
+ , m_xBtnCancel(m_xBuilder->weld_button("cancel"))
+{
+ m_xFtSearchType->set_size_request(m_xFtSearchType->get_preferred_size().Width(), -1);
+ m_xBtnCancel->connect_clicked(LINK(this, SearchProgress, ClickCancelBtn));
+}
+
+SearchProgress::~SearchProgress()
+{
+}
+
+IMPL_LINK_NOARG(SearchProgress, ClickCancelBtn, weld::Button&, void)
+{
+ if (m_aSearchThread.is())
+ m_aSearchThread->terminate();
+}
+
+IMPL_LINK_NOARG(SearchProgress, CleanUpHdl, void*, void)
+{
+ if (m_aSearchThread.is())
+ m_aSearchThread->join();
+
+ m_xDialog->response(RET_OK);
+}
+
+void SearchProgress::LaunchThread()
+{
+ assert(!m_aSearchThread.is());
+ m_aSearchThread = new SearchThread(this, m_pTabPage, startUrl_);
+ m_aSearchThread->launch();
+}
+
+TakeThread::TakeThread(
+ TakeProgress* pProgress,
+ TPGalleryThemeProperties* pBrowser,
+ TokenList_impl& rTakenList
+) :
+ Thread ( "cuiTakeThread" ),
+ mpProgress ( pProgress ),
+ mpBrowser ( pBrowser ),
+ mrTakenList ( rTakenList )
+{
+}
+
+
+TakeThread::~TakeThread()
+{
+}
+
+void TakeThread::execute()
+{
+ sal_Int32 nEntries;
+ GalleryTheme* pThm = mpBrowser->GetXChgData()->pTheme;
+ std::unique_ptr<GalleryProgress> pStatusProgress;
+
+ std::vector<int> aSelectedRows;
+
+ {
+ SolarMutexGuard aGuard;
+ pStatusProgress.reset(new GalleryProgress);
+ if (mpBrowser->bTakeAll)
+ nEntries = mpBrowser->m_xLbxFound->n_children();
+ else
+ {
+ aSelectedRows = mpBrowser->m_xLbxFound->get_selected_rows();
+ nEntries = aSelectedRows.size();
+ }
+ pThm->LockBroadcaster();
+ }
+
+ for( sal_Int32 i = 0; i < nEntries && schedule(); ++i )
+ {
+ const sal_Int32 nPos = mpBrowser->bTakeAll ? i : aSelectedRows[i];
+ const INetURLObject aURL( mpBrowser->aFoundList[ nPos ]);
+
+ mrTakenList.push_back( nPos );
+
+ {
+ SolarMutexGuard aGuard;
+
+ mpProgress->SetFile( aURL );
+ pStatusProgress->Update( i, nEntries - 1 );
+ pThm->InsertURL( aURL );
+ }
+ }
+
+ {
+ SolarMutexGuard aGuard;
+
+ pThm->UnlockBroadcaster();
+ pStatusProgress.reset();
+ }
+
+ Application::PostUserEvent(LINK(mpProgress, TakeProgress, CleanUpHdl));
+}
+
+TakeProgress::TakeProgress(weld::Window* pParent, TPGalleryThemeProperties* pTabPage)
+ : GenericDialogController(pParent, "cui/ui/galleryapplyprogress.ui",
+ "GalleryApplyProgress")
+ , m_pParent(pParent)
+ , m_pTabPage(pTabPage)
+ , m_xFtTakeFile(m_xBuilder->weld_label("file"))
+ , m_xBtnCancel(m_xBuilder->weld_button("cancel"))
+{
+ m_xBtnCancel->connect_clicked(LINK(this, TakeProgress, ClickCancelBtn));
+}
+
+TakeProgress::~TakeProgress()
+{
+}
+
+IMPL_LINK_NOARG(TakeProgress, ClickCancelBtn, weld::Button&, void)
+{
+ if (maTakeThread.is())
+ maTakeThread->terminate();
+}
+
+
+IMPL_LINK_NOARG(TakeProgress, CleanUpHdl, void*, void)
+{
+ if (maTakeThread.is())
+ maTakeThread->join();
+
+ std::vector<bool, std::allocator<bool> > aRemoveEntries(m_pTabPage->aFoundList.size(), false);
+ std::vector< OUString > aRemainingVector;
+ sal_uInt32 i, nCount;
+
+ std::unique_ptr<weld::WaitObject> xWait(new weld::WaitObject(m_pParent));
+
+ m_pTabPage->m_xLbxFound->select(-1);
+ m_pTabPage->m_xLbxFound->freeze();
+
+ // mark all taken positions in aRemoveEntries
+ for( i = 0, nCount = maTakenList.size(); i < nCount; ++i )
+ aRemoveEntries[ maTakenList[ i ] ] = true;
+ maTakenList.clear();
+
+ // refill found list
+ for( i = 0, nCount = aRemoveEntries.size(); i < nCount; ++i )
+ if( !aRemoveEntries[ i ] )
+ aRemainingVector.push_back( m_pTabPage->aFoundList[i] );
+
+ m_pTabPage->aFoundList.clear();
+
+ for( i = 0, nCount = aRemainingVector.size(); i < nCount; ++i )
+ m_pTabPage->aFoundList.push_back( aRemainingVector[ i ] );
+
+ aRemainingVector.clear();
+
+ // refill list box
+ for( i = 0, nCount = aRemoveEntries.size(); i < nCount; ++i )
+ if( !aRemoveEntries[ i ] )
+ aRemainingVector.push_back(m_pTabPage->m_xLbxFound->get_text(i));
+
+ m_pTabPage->m_xLbxFound->clear();
+
+ for( i = 0, nCount = aRemainingVector.size(); i < nCount; ++i )
+ m_pTabPage->m_xLbxFound->append_text(aRemainingVector[i]);
+
+ aRemainingVector.clear();
+
+ m_pTabPage->m_xLbxFound->thaw();
+ m_pTabPage->SelectFoundHdl( *m_pTabPage->m_xLbxFound );
+
+ xWait.reset();
+
+ m_xDialog->response(RET_OK);
+}
+
+void TakeProgress::LaunchThread()
+{
+ assert(!maTakeThread.is());
+ maTakeThread = new TakeThread(this, m_pTabPage, maTakenList);
+ maTakeThread->launch();
+}
+
+ActualizeProgress::ActualizeProgress(weld::Widget* pWindow, GalleryTheme* pThm)
+ : GenericDialogController(pWindow, "cui/ui/galleryupdateprogress.ui",
+ "GalleryUpdateProgress")
+ , pIdle(nullptr)
+ , pTheme(pThm)
+ , m_xFtActualizeFile(m_xBuilder->weld_label("file"))
+ , m_xBtnCancel(m_xBuilder->weld_button("cancel"))
+{
+ m_xBtnCancel->connect_clicked(LINK(this, ActualizeProgress, ClickCancelBtn));
+}
+
+ActualizeProgress::~ActualizeProgress()
+{
+}
+
+short ActualizeProgress::run()
+{
+ pIdle = new Idle("ActualizeProgressTimeout");
+ pIdle->SetInvokeHandler( LINK( this, ActualizeProgress, TimeoutHdl ) );
+ pIdle->SetPriority( TaskPriority::LOWEST );
+ pIdle->Start();
+
+ return GenericDialogController::run();
+}
+
+IMPL_LINK_NOARG(ActualizeProgress, ClickCancelBtn, weld::Button&, void)
+{
+ pTheme->AbortActualize();
+ m_xDialog->response(RET_OK);
+}
+
+IMPL_LINK( ActualizeProgress, TimeoutHdl, Timer*, _pTimer, void)
+{
+ if (_pTimer)
+ {
+ _pTimer->Stop();
+ delete _pTimer;
+ }
+
+ pTheme->Actualize(LINK(this, ActualizeProgress, ActualizeHdl), &aStatusProgress);
+ ClickCancelBtn(*m_xBtnCancel);
+}
+
+IMPL_LINK( ActualizeProgress, ActualizeHdl, const INetURLObject&, rURL, void )
+{
+ Application::Reschedule(true);
+ m_xFtActualizeFile->set_label(GetReducedString(rURL, 30));
+}
+
+TitleDialog::TitleDialog(weld::Widget* pParent, const OUString& rOldTitle)
+ : GenericDialogController(pParent, "cui/ui/gallerytitledialog.ui", "GalleryTitleDialog")
+ , m_xEdit(m_xBuilder->weld_entry("entry"))
+{
+ m_xEdit->set_text(rOldTitle);
+ m_xEdit->grab_focus();
+}
+
+TitleDialog::~TitleDialog()
+{
+}
+
+GalleryIdDialog::GalleryIdDialog(weld::Widget* pParent, GalleryTheme* _pThm)
+ : GenericDialogController(pParent, "cui/ui/gallerythemeiddialog.ui", "GalleryThemeIDDialog")
+ , m_pThm(_pThm)
+ , m_xBtnOk(m_xBuilder->weld_button("ok"))
+ , m_xLbResName(m_xBuilder->weld_combo_box("entry"))
+{
+ m_xLbResName->append_text("!!! No Id !!!");
+
+ GalleryTheme::InsertAllThemes(*m_xLbResName);
+
+ m_xLbResName->set_active(m_pThm->GetId());
+ m_xLbResName->grab_focus();
+
+ m_xBtnOk->connect_clicked(LINK(this, GalleryIdDialog, ClickOkHdl));
+}
+
+GalleryIdDialog::~GalleryIdDialog()
+{
+}
+
+IMPL_LINK_NOARG(GalleryIdDialog, ClickOkHdl, weld::Button&, void)
+{
+ Gallery* pGal = m_pThm->GetParent();
+ const sal_uInt32 nId = GetId();
+ bool bDifferentThemeExists = false;
+
+ for( size_t i = 0, nCount = pGal->GetThemeCount(); i < nCount && !bDifferentThemeExists; i++ )
+ {
+ const GalleryThemeEntry* pInfo = pGal->GetThemeInfo( i );
+
+ if ((pInfo->GetId() == nId) && (pInfo->GetThemeName() != m_pThm->GetName()))
+ {
+ OUString aStr = CuiResId( RID_SVXSTR_GALLERY_ID_EXISTS ) +
+ " (" + pInfo->GetThemeName() + ")";
+
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ aStr));
+ xInfoBox->run();
+ m_xLbResName->grab_focus();
+ bDifferentThemeExists = true;
+ }
+ }
+
+ if (!bDifferentThemeExists)
+ m_xDialog->response(RET_OK);
+}
+
+GalleryThemeProperties::GalleryThemeProperties(weld::Widget* pParent,
+ ExchangeData* _pData, SfxItemSet const * pItemSet)
+ : SfxTabDialogController(pParent, "cui/ui/gallerythemedialog.ui",
+ "GalleryThemeDialog", pItemSet)
+ , pData(_pData)
+{
+ AddTabPage("general", TPGalleryThemeGeneral::Create, nullptr);
+ AddTabPage("files", TPGalleryThemeProperties::Create, nullptr);
+ if (pData->pTheme->IsReadOnly())
+ RemoveTabPage("files");
+
+ OUString aText = m_xDialog->get_title().replaceFirst( "%1", pData->pTheme->GetName() );
+
+ if (pData->pTheme->IsReadOnly())
+ aText += " " + CuiResId( RID_SVXSTR_GALLERY_READONLY );
+
+ m_xDialog->set_title(aText);
+}
+
+void GalleryThemeProperties::PageCreated(const OString& rId, SfxTabPage &rPage)
+{
+ if (rId == "general")
+ static_cast<TPGalleryThemeGeneral&>( rPage ).SetXChgData( pData );
+ else
+ static_cast<TPGalleryThemeProperties&>( rPage ).SetXChgData( pData );
+}
+
+TPGalleryThemeGeneral::TPGalleryThemeGeneral(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet)
+ : SfxTabPage(pPage, pController, "cui/ui/gallerygeneralpage.ui", "GalleryGeneralPage", &rSet)
+ , pData(nullptr)
+ , m_xFiMSImage(m_xBuilder->weld_image("image"))
+ , m_xEdtMSName(m_xBuilder->weld_entry("name"))
+ , m_xFtMSShowType(m_xBuilder->weld_label("type"))
+ , m_xFtMSShowPath(m_xBuilder->weld_label("location"))
+ , m_xFtMSShowContent(m_xBuilder->weld_label("contents"))
+ , m_xFtMSShowChangeDate(m_xBuilder->weld_label("modified"))
+{
+}
+
+void TPGalleryThemeGeneral::SetXChgData( ExchangeData* _pData )
+{
+ pData = _pData;
+
+ GalleryTheme* pThm = pData->pTheme;
+ OUString aOutStr( OUString::number(pThm->GetObjectCount()) );
+ OUString aObjStr( CuiResId( RID_SVXSTR_GALLERYPROPS_OBJECT ) );
+ OUString aAccess;
+ OUString aType( SvxResId( RID_SVXSTR_GALLERYPROPS_GALTHEME ) );
+ bool bReadOnly = pThm->IsReadOnly();
+
+ m_xEdtMSName->set_text(pThm->GetName());
+ m_xEdtMSName->set_editable(!bReadOnly);
+ m_xEdtMSName->set_sensitive(!bReadOnly);
+
+ if( pThm->IsReadOnly() )
+ aType += CuiResId( RID_SVXSTR_GALLERY_READONLY );
+
+ m_xFtMSShowType->set_label(aType);
+ m_xFtMSShowPath->set_label(pThm->GetSdgURL().GetMainURL(INetURLObject::DecodeMechanism::Unambiguous));
+
+ // singular or plural?
+ if ( 1 == pThm->GetObjectCount() )
+ aObjStr = aObjStr.getToken( 0, ';' );
+ else
+ aObjStr = aObjStr.getToken( 1, ';' );
+
+ aOutStr += " " + aObjStr;
+
+ m_xFtMSShowContent->set_label(aOutStr);
+
+ // get locale wrapper (singleton)
+ const SvtSysLocale aSysLocale;
+ const LocaleDataWrapper& aLocaleData = aSysLocale.GetLocaleData();
+
+ // ChangeDate/Time
+ aAccess = aLocaleData.getDate( pData->aThemeChangeDate ) + ", " + aLocaleData.getTime( pData->aThemeChangeTime );
+ m_xFtMSShowChangeDate->set_label(aAccess);
+
+ // set image
+ OUString sId;
+
+ if( pThm->IsReadOnly() )
+ sId = RID_SVXBMP_THEME_READONLY_BIG;
+ else if( pThm->IsDefault() )
+ sId = RID_SVXBMP_THEME_DEFAULT_BIG;
+ else
+ sId = RID_SVXBMP_THEME_NORMAL_BIG;
+
+ m_xFiMSImage->set_from_icon_name(sId);
+}
+
+bool TPGalleryThemeGeneral::FillItemSet( SfxItemSet* /*rSet*/ )
+{
+ pData->aEditedTitle = m_xEdtMSName->get_text();
+ return true;
+}
+
+std::unique_ptr<SfxTabPage> TPGalleryThemeGeneral::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet)
+{
+ return std::make_unique<TPGalleryThemeGeneral>(pPage, pController, *rSet);
+}
+
+TPGalleryThemeProperties::TPGalleryThemeProperties(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet)
+ : SfxTabPage(pPage, pController, "cui/ui/galleryfilespage.ui", "GalleryFilesPage", &rSet)
+ , pData(nullptr)
+ , bEntriesFound(false)
+ , bInputAllowed(true)
+ , bTakeAll(false)
+ , bSearchRecursive(false)
+ , xDialogListener(new ::svt::DialogClosedListener())
+ , m_xCbbFileType(m_xBuilder->weld_combo_box("filetype"))
+ , m_xLbxFound(m_xBuilder->weld_tree_view("files"))
+ , m_xBtnSearch(m_xBuilder->weld_button("findfiles"))
+ , m_xBtnTake(m_xBuilder->weld_button("add"))
+ , m_xBtnTakeAll(m_xBuilder->weld_button("addall"))
+ , m_xCbxPreview(m_xBuilder->weld_check_button("preview"))
+ , m_xWndPreview(new weld::CustomWeld(*m_xBuilder, "image", m_aWndPreview))
+{
+ m_xLbxFound->set_size_request(m_xLbxFound->get_approximate_digit_width() * 35,
+ m_xLbxFound->get_height_rows(15));
+ m_xLbxFound->set_selection_mode(SelectionMode::Multiple);
+ xDialogListener->SetDialogClosedLink( LINK( this, TPGalleryThemeProperties, DialogClosedHdl ) );
+}
+
+void TPGalleryThemeProperties::SetXChgData( ExchangeData* _pData )
+{
+ pData = _pData;
+
+ aPreviewTimer.SetInvokeHandler( LINK( this, TPGalleryThemeProperties, PreviewTimerHdl ) );
+ aPreviewTimer.SetTimeout( 500 );
+ m_xBtnSearch->connect_clicked(LINK(this, TPGalleryThemeProperties, ClickSearchHdl));
+ m_xBtnTake->connect_clicked(LINK(this, TPGalleryThemeProperties, ClickTakeHdl));
+ m_xBtnTakeAll->connect_clicked(LINK(this, TPGalleryThemeProperties, ClickTakeAllHdl));
+ m_xCbxPreview->connect_toggled(LINK(this, TPGalleryThemeProperties, ClickPreviewHdl));
+ m_xCbbFileType->connect_changed(LINK(this, TPGalleryThemeProperties, SelectFileTypeHdl));
+ m_xLbxFound->connect_row_activated(LINK(this, TPGalleryThemeProperties, DClickFoundHdl));
+ m_xLbxFound->connect_changed(LINK(this, TPGalleryThemeProperties, SelectFoundHdl));
+ m_xLbxFound->append_text(CuiResId(RID_SVXSTR_GALLERY_NOFILES));
+ m_xLbxFound->show();
+
+ FillFilterList();
+
+ m_xBtnTake->set_sensitive(true);
+ m_xBtnTakeAll->set_sensitive(false);
+ m_xCbxPreview->set_sensitive(false);
+}
+
+void TPGalleryThemeProperties::StartSearchFiles( const OUString& _rFolderURL, short _nDlgResult )
+{
+ if ( RET_OK == _nDlgResult )
+ {
+ aURL = INetURLObject( _rFolderURL );
+ bSearchRecursive = true; // UI choice no longer possible, windows file picker allows no user controls
+ SearchFiles();
+ }
+}
+
+TPGalleryThemeProperties::~TPGalleryThemeProperties()
+{
+ xMediaPlayer.clear();
+ xDialogListener.clear();
+ aFilterEntryList.clear();
+}
+
+std::unique_ptr<SfxTabPage> TPGalleryThemeProperties::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet)
+{
+ return std::make_unique<TPGalleryThemeProperties>(pPage, pController, *rSet);
+}
+
+OUString TPGalleryThemeProperties::addExtension( const OUString& _rDisplayText, const OUString& _rExtension )
+{
+ OUString sRet = _rDisplayText;
+ if ( sRet.indexOf( "(*.*)" ) == -1 )
+ {
+ sRet += " (" + _rExtension + ")";
+ }
+ return sRet;
+}
+
+void TPGalleryThemeProperties::FillFilterList()
+{
+ GraphicFilter &rFilter = GraphicFilter::GetGraphicFilter();
+ OUString aExt;
+ OUString aName;
+ sal_uInt16 i, nKeyCount;
+
+ // graphic filters
+ for( i = 0, nKeyCount = rFilter.GetImportFormatCount(); i < nKeyCount; i++ )
+ {
+ aExt = rFilter.GetImportFormatShortName( i );
+ aName = rFilter.GetImportFormatName( i );
+ size_t entryIndex = 0;
+ FilterEntry* pTestEntry = aFilterEntryList.empty() ? nullptr : aFilterEntryList[ entryIndex ].get();
+ bool bInList = false;
+
+ OUString aExtensions;
+ int j = 0;
+ OUString sWildcard;
+ while( true )
+ {
+ sWildcard = rFilter.GetImportWildcard( i, j++ );
+ if ( sWildcard.isEmpty() )
+ break;
+ if ( aExtensions.indexOf( sWildcard ) == -1 )
+ {
+ if ( !aExtensions.isEmpty() )
+ aExtensions += ";";
+ aExtensions += sWildcard;
+ }
+ }
+ aName = addExtension( aName, aExtensions );
+
+ while( pTestEntry )
+ {
+ if ( pTestEntry->aFilterName == aExt )
+ {
+ bInList = true;
+ break;
+ }
+ pTestEntry = ( ++entryIndex < aFilterEntryList.size() )
+ ? aFilterEntryList[ entryIndex ].get() : nullptr;
+ }
+ if ( !bInList )
+ {
+ std::unique_ptr<FilterEntry> pFilterEntry(new FilterEntry);
+ pFilterEntry->aFilterName = aExt;
+ m_xCbbFileType->append_text(aName);
+ aFilterEntryList.push_back(std::move(pFilterEntry));
+ }
+ }
+
+#if HAVE_FEATURE_AVMEDIA
+ // media filters
+ static const char aWildcard[] = "*.";
+ ::avmedia::FilterNameVector aFilters= ::avmedia::MediaWindow::getMediaFilters();
+
+ for(const std::pair<OUString,OUString> & aFilter : aFilters)
+ {
+ for( sal_Int32 nIndex = 0; nIndex >= 0; )
+ {
+ OUString aFilterWildcard( aWildcard );
+
+ std::unique_ptr<FilterEntry> pFilterEntry(new FilterEntry);
+ pFilterEntry->aFilterName = aFilter.second.getToken( 0, ';', nIndex );
+ aFilterWildcard += pFilterEntry->aFilterName;
+ m_xCbbFileType->append_text(addExtension(aFilter.first, aFilterWildcard));
+ aFilterEntryList.push_back( std::move(pFilterEntry) );
+ }
+ }
+#endif
+
+ // 'All' filters
+ OUString aExtensions;
+
+ // graphic filters
+ for ( i = 0; i < nKeyCount; ++i )
+ {
+ int j = 0;
+ OUString sWildcard;
+ while( true )
+ {
+ sWildcard = rFilter.GetImportWildcard( i, j++ );
+ if ( sWildcard.isEmpty() )
+ break;
+ if ( aExtensions.indexOf( sWildcard ) == -1 )
+ {
+ if ( !aExtensions.isEmpty() )
+ aExtensions += ";";
+
+ aExtensions += sWildcard;
+ }
+ }
+ }
+
+#if HAVE_FEATURE_AVMEDIA
+ // media filters
+ for(const std::pair<OUString,OUString> & aFilter : aFilters)
+ {
+ for( sal_Int32 nIndex = 0; nIndex >= 0; )
+ {
+ if ( !aExtensions.isEmpty() )
+ aExtensions += ";";
+ aExtensions += aWildcard + aFilter.second.getToken( 0, ';', nIndex );
+ }
+ }
+#endif
+
+#if defined(_WIN32)
+ if (aExtensions.getLength() > 240)
+ aExtensions = "*.*";
+#endif
+
+ std::unique_ptr<FilterEntry> pFilterEntry(new FilterEntry);
+ pFilterEntry->aFilterName = CuiResId(RID_SVXSTR_GALLERY_ALLFILES);
+ pFilterEntry->aFilterName = addExtension(pFilterEntry->aFilterName, aExtensions);
+ m_xCbbFileType->insert_text(0, pFilterEntry->aFilterName);
+ m_xCbbFileType->set_active(0);
+ aFilterEntryList.insert(aFilterEntryList.begin(), std::move(pFilterEntry));
+}
+
+IMPL_LINK_NOARG(TPGalleryThemeProperties, SelectFileTypeHdl, weld::ComboBox&, void)
+{
+ OUString aText(m_xCbbFileType->get_active_text());
+
+ if( bInputAllowed && ( aLastFilterName != aText ) )
+ {
+ aLastFilterName = aText;
+
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(GetFrameWeld(), "cui/ui/queryupdategalleryfilelistdialog.ui"));
+ std::unique_ptr<weld::MessageDialog> xQuery(xBuilder->weld_message_dialog("QueryUpdateFileListDialog"));
+ if (xQuery->run() == RET_YES)
+ SearchFiles();
+ }
+}
+
+void TPGalleryThemeProperties::SearchFiles()
+{
+ auto xProgress = std::make_shared<SearchProgress>(GetFrameWeld(), this, aURL);
+
+ aFoundList.clear();
+ m_xLbxFound->clear();
+
+ xProgress->SetFileType( m_xCbbFileType->get_active_text() );
+ xProgress->SetDirectory( INetURLObject() );
+
+ xProgress->LaunchThread();
+ weld::DialogController::runAsync(xProgress, [this](sal_Int32 nResult) {
+ EndSearchProgressHdl(nResult);
+ });
+}
+
+IMPL_LINK_NOARG(TPGalleryThemeProperties, ClickSearchHdl, weld::Button&, void)
+{
+ if( !bInputAllowed )
+ return;
+
+ try
+ {
+ // setup folder picker
+ css::uno::Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
+ xFolderPicker = FolderPicker::create(xContext);
+
+ OUString aDlgPathName( SvtPathOptions().GetGraphicPath() );
+ xFolderPicker->setDisplayDirectory(aDlgPathName);
+
+ aPreviewTimer.Stop();
+
+ css::uno::Reference< XAsynchronousExecutableDialog > xAsyncDlg( xFolderPicker, UNO_QUERY );
+ if ( xAsyncDlg.is() )
+ xAsyncDlg->startExecuteModal( xDialogListener.get() );
+ else
+ {
+ if( xFolderPicker->execute() == RET_OK )
+ {
+ aURL = INetURLObject( xFolderPicker->getDirectory() );
+ bSearchRecursive = true; // UI choice no longer possible, windows file picker allows no user controls
+ SearchFiles();
+ }
+ }
+ }
+ catch (const IllegalArgumentException&)
+ {
+ OSL_FAIL( "Folder picker failed with illegal arguments" );
+ }
+}
+
+void TPGalleryThemeProperties::TakeFiles()
+{
+ if (m_xLbxFound->count_selected_rows() || (bTakeAll && bEntriesFound))
+ {
+ auto xTakeProgress = std::make_shared<TakeProgress>(GetFrameWeld(), this);
+ xTakeProgress->LaunchThread();
+ weld::DialogController::runAsync(xTakeProgress, [=](sal_Int32 /*nResult*/) {
+ /* no postprocessing needed, pTakeProgress
+ will be disposed in TakeProgress::CleanupHdl */
+ });
+
+ }
+}
+
+IMPL_LINK_NOARG(TPGalleryThemeProperties, ClickPreviewHdl, weld::ToggleButton&, void)
+{
+ if ( !bInputAllowed )
+ return;
+
+ aPreviewTimer.Stop();
+ aPreviewString.clear();
+
+ if (!m_xCbxPreview->get_active())
+ {
+ xMediaPlayer.clear();
+ m_aWndPreview.SetGraphic(Graphic());
+ m_aWndPreview.Invalidate();
+ }
+ else
+ DoPreview();
+}
+
+void TPGalleryThemeProperties::DoPreview()
+{
+ int nIndex = m_xLbxFound->get_selected_index();
+ OUString aString(m_xLbxFound->get_text(nIndex));
+
+ if (aString == aPreviewString)
+ return;
+
+ INetURLObject _aURL(aFoundList[nIndex]);
+ bInputAllowed = false;
+
+ if (!m_aWndPreview.SetGraphic(_aURL))
+ {
+ weld::WaitObject aWaitObject(GetFrameWeld());
+ ErrorHandler::HandleError(ERRCODE_IO_NOTEXISTSPATH, GetFrameWeld());
+ }
+#if HAVE_FEATURE_AVMEDIA
+ else if( ::avmedia::MediaWindow::isMediaURL( _aURL.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous ), "" ) )
+ {
+ xMediaPlayer = ::avmedia::MediaWindow::createPlayer( _aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), "" );
+ if( xMediaPlayer.is() )
+ xMediaPlayer->start();
+ }
+#endif
+ bInputAllowed = true;
+ aPreviewString = aString;
+}
+
+IMPL_LINK_NOARG(TPGalleryThemeProperties, ClickTakeHdl, weld::Button&, void)
+{
+ if( !bInputAllowed )
+ return;
+
+ aPreviewTimer.Stop();
+
+ if (!m_xLbxFound->count_selected_rows() || !bEntriesFound)
+ {
+ SvxOpenGraphicDialog aDlg(CuiResId(RID_SVXSTR_KEY_GALLERY_DIR), GetFrameWeld());
+ aDlg.EnableLink(false);
+ aDlg.AsLink(false);
+
+ if( !aDlg.Execute() )
+ pData->pTheme->InsertURL( INetURLObject( aDlg.GetPath() ) );
+ }
+ else
+ {
+ bTakeAll = false;
+ TakeFiles();
+ }
+}
+
+IMPL_LINK_NOARG(TPGalleryThemeProperties, ClickTakeAllHdl, weld::Button&, void)
+{
+ if( bInputAllowed )
+ {
+ aPreviewTimer.Stop();
+ bTakeAll = true;
+ TakeFiles();
+ }
+}
+
+IMPL_LINK_NOARG(TPGalleryThemeProperties, SelectFoundHdl, weld::TreeView&, void)
+{
+ if (!bInputAllowed)
+ return;
+
+ bool bPreviewPossible = false;
+
+ aPreviewTimer.Stop();
+
+ if( bEntriesFound )
+ {
+ if (m_xLbxFound->count_selected_rows() == 1)
+ {
+ m_xCbxPreview->set_sensitive(true);
+ bPreviewPossible = true;
+ }
+ else
+ m_xCbxPreview->set_sensitive(false);
+
+ if( !aFoundList.empty() )
+ m_xBtnTakeAll->set_sensitive(true);
+ else
+ m_xBtnTakeAll->set_sensitive(false);
+ }
+
+ if (bPreviewPossible && m_xCbxPreview->get_active())
+ aPreviewTimer.Start();
+}
+
+IMPL_LINK_NOARG(TPGalleryThemeProperties, DClickFoundHdl, weld::TreeView&, bool)
+{
+ if( bInputAllowed )
+ {
+ aPreviewTimer.Stop();
+
+ if (m_xLbxFound->count_selected_rows() == 1 && bEntriesFound)
+ ClickTakeHdl(*m_xBtnTake);
+ }
+ return true;
+}
+
+IMPL_LINK_NOARG(TPGalleryThemeProperties, PreviewTimerHdl, Timer *, void)
+{
+ aPreviewTimer.Stop();
+ DoPreview();
+}
+
+void TPGalleryThemeProperties::EndSearchProgressHdl(sal_Int32 /*nResult*/)
+{
+ if( !aFoundList.empty() )
+ {
+ m_xLbxFound->select(0);
+ m_xBtnTakeAll->set_sensitive(true);
+ m_xCbxPreview->set_sensitive(true);
+ bEntriesFound = true;
+ }
+ else
+ {
+ m_xLbxFound->append_text(CuiResId(RID_SVXSTR_GALLERY_NOFILES));
+ m_xBtnTakeAll->set_sensitive(false);
+ m_xCbxPreview->set_sensitive(false);
+ bEntriesFound = false;
+ }
+}
+
+IMPL_LINK( TPGalleryThemeProperties, DialogClosedHdl, css::ui::dialogs::DialogClosedEvent*, pEvt, void )
+{
+ DBG_ASSERT( xFolderPicker.is(), "TPGalleryThemeProperties::DialogClosedHdl(): no folder picker" );
+
+ OUString sURL = xFolderPicker->getDirectory();
+ StartSearchFiles( sURL, pEvt->DialogResult );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/dialogs/cuigrfflt.cxx b/cui/source/dialogs/cuigrfflt.cxx
new file mode 100644
index 000000000..baaa6603c
--- /dev/null
+++ b/cui/source/dialogs/cuigrfflt.cxx
@@ -0,0 +1,468 @@
+/* -*- 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/BitmapMosaicFilter.hxx>
+#include <vcl/BitmapSharpenFilter.hxx>
+#include <vcl/BitmapEmbossGreyFilter.hxx>
+#include <vcl/BitmapSepiaFilter.hxx>
+#include <vcl/BitmapSmoothenFilter.hxx>
+#include <vcl/BitmapSolarizeFilter.hxx>
+#include <vcl/BitmapColorQuantizationFilter.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <osl/diagnose.h>
+#include <tools/helpers.hxx>
+#include <cuigrfflt.hxx>
+
+CuiGraphicPreviewWindow::CuiGraphicPreviewWindow()
+ : mpOrigGraphic(nullptr)
+ , mfScaleX(0.0)
+ , mfScaleY(0.0)
+{
+}
+
+void CuiGraphicPreviewWindow::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ CustomWidgetController::SetDrawingArea(pDrawingArea);
+ OutputDevice &rDevice = pDrawingArea->get_ref_device();
+ maOutputSizePixel = rDevice.LogicToPixel(Size(81, 73), MapMode(MapUnit::MapAppFont));
+ pDrawingArea->set_size_request(maOutputSizePixel.Width(), maOutputSizePixel.Height());
+}
+
+void CuiGraphicPreviewWindow::Paint(vcl::RenderContext& rRenderContext, const ::tools::Rectangle&)
+{
+ rRenderContext.SetBackground(Wallpaper(Application::GetSettings().GetStyleSettings().GetDialogColor()));
+ rRenderContext.Erase();
+
+ const Size aOutputSize(GetOutputSizePixel());
+
+ if (maPreview.IsAnimated())
+ {
+ const Size aGraphicSize(rRenderContext.LogicToPixel(maPreview.GetPrefSize(), maPreview.GetPrefMapMode()));
+ const Point aGraphicPosition((aOutputSize.Width() - aGraphicSize.Width() ) >> 1,
+ (aOutputSize.Height() - aGraphicSize.Height() ) >> 1);
+ maPreview.StartAnimation(&rRenderContext, aGraphicPosition, aGraphicSize);
+ }
+ else
+ {
+ const Size aGraphicSize(maPreview.GetSizePixel());
+ const Point aGraphicPosition((aOutputSize.Width() - aGraphicSize.Width()) >> 1,
+ (aOutputSize.Height() - aGraphicSize.Height()) >> 1);
+ maPreview.Draw(&rRenderContext, aGraphicPosition, aGraphicSize);
+ }
+}
+
+void CuiGraphicPreviewWindow::SetPreview(const Graphic& rGraphic)
+{
+ maPreview = rGraphic;
+ Invalidate();
+}
+
+void CuiGraphicPreviewWindow::ScaleImageToFit()
+{
+ if (!mpOrigGraphic)
+ return;
+
+ maScaledOrig = *mpOrigGraphic;
+
+ const Size aPreviewSize(GetOutputSizePixel());
+ Size aGrfSize(maOrigGraphicSizePixel);
+
+ if( mpOrigGraphic->GetType() == GraphicType::Bitmap &&
+ aPreviewSize.Width() && aPreviewSize.Height() &&
+ aGrfSize.Width() && aGrfSize.Height() )
+ {
+ const double fGrfWH = static_cast<double>(aGrfSize.Width()) / aGrfSize.Height();
+ const double fPreWH = static_cast<double>(aPreviewSize.Width()) / aPreviewSize.Height();
+
+ if( fGrfWH < fPreWH )
+ {
+ aGrfSize.setWidth( static_cast<long>( aPreviewSize.Height() * fGrfWH ) );
+ aGrfSize.setHeight( aPreviewSize.Height() );
+ }
+ else
+ {
+ aGrfSize.setWidth( aPreviewSize.Width() );
+ aGrfSize.setHeight( static_cast<long>( aPreviewSize.Width() / fGrfWH ) );
+ }
+
+ mfScaleX = static_cast<double>(aGrfSize.Width()) / maOrigGraphicSizePixel.Width();
+ mfScaleY = static_cast<double>(aGrfSize.Height()) / maOrigGraphicSizePixel.Height();
+
+ if( !mpOrigGraphic->IsAnimated() )
+ {
+ BitmapEx aBmpEx( mpOrigGraphic->GetBitmapEx() );
+
+ if( aBmpEx.Scale( aGrfSize ) )
+ maScaledOrig = aBmpEx;
+ }
+ }
+
+ maModifyHdl.Call(nullptr);
+}
+
+void CuiGraphicPreviewWindow::Resize()
+{
+ maOutputSizePixel = GetOutputSizePixel();
+ ScaleImageToFit();
+}
+
+GraphicFilterDialog::GraphicFilterDialog(weld::Window* pParent,
+ const OUString& rUIXMLDescription, const OString& rID,
+ const Graphic& rGraphic)
+ : GenericDialogController(pParent, rUIXMLDescription, rID)
+ , maModifyHdl(LINK(this, GraphicFilterDialog, ImplModifyHdl))
+ , mxPreview(new weld::CustomWeld(*m_xBuilder, "preview", maPreview))
+{
+ bIsBitmap = rGraphic.GetType() == GraphicType::Bitmap;
+
+ maTimer.SetInvokeHandler(LINK(this, GraphicFilterDialog, ImplPreviewTimeoutHdl));
+ maTimer.SetTimeout(5);
+
+ maPreview.init(&rGraphic, maModifyHdl);
+}
+
+IMPL_LINK_NOARG(GraphicFilterDialog, ImplPreviewTimeoutHdl, Timer *, void)
+{
+ maTimer.Stop();
+ maPreview.SetPreview(GetFilteredGraphic(maPreview.GetScaledOriginal(),
+ maPreview.GetScaleX(), maPreview.GetScaleY()));
+}
+
+IMPL_LINK_NOARG(GraphicFilterDialog, ImplModifyHdl, LinkParamNone*, void)
+{
+ if (bIsBitmap)
+ {
+ maTimer.Stop();
+ maTimer.Start();
+ }
+}
+
+GraphicFilterMosaic::GraphicFilterMosaic(weld::Window* pParent, const Graphic& rGraphic,
+ sal_uInt16 nTileWidth, sal_uInt16 nTileHeight, bool bEnhanceEdges)
+ : GraphicFilterDialog(pParent, "cui/ui/mosaicdialog.ui", "MosaicDialog", rGraphic)
+ , mxMtrWidth(m_xBuilder->weld_metric_spin_button("width", FieldUnit::PIXEL))
+ , mxMtrHeight(m_xBuilder->weld_metric_spin_button("height", FieldUnit::PIXEL))
+ , mxCbxEdges(m_xBuilder->weld_check_button("edges"))
+{
+ mxMtrWidth->set_value(nTileWidth, FieldUnit::PIXEL);
+ mxMtrWidth->set_max(GetGraphicSizePixel().Width(), FieldUnit::PIXEL);
+ mxMtrWidth->connect_value_changed(LINK(this, GraphicFilterMosaic, EditModifyHdl));
+
+ mxMtrHeight->set_value(nTileHeight, FieldUnit::PIXEL);
+ mxMtrHeight->set_max(GetGraphicSizePixel().Height(), FieldUnit::PIXEL);
+ mxMtrHeight->connect_value_changed(LINK(this, GraphicFilterMosaic, EditModifyHdl));
+
+ mxCbxEdges->set_active(bEnhanceEdges);
+ mxCbxEdges->connect_toggled(LINK(this, GraphicFilterMosaic, CheckBoxModifyHdl));
+
+ mxMtrWidth->grab_focus();
+}
+
+IMPL_LINK_NOARG(GraphicFilterMosaic, CheckBoxModifyHdl, weld::ToggleButton&, void)
+{
+ GetModifyHdl().Call(nullptr);
+}
+
+IMPL_LINK_NOARG(GraphicFilterMosaic, EditModifyHdl, weld::MetricSpinButton&, void)
+{
+ GetModifyHdl().Call(nullptr);
+}
+
+Graphic GraphicFilterMosaic::GetFilteredGraphic( const Graphic& rGraphic,
+ double fScaleX, double fScaleY )
+{
+ Graphic aRet;
+ long nTileWidth = static_cast<long>(mxMtrWidth->get_value(FieldUnit::PIXEL));
+ long nTileHeight = static_cast<long>(mxMtrHeight->get_value(FieldUnit::PIXEL));
+ const Size aSize( std::max( FRound( nTileWidth * fScaleX ), 1L ),
+ std::max( FRound( nTileHeight * fScaleY ), 1L ) );
+
+ if( rGraphic.IsAnimated() )
+ {
+ Animation aAnim( rGraphic.GetAnimation() );
+
+ if (BitmapFilter::Filter(aAnim, BitmapMosaicFilter(aSize.getWidth(), aSize.getHeight())))
+ {
+ if( IsEnhanceEdges() )
+ (void)BitmapFilter::Filter(aAnim, BitmapSharpenFilter());
+
+ aRet = aAnim;
+ }
+ }
+ else
+ {
+ BitmapEx aBmpEx( rGraphic.GetBitmapEx() );
+
+ if (BitmapFilter::Filter(aBmpEx, BitmapMosaicFilter(aSize.getWidth(), aSize.getHeight())))
+ {
+ if( IsEnhanceEdges() )
+ BitmapFilter::Filter(aBmpEx, BitmapSharpenFilter());
+
+ aRet = aBmpEx;
+ }
+ }
+
+ return aRet;
+}
+
+GraphicFilterSmooth::GraphicFilterSmooth(weld::Window* pParent, const Graphic& rGraphic, double nRadius)
+ : GraphicFilterDialog(pParent, "cui/ui/smoothdialog.ui", "SmoothDialog", rGraphic)
+ , mxMtrRadius(m_xBuilder->weld_spin_button("radius"))
+{
+ mxMtrRadius->set_value(nRadius * 10);
+ mxMtrRadius->connect_value_changed(LINK(this, GraphicFilterSmooth, EditModifyHdl));
+ mxMtrRadius->grab_focus();
+}
+
+IMPL_LINK_NOARG(GraphicFilterSmooth, EditModifyHdl, weld::SpinButton&, void)
+{
+ GetModifyHdl().Call(nullptr);
+}
+
+Graphic GraphicFilterSmooth::GetFilteredGraphic( const Graphic& rGraphic, double, double )
+{
+ Graphic aRet;
+ double nRadius = mxMtrRadius->get_value() / 10.0;
+
+ if( rGraphic.IsAnimated() )
+ {
+ Animation aAnim( rGraphic.GetAnimation() );
+
+ if (BitmapFilter::Filter(aAnim, BitmapSmoothenFilter(nRadius)))
+ {
+ aRet = aAnim;
+ }
+ }
+ else
+ {
+ BitmapEx aBmpEx( rGraphic.GetBitmapEx() );
+
+ if (BitmapFilter::Filter(aBmpEx, BitmapSmoothenFilter(nRadius)))
+ {
+ aRet = aBmpEx;
+ }
+ }
+
+ return aRet;
+}
+
+GraphicFilterSolarize::GraphicFilterSolarize(weld::Window* pParent, const Graphic& rGraphic,
+ sal_uInt8 cGreyThreshold, bool bInvert)
+ : GraphicFilterDialog(pParent, "cui/ui/solarizedialog.ui", "SolarizeDialog", rGraphic)
+ , mxMtrThreshold(m_xBuilder->weld_metric_spin_button("value", FieldUnit::PERCENT))
+ , mxCbxInvert(m_xBuilder->weld_check_button("invert"))
+{
+ mxMtrThreshold->set_value(FRound(cGreyThreshold / 2.55), FieldUnit::PERCENT);
+ mxMtrThreshold->connect_value_changed(LINK(this, GraphicFilterSolarize, EditModifyHdl));
+
+ mxCbxInvert->set_active(bInvert);
+ mxCbxInvert->connect_toggled(LINK(this, GraphicFilterSolarize, CheckBoxModifyHdl));
+}
+
+IMPL_LINK_NOARG(GraphicFilterSolarize, CheckBoxModifyHdl, weld::ToggleButton&, void)
+{
+ GetModifyHdl().Call(nullptr);
+}
+
+IMPL_LINK_NOARG(GraphicFilterSolarize, EditModifyHdl, weld::MetricSpinButton&, void)
+{
+ GetModifyHdl().Call(nullptr);
+}
+
+Graphic GraphicFilterSolarize::GetFilteredGraphic( const Graphic& rGraphic, double, double )
+{
+ Graphic aRet;
+ sal_uInt8 nGreyThreshold = static_cast<sal_uInt8>(FRound(mxMtrThreshold->get_value(FieldUnit::PERCENT) * 2.55));
+
+ if( rGraphic.IsAnimated() )
+ {
+ Animation aAnim( rGraphic.GetAnimation() );
+
+ if (BitmapFilter::Filter(aAnim, BitmapSolarizeFilter(nGreyThreshold)))
+ {
+ if( IsInvert() )
+ aAnim.Invert();
+
+ aRet = aAnim;
+ }
+ }
+ else
+ {
+ BitmapEx aBmpEx( rGraphic.GetBitmapEx() );
+
+ if (BitmapFilter::Filter(aBmpEx, BitmapSolarizeFilter(nGreyThreshold)))
+ {
+ if( IsInvert() )
+ aBmpEx.Invert();
+
+ aRet = aBmpEx;
+ }
+ }
+
+ return aRet;
+}
+
+GraphicFilterSepia::GraphicFilterSepia(weld::Window* pParent, const Graphic& rGraphic,
+ sal_uInt16 nSepiaPercent)
+ : GraphicFilterDialog(pParent, "cui/ui/agingdialog.ui", "AgingDialog", rGraphic)
+ , mxMtrSepia(m_xBuilder->weld_metric_spin_button("value", FieldUnit::PERCENT))
+{
+ mxMtrSepia->set_value(nSepiaPercent, FieldUnit::PERCENT);
+ mxMtrSepia->connect_value_changed(LINK(this, GraphicFilterSepia, EditModifyHdl));
+}
+
+IMPL_LINK_NOARG(GraphicFilterSepia, EditModifyHdl, weld::MetricSpinButton&, void)
+{
+ GetModifyHdl().Call(nullptr);
+}
+
+Graphic GraphicFilterSepia::GetFilteredGraphic( const Graphic& rGraphic, double, double )
+{
+ Graphic aRet;
+ sal_uInt16 nSepiaPct = sal::static_int_cast< sal_uInt16 >(mxMtrSepia->get_value(FieldUnit::PERCENT));
+
+ if( rGraphic.IsAnimated() )
+ {
+ Animation aAnim( rGraphic.GetAnimation() );
+
+ if (BitmapFilter::Filter(aAnim, BitmapSepiaFilter(nSepiaPct)))
+ aRet = aAnim;
+ }
+ else
+ {
+ BitmapEx aBmpEx( rGraphic.GetBitmapEx() );
+
+ if (BitmapFilter::Filter(aBmpEx, BitmapSepiaFilter(nSepiaPct)))
+ aRet = aBmpEx;
+ }
+
+ return aRet;
+}
+
+GraphicFilterPoster::GraphicFilterPoster(weld::Window* pParent, const Graphic& rGraphic,
+ sal_uInt16 nPosterCount)
+ : GraphicFilterDialog(pParent, "cui/ui/posterdialog.ui", "PosterDialog", rGraphic)
+ , mxNumPoster(m_xBuilder->weld_spin_button("value"))
+{
+ mxNumPoster->set_range(2, rGraphic.GetBitmapEx().GetBitCount());
+ mxNumPoster->set_value(nPosterCount);
+ mxNumPoster->connect_value_changed(LINK(this, GraphicFilterPoster, EditModifyHdl));
+}
+
+IMPL_LINK_NOARG(GraphicFilterPoster, EditModifyHdl, weld::SpinButton&, void)
+{
+ GetModifyHdl().Call(nullptr);
+}
+
+Graphic GraphicFilterPoster::GetFilteredGraphic( const Graphic& rGraphic, double, double )
+{
+ Graphic aRet;
+ const sal_uInt16 nPosterCount = static_cast<sal_uInt16>(mxNumPoster->get_value());
+
+ if( rGraphic.IsAnimated() )
+ {
+ Animation aAnim( rGraphic.GetAnimation() );
+
+ if( aAnim.ReduceColors( nPosterCount ) )
+ aRet = aAnim;
+ }
+ else
+ {
+ BitmapEx aBmpEx( rGraphic.GetBitmapEx() );
+
+ if (BitmapFilter::Filter(aBmpEx, BitmapColorQuantizationFilter(nPosterCount)))
+ aRet = aBmpEx;
+ }
+
+ return aRet;
+}
+
+bool EmbossControl::MouseButtonDown( const MouseEvent& rEvt )
+{
+ const RectPoint eOldRP = GetActualRP();
+
+ SvxRectCtl::MouseButtonDown( rEvt );
+
+ if( GetActualRP() != eOldRP )
+ maModifyHdl.Call( nullptr );
+
+ return true;
+}
+
+void EmbossControl::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ SvxRectCtl::SetDrawingArea(pDrawingArea);
+ Size aSize(pDrawingArea->get_ref_device().LogicToPixel(Size(77, 60), MapMode(MapUnit::MapAppFont)));
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+}
+
+GraphicFilterEmboss::GraphicFilterEmboss(weld::Window* pParent,
+ const Graphic& rGraphic, RectPoint eLightSource)
+ : GraphicFilterDialog(pParent, "cui/ui/embossdialog.ui", "EmbossDialog", rGraphic)
+ , mxCtlLight(new weld::CustomWeld(*m_xBuilder, "lightsource", maCtlLight))
+{
+ maCtlLight.SetActualRP(eLightSource);
+ maCtlLight.SetModifyHdl( GetModifyHdl() );
+ maCtlLight.GrabFocus();
+}
+
+GraphicFilterEmboss::~GraphicFilterEmboss()
+{
+}
+
+Graphic GraphicFilterEmboss::GetFilteredGraphic( const Graphic& rGraphic, double, double )
+{
+ Graphic aRet;
+ sal_uInt16 nAzim, nElev;
+
+ switch (maCtlLight.GetActualRP())
+ {
+ default: OSL_FAIL("svx::GraphicFilterEmboss::GetFilteredGraphic(), unknown Reference Point!" );
+ [[fallthrough]];
+ case RectPoint::LT: nAzim = 4500; nElev = 4500; break;
+ case RectPoint::MT: nAzim = 9000; nElev = 4500; break;
+ case RectPoint::RT: nAzim = 13500; nElev = 4500; break;
+ case RectPoint::LM: nAzim = 0; nElev = 4500; break;
+ case RectPoint::MM: nAzim = 0; nElev = 9000; break;
+ case RectPoint::RM: nAzim = 18000; nElev = 4500; break;
+ case RectPoint::LB: nAzim = 31500; nElev = 4500; break;
+ case RectPoint::MB: nAzim = 27000; nElev = 4500; break;
+ case RectPoint::RB: nAzim = 22500; nElev = 4500; break;
+ }
+
+ if( rGraphic.IsAnimated() )
+ {
+ Animation aAnim( rGraphic.GetAnimation() );
+
+ if (BitmapFilter::Filter(aAnim, BitmapEmbossGreyFilter(nAzim, nElev)))
+ aRet = aAnim;
+ }
+ else
+ {
+ BitmapEx aBmpEx( rGraphic.GetBitmapEx() );
+
+ if (BitmapFilter::Filter(aBmpEx, BitmapEmbossGreyFilter(nAzim, nElev)))
+ aRet = aBmpEx;
+ }
+
+ return aRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/dialogs/cuihyperdlg.cxx b/cui/source/dialogs/cuihyperdlg.cxx
new file mode 100644
index 000000000..9ca722680
--- /dev/null
+++ b/cui/source/dialogs/cuihyperdlg.cxx
@@ -0,0 +1,293 @@
+/* -*- 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 <osl/diagnose.h>
+#include <comphelper/lok.hxx>
+#include <unotools/viewoptions.hxx>
+#include <cuihyperdlg.hxx>
+#include <hlinettp.hxx>
+#include <hlmailtp.hxx>
+#include <hldoctp.hxx>
+#include <hldocntp.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svl/eitem.hxx>
+#include <svx/svxids.hrc>
+#include <dialmgr.hxx>
+#include <strings.hrc>
+#include <vector>
+
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::frame::XFrame;
+
+
+//# #
+//# Childwindow-Wrapper-Class #
+//# #
+
+
+SvxHlinkCtrl::SvxHlinkCtrl( sal_uInt16 _nId, SfxBindings & rBindings, SvxHpLinkDlg* pDlg )
+ : SfxControllerItem ( _nId, rBindings )
+ , aRdOnlyForwarder ( SID_READONLY_MODE, *this )
+{
+ pParent = pDlg;
+}
+
+void SvxHlinkCtrl::dispose()
+{
+ pParent = nullptr;
+ aRdOnlyForwarder.dispose();
+ ::SfxControllerItem::dispose();
+}
+
+void SvxHlinkCtrl::StateChanged( sal_uInt16 nSID, SfxItemState eState,
+ const SfxPoolItem* pState )
+{
+ if (!(eState == SfxItemState::DEFAULT && pParent))
+ return;
+
+ switch ( nSID )
+ {
+ case SID_HYPERLINK_GETLINK :
+ {
+ pParent->SetPage( static_cast<const SvxHyperlinkItem*>(pState) );
+ }
+ break;
+ case SID_READONLY_MODE :
+ {
+ pParent->SetReadOnlyMode( static_cast<const SfxBoolItem*>(pState)->GetValue() );
+ }
+ break;
+ }
+}
+
+//# #
+//# Hyperlink - Dialog #
+//# #
+SvxHpLinkDlg::SvxHpLinkDlg(SfxBindings* pBindings, SfxChildWindow* pChild, weld::Window* pParent)
+ : SfxModelessDialogController(pBindings, pChild, pParent, "cui/ui/hyperlinkdialog.ui", "HyperlinkDialog")
+ , pSet ( nullptr )
+ , pExampleSet ( nullptr )
+ , maCtrl ( SID_HYPERLINK_GETLINK, *pBindings, this )
+ , mbIsHTMLDoc ( false )
+ , m_xIconCtrl(m_xBuilder->weld_notebook("tabcontrol"))
+ , m_xOKBtn(m_xBuilder->weld_button("ok"))
+ , m_xApplyBtn(m_xBuilder->weld_button("apply"))
+ , m_xCancelBtn(m_xBuilder->weld_button("cancel"))
+ , m_xHelpBtn(m_xBuilder->weld_button("help"))
+ , m_xResetBtn(m_xBuilder->weld_button("reset"))
+{
+ m_xIconCtrl->connect_enter_page( LINK ( this, SvxHpLinkDlg, ChosePageHdl_Impl ) );
+ m_xIconCtrl->show();
+
+ // ItemSet
+ if ( pSet )
+ {
+ pExampleSet = new SfxItemSet( *pSet );
+ pOutSet.reset(new SfxItemSet( *pSet->GetPool(), pSet->GetRanges() ));
+ }
+
+ // Buttons
+ m_xOKBtn->show();
+ m_xApplyBtn->show();
+ m_xCancelBtn->show();
+ m_xHelpBtn->show();
+ m_xResetBtn->show();
+
+ mbGrabFocus = true;
+
+ // set OK/Cancel - button
+ m_xCancelBtn->set_label(CuiResId(RID_SVXSTR_HYPDLG_CLOSEBUT));
+
+ // create itemset for tabpages
+ mpItemSet = std::make_unique<SfxItemSet>( SfxGetpApp()->GetPool(), svl::Items<SID_HYPERLINK_GETLINK,
+ SID_HYPERLINK_SETLINK>{} );
+
+ SvxHyperlinkItem aItem(SID_HYPERLINK_GETLINK);
+ mpItemSet->Put(aItem);
+
+ SetInputSet (mpItemSet.get());
+
+ // insert pages
+ AddTabPage("internet", SvxHyperlinkInternetTp::Create);
+ AddTabPage("mail", SvxHyperlinkMailTp::Create);
+ if (!comphelper::LibreOfficeKit::isActive())
+ {
+ AddTabPage("document", SvxHyperlinkDocTp::Create);
+ AddTabPage("newdocument", SvxHyperlinkNewDocTp::Create);
+ }
+
+ SetCurPageId("internet");
+
+ // Init Dialog
+ Start();
+
+ GetBindings().Update(SID_READONLY_MODE);
+
+ m_xResetBtn->connect_clicked( LINK( this, SvxHpLinkDlg, ResetHdl ) );
+ m_xOKBtn->connect_clicked( LINK ( this, SvxHpLinkDlg, ClickOkHdl_Impl ) );
+ m_xApplyBtn->connect_clicked ( LINK ( this, SvxHpLinkDlg, ClickApplyHdl_Impl ) );
+}
+
+SvxHpLinkDlg::~SvxHpLinkDlg()
+{
+ // delete config item, so the base class (SfxModelessDialogController) can not load it on the next start
+ SvtViewOptions aViewOpt( EViewType::TabDialog, OUString::number(SID_HYPERLINK_DIALOG) );
+ aViewOpt.Delete();
+
+ mpItemSet.reset();
+
+ maCtrl.dispose();
+
+ maPageList.clear();
+
+ pRanges.reset();
+ pOutSet.reset();
+}
+
+void SvxHpLinkDlg::Close()
+{
+ if (IsClosing())
+ return;
+ SfxViewFrame* pViewFrame = SfxViewFrame::Current();
+ if (pViewFrame)
+ pViewFrame->ToggleChildWindow(SID_HYPERLINK_DIALOG);
+}
+
+void SvxHpLinkDlg::Apply()
+{
+ SfxItemSet aItemSet( SfxGetpApp()->GetPool(), svl::Items<SID_HYPERLINK_GETLINK,
+ SID_HYPERLINK_SETLINK>{} );
+
+ SvxHyperlinkTabPageBase* pCurrentPage = static_cast<SvxHyperlinkTabPageBase*>(
+ GetTabPage( GetCurPageId() ) );
+
+ if ( pCurrentPage->AskApply() )
+ {
+ pCurrentPage->FillItemSet( &aItemSet );
+
+ const SvxHyperlinkItem *aItem = aItemSet.GetItem(SID_HYPERLINK_SETLINK);
+ if ( !aItem->GetURL().isEmpty() )
+ GetDispatcher()->ExecuteList(SID_HYPERLINK_SETLINK,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD, { aItem });
+
+ static_cast<SvxHyperlinkTabPageBase*>( GetTabPage( GetCurPageId() ) )->DoApply();
+ }
+}
+
+/// Click on OK button
+IMPL_LINK_NOARG(SvxHpLinkDlg, ClickOkHdl_Impl, weld::Button&, void)
+{
+ Apply();
+ m_xDialog->response(RET_OK);
+}
+
+/*************************************************************************
+|*
+|* Click on Apply-button
+|*
+|************************************************************************/
+IMPL_LINK_NOARG(SvxHpLinkDlg, ClickApplyHdl_Impl, weld::Button&, void)
+{
+ Apply();
+}
+
+/*************************************************************************
+|*
+|* Set Page
+|*
+|************************************************************************/
+void SvxHpLinkDlg::SetPage ( SvxHyperlinkItem const * pItem )
+{
+ OString sPageId("internet");
+
+ OUString aStrURL(pItem->GetURL());
+ INetURLObject aURL(aStrURL);
+ INetProtocol eProtocolTyp = aURL.GetProtocol();
+
+ switch ( eProtocolTyp )
+ {
+ case INetProtocol::Http :
+ case INetProtocol::Ftp :
+ sPageId = "internet";
+ break;
+ case INetProtocol::File :
+ sPageId = "document";
+ break;
+ case INetProtocol::Mailto :
+ sPageId = "mail";
+ break;
+ default :
+ if (aStrURL.startsWith("#"))
+ sPageId = "document";
+ else
+ {
+ // not valid
+ sPageId = GetCurPageId();
+ }
+ break;
+ }
+
+ ShowPage (sPageId);
+
+ SvxHyperlinkTabPageBase* pCurrentPage = static_cast<SvxHyperlinkTabPageBase*>(GetTabPage( sPageId ));
+
+ mbIsHTMLDoc = (pItem->GetInsertMode() & HLINK_HTMLMODE) != 0;
+
+ IconChoicePage* pPage = GetTabPage (sPageId);
+ if(pPage)
+ {
+ SfxItemSet& aPageSet = const_cast<SfxItemSet&>(pPage->GetItemSet ());
+ aPageSet.Put ( *pItem );
+
+ pCurrentPage->Reset( aPageSet );
+ if ( mbGrabFocus )
+ {
+ pCurrentPage->SetInitFocus(); // #92535# grab the focus only once at initialization
+ mbGrabFocus = false;
+ }
+ }
+}
+
+/*************************************************************************
+|*
+|* Enable/Disable ReadOnly mode
+|*
+|************************************************************************/
+void SvxHpLinkDlg::SetReadOnlyMode( bool bRdOnly )
+{
+ m_xOKBtn->set_sensitive(!bRdOnly);
+}
+
+/*************************************************************************
+|*
+|* late-initialization of newly created pages
+|*
+|************************************************************************/
+void SvxHpLinkDlg::PageCreated(const OString& /*rId*/, IconChoicePage& rPage)
+{
+ SvxHyperlinkTabPageBase& rHyperlinkPage = dynamic_cast< SvxHyperlinkTabPageBase& >( rPage );
+ Reference< XFrame > xDocumentFrame = GetBindings().GetActiveFrame();
+ OSL_ENSURE( xDocumentFrame.is(), "SvxHpLinkDlg::PageCreated: macro assignment functionality won't work with a proper frame!" );
+ rHyperlinkPage.SetDocumentFrame( xDocumentFrame );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/dialogs/cuiimapwnd.cxx b/cui/source/dialogs/cuiimapwnd.cxx
new file mode 100644
index 000000000..60346dc69
--- /dev/null
+++ b/cui/source/dialogs/cuiimapwnd.cxx
@@ -0,0 +1,59 @@
+/* -*- 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 <cuiimapwnd.hxx>
+
+/*************************************************************************
+|*
+|* URLDlg
+|*
+\************************************************************************/
+
+URLDlg::URLDlg(weld::Widget* pWindow, const OUString& rURL, const OUString& rAlternativeText,
+ const OUString& rDescription, const OUString& rTarget, const OUString& rName,
+ TargetList& rTargetList)
+ : GenericDialogController(pWindow, "cui/ui/cuiimapdlg.ui", "IMapDialog")
+ , m_xEdtURL(m_xBuilder->weld_entry("urlentry"))
+ , m_xCbbTargets(m_xBuilder->weld_combo_box("frameCB"))
+ , m_xEdtName(m_xBuilder->weld_entry("nameentry"))
+ , m_xEdtAlternativeText(m_xBuilder->weld_entry("textentry"))
+ , m_xEdtDescription(m_xBuilder->weld_text_view("descTV"))
+{
+ m_xEdtDescription->set_size_request(m_xEdtDescription->get_approximate_digit_width() * 51,
+ m_xEdtDescription->get_height_rows(5));
+
+ m_xEdtURL->set_text( rURL );
+ m_xEdtAlternativeText->set_text( rAlternativeText );
+ m_xEdtDescription->set_text( rDescription );
+ m_xEdtName->set_text( rName );
+
+ for (const OUString& a : rTargetList)
+ m_xCbbTargets->append_text(a);
+
+ if (rTarget.isEmpty())
+ m_xCbbTargets->set_entry_text("_self");
+ else
+ m_xCbbTargets->set_entry_text(rTarget);
+}
+
+URLDlg::~URLDlg()
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/dialogs/cuitbxform.cxx b/cui/source/dialogs/cuitbxform.cxx
new file mode 100644
index 000000000..eb0a76814
--- /dev/null
+++ b/cui/source/dialogs/cuitbxform.cxx
@@ -0,0 +1,33 @@
+/* -*- 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 <cuitbxform.hxx>
+
+FmInputRecordNoDialog::FmInputRecordNoDialog(weld::Window * pParent)
+ : GenericDialogController(pParent, "cui/ui/recordnumberdialog.ui", "RecordNumberDialog")
+ , m_xRecordNo(m_xBuilder->weld_spin_button("entry"))
+{
+ m_xRecordNo->set_range(1, 0x7FFFFFFF);
+}
+
+FmInputRecordNoDialog::~FmInputRecordNoDialog()
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/dialogs/dlgname.cxx b/cui/source/dialogs/dlgname.cxx
new file mode 100644
index 000000000..d8044366b
--- /dev/null
+++ b/cui/source/dialogs/dlgname.cxx
@@ -0,0 +1,104 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <dlgname.hxx>
+
+/*************************************************************************
+|*
+|* Dialog for editing a name
+|*
+\************************************************************************/
+
+SvxNameDialog::SvxNameDialog(weld::Window* pParent, const OUString& rName, const OUString& rDesc)
+ : GenericDialogController(pParent, "cui/ui/namedialog.ui", "NameDialog")
+ , m_xEdtName(m_xBuilder->weld_entry("name_entry"))
+ , m_xFtDescription(m_xBuilder->weld_label("description_label"))
+ , m_xBtnOK(m_xBuilder->weld_button("ok"))
+{
+ m_xFtDescription->set_label(rDesc);
+ m_xEdtName->set_text(rName);
+ m_xEdtName->select_region(0, -1);
+ ModifyHdl(*m_xEdtName);
+ m_xEdtName->connect_changed(LINK(this, SvxNameDialog, ModifyHdl));
+}
+
+IMPL_LINK_NOARG(SvxNameDialog, ModifyHdl, weld::Entry&, void)
+{
+ // Do not allow empty names
+ bool bEnable;
+ if (m_aCheckNameHdl.IsSet())
+ bEnable = !m_xEdtName->get_text().isEmpty() && m_aCheckNameHdl.Call(*this);
+ else
+ bEnable = !m_xEdtName->get_text().isEmpty();
+ m_xBtnOK->set_sensitive(bEnable);
+ // tdf#129032: feedback on reason to disabled controls
+ m_xEdtName->set_message_type(bEnable ? weld::EntryMessageType::Normal : weld::EntryMessageType::Error);
+ OUString rTip = "";
+ if (!bEnable && m_aCheckNameTooltipHdl.IsSet())
+ rTip = m_aCheckNameTooltipHdl.Call(*this);
+ m_xBtnOK->set_tooltip_text(rTip);
+ m_xEdtName->set_tooltip_text(rTip);
+}
+
+// #i68101#
+// Dialog for editing Object Name
+// plus uniqueness-callback-linkHandler
+
+SvxObjectNameDialog::SvxObjectNameDialog(weld::Window* pParent, const OUString& rName)
+ : GenericDialogController(pParent, "cui/ui/objectnamedialog.ui", "ObjectNameDialog")
+ , m_xEdtName(m_xBuilder->weld_entry("object_name_entry"))
+ , m_xBtnOK(m_xBuilder->weld_button("ok"))
+{
+ // set name
+ m_xEdtName->set_text(rName);
+ m_xEdtName->select_region(0, -1);
+
+ // activate name
+ ModifyHdl(*m_xEdtName);
+ m_xEdtName->connect_changed(LINK(this, SvxObjectNameDialog, ModifyHdl));
+}
+
+IMPL_LINK_NOARG(SvxObjectNameDialog, ModifyHdl, weld::Entry&, void)
+{
+ if (aCheckNameHdl.IsSet())
+ {
+ m_xBtnOK->set_sensitive(aCheckNameHdl.Call(*this));
+ }
+}
+
+// #i68101#
+// Dialog for editing Object Title and Description
+
+SvxObjectTitleDescDialog::SvxObjectTitleDescDialog(weld::Window* pParent, const OUString& rTitle,
+ const OUString& rDescription)
+ : GenericDialogController(pParent, "cui/ui/objecttitledescdialog.ui", "ObjectTitleDescDialog")
+ , m_xEdtTitle(m_xBuilder->weld_entry("object_title_entry"))
+ , m_xEdtDescription(m_xBuilder->weld_text_view("desc_entry"))
+{
+ //lock height to initial height
+ m_xEdtDescription->set_size_request(-1, m_xEdtDescription->get_text_height() * 5);
+ // set title & desc
+ m_xEdtTitle->set_text(rTitle);
+ m_xEdtDescription->set_text(rDescription);
+
+ // activate title
+ m_xEdtTitle->select_region(0, -1);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/dialogs/hangulhanjadlg.cxx b/cui/source/dialogs/hangulhanjadlg.cxx
new file mode 100644
index 000000000..5e273b3b1
--- /dev/null
+++ b/cui/source/dialogs/hangulhanjadlg.cxx
@@ -0,0 +1,1505 @@
+/* -*- 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 <hangulhanjadlg.hxx>
+#include <dialmgr.hxx>
+
+#include <helpids.h>
+#include <strings.hrc>
+
+#include <algorithm>
+#include <sal/log.hxx>
+#include <osl/diagnose.h>
+#include <tools/debug.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/virdev.hxx>
+#include <unotools/lingucfg.hxx>
+#include <unotools/linguprops.hxx>
+#include <com/sun/star/lang/NoSupportException.hpp>
+#include <com/sun/star/linguistic2/ConversionDictionaryType.hpp>
+#include <com/sun/star/linguistic2/ConversionDirection.hpp>
+#include <com/sun/star/linguistic2/ConversionDictionaryList.hpp>
+#include <com/sun/star/i18n/TextConversionOption.hpp>
+#include <com/sun/star/util/XFlushable.hpp>
+
+#include <comphelper/processfactory.hxx>
+#include <comphelper/string.hxx>
+
+#define HHC editeng::HangulHanjaConversion
+#define LINE_CNT static_cast< sal_uInt16 >(2)
+#define MAXNUM_SUGGESTIONS 50
+
+
+namespace svx
+{
+
+ using namespace ::com::sun::star;
+ using namespace css::uno;
+ using namespace css::linguistic2;
+ using namespace css::lang;
+ using namespace css::container;
+
+
+ namespace
+ {
+ class FontSwitch
+ {
+ private:
+ OutputDevice& m_rDev;
+
+ public:
+ FontSwitch( OutputDevice& _rDev, const vcl::Font& _rTemporaryFont )
+ :m_rDev( _rDev )
+ {
+ m_rDev.Push( PushFlags::FONT );
+ m_rDev.SetFont( _rTemporaryFont );
+ }
+ ~FontSwitch() COVERITY_NOEXCEPT_FALSE
+ {
+ m_rDev.Pop();
+ }
+ };
+
+ /** a class which allows to draw two texts in a pseudo-ruby way (which basically
+ means one text above or below the other, and a little bit smaller)
+ */
+ class PseudoRubyText
+ {
+ public:
+ enum RubyPosition
+ {
+ eAbove, eBelow
+ };
+
+ protected:
+ OUString m_sPrimaryText;
+ OUString m_sSecondaryText;
+ RubyPosition m_ePosition;
+
+ public:
+ PseudoRubyText();
+ void init( const OUString& rPrimaryText, const OUString& rSecondaryText, const RubyPosition& rPosition );
+ const OUString& getPrimaryText() const { return m_sPrimaryText; }
+ const OUString& getSecondaryText() const { return m_sSecondaryText; }
+
+ public:
+ void Paint( vcl::RenderContext& _rDevice, const ::tools::Rectangle& _rRect,
+ ::tools::Rectangle* _pPrimaryLocation, ::tools::Rectangle* _pSecondaryLocation );
+ };
+
+ }
+
+ PseudoRubyText::PseudoRubyText()
+ : m_ePosition(eAbove)
+ {
+ }
+
+ void PseudoRubyText::init( const OUString& rPrimaryText, const OUString& rSecondaryText, const RubyPosition& rPosition )
+ {
+ m_sPrimaryText = rPrimaryText;
+ m_sSecondaryText = rSecondaryText;
+ m_ePosition = rPosition;
+ }
+
+
+ void PseudoRubyText::Paint(vcl::RenderContext& rRenderContext, const ::tools::Rectangle& _rRect,
+ ::tools::Rectangle* _pPrimaryLocation, ::tools::Rectangle* _pSecondaryLocation )
+ {
+ // calculate the text flags for the painting
+ constexpr DrawTextFlags nTextStyle = DrawTextFlags::Mnemonic |
+ DrawTextFlags::Left |
+ DrawTextFlags::VCenter;
+
+ Size aPlaygroundSize(_rRect.GetSize());
+
+ // the font for the secondary text:
+ vcl::Font aSmallerFont(rRenderContext.GetFont());
+ // heuristic: 80% of the original size
+ aSmallerFont.SetFontHeight( static_cast<long>( 0.8 * aSmallerFont.GetFontHeight() ) );
+
+ // let's calculate the size of our two texts
+ ::tools::Rectangle aPrimaryRect = rRenderContext.GetTextRect( _rRect, m_sPrimaryText, nTextStyle );
+ ::tools::Rectangle aSecondaryRect;
+ {
+ FontSwitch aFontRestore(rRenderContext, aSmallerFont);
+ aSecondaryRect = rRenderContext.GetTextRect(_rRect, m_sSecondaryText, nTextStyle);
+ }
+
+ // position these rectangles properly
+ // x-axis:
+ sal_Int32 nCombinedWidth = std::max( aSecondaryRect.GetWidth(), aPrimaryRect.GetWidth() );
+ // the rectangle where both texts will reside is as high as possible, and as wide as the
+ // widest of both text rects
+ aPrimaryRect.SetLeft( _rRect.Left() );
+ aSecondaryRect.SetLeft( aPrimaryRect.Left() );
+ aPrimaryRect.SetRight( _rRect.Left() + nCombinedWidth );
+ aSecondaryRect.SetRight( aPrimaryRect.Right() );
+
+ // y-axis:
+ sal_Int32 nCombinedHeight = aPrimaryRect.GetHeight() + aSecondaryRect.GetHeight();
+ // align to the top, for the moment
+ aPrimaryRect.Move( 0, _rRect.Top() - aPrimaryRect.Top() );
+ aSecondaryRect.Move( 0, aPrimaryRect.Top() + aPrimaryRect.GetHeight() - aSecondaryRect.Top() );
+ // move the rects to the bottom
+ aPrimaryRect.Move( 0, ( aPlaygroundSize.Height() - nCombinedHeight ) / 2 );
+ aSecondaryRect.Move( 0, ( aPlaygroundSize.Height() - nCombinedHeight ) / 2 );
+
+ // 'til here, everything we did assumes that the secondary text is painted _below_ the primary
+ // text. If this isn't the case, we need to correct the rectangles
+ if (eAbove == m_ePosition)
+ {
+ sal_Int32 nVertDistance = aSecondaryRect.Top() - aPrimaryRect.Top();
+ aSecondaryRect.Move( 0, -nVertDistance );
+ aPrimaryRect.Move( 0, nCombinedHeight - nVertDistance );
+ }
+
+ // now draw the texts
+ // as we already calculated the precise rectangles for the texts, we don't want to
+ // use the alignment flags given - within it's rect, every text is centered
+ DrawTextFlags nDrawTextStyle( nTextStyle );
+ nDrawTextStyle &= ~DrawTextFlags( DrawTextFlags::Right | DrawTextFlags::Left | DrawTextFlags::Bottom | DrawTextFlags::Top );
+ nDrawTextStyle |= DrawTextFlags::Center | DrawTextFlags::VCenter;
+
+ rRenderContext.DrawText( aPrimaryRect, m_sPrimaryText, nDrawTextStyle );
+ {
+ FontSwitch aFontRestore(rRenderContext, aSmallerFont);
+ rRenderContext.DrawText( aSecondaryRect, m_sSecondaryText, nDrawTextStyle );
+ }
+
+ // outta here
+ if (_pPrimaryLocation)
+ *_pPrimaryLocation = aPrimaryRect;
+ if (_pSecondaryLocation)
+ *_pSecondaryLocation = aSecondaryRect;
+ }
+
+ class RubyRadioButton
+ {
+ public:
+ RubyRadioButton(std::unique_ptr<weld::RadioButton> xControl);
+ void init(const OUString& rPrimaryText, const OUString& rSecondaryText, const PseudoRubyText::RubyPosition& rPosition);
+
+ void set_sensitive(bool sensitive) { m_xControl->set_sensitive(sensitive); }
+ void set_active(bool active) { m_xControl->set_active(active); }
+ bool get_active() const { return m_xControl->get_active(); }
+
+ void connect_clicked(const Link<weld::Button&, void>& rLink) { m_xControl->connect_clicked(rLink); }
+
+ private:
+ Size GetOptimalSize() const;
+ void Paint(vcl::RenderContext& rRenderContext);
+
+ ScopedVclPtr<VirtualDevice> m_xVirDev;
+ std::unique_ptr<weld::RadioButton> m_xControl;
+ PseudoRubyText m_aRubyText;
+ };
+
+ RubyRadioButton::RubyRadioButton(std::unique_ptr<weld::RadioButton> xControl)
+ : m_xVirDev(xControl->create_virtual_device())
+ , m_xControl(std::move(xControl))
+ {
+ // expand the point size of the desired font to the equivalent pixel size
+ if (vcl::Window* pDefaultDevice = dynamic_cast<vcl::Window*>(Application::GetDefaultDevice()))
+ pDefaultDevice->SetPointFont(*m_xVirDev, m_xControl->get_font());
+ }
+
+ void RubyRadioButton::init( const OUString& rPrimaryText, const OUString& rSecondaryText, const PseudoRubyText::RubyPosition& rPosition )
+ {
+ m_aRubyText.init(rPrimaryText, rSecondaryText, rPosition);
+
+ m_xVirDev->SetOutputSizePixel(GetOptimalSize());
+
+ Paint(*m_xVirDev);
+
+ m_xControl->set_image(m_xVirDev.get());
+ }
+
+ void RubyRadioButton::Paint(vcl::RenderContext& rRenderContext)
+ {
+ ::tools::Rectangle aOverallRect(Point(0, 0), rRenderContext.GetOutputSizePixel());
+ // inflate the rect a little bit (because the VCL radio button does the same)
+ ::tools::Rectangle aTextRect( aOverallRect );
+ aTextRect.AdjustLeft( 1 ); aTextRect.AdjustRight( -1 );
+ aTextRect.AdjustTop( 1 ); aTextRect.AdjustBottom( -1 );
+
+ // paint the ruby text
+ ::tools::Rectangle aPrimaryTextLocation;
+ ::tools::Rectangle aSecondaryTextLocation;
+
+ m_aRubyText.Paint(rRenderContext, aTextRect, &aPrimaryTextLocation, &aSecondaryTextLocation);
+ }
+
+ Size RubyRadioButton::GetOptimalSize() const
+ {
+ vcl::Font aSmallerFont(m_xVirDev->GetFont());
+ aSmallerFont.SetFontHeight( static_cast<long>( 0.8 * aSmallerFont.GetFontHeight() ) );
+ ::tools::Rectangle rect( Point(), Size( SAL_MAX_INT32, SAL_MAX_INT32 ) );
+
+ Size aPrimarySize = m_xVirDev->GetTextRect( rect, m_aRubyText.getPrimaryText() ).GetSize();
+ Size aSecondarySize;
+ {
+ FontSwitch aFontRestore(*m_xVirDev, aSmallerFont);
+ aSecondarySize = m_xVirDev->GetTextRect( rect, m_aRubyText.getSecondaryText() ).GetSize();
+ }
+
+ Size minimumSize;
+ minimumSize.setHeight( aPrimarySize.Height() + aSecondarySize.Height() + 5 );
+ minimumSize.setWidth( aPrimarySize.Width() + aSecondarySize.Width() + 5 );
+ return minimumSize;
+ }
+
+ SuggestionSet::SuggestionSet(std::unique_ptr<weld::ScrolledWindow> xScrolledWindow)
+ : ValueSet(std::move(xScrolledWindow))
+
+ {
+ }
+
+ void SuggestionSet::UserDraw( const UserDrawEvent& rUDEvt )
+ {
+ vcl::RenderContext* pDev = rUDEvt.GetRenderContext();
+ ::tools::Rectangle aRect = rUDEvt.GetRect();
+ sal_uInt16 nItemId = rUDEvt.GetItemId();
+
+ OUString sText = *static_cast< OUString* >( GetItemData( nItemId ) );
+ pDev->DrawText( aRect, sText, DrawTextFlags::Center | DrawTextFlags::VCenter );
+ }
+
+ SuggestionDisplay::SuggestionDisplay(weld::Builder& rBuilder)
+ : m_bDisplayListBox( true )
+ , m_bInSelectionUpdate( false )
+ , m_xValueSet(new SuggestionSet(rBuilder.weld_scrolled_window("scrollwin")))
+ , m_xValueSetWin(new weld::CustomWeld(rBuilder, "valueset", *m_xValueSet))
+ , m_xListBox(rBuilder.weld_tree_view("listbox"))
+ {
+ m_xValueSet->SetSelectHdl( LINK( this, SuggestionDisplay, SelectSuggestionValueSetHdl ) );
+ m_xListBox->connect_changed( LINK( this, SuggestionDisplay, SelectSuggestionListBoxHdl ) );
+
+ m_xValueSet->SetLineCount( LINE_CNT );
+ m_xValueSet->SetStyle( m_xValueSet->GetStyle() | WB_ITEMBORDER | WB_VSCROLL );
+
+ OUString const aOneCharacter("AU");
+ auto nItemWidth = 2 * m_xListBox->get_pixel_size(aOneCharacter).Width();
+ m_xValueSet->SetItemWidth( nItemWidth );
+
+ Size aSize(m_xListBox->get_approximate_digit_width() * 42, m_xListBox->get_text_height() * 5);
+ m_xValueSet->set_size_request(aSize.Width(), aSize.Height());
+ m_xListBox->set_size_request(aSize.Width(), aSize.Height());
+
+ implUpdateDisplay();
+ }
+
+ void SuggestionDisplay::implUpdateDisplay()
+ {
+ m_xListBox->set_visible(m_bDisplayListBox);
+ if (!m_bDisplayListBox)
+ m_xValueSetWin->show();
+ else
+ m_xValueSetWin->hide();
+ }
+
+ weld::Widget& SuggestionDisplay::implGetCurrentControl()
+ {
+ if (m_bDisplayListBox)
+ return *m_xListBox;
+ return *m_xValueSet->GetDrawingArea();
+ }
+
+ void SuggestionDisplay::DisplayListBox( bool bDisplayListBox )
+ {
+ if( m_bDisplayListBox == bDisplayListBox )
+ return;
+
+ weld::Widget& rOldControl = implGetCurrentControl();
+ bool bHasFocus = rOldControl.has_focus();
+
+ m_bDisplayListBox = bDisplayListBox;
+
+ if( bHasFocus )
+ {
+ weld::Widget& rNewControl = implGetCurrentControl();
+ rNewControl.grab_focus();
+ }
+
+ implUpdateDisplay();
+ }
+
+ IMPL_LINK_NOARG(SuggestionDisplay, SelectSuggestionValueSetHdl, ValueSet*, void)
+ {
+ SelectSuggestionHdl(false);
+ }
+
+ IMPL_LINK_NOARG(SuggestionDisplay, SelectSuggestionListBoxHdl, weld::TreeView&, void)
+ {
+ SelectSuggestionHdl(true);
+ }
+
+ void SuggestionDisplay::SelectSuggestionHdl(bool bListBox)
+ {
+ if( m_bInSelectionUpdate )
+ return;
+
+ m_bInSelectionUpdate = true;
+ if (bListBox)
+ {
+ sal_uInt16 nPos = m_xListBox->get_selected_index();
+ m_xValueSet->SelectItem( nPos+1 ); //itemid == pos+1 (id 0 has special meaning)
+ }
+ else
+ {
+ sal_uInt16 nPos = m_xValueSet->GetSelectedItemId()-1; //itemid == pos+1 (id 0 has special meaning)
+ m_xListBox->select(nPos);
+ }
+ m_bInSelectionUpdate = false;
+ m_aSelectLink.Call( *this );
+ }
+
+ void SuggestionDisplay::SetSelectHdl( const Link<SuggestionDisplay&,void>& rLink )
+ {
+ m_aSelectLink = rLink;
+ }
+
+ void SuggestionDisplay::Clear()
+ {
+ m_xListBox->clear();
+ m_xValueSet->Clear();
+ }
+
+ void SuggestionDisplay::InsertEntry( const OUString& rStr )
+ {
+ m_xListBox->append_text(rStr);
+ sal_uInt16 nItemId = m_xListBox->n_children(); //itemid == pos+1 (id 0 has special meaning)
+ m_xValueSet->InsertItem( nItemId );
+ OUString* pItemData = new OUString( rStr );
+ m_xValueSet->SetItemData( nItemId, pItemData );
+ }
+
+ void SuggestionDisplay::SelectEntryPos( sal_uInt16 nPos )
+ {
+ m_xListBox->select(nPos);
+ m_xValueSet->SelectItem( nPos+1 ); //itemid == pos+1 (id 0 has special meaning)
+ }
+
+ sal_uInt16 SuggestionDisplay::GetEntryCount() const
+ {
+ return m_xListBox->n_children();
+ }
+
+ OUString SuggestionDisplay::GetEntry( sal_uInt16 nPos ) const
+ {
+ return m_xListBox->get_text( nPos );
+ }
+
+ OUString SuggestionDisplay::GetSelectedEntry() const
+ {
+ return m_xListBox->get_selected_text();
+ }
+
+ void SuggestionDisplay::SetHelpIds()
+ {
+ m_xValueSet->SetHelpId(HID_HANGULDLG_SUGGESTIONS_GRID);
+ m_xListBox->set_help_id(HID_HANGULDLG_SUGGESTIONS_LIST);
+ }
+
+ HangulHanjaConversionDialog::HangulHanjaConversionDialog(weld::Window* pParent)
+ : GenericDialogController(pParent, "cui/ui/hangulhanjaconversiondialog.ui", "HangulHanjaConversionDialog")
+ , m_bDocumentMode( true )
+ , m_xFind(m_xBuilder->weld_button("find"))
+ , m_xIgnore(m_xBuilder->weld_button("ignore"))
+ , m_xIgnoreAll(m_xBuilder->weld_button("ignoreall"))
+ , m_xReplace(m_xBuilder->weld_button("replace"))
+ , m_xReplaceAll(m_xBuilder->weld_button("replaceall"))
+ , m_xOptions(m_xBuilder->weld_button("options"))
+ , m_xSuggestions(new SuggestionDisplay(*m_xBuilder))
+ , m_xSimpleConversion(m_xBuilder->weld_radio_button("simpleconversion"))
+ , m_xHangulBracketed(m_xBuilder->weld_radio_button("hangulbracket"))
+ , m_xHanjaBracketed(m_xBuilder->weld_radio_button("hanjabracket"))
+ , m_xWordInput(m_xBuilder->weld_entry("wordinput"))
+ , m_xOriginalWord(m_xBuilder->weld_label("originalword"))
+ , m_xHanjaAbove(new RubyRadioButton(m_xBuilder->weld_radio_button("hanja_above")))
+ , m_xHanjaBelow(new RubyRadioButton(m_xBuilder->weld_radio_button("hanja_below")))
+ , m_xHangulAbove(new RubyRadioButton(m_xBuilder->weld_radio_button("hangul_above")))
+ , m_xHangulBelow(new RubyRadioButton(m_xBuilder->weld_radio_button("hangul_below")))
+ , m_xHangulOnly(m_xBuilder->weld_check_button("hangulonly"))
+ , m_xHanjaOnly(m_xBuilder->weld_check_button("hanjaonly"))
+ , m_xReplaceByChar(m_xBuilder->weld_check_button("replacebychar"))
+ {
+ m_xSuggestions->set_size_request(m_xOriginalWord->get_approximate_digit_width() * 42,
+ m_xOriginalWord->get_text_height() * 5);
+
+ const OUString sHangul(CuiResId(RID_SVXSTR_HANGUL));
+ const OUString sHanja(CuiResId(RID_SVXSTR_HANJA));
+ m_xHanjaAbove->init( sHangul, sHanja, PseudoRubyText::eAbove );
+ m_xHanjaBelow->init( sHangul, sHanja, PseudoRubyText::eBelow );
+ m_xHangulAbove->init( sHanja, sHangul, PseudoRubyText::eAbove );
+ m_xHangulBelow->init( sHanja, sHangul, PseudoRubyText::eBelow );
+
+ m_xWordInput->connect_changed( LINK( this, HangulHanjaConversionDialog, OnSuggestionModified ) );
+ m_xSuggestions->SetSelectHdl( LINK( this, HangulHanjaConversionDialog, OnSuggestionSelected ) );
+ m_xReplaceByChar->connect_toggled( LINK( this, HangulHanjaConversionDialog, ClickByCharacterHdl ) );
+ m_xHangulOnly->connect_toggled( LINK( this, HangulHanjaConversionDialog, OnConversionDirectionClicked ) );
+ m_xHanjaOnly->connect_toggled( LINK( this, HangulHanjaConversionDialog, OnConversionDirectionClicked ) );
+ m_xOptions->connect_clicked(LINK(this, HangulHanjaConversionDialog, OnOption));
+
+ // initial focus
+ FocusSuggestion( );
+
+ // initial control values
+ m_xSimpleConversion->set_active(true);
+
+ m_xSuggestions->SetHelpIds();
+ }
+
+ HangulHanjaConversionDialog::~HangulHanjaConversionDialog()
+ {
+ }
+
+ void HangulHanjaConversionDialog::FillSuggestions( const css::uno::Sequence< OUString >& _rSuggestions )
+ {
+ m_xSuggestions->Clear();
+ for ( auto const & suggestion : _rSuggestions )
+ m_xSuggestions->InsertEntry( suggestion );
+
+ // select the first suggestion, and fill in the suggestion edit field
+ OUString sFirstSuggestion;
+ if ( m_xSuggestions->GetEntryCount() )
+ {
+ sFirstSuggestion = m_xSuggestions->GetEntry( 0 );
+ m_xSuggestions->SelectEntryPos( 0 );
+ }
+ m_xWordInput->set_text( sFirstSuggestion );
+ m_xWordInput->save_value();
+ OnSuggestionModified( *m_xWordInput );
+ }
+
+ void HangulHanjaConversionDialog::SetOptionsChangedHdl(const Link<LinkParamNone*,void>& rHdl)
+ {
+ m_aOptionsChangedLink = rHdl;
+ }
+
+ void HangulHanjaConversionDialog::SetIgnoreHdl(const Link<weld::Button&,void>& rHdl)
+ {
+ m_xIgnore->connect_clicked(rHdl);
+ }
+
+ void HangulHanjaConversionDialog::SetIgnoreAllHdl(const Link<weld::Button&,void>& rHdl)
+ {
+ m_xIgnoreAll->connect_clicked(rHdl);
+ }
+
+ void HangulHanjaConversionDialog::SetChangeHdl(const Link<weld::Button&,void>& rHdl )
+ {
+ m_xReplace->connect_clicked(rHdl);
+ }
+
+ void HangulHanjaConversionDialog::SetChangeAllHdl(const Link<weld::Button&,void>& rHdl)
+ {
+ m_xReplaceAll->connect_clicked(rHdl);
+ }
+
+ void HangulHanjaConversionDialog::SetFindHdl(const Link<weld::Button&,void>& rHdl)
+ {
+ m_xFind->connect_clicked(rHdl);
+ }
+
+ void HangulHanjaConversionDialog::SetConversionFormatChangedHdl( const Link<weld::Button&,void>& rHdl )
+ {
+ m_xSimpleConversion->connect_clicked( rHdl );
+ m_xHangulBracketed->connect_clicked( rHdl );
+ m_xHanjaBracketed->connect_clicked( rHdl );
+ m_xHanjaAbove->connect_clicked( rHdl );
+ m_xHanjaBelow->connect_clicked( rHdl );
+ m_xHangulAbove->connect_clicked( rHdl );
+ m_xHangulBelow->connect_clicked( rHdl );
+ }
+
+ void HangulHanjaConversionDialog::SetClickByCharacterHdl( const Link<weld::ToggleButton&,void>& _rHdl )
+ {
+ m_aClickByCharacterLink = _rHdl;
+ }
+
+ IMPL_LINK_NOARG( HangulHanjaConversionDialog, OnSuggestionSelected, SuggestionDisplay&, void )
+ {
+ m_xWordInput->set_text(m_xSuggestions->GetSelectedEntry());
+ OnSuggestionModified( *m_xWordInput );
+ }
+
+ IMPL_LINK_NOARG( HangulHanjaConversionDialog, OnSuggestionModified, weld::Entry&, void )
+ {
+ m_xFind->set_sensitive(m_xWordInput->get_value_changed_from_saved());
+
+ bool bSameLen = m_xWordInput->get_text().getLength() == m_xOriginalWord->get_label().getLength();
+ m_xReplace->set_sensitive( m_bDocumentMode && bSameLen );
+ m_xReplaceAll->set_sensitive( m_bDocumentMode && bSameLen );
+ }
+
+ IMPL_LINK(HangulHanjaConversionDialog, ClickByCharacterHdl, weld::ToggleButton&, rBox, void)
+ {
+ m_aClickByCharacterLink.Call(rBox);
+ bool bByCharacter = rBox.get_active();
+ m_xSuggestions->DisplayListBox( !bByCharacter );
+ }
+
+ IMPL_LINK(HangulHanjaConversionDialog, OnConversionDirectionClicked, weld::ToggleButton&, rBox, void)
+ {
+ weld::CheckButton* pOtherBox = nullptr;
+ if (&rBox == m_xHangulOnly.get())
+ pOtherBox = m_xHanjaOnly.get();
+ else
+ pOtherBox = m_xHangulOnly.get();
+ bool bBoxChecked = rBox.get_active();
+ if (bBoxChecked)
+ pOtherBox->set_active(false);
+ pOtherBox->set_sensitive(!bBoxChecked);
+ }
+
+ IMPL_LINK_NOARG(HangulHanjaConversionDialog, OnOption, weld::Button&, void)
+ {
+ HangulHanjaOptionsDialog aOptDlg(m_xDialog.get());
+ aOptDlg.run();
+ m_aOptionsChangedLink.Call( nullptr );
+ }
+
+ OUString HangulHanjaConversionDialog::GetCurrentString( ) const
+ {
+ return m_xOriginalWord->get_label();
+ }
+
+ void HangulHanjaConversionDialog::FocusSuggestion( )
+ {
+ m_xWordInput->grab_focus();
+ }
+
+ void HangulHanjaConversionDialog::SetCurrentString( const OUString& _rNewString,
+ const Sequence< OUString >& _rSuggestions, bool _bOriginatesFromDocument )
+ {
+ m_xOriginalWord->set_label(_rNewString);
+
+ bool bOldDocumentMode = m_bDocumentMode;
+ m_bDocumentMode = _bOriginatesFromDocument; // before FillSuggestions!
+ FillSuggestions( _rSuggestions );
+
+ m_xIgnoreAll->set_sensitive( m_bDocumentMode );
+
+ // switch the def button depending if we're working for document text
+ if (bOldDocumentMode == m_bDocumentMode)
+ return;
+
+ weld::Widget* pOldDefButton = nullptr;
+ weld::Widget* pNewDefButton = nullptr;
+ if (m_bDocumentMode)
+ {
+ pOldDefButton = m_xFind.get();
+ pNewDefButton = m_xReplace.get();
+ }
+ else
+ {
+ pOldDefButton = m_xReplace.get();
+ pNewDefButton = m_xFind.get();
+ }
+
+ pOldDefButton->set_has_default(false);
+ pNewDefButton->set_has_default(true);
+ }
+
+ OUString HangulHanjaConversionDialog::GetCurrentSuggestion( ) const
+ {
+ return m_xWordInput->get_text();
+ }
+
+ void HangulHanjaConversionDialog::SetByCharacter( bool _bByCharacter )
+ {
+ m_xReplaceByChar->set_active( _bByCharacter );
+ m_xSuggestions->DisplayListBox( !_bByCharacter );
+ }
+
+ void HangulHanjaConversionDialog::SetConversionDirectionState(
+ bool _bTryBothDirections,
+ HHC::ConversionDirection ePrimaryConversionDirection )
+ {
+ // default state: try both direction
+ m_xHangulOnly->set_active( false );
+ m_xHangulOnly->set_sensitive(true);
+ m_xHanjaOnly->set_active( false );
+ m_xHanjaOnly->set_sensitive(true);
+
+ if (!_bTryBothDirections)
+ {
+ weld::CheckButton* pBox = ePrimaryConversionDirection == HHC::eHangulToHanja ?
+ m_xHangulOnly.get() : m_xHanjaOnly.get();
+ pBox->set_active(true);
+ OnConversionDirectionClicked(*pBox);
+ }
+ }
+
+ bool HangulHanjaConversionDialog::GetUseBothDirections( ) const
+ {
+ return !m_xHangulOnly->get_active() && !m_xHanjaOnly->get_active();
+ }
+
+ HHC::ConversionDirection HangulHanjaConversionDialog::GetDirection(
+ HHC::ConversionDirection eDefaultDirection ) const
+ {
+ HHC::ConversionDirection eDirection = eDefaultDirection;
+ if (m_xHangulOnly->get_active() && !m_xHanjaOnly->get_active())
+ eDirection = HHC::eHangulToHanja;
+ else if (!m_xHangulOnly->get_active() && m_xHanjaOnly->get_active())
+ eDirection = HHC::eHanjaToHangul;
+ return eDirection;
+ }
+
+ void HangulHanjaConversionDialog::SetConversionFormat( HHC::ConversionFormat _eType )
+ {
+ switch ( _eType )
+ {
+ case HHC::eSimpleConversion: m_xSimpleConversion->set_active(true); break;
+ case HHC::eHangulBracketed: m_xHangulBracketed->set_active(true); break;
+ case HHC::eHanjaBracketed: m_xHanjaBracketed->set_active(true); break;
+ case HHC::eRubyHanjaAbove: m_xHanjaAbove->set_active(true); break;
+ case HHC::eRubyHanjaBelow: m_xHanjaBelow->set_active(true); break;
+ case HHC::eRubyHangulAbove: m_xHangulAbove->set_active(true); break;
+ case HHC::eRubyHangulBelow: m_xHangulBelow->set_active(true); break;
+ default:
+ OSL_FAIL( "HangulHanjaConversionDialog::SetConversionFormat: unknown type!" );
+ }
+ }
+
+ HHC::ConversionFormat HangulHanjaConversionDialog::GetConversionFormat( ) const
+ {
+ if ( m_xSimpleConversion->get_active() )
+ return HHC::eSimpleConversion;
+ if ( m_xHangulBracketed->get_active() )
+ return HHC::eHangulBracketed;
+ if ( m_xHanjaBracketed->get_active() )
+ return HHC::eHanjaBracketed;
+ if ( m_xHanjaAbove->get_active() )
+ return HHC::eRubyHanjaAbove;
+ if ( m_xHanjaBelow->get_active() )
+ return HHC::eRubyHanjaBelow;
+ if ( m_xHangulAbove->get_active() )
+ return HHC::eRubyHangulAbove;
+ if ( m_xHangulBelow->get_active() )
+ return HHC::eRubyHangulBelow;
+
+ OSL_FAIL( "HangulHanjaConversionDialog::GetConversionFormat: no radio checked?" );
+ return HHC::eSimpleConversion;
+ }
+
+ void HangulHanjaConversionDialog::EnableRubySupport( bool bVal )
+ {
+ m_xHanjaAbove->set_sensitive( bVal );
+ m_xHanjaBelow->set_sensitive( bVal );
+ m_xHangulAbove->set_sensitive( bVal );
+ m_xHangulBelow->set_sensitive( bVal );
+ }
+
+ void HangulHanjaOptionsDialog::Init()
+ {
+ if( !m_xConversionDictionaryList.is() )
+ {
+ m_xConversionDictionaryList = ConversionDictionaryList::create( ::comphelper::getProcessComponentContext() );
+ }
+
+ m_aDictList.clear();
+ m_xDictsLB->clear();
+
+ Reference< XNameContainer > xNameCont = m_xConversionDictionaryList->getDictionaryContainer();
+ if( xNameCont.is() )
+ {
+ Sequence< OUString > aDictNames( xNameCont->getElementNames() );
+
+ const OUString* pDic = aDictNames.getConstArray();
+ sal_Int32 nCount = aDictNames.getLength();
+
+ sal_Int32 i;
+ for( i = 0 ; i < nCount ; ++i )
+ {
+ Any aAny( xNameCont->getByName( pDic[ i ] ) );
+ Reference< XConversionDictionary > xDic;
+ if( ( aAny >>= xDic ) && xDic.is() )
+ {
+ if( LANGUAGE_KOREAN == LanguageTag( xDic->getLocale() ).getLanguageType() )
+ {
+ m_aDictList.push_back( xDic );
+ AddDict( xDic->getName(), xDic->isActive() );
+ }
+ }
+ }
+ }
+ if (m_xDictsLB->n_children())
+ m_xDictsLB->select(0);
+ }
+
+ IMPL_LINK_NOARG(HangulHanjaOptionsDialog, OkHdl, weld::Button&, void)
+ {
+ sal_uInt32 nCnt = m_aDictList.size();
+ sal_uInt32 n = 0;
+ sal_uInt32 nActiveDics = 0;
+ Sequence< OUString > aActiveDics;
+
+ aActiveDics.realloc( nCnt );
+ OUString* pActActiveDic = aActiveDics.getArray();
+
+ while( nCnt )
+ {
+ Reference< XConversionDictionary > xDict = m_aDictList[ n ];
+
+ DBG_ASSERT( xDict.is(), "-HangulHanjaOptionsDialog::OkHdl(): someone is evaporated..." );
+
+ bool bActive = m_xDictsLB->get_toggle(n, 0) == TRISTATE_TRUE;
+ xDict->setActive( bActive );
+ Reference< util::XFlushable > xFlush( xDict, uno::UNO_QUERY );
+ if( xFlush.is() )
+ xFlush->flush();
+
+ if( bActive )
+ {
+ pActActiveDic[ nActiveDics ] = xDict->getName();
+ ++nActiveDics;
+ }
+
+ ++n;
+ --nCnt;
+ }
+
+ // save configuration
+ aActiveDics.realloc( nActiveDics );
+ Any aTmp;
+ SvtLinguConfig aLngCfg;
+ aTmp <<= aActiveDics;
+ aLngCfg.SetProperty( UPH_ACTIVE_CONVERSION_DICTIONARIES, aTmp );
+
+ aTmp <<= m_xIgnorepostCB->get_active();
+ aLngCfg.SetProperty( UPH_IS_IGNORE_POST_POSITIONAL_WORD, aTmp );
+
+ aTmp <<= m_xShowrecentlyfirstCB->get_active();
+ aLngCfg.SetProperty( UPH_IS_SHOW_ENTRIES_RECENTLY_USED_FIRST, aTmp );
+
+ aTmp <<= m_xAutoreplaceuniqueCB->get_active();
+ aLngCfg.SetProperty( UPH_IS_AUTO_REPLACE_UNIQUE_ENTRIES, aTmp );
+
+ m_xDialog->response(RET_OK);
+ }
+
+ IMPL_LINK_NOARG(HangulHanjaOptionsDialog, DictsLB_SelectHdl, weld::TreeView&, void)
+ {
+ bool bSel = m_xDictsLB->get_selected_index() != -1;
+
+ m_xEditPB->set_sensitive(bSel);
+ m_xDeletePB->set_sensitive(bSel);
+ }
+
+ IMPL_LINK_NOARG(HangulHanjaOptionsDialog, NewDictHdl, weld::Button&, void)
+ {
+ OUString aName;
+ HangulHanjaNewDictDialog aNewDlg(m_xDialog.get());
+ aNewDlg.run();
+ if (!aNewDlg.GetName(aName))
+ return;
+
+ if( !m_xConversionDictionaryList.is() )
+ return;
+
+ try
+ {
+ Reference< XConversionDictionary > xDic =
+ m_xConversionDictionaryList->addNewDictionary( aName, LanguageTag::convertToLocale( LANGUAGE_KOREAN ), ConversionDictionaryType::HANGUL_HANJA );
+
+ if( xDic.is() )
+ {
+ //adapt local caches:
+ m_aDictList.push_back( xDic );
+ AddDict( xDic->getName(), xDic->isActive() );
+ }
+ }
+ catch( const ElementExistException& )
+ {
+ }
+ catch( const NoSupportException& )
+ {
+ }
+ }
+
+ IMPL_LINK_NOARG(HangulHanjaOptionsDialog, EditDictHdl, weld::Button&, void)
+ {
+ int nEntry = m_xDictsLB->get_selected_index();
+ DBG_ASSERT(nEntry != -1, "+HangulHanjaEditDictDialog::EditDictHdl(): call of edit should not be possible with no selection!");
+ if (nEntry != -1)
+ {
+ HangulHanjaEditDictDialog aEdDlg(m_xDialog.get(), m_aDictList, nEntry);
+ aEdDlg.run();
+ }
+ }
+
+ IMPL_LINK_NOARG(HangulHanjaOptionsDialog, DeleteDictHdl, weld::Button&, void)
+ {
+ int nSelPos = m_xDictsLB->get_selected_index();
+ if (nSelPos == -1)
+ return;
+
+ Reference< XConversionDictionary > xDic( m_aDictList[ nSelPos ] );
+ if( !(m_xConversionDictionaryList.is() && xDic.is()) )
+ return;
+
+ Reference< XNameContainer > xNameCont = m_xConversionDictionaryList->getDictionaryContainer();
+ if( !xNameCont.is() )
+ return;
+
+ try
+ {
+ xNameCont->removeByName( xDic->getName() );
+
+ //adapt local caches:
+ m_aDictList.erase(m_aDictList.begin()+nSelPos );
+ m_xDictsLB->remove(nSelPos);
+ }
+ catch( const ElementExistException& )
+ {
+ }
+ catch( const NoSupportException& )
+ {
+ }
+ }
+
+ HangulHanjaOptionsDialog::HangulHanjaOptionsDialog(weld::Window* pParent)
+ : GenericDialogController(pParent, "cui/ui/hangulhanjaoptdialog.ui", "HangulHanjaOptDialog")
+ , m_xDictsLB(m_xBuilder->weld_tree_view("dicts"))
+ , m_xIgnorepostCB(m_xBuilder->weld_check_button("ignorepost"))
+ , m_xShowrecentlyfirstCB(m_xBuilder->weld_check_button("showrecentfirst"))
+ , m_xAutoreplaceuniqueCB(m_xBuilder->weld_check_button("autoreplaceunique"))
+ , m_xNewPB(m_xBuilder->weld_button("new"))
+ , m_xEditPB(m_xBuilder->weld_button("edit"))
+ , m_xDeletePB(m_xBuilder->weld_button("delete"))
+ , m_xOkPB(m_xBuilder->weld_button("ok"))
+ {
+ m_xDictsLB->set_size_request(m_xDictsLB->get_approximate_digit_width() * 32,
+ m_xDictsLB->get_height_rows(5));
+
+ std::vector<int> aWidths;
+ aWidths.push_back(m_xDictsLB->get_checkbox_column_width());
+ m_xDictsLB->set_column_fixed_widths(aWidths);
+
+ m_xDictsLB->connect_changed( LINK( this, HangulHanjaOptionsDialog, DictsLB_SelectHdl ) );
+
+ m_xOkPB->connect_clicked( LINK( this, HangulHanjaOptionsDialog, OkHdl ) );
+ m_xNewPB->connect_clicked( LINK( this, HangulHanjaOptionsDialog, NewDictHdl ) );
+ m_xEditPB->connect_clicked( LINK( this, HangulHanjaOptionsDialog, EditDictHdl ) );
+ m_xDeletePB->connect_clicked( LINK( this, HangulHanjaOptionsDialog, DeleteDictHdl ) );
+
+ SvtLinguConfig aLngCfg;
+ Any aTmp;
+ bool bVal = bool();
+ aTmp = aLngCfg.GetProperty( UPH_IS_IGNORE_POST_POSITIONAL_WORD );
+ if( aTmp >>= bVal )
+ m_xIgnorepostCB->set_active( bVal );
+
+ aTmp = aLngCfg.GetProperty( UPH_IS_SHOW_ENTRIES_RECENTLY_USED_FIRST );
+ if( aTmp >>= bVal )
+ m_xShowrecentlyfirstCB->set_active( bVal );
+
+ aTmp = aLngCfg.GetProperty( UPH_IS_AUTO_REPLACE_UNIQUE_ENTRIES );
+ if( aTmp >>= bVal )
+ m_xAutoreplaceuniqueCB->set_active( bVal );
+
+ Init();
+ }
+
+ HangulHanjaOptionsDialog::~HangulHanjaOptionsDialog()
+ {
+ }
+
+ void HangulHanjaOptionsDialog::AddDict(const OUString& rName, bool bChecked)
+ {
+ m_xDictsLB->append();
+ int nRow = m_xDictsLB->n_children() - 1;
+ m_xDictsLB->set_toggle(nRow, bChecked ? TRISTATE_TRUE : TRISTATE_FALSE, 0);
+ m_xDictsLB->set_text(nRow, rName, 1);
+ m_xDictsLB->set_id(nRow, rName);
+ }
+
+ IMPL_LINK_NOARG(HangulHanjaNewDictDialog, OKHdl, weld::Button&, void)
+ {
+ OUString aName(comphelper::string::stripEnd(m_xDictNameED->get_text(), ' '));
+
+ m_bEntered = !aName.isEmpty();
+ if (m_bEntered)
+ m_xDictNameED->set_text(aName); // do this in case of trailing chars have been deleted
+
+ m_xDialog->response(RET_OK);
+ }
+
+ IMPL_LINK_NOARG(HangulHanjaNewDictDialog, ModifyHdl, weld::Entry&, void)
+ {
+ OUString aName(comphelper::string::stripEnd(m_xDictNameED->get_text(), ' '));
+
+ m_xOkBtn->set_sensitive(!aName.isEmpty());
+ }
+
+ HangulHanjaNewDictDialog::HangulHanjaNewDictDialog(weld::Window* pParent)
+ : GenericDialogController(pParent, "cui/ui/hangulhanjaadddialog.ui", "HangulHanjaAddDialog")
+ , m_bEntered(false)
+ , m_xOkBtn(m_xBuilder->weld_button("ok"))
+ , m_xDictNameED(m_xBuilder->weld_entry("entry"))
+ {
+ m_xOkBtn->connect_clicked( LINK( this, HangulHanjaNewDictDialog, OKHdl ) );
+ m_xDictNameED->connect_changed( LINK( this, HangulHanjaNewDictDialog, ModifyHdl ) );
+ }
+
+ HangulHanjaNewDictDialog::~HangulHanjaNewDictDialog()
+ {
+ }
+
+ bool HangulHanjaNewDictDialog::GetName( OUString& _rRetName ) const
+ {
+ if( m_bEntered )
+ _rRetName = comphelper::string::stripEnd(m_xDictNameED->get_text(), ' ');
+
+ return m_bEntered;
+ }
+
+ class SuggestionList
+ {
+ private:
+ protected:
+ std::vector<OUString> m_vElements;
+ sal_uInt16 m_nNumOfEntries;
+ // index of the internal iterator, used for First() and Next() methods
+ sal_uInt16 m_nAct;
+
+ const OUString* Next_();
+ public:
+ SuggestionList();
+ ~SuggestionList();
+
+ void Set( const OUString& _rElement, sal_uInt16 _nNumOfElement );
+ void Reset( sal_uInt16 _nNumOfElement );
+ const OUString & Get( sal_uInt16 _nNumOfElement ) const;
+ void Clear();
+
+ const OUString* First();
+ const OUString* Next();
+
+ sal_uInt16 GetCount() const { return m_nNumOfEntries; }
+ };
+
+ SuggestionList::SuggestionList() :
+ m_vElements(MAXNUM_SUGGESTIONS)
+ {
+ m_nAct = m_nNumOfEntries = 0;
+ }
+
+ SuggestionList::~SuggestionList()
+ {
+ Clear();
+ }
+
+ void SuggestionList::Set( const OUString& _rElement, sal_uInt16 _nNumOfElement )
+ {
+ m_vElements[_nNumOfElement] = _rElement;
+ ++m_nNumOfEntries;
+ }
+
+ void SuggestionList::Reset( sal_uInt16 _nNumOfElement )
+ {
+ m_vElements[_nNumOfElement].clear();
+ --m_nNumOfEntries;
+ }
+
+ const OUString& SuggestionList::Get( sal_uInt16 _nNumOfElement ) const
+ {
+ return m_vElements[_nNumOfElement];
+ }
+
+ void SuggestionList::Clear()
+ {
+ if( m_nNumOfEntries )
+ {
+ for (auto & vElement : m_vElements)
+ vElement.clear();
+ m_nNumOfEntries = m_nAct = 0;
+ }
+ }
+
+ const OUString* SuggestionList::Next_()
+ {
+ while( m_nAct < m_vElements.size() )
+ {
+ auto & s = m_vElements[ m_nAct ];
+ if (!s.isEmpty())
+ return &s;
+ ++m_nAct;
+ }
+
+ return nullptr;
+ }
+
+ const OUString* SuggestionList::First()
+ {
+ m_nAct = 0;
+ return Next_();
+ }
+
+ const OUString* SuggestionList::Next()
+ {
+ const OUString* pRet;
+
+ if( m_nAct < m_nNumOfEntries )
+ {
+ ++m_nAct;
+ pRet = Next_();
+ }
+ else
+ pRet = nullptr;
+
+ return pRet;
+ }
+
+
+ bool SuggestionEdit::ShouldScroll( bool _bUp ) const
+ {
+ bool bRet = false;
+
+ if( _bUp )
+ {
+ if( !m_pPrev )
+ bRet = m_pScrollBar->vadjustment_get_value() > m_pScrollBar->vadjustment_get_lower();
+ }
+ else
+ {
+ if( !m_pNext )
+ bRet = m_pScrollBar->vadjustment_get_value() < ( m_pScrollBar->vadjustment_get_upper() - 4 );
+ }
+
+ return bRet;
+ }
+
+ void SuggestionEdit::DoJump( bool _bUp )
+ {
+ m_pScrollBar->vadjustment_set_value( m_pScrollBar->vadjustment_get_value() + ( _bUp? -1 : 1 ) );
+ m_pParent->UpdateScrollbar();
+ }
+
+ SuggestionEdit::SuggestionEdit(std::unique_ptr<weld::Entry> xEntry, HangulHanjaEditDictDialog* pParent)
+ : m_pParent(pParent)
+ , m_pPrev(nullptr)
+ , m_pNext(nullptr)
+ , m_pScrollBar(nullptr)
+ , m_xEntry(std::move(xEntry))
+ {
+ m_xEntry->connect_key_press(LINK(this, SuggestionEdit, KeyInputHdl));
+ }
+
+ IMPL_LINK(SuggestionEdit, KeyInputHdl, 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 ) )
+ {
+ bool bUp = KEY_SHIFT == nMod;
+ if( ShouldScroll( bUp ) )
+ {
+ DoJump( bUp );
+ m_xEntry->select_region(0, -1);
+ // Tab-travel doesn't really happen, so emulate it by setting a selection manually
+ bHandled = true;
+ }
+ }
+ else if( KEY_UP == nCode || KEY_DOWN == nCode )
+ {
+ bool bUp = KEY_UP == nCode;
+ if( ShouldScroll( bUp ) )
+ {
+ DoJump( bUp );
+ bHandled = true;
+ }
+ else if( bUp )
+ {
+ if( m_pPrev )
+ {
+ m_pPrev->grab_focus();
+ bHandled = true;
+ }
+ }
+ else if( m_pNext )
+ {
+ m_pNext->grab_focus();
+ bHandled = true;
+ }
+ }
+
+ return bHandled;
+ }
+
+ void SuggestionEdit::init(weld::ScrolledWindow* pScrollBar, SuggestionEdit* pPrev, SuggestionEdit* pNext)
+ {
+ m_pScrollBar = pScrollBar;
+ m_pPrev = pPrev;
+ m_pNext = pNext;
+ }
+
+ namespace
+ {
+ bool GetConversions( const Reference< XConversionDictionary >& _xDict,
+ const OUString& _rOrg,
+ Sequence< OUString >& _rEntries )
+ {
+ bool bRet = false;
+ if( _xDict.is() && !_rOrg.isEmpty() )
+ {
+ try
+ {
+ _rEntries = _xDict->getConversions( _rOrg,
+ 0,
+ _rOrg.getLength(),
+ ConversionDirection_FROM_LEFT,
+ css::i18n::TextConversionOption::NONE );
+ bRet = _rEntries.hasElements();
+ }
+ catch( const IllegalArgumentException& )
+ {
+ }
+ }
+
+ return bRet;
+ }
+ }
+
+ IMPL_LINK_NOARG( HangulHanjaEditDictDialog, ScrollHdl, weld::ScrolledWindow&, void )
+ {
+ UpdateScrollbar();
+ }
+
+ IMPL_LINK_NOARG( HangulHanjaEditDictDialog, OriginalModifyHdl, weld::ComboBox&, void )
+ {
+ m_bModifiedOriginal = true;
+ m_aOriginal = comphelper::string::stripEnd( m_xOriginalLB->get_active_text(), ' ' );
+
+ UpdateSuggestions();
+ UpdateButtonStates();
+ }
+
+ IMPL_LINK( HangulHanjaEditDictDialog, EditModifyHdl1, weld::Entry&, rEdit, void )
+ {
+ EditModify( &rEdit, 0 );
+ }
+
+ IMPL_LINK( HangulHanjaEditDictDialog, EditModifyHdl2, weld::Entry&, rEdit, void )
+ {
+ EditModify( &rEdit, 1 );
+ }
+
+ IMPL_LINK( HangulHanjaEditDictDialog, EditModifyHdl3, weld::Entry&, rEdit, void )
+ {
+ EditModify( &rEdit, 2 );
+ }
+
+ IMPL_LINK( HangulHanjaEditDictDialog, EditModifyHdl4, weld::Entry&, rEdit, void )
+ {
+ EditModify( &rEdit, 3 );
+ }
+
+ IMPL_LINK_NOARG( HangulHanjaEditDictDialog, BookLBSelectHdl, weld::ComboBox&, void )
+ {
+ InitEditDictDialog( m_xBookLB->get_active() );
+ }
+
+ IMPL_LINK_NOARG( HangulHanjaEditDictDialog, NewPBPushHdl, weld::Button&, void )
+ {
+ DBG_ASSERT( m_xSuggestions, "-HangulHanjaEditDictDialog::NewPBPushHdl(): no suggestions... search in hell..." );
+ Reference< XConversionDictionary > xDict = m_rDictList[ m_nCurrentDict ];
+ if( xDict.is() && m_xSuggestions )
+ {
+ //delete old entry
+ bool bRemovedSomething = DeleteEntryFromDictionary( xDict );
+
+ OUString aLeft( m_aOriginal );
+ const OUString* pRight = m_xSuggestions->First();
+ bool bAddedSomething = false;
+ while( pRight )
+ {
+ try
+ {
+ //add new entry
+ xDict->addEntry( aLeft, *pRight );
+ bAddedSomething = true;
+ }
+ catch( const IllegalArgumentException& )
+ {
+ }
+ catch( const ElementExistException& )
+ {
+ }
+
+ pRight = m_xSuggestions->Next();
+ }
+
+ if( bAddedSomething || bRemovedSomething )
+ InitEditDictDialog( m_nCurrentDict );
+ }
+ else
+ {
+ SAL_INFO( "cui.dialogs", "dictionary faded away..." );
+ }
+ }
+
+ bool HangulHanjaEditDictDialog::DeleteEntryFromDictionary( const Reference< XConversionDictionary >& xDict )
+ {
+ bool bRemovedSomething = false;
+ if( xDict.is() )
+ {
+ OUString aOrg( m_aOriginal );
+ Sequence< OUString > aEntries;
+ GetConversions( xDict, m_aOriginal, aEntries );
+
+ sal_uInt32 n = aEntries.getLength();
+ OUString* pEntry = aEntries.getArray();
+ while( n )
+ {
+ try
+ {
+ xDict->removeEntry( aOrg, *pEntry );
+ bRemovedSomething = true;
+ }
+ catch( const NoSuchElementException& )
+ { // can not be...
+ }
+
+ ++pEntry;
+ --n;
+ }
+ }
+ return bRemovedSomething;
+ }
+
+ IMPL_LINK_NOARG( HangulHanjaEditDictDialog, DeletePBPushHdl, weld::Button&, void )
+ {
+ if( DeleteEntryFromDictionary( m_rDictList[ m_nCurrentDict ] ) )
+ {
+ m_aOriginal.clear();
+ m_bModifiedOriginal = true;
+ InitEditDictDialog( m_nCurrentDict );
+ }
+ }
+
+ void HangulHanjaEditDictDialog::InitEditDictDialog( sal_uInt32 nSelDict )
+ {
+ if( m_xSuggestions )
+ m_xSuggestions->Clear();
+
+ if( m_nCurrentDict != nSelDict )
+ {
+ m_nCurrentDict = nSelDict;
+ m_aOriginal.clear();
+ m_bModifiedOriginal = true;
+ }
+
+ UpdateOriginalLB();
+
+ m_xOriginalLB->set_entry_text( !m_aOriginal.isEmpty() ? m_aOriginal : m_aEditHintText);
+ m_xOriginalLB->select_entry_region(0, -1);
+ m_xOriginalLB->grab_focus();
+
+ UpdateSuggestions();
+ UpdateButtonStates();
+ }
+
+ void HangulHanjaEditDictDialog::UpdateOriginalLB()
+ {
+ m_xOriginalLB->clear();
+ Reference< XConversionDictionary > xDict = m_rDictList[ m_nCurrentDict ];
+ if( xDict.is() )
+ {
+ Sequence< OUString > aEntries = xDict->getConversionEntries( ConversionDirection_FROM_LEFT );
+ sal_uInt32 n = aEntries.getLength();
+ OUString* pEntry = aEntries.getArray();
+ while( n )
+ {
+ m_xOriginalLB->append_text( *pEntry );
+
+ ++pEntry;
+ --n;
+ }
+ }
+ else
+ {
+ SAL_INFO( "cui.dialogs", "dictionary faded away..." );
+ }
+ }
+
+ void HangulHanjaEditDictDialog::UpdateButtonStates()
+ {
+ bool bHaveValidOriginalString = !m_aOriginal.isEmpty() && m_aOriginal != m_aEditHintText;
+ bool bNew = bHaveValidOriginalString && m_xSuggestions && m_xSuggestions->GetCount() > 0;
+ bNew = bNew && ( m_bModifiedSuggestions || m_bModifiedOriginal );
+
+ m_xNewPB->set_sensitive( bNew );
+ m_xDeletePB->set_sensitive(!m_bModifiedOriginal && bHaveValidOriginalString);
+ }
+
+ void HangulHanjaEditDictDialog::UpdateSuggestions()
+ {
+ Sequence< OUString > aEntries;
+ bool bFound = GetConversions( m_rDictList[ m_nCurrentDict ], m_aOriginal, aEntries );
+ if( bFound )
+ {
+ m_bModifiedOriginal = false;
+
+ if( m_xSuggestions )
+ m_xSuggestions->Clear();
+
+ //fill found entries into boxes
+ sal_uInt32 nCnt = aEntries.getLength();
+ if( nCnt )
+ {
+ if( !m_xSuggestions )
+ m_xSuggestions.reset(new SuggestionList);
+
+ const OUString* pSugg = aEntries.getConstArray();
+ sal_uInt32 n = 0;
+ while( nCnt )
+ {
+ m_xSuggestions->Set( pSugg[ n ], sal_uInt16( n ) );
+ ++n;
+ --nCnt;
+ }
+ }
+ m_bModifiedSuggestions = false;
+ }
+
+ m_xScrollSB->vadjustment_set_value( 0 );
+ UpdateScrollbar(); // will force edits to be filled new
+ }
+
+ void HangulHanjaEditDictDialog::SetEditText(SuggestionEdit& rEdit, sal_uInt16 nEntryNum)
+ {
+ OUString aStr;
+ if( m_xSuggestions )
+ {
+ aStr = m_xSuggestions->Get(nEntryNum);
+ }
+
+ rEdit.set_text(aStr);
+ }
+
+ void HangulHanjaEditDictDialog::EditModify(const weld::Entry* pEdit, sal_uInt8 _nEntryOffset)
+ {
+ m_bModifiedSuggestions = true;
+
+ OUString aTxt( pEdit->get_text() );
+ sal_uInt16 nEntryNum = m_nTopPos + _nEntryOffset;
+ if( aTxt.isEmpty() )
+ {
+ //reset suggestion
+ if( m_xSuggestions )
+ m_xSuggestions->Reset( nEntryNum );
+ }
+ else
+ {
+ //set suggestion
+ if( !m_xSuggestions )
+ m_xSuggestions.reset(new SuggestionList);
+ m_xSuggestions->Set( aTxt, nEntryNum );
+ }
+
+ UpdateButtonStates();
+ }
+
+ HangulHanjaEditDictDialog::HangulHanjaEditDictDialog(weld::Window* pParent, HHDictList& _rDictList, sal_uInt32 nSelDict)
+ : GenericDialogController(pParent, "cui/ui/hangulhanjaeditdictdialog.ui", "HangulHanjaEditDictDialog")
+ , m_aEditHintText ( CuiResId(RID_SVXSTR_EDITHINT) )
+ , m_rDictList ( _rDictList )
+ , m_nCurrentDict ( 0xFFFFFFFF )
+ , m_nTopPos ( 0 )
+ , m_bModifiedSuggestions ( false )
+ , m_bModifiedOriginal ( false )
+ , m_xBookLB(m_xBuilder->weld_combo_box("book"))
+ , m_xOriginalLB(m_xBuilder->weld_combo_box("original"))
+ , m_xEdit1(new SuggestionEdit(m_xBuilder->weld_entry("edit1"), this))
+ , m_xEdit2(new SuggestionEdit(m_xBuilder->weld_entry("edit2"), this))
+ , m_xEdit3(new SuggestionEdit(m_xBuilder->weld_entry("edit3"), this))
+ , m_xEdit4(new SuggestionEdit(m_xBuilder->weld_entry("edit4"), this))
+ , m_xContents(m_xBuilder->weld_widget("box"))
+ , m_xScrollSB(m_xBuilder->weld_scrolled_window("scrollbar"))
+ , m_xNewPB(m_xBuilder->weld_button("new"))
+ , m_xDeletePB(m_xBuilder->weld_button("delete"))
+ {
+ m_xScrollSB->set_user_managed_scrolling();
+
+ Size aSize(m_xContents->get_preferred_size());
+ m_xScrollSB->set_size_request(-1, aSize.Height());
+
+ m_xEdit1->init( m_xScrollSB.get(), nullptr, m_xEdit2.get() );
+ m_xEdit2->init( m_xScrollSB.get(), m_xEdit1.get(), m_xEdit3.get() );
+ m_xEdit3->init( m_xScrollSB.get(), m_xEdit2.get(), m_xEdit4.get() );
+ m_xEdit4->init( m_xScrollSB.get(), m_xEdit3.get(), nullptr );
+
+ m_xOriginalLB->connect_changed( LINK( this, HangulHanjaEditDictDialog, OriginalModifyHdl ) );
+
+ m_xNewPB->connect_clicked( LINK( this, HangulHanjaEditDictDialog, NewPBPushHdl ) );
+ m_xNewPB->set_sensitive( false );
+
+ m_xDeletePB->connect_clicked( LINK( this, HangulHanjaEditDictDialog, DeletePBPushHdl ) );
+ m_xDeletePB->set_sensitive( false );
+
+ static_assert(MAXNUM_SUGGESTIONS >= 5, "number of suggestions should not under-run the value of 5");
+
+ // 4 here, because we have 4 edits / page
+ m_xScrollSB->vadjustment_configure(0, 0, MAXNUM_SUGGESTIONS, 1, 4, 4);
+ m_xScrollSB->connect_vadjustment_changed(LINK(this, HangulHanjaEditDictDialog, ScrollHdl));
+
+ m_xEdit1->connect_changed( LINK( this, HangulHanjaEditDictDialog, EditModifyHdl1 ) );
+ m_xEdit2->connect_changed( LINK( this, HangulHanjaEditDictDialog, EditModifyHdl2 ) );
+ m_xEdit3->connect_changed( LINK( this, HangulHanjaEditDictDialog, EditModifyHdl3 ) );
+ m_xEdit4->connect_changed( LINK( this, HangulHanjaEditDictDialog, EditModifyHdl4 ) );
+
+ m_xBookLB->connect_changed( LINK( this, HangulHanjaEditDictDialog, BookLBSelectHdl ) );
+ sal_uInt32 nDictCnt = m_rDictList.size();
+ for( sal_uInt32 n = 0 ; n < nDictCnt ; ++n )
+ {
+ Reference< XConversionDictionary > xDic( m_rDictList[n] );
+ OUString aName;
+ if( xDic.is() )
+ aName = xDic->getName();
+ m_xBookLB->append_text( aName );
+ }
+ m_xBookLB->set_active(nSelDict);
+
+ InitEditDictDialog(nSelDict);
+ }
+
+ HangulHanjaEditDictDialog::~HangulHanjaEditDictDialog()
+ {
+ }
+
+ void HangulHanjaEditDictDialog::UpdateScrollbar()
+ {
+ sal_uInt16 nPos = m_xScrollSB->vadjustment_get_value();
+ m_nTopPos = nPos;
+
+ SetEditText( *m_xEdit1, nPos++ );
+ SetEditText( *m_xEdit2, nPos++ );
+ SetEditText( *m_xEdit3, nPos++ );
+ SetEditText( *m_xEdit4, nPos );
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/dialogs/hldocntp.cxx b/cui/source/dialogs/hldocntp.cxx
new file mode 100644
index 000000000..50d7131ad
--- /dev/null
+++ b/cui/source/dialogs/hldocntp.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 <hldocntp.hxx>
+#include <osl/file.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/docfilt.hxx>
+#include <svl/stritem.hxx>
+#include <com/sun/star/awt/XTopWindow.hpp>
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/uno/Sequence.h>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/uno/Exception.hpp>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <tools/urlobj.hxx>
+#include <unotools/pathoptions.hxx>
+#include <unotools/dynamicmenuoptions.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <unotools/ucbhelper.hxx>
+
+#include <comphelper/processfactory.hxx>
+#include <com/sun/star/ui/dialogs/FolderPicker.hpp>
+#include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
+
+#include <cuihyperdlg.hxx>
+#include <dialmgr.hxx>
+#include <strings.hrc>
+
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::ui::dialogs;
+using namespace ::com::sun::star::uno;
+
+using namespace ::com::sun::star;
+
+/*************************************************************************
+|*
+|* Data-struct for documenttypes in listbox
+|*
+|************************************************************************/
+
+namespace {
+
+struct DocumentTypeData
+{
+ OUString aStrURL;
+ OUString aStrExt;
+ DocumentTypeData (const OUString& aURL, const OUString& aExt) : aStrURL(aURL), aStrExt(aExt)
+ {}
+};
+
+}
+
+bool SvxHyperlinkNewDocTp::ImplGetURLObject( const OUString& rPath, const OUString& rBase, INetURLObject& aURLObject ) const
+{
+ bool bIsValidURL = !rPath.isEmpty();
+ if ( bIsValidURL )
+ {
+ aURLObject.SetURL( rPath );
+ if ( aURLObject.GetProtocol() == INetProtocol::NotValid ) // test if the source is already a valid url
+ { // if not we have to create a url from a physical file name
+ bool wasAbs;
+ INetURLObject base(rBase);
+ base.setFinalSlash();
+ aURLObject = base.smartRel2Abs(
+ rPath, wasAbs, true, INetURLObject::EncodeMechanism::All,
+ RTL_TEXTENCODING_UTF8, true);
+ }
+ bIsValidURL = aURLObject.GetProtocol() != INetProtocol::NotValid;
+ if ( bIsValidURL )
+ {
+ OUString aBase( aURLObject.getName( INetURLObject::LAST_SEGMENT, false ) );
+ if ( aBase.isEmpty() || ( aBase[0] == '.' ) )
+ bIsValidURL = false;
+ }
+ if ( bIsValidURL )
+ {
+ sal_Int32 nPos = m_xLbDocTypes->get_selected_index();
+ if (nPos != -1)
+ aURLObject.SetExtension(reinterpret_cast<DocumentTypeData*>(m_xLbDocTypes->get_id(nPos).toInt64())->aStrExt);
+ }
+
+ }
+ return bIsValidURL;
+}
+
+/*************************************************************************
+|*
+|* Constructor / Destructor
+|*
+|************************************************************************/
+
+SvxHyperlinkNewDocTp::SvxHyperlinkNewDocTp(weld::Container* pParent, SvxHpLinkDlg* pDlg, const SfxItemSet* pItemSet)
+ : SvxHyperlinkTabPageBase(pParent, pDlg, "cui/ui/hyperlinknewdocpage.ui", "HyperlinkNewDocPage", pItemSet)
+ , m_xRbtEditNow(xBuilder->weld_radio_button("editnow"))
+ , m_xRbtEditLater(xBuilder->weld_radio_button("editlater"))
+ , m_xCbbPath(new SvxHyperURLBox(xBuilder->weld_combo_box("path")))
+ , m_xBtCreate(xBuilder->weld_button("create"))
+ , m_xLbDocTypes(xBuilder->weld_tree_view("types"))
+{
+ m_xCbbPath->SetSmartProtocol(INetProtocol::File);
+ m_xLbDocTypes->set_size_request(-1, m_xLbDocTypes->get_height_rows(5));
+
+ InitStdControls();
+
+ SetExchangeSupport ();
+
+ m_xCbbPath->show();
+ m_xCbbPath->SetBaseURL(SvtPathOptions().GetWorkPath());
+
+ // set defaults
+ m_xRbtEditNow->set_active(true);
+
+ m_xBtCreate->connect_clicked(LINK(this, SvxHyperlinkNewDocTp, ClickNewHdl_Impl));
+
+ FillDocumentList ();
+}
+
+SvxHyperlinkNewDocTp::~SvxHyperlinkNewDocTp ()
+{
+ if (m_xLbDocTypes)
+ {
+ for (sal_Int32 n = 0, nEntryCount = m_xLbDocTypes->n_children(); n < nEntryCount; ++n)
+ delete reinterpret_cast<DocumentTypeData*>(m_xLbDocTypes->get_id(n).toInt64());
+ m_xLbDocTypes = nullptr;
+ }
+}
+
+/*************************************************************************
+|*
+|* Fill the all dialog-controls except controls in groupbox "more..."
+|*
+|************************************************************************/
+
+
+void SvxHyperlinkNewDocTp::FillDlgFields(const OUString& /*rStrURL*/)
+{
+}
+
+void SvxHyperlinkNewDocTp::FillDocumentList()
+{
+ weld::WaitObject aWaitObj(mpDialog->getDialog());
+
+ uno::Sequence< uno::Sequence< beans::PropertyValue > >
+ aDynamicMenuEntries( SvtDynamicMenuOptions().GetMenu( EDynamicMenuType::NewMenu ) );
+
+ sal_uInt32 i, nCount = aDynamicMenuEntries.getLength();
+ for ( i = 0; i < nCount; i++ )
+ {
+ const uno::Sequence< beans::PropertyValue >& rDynamicMenuEntry = aDynamicMenuEntries[ i ];
+
+ OUString aDocumentUrl, aTitle;
+
+ for ( const beans::PropertyValue& e : rDynamicMenuEntry )
+ {
+ if ( e.Name == DYNAMICMENU_PROPERTYNAME_URL )
+ e.Value >>= aDocumentUrl;
+ else if ( e.Name == DYNAMICMENU_PROPERTYNAME_TITLE )
+ e.Value >>= aTitle;
+ }
+ //#i96822# business cards, labels and database should not be inserted here
+ if( aDocumentUrl == "private:factory/swriter?slot=21051" ||
+ aDocumentUrl == "private:factory/swriter?slot=21052" ||
+ aDocumentUrl == "private:factory/sdatabase?Interactive" )
+ continue;
+
+ // Insert into listbox
+ if ( !aDocumentUrl.isEmpty() )
+ {
+ if ( aDocumentUrl == "private:factory/simpress?slot=6686" ) // SJ: #106216# do not start
+ aDocumentUrl = "private:factory/simpress"; // the AutoPilot for impress
+
+ // insert private-url and default-extension as user-data
+ std::shared_ptr<const SfxFilter> pFilter = SfxFilter::GetDefaultFilterFromFactory( aDocumentUrl );
+ if ( pFilter )
+ {
+ // insert doc-name and image
+ OUString aTitleName = aTitle.replaceFirst( "~", "" );
+
+ OUString aStrDefExt(pFilter->GetDefaultExtension());
+ DocumentTypeData *pTypeData = new DocumentTypeData(aDocumentUrl, aStrDefExt.copy(2));
+ OUString sId(OUString::number(reinterpret_cast<sal_Int64>(pTypeData)));
+ m_xLbDocTypes->append(sId, aTitleName);
+ }
+ }
+ }
+ m_xLbDocTypes->select(0);
+}
+
+/*************************************************************************
+|*
+|* retrieve and prepare data from dialog-fields
+|*
+|************************************************************************/
+
+void SvxHyperlinkNewDocTp::GetCurentItemData ( OUString& rStrURL, OUString& aStrName,
+ OUString& aStrIntName, OUString& aStrFrame,
+ SvxLinkInsertMode& eMode )
+{
+ // get data from dialog-controls
+ rStrURL = m_xCbbPath->get_active_text();
+ INetURLObject aURL;
+ if ( ImplGetURLObject( rStrURL, m_xCbbPath->GetBaseURL(), aURL ) )
+ {
+ rStrURL = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+ }
+
+ GetDataFromCommonFields( aStrName, aStrIntName, aStrFrame, eMode );
+}
+
+/*************************************************************************
+|*
+|* static method to create Tabpage
+|*
+|************************************************************************/
+
+std::unique_ptr<IconChoicePage> SvxHyperlinkNewDocTp::Create(weld::Container* pWindow, SvxHpLinkDlg* pDlg, const SfxItemSet* pItemSet)
+{
+ return std::make_unique<SvxHyperlinkNewDocTp>(pWindow, pDlg, pItemSet);
+}
+
+/*************************************************************************
+|*
+|* Set initial focus
+|*
+|************************************************************************/
+void SvxHyperlinkNewDocTp::SetInitFocus()
+{
+ m_xCbbPath->grab_focus();
+}
+
+/*************************************************************************
+|*
+|* Ask page whether an insert is possible
+|*
+\************************************************************************/
+bool SvxHyperlinkNewDocTp::AskApply()
+{
+ INetURLObject aINetURLObject;
+ bool bRet = ImplGetURLObject(m_xCbbPath->get_active_text(), m_xCbbPath->GetBaseURL(), aINetURLObject);
+ if ( !bRet )
+ {
+ std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(mpDialog->getDialog(),
+ VclMessageType::Warning, VclButtonsType::Ok,
+ CuiResId(RID_SVXSTR_HYPDLG_NOVALIDFILENAME)));
+ xWarn->run();
+ }
+ return bRet;
+}
+
+namespace
+{
+ struct ExecuteInfo
+ {
+ bool bRbtEditLater;
+ bool bRbtEditNow;
+ INetURLObject aURL;
+ OUString aStrDocName;
+ // current document
+ css::uno::Reference<css::frame::XFrame> xFrame;
+ SfxDispatcher* pDispatcher;
+ };
+}
+
+IMPL_STATIC_LINK(SvxHyperlinkNewDocTp, DispatchDocument, void*, p, void)
+{
+ std::unique_ptr<ExecuteInfo> xExecuteInfo(static_cast<ExecuteInfo*>(p));
+ if (!xExecuteInfo->xFrame.is())
+ return;
+ try
+ {
+ //if it throws dispatcher is invalid
+ css::uno::Reference<css::awt::XTopWindow>(xExecuteInfo->xFrame->getContainerWindow(), css::uno::UNO_QUERY_THROW);
+
+ SfxViewFrame *pViewFrame = nullptr;
+
+ // create items
+ SfxStringItem aName( SID_FILE_NAME, xExecuteInfo->aStrDocName );
+ SfxStringItem aReferer( SID_REFERER, "private:user" );
+ SfxStringItem aFrame( SID_TARGETNAME, "_blank");
+
+ OUString aStrFlags('S');
+ if (xExecuteInfo->bRbtEditLater)
+ {
+ aStrFlags += "H";
+ }
+ SfxStringItem aFlags (SID_OPTIONS, aStrFlags);
+
+ // open url
+ const SfxPoolItem* pReturn = xExecuteInfo->pDispatcher->ExecuteList(
+ SID_OPENDOC, SfxCallMode::SYNCHRON,
+ { &aName, &aFlags, &aFrame, &aReferer });
+
+ // save new doc
+ const SfxViewFrameItem *pItem = dynamic_cast<const SfxViewFrameItem*>( pReturn ); // SJ: pReturn is NULL if the Hyperlink
+ if ( pItem ) // creation is cancelled #106216#
+ {
+ pViewFrame = pItem->GetFrame();
+ if (pViewFrame)
+ {
+ SfxStringItem aNewName( SID_FILE_NAME, xExecuteInfo->aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
+ SfxUnoFrameItem aDocFrame( SID_FILLFRAME, pViewFrame->GetFrame().GetFrameInterface() );
+ fprintf(stderr, "is there a frame int %p\n", pViewFrame->GetFrame().GetFrameInterface().get() );
+ pViewFrame->GetDispatcher()->ExecuteList(
+ SID_SAVEASDOC, SfxCallMode::SYNCHRON,
+ { &aNewName }, { &aDocFrame });
+ }
+ }
+
+ if (xExecuteInfo->bRbtEditNow)
+ {
+ css::uno::Reference<css::awt::XTopWindow> xWindow(xExecuteInfo->xFrame->getContainerWindow(), css::uno::UNO_QUERY);
+ if (xWindow.is()) //will be false if the frame was exited while the document was loading (e.g. we waited for warning dialogs)
+ xWindow->toFront();
+ }
+
+ if (pViewFrame && xExecuteInfo->bRbtEditLater)
+ {
+ SfxObjectShell* pObjShell = pViewFrame->GetObjectShell();
+ pObjShell->DoClose();
+ }
+ }
+ catch (...)
+ {
+ }
+}
+
+/*************************************************************************
+|*
+|* Any action to do after apply-button is pressed
+|*
+\************************************************************************/
+void SvxHyperlinkNewDocTp::DoApply()
+{
+ weld::WaitObject aWait(mpDialog->getDialog());
+
+ // get data from dialog-controls
+ OUString aStrNewName = m_xCbbPath->get_active_text();
+
+ if ( aStrNewName.isEmpty() )
+ aStrNewName = maStrInitURL;
+
+ // create a real URL-String
+ INetURLObject aURL;
+ if ( !ImplGetURLObject( aStrNewName, m_xCbbPath->GetBaseURL(), aURL ) )
+ return;
+
+ // create Document
+ aStrNewName = aURL.GetURLPath( INetURLObject::DecodeMechanism::NONE );
+ bool bCreate = true;
+ try
+ {
+ // check if file exists, warn before we overwrite it
+ std::unique_ptr<SvStream> pIStm = ::utl::UcbStreamHelper::CreateStream( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::READ );
+
+ bool bOk = pIStm && ( pIStm->GetError() == ERRCODE_NONE);
+
+ pIStm.reset();
+
+ if( bOk )
+ {
+ std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(mpDialog->getDialog(),
+ VclMessageType::Warning, VclButtonsType::YesNo,
+ CuiResId(RID_SVXSTR_HYPERDLG_QUERYOVERWRITE)));
+ bCreate = xWarn->run() == RET_YES;
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ }
+
+ if (!(bCreate && !aStrNewName.isEmpty()))
+ return;
+
+ ExecuteInfo* pExecuteInfo = new ExecuteInfo;
+
+ pExecuteInfo->bRbtEditLater = m_xRbtEditLater->get_active();
+ pExecuteInfo->bRbtEditNow = m_xRbtEditNow->get_active();
+ // get private-url
+ sal_Int32 nPos = m_xLbDocTypes->get_selected_index();
+ if (nPos == -1)
+ nPos = 0;
+ pExecuteInfo->aURL = aURL;
+ pExecuteInfo->aStrDocName = reinterpret_cast<DocumentTypeData*>(m_xLbDocTypes->get_id(nPos).toInt64())->aStrURL;
+
+ // current document
+ pExecuteInfo->xFrame = GetDispatcher()->GetFrame()->GetFrame().GetFrameInterface();
+ pExecuteInfo->pDispatcher = GetDispatcher();
+
+ Application::PostUserEvent(LINK(nullptr, SvxHyperlinkNewDocTp, DispatchDocument), pExecuteInfo);
+}
+
+/*************************************************************************
+|*
+|* Click on imagebutton : new
+|*
+|************************************************************************/
+IMPL_LINK_NOARG(SvxHyperlinkNewDocTp, ClickNewHdl_Impl, weld::Button&, void)
+{
+ DisableClose( true );
+ uno::Reference < XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
+ uno::Reference < XFolderPicker2 > xFolderPicker = FolderPicker::create(xContext);
+
+ OUString aStrURL;
+ OUString aTempStrURL( m_xCbbPath->get_active_text() );
+ osl::FileBase::getFileURLFromSystemPath( aTempStrURL, aStrURL );
+
+ OUString aStrPath = aStrURL;
+ bool bZeroPath = aStrPath.isEmpty();
+ bool bHandleFileName = bZeroPath; // when path has length of 0, then the rest should always be handled
+ // as file name, otherwise we do not yet know
+
+ if( bZeroPath )
+ aStrPath = SvtPathOptions().GetWorkPath();
+ else if( !::utl::UCBContentHelper::IsFolder( aStrURL ) )
+ bHandleFileName = true;
+
+ xFolderPicker->setDisplayDirectory( aStrPath );
+ sal_Int16 nResult = xFolderPicker->execute();
+ DisableClose( false );
+ if( ExecutableDialogResults::OK != nResult )
+ return;
+
+ char const sSlash[] = "/";
+
+ INetURLObject aURL( aStrURL, INetProtocol::File );
+ OUString aStrName;
+ if( bHandleFileName )
+ aStrName = bZeroPath? aTempStrURL : aURL.getName();
+
+ m_xCbbPath->SetBaseURL( xFolderPicker->getDirectory() );
+ OUString aStrTmp( xFolderPicker->getDirectory() );
+
+ if( aStrTmp[ aStrTmp.getLength() - 1 ] != sSlash[0] )
+ aStrTmp += sSlash;
+
+ // append old file name
+ if( bHandleFileName )
+ aStrTmp += aStrName;
+
+ INetURLObject aNewURL( aStrTmp );
+
+ if (!aStrName.isEmpty() && !aNewURL.getExtension().isEmpty() &&
+ m_xLbDocTypes->get_selected_index() != -1)
+ {
+ // get private-url
+ const sal_Int32 nPos = m_xLbDocTypes->get_selected_index();
+ aNewURL.setExtension(reinterpret_cast<DocumentTypeData*>(m_xLbDocTypes->get_id(nPos).toInt64())->aStrExt);
+ }
+
+ if( aNewURL.GetProtocol() == INetProtocol::File )
+ {
+ osl::FileBase::getSystemPathFromFileURL(aNewURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), aStrTmp);
+ }
+ else
+ {
+ aStrTmp = aNewURL.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous );
+ }
+
+ m_xCbbPath->set_entry_text( aStrTmp );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/dialogs/hldoctp.cxx b/cui/source/dialogs/hldoctp.cxx
new file mode 100644
index 000000000..8bfe89465
--- /dev/null
+++ b/cui/source/dialogs/hldoctp.cxx
@@ -0,0 +1,318 @@
+/* -*- 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 <cuihyperdlg.hxx>
+#include <osl/file.hxx>
+#include <sfx2/filedlghelper.hxx>
+#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
+
+#include <hldoctp.hxx>
+#include <hlmarkwn_def.hxx>
+
+char const sHash[] = "#";
+char const sFileScheme[] = INET_FILE_SCHEME;
+
+/*************************************************************************
+|*
+|* Constructor / Destructor
+|*
+|************************************************************************/
+
+SvxHyperlinkDocTp::SvxHyperlinkDocTp(weld::Container* pParent, SvxHpLinkDlg* pDlg, const SfxItemSet* pItemSet)
+ : SvxHyperlinkTabPageBase(pParent, pDlg, "cui/ui/hyperlinkdocpage.ui", "HyperlinkDocPage", pItemSet)
+ , m_xCbbPath(new SvxHyperURLBox(xBuilder->weld_combo_box("path")))
+ , m_xBtFileopen(xBuilder->weld_button("fileopen"))
+ , m_xEdTarget(xBuilder->weld_entry("target"))
+ , m_xFtFullURL(xBuilder->weld_label("url"))
+ , m_xBtBrowse(xBuilder->weld_button("browse"))
+ , m_bMarkWndOpen(false)
+{
+ m_xCbbPath->SetSmartProtocol(INetProtocol::File);
+
+ InitStdControls();
+
+ m_xCbbPath->show();
+ m_xCbbPath->SetBaseURL(INET_FILE_SCHEME);
+
+ SetExchangeSupport();
+
+ // set handlers
+ m_xBtFileopen->connect_clicked( LINK ( this, SvxHyperlinkDocTp, ClickFileopenHdl_Impl ) );
+ m_xBtBrowse->connect_clicked( LINK ( this, SvxHyperlinkDocTp, ClickTargetHdl_Impl ) );
+ m_xCbbPath->connect_changed( LINK ( this, SvxHyperlinkDocTp, ModifiedPathHdl_Impl ) );
+ m_xEdTarget->connect_changed( LINK ( this, SvxHyperlinkDocTp, ModifiedTargetHdl_Impl ) );
+
+ m_xCbbPath->connect_focus_out( LINK ( this, SvxHyperlinkDocTp, LostFocusPathHdl_Impl ) );
+
+ maTimer.SetInvokeHandler ( LINK ( this, SvxHyperlinkDocTp, TimeoutHdl_Impl ) );
+}
+
+SvxHyperlinkDocTp::~SvxHyperlinkDocTp()
+{
+}
+
+/*************************************************************************
+|*
+|* Fill all dialog-controls except controls in groupbox "more..."
+|*
+|************************************************************************/
+void SvxHyperlinkDocTp::FillDlgFields(const OUString& rStrURL)
+{
+ sal_Int32 nPos = rStrURL.indexOf(sHash);
+ // path
+ m_xCbbPath->set_entry_text( rStrURL.copy( 0, ( nPos == -1 ? rStrURL.getLength() : nPos ) ) );
+
+ // set target in document at editfield
+ OUString aStrMark;
+ if ( nPos != -1 && nPos < rStrURL.getLength()-1 )
+ aStrMark = rStrURL.copy( nPos+1 );
+ m_xEdTarget->set_text( aStrMark );
+
+ ModifiedPathHdl_Impl(*m_xCbbPath->getWidget());
+}
+
+/*************************************************************************
+|*
+|* retrieve current url-string
+|*
+|************************************************************************/
+OUString SvxHyperlinkDocTp::GetCurrentURL () const
+{
+ // get data from dialog-controls
+ OUString aStrURL;
+ OUString aStrPath( m_xCbbPath->get_active_text() );
+ OUString aStrMark( m_xEdTarget->get_text() );
+
+ if ( !aStrPath.isEmpty() )
+ {
+ INetURLObject aURL( aStrPath );
+ if ( aURL.GetProtocol() != INetProtocol::NotValid ) // maybe the path is already a valid
+ aStrURL = aStrPath; // hyperlink, then we can use this path directly
+ else
+ {
+ osl::FileBase::getFileURLFromSystemPath( aStrPath, aStrURL );
+ aStrURL = INetURLObject::decode(aStrURL, INetURLObject::DecodeMechanism::ToIUri, RTL_TEXTENCODING_UTF8);
+ }
+
+ //#105788# always create a URL even if it is not valid
+ if( aStrURL.isEmpty() )
+ aStrURL = aStrPath;
+ }
+
+ if( !aStrMark.isEmpty() )
+ {
+ aStrURL += sHash + aStrMark;
+ }
+
+ return aStrURL;
+}
+
+/*************************************************************************
+|*
+|* retrieve and prepare data from dialog-fields
+|*
+|************************************************************************/
+void SvxHyperlinkDocTp::GetCurentItemData ( OUString& rStrURL, OUString& aStrName,
+ OUString& aStrIntName, OUString& aStrFrame,
+ SvxLinkInsertMode& eMode )
+{
+ // get data from standard-fields
+ rStrURL = GetCurrentURL();
+
+ if( rStrURL.equalsIgnoreAsciiCase( sFileScheme ) )
+ rStrURL.clear();
+
+ GetDataFromCommonFields( aStrName, aStrIntName, aStrFrame, eMode );
+}
+
+/*************************************************************************
+|*
+|* static method to create Tabpage
+|*
+|************************************************************************/
+std::unique_ptr<IconChoicePage> SvxHyperlinkDocTp::Create(weld::Container* pWindow, SvxHpLinkDlg* pDlg, const SfxItemSet* pItemSet)
+{
+ return std::make_unique<SvxHyperlinkDocTp>(pWindow, pDlg, pItemSet);
+}
+
+/*************************************************************************
+|*
+|* Set initial focus
+|*
+|************************************************************************/
+void SvxHyperlinkDocTp::SetInitFocus()
+{
+ m_xCbbPath->grab_focus();
+}
+
+/*************************************************************************
+|*
+|* Click on imagebutton : fileopen
+|*
+|************************************************************************/
+IMPL_LINK_NOARG(SvxHyperlinkDocTp, ClickFileopenHdl_Impl, weld::Button&, void)
+{
+ DisableClose( true );
+ // Open Fileopen-Dialog
+ sfx2::FileDialogHelper aDlg(
+ css::ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE, FileDialogFlags::NONE,
+ mpDialog->getDialog() );
+ OUString aOldURL( GetCurrentURL() );
+ if( aOldURL.startsWithIgnoreAsciiCase( sFileScheme ) )
+ {
+ OUString aPath;
+ osl::FileBase::getSystemPathFromFileURL(aOldURL, aPath);
+ aDlg.SetDisplayFolder( aPath );
+ }
+
+ ErrCode nError = aDlg.Execute();
+ DisableClose( false );
+
+ if ( ERRCODE_NONE != nError )
+ return;
+
+ OUString aURL( aDlg.GetPath() );
+ OUString aPath;
+
+ osl::FileBase::getSystemPathFromFileURL(aURL, aPath);
+
+ m_xCbbPath->SetBaseURL( aURL );
+ m_xCbbPath->set_entry_text(aPath);
+
+ if ( aOldURL != GetCurrentURL() )
+ ModifiedPathHdl_Impl(*m_xCbbPath->getWidget());
+}
+
+/*************************************************************************
+|*
+|* Click on imagebutton : target
+|*
+|************************************************************************/
+IMPL_LINK_NOARG(SvxHyperlinkDocTp, ClickTargetHdl_Impl, weld::Button&, void)
+{
+ ShowMarkWnd();
+
+ if ( GetPathType ( maStrURL ) == EPathType::ExistsFile ||
+ maStrURL.isEmpty() ||
+ maStrURL.equalsIgnoreAsciiCase( sFileScheme ) ||
+ maStrURL.startsWith( sHash ) )
+ {
+ mxMarkWnd->SetError( LERR_NOERROR );
+
+ weld::WaitObject aWait(mpDialog->getDialog());
+
+ if ( maStrURL.equalsIgnoreAsciiCase( sFileScheme ) )
+ mxMarkWnd->RefreshTree ( "" );
+ else
+ mxMarkWnd->RefreshTree ( maStrURL );
+ }
+ else
+ mxMarkWnd->SetError( LERR_DOCNOTOPEN );
+}
+
+/*************************************************************************
+|*
+|* Contents of combobox "Path" modified
+|*
+|************************************************************************/
+IMPL_LINK_NOARG(SvxHyperlinkDocTp, ModifiedPathHdl_Impl, weld::ComboBox&, void)
+{
+ maStrURL = GetCurrentURL();
+
+ maTimer.SetTimeout( 2500 );
+ maTimer.Start();
+
+ m_xFtFullURL->set_label( maStrURL );
+}
+
+/*************************************************************************
+|*
+|* If path-field was modify, to browse the new doc after timeout
+|*
+|************************************************************************/
+IMPL_LINK_NOARG(SvxHyperlinkDocTp, TimeoutHdl_Impl, Timer *, void)
+{
+ if ( IsMarkWndVisible() && ( GetPathType( maStrURL )== EPathType::ExistsFile ||
+ maStrURL.isEmpty() ||
+ maStrURL.equalsIgnoreAsciiCase( sFileScheme ) ) )
+ {
+ weld::WaitObject aWait(mpDialog->getDialog());
+
+ if ( maStrURL.equalsIgnoreAsciiCase( sFileScheme ) )
+ mxMarkWnd->RefreshTree ( "" );
+ else
+ mxMarkWnd->RefreshTree ( maStrURL );
+ }
+}
+
+/*************************************************************************
+|*
+|* Contents of editfield "Target" modified
+|*
+|************************************************************************/
+IMPL_LINK_NOARG(SvxHyperlinkDocTp, ModifiedTargetHdl_Impl, weld::Entry&, void)
+{
+ maStrURL = GetCurrentURL();
+
+ if (IsMarkWndVisible())
+ mxMarkWnd->SelectEntry(m_xEdTarget->get_text());
+
+ m_xFtFullURL->set_label( maStrURL );
+}
+
+/*************************************************************************
+|*
+|* editfield "Target" lost focus
+|*
+|************************************************************************/
+IMPL_LINK_NOARG(SvxHyperlinkDocTp, LostFocusPathHdl_Impl, weld::Widget&, void)
+{
+ maStrURL = GetCurrentURL();
+
+ m_xFtFullURL->set_label( maStrURL );
+}
+
+/*************************************************************************
+|*
+|* Get String from Bookmark-Wnd
+|*
+|************************************************************************/
+void SvxHyperlinkDocTp::SetMarkStr ( const OUString& aStrMark )
+{
+ m_xEdTarget->set_text(aStrMark);
+
+ ModifiedTargetHdl_Impl ( *m_xEdTarget );
+}
+
+/*************************************************************************
+|*
+|* retrieve kind of pathstr
+|*
+|************************************************************************/
+SvxHyperlinkDocTp::EPathType SvxHyperlinkDocTp::GetPathType ( const OUString& rStrPath )
+{
+ INetURLObject aURL( rStrPath, INetProtocol::File );
+
+ if( aURL.HasError() )
+ return EPathType::Invalid;
+ else
+ return EPathType::ExistsFile;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/dialogs/hlinettp.cxx b/cui/source/dialogs/hlinettp.cxx
new file mode 100644
index 000000000..f2deeb9b3
--- /dev/null
+++ b/cui/source/dialogs/hlinettp.cxx
@@ -0,0 +1,393 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <unotools/useroptions.hxx>
+#include <svl/adrparse.hxx>
+
+#include <hlinettp.hxx>
+#include <hlmarkwn_def.hxx>
+
+char const sAnonymous[] = "anonymous";
+char const sFTPScheme[] = INET_FTP_SCHEME;
+
+/*************************************************************************
+|*
+|* Constructor / Destructor
+|*
+|************************************************************************/
+SvxHyperlinkInternetTp::SvxHyperlinkInternetTp(weld::Container* pParent,
+ SvxHpLinkDlg* pDlg,
+ const SfxItemSet* pItemSet)
+ : SvxHyperlinkTabPageBase(pParent, pDlg, "cui/ui/hyperlinkinternetpage.ui", "HyperlinkInternetPage",
+ pItemSet)
+ , m_bMarkWndOpen(false)
+ , m_xRbtLinktypInternet(xBuilder->weld_radio_button("linktyp_internet"))
+ , m_xRbtLinktypFTP(xBuilder->weld_radio_button("linktyp_ftp"))
+ , m_xCbbTarget(new SvxHyperURLBox(xBuilder->weld_combo_box("target")))
+ , m_xFtTarget(xBuilder->weld_label("target_label"))
+ , m_xFtLogin(xBuilder->weld_label("login_label"))
+ , m_xEdLogin(xBuilder->weld_entry("login"))
+ , m_xFtPassword(xBuilder->weld_label("password_label"))
+ , m_xEdPassword(xBuilder->weld_entry("password"))
+ , m_xCbAnonymous(xBuilder->weld_check_button("anonymous"))
+{
+ // gtk_size_group_set_ignore_hidden, "Measuring the size of hidden widgets
+ // ... they will report a size of 0 nowadays, and thus, their size will
+ // not affect the other size group members", which is unfortunate. So here
+ // before we hide the labels, take the size group width and set it as
+ // explicit preferred size on a label that won't be hidden
+ auto nLabelWidth = m_xFtTarget->get_preferred_size().Width();
+ m_xFtTarget->set_size_request(nLabelWidth, -1);
+
+ m_xCbbTarget->SetSmartProtocol(INetProtocol::Http);
+
+ InitStdControls();
+
+ m_xCbbTarget->show();
+
+ SetExchangeSupport ();
+
+ // set defaults
+ m_xRbtLinktypInternet->set_active(true);
+
+ // set handlers
+ Link<weld::Button&, void> aLink( LINK ( this, SvxHyperlinkInternetTp, Click_SmartProtocol_Impl ) );
+ m_xRbtLinktypInternet->connect_clicked( aLink );
+ m_xRbtLinktypFTP->connect_clicked( aLink );
+ m_xCbAnonymous->connect_clicked( LINK ( this, SvxHyperlinkInternetTp, ClickAnonymousHdl_Impl ) );
+ m_xEdLogin->connect_changed( LINK ( this, SvxHyperlinkInternetTp, ModifiedLoginHdl_Impl ) );
+ m_xCbbTarget->connect_focus_out( LINK ( this, SvxHyperlinkInternetTp, LostFocusTargetHdl_Impl ) );
+ m_xCbbTarget->connect_changed( LINK ( this, SvxHyperlinkInternetTp, ModifiedTargetHdl_Impl ) );
+ maTimer.SetInvokeHandler ( LINK ( this, SvxHyperlinkInternetTp, TimeoutHdl_Impl ) );
+}
+
+SvxHyperlinkInternetTp::~SvxHyperlinkInternetTp()
+{
+}
+
+/*************************************************************************
+|*
+|* Fill the all dialog-controls except controls in groupbox "more..."
+|*
+|************************************************************************/
+void SvxHyperlinkInternetTp::FillDlgFields(const OUString& rStrURL)
+{
+ INetURLObject aURL(rStrURL);
+ OUString aStrScheme(GetSchemeFromURL(rStrURL));
+
+ // set additional controls for FTP: Username / Password
+ if (aStrScheme.startsWith(sFTPScheme))
+ {
+ if ( aURL.GetUser().toAsciiLowerCase().startsWith( sAnonymous ) )
+ setAnonymousFTPUser();
+ else
+ setFTPUser(aURL.GetUser(), aURL.GetPass());
+
+ //do not show password and user in url
+ if(!aURL.GetUser().isEmpty() || !aURL.GetPass().isEmpty() )
+ aURL.SetUserAndPass("", "");
+ }
+
+ // set URL-field
+ // Show the scheme, #72740
+ if ( aURL.GetProtocol() != INetProtocol::NotValid )
+ m_xCbbTarget->set_entry_text( aURL.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous ) );
+ else
+ m_xCbbTarget->set_entry_text(rStrURL);
+
+ SetScheme(aStrScheme);
+}
+
+void SvxHyperlinkInternetTp::setAnonymousFTPUser()
+{
+ m_xEdLogin->set_text(sAnonymous);
+ SvAddressParser aAddress(SvtUserOptions().GetEmail());
+ m_xEdPassword->set_text(aAddress.Count() ? aAddress.GetEmailAddress(0) : OUString());
+
+ m_xFtLogin->set_sensitive(false);
+ m_xFtPassword->set_sensitive(false);
+ m_xEdLogin->set_sensitive(false);
+ m_xEdPassword->set_sensitive(false);
+ m_xCbAnonymous->set_active(true);
+}
+
+void SvxHyperlinkInternetTp::setFTPUser(const OUString& rUser, const OUString& rPassword)
+{
+ m_xEdLogin->set_text(rUser);
+ m_xEdPassword->set_text(rPassword);
+
+ m_xFtLogin->set_sensitive(true);
+ m_xFtPassword->set_sensitive(true);
+ m_xEdLogin->set_sensitive(true);
+ m_xEdPassword->set_sensitive(true);
+ m_xCbAnonymous->set_active(false);
+}
+
+/*************************************************************************
+|*
+|* retrieve and prepare data from dialog-fields
+|*
+|************************************************************************/
+
+void SvxHyperlinkInternetTp::GetCurentItemData ( OUString& rStrURL, OUString& aStrName,
+ OUString& aStrIntName, OUString& aStrFrame,
+ SvxLinkInsertMode& eMode )
+{
+ rStrURL = CreateAbsoluteURL();
+ GetDataFromCommonFields( aStrName, aStrIntName, aStrFrame, eMode );
+}
+
+OUString SvxHyperlinkInternetTp::CreateAbsoluteURL() const
+{
+ // erase leading and trailing whitespaces
+ OUString aStrURL(m_xCbbTarget->get_active_text().trim());
+
+ INetURLObject aURL(aStrURL);
+
+ if( aURL.GetProtocol() == INetProtocol::NotValid )
+ {
+ aURL.SetSmartProtocol( GetSmartProtocolFromButtons() );
+ aURL.SetSmartURL(aStrURL);
+ }
+
+ // username and password for ftp-url
+ if( aURL.GetProtocol() == INetProtocol::Ftp && !m_xEdLogin->get_text().isEmpty() )
+ aURL.SetUserAndPass ( m_xEdLogin->get_text(), m_xEdPassword->get_text() );
+
+ if ( aURL.GetProtocol() != INetProtocol::NotValid )
+ return aURL.GetMainURL( INetURLObject::DecodeMechanism::ToIUri );
+ else //#105788# always create a URL even if it is not valid
+ return aStrURL;
+}
+
+/*************************************************************************
+|*
+|* static method to create Tabpage
+|*
+|************************************************************************/
+
+std::unique_ptr<IconChoicePage> SvxHyperlinkInternetTp::Create(weld::Container* pWindow, SvxHpLinkDlg* pDlg, const SfxItemSet* pItemSet)
+{
+ return std::make_unique<SvxHyperlinkInternetTp>(pWindow, pDlg, pItemSet);
+}
+
+/*************************************************************************
+|*
+|* Set initial focus
+|*
+|************************************************************************/
+void SvxHyperlinkInternetTp::SetInitFocus()
+{
+ m_xCbbTarget->grab_focus();
+}
+
+/*************************************************************************
+|*
+|* Contents of editfield "Target" modified
+|*
+|************************************************************************/
+IMPL_LINK_NOARG(SvxHyperlinkInternetTp, ModifiedTargetHdl_Impl, weld::ComboBox&, void)
+{
+ OUString aScheme = GetSchemeFromURL( m_xCbbTarget->get_active_text() );
+ if( !aScheme.isEmpty() )
+ SetScheme( aScheme );
+
+ // start timer
+ maTimer.SetTimeout( 2500 );
+ maTimer.Start();
+}
+
+/*************************************************************************
+|*
+|* If target-field was modify, to browse the new doc after timeout
+|*
+|************************************************************************/
+IMPL_LINK_NOARG(SvxHyperlinkInternetTp, TimeoutHdl_Impl, Timer *, void)
+{
+ RefreshMarkWindow();
+}
+
+/*************************************************************************
+|*
+|* Contents of editfield "Login" modified
+|*
+|************************************************************************/
+IMPL_LINK_NOARG(SvxHyperlinkInternetTp, ModifiedLoginHdl_Impl, weld::Entry&, void)
+{
+ OUString aStrLogin ( m_xEdLogin->get_text() );
+ if ( aStrLogin.equalsIgnoreAsciiCase( sAnonymous ) )
+ {
+ m_xCbAnonymous->set_active(true);
+ ClickAnonymousHdl_Impl(*m_xCbAnonymous);
+ }
+}
+
+void SvxHyperlinkInternetTp::SetScheme(const OUString& rScheme)
+{
+ //if rScheme is empty or unknown the default behaviour is like it where HTTP
+ bool bFTP = rScheme.startsWith(sFTPScheme);
+ bool bInternet = !bFTP;
+
+ //update protocol button selection:
+ m_xRbtLinktypFTP->set_active(bFTP);
+ m_xRbtLinktypInternet->set_active(bInternet);
+
+ //update target:
+ RemoveImproperProtocol(rScheme);
+ m_xCbbTarget->SetSmartProtocol( GetSmartProtocolFromButtons() );
+
+ //show/hide special fields for FTP:
+ m_xFtLogin->set_visible( bFTP );
+ m_xFtPassword->set_visible( bFTP );
+ m_xEdLogin->set_visible( bFTP );
+ m_xEdPassword->set_visible( bFTP );
+ m_xCbAnonymous->set_visible( bFTP );
+
+ //update 'link target in document'-window and opening-button
+ if (rScheme.startsWith(INET_HTTP_SCHEME) || rScheme.isEmpty())
+ {
+ if ( m_bMarkWndOpen )
+ ShowMarkWnd ();
+ }
+ else
+ {
+ //disable for https and ftp
+ if ( m_bMarkWndOpen )
+ HideMarkWnd ();
+ }
+}
+
+/*************************************************************************
+|*
+|* Remove protocol if it does not fit to the current button selection
+|*
+|************************************************************************/
+
+void SvxHyperlinkInternetTp::RemoveImproperProtocol(const OUString& aProperScheme)
+{
+ OUString aStrURL ( m_xCbbTarget->get_active_text() );
+ if ( !aStrURL.isEmpty() )
+ {
+ OUString aStrScheme(GetSchemeFromURL(aStrURL));
+ if ( !aStrScheme.isEmpty() && aStrScheme != aProperScheme )
+ {
+ aStrURL = aStrURL.copy( aStrScheme.getLength() );
+ m_xCbbTarget->set_entry_text( aStrURL );
+ }
+ }
+}
+
+OUString SvxHyperlinkInternetTp::GetSchemeFromButtons() const
+{
+ if( m_xRbtLinktypFTP->get_active() )
+ return INET_FTP_SCHEME;
+ return INET_HTTP_SCHEME;
+}
+
+INetProtocol SvxHyperlinkInternetTp::GetSmartProtocolFromButtons() const
+{
+ if( m_xRbtLinktypFTP->get_active() )
+ {
+ return INetProtocol::Ftp;
+ }
+ return INetProtocol::Http;
+}
+
+/*************************************************************************
+|*
+|* Click on Radiobutton : Internet or FTP
+|*
+|************************************************************************/
+IMPL_LINK_NOARG(SvxHyperlinkInternetTp, Click_SmartProtocol_Impl, weld::Button&, void)
+{
+ OUString aScheme = GetSchemeFromButtons();
+ SetScheme(aScheme);
+}
+
+/*************************************************************************
+|*
+|* Click on Checkbox : Anonymous user
+|*
+|************************************************************************/
+IMPL_LINK_NOARG(SvxHyperlinkInternetTp, ClickAnonymousHdl_Impl, weld::Button&, void)
+{
+ // disable login-editfields if checked
+ if ( m_xCbAnonymous->get_active() )
+ {
+ if ( m_xEdLogin->get_text().toAsciiLowerCase().startsWith( sAnonymous ) )
+ {
+ maStrOldUser.clear();
+ maStrOldPassword.clear();
+ }
+ else
+ {
+ maStrOldUser = m_xEdLogin->get_text();
+ maStrOldPassword = m_xEdPassword->get_text();
+ }
+
+ setAnonymousFTPUser();
+ }
+ else
+ setFTPUser(maStrOldUser, maStrOldPassword);
+}
+
+/*************************************************************************
+|*
+|* Combobox Target lost the focus
+|*
+|************************************************************************/
+IMPL_LINK_NOARG(SvxHyperlinkInternetTp, LostFocusTargetHdl_Impl, weld::Widget&, void)
+{
+ RefreshMarkWindow();
+}
+
+void SvxHyperlinkInternetTp::RefreshMarkWindow()
+{
+ if (m_xRbtLinktypInternet->get_active() && IsMarkWndVisible())
+ {
+ weld::WaitObject aWait(mpDialog->getDialog());
+ OUString aStrURL( CreateAbsoluteURL() );
+ if ( !aStrURL.isEmpty() )
+ mxMarkWnd->RefreshTree ( aStrURL );
+ else
+ mxMarkWnd->SetError( LERR_DOCNOTOPEN );
+ }
+}
+
+/*************************************************************************
+|*
+|* Get String from Bookmark-Wnd
+|*
+|************************************************************************/
+void SvxHyperlinkInternetTp::SetMarkStr ( const OUString& aStrMark )
+{
+ OUString aStrURL(m_xCbbTarget->get_active_text());
+
+ const sal_Unicode sUHash = '#';
+ sal_Int32 nPos = aStrURL.lastIndexOf( sUHash );
+
+ if( nPos != -1 )
+ aStrURL = aStrURL.copy(0, nPos);
+
+ aStrURL += OUStringChar(sUHash) + aStrMark;
+
+ m_xCbbTarget->set_entry_text(aStrURL);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/dialogs/hlmailtp.cxx b/cui/source/dialogs/hlmailtp.cxx
new file mode 100644
index 000000000..4e2e111fc
--- /dev/null
+++ b/cui/source/dialogs/hlmailtp.cxx
@@ -0,0 +1,228 @@
+/* -*- 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/request.hxx>
+
+#include <sfx2/viewfrm.hxx>
+#include <unotools/moduleoptions.hxx>
+
+#include <hlmailtp.hxx>
+
+#include <comphelper/lok.hxx>
+
+using namespace ::com::sun::star;
+
+/*************************************************************************
+|*
+|* Constructor / Destructor
+|*
+|************************************************************************/
+SvxHyperlinkMailTp::SvxHyperlinkMailTp(weld::Container* pParent, SvxHpLinkDlg* pDlg, const SfxItemSet* pItemSet)
+ : SvxHyperlinkTabPageBase(pParent, pDlg, "cui/ui/hyperlinkmailpage.ui", "HyperlinkMailPage", pItemSet)
+ , m_xCbbReceiver(new SvxHyperURLBox(xBuilder->weld_combo_box("receiver")))
+ , m_xBtAdrBook(xBuilder->weld_button("adressbook"))
+ , m_xFtSubject(xBuilder->weld_label("subject_label"))
+ , m_xEdSubject(xBuilder->weld_entry("subject"))
+{
+ m_xCbbReceiver->SetSmartProtocol(INetProtocol::Mailto);
+
+ InitStdControls();
+
+ m_xCbbReceiver->show();
+
+ SetExchangeSupport ();
+
+ // set handlers
+ m_xBtAdrBook->connect_clicked( LINK ( this, SvxHyperlinkMailTp, ClickAdrBookHdl_Impl ) );
+ m_xCbbReceiver->connect_changed( LINK ( this, SvxHyperlinkMailTp, ModifiedReceiverHdl_Impl) );
+
+ if ( !SvtModuleOptions().IsModuleInstalled( SvtModuleOptions::EModule::DATABASE ) ||
+ comphelper::LibreOfficeKit::isActive() )
+ m_xBtAdrBook->hide();
+}
+
+SvxHyperlinkMailTp::~SvxHyperlinkMailTp()
+{
+}
+
+/*************************************************************************
+|*
+|* Fill the all dialog-controls except controls in groupbox "more..."
+|*
+|************************************************************************/
+
+void SvxHyperlinkMailTp::FillDlgFields(const OUString& rStrURL)
+{
+ OUString aStrScheme = GetSchemeFromURL(rStrURL);
+
+ // set URL-field and additional controls
+ OUString aStrURLc (rStrURL);
+ // set additional controls for EMail:
+ if ( aStrScheme.startsWith( INET_MAILTO_SCHEME ) )
+ {
+ // Find mail-subject
+ OUString aStrSubject, aStrTmp( aStrURLc );
+
+ sal_Int32 nPos = aStrTmp.toAsciiLowerCase().indexOf( "subject" );
+
+ if ( nPos != -1 )
+ nPos = aStrTmp.indexOf( '=', nPos );
+
+ if ( nPos != -1 )
+ aStrSubject = aStrURLc.copy( nPos+1 );
+
+ nPos = aStrURLc.indexOf( '?' );
+
+ if ( nPos != -1 )
+ aStrURLc = aStrURLc.copy( 0, nPos );
+
+ m_xEdSubject->set_text( aStrSubject );
+ }
+ else
+ {
+ m_xEdSubject->set_text("");
+ }
+
+ m_xCbbReceiver->set_entry_text(aStrURLc);
+
+ SetScheme( aStrScheme );
+}
+
+/*************************************************************************
+|*
+|* retrieve and prepare data from dialog-fields
+|*
+|************************************************************************/
+void SvxHyperlinkMailTp::GetCurentItemData ( OUString& rStrURL, OUString& aStrName,
+ OUString& aStrIntName, OUString& aStrFrame,
+ SvxLinkInsertMode& eMode )
+{
+ rStrURL = CreateAbsoluteURL();
+ GetDataFromCommonFields( aStrName, aStrIntName, aStrFrame, eMode );
+}
+
+OUString SvxHyperlinkMailTp::CreateAbsoluteURL() const
+{
+ OUString aStrURL = m_xCbbReceiver->get_active_text();
+ INetURLObject aURL(aStrURL);
+
+ if( aURL.GetProtocol() == INetProtocol::NotValid )
+ {
+ aURL.SetSmartProtocol( INetProtocol::Mailto );
+ aURL.SetSmartURL(aStrURL);
+ }
+
+ // subject for EMail-url
+ if( aURL.GetProtocol() == INetProtocol::Mailto )
+ {
+ if (!m_xEdSubject->get_text().isEmpty())
+ {
+ OUString aQuery = "subject=" + m_xEdSubject->get_text();
+ aURL.SetParam(aQuery);
+ }
+ }
+
+ if ( aURL.GetProtocol() != INetProtocol::NotValid )
+ return aURL.GetMainURL( INetURLObject::DecodeMechanism::WithCharset );
+ else //#105788# always create a URL even if it is not valid
+ return aStrURL;
+}
+
+/*************************************************************************
+|*
+|* static method to create Tabpage
+|*
+|************************************************************************/
+
+std::unique_ptr<IconChoicePage> SvxHyperlinkMailTp::Create(weld::Container* pWindow, SvxHpLinkDlg* pDlg, const SfxItemSet* pItemSet)
+{
+ return std::make_unique<SvxHyperlinkMailTp>(pWindow, pDlg, pItemSet);
+}
+
+/*************************************************************************
+|*
+|* Set initial focus
+|*
+|************************************************************************/
+void SvxHyperlinkMailTp::SetInitFocus()
+{
+ m_xCbbReceiver->grab_focus();
+}
+
+/*************************************************************************
+|************************************************************************/
+void SvxHyperlinkMailTp::SetScheme(const OUString& rScheme)
+{
+ //update target:
+ RemoveImproperProtocol(rScheme);
+ m_xCbbReceiver->SetSmartProtocol( INetProtocol::Mailto );
+
+ //show/hide special fields for MAIL:
+ m_xBtAdrBook->set_sensitive(true);
+ m_xEdSubject->set_sensitive(true);
+}
+
+/*************************************************************************
+|*
+|* Remove protocol if it does not fit to the current button selection
+|*
+|************************************************************************/
+void SvxHyperlinkMailTp::RemoveImproperProtocol(const OUString& aProperScheme)
+{
+ OUString aStrURL(m_xCbbReceiver->get_active_text());
+ if ( !aStrURL.isEmpty() )
+ {
+ OUString aStrScheme = GetSchemeFromURL( aStrURL );
+ if ( !aStrScheme.isEmpty() && aStrScheme != aProperScheme )
+ {
+ aStrURL = aStrURL.copy( aStrScheme.getLength() );
+ m_xCbbReceiver->set_entry_text(aStrURL);
+ }
+ }
+}
+
+/*************************************************************************
+|*
+|* Contents of editfield "receiver" modified
+|*
+|************************************************************************/
+IMPL_LINK_NOARG(SvxHyperlinkMailTp, ModifiedReceiverHdl_Impl, weld::ComboBox&, void)
+{
+ OUString aScheme = GetSchemeFromURL( m_xCbbReceiver->get_active_text() );
+ if(!aScheme.isEmpty())
+ SetScheme( aScheme );
+}
+
+/*************************************************************************
+|*
+|* Click on imagebutton : addressbook
+|*
+|************************************************************************/
+IMPL_STATIC_LINK_NOARG(SvxHyperlinkMailTp, ClickAdrBookHdl_Impl, weld::Button&, void)
+{
+ SfxViewFrame* pViewFrame = SfxViewFrame::Current();
+ if( pViewFrame )
+ {
+ SfxItemPool &rPool = pViewFrame->GetPool();
+ SfxRequest aReq(SID_VIEW_DATA_SOURCE_BROWSER, SfxCallMode::SLOT, rPool);
+ pViewFrame->ExecuteSlot( aReq, true );
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/dialogs/hlmarkwn.cxx b/cui/source/dialogs/hlmarkwn.cxx
new file mode 100644
index 000000000..3b985b2b0
--- /dev/null
+++ b/cui/source/dialogs/hlmarkwn.cxx
@@ -0,0 +1,473 @@
+/* -*- 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 <dialmgr.hxx>
+#include <unotools/viewoptions.hxx>
+#include <vcl/graph.hxx>
+
+// UNO-Stuff
+#include <comphelper/processfactory.hxx>
+#include <comphelper/sequence.hxx>
+#include <com/sun/star/awt/XBitmap.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/document/XLinkTargetSupplier.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/io/IOException.hpp>
+
+#include <toolkit/helper/vclunohelper.hxx>
+
+#include <strings.hrc>
+#include <hlmarkwn.hxx>
+#include <hltpbase.hxx>
+#include <hlmarkwn_def.hxx>
+
+using namespace ::com::sun::star;
+
+namespace {
+
+// Userdata-struct for tree-entries
+struct TargetData
+{
+ OUString aUStrLinkname;
+ bool bIsTarget;
+
+ TargetData (const OUString& aUStrLName, bool bTarget)
+ : bIsTarget(bTarget)
+ {
+ if (bIsTarget)
+ aUStrLinkname = aUStrLName;
+ }
+};
+
+}
+
+//*** Window-Class ***
+// Constructor / Destructor
+SvxHlinkDlgMarkWnd::SvxHlinkDlgMarkWnd(weld::Window* pParentDialog, SvxHyperlinkTabPageBase *pParentPage)
+ : GenericDialogController(pParentDialog, "cui/ui/hyperlinkmarkdialog.ui", "HyperlinkMark")
+ , mpParent(pParentPage)
+ , mnError(LERR_NOERROR)
+ , mxBtApply(m_xBuilder->weld_button("ok"))
+ , mxBtClose(m_xBuilder->weld_button("close"))
+ , mxLbTree(m_xBuilder->weld_tree_view("TreeListBox"))
+ , mxError(m_xBuilder->weld_label("error"))
+{
+ mxLbTree->set_size_request(mxLbTree->get_approximate_digit_width() * 25,
+ mxLbTree->get_height_rows(12));
+ mxBtApply->connect_clicked( LINK ( this, SvxHlinkDlgMarkWnd, ClickApplyHdl_Impl ) );
+ mxBtClose->connect_clicked( LINK ( this, SvxHlinkDlgMarkWnd, ClickCloseHdl_Impl ) );
+ mxLbTree->connect_row_activated( LINK ( this, SvxHlinkDlgMarkWnd, DoubleClickApplyHdl_Impl ) );
+}
+
+SvxHlinkDlgMarkWnd::~SvxHlinkDlgMarkWnd()
+{
+ ClearTree();
+}
+
+void SvxHlinkDlgMarkWnd::ErrorChanged()
+{
+ if (mnError == LERR_NOENTRIES)
+ {
+ OUString aStrMessage = CuiResId( RID_SVXSTR_HYPDLG_ERR_LERR_NOENTRIES );
+ mxError->set_label(aStrMessage);
+ mxError->show();
+ mxLbTree->hide();
+ }
+ else if (mnError == LERR_DOCNOTOPEN)
+ {
+ OUString aStrMessage = CuiResId( RID_SVXSTR_HYPDLG_ERR_LERR_DOCNOTOPEN );
+ mxError->set_label(aStrMessage);
+ mxError->show();
+ mxLbTree->hide();
+ }
+ else
+ {
+ mxLbTree->show();
+ mxError->hide();
+ }
+}
+
+// Set an errorstatus
+sal_uInt16 SvxHlinkDlgMarkWnd::SetError( sal_uInt16 nError)
+{
+ sal_uInt16 nOldError = mnError;
+ mnError = nError;
+
+ if( mnError != LERR_NOERROR )
+ ClearTree();
+
+ ErrorChanged();
+
+ return nOldError;
+}
+
+// Move window
+void SvxHlinkDlgMarkWnd::MoveTo(const Point& rNewPos)
+{
+ m_xDialog->window_move(rNewPos.X(), rNewPos.Y());
+}
+
+namespace
+{
+ void SelectPath(weld::TreeIter* pEntry, weld::TreeView& rLbTree,
+ std::deque<OUString> &rLastSelectedPath)
+ {
+ OUString sTitle(rLastSelectedPath.front());
+ rLastSelectedPath.pop_front();
+ if (sTitle.isEmpty())
+ return;
+ while (pEntry)
+ {
+ if (sTitle == rLbTree.get_text(*pEntry))
+ {
+ rLbTree.select(*pEntry);
+ rLbTree.scroll_to_row(*pEntry);
+ if (!rLastSelectedPath.empty())
+ {
+ rLbTree.expand_row(*pEntry);
+ if (!rLbTree.iter_children(*pEntry))
+ pEntry = nullptr;
+ SelectPath(pEntry, rLbTree, rLastSelectedPath);
+ }
+ break;
+ }
+ if (!rLbTree.iter_next_sibling(*pEntry))
+ pEntry = nullptr;
+ }
+ }
+}
+
+#define TG_SETTING_MANAGER "TargetInDocument"
+#define TG_SETTING_LASTMARK "LastSelectedMark"
+#define TG_SETTING_LASTPATH "LastSelectedPath"
+
+void SvxHlinkDlgMarkWnd::RestoreLastSelection()
+{
+ bool bSelectedEntry = false;
+
+ OUString sLastSelectedMark;
+ std::deque<OUString> aLastSelectedPath;
+ SvtViewOptions aViewSettings( EViewType::Dialog, TG_SETTING_MANAGER );
+ if (aViewSettings.Exists())
+ {
+ //Maybe we might want to have some sort of mru list and keep a mapping
+ //per document, rather than the current reuse of "the last thing
+ //selected, regardless of the document"
+ aViewSettings.GetUserItem(TG_SETTING_LASTMARK) >>= sLastSelectedMark;
+ uno::Sequence<OUString> aTmp;
+ aViewSettings.GetUserItem(TG_SETTING_LASTPATH) >>= aTmp;
+ aLastSelectedPath = comphelper::sequenceToContainer< std::deque<OUString> >(aTmp);
+ }
+ //fallback to previous entry selected the last time we executed this dialog.
+ //First see if the exact mark exists and re-use that
+ if (!sLastSelectedMark.isEmpty())
+ bSelectedEntry = SelectEntry(sLastSelectedMark);
+ //Otherwise just select the closest path available
+ //now to what was available at dialog close time
+ if (!bSelectedEntry && !aLastSelectedPath.empty())
+ {
+ std::deque<OUString> aTmpSelectedPath(aLastSelectedPath);
+ std::unique_ptr<weld::TreeIter> xEntry(mxLbTree->make_iterator());
+ if (!mxLbTree->get_iter_first(*xEntry))
+ xEntry.reset();
+ SelectPath(xEntry.get(), *mxLbTree, aTmpSelectedPath);
+ }
+}
+
+// Interface to refresh tree
+void SvxHlinkDlgMarkWnd::RefreshTree (const OUString& aStrURL)
+{
+ OUString aUStrURL;
+
+ weld::WaitObject aWait(m_xDialog.get());
+
+ ClearTree();
+
+ sal_Int32 nPos = aStrURL.indexOf('#');
+
+ if (nPos != 0)
+ aUStrURL = aStrURL;
+
+ if (!RefreshFromDoc(aUStrURL))
+ ErrorChanged();
+
+ bool bSelectedEntry = false;
+
+ if ( nPos != -1 )
+ {
+ OUString aStrMark = aStrURL.copy(nPos+1);
+ bSelectedEntry = SelectEntry(aStrMark);
+ }
+
+ if (!bSelectedEntry)
+ RestoreLastSelection();
+}
+
+// get links from document
+bool SvxHlinkDlgMarkWnd::RefreshFromDoc(const OUString& aURL)
+{
+ mnError = LERR_NOERROR;
+
+ uno::Reference< frame::XDesktop2 > xDesktop = frame::Desktop::create( ::comphelper::getProcessComponentContext() );
+ uno::Reference< lang::XComponent > xComp;
+
+ if( !aURL.isEmpty() )
+ {
+ // load from url
+ if( xDesktop.is() )
+ {
+ try
+ {
+ uno::Sequence< beans::PropertyValue > aArg(1);
+ aArg.getArray()[0].Name = "Hidden";
+ aArg.getArray()[0].Value <<= true;
+ xComp = xDesktop->loadComponentFromURL( aURL, "_blank", 0, aArg );
+ }
+ catch( const io::IOException& )
+ {
+
+ }
+ catch( const lang::IllegalArgumentException& )
+ {
+
+ }
+ }
+ }
+ else
+ {
+ // the component with user focus ( current document )
+ xComp = xDesktop->getCurrentComponent();
+ }
+
+ if( xComp.is() )
+ {
+ uno::Reference< document::XLinkTargetSupplier > xLTS( xComp, uno::UNO_QUERY );
+
+ if( xLTS.is() )
+ {
+ if( FillTree( xLTS->getLinks() ) == 0 )
+ mnError = LERR_NOENTRIES;
+ }
+ else
+ mnError = LERR_DOCNOTOPEN;
+
+ if ( !aURL.isEmpty() )
+ xComp->dispose();
+ }
+ else
+ {
+ if( !aURL.isEmpty() )
+ mnError=LERR_DOCNOTOPEN;
+ }
+ return (mnError==0);
+}
+
+// Fill Tree-Control
+int SvxHlinkDlgMarkWnd::FillTree( const uno::Reference< container::XNameAccess >& xLinks, const weld::TreeIter* pParentEntry )
+{
+ int nEntries=0;
+ const uno::Sequence< OUString > aNames( xLinks->getElementNames() );
+ const sal_uLong nLinks = aNames.getLength();
+ const OUString* pNames = aNames.getConstArray();
+
+ const OUString aProp_LinkDisplayName( "LinkDisplayName" );
+ const OUString aProp_LinkTarget( "com.sun.star.document.LinkTarget" );
+ const OUString aProp_LinkDisplayBitmap( "LinkDisplayBitmap" );
+ for( sal_uLong i = 0; i < nLinks; i++ )
+ {
+ uno::Any aAny;
+ OUString aLink( *pNames++ );
+
+ bool bError = false;
+ try
+ {
+ aAny = xLinks->getByName( aLink );
+ }
+ catch(const uno::Exception&)
+ {
+ // if the name of the target was invalid (like empty headings)
+ // no object can be provided
+ bError = true;
+ }
+ if(bError)
+ continue;
+
+ uno::Reference< beans::XPropertySet > xTarget;
+
+ if( aAny >>= xTarget )
+ {
+ try
+ {
+ // get name to display
+ aAny = xTarget->getPropertyValue( aProp_LinkDisplayName );
+ OUString aDisplayName;
+ aAny >>= aDisplayName;
+ OUString aStrDisplayname ( aDisplayName );
+
+ // is it a target ?
+ uno::Reference< lang::XServiceInfo > xSI( xTarget, uno::UNO_QUERY );
+ bool bIsTarget = xSI->supportsService( aProp_LinkTarget );
+
+ // create userdata
+ TargetData *pData = new TargetData ( aLink, bIsTarget );
+ OUString sId(OUString::number(reinterpret_cast<sal_Int64>(pData)));
+
+ std::unique_ptr<weld::TreeIter> xEntry(mxLbTree->make_iterator());
+ mxLbTree->insert(pParentEntry, -1, &aStrDisplayname, &sId, nullptr, nullptr, nullptr, false, xEntry.get());
+
+ try
+ {
+ // get bitmap for the tree-entry
+ uno::Reference< awt::XBitmap >
+ aXBitmap( xTarget->getPropertyValue( aProp_LinkDisplayBitmap ), uno::UNO_QUERY );
+ if (aXBitmap.is())
+ {
+ Graphic aBmp(Graphic(VCLUnoHelper::GetBitmap(aXBitmap)));
+ // insert Displayname into treelist with bitmaps
+ mxLbTree->set_image(*xEntry, aBmp.GetXGraphic(), -1);
+ }
+ }
+ catch(const css::uno::Exception&)
+ {
+ }
+
+ nEntries++;
+
+ uno::Reference< document::XLinkTargetSupplier > xLTS( xTarget, uno::UNO_QUERY );
+ if( xLTS.is() )
+ nEntries += FillTree( xLTS->getLinks(), xEntry.get() );
+ }
+ catch(const css::uno::Exception&)
+ {
+ }
+ }
+ }
+
+ return nEntries;
+}
+
+// Clear Tree
+void SvxHlinkDlgMarkWnd::ClearTree()
+{
+ std::unique_ptr<weld::TreeIter> xEntry = mxLbTree->make_iterator();
+ bool bEntry = mxLbTree->get_iter_first(*xEntry);
+
+ while (bEntry)
+ {
+ TargetData* pUserData = reinterpret_cast<TargetData*>(mxLbTree->get_id(*xEntry).toInt64());
+ delete pUserData;
+
+ bEntry = mxLbTree->iter_next(*xEntry);
+ }
+
+ mxLbTree->clear();
+}
+
+// Find Entry for String
+std::unique_ptr<weld::TreeIter> SvxHlinkDlgMarkWnd::FindEntry (const OUString& aStrName)
+{
+ bool bFound=false;
+ std::unique_ptr<weld::TreeIter> xEntry = mxLbTree->make_iterator();
+ bool bEntry = mxLbTree->get_iter_first(*xEntry);
+
+ while (bEntry && !bFound)
+ {
+ TargetData* pUserData = reinterpret_cast<TargetData*>(mxLbTree->get_id(*xEntry).toInt64());
+ if (aStrName == pUserData->aUStrLinkname)
+ bFound = true;
+ else
+ bEntry = mxLbTree->iter_next(*xEntry);
+ }
+
+ if (!bFound)
+ xEntry.reset();
+
+ return xEntry;
+}
+
+// Select Entry
+bool SvxHlinkDlgMarkWnd::SelectEntry(const OUString& aStrMark)
+{
+ std::unique_ptr<weld::TreeIter> xEntry = FindEntry(aStrMark);
+ if (!xEntry)
+ return false;
+ mxLbTree->select(*xEntry);
+ mxLbTree->scroll_to_row(*xEntry);
+ return true;
+}
+
+// Click on Apply-Button / Double-click on item in tree
+IMPL_LINK_NOARG(SvxHlinkDlgMarkWnd, DoubleClickApplyHdl_Impl, weld::TreeView&, bool)
+{
+ ClickApplyHdl_Impl(*mxBtApply);
+ return true;
+}
+
+IMPL_LINK_NOARG(SvxHlinkDlgMarkWnd, ClickApplyHdl_Impl, weld::Button&, void)
+{
+ std::unique_ptr<weld::TreeIter> xEntry(mxLbTree->make_iterator());
+ bool bEntry = mxLbTree->get_cursor(xEntry.get());
+ if (bEntry)
+ {
+ TargetData* pData = reinterpret_cast<TargetData*>(mxLbTree->get_id(*xEntry).toInt64());
+ if (pData->bIsTarget)
+ {
+ mpParent->SetMarkStr(pData->aUStrLinkname);
+ }
+ }
+}
+
+// Click on Close-Button
+IMPL_LINK_NOARG(SvxHlinkDlgMarkWnd, ClickCloseHdl_Impl, weld::Button&, void)
+{
+ std::unique_ptr<weld::TreeIter> xEntry(mxLbTree->make_iterator());
+ bool bEntry = mxLbTree->get_cursor(xEntry.get());
+ if (bEntry)
+ {
+ TargetData* pUserData = reinterpret_cast<TargetData*>(mxLbTree->get_id(*xEntry).toInt64());
+ OUString sLastSelectedMark = pUserData->aUStrLinkname;
+
+ std::deque<OUString> aLastSelectedPath;
+ //If the bottommost entry is expanded but nothing
+ //underneath it is selected leave a dummy entry
+ if (mxLbTree->get_row_expanded(*xEntry))
+ aLastSelectedPath.push_front(OUString());
+ while (bEntry)
+ {
+ aLastSelectedPath.push_front(mxLbTree->get_text(*xEntry));
+ bEntry = mxLbTree->iter_parent(*xEntry);
+ }
+
+ uno::Sequence< beans::NamedValue > aSettings
+ {
+ { TG_SETTING_LASTMARK, css::uno::Any(sLastSelectedMark) },
+ { TG_SETTING_LASTPATH, css::uno::Any(comphelper::containerToSequence(aLastSelectedPath)) }
+ };
+
+ // write
+ SvtViewOptions aViewSettings( EViewType::Dialog, TG_SETTING_MANAGER );
+ aViewSettings.SetUserData( aSettings );
+ }
+
+ m_xDialog->response(RET_CANCEL);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/dialogs/hltpbase.cxx b/cui/source/dialogs/hltpbase.cxx
new file mode 100644
index 000000000..b3c7b076f
--- /dev/null
+++ b/cui/source/dialogs/hltpbase.cxx
@@ -0,0 +1,545 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include <sal/config.h>
+
+#include <comphelper/lok.hxx>
+#include <osl/file.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/event.hxx>
+#include <sfx2/frame.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sot/formats.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <svl/macitem.hxx>
+#include <ucbhelper/content.hxx>
+#include <cuihyperdlg.hxx>
+#include <hltpbase.hxx>
+#include <macroass.hxx>
+#include <svx/svxdlg.hxx>
+#include <strings.hrc>
+#include <dialmgr.hxx>
+#include <bitmaps.hlst>
+
+using namespace ::ucbhelper;
+
+namespace {
+
+OUString CreateUiNameFromURL( const OUString& aStrURL )
+{
+ OUString aStrUiURL;
+ INetURLObject aURLObj( aStrURL );
+
+ switch(aURLObj.GetProtocol())
+ {
+ case INetProtocol::File:
+ osl::FileBase::getSystemPathFromFileURL(aURLObj.GetMainURL(INetURLObject::DecodeMechanism::NONE), aStrUiURL);
+ break;
+ case INetProtocol::Ftp :
+ {
+ //remove password from name
+ INetURLObject aTmpURL(aURLObj);
+ aTmpURL.SetPass("");
+ aStrUiURL = aTmpURL.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous );
+ }
+ break;
+ default :
+ {
+ aStrUiURL = aURLObj.GetMainURL(INetURLObject::DecodeMechanism::Unambiguous);
+ }
+ }
+ if(aStrUiURL.isEmpty())
+ return aStrURL;
+ return aStrUiURL;
+}
+
+}
+
+// ComboBox-Control for URL's with History and Autocompletion
+SvxHyperURLBox::SvxHyperURLBox(std::unique_ptr<weld::ComboBox> xControl)
+ : SvtURLBox(std::move(xControl))
+ , DropTargetHelper(getWidget()->get_drop_target())
+{
+ SetSmartProtocol(INetProtocol::Http);
+}
+
+sal_Int8 SvxHyperURLBox::AcceptDrop( const AcceptDropEvent& /* rEvt */ )
+{
+ return IsDropFormatSupported( SotClipboardFormatId::STRING ) ? DND_ACTION_COPY : DND_ACTION_NONE;
+}
+
+sal_Int8 SvxHyperURLBox::ExecuteDrop( const ExecuteDropEvent& rEvt )
+{
+ TransferableDataHelper aDataHelper( rEvt.maDropEvent.Transferable );
+ OUString aString;
+ sal_Int8 nRet = DND_ACTION_NONE;
+
+ if( aDataHelper.GetString( SotClipboardFormatId::STRING, aString ) )
+ {
+ set_entry_text(aString);
+ nRet = DND_ACTION_COPY;
+ }
+
+ return nRet;
+}
+
+//# Hyperlink-Dialog: Tabpages-Baseclass #
+
+SvxHyperlinkTabPageBase::SvxHyperlinkTabPageBase(weld::Container* pParent,
+ SvxHpLinkDlg* pDlg,
+ const OUString& rUIXMLDescription,
+ const OString& rID,
+ const SfxItemSet* pItemSet)
+ : IconChoicePage(pParent, rUIXMLDescription, rID, pItemSet)
+ , mxCbbFrame(xBuilder->weld_combo_box("frame"))
+ , mxLbForm(xBuilder->weld_combo_box("form"))
+ , mxEdIndication(xBuilder->weld_entry("indication"))
+ , mxEdText(xBuilder->weld_entry("name"))
+ , mxBtScript(xBuilder->weld_button("script"))
+ , mxFormLabel(xBuilder->weld_label("form_label"))
+ , mxFrameLabel(xBuilder->weld_label("frame_label"))
+ , mbIsCloseDisabled( false )
+ , mpDialog( pDlg )
+ , mbStdControlsInit( false )
+{
+ // create bookmark-window
+}
+
+SvxHyperlinkTabPageBase::~SvxHyperlinkTabPageBase()
+{
+ maTimer.Stop();
+
+ HideMarkWnd();
+}
+
+bool SvxHyperlinkTabPageBase::QueryClose()
+{
+ return !mbIsCloseDisabled;
+}
+
+void SvxHyperlinkTabPageBase::InitStdControls ()
+{
+ if ( !mbStdControlsInit )
+ {
+ SfxDispatcher* pDispatch = GetDispatcher();
+ SfxViewFrame* pViewFrame = pDispatch ? pDispatch->GetFrame() : nullptr;
+ SfxFrame* pFrame = pViewFrame ? &pViewFrame->GetFrame() : nullptr;
+ if ( pFrame )
+ {
+ std::unique_ptr<TargetList> pList(new TargetList);
+ SfxFrame::GetDefaultTargetList(*pList);
+ if( !pList->empty() )
+ {
+ size_t nCount = pList->size();
+ size_t i;
+ for ( i = 0; i < nCount; i++ )
+ {
+ mxCbbFrame->append_text( pList->at( i ) );
+ }
+ }
+ }
+
+ mxBtScript->set_from_icon_name(RID_SVXBMP_SCRIPT);
+
+ mxBtScript->connect_clicked ( LINK ( this, SvxHyperlinkTabPageBase, ClickScriptHdl_Impl ) );
+ }
+
+ mbStdControlsInit = true;
+}
+
+// Move Extra-Window
+void SvxHyperlinkTabPageBase::MoveToExtraWnd( Point aNewPos )
+{
+ mxMarkWnd->MoveTo(aNewPos);
+}
+
+// Show Extra-Window
+void SvxHyperlinkTabPageBase::ShowMarkWnd()
+{
+ if (mxMarkWnd)
+ {
+ mxMarkWnd->getDialog()->present();
+ return;
+ }
+
+ weld::Dialog* pDialog = mpDialog->getDialog();
+
+ mxMarkWnd = std::make_shared<SvxHlinkDlgMarkWnd>(pDialog, this);
+
+ // Size of dialog-window in screen pixels
+ Point aDlgPos(pDialog->get_position());
+ Size aDlgSize(pDialog->get_size());
+
+ // Absolute size of the screen
+ ::tools::Rectangle aScreen(pDialog->get_monitor_workarea());
+
+ // Size of Extrawindow
+ Size aExtraWndSize(mxMarkWnd->getDialog()->get_preferred_size());
+
+ // mxMarkWnd is a child of mpDialog, so coordinates for positioning must be relative to mpDialog
+ if( aDlgPos.X()+(1.05*aDlgSize.Width())+aExtraWndSize.Width() > aScreen.Right() )
+ {
+ if( aDlgPos.X() - ( 0.05*aDlgSize.Width() ) - aExtraWndSize.Width() < 0 )
+ {
+ // Pos Extrawindow anywhere
+ MoveToExtraWnd( Point(10,10) ); // very unlikely
+ }
+ else
+ {
+ // Pos Extrawindow on the left side of Dialog
+ MoveToExtraWnd( Point(0,0) - Point( long(0.05*aDlgSize.Width()), 0 ) - Point( aExtraWndSize.Width(), 0 ) );
+ }
+ }
+ else
+ {
+ // Pos Extrawindow on the right side of Dialog
+ MoveToExtraWnd ( Point( long(1.05*aDlgSize.getWidth()), 0 ) );
+ }
+
+ // Set size of Extra-Window
+ mxMarkWnd->getDialog()->set_size_request(aExtraWndSize.Width(), aDlgSize.Height());
+
+ weld::DialogController::runAsync(mxMarkWnd, [this](sal_Int32 /*nResult*/) { mxMarkWnd.reset(); } );
+}
+
+void SvxHyperlinkTabPageBase::HideMarkWnd()
+{
+ if (mxMarkWnd)
+ {
+ mxMarkWnd->response(RET_CANCEL);
+ mxMarkWnd.reset();
+ }
+}
+
+// Fill Dialogfields
+void SvxHyperlinkTabPageBase::FillStandardDlgFields ( const SvxHyperlinkItem* pHyperlinkItem )
+{
+ if (!comphelper::LibreOfficeKit::isActive())
+ {
+ // Frame
+ sal_Int32 nPos = mxCbbFrame->find_text(pHyperlinkItem->GetTargetFrame());
+ if (nPos != -1)
+ mxCbbFrame->set_active(nPos);
+
+ // Form
+ OUString aStrFormText = CuiResId( RID_SVXSTR_HYPERDLG_FROM_TEXT );
+
+ OUString aStrFormButton = CuiResId( RID_SVXSTR_HYPERDLG_FORM_BUTTON );
+
+ if( pHyperlinkItem->GetInsertMode() & HLINK_HTMLMODE )
+ {
+ mxLbForm->clear();
+ mxLbForm->append_text( aStrFormText );
+ mxLbForm->set_active( 0 );
+ }
+ else
+ {
+ mxLbForm->clear();
+ mxLbForm->append_text( aStrFormText );
+ mxLbForm->append_text( aStrFormButton );
+ mxLbForm->set_active( pHyperlinkItem->GetInsertMode() == HLINK_BUTTON ? 1 : 0 );
+ }
+ }
+ else
+ {
+ mxCbbFrame->hide();
+ mxLbForm->hide();
+ mxFormLabel->hide();
+ mxFrameLabel->hide();
+ }
+
+ // URL
+ mxEdIndication->set_text( pHyperlinkItem->GetName() );
+
+ // Name
+ mxEdText->set_text( pHyperlinkItem->GetIntName() );
+
+ // Script-button
+ if (!comphelper::LibreOfficeKit::isActive())
+ {
+ if ( pHyperlinkItem->GetMacroEvents() == HyperDialogEvent::NONE )
+ mxBtScript->set_sensitive(false);
+ else
+ mxBtScript->set_sensitive(true);
+ }
+ else
+ {
+ mxBtScript->hide();
+ }
+}
+
+// Any action to do after apply-button is pressed
+void SvxHyperlinkTabPageBase::DoApply ()
+{
+ // default-implementation : do nothing
+}
+
+// Ask page whether an insert is possible
+bool SvxHyperlinkTabPageBase::AskApply ()
+{
+ // default-implementation
+ return true;
+}
+
+// This method would be called from bookmark-window to set new mark-string
+void SvxHyperlinkTabPageBase::SetMarkStr ( const OUString& /*aStrMark*/ )
+{
+ // default-implementation : do nothing
+}
+
+// Set initial focus
+void SvxHyperlinkTabPageBase::SetInitFocus()
+{
+ xContainer->grab_focus();
+}
+
+// retrieve dispatcher
+SfxDispatcher* SvxHyperlinkTabPageBase::GetDispatcher() const
+{
+ return mpDialog->GetDispatcher();
+}
+
+void SvxHyperlinkTabPageBase::DisableClose(bool _bDisable)
+{
+ mbIsCloseDisabled = _bDisable;
+ if (mbIsCloseDisabled)
+ maBusy.incBusy(mpDialog->getDialog());
+ else
+ maBusy.decBusy();
+}
+
+// Click on imagebutton : Script
+IMPL_LINK_NOARG(SvxHyperlinkTabPageBase, ClickScriptHdl_Impl, weld::Button&, void)
+{
+ SvxHyperlinkItem *pHyperlinkItem = const_cast<SvxHyperlinkItem*>(static_cast<const SvxHyperlinkItem *>(
+ GetItemSet().GetItem (SID_HYPERLINK_GETLINK)));
+
+ if ( pHyperlinkItem->GetMacroEvents() == HyperDialogEvent::NONE )
+ return;
+
+ // get macros from itemset
+ const SvxMacroTableDtor* pMacroTbl = pHyperlinkItem->GetMacroTable();
+ SvxMacroItem aItem ( SID_ATTR_MACROITEM );
+ if( pMacroTbl )
+ aItem.SetMacroTable( *pMacroTbl );
+
+ // create empty itemset for macro-dlg
+ std::unique_ptr<SfxItemSet> pItemSet( new SfxItemSet(SfxGetpApp()->GetPool(),
+ svl::Items<SID_ATTR_MACROITEM,
+ SID_ATTR_MACROITEM>{} ) );
+ pItemSet->Put ( aItem );
+
+ DisableClose( true );
+
+ SfxMacroAssignDlg aDlg(mpDialog->getDialog(), mxDocumentFrame, *pItemSet);
+
+ // add events
+ SfxMacroTabPage *pMacroPage = aDlg.GetTabPage();
+
+ if ( pHyperlinkItem->GetMacroEvents() & HyperDialogEvent::MouseOverObject )
+ pMacroPage->AddEvent( CuiResId(RID_SVXSTR_HYPDLG_MACROACT1),
+ SvMacroItemId::OnMouseOver );
+ if ( pHyperlinkItem->GetMacroEvents() & HyperDialogEvent::MouseClickObject )
+ pMacroPage->AddEvent( CuiResId(RID_SVXSTR_HYPDLG_MACROACT2),
+ SvMacroItemId::OnClick);
+ if ( pHyperlinkItem->GetMacroEvents() & HyperDialogEvent::MouseOutObject )
+ pMacroPage->AddEvent( CuiResId(RID_SVXSTR_HYPDLG_MACROACT3),
+ SvMacroItemId::OnMouseOut);
+ // execute dlg
+ short nRet = aDlg.run();
+ DisableClose( false );
+ if ( RET_OK == nRet )
+ {
+ const SfxItemSet* pOutSet = aDlg.GetOutputItemSet();
+ const SfxPoolItem* pItem;
+ if( SfxItemState::SET == pOutSet->GetItemState( SID_ATTR_MACROITEM, false, &pItem ))
+ {
+ pHyperlinkItem->SetMacroTable( static_cast<const SvxMacroItem*>(pItem)->GetMacroTable() );
+ }
+ }
+}
+
+// Get Macro-Infos
+HyperDialogEvent SvxHyperlinkTabPageBase::GetMacroEvents() const
+{
+ const SvxHyperlinkItem *pHyperlinkItem = static_cast<const SvxHyperlinkItem *>(
+ GetItemSet().GetItem (SID_HYPERLINK_GETLINK));
+
+ return pHyperlinkItem->GetMacroEvents();
+}
+
+SvxMacroTableDtor* SvxHyperlinkTabPageBase::GetMacroTable()
+{
+ const SvxHyperlinkItem *pHyperlinkItem = static_cast<const SvxHyperlinkItem *>(
+ GetItemSet().GetItem (SID_HYPERLINK_GETLINK));
+
+ return const_cast<SvxMacroTableDtor*>(pHyperlinkItem->GetMacroTable());
+}
+
+// try to detect the current protocol that is used in rStrURL
+OUString SvxHyperlinkTabPageBase::GetSchemeFromURL( const OUString& rStrURL )
+{
+ OUString aStrScheme;
+
+ INetURLObject aURL( rStrURL );
+ INetProtocol aProtocol = aURL.GetProtocol();
+
+ // our new INetUrlObject now has the ability
+ // to detect if a Url is valid or not :-(
+ if ( aProtocol == INetProtocol::NotValid )
+ {
+ if ( rStrURL.startsWithIgnoreAsciiCase( INET_HTTP_SCHEME ) )
+ {
+ aStrScheme = INET_HTTP_SCHEME;
+ }
+ else if ( rStrURL.startsWithIgnoreAsciiCase( INET_HTTPS_SCHEME ) )
+ {
+ aStrScheme = INET_HTTPS_SCHEME;
+ }
+ else if ( rStrURL.startsWithIgnoreAsciiCase( INET_FTP_SCHEME ) )
+ {
+ aStrScheme = INET_FTP_SCHEME;
+ }
+ else if ( rStrURL.startsWithIgnoreAsciiCase( INET_MAILTO_SCHEME ) )
+ {
+ aStrScheme = INET_MAILTO_SCHEME;
+ }
+ }
+ else
+ aStrScheme = INetURLObject::GetScheme( aProtocol );
+ return aStrScheme;
+}
+
+void SvxHyperlinkTabPageBase::GetDataFromCommonFields( OUString& aStrName,
+ OUString& aStrIntName, OUString& aStrFrame,
+ SvxLinkInsertMode& eMode )
+{
+ aStrIntName = mxEdText->get_text();
+ aStrName = mxEdIndication->get_text();
+ aStrFrame = mxCbbFrame->get_active_text();
+
+ sal_Int32 nPos = mxLbForm->get_active();
+ if (nPos == -1)
+ // This happens when FillStandardDlgFields() hides mpLbForm.
+ nPos = 0;
+ eMode = static_cast<SvxLinkInsertMode>(nPos + 1);
+
+ // Ask dialog whether the current doc is a HTML-doc
+ if (mpDialog->IsHTMLDoc())
+ eMode = static_cast<SvxLinkInsertMode>( sal_uInt16(eMode) | HLINK_HTMLMODE );
+}
+
+// reset dialog-fields
+void SvxHyperlinkTabPageBase::Reset( const SfxItemSet& rItemSet)
+{
+
+ // Set dialog-fields from create-itemset
+ maStrInitURL.clear();
+
+ const SvxHyperlinkItem *pHyperlinkItem = static_cast<const SvxHyperlinkItem *>(
+ rItemSet.GetItem (SID_HYPERLINK_GETLINK));
+
+ if ( pHyperlinkItem )
+ {
+ // set dialog-fields
+ FillStandardDlgFields (pHyperlinkItem);
+
+ // set all other fields
+ FillDlgFields ( pHyperlinkItem->GetURL() );
+
+ // Store initial URL
+ maStrInitURL = pHyperlinkItem->GetURL();
+ }
+}
+
+// Fill output-ItemSet
+bool SvxHyperlinkTabPageBase::FillItemSet( SfxItemSet* rOut)
+{
+ OUString aStrURL, aStrName, aStrIntName, aStrFrame;
+ SvxLinkInsertMode eMode;
+
+ GetCurentItemData ( aStrURL, aStrName, aStrIntName, aStrFrame, eMode);
+ if ( aStrName.isEmpty() ) //automatically create a visible name if the link is created without name
+ aStrName = CreateUiNameFromURL(aStrURL);
+
+ HyperDialogEvent nEvents = GetMacroEvents();
+ SvxMacroTableDtor* pTable = GetMacroTable();
+
+ SvxHyperlinkItem aItem( SID_HYPERLINK_SETLINK, aStrName, aStrURL, aStrFrame,
+ aStrIntName, eMode, nEvents, pTable );
+ rOut->Put (aItem);
+
+ return true;
+}
+
+// Activate / Deactivate Tabpage
+void SvxHyperlinkTabPageBase::ActivatePage( const SfxItemSet& rItemSet )
+{
+
+ // Set dialog-fields from input-itemset
+ const SvxHyperlinkItem *pHyperlinkItem = static_cast<const SvxHyperlinkItem *>(
+ rItemSet.GetItem (SID_HYPERLINK_GETLINK));
+
+ if ( pHyperlinkItem )
+ {
+ // standard-fields
+ FillStandardDlgFields (pHyperlinkItem);
+ }
+
+ // show mark-window if it was open before
+ if ( ShouldOpenMarkWnd () )
+ ShowMarkWnd ();
+}
+
+DeactivateRC SvxHyperlinkTabPageBase::DeactivatePage( SfxItemSet* _pSet)
+{
+ // hide mark-wnd
+ SetMarkWndShouldOpen( IsMarkWndVisible () );
+ HideMarkWnd ();
+
+ // retrieve data of dialog
+ OUString aStrURL, aStrName, aStrIntName, aStrFrame;
+ SvxLinkInsertMode eMode;
+
+ GetCurentItemData ( aStrURL, aStrName, aStrIntName, aStrFrame, eMode);
+
+ HyperDialogEvent nEvents = GetMacroEvents();
+ SvxMacroTableDtor* pTable = GetMacroTable();
+
+ if( _pSet )
+ {
+ SvxHyperlinkItem aItem( SID_HYPERLINK_GETLINK, aStrName, aStrURL, aStrFrame,
+ aStrIntName, eMode, nEvents, pTable );
+ _pSet->Put( aItem );
+ }
+
+ return DeactivateRC::LeavePage;
+}
+
+bool SvxHyperlinkTabPageBase::ShouldOpenMarkWnd()
+{
+ return false;
+}
+
+void SvxHyperlinkTabPageBase::SetMarkWndShouldOpen(bool)
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/dialogs/hyphen.cxx b/cui/source/dialogs/hyphen.cxx
new file mode 100644
index 000000000..f7b6549fc
--- /dev/null
+++ b/cui/source/dialogs/hyphen.cxx
@@ -0,0 +1,471 @@
+/* -*- 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 <hyphen.hxx>
+
+#include <com/sun/star/linguistic2/XLinguProperties.hpp>
+
+#include <editeng/splwrap.hxx>
+#include <editeng/unolingu.hxx>
+#include <svtools/langtab.hxx>
+#include <sal/log.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <tools/debug.hxx>
+
+#define HYPH_POS_CHAR '='
+
+#define CUR_HYPH_POS_CHAR '-'
+
+using namespace css;
+
+IMPL_LINK_NOARG(SvxHyphenWordDialog, CursorChangeHdl_Impl, weld::Entry&, void)
+{
+ int nStart, nEnd;
+ m_xWordEdit->get_selection_bounds(nStart, nEnd);
+ if (nStart == m_nOldPos && nEnd == m_nOldPos + 1)
+ return;
+ bool bReSelect;
+ if (nStart <= m_nOldPos)
+ bReSelect = !SelLeft();
+ else
+ bReSelect = !SelRight();
+ if (bReSelect)
+ select_region(m_nOldPos, m_nOldPos + 1);
+}
+
+void SvxHyphenWordDialog::EnableLRBtn_Impl()
+{
+ const sal_Int32 nLen = m_aEditWord.getLength();
+
+ m_xRightBtn->set_sensitive(false);
+ for ( sal_Int32 i = m_nOldPos + 2; i < nLen; ++i )
+ {
+ if ( m_aEditWord[ i ] == sal_Unicode( HYPH_POS_CHAR ) )
+ {
+ m_xRightBtn->set_sensitive(true);
+ break;
+ }
+ }
+
+ DBG_ASSERT(m_nOldPos < nLen, "nOldPos out of range");
+ if (m_nOldPos >= nLen)
+ m_nOldPos = nLen - 1;
+ m_xLeftBtn->set_sensitive(false);
+ for ( sal_Int32 i = m_nOldPos; i-- > 0; )
+ {
+ if ( m_aEditWord[ i ] == sal_Unicode( HYPH_POS_CHAR ) )
+ {
+ m_xLeftBtn->set_sensitive(true);
+ break;
+ }
+ }
+}
+
+OUString SvxHyphenWordDialog::EraseUnusableHyphens_Impl()
+{
+ // returns a String showing only those hyphen positions which will result
+ // in a line break if hyphenation is done there
+ // 1) we will need to discard all hyphenation positions at the end that
+ // will not result in a line break where the text to the left still fits
+ // on the line.
+ // 2) since as from OOo 3.2 '-' are part of a word and thus text like
+ // 'multi-line-editor' is regarded as single word we also need to discard those
+ // hyphenation positions to the left of the rightmost '-' that is still left of
+ // the rightmost valid hyphenation position according to 1)
+
+ // Example:
+ // If the possible hyphenation position in 'multi-line-editor' are to be marked
+ // by '=' then the text will look like this: 'mul=ti-line-ed=it=or'.
+ // If now the first line is only large enough for 'multi-line-edi' we need to discard
+ // the last possible hyphenation point because of 1). The right most valid
+ // hyphenation position is "ed=itor". The first '-' left of this position is
+ // "line-ed", thus because of 2) we now need to discard all possible hyphenation
+ // positions to the left of that as well. Thus in the end leaving us with just
+ // 'multi-line-ed=itor' as return value for this function. (Just one valid hyphenation
+ // position for the user to choose from. However ALL the '-' characters in the word
+ // will ALWAYS be valid implicit hyphenation positions for the core to choose from!
+ // And thus even if this word is skipped in the hyphenation dialog it will still be broken
+ // right after 'multi-line-' (actually it might already be broken up that way before
+ // the hyphenation dialog is called!).
+ // Thus rule 2) just eliminates those positions which will not be used by the core at all
+ // even if the user were to select one of them.
+
+ OUString aTxt;
+ DBG_ASSERT(m_xPossHyph.is(), "missing possible hyphens");
+ if (m_xPossHyph.is())
+ {
+ DBG_ASSERT( m_aActWord == m_xPossHyph->getWord(), "word mismatch" );
+
+ aTxt = m_xPossHyph->getPossibleHyphens();
+
+ m_nHyphenationPositionsOffset = 0;
+ uno::Sequence< sal_Int16 > aHyphenationPositions(
+ m_xPossHyph->getHyphenationPositions() );
+ sal_Int32 nLen = aHyphenationPositions.getLength();
+ const sal_Int16 *pHyphenationPos = aHyphenationPositions.getConstArray();
+
+ // find position nIdx after which all hyphen positions are unusable
+ sal_Int32 nIdx = -1;
+ sal_Int32 nPos = 0, nPos1 = 0;
+ if (nLen)
+ {
+ sal_Int32 nStart = 0;
+ for (sal_Int32 i = 0; i < nLen; ++i)
+ {
+ if (pHyphenationPos[i] > m_nMaxHyphenationPos)
+ break;
+ else
+ {
+ // find corresponding hyphen positions in string
+ nPos = aTxt.indexOf( sal_Unicode( HYPH_POS_CHAR ), nStart );
+
+ if (nPos == -1)
+ break;
+ else
+ {
+ nIdx = nPos;
+ nStart = nPos + 1;
+ }
+ }
+ }
+ }
+ DBG_ASSERT(nIdx != -1, "no usable hyphenation position");
+
+ // 1) remove all not usable hyphenation positions from the end of the string
+ nPos = nIdx == -1 ? 0 : nIdx + 1;
+ nPos1 = nPos; //save for later use in 2) below
+ const OUString aTmp( sal_Unicode( HYPH_POS_CHAR ) );
+ while (nPos != -1)
+ {
+ nPos++;
+ aTxt = aTxt.replaceFirst( aTmp, "", &nPos);
+ }
+
+ // 2) remove all hyphenation positions from the start that are not considered by the core
+ const OUString aSearchRange( aTxt.copy( 0, nPos1 ) );
+ sal_Int32 nPos2 = aSearchRange.lastIndexOf( '-' ); // the '-' position the core will use by default
+ if (nPos2 != -1 )
+ {
+ OUString aLeft( aSearchRange.copy( 0, nPos2 ) );
+ nPos = 0;
+ while (nPos != -1)
+ {
+ nPos++;
+ aLeft = aLeft.replaceFirst( aTmp, "", &nPos );
+ if (nPos != -1)
+ ++m_nHyphenationPositionsOffset;
+ }
+ aTxt = aTxt.replaceAt( 0, nPos2, aLeft );
+ }
+ }
+ return aTxt;
+}
+
+void SvxHyphenWordDialog::InitControls_Impl()
+{
+ m_xPossHyph = nullptr;
+ if (m_xHyphenator.is())
+ {
+ lang::Locale aLocale( LanguageTag::convertToLocale(m_nActLanguage) );
+ m_xPossHyph = m_xHyphenator->createPossibleHyphens( m_aActWord, aLocale,
+ uno::Sequence< beans::PropertyValue >() );
+ if (m_xPossHyph.is())
+ m_aEditWord = EraseUnusableHyphens_Impl();
+ }
+ m_xWordEdit->set_text(m_aEditWord);
+
+ m_nOldPos = m_aEditWord.getLength();
+ SelLeft();
+ EnableLRBtn_Impl();
+}
+
+void SvxHyphenWordDialog::ContinueHyph_Impl( sal_Int32 nInsPos )
+{
+ if ( nInsPos >= 0 && m_xPossHyph.is() )
+ {
+ if (nInsPos)
+ {
+ DBG_ASSERT(nInsPos <= m_aEditWord.getLength() - 2, "wrong hyphen position");
+
+ sal_Int32 nIdxPos = -1;
+ for (sal_Int32 i = 0; i <= nInsPos; ++i)
+ {
+ if (HYPH_POS_CHAR == m_aEditWord[ i ])
+ nIdxPos++;
+ }
+ // take the possible hyphenation positions that got removed from the
+ // start of the word into account:
+ nIdxPos += m_nHyphenationPositionsOffset;
+
+ uno::Sequence< sal_Int16 > aSeq = m_xPossHyph->getHyphenationPositions();
+ sal_Int32 nLen = aSeq.getLength();
+ DBG_ASSERT(nLen, "empty sequence");
+ DBG_ASSERT(0 <= nIdxPos && nIdxPos < nLen, "index out of range");
+ if (nLen && 0 <= nIdxPos && nIdxPos < nLen)
+ {
+ nInsPos = aSeq.getConstArray()[ nIdxPos ];
+ m_pHyphWrapper->InsertHyphen( nInsPos );
+ }
+ }
+ else
+ {
+ //! calling with 0 as argument will remove hyphens!
+ m_pHyphWrapper->InsertHyphen( nInsPos );
+ }
+ }
+
+ if ( m_pHyphWrapper->FindSpellError() )
+ {
+ uno::Reference< linguistic2::XHyphenatedWord > xHyphWord( m_pHyphWrapper->GetLast(), uno::UNO_QUERY );
+
+ // adapt actual word and language to new found hyphenation result
+ if(xHyphWord.is())
+ {
+ m_aActWord = xHyphWord->getWord();
+ m_nActLanguage = LanguageTag( xHyphWord->getLocale() ).getLanguageType();
+ m_nMaxHyphenationPos = xHyphWord->getHyphenationPos();
+ InitControls_Impl();
+ SetWindowTitle( m_nActLanguage );
+ }
+ }
+ else
+ {
+ m_xCloseBtn->set_sensitive(false);
+ m_xDialog->response(RET_OK);
+ }
+}
+
+bool SvxHyphenWordDialog::SelLeft()
+{
+ bool bRet = false;
+ DBG_ASSERT( m_nOldPos > 0, "invalid hyphenation position" );
+ if (m_nOldPos > 0)
+ {
+ OUString aTxt( m_aEditWord );
+ for( sal_Int32 i = m_nOldPos - 1; i > 0; --i )
+ {
+ DBG_ASSERT(i <= aTxt.getLength(), "index out of range");
+ if (aTxt[ i ] == sal_Unicode( HYPH_POS_CHAR ))
+ {
+ aTxt = aTxt.replaceAt( i, 1, OUString( CUR_HYPH_POS_CHAR ) );
+
+ m_nOldPos = i;
+ m_xWordEdit->set_text(aTxt);
+ select_region(i, i + 1);
+ m_xWordEdit->grab_focus();
+ bRet = true;
+ break;
+ }
+ }
+ EnableLRBtn_Impl();
+ }
+ return bRet;
+}
+
+bool SvxHyphenWordDialog::SelRight()
+{
+ bool bRet = false;
+ OUString aTxt( m_aEditWord );
+ for ( sal_Int32 i = m_nOldPos + 1; i < aTxt.getLength(); ++i )
+ {
+ if (aTxt[ i ] == sal_Unicode( HYPH_POS_CHAR ))
+ {
+ aTxt = aTxt.replaceAt( i, 1, OUString( CUR_HYPH_POS_CHAR ) );
+
+ m_nOldPos = i;
+ m_xWordEdit->set_text(aTxt);
+ select_region(i, i + 1);
+ m_xWordEdit->grab_focus();
+ bRet = true;
+ break;
+ }
+ }
+ EnableLRBtn_Impl();
+ return bRet;
+}
+
+IMPL_LINK_NOARG(SvxHyphenWordDialog, CutHdl_Impl, weld::Button&, void)
+{
+ if( !m_bBusy )
+ {
+ m_bBusy = true;
+ ContinueHyph_Impl( /*m_nHyphPos*/m_nOldPos );
+ m_bBusy = false;
+ }
+}
+
+IMPL_LINK_NOARG(SvxHyphenWordDialog, HyphenateAllHdl_Impl, weld::Button&, void)
+{
+ if( m_bBusy )
+ return;
+
+ try
+ {
+ uno::Reference< linguistic2::XLinguProperties > xProp( LinguMgr::GetLinguPropertySet() );
+
+ xProp->setIsHyphAuto( true );
+
+ m_bBusy = true;
+ ContinueHyph_Impl( /*m_nHyphPos*/m_nOldPos );
+ m_bBusy = false;
+
+ xProp->setIsHyphAuto( false );
+ }
+ catch (uno::Exception &)
+ {
+ SAL_WARN( "cui.dialogs", "Hyphenate All failed" );
+ }
+}
+
+IMPL_LINK_NOARG(SvxHyphenWordDialog, DeleteHdl_Impl, weld::Button&, void)
+{
+ if( !m_bBusy )
+ {
+ m_bBusy = true;
+ ContinueHyph_Impl( 0 );
+ m_bBusy = false;
+ }
+}
+
+IMPL_LINK_NOARG(SvxHyphenWordDialog, ContinueHdl_Impl, weld::Button&, void)
+{
+ if( !m_bBusy )
+ {
+ m_bBusy = true;
+ ContinueHyph_Impl();
+ m_bBusy = false;
+ }
+}
+
+IMPL_LINK_NOARG(SvxHyphenWordDialog, CancelHdl_Impl, weld::Button&, void)
+{
+ if( !m_bBusy )
+ {
+ m_bBusy = true;
+ m_xDialog->response(RET_CANCEL);
+ m_bBusy = false;
+ }
+}
+
+IMPL_LINK_NOARG(SvxHyphenWordDialog, Left_Impl, weld::Button&, void)
+{
+ if( !m_bBusy )
+ {
+ m_bBusy = true;
+ SelLeft();
+ m_bBusy = false;
+ }
+}
+
+IMPL_LINK_NOARG(SvxHyphenWordDialog, Right_Impl, weld::Button&, void)
+{
+ if( !m_bBusy )
+ {
+ m_bBusy = true;
+ SelRight();
+ m_bBusy = false;
+ }
+}
+
+void SvxHyphenWordDialog::select_region(int nStart, int nEnd)
+{
+ int nScrollPos = nStart + m_nWordEditWidth/2;
+ if (nScrollPos > m_aEditWord.getLength())
+ nScrollPos = m_aEditWord.getLength() - m_nWordEditWidth/2;
+ if (nScrollPos < 0)
+ nScrollPos = 0;
+ m_xWordEdit->set_position(nScrollPos);
+ m_xWordEdit->select_region(nStart, nEnd);
+}
+
+IMPL_LINK_NOARG(SvxHyphenWordDialog, GetFocusHdl_Impl, weld::Widget&, void)
+{
+ select_region(m_nOldPos, m_nOldPos + 1);
+}
+
+// class SvxHyphenWordDialog ---------------------------------------------
+
+SvxHyphenWordDialog::SvxHyphenWordDialog(
+ const OUString &rWord, LanguageType nLang,
+ weld::Window* pParent,
+ uno::Reference< linguistic2::XHyphenator > const &xHyphen,
+ SvxSpellWrapper* pWrapper)
+ : SfxDialogController(pParent, "cui/ui/hyphenate.ui", "HyphenateDialog")
+ , m_pHyphWrapper(pWrapper)
+ , m_aActWord(rWord)
+ , m_nActLanguage(nLang)
+ , m_nMaxHyphenationPos(0)
+ , m_nOldPos(0)
+ , m_nHyphenationPositionsOffset(0)
+ , m_bBusy(false)
+ , m_xWordEdit(m_xBuilder->weld_entry("worded"))
+ , m_xLeftBtn(m_xBuilder->weld_button("left"))
+ , m_xRightBtn(m_xBuilder->weld_button("right"))
+ , m_xOkBtn(m_xBuilder->weld_button("ok"))
+ , m_xContBtn(m_xBuilder->weld_button("continue"))
+ , m_xDelBtn(m_xBuilder->weld_button("delete"))
+ , m_xHyphAll(m_xBuilder->weld_button("hyphall"))
+ , m_xCloseBtn(m_xBuilder->weld_button("close"))
+{
+ m_nWordEditWidth = m_xWordEdit->get_width_chars();
+ m_aLabel = m_xDialog->get_title();
+ m_xHyphenator = xHyphen;
+
+ uno::Reference< linguistic2::XHyphenatedWord > xHyphWord( m_pHyphWrapper ?
+ m_pHyphWrapper->GetLast() : nullptr, uno::UNO_QUERY );
+ DBG_ASSERT( xHyphWord.is(), "hyphenation result missing" );
+ if (xHyphWord.is())
+ {
+ DBG_ASSERT( m_aActWord == xHyphWord->getWord(), "word mismatch" );
+ DBG_ASSERT( m_nActLanguage == LanguageTag( xHyphWord->getLocale() ).getLanguageType(), "language mismatch" );
+ m_nMaxHyphenationPos = xHyphWord->getHyphenationPos();
+ }
+
+ InitControls_Impl();
+ m_xWordEdit->grab_focus();
+
+ m_xLeftBtn->connect_clicked( LINK( this, SvxHyphenWordDialog, Left_Impl ) );
+ m_xRightBtn->connect_clicked( LINK( this, SvxHyphenWordDialog, Right_Impl ) );
+ m_xOkBtn->connect_clicked( LINK( this, SvxHyphenWordDialog, CutHdl_Impl ) );
+ m_xContBtn->connect_clicked( LINK( this, SvxHyphenWordDialog, ContinueHdl_Impl ) );
+ m_xDelBtn->connect_clicked( LINK( this, SvxHyphenWordDialog, DeleteHdl_Impl ) );
+ m_xHyphAll->connect_clicked( LINK( this, SvxHyphenWordDialog, HyphenateAllHdl_Impl ) );
+ m_xCloseBtn->connect_clicked( LINK( this, SvxHyphenWordDialog, CancelHdl_Impl ) );
+ m_xWordEdit->connect_focus_in( LINK( this, SvxHyphenWordDialog, GetFocusHdl_Impl ) );
+ m_xWordEdit->connect_cursor_position( LINK( this, SvxHyphenWordDialog, CursorChangeHdl_Impl ) );
+
+ SetWindowTitle( nLang );
+
+ // disable controls if service is not available
+ if (!m_xHyphenator.is())
+ m_xDialog->set_sensitive(false);
+}
+
+SvxHyphenWordDialog::~SvxHyphenWordDialog()
+{
+ if (m_xCloseBtn->get_sensitive())
+ m_pHyphWrapper->SpellEnd();
+}
+
+void SvxHyphenWordDialog::SetWindowTitle(LanguageType nLang)
+{
+ m_xDialog->set_title(m_aLabel + " (" + SvtLanguageTable::GetLanguageString(nLang) + ")");
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/dialogs/iconcdlg.cxx b/cui/source/dialogs/iconcdlg.cxx
new file mode 100644
index 000000000..bca5984f8
--- /dev/null
+++ b/cui/source/dialogs/iconcdlg.cxx
@@ -0,0 +1,311 @@
+/* -*- 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 <iconcdlg.hxx>
+#include <cuihyperdlg.hxx>
+
+#include <cassert>
+#include <sal/log.hxx>
+#include <vcl/svapp.hxx>
+
+/**********************************************************************
+|
+| Ctor / Dtor
+|
+\**********************************************************************/
+
+IconChoicePage::IconChoicePage(weld::Container* pParent,
+ const OUString& rUIXMLDescription, const OString& rID,
+ const SfxItemSet* pItemSet)
+ : xBuilder(Application::CreateBuilder(pParent, rUIXMLDescription))
+ , xContainer(xBuilder->weld_container(rID))
+ , pSet(pItemSet)
+ , bHasExchangeSupport(false)
+{
+}
+
+IconChoicePage::~IconChoicePage()
+{
+}
+
+/**********************************************************************
+|
+| Activate / Deactivate
+|
+\**********************************************************************/
+
+void IconChoicePage::ActivatePage( const SfxItemSet& )
+{
+}
+
+
+DeactivateRC IconChoicePage::DeactivatePage( SfxItemSet* )
+{
+ return DeactivateRC::LeavePage;
+}
+
+bool IconChoicePage::QueryClose()
+{
+ return true;
+}
+
+/**********************************************************************
+|
+| add new page
+|
+\**********************************************************************/
+void SvxHpLinkDlg::AddTabPage(const OString& rId, CreatePage pCreateFunc /* != 0 */)
+{
+ weld::Container* pPage = m_xIconCtrl->get_page(rId);
+ maPageList.emplace_back(new IconChoicePageData(rId, pCreateFunc(pPage, this, pSet)));
+ maPageList.back()->xPage->Reset(*pSet);
+ PageCreated(rId, *maPageList.back()->xPage);
+}
+
+/**********************************************************************
+|
+| Show / Hide page or button
+|
+\**********************************************************************/
+void SvxHpLinkDlg::ShowPage(const OString& rId)
+{
+ OString sOldPageId = GetCurPageId();
+ bool bInvalidate = sOldPageId != rId;
+ if (bInvalidate)
+ {
+ IconChoicePageData* pOldData = GetPageData(sOldPageId);
+ if (pOldData && pOldData->xPage)
+ {
+ DeActivatePageImpl();
+ }
+ }
+ SetCurPageId(rId);
+ ActivatePageImpl();
+}
+
+/**********************************************************************
+|
+| select a page
+|
+\**********************************************************************/
+IMPL_LINK(SvxHpLinkDlg, ChosePageHdl_Impl, const OString&, rId, void)
+{
+ if (rId != msCurrentPageId)
+ {
+ ShowPage(rId);
+ }
+}
+
+/**********************************************************************
+|
+| Button-handler
+|
+\**********************************************************************/
+IMPL_LINK_NOARG(SvxHpLinkDlg, ResetHdl, weld::Button&, void)
+{
+ ResetPageImpl ();
+
+ IconChoicePageData* pData = GetPageData ( msCurrentPageId );
+ assert( pData && "ID not known " );
+
+ pData->xPage->Reset( *pSet );
+}
+
+/**********************************************************************
+|
+| call page
+|
+\**********************************************************************/
+void SvxHpLinkDlg::ActivatePageImpl()
+{
+ assert( !maPageList.empty() && "no Pages registered " );
+ IconChoicePageData* pData = GetPageData ( msCurrentPageId );
+ assert( pData && "ID not known " );
+
+ if ( pData->bRefresh )
+ {
+ pData->xPage->Reset( *pSet );
+ pData->bRefresh = false;
+ }
+
+ if ( pExampleSet )
+ pData->xPage->ActivatePage( *pExampleSet );
+ m_xDialog->set_help_id(pData->xPage->GetHelpId());
+
+ m_xResetBtn->show();
+}
+
+void SvxHpLinkDlg::DeActivatePageImpl ()
+{
+ IconChoicePageData *pData = GetPageData ( msCurrentPageId );
+
+ DeactivateRC nRet = DeactivateRC::LeavePage;
+
+ if ( !pData )
+ return;
+
+ IconChoicePage * pPage = pData->xPage.get();
+
+ if ( !pExampleSet && pPage->HasExchangeSupport() && pSet )
+ pExampleSet = new SfxItemSet( *pSet->GetPool(), pSet->GetRanges() );
+
+ if ( pSet )
+ {
+ SfxItemSet aTmp( *pSet->GetPool(), pSet->GetRanges() );
+
+ if ( pPage->HasExchangeSupport() )
+ nRet = pPage->DeactivatePage( &aTmp );
+
+ if ( ( DeactivateRC::LeavePage & nRet ) &&
+ aTmp.Count() )
+ {
+ if (pExampleSet)
+ pExampleSet->Put(aTmp);
+ pOutSet->Put( aTmp );
+ }
+ }
+ else
+ {
+ if ( pPage->HasExchangeSupport() ) //!!!
+ {
+ if ( !pExampleSet )
+ {
+ SfxItemPool* pPool = pPage->GetItemSet().GetPool();
+ pExampleSet =
+ new SfxItemSet( *pPool, GetInputRanges( *pPool ) );
+ }
+ nRet = pPage->DeactivatePage( pExampleSet );
+ }
+ else
+ nRet = pPage->DeactivatePage( nullptr );
+ }
+
+ if ( nRet & DeactivateRC::RefreshSet )
+ {
+ // TODO refresh input set
+ // flag all pages to be newly initialized
+ for (auto & pObj : maPageList)
+ {
+ if ( pObj->xPage.get() != pPage )
+ pObj->bRefresh = true;
+ else
+ pObj->bRefresh = false;
+ }
+ }
+}
+
+
+void SvxHpLinkDlg::ResetPageImpl ()
+{
+ IconChoicePageData *pData = GetPageData ( msCurrentPageId );
+
+ assert( pData && "ID not known " );
+
+ pData->xPage->Reset( *pSet );
+}
+
+/**********************************************************************
+|
+| handling itemsets
+|
+\**********************************************************************/
+
+const sal_uInt16* SvxHpLinkDlg::GetInputRanges( const SfxItemPool& )
+{
+ if ( pSet )
+ {
+ SAL_WARN( "cui.dialogs", "Set does already exist!" );
+ return pSet->GetRanges();
+ }
+
+ if ( pRanges )
+ return pRanges.get();
+
+ pRanges.reset(new sal_uInt16[1]);
+ pRanges[0] = 0;
+
+ return pRanges.get();
+}
+
+
+void SvxHpLinkDlg::SetInputSet( const SfxItemSet* pInSet )
+{
+ bool bSet = ( pSet != nullptr );
+
+ pSet = pInSet;
+
+ if ( !bSet && !pExampleSet && !pOutSet )
+ {
+ pExampleSet = new SfxItemSet( *pSet );
+ pOutSet.reset(new SfxItemSet( *pSet->GetPool(), pSet->GetRanges() ));
+ }
+}
+
+bool SvxHpLinkDlg::QueryClose()
+{
+ bool bRet = true;
+ for (auto & pData : maPageList)
+ {
+ if ( pData->xPage && !pData->xPage->QueryClose() )
+ {
+ bRet = false;
+ break;
+ }
+ }
+ return bRet;
+}
+
+void SvxHpLinkDlg::Start()
+{
+ SwitchPage(msCurrentPageId);
+ ActivatePageImpl();
+}
+
+/**********************************************************************
+|
+| tool-methods
+|
+\**********************************************************************/
+
+IconChoicePageData* SvxHpLinkDlg::GetPageData ( const OString& rId )
+{
+ IconChoicePageData *pRet = nullptr;
+ for (const auto & pData : maPageList)
+ {
+ if ( pData->sId == rId )
+ {
+ pRet = pData.get();
+ break;
+ }
+ }
+ return pRet;
+}
+
+/**********************************************************************
+|
+| OK-Status
+|
+\**********************************************************************/
+
+void SvxHpLinkDlg::SwitchPage( const OString& rId )
+{
+ m_xIconCtrl->set_current_page(rId);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/dialogs/insdlg.cxx b/cui/source/dialogs/insdlg.cxx
new file mode 100644
index 000000000..4f34b461e
--- /dev/null
+++ b/cui/source/dialogs/insdlg.cxx
@@ -0,0 +1,583 @@
+/* -*- 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/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/embed/EmbedStates.hpp>
+#include <com/sun/star/embed/XInsertObjectDialog.hpp>
+#include <com/sun/star/embed/MSOLEObjectSystemCreator.hpp>
+#include <com/sun/star/task/InteractionHandler.hpp>
+#include <com/sun/star/ucb/CommandAbortedException.hpp>
+#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
+#include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
+#include <com/sun/star/ui/dialogs/XFilePicker3.hpp>
+#include <comphelper/processfactory.hxx>
+
+#include <insdlg.hxx>
+#include <dialmgr.hxx>
+#include <osl/diagnose.h>
+#include <svtools/imagemgr.hxx>
+#include <svtools/strings.hrc>
+#include <svtools/svtresid.hxx>
+
+#include <sal/log.hxx>
+#include <tools/urlobj.hxx>
+#include <tools/debug.hxx>
+#include <tools/stream.hxx>
+#include <vcl/image.hxx>
+#include <vcl/weld.hxx>
+#include <vcl/svapp.hxx>
+#include <comphelper/classids.hxx>
+#include <sfx2/filedlghelper.hxx>
+#include <sfx2/frmdescr.hxx>
+#include <sfx2/viewsh.hxx>
+#include <comphelper/seqstream.hxx>
+
+#include <strings.hrc>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::ui::dialogs;
+
+bool InsertObjectDialog_Impl::IsCreateNew() const
+{
+ return false;
+}
+
+uno::Reference< io::XInputStream > InsertObjectDialog_Impl::GetIconIfIconified( OUString* /*pGraphicMediaType*/ )
+{
+ return uno::Reference< io::XInputStream >();
+}
+
+InsertObjectDialog_Impl::InsertObjectDialog_Impl(weld::Window* pParent,
+ const OUString& rUIXMLDescription, const OString& rID,
+ const css::uno::Reference < css::embed::XStorage >& xStorage)
+ : GenericDialogController(pParent, rUIXMLDescription, rID)
+ , m_xStorage( xStorage )
+ , aCnt( m_xStorage )
+{
+}
+
+IMPL_LINK_NOARG(SvInsertOleDlg, DoubleClickHdl, weld::TreeView&, bool)
+{
+ m_xDialog->response(RET_OK);
+ return true;
+}
+
+IMPL_LINK_NOARG(SvInsertOleDlg, BrowseHdl, weld::Button&, void)
+{
+ sfx2::FileDialogHelper aHelper(ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE, FileDialogFlags::NONE, m_xDialog.get());
+ const Reference< XFilePicker3 >& xFilePicker = aHelper.GetFilePicker();
+
+ // add filter
+ try
+ {
+ xFilePicker->appendFilter(CuiResId(RID_SVXSTR_FILTER_ALL), "*.*");
+ }
+ catch( const IllegalArgumentException& )
+ {
+ SAL_WARN( "cui.dialogs", "caught IllegalArgumentException when registering filter" );
+ }
+
+ if( xFilePicker->execute() == ExecutableDialogResults::OK )
+ {
+ Sequence< OUString > aPathSeq( xFilePicker->getSelectedFiles() );
+ INetURLObject aObj( aPathSeq[0] );
+ m_xEdFilepath->set_text(aObj.PathToFileName());
+ }
+}
+
+IMPL_LINK_NOARG(SvInsertOleDlg, RadioHdl, weld::Button&, void)
+{
+ if (m_xRbNewObject->get_active())
+ {
+ m_xObjectTypeFrame->show();
+ m_xFileFrame->hide();
+ }
+ else
+ {
+ m_xFileFrame->show();
+ m_xObjectTypeFrame->hide();
+ }
+}
+
+SvInsertOleDlg::SvInsertOleDlg(weld::Window* pParent, const Reference<embed::XStorage>& xStorage,
+ const SvObjectServerList* pServers)
+ : InsertObjectDialog_Impl( pParent, "cui/ui/insertoleobject.ui", "InsertOLEObjectDialog", xStorage)
+ , m_pServers( pServers )
+ , m_xRbNewObject(m_xBuilder->weld_radio_button("createnew"))
+ , m_xRbObjectFromfile(m_xBuilder->weld_radio_button("createfromfile"))
+ , m_xObjectTypeFrame(m_xBuilder->weld_frame("objecttypeframe"))
+ , m_xLbObjecttype(m_xBuilder->weld_tree_view("types"))
+ , m_xFileFrame(m_xBuilder->weld_frame("fileframe"))
+ , m_xEdFilepath(m_xBuilder->weld_entry("urled"))
+ , m_xBtnFilepath(m_xBuilder->weld_button("urlbtn"))
+ , m_xCbFilelink(m_xBuilder->weld_check_button("linktofile"))
+ , m_xCbAsIcon(m_xBuilder->weld_check_button("asicon"))
+{
+ m_xLbObjecttype->set_size_request(m_xLbObjecttype->get_approximate_digit_width() * 32,
+ m_xLbObjecttype->get_height_rows(6));
+ m_xLbObjecttype->connect_row_activated(LINK(this, SvInsertOleDlg, DoubleClickHdl));
+ m_xBtnFilepath->connect_clicked(LINK( this, SvInsertOleDlg, BrowseHdl));
+ Link<weld::Button&,void> aLink( LINK( this, SvInsertOleDlg, RadioHdl ) );
+ m_xRbNewObject->connect_clicked( aLink );
+ m_xRbObjectFromfile->connect_clicked( aLink );
+ m_xRbNewObject->set_active(true);
+}
+
+short SvInsertOleDlg::run()
+{
+ short nRet = RET_OK;
+ SvObjectServerList aObjS;
+ if ( !m_pServers )
+ {
+ // if no list was provided, take the complete one
+ aObjS.FillInsertObjects();
+ m_pServers = &aObjS;
+ }
+
+ // fill listbox and select default
+ m_xLbObjecttype->freeze();
+ for ( sal_uLong i = 0; i < m_pServers->Count(); i++ )
+ m_xLbObjecttype->append_text((*m_pServers)[i].GetHumanName());
+ m_xLbObjecttype->thaw();
+ m_xLbObjecttype->select(0);
+ OUString aName;
+
+ DBG_ASSERT( m_xStorage.is(), "No storage!");
+ if ( m_xStorage.is() && ( nRet = InsertObjectDialog_Impl::run() ) == RET_OK )
+ {
+ OUString aFileName;
+ bool bCreateNew = IsCreateNew();
+ if ( bCreateNew )
+ {
+ // create and insert new embedded object
+ OUString aServerName = m_xLbObjecttype->get_selected_text();
+ const SvObjectServer* pS = m_pServers->Get( aServerName );
+ if ( pS )
+ {
+ if( pS->GetClassName() == SvGlobalName( SO3_OUT_CLASSID ) )
+ {
+ try
+ {
+ uno::Reference < embed::XInsertObjectDialog > xDialogCreator(
+ embed::MSOLEObjectSystemCreator::create( ::comphelper::getProcessComponentContext() ),
+ uno::UNO_QUERY );
+
+ if ( xDialogCreator.is() )
+ {
+ aName = aCnt.CreateUniqueObjectName();
+ const embed::InsertedObjectInfo aNewInf = xDialogCreator->createInstanceByDialog(
+ m_xStorage,
+ aName,
+ uno::Sequence < beans::PropertyValue >() );
+
+ OSL_ENSURE( aNewInf.Object.is(), "The object must be created or an exception must be thrown!" );
+ m_xObj = aNewInf.Object;
+ for ( const auto& opt : aNewInf.Options )
+ if ( opt.Name == "Icon" )
+ {
+ opt.Value >>= m_aIconMetaFile;
+ }
+ else if ( opt.Name == "IconFormat" )
+ {
+ datatransfer::DataFlavor aFlavor;
+ if ( opt.Value >>= aFlavor )
+ m_aIconMediaType = aFlavor.MimeType;
+ }
+
+ }
+ }
+ catch( ucb::CommandAbortedException& )
+ {
+ // the user has pressed cancel
+ }
+ catch( uno::Exception& )
+ {
+ // TODO: Error handling
+ }
+ }
+ else
+ {
+ // create object with desired ClassId
+ m_xObj = aCnt.CreateEmbeddedObject( pS->GetClassName().GetByteSequence(), aName );
+ }
+
+ if ( !m_xObj.is() )
+ {
+ if( !aFileName.isEmpty() ) // from OLE Dialog
+ {
+ // object couldn't be created from file
+ // global Resource from svtools (former so3 resource)
+ OUString aErr(SvtResId(STR_ERROR_OBJNOCREATE_FROM_FILE));
+ aErr = aErr.replaceFirst( "%", aFileName );
+
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Warning, VclButtonsType::Ok, aErr));
+ xBox->run();
+ }
+ else
+ {
+ // object couldn't be created
+ // global Resource from svtools (former so3 resource)
+ OUString aErr(SvtResId(STR_ERROR_OBJNOCREATE));
+ aErr = aErr.replaceFirst( "%", aServerName );
+
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Warning, VclButtonsType::Ok, aErr));
+ xBox->run();
+ }
+ }
+ }
+ }
+ else
+ {
+ aFileName = m_xEdFilepath->get_text();
+ INetURLObject aURL;
+ aURL.SetSmartProtocol( INetProtocol::File );
+ aURL.SetSmartURL( aFileName );
+ aFileName = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+ bool bLink = m_xCbFilelink->get_active();
+
+ if ( !aFileName.isEmpty() )
+ {
+ // create MediaDescriptor for file to create object from
+ uno::Sequence < beans::PropertyValue > aMedium( 2 );
+ aMedium[0].Name = "URL";
+ aMedium[0].Value <<= aFileName;
+
+ uno::Reference< uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
+ uno::Reference< task::XInteractionHandler2 > xInteraction(
+ task::InteractionHandler::createWithParent(xContext, nullptr) );
+
+ aMedium[1].Name = "InteractionHandler";
+ aMedium[1].Value <<= xInteraction;
+
+ // create object from media descriptor
+ if ( bLink )
+ m_xObj = aCnt.InsertEmbeddedLink( aMedium, aName );
+ else
+ m_xObj = aCnt.InsertEmbeddedObject( aMedium, aName );
+ }
+
+ if ( !m_xObj.is() )
+ {
+ // object couldn't be created from file
+ // global Resource from svtools (former so3 resource)
+ OUString aErr(SvtResId(STR_ERROR_OBJNOCREATE_FROM_FILE));
+ aErr = aErr.replaceFirst( "%", aFileName );
+
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Warning, VclButtonsType::Ok, aErr));
+ xBox->run();
+ }
+ else
+ {
+ if (m_xCbAsIcon->get_active())
+ {
+ //something nice here I guess would be to write the filename into
+ //the image with this icon above it
+ Image aImage = SvFileInformationManager::GetImage(aURL, true);
+ SvMemoryStream aTemp;
+ WriteDIBBitmapEx(aImage.GetBitmapEx(), aTemp);
+ m_aIconMetaFile = Sequence<sal_Int8>(static_cast<const sal_Int8*>(aTemp.GetData()), aTemp.TellEnd());
+ m_aIconMediaType = "application/x-openoffice-bitmap;windows_formatname=\"Bitmap\"";
+ }
+ }
+ }
+ }
+
+ m_pServers = nullptr;
+ return nRet;
+}
+
+uno::Reference< io::XInputStream > SvInsertOleDlg::GetIconIfIconified( OUString* pGraphicMediaType )
+{
+ if ( m_aIconMetaFile.hasElements() )
+ {
+ if ( pGraphicMediaType )
+ *pGraphicMediaType = m_aIconMediaType;
+
+ return uno::Reference< io::XInputStream >( new ::comphelper::SequenceInputStream( m_aIconMetaFile ) );
+ }
+
+ return uno::Reference< io::XInputStream >();
+}
+
+
+SfxInsertFloatingFrameDialog::SfxInsertFloatingFrameDialog(weld::Window *pParent,
+ const css::uno::Reference < css::embed::XStorage >& xStorage)
+ : InsertObjectDialog_Impl(pParent, "cui/ui/insertfloatingframe.ui", "InsertFloatingFrameDialog",
+ xStorage)
+{
+ Init();
+}
+
+SfxInsertFloatingFrameDialog::SfxInsertFloatingFrameDialog(weld::Window *pParent,
+ const uno::Reference < embed::XEmbeddedObject >& xObj)
+ : InsertObjectDialog_Impl(pParent, "cui/ui/insertfloatingframe.ui", "InsertFloatingFrameDialog",
+ uno::Reference<embed::XStorage>())
+{
+ m_xObj = xObj;
+
+ Init();
+}
+
+void SfxInsertFloatingFrameDialog::Init()
+{
+ m_xEDName = m_xBuilder->weld_entry("edname");
+ m_xEDURL = m_xBuilder->weld_entry("edurl");
+ m_xBTOpen = m_xBuilder->weld_button("buttonbrowse");
+ m_xRBScrollingOn = m_xBuilder->weld_radio_button("scrollbaron");
+ m_xRBScrollingOff = m_xBuilder->weld_radio_button("scrollbaroff");
+ m_xRBScrollingAuto = m_xBuilder->weld_radio_button("scrollbarauto");
+ m_xRBFrameBorderOn = m_xBuilder->weld_radio_button("borderon");
+ m_xRBFrameBorderOff = m_xBuilder->weld_radio_button("borderoff");
+ m_xFTMarginWidth = m_xBuilder->weld_label("widthlabel");
+ m_xNMMarginWidth = m_xBuilder->weld_spin_button("width");
+ m_xCBMarginWidthDefault = m_xBuilder->weld_check_button("defaultwidth");
+ m_xFTMarginHeight = m_xBuilder->weld_label("heightlabel");
+ m_xNMMarginHeight = m_xBuilder->weld_spin_button("height");
+ m_xCBMarginHeightDefault = m_xBuilder->weld_check_button("defaultheight");
+
+ Link<weld::Button&, void> aLink(LINK(this, SfxInsertFloatingFrameDialog, CheckHdl));
+ m_xCBMarginWidthDefault->connect_clicked(aLink);
+ m_xCBMarginHeightDefault->connect_clicked(aLink);
+
+ m_xCBMarginWidthDefault->set_active(true);
+ m_xCBMarginHeightDefault->set_active(true);
+ m_xRBScrollingAuto->set_active(true);
+ m_xRBFrameBorderOn->set_active(true);
+
+ m_xBTOpen->connect_clicked(LINK(this, SfxInsertFloatingFrameDialog, OpenHdl));
+}
+
+short SfxInsertFloatingFrameDialog::run()
+{
+ short nRet = RET_OK;
+ bool bOK = false;
+ uno::Reference < beans::XPropertySet > xSet;
+ if ( m_xObj.is() )
+ {
+ try
+ {
+ if ( m_xObj->getCurrentState() == embed::EmbedStates::LOADED )
+ m_xObj->changeState( embed::EmbedStates::RUNNING );
+ xSet.set( m_xObj->getComponent(), uno::UNO_QUERY );
+ OUString aStr;
+ uno::Any aAny = xSet->getPropertyValue( "FrameURL" );
+ if ( aAny >>= aStr )
+ m_xEDURL->set_text( aStr );
+ aAny = xSet->getPropertyValue( "FrameName" );
+ if ( aAny >>= aStr )
+ m_xEDName->set_text(aStr);
+
+ sal_Int32 nSize = SIZE_NOT_SET;
+ aAny = xSet->getPropertyValue( "FrameMarginWidth" );
+ aAny >>= nSize;
+
+ if ( nSize == SIZE_NOT_SET )
+ {
+ m_xCBMarginWidthDefault->set_active(true);
+ m_xNMMarginWidth->set_text(OUString::number(DEFAULT_MARGIN_WIDTH));
+ m_xFTMarginWidth->set_sensitive(false);
+ m_xNMMarginWidth->set_sensitive(false);
+ }
+ else
+ m_xNMMarginWidth->set_text(OUString::number(nSize));
+
+ aAny = xSet->getPropertyValue( "FrameMarginHeight" );
+ aAny >>= nSize;
+
+ if ( nSize == SIZE_NOT_SET )
+ {
+ m_xCBMarginHeightDefault->set_active(true);
+ m_xNMMarginHeight->set_text(OUString::number(DEFAULT_MARGIN_HEIGHT));
+ m_xFTMarginHeight->set_sensitive(false);
+ m_xNMMarginHeight->set_sensitive(false);
+ }
+ else
+ m_xNMMarginHeight->set_text(OUString::number(nSize));
+
+ bool bScrollOn = false;
+ bool bScrollOff = false;
+ bool bScrollAuto = false;
+
+ bool bSet = false;
+ aAny = xSet->getPropertyValue( "FrameIsAutoScroll" );
+ aAny >>= bSet;
+ if ( !bSet )
+ {
+ aAny = xSet->getPropertyValue( "FrameIsScrollingMode" );
+ aAny >>= bSet;
+ bScrollOn = bSet;
+ bScrollOff = !bSet;
+ }
+ else
+ bScrollAuto = true;
+
+ m_xRBScrollingOn->set_sensitive(bScrollOn);
+ m_xRBScrollingOff->set_sensitive(bScrollOff);
+ m_xRBScrollingAuto->set_sensitive(bScrollAuto);
+
+ bSet = false;
+ aAny = xSet->getPropertyValue( "FrameIsAutoBorder" );
+ aAny >>= bSet;
+ if ( !bSet )
+ {
+ aAny = xSet->getPropertyValue( "FrameIsBorder" );
+ aAny >>= bSet;
+ m_xRBFrameBorderOn->set_active(bSet);
+ m_xRBFrameBorderOff->set_active(!bSet);
+ }
+
+ bOK = true;
+ }
+ catch ( uno::Exception& )
+ {
+ OSL_FAIL( "No IFrame!" );
+ }
+ }
+ else
+ {
+ DBG_ASSERT( m_xStorage.is(), "No storage!");
+ bOK = m_xStorage.is();
+ }
+
+ if (!bOK)
+ return RET_OK;
+
+ nRet = InsertObjectDialog_Impl::run();
+ if ( nRet == RET_OK )
+ {
+ OUString aURL;
+ if (!m_xEDURL->get_text().isEmpty())
+ {
+ // URL can be a valid and absolute URL or a system file name
+ INetURLObject aObj;
+ aObj.SetSmartProtocol( INetProtocol::File );
+ if ( aObj.SetSmartURL( m_xEDURL->get_text() ) )
+ aURL = aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+ }
+
+ if ( !m_xObj.is() && !aURL.isEmpty() )
+ {
+ // create the object
+ OUString aName;
+ SvGlobalName aClassId( SO3_IFRAME_CLASSID );
+ m_xObj = aCnt.CreateEmbeddedObject( aClassId.GetByteSequence(), aName );
+ if ( m_xObj->getCurrentState() == embed::EmbedStates::LOADED )
+ m_xObj->changeState( embed::EmbedStates::RUNNING );
+ xSet.set( m_xObj->getComponent(), uno::UNO_QUERY );
+ }
+
+ if ( m_xObj.is() )
+ {
+ try
+ {
+ bool bIPActive = m_xObj->getCurrentState() == embed::EmbedStates::INPLACE_ACTIVE;
+ if ( bIPActive )
+ m_xObj->changeState( embed::EmbedStates::RUNNING );
+
+ OUString aName = m_xEDName->get_text();
+ ScrollingMode eScroll = ScrollingMode::No;
+ if (m_xRBScrollingOn->get_active())
+ eScroll = ScrollingMode::Yes;
+ if (m_xRBScrollingOff->get_active())
+ eScroll = ScrollingMode::No;
+ if (m_xRBScrollingAuto->get_active())
+ eScroll = ScrollingMode::Auto;
+
+ bool bHasBorder = m_xRBFrameBorderOn->get_active();
+
+ long lMarginWidth;
+ if (!m_xCBMarginWidthDefault->get_active())
+ lMarginWidth = static_cast<long>(m_xNMMarginWidth->get_text().toInt32());
+ else
+ lMarginWidth = SIZE_NOT_SET;
+
+ long lMarginHeight;
+ if (!m_xCBMarginHeightDefault->get_active())
+ lMarginHeight = static_cast<long>(m_xNMMarginHeight->get_text().toInt32());
+ else
+ lMarginHeight = SIZE_NOT_SET;
+
+ xSet->setPropertyValue( "FrameURL", Any( aURL ) );
+ xSet->setPropertyValue( "FrameName", Any( aName ) );
+
+ if ( eScroll == ScrollingMode::Auto )
+ xSet->setPropertyValue( "FrameIsAutoScroll", Any( true ) );
+ else
+ xSet->setPropertyValue( "FrameIsScrollingMode", Any( eScroll == ScrollingMode::Yes ) );
+
+ xSet->setPropertyValue( "FrameIsBorder", Any( bHasBorder ) );
+ xSet->setPropertyValue( "FrameMarginWidth", Any( sal_Int32( lMarginWidth ) ) );
+ xSet->setPropertyValue( "FrameMarginHeight", Any( sal_Int32( lMarginHeight ) ) );
+
+ if ( bIPActive )
+ m_xObj->changeState( embed::EmbedStates::INPLACE_ACTIVE );
+ }
+ catch ( uno::Exception& )
+ {
+ OSL_FAIL( "No IFrame!" );
+ }
+ }
+ }
+
+ return nRet;
+}
+
+IMPL_LINK(SfxInsertFloatingFrameDialog, CheckHdl, weld::Button&, rButton, void)
+{
+ weld::CheckButton& rCB = dynamic_cast<weld::CheckButton&>(rButton);
+ if (&rCB == m_xCBMarginWidthDefault.get())
+ {
+ if (rCB.get_active())
+ m_xNMMarginWidth->set_text(OUString::number(DEFAULT_MARGIN_WIDTH));
+ m_xFTMarginWidth->set_sensitive(!rCB.get_active());
+ m_xNMMarginWidth->set_sensitive(!rCB.get_active());
+ }
+
+ if (&rCB == m_xCBMarginHeightDefault.get())
+ {
+ if (rCB.get_active())
+ m_xNMMarginHeight->set_text(OUString::number(DEFAULT_MARGIN_HEIGHT));
+ m_xFTMarginHeight->set_sensitive(!rCB.get_active());
+ m_xNMMarginHeight->set_sensitive(!rCB.get_active());
+ }
+}
+
+IMPL_LINK_NOARG( SfxInsertFloatingFrameDialog, OpenHdl, weld::Button&, void)
+{
+ // create the file dialog
+ sfx2::FileDialogHelper aFileDlg(
+ ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE, FileDialogFlags::NONE, OUString(),
+ SfxFilterFlags::NONE, SfxFilterFlags::NONE, m_xDialog.get());
+
+ // set the title
+ aFileDlg.SetTitle(CuiResId(RID_SVXSTR_SELECT_FILE_IFRAME));
+
+ // show the dialog
+ if ( aFileDlg.Execute() == ERRCODE_NONE )
+ m_xEDURL->set_text(INetURLObject(aFileDlg.GetPath()).GetMainURL(INetURLObject::DecodeMechanism::WithCharset));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/dialogs/insrc.cxx b/cui/source/dialogs/insrc.cxx
new file mode 100644
index 000000000..862963275
--- /dev/null
+++ b/cui/source/dialogs/insrc.cxx
@@ -0,0 +1,59 @@
+/* -*- 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 <dialmgr.hxx>
+#include <strings.hrc>
+#include <insrc.hxx>
+
+bool SvxInsRowColDlg::isInsertBefore() const
+{
+ return !m_xAfterBtn->get_active();
+}
+
+sal_uInt16 SvxInsRowColDlg::getInsertCount() const
+{
+ return m_xCountEdit->get_value();
+}
+
+SvxInsRowColDlg::SvxInsRowColDlg(weld::Window* pParent, bool bColumn, const OString& rHelpId)
+ : GenericDialogController(pParent, "cui/ui/insertrowcolumn.ui", "InsertRowColumnDialog")
+ , m_xCountEdit(m_xBuilder->weld_spin_button("insert_number"))
+ , m_xBeforeBtn(m_xBuilder->weld_radio_button("insert_before"))
+ , m_xAfterBtn(m_xBuilder->weld_radio_button("insert_after"))
+{
+ m_xDialog->set_title(bColumn ? CuiResId(RID_SVXSTR_COL) : CuiResId(RID_SVXSTR_ROW));
+
+ // tdf#119293
+ if (bColumn) {
+ m_xBeforeBtn->set_label(CuiResId(RID_SVXSTR_INSERTCOL_BEFORE));
+ m_xAfterBtn->set_label(CuiResId(RID_SVXSTR_INSERTCOL_AFTER));
+ } else {
+ m_xBeforeBtn->set_label(CuiResId(RID_SVXSTR_INSERTROW_BEFORE));
+ m_xAfterBtn->set_label(CuiResId(RID_SVXSTR_INSERTROW_AFTER));
+ }
+
+ m_xDialog->set_help_id(rHelpId);
+}
+
+short SvxInsRowColDlg::Execute()
+{
+ return run();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/dialogs/linkdlg.cxx b/cui/source/dialogs/linkdlg.cxx
new file mode 100644
index 000000000..764d29e0c
--- /dev/null
+++ b/cui/source/dialogs/linkdlg.cxx
@@ -0,0 +1,636 @@
+/* -*- 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 <linkdlg.hxx>
+#include <vcl/svapp.hxx>
+
+#include <tools/diagnose_ex.h>
+#include <tools/debug.hxx>
+#include <tools/urlobj.hxx>
+#include <vcl/idle.hxx>
+#include <vcl/timer.hxx>
+#include <vcl/weld.hxx>
+#include <vcl/window.hxx>
+
+#include <strings.hrc>
+#include <sfx2/linkmgr.hxx>
+#include <sfx2/linksrc.hxx>
+#include <sfx2/lnkbase.hxx>
+#include <sfx2/objsh.hxx>
+
+#include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
+#include <com/sun/star/ui/dialogs/FolderPicker.hpp>
+#include <comphelper/processfactory.hxx>
+
+#include <dialmgr.hxx>
+
+
+using namespace sfx2;
+using namespace ::com::sun::star;
+
+namespace {
+
+class SvBaseLinkMemberList {
+private:
+ std::vector<SvBaseLink*> mLinks;
+
+public:
+ ~SvBaseLinkMemberList()
+ {
+ for (auto const& link : mLinks)
+ {
+ if( link )
+ link->ReleaseRef();
+ }
+ }
+
+ size_t size() const { return mLinks.size(); }
+
+ SvBaseLink *operator[](size_t i) const { return mLinks[i]; }
+
+ void push_back(SvBaseLink* p)
+ {
+ mLinks.push_back(p);
+ p->AddFirstRef();
+ }
+};
+
+}
+
+SvBaseLinksDlg::SvBaseLinksDlg(weld::Window * pParent, LinkManager* pMgr, bool bHtmlMode)
+ : GenericDialogController(pParent, "cui/ui/baselinksdialog.ui", "BaseLinksDialog")
+ , aStrAutolink( CuiResId( STR_AUTOLINK ) )
+ , aStrManuallink( CuiResId( STR_MANUALLINK ) )
+ , aStrBrokenlink( CuiResId( STR_BROKENLINK ) )
+ , aStrCloselinkmsg( CuiResId( STR_CLOSELINKMSG ) )
+ , aStrCloselinkmsgMulti( CuiResId( STR_CLOSELINKMSG_MULTI ) )
+ , aStrWaitinglink( CuiResId( STR_WAITINGLINK ) )
+ , pLinkMgr( nullptr )
+ , aUpdateIdle("cui SvBaseLinksDlg UpdateIdle")
+ , m_xTbLinks(m_xBuilder->weld_tree_view("TB_LINKS"))
+ , m_xFtFullFileName(m_xBuilder->weld_link_button("FULL_FILE_NAME"))
+ , m_xFtFullSourceName(m_xBuilder->weld_label("FULL_SOURCE_NAME"))
+ , m_xFtFullTypeName(m_xBuilder->weld_label("FULL_TYPE_NAME"))
+ , m_xRbAutomatic(m_xBuilder->weld_radio_button("AUTOMATIC"))
+ , m_xRbManual(m_xBuilder->weld_radio_button("MANUAL"))
+ , m_xPbUpdateNow(m_xBuilder->weld_button("UPDATE_NOW"))
+ , m_xPbChangeSource(m_xBuilder->weld_button("CHANGE_SOURCE"))
+ , m_xPbBreakLink(m_xBuilder->weld_button("BREAK_LINK"))
+ , m_xVirDev(VclPtr<VirtualDevice>::Create())
+{
+ // expand the point size of the desired font to the equivalent pixel size
+ if (vcl::Window* pDefaultDevice = dynamic_cast<vcl::Window*>(Application::GetDefaultDevice()))
+ pDefaultDevice->SetPointFont(*m_xVirDev, m_xTbLinks->get_font());
+ m_xTbLinks->set_size_request(m_xTbLinks->get_approximate_digit_width() * 90,
+ m_xTbLinks->get_height_rows(12));
+
+ m_xTbLinks->set_selection_mode(SelectionMode::Multiple);
+
+ std::vector<int> aWidths;
+ aWidths.push_back(m_xTbLinks->get_approximate_digit_width() * 30);
+ aWidths.push_back(m_xTbLinks->get_approximate_digit_width() * 20);
+ aWidths.push_back(m_xTbLinks->get_approximate_digit_width() * 20);
+ m_xTbLinks->set_column_fixed_widths(aWidths);
+
+ // UpdateTimer for DDE-/Grf-links, which are waited for
+ aUpdateIdle.SetInvokeHandler( LINK( this, SvBaseLinksDlg, UpdateWaitingHdl ) );
+ aUpdateIdle.SetPriority( TaskPriority::LOWEST );
+
+ m_xTbLinks->connect_changed( LINK( this, SvBaseLinksDlg, LinksSelectHdl ) );
+ m_xTbLinks->connect_row_activated( LINK( this, SvBaseLinksDlg, LinksDoubleClickHdl ) );
+ m_xRbAutomatic->connect_clicked( LINK( this, SvBaseLinksDlg, AutomaticClickHdl ) );
+ m_xRbManual->connect_clicked( LINK( this, SvBaseLinksDlg, ManualClickHdl ) );
+ m_xPbUpdateNow->connect_clicked( LINK( this, SvBaseLinksDlg, UpdateNowClickHdl ) );
+ m_xPbChangeSource->connect_clicked( LINK( this, SvBaseLinksDlg, ChangeSourceClickHdl ) );
+ if(!bHtmlMode)
+ m_xPbBreakLink->connect_clicked( LINK( this, SvBaseLinksDlg, BreakLinkClickHdl ) );
+ else
+ m_xPbBreakLink->hide();
+
+ SetManager( pMgr );
+}
+
+SvBaseLinksDlg::~SvBaseLinksDlg()
+{
+}
+
+/*************************************************************************
+|* SvBaseLinksDlg::Handler()
+*************************************************************************/
+IMPL_LINK(SvBaseLinksDlg, LinksSelectHdl, weld::TreeView&, rTreeView, void)
+{
+ LinksSelectHdl(&rTreeView);
+}
+
+void SvBaseLinksDlg::LinksSelectHdl(weld::TreeView* pSvTabListBox)
+{
+ const int nSelectionCount = pSvTabListBox ?
+ pSvTabListBox->count_selected_rows() : 0;
+ if (nSelectionCount > 1)
+ {
+ // possibly deselect old entries in case of multi-selection
+ int nSelEntry = pSvTabListBox->get_selected_index();
+ SvBaseLink* pLink = reinterpret_cast<SvBaseLink*>(pSvTabListBox->get_id(nSelEntry).toInt64());
+ SvBaseLinkObjectType nObjectType = pLink->GetObjType();
+ if(!isClientFileType(nObjectType))
+ {
+ pSvTabListBox->unselect_all();
+ pSvTabListBox->select(nSelEntry);
+ }
+ else
+ {
+ std::vector<int> aRows = pSvTabListBox->get_selected_rows();
+ for (auto nEntry : aRows)
+ {
+ pLink = reinterpret_cast<SvBaseLink*>(pSvTabListBox->get_id(nEntry).toInt64());
+ DBG_ASSERT(pLink, "Where is the Link?");
+ if (!pLink)
+ continue;
+ if( !isClientFileType(pLink->GetObjType()) )
+ pSvTabListBox->unselect(nEntry);
+ }
+ }
+
+ m_xPbUpdateNow->set_sensitive(true);
+ m_xRbAutomatic->set_sensitive(false);
+ m_xRbManual->set_active(true);
+ m_xRbManual->set_sensitive(false);
+ }
+ else
+ {
+ int nPos;
+ SvBaseLink* pLink = GetSelEntry( &nPos );
+ if( !pLink )
+ return;
+
+ m_xPbUpdateNow->set_sensitive(true);
+
+ OUString sType, sLink;
+ OUString *pLinkNm = &sLink, *pFilter = nullptr;
+
+ if( isClientFileType(pLink->GetObjType()) )
+ {
+ m_xRbAutomatic->set_sensitive(false);
+ m_xRbManual->set_active(true);
+ m_xRbManual->set_sensitive(false);
+ if( SvBaseLinkObjectType::ClientGraphic == pLink->GetObjType() )
+ {
+ pLinkNm = nullptr;
+ pFilter = &sLink;
+ }
+ }
+ else
+ {
+ m_xRbAutomatic->set_sensitive(true);
+ m_xRbManual->set_sensitive(true);
+
+ if( SfxLinkUpdateMode::ALWAYS == pLink->GetUpdateMode() )
+ m_xRbAutomatic->set_active(true);
+ else
+ m_xRbManual->set_active(true);
+ }
+
+ OUString aFileName;
+ sfx2::LinkManager::GetDisplayNames( pLink, &sType, &aFileName, pLinkNm, pFilter );
+ aFileName = INetURLObject::decode(aFileName, INetURLObject::DecodeMechanism::Unambiguous);
+ m_xFtFullFileName->set_label( aFileName );
+ m_xFtFullFileName->set_uri( aFileName );
+ m_xFtFullSourceName->set_label( sLink );
+ m_xFtFullTypeName->set_label( sType );
+ }
+}
+
+IMPL_LINK_NOARG( SvBaseLinksDlg, LinksDoubleClickHdl, weld::TreeView&, bool )
+{
+ ChangeSourceClickHdl(*m_xPbChangeSource);
+ return true;
+}
+
+IMPL_LINK_NOARG( SvBaseLinksDlg, AutomaticClickHdl, weld::Button&, void )
+{
+ int nPos;
+ SvBaseLink* pLink = GetSelEntry( &nPos );
+ if( pLink && !isClientFileType( pLink->GetObjType() ) &&
+ SfxLinkUpdateMode::ALWAYS != pLink->GetUpdateMode() )
+ SetType( *pLink, nPos, SfxLinkUpdateMode::ALWAYS );
+}
+
+IMPL_LINK_NOARG( SvBaseLinksDlg, ManualClickHdl, weld::Button&, void )
+{
+ int nPos;
+ SvBaseLink* pLink = GetSelEntry( &nPos );
+ if( pLink && !isClientFileType( pLink->GetObjType() ) &&
+ SfxLinkUpdateMode::ONCALL != pLink->GetUpdateMode())
+ SetType( *pLink, nPos, SfxLinkUpdateMode::ONCALL );
+}
+
+IMPL_LINK_NOARG(SvBaseLinksDlg, UpdateNowClickHdl, weld::Button&, void)
+{
+ std::vector< SvBaseLink* > aLnkArr;
+ std::vector< sal_Int16 > aPosArr;
+
+ std::vector<int> aRows = m_xTbLinks->get_selected_rows();
+ for (int nFndPos : aRows)
+ {
+ aLnkArr.push_back( reinterpret_cast<SvBaseLink*>( m_xTbLinks->get_id(nFndPos).toInt64() ) );
+ aPosArr.push_back( nFndPos );
+ }
+
+ if( aLnkArr.empty() )
+ return;
+
+ for( size_t n = 0; n < aLnkArr.size(); ++n )
+ {
+ tools::SvRef<SvBaseLink> xLink = aLnkArr[ n ];
+
+ // first look for the entry in the array
+ for(const auto & i : pLinkMgr->GetLinks())
+ if( xLink == i )
+ {
+ SetType( *xLink, aPosArr[ n ], xLink->GetUpdateMode() );
+ break;
+ }
+ }
+
+ // if somebody is of the opinion to swap his links (SD)
+ LinkManager* pNewMgr = pLinkMgr;
+ pLinkMgr = nullptr;
+ SetManager( pNewMgr );
+
+
+ OUString sId = OUString::number(reinterpret_cast<sal_Int64>(aLnkArr[0]));
+ int nE = m_xTbLinks->find_id(sId);
+ if (nE == -1)
+ nE = m_xTbLinks->get_selected_index();
+ int nSelEntry = m_xTbLinks->get_selected_index();
+ if (nE != nSelEntry)
+ m_xTbLinks->unselect(nSelEntry);
+ m_xTbLinks->select(nE);
+ m_xTbLinks->scroll_to_row(nE);
+
+ pNewMgr->CloseCachedComps();
+}
+
+IMPL_LINK_NOARG(SvBaseLinksDlg, ChangeSourceClickHdl, weld::Button&, void)
+{
+ std::vector<int> aRows = m_xTbLinks->get_selected_rows();
+ if (aRows.size() > 1)
+ {
+ try
+ {
+ uno::Reference<ui::dialogs::XFolderPicker2> xFolderPicker = ui::dialogs::FolderPicker::create(comphelper::getProcessComponentContext());
+
+ OUString sType, sFile, sLinkName;
+ OUString sFilter;
+ SvBaseLink* pLink = reinterpret_cast<SvBaseLink*>(m_xTbLinks->get_id(aRows[0]).toInt64());
+ sfx2::LinkManager::GetDisplayNames( pLink, &sType, &sFile );
+ INetURLObject aUrl(sFile);
+ if(aUrl.GetProtocol() == INetProtocol::File)
+ {
+ OUString sOldPath(aUrl.PathToFileName());
+ sal_Int32 nLen = aUrl.GetLastName().getLength();
+ sOldPath = sOldPath.copy(0, sOldPath.getLength() - nLen);
+ xFolderPicker->setDisplayDirectory(sOldPath);
+ }
+ if (xFolderPicker->execute() == ui::dialogs::ExecutableDialogResults::OK)
+ {
+ OUString aPath = xFolderPicker->getDirectory();
+
+ for (auto nRow : aRows)
+ {
+ pLink = reinterpret_cast<SvBaseLink*>(m_xTbLinks->get_id(nRow).toInt64());
+ DBG_ASSERT(pLink,"Where is the link?");
+ if (!pLink)
+ continue;
+ sfx2::LinkManager::GetDisplayNames( pLink, &sType, &sFile, &sLinkName, &sFilter );
+ INetURLObject aUrl_(sFile);
+ INetURLObject aUrl2(aPath, INetProtocol::File);
+ aUrl2.insertName( aUrl_.getName() );
+ OUString sNewLinkName;
+ MakeLnkName( sNewLinkName, nullptr ,
+ aUrl2.GetMainURL(INetURLObject::DecodeMechanism::ToIUri), sLinkName, &sFilter);
+ pLink->SetLinkSourceName( sNewLinkName );
+ pLink->Update();
+ }
+ if( pLinkMgr->GetPersist() )
+ pLinkMgr->GetPersist()->SetModified();
+ LinkManager* pNewMgr = pLinkMgr;
+ pLinkMgr = nullptr;
+ SetManager( pNewMgr );
+ }
+ }
+ catch (const uno::Exception &)
+ {
+ TOOLS_WARN_EXCEPTION("cui.dialogs", "SvBaseLinksDlg");
+ }
+ }
+ else
+ {
+ int nPos;
+ SvBaseLink* pLink = GetSelEntry( &nPos );
+ if ( pLink && !pLink->GetLinkSourceName().isEmpty() )
+ pLink->Edit(m_xDialog.get(), LINK(this, SvBaseLinksDlg, EndEditHdl));
+ }
+}
+
+IMPL_LINK_NOARG( SvBaseLinksDlg, BreakLinkClickHdl, weld::Button&, void )
+{
+ bool bModified = false;
+ if (m_xTbLinks->count_selected_rows() <= 1)
+ {
+ int nPos;
+ tools::SvRef<SvBaseLink> xLink = GetSelEntry( &nPos );
+ if( !xLink.is() )
+ return;
+
+ std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Question, VclButtonsType::YesNo,
+ aStrCloselinkmsg));
+ xQueryBox->set_default_response(RET_YES);
+
+ if (RET_YES == xQueryBox->run())
+ {
+ m_xTbLinks->remove(nPos);
+
+ // close object, if it's still existing
+ bool bNewLnkMgr = SvBaseLinkObjectType::ClientFile == xLink->GetObjType();
+
+ // tell the link that it will be resolved!
+ xLink->Closed();
+
+ // if somebody has forgotten to deregister himself
+ if( xLink.is() )
+ pLinkMgr->Remove( xLink.get() );
+
+ if( bNewLnkMgr )
+ {
+ LinkManager* pNewMgr = pLinkMgr;
+ pLinkMgr = nullptr;
+ SetManager( pNewMgr );
+ m_xTbLinks->set_cursor(nPos ? --nPos : 0);
+ }
+ bModified = true;
+ }
+ }
+ else
+ {
+ std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Question, VclButtonsType::YesNo,
+ aStrCloselinkmsgMulti));
+ xQueryBox->set_default_response(RET_YES);
+
+ if (RET_YES == xQueryBox->run())
+ {
+ std::vector<int> aRows = m_xTbLinks->get_selected_rows();
+ SvBaseLinkMemberList aLinkList;
+ for (auto nRow : aRows)
+ {
+ SvBaseLink* pLink = reinterpret_cast<SvBaseLink*>(m_xTbLinks->get_id(nRow).toInt64());
+ if (pLink)
+ aLinkList.push_back(pLink);
+ }
+ std::sort(aRows.begin(), aRows.end());
+ for (auto it = aRows.rbegin(); it != aRows.rend(); ++it)
+ m_xTbLinks->remove(*it);
+ for (size_t i = 0; i < aLinkList.size(); ++i)
+ {
+ tools::SvRef<SvBaseLink> xLink = aLinkList[i];
+ // tell the link that it will be resolved!
+ xLink->Closed();
+
+ // if somebody has forgotten to deregister himself
+ pLinkMgr->Remove( xLink.get() );
+ bModified = true;
+ }
+ // then remove all selected entries
+ }
+ }
+ if(!bModified)
+ return;
+
+ if (!m_xTbLinks->n_children())
+ {
+ m_xRbAutomatic->set_sensitive(false);
+ m_xRbManual->set_sensitive(false);
+ m_xPbUpdateNow->set_sensitive(false);
+ m_xPbChangeSource->set_sensitive(false);
+ m_xPbBreakLink->set_sensitive(false);
+
+ m_xFtFullSourceName->set_label( "" );
+ m_xFtFullTypeName->set_label( "" );
+ }
+ if( pLinkMgr && pLinkMgr->GetPersist() )
+ pLinkMgr->GetPersist()->SetModified();
+}
+
+IMPL_LINK_NOARG( SvBaseLinksDlg, UpdateWaitingHdl, Timer*, void )
+{
+ m_xTbLinks->freeze();
+ for (int nPos = m_xTbLinks->n_children(); nPos; --nPos)
+ {
+ tools::SvRef<SvBaseLink> xLink( reinterpret_cast<SvBaseLink*>(m_xTbLinks->get_id(nPos).toInt64()) );
+ if( xLink.is() )
+ {
+ OUString sCur( ImplGetStateStr( *xLink ) ),
+ sOld( m_xTbLinks->get_text(nPos, 3) );
+ if( sCur != sOld )
+ m_xTbLinks->set_text(nPos, sCur, 3);
+ }
+ }
+ m_xTbLinks->thaw();
+}
+
+IMPL_LINK( SvBaseLinksDlg, EndEditHdl, sfx2::SvBaseLink&, _rLink, void )
+{
+ int nPos;
+ GetSelEntry( &nPos );
+
+ if( !_rLink.WasLastEditOK() )
+ return;
+
+ // StarImpress/Draw swap the LinkObjects themselves!
+ // So search for the link in the manager; if it does not exist
+ // anymore, fill the list completely new. Otherwise only the
+ // edited link needs to be refreshed.
+ bool bLinkFnd = false;
+ for( size_t n = pLinkMgr->GetLinks().size(); n; )
+ if( &_rLink == &(*pLinkMgr->GetLinks()[ --n ]) )
+ {
+ bLinkFnd = true;
+ break;
+ }
+
+ if( bLinkFnd )
+ {
+ m_xTbLinks->remove(nPos);
+ int nToUnselect = m_xTbLinks->get_selected_index();
+ InsertEntry(_rLink, nPos, true);
+ if (nToUnselect != -1)
+ m_xTbLinks->unselect(nToUnselect);
+ }
+ else
+ {
+ LinkManager* pNewMgr = pLinkMgr;
+ pLinkMgr = nullptr;
+ SetManager( pNewMgr );
+ }
+ if (pLinkMgr && pLinkMgr->GetPersist())
+ pLinkMgr->GetPersist()->SetModified();
+}
+
+OUString SvBaseLinksDlg::ImplGetStateStr( const SvBaseLink& rLnk )
+{
+ OUString sRet;
+ if( !rLnk.GetObj() )
+ sRet = aStrBrokenlink;
+ else if( rLnk.GetObj()->IsPending() )
+ {
+ sRet = aStrWaitinglink;
+ aUpdateIdle.Start();
+ }
+ else if( SfxLinkUpdateMode::ALWAYS == rLnk.GetUpdateMode() )
+ sRet = aStrAutolink;
+ else
+ sRet = aStrManuallink;
+
+ return sRet;
+}
+
+void SvBaseLinksDlg::SetManager( LinkManager* pNewMgr )
+{
+ if( pLinkMgr == pNewMgr )
+ return;
+
+ if (pNewMgr)
+ {
+ // update has to be stopped before clear
+ m_xTbLinks->freeze();
+ }
+
+ m_xTbLinks->clear();
+ pLinkMgr = pNewMgr;
+
+ if( !pLinkMgr )
+ return;
+
+ SvBaseLinks& rLnks = const_cast<SvBaseLinks&>(pLinkMgr->GetLinks());
+ for( size_t n = 0; n < rLnks.size(); ++n )
+ {
+ tools::SvRef<SvBaseLink>& rLinkRef = rLnks[ n ];
+ if( !rLinkRef.is() )
+ {
+ rLnks.erase( rLnks.begin() + n );
+ --n;
+ continue;
+ }
+ if( rLinkRef->IsVisible() )
+ InsertEntry( *rLinkRef );
+ }
+
+ m_xTbLinks->thaw();
+
+ if( !rLnks.empty() )
+ {
+ m_xTbLinks->set_cursor(0);
+ m_xTbLinks->select(0);
+ LinksSelectHdl( nullptr );
+ }
+}
+
+void SvBaseLinksDlg::InsertEntry(const SvBaseLink& rLink, int nPos, bool bSelect)
+{
+ OUString sFileNm, sLinkNm, sTypeNm, sFilter;
+
+ sfx2::LinkManager::GetDisplayNames( &rLink, &sTypeNm, &sFileNm, &sLinkNm, &sFilter );
+
+ auto nWidthPixel = m_xTbLinks->get_column_width(0);
+ OUString aTxt = m_xVirDev->GetEllipsisString(sFileNm, nWidthPixel, DrawTextFlags::PathEllipsis);
+ INetURLObject aPath( sFileNm, INetProtocol::File );
+ OUString aFileName = aPath.getName(
+ INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::Unambiguous);
+
+ if( aFileName.getLength() > aTxt.getLength() )
+ aTxt = aFileName;
+ else if (!aFileName.isEmpty() && aTxt.indexOf(aFileName, aTxt.getLength() - aFileName.getLength()) == -1)
+ // filename not in string
+ aTxt = aFileName;
+
+ if (nPos == -1)
+ nPos = m_xTbLinks->n_children();
+ m_xTbLinks->insert(nPos);
+ m_xTbLinks->set_text(nPos, aTxt, 0);
+ m_xTbLinks->set_id(nPos, OUString::number(reinterpret_cast<sal_Int64>(&rLink)));
+ if( SvBaseLinkObjectType::ClientGraphic == rLink.GetObjType() )
+ m_xTbLinks->set_text(nPos, sFilter, 1);
+ else
+ m_xTbLinks->set_text(nPos, sLinkNm, 1);
+ m_xTbLinks->set_text(nPos, sTypeNm, 2);
+ m_xTbLinks->set_text(nPos, ImplGetStateStr(rLink), 3);
+ if (bSelect)
+ m_xTbLinks->select(nPos);
+}
+
+SvBaseLink* SvBaseLinksDlg::GetSelEntry(int* pPos)
+{
+ int nPos = m_xTbLinks->get_selected_index();
+ if (nPos != -1)
+ {
+ if (pPos)
+ *pPos = nPos;
+ return reinterpret_cast<SvBaseLink*>(m_xTbLinks->get_id(nPos).toInt64());
+ }
+ return nullptr;
+}
+
+void SvBaseLinksDlg::SetType(SvBaseLink& rLink,
+ int nSelPos,
+ SfxLinkUpdateMode nType)
+{
+ rLink.SetUpdateMode( nType );
+ rLink.Update();
+ m_xTbLinks->set_text(nSelPos, ImplGetStateStr(rLink), 3);
+ if (pLinkMgr->GetPersist())
+ pLinkMgr->GetPersist()->SetModified();
+}
+
+void SvBaseLinksDlg::SetActLink( SvBaseLink const * pLink )
+{
+ if( !pLinkMgr )
+ return;
+
+ const SvBaseLinks& rLnks = pLinkMgr->GetLinks();
+ int nSelect = 0;
+ for(const auto & rLinkRef : rLnks)
+ {
+ // #109573# only visible links have been inserted into the TreeListBox,
+ // invisible ones have to be skipped here
+ if( rLinkRef->IsVisible() )
+ {
+ if( pLink == rLinkRef.get() )
+ {
+ m_xTbLinks->select(nSelect);
+ LinksSelectHdl( nullptr );
+ return ;
+ }
+ ++nSelect;
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/dialogs/multipat.cxx b/cui/source/dialogs/multipat.cxx
new file mode 100644
index 000000000..48dc545f9
--- /dev/null
+++ b/cui/source/dialogs/multipat.cxx
@@ -0,0 +1,320 @@
+/* -*- 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 <osl/file.hxx>
+#include <tools/urlobj.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+
+#include <multipat.hxx>
+#include <dialmgr.hxx>
+
+#include <strings.hrc>
+#include <comphelper/processfactory.hxx>
+#include <com/sun/star/ui/dialogs/FolderPicker.hpp>
+#include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
+
+#include <unotools/pathoptions.hxx>
+
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::ui::dialogs;
+using namespace ::com::sun::star::uno;
+
+IMPL_LINK_NOARG(SvxMultiPathDialog, SelectHdl_Impl, weld::TreeView&, void)
+{
+ auto nCount = m_xRadioLB->n_children();
+ bool bIsSelected = m_xRadioLB->get_selected_index() != -1;
+ bool bEnable = nCount > 1;
+ m_xDelBtn->set_sensitive(bEnable && bIsSelected);
+}
+
+IMPL_LINK_NOARG(SvxPathSelectDialog, SelectHdl_Impl, weld::TreeView&, void)
+{
+ auto nCount = m_xPathLB->n_children();
+ bool bIsSelected = m_xPathLB->get_selected_index() != -1;
+ bool bEnable = nCount > 1;
+ m_xDelBtn->set_sensitive(bEnable && bIsSelected);
+}
+
+void SvxMultiPathDialog::HandleEntryChecked(int nRow)
+{
+ m_xRadioLB->select(nRow);
+ bool bChecked = m_xRadioLB->get_toggle(nRow, 0) == TRISTATE_TRUE;
+ if (bChecked)
+ {
+ // we have radio button behavior -> so uncheck the other entries
+ int nCount = m_xRadioLB->n_children();
+ for (int i = 0; i < nCount; ++i)
+ {
+ if (i != nRow)
+ m_xRadioLB->set_toggle(i, TRISTATE_FALSE, 0);
+ }
+ }
+}
+
+IMPL_LINK(SvxMultiPathDialog, CheckHdl_Impl, const row_col&, rRowCol, void)
+{
+ HandleEntryChecked(rRowCol.first);
+}
+
+void SvxMultiPathDialog::AppendEntry(const OUString& rText, const OUString& rId)
+{
+ m_xRadioLB->append();
+ const int nRow = m_xRadioLB->n_children() - 1;
+ m_xRadioLB->set_toggle(nRow, TRISTATE_FALSE, 0);
+ m_xRadioLB->set_text(nRow, rText, 1);
+ m_xRadioLB->set_id(nRow, rId);
+}
+
+IMPL_LINK_NOARG(SvxMultiPathDialog, AddHdl_Impl, weld::Button&, void)
+{
+ Reference < XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
+ Reference < XFolderPicker2 > xFolderPicker = FolderPicker::create(xContext);
+
+ if ( xFolderPicker->execute() != ExecutableDialogResults::OK )
+ return;
+
+ INetURLObject aPath( xFolderPicker->getDirectory() );
+ aPath.removeFinalSlash();
+ OUString aURL = aPath.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+ OUString sInsPath;
+ osl::FileBase::getSystemPathFromFileURL(aURL, sInsPath);
+
+ if (m_xRadioLB->find_text(sInsPath) != -1)
+ {
+ OUString sMsg( CuiResId( RID_MULTIPATH_DBL_ERR ) );
+ sMsg = sMsg.replaceFirst( "%1", sInsPath );
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Info, VclButtonsType::Ok, sMsg));
+ xInfoBox->run();
+ }
+ else
+ {
+ AppendEntry(sInsPath, aURL);
+ }
+
+ SelectHdl_Impl(*m_xRadioLB);
+}
+
+IMPL_LINK_NOARG(SvxPathSelectDialog, AddHdl_Impl, weld::Button&, void)
+{
+ Reference < XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
+ Reference < XFolderPicker2 > xFolderPicker = FolderPicker::create(xContext);
+
+ if ( xFolderPicker->execute() != ExecutableDialogResults::OK )
+ return;
+
+ INetURLObject aPath( xFolderPicker->getDirectory() );
+ aPath.removeFinalSlash();
+ OUString aURL = aPath.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+ OUString sInsPath;
+ osl::FileBase::getSystemPathFromFileURL(aURL, sInsPath);
+
+ if (m_xPathLB->find_text(sInsPath) != -1)
+ {
+ OUString sMsg( CuiResId( RID_MULTIPATH_DBL_ERR ) );
+ sMsg = sMsg.replaceFirst( "%1", sInsPath );
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Info, VclButtonsType::Ok, sMsg));
+ xInfoBox->run();
+ }
+ else
+ {
+ m_xPathLB->append(aURL, sInsPath);
+ }
+
+ SelectHdl_Impl(*m_xPathLB);
+}
+
+IMPL_LINK_NOARG(SvxMultiPathDialog, DelHdl_Impl, weld::Button&, void)
+{
+ int nPos = m_xRadioLB->get_selected_index();
+ bool bChecked = m_xRadioLB->get_toggle(nPos, 0) == TRISTATE_TRUE;
+ m_xRadioLB->remove(nPos);
+ int nCnt = m_xRadioLB->n_children();
+ if (nCnt)
+ {
+ --nCnt;
+
+ if ( nPos > nCnt )
+ nPos = nCnt;
+ if (bChecked)
+ {
+ m_xRadioLB->set_toggle(nPos, TRISTATE_TRUE, 0);
+ HandleEntryChecked(nPos);
+ }
+ m_xRadioLB->select(nPos);
+ }
+
+ SelectHdl_Impl(*m_xRadioLB);
+}
+
+IMPL_LINK_NOARG(SvxPathSelectDialog, DelHdl_Impl, weld::Button&, void)
+{
+ int nPos = m_xPathLB->get_selected_index();
+ m_xPathLB->remove(nPos);
+ int nCnt = m_xPathLB->n_children();
+
+ if (nCnt)
+ {
+ --nCnt;
+
+ if ( nPos > nCnt )
+ nPos = nCnt;
+ m_xPathLB->select(nPos);
+ }
+
+ SelectHdl_Impl(*m_xPathLB);
+}
+
+SvxMultiPathDialog::SvxMultiPathDialog(weld::Window* pParent)
+ : GenericDialogController(pParent, "cui/ui/multipathdialog.ui", "MultiPathDialog")
+ , m_xRadioLB(m_xBuilder->weld_tree_view("paths"))
+ , m_xAddBtn(m_xBuilder->weld_button("add"))
+ , m_xDelBtn(m_xBuilder->weld_button("delete"))
+{
+ m_xRadioLB->set_size_request(m_xRadioLB->get_approximate_digit_width() * 60,
+ m_xRadioLB->get_text_height() * 10);
+
+ std::vector<int> aWidths;
+ aWidths.push_back(m_xRadioLB->get_checkbox_column_width());
+ m_xRadioLB->set_column_fixed_widths(aWidths);
+
+ std::vector<int> aRadioColumns;
+ aRadioColumns.push_back(0);
+ m_xRadioLB->set_toggle_columns_as_radio(aRadioColumns);
+ m_xRadioLB->connect_toggled(LINK(this, SvxMultiPathDialog, CheckHdl_Impl));
+ m_xRadioLB->connect_changed(LINK(this, SvxMultiPathDialog, SelectHdl_Impl));
+ m_xAddBtn->connect_clicked(LINK(this, SvxMultiPathDialog, AddHdl_Impl));
+ m_xDelBtn->connect_clicked(LINK(this, SvxMultiPathDialog, DelHdl_Impl));
+
+ SelectHdl_Impl(*m_xRadioLB);
+}
+
+SvxPathSelectDialog::SvxPathSelectDialog(weld::Window* pParent)
+ : GenericDialogController(pParent, "cui/ui/selectpathdialog.ui", "SelectPathDialog")
+ , m_xPathLB(m_xBuilder->weld_tree_view("paths"))
+ , m_xAddBtn(m_xBuilder->weld_button("add"))
+ , m_xDelBtn(m_xBuilder->weld_button("delete"))
+{
+ m_xPathLB->set_size_request(m_xPathLB->get_approximate_digit_width() * 60,
+ m_xPathLB->get_text_height() * 10);
+
+ m_xPathLB->connect_changed(LINK(this, SvxPathSelectDialog, SelectHdl_Impl));
+ m_xAddBtn->connect_clicked(LINK(this, SvxPathSelectDialog, AddHdl_Impl));
+ m_xDelBtn->connect_clicked(LINK(this, SvxPathSelectDialog, DelHdl_Impl));
+
+ SelectHdl_Impl(*m_xPathLB);
+}
+
+SvxMultiPathDialog::~SvxMultiPathDialog()
+{
+}
+
+OUString SvxMultiPathDialog::GetPath() const
+{
+ OUStringBuffer sNewPath;
+ sal_Unicode cDelim = SVT_SEARCHPATH_DELIMITER;
+
+ OUString sWritable;
+ for (int i = 0, nCount = m_xRadioLB->n_children(); i < nCount; ++i)
+ {
+ if (m_xRadioLB->get_toggle(i, 0) == TRISTATE_TRUE)
+ sWritable = m_xRadioLB->get_id(i);
+ else
+ {
+ if (!sNewPath.isEmpty())
+ sNewPath.append(cDelim);
+ sNewPath.append(m_xRadioLB->get_id(i));
+ }
+ }
+ if (!sNewPath.isEmpty())
+ sNewPath.append(cDelim);
+ sNewPath.append(sWritable);
+
+ return sNewPath.makeStringAndClear();
+}
+
+OUString SvxPathSelectDialog::GetPath() const
+{
+ OUStringBuffer sNewPath;
+
+ for (int i = 0; i < m_xPathLB->n_children(); ++i)
+ {
+ if ( !sNewPath.isEmpty() )
+ sNewPath.append(SVT_SEARCHPATH_DELIMITER);
+ sNewPath.append( m_xPathLB->get_id(i));
+ }
+
+ return sNewPath.makeStringAndClear();
+}
+
+void SvxMultiPathDialog::SetPath( const OUString& rPath )
+{
+ if ( !rPath.isEmpty() )
+ {
+ const sal_Unicode cDelim = SVT_SEARCHPATH_DELIMITER;
+ int nCount = 0;
+ sal_Int32 nIndex = 0;
+ do
+ {
+ const OUString sPath = rPath.getToken( 0, cDelim, nIndex );
+ OUString sSystemPath;
+ bool bIsSystemPath =
+ osl::FileBase::getSystemPathFromFileURL(sPath, sSystemPath) == osl::FileBase::E_None;
+
+ const OUString sEntry((bIsSystemPath ? sSystemPath : sPath));
+ AppendEntry(sEntry, sPath);
+ ++nCount;
+ }
+ while (nIndex >= 0);
+
+ if (nCount)
+ {
+ m_xRadioLB->set_toggle(nCount - 1, TRISTATE_TRUE, 0);
+ HandleEntryChecked(nCount - 1);
+ }
+ }
+
+ SelectHdl_Impl(*m_xRadioLB);
+}
+
+void SvxPathSelectDialog::SetPath(const OUString& rPath)
+{
+ if ( !rPath.isEmpty() )
+ {
+ sal_Int32 nIndex = 0;
+ do
+ {
+ const OUString sPath = rPath.getToken( 0, SVT_SEARCHPATH_DELIMITER, nIndex );
+ OUString sSystemPath;
+ bool bIsSystemPath =
+ osl::FileBase::getSystemPathFromFileURL(sPath, sSystemPath) == osl::FileBase::E_None;
+
+ m_xPathLB->append(sPath, bIsSystemPath ? sSystemPath : sPath);
+ }
+ while (nIndex >= 0);
+ }
+
+ SelectHdl_Impl(*m_xPathLB);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/dialogs/newtabledlg.cxx b/cui/source/dialogs/newtabledlg.cxx
new file mode 100644
index 000000000..16e81f8d9
--- /dev/null
+++ b/cui/source/dialogs/newtabledlg.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 <newtabledlg.hxx>
+
+SvxNewTableDialog::SvxNewTableDialog(weld::Window* pWindow)
+ : GenericDialogController(pWindow, "cui/ui/newtabledialog.ui", "NewTableDialog")
+ , mxNumColumns(m_xBuilder->weld_spin_button("columns"))
+ , mxNumRows(m_xBuilder->weld_spin_button("rows"))
+{
+}
+
+sal_Int32 SvxNewTableDialog::getRows() const
+{
+ return sal::static_int_cast< sal_Int32 >( mxNumRows->get_value() );
+}
+
+sal_Int32 SvxNewTableDialog::getColumns() const
+{
+ return sal::static_int_cast< sal_Int32 >( mxNumColumns->get_value() );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/dialogs/passwdomdlg.cxx b/cui/source/dialogs/passwdomdlg.cxx
new file mode 100644
index 000000000..250f9e728
--- /dev/null
+++ b/cui/source/dialogs/passwdomdlg.cxx
@@ -0,0 +1,171 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vcl/svapp.hxx>
+#include <passwdomdlg.hxx>
+#include <strings.hrc>
+#include <dialmgr.hxx>
+
+IMPL_LINK_NOARG(PasswordToOpenModifyDialog, OkBtnClickHdl, weld::Button&, void)
+{
+ bool bInvalidState = !m_xOpenReadonlyCB->get_active() &&
+ m_xPasswdToOpenED->get_text().isEmpty() &&
+ m_xPasswdToModifyED->get_text().isEmpty();
+ if (bInvalidState)
+ {
+ std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Warning, VclButtonsType::Ok,
+ m_bIsPasswordToModify? m_aInvalidStateForOkButton : m_aInvalidStateForOkButton_v2));
+ xErrorBox->run();
+ }
+ else // check for mismatched passwords...
+ {
+ const bool bToOpenMatch = m_xPasswdToOpenED->get_text() == m_xReenterPasswdToOpenED->get_text();
+ const bool bToModifyMatch = m_xPasswdToModifyED->get_text() == m_xReenterPasswdToModifyED->get_text();
+ const int nMismatch = (bToOpenMatch? 0 : 1) + (bToModifyMatch? 0 : 1);
+ if (nMismatch > 0)
+ {
+ std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Warning, VclButtonsType::Ok,
+ nMismatch == 1 ? m_aOneMismatch : m_aTwoMismatch));
+ xErrorBox->run();
+
+ weld::Entry* pEdit = !bToOpenMatch ? m_xPasswdToOpenED.get() : m_xPasswdToModifyED.get();
+ weld::Entry* pRepeatEdit = !bToOpenMatch? m_xReenterPasswdToOpenED.get() : m_xReenterPasswdToModifyED.get();
+ if (nMismatch == 1)
+ {
+ pEdit->set_text( "" );
+ pRepeatEdit->set_text( "" );
+ }
+ else if (nMismatch == 2)
+ {
+ m_xPasswdToOpenED->set_text( "" );
+ m_xReenterPasswdToOpenED->set_text( "" );
+ m_xPasswdToModifyED->set_text( "" );
+ m_xReenterPasswdToModifyED->set_text( "" );
+ }
+ pEdit->grab_focus();
+ }
+ else
+ {
+ m_xDialog->response(RET_OK);
+ }
+ }
+}
+
+IMPL_LINK(PasswordToOpenModifyDialog, ChangeHdl, weld::Entry&, rEntry, void)
+{
+ weld::Label* pIndicator = nullptr;
+ int nLength = rEntry.get_text().getLength();
+ if (&rEntry == m_xPasswdToOpenED.get())
+ pIndicator = m_xPasswdToOpenInd.get();
+ else if (&rEntry == m_xReenterPasswdToOpenED.get())
+ pIndicator = m_xReenterPasswdToOpenInd.get();
+ else if (&rEntry == m_xPasswdToModifyED.get())
+ pIndicator = m_xPasswdToModifyInd.get();
+ else if (&rEntry == m_xReenterPasswdToModifyED.get())
+ pIndicator = m_xReenterPasswdToModifyInd.get();
+ assert(pIndicator);
+ pIndicator->set_visible(nLength >= m_nMaxPasswdLen);
+}
+
+PasswordToOpenModifyDialog::PasswordToOpenModifyDialog(weld::Window * pParent, sal_uInt16 nMaxPasswdLen, bool bIsPasswordToModify)
+ : SfxDialogController(pParent, "cui/ui/password.ui", "PasswordDialog")
+ , m_xPasswdToOpenED(m_xBuilder->weld_entry("newpassEntry"))
+ , m_xPasswdToOpenInd(m_xBuilder->weld_label("newpassIndicator"))
+ , m_xReenterPasswdToOpenED(m_xBuilder->weld_entry("confirmpassEntry"))
+ , m_xReenterPasswdToOpenInd(m_xBuilder->weld_label("confirmpassIndicator"))
+ , m_xOptionsExpander(m_xBuilder->weld_expander("expander"))
+ , m_xOk(m_xBuilder->weld_button("ok"))
+ , m_xOpenReadonlyCB(m_xBuilder->weld_check_button("readonly"))
+ , m_xPasswdToModifyFT(m_xBuilder->weld_label("label7"))
+ , m_xPasswdToModifyED(m_xBuilder->weld_entry("newpassroEntry"))
+ , m_xPasswdToModifyInd(m_xBuilder->weld_label("newpassroIndicator"))
+ , m_xReenterPasswdToModifyFT(m_xBuilder->weld_label("label8"))
+ , m_xReenterPasswdToModifyED(m_xBuilder->weld_entry("confirmropassEntry"))
+ , m_xReenterPasswdToModifyInd(m_xBuilder->weld_label("confirmropassIndicator"))
+ , m_aOneMismatch( CuiResId( RID_SVXSTR_ONE_PASSWORD_MISMATCH ) )
+ , m_aTwoMismatch( CuiResId( RID_SVXSTR_TWO_PASSWORDS_MISMATCH ) )
+ , m_aInvalidStateForOkButton( CuiResId( RID_SVXSTR_INVALID_STATE_FOR_OK_BUTTON ) )
+ , m_aInvalidStateForOkButton_v2( CuiResId( RID_SVXSTR_INVALID_STATE_FOR_OK_BUTTON_V2 ) )
+ , m_aIndicatorTemplate(CuiResId(RID_SVXSTR_PASSWORD_LEN_INDICATOR).replaceFirst("%1", OUString::number(nMaxPasswdLen)))
+ , m_nMaxPasswdLen(nMaxPasswdLen)
+ , m_bIsPasswordToModify( bIsPasswordToModify )
+{
+ m_xOk->connect_clicked(LINK(this, PasswordToOpenModifyDialog, OkBtnClickHdl));
+
+ if (nMaxPasswdLen)
+ {
+ m_xPasswdToOpenED->set_max_length( nMaxPasswdLen );
+ m_xPasswdToOpenED->connect_changed(LINK(this, PasswordToOpenModifyDialog, ChangeHdl));
+ m_xPasswdToOpenInd->set_label(m_aIndicatorTemplate);
+ m_xReenterPasswdToOpenED->set_max_length( nMaxPasswdLen );
+ m_xReenterPasswdToOpenED->connect_changed(LINK(this, PasswordToOpenModifyDialog, ChangeHdl));
+ m_xReenterPasswdToOpenInd->set_label(m_aIndicatorTemplate);
+ m_xPasswdToModifyED->set_max_length( nMaxPasswdLen );
+ m_xPasswdToModifyED->connect_changed(LINK(this, PasswordToOpenModifyDialog, ChangeHdl));
+ m_xPasswdToModifyInd->set_label(m_aIndicatorTemplate);
+ m_xReenterPasswdToModifyED->set_max_length( nMaxPasswdLen );
+ m_xReenterPasswdToModifyED->connect_changed(LINK(this, PasswordToOpenModifyDialog, ChangeHdl));
+ m_xReenterPasswdToModifyInd->set_label(m_aIndicatorTemplate);
+ }
+
+ m_xPasswdToOpenED->grab_focus();
+
+ m_xOptionsExpander->set_sensitive(bIsPasswordToModify);
+ if (!bIsPasswordToModify)
+ m_xOptionsExpander->hide();
+
+ m_xOpenReadonlyCB->connect_clicked(LINK(this, PasswordToOpenModifyDialog, ReadonlyOnOffHdl));
+ ReadonlyOnOffHdl(*m_xOpenReadonlyCB);
+}
+
+OUString PasswordToOpenModifyDialog::GetPasswordToOpen() const
+{
+ const bool bPasswdOk =
+ !m_xPasswdToOpenED->get_text().isEmpty() &&
+ m_xPasswdToOpenED->get_text() == m_xReenterPasswdToOpenED->get_text();
+ return bPasswdOk ? m_xPasswdToOpenED->get_text() : OUString();
+}
+
+
+OUString PasswordToOpenModifyDialog::GetPasswordToModify() const
+{
+ const bool bPasswdOk =
+ !m_xPasswdToModifyED->get_text().isEmpty() &&
+ m_xPasswdToModifyED->get_text() == m_xReenterPasswdToModifyED->get_text();
+ return bPasswdOk ? m_xPasswdToModifyED->get_text() : OUString();
+}
+
+
+bool PasswordToOpenModifyDialog::IsRecommendToOpenReadonly() const
+{
+ return m_xOpenReadonlyCB->get_active();
+}
+
+IMPL_LINK_NOARG(PasswordToOpenModifyDialog, ReadonlyOnOffHdl, weld::Button&, void)
+{
+ bool bEnable = m_xOpenReadonlyCB->get_active();
+ m_xPasswdToModifyED->set_sensitive(bEnable);
+ m_xPasswdToModifyFT->set_sensitive(bEnable);
+ m_xReenterPasswdToModifyED->set_sensitive(bEnable);
+ m_xReenterPasswdToModifyFT->set_sensitive(bEnable);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/dialogs/pastedlg.cxx b/cui/source/dialogs/pastedlg.cxx
new file mode 100644
index 000000000..375a966c7
--- /dev/null
+++ b/cui/source/dialogs/pastedlg.cxx
@@ -0,0 +1,339 @@
+/* -*- 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 <pastedlg.hxx>
+#include <svtools/insdlg.hxx>
+#include <sot/exchange.hxx>
+#include <sot/formats.hxx>
+#include <svtools/strings.hrc>
+#include <svtools/svtresid.hxx>
+#include <tools/lineend.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/dispatchcommand.hxx>
+
+SvPasteObjectDialog::SvPasteObjectDialog(weld::Window* pParent)
+ : GenericDialogController(pParent, "cui/ui/pastespecial.ui", "PasteSpecialDialog")
+ , m_xFtObjectSource(m_xBuilder->weld_label("source"))
+ , m_xLbInsertList(m_xBuilder->weld_tree_view("list"))
+ , m_xOKButton(m_xBuilder->weld_button("ok"))
+{
+ m_xLbInsertList->set_size_request(m_xLbInsertList->get_approximate_digit_width() * 40,
+ m_xLbInsertList->get_height_rows(6));
+ m_xOKButton->set_sensitive(false);
+
+ ObjectLB().connect_changed(LINK(this, SvPasteObjectDialog, SelectHdl));
+ ObjectLB().connect_row_activated(LINK( this, SvPasteObjectDialog, DoubleClickHdl));
+}
+
+void SvPasteObjectDialog::SelectObject()
+{
+ if (m_xLbInsertList->n_children())
+ {
+ m_xLbInsertList->select(0);
+ SelectHdl(*m_xLbInsertList);
+ }
+}
+
+IMPL_LINK_NOARG(SvPasteObjectDialog, SelectHdl, weld::TreeView&, void)
+{
+ if (!m_xOKButton->get_sensitive())
+ m_xOKButton->set_sensitive(true);
+}
+
+IMPL_LINK_NOARG(SvPasteObjectDialog, DoubleClickHdl, weld::TreeView&, bool)
+{
+ m_xDialog->response(RET_OK);
+ return true;
+}
+
+/*************************************************************************
+|* SvPasteObjectDialog::Insert()
+*************************************************************************/
+void SvPasteObjectDialog::Insert( SotClipboardFormatId nFormat, const OUString& rFormatName )
+{
+ aSupplementMap.insert( std::make_pair( nFormat, rFormatName ) );
+}
+
+void SvPasteObjectDialog::InsertUno(const OUString& sCmd, const OUString& sLabel)
+{
+ aExtraCommand.first = sCmd;
+ aExtraCommand.second = sLabel;
+}
+
+
+void SvPasteObjectDialog::PreGetFormat( const TransferableDataHelper &rHelper )
+{
+ //TODO/LATER: why is the Descriptor never used?!
+ TransferableObjectDescriptor aDesc;
+ if (rHelper.HasFormat(SotClipboardFormatId::OBJECTDESCRIPTOR))
+ {
+ (void)const_cast<TransferableDataHelper&>(rHelper).GetTransferableObjectDescriptor(
+ SotClipboardFormatId::OBJECTDESCRIPTOR, aDesc);
+ }
+ const DataFlavorExVector* pFormats = &rHelper.GetDataFlavorExVector();
+
+ // create and fill dialog box
+ OUString aSourceName, aTypeName;
+ SvGlobalName aEmptyNm;
+
+ //ObjectLB().SetUpdateMode( false );
+ ObjectLB().freeze();
+
+ DataFlavorExVector::iterator aIter( const_cast<DataFlavorExVector&>(*pFormats).begin() ),
+ aEnd( const_cast<DataFlavorExVector&>(*pFormats).end() );
+ while( aIter != aEnd )
+ {
+ SotClipboardFormatId nFormat = (*aIter++).mnSotId;
+
+ std::map< SotClipboardFormatId, OUString >::iterator itName =
+ aSupplementMap.find( nFormat );
+
+ // if there is an "Embed Source" or and "Embedded Object" on the
+ // Clipboard we read the Description and the Source of this object
+ // from an accompanied "Object Descriptor" format on the clipboard
+ // Remember: these formats mostly appear together on the clipboard
+ OUString aName;
+ const OUString* pName = nullptr;
+ if ( itName == aSupplementMap.end() )
+ {
+ SvPasteObjectHelper::GetEmbeddedName(rHelper,aName,aSourceName,nFormat);
+ if ( !aName.isEmpty() )
+ pName = &aName;
+ }
+ else
+ {
+ pName = &(itName->second);
+ }
+
+ if( pName )
+ {
+ aName = *pName;
+
+ if( SotClipboardFormatId::EMBED_SOURCE == nFormat )
+ {
+ if( aDesc.maClassName != aEmptyNm )
+ {
+ aSourceName = aDesc.maDisplayName;
+
+ if( aDesc.maClassName == aObjClassName )
+ aName = aObjName;
+ else
+ aName = aTypeName = aDesc.maTypeName;
+ }
+ }
+ else if( SotClipboardFormatId::LINK_SOURCE == nFormat )
+ {
+ continue;
+ }
+ else if( aName.isEmpty() )
+ aName = SvPasteObjectHelper::GetSotFormatUIName( nFormat );
+
+ // Show RICHTEXT only in case RTF is not present.
+ if (nFormat == SotClipboardFormatId::RICHTEXT &&
+ std::any_of(pFormats->begin(), pFormats->end(),
+ [](const DataFlavorEx& rFlavor) {
+ return rFlavor.mnSotId == SotClipboardFormatId::RTF;
+ }))
+ {
+ continue;
+ }
+
+ if (ObjectLB().find_text(aName) == -1)
+ {
+ ObjectLB().append(OUString::number(static_cast<sal_uInt32>(nFormat)), aName);
+ }
+ }
+ }
+
+ if( aTypeName.isEmpty() && aSourceName.isEmpty() )
+ {
+ if( aDesc.maClassName != aEmptyNm )
+ {
+ aSourceName = aDesc.maDisplayName;
+ aTypeName = aDesc.maTypeName;
+ }
+
+ if( aTypeName.isEmpty() && aSourceName.isEmpty() )
+ {
+ // global resource from svtools (former so3 resource)
+ aSourceName = SvtResId(STR_UNKNOWN_SOURCE);
+ }
+ }
+
+ ObjectLB().thaw();
+ SelectObject();
+
+ if( !aSourceName.isEmpty() )
+ {
+ if( !aTypeName.isEmpty() )
+ aTypeName += "\n";
+
+ aTypeName += aSourceName;
+ aTypeName = convertLineEnd(aTypeName, GetSystemLineEnd());
+ }
+
+ m_xFtObjectSource->set_label(aTypeName);
+}
+
+SotClipboardFormatId SvPasteObjectDialog::GetFormatOnly()
+{
+ return static_cast<SotClipboardFormatId>(ObjectLB().get_selected_id().toUInt32());
+}
+
+SotClipboardFormatId SvPasteObjectDialog::GetFormat( const TransferableDataHelper& rHelper)
+{
+ //TODO/LATER: why is the Descriptor never used?!
+ TransferableObjectDescriptor aDesc;
+ if (rHelper.HasFormat(SotClipboardFormatId::OBJECTDESCRIPTOR))
+ {
+ (void)const_cast<TransferableDataHelper&>(rHelper).GetTransferableObjectDescriptor(
+ SotClipboardFormatId::OBJECTDESCRIPTOR, aDesc);
+ }
+ const DataFlavorExVector* pFormats = &rHelper.GetDataFlavorExVector();
+
+ // create and fill dialog box
+ OUString aSourceName, aTypeName;
+ SotClipboardFormatId nSelFormat = SotClipboardFormatId::NONE;
+ SvGlobalName aEmptyNm;
+
+ ObjectLB().freeze();
+
+ for (auto const& format : *pFormats)
+ {
+ SotClipboardFormatId nFormat = format.mnSotId;
+
+ std::map< SotClipboardFormatId, OUString >::iterator itName =
+ aSupplementMap.find( nFormat );
+
+ // if there is an "Embed Source" or and "Embedded Object" on the
+ // Clipboard we read the Description and the Source of this object
+ // from an accompanied "Object Descriptor" format on the clipboard
+ // Remember: these formats mostly appear together on the clipboard
+ OUString aName;
+ const OUString* pName = nullptr;
+ if ( itName == aSupplementMap.end() )
+ {
+ SvPasteObjectHelper::GetEmbeddedName(rHelper,aName,aSourceName,nFormat);
+ if ( !aName.isEmpty() )
+ pName = &aName;
+ }
+ else
+ {
+ pName = &(itName->second);
+ }
+
+ if( pName )
+ {
+ aName = *pName;
+
+ if( SotClipboardFormatId::EMBED_SOURCE == nFormat )
+ {
+ if( aDesc.maClassName != aEmptyNm )
+ {
+ aSourceName = aDesc.maDisplayName;
+
+ if( aDesc.maClassName == aObjClassName )
+ aName = aObjName;
+ else
+ aName = aTypeName = aDesc.maTypeName;
+ }
+ }
+ else if( SotClipboardFormatId::LINK_SOURCE == nFormat )
+ {
+ continue;
+ }
+ else if( aName.isEmpty() )
+ aName = SvPasteObjectHelper::GetSotFormatUIName( nFormat );
+
+ // Show RICHTEXT only in case RTF is not present.
+ if (nFormat == SotClipboardFormatId::RICHTEXT &&
+ std::any_of(pFormats->begin(), pFormats->end(),
+ [](const DataFlavorEx& rFlavor) {
+ return rFlavor.mnSotId == SotClipboardFormatId::RTF;
+ }))
+ {
+ continue;
+ }
+
+ if (ObjectLB().find_text(aName) == -1)
+ {
+ ObjectLB().append(OUString::number(static_cast<sal_uInt32>(nFormat)), aName);
+ }
+ }
+ }
+
+ if( aTypeName.isEmpty() && aSourceName.isEmpty() )
+ {
+ if( aDesc.maClassName != aEmptyNm )
+ {
+ aSourceName = aDesc.maDisplayName;
+ aTypeName = aDesc.maTypeName;
+ }
+
+ if( aTypeName.isEmpty() && aSourceName.isEmpty() )
+ {
+ // global resource from svtools (former so3 resource)
+ aSourceName = SvtResId(STR_UNKNOWN_SOURCE);
+ }
+ }
+
+ if (!aExtraCommand.first.isEmpty())
+ {
+ ObjectLB().append(aExtraCommand.first, aExtraCommand.second);
+ }
+
+ ObjectLB().thaw();
+ SelectObject();
+
+ if( !aSourceName.isEmpty() )
+ {
+ if( !aTypeName.isEmpty() )
+ aTypeName += "\n";
+
+ aTypeName += aSourceName;
+ aTypeName = convertLineEnd(aTypeName, GetSystemLineEnd());
+ }
+
+ m_xFtObjectSource->set_label(aTypeName);
+
+ if (run() == RET_OK)
+ {
+ if (ObjectLB().get_selected_id().startsWithIgnoreAsciiCase(".uno"))
+ {
+ comphelper::dispatchCommand(aExtraCommand.first, {});
+ nSelFormat = SotClipboardFormatId::NONE;
+ }
+ else
+ {
+ nSelFormat = static_cast<SotClipboardFormatId>(ObjectLB().get_selected_id().toUInt32());
+ }
+ }
+
+ return nSelFormat;
+}
+
+void SvPasteObjectDialog::SetObjName( const SvGlobalName & rClass, const OUString & rObjName )
+{
+ aObjClassName = rClass;
+ aObjName = rObjName;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/dialogs/postdlg.cxx b/cui/source/dialogs/postdlg.cxx
new file mode 100644
index 000000000..b96c1dd85
--- /dev/null
+++ b/cui/source/dialogs/postdlg.cxx
@@ -0,0 +1,180 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * 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/date.hxx>
+#include <tools/lineend.hxx>
+#include <tools/time.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <svl/itempool.hxx>
+#include <svl/itemset.hxx>
+#include <unotools/useroptions.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <svx/svxids.hrc>
+
+#include <svx/postattr.hxx>
+#include <postdlg.hxx>
+
+// class SvxPostItDialog -------------------------------------------------
+
+SvxPostItDialog::SvxPostItDialog(weld::Widget* pParent, const SfxItemSet& rCoreSet,
+ bool bPrevNext)
+ : SfxDialogController(pParent, "cui/ui/comment.ui", "CommentDialog")
+ , m_rSet(rCoreSet)
+ , m_xLastEditFT(m_xBuilder->weld_label("lastedit"))
+ , m_xAltTitle(m_xBuilder->weld_label("alttitle"))
+ , m_xEditED(m_xBuilder->weld_text_view("edit"))
+ , m_xInsertAuthor(m_xBuilder->weld_widget("insertauthor"))
+ , m_xAuthorBtn(m_xBuilder->weld_button("author"))
+ , m_xOKBtn(m_xBuilder->weld_button("ok"))
+ , m_xPrevBtn(m_xBuilder->weld_button("previous"))
+ , m_xNextBtn(m_xBuilder->weld_button("next"))
+{
+ m_xPrevBtn->connect_clicked( LINK( this, SvxPostItDialog, PrevHdl ) );
+ m_xNextBtn->connect_clicked( LINK( this, SvxPostItDialog, NextHdl ) );
+ m_xAuthorBtn->connect_clicked( LINK( this, SvxPostItDialog, Stamp ) );
+ m_xOKBtn->connect_clicked( LINK( this, SvxPostItDialog, OKHdl ) );
+
+ bool bNew = true;
+ sal_uInt16 nWhich = 0;
+
+ m_xPrevBtn->set_visible(bPrevNext);
+ m_xNextBtn->set_visible(bPrevNext);
+
+ nWhich = m_rSet.GetPool()->GetWhich( SID_ATTR_POSTIT_AUTHOR );
+ OUString aAuthorStr, aDateStr;
+
+ if (m_rSet.GetItemState( nWhich ) >= SfxItemState::DEFAULT)
+ {
+ bNew = false;
+ const SvxPostItAuthorItem& rAuthor =
+ static_cast<const SvxPostItAuthorItem&>(m_rSet.Get(nWhich));
+ aAuthorStr = rAuthor.GetValue();
+ }
+ else
+ aAuthorStr = SvtUserOptions().GetID();
+
+ nWhich = m_rSet.GetPool()->GetWhich( SID_ATTR_POSTIT_DATE );
+
+ if (m_rSet.GetItemState( nWhich ) >= SfxItemState::DEFAULT)
+ {
+ const SvxPostItDateItem& rDate =
+ static_cast<const SvxPostItDateItem&>(m_rSet.Get( nWhich ));
+ aDateStr = rDate.GetValue();
+ }
+ else
+ {
+ const LocaleDataWrapper& rLocaleWrapper( Application::GetSettings().GetLocaleDataWrapper() );
+ aDateStr = rLocaleWrapper.getDate( Date( Date::SYSTEM ) );
+ }
+
+ nWhich = m_rSet.GetPool()->GetWhich( SID_ATTR_POSTIT_TEXT );
+
+ OUString aTextStr;
+ if (m_rSet.GetItemState( nWhich ) >= SfxItemState::DEFAULT)
+ {
+ const SvxPostItTextItem& rText =
+ static_cast<const SvxPostItTextItem&>(m_rSet.Get( nWhich ));
+ aTextStr = rText.GetValue();
+ }
+
+ ShowLastAuthor(aAuthorStr, aDateStr);
+
+ //lock to an initial size before replacing contents
+ m_xEditED->set_size_request(m_xEditED->get_approximate_digit_width() * 32,
+ m_xEditED->get_height_rows(10));
+ m_xEditED->set_text(convertLineEnd(aTextStr, GetSystemLineEnd()));
+
+ if (!bNew)
+ m_xDialog->set_title(m_xAltTitle->get_label());
+}
+
+
+SvxPostItDialog::~SvxPostItDialog()
+{
+}
+
+void SvxPostItDialog::ShowLastAuthor(const OUString& rAuthor, const OUString& rDate)
+{
+ OUString sTxt = rAuthor + ", " + rDate;
+ m_xLastEditFT->set_label( sTxt );
+}
+
+const sal_uInt16* SvxPostItDialog::GetRanges()
+{
+ static const sal_uInt16 pRanges[] =
+ {
+ SID_ATTR_POSTIT_AUTHOR,
+ SID_ATTR_POSTIT_TEXT,
+ 0
+ };
+ return pRanges;
+}
+
+void SvxPostItDialog::EnableTravel(bool bNext, bool bPrev)
+{
+ m_xPrevBtn->set_sensitive(bPrev);
+ m_xNextBtn->set_sensitive(bNext);
+}
+
+IMPL_LINK_NOARG(SvxPostItDialog, PrevHdl, weld::Button&, void)
+{
+ m_aPrevHdlLink.Call( *this );
+}
+
+IMPL_LINK_NOARG(SvxPostItDialog, NextHdl, weld::Button&, void)
+{
+ m_aNextHdlLink.Call( *this );
+}
+
+IMPL_LINK_NOARG(SvxPostItDialog, Stamp, weld::Button&, void)
+{
+ Date aDate( Date::SYSTEM );
+ tools::Time aTime( tools::Time::SYSTEM );
+ OUString aTmp( SvtUserOptions().GetID() );
+ const LocaleDataWrapper& rLocaleWrapper( Application::GetSettings().GetLocaleDataWrapper() );
+ OUString aStr( m_xEditED->get_text() + "\n---- " );
+
+ if ( !aTmp.isEmpty() )
+ {
+ aStr += aTmp + ", ";
+ }
+ aStr += rLocaleWrapper.getDate(aDate) + ", " + rLocaleWrapper.getTime(aTime, false) + " ----\n";
+ aStr = convertLineEnd(aStr, GetSystemLineEnd());
+
+ m_xEditED->set_text(aStr);
+ sal_Int32 nLen = aStr.getLength();
+ m_xEditED->grab_focus();
+ m_xEditED->select_region(nLen, nLen);
+}
+
+IMPL_LINK_NOARG(SvxPostItDialog, OKHdl, weld::Button&, void)
+{
+ const LocaleDataWrapper& rLocaleWrapper( Application::GetSettings().GetLocaleDataWrapper() );
+ m_xOutSet.reset(new SfxItemSet(m_rSet));
+ m_xOutSet->Put( SvxPostItAuthorItem(SvtUserOptions().GetID(),
+ m_rSet.GetPool()->GetWhich( SID_ATTR_POSTIT_AUTHOR ) ) );
+ m_xOutSet->Put( SvxPostItDateItem(rLocaleWrapper.getDate( Date( Date::SYSTEM ) ),
+ m_rSet.GetPool()->GetWhich( SID_ATTR_POSTIT_DATE ) ) );
+ m_xOutSet->Put( SvxPostItTextItem(m_xEditED->get_text(),
+ m_rSet.GetPool()->GetWhich( SID_ATTR_POSTIT_TEXT ) ) );
+ m_xDialog->response(RET_OK);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/dialogs/screenshotannotationdlg.cxx b/cui/source/dialogs/screenshotannotationdlg.cxx
new file mode 100644
index 000000000..4054fa573
--- /dev/null
+++ b/cui/source/dialogs/screenshotannotationdlg.cxx
@@ -0,0 +1,583 @@
+/* -*- 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 <screenshotannotationdlg.hxx>
+
+#include <strings.hrc>
+#include <dialmgr.hxx>
+
+#include <basegfx/range/b2irange.hxx>
+#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
+#include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
+#include <com/sun/star/ui/dialogs/XFilePicker3.hpp>
+
+#include <comphelper/random.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <sfx2/filedlghelper.hxx>
+#include <tools/stream.hxx>
+#include <tools/urlobj.hxx>
+#include <vcl/bitmapex.hxx>
+#include <vcl/customweld.hxx>
+#include <vcl/event.hxx>
+#include <vcl/pngwrite.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/salgtype.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/weld.hxx>
+#include <svtools/optionsdrawinglayer.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <set>
+
+using namespace com::sun::star;
+
+namespace
+{
+ OUString lcl_genRandom( const OUString &rId )
+ {
+ //FIXME: plus timestamp
+ unsigned int nRand = comphelper::rng::uniform_uint_distribution(0, 0xFFFF);
+ return OUString( rId + OUString::number( nRand ) );
+ }
+
+
+ OUString lcl_AltDescr()
+ {
+ OUString aTempl("<alt id=\"%1\">"
+ " " //FIXME real dialog title or something
+ "</alt>");
+ aTempl = aTempl.replaceFirst( "%1", lcl_genRandom("alt_id") );
+
+ return aTempl;
+ }
+
+ OUString lcl_Image( const OUString& rScreenshotId, const Size& rSize )
+ {
+ OUString aTempl("<image id=\"%1\" src=\"media/screenshots/%2.png\""
+ " width=\"%3cm\" height=\"%4cm\">"
+ "%5"
+ "</image>");
+ aTempl = aTempl.replaceFirst( "%1", lcl_genRandom("img_id") );
+ aTempl = aTempl.replaceFirst( "%2", rScreenshotId );
+ aTempl = aTempl.replaceFirst( "%3", OUString::number( rSize.Width() ) );
+ aTempl = aTempl.replaceFirst( "%4", OUString::number( rSize.Height() ) );
+ aTempl = aTempl.replaceFirst( "%5", lcl_AltDescr() );
+
+ return aTempl;
+ }
+
+ OUString lcl_ParagraphWithImage( const OUString& rScreenshotId, const Size& rSize )
+ {
+ OUString aTempl( "<paragraph id=\"%1\" role=\"paragraph\">%2"
+ "</paragraph>" SAL_NEWLINE_STRING );
+ aTempl = aTempl.replaceFirst( "%1", lcl_genRandom("par_id") );
+ aTempl = aTempl.replaceFirst( "%2", lcl_Image(rScreenshotId, rSize) );
+
+ return aTempl;
+ }
+
+ OUString lcl_Bookmark( const OUString& rWidgetId )
+ {
+ OUString aTempl = "<!-- Bookmark for widget %1 -->" SAL_NEWLINE_STRING
+ "<bookmark branch=\"hid/%2\" id=\"%3\" localize=\"false\"/>" SAL_NEWLINE_STRING;
+ aTempl = aTempl.replaceFirst( "%1", rWidgetId );
+ aTempl = aTempl.replaceFirst( "%2", rWidgetId );
+ aTempl = aTempl.replaceFirst( "%3", lcl_genRandom("bm_id") );
+
+ return aTempl;
+ }
+}
+
+namespace
+{
+ class Picture : public weld::CustomWidgetController
+ {
+ private:
+ ScreenshotAnnotationDlg_Impl *m_pDialog;
+ bool m_bMouseOver;
+ private:
+ virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) override;
+ virtual bool MouseMove(const MouseEvent& rMouseEvent) override;
+ virtual bool MouseButtonUp(const MouseEvent& rMouseEvent) override;
+ public:
+ Picture(ScreenshotAnnotationDlg_Impl* pDialog)
+ : m_pDialog(pDialog)
+ , m_bMouseOver(false)
+ {
+ }
+
+ bool IsMouseOver() const
+ {
+ return m_bMouseOver;
+ }
+ };
+}
+
+class ScreenshotAnnotationDlg_Impl
+{
+public:
+ ScreenshotAnnotationDlg_Impl(
+ weld::Window* pParent,
+ weld::Builder& rParent,
+ weld::Dialog& rParentDialog);
+ ~ScreenshotAnnotationDlg_Impl();
+
+private:
+ // Handler for click on save
+ DECL_LINK(saveButtonHandler, weld::Button&, void);
+
+ // helper methods
+ weld::ScreenShotEntry* CheckHit(const basegfx::B2IPoint& rPosition);
+ void PaintScreenShotEntry(
+ const weld::ScreenShotEntry& rEntry,
+ const Color& rColor,
+ double fLineWidth,
+ double fTransparency);
+ void RepaintToBuffer(
+ bool bUseDimmed = false,
+ bool bPaintHilight = false);
+ void RepaintPictureElement();
+ Point GetOffsetInPicture() const;
+
+ // local variables
+ weld::Window* mpParentWindow;
+ weld::Dialog& mrParentDialog;
+ BitmapEx maParentDialogBitmap;
+ BitmapEx maDimmedDialogBitmap;
+ Size maParentDialogSize;
+
+ // VirtualDevice for buffered interaction paints
+ VclPtr<VirtualDevice> mxVirtualBufferDevice;
+
+ // all detected children
+ weld::ScreenShotCollection maAllChildren;
+
+ // highlighted/selected children
+ weld::ScreenShotEntry* mpHilighted;
+ std::set< weld::ScreenShotEntry* >
+ maSelected;
+
+ // list of detected controls
+ Picture maPicture;
+ std::unique_ptr<weld::CustomWeld> mxPicture;
+ std::unique_ptr<weld::TextView> mxText;
+ std::unique_ptr<weld::Button> mxSave;
+
+ // save as text
+ OUString maSaveAsText;
+ OUString maMainMarkupText;
+
+ // folder URL
+ static OUString maLastFolderURL;
+public:
+ void Paint(vcl::RenderContext& rRenderContext);
+ bool MouseMove(const MouseEvent& rMouseEvent);
+ bool MouseButtonUp();
+};
+
+OUString ScreenshotAnnotationDlg_Impl::maLastFolderURL = OUString();
+
+ScreenshotAnnotationDlg_Impl::ScreenshotAnnotationDlg_Impl(
+ weld::Window* pParent,
+ weld::Builder& rParentBuilder,
+ weld::Dialog& rParentDialog)
+: mpParentWindow(pParent),
+ mrParentDialog(rParentDialog),
+ mxVirtualBufferDevice(nullptr),
+ maAllChildren(),
+ mpHilighted(nullptr),
+ maSelected(),
+ maPicture(this),
+ maSaveAsText(CuiResId(RID_SVXSTR_SAVE_SCREENSHOT_AS))
+{
+ VclPtr<VirtualDevice> xParentDialogSurface(VclPtr<VirtualDevice>::Create(DeviceFormat::DEFAULT));
+ rParentDialog.draw(*xParentDialogSurface);
+ maParentDialogSize = xParentDialogSurface->GetOutputSizePixel();
+ maParentDialogBitmap = xParentDialogSurface->GetBitmapEx(Point(), maParentDialogSize);
+ maDimmedDialogBitmap = maParentDialogBitmap;
+
+ // image ain't empty
+ assert(!maParentDialogBitmap.IsEmpty());
+ assert(0 != maParentDialogBitmap.GetSizePixel().Width());
+ assert(0 != maParentDialogBitmap.GetSizePixel().Height());
+
+ // get needed widgets
+ mxPicture.reset(new weld::CustomWeld(rParentBuilder, "picture", maPicture));
+ assert(mxPicture);
+ mxText = rParentBuilder.weld_text_view("text");
+ assert(mxText);
+ mxSave = rParentBuilder.weld_button("save");
+ assert(mxSave);
+
+ // set screenshot image at DrawingArea, resize, set event listener
+ if (mxPicture)
+ {
+ maAllChildren = mrParentDialog.collect_screenshot_data();
+
+ // to make clear that maParentDialogBitmap is a background image, adjust
+ // luminance a bit for maDimmedDialogBitmap - other methods may be applied
+ maDimmedDialogBitmap.Adjust(-15, 0, 0, 0, 0);
+
+ // init paint buffering VirtualDevice
+ mxVirtualBufferDevice = VclPtr<VirtualDevice>::Create(*Application::GetDefaultDevice(), DeviceFormat::DEFAULT, DeviceFormat::BITMASK);
+ mxVirtualBufferDevice->SetOutputSizePixel(maParentDialogSize);
+ mxVirtualBufferDevice->SetFillColor(COL_TRANSPARENT);
+
+ // initially set image for picture control
+ mxVirtualBufferDevice->DrawBitmapEx(Point(0, 0), maDimmedDialogBitmap);
+
+ // set size for picture control, this will re-layout so that
+ // the picture control shows the whole dialog
+ maPicture.SetOutputSizePixel(maParentDialogSize);
+ mxPicture->set_size_request(maParentDialogSize.Width(), maParentDialogSize.Height());
+
+ mxPicture->queue_draw();
+ }
+
+ // set some test text at VclMultiLineEdit and make read-only - only
+ // copying content to clipboard is allowed
+ if (mxText)
+ {
+ mxText->set_size_request(400, mxText->get_height_rows(10));
+ OUString aHelpId = OStringToOUString( mrParentDialog.get_help_id(), RTL_TEXTENCODING_UTF8 );
+ Size aSizeCm = Application::GetDefaultDevice()->PixelToLogic(maParentDialogSize, MapMode(MapUnit::MapCM));
+ maMainMarkupText = lcl_ParagraphWithImage( aHelpId, aSizeCm );
+ mxText->set_text( maMainMarkupText );
+ mxText->set_editable(false);
+ }
+
+ // set click handler for save button
+ if (mxSave)
+ {
+ mxSave->connect_clicked(LINK(this, ScreenshotAnnotationDlg_Impl, saveButtonHandler));
+ }
+}
+
+ScreenshotAnnotationDlg_Impl::~ScreenshotAnnotationDlg_Impl()
+{
+ mxVirtualBufferDevice.disposeAndClear();
+}
+
+IMPL_LINK_NOARG(ScreenshotAnnotationDlg_Impl, saveButtonHandler, weld::Button&, void)
+{
+ // 'save screenshot...' pressed, offer to save maParentDialogBitmap
+ // as PNG image, use *.id file name as screenshot file name offering
+ // get a suggestion for the filename from buildable name
+ OString aDerivedFileName = mrParentDialog.get_buildable_name();
+
+ auto xFileDlg = std::make_unique<sfx2::FileDialogHelper>(ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION,
+ FileDialogFlags::NONE, mpParentWindow);
+
+ const uno::Reference< ui::dialogs::XFilePicker3 > xFilePicker = xFileDlg->GetFilePicker();
+
+ xFilePicker->setTitle(maSaveAsText);
+
+ if (!maLastFolderURL.isEmpty())
+ {
+ xFilePicker->setDisplayDirectory(maLastFolderURL);
+ }
+
+ xFilePicker->appendFilter("*.png", "*.png");
+ xFilePicker->setCurrentFilter("*.png");
+ xFilePicker->setDefaultName(OStringToOUString(aDerivedFileName, RTL_TEXTENCODING_UTF8));
+ xFilePicker->setMultiSelectionMode(false);
+
+ if (xFilePicker->execute() != ui::dialogs::ExecutableDialogResults::OK)
+ return;
+
+ maLastFolderURL = xFilePicker->getDisplayDirectory();
+ const uno::Sequence< OUString > files(xFilePicker->getSelectedFiles());
+
+ if (!files.hasElements())
+ return;
+
+ OUString aConfirmedName = files[0];
+
+ if (aConfirmedName.isEmpty())
+ return;
+
+ INetURLObject aConfirmedURL(aConfirmedName);
+ OUString aCurrentExtension(aConfirmedURL.getExtension());
+
+ if (!aCurrentExtension.isEmpty() && aCurrentExtension != "png")
+ {
+ aConfirmedURL.removeExtension();
+ aCurrentExtension.clear();
+ }
+
+ if (aCurrentExtension.isEmpty())
+ {
+ aConfirmedURL.setExtension("png");
+ }
+
+ // open stream
+ SvFileStream aNew(aConfirmedURL.PathToFileName(), StreamMode::WRITE | StreamMode::TRUNC);
+
+ if (!aNew.IsOpen())
+ return;
+
+ // prepare bitmap to save - do use the original screenshot here,
+ // not the dimmed one
+ RepaintToBuffer();
+
+ // extract Bitmap
+ const BitmapEx aTargetBitmap(
+ mxVirtualBufferDevice->GetBitmapEx(
+ Point(0, 0),
+ mxVirtualBufferDevice->GetOutputSizePixel()));
+
+ // write as PNG
+ vcl::PNGWriter aPNGWriter(aTargetBitmap);
+ aPNGWriter.Write(aNew);
+}
+
+weld::ScreenShotEntry* ScreenshotAnnotationDlg_Impl::CheckHit(const basegfx::B2IPoint& rPosition)
+{
+ weld::ScreenShotEntry* pRetval = nullptr;
+
+ for (auto&& rCandidate : maAllChildren)
+ {
+ if (rCandidate.getB2IRange().isInside(rPosition))
+ {
+ if (pRetval)
+ {
+ if (pRetval->getB2IRange().isInside(rCandidate.getB2IRange().getMinimum())
+ && pRetval->getB2IRange().isInside(rCandidate.getB2IRange().getMaximum()))
+ {
+ pRetval = &rCandidate;
+ }
+ }
+ else
+ {
+ pRetval = &rCandidate;
+ }
+ }
+ }
+
+ return pRetval;
+}
+
+void ScreenshotAnnotationDlg_Impl::PaintScreenShotEntry(
+ const weld::ScreenShotEntry& rEntry,
+ const Color& rColor,
+ double fLineWidth,
+ double fTransparency)
+{
+ if (!(mxPicture && mxVirtualBufferDevice))
+ return;
+
+ basegfx::B2DRange aB2DRange(rEntry.getB2IRange());
+
+ // grow in pixels to be a little bit 'outside'. This also
+ // ensures that getWidth()/getHeight() ain't 0.0 (see division below)
+ static const double fGrowTopLeft(1.5);
+ static const double fGrowBottomRight(0.5);
+ aB2DRange.expand(aB2DRange.getMinimum() - basegfx::B2DPoint(fGrowTopLeft, fGrowTopLeft));
+ aB2DRange.expand(aB2DRange.getMaximum() + basegfx::B2DPoint(fGrowBottomRight, fGrowBottomRight));
+
+ // edge rounding in pixel. Need to convert, value for
+ // createPolygonFromRect is relative [0.0 .. 1.0]
+ static const double fEdgeRoundPixel(8.0);
+ const basegfx::B2DPolygon aPolygon(
+ basegfx::utils::createPolygonFromRect(
+ aB2DRange,
+ fEdgeRoundPixel / aB2DRange.getWidth(),
+ fEdgeRoundPixel / aB2DRange.getHeight()));
+
+ mxVirtualBufferDevice->SetLineColor(rColor);
+
+ // try to use transparency
+ if (!mxVirtualBufferDevice->DrawPolyLineDirect(
+ basegfx::B2DHomMatrix(),
+ aPolygon,
+ fLineWidth,
+ fTransparency,
+ nullptr, // MM01
+ basegfx::B2DLineJoin::Round))
+ {
+ // no transparency, draw without
+ mxVirtualBufferDevice->DrawPolyLine(
+ aPolygon,
+ fLineWidth);
+ }
+}
+
+Point ScreenshotAnnotationDlg_Impl::GetOffsetInPicture() const
+{
+ const Size aPixelSizeTarget(maPicture.GetOutputSizePixel());
+
+ return Point(
+ aPixelSizeTarget.Width() > maParentDialogSize.Width() ? (aPixelSizeTarget.Width() - maParentDialogSize.Width()) >> 1 : 0,
+ aPixelSizeTarget.Height() > maParentDialogSize.Height() ? (aPixelSizeTarget.Height() - maParentDialogSize.Height()) >> 1 : 0);
+}
+
+void ScreenshotAnnotationDlg_Impl::RepaintToBuffer(
+ bool bUseDimmed,
+ bool bPaintHilight)
+{
+ if (!mxVirtualBufferDevice)
+ return;
+
+ // reset with original screenshot bitmap
+ mxVirtualBufferDevice->DrawBitmapEx(
+ Point(0, 0),
+ bUseDimmed ? maDimmedDialogBitmap : maParentDialogBitmap);
+
+ // get various options
+ const SvtOptionsDrawinglayer aSvtOptionsDrawinglayer;
+ const Color aHilightColor(aSvtOptionsDrawinglayer.getHilightColor());
+ const double fTransparence(aSvtOptionsDrawinglayer.GetTransparentSelectionPercent() * 0.01);
+ const bool bIsAntiAliasing(aSvtOptionsDrawinglayer.IsAntiAliasing());
+ const AntialiasingFlags nOldAA(mxVirtualBufferDevice->GetAntialiasing());
+
+ if (bIsAntiAliasing)
+ {
+ mxVirtualBufferDevice->SetAntialiasing(AntialiasingFlags::EnableB2dDraw);
+ }
+
+ // paint selected entries
+ for (auto&& rCandidate : maSelected)
+ {
+ static const double fLineWidthEntries(5.0);
+ PaintScreenShotEntry(*rCandidate, COL_LIGHTRED, fLineWidthEntries, fTransparence * 0.2);
+ }
+
+ // paint highlighted entry
+ if (mpHilighted && bPaintHilight)
+ {
+ static const double fLineWidthHilight(7.0);
+ PaintScreenShotEntry(*mpHilighted, aHilightColor, fLineWidthHilight, fTransparence);
+ }
+
+ if (bIsAntiAliasing)
+ {
+ mxVirtualBufferDevice->SetAntialiasing(nOldAA);
+ }
+}
+
+void ScreenshotAnnotationDlg_Impl::RepaintPictureElement()
+{
+ if (mxPicture && mxVirtualBufferDevice)
+ {
+ // reset image in buffer, use dimmed version and allow highlight
+ RepaintToBuffer(true, true);
+ mxPicture->queue_draw();
+ }
+}
+
+void ScreenshotAnnotationDlg_Impl::Paint(vcl::RenderContext& rRenderContext)
+{
+ Point aPos(GetOffsetInPicture());
+ Size aSize(mxVirtualBufferDevice->GetOutputSizePixel());
+ rRenderContext.DrawOutDev(aPos, aSize, Point(), aSize, *mxVirtualBufferDevice);
+}
+
+void Picture::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ m_pDialog->Paint(rRenderContext);
+}
+
+bool ScreenshotAnnotationDlg_Impl::MouseMove(const MouseEvent& rMouseEvent)
+{
+ bool bRepaint(false);
+
+ if (maPicture.IsMouseOver())
+ {
+ const weld::ScreenShotEntry* pOldHit = mpHilighted;
+ const Point aOffset(GetOffsetInPicture());
+ const basegfx::B2IPoint aMousePos(
+ rMouseEvent.GetPosPixel().X() - aOffset.X(),
+ rMouseEvent.GetPosPixel().Y() - aOffset.Y());
+ const weld::ScreenShotEntry* pHit = CheckHit(aMousePos);
+
+ if (pHit && pOldHit != pHit)
+ {
+ mpHilighted = const_cast<weld::ScreenShotEntry*>(pHit);
+ bRepaint = true;
+ }
+ }
+ else if (mpHilighted)
+ {
+ mpHilighted = nullptr;
+ bRepaint = true;
+ }
+
+ if (bRepaint)
+ {
+ RepaintPictureElement();
+ }
+
+ return true;
+}
+
+bool Picture::MouseMove(const MouseEvent& rMouseEvent)
+{
+ if (rMouseEvent.IsEnterWindow())
+ m_bMouseOver = true;
+ if (rMouseEvent.IsLeaveWindow())
+ m_bMouseOver = false;
+ return m_pDialog->MouseMove(rMouseEvent);
+}
+
+bool ScreenshotAnnotationDlg_Impl::MouseButtonUp()
+{
+ // event in picture frame
+ bool bRepaint(false);
+
+ if (maPicture.IsMouseOver() && mpHilighted)
+ {
+ if (maSelected.erase(mpHilighted) == 0)
+ {
+ maSelected.insert(mpHilighted);
+ }
+
+ OUStringBuffer aBookmarks(maMainMarkupText);
+ for (auto&& rCandidate : maSelected)
+ {
+ OUString aHelpId = OStringToOUString( rCandidate->GetHelpId(), RTL_TEXTENCODING_UTF8 );
+ aBookmarks.append(lcl_Bookmark( aHelpId ));
+ }
+
+ mxText->set_text( aBookmarks.makeStringAndClear() );
+ bRepaint = true;
+ }
+
+ if (bRepaint)
+ {
+ RepaintPictureElement();
+ }
+
+ return true;
+}
+
+bool Picture::MouseButtonUp(const MouseEvent&)
+{
+ return m_pDialog->MouseButtonUp();
+}
+
+ScreenshotAnnotationDlg::ScreenshotAnnotationDlg(weld::Dialog& rParentDialog)
+ : GenericDialogController(&rParentDialog, "cui/ui/screenshotannotationdialog.ui", "ScreenshotAnnotationDialog")
+{
+ m_pImpl.reset(new ScreenshotAnnotationDlg_Impl(m_xDialog.get(), *m_xBuilder, rParentDialog));
+}
+
+ScreenshotAnnotationDlg::~ScreenshotAnnotationDlg()
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/dialogs/scriptdlg.cxx b/cui/source/dialogs/scriptdlg.cxx
new file mode 100644
index 000000000..5319ac680
--- /dev/null
+++ b/cui/source/dialogs/scriptdlg.cxx
@@ -0,0 +1,1351 @@
+/* -*- 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 <utility>
+
+#include <sfx2/objsh.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+
+#include <strings.hrc>
+#include <bitmaps.hlst>
+#include <scriptdlg.hxx>
+#include <dialmgr.hxx>
+
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/script/provider/ScriptFrameworkErrorException.hpp>
+#include <com/sun/star/script/provider/XScriptProviderSupplier.hpp>
+#include <com/sun/star/script/provider/XScriptProvider.hpp>
+#include <com/sun/star/script/browse/BrowseNodeTypes.hpp>
+#include <com/sun/star/script/browse/XBrowseNodeFactory.hpp>
+#include <com/sun/star/script/browse/BrowseNodeFactoryViewTypes.hpp>
+#include <com/sun/star/script/browse/theBrowseNodeFactory.hpp>
+#include <com/sun/star/script/provider/ScriptErrorRaisedException.hpp>
+#include <com/sun/star/script/provider/ScriptExceptionRaisedException.hpp>
+#include <com/sun/star/script/provider/ScriptFrameworkErrorType.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/frame/ModuleManager.hpp>
+#include <com/sun/star/script/XInvocation.hpp>
+#include <com/sun/star/document/XEmbeddedScripts.hpp>
+
+#include <comphelper/SetFlagContextHelper.hxx>
+#include <comphelper/documentinfo.hxx>
+#include <comphelper/processfactory.hxx>
+
+#include <svtools/imagemgr.hxx>
+#include <tools/urlobj.hxx>
+#include <tools/diagnose_ex.h>
+
+using namespace ::com::sun::star;
+using namespace css::uno;
+using namespace css::script;
+using namespace css::frame;
+using namespace css::document;
+
+static void ShowErrorDialog( const Any& aException )
+{
+ ScopedVclPtrInstance<SvxScriptErrorDialog> pDlg( aException );
+ pDlg->Execute();
+}
+
+void SvxScriptOrgDialog::delUserData(const weld::TreeIter& rIter)
+{
+ SFEntry* pUserData = reinterpret_cast<SFEntry*>(m_xScriptsBox->get_id(rIter).toInt64());
+ if (pUserData)
+ {
+ delete pUserData;
+ // TBD seem to get a Select event on node that is remove ( below )
+ // so need to be able to detect that this node is not to be
+ // processed in order to do this, setting userData to NULL ( must
+ // be a better way to do this )
+ m_xScriptsBox->set_id(rIter, OUString());
+ }
+}
+
+void SvxScriptOrgDialog::deleteTree(weld::TreeIter& rIter)
+{
+ delUserData(rIter);
+ std::unique_ptr<weld::TreeIter> xIter = m_xScriptsBox->make_iterator(&rIter);
+ if (!m_xScriptsBox->iter_children(*xIter))
+ return;
+
+ std::unique_ptr<weld::TreeIter> xAltIter = m_xScriptsBox->make_iterator();
+ bool bNextEntry;
+ do
+ {
+ m_xScriptsBox->copy_iterator(*xIter, *xAltIter);
+ bNextEntry = m_xScriptsBox->iter_next_sibling(*xAltIter);
+ deleteTree(*xIter);
+ m_xScriptsBox->remove(*xIter);
+ m_xScriptsBox->copy_iterator(*xAltIter, *xIter);
+ }
+ while (bNextEntry);
+}
+
+void SvxScriptOrgDialog::deleteAllTree()
+{
+ std::unique_ptr<weld::TreeIter> xIter = m_xScriptsBox->make_iterator();
+ if (!m_xScriptsBox->get_iter_first(*xIter))
+ return;
+
+ std::unique_ptr<weld::TreeIter> xAltIter = m_xScriptsBox->make_iterator();
+ // TBD - below is a candidate for a destroyAllTrees method
+ bool bNextEntry;
+ do
+ {
+ m_xScriptsBox->copy_iterator(*xIter, *xAltIter);
+ bNextEntry = m_xScriptsBox->iter_next_sibling(*xAltIter);
+ deleteTree(*xIter);
+ m_xScriptsBox->remove(*xIter);
+ m_xScriptsBox->copy_iterator(*xAltIter, *xIter);
+ }
+ while (bNextEntry);
+}
+
+void SvxScriptOrgDialog::Init( const OUString& language )
+{
+ m_xScriptsBox->freeze();
+
+ deleteAllTree();
+
+ Reference< browse::XBrowseNode > rootNode;
+ Reference< XComponentContext > xCtx(
+ comphelper::getProcessComponentContext() );
+
+ Sequence< Reference< browse::XBrowseNode > > children;
+
+ OUString userStr("user");
+ OUString const shareStr("share");
+
+ try
+ {
+ Reference< browse::XBrowseNodeFactory > xFac = browse::theBrowseNodeFactory::get(xCtx);
+
+ rootNode.set( xFac->createView(
+ browse::BrowseNodeFactoryViewTypes::MACROORGANIZER ) );
+
+ if ( rootNode.is() && rootNode->hasChildNodes() )
+ {
+ children = rootNode->getChildNodes();
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("cui.dialogs", "Exception getting root browse node from factory");
+ // TODO exception handling
+ }
+
+ Reference<XModel> xDocumentModel;
+ for ( const Reference< browse::XBrowseNode >& childNode : std::as_const(children) )
+ {
+ bool app = false;
+ OUString uiName = childNode->getName();
+ OUString factoryURL;
+ if ( uiName == userStr || uiName == shareStr )
+ {
+ app = true;
+ if ( uiName == userStr )
+ {
+ uiName = m_sMyMacros;
+ }
+ else
+ {
+ uiName = m_sProdMacros;
+ }
+ }
+ else
+ {
+ xDocumentModel.set(getDocumentModel(xCtx, uiName ), UNO_QUERY);
+
+ if ( xDocumentModel.is() )
+ {
+ Reference< frame::XModuleManager2 > xModuleManager( frame::ModuleManager::create(xCtx) );
+
+ // get the long name of the document:
+ Sequence<beans::PropertyValue> moduleDescr;
+ try{
+ OUString appModule = xModuleManager->identify( xDocumentModel );
+ xModuleManager->getByName(appModule) >>= moduleDescr;
+ } catch(const uno::Exception&)
+ {}
+
+ for ( const beans::PropertyValue& prop : std::as_const(moduleDescr))
+ {
+ if ( prop.Name == "ooSetupFactoryEmptyDocumentURL" )
+ {
+ prop.Value >>= factoryURL;
+ break;
+ }
+ }
+ }
+ }
+
+ Reference< browse::XBrowseNode > langEntries =
+ getLangNodeFromRootNode( childNode, language );
+
+ insertEntry( uiName, app ? OUStringLiteral(RID_CUIBMP_HARDDISK) : OUStringLiteral(RID_CUIBMP_DOC),
+ nullptr, true, std::make_unique< SFEntry >( langEntries, xDocumentModel ), factoryURL, false );
+ }
+
+ m_xScriptsBox->thaw();
+}
+
+Reference< XInterface >
+SvxScriptOrgDialog::getDocumentModel( Reference< XComponentContext > const & xCtx, OUString const & docName )
+{
+ Reference< XInterface > xModel;
+ Reference< frame::XDesktop2 > desktop = frame::Desktop::create(xCtx);
+
+ Reference< container::XEnumerationAccess > componentsAccess =
+ desktop->getComponents();
+ Reference< container::XEnumeration > components =
+ componentsAccess->createEnumeration();
+ while (components->hasMoreElements())
+ {
+ Reference< frame::XModel > model(
+ components->nextElement(), UNO_QUERY );
+ if ( model.is() )
+ {
+ OUString sTdocUrl = ::comphelper::DocumentInfo::getDocumentTitle( model );
+ if( sTdocUrl == docName )
+ {
+ xModel = model;
+ break;
+ }
+ }
+ }
+ return xModel;
+}
+
+Reference< browse::XBrowseNode >
+SvxScriptOrgDialog::getLangNodeFromRootNode( Reference< browse::XBrowseNode > const & rootNode, OUString const & language )
+{
+ Reference< browse::XBrowseNode > langNode;
+
+ try
+ {
+ auto tryFind = [&] {
+ const Sequence<Reference<browse::XBrowseNode>> children = rootNode->getChildNodes();
+ const auto it = std::find_if(children.begin(), children.end(),
+ [&](const Reference<browse::XBrowseNode>& child) {
+ return child->getName() == language;
+ });
+ return (it != children.end()) ? *it : nullptr;
+ };
+ {
+ // First try without Java interaction, to avoid warnings for non-JRE-dependent providers
+ css::uno::ContextLayer layer(comphelper::NoEnableJavaInteractionContext());
+ langNode = tryFind();
+ }
+ if (!langNode)
+ {
+ // Now try with Java interaction enabled
+ langNode = tryFind();
+ }
+ }
+ catch ( Exception& )
+ {
+ // if getChildNodes() throws an exception we just return
+ // the empty Reference
+ }
+ return langNode;
+}
+
+void SvxScriptOrgDialog::RequestSubEntries(const weld::TreeIter& rRootEntry, Reference< css::script::browse::XBrowseNode > const & node,
+ Reference< XModel >& model)
+{
+ if (!node.is())
+ {
+ return;
+ }
+
+ Sequence< Reference< browse::XBrowseNode > > children;
+ try
+ {
+ children = node->getChildNodes();
+ }
+ catch ( Exception& )
+ {
+ // if we catch an exception in getChildNodes then no entries are added
+ }
+
+ for ( const Reference< browse::XBrowseNode >& childNode : std::as_const(children) )
+ {
+ OUString name( childNode->getName() );
+ if ( childNode->getType() != browse::BrowseNodeTypes::SCRIPT)
+ {
+ insertEntry(name, RID_CUIBMP_LIB, &rRootEntry, true, std::make_unique<SFEntry>(childNode, model), false);
+ }
+ else
+ {
+ insertEntry(name, RID_CUIBMP_MACRO, &rRootEntry, false, std::make_unique<SFEntry>(childNode, model), false);
+ }
+ }
+}
+
+void SvxScriptOrgDialog::insertEntry(const OUString& rText, const OUString& rBitmap,
+ const weld::TreeIter* pParent, bool bChildrenOnDemand, std::unique_ptr<SFEntry> && aUserData,
+ const OUString& factoryURL, bool bSelect)
+{
+ if (rBitmap == RID_CUIBMP_DOC && !factoryURL.isEmpty())
+ {
+ OUString aImage = SvFileInformationManager::GetFileImageId(INetURLObject(factoryURL));
+ insertEntry(rText, aImage, pParent, bChildrenOnDemand, std::move(aUserData), bSelect);
+ return;
+ }
+ insertEntry(rText, rBitmap, pParent, bChildrenOnDemand, std::move(aUserData), bSelect);
+}
+
+void SvxScriptOrgDialog::insertEntry(
+ const OUString& rText, const OUString& rBitmap, const weld::TreeIter* pParent,
+ bool bChildrenOnDemand, std::unique_ptr<SFEntry> && aUserData, bool bSelect)
+{
+ std::unique_ptr<weld::TreeIter> xRetIter;
+ if (bSelect)
+ xRetIter = m_xScriptsBox->make_iterator();
+ OUString sId(OUString::number(reinterpret_cast<sal_Int64>(aUserData.release()))); // XXX possible leak
+ m_xScriptsBox->insert(pParent, -1, &rText, &sId, nullptr, nullptr, &rBitmap,
+ bChildrenOnDemand, xRetIter.get());
+ if (bSelect)
+ {
+ m_xScriptsBox->set_cursor(*xRetIter);
+ m_xScriptsBox->select(*xRetIter);
+ }
+}
+
+IMPL_LINK(SvxScriptOrgDialog, ExpandingHdl, const weld::TreeIter&, rIter, bool)
+{
+ SFEntry* userData = reinterpret_cast<SFEntry*>(m_xScriptsBox->get_id(rIter).toInt64());
+
+ Reference< browse::XBrowseNode > node;
+ Reference< XModel > model;
+ if ( userData && !userData->isLoaded() )
+ {
+ node = userData->GetNode();
+ model = userData->GetModel();
+ RequestSubEntries(rIter, node, model);
+ userData->setLoaded();
+ }
+
+ return true;
+}
+
+// CuiInputDialog ------------------------------------------------------------
+CuiInputDialog::CuiInputDialog(weld::Window * pParent, InputDialogMode nMode)
+ : GenericDialogController(pParent, "cui/ui/newlibdialog.ui", "NewLibDialog")
+ , m_xEdit(m_xBuilder->weld_entry("entry"))
+{
+ m_xEdit->grab_focus();
+
+ std::unique_ptr<weld::Label> xNewLibFT(m_xBuilder->weld_label("newlibft"));
+
+ if ( nMode == InputDialogMode::NEWMACRO )
+ {
+ xNewLibFT->hide();
+ std::unique_ptr<weld::Label> xNewMacroFT(m_xBuilder->weld_label("newmacroft"));
+ xNewMacroFT->show();
+ std::unique_ptr<weld::Label> xAltTitle(m_xBuilder->weld_label("altmacrotitle"));
+ m_xDialog->set_title(xAltTitle->get_label());
+ }
+ else if ( nMode == InputDialogMode::RENAME )
+ {
+ xNewLibFT->hide();
+ std::unique_ptr<weld::Label> xRenameFT(m_xBuilder->weld_label("renameft"));
+ xRenameFT->show();
+ std::unique_ptr<weld::Label> xAltTitle(m_xBuilder->weld_label("altrenametitle"));
+ m_xDialog->set_title(xAltTitle->get_label());
+ }
+}
+
+// ScriptOrgDialog ------------------------------------------------------------
+
+SvxScriptOrgDialog::SvxScriptOrgDialog(weld::Window* pParent, const OUString& language)
+ : SfxDialogController(pParent, "cui/ui/scriptorganizer.ui", "ScriptOrganizerDialog")
+ , m_sLanguage(language)
+ , m_delErrStr(CuiResId(RID_SVXSTR_DELFAILED))
+ , m_delErrTitleStr(CuiResId(RID_SVXSTR_DELFAILED_TITLE))
+ , m_delQueryStr(CuiResId(RID_SVXSTR_DELQUERY))
+ , m_delQueryTitleStr(CuiResId(RID_SVXSTR_DELQUERY_TITLE))
+ , m_createErrStr(CuiResId(RID_SVXSTR_CREATEFAILED))
+ , m_createDupStr(CuiResId(RID_SVXSTR_CREATEFAILEDDUP))
+ , m_createErrTitleStr(CuiResId(RID_SVXSTR_CREATEFAILED_TITLE))
+ , m_renameErrStr(CuiResId(RID_SVXSTR_RENAMEFAILED))
+ , m_renameErrTitleStr(CuiResId(RID_SVXSTR_RENAMEFAILED_TITLE))
+ , m_sMyMacros(CuiResId(RID_SVXSTR_MYMACROS))
+ , m_sProdMacros(CuiResId(RID_SVXSTR_PRODMACROS))
+ , m_xScriptsBox(m_xBuilder->weld_tree_view("scripts"))
+ , m_xRunButton(m_xBuilder->weld_button("ok"))
+ , m_xCloseButton(m_xBuilder->weld_button("close"))
+ , m_xCreateButton(m_xBuilder->weld_button("create"))
+ , m_xEditButton(m_xBuilder->weld_button("edit"))
+ , m_xRenameButton(m_xBuilder->weld_button("rename"))
+ , m_xDelButton(m_xBuilder->weld_button("delete"))
+{
+ // must be a neater way to deal with the strings than as above
+ // append the language to the dialog title
+ OUString winTitle(m_xDialog->get_title());
+ winTitle = winTitle.replaceFirst( "%MACROLANG", m_sLanguage );
+ m_xDialog->set_title(winTitle);
+
+ m_xScriptsBox->set_size_request(m_xScriptsBox->get_approximate_digit_width() * 45,
+ m_xScriptsBox->get_height_rows(12));
+
+ m_xScriptsBox->connect_changed( LINK( this, SvxScriptOrgDialog, ScriptSelectHdl ) );
+ m_xScriptsBox->connect_expanding(LINK( this, SvxScriptOrgDialog, ExpandingHdl ) );
+ m_xRunButton->connect_clicked( LINK( this, SvxScriptOrgDialog, ButtonHdl ) );
+ m_xCloseButton->connect_clicked( LINK( this, SvxScriptOrgDialog, ButtonHdl ) );
+ m_xRenameButton->connect_clicked( LINK( this, SvxScriptOrgDialog, ButtonHdl ) );
+ m_xEditButton->connect_clicked( LINK( this, SvxScriptOrgDialog, ButtonHdl ) );
+ m_xDelButton->connect_clicked( LINK( this, SvxScriptOrgDialog, ButtonHdl ) );
+ m_xCreateButton->connect_clicked( LINK( this, SvxScriptOrgDialog, ButtonHdl ) );
+
+ m_xRunButton->set_sensitive(false);
+ m_xRenameButton->set_sensitive(false);
+ m_xEditButton->set_sensitive(false);
+ m_xDelButton->set_sensitive(false);
+ m_xCreateButton->set_sensitive(false);
+
+ Init(m_sLanguage);
+ RestorePreviousSelection();
+}
+
+SvxScriptOrgDialog::~SvxScriptOrgDialog()
+{
+ deleteAllTree();
+}
+
+short SvxScriptOrgDialog::run()
+{
+ SfxObjectShell *pDoc = SfxObjectShell::GetFirst();
+
+ // force load of MSPs for all documents
+ while ( pDoc )
+ {
+ Reference< provider::XScriptProviderSupplier > xSPS( pDoc->GetModel(), UNO_QUERY );
+ if ( xSPS.is() )
+ {
+ xSPS->getScriptProvider();
+ }
+
+ pDoc = SfxObjectShell::GetNext(*pDoc);
+ }
+
+ return SfxDialogController::run();
+}
+
+void SvxScriptOrgDialog::CheckButtons( Reference< browse::XBrowseNode > const & node )
+{
+ if ( node.is() )
+ {
+ if ( node->getType() == browse::BrowseNodeTypes::SCRIPT)
+ {
+ m_xRunButton->set_sensitive(true);
+ }
+ else
+ {
+ m_xRunButton->set_sensitive(false);
+ }
+ Reference< beans::XPropertySet > xProps( node, UNO_QUERY );
+
+ if ( !xProps.is() )
+ {
+ m_xEditButton->set_sensitive(false);
+ m_xDelButton->set_sensitive(false);
+ m_xCreateButton->set_sensitive(false);
+ m_xRunButton->set_sensitive(false);
+ return;
+ }
+
+ OUString sName("Editable");
+
+ if ( getBoolProperty( xProps, sName ) )
+ {
+ m_xEditButton->set_sensitive(true);
+ }
+ else
+ {
+ m_xEditButton->set_sensitive(false);
+ }
+
+ sName = "Deletable";
+
+ if ( getBoolProperty( xProps, sName ) )
+ {
+ m_xDelButton->set_sensitive(true);
+ }
+ else
+ {
+ m_xDelButton->set_sensitive(false);
+ }
+
+ sName = "Creatable";
+
+ if ( getBoolProperty( xProps, sName ) )
+ {
+ m_xCreateButton->set_sensitive(true);
+ }
+ else
+ {
+ m_xCreateButton->set_sensitive(false);
+ }
+
+ sName = "Renamable";
+
+ if ( getBoolProperty( xProps, sName ) )
+ {
+ m_xRenameButton->set_sensitive(true);
+ }
+ else
+ {
+ m_xRenameButton->set_sensitive(false);
+ }
+ }
+ else
+ {
+ // no node info available, disable all configurable actions
+ m_xDelButton->set_sensitive(false);
+ m_xCreateButton->set_sensitive(false);
+ m_xEditButton->set_sensitive(false);
+ m_xRunButton->set_sensitive(false);
+ m_xRenameButton->set_sensitive(false);
+ }
+}
+
+IMPL_LINK_NOARG(SvxScriptOrgDialog, ScriptSelectHdl, weld::TreeView&, void)
+{
+ std::unique_ptr<weld::TreeIter> xIter = m_xScriptsBox->make_iterator();
+ if (!m_xScriptsBox->get_selected(xIter.get()))
+ return;
+
+ SFEntry* userData = reinterpret_cast<SFEntry*>(m_xScriptsBox->get_id(*xIter).toInt64());
+
+ Reference< browse::XBrowseNode > node;
+ if (userData)
+ {
+ node = userData->GetNode();
+ CheckButtons(node);
+ }
+}
+
+IMPL_LINK(SvxScriptOrgDialog, ButtonHdl, weld::Button&, rButton, void)
+{
+ if ( &rButton == m_xCloseButton.get() )
+ {
+ StoreCurrentSelection();
+ m_xDialog->response(RET_CANCEL);
+ }
+ if (!(&rButton == m_xEditButton.get() ||
+ &rButton == m_xCreateButton.get() ||
+ &rButton == m_xDelButton.get() ||
+ &rButton == m_xRunButton.get() ||
+ &rButton == m_xRenameButton.get()))
+
+ return;
+
+ std::unique_ptr<weld::TreeIter> xIter = m_xScriptsBox->make_iterator();
+ if (!m_xScriptsBox->get_selected(xIter.get()))
+ return;
+ SFEntry* userData = reinterpret_cast<SFEntry*>(m_xScriptsBox->get_id(*xIter).toInt64());
+ if (!userData)
+ return;
+
+ Reference< browse::XBrowseNode > node;
+ Reference< XModel > xModel;
+
+ node = userData->GetNode();
+ xModel = userData->GetModel();
+
+ if ( !node.is() )
+ {
+ return;
+ }
+
+ if (&rButton == m_xRunButton.get())
+ {
+ OUString tmpString;
+ Reference< beans::XPropertySet > xProp( node, UNO_QUERY );
+ Reference< provider::XScriptProvider > mspNode;
+ if( !xProp.is() )
+ {
+ return;
+ }
+
+ if ( xModel.is() )
+ {
+ Reference< XEmbeddedScripts > xEmbeddedScripts( xModel, UNO_QUERY);
+ if( !xEmbeddedScripts.is() )
+ {
+ return;
+ }
+
+ if (!xEmbeddedScripts->getAllowMacroExecution())
+ {
+ // Please FIXME: Show a message box if AllowMacroExecution is false
+ return;
+ }
+ }
+
+ std::unique_ptr<weld::TreeIter> xParentIter = m_xScriptsBox->make_iterator(xIter.get());
+ bool bParent = m_xScriptsBox->iter_parent(*xParentIter);
+ while (bParent && !mspNode.is() )
+ {
+ SFEntry* mspUserData = reinterpret_cast<SFEntry*>(m_xScriptsBox->get_id(*xParentIter).toInt64());
+ mspNode.set( mspUserData->GetNode() , UNO_QUERY );
+ bParent = m_xScriptsBox->iter_parent(*xParentIter);
+ }
+ xProp->getPropertyValue("URI") >>= tmpString;
+ const OUString scriptURL( tmpString );
+
+ if ( mspNode.is() )
+ {
+ try
+ {
+ Reference< provider::XScript > xScript(
+ mspNode->getScript( scriptURL ), UNO_SET_THROW );
+
+ const Sequence< Any > args(0);
+ Sequence< sal_Int16 > outIndex;
+ Sequence< Any > outArgs( 0 );
+ xScript->invoke( args, outIndex, outArgs );
+ }
+ catch ( reflection::InvocationTargetException& ite )
+ {
+ ShowErrorDialog(css::uno::Any(ite));
+ }
+ catch ( provider::ScriptFrameworkErrorException& ite )
+ {
+ ShowErrorDialog(css::uno::Any(ite));
+ }
+ catch ( RuntimeException& re )
+ {
+ ShowErrorDialog(css::uno::Any(re));
+ }
+ catch ( Exception& e )
+ {
+ ShowErrorDialog(css::uno::Any(e));
+ }
+ }
+ StoreCurrentSelection();
+ m_xDialog->response(RET_CANCEL);
+ }
+ else if ( &rButton == m_xEditButton.get() )
+ {
+ Reference< script::XInvocation > xInv( node, UNO_QUERY );
+ if ( xInv.is() )
+ {
+ StoreCurrentSelection();
+ m_xDialog->response(RET_CANCEL);
+ Sequence< Any > args(0);
+ Sequence< Any > outArgs( 0 );
+ Sequence< sal_Int16 > outIndex;
+ try
+ {
+ // ISSUE need code to run script here
+ xInv->invoke( "Editable", args, outIndex, outArgs );
+ }
+ catch( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION("cui.dialogs", "Caught exception trying to invoke" );
+ }
+ }
+ }
+ else if ( &rButton == m_xCreateButton.get() )
+ {
+ createEntry(*xIter);
+ }
+ else if ( &rButton == m_xDelButton.get() )
+ {
+ deleteEntry(*xIter);
+ }
+ else if ( &rButton == m_xRenameButton.get() )
+ {
+ renameEntry(*xIter);
+ }
+}
+
+Reference< browse::XBrowseNode > SvxScriptOrgDialog::getBrowseNode(const weld::TreeIter& rEntry)
+{
+ Reference< browse::XBrowseNode > node;
+ SFEntry* userData = reinterpret_cast<SFEntry*>(m_xScriptsBox->get_id(rEntry).toInt64());
+ if (userData)
+ {
+ node = userData->GetNode();
+ }
+ return node;
+}
+
+Reference< XModel > SvxScriptOrgDialog::getModel(const weld::TreeIter& rEntry)
+{
+ Reference< XModel > model;
+ SFEntry* userData = reinterpret_cast<SFEntry*>(m_xScriptsBox->get_id(rEntry).toInt64());
+ if ( userData )
+ {
+ model = userData->GetModel();
+ }
+ return model;
+}
+
+void SvxScriptOrgDialog::createEntry(weld::TreeIter& rEntry)
+{
+
+ Reference< browse::XBrowseNode > aChildNode;
+ Reference< browse::XBrowseNode > node = getBrowseNode( rEntry );
+ Reference< script::XInvocation > xInv( node, UNO_QUERY );
+
+ if ( xInv.is() )
+ {
+ OUString aNewName;
+ OUString aNewStdName;
+ InputDialogMode nMode = InputDialogMode::NEWLIB;
+ if (m_xScriptsBox->get_iter_depth(rEntry) == 0)
+ {
+ aNewStdName = "Library" ;
+ }
+ else
+ {
+ aNewStdName = "Macro" ;
+ nMode = InputDialogMode::NEWMACRO;
+ }
+ //do we need L10N for this? ie something like:
+ //String aNewStdName( ResId( STR_STDMODULENAME ) );
+ bool bValid = false;
+ sal_Int32 i = 1;
+
+ Sequence< Reference< browse::XBrowseNode > > childNodes;
+ // no children => ok to create Parcel1 or Script1 without checking
+ try
+ {
+ if( !node->hasChildNodes() )
+ {
+ aNewName = aNewStdName + OUString::number(i);
+ bValid = true;
+ }
+ else
+ {
+ childNodes = node->getChildNodes();
+ }
+ }
+ catch ( Exception& )
+ {
+ // ignore, will continue on with empty sequence
+ }
+
+ OUString extn;
+ while ( !bValid )
+ {
+ aNewName = aNewStdName + OUString::number(i);
+ bool bFound = false;
+ if(childNodes.hasElements() )
+ {
+ OUString nodeName = childNodes[0]->getName();
+ sal_Int32 extnPos = nodeName.lastIndexOf( '.' );
+ if(extnPos>0)
+ extn = nodeName.copy(extnPos);
+ }
+ for( const Reference< browse::XBrowseNode >& n : std::as_const(childNodes) )
+ {
+ if (aNewName+extn == n->getName())
+ {
+ bFound = true;
+ break;
+ }
+ }
+ if( bFound )
+ {
+ i++;
+ }
+ else
+ {
+ bValid = true;
+ }
+ }
+
+ CuiInputDialog aNewDlg(m_xDialog.get(), nMode);
+ aNewDlg.SetObjectName(aNewName);
+
+ do
+ {
+ if (aNewDlg.run() && !aNewDlg.GetObjectName().isEmpty())
+ {
+ OUString aUserSuppliedName = aNewDlg.GetObjectName();
+ bValid = true;
+ for( const Reference< browse::XBrowseNode >& n : std::as_const(childNodes) )
+ {
+ if (aUserSuppliedName+extn == n->getName())
+ {
+ bValid = false;
+ OUString aError = m_createErrStr + m_createDupStr;
+
+ std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Warning, VclButtonsType::Ok, aError));
+ xErrorBox->set_title(m_createErrTitleStr);
+ xErrorBox->run();
+ aNewDlg.SetObjectName(aNewName);
+ break;
+ }
+ }
+ if( bValid )
+ aNewName = aUserSuppliedName;
+ }
+ else
+ {
+ // user hit cancel or hit OK with nothing in the editbox
+
+ return;
+ }
+ }
+ while ( !bValid );
+
+ // open up parent node (which ensures it's loaded)
+ m_xScriptsBox->expand_row(rEntry);
+
+ Sequence< Any > args( 1 );
+ args[ 0 ] <<= aNewName;
+ Sequence< Any > outArgs( 0 );
+ Sequence< sal_Int16 > outIndex;
+ try
+ {
+ Any aResult = xInv->invoke( "Creatable", args, outIndex, outArgs );
+ Reference< browse::XBrowseNode > newNode( aResult, UNO_QUERY );
+ aChildNode = newNode;
+
+ }
+ catch( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION("cui.dialogs", "Caught exception trying to Create" );
+ }
+ }
+ if ( aChildNode.is() )
+ {
+ OUString aChildName = aChildNode->getName();
+
+ Reference<XModel> xDocumentModel = getModel( rEntry );
+
+ // ISSUE do we need to remove all entries for parent
+ // to achieve sort? Just need to determine position
+ // -- Basic doesn't do this on create.
+ // Suppose we could avoid this too. -> created nodes are
+ // not in alphabetical order
+ if ( aChildNode->getType() == browse::BrowseNodeTypes::SCRIPT )
+ {
+ insertEntry(aChildName, RID_CUIBMP_MACRO, &rEntry, false,
+ std::make_unique<SFEntry>(aChildNode,xDocumentModel), true);
+ }
+ else
+ {
+ insertEntry(aChildName, RID_CUIBMP_LIB, &rEntry, false,
+ std::make_unique<SFEntry>(aChildNode,xDocumentModel), true);
+
+ // If the Parent is not loaded then set to
+ // loaded, this will prevent RequestingChildren ( called
+ // from vcl via RequestingChildren ) from
+ // creating new ( duplicate ) children
+ SFEntry* userData = reinterpret_cast<SFEntry*>(m_xScriptsBox->get_id(rEntry).toInt64());
+ if ( userData && !userData->isLoaded() )
+ {
+ userData->setLoaded();
+ }
+ }
+ }
+ else
+ {
+ //ISSUE L10N & message from exception?
+ OUString aError( m_createErrStr );
+ std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Warning, VclButtonsType::Ok, aError));
+ xErrorBox->set_title(m_createErrTitleStr);
+ xErrorBox->run();
+ }
+}
+
+void SvxScriptOrgDialog::renameEntry(const weld::TreeIter& rEntry)
+{
+
+ Reference< browse::XBrowseNode > aChildNode;
+ Reference< browse::XBrowseNode > node = getBrowseNode(rEntry);
+ Reference< script::XInvocation > xInv( node, UNO_QUERY );
+
+ if ( xInv.is() )
+ {
+ OUString aNewName = node->getName();
+ sal_Int32 extnPos = aNewName.lastIndexOf( '.' );
+ if(extnPos>0)
+ {
+ aNewName = aNewName.copy(0,extnPos);
+ }
+ CuiInputDialog aNewDlg(m_xDialog.get(), InputDialogMode::RENAME);
+ aNewDlg.SetObjectName(aNewName);
+
+ if (!aNewDlg.run() || aNewDlg.GetObjectName().isEmpty())
+ return; // user hit cancel or hit OK with nothing in the editbox
+
+ aNewName = aNewDlg.GetObjectName();
+
+ Sequence< Any > args( 1 );
+ args[ 0 ] <<= aNewName;
+ Sequence< Any > outArgs( 0 );
+ Sequence< sal_Int16 > outIndex;
+ try
+ {
+ Any aResult = xInv->invoke( "Renamable", args, outIndex, outArgs );
+ Reference< browse::XBrowseNode > newNode( aResult, UNO_QUERY );
+ aChildNode = newNode;
+
+ }
+ catch( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION("cui.dialogs", "Caught exception trying to Rename" );
+ }
+ }
+ if ( aChildNode.is() )
+ {
+ m_xScriptsBox->set_text(rEntry, aChildNode->getName());
+ m_xScriptsBox->set_cursor(rEntry);
+ m_xScriptsBox->select(rEntry);
+
+ }
+ else
+ {
+ //ISSUE L10N & message from exception?
+ OUString aError( m_renameErrStr );
+ std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Warning, VclButtonsType::Ok, aError));
+ xErrorBox->set_title(m_renameErrTitleStr);
+ xErrorBox->run();
+ }
+}
+
+void SvxScriptOrgDialog::deleteEntry(weld::TreeIter& rEntry)
+{
+ bool result = false;
+ Reference< browse::XBrowseNode > node = getBrowseNode(rEntry);
+ // ISSUE L10N string & can we center list?
+ OUString aQuery = m_delQueryStr + getListOfChildren( node, 0 );
+ std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Question, VclButtonsType::YesNo, aQuery));
+ xQueryBox->set_title(m_delQueryTitleStr);
+ if (xQueryBox->run() == RET_NO)
+ {
+ return;
+ }
+
+ Reference< script::XInvocation > xInv( node, UNO_QUERY );
+ if ( xInv.is() )
+ {
+ Sequence< Any > args( 0 );
+ Sequence< Any > outArgs( 0 );
+ Sequence< sal_Int16 > outIndex;
+ try
+ {
+ Any aResult = xInv->invoke( "Deletable", args, outIndex, outArgs );
+ aResult >>= result; // or do we just assume true if no exception ?
+ }
+ catch( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION("cui.dialogs", "Caught exception trying to delete" );
+ }
+ }
+
+ if ( result )
+ {
+ deleteTree(rEntry);
+ m_xScriptsBox->remove(rEntry);
+ }
+ else
+ {
+ //ISSUE L10N & message from exception?
+ std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Warning, VclButtonsType::Ok, m_delErrStr));
+ xErrorBox->set_title(m_delErrTitleStr);
+ xErrorBox->run();
+ }
+
+}
+
+bool SvxScriptOrgDialog::getBoolProperty( Reference< beans::XPropertySet > const & xProps,
+ OUString const & propName )
+{
+ bool result = false;
+ try
+ {
+ xProps->getPropertyValue( propName ) >>= result;
+ }
+ catch ( Exception& )
+ {
+ return result;
+ }
+ return result;
+}
+
+OUString SvxScriptOrgDialog::getListOfChildren( const Reference< browse::XBrowseNode >& node, int depth )
+{
+ OUStringBuffer result = "\n";
+ for( int i=0;i<=depth;i++ )
+ {
+ result.append("\t");
+ }
+ result.append(node->getName());
+
+ try
+ {
+ if ( node->hasChildNodes() )
+ {
+ const Sequence< Reference< browse::XBrowseNode > > children
+ = node->getChildNodes();
+ for( const Reference< browse::XBrowseNode >& n : children )
+ {
+ result.append( getListOfChildren( n , depth+1 ) );
+ }
+ }
+ }
+ catch ( Exception& )
+ {
+ // ignore, will return an empty string
+ }
+
+ return result.makeStringAndClear();
+}
+
+Selection_hash SvxScriptOrgDialog::m_lastSelection;
+
+void SvxScriptOrgDialog::StoreCurrentSelection()
+{
+ std::unique_ptr<weld::TreeIter> xIter = m_xScriptsBox->make_iterator();
+ if (!m_xScriptsBox->get_selected(xIter.get()))
+ return;
+ OUString aDescription;
+ bool bEntry;
+ do
+ {
+ aDescription = m_xScriptsBox->get_text(*xIter) + aDescription;
+ bEntry = m_xScriptsBox->iter_parent(*xIter);
+ if (bEntry)
+ aDescription = ";" + aDescription;
+ }
+ while (bEntry);
+ OUString sDesc( aDescription );
+ m_lastSelection[ m_sLanguage ] = sDesc;
+}
+
+void SvxScriptOrgDialog::RestorePreviousSelection()
+{
+ OUString aStoredEntry = m_lastSelection[ m_sLanguage ];
+ if( aStoredEntry.isEmpty() )
+ return;
+ std::unique_ptr<weld::TreeIter> xEntry;
+ std::unique_ptr<weld::TreeIter> xTmpEntry(m_xScriptsBox->make_iterator());
+ sal_Int32 nIndex = 0;
+ while (nIndex != -1)
+ {
+ OUString aTmp( aStoredEntry.getToken( 0, ';', nIndex ) );
+
+ bool bTmpEntry;
+ if (!xEntry)
+ {
+ xEntry = m_xScriptsBox->make_iterator();
+ bTmpEntry = m_xScriptsBox->get_iter_first(*xEntry);
+ m_xScriptsBox->copy_iterator(*xEntry, *xTmpEntry);
+ }
+ else
+ {
+ m_xScriptsBox->copy_iterator(*xEntry, *xTmpEntry);
+ bTmpEntry = m_xScriptsBox->iter_children(*xTmpEntry);
+ }
+
+ while (bTmpEntry)
+ {
+ if (m_xScriptsBox->get_text(*xTmpEntry) == aTmp)
+ {
+ m_xScriptsBox->copy_iterator(*xTmpEntry, *xEntry);
+ break;
+ }
+ bTmpEntry = m_xScriptsBox->iter_next_sibling(*xTmpEntry);
+ }
+
+ if (!bTmpEntry)
+ break;
+
+ m_xScriptsBox->expand_row(*xEntry);
+ }
+
+ if (xEntry)
+ m_xScriptsBox->set_cursor(*xEntry);
+}
+
+namespace {
+
+OUString ReplaceString(
+ const OUString& source,
+ const OUString& token,
+ const OUString& value )
+{
+ sal_Int32 pos = source.indexOf( token );
+
+ if ( pos != -1 && !value.isEmpty() )
+ {
+ return source.replaceAt( pos, token.getLength(), value );
+ }
+ else
+ {
+ return source;
+ }
+}
+
+OUString FormatErrorString(
+ const OUString& unformatted,
+ const OUString& language,
+ const OUString& script,
+ const OUString& line,
+ const OUString& type,
+ const OUString& message )
+{
+ OUString result = unformatted.copy( 0 );
+
+ result = ReplaceString(result, "%LANGUAGENAME", language );
+ result = ReplaceString(result, "%SCRIPTNAME", script );
+ result = ReplaceString(result, "%LINENUMBER", line );
+
+ if ( !type.isEmpty() )
+ {
+ result += "\n\n" + CuiResId(RID_SVXSTR_ERROR_TYPE_LABEL) + " " + type;
+ }
+
+ if ( !message.isEmpty() )
+ {
+ result += "\n\n" + CuiResId(RID_SVXSTR_ERROR_MESSAGE_LABEL) + " " + message;
+ }
+
+ return result;
+}
+
+OUString GetErrorMessage(
+ const provider::ScriptErrorRaisedException& eScriptError )
+{
+ OUString unformatted = CuiResId( RID_SVXSTR_ERROR_AT_LINE );
+
+ OUString unknown("UNKNOWN");
+ OUString language = unknown;
+ OUString script = unknown;
+ OUString line = unknown;
+ OUString type = "";
+ OUString message = eScriptError.Message;
+
+ if ( !eScriptError.language.isEmpty() )
+ {
+ language = eScriptError.language;
+ }
+
+ if ( !eScriptError.scriptName.isEmpty() )
+ {
+ script = eScriptError.scriptName;
+ }
+
+ if ( !eScriptError.Message.isEmpty() )
+ {
+ message = eScriptError.Message;
+ }
+ if ( eScriptError.lineNum != -1 )
+ {
+ line = OUString::number( eScriptError.lineNum );
+ unformatted = CuiResId( RID_SVXSTR_ERROR_AT_LINE );
+ }
+ else
+ {
+ unformatted = CuiResId( RID_SVXSTR_ERROR_RUNNING );
+ }
+
+ return FormatErrorString(
+ unformatted, language, script, line, type, message );
+}
+
+OUString GetErrorMessage(
+ const provider::ScriptExceptionRaisedException& eScriptException )
+{
+ OUString unformatted = CuiResId( RID_SVXSTR_EXCEPTION_AT_LINE );
+
+ OUString unknown("UNKNOWN");
+ OUString language = unknown;
+ OUString script = unknown;
+ OUString line = unknown;
+ OUString type = unknown;
+ OUString message = eScriptException.Message;
+
+ if ( !eScriptException.language.isEmpty() )
+ {
+ language = eScriptException.language;
+ }
+ if ( !eScriptException.scriptName.isEmpty() )
+ {
+ script = eScriptException.scriptName;
+ }
+
+ if ( !eScriptException.Message.isEmpty() )
+ {
+ message = eScriptException.Message;
+ }
+
+ if ( eScriptException.lineNum != -1 )
+ {
+ line = OUString::number( eScriptException.lineNum );
+ unformatted = CuiResId( RID_SVXSTR_EXCEPTION_AT_LINE );
+ }
+ else
+ {
+ unformatted = CuiResId( RID_SVXSTR_EXCEPTION_RUNNING );
+ }
+
+ if ( !eScriptException.exceptionType.isEmpty() )
+ {
+ type = eScriptException.exceptionType;
+ }
+
+ return FormatErrorString(
+ unformatted, language, script, line, type, message );
+
+}
+OUString GetErrorMessage(
+ const provider::ScriptFrameworkErrorException& sError )
+{
+ OUString unformatted = CuiResId( RID_SVXSTR_FRAMEWORK_ERROR_RUNNING );
+
+ OUString language("UNKNOWN");
+
+ OUString script("UNKNOWN");
+
+ OUString message;
+
+ if ( !sError.scriptName.isEmpty() )
+ {
+ script = sError.scriptName;
+ }
+ if ( !sError.language.isEmpty() )
+ {
+ language = sError.language;
+ }
+ if ( sError.errorType == provider::ScriptFrameworkErrorType::NOTSUPPORTED )
+ {
+ message =
+ CuiResId( RID_SVXSTR_ERROR_LANG_NOT_SUPPORTED );
+ message = ReplaceString(message, "%LANGUAGENAME", language );
+
+ }
+ else
+ {
+ message = sError.Message;
+ }
+ return FormatErrorString(
+ unformatted, language, script, OUString(), OUString(), message );
+}
+
+OUString GetErrorMessage( const css::uno::Any& aException )
+{
+ if ( aException.getValueType() ==
+ cppu::UnoType<reflection::InvocationTargetException>::get())
+ {
+ reflection::InvocationTargetException ite;
+ aException >>= ite;
+ if ( ite.TargetException.getValueType() == cppu::UnoType<provider::ScriptErrorRaisedException>::get())
+ {
+ // Error raised by script
+ provider::ScriptErrorRaisedException scriptError;
+ ite.TargetException >>= scriptError;
+ return GetErrorMessage( scriptError );
+ }
+ else if ( ite.TargetException.getValueType() == cppu::UnoType<provider::ScriptExceptionRaisedException>::get())
+ {
+ // Exception raised by script
+ provider::ScriptExceptionRaisedException scriptException;
+ ite.TargetException >>= scriptException;
+ return GetErrorMessage( scriptException );
+ }
+ else
+ {
+ // Unknown error, shouldn't happen
+ // OSL_ASSERT(...)
+ }
+
+ }
+ else if ( aException.getValueType() == cppu::UnoType<provider::ScriptFrameworkErrorException>::get())
+ {
+ // A Script Framework error has occurred
+ provider::ScriptFrameworkErrorException sfe;
+ aException >>= sfe;
+ return GetErrorMessage( sfe );
+
+ }
+ // unknown exception
+ auto msg = aException.getValueTypeName();
+ Exception e;
+ if ( (aException >>= e) && !e.Message.isEmpty() )
+ {
+ msg += ": " + e.Message;
+ }
+ return msg;
+}
+
+}
+
+SvxScriptErrorDialog::SvxScriptErrorDialog( css::uno::Any const & aException )
+ : m_sMessage()
+{
+ SolarMutexGuard aGuard;
+ m_sMessage = GetErrorMessage( aException );
+}
+
+SvxScriptErrorDialog::~SvxScriptErrorDialog()
+{
+}
+
+short SvxScriptErrorDialog::Execute()
+{
+ // Show Error dialog asynchronously
+
+ // Pass a copy of the message to the ShowDialog method as the
+ // SvxScriptErrorDialog may be deleted before ShowDialog is called
+ Application::PostUserEvent(
+ LINK( this, SvxScriptErrorDialog, ShowDialog ),
+ new OUString( m_sMessage ) );
+
+ return 0;
+}
+
+IMPL_STATIC_LINK( SvxScriptErrorDialog, ShowDialog, void*, p, void )
+{
+ OUString* pMessage = static_cast<OUString*>(p);
+ OUString message;
+
+ if ( pMessage && !pMessage->isEmpty() )
+ {
+ message = *pMessage;
+ }
+ else
+ {
+ message = CuiResId( RID_SVXSTR_ERROR_TITLE );
+ }
+
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
+ VclMessageType::Warning, VclButtonsType::Ok, message));
+ xBox->set_title(CuiResId(RID_SVXSTR_ERROR_TITLE));
+ xBox->run();
+
+ delete pMessage;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/dialogs/sdrcelldlg.cxx b/cui/source/dialogs/sdrcelldlg.cxx
new file mode 100644
index 000000000..3c745692f
--- /dev/null
+++ b/cui/source/dialogs/sdrcelldlg.cxx
@@ -0,0 +1,62 @@
+/* -*- 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 <sdrcelldlg.hxx>
+#include <cuitabarea.hxx>
+#include <svx/svdmodel.hxx>
+#include <border.hxx>
+#include <svx/dialogs.hrc>
+
+SvxFormatCellsDialog::SvxFormatCellsDialog(weld::Window* pParent, const SfxItemSet* pAttr, const SdrModel& rModel)
+ : SfxTabDialogController(pParent, "cui/ui/formatcellsdialog.ui", "FormatCellsDialog", pAttr)
+ , mrOutAttrs(*pAttr)
+ , mpColorTab(rModel.GetColorList())
+ , mpGradientList(rModel.GetGradientList())
+ , mpHatchingList(rModel.GetHatchList())
+ , mpBitmapList(rModel.GetBitmapList())
+ , mpPatternList(rModel.GetPatternList())
+{
+ AddTabPage("name", RID_SVXPAGE_CHAR_NAME);
+ AddTabPage("effects", RID_SVXPAGE_CHAR_EFFECTS);
+ AddTabPage("border", RID_SVXPAGE_BORDER );
+ AddTabPage("area", RID_SVXPAGE_AREA);
+}
+
+void SvxFormatCellsDialog::PageCreated(const OString& rId, SfxTabPage &rPage)
+{
+ if (rId == "area")
+ {
+ SvxAreaTabPage& rAreaPage = static_cast<SvxAreaTabPage&>(rPage);
+ rAreaPage.SetColorList( mpColorTab );
+ rAreaPage.SetGradientList( mpGradientList );
+ rAreaPage.SetHatchingList( mpHatchingList );
+ rAreaPage.SetBitmapList( mpBitmapList );
+ rAreaPage.SetPatternList( mpPatternList );
+ rAreaPage.ActivatePage( mrOutAttrs );
+ }
+ else if (rId == "border")
+ {
+ SvxBorderTabPage& rBorderPage = static_cast<SvxBorderTabPage&>(rPage);
+ rBorderPage.SetTableMode();
+ }
+ else
+ SfxTabDialogController::PageCreated(rId, rPage);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/dialogs/showcols.cxx b/cui/source/dialogs/showcols.cxx
new file mode 100644
index 000000000..895ed485e
--- /dev/null
+++ b/cui/source/dialogs/showcols.cxx
@@ -0,0 +1,107 @@
+/* -*- 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 <showcols.hxx>
+
+#include <osl/diagnose.h>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <comphelper/types.hxx>
+#include <tools/debug.hxx>
+
+#define CUIFM_PROP_HIDDEN "Hidden"
+#define CUIFM_PROP_LABEL "Label"
+
+FmShowColsDialog::FmShowColsDialog(weld::Window* pParent)
+ : GenericDialogController(pParent, "cui/ui/showcoldialog.ui", "ShowColDialog")
+ , m_xList(m_xBuilder->weld_tree_view("treeview"))
+ , m_xOK(m_xBuilder->weld_button("ok"))
+{
+ m_xList->set_size_request(m_xList->get_approximate_digit_width() * 40, m_xList->get_height_rows(8));
+ m_xList->set_selection_mode(SelectionMode::Multiple);
+ m_xOK->connect_clicked(LINK(this, FmShowColsDialog, OnClickedOk));
+}
+
+FmShowColsDialog::~FmShowColsDialog()
+{
+}
+
+IMPL_LINK_NOARG(FmShowColsDialog, OnClickedOk, weld::Button&, void)
+{
+ DBG_ASSERT(m_xColumns.is(), "FmShowColsDialog::OnClickedOk : you should call SetColumns before executing the dialog !");
+ if (m_xColumns.is())
+ {
+ css::uno::Reference< css::beans::XPropertySet > xCol;
+ auto nSelectedRows = m_xList->get_selected_rows();
+ for (auto i : nSelectedRows)
+ {
+ m_xColumns->getByIndex(m_xList->get_id(i).toInt32()) >>= xCol;
+ if (xCol.is())
+ {
+ try
+ {
+ xCol->setPropertyValue(CUIFM_PROP_HIDDEN, css::uno::Any(false));
+ }
+ catch(...)
+ {
+ OSL_FAIL("FmShowColsDialog::OnClickedOk Exception occurred!");
+ }
+ }
+ }
+ }
+
+ m_xDialog->response(RET_OK);
+}
+
+void FmShowColsDialog::SetColumns(const css::uno::Reference< css::container::XIndexContainer>& xCols)
+{
+ DBG_ASSERT(xCols.is(), "FmShowColsDialog::SetColumns : invalid columns !");
+ if (!xCols.is())
+ return;
+ m_xColumns = xCols.get();
+
+ m_xList->clear();
+
+ css::uno::Reference< css::beans::XPropertySet> xCurCol;
+ OUString sCurName;
+ for (sal_Int32 i=0; i<xCols->getCount(); ++i)
+ {
+ sCurName.clear();
+ xCurCol.set(xCols->getByIndex(i), css::uno::UNO_QUERY);
+ bool bIsHidden = false;
+ try
+ {
+ css::uno::Any aHidden = xCurCol->getPropertyValue(CUIFM_PROP_HIDDEN);
+ bIsHidden = ::comphelper::getBOOL(aHidden);
+
+ OUString sName;
+ xCurCol->getPropertyValue(CUIFM_PROP_LABEL) >>= sName;
+ sCurName = sName;
+ }
+ catch(...)
+ {
+ OSL_FAIL("FmShowColsDialog::SetColumns Exception occurred!");
+ }
+
+ // if the col is hidden, put it into the list
+ if (bIsHidden)
+ m_xList->append(OUString::number(i), sCurName);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/dialogs/splitcelldlg.cxx b/cui/source/dialogs/splitcelldlg.cxx
new file mode 100644
index 000000000..40b798b7c
--- /dev/null
+++ b/cui/source/dialogs/splitcelldlg.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 <splitcelldlg.hxx>
+
+SvxSplitTableDlg::SvxSplitTableDlg(weld::Window *pParent, bool bIsTableVertical, long nMaxVertical, long nMaxHorizontal)
+ : GenericDialogController(pParent, "cui/ui/splitcellsdialog.ui", "SplitCellsDialog")
+ , m_xCountEdit(m_xBuilder->weld_spin_button("countnf"))
+ , m_xHorzBox(!bIsTableVertical ? m_xBuilder->weld_radio_button("hori") : m_xBuilder->weld_radio_button("vert"))
+ , m_xVertBox(!bIsTableVertical ? m_xBuilder->weld_radio_button("vert") : m_xBuilder->weld_radio_button("hori"))
+ , m_xPropCB(m_xBuilder->weld_check_button("prop"))
+ , mnMaxVertical(nMaxVertical)
+ , mnMaxHorizontal(nMaxHorizontal)
+{
+ m_xHorzBox->connect_clicked(LINK(this, SvxSplitTableDlg, ClickHdl));
+ m_xPropCB->connect_clicked(LINK(this, SvxSplitTableDlg, ClickHdl));
+ m_xVertBox->connect_clicked(LINK(this, SvxSplitTableDlg, ClickHdl));
+
+ if (mnMaxVertical < 2)
+ {
+ if (!bIsTableVertical)
+ m_xVertBox->set_sensitive(false);
+ else
+ m_xHorzBox->set_sensitive(false);
+ }
+
+ //exchange the meaning of horizontal and vertical for vertical text
+ if (bIsTableVertical)
+ {
+ int nHorzTopAttach = m_xHorzBox->get_grid_top_attach();
+ int nVertTopAttach = m_xVertBox->get_grid_top_attach();
+ m_xHorzBox->set_grid_top_attach(nVertTopAttach);
+ m_xVertBox->set_grid_top_attach(nHorzTopAttach);
+ m_xHorzBox->set_active(m_xVertBox->get_active());
+ }
+}
+
+IMPL_LINK(SvxSplitTableDlg, ClickHdl, weld::Button&, rButton, void)
+{
+ const bool bIsVert = &rButton == m_xVertBox.get();
+ long nMax = bIsVert ? mnMaxVertical : mnMaxHorizontal;
+ m_xPropCB->set_sensitive(!bIsVert);
+ m_xCountEdit->set_max(nMax);
+}
+
+bool SvxSplitTableDlg::IsHorizontal() const
+{
+ return m_xHorzBox->get_active();
+}
+
+bool SvxSplitTableDlg::IsProportional() const
+{
+ return m_xPropCB->get_active() && m_xHorzBox->get_active();
+}
+
+long SvxSplitTableDlg::GetCount() const
+{
+ return m_xCountEdit->get_value();
+}
+
+short SvxSplitTableDlg::Execute()
+{
+ return run();
+}
+
+void SvxSplitTableDlg::SetSplitVerticalByDefault()
+{
+ if( mnMaxVertical >= 2 )
+ m_xVertBox->set_active(true); // tdf#60242
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/dialogs/srchxtra.cxx b/cui/source/dialogs/srchxtra.cxx
new file mode 100644
index 000000000..2a68293f0
--- /dev/null
+++ b/cui/source/dialogs/srchxtra.cxx
@@ -0,0 +1,235 @@
+/* -*- 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 <srchxtra.hxx>
+#include <sal/log.hxx>
+#include <svl/cjkoptions.hxx>
+#include <svl/intitem.hxx>
+#include <svl/whiter.hxx>
+#include <sfx2/objsh.hxx>
+#include <svx/flagsdef.hxx>
+#include <svx/strarray.hxx>
+#include <editeng/flstitem.hxx>
+#include <chardlg.hxx>
+#include <paragrph.hxx>
+#include <backgrnd.hxx>
+#include <editeng/editids.hrc>
+#include <svx/svxids.hrc>
+#include <tools/debug.hxx>
+#include <tools/resary.hxx>
+#include <vcl/svapp.hxx>
+
+SvxSearchFormatDialog::SvxSearchFormatDialog(weld::Window* pParent, const SfxItemSet& rSet)
+ : SfxTabDialogController(pParent, "cui/ui/searchformatdialog.ui", "SearchFormatDialog", &rSet)
+{
+ AddTabPage("font", SvxCharNamePage::Create, nullptr);
+ AddTabPage("fonteffects", SvxCharEffectsPage::Create, nullptr);
+ AddTabPage("position", SvxCharPositionPage::Create, nullptr);
+ AddTabPage("asianlayout", SvxCharTwoLinesPage::Create, nullptr);
+ AddTabPage("labelTP_PARA_STD", SvxStdParagraphTabPage::Create, nullptr);
+ AddTabPage("labelTP_PARA_ALIGN", SvxParaAlignTabPage::Create, nullptr);
+ AddTabPage("labelTP_PARA_EXT", SvxExtParagraphTabPage::Create, nullptr);
+ AddTabPage("labelTP_PARA_ASIAN", SvxAsianTabPage::Create, nullptr );
+ AddTabPage("background", SvxBkgTabPage::Create, nullptr);
+
+ // remove asian tabpages if necessary
+ SvtCJKOptions aCJKOptions;
+ if ( !aCJKOptions.IsDoubleLinesEnabled() )
+ RemoveTabPage("asianlayout");
+ if ( !aCJKOptions.IsAsianTypographyEnabled() )
+ RemoveTabPage("labelTP_PARA_ASIAN");
+}
+
+SvxSearchFormatDialog::~SvxSearchFormatDialog()
+{
+}
+
+void SvxSearchFormatDialog::PageCreated(const OString& rId, SfxTabPage& rPage)
+{
+ if (rId == "font")
+ {
+ const FontList* pApm_pFontList = nullptr;
+ SfxObjectShell* pSh = SfxObjectShell::Current();
+
+ if ( pSh )
+ {
+ const SvxFontListItem* pFLItem = static_cast<const SvxFontListItem*>(
+ pSh->GetItem( SID_ATTR_CHAR_FONTLIST ));
+ if ( pFLItem )
+ pApm_pFontList = pFLItem->GetFontList();
+ }
+
+ const FontList* pList = pApm_pFontList;
+
+ if ( !pList )
+ {
+ if ( !m_pFontList )
+ m_pFontList.reset(new FontList(Application::GetDefaultDevice()));
+ pList = m_pFontList.get();
+ }
+
+ static_cast<SvxCharNamePage&>(rPage).
+ SetFontList( SvxFontListItem( pList, SID_ATTR_CHAR_FONTLIST ) );
+ static_cast<SvxCharNamePage&>(rPage).EnableSearchMode();
+ }
+ else if (rId == "labelTP_PARA_STD")
+ {
+ static_cast<SvxStdParagraphTabPage&>(rPage).EnableAutoFirstLine();
+ }
+ else if (rId == "labelTP_PARA_ALIGN")
+ {
+ static_cast<SvxParaAlignTabPage&>(rPage).EnableJustifyExt();
+ }
+ else if (rId == "background")
+ {
+ SfxAllItemSet aSet(*(GetInputSetImpl()->GetPool()));
+ aSet.Put(SfxUInt32Item(SID_FLAG_TYPE,static_cast<sal_uInt32>(SvxBackgroundTabFlags::SHOW_HIGHLIGHTING)));
+ rPage.PageCreated(aSet);
+ }
+}
+
+SvxSearchAttributeDialog::SvxSearchAttributeDialog(weld::Window* pParent,
+ SearchAttrItemList& rLst, const sal_uInt16* pWhRanges)
+ : GenericDialogController(pParent, "cui/ui/searchattrdialog.ui", "SearchAttrDialog")
+ , rList(rLst)
+ , m_xAttrLB(m_xBuilder->weld_tree_view("treeview"))
+ , m_xOKBtn(m_xBuilder->weld_button("ok"))
+{
+ m_xAttrLB->set_size_request(m_xAttrLB->get_approximate_digit_width() * 50,
+ m_xAttrLB->get_height_rows(12));
+
+ std::vector<int> aWidths;
+ aWidths.push_back(m_xAttrLB->get_checkbox_column_width());
+ m_xAttrLB->set_column_fixed_widths(aWidths);
+
+ m_xOKBtn->connect_clicked(LINK( this, SvxSearchAttributeDialog, OKHdl));
+
+ SfxObjectShell* pSh = SfxObjectShell::Current();
+ DBG_ASSERT( pSh, "No DocShell" );
+
+ SfxItemPool& rPool = pSh->GetPool();
+ SfxItemSet aSet( rPool, pWhRanges );
+ SfxWhichIter aIter( aSet );
+ sal_uInt16 nWhich = aIter.FirstWhich();
+
+ while ( nWhich )
+ {
+ sal_uInt16 nSlot = rPool.GetSlotId( nWhich );
+ if ( nSlot >= SID_SVX_START )
+ {
+ bool bChecked = false, bFound = false;
+ for ( sal_uInt16 i = 0; !bFound && i < rList.Count(); ++i )
+ {
+ if ( nSlot == rList[i].nSlot )
+ {
+ bFound = true;
+ if ( IsInvalidItem( rList[i].pItem ) )
+ bChecked = true;
+ }
+ }
+
+ // item resources are in svx
+ sal_uInt32 nId = SvxAttrNameTable::FindIndex(nSlot);
+ if (RESARRAY_INDEX_NOTFOUND != nId)
+ {
+ m_xAttrLB->append();
+ const int nRow = m_xAttrLB->n_children() - 1;
+ m_xAttrLB->set_toggle(nRow, bChecked ? TRISTATE_TRUE : TRISTATE_FALSE, 0);
+ m_xAttrLB->set_text(nRow, SvxAttrNameTable::GetString(nId), 1);
+ m_xAttrLB->set_id(nRow, OUString::number(nSlot));
+ }
+ else
+ SAL_WARN( "cui.dialogs", "no resource for slot id " << static_cast<sal_Int32>(nSlot) );
+ }
+ nWhich = aIter.NextWhich();
+ }
+
+ m_xAttrLB->make_sorted();
+ m_xAttrLB->select(0);
+}
+
+SvxSearchAttributeDialog::~SvxSearchAttributeDialog()
+{
+}
+
+IMPL_LINK_NOARG(SvxSearchAttributeDialog, OKHdl, weld::Button&, void)
+{
+ SearchAttrItem aInvalidItem;
+ aInvalidItem.pItem = INVALID_POOL_ITEM;
+
+ for (int i = 0, nCount = m_xAttrLB->n_children(); i < nCount; ++i)
+ {
+ sal_uInt16 nSlot = m_xAttrLB->get_id(i).toUInt32();
+ bool bChecked = m_xAttrLB->get_toggle(i, 0) == TRISTATE_TRUE;
+
+ sal_uInt16 j;
+ for ( j = rList.Count(); j; )
+ {
+ SearchAttrItem& rItem = rList[ --j ];
+ if( rItem.nSlot == nSlot )
+ {
+ if( bChecked )
+ {
+ if( !IsInvalidItem( rItem.pItem ) )
+ delete rItem.pItem;
+ rItem.pItem = INVALID_POOL_ITEM;
+ }
+ else if( IsInvalidItem( rItem.pItem ) )
+ rItem.pItem = nullptr;
+ j = 1;
+ break;
+ }
+ }
+
+ if ( !j && bChecked )
+ {
+ aInvalidItem.nSlot = nSlot;
+ rList.Insert( aInvalidItem );
+ }
+ }
+
+ // remove invalid items (pItem == NULL)
+ for ( sal_uInt16 n = rList.Count(); n; )
+ if ( !rList[ --n ].pItem )
+ rList.Remove( n );
+
+ m_xDialog->response(RET_OK);
+}
+
+// class SvxSearchSimilarityDialog ---------------------------------------
+
+SvxSearchSimilarityDialog::SvxSearchSimilarityDialog(weld::Window* pParent, bool bRelax,
+ sal_uInt16 nOther, sal_uInt16 nShorter, sal_uInt16 nLonger)
+ : GenericDialogController(pParent, "cui/ui/similaritysearchdialog.ui", "SimilaritySearchDialog")
+ , m_xOtherFld(m_xBuilder->weld_spin_button("otherfld"))
+ , m_xLongerFld(m_xBuilder->weld_spin_button("longerfld"))
+ , m_xShorterFld(m_xBuilder->weld_spin_button("shorterfld"))
+ , m_xRelaxBox(m_xBuilder->weld_check_button("relaxbox"))
+{
+ m_xOtherFld->set_value(nOther);
+ m_xShorterFld->set_value(nShorter);
+ m_xLongerFld->set_value(nLonger);
+ m_xRelaxBox->set_active(bRelax);
+}
+
+SvxSearchSimilarityDialog::~SvxSearchSimilarityDialog()
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/dialogs/thesdlg.cxx b/cui/source/dialogs/thesdlg.cxx
new file mode 100644
index 000000000..612f5fe01
--- /dev/null
+++ b/cui/source/dialogs/thesdlg.cxx
@@ -0,0 +1,343 @@
+/* -*- 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 <thesdlg.hxx>
+
+#include <tools/debug.hxx>
+#include <svl/lngmisc.hxx>
+#include <vcl/event.hxx>
+#include <vcl/svapp.hxx>
+#include <svtools/langtab.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <comphelper/string.hxx>
+
+#include <stack>
+#include <algorithm>
+
+#include <com/sun/star/linguistic2/XThesaurus.hpp>
+#include <com/sun/star/linguistic2/XMeaning.hpp>
+
+using namespace ::com::sun::star;
+
+IMPL_LINK_NOARG( SvxThesaurusDialog, ModifyTimer_Hdl, Timer *, void )
+{
+ LookUp(m_xWordCB->get_active_text());
+ m_aModifyIdle.Stop();
+}
+
+IMPL_LINK_NOARG(SvxThesaurusDialog, ReplaceEditHdl_Impl, weld::Entry&, void)
+{
+ m_xReplaceBtn->set_sensitive(!m_xReplaceEdit->get_text().isEmpty());
+}
+
+IMPL_LINK(SvxThesaurusDialog, KeyInputHdl, const KeyEvent&, rKEvt, bool)
+{
+ const vcl::KeyCode& rKey = rKEvt.GetKeyCode();
+
+ if (rKey.GetCode() == KEY_RETURN)
+ {
+ m_xDialog->response(RET_OK);
+ return true;
+ }
+
+ return false;
+}
+
+uno::Sequence< uno::Reference< linguistic2::XMeaning > > SvxThesaurusDialog::queryMeanings_Impl(
+ OUString& rTerm,
+ const lang::Locale& rLocale,
+ const beans::PropertyValues& rProperties )
+{
+ uno::Sequence< uno::Reference< linguistic2::XMeaning > > aMeanings(
+ xThesaurus->queryMeanings( rTerm, rLocale, rProperties ) );
+
+ // text with '.' at the end?
+ if ( !aMeanings.hasElements() && rTerm.endsWith(".") )
+ {
+ // try again without trailing '.' chars. It may be a word at the
+ // end of a sentence and not an abbreviation...
+ OUString aTxt(comphelper::string::stripEnd(rTerm, '.'));
+ aMeanings = xThesaurus->queryMeanings( aTxt, rLocale, rProperties );
+ if (aMeanings.hasElements())
+ {
+ rTerm = aTxt;
+ }
+ }
+
+ return aMeanings;
+}
+
+bool SvxThesaurusDialog::UpdateAlternativesBox_Impl()
+{
+ lang::Locale aLocale( LanguageTag::convertToLocale( nLookUpLanguage ) );
+ uno::Sequence< uno::Reference< linguistic2::XMeaning > > aMeanings = queryMeanings_Impl(
+ aLookUpText, aLocale, uno::Sequence< beans::PropertyValue >() );
+ const sal_Int32 nMeanings = aMeanings.getLength();
+ const uno::Reference< linguistic2::XMeaning > *pMeanings = aMeanings.getConstArray();
+
+ m_xAlternativesCT->freeze();
+
+ m_xAlternativesCT->clear();
+ int nRow = 0;
+ for (sal_Int32 i = 0; i < nMeanings; ++i)
+ {
+ OUString rMeaningTxt = pMeanings[i]->getMeaning();
+ uno::Sequence< OUString > aSynonyms( pMeanings[i]->querySynonyms() );
+ const sal_Int32 nSynonyms = aSynonyms.getLength();
+ const OUString *pSynonyms = aSynonyms.getConstArray();
+ DBG_ASSERT( !rMeaningTxt.isEmpty(), "meaning with empty text" );
+ DBG_ASSERT( nSynonyms > 0, "meaning without synonym" );
+
+ OUString sHeading = OUString::number(i + 1) + ". " + rMeaningTxt;
+ m_xAlternativesCT->append_text(sHeading);
+ m_xAlternativesCT->set_text_emphasis(nRow, true, 0);
+ ++nRow;
+
+ for (sal_Int32 k = 0; k < nSynonyms; ++k)
+ {
+ // GetThesaurusReplaceText will strip the leading spaces
+ m_xAlternativesCT->append_text(" " + pSynonyms[k]);
+ m_xAlternativesCT->set_text_emphasis(nRow, false, 0);
+ ++nRow;
+ }
+ }
+
+ m_xAlternativesCT->thaw();
+
+ return nMeanings > 0;
+}
+
+void SvxThesaurusDialog::LookUp( const OUString &rText )
+{
+ if (rText != m_xWordCB->get_active_text()) // avoid moving of the cursor if the text is the same
+ m_xWordCB->set_entry_text(rText);
+ LookUp_Impl();
+}
+
+IMPL_LINK_NOARG(SvxThesaurusDialog, LeftBtnHdl_Impl, weld::Button&, void)
+{
+ if (aLookUpHistory.size() >= 2)
+ {
+ aLookUpHistory.pop(); // remove current look up word from stack
+ m_xWordCB->set_entry_text(aLookUpHistory.top()); // retrieve previous look up word
+ aLookUpHistory.pop();
+ LookUp_Impl();
+ }
+}
+
+IMPL_LINK( SvxThesaurusDialog, LanguageHdl_Impl, weld::ComboBox&, rLB, void )
+{
+ OUString aLangText(rLB.get_active_text());
+ LanguageType nLang = SvtLanguageTable::GetLanguageType( aLangText );
+ DBG_ASSERT( nLang != LANGUAGE_NONE && nLang != LANGUAGE_DONTKNOW, "failed to get language" );
+ if (xThesaurus->hasLocale( LanguageTag::convertToLocale( nLang ) ))
+ nLookUpLanguage = nLang;
+ SetWindowTitle( nLang );
+ LookUp_Impl();
+}
+
+void SvxThesaurusDialog::LookUp_Impl()
+{
+ OUString aText(m_xWordCB->get_active_text());
+
+ aLookUpText = aText;
+ if (!aLookUpText.isEmpty() &&
+ (aLookUpHistory.empty() || aLookUpText != aLookUpHistory.top()))
+ aLookUpHistory.push( aLookUpText );
+
+ m_bWordFound = UpdateAlternativesBox_Impl();
+ m_xAlternativesCT->set_visible(m_bWordFound);
+ m_xNotFound->set_visible(!m_bWordFound);
+
+ if (m_bWordFound)
+ Application::PostUserEvent(LINK(this, SvxThesaurusDialog, SelectFirstHdl_Impl));
+
+ if (m_xWordCB->find_text(aText) == -1)
+ m_xWordCB->append_text(aText);
+
+ m_xReplaceEdit->set_text( OUString() );
+ ReplaceEditHdl_Impl(*m_xReplaceEdit);
+ m_xLeftBtn->set_sensitive( aLookUpHistory.size() > 1 );
+}
+
+IMPL_LINK_NOARG(SvxThesaurusDialog, WordSelectHdl_Impl, weld::ComboBox&, void)
+{
+ m_aModifyIdle.Start();
+}
+
+IMPL_LINK( SvxThesaurusDialog, AlternativesSelectHdl_Impl, weld::TreeView&, rBox, void )
+{
+ int nEntry = rBox.get_selected_index();
+ if (nEntry != -1)
+ {
+ bool bIsHeader = rBox.get_text_emphasis(nEntry, 0);
+ if (bIsHeader)
+ {
+ ++nEntry;
+ rBox.select(nEntry);
+ }
+ OUString aStr = linguistic::GetThesaurusReplaceText(rBox.get_text(nEntry));
+ m_xReplaceEdit->set_text(aStr);
+ ReplaceEditHdl_Impl(*m_xReplaceEdit);
+ }
+}
+
+IMPL_LINK( SvxThesaurusDialog, AlternativesDoubleClickHdl_Impl, weld::TreeView&, rBox, bool )
+{
+ int nEntry = rBox.get_selected_index();
+ if (nEntry != -1)
+ {
+ bool bIsHeader = rBox.get_text_emphasis(nEntry, 0);
+ if (bIsHeader)
+ {
+ ++nEntry;
+ rBox.select(nEntry);
+ }
+ OUString aStr = linguistic::GetThesaurusReplaceText(rBox.get_text(nEntry));
+ m_xWordCB->set_entry_text(aStr);
+ if (!aStr.isEmpty())
+ LookUp_Impl();
+ }
+
+ //! workaround to set the selection since calling SelectEntryPos within
+ //! the double click handler does not work
+ Application::PostUserEvent(LINK(this, SvxThesaurusDialog, SelectFirstHdl_Impl));
+
+ return true;
+}
+
+IMPL_LINK_NOARG(SvxThesaurusDialog, SelectFirstHdl_Impl, void *, void)
+{
+ if (m_xAlternativesCT->n_children() >= 2)
+ {
+ m_xAlternativesCT->select(1); // pos 0 is a 'header' that is not selectable
+ AlternativesSelectHdl_Impl(*m_xAlternativesCT);
+ }
+}
+
+// class SvxThesaurusDialog ----------------------------------------------
+
+SvxThesaurusDialog::SvxThesaurusDialog(
+ weld::Window* pParent,
+ uno::Reference< linguistic2::XThesaurus > const & xThes,
+ const OUString &rWord,
+ LanguageType nLanguage)
+ : SfxDialogController(pParent, "cui/ui/thesaurus.ui", "ThesaurusDialog")
+ , m_aModifyIdle("cui SvxThesaurusDialog LookUp Modify")
+ , aLookUpText()
+ , nLookUpLanguage(LANGUAGE_NONE)
+ , m_bWordFound(false)
+ , m_xLeftBtn(m_xBuilder->weld_button("left"))
+ , m_xWordCB(m_xBuilder->weld_combo_box("wordcb"))
+ , m_xAlternativesCT(m_xBuilder->weld_tree_view("alternatives"))
+ , m_xNotFound(m_xBuilder->weld_label("notfound"))
+ , m_xReplaceEdit(m_xBuilder->weld_entry("replaceed"))
+ , m_xLangLB(m_xBuilder->weld_combo_box("langcb"))
+ , m_xReplaceBtn(m_xBuilder->weld_button("ok"))
+{
+ m_aModifyIdle.SetInvokeHandler( LINK( this, SvxThesaurusDialog, ModifyTimer_Hdl ) );
+ m_aModifyIdle.SetPriority( TaskPriority::LOWEST );
+
+ m_xReplaceEdit->connect_changed( LINK( this, SvxThesaurusDialog, ReplaceEditHdl_Impl ) );
+ m_xReplaceBtn->connect_clicked( LINK( this, SvxThesaurusDialog, ReplaceBtnHdl_Impl ) );
+ m_xLeftBtn->connect_clicked( LINK( this, SvxThesaurusDialog, LeftBtnHdl_Impl ) );
+ m_xWordCB->set_entry_completion(false);
+ m_xWordCB->connect_changed( LINK( this, SvxThesaurusDialog, WordSelectHdl_Impl ) );
+ m_xLangLB->connect_changed( LINK( this, SvxThesaurusDialog, LanguageHdl_Impl ) );
+ m_xAlternativesCT->connect_changed( LINK( this, SvxThesaurusDialog, AlternativesSelectHdl_Impl ));
+ m_xAlternativesCT->connect_row_activated( LINK( this, SvxThesaurusDialog, AlternativesDoubleClickHdl_Impl ));
+ m_xAlternativesCT->connect_key_press(LINK(this, SvxThesaurusDialog, KeyInputHdl));
+
+ xThesaurus = xThes;
+ aLookUpText = rWord;
+ nLookUpLanguage = nLanguage;
+ if (!rWord.isEmpty())
+ aLookUpHistory.push( rWord );
+
+ OUString aTmp( rWord );
+ (void)linguistic::RemoveHyphens( aTmp );
+ (void)linguistic::ReplaceControlChars( aTmp );
+ m_xReplaceEdit->set_text( aTmp );
+ ReplaceEditHdl_Impl(*m_xReplaceEdit);
+ m_xWordCB->append_text( aTmp );
+
+ LookUp( aTmp );
+ m_xAlternativesCT->grab_focus();
+ m_xLeftBtn->set_sensitive(false);
+
+ // fill language menu button list
+ uno::Sequence< lang::Locale > aLocales;
+ if (xThesaurus.is())
+ aLocales = xThesaurus->getLocales();
+ const sal_Int32 nLocales = aLocales.getLength();
+ const lang::Locale *pLocales = aLocales.getConstArray();
+ m_xLangLB->clear();
+ std::vector< OUString > aLangVec;
+ for (sal_Int32 i = 0; i < nLocales; ++i)
+ {
+ const LanguageType nLang = LanguageTag::convertToLanguageType( pLocales[i] );
+ DBG_ASSERT( nLang != LANGUAGE_NONE && nLang != LANGUAGE_DONTKNOW, "failed to get language" );
+ aLangVec.push_back( SvtLanguageTable::GetLanguageString( nLang ) );
+ }
+ std::sort( aLangVec.begin(), aLangVec.end() );
+ m_xLangLB->freeze();
+ for (const OUString & i : aLangVec)
+ m_xLangLB->append_text(i);
+ m_xLangLB->thaw();
+
+ std::vector< OUString >::iterator aI = std::find(aLangVec.begin(), aLangVec.end(),
+ SvtLanguageTable::GetLanguageString(nLanguage));
+ if (aI != aLangVec.end())
+ {
+ m_xLangLB->set_active_text(*aI);
+ }
+
+ SetWindowTitle(nLanguage);
+
+ // disable controls if service is missing
+ if (!xThesaurus.is())
+ m_xDialog->set_sensitive(false);
+}
+
+SvxThesaurusDialog::~SvxThesaurusDialog()
+{
+}
+
+IMPL_LINK_NOARG(SvxThesaurusDialog, ReplaceBtnHdl_Impl, weld::Button&, void)
+{
+ m_xDialog->response(RET_OK);
+}
+
+void SvxThesaurusDialog::SetWindowTitle( LanguageType nLanguage )
+{
+ // adjust language
+ OUString aStr(m_xDialog->get_title());
+ sal_Int32 nIndex = aStr.indexOf( '(' );
+ if( nIndex != -1 )
+ aStr = aStr.copy( 0, nIndex - 1 );
+ aStr += " (" + SvtLanguageTable::GetLanguageString( nLanguage ) + ")";
+ m_xDialog->set_title(aStr); // set window title
+}
+
+OUString SvxThesaurusDialog::GetWord() const
+{
+ return m_xReplaceEdit->get_text();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/dialogs/tipofthedaydlg.cxx b/cui/source/dialogs/tipofthedaydlg.cxx
new file mode 100644
index 000000000..4775ed057
--- /dev/null
+++ b/cui/source/dialogs/tipofthedaydlg.cxx
@@ -0,0 +1,168 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * 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 <tipofthedaydlg.hxx>
+
+#include <dialmgr.hxx>
+#include <officecfg/Office/Common.hxx>
+#include <osl/file.hxx>
+#include <rtl/bootstrap.hxx>
+#include <tipoftheday.hrc>
+#include <vcl/graphicfilter.hxx>
+#include <vcl/help.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/svapp.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <unotools/resmgr.hxx>
+#include <unotools/configmgr.hxx>
+
+TipOfTheDayDialog::TipOfTheDayDialog(weld::Window* pParent)
+ : GenericDialogController(pParent, "cui/ui/tipofthedaydialog.ui", "TipOfTheDayDialog")
+ , m_pImage(m_xBuilder->weld_image("imImage"))
+ , m_pText(m_xBuilder->weld_label("lbText"))
+ , m_pShowTip(m_xBuilder->weld_check_button("cbShowTip"))
+ , m_pNext(m_xBuilder->weld_button("btnNext"))
+ , m_pLink(m_xBuilder->weld_link_button("btnLink"))
+{
+ m_pShowTip->set_active(officecfg::Office::Common::Misc::ShowTipOfTheDay::get());
+ m_pNext->connect_clicked(LINK(this, TipOfTheDayDialog, OnNextClick));
+
+ nNumberOfTips = SAL_N_ELEMENTS(TIPOFTHEDAY_STRINGARRAY);
+ nCurrentTip = officecfg::Office::Common::Misc::LastTipOfTheDayID::get();
+
+ const auto t0 = std::chrono::system_clock::now().time_since_epoch();
+ nDay = std::chrono::duration_cast<std::chrono::hours>(t0).count() / 24; //days since 1970-01-01
+ if (nDay > officecfg::Office::Common::Misc::LastTipOfTheDayShown::get())
+ nCurrentTip++;
+
+ UpdateTip();
+}
+
+TipOfTheDayDialog::~TipOfTheDayDialog()
+{
+ std::shared_ptr<comphelper::ConfigurationChanges> xChanges(
+ comphelper::ConfigurationChanges::create());
+ officecfg::Office::Common::Misc::LastTipOfTheDayShown::set(nDay, xChanges);
+ officecfg::Office::Common::Misc::LastTipOfTheDayID::set(nCurrentTip, xChanges);
+ officecfg::Office::Common::Misc::ShowTipOfTheDay::set(m_pShowTip->get_active(), xChanges);
+ xChanges->commit();
+}
+
+static bool file_exists(const OUString& fileName)
+{
+ ::osl::File aFile(fileName);
+ return aFile.open(osl_File_OpenFlag_Read) == osl::FileBase::E_None;
+}
+
+void TipOfTheDayDialog::UpdateTip()
+{
+ if ((nCurrentTip + 1 > nNumberOfTips) || (nCurrentTip < 0))
+ nCurrentTip = 0;
+ m_xDialog->set_title(CuiResId(STR_TITLE) + ": " + OUString::number(nCurrentTip + 1) + "/"
+ + OUString::number(nNumberOfTips));
+
+ // text
+ OUString aText = CuiResId(std::get<0>(TIPOFTHEDAY_STRINGARRAY[nCurrentTip]));
+//replace MOD1 & MOD2 shortcuts depending on platform
+#ifdef MACOSX
+ const OUString aMOD1 = CuiResId(STR_CMD);
+ const OUString aMOD2 = CuiResId(STR_Option);
+#else
+ const OUString aMOD1 = CuiResId(STR_CTRL);
+ const OUString aMOD2 = CuiResId(STR_Alt);
+#endif
+ sal_Int32 aPos;
+ aPos = aText.indexOf("%MOD1");
+ while (aPos != -1)
+ {
+ aText = aText.replaceAt(aPos, 5, aMOD1);
+ aPos = aText.indexOf("%MOD1");
+ }
+ aPos = aText.indexOf("%MOD2");
+ while (aPos != -1)
+ {
+ aText = aText.replaceAt(aPos, 5, aMOD2);
+ aPos = aText.indexOf("%MOD2");
+ }
+ m_pText->set_label(aText);
+
+ // hyperlink
+ aLink = std::get<1>(TIPOFTHEDAY_STRINGARRAY[nCurrentTip]);
+ if (aLink.isEmpty())
+ {
+ m_pLink->set_visible(false);
+ }
+ else if (aLink.startsWith("http"))
+ {
+ // Links may have some %PRODUCTVERSION which need to be expanded
+ aText = Translate::ExpandVariables(aLink);
+ aPos = aText.indexOf("%LANGUAGENAME");
+ if (aPos != -1)
+ {
+ OUString aLang = LanguageTag(utl::ConfigManager::getUILocale()).getLanguage();
+ if (aLang == "en" || aLang == "pt" || aLang == "zh") //en-US/GB, pt-BR, zh-CH/TW
+ aLang = LanguageTag(utl::ConfigManager::getUILocale()).getBcp47();
+ aText = aText.replaceAt(aPos, 13, aLang);
+ }
+ m_pLink->set_uri(aText);
+
+ m_pLink->set_label(CuiResId(STR_MORE_LINK));
+ m_pLink->set_visible(true);
+ m_pLink->connect_activate_link(Link<weld::LinkButton&, bool>());
+ }
+ else
+ {
+ m_pLink->set_uri("");
+ m_pLink->set_label(CuiResId(STR_HELP_LINK));
+ m_pLink->set_visible(true);
+ //converts aLink into the proper offline/online hyperlink
+ m_pLink->connect_activate_link(LINK(this, TipOfTheDayDialog, OnLinkClick));
+ }
+ // image
+ OUString aURL("$BRAND_BASE_DIR/$BRAND_SHARE_SUBDIR/tipoftheday/");
+ rtl::Bootstrap::expandMacros(aURL);
+ OUString aImage = std::get<2>(TIPOFTHEDAY_STRINGARRAY[nCurrentTip]);
+ // use default image if none is available with the number
+ if (aImage.isEmpty() || !file_exists(aURL + aImage))
+ aImage = "tipoftheday.png";
+ // draw image
+ Graphic aGraphic;
+ if (GraphicFilter::LoadGraphic(aURL + aImage, OUString(), aGraphic) == ERRCODE_NONE)
+ {
+ ScopedVclPtr<VirtualDevice> m_pVirDev = m_pImage->create_virtual_device();
+ m_pVirDev->SetOutputSizePixel(aGraphic.GetSizePixel());
+ m_pVirDev->DrawBitmapEx(Point(0, 0), aGraphic.GetBitmapEx());
+ m_pImage->set_image(m_pVirDev.get());
+ m_pVirDev.disposeAndClear();
+ }
+}
+
+IMPL_LINK_NOARG(TipOfTheDayDialog, OnLinkClick, weld::LinkButton&, bool)
+{
+ Application::GetHelp()->Start(aLink, static_cast<weld::Widget*>(nullptr));
+ return true;
+}
+
+IMPL_LINK_NOARG(TipOfTheDayDialog, OnNextClick, weld::Button&, void)
+{
+ nCurrentTip++; //zeroed at updatetip when out of range
+ UpdateTip();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/dialogs/zoom.cxx b/cui/source/dialogs/zoom.cxx
new file mode 100644
index 000000000..b80080dfa
--- /dev/null
+++ b/cui/source/dialogs/zoom.cxx
@@ -0,0 +1,406 @@
+/* -*- 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 <svl/itemset.hxx>
+#include <svl/itempool.hxx>
+#include <sfx2/objsh.hxx>
+#include <zoom.hxx>
+#include <sfx2/zoomitem.hxx>
+#include <svx/viewlayoutitem.hxx>
+#include <svx/zoom_def.hxx>
+
+namespace
+{
+const sal_uInt16 SPECIAL_FACTOR = 0xFFFF;
+
+} // anonymous namespace
+
+sal_uInt16 SvxZoomDialog::GetFactor() const
+{
+ if (m_x100Btn->get_active())
+ return 100;
+
+ if (m_xUserBtn->get_active())
+ return static_cast<sal_uInt16>(m_xUserEdit->get_value(FieldUnit::PERCENT));
+ else
+ return SPECIAL_FACTOR;
+}
+
+void SvxZoomDialog::SetFactor(sal_uInt16 nNewFactor, ZoomButtonId nButtonId)
+{
+ m_xUserEdit->set_sensitive(false);
+
+ if (nButtonId == ZoomButtonId::NONE)
+ {
+ if (nNewFactor == 100)
+ {
+ m_x100Btn->set_active(true);
+ m_x100Btn->grab_focus();
+ }
+ else
+ {
+ m_xUserBtn->set_active(true);
+ m_xUserEdit->set_sensitive(true);
+ m_xUserEdit->set_value(nNewFactor, FieldUnit::PERCENT);
+ m_xUserEdit->grab_focus();
+ }
+ }
+ else
+ {
+ m_xUserEdit->set_value(nNewFactor, FieldUnit::PERCENT);
+ switch (nButtonId)
+ {
+ case ZoomButtonId::OPTIMAL:
+ {
+ m_xOptimalBtn->set_active(true);
+ m_xOptimalBtn->grab_focus();
+ break;
+ }
+ case ZoomButtonId::PAGEWIDTH:
+ {
+ m_xPageWidthBtn->set_active(true);
+ m_xPageWidthBtn->grab_focus();
+ break;
+ }
+ case ZoomButtonId::WHOLEPAGE:
+ {
+ m_xWholePageBtn->set_active(true);
+ m_xWholePageBtn->grab_focus();
+ break;
+ }
+ default:
+ break;
+ }
+ }
+}
+
+void SvxZoomDialog::HideButton(ZoomButtonId nButtonId)
+{
+ switch (nButtonId)
+ {
+ case ZoomButtonId::OPTIMAL:
+ m_xOptimalBtn->hide();
+ break;
+
+ case ZoomButtonId::PAGEWIDTH:
+ m_xPageWidthBtn->hide();
+ break;
+
+ case ZoomButtonId::WHOLEPAGE:
+ m_xWholePageBtn->hide();
+ break;
+
+ default:
+ OSL_FAIL("Wrong button number!");
+ }
+}
+
+void SvxZoomDialog::SetLimits(sal_uInt16 nMin, sal_uInt16 nMax)
+{
+ DBG_ASSERT(nMin < nMax, "invalid limits");
+ m_xUserEdit->set_range(nMin, nMax, FieldUnit::PERCENT);
+}
+
+const SfxItemSet* SvxZoomDialog::GetOutputItemSet() const { return m_pOutSet.get(); }
+
+SvxZoomDialog::SvxZoomDialog(weld::Window* pParent, const SfxItemSet& rCoreSet)
+ : SfxDialogController(pParent, "cui/ui/zoomdialog.ui", "ZoomDialog")
+ , m_rSet(rCoreSet)
+ , m_bModified(false)
+ , m_xOptimalBtn(m_xBuilder->weld_radio_button("optimal"))
+ , m_xWholePageBtn(m_xBuilder->weld_radio_button("fitwandh"))
+ , m_xPageWidthBtn(m_xBuilder->weld_radio_button("fitw"))
+ , m_x100Btn(m_xBuilder->weld_radio_button("100pc"))
+ , m_xUserBtn(m_xBuilder->weld_radio_button("variable"))
+ , m_xUserEdit(m_xBuilder->weld_metric_spin_button("zoomsb", FieldUnit::PERCENT))
+ , m_xViewFrame(m_xBuilder->weld_widget("viewframe"))
+ , m_xAutomaticBtn(m_xBuilder->weld_radio_button("automatic"))
+ , m_xSingleBtn(m_xBuilder->weld_radio_button("singlepage"))
+ , m_xColumnsBtn(m_xBuilder->weld_radio_button("columns"))
+ , m_xColumnsEdit(m_xBuilder->weld_spin_button("columnssb"))
+ , m_xBookModeChk(m_xBuilder->weld_check_button("bookmode"))
+ , m_xOKBtn(m_xBuilder->weld_button("ok"))
+{
+ Link<weld::ToggleButton&, void> aLink = LINK(this, SvxZoomDialog, UserHdl);
+ m_x100Btn->connect_toggled(aLink);
+ m_xOptimalBtn->connect_toggled(aLink);
+ m_xPageWidthBtn->connect_toggled(aLink);
+ m_xWholePageBtn->connect_toggled(aLink);
+ m_xUserBtn->connect_toggled(aLink);
+
+ Link<weld::ToggleButton&, void> aViewLayoutLink = LINK(this, SvxZoomDialog, ViewLayoutUserHdl);
+ m_xAutomaticBtn->connect_toggled(aViewLayoutLink);
+ m_xSingleBtn->connect_toggled(aViewLayoutLink);
+ m_xColumnsBtn->connect_toggled(aViewLayoutLink);
+
+ Link<weld::SpinButton&, void> aViewLayoutSpinLink
+ = LINK(this, SvxZoomDialog, ViewLayoutSpinHdl);
+ m_xColumnsEdit->connect_value_changed(aViewLayoutSpinLink);
+
+ Link<weld::ToggleButton&, void> aViewLayoutCheckLink
+ = LINK(this, SvxZoomDialog, ViewLayoutCheckHdl);
+ m_xBookModeChk->connect_toggled(aViewLayoutCheckLink);
+
+ m_xOKBtn->connect_clicked(LINK(this, SvxZoomDialog, OKHdl));
+ m_xUserEdit->connect_value_changed(LINK(this, SvxZoomDialog, SpinHdl));
+
+ // default values
+ sal_uInt16 nValue = 100;
+ sal_uInt16 nMin = 10;
+ sal_uInt16 nMax = 1000;
+
+ // maybe get the old value first
+ const SfxUInt16Item* pOldUserItem = nullptr;
+ SfxObjectShell* pShell = SfxObjectShell::Current();
+
+ if (pShell)
+ pOldUserItem = pShell->GetItem(SID_ATTR_ZOOM_USER);
+
+ if (pOldUserItem)
+ nValue = pOldUserItem->GetValue();
+
+ // initialize UserEdit
+ if (nMin > nValue)
+ nMin = nValue;
+ if (nMax < nValue)
+ nMax = nValue;
+
+ SetLimits(nMin, nMax);
+ m_xUserEdit->set_value(nValue, FieldUnit::PERCENT);
+
+ const SfxPoolItem& rItem = m_rSet.Get(m_rSet.GetPool()->GetWhich(SID_ATTR_ZOOM));
+
+ if (nullptr != dynamic_cast<const SvxZoomItem*>(&rItem))
+ {
+ const SvxZoomItem& rZoomItem = static_cast<const SvxZoomItem&>(rItem);
+ const sal_uInt16 nZoom = rZoomItem.GetValue();
+ const SvxZoomType eType = rZoomItem.GetType();
+ const SvxZoomEnableFlags nValSet = rZoomItem.GetValueSet();
+ ZoomButtonId nButtonId = ZoomButtonId::NONE;
+
+ switch (eType)
+ {
+ case SvxZoomType::OPTIMAL:
+ nButtonId = ZoomButtonId::OPTIMAL;
+ break;
+ case SvxZoomType::PAGEWIDTH:
+ nButtonId = ZoomButtonId::PAGEWIDTH;
+ break;
+ case SvxZoomType::WHOLEPAGE:
+ nButtonId = ZoomButtonId::WHOLEPAGE;
+ break;
+ case SvxZoomType::PERCENT:
+ break;
+ case SvxZoomType::PAGEWIDTH_NOBORDER:
+ break;
+ }
+
+ if (!(SvxZoomEnableFlags::N100 & nValSet))
+ m_x100Btn->set_sensitive(false);
+ if (!(SvxZoomEnableFlags::OPTIMAL & nValSet))
+ m_xOptimalBtn->set_sensitive(false);
+ if (!(SvxZoomEnableFlags::PAGEWIDTH & nValSet))
+ m_xPageWidthBtn->set_sensitive(false);
+ if (!(SvxZoomEnableFlags::WHOLEPAGE & nValSet))
+ m_xWholePageBtn->set_sensitive(false);
+
+ SetFactor(nZoom, nButtonId);
+ }
+ else
+ {
+ const sal_uInt16 nZoom = static_cast<const SfxUInt16Item&>(rItem).GetValue();
+ SetFactor(nZoom);
+ }
+
+ const SfxPoolItem* pPoolViewLayoutItem = nullptr;
+ if (SfxItemState::SET == m_rSet.GetItemState(SID_ATTR_VIEWLAYOUT, false, &pPoolViewLayoutItem))
+ {
+ const SvxViewLayoutItem* pViewLayoutItem
+ = static_cast<const SvxViewLayoutItem*>(pPoolViewLayoutItem);
+ const sal_uInt16 nColumns = pViewLayoutItem->GetValue();
+ const bool bBookMode = pViewLayoutItem->IsBookMode();
+
+ if (0 == nColumns)
+ {
+ m_xAutomaticBtn->set_active(true);
+ m_xColumnsEdit->set_value(2);
+ m_xColumnsEdit->set_sensitive(false);
+ m_xBookModeChk->set_sensitive(false);
+ }
+ else if (1 == nColumns)
+ {
+ m_xSingleBtn->set_active(true);
+ m_xColumnsEdit->set_value(2);
+ m_xColumnsEdit->set_sensitive(false);
+ m_xBookModeChk->set_sensitive(false);
+ }
+ else
+ {
+ m_xColumnsBtn->set_active(true);
+ if (!bBookMode)
+ {
+ m_xColumnsEdit->set_value(nColumns);
+ if (nColumns % 2 != 0)
+ m_xBookModeChk->set_sensitive(false);
+ }
+ else
+ {
+ m_xColumnsEdit->set_value(nColumns);
+ m_xBookModeChk->set_active(true);
+ }
+ }
+ }
+ else
+ {
+ // hide view layout related controls:
+ m_xViewFrame->set_sensitive(false);
+ }
+}
+
+IMPL_LINK_NOARG(SvxZoomDialog, UserHdl, weld::ToggleButton&, void)
+{
+ m_bModified = true;
+
+ if (m_xUserBtn->get_active())
+ {
+ m_xUserEdit->set_sensitive(true);
+ m_xUserEdit->grab_focus();
+ }
+ else
+ {
+ m_xUserEdit->set_sensitive(false);
+ }
+}
+
+IMPL_LINK_NOARG(SvxZoomDialog, SpinHdl, weld::MetricSpinButton&, void)
+{
+ if (!m_xUserBtn->get_active())
+ return;
+
+ m_bModified = true;
+}
+
+IMPL_LINK_NOARG(SvxZoomDialog, ViewLayoutUserHdl, weld::ToggleButton&, void)
+{
+ m_bModified = true;
+
+ if (m_xAutomaticBtn->get_active() || m_xSingleBtn->get_active())
+ {
+ m_xColumnsEdit->set_sensitive(false);
+ m_xBookModeChk->set_sensitive(false);
+ }
+ else if (m_xColumnsBtn->get_active())
+ {
+ m_xColumnsEdit->set_sensitive(true);
+ m_xColumnsEdit->grab_focus();
+ if (m_xColumnsEdit->get_value() % 2 == 0)
+ m_xBookModeChk->set_sensitive(true);
+ }
+}
+
+IMPL_LINK_NOARG(SvxZoomDialog, ViewLayoutSpinHdl, weld::SpinButton&, void)
+{
+ if (!m_xColumnsBtn->get_active())
+ return;
+
+ if (m_xColumnsEdit->get_value() % 2 == 0)
+ {
+ m_xBookModeChk->set_sensitive(true);
+ }
+ else
+ {
+ m_xBookModeChk->set_active(false);
+ m_xBookModeChk->set_sensitive(false);
+ }
+
+ m_bModified = true;
+}
+
+IMPL_LINK_NOARG(SvxZoomDialog, ViewLayoutCheckHdl, weld::ToggleButton&, void)
+{
+ if (!m_xColumnsBtn->get_active())
+ return;
+
+ m_bModified = true;
+}
+
+IMPL_LINK_NOARG(SvxZoomDialog, OKHdl, weld::Button&, void)
+{
+ if (m_bModified)
+ {
+ SvxZoomItem aZoomItem(SvxZoomType::PERCENT, 0, m_rSet.GetPool()->GetWhich(SID_ATTR_ZOOM));
+ SvxViewLayoutItem aViewLayoutItem(0, false,
+ m_rSet.GetPool()->GetWhich(SID_ATTR_VIEWLAYOUT));
+
+ sal_uInt16 nFactor = GetFactor();
+
+ if (SPECIAL_FACTOR == nFactor)
+ {
+ if (m_xOptimalBtn->get_active())
+ aZoomItem.SetType(SvxZoomType::OPTIMAL);
+ else if (m_xPageWidthBtn->get_active())
+ aZoomItem.SetType(SvxZoomType::PAGEWIDTH);
+ else if (m_xWholePageBtn->get_active())
+ aZoomItem.SetType(SvxZoomType::WHOLEPAGE);
+ }
+ else
+ {
+ aZoomItem.SetValue(nFactor);
+ }
+
+ if (m_xAutomaticBtn->get_active())
+ {
+ aViewLayoutItem.SetValue(0);
+ aViewLayoutItem.SetBookMode(false);
+ }
+ if (m_xSingleBtn->get_active())
+ {
+ aViewLayoutItem.SetValue(1);
+ aViewLayoutItem.SetBookMode(false);
+ }
+ else if (m_xColumnsBtn->get_active())
+ {
+ aViewLayoutItem.SetValue(static_cast<sal_uInt16>(m_xColumnsEdit->get_value()));
+ aViewLayoutItem.SetBookMode(m_xBookModeChk->get_active());
+ }
+
+ m_pOutSet.reset(new SfxItemSet(m_rSet));
+ m_pOutSet->Put(aZoomItem);
+
+ // don't set attribute in case the whole viewlayout stuff is disabled:
+ if (m_xViewFrame->get_sensitive())
+ m_pOutSet->Put(aViewLayoutItem);
+
+ // memorize value from the UserEdit beyond the dialog
+ SfxObjectShell* pShell = SfxObjectShell::Current();
+
+ if (pShell)
+ {
+ sal_uInt16 nZoomValue
+ = static_cast<sal_uInt16>(m_xUserEdit->get_value(FieldUnit::PERCENT));
+ pShell->PutItem(SfxUInt16Item(SID_ATTR_ZOOM_USER, nZoomValue));
+ }
+ m_xDialog->response(RET_OK);
+ }
+ else
+ m_xDialog->response(RET_CANCEL);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */