sw/Library_swqahelper.mk                                    |    3 
 sw/qa/extras/tiledrendering/tiledrendering.cxx              |  126 +-
 sw/qa/extras/tiledrendering/tiledrendering2.cxx             |   63 -
 sw/qa/extras/tiledrendering/tiledrenderingmodeltestbase.cxx |  531 ------------
 sw/qa/inc/swtestviewcallback.hxx                            |   70 +
 sw/qa/inc/swtiledrenderingtest.hxx                          |   64 +
 sw/qa/unit/swtestviewcallback.cxx                           |  205 ++++
 sw/qa/unit/swtiledrenderingtest.cxx                         |  230 +++++
 8 files changed, 697 insertions(+), 595 deletions(-)

New commits:
commit 115ff718c45bba45dfbd981fc6759bc209706ea6
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Wed Jan 8 08:50:38 2025 +0100
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Fri Mar 7 13:47:32 2025 +0100

    sw: stop including .cxx files in Writer tests
    
    The remaining 2 classes are not used in multiple .cxx files, so just
    move them closer to their only user.
    
    [ Pick to co-25.04, to reduce conflicts vs master. ]
    
    Change-Id: I7c7b295e21ea97acf33d7f4a60a61b25788ab5c2
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/179926
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    Tested-by: Jenkins

diff --git a/sw/qa/extras/tiledrendering/tiledrendering.cxx 
b/sw/qa/extras/tiledrendering/tiledrendering.cxx
index 259d785b7b0b..1e404a1d733a 100644
--- a/sw/qa/extras/tiledrendering/tiledrendering.cxx
+++ b/sw/qa/extras/tiledrendering/tiledrendering.cxx
@@ -7,17 +7,21 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
-#include "tiledrenderingmodeltestbase.cxx"
+#include <swtiledrenderingtest.hxx>
 
 #include <string>
 #include <string_view>
 
+#include <boost/property_tree/json_parser.hpp>
+
 #include <com/sun/star/frame/XStorable.hpp>
 #include <com/sun/star/frame/Desktop.hpp>
 #include <com/sun/star/text/XTextViewCursorSupplier.hpp>
 #include <com/sun/star/text/XTextField.hpp>
 #include <com/sun/star/text/AuthorDisplayFormat.hpp>
 #include <com/sun/star/datatransfer/XTransferable2.hpp>
+#include <com/sun/star/frame/XDispatchResultListener.hpp>
+#include <com/sun/star/frame/DispatchResultState.hpp>
 
 #include <test/helper/transferable.hxx>
 #include <comphelper/dispatchcommand.hxx>
@@ -47,6 +51,10 @@
 #include <comphelper/propertyvalue.hxx>
 #include <comphelper/scopeguard.hxx>
 #include <unotools/searchopt.hxx>
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <sfx2/lokhelper.hxx>
+#include <comphelper/lok.hxx>
+#include <comphelper/string.hxx>
 
 #include <drawdoc.hxx>
 #include <ndtxt.hxx>
@@ -61,7 +69,11 @@
 #include <txtfrm.hxx>
 #include <rootfrm.hxx>
 #include <fmtanchr.hxx>
+#include <docsh.hxx>
+#include <wrtsh.hxx>
+#include <unotxdoc.hxx>
 #include <textcontentcontrol.hxx>
+#include <swtestviewcallback.hxx>
 
 static std::ostream& operator<<(std::ostream& os, ViewShellId id)
 {
@@ -1711,6 +1723,30 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testPaintCallbacks)
     CPPUNIT_ASSERT(!aView1.m_bCalled);
 }
 
+namespace
+{
+class TestResultListener : public 
cppu::WeakImplHelper<css::frame::XDispatchResultListener>
+{
+public:
+    sal_uInt32 m_nDocRepair;
+
+    TestResultListener()
+        : m_nDocRepair(0)
+    {
+    }
+
+    virtual void SAL_CALL dispatchFinished(const 
css::frame::DispatchResultEvent& rEvent) override
+    {
+        if (rEvent.State == frame::DispatchResultState::SUCCESS)
+        {
+            rEvent.Result >>= m_nDocRepair;
+        }
+    }
+
+    virtual void SAL_CALL disposing(const css::lang::EventObject&) override {}
+};
+}
+
 CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testUndoRepairResult)
 {
     // Load a document and create two views.
diff --git a/sw/qa/extras/tiledrendering/tiledrendering2.cxx 
b/sw/qa/extras/tiledrendering/tiledrendering2.cxx
index 936938c82901..c33a9204fad1 100644
--- a/sw/qa/extras/tiledrendering/tiledrendering2.cxx
+++ b/sw/qa/extras/tiledrendering/tiledrendering2.cxx
@@ -7,7 +7,7 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
-#include "tiledrenderingmodeltestbase.cxx"
+#include <swtiledrenderingtest.hxx>
 
 #include <com/sun/star/util/URLTransformer.hpp>
 
@@ -22,12 +22,18 @@
 #include <comphelper/dispatchcommand.hxx>
 #include <comphelper/scopeguard.hxx>
 #include <sfx2/dispatch.hxx>
+#include <sfx2/lokhelper.hxx>
+#include <comphelper/lok.hxx>
+#include <unotxdoc.hxx>
 
 #include <view.hxx>
 #include <IDocumentLayoutAccess.hxx>
 #include <rootfrm.hxx>
 #include <pagefrm.hxx>
 #include <cmdid.h>
+#include <docsh.hxx>
+#include <wrtsh.hxx>
+#include <swtestviewcallback.hxx>
 
 namespace
 {
@@ -191,6 +197,25 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testAsyncLayout)
     CPPUNIT_ASSERT(!pPage3->IsInvalidContent());
 }
 
+/// Test callback that works with 
comphelper::LibreOfficeKit::setAnyInputCallback().
+class AnyInputCallback final
+{
+public:
+    static bool callback(void* /*pData*/, int /*nPriority*/) { return true; }
+
+    AnyInputCallback()
+    {
+        comphelper::LibreOfficeKit::setAnyInputCallback(&callback, this,
+                                                        []() -> int { return 
-1; });
+    }
+
+    ~AnyInputCallback()
+    {
+        comphelper::LibreOfficeKit::setAnyInputCallback(nullptr, nullptr,
+                                                        []() -> int { return 
-1; });
+    }
+};
+
 CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testAnyInput)
 {
     // Given a document with 3 pages, the first page is visible:
diff --git a/sw/qa/extras/tiledrendering/tiledrenderingmodeltestbase.cxx 
b/sw/qa/extras/tiledrendering/tiledrenderingmodeltestbase.cxx
deleted file mode 100644
index 09630d80b5e4..000000000000
--- a/sw/qa/extras/tiledrendering/tiledrenderingmodeltestbase.cxx
+++ /dev/null
@@ -1,67 +0,0 @@
-/* -*- 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 <swtiledrenderingtest.hxx>
-#include <swtestviewcallback.hxx>
-
-#include <com/sun/star/frame/DispatchResultState.hpp>
-#include <com/sun/star/frame/XDispatchResultListener.hpp>
-#include <boost/property_tree/json_parser.hpp>
-#include <swmodule.hxx>
-#include <swdll.hxx>
-#include <sfx2/lokhelper.hxx>
-#include <test/lokcallback.hxx>
-#include <LibreOfficeKit/LibreOfficeKitEnums.h>
-#include <comphelper/lok.hxx>
-#include <comphelper/string.hxx>
-#include <docsh.hxx>
-#include <unotxdoc.hxx>
-#include <wrtsh.hxx>
-
-class TestResultListener : public 
cppu::WeakImplHelper<css::frame::XDispatchResultListener>
-{
-public:
-    sal_uInt32 m_nDocRepair;
-
-    TestResultListener()
-        : m_nDocRepair(0)
-    {
-    }
-
-    virtual void SAL_CALL dispatchFinished(const 
css::frame::DispatchResultEvent& rEvent) override
-    {
-        if (rEvent.State == frame::DispatchResultState::SUCCESS)
-        {
-            rEvent.Result >>= m_nDocRepair;
-        }
-    }
-
-    virtual void SAL_CALL disposing(const css::lang::EventObject&) override {}
-};
-
-/// Test callback that works with 
comphelper::LibreOfficeKit::setAnyInputCallback().
-class AnyInputCallback final
-{
-public:
-    static bool callback(void* /*pData*/, int /*nPriority*/) { return true; }
-
-    AnyInputCallback()
-    {
-        comphelper::LibreOfficeKit::setAnyInputCallback(&callback, this,
-                                                        []() -> int { return 
-1; });
-    }
-
-    ~AnyInputCallback()
-    {
-        comphelper::LibreOfficeKit::setAnyInputCallback(nullptr, nullptr,
-                                                        []() -> int { return 
-1; });
-    }
-};
-
-/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 5e04458db255359885536f2bba11de1e15d3fe86
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Tue Jan 7 13:55:51 2025 +0100
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Fri Mar 7 13:47:26 2025 +0100

    sw: move ViewCallback to Library_swqahelper
    
    Towards not including .cxx files in Writer tests.
    
    [ Pick to co-25.04, to reduce conflicts vs master. ]
    
    Change-Id: I42c6dba93599819ff93c92444a91a7ddc29ece38
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/179885
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    Tested-by: Jenkins

