1
0
mirror of https://github.com/QtExcel/QXlsx.git synced 2025-01-30 05:02:52 +08:00

update v2

This commit is contained in:
unknown 2017-09-08 21:49:19 +09:00
parent b678e7f331
commit 1c9eff24d6
31 changed files with 13210 additions and 0 deletions

View File

@ -0,0 +1,119 @@
/****************************************************************************
** 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 "xlsxabstractooxmlfile.h"
#include "xlsxabstractooxmlfile_p.h"
#include <QBuffer>
#include <QByteArray>
QT_BEGIN_NAMESPACE_XLSX
AbstractOOXmlFilePrivate::AbstractOOXmlFilePrivate(AbstractOOXmlFile *q, AbstractOOXmlFile::CreateFlag flag=AbstractOOXmlFile::F_NewFromScratch)
:relationships(new Relationships), flag(flag), q_ptr(q)
{
}
AbstractOOXmlFilePrivate::~AbstractOOXmlFilePrivate()
{
}
/*!
* \internal
*
* \class AbstractOOXmlFile
*
* Base class of all the ooxml part file.
*/
AbstractOOXmlFile::AbstractOOXmlFile(CreateFlag flag)
:d_ptr(new AbstractOOXmlFilePrivate(this, flag))
{
}
AbstractOOXmlFile::AbstractOOXmlFile(AbstractOOXmlFilePrivate *d)
:d_ptr(d)
{
}
AbstractOOXmlFile::~AbstractOOXmlFile()
{
if (d_ptr->relationships)
delete d_ptr->relationships;
delete d_ptr;
}
QByteArray AbstractOOXmlFile::saveToXmlData() const
{
QByteArray data;
QBuffer buffer(&data);
buffer.open(QIODevice::WriteOnly);
saveToXmlFile(&buffer);
return data;
}
bool AbstractOOXmlFile::loadFromXmlData(const QByteArray &data)
{
QBuffer buffer;
buffer.setData(data);
buffer.open(QIODevice::ReadOnly);
return loadFromXmlFile(&buffer);
}
/*!
* \internal
*/
void AbstractOOXmlFile::setFilePath(const QString path)
{
Q_D(AbstractOOXmlFile);
d->filePathInPackage = path;
}
/*!
* \internal
*/
QString AbstractOOXmlFile::filePath() const
{
Q_D(const AbstractOOXmlFile);
return d->filePathInPackage;
}
/*!
* \internal
*/
Relationships *AbstractOOXmlFile::relationships() const
{
Q_D(const AbstractOOXmlFile);
return d->relationships;
}
QT_END_NAMESPACE_XLSX

View File

@ -0,0 +1,206 @@
/****************************************************************************
** 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 "xlsxabstractsheet.h"
#include "xlsxabstractsheet_p.h"
#include "xlsxworkbook.h"
QT_BEGIN_NAMESPACE_XLSX
AbstractSheetPrivate::AbstractSheetPrivate(AbstractSheet *p, AbstractSheet::CreateFlag flag)
: AbstractOOXmlFilePrivate(p, flag)
{
type = AbstractSheet::ST_WorkSheet;
sheetState = AbstractSheet::SS_Visible;
}
AbstractSheetPrivate::~AbstractSheetPrivate()
{
}
/*!
\class AbstractSheet
\inmodule QtXlsx
\brief Base class for worksheet, chartsheet, etc.
*/
/*!
\enum AbstractSheet::SheetType
\value ST_WorkSheet
\value ST_ChartSheet
\omitvalue ST_DialogSheet
\omitvalue ST_MacroSheet
*/
/*!
\enum AbstractSheet::SheetState
\value SS_Visible
\value SS_Hidden
\value SS_VeryHidden User cann't make a veryHidden sheet visible in normal way.
*/
/*!
\fn AbstractSheet::copy(const QString &distName, int distId) const
Copies the current sheet to a sheet called \a distName with \a distId.
Returns the new sheet.
*/
/*!
* \internal
*/
AbstractSheet::AbstractSheet(const QString &name, int id, Workbook *workbook, AbstractSheetPrivate *d) :
AbstractOOXmlFile(d)
{
d_func()->name = name;
d_func()->id = id;
d_func()->workbook = workbook;
}
/*!
* Returns the name of the sheet.
*/
QString AbstractSheet::sheetName() const
{
Q_D(const AbstractSheet);
return d->name;
}
/*!
* \internal
*/
void AbstractSheet::setSheetName(const QString &sheetName)
{
Q_D(AbstractSheet);
d->name = sheetName;
}
/*!
* Returns the type of the sheet.
*/
AbstractSheet::SheetType AbstractSheet::sheetType() const
{
Q_D(const AbstractSheet);
return d->type;
}
/*!
* \internal
*/
void AbstractSheet::setSheetType(SheetType type)
{
Q_D(AbstractSheet);
d->type = type;
}
/*!
* Returns the state of the sheet.
*
* \sa isHidden(), isVisible(), setSheetState()
*/
AbstractSheet::SheetState AbstractSheet::sheetState() const
{
Q_D(const AbstractSheet);
return d->sheetState;
}
/*!
* Set the state of the sheet to \a state.
*/
void AbstractSheet::setSheetState(SheetState state)
{
Q_D(AbstractSheet);
d->sheetState = state;
}
/*!
* Returns true if the sheet is not visible, otherwise false will be returned.
*
* \sa sheetState(), setHidden()
*/
bool AbstractSheet::isHidden() const
{
Q_D(const AbstractSheet);
return d->sheetState != SS_Visible;
}
/*!
* Returns true if the sheet is visible.
*/
bool AbstractSheet::isVisible() const
{
return !isHidden();
}
/*!
* Make the sheet hiden or visible based on \a hidden.
*/
void AbstractSheet::setHidden(bool hidden)
{
Q_D(AbstractSheet);
if (hidden == isHidden())
return;
d->sheetState = hidden ? SS_Hidden : SS_Visible;
}
/*!
* Convenience function, equivalent to setHidden(! \a visible).
*/
void AbstractSheet::setVisible(bool visible)
{
setHidden(!visible);
}
/*!
* \internal
*/
int AbstractSheet::sheetId() const
{
Q_D(const AbstractSheet);
return d->id;
}
/*!
* \internal
*/
Drawing *AbstractSheet::drawing() const
{
Q_D(const AbstractSheet);
return d->drawing.data();
}
/*!
* Return the workbook
*/
Workbook *AbstractSheet::workbook() const
{
Q_D(const AbstractSheet);
return d->workbook;
}
QT_END_NAMESPACE_XLSX

View File

@ -0,0 +1,178 @@
/****************************************************************************
** 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 "xlsxcell.h"
#include "xlsxcell_p.h"
#include "xlsxformat.h"
#include "xlsxformat_p.h"
#include "xlsxutility_p.h"
#include "xlsxworksheet.h"
#include "xlsxworkbook.h"
#include <QDateTime>
QT_BEGIN_NAMESPACE_XLSX
CellPrivate::CellPrivate(Cell *p) :
q_ptr(p)
{
}
CellPrivate::CellPrivate(const CellPrivate * const cp)
: value(cp->value), formula(cp->formula), cellType(cp->cellType)
, format(cp->format), richString(cp->richString), parent(cp->parent)
{
}
/*!
\class Cell
\inmodule QtXlsx
\brief The Cell class provides a API that is used to handle the worksheet cell.
*/
/*!
\enum Cell::CellType
\value BooleanType Boolean type
\value NumberType Number type, can be blank or used with forumula
\value ErrorType Error type
\value SharedStringType Shared string type
\value StringType String type, can be used with forumula
\value InlineStringType Inline string type
*/
/*!
* \internal
* Created by Worksheet only.
*/
Cell::Cell(const QVariant &data, CellType type, const Format &format, Worksheet *parent) :
d_ptr(new CellPrivate(this))
{
d_ptr->value = data;
d_ptr->cellType = type;
d_ptr->format = format;
d_ptr->parent = parent;
}
/*!
* \internal
*/
Cell::Cell(const Cell * const cell):
d_ptr(new CellPrivate(cell->d_ptr))
{
d_ptr->q_ptr = this;
}
/*!
* Destroys the Cell and cleans up.
*/
Cell::~Cell()
{
delete d_ptr;
}
/*!
* Return the dataType of this Cell
*/
Cell::CellType Cell::cellType() const
{
Q_D(const Cell);
return d->cellType;
}
/*!
* Return the data content of this Cell
*/
QVariant Cell::value() const
{
Q_D(const Cell);
return d->value;
}
/*!
* Return the style used by this Cell. If no style used, 0 will be returned.
*/
Format Cell::format() const
{
Q_D(const Cell);
return d->format;
}
/*!
* Returns true if the cell has one formula.
*/
bool Cell::hasFormula() const
{
Q_D(const Cell);
return d->formula.isValid();
}
/*!
* Return the formula contents if the dataType is Formula
*/
CellFormula Cell::formula() const
{
Q_D(const Cell);
return d->formula;
}
/*!
* Returns whether the value is probably a dateTime or not
*/
bool Cell::isDateTime() const
{
Q_D(const Cell);
if (d->cellType == NumberType && d->value.toDouble() >=0
&& d->format.isValid() && d->format.isDateTimeFormat()) {
return true;
}
return false;
}
/*!
* Return the data time value.
*/
QDateTime Cell::dateTime() const
{
Q_D(const Cell);
if (!isDateTime())
return QDateTime();
return datetimeFromNumber(d->value.toDouble(), d->parent->workbook()->isDate1904());
}
/*!
* Returns whether the cell is probably a rich string or not
*/
bool Cell::isRichString() const
{
Q_D(const Cell);
if (d->cellType != SharedStringType && d->cellType != InlineStringType
&& d->cellType != StringType)
return false;
return d->richString.isRichString();
}
QT_END_NAMESPACE_XLSX

View File

@ -0,0 +1,259 @@
/****************************************************************************
** 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 "xlsxcellformula.h"
#include "xlsxcellformula_p.h"
#include "xlsxutility_p.h"
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
QT_BEGIN_NAMESPACE_XLSX
CellFormulaPrivate::CellFormulaPrivate(const QString &formula_, const CellRange &ref_, CellFormula::FormulaType type_)
:formula(formula_), type(type_), reference(ref_), ca(false), si(0)
{
//Remove the formula '=' sign if exists
if (formula.startsWith(QLatin1String("=")))
formula.remove(0,1);
else if (formula.startsWith(QLatin1String("{=")) && formula.endsWith(QLatin1String("}")))
formula = formula.mid(2, formula.length()-3);
}
CellFormulaPrivate::CellFormulaPrivate(const CellFormulaPrivate &other)
: QSharedData(other)
, formula(other.formula), type(other.type), reference(other.reference)
, ca(other.ca), si(other.si)
{
}
CellFormulaPrivate::~CellFormulaPrivate()
{
}
/*!
\class CellFormula
\inmodule QtXlsx
\brief The CellFormula class provides a API that is used to handle the cell formula.
*/
/*!
\enum CellFormula::FormulaType
\value NormalType
\value ArrayType
\value DataTableType
\value SharedType
*/
/*!
* Creates a new formula.
*/
CellFormula::CellFormula()
{
//The d pointer is initialized with a null pointer
}
/*!
* Creates a new formula with the given \a formula and \a type.
*/
CellFormula::CellFormula(const char *formula, FormulaType type)
:d(new CellFormulaPrivate(QString::fromLatin1(formula), CellRange(), type))
{
}
/*!
* Creates a new formula with the given \a formula and \a type.
*/
CellFormula::CellFormula(const QString &formula, FormulaType type)
:d(new CellFormulaPrivate(formula, CellRange(), type))
{
}
/*!
* Creates a new formula with the given \a formula, \a ref and \a type.
*/
CellFormula::CellFormula(const QString &formula, const CellRange &ref, FormulaType type)
:d(new CellFormulaPrivate(formula, ref, type))
{
}
/*!
Creates a new formula with the same attributes as the \a other formula.
*/
CellFormula::CellFormula(const CellFormula &other)
:d(other.d)
{
}
/*!
Assigns the \a other formula to this formula, and returns a
reference to this formula.
*/
CellFormula &CellFormula::operator =(const CellFormula &other)
{
d = other.d;
return *this;
}
/*!
* Destroys this formula.
*/
CellFormula::~CellFormula()
{
}
/*!
* Returns the type of the formula.
*/
CellFormula::FormulaType CellFormula::formulaType() const
{
return d ? d->type : NormalType;
}
/*!
* Returns the contents of the formula.
*/
QString CellFormula::formulaText() const
{
return d ? d->formula : QString();
}
/*!
* Returns the reference cells of the formula. For normal formula,
* this will return an invalid CellRange object.
*/
CellRange CellFormula::reference() const
{
return d ? d->reference : CellRange();
}
/*!
* Returns whether the formula is valid.
*/
bool CellFormula::isValid() const
{
return d;
}
/*!
* Returns the shared index for shared formula.
*/
int CellFormula::sharedIndex() const
{
return d && d->type == SharedType ? d->si : -1;
}
/*!
* \internal
*/
bool CellFormula::saveToXml(QXmlStreamWriter &writer) const
{
writer.writeStartElement(QStringLiteral("f"));
QString t;
switch (d->type) {
case CellFormula::ArrayType:
t = QStringLiteral("array");
break;
case CellFormula::SharedType:
t = QStringLiteral("shared");
break;
default:
break;
}
if (!t.isEmpty())
writer.writeAttribute(QStringLiteral("t"), t);
if (d->reference.isValid())
writer.writeAttribute(QStringLiteral("ref"), d->reference.toString());
if (d->ca)
writer.writeAttribute(QStringLiteral("ca"), QStringLiteral("1"));
if (d->type == CellFormula::SharedType)
writer.writeAttribute(QStringLiteral("si"), QString::number(d->si));
if (!d->formula.isEmpty())
writer.writeCharacters(d->formula);
writer.writeEndElement(); //f
return true;
}
/*!
* \internal
*/
bool CellFormula::loadFromXml(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("f"));
if (!d)
d = new CellFormulaPrivate(QString(), CellRange(), NormalType);
QXmlStreamAttributes attributes = reader.attributes();
QString typeString = attributes.value(QLatin1String("t")).toString();
if (typeString == QLatin1String("array"))
d->type = ArrayType;
else if (typeString == QLatin1String("shared"))
d->type = SharedType;
else
d->type = NormalType;
if (attributes.hasAttribute(QLatin1String("ref"))) {
QString refString = attributes.value(QLatin1String("ref")).toString();
d->reference = CellRange(refString);
}
QString ca = attributes.value(QLatin1String("si")).toString();
d->ca = parseXsdBoolean(ca, false);
if (attributes.hasAttribute(QLatin1String("si")))
d->si = attributes.value(QLatin1String("si")).toString().toInt();
d->formula = reader.readElementText();
return true;
}
/*!
* \internal
*/
bool CellFormula::operator ==(const CellFormula &formula) const
{
return d->formula == formula.d->formula && d->type == formula.d->type
&& d->si ==formula.d->si;
}
/*!
* \internal
*/
bool CellFormula::operator !=(const CellFormula &formula) const
{
return d->formula != formula.d->formula || d->type != formula.d->type
|| d->si !=formula.d->si;
}
QT_END_NAMESPACE_XLSX

View File

@ -0,0 +1,147 @@
/****************************************************************************
** 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 "xlsxcellrange.h"
#include "xlsxcellreference.h"
#include <QString>
#include <QPoint>
#include <QStringList>
QT_BEGIN_NAMESPACE_XLSX
/*!
\class CellRange
\brief For a range "A1:B2" or single cell "A1"
\inmodule QtXlsx
The CellRange class stores the top left and bottom
right rows and columns of a range in a worksheet.
*/
/*!
Constructs an range, i.e. a range
whose rowCount() and columnCount() are 0.
*/
CellRange::CellRange()
: top(-1), left(-1), bottom(-2), right(-2)
{
}
/*!
Constructs the range from the given \a top, \a
left, \a bottom and \a right rows and columns.
\sa topRow(), leftColumn(), bottomRow(), rightColumn()
*/
CellRange::CellRange(int top, int left, int bottom, int right)
: top(top), left(left), bottom(bottom), right(right)
{
}
CellRange::CellRange(const CellReference &topLeft, const CellReference &bottomRight)
: top(topLeft.row()), left(topLeft.column())
, bottom(bottomRight.row()), right(bottomRight.column())
{
}
/*!
\overload
Constructs the range form the given \a range string.
*/
CellRange::CellRange(const QString &range)
{
init(range);
}
/*!
\overload
Constructs the range form the given \a range string.
*/
CellRange::CellRange(const char *range)
{
init(QString::fromLatin1(range));
}
void CellRange::init(const QString &range)
{
QStringList rs = range.split(QLatin1Char(':'));
if (rs.size() == 2) {
CellReference start(rs[0]);
CellReference end(rs[1]);
top = start.row();
left = start.column();
bottom = end.row();
right = end.column();
} else {
CellReference p(rs[0]);
top = p.row();
left = p.column();
bottom = p.row();
right = p.column();
}
}
/*!
Constructs a the range by copying the given \a
other range.
*/
CellRange::CellRange(const CellRange &other)
: top(other.top), left(other.left), bottom(other.bottom), right(other.right)
{
}
/*!
Destroys the range.
*/
CellRange::~CellRange()
{
}
/*!
Convert the range to string notation, such as "A1:B5".
*/
QString CellRange::toString(bool row_abs, bool col_abs) const
{
if (!isValid())
return QString();
if (left == right && top == bottom) {
//Single cell
return CellReference(top, left).toString(row_abs, col_abs);
}
QString cell_1 = CellReference(top, left).toString(row_abs, col_abs);
QString cell_2 = CellReference(bottom, right).toString(row_abs, col_abs);
return cell_1 + QLatin1String(":") + cell_2;
}
/*!
* Returns true if the Range is valid.
*/
bool CellRange::isValid() const
{
return left <= right && top <= bottom;
}
QT_END_NAMESPACE_XLSX

View File

@ -0,0 +1,174 @@
/****************************************************************************
** 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 "xlsxcellreference.h"
#include <QStringList>
#include <QMap>
#include <QRegularExpression>
QT_BEGIN_NAMESPACE_XLSX
namespace {
int intPow(int x, int p)
{
if (p == 0) return 1;
if (p == 1) return x;
int tmp = intPow(x, p/2);
if (p%2 == 0) return tmp * tmp;
else return x * tmp * tmp;
}
QString col_to_name(int col_num)
{
static QMap<int, QString> col_cache;
if (!col_cache.contains(col_num)) {
QString col_str;
int remainder;
while (col_num) {
remainder = col_num % 26;
if (remainder == 0)
remainder = 26;
col_str.prepend(QChar('A'+remainder-1));
col_num = (col_num - 1) / 26;
}
col_cache.insert(col_num, col_str);
}
return col_cache[col_num];
}
int col_from_name(const QString &col_str)
{
int col = 0;
int expn = 0;
for (int i=col_str.size()-1; i>-1; --i) {
col += (col_str[i].unicode() - 'A' + 1) * intPow(26, expn);
expn++;
}
return col;
}
} //namespace
/*!
\class CellReference
\brief For one single cell such as "A1"
\inmodule QtXlsx
The CellReference class stores the cell location in a worksheet.
*/
/*!
Constructs an invalid Cell Reference
*/
CellReference::CellReference()
: _row(-1), _column(-1)
{
}
/*!
Constructs the Reference from the given \a row, and \a column.
*/
CellReference::CellReference(int row, int column)
: _row(row), _column(column)
{
}
/*!
\overload
Constructs the Reference form the given \a cell string.
*/
CellReference::CellReference(const QString &cell)
{
init(cell);
}
/*!
\overload
Constructs the Reference form the given \a cell string.
*/
CellReference::CellReference(const char *cell)
{
init(QString::fromLatin1(cell));
}
void CellReference::init(const QString &cell_str)
{
static QRegularExpression re(QStringLiteral("^\\$?([A-Z]{1,3})\\$?(\\d+)$"));
QRegularExpressionMatch match = re.match(cell_str);
if (match.hasMatch()) {
const QString col_str = match.captured(1);
const QString row_str = match.captured(2);
_row = row_str.toInt();
_column = col_from_name(col_str);
}
}
/*!
Constructs a Reference by copying the given \a
other Reference.
*/
CellReference::CellReference(const CellReference &other)
: _row(other._row), _column(other._column)
{
}
/*!
Destroys the Reference.
*/
CellReference::~CellReference()
{
}
/*!
Convert the Reference to string notation, such as "A1" or "$A$1".
If current object is invalid, an empty string will be returned.
*/
QString CellReference::toString(bool row_abs, bool col_abs) const
{
if (!isValid())
return QString();
QString cell_str;
if (col_abs)
cell_str.append(QLatin1Char('$'));
cell_str.append(col_to_name(_column));
if (row_abs)
cell_str.append(QLatin1Char('$'));
cell_str.append(QString::number(_row));
return cell_str;
}
/*!
* Returns true if the Reference is valid.
*/
bool CellReference::isValid() const
{
return _row > 0 && _column > 0;
}
QT_END_NAMESPACE_XLSX

View File

@ -0,0 +1,645 @@
/****************************************************************************
** 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 "xlsxchart_p.h"
#include "xlsxworksheet.h"
#include "xlsxcellrange.h"
#include "xlsxutility_p.h"
#include <QIODevice>
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
#include <QDebug>
QT_BEGIN_NAMESPACE_XLSX
ChartPrivate::ChartPrivate(Chart *q, Chart::CreateFlag flag)
:AbstractOOXmlFilePrivate(q, flag), chartType(static_cast<Chart::ChartType>(0))
{
}
ChartPrivate::~ChartPrivate()
{
}
/*!
* \class Chart
* \inmodule QtXlsx
* \brief Main class for the charts.
*/
/*!
\enum Chart::ChartType
\value CT_Area
\value CT_Area3D,
\value CT_Line,
\value CT_Line3D,
\value CT_Scatter,
\value CT_Pie,
\value CT_Pie3D,
\value CT_Doughnut,
\value CT_Bar,
\value CT_Bar3D,
\omitvalue CT_Stock,
\omitvalue CT_Radar,
\omitvalue CT_OfPie,
\omitvalue CT_Surface,
\omitvalue CT_Surface3D,
\omitvalue CT_Bubble
*/
/*!
* \internal
*/
Chart::Chart(AbstractSheet *parent, CreateFlag flag)
:AbstractOOXmlFile(new ChartPrivate(this, flag))
{
d_func()->sheet = parent;
}
/*!
* Destroys the chart.
*/
Chart::~Chart()
{
}
/*!
* Add the data series which is in the range \a range of the \a sheet.
*/
void Chart::addSeries(const CellRange &range, AbstractSheet *sheet)
{
Q_D(Chart);
if (!range.isValid())
return;
if (sheet && sheet->sheetType() != AbstractSheet::ST_WorkSheet)
return;
if (!sheet && d->sheet->sheetType() != AbstractSheet::ST_WorkSheet)
return;
QString sheetName = sheet ? sheet->sheetName() : d->sheet->sheetName();
//In case sheetName contains space or '
sheetName = escapeSheetName(sheetName);
if (range.columnCount() == 1 || range.rowCount() == 1) {
QSharedPointer<XlsxSeries> series = QSharedPointer<XlsxSeries>(new XlsxSeries);
series->numberDataSource_numRef = sheetName + QLatin1String("!") + range.toString(true, true);
d->seriesList.append(series);
} else if (range.columnCount() < range.rowCount()) {
//Column based series
int firstDataColumn = range.firstColumn();
QString axDataSouruce_numRef;
if (d->chartType == CT_Scatter || d->chartType == CT_Bubble) {
firstDataColumn += 1;
CellRange subRange(range.firstRow(), range.firstColumn(), range.lastRow(), range.firstColumn());
axDataSouruce_numRef = sheetName + QLatin1String("!") + subRange.toString(true, true);
}
for (int col=firstDataColumn; col<=range.lastColumn(); ++col) {
CellRange subRange(range.firstRow(), col, range.lastRow(), col);
QSharedPointer<XlsxSeries> series = QSharedPointer<XlsxSeries>(new XlsxSeries);
series->axDataSource_numRef = axDataSouruce_numRef;
series->numberDataSource_numRef = sheetName + QLatin1String("!") + subRange.toString(true, true);
d->seriesList.append(series);
}
} else {
//Row based series
int firstDataRow = range.firstRow();
QString axDataSouruce_numRef;
if (d->chartType == CT_Scatter || d->chartType == CT_Bubble) {
firstDataRow += 1;
CellRange subRange(range.firstRow(), range.firstColumn(), range.firstRow(), range.lastColumn());
axDataSouruce_numRef = sheetName + QLatin1String("!") + subRange.toString(true, true);
}
for (int row=firstDataRow; row<=range.lastRow(); ++row) {
CellRange subRange(row, range.firstColumn(), row, range.lastColumn());
QSharedPointer<XlsxSeries> series = QSharedPointer<XlsxSeries>(new XlsxSeries);
series->axDataSource_numRef = axDataSouruce_numRef;
series->numberDataSource_numRef = sheetName + QLatin1String("!") + subRange.toString(true, true);
d->seriesList.append(series);
}
}
}
/*!
* Set the type of the chart to \a type
*/
void Chart::setChartType(ChartType type)
{
Q_D(Chart);
d->chartType = type;
}
/*!
* \internal
*
*/
void Chart::setChartStyle(int id)
{
Q_UNUSED(id)
//!Todo
}
/*!
* \internal
*/
void Chart::saveToXmlFile(QIODevice *device) const
{
Q_D(const Chart);
QXmlStreamWriter writer(device);
writer.writeStartDocument(QStringLiteral("1.0"), true);
writer.writeStartElement(QStringLiteral("c:chartSpace"));
writer.writeAttribute(QStringLiteral("xmlns:c"), QStringLiteral("http://schemas.openxmlformats.org/drawingml/2006/chart"));
writer.writeAttribute(QStringLiteral("xmlns:a"), QStringLiteral("http://schemas.openxmlformats.org/drawingml/2006/main"));
writer.writeAttribute(QStringLiteral("xmlns:r"), QStringLiteral("http://schemas.openxmlformats.org/officeDocument/2006/relationships"));
d->saveXmlChart(writer);
writer.writeEndElement();//c:chartSpace
writer.writeEndDocument();
}
/*!
* \internal
*/
bool Chart::loadFromXmlFile(QIODevice *device)
{
Q_D(Chart);
QXmlStreamReader reader(device);
while (!reader.atEnd()) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("chart")) {
if (!d->loadXmlChart(reader))
return false;
}
}
}
return true;
}
bool ChartPrivate::loadXmlChart(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("chart"));
while (!reader.atEnd()) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("plotArea")) {
if (!loadXmlPlotArea(reader))
return false;
} else if (reader.name() == QLatin1String("legend")) {
//!Todo
}
} else if (reader.tokenType() == QXmlStreamReader::EndElement &&
reader.name() == QLatin1String("chart")) {
break;
}
}
return true;
}
bool ChartPrivate::loadXmlPlotArea(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("plotArea"));
while (!reader.atEnd()) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("layout")) {
//!ToDo
} else if (reader.name().endsWith(QLatin1String("Chart"))) {
//For pieChart, barChart, ...
loadXmlXxxChart(reader);
} else if (reader.name().endsWith(QLatin1String("Ax"))) {
//For valAx, catAx, serAx, dateAx
loadXmlAxis(reader);
}
} else if (reader.tokenType() == QXmlStreamReader::EndElement &&
reader.name() == QLatin1String("plotArea")) {
break;
}
}
return true;
}
bool ChartPrivate::loadXmlXxxChart(QXmlStreamReader &reader)
{
QStringRef name = reader.name();
if (name == QLatin1String("pieChart")) chartType = Chart::CT_Pie;
else if (name == QLatin1String("pie3DChart")) chartType = Chart::CT_Pie3D;
else if (name == QLatin1String("barChart")) chartType = Chart::CT_Bar;
else if (name == QLatin1String("bar3DChart")) chartType = Chart::CT_Bar3D;
else if (name == QLatin1String("lineChart")) chartType = Chart::CT_Line;
else if (name == QLatin1String("line3DChart")) chartType = Chart::CT_Line3D;
else if (name == QLatin1String("scatterChart")) chartType = Chart::CT_Scatter;
else if (name == QLatin1String("areaChart")) chartType = Chart::CT_Area;
else if (name == QLatin1String("area3DChart")) chartType = Chart::CT_Area3D;
else if (name == QLatin1String("doughnutChart")) chartType = Chart::CT_Doughnut;
else qDebug()<<"Cann't load chart: "<<name;
while (!reader.atEnd()) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("ser")) {
loadXmlSer(reader);
} else if (reader.name() == QLatin1String("axId")) {
}
} else if (reader.tokenType() == QXmlStreamReader::EndElement
&& reader.name() == name) {
break;
}
}
return true;
}
bool ChartPrivate::loadXmlSer(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("ser"));
QSharedPointer<XlsxSeries> series = QSharedPointer<XlsxSeries>(new XlsxSeries);
seriesList.append(series);
while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement
&& reader.name() == QLatin1String("ser"))) {
if (reader.readNextStartElement()) {
QStringRef name = reader.name();
if (name == QLatin1String("cat") || name == QLatin1String("xVal")) {
while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement
&& reader.name() == name)) {
if (reader.readNextStartElement()) {
if (reader.name() == QLatin1String("numRef"))
series->axDataSource_numRef = loadXmlNumRef(reader);
}
}
} else if (name == QLatin1String("val") || name == QLatin1String("yVal")) {
while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement
&& reader.name() == name)) {
if (reader.readNextStartElement()) {
if (reader.name() == QLatin1String("numRef"))
series->numberDataSource_numRef = loadXmlNumRef(reader);
}
}
} else if (name == QLatin1String("extLst")) {
while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement
&& reader.name() == name)) {
reader.readNextStartElement();
}
}
}
}
return true;
}
QString ChartPrivate::loadXmlNumRef(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("numRef"));
while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement
&& reader.name() == QLatin1String("numRef"))) {
if (reader.readNextStartElement()) {
if (reader.name() == QLatin1String("f"))
return reader.readElementText();
}
}
return QString();
}
void ChartPrivate::saveXmlChart(QXmlStreamWriter &writer) const
{
writer.writeStartElement(QStringLiteral("c:chart"));
writer.writeStartElement(QStringLiteral("c:plotArea"));
switch (chartType) {
case Chart::CT_Pie:
case Chart::CT_Pie3D:
saveXmlPieChart(writer);
break;
case Chart::CT_Bar:
case Chart::CT_Bar3D:
saveXmlBarChart(writer);
break;
case Chart::CT_Line:
case Chart::CT_Line3D:
saveXmlLineChart(writer);
break;
case Chart::CT_Scatter:
saveXmlScatterChart(writer);
break;
case Chart::CT_Area:
case Chart::CT_Area3D:
saveXmlAreaChart(writer);
break;
case Chart::CT_Doughnut:
saveXmlDoughnutChart(writer);
break;
default:
break;
}
saveXmlAxes(writer);
writer.writeEndElement(); //plotArea
// saveXmlLegend(writer);
writer.writeEndElement(); //chart
}
void ChartPrivate::saveXmlPieChart(QXmlStreamWriter &writer) const
{
QString name = chartType==Chart::CT_Pie ? QStringLiteral("c:pieChart") : QStringLiteral("c:pie3DChart");
writer.writeStartElement(name);
//Do the same behavior as Excel, Pie prefer varyColors
writer.writeEmptyElement(QStringLiteral("c:varyColors"));
writer.writeAttribute(QStringLiteral("val"), QStringLiteral("1"));
for (int i=0; i<seriesList.size(); ++i)
saveXmlSer(writer, seriesList[i].data(), i);
writer.writeEndElement(); //pieChart, pie3DChart
}
void ChartPrivate::saveXmlBarChart(QXmlStreamWriter &writer) const
{
QString name = chartType==Chart::CT_Bar ? QStringLiteral("c:barChart") : QStringLiteral("c:bar3DChart");
writer.writeStartElement(name);
writer.writeEmptyElement(QStringLiteral("c:barDir"));
writer.writeAttribute(QStringLiteral("val"), QStringLiteral("col"));
for (int i=0; i<seriesList.size(); ++i)
saveXmlSer(writer, seriesList[i].data(), i);
if (axisList.isEmpty()) {
//The order the axes??
const_cast<ChartPrivate*>(this)->axisList.append(QSharedPointer<XlsxAxis>(new XlsxAxis(XlsxAxis::T_Cat, XlsxAxis::Bottom, 0, 1)));
const_cast<ChartPrivate*>(this)->axisList.append(QSharedPointer<XlsxAxis>(new XlsxAxis(XlsxAxis::T_Val, XlsxAxis::Left, 1, 0)));
}
//Note: Bar3D have 2~3 axes
Q_ASSERT(axisList.size()==2 || (axisList.size()==3 && chartType==Chart::CT_Bar3D));
for (int i=0; i<axisList.size(); ++i) {
writer.writeEmptyElement(QStringLiteral("c:axId"));
writer.writeAttribute(QStringLiteral("val"), QString::number(axisList[i]->axisId));
}
writer.writeEndElement(); //barChart, bar3DChart
}
void ChartPrivate::saveXmlLineChart(QXmlStreamWriter &writer) const
{
QString name = chartType==Chart::CT_Line ? QStringLiteral("c:lineChart") : QStringLiteral("c:line3DChart");
writer.writeStartElement(name);
writer.writeEmptyElement(QStringLiteral("grouping"));
for (int i=0; i<seriesList.size(); ++i)
saveXmlSer(writer, seriesList[i].data(), i);
if (axisList.isEmpty()) {
const_cast<ChartPrivate*>(this)->axisList.append(QSharedPointer<XlsxAxis>(new XlsxAxis(XlsxAxis::T_Cat, XlsxAxis::Bottom, 0, 1)));
const_cast<ChartPrivate*>(this)->axisList.append(QSharedPointer<XlsxAxis>(new XlsxAxis(XlsxAxis::T_Val, XlsxAxis::Left, 1, 0)));
if (chartType==Chart::CT_Line3D)
const_cast<ChartPrivate*>(this)->axisList.append(QSharedPointer<XlsxAxis>(new XlsxAxis(XlsxAxis::T_Ser, XlsxAxis::Bottom, 2, 0)));
}
Q_ASSERT((axisList.size()==2||chartType==Chart::CT_Line)|| (axisList.size()==3 && chartType==Chart::CT_Line3D));
for (int i=0; i<axisList.size(); ++i) {
writer.writeEmptyElement(QStringLiteral("c:axId"));
writer.writeAttribute(QStringLiteral("val"), QString::number(axisList[i]->axisId));
}
writer.writeEndElement(); //lineChart, line3DChart
}
void ChartPrivate::saveXmlScatterChart(QXmlStreamWriter &writer) const
{
const QString name = QStringLiteral("c:scatterChart");
writer.writeStartElement(name);
writer.writeEmptyElement(QStringLiteral("c:scatterStyle"));
for (int i=0; i<seriesList.size(); ++i)
saveXmlSer(writer, seriesList[i].data(), i);
if (axisList.isEmpty()) {
const_cast<ChartPrivate*>(this)->axisList.append(QSharedPointer<XlsxAxis>(new XlsxAxis(XlsxAxis::T_Val, XlsxAxis::Bottom, 0, 1)));
const_cast<ChartPrivate*>(this)->axisList.append(QSharedPointer<XlsxAxis>(new XlsxAxis(XlsxAxis::T_Val, XlsxAxis::Left, 1, 0)));
}
Q_ASSERT(axisList.size()==2);
for (int i=0; i<axisList.size(); ++i) {
writer.writeEmptyElement(QStringLiteral("c:axId"));
writer.writeAttribute(QStringLiteral("val"), QString::number(axisList[i]->axisId));
}
writer.writeEndElement(); //c:scatterChart
}
void ChartPrivate::saveXmlAreaChart(QXmlStreamWriter &writer) const
{
QString name = chartType==Chart::CT_Area ? QStringLiteral("c:areaChart") : QStringLiteral("c:area3DChart");
writer.writeStartElement(name);
writer.writeEmptyElement(QStringLiteral("grouping"));
for (int i=0; i<seriesList.size(); ++i)
saveXmlSer(writer, seriesList[i].data(), i);
if (axisList.isEmpty()) {
const_cast<ChartPrivate*>(this)->axisList.append(QSharedPointer<XlsxAxis>(new XlsxAxis(XlsxAxis::T_Cat, XlsxAxis::Bottom, 0, 1)));
const_cast<ChartPrivate*>(this)->axisList.append(QSharedPointer<XlsxAxis>(new XlsxAxis(XlsxAxis::T_Val, XlsxAxis::Left, 1, 0)));
}
//Note: Area3D have 2~3 axes
Q_ASSERT(axisList.size()==2 || (axisList.size()==3 && chartType==Chart::CT_Area3D));
for (int i=0; i<axisList.size(); ++i) {
writer.writeEmptyElement(QStringLiteral("c:axId"));
writer.writeAttribute(QStringLiteral("val"), QString::number(axisList[i]->axisId));
}
writer.writeEndElement(); //lineChart, line3DChart
}
void ChartPrivate::saveXmlDoughnutChart(QXmlStreamWriter &writer) const
{
QString name = QStringLiteral("c:doughnutChart");
writer.writeStartElement(name);
writer.writeEmptyElement(QStringLiteral("c:varyColors"));
writer.writeAttribute(QStringLiteral("val"), QStringLiteral("1"));
for (int i=0; i<seriesList.size(); ++i)
saveXmlSer(writer, seriesList[i].data(), i);
writer.writeStartElement(QStringLiteral("c:holeSize"));
writer.writeAttribute(QStringLiteral("val"), QString::number(50));
writer.writeEndElement();
}
void ChartPrivate::saveXmlSer(QXmlStreamWriter &writer, XlsxSeries *ser, int id) const
{
writer.writeStartElement(QStringLiteral("c:ser"));
writer.writeEmptyElement(QStringLiteral("c:idx"));
writer.writeAttribute(QStringLiteral("val"), QString::number(id));
writer.writeEmptyElement(QStringLiteral("c:order"));
writer.writeAttribute(QStringLiteral("val"), QString::number(id));
if (!ser->axDataSource_numRef.isEmpty()) {
if (chartType == Chart::CT_Scatter || chartType == Chart::CT_Bubble)
writer.writeStartElement(QStringLiteral("c:xVal"));
else
writer.writeStartElement(QStringLiteral("c:cat"));
writer.writeStartElement(QStringLiteral("c:numRef"));
writer.writeTextElement(QStringLiteral("c:f"), ser->axDataSource_numRef);
writer.writeEndElement();//c:numRef
writer.writeEndElement();//c:cat or c:xVal
}
if (!ser->numberDataSource_numRef.isEmpty()) {
if (chartType == Chart::CT_Scatter || chartType == Chart::CT_Bubble)
writer.writeStartElement(QStringLiteral("c:yVal"));
else
writer.writeStartElement(QStringLiteral("c:val"));
writer.writeStartElement(QStringLiteral("c:numRef"));
writer.writeTextElement(QStringLiteral("c:f"), ser->numberDataSource_numRef);
writer.writeEndElement();//c:numRef
writer.writeEndElement();//c:val or c:yVal
}
writer.writeEndElement();//c:ser
}
bool ChartPrivate::loadXmlAxis(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name().endsWith(QLatin1String("Ax")));
QString name = reader.name().toString();
XlsxAxis *axis = new XlsxAxis;
if (name == QLatin1String("valAx"))
axis->type = XlsxAxis::T_Val;
else if (name == QLatin1String("catAx"))
axis->type = XlsxAxis::T_Cat;
else if (name == QLatin1String("serAx"))
axis->type = XlsxAxis::T_Ser;
else
axis->type = XlsxAxis::T_Date;
axisList.append(QSharedPointer<XlsxAxis>(axis));
while (!reader.atEnd()) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("axPos")) {
QXmlStreamAttributes attrs = reader.attributes();
QStringRef pos = attrs.value(QLatin1String("val"));
if (pos==QLatin1String("l"))
axis->axisPos = XlsxAxis::Left;
else if (pos==QLatin1String("r"))
axis->axisPos = XlsxAxis::Right;
else if (pos==QLatin1String("b"))
axis->axisPos = XlsxAxis::Bottom;
else
axis->axisPos = XlsxAxis::Top;
} else if (reader.name() == QLatin1String("axId")) {
axis->axisId = reader.attributes().value(QLatin1String("val")).toString().toInt();
} else if (reader.name() == QLatin1String("crossAx")) {
axis->crossAx = reader.attributes().value(QLatin1String("val")).toString().toInt();
}
} else if (reader.tokenType() == QXmlStreamReader::EndElement
&& reader.name() == name) {
break;
}
}
return true;
}
void ChartPrivate::saveXmlAxes(QXmlStreamWriter &writer) const
{
for (int i=0; i<axisList.size(); ++i) {
XlsxAxis *axis = axisList[i].data();
QString name;
switch (axis->type) {
case XlsxAxis::T_Cat: name = QStringLiteral("c:catAx"); break;
case XlsxAxis::T_Val: name = QStringLiteral("c:valAx"); break;
case XlsxAxis::T_Ser: name = QStringLiteral("c:serAx"); break;
case XlsxAxis::T_Date: name = QStringLiteral("c:dateAx"); break;
default: break;
}
QString pos;
switch (axis->axisPos) {
case XlsxAxis::Top: pos = QStringLiteral("t"); break;
case XlsxAxis::Bottom: pos = QStringLiteral("b"); break;
case XlsxAxis::Left: pos = QStringLiteral("l"); break;
case XlsxAxis::Right: pos = QStringLiteral("r"); break;
default: break;
}
writer.writeStartElement(name);
writer.writeEmptyElement(QStringLiteral("c:axId"));
writer.writeAttribute(QStringLiteral("val"), QString::number(axis->axisId));
writer.writeStartElement(QStringLiteral("c:scaling"));
writer.writeEmptyElement(QStringLiteral("c:orientation"));
writer.writeAttribute(QStringLiteral("val"), QStringLiteral("minMax"));
writer.writeEndElement();//c:scaling
writer.writeEmptyElement(QStringLiteral("c:axPos"));
writer.writeAttribute(QStringLiteral("val"), pos);
writer.writeEmptyElement(QStringLiteral("c:crossAx"));
writer.writeAttribute(QStringLiteral("val"), QString::number(axis->crossAx));
writer.writeEndElement();//name
}
}
QT_END_NAMESPACE_XLSX

View File

