diff options
-rw-r--r-- | desktop/source/lib/init.cxx | 17 | ||||
-rw-r--r-- | include/vcl/ITiledRenderable.hxx | 7 | ||||
-rw-r--r-- | libreofficekit/source/gtk/lokdocview.cxx | 91 | ||||
-rw-r--r-- | sw/inc/swmodule.hxx | 2 | ||||
-rw-r--r-- | sw/inc/unotxdoc.hxx | 2 | ||||
-rw-r--r-- | sw/qa/extras/tiledrendering/tiledrendering.cxx | 25 | ||||
-rw-r--r-- | sw/source/uibase/app/swmodul1.cxx | 49 | ||||
-rw-r--r-- | sw/source/uibase/uno/unotxdoc.cxx | 5 |
8 files changed, 167 insertions, 31 deletions
diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx index ead812baf6d4..fcb27d97a07c 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 3a8a69743e9d..700a6bd4a283 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 786d827d92d5..8ec54a003a7f 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 66cb66b8ff79..60bf7deb4d0a 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 8867994ca2e5..56d36debdb10 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 cce710aefd4c..f6fb64fe6652 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 649937193ea2..ef0a992f5bf9 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 1e10d09256a3..5e92ecb8fee1 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; |