sw/qa/core/edit/data/compare-new.odt |binary
 sw/qa/core/edit/data/compare-old.odt |binary
 sw/qa/core/edit/edit.cxx             |   80 +++++++++++++++++++++++++++++++++++
 sw/source/core/edit/editsh.cxx       |   54 +++++++++++++++++++++++
 4 files changed, 133 insertions(+), 1 deletion(-)

New commits:
commit 8c57a6f8ac0df14201a83b1ed83bdfd39ca7301a
Author:     Miklos Vajna <[email protected]>
AuthorDate: Fri Feb 13 09:07:51 2026 +0100
Commit:     Caolán McNamara <[email protected]>
CommitDate: Fri Feb 13 11:31:56 2026 +0100

    cool#13988 sw redline render mode: expose old/new author/date when comparing
    
    Document compare works best when you open the new document, then perform
    document compare taking the old document as a parameter. This way
    insertions and deletions are correct (instead of being the other way
    around.)
    
    This is not intuitive, so help a LOK client provide hints to the user by
    exposing the last modified date and the last modifying user when
    comparing.
    
    Unfortunately this info is just available when comparing, so we can't
    send it again on document load, since the "this document" model doesn't
    have both the old and new metadata, we only compare content.
    
    Change-Id: I24c1968ea359536efbe26d7a673374ad42c2ff83
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/199315
    Reviewed-by: Caolán McNamara <[email protected]>
    Tested-by: Caolán McNamara <[email protected]>
    Tested-by: Jenkins CollaboraOffice <[email protected]>

diff --git a/sw/qa/core/edit/data/compare-new.odt 
b/sw/qa/core/edit/data/compare-new.odt
new file mode 100644
index 000000000000..50b6ae83f46f
Binary files /dev/null and b/sw/qa/core/edit/data/compare-new.odt differ
diff --git a/sw/qa/core/edit/data/compare-old.odt 
b/sw/qa/core/edit/data/compare-old.odt
new file mode 100644
index 000000000000..e3200824433c
Binary files /dev/null and b/sw/qa/core/edit/data/compare-old.odt differ
diff --git a/sw/qa/core/edit/edit.cxx b/sw/qa/core/edit/edit.cxx
index 270490688315..21f187ebee59 100644
--- a/sw/qa/core/edit/edit.cxx
+++ b/sw/qa/core/edit/edit.cxx
@@ -9,7 +9,13 @@
 
 #include <swmodeltestbase.hxx>
 
+#include <boost/property_tree/json_parser.hpp>
+
 #include <editeng/wghtitem.hxx>
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <test/lokcallback.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <sfx2/lokhelper.hxx>
 
 #include <docsh.hxx>
 #include <view.hxx>
@@ -32,6 +38,33 @@ public:
     {
     }
 };
+
+/// LOK view callback for test purposes.
+struct ViewCallback
+{
+    std::vector<OUString> m_aStateChanges;
+
+    static void callback(int nType, const char* pPayload, void* pData);
+    void callbackImpl(int nType, const char* pPayload);
+};
+
+void ViewCallback::callback(int nType, const char* pPayload, void* pData)
+{
+    static_cast<ViewCallback*>(pData)->callbackImpl(nType, pPayload);
+}
+
+void ViewCallback::callbackImpl(int nType, const char* pPayload)
+{
+    switch (nType)
+    {
+        case LOK_CALLBACK_STATE_CHANGED:
+        {
+            OUString aPayload = OUString::fromUtf8(pPayload);
+            m_aStateChanges.push_back(aPayload);
+        }
+        break;
+    }
+}
 }
 
 CPPUNIT_TEST_FIXTURE(Test, testRedlineHidden)
@@ -451,6 +484,53 @@ CPPUNIT_TEST_FIXTURE(Test, testRedlineReinstateSelf)
     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rRedlines.size());
 }
 
