sw/source/core/inc/scriptinfo.hxx |    4 +
 sw/source/core/text/itrform2.cxx  |    6 +-
 sw/source/core/text/porlay.cxx    |  109 ++++++++++++++++++++++++++++++++------
 sw/source/core/text/porrst.cxx    |   70 ++++++++++++++++++++++++
 sw/source/core/text/porrst.hxx    |   10 ++-
 5 files changed, 178 insertions(+), 21 deletions(-)

New commits:
commit 412e0ab26618c38f548c340f85ef63bbe73ef6b2
Author:     László Németh <[email protected]>
AuthorDate: Wed Aug 31 12:49:20 2022 +0200
Commit:     László Németh <[email protected]>
CommitDate: Fri Sep 2 14:18:49 2022 +0200

    tdf#150717 sw RDF metadata: add custom color bookmark boundary marks
    
    Bookmark boundary marks applied a single color for all bookmarks
    with metadata. For visualization of metadata categories e.g.
    for quick verification of automatic annotation, add RDF-based
    custom color bookmark boundary marks, using LO_EXT_SHADING
    feature added by commit a8a9b4f4635bff3f1b7ec63b62f661bc15196cd6
    "tdf#142448 sw offapi: add custom color metadata field shading".
    
    Show all colors of overlapping or neighboring bookmarks,
    when there are multiple boundary marks at the same
    character position, by painting all custom color bookmark
    boundary marks of the same character position.
    
    See also commit 4ce8120f1e53f7b81e653b01d141643013bc69ab
    "tdf#45589 sw: create and paint text portions for bookmarks".
    
    Change-Id: I845dadcf2f888493c43fcf48bc34af1c4cf340c5
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/139110
    Tested-by: Jenkins
    Reviewed-by: László Németh <[email protected]>

diff --git a/sw/source/core/inc/scriptinfo.hxx 
b/sw/source/core/inc/scriptinfo.hxx
index ee536803a617..77ed50e497d5 100644
--- a/sw/source/core/inc/scriptinfo.hxx
+++ b/sw/source/core/inc/scriptinfo.hxx
@@ -28,6 +28,7 @@
 #include <i18nlangtag/lang.h>
 #include <tools/long.hxx>
 #include "TextFrameIndex.hxx"
+#include <doc.hxx>
 
 class SwTextNode;
 class SwTextFrame;
@@ -71,7 +72,7 @@ private:
     std::deque<TextFrameIndex> m_NoKashidaLine;
     std::deque<TextFrameIndex> m_NoKashidaLineEnd;
     std::vector<TextFrameIndex> m_HiddenChg;
-    std::vector<std::pair<TextFrameIndex, MarkKind>> m_Bookmarks;
+    std::vector<std::tuple<TextFrameIndex, MarkKind, Color>> m_Bookmarks;
     //! Records a single change in compression.
     struct CompressionChangeInfo
     {
@@ -185,6 +186,7 @@ public:
     TextFrameIndex NextHiddenChg(TextFrameIndex nPos) const;
     TextFrameIndex NextBookmark(TextFrameIndex nPos) const;
     MarkKind GetBookmark(TextFrameIndex nPos) const;
+    std::optional<std::vector<Color>> GetBookmarkColors(TextFrameIndex nPos) 
const;
     static void CalcHiddenRanges(const SwTextNode& rNode,
             MultiSelection& rHiddenMulti,
             std::vector<std::pair<sw::mark::IBookmark const*, MarkKind>> * 
pBookmarks);
diff --git a/sw/source/core/text/itrform2.cxx b/sw/source/core/text/itrform2.cxx
index 54f8e993b4cb..6c38bdbe3586 100644
--- a/sw/source/core/text/itrform2.cxx
+++ b/sw/source/core/text/itrform2.cxx
@@ -1321,7 +1321,11 @@ SwLinePortion 
*SwTextFormatter::WhichFirstPortion(SwTextFormatInfo &rInf)
                 assert(bookmark & SwScriptInfo::MarkKind::Point);
                 mark = '|';
             }