diff --git a/sw/Library_swqahelper.mk b/sw/Library_swqahelper.mk
index aa0f05575340..a2e1adbd9b6d 100644
--- a/sw/Library_swqahelper.mk
+++ b/sw/Library_swqahelper.mk
@@ -68,6 +68,7 @@ $(eval $(call gb_Library_use_libraries,swqahelper,\
 $(eval $(call gb_Library_add_exception_objects,swqahelper,\
        sw/qa/unit/swmodeltestbase \
        sw/qa/unit/swtiledrenderingtest \
+       sw/qa/unit/swtestviewcallback \
 ))
 
 # vim: set noet sw=4 ts=4:
diff --git a/sw/qa/extras/tiledrendering/tiledrendering.cxx 
b/sw/qa/extras/tiledrendering/tiledrendering.cxx
index 26eed6a2b475..259d785b7b0b 100644
--- a/sw/qa/extras/tiledrendering/tiledrendering.cxx
+++ b/sw/qa/extras/tiledrendering/tiledrendering.cxx
@@ -499,10 +499,10 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testMissingInvalidation)
 {
     // Create two views.
     SwXTextDocument* pXTextDocument = createDoc("dummy.fodt");
-    ViewCallback aView1;
+    SwTestViewCallback aView1;
     int nView1 = SfxLokHelper::getView();
     SfxLokHelper::createView();
-    ViewCallback aView2;
+    SwTestViewCallback aView2;
     int nView2 = SfxLokHelper::getView();
 
     // First view: put the cursor into the first word.
@@ -531,9 +531,9 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testMissingInvalidation)
 CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testViewCursors)
 {
     createDoc("dummy.fodt");
-    ViewCallback aView1;
+    SwTestViewCallback aView1;
     SfxLokHelper::createView();
-    ViewCallback aView2;
+    SwTestViewCallback aView2;
 
     Scheduler::ProcessEventsToIdle();
     CPPUNIT_ASSERT(aView1.m_bOwnCursorInvalidated);
@@ -570,10 +570,10 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testShapeViewCursors)
 {
     // Load a document and create a view, so we have 2 ones.
     SwXTextDocument* pXTextDocument = createDoc("shape.fodt");
-    ViewCallback aView1;
+    SwTestViewCallback aView1;
     SfxLokHelper::createView();
     
pXTextDocument->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>());
-    ViewCallback aView2;
+    SwTestViewCallback aView2;
     SwWrtShell* pWrtShell2 = getSwDocShell()->GetWrtShell();
 
     // Start shape text in the second view.
@@ -605,10 +605,10 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testViewCursorVisibility)
 {
     // Load a document that has a shape and create two views.
     SwXTextDocument* pXTextDocument = createDoc("shape.fodt");
-    ViewCallback aView1;
+    SwTestViewCallback aView1;
     SfxLokHelper::createView();
     
pXTextDocument->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>());
-    ViewCallback aView2;
+    SwTestViewCallback aView2;
     // This failed, initially the view cursor in the second view wasn't 
visible.
     CPPUNIT_ASSERT(aView2.m_bViewCursorVisible);
 
@@ -629,11 +629,11 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testViewCursorCleanup)
 {
     // Load a document that has a shape and create two views.
     SwXTextDocument* pXTextDocument = createDoc("shape.fodt");
-    ViewCallback aView1;
+    SwTestViewCallback aView1;
     int nView2 = SfxLokHelper::createView();
     
pXTextDocument->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>());
     {
-        ViewCallback aView2;
+        SwTestViewCallback aView2;
 
         // Click on the shape in the second view.
         SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
@@ -659,10 +659,10 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testViewLock)
 {
     // Load a document that has a shape and create two views.
     SwXTextDocument* pXTextDocument = createDoc("shape.fodt");
-    ViewCallback aView1;
+    SwTestViewCallback aView1;
     SfxLokHelper::createView();
     
pXTextDocument->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>());
-    ViewCallback aView2;
+    SwTestViewCallback aView2;
 
     // Begin text edit in the second view and assert that the first gets a lock
     // notification.
@@ -684,10 +684,10 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testTextEditViewInvalidations)
 {
     // Load a document that has a shape and create two views.
     SwXTextDocument* pXTextDocument = createDoc("shape.fodt");
-    ViewCallback aView1;
+    SwTestViewCallback aView1;
     SfxLokHelper::createView();
     
pXTextDocument->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>());
-    ViewCallback aView2;
+    SwTestViewCallback aView2;
 
     // Begin text edit in the second view.
     SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
@@ -710,11 +710,11 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testUndoInvalidations)
 {
     // Load a document and create two views.
     SwXTextDocument* pXTextDocument = createDoc("dummy.fodt");
-    ViewCallback aView1;
+    SwTestViewCallback aView1;
     int nView1 = SfxLokHelper::getView();
     SfxLokHelper::createView();
     
pXTextDocument->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>());
-    ViewCallback aView2;
+    SwTestViewCallback aView2;
     SfxLokHelper::setView(nView1);
 
     // Insert a character the end of the document.
@@ -1075,7 +1075,7 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testShapeTextUndoGroupShells)
 {
     // Load a document and create a view.
     SwXTextDocument* pXTextDocument = createDoc("shape.fodt");
-    ViewCallback aView1;
+    SwTestViewCallback aView1;
     sal_Int32 nView1 = SfxLokHelper::getView();
 
     // Begin text edit.
@@ -1114,7 +1114,7 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testShapeTextUndoGroupShells)
     // cursor position as the old one.
     SfxLokHelper::createView();
     pXTextDocument->initializeForTiledRendering({});
-    ViewCallback aView2;
+    SwTestViewCallback aView2;
     // Difference was 935 twips, the new view didn't see the editeng cursor of
     // the old one. The new difference should be <1px, but here we deal with 
twips.
     CPPUNIT_ASSERT(std::abs(aView1.m_aOwnCursor.Top() - 
aView2.m_aViewCursor.Top()) < 10);
@@ -1135,7 +1135,7 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testTrackChanges)
     uno::Reference<beans::XPropertySet> xPropertySet(mxComponent, 
uno::UNO_QUERY);
     xPropertySet->setPropertyValue(u"RecordChanges"_ustr, uno::Any(true));
     SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
-    ViewCallback aView(pWrtShell->GetSfxViewShell());
+    SwTestViewCallback aView(pWrtShell->GetSfxViewShell());
     pWrtShell->EndOfSection();
     pWrtShell->Insert(u"zzz"_ustr);
     pWrtShell->StartOfSection();
@@ -1257,7 +1257,7 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testGetViewRenderState)
     addDarkLightThemes(COL_BLACK, COL_WHITE);
     SwXTextDocument* pXTextDocument = createDoc();
     int nFirstViewId = SfxLokHelper::getView();
-    ViewCallback aView1;
+    SwTestViewCallback aView1;
     {
         SwViewOption aViewOptions;
         aViewOptions.SetViewMetaChars(true);
@@ -1269,7 +1269,7 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testGetViewRenderState)
     // Create a second view
     SfxLokHelper::createView();
     int nSecondViewId = SfxLokHelper::getView();
-    ViewCallback aView2;
+    SwTestViewCallback aView2;
     {
         // Give the second view different options
         SwViewOption aViewOptions;
@@ -1328,7 +1328,7 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testThemeViewSeparation)
     addDarkLightThemes(aDarkColor, COL_WHITE);
     SwXTextDocument* pXTextDocument = createDoc();
     int nFirstViewId = SfxLokHelper::getView();
-    ViewCallback aView1;
+    SwTestViewCallback aView1;
     // Set first view to light scheme
     {
         SwView* pView = getSwDocShell()->GetView();
@@ -1345,7 +1345,7 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testThemeViewSeparation)
     // Create second view
     SfxLokHelper::createView();
     int nSecondViewId = SfxLokHelper::getView();
-    ViewCallback aView2;
+    SwTestViewCallback aView2;
     // Set second view to dark scheme
     {
         SwView* pView = getSwDocShell()->GetView();
@@ -1386,7 +1386,7 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testInvertBackgroundViewSeparation)
     addDarkLightThemes(aDarkColor, COL_WHITE);
     SwXTextDocument* pXTextDocument = createDoc();
     int nFirstViewId = SfxLokHelper::getView();
-    ViewCallback aView1;
+    SwTestViewCallback aView1;
     // Set view to dark scheme
     {
         SwView* pView = getSwDocShell()->GetView();
@@ -1403,7 +1403,7 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testInvertBackgroundViewSeparation)
     // Create second view
     SfxLokHelper::createView();
     int nSecondViewId = SfxLokHelper::getView();
-    ViewCallback aView2;
+    SwTestViewCallback aView2;
     // Set second view to dark scheme
     {
         SwView* pView = getSwDocShell()->GetView();
@@ -1480,7 +1480,7 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testThemeChangeBackgroundCallback)
     Color aDarkColor(0x1c, 0x1c, 0x1c);
     addDarkLightThemes(aDarkColor, COL_WHITE);
     createDoc();
