xlsxworksheet.cpp 89 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090
  1. // xlsxworksheet.cpp
  2. #include <QtGlobal>
  3. #include <QVariant>
  4. #include <QDateTime>
  5. #include <QDate>
  6. #include <QTime>
  7. #include <QPoint>
  8. #include <QFile>
  9. #include <QUrl>
  10. #include <QDebug>
  11. #include <QBuffer>
  12. #include <QXmlStreamWriter>
  13. #include <QXmlStreamReader>
  14. #include <QTextDocument>
  15. #include <QDir>
  16. #include <QMapIterator>
  17. #include <QMap>
  18. #include <cmath>
  19. #include "xlsxrichstring.h"
  20. #include "xlsxcellreference.h"
  21. #include "xlsxworksheet.h"
  22. #include "xlsxworksheet_p.h"
  23. #include "xlsxworkbook.h"
  24. #include "xlsxformat.h"
  25. #include "xlsxformat_p.h"
  26. #include "xlsxutility_p.h"
  27. #include "xlsxsharedstrings_p.h"
  28. #include "xlsxdrawing_p.h"
  29. #include "xlsxstyles_p.h"
  30. #include "xlsxcell.h"
  31. #include "xlsxcell_p.h"
  32. #include "xlsxcellrange.h"
  33. #include "xlsxconditionalformatting_p.h"
  34. #include "xlsxdrawinganchor_p.h"
  35. #include "xlsxchart.h"
  36. #include "xlsxcellformula.h"
  37. #include "xlsxcellformula_p.h"
  38. #include "xlsxcelllocation.h"
  39. QT_BEGIN_NAMESPACE_XLSX
  40. WorksheetPrivate::WorksheetPrivate(Worksheet *p, Worksheet::CreateFlag flag)
  41. : AbstractSheetPrivate(p, flag),
  42. windowProtection(false),
  43. showFormulas(false),
  44. showGridLines(true),
  45. showRowColHeaders(true),
  46. showZeros(true),
  47. rightToLeft(false),
  48. tabSelected(false),
  49. showRuler(false),
  50. showOutlineSymbols(true),
  51. showWhiteSpace(true),
  52. urlPattern(QStringLiteral("^([fh]tt?ps?://)|(mailto:)|(file://)"))
  53. {
  54. previous_row = 0;
  55. outline_row_level = 0;
  56. outline_col_level = 0;
  57. default_row_height = 15;
  58. default_row_zeroed = false;
  59. }
  60. WorksheetPrivate::~WorksheetPrivate()
  61. {
  62. }
  63. /*
  64. Calculate the "spans" attribute of the <row> tag. This is an
  65. XLSX optimisation and isn't strictly required. However, it
  66. makes comparing files easier. The span is the same for each
  67. block of 16 rows.
  68. */
  69. void WorksheetPrivate::calculateSpans() const
  70. {
  71. row_spans.clear();
  72. int span_min = XLSX_COLUMN_MAX+1;
  73. int span_max = -1;
  74. for (int row_num = dimension.firstRow(); row_num <= dimension.lastRow(); row_num++) {
  75. auto it = cellTable.constFind(row_num);
  76. if (it != cellTable.constEnd()) {
  77. for (int col_num = dimension.firstColumn(); col_num <= dimension.lastColumn(); col_num++) {
  78. if (it->contains(col_num)) {
  79. if (span_max == -1) {
  80. span_min = col_num;
  81. span_max = col_num;
  82. } else {
  83. if (col_num < span_min)
  84. span_min = col_num;
  85. else if (col_num > span_max)
  86. span_max = col_num;
  87. }
  88. }
  89. }
  90. }
  91. auto cIt = comments.constFind(row_num);
  92. if (cIt != comments.constEnd()) {
  93. for (int col_num = dimension.firstColumn(); col_num <= dimension.lastColumn(); col_num++) {
  94. if (cIt->contains(col_num)) {
  95. if (span_max == -1) {
  96. span_min = col_num;
  97. span_max = col_num;
  98. } else {
  99. if (col_num < span_min)
  100. span_min = col_num;
  101. else if (col_num > span_max)
  102. span_max = col_num;
  103. }
  104. }
  105. }
  106. }
  107. if (row_num%16 == 0 || row_num == dimension.lastRow()) {
  108. if (span_max != -1) {
  109. row_spans[row_num / 16] = QStringLiteral("%1:%2").arg(span_min).arg(span_max);
  110. span_min = XLSX_COLUMN_MAX+1;
  111. span_max = -1;
  112. }
  113. }
  114. }
  115. }
  116. QString WorksheetPrivate::generateDimensionString() const
  117. {
  118. if (!dimension.isValid())
  119. return QStringLiteral("A1");
  120. else
  121. return dimension.toString();
  122. }
  123. /*
  124. Check that row and col are valid and store the max and min
  125. values for use in other methods/elements. The ignore_row /
  126. ignore_col flags is used to indicate that we wish to perform
  127. the dimension check without storing the value. The ignore
  128. flags are use by setRow() and dataValidate.
  129. */
  130. int WorksheetPrivate::checkDimensions(int row, int col, bool ignore_row, bool ignore_col)
  131. {
  132. Q_ASSERT_X(row!=0, "checkDimensions", "row should start from 1 instead of 0");
  133. Q_ASSERT_X(col!=0, "checkDimensions", "column should start from 1 instead of 0");
  134. if (row > XLSX_ROW_MAX || row < 1 || col > XLSX_COLUMN_MAX || col < 1)
  135. return -1;
  136. if (!ignore_row) {
  137. if (row < dimension.firstRow() || dimension.firstRow() == -1) dimension.setFirstRow(row);
  138. if (row > dimension.lastRow()) dimension.setLastRow(row);
  139. }
  140. if (!ignore_col) {
  141. if (col < dimension.firstColumn() || dimension.firstColumn() == -1) dimension.setFirstColumn(col);
  142. if (col > dimension.lastColumn()) dimension.setLastColumn(col);
  143. }
  144. return 0;
  145. }
  146. /*!
  147. \class Worksheet
  148. \inmodule QtXlsx
  149. \brief Represent one worksheet in the workbook.
  150. */
  151. /*!
  152. * \internal
  153. */
  154. Worksheet::Worksheet(const QString &name, int id, Workbook *workbook, CreateFlag flag)
  155. :AbstractSheet(name, id, workbook, new WorksheetPrivate(this, flag))
  156. {
  157. if (!workbook) //For unit test propose only. Ignore the memery leak.
  158. d_func()->workbook = new Workbook(flag);
  159. }
  160. /*!
  161. * \internal
  162. *
  163. * Make a copy of this sheet.
  164. */
  165. Worksheet *Worksheet::copy(const QString &distName, int distId) const
  166. {
  167. Q_D(const Worksheet);
  168. Worksheet *sheet = new Worksheet(distName, distId, d->workbook, F_NewFromScratch);
  169. WorksheetPrivate *sheet_d = sheet->d_func();
  170. sheet_d->dimension = d->dimension;
  171. QMapIterator<int, QMap<int, QSharedPointer<Cell> > > it(d->cellTable);
  172. while (it.hasNext())
  173. {
  174. it.next();
  175. int row = it.key();
  176. QMapIterator<int, QSharedPointer<Cell> > it2(it.value());
  177. while (it2.hasNext())
  178. {
  179. it2.next();
  180. int col = it2.key();
  181. QSharedPointer<Cell> cell(new Cell(it2.value().data()));
  182. cell->d_ptr->parent = sheet;
  183. if (cell->cellType() == Cell::SharedStringType)
  184. d->workbook->sharedStrings()->addSharedString(cell->d_ptr->richString);
  185. sheet_d->cellTable[row][col] = cell;
  186. }
  187. }
  188. sheet_d->merges = d->merges;
  189. // sheet_d->rowsInfo = d->rowsInfo;
  190. // sheet_d->colsInfo = d->colsInfo;
  191. // sheet_d->colsInfoHelper = d->colsInfoHelper;
  192. // sheet_d->dataValidationsList = d->dataValidationsList;
  193. // sheet_d->conditionalFormattingList = d->conditionalFormattingList;
  194. return sheet;
  195. }
  196. /*!
  197. * Destroys this workssheet.
  198. */
  199. Worksheet::~Worksheet()
  200. {
  201. }
  202. /*!
  203. * Returns whether sheet is protected.
  204. */
  205. bool Worksheet::isWindowProtected() const
  206. {
  207. Q_D(const Worksheet);
  208. return d->windowProtection;
  209. }
  210. /*!
  211. * Protects/unprotects the sheet based on \a protect.
  212. */
  213. void Worksheet::setWindowProtected(bool protect)
  214. {
  215. Q_D(Worksheet);
  216. d->windowProtection = protect;
  217. }
  218. /*!
  219. * Return whether formulas instead of their calculated results shown in cells
  220. */
  221. bool Worksheet::isFormulasVisible() const
  222. {
  223. Q_D(const Worksheet);
  224. return d->showFormulas;
  225. }
  226. /*!
  227. * Show formulas in cells instead of their calculated results when \a visible is true.
  228. */
  229. void Worksheet::setFormulasVisible(bool visible)
  230. {
  231. Q_D(Worksheet);
  232. d->showFormulas = visible;
  233. }
  234. /*!
  235. * Return whether gridlines is shown or not.
  236. */
  237. bool Worksheet::isGridLinesVisible() const
  238. {
  239. Q_D(const Worksheet);
  240. return d->showGridLines;
  241. }
  242. /*!
  243. * Show or hide the gridline based on \a visible
  244. */
  245. void Worksheet::setGridLinesVisible(bool visible)
  246. {
  247. Q_D(Worksheet);
  248. d->showGridLines = visible;
  249. }
  250. /*!
  251. * Return whether is row and column headers is vislbe.
  252. */
  253. bool Worksheet::isRowColumnHeadersVisible() const
  254. {
  255. Q_D(const Worksheet);
  256. return d->showRowColHeaders;
  257. }
  258. /*!
  259. * Show or hide the row column headers based on \a visible
  260. */
  261. void Worksheet::setRowColumnHeadersVisible(bool visible)
  262. {
  263. Q_D(Worksheet);
  264. d->showRowColHeaders = visible;
  265. }
  266. /*!
  267. * Return whether the sheet is shown right-to-left or not.
  268. */
  269. bool Worksheet::isRightToLeft() const
  270. {
  271. Q_D(const Worksheet);
  272. return d->rightToLeft;
  273. }
  274. /*!
  275. * Enable or disable the right-to-left based on \a enable.
  276. */
  277. void Worksheet::setRightToLeft(bool enable)
  278. {
  279. Q_D(Worksheet);
  280. d->rightToLeft = enable;
  281. }
  282. /*!
  283. * Return whether is cells that have zero value show a zero.
  284. */
  285. bool Worksheet::isZerosVisible() const
  286. {
  287. Q_D(const Worksheet);
  288. return d->showZeros;
  289. }
  290. /*!
  291. * Show a zero in cells that have zero value if \a visible is true.
  292. */
  293. void Worksheet::setZerosVisible(bool visible)
  294. {
  295. Q_D(Worksheet);
  296. d->showZeros = visible;
  297. }
  298. /*!
  299. * Return whether this tab is selected.
  300. */
  301. bool Worksheet::isSelected() const
  302. {
  303. Q_D(const Worksheet);
  304. return d->tabSelected;
  305. }
  306. /*!
  307. * Select this sheet if \a select is true.
  308. */
  309. void Worksheet::setSelected(bool select)
  310. {
  311. Q_D(Worksheet);
  312. d->tabSelected = select;
  313. }
  314. /*!
  315. * Return whether is ruler is shown.
  316. */
  317. bool Worksheet::isRulerVisible() const
  318. {
  319. Q_D(const Worksheet);
  320. return d->showRuler;
  321. }
  322. /*!
  323. * Show or hide the ruler based on \a visible.
  324. */
  325. void Worksheet::setRulerVisible(bool visible)
  326. {
  327. Q_D(Worksheet);
  328. d->showRuler = visible;
  329. }
  330. /*!
  331. * Return whether is outline symbols is shown.
  332. */
  333. bool Worksheet::isOutlineSymbolsVisible() const
  334. {
  335. Q_D(const Worksheet);
  336. return d->showOutlineSymbols;
  337. }
  338. /*!
  339. * Show or hide the outline symbols based ib \a visible.
  340. */
  341. void Worksheet::setOutlineSymbolsVisible(bool visible)
  342. {
  343. Q_D(Worksheet);
  344. d->showOutlineSymbols = visible;
  345. }
  346. /*!
  347. * Return whether is white space is shown.
  348. */
  349. bool Worksheet::isWhiteSpaceVisible() const
  350. {
  351. Q_D(const Worksheet);
  352. return d->showWhiteSpace;
  353. }
  354. /*!
  355. * Show or hide the white space based on \a visible.
  356. */
  357. void Worksheet::setWhiteSpaceVisible(bool visible)
  358. {
  359. Q_D(Worksheet);
  360. d->showWhiteSpace = visible;
  361. }
  362. /*!
  363. * Write \a value to cell (\a row, \a column) with the \a format.
  364. * Both \a row and \a column are all 1-indexed value.
  365. *
  366. * Returns true on success.
  367. */
  368. bool Worksheet::write(int row, int column, const QVariant &value, const Format &format)
  369. {
  370. Q_D(Worksheet);
  371. if (d->checkDimensions(row, column))
  372. return false;
  373. bool ret = true;
  374. if (value.isNull())
  375. {
  376. //Blank
  377. ret = writeBlank(row, column, format);
  378. }
  379. else if (value.userType() == QMetaType::QString)
  380. {
  381. //String
  382. QString token = value.toString();
  383. bool ok;
  384. if (token.startsWith(QLatin1String("=")))
  385. {
  386. //convert to formula
  387. ret = writeFormula(row, column, CellFormula(token), format);
  388. }
  389. else if (d->workbook->isStringsToHyperlinksEnabled() && token.contains(d->urlPattern))
  390. {
  391. //convert to url
  392. ret = writeHyperlink(row, column, QUrl(token));
  393. }
  394. else if (d->workbook->isStringsToNumbersEnabled() && (value.toDouble(&ok), ok))
  395. {
  396. //Try convert string to number if the flag enabled.
  397. ret = writeString(row, column, value.toString(), format);
  398. }
  399. else
  400. {
  401. //normal string now
  402. ret = writeString(row, column, token, format);
  403. }
  404. }
  405. else if (value.userType() == qMetaTypeId<RichString>())
  406. {
  407. ret = writeString(row, column, value.value<RichString>(), format);
  408. }
  409. else if (value.userType() == QMetaType::Int || value.userType() == QMetaType::UInt
  410. || value.userType() == QMetaType::LongLong || value.userType() == QMetaType::ULongLong
  411. || value.userType() == QMetaType::Double || value.userType() == QMetaType::Float)
  412. {
  413. //Number
  414. ret = writeNumeric(row, column, value.toDouble(), format);
  415. }
  416. else if (value.userType() == QMetaType::Bool)
  417. {
  418. //Bool
  419. ret = writeBool(row,column, value.toBool(), format);
  420. }
  421. else if (value.userType() == QMetaType::QDateTime ) // dev67
  422. {
  423. //DateTime, Date
  424. // note that, QTime cann't convert to QDateTime
  425. ret = writeDateTime(row, column, value.toDateTime(), format);
  426. }
  427. else if ( value.userType() == QMetaType::QDate ) // dev67
  428. {
  429. ret = writeDate(row, column, value.toDate(), format);
  430. }
  431. else if (value.userType() == QMetaType::QTime)
  432. {
  433. //Time
  434. ret = writeTime(row, column, value.toTime(), format);
  435. }
  436. else if (value.userType() == QMetaType::QUrl)
  437. {
  438. //Url
  439. ret = writeHyperlink(row, column, value.toUrl(), format);
  440. }
  441. else
  442. {
  443. //Wrong type
  444. return false;
  445. }
  446. return ret;
  447. }
  448. /*!
  449. * \overload
  450. * Write \a value to cell \a row_column with the \a format.
  451. * Both row and column are all 1-indexed value.
  452. * Returns true on success.
  453. */
  454. bool Worksheet::write(const CellReference &row_column, const QVariant &value, const Format &format)
  455. {
  456. if (!row_column.isValid())
  457. return false;
  458. return write(row_column.row(), row_column.column(), value, format);
  459. }
  460. /*!
  461. \overload
  462. Return the contents of the cell \a row_column.
  463. */
  464. QVariant Worksheet::read(const CellReference &row_column) const
  465. {
  466. if (!row_column.isValid())
  467. return QVariant();
  468. return read(row_column.row(), row_column.column());
  469. }
  470. /*!
  471. Return the contents of the cell (\a row, \a column).
  472. */
  473. QVariant Worksheet::read(int row, int column) const
  474. {
  475. Q_D(const Worksheet);
  476. Cell *cell = cellAt(row, column);
  477. if (!cell)
  478. return QVariant();
  479. if (cell->hasFormula())
  480. {
  481. if (cell->formula().formulaType() == CellFormula::NormalType)
  482. {
  483. return QVariant(QLatin1String("=")+cell->formula().formulaText());
  484. }
  485. else if (cell->formula().formulaType() == CellFormula::SharedType)
  486. {
  487. if (!cell->formula().formulaText().isEmpty())
  488. {
  489. return QVariant(QLatin1String("=")+cell->formula().formulaText());
  490. }
  491. else
  492. {
  493. int si = cell->formula().sharedIndex();
  494. const CellFormula &rootFormula = d->sharedFormulaMap[ si ];
  495. CellReference rootCellRef = rootFormula.reference().topLeft();
  496. QString rootFormulaText = rootFormula.formulaText();
  497. QString newFormulaText = convertSharedFormula(rootFormulaText, rootCellRef, CellReference(row, column));
  498. return QVariant(QLatin1String("=")+newFormulaText);
  499. }
  500. }
  501. }
  502. if (cell->isDateTime())
  503. {
  504. QVariant vDateTime = cell->dateTime();
  505. return vDateTime;
  506. }
  507. return cell->value();
  508. }
  509. /*!
  510. * Returns the cell at the given \a row_column. If there
  511. * is no cell at the specified position, the function returns 0.
  512. */
  513. Cell *Worksheet::cellAt(const CellReference &row_column) const
  514. {
  515. if (!row_column.isValid())
  516. return 0;
  517. return cellAt(row_column.row(), row_column.column());
  518. }
  519. /*!
  520. * Returns the cell at the given \a row and \a column. If there
  521. * is no cell at the specified position, the function returns 0.
  522. */
  523. Cell *Worksheet::cellAt(int row, int col) const
  524. {
  525. Q_D(const Worksheet);
  526. auto it = d->cellTable.constFind(row);
  527. if (it == d->cellTable.constEnd())
  528. return 0;
  529. if (!it->contains(col))
  530. return 0;
  531. return (*it)[col].data();
  532. }
  533. Format WorksheetPrivate::cellFormat(int row, int col) const
  534. {
  535. auto it = cellTable.constFind(row);
  536. if (it == cellTable.constEnd())
  537. return Format();
  538. if (!it->contains(col))
  539. return Format();
  540. return (*it)[col]->format();
  541. }
  542. /*!
  543. \overload
  544. Write string \a value to the cell \a row_column with the \a format.
  545. Returns true on success.
  546. */
  547. bool Worksheet::writeString(const CellReference &row_column, const RichString &value, const Format &format)
  548. {
  549. if (!row_column.isValid())
  550. return false;
  551. return writeString(row_column.row(), row_column.column(), value, format);
  552. }
  553. /*!
  554. Write string \a value to the cell (\a row, \a column) with the \a format.
  555. Returns true on success.
  556. */
  557. bool Worksheet::writeString(int row, int column, const RichString &value, const Format &format)
  558. {
  559. Q_D(Worksheet);
  560. // QString content = value.toPlainString();
  561. if (d->checkDimensions(row, column))
  562. return false;
  563. // if (content.size() > d->xls_strmax) {
  564. // content = content.left(d->xls_strmax);
  565. // error = -2;
  566. // }
  567. d->sharedStrings()->addSharedString(value);
  568. Format fmt = format.isValid() ? format : d->cellFormat(row, column);
  569. if (value.fragmentCount() == 1 && value.fragmentFormat(0).isValid())
  570. fmt.mergeFormat(value.fragmentFormat(0));
  571. d->workbook->styles()->addXfFormat(fmt);
  572. QSharedPointer<Cell> cell = QSharedPointer<Cell>(new Cell(value.toPlainString(), Cell::SharedStringType, fmt, this));
  573. cell->d_ptr->richString = value;
  574. d->cellTable[row][column] = cell;
  575. return true;
  576. }
  577. /*!
  578. \overload
  579. Write string \a value to the cell \a row_column with the \a format.
  580. */
  581. bool Worksheet::writeString(const CellReference &row_column, const QString &value, const Format &format)
  582. {
  583. if (!row_column.isValid())
  584. return false;
  585. return writeString(row_column.row(), row_column.column(), value, format);
  586. }
  587. /*!
  588. \overload
  589. Write string \a value to the cell (\a row, \a column) with the \a format.
  590. Returns true on success.
  591. */
  592. bool Worksheet::writeString(int row, int column, const QString &value, const Format &format)
  593. {
  594. Q_D(Worksheet);
  595. if (d->checkDimensions(row, column))
  596. return false;
  597. RichString rs;
  598. if (d->workbook->isHtmlToRichStringEnabled() && Qt::mightBeRichText(value))
  599. rs.setHtml(value);
  600. else
  601. rs.addFragment(value, Format());
  602. return writeString(row, column, rs, format);
  603. }
  604. /*!
  605. \overload
  606. Write string \a value to the cell \a row_column with the \a format
  607. */
  608. bool Worksheet::writeInlineString(const CellReference &row_column, const QString &value, const Format &format)
  609. {
  610. if (!row_column.isValid())
  611. return false;
  612. return writeInlineString(row_column.row(), row_column.column(), value, format);
  613. }
  614. /*!
  615. Write string \a value to the cell (\a row, \a column) with the \a format.
  616. Returns true on success.
  617. */
  618. bool Worksheet::writeInlineString(int row, int column, const QString &value, const Format &format)
  619. {
  620. Q_D(Worksheet);
  621. //int error = 0;
  622. QString content = value;
  623. if (d->checkDimensions(row, column))
  624. return false;
  625. if (value.size() > XLSX_STRING_MAX) {
  626. content = value.left(XLSX_STRING_MAX);
  627. //error = -2;
  628. }
  629. Format fmt = format.isValid() ? format : d->cellFormat(row, column);
  630. d->workbook->styles()->addXfFormat(fmt);
  631. d->cellTable[row][column] = QSharedPointer<Cell>(new Cell(value, Cell::InlineStringType, fmt, this));
  632. return true;
  633. }
  634. /*!
  635. \overload
  636. Write numeric \a value to the cell \a row_column with the \a format.
  637. Returns true on success.
  638. */
  639. bool Worksheet::writeNumeric(const CellReference &row_column, double value, const Format &format)
  640. {
  641. if (!row_column.isValid())
  642. return false;
  643. return writeNumeric(row_column.row(), row_column.column(), value, format);
  644. }
  645. /*!
  646. Write numeric \a value to the cell (\a row, \a column) with the \a format.
  647. Returns true on success.
  648. */
  649. bool Worksheet::writeNumeric(int row, int column, double value, const Format &format)
  650. {
  651. Q_D(Worksheet);
  652. if (d->checkDimensions(row, column))
  653. return false;
  654. Format fmt = format.isValid() ? format : d->cellFormat(row, column);
  655. d->workbook->styles()->addXfFormat(fmt);
  656. d->cellTable[row][column] = QSharedPointer<Cell>(new Cell(value, Cell::NumberType, fmt, this));
  657. return true;
  658. }
  659. /*!
  660. \overload
  661. Write \a formula to the cell \a row_column with the \a format and \a result.
  662. Returns true on success.
  663. */
  664. bool Worksheet::writeFormula(const CellReference &row_column, const CellFormula &formula, const Format &format, double result)
  665. {
  666. if (!row_column.isValid())
  667. return false;
  668. return writeFormula(row_column.row(), row_column.column(), formula, format, result);
  669. }
  670. /*!
  671. Write \a formula_ to the cell (\a row, \a column) with the \a format and \a result.
  672. Returns true on success.
  673. */
  674. bool Worksheet::writeFormula(int row, int column, const CellFormula &formula_, const Format &format, double result)
  675. {
  676. Q_D(Worksheet);
  677. if (d->checkDimensions(row, column))
  678. return false;
  679. Format fmt = format.isValid() ? format : d->cellFormat(row, column);
  680. d->workbook->styles()->addXfFormat(fmt);
  681. CellFormula formula = formula_;
  682. formula.d->ca = true;
  683. if (formula.formulaType() == CellFormula::SharedType)
  684. {
  685. //Assign proper shared index for shared formula
  686. int si = 0;
  687. while ( d->sharedFormulaMap.contains(si) )
  688. {
  689. ++si;
  690. }
  691. formula.d->si = si;
  692. d->sharedFormulaMap[si] = formula;
  693. }
  694. QSharedPointer<Cell> data = QSharedPointer<Cell>(new Cell(result, Cell::NumberType, fmt, this));
  695. data->d_ptr->formula = formula;
  696. d->cellTable[row][column] = data;
  697. CellRange range = formula.reference();
  698. if (formula.formulaType() == CellFormula::SharedType) {
  699. CellFormula sf(QString(), CellFormula::SharedType);
  700. sf.d->si = formula.sharedIndex();
  701. for (int r=range.firstRow(); r<=range.lastRow(); ++r) {
  702. for (int c=range.firstColumn(); c<=range.lastColumn(); ++c) {
  703. if (!(r==row && c==column)) {
  704. if(Cell *cell = cellAt(r, c)) {
  705. cell->d_ptr->formula = sf;
  706. } else {
  707. QSharedPointer<Cell> newCell = QSharedPointer<Cell>(new Cell(result, Cell::NumberType, fmt, this));
  708. newCell->d_ptr->formula = sf;
  709. d->cellTable[r][c] = newCell;
  710. }
  711. }
  712. }
  713. }
  714. } else if (formula.formulaType() == CellFormula::SharedType) {
  715. }
  716. return true;
  717. }
  718. /*!
  719. \overload
  720. Write a empty cell \a row_column with the \a format.
  721. Returns true on success.
  722. */
  723. bool Worksheet::writeBlank(const CellReference &row_column, const Format &format)
  724. {
  725. if (!row_column.isValid())
  726. return false;
  727. return writeBlank(row_column.row(), row_column.column(), format);
  728. }
  729. /*!
  730. Write a empty cell (\a row, \a column) with the \a format.
  731. Returns true on success.
  732. */
  733. bool Worksheet::writeBlank(int row, int column, const Format &format)
  734. {
  735. Q_D(Worksheet);
  736. if (d->checkDimensions(row, column))
  737. return false;
  738. Format fmt = format.isValid() ? format : d->cellFormat(row, column);
  739. d->workbook->styles()->addXfFormat(fmt);
  740. //Note: NumberType with an invalid QVariant value means blank.
  741. d->cellTable[row][column] = QSharedPointer<Cell>(new Cell(QVariant(), Cell::NumberType, fmt, this));
  742. return true;
  743. }
  744. /*!
  745. \overload
  746. Write a bool \a value to the cell \a row_column with the \a format.
  747. Returns true on success.
  748. */
  749. bool Worksheet::writeBool(const CellReference &row_column, bool value, const Format &format)
  750. {
  751. if (!row_column.isValid())
  752. return false;
  753. return writeBool(row_column.row(), row_column.column(), value, format);
  754. }
  755. /*!
  756. Write a bool \a value to the cell (\a row, \a column) with the \a format.
  757. Returns true on success.
  758. */
  759. bool Worksheet::writeBool(int row, int column, bool value, const Format &format)
  760. {
  761. Q_D(Worksheet);
  762. if (d->checkDimensions(row, column))
  763. return false;
  764. Format fmt = format.isValid() ? format : d->cellFormat(row, column);
  765. d->workbook->styles()->addXfFormat(fmt);
  766. d->cellTable[row][column] = QSharedPointer<Cell>(new Cell(value, Cell::BooleanType, fmt, this));
  767. return true;
  768. }
  769. /*!
  770. \overload
  771. Write a QDateTime \a dt to the cell \a row_column with the \a format.
  772. Returns true on success.
  773. */
  774. bool Worksheet::writeDateTime(const CellReference &row_column, const QDateTime &dt, const Format &format)
  775. {
  776. if (!row_column.isValid())
  777. return false;
  778. return writeDateTime(row_column.row(), row_column.column(), dt, format);
  779. }
  780. /*!
  781. Write a QDateTime \a dt to the cell (\a row, \a column) with the \a format.
  782. Returns true on success.
  783. */
  784. bool Worksheet::writeDateTime(int row, int column, const QDateTime &dt, const Format &format)
  785. {
  786. Q_D(Worksheet);
  787. if (d->checkDimensions(row, column))
  788. return false;
  789. Format fmt = format.isValid() ? format : d->cellFormat(row, column);
  790. if (!fmt.isValid() || !fmt.isDateTimeFormat())
  791. fmt.setNumberFormat(d->workbook->defaultDateFormat());
  792. d->workbook->styles()->addXfFormat(fmt);
  793. double value = datetimeToNumber(dt, d->workbook->isDate1904());
  794. d->cellTable[row][column] = QSharedPointer<Cell>(new Cell(value, Cell::NumberType, fmt, this));
  795. return true;
  796. }
  797. // dev67
  798. bool Worksheet::writeDate(const CellReference &row_column, const QDate &dt, const Format &format)
  799. {
  800. if (!row_column.isValid())
  801. return false;
  802. return writeDate(row_column.row(), row_column.column(), dt, format);
  803. }
  804. // dev67
  805. bool Worksheet::writeDate(int row, int column, const QDate &dt, const Format &format)
  806. {
  807. Q_D(Worksheet);
  808. if (d->checkDimensions(row, column))
  809. return false;
  810. Format fmt = format.isValid() ? format : d->cellFormat(row, column);
  811. if (!fmt.isValid() || !fmt.isDateTimeFormat())
  812. fmt.setNumberFormat(d->workbook->defaultDateFormat());
  813. d->workbook->styles()->addXfFormat(fmt);
  814. double value = datetimeToNumber(QDateTime(dt, QTime(0,0,0)), d->workbook->isDate1904());
  815. d->cellTable[row][column] = QSharedPointer<Cell>(new Cell(value, Cell::NumberType, fmt, this));
  816. return true;
  817. }
  818. /*!
  819. \overload
  820. Write a QTime \a t to the cell \a row_column with the \a format.
  821. Returns true on success.
  822. */
  823. bool Worksheet::writeTime(const CellReference &row_column, const QTime &t, const Format &format)
  824. {
  825. if (!row_column.isValid())
  826. return false;
  827. return writeTime(row_column.row(), row_column.column(), t, format);
  828. }
  829. /*!
  830. Write a QTime \a t to the cell (\a row, \a column) with the \a format.
  831. Returns true on success.
  832. */
  833. bool Worksheet::writeTime(int row, int column, const QTime &t, const Format &format)
  834. {
  835. Q_D(Worksheet);
  836. if (d->checkDimensions(row, column))
  837. return false;
  838. Format fmt = format.isValid() ? format : d->cellFormat(row, column);
  839. if (!fmt.isValid() || !fmt.isDateTimeFormat())
  840. fmt.setNumberFormat(QStringLiteral("hh:mm:ss"));
  841. d->workbook->styles()->addXfFormat(fmt);
  842. d->cellTable[row][column] = QSharedPointer<Cell>(new Cell(timeToNumber(t), Cell::NumberType, fmt, this));
  843. return true;
  844. }
  845. /*!
  846. \overload
  847. Write a QUrl \a url to the cell \a row_column with the given \a format \a display and \a tip.
  848. Returns true on success.
  849. */
  850. bool Worksheet::writeHyperlink(const CellReference &row_column, const QUrl &url, const Format &format, const QString &display, const QString &tip)
  851. {
  852. if (!row_column.isValid())
  853. return false;
  854. return writeHyperlink(row_column.row(), row_column.column(), url, format, display, tip);
  855. }
  856. /*!
  857. Write a QUrl \a url to the cell (\a row, \a column) with the given \a format \a display and \a tip.
  858. Returns true on success.
  859. */
  860. bool Worksheet::writeHyperlink(int row, int column, const QUrl &url, const Format &format, const QString &display, const QString &tip)
  861. {
  862. Q_D(Worksheet);
  863. if (d->checkDimensions(row, column))
  864. return false;
  865. //int error = 0;
  866. QString urlString = url.toString();
  867. //Generate proper display string
  868. QString displayString = display.isEmpty() ? urlString : display;
  869. if (displayString.startsWith(QLatin1String("mailto:")))
  870. displayString.replace(QLatin1String("mailto:"), QString());
  871. if (displayString.size() > XLSX_STRING_MAX) {
  872. displayString = displayString.left(XLSX_STRING_MAX);
  873. //error = -2;
  874. }
  875. /*
  876. Location within target. If target is a workbook (or this workbook)
  877. this shall refer to a sheet and cell or a defined name. Can also
  878. be an HTML anchor if target is HTML file.
  879. c:\temp\file.xlsx#Sheet!A1
  880. http://a.com/aaa.html#aaaaa
  881. */
  882. QString locationString;
  883. if (url.hasFragment()) {
  884. locationString = url.fragment();
  885. urlString = url.toString(QUrl::RemoveFragment);
  886. }
  887. Format fmt = format.isValid() ? format : d->cellFormat(row, column);
  888. //Given a default style for hyperlink
  889. if (!fmt.isValid()) {
  890. fmt.setVerticalAlignment(Format::AlignVCenter);
  891. fmt.setFontColor(Qt::blue);
  892. fmt.setFontUnderline(Format::FontUnderlineSingle);
  893. }
  894. d->workbook->styles()->addXfFormat(fmt);
  895. //Write the hyperlink string as normal string.
  896. d->sharedStrings()->addSharedString(displayString);
  897. d->cellTable[row][column] = QSharedPointer<Cell>(new Cell(displayString, Cell::SharedStringType, fmt, this));
  898. //Store the hyperlink data in a separate table
  899. d->urlTable[row][column] = QSharedPointer<XlsxHyperlinkData>(new XlsxHyperlinkData(XlsxHyperlinkData::External, urlString, locationString, QString(), tip));
  900. return true;
  901. }
  902. /*!
  903. * Add one DataValidation \a validation to the sheet.
  904. * Returns true on success.
  905. */
  906. bool Worksheet::addDataValidation(const DataValidation &validation)
  907. {
  908. Q_D(Worksheet);
  909. if (validation.ranges().isEmpty() || validation.validationType()==DataValidation::None)
  910. return false;
  911. d->dataValidationsList.append(validation);
  912. return true;
  913. }
  914. /*!
  915. * Add one ConditionalFormatting \a cf to the sheet.
  916. * Returns true on success.
  917. */
  918. bool Worksheet::addConditionalFormatting(const ConditionalFormatting &cf)
  919. {
  920. Q_D(Worksheet);
  921. if (cf.ranges().isEmpty())
  922. return false;
  923. for (int i=0; i<cf.d->cfRules.size(); ++i) {
  924. const QSharedPointer<XlsxCfRuleData> &rule = cf.d->cfRules[i];
  925. if (!rule->dxfFormat.isEmpty())
  926. d->workbook->styles()->addDxfFormat(rule->dxfFormat);
  927. rule->priority = 1;
  928. }
  929. d->conditionalFormattingList.append(cf);
  930. return true;
  931. }
  932. /*!
  933. * Insert an \a image at the position \a row, \a column
  934. * Returns true on success.
  935. */
  936. int Worksheet::insertImage(int row, int column, const QImage &image)
  937. {
  938. Q_D(Worksheet);
  939. int imageIndex = 0;
  940. if (image.isNull())
  941. return imageIndex;
  942. if (!d->drawing)
  943. {
  944. d->drawing = QSharedPointer<Drawing>(new Drawing(this, F_NewFromScratch));
  945. }
  946. DrawingOneCellAnchor* anchor = new DrawingOneCellAnchor(d->drawing.data(), DrawingAnchor::Picture);
  947. /*
  948. The size are expressed as English Metric Units (EMUs).
  949. EMU is 1/360 000 of centimiter.
  950. */
  951. anchor->from = XlsxMarker(row, column, 0, 0);
  952. float scaleX = 36e6f / std::max(1,image.dotsPerMeterX());
  953. float scaleY = 36e6f / std::max(1,image.dotsPerMeterY());
  954. anchor->ext = QSize( int(image.width() * scaleX), int(image.height() * scaleY) );
  955. anchor->setObjectPicture(image);
  956. imageIndex = anchor->getm_id();
  957. return imageIndex;
  958. }
  959. bool Worksheet::getImage(int imageIndex, QImage& img)
  960. {
  961. Q_D(Worksheet);
  962. if( imageIndex <= (-1) )
  963. {
  964. return false;
  965. }
  966. if ( d->drawing == nullptr )
  967. {
  968. return false;
  969. }
  970. int realImageIndex = imageIndex - 1; // minus one
  971. DrawingAnchor* danchor = d->drawing->anchors.at( realImageIndex );
  972. // QSharedPointer<Drawing> // for multithread
  973. if ( danchor == nullptr )
  974. {
  975. return false;
  976. }
  977. bool ret= danchor->getObjectPicture(img);
  978. return ret;
  979. }
  980. bool Worksheet::getImage(int row, int column, QImage &img)
  981. {
  982. Q_D(Worksheet);
  983. if ( d->drawing == nullptr )
  984. {
  985. return false;
  986. }
  987. for(int i = 0; i < d->drawing->anchors.size(); i++)
  988. {
  989. if(d->drawing->anchors[i]->row() == row && d->drawing->anchors[i]->col() == column)
  990. {
  991. DrawingAnchor* danchor = d->drawing->anchors.at( i );
  992. if ( danchor == nullptr )
  993. {
  994. return false;
  995. }
  996. bool ret= danchor->getObjectPicture(img);
  997. return ret;
  998. }
  999. }
  1000. return false;
  1001. }
  1002. uint Worksheet::getImageCount()
  1003. {
  1004. Q_D(Worksheet);
  1005. if ( d->drawing == nullptr )
  1006. {
  1007. return false;
  1008. }
  1009. int size = d->drawing->anchors.size();
  1010. return uint(size);
  1011. }
  1012. /*!
  1013. * Creates an chart with the given \a size and insert
  1014. * at the position \a row, \a column.
  1015. * The chart will be returned.
  1016. */
  1017. Chart *Worksheet::insertChart(int row, int column, const QSize &size)
  1018. {
  1019. Q_D(Worksheet);
  1020. if (!d->drawing)
  1021. d->drawing = QSharedPointer<Drawing>(new Drawing(this, F_NewFromScratch));
  1022. DrawingOneCellAnchor *anchor = new DrawingOneCellAnchor(d->drawing.data(), DrawingAnchor::Picture);
  1023. /*
  1024. The size are expressed as English Metric Units (EMUs). There are
  1025. 12,700 EMUs per point. Therefore, 12,700 * 3 /4 = 9,525 EMUs per
  1026. pixel
  1027. */
  1028. anchor->from = XlsxMarker(row, column, 0, 0);
  1029. anchor->ext = size * 9525;
  1030. QSharedPointer<Chart> chart = QSharedPointer<Chart>(new Chart(this, F_NewFromScratch));
  1031. anchor->setObjectGraphicFrame(chart);
  1032. return chart.data();
  1033. }
  1034. /*!
  1035. Merge a \a range of cells. The first cell should contain the data and the others should
  1036. be blank. All cells will be applied the same style if a valid \a format is given.
  1037. Returns true on success.
  1038. \note All cells except the top-left one will be cleared.
  1039. */
  1040. bool Worksheet::mergeCells(const CellRange &range, const Format &format)
  1041. {
  1042. Q_D(Worksheet);
  1043. if (range.rowCount() < 2 && range.columnCount() < 2)
  1044. return false;
  1045. if (d->checkDimensions(range.firstRow(), range.firstColumn()))
  1046. return false;
  1047. if (format.isValid())
  1048. {
  1049. d->workbook->styles()->addXfFormat(format);
  1050. }
  1051. for (int row = range.firstRow(); row <= range.lastRow(); ++row)
  1052. {
  1053. for (int col = range.firstColumn(); col <= range.lastColumn(); ++col)
  1054. {
  1055. if (row == range.firstRow() && col == range.firstColumn())
  1056. {
  1057. Cell *cell = cellAt(row, col);
  1058. if (cell)
  1059. {
  1060. if (format.isValid())
  1061. cell->d_ptr->format = format;
  1062. }
  1063. else
  1064. {
  1065. writeBlank(row, col, format);
  1066. }
  1067. }
  1068. else
  1069. {
  1070. writeBlank(row, col, format);
  1071. }
  1072. }
  1073. }
  1074. d->merges.append(range);
  1075. return true;
  1076. }
  1077. /*!
  1078. Unmerge the cells in the \a range. Returns true on success.
  1079. */
  1080. bool Worksheet::unmergeCells(const CellRange &range)
  1081. {
  1082. Q_D(Worksheet);
  1083. return d->merges.removeOne(range);
  1084. }
  1085. /*!
  1086. Returns all the merged cells.
  1087. */
  1088. QList<CellRange> Worksheet::mergedCells() const
  1089. {
  1090. Q_D(const Worksheet);
  1091. // dev57
  1092. QList<CellRange> emptyList;
  1093. if ( d->type == AbstractSheet::ST_WorkSheet )
  1094. {
  1095. return d->merges;
  1096. }
  1097. else if ( d->type == AbstractSheet::ST_ChartSheet )
  1098. {
  1099. }
  1100. else if ( d->type == AbstractSheet::ST_DialogSheet )
  1101. {
  1102. }
  1103. else if ( d->type == AbstractSheet::ST_MacroSheet )
  1104. {
  1105. }
  1106. else
  1107. { // undefined
  1108. }
  1109. return emptyList;
  1110. }
  1111. /*!
  1112. * \internal
  1113. */
  1114. void Worksheet::saveToXmlFile(QIODevice *device) const
  1115. {
  1116. Q_D(const Worksheet);
  1117. d->relationships->clear();
  1118. QXmlStreamWriter writer(device);
  1119. writer.writeStartDocument(QStringLiteral("1.0"), true);
  1120. writer.writeStartElement(QStringLiteral("worksheet"));
  1121. writer.writeAttribute(QStringLiteral("xmlns"), QStringLiteral("http://schemas.openxmlformats.org/spreadsheetml/2006/main"));
  1122. writer.writeAttribute(QStringLiteral("xmlns:r"), QStringLiteral("http://schemas.openxmlformats.org/officeDocument/2006/relationships"));
  1123. //for Excel 2010
  1124. // writer.writeAttribute("xmlns:mc", "http://schemas.openxmlformats.org/markup-compatibility/2006");
  1125. // writer.writeAttribute("xmlns:x14ac", "http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac");
  1126. // writer.writeAttribute("mc:Ignorable", "x14ac");
  1127. writer.writeStartElement(QStringLiteral("dimension"));
  1128. writer.writeAttribute(QStringLiteral("ref"), d->generateDimensionString());
  1129. writer.writeEndElement();//dimension
  1130. writer.writeStartElement(QStringLiteral("sheetViews"));
  1131. writer.writeStartElement(QStringLiteral("sheetView"));
  1132. if (d->windowProtection)
  1133. writer.writeAttribute(QStringLiteral("windowProtection"), QStringLiteral("1"));
  1134. if (d->showFormulas)
  1135. writer.writeAttribute(QStringLiteral("showFormulas"), QStringLiteral("1"));
  1136. if (!d->showGridLines)
  1137. writer.writeAttribute(QStringLiteral("showGridLines"), QStringLiteral("0"));
  1138. if (!d->showRowColHeaders)
  1139. writer.writeAttribute(QStringLiteral("showRowColHeaders"), QStringLiteral("0"));
  1140. if (!d->showZeros)
  1141. writer.writeAttribute(QStringLiteral("showZeros"), QStringLiteral("0"));
  1142. if (d->rightToLeft)
  1143. writer.writeAttribute(QStringLiteral("rightToLeft"), QStringLiteral("1"));
  1144. if (d->tabSelected)
  1145. writer.writeAttribute(QStringLiteral("tabSelected"), QStringLiteral("1"));
  1146. if (!d->showRuler)
  1147. writer.writeAttribute(QStringLiteral("showRuler"), QStringLiteral("0"));
  1148. if (!d->showOutlineSymbols)
  1149. writer.writeAttribute(QStringLiteral("showOutlineSymbols"), QStringLiteral("0"));
  1150. if (!d->showWhiteSpace)
  1151. writer.writeAttribute(QStringLiteral("showWhiteSpace"), QStringLiteral("0"));
  1152. writer.writeAttribute(QStringLiteral("workbookViewId"), QStringLiteral("0"));
  1153. writer.writeEndElement();//sheetView
  1154. writer.writeEndElement();//sheetViews
  1155. writer.writeStartElement(QStringLiteral("sheetFormatPr"));
  1156. writer.writeAttribute(QStringLiteral("defaultRowHeight"), QString::number(d->default_row_height));
  1157. if (d->default_row_height != 15)
  1158. writer.writeAttribute(QStringLiteral("customHeight"), QStringLiteral("1"));
  1159. if (d->default_row_zeroed)
  1160. writer.writeAttribute(QStringLiteral("zeroHeight"), QStringLiteral("1"));
  1161. if (d->outline_row_level)
  1162. writer.writeAttribute(QStringLiteral("outlineLevelRow"), QString::number(d->outline_row_level));
  1163. if (d->outline_col_level)
  1164. writer.writeAttribute(QStringLiteral("outlineLevelCol"), QString::number(d->outline_col_level));
  1165. //for Excel 2010
  1166. // writer.writeAttribute("x14ac:dyDescent", "0.25");
  1167. writer.writeEndElement();//sheetFormatPr
  1168. if (!d->colsInfo.isEmpty())
  1169. {
  1170. writer.writeStartElement(QStringLiteral("cols"));
  1171. QMapIterator<int, QSharedPointer<XlsxColumnInfo> > it(d->colsInfo);
  1172. while (it.hasNext())
  1173. {
  1174. it.next();
  1175. QSharedPointer<XlsxColumnInfo> col_info = it.value();
  1176. writer.writeStartElement(QStringLiteral("col"));
  1177. writer.writeAttribute(QStringLiteral("min"), QString::number(col_info->firstColumn));
  1178. writer.writeAttribute(QStringLiteral("max"), QString::number(col_info->lastColumn));
  1179. if (col_info->width)
  1180. writer.writeAttribute(QStringLiteral("width"), QString::number(col_info->width, 'g', 15));
  1181. if (!col_info->format.isEmpty())
  1182. writer.writeAttribute(QStringLiteral("style"), QString::number(col_info->format.xfIndex()));
  1183. if (col_info->hidden)
  1184. writer.writeAttribute(QStringLiteral("hidden"), QStringLiteral("1"));
  1185. if (col_info->width)
  1186. writer.writeAttribute(QStringLiteral("customWidth"), QStringLiteral("1"));
  1187. if (col_info->outlineLevel)
  1188. writer.writeAttribute(QStringLiteral("outlineLevel"), QString::number(col_info->outlineLevel));
  1189. if (col_info->collapsed)
  1190. writer.writeAttribute(QStringLiteral("collapsed"), QStringLiteral("1"));
  1191. writer.writeEndElement();//col
  1192. }
  1193. writer.writeEndElement();//cols
  1194. }
  1195. writer.writeStartElement(QStringLiteral("sheetData"));
  1196. if (d->dimension.isValid())
  1197. d->saveXmlSheetData(writer);
  1198. writer.writeEndElement();//sheetData
  1199. d->saveXmlMergeCells(writer);
  1200. for (const ConditionalFormatting &cf : d->conditionalFormattingList)
  1201. cf.saveToXml(writer);
  1202. d->saveXmlDataValidations(writer);
  1203. //{{ liufeijin : write pagesettings add by liufeijin 20181028
  1204. // fixed by j2doll [dev18]
  1205. // NOTE: empty element is not problem. but, empty structure of element is not parsed by Excel.
  1206. // pageMargins
  1207. if ( false == d->PMleft.isEmpty() &&
  1208. false == d->PMright.isEmpty() &&
  1209. false == d->PMtop.isEmpty() &&
  1210. false == d->PMbotton.isEmpty() &&
  1211. false == d->PMheader.isEmpty() &&
  1212. false == d->PMfooter.isEmpty()
  1213. )
  1214. {
  1215. writer.writeStartElement(QStringLiteral("pageMargins"));
  1216. writer.writeAttribute(QStringLiteral("left"), d->PMleft );
  1217. writer.writeAttribute(QStringLiteral("right"), d->PMright );
  1218. writer.writeAttribute(QStringLiteral("top"), d->PMtop );
  1219. writer.writeAttribute(QStringLiteral("bottom"), d->PMbotton );
  1220. writer.writeAttribute(QStringLiteral("header"), d->PMheader );
  1221. writer.writeAttribute(QStringLiteral("footer"), d->PMfooter );
  1222. writer.writeEndElement(); // pageMargins
  1223. }
  1224. // dev57
  1225. if ( !d->Prid.isEmpty() )
  1226. {
  1227. writer.writeStartElement(QStringLiteral("pageSetup")); // pageSetup
  1228. writer.writeAttribute(QStringLiteral("r:id"), d->Prid);
  1229. if ( !d->PverticalDpi.isEmpty() )
  1230. {
  1231. writer.writeAttribute(QStringLiteral("verticalDpi"), d->PverticalDpi);
  1232. }
  1233. if ( !d->PhorizontalDpi.isEmpty() )
  1234. {
  1235. writer.writeAttribute(QStringLiteral("horizontalDpi"), d->PhorizontalDpi);
  1236. }
  1237. if ( !d->PuseFirstPageNumber.isEmpty() )
  1238. {
  1239. writer.writeAttribute(QStringLiteral("useFirstPageNumber"), d->PuseFirstPageNumber);
  1240. }
  1241. if ( !d->PfirstPageNumber.isEmpty() )
  1242. {
  1243. writer.writeAttribute(QStringLiteral("firstPageNumber"), d->PfirstPageNumber);
  1244. }
  1245. if ( !d->Pscale.isEmpty() )
  1246. {
  1247. writer.writeAttribute(QStringLiteral("scale"), d->Pscale);
  1248. }
  1249. if ( !d->PpaperSize.isEmpty() )
  1250. {
  1251. writer.writeAttribute(QStringLiteral("paperSize"), d->PpaperSize);
  1252. }
  1253. if ( !d->Porientation.isEmpty() )
  1254. {
  1255. writer.writeAttribute(QStringLiteral("orientation"), d->Porientation);
  1256. }
  1257. if(!d->Pcopies.isEmpty())
  1258. {
  1259. writer.writeAttribute(QStringLiteral("copies"), d->Pcopies);
  1260. }
  1261. writer.writeEndElement(); // pageSetup
  1262. } // if ( !d->Prid.isEmpty() )
  1263. // headerFooter
  1264. if( !(d->MoodFooter.isNull()) ||
  1265. !(d->MoodFooter.isNull()) )
  1266. {
  1267. writer.writeStartElement(QStringLiteral("headerFooter")); // headerFooter
  1268. if ( !d->MoodalignWithMargins.isEmpty() )
  1269. {
  1270. writer.writeAttribute(QStringLiteral("alignWithMargins"), d->MoodalignWithMargins);
  1271. }
  1272. if ( !d->ModdHeader.isNull() )
  1273. {
  1274. writer.writeStartElement(QStringLiteral("oddHeader"));
  1275. writer.writeCharacters(d->ModdHeader);
  1276. writer.writeEndElement(); // oddHeader
  1277. }
  1278. if ( !d->MoodFooter.isNull() )
  1279. {
  1280. writer.writeTextElement(QStringLiteral("oddFooter"), d->MoodFooter);
  1281. }
  1282. writer.writeEndElement(); // headerFooter
  1283. }
  1284. d->saveXmlHyperlinks(writer);
  1285. d->saveXmlDrawings(writer);
  1286. writer.writeEndElement(); // worksheet
  1287. writer.writeEndDocument();
  1288. }
  1289. //{{ liufeijin
  1290. bool Worksheet::setStartPage(int spagen)
  1291. {
  1292. Q_D(Worksheet);
  1293. d->PfirstPageNumber=QString::number(spagen);
  1294. return true;
  1295. }
  1296. //}}
  1297. void WorksheetPrivate::saveXmlSheetData(QXmlStreamWriter &writer) const
  1298. {
  1299. calculateSpans();
  1300. for (int row_num = dimension.firstRow(); row_num <= dimension.lastRow(); row_num++)
  1301. {
  1302. auto ctIt = cellTable.constFind(row_num);
  1303. auto riIt = rowsInfo.constFind(row_num);
  1304. if (ctIt == cellTable.constEnd() && riIt == rowsInfo.constEnd() && !comments.contains(row_num))
  1305. {
  1306. //Only process rows with cell data / comments / formatting
  1307. continue;
  1308. }
  1309. int span_index = (row_num-1) / 16;
  1310. QString span;
  1311. auto rsIt = row_spans.constFind(span_index);
  1312. if (rsIt != row_spans.constEnd())
  1313. span = rsIt.value();
  1314. writer.writeStartElement(QStringLiteral("row"));
  1315. writer.writeAttribute(QStringLiteral("r"), QString::number(row_num));
  1316. if (!span.isEmpty())
  1317. writer.writeAttribute(QStringLiteral("spans"), span);
  1318. if (riIt != rowsInfo.constEnd())
  1319. {
  1320. QSharedPointer<XlsxRowInfo> rowInfo = riIt.value();
  1321. if (!rowInfo->format.isEmpty())
  1322. {
  1323. writer.writeAttribute(QStringLiteral("s"), QString::number(rowInfo->format.xfIndex()));
  1324. writer.writeAttribute(QStringLiteral("customFormat"), QStringLiteral("1"));
  1325. }
  1326. //!Todo: support customHeight from info struct
  1327. //!Todo: where does this magic number '15' come from?
  1328. if (rowInfo->customHeight) {
  1329. writer.writeAttribute(QStringLiteral("ht"), QString::number(rowInfo->height));
  1330. writer.writeAttribute(QStringLiteral("customHeight"), QStringLiteral("1"));
  1331. } else {
  1332. writer.writeAttribute(QStringLiteral("customHeight"), QStringLiteral("0"));
  1333. }
  1334. if (rowInfo->hidden)
  1335. writer.writeAttribute(QStringLiteral("hidden"), QStringLiteral("1"));
  1336. if (rowInfo->outlineLevel > 0)
  1337. writer.writeAttribute(QStringLiteral("outlineLevel"), QString::number(rowInfo->outlineLevel));
  1338. if (rowInfo->collapsed)
  1339. writer.writeAttribute(QStringLiteral("collapsed"), QStringLiteral("1"));
  1340. }
  1341. //Write cell data if row contains filled cells
  1342. if (ctIt != cellTable.constEnd())
  1343. {
  1344. for (int col_num = dimension.firstColumn(); col_num <= dimension.lastColumn(); col_num++)
  1345. {
  1346. if (ctIt->contains(col_num))
  1347. {
  1348. saveXmlCellData(writer, row_num, col_num, (*ctIt)[col_num]);
  1349. }
  1350. }
  1351. }
  1352. writer.writeEndElement(); //row
  1353. }
  1354. }
  1355. void WorksheetPrivate::saveXmlCellData(QXmlStreamWriter &writer, int row, int col, QSharedPointer<Cell> cell) const
  1356. {
  1357. Q_Q(const Worksheet);
  1358. //This is the innermost loop so efficiency is important.
  1359. QString cell_pos = CellReference(row, col).toString();
  1360. writer.writeStartElement(QStringLiteral("c"));
  1361. writer.writeAttribute(QStringLiteral("r"), cell_pos);
  1362. QMap<int, QSharedPointer<XlsxRowInfo> >::ConstIterator rIt;
  1363. QMap<int, QSharedPointer<XlsxColumnInfo> >::ConstIterator cIt;
  1364. //Style used by the cell, row or col
  1365. if (!cell->format().isEmpty())
  1366. writer.writeAttribute(QStringLiteral("s"), QString::number(cell->format().xfIndex()));
  1367. else if ((rIt = rowsInfo.constFind(row)) != rowsInfo.constEnd() && !(*rIt)->format.isEmpty())
  1368. writer.writeAttribute(QStringLiteral("s"), QString::number((*rIt)->format.xfIndex()));
  1369. else if ((cIt = colsInfoHelper.constFind(col)) != colsInfoHelper.constEnd() && !(*cIt)->format.isEmpty())
  1370. writer.writeAttribute(QStringLiteral("s"), QString::number((*cIt)->format.xfIndex()));
  1371. if (cell->cellType() == Cell::SharedStringType) // 's'
  1372. {
  1373. int sst_idx;
  1374. if (cell->isRichString())
  1375. sst_idx = sharedStrings()->getSharedStringIndex(cell->d_ptr->richString);
  1376. else
  1377. sst_idx = sharedStrings()->getSharedStringIndex(cell->value().toString());
  1378. writer.writeAttribute(QStringLiteral("t"), QStringLiteral("s"));
  1379. writer.writeTextElement(QStringLiteral("v"), QString::number(sst_idx));
  1380. }
  1381. else if (cell->cellType() == Cell::InlineStringType) // 'inlineStr'
  1382. {
  1383. writer.writeAttribute(QStringLiteral("t"), QStringLiteral("inlineStr"));
  1384. writer.writeStartElement(QStringLiteral("is"));
  1385. if (cell->isRichString())
  1386. {
  1387. //Rich text string
  1388. RichString string = cell->d_ptr->richString;
  1389. for (int i=0; i<string.fragmentCount(); ++i)
  1390. {
  1391. writer.writeStartElement(QStringLiteral("r"));
  1392. if (string.fragmentFormat(i).hasFontData())
  1393. {
  1394. writer.writeStartElement(QStringLiteral("rPr"));
  1395. //:Todo
  1396. writer.writeEndElement();// rPr
  1397. }
  1398. writer.writeStartElement(QStringLiteral("t"));
  1399. if (isSpaceReserveNeeded(string.fragmentText(i)))
  1400. writer.writeAttribute(QStringLiteral("xml:space"), QStringLiteral("preserve"));
  1401. writer.writeCharacters(string.fragmentText(i));
  1402. writer.writeEndElement();// t
  1403. writer.writeEndElement(); // r
  1404. }
  1405. }
  1406. else
  1407. {
  1408. writer.writeStartElement(QStringLiteral("t"));
  1409. QString string = cell->value().toString();
  1410. if (isSpaceReserveNeeded(string))
  1411. writer.writeAttribute(QStringLiteral("xml:space"), QStringLiteral("preserve"));
  1412. writer.writeCharacters(string);
  1413. writer.writeEndElement(); // t
  1414. }
  1415. writer.writeEndElement();//is
  1416. }
  1417. else if (cell->cellType() == Cell::NumberType) // 'n'
  1418. {
  1419. writer.writeAttribute(QStringLiteral("t"), QStringLiteral("n")); // dev67
  1420. if (cell->hasFormula())
  1421. {
  1422. QString strFormula = cell->formula().d->formula;
  1423. Q_UNUSED(strFormula);
  1424. cell->formula().saveToXml(writer);
  1425. }
  1426. if (cell->value().isValid())
  1427. { //note that, invalid value means 'v' is blank
  1428. double value = cell->value().toDouble();
  1429. writer.writeTextElement(QStringLiteral("v"), QString::number(value, 'g', 15));
  1430. }
  1431. }
  1432. else if (cell->cellType() == Cell::StringType) // 'str'
  1433. {
  1434. writer.writeAttribute(QStringLiteral("t"), QStringLiteral("str"));
  1435. if (cell->hasFormula())
  1436. cell->formula().saveToXml(writer);
  1437. writer.writeTextElement(QStringLiteral("v"), cell->value().toString());
  1438. }
  1439. else if (cell->cellType() == Cell::BooleanType) // 'b'
  1440. {
  1441. writer.writeAttribute(QStringLiteral("t"), QStringLiteral("b"));
  1442. // dev34
  1443. if (cell->hasFormula())
  1444. {
  1445. QString strFormula = cell->formula().d->formula;
  1446. Q_UNUSED(strFormula);
  1447. cell->formula().saveToXml(writer);
  1448. }
  1449. writer.writeTextElement(QStringLiteral("v"), cell->value().toBool() ? QStringLiteral("1") : QStringLiteral("0"));
  1450. }
  1451. else if (cell->cellType() == Cell::DateType) // 'd'
  1452. {
  1453. // dev67
  1454. double num = cell->value().toDouble();
  1455. bool is1904 = q->workbook()->isDate1904();
  1456. if (!is1904 && num > 60) // for mac os excel
  1457. {
  1458. num = num - 1;
  1459. }
  1460. // number type. see for 18.18.11 ST_CellType (Cell Type) more information.
  1461. writer.writeAttribute(QStringLiteral("t"), QStringLiteral("n"));
  1462. writer.writeTextElement(QStringLiteral("v"), cell->value().toString() );
  1463. }
  1464. else if (cell->cellType() == Cell::ErrorType) // 'e'
  1465. {
  1466. writer.writeAttribute(QStringLiteral("t"), QStringLiteral("e"));
  1467. writer.writeTextElement(QStringLiteral("v"), cell->value().toString() );
  1468. }
  1469. else // if (cell->cellType() == Cell::CustomType)
  1470. {
  1471. // custom type
  1472. if (cell->hasFormula())
  1473. {
  1474. QString strFormula = cell->formula().d->formula;
  1475. Q_UNUSED(strFormula);
  1476. cell->formula().saveToXml(writer);
  1477. }
  1478. if (cell->value().isValid())
  1479. { //note that, invalid value means 'v' is blank
  1480. double value = cell->value().toDouble();
  1481. writer.writeTextElement(QStringLiteral("v"), QString::number(value, 'g', 15));
  1482. }
  1483. }
  1484. writer.writeEndElement(); // c
  1485. }
  1486. void WorksheetPrivate::saveXmlMergeCells(QXmlStreamWriter &writer) const
  1487. {
  1488. if (merges.isEmpty())
  1489. return;
  1490. writer.writeStartElement(QStringLiteral("mergeCells"));
  1491. writer.writeAttribute(QStringLiteral("count"), QString::number(merges.size()));
  1492. for (const CellRange &range : merges)
  1493. {
  1494. writer.writeEmptyElement(QStringLiteral("mergeCell"));
  1495. writer.writeAttribute(QStringLiteral("ref"), range.toString());
  1496. }
  1497. writer.writeEndElement(); //mergeCells
  1498. }
  1499. void WorksheetPrivate::saveXmlDataValidations(QXmlStreamWriter &writer) const
  1500. {
  1501. if (dataValidationsList.isEmpty())
  1502. return;
  1503. writer.writeStartElement(QStringLiteral("dataValidations"));
  1504. writer.writeAttribute(QStringLiteral("count"), QString::number(dataValidationsList.size()));
  1505. for (const DataValidation &validation : dataValidationsList)
  1506. validation.saveToXml(writer);
  1507. writer.writeEndElement(); //dataValidations
  1508. }
  1509. void WorksheetPrivate::saveXmlHyperlinks(QXmlStreamWriter &writer) const
  1510. {
  1511. if (urlTable.isEmpty())
  1512. return;
  1513. writer.writeStartElement(QStringLiteral("hyperlinks"));
  1514. QMapIterator<int, QMap< int, QSharedPointer<XlsxHyperlinkData> > > it(urlTable);
  1515. while (it.hasNext())
  1516. {
  1517. it.next();
  1518. int row = it.key();
  1519. QMapIterator< int, QSharedPointer<XlsxHyperlinkData> > it2(it.value());
  1520. while (it2.hasNext())
  1521. {
  1522. it2.next();
  1523. int col = it2.key();
  1524. QSharedPointer<XlsxHyperlinkData> data = it2.value();
  1525. QString ref = CellReference(row, col).toString();
  1526. // dev57
  1527. // writer.writeEmptyElement(QStringLiteral("hyperlink"));
  1528. writer.writeStartElement(QStringLiteral("hyperlink"));
  1529. writer.writeAttribute(QStringLiteral("ref"), ref); // required field
  1530. if ( data->linkType == XlsxHyperlinkData::External )
  1531. {
  1532. // Update relationships
  1533. relationships->addWorksheetRelationship(QStringLiteral("/hyperlink"), data->target, QStringLiteral("External"));
  1534. writer.writeAttribute(QStringLiteral("r:id"), QStringLiteral("rId%1").arg(relationships->count()));
  1535. }
  1536. if (!data->location.isEmpty())
  1537. {
  1538. writer.writeAttribute(QStringLiteral("location"), data->location);
  1539. }
  1540. if (!data->display.isEmpty())
  1541. {
  1542. writer.writeAttribute(QStringLiteral("display"), data->display);
  1543. }
  1544. if (!data->tooltip.isEmpty())
  1545. {
  1546. writer.writeAttribute(QStringLiteral("tooltip"), data->tooltip);
  1547. }
  1548. // dev57
  1549. writer.writeEndElement(); // hyperlink
  1550. }
  1551. }
  1552. writer.writeEndElement(); // hyperlinks
  1553. }
  1554. void WorksheetPrivate::saveXmlDrawings(QXmlStreamWriter &writer) const
  1555. {
  1556. if (!drawing)
  1557. return;
  1558. int idx = workbook->drawings().indexOf(drawing.data());
  1559. relationships->addWorksheetRelationship(QStringLiteral("/drawing"), QStringLiteral("../drawings/drawing%1.xml").arg(idx+1));
  1560. writer.writeEmptyElement(QStringLiteral("drawing"));
  1561. writer.writeAttribute(QStringLiteral("r:id"), QStringLiteral("rId%1").arg(relationships->count()));
  1562. }
  1563. void WorksheetPrivate::splitColsInfo(int colFirst, int colLast)
  1564. {
  1565. // Split current columnInfo, for example, if "A:H" has been set,
  1566. // we are trying to set "B:D", there should be "A", "B:D", "E:H".
  1567. // This will be more complex if we try to set "C:F" after "B:D".
  1568. {
  1569. QMapIterator<int, QSharedPointer<XlsxColumnInfo> > it(colsInfo);
  1570. while (it.hasNext()) {
  1571. it.next();
  1572. QSharedPointer<XlsxColumnInfo> info = it.value();
  1573. if (colFirst > info->firstColumn && colFirst <= info->lastColumn) {
  1574. //split the range,
  1575. QSharedPointer<XlsxColumnInfo> info2(new XlsxColumnInfo(*info));
  1576. info->lastColumn = colFirst - 1;
  1577. info2->firstColumn = colFirst;
  1578. colsInfo.insert(colFirst, info2);
  1579. for (int c = info2->firstColumn; c <= info2->lastColumn; ++c)
  1580. colsInfoHelper[c] = info2;
  1581. break;
  1582. }
  1583. }
  1584. }
  1585. {
  1586. QMapIterator<int, QSharedPointer<XlsxColumnInfo> > it(colsInfo);
  1587. while (it.hasNext()) {
  1588. it.next();
  1589. QSharedPointer<XlsxColumnInfo> info = it.value();
  1590. if (colLast >= info->firstColumn && colLast < info->lastColumn) {
  1591. QSharedPointer<XlsxColumnInfo> info2(new XlsxColumnInfo(*info));
  1592. info->lastColumn = colLast;
  1593. info2->firstColumn = colLast + 1;
  1594. colsInfo.insert(colLast + 1, info2);
  1595. for (int c = info2->firstColumn; c <= info2->lastColumn; ++c)
  1596. colsInfoHelper[c] = info2;
  1597. break;
  1598. }
  1599. }
  1600. }
  1601. }
  1602. bool WorksheetPrivate::isColumnRangeValid(int colFirst, int colLast)
  1603. {
  1604. bool ignore_row = true;
  1605. bool ignore_col = false;
  1606. if (colFirst > colLast)
  1607. return false;
  1608. if (checkDimensions(1, colLast, ignore_row, ignore_col))
  1609. return false;
  1610. if (checkDimensions(1, colFirst, ignore_row, ignore_col))
  1611. return false;
  1612. return true;
  1613. }
  1614. QList<int> WorksheetPrivate ::getColumnIndexes(int colFirst, int colLast)
  1615. {
  1616. splitColsInfo(colFirst, colLast);
  1617. QList<int> nodes;
  1618. nodes.append(colFirst);
  1619. for (int col = colFirst; col <= colLast; ++col)
  1620. {
  1621. auto it = colsInfo.constFind(col);
  1622. if (it != colsInfo.constEnd())
  1623. {
  1624. if (nodes.last() != col)
  1625. nodes.append(col);
  1626. int nextCol = (*it)->lastColumn + 1;
  1627. if (nextCol <= colLast)
  1628. nodes.append(nextCol);
  1629. }
  1630. }
  1631. return nodes;
  1632. }
  1633. /*!
  1634. Sets width in characters of a \a range of columns to \a width.
  1635. Returns true on success.
  1636. */
  1637. bool Worksheet::setColumnWidth(const CellRange &range, double width)
  1638. {
  1639. if (!range.isValid())
  1640. return false;
  1641. return setColumnWidth(range.firstColumn(), range.lastColumn(), width);
  1642. }
  1643. /*!
  1644. Sets format property of a \a range of columns to \a format. Columns are 1-indexed.
  1645. Returns true on success.
  1646. */
  1647. bool Worksheet::setColumnFormat(const CellRange& range, const Format &format)
  1648. {
  1649. if (!range.isValid())
  1650. return false;
  1651. return setColumnFormat(range.firstColumn(), range.lastColumn(), format);
  1652. }
  1653. /*!
  1654. Sets hidden property of a \a range of columns to \a hidden. Columns are 1-indexed.
  1655. Hidden columns are not visible.
  1656. Returns true on success.
  1657. */
  1658. bool Worksheet::setColumnHidden(const CellRange &range, bool hidden)
  1659. {
  1660. if (!range.isValid())
  1661. return false;
  1662. return setColumnHidden(range.firstColumn(), range.lastColumn(), hidden);
  1663. }
  1664. /*!
  1665. Sets width in characters for columns [\a colFirst, \a colLast] to \a width.
  1666. Columns are 1-indexed.
  1667. Returns true on success.
  1668. */
  1669. bool Worksheet::setColumnWidth(int colFirst, int colLast, double width)
  1670. {
  1671. Q_D(Worksheet);
  1672. const QList <QSharedPointer<XlsxColumnInfo> > columnInfoList = d->getColumnInfoList(colFirst, colLast);
  1673. for (const QSharedPointer<XlsxColumnInfo> &columnInfo : columnInfoList)
  1674. {
  1675. columnInfo->width = width;
  1676. }
  1677. return (columnInfoList.count() > 0);
  1678. }
  1679. /*!
  1680. Sets format property of a range of columns [\a colFirst, \a colLast] to \a format.
  1681. Columns are 1-indexed.
  1682. Returns true on success.
  1683. */
  1684. bool Worksheet::setColumnFormat(int colFirst, int colLast, const Format &format)
  1685. {
  1686. Q_D(Worksheet);
  1687. const QList <QSharedPointer<XlsxColumnInfo> > columnInfoList = d->getColumnInfoList(colFirst, colLast);
  1688. for (const QSharedPointer<XlsxColumnInfo> &columnInfo : columnInfoList)
  1689. columnInfo->format = format;
  1690. if(columnInfoList.count() > 0) {
  1691. d->workbook->styles()->addXfFormat(format);
  1692. return true;
  1693. }
  1694. return false;
  1695. }
  1696. /*!
  1697. Sets hidden property of a range of columns [\a colFirst, \a colLast] to \a hidden.
  1698. Columns are 1-indexed. Returns true on success.
  1699. */
  1700. bool Worksheet::setColumnHidden(int colFirst, int colLast, bool hidden)
  1701. {
  1702. Q_D(Worksheet);
  1703. const QList <QSharedPointer<XlsxColumnInfo> > columnInfoList = d->getColumnInfoList(colFirst, colLast);
  1704. for (const QSharedPointer<XlsxColumnInfo> &columnInfo : columnInfoList)
  1705. columnInfo->hidden = hidden;
  1706. return (columnInfoList.count() > 0);
  1707. }
  1708. /*!
  1709. Returns width of the \a column in characters of the normal font. Columns are 1-indexed.
  1710. */
  1711. double Worksheet::columnWidth(int column)
  1712. {
  1713. Q_D(Worksheet);
  1714. QList< QSharedPointer<XlsxColumnInfo> > columnInfoList = d->getColumnInfoList(column, column);
  1715. // [dev54]
  1716. if ( columnInfoList.size() == 0 )
  1717. {
  1718. // column information is not found
  1719. // qDebug() << "[debug]" << __FUNCTION__ << "column (info) is not found. " << column;
  1720. }
  1721. if (columnInfoList.count() == 1)
  1722. {
  1723. // column information is found
  1724. // qDebug() << "[debug]" << __FUNCTION__ << "column (info) is found. " << column << oneColWidth;
  1725. double oneColWidth = columnInfoList.at(0)->width;
  1726. bool isSetWidth = columnInfoList.at(0)->isSetWidth;
  1727. if ( isSetWidth )
  1728. {
  1729. return oneColWidth;
  1730. }
  1731. }
  1732. // use default width
  1733. double defaultColWidth = d->sheetFormatProps.defaultColWidth;
  1734. return defaultColWidth;
  1735. }
  1736. /*!
  1737. Returns formatting of the \a column. Columns are 1-indexed.
  1738. */
  1739. Format Worksheet::columnFormat(int column)
  1740. {
  1741. Q_D(Worksheet);
  1742. QList <QSharedPointer<XlsxColumnInfo> > columnInfoList = d->getColumnInfoList(column, column);
  1743. if (columnInfoList.count() == 1)
  1744. return columnInfoList.at(0)->format;
  1745. return Format();
  1746. }
  1747. /*!
  1748. Returns true if \a column is hidden. Columns are 1-indexed.
  1749. */
  1750. bool Worksheet::isColumnHidden(int column)
  1751. {
  1752. Q_D(Worksheet);
  1753. QList <QSharedPointer<XlsxColumnInfo> > columnInfoList = d->getColumnInfoList(column, column);
  1754. if (columnInfoList.count() == 1)
  1755. return columnInfoList.at(0)->hidden;
  1756. return false;
  1757. }
  1758. /*!
  1759. Sets the \a height of the rows including and between \a rowFirst and \a rowLast.
  1760. Row height measured in point size.
  1761. Rows are 1-indexed.
  1762. Returns true if success.
  1763. */
  1764. bool Worksheet::setRowHeight(int rowFirst,int rowLast, double height)
  1765. {
  1766. Q_D(Worksheet);
  1767. const QList <QSharedPointer<XlsxRowInfo> > rowInfoList = d->getRowInfoList(rowFirst,rowLast);
  1768. for (const QSharedPointer<XlsxRowInfo> &rowInfo : rowInfoList) {
  1769. rowInfo->height = height;
  1770. rowInfo->customHeight = true;
  1771. }
  1772. return rowInfoList.count() > 0;
  1773. }
  1774. /*!
  1775. Sets the \a format of the rows including and between \a rowFirst and \a rowLast.
  1776. Rows are 1-indexed.
  1777. Returns true if success.
  1778. */
  1779. bool Worksheet::setRowFormat(int rowFirst,int rowLast, const Format &format)
  1780. {
  1781. Q_D(Worksheet);
  1782. const QList <QSharedPointer<XlsxRowInfo> > rowInfoList = d->getRowInfoList(rowFirst,rowLast);
  1783. for (const QSharedPointer<XlsxRowInfo> &rowInfo : rowInfoList)
  1784. rowInfo->format = format;
  1785. d->workbook->styles()->addXfFormat(format);
  1786. return rowInfoList.count() > 0;
  1787. }
  1788. /*!
  1789. Sets the \a hidden proeprty of the rows including and between \a rowFirst and \a rowLast.
  1790. Rows are 1-indexed. If hidden is true rows will not be visible.
  1791. Returns true if success.
  1792. */
  1793. bool Worksheet::setRowHidden(int rowFirst,int rowLast, bool hidden)
  1794. {
  1795. Q_D(Worksheet);
  1796. const QList <QSharedPointer<XlsxRowInfo> > rowInfoList = d->getRowInfoList(rowFirst,rowLast);
  1797. for (const QSharedPointer<XlsxRowInfo> &rowInfo : rowInfoList)
  1798. rowInfo->hidden = hidden;
  1799. return rowInfoList.count() > 0;
  1800. }
  1801. /*!
  1802. Returns height of \a row in points.
  1803. */
  1804. double Worksheet::rowHeight(int row)
  1805. {
  1806. Q_D(Worksheet);
  1807. const int min_col = d->dimension.isValid() ? d->dimension.firstColumn() : 1;
  1808. auto it = d->rowsInfo.constFind(row);
  1809. if (d->checkDimensions(row, min_col, false, true) || it == d->rowsInfo.constEnd())
  1810. {
  1811. return d->sheetFormatProps.defaultRowHeight; //return default on invalid row
  1812. }
  1813. return (*it)->height;
  1814. }
  1815. /*!
  1816. Returns format of \a row.
  1817. */
  1818. Format Worksheet::rowFormat(int row)
  1819. {
  1820. Q_D(Worksheet);
  1821. const int min_col = d->dimension.isValid() ? d->dimension.firstColumn() : 1;
  1822. auto it = d->rowsInfo.constFind(row);
  1823. if (d->checkDimensions(row, min_col, false, true) || it == d->rowsInfo.constEnd())
  1824. return Format(); //return default on invalid row
  1825. return (*it)->format;
  1826. }
  1827. /*!
  1828. Returns true if \a row is hidden.
  1829. */
  1830. bool Worksheet::isRowHidden(int row)
  1831. {
  1832. Q_D(Worksheet);
  1833. const int min_col = d->dimension.isValid() ? d->dimension.firstColumn() : 1;
  1834. auto it = d->rowsInfo.constFind(row);
  1835. if (d->checkDimensions(row, min_col, false, true) || it == d->rowsInfo.constEnd())
  1836. return false; //return default on invalid row
  1837. return (*it)->hidden;
  1838. }
  1839. /*!
  1840. Groups rows from \a rowFirst to \a rowLast with the given \a collapsed.
  1841. Returns false if error occurs.
  1842. */
  1843. bool Worksheet::groupRows(int rowFirst, int rowLast, bool collapsed)
  1844. {
  1845. Q_D(Worksheet);
  1846. for (int row=rowFirst; row<=rowLast; ++row) {
  1847. auto it = d->rowsInfo.find(row);
  1848. if (it != d->rowsInfo.end()) {
  1849. (*it)->outlineLevel += 1;
  1850. } else {
  1851. QSharedPointer<XlsxRowInfo> info(new XlsxRowInfo);
  1852. info->outlineLevel += 1;
  1853. it = d->rowsInfo.insert(row, info);
  1854. }
  1855. if (collapsed)
  1856. (*it)->hidden = true;
  1857. }
  1858. if (collapsed) {
  1859. auto it = d->rowsInfo.find(rowLast+1);
  1860. if (it == d->rowsInfo.end())
  1861. it = d->rowsInfo.insert(rowLast+1, QSharedPointer<XlsxRowInfo>(new XlsxRowInfo));
  1862. (*it)->collapsed = true;
  1863. }
  1864. return true;
  1865. }
  1866. /*!
  1867. \overload
  1868. Groups columns with the given \a range and \a collapsed.
  1869. */
  1870. bool Worksheet::groupColumns(const CellRange &range, bool collapsed)
  1871. {
  1872. if (!range.isValid())
  1873. return false;
  1874. return groupColumns(range.firstColumn(), range.lastColumn(), collapsed);
  1875. }
  1876. /*!
  1877. Groups columns from \a colFirst to \a colLast with the given \a collapsed.
  1878. Returns false if error occurs.
  1879. */
  1880. bool Worksheet::groupColumns(int colFirst, int colLast, bool collapsed)
  1881. {
  1882. Q_D(Worksheet);
  1883. d->splitColsInfo(colFirst, colLast);
  1884. QList<int> nodes;
  1885. nodes.append(colFirst);
  1886. for (int col = colFirst; col <= colLast; ++col) {
  1887. auto it = d->colsInfo.constFind(col);
  1888. if (it != d->colsInfo.constEnd()) {
  1889. if (nodes.last() != col)
  1890. nodes.append(col);
  1891. int nextCol = (*it)->lastColumn + 1;
  1892. if (nextCol <= colLast)
  1893. nodes.append(nextCol);
  1894. }
  1895. }
  1896. for (int idx = 0; idx < nodes.size(); ++idx)
  1897. {
  1898. int colStart = nodes[idx];
  1899. auto it = d->colsInfo.constFind(colStart);
  1900. if (it != d->colsInfo.constEnd())
  1901. {
  1902. (*it)->outlineLevel += 1;
  1903. if (collapsed)
  1904. (*it)->hidden = true;
  1905. }
  1906. else
  1907. {
  1908. int colEnd = (idx == nodes.size() - 1) ? colLast : nodes[idx+1] - 1;
  1909. QSharedPointer<XlsxColumnInfo> info(new XlsxColumnInfo(colStart, colEnd, false));
  1910. info->outlineLevel += 1;
  1911. d->colsInfo.insert(colFirst, info);
  1912. if (collapsed)
  1913. info->hidden = true;
  1914. for (int c = colStart; c <= colEnd; ++c)
  1915. d->colsInfoHelper[c] = info;
  1916. }
  1917. }
  1918. if (collapsed) {
  1919. int col = colLast+1;
  1920. d->splitColsInfo(col, col);
  1921. auto it = d->colsInfo.constFind(col);
  1922. if (it != d->colsInfo.constEnd())
  1923. (*it)->collapsed = true;
  1924. else {
  1925. QSharedPointer<XlsxColumnInfo> info(new XlsxColumnInfo(col, col, false));
  1926. info->collapsed = true;
  1927. d->colsInfo.insert(col, info);
  1928. d->colsInfoHelper[col] = info;
  1929. }
  1930. }
  1931. return false;
  1932. }
  1933. /*!
  1934. Return the range that contains cell data.
  1935. */
  1936. CellRange Worksheet::dimension() const
  1937. {
  1938. Q_D(const Worksheet);
  1939. return d->dimension;
  1940. }
  1941. /*
  1942. Convert the height of a cell from user's units to pixels. If the
  1943. height hasn't been set by the user we use the default value. If
  1944. the row is hidden it has a value of zero.
  1945. */
  1946. int WorksheetPrivate::rowPixelsSize(int row) const
  1947. {
  1948. double height;
  1949. auto it = row_sizes.constFind(row);
  1950. if (it != row_sizes.constEnd())
  1951. height = it.value();
  1952. else
  1953. height = default_row_height;
  1954. return static_cast<int>(4.0 / 3.0 *height);
  1955. }
  1956. /*
  1957. Convert the width of a cell from user's units to pixels. Excel rounds
  1958. the column width to the nearest pixel. If the width hasn't been set
  1959. by the user we use the default value. If the column is hidden it
  1960. has a value of zero.
  1961. */
  1962. int WorksheetPrivate::colPixelsSize(int col) const
  1963. {
  1964. double max_digit_width = 7.0; //For Calabri 11
  1965. double padding = 5.0;
  1966. int pixels = 0;
  1967. auto it = col_sizes.constFind(col);
  1968. if (it != col_sizes.constEnd()) {
  1969. double width = it.value();
  1970. if (width < 1)
  1971. pixels = static_cast<int>(width * (max_digit_width + padding) + 0.5);
  1972. else
  1973. pixels = static_cast<int>(width * max_digit_width + 0.5) + padding;
  1974. } else {
  1975. pixels = 64;
  1976. }
  1977. return pixels;
  1978. }
  1979. void WorksheetPrivate::loadXmlSheetData(QXmlStreamReader &reader)
  1980. {
  1981. Q_Q(Worksheet);
  1982. Q_ASSERT(reader.name() == QLatin1String("sheetData"));
  1983. while (!reader.atEnd() && !(reader.name() == QLatin1String("sheetData") && reader.tokenType() == QXmlStreamReader::EndElement))
  1984. {
  1985. if (reader.readNextStartElement())
  1986. {
  1987. if (reader.name() == QLatin1String("row"))
  1988. {
  1989. QXmlStreamAttributes attributes = reader.attributes();
  1990. if (attributes.hasAttribute(QLatin1String("customFormat"))
  1991. || attributes.hasAttribute(QLatin1String("customHeight"))
  1992. || attributes.hasAttribute(QLatin1String("hidden"))
  1993. || attributes.hasAttribute(QLatin1String("outlineLevel"))
  1994. || attributes.hasAttribute(QLatin1String("collapsed")))
  1995. {
  1996. QSharedPointer<XlsxRowInfo> info(new XlsxRowInfo);
  1997. if (attributes.hasAttribute(QLatin1String("customFormat")) &&
  1998. attributes.hasAttribute(QLatin1String("s")))
  1999. {
  2000. int idx = attributes.value(QLatin1String("s")).toString().toInt();
  2001. info->format = workbook->styles()->xfFormat(idx);
  2002. }
  2003. if (attributes.hasAttribute(QLatin1String("customHeight")))
  2004. {
  2005. info->customHeight = attributes.value(QLatin1String("customHeight")) == QLatin1String("1");
  2006. //Row height is only specified when customHeight is set
  2007. if(attributes.hasAttribute(QLatin1String("ht")))
  2008. {
  2009. info->height = attributes.value(QLatin1String("ht")).toString().toDouble();
  2010. }
  2011. }
  2012. //both "hidden" and "collapsed" default are false
  2013. info->hidden = attributes.value(QLatin1String("hidden")) == QLatin1String("1");
  2014. info->collapsed = attributes.value(QLatin1String("collapsed")) == QLatin1String("1");
  2015. if (attributes.hasAttribute(QLatin1String("outlineLevel")))
  2016. info->outlineLevel = attributes.value(QLatin1String("outlineLevel")).toString().toInt();
  2017. //"r" is optional too.
  2018. if (attributes.hasAttribute(QLatin1String("r")))
  2019. {
  2020. int row = attributes.value(QLatin1String("r")).toString().toInt();
  2021. rowsInfo[row] = info;
  2022. }
  2023. }
  2024. }
  2025. else if (reader.name() == QLatin1String("c")) // Cell
  2026. {
  2027. //Cell
  2028. QXmlStreamAttributes attributes = reader.attributes();
  2029. QString r = attributes.value(QLatin1String("r")).toString();
  2030. CellReference pos(r);
  2031. //get format
  2032. Format format;
  2033. qint32 styleIndex = -1;
  2034. if (attributes.hasAttribute(QLatin1String("s"))) // Style (defined in the styles.xml file)
  2035. {
  2036. //"s" == style index
  2037. int idx = attributes.value(QLatin1String("s")).toString().toInt();
  2038. format = workbook->styles()->xfFormat(idx);
  2039. styleIndex = idx;
  2040. }
  2041. // Cell::CellType cellType = Cell::NumberType;
  2042. Cell::CellType cellType = Cell::CustomType;
  2043. if (attributes.hasAttribute(QLatin1String("t"))) // Type
  2044. {
  2045. QString typeString = attributes.value(QLatin1String("t")).toString();
  2046. if (typeString == QLatin1String("s")) // Shared string
  2047. {
  2048. cellType = Cell::SharedStringType;
  2049. }
  2050. else if (typeString == QLatin1String("inlineStr")) // Inline String
  2051. {
  2052. cellType = Cell::InlineStringType;
  2053. }
  2054. else if (typeString == QLatin1String("str")) // String
  2055. {
  2056. cellType = Cell::StringType;
  2057. }
  2058. else if (typeString == QLatin1String("b")) // Boolean
  2059. {
  2060. cellType = Cell::BooleanType;
  2061. }
  2062. else if (typeString == QLatin1String("e")) // Error
  2063. {
  2064. cellType = Cell::ErrorType;
  2065. }
  2066. else if (typeString == QLatin1String("d")) // Date
  2067. {
  2068. cellType = Cell::DateType;
  2069. }
  2070. else if (typeString == QLatin1String("n")) // Number
  2071. {
  2072. cellType = Cell::NumberType;
  2073. }
  2074. else
  2075. {
  2076. // custom type
  2077. cellType = Cell::CustomType;
  2078. }
  2079. }
  2080. // [dev54] temp cell for checking datetype
  2081. Cell tempCell(QVariant(), cellType, format, q, styleIndex);
  2082. if ( tempCell.isDateTime() )
  2083. {
  2084. cellType = Cell::DateType;
  2085. }
  2086. // create a heap of new cell
  2087. QSharedPointer<Cell> cell(new Cell(QVariant(), cellType, format, q, styleIndex));
  2088. while (!reader.atEnd() &&
  2089. !(reader.name() == QLatin1String("c") &&
  2090. reader.tokenType() == QXmlStreamReader::EndElement))
  2091. {
  2092. if (reader.readNextStartElement())
  2093. {
  2094. if (reader.name() == QLatin1String("f")) // formula
  2095. {
  2096. CellFormula &formula = cell->d_func()->formula;
  2097. formula.loadFromXml(reader);
  2098. if (formula.formulaType() == CellFormula::SharedType &&
  2099. !formula.formulaText().isEmpty())
  2100. {
  2101. int si = formula.sharedIndex();
  2102. sharedFormulaMap[ si ] = formula;
  2103. }
  2104. }
  2105. else if (reader.name() == QLatin1String("v")) // Value
  2106. {
  2107. QString value = reader.readElementText();
  2108. if (cellType == Cell::SharedStringType)
  2109. {
  2110. int sst_idx = value.toInt();
  2111. sharedStrings()->incRefByStringIndex(sst_idx);
  2112. RichString rs = sharedStrings()->getSharedString(sst_idx);
  2113. QString strPlainString = rs.toPlainString();
  2114. cell->d_func()->value = strPlainString;
  2115. if (rs.isRichString())
  2116. cell->d_func()->richString = rs;
  2117. }
  2118. else if (cellType == Cell::NumberType)
  2119. {
  2120. cell->d_func()->value = value.toDouble();
  2121. }
  2122. else if (cellType == Cell::BooleanType)
  2123. {
  2124. cell->d_func()->value = value.toInt() ? true : false;
  2125. }
  2126. else if (cellType == Cell::DateType)
  2127. {
  2128. // [dev54] DateType
  2129. double dValue = value.toDouble(); // days from 1900(or 1904)
  2130. bool bIsDate1904 = q->workbook()->isDate1904();
  2131. QVariant vDatetimeValue = datetimeFromNumber( dValue, bIsDate1904 );
  2132. Q_UNUSED(vDatetimeValue);
  2133. // cell->d_func()->value = vDatetimeValue;
  2134. cell->d_func()->value = dValue; // dev67
  2135. }
  2136. else
  2137. {
  2138. // ELSE type
  2139. cell->d_func()->value = value;
  2140. }
  2141. }
  2142. else if (reader.name() == QLatin1String("is"))
  2143. {
  2144. while (!reader.atEnd() &&
  2145. !(reader.name() == QLatin1String("is") &&
  2146. reader.tokenType() == QXmlStreamReader::EndElement))
  2147. {
  2148. if (reader.readNextStartElement())
  2149. {
  2150. //:Todo, add rich text read support
  2151. if (reader.name() == QLatin1String("t"))
  2152. {
  2153. cell->d_func()->value = reader.readElementText();
  2154. }
  2155. }
  2156. }
  2157. }
  2158. else if (reader.name() == QLatin1String("extLst"))
  2159. {
  2160. //skip extLst element
  2161. while ( !reader.atEnd() &&
  2162. !(reader.name() == QLatin1String("extLst") &&
  2163. reader.tokenType() == QXmlStreamReader::EndElement))
  2164. {
  2165. reader.readNextStartElement();
  2166. }
  2167. }
  2168. }
  2169. }
  2170. cellTable[ pos.row() ][ pos.column() ] = cell;
  2171. }
  2172. }
  2173. }
  2174. }
  2175. void WorksheetPrivate::loadXmlColumnsInfo(QXmlStreamReader &reader)
  2176. {
  2177. Q_ASSERT(reader.name() == QLatin1String("cols"));
  2178. while (!reader.atEnd() &&
  2179. !(reader.name() == QLatin1String("cols") &&
  2180. reader.tokenType() == QXmlStreamReader::EndElement))
  2181. {
  2182. reader.readNextStartElement();
  2183. if (reader.tokenType() == QXmlStreamReader::StartElement)
  2184. {
  2185. if (reader.name() == QLatin1String("col"))
  2186. {
  2187. QSharedPointer<XlsxColumnInfo> info(new XlsxColumnInfo(0, 1, false));
  2188. QXmlStreamAttributes colAttrs = reader.attributes();
  2189. int min = colAttrs.value(QLatin1String("min")).toString().toInt();
  2190. int max = colAttrs.value(QLatin1String("max")).toString().toInt();
  2191. info->firstColumn = min;
  2192. info->lastColumn = max;
  2193. //Flag indicating that the column width for the affected column(s) is different from the
  2194. // default or has been manually set
  2195. if(colAttrs.hasAttribute(QLatin1String("customWidth")))
  2196. {
  2197. info->customWidth = colAttrs.value(QLatin1String("customWidth")) == QLatin1String("1");
  2198. }
  2199. //Note, node may have "width" without "customWidth"
  2200. // [dev54]
  2201. if (colAttrs.hasAttribute(QLatin1String("width")))
  2202. {
  2203. double width = colAttrs.value(QLatin1String("width")).toString().toDouble();
  2204. info->width = width;
  2205. info->isSetWidth = true; // [dev54]
  2206. }
  2207. info->hidden = colAttrs.value(QLatin1String("hidden")) == QLatin1String("1");
  2208. info->collapsed = colAttrs.value(QLatin1String("collapsed")) == QLatin1String("1");
  2209. if (colAttrs.hasAttribute(QLatin1String("style")))
  2210. {
  2211. int idx = colAttrs.value(QLatin1String("style")).toString().toInt();
  2212. info->format = workbook->styles()->xfFormat(idx);
  2213. }
  2214. if (colAttrs.hasAttribute(QLatin1String("outlineLevel")))
  2215. {
  2216. info->outlineLevel = colAttrs.value(QLatin1String("outlineLevel")).toString().toInt();
  2217. }
  2218. // qDebug() << "[debug] " << __FUNCTION__ << min << max << info->width << hasWidth;
  2219. colsInfo.insert(min, info);
  2220. for (int col = min ; col <= max ; ++col)
  2221. {
  2222. colsInfoHelper[col] = info;
  2223. }
  2224. }
  2225. }
  2226. }
  2227. }
  2228. void WorksheetPrivate::loadXmlMergeCells(QXmlStreamReader &reader)
  2229. {
  2230. // issue #173 https://github.com/QtExcel/QXlsx/issues/173
  2231. Q_ASSERT(reader.name() == QLatin1String("mergeCells"));
  2232. QXmlStreamAttributes attributes = reader.attributes();
  2233. bool isCount = attributes.hasAttribute(QLatin1String("count"));
  2234. int count = 0;
  2235. if ( !isCount )
  2236. {
  2237. qWarning("no count");
  2238. }
  2239. else
  2240. {
  2241. count = attributes.value(QLatin1String("count")).toString().toInt();
  2242. }
  2243. while ( !reader.atEnd() &&
  2244. !(reader.name() == QLatin1String("mergeCells") &&
  2245. reader.tokenType() == QXmlStreamReader::EndElement) )
  2246. {
  2247. reader.readNextStartElement();
  2248. if (reader.tokenType() == QXmlStreamReader::StartElement)
  2249. {
  2250. if (reader.name() == QLatin1String("mergeCell"))
  2251. {
  2252. QXmlStreamAttributes attrs = reader.attributes();
  2253. QString rangeStr = attrs.value(QLatin1String("ref")).toString();
  2254. merges.append(CellRange(rangeStr));
  2255. }
  2256. }
  2257. }
  2258. if (isCount)
  2259. {
  2260. int mergesSize = merges.size();
  2261. if ( mergesSize != count )
  2262. {
  2263. qWarning("read merge cells error");
  2264. }
  2265. }
  2266. }
  2267. void WorksheetPrivate::loadXmlDataValidations(QXmlStreamReader &reader)
  2268. {
  2269. Q_ASSERT(reader.name() == QLatin1String("dataValidations"));
  2270. QXmlStreamAttributes attributes = reader.attributes();
  2271. int count = attributes.value(QLatin1String("count")).toString().toInt();
  2272. while (!reader.atEnd() && !(reader.name() == QLatin1String("dataValidations")
  2273. && reader.tokenType() == QXmlStreamReader::EndElement)) {
  2274. reader.readNextStartElement();
  2275. if (reader.tokenType() == QXmlStreamReader::StartElement
  2276. && reader.name() == QLatin1String("dataValidation")) {
  2277. dataValidationsList.append(DataValidation::loadFromXml(reader));
  2278. }
  2279. }
  2280. if (dataValidationsList.size() != count)
  2281. qDebug("read data validation error");
  2282. }
  2283. void WorksheetPrivate::loadXmlSheetViews(QXmlStreamReader &reader)
  2284. {
  2285. Q_ASSERT(reader.name() == QLatin1String("sheetViews"));
  2286. while (!reader.atEnd() && !(reader.name() == QLatin1String("sheetViews")
  2287. && reader.tokenType() == QXmlStreamReader::EndElement)) {
  2288. reader.readNextStartElement();
  2289. if (reader.tokenType() == QXmlStreamReader::StartElement && reader.name() == QLatin1String("sheetView")) {
  2290. QXmlStreamAttributes attrs = reader.attributes();
  2291. //default false
  2292. windowProtection = attrs.value(QLatin1String("windowProtection")) == QLatin1String("1");
  2293. showFormulas = attrs.value(QLatin1String("showFormulas")) == QLatin1String("1");
  2294. rightToLeft = attrs.value(QLatin1String("rightToLeft")) == QLatin1String("1");
  2295. tabSelected = attrs.value(QLatin1String("tabSelected")) == QLatin1String("1");
  2296. //default true
  2297. showGridLines = attrs.value(QLatin1String("showGridLines")) != QLatin1String("0");
  2298. showRowColHeaders = attrs.value(QLatin1String("showRowColHeaders")) != QLatin1String("0");
  2299. showZeros = attrs.value(QLatin1String("showZeros")) != QLatin1String("0");
  2300. showRuler = attrs.value(QLatin1String("showRuler")) != QLatin1String("0");
  2301. showOutlineSymbols = attrs.value(QLatin1String("showOutlineSymbols")) != QLatin1String("0");
  2302. showWhiteSpace = attrs.value(QLatin1String("showWhiteSpace")) != QLatin1String("0");
  2303. }
  2304. }
  2305. }
  2306. void WorksheetPrivate::loadXmlSheetFormatProps(QXmlStreamReader &reader)
  2307. {
  2308. Q_ASSERT(reader.name() == QLatin1String("sheetFormatPr"));
  2309. const QXmlStreamAttributes attributes = reader.attributes();
  2310. XlsxSheetFormatProps formatProps;
  2311. bool isSetWidth = false;
  2312. // Retain default values
  2313. for (const QXmlStreamAttribute &attrib : attributes)
  2314. {
  2315. if(attrib.name() == QLatin1String("baseColWidth") )
  2316. {
  2317. formatProps.baseColWidth = attrib.value().toString().toInt();
  2318. }
  2319. else if(attrib.name() == QLatin1String("customHeight"))
  2320. {
  2321. formatProps.customHeight = attrib.value() == QLatin1String("1");
  2322. }
  2323. else if(attrib.name() == QLatin1String("defaultColWidth"))
  2324. {
  2325. double dDefaultColWidth = attrib.value().toString().toDouble();
  2326. formatProps.defaultColWidth = dDefaultColWidth;
  2327. isSetWidth = true;
  2328. }
  2329. else if(attrib.name() == QLatin1String("defaultRowHeight"))
  2330. {
  2331. formatProps.defaultRowHeight = attrib.value().toString().toDouble();
  2332. }
  2333. else if(attrib.name() == QLatin1String("outlineLevelCol"))
  2334. {
  2335. formatProps.outlineLevelCol = attrib.value().toString().toInt();
  2336. }
  2337. else if(attrib.name() == QLatin1String("outlineLevelRow"))
  2338. {
  2339. formatProps.outlineLevelRow = attrib.value().toString().toInt();
  2340. }
  2341. else if(attrib.name() == QLatin1String("thickBottom"))
  2342. {
  2343. formatProps.thickBottom = attrib.value() == QLatin1String("1");
  2344. }
  2345. else if(attrib.name() == QLatin1String("thickTop"))
  2346. {
  2347. formatProps.thickTop = attrib.value() == QLatin1String("1");
  2348. }
  2349. else if(attrib.name() == QLatin1String("zeroHeight"))
  2350. {
  2351. formatProps.zeroHeight = attrib.value() == QLatin1String("1");
  2352. }
  2353. }
  2354. // if (formatProps.defaultColWidth == 0.0)
  2355. if ( !isSetWidth )
  2356. {
  2357. //not set
  2358. double dCalcWidth = WorksheetPrivate::calculateColWidth(formatProps.baseColWidth);
  2359. formatProps.defaultColWidth = dCalcWidth;
  2360. }
  2361. // [dev54]
  2362. // Where is code of setting 'formatProps'?
  2363. this->sheetFormatProps = formatProps;
  2364. }
  2365. double WorksheetPrivate::calculateColWidth(int characters)
  2366. {
  2367. // //!Todo
  2368. //Take normal style' font maximum width and add padding and margin pixels
  2369. // return characters + 0.5;
  2370. return characters;
  2371. }
  2372. void WorksheetPrivate::loadXmlHyperlinks(QXmlStreamReader &reader)
  2373. {
  2374. Q_ASSERT(reader.name() == QLatin1String("hyperlinks"));
  2375. while (!reader.atEnd() && !(reader.name() == QLatin1String("hyperlinks")
  2376. && reader.tokenType() == QXmlStreamReader::EndElement)) {
  2377. reader.readNextStartElement();
  2378. if (reader.tokenType() == QXmlStreamReader::StartElement && reader.name() == QLatin1String("hyperlink")) {
  2379. QXmlStreamAttributes attrs = reader.attributes();
  2380. CellReference pos(attrs.value(QLatin1String("ref")).toString());
  2381. if (pos.isValid()) { //Valid
  2382. QSharedPointer<XlsxHyperlinkData> link(new XlsxHyperlinkData);
  2383. link->display = attrs.value(QLatin1String("display")).toString();
  2384. link->tooltip = attrs.value(QLatin1String("tooltip")).toString();
  2385. link->location = attrs.value(QLatin1String("location")).toString();
  2386. if (attrs.hasAttribute(QLatin1String("r:id"))) {
  2387. link->linkType = XlsxHyperlinkData::External;
  2388. XlsxRelationship ship = relationships->getRelationshipById(attrs.value(QLatin1String("r:id")).toString());
  2389. link->target = ship.target;
  2390. } else {
  2391. link->linkType = XlsxHyperlinkData::Internal;
  2392. }
  2393. urlTable[pos.row()][pos.column()] = link;
  2394. }
  2395. }
  2396. }
  2397. }
  2398. QList <QSharedPointer<XlsxColumnInfo> > WorksheetPrivate::getColumnInfoList(int colFirst, int colLast)
  2399. {
  2400. QList <QSharedPointer<XlsxColumnInfo> > columnsInfoList;
  2401. if (isColumnRangeValid(colFirst,colLast))
  2402. {
  2403. QList<int> nodes = getColumnIndexes(colFirst, colLast);
  2404. for (int idx = 0; idx < nodes.size(); ++idx)
  2405. {
  2406. int colStart = nodes[idx];
  2407. auto it = colsInfo.constFind(colStart);
  2408. if (it != colsInfo.constEnd())
  2409. {
  2410. columnsInfoList.append(*it);
  2411. }
  2412. else
  2413. {
  2414. int colEnd = (idx == nodes.size() - 1) ? colLast : nodes[idx+1] - 1;
  2415. QSharedPointer<XlsxColumnInfo> info(new XlsxColumnInfo(colStart, colEnd, false));
  2416. colsInfo.insert(colFirst, info);
  2417. columnsInfoList.append(info);
  2418. for (int c = colStart; c <= colEnd; ++c)
  2419. {
  2420. colsInfoHelper[c] = info;
  2421. }
  2422. }
  2423. }
  2424. }
  2425. return columnsInfoList;
  2426. }
  2427. QList <QSharedPointer<XlsxRowInfo> > WorksheetPrivate::getRowInfoList(int rowFirst, int rowLast)
  2428. {
  2429. QList <QSharedPointer<XlsxRowInfo> > rowInfoList;
  2430. int min_col = dimension.firstColumn() < 1 ? 1 : dimension.firstColumn();
  2431. for(int row = rowFirst; row <= rowLast; ++row) {
  2432. if (checkDimensions(row, min_col, false, true))
  2433. continue;
  2434. QSharedPointer<XlsxRowInfo> rowInfo;
  2435. if ((rowsInfo[row]).isNull()){
  2436. rowsInfo[row] = QSharedPointer<XlsxRowInfo>(new XlsxRowInfo());
  2437. }
  2438. rowInfoList.append(rowsInfo[row]);
  2439. }
  2440. return rowInfoList;
  2441. }
  2442. bool Worksheet::loadFromXmlFile(QIODevice *device)
  2443. {
  2444. Q_D(Worksheet);
  2445. QXmlStreamReader reader(device);
  2446. while (!reader.atEnd())
  2447. {
  2448. reader.readNextStartElement();
  2449. if (reader.tokenType() == QXmlStreamReader::StartElement)
  2450. {
  2451. if (reader.name() == QLatin1String("dimension"))
  2452. {
  2453. QXmlStreamAttributes attributes = reader.attributes();
  2454. QString range = attributes.value(QLatin1String("ref")).toString();
  2455. d->dimension = CellRange(range);
  2456. }
  2457. else if (reader.name() == QLatin1String("sheetViews"))
  2458. {
  2459. d->loadXmlSheetViews(reader);
  2460. }
  2461. else if (reader.name() == QLatin1String("sheetFormatPr"))
  2462. {
  2463. d->loadXmlSheetFormatProps(reader);
  2464. }
  2465. else if (reader.name() == QLatin1String("cols"))
  2466. {
  2467. d->loadXmlColumnsInfo(reader);
  2468. }
  2469. else if (reader.name() == QLatin1String("sheetData"))
  2470. {
  2471. d->loadXmlSheetData(reader);
  2472. }
  2473. else if (reader.name() == QLatin1String("mergeCells"))
  2474. {
  2475. d->loadXmlMergeCells(reader);
  2476. }
  2477. else if (reader.name() == QLatin1String("dataValidations"))
  2478. {
  2479. d->loadXmlDataValidations(reader);
  2480. }
  2481. else if (reader.name() == QLatin1String("conditionalFormatting"))
  2482. {
  2483. ConditionalFormatting cf;
  2484. cf.loadFromXml(reader, workbook()->styles());
  2485. d->conditionalFormattingList.append(cf);
  2486. }
  2487. else if (reader.name() == QLatin1String("hyperlinks"))
  2488. {
  2489. d->loadXmlHyperlinks(reader);
  2490. }
  2491. else if(reader.name() == QLatin1String("pageSetup"))
  2492. {
  2493. QXmlStreamAttributes attributes = reader.attributes();
  2494. d->PpaperSize = attributes.value(QLatin1String("paperSize")).toString().trimmed();
  2495. d->Pscale = attributes.value(QLatin1String("scale")).toString().trimmed();
  2496. d->PfirstPageNumber = attributes.value(QLatin1String("firstPageNumber")).toString().trimmed();
  2497. d->Porientation = attributes.value(QLatin1String("orientation")).toString().trimmed();
  2498. d->PuseFirstPageNumber = attributes.value(QLatin1String("useFirstPageNumber")).toString().trimmed();
  2499. d->PhorizontalDpi = attributes.value(QLatin1String("horizontalDpi")).toString().trimmed();
  2500. d->PverticalDpi = attributes.value(QLatin1String("verticalDpi")).toString().trimmed();
  2501. d->Prid = attributes.value(QLatin1String("r:id")).toString().trimmed();
  2502. d->Pcopies = attributes.value(QLatin1String("copies")).toString().trimmed();
  2503. }
  2504. else if(reader.name() == QLatin1String("pageMargins"))
  2505. {
  2506. QXmlStreamAttributes attributes = reader.attributes();
  2507. d->PMfooter= attributes.value(QLatin1String("footer")).toString().trimmed();
  2508. d->PMheader = attributes.value(QLatin1String("header")).toString().trimmed();
  2509. d->PMbotton = attributes.value(QLatin1String("bottom")).toString().trimmed();
  2510. d->PMtop = attributes.value(QLatin1String("top")).toString().trimmed();
  2511. d->PMright = attributes.value(QLatin1String("right")).toString().trimmed();
  2512. d->PMleft = attributes.value(QLatin1String("left")).toString().trimmed();
  2513. }
  2514. else if(reader.name() == QLatin1String("headerFooter"))
  2515. {
  2516. // dev40
  2517. while (reader.readNextStartElement())
  2518. {
  2519. if (reader.name() == QLatin1String("oddHeader"))
  2520. d->ModdHeader = reader.readElementText();
  2521. if (reader.name() == QLatin1String("oddFooter"))
  2522. d->MoodFooter = reader.readElementText();
  2523. }
  2524. }
  2525. else if (reader.name() == QLatin1String("drawing"))
  2526. {
  2527. QString rId = reader.attributes().value(QStringLiteral("r:id")).toString();
  2528. QString name = d->relationships->getRelationshipById(rId).target;
  2529. QString str = *( splitPath(filePath()).begin() );
  2530. str = str + QLatin1String("/");
  2531. str = str + name;
  2532. QString path = QDir::cleanPath( str );
  2533. d->drawing = QSharedPointer<Drawing>(new Drawing(this, F_LoadFromExists));
  2534. d->drawing->setFilePath(path);
  2535. }
  2536. else if (reader.name() == QLatin1String("extLst"))
  2537. {
  2538. //Todo: add extLst support
  2539. while ( !reader.atEnd() &&
  2540. !(reader.name() == QLatin1String("extLst") &&
  2541. reader.tokenType() == QXmlStreamReader::EndElement))
  2542. {
  2543. reader.readNextStartElement();
  2544. }
  2545. }
  2546. }
  2547. }
  2548. d->validateDimension();
  2549. return true;
  2550. }
  2551. /*
  2552. * Documents imported from Google Docs does not contain dimension data.
  2553. */
  2554. void WorksheetPrivate::validateDimension()
  2555. {
  2556. if (dimension.isValid() || cellTable.isEmpty())
  2557. return;
  2558. const auto firstRow = cellTable.constBegin().key();
  2559. const auto lastRow = (--cellTable.constEnd()).key();
  2560. int firstColumn = -1;
  2561. int lastColumn = -1;
  2562. for ( auto&& it = cellTable.constBegin()
  2563. ; it != cellTable.constEnd()
  2564. ; ++it )
  2565. {
  2566. Q_ASSERT(!it.value().isEmpty());
  2567. if (firstColumn == -1 || it.value().constBegin().key() < firstColumn)
  2568. firstColumn = it.value().constBegin().key();
  2569. if (lastColumn == -1 || (--it.value().constEnd()).key() > lastColumn)
  2570. {
  2571. lastColumn = (--it.value().constEnd()).key();
  2572. }
  2573. }
  2574. CellRange cr(firstRow, firstColumn, lastRow, lastColumn);
  2575. if (cr.isValid())
  2576. dimension = cr;
  2577. }
  2578. /*!
  2579. * \internal
  2580. * Unit test can use this member to get sharedString object.
  2581. */
  2582. SharedStrings *WorksheetPrivate::sharedStrings() const
  2583. {
  2584. return workbook->sharedStrings();
  2585. }
  2586. QVector<CellLocation> Worksheet::getFullCells(int* maxRow, int* maxCol)
  2587. {
  2588. Q_D(const Worksheet);
  2589. // return values
  2590. (*maxRow) = -1;
  2591. (*maxCol) = -1;
  2592. QVector<CellLocation> ret;
  2593. // QString privateName = d->name; // name of sheet (not object type)
  2594. // qDebug() << privateName ;
  2595. if ( d->type == AbstractSheet::ST_WorkSheet )
  2596. {
  2597. // use current sheet
  2598. }
  2599. else if ( d->type == AbstractSheet::ST_ChartSheet )
  2600. {
  2601. return ret;
  2602. }
  2603. else
  2604. {
  2605. qWarning("unsupported sheet type.");
  2606. Q_ASSERT(false);
  2607. return ret;
  2608. }
  2609. QMapIterator< int, QMap< int, QSharedPointer<Cell> > > _it( d->cellTable );
  2610. while ( _it.hasNext() )
  2611. {
  2612. _it.next();
  2613. int keyI = _it.key(); // key (cell row)
  2614. QMapIterator<int, QSharedPointer<Cell> > _iit( _it.value() ); // value
  2615. while ( _iit.hasNext() )
  2616. {
  2617. _iit.next();
  2618. int keyII = _iit.key(); // key (cell column)
  2619. QSharedPointer<Cell> ptrCell = _iit.value(); // value
  2620. CellLocation cl;
  2621. cl.row = keyI;
  2622. if ( keyI > (*maxRow) )
  2623. {
  2624. (*maxRow) = keyI;
  2625. }
  2626. cl.col = keyII;
  2627. if ( keyII > (*maxCol) )
  2628. {
  2629. (*maxCol) = keyII;
  2630. }
  2631. cl.cell = ptrCell;
  2632. ret.push_back( cl );
  2633. }
  2634. }
  2635. return ret;
  2636. }
  2637. QT_END_NAMESPACE_XLSX