@ -0,0 +1,159 @@
/****************************************************************************
** 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 "xlsxchartsheet.h"
#include "xlsxchartsheet_p.h"
#include "xlsxworkbook.h"
#include "xlsxutility_p.h"
#include "xlsxdrawing_p.h"
#include "xlsxdrawinganchor_p.h"
#include "xlsxchart.h"
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
#include <QDir>
QT_BEGIN_NAMESPACE_XLSX
ChartsheetPrivate::ChartsheetPrivate(Chartsheet *p, Chartsheet::CreateFlag flag)
: AbstractSheetPrivate(p, flag), chart(0)
{
}
ChartsheetPrivate::~ChartsheetPrivate()
{
}
/*!
\class Chartsheet
\inmodule QtXlsx
\brief Represent one chartsheet in the workbook.
*/
/*!
* \internal
*/
Chartsheet::Chartsheet(const QString &name, int id, Workbook *workbook, CreateFlag flag)
:AbstractSheet(name, id, workbook, new ChartsheetPrivate(this, flag))
{
setSheetType(ST_ChartSheet);
if (flag == Chartsheet::F_NewFromScratch) {
d_func()->drawing = QSharedPointer<Drawing>(new Drawing(this, flag));
DrawingAbsoluteAnchor *anchor = new DrawingAbsoluteAnchor(drawing(), DrawingAnchor::Picture);
anchor->pos = QPoint(0, 0);
anchor->ext = QSize(9293679, 6068786);
QSharedPointer<Chart> chart = QSharedPointer<Chart>(new Chart(this, flag));
chart->setChartType(Chart::CT_Bar);
anchor->setObjectGraphicFrame(chart);
d_func()->chart = chart.data();
}
}
/*!
* \internal
*
* Make a copy of this sheet.
*/
Chartsheet *Chartsheet::copy(const QString &distName, int distId) const
{
//:Todo
Q_UNUSED(distName)
Q_UNUSED(distId)
return 0;
}
/*!
* Destroys this workssheet.
*/
Chartsheet::~Chartsheet()
{
}
/*!
* Returns the chart object of the sheet.
*/
Chart *Chartsheet::chart()
{
Q_D(Chartsheet);
return d->chart;
}
void Chartsheet::saveToXmlFile(QIODevice *device) const
{
Q_D(const Chartsheet);
d->relationships->clear();
QXmlStreamWriter writer(device);
writer.writeStartDocument(QStringLiteral("1.0"), true);
writer.writeDefaultNamespace(QStringLiteral("http://schemas.openxmlformats.org/spreadsheetml/2006/main"));
writer.writeNamespace(QStringLiteral("http://schemas.openxmlformats.org/officeDocument/2006/relationships"), QStringLiteral("r"));
writer.writeStartElement(QStringLiteral("chartsheet"));
writer.writeStartElement(QStringLiteral("sheetViews"));
writer.writeEmptyElement(QStringLiteral("sheetView"));
writer.writeAttribute(QStringLiteral("workbookViewId"), QString::number(0));
writer.writeAttribute(QStringLiteral("zoomToFit"), QStringLiteral("1"));
writer.writeEndElement(); //sheetViews
int idx = d->workbook->drawings().indexOf(d->drawing.data());
d->relationships->addWorksheetRelationship(QStringLiteral("/drawing"), QStringLiteral("../drawings/drawing%1.xml").arg(idx+1));
writer.writeEmptyElement(QStringLiteral("drawing"));
writer.writeAttribute(QStringLiteral("r:id"), QStringLiteral("rId%1").arg(d->relationships->count()));
writer.writeEndElement();//chartsheet
writer.writeEndDocument();
}
bool Chartsheet::loadFromXmlFile(QIODevice *device)
{
Q_D(Chartsheet);
QXmlStreamReader reader(device);
while (!reader.atEnd()) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("drawing")) {
QString rId = reader.attributes().value(QStringLiteral("r:id")).toString();
QString name = d->relationships->getRelationshipById(rId).target;
QString path = QDir::cleanPath(splitPath(filePath())[0] + QLatin1String("/") + name);
d->drawing = QSharedPointer<Drawing>(new Drawing(this, F_LoadFromExists));
d->drawing->setFilePath(path);
}
}
}
return true;
}
QT_END_NAMESPACE_XLSX

View File

@ -0,0 +1,198 @@
#include "xlsxcolor_p.h"
#include "xlsxstyles_p.h"
#include "xlsxutility_p.h"
#include <QDataStream>
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
#include <QDebug>
namespace QXlsx {
XlsxColor::XlsxColor(const QColor &color)
{
if (color.isValid())
val.setValue(color);
}
XlsxColor::XlsxColor(const QString &theme, const QString &tint)
:val(QStringList()<<theme<<tint)
{
}
XlsxColor::XlsxColor(int index)
:val(index)
{
}
bool XlsxColor::isRgbColor() const
{
if (val.userType() == qMetaTypeId<QColor>() && val.value<QColor>().isValid())
return true;
return false;
}
bool XlsxColor::isIndexedColor() const
{
return val.userType() == QMetaType::Int;
}
bool XlsxColor::isThemeColor() const
{
return val.userType() == QMetaType::QStringList;
}
bool XlsxColor::isInvalid() const
{
return !val.isValid();
}
QColor XlsxColor::rgbColor() const
{
if (isRgbColor())
return val.value<QColor>();
return QColor();
}
int XlsxColor::indexedColor() const
{
if (isIndexedColor())
return val.toInt();
return -1;
}
QStringList XlsxColor::themeColor() const
{
if (isThemeColor())
return val.toStringList();
return QStringList();
}
bool XlsxColor::saveToXml(QXmlStreamWriter &writer, const QString &node) const
{
if (!node.isEmpty())
writer.writeEmptyElement(node); //color, bgColor, fgColor
else
writer.writeEmptyElement(QStringLiteral("color"));
if (val.userType() == qMetaTypeId<QColor>()) {
writer.writeAttribute(QStringLiteral("rgb"), XlsxColor::toARGBString(val.value<QColor>()));
} else if (val.userType() == QMetaType::QStringList) {
QStringList themes = val.toStringList();
writer.writeAttribute(QStringLiteral("theme"), themes[0]);
if (!themes[1].isEmpty())
writer.writeAttribute(QStringLiteral("tint"), themes[1]);
} else if (val.userType() == QMetaType::Int) {
writer.writeAttribute(QStringLiteral("indexed"), val.toString());
} else {
writer.writeAttribute(QStringLiteral("auto"), QStringLiteral("1"));
}
return true;
}
bool XlsxColor::loadFromXml(QXmlStreamReader &reader)
{
QXmlStreamAttributes attributes = reader.attributes();
if (attributes.hasAttribute(QLatin1String("rgb"))) {
QString colorString = attributes.value(QLatin1String("rgb")).toString();
val.setValue(fromARGBString(colorString));
} else if (attributes.hasAttribute(QLatin1String("indexed"))) {
int index = attributes.value(QLatin1String("indexed")).toString().toInt();
val.setValue(index);
} else if (attributes.hasAttribute(QLatin1String("theme"))) {
QString theme = attributes.value(QLatin1String("theme")).toString();
QString tint = attributes.value(QLatin1String("tint")).toString();
val.setValue(QStringList()<<theme<<tint);
}
return true;
}
XlsxColor::operator QVariant() const
{
return QVariant(qMetaTypeId<XlsxColor>(), this);
}
QColor XlsxColor::fromARGBString(const QString &c)
{
Q_ASSERT(c.length() == 8);
QColor color;
color.setAlpha(c.mid(0, 2).toInt(0, 16));
color.setRed(c.mid(2, 2).toInt(0, 16));
color.setGreen(c.mid(4, 2).toInt(0, 16));
color.setBlue(c.mid(6, 2).toInt(0, 16));
return color;
}
QString XlsxColor::toARGBString(const QColor &c)
{
QString color;
color.sprintf("%02X%02X%02X%02X", c.alpha(), c.red(), c.green(), c.blue());
return color;
}
#if !defined(QT_NO_DATASTREAM)
QDataStream &operator<<(QDataStream &s, const XlsxColor &color)
{
if (color.isInvalid())
s<<0;
else if (color.isRgbColor())
s<<1<<color.rgbColor();
else if (color.isIndexedColor())
s<<2<<color.indexedColor();
else if (color.isThemeColor())
s<<3<<color.themeColor();
else
s<<4;
return s;
}
QDataStream &operator>>(QDataStream &s, XlsxColor &color)
{
int marker(4);
s>>marker;
if (marker == 0) {
color = XlsxColor();
} else if (marker == 1) {
QColor c;
s>>c;
color = XlsxColor(c);
} else if (marker == 2) {
int indexed;
s>>indexed;
color = XlsxColor(indexed);
} else if (marker == 3) {
QStringList list;
s>>list;
color = XlsxColor(list[0], list[1]);
}
return s;
}
#endif
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, const XlsxColor &c)
{
if (c.isInvalid())
dbg.nospace() << "XlsxColor(invalid)";
else if (c.isRgbColor())
dbg.nospace() << c.rgbColor();
else if (c.isIndexedColor())
dbg.nospace() << "XlsxColor(indexed," << c.indexedColor() << ")";
else if (c.isThemeColor())
dbg.nospace() << "XlsxColor(theme," << c.themeColor().join(QLatin1Char(':')) << ")";
return dbg.space();
}
#endif
} // namespace QXlsx

View File

@ -0,0 +1,735 @@
/****************************************************************************
** 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(' ')));
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
} 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
return true;
}
QT_END_NAMESPACE_XLSX

View File

@ -0,0 +1,205 @@
/****************************************************************************
** 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 "xlsxcontenttypes_p.h"
#include <QXmlStreamWriter>
#include <QXmlStreamReader>
#include <QFile>
#include <QMapIterator>
#include <QBuffer>
#include <QDebug>
namespace QXlsx {
ContentTypes::ContentTypes(CreateFlag flag)
:AbstractOOXmlFile(flag)
{
m_package_prefix = QStringLiteral("application/vnd.openxmlformats-package.");
m_document_prefix = QStringLiteral("application/vnd.openxmlformats-officedocument.");
m_defaults.insert(QStringLiteral("rels"), m_package_prefix + QStringLiteral("relationships+xml"));
m_defaults.insert(QStringLiteral("xml"), QStringLiteral("application/xml"));
}
void ContentTypes::addDefault(const QString &key, const QString &value)
{
m_defaults.insert(key, value);
}
void ContentTypes::addOverride(const QString &key, const QString &value)
{
m_overrides.insert(key, value);
}
void ContentTypes::addDocPropApp()
{
addOverride(QStringLiteral("/docProps/app.xml"), m_document_prefix + QStringLiteral("extended-properties+xml"));
}
void ContentTypes::addDocPropCore()
{
addOverride(QStringLiteral("/docProps/core.xml"), m_package_prefix + QStringLiteral("core-properties+xml"));
}
void ContentTypes::addStyles()
{
addOverride(QStringLiteral("/xl/styles.xml"), m_document_prefix + QStringLiteral("spreadsheetml.styles+xml"));
}
void ContentTypes::addTheme()
{
addOverride(QStringLiteral("/xl/theme/theme1.xml"), m_document_prefix + QStringLiteral("theme+xml"));
}
void ContentTypes::addWorkbook()
{
addOverride(QStringLiteral("/xl/workbook.xml"), m_document_prefix + QStringLiteral("spreadsheetml.sheet.main+xml"));
}
void ContentTypes::addWorksheetName(const QString &name)
{
addOverride(QStringLiteral("/xl/worksheets/%1.xml").arg(name), m_document_prefix + QStringLiteral("spreadsheetml.worksheet+xml"));
}
void ContentTypes::addChartsheetName(const QString &name)
{
addOverride(QStringLiteral("/xl/chartsheets/%1.xml").arg(name), m_document_prefix + QStringLiteral("spreadsheetml.chartsheet+xml"));
}
void ContentTypes::addDrawingName(const QString &name)
{
addOverride(QStringLiteral("/xl/drawings/%1.xml").arg(name), m_document_prefix + QStringLiteral("drawing+xml"));
}
void ContentTypes::addChartName(const QString &name)
{
addOverride(QStringLiteral("/xl/charts/%1.xml").arg(name), m_document_prefix + QStringLiteral("drawingml.chart+xml"));
}
void ContentTypes::addCommentName(const QString &name)
{
addOverride(QStringLiteral("/xl/%1.xml").arg(name), m_document_prefix + QStringLiteral("spreadsheetml.comments+xml"));
}
void ContentTypes::addTableName(const QString &name)
{
addOverride(QStringLiteral("/xl/tables/%1.xml").arg(name), m_document_prefix + QStringLiteral("spreadsheetml.table+xml"));
}
void ContentTypes::addExternalLinkName(const QString &name)
{
addOverride(QStringLiteral("/xl/externalLinks/%1.xml").arg(name), m_document_prefix + QStringLiteral("spreadsheetml.externalLink+xml"));
}
void ContentTypes::addSharedString()
{
addOverride(QStringLiteral("/xl/sharedStrings.xml"), m_document_prefix + QStringLiteral("spreadsheetml.sharedStrings+xml"));
}
void ContentTypes::addVmlName()
{
addOverride(QStringLiteral("vml"), m_document_prefix + QStringLiteral("vmlDrawing"));
}
void ContentTypes::addCalcChain()
{
addOverride(QStringLiteral("/xl/calcChain.xml"), m_document_prefix + QStringLiteral("spreadsheetml.calcChain+xml"));
}
void ContentTypes::addVbaProject()
{
//:TODO
addOverride(QStringLiteral("bin"), QStringLiteral("application/vnd.ms-office.vbaProject"));
}
void ContentTypes::clearOverrides()
{
m_overrides.clear();
}
void ContentTypes::saveToXmlFile(QIODevice *device) const
{
QXmlStreamWriter writer(device);
writer.writeStartDocument(QStringLiteral("1.0"), true);
writer.writeStartElement(QStringLiteral("Types"));
writer.writeAttribute(QStringLiteral("xmlns"), QStringLiteral("http://schemas.openxmlformats.org/package/2006/content-types"));
{
QMapIterator<QString, QString> it(m_defaults);
while (it.hasNext()) {
it.next();
writer.writeStartElement(QStringLiteral("Default"));
writer.writeAttribute(QStringLiteral("Extension"), it.key());
writer.writeAttribute(QStringLiteral("ContentType"), it.value());
writer.writeEndElement();//Default
}
}
{
QMapIterator<QString, QString> it(m_overrides);
while (it.hasNext()) {
it.next();
writer.writeStartElement(QStringLiteral("Override"));
writer.writeAttribute(QStringLiteral("PartName"), it.key());
writer.writeAttribute(QStringLiteral("ContentType"), it.value());
writer.writeEndElement(); //Override
}
}
writer.writeEndElement();//Types
writer.writeEndDocument();
}
bool ContentTypes::loadFromXmlFile(QIODevice *device)
{
m_defaults.clear();
m_overrides.clear();
QXmlStreamReader reader(device);
while (!reader.atEnd()) {
QXmlStreamReader::TokenType token = reader.readNext();
if (token == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("Default")) {
QXmlStreamAttributes attrs = reader.attributes();
QString extension = attrs.value(QLatin1String("Extension")).toString();
QString type = attrs.value(QLatin1String("ContentType")).toString();
m_defaults.insert(extension, type);
} else if (reader.name() == QLatin1String("Override")) {
QXmlStreamAttributes attrs = reader.attributes();
QString partName = attrs.value(QLatin1String("PartName")).toString();
QString type = attrs.value(QLatin1String("ContentType")).toString();
m_overrides.insert(partName, type);
}
}
if (reader.hasError()) {
qDebug()<<reader.errorString();
}
}
return true;
}
} //namespace QXlsx

View File

@ -0,0 +1,552 @@
/****************************************************************************
** 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 "xlsxdatavalidation.h"
#include "xlsxdatavalidation_p.h"
#include "xlsxworksheet.h"
#include "xlsxcellrange.h"
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
QT_BEGIN_NAMESPACE_XLSX
DataValidationPrivate::DataValidationPrivate()
:validationType(DataValidation::None), validationOperator(DataValidation::Between)
, errorStyle(DataValidation::Stop), allowBlank(false), isPromptMessageVisible(true)
, isErrorMessageVisible(true)
{
}
DataValidationPrivate::DataValidationPrivate(DataValidation::ValidationType type, DataValidation::ValidationOperator op, const QString &formula1, const QString &formula2, bool allowBlank)
:validationType(type), validationOperator(op)
, errorStyle(DataValidation::Stop), allowBlank(allowBlank), isPromptMessageVisible(true)
, isErrorMessageVisible(true), formula1(formula1), formula2(formula2)
{
}
DataValidationPrivate::DataValidationPrivate(const DataValidationPrivate &other)
:QSharedData(other)
, validationType(DataValidation::None), validationOperator(DataValidation::Between)
, errorStyle(DataValidation::Stop), allowBlank(false), isPromptMessageVisible(true)
, isErrorMessageVisible(true)
{
}
DataValidationPrivate::~DataValidationPrivate()
{
}
/*!
* \class DataValidation
* \brief Data validation for single cell or a range
* \inmodule QtXlsx
*
* The data validation can be applied to a single cell or a range of cells.
*/
/*!
* \enum DataValidation::ValidationType
*
* The enum type defines the type of data that you wish to validate.
*
* \value None the type of data is unrestricted. This is the same as not applying a data validation.
* \value Whole restricts the cell to integer values. Means "Whole number"?
* \value Decimal restricts the cell to decimal values.
* \value List restricts the cell to a set of user specified values.
* \value Date restricts the cell to date values.
* \value Time restricts the cell to time values.
* \value TextLength restricts the cell data based on an integer string length.
* \value Custom restricts the cell based on an external Excel formula that returns a true/false value.
*/
/*!
* \enum DataValidation::ValidationOperator
*
* The enum type defines the criteria by which the data in the
* cell is validated
*
* \value Between
* \value NotBetween
* \value Equal
* \value NotEqual
* \value LessThan
* \value LessThanOrEqual
* \value GreaterThan
* \value GreaterThanOrEqual
*/
/*!
* \enum DataValidation::ErrorStyle
*
* The enum type defines the type of error dialog that
* is displayed.
*
* \value Stop
* \value Warning
* \value Information
*/
/*!
* Construct a data validation object with the given \a type, \a op, \a formula1
* \a formula2, and \a allowBlank.
*/
DataValidation::DataValidation(ValidationType type, ValidationOperator op, const QString &formula1, const QString &formula2, bool allowBlank)
:d(new DataValidationPrivate(type, op, formula1, formula2, allowBlank))
{
}
/*!
Construct a data validation object
*/
DataValidation::DataValidation()
:d(new DataValidationPrivate())
{
}
/*!
Constructs a copy of \a other.
*/
DataValidation::DataValidation(const DataValidation &other)
:d(other.d)
{
}
/*!
Assigns \a other to this validation and returns a reference to this validation.
*/
DataValidation &DataValidation::operator=(const DataValidation &other)
{
this->d = other.d;
return *this;
}
/*!
* Destroy the object.
*/
DataValidation::~DataValidation()
{
}
/*!
Returns the validation type.
*/
DataValidation::ValidationType DataValidation::validationType() const
{
return d->validationType;
}
/*!
Returns the validation operator.
*/
DataValidation::ValidationOperator DataValidation::validationOperator() const
{
return d->validationOperator;
}
/*!
Returns the validation error style.
*/
DataValidation::ErrorStyle DataValidation::errorStyle() const
{
return d->errorStyle;
}
/*!
Returns the formula1.
*/
QString DataValidation::formula1() const
{
return d->formula1;
}
/*!
Returns the formula2.
*/
QString DataValidation::formula2() const
{
return d->formula2;
}
/*!
Returns whether blank is allowed.
*/
bool DataValidation::allowBlank() const
{
return d->allowBlank;
}
/*!
Returns the error message.
*/
QString DataValidation::errorMessage() const
{
return d->errorMessage;
}
/*!
Returns the error message title.
*/
QString DataValidation::errorMessageTitle() const
{
return d->errorMessageTitle;
}
/*!
Returns the prompt message.
*/
QString DataValidation::promptMessage() const
{
return d->promptMessage;
}
/*!
Returns the prompt message title.
*/
QString DataValidation::promptMessageTitle() const
{
return d->promptMessageTitle;
}
/*!
Returns the whether prompt message is shown.
*/
bool DataValidation::isPromptMessageVisible() const
{
return d->isPromptMessageVisible;
}
/*!
Returns the whether error message is shown.
*/
bool DataValidation::isErrorMessageVisible() const
{
return d->isErrorMessageVisible;
}
/*!
Returns the ranges on which the validation will be applied.
*/
QList<CellRange> DataValidation::ranges() const
{
return d->ranges;
}
/*!
Sets the validation type to \a type.
*/
void DataValidation::setValidationType(DataValidation::ValidationType type)
{
d->validationType = type;
}
/*!
Sets the validation operator to \a op.
*/
void DataValidation::setValidationOperator(DataValidation::ValidationOperator op)
{
d->validationOperator = op;
}
/*!
Sets the error style to \a es.
*/
void DataValidation::setErrorStyle(DataValidation::ErrorStyle es)
{
d->errorStyle = es;
}
/*!
Sets the formula1 to \a formula.
*/
void DataValidation::setFormula1(const QString &formula)
{
if (formula.startsWith(QLatin1Char('=')))
d->formula1 = formula.mid(1);
else
d->formula1 = formula;
}
/*!
Sets the formulas to \a formula.
*/
void DataValidation::setFormula2(const QString &formula)
{
if (formula.startsWith(QLatin1Char('=')))
d->formula2 = formula.mid(1);
else
d->formula2 = formula;
}
/*!
Sets the error message to \a error with title \a title.
*/
void DataValidation::setErrorMessage(const QString &error, const QString &title)
{
d->errorMessage = error;
d->errorMessageTitle = title;
}
/*!
Sets the prompt message to \a prompt with title \a title.
*/
void DataValidation::setPromptMessage(const QString &prompt, const QString &title)
{
d->promptMessage = prompt;
d->promptMessageTitle = title;
}
/*!
Enable/disabe blank allow based on \a enable.
*/
void DataValidation::setAllowBlank(bool enable)
{
d->allowBlank = enable;
}
/*!
Enable/disabe prompt message visible based on \a visible.
*/
void DataValidation::setPromptMessageVisible(bool visible)
{
d->isPromptMessageVisible = visible;
}
/*!
Enable/disabe error message visible based on \a visible.
*/
void DataValidation::setErrorMessageVisible(bool visible)
{
d->isErrorMessageVisible = visible;
}
/*!
Add the \a cell on which the DataValidation will apply to.
*/
void DataValidation::addCell(const CellReference &cell)
{
d->ranges.append(CellRange(cell, cell));
}
/*!
\overload
Add the cell(\a row, \a col) on which the DataValidation will apply to.
*/
void DataValidation::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 DataValidation will apply to.
*/
void DataValidation::addRange(int firstRow, int firstCol, int lastRow, int lastCol)
{
d->ranges.append(CellRange(firstRow, firstCol, lastRow, lastCol));
}
/*!
Add the \a range on which the DataValidation will apply to.
*/
void DataValidation::addRange(const CellRange &range)
{
d->ranges.append(range);
}
/*!
* \internal
*/
bool DataValidation::saveToXml(QXmlStreamWriter &writer) const
{
static QMap<DataValidation::ValidationType, QString> typeMap;
static QMap<DataValidation::ValidationOperator, QString> opMap;
static QMap<DataValidation::ErrorStyle, QString> esMap;
if (typeMap.isEmpty()) {
typeMap.insert(DataValidation::None, QStringLiteral("none"));
typeMap.insert(DataValidation::Whole, QStringLiteral("whole"));
typeMap.insert(DataValidation::Decimal, QStringLiteral("decimal"));
typeMap.insert(DataValidation::List, QStringLiteral("list"));
typeMap.insert(DataValidation::Date, QStringLiteral("date"));
typeMap.insert(DataValidation::Time, QStringLiteral("time"));
typeMap.insert(DataValidation::TextLength, QStringLiteral("textLength"));
typeMap.insert(DataValidation::Custom, QStringLiteral("custom"));
opMap.insert(DataValidation::Between, QStringLiteral("between"));
opMap.insert(DataValidation::NotBetween, QStringLiteral("notBetween"));
opMap.insert(DataValidation::Equal, QStringLiteral("equal"));
opMap.insert(DataValidation::NotEqual, QStringLiteral("notEqual"));
opMap.insert(DataValidation::LessThan, QStringLiteral("lessThan"));
opMap.insert(DataValidation::LessThanOrEqual, QStringLiteral("lessThanOrEqual"));
opMap.insert(DataValidation::GreaterThan, QStringLiteral("greaterThan"));
opMap.insert(DataValidation::GreaterThanOrEqual, QStringLiteral("greaterThanOrEqual"));
esMap.insert(DataValidation::Stop, QStringLiteral("stop"));
esMap.insert(DataValidation::Warning, QStringLiteral("warning"));
esMap.insert(DataValidation::Information, QStringLiteral("information"));
}
writer.writeStartElement(QStringLiteral("dataValidation"));
if (validationType() != DataValidation::None)
writer.writeAttribute(QStringLiteral("type"), typeMap[validationType()]);
if (errorStyle() != DataValidation::Stop)
writer.writeAttribute(QStringLiteral("errorStyle"), esMap[errorStyle()]);
if (validationOperator() != DataValidation::Between)
writer.writeAttribute(QStringLiteral("operator"), opMap[validationOperator()]);
if (allowBlank())
writer.writeAttribute(QStringLiteral("allowBlank"), QStringLiteral("1"));
// if (dropDownVisible())
// writer.writeAttribute(QStringLiteral("showDropDown"), QStringLiteral("1"));
if (isPromptMessageVisible())
writer.writeAttribute(QStringLiteral("showInputMessage"), QStringLiteral("1"));
if (isErrorMessageVisible())
writer.writeAttribute(QStringLiteral("showErrorMessage"), QStringLiteral("1"));
if (!errorMessageTitle().isEmpty())
writer.writeAttribute(QStringLiteral("errorTitle"), errorMessageTitle());
if (!errorMessage().isEmpty())
writer.writeAttribute(QStringLiteral("error"), errorMessage());
if (!promptMessageTitle().isEmpty())
writer.writeAttribute(QStringLiteral("promptTitle"), promptMessageTitle());
if (!promptMessage().isEmpty())
writer.writeAttribute(QStringLiteral("prompt"), promptMessage());
QStringList sqref;
foreach (CellRange range, ranges())
sqref.append(range.toString());
writer.writeAttribute(QStringLiteral("sqref"), sqref.join(QLatin1Char(' ')));
if (!formula1().isEmpty())
writer.writeTextElement(QStringLiteral("formula1"), formula1());
if (!formula2().isEmpty())
writer.writeTextElement(QStringLiteral("formula2"), formula2());
writer.writeEndElement(); //dataValidation
return true;
}
/*!
* \internal
*/
DataValidation DataValidation::loadFromXml(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("dataValidation"));
static QMap<QString, DataValidation::ValidationType> typeMap;
static QMap<QString, DataValidation::ValidationOperator> opMap;
static QMap<QString, DataValidation::ErrorStyle> esMap;
if (typeMap.isEmpty()) {
typeMap.insert(QStringLiteral("none"), DataValidation::None);
typeMap.insert(QStringLiteral("whole"), DataValidation::Whole);
typeMap.insert(QStringLiteral("decimal"), DataValidation::Decimal);
typeMap.insert(QStringLiteral("list"), DataValidation::List);
typeMap.insert(QStringLiteral("date"), DataValidation::Date);
typeMap.insert(QStringLiteral("time"), DataValidation::Time);
typeMap.insert(QStringLiteral("textLength"), DataValidation::TextLength);
typeMap.insert(QStringLiteral("custom"), DataValidation::Custom);
opMap.insert(QStringLiteral("between"), DataValidation::Between);
opMap.insert(QStringLiteral("notBetween"), DataValidation::NotBetween);
opMap.insert(QStringLiteral("equal"), DataValidation::Equal);
opMap.insert(QStringLiteral("notEqual"), DataValidation::NotEqual);
opMap.insert(QStringLiteral("lessThan"), DataValidation::LessThan);
opMap.insert(QStringLiteral("lessThanOrEqual"), DataValidation::LessThanOrEqual);
opMap.insert(QStringLiteral("greaterThan"), DataValidation::GreaterThan);
opMap.insert(QStringLiteral("greaterThanOrEqual"), DataValidation::GreaterThanOrEqual);
esMap.insert(QStringLiteral("stop"), DataValidation::Stop);
esMap.insert(QStringLiteral("warning"), DataValidation::Warning);
esMap.insert(QStringLiteral("information"), DataValidation::Information);
}
DataValidation validation;
QXmlStreamAttributes attrs = reader.attributes();
QString sqref = attrs.value(QLatin1String("sqref")).toString();
foreach (QString range, sqref.split(QLatin1Char(' ')))
validation.addRange(range);
if (attrs.hasAttribute(QLatin1String("type"))) {
QString t = attrs.value(QLatin1String("type")).toString();
validation.setValidationType(typeMap.contains(t) ? typeMap[t] : DataValidation::None);
}
if (attrs.hasAttribute(QLatin1String("errorStyle"))) {
QString es = attrs.value(QLatin1String("errorStyle")).toString();
validation.setErrorStyle(esMap.contains(es) ? esMap[es] : DataValidation::Stop);
}
if (attrs.hasAttribute(QLatin1String("operator"))) {
QString op = attrs.value(QLatin1String("operator")).toString();
validation.setValidationOperator(opMap.contains(op) ? opMap[op] : DataValidation::Between);
}
if (attrs.hasAttribute(QLatin1String("allowBlank"))) {
validation.setAllowBlank(true);
} else {
validation.setAllowBlank(false);
}
if (attrs.hasAttribute(QLatin1String("showInputMessage"))) {
validation.setPromptMessageVisible(true);
} else {
validation.setPromptMessageVisible(false);
}
if (attrs.hasAttribute(QLatin1String("showErrorMessage"))) {
validation.setErrorMessageVisible(true);
} else {
validation.setErrorMessageVisible(false);
}
QString et = attrs.value(QLatin1String("errorTitle")).toString();
QString e = attrs.value(QLatin1String("error")).toString();
if (!e.isEmpty() || !et.isEmpty())
validation.setErrorMessage(e, et);
QString pt = attrs.value(QLatin1String("promptTitle")).toString();
QString p = attrs.value(QLatin1String("prompt")).toString();
if (!p.isEmpty() || !pt.isEmpty())
validation.setPromptMessage(p, pt);
//find the end
while(!(reader.name() == QLatin1String("dataValidation") && reader.tokenType() == QXmlStreamReader::EndElement)) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("formula1")) {
validation.setFormula1(reader.readElementText());
} else if (reader.name() == QLatin1String("formula2")) {
validation.setFormula2(reader.readElementText());
}
}
}
return validation;
}
QT_END_NAMESPACE_XLSX

