xlsxworksheet.cpp 80 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344
  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. #include "xlsxrichstring.h"
  26. #include "xlsxcellreference.h"
  27. #include "xlsxworksheet.h"
  28. #include "xlsxworksheet_p.h"
  29. #include "xlsxworkbook.h"
  30. #include "xlsxformat.h"
  31. #include "xlsxformat_p.h"
  32. #include "xlsxutility_p.h"
  33. #include "xlsxsharedstrings_p.h"
  34. #include "xlsxdrawing_p.h"
  35. #include "xlsxstyles_p.h"
  36. #include "xlsxcell.h"
  37. #include "xlsxcell_p.h"
  38. #include "xlsxcellrange.h"
  39. #include "xlsxconditionalformatting_p.h"
  40. #include "xlsxdrawinganchor_p.h"
  41. #include "xlsxchart.h"
  42. #include "xlsxcellformula.h"
  43. #include "xlsxcellformula_p.h"
  44. #include <QVariant>
  45. #include <QDateTime>
  46. #include <QPoint>
  47. #include <QFile>
  48. #include <QUrl>
  49. #include <QRegularExpression>
  50. #include <QDebug>
  51. #include <QBuffer>
  52. #include <QXmlStreamWriter>
  53. #include <QXmlStreamReader>
  54. #include <QTextDocument>
  55. #include <QDir>
  56. #include <math.h>
  57. QT_BEGIN_NAMESPACE_XLSX
  58. WorksheetPrivate::WorksheetPrivate(Worksheet *p, Worksheet::CreateFlag flag)
  59. : AbstractSheetPrivate(p, flag)
  60. , windowProtection(false), showFormulas(false), showGridLines(true), showRowColHeaders(true)
  61. , showZeros(true), rightToLeft(false), tabSelected(false), showRuler(false)
  62. , showOutlineSymbols(true), showWhiteSpace(true), urlPattern(QStringLiteral("^([fh]tt?ps?://)|(mailto:)|(file://)"))
  63. {
  64. previous_row = 0;
  65. outline_row_level = 0;
  66. outline_col_level = 0;
  67. default_row_height = 15;
  68. default_row_zeroed = false;
  69. }
  70. WorksheetPrivate::~WorksheetPrivate()
  71. {
  72. }
  73. /*
  74. Calculate the "spans" attribute of the <row> tag. This is an
  75. XLSX optimisation and isn't strictly required. However, it
  76. makes comparing files easier. The span is the same for each
  77. block of 16 rows.
  78. */
  79. void WorksheetPrivate::calculateSpans() const
  80. {
  81. row_spans.clear();
  82. int span_min = XLSX_COLUMN_MAX+1;
  83. int span_max = -1;
  84. for (int row_num = dimension.firstRow(); row_num <= dimension.lastRow(); row_num++) {
  85. if (cellTable.contains(row_num)) {
  86. for (int col_num = dimension.firstColumn(); col_num <= dimension.lastColumn(); col_num++) {
  87. if (cellTable[row_num].contains(col_num)) {
  88. if (span_max == -1) {
  89. span_min = col_num;
  90. span_max = col_num;
  91. } else {
  92. if (col_num < span_min)
  93. span_min = col_num;
  94. else if (col_num > span_max)
  95. span_max = col_num;
  96. }
  97. }
  98. }
  99. }
  100. if (comments.contains(row_num)) {
  101. for (int col_num = dimension.firstColumn(); col_num <= dimension.lastColumn(); col_num++) {
  102. if (comments[row_num].contains(col_num)) {
  103. if (span_max == -1) {
  104. span_min = col_num;
  105. span_max = col_num;
  106. } else {
  107. if (col_num < span_min)
  108. span_min = col_num;
  109. else if (col_num > span_max)
  110. span_max = col_num;
  111. }
  112. }
  113. }
  114. }
  115. if (row_num%16 == 0 || row_num == dimension.lastRow()) {
  116. if (span_max != -1) {
  117. row_spans[row_num / 16] = QStringLiteral("%1:%2").arg(span_min).arg(span_max);
  118. span_min = XLSX_COLUMN_MAX+1;
  119. span_max = -1;
  120. }
  121. }
  122. }
  123. }
  124. QString WorksheetPrivate::generateDimensionString() const
  125. {
  126. if (!dimension.isValid())
  127. return QStringLiteral("A1");
  128. else
  129. return dimension.toString();
  130. }
  131. /*
  132. Check that row and col are valid and store the max and min
  133. values for use in other methods/elements. The ignore_row /
  134. ignore_col flags is used to indicate that we wish to perform
  135. the dimension check without storing the value. The ignore
  136. flags are use by setRow() and dataValidate.
  137. */
  138. int WorksheetPrivate::checkDimensions(int row, int col, bool ignore_row, bool ignore_col)
  139. {
  140. Q_ASSERT_X(row!=0, "checkDimensions", "row should start from 1 instead of 0");
  141. Q_ASSERT_X(col!=0, "checkDimensions", "column should start from 1 instead of 0");
  142. if (row > XLSX_ROW_MAX || row < 1 || col > XLSX_COLUMN_MAX || col < 1)
  143. return -1;
  144. if (!ignore_row) {
  145. if (row < dimension.firstRow() || dimension.firstRow() == -1) dimension.setFirstRow(row);
  146. if (row > dimension.lastRow()) dimension.setLastRow(row);
  147. }
  148. if (!ignore_col) {
  149. if (col < dimension.firstColumn() || dimension.firstColumn() == -1) dimension.setFirstColumn(col);
  150. if (col > dimension.lastColumn()) dimension.setLastColumn(col);
  151. }
  152. return 0;
  153. }
  154. /*!
  155. \class Worksheet
  156. \inmodule QtXlsx
  157. \brief Represent one worksheet in the workbook.
  158. */
  159. /*!
  160. * \internal
  161. */
  162. Worksheet::Worksheet(const QString &name, int id, Workbook *workbook, CreateFlag flag)
  163. :AbstractSheet(name, id, workbook, new WorksheetPrivate(this, flag))
  164. {
  165. if (!workbook) //For unit test propose only. Ignore the memery leak.
  166. d_func()->workbook = new Workbook(flag);
  167. }
  168. /*!
  169. * \internal
  170. *
  171. * Make a copy of this sheet.
  172. */
  173. Worksheet *Worksheet::copy(const QString &distName, int distId) const
  174. {
  175. Q_D(const Worksheet);
  176. Worksheet *sheet = new Worksheet(distName, distId, d->workbook, F_NewFromScratch);
  177. WorksheetPrivate *sheet_d = sheet->d_func();
  178. sheet_d->dimension = d->dimension;
  179. QMapIterator<int, QMap<int, QSharedPointer<Cell> > > it(d->cellTable);
  180. while (it.hasNext()) {
  181. it.next();
  182. int row = it.key();
  183. QMapIterator<int, QSharedPointer<Cell> > it2(it.value());
  184. while (it2.hasNext()) {
  185. it2.next();
  186. int col = it2.key();
  187. QSharedPointer<Cell> cell(new Cell(it2.value().data()));
  188. cell->d_ptr->parent = sheet;
  189. if (cell->cellType() == Cell::SharedStringType)
  190. d->workbook->sharedStrings()->addSharedString(cell->d_ptr->richString);
  191. sheet_d->cellTable[row][col] = cell;
  192. }
  193. }
  194. sheet_d->merges = d->merges;
  195. // sheet_d->rowsInfo = d->rowsInfo;
  196. // sheet_d->colsInfo = d->colsInfo;
  197. // sheet_d->colsInfoHelper = d->colsInfoHelper;
  198. // sheet_d->dataValidationsList = d->dataValidationsList;
  199. // sheet_d->conditionalFormattingList = d->conditionalFormattingList;
  200. return sheet;
  201. }
  202. /*!
  203. * Destroys this workssheet.
  204. */
  205. Worksheet::~Worksheet()
  206. {
  207. }
  208. /*!
  209. * Returns whether sheet is protected.
  210. */
  211. bool Worksheet::isWindowProtected() const
  212. {
  213. Q_D(const Worksheet);
  214. return d->windowProtection;
  215. }
  216. /*!
  217. * Protects/unprotects the sheet based on \a protect.
  218. */
  219. void Worksheet::setWindowProtected(bool protect)
  220. {
  221. Q_D(Worksheet);
  222. d->windowProtection = protect;
  223. }
  224. /*!
  225. * Return whether formulas instead of their calculated results shown in cells
  226. */
  227. bool Worksheet::isFormulasVisible() const
  228. {
  229. Q_D(const Worksheet);
  230. return d->showFormulas;
  231. }
  232. /*!
  233. * Show formulas in cells instead of their calculated results when \a visible is true.
  234. */
  235. void Worksheet::setFormulasVisible(bool visible)
  236. {
  237. Q_D(Worksheet);
  238. d->showFormulas = visible;
  239. }
  240. /*!
  241. * Return whether gridlines is shown or not.
  242. */
  243. bool Worksheet::isGridLinesVisible() const
  244. {
  245. Q_D(const Worksheet);
  246. return d->showGridLines;
  247. }
  248. /*!
  249. * Show or hide the gridline based on \a visible
  250. */
  251. void Worksheet::setGridLinesVisible(bool visible)
  252. {
  253. Q_D(Worksheet);
  254. d->showGridLines = visible;
  255. }
  256. /*!
  257. * Return whether is row and column headers is vislbe.
  258. */
  259. bool Worksheet::isRowColumnHeadersVisible() const
  260. {
  261. Q_D(const Worksheet);
  262. return d->showRowColHeaders;
  263. }
  264. /*!
  265. * Show or hide the row column headers based on \a visible
  266. */
  267. void Worksheet::setRowColumnHeadersVisible(bool visible)
  268. {
  269. Q_D(Worksheet);
  270. d->showRowColHeaders = visible;
  271. }
  272. /*!
  273. * Return whether the sheet is shown right-to-left or not.
  274. */
  275. bool Worksheet::isRightToLeft() const
  276. {
  277. Q_D(const Worksheet);
  278. return d->rightToLeft;
  279. }
  280. /*!
  281. * Enable or disable the right-to-left based on \a enable.
  282. */
  283. void Worksheet::setRightToLeft(bool enable)
  284. {
  285. Q_D(Worksheet);
  286. d->rightToLeft = enable;
  287. }
  288. /*!
  289. * Return whether is cells that have zero value show a zero.
  290. */
  291. bool Worksheet::isZerosVisible() const
  292. {
  293. Q_D(const Worksheet);
  294. return d->showZeros;
  295. }
  296. /*!
  297. * Show a zero in cells that have zero value if \a visible is true.
  298. */
  299. void Worksheet::setZerosVisible(bool visible)
  300. {
  301. Q_D(Worksheet);
  302. d->showZeros = visible;
  303. }
  304. /*!
  305. * Return whether this tab is selected.
  306. */
  307. bool Worksheet::isSelected() const
  308. {
  309. Q_D(const Worksheet);
  310. return d->tabSelected;
  311. }
  312. /*!
  313. * Select this sheet if \a select is true.
  314. */
  315. void Worksheet::setSelected(bool select)
  316. {
  317. Q_D(Worksheet);
  318. d->tabSelected = select;
  319. }
  320. /*!
  321. * Return whether is ruler is shown.
  322. */
  323. bool Worksheet::isRulerVisible() const
  324. {
  325. Q_D(const Worksheet);
  326. return d->showRuler;
  327. }
  328. /*!
  329. * Show or hide the ruler based on \a visible.
  330. */
  331. void Worksheet::setRulerVisible(bool visible)
  332. {
  333. Q_D(Worksheet);
  334. d->showRuler = visible;
  335. }
  336. /*!
  337. * Return whether is outline symbols is shown.
  338. */
  339. bool Worksheet::isOutlineSymbolsVisible() const
  340. {
  341. Q_D(const Worksheet);
  342. return d->showOutlineSymbols;
  343. }
  344. /*!
  345. * Show or hide the outline symbols based ib \a visible.
  346. */
  347. void Worksheet::setOutlineSymbolsVisible(bool visible)
  348. {
  349. Q_D(Worksheet);
  350. d->showOutlineSymbols = visible;
  351. }
  352. /*!
  353. * Return whether is white space is shown.
  354. */
  355. bool Worksheet::isWhiteSpaceVisible() const
  356. {
  357. Q_D(const Worksheet);
  358. return d->showWhiteSpace;
  359. }
  360. /*!
  361. * Show or hide the white space based on \a visible.
  362. */
  363. void Worksheet::setWhiteSpaceVisible(bool visible)
  364. {
  365. Q_D(Worksheet);
  366. d->showWhiteSpace = visible;
  367. }
  368. /*!
  369. * Write \a value to cell (\a row, \a column) with the \a format.
  370. * Both \a row and \a column are all 1-indexed value.
  371. *
  372. * Returns true on success.
  373. */
  374. bool Worksheet::write(int row, int column, const QVariant &value, const Format &format)
  375. {
  376. Q_D(Worksheet);
  377. if (d->checkDimensions(row, column))
  378. return false;
  379. bool ret = true;
  380. if (value.isNull()) {
  381. //Blank
  382. ret = writeBlank(row, column, format);
  383. } else if (value.userType() == QMetaType::QString) {
  384. //String
  385. QString token = value.toString();
  386. bool ok;
  387. if (token.startsWith(QLatin1String("="))) {
  388. //convert to formula
  389. ret = writeFormula(row, column, CellFormula(token), format);
  390. } else if (d->workbook->isStringsToHyperlinksEnabled() && token.contains(d->urlPattern)) {
  391. //convert to url
  392. ret = writeHyperlink(row, column, QUrl(token));
  393. } else if (d->workbook->isStringsToNumbersEnabled() && (value.toDouble(&ok), ok)) {
  394. //Try convert string to number if the flag enabled.
  395. ret = writeString(row, column, value.toString(), format);
  396. } else {
  397. //normal string now
  398. ret = writeString(row, column, token, format);
  399. }
  400. } else if (value.userType() == qMetaTypeId<RichString>()) {
  401. ret = writeString(row, column, value.value<RichString>(), format);
  402. } else if (value.userType() == QMetaType::Int || value.userType() == QMetaType::UInt
  403. || value.userType() == QMetaType::LongLong || value.userType() == QMetaType::ULongLong
  404. || value.userType() == QMetaType::Double || value.userType() == QMetaType::Float) {
  405. //Number
  406. ret = writeNumeric(row, column, value.toDouble(), format);
  407. } else if (value.userType() == QMetaType::Bool) {
  408. //Bool
  409. ret = writeBool(row,column, value.toBool(), format);
  410. } else if (value.userType() == QMetaType::QDateTime || value.userType() == QMetaType::QDate) {
  411. //DateTime, Date
  412. // note that, QTime cann't convert to QDateTime
  413. ret = writeDateTime(row, column, value.toDateTime(), format);
  414. } else if (value.userType() == QMetaType::QTime) {
  415. //Time
  416. ret = writeTime(row, column, value.toTime(), format);
  417. } else if (value.userType() == QMetaType::QUrl) {
  418. //Url
  419. ret = writeHyperlink(row, column, value.toUrl(), format);
  420. } else {
  421. //Wrong type
  422. return false;
  423. }
  424. return ret;
  425. }
  426. /*!
  427. * \overload
  428. * Write \a value to cell \a row_column with the \a format.
  429. * Both row and column are all 1-indexed value.
  430. * Returns true on success.
  431. */
  432. bool Worksheet::write(const CellReference &row_column, const QVariant &value, const Format &format)
  433. {
  434. if (!row_column.isValid())
  435. return false;
  436. return write(row_column.row(), row_column.column(), value, format);
  437. }
  438. /*!
  439. \overload
  440. Return the contents of the cell \a row_column.
  441. */
  442. QVariant Worksheet::read(const CellReference &row_column) const
  443. {
  444. if (!row_column.isValid())
  445. return QVariant();
  446. return read(row_column.row(), row_column.column());
  447. }
  448. /*!
  449. Return the contents of the cell (\a row, \a column).
  450. */
  451. QVariant Worksheet::read(int row, int column) const
  452. {
  453. Q_D(const Worksheet);
  454. Cell *cell = cellAt(row, column);
  455. if (!cell)
  456. return QVariant();
  457. if (cell->hasFormula()) {
  458. if (cell->formula().formulaType() == CellFormula::NormalType) {
  459. return QVariant(QLatin1String("=")+cell->formula().formulaText());
  460. } else if (cell->formula().formulaType() == CellFormula::SharedType) {
  461. if (!cell->formula().formulaText().isEmpty()) {
  462. return QVariant(QLatin1String("=")+cell->formula().formulaText());
  463. } else {
  464. const CellFormula &rootFormula = d->sharedFormulaMap[cell->formula().sharedIndex()];
  465. CellReference rootCellRef = rootFormula.reference().topLeft();
  466. QString rootFormulaText = rootFormula.formulaText();
  467. QString newFormulaText = convertSharedFormula(rootFormulaText, rootCellRef, CellReference(row, column));
  468. return QVariant(QLatin1String("=")+newFormulaText);
  469. }
  470. }
  471. }
  472. if (cell->isDateTime()) {
  473. double val = cell->value().toDouble();
  474. QDateTime dt = cell->dateTime();
  475. if (val < 1)
  476. return dt.time();
  477. if (fmod(val, 1.0) < 1.0/(1000*60*60*24)) //integer
  478. return dt.date();
  479. return dt;
  480. }
  481. return cell->value();
  482. }
  483. /*!
  484. * Returns the cell at the given \a row_column. If there
  485. * is no cell at the specified position, the function returns 0.
  486. */
  487. Cell *Worksheet::cellAt(const CellReference &row_column) const
  488. {
  489. if (!row_column.isValid())
  490. return 0;
  491. return cellAt(row_column.row(), row_column.column());
  492. }
  493. /*!
  494. * Returns the cell at the given \a row and \a column. If there
  495. * is no cell at the specified position, the function returns 0.
  496. */
  497. Cell *Worksheet::cellAt(int row, int column) const
  498. {
  499. Q_D(const Worksheet);
  500. if (!d->cellTable.contains(row))
  501. return 0;
  502. if (!d->cellTable[row].contains(column))
  503. return 0;
  504. return d->cellTable[row][column].data();
  505. }
  506. Format WorksheetPrivate::cellFormat(int row, int col) const
  507. {
  508. if (!cellTable.contains(row))
  509. return Format();
  510. if (!cellTable[row].contains(col))
  511. return Format();
  512. return cellTable[row][col]->format();
  513. }
  514. /*!
  515. \overload
  516. Write string \a value to the cell \a row_column with the \a format.
  517. Returns true on success.
  518. */
  519. bool Worksheet::writeString(const CellReference &row_column, const RichString &value, const Format &format)
  520. {
  521. if (!row_column.isValid())
  522. return false;
  523. return writeString(row_column.row(), row_column.column(), value, format);
  524. }
  525. /*!
  526. Write string \a value to the cell (\a row, \a column) with the \a format.
  527. Returns true on success.
  528. */
  529. bool Worksheet::writeString(int row, int column, const RichString &value, const Format &format)
  530. {
  531. Q_D(Worksheet);
  532. // QString content = value.toPlainString();
  533. if (d->checkDimensions(row, column))
  534. return false;
  535. // if (content.size() > d->xls_strmax) {
  536. // content = content.left(d->xls_strmax);
  537. // error = -2;
  538. // }
  539. d->sharedStrings()->addSharedString(value);
  540. Format fmt = format.isValid() ? format : d->cellFormat(row, column);
  541. if (value.fragmentCount() == 1 && value.fragmentFormat(0).isValid())
  542. fmt.mergeFormat(value.fragmentFormat(0));
  543. d->workbook->styles()->addXfFormat(fmt);
  544. QSharedPointer<Cell> cell = QSharedPointer<Cell>(new Cell(value.toPlainString(), Cell::SharedStringType, fmt, this));
  545. cell->d_ptr->richString = value;
  546. d->cellTable[row][column] = cell;
  547. return true;
  548. }
  549. /*!
  550. \overload
  551. Write string \a value to the cell \a row_column with the \a format.
  552. */
  553. bool Worksheet::writeString(const CellReference &row_column, const QString &value, const Format &format)
  554. {
  555. if (!row_column.isValid())
  556. return false;
  557. return writeString(row_column.row(), row_column.column(), value, format);
  558. }
  559. /*!
  560. \overload
  561. Write string \a value to the cell (\a row, \a column) with the \a format.
  562. Returns true on success.
  563. */
  564. bool Worksheet::writeString(int row, int column, const QString &value, const Format &format)
  565. {
  566. Q_D(Worksheet);
  567. if (d->checkDimensions(row, column))
  568. return false;
  569. RichString rs;
  570. if (d->workbook->isHtmlToRichStringEnabled() && Qt::mightBeRichText(value))
  571. rs.setHtml(value);
  572. else
  573. rs.addFragment(value, Format());
  574. return writeString(row, column, rs, format);
  575. }
  576. /*!
  577. \overload
  578. Write string \a value to the cell \a row_column with the \a format
  579. */
  580. bool Worksheet::writeInlineString(const CellReference &row_column, const QString &value, const Format &format)
  581. {
  582. if (!row_column.isValid())
  583. return false;
  584. return writeInlineString(row_column.row(), row_column.column(), value, format);
  585. }
  586. /*!
  587. Write string \a value to the cell (\a row, \a column) with the \a format.
  588. Returns true on success.
  589. */
  590. bool Worksheet::writeInlineString(int row, int column, const QString &value, const Format &format)
  591. {
  592. Q_D(Worksheet);
  593. //int error = 0;
  594. QString content = value;
  595. if (d->checkDimensions(row, column))
  596. return false;
  597. if (value.size() > XLSX_STRING_MAX) {
  598. content = value.left(XLSX_STRING_MAX);
  599. //error = -2;
  600. }
  601. Format fmt = format.isValid() ? format : d->cellFormat(row, column);
  602. d->workbook->styles()->addXfFormat(fmt);
  603. d->cellTable[row][column] = QSharedPointer<Cell>(new Cell(value, Cell::InlineStringType, fmt, this));
  604. return true;
  605. }
  606. /*!
  607. \overload
  608. Write numeric \a value to the cell \a row_column with the \a format.
  609. Returns true on success.
  610. */
  611. bool Worksheet::writeNumeric(const CellReference &row_column, double value, const Format &format)
  612. {
  613. if (!row_column.isValid())
  614. return false;
  615. return writeNumeric(row_column.row(), row_column.column(), value, format);
  616. }
  617. /*!
  618. Write numeric \a value to the cell (\a row, \a column) with the \a format.
  619. Returns true on success.
  620. */
  621. bool Worksheet::writeNumeric(int row, int column, double value, const Format &format)
  622. {
  623. Q_D(Worksheet);
  624. if (d->checkDimensions(row, column))
  625. return false;
  626. Format fmt = format.isValid() ? format : d->cellFormat(row, column);
  627. d->workbook->styles()->addXfFormat(fmt);
  628. d->cellTable[row][column] = QSharedPointer<Cell>(new Cell(value, Cell::NumberType, fmt, this));
  629. return true;
  630. }
  631. /*!
  632. \overload
  633. Write \a formula to the cell \a row_column with the \a format and \a result.
  634. Returns true on success.
  635. */
  636. bool Worksheet::writeFormula(const CellReference &row_column, const CellFormula &formula, const Format &format, double result)
  637. {
  638. if (!row_column.isValid())
  639. return false;
  640. return writeFormula(row_column.row(), row_column.column(), formula, format, result);
  641. }
  642. /*!
  643. Write \a formula_ to the cell (\a row, \a column) with the \a format and \a result.
  644. Returns true on success.
  645. */
  646. bool Worksheet::writeFormula(int row, int column, const CellFormula &formula_, const Format &format, double result)
  647. {
  648. Q_D(Worksheet);
  649. if (d->checkDimensions(row, column))
  650. return false;
  651. Format fmt = format.isValid() ? format : d->cellFormat(row, column);
  652. d->workbook->styles()->addXfFormat(fmt);
  653. CellFormula formula = formula_;
  654. formula.d->ca = true;
  655. if (formula.formulaType() == CellFormula::SharedType) {
  656. //Assign proper shared index for shared formula
  657. int si=0;
  658. while(d->sharedFormulaMap.contains(si))
  659. ++si;
  660. formula.d->si = si;
  661. d->sharedFormulaMap[si] = formula;
  662. }
  663. QSharedPointer<Cell> data = QSharedPointer<Cell>(new Cell(result, Cell::NumberType, fmt, this));
  664. data->d_ptr->formula = formula;
  665. d->cellTable[row][column] = data;
  666. CellRange range = formula.reference();
  667. if (formula.formulaType() == CellFormula::SharedType) {
  668. CellFormula sf(QString(), CellFormula::SharedType);
  669. sf.d->si = formula.sharedIndex();
  670. for (int r=range.firstRow(); r<=range.lastRow(); ++r) {
  671. for (int c=range.firstColumn(); c<=range.lastColumn(); ++c) {
  672. if (!(r==row && c==column)) {
  673. if(Cell *cell = cellAt(r, c)) {
  674. cell->d_ptr->formula = sf;
  675. } else {
  676. QSharedPointer<Cell> newCell = QSharedPointer<Cell>(new Cell(result, Cell::NumberType, fmt, this));
  677. newCell->d_ptr->formula = sf;
  678. d->cellTable[r][c] = newCell;
  679. }
  680. }
  681. }
  682. }
  683. } else if (formula.formulaType() == CellFormula::SharedType) {
  684. }
  685. return true;
  686. }
  687. /*!
  688. \overload
  689. Write a empty cell \a row_column with the \a format.
  690. Returns true on success.
  691. */
  692. bool Worksheet::writeBlank(const CellReference &row_column, const Format &format)
  693. {
  694. if (!row_column.isValid())
  695. return false;
  696. return writeBlank(row_column.row(), row_column.column(), format);
  697. }
  698. /*!
  699. Write a empty cell (\a row, \a column) with the \a format.
  700. Returns true on success.
  701. */
  702. bool Worksheet::writeBlank(int row, int column, const Format &format)
  703. {
  704. Q_D(Worksheet);
  705. if (d->checkDimensions(row, column))
  706. return false;
  707. Format fmt = format.isValid() ? format : d->cellFormat(row, column);
  708. d->workbook->styles()->addXfFormat(fmt);
  709. //Note: NumberType with an invalid QVariant value means blank.
  710. d->cellTable[row][column] = QSharedPointer<Cell>(new Cell(QVariant(), Cell::NumberType, fmt, this));
  711. return true;
  712. }
  713. /*!
  714. \overload
  715. Write a bool \a value to the cell \a row_column with the \a format.
  716. Returns true on success.
  717. */
  718. bool Worksheet::writeBool(const CellReference &row_column, bool value, const Format &format)
  719. {
  720. if (!row_column.isValid())
  721. return false;
  722. return writeBool(row_column.row(), row_column.column(), value, format);
  723. }
  724. /*!
  725. Write a bool \a value to the cell (\a row, \a column) with the \a format.
  726. Returns true on success.
  727. */
  728. bool Worksheet::writeBool(int row, int column, bool value, const Format &format)
  729. {
  730. Q_D(Worksheet);
  731. if (d->checkDimensions(row, column))
  732. return false;
  733. Format fmt = format.isValid() ? format : d->cellFormat(row, column);
  734. d->workbook->styles()->addXfFormat(fmt);
  735. d->cellTable[row][column] = QSharedPointer<Cell>(new Cell(value, Cell::BooleanType, fmt, this));
  736. return true;
  737. }
  738. /*!
  739. \overload
  740. Write a QDateTime \a dt to the cell \a row_column with the \a format.
  741. Returns true on success.
  742. */
  743. bool Worksheet::writeDateTime(const CellReference &row_column, const QDateTime &dt, const Format &format)
  744. {
  745. if (!row_column.isValid())
  746. return false;
  747. return writeDateTime(row_column.row(), row_column.column(), dt, format);
  748. }
  749. /*!
  750. Write a QDateTime \a dt to the cell (\a row, \a column) with the \a format.
  751. Returns true on success.
  752. */
  753. bool Worksheet::writeDateTime(int row, int column, const QDateTime &dt, const Format &format)
  754. {
  755. Q_D(Worksheet);
  756. if (d->checkDimensions(row, column))
  757. return false;
  758. Format fmt = format.isValid() ? format : d->cellFormat(row, column);
  759. if (!fmt.isValid() || !fmt.isDateTimeFormat())
  760. fmt.setNumberFormat(d->workbook->defaultDateFormat());
  761. d->workbook->styles()->addXfFormat(fmt);
  762. double value = datetimeToNumber(dt, d->workbook->isDate1904());
  763. d->cellTable[row][column] = QSharedPointer<Cell>(new Cell(value, Cell::NumberType, fmt, this));
  764. return true;
  765. }
  766. /*!
  767. \overload
  768. Write a QTime \a t to the cell \a row_column with the \a format.
  769. Returns true on success.
  770. */
  771. bool Worksheet::writeTime(const CellReference &row_column, const QTime &t, const Format &format)
  772. {
  773. if (!row_column.isValid())
  774. return false;
  775. return writeTime(row_column.row(), row_column.column(), t, format);
  776. }
  777. /*!
  778. Write a QTime \a t to the cell (\a row, \a column) with the \a format.
  779. Returns true on success.
  780. */
  781. bool Worksheet::writeTime(int row, int column, const QTime &t, const Format &format)
  782. {
  783. Q_D(Worksheet);
  784. if (d->checkDimensions(row, column))
  785. return false;
  786. Format fmt = format.isValid() ? format : d->cellFormat(row, column);
  787. if (!fmt.isValid() || !fmt.isDateTimeFormat())
  788. fmt.setNumberFormat(QStringLiteral("hh:mm:ss"));
  789. d->workbook->styles()->addXfFormat(fmt);
  790. d->cellTable[row][column] = QSharedPointer<Cell>(new Cell(timeToNumber(t), Cell::NumberType, fmt, this));
  791. return true;
  792. }
  793. /*!
  794. \overload
  795. Write a QUrl \a url to the cell \a row_column with the given \a format \a display and \a tip.
  796. Returns true on success.
  797. */
  798. bool Worksheet::writeHyperlink(const CellReference &row_column, const QUrl &url, const Format &format, const QString &display, const QString &tip)
  799. {
  800. if (!row_column.isValid())
  801. return false;
  802. return writeHyperlink(row_column.row(), row_column.column(), url, format, display, tip);
  803. }
  804. /*!
  805. Write a QUrl \a url to the cell (\a row, \a column) with the given \a format \a display and \a tip.
  806. Returns true on success.
  807. */
  808. bool Worksheet::writeHyperlink(int row, int column, const QUrl &url, const Format &format, const QString &display, const QString &tip)
  809. {
  810. Q_D(Worksheet);
  811. if (d->checkDimensions(row, column))
  812. return false;
  813. //int error = 0;
  814. QString urlString = url.toString();
  815. //Generate proper display string
  816. QString displayString = display.isEmpty() ? urlString : display;
  817. if (displayString.startsWith(QLatin1String("mailto:")))
  818. displayString.replace(QLatin1String("mailto:"), QString());
  819. if (displayString.size() > XLSX_STRING_MAX) {
  820. displayString = displayString.left(XLSX_STRING_MAX);
  821. //error = -2;
  822. }
  823. /*
  824. Location within target. If target is a workbook (or this workbook)
  825. this shall refer to a sheet and cell or a defined name. Can also
  826. be an HTML anchor if target is HTML file.
  827. c:\temp\file.xlsx#Sheet!A1
  828. http://a.com/aaa.html#aaaaa
  829. */
  830. QString locationString;
  831. if (url.hasFragment()) {
  832. locationString = url.fragment();
  833. urlString = url.toString(QUrl::RemoveFragment);
  834. }
  835. Format fmt = format.isValid() ? format : d->cellFormat(row, column);
  836. //Given a default style for hyperlink
  837. if (!fmt.isValid()) {
  838. fmt.setFontColor(Qt::blue);
  839. fmt.setFontUnderline(Format::FontUnderlineSingle);
  840. }
  841. d->workbook->styles()->addXfFormat(fmt);
  842. //Write the hyperlink string as normal string.
  843. d->sharedStrings()->addSharedString(displayString);
  844. d->cellTable[row][column] = QSharedPointer<Cell>(new Cell(displayString, Cell::SharedStringType, fmt, this));
  845. //Store the hyperlink data in a separate table
  846. d->urlTable[row][column] = QSharedPointer<XlsxHyperlinkData>(new XlsxHyperlinkData(XlsxHyperlinkData::External, urlString, locationString, QString(), tip));
  847. return true;
  848. }
  849. /*!
  850. * Add one DataValidation \a validation to the sheet.
  851. * Returns true on success.
  852. */
  853. bool Worksheet::addDataValidation(const DataValidation &validation)
  854. {
  855. Q_D(Worksheet);
  856. if (validation.ranges().isEmpty() || validation.validationType()==DataValidation::None)
  857. return false;
  858. d->dataValidationsList.append(validation);
  859. return true;
  860. }
  861. /*!
  862. * Add one ConditionalFormatting \a cf to the sheet.
  863. * Returns true on success.
  864. */
  865. bool Worksheet::addConditionalFormatting(const ConditionalFormatting &cf)
  866. {
  867. Q_D(Worksheet);
  868. if (cf.ranges().isEmpty())
  869. return false;
  870. for (int i=0; i<cf.d->cfRules.size(); ++i) {
  871. const QSharedPointer<XlsxCfRuleData> &rule = cf.d->cfRules[i];
  872. if (!rule->dxfFormat.isEmpty())
  873. d->workbook->styles()->addDxfFormat(rule->dxfFormat);
  874. rule->priority = 1;
  875. }
  876. d->conditionalFormattingList.append(cf);
  877. return true;
  878. }
  879. /*!
  880. * Insert an \a image at the position \a row, \a column
  881. * Returns true on success.
  882. */
  883. bool Worksheet::insertImage(int row, int column, const QImage &image)
  884. {
  885. Q_D(Worksheet);
  886. if (image.isNull())
  887. return false;
  888. if (!d->drawing)
  889. d->drawing = QSharedPointer<Drawing>(new Drawing(this, F_NewFromScratch));
  890. DrawingOneCellAnchor *anchor = new DrawingOneCellAnchor(d->drawing.data(), DrawingAnchor::Picture);
  891. /*
  892. The size are expressed as English Metric Units (EMUs). There are
  893. 12,700 EMUs per point. Therefore, 12,700 * 3 /4 = 9,525 EMUs per
  894. pixel
  895. */
  896. anchor->from = XlsxMarker(row, column, 0, 0);
  897. anchor->ext = QSize(image.width() * 9525, image.height() * 9525);
  898. anchor->setObjectPicture(image);
  899. return true;
  900. }
  901. /*!
  902. * Creates an chart with the given \a size and insert
  903. * at the position \a row, \a column.
  904. * The chart will be returned.
  905. */
  906. Chart *Worksheet::insertChart(int row, int column, const QSize &size)
  907. {
  908. Q_D(Worksheet);
  909. if (!d->drawing)
  910. d->drawing = QSharedPointer<Drawing>(new Drawing(this, F_NewFromScratch));
  911. DrawingOneCellAnchor *anchor = new DrawingOneCellAnchor(d->drawing.data(), DrawingAnchor::Picture);
  912. /*
  913. The size are expressed as English Metric Units (EMUs). There are
  914. 12,700 EMUs per point. Therefore, 12,700 * 3 /4 = 9,525 EMUs per
  915. pixel
  916. */
  917. anchor->from = XlsxMarker(row, column, 0, 0);
  918. anchor->ext = size * 9525;
  919. QSharedPointer<Chart> chart = QSharedPointer<Chart>(new Chart(this, F_NewFromScratch));
  920. anchor->setObjectGraphicFrame(chart);
  921. return chart.data();
  922. }
  923. /*!
  924. Merge a \a range of cells. The first cell should contain the data and the others should
  925. be blank. All cells will be applied the same style if a valid \a format is given.
  926. Returns true on success.
  927. \note All cells except the top-left one will be cleared.
  928. */
  929. bool Worksheet::mergeCells(const CellRange &range, const Format &format)
  930. {
  931. Q_D(Worksheet);
  932. if (range.rowCount() < 2 && range.columnCount() < 2)
  933. return false;
  934. if (d->checkDimensions(range.firstRow(), range.firstColumn()))
  935. return false;
  936. if (format.isValid())
  937. d->workbook->styles()->addXfFormat(format);
  938. for (int row = range.firstRow(); row <= range.lastRow(); ++row) {
  939. for (int col = range.firstColumn(); col <= range.lastColumn(); ++col) {
  940. if (row == range.firstRow() && col == range.firstColumn()) {
  941. Cell *cell = cellAt(row, col);
  942. if (cell) {
  943. if (format.isValid())
  944. cell->d_ptr->format = format;
  945. } else {
  946. writeBlank(row, col, format);
  947. }
  948. } else {
  949. writeBlank(row, col, format);
  950. }
  951. }
  952. }
  953. d->merges.append(range);
  954. return true;
  955. }
  956. /*!
  957. Unmerge the cells in the \a range. Returns true on success.
  958. */
  959. bool Worksheet::unmergeCells(const CellRange &range)
  960. {
  961. Q_D(Worksheet);
  962. if (!d->merges.contains(range))
  963. return false;
  964. d->merges.removeOne(range);
  965. return true;
  966. }
  967. /*!
  968. Returns all the merged cells.
  969. */
  970. QList<CellRange> Worksheet::mergedCells() const
  971. {
  972. Q_D(const Worksheet);
  973. return d->merges;
  974. }
  975. /*!
  976. * \internal
  977. */
  978. void Worksheet::saveToXmlFile(QIODevice *device) const
  979. {
  980. Q_D(const Worksheet);
  981. d->relationships->clear();
  982. QXmlStreamWriter writer(device);
  983. writer.writeStartDocument(QStringLiteral("1.0"), true);
  984. writer.writeStartElement(QStringLiteral("worksheet"));
  985. writer.writeAttribute(QStringLiteral("xmlns"), QStringLiteral("http://schemas.openxmlformats.org/spreadsheetml/2006/main"));
  986. writer.writeAttribute(QStringLiteral("xmlns:r"), QStringLiteral("http://schemas.openxmlformats.org/officeDocument/2006/relationships"));
  987. //for Excel 2010
  988. // writer.writeAttribute("xmlns:mc", "http://schemas.openxmlformats.org/markup-compatibility/2006");
  989. // writer.writeAttribute("xmlns:x14ac", "http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac");
  990. // writer.writeAttribute("mc:Ignorable", "x14ac");
  991. writer.writeStartElement(QStringLiteral("dimension"));
  992. writer.writeAttribute(QStringLiteral("ref"), d->generateDimensionString());
  993. writer.writeEndElement();//dimension
  994. writer.writeStartElement(QStringLiteral("sheetViews"));
  995. writer.writeStartElement(QStringLiteral("sheetView"));
  996. if (d->windowProtection)
  997. writer.writeAttribute(QStringLiteral("windowProtection"), QStringLiteral("1"));
  998. if (d->showFormulas)
  999. writer.writeAttribute(QStringLiteral("showFormulas"), QStringLiteral("1"));
  1000. if (!d->showGridLines)
  1001. writer.writeAttribute(QStringLiteral("showGridLines"), QStringLiteral("0"));
  1002. if (!d->showRowColHeaders)
  1003. writer.writeAttribute(QStringLiteral("showRowColHeaders"), QStringLiteral("0"));
  1004. if (!d->showZeros)
  1005. writer.writeAttribute(QStringLiteral("showZeros"), QStringLiteral("0"));
  1006. if (d->rightToLeft)
  1007. writer.writeAttribute(QStringLiteral("rightToLeft"), QStringLiteral("1"));
  1008. if (d->tabSelected)
  1009. writer.writeAttribute(QStringLiteral("tabSelected"), QStringLiteral("1"));
  1010. if (!d->showRuler)
  1011. writer.writeAttribute(QStringLiteral("showRuler"), QStringLiteral("0"));
  1012. if (!d->showOutlineSymbols)
  1013. writer.writeAttribute(QStringLiteral("showOutlineSymbols"), QStringLiteral("0"));
  1014. if (!d->showWhiteSpace)
  1015. writer.writeAttribute(QStringLiteral("showWhiteSpace"), QStringLiteral("0"));
  1016. writer.writeAttribute(QStringLiteral("workbookViewId"), QStringLiteral("0"));
  1017. writer.writeEndElement();//sheetView
  1018. writer.writeEndElement();//sheetViews
  1019. writer.writeStartElement(QStringLiteral("sheetFormatPr"));
  1020. writer.writeAttribute(QStringLiteral("defaultRowHeight"), QString::number(d->default_row_height));
  1021. if (d->default_row_height != 15)
  1022. writer.writeAttribute(QStringLiteral("customHeight"), QStringLiteral("1"));
  1023. if (d->default_row_zeroed)
  1024. writer.writeAttribute(QStringLiteral("zeroHeight"), QStringLiteral("1"));
  1025. if (d->outline_row_level)
  1026. writer.writeAttribute(QStringLiteral("outlineLevelRow"), QString::number(d->outline_row_level));
  1027. if (d->outline_col_level)
  1028. writer.writeAttribute(QStringLiteral("outlineLevelCol"), QString::number(d->outline_col_level));
  1029. //for Excel 2010
  1030. // writer.writeAttribute("x14ac:dyDescent", "0.25");
  1031. writer.writeEndElement();//sheetFormatPr
  1032. if (!d->colsInfo.isEmpty()) {
  1033. writer.writeStartElement(QStringLiteral("cols"));
  1034. QMapIterator<int, QSharedPointer<XlsxColumnInfo> > it(d->colsInfo);
  1035. while (it.hasNext()) {
  1036. it.next();
  1037. QSharedPointer<XlsxColumnInfo> col_info = it.value();
  1038. writer.writeStartElement(QStringLiteral("col"));
  1039. writer.writeAttribute(QStringLiteral("min"), QString::number(col_info->firstColumn));
  1040. writer.writeAttribute(QStringLiteral("max"), QString::number(col_info->lastColumn));
  1041. if (col_info->width)
  1042. writer.writeAttribute(QStringLiteral("width"), QString::number(col_info->width, 'g', 15));
  1043. if (!col_info->format.isEmpty())
  1044. writer.writeAttribute(QStringLiteral("style"), QString::number(col_info->format.xfIndex()));
  1045. if (col_info->hidden)
  1046. writer.writeAttribute(QStringLiteral("hidden"), QStringLiteral("1"));
  1047. if (col_info->width)
  1048. writer.writeAttribute(QStringLiteral("customWidth"), QStringLiteral("1"));
  1049. if (col_info->outlineLevel)
  1050. writer.writeAttribute(QStringLiteral("outlineLevel"), QString::number(col_info->outlineLevel));
  1051. if (col_info->collapsed)
  1052. writer.writeAttribute(QStringLiteral("collapsed"), QStringLiteral("1"));
  1053. writer.writeEndElement();//col
  1054. }
  1055. writer.writeEndElement();//cols
  1056. }
  1057. writer.writeStartElement(QStringLiteral("sheetData"));
  1058. if (d->dimension.isValid())
  1059. d->saveXmlSheetData(writer);
  1060. writer.writeEndElement();//sheetData
  1061. d->saveXmlMergeCells(writer);
  1062. foreach (const ConditionalFormatting cf, d->conditionalFormattingList)
  1063. cf.saveToXml(writer);
  1064. d->saveXmlDataValidations(writer);
  1065. d->saveXmlHyperlinks(writer);
  1066. d->saveXmlDrawings(writer);
  1067. writer.writeEndElement();//worksheet
  1068. writer.writeEndDocument();
  1069. }
  1070. void WorksheetPrivate::saveXmlSheetData(QXmlStreamWriter &writer) const
  1071. {
  1072. calculateSpans();
  1073. for (int row_num = dimension.firstRow(); row_num <= dimension.lastRow(); row_num++) {
  1074. if (!(cellTable.contains(row_num) || comments.contains(row_num) || rowsInfo.contains(row_num))) {
  1075. //Only process rows with cell data / comments / formatting
  1076. continue;
  1077. }
  1078. int span_index = (row_num-1) / 16;
  1079. QString span;
  1080. if (row_spans.contains(span_index))
  1081. span = row_spans[span_index];
  1082. writer.writeStartElement(QStringLiteral("row"));
  1083. writer.writeAttribute(QStringLiteral("r"), QString::number(row_num));
  1084. if (!span.isEmpty())
  1085. writer.writeAttribute(QStringLiteral("spans"), span);
  1086. if (rowsInfo.contains(row_num)) {
  1087. QSharedPointer<XlsxRowInfo> rowInfo = rowsInfo[row_num];
  1088. if (!rowInfo->format.isEmpty()) {
  1089. writer.writeAttribute(QStringLiteral("s"), QString::number(rowInfo->format.xfIndex()));
  1090. writer.writeAttribute(QStringLiteral("customFormat"), QStringLiteral("1"));
  1091. }
  1092. //!Todo: support customHeight from info struct
  1093. //!Todo: where does this magic number '15' come from?
  1094. if (rowInfo->customHeight) {
  1095. writer.writeAttribute(QStringLiteral("ht"), QString::number(rowInfo->height));
  1096. writer.writeAttribute(QStringLiteral("customHeight"), QStringLiteral("1"));
  1097. } else {
  1098. writer.writeAttribute(QStringLiteral("customHeight"), QStringLiteral("0"));
  1099. }
  1100. if (rowInfo->hidden)
  1101. writer.writeAttribute(QStringLiteral("hidden"), QStringLiteral("1"));
  1102. if (rowInfo->outlineLevel > 0)
  1103. writer.writeAttribute(QStringLiteral("outlineLevel"), QString::number(rowInfo->outlineLevel));
  1104. if (rowInfo->collapsed)
  1105. writer.writeAttribute(QStringLiteral("collapsed"), QStringLiteral("1"));
  1106. }
  1107. //Write cell data if row contains filled cells
  1108. if (cellTable.contains(row_num)) {
  1109. for (int col_num = dimension.firstColumn(); col_num <= dimension.lastColumn(); col_num++) {
  1110. if (cellTable[row_num].contains(col_num)) {
  1111. saveXmlCellData(writer, row_num, col_num, cellTable[row_num][col_num]);
  1112. }
  1113. }
  1114. }
  1115. writer.writeEndElement(); //row
  1116. }
  1117. }
  1118. void WorksheetPrivate::saveXmlCellData(QXmlStreamWriter &writer, int row, int col, QSharedPointer<Cell> cell) const
  1119. {
  1120. //This is the innermost loop so efficiency is important.
  1121. QString cell_pos = CellReference(row, col).toString();
  1122. writer.writeStartElement(QStringLiteral("c"));
  1123. writer.writeAttribute(QStringLiteral("r"), cell_pos);
  1124. //Style used by the cell, row or col
  1125. if (!cell->format().isEmpty())
  1126. writer.writeAttribute(QStringLiteral("s"), QString::number(cell->format().xfIndex()));
  1127. else if (rowsInfo.contains(row) && !rowsInfo[row]->format.isEmpty())
  1128. writer.writeAttribute(QStringLiteral("s"), QString::number(rowsInfo[row]->format.xfIndex()));
  1129. else if (colsInfoHelper.contains(col) && !colsInfoHelper[col]->format.isEmpty())
  1130. writer.writeAttribute(QStringLiteral("s"), QString::number(colsInfoHelper[col]->format.xfIndex()));
  1131. if (cell->cellType() == Cell::SharedStringType) {
  1132. int sst_idx;
  1133. if (cell->isRichString())
  1134. sst_idx = sharedStrings()->getSharedStringIndex(cell->d_ptr->richString);
  1135. else
  1136. sst_idx = sharedStrings()->getSharedStringIndex(cell->value().toString());
  1137. writer.writeAttribute(QStringLiteral("t"), QStringLiteral("s"));
  1138. writer.writeTextElement(QStringLiteral("v"), QString::number(sst_idx));
  1139. } else if (cell->cellType() == Cell::InlineStringType) {
  1140. writer.writeAttribute(QStringLiteral("t"), QStringLiteral("inlineStr"));
  1141. writer.writeStartElement(QStringLiteral("is"));
  1142. if (cell->isRichString()) {
  1143. //Rich text string
  1144. RichString string = cell->d_ptr->richString;
  1145. for (int i=0; i<string.fragmentCount(); ++i) {
  1146. writer.writeStartElement(QStringLiteral("r"));
  1147. if (string.fragmentFormat(i).hasFontData()) {
  1148. writer.writeStartElement(QStringLiteral("rPr"));
  1149. //:Todo
  1150. writer.writeEndElement();// rPr
  1151. }
  1152. writer.writeStartElement(QStringLiteral("t"));
  1153. if (isSpaceReserveNeeded(string.fragmentText(i)))
  1154. writer.writeAttribute(QStringLiteral("xml:space"), QStringLiteral("preserve"));
  1155. writer.writeCharacters(string.fragmentText(i));
  1156. writer.writeEndElement();// t
  1157. writer.writeEndElement(); // r
  1158. }
  1159. } else {
  1160. writer.writeStartElement(QStringLiteral("t"));
  1161. QString string = cell->value().toString();
  1162. if (isSpaceReserveNeeded(string))
  1163. writer.writeAttribute(QStringLiteral("xml:space"), QStringLiteral("preserve"));
  1164. writer.writeCharacters(string);
  1165. writer.writeEndElement(); // t
  1166. }
  1167. writer.writeEndElement();//is
  1168. } else if (cell->cellType() == Cell::NumberType){
  1169. if (cell->hasFormula())
  1170. cell->formula().saveToXml(writer);
  1171. if (cell->value().isValid()) {//note that, invalid value means 'v' is blank
  1172. double value = cell->value().toDouble();
  1173. writer.writeTextElement(QStringLiteral("v"), QString::number(value, 'g', 15));
  1174. }
  1175. } else if (cell->cellType() == Cell::StringType) {
  1176. writer.writeAttribute(QStringLiteral("t"), QStringLiteral("str"));
  1177. if (cell->hasFormula())
  1178. cell->formula().saveToXml(writer);
  1179. writer.writeTextElement(QStringLiteral("v"), cell->value().toString());
  1180. } else if (cell->cellType() == Cell::BooleanType) {
  1181. writer.writeAttribute(QStringLiteral("t"), QStringLiteral("b"));
  1182. writer.writeTextElement(QStringLiteral("v"), cell->value().toBool() ? QStringLiteral("1") : QStringLiteral("0"));
  1183. }
  1184. writer.writeEndElement(); //c
  1185. }
  1186. void WorksheetPrivate::saveXmlMergeCells(QXmlStreamWriter &writer) const
  1187. {
  1188. if (merges.isEmpty())
  1189. return;
  1190. writer.writeStartElement(QStringLiteral("mergeCells"));
  1191. writer.writeAttribute(QStringLiteral("count"), QString::number(merges.size()));
  1192. foreach (CellRange range, merges) {
  1193. writer.writeEmptyElement(QStringLiteral("mergeCell"));
  1194. writer.writeAttribute(QStringLiteral("ref"), range.toString());
  1195. }
  1196. writer.writeEndElement(); //mergeCells
  1197. }
  1198. void WorksheetPrivate::saveXmlDataValidations(QXmlStreamWriter &writer) const
  1199. {
  1200. if (dataValidationsList.isEmpty())
  1201. return;
  1202. writer.writeStartElement(QStringLiteral("dataValidations"));
  1203. writer.writeAttribute(QStringLiteral("count"), QString::number(dataValidationsList.size()));
  1204. foreach (DataValidation validation, dataValidationsList)
  1205. validation.saveToXml(writer);
  1206. writer.writeEndElement(); //dataValidations
  1207. }
  1208. void WorksheetPrivate::saveXmlHyperlinks(QXmlStreamWriter &writer) const
  1209. {
  1210. if (urlTable.isEmpty())
  1211. return;
  1212. writer.writeStartElement(QStringLiteral("hyperlinks"));
  1213. QMapIterator<int, QMap<int, QSharedPointer<XlsxHyperlinkData> > > it(urlTable);
  1214. while (it.hasNext()) {
  1215. it.next();
  1216. int row = it.key();
  1217. QMapIterator <int, QSharedPointer<XlsxHyperlinkData> > it2(it.value());
  1218. while (it2.hasNext()) {
  1219. it2.next();
  1220. int col = it2.key();
  1221. QSharedPointer<XlsxHyperlinkData> data = it2.value();
  1222. QString ref = CellReference(row, col).toString();
  1223. writer.writeEmptyElement(QStringLiteral("hyperlink"));
  1224. writer.writeAttribute(QStringLiteral("ref"), ref);
  1225. if (data->linkType == XlsxHyperlinkData::External) {
  1226. //Update relationships
  1227. relationships->addWorksheetRelationship(QStringLiteral("/hyperlink"), data->target, QStringLiteral("External"));
  1228. writer.writeAttribute(QStringLiteral("r:id"), QStringLiteral("rId%1").arg(relationships->count()));
  1229. }
  1230. if (!data->location.isEmpty())
  1231. writer.writeAttribute(QStringLiteral("location"), data->location);
  1232. if (!data->display.isEmpty())
  1233. writer.writeAttribute(QStringLiteral("display"), data->display);
  1234. if (!data->tooltip.isEmpty())
  1235. writer.writeAttribute(QStringLiteral("tooltip"), data->tooltip);
  1236. }
  1237. }
  1238. writer.writeEndElement();//hyperlinks
  1239. }
  1240. void WorksheetPrivate::saveXmlDrawings(QXmlStreamWriter &writer) const
  1241. {
  1242. if (!drawing)
  1243. return;
  1244. int idx = workbook->drawings().indexOf(drawing.data());
  1245. relationships->addWorksheetRelationship(QStringLiteral("/drawing"), QStringLiteral("../drawings/drawing%1.xml").arg(idx+1));
  1246. writer.writeEmptyElement(QStringLiteral("drawing"));
  1247. writer.writeAttribute(QStringLiteral("r:id"), QStringLiteral("rId%1").arg(relationships->count()));
  1248. }
  1249. void WorksheetPrivate::splitColsInfo(int colFirst, int colLast)
  1250. {
  1251. // Split current columnInfo, for example, if "A:H" has been set,
  1252. // we are trying to set "B:D", there should be "A", "B:D", "E:H".
  1253. // This will be more complex if we try to set "C:F" after "B:D".
  1254. {
  1255. QMapIterator<int, QSharedPointer<XlsxColumnInfo> > it(colsInfo);
  1256. while (it.hasNext()) {
  1257. it.next();
  1258. QSharedPointer<XlsxColumnInfo> info = it.value();
  1259. if (colFirst > info->firstColumn && colFirst <= info->lastColumn) {
  1260. //split the range,
  1261. QSharedPointer<XlsxColumnInfo> info2(new XlsxColumnInfo(*info));
  1262. info->lastColumn = colFirst - 1;
  1263. info2->firstColumn = colFirst;
  1264. colsInfo.insert(colFirst, info2);
  1265. for (int c = info2->firstColumn; c <= info2->lastColumn; ++c)
  1266. colsInfoHelper[c] = info2;
  1267. break;
  1268. }
  1269. }
  1270. }
  1271. {
  1272. QMapIterator<int, QSharedPointer<XlsxColumnInfo> > it(colsInfo);
  1273. while (it.hasNext()) {
  1274. it.next();
  1275. QSharedPointer<XlsxColumnInfo> info = it.value();
  1276. if (colLast >= info->firstColumn && colLast < info->lastColumn) {
  1277. QSharedPointer<XlsxColumnInfo> info2(new XlsxColumnInfo(*info));
  1278. info->lastColumn = colLast;
  1279. info2->firstColumn = colLast + 1;
  1280. colsInfo.insert(colLast + 1, info2);
  1281. for (int c = info2->firstColumn; c <= info2->lastColumn; ++c)
  1282. colsInfoHelper[c] = info2;
  1283. break;
  1284. }
  1285. }
  1286. }
  1287. }
  1288. bool WorksheetPrivate::isColumnRangeValid(int colFirst, int colLast)
  1289. {
  1290. bool ignore_row = true;
  1291. bool ignore_col = false;
  1292. if (colFirst > colLast)
  1293. return false;
  1294. if (checkDimensions(1, colLast, ignore_row, ignore_col))
  1295. return false;
  1296. if (checkDimensions(1, colFirst, ignore_row, ignore_col))
  1297. return false;
  1298. return true;
  1299. }
  1300. QList<int> WorksheetPrivate ::getColumnIndexes(int colFirst, int colLast)
  1301. {
  1302. splitColsInfo(colFirst, colLast);
  1303. QList<int> nodes;
  1304. nodes.append(colFirst);
  1305. for (int col = colFirst; col <= colLast; ++col) {
  1306. if (colsInfo.contains(col)) {
  1307. if (nodes.last() != col)
  1308. nodes.append(col);
  1309. int nextCol = colsInfo[col]->lastColumn + 1;
  1310. if (nextCol <= colLast)
  1311. nodes.append(nextCol);
  1312. }
  1313. }
  1314. return nodes;
  1315. }
  1316. /*!
  1317. Sets width in characters of a \a range of columns to \a width.
  1318. Returns true on success.
  1319. */
  1320. bool Worksheet::setColumnWidth(const CellRange &range, double width)
  1321. {
  1322. if (!range.isValid())
  1323. return false;
  1324. return setColumnWidth(range.firstColumn(), range.lastColumn(), width);
  1325. }
  1326. /*!
  1327. Sets format property of a \a range of columns to \a format. Columns are 1-indexed.
  1328. Returns true on success.
  1329. */
  1330. bool Worksheet::setColumnFormat(const CellRange& range, const Format &format)
  1331. {
  1332. if (!range.isValid())
  1333. return false;
  1334. return setColumnFormat(range.firstColumn(), range.lastColumn(), format);
  1335. }
  1336. /*!
  1337. Sets hidden property of a \a range of columns to \a hidden. Columns are 1-indexed.
  1338. Hidden columns are not visible.
  1339. Returns true on success.
  1340. */
  1341. bool Worksheet::setColumnHidden(const CellRange &range, bool hidden)
  1342. {
  1343. if (!range.isValid())
  1344. return false;
  1345. return setColumnHidden(range.firstColumn(), range.lastColumn(), hidden);
  1346. }
  1347. /*!
  1348. Sets width in characters for columns [\a colFirst, \a colLast] to \a width.
  1349. Columns are 1-indexed.
  1350. Returns true on success.
  1351. */
  1352. bool Worksheet::setColumnWidth(int colFirst, int colLast, double width)
  1353. {
  1354. Q_D(Worksheet);
  1355. QList <QSharedPointer<XlsxColumnInfo> > columnInfoList = d->getColumnInfoList(colFirst, colLast);
  1356. foreach(QSharedPointer<XlsxColumnInfo> columnInfo, columnInfoList)
  1357. columnInfo->width = width;
  1358. return (columnInfoList.count() > 0);
  1359. }
  1360. /*!
  1361. Sets format property of a range of columns [\a colFirst, \a colLast] to \a format.
  1362. Columns are 1-indexed.
  1363. Returns true on success.
  1364. */
  1365. bool Worksheet::setColumnFormat(int colFirst, int colLast, const Format &format)
  1366. {
  1367. Q_D(Worksheet);
  1368. QList <QSharedPointer<XlsxColumnInfo> > columnInfoList = d->getColumnInfoList(colFirst, colLast);
  1369. foreach(QSharedPointer<XlsxColumnInfo> columnInfo, columnInfoList)
  1370. columnInfo->format = format;
  1371. if(columnInfoList.count() > 0) {
  1372. d->workbook->styles()->addXfFormat(format);
  1373. return true;
  1374. }
  1375. return false;
  1376. }
  1377. /*!
  1378. Sets hidden property of a range of columns [\a colFirst, \a colLast] to \a hidden.
  1379. Columns are 1-indexed. Returns true on success.
  1380. */
  1381. bool Worksheet::setColumnHidden(int colFirst, int colLast, bool hidden)
  1382. {
  1383. Q_D(Worksheet);
  1384. QList <QSharedPointer<XlsxColumnInfo> > columnInfoList = d->getColumnInfoList(colFirst, colLast);
  1385. foreach(QSharedPointer<XlsxColumnInfo> columnInfo, columnInfoList)
  1386. columnInfo->hidden = hidden;
  1387. return (columnInfoList.count() > 0);
  1388. }
  1389. /*!
  1390. Returns width of the \a column in characters of the normal font. Columns are 1-indexed.
  1391. */
  1392. double Worksheet::columnWidth(int column)
  1393. {
  1394. Q_D(Worksheet);
  1395. QList <QSharedPointer<XlsxColumnInfo> > columnInfoList = d->getColumnInfoList(column, column);
  1396. if (columnInfoList.count() == 1)
  1397. return columnInfoList.at(0)->width ;
  1398. return d->sheetFormatProps.defaultColWidth;
  1399. }
  1400. /*!
  1401. Returns formatting of the \a column. Columns are 1-indexed.
  1402. */
  1403. Format Worksheet::columnFormat(int column)
  1404. {
  1405. Q_D(Worksheet);
  1406. QList <QSharedPointer<XlsxColumnInfo> > columnInfoList = d->getColumnInfoList(column, column);
  1407. if (columnInfoList.count() == 1)
  1408. return columnInfoList.at(0)->format;
  1409. return Format();
  1410. }
  1411. /*!
  1412. Returns true if \a column is hidden. Columns are 1-indexed.
  1413. */
  1414. bool Worksheet::isColumnHidden(int column)
  1415. {
  1416. Q_D(Worksheet);
  1417. QList <QSharedPointer<XlsxColumnInfo> > columnInfoList = d->getColumnInfoList(column, column);
  1418. if (columnInfoList.count() == 1)
  1419. return columnInfoList.at(0)->hidden;
  1420. return false;
  1421. }
  1422. /*!
  1423. Sets the \a height of the rows including and between \a rowFirst and \a rowLast.
  1424. Row height measured in point size.
  1425. Rows are 1-indexed.
  1426. Returns true if success.
  1427. */
  1428. bool Worksheet::setRowHeight(int rowFirst,int rowLast, double height)
  1429. {
  1430. Q_D(Worksheet);
  1431. QList <QSharedPointer<XlsxRowInfo> > rowInfoList = d->getRowInfoList(rowFirst,rowLast);
  1432. foreach(QSharedPointer<XlsxRowInfo> rowInfo, rowInfoList) {
  1433. rowInfo->height = height;
  1434. rowInfo->customHeight = true;
  1435. }
  1436. return rowInfoList.count() > 0;
  1437. }
  1438. /*!
  1439. Sets the \a format of the rows including and between \a rowFirst and \a rowLast.
  1440. Rows are 1-indexed.
  1441. Returns true if success.
  1442. */
  1443. bool Worksheet::setRowFormat(int rowFirst,int rowLast, const Format &format)
  1444. {
  1445. Q_D(Worksheet);
  1446. QList <QSharedPointer<XlsxRowInfo> > rowInfoList = d->getRowInfoList(rowFirst,rowLast);
  1447. foreach(QSharedPointer<XlsxRowInfo> rowInfo, rowInfoList)
  1448. rowInfo->format = format;
  1449. d->workbook->styles()->addXfFormat(format);
  1450. return rowInfoList.count() > 0;
  1451. }
  1452. /*!
  1453. Sets the \a hidden proeprty of the rows including and between \a rowFirst and \a rowLast.
  1454. Rows are 1-indexed. If hidden is true rows will not be visible.
  1455. Returns true if success.
  1456. */
  1457. bool Worksheet::setRowHidden(int rowFirst,int rowLast, bool hidden)
  1458. {
  1459. Q_D(Worksheet);
  1460. QList <QSharedPointer<XlsxRowInfo> > rowInfoList = d->getRowInfoList(rowFirst,rowLast);
  1461. foreach(QSharedPointer<XlsxRowInfo> rowInfo, rowInfoList)
  1462. rowInfo->hidden = hidden;
  1463. return rowInfoList.count() > 0;
  1464. }
  1465. /*!
  1466. Returns height of \a row in points.
  1467. */
  1468. double Worksheet::rowHeight(int row)
  1469. {
  1470. Q_D(Worksheet);
  1471. int min_col = d->dimension.isValid() ? d->dimension.firstColumn() : 1;
  1472. if (d->checkDimensions(row, min_col, false, true) || !d->rowsInfo.contains(row))
  1473. return d->sheetFormatProps.defaultRowHeight; //return default on invalid row
  1474. return d->rowsInfo[row]->height;
  1475. }
  1476. /*!
  1477. Returns format of \a row.
  1478. */
  1479. Format Worksheet::rowFormat(int row)
  1480. {
  1481. Q_D(Worksheet);
  1482. int min_col = d->dimension.isValid() ? d->dimension.firstColumn() : 1;
  1483. if (d->checkDimensions(row, min_col, false, true) || !d->rowsInfo.contains(row))
  1484. return Format(); //return default on invalid row
  1485. return d->rowsInfo[row]->format;
  1486. }
  1487. /*!
  1488. Returns true if \a row is hidden.
  1489. */
  1490. bool Worksheet::isRowHidden(int row)
  1491. {
  1492. Q_D(Worksheet);
  1493. int min_col = d->dimension.isValid() ? d->dimension.firstColumn() : 1;
  1494. if (d->checkDimensions(row, min_col, false, true) || !d->rowsInfo.contains(row))
  1495. return false; //return default on invalid row
  1496. return d->rowsInfo[row]->hidden;
  1497. }
  1498. /*!
  1499. Groups rows from \a rowFirst to \a rowLast with the given \a collapsed.
  1500. Returns false if error occurs.
  1501. */
  1502. bool Worksheet::groupRows(int rowFirst, int rowLast, bool collapsed)
  1503. {
  1504. Q_D(Worksheet);
  1505. for (int row=rowFirst; row<=rowLast; ++row) {
  1506. if (d->rowsInfo.contains(row)) {
  1507. d->rowsInfo[row]->outlineLevel += 1;
  1508. } else {
  1509. QSharedPointer<XlsxRowInfo> info(new XlsxRowInfo);
  1510. info->outlineLevel += 1;
  1511. d->rowsInfo.insert(row, info);
  1512. }
  1513. if (collapsed)
  1514. d->rowsInfo[row]->hidden = true;
  1515. }
  1516. if (collapsed) {
  1517. if (!d->rowsInfo.contains(rowLast+1))
  1518. d->rowsInfo.insert(rowLast+1, QSharedPointer<XlsxRowInfo>(new XlsxRowInfo));
  1519. d->rowsInfo[rowLast+1]->collapsed = true;
  1520. }
  1521. return true;
  1522. }
  1523. /*!
  1524. \overload
  1525. Groups columns with the given \a range and \a collapsed.
  1526. */
  1527. bool Worksheet::groupColumns(const CellRange &range, bool collapsed)
  1528. {
  1529. if (!range.isValid())
  1530. return false;
  1531. return groupColumns(range.firstColumn(), range.lastColumn(), collapsed);
  1532. }
  1533. /*!
  1534. Groups columns from \a colFirst to \a colLast with the given \a collapsed.
  1535. Returns false if error occurs.
  1536. */
  1537. bool Worksheet::groupColumns(int colFirst, int colLast, bool collapsed)
  1538. {
  1539. Q_D(Worksheet);
  1540. d->splitColsInfo(colFirst, colLast);
  1541. QList<int> nodes;
  1542. nodes.append(colFirst);
  1543. for (int col = colFirst; col <= colLast; ++col) {
  1544. if (d->colsInfo.contains(col)) {
  1545. if (nodes.last() != col)
  1546. nodes.append(col);
  1547. int nextCol = d->colsInfo[col]->lastColumn + 1;
  1548. if (nextCol <= colLast)
  1549. nodes.append(nextCol);
  1550. }
  1551. }
  1552. for (int idx = 0; idx < nodes.size(); ++idx) {
  1553. int colStart = nodes[idx];
  1554. if (d->colsInfo.contains(colStart)) {
  1555. QSharedPointer<XlsxColumnInfo> info = d->colsInfo[colStart];
  1556. info->outlineLevel += 1;
  1557. if (collapsed)
  1558. info->hidden = true;
  1559. } else {
  1560. int colEnd = (idx == nodes.size() - 1) ? colLast : nodes[idx+1] - 1;
  1561. QSharedPointer<XlsxColumnInfo> info(new XlsxColumnInfo(colStart, colEnd));
  1562. info->outlineLevel += 1;
  1563. d->colsInfo.insert(colFirst, info);
  1564. if (collapsed)
  1565. info->hidden = true;
  1566. for (int c = colStart; c <= colEnd; ++c)
  1567. d->colsInfoHelper[c] = info;
  1568. }
  1569. }
  1570. if (collapsed) {
  1571. int col = colLast+1;
  1572. d->splitColsInfo(col, col);
  1573. if (d->colsInfo.contains(col))
  1574. d->colsInfo[col]->collapsed = true;
  1575. else {
  1576. QSharedPointer<XlsxColumnInfo> info(new XlsxColumnInfo(col, col));
  1577. info->collapsed = true;
  1578. d->colsInfo.insert(col, info);
  1579. d->colsInfoHelper[col] = info;
  1580. }
  1581. }
  1582. return false;
  1583. }
  1584. /*!
  1585. Return the range that contains cell data.
  1586. */
  1587. CellRange Worksheet::dimension() const
  1588. {
  1589. Q_D(const Worksheet);
  1590. return d->dimension;
  1591. }
  1592. /*
  1593. Convert the height of a cell from user's units to pixels. If the
  1594. height hasn't been set by the user we use the default value. If
  1595. the row is hidden it has a value of zero.
  1596. */
  1597. int WorksheetPrivate::rowPixelsSize(int row) const
  1598. {
  1599. double height;
  1600. if (row_sizes.contains(row))
  1601. height = row_sizes[row];
  1602. else
  1603. height = default_row_height;
  1604. return static_cast<int>(4.0 / 3.0 *height);
  1605. }
  1606. /*
  1607. Convert the width of a cell from user's units to pixels. Excel rounds
  1608. the column width to the nearest pixel. If the width hasn't been set
  1609. by the user we use the default value. If the column is hidden it
  1610. has a value of zero.
  1611. */
  1612. int WorksheetPrivate::colPixelsSize(int col) const
  1613. {
  1614. double max_digit_width = 7.0; //For Calabri 11
  1615. double padding = 5.0;
  1616. int pixels = 0;
  1617. if (col_sizes.contains(col)) {
  1618. double width = col_sizes[col];
  1619. if (width < 1)
  1620. pixels = static_cast<int>(width * (max_digit_width + padding) + 0.5);
  1621. else
  1622. pixels = static_cast<int>(width * max_digit_width + 0.5) + padding;
  1623. } else {
  1624. pixels = 64;
  1625. }
  1626. return pixels;
  1627. }
  1628. void WorksheetPrivate::loadXmlSheetData(QXmlStreamReader &reader)
  1629. {
  1630. Q_Q(Worksheet);
  1631. Q_ASSERT(reader.name() == QLatin1String("sheetData"));
  1632. while (!reader.atEnd() && !(reader.name() == QLatin1String("sheetData") && reader.tokenType() == QXmlStreamReader::EndElement)) {
  1633. if (reader.readNextStartElement()) {
  1634. if (reader.name() == QLatin1String("row")) {
  1635. QXmlStreamAttributes attributes = reader.attributes();
  1636. if (attributes.hasAttribute(QLatin1String("customFormat"))
  1637. || attributes.hasAttribute(QLatin1String("customHeight"))
  1638. || attributes.hasAttribute(QLatin1String("hidden"))
  1639. || attributes.hasAttribute(QLatin1String("outlineLevel"))
  1640. || attributes.hasAttribute(QLatin1String("collapsed"))) {
  1641. QSharedPointer<XlsxRowInfo> info(new XlsxRowInfo);
  1642. if (attributes.hasAttribute(QLatin1String("customFormat")) && attributes.hasAttribute(QLatin1String("s"))) {
  1643. int idx = attributes.value(QLatin1String("s")).toString().toInt();
  1644. info->format = workbook->styles()->xfFormat(idx);
  1645. }
  1646. if (attributes.hasAttribute(QLatin1String("customHeight"))) {
  1647. info->customHeight = attributes.value(QLatin1String("customHeight")) == QLatin1String("1");
  1648. //Row height is only specified when customHeight is set
  1649. if(attributes.hasAttribute(QLatin1String("ht"))) {
  1650. info->height = attributes.value(QLatin1String("ht")).toString().toDouble();
  1651. }
  1652. }
  1653. //both "hidden" and "collapsed" default are false
  1654. info->hidden = attributes.value(QLatin1String("hidden")) == QLatin1String("1");
  1655. info->collapsed = attributes.value(QLatin1String("collapsed")) == QLatin1String("1");
  1656. if (attributes.hasAttribute(QLatin1String("outlineLevel")))
  1657. info->outlineLevel = attributes.value(QLatin1String("outlineLevel")).toString().toInt();
  1658. //"r" is optional too.
  1659. if (attributes.hasAttribute(QLatin1String("r"))) {
  1660. int row = attributes.value(QLatin1String("r")).toString().toInt();
  1661. rowsInfo[row] = info;
  1662. }
  1663. }
  1664. } else if (reader.name() == QLatin1String("c")) { //Cell
  1665. QXmlStreamAttributes attributes = reader.attributes();
  1666. QString r = attributes.value(QLatin1String("r")).toString();
  1667. CellReference pos(r);
  1668. //get format
  1669. Format format;
  1670. if (attributes.hasAttribute(QLatin1String("s"))) { //"s" == style index
  1671. int idx = attributes.value(QLatin1String("s")).toString().toInt();
  1672. format = workbook->styles()->xfFormat(idx);
  1673. ////Empty format exists in styles xf table of real .xlsx files, see issue #65.
  1674. //if (!format.isValid())
  1675. // qDebug()<<QStringLiteral("<c s=\"%1\">Invalid style index: ").arg(idx)<<idx;
  1676. }
  1677. Cell::CellType cellType = Cell::NumberType;
  1678. if (attributes.hasAttribute(QLatin1String("t"))) {
  1679. QString typeString = attributes.value(QLatin1String("t")).toString();
  1680. if (typeString == QLatin1String("s"))
  1681. cellType = Cell::SharedStringType;
  1682. else if (typeString == QLatin1String("inlineStr"))
  1683. cellType = Cell::InlineStringType;
  1684. else if (typeString == QLatin1String("str"))
  1685. cellType = Cell::StringType;
  1686. else if (typeString == QLatin1String("b"))
  1687. cellType = Cell::BooleanType;
  1688. else if (typeString == QLatin1String("e"))
  1689. cellType = Cell::ErrorType;
  1690. else
  1691. cellType = Cell::NumberType;
  1692. }
  1693. QSharedPointer<Cell> cell(new Cell(QVariant() ,cellType, format, q));
  1694. while (!reader.atEnd() && !(reader.name() == QLatin1String("c") && reader.tokenType() == QXmlStreamReader::EndElement)) {
  1695. if (reader.readNextStartElement()) {
  1696. if (reader.name() == QLatin1String("f")) {
  1697. CellFormula &formula = cell->d_func()->formula;
  1698. formula.loadFromXml(reader);
  1699. if (formula.formulaType() == CellFormula::SharedType && !formula.formulaText().isEmpty()) {
  1700. sharedFormulaMap[formula.sharedIndex()] = formula;
  1701. }
  1702. } else if (reader.name() == QLatin1String("v")) {
  1703. QString value = reader.readElementText();
  1704. if (cellType == Cell::SharedStringType) {
  1705. int sst_idx = value.toInt();
  1706. sharedStrings()->incRefByStringIndex(sst_idx);
  1707. RichString rs = sharedStrings()->getSharedString(sst_idx);
  1708. cell->d_func()->value = rs.toPlainString();
  1709. if (rs.isRichString())
  1710. cell->d_func()->richString = rs;
  1711. } else if (cellType == Cell::NumberType) {
  1712. cell->d_func()->value = value.toDouble();
  1713. } else if (cellType == Cell::BooleanType) {
  1714. cell->d_func()->value = value.toInt() ? true : false;
  1715. } else { //Cell::ErrorType and Cell::StringType
  1716. cell->d_func()->value = value;
  1717. }
  1718. } else if (reader.name() == QLatin1String("is")) {
  1719. while (!reader.atEnd() && !(reader.name() == QLatin1String("is") && reader.tokenType() == QXmlStreamReader::EndElement)) {
  1720. if (reader.readNextStartElement()) {
  1721. //:Todo, add rich text read support
  1722. if (reader.name() == QLatin1String("t")) {
  1723. cell->d_func()->value = reader.readElementText();
  1724. }
  1725. }
  1726. }
  1727. } else if (reader.name() == QLatin1String("extLst")) {
  1728. //skip extLst element
  1729. while (!reader.atEnd() && !(reader.name() == QLatin1String("extLst")
  1730. && reader.tokenType() == QXmlStreamReader::EndElement)) {
  1731. reader.readNextStartElement();
  1732. }
  1733. }
  1734. }
  1735. }
  1736. cellTable[pos.row()][pos.column()] = cell;
  1737. }
  1738. }
  1739. }
  1740. }
  1741. void WorksheetPrivate::loadXmlColumnsInfo(QXmlStreamReader &reader)
  1742. {
  1743. Q_ASSERT(reader.name() == QLatin1String("cols"));
  1744. while (!reader.atEnd() && !(reader.name() == QLatin1String("cols") && reader.tokenType() == QXmlStreamReader::EndElement)) {
  1745. reader.readNextStartElement();
  1746. if (reader.tokenType() == QXmlStreamReader::StartElement) {
  1747. if (reader.name() == QLatin1String("col")) {
  1748. QSharedPointer<XlsxColumnInfo> info(new XlsxColumnInfo);
  1749. QXmlStreamAttributes colAttrs = reader.attributes();
  1750. int min = colAttrs.value(QLatin1String("min")).toString().toInt();
  1751. int max = colAttrs.value(QLatin1String("max")).toString().toInt();
  1752. info->firstColumn = min;
  1753. info->lastColumn = max;
  1754. //Flag indicating that the column width for the affected column(s) is different from the
  1755. // default or has been manually set
  1756. if(colAttrs.hasAttribute(QLatin1String("customWidth"))) {
  1757. info->customWidth = colAttrs.value(QLatin1String("customWidth")) == QLatin1String("1");
  1758. }
  1759. //Note, node may have "width" without "customWidth"
  1760. if (colAttrs.hasAttribute(QLatin1String("width"))) {
  1761. double width = colAttrs.value(QLatin1String("width")).toString().toDouble();
  1762. info->width = width;
  1763. }
  1764. info->hidden = colAttrs.value(QLatin1String("hidden")) == QLatin1String("1");
  1765. info->collapsed = colAttrs.value(QLatin1String("collapsed")) == QLatin1String("1");
  1766. if (colAttrs.hasAttribute(QLatin1String("style"))) {
  1767. int idx = colAttrs.value(QLatin1String("style")).toString().toInt();
  1768. info->format = workbook->styles()->xfFormat(idx);
  1769. }
  1770. if (colAttrs.hasAttribute(QLatin1String("outlineLevel")))
  1771. info->outlineLevel = colAttrs.value(QLatin1String("outlineLevel")).toString().toInt();
  1772. colsInfo.insert(min, info);
  1773. for (int col=min; col<=max; ++col)
  1774. colsInfoHelper[col] = info;
  1775. }
  1776. }
  1777. }
  1778. }
  1779. void WorksheetPrivate::loadXmlMergeCells(QXmlStreamReader &reader)
  1780. {
  1781. Q_ASSERT(reader.name() == QLatin1String("mergeCells"));
  1782. QXmlStreamAttributes attributes = reader.attributes();
  1783. int count = attributes.value(QLatin1String("count")).toString().toInt();
  1784. while (!reader.atEnd() && !(reader.name() == QLatin1String("mergeCells") && reader.tokenType() == QXmlStreamReader::EndElement)) {
  1785. reader.readNextStartElement();
  1786. if (reader.tokenType() == QXmlStreamReader::StartElement) {
  1787. if (reader.name() == QLatin1String("mergeCell")) {
  1788. QXmlStreamAttributes attrs = reader.attributes();
  1789. QString rangeStr = attrs.value(QLatin1String("ref")).toString();
  1790. merges.append(CellRange(rangeStr));
  1791. }
  1792. }
  1793. }
  1794. if (merges.size() != count)
  1795. qDebug("read merge cells error");
  1796. }
  1797. void WorksheetPrivate::loadXmlDataValidations(QXmlStreamReader &reader)
  1798. {
  1799. Q_ASSERT(reader.name() == QLatin1String("dataValidations"));
  1800. QXmlStreamAttributes attributes = reader.attributes();
  1801. int count = attributes.value(QLatin1String("count")).toString().toInt();
  1802. while (!reader.atEnd() && !(reader.name() == QLatin1String("dataValidations")
  1803. && reader.tokenType() == QXmlStreamReader::EndElement)) {
  1804. reader.readNextStartElement();
  1805. if (reader.tokenType() == QXmlStreamReader::StartElement
  1806. && reader.name() == QLatin1String("dataValidation")) {
  1807. dataValidationsList.append(DataValidation::loadFromXml(reader));
  1808. }
  1809. }
  1810. if (dataValidationsList.size() != count)
  1811. qDebug("read data validation error");
  1812. }
  1813. void WorksheetPrivate::loadXmlSheetViews(QXmlStreamReader &reader)
  1814. {
  1815. Q_ASSERT(reader.name() == QLatin1String("sheetViews"));
  1816. while (!reader.atEnd() && !(reader.name() == QLatin1String("sheetViews")
  1817. && reader.tokenType() == QXmlStreamReader::EndElement)) {
  1818. reader.readNextStartElement();
  1819. if (reader.tokenType() == QXmlStreamReader::StartElement && reader.name() == QLatin1String("sheetView")) {
  1820. QXmlStreamAttributes attrs = reader.attributes();
  1821. //default false
  1822. windowProtection = attrs.value(QLatin1String("windowProtection")) == QLatin1String("1");
  1823. showFormulas = attrs.value(QLatin1String("showFormulas")) == QLatin1String("1");
  1824. rightToLeft = attrs.value(QLatin1String("rightToLeft")) == QLatin1String("1");
  1825. tabSelected = attrs.value(QLatin1String("tabSelected")) == QLatin1String("1");
  1826. //default true
  1827. showGridLines = attrs.value(QLatin1String("showGridLines")) != QLatin1String("0");
  1828. showRowColHeaders = attrs.value(QLatin1String("showRowColHeaders")) != QLatin1String("0");
  1829. showZeros = attrs.value(QLatin1String("showZeros")) != QLatin1String("0");
  1830. showRuler = attrs.value(QLatin1String("showRuler")) != QLatin1String("0");
  1831. showOutlineSymbols = attrs.value(QLatin1String("showOutlineSymbols")) != QLatin1String("0");
  1832. showWhiteSpace = attrs.value(QLatin1String("showWhiteSpace")) != QLatin1String("0");
  1833. }
  1834. }
  1835. }
  1836. void WorksheetPrivate::loadXmlSheetFormatProps(QXmlStreamReader &reader)
  1837. {
  1838. Q_ASSERT(reader.name() == QLatin1String("sheetFormatPr"));
  1839. QXmlStreamAttributes attributes = reader.attributes();
  1840. XlsxSheetFormatProps formatProps;
  1841. //Retain default values
  1842. foreach (QXmlStreamAttribute attrib, attributes) {
  1843. if(attrib.name() == QLatin1String("baseColWidth") ) {
  1844. formatProps.baseColWidth = attrib.value().toString().toInt();
  1845. } else if(attrib.name() == QLatin1String("customHeight")) {
  1846. formatProps.customHeight = attrib.value() == QLatin1String("1");
  1847. } else if(attrib.name() == QLatin1String("defaultColWidth")) {
  1848. formatProps.defaultColWidth = attrib.value().toString().toDouble();
  1849. } else if(attrib.name() == QLatin1String("defaultRowHeight")) {
  1850. formatProps.defaultRowHeight = attrib.value().toString().toDouble();
  1851. } else if(attrib.name() == QLatin1String("outlineLevelCol")) {
  1852. formatProps.outlineLevelCol = attrib.value().toString().toInt();
  1853. } else if(attrib.name() == QLatin1String("outlineLevelRow")) {
  1854. formatProps.outlineLevelRow = attrib.value().toString().toInt();
  1855. } else if(attrib.name() == QLatin1String("thickBottom")) {
  1856. formatProps.thickBottom = attrib.value() == QLatin1String("1");
  1857. } else if(attrib.name() == QLatin1String("thickTop")) {
  1858. formatProps.thickTop = attrib.value() == QLatin1String("1");
  1859. } else if(attrib.name() == QLatin1String("zeroHeight")) {
  1860. formatProps.zeroHeight = attrib.value() == QLatin1String("1");
  1861. }
  1862. }
  1863. if(formatProps.defaultColWidth == 0.0) { //not set
  1864. formatProps.defaultColWidth = WorksheetPrivate::calculateColWidth(formatProps.baseColWidth);
  1865. }
  1866. }
  1867. double WorksheetPrivate::calculateColWidth(int characters)
  1868. {
  1869. //!Todo
  1870. //Take normal style' font maximum width and add padding and margin pixels
  1871. return characters + 0.5;
  1872. }
  1873. void WorksheetPrivate::loadXmlHyperlinks(QXmlStreamReader &reader)
  1874. {
  1875. Q_ASSERT(reader.name() == QLatin1String("hyperlinks"));
  1876. while (!reader.atEnd() && !(reader.name() == QLatin1String("hyperlinks")
  1877. && reader.tokenType() == QXmlStreamReader::EndElement)) {
  1878. reader.readNextStartElement();
  1879. if (reader.tokenType() == QXmlStreamReader::StartElement && reader.name() == QLatin1String("hyperlink")) {
  1880. QXmlStreamAttributes attrs = reader.attributes();
  1881. CellReference pos(attrs.value(QLatin1String("ref")).toString());
  1882. if (pos.isValid()) { //Valid
  1883. QSharedPointer<XlsxHyperlinkData> link(new XlsxHyperlinkData);
  1884. link->display = attrs.value(QLatin1String("display")).toString();
  1885. link->tooltip = attrs.value(QLatin1String("tooltip")).toString();
  1886. link->location = attrs.value(QLatin1String("location")).toString();
  1887. if (attrs.hasAttribute(QLatin1String("r:id"))) {
  1888. link->linkType = XlsxHyperlinkData::External;
  1889. XlsxRelationship ship = relationships->getRelationshipById(attrs.value(QLatin1String("r:id")).toString());
  1890. link->target = ship.target;
  1891. } else {
  1892. link->linkType = XlsxHyperlinkData::Internal;
  1893. }
  1894. urlTable[pos.row()][pos.column()] = link;
  1895. }
  1896. }
  1897. }
  1898. }
  1899. QList <QSharedPointer<XlsxColumnInfo> > WorksheetPrivate::getColumnInfoList(int colFirst, int colLast)
  1900. {
  1901. QList <QSharedPointer<XlsxColumnInfo> > columnsInfoList;
  1902. if(isColumnRangeValid(colFirst,colLast))
  1903. {
  1904. QList<int> nodes = getColumnIndexes(colFirst, colLast);
  1905. for (int idx = 0; idx < nodes.size(); ++idx) {
  1906. int colStart = nodes[idx];
  1907. if (colsInfo.contains(colStart)) {
  1908. QSharedPointer<XlsxColumnInfo> info = colsInfo[colStart];
  1909. columnsInfoList.append(info);
  1910. } else {
  1911. int colEnd = (idx == nodes.size() - 1) ? colLast : nodes[idx+1] - 1;
  1912. QSharedPointer<XlsxColumnInfo> info(new XlsxColumnInfo(colStart, colEnd));
  1913. colsInfo.insert(colFirst, info);
  1914. columnsInfoList.append(info);
  1915. for (int c = colStart; c <= colEnd; ++c)
  1916. colsInfoHelper[c] = info;
  1917. }
  1918. }
  1919. }
  1920. return columnsInfoList;
  1921. }
  1922. QList <QSharedPointer<XlsxRowInfo> > WorksheetPrivate::getRowInfoList(int rowFirst, int rowLast)
  1923. {
  1924. QList <QSharedPointer<XlsxRowInfo> > rowInfoList;
  1925. int min_col = dimension.firstColumn() < 1 ? 1 : dimension.firstColumn();
  1926. for(int row = rowFirst; row <= rowLast; ++row) {
  1927. if (checkDimensions(row, min_col, false, true))
  1928. continue;
  1929. QSharedPointer<XlsxRowInfo> rowInfo;
  1930. if ((rowsInfo[row]).isNull()){
  1931. rowsInfo[row] = QSharedPointer<XlsxRowInfo>(new XlsxRowInfo());
  1932. }
  1933. rowInfoList.append(rowsInfo[row]);
  1934. }
  1935. return rowInfoList;
  1936. }
  1937. bool Worksheet::loadFromXmlFile(QIODevice *device)
  1938. {
  1939. Q_D(Worksheet);
  1940. QXmlStreamReader reader(device);
  1941. while (!reader.atEnd()) {
  1942. reader.readNextStartElement();
  1943. if (reader.tokenType() == QXmlStreamReader::StartElement) {
  1944. if (reader.name() == QLatin1String("dimension")) {
  1945. QXmlStreamAttributes attributes = reader.attributes();
  1946. QString range = attributes.value(QLatin1String("ref")).toString();
  1947. d->dimension = CellRange(range);
  1948. } else if (reader.name() == QLatin1String("sheetViews")) {
  1949. d->loadXmlSheetViews(reader);
  1950. } else if (reader.name() == QLatin1String("sheetFormatPr")) {
  1951. d->loadXmlSheetFormatProps(reader);
  1952. } else if (reader.name() == QLatin1String("cols")) {
  1953. d->loadXmlColumnsInfo(reader);
  1954. } else if (reader.name() == QLatin1String("sheetData")) {
  1955. d->loadXmlSheetData(reader);
  1956. } else if (reader.name() == QLatin1String("mergeCells")) {
  1957. d->loadXmlMergeCells(reader);
  1958. } else if (reader.name() == QLatin1String("dataValidations")) {
  1959. d->loadXmlDataValidations(reader);
  1960. } else if (reader.name() == QLatin1String("conditionalFormatting")) {
  1961. ConditionalFormatting cf;
  1962. cf.loadFromXml(reader, workbook()->styles());
  1963. d->conditionalFormattingList.append(cf);
  1964. } else if (reader.name() == QLatin1String("hyperlinks")) {
  1965. d->loadXmlHyperlinks(reader);
  1966. } else if (reader.name() == QLatin1String("drawing")) {
  1967. QString rId = reader.attributes().value(QStringLiteral("r:id")).toString();
  1968. QString name = d->relationships->getRelationshipById(rId).target;
  1969. QString path = QDir::cleanPath(splitPath(filePath())[0] + QLatin1String("/") + name);
  1970. d->drawing = QSharedPointer<Drawing>(new Drawing(this, F_LoadFromExists));
  1971. d->drawing->setFilePath(path);
  1972. } else if (reader.name() == QLatin1String("extLst")) {
  1973. //Todo: add extLst support
  1974. while (!reader.atEnd() && !(reader.name() == QLatin1String("extLst")
  1975. && reader.tokenType() == QXmlStreamReader::EndElement)) {
  1976. reader.readNextStartElement();
  1977. }
  1978. }
  1979. }
  1980. }
  1981. d->validateDimension();
  1982. return true;
  1983. }
  1984. /*
  1985. * Documents imported from Google Docs does not contain dimension data.
  1986. */
  1987. void WorksheetPrivate::validateDimension()
  1988. {
  1989. if (dimension.isValid() || cellTable.isEmpty())
  1990. return;
  1991. int firstRow = cellTable.constBegin().key();
  1992. int lastRow = (cellTable.constEnd()-1).key();
  1993. int firstColumn = -1;
  1994. int lastColumn = -1;
  1995. for (QMap<int, QMap<int, QSharedPointer<Cell> > >::const_iterator it = cellTable.begin(); it != cellTable.end(); ++it)
  1996. {
  1997. Q_ASSERT(!it.value().isEmpty());
  1998. if (firstColumn == -1 || it.value().constBegin().key() < firstColumn)
  1999. firstColumn = it.value().constBegin().key();
  2000. if (lastColumn == -1 || (it.value().constEnd()-1).key() > lastColumn)
  2001. lastColumn = (it.value().constEnd()-1).key();
  2002. }
  2003. CellRange cr(firstRow, firstColumn, lastRow, lastColumn);
  2004. if (cr.isValid())
  2005. dimension = cr;
  2006. }
  2007. /*!
  2008. * \internal
  2009. * Unit test can use this member to get sharedString object.
  2010. */
  2011. SharedStrings *WorksheetPrivate::sharedStrings() const
  2012. {
  2013. return workbook->sharedStrings();
  2014. }
  2015. QT_END_NAMESPACE_XLSX