Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  patattr.cxx   Sprache: C

 
/* -*- 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/.
 *
 * 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 <memory>
#include <utility>
#include <scitems.hxx>
#include <editeng/adjustitem.hxx>
#include <editeng/boxitem.hxx>
#include <editeng/lineitem.hxx>
#include <editeng/brushitem.hxx>
#include <editeng/charreliefitem.hxx>
#include <editeng/contouritem.hxx>
#include <svtools/colorcfg.hxx>
#include <editeng/colritem.hxx>
#include <editeng/crossedoutitem.hxx>
#include <editeng/eeitem.hxx>
#include <editeng/emphasismarkitem.hxx>
#include <editeng/fhgtitem.hxx>
#include <editeng/fontitem.hxx>
#include <editeng/forbiddenruleitem.hxx>
#include <editeng/frmdiritem.hxx>
#include <editeng/langitem.hxx>
#include <editeng/postitem.hxx>
#include <svx/rotmodit.hxx>
#include <editeng/scriptspaceitem.hxx>
#include <editeng/shaditem.hxx>
#include <editeng/shdditem.hxx>
#include <editeng/udlnitem.hxx>
#include <editeng/wghtitem.hxx>
#include <editeng/wrlmitem.hxx>
#include <editeng/justifyitem.hxx>
#include <svl/intitem.hxx>
#include <svl/numformat.hxx>
#include <svl/zforlist.hxx>
#include <vcl/outdev.hxx>
#include <tools/fract.hxx>
#include <tools/UnitConversion.hxx>
#include <osl/diagnose.h>

#include <attrib.hxx>
#include <patattr.hxx>
#include <stlsheet.hxx>
#include <stlpool.hxx>
#include <document.hxx>
#include <globstr.hrc>
#include <scresid.hxx>
#include <validat.hxx>
#include <scmod.hxx>
#include <fillinfo.hxx>
#include <comphelper/lok.hxx>
#include <tabvwsh.hxx>

CellAttributeHelper::CellAttributeHelper(SfxItemPool& rSfxItemPool)
: mrSfxItemPool(rSfxItemPool)
, mpDefaultCellAttribute(nullptr)
, maRegisteredCellAttributes()
, mpLastHit(nullptr)
, mnCurrentMaxKey(0)
{
}

CellAttributeHelper::~CellAttributeHelper()
{
    delete mpDefaultCellAttribute;
}

static int CompareStringPtr(const OUString* lhs, const OUString* rhs)
{
    if (lhs == rhs)
        return 0;
    if (lhs && rhs)
        return (*lhs).compareTo(*rhs);
    if (!lhs && rhs)
        return -1;
    return 1;
}

const ScPatternAttr* CellAttributeHelper::registerAndCheck(const ScPatternAttr& rCandidate, bool bPassingOwnership) const
{
    if (&rCandidate == &getDefaultCellAttribute())
        return &rCandidate;

    assert(rCandidate.pCellAttributeHelper == this && "WRONG CellAttributeHelper in ScPatternAttr (!)");

    if (rCandidate.isRegistered())
    {
        assert(!bPassingOwnership && "Trying to register an already registered CellAttribute with ownership change (!)");
        rCandidate.mnRefCount++;
        return &rCandidate;
    }

    if (ScPatternAttr::areSame(mpLastHit, &rCandidate))
    {
        // hit for single-entry cache, make use of it
        mpLastHit->mnRefCount++;
        if (bPassingOwnership)
            delete &rCandidate;
        return mpLastHit;
    }
    const OUString* pCandidateStyleName = rCandidate.GetStyleName();
    auto it = maRegisteredCellAttributes.lower_bound(pCandidateStyleName);
    for (; it != maRegisteredCellAttributes.end(); ++it)
    {
        const ScPatternAttr* pCheck = *it;
        if (CompareStringPtr(pCheck->GetStyleName(), pCandidateStyleName) != 0)
            break;
        if (ScPatternAttr::areSame(pCheck, &rCandidate))
        {
            pCheck->mnRefCount++;
            if (bPassingOwnership)
                delete &rCandidate;
            mpLastHit = pCheck;
            return pCheck;
        }
    }

    const ScPatternAttr* pCandidate(bPassingOwnership ? &rCandidate : new ScPatternAttr(rCandidate));
    pCandidate->mnRefCount++;
    const_cast<ScPatternAttr*>(pCandidate)->SetPAKey(mnCurrentMaxKey++);
    maRegisteredCellAttributes.insert(pCandidate);
    mpLastHit = pCandidate;
    return pCandidate;
}

void CellAttributeHelper::doUnregister(const ScPatternAttr& rCandidate)
{
    if (&rCandidate == mpDefaultCellAttribute)
        return;

    assert(rCandidate.isRegistered());
    rCandidate.mnRefCount--;

    if (0 != rCandidate.mnRefCount)
        return;

    if (mpLastHit == &rCandidate)
        mpLastHit = nullptr;

    assert(maRegisteredCellAttributes.find(&rCandidate) != maRegisteredCellAttributes.end());
    maRegisteredCellAttributes.erase(&rCandidate);
    delete &rCandidate;
}

const ScPatternAttr& CellAttributeHelper::getDefaultCellAttribute() const
{
    // *have* to create on-demand due to mrScDocument.GetPool() *can* be nullptr
    // since mxPoolHelper is *only* created for SCDOCMODE_DOCUMENT and
    // SCDOCMODE_FUNCTIONACCESS (!)
    if (!mpDefaultCellAttribute)
    {
        // GetRscString only works after ScGlobal::Init (indicated by the EmptyBrushItem)
        // TODO: Write additional method ScGlobal::IsInit() or somesuch
        //       or detect whether this is the Secondary Pool for a MessagePool
        if (ScGlobal::GetEmptyBrushItem())
        {
            const OUString aInitialStyle(ScResId(STR_STYLENAME_STANDARD));
            mpDefaultCellAttribute = new ScPatternAttr(
                *const_cast<CellAttributeHelper*>(this),
                nullptr, // no SfxItemSet
                &aInitialStyle);
        }
        else
        {
            mpDefaultCellAttribute = new ScPatternAttr(*const_cast<CellAttributeHelper*>(this));
        }
    }
    return *mpDefaultCellAttribute;
}

void CellAttributeHelper::CellStyleDeleted(const ScStyleSheet& rStyle)
{
    const OUString& rCandidateStyleName = rStyle.GetName();
    auto it = maRegisteredCellAttributes.lower_bound(&rCandidateStyleName);
    for (; it != maRegisteredCellAttributes.end(); ++it)
    {
        const ScPatternAttr* pCheck = *it;
        if (CompareStringPtr(pCheck->GetStyleName(), &rCandidateStyleName) != 0)
            break;
        if (&rStyle == pCheck->GetStyleSheet())
            const_cast<ScPatternAttr*>(pCheck)->StyleToName();
    }
}

void CellAttributeHelper::RenameCellStyle(ScStyleSheet& rStyle, const OUString&&nbsp;rNewName)
{
    std::vector<const ScPatternAttr*> aChanged;

    const OUString& rCandidateStyleName = rStyle.GetName();
    auto it = maRegisteredCellAttributes.lower_bound(&rCandidateStyleName);
    while(it != maRegisteredCellAttributes.end())
    {
        const ScPatternAttr* pCheck = *it;
        if (CompareStringPtr(pCheck->GetStyleName(), &rCandidateStyleName) != 0)
            break;
        if (&rStyle == pCheck->GetStyleSheet())
        {
            aChanged.push_back(pCheck);
            // The name will change, we have to re-insert it
            it = maRegisteredCellAttributes.erase(it);
        }
        else
            ++it;
    }

    rStyle.SetName(rNewName);

    for (const ScPatternAttr* p : aChanged)
        maRegisteredCellAttributes.insert(p);
}

void CellAttributeHelper::CellStyleCreated(const ScDocument& rDoc, const OUString&&nbsp;rName)
{
    // If a style was created, don't keep any pattern with its name string in the pool,
    // because it would compare equal to a pattern with a pointer to the new style.
    // Calling StyleSheetChanged isn't enough because the pool may still contain items
    // for undo or clipboard content.
    std::vector<const ScPatternAttr*> aChanged;
    auto it = maRegisteredCellAttributes.lower_bound(&rName);
    while(it != maRegisteredCellAttributes.end())
    {
        const ScPatternAttr* pCheck = *it;
        if (CompareStringPtr(pCheck->GetStyleName(), &rName) != 0)
            break;
        // tdf#163831 Invalidate cache if the style is modified/created
        const_cast<ScPatternAttr*>(pCheck)->InvalidateCaches();
        if (nullptr == pCheck->GetStyleSheet())
            if (const_cast<ScPatternAttr*>(pCheck)->UpdateStyleSheet(rDoc)) // find and store style pointer
            {
                aChanged.push_back(pCheck);
                // if the name changed, we have to re-insert it
                it = maRegisteredCellAttributes.erase(it);
            }
            else
                ++it;
        else
            ++it;
    }
    for (const ScPatternAttr* p : aChanged)
        maRegisteredCellAttributes.insert(p);
}

void CellAttributeHelper::UpdateAllStyleSheets(const ScDocument& rDoc)
{
    bool bNameChanged = false;
    for (const ScPatternAttr* pCheck : maRegisteredCellAttributes)
        bNameChanged |= const_cast<ScPatternAttr*>(pCheck)->UpdateStyleSheet(rDoc);
    if (bNameChanged)
        ReIndexRegistered();

    // force existence, then access
    getDefaultCellAttribute();
    mpDefaultCellAttribute->UpdateStyleSheet(rDoc);
}

void CellAttributeHelper::AllStylesToNames()
{
    for (const ScPatternAttr* pCheck : maRegisteredCellAttributes)
        const_cast<ScPatternAttr*>(pCheck)->StyleToName();

    // force existence, then access
    getDefaultCellAttribute();
    mpDefaultCellAttribute->StyleToName();
}

/// If the style name changed, we need to reindex.
void CellAttributeHelper::ReIndexRegistered()
{
    RegisteredAttrSet aNewSet;
    for (auto const & p : maRegisteredCellAttributes)
        aNewSet.insert(p);
    maRegisteredCellAttributes = std::move(aNewSet);
}

bool CellAttributeHelper::RegisteredAttrSetLess::operator()(const ScPatternAttr* lhs, const ScPatternAttr* rhs) const
{
    int cmp = CompareStringPtr(lhs->GetStyleName(), rhs->GetStyleName());
    if (cmp < 0)
        return true;
    if (cmp > 0)
        return false;
    return lhs < rhs;
}
bool CellAttributeHelper::RegisteredAttrSetLess::operator()(const ScPatternAttr* lhs, const OUString* rhs) const
{
    int cmp = CompareStringPtr(lhs->GetStyleName(), rhs);
    if (cmp < 0)
        return true;
    if (cmp > 0)
        return false;
    return false;
}
bool CellAttributeHelper::RegisteredAttrSetLess::operator()(const OUString* lhs, const ScPatternAttr* rhs) const
{
    int cmp = CompareStringPtr(lhs, rhs->GetStyleName());
    if (cmp < 0)
        return true;
    if (cmp > 0)
        return false;
    return true;
}


CellAttributeHolder::CellAttributeHolder(const ScPatternAttr* pNew, bool bPassingOwnership)
: mpScPatternAttr(nullptr)
{
    if (nullptr != pNew)
        suppress_fun_call_w_exception(mpScPatternAttr = pNew->getCellAttributeHelper().registerAndCheck(*pNew, bPassingOwnership));
}

CellAttributeHolder::CellAttributeHolder(const CellAttributeHolder& rHolder)
: mpScPatternAttr(nullptr)
{
    if (rHolder.getScPatternAttr())
        suppress_fun_call_w_exception(mpScPatternAttr = rHolder.getScPatternAttr()->getCellAttributeHelper().registerAndCheck(*rHolder.getScPatternAttr(), false));
}

CellAttributeHolder::~CellAttributeHolder()
{
    if (nullptr != mpScPatternAttr)
        suppress_fun_call_w_exception(mpScPatternAttr->getCellAttributeHelper().doUnregister(*mpScPatternAttr));
}

CellAttributeHolder& CellAttributeHolder::operator=(const CellAttributeHolder&&nbsp;rHolder)
{
    if (nullptr != mpScPatternAttr)
    {
        mpScPatternAttr->getCellAttributeHelper().doUnregister(*mpScPatternAttr);
        mpScPatternAttr = nullptr;
    }

    if (rHolder.getScPatternAttr())
        mpScPatternAttr = rHolder.getScPatternAttr()->getCellAttributeHelper().registerAndCheck(*rHolder.getScPatternAttr(), false);

    return *this;
}

bool CellAttributeHolder::operator==(const CellAttributeHolder& rHolder) const
{
    // here we have registered entries, so no need to test for equality
    return mpScPatternAttr == rHolder.mpScPatternAttr;
}

void CellAttributeHolder::setScPatternAttr(const ScPatternAttr* pNew, bool bPassingOwnership)
{
    if (nullptr != mpScPatternAttr)
        mpScPatternAttr->getCellAttributeHelper().doUnregister(*mpScPatternAttr);

    mpScPatternAttr = nullptr;

    if (nullptr != pNew)
        mpScPatternAttr = pNew->getCellAttributeHelper().registerAndCheck(*pNew, bPassingOwnership);
}

bool CellAttributeHolder::areSame(const CellAttributeHolder* p1, const CellAttributeHolder* p2)
{
    if (p1 == p2)
        // pointer compare, this handles already
        // nullptr and if indeed handed over twice
        return true;

    if (nullptr == p1 || nullptr == p2)
        // one ptr is nullptr, not both, that would
        // have triggered above
        return false;

    // return content compare using operator== at last
    return *p1 == *p2;
}

#ifdef DBG_UTIL
static size_t nUsedScPatternAttr(0);
#endif

const WhichRangesContainer aScPatternAttrSchema(svl::Items<ATTR_PATTERN_START, ATTR_PATTERN_END>);

ScPatternAttr::ScPatternAttr(CellAttributeHelper& rHelper, const SfxItemSet* pItemSet, const OUString* pStyleName)
: maLocalSfxItemSet(rHelper.GetPool(), aScPatternAttrSchema)
, mxVisible()
, pStyle(nullptr)
, pCellAttributeHelper(&rHelper)
, mnPAKey(0)
, mnRefCount(0)
#ifdef DBG_UTIL
, m_nSerialNumber(nUsedScPatternAttr++)
, m_bDeleted(false)
#endif
{
    if (nullptr != pStyleName)
        moName = *pStyleName;

    // We need to ensure that ScPatternAttr is using the correct WhichRange,
    // see comments in commit message. This does transfers the items with
    // minimized overhead, too
    if (nullptr != pItemSet)
    {
        // CAUTION: Use bInvalidAsDefault == false for the ::Put,
        // we *need* to take over also Items/Slots in state
        // SfxItemState::INVALID aka IsInvalidItem, this is a precious
        // value/information e.g. in ScDocument::CreateSelectionPattern
        maLocalSfxItemSet.Put(*pItemSet, false);
    }
}

ScPatternAttr::ScPatternAttr(const ScPatternAttr& rPatternAttr)
: maLocalSfxItemSet(rPatternAttr.maLocalSfxItemSet)
, moName(rPatternAttr.moName)
, mxVisible()
, pStyle(rPatternAttr.pStyle)
, pCellAttributeHelper(rPatternAttr.pCellAttributeHelper)
, mnPAKey(rPatternAttr.mnPAKey)
, mnRefCount(0)
#ifdef DBG_UTIL
, m_nSerialNumber(nUsedScPatternAttr++)
, m_bDeleted(false)
#endif
{
}

ScPatternAttr::~ScPatternAttr()
{
#ifdef DBG_UTIL
    m_bDeleted = true;
#endif
    // should no longer be referenced, complain if not so
    assert(!isRegistered());
}

static bool StrCmp( const OUString* pStr1, const OUString* pStr2 )
{
    if (pStr1 == pStr2)
        return true;
    if (pStr1 == nullptr || pStr2 == nullptr)
        return false// one ptr is nullptr, not both, that would have triggered above
    return *pStr1 == *pStr2;
}

bool ScPatternAttr::operator==(const ScPatternAttr& rCmp) const
{
    // check if same incarnation
    if (this == &rCmp)
        return true;

    // check everything except the SfxItemSet from base class SfxSetItem
    if (!StrCmp(GetStyleName(), rCmp.GetStyleName()))
        return false;

    // use SfxItemSet::operator==, does the same as locally done here before,
    // including pool compare (default). It also compares parent, not used here.
    // There was the old comment from
    //   "Actually test_tdf133629 from UITest_calc_tests9 somehow manages to have
    //   a different range (and I don't understand enough why), so better be safe and compare fully."
    // that hints to different WhichRanges, but WhichRanges are not compared in
    // the std-operator (but the Items - if needed - as was here done locally)
    return maLocalSfxItemSet == rCmp.maLocalSfxItemSet;
}

bool ScPatternAttr::areSame(const ScPatternAttr* pItem1, const ScPatternAttr* pItem2)
{
    if (pItem1 == pItem2)
        // pointer compare, this handles already
        // nullptr and if indeed handed over twice
        return true;

    if (nullptr == pItem1 || nullptr == pItem2)
        // one ptr is nullptr, not both, that would
        // have triggered above
        return false;

    // return content compare using operator== at last
    return *pItem1 == *pItem2;
}

SvxCellOrientation ScPatternAttr::GetCellOrientation( const SfxItemSet& rItemSetconst SfxItemSet* pCondSet )
{
    SvxCellOrientation eOrient = SvxCellOrientation::Standard;

    if( GetItem( ATTR_STACKED, rItemSet, pCondSet ).GetValue() )
    {
        eOrient = SvxCellOrientation::Stacked;
    }
    else
    {
        Degree100 nAngle = GetItem( ATTR_ROTATE_VALUE, rItemSet, pCondSet ).GetValue();
        if( nAngle == 9000_deg100 )
            eOrient = SvxCellOrientation::BottomUp;
        else if( nAngle == 27000_deg100 )
            eOrient = SvxCellOrientation::TopBottom;
    }

    return eOrient;
}

SvxCellOrientation ScPatternAttr::GetCellOrientation( const SfxItemSet* pCondSet ) const
{
    return GetCellOrientation( GetItemSet(), pCondSet );
}

namespace {

void getFontIDsByScriptType(SvtScriptType nScript,
        TypedWhichId<SvxFontItem>& nFontId,
        TypedWhichId<SvxFontHeightItem>& nHeightId,
        TypedWhichId<SvxWeightItem>& nWeightId,
        TypedWhichId<SvxPostureItem>& nPostureId,
        TypedWhichId<SvxLanguageItem>& nLangId)
{
    if ( nScript == SvtScriptType::ASIAN )
    {
        nFontId    = ATTR_CJK_FONT;
        nHeightId  = ATTR_CJK_FONT_HEIGHT;
        nWeightId  = ATTR_CJK_FONT_WEIGHT;
        nPostureId = ATTR_CJK_FONT_POSTURE;
        nLangId    = ATTR_CJK_FONT_LANGUAGE;
    }
    else if ( nScript == SvtScriptType::COMPLEX )
    {
        nFontId    = ATTR_CTL_FONT;
        nHeightId  = ATTR_CTL_FONT_HEIGHT;
        nWeightId  = ATTR_CTL_FONT_WEIGHT;
        nPostureId = ATTR_CTL_FONT_POSTURE;
        nLangId    = ATTR_CTL_FONT_LANGUAGE;
    }
    else
    {
        nFontId    = ATTR_FONT;
        nHeightId  = ATTR_FONT_HEIGHT;
        nWeightId  = ATTR_FONT_WEIGHT;
        nPostureId = ATTR_FONT_POSTURE;
        nLangId    = ATTR_FONT_LANGUAGE;
    }
}

}

void ScPatternAttr::fillFont(
        vcl::Font& rFont, const SfxItemSet& rItemSet, ScAutoFontColorMode eAutoMode,
        const OutputDevice* pOutDev, const Fraction* pScale,
        const SfxItemSet* pCondSet, SvtScriptType nScript,
        const Color* pBackConfigColor, const Color* pTextConfigColor)
{
    model::ComplexColor aComplexColor;

    //  determine effective font color
    ScPatternAttr::fillFontOnly(rFont, rItemSet, pOutDev, pScale, pCondSet, nScript);
    ScPatternAttr::fillColor(aComplexColor, rItemSet, eAutoMode, pCondSet, pBackConfigColor, pTextConfigColor);

    //  set font effects
    rFont.SetColor(aComplexColor.getFinalColor());
}

void ScPatternAttr::fillFontOnly(
        vcl::Font& rFont, const SfxItemSet& rItemSet,
        const OutputDevice* pOutDev, const Fraction* pScale,
        const SfxItemSet* pCondSet, SvtScriptType nScript)
{
    // Read items

    const SvxFontItem* pFontAttr;
    sal_uInt32 nFontHeight;
    FontWeight eWeight;
    FontItalic eItalic;
    FontLineStyle eUnder;
    FontLineStyle eOver;
    bool bWordLine;
    FontStrikeout eStrike;
    bool bOutline;
    bool bShadow;
    FontEmphasisMark eEmphasis;
    FontRelief eRelief;
    LanguageType eLang;

    TypedWhichId<SvxFontItem> nFontId(0);
    TypedWhichId<SvxFontHeightItem> nHeightId(0);
    TypedWhichId<SvxWeightItem> nWeightId(0);
    TypedWhichId<SvxPostureItem> nPostureId(0);
    TypedWhichId<SvxLanguageItem> nLangId(0);
    getFontIDsByScriptType(nScript, nFontId, nHeightId, nWeightId, nPostureId, nLangId);

    if (pCondSet)
    {
        pFontAttr = pCondSet->GetItemIfSet( nFontId );
        if ( !pFontAttr )
            pFontAttr = &rItemSet.Get( nFontId );

        const SvxFontHeightItem* pFontHeightItem = pCondSet->GetItemIfSet( nHeightId );
        if ( !pFontHeightItem )
            pFontHeightItem = &rItemSet.Get( nHeightId );
        nFontHeight = pFontHeightItem->GetHeight();

        const SvxWeightItem* pFontHWeightItem = pCondSet->GetItemIfSet( nWeightId );
        if ( !pFontHWeightItem )
            pFontHWeightItem = &rItemSet.Get( nWeightId );
        eWeight = pFontHWeightItem->GetValue();

        const SvxPostureItem* pPostureItem = pCondSet->GetItemIfSet( nPostureId );
        if ( !pPostureItem )
            pPostureItem = &rItemSet.Get( nPostureId );
        eItalic = pPostureItem->GetValue();

        const SvxUnderlineItem* pUnderlineItem = pCondSet->GetItemIfSet( ATTR_FONT_UNDERLINE );
        if ( !pUnderlineItem )
            pUnderlineItem = &rItemSet.Get( ATTR_FONT_UNDERLINE );
        eUnder = pUnderlineItem->GetValue();

        const SvxOverlineItem* pOverlineItem = pCondSet->GetItemIfSet( ATTR_FONT_OVERLINE );
        if ( !pOverlineItem )
            pOverlineItem = &rItemSet.Get( ATTR_FONT_OVERLINE );
        eOver = pOverlineItem->GetValue();

        const SvxWordLineModeItem* pWordlineItem = pCondSet->GetItemIfSet( ATTR_FONT_WORDLINE );
        if ( !pWordlineItem )
            pWordlineItem = &rItemSet.Get( ATTR_FONT_WORDLINE );
        bWordLine = pWordlineItem->GetValue();

        const SvxCrossedOutItem* pCrossedOutItem = pCondSet->GetItemIfSet( ATTR_FONT_CROSSEDOUT );
        if ( !pCrossedOutItem )
            pCrossedOutItem = &rItemSet.Get( ATTR_FONT_CROSSEDOUT );
        eStrike = pCrossedOutItem->GetValue();

        const SvxContourItem* pContourItem = pCondSet->GetItemIfSet( ATTR_FONT_CONTOUR );
        if ( !pContourItem )
            pContourItem = &rItemSet.Get( ATTR_FONT_CONTOUR );
        bOutline = pContourItem->GetValue();

        const SvxShadowedItem* pShadowedItem = pCondSet->GetItemIfSet( ATTR_FONT_SHADOWED );
        if ( !pShadowedItem )
            pShadowedItem = &rItemSet.Get( ATTR_FONT_SHADOWED );
        bShadow = pShadowedItem->GetValue();

        const SvxEmphasisMarkItem* pEmphasisMarkItem = pCondSet->GetItemIfSet( ATTR_FONT_EMPHASISMARK );
        if ( !pEmphasisMarkItem )
            pEmphasisMarkItem = &rItemSet.Get( ATTR_FONT_EMPHASISMARK );
        eEmphasis = pEmphasisMarkItem->GetEmphasisMark();

        const SvxCharReliefItem* pCharReliefItem = pCondSet->GetItemIfSet( ATTR_FONT_RELIEF );
        if ( !pCharReliefItem )
            pCharReliefItem = &rItemSet.Get( ATTR_FONT_RELIEF );
        eRelief = pCharReliefItem->GetValue();

        const SvxLanguageItem* pLanguageItem = pCondSet->GetItemIfSet( nLangId );
        if ( !pLanguageItem )
            pLanguageItem = &rItemSet.Get( nLangId );
        eLang = pLanguageItem->GetLanguage();
    }
    else    // Everything from rItemSet
    {
        pFontAttr = &rItemSet.Get( nFontId );
        nFontHeight = rItemSet.Get( nHeightId ).GetHeight();
        eWeight = rItemSet.Get( nWeightId ).GetValue();
        eItalic = rItemSet.Get( nPostureId ).GetValue();
        eUnder = rItemSet.Get( ATTR_FONT_UNDERLINE ).GetValue();
        eOver = rItemSet.Get( ATTR_FONT_OVERLINE ).GetValue();
        bWordLine = rItemSet.Get( ATTR_FONT_WORDLINE ).GetValue();
        eStrike = rItemSet.Get( ATTR_FONT_CROSSEDOUT ).GetValue();
        bOutline = rItemSet.Get( ATTR_FONT_CONTOUR ).GetValue();
        bShadow = rItemSet.Get( ATTR_FONT_SHADOWED ).GetValue();
        eEmphasis = rItemSet.Get( ATTR_FONT_EMPHASISMARK ).GetEmphasisMark();
        eRelief = rItemSet.Get( ATTR_FONT_RELIEF ).GetValue();
        // for graphite language features
        eLang = rItemSet.Get( nLangId ).GetLanguage();
    }
    OSL_ENSURE(pFontAttr,"Oops?");

    //  Evaluate

    //  FontItem:

    if (rFont.GetFamilyName() != pFontAttr->GetFamilyName())
        rFont.SetFamilyName( pFontAttr->GetFamilyName() );
    if (rFont.GetStyleName() != pFontAttr->GetStyleName())
        rFont.SetStyleName( pFontAttr->GetStyleName() );

    rFont.SetFamily( pFontAttr->GetFamily() );
    rFont.SetCharSet( pFontAttr->GetCharSet() );
    rFont.SetPitch( pFontAttr->GetPitch() );

    rFont.SetLanguage(eLang);

    //  Size

    if ( pOutDev != nullptr )
    {
        Size aEffSize;
        Fraction aFraction( 1,1 );
        if (pScale)
            aFraction = *pScale;
        Size aSize( 0, static_cast<tools::Long>(nFontHeight) );
        MapMode aDestMode = pOutDev->GetMapMode();
        MapMode aSrcMode( MapUnit::MapTwip, Point(), aFraction, aFraction );
        if (aDestMode.GetMapUnit() == MapUnit::MapPixel && pOutDev->GetDPIX() > 0)
            aEffSize = pOutDev->LogicToPixel( aSize, aSrcMode );
        else
        {
            Fraction aFractOne(1,1);
            aDestMode.SetScaleX( aFractOne );
            aDestMode.SetScaleY( aFractOne );
            aEffSize = OutputDevice::LogicToLogic( aSize, aSrcMode, aDestMode );
        }
        rFont.SetFontSize( aEffSize );
    }
    else /* if pOutDev != NULL */
    {
        rFont.SetFontSize( Size( 0, static_cast<tools::Long>(nFontHeight) ) );
    }

    //  set font effects
    rFont.SetWeight( eWeight );
    rFont.SetItalic( eItalic );
    rFont.SetUnderline( eUnder );
    rFont.SetOverline( eOver );
    rFont.SetWordLineMode( bWordLine );
    rFont.SetStrikeout( eStrike );
    rFont.SetOutline( bOutline );
    rFont.SetShadow( bShadow );
    rFont.SetEmphasisMark( eEmphasis );
    rFont.SetRelief( eRelief );
    rFont.SetTransparent( true );
}

