sw: avoid popup window for the EmbeddedObject property of an UNO OLE object

The old behavior was that in case loading the native data of the
embedded object failed, then we presented a popup to the user, but we
still returned a valid com.sun.star.comp.embed.OCommonEmbeddedObject.

Given that the return valid is desired even in the error case, don't
turn the error popup into an UNO exception, rather redirect the popup to
SAL_WARN().

This is meant to be consistent with other UNO API functions that pass
down an "is API" boolean to internal code to control if interactive
behavior is allowed or not.

One extreme would be to do this only for the EmbeddedObject property of
frames, the other one would be to do this for more object types. Go with
a middle ground for now, so all properties of Writer frame objects use
this, but leave other object types unchanged.

Change-Id: I655fcb3780e96cecc7ed3f01ded52948d013172e
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/123752
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Tested-by: Jenkins
This commit is contained in:
Miklos Vajna 2021-10-18 16:22:45 +02:00
parent 67fa088be7
commit 86e07d951b
5 changed files with 72 additions and 1 deletions

View file

@ -65,11 +65,18 @@ public:
static void RegisterDisplay(BasicDisplayErrorFunc*);
static void RegisterDisplay(WindowDisplayErrorFunc*);
static void SetLock(bool bLock);
static bool GetLock();
static void Reset();
private:
DisplayFnPtr pDsp;
bool bIsWindowDsp;
bool m_bLock;
sal_uInt16 nNextError;
std::vector<ErrorHandler*> errorHandlers;

Binary file not shown.

View file

@ -16,6 +16,7 @@
#include <comphelper/propertyvalue.hxx>
#include <comphelper/sequenceashashmap.hxx>
#include <vcl/errinf.hxx>
#include <wrtsh.hxx>
#include <unotextrange.hxx>
@ -184,6 +185,36 @@ CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testViewCursorTextFrame)
xStorable->storeToURL(maTempFile.GetURL(), aStoreArgs);
}
/// Fails the test if an error popup would be presented.
static void BasicDisplayErrorHandler(const OUString& /*rErr*/, const OUString& /*rAction*/)
{
CPPUNIT_ASSERT(false);
}
CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testBrokenEmbeddedObject)
{
// Given a document with a broken embedded object (the XML markup is not well-formed):
load(DATA_DIRECTORY, "broken-embedded-object.odt");
uno::Reference<text::XTextEmbeddedObjectsSupplier> xSupplier(mxComponent, uno::UNO_QUERY);
uno::Reference<container::XIndexAccess> xObjects(xSupplier->getEmbeddedObjects(),
uno::UNO_QUERY);
uno::Reference<beans::XPropertySet> xObject(xObjects->getByIndex(0), uno::UNO_QUERY);
uno::Reference<lang::XServiceInfo> xEmbeddedObject;
// Get the property first, which initializes Draw, which would overwrite our error handler.
xObject->getPropertyValue("EmbeddedObject") >>= xEmbeddedObject;
ErrorRegistry::RegisterDisplay(&BasicDisplayErrorHandler);
// When trying to load that embedded object:
xObject->getPropertyValue("EmbeddedObject") >>= xEmbeddedObject;
// Then make sure we get a non-empty reference and an error popup it not shown:
CPPUNIT_ASSERT(xEmbeddedObject.is());
// Without the accompanying fix in place, we got this reference, but first an error popup was
// shown to the user.
CPPUNIT_ASSERT(
xEmbeddedObject->supportsService("com.sun.star.comp.embed.OCommonEmbeddedObject"));
}
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

View file

@ -112,6 +112,7 @@
#include <comphelper/servicehelper.hxx>
#include <cppuhelper/supportsservice.hxx>
#include <sal/log.hxx>
#include <vcl/errinf.hxx>
#include <svx/unobrushitemhelper.hxx>
#include <svx/xbtmpit.hxx>
@ -1977,9 +1978,28 @@ void SwXFrame::setPropertyValue(const OUString& rPropertyName, const ::uno::Any&
throw uno::RuntimeException();
}
namespace
{
/// Redirect error popups to developer warnings for the duration of the UNO API call.
class DisplayLockGuard
{
bool m_bLock;
public:
DisplayLockGuard()
{
m_bLock = ErrorRegistry::GetLock();
ErrorRegistry::SetLock(true);
}
~DisplayLockGuard() { ErrorRegistry::SetLock(m_bLock); }
};
}
uno::Any SwXFrame::getPropertyValue(const OUString& rPropertyName)
{
SolarMutexGuard aGuard;
DisplayLockGuard aDisplayGuard;
uno::Any aAny;
SwFrameFormat* pFormat = GetFrameFormat();
const SfxItemPropertyMapEntry* pEntry = m_pPropSet->getPropertyMap().getByName(rPropertyName);

View file

@ -51,6 +51,7 @@ bool ErrorStringFactory::CreateString(const ErrorInfo* pInfo, OUString& rStr)
ErrorRegistry::ErrorRegistry()
: pDsp(nullptr)
, bIsWindowDsp(false)
, m_bLock(false)
, nNextError(0)
{
for(DynamicErrorInfo*& rp : ppDynErrInfo)
@ -71,6 +72,18 @@ void ErrorRegistry::RegisterDisplay(WindowDisplayErrorFunc *aDsp)
rData.pDsp = reinterpret_cast< DisplayFnPtr >(aDsp);
}
void ErrorRegistry::SetLock(bool bLock)
{
ErrorRegistry& rData = GetErrorRegistry();
rData.m_bLock = bLock;
}
bool ErrorRegistry::GetLock()
{
ErrorRegistry& rData = GetErrorRegistry();
return rData.m_bLock;
}
void ErrorRegistry::Reset()
{
ErrorRegistry &rData = GetErrorRegistry();
@ -157,7 +170,7 @@ DialogMask ErrorHandler::HandleError(ErrCode nErrCodeId, weld::Window *pParent,
OUString aErr;
if (ErrorStringFactory::CreateString(pInfo.get(), aErr))
{
if(!rData.pDsp)
if (!rData.pDsp || rData.m_bLock)
{
SAL_WARN( "vcl", "Action: " << aAction << "Error: " << aErr);
}