summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Holesovsky <kendy@collabora.com>2016-02-02 22:59:34 +0100
committerJan Holesovsky <kendy@collabora.com>2016-02-03 10:33:04 +0100
commitc406c90289baa12663a382c7ed664f2cf93b75ab (patch)
tree55654fcd867a2cd650f2615e26e793b32d936375
parentad680b8600aac8c26996b3af2d1414c3c0ebe4ee (diff)
lok interaction handler: Add handling of io and network errors.
Change-Id: If7c84a7b24f2072439718fb0c473b73243f2ecc1
-rw-r--r--desktop/source/lib/init.cxx39
-rw-r--r--desktop/source/lib/lokinteractionhandler.cxx194
-rw-r--r--desktop/source/lib/lokinteractionhandler.hxx32
-rw-r--r--include/LibreOfficeKit/LibreOfficeKitEnums.h14
-rw-r--r--libreofficekit/source/gtk/lokdocview.cxx17
5 files changed, 263 insertions, 33 deletions
diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index 5010bd0347c3..3ae825ae4966 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -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)
{
diff --git a/desktop/source/lib/lokinteractionhandler.cxx b/desktop/source/lib/lokinteractionhandler.cxx
index 5bb164c7d2ca..bb287ff3af96 100644
--- a/desktop/source/lib/lokinteractionhandler.cxx
+++ b/desktop/source/lib/lokinteractionhandler.cxx
@@ -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;
}
diff --git a/desktop/source/lib/lokinteractionhandler.hxx b/desktop/source/lib/lokinteractionhandler.hxx
index e21d7570f253..337e21591cc2 100644
--- a/desktop/source/lib/lokinteractionhandler.hxx
+++ b/desktop/source/lib/lokinteractionhandler.hxx
@@ -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();
diff --git a/include/LibreOfficeKit/LibreOfficeKitEnums.h b/include/LibreOfficeKit/LibreOfficeKitEnums.h
index b615bd94f9d1..5ce8610267ec 100644
--- a/include/LibreOfficeKit/LibreOfficeKitEnums.h
+++ b/include/LibreOfficeKit/LibreOfficeKitEnums.h
@@ -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;
diff --git a/libreofficekit/source/gtk/lokdocview.cxx b/libreofficekit/source/gtk/lokdocview.cxx
index 17104a00b838..737157bf515c 100644
--- a/libreofficekit/source/gtk/lokdocview.cxx
+++ b/libreofficekit/source/gtk/lokdocview.cxx
@@ -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;