Mercurial > clickerconvert
view src/xlsx/xlsxdocument.cpp @ 70:3438f5cce8cc
Force text codec for html to use UTF-8
author | Andre Heinecke <andre.heinecke@intevation.de> |
---|---|
date | Thu, 29 Sep 2016 14:41:48 +0200 |
parents | 93d3106bb9a4 |
children |
line wrap: on
line source
/**************************************************************************** ** Copyright (c) 2013-2014 Debao Zhang <hello@debao.me> ** All right reserved. ** ** Permission is hereby granted, free of charge, to any person obtaining ** a copy of this software and associated documentation files (the ** "Software"), to deal in the Software without restriction, including ** without limitation the rights to use, copy, modify, merge, publish, ** distribute, sublicense, and/or sell copies of the Software, and to ** permit persons to whom the Software is furnished to do so, subject to ** the following conditions: ** ** The above copyright notice and this permission notice shall be ** included in all copies or substantial portions of the Software. ** ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE ** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ** ****************************************************************************/ #include "xlsxdocument.h" #include "xlsxdocument_p.h" #include "xlsxworkbook.h" #include "xlsxworksheet.h" #include "xlsxcontenttypes_p.h" #include "xlsxrelationships_p.h" #include "xlsxstyles_p.h" #include "xlsxtheme_p.h" #include "xlsxdocpropsapp_p.h" #include "xlsxdocpropscore_p.h" #include "xlsxsharedstrings_p.h" #include "xlsxutility_p.h" #include "xlsxworkbook_p.h" #include "xlsxdrawing_p.h" #include "xlsxmediafile_p.h" #include "xlsxchart.h" #include "xlsxzipreader_p.h" #include "xlsxzipwriter_p.h" #include <QFile> #include <QPointF> #include <QBuffer> #include <QDir> QT_BEGIN_NAMESPACE_XLSX /* From Wikipedia: The Open Packaging Conventions (OPC) is a container-file technology initially created by Microsoft to store a combination of XML and non-XML files that together form a single entity such as an Open XML Paper Specification (OpenXPS) document. http://en.wikipedia.org/wiki/Open_Packaging_Conventions. At its simplest an Excel XLSX file contains the following elements: ____ [Content_Types].xml | |____ docProps | |____ app.xml | |____ core.xml | |____ xl | |____ workbook.xml | |____ worksheets | | |____ sheet1.xml | | | |____ styles.xml | | | |____ theme | | |____ theme1.xml | | | |_____rels | |____ workbook.xml.rels | |_____rels |____ .rels The Packager class coordinates the classes that represent the elements of the package and writes them into the XLSX file. */ DocumentPrivate::DocumentPrivate(Document *p) : q_ptr(p), defaultPackageName(QStringLiteral("Book1.xlsx")) { } void DocumentPrivate::init() { if (contentTypes.isNull()) contentTypes = QSharedPointer<ContentTypes>(new ContentTypes(ContentTypes::F_NewFromScratch)); if (workbook.isNull()) workbook = QSharedPointer<Workbook>(new Workbook(Workbook::F_NewFromScratch)); } bool DocumentPrivate::loadPackage(QIODevice *device) { Q_Q(Document); ZipReader zipReader(device); QStringList filePaths = zipReader.filePaths(); //Load the Content_Types file if (!filePaths.contains(QLatin1String("[Content_Types].xml"))) return false; contentTypes = QSharedPointer<ContentTypes>(new ContentTypes(ContentTypes::F_LoadFromExists)); contentTypes->loadFromXmlData(zipReader.fileData(QStringLiteral("[Content_Types].xml"))); //Load root rels file if (!filePaths.contains(QLatin1String("_rels/.rels"))) return false; Relationships rootRels; rootRels.loadFromXmlData(zipReader.fileData(QStringLiteral("_rels/.rels"))); //load core property QList<XlsxRelationship> rels_core = rootRels.packageRelationships(QStringLiteral("/metadata/core-properties")); if (!rels_core.isEmpty()) { //Get the core property file name if it exists. //In normal case, this should be "docProps/core.xml" QString docPropsCore_Name = rels_core[0].target; DocPropsCore props(DocPropsCore::F_LoadFromExists); props.loadFromXmlData(zipReader.fileData(docPropsCore_Name)); foreach (QString name, props.propertyNames()) q->setDocumentProperty(name, props.property(name)); } //load app property QList<XlsxRelationship> rels_app = rootRels.documentRelationships(QStringLiteral("/extended-properties")); if (!rels_app.isEmpty()) { //Get the app property file name if it exists. //In normal case, this should be "docProps/app.xml" QString docPropsApp_Name = rels_app[0].target; DocPropsApp props(DocPropsApp::F_LoadFromExists); props.loadFromXmlData(zipReader.fileData(docPropsApp_Name)); foreach (QString name, props.propertyNames()) q->setDocumentProperty(name, props.property(name)); } //load workbook now, Get the workbook file path from the root rels file //In normal case, this should be "xl/workbook.xml" workbook = QSharedPointer<Workbook>(new Workbook(Workbook::F_LoadFromExists)); QList<XlsxRelationship> rels_xl = rootRels.documentRelationships(QStringLiteral("/officeDocument")); if (rels_xl.isEmpty()) return false; QString xlworkbook_Path = rels_xl[0].target; QString xlworkbook_Dir = splitPath(xlworkbook_Path)[0]; workbook->relationships()->loadFromXmlData(zipReader.fileData(getRelFilePath(xlworkbook_Path))); workbook->setFilePath(xlworkbook_Path); workbook->loadFromXmlData(zipReader.fileData(xlworkbook_Path)); //load styles QList<XlsxRelationship> rels_styles = workbook->relationships()->documentRelationships(QStringLiteral("/styles")); if (!rels_styles.isEmpty()) { //In normal case this should be styles.xml which in xl QString name = rels_styles[0].target; QString path = xlworkbook_Dir + QLatin1String("/") + name; QSharedPointer<Styles> styles (new Styles(Styles::F_LoadFromExists)); styles->loadFromXmlData(zipReader.fileData(path)); workbook->d_func()->styles = styles; } //load sharedStrings QList<XlsxRelationship> rels_sharedStrings = workbook->relationships()->documentRelationships(QStringLiteral("/sharedStrings")); if (!rels_sharedStrings.isEmpty()) { //In normal case this should be sharedStrings.xml which in xl QString name = rels_sharedStrings[0].target; QString path = xlworkbook_Dir + QLatin1String("/") + name; workbook->d_func()->sharedStrings->loadFromXmlData(zipReader.fileData(path)); } //load theme QList<XlsxRelationship> rels_theme = workbook->relationships()->documentRelationships(QStringLiteral("/theme")); if (!rels_theme.isEmpty()) { //In normal case this should be theme/theme1.xml which in xl QString name = rels_theme[0].target; QString path = xlworkbook_Dir + QLatin1String("/") + name; workbook->theme()->loadFromXmlData(zipReader.fileData(path)); } //load sheets for (int i=0; i<workbook->sheetCount(); ++i) { AbstractSheet *sheet = workbook->sheet(i); QString rel_path = getRelFilePath(sheet->filePath()); //If the .rel file exists, load it. if (zipReader.filePaths().contains(rel_path)) sheet->relationships()->loadFromXmlData(zipReader.fileData(rel_path)); sheet->loadFromXmlData(zipReader.fileData(sheet->filePath())); } //load external links for (int i=0; i<workbook->d_func()->externalLinks.count(); ++i) { SimpleOOXmlFile *link = workbook->d_func()->externalLinks[i].data(); QString rel_path = getRelFilePath(link->filePath()); //If the .rel file exists, load it. if (zipReader.filePaths().contains(rel_path)) link->relationships()->loadFromXmlData(zipReader.fileData(rel_path)); link->loadFromXmlData(zipReader.fileData(link->filePath())); } //load drawings for (int i=0; i<workbook->drawings().size(); ++i) { Drawing *drawing = workbook->drawings()[i]; QString rel_path = getRelFilePath(drawing->filePath()); if (zipReader.filePaths().contains(rel_path)) drawing->relationships()->loadFromXmlData(zipReader.fileData(rel_path)); drawing->loadFromXmlData(zipReader.fileData(drawing->filePath())); } //load charts QList<QSharedPointer<Chart> > chartFileToLoad = workbook->chartFiles(); for (int i=0; i<chartFileToLoad.size(); ++i) { QSharedPointer<Chart> cf = chartFileToLoad[i]; cf->loadFromXmlData(zipReader.fileData(cf->filePath())); } //load media files QList<QSharedPointer<MediaFile> > mediaFileToLoad = workbook->mediaFiles(); for (int i=0; i<mediaFileToLoad.size(); ++i) { QSharedPointer<MediaFile> mf = mediaFileToLoad[i]; const QString path = mf->fileName(); const QString suffix = path.mid(path.lastIndexOf(QLatin1Char('.'))+1); mf->set(zipReader.fileData(path), suffix); } return true; } bool DocumentPrivate::savePackage(QIODevice *device) const { Q_Q(const Document); ZipWriter zipWriter(device); if (zipWriter.error()) return false; contentTypes->clearOverrides(); DocPropsApp docPropsApp(DocPropsApp::F_NewFromScratch); DocPropsCore docPropsCore(DocPropsCore::F_NewFromScratch); // save worksheet xml files QList<QSharedPointer<AbstractSheet> > worksheets = workbook->getSheetsByTypes(AbstractSheet::ST_WorkSheet); if (!worksheets.isEmpty()) docPropsApp.addHeadingPair(QStringLiteral("Worksheets"), worksheets.size()); for (int i=0; i<worksheets.size(); ++i) { QSharedPointer<AbstractSheet> sheet = worksheets[i]; contentTypes->addWorksheetName(QStringLiteral("sheet%1").arg(i+1)); docPropsApp.addPartTitle(sheet->sheetName()); zipWriter.addFile(QStringLiteral("xl/worksheets/sheet%1.xml").arg(i+1), sheet->saveToXmlData()); Relationships *rel = sheet->relationships(); if (!rel->isEmpty()) zipWriter.addFile(QStringLiteral("xl/worksheets/_rels/sheet%1.xml.rels").arg(i+1), rel->saveToXmlData()); } //save chartsheet xml files QList<QSharedPointer<AbstractSheet> > chartsheets = workbook->getSheetsByTypes(AbstractSheet::ST_ChartSheet); if (!chartsheets.isEmpty()) docPropsApp.addHeadingPair(QStringLiteral("Chartsheets"), chartsheets.size()); for (int i=0; i<chartsheets.size(); ++i) { QSharedPointer<AbstractSheet> sheet = chartsheets[i]; contentTypes->addWorksheetName(QStringLiteral("sheet%1").arg(i+1)); docPropsApp.addPartTitle(sheet->sheetName()); zipWriter.addFile(QStringLiteral("xl/chartsheets/sheet%1.xml").arg(i+1), sheet->saveToXmlData()); Relationships *rel = sheet->relationships(); if (!rel->isEmpty()) zipWriter.addFile(QStringLiteral("xl/chartsheets/_rels/sheet%1.xml.rels").arg(i+1), rel->saveToXmlData()); } // save external links xml files for (int i=0; i<workbook->d_func()->externalLinks.count(); ++i) { SimpleOOXmlFile *link = workbook->d_func()->externalLinks[i].data(); contentTypes->addExternalLinkName(QStringLiteral("externalLink%1").arg(i+1)); zipWriter.addFile(QStringLiteral("xl/externalLinks/externalLink%1.xml").arg(i+1), link->saveToXmlData()); Relationships *rel = link->relationships(); if (!rel->isEmpty()) zipWriter.addFile(QStringLiteral("xl/externalLinks/_rels/externalLink%1.xml.rels").arg(i+1), rel->saveToXmlData()); } // save workbook xml file contentTypes->addWorkbook(); zipWriter.addFile(QStringLiteral("xl/workbook.xml"), workbook->saveToXmlData()); zipWriter.addFile(QStringLiteral("xl/_rels/workbook.xml.rels"), workbook->relationships()->saveToXmlData()); // save drawing xml files for (int i=0; i<workbook->drawings().size(); ++i) { contentTypes->addDrawingName(QStringLiteral("drawing%1").arg(i+1)); Drawing *drawing = workbook->drawings()[i]; zipWriter.addFile(QStringLiteral("xl/drawings/drawing%1.xml").arg(i+1), drawing->saveToXmlData()); if (!drawing->relationships()->isEmpty()) zipWriter.addFile(QStringLiteral("xl/drawings/_rels/drawing%1.xml.rels").arg(i+1), drawing->relationships()->saveToXmlData()); } // save docProps app/core xml file foreach (QString name, q->documentPropertyNames()) { docPropsApp.setProperty(name, q->documentProperty(name)); docPropsCore.setProperty(name, q->documentProperty(name)); } contentTypes->addDocPropApp(); contentTypes->addDocPropCore(); zipWriter.addFile(QStringLiteral("docProps/app.xml"), docPropsApp.saveToXmlData()); zipWriter.addFile(QStringLiteral("docProps/core.xml"), docPropsCore.saveToXmlData()); // save sharedStrings xml file if (!workbook->sharedStrings()->isEmpty()) { contentTypes->addSharedString(); zipWriter.addFile(QStringLiteral("xl/sharedStrings.xml"), workbook->sharedStrings()->saveToXmlData()); } // save styles xml file contentTypes->addStyles(); zipWriter.addFile(QStringLiteral("xl/styles.xml"), workbook->styles()->saveToXmlData()); // save theme xml file contentTypes->addTheme(); zipWriter.addFile(QStringLiteral("xl/theme/theme1.xml"), workbook->theme()->saveToXmlData()); // save chart xml files for (int i=0; i<workbook->chartFiles().size(); ++i) { contentTypes->addChartName(QStringLiteral("chart%1").arg(i+1)); QSharedPointer<Chart> cf = workbook->chartFiles()[i]; zipWriter.addFile(QStringLiteral("xl/charts/chart%1.xml").arg(i+1), cf->saveToXmlData()); } // save image files for (int i=0; i<workbook->mediaFiles().size(); ++i) { QSharedPointer<MediaFile> mf = workbook->mediaFiles()[i]; if (!mf->mimeType().isEmpty()) contentTypes->addDefault(mf->suffix(), mf->mimeType()); zipWriter.addFile(QStringLiteral("xl/media/image%1.%2").arg(i+1).arg(mf->suffix()), mf->contents()); } // save root .rels xml file Relationships rootrels; rootrels.addDocumentRelationship(QStringLiteral("/officeDocument"), QStringLiteral("xl/workbook.xml")); rootrels.addPackageRelationship(QStringLiteral("/metadata/core-properties"), QStringLiteral("docProps/core.xml")); rootrels.addDocumentRelationship(QStringLiteral("/extended-properties"), QStringLiteral("docProps/app.xml")); zipWriter.addFile(QStringLiteral("_rels/.rels"), rootrels.saveToXmlData()); // save content types xml file zipWriter.addFile(QStringLiteral("[Content_Types].xml"), contentTypes->saveToXmlData()); zipWriter.close(); return true; } /*! \class Document \inmodule QtXlsx \brief The Document class provides a API that is used to handle the contents of .xlsx files. */ /*! * Creates a new empty xlsx document. * The \a parent argument is passed to QObject's constructor. */ Document::Document(QObject *parent) : QObject(parent), d_ptr(new DocumentPrivate(this)) { d_ptr->init(); } /*! * \overload * Try to open an existing xlsx document named \a name. * The \a parent argument is passed to QObject's constructor. */ Document::Document(const QString &name, QObject *parent) : QObject(parent), d_ptr(new DocumentPrivate(this)) { d_ptr->packageName = name; if (QFile::exists(name)) { QFile xlsx(name); if (xlsx.open(QFile::ReadOnly)) d_ptr->loadPackage(&xlsx); } d_ptr->init(); } /*! * \overload * Try to open an existing xlsx document from \a device. * The \a parent argument is passed to QObject's constructor. */ Document::Document(QIODevice *device, QObject *parent) : QObject(parent), d_ptr(new DocumentPrivate(this)) { if (device && device->isReadable()) d_ptr->loadPackage(device); d_ptr->init(); } /*! \overload Write \a value to cell \a row_column with the given \a format. */ bool Document::write(const CellReference &row_column, const QVariant &value, const Format &format) { if (Worksheet *sheet = currentWorksheet()) return sheet->write(row_column, value, format); return false; } /*! * Write \a value to cell (\a row, \a col) with the \a format. * Returns true on success. */ bool Document::write(int row, int col, const QVariant &value, const Format &format) { if (Worksheet *sheet = currentWorksheet()) return sheet->write(row, col, value, format); return false; } /*! \overload Returns the contents of the cell \a cell. \sa cellAt() */ QVariant Document::read(const CellReference &cell) const { if (Worksheet *sheet = currentWorksheet()) return sheet->read(cell); return QVariant(); } /*! Returns the contents of the cell (\a row, \a col). \sa cellAt() */ QVariant Document::read(int row, int col) const { if (Worksheet *sheet = currentWorksheet()) return sheet->read(row, col); return QVariant(); } /*! * Insert an \a image to current active worksheet at the position \a row, \a column * Returns ture if success. */ bool Document::insertImage(int row, int column, const QImage &image) { if (Worksheet *sheet = currentWorksheet()) return sheet->insertImage(row, column, image); return false; } /*! * Creates an chart with the given \a size and insert it to the current * active worksheet at the position \a row, \a col. * The chart will be returned. */ Chart *Document::insertChart(int row, int col, const QSize &size) { if (Worksheet *sheet = currentWorksheet()) return sheet->insertChart(row, col, size); return 0; } /*! Merge a \a range of cells. The first cell should contain the data and the others should be blank. All cells will be applied the same style if a valid \a format is given. Returns true on success. \note All cells except the top-left one will be cleared. */ bool Document::mergeCells(const CellRange &range, const Format &format) { if (Worksheet *sheet = currentWorksheet()) return sheet->mergeCells(range, format); return false; } /*! Unmerge the cells in the \a range. Returns true on success. */ bool Document::unmergeCells(const CellRange &range) { if (Worksheet *sheet = currentWorksheet()) return sheet->unmergeCells(range); return false; } /*! Sets width in characters of columns with the given \a range and \a width. Returns true on success. */ bool Document::setColumnWidth(const CellRange &range, double width) { if (Worksheet *sheet = currentWorksheet()) return sheet->setColumnWidth(range, width); return false; } /*! Sets format property of columns with the gien \a range and \a format. Returns true on success. */ bool Document::setColumnFormat(const CellRange &range, const Format &format) { if (Worksheet *sheet = currentWorksheet()) return sheet->setColumnFormat(range, format); return false; } /*! Sets hidden property of columns \a range to \a hidden. Columns are 1-indexed. Hidden columns are not visible. Returns true on success. */ bool Document::setColumnHidden(const CellRange &range, bool hidden) { if (Worksheet *sheet = currentWorksheet()) return sheet->setColumnWidth(range, hidden); return false; } /*! Sets width in characters \a column to \a width. Columns are 1-indexed. Returns true on success. */ bool Document::setColumnWidth(int column, double width) { return setColumnWidth(column,column,width); } /*! Sets format property \a column to \a format. Columns are 1-indexed. Returns true on success. */ bool Document::setColumnFormat(int column, const Format &format) { return setColumnFormat(column,column,format); } /*! Sets hidden property of a \a column. Columns are 1-indexed. Returns true on success. */ bool Document::setColumnHidden(int column, bool hidden) { return setColumnHidden(column,column,hidden); } /*! Sets width in characters for columns [\a colFirst, \a colLast]. Columns are 1-indexed. Returns true on success. */ bool Document::setColumnWidth(int colFirst, int colLast, double width) { if (Worksheet *sheet = currentWorksheet()) return sheet->setColumnWidth(colFirst, colLast, width); return false; } /*! Sets format property of columns [\a colFirst, \a colLast] to \a format. Columns are 1-indexed. Returns true on success. */ bool Document::setColumnFormat(int colFirst, int colLast, const Format &format) { if (Worksheet *sheet = currentWorksheet()) return sheet->setColumnFormat(colFirst, colLast, format); return false; } /*! Sets hidden property of columns [\a colFirst, \a colLast] to \a hidden. Columns are 1-indexed. Returns true on success. */ bool Document::setColumnHidden(int colFirst, int colLast, bool hidden) { if (Worksheet *sheet = currentWorksheet()) return sheet->setColumnHidden(colFirst, colLast, hidden); return false; } /*! Returns width of the \a column in characters of the normal font. Columns are 1-indexed. Returns true on success. */ double Document::columnWidth(int column) { if (Worksheet *sheet = currentWorksheet()) return sheet->columnWidth(column); return 0.0; } /*! Returns formatting of the \a column. Columns are 1-indexed. */ Format Document::columnFormat(int column) { if (Worksheet *sheet = currentWorksheet()) return sheet->columnFormat(column); return Format(); } /*! Returns true if \a column is hidden. Columns are 1-indexed. */ bool Document::isColumnHidden(int column) { if (Worksheet *sheet = currentWorksheet()) return sheet->isColumnHidden(column); return false; } /*! Sets the \a format of the \a row. Rows are 1-indexed. Returns true if success. */ bool Document::setRowFormat(int row, const Format &format) { return setRowFormat(row,row, format); } /*! Sets the \a format of the rows including and between \a rowFirst and \a rowLast. Rows are 1-indexed. Returns true if success. */ bool Document::setRowFormat(int rowFirst, int rowLast, const Format &format) { if (Worksheet *sheet = currentWorksheet()) return sheet->setRowFormat(rowFirst, rowLast, format); return false; } /*! Sets the \a hidden property of the row \a row. Rows are 1-indexed. If hidden is true rows will not be visible. Returns true if success. */ bool Document::setRowHidden(int row, bool hidden) { return setRowHidden(row,row,hidden); } /*! Sets the \a hidden property of the rows including and between \a rowFirst and \a rowLast. Rows are 1-indexed. If hidden is true rows will not be visible. Returns true if success. */ bool Document::setRowHidden(int rowFirst, int rowLast, bool hidden) { if (Worksheet *sheet = currentWorksheet()) return sheet->setRowHidden(rowFirst, rowLast, hidden); return false; } /*! Sets the \a height of the row \a row. Row height measured in point size. Rows are 1-indexed. Returns true if success. */ bool Document::setRowHeight(int row, double height) { return setRowHeight(row,row,height); } /*! Sets the \a height of the rows including and between \a rowFirst and \a rowLast. Row height measured in point size. Rows are 1-indexed. Returns true if success. */ bool Document::setRowHeight(int rowFirst, int rowLast, double height) { if (Worksheet *sheet = currentWorksheet()) return sheet->setRowHeight(rowFirst, rowLast, height); return false; } /*! Returns height of \a row in points. */ double Document::rowHeight(int row) { if (Worksheet *sheet = currentWorksheet()) return sheet->rowHeight(row); return 0.0; } /*! Returns format of \a row. */ Format Document::rowFormat(int row) { if (Worksheet *sheet = currentWorksheet()) return sheet->rowFormat(row); return Format(); } /*! Returns true if \a row is hidden. */ bool Document::isRowHidden(int row) { if (Worksheet *sheet = currentWorksheet()) return sheet->isRowHidden(row); return false; } /*! Groups rows from \a rowFirst to \a rowLast with the given \a collapsed. Returns false if error occurs. */ bool Document::groupRows(int rowFirst, int rowLast, bool collapsed) { if (Worksheet *sheet = currentWorksheet()) return sheet->groupRows(rowFirst, rowLast, collapsed); return false; } /*! Groups columns from \a colFirst to \a colLast with the given \a collapsed. Returns false if error occurs. */ bool Document::groupColumns(int colFirst, int colLast, bool collapsed) { if (Worksheet *sheet = currentWorksheet()) return sheet->groupColumns(colFirst, colLast, collapsed); return false; } /*! * Add a data \a validation rule for current worksheet. Returns true if successful. */ bool Document::addDataValidation(const DataValidation &validation) { if (Worksheet *sheet = currentWorksheet()) return sheet->addDataValidation(validation); return false; } /*! * Add a conditional formatting \a cf for current worksheet. Returns true if successful. */ bool Document::addConditionalFormatting(const ConditionalFormatting &cf) { if (Worksheet *sheet = currentWorksheet()) return sheet->addConditionalFormatting(cf); return false; } /*! * \overload * Returns the cell at the position \a pos. If there is no cell at * the specified position, the function returns 0. * * \sa read() */ Cell *Document::cellAt(const CellReference &pos) const { if (Worksheet *sheet = currentWorksheet()) return sheet->cellAt(pos); return 0; } /*! * Returns the cell at the given \a row and \a col. If there * is no cell at the specified position, the function returns 0. * * \sa read() */ Cell *Document::cellAt(int row, int col) const { if (Worksheet *sheet = currentWorksheet()) return sheet->cellAt(row, col); return 0; } /*! * \brief Create a defined name in the workbook with the given \a name, \a formula, \a comment * and \a scope. * * \param name The defined name. * \param formula The cell or range that the defined name refers to. * \param scope The name of one worksheet, or empty which means golbal scope. * \return Return false if the name invalid. */ bool Document::defineName(const QString &name, const QString &formula, const QString &comment, const QString &scope) { Q_D(Document); return d->workbook->defineName(name, formula, comment, scope); } /*! Return the range that contains cell data. */ CellRange Document::dimension() const { if (Worksheet *sheet = currentWorksheet()) return sheet->dimension(); return CellRange(); } /*! * Returns the value of the document's \a key property. */ QString Document::documentProperty(const QString &key) const { Q_D(const Document); if (d->documentProperties.contains(key)) return d->documentProperties[key]; else return QString(); } /*! Set the document properties such as Title, Author etc. The method can be used to set the document properties of the Excel file created by Qt Xlsx. These properties are visible when you use the Office Button -> Prepare -> Properties option in Excel and are also available to external applications that read or index windows files. The \a property \a key that can be set are: \list \li title \li subject \li creator \li manager \li company \li category \li keywords \li description \li status \endlist */ void Document::setDocumentProperty(const QString &key, const QString &property) { Q_D(Document); d->documentProperties[key] = property; } /*! * Returns the names of all properties that were addedusing setDocumentProperty(). */ QStringList Document::documentPropertyNames() const { Q_D(const Document); return d->documentProperties.keys(); } /*! * Return the internal Workbook object. */ Workbook *Document::workbook() const { Q_D(const Document); return d->workbook.data(); } /*! * Returns the sheet object named \a sheetName. */ AbstractSheet *Document::sheet(const QString &sheetName) const { Q_D(const Document); return d->workbook->sheet(sheetNames().indexOf(sheetName)); } /*! * Creates and append an sheet with the given \a name and \a type. * Return true if success. */ bool Document::addSheet(const QString &name, AbstractSheet::SheetType type) { Q_D(Document); return d->workbook->addSheet(name, type); } /*! * Creates and inserts an document with the given \a name and \a type at the \a index. * Returns false if the \a name already used. */ bool Document::insertSheet(int index, const QString &name, AbstractSheet::SheetType type) { Q_D(Document); return d->workbook->insertSheet(index, name, type); } /*! Rename the worksheet from \a oldName to \a newName. Returns true if the success. */ bool Document::renameSheet(const QString &oldName, const QString &newName) { Q_D(Document); if (oldName == newName) return false; return d->workbook->renameSheet(sheetNames().indexOf(oldName), newName); } /*! Make a copy of the worksheet \a srcName with the new name \a distName. Returns true if the success. */ bool Document::copySheet(const QString &srcName, const QString &distName) { Q_D(Document); if (srcName == distName) return false; return d->workbook->copySheet(sheetNames().indexOf(srcName), distName); } /*! Move the worksheet \a srcName to the new pos \a distIndex. Returns true if the success. */ bool Document::moveSheet(const QString &srcName, int distIndex) { Q_D(Document); return d->workbook->moveSheet(sheetNames().indexOf(srcName), distIndex); } /*! Delete the worksheet \a name. Returns true if current sheet was deleted successfully. */ bool Document::deleteSheet(const QString &name) { Q_D(Document); return d->workbook->deleteSheet(sheetNames().indexOf(name)); } /*! * \brief Return pointer of current sheet. */ AbstractSheet *Document::currentSheet() const { Q_D(const Document); return d->workbook->activeSheet(); } /*! * \brief Return pointer of current worksheet. * If the type of sheet is not AbstractSheet::ST_WorkSheet, then 0 will be returned. */ Worksheet *Document::currentWorksheet() const { AbstractSheet *st = currentSheet(); if (st && st->sheetType() == AbstractSheet::ST_WorkSheet) return static_cast<Worksheet *>(st); else return 0; } /*! * \brief Set worksheet named \a name to be active sheet. * Returns true if success. */ bool Document::selectSheet(const QString &name) { Q_D(Document); return d->workbook->setActiveSheet(sheetNames().indexOf(name)); } /*! * Returns the names of worksheets contained in current document. */ QStringList Document::sheetNames() const { Q_D(const Document); return d->workbook->worksheetNames(); } /*! * Save current document to the filesystem. If no name specified when * the document constructed, a default name "book1.xlsx" will be used. * Returns true if saved successfully. */ bool Document::save() const { Q_D(const Document); QString name = d->packageName.isEmpty() ? d->defaultPackageName : d->packageName; return saveAs(name); } /*! * Saves the document to the file with the given \a name. * Returns true if saved successfully. */ bool Document::saveAs(const QString &name) const { QFile file(name); if (file.open(QIODevice::WriteOnly)) return saveAs(&file); return false; } /*! * \overload * This function writes a document to the given \a device. * * \warning The \a device will be closed when this function returned. */ bool Document::saveAs(QIODevice *device) const { Q_D(const Document); return d->savePackage(device); } /*! * Destroys the document and cleans up. */ Document::~Document() { delete d_ptr; } QT_END_NAMESPACE_XLSX