-    ViewCallback aView;
+    SwTestViewCallback aView;
 
     SwView* pView = getSwDocShell()->GetView();
     uno::Reference<frame::XFrame> xFrame = 
pView->GetViewFrame().GetFrame().GetFrameInterface();
@@ -1511,7 +1511,7 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testSetViewGraphicSelection)
     // Load a document.
     SwXTextDocument* pXTextDocument = createDoc("frame.odt");
     int nView1 = SfxLokHelper::getView();
-    ViewCallback aView1;
+    SwTestViewCallback aView1;
     // Create a second view, and switch back to the first view.
     SfxLokHelper::createView();
     pXTextDocument->initializeForTiledRendering({});
@@ -1535,7 +1535,7 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testCreateViewGraphicSelection)
 {
     // Load a document.
     createDoc("frame.odt");
-    ViewCallback aView1;
+    SwTestViewCallback aView1;
 
     // Mark the textframe in the first view.
     SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
@@ -1554,8 +1554,8 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testCreateViewGraphicSelection)
     CPPUNIT_ASSERT(aView1.m_bGraphicSelection);
 
     // Make sure that the hidden text cursor isn't visible in the second view, 
either.
-    ViewCallback aView2(SfxViewShell::Current(),
-            [](ViewCallback& rView) { rView.m_bViewCursorVisible = true; });
+    SwTestViewCallback aView2(SfxViewShell::Current(),
+            [](SwTestViewCallback& rView) { rView.m_bViewCursorVisible = true; 
});
     // This was true, the second view didn't get the visibility of the text
     // cursor of the first view.
     CPPUNIT_ASSERT(!aView2.m_bViewCursorVisible);
@@ -1568,7 +1568,7 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testCreateViewTextSelection)
 {
     // Load a document.
     createDoc("dummy.fodt");
-    ViewCallback aView1;
+    SwTestViewCallback aView1;
 
     // Create a text selection:
     SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
@@ -1584,7 +1584,7 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testCreateViewTextSelection)
     SfxLokHelper::createView();
 
     // Make sure that the text selection is visible in the second view.
-    ViewCallback aView2;
+    SwTestViewCallback aView2;
     // This failed, the second view didn't get the text selection of the first 
view.
     CPPUNIT_ASSERT(!aView2.m_aViewSelection.isEmpty());
 }
@@ -1614,7 +1614,7 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testCommentEndTextEdit)
 {
     // Create a document, type a character and remember the cursor position.
     SwXTextDocument* pXTextDocument = createDoc();
-    ViewCallback aView1;
+    SwTestViewCallback aView1;
     emulateTyping(u"x");
     tools::Rectangle aBodyCursor = aView1.m_aOwnCursor;
 
@@ -1659,7 +1659,7 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testCommentInsert)
             {"Text", uno::Any(u"some text"_ustr)},
             {"Author", uno::Any(u"me"_ustr)},
             });
-    ViewCallback aView;
+    SwTestViewCallback aView;
     comphelper::dispatchCommand(u".uno:InsertAnnotation"_ustr, xFrame, 
aPropertyValues);
     Scheduler::ProcessEventsToIdle();
     OString 
aAnchorPos(aView.m_aComment.get_child("anchorPos").get_value<std::string>());
@@ -1675,12 +1675,12 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testCursorPosition)
 {
     // Load a document and register a callback, should get an own cursor.
     SwXTextDocument* pXTextDocument = createDoc();
-    ViewCallback aView1;
+    SwTestViewCallback aView1;
 
     // Create a second view, so the first view gets a collaborative cursor.
     SfxLokHelper::createView();
     pXTextDocument->initializeForTiledRendering({});
-    ViewCallback aView2;
+    SwTestViewCallback aView2;
 
     // Make sure the two are exactly the same.
     // This failed, own cursor was at '1418, 1418', collaborative cursor was at
@@ -1695,7 +1695,7 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testPaintCallbacks)
 
     // Load a document and register a callback for the first view.
     SwXTextDocument* pXTextDocument = createDoc();
-    ViewCallback aView1;
+    SwTestViewCallback aView1;
 
     // Create a second view and paint a tile on that second view.
     SfxLokHelper::createView();
@@ -1799,12 +1799,12 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testDisableUndoRepair)
 {
     // Create two views.
     SwXTextDocument* pXTextDocument = createDoc("dummy.fodt");
-    ViewCallback aView1;
+    SwTestViewCallback aView1;
     SwView* pView1 = dynamic_cast<SwView*>(SfxViewShell::Current());
     CPPUNIT_ASSERT(pView1);
     int nView1 = SfxLokHelper::getView();
     SfxLokHelper::createView();
-    ViewCallback aView2;
+    SwTestViewCallback aView2;
     SwView* pView2 = dynamic_cast<SwView*>(SfxViewShell::Current());
     CPPUNIT_ASSERT(pView2);
     int nView2 = SfxLokHelper::getView();
@@ -2426,12 +2426,12 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testDeleteNodeRedlineCallback)
 CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testVisCursorInvalidation)
 {
     SwXTextDocument* pXTextDocument = createDoc("dummy.fodt");
-    ViewCallback aView1;
+    SwTestViewCallback aView1;
     int nView1 = SfxLokHelper::getView();
 
     SfxLokHelper::createView();
     int nView2 = SfxLokHelper::getView();
-    ViewCallback aView2;
+    SwTestViewCallback aView2;
     Scheduler::ProcessEventsToIdle();
 
     // Move visible cursor in the first view
@@ -3173,7 +3173,7 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testTableCommentRemoveCallback)
     SwXTextDocument* pXTextDocument = 
createDoc("testTableCommentRemoveCallback.odt");
     SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
     setupLibreOfficeKitViewCallback(pWrtShell->GetSfxViewShell());
-    ViewCallback aView;
+    SwTestViewCallback aView;
 
     // delete all characters
     comphelper::dispatchCommand(u".uno:SelectAll"_ustr, 
uno::Sequence<beans::PropertyValue>());
@@ -3760,10 +3760,10 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testToggleFormattingMarks)
     
pXTextDocument->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>());
 
     SfxLokHelper::setView(nView1);
-    ViewCallback aView1;
+    SwTestViewCallback aView1;
 
     SfxLokHelper::setView(nView2);
-    ViewCallback aView2;
+    SwTestViewCallback aView2;
 
     OString sOrigView2RenderState = pXTextDocument->getViewRenderState();
 
diff --git a/sw/qa/extras/tiledrendering/tiledrendering2.cxx 
b/sw/qa/extras/tiledrendering/tiledrendering2.cxx
index 9c2e7dba2155..936938c82901 100644
--- a/sw/qa/extras/tiledrendering/tiledrendering2.cxx
+++ b/sw/qa/extras/tiledrendering/tiledrendering2.cxx
@@ -47,12 +47,12 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testStatusBarPageNumber)
     int nView2 = SfxLokHelper::getView();
     
pXTextDocument->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>());
     SfxLokHelper::setView(nView1);
-    ViewCallback aView1;
+    SwTestViewCallback aView1;
     pWrtShell1->SttEndDoc(/*bStt=*/true);
     pWrtShell1->Insert(u"start"_ustr);
     pWrtShell1->GetView().SetVisArea(pPage1->getFrameArea().SVRect());
     SfxLokHelper::setView(nView2);
-    ViewCallback aView2;
+    SwTestViewCallback aView2;
     SwWrtShell* pWrtShell2 = getSwDocShell()->GetWrtShell();
     pWrtShell2->SttEndDoc(/*bStt=*/false);
     pWrtShell2->Insert(u"end"_ustr);
@@ -159,7 +159,7 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testAsyncLayout)
 {
     // Given a document with 3 pages, the first page is visible:
     createDoc();
-    ViewCallback aView;
+    SwTestViewCallback aView;
     SwDocShell* pDocShell = getSwDocShell();
     SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
     pWrtShell->InsertPageBreak();
@@ -195,7 +195,7 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testAnyInput)
 {
     // Given a document with 3 pages, the first page is visible:
     createDoc();
-    ViewCallback aView;
+    SwTestViewCallback aView;
     SwDocShell* pDocShell = getSwDocShell();
     SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
     pWrtShell->InsertPageBreak();
@@ -288,9 +288,9 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testPDFExportViewSwitch)
     SwXTextDocument* pXTextDocument = createDoc("to-pdf.odt");
     SfxLokHelper::registerViewCallbacks();
     SwDoc* pDoc = pXTextDocument->GetDocShell()->GetDoc();
-    ViewCallback aView1;
+    SwTestViewCallback aView1;
     SfxLokHelper::createView();
-    ViewCallback aView2;
+    SwTestViewCallback aView2;
     SwView* pView2 = pDoc->GetDocShell()->GetView();
     uno::Reference<frame::XFrame> xFrame2 = 
pView2->GetViewFrame().GetFrame().GetFrameInterface();
 
@@ -355,10 +355,10 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testTrackChangesPerViewEnableOne)
     // Given a document with two views:
     SwXTextDocument* pXTextDocument = createDoc();
     CPPUNIT_ASSERT(pXTextDocument);
-    ViewCallback aView1;
+    SwTestViewCallback aView1;
     int nView1 = SfxLokHelper::getView();
     SfxLokHelper::createView();
