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