Mercurial > clickerconvert
view src/xlsx/xlsxconditionalformatting.cpp @ 39:41cd27a64365
Write empty columns for XSLX to avoid strange 0 formatting
Excel shows a pretty large bar for zero values
author | Andre Heinecke <andre.heinecke@intevation.de> |
---|---|
date | Fri, 15 Apr 2016 15:24:07 +0200 |
parents | 4ecb91aaf33f |
children |
line wrap: on
line source
/**************************************************************************** ** Copyright (c) 2013-2014 Debao Zhang <hello@debao.me> ** All right reserved. ** ** Permission is hereby granted, free of charge, to any person obtaining ** a copy of this software and associated documentation files (the ** "Software"), to deal in the Software without restriction, including ** without limitation the rights to use, copy, modify, merge, publish, ** distribute, sublicense, and/or sell copies of the Software, and to ** permit persons to whom the Software is furnished to do so, subject to ** the following conditions: ** ** The above copyright notice and this permission notice shall be ** included in all copies or substantial portions of the Software. ** ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE ** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ** ****************************************************************************/ #include "xlsxconditionalformatting.h" #include "xlsxconditionalformatting_p.h" #include "xlsxworksheet.h" #include "xlsxcellrange.h" #include "xlsxstyles_p.h" #include <QXmlStreamReader> #include <QXmlStreamWriter> #include <QDebug> 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) { this->d = other.d; return *this; } /*! * Destroy the object. */ ConditionalFormatting::~ConditionalFormatting() { } /*! * Add a hightlight 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; QSharedPointer<XlsxCfRuleData> cfRule(new 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 hightlight 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 hightlight 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) { QSharedPointer<XlsxCfRuleData> cfRule(new 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"); QSharedPointer<XlsxCfRuleData> cfRule(new 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"); QSharedPointer<XlsxCfRuleData> cfRule(new 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")).toString().toInt(); if (styles) rule->dxfFormat = styles->dxfFormat(id); else rule->dxfFormat.setDxfIndex(id); } rule->priority = attrs.value(QLatin1String("priority")).toString().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")) { 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_cfvo2] = 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(); QString sqref = attrs.value(QLatin1String("sqref")).toString(); foreach (QString range, sqref.split(QLatin1Char(' '))) this->addRange(range); while (!reader.atEnd()) { reader.readNextStartElement(); if (reader.tokenType() == QXmlStreamReader::StartElement) { if (reader.name() == QLatin1String("cfRule")) { QSharedPointer<XlsxCfRuleData> cfRule(new XlsxCfRuleData); d->readCfRule(reader, cfRule.data(), 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; foreach (CellRange range, ranges()) sqref.append(range.toString()); writer.writeAttribute(QStringLiteral("sqref"), sqref.join(QLatin1Char(' '))); const QString extNS = QStringLiteral("http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"); const QString xmNS = QStringLiteral("http://schemas.microsoft.com/office/excel/2006/main"); for (int i=0; i<d->cfRules.size(); ++i) { const QSharedPointer<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)); if (rule->attrs.contains(XlsxCfRuleData::A_stopIfTrue)) writer.writeAttribute(QStringLiteral("stopIfTrue"), rule->attrs[XlsxCfRuleData::A_stopIfTrue].toString()); if (rule->attrs.contains(XlsxCfRuleData::A_aboveAverage)) writer.writeAttribute(QStringLiteral("aboveAverage"), rule->attrs[XlsxCfRuleData::A_aboveAverage].toString()); if (rule->attrs.contains(XlsxCfRuleData::A_percent)) writer.writeAttribute(QStringLiteral("percent"), rule->attrs[XlsxCfRuleData::A_percent].toString()); if (rule->attrs.contains(XlsxCfRuleData::A_bottom)) writer.writeAttribute(QStringLiteral("bottom"), rule->attrs[XlsxCfRuleData::A_bottom].toString()); if (rule->attrs.contains(XlsxCfRuleData::A_operator)) writer.writeAttribute(QStringLiteral("operator"), rule->attrs[XlsxCfRuleData::A_operator].toString()); if (rule->attrs.contains(XlsxCfRuleData::A_text)) writer.writeAttribute(QStringLiteral("text"), rule->attrs[XlsxCfRuleData::A_text].toString()); if (rule->attrs.contains(XlsxCfRuleData::A_timePeriod)) writer.writeAttribute(QStringLiteral("timePeriod"), rule->attrs[XlsxCfRuleData::A_timePeriod].toString()); if (rule->attrs.contains(XlsxCfRuleData::A_rank)) writer.writeAttribute(QStringLiteral("rank"), rule->attrs[XlsxCfRuleData::A_rank].toString()); if (rule->attrs.contains(XlsxCfRuleData::A_stdDev)) writer.writeAttribute(QStringLiteral("stdDev"), rule->attrs[XlsxCfRuleData::A_stdDev].toString()); 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(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 writer.writeStartElement(QStringLiteral("extLst")); writer.writeStartElement(QStringLiteral("ext")); writer.writeNamespace(extNS, QStringLiteral("x14")); writer.writeAttribute(QStringLiteral("uri"), QStringLiteral("{B025F937-C7B1-47D3-B67F-A62EFF666E3E}")); writer.writeStartElement(extNS, QStringLiteral("id")); writer.writeCharacters(QStringLiteral("{00000000-000E-0000-0000-000001000000}")); writer.writeEndElement(); //id writer.writeEndElement(); //ext writer.writeEndElement(); //extLst } 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>()); if (rule->attrs.contains(XlsxCfRuleData::A_cfvo3)) d->writeCfVo(writer, rule->attrs[XlsxCfRuleData::A_cfvo3].value<XlsxCfVoData>()); rule->attrs[XlsxCfRuleData::A_color1].value<XlsxColor>().saveToXml(writer); rule->attrs[XlsxCfRuleData::A_color2].value<XlsxColor>().saveToXml(writer); if (rule->attrs.contains(XlsxCfRuleData::A_color3)) rule->attrs[XlsxCfRuleData::A_color3].value<XlsxColor>().saveToXml(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)); } else if (rule->attrs.contains(XlsxCfRuleData::A_formula1)) { writer.writeTextElement(QStringLiteral("formula"), rule->attrs[XlsxCfRuleData::A_formula1].toString()); } if (rule->attrs.contains(XlsxCfRuleData::A_formula2)) writer.writeTextElement(QStringLiteral("formula"), rule->attrs[XlsxCfRuleData::A_formula2].toString()); if (rule->attrs.contains(XlsxCfRuleData::A_formula3)) writer.writeTextElement(QStringLiteral("formula"), rule->attrs[XlsxCfRuleData::A_formula3].toString()); writer.writeEndElement(); //cfRule } writer.writeEndElement(); //conditionalFormatting writer.writeStartElement(QStringLiteral("extLst")); writer.writeStartElement(QStringLiteral("ext")); writer.writeNamespace(extNS, QStringLiteral("x14")); writer.writeAttribute(QStringLiteral("uri"), QStringLiteral("{78C0D931-6437-407d-A8EE-F0AAD7539E65}")); writer.writeStartElement(extNS, QStringLiteral("conditionalFormattings")); writer.writeStartElement(extNS, QStringLiteral("conditionalFormatting")); writer.writeNamespace(xmNS, QStringLiteral("xm")); writer.writeStartElement(extNS, QStringLiteral("cfRule")); writer.writeAttribute("type", "dataBar"); writer.writeAttribute("id", "{00000000-000E-0000-0000-000001000000}"); writer.writeStartElement(extNS, "dataBar"); writer.writeAttribute("gradient", "0"); writer.writeAttribute("negativeBarColorSameAsPositive", "1"); writer.writeAttribute("axisPosition", "none"); writer.writeStartElement(extNS, "cfvo"); writer.writeAttribute("type", "num"); writer.writeStartElement(xmNS, "f"); writer.writeCharacters("0"); writer.writeEndElement(); // f writer.writeEndElement(); // cfvo writer.writeStartElement(extNS, "cfvo"); writer.writeAttribute("type", "num"); writer.writeStartElement(xmNS, "f"); writer.writeCharacters("100"); writer.writeEndElement(); // f writer.writeEndElement(); // cfvo writer.writeEndElement(); // dataBar writer.writeEndElement(); // cfrule writer.writeStartElement(xmNS, "sqref"); writer.writeCharacters(sqref.join(QLatin1Char(' '))); writer.writeEndElement(); // sqref writer.writeEndElement(); // conditionalFormatting writer.writeEndElement(); // conditionalFormattings writer.writeEndElement(); //ext writer.writeEndElement(); //extLst return true; } QT_END_NAMESPACE_XLSX