-    ViewCallback aView2;
+    SwTestViewCallback aView2;
     int nView2 = SfxLokHelper::getView();
 
     // When recording changes in view1:
@@ -398,11 +398,11 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testTrackChangesPerViewEnableBoth)
     // Given a document with 2 views, view1 record changes:
     SwXTextDocument* pXTextDocument = createDoc();
     CPPUNIT_ASSERT(pXTextDocument);
-    ViewCallback aView1;
+    SwTestViewCallback aView1;
     int nView1 = SfxLokHelper::getView();
     SwWrtShell* pWrtShell1 = pXTextDocument->GetDocShell()->GetWrtShell();
     SfxLokHelper::createView();
-    ViewCallback aView2;
+    SwTestViewCallback aView2;
     int nView2 = SfxLokHelper::getView();
     SwWrtShell* pWrtShell2 = pXTextDocument->GetDocShell()->GetWrtShell();
     SfxLokHelper::setView(nView1);
@@ -426,12 +426,12 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testTrackChangesPerViewInsert)
     // Given 2 views, view 1 records changes, view does not record changes:
     SwXTextDocument* pXTextDocument = createDoc();
     CPPUNIT_ASSERT(pXTextDocument);
-    ViewCallback aView1;
+    SwTestViewCallback aView1;
     int nView1 = SfxLokHelper::getView();
     SwWrtShell* pWrtShell1 = pXTextDocument->GetDocShell()->GetWrtShell();
     pWrtShell1->Insert(u"X"_ustr);
     SfxLokHelper::createView();
-    ViewCallback aView2;
+    SwTestViewCallback aView2;
     int nView2 = SfxLokHelper::getView();
     SwWrtShell* pWrtShell2 = pXTextDocument->GetDocShell()->GetWrtShell();
     SfxLokHelper::setView(nView1);
@@ -460,12 +460,12 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testTrackChangesPerViewDelete)
     // Given 2 views, view 1 records changes, view does not record changes:
     SwXTextDocument* pXTextDocument = createDoc();
     CPPUNIT_ASSERT(pXTextDocument);
-    ViewCallback aView1;
+    SwTestViewCallback aView1;
     int nView1 = SfxLokHelper::getView();
     SwWrtShell* pWrtShell1 = pXTextDocument->GetDocShell()->GetWrtShell();
     pWrtShell1->Insert(u"test"_ustr);
     SfxLokHelper::createView();
-    ViewCallback aView2;
+    SwTestViewCallback aView2;
     int nView2 = SfxLokHelper::getView();
     SwWrtShell* pWrtShell2 = pXTextDocument->GetDocShell()->GetWrtShell();
     SfxLokHelper::setView(nView1);
@@ -496,12 +496,12 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testTrackChangesPerDocInsert)
     // Given 2 views, view 1 turns on per-doc change recording:
     SwXTextDocument* pXTextDocument = createDoc();
     CPPUNIT_ASSERT(pXTextDocument);
-    ViewCallback aView1;
+    SwTestViewCallback aView1;
     int nView1 = SfxLokHelper::getView();
     SwWrtShell* pWrtShell1 = pXTextDocument->GetDocShell()->GetWrtShell();
     pWrtShell1->Insert(u"X"_ustr);
     SfxLokHelper::createView();
-    ViewCallback aView2;
+    SwTestViewCallback aView2;
     int nView2 = SfxLokHelper::getView();
     SwWrtShell* pWrtShell2 = pXTextDocument->GetDocShell()->GetWrtShell();
     SfxLokHelper::setView(nView1);
@@ -529,11 +529,11 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testTrackChangesStates)
     // Given a document with 2 views:
     SwXTextDocument* pXTextDocument = createDoc();
     CPPUNIT_ASSERT(pXTextDocument);
-    ViewCallback aView1;
+    SwTestViewCallback aView1;
     int nView1 = SfxLokHelper::getView();
     SwView* pView1 = pXTextDocument->GetDocShell()->GetView();
     SfxLokHelper::createView();
-    ViewCallback aView2;
+    SwTestViewCallback aView2;
     SwView* pView2 = pXTextDocument->GetDocShell()->GetView();
     SfxLokHelper::setView(nView1);
 
diff --git a/sw/qa/extras/tiledrendering/tiledrenderingmodeltestbase.cxx 
b/sw/qa/extras/tiledrendering/tiledrenderingmodeltestbase.cxx
index 4a4d358111f2..09630d80b5e4 100644
--- a/sw/qa/extras/tiledrendering/tiledrenderingmodeltestbase.cxx
+++ b/sw/qa/extras/tiledrendering/tiledrenderingmodeltestbase.cxx
@@ -8,6 +8,7 @@
  */
 
 #include <swtiledrenderingtest.hxx>
+#include <swtestviewcallback.hxx>
 
 #include <com/sun/star/frame/DispatchResultState.hpp>
 #include <com/sun/star/frame/XDispatchResultListener.hpp>
@@ -23,226 +24,6 @@
 #include <unotxdoc.hxx>
 #include <wrtsh.hxx>
 
