filter/source/pdf/impdialog.cxx | 7 filter/source/pdf/impdialog.hxx | 2 filter/source/pdf/pdfdialog.cxx | 24 ++ filter/source/pdf/pdfdialog.hxx | 13 + include/LibreOfficeKit/LibreOfficeKitEnums.h | 10 + include/sfx2/viewsh.hxx | 6 include/svtools/genericasyncunodialog.hxx | 132 ++++++++++++++ libreofficekit/source/gtk/lokdocview.cxx | 1 offapi/com/sun/star/document/PDFDialog.idl | 1 sfx2/inc/guisaveas.hxx | 32 +++ sfx2/source/doc/guisaveas.cxx | 246 +++++++++++++++++++-------- sfx2/source/doc/objserv.cxx | 15 + sfx2/source/view/ipclient.cxx | 3 vcl/jsdialog/enabled.cxx | 9 14 files changed, 419 insertions(+), 82 deletions(-)
New commits: commit 89f5912ad2eee786508414791653a017206a7c04 Author: NickWingate <nick.wing...@collabora.com> AuthorDate: Thu Sep 22 09:02:42 2022 +0100 Commit: Andras Timar <andras.ti...@collabora.com> CommitDate: Tue Dec 20 03:11:16 2022 +0000 Async PDFExport dialog and parent methods Filter dialogs are all called generically from guisaveas.cxx in GUIStoreModel() Signed-off-by: NickWingate <nick.wing...@collabora.com> Change-Id: Idfbe85c09f84d4a7cf3f00b9704d5af94868a051 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/140403 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Andras Timar <andras.ti...@collabora.com> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/144511 Tested-by: Jenkins diff --git a/filter/source/pdf/impdialog.cxx b/filter/source/pdf/impdialog.cxx index fd68322f1a23..a02412ac6caa 100644 --- a/filter/source/pdf/impdialog.cxx +++ b/filter/source/pdf/impdialog.cxx @@ -541,6 +541,8 @@ ImpPDFTabGeneralPage::ImpPDFTabGeneralPage(weld::Container* pPage, weld::DialogC ImpPDFTabGeneralPage::~ImpPDFTabGeneralPage() { + if (mxPasswordUnusedWarnDialog) + mxPasswordUnusedWarnDialog->response(RET_CANCEL); } void ImpPDFTabGeneralPage::SetFilterConfigItem(ImpPDFTabDialog* pParent) @@ -871,10 +873,11 @@ IMPL_LINK_NOARG(ImpPDFTabGeneralPage, TogglePDFVersionOrUniversalAccessibilityHa // if a password was set, inform the user that this will not be used if (pSecPage && pSecPage->hasPassword()) { - std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xContainer.get(), + mxPasswordUnusedWarnDialog = + std::shared_ptr<weld::MessageDialog>(Application::CreateMessageDialog(m_xContainer.get(), VclMessageType::Warning, VclButtonsType::Ok, FilterResId(STR_WARN_PASSWORD_PDFA))); - xBox->run(); + mxPasswordUnusedWarnDialog->runAsync(mxPasswordUnusedWarnDialog, [] (sal_uInt32){ }); } } else diff --git a/filter/source/pdf/impdialog.hxx b/filter/source/pdf/impdialog.hxx index 828422bdc63e..d0d63bccc86b 100644 --- a/filter/source/pdf/impdialog.hxx +++ b/filter/source/pdf/impdialog.hxx @@ -232,6 +232,8 @@ class ImpPDFTabGeneralPage : public SfxTabPage DECL_LINK(TogglePDFVersionOrUniversalAccessibilityHandle, weld::Toggleable&, void); + std::shared_ptr<weld::MessageDialog> mxPasswordUnusedWarnDialog; + public: ImpPDFTabGeneralPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet); diff --git a/filter/source/pdf/pdfdialog.cxx b/filter/source/pdf/pdfdialog.cxx index 7c3e5dda1956..c036fc747b2a 100644 --- a/filter/source/pdf/pdfdialog.cxx +++ b/filter/source/pdf/pdfdialog.cxx @@ -62,6 +62,13 @@ std::unique_ptr<weld::DialogController> PDFDialog::createDialog(const css::uno:: return nullptr; } +std::shared_ptr<SfxTabDialogController> PDFDialog::createAsyncDialog(const css::uno::Reference<css::awt::XWindow>& rParent) +{ + if( mxSrcDoc.is() ) + return std::make_shared<ImpPDFTabDialog>(Application::GetFrameWeld(rParent), maFilterData, mxSrcDoc); + return nullptr; +} + void PDFDialog::executedDialog( sal_Int16 nExecutionResult ) { if (nExecutionResult && m_xDialog) @@ -69,6 +76,23 @@ void PDFDialog::executedDialog( sal_Int16 nExecutionResult ) destroyDialog(); } +void PDFDialog::runAsync(const css::uno::Reference< css::ui::dialogs::XDialogClosedListener >& xListener) +{ + SfxTabDialogController::runAsync(m_xAsyncDialog, [this, xListener](sal_Int32 nResponse) { + executedAsyncDialog( m_xAsyncDialog, nResponse ); + css::ui::dialogs::DialogClosedEvent aEvent; + aEvent.DialogResult = nResponse; + xListener->dialogClosed( aEvent ); + destroyAsyncDialog(); + }); +} + +void PDFDialog::executedAsyncDialog( std::shared_ptr<SfxTabDialogController> xAsyncDialog, sal_Int32 nExecutionResult ) +{ + if (nExecutionResult && xAsyncDialog) + maFilterData = static_cast<ImpPDFTabDialog*>(xAsyncDialog.get())->GetFilterData(); +} + Reference< XPropertySetInfo > SAL_CALL PDFDialog::getPropertySetInfo() { Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); diff --git a/filter/source/pdf/pdfdialog.hxx b/filter/source/pdf/pdfdialog.hxx index fcfd1d0976bd..2410192a2617 100644 --- a/filter/source/pdf/pdfdialog.hxx +++ b/filter/source/pdf/pdfdialog.hxx @@ -19,8 +19,6 @@ #pragma once -#include <svtools/genericunodialog.hxx> - #include <comphelper/proparrhlp.hxx> #include <cppuhelper/implbase.hxx> @@ -28,12 +26,16 @@ #include <com/sun/star/document/XExporter.hpp> #include <com/sun/star/lang/XComponent.hpp> +#include <sfx2/tabdlg.hxx> +#include <svtools/genericasyncunodialog.hxx> + using namespace ::com::sun::star::beans; using namespace ::com::sun::star::document; using namespace ::com::sun::star::lang; using namespace ::com::sun::star::uno; -typedef ::cppu::ImplInheritanceHelper < ::svt::OGenericUnoDialog, XPropertyAccess, XExporter > PDFDialog_Base; +typedef ::cppu::ImplInheritanceHelper < ::svt::OGenericUnoAsyncDialog<SfxTabDialogController>, + XPropertyAccess, XExporter > PDFDialog_Base; class PDFDialog final: public PDFDialog_Base, @@ -54,6 +56,11 @@ private: virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override; + // OGenericUnoAsyncDialog + virtual std::shared_ptr<SfxTabDialogController> createAsyncDialog(const css::uno::Reference<css::awt::XWindow>& rParent) override; + virtual void runAsync(const css::uno::Reference< css::ui::dialogs::XDialogClosedListener >& xListener) override; + virtual void executedAsyncDialog(std::shared_ptr<SfxTabDialogController> xAsyncDialog, sal_Int32 nExecutionResult) override; + // XPropertyAccess using OPropertySetHelper::getPropertyValues; virtual Sequence< PropertyValue > SAL_CALL getPropertyValues( ) override; diff --git a/include/LibreOfficeKit/LibreOfficeKitEnums.h b/include/LibreOfficeKit/LibreOfficeKitEnums.h index 1e9821204c0b..38b3e5e62a40 100644 --- a/include/LibreOfficeKit/LibreOfficeKitEnums.h +++ b/include/LibreOfficeKit/LibreOfficeKitEnums.h @@ -899,6 +899,14 @@ typedef enum * which is a representation of the pie segment. */ LOK_CALLBACK_MEDIA_SHAPE = 58, + + /** + * The document is available to download by the client. + * + * Payload example: + * "file:///tmp/hello-world.pdf" + */ + LOK_CALLBACK_EXPORT_FILE = 59, } LibreOfficeKitCallbackType; @@ -1045,6 +1053,8 @@ static inline const char* lokCallbackTypeToString(int nType) return "LOK_CALLBACK_FONTS_MISSING"; case LOK_CALLBACK_MEDIA_SHAPE: return "LOK_CALLBACK_MEDIA_SHAPE"; + case LOK_CALLBACK_EXPORT_FILE: + return "LOK_CALLBACK_EXPORT_FILE"; } assert(!"Unknown LibreOfficeKitCallbackType type."); diff --git a/include/sfx2/viewsh.hxx b/include/sfx2/viewsh.hxx index 5c8e8b1152f8..bb805cdc4179 100644 --- a/include/sfx2/viewsh.hxx +++ b/include/sfx2/viewsh.hxx @@ -56,6 +56,7 @@ class SfxPrinter; class NotifyEvent; class SfxInPlaceClient; class SfxLokCallbackInterface; +class SfxStoringHelper; namespace rtl { class OStringBuffer; } namespace vcl { class PrinterController; } @@ -173,6 +174,9 @@ friend class SfxPrinterController; /// Used to set the DocId at construction time. See SetCurrentDocId. static ViewShellDocId mnCurrentDocId; + /// Used for async export + std::shared_ptr<SfxStoringHelper> m_xHelper; + protected: virtual void Activate(bool IsMDIActivate) override; virtual void Deactivate(bool IsMDIActivate) override; @@ -416,6 +420,8 @@ public: // Blocked Command view settings void setBlockedCommandList(const char* blockedCommandList); bool isBlockedCommand(OUString command); + + void SetStoringHelper(std::shared_ptr<SfxStoringHelper> xHelper) { m_xHelper = xHelper; } }; diff --git a/include/svtools/genericasyncunodialog.hxx b/include/svtools/genericasyncunodialog.hxx new file mode 100644 index 000000000000..7168d08f4301 --- /dev/null +++ b/include/svtools/genericasyncunodialog.hxx @@ -0,0 +1,132 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <com/sun/star/ui/dialogs/XAsynchronousExecutableDialog.hpp> +#include <sfx2/tabdlg.hxx> +#include <svtools/genericunodialog.hxx> +#include <vcl/svapp.hxx> + +using namespace css::uno; + +namespace svt +{ +typedef cppu::ImplInheritanceHelper<::svt::OGenericUnoDialog, + css::ui::dialogs::XAsynchronousExecutableDialog> + OGenericUnoAsyncDialogBase; + +/** abstract base class for implementing UNO objects representing asynchronous dialogs + */ +template <typename T> class OGenericUnoAsyncDialog : public OGenericUnoAsyncDialogBase +{ + class UnoAsyncDialogEntryGuard + { + public: + UnoAsyncDialogEntryGuard(OGenericUnoAsyncDialog<T>& _rDialog) + : m_aGuard(_rDialog.GetMutex()) + { + } + + private: + ::osl::MutexGuard m_aGuard; + }; + +protected: + std::shared_ptr<T> m_xAsyncDialog; + +protected: + OGenericUnoAsyncDialog(const css::uno::Reference<css::uno::XComponentContext>& _rxContext) + : OGenericUnoAsyncDialogBase(_rxContext) + { + } + + virtual ~OGenericUnoAsyncDialog() override + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard(m_aMutex); + if (m_xAsyncDialog) + destroyAsyncDialog(); + } + +public: + // XAsynchronousExecutableDialog + void SAL_CALL setDialogTitle(const OUString& aTitle) override + { + OGenericUnoDialog::setTitle(aTitle); + } + + virtual void SAL_CALL startExecuteModal( + const css::uno::Reference<css::ui::dialogs::XDialogClosedListener>& xListener) override + { + SolarMutexGuard aSolarGuard; + + { + UnoAsyncDialogEntryGuard aGuard(*this); + + if (m_bExecuting) + throw RuntimeException("already executing the dialog (recursive call)", *this); + + if (!m_xAsyncDialog) + { + m_xAsyncDialog = createAsyncDialog(m_xParent); + OSL_ENSURE(m_xAsyncDialog, "OGenericUnoAsyncDialog::startExecuteModal: " + "createAsyncDialog returned nonsense!"); + if (!m_xAsyncDialog) + return; + + // do some initialisations + if (!m_bTitleAmbiguous) + m_xAsyncDialog->set_title(m_sTitle); + } + + m_bExecuting = true; + } + + runAsync(xListener); + } + +protected: + virtual std::shared_ptr<T> + createAsyncDialog(const css::uno::Reference<css::awt::XWindow>& /*rParent*/) + { + return nullptr; + } + + void destroyAsyncDialog() + { + SolarMutexGuard aSolarGuard; + if (m_xAsyncDialog) + m_xAsyncDialog.reset(); + } + + virtual void + runAsync(const css::uno::Reference<css::ui::dialogs::XDialogClosedListener>& /*xListener*/) + { + } + + virtual void executedAsyncDialog(std::shared_ptr<T> /*xAsyncDialog*/, + sal_Int32 /*_nExecutionResult*/) + { + } +}; + +} // namespace svt + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/libreofficekit/source/gtk/lokdocview.cxx b/libreofficekit/source/gtk/lokdocview.cxx index 4fc6fe0452c1..ff40e4929781 100644 --- a/libreofficekit/source/gtk/lokdocview.cxx +++ b/libreofficekit/source/gtk/lokdocview.cxx @@ -1485,6 +1485,7 @@ callback (gpointer pData) case LOK_CALLBACK_PRINT_RANGES: case LOK_CALLBACK_FONTS_MISSING: case LOK_CALLBACK_MEDIA_SHAPE: + case LOK_CALLBACK_EXPORT_FILE: { // TODO: Implement me break; diff --git a/offapi/com/sun/star/document/PDFDialog.idl b/offapi/com/sun/star/document/PDFDialog.idl index e92b57accd2d..007b30ebef22 100644 --- a/offapi/com/sun/star/document/PDFDialog.idl +++ b/offapi/com/sun/star/document/PDFDialog.idl @@ -36,6 +36,7 @@ service PDFDialog "officecfg/registry/schema/org/openoffice/Office/Common.xcs" */ + interface ::com::sun::star::ui::dialogs::XAsynchronousExecutableDialog; }; diff --git a/sfx2/inc/guisaveas.hxx b/sfx2/inc/guisaveas.hxx index c19f78e3fdf1..88a69711c8fd 100644 --- a/sfx2/inc/guisaveas.hxx +++ b/sfx2/inc/guisaveas.hxx @@ -31,8 +31,15 @@ #include <com/sun/star/frame/XModel.hpp> #include <com/sun/star/frame/XModuleManager2.hpp> +#include <comphelper/sequenceashashmap.hxx> + +#include <sfx2/bindings.hxx> #include <sfx2/signaturestate.hxx> +#include <svtools/dialogclosedlistener.hxx> + +#include <tools/urlobj.hxx> + namespace com::sun::star::document { class XDocumentProperties; } @@ -48,10 +55,32 @@ private: css::uno::Reference< css::container::XContainerQuery > m_xFilterQuery; css::uno::Reference< css::frame::XModuleManager2 > m_xModuleManager; + std::shared_ptr<ModelData_Impl> m_xModelData; + css::uno::Sequence< css::beans::PropertyValue > m_aArgsSequence; + css::uno::Reference< css::container::XNameAccess > const & GetFilterConfiguration(); css::uno::Reference< css::container::XContainerQuery > const & GetFilterQuery(); css::uno::Reference< css::frame::XModuleManager2 > const & GetModuleManager(); + bool m_xDialogUsed; + bool m_bRemote; + bool m_bPreselectPassword; + bool m_bDialogUsed; + bool m_bSetStandardName; + sal_Int16 m_nStoreMode; + + DECL_LINK(FilterDialogClosedHdl, css::ui::dialogs::DialogClosedEvent*, void); + + static bool FinishGUIStoreModel(::comphelper::SequenceAsHashMap::const_iterator& aFileNameIter, + ModelData_Impl& aModelData, bool bRemote, sal_Int16 nStoreMode, + css::uno::Sequence< css::beans::PropertyValue >& aFilterProps, + bool bSetStandardName, bool bPreselectPassword, bool bDialogUsed, + std::u16string_view aFilterFromMediaDescr, std::u16string_view aOldFilterName, + css::uno::Sequence< css::beans::PropertyValue >& aArgsSequence, + OUString aFilterName); + + void CallFinishGUIStoreModel(); + public: SfxStoringHelper(); @@ -60,7 +89,8 @@ public: std::u16string_view aSlotName, css::uno::Sequence< css::beans::PropertyValue >& aArgsSequence, bool bPreselectPassword, - SignatureState nDocumentSignatureState ); + SignatureState nDocumentSignatureState, + bool bIsAsync ); static bool CheckFilterOptionsAppearance( const css::uno::Reference< css::container::XNameAccess >& xFilterCFG, diff --git a/sfx2/source/doc/guisaveas.cxx b/sfx2/source/doc/guisaveas.cxx index 7cce6b515db4..d95d2bb2c289 100644 --- a/sfx2/source/doc/guisaveas.cxx +++ b/sfx2/source/doc/guisaveas.cxx @@ -18,6 +18,7 @@ */ #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp> +#include <com/sun/star/ui/dialogs/XAsynchronousExecutableDialog.hpp> #include <com/sun/star/ui/dialogs/XFilePicker3.hpp> #include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp> #include <com/sun/star/ui/dialogs/CommonFilePickerElementIds.hpp> @@ -55,16 +56,20 @@ #include <tools/debug.hxx> #include <comphelper/diagnose_ex.hxx> #include <tools/urlobj.hxx> +#include <tools/json_writer.hxx> +#include <tools/urlobj.hxx> #include <comphelper/processfactory.hxx> #include <comphelper/propertysequence.hxx> #include <comphelper/propertyvalue.hxx> #include <comphelper/sequenceashashmap.hxx> #include <comphelper/mimeconfighelper.hxx> #include <comphelper/lok.hxx> +#include <LibreOfficeKit/LibreOfficeKitEnums.h> #include <utility> #include <vcl/svapp.hxx> #include <vcl/weld.hxx> #include <o3tl/char16_t2wchar_t.hxx> +#include <unotools/tempfile.hxx> #include <sfx2/sfxsids.hrc> #include <sfx2/strings.hrc> @@ -72,6 +77,8 @@ #include <sfx2/filedlghelper.hxx> #include <sfx2/app.hxx> #include <sfx2/sfxuno.hxx> +#include <sfx2/viewsh.hxx> +#include <sfx2/bindings.hxx> #include <alienwarn.hxx> #include <memory> @@ -261,10 +268,15 @@ class ModelData_Impl std::unique_ptr<::comphelper::SequenceAsHashMap> m_pDocumentPropsHM; std::unique_ptr<::comphelper::SequenceAsHashMap> m_pModulePropsHM; + uno::Reference<beans::XPropertyAccess> m_xFilterProperties; + uno::Reference<ui::dialogs::XAsynchronousExecutableDialog> m_xFilterDialog; + ::comphelper::SequenceAsHashMap m_aMediaDescrHM; bool m_bRecommendReadOnly; + DECL_LINK(OptionsDialogClosedHdl, css::ui::dialogs::DialogClosedEvent*, void); + public: ModelData_Impl( SfxStoringHelper& aOwner, uno::Reference< frame::XModel > xModel, @@ -296,7 +308,7 @@ public: uno::Sequence< beans::PropertyValue > GetPreselectedFilter_Impl( sal_Int16 nStoreMode ); uno::Sequence< beans::PropertyValue > GetDocServiceDefaultFilter(); - bool ExecuteFilterDialog_Impl( const OUString& aFilterName ); + bool ExecuteFilterDialog_Impl( const OUString& aFilterName, bool bAsync ); sal_Int8 CheckSaveAcceptable( sal_Int8 nCurStatus ); sal_Int8 CheckStateForSave(); @@ -322,7 +334,6 @@ public: OUString GetRecommendedDir( const OUString& aSuggestedDir ); OUString GetRecommendedName( const OUString& aSuggestedName, const OUString& aTypeName ); - }; @@ -343,6 +354,8 @@ ModelData_Impl::~ModelData_Impl() FreeDocumentProps(); m_pDocumentPropsHM.reset(); m_pModulePropsHM.reset(); + if (m_xFilterProperties) + m_xFilterProperties.clear(); } @@ -535,7 +548,7 @@ uno::Sequence< beans::PropertyValue > ModelData_Impl::GetPreselectedFilter_Impl( } -bool ModelData_Impl::ExecuteFilterDialog_Impl( const OUString& aFilterName ) +bool ModelData_Impl::ExecuteFilterDialog_Impl( const OUString& aFilterName, bool bIsAsync ) { bool bDialogUsed = false; @@ -557,15 +570,31 @@ bool ModelData_Impl::ExecuteFilterDialog_Impl( const OUString& aFilterName ) {"ParentWindow", uno::Any(SfxStoringHelper::GetModelXWindow(m_xModel))}, })); - uno::Reference< ui::dialogs::XExecutableDialog > xFilterDialog( - comphelper::getProcessServiceFactory()->createInstanceWithArguments(aServiceName, aDialogArgs), uno::UNO_QUERY ); - uno::Reference< beans::XPropertyAccess > xFilterProperties( xFilterDialog, uno::UNO_QUERY ); + uno::Reference< beans::XPropertyAccess > xFilterProperties; + uno::Reference< ui::dialogs::XExecutableDialog > xFilterDialog; + uno::Reference< ui::dialogs::XAsynchronousExecutableDialog > xAsyncFilterDialog; + uno::Reference< document::XExporter > xExporter; - if( xFilterDialog.is() && xFilterProperties.is() ) + if ( bIsAsync ) + { + xAsyncFilterDialog = uno::Reference< ui::dialogs::XAsynchronousExecutableDialog >( + comphelper::getProcessServiceFactory()->createInstanceWithArguments( aServiceName, aDialogArgs ), uno::UNO_QUERY ); + OSL_ENSURE(xAsyncFilterDialog.is(), "ModelData_Impl::ExecuteFilterDialog_Impl: Dialog is not async!"); + xFilterProperties = uno::Reference< beans::XPropertyAccess >( xAsyncFilterDialog, uno::UNO_QUERY ); + xExporter = uno::Reference< document::XExporter >( xAsyncFilterDialog, uno::UNO_QUERY ); + } + else + { + xFilterDialog = uno::Reference< ui::dialogs::XExecutableDialog >( + comphelper::getProcessServiceFactory()->createInstanceWithArguments( aServiceName, aDialogArgs ), uno::UNO_QUERY ); + xFilterProperties = uno::Reference< beans::XPropertyAccess >( xFilterDialog, uno::UNO_QUERY ); + xExporter = uno::Reference< document::XExporter >( xFilterDialog, uno::UNO_QUERY ); + } + + if ( xFilterProperties.is() && ( xFilterDialog.is() || xAsyncFilterDialog.is() ) ) { bDialogUsed = true; - uno::Reference< document::XExporter > xExporter( xFilterDialog, uno::UNO_QUERY ); if( xExporter.is() ) xExporter->setSourceDocument( GetModel() ); @@ -573,19 +602,32 @@ bool ModelData_Impl::ExecuteFilterDialog_Impl( const OUString& aFilterName ) GetMediaDescr() >> aPropsForDialog; xFilterProperties->setPropertyValues( aPropsForDialog ); - if( !xFilterDialog->execute() ) + if ( bIsAsync ) { - throw task::ErrorCodeIOException( - ("ModelData_Impl::ExecuteFilterDialog_Impl:" - " ERRCODE_IO_ABORT"), - uno::Reference< uno::XInterface >(), - sal_uInt32(ERRCODE_IO_ABORT)); - } + m_xFilterProperties = xFilterProperties; + m_xFilterDialog = xAsyncFilterDialog; + + auto aDialogClosedListener = rtl::Reference(new svt::DialogClosedListener()); + aDialogClosedListener->SetDialogClosedLink( LINK( this, ModelData_Impl, OptionsDialogClosedHdl ) ); - const uno::Sequence< beans::PropertyValue > aPropsFromDialog = - xFilterProperties->getPropertyValues(); - for ( const auto& rProp : aPropsFromDialog ) - GetMediaDescr()[rProp.Name] = rProp.Value; + m_xFilterDialog->startExecuteModal( aDialogClosedListener ); + } + else + { + if( !xFilterDialog->execute() ) + { + throw task::ErrorCodeIOException( + ("ModelData_Impl::ExecuteFilterDialog_Impl:" + " ERRCODE_IO_ABORT"), + uno::Reference< uno::XInterface >(), + sal_uInt32(ERRCODE_IO_ABORT)); + } + + const uno::Sequence< beans::PropertyValue > aPropsFromDialog = + xFilterProperties->getPropertyValues(); + for ( const auto& rProp : aPropsFromDialog ) + GetMediaDescr()[rProp.Name] = rProp.Value; + } } } } @@ -611,6 +653,34 @@ bool ModelData_Impl::ExecuteFilterDialog_Impl( const OUString& aFilterName ) return bDialogUsed; } +void SfxStoringHelper::CallFinishGUIStoreModel() +{ + ::comphelper::SequenceAsHashMap::const_iterator aFileNameIter = m_xModelData->GetMediaDescr().find( OUString("URL") ); + uno::Sequence< beans::PropertyValue > aFilterProps = m_xModelData->GetPreselectedFilter_Impl( m_nStoreMode ); + const OUString aFilterFromMediaDescr = m_xModelData->GetMediaDescr().getUnpackedValueOrDefault( aFilterNameString, OUString() ); + const OUString aOldFilterName = m_xModelData->GetDocProps().getUnpackedValueOrDefault( aFilterNameString, OUString() ); + ::comphelper::SequenceAsHashMap aFilterPropsHM( aFilterProps ); + OUString aFilterName = aFilterPropsHM.getUnpackedValueOrDefault( "Name", OUString() ); + + SfxStoringHelper::FinishGUIStoreModel(aFileNameIter, *m_xModelData, m_bRemote, m_nStoreMode, aFilterProps, + m_bSetStandardName, m_bPreselectPassword, m_bDialogUsed, + aFilterFromMediaDescr, aOldFilterName, m_aArgsSequence, aFilterName); + + if (SfxViewShell::Current()) + SfxViewShell::Current()->SetStoringHelper(nullptr); +} + +IMPL_LINK( ModelData_Impl, OptionsDialogClosedHdl, css::ui::dialogs::DialogClosedEvent*, pEvt, void ) +{ + if (pEvt->DialogResult == RET_OK && m_xFilterProperties) + { + const uno::Sequence< beans::PropertyValue > aPropsFromDialog = m_xFilterProperties->getPropertyValues(); + for ( const auto& rProp : aPropsFromDialog ) + GetMediaDescr()[rProp.Name] = rProp.Value; + + m_pOwner->CallFinishGUIStoreModel(); + } +} sal_Int8 ModelData_Impl::CheckSaveAcceptable( sal_Int8 nCurStatus ) { @@ -994,12 +1064,18 @@ bool ModelData_Impl::OutputFileDialog( sal_Int16 nStoreMode, // aFilterName is a pure output parameter, pDialogParams is an in/out parameter OUString aFilterName; - if ( pFileDlg->Execute( pDialogParams, aFilterName ) != ERRCODE_NONE ) + // in LOK case we don't show File Picker so it will fail, but execute to do other preparations + if ( pFileDlg->Execute( pDialogParams, aFilterName ) != ERRCODE_NONE + && !comphelper::LibreOfficeKit::isActive() ) { throw task::ErrorCodeIOException( "ModelData_Impl::OutputFileDialog: ERRCODE_IO_ABORT", uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_IO_ABORT)); } + else if (comphelper::LibreOfficeKit::isActive()) + { + aFilterName = aPreselectedFilterPropsHM.getUnpackedValueOrDefault( "Name", OUString() ); + } // the following two arguments can not be converted in MediaDescriptor, // so they should be removed from the ItemSet after retrieving @@ -1022,9 +1098,6 @@ bool ModelData_Impl::OutputFileDialog( sal_Int16 nStoreMode, const OUString aFilterFromMediaDescr = GetMediaDescr().getUnpackedValueOrDefault( sFilterNameString, OUString() ); const OUString aOldFilterName = GetDocProps().getUnpackedValueOrDefault( sFilterNameString, OUString() ); - const OUString sFilterOptionsString(aFilterOptionsString); - const OUString sFilterDataString(aFilterDataString); - if ( aFilterName == aFilterFromMediaDescr ) { // preserve current settings if any @@ -1034,32 +1107,32 @@ bool ModelData_Impl::OutputFileDialog( sal_Int16 nStoreMode, if ( aFilterFromMediaDescr == aOldFilterName ) { ::comphelper::SequenceAsHashMap::const_iterator aIter = - GetDocProps().find( sFilterOptionsString ); + GetDocProps().find( aFilterOptionsString ); if ( aIter != GetDocProps().end() - && GetMediaDescr().find( sFilterOptionsString ) == GetMediaDescr().end() ) + && GetMediaDescr().find( aFilterOptionsString ) == GetMediaDescr().end() ) GetMediaDescr()[aIter->first] = aIter->second; - aIter = GetDocProps().find( sFilterDataString ); + aIter = GetDocProps().find( aFilterDataString ); if ( aIter != GetDocProps().end() - && GetMediaDescr().find( sFilterDataString ) == GetMediaDescr().end() ) + && GetMediaDescr().find( aFilterDataString ) == GetMediaDescr().end() ) GetMediaDescr()[aIter->first] = aIter->second; } } else { - GetMediaDescr().erase( sFilterDataString ); - GetMediaDescr().erase( sFilterOptionsString ); + GetMediaDescr().erase( aFilterDataString ); + GetMediaDescr().erase( aFilterOptionsString ); if ( aFilterName == aOldFilterName ) { // merge filter option of the document filter ::comphelper::SequenceAsHashMap::const_iterator aIter = - GetDocProps().find( sFilterOptionsString ); + GetDocProps().find( aFilterOptionsString ); if ( aIter != GetDocProps().end() ) GetMediaDescr()[aIter->first] = aIter->second; - aIter = GetDocProps().find( sFilterDataString ); + aIter = GetDocProps().find( aFilterDataString ); if ( aIter != GetDocProps().end() ) GetMediaDescr()[aIter->first] = aIter->second; } @@ -1083,8 +1156,8 @@ bool ModelData_Impl::OutputFileDialog( sal_Int16 nStoreMode, aVal >>= bUseFilterOptions; if ( !bUseFilterOptions ) bUseFilterOptions = - ( GetMediaDescr().find( sFilterDataString ) == GetMediaDescr().end() - && GetMediaDescr().find( sFilterOptionsString ) == GetMediaDescr().end() ); + ( GetMediaDescr().find( aFilterDataString ) == GetMediaDescr().end() + && GetMediaDescr().find( aFilterOptionsString ) == GetMediaDescr().end() ); } catch( const lang::IllegalArgumentException& ) {} @@ -1309,24 +1382,26 @@ bool SfxStoringHelper::GUIStoreModel( const uno::Reference< frame::XModel >& xMo std::u16string_view aSlotName, uno::Sequence< beans::PropertyValue >& aArgsSequence, bool bPreselectPassword, - SignatureState nDocumentSignatureState ) + SignatureState nDocumentSignatureState, + bool bIsAsync) { - ModelData_Impl aModelData( *this, xModel, aArgsSequence ); - - bool bDialogUsed = false; + m_xModelData = std::make_shared<ModelData_Impl>( *this, xModel, aArgsSequence ); + m_aArgsSequence = aArgsSequence; + ModelData_Impl& aModelData = *m_xModelData; - INetURLObject aURL; + m_bDialogUsed = false; - bool bSetStandardName = false; // can be set only for SaveAs + m_bSetStandardName = false; // can be set only for SaveAs + m_bPreselectPassword = bPreselectPassword; // parse the slot name - bool bRemote = false; - sal_Int16 nStoreMode = getStoreModeFromSlotName( aSlotName ); + m_bRemote = false; + m_nStoreMode = getStoreModeFromSlotName( aSlotName ); - if ( nStoreMode == SAVEASREMOTE_REQUESTED ) + if ( m_nStoreMode == SAVEASREMOTE_REQUESTED ) { - nStoreMode = SAVEAS_REQUESTED; - bRemote = true; + m_nStoreMode = SAVEAS_REQUESTED; + m_bRemote = true; } sal_Int8 nStatusSave = STATUS_NO_ACTION; @@ -1338,10 +1413,10 @@ bool SfxStoringHelper::GUIStoreModel( const uno::Reference< frame::XModel >& xMo bool bSaveACopy = false; aSaveACopyIter->second >>= bSaveACopy; if ( bSaveACopy ) - nStoreMode = EXPORT_REQUESTED | SAVEACOPY_REQUESTED | WIDEEXPORT_REQUESTED; + m_nStoreMode = EXPORT_REQUESTED | SAVEACOPY_REQUESTED | WIDEEXPORT_REQUESTED; } // handle the special cases - if ( nStoreMode & SAVEAS_REQUESTED ) + if ( m_nStoreMode & SAVEAS_REQUESTED ) { ::comphelper::SequenceAsHashMap::const_iterator aSaveToIter = aModelData.GetMediaDescr().find( OUString("SaveTo") ); @@ -1350,16 +1425,16 @@ bool SfxStoringHelper::GUIStoreModel( const uno::Reference< frame::XModel >& xMo bool bWideExport = false; aSaveToIter->second >>= bWideExport; if ( bWideExport ) - nStoreMode = EXPORT_REQUESTED | WIDEEXPORT_REQUESTED; + m_nStoreMode = EXPORT_REQUESTED | WIDEEXPORT_REQUESTED; } // if saving is not acceptable the warning must be shown even in case of SaveAs operation - if ( ( nStoreMode & SAVEAS_REQUESTED ) && aModelData.CheckSaveAcceptable( STATUS_SAVEAS ) == STATUS_NO_ACTION ) + if ( ( m_nStoreMode & SAVEAS_REQUESTED ) && aModelData.CheckSaveAcceptable( STATUS_SAVEAS ) == STATUS_NO_ACTION ) throw task::ErrorCodeIOException( "SfxStoringHelper::GUIStoreModel: ERRCODE_IO_ABORT", uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_IO_ABORT)); } - else if ( nStoreMode & SAVE_REQUESTED ) + else if ( m_nStoreMode & SAVE_REQUESTED ) { // if saving is not acceptable by the configuration the warning must be shown nStatusSave = aModelData.CheckSaveAcceptable( STATUS_SAVE ); @@ -1383,13 +1458,13 @@ bool SfxStoringHelper::GUIStoreModel( const uno::Reference< frame::XModel >& xMo else if ( nStatusSave != STATUS_SAVE ) { // this should be a usual SaveAs operation - nStoreMode = SAVEAS_REQUESTED; + m_nStoreMode = SAVEAS_REQUESTED; if ( nStatusSave == STATUS_SAVEAS_STANDARDNAME ) - bSetStandardName = true; + m_bSetStandardName = true; } } - if (!comphelper::LibreOfficeKit::isActive() && !( nStoreMode & EXPORT_REQUESTED ) ) + if (!comphelper::LibreOfficeKit::isActive() && !( m_nStoreMode & EXPORT_REQUESTED ) ) { // if it is no export, warn user that the signature will be removed if ( SignatureState::OK == nDocumentSignatureState @@ -1409,7 +1484,7 @@ bool SfxStoringHelper::GUIStoreModel( const uno::Reference< frame::XModel >& xMo } } - if ( nStoreMode & SAVE_REQUESTED && nStatusSave == STATUS_SAVE ) + if ( m_nStoreMode & SAVE_REQUESTED && nStatusSave == STATUS_SAVE ) { // Document properties can contain streams that should be freed before storing aModelData.FreeDocumentProps(); @@ -1436,7 +1511,7 @@ bool SfxStoringHelper::GUIStoreModel( const uno::Reference< frame::XModel >& xMo } // preselect a filter for the storing process - uno::Sequence< beans::PropertyValue > aFilterProps = aModelData.GetPreselectedFilter_Impl( nStoreMode ); + uno::Sequence< beans::PropertyValue > aFilterProps = aModelData.GetPreselectedFilter_Impl( m_nStoreMode ); DBG_ASSERT( aFilterProps.hasElements(), "No filter for storing!\n" ); if ( !aFilterProps.hasElements() ) @@ -1447,33 +1522,50 @@ bool SfxStoringHelper::GUIStoreModel( const uno::Reference< frame::XModel >& xMo ::comphelper::SequenceAsHashMap aFilterPropsHM( aFilterProps ); OUString aFilterName = aFilterPropsHM.getUnpackedValueOrDefault( "Name", OUString() ); - const OUString sFilterNameString(aFilterNameString); + const OUString aFilterFromMediaDescr = aModelData.GetMediaDescr().getUnpackedValueOrDefault( aFilterNameString, OUString() ); + const OUString aOldFilterName = aModelData.GetDocProps().getUnpackedValueOrDefault( aFilterNameString, OUString() ); - const OUString aFilterFromMediaDescr = aModelData.GetMediaDescr().getUnpackedValueOrDefault( sFilterNameString, OUString() ); - const OUString aOldFilterName = aModelData.GetDocProps().getUnpackedValueOrDefault( sFilterNameString, OUString() ); - - bool bUseFilterOptions = false; ::comphelper::SequenceAsHashMap::const_iterator aFileNameIter = aModelData.GetMediaDescr().find( OUString("URL") ); - const OUString sFilterOptionsString(aFilterOptionsString); - const OUString sFilterDataString(aFilterDataString); - - bool bPDFOptions = (nStoreMode & PDFEXPORT_REQUESTED) && !(nStoreMode & PDFDIRECTEXPORT_REQUESTED); - bool bEPUBOptions = (nStoreMode & EPUBEXPORT_REQUESTED) && !(nStoreMode & EPUBDIRECTEXPORT_REQUESTED); - if ( ( nStoreMode & EXPORT_REQUESTED ) && (bPDFOptions || bEPUBOptions) ) + bool bPDFOptions = (m_nStoreMode & PDFEXPORT_REQUESTED) && !(m_nStoreMode & PDFDIRECTEXPORT_REQUESTED); + bool bEPUBOptions = (m_nStoreMode & EPUBEXPORT_REQUESTED) && !(m_nStoreMode & EPUBDIRECTEXPORT_REQUESTED); + if ( ( m_nStoreMode & EXPORT_REQUESTED ) && (bPDFOptions || bEPUBOptions) ) { // this is PDF or EPUB export, the filter options dialog should be shown before the export - aModelData.GetMediaDescr()[sFilterNameString] <<= aFilterName; + aModelData.GetMediaDescr()[aFilterNameString] <<= aFilterName; if ( aModelData.GetMediaDescr().find( "FilterFlags" ) == aModelData.GetMediaDescr().end() - && aModelData.GetMediaDescr().find( sFilterOptionsString ) == aModelData.GetMediaDescr().end() - && aModelData.GetMediaDescr().find( sFilterDataString ) == aModelData.GetMediaDescr().end() ) + && aModelData.GetMediaDescr().find( aFilterOptionsString ) == aModelData.GetMediaDescr().end() + && aModelData.GetMediaDescr().find( aFilterDataString ) == aModelData.GetMediaDescr().end() ) { // execute filter options dialog since no options are set in the media descriptor - if ( aModelData.ExecuteFilterDialog_Impl( aFilterName ) ) - bDialogUsed = true; + if ( aModelData.ExecuteFilterDialog_Impl( aFilterName, bIsAsync ) ) + m_bDialogUsed = true; } } + if (bIsAsync) + return false; + + return SfxStoringHelper::FinishGUIStoreModel(aFileNameIter, aModelData, m_bRemote, m_nStoreMode, aFilterProps, + m_bSetStandardName, m_bPreselectPassword, m_bDialogUsed, + aFilterFromMediaDescr, aOldFilterName, aArgsSequence, aFilterName); +} + +bool SfxStoringHelper::FinishGUIStoreModel(::comphelper::SequenceAsHashMap::const_iterator& aFileNameIter, + ModelData_Impl& aModelData, bool bRemote, sal_Int16 nStoreMode, + uno::Sequence< beans::PropertyValue >& aFilterProps, + bool bSetStandardName, bool bPreselectPassword, bool bDialogUsed, + std::u16string_view aFilterFromMediaDescr, + std::u16string_view aOldFilterName, + uno::Sequence< beans::PropertyValue >& aArgsSequence, + OUString aFilterName) +{ + const OUString sFilterNameString(aFilterNameString); + const OUString sFilterOptionsString(aFilterOptionsString); + const OUString sFilterDataString(aFilterDataString); + bool bUseFilterOptions = false; + INetURLObject aURL; + if ( aFileNameIter == aModelData.GetMediaDescr().end() ) { sal_Int16 nDialog = SFX2_IMPL_DIALOG_CONFIG; @@ -1605,7 +1697,7 @@ bool SfxStoringHelper::GUIStoreModel( const uno::Reference< frame::XModel >& xMo && ( ( nStoreMode & EXPORT_REQUESTED ) || bUseFilterOptions ) ) { // execute filter options dialog - if ( aModelData.ExecuteFilterDialog_Impl( aFilterName ) ) + if ( aModelData.ExecuteFilterDialog_Impl( aFilterName, false ) ) { bDialogUsed = true; // check if the file is a pdf or not and change the storing mode at convenience @@ -1681,7 +1773,7 @@ bool SfxStoringHelper::GUIStoreModel( const uno::Reference< frame::XModel >& xMo } // Launch PDF viewer - if ( nStoreMode & PDFEXPORT_REQUESTED ) + if ( nStoreMode & PDFEXPORT_REQUESTED && !comphelper::LibreOfficeKit::isActive() ) { FilterConfigItem aItem(u"Office.Common/Filter/PDF/Export/"); bool aViewPDF = aItem.ReadBool( "ViewPDFAfterExport", false ); @@ -1693,6 +1785,16 @@ bool SfxStoringHelper::GUIStoreModel( const uno::Reference< frame::XModel >& xMo } } + if ( comphelper::LibreOfficeKit::isActive() ) + { + if ( SfxViewShell* pShell = SfxViewShell::Current() ) + { + OUString sURL = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ); + pShell->libreOfficeKitViewCallback( LOK_CALLBACK_EXPORT_FILE, + OUStringToOString(sURL, RTL_TEXTENCODING_UTF8).getStr() ); + } + } + return bDialogUsed; } diff --git a/sfx2/source/doc/objserv.cxx b/sfx2/source/doc/objserv.cxx index f0bc6172ab1d..35716406cd80 100644 --- a/sfx2/source/doc/objserv.cxx +++ b/sfx2/source/doc/objserv.cxx @@ -590,6 +590,7 @@ void SfxObjectShell::ExecFile_Impl(SfxRequest &rReq) bool bIsPDFExport = false; bool bIsAutoRedact = false; + bool bIsAsync = false; std::vector<std::pair<RedactionTarget, OUString>> aRedactionTargets; switch(nId) { @@ -896,6 +897,11 @@ void SfxObjectShell::ExecFile_Impl(SfxRequest &rReq) case SID_SAVEASREMOTE: case SID_SAVEDOC: { + // so far only pdf and epub support Async interface + if (comphelper::LibreOfficeKit::isActive() && rReq.GetCallMode() == SfxCallMode::ASYNCHRON + && (nId == SID_EXPORTDOCASEPUB || nId == SID_EXPORTDOCASPDF)) + bIsAsync = true; + // derived class may decide to abort this if( !QuerySlotExecutable( nId ) ) { @@ -1014,7 +1020,9 @@ void SfxObjectShell::ExecFile_Impl(SfxRequest &rReq) if ( !pSlot ) throw uno::Exception("no slot", nullptr); - SfxStoringHelper aHelper; + std::shared_ptr<SfxStoringHelper> xHelper = std::make_shared<SfxStoringHelper>(); + if (bIsAsync && SfxViewShell::Current()) + SfxViewShell::Current()->SetStoringHelper(xHelper); if ( QueryHiddenInformation( bIsPDFExport ? HiddenWarningFact::WhenCreatingPDF : HiddenWarningFact::WhenSaving, nullptr ) != RET_YES ) { @@ -1036,11 +1044,12 @@ void SfxObjectShell::ExecFile_Impl(SfxRequest &rReq) ExecuteSlot(aRequest); } - aHelper.GUIStoreModel( GetModel(), + xHelper->GUIStoreModel( GetModel(), OUString::createFromAscii( pSlot->GetUnoName() ), aDispatchArgs, bPreselectPassword, - GetDocumentSignatureState() ); + GetDocumentSignatureState(), + bIsAsync ); if (bMailPrepareExport) { diff --git a/sfx2/source/view/ipclient.cxx b/sfx2/source/view/ipclient.cxx index 03ed38a78f3b..fd52355f3ed5 100644 --- a/sfx2/source/view/ipclient.cxx +++ b/sfx2/source/view/ipclient.cxx @@ -922,7 +922,8 @@ ErrCode SfxInPlaceClient::DoVerb(sal_Int32 nVerb) u"SaveAs", aDispatchArgs, false, - SignatureState::NOSIGNATURES ); + SignatureState::NOSIGNATURES, + false ); } catch( const task::ErrorCodeIOException& aErrorEx ) { diff --git a/vcl/jsdialog/enabled.cxx b/vcl/jsdialog/enabled.cxx index 9a54ed001d39..3f58aa100b94 100644 --- a/vcl/jsdialog/enabled.cxx +++ b/vcl/jsdialog/enabled.cxx @@ -97,6 +97,15 @@ bool isBuilderEnabled(std::u16string_view rUIFile, bool bMobile) || rUIFile == u"xmlsec/ui/certpage.ui" || rUIFile == u"xmlsec/ui/digitalsignaturesdialog.ui" || rUIFile == u"xmlsec/ui/viewcertdialog.ui" + || rUIFile == u"filter/ui/pdfoptionsdialog.ui" + || rUIFile == u"filter/ui/pdfgeneralpage.ui" + || rUIFile == u"filter/ui/pdfviewpage.ui" + || rUIFile == u"filter/ui/pdfuserinterfacepage.ui" + || rUIFile == u"filter/ui/pdfsecuritypage.ui" + || rUIFile == u"filter/ui/pdflinkspage.ui" + || rUIFile == u"filter/ui/warnpdfdialog.ui" + || rUIFile == u"filter/ui/pdfsignpage.ui" + || rUIFile == u"writerperfect/ui/exportepub.ui" ) { return true;