View File

@ -0,0 +1,157 @@
/****************************************************************************
** 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 "xlsxdocpropsapp_p.h"
#include <QXmlStreamWriter>
#include <QXmlStreamReader>
#include <QDir>
#include <QFile>
#include <QDateTime>
#include <QVariant>
#include <QBuffer>
namespace QXlsx {
DocPropsApp::DocPropsApp(CreateFlag flag)
:AbstractOOXmlFile(flag)
{
}
void DocPropsApp::addPartTitle(const QString &title)
{
m_titlesOfPartsList.append(title);
}
void DocPropsApp::addHeadingPair(const QString &name, int value)
{
m_headingPairsList.append(qMakePair(name, value));
}
bool DocPropsApp::setProperty(const QString &name, const QString &value)
{
static QStringList validKeys;
if (validKeys.isEmpty()) {
validKeys << QStringLiteral("manager") << QStringLiteral("company");
}
if (!validKeys.contains(name))
return false;
if (value.isEmpty())
m_properties.remove(name);
else
m_properties[name] = value;
return true;
}
QString DocPropsApp::property(const QString &name) const
{
if (m_properties.contains(name))
return m_properties[name];
return QString();
}
QStringList DocPropsApp::propertyNames() const
{
return m_properties.keys();
}
void DocPropsApp::saveToXmlFile(QIODevice *device) const
{
QXmlStreamWriter writer(device);
QString vt = QStringLiteral("http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes");
writer.writeStartDocument(QStringLiteral("1.0"), true);
writer.writeStartElement(QStringLiteral("Properties"));
writer.writeDefaultNamespace(QStringLiteral("http://schemas.openxmlformats.org/officeDocument/2006/extended-properties"));
writer.writeNamespace(vt, QStringLiteral("vt"));
writer.writeTextElement(QStringLiteral("Application"), QStringLiteral("Microsoft Excel"));
writer.writeTextElement(QStringLiteral("DocSecurity"), QStringLiteral("0"));
writer.writeTextElement(QStringLiteral("ScaleCrop"), QStringLiteral("false"));
writer.writeStartElement(QStringLiteral("HeadingPairs"));
writer.writeStartElement(vt, QStringLiteral("vector"));
writer.writeAttribute(QStringLiteral("size"), QString::number(m_headingPairsList.size()*2));
writer.writeAttribute(QStringLiteral("baseType"), QStringLiteral("variant"));
typedef QPair<QString,int> PairType; //Make foreach happy
foreach (PairType pair, m_headingPairsList) {
writer.writeStartElement(vt, QStringLiteral("variant"));
writer.writeTextElement(vt, QStringLiteral("lpstr"), pair.first);
writer.writeEndElement(); //vt:variant
writer.writeStartElement(vt, QStringLiteral("variant"));
writer.writeTextElement(vt, QStringLiteral("i4"), QString::number(pair.second));
writer.writeEndElement(); //vt:variant
}
writer.writeEndElement();//vt:vector
writer.writeEndElement();//HeadingPairs
writer.writeStartElement(QStringLiteral("TitlesOfParts"));
writer.writeStartElement(vt, QStringLiteral("vector"));
writer.writeAttribute(QStringLiteral("size"), QString::number(m_titlesOfPartsList.size()));
writer.writeAttribute(QStringLiteral("baseType"), QStringLiteral("lpstr"));
foreach (QString title, m_titlesOfPartsList)
writer.writeTextElement(vt, QStringLiteral("lpstr"), title);
writer.writeEndElement();//vt:vector
writer.writeEndElement();//TitlesOfParts
if (m_properties.contains(QStringLiteral("manager")))
writer.writeTextElement(QStringLiteral("Manager"), m_properties[QStringLiteral("manager")]);
//Not like "manager", "company" always exists for Excel generated file.
writer.writeTextElement(QStringLiteral("Company"), m_properties.contains(QStringLiteral("company")) ? m_properties[QStringLiteral("company")]: QString());
writer.writeTextElement(QStringLiteral("LinksUpToDate"), QStringLiteral("false"));
writer.writeTextElement(QStringLiteral("SharedDoc"), QStringLiteral("false"));
writer.writeTextElement(QStringLiteral("HyperlinksChanged"), QStringLiteral("false"));
writer.writeTextElement(QStringLiteral("AppVersion"), QStringLiteral("12.0000"));
writer.writeEndElement(); //Properties
writer.writeEndDocument();
}
bool DocPropsApp::loadFromXmlFile(QIODevice *device)
{
QXmlStreamReader reader(device);
while (!reader.atEnd()) {
QXmlStreamReader::TokenType token = reader.readNext();
if (token == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("Properties"))
continue;
if (reader.name() == QStringLiteral("Manager")) {
setProperty(QStringLiteral("manager"), reader.readElementText());
} else if (reader.name() == QStringLiteral("Company")) {
setProperty(QStringLiteral("company"), reader.readElementText());
}
}
if (reader.hasError()) {
qDebug("Error when read doc props app file.");
}
}
return true;
}
} //namespace

View File

@ -0,0 +1,168 @@
/****************************************************************************
** 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 "xlsxdocpropscore_p.h"
#include <QXmlStreamWriter>
#include <QXmlStreamReader>
#include <QDir>
#include <QFile>
#include <QDateTime>
#include <QDebug>
#include <QBuffer>
namespace QXlsx {
DocPropsCore::DocPropsCore(CreateFlag flag)
:AbstractOOXmlFile(flag)
{
}
bool DocPropsCore::setProperty(const QString &name, const QString &value)
{
static QStringList validKeys;
if (validKeys.isEmpty()) {
validKeys << QStringLiteral("title") << QStringLiteral("subject")
<< QStringLiteral("keywords") << QStringLiteral("description")
<< QStringLiteral("category") << QStringLiteral("status")
<< QStringLiteral("created") << QStringLiteral("creator");
}
if (!validKeys.contains(name))
return false;
if (value.isEmpty())
m_properties.remove(name);
else
m_properties[name] = value;
return true;
}
QString DocPropsCore::property(const QString &name) const
{
if (m_properties.contains(name))
return m_properties[name];
return QString();
}
QStringList DocPropsCore::propertyNames() const
{
return m_properties.keys();
}
void DocPropsCore::saveToXmlFile(QIODevice *device) const
{
QXmlStreamWriter writer(device);
const QString cp = QStringLiteral("http://schemas.openxmlformats.org/package/2006/metadata/core-properties");
const QString dc = QStringLiteral("http://purl.org/dc/elements/1.1/");
const QString dcterms = QStringLiteral("http://purl.org/dc/terms/");
const QString dcmitype = QStringLiteral("http://purl.org/dc/dcmitype/");
const QString xsi = QStringLiteral("http://www.w3.org/2001/XMLSchema-instance");
writer.writeStartDocument(QStringLiteral("1.0"), true);
writer.writeStartElement(QStringLiteral("cp:coreProperties"));
writer.writeNamespace(cp, QStringLiteral("cp"));
writer.writeNamespace(dc, QStringLiteral("dc"));
writer.writeNamespace(dcterms, QStringLiteral("dcterms"));
writer.writeNamespace(dcmitype, QStringLiteral("dcmitype"));
writer.writeNamespace(xsi, QStringLiteral("xsi"));
if (m_properties.contains(QStringLiteral("title")))
writer.writeTextElement(dc, QStringLiteral("title"), m_properties[QStringLiteral("title")]);
if (m_properties.contains(QStringLiteral("subject")))
writer.writeTextElement(dc, QStringLiteral("subject"), m_properties[QStringLiteral("subject")]);
writer.writeTextElement(dc, QStringLiteral("creator"), m_properties.contains(QStringLiteral("creator")) ? m_properties[QStringLiteral("creator")] : QStringLiteral("Qt Xlsx Library"));
if (m_properties.contains(QStringLiteral("keywords")))
writer.writeTextElement(cp, QStringLiteral("keywords"), m_properties[QStringLiteral("keywords")]);
if (m_properties.contains(QStringLiteral("description")))
writer.writeTextElement(dc, QStringLiteral("description"), m_properties[QStringLiteral("description")]);
writer.writeTextElement(cp, QStringLiteral("lastModifiedBy"), m_properties.contains(QStringLiteral("creator")) ? m_properties[QStringLiteral("creator")] : QStringLiteral("Qt Xlsx Library"));
writer.writeStartElement(dcterms, QStringLiteral("created"));
writer.writeAttribute(xsi, QStringLiteral("type"), QStringLiteral("dcterms:W3CDTF"));
writer.writeCharacters(m_properties.contains(QStringLiteral("created")) ? m_properties[QStringLiteral("created")] : QDateTime::currentDateTime().toString(Qt::ISODate));
writer.writeEndElement();//dcterms:created
writer.writeStartElement(dcterms, QStringLiteral("modified"));
writer.writeAttribute(xsi, QStringLiteral("type"), QStringLiteral("dcterms:W3CDTF"));
writer.writeCharacters(QDateTime::currentDateTime().toString(Qt::ISODate));
writer.writeEndElement();//dcterms:created
if (m_properties.contains(QStringLiteral("category")))
writer.writeTextElement(cp, QStringLiteral("category"), m_properties[QStringLiteral("category")]);
if (m_properties.contains(QStringLiteral("status")))
writer.writeTextElement(cp, QStringLiteral("contentStatus"), m_properties[QStringLiteral("status")]);
writer.writeEndElement(); //cp:coreProperties
writer.writeEndDocument();
}
bool DocPropsCore::loadFromXmlFile(QIODevice *device)
{
QXmlStreamReader reader(device);
const QString cp = QStringLiteral("http://schemas.openxmlformats.org/package/2006/metadata/core-properties");
const QString dc = QStringLiteral("http://purl.org/dc/elements/1.1/");
const QString dcterms = QStringLiteral("http://purl.org/dc/terms/");
while (!reader.atEnd()) {
QXmlStreamReader::TokenType token = reader.readNext();
if (token == QXmlStreamReader::StartElement) {
const QStringRef nsUri = reader.namespaceUri();
const QStringRef name = reader.name();
if (name == QStringLiteral("subject") && nsUri == dc) {
setProperty(QStringLiteral("subject"), reader.readElementText());
} else if (name == QStringLiteral("title") && nsUri == dc) {
setProperty(QStringLiteral("title"), reader.readElementText());
} else if (name == QStringLiteral("creator") && nsUri == dc) {
setProperty(QStringLiteral("creator"), reader.readElementText());
} else if (name == QStringLiteral("description") && nsUri == dc) {
setProperty(QStringLiteral("description"), reader.readElementText());
} else if (name == QStringLiteral("keywords") && nsUri == cp) {
setProperty(QStringLiteral("keywords"), reader.readElementText());
} else if (name == QStringLiteral("created") && nsUri == dcterms) {
setProperty(QStringLiteral("created"), reader.readElementText());
} else if (name == QStringLiteral("category") && nsUri == cp) {
setProperty(QStringLiteral("category"), reader.readElementText());
} else if (name == QStringLiteral("contentStatus") && nsUri == cp) {
setProperty(QStringLiteral("status"), reader.readElementText());
}
}
if (reader.hasError()) {
qDebug()<<"Error when read doc props core file."<<reader.errorString();
}
}
return true;
}
} //namespace

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,87 @@
/****************************************************************************
** 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 "xlsxdrawing_p.h"
#include "xlsxdrawinganchor_p.h"
#include "xlsxabstractsheet.h"
#include <QXmlStreamWriter>
#include <QXmlStreamReader>
#include <QBuffer>
namespace QXlsx {
Drawing::Drawing(AbstractSheet *sheet, CreateFlag flag)
:AbstractOOXmlFile(flag), sheet(sheet)
{
workbook = sheet->workbook();
}
Drawing::~Drawing()
{
qDeleteAll(anchors);
}
void Drawing::saveToXmlFile(QIODevice *device) const
{
relationships()->clear();
QXmlStreamWriter writer(device);
writer.writeStartDocument(QStringLiteral("1.0"), true);
writer.writeStartElement(QStringLiteral("xdr:wsDr"));
writer.writeAttribute(QStringLiteral("xmlns:xdr"), QStringLiteral("http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"));
writer.writeAttribute(QStringLiteral("xmlns:a"), QStringLiteral("http://schemas.openxmlformats.org/drawingml/2006/main"));
foreach (DrawingAnchor *anchor, anchors)
anchor->saveToXml(writer);
writer.writeEndElement();//xdr:wsDr
writer.writeEndDocument();
}
bool Drawing::loadFromXmlFile(QIODevice *device)
{
QXmlStreamReader reader(device);
while (!reader.atEnd()) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("absoluteAnchor")) {
DrawingAbsoluteAnchor * anchor = new DrawingAbsoluteAnchor(this);
anchor->loadFromXml(reader);
} else if (reader.name() == QLatin1String("oneCellAnchor")) {
DrawingOneCellAnchor * anchor = new DrawingOneCellAnchor(this);
anchor->loadFromXml(reader);
} else if (reader.name() == QLatin1String("twoCellAnchor")) {
DrawingTwoCellAnchor * anchor = new DrawingTwoCellAnchor(this);
anchor->loadFromXml(reader);
}
}
}
return true;
}
} // namespace QXlsx

View File

@ -0,0 +1,529 @@
/****************************************************************************
** 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 "xlsxdrawinganchor_p.h"
#include "xlsxdrawing_p.h"
#include "xlsxmediafile_p.h"
#include "xlsxchart.h"
#include "xlsxworkbook.h"
#include "xlsxutility_p.h"
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
#include <QBuffer>
#include <QDir>
namespace QXlsx {
/*
The vertices that define the position of a graphical object
within the worksheet in pixels.
+------------+------------+
| A | B |
+-----+------------+------------+
| |(x1,y1) | |
| 1 |(A1)._______|______ |
| | | | |
| | | | |
+-----+----| OBJECT |-----+
| | | | |
| 2 | |______________. |
| | | (B2)|
| | | (x2,y2)|
+---- +------------+------------+
Example of an object that covers some of the area from cell A1 to B2.
Based on the width and height of the object we need to calculate 8 vars:
col_start, row_start, col_end, row_end, x1, y1, x2, y2.
We also calculate the absolute x and y position of the top left vertex of
the object. This is required for images.
The width and height of the cells that the object occupies can be
variable and have to be taken into account.
*/
//anchor
DrawingAnchor::DrawingAnchor(Drawing *drawing, ObjectType objectType)
:m_drawing(drawing), m_objectType(objectType)
{
m_drawing->anchors.append(this);
m_id = m_drawing->anchors.size();//must be unique in one drawing{x}.xml file.
}
DrawingAnchor::~DrawingAnchor()
{
}
void DrawingAnchor::setObjectPicture(const QImage &img)
{
QByteArray ba;
QBuffer buffer(&ba);
buffer.open(QIODevice::WriteOnly);
img.save(&buffer, "PNG");
m_pictureFile = QSharedPointer<MediaFile>(new MediaFile(ba, QStringLiteral("png"), QStringLiteral("image/png")));
m_drawing->workbook->addMediaFile(m_pictureFile);
m_objectType = Picture;
}
void DrawingAnchor::setObjectGraphicFrame(QSharedPointer<Chart> chart)
{
m_chartFile = chart;
m_drawing->workbook->addChartFile(chart);
m_objectType = GraphicFrame;
}
QPoint DrawingAnchor::loadXmlPos(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("pos"));
QPoint pos;
QXmlStreamAttributes attrs = reader.attributes();
pos.setX(attrs.value(QLatin1String("x")).toString().toInt());
pos.setY(attrs.value(QLatin1String("y")).toString().toInt());
return pos;
}
QSize DrawingAnchor::loadXmlExt(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("ext"));
QSize size;
QXmlStreamAttributes attrs = reader.attributes();
size.setWidth(attrs.value(QLatin1String("cx")).toString().toInt());
size.setHeight(attrs.value(QLatin1String("cy")).toString().toInt());
return size;
}
XlsxMarker DrawingAnchor::loadXmlMarker(QXmlStreamReader &reader, const QString &node)
{
Q_ASSERT(reader.name() == node);
int col = 0;
int colOffset = 0;
int row = 0;
int rowOffset = 0;
while (!reader.atEnd()) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("col")) {
col = reader.readElementText().toInt();
} else if (reader.name() == QLatin1String("colOff")) {
colOffset = reader.readElementText().toInt();
} else if (reader.name() == QLatin1String("row")) {
row = reader.readElementText().toInt();
} else if (reader.name() == QLatin1String("rowOff")) {
rowOffset = reader.readElementText().toInt();
}
} else if (reader.tokenType() == QXmlStreamReader::EndElement
&& reader.name() == node) {
break;
}
}
return XlsxMarker(row, col, rowOffset, colOffset);
}
void DrawingAnchor::loadXmlObject(QXmlStreamReader &reader)
{
if (reader.name() == QLatin1String("sp")) {
//Shape
m_objectType = Shape;
loadXmlObjectShape(reader);
} else if (reader.name() == QLatin1String("grpSp")) {
//Group Shape
m_objectType = GroupShape;
loadXmlObjectGroupShape(reader);
} else if (reader.name() == QLatin1String("graphicFrame")) {
//Graphic Frame
m_objectType = GraphicFrame;
loadXmlObjectGraphicFrame(reader);
} else if (reader.name() == QLatin1String("cxnSp")) {
//Connection Shape
m_objectType = ConnectionShape;
loadXmlObjectConnectionShape(reader);
} else if (reader.name() == QLatin1String("pic")) {
//Picture
m_objectType = Picture;
loadXmlObjectPicture(reader);
}
}
void DrawingAnchor::loadXmlObjectConnectionShape(QXmlStreamReader &reader)
{
Q_UNUSED(reader)
}
void DrawingAnchor::loadXmlObjectGraphicFrame(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("graphicFrame"));
while (!reader.atEnd()) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("chart")) {
QString rId = reader.attributes().value(QLatin1String("r:id")).toString();
QString name = m_drawing->relationships()->getRelationshipById(rId).target;
QString path = QDir::cleanPath(splitPath(m_drawing->filePath())[0] + QLatin1String("/") + name);
bool exist = false;
QList<QSharedPointer<Chart> > cfs = m_drawing->workbook->chartFiles();
for (int i=0; i<cfs.size(); ++i) {
if (cfs[i]->filePath() == path) {
//already exist
exist = true;
m_chartFile = cfs[i];
}
}
if (!exist) {
m_chartFile = QSharedPointer<Chart> (new Chart(m_drawing->sheet, Chart::F_LoadFromExists));
m_chartFile->setFilePath(path);
m_drawing->workbook->addChartFile(m_chartFile);
}
}
} else if (reader.tokenType() == QXmlStreamReader::EndElement
&& reader.name() == QLatin1String("graphicFrame")) {
break;
}
}
return;
}
void DrawingAnchor::loadXmlObjectGroupShape(QXmlStreamReader &reader)
{
Q_UNUSED(reader)
}
void DrawingAnchor::loadXmlObjectPicture(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("pic"));
while (!reader.atEnd()) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("blip")) {
QString rId = reader.attributes().value(QLatin1String("r:embed")).toString();
QString name = m_drawing->relationships()->getRelationshipById(rId).target;
QString path = QDir::cleanPath(splitPath(m_drawing->filePath())[0] + QLatin1String("/") + name);
bool exist = false;
QList<QSharedPointer<MediaFile> > mfs = m_drawing->workbook->mediaFiles();
for (int i=0; i<mfs.size(); ++i) {
if (mfs[i]->fileName() == path) {
//already exist
exist = true;
m_pictureFile = mfs[i];
}
}
if (!exist) {
m_pictureFile = QSharedPointer<MediaFile> (new MediaFile(path));
m_drawing->workbook->addMediaFile(m_pictureFile, true);
}
}
} else if (reader.tokenType() == QXmlStreamReader::EndElement
&& reader.name() == QLatin1String("pic")) {
break;
}
}
return;
}
void DrawingAnchor::loadXmlObjectShape(QXmlStreamReader &reader)
{
Q_UNUSED(reader)
}
void DrawingAnchor::saveXmlPos(QXmlStreamWriter &writer, const QPoint &pos) const
{
writer.writeEmptyElement(QStringLiteral("xdr:pos"));
writer.writeAttribute(QStringLiteral("x"), QString::number(pos.x()));
writer.writeAttribute(QStringLiteral("y"), QString::number(pos.y()));
}
void DrawingAnchor::saveXmlExt(QXmlStreamWriter &writer, const QSize &ext) const
{
writer.writeStartElement(QStringLiteral("xdr:ext"));
writer.writeAttribute(QStringLiteral("cx"), QString::number(ext.width()));
writer.writeAttribute(QStringLiteral("cy"), QString::number(ext.height()));
writer.writeEndElement(); //xdr:ext
}
void DrawingAnchor::saveXmlMarker(QXmlStreamWriter &writer, const XlsxMarker &marker, const QString &node) const
{
writer.writeStartElement(node); //xdr:from or xdr:to
writer.writeTextElement(QStringLiteral("xdr:col"), QString::number(marker.col()));
writer.writeTextElement(QStringLiteral("xdr:colOff"), QString::number(marker.colOff()));
writer.writeTextElement(QStringLiteral("xdr:row"), QString::number(marker.row()));
writer.writeTextElement(QStringLiteral("xdr:rowOff"), QString::number(marker.rowOff()));
writer.writeEndElement();
}
void DrawingAnchor::saveXmlObject(QXmlStreamWriter &writer) const
{
if (m_objectType == Picture)
saveXmlObjectPicture(writer);
else if (m_objectType == ConnectionShape)
saveXmlObjectConnectionShape(writer);
else if (m_objectType == GraphicFrame)
saveXmlObjectGraphicFrame(writer);
else if (m_objectType == GroupShape)
saveXmlObjectGroupShape(writer);
else if (m_objectType == Shape)
saveXmlObjectShape(writer);
}
void DrawingAnchor::saveXmlObjectConnectionShape(QXmlStreamWriter &writer) const
{
Q_UNUSED(writer)
}
void DrawingAnchor::saveXmlObjectGraphicFrame(QXmlStreamWriter &writer) const
{
writer.writeStartElement(QStringLiteral("xdr:graphicFrame"));
writer.writeAttribute(QStringLiteral("macro"), QString());
writer.writeStartElement(QStringLiteral("xdr:nvGraphicFramePr"));
writer.writeEmptyElement(QStringLiteral("xdr:cNvPr"));
writer.writeAttribute(QStringLiteral("id"), QString::number(m_id));
writer.writeAttribute(QStringLiteral("name"),QStringLiteral("Chart %1").arg(m_id));
writer.writeEmptyElement(QStringLiteral("xdr:cNvGraphicFramePr"));
writer.writeEndElement();//xdr:nvGraphicFramePr
writer.writeStartElement(QStringLiteral("xdr:xfrm"));
writer.writeEndElement(); //xdr:xfrm
writer.writeStartElement(QStringLiteral("a:graphic"));
writer.writeStartElement(QStringLiteral("a:graphicData"));
writer.writeAttribute(QStringLiteral("uri"), QStringLiteral("http://schemas.openxmlformats.org/drawingml/2006/chart"));
int idx = m_drawing->workbook->chartFiles().indexOf(m_chartFile);
m_drawing->relationships()->addDocumentRelationship(QStringLiteral("/chart"), QStringLiteral("../charts/chart%1.xml").arg(idx+1));
writer.writeEmptyElement(QStringLiteral("c:chart"));
writer.writeAttribute(QStringLiteral("xmlns:c"), QStringLiteral("http://schemas.openxmlformats.org/drawingml/2006/chart"));
writer.writeAttribute(QStringLiteral("xmlns:r"), QStringLiteral("http://schemas.openxmlformats.org/officeDocument/2006/relationships"));
writer.writeAttribute(QStringLiteral("r:id"), QStringLiteral("rId%1").arg(m_drawing->relationships()->count()));
writer.writeEndElement(); //a:graphicData
writer.writeEndElement(); //a:graphic
writer.writeEndElement(); //xdr:graphicFrame
}
void DrawingAnchor::saveXmlObjectGroupShape(QXmlStreamWriter &writer) const
{
Q_UNUSED(writer)
}
void DrawingAnchor::saveXmlObjectPicture(QXmlStreamWriter &writer) const
{
Q_ASSERT(m_objectType == Picture && !m_pictureFile.isNull());
writer.writeStartElement(QStringLiteral("xdr:pic"));
writer.writeStartElement(QStringLiteral("xdr:nvPicPr"));
writer.writeEmptyElement(QStringLiteral("xdr:cNvPr"));
writer.writeAttribute(QStringLiteral("id"), QString::number(m_id));
writer.writeAttribute(QStringLiteral("name"), QStringLiteral("Picture %1").arg(m_id));
writer.writeStartElement(QStringLiteral("xdr:cNvPicPr"));
writer.writeEmptyElement(QStringLiteral("a:picLocks"));
writer.writeAttribute(QStringLiteral("noChangeAspect"), QStringLiteral("1"));
writer.writeEndElement(); //xdr:cNvPicPr
writer.writeEndElement(); //xdr:nvPicPr
m_drawing->relationships()->addDocumentRelationship(QStringLiteral("/image"), QStringLiteral("../media/image%1.%2")
.arg(m_pictureFile->index()+1)
.arg(m_pictureFile->suffix()));
writer.writeStartElement(QStringLiteral("xdr:blipFill"));
writer.writeEmptyElement(QStringLiteral("a:blip"));
writer.writeAttribute(QStringLiteral("xmlns:r"), QStringLiteral("http://schemas.openxmlformats.org/officeDocument/2006/relationships"));
writer.writeAttribute(QStringLiteral("r:embed"), QStringLiteral("rId%1").arg(m_drawing->relationships()->count()));
writer.writeStartElement(QStringLiteral("a:stretch"));
writer.writeEmptyElement(QStringLiteral("a:fillRect"));
writer.writeEndElement(); //a:stretch
writer.writeEndElement();//xdr:blipFill
writer.writeStartElement(QStringLiteral("xdr:spPr"));
writer.writeStartElement(QStringLiteral("a:prstGeom"));
writer.writeAttribute(QStringLiteral("prst"), QStringLiteral("rect"));
writer.writeEmptyElement(QStringLiteral("a:avLst"));
writer.writeEndElement(); //a:prstGeom
writer.writeEndElement(); //xdr:spPr
writer.writeEndElement(); //xdr:pic
}
void DrawingAnchor::saveXmlObjectShape(QXmlStreamWriter &writer) const
{
Q_UNUSED(writer)
}
//absolute anchor
DrawingAbsoluteAnchor::DrawingAbsoluteAnchor(Drawing *drawing, ObjectType objectType)
:DrawingAnchor(drawing, objectType)
{
}
bool DrawingAbsoluteAnchor::loadFromXml(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("absoluteAnchor"));
while (!reader.atEnd()) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("pos")) {
pos = loadXmlPos(reader);
} else if (reader.name() == QLatin1String("ext")) {
ext = loadXmlExt(reader);
} else {
loadXmlObject(reader);
}
} else if (reader.tokenType() == QXmlStreamReader::EndElement
&& reader.name() == QLatin1String("absoluteAnchor")) {
break;
}
}
return true;
}
void DrawingAbsoluteAnchor::saveToXml(QXmlStreamWriter &writer) const
{
writer.writeStartElement(QStringLiteral("xdr:absoluteAnchor"));
saveXmlPos(writer, pos);
saveXmlExt(writer, ext);
saveXmlObject(writer);
writer.writeEmptyElement(QStringLiteral("xdr:clientData"));
writer.writeEndElement(); //xdr:absoluteAnchor
}
//one cell anchor
DrawingOneCellAnchor::DrawingOneCellAnchor(Drawing *drawing, ObjectType objectType)
:DrawingAnchor(drawing, objectType)
{
}
bool DrawingOneCellAnchor::loadFromXml(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("oneCellAnchor"));
while (!reader.atEnd()) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("from")) {
from = loadXmlMarker(reader, QLatin1String("from"));
} else if (reader.name() == QLatin1String("ext")) {
ext = loadXmlExt(reader);
} else {
loadXmlObject(reader);
}
} else if (reader.tokenType() == QXmlStreamReader::EndElement
&& reader.name() == QLatin1String("oneCellAnchor")) {
break;
}
}
return true;
}
void DrawingOneCellAnchor::saveToXml(QXmlStreamWriter &writer) const
{
writer.writeStartElement(QStringLiteral("xdr:oneCellAnchor"));
saveXmlMarker(writer, from, QStringLiteral("xdr:from"));
saveXmlExt(writer, ext);
saveXmlObject(writer);
writer.writeEmptyElement(QStringLiteral("xdr:clientData"));
writer.writeEndElement(); //xdr:oneCellAnchor
}
/*
Two cell anchor
This class specifies a two cell anchor placeholder for a group
, a shape, or a drawing element. It moves with
cells and its extents are in EMU units.
*/
DrawingTwoCellAnchor::DrawingTwoCellAnchor(Drawing *drawing, ObjectType objectType)
:DrawingAnchor(drawing, objectType)
{
}
bool DrawingTwoCellAnchor::loadFromXml(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("twoCellAnchor"));
while (!reader.atEnd()) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("from")) {
from = loadXmlMarker(reader, QLatin1String("from"));
} else if (reader.name() == QLatin1String("to")) {
to = loadXmlMarker(reader, QLatin1String("to"));
} else {
loadXmlObject(reader);
}
} else if (reader.tokenType() == QXmlStreamReader::EndElement
&& reader.name() == QLatin1String("twoCellAnchor")) {
break;
}
}
return true;
}
void DrawingTwoCellAnchor::saveToXml(QXmlStreamWriter &writer) const
{
writer.writeStartElement(QStringLiteral("xdr:twoCellAnchor"));
writer.writeAttribute(QStringLiteral("editAs"), QStringLiteral("oneCell"));
saveXmlMarker(writer, from, QStringLiteral("xdr:from"));
saveXmlMarker(writer, to, QStringLiteral("xdr:to"));
saveXmlObject(writer);
writer.writeEmptyElement(QStringLiteral("xdr:clientData"));
writer.writeEndElement(); //xdr:twoCellAnchor
}
} // namespace QXlsx

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,99 @@
/****************************************************************************
** 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 "xlsxmediafile_p.h"
#include <QCryptographicHash>
namespace QXlsx {
MediaFile::MediaFile(const QByteArray &bytes, const QString &suffix, const QString &mimeType)
: m_contents(bytes), m_suffix(suffix), m_mimeType(mimeType)
, m_index(0), m_indexValid(false)
{
m_hashKey = QCryptographicHash::hash(m_contents, QCryptographicHash::Md5);
}
MediaFile::MediaFile(const QString &fileName)
:m_fileName(fileName), m_index(0), m_indexValid(false)
{
}
void MediaFile::set(const QByteArray &bytes, const QString &suffix, const QString &mimeType)
{
m_contents = bytes;
m_suffix = suffix;
m_mimeType = mimeType;
m_hashKey = QCryptographicHash::hash(m_contents, QCryptographicHash::Md5);
m_indexValid = false;
}
void MediaFile::setFileName(const QString &name)
{
m_fileName = name;
}
QString MediaFile::fileName() const
{
return m_fileName;
}
QString MediaFile::suffix() const
{
return m_suffix;
}
QString MediaFile::mimeType() const
{
return m_mimeType;
}
QByteArray MediaFile::contents() const
{
return m_contents;
}
int MediaFile::index() const
{
return m_index;
}
bool MediaFile::isIndexValid() const
{
return m_indexValid;
}
void MediaFile::setIndex(int idx)
{
m_index = idx;
m_indexValid = true;
}
QByteArray MediaFile::hashKey() const
{
return m_hashKey;
}
} // namespace QXlsx

View File

@ -0,0 +1,94 @@
/****************************************************************************
** 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 "xlsxnumformatparser_p.h"
#include <QString>
namespace QXlsx {
bool NumFormatParser::isDateTime(const QString &formatCode)
{
for (int i = 0; i < formatCode.length(); ++i) {
const QChar &c = formatCode[i];
switch (c.unicode()) {
case '[':
// [h], [m], [s] are valid format for time
if (i < formatCode.length()-2 && formatCode[i+2] == QLatin1Char(']')) {
const QChar cc = formatCode[i+1].toLower();
if (cc == QLatin1Char('h') || cc == QLatin1Char('m') || cc == QLatin1Char('s'))
return true;
i+=2;
break;
} else {
// condition or color: don't care, ignore
while (i < formatCode.length() && formatCode[i] != QLatin1Char(']'))
++i;
break;
}
// quoted plain text block: don't care, ignore
case '"':
while (i < formatCode.length()-1 && formatCode[++i] != QLatin1Char('"'))
;
break;
// escaped char: don't care, ignore
case '\\':
if (i < formatCode.length() - 1)
++i;
break;
// date/time can only be positive number,
// so only the first section of the format make sense.
case ';':
return false;
break;
// days
case 'D':
case 'd':
// years
case 'Y':
case 'y':
// hours
case 'H':
case 'h':
// seconds
case 'S':
case 's':
// minutes or months, depending on context
case 'M':
case 'm':
return true;
default:
break;
}
}
return false;
}
} // namespace QXlsx

View File

@ -0,0 +1,189 @@
/****************************************************************************
** 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 "xlsxrelationships_p.h"
#include <QXmlStreamWriter>
#include <QXmlStreamReader>
#include <QDir>
#include <QFile>
#include <QBuffer>
namespace QXlsx {
const QString schema_doc = QStringLiteral("http://schemas.openxmlformats.org/officeDocument/2006/relationships");
const QString schema_msPackage = QStringLiteral("http://schemas.microsoft.com/office/2006/relationships");
const QString schema_package = QStringLiteral("http://schemas.openxmlformats.org/package/2006/relationships");
//const QString schema_worksheet = QStringLiteral("http://schemas.openxmlformats.org/officeDocument/2006/relationships");
Relationships::Relationships()
{
}
QList<XlsxRelationship> Relationships::documentRelationships(const QString &relativeType) const
{
return relationships(schema_doc + relativeType);
}
void Relationships::addDocumentRelationship(const QString &relativeType, const QString &target)
{
addRelationship(schema_doc + relativeType, target);
}
QList<XlsxRelationship> Relationships::msPackageRelationships(const QString &relativeType) const
{
return relationships(schema_msPackage + relativeType);
}
void Relationships::addMsPackageRelationship(const QString &relativeType, const QString &target)
{
addRelationship(schema_msPackage + relativeType, target);
}
QList<XlsxRelationship> Relationships::packageRelationships(const QString &relativeType) const
{
return relationships(schema_package + relativeType);
}
void Relationships::addPackageRelationship(const QString &relativeType, const QString &target)
{
addRelationship(schema_package + relativeType, target);
}
QList<XlsxRelationship> Relationships::worksheetRelationships(const QString &relativeType) const
{
return relationships(schema_doc + relativeType);
}
void Relationships::addWorksheetRelationship(const QString &relativeType, const QString &target, const QString &targetMode)
{
addRelationship(schema_doc + relativeType, target, targetMode);
}
QList<XlsxRelationship> Relationships::relationships(const QString &type) const
{
QList<XlsxRelationship> res;
foreach (XlsxRelationship ship, m_relationships) {
if (ship.type == type)
res.append(ship);
}
return res;
}
void Relationships::addRelationship(const QString &type, const QString &target, const QString &targetMode)
{
XlsxRelationship relation;
relation.id = QStringLiteral("rId%1").arg(m_relationships.size()+1);
relation.type = type;
relation.target = target;
relation.targetMode = targetMode;
m_relationships.append(relation);
}
void Relationships::saveToXmlFile(QIODevice *device) const
{
QXmlStreamWriter writer(device);
writer.writeStartDocument(QStringLiteral("1.0"), true);
writer.writeStartElement(QStringLiteral("Relationships"));
writer.writeAttribute(QStringLiteral("xmlns"), QStringLiteral("http://schemas.openxmlformats.org/package/2006/relationships"));
foreach (XlsxRelationship relation, m_relationships) {
writer.writeStartElement(QStringLiteral("Relationship"));
writer.writeAttribute(QStringLiteral("Id"), relation.id);
writer.writeAttribute(QStringLiteral("Type"), relation.type);
writer.writeAttribute(QStringLiteral("Target"), relation.target);
if (!relation.targetMode.isNull())
writer.writeAttribute(QStringLiteral("TargetMode"), relation.targetMode);
writer.writeEndElement();
}
writer.writeEndElement();//Relationships
writer.writeEndDocument();
}
QByteArray Relationships::saveToXmlData() const
{
QByteArray data;
QBuffer buffer(&data);
buffer.open(QIODevice::WriteOnly);
saveToXmlFile(&buffer);
return data;
}
bool Relationships::loadFromXmlFile(QIODevice *device)
{
clear();
QXmlStreamReader reader(device);
while (!reader.atEnd()) {
QXmlStreamReader::TokenType token = reader.readNext();
if (token == QXmlStreamReader::StartElement) {
if (reader.name() == QStringLiteral("Relationship")) {
QXmlStreamAttributes attributes = reader.attributes();
XlsxRelationship relationship;
relationship.id = attributes.value(QLatin1String("Id")).toString();
relationship.type = attributes.value(QLatin1String("Type")).toString();
relationship.target = attributes.value(QLatin1String("Target")).toString();
relationship.targetMode = attributes.value(QLatin1String("TargetMode")).toString();
m_relationships.append(relationship);
}
}
if (reader.hasError())
return false;
}
return true;
}
bool Relationships::loadFromXmlData(const QByteArray &data)
{
QBuffer buffer;
buffer.setData(data);
buffer.open(QIODevice::ReadOnly);
return loadFromXmlFile(&buffer);
}
XlsxRelationship Relationships::getRelationshipById(const QString &id) const
{
foreach (XlsxRelationship ship, m_relationships) {
if (ship.id == id)
return ship;
}
return XlsxRelationship();
}
void Relationships::clear()
{
m_relationships.clear();
}
int Relationships::count() const
{
return m_relationships.count();
}
bool Relationships::isEmpty() const
{
return m_relationships.isEmpty();
}
} //namespace

View File

@ -0,0 +1,343 @@
/****************************************************************************
** 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 "xlsxrichstring.h"
#include "xlsxrichstring_p.h"
#include "xlsxformat_p.h"
#include <QDebug>
#include <QTextDocument>
#include <QTextFragment>
QT_BEGIN_NAMESPACE_XLSX
RichStringPrivate::RichStringPrivate()
:_dirty(true)
{
}
RichStringPrivate::RichStringPrivate(const RichStringPrivate &other)
:QSharedData(other), fragmentTexts(other.fragmentTexts)
,fragmentFormats(other.fragmentFormats)
, _idKey(other.idKey()), _dirty(other._dirty)
{
}
RichStringPrivate::~RichStringPrivate()
{
}
/*!
\class RichString
\inmodule QtXlsx
\brief This class add support for the rich text string of the cell.
*/
/*!
Constructs a null string.
*/
RichString::RichString()
:d(new RichStringPrivate)
{
}
/*!
Constructs a plain string with the given \a text.
*/
RichString::RichString(const QString text)
:d(new RichStringPrivate)
{
addFragment(text, Format());
}
/*!
Constructs a copy of \a other.
*/
RichString::RichString(const RichString &other)
:d(other.d)
{
}
/*!
Destructs the string.
*/
RichString::~RichString()
{
}
/*!
Assigns \a other to this string and returns a reference to this string
*/
RichString &RichString::operator =(const RichString &other)
{
this->d = other.d;
return *this;
}
/*!
Returns the rich string as a QVariant
*/
RichString::operator QVariant() const
{
return QVariant(qMetaTypeId<RichString>(), this);
}
/*!
Returns true if this is rich text string.
*/
bool RichString::isRichString() const
{
if (fragmentCount() > 1) //Is this enough??
return true;
return false;
}
/*!
Returns true is this is an Null string.
*/
bool RichString::isNull() const
{
return d->fragmentTexts.size() == 0;
}
/*!
Returns true is this is an empty string.
*/
bool RichString::isEmtpy() const
{
foreach (const QString str, d->fragmentTexts) {
if (!str.isEmpty())
return false;
}
return true;
}
/*!
Converts to plain text string.
*/
QString RichString::toPlainString() const
{
if (isEmtpy())
return QString();
if (d->fragmentTexts.size() == 1)
return d->fragmentTexts[0];
return d->fragmentTexts.join(QString());
}
/*!
Converts to html string
*/
QString RichString::toHtml() const
{
//: Todo
return QString();
}
/*!
Replaces the entire contents of the document
with the given HTML-formatted text in the \a text string
*/
void RichString::setHtml(const QString &text)
{
QTextDocument doc;
doc.setHtml(text);
QTextBlock block = doc.firstBlock();
QTextBlock::iterator it;
for (it = block.begin(); !(it.atEnd()); ++it) {
QTextFragment textFragment = it.fragment();
if (textFragment.isValid()) {
Format fmt;
fmt.setFont(textFragment.charFormat().font());
fmt.setFontColor(textFragment.charFormat().foreground().color());
addFragment(textFragment.text(), fmt);
}
}
}
/*!
Returns fragment count.
*/
int RichString::fragmentCount() const
{
return d->fragmentTexts.size();
}
/*!
Appends a fragment with the given \a text and \a format.
*/
void RichString::addFragment(const QString &text, const Format &format)
{
d->fragmentTexts.append(text);
d->fragmentFormats.append(format);
d->_dirty = true;
}
/*!
Returns fragment text at the position \a index.
*/
QString RichString::fragmentText(int index) const
{
if (index < 0 || index >= fragmentCount())
return QString();
return d->fragmentTexts[index];
}
/*!
Returns fragment format at the position \a index.
*/
Format RichString::fragmentFormat(int index) const
{
if (index < 0 || index >= fragmentCount())
return Format();
return d->fragmentFormats[index];
}
/*!
* \internal
*/
QByteArray RichStringPrivate::idKey() const
{
if (_dirty) {
RichStringPrivate *rs = const_cast<RichStringPrivate *>(this);
QByteArray bytes;
if (fragmentTexts.size() == 1) {
bytes = fragmentTexts[0].toUtf8();
} else {
//Generate a hash value base on QByteArray ?
bytes.append("@@QtXlsxRichString=");
for (int i=0; i<fragmentTexts.size(); ++i) {
bytes.append("@Text");
bytes.append(fragmentTexts[i].toUtf8());
bytes.append("@Format");
if (fragmentFormats[i].hasFontData())
bytes.append(fragmentFormats[i].fontKey());
}
}
rs->_idKey = bytes;
rs->_dirty = false;
}
return _idKey;
}
/*!
Returns true if this string \a rs1 is equal to string \a rs2;
otherwise returns false.
*/
bool operator==(const RichString &rs1, const RichString &rs2)
{
if (rs1.fragmentCount() != rs2.fragmentCount())
return false;
return rs1.d->idKey() == rs2.d->idKey();
}
/*!
Returns true if this string \a rs1 is not equal to string \a rs2;
otherwise returns false.
*/
bool operator!=(const RichString &rs1, const RichString &rs2)
{
if (rs1.fragmentCount() != rs2.fragmentCount())
return true;
return rs1.d->idKey() != rs2.d->idKey();
}
/*!
* \internal
*/
bool operator<(const RichString &rs1, const RichString &rs2)
{
return rs1.d->idKey() < rs2.d->idKey();
}
/*!
\overload
Returns true if this string \a rs1 is equal to string \a rs2;
otherwise returns false.
*/
bool operator ==(const RichString &rs1, const QString &rs2)
{
if (rs1.fragmentCount() == 1 && rs1.fragmentText(0) == rs2) //format == 0
return true;
return false;
}
/*!
\overload
Returns true if this string \a rs1 is not equal to string \a rs2;
otherwise returns false.
*/
bool operator !=(const RichString &rs1, const QString &rs2)
{
if (rs1.fragmentCount() == 1 && rs1.fragmentText(0) == rs2) //format == 0
return false;
return true;
}
/*!
\overload
Returns true if this string \a rs1 is equal to string \a rs2;
otherwise returns false.
*/
bool operator ==(const QString &rs1, const RichString &rs2)
{
return rs2 == rs1;
}
/*!
\overload
Returns true if this string \a rs1 is not equal to string \a rs2;
otherwise returns false.
*/
bool operator !=(const QString &rs1, const RichString &rs2)
{
return rs2 != rs1;
}
uint qHash(const RichString &rs, uint seed) Q_DECL_NOTHROW
{
return qHash(rs.d->idKey(), seed);
}
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, const RichString &rs)
{
dbg.nospace() << "QXlsx::RichString(" << rs.d->fragmentTexts << ")";
return dbg.space();
}
#endif
QT_END_NAMESPACE_XLSX

