summaryrefslogtreecommitdiff
path: root/desktop
diff options
context:
space:
mode:
authorAshod Nakashian <ashod.nakashian@collabora.co.uk>2020-08-02 14:52:02 -0400
committerAshod Nakashian <ash@collabora.com>2020-08-11 17:34:47 +0200
commit4fd2679a7a2b0494da84f344ab97b835edf73377 (patch)
tree3c4c043664fbee79758870d270e458b6d378ab0a /desktop
parent95ba7d3eb0a1d78958d43573d73669935364f481 (diff)
sfx2: lok: reliably support multi-documents
Instead of using the current view to set the DocId, we instead make sure that the ShellView object has the DocId set at construction time. This turned out to be necessary in at least one case (which has a unit-test that failed), which is when events fired during the creation of a new view. The cursor position is notified before we have a chance to set the DocId and because of that we miss the notifications (or worse, we end up sending them to all other documents' views in an effort to fix this bug). This approach is clean and always guarantees that all views have the correct DocId set as soon as possible and that all notifications are sent as expected. A unit-test is added to exercise mult-document usage, which exposed a number of bugs and issues that have been addressed in this patch. Change-Id: Icf5145fb1dabd0d029368310c2b9bf73ae927ccc Reviewed-on: https://gerrit.libreoffice.org/c/core/+/99975 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com> Reviewed-by: Michael Meeks <michael.meeks@collabora.com> Reviewed-by: Ashod Nakashian <ash@collabora.com>
Diffstat (limited to 'desktop')
-rw-r--r--desktop/inc/lib/init.hxx3
-rw-r--r--desktop/qa/desktop_lib/test_desktop_lib.cxx100
-rw-r--r--desktop/source/lib/init.cxx36
3 files changed, 124 insertions, 15 deletions
diff --git a/desktop/inc/lib/init.hxx b/desktop/inc/lib/init.hxx
index 237a17a59eee..1a927280e24b 100644
--- a/desktop/inc/lib/init.hxx
+++ b/desktop/inc/lib/init.hxx
@@ -151,7 +151,8 @@ namespace desktop {
std::map<size_t, std::shared_ptr<CallbackFlushHandler>> mpCallbackFlushHandlers;
const int mnDocumentId;
- explicit LibLODocument_Impl(const css::uno::Reference <css::lang::XComponent> &xComponent, int nDocumentId = -1);
+ explicit LibLODocument_Impl(const css::uno::Reference<css::lang::XComponent>& xComponent,
+ int nDocumentId);
~LibLODocument_Impl();
};
diff --git a/desktop/qa/desktop_lib/test_desktop_lib.cxx b/desktop/qa/desktop_lib/test_desktop_lib.cxx
index 7acb50499ae9..f448965c02d7 100644
--- a/desktop/qa/desktop_lib/test_desktop_lib.cxx
+++ b/desktop/qa/desktop_lib/test_desktop_lib.cxx
@@ -225,6 +225,7 @@ public:
void testCalcSaveAs();
void testControlState();
void testMetricField();
+ void testMultiDocuments();
void testABI();
CPPUNIT_TEST_SUITE(DesktopLOKTest);
@@ -287,6 +288,7 @@ public:
CPPUNIT_TEST(testCalcSaveAs);
CPPUNIT_TEST(testControlState);
CPPUNIT_TEST(testMetricField);
+ CPPUNIT_TEST(testMultiDocuments);
CPPUNIT_TEST(testABI);
CPPUNIT_TEST_SUITE_END();
@@ -352,10 +354,13 @@ DesktopLOKTest::loadDocUrlImpl(const OUString& rFileURL, LibreOfficeKitDocumentT
break;
}
+ static int nDocumentIdCounter = 0;
+ SfxViewShell::SetCurrentDocId(ViewShellDocId(nDocumentIdCounter));
uno::Reference<lang::XComponent> xComponent = loadFromDesktop(rFileURL, aService);
CPPUNIT_ASSERT(xComponent.is());
- std::unique_ptr<LibLODocument_Impl> pDocument(new LibLODocument_Impl(xComponent));
+ std::unique_ptr<LibLODocument_Impl> pDocument(new LibLODocument_Impl(xComponent, nDocumentIdCounter));
+ ++nDocumentIdCounter;
return std::make_pair(std::move(pDocument), xComponent);
}
@@ -2987,6 +2992,99 @@ void DesktopLOKTest::testSpellcheckerMultiView()
CPPUNIT_ASSERT_EQUAL(1, pDocument->m_pDocumentClass->getViewsCount(pDocument));
}
+void DesktopLOKTest::testMultiDocuments()
+{
+ // Load a document.
+ uno::Reference<lang::XComponent> xComponent1;
+ std::unique_ptr<LibLODocument_Impl> document1;
+ std::tie(document1, xComponent1) = loadDocImpl("blank_text.odt");
+ LibLODocument_Impl* pDocument1 = document1.get();
+ CPPUNIT_ASSERT_EQUAL(1, pDocument1->m_pDocumentClass->getViewsCount(pDocument1));
+ const int nDocId1 = pDocument1->mnDocumentId;
+
+ const int nDoc1View0 = pDocument1->m_pDocumentClass->getView(pDocument1);
+ CPPUNIT_ASSERT_EQUAL(nDocId1, SfxLokHelper::getDocumentIdOfView(nDoc1View0));
+ const int nDoc1View1 = pDocument1->m_pDocumentClass->createView(pDocument1);
+ CPPUNIT_ASSERT_EQUAL(nDoc1View1, pDocument1->m_pDocumentClass->getView(pDocument1));
+ CPPUNIT_ASSERT_EQUAL(nDocId1, SfxLokHelper::getDocumentIdOfView(nDoc1View1));
+ CPPUNIT_ASSERT_EQUAL(2, pDocument1->m_pDocumentClass->getViewsCount(pDocument1));
+
+ // Validate the views of document 1.
+ std::vector<int> aViewIdsDoc1(2);
+ CPPUNIT_ASSERT(pDocument1->m_pDocumentClass->getViewIds(pDocument1, aViewIdsDoc1.data(), aViewIdsDoc1.size()));
+ CPPUNIT_ASSERT_EQUAL(nDoc1View0, aViewIdsDoc1[0]);
+ CPPUNIT_ASSERT_EQUAL(nDoc1View1, aViewIdsDoc1[1]);
+
+ CPPUNIT_ASSERT_EQUAL(nDoc1View1, pDocument1->m_pDocumentClass->getView(pDocument1));
+ CPPUNIT_ASSERT_EQUAL(nDocId1, SfxLokHelper::getDocumentIdOfView(nDoc1View1));
+ pDocument1->m_pDocumentClass->setView(pDocument1, nDoc1View0);
+ CPPUNIT_ASSERT_EQUAL(nDoc1View0, pDocument1->m_pDocumentClass->getView(pDocument1));
+ CPPUNIT_ASSERT_EQUAL(nDocId1, SfxLokHelper::getDocumentIdOfView(nDoc1View0));
+ pDocument1->m_pDocumentClass->setView(pDocument1, nDoc1View1);
+ CPPUNIT_ASSERT_EQUAL(nDoc1View1, pDocument1->m_pDocumentClass->getView(pDocument1));
+ CPPUNIT_ASSERT_EQUAL(nDocId1, SfxLokHelper::getDocumentIdOfView(nDoc1View1));
+ CPPUNIT_ASSERT_EQUAL(2, pDocument1->m_pDocumentClass->getViewsCount(pDocument1));
+
+ // Load another document.
+ uno::Reference<lang::XComponent> xComponent2;
+ std::unique_ptr<LibLODocument_Impl> document2;
+ std::tie(document2, xComponent2) = loadDocImpl("blank_presentation.odp");
+ LibLODocument_Impl* pDocument2 = document2.get();
+ CPPUNIT_ASSERT_EQUAL(1, pDocument2->m_pDocumentClass->getViewsCount(pDocument2));
+ const int nDocId2 = pDocument2->mnDocumentId;
+
+ const int nDoc2View0 = pDocument2->m_pDocumentClass->getView(pDocument2);
+ CPPUNIT_ASSERT_EQUAL(nDocId2, SfxLokHelper::getDocumentIdOfView(nDoc2View0));
+ const int nDoc2View1 = pDocument2->m_pDocumentClass->createView(pDocument2);
+ CPPUNIT_ASSERT_EQUAL(nDoc2View1, pDocument2->m_pDocumentClass->getView(pDocument2));
+ CPPUNIT_ASSERT_EQUAL(nDocId2, SfxLokHelper::getDocumentIdOfView(nDoc2View1));
+ CPPUNIT_ASSERT_EQUAL(2, pDocument2->m_pDocumentClass->getViewsCount(pDocument2));
+
+ // Validate the views of document 2.
+ std::vector<int> aViewIdsDoc2(2);
+ CPPUNIT_ASSERT(pDocument2->m_pDocumentClass->getViewIds(pDocument2, aViewIdsDoc2.data(), aViewIdsDoc2.size()));
+ CPPUNIT_ASSERT_EQUAL(nDoc2View0, aViewIdsDoc2[0]);
+ CPPUNIT_ASSERT_EQUAL(nDoc2View1, aViewIdsDoc2[1]);
+
+ CPPUNIT_ASSERT_EQUAL(nDoc2View1, pDocument2->m_pDocumentClass->getView(pDocument2));
+ CPPUNIT_ASSERT_EQUAL(nDocId2, SfxLokHelper::getDocumentIdOfView(nDoc2View1));
+ pDocument2->m_pDocumentClass->setView(pDocument2, nDoc2View0);
+ CPPUNIT_ASSERT_EQUAL(nDoc2View0, pDocument2->m_pDocumentClass->getView(pDocument2));
+ CPPUNIT_ASSERT_EQUAL(nDocId2, SfxLokHelper::getDocumentIdOfView(nDoc2View0));
+ pDocument2->m_pDocumentClass->setView(pDocument2, nDoc2View1);
+ CPPUNIT_ASSERT_EQUAL(nDoc2View1, pDocument2->m_pDocumentClass->getView(pDocument2));
+ CPPUNIT_ASSERT_EQUAL(nDocId2, SfxLokHelper::getDocumentIdOfView(nDoc2View1));
+ CPPUNIT_ASSERT_EQUAL(2, pDocument2->m_pDocumentClass->getViewsCount(pDocument2));
+
+ // The views of document1 should be unchanged.
+ CPPUNIT_ASSERT(pDocument1->m_pDocumentClass->getViewIds(pDocument1, aViewIdsDoc1.data(), aViewIdsDoc1.size()));
+ CPPUNIT_ASSERT_EQUAL(nDoc1View0, aViewIdsDoc1[0]);
+ CPPUNIT_ASSERT_EQUAL(nDoc1View1, aViewIdsDoc1[1]);
+ // Switch views in the first doc.
+ CPPUNIT_ASSERT_EQUAL(nDocId1, SfxLokHelper::getDocumentIdOfView(nDoc1View0));
+ pDocument1->m_pDocumentClass->setView(pDocument1, nDoc1View0);
+ CPPUNIT_ASSERT_EQUAL(nDoc1View0, pDocument1->m_pDocumentClass->getView(pDocument1));
+ CPPUNIT_ASSERT_EQUAL(nDocId1, SfxLokHelper::getDocumentIdOfView(nDoc1View1));
+ pDocument1->m_pDocumentClass->destroyView(pDocument1, nDoc1View1);
+ CPPUNIT_ASSERT_EQUAL(1, pDocument1->m_pDocumentClass->getViewsCount(pDocument1));
+
+ // The views of document2 should be unchanged.
+ CPPUNIT_ASSERT(pDocument2->m_pDocumentClass->getViewIds(pDocument2, aViewIdsDoc2.data(), aViewIdsDoc2.size()));
+ CPPUNIT_ASSERT_EQUAL(nDoc2View0, aViewIdsDoc2[0]);
+ CPPUNIT_ASSERT_EQUAL(nDoc2View1, aViewIdsDoc2[1]);
+ // Switch views in the second doc.
+ CPPUNIT_ASSERT_EQUAL(nDocId2, SfxLokHelper::getDocumentIdOfView(nDoc2View0));
+ pDocument2->m_pDocumentClass->setView(pDocument2, nDoc2View0);
+ CPPUNIT_ASSERT_EQUAL(nDoc2View0, pDocument2->m_pDocumentClass->getView(pDocument2));
+ CPPUNIT_ASSERT_EQUAL(nDocId2, SfxLokHelper::getDocumentIdOfView(nDoc2View1));
+ pDocument2->m_pDocumentClass->destroyView(pDocument2, nDoc2View1);
+ CPPUNIT_ASSERT_EQUAL(1, pDocument2->m_pDocumentClass->getViewsCount(pDocument2));
+
+ closeDoc(document2, xComponent2);
+
+ closeDoc(document1, xComponent1);
+}
+
namespace {
constexpr size_t classOffset(int i)
diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index fdd92d2d3430..08a4247513c7 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -1241,6 +1241,8 @@ LibLODocument_Impl::LibLODocument_Impl(const uno::Reference <css::lang::XCompone
: mxComponent(xComponent)
, mnDocumentId(nDocumentId)
{
+ assert(nDocumentId != -1 && "Cannot set mnDocumentId to -1");
+
if (!(m_pDocumentClass = gDocumentClass.lock()))
{
m_pDocumentClass.reset(new LibreOfficeKitDocumentClass);
@@ -2289,7 +2291,6 @@ static LibreOfficeKitDocument* lo_documentLoadWithOptions(LibreOfficeKit* pThis,
LibLODocument_Impl* pDocument = new LibLODocument_Impl(xComponent, nDocumentIdCounter++);
// After loading the document, its initial view is the "current" view.
- SfxLokHelper::setDocumentIdOfView(pDocument->mnDocumentId);
if (pLib->mpCallback)
{
int nState = doc_getSignatureState(pDocument);
@@ -3350,13 +3351,13 @@ static void doc_registerCallback(LibreOfficeKitDocument* pThis,
LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
- int nView = SfxLokHelper::getView();
+ const int nView = SfxLokHelper::getView();
if (nView < 0)
return;
+ const size_t nId = nView;
if (pCallback != nullptr)
{
- size_t nId = nView;
for (auto& pair : pDocument->mpCallbackFlushHandlers)
{
if (pair.first == nId)
@@ -3367,7 +3368,6 @@ static void doc_registerCallback(LibreOfficeKitDocument* pThis,
}
else
{
- size_t nId = nView;
for (auto& pair : pDocument->mpCallbackFlushHandlers)
{
if (pair.first == nId)
@@ -3381,7 +3381,6 @@ static void doc_registerCallback(LibreOfficeKitDocument* pThis,
if (pCallback != nullptr)
{
- size_t nId = nView;
for (const auto& pair : pDocument->mpCallbackFlushHandlers)
{
if (pair.first == nId)
@@ -3389,11 +3388,19 @@ static void doc_registerCallback(LibreOfficeKitDocument* pThis,
pDocument->mpCallbackFlushHandlers[nView]->addViewStates(pair.first);
}
- }
- if (SfxViewShell* pViewShell = SfxViewShell::Current())
+ if (SfxViewShell* pViewShell = SfxViewShell::Current())
+ {
+ pViewShell->registerLibreOfficeKitViewCallback(
+ CallbackFlushHandler::callback, pDocument->mpCallbackFlushHandlers[nView].get());
+ }
+ }
+ else
{
- pViewShell->registerLibreOfficeKitViewCallback(CallbackFlushHandler::callback, pDocument->mpCallbackFlushHandlers[nView].get());
+ if (SfxViewShell* pViewShell = SfxViewShell::Current())
+ {
+ pViewShell->registerLibreOfficeKitViewCallback(nullptr, nullptr);
+ }
}
}
@@ -5146,7 +5153,8 @@ static int doc_createViewWithOptions(LibreOfficeKitDocument* pThis,
const OUString aDeviceFormFactor = extractParameter(aOptions, "DeviceFormFactor");
SfxLokHelper::setDeviceFormFactor(aDeviceFormFactor);
- int nId = SfxLokHelper::createView();
+ LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
+ const int nId = SfxLokHelper::createView(pDocument->mnDocumentId);
#ifdef IOS
(void) pThis;
@@ -5194,24 +5202,26 @@ static int doc_getView(SAL_UNUSED_PARAMETER LibreOfficeKitDocument* /*pThis*/)
return SfxLokHelper::getView();
}
-static int doc_getViewsCount(SAL_UNUSED_PARAMETER LibreOfficeKitDocument* /*pThis*/)
+static int doc_getViewsCount(SAL_UNUSED_PARAMETER LibreOfficeKitDocument* pThis)
{
comphelper::ProfileZone aZone("doc_getViewsCount");
SolarMutexGuard aGuard;
SetLastExceptionMsg();
- return SfxLokHelper::getViewsCount();
+ LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
+ return SfxLokHelper::getViewsCount(pDocument->mnDocumentId);
}
-static bool doc_getViewIds(SAL_UNUSED_PARAMETER LibreOfficeKitDocument* /*pThis*/, int* pArray, size_t nSize)
+static bool doc_getViewIds(SAL_UNUSED_PARAMETER LibreOfficeKitDocument* pThis, int* pArray, size_t nSize)
{
comphelper::ProfileZone aZone("doc_getViewsIds");
SolarMutexGuard aGuard;
SetLastExceptionMsg();
- return SfxLokHelper::getViewIds(pArray, nSize);
+ LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
+ return SfxLokHelper::getViewIds(pDocument->mnDocumentId, pArray, nSize);
}
static void doc_setViewLanguage(SAL_UNUSED_PARAMETER LibreOfficeKitDocument* /*pThis*/, int nId, const char* language)