summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuboš Luňák <l.lunak@collabora.com>2021-10-15 08:43:23 +0200
committerLuboš Luňák <l.lunak@collabora.com>2021-10-24 01:41:00 +0200
commitd18d53da7cd554ed887ae53f5fb7c6ac1f7e4a98 (patch)
tree4b08f27a0f5fcc116700c8e4334cdbd2caa05dca
parent5c30093f5bcc9f2d2c5ec072263ca0d58337924e (diff)
change some LOK internal updates to be pull model instead of push
Some LOK messages may get called very often, such as updates about cursor position. And since only the last one matters, they get generated every time, which costs some time, and then later except for one they get all discard again from CallbackFlushHandler queue, which again costs time. Change the model to instead only set an 'updated' flag, and CallbackFlushHandler will request the actual message payload only before flushing. This commit changes LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR and LOK_CALLBACK_INVALIDATE_VIEW_CURSOR to work this way. Change-Id: I376be63176c0b4b5cb492fbf529c21ed01b35481 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/124084 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com> Reviewed-by: Luboš Luňák <l.lunak@collabora.com>
-rw-r--r--desktop/inc/lib/init.hxx23
-rw-r--r--desktop/source/lib/init.cxx148
-rw-r--r--include/editeng/outliner.hxx2
-rw-r--r--include/sfx2/lokcallback.hxx11
-rw-r--r--include/sfx2/lokhelper.hxx18
-rw-r--r--include/sfx2/viewsh.hxx5
-rw-r--r--include/test/lokcallback.hxx24
-rw-r--r--sc/qa/unit/tiledrendering/tiledrendering.cxx15
-rw-r--r--sd/qa/unit/tiledrendering/tiledrendering.cxx15
-rw-r--r--sfx2/source/view/lokhelper.cxx69
-rw-r--r--sfx2/source/view/viewsh.cxx33
-rw-r--r--sw/inc/view.hxx1
-rw-r--r--sw/inc/viscrs.hxx3
-rw-r--r--sw/qa/core/txtnode/txtnode.cxx2
-rw-r--r--sw/qa/extras/tiledrendering/tiledrendering.cxx72
-rw-r--r--sw/source/core/crsr/viscrs.cxx85
-rw-r--r--sw/source/uibase/inc/wrtsh.hxx2
-rw-r--r--sw/source/uibase/uiview/view.cxx7
-rw-r--r--sw/source/uibase/wrtsh/wrtsh4.cxx13
-rw-r--r--test/source/lokcallback.cxx121
20 files changed, 588 insertions, 81 deletions
diff --git a/desktop/inc/lib/init.hxx b/desktop/inc/lib/init.hxx
index c43e82fdd430..2035226bc059 100644
--- a/desktop/inc/lib/init.hxx
+++ b/desktop/inc/lib/init.hxx
@@ -103,6 +103,8 @@ namespace desktop {
virtual void libreOfficeKitViewCallback(int nType, const char* pPayload) override;
virtual void libreOfficeKitViewCallbackWithViewId(int nType, const char* pPayload, int nViewId) override;
virtual void libreOfficeKitViewInvalidateTilesCallback(const tools::Rectangle* pRect, int nPart) override;
+ virtual void libreOfficeKitViewUpdatedCallback(int nType) override;
+ virtual void libreOfficeKitViewUpdatedCallbackPerViewId(int nType, int nViewId, int nSourceViewId) override;
private:
struct CallbackData
@@ -171,6 +173,8 @@ namespace desktop {
queue_type2::iterator toQueue2(queue_type1::iterator);
queue_type2::reverse_iterator toQueue2(queue_type1::reverse_iterator);
void queue(const int type, CallbackData& data);
+ void enqueueUpdatedTypes();
+ void enqueueUpdatedType( int type, SfxViewShell* sourceViewShell, int viewId );
/** we frequently want to scan the queue, and mostly when we do so, we only care about the element type
so we split the queue in 2 to make the scanning cache friendly. */
@@ -178,6 +182,25 @@ namespace desktop {
queue_type2 m_queue2;
std::map<int, std::string> m_states;
std::unordered_map<int, std::unordered_map<int, std::string>> m_viewStates;
+
+ // For some types only the last message matters (see isUpdatedType()) or only the last message
+ // per each viewId value matters (see isUpdatedTypePerViewId()), so instead of using push model
+ // where we'd get flooded by repeated messages (which might be costly to generate and process),
+ // the preferred way is that libreOfficeKitViewUpdatedCallback()
+ // or libreOfficeKitViewUpdatedCallbackPerViewId() get called to notify about such a message being
+ // needed, and we'll set a flag here to fetch the actual message before flushing.
+ void setUpdatedType( int nType, bool value );
+ void setUpdatedTypePerViewId( int nType, int nViewId, int nSourceViewId, bool value );
+ void resetUpdatedType( int nType);
+ void resetUpdatedTypePerViewId( int nType, int nViewId );
+ std::vector<bool> m_updatedTypes; // index is type, value is if set
+ struct PerViewIdData
+ {
+ bool set; // value is if set
+ int sourceViewId;
+ };
+ std::unordered_map<int, std::vector<PerViewIdData>> m_updatedTypesPerViewId; // key is view, index is type
+
LibreOfficeKitDocument* m_pDocument;
int m_viewId = -1; // view id of the associated SfxViewShell
LibreOfficeKitCallback m_pCallback;
diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index 9e1eeb78d184..b7bd3ca28a32 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -697,6 +697,27 @@ static bool lcl_isViewCallbackType(const int type)
}
}
+static bool isUpdatedType(int type)
+{
+ switch (type)
+ {
+ default:
+ return false;
+ }
+}
+
+static bool isUpdatedTypePerViewId(int type)
+{
+ switch (type)
+ {
+ case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR:
+ case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR:
+ return true;
+ default:
+ return false;
+ }
+}
+
static int lcl_getViewId(const std::string& payload)
{
// this is a cheap way how to get the viewId from a JSON message; proper
@@ -1461,6 +1482,48 @@ CallbackFlushHandler::queue_type2::reverse_iterator CallbackFlushHandler::toQueu
return m_queue2.rbegin() + delta;
}
+void CallbackFlushHandler::setUpdatedType( int nType, bool value )
+{
+ assert(isUpdatedType(nType));
+ if( m_updatedTypes.size() <= o3tl::make_unsigned( nType ))
+ m_updatedTypes.resize( nType + 1 ); // new are default-constructed, i.e. false
+ m_updatedTypes[ nType ] = value;
+}
+
+void CallbackFlushHandler::resetUpdatedType( int nType )
+{
+ setUpdatedType( nType, false );
+}
+
+void CallbackFlushHandler::setUpdatedTypePerViewId( int nType, int nViewId, int nSourceViewId, bool value )
+{
+ assert(isUpdatedTypePerViewId(nType));
+ std::vector<PerViewIdData>& types = m_updatedTypesPerViewId[ nViewId ];
+ if( types.size() <= o3tl::make_unsigned( nType ))
+ types.resize( nType + 1 ); // new are default-constructed, i.e. false
+ types[ nType ] = PerViewIdData{ value, nSourceViewId };
+}
+
+void CallbackFlushHandler::resetUpdatedTypePerViewId( int nType, int nViewId )
+{
+ assert(isUpdatedTypePerViewId(nType));
+ bool allViewIds = false;
+ // Handle specially messages that do not have viewId for backwards compatibility.
+ if( nType == LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR && !comphelper::LibreOfficeKit::isViewIdForVisCursorInvalidation())
+ allViewIds = true;
+ if( !allViewIds )
+ {
+ setUpdatedTypePerViewId( nType, nViewId, -1, false );
+ return;
+ }
+ for( auto& it : m_updatedTypesPerViewId )
+ {
+ std::vector<PerViewIdData>& types = it.second;
+ if( types.size() >= o3tl::make_unsigned( nType ))
+ types[ nType ].set = false;
+ }
+}
+
void CallbackFlushHandler::libreOfficeKitViewCallback(int nType, const char* pPayload)
{
CallbackData callbackData(pPayload);
@@ -1479,6 +1542,22 @@ void CallbackFlushHandler::libreOfficeKitViewInvalidateTilesCallback(const tools
queue(LOK_CALLBACK_INVALIDATE_TILES, callbackData);
}
+void CallbackFlushHandler::libreOfficeKitViewUpdatedCallback(int nType)
+{
+ assert(isUpdatedType( nType ));
+ std::unique_lock<std::mutex> lock(m_mutex);
+ SAL_INFO("lok", "Updated: [" << nType << "]");
+ setUpdatedType(nType, true);
+}
+
+void CallbackFlushHandler::libreOfficeKitViewUpdatedCallbackPerViewId(int nType, int nViewId, int nSourceViewId)
+{
+ assert(isUpdatedTypePerViewId( nType ));
+ std::unique_lock<std::mutex> lock(m_mutex);
+ SAL_INFO("lok", "Updated: [" << nType << "]");
+ setUpdatedTypePerViewId(nType, nViewId, nSourceViewId, true);
+}
+
void CallbackFlushHandler::queue(const int type, const char* data)
{
CallbackData callbackData(data);
@@ -1542,6 +1621,20 @@ void CallbackFlushHandler::queue(const int type, CallbackData& aCallbackData)
std::unique_lock<std::mutex> lock(m_mutex);
+ // Update types should be received via the updated callbacks for performance,
+ // getting them as normal callbacks is technically not wrong, but probably should be avoided.
+ // Reset the updated flag if we get a normal message.
+ if(isUpdatedType(type))
+ {
+ SAL_INFO("lok", "Received event with updated type [" << type << "] as normal callback");
+ resetUpdatedType(type);
+ }
+ if(isUpdatedTypePerViewId(type))
+ {
+ SAL_INFO("lok", "Received event with updated type [" << type << "] as normal callback");
+ resetUpdatedTypePerViewId(type, aCallbackData.getViewId());
+ }
+
// drop duplicate callbacks for the listed types
switch (type)
{
@@ -2034,6 +2127,58 @@ bool CallbackFlushHandler::processWindowEvent(int type, CallbackData& aCallbackD
return false;
}
+void CallbackFlushHandler::enqueueUpdatedTypes()
+{
+ if( m_updatedTypes.empty() && m_updatedTypesPerViewId.empty())
+ return;
+ SfxViewShell* viewShell = SfxViewShell::GetFirst( false,
+ [this](const SfxViewShell* shell) { return shell->GetViewShellId().get() == m_viewId; } );
+ assert(viewShell != nullptr);
+ for( size_t type = 0; type < m_updatedTypes.size(); ++type )
+ {
+ if(m_updatedTypes[ type ])
+ {
+ assert(isUpdatedType( type ));
+ enqueueUpdatedType( type, viewShell, m_viewId );
+ }
+ }
+ for( auto it : m_updatedTypesPerViewId )
+ {
+ int viewId = it.first;
+ const std::vector<PerViewIdData>& types = it.second;
+ for( size_t type = 0; type < types.size(); ++type )
+ {
+ if(types[ type ].set)
+ {
+ assert(isUpdatedTypePerViewId( type ));
+ SfxViewShell* sourceViewShell = viewShell;
+ const int sourceViewId = types[ type ].sourceViewId;
+ if( sourceViewId != m_viewId )
+ sourceViewShell = SfxViewShell::GetFirst( false,
+ [sourceViewId](const SfxViewShell* shell) { return shell->GetViewShellId().get() == sourceViewId; } );
+ if(sourceViewShell == nullptr)
+ {
+ SAL_INFO("lok", "View #" << sourceViewId << " no longer found for updated event [" << type << "]");
+ continue; // View removed, probably cleaning up.
+ }
+ enqueueUpdatedType( type, sourceViewShell, viewId );
+ }
+ }
+ }
+ m_updatedTypes.clear();
+ m_updatedTypesPerViewId.clear();
+}
+
+void CallbackFlushHandler::enqueueUpdatedType( int type, SfxViewShell* viewShell, int viewId )
+{
+ OString payload = viewShell->getLOKPayload( type, viewId );
+ CallbackData callbackData(payload.getStr(), viewId);
+ m_queue1.emplace_back(type);
+ m_queue2.emplace_back(callbackData);
+ SAL_INFO("lok", "Queued updated [" << type << "]: [" << callbackData.getPayload()
+ << "] to have " << m_queue1.size() << " entries.");
+}
+
void CallbackFlushHandler::Invoke()
{
comphelper::ProfileZone aZone("CallbackFlushHandler::Invoke");
@@ -2051,6 +2196,9 @@ void CallbackFlushHandler::Invoke()
std::scoped_lock<std::mutex> lock(m_mutex);
+ // Append messages for updated types, fetch them only now.
+ enqueueUpdatedTypes();
+
SAL_INFO("lok", "Flushing " << m_queue1.size() << " elements.");
auto it1 = m_queue1.begin();
auto it2 = m_queue2.begin();
diff --git a/include/editeng/outliner.hxx b/include/editeng/outliner.hxx
index 1374a9f26f82..8cc3e8c23247 100644
--- a/include/editeng/outliner.hxx
+++ b/include/editeng/outliner.hxx
@@ -367,6 +367,8 @@ public:
virtual void libreOfficeKitViewCallback(int nType, const char* pPayload) const = 0;
virtual void libreOfficeKitViewCallbackWithViewId(int nType, const char* pPayload, int nViewId) const = 0;
virtual void libreOfficeKitViewInvalidateTilesCallback(const tools::Rectangle* pRect, int nPart) const = 0;
+ virtual void libreOfficeKitViewUpdatedCallback(int nType) const = 0;
+ virtual void libreOfficeKitViewUpdatedCallbackPerViewId(int nType, int nViewId, int nSourceViewId) const = 0;
virtual ViewShellId GetViewShellId() const = 0;
virtual ViewShellDocId GetDocId() const = 0;
/// Wrapper around SfxLokHelper::notifyOtherViews().
diff --git a/include/sfx2/lokcallback.hxx b/include/sfx2/lokcallback.hxx
index d01e7203205e..6f59402d0cec 100644
--- a/include/sfx2/lokcallback.hxx
+++ b/include/sfx2/lokcallback.hxx
@@ -11,6 +11,8 @@
#include <sal/types.h>
+#include <vector>
+
namespace tools
{
class Rectangle;
@@ -37,6 +39,15 @@ public:
// comphelper::LibreOfficeKit::isPartInInvalidation() is not set
virtual void libreOfficeKitViewInvalidateTilesCallback(const tools::Rectangle* pRect, int nPart)
= 0;
+ // A message of the given type should be sent, for performance purpose only a notification
+ // is given here, details about the message should be queried from SfxViewShell when necessary.
+ // This is used for messages that are generated often but only the last one is needed.
+ virtual void libreOfficeKitViewUpdatedCallback(int nType) = 0;
+ // Like libreOfficeKitViewUpdatedCallback(), but a last message is needed for each nViewId value.
+ // SfxViewShell:getLOKPayload() will be called on nSourceViewId view.
+ virtual void libreOfficeKitViewUpdatedCallbackPerViewId(int nType, int nViewId,
+ int nSourceViewId)
+ = 0;
};
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/sfx2/lokhelper.hxx b/include/sfx2/lokhelper.hxx
index 060e0b152722..d5c3adbf9d95 100644
--- a/include/sfx2/lokhelper.hxx
+++ b/include/sfx2/lokhelper.hxx
@@ -109,14 +109,28 @@ public:
static void notifyDocumentSizeChangedAllViews(vcl::ITiledRenderable* pDoc, bool bInvalidateAll = true);
/// Emits a LOK_CALLBACK_INVALIDATE_TILES, but tweaks it according to setOptionalFeatures() if needed.
static void notifyInvalidation(SfxViewShell const* pThisView, tools::Rectangle const *);
- /// Emits a LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR, but tweaks it according to setOptionalFeatures() if needed.
- static void notifyVisCursorInvalidation(OutlinerViewShell const* pThisView, const OString& rRectangle, bool bMispelledWord = false, const OString& rHyperlink = "");
/// Notifies all views with the given type and payload.
static void notifyAllViews(int nType, const OString& rPayload);
/// Notify about the editing context change.
static void notifyContextChange(SfxViewShell const* pViewShell, const OUString& aApplication, const OUString& aContext);
+ // Notify about the given type needing an update.
+ static void notifyUpdate(SfxViewShell const* pViewShell, int nType);
+ // Notify about the given type needing a per-viewid update.
+ static void notifyUpdatePerViewId(SfxViewShell const* pViewShell, int nType);
+ /// Same as notifyUpdatePerViewId(), pTargetShell will be notified, relevant viewId in pViewShell,
+ /// pSourceView->getLOKPayload() will be called to get the data.
+ static void notifyUpdatePerViewId(SfxViewShell const* pTargetShell, SfxViewShell const* pViewShell,
+ SfxViewShell const* pSourceShell, int nType);
+ // Notify other views about the given type needing a per-viewid update.
+ static void notifyOtherViewsUpdatePerViewId(SfxViewShell const* pViewShell, int nType);
+
+ static OString makePayloadJSON(const SfxViewShell* pThisView, int nViewId, const OString& rKey, const OString& rPayload);
+ /// Makes a LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR payload, but tweaks it according to setOptionalFeatures() if needed.
+ static OString makeVisCursorInvalidation(int nViewId, const OString& rRectangle,
+ bool bMispelledWord = false, const OString& rHyperlink = "");
+
/// Helper for posting async key event
static void postKeyEventAsync(const VclPtr<vcl::Window> &xWindow,
int nType, int nCharCode, int nKeyCode, int nRepeat = 0);
diff --git a/include/sfx2/viewsh.hxx b/include/sfx2/viewsh.hxx
index ee11c77a418d..f0d71bc542e6 100644
--- a/include/sfx2/viewsh.hxx
+++ b/include/sfx2/viewsh.hxx
@@ -342,6 +342,11 @@ public:
virtual void libreOfficeKitViewInvalidateTilesCallback(const tools::Rectangle* pRect, int nPart) const override;
// Performs any pending calls to libreOfficeKitViewInvalidateTilesCallback() as necessary.
virtual void flushPendingLOKInvalidateTiles();
+ virtual void libreOfficeKitViewUpdatedCallback(int nType) const override;
+ virtual void libreOfficeKitViewUpdatedCallbackPerViewId(int nType, int nViewId, int nSourceViewId) const override;
+ // Returns current payload for nType, after libreOfficeKitViewUpdatedCallback() or
+ // libreOfficeKitViewUpdatedCallbackPerViewId() were called.
+ virtual OString getLOKPayload(int nType, int nViewId) const;
/// Set if we are doing tiled searching.
void setTiledSearching(bool bTiledSearching);
diff --git a/include/test/lokcallback.hxx b/include/test/lokcallback.hxx
index f7372bc7ec80..a3f383bcec5e 100644
--- a/include/test/lokcallback.hxx
+++ b/include/test/lokcallback.hxx
@@ -15,28 +15,48 @@
#include <sfx2/lokcallback.hxx>
#include <vcl/idle.hxx>
+#include <vector>
+
/**
A helper to convert SfxLokCallbackInterface to a LIbreOfficeKitCallback for tests.
It reimplements the specialized callbacks and converts them to the generic type/payload
callback.
*/
-
class OOO_DLLPUBLIC_TEST TestLokCallbackWrapper final : public SfxLokCallbackInterface, public Idle
{
public:
TestLokCallbackWrapper(LibreOfficeKitCallback callback, void* data);
+ /// Discard all possibly still held events.
+ void clear();
+ /// Set the view id of the associated SfxViewShell.
+ void setLOKViewId(int viewId) { m_viewId = viewId; }
virtual void libreOfficeKitViewCallback(int nType, const char* pPayload) override;
virtual void libreOfficeKitViewCallbackWithViewId(int nType, const char* pPayload,
int nViewId) override;
virtual void libreOfficeKitViewInvalidateTilesCallback(const tools::Rectangle* pRect,
int nPart) override;
+ virtual void libreOfficeKitViewUpdatedCallback(int nType) override;
+ virtual void libreOfficeKitViewUpdatedCallbackPerViewId(int nType, int nViewId,
+ int nSourceViewId) override;
virtual void Invoke() override;
private:
- void callCallback(int nType, const char* pPayload);
+ void callCallback(int nType, const char* pPayload, int nViewId);
+ void startTimer();
+ void flushLOKData();
+ void discardUpdatedTypes(int nType, int nViewId);
LibreOfficeKitCallback m_callback;
void* m_data;
+ int m_viewId = -1; // the associated SfxViewShell
+ std::vector<int> m_updatedTypes; // value is type
+ struct PerViewIdData
+ {
+ int type;
+ int viewId;
+ int sourceViewId;
+ };
+ std::vector<PerViewIdData> m_updatedTypesPerViewId;
};
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/sc/qa/unit/tiledrendering/tiledrendering.cxx b/sc/qa/unit/tiledrendering/tiledrendering.cxx
index 82287bfb2441..341852641b22 100644
--- a/sc/qa/unit/tiledrendering/tiledrendering.cxx
+++ b/sc/qa/unit/tiledrendering/tiledrendering.cxx
@@ -181,6 +181,7 @@ public:
private:
ScModelObj* createDoc(const char* pName);
+ void setupLibreOfficeKitViewCallback(SfxViewShell* pViewShell);
static void callback(int nType, const char* pPayload, void* pData);
void callbackImpl(int nType, const char* pPayload);
@@ -222,6 +223,7 @@ void ScTiledRenderingTest::tearDown()
}
mxComponent->dispose();
}
+ m_callbackWrapper.clear();
comphelper::LibreOfficeKit::setActive(false);
test::BootstrapFixture::tearDown();
@@ -238,6 +240,12 @@ ScModelObj* ScTiledRenderingTest::createDoc(const char* pName)
return pModelObj;
}
+void ScTiledRenderingTest::setupLibreOfficeKitViewCallback(SfxViewShell* pViewShell)
+{
+ pViewShell->setLibreOfficeKitViewCallback(&m_callbackWrapper);
+ m_callbackWrapper.setLOKViewId(SfxLokHelper::getView(pViewShell));
+}
+
void ScTiledRenderingTest::callback(int nType, const char* pPayload, void* pData)
{
static_cast<ScTiledRenderingTest*>(pData)->callbackImpl(nType, pPayload);
@@ -400,7 +408,7 @@ void ScTiledRenderingTest::testDocumentSize()
ScTabViewShell* pViewShell = pDocSh->GetBestViewShell(false);
CPPUNIT_ASSERT(pViewShell);
- pViewShell->setLibreOfficeKitViewCallback(&m_callbackWrapper);
+ setupLibreOfficeKitViewCallback(pViewShell);
// check initial document size
Size aDocSize = pModelObj->getDocumentSize();
@@ -600,6 +608,7 @@ public:
mpViewShell = SfxViewShell::Current();
mpViewShell->setLibreOfficeKitViewCallback(&m_callbackWrapper);
mnView = SfxLokHelper::getView();
+ m_callbackWrapper.setLOKViewId( mnView );
if (!bDeleteListenerOnDestruct)
mpViewShell = nullptr;
}
@@ -783,7 +792,7 @@ void ScTiledRenderingTest::testDocumentSizeChanged()
// Load a document that doesn't have much content.
createDoc("small.ods");
- SfxViewShell::Current()->setLibreOfficeKitViewCallback(&m_callbackWrapper);
+ setupLibreOfficeKitViewCallback(SfxViewShell::Current());
// Go to the A30 cell -- that will extend the document size.
uno::Sequence<beans::PropertyValue> aPropertyValues =
@@ -885,7 +894,7 @@ void ScTiledRenderingTest::testColRowResize()
ScTabViewShell* pViewShell = pDocSh->GetBestViewShell(false);
CPPUNIT_ASSERT(pViewShell);
- pViewShell->setLibreOfficeKitViewCallback(&m_callbackWrapper);
+ setupLibreOfficeKitViewCallback(pViewShell);
ScDocument& rDoc = pDocSh->GetDocument();
diff --git a/sd/qa/unit/tiledrendering/tiledrendering.cxx b/sd/qa/unit/tiledrendering/tiledrendering.cxx
index 8d9a23afaa5b..917f2eb04038 100644
--- a/sd/qa/unit/tiledrendering/tiledrendering.cxx
+++ b/sd/qa/unit/tiledrendering/tiledrendering.cxx
@@ -197,6 +197,7 @@ public:
private:
SdXImpressDocument* createDoc(const char* pName, const uno::Sequence<beans::PropertyValue>& rArguments = uno::Sequence<beans::PropertyValue>());
+ void setupLibreOfficeKitViewCallback(SfxViewShell& pViewShell);
static void callback(int nType, const char* pPayload, void* pData);
void callbackImpl(int nType, const char* pPayload);
xmlDocUniquePtr parseXmlDump();
@@ -246,6 +247,7 @@ void SdTiledRenderingTest::tearDown()
if (m_pXmlBuffer)
xmlBufferFree(m_pXmlBuffer);
+ m_callbackWrapper.clear();
comphelper::LibreOfficeKit::setActive(false);
test::BootstrapFixture::tearDown();
@@ -262,6 +264,12 @@ SdXImpressDocument* SdTiledRenderingTest::createDoc(const char* pName, const uno
return pImpressDocument;
}
+void SdTiledRenderingTest::setupLibreOfficeKitViewCallback(SfxViewShell& pViewShell)
+{
+ pViewShell.setLibreOfficeKitViewCallback(&m_callbackWrapper);
+ m_callbackWrapper.setLOKViewId(SfxLokHelper::getView(&pViewShell));
+}
+
void SdTiledRenderingTest::callback(int nType, const char* pPayload, void* pData)
{
static_cast<SdTiledRenderingTest*>(pData)->callbackImpl(nType, pPayload);
@@ -398,7 +406,7 @@ void SdTiledRenderingTest::testRegisterCallback()
{
SdXImpressDocument* pXImpressDocument = createDoc("dummy.odp");
sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
- pViewShell->GetViewShellBase().setLibreOfficeKitViewCallback(&m_callbackWrapper);
+ setupLibreOfficeKitViewCallback(pViewShell->GetViewShellBase());
// Start text edit of the empty title shape.
SdPage* pActualPage = pViewShell->GetActualPage();
@@ -628,7 +636,7 @@ void SdTiledRenderingTest::testInsertDeletePage()
{
SdXImpressDocument* pXImpressDocument = createDoc("insert-delete.odp");
sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
- pViewShell->GetViewShellBase().setLibreOfficeKitViewCallback(&m_callbackWrapper);
+ setupLibreOfficeKitViewCallback(pViewShell->GetViewShellBase());
SdDrawDocument* pDoc = pXImpressDocument->GetDocShell()->GetDoc();
CPPUNIT_ASSERT(pDoc);
@@ -915,6 +923,7 @@ public:
mpViewShell = SfxViewShell::Current();
mpViewShell->setLibreOfficeKitViewCallback(&m_callbackWrapper);
mnView = SfxLokHelper::getView();
+ m_callbackWrapper.setLOKViewId( mnView );
}
~ViewCallback()
@@ -2528,7 +2537,7 @@ void SdTiledRenderingTest::testCutSelectionChange()
CPPUNIT_ASSERT(pXImpressDocument);
sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
- pViewShell->GetViewShellBase().setLibreOfficeKitViewCallback(&m_callbackWrapper);
+ setupLibreOfficeKitViewCallback(pViewShell->GetViewShellBase());
Scheduler::ProcessEventsToIdle();
// Select first text object
diff --git a/sfx2/source/view/lokhelper.cxx b/sfx2/source/view/lokhelper.cxx
index e2039498ca53..9b65dcec7df7 100644
--- a/sfx2/source/view/lokhelper.cxx
+++ b/sfx2/source/view/lokhelper.cxx
@@ -355,15 +355,21 @@ static OString lcl_generateJSON(const SfxViewShell* pView, const boost::property
return OString(aString.c_str(), aString.size()).trim();
}
-static inline OString lcl_generateJSON(const SfxViewShell* pView, const OString& rKey,
+static inline OString lcl_generateJSON(const SfxViewShell* pView, int nViewId, const OString& rKey,
const OString& rPayload)
{
assert(pView != nullptr && "pView must be valid");
- return OStringLiteral("{ \"viewId\": \"") + OString::number(SfxLokHelper::getView(pView))
+ return OStringLiteral("{ \"viewId\": \"") + OString::number(nViewId)
+ "\", \"part\": \"" + OString::number(pView->getPart()) + "\", \"" + rKey + "\": \""
+ lcl_sanitizeJSONAsValue(rPayload) + "\" }";
}
+static inline OString lcl_generateJSON(const SfxViewShell* pView, const OString& rKey,
+ const OString& rPayload)
+{
+ return lcl_generateJSON(pView, SfxLokHelper::getView(pView), rKey, rPayload);
+}
+
void SfxLokHelper::notifyOtherView(const SfxViewShell* pThisView, SfxViewShell const* pOtherView,
int nType, const OString& rKey, const OString& rPayload)
{
@@ -449,6 +455,11 @@ void SfxLokHelper::notifyOtherViews(const SfxViewShell* pThisView, int nType,
}
}
+OString SfxLokHelper::makePayloadJSON(const SfxViewShell* pThisView, int nViewId, const OString& rKey, const OString& rPayload)
+{
+ return lcl_generateJSON(pThisView, nViewId, rKey, rPayload);
+}
+
namespace {
OUString lcl_getNameForSlot(const SfxViewShell* pShell, sal_uInt16 nWhich)
{
@@ -563,25 +574,20 @@ void SfxLokHelper::notifyDocumentSizeChangedAllViews(vcl::ITiledRenderable* pDoc
}
}
-void SfxLokHelper::notifyVisCursorInvalidation(OutlinerViewShell const* pThisView, const OString& rRectangle, bool bMispelledWord, const OString& rHyperlink)
+OString SfxLokHelper::makeVisCursorInvalidation(int nViewId, const OString& rRectangle,
+ bool bMispelledWord, const OString& rHyperlink)
{
- if (DisableCallbacks::disabled())
- return;
-
if (comphelper::LibreOfficeKit::isViewIdForVisCursorInvalidation())
{
OString sHyperlink = rHyperlink.isEmpty() ? "{}" : rHyperlink;
- OString sPayload = OStringLiteral("{ \"viewId\": \"") + OString::number(SfxLokHelper::getView()) +
+ return OStringLiteral("{ \"viewId\": \"") + OString::number(nViewId) +
"\", \"rectangle\": \"" + rRectangle +
"\", \"mispelledWord\": \"" + OString::number(bMispelledWord ? 1 : 0) +
"\", \"hyperlink\": " + sHyperlink + " }";
- const int viewId = SfxLokHelper::getView();
- pThisView->libreOfficeKitViewCallbackWithViewId(LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR, sPayload.getStr(), viewId);
}
else
{
- OString sPayload = rRectangle;
- pThisView->libreOfficeKitViewCallback(LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR, sPayload.getStr());
+ return rRectangle;
}
}
@@ -613,6 +619,47 @@ void SfxLokHelper::notifyContextChange(SfxViewShell const* pViewShell, const OUS
pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_CONTEXT_CHANGED, aBuffer.getStr());
}
+void SfxLokHelper::notifyUpdate(SfxViewShell const* pThisView, int nType)
+{
+ if (DisableCallbacks::disabled())
+ return;
+
+ pThisView->libreOfficeKitViewUpdatedCallback(nType);
+}
+
+void SfxLokHelper::notifyUpdatePerViewId(SfxViewShell const* pThisView, int nType)
+{
+ notifyUpdatePerViewId(pThisView, pThisView, pThisView, nType);
+}
+
+void SfxLokHelper::notifyUpdatePerViewId(SfxViewShell const* pTargetShell, SfxViewShell const* pViewShell,
+ SfxViewShell const* pSourceShell, int nType)
+{
+ if (DisableCallbacks::disabled())
+ return;
+
+ int viewId = SfxLokHelper::getView(pViewShell);
+ int sourceViewId = SfxLokHelper::getView(pSourceShell);
+ pTargetShell->libreOfficeKitViewUpdatedCallbackPerViewId(nType, viewId, sourceViewId);
+}
+
+void SfxLokHelper::notifyOtherViewsUpdatePerViewId(SfxViewShell const* pThisView, int nType)
+{
+ assert(pThisView != nullptr && "pThisView must be valid");
+ if (DisableCallbacks::disabled())
+ return;
+
+ int viewId = SfxLokHelper::getView(pThisView);
+ const ViewShellDocId nCurrentDocId = pThisView->GetDocId();
+ SfxViewShell* pViewShell = SfxViewShell::GetFirst();
+ while (pViewShell)
+ {
+ if (pViewShell != pThisView && nCurrentDocId == pViewShell->GetDocId())
+ pViewShell->libreOfficeKitViewUpdatedCallbackPerViewId(nType, viewId, viewId);
+
+ pViewShell = SfxViewShell::GetNext(*pViewShell);
+ }
+}
namespace
{
diff --git a/sfx2/source/view/viewsh.cxx b/sfx2/source/view/viewsh.cxx
index 419b0284de2e..81757258805a 100644
--- a/sfx2/source/view/viewsh.cxx
+++ b/sfx2/source/view/viewsh.cxx
@@ -1532,6 +1532,32 @@ void SfxViewShell::libreOfficeKitViewCallback(int nType, const char* pPayload) c
<< lokCallbackTypeToString(nType) << ": [" << pPayload << ']');
}
+void SfxViewShell::libreOfficeKitViewUpdatedCallback(int nType) const
+{
+ if (ignoreLibreOfficeKitViewCallback(nType, pImpl.get()))
+ return;
+ if (pImpl->m_pLibreOfficeKitViewCallback)
+ pImpl->m_pLibreOfficeKitViewCallback->libreOfficeKitViewUpdatedCallback(nType);
+ else
+ SAL_INFO(
+ "sfx.view",
+ "SfxViewShell::libreOfficeKitViewUpdatedCallback no callback set! Dropped payload of type "
+ << lokCallbackTypeToString(nType));
+}
+
+void SfxViewShell::libreOfficeKitViewUpdatedCallbackPerViewId(int nType, int nViewId, int nSourceViewId) const
+{
+ if (ignoreLibreOfficeKitViewCallback(nType, pImpl.get()))
+ return;
+ if (pImpl->m_pLibreOfficeKitViewCallback)
+ pImpl->m_pLibreOfficeKitViewCallback->libreOfficeKitViewUpdatedCallbackPerViewId(nType, nViewId, nSourceViewId);
+ else
+ SAL_INFO(
+ "sfx.view",
+ "SfxViewShell::libreOfficeKitViewUpdatedCallbackPerViewId no callback set! Dropped payload of type "
+ << lokCallbackTypeToString(nType));
+}
+
void SfxViewShell::afterCallbackRegistered()
{
}
@@ -1541,6 +1567,13 @@ void SfxViewShell::flushPendingLOKInvalidateTiles()
// SfxViewShell itself does not delay any tile invalidations.
}
+OString SfxViewShell::getLOKPayload(int nType, int /*nViewId*/) const
+{
+ // SfxViewShell itself currently doesn't handle any updated-payload types.
+ SAL_WARN("sfx.view", "SfxViewShell::getLOKPayload unhandled type " << lokCallbackTypeToString(nType));
+ abort();
+}
+
vcl::Window* SfxViewShell::GetEditWindowForActiveOLEObj() const
{
vcl::Window* pEditWin = nullptr;
diff --git a/sw/inc/view.hxx b/sw/inc/view.hxx
index a2d1a86d1356..b793614f58f7 100644
--- a/sw/inc/view.hxx
+++ b/sw/inc/view.hxx
@@ -680,6 +680,7 @@ public:
virtual tools::Rectangle getLOKVisibleArea() const override;
virtual void flushPendingLOKInvalidateTiles() override;
+ virtual OString getLOKPayload(int nType, int nViewId) const override;
};
inline tools::Long SwView::GetXScroll() const
diff --git a/sw/inc/viscrs.hxx b/sw/inc/viscrs.hxx
index 95c013b233ca..3bd001bce074 100644
--- a/sw/inc/viscrs.hxx
+++ b/sw/inc/viscrs.hxx
@@ -47,6 +47,7 @@ class SW_DLLPUBLIC SwVisibleCursor
/// For LibreOfficeKit only - remember what page we were at the last time.
sal_uInt16 m_nPageLastTime;
+ SwRect m_aLastLOKRect;
public:
SwVisibleCursor( const SwCursorShell * pCShell );
@@ -59,6 +60,8 @@ public:
void SetDragCursor( bool bFlag = true ) { m_bIsDragCursor = bFlag; }
void SetPosAndShow(SfxViewShell const * pViewShell);
const vcl::Cursor& GetTextCursor() const;
+
+ OString getLOKPayload(int nType, int nViewId) const;
};
// From here classes/methods for selections.
diff --git a/sw/qa/core/txtnode/txtnode.cxx b/sw/qa/core/txtnode/txtnode.cxx
index 78eecb14a631..9d3c798dc0fa 100644
--- a/sw/qa/core/txtnode/txtnode.cxx
+++ b/sw/qa/core/txtnode/txtnode.cxx
@@ -14,6 +14,7 @@
#include <sfx2/viewsh.hxx>
#include <vcl/gdimtf.hxx>
#include <vcl/scheduler.hxx>
+#include <sfx2/lokhelper.hxx>
#include <test/lokcallback.hxx>
#include <IDocumentStatistics.hxx>
@@ -134,6 +135,7 @@ CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testTitleFieldInvalidate)
ViewCallback aCallback;
TestLokCallbackWrapper aCallbackWrapper(&ViewCallback::callback, &aCallback);
pWrtShell->GetSfxViewShell()->setLibreOfficeKitViewCallback(&aCallbackWrapper);
+ aCallbackWrapper.setLOKViewId(SfxLokHelper::getView(pWrtShell->GetSfxViewShell()));
Scheduler::ProcessEventsToIdle();
aCallback.m_nInvalidations = 0;
diff --git a/sw/qa/extras/tiledrendering/tiledrendering.cxx b/sw/qa/extras/tiledrendering/tiledrendering.cxx
index a9aa0b63cc7c..20a8141584fb 100644
--- a/sw/qa/extras/tiledrendering/tiledrendering.cxx
+++ b/sw/qa/extras/tiledrendering/tiledrendering.cxx
@@ -243,6 +243,7 @@ public:
private:
SwXTextDocument* createDoc(const char* pName = nullptr);
+ void setupLibreOfficeKitViewCallback(SfxViewShell* pViewShell);
static void callback(int nType, const char* pPayload, void* pData);
void callbackImpl(int nType, const char* pPayload);
// First invalidation.
@@ -302,6 +303,7 @@ void SwTiledRenderingTest::tearDown()
mxComponent->dispose();
mxComponent.clear();
}
+ m_callbackWrapper.clear();
comphelper::LibreOfficeKit::setActive(false);
test::BootstrapFixture::tearDown();
@@ -320,6 +322,12 @@ SwXTextDocument* SwTiledRenderingTest::createDoc(const char* pName)
return pTextDocument;
}
+void SwTiledRenderingTest::setupLibreOfficeKitViewCallback(SfxViewShell* pViewShell)
+{
+ pViewShell->setLibreOfficeKitViewCallback(&m_callbackWrapper);
+ m_callbackWrapper.setLOKViewId(SfxLokHelper::getView(pViewShell));
+}
+
void SwTiledRenderingTest::callback(int nType, const char* pPayload, void* pData)
{
static_cast<SwTiledRenderingTest*>(pData)->callbackImpl(nType, pPayload);
@@ -438,7 +446,7 @@ void SwTiledRenderingTest::testRegisterCallback()
{
SwXTextDocument* pXTextDocument = createDoc("dummy.fodt");
SwWrtShell* pWrtShell = pXTextDocument->GetDocShell()->GetWrtShell();
- pWrtShell->GetSfxViewShell()->setLibreOfficeKitViewCallback(&m_callbackWrapper);
+ setupLibreOfficeKitViewCallback(pWrtShell->GetSfxViewShell());
// Insert a character at the beginning of the document.
pWrtShell->Insert("x");
Scheduler::ProcessEventsToIdle();
@@ -621,7 +629,7 @@ void SwTiledRenderingTest::testSearch()
{
SwXTextDocument* pXTextDocument = createDoc("search.odt");
SwWrtShell* pWrtShell = pXTextDocument->GetDocShell()->GetWrtShell();
- pWrtShell->GetSfxViewShell()->setLibreOfficeKitViewCallback(&m_callbackWrapper);
+ setupLibreOfficeKitViewCallback(pWrtShell->GetSfxViewShell());
std::size_t nNode = pWrtShell->getShellCursor(false)->Start()->nNode.GetNode().GetIndex();
// First hit, in the second paragraph, before the shape.
@@ -686,7 +694,7 @@ void SwTiledRenderingTest::testSearchTextFrame()
{
SwXTextDocument* pXTextDocument = createDoc("search.odt");
SwWrtShell* pWrtShell = pXTextDocument->GetDocShell()->GetWrtShell();
- pWrtShell->GetSfxViewShell()->setLibreOfficeKitViewCallback(&m_callbackWrapper);
+ setupLibreOfficeKitViewCallback(pWrtShell->GetSfxViewShell());
uno::Sequence<beans::PropertyValue> aPropertyValues(comphelper::InitPropertySequence(
{
{"SearchItem.SearchString", uno::makeAny(OUString("TextFrame"))},
@@ -701,7 +709,7 @@ void SwTiledRenderingTest::testSearchTextFrameWrapAround()
{
SwXTextDocument* pXTextDocument = createDoc("search.odt");
SwWrtShell* pWrtShell = pXTextDocument->GetDocShell()->GetWrtShell();
- pWrtShell->GetSfxViewShell()->setLibreOfficeKitViewCallback(&m_callbackWrapper);
+ setupLibreOfficeKitViewCallback(pWrtShell->GetSfxViewShell());
uno::Sequence<beans::PropertyValue> aPropertyValues(comphelper::InitPropertySequence(
{
{"SearchItem.SearchString", uno::makeAny(OUString("TextFrame"))},
@@ -719,7 +727,7 @@ void SwTiledRenderingTest::testDocumentSizeChanged()
// Get the current document size.
SwXTextDocument* pXTextDocument = createDoc("2-pages.odt");
SwWrtShell* pWrtShell = pXTextDocument->GetDocShell()->GetWrtShell();
- pWrtShell->GetSfxViewShell()->setLibreOfficeKitViewCallback(&m_callbackWrapper);
+ setupLibreOfficeKitViewCallback(pWrtShell->GetSfxViewShell());
Size aSize = pXTextDocument->getDocumentSize();
// Delete the second page and see how the size changes.
@@ -735,7 +743,7 @@ void SwTiledRenderingTest::testSearchAll()
{
SwXTextDocument* pXTextDocument = createDoc("search.odt");
SwWrtShell* pWrtShell = pXTextDocument->GetDocShell()->GetWrtShell();
- pWrtShell->GetSfxViewShell()->setLibreOfficeKitViewCallback(&m_callbackWrapper);
+ setupLibreOfficeKitViewCallback(pWrtShell->GetSfxViewShell());
uno::Sequence<beans::PropertyValue> aPropertyValues(comphelper::InitPropertySequence(
{
{"SearchItem.SearchString", uno::makeAny(OUString("shape"))},
@@ -753,7 +761,7 @@ void SwTiledRenderingTest::testSearchAllNotifications()
{
SwXTextDocument* pXTextDocument = createDoc("search.odt");
SwWrtShell* pWrtShell = pXTextDocument->GetDocShell()->GetWrtShell();
- pWrtShell->GetSfxViewShell()->setLibreOfficeKitViewCallback(&m_callbackWrapper);
+ setupLibreOfficeKitViewCallback(pWrtShell->GetSfxViewShell());
// Reset notification counter before search.
m_nSelectionBeforeSearchResult = 0;
uno::Sequence<beans::PropertyValue> aPropertyValues(comphelper::InitPropertySequence(
@@ -780,7 +788,7 @@ void SwTiledRenderingTest::testPageDownInvalidation()
}));
pXTextDocument->initializeForTiledRendering(aPropertyValues);
SwWrtShell* pWrtShell = pXTextDocument->GetDocShell()->GetWrtShell();
- pWrtShell->GetSfxViewShell()->setLibreOfficeKitViewCallback(&m_callbackWrapper);
+ setupLibreOfficeKitViewCallback(pWrtShell->GetSfxViewShell());
comphelper::dispatchCommand(".uno:PageDown", uno::Sequence<beans::PropertyValue>());
// This was 2.
@@ -851,6 +859,7 @@ public:
mpViewShell = pViewShell ? pViewShell : SfxViewShell::Current();
mpViewShell->setLibreOfficeKitViewCallback(&m_callbackWrapper);
mnView = SfxLokHelper::getView();
+ m_callbackWrapper.setLOKViewId( mnView );
}
~ViewCallback()
@@ -1052,6 +1061,7 @@ void SwTiledRenderingTest::testViewCursors()
SfxLokHelper::createView();
ViewCallback aView2;
+ Scheduler::ProcessEventsToIdle();
CPPUNIT_ASSERT(aView1.m_bOwnCursorInvalidated);
CPPUNIT_ASSERT(aView1.m_bViewCursorInvalidated);
CPPUNIT_ASSERT(aView2.m_bOwnCursorInvalidated);
@@ -1070,6 +1080,7 @@ void SwTiledRenderingTest::testViewCursors()
pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 5, /*bBasicCall=*/false);
// Create a selection on the word.
pWrtShell->SelWrd();
+ Scheduler::ProcessEventsToIdle();
SwShellCursor* pShellCursor = pWrtShell->getShellCursor(false);
// Did we indeed manage to select the second word?
CPPUNIT_ASSERT_EQUAL(OUString("bbb"), pShellCursor->GetText());
@@ -1529,7 +1540,7 @@ void SwTiledRenderingTest::testTrackChangesCallback()
// Load a document.
SwXTextDocument* pXTextDocument = createDoc("dummy.fodt");
SwWrtShell* pWrtShell = pXTextDocument->GetDocShell()->GetWrtShell();
- pWrtShell->GetSfxViewShell()->setLibreOfficeKitViewCallback(&m_callbackWrapper);
+ setupLibreOfficeKitViewCallback(pWrtShell->GetSfxViewShell());
// Turn on track changes and type "x".
uno::Reference<beans::XPropertySet> xPropertySet(mxComponent, uno::UNO_QUERY);
@@ -1556,7 +1567,7 @@ void SwTiledRenderingTest::testRedlineUpdateCallback()
// Load a document.
SwXTextDocument* pXTextDocument = createDoc("dummy.fodt");
SwWrtShell* pWrtShell = pXTextDocument->GetDocShell()->GetWrtShell();
- pWrtShell->GetSfxViewShell()->setLibreOfficeKitViewCallback(&m_callbackWrapper);
+ setupLibreOfficeKitViewCallback(pWrtShell->GetSfxViewShell());
// Turn on track changes, type "xx" and delete the second one.
uno::Reference<beans::XPropertySet> xPropertySet(mxComponent, uno::UNO_QUERY);
@@ -2346,7 +2357,7 @@ void SwTiledRenderingTest::testSplitNodeRedlineCallback()
// Load a document.
SwXTextDocument* pXTextDocument = createDoc("splitnode_redline_callback.fodt");
SwWrtShell* pWrtShell = pXTextDocument->GetDocShell()->GetWrtShell();
- pWrtShell->GetSfxViewShell()->setLibreOfficeKitViewCallback(&m_callbackWrapper);
+ setupLibreOfficeKitViewCallback(pWrtShell->GetSfxViewShell());
// 1. test case
// Move cursor between the two tracked changes
@@ -2404,7 +2415,7 @@ void SwTiledRenderingTest::testDeleteNodeRedlineCallback()
// Load a document.
SwXTextDocument* pXTextDocument = createDoc("removenode_redline_callback.fodt");
SwWrtShell* pWrtShell = pXTextDocument->GetDocShell()->GetWrtShell();
- pWrtShell->GetSfxViewShell()->setLibreOfficeKitViewCallback(&m_callbackWrapper);
+ setupLibreOfficeKitViewCallback(pWrtShell->GetSfxViewShell());
// 1. test case
// Move cursor between the two tracked changes
@@ -2469,7 +2480,6 @@ void SwTiledRenderingTest::testVisCursorInvalidation()
ViewCallback aView2;
Scheduler::ProcessEventsToIdle();
-
// Move visible cursor in the first view
SfxLokHelper::setView(nView1);
Scheduler::ProcessEventsToIdle();
@@ -2491,6 +2501,7 @@ void SwTiledRenderingTest::testVisCursorInvalidation()
// Insert text in the second view which moves the other view's cursor too
SfxLokHelper::setView(nView2);
+ Scheduler::ProcessEventsToIdle();
aView1.m_bOwnCursorInvalidated = false;
aView1.m_bViewCursorInvalidated = false;
aView2.m_bOwnCursorInvalidated = false;
@@ -2504,12 +2515,19 @@ void SwTiledRenderingTest::testVisCursorInvalidation()
CPPUNIT_ASSERT(aView1.m_bOwnCursorInvalidated);
CPPUNIT_ASSERT(aView2.m_bViewCursorInvalidated);
CPPUNIT_ASSERT(aView2.m_bOwnCursorInvalidated);
+ // Check that views have correct location for the other's cursor.
+ CPPUNIT_ASSERT_EQUAL(aView1.m_aOwnCursor, aView2.m_aViewCursor);
+ CPPUNIT_ASSERT_EQUAL(aView2.m_aOwnCursor, aView1.m_aViewCursor);
+ // Their cursors should be on the same line, first view's more to the right.
+ CPPUNIT_ASSERT_EQUAL(aView1.m_aOwnCursor.getY(), aView2.m_aOwnCursor.getY());
+ CPPUNIT_ASSERT_GREATER(aView2.m_aOwnCursor.getX(), aView1.m_aOwnCursor.getX());
// Do the same as before, but set the related compatibility flag first
SfxLokHelper::setView(nView2);
comphelper::LibreOfficeKit::setViewIdForVisCursorInvalidation(true);
+ Scheduler::ProcessEventsToIdle();
aView1.m_bOwnCursorInvalidated = false;
aView1.m_bViewCursorInvalidated = false;
aView2.m_bOwnCursorInvalidated = false;
@@ -2525,6 +2543,11 @@ void SwTiledRenderingTest::testVisCursorInvalidation()
CPPUNIT_ASSERT(aView2.m_bViewCursorInvalidated);
CPPUNIT_ASSERT(aView2.m_bOwnCursorInvalidated);
CPPUNIT_ASSERT_EQUAL(nView2, aView2.m_nOwnCursorInvalidatedBy);
+ CPPUNIT_ASSERT_EQUAL(aView1.m_aOwnCursor, aView2.m_aViewCursor);
+ CPPUNIT_ASSERT_EQUAL(aView2.m_aOwnCursor, aView1.m_aViewCursor);
+ // Their cursors should be on the same line, first view's more to the right.
+ CPPUNIT_ASSERT_EQUAL(aView1.m_aOwnCursor.getY(), aView2.m_aOwnCursor.getY());
+ CPPUNIT_ASSERT_GREATER(aView2.m_aOwnCursor.getX(), aView1.m_aOwnCursor.getX());
comphelper::LibreOfficeKit::setViewIdForVisCursorInvalidation(false);
}
@@ -2756,7 +2779,7 @@ void SwTiledRenderingTest::testRedlineNotificationDuringSave()
// It's an empty document, just settings.xml and content.xml are custom.
SwXTextDocument* pXTextDocument = createDoc("redline-notification-during-save.odt");
SwWrtShell* pWrtShell = pXTextDocument->GetDocShell()->GetWrtShell();
- pWrtShell->GetSfxViewShell()->setLibreOfficeKitViewCallback(&m_callbackWrapper);
+ setupLibreOfficeKitViewCallback(pWrtShell->GetSfxViewShell());
// Save the document.
utl::MediaDescriptor aMediaDescriptor;
@@ -2772,7 +2795,8 @@ void SwTiledRenderingTest::testHyperlink()
comphelper::LibreOfficeKit::setViewIdForVisCursorInvalidation(true);
SwXTextDocument* pXTextDocument = createDoc("hyperlink.odt");
SwWrtShell* pWrtShell = pXTextDocument->GetDocShell()->GetWrtShell();
- pWrtShell->GetSfxViewShell()->setLibreOfficeKitViewCallback(&m_callbackWrapper);
+ setupLibreOfficeKitViewCallback(pWrtShell->GetSfxViewShell());
+ m_callbackWrapper.setLOKViewId(SfxLokHelper::getView(pWrtShell->GetSfxViewShell()));
SwShellCursor* pShellCursor = pWrtShell->getShellCursor(false);
Point aStart = pShellCursor->GetSttPos();
@@ -2799,7 +2823,7 @@ void SwTiledRenderingTest::testDropDownFormFieldButton()
pXTextDocument->setClientVisibleArea(tools::Rectangle(0, 0, 10000, 4000));
SwWrtShell* pWrtShell = pXTextDocument->GetDocShell()->GetWrtShell();
- pWrtShell->GetSfxViewShell()->setLibreOfficeKitViewCallback(&m_callbackWrapper);
+ setupLibreOfficeKitViewCallback(pWrtShell->GetSfxViewShell());
// Move the cursor to trigger displaying of the field button.
pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
@@ -2872,7 +2896,7 @@ void SwTiledRenderingTest::testDropDownFormFieldButtonEditing()
pXTextDocument->setClientVisibleArea(tools::Rectangle(0, 0, 10000, 4000));
SwWrtShell* pWrtShell = pXTextDocument->GetDocShell()->GetWrtShell();
- pWrtShell->GetSfxViewShell()->setLibreOfficeKitViewCallback(&m_callbackWrapper);
+ setupLibreOfficeKitViewCallback(pWrtShell->GetSfxViewShell());
// Move the cursor to trigger displaying of the field button.
pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
@@ -2929,7 +2953,7 @@ void SwTiledRenderingTest::testDropDownFormFieldButtonNoSelection()
pXTextDocument->setClientVisibleArea(tools::Rectangle(0, 0, 10000, 4000));
SwWrtShell* pWrtShell = pXTextDocument->GetDocShell()->GetWrtShell();
- pWrtShell->GetSfxViewShell()->setLibreOfficeKitViewCallback(&m_callbackWrapper);
+ setupLibreOfficeKitViewCallback(pWrtShell->GetSfxViewShell());
// Move the cursor to trigger displaying of the field button.
pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
@@ -2982,7 +3006,7 @@ void SwTiledRenderingTest::testMoveShapeHandle()
SwXTextDocument* pXTextDocument = createDoc("shape.fodt");
SwWrtShell* pWrtShell = pXTextDocument->GetDocShell()->GetWrtShell();
- pWrtShell->GetSfxViewShell()->setLibreOfficeKitViewCallback(&m_callbackWrapper);
+ setupLibreOfficeKitViewCallback(pWrtShell->GetSfxViewShell());
SdrPage* pPage = pWrtShell->GetDoc()->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0);
SdrObject* pObject = pPage->GetObj(0);
pWrtShell->SelectObj(Point(), 0, pObject);
@@ -3015,7 +3039,7 @@ void SwTiledRenderingTest::testDropDownFormFieldButtonNoItem()
pXTextDocument->setClientVisibleArea(tools::Rectangle(0, 0, 10000, 4000));
SwWrtShell* pWrtShell = pXTextDocument->GetDocShell()->GetWrtShell();
- pWrtShell->GetSfxViewShell()->setLibreOfficeKitViewCallback(&m_callbackWrapper);
+ setupLibreOfficeKitViewCallback(pWrtShell->GetSfxViewShell());
// Move the cursor to trigger displaying of the field button.
pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
@@ -3052,7 +3076,7 @@ void SwTiledRenderingTest::testTablePaintInvalidate()
// Load a document with a table in it.
SwXTextDocument* pXTextDocument = createDoc("table-paint-invalidate.odt");
SwWrtShell* pWrtShell = pXTextDocument->GetDocShell()->GetWrtShell();
- pWrtShell->GetSfxViewShell()->setLibreOfficeKitViewCallback(&m_callbackWrapper);
+ setupLibreOfficeKitViewCallback(pWrtShell->GetSfxViewShell());
// Enter the table.
pWrtShell->Down(/*bSelect=*/false);
Scheduler::ProcessEventsToIdle();
@@ -3150,7 +3174,7 @@ void SwTiledRenderingTest::testBulletDeleteInvalidation()
pWrtShell->GetLayout()->PaintSwFrame(*pWrtShell->GetOut(),
pWrtShell->GetLayout()->getFrameArea());
Scheduler::ProcessEventsToIdle();
- pWrtShell->GetSfxViewShell()->setLibreOfficeKitViewCallback(&m_callbackWrapper);
+ setupLibreOfficeKitViewCallback(pWrtShell->GetSfxViewShell());
m_aInvalidations = tools::Rectangle();
// When pressing backspace in the last paragraph.
@@ -3180,7 +3204,7 @@ void SwTiledRenderingTest::testBulletNoNumInvalidation()
pWrtShell->GetLayout()->PaintSwFrame(*pWrtShell->GetOut(),
pWrtShell->GetLayout()->getFrameArea());
Scheduler::ProcessEventsToIdle();
- pWrtShell->GetSfxViewShell()->setLibreOfficeKitViewCallback(&m_callbackWrapper);
+ setupLibreOfficeKitViewCallback(pWrtShell->GetSfxViewShell());
m_aInvalidations = tools::Rectangle();
// When pressing backspace in the last paragraph to turn bullets off.
@@ -3217,7 +3241,7 @@ void SwTiledRenderingTest::testBulletMultiDeleteInvalidation()
pWrtShell->GetLayout()->PaintSwFrame(*pWrtShell->GetOut(),
pWrtShell->GetLayout()->getFrameArea());
Scheduler::ProcessEventsToIdle();
- pWrtShell->GetSfxViewShell()->setLibreOfficeKitViewCallback(&m_callbackWrapper);
+ setupLibreOfficeKitViewCallback(pWrtShell->GetSfxViewShell());
m_aInvalidations = tools::Rectangle();
// When selecting and deleting several bullets: select till the end of the 2nd para and delete.
diff --git a/sw/source/core/crsr/viscrs.cxx b/sw/source/core/crsr/viscrs.cxx
index b664e5f6c80b..26e3a4d1d30e 100644
--- a/sw/source/core/crsr/viscrs.cxx
+++ b/sw/source/core/crsr/viscrs.cxx
@@ -224,12 +224,64 @@ void SwVisibleCursor::SetPosAndShow(SfxViewShell const * pViewShell)
m_pCursorShell->GetSfxViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_SET_PART, aPayload.getStr());
}
+ // This may get called often, so instead of sending data on each update, just notify
+ // that there's been an update, and the other side will pull the data using
+ // getLOKPayload() when it decides to.
+ m_aLastLOKRect = aRect;
+ if (pViewShell)
+ {
+ if (pViewShell == m_pCursorShell->GetSfxViewShell())
+ {
+ SfxLokHelper::notifyUpdatePerViewId(pViewShell, LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR);
+ }
+ else
+ {
+ SfxLokHelper::notifyUpdatePerViewId(pViewShell, m_pCursorShell->GetSfxViewShell(), pViewShell,
+ LOK_CALLBACK_INVALIDATE_VIEW_CURSOR);
+ }
+ }
+ else
+ {
+ SfxLokHelper::notifyUpdatePerViewId(m_pCursorShell->GetSfxViewShell(), SfxViewShell::Current(),
+ m_pCursorShell->GetSfxViewShell(), LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR);
+ SfxLokHelper::notifyOtherViewsUpdatePerViewId(m_pCursorShell->GetSfxViewShell(), LOK_CALLBACK_INVALIDATE_VIEW_CURSOR);
+ }
+ }
+
+ if ( m_pCursorShell->IsCursorReadonly() && !m_pCursorShell->GetViewOptions()->IsSelectionInReadonly() )
+ return;
+
+ if ( m_pCursorShell->GetDrawView() )
+ const_cast<SwDrawView*>(static_cast<const SwDrawView*>(m_pCursorShell->GetDrawView()))->SetAnimationEnabled(
+ !m_pCursorShell->IsSelection() );
+
+ sal_uInt16 nStyle = m_bIsDragCursor ? CURSOR_SHADOW : 0;
+ if( nStyle != m_aTextCursor.GetStyle() )
+ {
+ m_aTextCursor.SetStyle( nStyle );
+ m_aTextCursor.SetWindow( m_bIsDragCursor ? m_pCursorShell->GetWin() : nullptr );
+ }
+
+ m_aTextCursor.Show();
+}
+
+OString SwVisibleCursor::getLOKPayload(int nType, int nViewId) const
+{
+ assert(nType == LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR || nType == LOK_CALLBACK_INVALIDATE_VIEW_CURSOR);
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ SwRect aRect = m_aLastLOKRect;
+
// notify about the cursor position & size
tools::Rectangle aSVRect(aRect.Pos().getX(), aRect.Pos().getY(), aRect.Pos().getX() + aRect.SSize().Width(), aRect.Pos().getY() + aRect.SSize().Height());
OString sRect = aSVRect.toString();
+ if(nType == LOK_CALLBACK_INVALIDATE_VIEW_CURSOR)
+ return SfxLokHelper::makePayloadJSON(m_pCursorShell->GetSfxViewShell(), nViewId, "rectangle", sRect);
+
// is cursor at a misspelled word ?
bool bIsWrong = false;
+ SwView* pView = dynamic_cast<SwView*>(m_pCursorShell->GetSfxViewShell());
if (pView && pView->GetWrtShellPtr())
{
const SwViewOption* pVOpt = pView->GetWrtShell().GetViewOptions();
@@ -284,37 +336,10 @@ void SwVisibleCursor::SetPosAndShow(SfxViewShell const * pViewShell)
}
}
- if (pViewShell)
- {
- if (pViewShell == m_pCursorShell->GetSfxViewShell())
- {
- SfxLokHelper::notifyVisCursorInvalidation(pViewShell, sRect, bIsWrong, sHyperlink);
- }
- else
- SfxLokHelper::notifyOtherView(m_pCursorShell->GetSfxViewShell(), pViewShell, LOK_CALLBACK_INVALIDATE_VIEW_CURSOR, "rectangle", sRect);
- }
- else
- {
- SfxLokHelper::notifyVisCursorInvalidation(m_pCursorShell->GetSfxViewShell(), sRect, bIsWrong, sHyperlink);
- SfxLokHelper::notifyOtherViews(m_pCursorShell->GetSfxViewShell(), LOK_CALLBACK_INVALIDATE_VIEW_CURSOR, "rectangle", sRect);
- }
+ return SfxLokHelper::makeVisCursorInvalidation(nViewId, sRect, bIsWrong, sHyperlink);
}
-
- if ( m_pCursorShell->IsCursorReadonly() && !m_pCursorShell->GetViewOptions()->IsSelectionInReadonly() )
- return;
-
- if ( m_pCursorShell->GetDrawView() )
- const_cast<SwDrawView*>(static_cast<const SwDrawView*>(m_pCursorShell->GetDrawView()))->SetAnimationEnabled(
- !m_pCursorShell->IsSelection() );
-
- sal_uInt16 nStyle = m_bIsDragCursor ? CURSOR_SHADOW : 0;
- if( nStyle != m_aTextCursor.GetStyle() )
- {
- m_aTextCursor.SetStyle( nStyle );
- m_aTextCursor.SetWindow( m_bIsDragCursor ? m_pCursorShell->GetWin() : nullptr );
- }
-
- m_aTextCursor.Show();
+ else
+ abort();
}
const vcl::Cursor& SwVisibleCursor::GetTextCursor() const
diff --git a/sw/source/uibase/inc/wrtsh.hxx b/sw/source/uibase/inc/wrtsh.hxx
index a8cc9a49d6cb..a98cb26bfdfc 100644
--- a/sw/source/uibase/inc/wrtsh.hxx
+++ b/sw/source/uibase/inc/wrtsh.hxx
@@ -493,6 +493,8 @@ typedef bool (SwWrtShell::*FNSimpleMove)();
void ToggleOutlineContentVisibility(SwNode* pNd, bool bForceFold = false);
void ToggleOutlineContentVisibility(const size_t nPos, bool bForceFold = false);
+ OString getLOKPayload(int nType, int nViewId) const;
+
private:
SAL_DLLPRIVATE void OpenMark();
diff --git a/sw/source/uibase/uiview/view.cxx b/sw/source/uibase/uiview/view.cxx
index 96f53fda5923..ebf2a31fc08c 100644
--- a/sw/source/uibase/uiview/view.cxx
+++ b/sw/source/uibase/uiview/view.cxx
@@ -1892,6 +1892,13 @@ void SwView::flushPendingLOKInvalidateTiles()
pSh->FlushPendingLOKInvalidateTiles();
}
+OString SwView::getLOKPayload(int nType, int nViewId) const
+{
+ SwWrtShell* pSh = GetWrtShellPtr();
+ assert(pSh);
+ return pSh->getLOKPayload(nType, nViewId);
+}
+
OUString SwView::GetDataSourceName() const
{
uno::Reference<lang::XMultiServiceFactory> xFactory(GetDocShell()->GetModel(), uno::UNO_QUERY);
diff --git a/sw/source/uibase/wrtsh/wrtsh4.cxx b/sw/source/uibase/wrtsh/wrtsh4.cxx
index 8009ce98037b..b80b41b41e54 100644
--- a/sw/source/uibase/wrtsh/wrtsh4.cxx
+++ b/sw/source/uibase/wrtsh/wrtsh4.cxx
@@ -19,6 +19,8 @@
#include <wrtsh.hxx>
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+
// Private methods, which move the cursor over search.
// The removal of the selection must be made on the level above.
@@ -232,4 +234,15 @@ bool SwWrtShell::BwdPara_()
return bRet;
}
+OString SwWrtShell::getLOKPayload(int nType, int nViewId) const
+{
+ switch(nType)
+ {
+ case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR:
+ case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR:
+ return GetVisibleCursor()->getLOKPayload(nType, nViewId);
+ }
+ abort();
+}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/test/source/lokcallback.cxx b/test/source/lokcallback.cxx
index 13d381f0b46a..8cda54424961 100644
--- a/test/source/lokcallback.cxx
+++ b/test/source/lokcallback.cxx
@@ -25,22 +25,37 @@ TestLokCallbackWrapper::TestLokCallbackWrapper(LibreOfficeKitCallback callback,
SetPriority(TaskPriority::LOWEST);
}
-inline void TestLokCallbackWrapper::callCallback(int nType, const char* pPayload)
+void TestLokCallbackWrapper::clear()
+{
+ m_viewId = -1;
+ m_updatedTypes.clear();
+ m_updatedTypesPerViewId.clear();
+}
+
+inline void TestLokCallbackWrapper::startTimer()
{
- m_callback(nType, pPayload, m_data);
if (!IsActive())
Start();
}
+static constexpr int NO_VIEWID = -1;
+
+inline void TestLokCallbackWrapper::callCallback(int nType, const char* pPayload, int nViewId)
+{
+ discardUpdatedTypes(nType, nViewId);
+ m_callback(nType, pPayload, m_data);
+ startTimer();
+}
+
void TestLokCallbackWrapper::libreOfficeKitViewCallback(int nType, const char* pPayload)
{
- callCallback(nType, pPayload);
+ callCallback(nType, pPayload, NO_VIEWID);
}
void TestLokCallbackWrapper::libreOfficeKitViewCallbackWithViewId(int nType, const char* pPayload,
- int /*nViewId*/)
+ int nViewId)
{
- callCallback(nType, pPayload); // the view id is also included in payload
+ callCallback(nType, pPayload, nViewId);
}
void TestLokCallbackWrapper::libreOfficeKitViewInvalidateTilesCallback(
@@ -56,7 +71,100 @@ void TestLokCallbackWrapper::libreOfficeKitViewInvalidateTilesCallback(
buf.append(", ");
buf.append(static_cast<sal_Int32>(nPart));
}
- callCallback(LOK_CALLBACK_INVALIDATE_TILES, buf.makeStringAndClear().getStr());
+ callCallback(LOK_CALLBACK_INVALIDATE_TILES, buf.makeStringAndClear().getStr(), NO_VIEWID);
+}
+
+// TODO This is probably a pointless code duplication with CallbackFlushHandler,
+// and using this in unittests also means that CallbackFlushHandler does not get
+// tested as thoroughly as it could. On the other hand, this class is simpler,
+// so debugging those unittests should also be simpler. The proper solution
+// is presumably this class using CallbackFlushHandler internally by default,
+// but having an option to use this simpler code when needed.
+
+void TestLokCallbackWrapper::libreOfficeKitViewUpdatedCallback(int nType)
+{
+ if (std::find(m_updatedTypes.begin(), m_updatedTypes.end(), nType) == m_updatedTypes.end())
+ {
+ m_updatedTypes.push_back(nType);
+ startTimer();
+ }
+}
+
+void TestLokCallbackWrapper::libreOfficeKitViewUpdatedCallbackPerViewId(int nType, int nViewId,
+ int nSourceViewId)
+{
+ const PerViewIdData data{ nType, nViewId, nSourceViewId };
+ auto& l = m_updatedTypesPerViewId;
+ // The source view doesn't matter for uniqueness, just keep the latest one.
+ auto it = std::find_if(l.begin(), l.end(), [data](const PerViewIdData& other) {
+ return data.type == other.type && data.viewId == other.viewId;
+ });
+ if (it != l.end())
+ *it = data;
+ else
+ l.push_back(data);
+ startTimer();
+}
+
+void TestLokCallbackWrapper::discardUpdatedTypes(int nType, int nViewId)
+{
+ // If a callback is called directly with an event, drop the updated flag for it, since
+ // the direct event replaces it.
+ for (auto it = m_updatedTypes.begin(); it != m_updatedTypes.end();)
+ {
+ if (*it == nType)
+ it = m_updatedTypes.erase(it);
+ else
+ ++it;
+ }
+ // If we do not have a specific view id, drop flag for all views.
+ bool allViewIds = false;
+ if (nViewId < 0)
+ allViewIds = true;
+ if (nType == LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
+ && !comphelper::LibreOfficeKit::isViewIdForVisCursorInvalidation())
+ allViewIds = true;
+ for (auto it = m_updatedTypesPerViewId.begin(); it != m_updatedTypesPerViewId.end();)
+ {
+ if (it->type == nType && (allViewIds || it->viewId == nViewId))
+ it = m_updatedTypesPerViewId.erase(it);
+ else
+ ++it;
+ }
+}
+
+void TestLokCallbackWrapper::flushLOKData()
+{
+ if (m_updatedTypes.empty() && m_updatedTypesPerViewId.empty())
+ return;
+ // Ask for payloads of all the pending types that need updating, and call the generic callback with that data.
+ assert(m_viewId >= 0);
+ SfxViewShell* viewShell = SfxViewShell::GetFirst(false, [this](const SfxViewShell* shell) {
+ return shell->GetViewShellId().get() == m_viewId;
+ });
+ assert(viewShell != nullptr);
+ // First move data to local structures, so that notifyFromLOKCallback() doesn't modify it.
+ std::vector<int> updatedTypes;
+ std::swap(updatedTypes, m_updatedTypes);
+ std::vector<PerViewIdData> updatedTypesPerViewId;
+ std::swap(updatedTypesPerViewId, m_updatedTypesPerViewId);
+
+ for (int type : updatedTypes)
+ {
+ OString payload = viewShell->getLOKPayload(type, m_viewId);
+ if (!payload.isEmpty())
+ libreOfficeKitViewCallback(type, payload.getStr());
+ }
+ for (const PerViewIdData& data : updatedTypesPerViewId)
+ {
+ viewShell = SfxViewShell::GetFirst(false, [data](const SfxViewShell* shell) {
+ return shell->GetViewShellId().get() == data.sourceViewId;
+ });
+ assert(viewShell != nullptr);
+ OString payload = viewShell->getLOKPayload(data.type, data.viewId);
+ if (!payload.isEmpty())
+ libreOfficeKitViewCallbackWithViewId(data.type, payload.getStr(), data.viewId);
+ }
}
void TestLokCallbackWrapper::Invoke()
@@ -67,6 +175,7 @@ void TestLokCallbackWrapper::Invoke()
{
viewShell->flushPendingLOKInvalidateTiles();
}
+ flushLOKData();
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */