From 1c5b0b2f4a2e883f5da3a4afb3cadaf695d58fac Mon Sep 17 00:00:00 2001 From: Jan Holesovsky Date: Tue, 3 Nov 2015 13:20:06 +0100 Subject: [PATCH 264/398] lok: Introduce LOK_CALLBACK_UNO_COMMAND_RESULT callback. Posting of the .uno:Something commands is asynchronous. To be able to find out when eg. .uno:Save finished, this commit introduces a callback that fires when that happens. To be able to receive such a notification, the appropriate postUnoCommand() must be called with 'true' as the parameter for bNotifyWhenFinished (defaults to 'false'). Change-Id: I254939ebc8ea5f309ae39686dcaaeddd5148b0c9 (cherry picked from commit 8c987fababbddb6e4f81b0cd717b59b9a9ff9be0) --- comphelper/source/misc/dispatchcommand.cxx | 9 ++- desktop/inc/lib/init.hxx | 2 + desktop/source/lib/init.cxx | 74 ++++++++++++++++++++-- include/LibreOfficeKit/LibreOfficeKit.h | 8 ++- include/LibreOfficeKit/LibreOfficeKit.hxx | 4 +- include/LibreOfficeKit/LibreOfficeKitEnums.h | 17 ++++- include/LibreOfficeKit/LibreOfficeKitGtk.h | 4 +- include/comphelper/dispatchcommand.hxx | 5 +- .../qa/gtktiledviewer/gtktiledviewer.cxx | 15 ++++- libreofficekit/source/gtk/lokdocview.cxx | 34 +++++++++- libreofficekit/source/gtk/tilebuffer.hxx | 2 + 11 files changed, 157 insertions(+), 17 deletions(-) diff --git a/comphelper/source/misc/dispatchcommand.cxx b/comphelper/source/misc/dispatchcommand.cxx index 5de05542dbb4..a5a6dde0885d 100644 --- a/comphelper/source/misc/dispatchcommand.cxx +++ b/comphelper/source/misc/dispatchcommand.cxx @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -30,7 +31,7 @@ using namespace css; namespace comphelper { -bool dispatchCommand(const OUString& rCommand, const css::uno::Sequence& rArguments) +bool dispatchCommand(const OUString& rCommand, const css::uno::Sequence& rArguments, uno::Reference aListener) { // Target where we will execute the .uno: command uno::Reference xContext = ::comphelper::getProcessComponentContext(); @@ -54,7 +55,11 @@ bool dispatchCommand(const OUString& rCommand, const css::uno::Sequencedispatch(aCommandURL, rArguments); + uno::Reference xNotifyingDisp(xDisp, uno::UNO_QUERY); + if (xNotifyingDisp.is()) + xNotifyingDisp->dispatchWithNotification(aCommandURL, rArguments, aListener); + else + xNotifyingDisp->dispatch(aCommandURL, rArguments); return true; } diff --git a/desktop/inc/lib/init.hxx b/desktop/inc/lib/init.hxx index d3a42fb10bde..4f878d26c007 100644 --- a/desktop/inc/lib/init.hxx +++ b/desktop/inc/lib/init.hxx @@ -20,6 +20,8 @@ namespace desktop { { uno::Reference mxComponent; std::shared_ptr< LibreOfficeKitDocumentClass > m_pDocumentClass; + LibreOfficeKitCallback mpCallback; + void *mpCallbackData; explicit LibLODocument_Impl(const uno::Reference &xComponent); ~LibLODocument_Impl(); diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx index 98747ea62e3a..9ba26c414d8c 100644 --- a/desktop/source/lib/init.cxx +++ b/desktop/source/lib/init.cxx @@ -35,6 +35,8 @@ #include #include #include +#include +#include #include #include #include @@ -240,7 +242,8 @@ static void doc_postMouseEvent (LibreOfficeKitDocument* pThis, int nModifier); static void doc_postUnoCommand(LibreOfficeKitDocument* pThis, const char* pCommand, - const char* pArguments); + const char* pArguments, + bool bNotifyWhenFinished); static void doc_setTextSelection (LibreOfficeKitDocument* pThis, int nType, int nX, @@ -883,9 +886,14 @@ static void doc_initializeForRendering(LibreOfficeKitDocument* pThis) } static void doc_registerCallback(LibreOfficeKitDocument* pThis, - LibreOfficeKitCallback pCallback, - void* pData) + LibreOfficeKitCallback pCallback, + void* pData) { + LibLODocument_Impl* pDocument = static_cast(pThis); + + pDocument->mpCallback = pCallback; + pDocument->mpCallbackData = pData; + if (comphelper::LibreOfficeKit::isViewCallback()) { if (SfxViewShell* pViewShell = SfxViewFrame::Current()->GetViewShell()) @@ -950,13 +958,69 @@ static void jsonToPropertyValues(const char* pJSON, uno::Sequence +{ + OString maCommand; ///< Command for which this is the result. + LibreOfficeKitCallback mpCallback; ///< Callback to call. + void* mpCallbackData; ///< The callback's data. + +public: + DispatchResultListener(const char* pCommand, LibreOfficeKitCallback pCallback, void* pCallbackData) + : maCommand(pCommand) + , mpCallback(pCallback) + , mpCallbackData(pCallbackData) + { + assert(mpCallback); + } + + virtual void SAL_CALL dispatchFinished(const css::frame::DispatchResultEvent& rEvent) throw(css::uno::RuntimeException, std::exception) override + { + boost::property_tree::ptree aTree; + aTree.put("commandName", maCommand.getStr()); + + if (rEvent.State != frame::DispatchResultState::DONTKNOW) + { + bool bSuccess = (rEvent.State == frame::DispatchResultState::SUCCESS); + aTree.put("success", bSuccess); + } + + // TODO UNO Any rEvent.Result -> JSON + // aTree.put("result": "..."); + + std::stringstream aStream; + boost::property_tree::write_json(aStream, aTree); + mpCallback(LOK_CALLBACK_UNO_COMMAND_RESULT, strdup(aStream.str().c_str()), mpCallbackData); + } + + virtual void SAL_CALL disposing(const css::lang::EventObject&) throw (css::uno::RuntimeException, std::exception) override {} +}; + +static void doc_postUnoCommand(LibreOfficeKitDocument* pThis, const char* pCommand, const char* pArguments, bool bNotifyWhenFinished) { OUString aCommand(pCommand, strlen(pCommand), RTL_TEXTENCODING_UTF8); uno::Sequence aPropertyValues; jsonToPropertyValues(pArguments, aPropertyValues); - if (!comphelper::dispatchCommand(aCommand, aPropertyValues)) + bool bResult = false; + + LibLODocument_Impl* pDocument = static_cast(pThis); + + if (bNotifyWhenFinished && pDocument->mpCallback) + { + bResult = comphelper::dispatchCommand(aCommand, aPropertyValues, + new DispatchResultListener(pCommand, pDocument->mpCallback, pDocument->mpCallbackData)); + } + else + bResult = comphelper::dispatchCommand(aCommand, aPropertyValues); + + if (!bResult) { gImpl->maLastExceptionMsg = "Failed to dispatch the .uno: command"; } diff --git a/include/LibreOfficeKit/LibreOfficeKit.h b/include/LibreOfficeKit/LibreOfficeKit.h index d83717b4a809..c887f5f64b8a 100644 --- a/include/LibreOfficeKit/LibreOfficeKit.h +++ b/include/LibreOfficeKit/LibreOfficeKit.h @@ -12,6 +12,11 @@ #include +#ifdef LOK_USE_UNSTABLE_API +// the unstable API needs C99's bool +#include +#endif + #include #ifdef __cplusplus @@ -144,7 +149,8 @@ struct _LibreOfficeKitDocumentClass /// @see lok::Document::postUnoCommand void (*postUnoCommand) (LibreOfficeKitDocument* pThis, const char* pCommand, - const char* pArguments); + const char* pArguments, + bool bNotifyWhenFinished); /// @see lok::Document::setTextSelection void (*setTextSelection) (LibreOfficeKitDocument* pThis, diff --git a/include/LibreOfficeKit/LibreOfficeKit.hxx b/include/LibreOfficeKit/LibreOfficeKit.hxx index 6673cd731eb7..c51339fa3ba8 100644 --- a/include/LibreOfficeKit/LibreOfficeKit.hxx +++ b/include/LibreOfficeKit/LibreOfficeKit.hxx @@ -220,9 +220,9 @@ public: * @param pCommand uno command to be posted to the document, like ".uno:Bold" * @param pArguments arguments of the uno command. */ - inline void postUnoCommand(const char* pCommand, const char* pArguments = 0) + inline void postUnoCommand(const char* pCommand, const char* pArguments = 0, bool bNotifyWhenFinished = false) { - mpDoc->pClass->postUnoCommand(mpDoc, pCommand, pArguments); + mpDoc->pClass->postUnoCommand(mpDoc, pCommand, pArguments, bNotifyWhenFinished); } /** diff --git a/include/LibreOfficeKit/LibreOfficeKitEnums.h b/include/LibreOfficeKit/LibreOfficeKitEnums.h index 459da5d196f4..86d9e6bfd873 100644 --- a/include/LibreOfficeKit/LibreOfficeKitEnums.h +++ b/include/LibreOfficeKit/LibreOfficeKitEnums.h @@ -180,7 +180,22 @@ typedef enum * - searchResultSelection is an array of part-number and rectangle list * pairs, in LOK_CALLBACK_SET_PART / LOK_CALLBACK_TEXT_SELECTION format. */ - LOK_CALLBACK_SEARCH_RESULT_SELECTION + LOK_CALLBACK_SEARCH_RESULT_SELECTION, + + /** + * Result of the UNO command execution when bNotifyWhenFinished was set + * to 'true' during the postUnoCommand() call. + * + * The result returns a success / failure state, and potentially + * additional data: + * + * { + * "commandName": "...", // the command for which this is the result + * "success": true/false, // when the result is "don't know", this is missing + * // TODO "result": "..." // UNO Any converted to JSON (not implemented yet) + * } + */ + LOK_CALLBACK_UNO_COMMAND_RESULT } LibreOfficeKitCallbackType; diff --git a/include/LibreOfficeKit/LibreOfficeKitGtk.h b/include/LibreOfficeKit/LibreOfficeKitGtk.h index 81f42105d374..32cb66963220 100644 --- a/include/LibreOfficeKit/LibreOfficeKitGtk.h +++ b/include/LibreOfficeKit/LibreOfficeKitGtk.h @@ -184,12 +184,14 @@ gboolean lok_doc_view_get_edit (LOKDocView* * @pDocView: the #LOKDocView instance * @pCommand: the command to issue to LO core * @pArguments: the arguments to the given command + * @bNotifyWhenFinished: normally false, but it may be useful for eg. .uno:Save * * Posts the .uno: command to the LibreOfficeKit. */ void lok_doc_view_post_command (LOKDocView* pDocView, const gchar* pCommand, - const gchar* pArguments); + const gchar* pArguments, + gboolean bNotifyWhenFinished); /** * lok_doc_view_pixel_to_twip: diff --git a/include/comphelper/dispatchcommand.hxx b/include/comphelper/dispatchcommand.hxx index 58aa0b940f4e..7b76bd5a0310 100644 --- a/include/comphelper/dispatchcommand.hxx +++ b/include/comphelper/dispatchcommand.hxx @@ -14,6 +14,7 @@ #include #include #include +#include namespace comphelper { @@ -24,7 +25,9 @@ namespace comphelper @return true on success. */ -COMPHELPER_DLLPUBLIC bool dispatchCommand(const OUString& rCommand, const css::uno::Sequence& rArguments); +COMPHELPER_DLLPUBLIC bool dispatchCommand(const OUString& rCommand, + const css::uno::Sequence& rArguments, + css::uno::Reference aListener = css::uno::Reference()); } diff --git a/libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx b/libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx index 795fb4ed7ff7..96a69fcf64f8 100644 --- a/libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx +++ b/libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx @@ -595,7 +595,7 @@ static void doSearch(GtkWidget* pButton, bool bBackwards) std::stringstream aStream; boost::property_tree::write_json(aStream, aTree); - lok_doc_view_post_command(pLOKDocView, ".uno:ExecuteSearch", aStream.str().c_str()); + lok_doc_view_post_command(pLOKDocView, ".uno:ExecuteSearch", aStream.str().c_str(), false); } /// Click handler for the search next button. @@ -671,6 +671,12 @@ static void signalCommand(LOKDocView* pLOKDocView, char* pPayload, gpointer /*pD } } +/// LOKDocView command finished -> just write it to the console, not that useful for the viewer. +static void signalCommandResult(LOKDocView* /*pLOKDocView*/, char* pPayload, gpointer /*pData*/) +{ + fprintf(stderr, "Command finished: %s\n", pPayload); +} + static void loadChanged(LOKDocView* /*pLOKDocView*/, gdouble fValue, gpointer pData) { GtkWidget* pProgressBar = GTK_WIDGET (pData); @@ -773,7 +779,11 @@ static void toggleToolItem(GtkWidget* pWidget, gpointer /*pData*/) GtkToolItem* pItem = GTK_TOOL_ITEM(pWidget); const std::string& rString = rWindow.m_aToolItemCommandNames[pItem]; g_info("toggleToolItem: lok_doc_view_post_command('%s')", rString.c_str()); - lok_doc_view_post_command(pLOKDocView, rString.c_str(), 0); + + // notify about the finished Save + gboolean bNotify = (rString == ".uno:Save"); + + lok_doc_view_post_command(pLOKDocView, rString.c_str(), 0, bNotify); } } @@ -1171,6 +1181,7 @@ static void setupDocView(GtkWidget* pDocView) #endif g_signal_connect(pDocView, "edit-changed", G_CALLBACK(signalEdit), NULL); g_signal_connect(pDocView, "command-changed", G_CALLBACK(signalCommand), NULL); + g_signal_connect(pDocView, "command-result", G_CALLBACK(signalCommandResult), NULL); g_signal_connect(pDocView, "search-not-found", G_CALLBACK(signalSearch), NULL); g_signal_connect(pDocView, "search-result-count", G_CALLBACK(signalSearchResultCount), NULL); g_signal_connect(pDocView, "part-changed", G_CALLBACK(signalPart), NULL); diff --git a/libreofficekit/source/gtk/lokdocview.cxx b/libreofficekit/source/gtk/lokdocview.cxx index 49d5ecc54f65..bcb1d136b749 100644 --- a/libreofficekit/source/gtk/lokdocview.cxx +++ b/libreofficekit/source/gtk/lokdocview.cxx @@ -180,6 +180,7 @@ enum HYPERLINK_CLICKED, CURSOR_CHANGED, SEARCH_RESULT_COUNT, + COMMAND_RESULT, LAST_SIGNAL }; @@ -461,6 +462,11 @@ static void searchResultCount(LOKDocView* pDocView, const std::string& rString) g_signal_emit(pDocView, doc_view_signals[SEARCH_RESULT_COUNT], 0, rString.c_str()); } +static void commandResult(LOKDocView* pDocView, const std::string& rString) +{ + g_signal_emit(pDocView, doc_view_signals[COMMAND_RESULT], 0, rString.c_str()); +} + static void setPart(LOKDocView* pDocView, const std::string& rString) { @@ -752,6 +758,11 @@ callback (gpointer pData) searchResultCount(pDocView, std::to_string(nCount)); } break; + case LOK_CALLBACK_UNO_COMMAND_RESULT: + { + commandResult(pDocView, pCallback->m_aPayload); + } + break; default: g_assert(false); break; @@ -1520,7 +1531,7 @@ postCommandInThread (gpointer data) std::stringstream ss; ss << "lok::Document::postUnoCommand(" << pLOEvent->m_pCommand << ", " << pLOEvent->m_pArguments << ")"; g_info(ss.str().c_str()); - priv->m_pDocument->pClass->postUnoCommand(priv->m_pDocument, pLOEvent->m_pCommand, pLOEvent->m_pArguments); + priv->m_pDocument->pClass->postUnoCommand(priv->m_pDocument, pLOEvent->m_pCommand, pLOEvent->m_pArguments, pLOEvent->m_bNotifyWhenFinished); } static void @@ -2077,6 +2088,7 @@ static void lok_doc_view_class_init (LOKDocViewClass* pClass) G_TYPE_NONE, 4, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT); + /** * LOKDocView::search-result-count: * @pDocView: the #LOKDocView on which the signal is emitted @@ -2092,6 +2104,22 @@ static void lok_doc_view_class_init (LOKDocViewClass* pClass) G_TYPE_NONE, 1, G_TYPE_STRING); + /** + * LOKDocView::command-result: + * @pDocView: the #LOKDocView on which the signal is emitted + * @aCommand: JSON containing the info about the command that finished, + * and its success status. + */ + doc_view_signals[COMMAND_RESULT] = + g_signal_new("command-result", + G_TYPE_FROM_CLASS(pGObjectClass), + G_SIGNAL_RUN_FIRST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, + G_TYPE_STRING); + } SAL_DLLPUBLIC_EXPORT GtkWidget* @@ -2326,7 +2354,8 @@ lok_doc_view_get_edit (LOKDocView* pDocView) SAL_DLLPUBLIC_EXPORT void lok_doc_view_post_command (LOKDocView* pDocView, const gchar* pCommand, - const gchar* pArguments) + const gchar* pArguments, + gboolean bNotifyWhenFinished) { LOKDocViewPrivate& priv = getPrivate(pDocView); GTask* task = g_task_new(pDocView, NULL, NULL, NULL); @@ -2334,6 +2363,7 @@ lok_doc_view_post_command (LOKDocView* pDocView, GError* error = NULL; pLOEvent->m_pCommand = pCommand; pLOEvent->m_pArguments = g_strdup(pArguments); + pLOEvent->m_bNotifyWhenFinished = bNotifyWhenFinished; g_task_set_task_data(task, pLOEvent, LOEvent::destroy); g_thread_pool_push(priv->lokThreadPool, g_object_ref(task), &error); diff --git a/libreofficekit/source/gtk/tilebuffer.hxx b/libreofficekit/source/gtk/tilebuffer.hxx index 5e1ea1a27049..8a8569eeb306 100644 --- a/libreofficekit/source/gtk/tilebuffer.hxx +++ b/libreofficekit/source/gtk/tilebuffer.hxx @@ -171,6 +171,7 @@ struct LOEvent ///@{ const gchar* m_pCommand; gchar* m_pArguments; + gboolean m_bNotifyWhenFinished; ///@} /// @name open_document parameter @@ -223,6 +224,7 @@ struct LOEvent : m_nType(type) , m_pCommand(0) , m_pArguments(0) + , m_bNotifyWhenFinished(false) , m_pPath(0) , m_bEdit(false) , m_nPartMode(0) -- 2.12.0