Kaydet (Commit) 8c987fab authored tarafından Jan Holesovsky's avatar Jan Holesovsky

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
üst c0f37892
......@@ -23,6 +23,7 @@
#include <com/sun/star/frame/Desktop.hpp>
#include <com/sun/star/frame/XDispatch.hpp>
#include <com/sun/star/frame/XDispatchProvider.hpp>
#include <com/sun/star/frame/XNotifyingDispatch.hpp>
#include <com/sun/star/util/URL.hpp>
#include <com/sun/star/util/URLTransformer.hpp>
......@@ -30,7 +31,7 @@ using namespace css;
namespace comphelper {
bool dispatchCommand(const OUString& rCommand, const css::uno::Sequence<css::beans::PropertyValue>& rArguments)
bool dispatchCommand(const OUString& rCommand, const css::uno::Sequence<css::beans::PropertyValue>& rArguments, uno::Reference<css::frame::XDispatchResultListener> aListener)
{
// Target where we will execute the .uno: command
uno::Reference<uno::XComponentContext> xContext = ::comphelper::getProcessComponentContext();
......@@ -54,7 +55,11 @@ bool dispatchCommand(const OUString& rCommand, const css::uno::Sequence<css::bea
return false;
// And do the work...
xDisp->dispatch(aCommandURL, rArguments);
uno::Reference<frame::XNotifyingDispatch> xNotifyingDisp(xDisp, uno::UNO_QUERY);
if (xNotifyingDisp.is())
xNotifyingDisp->dispatchWithNotification(aCommandURL, rArguments, aListener);
else
xNotifyingDisp->dispatch(aCommandURL, rArguments);
return true;
}
......
......@@ -22,6 +22,8 @@ namespace desktop {
{
css::uno::Reference<css::lang::XComponent> mxComponent;
std::shared_ptr< LibreOfficeKitDocumentClass > m_pDocumentClass;
LibreOfficeKitCallback mpCallback;
void *mpCallbackData;
explicit LibLODocument_Impl(const css::uno::Reference <css::lang::XComponent> &xComponent);
~LibLODocument_Impl();
......
......@@ -36,6 +36,8 @@
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/container/XNameAccess.hpp>
#include <com/sun/star/frame/Desktop.hpp>
#include <com/sun/star/frame/DispatchResultEvent.hpp>
#include <com/sun/star/frame/DispatchResultState.hpp>
#include <com/sun/star/frame/XStorable.hpp>
#include <com/sun/star/lang/Locale.hpp>
#include <com/sun/star/lang/XComponent.hpp>
......@@ -241,7 +243,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,
......@@ -884,9 +887,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<LibLODocument_Impl*>(pThis);
pDocument->mpCallback = pCallback;
pDocument->mpCallbackData = pData;
if (comphelper::LibreOfficeKit::isViewCallback())
{
if (SfxViewShell* pViewShell = SfxViewFrame::Current()->GetViewShell())
......@@ -951,13 +959,69 @@ static void jsonToPropertyValues(const char* pJSON, uno::Sequence<beans::Propert
rPropertyValues = comphelper::containerToSequence(aArguments);
}
static void doc_postUnoCommand(LibreOfficeKitDocument* /*pThis*/, const char* pCommand, const char* pArguments)
/** Class to react on finishing of a dispatched command.
This will call a LOK_COMMAND_FINISHED callback when postUnoCommand was
called with the parameter requesting the notification.
@see LibreOfficeKitCallbackType::LOK_CALLBACK_UNO_COMMAND_RESULT.
*/
class DispatchResultListener : public cppu::WeakImplHelper<css::frame::XDispatchResultListener>
{
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<beans::PropertyValue> aPropertyValues;
jsonToPropertyValues(pArguments, aPropertyValues);
if (!comphelper::dispatchCommand(aCommand, aPropertyValues))
bool bResult = false;
LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(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";
}
......
......@@ -12,6 +12,11 @@
#include <stddef.h>
#ifdef LOK_USE_UNSTABLE_API
// the unstable API needs C99's bool
#include <stdbool.h>
#endif
#include <LibreOfficeKit/LibreOfficeKitTypes.h>
#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,
......
......@@ -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);
}
/**
......
......@@ -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;
......
......@@ -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:
......
......@@ -14,6 +14,7 @@
#include <rtl/ustring.hxx>
#include <com/sun/star/uno/Sequence.hxx>
#include <com/sun/star/beans/PropertyValue.hpp>
#include <com/sun/star/frame/XDispatchResultListener.hpp>
namespace comphelper
{
......@@ -24,7 +25,9 @@ namespace comphelper
@return true on success.
*/
COMPHELPER_DLLPUBLIC bool dispatchCommand(const OUString& rCommand, const css::uno::Sequence<css::beans::PropertyValue>& rArguments);
COMPHELPER_DLLPUBLIC bool dispatchCommand(const OUString& rCommand,
const css::uno::Sequence<css::beans::PropertyValue>& rArguments,
css::uno::Reference<css::frame::XDispatchResultListener> aListener = css::uno::Reference<css::frame::XDispatchResultListener>());
}
......
......@@ -596,7 +596,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.
......@@ -672,6 +672,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);
......@@ -774,7 +780,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);
}
}
......@@ -1172,6 +1182,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);
......
......@@ -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);
......
......@@ -169,6 +169,7 @@ struct LOEvent
///@{
const gchar* m_pCommand;
gchar* m_pArguments;
gboolean m_bNotifyWhenFinished;
///@}
/// @name open_document parameter
......@@ -221,6 +222,7 @@ struct LOEvent
: m_nType(type)
, m_pCommand(0)
, m_pArguments(0)
, m_bNotifyWhenFinished(false)
, m_pPath(0)
, m_bEdit(false)
, m_nPartMode(0)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment