sw/source/core/inc/scriptinfo.hxx | 4 +- sw/source/core/text/porlay.cxx | 74 +++++++++++++++++++++++++++++--------- sw/source/core/text/porrst.cxx | 65 +++++++++++++++++++++++++++++++++ sw/source/core/text/porrst.hxx | 4 +- 4 files changed, 127 insertions(+), 20 deletions(-)
New commits: commit 3393e52be0900ad63ceee0a43cd44d473ec8248a Author: László Németh <nem...@numbertext.org> AuthorDate: Tue Oct 1 19:33:46 2024 +0200 Commit: László Németh <nem...@numbertext.org> CommitDate: Sat Oct 5 16:20:57 2024 +0200 tdf#163309 sw: show rdf:type as labels on bookmark boundary marks OOo's RDF handling had limited support to optional metadata visualization, like custom prefix/suffix of metadata fields. This is a similar visualization for bookmark rdf:type metadata, but without changing the text layout by enabling/disabling View->Field Shading. The labels, i.e. text content of rdf:type have left-aligned top position after the opening bracket of the optional bookmark boundary mark, and right-aligned bottom position before the closing bracket. The labels don't overlap at multiple brackets. Note: the labels are very next to the line text vertically to support fixed line height better. Follow-up to commit 412e0ab26618c38f548c340f85ef63bbe73ef6b2 "tdf#150717 sw RDF metadata: add custom color bookmark boundary marks" Change-Id: I0756c91b51c706f4c7b70fa07f1c7e8fbbf0dc90 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/174486 Tested-by: Jenkins Reviewed-by: László Németh <nem...@numbertext.org> diff --git a/sw/source/core/inc/scriptinfo.hxx b/sw/source/core/inc/scriptinfo.hxx index 60cf9c542eab..65c34f407a3e 100644 --- a/sw/source/core/inc/scriptinfo.hxx +++ b/sw/source/core/inc/scriptinfo.hxx @@ -72,7 +72,7 @@ private: std::deque<TextFrameIndex> m_NoKashidaLine; std::deque<TextFrameIndex> m_NoKashidaLineEnd; std::vector<TextFrameIndex> m_HiddenChg; - std::vector<std::tuple<TextFrameIndex, MarkKind, Color, OUString>> m_Bookmarks; + std::vector<std::tuple<TextFrameIndex, MarkKind, Color, OUString, OUString>> m_Bookmarks; //! Records a single change in compression. struct CompressionChangeInfo { @@ -184,7 +184,7 @@ public: } TextFrameIndex NextHiddenChg(TextFrameIndex nPos) const; TextFrameIndex NextBookmark(TextFrameIndex nPos) const; - std::vector<std::tuple<MarkKind, Color, OUString>> + std::vector<std::tuple<MarkKind, Color, OUString, OUString>> GetBookmarks(TextFrameIndex const nPos); static void CalcHiddenRanges(const SwTextNode& rNode, MultiSelection& rHiddenMulti, diff --git a/sw/source/core/text/porlay.cxx b/sw/source/core/text/porlay.cxx index 39a260ac0ef8..9f0fd502114f 100644 --- a/sw/source/core/text/porlay.cxx +++ b/sw/source/core/text/porlay.cxx @@ -909,13 +909,54 @@ static Color getBookmarkColor(const SwTextNode& rNode, const sw::mark::Bookmark* return c; } +static OUString getBookmarkType(const SwTextNode& rNode, const sw::mark::Bookmark* pBookmark) +{ + // search ODF_PREFIX in metadata, otherwise use empty string; + OUString sRet; + + try + { + SwDoc& rDoc = const_cast<SwDoc&>(rNode.GetDoc()); + const rtl::Reference< SwXBookmark > xRef = SwXBookmark::CreateXBookmark(rDoc, + const_cast<sw::mark::MarkBase*>(static_cast<const sw::mark::MarkBase*>(pBookmark))); + const css::uno::Reference<css::rdf::XResource> xSubject(xRef); + rtl::Reference<SwXTextDocument> xModel = rDoc.GetDocShell()->GetBaseModel(); + + static uno::Reference< uno::XComponentContext > xContext( + ::comphelper::getProcessComponentContext()); + + static uno::Reference< rdf::XURI > xODF_PREFIX( + rdf::URI::createKnown(xContext, rdf::URIs::RDF_TYPE), uno::UNO_SET_THROW); + + uno::Reference<rdf::XDocumentMetadataAccess> xDocumentMetadataAccess( + rDoc.GetDocShell()->GetBaseModel()); + const uno::Reference<rdf::XRepository>& xRepository = + xDocumentMetadataAccess->getRDFRepository(); + const uno::Reference<container::XEnumeration> xEnum( + xRepository->getStatements(xSubject, xODF_PREFIX, 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() ) + sRet = xObject->getValue(); + } + } + catch (const lang::IllegalArgumentException&) + { + } + + return sRet; +} + 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::Bookmark const*, SwScriptInfo::MarkKind>> & rBookmarks, - std::vector<std::tuple<TextFrameIndex, SwScriptInfo::MarkKind, Color, OUString>> & o_rBookmarks) + std::vector<std::tuple<TextFrameIndex, SwScriptInfo::MarkKind, Color, OUString, OUString>> & o_rBookmarks) { SwTextNode const*const pNode(iter->pNode); for (auto const& it : rBookmarks) @@ -925,7 +966,7 @@ static void InitBookmarks( // search for custom bookmark boundary mark color Color c = getBookmarkColor(*pNode, it.first); - + OUString sType = getBookmarkType(*pNode, it.first); switch (it.second) { case SwScriptInfo::MarkKind::Start: @@ -953,7 +994,7 @@ static void InitBookmarks( } else { - o_rBookmarks.emplace_back(nOffset, it.second, c, it.first->GetName()); + o_rBookmarks.emplace_back(nOffset, it.second, c, it.first->GetName(), sType); break; } } @@ -972,7 +1013,7 @@ static void InitBookmarks( { o_rBookmarks.emplace_back( nOffset + TextFrameIndex(rStart.GetContentIndex() - iter->nStart), - it.second, c, it.first->GetName()); + it.second, c, it.first->GetName(), sType); break; } } @@ -991,7 +1032,7 @@ static void InitBookmarks( } else { - o_rBookmarks.emplace_back(nOffset, it.second, c, it.first->GetName()); + o_rBookmarks.emplace_back(nOffset, it.second, c, it.first->GetName(), sType); } } break; @@ -1020,7 +1061,7 @@ static void InitBookmarks( } else { - o_rBookmarks.emplace_back(nOffset, it.second, c, it.first->GetName()); + o_rBookmarks.emplace_back(nOffset, it.second, c, it.first->GetName(), sType); break; } } @@ -1028,7 +1069,7 @@ static void InitBookmarks( { o_rBookmarks.emplace_back( nOffset + TextFrameIndex(rEnd.GetContentIndex() - iter->nStart), - it.second, c, it.first->GetName()); + it.second, c, it.first->GetName(), sType); break; } else @@ -1062,7 +1103,7 @@ static void InitBookmarks( { o_rBookmarks.emplace_back( nOffset + TextFrameIndex(rPos.GetContentIndex() - iter->nStart), - it.second, c, it.first->GetName()); + it.second, c, it.first->GetName(), sType); } break; } @@ -1210,17 +1251,18 @@ void SwScriptInfo::InitScriptInfo(const SwTextNode& rNode, // search for custom bookmark boundary mark color Color c = getBookmarkColor(rNode, it.first); + OUString sType = getBookmarkType(rNode, it.first); switch (it.second) { case MarkKind::Start: - m_Bookmarks.emplace_back(TextFrameIndex(it.first->GetMarkStart().GetContentIndex()), it.second, c, it.first->GetName()); + m_Bookmarks.emplace_back(TextFrameIndex(it.first->GetMarkStart().GetContentIndex()), it.second, c, it.first->GetName(), sType); break; case MarkKind::End: - m_Bookmarks.emplace_back(TextFrameIndex(it.first->GetMarkEnd().GetContentIndex()), it.second, c, it.first->GetName()); + m_Bookmarks.emplace_back(TextFrameIndex(it.first->GetMarkEnd().GetContentIndex()), it.second, c, it.first->GetName(), sType); break; case MarkKind::Point: - m_Bookmarks.emplace_back(TextFrameIndex(it.first->GetMarkPos().GetContentIndex()), it.second, c, it.first->GetName()); + m_Bookmarks.emplace_back(TextFrameIndex(it.first->GetMarkPos().GetContentIndex()), it.second, c, it.first->GetName(), sType); break; } } @@ -1762,10 +1804,10 @@ TextFrameIndex SwScriptInfo::NextBookmark(TextFrameIndex const nPos) const return TextFrameIndex(COMPLETE_STRING); } -std::vector<std::tuple<SwScriptInfo::MarkKind, Color, OUString>> +std::vector<std::tuple<SwScriptInfo::MarkKind, Color, OUString, OUString>> SwScriptInfo::GetBookmarks(TextFrameIndex const nPos) { - std::vector<std::tuple<SwScriptInfo::MarkKind, Color, OUString>> aColors; + std::vector<std::tuple<SwScriptInfo::MarkKind, Color, OUString, OUString>> aColors; for (auto const& it : m_Bookmarks) { if (nPos == std::get<0>(it)) @@ -1774,8 +1816,8 @@ std::vector<std::tuple<SwScriptInfo::MarkKind, Color, OUString>> // filter hidden bookmarks imported from OOXML // TODO import them as hidden bookmarks if ( !( sName.startsWith("_Toc") || sName.startsWith("_Ref") ) ) - aColors.push_back(std::tuple<MarkKind, Color, - OUString>(std::get<1>(it), std::get<2>(it), std::get<3>(it))); + aColors.push_back(std::tuple<MarkKind, Color, OUString, + OUString>(std::get<1>(it), std::get<2>(it), std::get<3>(it), std::get<4>(it))); } else if (nPos < std::get<0>(it)) { @@ -1787,7 +1829,7 @@ std::vector<std::tuple<SwScriptInfo::MarkKind, Color, OUString>> // mark order: ] | [ // color order: [c1 [c2 [c3 ... c3] c2] c1] sort(aColors.begin(), aColors.end(), - [](std::tuple<MarkKind, Color, OUString> const a, std::tuple<MarkKind, Color, OUString> const b) { + [](std::tuple<MarkKind, Color, OUString, OUString> const a, std::tuple<MarkKind, Color, OUString, OUString> const b) { return (MarkKind::End == std::get<0>(a) && MarkKind::End != std::get<0>(b)) || (MarkKind::Point == std::get<0>(a) && MarkKind::Start == std::get<0>(b)) || // if both are end or start, order by color diff --git a/sw/source/core/text/porrst.cxx b/sw/source/core/text/porrst.cxx index ee409a4c80e2..0a8bab3d66ea 100644 --- a/sw/source/core/text/porrst.cxx +++ b/sw/source/core/text/porrst.cxx @@ -819,6 +819,8 @@ void SwBookmarkPortion::Paint( const SwTextPaintInfo &rInf ) const if ( !mnHalfCharWidth ) mnHalfCharWidth = rInf.GetTextSize( aOutString ).Width() / 2; + auto nHeight = rInf.GetTextSize( aOutString ).Height(); + Point aOldPos = rInf.GetPos(); Point aNewPos( aOldPos ); auto const deltaX((Width() / 2) - mnHalfCharWidth); @@ -858,6 +860,9 @@ void SwBookmarkPortion::Paint( const SwTextPaintInfo &rInf ) const const_cast< SwTextPaintInfo& >( rInf ).SetPos( aNewPos ); + SwTwips nTypePos = 0; // shift to the position of the next rdf:type label + sal_Int32 nDirection = -1; // start with the closing brackets + bool bStart = true; for ( const auto& it : m_aColors ) { // set bold for custom colored bookmark symbol @@ -866,6 +871,17 @@ void SwBookmarkPortion::Paint( const SwTextPaintInfo &rInf ) const aTmpFont.SetColor( COL_TRANSPARENT == std::get<1>(it) ? rInf.GetOpt().GetFieldShadingsColor() : std::get<1>(it) ); aOutString = OUString(std::get<0>(it) == SwScriptInfo::MarkKind::Start ? '[' : ']'); + if (nDirection == -1 && std::get<0>(it) != SwScriptInfo::MarkKind::End) + { + nDirection = 1; + nTypePos = mnHalfCharWidth * 2; // start label after the opening bracket + } + + // vertical rdf:type label position for the opening and closing brackets + sal_Int32 fPos = std::get<0>(it) == SwScriptInfo::MarkKind::Start + ? -0.6 * nHeight + : 0.3 * nHeight; + // MarkKind::Point: drawn I-beam (e.g. U+2336) as overlapping ][ if ( std::get<0>(it) == SwScriptInfo::MarkKind::Point ) { @@ -880,6 +896,55 @@ void SwBookmarkPortion::Paint( const SwTextPaintInfo &rInf ) const aOutString = OUString('['); } rInf.DrawText( aOutString, *this ); + + // show rdf:type labels, left-aligned top position after the opening brackets + // right-aligned bottom position before the closing brackets + // if there are multiple opening or closing brackets, collect + // their length in nTypePos to show non-overlapping labels + OUString sType = std::get<3>(it); + if ( !sType.isEmpty() ) + { + Size aTmpSz = aTmpFont.GetSize( SwFontScript::Latin ); + auto origSize = aTmpSz; + + // calculate label size + aTmpSz.setHeight( ( 100 * aTmpSz.Height() ) / 250 ); + aTmpSz.setWidth( ( 100 * aTmpSz.Width() ) / 250 ); + + if ( aTmpSz.Width() || aTmpSz.Height() ) + { + aTmpFont.SetSize( aTmpSz, SwFontScript::Latin ); + + aNewPos.AdjustY(fPos); + if ( nDirection == -1 ) + { + if (bStart) + { + nTypePos += rInf.GetTextSize( sType ).Width(); + bStart = false; + } + else + nTypePos += rInf.GetTextSize( sType + " " ).Width() + 2 * mnHalfCharWidth; + } + aNewPos.AdjustX( nDirection * nTypePos ); + + const_cast< SwTextPaintInfo& >( rInf ).SetPos( aNewPos ); + + rInf.DrawText( sType, *this ); + + // restore original position + aNewPos.AdjustX( -nDirection * nTypePos ); + if ( nDirection == 1 ) + nTypePos += rInf.GetTextSize( sType + " " ).Width() - mnHalfCharWidth * 2; + + aNewPos.AdjustY(-fPos); + } + // restore original text size + aTmpSz.setHeight(origSize.Height()); + aTmpSz.setWidth(origSize.Width()); + aTmpFont.SetSize( origSize, SwFontScript::Latin ); + } + // place the next symbol after the previous one // TODO: fix orientation and start/end aNewPos.AdjustX(mnHalfCharWidth * 2); diff --git a/sw/source/core/text/porrst.hxx b/sw/source/core/text/porrst.hxx index 889f7e7d775a..85c58d6e2619 100644 --- a/sw/source/core/text/porrst.hxx +++ b/sw/source/core/text/porrst.hxx @@ -185,13 +185,13 @@ public: class SwBookmarkPortion : public SwControlCharPortion { // custom colors defined by metadata - std::vector<std::tuple<SwScriptInfo::MarkKind, Color, OUString>> m_aColors; + std::vector<std::tuple<SwScriptInfo::MarkKind, Color, OUString, OUString>> m_aColors; // number of MarkKind marks sal_Int16 m_nStart, m_nEnd, m_nPoint; bool m_bHasCustomColor; public: - explicit SwBookmarkPortion(sal_Unicode const cChar, std::vector<std::tuple<SwScriptInfo::MarkKind, Color, OUString>> aColors) + explicit SwBookmarkPortion(sal_Unicode const cChar, std::vector<std::tuple<SwScriptInfo::MarkKind, Color, OUString, OUString>> aColors) : SwControlCharPortion(cChar), m_aColors(std::move(aColors)), m_nStart(0), m_nEnd(0), m_nPoint(0), m_bHasCustomColor(false) { SetWhichPor(PortionType::Bookmark);