-            pPor = new SwBookmarkPortion(mark);
+
+            // collect custom bookmark colors
+            auto rColors = m_pScriptInfo->GetBookmarkColors(rInf.GetIdx());
+
+            pPor = new SwBookmarkPortion(mark, rColors);
         }
     }
 
diff --git a/sw/source/core/text/porlay.cxx b/sw/source/core/text/porlay.cxx
index 004e8c482e77..e85bcb8d3071 100644
--- a/sw/source/core/text/porlay.cxx
+++ b/sw/source/core/text/porlay.cxx
@@ -58,6 +58,19 @@
 #include <IDocumentContentOperations.hxx>
 #include <IMark.hxx>
 #include <sortedobjs.hxx>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/text/XBookmarksSupplier.hpp>
+#include <officecfg/Office/Common.hxx>
+#include <comphelper/processfactory.hxx>
+#include <docsh.hxx>
+#include <unobookmark.hxx>
+#include <unocrsrhelper.hxx>
+#include <com/sun/star/rdf/Statement.hpp>
+#include <com/sun/star/rdf/URI.hpp>
+#include <com/sun/star/rdf/URIs.hpp>
+#include <com/sun/star/rdf/XDocumentMetadataAccess.hpp>
+#include <com/sun/star/rdf/XLiteral.hpp>
+#include <com/sun/star/text/XTextContent.hpp>
 
 using namespace ::com::sun::star;
 using namespace i18n::ScriptType;
@@ -887,19 +900,64 @@ SwFontScript SwScriptInfo::WhichFont(sal_Int32 nIdx, 
OUString const& rText)
     return lcl_ScriptToFont(nScript);
 }
 
+static Color getBookmarkColor(const SwTextNode& rNode, const 
sw::mark::IBookmark* pBookmark)
+{
+    // search custom color in metadata, otherwise use COL_TRANSPARENT;
+    Color c = COL_TRANSPARENT;
+
+    try
+    {
+        SwDoc& rDoc = const_cast<SwDoc&>(rNode.GetDoc());
+        const uno::Reference< text::XTextContent > xRef = 
SwXBookmark::CreateXBookmark(rDoc,
+                const_cast<sw::mark::IMark*>(static_cast<const 
sw::mark::IMark*>(pBookmark)));
+        const css::uno::Reference<css::rdf::XResource> xSubject(xRef, 
uno::UNO_QUERY);
+        uno::Reference<frame::XModel> xModel = 
rDoc.GetDocShell()->GetBaseModel();
+
+        static uno::Reference< uno::XComponentContext > xContext(
+            ::comphelper::getProcessComponentContext());
+
+        static uno::Reference< rdf::XURI > xODF_SHADING(
+            rdf::URI::createKnown(xContext, rdf::URIs::LO_EXT_SHADING), 
uno::UNO_SET_THROW);
+
+        uno::Reference<rdf::XDocumentMetadataAccess> xDocumentMetadataAccess(
+            rDoc.GetDocShell()->GetBaseModel(), uno::UNO_QUERY);
+        const uno::Reference<rdf::XRepository>& xRepository =
+            xDocumentMetadataAccess->getRDFRepository();
+        const uno::Reference<container::XEnumeration> xEnum(
+            xRepository->getStatements(xSubject, xODF_SHADING, nullptr), 
uno::UNO_SET_THROW);
+
+        rdf::Statement stmt;
+        if ( xEnum->hasMoreElements() && (xEnum->nextElement() >>= stmt) )
+        {
+            const uno::Reference<rdf::XLiteral> xObject(stmt.Object, 
uno::UNO_QUERY);
+            if ( xObject.is() )
+                c = Color::STRtoRGB(xObject->getValue());
+        }
+    }
+    catch (const lang::IllegalArgumentException&)
+    {
+    }
+
+    return c;
+}
+
 static void InitBookmarks(
     std::optional<std::vector<sw::Extent>::const_iterator> oPrevIter,
     std::vector<sw::Extent>::const_iterator iter,
     std::vector<sw::Extent>::const_iterator const end,
     TextFrameIndex nOffset,
     std::vector<std::pair<sw::mark::IBookmark const*, SwScriptInfo::MarkKind>> 
& rBookmarks,
-    std::vector<std::pair<TextFrameIndex, SwScriptInfo::MarkKind>> & 
o_rBookmarks)
+    std::vector<std::tuple<TextFrameIndex, SwScriptInfo::MarkKind, Color>> & 
o_rBookmarks)
 {
     SwTextNode const*const pNode(iter->pNode);
     for (auto const& it : rBookmarks)
     {
         assert(iter->pNode == pNode || pNode->GetIndex() < 
iter->pNode->GetIndex());
         assert(!oPrevIter || (*oPrevIter)->pNode->GetIndex() <= 
pNode->GetIndex());
+
+        // search for custom bookmark boundary mark color
+        Color c = getBookmarkColor(*pNode, it.first);
+
         switch (it.second)
         {
             case SwScriptInfo::MarkKind::Start:
@@ -928,7 +986,7 @@ static void InitBookmarks(
                         }
                         else
                         {
-                            o_rBookmarks.emplace_back(nOffset, it.second);
+                            o_rBookmarks.emplace_back(nOffset, it.second, c);
                             break;
                         }
                     }
@@ -947,7 +1005,7 @@ static void InitBookmarks(
                         {
                             o_rBookmarks.emplace_back(
                                 nOffset + 
TextFrameIndex(rStart.GetContentIndex() - iter->nStart),
-                                it.second);
+                                it.second, c);
                             break;
                         }
                     }
@@ -966,7 +1024,7 @@ static void InitBookmarks(
                     }
                     else
                     {
-                        o_rBookmarks.emplace_back(nOffset, it.second);
+                        o_rBookmarks.emplace_back(nOffset, it.second, c);
                     }
                 }
                 break;
