Mercurial > clickerconvert
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 |