+CPPUNIT_TEST_FIXTURE(Test, testDocumentCompareCallback)
+{
+    // Set up LOK:
+    comphelper::LibreOfficeKit::setActive(true);
+
+    // Given a new document:
+    createSwDoc("compare-new.odt");
+    SwDocShell* pDocShell = getSwDocShell();
+    SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
+    ViewCallback aCallback;
+    TestLokCallbackWrapper aCallbackWrapper(&ViewCallback::callback, 
&aCallback);
+    
pWrtShell->GetSfxViewShell()->setLibreOfficeKitViewCallback(&aCallbackWrapper);
+    
aCallbackWrapper.setLOKViewId(SfxLokHelper::getView(*pWrtShell->GetSfxViewShell()));
+
+    // When comparing with an old document:
+    OUString aOther = createFileURL(u"compare-old.odt");
+    uno::Sequence<beans::PropertyValue> aArgs = {
+        comphelper::makePropertyValue("URL", aOther),
+        comphelper::makePropertyValue("NoAcceptDialog", true),
+    };
+    dispatchCommand(mxComponent, ".uno:CompareDocuments", aArgs);
+
+    // Then make sure a JSON callback with the expected content is emitted:
+    auto it = std::find_if(aCallback.m_aStateChanges.begin(), 
aCallback.m_aStateChanges.end(),
+                           [](const OUString& i) -> bool { return 
i.startsWith("{"); });
+    CPPUNIT_ASSERT(it != aCallback.m_aStateChanges.end());
+    std::stringstream aStream((std::string(it->toUtf8())));
+    boost::property_tree::ptree aTree;
+    boost::property_tree::read_json(aStream, aTree);
+    CPPUNIT_ASSERT_EQUAL(std::string("CompareDocumentsProperties"),
+                         aTree.get<std::string>("commandName"));
+    CPPUNIT_ASSERT_EQUAL(std::string("Alice"),
+                         
aTree.get<std::string>("state.metadata.otherDocument.modifiedBy"));
+    CPPUNIT_ASSERT_EQUAL(std::string("2010-02-12T13:51:17.860434211"),
+                         
aTree.get<std::string>("state.metadata.otherDocument.modificationDate"));
+    CPPUNIT_ASSERT_EQUAL(std::string("Bob"),
+                         
aTree.get<std::string>("state.metadata.thisDocument.modifiedBy"));
+    CPPUNIT_ASSERT_EQUAL(std::string("2026-02-12T13:52:55.923182809"),
+                         
aTree.get<std::string>("state.metadata.thisDocument.modificationDate"));
+
+    // Tear down LOK:
+    pWrtShell->GetSfxViewShell()->setLibreOfficeKitViewCallback(nullptr);
+    mxComponent->dispose();
+    mxComponent.clear();
+    comphelper::LibreOfficeKit::setActive(false);
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/sw/source/core/edit/editsh.cxx b/sw/source/core/edit/editsh.cxx
index df06d04efc18..74c8e37e4e45 100644
--- a/sw/source/core/edit/editsh.cxx
+++ b/sw/source/core/edit/editsh.cxx
@@ -17,6 +17,8 @@
  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
  */
 
+#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
+
 #include <hintids.hxx>
 #include <osl/diagnose.h>
 #include <vcl/commandevent.hxx>
@@ -24,6 +26,9 @@
 #include <comphelper/processfactory.hxx>
 #include <comphelper/string.hxx>
 #include <unotools/transliterationwrapper.hxx>
+#include <tools/json_writer.hxx>
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <sax/tools/converter.hxx>
 #include <fmtsrnd.hxx>
 #include <fmtinfmt.hxx>
 #include <txtinet.hxx>
@@ -56,6 +61,7 @@
 #include <SwNodeNum.hxx>
 #include <unocrsr.hxx>
 #include <calbck.hxx>
+#include <docsh.hxx>
 
 using namespace com::sun::star;
 
@@ -876,11 +882,57 @@ sal_Int32 SwEditShell::GetLineCount()
     return nRet;
 }
 
+namespace
+{
+/// Write document compare metadata about rDoc into rWriter.
+void WriteCompareDocMetadata(tools::JsonWriter& rWriter, const SwDoc& rDoc)
+{
+    const SwDocShell* pDocShell = rDoc.GetDocShell();
+    if (!pDocShell)
+    {
+        return;
+    }
+
+    uno::Reference<document::XDocumentPropertiesSupplier> 
xDPS(pDocShell->GetModel(),
+                                                               uno::UNO_QUERY);
+    uno::Reference<document::XDocumentProperties> xDocProps = 
xDPS->getDocumentProperties();
+    rWriter.put("modifiedBy", xDocProps->getModifiedBy());
+
+    util::DateTime aModificationDate = xDocProps->getModificationDate();
+    OUStringBuffer aBuffer;
+    sax::Converter::convertDateTime(aBuffer, aModificationDate, nullptr, true);
+    rWriter.put("modificationDate", aBuffer.makeStringAndClear());
+}
+}
+
 tools::Long SwEditShell::CompareDoc( const SwDoc& rDoc )
 {
+    SwDoc* pThisDoc = GetDoc();
     StartAllAction();
-    tools::Long nRet = GetDoc()->CompareDoc( rDoc );
+    tools::Long nRet = pThisDoc->CompareDoc( rDoc );
     EndAllAction();
+
+    SfxViewShell* pSfxViewShell = GetSfxViewShell();
+    if (pSfxViewShell && pSfxViewShell->getLibreOfficeKitViewCallback())
+    {
+        tools::JsonWriter aWriter;
+        aWriter.put("commandName", "CompareDocumentsProperties");
+        {
+            auto aState = aWriter.startNode("state");
+            auto aMetadata = aWriter.startNode("metadata");
+            {
+                auto aDocument = aWriter.startNode("otherDocument");
+                WriteCompareDocMetadata(aWriter, rDoc);
+            }
+            {
+                auto aDocument = aWriter.startNode("thisDocument");
+                WriteCompareDocMetadata(aWriter, *pThisDoc);
+            }
+        }
+        OString aPayload = aWriter.finishAndGetAsOString();
+        pSfxViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_STATE_CHANGED, 
aPayload);
+    }
+
     return nRet;
 }
 

Reply via email to