mirror of
https://github.com/QtExcel/QXlsx.git
synced 2025-01-30 05:02:52 +08:00
update v2
This commit is contained in:
parent
b678e7f331
commit
1c9eff24d6
119
QtXlsxWriter-Static/source/xlsxabstractooxmlfile.cpp
Normal file
119
QtXlsxWriter-Static/source/xlsxabstractooxmlfile.cpp
Normal 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
|
206
QtXlsxWriter-Static/source/xlsxabstractsheet.cpp
Normal file
206
QtXlsxWriter-Static/source/xlsxabstractsheet.cpp
Normal 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
|
178
QtXlsxWriter-Static/source/xlsxcell.cpp
Normal file
178
QtXlsxWriter-Static/source/xlsxcell.cpp
Normal 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
|
259
QtXlsxWriter-Static/source/xlsxcellformula.cpp
Normal file
259
QtXlsxWriter-Static/source/xlsxcellformula.cpp
Normal 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
|
147
QtXlsxWriter-Static/source/xlsxcellrange.cpp
Normal file
147
QtXlsxWriter-Static/source/xlsxcellrange.cpp
Normal 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
|
174
QtXlsxWriter-Static/source/xlsxcellreference.cpp
Normal file
174
QtXlsxWriter-Static/source/xlsxcellreference.cpp
Normal 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
|
645
QtXlsxWriter-Static/source/xlsxchart.cpp
Normal file
645
QtXlsxWriter-Static/source/xlsxchart.cpp
Normal 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
|
159
QtXlsxWriter-Static/source/xlsxchartsheet.cpp
Normal file
159
QtXlsxWriter-Static/source/xlsxchartsheet.cpp
Normal 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
|
198
QtXlsxWriter-Static/source/xlsxcolor.cpp
Normal file
198
QtXlsxWriter-Static/source/xlsxcolor.cpp
Normal 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
|
735
QtXlsxWriter-Static/source/xlsxconditionalformatting.cpp
Normal file
735
QtXlsxWriter-Static/source/xlsxconditionalformatting.cpp
Normal 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
|
205
QtXlsxWriter-Static/source/xlsxcontenttypes.cpp
Normal file
205
QtXlsxWriter-Static/source/xlsxcontenttypes.cpp
Normal 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
|
552
QtXlsxWriter-Static/source/xlsxdatavalidation.cpp
Normal file
552
QtXlsxWriter-Static/source/xlsxdatavalidation.cpp
Normal 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
|
157
QtXlsxWriter-Static/source/xlsxdocpropsapp.cpp
Normal file
157
QtXlsxWriter-Static/source/xlsxdocpropsapp.cpp
Normal 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
|
168
QtXlsxWriter-Static/source/xlsxdocpropscore.cpp
Normal file
168
QtXlsxWriter-Static/source/xlsxdocpropscore.cpp
Normal 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
|
1046
QtXlsxWriter-Static/source/xlsxdocument.cpp
Normal file
1046
QtXlsxWriter-Static/source/xlsxdocument.cpp
Normal file
File diff suppressed because it is too large
Load Diff
87
QtXlsxWriter-Static/source/xlsxdrawing.cpp
Normal file
87
QtXlsxWriter-Static/source/xlsxdrawing.cpp
Normal 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
|
529
QtXlsxWriter-Static/source/xlsxdrawinganchor.cpp
Normal file
529
QtXlsxWriter-Static/source/xlsxdrawinganchor.cpp
Normal 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
|
1432
QtXlsxWriter-Static/source/xlsxformat.cpp
Normal file
1432
QtXlsxWriter-Static/source/xlsxformat.cpp
Normal file
File diff suppressed because it is too large
Load Diff
99
QtXlsxWriter-Static/source/xlsxmediafile.cpp
Normal file
99
QtXlsxWriter-Static/source/xlsxmediafile.cpp
Normal 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
|
94
QtXlsxWriter-Static/source/xlsxnumformatparser.cpp
Normal file
94
QtXlsxWriter-Static/source/xlsxnumformatparser.cpp
Normal 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
|
189
QtXlsxWriter-Static/source/xlsxrelationships.cpp
Normal file
189
QtXlsxWriter-Static/source/xlsxrelationships.cpp
Normal 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
|
343
QtXlsxWriter-Static/source/xlsxrichstring.cpp
Normal file
343
QtXlsxWriter-Static/source/xlsxrichstring.cpp
Normal 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
|
400
QtXlsxWriter-Static/source/xlsxsharedstrings.cpp
Normal file
400
QtXlsxWriter-Static/source/xlsxsharedstrings.cpp
Normal 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
|
56
QtXlsxWriter-Static/source/xlsxsimpleooxmlfile.cpp
Normal file
56
QtXlsxWriter-Static/source/xlsxsimpleooxmlfile.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
1334
QtXlsxWriter-Static/source/xlsxstyles.cpp
Normal file
1334
QtXlsxWriter-Static/source/xlsxstyles.cpp
Normal file
File diff suppressed because it is too large
Load Diff
237
QtXlsxWriter-Static/source/xlsxtheme.cpp
Normal file
237
QtXlsxWriter-Static/source/xlsxtheme.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
276
QtXlsxWriter-Static/source/xlsxutility.cpp
Normal file
276
QtXlsxWriter-Static/source/xlsxutility.cpp
Normal 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
|
697
QtXlsxWriter-Static/source/xlsxworkbook.cpp
Normal file
697
QtXlsxWriter-Static/source/xlsxworkbook.cpp
Normal 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
|
2344
QtXlsxWriter-Static/source/xlsxworksheet.cpp
Normal file
2344
QtXlsxWriter-Static/source/xlsxworksheet.cpp
Normal file
File diff suppressed because it is too large
Load Diff
77
QtXlsxWriter-Static/source/xlsxzipreader.cpp
Normal file
77
QtXlsxWriter-Static/source/xlsxzipreader.cpp
Normal 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
|
68
QtXlsxWriter-Static/source/xlsxzipwriter.cpp
Normal file
68
QtXlsxWriter-Static/source/xlsxzipwriter.cpp
Normal 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
|
Loading…
x
Reference in New Issue
Block a user