void ScPatternAttr::fillColor(model::ComplexColor& rComplexColor, const SfxItemSet& rItemSet, ScAutoFontColorMode eAutoMode, const SfxItemSet* pCondSet, const Color* pBackConfigColor, const Color* pTextConfigColor)
{
    model::ComplexColor aComplexColor;

    Color aColor;

    SvxColorItem const* pColorItem = nullptr;

    if (pCondSet)
        pColorItem = pCondSet->GetItemIfSet(ATTR_FONT_COLOR);

    if (!pColorItem)
        pColorItem = &rItemSet.Get(ATTR_FONT_COLOR);

    if (pColorItem)
    {
        aComplexColor = pColorItem->getComplexColor();
        aColor = pColorItem->GetValue();
    }

    if (aComplexColor.getType() == model::ColorType::Unused)
    {
        aComplexColor.setColor(aColor);
    }

    if ((aColor == COL_AUTO && eAutoMode != ScAutoFontColorMode::Raw)
        || eAutoMode == ScAutoFontColorMode::IgnoreFont
        || eAutoMode == ScAutoFontColorMode::IgnoreAll)
    {
        //  get background color from conditional or own set
        Color aBackColor;
        if ( pCondSet )
        {
            const SvxBrushItem* pItem = pCondSet->GetItemIfSet(ATTR_BACKGROUND);
            if (!pItem)
                pItem = &rItemSet.Get(ATTR_BACKGROUND);
            aBackColor = pItem->GetColor();
        }
        else
        {
            aBackColor = rItemSet.Get(ATTR_BACKGROUND).GetColor();
        }

        //  if background color attribute is transparent, use window color for brightness comparisons
        if (aBackColor == COL_TRANSPARENT
            || eAutoMode == ScAutoFontColorMode::IgnoreBack
            || eAutoMode == ScAutoFontColorMode::IgnoreAll)
        {
            if (!comphelper::LibreOfficeKit::isActive())
            {
                if ( eAutoMode == ScAutoFontColorMode::Print )
                    aBackColor = COL_WHITE;
                else if ( pBackConfigColor )
                {
                    // pBackConfigColor can be used to avoid repeated lookup of the configured color
                    aBackColor = *pBackConfigColor;
                }
                else
                    aBackColor = ScModule::get()->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor;
            }
            else
            {
                // Get document color from current view instead
                SfxViewShell* pSfxViewShell = SfxViewShell::Current();
                ScTabViewShell* pViewShell = dynamic_cast<ScTabViewShell*>(pSfxViewShell);
                if (pViewShell)
                {
                    const ScViewRenderingOptions& rViewRenderingOptions = pViewShell->GetViewRenderingData();
                    aBackColor = eAutoMode == ScAutoFontColorMode::Print ? COL_WHITE :
                        rViewRenderingOptions.GetDocColor();
                }
            }
        }

        //  get system text color for comparison
        Color aSysTextColor;
        if (eAutoMode == ScAutoFontColorMode::Print)
        {
            aSysTextColor = COL_BLACK;
        }
        else if (pTextConfigColor)
        {
            // pTextConfigColor can be used to avoid repeated lookup of the configured color
            aSysTextColor = *pTextConfigColor;
            if (ScModule::get()->GetColorConfig().GetColorValue(svtools::FONTCOLOR, false).nColor == COL_AUTO)
            {
                if ( aBackColor.IsDark() && aSysTextColor.IsDark() )
                    aSysTextColor = COL_WHITE;
                else
                    aSysTextColor = COL_BLACK;
            }
        }
        else
        {
            aSysTextColor = ScModule::get()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor;
        }

        if (SfxViewShell::Current())
        {
            if (aBackColor.IsDark())
                aColor = COL_WHITE;
            else
                aColor = COL_BLACK;
        }
        else
        {
            aColor = aSysTextColor;
        }
    }
    aComplexColor.setFinalColor(aColor);
    rComplexColor = std::move(aComplexColor);
}

