diff options
author | Jim Raykowski <raykowj@gmail.com> | 2023-04-15 19:53:05 -0800 |
---|---|---|
committer | Jim Raykowski <raykowj@gmail.com> | 2023-04-25 19:43:33 +0200 |
commit | 4bc86f6477c3ed5f0e97b0a530acf7e102b613b3 (patch) | |
tree | 7fa32d1191383d0f73456daecf6dbfe275f26b8e /sw | |
parent | fb76d7f454522c4e8982b8fe1e75d0eb6f37c12d (diff) |
tdf#38194 tdf#106556 Enhancement to highlight direct formatting,
paragraph style, and character style use in Writer documents
Initial commit to realize direct formatting, paragraph style, and
character style highlighting enhancement requests.
Highlighting of character direct formatting is turned on/off using
.uno:HighlightCharDF. Highlighting of paragraph styles and character
styles is turned on/off using a check box in the Sidebar Styles panel.
Closing the Sidebar also turns paragraph and character style
highlighting off. Paragraph direct formatting is indicated by a hatch
pattern over the paragraph style highlight bar and also by "+ Paragraph
Direct Formatting" appended to the tooltip that appears showing the
name of the paragraph style when the mouse pointer is over the style
highlight bar.
Colors used for styles highlighting are determined by a hash of the
style name. Lightgray is used for character direct formatting.
Known issue:
Tooltip doesn't show for paragraph style highlighting in tables and in
frames where the highlighting bar is drawn outside of the frame.
Change-Id: I6e00ee38c1c169bc7c6542a1782c03b2593e1891
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/150451
Tested-by: Jenkins
Reviewed-by: Heiko Tietze <heiko.tietze@documentfoundation.org>
Diffstat (limited to 'sw')
-rw-r--r-- | sw/inc/cmdid.h | 2 | ||||
-rw-r--r-- | sw/inc/doc.hxx | 2 | ||||
-rw-r--r-- | sw/inc/strings.hrc | 4 | ||||
-rw-r--r-- | sw/inc/view.hxx | 4 | ||||
-rw-r--r-- | sw/sdi/_viewsh.sdi | 6 | ||||
-rw-r--r-- | sw/sdi/swriter.sdi | 17 | ||||
-rw-r--r-- | sw/source/core/doc/doc.cxx | 55 | ||||
-rw-r--r-- | sw/source/core/inc/txtfrm.hxx | 6 | ||||
-rw-r--r-- | sw/source/core/layout/paintfrm.cxx | 89 | ||||
-rw-r--r-- | sw/source/core/text/frmpaint.cxx | 4 | ||||
-rw-r--r-- | sw/source/core/text/inftxt.cxx | 177 | ||||
-rw-r--r-- | sw/source/core/text/inftxt.hxx | 2 | ||||
-rw-r--r-- | sw/source/core/text/porexp.cxx | 3 | ||||
-rw-r--r-- | sw/source/core/text/portxt.cxx | 2 | ||||
-rw-r--r-- | sw/source/uibase/docvw/edtwin2.cxx | 203 | ||||
-rw-r--r-- | sw/source/uibase/uiview/view0.cxx | 11 |
16 files changed, 585 insertions, 2 deletions
diff --git a/sw/inc/cmdid.h b/sw/inc/cmdid.h index 82616e3c2340..5459c63b8ff1 100644 --- a/sw/inc/cmdid.h +++ b/sw/inc/cmdid.h @@ -170,6 +170,8 @@ class SwUINumRuleItem; #define FN_VIEW_FIELDNAME (FN_VIEW + 26) /* View field names */ #define FN_VIEW_TABLEGRID (FN_VIEW + 27) /* View tablegrid */ +#define FN_HIGHLIGHT_CHAR_DF (FN_VIEW + 28) + #define FN_SET_PAGE (FN_VIEW + 29) /* Set page template to paragraph */ #define FN_PRINT_LAYOUT (FN_VIEW + 37) /* print layout */ diff --git a/sw/inc/doc.hxx b/sw/inc/doc.hxx index 1b008bf2bac2..7a1b2e0ee969 100644 --- a/sw/inc/doc.hxx +++ b/sw/inc/doc.hxx @@ -1690,6 +1690,8 @@ public: void SetLanguage(const LanguageType eLang, const sal_uInt16 nId); + static bool HasParagraphDirectFormatting(const SwPosition& rPos); + private: // Copies master header to left / first one, if necessary - used by ChgPageDesc(). void CopyMasterHeader(const SwPageDesc &rChged, const SwFormatHeader &rHead, SwPageDesc &pDesc, bool bLeft, bool bFirst); diff --git a/sw/inc/strings.hrc b/sw/inc/strings.hrc index a9e5a78828e0..a29a9c9e6e52 100644 --- a/sw/inc/strings.hrc +++ b/sw/inc/strings.hrc @@ -1468,6 +1468,10 @@ #define STR_INFORODLG_FOLDED_PRIMARY NC_("STR_INFORODLG_FOLDED_PRIMARY", "You are trying to delete folded (hidden) content.") #define STR_INFORODLG_FOLDED_SECONDARY NC_("STR_INFORODLG_FOLDED_SECONDARY", "To delete this content, first unfold it so you can see what you intend to delete.") +#define STR_PARAGRAPH_DIRECT_FORMATTING NC_("STR_PARAGRAPH_DIRECT_FORMATTING", "Paragraph Direct Formatting") +#define STR_CHARACTER_DIRECT_FORMATTING NC_("STR_CHARACTER_DIRECT_FORMATTING", "Character Direct Formatting") +#define STR_CHARACTER_DIRECT_FORMATTING_TAG NC_("STR_CHARACTER_DIRECT_FORMATTING_TAG", "df") + #endif /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/inc/view.hxx b/sw/inc/view.hxx index ff0099ace634..60fe6fdc7303 100644 --- a/sw/inc/view.hxx +++ b/sw/inc/view.hxx @@ -270,6 +270,8 @@ class SW_DLLPUBLIC SwView: public SfxViewShell int m_nMaxOutlineLevelShown = 10; + bool m_bIsHighlightCharDF = false; + static constexpr sal_uInt16 MAX_ZOOM_PERCENT = 600; static constexpr sal_uInt16 MIN_ZOOM_PERCENT = 20; @@ -706,6 +708,8 @@ public: virtual tools::Rectangle getLOKVisibleArea() const override; virtual void flushPendingLOKInvalidateTiles() override; virtual std::optional<OString> getLOKPayload(int nType, int nViewId) const override; + + bool IsHighlightCharDF() { return m_bIsHighlightCharDF; } }; inline tools::Long SwView::GetXScroll() const diff --git a/sw/sdi/_viewsh.sdi b/sw/sdi/_viewsh.sdi index 020383d31abc..a3b2e5e3cdcc 100644 --- a/sw/sdi/_viewsh.sdi +++ b/sw/sdi/_viewsh.sdi @@ -912,6 +912,12 @@ interface BaseTextEditView StateMethod = StateViewOptions ; ] + FN_HIGHLIGHT_CHAR_DF + [ + ExecMethod = ExecViewOptions ; + StateMethod = StateViewOptions ; + ] + FN_VIEW_META_CHARS // status() [ ExecMethod = ExecViewOptions ; diff --git a/sw/sdi/swriter.sdi b/sw/sdi/swriter.sdi index 69e41da52ccc..15d098cc996c 100644 --- a/sw/sdi/swriter.sdi +++ b/sw/sdi/swriter.sdi @@ -4070,6 +4070,23 @@ SfxBoolItem Marks FN_VIEW_MARKS GroupId = SfxGroupId::View; ] +SfxBoolItem HighlightCharDF FN_HIGHLIGHT_CHAR_DF + +[ + AutoUpdate = TRUE, + FastCall = FALSE, + ReadOnlyDoc = TRUE, + Toggle = TRUE, + Container = FALSE, + RecordAbsolute = FALSE, + RecordPerSet; + + AccelConfig = TRUE, + MenuConfig = TRUE, + ToolBoxConfig = TRUE, + GroupId = SfxGroupId::View; +] + SfxVoidItem MergeCells FN_TABLE_MERGE_CELLS () [ diff --git a/sw/source/core/doc/doc.cxx b/sw/source/core/doc/doc.cxx index 07f54882fbdd..5c686f1f8c3a 100644 --- a/sw/source/core/doc/doc.cxx +++ b/sw/source/core/doc/doc.cxx @@ -105,6 +105,12 @@ */ #include <docsh.hxx> +#include <com/sun/star/text/XTextRange.hpp> +#include <editeng/unoprnms.hxx> +#include <unotextrange.hxx> +#include <unoprnms.hxx> +#include <unomap.hxx> + using namespace ::com::sun::star; sal_Int32 SwDoc::acquire() @@ -1859,4 +1865,53 @@ void SwDoc::SetLanguage(const LanguageType eLang, const sal_uInt16 nId) mpAttrPool->SetPoolDefaultItem(SvxLanguageItem(eLang, nId)); } +bool SwDoc::HasParagraphDirectFormatting(const SwPosition& rPos) +{ + uno::Reference<text::XTextRange> xRange(SwXTextRange::CreateXTextRange(rPos.GetDoc(), rPos, + &rPos)); + uno::Reference<container::XEnumerationAccess> xParaEnumAccess(xRange, uno::UNO_QUERY_THROW); + uno::Reference<container::XEnumeration> xParaEnum = xParaEnumAccess->createEnumeration(); + uno::Reference<text::XTextRange> xThisParagraphRange(xParaEnum->nextElement(), uno::UNO_QUERY); + if (xThisParagraphRange.is()) + { + const std::vector<OUString> aHiddenProperties{ UNO_NAME_RSID, + UNO_NAME_PARA_IS_NUMBERING_RESTART, + UNO_NAME_PARA_STYLE_NAME, + UNO_NAME_PARA_CONDITIONAL_STYLE_NAME, + UNO_NAME_PAGE_STYLE_NAME, + UNO_NAME_NUMBERING_START_VALUE, + UNO_NAME_NUMBERING_IS_NUMBER, + UNO_NAME_PARA_CONTINUEING_PREVIOUS_SUB_TREE, + UNO_NAME_CHAR_STYLE_NAME, + UNO_NAME_NUMBERING_LEVEL, + UNO_NAME_SORTED_TEXT_ID, + UNO_NAME_PARRSID, + UNO_NAME_CHAR_COLOR_THEME, + UNO_NAME_CHAR_COLOR_TINT_OR_SHADE }; + + SfxItemPropertySet const& rPropSet(*aSwMapProvider.GetPropertySet( + PROPERTY_MAP_PARA_AUTO_STYLE)); + SfxItemPropertyMap const& rMap(rPropSet.getPropertyMap()); + + uno::Reference<beans::XPropertySet> xPropertySet(xThisParagraphRange, + uno::UNO_QUERY_THROW); + uno::Reference<beans::XPropertyState> xPropertyState(xThisParagraphRange, + uno::UNO_QUERY_THROW); + const uno::Sequence<beans::Property> aProperties + = xPropertySet->getPropertySetInfo()->getProperties(); + for (const beans::Property& rProperty : aProperties) + { + const OUString& rPropName = rProperty.Name; + if (!rMap.hasPropertyByName(rPropName)) + continue; + if (std::find(aHiddenProperties.begin(), aHiddenProperties.end(), rPropName) + != aHiddenProperties.end()) + continue; + if (xPropertyState->getPropertyState(rPropName) == beans::PropertyState_DIRECT_VALUE) + return true; + } + } + return false; +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/inc/txtfrm.hxx b/sw/source/core/inc/txtfrm.hxx index 942867882626..2376153b40d3 100644 --- a/sw/source/core/inc/txtfrm.hxx +++ b/sw/source/core/inc/txtfrm.hxx @@ -27,6 +27,8 @@ #include <set> #include <utility> +#include <view.hxx> + namespace com::sun::star::linguistic2 { class XHyphenatedWord; } namespace sw::mark { class IMark; } @@ -330,6 +332,8 @@ class SW_DLLPUBLIC SwTextFrame final : public SwContentFrame void UpdateOutlineContentVisibilityButton(SwWrtShell* pWrtSh) const; void PaintOutlineContentVisibilityButton() const; + void PaintParagraphStylesHighlighting() const; + virtual void SwClientNotify(SwModify const& rModify, SfxHint const& rHint) override; /// Like GetDrawObjs(), but limit to fly frames which are allowed to split. @@ -791,6 +795,8 @@ public: /// a follow, i.e. not the last in a master -> follow 1 -> ... -> last follow chain? bool HasNonLastSplitFlyDrawObj() const; + static SwView* GetView(); + virtual void dumpAsXmlAttributes(xmlTextWriterPtr writer) const override; }; diff --git a/sw/source/core/layout/paintfrm.cxx b/sw/source/core/layout/paintfrm.cxx index 66612ba3b840..a68f58eaf5d7 100644 --- a/sw/source/core/layout/paintfrm.cxx +++ b/sw/source/core/layout/paintfrm.cxx @@ -120,6 +120,10 @@ #include <vcl/GraphicLoader.hxx> #include <basegfx/polygon/b2dpolygontools.hxx> +#include <svl/style.hxx> +#include <ndtxt.hxx> +#include <vcl/hatch.hxx> + using namespace ::editeng; using namespace ::com::sun::star; @@ -4332,6 +4336,90 @@ void SwFlyFrame::PaintDecorators() const } } +SwView* SwTextFrame::GetView() +{ + SwWrtShell* pWrtSh = dynamic_cast<SwWrtShell*>(gProp.pSGlobalShell); + + if (!pWrtSh) + return nullptr; + + return &pWrtSh->GetView(); +} + +void SwTextFrame::PaintParagraphStylesHighlighting() const +{ + // Maybe avoid the dynamic_cast and just use GetActiveWrtShell() + // NO! Multiple windows will not dispay the highlighting correctly if GetActiveWrtShell is used. + SwWrtShell* pWrtSh = dynamic_cast<SwWrtShell*>(gProp.pSGlobalShell); + + if (!pWrtSh) + return; + + vcl::RenderContext* pRenderContext = pWrtSh->GetOut(); + if (!pRenderContext) + return; + + StylesHighlighterColorMap& rParaStylesColorMap + = pWrtSh->GetView().GetStylesHighlighterParaColorMap(); + + if (rParaStylesColorMap.empty()) + return; + + // draw styles highlighter + OUString sStyleName = GetTextNodeFirst()->GetTextColl()->GetName(); + if (rParaStylesColorMap.find(sStyleName) != rParaStylesColorMap.end()) + { + SwRect aFrameAreaRect(getFrameArea()); + + if (IsRightToLeft()) + { + aFrameAreaRect.AddRight(75); + aFrameAreaRect.Left(aFrameAreaRect.Right() + 300); + } + else + { + aFrameAreaRect.AddLeft(-375); + aFrameAreaRect.Right(aFrameAreaRect.Left() + 300); + } + + const tools::Rectangle& rRect = aFrameAreaRect.SVRect(); + + vcl::Font aFont(OutputDevice::GetDefaultFont(DefaultFontType::UI_SANS, GetAppLanguage(), + GetDefaultFontFlags::OnlyOne, pRenderContext)); + aFont.SetFontSize(Size(0, 140 * pRenderContext->GetDPIScaleFactor())); + aFont.SetUnderline(FontLineStyle::LINESTYLE_NONE); + aFont.SetTransparent(false); + aFont.SetWeight(WEIGHT_NORMAL); + aFont.SetFamily(FontFamily::FAMILY_MODERN); + aFont.SetColor(COL_BLACK); + + pRenderContext->Push(vcl::PushFlags::ALL); + + pRenderContext->SetFillColor(rParaStylesColorMap[sStyleName].first); + pRenderContext->SetLineColor(rParaStylesColorMap[sStyleName].first); + + pRenderContext->DrawRect(rRect); + + // draw hatch pattern if paragraph has direct formatting + if (SwDoc::HasParagraphDirectFormatting(SwPosition(*GetTextNodeForParaProps()))) + { + Color aHatchColor(rParaStylesColorMap[sStyleName].first); + // make hatch line color 41% darker than the fill color + aHatchColor.ApplyTintOrShade(-4100); + Hatch aHatch(HatchStyle::Single, aHatchColor, 50, 450_deg10); + pRenderContext->DrawHatch(tools::PolyPolygon(rRect), aHatch); + } + + pRenderContext->SetFont(aFont); + pRenderContext->SetLayoutMode(vcl::text::ComplexTextLayoutFlags::Default); + pRenderContext->SetTextFillColor(rParaStylesColorMap[sStyleName].first); + pRenderContext->DrawText(rRect, OUString::number(rParaStylesColorMap[sStyleName].second), + DrawTextFlags::Center | DrawTextFlags::VCenter); + + pRenderContext->Pop(); + } +} + void SwTextFrame::PaintOutlineContentVisibilityButton() const { SwWrtShell* pWrtSh = dynamic_cast<SwWrtShell*>(gProp.pSGlobalShell); @@ -4339,7 +4427,6 @@ void SwTextFrame::PaintOutlineContentVisibilityButton() const UpdateOutlineContentVisibilityButton(pWrtSh); } - void SwTabFrame::PaintSwFrame(vcl::RenderContext& rRenderContext, SwRect const& rRect, SwPrintData const*const) const { const SwViewOption* pViewOption = gProp.pSGlobalShell->GetViewOptions(); diff --git a/sw/source/core/text/frmpaint.cxx b/sw/source/core/text/frmpaint.cxx index 74ff8c968e07..b187db7ac0b1 100644 --- a/sw/source/core/text/frmpaint.cxx +++ b/sw/source/core/text/frmpaint.cxx @@ -501,6 +501,8 @@ SwRect SwTextFrame::GetPaintSwRect() bool SwTextFrame::PaintEmpty( const SwRect &rRect, bool bCheck ) const { + PaintParagraphStylesHighlighting(); + SwViewShell *pSh = getRootFrame()->GetCurrShell(); if( pSh && ( pSh->GetViewOptions()->IsParagraph() || bInitFont ) ) { @@ -793,6 +795,8 @@ void SwTextFrame::PaintSwFrame(vcl::RenderContext& rRenderContext, SwRect const& rRepaint.Clear(); } + PaintParagraphStylesHighlighting(); + const_cast<SwRect&>(rRect) = aOldRect; OSL_ENSURE( ! IsSwapped(), "A frame is swapped after Paint" ); diff --git a/sw/source/core/text/inftxt.cxx b/sw/source/core/text/inftxt.cxx index a0032082dd95..895d2aba2dd7 100644 --- a/sw/source/core/text/inftxt.cxx +++ b/sw/source/core/text/inftxt.cxx @@ -67,6 +67,16 @@ #include <i18nlangtag/mslangid.hxx> #include <formatlinebreak.hxx> +#include <view.hxx> +#include <wrtsh.hxx> +#include <com/sun/star/text/XTextRange.hpp> +#include <unotextrange.hxx> +#include <SwStyleNameMapper.hxx> +#include <unoprnms.hxx> +#include <editeng/unoprnms.hxx> +#include <unomap.hxx> +#include <com/sun/star/awt/FontSlant.hpp> + using namespace ::com::sun::star; using namespace ::com::sun::star::linguistic2; using namespace ::com::sun::star::uno; @@ -1305,6 +1315,173 @@ void SwTextPaintInfo::DrawBorder( const SwLinePortion &rPor ) const } } +namespace { + +bool HasValidPropertyValue(const uno::Any& rAny) +{ + if (bool bValue; rAny >>= bValue) + { + return true; + } + else if (OUString aValue; (rAny >>= aValue) && !(aValue.isEmpty())) + { + return true; + } + else if (awt::FontSlant eValue; rAny >>= eValue) + { + return true; + } + else if (tools::Long nValueLong; rAny >>= nValueLong) + { + return true; + } + else if (double fValue; rAny >>= fValue) + { + return true; + } + else if (short nValueShort; rAny >>= nValueShort) + { + return true; + } + else + return false; +} +} + +void SwTextPaintInfo::DrawCSDFHighlighting(const SwLinePortion &rPor) const +{ + // Don't use GetActiveView() as it does not work as expected when there are multiple open + // documents. + SwView* pView = SwTextFrame::GetView(); + if (!pView) + return; + + StylesHighlighterColorMap& rCharStylesColorMap = pView->GetStylesHighlighterCharColorMap(); + + if (rCharStylesColorMap.empty() && !pView->IsHighlightCharDF()) + return; + + SwRect aRect; + CalcRect(rPor, &aRect, nullptr, true); + if(!aRect.HasArea()) + return; + + SwTextFrame* pFrame = const_cast<SwTextFrame*>(GetTextFrame()); + if (!pFrame) + return; + + SwPosition aPosition(pFrame->MapViewToModelPos(GetIdx())); + SwPosition aMarkPosition(pFrame->MapViewToModelPos(GetIdx() + GetLen())); + + uno::Reference<text::XTextRange> xRange( + SwXTextRange::CreateXTextRange(pFrame->GetDoc(), aPosition, &aMarkPosition)); + uno::Reference<beans::XPropertySet> xPropertiesSet(xRange, uno::UNO_QUERY_THROW); + + OUString sCurrentCharStyle; + xPropertiesSet->getPropertyValue("CharStyleName") >>= sCurrentCharStyle; + + std::optional<OUString> sCSNumberOrDF; // CS number or "df" or not used + std::optional<Color> aFillColor; + + // check for CS formatting, if not CS formatted check for direct character formatting + if (!sCurrentCharStyle.isEmpty()) + { + if (!rCharStylesColorMap.empty()) + { + OUString sCharStyleDisplayName; + sCharStyleDisplayName = SwStyleNameMapper::GetUIName(sCurrentCharStyle, + SwGetPoolIdFromName::ChrFmt); + if (!sCharStyleDisplayName.isEmpty() + && rCharStylesColorMap.find(sCharStyleDisplayName) + != rCharStylesColorMap.end()) + { + aFillColor = rCharStylesColorMap[sCharStyleDisplayName].first; + sCSNumberOrDF = OUString::number(rCharStylesColorMap[sCharStyleDisplayName].second); + } + } + } + // not character style formatted + else if (pView->IsHighlightCharDF()) + { + const std::vector<OUString> aHiddenProperties{ UNO_NAME_RSID, + UNO_NAME_PARA_IS_NUMBERING_RESTART, + UNO_NAME_PARA_STYLE_NAME, + UNO_NAME_PARA_CONDITIONAL_STYLE_NAME, + UNO_NAME_PAGE_STYLE_NAME, + UNO_NAME_NUMBERING_START_VALUE, + UNO_NAME_NUMBERING_IS_NUMBER, + UNO_NAME_PARA_CONTINUEING_PREVIOUS_SUB_TREE, + UNO_NAME_CHAR_STYLE_NAME, + UNO_NAME_NUMBERING_LEVEL, + UNO_NAME_SORTED_TEXT_ID, + UNO_NAME_PARRSID, + UNO_NAME_CHAR_COLOR_THEME, + UNO_NAME_CHAR_COLOR_TINT_OR_SHADE }; + + SfxItemPropertySet const& rPropSet( + *aSwMapProvider.GetPropertySet(PROPERTY_MAP_CHAR_AUTO_STYLE)); + SfxItemPropertyMap const& rMap(rPropSet.getPropertyMap()); + + + uno::Reference<beans::XPropertyState> xPropertiesState(xRange, uno::UNO_QUERY_THROW); + const uno::Sequence<beans::Property> aProperties + = xPropertiesSet->getPropertySetInfo()->getProperties(); + + for (const beans::Property& rProperty : aProperties) + { + const OUString& rPropName = rProperty.Name; + + if (!rMap.hasPropertyByName(rPropName)) + continue; + + if (std::find(aHiddenProperties.begin(), aHiddenProperties.end(), rPropName) + != aHiddenProperties.end()) + continue; + + if (xPropertiesState->getPropertyState(rPropName) == beans::PropertyState_DIRECT_VALUE) + { + const uno::Any aAny = xPropertiesSet->getPropertyValue(rPropName); + if (HasValidPropertyValue(aAny)) + { + sCSNumberOrDF = SwResId(STR_CHARACTER_DIRECT_FORMATTING_TAG); + aFillColor = COL_LIGHTGRAY; + break; + } + } + } + } + if (sCSNumberOrDF) + { + OutputDevice* pTmpOut = const_cast<OutputDevice*>(GetOut()); + pTmpOut->Push(vcl::PushFlags::LINECOLOR | vcl::PushFlags::FILLCOLOR + | vcl::PushFlags::TEXTLAYOUTMODE | vcl::PushFlags::FONT); + + // draw a filled rectangle at the formatted CS or DF text + pTmpOut->SetFillColor(aFillColor.value()); + pTmpOut->SetLineColor(aFillColor.value()); + tools::Rectangle aSVRect(aRect.SVRect()); + pTmpOut->DrawRect(aSVRect); + + // calculate size and position for the CS number or "df" text and rectangle + tools::Long nWidth = pTmpOut->GetTextWidth(sCSNumberOrDF.value()); + tools::Long nHeight = pTmpOut->GetTextHeight(); + aSVRect.SetSize(Size(nWidth, nHeight)); + aSVRect.Move(-(nWidth / 1.5), -(nHeight / 1.5)); + + vcl::Font aFont(pTmpOut->GetFont()); + aFont.SetOrientation(Degree10(0)); + pTmpOut->SetFont(aFont); + + pTmpOut->SetLayoutMode(vcl::text::ComplexTextLayoutFlags::TextOriginLeft); + //pTmpOut->SetLayoutMode(vcl::text::ComplexTextLayoutFlags::BiDiStrong); + + pTmpOut->SetTextFillColor(aFillColor.value()); + pTmpOut->DrawText(aSVRect, sCSNumberOrDF.value(), DrawTextFlags::NONE); + + pTmpOut->Pop(); + } +} + void SwTextPaintInfo::DrawViewOpt( const SwLinePortion &rPor, PortionType nWhich, const Color *pColor ) const { diff --git a/sw/source/core/text/inftxt.hxx b/sw/source/core/text/inftxt.hxx index 8011b29b442a..62cca26ac08f 100644 --- a/sw/source/core/text/inftxt.hxx +++ b/sw/source/core/text/inftxt.hxx @@ -416,6 +416,8 @@ public: void DrawCheckBox(const SwFieldFormCheckboxPortion &rPor, bool bChecked) const; + void DrawCSDFHighlighting(const SwLinePortion &rPor) const; + /** * Calculate the rectangular area where the portion takes place. * @param[in] rPor portion for which the method specify the painting area diff --git a/sw/source/core/text/porexp.cxx b/sw/source/core/text/porexp.cxx index 9251d9f84171..de435df5ae54 100644 --- a/sw/source/core/text/porexp.cxx +++ b/sw/source/core/text/porexp.cxx @@ -74,12 +74,15 @@ bool SwExpandPortion::Format( SwTextFormatInfo &rInf ) void SwExpandPortion::Paint( const SwTextPaintInfo &rInf ) const { + rInf.DrawCSDFHighlighting(*this); // here it detects as CS and not DF + SwTextSlot aDiffText( &rInf, this, true, true ); const SwFont aOldFont = *rInf.GetFont(); if( GetJoinBorderWithPrev() ) const_cast<SwTextPaintInfo&>(rInf).GetFont()->SetLeftBorder(nullptr); if( GetJoinBorderWithNext() ) const_cast<SwTextPaintInfo&>(rInf).GetFont()->SetRightBorder(nullptr); +// rInf.DrawCSDFHighlighting(*this); // here it detects as DF and only the '/' is detected as CS rInf.DrawBackBrush( *this ); rInf.DrawBorder( *this ); diff --git a/sw/source/core/text/portxt.cxx b/sw/source/core/text/portxt.cxx index 778a319d2470..ebd281c607cf 100644 --- a/sw/source/core/text/portxt.cxx +++ b/sw/source/core/text/portxt.cxx @@ -549,6 +549,8 @@ void SwTextPortion::Paint( const SwTextPaintInfo &rInf ) const rInf.DrawBackBrush( *this ); rInf.DrawBorder( *this ); + rInf.DrawCSDFHighlighting(*this); + // do we have to repaint a post it portion? if( rInf.OnWin() && mpNextPortion && !mpNextPortion->Width() ) mpNextPortion->PrePaint( rInf, this ); diff --git a/sw/source/uibase/docvw/edtwin2.cxx b/sw/source/uibase/docvw/edtwin2.cxx index 94febf8b1f72..a98d38cf1e79 100644 --- a/sw/source/uibase/docvw/edtwin2.cxx +++ b/sw/source/uibase/docvw/edtwin2.cxx @@ -54,6 +54,205 @@ #include <comphelper/lok.hxx> #include <authfld.hxx> +#include <com/sun/star/text/XTextRange.hpp> +#include <unotextrange.hxx> +#include <SwStyleNameMapper.hxx> +#include <unoprnms.hxx> +#include <editeng/unoprnms.hxx> +#include <rootfrm.hxx> +#include <unomap.hxx> +#include <com/sun/star/style/XStyleFamiliesSupplier.hpp> + +namespace { + +bool HasValidPropertyValue(const uno::Any& rAny) +{ + if (bool bValue; rAny >>= bValue) + { + return true; + } + else if (OUString aValue; (rAny >>= aValue) && !(aValue.isEmpty())) + { + return true; + } + else if (awt::FontSlant eValue; rAny >>= eValue) + { + return true; + } + else if (tools::Long nValueLong; rAny >>= nValueLong) + { + return true; + } + else if (double fValue; rAny >>= fValue) + { + return true; + } + else if (short nValueShort; rAny >>= nValueShort) + { + return true; + } + else + return false; +} + +bool PSCSDFPropsQuickHelp(const HelpEvent &rEvt, SwWrtShell& rSh) +{ + OUString sText; + SwView& rView = rSh.GetView(); + + if (rView.IsHighlightCharDF() || rView.GetStylesHighlighterParaColorMap().size() + || rView.GetStylesHighlighterCharColorMap().size()) + { + SwPosition aPos(rSh.GetDoc()->GetNodes()); + Point aPt(rSh.GetWin()->PixelToLogic( + rSh.GetWin()->ScreenToOutputPixel(rEvt.GetMousePosPixel()))); + + rSh.GetLayout()->GetModelPositionForViewPoint(&aPos, aPt); + + if (!aPos.GetContentNode()->IsTextNode()) + return false; + + uno::Reference<text::XTextRange> xRange( + SwXTextRange::CreateXTextRange(*(rView.GetDocShell()->GetDoc()), + aPos, &aPos)); + uno::Reference<beans::XPropertySet> xPropertySet(xRange, uno::UNO_QUERY_THROW); + + SwContentFrame* pContentFrame = aPos.GetContentNode()->GetTextNode()->getLayoutFrame( + rSh.GetLayout()); + + SwRect aFrameAreaRect; + + bool bContainsPt = false; + do + { + aFrameAreaRect = pContentFrame->getFrameArea(); + if (aFrameAreaRect.Contains(aPt)) + { + bContainsPt = true; + break; + } + } while((pContentFrame = pContentFrame->GetFollow())); + + if (bContainsPt) + { + if (rView.GetStylesHighlighterCharColorMap().size()) + { + // check if in CS formatting highlighted area + OUString sCharStyle; + xPropertySet->getPropertyValue("CharStyleName") >>= sCharStyle; + if (!sCharStyle.isEmpty()) + sText = SwStyleNameMapper::GetUIName(sCharStyle, SwGetPoolIdFromName::ChrFmt); + } + + if (sText.isEmpty() && rView.IsHighlightCharDF()) + { + // check if in direct formatting highlighted area + const std::vector<OUString> aHiddenProperties{ UNO_NAME_RSID, + UNO_NAME_PARA_IS_NUMBERING_RESTART, + UNO_NAME_PARA_STYLE_NAME, + UNO_NAME_PARA_CONDITIONAL_STYLE_NAME, + UNO_NAME_PAGE_STYLE_NAME, + UNO_NAME_NUMBERING_START_VALUE, + UNO_NAME_NUMBERING_IS_NUMBER, + UNO_NAME_PARA_CONTINUEING_PREVIOUS_SUB_TREE, + UNO_NAME_CHAR_STYLE_NAME, + UNO_NAME_NUMBERING_LEVEL, + UNO_NAME_SORTED_TEXT_ID, + UNO_NAME_PARRSID, + UNO_NAME_CHAR_COLOR_THEME, + UNO_NAME_CHAR_COLOR_TINT_OR_SHADE }; + + SfxItemPropertySet const& rPropSet( + *aSwMapProvider.GetPropertySet(PROPERTY_MAP_CHAR_AUTO_STYLE)); + SfxItemPropertyMap const& rMap(rPropSet.getPropertyMap()); + + uno::Reference<beans::XPropertyState> xPropertiesState(xRange, uno::UNO_QUERY_THROW); + const uno::Sequence<beans::Property> aProperties + = xPropertySet->getPropertySetInfo()->getProperties(); + + for (const beans::Property& rProperty : aProperties) + { + const OUString& rPropName = rProperty.Name; + + if (!rMap.hasPropertyByName(rPropName)) + continue; + + if (std::find(aHiddenProperties.begin(), aHiddenProperties.end(), rPropName) + != aHiddenProperties.end()) + continue; + + if (xPropertiesState->getPropertyState(rPropName) + == beans::PropertyState_DIRECT_VALUE) + { + const uno::Any aAny = xPropertySet->getPropertyValue(rPropName); + if (HasValidPropertyValue(aAny)) + { + sText = SwResId(STR_CHARACTER_DIRECT_FORMATTING); + break; + } + } + } + } + } + else if (rView.GetStylesHighlighterParaColorMap().size()) + { + // check if in paragraph style formatting highlighted area + pContentFrame = aPos.GetContentNode()->GetTextNode()->getLayoutFrame( + rSh.GetLayout()); + do + { + aFrameAreaRect = pContentFrame->getFrameArea(); + if (pContentFrame->IsRightToLeft()) + { + aFrameAreaRect.AddRight(375); + aFrameAreaRect.Left(aFrameAreaRect.Right() - 300); + } + else + { + aFrameAreaRect.AddLeft(-375); + aFrameAreaRect.Right(aFrameAreaRect.Left() + 300); + } + if (aFrameAreaRect.Contains(aPt)) + { + OUString sParaStyle; + xPropertySet->getPropertyValue("ParaStyleName") >>= sParaStyle; + sText = SwStyleNameMapper::GetUIName(sParaStyle, SwGetPoolIdFromName::TxtColl); + // check for paragraph direct formatting + if (SwDoc::HasParagraphDirectFormatting(aPos)) + sText = sText + " + " + SwResId(STR_PARAGRAPH_DIRECT_FORMATTING); + break; + } + } while((pContentFrame = pContentFrame->GetFollow())); + } + } + + if (!sText.isEmpty()) + { + tools::Rectangle aRect(rSh.GetWin()->PixelToLogic( + rSh.GetWin()->ScreenToOutputPixel(rEvt.GetMousePosPixel())), + Size(1, 1)); + Point aPt(rSh.GetWin()->OutputToScreenPixel(rSh.GetWin()->LogicToPixel(aRect.TopLeft()))); + aRect.SetLeft(aPt.X()); + aRect.SetTop(aPt.Y()); + aPt = rSh.GetWin()->OutputToScreenPixel(rSh.GetWin()->LogicToPixel(aRect.BottomRight())); + aRect.SetRight(aPt.X()); + aRect.SetBottom(aPt.Y()); + + // tdf#136336 ensure tooltip area surrounds the current mouse position with at least a pixel margin + aRect.Union(tools::Rectangle(rEvt.GetMousePosPixel(), Size(1, 1))); + aRect.AdjustLeft(-1); + aRect.AdjustRight(1); + aRect.AdjustTop(-1); + aRect.AdjustBottom(1); + + QuickHelpFlags nStyle = QuickHelpFlags::NONE; //TipStyleBalloon; + Help::ShowQuickHelp(rSh.GetWin(), aRect, sText, nStyle); + } + + return !sText.isEmpty(); +} +} + static OUString lcl_GetRedlineHelp( const SwRangeRedline& rRedl, bool bBalloon, bool bTableChange ) { TranslateId pResId; @@ -108,6 +307,10 @@ OUString SwEditWin::ClipLongToolTip(const OUString& rText) void SwEditWin::RequestHelp(const HelpEvent &rEvt) { SwWrtShell &rSh = m_rView.GetWrtShell(); + + if (PSCSDFPropsQuickHelp(rEvt, rSh)) + return; + bool bQuickBalloon = bool(rEvt.GetMode() & ( HelpEventMode::QUICK | HelpEventMode::BALLOON )); if(bQuickBalloon && !rSh.GetViewOptions()->IsShowContentTips()) return; diff --git a/sw/source/uibase/uiview/view0.cxx b/sw/source/uibase/uiview/view0.cxx index ba555570044e..0a620a0a05e5 100644 --- a/sw/source/uibase/uiview/view0.cxx +++ b/sw/source/uibase/uiview/view0.cxx @@ -225,7 +225,7 @@ void SwView::StateViewOptions(SfxItemSet &rSet) while(nWhich) { bool bReadonly = GetDocShell()->IsReadOnly(); - if ( bReadonly && nWhich != FN_VIEW_GRAPHIC ) + if (bReadonly && nWhich != FN_VIEW_GRAPHIC && nWhich != FN_HIGHLIGHT_CHAR_DF) { rSet.DisableItem(nWhich); nWhich = 0; @@ -359,6 +359,9 @@ void SwView::StateViewOptions(SfxItemSet &rSet) case FN_SHOW_CHANGES_IN_MARGIN: aBool.SetValue( pOpt->IsShowChangesInMargin() ); break; + case FN_HIGHLIGHT_CHAR_DF: + aBool.SetValue(m_bIsHighlightCharDF); + break; } if( nWhich ) @@ -549,6 +552,12 @@ void SwView::ExecViewOptions(SfxRequest &rReq) lcl_SetViewMarks( *pOpt, bFlag ); break; + case FN_HIGHLIGHT_CHAR_DF: + if (STATE_TOGGLE == eState) + bFlag = !m_bIsHighlightCharDF; + m_bIsHighlightCharDF = bFlag; + break; + case FN_VIEW_META_CHARS: if( STATE_TOGGLE == eState ) bFlag = !pOpt->IsViewMetaChars(); |