-/// A view callback tracks callbacks invoked on one specific view.
-class ViewCallback final
-{
-    SfxViewShell* mpViewShell;
-    int mnView;
-
-public:
-    bool m_bOwnCursorInvalidated;
-    int m_nOwnCursorInvalidatedBy;
-    bool m_bOwnCursorAtOrigin;
-    tools::Rectangle m_aOwnCursor;
-    bool m_bViewCursorInvalidated;
-    tools::Rectangle m_aViewCursor;
-    bool m_bOwnSelectionSet;
-    bool m_bViewSelectionSet;
-    OString m_aViewSelection;
-    OString m_aViewRenderState;
-    bool m_bTilesInvalidated;
-    bool m_bViewCursorVisible;
-    bool m_bGraphicViewSelection;
-    bool m_bGraphicSelection;
-    bool m_bViewLock;
-    OString m_aDocColor;
-    /// Set if any callback was invoked.
-    bool m_bCalled;
-    /// Redline table size changed payload
-    boost::property_tree::ptree m_aRedlineTableChanged;
-    /// Redline table modified payload
-    boost::property_tree::ptree m_aRedlineTableModified;
-    /// Post-it / annotation payload.
-    boost::property_tree::ptree m_aComment;
-    std::vector<OString> m_aStateChanges;
-    TestLokCallbackWrapper m_callbackWrapper;
-    OString m_aExportFile;
-
-    ViewCallback(SfxViewShell* pViewShell = nullptr,
-                 std::function<void(ViewCallback&)> const& rBeforeInstallFunc 
= {})
-        : m_bOwnCursorInvalidated(false)
-        , m_nOwnCursorInvalidatedBy(-1)
-        , m_bOwnCursorAtOrigin(false)
-        , m_bViewCursorInvalidated(false)
-        , m_bOwnSelectionSet(false)
-        , m_bViewSelectionSet(false)
-        , m_bTilesInvalidated(false)
-        , m_bViewCursorVisible(false)
-        , m_bGraphicViewSelection(false)
-        , m_bGraphicSelection(false)
-        , m_bViewLock(false)
-        , m_bCalled(false)
-        , m_callbackWrapper(&callback, this)
-    {
-        // Because one call-site wants to set the bool fields up before the 
callback is installed
-        if (rBeforeInstallFunc)
-            rBeforeInstallFunc(*this);
-
-        mpViewShell = pViewShell ? pViewShell : SfxViewShell::Current();
-        mpViewShell->setLibreOfficeKitViewCallback(&m_callbackWrapper);
-        mnView = SfxLokHelper::getView();
-        m_callbackWrapper.setLOKViewId(mnView);
-    }
-
-    ~ViewCallback()
-    {
-        SfxLokHelper::setView(mnView);
-        mpViewShell->setLibreOfficeKitViewCallback(nullptr);
-    }
-
-    static void callback(int nType, const char* pPayload, void* pData)
-    {
-        static_cast<ViewCallback*>(pData)->callbackImpl(nType, pPayload);
-    }
-
-    void callbackImpl(int nType, const char* pPayload)
-    {
-        OString aPayload(pPayload);
-        m_bCalled = true;
-        switch (nType)
-        {
-            case LOK_CALLBACK_STATE_CHANGED:
-            {
-                m_aStateChanges.push_back(pPayload);
-                break;
-            }
-            case LOK_CALLBACK_INVALIDATE_TILES:
-            {
-                m_bTilesInvalidated = true;
-            }
-            break;
-            case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR:
-            {
-                m_bOwnCursorInvalidated = true;
-
-                OString sRect;
-                if 
(comphelper::LibreOfficeKit::isViewIdForVisCursorInvalidation())
-                {
-                    std::stringstream aStream(pPayload);
-                    boost::property_tree::ptree aTree;
-                    boost::property_tree::read_json(aStream, aTree);
-                    sRect = 
OString(aTree.get_child("rectangle").get_value<std::string>());
-                    m_nOwnCursorInvalidatedBy = 
aTree.get_child("viewId").get_value<int>();
-                }
-                else
-                    sRect = aPayload;
-                uno::Sequence<OUString> aSeq
-                    = 
comphelper::string::convertCommaSeparated(OUString::fromUtf8(sRect));
-                if (std::string_view("EMPTY") == pPayload)
-                    return;
-                CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(4), 
aSeq.getLength());
-                m_aOwnCursor.SetLeft(aSeq[0].toInt32());
-                m_aOwnCursor.SetTop(aSeq[1].toInt32());
-                m_aOwnCursor.setWidth(aSeq[2].toInt32());
-                m_aOwnCursor.setHeight(aSeq[3].toInt32());
-                if (m_aOwnCursor.Left() == 0 && m_aOwnCursor.Top() == 0)
-                    m_bOwnCursorAtOrigin = true;
-            }
-            break;
-            case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR:
-            {
-                m_bViewCursorInvalidated = true;
-                std::stringstream aStream(pPayload);
-                boost::property_tree::ptree aTree;
-                boost::property_tree::read_json(aStream, aTree);
-                OString 
aRect(aTree.get_child("rectangle").get_value<std::string>());
-
-                uno::Sequence<OUString> aSeq
-                    = 
comphelper::string::convertCommaSeparated(OUString::fromUtf8(aRect));
-                if (std::string_view("EMPTY") == pPayload)
-                    return;
-                CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(4), 
aSeq.getLength());
-                m_aViewCursor.SetLeft(aSeq[0].toInt32());
-                m_aViewCursor.SetTop(aSeq[1].toInt32());
-                m_aViewCursor.setWidth(aSeq[2].toInt32());
-                m_aViewCursor.setHeight(aSeq[3].toInt32());
-            }
-            break;
-            case LOK_CALLBACK_TEXT_SELECTION:
-            {
-                m_bOwnSelectionSet = true;
-            }
-            break;
-            case LOK_CALLBACK_TEXT_VIEW_SELECTION:
-            {
-                m_bViewSelectionSet = true;
-                m_aViewSelection = aPayload;
-            }
-            break;
-            case LOK_CALLBACK_VIEW_CURSOR_VISIBLE:
-            {
-                std::stringstream aStream(pPayload);
-                boost::property_tree::ptree aTree;
-                boost::property_tree::read_json(aStream, aTree);
-                m_bViewCursorVisible
-                    = aTree.get_child("visible").get_value<std::string>() == 
"true";
-            }
-            break;
-            case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION:
-            {
-                std::stringstream aStream(pPayload);
-                boost::property_tree::ptree aTree;
-                boost::property_tree::read_json(aStream, aTree);
-                m_bGraphicViewSelection
-                    = aTree.get_child("selection").get_value<std::string>() != 
"EMPTY";
-            }
-            break;
-            case LOK_CALLBACK_GRAPHIC_SELECTION:
-            {
-                m_bGraphicSelection = aPayload != "EMPTY";
-            }
-            break;
-            case LOK_CALLBACK_VIEW_LOCK:
-            {
-                std::stringstream aStream(pPayload);
-                boost::property_tree::ptree aTree;
-                boost::property_tree::read_json(aStream, aTree);
-                m_bViewLock = 
aTree.get_child("rectangle").get_value<std::string>() != "EMPTY";
-            }
-            break;
-            case LOK_CALLBACK_VIEW_RENDER_STATE:
-            {
-                m_aViewRenderState = pPayload;
-            }
-            break;
-            case LOK_CALLBACK_REDLINE_TABLE_SIZE_CHANGED:
-            {
-                m_aRedlineTableChanged.clear();
-                std::stringstream aStream(pPayload);
-                boost::property_tree::read_json(aStream, 
m_aRedlineTableChanged);
-                m_aRedlineTableChanged = 
m_aRedlineTableChanged.get_child("redline");
-            }
-            break;
-            case LOK_CALLBACK_REDLINE_TABLE_ENTRY_MODIFIED:
-            {
-                m_aRedlineTableModified.clear();
-                std::stringstream aStream(pPayload);
-                boost::property_tree::read_json(aStream, 
m_aRedlineTableModified);
-                m_aRedlineTableModified = 
m_aRedlineTableModified.get_child("redline");
-            }
-            break;
-            case LOK_CALLBACK_COMMENT:
-            {
-                m_aComment.clear();
-                std::stringstream aStream(pPayload);
-                boost::property_tree::read_json(aStream, m_aComment);
-                m_aComment = m_aComment.get_child("comment");
-            }
-            break;
-            case LOK_CALLBACK_DOCUMENT_BACKGROUND_COLOR:
-            {
-                m_aDocColor = aPayload;
-                break;
-            }
-            case LOK_CALLBACK_EXPORT_FILE:
-            {
-                m_aExportFile = aPayload;
-                break;
-            }
-        }
-    }
-};
-
 class TestResultListener : public 
