xlsxstyles.cpp 63 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415
  1. // xlsxstyles.cpp
  2. #include <QtGlobal>
  3. #include <QXmlStreamWriter>
  4. #include <QXmlStreamReader>
  5. #include <QFile>
  6. #include <QMap>
  7. #include <QDataStream>
  8. #include <QDebug>
  9. #include <QBuffer>
  10. #include "xlsxglobal.h"
  11. #include "xlsxstyles_p.h"
  12. #include "xlsxformat_p.h"
  13. #include "xlsxutility_p.h"
  14. #include "xlsxcolor_p.h"
  15. QT_BEGIN_NAMESPACE_XLSX
  16. /*
  17. When loading from existing .xlsx file. we should create a clean styles object.
  18. otherwise, default formats should be added.
  19. */
  20. Styles::Styles(CreateFlag flag)
  21. : AbstractOOXmlFile(flag), m_nextCustomNumFmtId(176), m_isIndexedColorsDefault(true)
  22. , m_emptyFormatAdded(false)
  23. {
  24. //!Fix me. Should the custom num fmt Id starts with 164 or 176 or others??
  25. //!Fix me! Where should we put these register code?
  26. // issue #172, #89
  27. #if QT_VERSION >= 0x060000 // Qt 6.0 or over
  28. if (QMetaType::fromName("XlsxColor").isRegistered())
  29. #else
  30. #if QT_VERSION >= QT_VERSION_CHECK( 5, 0, 0 ) // Qt 5 or higher
  31. if (QMetaType::type("XlsxColor") == QMetaType::UnknownType)
  32. #else
  33. if (QMetaType::type("XlsxColor") == 0
  34. || !QMetaType::isRegistered(QMetaType::type("XlsxColor")))
  35. #endif
  36. #endif
  37. {
  38. qRegisterMetaType<XlsxColor>("XlsxColor");
  39. #if QT_VERSION >= 0x060000
  40. // Qt 6
  41. ///TODO:
  42. #else
  43. // Qt 5
  44. qRegisterMetaTypeStreamOperators<XlsxColor>("XlsxColor");
  45. #if QT_VERSION >= 0x050200 // 5.2 or higher
  46. QMetaType::registerDebugStreamOperator<XlsxColor>();
  47. #endif
  48. #endif
  49. }
  50. if (flag == F_NewFromScratch) {
  51. //Add default Format
  52. Format defaultFmt;
  53. addXfFormat(defaultFmt);
  54. //Add another fill format
  55. Format fillFmt;
  56. fillFmt.setFillPattern(Format::PatternGray125);
  57. m_fillsList.append(fillFmt);
  58. m_fillsHash.insert(fillFmt.fillKey(), fillFmt);
  59. }
  60. }
  61. Styles::~Styles()
  62. {
  63. }
  64. Format Styles::xfFormat(int idx) const
  65. {
  66. if (idx <0 || idx >= m_xf_formatsList.size())
  67. return Format();
  68. return m_xf_formatsList[idx];
  69. }
  70. Format Styles::dxfFormat(int idx) const
  71. {
  72. if (idx <0 || idx >= m_dxf_formatsList.size())
  73. return Format();
  74. return m_dxf_formatsList[idx];
  75. }
  76. // dev74 issue#57
  77. void Styles::fixNumFmt(const Format &format)
  78. {
  79. if (!format.hasNumFmtData())
  80. return;
  81. if (format.hasProperty(FormatPrivate::P_NumFmt_Id)
  82. && !format.stringProperty(FormatPrivate::P_NumFmt_FormatCode).isEmpty())
  83. {
  84. return;
  85. }
  86. if ( m_builtinNumFmtsHash.isEmpty() )
  87. {
  88. m_builtinNumFmtsHash.insert(QStringLiteral("General"), 0);
  89. m_builtinNumFmtsHash.insert(QStringLiteral("0"), 1);
  90. m_builtinNumFmtsHash.insert(QStringLiteral("0.00"), 2);
  91. m_builtinNumFmtsHash.insert(QStringLiteral("#,##0"), 3);
  92. m_builtinNumFmtsHash.insert(QStringLiteral("#,##0.00"), 4);
  93. // m_builtinNumFmtsHash.insert(QStringLiteral("($#,##0_);($#,##0)"), 5);
  94. // m_builtinNumFmtsHash.insert(QStringLiteral("($#,##0_);[Red]($#,##0)"), 6);
  95. // m_builtinNumFmtsHash.insert(QStringLiteral("($#,##0.00_);($#,##0.00)"), 7);
  96. // m_builtinNumFmtsHash.insert(QStringLiteral("($#,##0.00_);[Red]($#,##0.00)"), 8);
  97. m_builtinNumFmtsHash.insert(QStringLiteral("0%"), 9);
  98. m_builtinNumFmtsHash.insert(QStringLiteral("0.00%"), 10);
  99. m_builtinNumFmtsHash.insert(QStringLiteral("0.00E+00"), 11);
  100. m_builtinNumFmtsHash.insert(QStringLiteral("# ?/?"), 12);
  101. m_builtinNumFmtsHash.insert(QStringLiteral("# ?\?/??"), 13);// Note: "??/" is a c++ trigraph, so escape one "?"
  102. m_builtinNumFmtsHash.insert(QStringLiteral("m/d/yy"), 14);
  103. m_builtinNumFmtsHash.insert(QStringLiteral("d-mmm-yy"), 15);
  104. m_builtinNumFmtsHash.insert(QStringLiteral("d-mmm"), 16);
  105. m_builtinNumFmtsHash.insert(QStringLiteral("mmm-yy"), 17);
  106. m_builtinNumFmtsHash.insert(QStringLiteral("h:mm AM/PM"), 18);
  107. m_builtinNumFmtsHash.insert(QStringLiteral("h:mm:ss AM/PM"), 19);
  108. m_builtinNumFmtsHash.insert(QStringLiteral("h:mm"), 20);
  109. m_builtinNumFmtsHash.insert(QStringLiteral("h:mm:ss"), 21);
  110. m_builtinNumFmtsHash.insert(QStringLiteral("m/d/yy h:mm"), 22);
  111. m_builtinNumFmtsHash.insert(QStringLiteral("(#,##0_);(#,##0)"), 37);
  112. m_builtinNumFmtsHash.insert(QStringLiteral("(#,##0_);[Red](#,##0)"), 38);
  113. m_builtinNumFmtsHash.insert(QStringLiteral("(#,##0.00_);(#,##0.00)"), 39);
  114. m_builtinNumFmtsHash.insert(QStringLiteral("(#,##0.00_);[Red](#,##0.00)"), 40);
  115. // m_builtinNumFmtsHash.insert(QStringLiteral("_(* #,##0_);_(* (#,##0);_(* \"-\"_);_(_)"), 41);
  116. // m_builtinNumFmtsHash.insert(QStringLiteral("_($* #,##0_);_($* (#,##0);_($* \"-\"_);_(_)"), 42);
  117. // m_builtinNumFmtsHash.insert(QStringLiteral("_(* #,##0.00_);_(* (#,##0.00);_(* \"-\"??_);_(_)"), 43);
  118. // m_builtinNumFmtsHash.insert(QStringLiteral("_($* #,##0.00_);_($* (#,##0.00);_($* \"-\"??_);_(_)"), 44);
  119. m_builtinNumFmtsHash.insert(QStringLiteral("mm:ss"), 45);
  120. m_builtinNumFmtsHash.insert(QStringLiteral("[h]:mm:ss"), 46);
  121. m_builtinNumFmtsHash.insert(QStringLiteral("mm:ss.0"), 47);
  122. m_builtinNumFmtsHash.insert(QStringLiteral("##0.0E+0"), 48);
  123. m_builtinNumFmtsHash.insert(QStringLiteral("@"), 49);
  124. // dev74
  125. // m_builtinNumFmtsHash.insert(QStringLiteral("0.####"), 176);
  126. }
  127. const auto& str = format.numberFormat();
  128. if (!str.isEmpty())
  129. {
  130. QHash<QString, QSharedPointer<XlsxFormatNumberData> >::ConstIterator cIt;
  131. //Assign proper number format index
  132. const auto& it = m_builtinNumFmtsHash.constFind(str);
  133. if (it != m_builtinNumFmtsHash.constEnd())
  134. {
  135. const_cast<Format *>(&format)->fixNumberFormat(it.value(), str);
  136. }
  137. else if ((cIt = m_customNumFmtsHash.constFind(str)) != m_customNumFmtsHash.constEnd())
  138. {
  139. const_cast<Format *>(&format)->fixNumberFormat(cIt.value()->formatIndex, str);
  140. }
  141. else
  142. {
  143. //Assign a new fmt Id.
  144. const_cast<Format *>(&format)->fixNumberFormat(m_nextCustomNumFmtId, str);
  145. QSharedPointer<XlsxFormatNumberData> fmt(new XlsxFormatNumberData);
  146. fmt->formatIndex = m_nextCustomNumFmtId;
  147. fmt->formatString = str;
  148. m_customNumFmtIdMap.insert(m_nextCustomNumFmtId, fmt);
  149. m_customNumFmtsHash.insert(str, fmt);
  150. m_nextCustomNumFmtId += 1;
  151. }
  152. }
  153. else
  154. {
  155. const auto id = format.numberFormatIndex();
  156. //Assign proper format code, this is needed by dxf format
  157. const auto& it = m_customNumFmtIdMap.constFind(id);
  158. if (it != m_customNumFmtIdMap.constEnd())
  159. {
  160. const_cast<Format *>(&format)->fixNumberFormat(id, it.value()->formatString);
  161. }
  162. else
  163. {
  164. bool found = false;
  165. for ( auto&& it = m_builtinNumFmtsHash.constBegin() ; it != m_builtinNumFmtsHash.constEnd() ; ++it )
  166. {
  167. if (it.value() == id)
  168. {
  169. const_cast<Format *>(&format)->fixNumberFormat(id, it.key());
  170. found = true;
  171. break;
  172. }
  173. }
  174. if (!found)
  175. {
  176. //Wrong numFmt
  177. const_cast<Format *>(&format)->fixNumberFormat(id, QStringLiteral("General"));
  178. }
  179. }
  180. }
  181. }
  182. /*
  183. Assign index to Font/Fill/Border and Format
  184. When \a force is true, add the format to the format list, even other format has
  185. the same key have been in.
  186. This is useful when reading existing .xlsx files which may contains duplicated formats.
  187. */
  188. void Styles::addXfFormat(const Format &format, bool force)
  189. {
  190. if (format.isEmpty())
  191. {
  192. //Try do something for empty Format.
  193. if (m_emptyFormatAdded && !force)
  194. return;
  195. m_emptyFormatAdded = true;
  196. }
  197. //numFmt
  198. if (format.hasNumFmtData() &&
  199. !format.hasProperty(FormatPrivate::P_NumFmt_Id))
  200. {
  201. fixNumFmt(format);
  202. }
  203. //Font
  204. const auto& fontIt = m_fontsHash.constFind(format.fontKey());
  205. if (format.hasFontData() && !format.fontIndexValid())
  206. {
  207. //Assign proper font index, if has font data.
  208. if (fontIt == m_fontsHash.constEnd())
  209. const_cast<Format *>(&format)->setFontIndex(m_fontsList.size());
  210. else
  211. const_cast<Format *>(&format)->setFontIndex(fontIt->fontIndex());
  212. }
  213. if (fontIt == m_fontsHash.constEnd())
  214. {
  215. //Still a valid font if the format has no fontData. (All font properties are default)
  216. m_fontsList.append(format);
  217. m_fontsHash[format.fontKey()] = format;
  218. }
  219. //Fill
  220. const auto& fillIt = m_fillsHash.constFind(format.fillKey());
  221. if (format.hasFillData() && !format.fillIndexValid()) {
  222. //Assign proper fill index, if has fill data.
  223. if (fillIt == m_fillsHash.constEnd())
  224. const_cast<Format *>(&format)->setFillIndex(m_fillsList.size());
  225. else
  226. const_cast<Format *>(&format)->setFillIndex(fillIt->fillIndex());
  227. }
  228. if (fillIt == m_fillsHash.constEnd()) {
  229. //Still a valid fill if the format has no fillData. (All fill properties are default)
  230. m_fillsList.append(format);
  231. m_fillsHash[format.fillKey()] = format;
  232. }
  233. //Border
  234. const auto& borderIt = m_bordersHash.constFind(format.borderKey());
  235. if (format.hasBorderData() && !format.borderIndexValid()) {
  236. //Assign proper border index, if has border data.
  237. if (borderIt == m_bordersHash.constEnd())
  238. const_cast<Format *>(&format)->setBorderIndex(m_bordersList.size());
  239. else
  240. const_cast<Format *>(&format)->setBorderIndex(borderIt->borderIndex());
  241. }
  242. if (borderIt == m_bordersHash.constEnd()) {
  243. //Still a valid border if the format has no borderData. (All border properties are default)
  244. m_bordersList.append(format);
  245. m_bordersHash[format.borderKey()] = format;
  246. }
  247. //Format
  248. const auto& formatIt = m_xf_formatsHash.constFind(format.formatKey());
  249. if (!format.isEmpty() && !format.xfIndexValid())
  250. {
  251. if (formatIt == m_xf_formatsHash.constEnd())
  252. const_cast<Format *>(&format)->setXfIndex(m_xf_formatsList.size());
  253. else
  254. const_cast<Format *>(&format)->setXfIndex(formatIt->xfIndex());
  255. }
  256. if (formatIt == m_xf_formatsHash.constEnd() ||
  257. force)
  258. {
  259. m_xf_formatsList.append(format);
  260. m_xf_formatsHash[format.formatKey()] = format;
  261. }
  262. }
  263. void Styles::addDxfFormat(const Format &format, bool force)
  264. {
  265. //numFmt
  266. if ( format.hasNumFmtData() )
  267. {
  268. fixNumFmt(format);
  269. }
  270. const auto& formatIt = m_dxf_formatsHash.constFind(format.formatKey());
  271. if ( !format.isEmpty() &&
  272. !format.dxfIndexValid() )
  273. {
  274. if (formatIt == m_dxf_formatsHash.constEnd() ) // m_xf_formatsHash.constEnd()) // issue #108
  275. {
  276. const_cast<Format *>(&format)->setDxfIndex( m_dxf_formatsList.size() );
  277. }
  278. else
  279. {
  280. const_cast<Format *>(&format)->setDxfIndex( formatIt->dxfIndex() );
  281. }
  282. }
  283. if (formatIt == m_xf_formatsHash.constEnd() ||
  284. force )
  285. {
  286. m_dxf_formatsList.append(format);
  287. m_dxf_formatsHash[ format.formatKey() ] = format;
  288. }
  289. }
  290. void Styles::saveToXmlFile(QIODevice *device) const
  291. {
  292. QXmlStreamWriter writer(device);
  293. writer.writeStartDocument(QStringLiteral("1.0"), true);
  294. writer.writeStartElement(QStringLiteral("styleSheet"));
  295. writer.writeAttribute(QStringLiteral("xmlns"), QStringLiteral("http://schemas.openxmlformats.org/spreadsheetml/2006/main"));
  296. writeNumFmts(writer);
  297. writeFonts(writer);
  298. writeFills(writer);
  299. writeBorders(writer);
  300. writer.writeStartElement(QStringLiteral("cellStyleXfs"));
  301. writer.writeAttribute(QStringLiteral("count"), QStringLiteral("1"));
  302. writer.writeStartElement(QStringLiteral("xf"));
  303. writer.writeAttribute(QStringLiteral("numFmtId"), QStringLiteral("0"));
  304. writer.writeAttribute(QStringLiteral("fontId"), QStringLiteral("0"));
  305. writer.writeAttribute(QStringLiteral("fillId"), QStringLiteral("0"));
  306. writer.writeAttribute(QStringLiteral("borderId"), QStringLiteral("0"));
  307. writer.writeEndElement();//xf
  308. writer.writeEndElement();//cellStyleXfs
  309. writeCellXfs(writer);
  310. writer.writeStartElement(QStringLiteral("cellStyles"));
  311. writer.writeAttribute(QStringLiteral("count"), QStringLiteral("1"));
  312. writer.writeStartElement(QStringLiteral("cellStyle"));
  313. writer.writeAttribute(QStringLiteral("name"), QStringLiteral("Normal"));
  314. writer.writeAttribute(QStringLiteral("xfId"), QStringLiteral("0"));
  315. writer.writeAttribute(QStringLiteral("builtinId"), QStringLiteral("0"));
  316. writer.writeEndElement();//cellStyle
  317. writer.writeEndElement();//cellStyles
  318. writeDxfs(writer);
  319. writer.writeStartElement(QStringLiteral("tableStyles"));
  320. writer.writeAttribute(QStringLiteral("count"), QStringLiteral("0"));
  321. writer.writeAttribute(QStringLiteral("defaultTableStyle"), QStringLiteral("TableStyleMedium9"));
  322. writer.writeAttribute(QStringLiteral("defaultPivotStyle"), QStringLiteral("PivotStyleLight16"));
  323. writer.writeEndElement();//tableStyles
  324. writeColors(writer);
  325. writer.writeEndElement();//styleSheet
  326. writer.writeEndDocument();
  327. }
  328. void Styles::writeNumFmts(QXmlStreamWriter &writer) const
  329. {
  330. if (m_customNumFmtIdMap.size() == 0)
  331. return;
  332. writer.writeStartElement(QStringLiteral("numFmts"));
  333. writer.writeAttribute(QStringLiteral("count"), QString::number(m_customNumFmtIdMap.count()));
  334. QMapIterator<int, QSharedPointer<XlsxFormatNumberData> > it(m_customNumFmtIdMap);
  335. while (it.hasNext()) {
  336. it.next();
  337. writer.writeEmptyElement(QStringLiteral("numFmt"));
  338. writer.writeAttribute(QStringLiteral("numFmtId"), QString::number(it.value()->formatIndex));
  339. writer.writeAttribute(QStringLiteral("formatCode"), it.value()->formatString);
  340. }
  341. writer.writeEndElement();//numFmts
  342. }
  343. /*
  344. */
  345. void Styles::writeFonts(QXmlStreamWriter &writer) const
  346. {
  347. writer.writeStartElement(QStringLiteral("fonts"));
  348. writer.writeAttribute(QStringLiteral("count"), QString::number(m_fontsList.count()));
  349. for (size_t i=0; i<m_fontsList.size(); ++i)
  350. writeFont(writer, m_fontsList[i], false);
  351. writer.writeEndElement();//fonts
  352. }
  353. void Styles::writeFont(QXmlStreamWriter &writer, const Format &format, bool isDxf) const
  354. {
  355. writer.writeStartElement(QStringLiteral("font"));
  356. //The condense and extend elements are mainly used in dxf format
  357. if (format.hasProperty(FormatPrivate::P_Font_Condense)
  358. && !format.boolProperty(FormatPrivate::P_Font_Condense)) {
  359. writer.writeEmptyElement(QStringLiteral("condense"));
  360. writer.writeAttribute(QStringLiteral("val"), QStringLiteral("0"));
  361. }
  362. if (format.hasProperty(FormatPrivate::P_Font_Extend)
  363. && !format.boolProperty(FormatPrivate::P_Font_Extend)) {
  364. writer.writeEmptyElement(QStringLiteral("extend"));
  365. writer.writeAttribute(QStringLiteral("val"), QStringLiteral("0"));
  366. }
  367. if (format.fontBold())
  368. writer.writeEmptyElement(QStringLiteral("b"));
  369. if (format.fontItalic())
  370. writer.writeEmptyElement(QStringLiteral("i"));
  371. if (format.fontStrikeOut())
  372. writer.writeEmptyElement(QStringLiteral("strike"));
  373. if (format.fontOutline())
  374. writer.writeEmptyElement(QStringLiteral("outline"));
  375. if (format.boolProperty(FormatPrivate::P_Font_Shadow))
  376. writer.writeEmptyElement(QStringLiteral("shadow"));
  377. if (format.hasProperty(FormatPrivate::P_Font_Underline)) {
  378. Format::FontUnderline u = format.fontUnderline();
  379. if (u != Format::FontUnderlineNone) {
  380. writer.writeEmptyElement(QStringLiteral("u"));
  381. if (u== Format::FontUnderlineDouble)
  382. writer.writeAttribute(QStringLiteral("val"), QStringLiteral("double"));
  383. else if (u == Format::FontUnderlineSingleAccounting)
  384. writer.writeAttribute(QStringLiteral("val"), QStringLiteral("singleAccounting"));
  385. else if (u == Format::FontUnderlineDoubleAccounting)
  386. writer.writeAttribute(QStringLiteral("val"), QStringLiteral("doubleAccounting"));
  387. }
  388. }
  389. if (format.hasProperty(FormatPrivate::P_Font_Script)) {
  390. Format::FontScript s = format.fontScript();
  391. if (s != Format::FontScriptNormal) {
  392. writer.writeEmptyElement(QStringLiteral("vertAlign"));
  393. if (s == Format::FontScriptSuper)
  394. writer.writeAttribute(QStringLiteral("val"), QStringLiteral("superscript"));
  395. else
  396. writer.writeAttribute(QStringLiteral("val"), QStringLiteral("subscript"));
  397. }
  398. }
  399. if (!isDxf && format.hasProperty(FormatPrivate::P_Font_Size)) {
  400. writer.writeEmptyElement(QStringLiteral("sz"));
  401. writer.writeAttribute(QStringLiteral("val"), QString::number(format.fontSize()));
  402. }
  403. if (format.hasProperty(FormatPrivate::P_Font_Color)) {
  404. XlsxColor color = format.property(FormatPrivate::P_Font_Color).value<XlsxColor>();
  405. color.saveToXml(writer);
  406. }
  407. if (!isDxf) {
  408. if (!format.fontName().isEmpty()) {
  409. writer.writeEmptyElement(QStringLiteral("name"));
  410. writer.writeAttribute(QStringLiteral("val"), format.fontName());
  411. }
  412. if (format.hasProperty(FormatPrivate::P_Font_Charset)) {
  413. writer.writeEmptyElement(QStringLiteral("charset"));
  414. writer.writeAttribute(QStringLiteral("val"), QString::number(format.intProperty(FormatPrivate::P_Font_Charset)));
  415. }
  416. if (format.hasProperty(FormatPrivate::P_Font_Family)) {
  417. writer.writeEmptyElement(QStringLiteral("family"));
  418. writer.writeAttribute(QStringLiteral("val"), QString::number(format.intProperty(FormatPrivate::P_Font_Family)));
  419. }
  420. if (format.hasProperty(FormatPrivate::P_Font_Scheme)) {
  421. writer.writeEmptyElement(QStringLiteral("scheme"));
  422. writer.writeAttribute(QStringLiteral("val"), format.stringProperty(FormatPrivate::P_Font_Scheme));
  423. }
  424. }
  425. writer.writeEndElement(); //font
  426. }
  427. void Styles::writeFills(QXmlStreamWriter &writer) const
  428. {
  429. writer.writeStartElement(QStringLiteral("fills"));
  430. writer.writeAttribute(QStringLiteral("count"), QString::number(m_fillsList.size()));
  431. for (size_t i=0; i<m_fillsList.size(); ++i)
  432. writeFill(writer, m_fillsList[i]);
  433. writer.writeEndElement(); //fills
  434. }
  435. void Styles::writeFill(QXmlStreamWriter &writer, const Format &fill, bool isDxf) const
  436. {
  437. static const QMap<int, QString> patternStrings = {
  438. {Format::PatternNone, QStringLiteral("none")},
  439. {Format::PatternSolid, QStringLiteral("solid")},
  440. {Format::PatternMediumGray, QStringLiteral("mediumGray")},
  441. {Format::PatternDarkGray, QStringLiteral("darkGray")},
  442. {Format::PatternLightGray, QStringLiteral("lightGray")},
  443. {Format::PatternDarkHorizontal, QStringLiteral("darkHorizontal")},
  444. {Format::PatternDarkVertical, QStringLiteral("darkVertical")},
  445. {Format::PatternDarkDown, QStringLiteral("darkDown")},
  446. {Format::PatternDarkUp, QStringLiteral("darkUp")},
  447. {Format::PatternDarkGrid, QStringLiteral("darkGrid")},
  448. {Format::PatternDarkTrellis, QStringLiteral("darkTrellis")},
  449. {Format::PatternLightHorizontal, QStringLiteral("lightHorizontal")},
  450. {Format::PatternLightVertical, QStringLiteral("lightVertical")},
  451. {Format::PatternLightDown, QStringLiteral("lightDown")},
  452. {Format::PatternLightUp, QStringLiteral("lightUp")},
  453. {Format::PatternLightTrellis, QStringLiteral("lightTrellis")},
  454. {Format::PatternGray125, QStringLiteral("gray125")},
  455. {Format::PatternGray0625, QStringLiteral("gray0625")},
  456. {Format::PatternLightGrid, QStringLiteral("lightGrid")}
  457. };
  458. writer.writeStartElement(QStringLiteral("fill"));
  459. writer.writeStartElement(QStringLiteral("patternFill"));
  460. Format::FillPattern pattern = fill.fillPattern();
  461. // For normal fill formats, Excel prefer to outputing the default "none" attribute
  462. // But for dxf, Excel prefer to omiting the default "none"
  463. // Though not make any difference, but it make easier to compare origin files with generate files during debug
  464. if (!(pattern == Format::PatternNone && isDxf))
  465. writer.writeAttribute(QStringLiteral("patternType"), patternStrings[pattern]);
  466. // For a solid fill, Excel reverses the role of foreground and background colours
  467. if (fill.fillPattern() == Format::PatternSolid) {
  468. if (fill.hasProperty(FormatPrivate::P_Fill_BgColor))
  469. fill.property(FormatPrivate::P_Fill_BgColor).value<XlsxColor>().saveToXml(writer, QStringLiteral("fgColor"));
  470. if (fill.hasProperty(FormatPrivate::P_Fill_FgColor))
  471. fill.property(FormatPrivate::P_Fill_FgColor).value<XlsxColor>().saveToXml(writer, QStringLiteral("bgColor"));
  472. } else {
  473. if (fill.hasProperty(FormatPrivate::P_Fill_FgColor))
  474. fill.property(FormatPrivate::P_Fill_FgColor).value<XlsxColor>().saveToXml(writer, QStringLiteral("fgColor"));
  475. if (fill.hasProperty(FormatPrivate::P_Fill_BgColor))
  476. fill.property(FormatPrivate::P_Fill_BgColor).value<XlsxColor>().saveToXml(writer, QStringLiteral("bgColor"));
  477. }
  478. writer.writeEndElement();//patternFill
  479. writer.writeEndElement();//fill
  480. }
  481. void Styles::writeBorders(QXmlStreamWriter &writer) const
  482. {
  483. writer.writeStartElement(QStringLiteral("borders"));
  484. writer.writeAttribute(QStringLiteral("count"), QString::number(m_bordersList.count()));
  485. for (size_t i=0; i<m_bordersList.size(); ++i)
  486. writeBorder(writer, m_bordersList[i]);
  487. writer.writeEndElement();//borders
  488. }
  489. void Styles::writeBorder(QXmlStreamWriter &writer, const Format &border, bool isDxf) const
  490. {
  491. writer.writeStartElement(QStringLiteral("border"));
  492. if (border.hasProperty(FormatPrivate::P_Border_DiagonalType)) {
  493. Format::DiagonalBorderType t = border.diagonalBorderType();
  494. if (t == Format::DiagonalBorderUp) {
  495. writer.writeAttribute(QStringLiteral("diagonalUp"), QStringLiteral("1"));
  496. } else if (t == Format::DiagonalBorderDown) {
  497. writer.writeAttribute(QStringLiteral("diagonalDown"), QStringLiteral("1"));
  498. } else if (t == Format::DiagnoalBorderBoth) {
  499. writer.writeAttribute(QStringLiteral("diagonalUp"), QStringLiteral("1"));
  500. writer.writeAttribute(QStringLiteral("diagonalDown"), QStringLiteral("1"));
  501. }
  502. }
  503. writeSubBorder(writer, QStringLiteral("left"), border.leftBorderStyle(), border.property(FormatPrivate::P_Border_LeftColor).value<XlsxColor>());
  504. writeSubBorder(writer, QStringLiteral("right"), border.rightBorderStyle(), border.property(FormatPrivate::P_Border_RightColor).value<XlsxColor>());
  505. writeSubBorder(writer, QStringLiteral("top"), border.topBorderStyle(), border.property(FormatPrivate::P_Border_TopColor).value<XlsxColor>());
  506. writeSubBorder(writer, QStringLiteral("bottom"), border.bottomBorderStyle(), border.property(FormatPrivate::P_Border_BottomColor).value<XlsxColor>());
  507. //Condition DXF formats don't allow diagonal style
  508. if (!isDxf)
  509. writeSubBorder(writer, QStringLiteral("diagonal"), border.diagonalBorderStyle(), border.property(FormatPrivate::P_Border_DiagonalColor).value<XlsxColor>());
  510. if (isDxf) {
  511. // writeSubBorder(wirter, QStringLiteral("vertical"), );
  512. // writeSubBorder(writer, QStringLiteral("horizontal"), );
  513. }
  514. writer.writeEndElement();//border
  515. }
  516. void Styles::writeSubBorder(QXmlStreamWriter &writer, const QString &type, int style, const XlsxColor &color) const
  517. {
  518. if (style == Format::BorderNone) {
  519. writer.writeEmptyElement(type);
  520. return;
  521. }
  522. static const QMap<int, QString> stylesString = {
  523. {Format::BorderNone, QStringLiteral("none")},
  524. {Format::BorderThin, QStringLiteral("thin")},
  525. {Format::BorderMedium, QStringLiteral("medium")},
  526. {Format::BorderDashed, QStringLiteral("dashed")},
  527. {Format::BorderDotted, QStringLiteral("dotted")},
  528. {Format::BorderThick, QStringLiteral("thick")},
  529. {Format::BorderDouble, QStringLiteral("double")},
  530. {Format::BorderHair, QStringLiteral("hair")},
  531. {Format::BorderMediumDashed, QStringLiteral("mediumDashed")},
  532. {Format::BorderDashDot, QStringLiteral("dashDot")},
  533. {Format::BorderMediumDashDot, QStringLiteral("mediumDashDot")},
  534. {Format::BorderDashDotDot, QStringLiteral("dashDotDot")},
  535. {Format::BorderMediumDashDotDot, QStringLiteral("mediumDashDotDot")},
  536. {Format::BorderSlantDashDot, QStringLiteral("slantDashDot")}
  537. };
  538. writer.writeStartElement(type);
  539. writer.writeAttribute(QStringLiteral("style"), stylesString[style]);
  540. color.saveToXml(writer); //write color element
  541. writer.writeEndElement();//type
  542. }
  543. void Styles::writeCellXfs(QXmlStreamWriter &writer) const
  544. {
  545. writer.writeStartElement(QStringLiteral("cellXfs"));
  546. writer.writeAttribute(QStringLiteral("count"), QString::number(m_xf_formatsList.size()));
  547. for (const Format &format : m_xf_formatsList) {
  548. int xf_id = 0;
  549. writer.writeStartElement(QStringLiteral("xf"));
  550. writer.writeAttribute(QStringLiteral("numFmtId"), QString::number(format.numberFormatIndex()));
  551. writer.writeAttribute(QStringLiteral("fontId"), QString::number(format.fontIndex()));
  552. writer.writeAttribute(QStringLiteral("fillId"), QString::number(format.fillIndex()));
  553. writer.writeAttribute(QStringLiteral("borderId"), QString::number(format.borderIndex()));
  554. writer.writeAttribute(QStringLiteral("xfId"), QString::number(xf_id));
  555. if (format.hasNumFmtData())
  556. writer.writeAttribute(QStringLiteral("applyNumberFormat"), QStringLiteral("1"));
  557. if (format.hasFontData())
  558. writer.writeAttribute(QStringLiteral("applyFont"), QStringLiteral("1"));
  559. if (format.hasFillData())
  560. writer.writeAttribute(QStringLiteral("applyFill"), QStringLiteral("1"));
  561. if (format.hasBorderData())
  562. writer.writeAttribute(QStringLiteral("applyBorder"), QStringLiteral("1"));
  563. if (format.hasAlignmentData())
  564. writer.writeAttribute(QStringLiteral("applyAlignment"), QStringLiteral("1"));
  565. if (format.hasAlignmentData()) {
  566. writer.writeEmptyElement(QStringLiteral("alignment"));
  567. if (format.hasProperty(FormatPrivate::P_Alignment_AlignH)) {
  568. switch (format.horizontalAlignment()) {
  569. case Format::AlignLeft:
  570. writer.writeAttribute(QStringLiteral("horizontal"), QStringLiteral("left"));
  571. break;
  572. case Format::AlignHCenter:
  573. writer.writeAttribute(QStringLiteral("horizontal"), QStringLiteral("center"));
  574. break;
  575. case Format::AlignRight:
  576. writer.writeAttribute(QStringLiteral("horizontal"), QStringLiteral("right"));
  577. break;
  578. case Format::AlignHFill:
  579. writer.writeAttribute(QStringLiteral("horizontal"), QStringLiteral("fill"));
  580. break;
  581. case Format::AlignHJustify:
  582. writer.writeAttribute(QStringLiteral("horizontal"), QStringLiteral("justify"));
  583. break;
  584. case Format::AlignHMerge:
  585. writer.writeAttribute(QStringLiteral("horizontal"), QStringLiteral("centerContinuous"));
  586. break;
  587. case Format::AlignHDistributed:
  588. writer.writeAttribute(QStringLiteral("horizontal"), QStringLiteral("distributed"));
  589. break;
  590. default:
  591. break;
  592. }
  593. }
  594. if (format.hasProperty(FormatPrivate::P_Alignment_AlignV)) {
  595. switch (format.verticalAlignment()) {
  596. case Format::AlignTop:
  597. writer.writeAttribute(QStringLiteral("vertical"), QStringLiteral("top"));
  598. break;
  599. case Format::AlignVCenter:
  600. writer.writeAttribute(QStringLiteral("vertical"), QStringLiteral("center"));
  601. break;
  602. case Format::AlignVJustify:
  603. writer.writeAttribute(QStringLiteral("vertical"), QStringLiteral("justify"));
  604. break;
  605. case Format::AlignVDistributed:
  606. writer.writeAttribute(QStringLiteral("vertical"), QStringLiteral("distributed"));
  607. break;
  608. default:
  609. break;
  610. }
  611. }
  612. if (format.hasProperty(FormatPrivate::P_Alignment_Indent))
  613. writer.writeAttribute(QStringLiteral("indent"), QString::number(format.indent()));
  614. if (format.hasProperty(FormatPrivate::P_Alignment_Wrap) && format.textWrap())
  615. writer.writeAttribute(QStringLiteral("wrapText"), QStringLiteral("1"));
  616. if (format.hasProperty(FormatPrivate::P_Alignment_ShinkToFit) && format.shrinkToFit())
  617. writer.writeAttribute(QStringLiteral("shrinkToFit"), QStringLiteral("1"));
  618. if (format.hasProperty(FormatPrivate::P_Alignment_Rotation))
  619. writer.writeAttribute(QStringLiteral("textRotation"), QString::number(format.rotation()));
  620. }
  621. writer.writeEndElement();//xf
  622. }
  623. writer.writeEndElement();//cellXfs
  624. }
  625. void Styles::writeDxfs(QXmlStreamWriter &writer) const
  626. {
  627. writer.writeStartElement(QStringLiteral("dxfs"));
  628. writer.writeAttribute(QStringLiteral("count"), QString::number(m_dxf_formatsList.size()));
  629. for (const Format &format : m_dxf_formatsList)
  630. writeDxf(writer, format);
  631. writer.writeEndElement(); //dxfs
  632. }
  633. void Styles::writeDxf(QXmlStreamWriter &writer, const Format &format) const
  634. {
  635. writer.writeStartElement(QStringLiteral("dxf"));
  636. if (format.hasFontData())
  637. writeFont(writer, format, true);
  638. if (format.hasNumFmtData()) {
  639. writer.writeEmptyElement(QStringLiteral("numFmt"));
  640. writer.writeAttribute(QStringLiteral("numFmtId"), QString::number(format.numberFormatIndex()));
  641. writer.writeAttribute(QStringLiteral("formatCode"), format.numberFormat());
  642. }
  643. if (format.hasFillData())
  644. writeFill(writer, format, true);
  645. if (format.hasBorderData())
  646. writeBorder(writer, format, true);
  647. writer.writeEndElement();//dxf
  648. }
  649. void Styles::writeColors(QXmlStreamWriter &writer) const
  650. {
  651. if (m_isIndexedColorsDefault) //Don't output the default indexdeColors
  652. return;
  653. writer.writeStartElement(QStringLiteral("colors"));
  654. writer.writeStartElement(QStringLiteral("indexedColors"));
  655. for (const QColor &color : m_indexedColors) {
  656. writer.writeEmptyElement(QStringLiteral("rgbColor"));
  657. writer.writeAttribute(QStringLiteral("rgb"), XlsxColor::toARGBString(color));
  658. }
  659. writer.writeEndElement();//indexedColors
  660. writer.writeEndElement();//colors
  661. }
  662. bool Styles::readNumFmts(QXmlStreamReader &reader)
  663. {
  664. Q_ASSERT(reader.name() == QLatin1String("numFmts"));
  665. const auto& attributes = reader.attributes();
  666. const auto hasCount = attributes.hasAttribute(QLatin1String("count"));
  667. const auto count = hasCount ? attributes.value(QLatin1String("count")).toString().toInt() : -1;
  668. //Read utill we find the numFmts end tag or ....
  669. while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement
  670. && reader.name() == QLatin1String("numFmts"))) {
  671. reader.readNextStartElement();
  672. if (reader.tokenType() == QXmlStreamReader::StartElement) {
  673. if (reader.name() == QLatin1String("numFmt")) {
  674. const auto& attributes = reader.attributes();
  675. QSharedPointer<XlsxFormatNumberData> fmt (new XlsxFormatNumberData);
  676. fmt->formatIndex = attributes.value(QLatin1String("numFmtId")).toString().toInt();
  677. fmt->formatString = attributes.value(QLatin1String("formatCode")).toString();
  678. if (fmt->formatIndex >= m_nextCustomNumFmtId)
  679. m_nextCustomNumFmtId = fmt->formatIndex + 1;
  680. m_customNumFmtIdMap.insert(fmt->formatIndex, fmt);
  681. m_customNumFmtsHash.insert(fmt->formatString, fmt);
  682. }
  683. }
  684. }
  685. if (reader.hasError())
  686. qWarning()<<reader.errorString();
  687. if (hasCount && (count != m_customNumFmtIdMap.size()))
  688. qWarning("error read custom numFmts");
  689. return true;
  690. }
  691. bool Styles::readFonts(QXmlStreamReader &reader)
  692. {
  693. Q_ASSERT(reader.name() == QLatin1String("fonts"));
  694. const auto& attributes = reader.attributes();
  695. const auto hasCount = attributes.hasAttribute(QLatin1String("count"));
  696. const auto count = hasCount ? attributes.value(QLatin1String("count")).toString().toInt() : -1;
  697. while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement
  698. && reader.name() == QLatin1String("fonts"))) {
  699. reader.readNextStartElement();
  700. if (reader.tokenType() == QXmlStreamReader::StartElement) {
  701. if (reader.name() == QLatin1String("font")) {
  702. Format format;
  703. readFont(reader, format);
  704. m_fontsList.append(format);
  705. m_fontsHash.insert(format.fontKey(), format);
  706. if (format.isValid())
  707. format.setFontIndex(m_fontsList.size()-1);
  708. }
  709. }
  710. }
  711. if (reader.hasError())
  712. qWarning()<<reader.errorString();
  713. if (hasCount && (count != m_fontsList.size()))
  714. qWarning("error read fonts");
  715. return true;
  716. }
  717. bool Styles::readFont(QXmlStreamReader &reader, Format &format)
  718. {
  719. Q_ASSERT(reader.name() == QLatin1String("font"));
  720. while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement
  721. && reader.name() == QLatin1String("font"))) {
  722. reader.readNextStartElement();
  723. if (reader.tokenType() == QXmlStreamReader::StartElement) {
  724. const auto& attributes = reader.attributes();
  725. if (reader.name() == QLatin1String("name")) {
  726. format.setFontName(attributes.value(QLatin1String("val")).toString());
  727. } else if (reader.name() == QLatin1String("charset")) {
  728. format.setProperty(FormatPrivate::P_Font_Charset, attributes.value(QLatin1String("val")).toString().toInt());
  729. } else if (reader.name() == QLatin1String("family")) {
  730. format.setProperty(FormatPrivate::P_Font_Family, attributes.value(QLatin1String("val")).toString().toInt());
  731. } else if (reader.name() == QLatin1String("b")) {
  732. format.setFontBold(true);
  733. } else if (reader.name() == QLatin1String("i")) {
  734. format.setFontItalic(true);
  735. } else if (reader.name() == QLatin1String("strike")) {
  736. format.setFontStrikeOut(true);
  737. } else if (reader.name() == QLatin1String("outline")) {
  738. format.setFontOutline(true);
  739. } else if (reader.name() == QLatin1String("shadow")) {
  740. format.setProperty(FormatPrivate::P_Font_Shadow, true);
  741. } else if (reader.name() == QLatin1String("condense")) {
  742. format.setProperty(FormatPrivate::P_Font_Condense, attributes.value(QLatin1String("val")).toString().toInt());
  743. } else if (reader.name() == QLatin1String("extend")) {
  744. format.setProperty(FormatPrivate::P_Font_Extend, attributes.value(QLatin1String("val")).toString().toInt());
  745. } else if (reader.name() == QLatin1String("color")) {
  746. XlsxColor color;
  747. color.loadFromXml(reader);
  748. format.setProperty(FormatPrivate::P_Font_Color, color);
  749. } else if (reader.name() == QLatin1String("sz")) {
  750. const auto sz = attributes.value(QLatin1String("val")).toString().toInt();
  751. format.setFontSize(sz);
  752. } else if (reader.name() == QLatin1String("u")) {
  753. QString value = attributes.value(QLatin1String("val")).toString();
  754. if (value == QLatin1String("double"))
  755. format.setFontUnderline(Format::FontUnderlineDouble);
  756. else if (value == QLatin1String("doubleAccounting"))
  757. format.setFontUnderline(Format::FontUnderlineDoubleAccounting);
  758. else if (value == QLatin1String("singleAccounting"))
  759. format.setFontUnderline(Format::FontUnderlineSingleAccounting);
  760. else
  761. format.setFontUnderline(Format::FontUnderlineSingle);
  762. } else if (reader.name() == QLatin1String("vertAlign")) {
  763. QString value = attributes.value(QLatin1String("val")).toString();
  764. if (value == QLatin1String("superscript"))
  765. format.setFontScript(Format::FontScriptSuper);
  766. else if (value == QLatin1String("subscript"))
  767. format.setFontScript(Format::FontScriptSub);
  768. } else if (reader.name() == QLatin1String("scheme")) {
  769. format.setProperty(FormatPrivate::P_Font_Scheme, attributes.value(QLatin1String("val")).toString());
  770. }
  771. }
  772. }
  773. return true;
  774. }
  775. bool Styles::readFills(QXmlStreamReader &reader)
  776. {
  777. Q_ASSERT(reader.name() == QLatin1String("fills"));
  778. const auto& attributes = reader.attributes();
  779. const auto hasCount = attributes.hasAttribute(QLatin1String("count"));
  780. const auto count = hasCount ? attributes.value(QLatin1String("count")).toString().toInt() : -1;
  781. while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement
  782. && reader.name() == QLatin1String("fills"))) {
  783. reader.readNextStartElement();
  784. if (reader.tokenType() == QXmlStreamReader::StartElement) {
  785. if (reader.name() == QLatin1String("fill")) {
  786. Format fill;
  787. readFill(reader, fill);
  788. m_fillsList.append(fill);
  789. m_fillsHash.insert(fill.fillKey(), fill);
  790. if (fill.isValid())
  791. fill.setFillIndex(m_fillsList.size()-1);
  792. }
  793. }
  794. }
  795. if (reader.hasError())
  796. qWarning()<<reader.errorString();
  797. if (hasCount && (count != m_fillsList.size()))
  798. qWarning("error read fills");
  799. return true;
  800. }
  801. bool Styles::readFill(QXmlStreamReader &reader, Format &fill)
  802. {
  803. Q_ASSERT(reader.name() == QLatin1String("fill"));
  804. static const QMap<QString, Format::FillPattern> patternValues = {
  805. {QStringLiteral("none"), Format::PatternNone},
  806. {QStringLiteral("solid"), Format::PatternSolid},
  807. {QStringLiteral("mediumGray"), Format::PatternMediumGray},
  808. {QStringLiteral("darkGray"), Format::PatternDarkGray},
  809. {QStringLiteral("lightGray"), Format::PatternLightGray},
  810. {QStringLiteral("darkHorizontal"), Format::PatternDarkHorizontal},
  811. {QStringLiteral("darkVertical"), Format::PatternDarkVertical},
  812. {QStringLiteral("darkDown"), Format::PatternDarkDown},
  813. {QStringLiteral("darkUp"), Format::PatternDarkUp},
  814. {QStringLiteral("darkGrid"), Format::PatternDarkGrid},
  815. {QStringLiteral("darkTrellis"), Format::PatternDarkTrellis},
  816. {QStringLiteral("lightHorizontal"), Format::PatternLightHorizontal},
  817. {QStringLiteral("lightVertical"), Format::PatternLightVertical},
  818. {QStringLiteral("lightDown"), Format::PatternLightDown},
  819. {QStringLiteral("lightUp"), Format::PatternLightUp},
  820. {QStringLiteral("lightTrellis"), Format::PatternLightTrellis},
  821. {QStringLiteral("gray125"), Format::PatternGray125},
  822. {QStringLiteral("gray0625"), Format::PatternGray0625},
  823. {QStringLiteral("lightGrid"), Format::PatternLightGrid}
  824. };
  825. while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("fill"))) {
  826. reader.readNextStartElement();
  827. if (reader.tokenType() == QXmlStreamReader::StartElement) {
  828. if (reader.name() == QLatin1String("patternFill")) {
  829. const auto& attributes = reader.attributes();
  830. if (attributes.hasAttribute(QLatin1String("patternType"))) {
  831. const auto& it = patternValues.constFind(attributes.value(QLatin1String("patternType")).toString());
  832. fill.setFillPattern(it != patternValues.constEnd() ? it.value() : Format::PatternNone);
  833. //parse foreground and background colors if they exist
  834. while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("patternFill"))) {
  835. reader.readNextStartElement();
  836. if (reader.tokenType() == QXmlStreamReader::StartElement) {
  837. if (reader.name() == QLatin1String("fgColor")) {
  838. XlsxColor c;
  839. if ( c.loadFromXml(reader) )
  840. {
  841. if (fill.fillPattern() == Format::PatternSolid)
  842. fill.setProperty(FormatPrivate::P_Fill_BgColor, c);
  843. else
  844. fill.setProperty(FormatPrivate::P_Fill_FgColor, c);
  845. }
  846. } else if (reader.name() == QLatin1String("bgColor")) {
  847. XlsxColor c;
  848. if ( c.loadFromXml(reader) )
  849. {
  850. if (fill.fillPattern() == Format::PatternSolid)
  851. fill.setProperty(FormatPrivate::P_Fill_FgColor, c);
  852. else
  853. fill.setProperty(FormatPrivate::P_Fill_BgColor, c);
  854. }
  855. }
  856. }
  857. }
  858. }
  859. }
  860. }
  861. }
  862. return true;
  863. }
  864. bool Styles::readBorders(QXmlStreamReader &reader)
  865. {
  866. Q_ASSERT(reader.name() == QLatin1String("borders"));
  867. const auto& attributes = reader.attributes();
  868. const auto hasCount = attributes.hasAttribute(QLatin1String("count"));
  869. const auto count = hasCount ? attributes.value(QLatin1String("count")).toString().toInt() : -1;
  870. while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement
  871. && reader.name() == QLatin1String("borders"))) {
  872. reader.readNextStartElement();
  873. if (reader.tokenType() == QXmlStreamReader::StartElement) {
  874. if (reader.name() == QLatin1String("border")) {
  875. Format border;
  876. readBorder(reader, border);
  877. m_bordersList.append(border);
  878. m_bordersHash.insert(border.borderKey(), border);
  879. if (border.isValid())
  880. border.setBorderIndex(m_bordersList.size()-1);
  881. }
  882. }
  883. }
  884. if (reader.hasError())
  885. qWarning()<<reader.errorString();
  886. if (hasCount && (count != m_bordersList.size()))
  887. qWarning("error read borders");
  888. return true;
  889. }
  890. bool Styles::readBorder(QXmlStreamReader &reader, Format &border)
  891. {
  892. Q_ASSERT(reader.name() == QLatin1String("border"));
  893. const auto& attributes = reader.attributes();
  894. const auto isUp = attributes.hasAttribute(QLatin1String("diagonalUp"));
  895. const auto isDown = attributes.hasAttribute(QLatin1String("diagonalUp"));
  896. if (isUp && isDown)
  897. border.setDiagonalBorderType(Format::DiagnoalBorderBoth);
  898. else if (isUp)
  899. border.setDiagonalBorderType(Format::DiagonalBorderUp);
  900. else if (isDown)
  901. border.setDiagonalBorderType(Format::DiagonalBorderDown);
  902. while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("border"))) {
  903. reader.readNextStartElement();
  904. if (reader.tokenType() == QXmlStreamReader::StartElement) {
  905. if (reader.name() == QLatin1String("left") || reader.name() == QLatin1String("right")
  906. || reader.name() == QLatin1String("top") || reader.name() == QLatin1String("bottom")
  907. || reader.name() == QLatin1String("diagonal") ) {
  908. Format::BorderStyle style(Format::BorderNone);
  909. XlsxColor color;
  910. readSubBorder(reader, reader.name().toString(), style, color);
  911. if (reader.name() == QLatin1String("left")) {
  912. border.setLeftBorderStyle(style);
  913. if (!color.isInvalid())
  914. border.setProperty(FormatPrivate::P_Border_LeftColor, color);
  915. } else if (reader.name() == QLatin1String("right")) {
  916. border.setRightBorderStyle(style);
  917. if (!color.isInvalid())
  918. border.setProperty(FormatPrivate::P_Border_RightColor, color);
  919. } else if (reader.name() == QLatin1String("top")) {
  920. border.setTopBorderStyle(style);
  921. if (!color.isInvalid())
  922. border.setProperty(FormatPrivate::P_Border_TopColor, color);
  923. } else if (reader.name() == QLatin1String("bottom")) {
  924. border.setBottomBorderStyle(style);
  925. if (!color.isInvalid())
  926. border.setProperty(FormatPrivate::P_Border_BottomColor, color);
  927. } else if (reader.name() == QLatin1String("diagonal")) {
  928. border.setDiagonalBorderStyle(style);
  929. if (!color.isInvalid())
  930. border.setProperty(FormatPrivate::P_Border_DiagonalColor, color);
  931. }
  932. }
  933. }
  934. if (reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("border"))
  935. break;
  936. }
  937. return true;
  938. }
  939. bool Styles::readCellStyleXfs(QXmlStreamReader &reader)
  940. {
  941. Q_UNUSED(reader);
  942. return true;
  943. }
  944. bool Styles::readSubBorder(QXmlStreamReader &reader, const QString &name, Format::BorderStyle &style, XlsxColor &color)
  945. {
  946. Q_ASSERT(reader.name() == name);
  947. static const QMap<QString, Format::BorderStyle> stylesStringsMap = {
  948. {QStringLiteral("none"), Format::BorderNone},
  949. {QStringLiteral("thin"), Format::BorderThin},
  950. {QStringLiteral("medium"), Format::BorderMedium},
  951. {QStringLiteral("dashed"), Format::BorderDashed},
  952. {QStringLiteral("dotted"), Format::BorderDotted},
  953. {QStringLiteral("thick"), Format::BorderThick},
  954. {QStringLiteral("double"), Format::BorderDouble},
  955. {QStringLiteral("hair"), Format::BorderHair},
  956. {QStringLiteral("mediumDashed"), Format::BorderMediumDashed},
  957. {QStringLiteral("dashDot"), Format::BorderDashDot},
  958. {QStringLiteral("mediumDashDot"), Format::BorderMediumDashDot},
  959. {QStringLiteral("dashDotDot"), Format::BorderDashDotDot},
  960. {QStringLiteral("mediumDashDotDot"), Format::BorderMediumDashDotDot},
  961. {QStringLiteral("slantDashDot"), Format::BorderSlantDashDot}
  962. };
  963. const auto& attributes = reader.attributes();
  964. if (attributes.hasAttribute(QLatin1String("style"))) {
  965. QString styleString = attributes.value(QLatin1String("style")).toString();
  966. const auto& it = stylesStringsMap.constFind(styleString);
  967. if (it != stylesStringsMap.constEnd()) {
  968. //get style
  969. style = it.value();
  970. while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == name)) {
  971. reader.readNextStartElement();
  972. if (reader.tokenType() == QXmlStreamReader::StartElement) {
  973. if (reader.name() == QLatin1String("color"))
  974. color.loadFromXml(reader);
  975. }
  976. }
  977. }
  978. }
  979. return true;
  980. }
  981. bool Styles::readCellXfs(QXmlStreamReader &reader)
  982. {
  983. Q_ASSERT(reader.name() == QLatin1String("cellXfs"));
  984. const auto& attributes = reader.attributes();
  985. const auto hasCount = attributes.hasAttribute(QLatin1String("count"));
  986. const auto count = hasCount ? attributes.value(QLatin1String("count")).toString().toInt() : -1;
  987. while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement
  988. && reader.name() == QLatin1String("cellXfs"))) {
  989. reader.readNextStartElement();
  990. if (reader.tokenType() == QXmlStreamReader::StartElement) {
  991. if (reader.name() == QLatin1String("xf")) {
  992. Format format;
  993. const auto& xfAttrs = reader.attributes();
  994. // qDebug()<<reader.name()<<reader.tokenString()<<" .........";
  995. // for (int i=0; i<xfAttrs.size(); ++i)
  996. // qDebug()<<"... "<<i<<" "<<xfAttrs[i].name()<<xfAttrs[i].value();
  997. if (xfAttrs.hasAttribute(QLatin1String("numFmtId"))) {
  998. const auto numFmtIndex = xfAttrs.value(QLatin1String("numFmtId")).toString().toInt();
  999. const auto apply = parseXsdBoolean(xfAttrs.value(QLatin1String("applyNumberFormat")).toString());
  1000. if(apply) {
  1001. const auto& it = m_customNumFmtIdMap.constFind(numFmtIndex);
  1002. if (it == m_customNumFmtIdMap.constEnd())
  1003. format.setNumberFormatIndex(numFmtIndex);
  1004. else
  1005. format.setNumberFormat(numFmtIndex, it.value()->formatString);
  1006. }
  1007. }
  1008. if (xfAttrs.hasAttribute(QLatin1String("fontId"))) {
  1009. const auto fontIndex = xfAttrs.value(QLatin1String("fontId")).toString().toInt();
  1010. if (fontIndex >= m_fontsList.size()) {
  1011. qDebug("Error read styles.xml, cellXfs fontId");
  1012. } else {
  1013. const auto apply = parseXsdBoolean(xfAttrs.value(QLatin1String("applyFont")).toString());
  1014. if(apply) {
  1015. Format fontFormat = m_fontsList[fontIndex];
  1016. for (int i=FormatPrivate::P_Font_STARTID; i<FormatPrivate::P_Font_ENDID; ++i) {
  1017. if (fontFormat.hasProperty(i))
  1018. format.setProperty(i, fontFormat.property(i));
  1019. }
  1020. }
  1021. }
  1022. }
  1023. if (xfAttrs.hasAttribute(QLatin1String("fillId"))) {
  1024. const auto id = xfAttrs.value(QLatin1String("fillId")).toString().toInt();
  1025. if (id >= m_fillsList.size()) {
  1026. qDebug("Error read styles.xml, cellXfs fillId");
  1027. } else {
  1028. // dev20 branch
  1029. // NOTE: MIcrosoft Excel does not have 'applyFill' tag.
  1030. //
  1031. // bool apply = parseXsdBoolean(xfAttrs.value(QLatin1String("applyFill")).toString());
  1032. // if (apply)
  1033. {
  1034. Format fillFormat = m_fillsList[id];
  1035. for (int i=FormatPrivate::P_Fill_STARTID; i<FormatPrivate::P_Fill_ENDID; ++i)
  1036. {
  1037. if (fillFormat.hasProperty(i))
  1038. format.setProperty(i, fillFormat.property(i));
  1039. }
  1040. }
  1041. }
  1042. }
  1043. if (xfAttrs.hasAttribute(QLatin1String("borderId"))) {
  1044. const auto id = xfAttrs.value(QLatin1String("borderId")).toString().toInt();
  1045. if (id >= m_bordersList.size()) {
  1046. qDebug("Error read styles.xml, cellXfs borderId");
  1047. } else {
  1048. const auto apply = parseXsdBoolean(xfAttrs.value(QLatin1String("applyBorder")).toString());
  1049. if(apply) {
  1050. Format borderFormat = m_bordersList[id];
  1051. for (int i=FormatPrivate::P_Border_STARTID; i<FormatPrivate::P_Border_ENDID; ++i) {
  1052. if (borderFormat.hasProperty(i))
  1053. format.setProperty(i, borderFormat.property(i));
  1054. }
  1055. }
  1056. }
  1057. }
  1058. const auto apply = parseXsdBoolean(xfAttrs.value(QLatin1String("applyAlignment")).toString());
  1059. if(apply) {
  1060. reader.readNextStartElement();
  1061. if (reader.name() == QLatin1String("alignment")) {
  1062. const auto& alignAttrs = reader.attributes();
  1063. if (alignAttrs.hasAttribute(QLatin1String("horizontal"))) {
  1064. static const QMap<QString, Format::HorizontalAlignment> alignStringMap = {
  1065. {QStringLiteral("left"), Format::AlignLeft},
  1066. {QStringLiteral("center"), Format::AlignHCenter},
  1067. {QStringLiteral("right"), Format::AlignRight},
  1068. {QStringLiteral("justify"), Format::AlignHJustify},
  1069. {QStringLiteral("centerContinuous"), Format::AlignHMerge},
  1070. {QStringLiteral("distributed"), Format::AlignHDistributed}
  1071. };
  1072. const auto& it = alignStringMap.constFind(alignAttrs.value(QLatin1String("horizontal")).toString());
  1073. if (it != alignStringMap.constEnd())
  1074. format.setHorizontalAlignment(it.value());
  1075. }
  1076. if (alignAttrs.hasAttribute(QLatin1String("vertical"))) {
  1077. static const QMap<QString, Format::VerticalAlignment> alignStringMap = {
  1078. {QStringLiteral("top"), Format::AlignTop},
  1079. {QStringLiteral("center"), Format::AlignVCenter},
  1080. {QStringLiteral("justify"), Format::AlignVJustify},
  1081. {QStringLiteral("distributed"), Format::AlignVDistributed}
  1082. };
  1083. const auto& it = alignStringMap.constFind(alignAttrs.value(QLatin1String("vertical")).toString());
  1084. if (it != alignStringMap.constEnd())
  1085. format.setVerticalAlignment(it.value());
  1086. }
  1087. if (alignAttrs.hasAttribute(QLatin1String("indent"))) {
  1088. const auto indent = alignAttrs.value(QLatin1String("indent")).toString().toInt();
  1089. format.setIndent(indent);
  1090. }
  1091. if (alignAttrs.hasAttribute(QLatin1String("textRotation"))) {
  1092. const auto rotation = alignAttrs.value(QLatin1String("textRotation")).toString().toInt();
  1093. format.setRotation(rotation);
  1094. }
  1095. if (alignAttrs.hasAttribute(QLatin1String("wrapText")))
  1096. format.setTextWrap(true);
  1097. if (alignAttrs.hasAttribute(QLatin1String("shrinkToFit")))
  1098. format.setShrinkToFit(true);
  1099. }
  1100. }
  1101. addXfFormat(format, true);
  1102. }
  1103. }
  1104. }
  1105. if (reader.hasError())
  1106. qWarning()<<reader.errorString();
  1107. if (hasCount && (count != m_xf_formatsList.size()))
  1108. qWarning("error read CellXfs");
  1109. return true;
  1110. }
  1111. bool Styles::readDxfs(QXmlStreamReader &reader)
  1112. {
  1113. Q_ASSERT(reader.name() == QLatin1String("dxfs"));
  1114. const auto& attributes = reader.attributes();
  1115. const auto hasCount = attributes.hasAttribute(QLatin1String("count"));
  1116. const auto count = hasCount ? attributes.value(QLatin1String("count")).toString().toInt() : -1;
  1117. while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement
  1118. && reader.name() == QLatin1String("dxfs"))) {
  1119. reader.readNextStartElement();
  1120. if (reader.tokenType() == QXmlStreamReader::StartElement) {
  1121. if (reader.name() == QLatin1String("dxf"))
  1122. readDxf(reader);
  1123. }
  1124. }
  1125. if (reader.hasError())
  1126. qWarning()<<reader.errorString();
  1127. if (hasCount && (count != m_dxf_formatsList.size()))
  1128. qWarning("error read dxfs");
  1129. return true;
  1130. }
  1131. bool Styles::readDxf(QXmlStreamReader &reader)
  1132. {
  1133. Q_ASSERT(reader.name() == QLatin1String("dxf"));
  1134. Format format;
  1135. while (!reader.atEnd() && !(reader.name() == QLatin1String("dxf") && reader.tokenType() == QXmlStreamReader::EndElement)) {
  1136. reader.readNextStartElement();
  1137. if (reader.tokenType() == QXmlStreamReader::StartElement) {
  1138. if (reader.name() == QLatin1String("numFmt")) {
  1139. const auto& attributes = reader.attributes();
  1140. const auto id = attributes.value(QLatin1String("numFmtId")).toString().toInt();
  1141. QString code = attributes.value(QLatin1String("formatCode")).toString();
  1142. format.setNumberFormat(id, code);
  1143. } else if (reader.name() == QLatin1String("font")) {
  1144. readFont(reader, format);
  1145. } else if (reader.name() == QLatin1String("fill")) {
  1146. readFill(reader, format);
  1147. } else if (reader.name() == QLatin1String("border")) {
  1148. readBorder(reader, format);
  1149. }
  1150. }
  1151. }
  1152. addDxfFormat(format, true);
  1153. return true;
  1154. }
  1155. bool Styles::readColors(QXmlStreamReader &reader)
  1156. {
  1157. Q_ASSERT(reader.name() == QLatin1String("colors"));
  1158. while (!reader.atEnd() && !(reader.name() == QLatin1String("colors") && reader.tokenType() == QXmlStreamReader::EndElement)) {
  1159. reader.readNextStartElement();
  1160. if (reader.tokenType() == QXmlStreamReader::StartElement) {
  1161. if (reader.name() == QLatin1String("indexedColors")) {
  1162. readIndexedColors(reader);
  1163. } else if (reader.name() == QLatin1String("mruColors")) {
  1164. }
  1165. }
  1166. }
  1167. return true;
  1168. }
  1169. bool Styles::readIndexedColors(QXmlStreamReader &reader)
  1170. {
  1171. Q_ASSERT(reader.name() == QLatin1String("indexedColors"));
  1172. m_indexedColors.clear();
  1173. while (!reader.atEnd() && !(reader.name() == QLatin1String("indexedColors") && reader.tokenType() == QXmlStreamReader::EndElement)) {
  1174. reader.readNextStartElement();
  1175. if (reader.tokenType() == QXmlStreamReader::StartElement) {
  1176. if (reader.name() == QLatin1String("rgbColor")) {
  1177. const auto& color = reader.attributes().value(QLatin1String("rgb")).toString();
  1178. m_indexedColors.append(XlsxColor::fromARGBString(color));
  1179. }
  1180. }
  1181. }
  1182. if (!m_indexedColors.isEmpty())
  1183. m_isIndexedColorsDefault = false;
  1184. return true;
  1185. }
  1186. bool Styles::loadFromXmlFile(QIODevice *device)
  1187. {
  1188. QXmlStreamReader reader(device);
  1189. while (!reader.atEnd()) {
  1190. QXmlStreamReader::TokenType token = reader.readNext();
  1191. if (token == QXmlStreamReader::StartElement) {
  1192. if (reader.name() == QLatin1String("numFmts")) {
  1193. readNumFmts(reader);
  1194. } else if (reader.name() == QLatin1String("fonts")) {
  1195. readFonts(reader);
  1196. } else if (reader.name() == QLatin1String("fills")) {
  1197. readFills(reader);
  1198. } else if (reader.name() == QLatin1String("borders")) {
  1199. readBorders(reader);
  1200. } else if (reader.name() == QLatin1String("cellStyleXfs")) {
  1201. readCellStyleXfs(reader);
  1202. } else if (reader.name() == QLatin1String("cellXfs")) {
  1203. readCellXfs(reader);
  1204. } else if (reader.name() == QLatin1String("cellStyles")) {
  1205. // cellStyles
  1206. } else if (reader.name() == QLatin1String("dxfs")) {
  1207. readDxfs(reader);
  1208. } else if (reader.name() == QLatin1String("colors")) {
  1209. readColors(reader);
  1210. }
  1211. }
  1212. if (reader.hasError()) {
  1213. qDebug()<<"Error when read style file: "<<reader.errorString();
  1214. }
  1215. }
  1216. return true;
  1217. }
  1218. #if QT_VERSION >= 0x050600
  1219. QColor Styles::getColorByIndex(int idx)
  1220. {
  1221. // #if QT_VERSION >= 0x050600
  1222. if (m_indexedColors.isEmpty()) {
  1223. m_indexedColors = {
  1224. QColor(QRgba64::fromArgb32(0x000000)), QColor(QRgba64::fromArgb32(0xFFFFFF)), QColor(QRgba64::fromArgb32(0xFF0000)), QColor(QRgba64::fromArgb32(0x00FF00)),
  1225. QColor(QRgba64::fromArgb32(0x0000FF)), QColor(QRgba64::fromArgb32(0xFFFF00)), QColor(QRgba64::fromArgb32(0xFF00FF)), QColor(QRgba64::fromArgb32(0x00FFFF)),
  1226. QColor(QRgba64::fromArgb32(0x000000)), QColor(QRgba64::fromArgb32(0xFFFFFF)), QColor(QRgba64::fromArgb32(0xFF0000)), QColor(QRgba64::fromArgb32(0x00FF00)),
  1227. QColor(QRgba64::fromArgb32(0x0000FF)), QColor(QRgba64::fromArgb32(0xFFFF00)), QColor(QRgba64::fromArgb32(0xFF00FF)), QColor(QRgba64::fromArgb32(0x00FFFF)),
  1228. QColor(QRgba64::fromArgb32(0x800000)), QColor(QRgba64::fromArgb32(0x008000)), QColor(QRgba64::fromArgb32(0x000080)), QColor(QRgba64::fromArgb32(0x808000)),
  1229. QColor(QRgba64::fromArgb32(0x800080)), QColor(QRgba64::fromArgb32(0x008080)), QColor(QRgba64::fromArgb32(0xC0C0C0)), QColor(QRgba64::fromArgb32(0x808080)),
  1230. QColor(QRgba64::fromArgb32(0x9999FF)), QColor(QRgba64::fromArgb32(0x993366)), QColor(QRgba64::fromArgb32(0xFFFFCC)), QColor(QRgba64::fromArgb32(0xCCFFFF)),
  1231. QColor(QRgba64::fromArgb32(0x660066)), QColor(QRgba64::fromArgb32(0xFF8080)), QColor(QRgba64::fromArgb32(0x0066CC)), QColor(QRgba64::fromArgb32(0xCCCCFF)),
  1232. QColor(QRgba64::fromArgb32(0x000080)), QColor(QRgba64::fromArgb32(0xFF00FF)), QColor(QRgba64::fromArgb32(0xFFFF00)), QColor(QRgba64::fromArgb32(0x00FFFF)),
  1233. QColor(QRgba64::fromArgb32(0x800080)), QColor(QRgba64::fromArgb32(0x800000)), QColor(QRgba64::fromArgb32(0x008080)), QColor(QRgba64::fromArgb32(0x0000FF)),
  1234. QColor(QRgba64::fromArgb32(0x00CCFF)), QColor(QRgba64::fromArgb32(0xCCFFFF)), QColor(QRgba64::fromArgb32(0xCCFFCC)), QColor(QRgba64::fromArgb32(0xFFFF99)),
  1235. QColor(QRgba64::fromArgb32(0x99CCFF)), QColor(QRgba64::fromArgb32(0xFF99CC)), QColor(QRgba64::fromArgb32(0xCC99FF)), QColor(QRgba64::fromArgb32(0xFFCC99)),
  1236. QColor(QRgba64::fromArgb32(0x3366FF)), QColor(QRgba64::fromArgb32(0x33CCCC)), QColor(QRgba64::fromArgb32(0x99CC00)), QColor(QRgba64::fromArgb32(0xFFCC00)),
  1237. QColor(QRgba64::fromArgb32(0xFF9900)), QColor(QRgba64::fromArgb32(0xFF6600)), QColor(QRgba64::fromArgb32(0x666699)), QColor(QRgba64::fromArgb32(0x969696)),
  1238. QColor(QRgba64::fromArgb32(0x003366)), QColor(QRgba64::fromArgb32(0x339966)), QColor(QRgba64::fromArgb32(0x003300)), QColor(QRgba64::fromArgb32(0x333300)),
  1239. QColor(QRgba64::fromArgb32(0x993300)), QColor(QRgba64::fromArgb32(0x993366)), QColor(QRgba64::fromArgb32(0x333399)), QColor(QRgba64::fromArgb32(0x333333)),
  1240. };
  1241. m_isIndexedColorsDefault = true;
  1242. }
  1243. if (idx < 0 || idx >= m_indexedColors.size())
  1244. return QColor();
  1245. return m_indexedColors[idx];
  1246. }
  1247. #endif
  1248. QT_END_NAMESPACE_XLSX