View File

@ -0,0 +1,400 @@
/****************************************************************************
** 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 "xlsxrichstring.h"
#include "xlsxsharedstrings_p.h"
#include "xlsxutility_p.h"
#include "xlsxformat_p.h"
#include "xlsxcolor_p.h"
#include <QXmlStreamWriter>
#include <QXmlStreamReader>
#include <QDir>
#include <QFile>
#include <QDebug>
#include <QBuffer>
namespace QXlsx {
/*
* Note that, when we open an existing .xlsx file (broken file?),
* duplicated string items may exist in the shared string table.
*
* In such case, the size of stringList will larger than stringTable.
* Duplicated items can be removed once we loaded all the worksheets.
*/
SharedStrings::SharedStrings(CreateFlag flag)
:AbstractOOXmlFile(flag)
{
m_stringCount = 0;
}
int SharedStrings::count() const
{
return m_stringCount;
}
bool SharedStrings::isEmpty() const
{
return m_stringList.isEmpty();
}
int SharedStrings::addSharedString(const QString &string)
{
return addSharedString(RichString(string));
}
int SharedStrings::addSharedString(const RichString &string)
{
m_stringCount += 1;
if (m_stringTable.contains(string)) {
XlsxSharedStringInfo &item = m_stringTable[string];
item.count += 1;
return item.index;
}
int index = m_stringList.size();
m_stringTable[string] = XlsxSharedStringInfo(index);
m_stringList.append(string);
return index;
}
void SharedStrings::incRefByStringIndex(int idx)
{
if (idx <0 || idx >= m_stringList.size()) {
qDebug("SharedStrings: invlid index");
return;
}
addSharedString(m_stringList[idx]);
}
/*
* Broken, don't use.
*/
void SharedStrings::removeSharedString(const QString &string)
{
removeSharedString(RichString(string));
}
/*
* Broken, don't use.
*/
void SharedStrings::removeSharedString(const RichString &string)
{
if (!m_stringTable.contains(string))
return;
m_stringCount -= 1;
XlsxSharedStringInfo &item = m_stringTable[string];
item.count -= 1;
if (item.count <= 0) {
for (int i=item.index+1; i<m_stringList.size(); ++i)
m_stringTable[m_stringList[i]].index -= 1;
m_stringList.removeAt(item.index);
m_stringTable.remove(string);
}
}
int SharedStrings::getSharedStringIndex(const QString &string) const
{
return getSharedStringIndex(RichString(string));
}
int SharedStrings::getSharedStringIndex(const RichString &string) const
{
if (m_stringTable.contains(string))
return m_stringTable[string].index;
return -1;
}
RichString SharedStrings::getSharedString(int index) const
{
if (index < m_stringList.count() && index >= 0)
return m_stringList[index];
return RichString();
}
QList<RichString> SharedStrings::getSharedStrings() const
{
return m_stringList;
}
void SharedStrings::writeRichStringPart_rPr(QXmlStreamWriter &writer, const Format &format) const
{
if (!format.hasFontData())
return;
if (format.fontBold())
writer.writeEmptyElement(QStringLiteral("b"));
if (format.fontItalic())
writer.writeEmptyElement(QStringLiteral("i"));
if (format.fontStrikeOut())
writer.writeEmptyElement(QStringLiteral("strike"));
if (format.fontOutline())
writer.writeEmptyElement(QStringLiteral("outline"));
if (format.boolProperty(FormatPrivate::P_Font_Shadow))
writer.writeEmptyElement(QStringLiteral("shadow"));
if (format.hasProperty(FormatPrivate::P_Font_Underline)) {
Format::FontUnderline u = format.fontUnderline();
if (u != Format::FontUnderlineNone) {
writer.writeEmptyElement(QStringLiteral("u"));
if (u== Format::FontUnderlineDouble)
writer.writeAttribute(QStringLiteral("val"), QStringLiteral("double"));
else if (u == Format::FontUnderlineSingleAccounting)
writer.writeAttribute(QStringLiteral("val"), QStringLiteral("singleAccounting"));
else if (u == Format::FontUnderlineDoubleAccounting)
writer.writeAttribute(QStringLiteral("val"), QStringLiteral("doubleAccounting"));
}
}
if (format.hasProperty(FormatPrivate::P_Font_Script)) {
Format::FontScript s = format.fontScript();
if (s != Format::FontScriptNormal) {
writer.writeEmptyElement(QStringLiteral("vertAlign"));
if (s == Format::FontScriptSuper)
writer.writeAttribute(QStringLiteral("val"), QStringLiteral("superscript"));
else
writer.writeAttribute(QStringLiteral("val"), QStringLiteral("subscript"));
}
}
if (format.hasProperty(FormatPrivate::P_Font_Size)) {
writer.writeEmptyElement(QStringLiteral("sz"));
writer.writeAttribute(QStringLiteral("val"), QString::number(format.fontSize()));
}
if (format.hasProperty(FormatPrivate::P_Font_Color)) {
XlsxColor color = format.property(FormatPrivate::P_Font_Color).value<XlsxColor>();
color.saveToXml(writer);
}
if (!format.fontName().isEmpty()) {
writer.writeEmptyElement(QStringLiteral("rFont"));
writer.writeAttribute(QStringLiteral("val"), format.fontName());
}
if (format.hasProperty(FormatPrivate::P_Font_Family)) {
writer.writeEmptyElement(QStringLiteral("family"));
writer.writeAttribute(QStringLiteral("val"), QString::number(format.intProperty(FormatPrivate::P_Font_Family)));
}
if (format.hasProperty(FormatPrivate::P_Font_Scheme)) {
writer.writeEmptyElement(QStringLiteral("scheme"));
writer.writeAttribute(QStringLiteral("val"), format.stringProperty(FormatPrivate::P_Font_Scheme));
}
}
void SharedStrings::saveToXmlFile(QIODevice *device) const
{
QXmlStreamWriter writer(device);
if (m_stringList.size() != m_stringTable.size()) {
//Duplicated string items exist in m_stringList
//Clean up can not be done here, as the indices
//have been used when we save the worksheets part.
}
writer.writeStartDocument(QStringLiteral("1.0"), true);
writer.writeStartElement(QStringLiteral("sst"));
writer.writeAttribute(QStringLiteral("xmlns"), QStringLiteral("http://schemas.openxmlformats.org/spreadsheetml/2006/main"));
writer.writeAttribute(QStringLiteral("count"), QString::number(m_stringCount));
writer.writeAttribute(QStringLiteral("uniqueCount"), QString::number(m_stringList.size()));
foreach (RichString string, m_stringList) {
writer.writeStartElement(QStringLiteral("si"));
if (string.isRichString()) {
//Rich text string
for (int i=0; i<string.fragmentCount(); ++i) {
writer.writeStartElement(QStringLiteral("r"));
if (string.fragmentFormat(i).hasFontData()) {
writer.writeStartElement(QStringLiteral("rPr"));
writeRichStringPart_rPr(writer, string.fragmentFormat(i));
writer.writeEndElement();// rPr
}
writer.writeStartElement(QStringLiteral("t"));
if (isSpaceReserveNeeded(string.fragmentText(i)))
writer.writeAttribute(QStringLiteral("xml:space"), QStringLiteral("preserve"));
writer.writeCharacters(string.fragmentText(i));
writer.writeEndElement();// t
writer.writeEndElement(); //r
}
} else {
writer.writeStartElement(QStringLiteral("t"));
QString pString = string.toPlainString();
if (isSpaceReserveNeeded(pString))
writer.writeAttribute(QStringLiteral("xml:space"), QStringLiteral("preserve"));
writer.writeCharacters(pString);
writer.writeEndElement();//t
}
writer.writeEndElement();//si
}
writer.writeEndElement(); //sst
writer.writeEndDocument();
}
void SharedStrings::readString(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("si"));
RichString richString;
while (!reader.atEnd() && !(reader.name() == QLatin1String("si") && reader.tokenType() == QXmlStreamReader::EndElement)) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("r"))
readRichStringPart(reader, richString);
else if (reader.name() == QLatin1String("t"))
readPlainStringPart(reader, richString);
}
}
int idx = m_stringList.size();
m_stringTable[richString] = XlsxSharedStringInfo(idx, 0);
m_stringList.append(richString);
}
void SharedStrings::readRichStringPart(QXmlStreamReader &reader, RichString &richString)
{
Q_ASSERT(reader.name() == QLatin1String("r"));
QString text;
Format format;
while (!reader.atEnd() && !(reader.name() == QLatin1String("r") && reader.tokenType() == QXmlStreamReader::EndElement)) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("rPr")) {
format = readRichStringPart_rPr(reader);
} else if (reader.name() == QLatin1String("t")) {
text = reader.readElementText();
}
}
}
richString.addFragment(text, format);
}
void SharedStrings::readPlainStringPart(QXmlStreamReader &reader, RichString &richString)
{
Q_ASSERT(reader.name() == QLatin1String("t"));
//QXmlStreamAttributes attributes = reader.attributes();
QString text = reader.readElementText();
richString.addFragment(text, Format());
}
Format SharedStrings::readRichStringPart_rPr(QXmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("rPr"));
Format format;
while (!reader.atEnd() && !(reader.name() == QLatin1String("rPr") && reader.tokenType() == QXmlStreamReader::EndElement)) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
QXmlStreamAttributes attributes = reader.attributes();
if (reader.name() == QLatin1String("rFont")) {
format.setFontName(attributes.value(QLatin1String("val")).toString());
} else if (reader.name() == QLatin1String("charset")) {
format.setProperty(FormatPrivate::P_Font_Charset, attributes.value(QLatin1String("val")).toString().toInt());
} else if (reader.name() == QLatin1String("family")) {
format.setProperty(FormatPrivate::P_Font_Family, attributes.value(QLatin1String("val")).toString().toInt());
} else if (reader.name() == QLatin1String("b")) {
format.setFontBold(true);
} else if (reader.name() == QLatin1String("i")) {
format.setFontItalic(true);
} else if (reader.name() == QLatin1String("strike")) {
format.setFontStrikeOut(true);
} else if (reader.name() == QLatin1String("outline")) {
format.setFontOutline(true);
} else if (reader.name() == QLatin1String("shadow")) {
format.setProperty(FormatPrivate::P_Font_Shadow, true);
} else if (reader.name() == QLatin1String("condense")) {
format.setProperty(FormatPrivate::P_Font_Condense, attributes.value(QLatin1String("val")).toString().toInt());
} else if (reader.name() == QLatin1String("extend")) {
format.setProperty(FormatPrivate::P_Font_Extend, attributes.value(QLatin1String("val")).toString().toInt());
} else if (reader.name() == QLatin1String("color")) {
XlsxColor color;
color.loadFromXml(reader);
format.setProperty(FormatPrivate::P_Font_Color, color);
} else if (reader.name() == QLatin1String("sz")) {
format.setFontSize(attributes.value(QLatin1String("val")).toString().toInt());
} else if (reader.name() == QLatin1String("u")) {
QString value = attributes.value(QLatin1String("val")).toString();
if (value == QLatin1String("double"))
format.setFontUnderline(Format::FontUnderlineDouble);
else if (value == QLatin1String("doubleAccounting"))
format.setFontUnderline(Format::FontUnderlineDoubleAccounting);
else if (value == QLatin1String("singleAccounting"))
format.setFontUnderline(Format::FontUnderlineSingleAccounting);
else
format.setFontUnderline(Format::FontUnderlineSingle);
} else if (reader.name() == QLatin1String("vertAlign")) {
QString value = attributes.value(QLatin1String("val")).toString();
if (value == QLatin1String("superscript"))
format.setFontScript(Format::FontScriptSuper);
else if (value == QLatin1String("subscript"))
format.setFontScript(Format::FontScriptSub);
} else if (reader.name() == QLatin1String("scheme")) {
format.setProperty(FormatPrivate::P_Font_Scheme, attributes.value(QLatin1String("val")).toString());
}
}
}
return format;
}
bool SharedStrings::loadFromXmlFile(QIODevice *device)
{
QXmlStreamReader reader(device);
int count = 0;
bool hasUniqueCountAttr=true;
while (!reader.atEnd()) {
QXmlStreamReader::TokenType token = reader.readNext();
if (token == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("sst")) {
QXmlStreamAttributes attributes = reader.attributes();
if ((hasUniqueCountAttr = attributes.hasAttribute(QLatin1String("uniqueCount"))))
count = attributes.value(QLatin1String("uniqueCount")).toString().toInt();
} else if (reader.name() == QLatin1String("si")) {
readString(reader);
}
}
}
if (hasUniqueCountAttr && m_stringList.size() != count) {
qDebug("Error: Shared string count");
return false;
}
if (m_stringList.size() != m_stringTable.size()) {
//qDebug("Warning: Duplicated items exist in shared string table.");
//Nothing we can do here, as indices of the strings will be used when loading sheets.
}
return true;
}
} //namespace

