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; } };