ScDxfFont ScPatternAttr::GetDxfFont(const SfxItemSet& rItemSet, SvtScriptType nScript)
{
    TypedWhichId<SvxFontItem> nFontId(0);
    TypedWhichId<SvxFontHeightItem> nHeightId(0);
    TypedWhichId<SvxWeightItem> nWeightId(0);
    TypedWhichId<SvxPostureItem> nPostureId(0);
    TypedWhichId<SvxLanguageItem> nLangId(0);
    getFontIDsByScriptType(nScript, nFontId, nHeightId, nWeightId, nPostureId, nLangId);

    ScDxfFont aReturn;

    if ( const SvxFontItem* pItem = rItemSet.GetItemIfSet( nFontId ) )
    {
        aReturn.pFontAttr = pItem;
    }

    if ( const SvxFontHeightItem* pItem = rItemSet.GetItemIfSet( nHeightId ) )
    {
        aReturn.nFontHeight = pItem->GetHeight();
    }

    if ( const SvxWeightItem* pItem = rItemSet.GetItemIfSet( nWeightId ) )
    {
        aReturn.eWeight = pItem->GetValue();
    }

    if ( const SvxPostureItem* pItem = rItemSet.GetItemIfSet( nPostureId ) )
    {
        aReturn.eItalic = pItem->GetValue();
    }

    if ( const SvxUnderlineItem* pItem = rItemSet.GetItemIfSet( ATTR_FONT_UNDERLINE ) )
    {
        pItem = &rItemSet.Get( ATTR_FONT_UNDERLINE );
        aReturn.eUnder = pItem->GetValue();
    }

    if ( const SvxOverlineItem* pItem = rItemSet.GetItemIfSet( ATTR_FONT_OVERLINE ) )
    {
        aReturn.eOver = pItem->GetValue();
    }

    if ( const SvxWordLineModeItem* pItem = rItemSet.GetItemIfSet( ATTR_FONT_WORDLINE ) )
    {
        aReturn.bWordLine = pItem->GetValue();
    }

    if ( const SvxCrossedOutItem* pItem = rItemSet.GetItemIfSet( ATTR_FONT_CROSSEDOUT ) )
    {
        pItem = &rItemSet.Get( ATTR_FONT_CROSSEDOUT );
        aReturn.eStrike = pItem->GetValue();
    }

    if ( const SvxContourItem* pItem = rItemSet.GetItemIfSet( ATTR_FONT_CONTOUR ) )
    {
        aReturn.bOutline = pItem->GetValue();
    }

    if ( const SvxShadowedItem* pItem = rItemSet.GetItemIfSet( ATTR_FONT_SHADOWED ) )
    {
        pItem = &rItemSet.Get( ATTR_FONT_SHADOWED );
        aReturn.bShadow = pItem->GetValue();
    }

    if ( const SvxEmphasisMarkItem* pItem = rItemSet.GetItemIfSet( ATTR_FONT_EMPHASISMARK ) )
    {
        aReturn.eEmphasis = pItem->GetEmphasisMark();
    }

    if ( const SvxCharReliefItem* pItem = rItemSet.GetItemIfSet( ATTR_FONT_RELIEF ) )
    {
        aReturn.eRelief = pItem->GetValue();
    }

    if ( const SvxColorItem* pItem = rItemSet.GetItemIfSet( ATTR_FONT_COLOR ) )
    {
        aReturn.aColor = pItem->GetValue();
    }

    if ( const SvxLanguageItem* pItem = rItemSet.GetItemIfSet( nLangId ) )
    {
        aReturn.eLang = pItem->GetLanguage();
    }

    return aReturn;
}