View File

@ -0,0 +1,56 @@
/****************************************************************************
** 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 "xlsxsimpleooxmlfile_p.h"
#include <QIODevice>
namespace QXlsx {
SimpleOOXmlFile::SimpleOOXmlFile(CreateFlag flag)
:AbstractOOXmlFile(flag)
{
}
void SimpleOOXmlFile::saveToXmlFile(QIODevice *device) const
{
device->write(xmlData);
}
QByteArray SimpleOOXmlFile::saveToXmlData() const
{
return xmlData;
}
bool SimpleOOXmlFile::loadFromXmlData(const QByteArray &data)
{
xmlData = data;
return true;
}
bool SimpleOOXmlFile::loadFromXmlFile(QIODevice *device)
{
xmlData = device->readAll();
return true;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,237 @@
/****************************************************************************
** 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 "xlsxtheme_p.h"
#include <QIODevice>
namespace QXlsx {
const char *defaultXmlData =
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n"
"<a:theme xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\" name=\"Office \xe4\xb8\xbb\xe9\xa2\x98\">"
"<a:themeElements>"
"<a:clrScheme name=\"Office\">"
"<a:dk1><a:sysClr val=\"windowText\" lastClr=\"000000\"/></a:dk1>"
"<a:lt1><a:sysClr val=\"window\" lastClr=\"FFFFFF\"/></a:lt1>"
"<a:dk2><a:srgbClr val=\"1F497D\"/></a:dk2>"
"<a:lt2><a:srgbClr val=\"EEECE1\"/></a:lt2>"
"<a:accent1><a:srgbClr val=\"4F81BD\"/></a:accent1>"
"<a:accent2><a:srgbClr val=\"C0504D\"/></a:accent2>"
"<a:accent3><a:srgbClr val=\"9BBB59\"/></a:accent3>"
"<a:accent4><a:srgbClr val=\"8064A2\"/></a:accent4>"
"<a:accent5><a:srgbClr val=\"4BACC6\"/></a:accent5>"
"<a:accent6><a:srgbClr val=\"F79646\"/></a:accent6>"
"<a:hlink><a:srgbClr val=\"0000FF\"/></a:hlink>"
"<a:folHlink><a:srgbClr val=\"800080\"/></a:folHlink>"
"</a:clrScheme>"
"<a:fontScheme name=\"Office\">"
"<a:majorFont>"
"<a:latin typeface=\"Cambria\"/>"
"<a:ea typeface=\"\"/>"
"<a:cs typeface=\"\"/>"
"<a:font script=\"Jpan\" typeface=\"\xef\xbc\xad\xef\xbc\xb3 \xef\xbc\xb0\xe3\x82\xb4\xe3\x82\xb7\xe3\x83\x83\xe3\x82\xaf\"/>"
"<a:font script=\"Hang\" typeface=\"\xeb\xa7\x91\xec\x9d\x80 \xea\xb3\xa0\xeb\x94\x95\"/>"
"<a:font script=\"Hans\" typeface=\"\xe5\xae\x8b\xe4\xbd\x93\"/>"
"<a:font script=\"Hant\" typeface=\"\xe6\x96\xb0\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94\"/>"
"<a:font script=\"Arab\" typeface=\"Times New Roman\"/>"
"<a:font script=\"Hebr\" typeface=\"Times New Roman\"/>"
"<a:font script=\"Thai\" typeface=\"Tahoma\"/>"
"<a:font script=\"Ethi\" typeface=\"Nyala\"/>"
"<a:font script=\"Beng\" typeface=\"Vrinda\"/>"
"<a:font script=\"Gujr\" typeface=\"Shruti\"/>"
"<a:font script=\"Khmr\" typeface=\"MoolBoran\"/>"
"<a:font script=\"Knda\" typeface=\"Tunga\"/>"
"<a:font script=\"Guru\" typeface=\"Raavi\"/>"
"<a:font script=\"Cans\" typeface=\"Euphemia\"/>"
"<a:font script=\"Cher\" typeface=\"Plantagenet Cherokee\"/>"
"<a:font script=\"Yiii\" typeface=\"Microsoft Yi Baiti\"/>"
"<a:font script=\"Tibt\" typeface=\"Microsoft Himalaya\"/>"
"<a:font script=\"Thaa\" typeface=\"MV Boli\"/>"
"<a:font script=\"Deva\" typeface=\"Mangal\"/>"
"<a:font script=\"Telu\" typeface=\"Gautami\"/>"
"<a:font script=\"Taml\" typeface=\"Latha\"/>"
"<a:font script=\"Syrc\" typeface=\"Estrangelo Edessa\"/>"
"<a:font script=\"Orya\" typeface=\"Kalinga\"/>"
"<a:font script=\"Mlym\" typeface=\"Kartika\"/>"
"<a:font script=\"Laoo\" typeface=\"DokChampa\"/>"
"<a:font script=\"Sinh\" typeface=\"Iskoola Pota\"/>"
"<a:font script=\"Mong\" typeface=\"Mongolian Baiti\"/>"
"<a:font script=\"Viet\" typeface=\"Times New Roman\"/>"
"<a:font script=\"Uigh\" typeface=\"Microsoft Uighur\"/>"
"</a:majorFont>"
"<a:minorFont>"
"<a:latin typeface=\"Calibri\"/>"
"<a:ea typeface=\"\"/>"
"<a:cs typeface=\"\"/>"
"<a:font script=\"Jpan\" typeface=\"\xef\xbc\xad\xef\xbc\xb3 \xef\xbc\xb0\xe3\x82\xb4\xe3\x82\xb7\xe3\x83\x83\xe3\x82\xaf\"/>"
"<a:font script=\"Hang\" typeface=\"\xeb\xa7\x91\xec\x9d\x80 \xea\xb3\xa0\xeb\x94\x95\"/>"
"<a:font script=\"Hans\" typeface=\"\xe5\xae\x8b\xe4\xbd\x93\"/>"
"<a:font script=\"Hant\" typeface=\"\xe6\x96\xb0\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94\"/>"
"<a:font script=\"Arab\" typeface=\"Arial\"/>"
"<a:font script=\"Hebr\" typeface=\"Arial\"/>"
"<a:font script=\"Thai\" typeface=\"Tahoma\"/>"
"<a:font script=\"Ethi\" typeface=\"Nyala\"/>"
"<a:font script=\"Beng\" typeface=\"Vrinda\"/>"
"<a:font script=\"Gujr\" typeface=\"Shruti\"/>"
"<a:font script=\"Khmr\" typeface=\"DaunPenh\"/>"
"<a:font script=\"Knda\" typeface=\"Tunga\"/>"
"<a:font script=\"Guru\" typeface=\"Raavi\"/>"
"<a:font script=\"Cans\" typeface=\"Euphemia\"/>"
"<a:font script=\"Cher\" typeface=\"Plantagenet Cherokee\"/>"
"<a:font script=\"Yiii\" typeface=\"Microsoft Yi Baiti\"/>"
"<a:font script=\"Tibt\" typeface=\"Microsoft Himalaya\"/>"
"<a:font script=\"Thaa\" typeface=\"MV Boli\"/>"
"<a:font script=\"Deva\" typeface=\"Mangal\"/>"
"<a:font script=\"Telu\" typeface=\"Gautami\"/>"
"<a:font script=\"Taml\" typeface=\"Latha\"/>"
"<a:font script=\"Syrc\" typeface=\"Estrangelo Edessa\"/>"
"<a:font script=\"Orya\" typeface=\"Kalinga\"/>"
"<a:font script=\"Mlym\" typeface=\"Kartika\"/>"
"<a:font script=\"Laoo\" typeface=\"DokChampa\"/>"
"<a:font script=\"Sinh\" typeface=\"Iskoola Pota\"/>"
"<a:font script=\"Mong\" typeface=\"Mongolian Baiti\"/>"
"<a:font script=\"Viet\" typeface=\"Arial\"/>"
"<a:font script=\"Uigh\" typeface=\"Microsoft Uighur\"/>"
"</a:minorFont>"
"</a:fontScheme>"
"<a:fmtScheme name=\"Office\">"
"<a:fillStyleLst>"
"<a:solidFill><a:schemeClr val=\"phClr\"/></a:solidFill>"
"<a:gradFill rotWithShape=\"1\">"
"<a:gsLst>"
"<a:gs pos=\"0\"><a:schemeClr val=\"phClr\"><a:tint val=\"50000\"/><a:satMod val=\"300000\"/></a:schemeClr></a:gs>"
"<a:gs pos=\"35000\"><a:schemeClr val=\"phClr\"><a:tint val=\"37000\"/><a:satMod val=\"300000\"/></a:schemeClr></a:gs>"
"<a:gs pos=\"100000\"><a:schemeClr val=\"phClr\"><a:tint val=\"15000\"/><a:satMod val=\"350000\"/></a:schemeClr></a:gs>"
"</a:gsLst>"
"<a:lin ang=\"16200000\" scaled=\"1\"/>"
"</a:gradFill>"
"<a:gradFill rotWithShape=\"1\">"
"<a:gsLst>"
"<a:gs pos=\"0\"><a:schemeClr val=\"phClr\"><a:shade val=\"51000\"/><a:satMod val=\"130000\"/></a:schemeClr></a:gs>"
"<a:gs pos=\"80000\"><a:schemeClr val=\"phClr\"><a:shade val=\"93000\"/><a:satMod val=\"130000\"/></a:schemeClr></a:gs>"
"<a:gs pos=\"100000\"><a:schemeClr val=\"phClr\"><a:shade val=\"94000\"/><a:satMod val=\"135000\"/></a:schemeClr></a:gs>"
"</a:gsLst>"
"<a:lin ang=\"16200000\" scaled=\"0\"/>"
"</a:gradFill>"
"</a:fillStyleLst>"
"<a:lnStyleLst>"
"<a:ln w=\"9525\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\">"
"<a:solidFill><a:schemeClr val=\"phClr\"><a:shade val=\"95000\"/><a:satMod val=\"105000\"/></a:schemeClr></a:solidFill>"
"<a:prstDash val=\"solid\"/>"
"</a:ln>"
"<a:ln w=\"25400\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\">"
"<a:solidFill><a:schemeClr val=\"phClr\"/></a:solidFill>"
"<a:prstDash val=\"solid\"/>"
"</a:ln>"
"<a:ln w=\"38100\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\">"
"<a:solidFill><a:schemeClr val=\"phClr\"/></a:solidFill>"
"<a:prstDash val=\"solid\"/>"
"</a:ln>"
"</a:lnStyleLst>"
"<a:effectStyleLst>"
"<a:effectStyle>"
"<a:effectLst>"
"<a:outerShdw blurRad=\"40000\" dist=\"20000\" dir=\"5400000\" rotWithShape=\"0\">"
"<a:srgbClr val=\"000000\"><a:alpha val=\"38000\"/></a:srgbClr>"
"</a:outerShdw>"
"</a:effectLst>"
"</a:effectStyle>"
"<a:effectStyle>"
"<a:effectLst>"
"<a:outerShdw blurRad=\"40000\" dist=\"23000\" dir=\"5400000\" rotWithShape=\"0\">"
"<a:srgbClr val=\"000000\"><a:alpha val=\"35000\"/></a:srgbClr>"
"</a:outerShdw>"
"</a:effectLst>"
"</a:effectStyle>"
"<a:effectStyle>"
"<a:effectLst>"
"<a:outerShdw blurRad=\"40000\" dist=\"23000\" dir=\"5400000\" rotWithShape=\"0\">"
"<a:srgbClr val=\"000000\"><a:alpha val=\"35000\"/></a:srgbClr>"
"</a:outerShdw>"
"</a:effectLst>"
"<a:scene3d>"
"<a:camera prst=\"orthographicFront\"><a:rot lat=\"0\" lon=\"0\" rev=\"0\"/></a:camera>"
"<a:lightRig rig=\"threePt\" dir=\"t\"><a:rot lat=\"0\" lon=\"0\" rev=\"1200000\"/></a:lightRig>"
"</a:scene3d>"
"<a:sp3d><a:bevelT w=\"63500\" h=\"25400\"/></a:sp3d>"
"</a:effectStyle>"
"</a:effectStyleLst>"
"<a:bgFillStyleLst>"
"<a:solidFill><a:schemeClr val=\"phClr\"/></a:solidFill>"
"<a:gradFill rotWithShape=\"1\">"
"<a:gsLst>"
"<a:gs pos=\"0\"><a:schemeClr val=\"phClr\"><a:tint val=\"40000\"/><a:satMod val=\"350000\"/></a:schemeClr></a:gs>"
"<a:gs pos=\"40000\"><a:schemeClr val=\"phClr\"><a:tint val=\"45000\"/><a:shade val=\"99000\"/><a:satMod val=\"350000\"/></a:schemeClr></a:gs>"
"<a:gs pos=\"100000\"><a:schemeClr val=\"phClr\"><a:shade val=\"20000\"/><a:satMod val=\"255000\"/></a:schemeClr></a:gs></a:gsLst>"
"<a:path path=\"circle\"><a:fillToRect l=\"50000\" t=\"-80000\" r=\"50000\" b=\"180000\"/></a:path>"
"</a:gradFill>"
"<a:gradFill rotWithShape=\"1\">"
"<a:gsLst>"
"<a:gs pos=\"0\"><a:schemeClr val=\"phClr\"><a:tint val=\"80000\"/><a:satMod val=\"300000\"/></a:schemeClr></a:gs>"
"<a:gs pos=\"100000\"><a:schemeClr val=\"phClr\"><a:shade val=\"30000\"/><a:satMod val=\"200000\"/></a:schemeClr></a:gs>"
"</a:gsLst>"
"<a:path path=\"circle\"><a:fillToRect l=\"50000\" t=\"50000\" r=\"50000\" b=\"50000\"/></a:path>"
"</a:gradFill>"
"</a:bgFillStyleLst>"
"</a:fmtScheme>"
"</a:themeElements>"
"<a:objectDefaults/>"
"<a:extraClrSchemeLst/>"
"</a:theme>"
;
Theme::Theme(CreateFlag flag)
:AbstractOOXmlFile(flag)
{
}
void Theme::saveToXmlFile(QIODevice *device) const
{
if (xmlData.isEmpty())
device->write(defaultXmlData);
else
device->write(xmlData);
}
QByteArray Theme::saveToXmlData() const
{
if (xmlData.isEmpty())
return defaultXmlData;
else
return xmlData;
}
bool Theme::loadFromXmlData(const QByteArray &data)
{
xmlData = data;
return true;
}
bool Theme::loadFromXmlFile(QIODevice *device)
{
xmlData = device->readAll();
return true;
}
}

View File

@ -0,0 +1,276 @@
/****************************************************************************
** 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 "xlsxutility_p.h"
#include "xlsxcellreference.h"
#include <QString>
#include <QPoint>
#include <QRegularExpression>
#include <QMap>
#include <QStringList>
#include <QColor>
#include <QDateTime>
#include <QDebug>
namespace QXlsx {
bool parseXsdBoolean(const QString &value, bool defaultValue)
{
if (value == QLatin1String("1") || value == QLatin1String("true"))
return true;
if (value == QLatin1String("0") || value == QLatin1String("false"))
return false;
return defaultValue;
}
QStringList splitPath(const QString &path)
{
int idx = path.lastIndexOf(QLatin1Char('/'));
if (idx == -1)
return QStringList()<<QStringLiteral(".")<<path;
return QStringList()<<path.left(idx)<<path.mid(idx+1);
}
/*
* Return the .rel file path based on filePath
*/
QString getRelFilePath(const QString &filePath)
{
int idx = filePath.lastIndexOf(QLatin1Char('/'));
if (idx == -1)
return QString();
return QString(filePath.left(idx) + QLatin1String("/_rels/")
+ filePath.mid(idx+1) + QLatin1String(".rels"));
}
double datetimeToNumber(const QDateTime &dt, bool is1904)
{
//Note, for number 0, Excel2007 shown as 1900-1-0, which should be 1899-12-31
QDateTime epoch(is1904 ? QDate(1904, 1, 1): QDate(1899, 12, 31), QTime(0,0));
double excel_time = epoch.msecsTo(dt) / (1000*60*60*24.0);
#if QT_VERSION >= 0x050200
if (dt.isDaylightTime()) // Add one hour if the date is Daylight
excel_time += 1.0 / 24.0;
#endif
if (!is1904 && excel_time > 59) {//31+28
//Account for Excel erroneously treating 1900 as a leap year.
excel_time += 1;
}
return excel_time;
}
double timeToNumber(const QTime &time)
{
return QTime(0,0).msecsTo(time) / (1000*60*60*24.0);
}
QDateTime datetimeFromNumber(double num, bool is1904)
{
if (!is1904 && num > 60)
num = num - 1;
qint64 msecs = static_cast<qint64>(num * 1000*60*60*24.0 + 0.5);
QDateTime epoch(is1904 ? QDate(1904, 1, 1): QDate(1899, 12, 31), QTime(0,0));
QDateTime dt = epoch.addMSecs(msecs);
#if QT_VERSION >= 0x050200
// Remove one hour to see whether the date is Daylight
QDateTime dt2 = dt.addMSecs(-3600);
if (dt2.isDaylightTime())
return dt2;
#endif
return dt;
}
/*
Creates a valid sheet name
minimum length is 1
maximum length is 31
doesn't contain special chars: / \ ? * ] [ :
Sheet names must not begin or end with ' (apostrophe)
Invalid characters are replaced by one space character ' '.
*/
QString createSafeSheetName(const QString &nameProposal)
{
if (nameProposal.isEmpty())
return QString();
QString ret = nameProposal;
if (nameProposal.length() > 2 && nameProposal.startsWith(QLatin1Char('\'')) && nameProposal.endsWith(QLatin1Char('\'')))
ret = unescapeSheetName(ret);
//Replace invalid chars with space.
if (nameProposal.contains(QRegularExpression(QStringLiteral("[/\\\\?*\\][:]"))))
ret.replace(QRegularExpression(QStringLiteral("[/\\\\?*\\][:]")), QStringLiteral(" "));
if (ret.startsWith(QLatin1Char('\'')))
ret[0] = QLatin1Char(' ');
if (ret.endsWith(QLatin1Char('\'')))
ret[ret.size()-1] = QLatin1Char(' ');
if (ret.size() > 31)
ret = ret.left(31);
return ret;
}
/*
* When sheetName contains space or apostrophe, escaped is needed by cellFormula/definedName/chartSerials.
*/
QString escapeSheetName(const QString &sheetName)
{
//Already escaped.
Q_ASSERT(!sheetName.startsWith(QLatin1Char('\'')) && !sheetName.endsWith(QLatin1Char('\'')));
//These is no need to escape
if (!sheetName.contains(QRegularExpression(QStringLiteral("[ +\\-,%^=<>'&]"))))
return sheetName;
//OK, escape is needed.
QString name = sheetName;
name.replace(QLatin1Char('\''), QLatin1String("\'\'"));
return QLatin1Char('\'') + name + QLatin1Char('\'');
}
/*
*/
QString unescapeSheetName(const QString &sheetName)
{
Q_ASSERT(sheetName.length() > 2 && sheetName.startsWith(QLatin1Char('\'')) && sheetName.endsWith(QLatin1Char('\'')));
QString name = sheetName.mid(1, sheetName.length()-2);
name.replace(QLatin1String("\'\'"), QLatin1String("\'"));
return name;
}
/*
* whether the string s starts or ends with space
*/
bool isSpaceReserveNeeded(const QString &s)
{
QString spaces(QStringLiteral(" \t\n\r"));
return !s.isEmpty() && (spaces.contains(s.at(0))||spaces.contains(s.at(s.length()-1)));
}
/*
* Convert shared formula for non-root cells.
*
* For example, if "B1:B10" have shared formula "=A1*A1", this function will return "=A2*A2"
* for "B2" cell, "=A3*A3" for "B3" cell, etc.
*
* Note, the formula "=A1*A1" for B1 can also be written as "=RC[-1]*RC[-1]", which is the same
* for all other cells. In other words, this formula is shared.
*
* For long run, we need a formula parser.
*/
QString convertSharedFormula(const QString &rootFormula, const CellReference &rootCell, const CellReference &cell)
{
//Find all the "$?[A-Z]+$?[0-9]+" patterns in the rootFormula.
QList<QPair<QString, int> > segments;
QString segment;
bool inQuote = false;
enum RefState{INVALID, PRE_AZ, AZ, PRE_09, _09};
RefState refState = INVALID;
int refFlag = 0; // 0x00, 0x01, 0x02, 0x03 ==> A1, $A1, A$1, $A$1
foreach (QChar ch, rootFormula) {
if (inQuote) {
segment.append(ch);
if (ch == QLatin1Char('"'))
inQuote = false;
} else {
if (ch == QLatin1Char('"')) {
inQuote = true;
refState = INVALID;
segment.append(ch);
} else if (ch == QLatin1Char('$')) {
if (refState == AZ) {
segment.append(ch);
refState = PRE_09;
refFlag |= 0x02;
} else {
segments.append(qMakePair(segment, refState==_09 ? refFlag : -1));
segment = QString(ch); //Start new segment.
refState = PRE_AZ;
refFlag = 0x01;
}
} else if (ch >= QLatin1Char('A') && ch <=QLatin1Char('Z')) {
if (refState == PRE_AZ || refState == AZ) {
segment.append(ch);
} else {
segments.append(qMakePair(segment, refState==_09 ? refFlag : -1));
segment = QString(ch); //Start new segment.
refFlag = 0x00;
}
refState = AZ;
} else if (ch >= QLatin1Char('0') && ch <=QLatin1Char('9')) {
segment.append(ch);
if (refState == AZ || refState == PRE_09 || refState == _09)
refState = _09;
else
refState = INVALID;
} else {
if (refState == _09) {
segments.append(qMakePair(segment, refFlag));
segment = QString(ch); //Start new segment.
} else {
segment.append(ch);
}
refState = INVALID;
}
}
}
if (!segment.isEmpty())
segments.append(qMakePair(segment, refState==_09 ? refFlag : -1));
//Replace "A1", "$A1", "A$1" segment with proper one.
QStringList result;
typedef QPair<QString, int> PairType;
foreach (PairType p, segments) {
//qDebug()<<p.first<<p.second;
if (p.second != -1 && p.second != 3) {
CellReference oldRef(p.first);
int row = p.second & 0x02 ? oldRef.row() : oldRef.row()-rootCell.row()+cell.row();
int col = p.second & 0x01 ? oldRef.column() : oldRef.column()-rootCell.column()+cell.column();
result.append(CellReference(row, col).toString(p.second & 0x02, p.second & 0x01));
} else {
result.append(p.first);
}
}
//OK
return result.join(QString());
}
} //namespace QXlsx

View File

@ -0,0 +1,697 @@
/****************************************************************************
** 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 "xlsxworkbook.h"
#include "xlsxworkbook_p.h"
#include "xlsxsharedstrings_p.h"
#include "xlsxworksheet.h"
#include "xlsxchartsheet.h"
#include "xlsxstyles_p.h"
#include "xlsxformat.h"
#include "xlsxworksheet_p.h"
#include "xlsxformat_p.h"
#include "xlsxmediafile_p.h"
#include "xlsxutility_p.h"
#include <QXmlStreamWriter>
#include <QXmlStreamReader>
#include <QFile>
#include <QBuffer>
#include <QDir>
QT_BEGIN_NAMESPACE_XLSX
WorkbookPrivate::WorkbookPrivate(Workbook *q, Workbook::CreateFlag flag) :
AbstractOOXmlFilePrivate(q, flag)
{
sharedStrings = QSharedPointer<SharedStrings> (new SharedStrings(flag));
styles = QSharedPointer<Styles>(new Styles(flag));
theme = QSharedPointer<Theme>(new Theme(flag));
x_window = 240;
y_window = 15;
window_width = 16095;
window_height = 9660;
strings_to_numbers_enabled = false;
strings_to_hyperlinks_enabled = true;
html_to_richstring_enabled = false;
date1904 = false;
defaultDateFormat = QStringLiteral("yyyy-mm-dd");
activesheetIndex = 0;
firstsheet = 0;
table_count = 0;
last_worksheet_index = 0;
last_chartsheet_index = 0;
last_sheet_id = 0;
}
Workbook::Workbook(CreateFlag flag)
: AbstractOOXmlFile(new WorkbookPrivate(this, flag))
{
}
Workbook::~Workbook()
{
}
bool Workbook::isDate1904() const
{
Q_D(const Workbook);
return d->date1904;
}
/*!
Excel for Windows uses a default epoch of 1900 and Excel
for Mac uses an epoch of 1904. However, Excel on either
platform will convert automatically between one system
and the other. Qt Xlsx stores dates in the 1900 format
by default.
\note This function should be called before any date/time
has been written.
*/
void Workbook::setDate1904(bool date1904)
{
Q_D(Workbook);
d->date1904 = date1904;
}
/*
Enable the worksheet.write() method to convert strings
to numbers, where possible, using float() in order to avoid
an Excel warning about "Numbers Stored as Text".
The default is false
*/
void Workbook::setStringsToNumbersEnabled(bool enable)
{
Q_D(Workbook);
d->strings_to_numbers_enabled = enable;
}
bool Workbook::isStringsToNumbersEnabled() const
{
Q_D(const Workbook);
return d->strings_to_numbers_enabled;
}
void Workbook::setStringsToHyperlinksEnabled(bool enable)
{
Q_D(Workbook);
d->strings_to_hyperlinks_enabled = enable;
}
bool Workbook::isStringsToHyperlinksEnabled() const
{
Q_D(const Workbook);
return d->strings_to_hyperlinks_enabled;
}
void Workbook::setHtmlToRichStringEnabled(bool enable)
{
Q_D(Workbook);
d->html_to_richstring_enabled = enable;
}
bool Workbook::isHtmlToRichStringEnabled() const
{
Q_D(const Workbook);
return d->html_to_richstring_enabled;
}
QString Workbook::defaultDateFormat() const
{
Q_D(const Workbook);
return d->defaultDateFormat;
}
void Workbook::setDefaultDateFormat(const QString &format)
{
Q_D(Workbook);
d->defaultDateFormat = format;
}
/*!
* \brief Create a defined name in the workbook.
* \param name The defined name
* \param formula The cell or range that the defined name refers to.
* \param comment
* \param scope The name of one worksheet, or empty which means golbal scope.
* \return Return false if the name invalid.
*/
bool Workbook::defineName(const QString &name, const QString &formula, const QString &comment, const QString &scope)
{
Q_D(Workbook);
//Remove the = sign from the formula if it exists.
QString formulaString = formula;
if (formulaString.startsWith(QLatin1Char('=')))
formulaString = formula.mid(1);
int id=-1;
if (!scope.isEmpty()) {
for (int i=0; i<d->sheets.size(); ++i) {
if (d->sheets[i]->sheetName() == scope) {
id = d->sheets[i]->sheetId();
break;
}
}
}
d->definedNamesList.append(XlsxDefineNameData(name, formulaString, comment, id));
return true;
}
AbstractSheet *Workbook::addSheet(const QString &name, AbstractSheet::SheetType type)
{
Q_D(Workbook);
return insertSheet(d->sheets.size(), name, type);
}
/*!
* \internal
*/
QStringList Workbook::worksheetNames() const
{
Q_D(const Workbook);
return d->sheetNames;
}
/*!
* \internal
* Used only when load the xlsx file!!
*/
AbstractSheet *Workbook::addSheet(const QString &name, int sheetId, AbstractSheet::SheetType type)
{
Q_D(Workbook);
if (sheetId > d->last_sheet_id)
d->last_sheet_id = sheetId;
AbstractSheet *sheet=0;
if (type == AbstractSheet::ST_WorkSheet) {
sheet = new Worksheet(name, sheetId, this, F_LoadFromExists);
} else if (type == AbstractSheet::ST_ChartSheet) {
sheet = new Chartsheet(name, sheetId, this, F_LoadFromExists);
} else {
qWarning("unsupported sheet type.");
Q_ASSERT(false);
}
d->sheets.append(QSharedPointer<AbstractSheet>(sheet));
d->sheetNames.append(name);
return sheet;
}
AbstractSheet *Workbook::insertSheet(int index, const QString &name, AbstractSheet::SheetType type)
{
Q_D(Workbook);
QString sheetName = createSafeSheetName(name);
if(index > d->last_sheet_id){
//User tries to insert, where no sheet has gone before.
return 0;
}
if (!sheetName.isEmpty()) {
//If user given an already in-used name, we should not continue any more!
if (d->sheetNames.contains(sheetName))
return 0;
} else {
if (type == AbstractSheet::ST_WorkSheet) {
do {
++d->last_worksheet_index;
sheetName = QStringLiteral("Sheet%1").arg(d->last_worksheet_index);
} while (d->sheetNames.contains(sheetName));
} else if (type == AbstractSheet::ST_ChartSheet) {
do {
++d->last_chartsheet_index;
sheetName = QStringLiteral("Chart%1").arg(d->last_chartsheet_index);
} while (d->sheetNames.contains(sheetName));
} else {
qWarning("unsupported sheet type.");
return 0;
}
}
++d->last_sheet_id;
AbstractSheet *sheet;
if (type == AbstractSheet::ST_WorkSheet)
sheet = new Worksheet(sheetName, d->last_sheet_id, this, F_NewFromScratch);
else
sheet = new Chartsheet(sheetName, d->last_sheet_id, this, F_NewFromScratch);
d->sheets.insert(index, QSharedPointer<AbstractSheet>(sheet));
d->sheetNames.insert(index, sheetName);
d->activesheetIndex = index;
return sheet;
}
/*!
* Returns current active worksheet.
*/
AbstractSheet *Workbook::activeSheet() const
{
Q_D(const Workbook);
if (d->sheets.isEmpty())
const_cast<Workbook*>(this)->addSheet();
return d->sheets[d->activesheetIndex].data();
}
bool Workbook::setActiveSheet(int index)
{
Q_D(Workbook);
if (index < 0 || index >= d->sheets.size()) {
//warning
return false;
}
d->activesheetIndex = index;
return true;
}
/*!
* Rename the worksheet at the \a index to \a newName.
*/
bool Workbook::renameSheet(int index, const QString &newName)
{
Q_D(Workbook);
QString name = createSafeSheetName(newName);
if (index < 0 || index >= d->sheets.size())
return false;
//If user given an already in-used name, return false
for (int i=0; i<d->sheets.size(); ++i) {
if (d->sheets[i]->sheetName() == name)
return false;
}
d->sheets[index]->setSheetName(name);
d->sheetNames[index] = name;
return true;
}
/*!
* Remove the worksheet at pos \a index.
*/
bool Workbook::deleteSheet(int index)
{
Q_D(Workbook);
if (d->sheets.size() <= 1)
return false;
if (index < 0 || index >= d->sheets.size())
return false;
d->sheets.removeAt(index);
d->sheetNames.removeAt(index);
return true;
}
/*!
* Moves the worksheet form \a srcIndex to \a distIndex.
*/
bool Workbook::moveSheet(int srcIndex, int distIndex)
{
Q_D(Workbook);
if (srcIndex == distIndex)
return false;
if (srcIndex < 0 || srcIndex >= d->sheets.size())
return false;
QSharedPointer<AbstractSheet> sheet = d->sheets.takeAt(srcIndex);
d->sheetNames.takeAt(srcIndex);
if (distIndex >= 0 || distIndex <= d->sheets.size()) {
d->sheets.insert(distIndex, sheet);
d->sheetNames.insert(distIndex, sheet->sheetName());
} else {
d->sheets.append(sheet);
d->sheetNames.append(sheet->sheetName());
}
return true;
}
bool Workbook::copySheet(int index, const QString &newName)
{
Q_D(Workbook);
if (index < 0 || index >= d->sheets.size())
return false;
QString worksheetName = createSafeSheetName(newName);
if (!newName.isEmpty()) {
//If user given an already in-used name, we should not continue any more!
if (d->sheetNames.contains(newName))
return false;
} else {
int copy_index = 1;
do {
++copy_index;
worksheetName = QStringLiteral("%1(%2)").arg(d->sheets[index]->sheetName()).arg(copy_index);
} while (d->sheetNames.contains(worksheetName));
}
++d->last_sheet_id;
AbstractSheet *sheet = d->sheets[index]->copy(worksheetName, d->last_sheet_id);
d->sheets.append(QSharedPointer<AbstractSheet> (sheet));
d->sheetNames.append(sheet->sheetName());
return false;
}
/*!
* Returns count of worksheets.
*/
int Workbook::sheetCount() const
{
Q_D(const Workbook);
return d->sheets.count();
}
/*!
* Returns the sheet object at index \a sheetIndex.
*/
AbstractSheet *Workbook::sheet(int index) const
{
Q_D(const Workbook);
if (index < 0 || index >= d->sheets.size())
return 0;
return d->sheets.at(index).data();
}
SharedStrings *Workbook::sharedStrings() const
{
Q_D(const Workbook);
return d->sharedStrings.data();
}
Styles *Workbook::styles()
{
Q_D(Workbook);
return d->styles.data();
}
Theme *Workbook::theme()
{
Q_D(Workbook);
return d->theme.data();
}
/*!
* \internal
*
* Unlike media files, drawing file is a property of the sheet.
*/
QList<Drawing *> Workbook::drawings()
{
Q_D(Workbook);
QList<Drawing *> ds;
for (int i=0; i<d->sheets.size(); ++i) {
QSharedPointer<AbstractSheet> sheet = d->sheets[i];
if (sheet->drawing())
ds.append(sheet->drawing());
}
return ds;
}
/*!
* \internal
*/
QList<QSharedPointer<AbstractSheet> > Workbook::getSheetsByTypes(AbstractSheet::SheetType type) const
{
Q_D(const Workbook);
QList<QSharedPointer<AbstractSheet> > list;
for (int i=0; i<d->sheets.size(); ++i) {
if (d->sheets[i]->sheetType() == type)
list.append(d->sheets[i]);
}
return list;
}
void Workbook::saveToXmlFile(QIODevice *device) const
{
Q_D(const Workbook);
d->relationships->clear();
if (d->sheets.isEmpty())
const_cast<Workbook *>(this)->addSheet();
QXmlStreamWriter writer(device);
writer.writeStartDocument(QStringLiteral("1.0"), true);
writer.writeStartElement(QStringLiteral("workbook"));
writer.writeAttribute(QStringLiteral("xmlns"), QStringLiteral("http://schemas.openxmlformats.org/spreadsheetml/2006/main"));
writer.writeAttribute(QStringLiteral("xmlns:r"), QStringLiteral("http://schemas.openxmlformats.org/officeDocument/2006/relationships"));
writer.writeEmptyElement(QStringLiteral("fileVersion"));
writer.writeAttribute(QStringLiteral("appName"), QStringLiteral("xl"));
writer.writeAttribute(QStringLiteral("lastEdited"), QStringLiteral("4"));
writer.writeAttribute(QStringLiteral("lowestEdited"), QStringLiteral("4"));
writer.writeAttribute(QStringLiteral("rupBuild"), QStringLiteral("4505"));
// writer.writeAttribute(QStringLiteral("codeName"), QStringLiteral("{37E998C4-C9E5-D4B9-71C8-EB1FF731991C}"));
writer.writeEmptyElement(QStringLiteral("workbookPr"));
if (d->date1904)
writer.writeAttribute(QStringLiteral("date1904"), QStringLiteral("1"));
writer.writeAttribute(QStringLiteral("defaultThemeVersion"), QStringLiteral("124226"));
writer.writeStartElement(QStringLiteral("bookViews"));
writer.writeEmptyElement(QStringLiteral("workbookView"));
writer.writeAttribute(QStringLiteral("xWindow"), QString::number(d->x_window));
writer.writeAttribute(QStringLiteral("yWindow"), QString::number(d->y_window));
writer.writeAttribute(QStringLiteral("windowWidth"), QString::number(d->window_width));
writer.writeAttribute(QStringLiteral("windowHeight"), QString::number(d->window_height));
//Store the firstSheet when it isn't the default
//For example, when "the first sheet 0 is hidden", the first sheet will be 1
if (d->firstsheet > 0)
writer.writeAttribute(QStringLiteral("firstSheet"), QString::number(d->firstsheet + 1));
//Store the activeTab when it isn't the first sheet
if (d->activesheetIndex > 0)
writer.writeAttribute(QStringLiteral("activeTab"), QString::number(d->activesheetIndex));
writer.writeEndElement();//bookViews
writer.writeStartElement(QStringLiteral("sheets"));
int worksheetIndex = 0;
int chartsheetIndex = 0;
for (int i=0; i<d->sheets.size(); ++i) {
QSharedPointer<AbstractSheet> sheet = d->sheets[i];
writer.writeEmptyElement(QStringLiteral("sheet"));
writer.writeAttribute(QStringLiteral("name"), sheet->sheetName());
writer.writeAttribute(QStringLiteral("sheetId"), QString::number(sheet->sheetId()));
if (sheet->sheetState() == AbstractSheet::SS_Hidden)
writer.writeAttribute(QStringLiteral("state"), QStringLiteral("hidden"));
else if (sheet->sheetState() == AbstractSheet::SS_VeryHidden)
writer.writeAttribute(QStringLiteral("state"), QStringLiteral("veryHidden"));
if (sheet->sheetType() == AbstractSheet::ST_WorkSheet)
d->relationships->addDocumentRelationship(QStringLiteral("/worksheet"), QStringLiteral("worksheets/sheet%1.xml").arg(++worksheetIndex));
else
d->relationships->addDocumentRelationship(QStringLiteral("/chartsheet"), QStringLiteral("chartsheets/sheet%1.xml").arg(++chartsheetIndex));
writer.writeAttribute(QStringLiteral("r:id"), QStringLiteral("rId%1").arg(d->relationships->count()));
}
writer.writeEndElement();//sheets
if (d->externalLinks.size() > 0) {
writer.writeStartElement(QStringLiteral("externalReferences"));
for (int i=0; i<d->externalLinks.size(); ++i) {
writer.writeEmptyElement(QStringLiteral("externalReference"));
d->relationships->addDocumentRelationship(QStringLiteral("/externalLink"), QStringLiteral("externalLinks/externalLink%1.xml").arg(i+1));
writer.writeAttribute(QStringLiteral("r:id"), QStringLiteral("rId%1").arg(d->relationships->count()));
}
writer.writeEndElement();//externalReferences
}
if (!d->definedNamesList.isEmpty()) {
writer.writeStartElement(QStringLiteral("definedNames"));
foreach (XlsxDefineNameData data, d->definedNamesList) {
writer.writeStartElement(QStringLiteral("definedName"));
writer.writeAttribute(QStringLiteral("name"), data.name);
if (!data.comment.isEmpty())
writer.writeAttribute(QStringLiteral("comment"), data.comment);
if (data.sheetId != -1) {
//find the local index of the sheet.
for (int i=0; i<d->sheets.size(); ++i) {
if (d->sheets[i]->sheetId() == data.sheetId) {
writer.writeAttribute(QStringLiteral("localSheetId"), QString::number(i));
break;
}
}
}
writer.writeCharacters(data.formula);
writer.writeEndElement();//definedName
}
writer.writeEndElement();//definedNames
}
writer.writeStartElement(QStringLiteral("calcPr"));
writer.writeAttribute(QStringLiteral("calcId"), QStringLiteral("124519"));
writer.writeEndElement(); //calcPr
writer.writeEndElement();//workbook
writer.writeEndDocument();
d->relationships->addDocumentRelationship(QStringLiteral("/theme"), QStringLiteral("theme/theme1.xml"));
d->relationships->addDocumentRelationship(QStringLiteral("/styles"), QStringLiteral("styles.xml"));
if (!sharedStrings()->isEmpty())
d->relationships->addDocumentRelationship(QStringLiteral("/sharedStrings"), QStringLiteral("sharedStrings.xml"));
}
bool Workbook::loadFromXmlFile(QIODevice *device)
{
Q_D(Workbook);
QXmlStreamReader reader(device);
while (!reader.atEnd()) {
QXmlStreamReader::TokenType token = reader.readNext();
if (token == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("sheet")) {
QXmlStreamAttributes attributes = reader.attributes();
const QString name = attributes.value(QLatin1String("name")).toString();
int sheetId = attributes.value(QLatin1String("sheetId")).toString().toInt();
const QString rId = attributes.value(QLatin1String("r:id")).toString();
const QStringRef &stateString = attributes.value(QLatin1String("state"));
AbstractSheet::SheetState state = AbstractSheet::SS_Visible;
if (stateString == QLatin1String("hidden"))
state = AbstractSheet::SS_Hidden;
else if (stateString == QLatin1String("veryHidden"))
state = AbstractSheet::SS_VeryHidden;
XlsxRelationship relationship = d->relationships->getRelationshipById(rId);
AbstractSheet::SheetType type = AbstractSheet::ST_WorkSheet;
if (relationship.type.endsWith(QLatin1String("/worksheet")))
type = AbstractSheet::ST_WorkSheet;
else if (relationship.type.endsWith(QLatin1String("/chartsheet")))
type = AbstractSheet::ST_ChartSheet;
else if (relationship.type.endsWith(QLatin1String("/dialogsheet")))
type = AbstractSheet::ST_DialogSheet;
else if (relationship.type.endsWith(QLatin1String("/xlMacrosheet")))
type = AbstractSheet::ST_MacroSheet;
else
qWarning("unknown sheet type");
AbstractSheet *sheet = addSheet(name, sheetId, type);
sheet->setSheetState(state);
const QString fullPath = QDir::cleanPath(splitPath(filePath())[0] +QLatin1String("/")+ relationship.target);
sheet->setFilePath(fullPath);
} else if (reader.name() == QLatin1String("workbookPr")) {
QXmlStreamAttributes attrs = reader.attributes();
if (attrs.hasAttribute(QLatin1String("date1904")))
d->date1904 = true;
} else if (reader.name() == QLatin1String("bookviews")) {
while (!(reader.name() == QLatin1String("bookviews") && reader.tokenType() == QXmlStreamReader::EndElement)) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("workbookView")) {
QXmlStreamAttributes attrs = reader.attributes();
if (attrs.hasAttribute(QLatin1String("xWindow")))
d->x_window = attrs.value(QLatin1String("xWindow")).toString().toInt();
if (attrs.hasAttribute(QLatin1String("yWindow")))
d->y_window = attrs.value(QLatin1String("yWindow")).toString().toInt();
if (attrs.hasAttribute(QLatin1String("windowWidth")))
d->window_width = attrs.value(QLatin1String("windowWidth")).toString().toInt();
if (attrs.hasAttribute(QLatin1String("windowHeight")))
d->window_height = attrs.value(QLatin1String("windowHeight")).toString().toInt();
if (attrs.hasAttribute(QLatin1String("firstSheet")))
d->firstsheet = attrs.value(QLatin1String("firstSheet")).toString().toInt();
if (attrs.hasAttribute(QLatin1String("activeTab")))
d->activesheetIndex = attrs.value(QLatin1String("activeTab")).toString().toInt();
}
}
}
} else if (reader.name() == QLatin1String("externalReference")) {
QXmlStreamAttributes attributes = reader.attributes();
const QString rId = attributes.value(QLatin1String("r:id")).toString();
XlsxRelationship relationship = d->relationships->getRelationshipById(rId);
QSharedPointer<SimpleOOXmlFile> link(new SimpleOOXmlFile(F_LoadFromExists));
const QString fullPath = QDir::cleanPath(splitPath(filePath())[0] +QLatin1String("/")+ relationship.target);
link->setFilePath(fullPath);
d->externalLinks.append(link);
} else if (reader.name() == QLatin1String("definedName")) {
QXmlStreamAttributes attrs = reader.attributes();
XlsxDefineNameData data;
data.name = attrs.value(QLatin1String("name")).toString();
if (attrs.hasAttribute(QLatin1String("comment")))
data.comment = attrs.value(QLatin1String("comment")).toString();
if (attrs.hasAttribute(QLatin1String("localSheetId"))) {
int localId = attrs.value(QLatin1String("localSheetId")).toString().toInt();
int sheetId = d->sheets.at(localId)->sheetId();
data.sheetId = sheetId;
}
data.formula = reader.readElementText();
d->definedNamesList.append(data);
}
}
}
return true;
}
/*!
* \internal
*/
QList<QSharedPointer<MediaFile> > Workbook::mediaFiles() const
{
Q_D(const Workbook);
return d->mediaFiles;
}
/*!
* \internal
*/
void Workbook::addMediaFile(QSharedPointer<MediaFile> media, bool force)
{
Q_D(Workbook);
if (!force) {
for (int i=0; i<d->mediaFiles.size(); ++i) {
if (d->mediaFiles[i]->hashKey() == media->hashKey()) {
media->setIndex(i);
return;
}
}
}
media->setIndex(d->mediaFiles.size());
d->mediaFiles.append(media);
}
/*!
* \internal
*/
QList<QSharedPointer<Chart> > Workbook::chartFiles() const
{
Q_D(const Workbook);
return d->chartFiles;
}
/*!
* \internal
*/
void Workbook::addChartFile(QSharedPointer<Chart> chart)
{
Q_D(Workbook);
if (!d->chartFiles.contains(chart))
d->chartFiles.append(chart);
}
QT_END_NAMESPACE_XLSX

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,77 @@
/****************************************************************************
** 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 "xlsxzipreader_p.h"
#include <private/qzipreader_p.h>
namespace QXlsx {
ZipReader::ZipReader(const QString &filePath) :
m_reader(new QZipReader(filePath))
{
init();
}
ZipReader::ZipReader(QIODevice *device) :
m_reader(new QZipReader(device))
{
init();
}
ZipReader::~ZipReader()
{
}
void ZipReader::init()
{
#if QT_VERSION >= 0x050600
QVector<QZipReader::FileInfo> allFiles = m_reader->fileInfoList();
#else
QList<QZipReader::FileInfo> allFiles = m_reader->fileInfoList();
#endif
foreach (const QZipReader::FileInfo &fi, allFiles) {
if (fi.isFile)
m_filePaths.append(fi.filePath);
}
}
bool ZipReader::exists() const
{
return m_reader->exists();
}
QStringList ZipReader::filePaths() const
{
return m_filePaths;
}
QByteArray ZipReader::fileData(const QString &fileName) const
{
return m_reader->fileData(fileName);
}
} // namespace QXlsx

View File

@ -0,0 +1,68 @@
/****************************************************************************
** 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 "xlsxzipwriter_p.h"
#include <QDebug>
#include <private/qzipwriter_p.h>
namespace QXlsx {
ZipWriter::ZipWriter(const QString &filePath)
{
m_writer = new QZipWriter(filePath, QIODevice::WriteOnly);
m_writer->setCompressionPolicy(QZipWriter::AutoCompress);
}
ZipWriter::ZipWriter(QIODevice *device)
{
m_writer = new QZipWriter(device);
m_writer->setCompressionPolicy(QZipWriter::AutoCompress);
}
ZipWriter::~ZipWriter()
{
delete m_writer;
}
bool ZipWriter::error() const
{
return m_writer->status() != QZipWriter::NoError;
}
void ZipWriter::addFile(const QString &filePath, QIODevice *device)
{
m_writer->addFile(filePath, device);
}
void ZipWriter::addFile(const QString &filePath, const QByteArray &data)
{
m_writer->addFile(filePath, data);
}
void ZipWriter::close()
{
m_writer->close();
}
} // namespace QXlsx