/* -*- 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 <memory>
#include "xmlcondformat.hxx"
#include <xmloff/nmspmap.hxx>
#include <xmloff/xmlnmspe.hxx>
#include <sal/log.hxx>
#include <colorscale.hxx>
#include <conditio.hxx>
#include <document.hxx>
#include <sax/tools/converter.hxx>
#include <rangelst.hxx>
#include <rangeutl.hxx>
#include <docfunc.hxx>
#include "XMLConverter.hxx"
#include <stylehelper.hxx>
#include <tokenarray.hxx>
using namespace xmloff::token;
ScXMLConditionalFormatsContext::ScXMLConditionalFormatsContext( ScXMLImport& rImport ):
ScXMLImportContext( rImport )
{
GetScImport().SetNewCondFormatData();
GetScImport().GetDocument()->SetCondFormList(new ScConditionalFormatList(), GetScImport().GetTables().GetCurrentSheet());
}
css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL ScXMLConditionalFormatsContext::createFastChildContext(
sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
{
SvXMLImportContext* pContext = nullptr;
sax_fastparser::FastAttributeList *pAttribList =
sax_fastparser::FastAttributeList::castToFastAttributeList( xAttrList );
switch (nElement)
{
case XML_ELEMENT( CALC_EXT, XML_CONDITIONAL_FORMAT ):
pContext = new ScXMLConditionalFormatContext( GetScImport(), pAttribList, *this );
break;
}
return pContext;
}
IMPL_LINK(ScXMLConditionalFormatsContext, FormatDeletedHdl, ScConditionalFormat*, pFormat, void)
{
mvCondFormatData.erase(std::remove_if(mvCondFormatData.begin(), mvCondFormatData.end(),
[pFormat](CondFormatData& r){ return r.mpFormat == pFormat; }),
mvCondFormatData.end());
}
void SAL_CALL ScXMLConditionalFormatsContext::endFastElement( sal_Int32 /*nElement*/ )
{
ScDocument* pDoc = GetScImport().GetDocument();
SCTAB nTab = GetScImport().GetTables().GetCurrentSheet();
ScConditionalFormatList* pCondFormatList = pDoc->GetCondFormList(nTab);
bool bDeleted = !pCondFormatList->CheckAllEntries(LINK(this, ScXMLConditionalFormatsContext, FormatDeletedHdl));
SAL_WARN_IF(bDeleted, "sc", "conditional formats have been deleted because they contained empty range info");
for (const auto& i : mvCondFormatData)
{
pDoc->AddCondFormatData( i.mpFormat->GetRange(), i.mnTab, i.mpFormat->GetKey() );
}
}
ScXMLConditionalFormatContext::ScXMLConditionalFormatContext( ScXMLImport& rImport,
const rtl::Reference<sax_fastparser::FastAttributeList>& rAttrList,
ScXMLConditionalFormatsContext& rParent ):
ScXMLImportContext( rImport ),
mrParent( rParent )
{
OUString sRange;
if ( rAttrList.is() )
{
for (auto &aIter : *rAttrList)
{
switch (aIter.getToken())
{
case XML_ELEMENT( CALC_EXT, XML_TARGET_RANGE_ADDRESS ):
sRange = aIter.toString();
break;
default:
break;
}
}
}
ScRangeList aRangeList;
ScRangeStringConverter::GetRangeListFromString(aRangeList, sRange, GetScImport().GetDocument(),
formula::FormulaGrammar::CONV_ODF);
mxFormat.reset(new ScConditionalFormat(0, GetScImport().GetDocument()));
mxFormat->SetRange(aRangeList);
}
css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL ScXMLConditionalFormatContext::createFastChildContext(
sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
{
SvXMLImportContext* pContext = nullptr;
sax_fastparser::FastAttributeList *pAttribList =
sax_fastparser::FastAttributeList::castToFastAttributeList( xAttrList );
switch (nElement)
{
case XML_ELEMENT( CALC_EXT, XML_CONDITION ):
pContext = new ScXMLCondContext( GetScImport(), pAttribList, mxFormat.get() );
break;
case XML_ELEMENT( CALC_EXT, XML_COLOR_SCALE ):
pContext = new ScXMLColorScaleFormatContext( GetScImport(), mxFormat.get() );
break;
case XML_ELEMENT( CALC_EXT, XML_DATA_BAR ):
pContext = new ScXMLDataBarFormatContext( GetScImport(), pAttribList, mxFormat.get() );
break;
case XML_ELEMENT( CALC_EXT, XML_ICON_SET ):
pContext = new ScXMLIconSetFormatContext( GetScImport(), pAttribList, mxFormat.get() );
break;
case XML_ELEMENT( CALC_EXT, XML_DATE_IS ):
pContext = new ScXMLDateContext( GetScImport(), pAttribList, mxFormat.get() );
break;
default:
break;
}
return pContext;
}
static bool HasRelRefIgnoringSheet0Relative( ScDocument* pDoc, const ScTokenArray* pTokens, sal_uInt16 nRecursion = 0 )
{
if (pTokens)
{
formula::FormulaTokenArrayPlainIterator aIter( *pTokens );
formula::FormulaToken* t;
for( t = aIter.Next(); t; t = aIter.Next() )
{
switch( t->GetType() )
{
case formula::svDoubleRef:
{
ScSingleRefData& rRef2 = t->GetDoubleRef()->Ref2;
if ( rRef2.IsColRel() || rRef2.IsRowRel() || (rRef2.IsFlag3D() && rRef2.IsTabRel()) )
return true;
SAL_FALLTHROUGH;
}
case formula::svSingleRef:
{
ScSingleRefData& rRef1 = *t->GetSingleRef();
if ( rRef1.IsColRel() || rRef1.IsRowRel() || (rRef1.IsFlag3D() && rRef1.IsTabRel()) )
return true;
}
break;
case formula::svIndex:
{
if( t->GetOpCode() == ocName ) // DB areas always absolute
if( ScRangeData* pRangeData = pDoc->FindRangeNameBySheetAndIndex( t->GetSheet(), t->GetIndex()) )
if( (nRecursion < 42) && HasRelRefIgnoringSheet0Relative( pDoc, pRangeData->GetCode(), nRecursion + 1 ) )
return true;
}
break;
// #i34474# function result dependent on cell position
case formula::svByte:
{
switch( t->GetOpCode() )
{
case ocRow: // ROW() returns own row index
case ocColumn: // COLUMN() returns own column index
case ocSheet: // SHEET() returns own sheet index
case ocCell: // CELL() may return own cell address
return true;
default:
break;
}
}
break;
default:
break;
}
}
}
return false;
}
static bool HasOneSingleFullyRelativeReference( const ScTokenArray* pTokens, ScSingleRefData& rOffset )
{
int nCount = 0;
if (pTokens)
{
formula::FormulaTokenArrayPlainIterator aIter( *pTokens );
formula::FormulaToken* t;
for( t = aIter.Next(); t; t = aIter.Next() )
{
switch( t->GetType() )
{
case formula::svSingleRef:
{
ScSingleRefData& rRef1 = *t->GetSingleRef();
if ( rRef1.IsColRel() && rRef1.IsRowRel() && !rRef1.IsFlag3D() && rRef1.IsTabRel() )
{
nCount++;
if (nCount == 1)
{
rOffset = rRef1;
}
}
}
break;
default:
break;
}
}
}
return nCount == 1;
}
void SAL_CALL ScXMLConditionalFormatContext::endFastElement( sal_Int32 /*nElement*/ )
{
ScDocument* pDoc = GetScImport().GetDocument();
SCTAB nTab = GetScImport().GetTables().GetCurrentSheet();
std::unique_ptr<ScConditionalFormat> pFormat(std::move(mxFormat));
bool bEligibleForCache = true;
bool bSingleRelativeReference = false;
ScSingleRefData aOffsetForSingleRelRef;
const ScTokenArray* pTokens = nullptr;
for (size_t nFormatEntryIx = 0; nFormatEntryIx < pFormat->size(); ++nFormatEntryIx)
{
auto pFormatEntry = pFormat->GetEntry(nFormatEntryIx);
auto pCondFormatEntry = dynamic_cast<const ScCondFormatEntry*>(pFormatEntry);
if (pCondFormatEntry == nullptr ||
(pCondFormatEntry->GetOperation() != ScConditionMode::Equal &&
pCondFormatEntry->GetOperation() != ScConditionMode::Direct))
{
bEligibleForCache = false;
break;
}
ScAddress aSrcPos;
OUString aSrcString = pCondFormatEntry->GetSrcString();
if ( !aSrcString.isEmpty() )
aSrcPos.Parse( aSrcString, pDoc );
ScCompiler aComp( pDoc, aSrcPos );
aComp.SetGrammar( formula::FormulaGrammar::GRAM_ODFF );
pTokens = aComp.CompileString( pCondFormatEntry->GetExpression(aSrcPos, 0), "" );
if (HasRelRefIgnoringSheet0Relative( pDoc, pTokens ))
{
// In general not eligible, but some might be. We handle one very special case: When the
// conditional format has one entry, the reference position is the first cell of the
// range, and with a single fully relative reference in its expression. (Possibly these
// conditions could be loosened, but I am too tired to think on that right now.)
if (pFormat->size() == 1 &&
pFormat->GetRange().size() == 1 &&
pFormat->GetRange()[0].aStart == aSrcPos &&
HasOneSingleFullyRelativeReference( pTokens, aOffsetForSingleRelRef ))
{
bSingleRelativeReference = true;
}
else
{
bEligibleForCache = false;
break;
}
}
}
if (bEligibleForCache)
{
for (auto& aCacheEntry : mrParent.maCache)
if (aCacheEntry.mnAge < SAL_MAX_INT64)
aCacheEntry.mnAge++;
for (auto& aCacheEntry : mrParent.maCache)
{
if (!aCacheEntry.mpFormat)
continue;
if (aCacheEntry.mpFormat->size() != pFormat->size())
continue;
// Check if the conditional format is identical to an existing one (but with different range) and can be shared
for (size_t nFormatEntryIx = 0; nFormatEntryIx < pFormat->size(); ++nFormatEntryIx)
{
auto pCacheFormatEntry = aCacheEntry.mpFormat->GetEntry(nFormatEntryIx);
auto pFormatEntry = pFormat->GetEntry(nFormatEntryIx);
if (pCacheFormatEntry->GetType() != pFormatEntry->GetType() ||
pFormatEntry->GetType() != ScFormatEntry::Type::Condition)
break;
auto pCacheCondFormatEntry = static_cast<const ScCondFormatEntry*>(pCacheFormatEntry);
auto pCondFormatEntry = static_cast<const ScCondFormatEntry*>(pFormatEntry);
if (pCacheCondFormatEntry->GetStyle() != pCondFormatEntry->GetStyle())
break;
// Note That comparing the formulas of the ScConditionEntry at this stage is
// comparing just the *strings* of the formulas. For the bSingleRelativeReference
// case we compare the tokenized ("compiled") formulas.
if (bSingleRelativeReference)
{
if (aCacheEntry.mbSingleRelativeReference &&
pTokens->EqualTokens(aCacheEntry.mpTokens.get()))
;
else
break;
}
else if (!pCacheCondFormatEntry->IsEqual(*pCondFormatEntry, /*bIgnoreSrcPos*/true))
{
break;
}
// If we get here on the last round through the for loop, we have a cache hit
if (nFormatEntryIx == pFormat->size() - 1)
{
// Mark cache entry as fresh, do necessary mangling of it and just return
aCacheEntry.mnAge = 0;
for (size_t k = 0; k < pFormat->GetRange().size(); ++k)
aCacheEntry.mpFormat->GetRangeList().Join(pFormat->GetRange()[k]);
return;
}
}
}
}
sal_uLong nIndex = pDoc->AddCondFormat(pFormat.release(), nTab);
ScConditionalFormat* pInsertedFormat = pDoc->GetCondFormList(nTab)->GetFormat(nIndex);
assert(pInsertedFormat && pInsertedFormat->GetKey() == nIndex);
mrParent.mvCondFormatData.push_back( { pInsertedFormat, nTab } );
if (bEligibleForCache)
{
// Not found in cache, replace oldest cache entry
sal_Int64 nOldestAge = -1;
size_t nIndexOfOldest = 0;
for (auto& aCacheEntry : mrParent.maCache)
{
if (aCacheEntry.mnAge > nOldestAge)
{
nOldestAge = aCacheEntry.mnAge;
nIndexOfOldest = (&aCacheEntry - &mrParent.maCache.front());
}
}
mrParent.maCache[nIndexOfOldest].mpFormat = pInsertedFormat;
mrParent.maCache[nIndexOfOldest].mbSingleRelativeReference = bSingleRelativeReference;
mrParent.maCache[nIndexOfOldest].mpTokens.reset(pTokens);
mrParent.maCache[nIndexOfOldest].mnAge = 0;
}
}
ScXMLConditionalFormatContext::~ScXMLConditionalFormatContext()
{
}
ScXMLColorScaleFormatContext::ScXMLColorScaleFormatContext( ScXMLImport& rImport,
ScConditionalFormat* pFormat):
ScXMLImportContext( rImport ),
pColorScaleFormat(nullptr)
{
pColorScaleFormat = new ScColorScaleFormat(GetScImport().GetDocument());
pFormat->AddEntry(pColorScaleFormat);
}
css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL ScXMLColorScaleFormatContext::createFastChildContext(
sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
{
SvXMLImportContext* pContext = nullptr;
sax_fastparser::FastAttributeList *pAttribList =
sax_fastparser::FastAttributeList::castToFastAttributeList( xAttrList );
switch (nElement)
{
case XML_ELEMENT( CALC_EXT, XML_COLOR_SCALE_ENTRY ):
pContext = new ScXMLColorScaleFormatEntryContext( GetScImport(), pAttribList, pColorScaleFormat );
break;
default:
break;
}
return pContext;
}
ScXMLDataBarFormatContext::ScXMLDataBarFormatContext( ScXMLImport& rImport,
const rtl::Reference<sax_fastparser::FastAttributeList>& rAttrList,
ScConditionalFormat* pFormat):
ScXMLImportContext( rImport ),
mpFormatData(nullptr),
mpParent(pFormat),
mnIndex(0)
{
OUString sPositiveColor;
OUString sNegativeColor;
OUString sGradient;
OUString sAxisPosition;
OUString sShowValue;
OUString sAxisColor;
OUString sMinLength;
OUString sMaxLength;
if ( rAttrList.is() )
{
for (auto &aIter : *rAttrList)
{
switch (aIter.getToken())
{
case XML_ELEMENT( CALC_EXT, XML_POSITIVE_COLOR ):
sPositiveColor = aIter.toString();
break;
case XML_ELEMENT( CALC_EXT, XML_GRADIENT ):
sGradient = aIter.toString();
break;
case XML_ELEMENT( CALC_EXT, XML_NEGATIVE_COLOR ):
sNegativeColor = aIter.toString();
break;
case XML_ELEMENT( CALC_EXT, XML_AXIS_POSITION ):
sAxisPosition = aIter.toString();
break;
case XML_ELEMENT( CALC_EXT, XML_SHOW_VALUE ):
sShowValue = aIter.toString();
break;
case XML_ELEMENT( CALC_EXT, XML_AXIS_COLOR ):
sAxisColor = aIter.toString();
break;
case XML_ELEMENT( CALC_EXT, XML_MIN_LENGTH ):
sMinLength = aIter.toString();
break;
case XML_ELEMENT( CALC_EXT, XML_MAX_LENGTH ):
sMaxLength = aIter.toString();
break;
default:
break;
}
}
}
ScDataBarFormat* pDataBarFormat = new ScDataBarFormat(rImport.GetDocument());
mpFormatData = new ScDataBarFormatData();
pDataBarFormat->SetDataBarData(mpFormatData);
if(!sGradient.isEmpty())
{
bool bGradient = true;
(void)sax::Converter::convertBool( bGradient, sGradient);
mpFormatData->mbGradient = bGradient;
}
if(!sPositiveColor.isEmpty())
{
sax::Converter::convertColor( mpFormatData->maPositiveColor, sPositiveColor );
}
if(!sNegativeColor.isEmpty())
{
// we might check here for 0xff0000 and don't write it
Color nColor;
sax::Converter::convertColor( nColor, sNegativeColor );
mpFormatData->mpNegativeColor.reset(new Color(nColor));
}
else
mpFormatData->mbNeg = false;
if(!sAxisPosition.isEmpty())
{
if(sAxisPosition == "middle")
mpFormatData->meAxisPosition = databar::MIDDLE;
else if (sAxisPosition == "none")
mpFormatData->meAxisPosition = databar::NONE;
}
if(!sAxisColor.isEmpty())
{
sax::Converter::convertColor( mpFormatData->maAxisColor, sAxisColor );
}
if(!sShowValue.isEmpty())
{
bool bShowValue = true;
(void)sax::Converter::convertBool( bShowValue, sShowValue );
mpFormatData->mbOnlyBar = !bShowValue;
}
if (!sMinLength.isEmpty())
{
double nVal = sMinLength.toDouble();
mpFormatData->mnMinLength = nVal;
}
if (!sMaxLength.isEmpty())
{
double nVal = sMaxLength.toDouble();
if (nVal == 0.0)
nVal = 100.0;
mpFormatData->mnMaxLength = nVal;
}
pFormat->AddEntry(pDataBarFormat);
}
css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL ScXMLDataBarFormatContext::createFastChildContext(
sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
{
SvXMLImportContext* pContext = nullptr;
sax_fastparser::FastAttributeList *pAttribList =
sax_fastparser::FastAttributeList::castToFastAttributeList( xAttrList );
switch (nElement)
{
case XML_ELEMENT( CALC_EXT, XML_FORMATTING_ENTRY ):
case XML_ELEMENT( CALC_EXT, XML_DATA_BAR_ENTRY ):
{
ScColorScaleEntry* pEntry(nullptr);
pContext = new ScXMLFormattingEntryContext( GetScImport(), pAttribList, pEntry );
pEntry->SetRepaintCallback(mpParent);
if(mnIndex == 0)
{
mpFormatData->mpLowerLimit.reset(pEntry);
}
else if (mnIndex == 1)
{
mpFormatData->mpUpperLimit.reset(pEntry);
}
else
{
// data bars only support 2 entries
assert(false);
}
++mnIndex;
}
break;
default:
break;
}
return pContext;
}
ScXMLIconSetFormatContext::ScXMLIconSetFormatContext(ScXMLImport& rImport,
const rtl::Reference<sax_fastparser::FastAttributeList>& rAttrList,
ScConditionalFormat* pFormat):
ScXMLImportContext( rImport ),
mpParent(pFormat)
{
OUString aIconSetType, sShowValue;
if ( rAttrList.is() )
{
for (auto &aIter : *rAttrList)
{
switch (aIter.getToken())
{
case XML_ELEMENT( CALC_EXT, XML_ICON_SET_TYPE ):
aIconSetType = aIter.toString();
break;
case XML_ELEMENT( CALC_EXT, XML_SHOW_VALUE ):
sShowValue = aIter.toString();
break;
default:
break;
}
}
}
const ScIconSetMap* pMap = ScIconSetFormat::g_IconSetMap;
ScIconSetType eType = IconSet_3Arrows;
for(; pMap->pName; ++pMap)
{
OUString aName = OUString::createFromAscii(pMap->pName);
if(aName ==aIconSetType)
{
eType = pMap->eType;
break;
}
}
ScIconSetFormat* pIconSetFormat = new ScIconSetFormat(GetScImport().GetDocument());
ScIconSetFormatData* pIconSetFormatData = new ScIconSetFormatData;
if(!sShowValue.isEmpty())
{
bool bShowValue = true;
(void)sax::Converter::convertBool( bShowValue, sShowValue );
pIconSetFormatData->mbShowValue = !bShowValue;
}
pIconSetFormatData->eIconSetType = eType;
pIconSetFormat->SetIconSetData(pIconSetFormatData);
pFormat->AddEntry(pIconSetFormat);
mpFormatData = pIconSetFormatData;
}
css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL ScXMLIconSetFormatContext::createFastChildContext(
sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
{
SvXMLImportContext* pContext = nullptr;
sax_fastparser::FastAttributeList *pAttribList =
sax_fastparser::FastAttributeList::castToFastAttributeList( xAttrList );
switch (nElement)
{
case XML_ELEMENT( CALC_EXT, XML_FORMATTING_ENTRY ):
{
ScColorScaleEntry* pEntry(nullptr);
pContext = new ScXMLFormattingEntryContext( GetScImport(), pAttribList, pEntry );
mpFormatData->m_Entries.push_back(std::unique_ptr<ScColorScaleEntry>(pEntry));
pEntry->SetRepaintCallback(mpParent);
}
break;
default:
break;
}
return pContext;
}
namespace {
void GetConditionData(const OUString& rValue, ScConditionMode& eMode, OUString& rExpr1, OUString& rExpr2)
{
if(rValue.startsWith("unique"))
{
eMode = ScConditionMode::NotDuplicate;
}
else if(rValue.startsWith("duplicate"))
{
eMode = ScConditionMode::Duplicate;
}
else if(rValue.startsWith("between"))
{
const sal_Unicode* pStr = rValue.getStr();
const sal_Unicode* pStart = pStr + 8;
const sal_Unicode* pEnd = pStr + rValue.getLength();
rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ',');
rExpr2 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
eMode = ScConditionMode::Between;
}
else if(rValue.startsWith("not-between"))
{
const sal_Unicode* pStr = rValue.getStr();
const sal_Unicode* pStart = pStr + 12;
const sal_Unicode* pEnd = pStr + rValue.getLength();
rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ',');
rExpr2 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
eMode = ScConditionMode::NotBetween;
}
else if(rValue.startsWith("<="))
{
rExpr1 = rValue.copy(2);
eMode = ScConditionMode::EqLess;
}
else if(rValue.startsWith(">="))
{
rExpr1 = rValue.copy(2);
eMode = ScConditionMode::EqGreater;
}
else if(rValue.startsWith("!="))
{
rExpr1 = rValue.copy(2);
eMode = ScConditionMode::NotEqual;
}
else if(rValue.startsWith("<"))
{
rExpr1 = rValue.copy(1);
eMode = ScConditionMode::Less;
}
else if(rValue.startsWith("="))
{
rExpr1 = rValue.copy(1);
eMode = ScConditionMode::Equal;
}
else if(rValue.startsWith(">"))
{
rExpr1 = rValue.copy(1);
eMode = ScConditionMode::Greater;
}
else if(rValue.startsWith("formula-is"))
{
const sal_Unicode* pStr = rValue.getStr();
const sal_Unicode* pStart = pStr + 11;
const sal_Unicode* pEnd = pStr + rValue.getLength();
rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
eMode = ScConditionMode::Direct;
}
else if(rValue.startsWith("top-elements"))
{
const sal_Unicode* pStr = rValue.getStr();
const sal_Unicode* pStart = pStr + 13;
const sal_Unicode* pEnd = pStr + rValue.getLength();
rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
eMode = ScConditionMode::Top10;
}
else if(rValue.startsWith("bottom-elements"))
{
const sal_Unicode* pStr = rValue.getStr();
const sal_Unicode* pStart = pStr + 16;
const sal_Unicode* pEnd = pStr + rValue.getLength();
rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
eMode = ScConditionMode::Bottom10;
}
else if(rValue.startsWith("top-percent"))
{
const sal_Unicode* pStr = rValue.getStr();
const sal_Unicode* pStart = pStr + 12;
const sal_Unicode* pEnd = pStr + rValue.getLength();
rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
eMode = ScConditionMode::TopPercent;
}
else if(rValue.startsWith("bottom-percent"))
{
const sal_Unicode* pStr = rValue.getStr();
const sal_Unicode* pStart = pStr + 15;
const sal_Unicode* pEnd = pStr + rValue.getLength();
rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
eMode = ScConditionMode::BottomPercent;
}
else if(rValue.startsWith("above-average"))
{
eMode = ScConditionMode::AboveAverage;
}
else if(rValue.startsWith("below-average"))
{
eMode = ScConditionMode::BelowAverage;
}
else if(rValue.startsWith("above-equal-average"))
{
eMode = ScConditionMode::AboveEqualAverage;
}
else if(rValue.startsWith("below-equal-average"))
{
eMode = ScConditionMode::BelowEqualAverage;
}
else if(rValue.startsWith("is-error"))
{
eMode = ScConditionMode::Error;
}
else if(rValue.startsWith("is-no-error"))
{
eMode = ScConditionMode::NoError;
}
else if(rValue.startsWith("begins-with"))
{
eMode = ScConditionMode::BeginsWith;
const sal_Unicode* pStr = rValue.getStr();
const sal_Unicode* pStart = pStr + 12;
const sal_Unicode* pEnd = pStr + rValue.getLength();
rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
}
else if(rValue.startsWith("ends-with"))
{
eMode = ScConditionMode::EndsWith;
const sal_Unicode* pStr = rValue.getStr();
const sal_Unicode* pStart = pStr + 10;
const sal_Unicode* pEnd = pStr + rValue.getLength();
rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
}
else if(rValue.startsWith("contains-text"))
{
eMode = ScConditionMode::ContainsText;
const sal_Unicode* pStr = rValue.getStr();
const sal_Unicode* pStart = pStr + 14;
const sal_Unicode* pEnd = pStr + rValue.getLength();
rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
}
else if(rValue.startsWith("not-contains-text"))
{
eMode = ScConditionMode::NotContainsText;
const sal_Unicode* pStr = rValue.getStr();
const sal_Unicode* pStart = pStr + 18;
const sal_Unicode* pEnd = pStr + rValue.getLength();
rExpr1 = ScXMLConditionHelper::getExpression( pStart, pEnd, ')');
}
else
eMode = ScConditionMode::NONE;
}
}
ScXMLCondContext::ScXMLCondContext( ScXMLImport& rImport,
const rtl::Reference<sax_fastparser::FastAttributeList>& rAttrList,
ScConditionalFormat* pFormat ):
ScXMLImportContext( rImport )
{
OUString sExpression;
OUString sStyle;
OUString sAddress;
if ( rAttrList.is() )
{
for (auto &aIter : *rAttrList)
{
switch (aIter.getToken())
{
case XML_ELEMENT( CALC_EXT, XML_VALUE ):
sExpression = aIter.toString();
break;
case XML_ELEMENT( CALC_EXT, XML_APPLY_STYLE_NAME ):
sStyle = ScStyleNameConversion::ProgrammaticToDisplayName(aIter.toString(), SfxStyleFamily::Para );
break;
case XML_ELEMENT( CALC_EXT, XML_BASE_CELL_ADDRESS ):
sAddress = aIter.toString();
break;
default:
break;
}
}
}
OUString aExpr1;
OUString aExpr2;
ScConditionMode eMode;
GetConditionData(sExpression, eMode, aExpr1, aExpr2);
ScCondFormatEntry* pFormatEntry = new ScCondFormatEntry(eMode, aExpr1, aExpr2, GetScImport().GetDocument(), ScAddress(), sStyle,
OUString(), OUString(), formula::FormulaGrammar::GRAM_ODFF, formula::FormulaGrammar::GRAM_ODFF);
pFormatEntry->SetSrcString(sAddress);
pFormat->AddEntry(pFormatEntry);
}
namespace {
void setColorEntryType(const OUString& rType, ScColorScaleEntry* pEntry, const OUString& rFormula,
ScXMLImport& rImport)
{
if(rType == "minimum")
pEntry->SetType(COLORSCALE_MIN);
else if(rType == "maximum")
pEntry->SetType(COLORSCALE_MAX);
else if(rType == "percentile")
pEntry->SetType(COLORSCALE_PERCENTILE);
else if(rType == "percent")
pEntry->SetType(COLORSCALE_PERCENT);
else if(rType == "formula")
{
pEntry->SetType(COLORSCALE_FORMULA);
//position does not matter, only table is important
pEntry->SetFormula(rFormula, rImport.GetDocument(), ScAddress(0,0,rImport.GetTables().GetCurrentSheet()), formula::FormulaGrammar::GRAM_ODFF);
}
else if(rType == "auto-minimum")
pEntry->SetType(COLORSCALE_AUTO);
else if(rType == "auto-maximum")
pEntry->SetType(COLORSCALE_AUTO);
}
}
ScXMLColorScaleFormatEntryContext::ScXMLColorScaleFormatEntryContext( ScXMLImport& rImport,
const rtl::Reference<sax_fastparser::FastAttributeList>& rAttrList,
ScColorScaleFormat* pFormat):
ScXMLImportContext( rImport )
{
double nVal = 0;
Color aColor;
OUString sType;
OUString sVal;
OUString sColor;
if ( rAttrList.is() )
{
for (auto &aIter : *rAttrList)
{
switch (aIter.getToken())
{
case XML_ELEMENT( CALC_EXT, XML_TYPE ):
sType = aIter.toString();
break;
case XML_ELEMENT( CALC_EXT, XML_VALUE ):
sVal = aIter.toString();
break;
case XML_ELEMENT( CALC_EXT, XML_COLOR ):
sColor = aIter.toString();
break;
default:
break;
}
}
}
sax::Converter::convertColor(aColor, sColor);
if(!sVal.isEmpty())
sax::Converter::convertDouble(nVal, sVal);
auto pFormatEntry = new ScColorScaleEntry(nVal, aColor);
setColorEntryType(sType, pFormatEntry, sVal, GetScImport());
pFormat->AddEntry(pFormatEntry);
}
ScXMLFormattingEntryContext::ScXMLFormattingEntryContext( ScXMLImport& rImport,
const rtl::Reference<sax_fastparser::FastAttributeList>& rAttrList,
ScColorScaleEntry*& pColorScaleEntry):
ScXMLImportContext( rImport )
{
OUString sVal;
OUString sType;
if ( rAttrList.is() )
{
for (auto &aIter : *rAttrList)
{
switch (aIter.getToken())
{
case XML_ELEMENT( CALC_EXT, XML_TYPE ):
sType = aIter.toString();
break;
case XML_ELEMENT( CALC_EXT, XML_VALUE ):
sVal = aIter.toString();
break;
default:
break;
}
}
}
double nVal = 0;
if(!sVal.isEmpty())
sax::Converter::convertDouble(nVal, sVal);
pColorScaleEntry = new ScColorScaleEntry(nVal, Color());
setColorEntryType(sType, pColorScaleEntry, sVal, GetScImport());
}
namespace {
condformat::ScCondFormatDateType getDateFromString(const OUString& rString)
{
if(rString == "today")
return condformat::TODAY;
else if(rString == "yesterday")
return condformat::YESTERDAY;
else if(rString == "tomorrow")
return condformat::TOMORROW;
else if(rString == "last-7-days")
return condformat::LAST7DAYS;
else if(rString == "this-week")
return condformat::THISWEEK;
else if(rString == "last-week")
return condformat::LASTWEEK;
else if(rString == "next-week")
return condformat::NEXTWEEK;
else if(rString == "this-month")
return condformat::THISMONTH;
else if(rString == "last-month")
return condformat::LASTMONTH;
else if(rString == "next-month")
return condformat::NEXTMONTH;
else if(rString == "this-year")
return condformat::THISYEAR;
else if(rString == "last-year")
return condformat::LASTYEAR;
else if(rString == "next-year")
return condformat::NEXTYEAR;
SAL_WARN("sc", "unknown date type: " << rString);
return condformat::TODAY;
}
}
ScXMLDateContext::ScXMLDateContext( ScXMLImport& rImport,
const rtl::Reference<sax_fastparser::FastAttributeList>& rAttrList,
ScConditionalFormat* pFormat ):
ScXMLImportContext( rImport )
{
OUString sDateType, sStyle;
if ( rAttrList.is() )
{
for (auto &aIter : *rAttrList)
{
switch (aIter.getToken())
{
case XML_ELEMENT( CALC_EXT, XML_DATE ):
sDateType = aIter.toString();
break;
case XML_ELEMENT( CALC_EXT, XML_STYLE ):
sStyle = ScStyleNameConversion::ProgrammaticToDisplayName(aIter.toString(), SfxStyleFamily::Para );
break;
default:
break;
}
}
}
ScCondDateFormatEntry* pFormatEntry = new ScCondDateFormatEntry(GetScImport().GetDocument());
pFormatEntry->SetStyleName(sStyle);
pFormatEntry->SetDateType(getDateFromString(sDateType));
pFormat->AddEntry(pFormatEntry);
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V730 Not all members of a class are initialized inside the constructor. Consider inspecting: maCache.