Browse Source

Add dataBar and colorScale write support

master
Debao Zhang 11 years ago
parent
commit
a84b996412
  1. 28
      examples/xlsx/conditionalformatting/main.cpp
  2. 175
      src/xlsx/xlsxconditionalformatting.cpp
  3. 15
      src/xlsx/xlsxconditionalformatting.h
  4. 35
      src/xlsx/xlsxconditionalformatting_p.h
  5. 20
      tests/auto/xlsxconditionalformatting/tst_conditionalformattingtest.cpp

28
examples/xlsx/conditionalformatting/main.cpp

@ -11,7 +11,10 @@ int main()
Format hFmt;
hFmt.setFontBold(true);
xlsx.write("B1", "(-inf,40)", hFmt);
xlsx.write("D1", "[30,70]", hFmt);
xlsx.write("C1", "[30,70]", hFmt);
xlsx.write("D1", "startsWith 2", hFmt);
xlsx.write("E1", "dataBar", hFmt);
xlsx.write("F1", "colorScale", hFmt);
for (int row=3; row<22; ++row) {
for (int col=2; col<22; ++col)
@ -19,7 +22,7 @@ int main()
}
//![0]
//![1]
//![cf1]
ConditionalFormatting cf1;
Format fmt1;
fmt1.setFontColor(Qt::green);
@ -27,7 +30,7 @@ int main()
cf1.addHighlightCellsRule(ConditionalFormatting::Highlight_LessThan, "40", fmt1);
cf1.addRange("B3:B21");
xlsx.addConditionalFormatting(cf1);
//![1]
//![cf1]
//![cf2]
ConditionalFormatting cf2;
@ -35,7 +38,7 @@ int main()
fmt2.setBorderStyle(Format::BorderDotted);
fmt2.setBorderColor(Qt::blue);
cf2.addHighlightCellsRule(ConditionalFormatting::Highlight_Between, "30", "70", fmt2);
cf2.addRange("D3:D21");
cf2.addRange("C3:C21");
xlsx.addConditionalFormatting(cf2);
//![cf2]
@ -43,11 +46,26 @@ int main()
ConditionalFormatting cf3;
Format fmt3;
fmt3.setFontStrikeOut(true);
fmt3.setFontBold(true);
cf3.addHighlightCellsRule(ConditionalFormatting::Highlight_BeginsWith, "2", fmt3);
cf3.addRange("F3:F21");
cf3.addRange("D3:D21");
xlsx.addConditionalFormatting(cf3);
//![cf3]
//![cf4]
ConditionalFormatting cf4;
cf4.addDataBarRule(Qt::blue);
cf4.addRange("E3:E21");
xlsx.addConditionalFormatting(cf4);
//![cf4]
//![cf5]
ConditionalFormatting cf5;
cf5.add2ColorScaleRule(Qt::blue, Qt::red);
cf5.addRange("F3:F21");
xlsx.addConditionalFormatting(cf5);
//![cf5]
//![2]
xlsx.save();
//![2]

175
src/xlsx/xlsxconditionalformatting.cpp