@@ -995,7 +1053,7 @@ static void InitBookmarks(
                         }
                         else
                         {
-                            o_rBookmarks.emplace_back(nOffset, it.second);
+                            o_rBookmarks.emplace_back(nOffset, it.second, c);
                             break;
                         }
                     }
@@ -1003,7 +1061,7 @@ static void InitBookmarks(
                     {
                         o_rBookmarks.emplace_back(
                             nOffset + TextFrameIndex(rEnd.GetContentIndex() - 
iter->nStart),
-                            it.second);
+                            it.second, c);
                         break;
                     }
                     else
@@ -1037,7 +1095,7 @@ static void InitBookmarks(
                         {
                             o_rBookmarks.emplace_back(
                                 nOffset + 
TextFrameIndex(rPos.GetContentIndex() - iter->nStart),
-                                it.second);
+                                it.second, c);
                         }
                         break;
                     }
@@ -1174,16 +1232,19 @@ void SwScriptInfo::InitScriptInfo(const SwTextNode& 
rNode,
 
         for (auto const& it : bookmarks)
         {
+            // search for custom bookmark boundary mark color
+            Color c = getBookmarkColor(rNode, it.first);
+
             switch (it.second)
             {
                 case MarkKind::Start:
-                    
m_Bookmarks.emplace_back(TextFrameIndex(it.first->GetMarkStart().GetContentIndex()),
 it.second);
+                    
m_Bookmarks.emplace_back(TextFrameIndex(it.first->GetMarkStart().GetContentIndex()),
 it.second, c);
                     break;
                 case MarkKind::End:
-                    
m_Bookmarks.emplace_back(TextFrameIndex(it.first->GetMarkEnd().GetContentIndex()),
 it.second);
+                    
m_Bookmarks.emplace_back(TextFrameIndex(it.first->GetMarkEnd().GetContentIndex()),
 it.second, c);
                     break;
                 case MarkKind::Point:
-                    
m_Bookmarks.emplace_back(TextFrameIndex(it.first->GetMarkPos().GetContentIndex()),
 it.second);
+                    
m_Bookmarks.emplace_back(TextFrameIndex(it.first->GetMarkPos().GetContentIndex()),
 it.second, c);
                     break;
             }
         }
@@ -1872,9 +1933,9 @@ TextFrameIndex SwScriptInfo::NextBookmark(TextFrameIndex 
const nPos) const
 {
     for (auto const& it : m_Bookmarks)
     {
-        if (nPos < it.first)
+        if (nPos < std::get<0>(it))
         {
-            return it.first;
+            return std::get<0>(it);
         }
     }
     return TextFrameIndex(COMPLETE_STRING);
@@ -1885,11 +1946,11 @@ auto SwScriptInfo::GetBookmark(TextFrameIndex const 
nPos) const -> MarkKind
     MarkKind ret{0};
     for (auto const& it : m_Bookmarks)
     {
-        if (nPos == it.first)
+        if (nPos == std::get<0>(it))
         {
-            ret |= it.second;
+            ret |= std::get<1>(it);
         }
-        else if (nPos < it.first)
+        else if (nPos < std::get<0>(it))
         {
             break;
         }
@@ -1897,6 +1958,24 @@ auto SwScriptInfo::GetBookmark(TextFrameIndex const 
nPos) const -> MarkKind
     return ret;
 }
 
+std::optional<std::vector<Color>> 
SwScriptInfo::GetBookmarkColors(TextFrameIndex const nPos) const
+{
+    std::optional<std::vector<Color>> ret;
+    std::vector<Color> aColors;
+    for (auto const& it : m_Bookmarks)
+    {
+        if (nPos == std::get<0>(it) && COL_TRANSPARENT != std::get<2>(it))
+        {
+            aColors.push_back(std::get<2>(it));
+        }
+        else if (nPos < std::get<0>(it))
+        {
+            break;
+        }
+    }
+    return aColors.empty() ? ret : ret.emplace(aColors);
+}
+
 // Takes a string and replaced the hidden ranges with cChar.
 sal_Int32 SwScriptInfo::MaskHiddenRanges( const SwTextNode& rNode, 
OUStringBuffer & rText,
                                        const sal_Int32 nStt, const sal_Int32 
nEnd,
diff --git a/sw/source/core/text/porrst.cxx b/sw/source/core/text/porrst.cxx
index e863ba29641d..d5acb572d911 100644
--- a/sw/source/core/text/porrst.cxx
+++ b/sw/source/core/text/porrst.cxx
@@ -650,7 +650,8 @@ bool SwControlCharPortion::DoPaint(SwTextPaintInfo const&,
 bool SwBookmarkPortion::DoPaint(SwTextPaintInfo const& rTextPaintInfo,
         OUString & rOutString, SwFont & rFont, int & rDeltaY) const
 {
-    if (!rTextPaintInfo.GetOpt().IsShowBookmarks())
+    // custom color is visible without field shading, too
+    if (!rTextPaintInfo.GetOpt().IsShowBookmarks(m_oColors.has_value()))
     {
         return false;
     }
@@ -739,6 +740,73 @@ void SwControlCharPortion::Paint( const SwTextPaintInfo 
&rInf ) const
     const_cast< SwTextPaintInfo& >( rInf ).SetPos( aOldPos );
 }
 
+void SwBookmarkPortion::Paint( const SwTextPaintInfo &rInf ) const
+{
+    if ( !Width() )  // is only set during prepaint mode
+        return;
+
+    rInf.DrawViewOpt(*this, GetWhichPor());
+
+    int deltaY(0);
+    SwFont aTmpFont( *rInf.GetFont() );
+    OUString aOutString;
+
+    if (!(rInf.OnWin()
+        && !rInf.GetOpt().IsPagePreview()
+        && !rInf.GetOpt().IsReadonly()
+        && DoPaint(rInf, aOutString, aTmpFont, deltaY)))
+        return;
+
+    SwFontSave aFontSave( rInf, &aTmpFont );
+
+    if ( !mnHalfCharWidth )
+        mnHalfCharWidth = rInf.GetTextSize( aOutString ).Width() / 2;
+
+    Point aOldPos = rInf.GetPos();
+    Point aNewPos( aOldPos );
+    auto const deltaX((Width() / 2) - mnHalfCharWidth);
+    switch 
(rInf.GetFont()->GetOrientation(rInf.GetTextFrame()->IsVertical()).get())
+    {
+        case 0:
+            aNewPos.AdjustX(deltaX);
+            aNewPos.AdjustY(deltaY);
+            break;
+        case 900:
+            aNewPos.AdjustY(-deltaX);
+            aNewPos.AdjustX(deltaY);
+            break;
+        case 2700:
+            aNewPos.AdjustY(deltaX);
+            aNewPos.AdjustX(-deltaY);
+            break;
+        default:
+            assert(false);
+            break;
+    }
+    const_cast< SwTextPaintInfo& >( rInf ).SetPos( aNewPos );
+
+    if ( m_oColors.has_value() )
+    {
+        // set bold for custom colored bookmark symbol
+        // and draw multiple symbols showing all custom colors
+        aTmpFont.SetWeight( WEIGHT_BOLD, aTmpFont.GetActual() );
+        for ( const Color& rColor : *m_oColors )
+        {
+            aTmpFont.SetColor( rColor );
+            rInf.DrawText( aOutString, *this );
+
+            // place the next symbol after the previous one
+            // TODO: fix orientation and start/end
+            aNewPos.AdjustX(mnHalfCharWidth * 2.5);
+            const_cast< SwTextPaintInfo& >( rInf ).SetPos( aNewPos );
+        }
+    }
+    else
+        rInf.DrawText( aOutString, *this );
+
+    const_cast< SwTextPaintInfo& >( rInf ).SetPos( aOldPos );
+}
+
 bool SwControlCharPortion::Format( SwTextFormatInfo &rInf )
 {
     const SwLinePortion* pRoot = rInf.GetRoot();
diff --git a/sw/source/core/text/porrst.hxx b/sw/source/core/text/porrst.hxx
index 66552eea3c7d..b09b838d253e 100644
--- a/sw/source/core/text/porrst.hxx
+++ b/sw/source/core/text/porrst.hxx
@@ -160,8 +160,8 @@ class SwControlCharPortion : public SwLinePortion
 
 private:
     mutable sal_uInt16 mnViewWidth;            // used to cache a calculated 
value
-    mutable sal_uInt16 mnHalfCharWidth;        // used to cache a calculated 
value
 protected:
+    mutable sal_uInt16 mnHalfCharWidth;        // used to cache a calculated 
value
     sal_Unicode mcChar;
 
 public:
@@ -183,9 +183,12 @@ public:
 /// SwControlCharPortion these do not have a character in the text.
 class SwBookmarkPortion : public SwControlCharPortion
 {
+    // custom colors defined by metadata
+    std::optional<std::vector<Color>> m_oColors;
+
 public:
-    explicit SwBookmarkPortion(sal_Unicode const cChar)
-        : SwControlCharPortion(cChar)
+    explicit SwBookmarkPortion(sal_Unicode const cChar, 
std::optional<std::vector<Color>>rColors)
+        : SwControlCharPortion(cChar), m_oColors(rColors)
     {
         SetWhichPor(PortionType::Bookmark);
         SetLen(TextFrameIndex(0));
@@ -193,6 +196,7 @@ public:
 
     virtual bool DoPaint(SwTextPaintInfo const& rInf,
         OUString & rOutString, SwFont & rTmpFont, int & rDeltaY) const 
override;
+    virtual void Paint( const SwTextPaintInfo &rInf ) const override;
     virtual SwLinePortion * Compress() override { return this; }
 };
 

Reply via email to