cppu::WeakImplHelper<css::frame::XDispatchResultListener>
 {
 public:
diff --git a/sw/qa/inc/swtestviewcallback.hxx b/sw/qa/inc/swtestviewcallback.hxx
new file mode 100644
index 000000000000..a82772c07b70
--- /dev/null
+++ b/sw/qa/inc/swtestviewcallback.hxx
@@ -0,0 +1,70 @@
+/* -*- 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/.
+ */
+
+#ifndef INCLUDED_SW_QA_INC_SWTESTVIEWCALLBACK_HXX
+#define INCLUDED_SW_QA_INC_SWTESTVIEWCALLBACK_HXX
+
+#include <boost/property_tree/ptree.hpp>
+
+#include <rtl/string.hxx>
+#include <test/lokcallback.hxx>
+#include <tools/gen.hxx>
+
+#include "swqahelperdllapi.h"
+
+class SfxViewShell;
+
+/// A view callback tracks callbacks invoked on one specific view.
+class SWQAHELPER_DLLPUBLIC SwTestViewCallback final
+{
+    SfxViewShell* mpViewShell;
+    int mnView;
+
+public:
+    bool m_bOwnCursorInvalidated;
+    int m_nOwnCursorInvalidatedBy;
+    bool m_bOwnCursorAtOrigin;
+    tools::Rectangle m_aOwnCursor;
+    bool m_bViewCursorInvalidated;
+    tools::Rectangle m_aViewCursor;
+    bool m_bOwnSelectionSet;
+    bool m_bViewSelectionSet;
+    OString m_aViewSelection;
+    OString m_aViewRenderState;
+    bool m_bTilesInvalidated;
+    bool m_bViewCursorVisible;
+    bool m_bGraphicViewSelection;
+    bool m_bGraphicSelection;
+    bool m_bViewLock;
+    OString m_aDocColor;
+    /// Set if any callback was invoked.
+    bool m_bCalled;
+    /// Redline table size changed payload
+    boost::property_tree::ptree m_aRedlineTableChanged;
+    /// Redline table modified payload
+    boost::property_tree::ptree m_aRedlineTableModified;
+    /// Post-it / annotation payload.
+    boost::property_tree::ptree m_aComment;
+    std::vector<OString> m_aStateChanges;
+    TestLokCallbackWrapper m_callbackWrapper;
+    OString m_aExportFile;
+
+    SwTestViewCallback(SfxViewShell* pViewShell = nullptr,
+                       std::function<void(SwTestViewCallback&)> const& 
rBeforeInstallFunc = {});
+
+    ~SwTestViewCallback();
+
+    static void callback(int nType, const char* pPayload, void* pData);
+
+    void callbackImpl(int nType, const char* pPayload);
+};
+
+#endif // INCLUDED_SW_QA_INC_SWTESTVIEWCALLBACK_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/unit/swtestviewcallback.cxx 
b/sw/qa/unit/swtestviewcallback.cxx
new file mode 100644
index 000000000000..b378723603a0
--- /dev/null
+++ b/sw/qa/unit/swtestviewcallback.cxx
@@ -0,0 +1,205 @@
+/* -*- 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 <swtestviewcallback.hxx>
+
+#include <boost/property_tree/json_parser.hpp>
+#include <cppunit/TestAssert.h>
+
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <comphelper/lok.hxx>
+#include <comphelper/string.hxx>
+#include <sfx2/lokhelper.hxx>
+
+using namespace css;
+
+SwTestViewCallback::SwTestViewCallback(
+    SfxViewShell* pViewShell, std::function<void(SwTestViewCallback&)> const& 
rBeforeInstallFunc)
+    : m_bOwnCursorInvalidated(false)
+    , m_nOwnCursorInvalidatedBy(-1)
+    , m_bOwnCursorAtOrigin(false)
+    , m_bViewCursorInvalidated(false)
+    , m_bOwnSelectionSet(false)
+    , m_bViewSelectionSet(false)
+    , m_bTilesInvalidated(false)
+    , m_bViewCursorVisible(false)
+    , m_bGraphicViewSelection(false)
+    , m_bGraphicSelection(false)
+    , m_bViewLock(false)
+    , m_bCalled(false)
+    , m_callbackWrapper(&callback, this)
+{
+    // Because one call-site wants to set the bool fields up before the 
callback is installed
+    if (rBeforeInstallFunc)
+        rBeforeInstallFunc(*this);
+
+    mpViewShell = pViewShell ? pViewShell : SfxViewShell::Current();
+    mpViewShell->setLibreOfficeKitViewCallback(&m_callbackWrapper);
+    mnView = SfxLokHelper::getView();
+    m_callbackWrapper.setLOKViewId(mnView);
+}
+
+SwTestViewCallback::~SwTestViewCallback()
+{
+    SfxLokHelper::setView(mnView);
+    mpViewShell->setLibreOfficeKitViewCallback(nullptr);
+}
+
+void SwTestViewCallback::callback(int nType, const char* pPayload, void* pData)
+{
+    static_cast<SwTestViewCallback*>(pData)->callbackImpl(nType, pPayload);
+}
+
+void SwTestViewCallback::callbackImpl(int nType, const char* pPayload)
+{
+    OString aPayload(pPayload);
+    m_bCalled = true;
+    switch (nType)
+    {
+        case LOK_CALLBACK_STATE_CHANGED:
+        {
+            m_aStateChanges.push_back(pPayload);
+            break;
+        }
+        case LOK_CALLBACK_INVALIDATE_TILES:
+        {
+            m_bTilesInvalidated = true;
+        }
+        break;
+        case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR:
+        {
+            m_bOwnCursorInvalidated = true;
+
+            OString sRect;
+            if (comphelper::LibreOfficeKit::isViewIdForVisCursorInvalidation())
+            {
+                std::stringstream aStream(pPayload);
+                boost::property_tree::ptree aTree;
+                boost::property_tree::read_json(aStream, aTree);
+                sRect = 
OString(aTree.get_child("rectangle").get_value<std::string>());
+                m_nOwnCursorInvalidatedBy = 
aTree.get_child("viewId").get_value<int>();
+            }
+            else
+                sRect = aPayload;
+            uno::Sequence<OUString> aSeq
+                = 
comphelper::string::convertCommaSeparated(OUString::fromUtf8(sRect));
+            if (std::string_view("EMPTY") == pPayload)
+                return;
+            CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(4), aSeq.getLength());
+            m_aOwnCursor.SetLeft(aSeq[0].toInt32());
+            m_aOwnCursor.SetTop(aSeq[1].toInt32());
+            m_aOwnCursor.setWidth(aSeq[2].toInt32());
+            m_aOwnCursor.setHeight(aSeq[3].toInt32());
+            if (m_aOwnCursor.Left() == 0 && m_aOwnCursor.Top() == 0)
+                m_bOwnCursorAtOrigin = true;
+        }
+        break;
+        case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR:
+        {
+            m_bViewCursorInvalidated = true;
+            std::stringstream aStream(pPayload);
+            boost::property_tree::ptree aTree;
+            boost::property_tree::read_json(aStream, aTree);
+            OString 
aRect(aTree.get_child("rectangle").get_value<std::string>());
+
+            uno::Sequence<OUString> aSeq
+                = 
comphelper::string::convertCommaSeparated(OUString::fromUtf8(aRect));
+            if (std::string_view("EMPTY") == pPayload)
+                return;
+            CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(4), aSeq.getLength());
+            m_aViewCursor.SetLeft(aSeq[0].toInt32());
+            m_aViewCursor.SetTop(aSeq[1].toInt32());
+            m_aViewCursor.setWidth(aSeq[2].toInt32());
+            m_aViewCursor.setHeight(aSeq[3].toInt32());
+        }
+        break;
+        case LOK_CALLBACK_TEXT_SELECTION:
+        {
+            m_bOwnSelectionSet = true;
+        }
+        break;
+        case LOK_CALLBACK_TEXT_VIEW_SELECTION:
+        {
+            m_bViewSelectionSet = true;
+            m_aViewSelection = aPayload;
+        }
+        break;
+        case LOK_CALLBACK_VIEW_CURSOR_VISIBLE:
+        {
+            std::stringstream aStream(pPayload);
+            boost::property_tree::ptree aTree;
+            boost::property_tree::read_json(aStream, aTree);
+            m_bViewCursorVisible = 
aTree.get_child("visible").get_value<std::string>() == "true";
+        }
+        break;
+        case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION:
+        {
+            std::stringstream aStream(pPayload);
+            boost::property_tree::ptree aTree;
+            boost::property_tree::read_json(aStream, aTree);
+            m_bGraphicViewSelection
+                = aTree.get_child("selection").get_value<std::string>() != 
"EMPTY";
+        }
+        break;
+        case LOK_CALLBACK_GRAPHIC_SELECTION:
+        {
+            m_bGraphicSelection = aPayload != "EMPTY";
+        }
+        break;
+        case LOK_CALLBACK_VIEW_LOCK:
+        {
+            std::stringstream aStream(pPayload);
+            boost::property_tree::ptree aTree;
+            boost::property_tree::read_json(aStream, aTree);
+            m_bViewLock = 
aTree.get_child("rectangle").get_value<std::string>() != "EMPTY";
+        }
+        break;
+        case LOK_CALLBACK_VIEW_RENDER_STATE:
+        {
+            m_aViewRenderState = pPayload;
+        }
+        break;
+        case LOK_CALLBACK_REDLINE_TABLE_SIZE_CHANGED:
+        {
+            m_aRedlineTableChanged.clear();
+            std::stringstream aStream(pPayload);
+            boost::property_tree::read_json(aStream, m_aRedlineTableChanged);
+            m_aRedlineTableChanged = 
m_aRedlineTableChanged.get_child("redline");
+        }
+        break;
+        case LOK_CALLBACK_REDLINE_TABLE_ENTRY_MODIFIED:
+        {
+            m_aRedlineTableModified.clear();
+            std::stringstream aStream(pPayload);
+            boost::property_tree::read_json(aStream, m_aRedlineTableModified);
+            m_aRedlineTableModified = 
m_aRedlineTableModified.get_child("redline");
+        }
+        break;
+        case LOK_CALLBACK_COMMENT:
+        {
+            m_aComment.clear();
+            std::stringstream aStream(pPayload);
+            boost::property_tree::read_json(aStream, m_aComment);
+            m_aComment = m_aComment.get_child("comment");
+        }
+        break;
+        case LOK_CALLBACK_DOCUMENT_BACKGROUND_COLOR:
+        {
+            m_aDocColor = aPayload;
+            break;
+        }
+        case LOK_CALLBACK_EXPORT_FILE:
+        {
+            m_aExportFile = aPayload;
+            break;
+        }
+    }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit dbb9455aa3fefd22d43053ae79fec88301252281
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Thu Jan 2 08:18:26 2025 +0100
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Fri Mar 7 13:18:15 2025 +0100

    sw: move SwTiledRenderingTest to Library_swqahelper
    
    Towards not including .cxx files in Writer tests.
    
    [ Pick to co-25.04, to reduce conflicts vs master. ]
    
    Change-Id: I92b3eb6d2208ba10797d0363fca53df5acc98324
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/179598
    Tested-by: Jenkins
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>

diff --git a/sw/Library_swqahelper.mk b/sw/Library_swqahelper.mk
index ec379d979658..aa0f05575340 100644
--- a/sw/Library_swqahelper.mk
+++ b/sw/Library_swqahelper.mk
@@ -12,6 +12,7 @@ $(eval $(call gb_Library_Library,swqahelper))
 $(eval $(call gb_Library_set_include,swqahelper,\
        -I$(SRCDIR)/sw/inc \
        -I$(SRCDIR)/sw/source/core/inc \
+       -I$(SRCDIR)/sw/source/uibase/inc \
        -I$(SRCDIR)/sw/qa/inc \
        $$(INCLUDE) \
 ))
@@ -66,6 +67,7 @@ $(eval $(call gb_Library_use_libraries,swqahelper,\
 
 $(eval $(call gb_Library_add_exception_objects,swqahelper,\
        sw/qa/unit/swmodeltestbase \
+       sw/qa/unit/swtiledrenderingtest \
 ))
 
 # vim: set noet sw=4 ts=4:
diff --git a/sw/qa/extras/tiledrendering/tiledrenderingmodeltestbase.cxx 
b/sw/qa/extras/tiledrendering/tiledrenderingmodeltestbase.cxx
index dbc781b90f43..4a4d358111f2 100644
--- a/sw/qa/extras/tiledrendering/tiledrenderingmodeltestbase.cxx
+++ b/sw/qa/extras/tiledrendering/tiledrenderingmodeltestbase.cxx
@@ -7,7 +7,7 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
-#include <swmodeltestbase.hxx>
+#include <swtiledrenderingtest.hxx>
 
 #include <com/sun/star/frame/DispatchResultState.hpp>
 #include <com/sun/star/frame/XDispatchResultListener.hpp>
@@ -23,251 +23,6 @@
 #include <unotxdoc.hxx>
 #include <wrtsh.hxx>
 
-/// Testsuite for the SwXTextDocument methods implementing the 
vcl::ITiledRenderable interface.
-class SwTiledRenderingTest : public SwModelTestBase
-{
-public:
-    SwTiledRenderingTest();
-    virtual void setUp() override;
-    virtual void tearDown() override;
-
-protected:
-    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.
-    tools::Rectangle m_aInvalidation;
-    /// Union of all invalidations.
-    tools::Rectangle m_aInvalidations;
-    tools::Rectangle m_aCursorRectangle;
-    Size m_aDocumentSize;
-    OString m_aTextSelection;
-    bool m_bFound;
-    std::vector<OString> m_aSearchResultSelection;
-    std::vector<int> m_aSearchResultPart;
-    int m_nSelectionBeforeSearchResult;
-    int m_nSelectionAfterSearchResult;
-    int m_nInvalidations;
-    int m_nRedlineTableSizeChanged;
-    int m_nRedlineTableEntryModified;
-    int m_nTrackedChangeIndex;
-    bool m_bFullInvalidateSeen;
-    OString m_sHyperlinkText;
-    OString m_sHyperlinkLink;
-    OString m_aFormFieldButton;
-    OString m_aContentControl;
-    OString m_ShapeSelection;
-    struct
-    {
-        std::string text;
-        std::string rect;
-    } m_aTooltip;
-    TestLokCallbackWrapper m_callbackWrapper;
-};
-
-SwTiledRenderingTest::SwTiledRenderingTest()
-    : SwModelTestBase(u"/sw/qa/extras/tiledrendering/data/"_ustr)
-    , m_bFound(true)
-    , m_nSelectionBeforeSearchResult(0)
-    , m_nSelectionAfterSearchResult(0)
-    , m_nInvalidations(0)
-    , m_nRedlineTableSizeChanged(0)
-    , m_nRedlineTableEntryModified(0)
-    , m_nTrackedChangeIndex(-1)
-    , m_bFullInvalidateSeen(false)
-    , m_callbackWrapper(&callback, this)
-{
-}
-
-void SwTiledRenderingTest::setUp()
-{
-    SwModelTestBase::setUp();
-
-    SwGlobals::ensure();
-    SwModule::get()->ClearRedlineAuthors();
-
-    comphelper::LibreOfficeKit::setActive(true);
-}
-
-void SwTiledRenderingTest::tearDown()
-{
-    if (mxComponent.is())
-    {
-        SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
-        if (pWrtShell)
-        {
-            
pWrtShell->GetSfxViewShell()->setLibreOfficeKitViewCallback(nullptr);
-        }
-        mxComponent->dispose();
-        mxComponent.clear();
-    }
-    m_callbackWrapper.clear();
-    comphelper::LibreOfficeKit::setActive(false);
-
-    test::BootstrapFixture::tearDown();
-}
-
-SwXTextDocument* SwTiledRenderingTest::createDoc(const char* pName)
-{
-    if (!pName)
-        createSwDoc();
-    else
-        createSwDoc(pName);
-
-    SwXTextDocument* pTextDocument = getSwTextDoc();
-    
pTextDocument->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>());
-    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);
-}
-
-void SwTiledRenderingTest::callbackImpl(int nType, const char* pPayload)
-{
-    OString aPayload(pPayload);
-    switch (nType)
-    {
-        case LOK_CALLBACK_INVALIDATE_TILES:
-        {
-            tools::Rectangle aInvalidation;
-            uno::Sequence<OUString> aSeq
-                = 
comphelper::string::convertCommaSeparated(OUString::createFromAscii(pPayload));
-            if (std::string_view("EMPTY") == pPayload)
-            {
-                m_bFullInvalidateSeen = true;
-                return;
-            }
-
-            CPPUNIT_ASSERT(aSeq.getLength() == 4 || aSeq.getLength() == 5);
-            aInvalidation.SetLeft(aSeq[0].toInt32());
-            aInvalidation.SetTop(aSeq[1].toInt32());
-            aInvalidation.setWidth(aSeq[2].toInt32());
-            aInvalidation.setHeight(aSeq[3].toInt32());
-            if (m_aInvalidation.IsEmpty())
-            {
-                m_aInvalidation = aInvalidation;
-            }
-            m_aInvalidations.Union(aInvalidation);
-            ++m_nInvalidations;
-        }
-        break;
-        case LOK_CALLBACK_DOCUMENT_SIZE_CHANGED:
-        {
-            uno::Sequence<OUString> aSeq
-                = 
comphelper::string::convertCommaSeparated(OUString::createFromAscii(pPayload));
-            CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(2), aSeq.getLength());
-            m_aDocumentSize.setWidth(aSeq[0].toInt32());
-            m_aDocumentSize.setHeight(aSeq[1].toInt32());
-        }
-        break;
-        case LOK_CALLBACK_TEXT_SELECTION:
-        {
-            m_aTextSelection = pPayload;
-            if (m_aSearchResultSelection.empty())
-                ++m_nSelectionBeforeSearchResult;
-            else
-                ++m_nSelectionAfterSearchResult;
-        }
-        break;
-        case LOK_CALLBACK_SEARCH_NOT_FOUND:
-        {
-            m_bFound = false;
-        }
-        break;
-        case LOK_CALLBACK_SEARCH_RESULT_SELECTION:
-        {
-            m_aSearchResultSelection.clear();
-            boost::property_tree::ptree aTree;
-            std::stringstream aStream(pPayload);
-            boost::property_tree::read_json(aStream, aTree);
-            for (const boost::property_tree::ptree::value_type& rValue :
-                 aTree.get_child("searchResultSelection"))
-            {
-                m_aSearchResultSelection.emplace_back(
-                    rValue.second.get<std::string>("rectangles").c_str());
-                m_aSearchResultPart.push_back(
-                    std::atoi(rValue.second.get<std::string>("part").c_str()));
-            }
-        }
-        break;
-        case LOK_CALLBACK_REDLINE_TABLE_SIZE_CHANGED:
-        {
-            ++m_nRedlineTableSizeChanged;
-        }
-        break;
-        case LOK_CALLBACK_REDLINE_TABLE_ENTRY_MODIFIED:
-        {
-            ++m_nRedlineTableEntryModified;
-        }
-        break;
-        case LOK_CALLBACK_STATE_CHANGED:
-        {
-            OString aTrackedChangeIndexPrefix(".uno:TrackedChangeIndex="_ostr);
-            if (aPayload.startsWith(aTrackedChangeIndexPrefix))
-            {
-                OString sIndex = 
aPayload.copy(aTrackedChangeIndexPrefix.getLength());
-                if (sIndex.isEmpty())
-                    m_nTrackedChangeIndex = -1;
-                else
-                    m_nTrackedChangeIndex = sIndex.toInt32();
-            }
-        }
-        break;
-        case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR:
-        {
-            if (comphelper::LibreOfficeKit::isViewIdForVisCursorInvalidation())
-            {
-                boost::property_tree::ptree aTree;
-                std::stringstream aStream(pPayload);
-                boost::property_tree::read_json(aStream, aTree);
-                boost::property_tree::ptree& aChild = 
aTree.get_child("hyperlink");
-                m_sHyperlinkText = OString(aChild.get("text", ""));
-                m_sHyperlinkLink = OString(aChild.get("link", ""));
-
-                OString 
aRectangle(aTree.get_child("rectangle").get_value<std::string>());
-                uno::Sequence<OUString> aSeq = 
comphelper::string::convertCommaSeparated(OUString::fromUtf8(aRectangle));
-                CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(4), 
aSeq.getLength());
-                m_aCursorRectangle = tools::Rectangle(Point(aSeq[0].toInt32(), 
aSeq[1].toInt32()), Size(aSeq[2].toInt32(), aSeq[3].toInt32()));
-
-            }
-        }
-        break;
-        case LOK_CALLBACK_FORM_FIELD_BUTTON:
-        {
-            m_aFormFieldButton = OString(pPayload);
-        }
-        break;
-        case LOK_CALLBACK_CONTENT_CONTROL:
-        {
-            m_aContentControl = OString(pPayload);
-        }
-        break;
-        case LOK_CALLBACK_GRAPHIC_SELECTION:
-        {
-            m_ShapeSelection = OString(pPayload);
-        }
-        break;
-        case LOK_CALLBACK_TOOLTIP:
-        {
-            std::stringstream aStream(pPayload);
-            boost::property_tree::ptree aTree;
-            boost::property_tree::read_json(aStream, aTree);
-            m_aTooltip.text = aTree.get_child("text").get_value<std::string>();
-            m_aTooltip.rect = 
aTree.get_child("rectangle").get_value<std::string>();
-        }
-        break;
-    }
-}
-
 /// A view callback tracks callbacks invoked on one specific view.
 class ViewCallback final
 {
diff --git a/sw/qa/inc/swtiledrenderingtest.hxx 
b/sw/qa/inc/swtiledrenderingtest.hxx
new file mode 100644
index 000000000000..d5885b6b1906
--- /dev/null
+++ b/sw/qa/inc/swtiledrenderingtest.hxx
@@ -0,0 +1,64 @@
+/* -*- 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/.
+ */
+
+#ifndef INCLUDED_SW_QA_INC_SWTILEDRENDERINGTEST_HXX
+#define INCLUDED_SW_QA_INC_SWTILEDRENDERINGTEST_HXX
+
+#include "swmodeltestbase.hxx"
+
+#include <test/lokcallback.hxx>
+
+#include "swqahelperdllapi.h"
+
+/// Testsuite for the SwXTextDocument methods implementing the 
vcl::ITiledRenderable interface.
+class SWQAHELPER_DLLPUBLIC SwTiledRenderingTest : public SwModelTestBase
+{
+public:
+    SwTiledRenderingTest();
+    virtual void setUp() override;
+    virtual void tearDown() override;
+
+protected:
+    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.
+    tools::Rectangle m_aInvalidation;
+    /// Union of all invalidations.
+    tools::Rectangle m_aInvalidations;
+    tools::Rectangle m_aCursorRectangle;
+    Size m_aDocumentSize;
+    OString m_aTextSelection;
+    bool m_bFound;
+    std::vector<OString> m_aSearchResultSelection;
+    std::vector<int> m_aSearchResultPart;
+    int m_nSelectionBeforeSearchResult;
+    int m_nSelectionAfterSearchResult;
+    int m_nInvalidations;
+    int m_nRedlineTableSizeChanged;
+    int m_nRedlineTableEntryModified;
+    int m_nTrackedChangeIndex;
+    bool m_bFullInvalidateSeen;
+    OString m_sHyperlinkText;
+    OString m_sHyperlinkLink;
+    OString m_aFormFieldButton;
+    OString m_aContentControl;
+    OString m_ShapeSelection;
+    struct
+    {
+        std::string text;
+        std::string rect;
+    } m_aTooltip;
+    TestLokCallbackWrapper m_callbackWrapper;
+};
+
+#endif // INCLUDED_SW_QA_INC_SWTILEDRENDERINGTEST_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/unit/swtiledrenderingtest.cxx 
b/sw/qa/unit/swtiledrenderingtest.cxx
new file mode 100644
index 000000000000..3ea1a08352b4
--- /dev/null
+++ b/sw/qa/unit/swtiledrenderingtest.cxx
@@ -0,0 +1,230 @@
+/* -*- 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 <swtiledrenderingtest.hxx>
+
+#include <boost/property_tree/json_parser.hpp>
+
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <comphelper/lok.hxx>
+#include <comphelper/string.hxx>
+#include <sfx2/lokhelper.hxx>
+
+#include <docsh.hxx>
+#include <swdll.hxx>
+#include <swmodule.hxx>
+#include <unotxdoc.hxx>
+#include <wrtsh.hxx>
+
+using namespace css;
+
+SwTiledRenderingTest::SwTiledRenderingTest()
+    : SwModelTestBase(u"/sw/qa/extras/tiledrendering/data/"_ustr)
+    , m_bFound(true)
+    , m_nSelectionBeforeSearchResult(0)
+    , m_nSelectionAfterSearchResult(0)
+    , m_nInvalidations(0)
+    , m_nRedlineTableSizeChanged(0)
+    , m_nRedlineTableEntryModified(0)
+    , m_nTrackedChangeIndex(-1)
+    , m_bFullInvalidateSeen(false)
+    , m_callbackWrapper(&callback, this)
+{
+}
+
+void SwTiledRenderingTest::setUp()
+{
+    SwModelTestBase::setUp();
+
+    SwGlobals::ensure();
+    SwModule::get()->ClearRedlineAuthors();
+
+    comphelper::LibreOfficeKit::setActive(true);
+}
+
+void SwTiledRenderingTest::tearDown()
+{
+    if (mxComponent.is())
+    {
+        SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
+        if (pWrtShell)
+        {
+            
pWrtShell->GetSfxViewShell()->setLibreOfficeKitViewCallback(nullptr);
+        }
+        mxComponent->dispose();
+        mxComponent.clear();
+    }
+    m_callbackWrapper.clear();
+    comphelper::LibreOfficeKit::setActive(false);
+
+    test::BootstrapFixture::tearDown();
+}
+
+SwXTextDocument* SwTiledRenderingTest::createDoc(const char* pName)
+{
+    if (!pName)
+        createSwDoc();
+    else
+        createSwDoc(pName);
+
+    SwXTextDocument* pTextDocument = getSwTextDoc();
+    
pTextDocument->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>());
+    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);
+}
+
+void SwTiledRenderingTest::callbackImpl(int nType, const char* pPayload)
+{
+    OString aPayload(pPayload);
+    switch (nType)
+    {
+        case LOK_CALLBACK_INVALIDATE_TILES:
+        {
+            tools::Rectangle aInvalidation;
+            uno::Sequence<OUString> aSeq
+                = 
comphelper::string::convertCommaSeparated(OUString::createFromAscii(pPayload));
+            if (std::string_view("EMPTY") == pPayload)
+            {
+                m_bFullInvalidateSeen = true;
+                return;
+            }
+
+            CPPUNIT_ASSERT(aSeq.getLength() == 4 || aSeq.getLength() == 5);
+            aInvalidation.SetLeft(aSeq[0].toInt32());
+            aInvalidation.SetTop(aSeq[1].toInt32());
+            aInvalidation.setWidth(aSeq[2].toInt32());
+            aInvalidation.setHeight(aSeq[3].toInt32());
+            if (m_aInvalidation.IsEmpty())
+            {
+                m_aInvalidation = aInvalidation;
+            }
+            m_aInvalidations.Union(aInvalidation);
+            ++m_nInvalidations;
+        }
+        break;
+        case LOK_CALLBACK_DOCUMENT_SIZE_CHANGED:
+        {
+            uno::Sequence<OUString> aSeq
+                = 
comphelper::string::convertCommaSeparated(OUString::createFromAscii(pPayload));
+            CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(2), aSeq.getLength());
+            m_aDocumentSize.setWidth(aSeq[0].toInt32());
+            m_aDocumentSize.setHeight(aSeq[1].toInt32());
+        }
+        break;
+        case LOK_CALLBACK_TEXT_SELECTION:
+        {
+            m_aTextSelection = pPayload;
+            if (m_aSearchResultSelection.empty())
+                ++m_nSelectionBeforeSearchResult;
+            else
+                ++m_nSelectionAfterSearchResult;
+        }
+        break;
+        case LOK_CALLBACK_SEARCH_NOT_FOUND:
+        {
+            m_bFound = false;
+        }
+        break;
+        case LOK_CALLBACK_SEARCH_RESULT_SELECTION:
+        {
+            m_aSearchResultSelection.clear();
+            boost::property_tree::ptree aTree;
+            std::stringstream aStream(pPayload);
+            boost::property_tree::read_json(aStream, aTree);
+            for (const boost::property_tree::ptree::value_type& rValue :
+                 aTree.get_child("searchResultSelection"))
+            {
+                m_aSearchResultSelection.emplace_back(
+                    rValue.second.get<std::string>("rectangles").c_str());
+                m_aSearchResultPart.push_back(
+                    std::atoi(rValue.second.get<std::string>("part").c_str()));
+            }
+        }
+        break;
+        case LOK_CALLBACK_REDLINE_TABLE_SIZE_CHANGED:
+        {
+            ++m_nRedlineTableSizeChanged;
+        }
+        break;
+        case LOK_CALLBACK_REDLINE_TABLE_ENTRY_MODIFIED:
+        {
+            ++m_nRedlineTableEntryModified;
+        }
+        break;
+        case LOK_CALLBACK_STATE_CHANGED:
+        {
+            OString aTrackedChangeIndexPrefix(".uno:TrackedChangeIndex="_ostr);
+            if (aPayload.startsWith(aTrackedChangeIndexPrefix))
+            {
+                OString sIndex = 
aPayload.copy(aTrackedChangeIndexPrefix.getLength());
+                if (sIndex.isEmpty())
+                    m_nTrackedChangeIndex = -1;
+                else
+                    m_nTrackedChangeIndex = sIndex.toInt32();
+            }
+        }
+        break;
+        case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR:
+        {
+            if (comphelper::LibreOfficeKit::isViewIdForVisCursorInvalidation())
+            {
+                boost::property_tree::ptree aTree;
+                std::stringstream aStream(pPayload);
+                boost::property_tree::read_json(aStream, aTree);
+                boost::property_tree::ptree& aChild = 
aTree.get_child("hyperlink");
+                m_sHyperlinkText = OString(aChild.get("text", ""));
+                m_sHyperlinkLink = OString(aChild.get("link", ""));
+
+                OString 
aRectangle(aTree.get_child("rectangle").get_value<std::string>());
+                uno::Sequence<OUString> aSeq
+                    = 
comphelper::string::convertCommaSeparated(OUString::fromUtf8(aRectangle));
+                CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(4), 
aSeq.getLength());
+                m_aCursorRectangle = tools::Rectangle(Point(aSeq[0].toInt32(), 
aSeq[1].toInt32()),
+                                                      Size(aSeq[2].toInt32(), 
aSeq[3].toInt32()));
+            }
+        }
+        break;
+        case LOK_CALLBACK_FORM_FIELD_BUTTON:
+        {
+            m_aFormFieldButton = OString(pPayload);
+        }
+        break;
+        case LOK_CALLBACK_CONTENT_CONTROL:
+        {
+            m_aContentControl = OString(pPayload);
+        }
+        break;
+        case LOK_CALLBACK_GRAPHIC_SELECTION:
+        {
+            m_ShapeSelection = OString(pPayload);
+        }
+        break;
+        case LOK_CALLBACK_TOOLTIP:
+        {
+            std::stringstream aStream(pPayload);
+            boost::property_tree::ptree aTree;
+            boost::property_tree::read_json(aStream, aTree);
+            m_aTooltip.text = aTree.get_child("text").get_value<std::string>();
+            m_aTooltip.rect = 
aTree.get_child("rectangle").get_value<std::string>();
+        }
+        break;
+    }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Reply via email to