/* -*- 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 <extlstcontext.hxx>
#include <worksheethelper.hxx>
#include <oox/core/contexthandler.hxx>
#include <oox/helper/attributelist.hxx>
#include <oox/token/namespaces.hxx>
#include <oox/token/tokens.hxx>
#include <colorscale.hxx>
#include <condformatbuffer.hxx>
#include <condformatcontext.hxx>
#include <document.hxx>
#include <worksheetfragment.hxx>
#include <workbookfragment.hxx>
#include <stylesbuffer.hxx>
#include <stylesfragment.hxx>
#include <SparklineFragment.hxx>
#include <rangeutl.hxx>
#include <sal/log.hxx>
using ::oox::core::ContextHandlerRef;
using ::oox::xls::CondFormatBuffer;
sal_Int32 gnStyleIdx = 0; // Holds index of the <extlst> <cfRule> style (Will be reset by finalize import)
namespace oox::xls {
ExtCfRuleContext::ExtCfRuleContext( WorksheetContextBase& rFragment, ScDataBarFormatData* pTarget ):
WorksheetContextBase( rFragment ),
mpTarget( pTarget ),
mbFirstEntry(true)
{
}
ContextHandlerRef ExtCfRuleContext::onCreateContext( sal_Int32 , const AttributeList& )
{
return this;
}
void ExtCfRuleContext::onStartElement( const AttributeList& rAttribs )
{
switch( getCurrentElement() )
{
case XLS14_TOKEN( dataBar ):
{
ExtCfDataBarRuleRef xRule = getCondFormats().createExtCfDataBarRule(mpTarget);
xRule->importDataBar( rAttribs );
break;
}
case XLS14_TOKEN( fillColor ):
{
ExtCfDataBarRuleRef xRule = getCondFormats().createExtCfDataBarRule(mpTarget);
xRule->importPositiveFillColor( rAttribs );
break;
}
case XLS14_TOKEN( negativeFillColor ):
{
ExtCfDataBarRuleRef xRule = getCondFormats().createExtCfDataBarRule(mpTarget);
xRule->importNegativeFillColor( rAttribs );
break;
}
case XLS14_TOKEN( axisColor ):
{
ExtCfDataBarRuleRef xRule = getCondFormats().createExtCfDataBarRule(mpTarget);
xRule->importAxisColor( rAttribs );
break;
}
case XLS14_TOKEN( cfvo ):
{
ExtCfDataBarRuleRef xRule = getCondFormats().createExtCfDataBarRule(mpTarget);
xRule->importCfvo( rAttribs );
xRule->getModel().mbIsLower = mbFirstEntry;
mbFirstEntry = false;
mpRule = std::move(xRule);
break;
}
default:
break;
}
}
void ExtCfRuleContext::onCharacters( const OUString& rChars )
{
switch( getCurrentElement() )
{
case XM_TOKEN( f ):
{
if (mpRule)
{
mpRule->getModel().msScaleTypeValue = rChars;
}
}
break;
}
}
void ExtCfRuleContext::onEndElement()
{
switch( getCurrentElement() )
{
case XLS14_TOKEN( cfvo ):
{
mpRule.reset();
break;
}
}
}
namespace {
bool IsSpecificTextCondMode(ScConditionMode eMode)
{
switch (eMode)
{
case ScConditionMode::BeginsWith:
case ScConditionMode::EndsWith:
case ScConditionMode::ContainsText:
case ScConditionMode::NotContainsText:
return true;
default:
break;
}
return false;
}
}
ExtConditionalFormattingContext::ExtConditionalFormattingContext(WorksheetContextBase& rFragment)
: WorksheetContextBase(rFragment)
, nFormulaCount(0)
, nPriority(-1)
, eOperator(ScConditionMode::NONE)
, isPreviousElementF(false)
{
}
ContextHandlerRef ExtConditionalFormattingContext::onCreateContext(sal_Int32 nElement, const AttributeList& rAttribs)
{
if (mpCurrentRule)
{
ScFormatEntry& rFormat = **maEntries.rbegin();
assert(rFormat.GetType() == ScFormatEntry::Type::Iconset);
ScIconSetFormat& rIconSet = static_cast<ScIconSetFormat&>(rFormat);
ScDocument& rDoc = getScDocument();
SCTAB nTab = getSheetIndex();
ScAddress aPos(0, 0, nTab);
mpCurrentRule->SetData(&rIconSet, &rDoc, aPos);
mpCurrentRule.reset();
}
if (nElement == XLS14_TOKEN(cfRule))
{
OUString aType = rAttribs.getString(XML_type, OUString());
OUString aId = rAttribs.getString(XML_id, OUString());
nPriority = rAttribs.getInteger( XML_priority, -1 );
maPriorities.push_back(nPriority);
maModel.nPriority = nPriority;
if (aType == "dataBar")
{
// an ext entry does not need to have an existing corresponding entry
ScDataBarFormatData* pInfo;
ExtLst::const_iterator aExt = getExtLst().find( aId );
if (aExt == getExtLst().end())
{
pInfo = new ScDataBarFormatData();
auto pFormat = std::make_unique<ScDataBarFormat>(&getScDocument());
pFormat->SetDataBarData(pInfo);
getCondFormats().importExtFormatEntries().push_back(std::move(pFormat));
}
else
{
pInfo = aExt->second;
}
if (!pInfo)
{
return nullptr;
}
return new ExtCfRuleContext( *this, pInfo );
}
else if (aType == "iconSet")
{
ScDocument& rDoc = getScDocument();
mpCurrentRule.reset(new IconSetRule(*this));
maEntries.push_back(std::make_unique<ScIconSetFormat>(&rDoc));
return new IconSetContext(*this, mpCurrentRule.get());
}
else if (aType == "cellIs")
{
sal_Int32 aToken = rAttribs.getToken( XML_operator, XML_TOKEN_INVALID );
eOperator = CondFormatBuffer::convertToInternalOperator(aToken);
maModel.eOperator = eOperator;
return this;
}
else if (aType == "containsText")
{
eOperator = ScConditionMode::ContainsText;
maModel.eOperator = eOperator;
return this;
}
else if (aType == "notContainsText")
{
eOperator = ScConditionMode::NotContainsText;
maModel.eOperator = eOperator;
return this;
}
else if (aType == "beginsWith")
{
eOperator = ScConditionMode::BeginsWith;
maModel.eOperator = eOperator;
return this;
}
else if (aType == "endsWith")
{
eOperator = ScConditionMode::EndsWith;
maModel.eOperator = eOperator;
return this;
}
else if (aType == "expression")
{
eOperator = ScConditionMode::Direct;
maModel.eOperator = eOperator;
return this;
}
else
{
SAL_WARN("sc", "unhandled XLS14_TOKEN(cfRule) with type: " << aType);
}
}
else if (nElement == XLS14_TOKEN( dxf ))
{
return new DxfContext( *this, getStyles().createExtDxf() );
}
else if (nElement == XM_TOKEN( sqref ) || nElement == XM_TOKEN( f ))
{
if(nElement == XM_TOKEN( f ))
nFormulaCount++;
return this;
}
return nullptr;
}
void ExtConditionalFormattingContext::onStartElement(const AttributeList& /*Attribs*/)
{
}
void ExtConditionalFormattingContext::onCharacters(const OUString& rCharacters)
{
switch (getCurrentElement())
{
case XM_TOKEN(f):
{
aChars = rCharacters;
isPreviousElementF = true;
}
break;
case XM_TOKEN(sqref):
{
aChars = rCharacters;
}
break;
}
}
void ExtConditionalFormattingContext::onEndElement()
{
switch (getCurrentElement())
{
case XM_TOKEN(f):
{
if(!IsSpecificTextCondMode(eOperator) || nFormulaCount == 2)
maModel.aFormula = aChars;
}
break;
case XLS14_TOKEN( cfRule ):
{
if (IsSpecificTextCondMode(maModel.eOperator) && nFormulaCount == 1)
{
maModel.aFormula = aChars;
maModel.eOperator = ScConditionMode::Direct;
}
if (Dxf* pDxf = getStyles().getExtDxfs().get(gnStyleIdx).get())
pDxf->finalizeImport();
maModel.aStyle = getStyles().createExtDxfStyle(gnStyleIdx);
gnStyleIdx++;
nFormulaCount = 0;
maModels.push_back(maModel);
}
break;
case XM_TOKEN(sqref):
{
ScRangeList aRange;
ScDocument& rDoc = getScDocument();
bool bSuccess = ScRangeStringConverter::GetRangeListFromString(aRange, aChars, rDoc, formula::FormulaGrammar::CONV_XL_OOX);
if (!bSuccess || aRange.empty())
break;
SCTAB nTab = getSheetIndex();
for (size_t i = 0; i < aRange.size(); ++i)
{
aRange[i].aStart.SetTab(nTab);
aRange[i].aEnd.SetTab(nTab);
}
if (maModels.size() > 1)
{
std::sort(maModels.begin(), maModels.end(),
[](const ExtCondFormatRuleModel& lhs, const ExtCondFormatRuleModel& rhs) {
return lhs.nPriority < rhs.nPriority;
});
}
if (isPreviousElementF) // sqref can be alone in some cases.
{
for (size_t i = 0; i < maModels.size(); ++i)
{
ScAddress rPos = aRange.GetTopLeftCorner();
ScCondFormatEntry* pEntry = new ScCondFormatEntry(maModels[i].eOperator, maModels[i].aFormula, u""_ustr, rDoc,
rPos, maModels[i].aStyle, u""_ustr, u""_ustr,
formula::FormulaGrammar::GRAM_OOXML ,
formula::FormulaGrammar::GRAM_OOXML,
ScFormatEntry::Type::ExtCondition );
maEntries.push_back(std::unique_ptr<ScFormatEntry>(pEntry));
}
assert(maPriorities.size() >= maModels.size());
maModels.clear();
}
std::vector< std::unique_ptr<ExtCfCondFormat> >& rExtFormats = getCondFormats().importExtCondFormat();
rExtFormats.push_back(std::make_unique<ExtCfCondFormat>(aRange, maEntries, &maPriorities));
maPriorities.clear();
isPreviousElementF = false;
}
break;
default:
break;
}
}
ExtLstLocalContext::ExtLstLocalContext( WorksheetContextBase& rFragment, ScDataBarFormatData* pTarget ):
WorksheetContextBase(rFragment),
mpTarget(pTarget)
{
}
ContextHandlerRef ExtLstLocalContext::onCreateContext( sal_Int32 nElement, const AttributeList& )
{
switch( getCurrentElement() )
{
case XLS_TOKEN( extLst ):
if(nElement == XLS_TOKEN( ext ))
return this;
else
return nullptr;
case XLS_TOKEN( ext ):
if (nElement == XLS14_TOKEN( id ))
return this;
else
return nullptr;
}
return nullptr;
}
void ExtLstLocalContext::onStartElement( const AttributeList& )
{
switch( getCurrentElement() )
{
case XLS14_TOKEN( id ):
break;
}
}
void ExtLstLocalContext::onCharacters( const OUString& rChars )
{
if (getCurrentElement() == XLS14_TOKEN( id ))
{
getExtLst().insert( std::pair< OUString, ScDataBarFormatData*>(rChars, mpTarget) );
}
}
ExtGlobalContext::ExtGlobalContext( WorksheetContextBase& rFragment ):
WorksheetContextBase(rFragment)
{
}
ContextHandlerRef ExtGlobalContext::onCreateContext( sal_Int32 nElement, const AttributeList& /*rAttribs*/ )
{
switch (nElement)
{
case XLS14_TOKEN(conditionalFormatting): return new ExtConditionalFormattingContext(*this);
case XLS14_TOKEN(dataValidations): return new ExtDataValidationsContext(*this);
case XLS14_TOKEN(sparklineGroups): return new SparklineGroupsContext(*this);
}
return this;
}
void ExtGlobalContext::onStartElement( const AttributeList& /*rAttribs*/ )
{
}
ExtLstGlobalContext::ExtLstGlobalContext( WorksheetFragment& rFragment ):
WorksheetContextBase(rFragment)
{
}
ContextHandlerRef ExtLstGlobalContext::onCreateContext( sal_Int32 nElement, const AttributeList& )
{
if (nElement == XLS_TOKEN( ext ))
return new ExtGlobalContext( *this );
return this;
}
ExtGlobalWorkbookContext::ExtGlobalWorkbookContext( WorkbookContextBase& rFragment ):
WorkbookContextBase(rFragment)
{
}
ContextHandlerRef ExtGlobalWorkbookContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
{
if (nElement == LOEXT_TOKEN(extCalcPr))
{
ScDocument& rDoc = getScDocument();
sal_Int32 nToken = rAttribs.getToken( XML_stringRefSyntax, XML_CalcA1 );
ScCalcConfig aCalcConfig = rDoc.GetCalcConfig();
switch( nToken )
{
case XML_CalcA1:
aCalcConfig.SetStringRefSyntax( formula::FormulaGrammar::CONV_OOO );
break;
case XML_ExcelA1:
aCalcConfig.SetStringRefSyntax( formula::FormulaGrammar::CONV_XL_A1 );
break;
case XML_ExcelR1C1:
aCalcConfig.SetStringRefSyntax( formula::FormulaGrammar::CONV_XL_R1C1 );
break;
case XML_CalcA1ExcelA1:
aCalcConfig.SetStringRefSyntax( formula::FormulaGrammar::CONV_A1_XL_A1 );
break;
default:
aCalcConfig.SetStringRefSyntax( formula::FormulaGrammar::CONV_UNSPECIFIED );
break;
}
rDoc.SetCalcConfig(aCalcConfig);
}
return this;
}
void ExtGlobalWorkbookContext::onStartElement( const AttributeList& /*rAttribs*/ )
{
}
ExtLstGlobalWorkbookContext::ExtLstGlobalWorkbookContext( WorkbookFragment& rFragment ):
WorkbookContextBase(rFragment)
{
}
ContextHandlerRef ExtLstGlobalWorkbookContext::onCreateContext( sal_Int32 nElement, const AttributeList& )
{
if (nElement == XLS_TOKEN( ext ))
return new ExtGlobalWorkbookContext( *this );
return this;
}
} //namespace oox::xls
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V730 Not all members of a class are initialized inside the constructor. Consider inspecting: maModel.