template <class T>
static void lcl_populate( std::unique_ptr<T>& rxItem, TypedWhichId<T> nWhich, const SfxItemSet& rSrcSet, const SfxItemSet* pCondSet )
{
    const T* pItem = pCondSet->GetItemIfSet( nWhich );
    if ( !pItem )
        pItem = &rSrcSet.Get( nWhich );
    rxItem.reset(pItem->Clone());
}

void ScPatternAttr::FillToEditItemSet( SfxItemSet& rEditSet, const SfxItemSet& ;rSrcSet, const SfxItemSet* pCondSet )
{
    //  Read Items

    std::unique_ptr<SvxColorItem> aColorItem(std::make_unique<SvxColorItem>(EE_CHAR_COLOR));              // use item as-is
    std::unique_ptr<SvxFontItem> aFontItem(std::make_unique<SvxFontItem>(EE_CHAR_FONTINFO));            // use item as-is
    std::unique_ptr<SvxFontItem> aCjkFontItem(std::make_unique<SvxFontItem>(EE_CHAR_FONTINFO_CJK));            // use item as-is
    std::unique_ptr<SvxFontItem> aCtlFontItem(std::make_unique<SvxFontItem>(EE_CHAR_FONTINFO_CTL));            // use item as-is
    tools::Long            nTHeight, nCjkTHeight, nCtlTHeight;     // Twips
    FontWeight      eWeight, eCjkWeight, eCtlWeight;
    std::unique_ptr<SvxUnderlineItem> aUnderlineItem(std::make_unique<SvxUnderlineItem>(LINESTYLE_NONE, EE_CHAR_UNDERLINE));
    std::unique_ptr<SvxOverlineItem> aOverlineItem(std::make_unique<SvxOverlineItem>(LINESTYLE_NONE, EE_CHAR_OVERLINE));
    bool            bWordLine;
    FontStrikeout   eStrike;
    FontItalic      eItalic, eCjkItalic, eCtlItalic;
    bool            bOutline;
    bool            bShadow;
    bool            bForbidden;
    FontEmphasisMark eEmphasis;
    FontRelief      eRelief;
    LanguageType    eLang, eCjkLang, eCtlLang;
    bool            bHyphenate;
    SvxFrameDirection eDirection;

    //TODO: additional parameter to control if language is needed?

    if ( pCondSet )
    {
        lcl_populate(aColorItem, ATTR_FONT_COLOR, rSrcSet, pCondSet);
        lcl_populate(aFontItem, ATTR_FONT, rSrcSet, pCondSet);
        lcl_populate(aCjkFontItem, ATTR_CJK_FONT, rSrcSet, pCondSet);
        lcl_populate(aCtlFontItem, ATTR_CTL_FONT, rSrcSet, pCondSet);

        const SvxFontHeightItem* pFontHeightItem = pCondSet->GetItemIfSet( ATTR_FONT_HEIGHT );
        if (!pFontHeightItem)
            pFontHeightItem = &rSrcSet.Get( ATTR_FONT_HEIGHT );
        nTHeight = pFontHeightItem->GetHeight();
        pFontHeightItem = pCondSet->GetItemIfSet( ATTR_CJK_FONT_HEIGHT );
        if ( !pFontHeightItem )
            pFontHeightItem = &rSrcSet.Get( ATTR_CJK_FONT_HEIGHT );
        nCjkTHeight = pFontHeightItem->GetHeight();
        pFontHeightItem = pCondSet->GetItemIfSet( ATTR_CTL_FONT_HEIGHT );
        if ( !pFontHeightItem )
            pFontHeightItem = &rSrcSet.Get( ATTR_CTL_FONT_HEIGHT );
        nCtlTHeight = pFontHeightItem->GetHeight();

        const SvxWeightItem* pWeightItem = pCondSet->GetItemIfSet( ATTR_FONT_WEIGHT );
        if ( !pWeightItem )
            pWeightItem = &rSrcSet.Get( ATTR_FONT_WEIGHT );
        eWeight = pWeightItem->GetValue();
        pWeightItem = pCondSet->GetItemIfSet( ATTR_CJK_FONT_WEIGHT );
        if ( !pWeightItem )
            pWeightItem = &rSrcSet.Get( ATTR_CJK_FONT_WEIGHT );
        eCjkWeight = pWeightItem->GetValue();
        pWeightItem = pCondSet->GetItemIfSet( ATTR_CTL_FONT_WEIGHT );
        if ( !pWeightItem )
            pWeightItem = &rSrcSet.Get( ATTR_CTL_FONT_WEIGHT );
        eCtlWeight = pWeightItem->GetValue();

        const SvxPostureItem* pPostureItem = pCondSet->GetItemIfSet( ATTR_FONT_POSTURE );
        if ( !pPostureItem )
            pPostureItem = &rSrcSet.Get( ATTR_FONT_POSTURE );
        eItalic = pPostureItem->GetValue();
        pPostureItem = pCondSet->GetItemIfSet( ATTR_CJK_FONT_POSTURE );
        if ( !pPostureItem )
            pPostureItem = &rSrcSet.Get( ATTR_CJK_FONT_POSTURE );
        eCjkItalic = pPostureItem->GetValue();
        pPostureItem = pCondSet->GetItemIfSet( ATTR_CTL_FONT_POSTURE );
        if ( !pPostureItem )
            pPostureItem = &rSrcSet.Get( ATTR_CTL_FONT_POSTURE );
        eCtlItalic = pPostureItem->GetValue();

        lcl_populate(aUnderlineItem, ATTR_FONT_UNDERLINE, rSrcSet, pCondSet);
        lcl_populate(aOverlineItem, ATTR_FONT_OVERLINE, rSrcSet, pCondSet);

        const SvxWordLineModeItem* pWordLineModeItem = pCondSet->GetItemIfSet( ATTR_FONT_WORDLINE );
        if ( !pWordLineModeItem )
            pWordLineModeItem = &rSrcSet.Get( ATTR_FONT_WORDLINE );
        bWordLine = pWordLineModeItem->GetValue();

        const SvxCrossedOutItem* pCrossedOutItem = pCondSet->GetItemIfSet( ATTR_FONT_CROSSEDOUT );
        if ( !pCrossedOutItem )
            pCrossedOutItem = &rSrcSet.Get( ATTR_FONT_CROSSEDOUT );
        eStrike = pCrossedOutItem->GetValue();

        const SvxContourItem* pContourItem = pCondSet->GetItemIfSet( ATTR_FONT_CONTOUR );
        if ( !pContourItem )
            pContourItem = &rSrcSet.Get( ATTR_FONT_CONTOUR );
        bOutline = pContourItem->GetValue();

        const SvxShadowedItem* pShadowedItem = pCondSet->GetItemIfSet( ATTR_FONT_SHADOWED );
        if ( !pShadowedItem )
            pShadowedItem = &rSrcSet.Get( ATTR_FONT_SHADOWED );
        bShadow = pShadowedItem->GetValue();

        const SvxForbiddenRuleItem* pForbiddenRuleItem = pCondSet->GetItemIfSet( ATTR_FORBIDDEN_RULES );
        if ( !pForbiddenRuleItem )
            pForbiddenRuleItem = &rSrcSet.Get( ATTR_FORBIDDEN_RULES );
        bForbidden = pForbiddenRuleItem->GetValue();

        const SvxEmphasisMarkItem* pEmphasisMarkItem = pCondSet->GetItemIfSet( ATTR_FONT_EMPHASISMARK );
        if ( !pEmphasisMarkItem )
            pEmphasisMarkItem = &rSrcSet.Get( ATTR_FONT_EMPHASISMARK );
        eEmphasis = pEmphasisMarkItem->GetEmphasisMark();
        const SvxCharReliefItem* pCharReliefItem = pCondSet->GetItemIfSet( ATTR_FONT_RELIEF );
        if ( !pCharReliefItem )
            pCharReliefItem = &rSrcSet.Get( ATTR_FONT_RELIEF );
        eRelief = pCharReliefItem->GetValue();

        const SvxLanguageItem* pLanguageItem = pCondSet->GetItemIfSet( ATTR_FONT_LANGUAGE );
        if ( !pLanguageItem )
            pLanguageItem = &rSrcSet.Get( ATTR_FONT_LANGUAGE );
        eLang = pLanguageItem->GetLanguage();
        pLanguageItem = pCondSet->GetItemIfSet( ATTR_CJK_FONT_LANGUAGE );
        if ( !pLanguageItem )
            pLanguageItem = &rSrcSet.Get( ATTR_CJK_FONT_LANGUAGE );
        eCjkLang = pLanguageItem->GetLanguage();
        pLanguageItem = pCondSet->GetItemIfSet( ATTR_CTL_FONT_LANGUAGE );
        if ( !pLanguageItem )
            pLanguageItem = &rSrcSet.Get( ATTR_CTL_FONT_LANGUAGE );
        eCtlLang = pLanguageItem->GetLanguage();

        const ScHyphenateCell* pHyphenateCell = pCondSet->GetItemIfSet( ATTR_HYPHENATE );
        if ( !pHyphenateCell )
            pHyphenateCell = &rSrcSet.Get( ATTR_HYPHENATE );
        bHyphenate = pHyphenateCell->GetValue();

        const SvxFrameDirectionItem* pFrameDirectionItem = pCondSet->GetItemIfSet( ATTR_WRITINGDIR );
        if ( !pFrameDirectionItem )
            pFrameDirectionItem = &rSrcSet.Get( ATTR_WRITINGDIR );
        eDirection = pFrameDirectionItem->GetValue();
    }
    else        // Everything directly from Pattern
    {
        aColorItem.reset(rSrcSet.Get(ATTR_FONT_COLOR).Clone());
        aFontItem.reset(rSrcSet.Get(ATTR_FONT).Clone());
        aCjkFontItem.reset(rSrcSet.Get(ATTR_CJK_FONT).Clone());
        aCtlFontItem.reset(rSrcSet.Get(ATTR_CTL_FONT).Clone());
        nTHeight = rSrcSet.Get( ATTR_FONT_HEIGHT ).GetHeight();
        nCjkTHeight = rSrcSet.Get( ATTR_CJK_FONT_HEIGHT ).GetHeight();
        nCtlTHeight = rSrcSet.Get( ATTR_CTL_FONT_HEIGHT ).GetHeight();
        eWeight = rSrcSet.Get( ATTR_FONT_WEIGHT ).GetValue();
        eCjkWeight = rSrcSet.Get( ATTR_CJK_FONT_WEIGHT ).GetValue();
        eCtlWeight = rSrcSet.Get( ATTR_CTL_FONT_WEIGHT ).GetValue();
        eItalic = rSrcSet.Get( ATTR_FONT_POSTURE ).GetValue();
        eCjkItalic = rSrcSet.Get( ATTR_CJK_FONT_POSTURE ).GetValue();
        eCtlItalic = rSrcSet.Get( ATTR_CTL_FONT_POSTURE ).GetValue();
        aUnderlineItem.reset(rSrcSet.Get(ATTR_FONT_UNDERLINE).Clone());
        aOverlineItem.reset(rSrcSet.Get(ATTR_FONT_OVERLINE).Clone());
        bWordLine = rSrcSet.Get( ATTR_FONT_WORDLINE ).GetValue();
        eStrike = rSrcSet.Get( ATTR_FONT_CROSSEDOUT ).GetValue();
        bOutline = rSrcSet.Get( ATTR_FONT_CONTOUR ).GetValue();
        bShadow = rSrcSet.Get( ATTR_FONT_SHADOWED ).GetValue();
        bForbidden = rSrcSet.Get( ATTR_FORBIDDEN_RULES ).GetValue();
        eEmphasis = rSrcSet.Get( ATTR_FONT_EMPHASISMARK ).GetEmphasisMark();
        eRelief = rSrcSet.Get( ATTR_FONT_RELIEF ).GetValue();
        eLang = rSrcSet.Get( ATTR_FONT_LANGUAGE ).GetLanguage();
        eCjkLang = rSrcSet.Get( ATTR_CJK_FONT_LANGUAGE ).GetLanguage();
        eCtlLang = rSrcSet.Get( ATTR_CTL_FONT_LANGUAGE ).GetLanguage();
        bHyphenate = rSrcSet.Get( ATTR_HYPHENATE ).GetValue();
        eDirection = rSrcSet.Get( ATTR_WRITINGDIR ).GetValue();
    }

    // Expect to be compatible to LogicToLogic, ie. 2540/1440 = 127/72, and round

    tools::Long nHeight = convertTwipToMm100(nTHeight);
    tools::Long nCjkHeight = convertTwipToMm100(nCjkTHeight);
    tools::Long nCtlHeight = convertTwipToMm100(nCtlTHeight);

    //  put items into EditEngine ItemSet

    if ( aColorItem->GetValue() == COL_AUTO )
    {
        //  When cell attributes are converted to EditEngine paragraph attributes,
        //  don't create a hard item for automatic color, because that would be converted
        //  to black when the item's Store method is used in CreateTransferable/WriteBin.
        //  COL_AUTO is the EditEngine's pool default, so ClearItem will result in automatic
        //  color, too, without having to store the item.
        rEditSet.ClearItem( EE_CHAR_COLOR );
    }
    else
    {
        // tdf#125054 adapt WhichID
        rEditSet.PutAsTargetWhich( std::move(aColorItem), EE_CHAR_COLOR );
    }

    // tdf#125054 adapt WhichID
    rEditSet.PutAsTargetWhich( std::move(aFontItem), EE_CHAR_FONTINFO );
    rEditSet.PutAsTargetWhich( std::move(aCjkFontItem), EE_CHAR_FONTINFO_CJK );
    rEditSet.PutAsTargetWhich( std::move(aCtlFontItem), EE_CHAR_FONTINFO_CTL );

    rEditSet.Put( SvxFontHeightItem( nHeight, 100, EE_CHAR_FONTHEIGHT ) );
    rEditSet.Put( SvxFontHeightItem( nCjkHeight, 100, EE_CHAR_FONTHEIGHT_CJK ) );
    rEditSet.Put( SvxFontHeightItem( nCtlHeight, 100, EE_CHAR_FONTHEIGHT_CTL ) );
    rEditSet.Put( SvxWeightItem ( eWeight,      EE_CHAR_WEIGHT ) );
    rEditSet.Put( SvxWeightItem ( eCjkWeight,   EE_CHAR_WEIGHT_CJK ) );
    rEditSet.Put( SvxWeightItem ( eCtlWeight,   EE_CHAR_WEIGHT_CTL ) );

    // tdf#125054 adapt WhichID
    rEditSet.PutAsTargetWhich( std::move(aUnderlineItem), EE_CHAR_UNDERLINE );
    rEditSet.PutAsTargetWhich( std::move(aOverlineItem), EE_CHAR_OVERLINE );

    rEditSet.Put( SvxWordLineModeItem( bWordLine,   EE_CHAR_WLM ) );
    rEditSet.Put( SvxCrossedOutItem( eStrike,       EE_CHAR_STRIKEOUT ) );
    rEditSet.Put( SvxPostureItem    ( eItalic,      EE_CHAR_ITALIC ) );
    rEditSet.Put( SvxPostureItem    ( eCjkItalic,   EE_CHAR_ITALIC_CJK ) );
    rEditSet.Put( SvxPostureItem    ( eCtlItalic,   EE_CHAR_ITALIC_CTL ) );
    rEditSet.Put( SvxContourItem    ( bOutline,     EE_CHAR_OUTLINE ) );
    rEditSet.Put( SvxShadowedItem   ( bShadow,      EE_CHAR_SHADOW ) );
    rEditSet.Put( SvxForbiddenRuleItem(bForbidden, EE_PARA_FORBIDDENRULES) );
    rEditSet.Put( SvxEmphasisMarkItem( eEmphasis,   EE_CHAR_EMPHASISMARK ) );
    rEditSet.Put( SvxCharReliefItem( eRelief,       EE_CHAR_RELIEF ) );
    rEditSet.Put( SvxLanguageItem   ( eLang,        EE_CHAR_LANGUAGE ) );
    rEditSet.Put( SvxLanguageItem   ( eCjkLang,     EE_CHAR_LANGUAGE_CJK ) );
    rEditSet.Put( SvxLanguageItem   ( eCtlLang,     EE_CHAR_LANGUAGE_CTL ) );
    rEditSet.Put( SfxBoolItem       ( EE_PARA_HYPHENATE, bHyphenate ) );
    rEditSet.Put( SvxFrameDirectionItem( eDirection, EE_PARA_WRITINGDIR ) );

    // Script spacing is always off.
    // The cell attribute isn't used here as long as there is no UI to set it
    // (don't evaluate attributes that can't be changed).
    // If a locale-dependent default is needed, it has to go into the cell
    // style, like the fonts.
    rEditSet.Put( SvxScriptSpaceItem( false, EE_PARA_ASIANCJKSPACING ) );
}

void ScPatternAttr::FillEditItemSet( SfxItemSet* pEditSet, const SfxItemSet* pCondSet ) const
{
    if( pEditSet )
        FillToEditItemSet( *pEditSet, GetItemSet(), pCondSet );
}

void ScPatternAttr::GetFromEditItemSet( SfxItemSet& rDestSet, const SfxItemSet&&nbsp;rEditSet )
{
    if (const SvxColorItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_COLOR))
        rDestSet.PutAsTargetWhich( *pItem, ATTR_FONT_COLOR );

    if (const SvxFontItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_FONTINFO))
        rDestSet.PutAsTargetWhich( *pItem, ATTR_FONT );
    if (const SvxFontItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_FONTINFO_CJK))
        rDestSet.PutAsTargetWhich( *pItem, ATTR_CJK_FONT );
    if (const SvxFontItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_FONTINFO_CTL))
        rDestSet.PutAsTargetWhich( *pItem, ATTR_CTL_FONT );

    if (const SvxFontHeightItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_FONTHEIGHT))
        rDestSet.Put( SvxFontHeightItem(o3tl::toTwips(pItem->GetHeight(), o3tl::Length::mm100),
                        100, ATTR_FONT_HEIGHT ) );
    if (const SvxFontHeightItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_FONTHEIGHT_CJK))
        rDestSet.Put( SvxFontHeightItem(o3tl::toTwips(pItem->GetHeight(), o3tl::Length::mm100),
                        100, ATTR_CJK_FONT_HEIGHT ) );
    if (const SvxFontHeightItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_FONTHEIGHT_CTL))
        rDestSet.Put( SvxFontHeightItem(o3tl::toTwips(pItem->GetHeight(), o3tl::Length::mm100),
                        100, ATTR_CTL_FONT_HEIGHT ) );

    if (const SvxWeightItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_WEIGHT))
        rDestSet.Put( SvxWeightItem( pItem->GetValue(),
                        ATTR_FONT_WEIGHT) );
    if (const SvxWeightItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_WEIGHT_CJK))
        rDestSet.Put( SvxWeightItem( pItem->GetValue(),
                        ATTR_CJK_FONT_WEIGHT) );
    if (const SvxWeightItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_WEIGHT_CTL))
        rDestSet.Put( SvxWeightItem( pItem->GetValue(),
                        ATTR_CTL_FONT_WEIGHT) );

    // SvxTextLineItem contains enum and color
    if (const SvxUnderlineItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_UNDERLINE))
        rDestSet.PutAsTargetWhich( *pItem, ATTR_FONT_UNDERLINE );
    if (const SvxOverlineItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_OVERLINE))
        rDestSet.PutAsTargetWhich( *pItem, ATTR_FONT_OVERLINE );
    if (const SvxWordLineModeItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_WLM))
        rDestSet.Put( SvxWordLineModeItem( pItem->GetValue(),
                        ATTR_FONT_WORDLINE) );

    if (const SvxCrossedOutItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_STRIKEOUT))
        rDestSet.Put( SvxCrossedOutItem( pItem->GetValue(),
                        ATTR_FONT_CROSSEDOUT) );

    if (const SvxPostureItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_ITALIC))
        rDestSet.Put( SvxPostureItem( pItem->GetValue(),
                        ATTR_FONT_POSTURE) );
    if (const SvxPostureItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_ITALIC_CJK))
        rDestSet.Put( SvxPostureItem( pItem->GetValue(),
                        ATTR_CJK_FONT_POSTURE) );
    if (const SvxPostureItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_ITALIC_CTL))
        rDestSet.Put( SvxPostureItem( pItem->GetValue(),
                        ATTR_CTL_FONT_POSTURE) );

    if (const SvxContourItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_OUTLINE))
        rDestSet.Put( SvxContourItem( pItem->GetValue(),
                        ATTR_FONT_CONTOUR) );
    if (const SvxShadowedItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_SHADOW))
        rDestSet.Put( SvxShadowedItem( pItem->GetValue(),
                        ATTR_FONT_SHADOWED) );
    if (const SvxEmphasisMarkItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_EMPHASISMARK))
        rDestSet.Put( SvxEmphasisMarkItem( pItem->GetEmphasisMark(),
                        ATTR_FONT_EMPHASISMARK) );
    if (const SvxCharReliefItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_RELIEF))
        rDestSet.Put( SvxCharReliefItem( pItem->GetValue(),
                        ATTR_FONT_RELIEF) );

    if (const SvxLanguageItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_LANGUAGE))
        rDestSet.Put( SvxLanguageItem(pItem->GetValue(), ATTR_FONT_LANGUAGE) );
    if (const SvxLanguageItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_LANGUAGE_CJK))
        rDestSet.Put( SvxLanguageItem(pItem->GetValue(), ATTR_CJK_FONT_LANGUAGE) );
    if (const SvxLanguageItem* pItem = rEditSet.GetItemIfSet(EE_CHAR_LANGUAGE_CTL))
        rDestSet.Put( SvxLanguageItem(pItem->GetValue(), ATTR_CTL_FONT_LANGUAGE) );

    const SvxAdjustItem* pAdjustItem = rEditSet.GetItemIfSet(EE_PARA_JUST);

    if (!pAdjustItem)
        return;

    SvxCellHorJustify eVal;
    switch ( pAdjustItem->GetAdjust() )
    {
        case SvxAdjust::Left:
            // EditEngine Default is always set in the GetAttribs() ItemSet !
            // whether left or right, is decided in text / number
            eVal = SvxCellHorJustify::Standard;
            break;
        case SvxAdjust::Right:
            eVal = SvxCellHorJustify::Right;
            break;
        case SvxAdjust::Block:
            eVal = SvxCellHorJustify::Block;
            break;
        case SvxAdjust::Center:
            eVal = SvxCellHorJustify::Center;
            break;
        case SvxAdjust::BlockLine:
            eVal = SvxCellHorJustify::Block;
            break;
        case SvxAdjust::End:
            eVal = SvxCellHorJustify::Right;
            break;
        default:
            eVal = SvxCellHorJustify::Standard;
    }
    if ( eVal != SvxCellHorJustify::Standard )
        rDestSet.Put( SvxHorJustifyItem( eVal, ATTR_HOR_JUSTIFY) );
}

void ScPatternAttr::GetFromEditItemSet( const SfxItemSet* pEditSet )
{
    if( !pEditSet )
        return;
    GetFromEditItemSet( GetItemSet(), *pEditSet );
    InvalidateCaches();
}

void ScPatternAttr::FillEditParaItems( SfxItemSet* pEditSet ) const
{
    //  already there in GetFromEditItemSet, but not in FillEditItemSet
    //  Default horizontal alignment is always implemented as left

    const SfxItemSet& rMySet = GetItemSet();

    SvxCellHorJustify eHorJust = rMySet.Get(ATTR_HOR_JUSTIFY).GetValue();

    SvxAdjust eSvxAdjust;
    switch (eHorJust)
    {
        case SvxCellHorJustify::Right:  eSvxAdjust = SvxAdjust::Right;  break;
        case SvxCellHorJustify::Center: eSvxAdjust = SvxAdjust::Center; break;
        case SvxCellHorJustify::Block:  eSvxAdjust = SvxAdjust::Block;  break;
        default:                     eSvxAdjust = SvxAdjust::Left;   break;
    }
    pEditSet->Put( SvxAdjustItem( eSvxAdjust, EE_PARA_JUST ) );
}

void ScPatternAttr::DeleteUnchanged( const ScPatternAttr* pOldAttrs )
{
    SfxItemSet& rThisSet = GetItemSet();
    const SfxItemSet& rOldSet = pOldAttrs->GetItemSet();

    const SfxPoolItem* pThisItem;
    const SfxPoolItem* pOldItem;

    for ( sal_uInt16 nSubWhich=ATTR_PATTERN_START; nSubWhich<=ATTR_PATTERN_END; nSubWhich++ )
    {
        //  only items that are set are interesting
        if ( rThisSet.GetItemState( nSubWhich, false, &pThisItem ) == SfxItemState::SET )
        {
            SfxItemState eOldState = rOldSet.GetItemState( nSubWhich, true, &pOldItem );
            if ( eOldState == SfxItemState::SET )
            {
                //  item is set in OldAttrs (or its parent) -> compare pointers
                if (SfxPoolItem::areSame( pThisItem, pOldItem ))
                {
                    rThisSet.ClearItem( nSubWhich );
                    InvalidateCaches();
                }
            }
            else if ( eOldState != SfxItemState::INVALID )
            {
                //  not set in OldAttrs -> compare item value to default item
                if ( *pThisItem == rThisSet.GetPool()->GetUserOrPoolDefaultItem( nSubWhich ) )
                {
                    rThisSet.ClearItem( nSubWhich );
                    InvalidateCaches();
                }
            }
        }
    }
}

bool ScPatternAttr::HasItemsSet( const sal_uInt16* pWhich ) const
{
    const SfxItemSet& rSet = GetItemSet();
    for (sal_uInt16 i=0; pWhich[i]; i++)
        if ( rSet.GetItemState( pWhich[i], false ) == SfxItemState::SET )
            return true;
    return false;
}

void ScPatternAttr::ClearItems( const sal_uInt16* pWhich )
{
    SfxItemSet& rSet = GetItemSet();
    for (sal_uInt16 i=0; pWhich[i]; i++)
        rSet.ClearItem(pWhich[i]);
    InvalidateCaches();
}

static SfxStyleSheetBase* lcl_CopyStyleToPool
    (
        SfxStyleSheetBase*      pSrcStyle,
        SfxStyleSheetBasePool*  pSrcPool,
        SfxStyleSheetBasePool*  pDestPool,
        const SvNumberFormatterIndexTable*     pFormatExchangeList
    )
{
    if ( !pSrcStyle || !pDestPool || !pSrcPool )
    {
        OSL_FAIL( "CopyStyleToPool: Invalid Arguments :-/" );
        return nullptr;
    }

    const OUString       aStrSrcStyle = pSrcStyle->GetName();
    const SfxStyleFamily eFamily      = pSrcStyle->GetFamily();
    SfxStyleSheetBase*   pDestStyle   = pDestPool->Find( aStrSrcStyle, eFamily );

    if ( !pDestStyle )
    {
        const OUString   aStrParent = pSrcStyle->GetParent();
        const SfxItemSet& rSrcSet = pSrcStyle->GetItemSet();

        pDestStyle = &pDestPool->Make( aStrSrcStyle, eFamily, SfxStyleSearchBits::UserDefined );
        SfxItemSet& rDestSet = pDestStyle->GetItemSet();
        rDestSet.Put( rSrcSet );

        // number format exchange list has to be handled here, too
        // (only called for cell styles)

        const SfxUInt32Item* pSrcItem;
        if ( pFormatExchangeList &&
             (pSrcItem = rSrcSet.GetItemIfSet( ATTR_VALUE_FORMAT, false )) )
        {
            sal_uInt32 nOldFormat = pSrcItem->GetValue();
            SvNumberFormatterIndexTable::const_iterator it = pFormatExchangeList->find(nOldFormat);
            if (it != pFormatExchangeList->end())
            {
                sal_uInt32 nNewFormat = it->second;
                rDestSet.Put( SfxUInt32Item( ATTR_VALUE_FORMAT, nNewFormat ) );
            }
        }

        // if necessary create derivative Styles, if not available:

        if ( ScResId(STR_STYLENAME_STANDARD) != aStrParent &&
             aStrSrcStyle != aStrParent &&
             !pDestPool->Find( aStrParent, eFamily ) )
        {
            lcl_CopyStyleToPool( pSrcPool->Find( aStrParent, eFamily ),
                                 pSrcPool, pDestPool, pFormatExchangeList );
        }

        pDestStyle->SetParent( aStrParent );
    }

    return pDestStyle;
}

CellAttributeHolder ScPatternAttr::MigrateToDocument( ScDocument* pDestDoc, ScDocument* pSrcDoc ) const
{
    const SfxItemSet* pSrcSet = &GetItemSet();
    ScPatternAttr* pDestPattern(new ScPatternAttr(pDestDoc->getCellAttributeHelper()));
    SfxItemSet* pDestSet(&pDestPattern->GetItemSet());

    // Copy cell pattern style to other document:
    if ( pDestDoc != pSrcDoc )
    {
        OSL_ENSURE( pStyle, "Missing Pattern-Style! :-/" );

        // if pattern in DestDoc is available, use this, otherwise copy
        // parent style to style or create if necessary and attach DestDoc

        SfxStyleSheetBase* pStyleCpy = lcl_CopyStyleToPool( pStyle,
                                                            pSrcDoc->GetStyleSheetPool(),
                                                            pDestDoc->GetStyleSheetPool(),
                                                            pDestDoc->GetFormatExchangeList() );

        pDestPattern->SetStyleSheet( static_cast<ScStyleSheet*>(pStyleCpy) );
    }

    for ( sal_uInt16 nAttrId = ATTR_PATTERN_START; nAttrId <= ATTR_PATTERN_END; nAttrId++ )
    {
        const SfxPoolItem* pSrcItem;
        SfxItemState eItemState = pSrcSet->GetItemState( nAttrId, false, &pSrcItem );
        if (eItemState==SfxItemState::SET)
        {
            std::unique_ptr<SfxPoolItem> pNewItem;

            if ( nAttrId == ATTR_VALIDDATA )
            {
                // Copy validity to the new document

                sal_uInt32 nNewIndex = 0;
                ScValidationDataList* pSrcList = pSrcDoc->GetValidationList();
                if ( pSrcList )
                {
                    sal_uInt32 nOldIndex = static_cast<const SfxUInt32Item*>(pSrcItem)->GetValue();
                    const ScValidationData* pOldData = pSrcList->GetData( nOldIndex );
                    if ( pOldData )
                        nNewIndex = pDestDoc->AddValidationEntry( *pOldData );
                }
                pNewItem.reset(new SfxUInt32Item( ATTR_VALIDDATA, nNewIndex ));
            }
            else if ( nAttrId == ATTR_VALUE_FORMAT && pDestDoc->GetFormatExchangeList() )
            {
                //  Number format to Exchange List

                sal_uInt32 nOldFormat = static_cast<const SfxUInt32Item*>(pSrcItem)->GetValue();
                SvNumberFormatterIndexTable::const_iterator it = pDestDoc->GetFormatExchangeList()->find(nOldFormat);
                if (it != pDestDoc->GetFormatExchangeList()->end())
                {
                    sal_uInt32 nNewFormat = it->second;
                    pNewItem.reset(new SfxUInt32Item( ATTR_VALUE_FORMAT, nNewFormat ));
                }
            }

            if ( pNewItem )
            {
                pDestSet->Put(std::move(pNewItem));
            }
            else
                pDestSet->Put(*pSrcItem);
        }
    }

    return CellAttributeHolder(pDestPattern, true);
}

bool ScPatternAttr::IsVisible() const
{
    if (!mxVisible.has_value())
        mxVisible = CalcVisible();
    return *mxVisible;
}

bool ScPatternAttr::CalcVisible() const
{
    const SfxItemSet& rSet = GetItemSet();

    if ( const SvxBrushItem* pItem = rSet.GetItemIfSet( ATTR_BACKGROUND ) )
        if ( pItem->GetColor() != COL_TRANSPARENT )
            return true;

    if ( const SvxBoxItem* pBoxItem = rSet.GetItemIfSet( ATTR_BORDER ) )
    {
        if ( pBoxItem->GetTop() || pBoxItem->GetBottom() ||
             pBoxItem->GetLeft() || pBoxItem->GetRight() )
            return true;
    }

    if ( const SvxLineItem* pItem = rSet.GetItemIfSet( ATTR_BORDER_TLBR ) )
        if( pItem->GetLine() )
            return true;

    if ( const SvxLineItem* pItem = rSet.GetItemIfSet( ATTR_BORDER_BLTR ) )
        if( pItem->GetLine() )
            return true;

    if ( const SvxShadowItem* pItem = rSet.GetItemIfSet( ATTR_SHADOW ) )
        if ( pItem->GetLocation() != SvxShadowLocation::NONE )
            return true;

    return false;
}

static bool OneEqual( const SfxItemSet& rSet1, const SfxItemSet& rSet2, sal_uInt16 nId )
{
    const SfxPoolItem* pItem1 = &rSet1.Get(nId);
    const SfxPoolItem* pItem2 = &rSet2.Get(nId);
    return ( pItem1 == pItem2 || *pItem1 == *pItem2 );
}

bool ScPatternAttr::IsVisibleEqual( const ScPatternAttr& rOther ) const
{
    const SfxItemSet& rThisSet = GetItemSet();
    const SfxItemSet& rOtherSet = rOther.GetItemSet();

    return OneEqual( rThisSet, rOtherSet, ATTR_BACKGROUND ) &&
            OneEqual( rThisSet, rOtherSet, ATTR_BORDER ) &&
            OneEqual( rThisSet, rOtherSet, ATTR_BORDER_TLBR ) &&
            OneEqual( rThisSet, rOtherSet, ATTR_BORDER_BLTR ) &&
            OneEqual( rThisSet, rOtherSet, ATTR_SHADOW );

    //TODO: also here only check really visible values !!!
}

const OUString* ScPatternAttr::GetStyleName() const
{
    return moName ? &*moName : ( pStyle ? &pStyle->GetName() : nullptr );
}

void ScPatternAttr::SetStyleSheet( ScStyleSheet* pNewStyle, bool bClearDirectFormat )
{
    if (pNewStyle)
    {
        SfxItemSet&       rPatternSet = GetItemSet();
        const SfxItemSet& rStyleSet = pNewStyle->GetItemSet();

        if (bClearDirectFormat)
        {
            for (sal_uInt16 i=ATTR_PATTERN_START; i<=ATTR_PATTERN_END; i++)
            {
                if (rStyleSet.GetItemState(i) == SfxItemState::SET)
                    rPatternSet.ClearItem(i);
            }
        }
        rPatternSet.SetParent(&pNewStyle->GetItemSet());
        pStyle = pNewStyle;
        moName.reset();
    }
    else
    {
        OSL_FAIL( "ScPatternAttr::SetStyleSheet( NULL ) :-|" );
        GetItemSet().SetParent(nullptr);
        pStyle = nullptr;
    }
    InvalidateCaches();
}

bool ScPatternAttr::UpdateStyleSheet(const ScDocument& rDoc)
{
    bool bNameChanged = false;
    if (moName)
    {
        pStyle = static_cast<ScStyleSheet*>(rDoc.GetStyleSheetPool()->Find(*moName, SfxStyleFamily::Para));

        //  use Standard if Style is not found,
        //  to avoid empty display in Toolbox-Controller
        //  Assumes that "Standard" is always the 1st entry!
        if (!pStyle)
        {
            std::unique_ptr<SfxStyleSheetIterator> pIter = rDoc.GetStyleSheetPool()->CreateIterator(SfxStyleFamily::Para);
            pStyle = dynamic_cast< ScStyleSheet* >(pIter->First());
        }

        if (pStyle)
        {
            GetItemSet().SetParent(&pStyle->GetItemSet());
            moName.reset();
        }
    }
    else
    {
        pStyle = nullptr;
        bNameChanged = true;
    }
    InvalidateCaches();
    return bNameChanged;
}

void ScPatternAttr::StyleToName()
{
    // Style was deleted, remember name:

    if ( pStyle )
    {
        moName = pStyle->GetName();
        pStyle = nullptr;
        GetItemSet().SetParent( nullptr );
        InvalidateCaches();
    }
}

bool ScPatternAttr::IsSymbolFont() const
{
    ifconst SvxFontItem* pItem = GetItemSet().GetItemIfSet( ATTR_FONT ) )
        return pItem->GetCharSet() == RTL_TEXTENCODING_SYMBOL;
    else
        return false;
}

namespace {

sal_uInt32 getNumberFormatKey(const SfxItemSet& rSet)
{
    return rSet.Get(ATTR_VALUE_FORMAT).GetValue();
}

LanguageType getLanguageType(const SfxItemSet& rSet)
{
    return rSet.Get(ATTR_LANGUAGE_FORMAT).GetLanguage();
}

}

bool ScPatternAttr::HasNumberFormat() const
{
    // If either ATTR_VALUE_FORMAT or ATTR_LANGUAGE_FORMAT are invalid in the pattern,
    // it means a multiselection with different formats
    return GetItemSet().GetItemState(ATTR_VALUE_FORMAT) != SfxItemState::INVALID
           && GetItemSet().GetItemState(ATTR_LANGUAGE_FORMAT) != SfxItemState::INVALID;
}

sal_uInt32 ScPatternAttr::GetNumberFormatKey() const
{
    if (!mxNumberFormatKey.has_value())
        mxNumberFormatKey = getNumberFormatKey(GetItemSet());
    return *mxNumberFormatKey;
}

LanguageType ScPatternAttr::GetLanguageType() const
{
    if (!mxLanguageType.has_value())
        mxLanguageType = getLanguageType(GetItemSet());
    return *mxLanguageType;
}

sal_uInt32 ScPatternAttr::GetNumberFormat( SvNumberFormatter* pFormatter ) const
{
    sal_uInt32 nFormat = GetNumberFormatKey();
    LanguageType eLang = GetLanguageType();
    if ( nFormat < SV_COUNTRY_LANGUAGE_OFFSET && eLang == LANGUAGE_SYSTEM )
        ;       // it remains as it is
    else if ( pFormatter )
        nFormat = pFormatter->GetFormatForLanguageIfBuiltIn( nFormat, eLang );
    return nFormat;
}

sal_uInt32 ScPatternAttr::GetNumberFormat( const ScInterpreterContext& rContext ) const
{
    sal_uInt32 nFormat = GetNumberFormatKey();
    LanguageType eLang = GetLanguageType();
    if ( nFormat < SV_COUNTRY_LANGUAGE_OFFSET && eLang == LANGUAGE_SYSTEM )
        ;       // it remains as it is
    else
        nFormat = rContext.NFGetFormatForLanguageIfBuiltIn( nFormat, eLang );
    return nFormat;
}

// the same if conditional formatting is in play:

sal_uInt32 ScPatternAttr::GetNumberFormat( SvNumberFormatter* pFormatter,
                                           const SfxItemSet* pCondSet ) const
{
    assert(pFormatter);
    if (!pCondSet || !pCondSet->HasItem(ATTR_VALUE_FORMAT))
        return GetNumberFormat(pFormatter);

    // Conditional format takes precedence over style and even hard format.

    sal_uInt32 nFormat = getNumberFormatKey(*pCondSet);
    LanguageType eLang = pCondSet->HasItem(ATTR_LANGUAGE_FORMAT) ? getLanguageType(*pCondSet)
                                                                 : GetLanguageType();

    return pFormatter->GetFormatForLanguageIfBuiltIn(nFormat, eLang);
}

sal_uInt32 ScPatternAttr::GetNumberFormat( const ScInterpreterContext& rContext,
                                           const SfxItemSet* pCondSet ) const
{
    if (!pCondSet || !pCondSet->HasItem(ATTR_VALUE_FORMAT))
        return GetNumberFormat(rContext);

    // Conditional format takes precedence over style and even hard format.

    sal_uInt32 nFormat = getNumberFormatKey(*pCondSet);
    LanguageType eLang = pCondSet->HasItem(ATTR_LANGUAGE_FORMAT) ? getLanguageType(*pCondSet)
                                                                 : GetLanguageType();

    return rContext.NFGetFormatForLanguageIfBuiltIn(nFormat, eLang);
}

const SfxPoolItem& ScPatternAttr::GetItem( sal_uInt16 nWhich, const SfxItemSet& ;rItemSet, const SfxItemSet* pCondSet )
{
    const SfxPoolItem* pCondItem;
    if ( pCondSet && pCondSet->GetItemState( nWhich, true, &pCondItem ) == SfxItemState::SET )
        return *pCondItem;
    return rItemSet.Get(nWhich);
}

const SfxPoolItem& ScPatternAttr::GetItem( sal_uInt16 nSubWhich, const SfxItemSet* pCondSet ) const
{
    return GetItem( nSubWhich, GetItemSet(), pCondSet );
}

//  GetRotateVal is tested before ATTR_ORIENTATION

--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=95 H=95 G=94

¤ Dauer der Verarbeitung: 0.20 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge