    /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
    /*
     * 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/.
     *
     */

    #include <sal/config.h>

    #include "ThemePanel.hxx"

    #include <swtypes.hxx>
    #include <cmdid.h>

    #include <svl/intitem.hxx>
    #include <svx/svxids.hrc>
    #include <svx/dlgutil.hxx>
    #include <svx/rulritem.hxx>

    #include <sfx2/sidebar/ControlFactory.hxx>
    #include <sfx2/dispatch.hxx>
    #include <sfx2/bindings.hxx>
    #include <sfx2/viewsh.hxx>
    #include <sfx2/objsh.hxx>

    #include <editeng/fontitem.hxx>
    #include <editeng/boxitem.hxx>
    #include <editeng/borderline.hxx>
    #include <charatr.hxx>
    #include <charfmt.hxx>
    #include <docstyle.hxx>
    #include <fmtcol.hxx>
    #include <format.hxx>

    namespace
    {

    class FontSet
    {
    public:
        OUString maName;
        OUString msMonoFont;
        OUString msHeadingFont;
        OUString msBaseFont;
    };

    class ColorVariable
    {
    public:
        long mnIndex;
        sal_Int16 mnTintShade;

        ColorVariable()
            : mnIndex(-1)
            , mnTintShade()
        {}

        ColorVariable(long nIndex, sal_Int16 nTintShade)
            : mnIndex(nIndex)
            , mnTintShade(nTintShade)
        {}
    };

    class StyleRedefinition
    {
        ColorVariable maVariable;

    public:
        OUString maElementName;

    public:
        explicit StyleRedefinition(const OUString& aElementName)
            : maElementName(aElementName)
        {}

        void setColorVariable(ColorVariable aVariable)
        {
            maVariable = aVariable;
        }

        Color getColor(svx::ColorSet const & rColorSet)
        {
            Color aColor;
            if (maVariable.mnIndex > -1)
            {
                aColor = rColorSet.getColor(maVariable.mnIndex);
                aColor.ApplyTintOrShade(maVariable.mnTintShade);
            }
            else
            {
                aColor = COL_BLACK;
            }
            return aColor;
        }
    };

    class StyleSet
    {
        std::vector<StyleRedefinition> maStyles;

    public:
        explicit StyleSet()
            : maStyles()
        {}

        void add(StyleRedefinition const & aRedefinition)
        {
            maStyles.push_back(aRedefinition);
        }

        StyleRedefinition* get(const OUString& aString)
        {
            for (StyleRedefinition & rStyle : maStyles)
            {
                if (rStyle.maElementName == aString)
                {
                    return &rStyle;
                }
            }
            return nullptr;
        }
    };

    StyleSet setupThemes()
    {
        StyleSet aSet;

        {
            StyleRedefinition aRedefinition("Heading 1");
            aRedefinition.setColorVariable(ColorVariable(10, -1000));
            aSet.add(aRedefinition);
        }

        {
            StyleRedefinition aRedefinition("Heading 2");
            aRedefinition.setColorVariable(ColorVariable(7, -500));
            aSet.add(aRedefinition);
        }

        {
            StyleRedefinition aRedefinition("Heading 3");
            aRedefinition.setColorVariable(ColorVariable(5, 0));
            aSet.add(aRedefinition);
        }

        {
            StyleRedefinition aRedefinition("Heading 4");
            aRedefinition.setColorVariable(ColorVariable(6, -1000));
            aSet.add(aRedefinition);
        }

        {
            StyleRedefinition aRedefinition("Heading 5");
            aRedefinition.setColorVariable(ColorVariable(4, -1500));
            aSet.add(aRedefinition);
        }

        {
            StyleRedefinition aRedefinition("Heading 6");
            aRedefinition.setColorVariable(ColorVariable(3, -2500));
            aSet.add(aRedefinition);
        }

        {
            StyleRedefinition aRedefinition("Heading 7");
            aRedefinition.setColorVariable(ColorVariable(3, -2500));
            aSet.add(aRedefinition);
        }

        {
            StyleRedefinition aRedefinition("Heading 8");
            aRedefinition.setColorVariable(ColorVariable(2, 0));
            aSet.add(aRedefinition);
        }

        {
            StyleRedefinition aRedefinition("Heading 9");
            aRedefinition.setColorVariable(ColorVariable(2, 0));
            aSet.add(aRedefinition);
        }

        {
            StyleRedefinition aRedefinition("Heading 10");
            aRedefinition.setColorVariable(ColorVariable(0, 0));
            aSet.add(aRedefinition);
        }

        return aSet;
    }

    void changeFont(SwFormat* pFormat, SwDocStyleSheet const * pStyle, FontSet const & rFontSet)
    {
        bool bChanged = false;

        if (pStyle->GetName() != "Default Style" && pFormat->GetAttrSet().GetItem(RES_CHRATR_FONT, false) == nullptr)
        {
            return;
        }

        SvxFontItem aFontItem(pFormat->GetFont(false));

        FontPitch ePitch = aFontItem.GetPitch();

        if (ePitch == PITCH_FIXED)
        {
            aFontItem.SetFamilyName(rFontSet.msMonoFont);
            bChanged = true;
        }
        else
        {
            if (pStyle->GetName() == "Heading")
            {
                aFontItem.SetFamilyName(rFontSet.msHeadingFont);
                bChanged = true;
            }
            else
            {
                aFontItem.SetFamilyName(rFontSet.msBaseFont);
                bChanged = true;
            }
        }

        if (bChanged)
        {
            pFormat->SetFormatAttr(aFontItem);
        }
    }

    /*void changeBorder(SwTextFormatColl* pCollection, SwDocStyleSheet* pStyle, StyleSet& rStyleSet)
    {
        if (pStyle->GetName() == "Heading")
        {
            SvxBoxItem aBoxItem(pCollection->GetBox());
            editeng::SvxBorderLine aBorderLine;
            aBorderLine.SetWidth(40); //20 = 1pt
            aBorderLine.SetColor(rColorSet.mBaseColors[0]);
            aBoxItem.SetLine(&aBorderLine, SvxBoxItemLine::BOTTOM);

            pCollection->SetFormatAttr(aBoxItem);
        }
    }*/

    void changeColor(SwTextFormatColl* pCollection, svx::ColorSet const & rColorSet, StyleRedefinition* pRedefinition)
    {
        Color aColor = pRedefinition->getColor(rColorSet);

        SvxColorItem aColorItem(pCollection->GetColor());
        aColorItem.SetValue(aColor);
        pCollection->SetFormatAttr(aColorItem);
    }

    std::vector<FontSet> initFontSets()
    {
        std::vector<FontSet> aFontSets;
        {
            FontSet aFontSet;
            aFontSet.maName = "Liberation Family";
            aFontSet.msHeadingFont = "Liberation Sans";
            aFontSet.msBaseFont = "Liberation Serif";
            aFontSet.msMonoFont = "Liberation Mono";
            aFontSets.push_back(aFontSet);
        }
        {
            FontSet aFontSet;
            aFontSet.maName = "DejaVu Family";
            aFontSet.msHeadingFont = "DejaVu Sans";
            aFontSet.msBaseFont = "DejaVu Serif";
            aFontSet.msMonoFont = "DejaVu Sans Mono";
            aFontSets.push_back(aFontSet);
        }
        {
            FontSet aFontSet;
            aFontSet.maName = "Croscore Modern";
            aFontSet.msHeadingFont = "Caladea";
            aFontSet.msBaseFont = "Carlito";
            aFontSet.msMonoFont = "Liberation Mono";
            aFontSets.push_back(aFontSet);
        }
        {
            FontSet aFontSet;
            aFontSet.maName = "Carlito";
            aFontSet.msHeadingFont = "Carlito";
            aFontSet.msBaseFont = "Carlito";
            aFontSet.msMonoFont = "Liberation Mono";
            aFontSets.push_back(aFontSet);
        }
        {
            FontSet aFontSet;
            aFontSet.maName = "Source Sans Family";
            aFontSet.msHeadingFont = "Source Sans Pro";
            aFontSet.msBaseFont = "Source Sans Pro";
            aFontSet.msMonoFont = "Source Code Pro";
            aFontSets.push_back(aFontSet);
        }
        {
            FontSet aFontSet;
            aFontSet.maName = "Source Sans Family 2";
            aFontSet.msHeadingFont = "Source Sans Pro";
            aFontSet.msBaseFont = "Source Sans Pro Light";
            aFontSet.msMonoFont = "Source Code Pro";
            aFontSets.push_back(aFontSet);
        }
        {
            FontSet aFontSet;
            aFontSet.maName = "Libertine Family";
            aFontSet.msHeadingFont = "Linux Biolinum G";
            aFontSet.msBaseFont = "Linux Libertine G";
            aFontSet.msMonoFont = "Liberation Mono";
            aFontSets.push_back(aFontSet);
        }
        {
            FontSet aFontSet;
            aFontSet.maName = "Open Sans";
            aFontSet.msHeadingFont = "Open Sans";
            aFontSet.msBaseFont = "Open Sans";
            aFontSet.msMonoFont = "Droid Sans Mono";
            aFontSets.push_back(aFontSet);
        }
        {
            FontSet aFontSet;
            aFontSet.maName = "Droid Sans";
            aFontSet.msHeadingFont = "Droid Sans";
            aFontSet.msBaseFont = "Droid Sans";
            aFontSet.msMonoFont = "Droid Sans Mono";
            aFontSets.push_back(aFontSet);
        }
        return aFontSets;
    }

    FontSet getFontSet(const OUString& rFontVariant, std::vector<FontSet>& aFontSets)
    {
        for (FontSet & rFontSet : aFontSets)
        {
            if (rFontSet.maName == rFontVariant)
                return rFontSet;
        }
        return aFontSets[0];
    }

    void applyTheme(SfxStyleSheetBasePool* pPool, const OUString& sFontSetName, const OUString& sColorSetName,
                    StyleSet& rStyleSet, svx::ColorSets& rColorSets)
    {
        SwDocStyleSheet* pStyle;

        std::vector<FontSet> aFontSets = initFontSets();
        FontSet aFontSet = getFontSet(sFontSetName, aFontSets);

        svx::ColorSet aColorSet = rColorSets.getColorSet(sColorSetName);

        pPool->SetSearchMask(SfxStyleFamily::Para);
        pStyle = static_cast<SwDocStyleSheet*>(pPool->First());

        while (pStyle)
        {
            SwTextFormatColl* pCollection = pStyle->GetCollection();

            changeFont(pCollection, pStyle, aFontSet);

            StyleRedefinition* pRedefinition = rStyleSet.get(pStyle->GetName());

            if (pRedefinition)
            {
                changeColor(pCollection, aColorSet, pRedefinition);
            }

            pStyle = static_cast<SwDocStyleSheet*>(pPool->Next());
        }

        pPool->SetSearchMask(SfxStyleFamily::Char);
        pStyle = static_cast<SwDocStyleSheet*>(pPool->First());

        while (pStyle)
        {
            SwCharFormat* pCharFormat = pStyle->GetCharFormat();

            changeFont(static_cast<SwFormat*>(pCharFormat), pStyle, aFontSet);

            pStyle = static_cast<SwDocStyleSheet*>(pPool->Next());
        }
    }

    BitmapEx GenerateColorPreview(const svx::ColorSet& rColorSet)
    {
        ScopedVclPtrInstance<VirtualDevice> pVirtualDev(*Application::GetDefaultDevice());
        float fScaleFactor = pVirtualDev->GetDPIScaleFactor();
        long BORDER = 2 * fScaleFactor;
        long SIZE = 12 * fScaleFactor;

        Size aSize(BORDER * 7 + SIZE * 6, BORDER * 3 + SIZE * 2);
        pVirtualDev->SetOutputSizePixel(aSize);

        long x = BORDER;
        long y1 = BORDER;
        long y2 = y1 + SIZE + BORDER;

        pVirtualDev->SetLineColor(COL_LIGHTGRAY);

        for (sal_uInt32 i = 0; i < 12; i += 2)
        {
            pVirtualDev->SetFillColor(rColorSet.getColor(i));
            pVirtualDev->DrawRect(tools::Rectangle(x, y1, x + SIZE, y1 + SIZE));

            pVirtualDev->SetFillColor(rColorSet.getColor(i + 1));
            pVirtualDev->DrawRect(tools::Rectangle(x, y2, x + SIZE, y2 + SIZE));

            x += SIZE + BORDER;
        }

        return pVirtualDev->GetBitmapEx(Point(), aSize);
    }

    } // end anonymous namespace

    namespace sw { namespace sidebar {

    VclPtr<vcl::Window> ThemePanel::Create (vcl::Window* pParent,
                                            const css::uno::Reference<css::frame::XFrame>& rxFrame)
    {
        if (pParent == nullptr)
            throw css::lang::IllegalArgumentException("no parent Window given to PagePropertyPanel::Create", nullptr, 0);
        if (!rxFrame.is())
            throw css::lang::IllegalArgumentException("no XFrame given to PagePropertyPanel::Create", nullptr, 1);

        return VclPtr<ThemePanel>::Create(pParent, rxFrame);
    }

    ThemePanel::ThemePanel(vcl::Window* pParent,
                           const css::uno::Reference<css::frame::XFrame>& rxFrame)
        : PanelLayout(pParent, "ThemePanel", "modules/swriter/ui/sidebartheme.ui", rxFrame)
        , maColorSets()
    {
        get(mpListBoxFonts, "listbox_fonts");
        get(mpValueSetColors, "valueset_colors");
        get(mpApplyButton, "apply");

        mpValueSetColors->SetColCount(2);
        mpValueSetColors->SetLineCount(4);

        mpApplyButton->SetClickHdl(LINK(this, ThemePanel, ClickHdl));
        mpListBoxFonts->SetDoubleClickHdl(LINK(this, ThemePanel, DoubleClickHdl));
        mpValueSetColors->SetDoubleClickHdl(LINK(this, ThemePanel, DoubleClickValueSetHdl));

        std::vector<FontSet> aFontSets = initFontSets();
        for (FontSet & rFontSet : aFontSets)
        {
            mpListBoxFonts->InsertEntry(rFontSet.maName);
        }

        maColorSets.init();

        const std::vector<svx::ColorSet>& aColorSets = maColorSets.getColorSets();
        for (size_t i = 0; i < aColorSets.size(); ++i)
        {
            const svx::ColorSet& rColorSet = aColorSets[i];

            const OUString& aName = rColorSet.getName();
            BitmapEx aPreview = GenerateColorPreview(rColorSet);
            mpValueSetColors->InsertItem(i, Image(aPreview), aName);
        }
    }

    ThemePanel::~ThemePanel()
    {
        disposeOnce();
    }

    void ThemePanel::dispose()
    {
        mpListBoxFonts.clear();
        mpValueSetColors.clear();
        mpApplyButton.clear();

        PanelLayout::dispose();
    }

    IMPL_LINK_NOARG(ThemePanel, ClickHdl, Button*, void)
    {
        DoubleClickHdl();
    }
    IMPL_LINK_NOARG(ThemePanel, DoubleClickValueSetHdl, ValueSet*, void)
    {
        DoubleClickHdl();
    }
    IMPL_LINK_NOARG(ThemePanel, DoubleClickHdl, ListBox&, void)
    {
        DoubleClickHdl();
    }
    void ThemePanel::DoubleClickHdl()
    {
        SwDocShell* pDocSh = static_cast<SwDocShell*>(SfxObjectShell::Current());
        if (pDocSh)
        {
            OUString sEntryFonts = mpListBoxFonts->GetSelectedEntry();
            sal_uInt32 nItemId = mpValueSetColors->GetSelectedItemId();
            OUString sEntryColors = maColorSets.getColorSet(nItemId).getName();

            StyleSet aStyleSet = setupThemes();

            applyTheme(pDocSh->GetStyleSheetPool(), sEntryFonts, sEntryColors, aStyleSet, maColorSets);
        }
    }

    void ThemePanel::NotifyItemUpdate(const sal_uInt16 /*nSId*/,
                                             const SfxItemState /*eState*/,
                                             const SfxPoolItem* /*pState*/,
                                             const bool /*bIsEnabled*/)
    {
    }

    }} // end of namespace ::sw::sidebar

    /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

↑ V547 Expression 'bChanged' is always true.