summaryrefslogtreecommitdiffstats
path: root/test/source/lokcallback.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'test/source/lokcallback.cxx')
-rw-r--r--test/source/lokcallback.cxx183
1 files changed, 183 insertions, 0 deletions
diff --git a/test/source/lokcallback.cxx b/test/source/lokcallback.cxx
new file mode 100644
index 000000000..323ba4af1
--- /dev/null
+++ b/test/source/lokcallback.cxx
@@ -0,0 +1,183 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <test/lokcallback.hxx>
+
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <rtl/strbuf.hxx>
+#include <tools/gen.hxx>
+#include <comphelper/lok.hxx>
+#include <sfx2/viewsh.hxx>
+
+TestLokCallbackWrapper::TestLokCallbackWrapper(LibreOfficeKitCallback callback, void* data)
+ : Idle("TestLokCallbackWrapper flush timer")
+ , m_callback(callback)
+ , m_data(data)
+{
+ // Flushing timer needs to run with the lowest priority, so that all pending tasks
+ // such as invalidations are processed before it.
+ SetPriority(TaskPriority::LOWEST);
+}
+
+void TestLokCallbackWrapper::clear()
+{
+ m_viewId = -1;
+ m_updatedTypes.clear();
+ m_updatedTypesPerViewId.clear();
+}
+
+inline void TestLokCallbackWrapper::startTimer()
+{
+ if (!IsActive())
+ Start();
+}
+
+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, NO_VIEWID);
+}
+
+void TestLokCallbackWrapper::libreOfficeKitViewCallbackWithViewId(int nType, const char* pPayload,
+ int nViewId)
+{
+ callCallback(nType, pPayload, nViewId);
+}
+
+void TestLokCallbackWrapper::libreOfficeKitViewInvalidateTilesCallback(
+ const tools::Rectangle* pRect, int nPart)
+{
+ OStringBuffer buf(64);
+ if (pRect)
+ buf.append(pRect->toString());
+ else
+ buf.append("EMPTY");
+ if (comphelper::LibreOfficeKit::isPartInInvalidation())
+ {
+ buf.append(", ");
+ buf.append(static_cast<sal_Int32>(nPart));
+ }
+ 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 callbacks don't possibly modify it.
+ std::vector<int> updatedTypes;
+ std::swap(updatedTypes, m_updatedTypes);
+ std::vector<PerViewIdData> updatedTypesPerViewId;
+ std::swap(updatedTypesPerViewId, m_updatedTypesPerViewId);
+
+ for (int type : updatedTypes)
+ {
+ bool ignore = false;
+ OString payload = viewShell->getLOKPayload(type, m_viewId, &ignore);
+ if (!ignore)
+ 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);
+ bool ignore = false;
+ OString payload = viewShell->getLOKPayload(data.type, data.viewId, &ignore);
+ if (!ignore)
+ libreOfficeKitViewCallbackWithViewId(data.type, payload.getStr(), data.viewId);
+ }
+}
+
+void TestLokCallbackWrapper::Invoke()
+{
+ // Timer timeout, flush any possibly pending data.
+ for (SfxViewShell* viewShell = SfxViewShell::GetFirst(false); viewShell != nullptr;
+ viewShell = SfxViewShell::GetNext(*viewShell, false))
+ {
+ viewShell->flushPendingLOKInvalidateTiles();
+ }
+ flushLOKData();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */