desktop/source/lib/init.cxx                    |   17 ++++
 include/vcl/ITiledRenderable.hxx               |    7 +
 libreofficekit/source/gtk/lokdocview.cxx       |   91 ++++++++++++++++++-------
 sw/inc/redline.hxx                             |   14 ---
 sw/inc/swmodule.hxx                            |    2 
 sw/inc/unotxdoc.hxx                            |    2 
 sw/qa/extras/tiledrendering/tiledrendering.cxx |   25 ++++++
 sw/qa/extras/uiwriter/uiwriter.cxx             |   11 ++-
 sw/source/core/doc/docredln.cxx                |   18 ++++
 sw/source/uibase/app/swmodul1.cxx              |   49 ++++++++++---
 sw/source/uibase/uno/unotxdoc.cxx              |    5 +
 11 files changed, 196 insertions(+), 45 deletions(-)

New commits:
commit 73ae22aae1d856c62d08ca576daea15056afbb58
Author: Miklos Vajna <vmik...@collabora.co.uk>
Date:   Wed Sep 21 17:27:48 2016 +0200

    lok::Document::getCommandValues: expose sw redline author colors
    
    These colors are used in the tiles, so it's a good idea if the client
    can use matching colors for cursors and selections. But to be able to do
    that, we need an API to expose these colors.
    
    Change-Id: Ia688c07e6c300fecdf8dc428d5a3f000d1857387
    (cherry picked from commit d7788287456cb633226203f259e212c143b83050)

diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index ead812b..fcb27d9 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -2117,6 +2117,19 @@ static char* getTrackedChanges(LibreOfficeKitDocument* 
pThis)
     return pJson;
 }
 
+/// Returns the JSON representation of the redline author table.
+static char* getTrackedChangeAuthors(LibreOfficeKitDocument* pThis)
+{
+    ITiledRenderable* pDoc = getTiledRenderable(pThis);
+    if (!pDoc)
+    {
+        gImpl->maLastExceptionMsg = "Document doesn't support tiled rendering";
+        return nullptr;
+    }
+    OUString aAuthors = pDoc->getTrackedChangeAuthors();
+    return strdup(aAuthors.toUtf8().getStr());
+}
+
 static char* doc_getCommandValues(LibreOfficeKitDocument* pThis, const char* 
pCommand)
 {
     SolarMutexGuard aGuard;
@@ -2145,6 +2158,10 @@ static char* 
doc_getCommandValues(LibreOfficeKitDocument* pThis, const char* pCo
     {
         return getTrackedChanges(pThis);
     }
+    else if (aCommand == ".uno:TrackedChangeAuthors")
+    {
+        return getTrackedChangeAuthors(pThis);
+    }
     else if (aCommand.startsWith(aViewRowColumnHeaders))
     {
         ITiledRenderable* pDoc = getTiledRenderable(pThis);
diff --git a/include/vcl/ITiledRenderable.hxx b/include/vcl/ITiledRenderable.hxx
index 3a8a697..700a6bd 100644
--- a/include/vcl/ITiledRenderable.hxx
+++ b/include/vcl/ITiledRenderable.hxx
@@ -207,6 +207,13 @@ public:
     {
         return OUString();
     }
+
+    /// Implementation for
+    /// lok::Document::getCommandValues(".uno:TrackedChangeAuthors").
+    virtual OUString getTrackedChangeAuthors()
+    {
+        return OUString();
+    }
 };
 
 } // namespace vcl
diff --git a/libreofficekit/source/gtk/lokdocview.cxx 
b/libreofficekit/source/gtk/lokdocview.cxx
index 786d827..8ec54a0 100644
--- a/libreofficekit/source/gtk/lokdocview.cxx
+++ b/libreofficekit/source/gtk/lokdocview.cxx
@@ -904,6 +904,28 @@ static gboolean queueDraw(gpointer pData)
     return G_SOURCE_REMOVE;
 }
 
+/// Looks up the author string from initializeForRendering()'s rendering 
arguments.
+static std::string getAuthorRenderingArgument(LOKDocViewPrivate& priv)
+{
+    std::stringstream aStream;
+    aStream << priv->m_aRenderingArguments;
+    boost::property_tree::ptree aTree;
+    boost::property_tree::read_json(aStream, aTree);
+    std::string aRet;
+    for (const std::pair<std::string, boost::property_tree::ptree>& rPair : 
aTree)
+    {
+        if (rPair.first == ".uno:Author")
+        {
+            aRet = rPair.second.get<std::string>("value");
+            break;
+        }
+    }
+    return aRet;
+}
+
+/// Author string <-> View ID map
+static std::map<std::string, int> g_aAuthorViews;
+
 /// Set up LOKDocView after the document is loaded, invoked on the main thread 
by openDocumentInThread() running in a thread.
 static gboolean postDocumentLoad(gpointer pData)
 {
@@ -913,6 +935,7 @@ static gboolean postDocumentLoad(gpointer pData)
     std::unique_lock<std::mutex> aGuard(g_aLOKMutex);
     priv->m_pDocument->pClass->initializeForRendering(priv->m_pDocument, 
priv->m_aRenderingArguments.c_str());
     priv->m_nViewId = priv->m_pDocument->pClass->getView(priv->m_pDocument);
+    g_aAuthorViews[getAuthorRenderingArgument(priv)] = priv->m_nViewId;
     priv->m_pDocument->pClass->registerCallback(priv->m_pDocument, 
callbackWorker, pLOKDocView);
     priv->m_pDocument->pClass->getDocumentSize(priv->m_pDocument, 
&priv->m_nDocumentWidthTwips, &priv->m_nDocumentHeightTwips);
     priv->m_nParts = priv->m_pDocument->pClass->getParts(priv->m_pDocument);
@@ -1586,29 +1609,53 @@ renderDocument(LOKDocView* pDocView, cairo_t* pCairo)
     return FALSE;
 }
 
-static const GdkRGBA& getDarkColor(int nViewId)
+static const GdkRGBA& getDarkColor(int nViewId, LOKDocViewPrivate& priv)
 {
     static std::map<int, GdkRGBA> aColorMap;
     auto it = aColorMap.find(nViewId);
     if (it != aColorMap.end())
         return it->second;
 
-    // Based on tools/colordata.hxx, COL_AUTHOR1_DARK..COL_AUTHOR9_DARK.
-    static std::vector<GdkRGBA> aColors =
-    {
-        {((double)198)/255, ((double)146)/255, ((double)0)/255, 0},
-        {((double)6)/255, ((double)70)/255, ((double)162)/255, 0},
-        {((double)87)/255, ((double)157)/255, ((double)28)/255, 0},
-        {((double)105)/255, ((double)43)/255, ((double)157)/255, 0},
-        {((double)197)/255, ((double)0)/255, ((double)11)/255, 0},
-        {((double)0)/255, ((double)128)/255, ((double)128)/255, 0},
-        {((double)140)/255, ((double)132)/255, ((double)0)/255, 0},
-        {((double)43)/255, ((double)85)/255, ((double)107)/255, 0},
-        {((double)209)/255, ((double)118)/255, ((double)0)/255, 0},
-    };
-    static int nColorCounter = 0;
-    GdkRGBA aColor = aColors[nColorCounter++ % aColors.size()];
-    aColorMap[nViewId] = aColor;
+    if (priv->m_eDocumentType == LOK_DOCTYPE_TEXT)
+    {
+        char* pValues = 
priv->m_pDocument->pClass->getCommandValues(priv->m_pDocument, 
".uno:TrackedChangeAuthors");
+        std::stringstream aInfo;
+        aInfo << "lok::Document::getCommandValues('.uno:TrackedChangeAuthors') 
returned '" << pValues << "'" << std::endl;
+        g_info("%s", aInfo.str().c_str());
+
+        std::stringstream aStream(pValues);
+        boost::property_tree::ptree aTree;
+        boost::property_tree::read_json(aStream, aTree);
+        for (const auto& rValue : aTree.get_child("authors"))
+        {
+            const std::string& rName = rValue.second.get<std::string>("name");
+            guint32 nColor = rValue.second.get<guint32>("color");
+            GdkRGBA aColor{((double)((guint8)((nColor)>>16)))/255, 
((double)((guint8)(((guint16)(nColor)) >> 8)))/255, 
((double)((guint8)(nColor)))/255, 0};
+            auto itAuthorViews = g_aAuthorViews.find(rName);
+            if (itAuthorViews != g_aAuthorViews.end())
+                aColorMap[itAuthorViews->second] = aColor;
+        }
+    }
+    else
+    {
+        // Based on tools/colordata.hxx, COL_AUTHOR1_DARK..COL_AUTHOR9_DARK.
+        static std::vector<GdkRGBA> aColors =
+        {
+            {((double)198)/255, ((double)146)/255, ((double)0)/255, 0},
+            {((double)6)/255, ((double)70)/255, ((double)162)/255, 0},
+            {((double)87)/255, ((double)157)/255, ((double)28)/255, 0},
+            {((double)105)/255, ((double)43)/255, ((double)157)/255, 0},
+            {((double)197)/255, ((double)0)/255, ((double)11)/255, 0},
+            {((double)0)/255, ((double)128)/255, ((double)128)/255, 0},
+            {((double)140)/255, ((double)132)/255, ((double)0)/255, 0},
+            {((double)43)/255, ((double)85)/255, ((double)107)/255, 0},
+            {((double)209)/255, ((double)118)/255, ((double)0)/255, 0},
+        };
+        static int nColorCounter = 0;
+        GdkRGBA aColor = aColors[nColorCounter++ % aColors.size()];
+        aColorMap[nViewId] = aColor;
+    }
+    assert(aColorMap.find(nViewId) != aColorMap.end());
     return aColorMap[nViewId];
 }
 
@@ -1650,7 +1697,7 @@ renderOverlay(LOKDocView* pDocView, cairo_t* pCairo)
                 // Set a minimal width if it would be 0.
                 rCursor.width = 30;
 
-            const GdkRGBA& rDark = getDarkColor(rPair.first);
+            const GdkRGBA& rDark = getDarkColor(rPair.first, priv);
             cairo_set_source_rgb(pCairo, rDark.red, rDark.green, rDark.blue);
             cairo_rectangle(pCairo,
                             twipToPixel(rCursor.x, priv->m_fZoom),
@@ -1723,7 +1770,7 @@ renderOverlay(LOKDocView* pDocView, cairo_t* pCairo)
 
         for (GdkRectangle& rRectangle : rPair.second.m_aRectangles)
         {
-            const GdkRGBA& rDark = getDarkColor(rPair.first);
+            const GdkRGBA& rDark = getDarkColor(rPair.first, priv);
             // 75% transparency.
             cairo_set_source_rgba(pCairo, rDark.red, rDark.green, rDark.blue, 
0.25);
             cairo_rectangle(pCairo,
@@ -1748,7 +1795,7 @@ renderOverlay(LOKDocView* pDocView, cairo_t* pCairo)
         if (rRectangle.m_nPart != priv->m_nPartId && priv->m_eDocumentType != 
LOK_DOCTYPE_TEXT)
             continue;
 
-        const GdkRGBA& rDark = getDarkColor(rPair.first);
+        const GdkRGBA& rDark = getDarkColor(rPair.first, priv);
         renderGraphicHandle(pDocView, pCairo, rRectangle.m_aRectangle, rDark);
     }
 
@@ -1772,7 +1819,7 @@ renderOverlay(LOKDocView* pDocView, cairo_t* pCairo)
         if (rCursor.m_nPart != priv->m_nPartId)
             continue;
 
-        const GdkRGBA& rDark = getDarkColor(rPair.first);
+        const GdkRGBA& rDark = getDarkColor(rPair.first, priv);
         cairo_set_source_rgb(pCairo, rDark.red, rDark.green, rDark.blue);
         cairo_rectangle(pCairo,
                         twipToPixel(rCursor.m_aRectangle.x, priv->m_fZoom),
@@ -1791,7 +1838,7 @@ renderOverlay(LOKDocView* pDocView, cairo_t* pCairo)
             continue;
 
         // Draw a rectangle.
-        const GdkRGBA& rDark = getDarkColor(rPair.first);
+        const GdkRGBA& rDark = getDarkColor(rPair.first, priv);
         cairo_set_source_rgb(pCairo, rDark.red, rDark.green, rDark.blue);
         cairo_rectangle(pCairo,
                         twipToPixel(rRectangle.m_aRectangle.x, priv->m_fZoom),
diff --git a/sw/inc/swmodule.hxx b/sw/inc/swmodule.hxx
index 66cb66b..60bf7de 100644
--- a/sw/inc/swmodule.hxx
+++ b/sw/inc/swmodule.hxx
@@ -187,6 +187,8 @@ public:
     // Redlining.
     sal_uInt16          GetRedlineAuthor();
     OUString            GetRedlineAuthor(sal_uInt16 nPos);
+    /// See SwXTextDocument::getTrackedChangeAuthors().
+    OUString GetRedlineAuthorInfo();
     sal_uInt16          InsertRedlineAuthor(const OUString& rAuthor);
     void                SetRedlineAuthor(const OUString& rAuthor); // for unit 
tests
 
diff --git a/sw/inc/unotxdoc.hxx b/sw/inc/unotxdoc.hxx
index 8867994..56d36de 100644
--- a/sw/inc/unotxdoc.hxx
+++ b/sw/inc/unotxdoc.hxx
@@ -439,6 +439,8 @@ public:
     virtual void setClientVisibleArea(const Rectangle& rRectangle) override;
     /// @see vcl::ITiledRenderable::getPointer().
     virtual Pointer getPointer() override;
+    /// @see vcl::ITiledRenderable::getTrackedChangeAuthors().
+    OUString getTrackedChangeAuthors() override;
 
     // css::tiledrendering::XTiledRenderable
     virtual void SAL_CALL paintTile( const ::css::uno::Any& Parent, 
::sal_Int32 nOutputWidth, ::sal_Int32 nOutputHeight, ::sal_Int32 nTilePosX, 
::sal_Int32 nTilePosY, ::sal_Int32 nTileWidth, ::sal_Int32 nTileHeight ) throw 
(::css::uno::RuntimeException, ::std::exception) override;
diff --git a/sw/qa/extras/tiledrendering/tiledrendering.cxx 
b/sw/qa/extras/tiledrendering/tiledrendering.cxx
index cce710a..f6fb64f 100644
--- a/sw/qa/extras/tiledrendering/tiledrendering.cxx
+++ b/sw/qa/extras/tiledrendering/tiledrendering.cxx
@@ -75,6 +75,7 @@ public:
     void testSetViewGraphicSelection();
     void testCreateViewGraphicSelection();
     void testCreateViewTextSelection();
+    void testRedlineColors();
 
     CPPUNIT_TEST_SUITE(SwTiledRenderingTest);
     CPPUNIT_TEST(testRegisterCallback);
@@ -113,6 +114,7 @@ public:
     CPPUNIT_TEST(testSetViewGraphicSelection);
     CPPUNIT_TEST(testCreateViewGraphicSelection);
     CPPUNIT_TEST(testCreateViewTextSelection);
+    CPPUNIT_TEST(testRedlineColors);
     CPPUNIT_TEST_SUITE_END();
 
 private:
@@ -1430,6 +1432,29 @@ void SwTiledRenderingTest::testCreateViewTextSelection()
     comphelper::LibreOfficeKit::setActive(false);
 }
 
+void SwTiledRenderingTest::testRedlineColors()
+{
+    // Load a document.
+    comphelper::LibreOfficeKit::setActive();
+    SwXTextDocument* pXTextDocument = createDoc("dummy.fodt");
+
+    // Turn on track changes, type "zzz" at the end.
+    uno::Reference<beans::XPropertySet> xPropertySet(mxComponent, 
uno::UNO_QUERY);
+    xPropertySet->setPropertyValue("RecordChanges", uno::makeAny(true));
+    SwWrtShell* pWrtShell = pXTextDocument->GetDocShell()->GetWrtShell();
+    pWrtShell->EndDoc();
+    pWrtShell->Insert("zzz");
+
+    // Assert that info about exactly one author is returned.
+    OUString aInfo = pXTextDocument->getTrackedChangeAuthors();
+    std::stringstream aStream(aInfo.toUtf8().getStr());
+    boost::property_tree::ptree aTree;
+    boost::property_tree::read_json(aStream, aTree);
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), 
aTree.get_child("authors").size());
+
+    comphelper::LibreOfficeKit::setActive(false);
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(SwTiledRenderingTest);
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/source/uibase/app/swmodul1.cxx 
b/sw/source/uibase/app/swmodul1.cxx
index 6499371..ef0a992 100644
--- a/sw/source/uibase/app/swmodul1.cxx
+++ b/sw/source/uibase/app/swmodul1.cxx
@@ -18,6 +18,7 @@
  */
 
 #include <memory>
+#include <boost/property_tree/json_parser.hpp>
 
 #include <hintids.hxx>
 #include <sfx2/request.hxx>
@@ -423,6 +424,44 @@ OUString SwModule::GetRedlineAuthor(sal_uInt16 nPos)
     return (*m_pAuthorNames)[nPos];
 }
 
+static ColorData lcl_GetAuthorColor(sal_uInt16 nPos)
+{
+    static const ColorData aColArr[] =
+    {
+        COL_AUTHOR1_DARK, COL_AUTHOR2_DARK, COL_AUTHOR3_DARK,
+        COL_AUTHOR4_DARK, COL_AUTHOR5_DARK, COL_AUTHOR6_DARK,
+        COL_AUTHOR7_DARK, COL_AUTHOR8_DARK, COL_AUTHOR9_DARK
+    };
+
+    return aColArr[nPos % SAL_N_ELEMENTS(aColArr)];
+}
+
+/// Returns a JSON representation of a redline author.
+boost::property_tree::ptree lcl_AuthorToJson(const OUString& rAuthor, size_t 
nIndex)
+{
+    boost::property_tree::ptree aRet;
+    aRet.put("index", nIndex);
+    aRet.put("name", rAuthor.toUtf8().getStr());
+    aRet.put("color", lcl_GetAuthorColor(nIndex));
+    return aRet;
+}
+
+OUString SwModule::GetRedlineAuthorInfo()
+{
+    boost::property_tree::ptree aTable;
+    for (size_t nAuthor = 0; nAuthor < m_pAuthorNames->size(); ++nAuthor)
+    {
+        boost::property_tree::ptree aAuthor = 
lcl_AuthorToJson((*m_pAuthorNames)[nAuthor], nAuthor);
+        aTable.push_back(std::make_pair("", aAuthor));
+    }
+
+    boost::property_tree::ptree aTree;
+    aTree.add_child("authors", aTable);
+    std::stringstream aStream;
+    boost::property_tree::write_json(aStream, aTree);
+    return OUString::fromUtf8(aStream.str().c_str());
+}
+
 sal_uInt16 SwModule::InsertRedlineAuthor(const OUString& rAuthor)
 {
     sal_uInt16 nPos = 0;
@@ -442,15 +481,7 @@ static void lcl_FillAuthorAttr( sal_uInt16 nAuthor, 
SfxItemSet &rSet,
     Color aCol( rAttr.nColor );
 
     if( COL_TRANSPARENT == rAttr.nColor )
-    {
-        static const ColorData aColArr[] = {
-         COL_AUTHOR1_DARK,      COL_AUTHOR2_DARK,   COL_AUTHOR3_DARK,
-         COL_AUTHOR4_DARK,      COL_AUTHOR5_DARK,   COL_AUTHOR6_DARK,
-         COL_AUTHOR7_DARK,      COL_AUTHOR8_DARK,   COL_AUTHOR9_DARK };
-
-        aCol.SetColor( aColArr[ nAuthor % (sizeof( aColArr ) /
-                                           sizeof( aColArr[0] )) ] );
-    }
+        aCol.SetColor(lcl_GetAuthorColor(nAuthor));
 
     bool bBackGr = COL_NONE_COLOR == rAttr.nColor;
 
diff --git a/sw/source/uibase/uno/unotxdoc.cxx 
b/sw/source/uibase/uno/unotxdoc.cxx
index 1e10d09..5e92ecb8 100644
--- a/sw/source/uibase/uno/unotxdoc.cxx
+++ b/sw/source/uibase/uno/unotxdoc.cxx
@@ -3199,6 +3199,11 @@ Pointer SwXTextDocument::getPointer()
     return pWrtShell->GetView().GetEditWin().GetPointer();
 }
 
+OUString SwXTextDocument::getTrackedChangeAuthors()
+{
+    return SW_MOD()->GetRedlineAuthorInfo();
+}
+
 int SwXTextDocument::getPart()
 {
     SolarMutexGuard aGuard;
commit 6f53baab070270b6913fd6035152382e963f4a66
Author: Miklos Vajna <vmik...@collabora.co.uk>
Date:   Wed Sep 21 12:12:51 2016 +0200

    Related: tdf#102308 sw: ignore seconds when combining redlines
    
    The purpose of storing seconds was to get a better timestamp, not to
    make combining impossible.
    
    Also fix two issues with the existing testcase:
    
    - read both timestamps, so test doesn't fail if the second is 0 in the
      first redline
    - don't fail if minute changes while waiting for a second
    
    Change-Id: Ib6c8ecdcf2f0da9191f0b48e6aaefc0b2449583e
    (cherry picked from commit f240f073d228e62afd3f60563c23626efad0df7f)

diff --git a/sw/inc/redline.hxx b/sw/inc/redline.hxx
index e51f25f..9de0a94 100644
--- a/sw/inc/redline.hxx
+++ b/sw/inc/redline.hxx
@@ -152,19 +152,7 @@ public:
 
     void SetAutoFormatFlag()
         { eType = (RedlineType_t)(eType | 
nsRedlineType_t::REDLINE_FORM_AUTOFMT); }
-    bool CanCombine( const SwRedlineData& rCmp ) const
-        {
-            return nAuthor == rCmp.nAuthor &&
-                    eType == rCmp.eType &&
-                    sComment == rCmp.sComment &&
-                    GetTimeStamp() == rCmp.GetTimeStamp() &&
-                    (( !pNext && !rCmp.pNext ) ||
-                        ( pNext && rCmp.pNext &&
-                        pNext->CanCombine( *rCmp.pNext ))) &&
-                    (( !pExtraData && !rCmp.pExtraData ) ||
-                        ( pExtraData && rCmp.pExtraData &&
-                            *pExtraData == *rCmp.pExtraData ));
-        }
+    bool CanCombine( const SwRedlineData& rCmp ) const;
 
     // ExtraData gets copied, the pointer is therefore not taken over by
     // the RedlilneObject
diff --git a/sw/qa/extras/uiwriter/uiwriter.cxx 
b/sw/qa/extras/uiwriter/uiwriter.cxx
index ad97db7..f68d292 100644
--- a/sw/qa/extras/uiwriter/uiwriter.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter.cxx
@@ -3379,11 +3379,20 @@ void SwUiWriterTest::testRedlineTimestamp()
     pWrtShell->EndDoc();
     pWrtShell->Insert("zzz");
 
+    // Inserting additional characters at the start changed the table size to
+    // 3, i.e. the first and the second "aaa" wasn't combined.
+    pWrtShell->SttDoc();
+    pWrtShell->Insert("aaa");
+
     // Now assert that at least one of the the seconds are not 0.
     const SwRedlineTable& rTable = 
pDoc->getIDocumentRedlineAccess().GetRedlineTable();
+    if (rTable.size() >= 2 && 
rTable[0]->GetRedlineData().GetTimeStamp().GetMin() != 
rTable[1]->GetRedlineData().GetTimeStamp().GetMin())
+        // The relatively rare case when waiting for a second also changes the 
minute.
+        return;
+
     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rTable.size());
     sal_uInt16 nSec1 = rTable[0]->GetRedlineData().GetTimeStamp().GetSec();
-    sal_uInt16 nSec2 = rTable[0]->GetRedlineData().GetTimeStamp().GetSec();
+    sal_uInt16 nSec2 = rTable[1]->GetRedlineData().GetTimeStamp().GetSec();
     // This failed, seconds was always 0.
     CPPUNIT_ASSERT(nSec1 != 0 || nSec2 != 0);
 }
diff --git a/sw/source/core/doc/docredln.cxx b/sw/source/core/doc/docredln.cxx
index afbb653..7049924 100644
--- a/sw/source/core/doc/docredln.cxx
+++ b/sw/source/core/doc/docredln.cxx
@@ -883,6 +883,24 @@ SwRedlineData::~SwRedlineData()
     delete pNext;
 }
 
+bool SwRedlineData::CanCombine(const SwRedlineData& rCmp) const
+{
+    DateTime aTime = GetTimeStamp();
+    aTime.SetSec(0);
+    DateTime aCompareTime = rCmp.GetTimeStamp();
+    aCompareTime.SetSec(0);
+    return nAuthor == rCmp.nAuthor &&
+            eType == rCmp.eType &&
+            sComment == rCmp.sComment &&
+            aTime == aCompareTime &&
+            (( !pNext && !rCmp.pNext ) ||
+                ( pNext && rCmp.pNext &&
+                pNext->CanCombine( *rCmp.pNext ))) &&
+            (( !pExtraData && !rCmp.pExtraData ) ||
+                ( pExtraData && rCmp.pExtraData &&
+                    *pExtraData == *rCmp.pExtraData ));
+}
+
 /// ExtraData is copied. The Pointer's ownership is thus NOT transferred
 /// to the Redline Object!
 void SwRedlineData::SetExtraData( const SwRedlineExtraData* pData )
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to