@ -50,6 +50,41 @@ ConditionalFormattingPrivate::~ConditionalFormattingPrivate()
}
void ConditionalFormattingPrivate::writeCfVo(const XlsxCfVoData &cfvo, QXmlStreamWriter &writer) 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"));
}
void ConditionalFormattingPrivate::writeColor(const QColor &color, QXmlStreamWriter &writer) const
{
writer.writeStartElement(QStringLiteral("color"));
if (color.isValid()) {
writer.writeAttribute(QStringLiteral("rgb"), QStringLiteral("FF")+color.name().mid(1)); //remove #
// } else if (!themeColor.isEmpty()) {
// QStringList themes = themeColor.split(QLatin1Char(':'));
// writer.writeAttribute(QStringLiteral("theme"), themes[0]);
// if (!themes[1].isEmpty())
// writer.writeAttribute(QStringLiteral("tint"), themes[1]);
} else {
writer.writeAttribute(QStringLiteral("auto"), QStringLiteral("1"));
}
writer.writeEndElement();//color
}
/*!
* \class ConditionalFormatting
* \brief Conditional formatting for single cell or ranges
@ -102,7 +137,7 @@ ConditionalFormattingPrivate::~ConditionalFormattingPrivate()
\value Highlight_BelowStdDev2
\value Highlight_BelowStdDev3
\value Highlight_SatisfyFormula
\value Highlight_Expression
*/
/*!
@ -150,7 +185,7 @@ bool ConditionalFormatting::addHighlightCellsRule(HighlightRuleType type, const
if (format.isEmpty())
return false;
bool skipFormula1 = false;
bool skipFormula = false;
QSharedPointer<XlsxCfRuleData> cfRule(new XlsxCfRuleData);
if (type >= Highlight_LessThan && type <= Highlight_NotBetween) {
@ -187,7 +222,7 @@ bool ConditionalFormatting::addHighlightCellsRule(HighlightRuleType type, const
cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("RIGHT(%2,LEN(\"%1\"))=\"%1\"").arg(formula1);
}
cfRule->attrs[XlsxCfRuleData::A_text] = formula1;
skipFormula1 = true;
skipFormula = true;
} else if (type == Highlight_TimePeriod) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("timePeriod");
//:Todo
@ -199,19 +234,19 @@ bool ConditionalFormatting::addHighlightCellsRule(HighlightRuleType type, const
} else if (type == Highlight_Errors) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("containsErrors");
cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("ISERROR(%1)");
skipFormula1 = true;
skipFormula = true;
} else if (type == Highlight_NoErrors) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("notContainsErrors");
cfRule->attrs[XlsxCfRuleData::A_formula1_temp] = QStringLiteral("NOT(ISERROR(%1))");
skipFormula1 = true;
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");
skipFormula1 = true;
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");
skipFormula1 = true;
skipFormula = true;
} else if (type >= Highlight_Top && type <= Highlight_BottomPercent) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("top10");
if (type == Highlight_Bottom || type == Highlight_BottomPercent)
@ -219,7 +254,7 @@ bool ConditionalFormatting::addHighlightCellsRule(HighlightRuleType type, const
if (type == Highlight_TopPercent || type == Highlight_BottomPercent)
cfRule->attrs[XlsxCfRuleData::A_percent] = QStringLiteral("1");
cfRule->attrs[XlsxCfRuleData::A_rank] = !formula1.isEmpty() ? formula1 : QStringLiteral("10");
skipFormula1 = true;
skipFormula = true;
} else if (type >= Highlight_AboveAverage && type <= Highlight_BelowStdDev3) {
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("aboveAverage");
if (type >= Highlight_BelowAverage && type <= Highlight_BelowStdDev3)
@ -232,6 +267,8 @@ bool ConditionalFormatting::addHighlightCellsRule(HighlightRuleType type, const
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;
}
@ -239,11 +276,12 @@ bool ConditionalFormatting::addHighlightCellsRule(HighlightRuleType type, const
cfRule->dxfFormat = format;
if (stopIfTrue)
cfRule->attrs[XlsxCfRuleData::A_stopIfTrue] = true;
if (!formula1.isEmpty() && !skipFormula1)
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;
}
@ -276,6 +314,99 @@ bool ConditionalFormatting::addHighlightCellsRule(HighlightRuleType type, const
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.
*/
bool ConditionalFormatting::addDataBarRule(const QColor &color, ValueObjectType type1, const QString &val1, ValueObjectType type2, const QString &val2, bool showData, bool stopIfTrue)
{
QSharedPointer<XlsxCfRuleData> cfRule(new XlsxCfRuleData);
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("dataBar");
cfRule->attrs[XlsxCfRuleData::A_color1] = 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.
*/
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");
QSharedPointer<XlsxCfRuleData> cfRule(new XlsxCfRuleData);
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("colorScale");
cfRule->attrs[XlsxCfRuleData::A_color1] = minColor;
cfRule->attrs[XlsxCfRuleData::A_color2] = 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.
*/
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");
QSharedPointer<XlsxCfRuleData> cfRule(new XlsxCfRuleData);
cfRule->attrs[XlsxCfRuleData::A_type] = QStringLiteral("colorScale");
cfRule->attrs[XlsxCfRuleData::A_color1] = minColor;
cfRule->attrs[XlsxCfRuleData::A_color2] = midColor;
cfRule->attrs[XlsxCfRuleData::A_color3] = 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.
*/
@ -371,6 +502,30 @@ bool ConditionalFormatting::saveToXml(QXmlStreamWriter &writer) const
if (rule->attrs.contains(XlsxCfRuleData::A_equalAverage))
writer.writeAttribute(QStringLiteral("equalAverage"), rule->attrs[XlsxCfRuleData::A_equalAverage].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(rule->attrs[XlsxCfRuleData::A_cfvo1].value<XlsxCfVoData>(), writer);
d->writeCfVo(rule->attrs[XlsxCfRuleData::A_cfvo2].value<XlsxCfVoData>(), writer);
d->writeColor(rule->attrs[XlsxCfRuleData::A_color1].value<QColor>(), writer);
writer.writeEndElement();//dataBar
} else if (rule->attrs[XlsxCfRuleData::A_type] == QLatin1String("colorScale")) {
writer.writeStartElement(QStringLiteral("colorScale"));
d->writeCfVo(rule->attrs[XlsxCfRuleData::A_cfvo1].value<XlsxCfVoData>(), writer);
d->writeCfVo(rule->attrs[XlsxCfRuleData::A_cfvo2].value<XlsxCfVoData>(), writer);
if (rule->attrs.contains(XlsxCfRuleData::A_cfvo3))
d->writeCfVo(rule->attrs[XlsxCfRuleData::A_cfvo3].value<XlsxCfVoData>(), writer);
d->writeColor(rule->attrs[XlsxCfRuleData::A_color1].value<QColor>(), writer);
d->writeColor(rule->attrs[XlsxCfRuleData::A_color2].value<QColor>(), writer);
if (rule->attrs.contains(XlsxCfRuleData::A_color3))
d->writeColor(rule->attrs[XlsxCfRuleData::A_color3].value<QColor>(), writer);
writer.writeEndElement();//colorScale
}
if (rule->attrs.contains(XlsxCfRuleData::A_formula1_temp)) {
QString startCell = ranges()[0].toString().split(QLatin1Char(':'))[0];
writer.writeTextElement(QStringLiteral("formula"), rule->attrs[XlsxCfRuleData::A_formula1_temp].toString().arg(startCell));

15
src/xlsx/xlsxconditionalformatting.h

@ -32,6 +32,7 @@
class QXmlStreamReader;
class QXmlStreamWriter;
class QColor;
class ConditionalFormattingTest;
QT_BEGIN_NAMESPACE_XLSX
@ -87,6 +88,16 @@ public:
Highlight_Expression
};
enum ValueObjectType
{
VOT_Formula,
VOT_Max,
VOT_Min,
VOT_Num,
VOT_Percent,
VOT_Percentile
};
ConditionalFormatting();
ConditionalFormatting(const ConditionalFormatting &other);
~ConditionalFormatting();
@ -94,6 +105,10 @@ public:
bool addHighlightCellsRule(HighlightRuleType type, const Format &format, bool stopIfTrue=false);
bool addHighlightCellsRule(HighlightRuleType type, const QString &formula1, const Format &format, bool stopIfTrue=false);
bool addHighlightCellsRule(HighlightRuleType type, const QString &formula1, const QString &formula2, const Format &format, bool stopIfTrue=false);
bool addDataBarRule(const QColor &color, bool showData=true, bool stopIfTrue=false);
bool addDataBarRule(const QColor &color, ValueObjectType type1, const QString &val1, ValueObjectType type2, const QString &val2, bool showData=true, bool stopIfTrue=false);
bool add2ColorScaleRule(const QColor &minColor, const QColor &maxColor, bool stopIfTrue=false);
bool add3ColorScaleRule(const QColor &minColor, const QColor &midColor, const QColor &maxColor, bool stopIfTrue=false);
QList<CellRange> ranges() const;

35
src/xlsx/xlsxconditionalformatting_p.h

@ -45,6 +45,24 @@
QT_BEGIN_NAMESPACE_XLSX
class XlsxCfVoData
{
public:
XlsxCfVoData()
:gte(true)
{
}
XlsxCfVoData(ConditionalFormatting::ValueObjectType type, const QString &value, bool gte=true)
:type(type), value(value), gte(gte)
{
}
ConditionalFormatting::ValueObjectType type;
QString value;
bool gte;
};
class XlsxCfRuleData
{
public:
@ -67,7 +85,17 @@ public:
A_formula1,
A_formula2,
A_formula3,
A_formula1_temp
A_formula1_temp,
A_color1,
A_color2,
A_color3,
A_cfvo1,
A_cfvo2,
A_cfvo3,
A_hideData
};
XlsxCfRuleData()
@ -86,9 +114,14 @@ public:
ConditionalFormattingPrivate(const ConditionalFormattingPrivate &other);
~ConditionalFormattingPrivate();
void writeCfVo(const XlsxCfVoData& cfvo, QXmlStreamWriter &writer) const;
void writeColor(const QColor &color, QXmlStreamWriter &writer) const;
QList<QSharedPointer<XlsxCfRuleData> >cfRules;
QList<CellRange> ranges;
};
QT_END_NAMESPACE_XLSX
Q_DECLARE_METATYPE(QXlsx::XlsxCfVoData)
#endif // XLSXCONDITIONALFORMATTING_P_H

20
tests/auto/xlsxconditionalformatting/tst_conditionalformattingtest.cpp

@ -19,6 +19,7 @@ public:
private Q_SLOTS:
void testHighlightRules();
void testHighlightRules_data();
void testDataBarRules();
};
ConditionalFormattingTest::ConditionalFormattingTest()
@ -78,6 +79,25 @@ void ConditionalFormattingTest::testHighlightRules()
QVERIFY(buffer.buffer().contains(result));
}
void ConditionalFormattingTest::testDataBarRules()
{
ConditionalFormatting cf;
cf.addDataBarRule(Qt::blue);
cf.addRange("C3:C10");
QBuffer buffer;
buffer.open(QIODevice::WriteOnly);
QXmlStreamWriter writer(&buffer);
cf.saveToXml(writer);
qDebug()<<buffer.buffer();
QByteArray res = "<cfRule type=\"dataBar\" priority=\"1\">"
"<dataBar><cfvo type=\"min\" val=\"0\"/>"
"<cfvo type=\"max\" val=\"0\"/>"
"<color rgb=\"FF0000ff\"/></dataBar>"
"</cfRule>";
QVERIFY(buffer.buffer().contains(res));
}
QTEST_APPLESS_MAIN(ConditionalFormattingTest)
#include "tst_conditionalformattingtest.moc"

Loading…
Cancel
Save