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

lok interaction handler: Add handling of io and network errors.

Change-Id: If7c84a7b24f2072439718fb0c473b73243f2ecc1
üst ad680b86
......@@ -252,7 +252,7 @@ static OUString getAbsoluteURL(const char* pURL)
return OUString();
}
static void jsonToPropertyValues(const char* pJSON, uno::Sequence<beans::PropertyValue>& rPropertyValues)
static std::vector<beans::PropertyValue> jsonToPropertyValuesVector(const char* pJSON)
{
std::vector<beans::PropertyValue> aArguments;
if (pJSON && pJSON[0] != '\0')
......@@ -279,11 +279,11 @@ static void jsonToPropertyValues(const char* pJSON, uno::Sequence<beans::Propert
else if (rType == "unsigned short")
aValue.Value <<= static_cast<sal_uInt16>(OString(rValue.c_str()).toUInt32());
else
SAL_WARN("desktop.lib", "jsonToPropertyValues: unhandled type '"<<rType<<"'");
SAL_WARN("desktop.lib", "jsonToPropertyValuesVector: unhandled type '"<<rType<<"'");
aArguments.push_back(aValue);
}
}
rPropertyValues = comphelper::containerToSequence(aArguments);
return aArguments;
}
extern "C"
......@@ -531,7 +531,7 @@ static LibreOfficeKitDocument* lo_documentLoadWithOptions(LibreOfficeKit* pThis,
beans::PropertyState_DIRECT_VALUE);
rtl::Reference<LOKInteractionHandler> const pInteraction(
new LOKInteractionHandler(::comphelper::getProcessComponentContext(), pLib));
new LOKInteractionHandler(::comphelper::getProcessComponentContext(), "load", pLib));
auto const pair(pLib->mInteractionMap.insert(std::make_pair(aURL.toUtf8(), pInteraction)));
comphelper::ScopeGuard const g([&] () {
if (pair.second)
......@@ -985,9 +985,9 @@ static void doc_initializeForRendering(LibreOfficeKitDocument* pThis,
if (pDoc)
{
doc_iniUnoCommands();
uno::Sequence<beans::PropertyValue> aPropertyValues;
jsonToPropertyValues(pArguments, aPropertyValues);
pDoc->initializeForTiledRendering(aPropertyValues);
pDoc->initializeForTiledRendering(
comphelper::containerToSequence(jsonToPropertyValuesVector(pArguments)));
}
}
......@@ -1077,20 +1077,33 @@ public:
static void doc_postUnoCommand(LibreOfficeKitDocument* pThis, const char* pCommand, const char* pArguments, bool bNotifyWhenFinished)
{
OUString aCommand(pCommand, strlen(pCommand), RTL_TEXTENCODING_UTF8);
LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
uno::Sequence<beans::PropertyValue> aPropertyValues;
jsonToPropertyValues(pArguments, aPropertyValues);
bool bResult = false;
std::vector<beans::PropertyValue> aPropertyValuesVector(jsonToPropertyValuesVector(pArguments));
LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
// handle potential interaction
if (aCommand == ".uno:Save")
{
rtl::Reference<LOKInteractionHandler> const pInteraction(
new LOKInteractionHandler(::comphelper::getProcessComponentContext(), "save", gImpl, pDocument));
uno::Reference<task::XInteractionHandler2> const xInteraction(pInteraction.get());
beans::PropertyValue aValue;
aValue.Name = "InteractionHandler";
aValue.Value <<= xInteraction;
aPropertyValuesVector.push_back(aValue);
}
bool bResult = false;
if (bNotifyWhenFinished && pDocument->mpCallback)
{
bResult = comphelper::dispatchCommand(aCommand, aPropertyValues,
bResult = comphelper::dispatchCommand(aCommand, comphelper::containerToSequence(aPropertyValuesVector),
new DispatchResultListener(pCommand, pDocument->mpCallback, pDocument->mpCallbackData));
}
else
bResult = comphelper::dispatchCommand(aCommand, aPropertyValues);
bResult = comphelper::dispatchCommand(aCommand, comphelper::containerToSequence(aPropertyValuesVector));
if (!bResult)
{
......
......@@ -19,12 +19,21 @@
#include "lokinteractionhandler.hxx"
#include <boost/property_tree/json_parser.hpp>
#include <rtl/ref.hxx>
#include <cppuhelper/supportsservice.hxx>
#include <com/sun/star/task/XInteractionAbort.hpp>
#include <com/sun/star/task/XInteractionApprove.hpp>
#include <com/sun/star/task/XInteractionPassword2.hpp>
#include <com/sun/star/ucb/InteractiveNetworkConnectException.hpp>
#include <com/sun/star/ucb/InteractiveNetworkOffLineException.hpp>
#include <com/sun/star/ucb/InteractiveIOException.hpp>
#include <com/sun/star/ucb/InteractiveNetworkReadException.hpp>
#include <com/sun/star/ucb/InteractiveNetworkResolveNameException.hpp>
#include <com/sun/star/ucb/InteractiveNetworkWriteException.hpp>
#include <../../inc/lib/init.hxx>
......@@ -34,8 +43,12 @@ using namespace com::sun::star;
LOKInteractionHandler::LOKInteractionHandler(
uno::Reference<uno::XComponentContext> const & /*rxContext*/,
desktop::LibLibreOffice_Impl *const pLOKit)
const OString& rCommand,
desktop::LibLibreOffice_Impl *const pLOKit,
desktop::LibLODocument_Impl *const pLOKDocument)
: m_pLOKit(pLOKit)
, m_pLOKDocument(pLOKDocument)
, m_command(rCommand)
, m_usePassword(false)
{
assert(m_pLOKit);
......@@ -78,8 +91,157 @@ throw (uno::RuntimeException, std::exception)
handleInteractionRequest(xRequest);
}
sal_Bool LOKInteractionHandler::handlePasswordRequest(const uno::Sequence<uno::Reference<task::XInteractionContinuation>> &rContinuations, const task::DocumentPasswordRequest2& passwordRequest)
void LOKInteractionHandler::postError(css::task::InteractionClassification classif, const char* kind, ErrCode code, const OUString &message)
{
const char *classification = "error";
switch (classif)
{
case task::InteractionClassification_ERROR: break;
case task::InteractionClassification_WARNING: classification = "warning"; break;
case task::InteractionClassification_INFO: classification = "info"; break;
case task::InteractionClassification_QUERY: classification = "query"; break;
default: assert(false); break;
}
// create the JSON representation
boost::property_tree::ptree aTree;
aTree.put("classification", classification);
aTree.put("cmd", m_command.getStr());
aTree.put("kind", kind);
aTree.put("code", code);
aTree.put("message", message.toUtf8());
std::stringstream aStream;
boost::property_tree::write_json(aStream, aTree);
if (m_pLOKDocument)
m_pLOKDocument->mpCallback(LOK_CALLBACK_ERROR, aStream.str().c_str(), m_pLOKDocument->mpCallbackData);
else
m_pLOKit->mpCallback(LOK_CALLBACK_ERROR, aStream.str().c_str(), m_pLOKit->mpCallbackData);
}
namespace {
/// Just approve the interaction.
void selectApproved(uno::Sequence<uno::Reference<task::XInteractionContinuation>> const &rContinuations)
{
for (sal_Int32 i = 0; i < rContinuations.getLength(); ++i)
{
uno::Reference<task::XInteractionApprove> xApprove(rContinuations[i], uno::UNO_QUERY);
if (xApprove.is())
xApprove->select();
}
}
}
bool LOKInteractionHandler::handleIOException(const css::uno::Sequence<css::uno::Reference<css::task::XInteractionContinuation>> &rContinuations, const css::uno::Any& rRequest)
{
ucb::InteractiveIOException aIoException;
if (!(rRequest >>= aIoException))
return false;
static ErrCode const aErrorCode[ucb::IOErrorCode_WRONG_VERSION + 1] =
{
ERRCODE_IO_ABORT,
ERRCODE_IO_ACCESSDENIED,
ERRCODE_IO_ALREADYEXISTS,
ERRCODE_IO_BADCRC,
ERRCODE_IO_CANTCREATE,
ERRCODE_IO_CANTREAD,
ERRCODE_IO_CANTSEEK,
ERRCODE_IO_CANTTELL,
ERRCODE_IO_CANTWRITE,
ERRCODE_IO_CURRENTDIR,
ERRCODE_IO_DEVICENOTREADY,
ERRCODE_IO_NOTSAMEDEVICE,
ERRCODE_IO_GENERAL,
ERRCODE_IO_INVALIDACCESS,
ERRCODE_IO_INVALIDCHAR,
ERRCODE_IO_INVALIDDEVICE,
ERRCODE_IO_INVALIDLENGTH,
ERRCODE_IO_INVALIDPARAMETER,
ERRCODE_IO_ISWILDCARD,
ERRCODE_IO_LOCKVIOLATION,
ERRCODE_IO_MISPLACEDCHAR,
ERRCODE_IO_NAMETOOLONG,
ERRCODE_IO_NOTEXISTS,
ERRCODE_IO_NOTEXISTSPATH,
ERRCODE_IO_NOTSUPPORTED,
ERRCODE_IO_NOTADIRECTORY,
ERRCODE_IO_NOTAFILE,
ERRCODE_IO_OUTOFSPACE,
ERRCODE_IO_TOOMANYOPENFILES,
ERRCODE_IO_OUTOFMEMORY,
ERRCODE_IO_PENDING,
ERRCODE_IO_RECURSIVE,
ERRCODE_IO_UNKNOWN,
ERRCODE_IO_WRITEPROTECTED,
ERRCODE_IO_WRONGFORMAT,
ERRCODE_IO_WRONGVERSION,
};
postError(aIoException.Classification, "io", aErrorCode[aIoException.Code], "");
selectApproved(rContinuations);
return true;
}
bool LOKInteractionHandler::handleNetworkException(const uno::Sequence<uno::Reference<task::XInteractionContinuation>> &rContinuations, const uno::Any &rRequest)
{
ucb::InteractiveNetworkException aNetworkException;
if (!(rRequest >>= aNetworkException))
return false;
ErrCode nErrorCode;
OUString aMessage;
ucb::InteractiveNetworkOffLineException aOffLineException;
ucb::InteractiveNetworkResolveNameException aResolveNameException;
ucb::InteractiveNetworkConnectException aConnectException;
ucb::InteractiveNetworkReadException aReadException;
ucb::InteractiveNetworkWriteException aWriteException;
if (rRequest >>= aOffLineException)
{
nErrorCode = ERRCODE_INET_OFFLINE;
}
else if (rRequest >>= aResolveNameException)
{
nErrorCode = ERRCODE_INET_NAME_RESOLVE;
aMessage = aResolveNameException.Server;
}
else if (rRequest >>= aConnectException)
{
nErrorCode = ERRCODE_INET_CONNECT;
aMessage = aConnectException.Server;
}
else if (rRequest >>= aReadException)
{
nErrorCode = ERRCODE_INET_READ;
aMessage = aReadException.Diagnostic;
}
else if (rRequest >>= aWriteException)
{
nErrorCode = ERRCODE_INET_WRITE;
aMessage = aWriteException.Diagnostic;
}
else
{
nErrorCode = ERRCODE_INET_GENERAL;
}
postError(aNetworkException.Classification, "network", nErrorCode, aMessage);
selectApproved(rContinuations);
return true;
}
bool LOKInteractionHandler::handlePasswordRequest(const uno::Sequence<uno::Reference<task::XInteractionContinuation>> &rContinuations, const uno::Any &rRequest)
{
task::DocumentPasswordRequest2 passwordRequest;
if (!(rRequest >>= passwordRequest))
return false;
if (m_pLOKit->hasOptionalFeature((passwordRequest.IsRequestPasswordToModify)
? LOK_FEATURE_DOCUMENT_PASSWORD_TO_MODIFY
: LOK_FEATURE_DOCUMENT_PASSWORD))
......@@ -134,28 +296,26 @@ sal_Bool LOKInteractionHandler::handlePasswordRequest(const uno::Sequence<uno::R
}
}
}
return sal_True;
return true;
}
sal_Bool SAL_CALL LOKInteractionHandler::handleInteractionRequest(
const uno::Reference<task::XInteractionRequest>& xRequest)
throw (uno::RuntimeException, std::exception)
const uno::Reference<task::XInteractionRequest>& xRequest) throw (uno::RuntimeException, std::exception)
{
uno::Sequence<uno::Reference<task::XInteractionContinuation>> const &rContinuations = xRequest->getContinuations();
uno::Any const request(xRequest->getRequest());
task::DocumentPasswordRequest2 passwordRequest;
if (request >>= passwordRequest)
return handlePasswordRequest(rContinuations, passwordRequest);
// TODO: add LOK api that allows handling this for real, for the moment we
// just set the interaction as 'Approved'
for (sal_Int32 i = 0; i < rContinuations.getLength(); ++i)
{
uno::Reference<task::XInteractionApprove> xApprove(rContinuations[i], uno::UNO_QUERY);
if (xApprove.is())
xApprove->select();
}
if (handleIOException(rContinuations, request))
return true;
if (handleNetworkException(rContinuations, request))
return true;
if (handlePasswordRequest(rContinuations, request))
return true;
// TODO: perform more interactions 'for real' like the above
selectApproved(rContinuations);
return sal_True;
}
......
......@@ -22,13 +22,18 @@
#include <osl/conditn.hxx>
#include <cppuhelper/implbase.hxx>
#include <tools/errcode.hxx>
#include <com/sun/star/lang/XInitialization.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/task/DocumentPasswordRequest2.hpp>
#include <com/sun/star/task/InteractionHandler.hpp>
#include <com/sun/star/ucb/InteractiveNetworkException.hpp>
namespace desktop { struct LibLibreOffice_Impl; }
namespace desktop {
struct LibLibreOffice_Impl;
struct LibLODocument_Impl;
}
/** InteractionHandler is an interface that provides the user with various dialogs / error messages.
......@@ -44,6 +49,11 @@ class LOKInteractionHandler: public cppu::WeakImplHelper<com::sun::star::lang::X
{
private:
desktop::LibLibreOffice_Impl * m_pLOKit;
desktop::LibLODocument_Impl * m_pLOKDocument;
/// Command for which we use this interaction handler (like "load", "save", "saveas", ...)
OString m_command;
OUString m_Password;
bool m_usePassword;
osl::Condition m_havePassword;
......@@ -51,14 +61,30 @@ private:
LOKInteractionHandler(const LOKInteractionHandler&) = delete;
LOKInteractionHandler& operator=(const LOKInteractionHandler&) = delete;
sal_Bool handlePasswordRequest(const css::uno::Sequence<css::uno::Reference<css::task::XInteractionContinuation>> &rContinuations, const css::task::DocumentPasswordRequest2& passwordRequest);
/** Call the LOK_CALLBACK_ERROR on the LOK document (if available) or LOK lib.
The error itself is a JSON message, like:
{
"classification": "error" | "warning" | "info"
"kind": "network" etc.
"code": 403 | 404 | ...
"message": freeform description
}
*/
void postError(css::task::InteractionClassification classif, const char* kind, ErrCode code, const OUString &message);
bool handleIOException(const css::uno::Sequence<css::uno::Reference<css::task::XInteractionContinuation>> &rContinuations, const css::uno::Any& rRequest);
bool handleNetworkException(const css::uno::Sequence<css::uno::Reference<css::task::XInteractionContinuation>> &rContinuations, const css::uno::Any& rRequest);
bool handlePasswordRequest(const css::uno::Sequence<css::uno::Reference<css::task::XInteractionContinuation>> &rContinuations, const css::uno::Any& rRequest);
public:
void SetPassword(char const* pPassword);
explicit LOKInteractionHandler(
com::sun::star::uno::Reference<com::sun::star::uno::XComponentContext> const & rxContext,
desktop::LibLibreOffice_Impl *);
const OString& rCommand,
desktop::LibLibreOffice_Impl *,
desktop::LibLODocument_Impl *pLOKDocumt = nullptr);
virtual ~LOKInteractionHandler();
......
......@@ -265,6 +265,20 @@ typedef enum
* lok::Office::setDocumentPassword().
*/
LOK_CALLBACK_DOCUMENT_PASSWORD_TO_MODIFY,
/**
* An error happened.
*
* The payload returns information further identifying the error, like:
*
* {
* "classification": "error" | "warning" | "info"
* "kind": "network" etc.
* "code": 403 | 404 | ...
* "message": freeform description
* }
*/
LOK_CALLBACK_ERROR,
}
LibreOfficeKitCallbackType;
......
......@@ -781,6 +781,18 @@ static void formulaChanged(LOKDocView* pDocView, const std::string& rString)
g_signal_emit(pDocView, doc_view_signals[FORMULA_CHANGED], 0, rString.c_str());
}
static void reportError(LOKDocView* /*pDocView*/, const std::string& rString)
{
GtkWidget *dialog = gtk_message_dialog_new(nullptr,
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_CLOSE,
"%s",
rString.c_str());
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
}
static void
setPart(LOKDocView* pDocView, const std::string& rString)
{
......@@ -1119,6 +1131,11 @@ callback (gpointer pData)
formulaChanged(pDocView, pCallback->m_aPayload);
}
break;
case LOK_CALLBACK_ERROR:
{
reportError(pDocView, pCallback->m_aPayload);
}
break;
default:
g_assert(false);
break;
......
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