qt/LedOK/QXlsx/source/xlsxconditionalformatting.cpp

815 lines
31 KiB
C++
Raw Normal View History

2025-06-27 22:06:33 +08:00
// xlsxconditionalformatting.cpp
#include "xlsxconditionalformatting.h"
#include "xlsxcellrange.h"
#include "xlsxconditionalformatting_p.h"
#include "xlsxstyles_p.h"
#include "xlsxworksheet.h"
#include <QDebug>
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
QT_BEGIN_NAMESPACE_XLSX
ConditionalFormattingPrivate::ConditionalFormattingPrivate()
{
}
ConditionalFormattingPrivate::ConditionalFormattingPrivate(
const ConditionalFormattingPrivate &other)
: QSharedData(other)
{
}
ConditionalFormattingPrivate::~ConditionalFormattingPrivate()
{
}
void ConditionalFormattingPrivate::writeCfVo(QXmlStreamWriter &writer,
const XlsxCfVoData &cfvo) const
{
writer.writeEmptyElement(QStringLiteral("cfvo"));
QString type;
switch (cfvo.type) {
case ConditionalFormatting::VOT_Formula:
type = QStringLiteral("formula");
break;
case ConditionalFormatting::VOT_Max:
type = QStringLiteral("max");
break;
case ConditionalFormatting::VOT_Min:
type = QStringLiteral("min");
break;
case ConditionalFormatting::VOT_Num:
type = QStringLiteral("num");
break;
case ConditionalFormatting::VOT_Percent:
type = QStringLiteral("percent");
break;
case ConditionalFormatting::VOT_Percentile:
type = QStringLiteral("percentile");
break;
default:
break;
}
writer.writeAttribute(QStringLiteral("type"), type);
writer.writeAttribute(QStringLiteral("val"), cfvo.value);
if (!cfvo.gte)
writer.writeAttribute(QStringLiteral("gte"), QStringLiteral("0"));
}
/*!
* \class ConditionalFormatting
* \brief Conditional formatting for single cell or ranges
* \inmodule QtXlsx
*
* The conditional formatting can be applied to a single cell or ranges of cells.
*/
/*!
\enum ConditionalFormatting::HighlightRuleType
\value Highlight_LessThan
\value Highlight_LessThanOrEqual
\value Highlight_Equal
\value Highlight_NotEqual
\value Highlight_GreaterThanOrEqual
\value Highlight_GreaterThan
\value Highlight_Between
\value Highlight_NotBetween
\value Highlight_ContainsText
\value Highlight_NotContainsText
\value Highlight_BeginsWith
\value Highlight_EndsWith
\value Highlight_TimePeriod
\value Highlight_Duplicate
\value Highlight_Unique
\value Highlight_Blanks
\value Highlight_NoBlanks
\value Highlight_Errors
\value Highlight_NoErrors
\value Highlight_Top
\value Highlight_TopPercent
\value Highlight_Bottom
\value Highlight_BottomPercent
\value Highlight_AboveAverage
\value Highlight_AboveOrEqualAverage
\value Highlight_BelowAverage
\value Highlight_BelowOrEqualAverage
\value Highlight_AboveStdDev1
\value Highlight_AboveStdDev2
\value Highlight_AboveStdDev3
\value Highlight_BelowStdDev1
\value Highlight_BelowStdDev2
\value Highlight_BelowStdDev3
\value Highlight_Expression
*/
/*!
\enum ConditionalFormatting::ValueObjectType
\value VOT_Formula
\value VOT_Max
\value VOT_Min
\value VOT_Num
\value VOT_Percent
\value VOT_Percentile
*/
/*!
Construct a conditional formatting object
*/
ConditionalFormatting::ConditionalFormatting()
: d(new ConditionalFormattingPrivate())
{
}
/*!
Constructs a copy of \a other.
*/
ConditionalFormatting::ConditionalFormatting(const ConditionalFormatting &other)
: d(other.d)
{
}
/*!
Assigns \a other to this conditional formatting and returns a reference to
this conditional formatting.
*/
ConditionalFormatting &ConditionalFormatting::operator=(const ConditionalFormatting &other)
{
if (this != &other) // Self-assignment check [cert-oop54-cpp]
{
this->d = other.d;
}
return *this;
}
/*!
* Destroy the object.
*/
ConditionalFormatting::~ConditionalFormatting()
{
}
/*!
* Add a highlight rule with the given \a type, \a formula1, \a formula2,
* \a format and \a stopIfTrue.
* Return false if failed.
*/
bool ConditionalFormatting::addHighlightCellsRule(HighlightRuleType type,
const QString &formula1,
const QString &formula2,
const Format &format,
bool stopIfTrue)
{
if (format.isEmpty())
return false;
bool skipFormula = false;
auto cfRule = std::make_shared<XlsxCfRuleData>();
if (type >= Highlight_LessThan && type <= Highlight_NotBetween) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("cellIs");
QString op;
switch (type) {
case Highlight_Between:
op = QStringLiteral("between");
break;
case Highlight_Equal:
op = QStringLiteral("equal");
break;
case Highlight_GreaterThan:
op = QStringLiteral("greaterThan");
break;
case Highlight_GreaterThanOrEqual:
op = QStringLiteral("greaterThanOrEqual");
break;
case Highlight_LessThan:
op = QStringLiteral("lessThan");
break;
case Highlight_LessThanOrEqual:
op = QStringLiteral("lessThanOrEqual");
break;
case Highlight_NotBetween:
op = QStringLiteral("notBetween");
break;
case Highlight_NotEqual:
op = QStringLiteral("notEqual");
break;
default:
break;
}
cfRule->attrs[XlsxCfRuleData::A_operator] = op;
} else if (type >= Highlight_ContainsText && type <= Highlight_EndsWith) {
if (type == Highlight_ContainsText) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("containsText");
cfRule->attrs[XlsxCfRuleData::A_operator] = QStringLiteral("containsText");
cfRule->attrs[XlsxCfRuleData::A_formula1_temp] =
QStringLiteral("NOT(ISERROR(SEARCH(\"%1\",%2)))").arg(formula1);
} else if (type == Highlight_NotContainsText) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("notContainsText");
cfRule->attrs[XlsxCfRuleData::A_operator] = QStringLiteral("notContains");
cfRule->attrs[XlsxCfRuleData::A_formula1_temp] =
QStringLiteral("ISERROR(SEARCH(\"%2\",%1))").arg(formula1);
} else if (type == Highlight_BeginsWith) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("beginsWith");
cfRule->attrs[XlsxCfRuleData::A_operator] = QStringLiteral("beginsWith");
cfRule->attrs[XlsxCfRuleData::A_formula1_temp] =
QStringLiteral("LEFT(%2,LEN(\"%1\"))=\"%1\"").arg(formula1);
} else {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("endsWith");
cfRule->attrs[XlsxCfRuleData::A_operator] = QStringLiteral("endsWith");
cfRule->attrs[XlsxCfRuleData::A_formula1_temp] =
QStringLiteral("RIGHT(%2,LEN(\"%1\"))=\"%1\"").arg(formula1);
}
cfRule->attrs[XlsxCfRuleData::A_text] = formula1;
skipFormula = true;
} else if (type == Highlight_TimePeriod) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("timePeriod");
//: Todo
return false;
} else if (type == Highlight_Duplicate) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("duplicateValues");
} else if (type == Highlight_Unique) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("uniqueValues");
} else if (type == Highlight_Errors) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("containsErrors");
cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("ISERROR(%1)");
skipFormula = true;
} else if (type == Highlight_NoErrors) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("notContainsErrors");
cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("NOT(ISERROR(%1))");
skipFormula = true;
} else if (type == Highlight_Blanks) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("containsBlanks");
cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("LEN(TRIM(%1))=0");
skipFormula = true;
} else if (type == Highlight_NoBlanks) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("notContainsBlanks");
cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("LEN(TRIM(%1))>0");
skipFormula = true;
} else if (type >= Highlight_Top && type <= Highlight_BottomPercent) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("top10");
if (type == Highlight_Bottom || type == Highlight_BottomPercent)
cfRule->attrs[XlsxCfRuleData::A_bottom] = QStringLiteral("1");
if (type == Highlight_TopPercent || type == Highlight_BottomPercent)
cfRule->attrs[XlsxCfRuleData::A_percent] = QStringLiteral("1");
cfRule->attrs[XlsxCfRuleData::A_rank] =
!formula1.isEmpty() ? formula1 : QStringLiteral("10");
skipFormula = true;
} else if (type >= Highlight_AboveAverage && type <= Highlight_BelowStdDev3) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("aboveAverage");
if (type >= Highlight_BelowAverage && type <= Highlight_BelowStdDev3)
cfRule->attrs[XlsxCfRuleData::A_aboveAverage] = QStringLiteral("0");
if (type == Highlight_AboveOrEqualAverage || type == Highlight_BelowOrEqualAverage)
cfRule->attrs[XlsxCfRuleData::A_equalAverage] = QStringLiteral("1");
if (type == Highlight_AboveStdDev1 || type == Highlight_BelowStdDev1)
cfRule->attrs[XlsxCfRuleData::A_stdDev] = QStringLiteral("1");
else if (type == Highlight_AboveStdDev2 || type == Highlight_BelowStdDev2)
cfRule->attrs[XlsxCfRuleData::A_stdDev] = QStringLiteral("2");
else if (type == Highlight_AboveStdDev3 || type == Highlight_BelowStdDev3)
cfRule->attrs[XlsxCfRuleData::A_stdDev] = QStringLiteral("3");
} else if (type == Highlight_Expression) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("expression");
} else {
return false;
}
cfRule->dxfFormat = format;
if (stopIfTrue)
cfRule->attrs[XlsxCfRuleData::A_stopIfTrue] = true;
if (!skipFormula) {
if (!formula1.isEmpty())
cfRule->attrs[XlsxCfRuleData::A_formula1] =
formula1.startsWith(QLatin1String("=")) ? formula1.mid(1) : formula1;
if (!formula2.isEmpty())
cfRule->attrs[XlsxCfRuleData::A_formula2] =
formula2.startsWith(QLatin1String("=")) ? formula2.mid(1) : formula2;
}
d->cfRules.append(cfRule);
return true;
}
/*!
* \overload
*
* Add a highlight rule with the given \a type \a format and \a stopIfTrue.
*/
bool ConditionalFormatting::addHighlightCellsRule(HighlightRuleType type,
const Format &format,
bool stopIfTrue)
{
if ((type >= Highlight_AboveAverage && type <= Highlight_BelowStdDev3) ||
(type >= Highlight_Duplicate && type <= Highlight_NoErrors)) {
return addHighlightCellsRule(type, QString(), QString(), format, stopIfTrue);
}
return false;
}
/*!
* \overload
*
* Add a highlight rule with the given \a type, \a formula, \a format and \a stopIfTrue.
* Return false if failed.
*/
bool ConditionalFormatting::addHighlightCellsRule(HighlightRuleType type,
const QString &formula,
const Format &format,
bool stopIfTrue)
{
if (type == Highlight_Between || type == Highlight_NotBetween)
return false;
return addHighlightCellsRule(type, formula, QString(), format, stopIfTrue);
}
/*!
* Add a dataBar rule with the given \a color, \a type1, \a val1
* , \a type2, \a val2, \a showData and \a stopIfTrue.
* Return false if failed.
*/
bool ConditionalFormatting::addDataBarRule(const QColor &color,
ValueObjectType type1,
const QString &val1,
ValueObjectType type2,
const QString &val2,
bool showData,
bool stopIfTrue)
{
auto cfRule = std::make_shared<XlsxCfRuleData>();
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("dataBar");
cfRule->attrs[XlsxCfRuleData::A_color1] = XlsxColor(color);
if (stopIfTrue)
cfRule->attrs[XlsxCfRuleData::A_stopIfTrue] = true;
if (!showData)
cfRule->attrs[XlsxCfRuleData::A_hideData] = true;
XlsxCfVoData cfvo1(type1, val1);
XlsxCfVoData cfvo2(type2, val2);
cfRule->attrs[XlsxCfRuleData::A_cfvo1] = QVariant::fromValue(cfvo1);
cfRule->attrs[XlsxCfRuleData::A_cfvo2] = QVariant::fromValue(cfvo2);
d->cfRules.append(cfRule);
return true;
}
/*!
* \overload
* Add a dataBar rule with the given \a color, \a showData and \a stopIfTrue.
*/
bool ConditionalFormatting::addDataBarRule(const QColor &color, bool showData, bool stopIfTrue)
{
return addDataBarRule(
color, VOT_Min, QStringLiteral("0"), VOT_Max, QStringLiteral("0"), showData, stopIfTrue);
}
/*!
* Add a colorScale rule with the given \a minColor, \a maxColor and \a stopIfTrue.
* Return false if failed.
*/
bool ConditionalFormatting::add2ColorScaleRule(const QColor &minColor,
const QColor &maxColor,
bool stopIfTrue)
{
ValueObjectType type1 = VOT_Min;
ValueObjectType type2 = VOT_Max;
QString val1 = QStringLiteral("0");
QString val2 = QStringLiteral("0");
auto cfRule = std::make_shared<XlsxCfRuleData>();
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("colorScale");
cfRule->attrs[XlsxCfRuleData::A_color1] = XlsxColor(minColor);
cfRule->attrs[XlsxCfRuleData::A_color2] = XlsxColor(maxColor);
if (stopIfTrue)
cfRule->attrs[XlsxCfRuleData::A_stopIfTrue] = true;
XlsxCfVoData cfvo1(type1, val1);
XlsxCfVoData cfvo2(type2, val2);
cfRule->attrs[XlsxCfRuleData::A_cfvo1] = QVariant::fromValue(cfvo1);
cfRule->attrs[XlsxCfRuleData::A_cfvo2] = QVariant::fromValue(cfvo2);
d->cfRules.append(cfRule);
return true;
}
/*!
* Add a colorScale rule with the given \a minColor, \a midColor, \a maxColor and \a stopIfTrue.
* Return false if failed.
*/
bool ConditionalFormatting::add3ColorScaleRule(const QColor &minColor,
const QColor &midColor,
const QColor &maxColor,
bool stopIfTrue)
{
ValueObjectType type1 = VOT_Min;
ValueObjectType type2 = VOT_Percent;
ValueObjectType type3 = VOT_Max;
QString val1 = QStringLiteral("0");
QString val2 = QStringLiteral("50");
QString val3 = QStringLiteral("0");
auto cfRule = std::make_shared<XlsxCfRuleData>();
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("colorScale");
cfRule->attrs[XlsxCfRuleData::A_color1] = XlsxColor(minColor);
cfRule->attrs[XlsxCfRuleData::A_color2] = XlsxColor(midColor);
cfRule->attrs[XlsxCfRuleData::A_color3] = XlsxColor(maxColor);
if (stopIfTrue)
cfRule->attrs[XlsxCfRuleData::A_stopIfTrue] = true;
XlsxCfVoData cfvo1(type1, val1);
XlsxCfVoData cfvo2(type2, val2);
XlsxCfVoData cfvo3(type3, val3);
cfRule->attrs[XlsxCfRuleData::A_cfvo1] = QVariant::fromValue(cfvo1);
cfRule->attrs[XlsxCfRuleData::A_cfvo2] = QVariant::fromValue(cfvo2);
cfRule->attrs[XlsxCfRuleData::A_cfvo3] = QVariant::fromValue(cfvo3);
d->cfRules.append(cfRule);
return true;
}
/*!
Returns the ranges on which the validation will be applied.
*/
QList<CellRange> ConditionalFormatting::ranges() const
{
return d->ranges;
}
/*!
Add the \a cell on which the conditional formatting will apply to.
*/
void ConditionalFormatting::addCell(const CellReference &cell)
{
d->ranges.append(CellRange(cell, cell));
}
/*!
\overload
Add the cell(\a row, \a col) on which the conditional formatting will apply to.
*/
void ConditionalFormatting::addCell(int row, int col)
{
d->ranges.append(CellRange(row, col, row, col));
}
/*!
\overload
Add the range(\a firstRow, \a firstCol, \a lastRow, \a lastCol) on
which the conditional formatting will apply to.
*/
void ConditionalFormatting::addRange(int firstRow, int firstCol, int lastRow, int lastCol)
{
d->ranges.append(CellRange(firstRow, firstCol, lastRow, lastCol));
}
/*!
Add the \a range on which the conditional formatting will apply to.
*/
void ConditionalFormatting::addRange(const CellRange &range)
{
d->ranges.append(range);
}
bool ConditionalFormattingPrivate::readCfRule(QXmlStreamReader &reader,
XlsxCfRuleData *rule,
Styles *styles)
{
Q_ASSERT(reader.name() == QLatin1String("cfRule"));
QXmlStreamAttributes attrs = reader.attributes();
if (attrs.hasAttribute(QLatin1String("type")))
rule->attrs[XlsxCfRuleData::A_type] = attrs.value(QLatin1String("type")).toString();
if (attrs.hasAttribute(QLatin1String("dxfId"))) {
int id = attrs.value(QLatin1String("dxfId")).toInt();
if (styles)
rule->dxfFormat = styles->dxfFormat(id);
else
rule->dxfFormat.setDxfIndex(id);
}
rule->priority = attrs.value(QLatin1String("priority")).toInt();
if (attrs.value(QLatin1String("stopIfTrue")) == QLatin1String("1")) {
// default is false
rule->attrs[XlsxCfRuleData::A_stopIfTrue] = QLatin1String("1");
}
if (attrs.value(QLatin1String("aboveAverage")) == QLatin1String("0")) {
// default is true
rule->attrs[XlsxCfRuleData::A_aboveAverage] = QLatin1String("0");
}
if (attrs.value(QLatin1String("percent")) == QLatin1String("1")) {
// default is false
rule->attrs[XlsxCfRuleData::A_percent] = QLatin1String("1");
}
if (attrs.value(QLatin1String("bottom")) == QLatin1String("1")) {
// default is false
rule->attrs[XlsxCfRuleData::A_bottom] = QLatin1String("1");
}
if (attrs.hasAttribute(QLatin1String("operator")))
rule->attrs[XlsxCfRuleData::A_operator] = attrs.value(QLatin1String("operator")).toString();
if (attrs.hasAttribute(QLatin1String("text")))
rule->attrs[XlsxCfRuleData::A_text] = attrs.value(QLatin1String("text")).toString();
if (attrs.hasAttribute(QLatin1String("timePeriod")))
rule->attrs[XlsxCfRuleData::A_timePeriod] =
attrs.value(QLatin1String("timePeriod")).toString();
if (attrs.hasAttribute(QLatin1String("rank")))
rule->attrs[XlsxCfRuleData::A_rank] = attrs.value(QLatin1String("rank")).toString();
if (attrs.hasAttribute(QLatin1String("stdDev")))
rule->attrs[XlsxCfRuleData::A_stdDev] = attrs.value(QLatin1String("stdDev")).toString();
if (attrs.value(QLatin1String("equalAverage")) == QLatin1String("1")) {
// default is false
rule->attrs[XlsxCfRuleData::A_equalAverage] = QLatin1String("1");
}
while (!reader.atEnd()) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("formula")) {
const QString f = reader.readElementText();
if (!rule->attrs.contains(XlsxCfRuleData::A_formula1))
rule->attrs[XlsxCfRuleData::A_formula1] = f;
else if (!rule->attrs.contains(XlsxCfRuleData::A_formula2))
rule->attrs[XlsxCfRuleData::A_formula2] = f;
else if (!rule->attrs.contains(XlsxCfRuleData::A_formula3))
rule->attrs[XlsxCfRuleData::A_formula3] = f;
} else if (reader.name() == QLatin1String("dataBar")) {
readCfDataBar(reader, rule);
} else if (reader.name() == QLatin1String("colorScale")) {
readCfColorScale(reader, rule);
}
}
if (reader.tokenType() == QXmlStreamReader::EndElement &&
reader.name() == QStringLiteral("conditionalFormatting")) {
break;
}
}
return true;
}
bool ConditionalFormattingPrivate::readCfDataBar(QXmlStreamReader &reader, XlsxCfRuleData *rule)
{
Q_ASSERT(reader.name() == QLatin1String("dataBar"));
QXmlStreamAttributes attrs = reader.attributes();
if (attrs.value(QLatin1String("showValue")) == QLatin1String("0"))
rule->attrs[XlsxCfRuleData::A_hideData] = QStringLiteral("1");
while (!reader.atEnd()) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("cfvo")) {
XlsxCfVoData data;
readCfVo(reader, data);
if (!rule->attrs.contains(XlsxCfRuleData::A_cfvo1))
rule->attrs[XlsxCfRuleData::A_cfvo1] = QVariant::fromValue(data);
else
rule->attrs[XlsxCfRuleData::A_cfvo2] = QVariant::fromValue(data);
} else if (reader.name() == QLatin1String("color")) {
XlsxColor color;
color.loadFromXml(reader);
rule->attrs[XlsxCfRuleData::A_color1] = color;
}
}
if (reader.tokenType() == QXmlStreamReader::EndElement &&
reader.name() == QStringLiteral("dataBar")) {
break;
}
}
return true;
}
bool ConditionalFormattingPrivate::readCfColorScale(QXmlStreamReader &reader, XlsxCfRuleData *rule)
{
Q_ASSERT(reader.name() == QLatin1String("colorScale"));
while (!reader.atEnd()) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("cfvo")) {
XlsxCfVoData data;
readCfVo(reader, data);
if (!rule->attrs.contains(XlsxCfRuleData::A_cfvo1))
rule->attrs[XlsxCfRuleData::A_cfvo1] = QVariant::fromValue(data);
else if (!rule->attrs.contains(XlsxCfRuleData::A_cfvo2))
rule->attrs[XlsxCfRuleData::A_cfvo2] = QVariant::fromValue(data);
else
rule->attrs[XlsxCfRuleData::A_cfvo3] = QVariant::fromValue(data);
} else if (reader.name() == QLatin1String("color")) {
XlsxColor color;
color.loadFromXml(reader);
if (!rule->attrs.contains(XlsxCfRuleData::A_color1))
rule->attrs[XlsxCfRuleData::A_color1] = color;
else if (!rule->attrs.contains(XlsxCfRuleData::A_color2))
rule->attrs[XlsxCfRuleData::A_color2] = color;
else
rule->attrs[XlsxCfRuleData::A_color3] = color;
}
}
if (reader.tokenType() == QXmlStreamReader::EndElement &&
reader.name() == QStringLiteral("colorScale")) {
break;
}
}
return true;
}
bool ConditionalFormattingPrivate::readCfVo(QXmlStreamReader &reader, XlsxCfVoData &cfvo)
{
Q_ASSERT(reader.name() == QStringLiteral("cfvo"));
QXmlStreamAttributes attrs = reader.attributes();
QString type = attrs.value(QLatin1String("type")).toString();
ConditionalFormatting::ValueObjectType t;
if (type == QLatin1String("formula"))
t = ConditionalFormatting::VOT_Formula;
else if (type == QLatin1String("max"))
t = ConditionalFormatting::VOT_Max;
else if (type == QLatin1String("min"))
t = ConditionalFormatting::VOT_Min;
else if (type == QLatin1String("num"))
t = ConditionalFormatting::VOT_Num;
else if (type == QLatin1String("percent"))
t = ConditionalFormatting::VOT_Percent;
else // if (type == QLatin1String("percentile"))
t = ConditionalFormatting::VOT_Percentile;
cfvo.type = t;
cfvo.value = attrs.value(QLatin1String("val")).toString();
if (attrs.value(QLatin1String("gte")) == QLatin1String("0")) {
// default is true
cfvo.gte = false;
}
return true;
}
bool ConditionalFormatting::loadFromXml(QXmlStreamReader &reader, Styles *styles)
{
Q_ASSERT(reader.name() == QStringLiteral("conditionalFormatting"));
d->ranges.clear();
d->cfRules.clear();
QXmlStreamAttributes attrs = reader.attributes();
const QString sqref = attrs.value(QLatin1String("sqref")).toString();
const auto sqrefParts = sqref.split(QLatin1Char(' '));
for (const QString &range : sqrefParts) {
this->addRange(range);
}
while (!reader.atEnd()) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("cfRule")) {
auto cfRule = std::make_shared<XlsxCfRuleData>();
d->readCfRule(reader, cfRule.get(), styles);
d->cfRules.append(cfRule);
}
}
if (reader.tokenType() == QXmlStreamReader::EndElement &&
reader.name() == QStringLiteral("conditionalFormatting")) {
break;
}
}
return true;
}
bool ConditionalFormatting::saveToXml(QXmlStreamWriter &writer) const
{
writer.writeStartElement(QStringLiteral("conditionalFormatting"));
QStringList sqref;
const auto rangeList = ranges();
for (const CellRange &range : rangeList) {
sqref.append(range.toString());
}
writer.writeAttribute(QStringLiteral("sqref"), sqref.join(QLatin1String(" ")));
for (int i = 0; i < d->cfRules.size(); ++i) {
const std::shared_ptr<XlsxCfRuleData> &rule = d->cfRules[i];
writer.writeStartElement(QStringLiteral("cfRule"));
writer.writeAttribute(QStringLiteral("type"),
rule->attrs[XlsxCfRuleData::A_type].toString());
if (rule->dxfFormat.dxfIndexValid())
writer.writeAttribute(QStringLiteral("dxfId"),
QString::number(rule->dxfFormat.dxfIndex()));
writer.writeAttribute(QStringLiteral("priority"), QString::number(rule->priority));
auto it = rule->attrs.constFind(XlsxCfRuleData::A_stopIfTrue);
if (it != rule->attrs.constEnd())
writer.writeAttribute(QStringLiteral("stopIfTrue"), it.value().toString());
it = rule->attrs.constFind(XlsxCfRuleData::A_aboveAverage);
if (it != rule->attrs.constEnd())
writer.writeAttribute(QStringLiteral("aboveAverage"), it.value().toString());
it = rule->attrs.constFind(XlsxCfRuleData::A_percent);
if (it != rule->attrs.constEnd())
writer.writeAttribute(QStringLiteral("percent"), it.value().toString());
it = rule->attrs.constFind(XlsxCfRuleData::A_bottom);
if (it != rule->attrs.constEnd())
writer.writeAttribute(QStringLiteral("bottom"), it.value().toString());
it = rule->attrs.constFind(XlsxCfRuleData::A_operator);
if (it != rule->attrs.constEnd())
writer.writeAttribute(QStringLiteral("operator"), it.value().toString());
it = rule->attrs.constFind(XlsxCfRuleData::A_text);
if (it != rule->attrs.constEnd())
writer.writeAttribute(QStringLiteral("text"), it.value().toString());
it = rule->attrs.constFind(XlsxCfRuleData::A_timePeriod);
if (it != rule->attrs.constEnd())
writer.writeAttribute(QStringLiteral("timePeriod"), it.value().toString());
it = rule->attrs.constFind(XlsxCfRuleData::A_rank);
if (it != rule->attrs.constEnd())
writer.writeAttribute(QStringLiteral("rank"), it.value().toString());
it = rule->attrs.constFind(XlsxCfRuleData::A_stdDev);
if (it != rule->attrs.constEnd())
writer.writeAttribute(QStringLiteral("stdDev"), it.value().toString());
it = rule->attrs.constFind(XlsxCfRuleData::A_equalAverage);
if (it != rule->attrs.constEnd())
writer.writeAttribute(QStringLiteral("equalAverage"), it.value().toString());
if (rule->attrs[XlsxCfRuleData::A_type] == QLatin1String("dataBar")) {
writer.writeStartElement(QStringLiteral("dataBar"));
if (rule->attrs.contains(XlsxCfRuleData::A_hideData))
writer.writeAttribute(QStringLiteral("showValue"), QStringLiteral("0"));
d->writeCfVo(writer, rule->attrs[XlsxCfRuleData::A_cfvo1].value<XlsxCfVoData>());
d->writeCfVo(writer, rule->attrs[XlsxCfRuleData::A_cfvo2].value<XlsxCfVoData>());
rule->attrs[XlsxCfRuleData::A_color1].value<XlsxColor>().saveToXml(writer);
writer.writeEndElement(); // dataBar
} else if (rule->attrs[XlsxCfRuleData::A_type] == QLatin1String("colorScale")) {
writer.writeStartElement(QStringLiteral("colorScale"));
d->writeCfVo(writer, rule->attrs[XlsxCfRuleData::A_cfvo1].value<XlsxCfVoData>());
d->writeCfVo(writer, rule->attrs[XlsxCfRuleData::A_cfvo2].value<XlsxCfVoData>());
it = rule->attrs.constFind(XlsxCfRuleData::A_cfvo3);
if (it != rule->attrs.constEnd())
d->writeCfVo(writer, it.value().value<XlsxCfVoData>());
rule->attrs[XlsxCfRuleData::A_color1].value<XlsxColor>().saveToXml(writer);
rule->attrs[XlsxCfRuleData::A_color2].value<XlsxColor>().saveToXml(writer);
it = rule->attrs.constFind(XlsxCfRuleData::A_color3);
if (it != rule->attrs.constEnd())
it.value().value<XlsxColor>().saveToXml(writer);
writer.writeEndElement(); // colorScale
}
it = rule->attrs.constFind(XlsxCfRuleData::A_formula1_temp);
if (it != rule->attrs.constEnd()) {
const auto _ranges = ranges();
const auto begin = _ranges.begin();
if (begin != _ranges.end()) {
QString str = begin->toString();
QString startCell = str.mid(0, str.indexOf(u':'));
writer.writeTextElement(QStringLiteral("formula"),
it.value().toString().arg(startCell));
}
} else {
it = rule->attrs.constFind(XlsxCfRuleData::A_formula1);
if (it != rule->attrs.constEnd()) {
writer.writeTextElement(QStringLiteral("formula"), it.value().toString());
}
}
it = rule->attrs.constFind(XlsxCfRuleData::A_formula2);
if (it != rule->attrs.constEnd())
writer.writeTextElement(QStringLiteral("formula"), it.value().toString());
it = rule->attrs.constFind(XlsxCfRuleData::A_formula3);
if (it != rule->attrs.constEnd())
writer.writeTextElement(QStringLiteral("formula"), it.value().toString());
writer.writeEndElement(); // cfRule
}
writer.writeEndElement(); // conditionalFormatting
return true;
}
QT_END_NAMESPACE_XLSX