comparison src/xlsx/xlsxdocument.cpp @ 1:93d3106bb9a4

Add qt xlsx library
author Andre Heinecke <andre.heinecke@intevation.de>
date Tue, 22 Mar 2016 10:38:08 +0100
parents
children
comparison
equal deleted inserted replaced
0:49cd5cc0b072 1:93d3106bb9a4
1 /****************************************************************************
2 ** Copyright (c) 2013-2014 Debao Zhang <hello@debao.me>
3 ** All right reserved.
4 **
5 ** Permission is hereby granted, free of charge, to any person obtaining
6 ** a copy of this software and associated documentation files (the
7 ** "Software"), to deal in the Software without restriction, including
8 ** without limitation the rights to use, copy, modify, merge, publish,
9 ** distribute, sublicense, and/or sell copies of the Software, and to
10 ** permit persons to whom the Software is furnished to do so, subject to
11 ** the following conditions:
12 **
13 ** The above copyright notice and this permission notice shall be
14 ** included in all copies or substantial portions of the Software.
15 **
16 ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 ** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 ** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 ** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 **
24 ****************************************************************************/
25
26 #include "xlsxdocument.h"
27 #include "xlsxdocument_p.h"
28 #include "xlsxworkbook.h"
29 #include "xlsxworksheet.h"
30 #include "xlsxcontenttypes_p.h"
31 #include "xlsxrelationships_p.h"
32 #include "xlsxstyles_p.h"
33 #include "xlsxtheme_p.h"
34 #include "xlsxdocpropsapp_p.h"
35 #include "xlsxdocpropscore_p.h"
36 #include "xlsxsharedstrings_p.h"
37 #include "xlsxutility_p.h"
38 #include "xlsxworkbook_p.h"
39 #include "xlsxdrawing_p.h"
40 #include "xlsxmediafile_p.h"
41 #include "xlsxchart.h"
42 #include "xlsxzipreader_p.h"
43 #include "xlsxzipwriter_p.h"
44
45 #include <QFile>
46 #include <QPointF>
47 #include <QBuffer>
48 #include <QDir>
49
50 QT_BEGIN_NAMESPACE_XLSX
51
52 /*
53 From Wikipedia: The Open Packaging Conventions (OPC) is a
54 container-file technology initially created by Microsoft to store
55 a combination of XML and non-XML files that together form a single
56 entity such as an Open XML Paper Specification (OpenXPS)
57 document. http://en.wikipedia.org/wiki/Open_Packaging_Conventions.
58
59 At its simplest an Excel XLSX file contains the following elements:
60
61 ____ [Content_Types].xml
62 |
63 |____ docProps
64 | |____ app.xml
65 | |____ core.xml
66 |
67 |____ xl
68 | |____ workbook.xml
69 | |____ worksheets
70 | | |____ sheet1.xml
71 | |
72 | |____ styles.xml
73 | |
74 | |____ theme
75 | | |____ theme1.xml
76 | |
77 | |_____rels
78 | |____ workbook.xml.rels
79 |
80 |_____rels
81 |____ .rels
82
83 The Packager class coordinates the classes that represent the
84 elements of the package and writes them into the XLSX file.
85 */
86
87 DocumentPrivate::DocumentPrivate(Document *p) :
88 q_ptr(p), defaultPackageName(QStringLiteral("Book1.xlsx"))
89 {
90 }
91
92 void DocumentPrivate::init()
93 {
94 if (contentTypes.isNull())
95 contentTypes = QSharedPointer<ContentTypes>(new ContentTypes(ContentTypes::F_NewFromScratch));
96
97 if (workbook.isNull())
98 workbook = QSharedPointer<Workbook>(new Workbook(Workbook::F_NewFromScratch));
99 }
100
101 bool DocumentPrivate::loadPackage(QIODevice *device)
102 {
103 Q_Q(Document);
104 ZipReader zipReader(device);
105 QStringList filePaths = zipReader.filePaths();
106
107 //Load the Content_Types file
108 if (!filePaths.contains(QLatin1String("[Content_Types].xml")))
109 return false;
110 contentTypes = QSharedPointer<ContentTypes>(new ContentTypes(ContentTypes::F_LoadFromExists));
111 contentTypes->loadFromXmlData(zipReader.fileData(QStringLiteral("[Content_Types].xml")));
112
113 //Load root rels file
114 if (!filePaths.contains(QLatin1String("_rels/.rels")))
115 return false;
116 Relationships rootRels;
117 rootRels.loadFromXmlData(zipReader.fileData(QStringLiteral("_rels/.rels")));
118
119 //load core property
120 QList<XlsxRelationship> rels_core = rootRels.packageRelationships(QStringLiteral("/metadata/core-properties"));
121 if (!rels_core.isEmpty()) {
122 //Get the core property file name if it exists.
123 //In normal case, this should be "docProps/core.xml"
124 QString docPropsCore_Name = rels_core[0].target;
125
126 DocPropsCore props(DocPropsCore::F_LoadFromExists);
127 props.loadFromXmlData(zipReader.fileData(docPropsCore_Name));
128 foreach (QString name, props.propertyNames())
129 q->setDocumentProperty(name, props.property(name));
130 }
131
132 //load app property
133 QList<XlsxRelationship> rels_app = rootRels.documentRelationships(QStringLiteral("/extended-properties"));
134 if (!rels_app.isEmpty()) {
135 //Get the app property file name if it exists.
136 //In normal case, this should be "docProps/app.xml"
137 QString docPropsApp_Name = rels_app[0].target;
138
139 DocPropsApp props(DocPropsApp::F_LoadFromExists);
140 props.loadFromXmlData(zipReader.fileData(docPropsApp_Name));
141 foreach (QString name, props.propertyNames())
142 q->setDocumentProperty(name, props.property(name));
143 }
144
145 //load workbook now, Get the workbook file path from the root rels file
146 //In normal case, this should be "xl/workbook.xml"
147 workbook = QSharedPointer<Workbook>(new Workbook(Workbook::F_LoadFromExists));
148 QList<XlsxRelationship> rels_xl = rootRels.documentRelationships(QStringLiteral("/officeDocument"));
149 if (rels_xl.isEmpty())
150 return false;
151 QString xlworkbook_Path = rels_xl[0].target;
152 QString xlworkbook_Dir = splitPath(xlworkbook_Path)[0];
153 workbook->relationships()->loadFromXmlData(zipReader.fileData(getRelFilePath(xlworkbook_Path)));
154 workbook->setFilePath(xlworkbook_Path);
155 workbook->loadFromXmlData(zipReader.fileData(xlworkbook_Path));
156
157 //load styles
158 QList<XlsxRelationship> rels_styles = workbook->relationships()->documentRelationships(QStringLiteral("/styles"));
159 if (!rels_styles.isEmpty()) {
160 //In normal case this should be styles.xml which in xl
161 QString name = rels_styles[0].target;
162 QString path = xlworkbook_Dir + QLatin1String("/") + name;
163 QSharedPointer<Styles> styles (new Styles(Styles::F_LoadFromExists));
164 styles->loadFromXmlData(zipReader.fileData(path));
165 workbook->d_func()->styles = styles;
166 }
167
168 //load sharedStrings
169 QList<XlsxRelationship> rels_sharedStrings = workbook->relationships()->documentRelationships(QStringLiteral("/sharedStrings"));
170 if (!rels_sharedStrings.isEmpty()) {
171 //In normal case this should be sharedStrings.xml which in xl
172 QString name = rels_sharedStrings[0].target;
173 QString path = xlworkbook_Dir + QLatin1String("/") + name;
174 workbook->d_func()->sharedStrings->loadFromXmlData(zipReader.fileData(path));
175 }
176
177 //load theme
178 QList<XlsxRelationship> rels_theme = workbook->relationships()->documentRelationships(QStringLiteral("/theme"));
179 if (!rels_theme.isEmpty()) {
180 //In normal case this should be theme/theme1.xml which in xl
181 QString name = rels_theme[0].target;
182 QString path = xlworkbook_Dir + QLatin1String("/") + name;
183 workbook->theme()->loadFromXmlData(zipReader.fileData(path));
184 }
185
186 //load sheets
187 for (int i=0; i<workbook->sheetCount(); ++i) {
188 AbstractSheet *sheet = workbook->sheet(i);
189 QString rel_path = getRelFilePath(sheet->filePath());
190 //If the .rel file exists, load it.
191 if (zipReader.filePaths().contains(rel_path))
192 sheet->relationships()->loadFromXmlData(zipReader.fileData(rel_path));
193 sheet->loadFromXmlData(zipReader.fileData(sheet->filePath()));
194 }
195
196 //load external links
197 for (int i=0; i<workbook->d_func()->externalLinks.count(); ++i) {
198 SimpleOOXmlFile *link = workbook->d_func()->externalLinks[i].data();
199 QString rel_path = getRelFilePath(link->filePath());
200 //If the .rel file exists, load it.
201 if (zipReader.filePaths().contains(rel_path))
202 link->relationships()->loadFromXmlData(zipReader.fileData(rel_path));
203 link->loadFromXmlData(zipReader.fileData(link->filePath()));
204 }
205
206 //load drawings
207 for (int i=0; i<workbook->drawings().size(); ++i) {
208 Drawing *drawing = workbook->drawings()[i];
209 QString rel_path = getRelFilePath(drawing->filePath());
210 if (zipReader.filePaths().contains(rel_path))
211 drawing->relationships()->loadFromXmlData(zipReader.fileData(rel_path));
212 drawing->loadFromXmlData(zipReader.fileData(drawing->filePath()));
213 }
214
215 //load charts
216 QList<QSharedPointer<Chart> > chartFileToLoad = workbook->chartFiles();
217 for (int i=0; i<chartFileToLoad.size(); ++i) {
218 QSharedPointer<Chart> cf = chartFileToLoad[i];
219 cf->loadFromXmlData(zipReader.fileData(cf->filePath()));
220 }
221
222 //load media files
223 QList<QSharedPointer<MediaFile> > mediaFileToLoad = workbook->mediaFiles();
224 for (int i=0; i<mediaFileToLoad.size(); ++i) {
225 QSharedPointer<MediaFile> mf = mediaFileToLoad[i];
226 const QString path = mf->fileName();
227 const QString suffix = path.mid(path.lastIndexOf(QLatin1Char('.'))+1);
228 mf->set(zipReader.fileData(path), suffix);
229 }
230
231 return true;
232 }
233
234 bool DocumentPrivate::savePackage(QIODevice *device) const
235 {
236 Q_Q(const Document);
237 ZipWriter zipWriter(device);
238 if (zipWriter.error())
239 return false;
240
241 contentTypes->clearOverrides();
242
243 DocPropsApp docPropsApp(DocPropsApp::F_NewFromScratch);
244 DocPropsCore docPropsCore(DocPropsCore::F_NewFromScratch);
245
246 // save worksheet xml files
247 QList<QSharedPointer<AbstractSheet> > worksheets = workbook->getSheetsByTypes(AbstractSheet::ST_WorkSheet);
248 if (!worksheets.isEmpty())
249 docPropsApp.addHeadingPair(QStringLiteral("Worksheets"), worksheets.size());
250 for (int i=0; i<worksheets.size(); ++i) {
251 QSharedPointer<AbstractSheet> sheet = worksheets[i];
252 contentTypes->addWorksheetName(QStringLiteral("sheet%1").arg(i+1));
253 docPropsApp.addPartTitle(sheet->sheetName());
254
255 zipWriter.addFile(QStringLiteral("xl/worksheets/sheet%1.xml").arg(i+1), sheet->saveToXmlData());
256 Relationships *rel = sheet->relationships();
257 if (!rel->isEmpty())
258 zipWriter.addFile(QStringLiteral("xl/worksheets/_rels/sheet%1.xml.rels").arg(i+1), rel->saveToXmlData());
259 }
260
261 //save chartsheet xml files
262 QList<QSharedPointer<AbstractSheet> > chartsheets = workbook->getSheetsByTypes(AbstractSheet::ST_ChartSheet);
263 if (!chartsheets.isEmpty())
264 docPropsApp.addHeadingPair(QStringLiteral("Chartsheets"), chartsheets.size());
265 for (int i=0; i<chartsheets.size(); ++i) {
266 QSharedPointer<AbstractSheet> sheet = chartsheets[i];
267 contentTypes->addWorksheetName(QStringLiteral("sheet%1").arg(i+1));
268 docPropsApp.addPartTitle(sheet->sheetName());
269
270 zipWriter.addFile(QStringLiteral("xl/chartsheets/sheet%1.xml").arg(i+1), sheet->saveToXmlData());
271 Relationships *rel = sheet->relationships();
272 if (!rel->isEmpty())
273 zipWriter.addFile(QStringLiteral("xl/chartsheets/_rels/sheet%1.xml.rels").arg(i+1), rel->saveToXmlData());
274 }
275
276 // save external links xml files
277 for (int i=0; i<workbook->d_func()->externalLinks.count(); ++i) {
278 SimpleOOXmlFile *link = workbook->d_func()->externalLinks[i].data();
279 contentTypes->addExternalLinkName(QStringLiteral("externalLink%1").arg(i+1));
280
281 zipWriter.addFile(QStringLiteral("xl/externalLinks/externalLink%1.xml").arg(i+1), link->saveToXmlData());
282 Relationships *rel = link->relationships();
283 if (!rel->isEmpty())
284 zipWriter.addFile(QStringLiteral("xl/externalLinks/_rels/externalLink%1.xml.rels").arg(i+1), rel->saveToXmlData());
285 }
286
287 // save workbook xml file
288 contentTypes->addWorkbook();
289 zipWriter.addFile(QStringLiteral("xl/workbook.xml"), workbook->saveToXmlData());
290 zipWriter.addFile(QStringLiteral("xl/_rels/workbook.xml.rels"), workbook->relationships()->saveToXmlData());
291
292 // save drawing xml files
293 for (int i=0; i<workbook->drawings().size(); ++i) {
294 contentTypes->addDrawingName(QStringLiteral("drawing%1").arg(i+1));
295
296 Drawing *drawing = workbook->drawings()[i];
297 zipWriter.addFile(QStringLiteral("xl/drawings/drawing%1.xml").arg(i+1), drawing->saveToXmlData());
298 if (!drawing->relationships()->isEmpty())
299 zipWriter.addFile(QStringLiteral("xl/drawings/_rels/drawing%1.xml.rels").arg(i+1), drawing->relationships()->saveToXmlData());
300 }
301
302 // save docProps app/core xml file
303 foreach (QString name, q->documentPropertyNames()) {
304 docPropsApp.setProperty(name, q->documentProperty(name));
305 docPropsCore.setProperty(name, q->documentProperty(name));
306 }
307 contentTypes->addDocPropApp();
308 contentTypes->addDocPropCore();
309 zipWriter.addFile(QStringLiteral("docProps/app.xml"), docPropsApp.saveToXmlData());
310 zipWriter.addFile(QStringLiteral("docProps/core.xml"), docPropsCore.saveToXmlData());
311
312 // save sharedStrings xml file
313 if (!workbook->sharedStrings()->isEmpty()) {
314 contentTypes->addSharedString();
315 zipWriter.addFile(QStringLiteral("xl/sharedStrings.xml"), workbook->sharedStrings()->saveToXmlData());
316 }
317
318 // save styles xml file
319 contentTypes->addStyles();
320 zipWriter.addFile(QStringLiteral("xl/styles.xml"), workbook->styles()->saveToXmlData());
321
322 // save theme xml file
323 contentTypes->addTheme();
324 zipWriter.addFile(QStringLiteral("xl/theme/theme1.xml"), workbook->theme()->saveToXmlData());
325
326 // save chart xml files
327 for (int i=0; i<workbook->chartFiles().size(); ++i) {
328 contentTypes->addChartName(QStringLiteral("chart%1").arg(i+1));
329 QSharedPointer<Chart> cf = workbook->chartFiles()[i];
330 zipWriter.addFile(QStringLiteral("xl/charts/chart%1.xml").arg(i+1), cf->saveToXmlData());
331 }
332
333 // save image files
334 for (int i=0; i<workbook->mediaFiles().size(); ++i) {
335 QSharedPointer<MediaFile> mf = workbook->mediaFiles()[i];
336 if (!mf->mimeType().isEmpty())
337 contentTypes->addDefault(mf->suffix(), mf->mimeType());
338
339 zipWriter.addFile(QStringLiteral("xl/media/image%1.%2").arg(i+1).arg(mf->suffix()), mf->contents());
340 }
341
342 // save root .rels xml file
343 Relationships rootrels;
344 rootrels.addDocumentRelationship(QStringLiteral("/officeDocument"), QStringLiteral("xl/workbook.xml"));
345 rootrels.addPackageRelationship(QStringLiteral("/metadata/core-properties"), QStringLiteral("docProps/core.xml"));
346 rootrels.addDocumentRelationship(QStringLiteral("/extended-properties"), QStringLiteral("docProps/app.xml"));
347 zipWriter.addFile(QStringLiteral("_rels/.rels"), rootrels.saveToXmlData());
348
349 // save content types xml file
350 zipWriter.addFile(QStringLiteral("[Content_Types].xml"), contentTypes->saveToXmlData());
351
352 zipWriter.close();
353 return true;
354 }
355
356
357 /*!
358 \class Document
359 \inmodule QtXlsx
360 \brief The Document class provides a API that is used to handle the contents of .xlsx files.
361
362 */
363
364 /*!
365 * Creates a new empty xlsx document.
366 * The \a parent argument is passed to QObject's constructor.
367 */
368 Document::Document(QObject *parent) :
369 QObject(parent), d_ptr(new DocumentPrivate(this))
370 {
371 d_ptr->init();
372 }
373
374 /*!
375 * \overload
376 * Try to open an existing xlsx document named \a name.
377 * The \a parent argument is passed to QObject's constructor.
378 */
379 Document::Document(const QString &name, QObject *parent) :
380 QObject(parent), d_ptr(new DocumentPrivate(this))
381 {
382 d_ptr->packageName = name;
383 if (QFile::exists(name)) {
384 QFile xlsx(name);
385 if (xlsx.open(QFile::ReadOnly))
386 d_ptr->loadPackage(&xlsx);
387 }
388 d_ptr->init();
389 }
390
391 /*!
392 * \overload
393 * Try to open an existing xlsx document from \a device.
394 * The \a parent argument is passed to QObject's constructor.
395 */
396 Document::Document(QIODevice *device, QObject *parent) :
397 QObject(parent), d_ptr(new DocumentPrivate(this))
398 {
399 if (device && device->isReadable())
400 d_ptr->loadPackage(device);
401 d_ptr->init();
402 }
403
404 /*!
405 \overload
406
407 Write \a value to cell \a row_column with the given \a format.
408 */
409 bool Document::write(const CellReference &row_column, const QVariant &value, const Format &format)
410 {
411 if (Worksheet *sheet = currentWorksheet())
412 return sheet->write(row_column, value, format);
413 return false;
414 }
415
416 /*!
417 * Write \a value to cell (\a row, \a col) with the \a format.
418 * Returns true on success.
419 */
420 bool Document::write(int row, int col, const QVariant &value, const Format &format)
421 {
422 if (Worksheet *sheet = currentWorksheet())
423 return sheet->write(row, col, value, format);
424 return false;
425 }
426
427 /*!
428 \overload
429 Returns the contents of the cell \a cell.
430
431 \sa cellAt()
432 */
433 QVariant Document::read(const CellReference &cell) const
434 {
435 if (Worksheet *sheet = currentWorksheet())
436 return sheet->read(cell);
437 return QVariant();
438 }
439
440 /*!
441 Returns the contents of the cell (\a row, \a col).
442
443 \sa cellAt()
444 */
445 QVariant Document::read(int row, int col) const
446 {
447 if (Worksheet *sheet = currentWorksheet())
448 return sheet->read(row, col);
449 return QVariant();
450 }
451
452 /*!
453 * Insert an \a image to current active worksheet at the position \a row, \a column
454 * Returns ture if success.
455 */
456 bool Document::insertImage(int row, int column, const QImage &image)
457 {
458 if (Worksheet *sheet = currentWorksheet())
459 return sheet->insertImage(row, column, image);
460 return false;
461 }
462
463 /*!
464 * Creates an chart with the given \a size and insert it to the current
465 * active worksheet at the position \a row, \a col.
466 * The chart will be returned.
467 */
468 Chart *Document::insertChart(int row, int col, const QSize &size)
469 {
470 if (Worksheet *sheet = currentWorksheet())
471 return sheet->insertChart(row, col, size);
472 return 0;
473 }
474
475 /*!
476 Merge a \a range of cells. The first cell should contain the data and the others should
477 be blank. All cells will be applied the same style if a valid \a format is given.
478 Returns true on success.
479
480 \note All cells except the top-left one will be cleared.
481 */
482 bool Document::mergeCells(const CellRange &range, const Format &format)
483 {
484 if (Worksheet *sheet = currentWorksheet())
485 return sheet->mergeCells(range, format);
486 return false;
487 }
488
489 /*!
490 Unmerge the cells in the \a range.
491 Returns true on success.
492 */
493 bool Document::unmergeCells(const CellRange &range)
494 {
495 if (Worksheet *sheet = currentWorksheet())
496 return sheet->unmergeCells(range);
497 return false;
498 }
499
500 /*!
501 Sets width in characters of columns with the given \a range and \a width.
502 Returns true on success.
503 */
504 bool Document::setColumnWidth(const CellRange &range, double width)
505 {
506 if (Worksheet *sheet = currentWorksheet())
507 return sheet->setColumnWidth(range, width);
508 return false;
509 }
510
511 /*!
512 Sets format property of columns with the gien \a range and \a format.
513 Returns true on success.
514 */
515 bool Document::setColumnFormat(const CellRange &range, const Format &format)
516 {
517 if (Worksheet *sheet = currentWorksheet())
518 return sheet->setColumnFormat(range, format);
519 return false;
520 }
521
522 /*!
523 Sets hidden property of columns \a range to \a hidden. Columns are 1-indexed.
524 Hidden columns are not visible.
525 Returns true on success.
526 */
527 bool Document::setColumnHidden(const CellRange &range, bool hidden)
528 {
529 if (Worksheet *sheet = currentWorksheet())
530 return sheet->setColumnWidth(range, hidden);
531 return false;
532 }
533
534 /*!
535 Sets width in characters \a column to \a width. Columns are 1-indexed.
536 Returns true on success.
537 */
538 bool Document::setColumnWidth(int column, double width)
539 {
540 return setColumnWidth(column,column,width);
541 }
542
543 /*!
544 Sets format property \a column to \a format. Columns are 1-indexed.
545 Returns true on success.
546 */
547 bool Document::setColumnFormat(int column, const Format &format)
548 {
549 return setColumnFormat(column,column,format);
550 }
551
552 /*!
553 Sets hidden property of a \a column. Columns are 1-indexed.
554 Returns true on success.
555 */
556 bool Document::setColumnHidden(int column, bool hidden)
557 {
558 return setColumnHidden(column,column,hidden);
559 }
560
561 /*!
562 Sets width in characters for columns [\a colFirst, \a colLast]. Columns are 1-indexed.
563 Returns true on success.
564 */
565 bool Document::setColumnWidth(int colFirst, int colLast, double width)
566 {
567 if (Worksheet *sheet = currentWorksheet())
568 return sheet->setColumnWidth(colFirst, colLast, width);
569 return false;
570 }
571
572 /*!
573 Sets format property of columns [\a colFirst, \a colLast] to \a format.
574 Columns are 1-indexed.
575 Returns true on success.
576 */
577 bool Document::setColumnFormat(int colFirst, int colLast, const Format &format)
578 {
579 if (Worksheet *sheet = currentWorksheet())
580 return sheet->setColumnFormat(colFirst, colLast, format);
581 return false;
582 }
583
584
585 /*!
586 Sets hidden property of columns [\a colFirst, \a colLast] to \a hidden.
587 Columns are 1-indexed.
588 Returns true on success.
589 */
590 bool Document::setColumnHidden(int colFirst, int colLast, bool hidden)
591 {
592 if (Worksheet *sheet = currentWorksheet())
593 return sheet->setColumnHidden(colFirst, colLast, hidden);
594 return false;
595 }
596
597 /*!
598 Returns width of the \a column in characters of the normal font.
599 Columns are 1-indexed.
600 Returns true on success.
601 */
602 double Document::columnWidth(int column)
603 {
604 if (Worksheet *sheet = currentWorksheet())
605 return sheet->columnWidth(column);
606 return 0.0;
607 }
608
609 /*!
610 Returns formatting of the \a column. Columns are 1-indexed.
611 */
612 Format Document::columnFormat(int column)
613 {
614 if (Worksheet *sheet = currentWorksheet())
615 return sheet->columnFormat(column);
616 return Format();
617 }
618
619 /*!
620 Returns true if \a column is hidden. Columns are 1-indexed.
621 */
622 bool Document::isColumnHidden(int column)
623 {
624 if (Worksheet *sheet = currentWorksheet())
625 return sheet->isColumnHidden(column);
626 return false;
627 }
628
629 /*!
630 Sets the \a format of the \a row.
631 Rows are 1-indexed.
632
633 Returns true if success.
634 */
635 bool Document::setRowFormat(int row, const Format &format)
636 {
637 return setRowFormat(row,row, format);
638 }
639
640 /*!
641 Sets the \a format of the rows including and between \a rowFirst and \a rowLast.
642 Rows are 1-indexed.
643
644 Returns true if success.
645 */
646 bool Document::setRowFormat(int rowFirst, int rowLast, const Format &format)
647 {
648 if (Worksheet *sheet = currentWorksheet())
649 return sheet->setRowFormat(rowFirst, rowLast, format);
650 return false;
651 }
652
653 /*!
654 Sets the \a hidden property of the row \a row.
655 Rows are 1-indexed. If hidden is true rows will not be visible.
656
657 Returns true if success.
658 */
659 bool Document::setRowHidden(int row, bool hidden)
660 {
661 return setRowHidden(row,row,hidden);
662 }
663
664 /*!
665 Sets the \a hidden property of the rows including and between \a rowFirst and \a rowLast.
666 Rows are 1-indexed. If hidden is true rows will not be visible.
667
668 Returns true if success.
669 */
670 bool Document::setRowHidden(int rowFirst, int rowLast, bool hidden)
671 {
672 if (Worksheet *sheet = currentWorksheet())
673 return sheet->setRowHidden(rowFirst, rowLast, hidden);
674 return false;
675 }
676
677 /*!
678 Sets the \a height of the row \a row.
679 Row height measured in point size.
680 Rows are 1-indexed.
681
682 Returns true if success.
683 */
684 bool Document::setRowHeight(int row, double height)
685 {
686 return setRowHeight(row,row,height);
687 }
688
689 /*!
690 Sets the \a height of the rows including and between \a rowFirst and \a rowLast.
691 Row height measured in point size.
692 Rows are 1-indexed.
693
694 Returns true if success.
695 */
696 bool Document::setRowHeight(int rowFirst, int rowLast, double height)
697 {
698 if (Worksheet *sheet = currentWorksheet())
699 return sheet->setRowHeight(rowFirst, rowLast, height);
700 return false;
701 }
702
703 /*!
704 Returns height of \a row in points.
705 */
706 double Document::rowHeight(int row)
707 {
708 if (Worksheet *sheet = currentWorksheet())
709 return sheet->rowHeight(row);
710 return 0.0;
711 }
712
713 /*!
714 Returns format of \a row.
715 */
716 Format Document::rowFormat(int row)
717 {
718 if (Worksheet *sheet = currentWorksheet())
719 return sheet->rowFormat(row);
720 return Format();
721 }
722
723 /*!
724 Returns true if \a row is hidden.
725 */
726 bool Document::isRowHidden(int row)
727 {
728 if (Worksheet *sheet = currentWorksheet())
729 return sheet->isRowHidden(row);
730 return false;
731 }
732
733 /*!
734 Groups rows from \a rowFirst to \a rowLast with the given \a collapsed.
735 Returns false if error occurs.
736 */
737 bool Document::groupRows(int rowFirst, int rowLast, bool collapsed)
738 {
739 if (Worksheet *sheet = currentWorksheet())
740 return sheet->groupRows(rowFirst, rowLast, collapsed);
741 return false;
742 }
743
744 /*!
745 Groups columns from \a colFirst to \a colLast with the given \a collapsed.
746 Returns false if error occurs.
747 */
748 bool Document::groupColumns(int colFirst, int colLast, bool collapsed)
749 {
750 if (Worksheet *sheet = currentWorksheet())
751 return sheet->groupColumns(colFirst, colLast, collapsed);
752 return false;
753 }
754
755 /*!
756 * Add a data \a validation rule for current worksheet. Returns true if successful.
757 */
758 bool Document::addDataValidation(const DataValidation &validation)
759 {
760 if (Worksheet *sheet = currentWorksheet())
761 return sheet->addDataValidation(validation);
762 return false;
763 }
764
765 /*!
766 * Add a conditional formatting \a cf for current worksheet. Returns true if successful.
767 */
768 bool Document::addConditionalFormatting(const ConditionalFormatting &cf)
769 {
770 if (Worksheet *sheet = currentWorksheet())
771 return sheet->addConditionalFormatting(cf);
772 return false;
773 }
774
775 /*!
776 * \overload
777 * Returns the cell at the position \a pos. If there is no cell at
778 * the specified position, the function returns 0.
779 *
780 * \sa read()
781 */
782 Cell *Document::cellAt(const CellReference &pos) const
783 {
784 if (Worksheet *sheet = currentWorksheet())
785 return sheet->cellAt(pos);
786 return 0;
787 }
788
789 /*!
790 * Returns the cell at the given \a row and \a col. If there
791 * is no cell at the specified position, the function returns 0.
792 *
793 * \sa read()
794 */
795 Cell *Document::cellAt(int row, int col) const
796 {
797 if (Worksheet *sheet = currentWorksheet())
798 return sheet->cellAt(row, col);
799 return 0;
800 }
801
802 /*!
803 * \brief Create a defined name in the workbook with the given \a name, \a formula, \a comment
804 * and \a scope.
805 *
806 * \param name The defined name.
807 * \param formula The cell or range that the defined name refers to.
808 * \param scope The name of one worksheet, or empty which means golbal scope.
809 * \return Return false if the name invalid.
810 */
811 bool Document::defineName(const QString &name, const QString &formula, const QString &comment, const QString &scope)
812 {
813 Q_D(Document);
814
815 return d->workbook->defineName(name, formula, comment, scope);
816 }
817
818 /*!
819 Return the range that contains cell data.
820 */
821 CellRange Document::dimension() const
822 {
823 if (Worksheet *sheet = currentWorksheet())
824 return sheet->dimension();
825 return CellRange();
826 }
827
828 /*!
829 * Returns the value of the document's \a key property.
830 */
831 QString Document::documentProperty(const QString &key) const
832 {
833 Q_D(const Document);
834 if (d->documentProperties.contains(key))
835 return d->documentProperties[key];
836 else
837 return QString();
838 }
839
840 /*!
841 Set the document properties such as Title, Author etc.
842
843 The method can be used to set the document properties of the Excel
844 file created by Qt Xlsx. These properties are visible when you use the
845 Office Button -> Prepare -> Properties option in Excel and are also
846 available to external applications that read or index windows files.
847
848 The \a property \a key that can be set are:
849
850 \list
851 \li title
852 \li subject
853 \li creator
854 \li manager
855 \li company
856 \li category
857 \li keywords
858 \li description
859 \li status
860 \endlist
861 */
862 void Document::setDocumentProperty(const QString &key, const QString &property)
863 {
864 Q_D(Document);
865 d->documentProperties[key] = property;
866 }
867
868 /*!
869 * Returns the names of all properties that were addedusing setDocumentProperty().
870 */
871 QStringList Document::documentPropertyNames() const
872 {
873 Q_D(const Document);
874 return d->documentProperties.keys();
875 }
876
877 /*!
878 * Return the internal Workbook object.
879 */
880 Workbook *Document::workbook() const
881 {
882 Q_D(const Document);
883 return d->workbook.data();
884 }
885
886 /*!
887 * Returns the sheet object named \a sheetName.
888 */
889 AbstractSheet *Document::sheet(const QString &sheetName) const
890 {
891 Q_D(const Document);
892 return d->workbook->sheet(sheetNames().indexOf(sheetName));
893 }
894
895 /*!
896 * Creates and append an sheet with the given \a name and \a type.
897 * Return true if success.
898 */
899 bool Document::addSheet(const QString &name, AbstractSheet::SheetType type)
900 {
901 Q_D(Document);
902 return d->workbook->addSheet(name, type);
903 }
904
905 /*!
906 * Creates and inserts an document with the given \a name and \a type at the \a index.
907 * Returns false if the \a name already used.
908 */
909 bool Document::insertSheet(int index, const QString &name, AbstractSheet::SheetType type)
910 {
911 Q_D(Document);
912 return d->workbook->insertSheet(index, name, type);
913 }
914
915 /*!
916 Rename the worksheet from \a oldName to \a newName.
917 Returns true if the success.
918 */
919 bool Document::renameSheet(const QString &oldName, const QString &newName)
920 {
921 Q_D(Document);
922 if (oldName == newName)
923 return false;
924 return d->workbook->renameSheet(sheetNames().indexOf(oldName), newName);
925 }
926
927 /*!
928 Make a copy of the worksheet \a srcName with the new name \a distName.
929 Returns true if the success.
930 */
931 bool Document::copySheet(const QString &srcName, const QString &distName)
932 {
933 Q_D(Document);
934 if (srcName == distName)
935 return false;
936 return d->workbook->copySheet(sheetNames().indexOf(srcName), distName);
937 }
938
939 /*!
940 Move the worksheet \a srcName to the new pos \a distIndex.
941 Returns true if the success.
942 */
943 bool Document::moveSheet(const QString &srcName, int distIndex)
944 {
945 Q_D(Document);
946 return d->workbook->moveSheet(sheetNames().indexOf(srcName), distIndex);
947 }
948
949 /*!
950 Delete the worksheet \a name.
951 Returns true if current sheet was deleted successfully.
952 */
953 bool Document::deleteSheet(const QString &name)
954 {
955 Q_D(Document);
956 return d->workbook->deleteSheet(sheetNames().indexOf(name));
957 }
958
959 /*!
960 * \brief Return pointer of current sheet.
961 */
962 AbstractSheet *Document::currentSheet() const
963 {
964 Q_D(const Document);
965
966 return d->workbook->activeSheet();
967 }
968
969 /*!
970 * \brief Return pointer of current worksheet.
971 * If the type of sheet is not AbstractSheet::ST_WorkSheet, then 0 will be returned.
972 */
973 Worksheet *Document::currentWorksheet() const
974 {
975 AbstractSheet *st = currentSheet();
976 if (st && st->sheetType() == AbstractSheet::ST_WorkSheet)
977 return static_cast<Worksheet *>(st);
978 else
979 return 0;
980 }
981
982 /*!
983 * \brief Set worksheet named \a name to be active sheet.
984 * Returns true if success.
985 */
986 bool Document::selectSheet(const QString &name)
987 {
988 Q_D(Document);
989 return d->workbook->setActiveSheet(sheetNames().indexOf(name));
990 }
991
992 /*!
993 * Returns the names of worksheets contained in current document.
994 */
995 QStringList Document::sheetNames() const
996 {
997 Q_D(const Document);
998 return d->workbook->worksheetNames();
999 }
1000
1001 /*!
1002 * Save current document to the filesystem. If no name specified when
1003 * the document constructed, a default name "book1.xlsx" will be used.
1004 * Returns true if saved successfully.
1005 */
1006 bool Document::save() const
1007 {
1008 Q_D(const Document);
1009 QString name = d->packageName.isEmpty() ? d->defaultPackageName : d->packageName;
1010
1011 return saveAs(name);
1012 }
1013
1014 /*!
1015 * Saves the document to the file with the given \a name.
1016 * Returns true if saved successfully.
1017 */
1018 bool Document::saveAs(const QString &name) const
1019 {
1020 QFile file(name);
1021 if (file.open(QIODevice::WriteOnly))
1022 return saveAs(&file);
1023 return false;
1024 }
1025
1026 /*!
1027 * \overload
1028 * This function writes a document to the given \a device.
1029 *
1030 * \warning The \a device will be closed when this function returned.
1031 */
1032 bool Document::saveAs(QIODevice *device) const
1033 {
1034 Q_D(const Document);
1035 return d->savePackage(device);
1036 }
1037
1038 /*!
1039 * Destroys the document and cleans up.
1040 */
1041 Document::~Document()
1042 {
1043 delete d_ptr;
1044 }
1045
1046 QT_END_NAMESPACE_XLSX
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)