desktop/inc/lib/init.hxx                       |    3 
 desktop/qa/desktop_lib/test_desktop_lib.cxx    |  100 ++++++++++++++++++++
 desktop/source/lib/init.cxx                    |   36 ++++---
 include/editeng/outliner.hxx                   |    1 
 include/sfx2/lokhelper.hxx                     |   17 ++-
 include/sfx2/viewsh.hxx                        |   15 ++-
 sc/source/ui/view/tabvwshc.cxx                 |    3 
 sd/qa/unit/tiledrendering/LOKitSearchTest.cxx  |    1 
 sd/source/ui/unoidl/unomodel.cxx               |    3 
 sfx2/source/view/lokhelper.cxx                 |  120 +++++++++++++++++--------
 sfx2/source/view/viewimp.hxx                   |    4 
 sfx2/source/view/viewsh.cxx                    |   13 +-
 sw/qa/extras/tiledrendering/tiledrendering.cxx |    2 
 13 files changed, 249 insertions(+), 69 deletions(-)

New commits:
commit e82335afd6e3e9a75275865661cf14a0a2959603
Author:     Ashod Nakashian <ashod.nakash...@collabora.co.uk>
AuthorDate: Sun Aug 2 14:52:02 2020 -0400
Commit:     Tor Lillqvist <t...@collabora.com>
CommitDate: Sat Nov 21 22:26:19 2020 +0100

    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 <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Michael Meeks <michael.me...@collabora.com>
    Reviewed-by: Ashod Nakashian <a...@collabora.com>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/106252
    Tested-by: Jenkins
    Reviewed-by: Tor Lillqvist <t...@collabora.com>

diff --git a/desktop/inc/lib/init.hxx b/desktop/inc/lib/init.hxx
index a71ecae79f83..84d9d5299fd4 100644
--- a/desktop/inc/lib/init.hxx
+++ b/desktop/inc/lib/init.hxx
@@ -150,7 +150,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 a02347450a38..0a19d5582e80 100644
--- a/desktop/qa/desktop_lib/test_desktop_lib.cxx
+++ b/desktop/qa/desktop_lib/test_desktop_lib.cxx
@@ -195,6 +195,7 @@ public:
     void testCalcSaveAs();
     void testControlState();
     void testMetricField();
+    void testMultiDocuments();
     void testABI();
 
     CPPUNIT_TEST_SUITE(DesktopLOKTest);
@@ -257,6 +258,7 @@ public:
     CPPUNIT_TEST(testCalcSaveAs);
     CPPUNIT_TEST(testControlState);
     CPPUNIT_TEST(testMetricField);
+    CPPUNIT_TEST(testMultiDocuments);
     CPPUNIT_TEST(testABI);
     CPPUNIT_TEST_SUITE_END();
 
@@ -322,10 +324,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);
 }
@@ -2933,6 +2938,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);
+}
+
 void DesktopLOKTest::testControlState()
 {
     LibLODocument_Impl* pDocument = loadDoc("search.ods");
diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index 6fe7347e9b70..9bcfff524bbf 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -1229,6 +1229,8 @@ LibLODocument_Impl::LibLODocument_Impl(const 
uno::Reference <css::lang::XCompone
     : mxComponent(xComponent)
     , mnDocumentId(nDocumentId)
 {
+    assert(nDocumentId != -1 && "Cannot set mnDocumentId to -1");
+
     m_pDocumentClass = gDocumentClass.lock();
     if (!m_pDocumentClass)
     {
@@ -2292,7 +2294,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);
@@ -3358,13 +3359,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)
@@ -3375,7 +3376,6 @@ static void doc_registerCallback(LibreOfficeKitDocument* 
pThis,
     }
     else
     {
-        size_t nId = nView;
         for (auto& pair : pDocument->mpCallbackFlushHandlers)
         {
             if (pair.first == nId)
@@ -3389,7 +3389,6 @@ static void doc_registerCallback(LibreOfficeKitDocument* 
pThis,
 
     if (pCallback != nullptr)
     {
-        size_t nId = nView;
         for (const auto& pair : pDocument->mpCallbackFlushHandlers)
         {
             if (pair.first == nId)
@@ -3397,11 +3396,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);
+        }
     }
 }
 
@@ -5145,7 +5152,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;
@@ -5193,24 +5201,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)
diff --git a/include/editeng/outliner.hxx b/include/editeng/outliner.hxx
index f06bd9a7448d..a6bc9fbd7ff2 100644
--- a/include/editeng/outliner.hxx
+++ b/include/editeng/outliner.hxx
@@ -365,7 +365,6 @@ class SAL_NO_VTABLE SAL_DLLPUBLIC_RTTI OutlinerViewShell
 public:
     virtual void libreOfficeKitViewCallback(int nType, const char* pPayload) 
const = 0;
     virtual ViewShellId GetViewShellId() const = 0;
-    virtual void SetDocId(ViewShellDocId nId) = 0;
     virtual ViewShellDocId GetDocId() const = 0;
     /// Wrapper around SfxLokHelper::notifyOtherViews().
     virtual void NotifyOtherViews(int nType, const OString& rKey, const 
OString& rPayload) = 0;
diff --git a/include/sfx2/lokhelper.hxx b/include/sfx2/lokhelper.hxx
index 2aad968681b8..521bf4207458 100644
--- a/include/sfx2/lokhelper.hxx
+++ b/include/sfx2/lokhelper.hxx
@@ -45,19 +45,21 @@ class SFX2_DLLPUBLIC SfxLokHelper
 {
 public:
     /// Create a new view shell from the current view frame.
+    /// This assumes a single document is ever loaded.
     static int createView();
+    /// Create a new view shell for the given DocId, for multi-document 
support.
+    static int createView(int nDocId);
     /// Destroy a view shell from the global shell list.
     static void destroyView(int nId);
     /// Set a view shell as current one.
     static void setView(int nId);
     /// Get the currently active view.
     static int getView(const SfxViewShell* pViewShell = nullptr);
-    /// Get the number of views of the current object shell.
-    static std::size_t getViewsCount();
-    /// Get viewIds of views of the current object shell.
-    static bool getViewIds(int* pArray, size_t nSize);
-    /// Set the document id of the currently active view
-    static void setDocumentIdOfView(int nId);
+    /// Get the number of views of the current DocId.
+    static std::size_t getViewsCount(int nDocId);
+    /// Get viewIds of views of the current DocId.
+    static bool getViewIds(int nDocId, int* pArray, size_t nSize);
+
     /// Get the document id for a view
     static int getDocumentIdOfView(int nViewId);
     /// Get the default language that should be used for views
@@ -125,6 +127,9 @@ public:
     /// A special value to signify 'infinity'.
     /// This value is chosen such that sal_Int32 will not overflow when 
manipulated.
     static const tools::Long MaxTwips = 1e9;
+
+private:
+    static int createView(SfxViewFrame* pViewFrame, ViewShellDocId docId);
 };
 
 template<typename ViewShellType, typename FunctionType>
diff --git a/include/sfx2/viewsh.hxx b/include/sfx2/viewsh.hxx
index 7965cb79dfc4..67671a6a678b 100644
--- a/include/sfx2/viewsh.hxx
+++ b/include/sfx2/viewsh.hxx
@@ -165,6 +165,9 @@ friend class SfxPrinterController;
     LanguageTag                 maLOKLocale;
     LOKDeviceFormFactor         maLOKDeviceFormFactor;
 
+    /// Used to set the DocId at construction time. See SetCurrentDocId.
+    static ViewShellDocId       mnCurrentDocId;
+
 protected:
     virtual void                Activate(bool IsMDIActivate) override;
     virtual void                Deactivate(bool IsMDIActivate) override;
@@ -339,8 +342,18 @@ public:
     virtual void dumpAsXml(xmlTextWriterPtr pWriter) const;
     /// See OutlinerViewShell::GetViewShellId().
     ViewShellId GetViewShellId() const override;
-    void SetDocId(ViewShellDocId nId) override;
+
+    /// Set the current DocId, which is used by Mobile LOKit to
+    /// load multiple documents and yet identify the views of each.
+    /// There are events that are fired while creating a new view,
+    /// and if we don't have a DocId, we can't know which other views
+    /// within the same document (if any) should get those events.
+    /// By setting this static value, we are able to set the DocId
+    /// of each SfxViewShell at construction time.
+    static void SetCurrentDocId(ViewShellDocId nId);
+    /// Get the DocId used by Mobile LOKit to load multiple documents.
     ViewShellDocId GetDocId() const override;
+
     /// See OutlinerViewShell::NotifyOtherViews().
     void NotifyOtherViews(int nType, const OString& rKey, const OString& 
rPayload) override;
     /// See OutlinerViewShell::NotifyOtherView().
diff --git a/sc/source/ui/view/tabvwshc.cxx b/sc/source/ui/view/tabvwshc.cxx
index f208a07af7af..6cafc717b992 100644
--- a/sc/source/ui/view/tabvwshc.cxx
+++ b/sc/source/ui/view/tabvwshc.cxx
@@ -520,7 +520,8 @@ void ScTabViewShell::notifyAllViewsHeaderInvalidation(const 
SfxViewShell* pForVi
     while (pViewShell)
     {
         ScTabViewShell* pTabViewShell = 
dynamic_cast<ScTabViewShell*>(pViewShell);
-        if (pTabViewShell && pViewShell->GetDocId() == 
pForViewShell->GetDocId() && (nCurrentTabIndex == -1 || 
pTabViewShell->getPart() == nCurrentTabIndex))
+        if (pTabViewShell && pViewShell->GetDocId() == 
pForViewShell->GetDocId()
+            && (nCurrentTabIndex == -1 || pTabViewShell->getPart() == 
nCurrentTabIndex))
         {
             
pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_INVALIDATE_HEADER, 
aPayload.getStr());
         }
diff --git a/sd/qa/unit/tiledrendering/LOKitSearchTest.cxx 
b/sd/qa/unit/tiledrendering/LOKitSearchTest.cxx
index a34914b88a60..beba53b67078 100644
--- a/sd/qa/unit/tiledrendering/LOKitSearchTest.cxx
+++ b/sd/qa/unit/tiledrendering/LOKitSearchTest.cxx
@@ -23,6 +23,7 @@
 #include <comphelper/string.hxx>
 #include <comphelper/lok.hxx>
 #include <sfx2/dispatch.hxx>
+#include <sfx2/lokhelper.hxx>
 #include <sfx2/viewfrm.hxx>
 #include <svl/srchitem.hxx>
 #include <svl/stritem.hxx>
diff --git a/sd/source/ui/unoidl/unomodel.cxx b/sd/source/ui/unoidl/unomodel.cxx
index 267fdbb3c34e..2ffc5acc0664 100644
--- a/sd/source/ui/unoidl/unomodel.cxx
+++ b/sd/source/ui/unoidl/unomodel.cxx
@@ -2305,6 +2305,9 @@ int SdXImpressDocument::getParts()
 {
     // TODO: master pages?
     // Read: drviews1.cxx
+    if (!mpDoc)
+        return 0;
+
     return mpDoc->GetSdPageCount(PageKind::Standard);
 }
 
diff --git a/sfx2/source/view/lokhelper.cxx b/sfx2/source/view/lokhelper.cxx
index 1240209d9fb2..f86b69a8af29 100644
--- a/sfx2/source/view/lokhelper.cxx
+++ b/sfx2/source/view/lokhelper.cxx
@@ -56,7 +56,10 @@ public:
         --m_nDisabled;
     }
 
-    static bool disabled() { return m_nDisabled != 0; }
+    static inline bool disabled()
+    {
+        return !comphelper::LibreOfficeKit::isActive() || m_nDisabled != 0;
+    }
 
 private:
     static int m_nDisabled;
@@ -71,28 +74,57 @@ LanguageTag g_defaultLanguageTag("en-US", true);
 LOKDeviceFormFactor g_deviceFormFactor = LOKDeviceFormFactor::UNKNOWN;
 }
 
-int SfxLokHelper::createView()
+int SfxLokHelper::createView(SfxViewFrame* pViewFrame, ViewShellDocId docId)
 {
-    SfxViewFrame* pViewFrame = SfxViewFrame::GetFirst();
+    assert(docId >= ViewShellDocId(0) && "Cannot createView for invalid 
(negative) DocId.");
+
     if (pViewFrame == nullptr)
         return -1;
-    SfxViewShell* pPrevViewShell = SfxViewShell::Current();
-    ViewShellDocId nId;
-    if (pPrevViewShell)
-        nId = pPrevViewShell->GetDocId();
+
+    SfxViewShell::SetCurrentDocId(docId);
     SfxRequest aRequest(pViewFrame, SID_NEWWINDOW);
     pViewFrame->ExecView_Impl(aRequest);
     SfxViewShell* pViewShell = SfxViewShell::Current();
     if (pViewShell == nullptr)
         return -1;
-    if (pPrevViewShell)
-        pViewShell->SetDocId(nId);
+
+    assert(pViewShell->GetDocId() == docId && "DocId must be already set!");
     return static_cast<sal_Int32>(pViewShell->GetViewShellId());
 }
 
+int SfxLokHelper::createView()
+{
+    // Assumes a single document, or at least that the
+    // current view belongs to the document on which the
+    // view will be created.
+    SfxViewShell* pViewShell = SfxViewShell::Current();
+    if (pViewShell == nullptr)
+        return -1;
+
+    return createView(pViewShell->GetViewFrame(), pViewShell->GetDocId());
+}
+
+int SfxLokHelper::createView(int nDocId)
+{
+    const SfxApplication* pApp = SfxApplication::Get();
+    if (pApp == nullptr)
+        return -1;
+
+    // Find a shell with the given DocId.
+    const ViewShellDocId docId(nDocId);
+    for (const SfxViewShell* pViewShell : pApp->GetViewShells_Impl())
+    {
+        if (pViewShell->GetDocId() == docId)
+            return createView(pViewShell->GetViewFrame(), docId);
+    }
+
+    // No frame with nDocId found.
+    return -1;
+}
+
 void SfxLokHelper::destroyView(int nId)
 {
-    SfxApplication* pApp = SfxApplication::Get();
+    const SfxApplication* pApp = SfxApplication::Get();
     if (pApp == nullptr)
         return;
 
@@ -157,14 +189,15 @@ int SfxLokHelper::getView(const SfxViewShell* pViewShell)
     return static_cast<sal_Int32>(pViewShell->GetViewShellId());
 }
 
-std::size_t SfxLokHelper::getViewsCount()
+std::size_t SfxLokHelper::getViewsCount(int nDocId)
 {
+    assert(nDocId != -1 && "Cannot getViewsCount for invalid DocId -1");
+
     SfxApplication* pApp = SfxApplication::Get();
     if (!pApp)
         return 0;
 
-    const SfxViewShell* const pCurrentViewShell = SfxViewShell::Current();
-    const ViewShellDocId nCurrentDocId = pCurrentViewShell ? 
pCurrentViewShell->GetDocId() : ViewShellDocId(-1);
+    const ViewShellDocId nCurrentDocId(nDocId);
     std::size_t n = 0;
     SfxViewShell* pViewShell = SfxViewShell::GetFirst();
     while (pViewShell)
@@ -173,40 +206,36 @@ std::size_t SfxLokHelper::getViewsCount()
             n++;
         pViewShell = SfxViewShell::GetNext(*pViewShell);
     }
+
     return n;
 }
 
-bool SfxLokHelper::getViewIds(int* pArray, size_t nSize)
+bool SfxLokHelper::getViewIds(int nDocId, int* pArray, size_t nSize)
 {
+    assert(nDocId != -1 && "Cannot getViewsIds for invalid DocId -1");
+
     SfxApplication* pApp = SfxApplication::Get();
     if (!pApp)
         return false;
 
-    const SfxViewShell* const pCurrentViewShell = SfxViewShell::Current();
-    const ViewShellDocId nCurrentDocId = pCurrentViewShell ? 
pCurrentViewShell->GetDocId() : ViewShellDocId(-1);
+    const ViewShellDocId nCurrentDocId(nDocId);
     std::size_t n = 0;
     SfxViewShell* pViewShell = SfxViewShell::GetFirst();
     while (pViewShell)
     {
-        if (n == nSize)
-            return false;
         if (pViewShell->GetDocId() == nCurrentDocId)
         {
+            if (n == nSize)
+                return false;
+
             pArray[n] = static_cast<sal_Int32>(pViewShell->GetViewShellId());
             n++;
         }
+
         pViewShell = SfxViewShell::GetNext(*pViewShell);
     }
-    return true;
-}
 
-void SfxLokHelper::setDocumentIdOfView(int nId)
-{
-    SfxViewShell* pViewShell = SfxViewShell::Current();
-    assert(pViewShell);
-    if (!pViewShell)
-        return;
-    pViewShell->SetDocId(ViewShellDocId(nId));
+    return true;
 }
 
 int SfxLokHelper::getDocumentIdOfView(int nViewId)
@@ -336,14 +365,25 @@ void SfxLokHelper::notifyOtherView(const SfxViewShell* 
pThisView, SfxViewShell c
 void SfxLokHelper::notifyOtherViews(const SfxViewShell* pThisView, int nType, 
const OString& rKey,
                                     const OString& rPayload)
 {
+    assert(pThisView != nullptr && "pThisView must be valid");
     if (DisableCallbacks::disabled())
         return;
 
+    // Cache the payload so we only have to generate it once, at most.
+    OString aPayload;
+
+    const ViewShellDocId nCurrentDocId = pThisView->GetDocId();
     SfxViewShell* pViewShell = SfxViewShell::GetFirst();
     while (pViewShell)
     {
-        if (pViewShell != pThisView && pViewShell->GetDocId() == pThisView-> 
GetDocId())
-            notifyOtherView(pThisView, pViewShell, nType, rKey, rPayload);
+        if (pViewShell != pThisView && nCurrentDocId == pViewShell->GetDocId())
+        {
+            // Payload is only dependent on pThisView.
+            if (aPayload.isEmpty())
+                aPayload = lcl_generateJSON(pThisView, rKey, rPayload);
+
+            pViewShell->libreOfficeKitViewCallback(nType, aPayload.getStr());
+        }
 
         pViewShell = SfxViewShell::GetNext(*pViewShell);
     }
@@ -352,17 +392,25 @@ void SfxLokHelper::notifyOtherViews(const SfxViewShell* 
pThisView, int nType, co
 void SfxLokHelper::notifyOtherViews(const SfxViewShell* pThisView, int nType,
                                     const boost::property_tree::ptree& rTree)
 {
-    if (SfxLokHelper::getViewsCount() <= 1 || DisableCallbacks::disabled())
+    assert(pThisView != nullptr && "pThisView must be valid");
+    if (DisableCallbacks::disabled())
         return;
 
-    // Payload is only dependent on pThisView.
-    OString aPayload = lcl_generateJSON(pThisView, rTree);
+    // Cache the payload so we only have to generate it once, at most.
+    OString aPayload;
 
+    const ViewShellDocId nCurrentDocId = pThisView->GetDocId();
     SfxViewShell* pViewShell = SfxViewShell::GetFirst();
     while (pViewShell)
     {
-        if (pViewShell != pThisView)
+        if (pViewShell != pThisView && nCurrentDocId == pViewShell->GetDocId())
+        {
+            // Payload is only dependent on pThisView.
+            if (aPayload.isEmpty())
+                aPayload = lcl_generateJSON(pThisView, rTree);
+
             pViewShell->libreOfficeKitViewCallback(nType, aPayload.getStr());
+        }
 
         pViewShell = SfxViewShell::GetNext(*pViewShell);
     }
@@ -414,7 +462,7 @@ void SfxLokHelper::notifyWindow(const SfxViewShell* 
pThisView,
 {
     assert(pThisView != nullptr && "pThisView must be valid");
 
-    if (SfxLokHelper::getViewsCount() <= 0 || nLOKWindowId == 0 || 
DisableCallbacks::disabled())
+    if (nLOKWindowId == 0 || DisableCallbacks::disabled())
         return;
 
     OStringBuffer aPayload;
@@ -453,7 +501,7 @@ void SfxLokHelper::notifyInvalidation(SfxViewShell const* 
pThisView, const OStri
 
 void SfxLokHelper::notifyDocumentSizeChanged(SfxViewShell const* pThisView, 
const OString& rPayload, vcl::ITiledRenderable* pDoc, bool bInvalidateAll)
 {
-    if (!pDoc || pDoc->isDisposed() || !comphelper::LibreOfficeKit::isActive() 
|| DisableCallbacks::disabled())
+    if (!pDoc || pDoc->isDisposed() || DisableCallbacks::disabled())
         return;
 
     if (bInvalidateAll)
@@ -470,7 +518,7 @@ void SfxLokHelper::notifyDocumentSizeChanged(SfxViewShell 
const* pThisView, cons
 
 void SfxLokHelper::notifyDocumentSizeChangedAllViews(vcl::ITiledRenderable* 
pDoc, bool bInvalidateAll)
 {
-    if (!comphelper::LibreOfficeKit::isActive() || 
DisableCallbacks::disabled())
+    if (DisableCallbacks::disabled())
         return;
 
     // FIXME: Do we know whether it is the views for the document that is in 
the "current" view that has changed?
diff --git a/sfx2/source/view/viewimp.hxx b/sfx2/source/view/viewimp.hxx
index c1ee641fdc16..d61f86b5dd82 100644
--- a/sfx2/source/view/viewimp.hxx
+++ b/sfx2/source/view/viewimp.hxx
@@ -54,9 +54,9 @@ struct SfxViewShell_Impl
     bool m_bTiledSearching;
     static sal_uInt32 m_nLastViewShellId;
     const ViewShellId m_nViewShellId;
-    ViewShellDocId m_nDocId;
+    const ViewShellDocId m_nDocId;
 
-    explicit SfxViewShell_Impl(SfxViewShellFlags const nFlags);
+    explicit SfxViewShell_Impl(SfxViewShellFlags const nFlags, ViewShellDocId 
nDocId);
     ~SfxViewShell_Impl();
 
     std::vector< SfxInPlaceClient* >* GetIPClients_Impl(bool bCreate = true) 
const;
diff --git a/sfx2/source/view/viewsh.cxx b/sfx2/source/view/viewsh.cxx
index f419e4f95c10..d35253d1342a 100644
--- a/sfx2/source/view/viewsh.cxx
+++ b/sfx2/source/view/viewsh.cxx
@@ -217,7 +217,7 @@ void SAL_CALL SfxClipboardChangeListener::changedContents( 
const datatransfer::c
 
 sal_uInt32 SfxViewShell_Impl::m_nLastViewShellId = 0;
 
-SfxViewShell_Impl::SfxViewShell_Impl(SfxViewShellFlags const nFlags)
+SfxViewShell_Impl::SfxViewShell_Impl(SfxViewShellFlags const nFlags, 
ViewShellDocId nDocId)
 : aInterceptorContainer( aMutex )
 ,   m_bHasPrintOptions(nFlags & SfxViewShellFlags::HAS_PRINTOPTIONS)
 ,   m_nFamily(0xFFFF)   // undefined, default set by TemplateDialog
@@ -225,7 +225,7 @@ SfxViewShell_Impl::SfxViewShell_Impl(SfxViewShellFlags 
const nFlags)
 ,   m_pLibreOfficeKitViewData(nullptr)
 ,   m_bTiledSearching(false)
 ,   m_nViewShellId(SfxViewShell_Impl::m_nLastViewShellId++)
-,   m_nDocId(-1)
+,   m_nDocId(nDocId)
 {
 }
 
@@ -1058,6 +1058,7 @@ void SfxViewShell::SetWindow
     //SfxGetpApp()->GrabFocus( pWindow );
 }
 
+ViewShellDocId SfxViewShell::mnCurrentDocId(0);
 
 SfxViewShell::SfxViewShell
 (
@@ -1067,7 +1068,7 @@ SfxViewShell::SfxViewShell
 )
 
 :   SfxShell(this)
-,   pImpl( new SfxViewShell_Impl(nFlags) )
+,   pImpl( new SfxViewShell_Impl(nFlags, SfxViewShell::mnCurrentDocId) )
 ,   pFrame(pViewFrame)
 ,   pWindow(nullptr)
 ,   bNoNewWindow( nFlags & SfxViewShellFlags::NO_NEWWINDOW )
@@ -1542,14 +1543,14 @@ ViewShellId SfxViewShell::GetViewShellId() const
     return pImpl->m_nViewShellId;
 }
 
-void SfxViewShell::SetDocId(ViewShellDocId nId)
+void SfxViewShell::SetCurrentDocId(ViewShellDocId nId)
 {
-    assert(static_cast<int>(pImpl->m_nDocId) == -1);
-    pImpl->m_nDocId = nId;
+    mnCurrentDocId = nId;
 }
 
 ViewShellDocId SfxViewShell::GetDocId() const
 {
+    assert(pImpl->m_nDocId >= ViewShellDocId(0) && "m_nDocId should have been 
initialized, but it is invalid.");
     return pImpl->m_nDocId;
 }
 
diff --git a/sw/qa/extras/tiledrendering/tiledrendering.cxx 
b/sw/qa/extras/tiledrendering/tiledrendering.cxx
index 7b497ae8c600..dc57ef1e451a 100644
--- a/sw/qa/extras/tiledrendering/tiledrendering.cxx
+++ b/sw/qa/extras/tiledrendering/tiledrendering.cxx
@@ -1124,7 +1124,7 @@ void SwTiledRenderingTest::testViewCursorCleanup()
     // Now destroy the second view.
     SfxLokHelper::destroyView(nView2);
     Scheduler::ProcessEventsToIdle();
-    CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(1), 
SfxLokHelper::getViewsCount());
+    CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(1), 
SfxLokHelper::getViewsCount(0));
     // Make sure that the graphic view selection on the first view is cleaned 
up.
     CPPUNIT_ASSERT(!aView1.m_bGraphicViewSelection);
 }
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to