/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include StyleStatusListener::StyleStatusListener( StylesPreviewWindow_Base* pPreviewControl, const css::uno::Reference& xDispatchProvider) : SfxStatusListener(xDispatchProvider, SID_STYLE_FAMILY2, ".uno:ParaStyle") , m_pPreviewControl(pPreviewControl) { ReBind(); } void StyleStatusListener::StateChangedAtStatusListener(SfxItemState /*eState*/, const SfxPoolItem* pState) { const SfxTemplateItem* pStateItem = dynamic_cast(pState); if (pStateItem) { if (pStateItem->GetStyleIdentifier().isEmpty()) m_pPreviewControl->Select(pStateItem->GetStyleName()); else m_pPreviewControl->Select(pStateItem->GetStyleIdentifier()); } } StylePoolChangeListener::StylePoolChangeListener(StylesPreviewWindow_Base* pPreviewControl) : m_pPreviewControl(pPreviewControl) { SfxObjectShell* pDocShell = SfxObjectShell::Current(); m_pStyleSheetPool = pDocShell ? pDocShell->GetStyleSheetPool() : nullptr; if (m_pStyleSheetPool) { StartListening(*m_pStyleSheetPool); } } StylePoolChangeListener::~StylePoolChangeListener() { if (m_pStyleSheetPool) EndListening(*m_pStyleSheetPool); } void StylePoolChangeListener::Notify(SfxBroadcaster& /*rBC*/, const SfxHint& /*rHint*/) { m_pPreviewControl->RequestStylesListUpdate(); } StyleItemController::StyleItemController(const std::pair& aStyleName) : m_eStyleFamily(SfxStyleFamily::Para) , m_aStyleName(aStyleName) { } void StyleItemController::Paint(vcl::RenderContext& rRenderContext) { rRenderContext.Push(vcl::PushFlags::FILLCOLOR | vcl::PushFlags::FONT | vcl::PushFlags::TEXTCOLOR); DrawEntry(rRenderContext); rRenderContext.Pop(); } bool StylesPreviewWindow_Base::Command(const CommandEvent& rEvent) { if (rEvent.GetCommand() != CommandEventId::ContextMenu) return false; std::unique_ptr xBuilder( Application::CreateBuilder(m_xStylesView.get(), "svx/ui/stylemenu.ui")); std::unique_ptr xMenu(xBuilder->weld_menu("menu")); OString rIdent = xMenu->popup_at_rect(m_xStylesView.get(), tools::Rectangle(rEvent.GetMousePosPixel(), Size(1, 1))); if (rIdent == "update" || rIdent == "edit") { css::uno::Sequence aArgs(0); SfxToolBoxControl::Dispatch(m_xDispatchProvider, rIdent == "update" ? OUString(".uno:StyleUpdateByExample") : OUString(".uno:EditStyle"), aArgs); return true; } return false; } static Color GetTextColorFromItemSet(std::optional const& pItemSet) { const SfxPoolItem* pItem = pItemSet->GetItem(SID_ATTR_CHAR_COLOR); if (pItem) return static_cast(pItem)->GetValue(); return COL_AUTO; } static Color GetHighlightColorFromItemSet(std::optional const& pItemSet) { const SfxPoolItem* pItem = pItemSet->GetItem(SID_ATTR_BRUSH_CHAR); if (pItem) return static_cast(pItem)->GetColor(); return COL_AUTO; } static Color GetBackgroundColorFromItemSet(std::optional const& pItemSet) { const SfxPoolItem* pItem = pItemSet->GetItem(XATTR_FILLCOLOR); if (pItem) return static_cast(pItem)->GetColorValue(); return COL_AUTO; } static css::drawing::FillStyle GetFillStyleFromItemSet(std::optional const& pItemSet) { const SfxPoolItem* pItem = pItemSet->GetItem(XATTR_FILLSTYLE); if (pItem) return static_cast(pItem)->GetValue(); return css::drawing::FillStyle_NONE; } static SvxFont GetFontFromItems(const SvxFontItem* pFontItem, Size aPixelFontSize, std::optional const& pItemSet) { SvxFont aFont; aFont.SetFamilyName(pFontItem->GetFamilyName()); aFont.SetStyleName(pFontItem->GetStyleName()); aFont.SetFontSize(aPixelFontSize); const SfxPoolItem* pItem = pItemSet->GetItem(SID_ATTR_CHAR_WEIGHT); if (pItem) aFont.SetWeight(static_cast(pItem)->GetWeight()); pItem = pItemSet->GetItem(SID_ATTR_CHAR_POSTURE); if (pItem) aFont.SetItalic(static_cast(pItem)->GetPosture()); pItem = pItemSet->GetItem(SID_ATTR_CHAR_CONTOUR); if (pItem) aFont.SetOutline(static_cast(pItem)->GetValue()); pItem = pItemSet->GetItem(SID_ATTR_CHAR_SHADOWED); if (pItem) aFont.SetShadow(static_cast(pItem)->GetValue()); pItem = pItemSet->GetItem(SID_ATTR_CHAR_RELIEF); if (pItem) aFont.SetRelief(static_cast(pItem)->GetValue()); pItem = pItemSet->GetItem(SID_ATTR_CHAR_UNDERLINE); if (pItem) aFont.SetUnderline(static_cast(pItem)->GetLineStyle()); pItem = pItemSet->GetItem(SID_ATTR_CHAR_OVERLINE); if (pItem) aFont.SetOverline(static_cast(pItem)->GetValue()); pItem = pItemSet->GetItem(SID_ATTR_CHAR_STRIKEOUT); if (pItem) aFont.SetStrikeout(static_cast(pItem)->GetStrikeout()); pItem = pItemSet->GetItem(SID_ATTR_CHAR_CASEMAP); if (pItem) aFont.SetCaseMap(static_cast(pItem)->GetCaseMap()); pItem = pItemSet->GetItem(SID_ATTR_CHAR_EMPHASISMARK); if (pItem) aFont.SetEmphasisMark(static_cast(pItem)->GetEmphasisMark()); return aFont; } void StyleItemController::DrawEntry(vcl::RenderContext& rRenderContext) { SfxObjectShell* pShell = SfxObjectShell::Current(); if (!pShell) return; SfxStyleSheetBasePool* pPool = pShell->GetStyleSheetPool(); SfxStyleSheetBase* pStyle = nullptr; if (!pPool) return; pStyle = pPool->First(m_eStyleFamily); while (pStyle && pStyle->GetName() != m_aStyleName.first && pStyle->GetName() != m_aStyleName.second) pStyle = pPool->Next(); if (!pStyle) return; Size aSize(rRenderContext.GetOutputSizePixel()); tools::Rectangle aFullRect(Point(0, 0), aSize); tools::Rectangle aContentRect(aFullRect); Color aOriginalColor = rRenderContext.GetFillColor(); Color aOriginalLineColor = rRenderContext.GetLineColor(); DrawContentBackground(rRenderContext, aContentRect, aOriginalColor); std::optional const pItemSet(pStyle->GetItemSetForPreview()); if (!pItemSet) return; Color aFontHighlight = COL_AUTO; sal_Int16 nScriptType = MsLangId::getScriptType(Application::GetSettings().GetUILanguageTag().getLanguageType()); sal_uInt16 nFontSlot = SID_ATTR_CHAR_FONT; if (nScriptType == css::i18n::ScriptType::ASIAN) nFontSlot = SID_ATTR_CHAR_CJK_FONT; else if (nScriptType == css::i18n::ScriptType::COMPLEX) nFontSlot = SID_ATTR_CHAR_CTL_FONT; const SvxFontItem* const pFontItem = pItemSet->GetItem(nFontSlot); const SvxFontHeightItem* const pFontHeightItem = pItemSet->GetItem(SID_ATTR_CHAR_FONTHEIGHT); if (pFontItem && pFontHeightItem) { Size aFontSize(0, pFontHeightItem->GetHeight()); Size aPixelSize(rRenderContext.LogicToPixel(aFontSize, MapMode(pShell->GetMapUnit()))); SvxFont aFont = GetFontFromItems(pFontItem, aPixelSize, pItemSet); rRenderContext.SetFont(aFont); Color aFontCol = GetTextColorFromItemSet(pItemSet); if (aFontCol != COL_AUTO) rRenderContext.SetTextColor(aFontCol); aFontHighlight = GetHighlightColorFromItemSet(pItemSet); css::drawing::FillStyle style = GetFillStyleFromItemSet(pItemSet); switch (style) { case css::drawing::FillStyle_SOLID: { Color aBackCol = GetBackgroundColorFromItemSet(pItemSet); if (aBackCol != COL_AUTO) DrawContentBackground(rRenderContext, aContentRect, aBackCol); } break; default: break; //TODO Draw the other background styles: gradient, hatching and bitmap } } if (aFontHighlight != COL_AUTO) DrawHighlight(rRenderContext, aFontHighlight); DrawText(rRenderContext); rRenderContext.SetFillColor(aOriginalColor); rRenderContext.SetLineColor(aOriginalLineColor); } void StyleItemController::DrawContentBackground(vcl::RenderContext& rRenderContext, const tools::Rectangle& aContentRect, const Color& aColor) { rRenderContext.SetLineColor(aColor); rRenderContext.SetFillColor(aColor); rRenderContext.DrawRect(aContentRect); } void StyleItemController::DrawHighlight(vcl::RenderContext& rRenderContext, Color aFontBack) { tools::Rectangle aTextRect; rRenderContext.GetTextBoundRect(aTextRect, m_aStyleName.second); Size aSize = aTextRect.GetSize(); aSize.AdjustHeight(aSize.getHeight()); aTextRect.SetSize(aSize); Point aPos(0, 0); aPos.AdjustX(LEFT_MARGIN); aPos.AdjustY((rRenderContext.GetOutputHeightPixel() - aTextRect.Bottom()) / 2); aTextRect.SetPos(aPos); rRenderContext.SetLineColor(aFontBack); rRenderContext.SetFillColor(aFontBack); rRenderContext.DrawRect(aTextRect); } void StyleItemController::DrawText(vcl::RenderContext& rRenderContext) { const SalLayoutGlyphs* layoutGlyphs = SalLayoutGlyphsCache::self()->GetLayoutGlyphs(&rRenderContext, m_aStyleName.second); tools::Rectangle aTextRect; rRenderContext.GetTextBoundRect(aTextRect, m_aStyleName.second, 0, 0, -1, 0, {}, layoutGlyphs); Point aPos(0, 0); aPos.AdjustX(LEFT_MARGIN); aPos.AdjustY((rRenderContext.GetOutputHeightPixel() - aTextRect.Bottom()) / 2); rRenderContext.DrawText(aPos, m_aStyleName.second, 0, -1, nullptr, nullptr, layoutGlyphs); } StylesPreviewWindow_Base::StylesPreviewWindow_Base( weld::Builder& xBuilder, std::vector>&& aDefaultStyles, const css::uno::Reference& xDispatchProvider) : m_xDispatchProvider(xDispatchProvider) , m_xStylesView(xBuilder.weld_icon_view("stylesview")) , m_aUpdateTask(*this) , m_aDefaultStyles(std::move(aDefaultStyles)) { m_xStylesView->connect_selection_changed(LINK(this, StylesPreviewWindow_Base, Selected)); m_xStylesView->connect_item_activated(LINK(this, StylesPreviewWindow_Base, DoubleClick)); m_xStylesView->connect_command(LINK(this, StylesPreviewWindow_Base, DoCommand)); m_xStatusListener = new StyleStatusListener(this, xDispatchProvider); m_pStylePoolChangeListener.reset(new StylePoolChangeListener(this)); RequestStylesListUpdate(); } IMPL_LINK(StylesPreviewWindow_Base, Selected, weld::IconView&, rIconView, void) { OUString sStyleName = rIconView.get_selected_text(); css::uno::Sequence aArgs{ comphelper::makePropertyValue("Template", sStyleName), comphelper::makePropertyValue("Family", sal_Int16(SfxStyleFamily::Para)) }; SfxToolBoxControl::Dispatch(m_xDispatchProvider, ".uno:StyleApply", aArgs); } IMPL_LINK(StylesPreviewWindow_Base, DoubleClick, weld::IconView&, rIconView, bool) { OUString sStyleName = rIconView.get_selected_text(); css::uno::Sequence aArgs{ comphelper::makePropertyValue("Param", sStyleName), comphelper::makePropertyValue("Family", sal_Int16(SfxStyleFamily::Para)) }; SfxToolBoxControl::Dispatch(m_xDispatchProvider, ".uno:EditStyle", aArgs); return true; } IMPL_LINK(StylesPreviewWindow_Base, DoCommand, const CommandEvent&, rPos, bool) { return Command(rPos); } StylesPreviewWindow_Base::~StylesPreviewWindow_Base() { m_xStatusListener->UnBind(); m_aUpdateTask.Stop(); try { m_xStatusListener->dispose(); } catch (css::uno::Exception&) { } m_xStatusListener = nullptr; } void StylesPreviewWindow_Base::Select(const OUString& rStyleName) { m_sSelectedStyle = rStyleName; UpdateSelection(); } void StylesPreviewWindow_Base::UpdateSelection() { for (std::vector>::size_type i = 0; i < m_aAllStyles.size(); ++i) { if (m_aAllStyles[i].first == m_sSelectedStyle || m_aAllStyles[i].second == m_sSelectedStyle) { m_xStylesView->select(i); break; } } } void StylesPreviewWindow_Base::RequestStylesListUpdate() { m_aUpdateTask.Start(); } void StylesListUpdateTask::Invoke() { m_rStylesList.UpdateStylesList(); m_rStylesList.UpdateSelection(); } void StylesPreviewWindow_Base::UpdateStylesList() { m_aAllStyles = m_aDefaultStyles; SfxObjectShell* pDocShell = SfxObjectShell::Current(); SfxStyleSheetBasePool* pStyleSheetPool = nullptr; if (pDocShell) pStyleSheetPool = pDocShell->GetStyleSheetPool(); if (pStyleSheetPool) { auto xIter = pStyleSheetPool->CreateIterator(SfxStyleFamily::Para, SfxStyleSearchBits::UserDefined); SfxStyleSheetBase* pStyle = xIter->First(); while (pStyle) { m_aAllStyles.push_back(std::pair("", pStyle->GetName())); pStyle = xIter->Next(); } } m_xStylesView->clear(); for (const auto& rStyle : m_aAllStyles) { ScopedVclPtr pImg = VclPtr::Create(); const Size aSize(100, 30); pImg->SetOutputSizePixel(aSize); StyleItemController aStyleController(rStyle); aStyleController.Paint(*pImg); m_xStylesView->append(rStyle.first, rStyle.second, pImg); } } StylesPreviewWindow_Impl::StylesPreviewWindow_Impl( vcl::Window* pParent, std::vector>&& aDefaultStyles, const css::uno::Reference& xDispatchProvider) : InterimItemWindow(pParent, "svx/ui/stylespreview.ui", "ApplyStyleBox", true, reinterpret_cast(SfxViewShell::Current())) , StylesPreviewWindow_Base(*m_xBuilder, std::move(aDefaultStyles), xDispatchProvider) { SetOptimalSize(); } StylesPreviewWindow_Impl::~StylesPreviewWindow_Impl() { disposeOnce(); } void StylesPreviewWindow_Impl::dispose() { m_xStylesView.reset(); InterimItemWindow::dispose(); } void StylesPreviewWindow_Impl::SetOptimalSize() { SetSizePixel(get_preferred_size()); } /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */