react-native-nitro-xlsx 0.2.5 → 0.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (449) hide show
  1. package/NitroXlsx.podspec +26 -27
  2. package/Package.swift +31 -10
  3. package/README.md +21 -9
  4. package/android/CMakeLists.txt +20 -27
  5. package/cpp/HybridNitroXlsx.cpp +25 -1
  6. package/cpp/HybridXlsxCellFormat.cpp +46 -146
  7. package/cpp/HybridXlsxCellFormat.hpp +9 -41
  8. package/cpp/HybridXlsxConditionalFormat.cpp +4 -1
  9. package/cpp/HybridXlsxConditionalFormats.cpp +5 -1
  10. package/cpp/HybridXlsxWorkbook.cpp +38 -8
  11. package/cpp/HybridXlsxWorkbook.hpp +10 -1
  12. package/cpp/HybridXlsxWorksheet.cpp +422 -141
  13. package/cpp/HybridXlsxWorksheet.hpp +4 -1
  14. package/cpp/XlsxCacheDir.cpp +25 -2
  15. package/cpp/XlsxCacheDir.hpp +3 -1
  16. package/cpp/XlsxCellStyle.hpp +360 -0
  17. package/cpp/XlsxJson.cpp +29 -8
  18. package/package.json +2 -2
  19. package/scripts/run-cpp-tests.sh +1 -1
  20. package/scripts/sync-openxlsx-headers.sh +34 -0
  21. package/src/__mocks__/react-native-nitro-modules.ts +523 -20
  22. package/src/__tests__/index.test.ts +124 -16
  23. package/src/index.ts +13 -13
  24. package/thirdparty/OpenXLSX/.clang-format +118 -0
  25. package/thirdparty/OpenXLSX/.clang-tidy +28 -0
  26. package/thirdparty/OpenXLSX/.gitignore +130 -0
  27. package/thirdparty/OpenXLSX/Benchmarks/2024-07-29-benchmarks_before_XMLNode_wrappers +46 -0
  28. package/thirdparty/OpenXLSX/Benchmarks/2024-07-29-benchmarks_with_XMLNode_wrappers_and_namespace_and_stripping +49 -0
  29. package/thirdparty/OpenXLSX/Benchmarks/2024-07-29-benchmarks_with_XMLNode_wrappers_and_namespace_char_support +49 -0
  30. package/thirdparty/OpenXLSX/Benchmarks/2024-07-29-benchmarks_with_XMLNode_wrappers_and_namespace_support +49 -0
  31. package/thirdparty/OpenXLSX/Benchmarks/2024-07-29-benchmarks_with_XMLNode_wrappers_and_namespaced_name_disabled +49 -0
  32. package/thirdparty/OpenXLSX/Benchmarks/2024-08-11-benchmarks_post-XLCellIterator-Rework +46 -0
  33. package/thirdparty/OpenXLSX/Benchmarks/2024-08-14-benchmarks_post-default-row-column-style-support +46 -0
  34. package/thirdparty/OpenXLSX/Benchmarks/2024-09-02-benchmarks +46 -0
  35. package/thirdparty/OpenXLSX/Benchmarks/2024-12-19-benchmarks +46 -0
  36. package/thirdparty/OpenXLSX/Benchmarks/2024-12-30-benchmarks-post-XLSharedStrings-by-ref +46 -0
  37. package/thirdparty/OpenXLSX/Benchmarks/2025-01-09-benchmarks-post-conditionalFormatsAndSheetProtection +46 -0
  38. package/thirdparty/OpenXLSX/Benchmarks/2025-01-10-benchmarks-post-XLCellValue-bugfix +46 -0
  39. package/thirdparty/OpenXLSX/Benchmarks/2025-01-31-benchmarks-post-XLComments-implementation +46 -0
  40. package/thirdparty/OpenXLSX/Benchmarks/2025-02-02-benchmarks-post-XLRowIterator-Rework +46 -0
  41. package/thirdparty/OpenXLSX/Benchmarks/2025-07-20-benchmarks-after-hiding-pugixml-internals +46 -0
  42. package/thirdparty/OpenXLSX/Benchmarks/2025-08-29-benchmarks-after-code-review-with-libzip +46 -0
  43. package/thirdparty/OpenXLSX/Benchmarks/Benchmark.cpp +249 -0
  44. package/thirdparty/OpenXLSX/Benchmarks/CMakeLists.txt +19 -0
  45. package/thirdparty/OpenXLSX/CMakeLists.txt +466 -0
  46. package/thirdparty/OpenXLSX/Documentation/CMakeLists.txt +31 -0
  47. package/thirdparty/OpenXLSX/Documentation/Doxyfile.in +2471 -0
  48. package/thirdparty/OpenXLSX/Documentation/DoxygenLayout.xml +194 -0
  49. package/thirdparty/OpenXLSX/Documentation/customdoxygen.css +1355 -0
  50. package/thirdparty/OpenXLSX/Examples/CMakeLists.txt +103 -0
  51. package/thirdparty/OpenXLSX/Examples/Demo1.cpp +279 -0
  52. package/thirdparty/OpenXLSX/Examples/Demo10.cpp +545 -0
  53. package/thirdparty/OpenXLSX/Examples/Demo1A.cpp +137 -0
  54. package/thirdparty/OpenXLSX/Examples/Demo2.cpp +65 -0
  55. package/thirdparty/OpenXLSX/Examples/Demo3.cpp +89 -0
  56. package/thirdparty/OpenXLSX/Examples/Demo4.cpp +86 -0
  57. package/thirdparty/OpenXLSX/Examples/Demo5.cpp +77 -0
  58. package/thirdparty/OpenXLSX/Examples/Demo6.cpp +103 -0
  59. package/thirdparty/OpenXLSX/Examples/Demo7.cpp +79 -0
  60. package/thirdparty/OpenXLSX/Examples/Demo8.cpp +117 -0
  61. package/thirdparty/OpenXLSX/Examples/Demo9.cpp +363 -0
  62. package/thirdparty/OpenXLSX/Examples/cmake/FindLIBZIP.cmake +61 -0
  63. package/thirdparty/OpenXLSX/Examples/external/CustomZip/CustomZip.hpp +256 -0
  64. package/thirdparty/OpenXLSX/LICENSE.md +29 -0
  65. package/thirdparty/OpenXLSX/Makefile.GNU +530 -0
  66. package/thirdparty/OpenXLSX/Notes/TBDs.txt +16 -0
  67. package/thirdparty/OpenXLSX/Notes/confirmed-TBCs.txt +8 -0
  68. package/thirdparty/OpenXLSX/Notes/styles-missing-support.xml +12 -0
  69. package/thirdparty/OpenXLSX/Notes/todo-list.txt +108 -0
  70. package/thirdparty/OpenXLSX/OpenXLSX/CMakeLists.txt +631 -0
  71. package/thirdparty/OpenXLSX/OpenXLSX/OpenXLSX.hpp +63 -0
  72. package/thirdparty/OpenXLSX/OpenXLSX/OpenXLSXConfig.cmake +11 -0
  73. package/thirdparty/OpenXLSX/OpenXLSX/cmake/bundle_static_library.cmake +198 -0
  74. package/thirdparty/OpenXLSX/OpenXLSX/cmake/patch_pkg_config.cmake +69 -0
  75. package/thirdparty/OpenXLSX/OpenXLSX/headers/IZipArchive.hpp +361 -0
  76. package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/IZipArchive.hpp +361 -0
  77. package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/OpenXLSX-Exports.hpp +12 -0
  78. package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLCell.hpp +367 -0
  79. package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLCellIterator.hpp +252 -0
  80. package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLCellRange.hpp +223 -0
  81. package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLCellReference.hpp +317 -0
  82. package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLCellValue.hpp +793 -0
  83. package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLColor.hpp +232 -0
  84. package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLColumn.hpp +159 -0
  85. package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLCommandQuery.hpp +228 -0
  86. package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLComments.hpp +270 -0
  87. package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLConstants.hpp +18 -0
  88. package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLContentTypes.hpp +264 -0
  89. package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLDateTime.hpp +175 -0
  90. package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLDocument.hpp +505 -0
  91. package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLDrawing.hpp +452 -0
  92. package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLException.hpp +161 -0
  93. package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLFormula.hpp +375 -0
  94. package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLIterator.hpp +40 -0
  95. package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLMergeCells.hpp +216 -0
  96. package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLProperties.hpp +348 -0
  97. package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLRelationships.hpp +348 -0
  98. package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLRow.hpp +721 -0
  99. package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLRowData.hpp +488 -0
  100. package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLSharedStrings.hpp +204 -0
  101. package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLSheet.hpp +1640 -0
  102. package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLStyles.hpp +2390 -0
  103. package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLTables.hpp +132 -0
  104. package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLWorkbook.hpp +404 -0
  105. package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLXmlData.hpp +283 -0
  106. package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLXmlFile.hpp +194 -0
  107. package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLXmlParser.hpp +282 -0
  108. package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLXmlParserForwardDeclarations.hpp +85 -0
  109. package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/XLZipArchive.hpp +232 -0
  110. package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/detail/LibZip.hpp +447 -0
  111. package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/detail/OpenXLSXFileSystemTools.hpp +207 -0
  112. package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX/detail/Zippy.hpp +1375 -0
  113. package/thirdparty/OpenXLSX/OpenXLSX/headers/OpenXLSX-Exports.hpp +12 -0
  114. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLCell.hpp +367 -0
  115. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLCellIterator.hpp +252 -0
  116. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLCellRange.hpp +223 -0
  117. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLCellReference.hpp +317 -0
  118. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLCellValue.hpp +793 -0
  119. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLColor.hpp +232 -0
  120. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLColumn.hpp +159 -0
  121. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLCommandQuery.hpp +228 -0
  122. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLComments.hpp +270 -0
  123. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLConstants.hpp +18 -0
  124. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLContentTypes.hpp +264 -0
  125. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLDateTime.hpp +175 -0
  126. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLDocument.hpp +505 -0
  127. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLDrawing.hpp +452 -0
  128. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLException.hpp +161 -0
  129. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLFormula.hpp +375 -0
  130. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLIterator.hpp +40 -0
  131. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLMergeCells.hpp +216 -0
  132. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLProperties.hpp +348 -0
  133. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLRelationships.hpp +348 -0
  134. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLRow.hpp +721 -0
  135. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLRowData.hpp +488 -0
  136. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLSharedStrings.hpp +204 -0
  137. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLSheet.hpp +1640 -0
  138. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLStyles.hpp +2390 -0
  139. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLTables.hpp +132 -0
  140. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLWorkbook.hpp +404 -0
  141. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLXmlData.hpp +283 -0
  142. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLXmlFile.hpp +194 -0
  143. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLXmlParser.hpp +282 -0
  144. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLXmlParserForwardDeclarations.hpp +85 -0
  145. package/thirdparty/OpenXLSX/OpenXLSX/headers/XLZipArchive.hpp +232 -0
  146. package/thirdparty/OpenXLSX/OpenXLSX/headers/detail/LibZip.hpp +447 -0
  147. package/thirdparty/OpenXLSX/OpenXLSX/headers/detail/OpenXLSXFileSystemTools.hpp +207 -0
  148. package/thirdparty/OpenXLSX/OpenXLSX/headers/detail/Zippy.hpp +1375 -0
  149. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLCell.cpp +340 -0
  150. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLCellIterator.cpp +427 -0
  151. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLCellRange.cpp +221 -0
  152. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLCellReference.cpp +408 -0
  153. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLCellValue.cpp +519 -0
  154. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLColor.cpp +202 -0
  155. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLColumn.cpp +141 -0
  156. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLComments.cpp +637 -0
  157. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLContentTypes.cpp +329 -0
  158. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLDateTime.cpp +269 -0
  159. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLDocument.cpp +1678 -0
  160. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLDrawing.cpp +784 -0
  161. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLFormula.cpp +201 -0
  162. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLMergeCells.cpp +357 -0
  163. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLProperties.cpp +810 -0
  164. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLRelationships.cpp +529 -0
  165. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLRow.cpp +918 -0
  166. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLRowData.cpp +508 -0
  167. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLSharedStrings.cpp +220 -0
  168. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLSheet.cpp +1970 -0
  169. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLStyles.cpp +3014 -0
  170. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLTables.cpp +125 -0
  171. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLWorkbook.cpp +784 -0
  172. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLXmlData.cpp +247 -0
  173. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLXmlFile.cpp +160 -0
  174. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLXmlParser.cpp +261 -0
  175. package/thirdparty/OpenXLSX/OpenXLSX/sources/XLZipArchive.cpp +266 -0
  176. package/thirdparty/OpenXLSX/OpenXLSX/sources/utilities/XLUtilities.hpp +478 -0
  177. package/thirdparty/OpenXLSX/README.md +1279 -0
  178. package/thirdparty/OpenXLSX/Scripts/cmake-cleanup.sh +102 -0
  179. package/thirdparty/OpenXLSX/Scripts/compile.sh +23 -0
  180. package/thirdparty/OpenXLSX/Scripts/demos-cleanup.sh +25 -0
  181. package/thirdparty/OpenXLSX/Scripts/demos-run-all.sh +60 -0
  182. package/thirdparty/OpenXLSX/Scripts/guarded-xml-format.sh +47 -0
  183. package/thirdparty/OpenXLSX/Scripts/make-gnu.sh +11 -0
  184. package/thirdparty/OpenXLSX/Scripts/uninstall-manifest.sh +48 -0
  185. package/thirdparty/OpenXLSX/Scripts/xml-format-all.sh +19 -0
  186. package/thirdparty/OpenXLSX/Scripts/xml-format.sh +38 -0
  187. package/thirdparty/OpenXLSX/Tests/CMakeLists.txt +37 -0
  188. package/thirdparty/OpenXLSX/Tests/catch/catch.hpp +17799 -0
  189. package/thirdparty/OpenXLSX/Tests/catch/catch_reporter_automake.hpp +68 -0
  190. package/thirdparty/OpenXLSX/Tests/catch/catch_reporter_sonarqube.hpp +182 -0
  191. package/thirdparty/OpenXLSX/Tests/catch/catch_reporter_tap.hpp +278 -0
  192. package/thirdparty/OpenXLSX/Tests/catch/catch_reporter_teamcity.hpp +212 -0
  193. package/thirdparty/OpenXLSX/Tests/main.cpp +55 -0
  194. package/thirdparty/OpenXLSX/Tests/testXLCell.cpp +176 -0
  195. package/thirdparty/OpenXLSX/Tests/testXLCellRange.cpp +180 -0
  196. package/thirdparty/OpenXLSX/Tests/testXLCellReference.cpp +160 -0
  197. package/thirdparty/OpenXLSX/Tests/testXLCellValue.cpp +366 -0
  198. package/thirdparty/OpenXLSX/Tests/testXLCellValueProxy.cpp +255 -0
  199. package/thirdparty/OpenXLSX/Tests/testXLColor.cpp +75 -0
  200. package/thirdparty/OpenXLSX/Tests/testXLDateTime.cpp +229 -0
  201. package/thirdparty/OpenXLSX/Tests/testXLDocument.cpp +197 -0
  202. package/thirdparty/OpenXLSX/Tests/testXLFormula.cpp +131 -0
  203. package/thirdparty/OpenXLSX/Tests/testXLRow.cpp +597 -0
  204. package/thirdparty/OpenXLSX/Tests/testXLSheet.cpp +77 -0
  205. package/thirdparty/OpenXLSX/Tests/ziptest-with-libs.cpp +88 -0
  206. package/thirdparty/OpenXLSX/Tests/ziptest.cpp +735 -0
  207. package/thirdparty/OpenXLSX/cmake/get-git-HEAD-ID.cmake +45 -0
  208. package/thirdparty/OpenXLSX/cmake/libopenxlsxCPackOptions.cmake.in +20 -0
  209. package/thirdparty/OpenXLSX/cmake/manage_dependency.cmake +813 -0
  210. package/thirdparty/OpenXLSX/cmake/recursive_library_type_test.cmake +52 -0
  211. package/thirdparty/OpenXLSX/gnu-make-crutch/OpenXLSX-Exports-shared.hpp +42 -0
  212. package/thirdparty/OpenXLSX/gnu-make-crutch/OpenXLSX-Exports-static.hpp +42 -0
  213. package/thirdparty/OpenXLSX/vcpkg.json +24 -0
  214. package/thirdparty/README.md +46 -0
  215. package/thirdparty/miniz/.clang-format +47 -0
  216. package/thirdparty/miniz/.travis.yml +2 -0
  217. package/thirdparty/miniz/CMakeLists.txt +333 -0
  218. package/thirdparty/miniz/CMakePresets.json +31 -0
  219. package/thirdparty/miniz/ChangeLog.md +272 -0
  220. package/thirdparty/miniz/Config.cmake.in +1 -0
  221. package/thirdparty/miniz/LICENSE +22 -0
  222. package/thirdparty/miniz/amalgamate.sh +57 -0
  223. package/thirdparty/miniz/examples/example1.c +105 -0
  224. package/thirdparty/miniz/examples/example2.c +164 -0
  225. package/thirdparty/miniz/examples/example3.c +269 -0
  226. package/thirdparty/miniz/examples/example4.c +102 -0
  227. package/thirdparty/miniz/examples/example5.c +327 -0
  228. package/thirdparty/miniz/examples/example6.c +189 -0
  229. package/thirdparty/miniz/meson.build +21 -0
  230. package/thirdparty/miniz/miniz.c +646 -0
  231. package/thirdparty/miniz/miniz.h +615 -0
  232. package/thirdparty/miniz/miniz.pc.in +13 -0
  233. package/thirdparty/miniz/miniz_common.h +89 -0
  234. package/thirdparty/miniz/miniz_export.h +20 -0
  235. package/thirdparty/miniz/miniz_tdef.c +1602 -0
  236. package/thirdparty/miniz/miniz_tdef.h +199 -0
  237. package/thirdparty/miniz/miniz_tinfl.c +778 -0
  238. package/thirdparty/miniz/miniz_tinfl.h +150 -0
  239. package/thirdparty/miniz/miniz_zip.c +4895 -0
  240. package/thirdparty/miniz/miniz_zip.h +454 -0
  241. package/thirdparty/miniz/readme.md +46 -0
  242. package/thirdparty/miniz/test.sh +36 -0
  243. package/thirdparty/miniz/tests/add_in_place_fuzzer.c +87 -0
  244. package/thirdparty/miniz/tests/catch_amalgamated.cpp +10795 -0
  245. package/thirdparty/miniz/tests/catch_amalgamated.hpp +13143 -0
  246. package/thirdparty/miniz/tests/checksum_fuzzer.c +26 -0
  247. package/thirdparty/miniz/tests/compress_fuzzer.c +91 -0
  248. package/thirdparty/miniz/tests/flush_fuzzer.c +88 -0
  249. package/thirdparty/miniz/tests/fuzz_main.c +55 -0
  250. package/thirdparty/miniz/tests/large_fuzzer.c +133 -0
  251. package/thirdparty/miniz/tests/main.cpp +185 -0
  252. package/thirdparty/miniz/tests/miniz_tdefl_fuzzer.cc +115 -0
  253. package/thirdparty/miniz/tests/miniz_tester.cpp +1881 -0
  254. package/thirdparty/miniz/tests/miniz_zip_validate_fuzzer.cc +71 -0
  255. package/thirdparty/miniz/tests/miniz_zip_writer_fuzzer.cc +96 -0
  256. package/thirdparty/miniz/tests/ossfuzz.sh +48 -0
  257. package/thirdparty/miniz/tests/small_fuzzer.c +126 -0
  258. package/thirdparty/miniz/tests/timer.cpp +152 -0
  259. package/thirdparty/miniz/tests/timer.h +40 -0
  260. package/thirdparty/miniz/tests/uncompress2_fuzzer.c +21 -0
  261. package/thirdparty/miniz/tests/uncompress_fuzzer.c +30 -0
  262. package/thirdparty/miniz/tests/zip.dict +9 -0
  263. package/thirdparty/miniz/tests/zip_fuzzer.c +63 -0
  264. package/thirdparty/pugixml/.codecov.yml +7 -0
  265. package/thirdparty/pugixml/.gitattributes +1 -0
  266. package/thirdparty/pugixml/CMakeLists.txt +330 -0
  267. package/thirdparty/pugixml/LICENSE.md +24 -0
  268. package/thirdparty/pugixml/Makefile +98 -0
  269. package/thirdparty/pugixml/README.md +81 -0
  270. package/thirdparty/pugixml/SECURITY.md +9 -0
  271. package/thirdparty/pugixml/appveyor.yml +50 -0
  272. package/thirdparty/pugixml/docs/config.adoc +7 -0
  273. package/thirdparty/pugixml/docs/images/dom_tree.png +0 -0
  274. package/thirdparty/pugixml/docs/images/vs2005_link1.png +0 -0
  275. package/thirdparty/pugixml/docs/images/vs2005_link2.png +0 -0
  276. package/thirdparty/pugixml/docs/images/vs2005_pch1.png +0 -0
  277. package/thirdparty/pugixml/docs/images/vs2005_pch2.png +0 -0
  278. package/thirdparty/pugixml/docs/images/vs2005_pch3.png +0 -0
  279. package/thirdparty/pugixml/docs/images/vs2005_pch4.png +0 -0
  280. package/thirdparty/pugixml/docs/images/vs2010_link1.png +0 -0
  281. package/thirdparty/pugixml/docs/images/vs2010_link2.png +0 -0
  282. package/thirdparty/pugixml/docs/manual.adoc +3326 -0
  283. package/thirdparty/pugixml/docs/manual.html +6395 -0
  284. package/thirdparty/pugixml/docs/quickstart.adoc +287 -0
  285. package/thirdparty/pugixml/docs/quickstart.html +1107 -0
  286. package/thirdparty/pugixml/docs/samples/character.xml +8 -0
  287. package/thirdparty/pugixml/docs/samples/custom_memory_management.cpp +27 -0
  288. package/thirdparty/pugixml/docs/samples/include.cpp +64 -0
  289. package/thirdparty/pugixml/docs/samples/load_error_handling.cpp +33 -0
  290. package/thirdparty/pugixml/docs/samples/load_file.cpp +16 -0
  291. package/thirdparty/pugixml/docs/samples/load_memory.cpp +66 -0
  292. package/thirdparty/pugixml/docs/samples/load_options.cpp +30 -0
  293. package/thirdparty/pugixml/docs/samples/load_stream.cpp +97 -0
  294. package/thirdparty/pugixml/docs/samples/modify_add.cpp +29 -0
  295. package/thirdparty/pugixml/docs/samples/modify_base.cpp +43 -0
  296. package/thirdparty/pugixml/docs/samples/modify_remove.cpp +27 -0
  297. package/thirdparty/pugixml/docs/samples/save_custom_writer.cpp +116 -0
  298. package/thirdparty/pugixml/docs/samples/save_declaration.cpp +27 -0
  299. package/thirdparty/pugixml/docs/samples/save_file.cpp +17 -0
  300. package/thirdparty/pugixml/docs/samples/save_options.cpp +48 -0
  301. package/thirdparty/pugixml/docs/samples/save_stream.cpp +18 -0
  302. package/thirdparty/pugixml/docs/samples/save_subtree.cpp +26 -0
  303. package/thirdparty/pugixml/docs/samples/text.cpp +35 -0
  304. package/thirdparty/pugixml/docs/samples/transitions.xml +7 -0
  305. package/thirdparty/pugixml/docs/samples/traverse_base.cpp +51 -0
  306. package/thirdparty/pugixml/docs/samples/traverse_iter.cpp +27 -0
  307. package/thirdparty/pugixml/docs/samples/traverse_predicate.cpp +48 -0
  308. package/thirdparty/pugixml/docs/samples/traverse_rangefor.cpp +32 -0
  309. package/thirdparty/pugixml/docs/samples/traverse_walker.cpp +35 -0
  310. package/thirdparty/pugixml/docs/samples/tree.xml +12 -0
  311. package/thirdparty/pugixml/docs/samples/weekly-shift_jis.xml +78 -0
  312. package/thirdparty/pugixml/docs/samples/weekly-utf-16.xml +0 -0
  313. package/thirdparty/pugixml/docs/samples/weekly-utf-8.xml +78 -0
  314. package/thirdparty/pugixml/docs/samples/xgconsole.xml +12 -0
  315. package/thirdparty/pugixml/docs/samples/xpath_error.cpp +43 -0
  316. package/thirdparty/pugixml/docs/samples/xpath_query.cpp +36 -0
  317. package/thirdparty/pugixml/docs/samples/xpath_select.cpp +28 -0
  318. package/thirdparty/pugixml/docs/samples/xpath_variables.cpp +38 -0
  319. package/thirdparty/pugixml/readme.txt +50 -0
  320. package/thirdparty/pugixml/scripts/archive.py +54 -0
  321. package/thirdparty/pugixml/scripts/cocoapods_push.sh +4 -0
  322. package/thirdparty/pugixml/scripts/natvis/pugixml.natvis +77 -0
  323. package/thirdparty/pugixml/scripts/natvis/pugixml_compact.natvis +506 -0
  324. package/thirdparty/pugixml/scripts/nuget/build/native/pugixml-propertiesui.xml +17 -0
  325. package/thirdparty/pugixml/scripts/nuget/build/native/pugixml.targets +28 -0
  326. package/thirdparty/pugixml/scripts/nuget/pugixml.nuspec +20 -0
  327. package/thirdparty/pugixml/scripts/nuget_build.ps1 +60 -0
  328. package/thirdparty/pugixml/scripts/premake4.lua +92 -0
  329. package/thirdparty/pugixml/scripts/pugixml-config.cmake.in +12 -0
  330. package/thirdparty/pugixml/scripts/pugixml.pc.in +11 -0
  331. package/thirdparty/pugixml/scripts/pugixml.podspec +14 -0
  332. package/thirdparty/pugixml/scripts/pugixml.xcodeproj/project.pbxproj +212 -0
  333. package/thirdparty/pugixml/scripts/pugixml_airplay.mkf +13 -0
  334. package/thirdparty/pugixml/scripts/pugixml_codeblocks.cbp +44 -0
  335. package/thirdparty/pugixml/scripts/pugixml_codelite.project +56 -0
  336. package/thirdparty/pugixml/scripts/pugixml_dll.rc +45 -0
  337. package/thirdparty/pugixml/scripts/pugixml_vs2005.vcproj +343 -0
  338. package/thirdparty/pugixml/scripts/pugixml_vs2005_static.vcproj +343 -0
  339. package/thirdparty/pugixml/scripts/pugixml_vs2008.vcproj +339 -0
  340. package/thirdparty/pugixml/scripts/pugixml_vs2008_static.vcproj +339 -0
  341. package/thirdparty/pugixml/scripts/pugixml_vs2010.vcxproj +191 -0
  342. package/thirdparty/pugixml/scripts/pugixml_vs2010_static.vcxproj +191 -0
  343. package/thirdparty/pugixml/scripts/pugixml_vs2013.vcxproj +199 -0
  344. package/thirdparty/pugixml/scripts/pugixml_vs2013_static.vcxproj +199 -0
  345. package/thirdparty/pugixml/scripts/pugixml_vs2015.vcxproj +172 -0
  346. package/thirdparty/pugixml/scripts/pugixml_vs2015_static.vcxproj +176 -0
  347. package/thirdparty/pugixml/scripts/pugixml_vs2017.vcxproj +172 -0
  348. package/thirdparty/pugixml/scripts/pugixml_vs2017_static.vcxproj +176 -0
  349. package/thirdparty/pugixml/scripts/pugixml_vs2019.vcxproj +176 -0
  350. package/thirdparty/pugixml/scripts/pugixml_vs2019_static.vcxproj +180 -0
  351. package/thirdparty/pugixml/scripts/pugixml_vs2022.vcxproj +176 -0
  352. package/thirdparty/pugixml/scripts/pugixml_vs2022_static.vcxproj +180 -0
  353. package/thirdparty/pugixml/scripts/pugixml_vs2026.vcxproj +176 -0
  354. package/thirdparty/pugixml/scripts/pugixml_vs2026_static.vcxproj +180 -0
  355. package/thirdparty/pugixml/scripts/sbom.cdx.json +47 -0
  356. package/thirdparty/pugixml/src/pugiconfig.hpp +81 -0
  357. package/thirdparty/pugixml/src/pugixml.cpp +13776 -0
  358. package/thirdparty/pugixml/src/pugixml.hpp +1604 -0
  359. package/thirdparty/pugixml/tests/allocator.cpp +175 -0
  360. package/thirdparty/pugixml/tests/allocator.hpp +10 -0
  361. package/thirdparty/pugixml/tests/autotest-appveyor.ps1 +93 -0
  362. package/thirdparty/pugixml/tests/cmake-appveyor.ps1 +57 -0
  363. package/thirdparty/pugixml/tests/data/empty.xml +0 -0
  364. package/thirdparty/pugixml/tests/data/large.xml +1 -0
  365. package/thirdparty/pugixml/tests/data/latintest_latin1.xml +1 -0
  366. package/thirdparty/pugixml/tests/data/latintest_utf8.xml +1 -0
  367. package/thirdparty/pugixml/tests/data/multiline.xml +3 -0
  368. package/thirdparty/pugixml/tests/data/small.xml +1 -0
  369. package/thirdparty/pugixml/tests/data/truncation.xml +19 -0
  370. package/thirdparty/pugixml/tests/data/utftest_utf16_be.xml +0 -0
  371. package/thirdparty/pugixml/tests/data/utftest_utf16_be_bom.xml +0 -0
  372. package/thirdparty/pugixml/tests/data/utftest_utf16_be_clean.xml +0 -0
  373. package/thirdparty/pugixml/tests/data/utftest_utf16_be_nodecl.xml +0 -0
  374. package/thirdparty/pugixml/tests/data/utftest_utf16_le.xml +0 -0
  375. package/thirdparty/pugixml/tests/data/utftest_utf16_le_bom.xml +0 -0
  376. package/thirdparty/pugixml/tests/data/utftest_utf16_le_clean.xml +0 -0
  377. package/thirdparty/pugixml/tests/data/utftest_utf16_le_nodecl.xml +0 -0
  378. package/thirdparty/pugixml/tests/data/utftest_utf32_be.xml +0 -0
  379. package/thirdparty/pugixml/tests/data/utftest_utf32_be_bom.xml +0 -0
  380. package/thirdparty/pugixml/tests/data/utftest_utf32_be_clean.xml +0 -0
  381. package/thirdparty/pugixml/tests/data/utftest_utf32_be_nodecl.xml +0 -0
  382. package/thirdparty/pugixml/tests/data/utftest_utf32_le.xml +0 -0
  383. package/thirdparty/pugixml/tests/data/utftest_utf32_le_bom.xml +0 -0
  384. package/thirdparty/pugixml/tests/data/utftest_utf32_le_clean.xml +0 -0
  385. package/thirdparty/pugixml/tests/data/utftest_utf32_le_nodecl.xml +0 -0
  386. package/thirdparty/pugixml/tests/data/utftest_utf8.xml +87 -0
  387. package/thirdparty/pugixml/tests/data/utftest_utf8_bom.xml +87 -0
  388. package/thirdparty/pugixml/tests/data/utftest_utf8_clean.xml +84 -0
  389. package/thirdparty/pugixml/tests/data/utftest_utf8_nodecl.xml +86 -0
  390. package/thirdparty/pugixml/tests/data//321/202/320/265/321/201/321/202.xml +1 -0
  391. package/thirdparty/pugixml/tests/data_fuzz_parse/basic.xml +1 -0
  392. package/thirdparty/pugixml/tests/data_fuzz_parse/doctype.xml +1 -0
  393. package/thirdparty/pugixml/tests/data_fuzz_parse/refs.xml +1 -0
  394. package/thirdparty/pugixml/tests/data_fuzz_parse/types.xml +1 -0
  395. package/thirdparty/pugixml/tests/data_fuzz_parse/utf16.xml +0 -0
  396. package/thirdparty/pugixml/tests/data_fuzz_parse/utf32.xml +0 -0
  397. package/thirdparty/pugixml/tests/data_fuzz_xpath/basic.xpath +1 -0
  398. package/thirdparty/pugixml/tests/data_fuzz_xpath/functions.xpath +1 -0
  399. package/thirdparty/pugixml/tests/data_fuzz_xpath/math.xpath +1 -0
  400. package/thirdparty/pugixml/tests/data_fuzz_xpath/path.xpath +1 -0
  401. package/thirdparty/pugixml/tests/data_fuzz_xpath/predicate.xpath +1 -0
  402. package/thirdparty/pugixml/tests/fuzz_parse.cpp +14 -0
  403. package/thirdparty/pugixml/tests/fuzz_parse.dict +72 -0
  404. package/thirdparty/pugixml/tests/fuzz_setup.sh +11 -0
  405. package/thirdparty/pugixml/tests/fuzz_xpath.cpp +46 -0
  406. package/thirdparty/pugixml/tests/fuzz_xpath.dict +72 -0
  407. package/thirdparty/pugixml/tests/helpers.hpp +114 -0
  408. package/thirdparty/pugixml/tests/main.cpp +218 -0
  409. package/thirdparty/pugixml/tests/test.cpp +220 -0
  410. package/thirdparty/pugixml/tests/test.hpp +175 -0
  411. package/thirdparty/pugixml/tests/test_compact.cpp +150 -0
  412. package/thirdparty/pugixml/tests/test_deprecated.cpp +25 -0
  413. package/thirdparty/pugixml/tests/test_document.cpp +1910 -0
  414. package/thirdparty/pugixml/tests/test_dom_modify.cpp +2122 -0
  415. package/thirdparty/pugixml/tests/test_dom_text.cpp +601 -0
  416. package/thirdparty/pugixml/tests/test_dom_traverse.cpp +1481 -0
  417. package/thirdparty/pugixml/tests/test_header_guard.cpp +3 -0
  418. package/thirdparty/pugixml/tests/test_header_iosfwd_1.cpp +3 -0
  419. package/thirdparty/pugixml/tests/test_header_iosfwd_2.cpp +3 -0
  420. package/thirdparty/pugixml/tests/test_header_iostream_1.cpp +3 -0
  421. package/thirdparty/pugixml/tests/test_header_iostream_2.cpp +3 -0
  422. package/thirdparty/pugixml/tests/test_header_only_1.cpp +21 -0
  423. package/thirdparty/pugixml/tests/test_header_only_2.cpp +21 -0
  424. package/thirdparty/pugixml/tests/test_header_string_1.cpp +3 -0
  425. package/thirdparty/pugixml/tests/test_header_string_2.cpp +3 -0
  426. package/thirdparty/pugixml/tests/test_header_string_iostream.cpp +5 -0
  427. package/thirdparty/pugixml/tests/test_memory.cpp +303 -0
  428. package/thirdparty/pugixml/tests/test_parse.cpp +1463 -0
  429. package/thirdparty/pugixml/tests/test_parse_doctype.cpp +366 -0
  430. package/thirdparty/pugixml/tests/test_unicode.cpp +152 -0
  431. package/thirdparty/pugixml/tests/test_version.cpp +5 -0
  432. package/thirdparty/pugixml/tests/test_write.cpp +757 -0
  433. package/thirdparty/pugixml/tests/test_xpath.cpp +833 -0
  434. package/thirdparty/pugixml/tests/test_xpath_api.cpp +646 -0
  435. package/thirdparty/pugixml/tests/test_xpath_functions.cpp +844 -0
  436. package/thirdparty/pugixml/tests/test_xpath_operators.cpp +566 -0
  437. package/thirdparty/pugixml/tests/test_xpath_parse.cpp +428 -0
  438. package/thirdparty/pugixml/tests/test_xpath_paths.cpp +787 -0
  439. package/thirdparty/pugixml/tests/test_xpath_paths_abbrev_w3c.cpp +219 -0
  440. package/thirdparty/pugixml/tests/test_xpath_paths_w3c.cpp +312 -0
  441. package/thirdparty/pugixml/tests/test_xpath_variables.cpp +683 -0
  442. package/thirdparty/pugixml/tests/test_xpath_xalan_1.cpp +411 -0
  443. package/thirdparty/pugixml/tests/test_xpath_xalan_2.cpp +417 -0
  444. package/thirdparty/pugixml/tests/test_xpath_xalan_3.cpp +321 -0
  445. package/thirdparty/pugixml/tests/test_xpath_xalan_4.cpp +300 -0
  446. package/thirdparty/pugixml/tests/test_xpath_xalan_5.cpp +295 -0
  447. package/thirdparty/pugixml/tests/writer_string.cpp +79 -0
  448. package/thirdparty/pugixml/tests/writer_string.hpp +27 -0
  449. package/scripts/prepare-openxlsx.js +0 -126
@@ -0,0 +1,3014 @@
1
+ /*
2
+
3
+ ____ ____ ___ ____ ____ ____ ___
4
+ 6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M'
5
+ 8P Y8 `MM. d' MM 6M' ` `MM. d'
6
+ 6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d'
7
+ MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d'
8
+ MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd
9
+ MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM.
10
+ MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM.
11
+ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM.
12
+ 8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM.
13
+ YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_
14
+ MM
15
+ MM
16
+ _MM_
17
+
18
+ Copyright (c) 2018, Kenneth Troldal Balslev
19
+
20
+ All rights reserved.
21
+
22
+ Redistribution and use in source and binary forms, with or without
23
+ modification, are permitted provided that the following conditions are met:
24
+ - Redistributions of source code must retain the above copyright
25
+ notice, this list of conditions and the following disclaimer.
26
+ - Redistributions in binary form must reproduce the above copyright
27
+ notice, this list of conditions and the following disclaimer in the
28
+ documentation and/or other materials provided with the distribution.
29
+ - Neither the name of the author nor the
30
+ names of any contributors may be used to endorse or promote products
31
+ derived from this software without specific prior written permission.
32
+
33
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
34
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
35
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36
+ DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
37
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
38
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
39
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
40
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
41
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
42
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43
+
44
+ */
45
+
46
+ // ===== External Includes ===== //
47
+ #include <cstdint> // uint32_t
48
+ #include <iostream> // std::cout, std::cerr
49
+ #include <memory> // std::make_unique
50
+ #include <stdexcept> // std::invalid_argument
51
+ #include <string> // std::stoi, std::literals::string_literals
52
+ #include <vector> // std::vector
53
+
54
+ // ===== OpenXLSX Includes ===== //
55
+ #include "XLColor.hpp"
56
+ #include "XLDocument.hpp"
57
+ #include "XLException.hpp"
58
+ #include "XLStyles.hpp"
59
+ #include "XLXmlParser.hpp" // pugixml wrapper
60
+ #include "utilities/XLUtilities.hpp" // OpenXLSX::ignore, ::XL(Keep|Remove)Attributes, appendAndGetNode, appendAnd(G|S)etAttribute, appendAnd(G|S)etNodeAttribute
61
+
62
+ using namespace OpenXLSX;
63
+
64
+ namespace // anonymous namespace for module local functions
65
+ {
66
+ enum XLStylesEntryType : uint8_t {
67
+ XLStylesNumberFormats = 0,
68
+ XLStylesFonts = 1,
69
+ XLStylesFills = 2,
70
+ XLStylesBorders = 3,
71
+ XLStylesCellStyleFormats = 4,
72
+ XLStylesCellFormats = 5,
73
+ XLStylesCellStyles = 6,
74
+ XLStylesColors = 7,
75
+ XLStylesDiffCellFormats = 8,
76
+ XLStylesTableStyles = 9,
77
+ XLStylesExtLst = 10,
78
+ XLStylesInvalid = 255
79
+ };
80
+
81
+ XLStylesEntryType XLStylesEntryTypeFromString(std::string name)
82
+ {
83
+ if (name == "numFmts") return XLStylesNumberFormats;
84
+ if (name == "fonts") return XLStylesFonts;
85
+ if (name == "fills") return XLStylesFills;
86
+ if (name == "borders") return XLStylesBorders;
87
+ if (name == "cellStyleXfs") return XLStylesCellStyleFormats;
88
+ if (name == "cellXfs") return XLStylesCellFormats;
89
+ if (name == "cellStyles") return XLStylesCellStyles;
90
+ if (name == "colors") return XLStylesColors;
91
+ if (name == "dxfs") return XLStylesDiffCellFormats;
92
+ if (name == "tableStyles") return XLStylesTableStyles;
93
+ if (name == "extLst") return XLStylesExtLst;
94
+ return XLStylesEntryType::XLStylesInvalid;
95
+ }
96
+
97
+ std::string XLStylesEntryTypeToString(XLStylesEntryType entryType)
98
+ {
99
+ switch (entryType) {
100
+ case XLStylesNumberFormats: return "numFmts";
101
+ case XLStylesFonts: return "fonts";
102
+ case XLStylesFills: return "fills";
103
+ case XLStylesBorders: return "borders";
104
+ case XLStylesCellStyleFormats: return "cellStyleXfs";
105
+ case XLStylesCellFormats: return "cellXfs";
106
+ case XLStylesCellStyles: return "cellStyles";
107
+ case XLStylesColors: return "colors";
108
+ case XLStylesDiffCellFormats: return "dxfs";
109
+ case XLStylesTableStyles: return "tableStyles";
110
+ case XLStylesExtLst: return "extLst";
111
+ case XLStylesInvalid: [[fallthrough]];
112
+ default: return "(invalid)";
113
+ }
114
+ }
115
+
116
+ XLUnderlineStyle XLUnderlineStyleFromString(std::string underline)
117
+ {
118
+ if (underline == ""
119
+ || underline == "none") return XLUnderlineNone;
120
+ if (underline == "single") return XLUnderlineSingle;
121
+ if (underline == "double") return XLUnderlineDouble;
122
+ std::cerr << __func__ << ": invalid underline style " << underline << std::endl;
123
+ return XLUnderlineInvalid;
124
+ }
125
+
126
+ std::string XLUnderlineStyleToString(XLUnderlineStyle underline)
127
+ {
128
+ switch (underline) {
129
+ case XLUnderlineNone : return "none";
130
+ case XLUnderlineSingle : return "single";
131
+ case XLUnderlineDouble : return "double";
132
+ case XLUnderlineInvalid: [[fallthrough]];
133
+ default: return "(invalid)";
134
+ }
135
+ }
136
+
137
+ XLFontSchemeStyle XLFontSchemeStyleFromString(std::string fontScheme)
138
+ {
139
+ if (fontScheme == ""
140
+ || fontScheme == "none") return XLFontSchemeNone;
141
+ if (fontScheme == "major") return XLFontSchemeMajor;
142
+ if (fontScheme == "minor") return XLFontSchemeMinor;
143
+ std::cerr << __func__ << ": invalid font scheme " << fontScheme << std::endl;
144
+ return XLFontSchemeInvalid;
145
+ }
146
+
147
+ std::string XLFontSchemeStyleToString(XLFontSchemeStyle fontScheme)
148
+ {
149
+ switch (fontScheme) {
150
+ case XLFontSchemeNone : return "none";
151
+ case XLFontSchemeMajor : return "major";
152
+ case XLFontSchemeMinor : return "minor";
153
+ case XLFontSchemeInvalid: [[fallthrough]];
154
+ default : return "(invalid)";
155
+ }
156
+ }
157
+
158
+ XLVerticalAlignRunStyle XLVerticalAlignRunStyleFromString(std::string vertAlign)
159
+ {
160
+ if (vertAlign == ""
161
+ || vertAlign == "baseline") return XLBaseline;
162
+ if (vertAlign == "subscript") return XLSubscript;
163
+ if (vertAlign == "superscript") return XLSuperscript;
164
+ std::cerr << __func__ << ": invalid font vertical align run style " << vertAlign << std::endl;
165
+ return XLVerticalAlignRunInvalid;
166
+ }
167
+
168
+ std::string XLVerticalAlignRunStyleToString(XLVerticalAlignRunStyle vertAlign)
169
+ {
170
+ switch (vertAlign) {
171
+ case XLBaseline : return "baseline";
172
+ case XLSubscript : return "subscript";
173
+ case XLSuperscript : return "superscript";
174
+ case XLVerticalAlignRunInvalid: [[fallthrough]];
175
+ default : return "(invalid)";
176
+ }
177
+ }
178
+
179
+ XLFillType XLFillTypeFromString(std::string fillType)
180
+ {
181
+ if (fillType == "gradientFill") return XLGradientFill;
182
+ if (fillType == "patternFill" ) return XLPatternFill;
183
+ if (fillType != "") // suppress error message for empty fillType (= no node exists yet)
184
+ std::cerr << __func__ << ": invalid fillType \"" << fillType << "\"" << std::endl;
185
+ return XLFillTypeInvalid;
186
+ }
187
+
188
+ std::string XLFillTypeToString(XLFillType fillType)
189
+ {
190
+ switch (fillType) {
191
+ case XLGradientFill : return "gradientFill";
192
+ case XLPatternFill : return "patternFill";
193
+ case XLFillTypeInvalid: [[fallthrough]];
194
+ default: return "(invalid)";
195
+ }
196
+ }
197
+
198
+ XLGradientType XLGradientTypeFromString(std::string gradientType)
199
+ {
200
+ if (gradientType == "linear") return XLGradientLinear;
201
+ if (gradientType == "path") return XLGradientPath;
202
+ std::cerr << __func__ << ": invalid gradient type " << gradientType << std::endl;
203
+ return XLGradientTypeInvalid;
204
+ }
205
+ std::string XLGradientTypeToString(XLGradientType gradientType)
206
+ {
207
+ switch (gradientType) {
208
+ case XLGradientLinear : return "linear";
209
+ case XLGradientPath : return "path";
210
+ case XLGradientTypeInvalid: [[fallthrough]];
211
+ default: return "(invalid)";
212
+ }
213
+ }
214
+
215
+ XLPatternType XLPatternTypeFromString(std::string patternType)
216
+ {
217
+ if (patternType == ""
218
+ || patternType == "none") return XLPatternNone;
219
+ if (patternType == "solid") return XLPatternSolid;
220
+ if (patternType == "mediumGray") return XLPatternMediumGray;
221
+ if (patternType == "darkGray") return XLPatternDarkGray;
222
+ if (patternType == "lightGray") return XLPatternLightGray;
223
+ if (patternType == "darkHorizontal") return XLPatternDarkHorizontal;
224
+ if (patternType == "darkVertical") return XLPatternDarkVertical;
225
+ if (patternType == "darkDown") return XLPatternDarkDown;
226
+ if (patternType == "darkUp") return XLPatternDarkUp;
227
+ if (patternType == "darkGrid") return XLPatternDarkGrid;
228
+ if (patternType == "darkTrellis") return XLPatternDarkTrellis;
229
+ if (patternType == "lightHorizontal") return XLPatternLightHorizontal;
230
+ if (patternType == "lightVertical") return XLPatternLightVertical;
231
+ if (patternType == "lightDown") return XLPatternLightDown;
232
+ if (patternType == "lightUp") return XLPatternLightUp;
233
+ if (patternType == "lightGrid") return XLPatternLightGrid;
234
+ if (patternType == "lightTrellis") return XLPatternLightTrellis;
235
+ if (patternType == "gray125") return XLPatternGray125;
236
+ if (patternType == "gray0625") return XLPatternGray0625;
237
+ std::cerr << __func__ << ": invalid patternType " << patternType << std::endl;
238
+ return XLPatternTypeInvalid;
239
+ }
240
+
241
+ std::string XLPatternTypeToString(XLPatternType patternType)
242
+ {
243
+ switch (patternType) {
244
+ case XLPatternNone : return "none";
245
+ case XLPatternSolid : return "solid";
246
+ case XLPatternMediumGray : return "mediumGray";
247
+ case XLPatternDarkGray : return "darkGray";
248
+ case XLPatternLightGray : return "lightGray";
249
+ case XLPatternDarkHorizontal : return "darkHorizontal";
250
+ case XLPatternDarkVertical : return "darkVertical";
251
+ case XLPatternDarkDown : return "darkDown";
252
+ case XLPatternDarkUp : return "darkUp";
253
+ case XLPatternDarkGrid : return "darkGrid";
254
+ case XLPatternDarkTrellis : return "darkTrellis";
255
+ case XLPatternLightHorizontal: return "lightHorizontal";
256
+ case XLPatternLightVertical : return "lightVertical";
257
+ case XLPatternLightDown : return "lightDown";
258
+ case XLPatternLightUp : return "lightUp";
259
+ case XLPatternLightGrid : return "lightGrid";
260
+ case XLPatternLightTrellis : return "lightTrellis";
261
+ case XLPatternGray125 : return "gray125";
262
+ case XLPatternGray0625 : return "gray0625";
263
+ case XLPatternTypeInvalid : [[fallthrough]];
264
+ default: return "(invalid)";
265
+ }
266
+ }
267
+
268
+ #ifdef __GNUC__ // conditionally enable GCC specific pragmas to suppress unused function warning
269
+ # pragma GCC diagnostic push
270
+ # pragma GCC diagnostic ignored "-Wunused-function"
271
+ #endif // __GNUC__
272
+ XLLineType XLLineTypeFromString(std::string lineType)
273
+ {
274
+ if (lineType == "left") return XLLineLeft;
275
+ if (lineType == "right") return XLLineRight;
276
+ if (lineType == "top") return XLLineTop;
277
+ if (lineType == "bottom") return XLLineBottom;
278
+ if (lineType == "diagonal") return XLLineDiagonal;
279
+ if (lineType == "vertical") return XLLineVertical;
280
+ if (lineType == "horizontal") return XLLineHorizontal;
281
+ std::cerr << __func__ << ": invalid line type" << lineType << std::endl;
282
+ return XLLineInvalid;
283
+ }
284
+ #ifdef __GNUC__ // conditionally enable GCC specific pragmas to suppress unused function warning
285
+ # pragma GCC diagnostic pop
286
+ #endif // __GNUC__
287
+
288
+ std::string XLLineTypeToString(XLLineType lineType)
289
+ {
290
+ switch (lineType) {
291
+ case XLLineLeft: return "left";
292
+ case XLLineRight: return "right";
293
+ case XLLineTop: return "top";
294
+ case XLLineBottom: return "bottom";
295
+ case XLLineDiagonal: return "diagonal";
296
+ case XLLineVertical: return "vertical";
297
+ case XLLineHorizontal: return "horizontal";
298
+ case XLLineInvalid: [[fallthrough]];
299
+ default: return "(invalid)";
300
+ }
301
+ }
302
+
303
+ XLLineStyle XLLineStyleFromString(std::string style)
304
+ {
305
+ if (style == "") return XLLineStyleNone;
306
+ if (style == "thin") return XLLineStyleThin;
307
+ if (style == "medium") return XLLineStyleMedium;
308
+ if (style == "dashed") return XLLineStyleDashed;
309
+ if (style == "dotted") return XLLineStyleDotted;
310
+ if (style == "thick") return XLLineStyleThick;
311
+ if (style == "double") return XLLineStyleDouble;
312
+ if (style == "hair") return XLLineStyleHair;
313
+ if (style == "mediumDashed") return XLLineStyleMediumDashed;
314
+ if (style == "dashDot") return XLLineStyleDashDot;
315
+ if (style == "mediumDashDot") return XLLineStyleMediumDashDot;
316
+ if (style == "dashDotDot") return XLLineStyleDashDotDot;
317
+ if (style == "mediumDashDotDot") return XLLineStyleMediumDashDotDot;
318
+ if (style == "slantDashDot") return XLLineStyleSlantDashDot;
319
+ std::cerr << __func__ << ": invalid line style " << style << std::endl;
320
+ return XLLineStyleInvalid;
321
+ }
322
+
323
+ std::string XLLineStyleToString(XLLineStyle style)
324
+ {
325
+ switch (style) {
326
+ case XLLineStyleNone : return "";
327
+ case XLLineStyleThin : return "thin";
328
+ case XLLineStyleMedium : return "medium";
329
+ case XLLineStyleDashed : return "dashed";
330
+ case XLLineStyleDotted : return "dotted";
331
+ case XLLineStyleThick : return "thick";
332
+ case XLLineStyleDouble : return "double";
333
+ case XLLineStyleHair : return "hair";
334
+ case XLLineStyleMediumDashed : return "mediumDashed";
335
+ case XLLineStyleDashDot : return "dashDot";
336
+ case XLLineStyleMediumDashDot : return "mediumDashDot";
337
+ case XLLineStyleDashDotDot : return "dashDotDot";
338
+ case XLLineStyleMediumDashDotDot: return "mediumDashDotDot";
339
+ case XLLineStyleSlantDashDot : return "slantDashDot";
340
+ case XLLineStyleInvalid : [[fallthrough]];
341
+ default : return "(invalid)";
342
+ }
343
+ }
344
+
345
+ XLAlignmentStyle XLAlignmentStyleFromString(std::string alignment)
346
+ {
347
+ if (alignment == ""
348
+ || alignment == "general") return XLAlignGeneral;
349
+ if (alignment == "left") return XLAlignLeft;
350
+ if (alignment == "right") return XLAlignRight;
351
+ if (alignment == "center") return XLAlignCenter;
352
+ if (alignment == "top") return XLAlignTop;
353
+ if (alignment == "bottom") return XLAlignBottom;
354
+ if (alignment == "fill") return XLAlignFill;
355
+ if (alignment == "justify") return XLAlignJustify;
356
+ if (alignment == "centerContinuous") return XLAlignCenterContinuous;
357
+ if (alignment == "distributed") return XLAlignDistributed;
358
+ std::cerr << __func__ << ": invalid alignment style " << alignment << std::endl;
359
+ return XLAlignInvalid;
360
+ }
361
+
362
+ std::string XLAlignmentStyleToString(XLAlignmentStyle alignment)
363
+ {
364
+ switch (alignment) {
365
+ case XLAlignGeneral : return "";
366
+ case XLAlignLeft : return "left";
367
+ case XLAlignRight : return "right";
368
+ case XLAlignCenter : return "center";
369
+ case XLAlignTop : return "top";
370
+ case XLAlignBottom : return "bottom";
371
+ case XLAlignFill : return "fill";
372
+ case XLAlignJustify : return "justify";
373
+ case XLAlignCenterContinuous : return "centerContinuous";
374
+ case XLAlignDistributed : return "distributed";
375
+ case XLAlignInvalid: [[fallthrough]];
376
+ default: return "(unknown)";
377
+ }
378
+ }
379
+
380
+ std::string XLReadingOrderToString(uint32_t readingOrder)
381
+ {
382
+ switch (readingOrder) {
383
+ case XLReadingOrderContextual : return "contextual";
384
+ case XLReadingOrderLeftToRight: return "left-to-right";
385
+ case XLReadingOrderRightToLeft: return "right-to-left";
386
+ default: return "(unknown)";
387
+ }
388
+ }
389
+
390
+ void copyXMLNode(XMLNode & destination, XMLNode & source)
391
+ {
392
+ if (not source.empty()) {
393
+ // ===== Copy all XML child nodes
394
+ for (XMLNode child = source.first_child(); not child.empty(); child = child.next_sibling())
395
+ destination.append_copy(child);
396
+ // ===== Copy all XML attributes
397
+ for (XMLAttribute attr = source.first_attribute(); not attr.empty(); attr = attr.next_attribute())
398
+ destination.append_copy(attr);
399
+ }
400
+ }
401
+
402
+ /**
403
+ * @brief remove trailing unwanted_chars from input
404
+ * @param input the string to trim
405
+ * @param unwanted_chars all characters to consider trimmable
406
+ * @return input minus any trailing characters that are part of unwanted_chars
407
+ */
408
+ std::string rtrim(const std::string & input, const std::string & unwanted_chars)
409
+ {
410
+ size_t end = input.find_last_not_of( unwanted_chars );
411
+ if( end == std::string::npos )
412
+ return "";
413
+ else
414
+ return input.substr( 0, end + 1 );
415
+ }
416
+
417
+ void wrapNode(XMLNode parentNode, XMLNode & node, std::string const & prefix)
418
+ {
419
+ if (not node.empty() && prefix.length() > 0) {
420
+ XMLNode prev = node.previous_sibling();
421
+ // 2026-06-10 beauty fix: ensure that inserted prefix is not combined with other blankspaces
422
+ if (prev.type() == pugi::node_pcdata) { // if node is already preceeded by a text node
423
+ std::string trimmedVal = rtrim(prev.value(), " \t"); // trim from end of preceeding text node all spaces & tabs
424
+ prev.set_value((trimmedVal + prefix).c_str()); // and set the value to any remaining characters + prefix
425
+ }
426
+ else // else: node is not (yet) preceeded by a text node
427
+ parentNode.insert_child_before(pugi::node_pcdata, node).set_value(prefix.c_str()); // insert prefix before node opening tag
428
+
429
+ node.append_child(pugi::node_pcdata).set_value(prefix.c_str()); // always: insert prefix before node closing tag (within node)
430
+ }
431
+ }
432
+
433
+ /**
434
+ * @brief Format val as a string with decimalPlaces
435
+ * @param val The value to format
436
+ * @param decimalPlaces The amount of digits following the decimal separator that shall be included in the formatted string
437
+ * @return The value formatted as a string with the desired amount of decimal places
438
+ */
439
+ std::string formatDoubleAsString(double val, int decimalPlaces = 2)
440
+ {
441
+ std::string result = std::to_string(val);
442
+ size_t decimalPos = result.find_first_of('.');
443
+ if (decimalPos >= result.length())
444
+ throw XLException("formatDoubleAsString: return value of std::to_string(double val) contains no decimal separator - this should never happen");
445
+
446
+ // ===== Return the string representation of val with the decimal separator and decimalPlaces digits following
447
+ return result.substr(0, decimalPos + 1 + decimalPlaces);
448
+ }
449
+
450
+ /**
451
+ * @brief Check that a double value is within range, and format it as a string with decimalPlaces
452
+ * @param val The value to check & format
453
+ * @param min The lower bound of the valid value range
454
+ * @param max The upper bound of the valid value range 0 must be larger than min
455
+ * @param absTolerance The tolerance for rounding errors when checking the valid range - must be positive
456
+ * @param decimalPlaces The amount of digits following the decimal separator that shall be included in the formatted string
457
+ * @return The value formatted as a string with the desired amount of decimal places
458
+ * @return An empty string ""s if the value falls outside the valid range
459
+ * @note values that fall outside the range but within the tolerance will be rounded to the nearest range bound
460
+ */
461
+ std::string checkAndFormatDoubleAsString(double val, double min, double max, double absTolerance, int decimalPlaces = 2)
462
+ {
463
+ if (max <= min || absTolerance < 0.0) throw XLException("checkAndFormatDoubleAsString: max must be greater than min and absTolerance must be >= 0.0");
464
+ if (val < min - absTolerance || val > max + absTolerance) return ""; // range check
465
+ if (val < min) val = min; else if (val > max) val = max; // fix rounding errors within tolerance
466
+ return formatDoubleAsString(val, decimalPlaces);
467
+ }
468
+ } // anonymous namespace
469
+
470
+
471
+
472
+ /**
473
+ * @details Default constructor. Initializes an empty XLNumberFormat object
474
+ */
475
+ XLNumberFormat::XLNumberFormat() : m_numberFormatNode(std::make_unique<XMLNode>()) {}
476
+
477
+ /**
478
+ * @details Constructor. Initializes the member variables for the new XLNumberFormat object.
479
+ */
480
+ XLNumberFormat::XLNumberFormat(const XMLNode& node) : m_numberFormatNode(std::make_unique<XMLNode>(node)) {}
481
+
482
+ /**
483
+ * @details Copy constructor
484
+ */
485
+ XLNumberFormat::XLNumberFormat(const XLNumberFormat& other)
486
+ : m_numberFormatNode(std::make_unique<XMLNode>(*other.m_numberFormatNode))
487
+ {}
488
+
489
+ /**
490
+ * @details Move constructor
491
+ */
492
+ XLNumberFormat::XLNumberFormat(XLNumberFormat&& other) noexcept = default;
493
+
494
+ /**
495
+ * @details
496
+ */
497
+ XLNumberFormat::~XLNumberFormat() = default;
498
+
499
+ /**
500
+ * @details Copy assignment operator
501
+ */
502
+ XLNumberFormat& XLNumberFormat::operator=(const XLNumberFormat& other)
503
+ {
504
+ if (&other != this) *m_numberFormatNode = *other.m_numberFormatNode;
505
+ return *this;
506
+ }
507
+
508
+ /**
509
+ * @details Move assignment operator
510
+ */
511
+ XLNumberFormat& XLNumberFormat::operator=(XLNumberFormat&& other) noexcept = default;
512
+
513
+ /**
514
+ * @details Returns the numFmtId value
515
+ */
516
+ uint32_t XLNumberFormat::numberFormatId() const { return m_numberFormatNode->attribute("numFmtId").as_uint(XLInvalidUInt32); }
517
+
518
+ /**
519
+ * @details Returns the formatCode value
520
+ */
521
+ std::string XLNumberFormat::formatCode() const { return m_numberFormatNode->attribute("formatCode").value(); }
522
+
523
+ /**
524
+ * @details Setter functions
525
+ */
526
+ bool XLNumberFormat::setNumberFormatId(uint32_t newNumberFormatId)
527
+ { return appendAndSetAttribute(*m_numberFormatNode, "numFmtId", std::to_string(newNumberFormatId)).empty() == false; }
528
+ bool XLNumberFormat::setFormatCode (std::string newFormatCode)
529
+ { return appendAndSetAttribute(*m_numberFormatNode, "formatCode", newFormatCode.c_str() ).empty() == false; }
530
+
531
+
532
+ /**
533
+ * @details assemble a string summary about the number format
534
+ */
535
+ std::string XLNumberFormat::summary() const
536
+ {
537
+ using namespace std::literals::string_literals;
538
+ return "numFmtId="s + std::to_string(numberFormatId())
539
+ + ", formatCode="s + formatCode();
540
+ }
541
+
542
+
543
+ // ===== XLNumberFormats, parent of XLNumberFormat
544
+
545
+ /**
546
+ * @details Constructor. Initializes an empty XLNumberFormats object
547
+ */
548
+ XLNumberFormats::XLNumberFormats() : m_numberFormatsNode(std::make_unique<XMLNode>()) {}
549
+
550
+ /**
551
+ * @details Constructor. Initializes the member variables for the new XLNumberFormats object.
552
+ */
553
+ XLNumberFormats::XLNumberFormats(const XMLNode& numberFormats)
554
+ : m_numberFormatsNode(std::make_unique<XMLNode>(numberFormats))
555
+ {
556
+ // initialize XLNumberFormat entries and m_numberFormats here
557
+ XMLNode node = numberFormats.first_child_of_type(pugi::node_element);
558
+ while (not node.empty()) {
559
+ std::string nodeName = node.name();
560
+ if (nodeName == "numFmt")
561
+ m_numberFormats.push_back(XLNumberFormat(node));
562
+ else
563
+ std::cerr << "WARNING: XLNumberFormats constructor: unknown subnode " << nodeName << std::endl;
564
+ node = node.next_sibling_of_type(pugi::node_element);
565
+ }
566
+ }
567
+
568
+ /**
569
+ * @details Copy constructor
570
+ */
571
+ XLNumberFormats::XLNumberFormats(const XLNumberFormats& other)
572
+ : m_numberFormatsNode(std::make_unique<XMLNode>(*other.m_numberFormatsNode)),
573
+ m_numberFormats(other.m_numberFormats)
574
+ {}
575
+
576
+ /**
577
+ * @details Move constructor
578
+ */
579
+ XLNumberFormats::XLNumberFormats(XLNumberFormats&& other)
580
+ : m_numberFormatsNode(std::move(other.m_numberFormatsNode)),
581
+ m_numberFormats(std::move(other.m_numberFormats))
582
+ {}
583
+
584
+ /**
585
+ * @details
586
+ */
587
+ XLNumberFormats::~XLNumberFormats()
588
+ {
589
+ m_numberFormats.clear(); // delete vector with all children
590
+ }
591
+
592
+ /**
593
+ * @details Copy assignment operator
594
+ */
595
+ XLNumberFormats& XLNumberFormats::operator=(const XLNumberFormats& other)
596
+ {
597
+ if (&other != this) {
598
+ *m_numberFormatsNode = *other.m_numberFormatsNode;
599
+ m_numberFormats.clear();
600
+ m_numberFormats = other.m_numberFormats;
601
+ }
602
+ return *this;
603
+ }
604
+
605
+ /**
606
+ * @details Move assignment operator.
607
+ */
608
+ XLNumberFormats& XLNumberFormats::operator=(XLNumberFormats&& other) noexcept = default;
609
+
610
+ /**
611
+ * @details Returns the amount of numberFormats held by the class
612
+ */
613
+ size_t XLNumberFormats::count() const { return m_numberFormats.size(); }
614
+
615
+ /**
616
+ * @details fetch XLNumberFormat from m_numberFormats by index
617
+ */
618
+ XLNumberFormat XLNumberFormats::numberFormatByIndex(XLStyleIndex index) const
619
+ {
620
+ if (index >= m_numberFormats.size()) {
621
+ using namespace std::literals::string_literals;
622
+ throw XLException("XLNumberFormats::"s + __func__ + ": index "s + std::to_string(index) + " is out of range"s);
623
+ }
624
+ return m_numberFormats.at(index);
625
+ }
626
+
627
+ /**
628
+ * @details fetch XLNumberFormat from m_numberFormats by its numberFormatId
629
+ */
630
+ XLNumberFormat XLNumberFormats::numberFormatById(uint32_t numberFormatId) const
631
+ {
632
+ for (XLNumberFormat fmt : m_numberFormats)
633
+ if (fmt.numberFormatId() == numberFormatId)
634
+ return fmt;
635
+ using namespace std::literals::string_literals;
636
+ throw XLException("XLNumberFormats::"s + __func__ + ": numberFormatId "s + std::to_string(numberFormatId) + " not found"s);
637
+ }
638
+
639
+ /**
640
+ * @details fetch a numFmtId from m_numberFormats by index
641
+ */
642
+ uint32_t XLNumberFormats::numberFormatIdFromIndex(XLStyleIndex index) const
643
+ {
644
+ if (index >= m_numberFormats.size()) {
645
+ using namespace std::literals::string_literals;
646
+ throw XLException("XLNumberFormats::"s + __func__ + ": index "s + std::to_string(index) + " is out of range"s);
647
+ }
648
+ return m_numberFormats[ index ].numberFormatId();
649
+ }
650
+
651
+ /**
652
+ * @details append a new XLNumberFormat to m_numberFormats and m_numberFormatsNode, based on copyFrom
653
+ */
654
+ XLStyleIndex XLNumberFormats::create(XLNumberFormat copyFrom, std::string styleEntriesPrefix)
655
+ {
656
+ XLStyleIndex index = count(); // index for the number format to be created
657
+ XMLNode newNode{}; // scope declaration
658
+
659
+ // ===== Append new node prior to final whitespaces, if any
660
+ XMLNode lastStyle = m_numberFormatsNode->last_child_of_type(pugi::node_element);
661
+ if (lastStyle.empty()) newNode = m_numberFormatsNode->prepend_child("numFmt");
662
+ else newNode = m_numberFormatsNode->insert_child_after("numFmt", lastStyle);
663
+ if (newNode.empty()) {
664
+ using namespace std::literals::string_literals;
665
+ throw XLException("XLNumberFormats::"s + __func__ + ": failed to append a new numFmt node"s);
666
+ }
667
+ if (styleEntriesPrefix.length() > 0) // if a whitespace prefix is configured
668
+ m_numberFormatsNode->insert_child_before(pugi::node_pcdata, newNode).set_value(styleEntriesPrefix.c_str()); // prefix the new node with styleEntriesPrefix
669
+
670
+ XLNumberFormat newNumberFormat(newNode);
671
+ if (copyFrom.m_numberFormatNode->empty()) { // if no template is given
672
+ // ===== Create a number format with default values
673
+ newNumberFormat.setNumberFormatId(0);
674
+ newNumberFormat.setFormatCode("General");
675
+ }
676
+ else
677
+ copyXMLNode(newNode, *copyFrom.m_numberFormatNode); // will use copyFrom as template, does nothing if copyFrom is empty
678
+
679
+ m_numberFormats.push_back(newNumberFormat);
680
+ appendAndSetAttribute(*m_numberFormatsNode, "count", std::to_string(m_numberFormats.size())); // update array count in XML
681
+ return index;
682
+ }
683
+
684
+
685
+ /**
686
+ * @details Constructor. Initializes an empty XLFont object
687
+ */
688
+ XLFont::XLFont() : m_fontNode(std::make_unique<XMLNode>()) {}
689
+
690
+ /**
691
+ * @details Constructor. Initializes the member variables for the new XLFont object.
692
+ */
693
+ XLFont::XLFont(const XMLNode& node) : m_fontNode(std::make_unique<XMLNode>(node)) {}
694
+
695
+ /**
696
+ * @details Copy constructor
697
+ */
698
+ XLFont::XLFont(const XLFont& other)
699
+ : m_fontNode(std::make_unique<XMLNode>(*other.m_fontNode))
700
+ {}
701
+
702
+ /**
703
+ * @details Move constructor
704
+ */
705
+ XLFont::XLFont(XLFont&& other) noexcept = default;
706
+
707
+ /**
708
+ * @details
709
+ */
710
+ XLFont::~XLFont() = default;
711
+
712
+ /**
713
+ * @details Copy assignment operator
714
+ */
715
+ XLFont& XLFont::operator=(const XLFont& other)
716
+ {
717
+ if (&other != this) *m_fontNode = *other.m_fontNode;
718
+ return *this;
719
+ }
720
+
721
+ /**
722
+ * @details Move assignment operator
723
+ */
724
+ XLFont& XLFont::operator=(XLFont&& other) noexcept = default;
725
+
726
+ /**
727
+ * @details Returns the font name property
728
+ */
729
+ std::string XLFont::fontName() const
730
+ {
731
+ XMLAttribute attr = appendAndGetNodeAttribute(*m_fontNode, "name", "val", OpenXLSX::XLDefaultFontName);
732
+ return attr.value();
733
+ }
734
+
735
+ /**
736
+ * @details Returns the font charset property
737
+ */
738
+ size_t XLFont::fontCharset() const
739
+ {
740
+ XMLAttribute attr = appendAndGetNodeAttribute(*m_fontNode, "charset", "val", std::to_string(OpenXLSX::XLDefaultFontCharset));
741
+ return attr.as_uint();
742
+ }
743
+
744
+ /**
745
+ * @details Returns the font family property
746
+ */
747
+ size_t XLFont::fontFamily() const
748
+ {
749
+ XMLAttribute attr = appendAndGetNodeAttribute(*m_fontNode, "family", "val", std::to_string(OpenXLSX::XLDefaultFontFamily));
750
+ return attr.as_uint();
751
+ }
752
+
753
+ /**
754
+ * @details Returns the font size property
755
+ */
756
+ size_t XLFont::fontSize() const
757
+ {
758
+ XMLAttribute attr = appendAndGetNodeAttribute(*m_fontNode, "sz", "val", std::to_string(OpenXLSX::XLDefaultFontSize));
759
+ return attr.as_uint();
760
+ }
761
+
762
+ /**
763
+ * @details Returns the font color property
764
+ */
765
+ XLColor XLFont::fontColor() const
766
+ {
767
+ using namespace std::literals::string_literals;
768
+ // XMLAttribute attr = appendAndGetNodeAttribute(*m_fontNode, "color", "theme", OpenXLSX::XLDefaultFontColorTheme);
769
+ // TBD what "theme" is and whether it should be supported at all
770
+ XMLAttribute attr = appendAndGetNodeAttribute(*m_fontNode, "color", "rgb", XLDefaultFontColor);
771
+ return XLColor(attr.value());
772
+ }
773
+
774
+ /**
775
+ * @details getter functions: return the font's bold, italic, underline, strikethrough status
776
+ */
777
+ bool XLFont::bold() const { return getBoolAttributeWhenOmittedMeansTrue(*m_fontNode, "b", "val"); }
778
+ bool XLFont::italic() const { return getBoolAttributeWhenOmittedMeansTrue(*m_fontNode, "i", "val"); }
779
+ bool XLFont::strikethrough() const { return getBoolAttributeWhenOmittedMeansTrue(*m_fontNode, "strike", "val"); }
780
+ XLUnderlineStyle XLFont::underline() const { return XLUnderlineStyleFromString (appendAndGetNodeAttribute(*m_fontNode, "u", "val", "none" ).value() ); }
781
+ XLFontSchemeStyle XLFont::scheme() const { return XLFontSchemeStyleFromString (appendAndGetNodeAttribute(*m_fontNode, "scheme", "val", "none" ).value() ); }
782
+ XLVerticalAlignRunStyle XLFont::vertAlign() const { return XLVerticalAlignRunStyleFromString(appendAndGetNodeAttribute(*m_fontNode, "vertAlign", "val", "baseline").value() ); }
783
+ bool XLFont::outline() const { return getBoolAttributeWhenOmittedMeansTrue(*m_fontNode, "outline", "val"); }
784
+ bool XLFont::shadow() const { return getBoolAttributeWhenOmittedMeansTrue(*m_fontNode, "shadow", "val"); }
785
+ bool XLFont::condense() const { return getBoolAttributeWhenOmittedMeansTrue(*m_fontNode, "condense", "val"); }
786
+ bool XLFont::extend() const { return getBoolAttributeWhenOmittedMeansTrue(*m_fontNode, "extend", "val"); }
787
+
788
+ /**
789
+ * @details Setter functions
790
+ */
791
+ bool XLFont::setFontName (std::string newName) { return appendAndSetNodeAttribute(*m_fontNode, "name", "val", newName.c_str() ).empty() == false; }
792
+ bool XLFont::setFontCharset (size_t newCharset) { return appendAndSetNodeAttribute(*m_fontNode, "charset", "val", std::to_string(newCharset) ).empty() == false; }
793
+ bool XLFont::setFontFamily (size_t newFamily) { return appendAndSetNodeAttribute(*m_fontNode, "family", "val", std::to_string(newFamily) ).empty() == false; }
794
+ bool XLFont::setFontSize (size_t newSize) { return appendAndSetNodeAttribute(*m_fontNode, "sz", "val", std::to_string(newSize) ).empty() == false; }
795
+ bool XLFont::setFontColor (XLColor newColor) { return appendAndSetNodeAttribute(*m_fontNode, "color", "rgb", newColor.hex(), XLRemoveAttributes ).empty() == false; }
796
+ bool XLFont::setBold (bool set) { return appendAndSetNodeAttribute(*m_fontNode, "b", "val", (set ? "true" : "false") ).empty() == false; }
797
+ bool XLFont::setItalic (bool set) { return appendAndSetNodeAttribute(*m_fontNode, "i", "val", (set ? "true" : "false") ).empty() == false; }
798
+ bool XLFont::setStrikethrough(bool set) { return appendAndSetNodeAttribute(*m_fontNode, "strike", "val", (set ? "true" : "false") ).empty() == false; }
799
+ bool XLFont::setUnderline (XLUnderlineStyle style)
800
+ { return appendAndSetNodeAttribute(*m_fontNode, "u", "val", XLUnderlineStyleToString (style ).c_str()).empty() == false; }
801
+ bool XLFont::setScheme (XLFontSchemeStyle newScheme)
802
+ { return appendAndSetNodeAttribute(*m_fontNode, "scheme", "val", XLFontSchemeStyleToString (newScheme ).c_str()).empty() == false; }
803
+ bool XLFont::setVertAlign (XLVerticalAlignRunStyle newVertAlign)
804
+ { return appendAndSetNodeAttribute(*m_fontNode, "vertAlign", "val", XLVerticalAlignRunStyleToString(newVertAlign).c_str()).empty() == false; }
805
+ bool XLFont::setOutline (bool set) { return appendAndSetNodeAttribute(*m_fontNode, "outline", "val", (set ? "true" : "false") ).empty() == false; }
806
+ bool XLFont::setShadow (bool set) { return appendAndSetNodeAttribute(*m_fontNode, "shadow", "val", (set ? "true" : "false") ).empty() == false; }
807
+ bool XLFont::setCondense(bool set) { return appendAndSetNodeAttribute(*m_fontNode, "condense", "val", (set ? "true" : "false") ).empty() == false; }
808
+ bool XLFont::setExtend (bool set) { return appendAndSetNodeAttribute(*m_fontNode, "extend", "val", (set ? "true" : "false") ).empty() == false; }
809
+
810
+
811
+ /**
812
+ * @details assemble a string summary about the font
813
+ */
814
+ std::string XLFont::summary() const
815
+ {
816
+ using namespace std::literals::string_literals;
817
+ return "font name is "s + fontName()
818
+ + ", charset: "s + std::to_string(fontCharset())
819
+ + ", font family: "s + std::to_string(fontFamily())
820
+ + ", size: "s + std::to_string(fontSize())
821
+ + ", color: "s + fontColor().hex()
822
+ + (bold() ? ", +bold"s : ""s)
823
+ + (italic() ? ", +italic"s : ""s)
824
+ + (strikethrough() ? ", +strikethrough"s : ""s)
825
+ + (underline() != XLUnderlineNone ? ", underline: "s + XLUnderlineStyleToString(underline()) : ""s)
826
+ + (scheme() != XLFontSchemeNone ? ", scheme: "s + XLFontSchemeStyleToString(scheme()) : ""s)
827
+ + (vertAlign() != XLBaseline ? ", vertAlign: "s + XLVerticalAlignRunStyleToString(vertAlign()) : ""s)
828
+ + (outline() ? ", +outline"s : ""s)
829
+ + (shadow() ? ", +shadow"s : ""s)
830
+ + (condense() ? ", +condense"s : ""s)
831
+ + (extend() ? ", +extend"s : ""s);
832
+ }
833
+
834
+
835
+ // ===== XLFonts, parent of XLFont
836
+
837
+ /**
838
+ * @details Constructor. Initializes an empty XLFonts object
839
+ */
840
+ XLFonts::XLFonts() : m_fontsNode(std::make_unique<XMLNode>()) {}
841
+
842
+ /**
843
+ * @details Constructor. Initializes the member variables for the new XLFonts object.
844
+ */
845
+ XLFonts::XLFonts(const XMLNode& fonts)
846
+ : m_fontsNode(std::make_unique<XMLNode>(fonts))
847
+ {
848
+ // initialize XLFonts entries and m_fonts here
849
+ XMLNode node = m_fontsNode->first_child_of_type(pugi::node_element);
850
+ while (not node.empty()) {
851
+ std::string nodeName = node.name();
852
+ if (nodeName == "font")
853
+ m_fonts.push_back(XLFont(node));
854
+ else
855
+ std::cerr << "WARNING: XLFonts constructor: unknown subnode " << nodeName << std::endl;
856
+ node = node.next_sibling_of_type(pugi::node_element);
857
+ }
858
+ }
859
+
860
+ /**
861
+ * @details Copy constructor
862
+ */
863
+ XLFonts::XLFonts(const XLFonts& other)
864
+ : m_fontsNode(std::make_unique<XMLNode>(*other.m_fontsNode)),
865
+ m_fonts(other.m_fonts)
866
+ {}
867
+
868
+ /**
869
+ * @details Move constructor
870
+ */
871
+ XLFonts::XLFonts(XLFonts&& other)
872
+ : m_fontsNode(std::move(other.m_fontsNode)),
873
+ m_fonts(std::move(other.m_fonts))
874
+ {}
875
+
876
+ /**
877
+ * @details
878
+ */
879
+ XLFonts::~XLFonts()
880
+ {
881
+ m_fonts.clear(); // delete vector with all children
882
+ }
883
+
884
+ /**
885
+ * @details Copy assignment operator
886
+ */
887
+ XLFonts& XLFonts::operator=(const XLFonts& other)
888
+ {
889
+ if (&other != this) {
890
+ *m_fontsNode = *other.m_fontsNode;
891
+ m_fonts.clear();
892
+ m_fonts = other.m_fonts;
893
+ }
894
+ return *this;
895
+ }
896
+
897
+ /**
898
+ * @details Move assignment operator
899
+ */
900
+ XLFonts& XLFonts::operator=(XLFonts&& other) noexcept = default;
901
+
902
+ /**
903
+ * @details Returns the amount of fonts held by the class
904
+ */
905
+ size_t XLFonts::count() const { return m_fonts.size(); }
906
+
907
+ /**
908
+ * @details fetch XLFont from m_Fonts by index
909
+ */
910
+ XLFont XLFonts::fontByIndex(XLStyleIndex index) const
911
+ {
912
+ if (index >= m_fonts.size()) {
913
+ using namespace std::literals::string_literals;
914
+ throw XLException("XLFonts::"s + __func__ + ": attempted to access index "s + std::to_string(index) + " with count "s + std::to_string(m_fonts.size()));
915
+ }
916
+ return m_fonts.at(index);
917
+ }
918
+
919
+ /**
920
+ * @details append a new XLFont to m_fonts and m_fontsNode, based on copyFrom
921
+ */
922
+ XLStyleIndex XLFonts::create(XLFont copyFrom, std::string styleEntriesPrefix)
923
+ {
924
+ XLStyleIndex index = count(); // index for the font to be created
925
+ XMLNode newNode{}; // scope declaration
926
+
927
+ // ===== Append new node prior to final whitespaces, if any
928
+ XMLNode lastStyle = m_fontsNode->last_child_of_type(pugi::node_element);
929
+ if (lastStyle.empty()) newNode = m_fontsNode->prepend_child("font");
930
+ else newNode = m_fontsNode->insert_child_after("font", lastStyle);
931
+ if (newNode.empty()) {
932
+ using namespace std::literals::string_literals;
933
+ throw XLException("XLFonts::"s + __func__ + ": failed to append a new fonts node"s);
934
+ }
935
+ if (styleEntriesPrefix.length() > 0) // if a whitespace prefix is configured
936
+ m_fontsNode->insert_child_before(pugi::node_pcdata, newNode).set_value(styleEntriesPrefix.c_str()); // prefix the new node with styleEntriesPrefix
937
+
938
+ XLFont newFont(newNode);
939
+ if (copyFrom.m_fontNode->empty()) { // if no template is given
940
+ // ===== Create a font with default values
941
+ // TODO: implement font defaults
942
+ // newFont.setProperty(defaultValue);
943
+ // ...
944
+ }
945
+ else
946
+ copyXMLNode(newNode, *copyFrom.m_fontNode); // will use copyFrom as template, does nothing if copyFrom is empty
947
+
948
+ m_fonts.push_back(newFont);
949
+ appendAndSetAttribute(*m_fontsNode, "count", std::to_string(m_fonts.size())); // update array count in XML
950
+ return index;
951
+ }
952
+
953
+
954
+ // ===== XLDataBarColor, used by XLFills gradientFill and by XLLine (to be implemented)
955
+
956
+ /**
957
+ * @details Constructor. Initializes an empty XLDataBarColor object
958
+ */
959
+ XLDataBarColor::XLDataBarColor() : m_colorNode(std::make_unique<XMLNode>()) {}
960
+
961
+ /**
962
+ * @details Constructor. Initializes the member variables for the new XLDataBarColor object.
963
+ */
964
+ XLDataBarColor::XLDataBarColor(const XMLNode& node) : m_colorNode(std::make_unique<XMLNode>(node)) {}
965
+
966
+ /**
967
+ * @details Copy constructor - initializes the member variables from other
968
+ */
969
+ XLDataBarColor::XLDataBarColor(const XLDataBarColor& other)
970
+ : m_colorNode(std::make_unique<XMLNode>(*other.m_colorNode))
971
+ {}
972
+
973
+ /**
974
+ * @details Move Constructor
975
+ */
976
+ XLDataBarColor::XLDataBarColor(XLDataBarColor&& other) noexcept = default;
977
+
978
+ /**
979
+ * @details
980
+ */
981
+ XLDataBarColor::~XLDataBarColor() = default;
982
+
983
+ /**
984
+ * @details Copy assignment operator
985
+ */
986
+ XLDataBarColor& XLDataBarColor::operator=(const XLDataBarColor& other)
987
+ {
988
+ if (&other != this) *m_colorNode = *other.m_colorNode;
989
+ return *this;
990
+ }
991
+
992
+ /**
993
+ * @details Move assignment operator
994
+ */
995
+ XLDataBarColor& XLDataBarColor::operator=(XLDataBarColor&& other) noexcept = default;
996
+
997
+ /**
998
+ * @details Getter functions
999
+ */
1000
+ XLColor XLDataBarColor::rgb() const { return XLColor(m_colorNode->attribute("rgb" ).as_string("ffffffff")); }
1001
+ double XLDataBarColor::tint() const { return m_colorNode->attribute("tint" ).as_double(0.0) ; }
1002
+ bool XLDataBarColor::automatic() const { return m_colorNode->attribute("auto" ).as_bool() ; }
1003
+ uint32_t XLDataBarColor::indexed() const { return m_colorNode->attribute("indexed").as_uint() ; }
1004
+ uint32_t XLDataBarColor::theme() const { return m_colorNode->attribute("theme" ).as_uint() ; }
1005
+ /**
1006
+ * @details Setter functions
1007
+ */
1008
+ bool XLDataBarColor::setRgb (XLColor newColor) { return appendAndSetAttribute(*m_colorNode, "rgb", newColor.hex() ).empty() == false; }
1009
+ bool XLDataBarColor::setTint(double newTint)
1010
+ {
1011
+ std::string tintString = "";
1012
+ if (newTint != 0.0) {
1013
+ tintString = checkAndFormatDoubleAsString(newTint, -1.0, +1.0, 0.01);
1014
+ if (tintString.length() == 0) {
1015
+ using namespace std::literals::string_literals;
1016
+ throw XLException("XLDataBarColor::setTint: color tint "s + std::to_string(newTint) + " is not in range [-1.0;+1.0]"s);
1017
+ }
1018
+ }
1019
+ if (tintString.length() == 0) return m_colorNode->remove_attribute("tint"); // remove tint attribute for a value 0
1020
+
1021
+ return (appendAndSetAttribute(*m_colorNode, "tint", tintString).empty() == false); // else: set tint attribute
1022
+ }
1023
+ bool XLDataBarColor::setAutomatic(bool set) { return appendAndSetAttribute(*m_colorNode, "auto", (set ? "true" : "false") ).empty() == false; }
1024
+ bool XLDataBarColor::setIndexed(uint32_t newIndex) { return appendAndSetAttribute(*m_colorNode, "indexed", std::to_string(newIndex) ).empty() == false; }
1025
+ bool XLDataBarColor::setTheme(uint32_t newTheme) {
1026
+ if( newTheme == XLDeleteProperty ) return m_colorNode->remove_attribute("theme");
1027
+ return appendAndSetAttribute(*m_colorNode, "theme", std::to_string(newTheme) ).empty() == false;
1028
+ }
1029
+
1030
+ /**
1031
+ * @details assemble a string summary about the color
1032
+ */
1033
+ std::string XLDataBarColor::summary() const
1034
+ {
1035
+ using namespace std::literals::string_literals;
1036
+ return "rgb is "s + rgb().hex()
1037
+ + ", tint is "s + formatDoubleAsString(tint())
1038
+ + (automatic() ? ", +automatic"s : ""s)
1039
+ + (indexed() ? (", index is "s + std::to_string(indexed())) : "")
1040
+ + (theme() ? (", theme is "s + std::to_string(theme() )) : "")
1041
+ ;
1042
+ }
1043
+
1044
+
1045
+ /**
1046
+ * @details Constructor. Initializes an empty XLGradientStop object
1047
+ */
1048
+ XLGradientStop::XLGradientStop() : m_stopNode(std::make_unique<XMLNode>()) {}
1049
+
1050
+ /**
1051
+ * @details Constructor. Initializes the member variables for the new XLGradientStop object.
1052
+ */
1053
+ XLGradientStop::XLGradientStop(const XMLNode& node) : m_stopNode(std::make_unique<XMLNode>(node)) {}
1054
+
1055
+ /**
1056
+ * @details Copy constructor - initializes the member variables from other
1057
+ */
1058
+ XLGradientStop::XLGradientStop(const XLGradientStop& other)
1059
+ : m_stopNode(std::make_unique<XMLNode>(*other.m_stopNode))
1060
+ {}
1061
+
1062
+ /**
1063
+ * @details Move Constructor
1064
+ */
1065
+ XLGradientStop::XLGradientStop(XLGradientStop&& other) noexcept = default;
1066
+
1067
+ /**
1068
+ * @details
1069
+ */
1070
+ XLGradientStop::~XLGradientStop() = default;
1071
+
1072
+ /**
1073
+ * @details Copy assignment operator
1074
+ */
1075
+ XLGradientStop& XLGradientStop::operator=(const XLGradientStop& other)
1076
+ {
1077
+ if (&other != this) *m_stopNode = *other.m_stopNode;
1078
+ return *this;
1079
+ }
1080
+
1081
+ /**
1082
+ * @details Move assignment operator
1083
+ */
1084
+ XLGradientStop& XLGradientStop::operator=(XLGradientStop&& other) noexcept = default;
1085
+
1086
+ /**
1087
+ * @details Getter functions
1088
+ */
1089
+ XLDataBarColor XLGradientStop::color() const
1090
+ {
1091
+ XMLNode color = appendAndGetNode(*m_stopNode, "color");
1092
+ if (color.empty()) return XLDataBarColor{};
1093
+ return XLDataBarColor(color);
1094
+ }
1095
+ double XLGradientStop::position() const
1096
+ {
1097
+ XMLAttribute attr = m_stopNode->attribute("position");
1098
+ return attr.as_double(0.0);
1099
+ }
1100
+
1101
+ /**
1102
+ * @details Setter functions
1103
+ */
1104
+ bool XLGradientStop::setPosition(double newPosition) { return appendAndSetAttribute(*m_stopNode, "position", formatDoubleAsString(newPosition)).empty() == false; }
1105
+
1106
+
1107
+ /**
1108
+ * @details assemble a string summary about the stop
1109
+ */
1110
+ std::string XLGradientStop::summary() const
1111
+ {
1112
+ using namespace std::literals::string_literals;
1113
+ return "stop position is "s + formatDoubleAsString(position())
1114
+ + ", " + color().summary();
1115
+ }
1116
+
1117
+
1118
+ // ===== XLGradientStops, parent of XLGradientStop
1119
+
1120
+ /**
1121
+ * @details Constructor. Initializes an empty XLGradientStops object
1122
+ */
1123
+ XLGradientStops::XLGradientStops() : m_gradientNode(std::make_unique<XMLNode>()) {}
1124
+
1125
+ /**
1126
+ * @details Constructor. Initializes the member variables for the new XLGradientStops object.
1127
+ */
1128
+ XLGradientStops::XLGradientStops(const XMLNode& gradient)
1129
+ : m_gradientNode(std::make_unique<XMLNode>(gradient))
1130
+ {
1131
+ // initialize XLGradientStops entries and m_gradientStops here
1132
+ XMLNode node = m_gradientNode->first_child_of_type(pugi::node_element);
1133
+ while (not node.empty()) {
1134
+ std::string nodeName = node.name();
1135
+ if (nodeName == "stop")
1136
+ m_gradientStops.push_back(XLGradientStop(node));
1137
+ else
1138
+ std::cerr << "WARNING: XLGradientStops constructor: unknown subnode " << nodeName << std::endl;
1139
+ node = node.next_sibling_of_type(pugi::node_element);
1140
+ }
1141
+ }
1142
+
1143
+ /**
1144
+ * @details Copy constructor
1145
+ */
1146
+ XLGradientStops::XLGradientStops(const XLGradientStops& other)
1147
+ : m_gradientNode(std::make_unique<XMLNode>(*other.m_gradientNode)),
1148
+ m_gradientStops(other.m_gradientStops)
1149
+ {}
1150
+
1151
+ /**
1152
+ * @details Move constructor
1153
+ */
1154
+ XLGradientStops::XLGradientStops(XLGradientStops&& other)
1155
+ : m_gradientNode(std::move(other.m_gradientNode)),
1156
+ m_gradientStops(std::move(other.m_gradientStops))
1157
+ {}
1158
+
1159
+ /**
1160
+ * @details
1161
+ */
1162
+ XLGradientStops::~XLGradientStops()
1163
+ {
1164
+ m_gradientStops.clear(); // delete vector with all children
1165
+ }
1166
+
1167
+ /**
1168
+ * @details Copy assignment operator
1169
+ */
1170
+ XLGradientStops& XLGradientStops::operator=(const XLGradientStops& other)
1171
+ {
1172
+ if (&other != this) {
1173
+ *m_gradientNode = *other.m_gradientNode;
1174
+ m_gradientStops.clear();
1175
+ m_gradientStops = other.m_gradientStops;
1176
+ }
1177
+ return *this;
1178
+ }
1179
+
1180
+ /**
1181
+ * @details Move assignment operator.
1182
+ */
1183
+ XLGradientStops& XLGradientStops::operator=(XLGradientStops&& other) noexcept = default;
1184
+
1185
+ /**
1186
+ * @details Returns the amount of gradient stops held by the class
1187
+ */
1188
+ size_t XLGradientStops::count() const { return m_gradientStops.size(); }
1189
+
1190
+ /**
1191
+ * @details fetch XLGradientStop from m_gradientStops by index
1192
+ */
1193
+ XLGradientStop XLGradientStops::stopByIndex(XLStyleIndex index) const
1194
+ {
1195
+ if (index >= m_gradientStops.size()) {
1196
+ using namespace std::literals::string_literals;
1197
+ throw XLException("XLGradientStops::"s + __func__ + ": attempted to access index "s + std::to_string(index) + " with count "s + std::to_string(m_gradientStops.size()));
1198
+ }
1199
+ return m_gradientStops.at(index);
1200
+ }
1201
+
1202
+ /**
1203
+ * @details append a new XLGradientStop to m_gradientStops m_gradientNode, based on copyFrom
1204
+ */
1205
+ XLStyleIndex XLGradientStops::create(XLGradientStop copyFrom, std::string styleEntriesPrefix)
1206
+ {
1207
+ XLStyleIndex index = count(); // index for the gradient stop to be created
1208
+ XMLNode newNode{}; // scope declaration
1209
+
1210
+ // ===== Append new node prior to final whitespaces, if any
1211
+ XMLNode lastStyle = m_gradientNode->last_child_of_type(pugi::node_element);
1212
+ if (lastStyle.empty()) newNode = m_gradientNode->prepend_child("stop");
1213
+ else newNode = m_gradientNode->insert_child_after("stop", lastStyle);
1214
+ if (newNode.empty()) {
1215
+ using namespace std::literals::string_literals;
1216
+ throw XLException("XLGradientStops::"s + __func__ + ": failed to append a new stop node"s);
1217
+ }
1218
+ if (styleEntriesPrefix.length() > 0) // if a whitespace prefix is configured
1219
+ m_gradientNode->insert_child_before(pugi::node_pcdata, newNode).set_value(styleEntriesPrefix.c_str()); // prefix the new node with styleEntriesPrefix
1220
+
1221
+ XLGradientStop newStop(newNode);
1222
+ if (copyFrom.m_stopNode->empty()) { // if no template is given
1223
+ // ===== Create a stop node with default values
1224
+ // TODO: implement stop defaults
1225
+ // newStop.setProperty(defaultValue);
1226
+ // ...
1227
+ }
1228
+ else
1229
+ copyXMLNode(newNode, *copyFrom.m_stopNode); // will use copyFrom as template, does nothing if copyFrom is empty
1230
+
1231
+ m_gradientStops.push_back(newStop);
1232
+ appendAndSetAttribute(*m_gradientNode, "count", std::to_string(m_gradientStops.size())); // update array count in XML
1233
+ return index;
1234
+ }
1235
+
1236
+ std::string XLGradientStops::summary() const
1237
+ {
1238
+ std::string result{};
1239
+ for(XLGradientStop stop : m_gradientStops)
1240
+ result += stop.summary() + ", ";
1241
+ if (result.length() < 2) return ""; // if no stop summary was created - return empty string
1242
+ return result.substr(0, result.length() - 2);
1243
+ }
1244
+
1245
+ /**
1246
+ * @details Constructor. Initializes an empty XLFill object
1247
+ */
1248
+ XLFill::XLFill() : m_fillNode(std::make_unique<XMLNode>()) {}
1249
+
1250
+ /**
1251
+ * @details Constructor. Initializes the member variables for the new XLFill object.
1252
+ */
1253
+ XLFill::XLFill(const XMLNode& node) : m_fillNode(std::make_unique<XMLNode>(node)) {}
1254
+
1255
+ /**
1256
+ * @details Copy constructor
1257
+ */
1258
+ XLFill::XLFill(const XLFill& other)
1259
+ : m_fillNode(std::make_unique<XMLNode>(*other.m_fillNode))
1260
+ {}
1261
+
1262
+ /**
1263
+ * @details Move constructor
1264
+ */
1265
+ XLFill::XLFill(XLFill&& other) noexcept = default;
1266
+
1267
+ /**
1268
+ * @details
1269
+ */
1270
+ XLFill::~XLFill() = default;
1271
+
1272
+ /**
1273
+ * @details Copy assignment operator
1274
+ */
1275
+ XLFill& XLFill::operator=(const XLFill& other)
1276
+ {
1277
+ if (&other != this) *m_fillNode = *other.m_fillNode;
1278
+ return *this;
1279
+ }
1280
+
1281
+ /**
1282
+ * @details Move assignment operator
1283
+ */
1284
+ XLFill& XLFill::operator=(XLFill&& other) noexcept = default;
1285
+
1286
+ /**
1287
+ * @details Returns the name of the first element child of fill
1288
+ * @note an empty node ::name() returns an empty string "", leading to XLFillTypeInvalid
1289
+ */
1290
+ XLFillType XLFill::fillType() const { return XLFillTypeFromString(m_fillNode->first_child_of_type(pugi::node_element).name()); }
1291
+
1292
+ /**
1293
+ * @details set the fill type for a fill node - if force is true, delete any existing fill properties
1294
+ */
1295
+ bool XLFill::setFillType(XLFillType newFillType, bool force)
1296
+ {
1297
+ XLFillType ft = fillType(); // determine once, use twice
1298
+
1299
+ // ===== If desired filltype is already set
1300
+ if (ft == newFillType) return true; // nothing to do
1301
+
1302
+ // ===== If force == true or fillType is just not set at all, delete existing child nodes, otherwise throw
1303
+ if (!force && ft != XLFillTypeInvalid) {
1304
+ using namespace std::literals::string_literals;
1305
+ throw XLException("XLFill::setFillType: can not change the fillType from "s + XLFillTypeToString(fillType())
1306
+ + " to "s + XLFillTypeToString(newFillType) + " - invoke with force == true if override is desired"s);
1307
+ }
1308
+ // ===== At this point, m_fillNode needs to be emptied for a setting / force-change of the fill type
1309
+
1310
+ // ===== Delete all fill node children and insert a new node for the newFillType
1311
+ m_fillNode->remove_children();
1312
+ return (m_fillNode->append_child(XLFillTypeToString(newFillType).c_str()).empty() == false);
1313
+ }
1314
+
1315
+ /**
1316
+ * @details Throw an XLException on a fill of typeToThrowOn
1317
+ */
1318
+ void XLFill::throwOnFillType(XLFillType typeToThrowOn, const char *functionName) const
1319
+ {
1320
+ using namespace std::literals::string_literals;
1321
+ if (fillType() == typeToThrowOn)
1322
+ throw XLException("XLFill::"s + functionName + " must not be invoked for a "s + XLFillTypeToString(typeToThrowOn));
1323
+ }
1324
+
1325
+ /**
1326
+ * @details get the fill element XML, create element with default XLFillType if none exists
1327
+ */
1328
+ XMLNode XLFill::getValidFillDescription(XLFillType fillTypeIfEmpty, const char *functionName)
1329
+ {
1330
+ XLFillType throwOnThis = XLFillTypeInvalid;
1331
+ switch (fillTypeIfEmpty) {
1332
+ case XLGradientFill: throwOnThis = XLPatternFill; break; // throw on non-matching fill type
1333
+ case XLPatternFill : throwOnThis = XLGradientFill; break; // "
1334
+ default: throw XLException("XLFill::getValidFillDescription was not invoked with XLPatternFill or XLGradientFill");
1335
+ }
1336
+ throwOnFillType(throwOnThis, functionName);
1337
+ XMLNode fillDescription = m_fillNode->first_child_of_type(pugi::node_element); // fetch an existing fill description
1338
+ if (fillDescription.empty() && setFillType(fillTypeIfEmpty)) // if none exists, attempt to create a description
1339
+ fillDescription = m_fillNode->first_child_of_type(pugi::node_element); // fetch newly inserted description
1340
+ return fillDescription;
1341
+ }
1342
+
1343
+
1344
+ /**
1345
+ * @details Getter functions for gradientFill
1346
+ */
1347
+ XLGradientType XLFill::gradientType() { return XLGradientTypeFromString(getValidFillDescription(XLGradientFill, __func__).attribute("type" ).value() ); }
1348
+ double XLFill::degree() { return getValidFillDescription(XLGradientFill, __func__).attribute("degree").as_double(0) ; }
1349
+ double XLFill::left() { return getValidFillDescription(XLGradientFill, __func__).attribute("left" ).as_double(0) ; }
1350
+ double XLFill::right() { return getValidFillDescription(XLGradientFill, __func__).attribute("right" ).as_double(0) ; }
1351
+ double XLFill::top() { return getValidFillDescription(XLGradientFill, __func__).attribute("top" ).as_double(0) ; }
1352
+ double XLFill::bottom() { return getValidFillDescription(XLGradientFill, __func__).attribute("bottom").as_double(0) ; }
1353
+ XLGradientStops XLFill::stops() { return XLGradientStops( getValidFillDescription(XLGradientFill, __func__) ); }
1354
+
1355
+ /**
1356
+ * @details Getter functions for patternFill
1357
+ */
1358
+ XLPatternType XLFill::patternType()
1359
+ {
1360
+ XMLNode fillDescription = getValidFillDescription(XLPatternFill, __func__);
1361
+ if (fillDescription.empty()) return XLDefaultPatternType; // if no description could be fetched: fail
1362
+ XMLAttribute attr = appendAndGetNodeAttribute(*m_fillNode, XLFillTypeToString(XLPatternFill), "patternType", XLPatternTypeToString(XLDefaultPatternType));
1363
+ return XLPatternTypeFromString(attr.value());
1364
+ }
1365
+
1366
+ XLColor XLFill::color()
1367
+ {
1368
+ XMLNode fillDescription = getValidFillDescription(XLPatternFill, __func__);
1369
+ if (fillDescription.empty()) return XLColor{}; // if no description could be fetched: fail
1370
+ XMLAttribute fgColorRGB = appendAndGetNodeAttribute(fillDescription, "fgColor", "rgb", XLDefaultPatternFgColor);
1371
+ return XLColor(fgColorRGB.value());
1372
+ }
1373
+ XLColor XLFill::backgroundColor()
1374
+ {
1375
+ XMLNode fillDescription = getValidFillDescription(XLPatternFill, __func__);
1376
+ if (fillDescription.empty()) return XLColor{}; // if no description could be fetched: fail
1377
+ XMLAttribute bgColorRGB = appendAndGetNodeAttribute(fillDescription, "bgColor", "rgb", XLDefaultPatternBgColor);
1378
+ return XLColor(bgColorRGB.value());
1379
+ }
1380
+
1381
+ /**
1382
+ * @details Setter functions for gradientFill
1383
+ */
1384
+ bool XLFill::setGradientType(XLGradientType newType)
1385
+ {
1386
+ XMLNode fillDescription = getValidFillDescription(XLGradientFill, __func__);
1387
+ return appendAndSetAttribute(fillDescription, "type", XLGradientTypeToString(newType)).empty() == false;
1388
+ }
1389
+ bool XLFill::setDegree(double newDegree)
1390
+ {
1391
+ std::string degreeString = checkAndFormatDoubleAsString(newDegree, 0.0, 360.0, 0.01);
1392
+ if (degreeString.length() == 0) {
1393
+ using namespace std::literals::string_literals;
1394
+ throw XLException("XLFill::setDegree: gradientFill degree value "s + std::to_string(newDegree) + " is not in range [0.0;360.0]"s);
1395
+ }
1396
+ XMLNode fillDescription = getValidFillDescription(XLGradientFill, __func__);
1397
+ return appendAndSetAttribute(fillDescription, "degree", degreeString ).empty() == false;
1398
+ }
1399
+ bool XLFill::setLeft(double newLeft)
1400
+ {
1401
+ XMLNode fillDescription = getValidFillDescription(XLGradientFill, __func__);
1402
+ return appendAndSetAttribute(fillDescription, "left", formatDoubleAsString(newLeft ).c_str()).empty() == false;
1403
+ }
1404
+ bool XLFill::setRight(double newRight)
1405
+ {
1406
+ XMLNode fillDescription = getValidFillDescription(XLGradientFill, __func__);
1407
+ return appendAndSetAttribute(fillDescription, "right", formatDoubleAsString(newRight ).c_str()).empty() == false;
1408
+ }
1409
+ bool XLFill::setTop(double newTop)
1410
+ {
1411
+ XMLNode fillDescription = getValidFillDescription(XLGradientFill, __func__);
1412
+ return appendAndSetAttribute(fillDescription, "top", formatDoubleAsString(newTop ).c_str()).empty() == false;
1413
+ }
1414
+ bool XLFill::setBottom(double newBottom)
1415
+ {
1416
+ XMLNode fillDescription = getValidFillDescription(XLGradientFill, __func__);
1417
+ return appendAndSetAttribute(fillDescription, "bottom", formatDoubleAsString(newBottom).c_str()).empty() == false;
1418
+ }
1419
+
1420
+ /**
1421
+ * @details Setter functions for patternFill
1422
+ */
1423
+ bool XLFill::setPatternType(XLPatternType newFillPattern)
1424
+ {
1425
+ XMLNode fillDescription = getValidFillDescription(XLPatternFill, __func__);
1426
+ if (fillDescription.empty()) return false; // if no description could be fetched: fail
1427
+ return appendAndSetAttribute(fillDescription, "patternType", XLPatternTypeToString(newFillPattern)).empty() == false;
1428
+ }
1429
+ bool XLFill::setColor(XLColor newColor)
1430
+ {
1431
+ XMLNode fillDescription = getValidFillDescription(XLPatternFill, __func__);
1432
+ if (fillDescription.empty()) return false; // if no description could be fetched: fail
1433
+ return appendAndSetNodeAttribute(fillDescription, "fgColor", "rgb", newColor.hex(), XLRemoveAttributes).empty() == false;
1434
+ }
1435
+ bool XLFill::setBackgroundColor(XLColor newBgColor)
1436
+ {
1437
+ XMLNode fillDescription = getValidFillDescription(XLPatternFill, __func__);
1438
+ if (fillDescription.empty()) return false; // if no description could be fetched: fail
1439
+ return appendAndSetNodeAttribute(fillDescription, "bgColor", "rgb", newBgColor.hex(), XLRemoveAttributes).empty() == false;
1440
+ }
1441
+
1442
+
1443
+ /**
1444
+ * @details assemble a string summary about the fill
1445
+ */
1446
+ std::string XLFill::summary()
1447
+ {
1448
+ using namespace std::literals::string_literals;
1449
+ switch (fillType()) {
1450
+ case XLGradientFill:
1451
+ return "fill type is "s + XLFillTypeToString(fillType())
1452
+ + ", gradient type is "s + XLGradientTypeToString(gradientType())
1453
+ + ", degree is: "s + formatDoubleAsString(degree())
1454
+ + ", left is: "s + formatDoubleAsString(left())
1455
+ + ", right is: "s + formatDoubleAsString(right())
1456
+ + ", top is: "s + formatDoubleAsString(top())
1457
+ + ", bottom is: "s + formatDoubleAsString(bottom())
1458
+ + ", stops: "s + stops().summary();
1459
+ case XLPatternFill :
1460
+ return "fill type is "s + XLFillTypeToString(fillType())
1461
+ + ", pattern type is "s + XLPatternTypeToString(patternType())
1462
+ + ", fgcolor is: "s + color().hex() + ", bgcolor: "s + backgroundColor().hex();
1463
+ case XLFillTypeInvalid: [[fallthrough]];
1464
+ default :
1465
+ return "fill type is invalid!"s;
1466
+ }
1467
+ }
1468
+
1469
+ // ===== XLFills, parent of XLFill
1470
+
1471
+ /**
1472
+ * @details Constructor. Initializes an empty XLFills object
1473
+ */
1474
+ XLFills::XLFills() : m_fillsNode(std::make_unique<XMLNode>()) {}
1475
+
1476
+ /**
1477
+ * @details Constructor. Initializes the member variables for the new XLFills object.
1478
+ */
1479
+ XLFills::XLFills(const XMLNode& fills)
1480
+ : m_fillsNode(std::make_unique<XMLNode>(fills))
1481
+ {
1482
+ // initialize XLFills entries and m_fills here
1483
+ XMLNode node = fills.first_child_of_type(pugi::node_element);
1484
+ while (not node.empty()) {
1485
+ std::string nodeName = node.name();
1486
+ if (nodeName == "fill")
1487
+ m_fills.push_back(XLFill(node));
1488
+ else
1489
+ std::cerr << "WARNING: XLFills constructor: unknown subnode " << nodeName << std::endl;
1490
+ node = node.next_sibling_of_type(pugi::node_element);
1491
+ }
1492
+ }
1493
+
1494
+ /**
1495
+ * @details Copy constructor
1496
+ */
1497
+ XLFills::XLFills(const XLFills& other)
1498
+ : m_fillsNode(std::make_unique<XMLNode>(*other.m_fillsNode)),
1499
+ m_fills(other.m_fills)
1500
+ {}
1501
+
1502
+ /**
1503
+ * @details Move constructor
1504
+ */
1505
+ XLFills::XLFills(XLFills&& other)
1506
+ : m_fillsNode(std::move(other.m_fillsNode)),
1507
+ m_fills(std::move(other.m_fills))
1508
+ {}
1509
+
1510
+ /**
1511
+ * @details
1512
+ */
1513
+ XLFills::~XLFills()
1514
+ {
1515
+ m_fills.clear(); // delete vector with all children
1516
+ }
1517
+
1518
+ /**
1519
+ * @details Copy assignment operator
1520
+ */
1521
+ XLFills& XLFills::operator=(const XLFills& other)
1522
+ {
1523
+ if (&other != this) {
1524
+ *m_fillsNode = *other.m_fillsNode;
1525
+ m_fills.clear();
1526
+ m_fills = other.m_fills;
1527
+ }
1528
+ return *this;
1529
+ }
1530
+
1531
+ /**
1532
+ * @details Move assignment operator
1533
+ */
1534
+ XLFills& XLFills::operator=(XLFills&& other) noexcept = default;
1535
+
1536
+ /**
1537
+ * @details Returns the amount of fills held by the class
1538
+ */
1539
+ size_t XLFills::count() const { return m_fills.size(); }
1540
+
1541
+ /**
1542
+ * @details fetch XLFill from m_fills by index
1543
+ */
1544
+ XLFill XLFills::fillByIndex(XLStyleIndex index) const
1545
+ {
1546
+ if (index >= m_fills.size()) {
1547
+ using namespace std::literals::string_literals;
1548
+ throw XLException("XLFills::"s + __func__ + ": attempted to access index "s + std::to_string(index) + " with count "s + std::to_string(m_fills.size()));
1549
+ }
1550
+ return m_fills.at(index);
1551
+ }
1552
+
1553
+ /**
1554
+ * @details append a new XLFill to m_fills and m_fillsNode, based on copyFrom
1555
+ */
1556
+ XLStyleIndex XLFills::create(XLFill copyFrom, std::string styleEntriesPrefix)
1557
+ {
1558
+ XLStyleIndex index = count(); // index for the fill to be created
1559
+ XMLNode newNode{}; // scope declaration
1560
+
1561
+ // ===== Append new node prior to final whitespaces, if any
1562
+ XMLNode lastStyle = m_fillsNode->last_child_of_type(pugi::node_element);
1563
+ if (lastStyle.empty()) newNode = m_fillsNode->prepend_child("fill");
1564
+ else newNode = m_fillsNode->insert_child_after("fill", lastStyle);
1565
+ if (newNode.empty()) {
1566
+ using namespace std::literals::string_literals;
1567
+ throw XLException("XLFills::"s + __func__ + ": failed to append a new fill node"s);
1568
+ }
1569
+ if (styleEntriesPrefix.length() > 0) // if a whitespace prefix is configured
1570
+ m_fillsNode->insert_child_before(pugi::node_pcdata, newNode).set_value(styleEntriesPrefix.c_str()); // prefix the new node with styleEntriesPrefix
1571
+
1572
+ XLFill newFill(newNode);
1573
+ if (copyFrom.m_fillNode->empty()) { // if no template is given
1574
+ // ===== Create a fill with default values
1575
+ // TODO: implement fill defaults
1576
+ // newFill.setProperty(defaultValue);
1577
+ // ...
1578
+ }
1579
+ else
1580
+ copyXMLNode(newNode, *copyFrom.m_fillNode); // will use copyFrom as template, does nothing if copyFrom is empty
1581
+
1582
+ m_fills.push_back(newFill);
1583
+ appendAndSetAttribute(*m_fillsNode, "count", std::to_string(m_fills.size())); // update array count in XML
1584
+ return index;
1585
+ }
1586
+
1587
+
1588
+ /**
1589
+ * @details Constructor. Initializes an empty XLLine object
1590
+ */
1591
+ XLLine::XLLine() : m_lineNode(std::make_unique<XMLNode>()) {}
1592
+
1593
+ /**
1594
+ * @details Constructor. Initializes the member variables for the new XLLine object.
1595
+ */
1596
+ XLLine::XLLine(const XMLNode& node) : m_lineNode(std::make_unique<XMLNode>(node)) {}
1597
+
1598
+ /**
1599
+ * @details Copy constructor
1600
+ */
1601
+ XLLine::XLLine(const XLLine& other)
1602
+ : m_lineNode(std::make_unique<XMLNode>(*other.m_lineNode))
1603
+ {}
1604
+
1605
+ /**
1606
+ * @details Move constructor
1607
+ */
1608
+ XLLine::XLLine(XLLine&& other) noexcept = default;
1609
+
1610
+ /**
1611
+ * @details
1612
+ */
1613
+ XLLine::~XLLine() = default;
1614
+
1615
+ /**
1616
+ * @details Copy assignment operator
1617
+ */
1618
+ XLLine& XLLine::operator=(const XLLine& other)
1619
+ {
1620
+ if (&other != this) *m_lineNode = *other.m_lineNode;
1621
+ return *this;
1622
+ }
1623
+
1624
+ /**
1625
+ * @details Move assignment operator
1626
+ */
1627
+ XLLine& XLLine::operator=(XLLine&& other) noexcept = default;
1628
+
1629
+ /**
1630
+ * @details Returns the line style (XLLineStyleNone if line is not set)
1631
+ */
1632
+ XLLineStyle XLLine::style() const
1633
+ {
1634
+ if (m_lineNode->empty()) return XLLineStyleNone;
1635
+ XMLAttribute attr = appendAndGetAttribute(*m_lineNode, "style", OpenXLSX::XLDefaultLineStyle);
1636
+ return XLLineStyleFromString(attr.value());
1637
+ }
1638
+
1639
+ /**
1640
+ * @details check if line is used (set) or not
1641
+ */
1642
+ XLLine::operator bool() const { return (style() != XLLineStyleNone); }
1643
+
1644
+ /**
1645
+ * @details Returns the line data bar color object
1646
+ */
1647
+ XLDataBarColor XLLine::color() const
1648
+ {
1649
+ XMLNode color = appendAndGetNode(*m_lineNode, "color");
1650
+ if (color.empty()) return XLDataBarColor{};
1651
+ return XLDataBarColor(color);
1652
+ }
1653
+ // XLColor XLLine::color() const
1654
+ // {
1655
+ // XMLNode colorDetails = m_lineNode->child("color");
1656
+ // if (colorDetails.empty()) return XLColor("ffffffff");
1657
+ // XMLAttribute colorRGB = colorDetails.attribute("rgb");
1658
+ // if (colorRGB.empty()) return XLColor("ffffffff");
1659
+ // return XLColor(colorRGB.value());
1660
+ // }
1661
+ //
1662
+ // /**
1663
+ // * @details Returns the line color tint
1664
+ // */
1665
+ // double XLLine::colorTint() const
1666
+ // {
1667
+ // XMLNode colorDetails = m_lineNode->child("color");
1668
+ // if (not colorDetails.empty()) {
1669
+ // XMLAttribute colorTint = colorDetails.attribute("tint");
1670
+ // if (not colorTint.empty())
1671
+ // return colorTint.as_double();
1672
+ // }
1673
+ // return 0.0;
1674
+ // }
1675
+
1676
+ /**
1677
+ * @details assemble a string summary about the fill
1678
+ */
1679
+ std::string XLLine::summary() const
1680
+ {
1681
+ using namespace std::literals::string_literals;
1682
+ return "line style is "s + XLLineStyleToString(style()) + ", "s + color().summary();
1683
+ // double tint = colorTint();
1684
+ // std::string tintSummary = "colorTint is "s + (tint == 0.0 ? "(none)"s : std::to_string(tint));
1685
+ // size_t tintDecimalPos = tintSummary.find_last_of('.');
1686
+ // if (tintDecimalPos != std::string::npos) tintSummary = tintSummary.substr(0, tintDecimalPos + 3); // truncate colorTint double output 2 digits after the decimal separator
1687
+ // return "line style is "s + XLLineStyleToString(style()) + ", color is "s + color().hex() + ", "s + tintSummary;
1688
+ }
1689
+
1690
+
1691
+ /**
1692
+ * @details Constructor. Initializes an empty XLBorder object
1693
+ */
1694
+ XLBorder::XLBorder() : m_borderNode(std::make_unique<XMLNode>()) {}
1695
+
1696
+ /**
1697
+ * @details Constructor. Initializes the member variables for the new XLBorder object.
1698
+ */
1699
+ XLBorder::XLBorder(const XMLNode& node) : m_borderNode(std::make_unique<XMLNode>(node)) {}
1700
+
1701
+ /**
1702
+ * @details Copy constructor
1703
+ */
1704
+ XLBorder::XLBorder(const XLBorder& other)
1705
+ : m_borderNode(std::make_unique<XMLNode>(*other.m_borderNode))
1706
+ {}
1707
+
1708
+ /**
1709
+ * @details Move constructor
1710
+ */
1711
+ XLBorder::XLBorder(XLBorder&& other) noexcept = default;
1712
+
1713
+ /**
1714
+ * @details
1715
+ */
1716
+ XLBorder::~XLBorder() = default;
1717
+
1718
+ /**
1719
+ * @details Copy assignment operator
1720
+ */
1721
+ XLBorder& XLBorder::operator=(const XLBorder& other)
1722
+ {
1723
+ if (&other != this) *m_borderNode = *other.m_borderNode;
1724
+ return *this;
1725
+ }
1726
+
1727
+ /**
1728
+ * @details Move assignment operator
1729
+ */
1730
+ XLBorder& XLBorder::operator=(XLBorder&& other) noexcept = default;
1731
+
1732
+ /**
1733
+ * @details determines whether the diagonalUp property is set
1734
+ */
1735
+ bool XLBorder::diagonalUp() const { return m_borderNode->attribute("diagonalUp").as_bool(); }
1736
+
1737
+ /**
1738
+ * @details determines whether the diagonalDown property is set
1739
+ */
1740
+ bool XLBorder::diagonalDown() const { return m_borderNode->attribute("diagonalDown").as_bool(); }
1741
+
1742
+ /**
1743
+ * @details determines whether the outline property is set
1744
+ */
1745
+ bool XLBorder::outline() const { return m_borderNode->attribute("outline").as_bool(); }
1746
+
1747
+ /**
1748
+ * @details fetch lines
1749
+ */
1750
+ XLLine XLBorder::left() const { return XLLine(m_borderNode->child("left") ); }
1751
+ XLLine XLBorder::right() const { return XLLine(m_borderNode->child("right") ); }
1752
+ XLLine XLBorder::top() const { return XLLine(m_borderNode->child("top") ); }
1753
+ XLLine XLBorder::bottom() const { return XLLine(m_borderNode->child("bottom") ); }
1754
+ XLLine XLBorder::diagonal() const { return XLLine(m_borderNode->child("diagonal") ); }
1755
+ XLLine XLBorder::vertical() const { return XLLine(m_borderNode->child("vertical") ); }
1756
+ XLLine XLBorder::horizontal() const { return XLLine(m_borderNode->child("horizontal")); }
1757
+
1758
+ /**
1759
+ * @details Setter functions
1760
+ */
1761
+ bool XLBorder::setDiagonalUp (bool set) { return appendAndSetAttribute(*m_borderNode, "diagonalUp", (set ? "true" : "false")).empty() == false; }
1762
+ bool XLBorder::setDiagonalDown(bool set) { return appendAndSetAttribute(*m_borderNode, "diagonalDown", (set ? "true" : "false")).empty() == false; }
1763
+ bool XLBorder::setOutline (bool set) { return appendAndSetAttribute(*m_borderNode, "outline", (set ? "true" : "false")).empty() == false; }
1764
+ bool XLBorder::setLine(XLLineType lineType, XLLineStyle lineStyle, XLColor lineColor, double lineTint)
1765
+ {
1766
+ XMLNode lineNode = appendAndGetNode(*m_borderNode, XLLineTypeToString(lineType), m_nodeOrder); // generate line node if not present
1767
+ // 2024-12-19: non-existing lines are added using an ordered insert to address issue #304
1768
+ bool success = (lineNode.empty() == false);
1769
+ if (success) success = (appendAndSetAttribute(lineNode, "style", XLLineStyleToString(lineStyle)).empty() == false); // set style attribute
1770
+ XMLNode colorNode{}; // empty node
1771
+ if (success) colorNode = appendAndGetNode(lineNode, "color"); // generate color node if not present
1772
+ XLDataBarColor colorObject{colorNode};
1773
+ success = (colorNode.empty() == false);
1774
+ if (success) success = colorObject.setRgb(lineColor);
1775
+ if (success) success = colorObject.setTint(lineTint);
1776
+ return success;
1777
+ }
1778
+ bool XLBorder::setLeft (XLLineStyle lineStyle, XLColor lineColor, double lineTint) { return setLine(XLLineLeft, lineStyle, lineColor, lineTint); }
1779
+ bool XLBorder::setRight (XLLineStyle lineStyle, XLColor lineColor, double lineTint) { return setLine(XLLineRight, lineStyle, lineColor, lineTint); }
1780
+ bool XLBorder::setTop (XLLineStyle lineStyle, XLColor lineColor, double lineTint) { return setLine(XLLineTop, lineStyle, lineColor, lineTint); }
1781
+ bool XLBorder::setBottom (XLLineStyle lineStyle, XLColor lineColor, double lineTint) { return setLine(XLLineBottom, lineStyle, lineColor, lineTint); }
1782
+ bool XLBorder::setDiagonal (XLLineStyle lineStyle, XLColor lineColor, double lineTint) { return setLine(XLLineDiagonal, lineStyle, lineColor, lineTint); }
1783
+ bool XLBorder::setVertical (XLLineStyle lineStyle, XLColor lineColor, double lineTint) { return setLine(XLLineVertical, lineStyle, lineColor, lineTint); }
1784
+ bool XLBorder::setHorizontal(XLLineStyle lineStyle, XLColor lineColor, double lineTint) { return setLine(XLLineHorizontal, lineStyle, lineColor, lineTint); }
1785
+
1786
+
1787
+ /**
1788
+ * @details assemble a string summary about the fill
1789
+ */
1790
+ std::string XLBorder::summary() const
1791
+ {
1792
+ using namespace std::literals::string_literals;
1793
+ std::string lineInfo{};
1794
+ lineInfo += ", left: "s + left().summary() + ", right: " + right().summary()
1795
+ + ", top: "s + top().summary() + ", bottom: " + bottom().summary()
1796
+ + ", diagonal: "s + diagonal().summary()
1797
+ + ", vertical: "s + vertical().summary()
1798
+ + ", horizontal: "s + horizontal().summary();
1799
+ return "diagonalUp: "s + (diagonalUp() ? "true"s : "false"s)
1800
+ + ", diagonalDown: "s + (diagonalDown() ? "true"s : "false"s)
1801
+ + ", outline: "s + (outline() ? "true"s : "false"s)
1802
+ + lineInfo;
1803
+ }
1804
+
1805
+
1806
+ // ===== XLBorders, parent of XLBorder
1807
+
1808
+ /**
1809
+ * @details Constructor. Initializes an empty XLBorders object
1810
+ */
1811
+ XLBorders::XLBorders() : m_bordersNode(std::make_unique<XMLNode>()) {}
1812
+
1813
+ /**
1814
+ * @details Constructor. Initializes the member variables for the new XLBorders object.
1815
+ */
1816
+ XLBorders::XLBorders(const XMLNode& borders)
1817
+ : m_bordersNode(std::make_unique<XMLNode>(borders))
1818
+ {
1819
+ // initialize XLBorders entries and m_borders here
1820
+ XMLNode node = borders.first_child_of_type(pugi::node_element);
1821
+ while (not node.empty()) {
1822
+ std::string nodeName = node.name();
1823
+ if (nodeName == "border")
1824
+ m_borders.push_back(XLBorder(node));
1825
+ else
1826
+ std::cerr << "WARNING: XLBorders constructor: unknown subnode " << nodeName << std::endl;
1827
+ node = node.next_sibling_of_type(pugi::node_element);
1828
+ }
1829
+ }
1830
+
1831
+ /**
1832
+ * @details Copy constructor
1833
+ */
1834
+ XLBorders::XLBorders(const XLBorders& other)
1835
+ : m_bordersNode(std::make_unique<XMLNode>(*other.m_bordersNode)),
1836
+ m_borders(other.m_borders)
1837
+ {}
1838
+
1839
+ /**
1840
+ * @details Move constructor
1841
+ */
1842
+ XLBorders::XLBorders(XLBorders&& other)
1843
+ : m_bordersNode(std::move(other.m_bordersNode)),
1844
+ m_borders(std::move(other.m_borders))
1845
+ {}
1846
+
1847
+ /**
1848
+ * @details
1849
+ */
1850
+ XLBorders::~XLBorders()
1851
+ {
1852
+ m_borders.clear(); // delete vector with all children
1853
+ }
1854
+
1855
+ /**
1856
+ * @details Copy assignment operator
1857
+ */
1858
+ XLBorders& XLBorders::operator=(const XLBorders& other)
1859
+ {
1860
+ if (&other != this) {
1861
+ *m_bordersNode = *other.m_bordersNode;
1862
+ m_borders.clear();
1863
+ m_borders = other.m_borders;
1864
+ }
1865
+ return *this;
1866
+ }
1867
+
1868
+ /**
1869
+ * @details Move assignment operator
1870
+ */
1871
+ XLBorders& XLBorders::operator=(XLBorders&& other) noexcept = default;
1872
+
1873
+ /**
1874
+ * @details Returns the amount of border descriptions held by the class
1875
+ */
1876
+ size_t XLBorders::count() const { return m_borders.size(); }
1877
+
1878
+ /**
1879
+ * @details fetch XLBorder from m_borders by index
1880
+ */
1881
+ XLBorder XLBorders::borderByIndex(XLStyleIndex index) const
1882
+ {
1883
+ if (index >= m_borders.size()) {
1884
+ using namespace std::literals::string_literals;
1885
+ throw XLException("XLBorders::"s + __func__ + ": attempted to access index "s + std::to_string(index) + " with count "s + std::to_string(m_borders.size()));
1886
+ }
1887
+ return m_borders.at(index);
1888
+ }
1889
+
1890
+ /**
1891
+ * @details append a new XLBorder to m_borders and m_bordersNode, based on copyFrom
1892
+ */
1893
+ XLStyleIndex XLBorders::create(XLBorder copyFrom, std::string styleEntriesPrefix)
1894
+ {
1895
+ XLStyleIndex index = count(); // index for the border to be created
1896
+ XMLNode newNode{}; // scope declaration
1897
+
1898
+ // ===== Append new node prior to final whitespaces, if any
1899
+ XMLNode lastStyle = m_bordersNode->last_child_of_type(pugi::node_element);
1900
+ if (lastStyle.empty()) newNode = m_bordersNode->prepend_child("border");
1901
+ else newNode = m_bordersNode->insert_child_after("border", lastStyle);
1902
+ if (newNode.empty()) {
1903
+ using namespace std::literals::string_literals;
1904
+ throw XLException("XLBorders::"s + __func__ + ": failed to append a new border node"s);
1905
+ }
1906
+ if (styleEntriesPrefix.length() > 0) // if a whitespace prefix is configured
1907
+ m_bordersNode->insert_child_before(pugi::node_pcdata, newNode).set_value(styleEntriesPrefix.c_str()); // prefix the new node with styleEntriesPrefix
1908
+
1909
+ XLBorder newBorder(newNode);
1910
+ if (copyFrom.m_borderNode->empty()) { // if no template is given
1911
+ // ===== Create a border with default values
1912
+ // TODO: implement border defaults
1913
+ // newBorder.setProperty(defaultValue);
1914
+ // ...
1915
+ }
1916
+ else
1917
+ copyXMLNode(newNode, *copyFrom.m_borderNode); // will use copyFrom as template, does nothing if copyFrom is empty
1918
+
1919
+ m_borders.push_back(newBorder);
1920
+ appendAndSetAttribute(*m_bordersNode, "count", std::to_string(m_borders.size())); // update array count in XML
1921
+ return index;
1922
+ }
1923
+
1924
+
1925
+ /**
1926
+ * @details Constructor. Initializes an empty XLAlignment object
1927
+ */
1928
+ XLAlignment::XLAlignment() : m_alignmentNode(std::make_unique<XMLNode>()) {}
1929
+
1930
+ /**
1931
+ * @details Constructor. Initializes the member variables for the new XLAlignment object.
1932
+ */
1933
+ XLAlignment::XLAlignment(const XMLNode& node) : m_alignmentNode(std::make_unique<XMLNode>(node)) {}
1934
+
1935
+ /**
1936
+ * @details Copy constructor
1937
+ */
1938
+ XLAlignment::XLAlignment(const XLAlignment& other)
1939
+ : m_alignmentNode(std::make_unique<XMLNode>(*other.m_alignmentNode))
1940
+ {}
1941
+
1942
+ /**
1943
+ * @details Move constructor
1944
+ */
1945
+ XLAlignment::XLAlignment(XLAlignment&& other) noexcept = default;
1946
+
1947
+ /**
1948
+ * @details
1949
+ */
1950
+ XLAlignment::~XLAlignment() = default;
1951
+
1952
+ /**
1953
+ * @details Copy assignment operator.
1954
+ */
1955
+ XLAlignment& XLAlignment::operator=(const XLAlignment& other)
1956
+ {
1957
+ if (&other != this) *m_alignmentNode = *other.m_alignmentNode;
1958
+ return *this;
1959
+ }
1960
+
1961
+ /**
1962
+ * @details Move assignment operator.
1963
+ */
1964
+ XLAlignment& XLAlignment::operator=(XLAlignment&& other) noexcept = default;
1965
+
1966
+ /**
1967
+ * @details Returns the horizontal alignment style
1968
+ */
1969
+ XLAlignmentStyle XLAlignment::horizontal() const { return XLAlignmentStyleFromString(m_alignmentNode->attribute("horizontal").value()); }
1970
+
1971
+ /**
1972
+ * @details Returns the vertical alignment style
1973
+ */
1974
+ XLAlignmentStyle XLAlignment::vertical() const { return XLAlignmentStyleFromString(m_alignmentNode->attribute("vertical").value()); }
1975
+
1976
+ /**
1977
+ * @details Returns the text rotation
1978
+ */
1979
+ uint16_t XLAlignment::textRotation() const { return m_alignmentNode->attribute("textRotation").as_uint(); }
1980
+
1981
+ /**
1982
+ * @details check if text wrapping is enabled
1983
+ */
1984
+ bool XLAlignment::wrapText() const { return m_alignmentNode->attribute("wrapText").as_bool(); }
1985
+
1986
+ /**
1987
+ * @details Returns the indent setting
1988
+ */
1989
+ uint32_t XLAlignment::indent() const { return m_alignmentNode->attribute("indent").as_uint(); }
1990
+
1991
+ /**
1992
+ * @details Returns the relative indent setting
1993
+ */
1994
+ int32_t XLAlignment::relativeIndent() const { return m_alignmentNode->attribute("relativeIndent").as_int(); }
1995
+
1996
+ /**
1997
+ * @details check if justification of last line is enabled
1998
+ */
1999
+ bool XLAlignment::justifyLastLine() const { return m_alignmentNode->attribute("justifyLastLine").as_bool(); }
2000
+
2001
+ /**
2002
+ * @details check if shrink to fit is enabled
2003
+ */
2004
+ bool XLAlignment::shrinkToFit() const { return m_alignmentNode->attribute("shrinkToFit").as_bool(); }
2005
+
2006
+ /**
2007
+ * @details Returns the reading order setting
2008
+ */
2009
+ uint32_t XLAlignment::readingOrder() const { return m_alignmentNode->attribute("readingOrder").as_uint(); }
2010
+
2011
+ /**
2012
+ * @details Setter functions
2013
+ */
2014
+ bool XLAlignment::setHorizontal (XLAlignmentStyle newStyle) { return appendAndSetAttribute(*m_alignmentNode, "horizontal", XLAlignmentStyleToString(newStyle).c_str()).empty() == false; }
2015
+ bool XLAlignment::setVertical (XLAlignmentStyle newStyle) { return appendAndSetAttribute(*m_alignmentNode, "vertical", XLAlignmentStyleToString(newStyle).c_str()).empty() == false; }
2016
+ bool XLAlignment::setTextRotation (uint16_t newRotation) { return appendAndSetAttribute(*m_alignmentNode, "textRotation", std::to_string(newRotation) ).empty() == false; }
2017
+ bool XLAlignment::setWrapText (bool set) { return appendAndSetAttribute(*m_alignmentNode, "wrapText", (set ? "true" : "false") ).empty() == false; }
2018
+ bool XLAlignment::setIndent (uint32_t newIndent) { return appendAndSetAttribute(*m_alignmentNode, "indent", std::to_string(newIndent) ).empty() == false; }
2019
+ bool XLAlignment::setRelativeIndent (int32_t newRelativeIndent) { return appendAndSetAttribute(*m_alignmentNode, "relativeIndent", std::to_string(newRelativeIndent) ).empty() == false; }
2020
+ bool XLAlignment::setJustifyLastLine(bool set) { return appendAndSetAttribute(*m_alignmentNode, "justifyLastLine", (set ? "true" : "false") ).empty() == false; }
2021
+ bool XLAlignment::setShrinkToFit (bool set) { return appendAndSetAttribute(*m_alignmentNode, "shrinkToFit", (set ? "true" : "false") ).empty() == false; }
2022
+ bool XLAlignment::setReadingOrder (uint32_t newReadingOrder) { return appendAndSetAttribute(*m_alignmentNode, "readingOrder", std::to_string(newReadingOrder) ).empty() == false; }
2023
+
2024
+ /**
2025
+ * @details assemble a string summary about the fill
2026
+ */
2027
+ std::string XLAlignment::summary() const
2028
+ {
2029
+ using namespace std::literals::string_literals;
2030
+ return "alignment horizontal="s + XLAlignmentStyleToString(horizontal()) + ", vertical="s + XLAlignmentStyleToString(vertical())
2031
+ + ", textRotation="s + std::to_string(textRotation())
2032
+ + ", wrapText="s + (wrapText() ? "true" : "false")
2033
+ + ", indent="s + std::to_string(indent())
2034
+ + ", relativeIndent="s + std::to_string(relativeIndent())
2035
+ + ", justifyLastLine="s + (justifyLastLine() ? "true" : "false")
2036
+ + ", shrinkToFit="s + (shrinkToFit() ? "true" : "false")
2037
+ + ", readingOrder="s + XLReadingOrderToString(readingOrder());
2038
+ }
2039
+
2040
+
2041
+ /**
2042
+ * @details Constructor. Initializes an empty XLCellFormat object
2043
+ */
2044
+ XLCellFormat::XLCellFormat() : m_cellFormatNode(std::make_unique<XMLNode>()) {}
2045
+
2046
+ /**
2047
+ * @details Constructor. Initializes the member variables for the new XLCellFormat object.
2048
+ */
2049
+ XLCellFormat::XLCellFormat(const XMLNode& node, bool permitXfId)
2050
+ : m_cellFormatNode(std::make_unique<XMLNode>(node)),
2051
+ m_permitXfId(permitXfId)
2052
+ {}
2053
+
2054
+ /**
2055
+ * @details Copy constructor
2056
+ */
2057
+ XLCellFormat::XLCellFormat(const XLCellFormat& other)
2058
+ : m_cellFormatNode(std::make_unique<XMLNode>(*other.m_cellFormatNode)),
2059
+ m_permitXfId(other.m_permitXfId)
2060
+ {}
2061
+
2062
+ /**
2063
+ * @details Move constructor
2064
+ */
2065
+ XLCellFormat::XLCellFormat(XLCellFormat&& other) noexcept = default;
2066
+
2067
+ /**
2068
+ * @details
2069
+ */
2070
+ XLCellFormat::~XLCellFormat() = default;
2071
+
2072
+ /*
2073
+ * @details Copy assignment operator
2074
+ */
2075
+ XLCellFormat& XLCellFormat::operator=(const XLCellFormat& other)
2076
+ {
2077
+ if (&other != this) {
2078
+ *m_cellFormatNode = *other.m_cellFormatNode;
2079
+ m_permitXfId = other.m_permitXfId;
2080
+ }
2081
+ return *this;
2082
+ }
2083
+
2084
+ /**
2085
+ * @details Move assignment operator
2086
+ */
2087
+ XLCellFormat& XLCellFormat::operator=(XLCellFormat&& other) noexcept = default;
2088
+
2089
+ /**
2090
+ * @details determines the numberFormatId
2091
+ * @note returns XLInvalidUInt32 if attribute is not defined / set / empty
2092
+ */
2093
+ uint32_t XLCellFormat::numberFormatId() const { return m_cellFormatNode->attribute("numFmtId").as_uint(XLInvalidUInt32); }
2094
+
2095
+ /**
2096
+ * @details determines the fontIndex
2097
+ * @note returns XLInvalidStyleIndex if attribute is not defined / set / empty
2098
+ */
2099
+ XLStyleIndex XLCellFormat::fontIndex() const { return m_cellFormatNode->attribute("fontId").as_uint(XLInvalidStyleIndex); }
2100
+
2101
+ /**
2102
+ * @details determines the fillIndex
2103
+ * @note returns XLInvalidStyleIndex if attribute is not defined / set / empty
2104
+ */
2105
+ XLStyleIndex XLCellFormat::fillIndex() const { return m_cellFormatNode->attribute("fillId").as_uint(XLInvalidStyleIndex); }
2106
+
2107
+ /**
2108
+ * @details determines the borderIndex
2109
+ * @note returns XLInvalidStyleIndex if attribute is not defined / set / empty
2110
+ */
2111
+ XLStyleIndex XLCellFormat::borderIndex() const { return m_cellFormatNode->attribute("borderId").as_uint(XLInvalidStyleIndex); }
2112
+
2113
+ /**
2114
+ * @details Returns the xfId value
2115
+ */
2116
+ XLStyleIndex XLCellFormat::xfId() const
2117
+ {
2118
+ if (m_permitXfId) return m_cellFormatNode->attribute("xfId").as_uint(XLInvalidStyleIndex);
2119
+ throw XLException("XLCellFormat::xfId not permitted when m_permitXfId is false");
2120
+ }
2121
+
2122
+ /**
2123
+ * @details determine the applyNumberFormat,applyFont,applyFill,applyBorder,applyAlignment,applyProtection status
2124
+ */
2125
+ bool XLCellFormat::applyNumberFormat() const { return m_cellFormatNode->attribute("applyNumberFormat").as_bool(); }
2126
+ bool XLCellFormat::applyFont() const { return m_cellFormatNode->attribute("applyFont").as_bool(); }
2127
+ bool XLCellFormat::applyFill() const { return m_cellFormatNode->attribute("applyFill").as_bool(); }
2128
+ bool XLCellFormat::applyBorder() const { return m_cellFormatNode->attribute("applyBorder").as_bool(); }
2129
+ bool XLCellFormat::applyAlignment() const { return m_cellFormatNode->attribute("applyAlignment").as_bool(); }
2130
+ bool XLCellFormat::applyProtection() const { return m_cellFormatNode->attribute("applyProtection").as_bool(); }
2131
+
2132
+ /**
2133
+ * @details determine the quotePrefix, pivotButton status
2134
+ */
2135
+ bool XLCellFormat::quotePrefix() const { return m_cellFormatNode->attribute("quotePrefix").as_bool(); }
2136
+ bool XLCellFormat::pivotButton() const { return m_cellFormatNode->attribute("pivotButton").as_bool(); }
2137
+
2138
+ /**
2139
+ * @details determine the protection:locked,protection:hidden status
2140
+ */
2141
+ bool XLCellFormat::locked() const { return m_cellFormatNode->child("protection").attribute("locked").as_bool(); }
2142
+ bool XLCellFormat::hidden() const { return m_cellFormatNode->child("protection").attribute("hidden").as_bool(); }
2143
+
2144
+ /**
2145
+ * @details fetch alignment object
2146
+ */
2147
+ XLAlignment XLCellFormat::alignment(bool createIfMissing) const
2148
+ {
2149
+ XMLNode nodeAlignment = m_cellFormatNode->child("alignment");
2150
+ if (nodeAlignment.empty() && createIfMissing)
2151
+ nodeAlignment = appendAndGetNode(*m_cellFormatNode, "alignment", m_nodeOrder); // 2024-12-19: ordered insert to address issue #305
2152
+ return XLAlignment(nodeAlignment);
2153
+ }
2154
+
2155
+ /**
2156
+ * @details Setter functions
2157
+ */
2158
+ bool XLCellFormat::setNumberFormatId (uint32_t newNumFmtId) { return appendAndSetAttribute(*m_cellFormatNode, "numFmtId", std::to_string(newNumFmtId )).empty() == false; }
2159
+ bool XLCellFormat::setFontIndex (XLStyleIndex newXfIndex) { return appendAndSetAttribute(*m_cellFormatNode, "fontId", std::to_string(newXfIndex )).empty() == false; }
2160
+ bool XLCellFormat::setFillIndex (XLStyleIndex newFillIndex) { return appendAndSetAttribute(*m_cellFormatNode, "fillId", std::to_string(newFillIndex )).empty() == false; }
2161
+ bool XLCellFormat::setBorderIndex (XLStyleIndex newBorderIndex) { return appendAndSetAttribute(*m_cellFormatNode, "borderId", std::to_string(newBorderIndex)).empty() == false; }
2162
+ bool XLCellFormat::setXfId (XLStyleIndex newXfId)
2163
+ {
2164
+ if (m_permitXfId) return appendAndSetAttribute(*m_cellFormatNode, "xfId", std::to_string(newXfId )).empty() == false;
2165
+ throw XLException("XLCellFormat::setXfId not permitted when m_permitXfId is false");
2166
+ }
2167
+ bool XLCellFormat::setApplyNumberFormat(bool set) { return appendAndSetAttribute (*m_cellFormatNode, "applyNumberFormat", (set ? "true" : "false")).empty() == false; }
2168
+ bool XLCellFormat::setApplyFont (bool set) { return appendAndSetAttribute (*m_cellFormatNode, "applyFont", (set ? "true" : "false")).empty() == false; }
2169
+ bool XLCellFormat::setApplyFill (bool set) { return appendAndSetAttribute (*m_cellFormatNode, "applyFill", (set ? "true" : "false")).empty() == false; }
2170
+ bool XLCellFormat::setApplyBorder (bool set) { return appendAndSetAttribute (*m_cellFormatNode, "applyBorder", (set ? "true" : "false")).empty() == false; }
2171
+ bool XLCellFormat::setApplyAlignment (bool set) { return appendAndSetAttribute (*m_cellFormatNode, "applyAlignment", (set ? "true" : "false")).empty() == false; }
2172
+ bool XLCellFormat::setApplyProtection (bool set) { return appendAndSetAttribute (*m_cellFormatNode, "applyProtection", (set ? "true" : "false")).empty() == false; }
2173
+ bool XLCellFormat::setQuotePrefix (bool set) { return appendAndSetAttribute (*m_cellFormatNode, "quotePrefix", (set ? "true" : "false")).empty() == false; }
2174
+ bool XLCellFormat::setPivotButton (bool set) { return appendAndSetAttribute (*m_cellFormatNode, "pivotButton", (set ? "true" : "false")).empty() == false; }
2175
+ bool XLCellFormat::setLocked(bool set)
2176
+ {
2177
+ return appendAndSetNodeAttribute(*m_cellFormatNode, "protection", "locked", (set ? "true" : "false"),
2178
+ /**/ XLKeepAttributes, m_nodeOrder).empty() == false; // 2024-12-19: ordered insert to address issue #305
2179
+ }
2180
+ bool XLCellFormat::setHidden(bool set)
2181
+ {
2182
+ return appendAndSetNodeAttribute(*m_cellFormatNode, "protection", "hidden", (set ? "true" : "false"),
2183
+ /**/ XLKeepAttributes, m_nodeOrder).empty() == false; // 2024-12-19: ordered insert to address issue #305
2184
+ }
2185
+
2186
+ /**
2187
+ * @details Unsupported setter function
2188
+ */
2189
+ bool XLCellFormat::setExtLst(XLUnsupportedElement const& newExtLst) { OpenXLSX::ignore(newExtLst); return false; }
2190
+
2191
+
2192
+ /**
2193
+ * @details assemble a string summary about the cell format
2194
+ */
2195
+ std::string XLCellFormat::summary() const
2196
+ {
2197
+ using namespace std::literals::string_literals;
2198
+ return "numberFormatId="s + std::to_string(numberFormatId())
2199
+ + ", fontIndex="s + std::to_string(fontIndex())
2200
+ + ", fillIndex="s + std::to_string(fillIndex())
2201
+ + ", borderIndex="s + std::to_string(borderIndex())
2202
+ + ( m_permitXfId ? (", xfId: "s + std::to_string(xfId())) : ""s)
2203
+ + ", applyNumberFormat: "s + (applyNumberFormat() ? "true"s : "false"s)
2204
+ + ", applyFont: "s + (applyFont() ? "true"s : "false"s)
2205
+ + ", applyFill: "s + (applyFill() ? "true"s : "false"s)
2206
+ + ", applyBorder: "s + (applyBorder() ? "true"s : "false"s)
2207
+ + ", applyAlignment: "s + (applyAlignment() ? "true"s : "false"s)
2208
+ + ", applyProtection: "s + (applyProtection() ? "true"s : "false"s)
2209
+ + ", quotePrefix: "s + (quotePrefix() ? "true"s : "false"s)
2210
+ + ", pivotButton: "s + (pivotButton() ? "true"s : "false"s)
2211
+ + ", locked: "s + (locked() ? "true"s : "false"s)
2212
+ + ", hidden: "s + (hidden() ? "true"s : "false"s)
2213
+ + ", " + alignment().summary();
2214
+ }
2215
+
2216
+
2217
+ // ===== XLCellFormats, one parent of XLCellFormat (the other being XLCellFormats)
2218
+
2219
+ /**
2220
+ * @details Constructor. Initializes an empty XLCellFormats object
2221
+ */
2222
+ XLCellFormats::XLCellFormats() : m_cellFormatsNode(std::make_unique<XMLNode>()) {}
2223
+
2224
+ /**
2225
+ * @details Constructor. Initializes the member variables for the new XLCellFormats object.
2226
+ */
2227
+ XLCellFormats::XLCellFormats(const XMLNode& cellStyleFormats, bool permitXfId)
2228
+ : m_cellFormatsNode(std::make_unique<XMLNode>(cellStyleFormats)),
2229
+ m_permitXfId(permitXfId)
2230
+ {
2231
+ // initialize XLCellFormats entries and m_cellFormats here
2232
+ XMLNode node = cellStyleFormats.first_child_of_type(pugi::node_element);
2233
+ while (not node.empty()) {
2234
+ std::string nodeName = node.name();
2235
+ if (nodeName == "xf")
2236
+ m_cellFormats.push_back(XLCellFormat(node, m_permitXfId));
2237
+ else
2238
+ std::cerr << "WARNING: XLCellFormats constructor: unknown subnode " << nodeName << std::endl;
2239
+ node = node.next_sibling_of_type(pugi::node_element);
2240
+ }
2241
+ }
2242
+
2243
+ /**
2244
+ * @details Copy constructor
2245
+ */
2246
+ XLCellFormats::XLCellFormats(const XLCellFormats& other)
2247
+ : m_cellFormatsNode(std::make_unique<XMLNode>(*other.m_cellFormatsNode)),
2248
+ m_cellFormats(other.m_cellFormats),
2249
+ m_permitXfId(other.m_permitXfId)
2250
+ {}
2251
+
2252
+ /**
2253
+ * @details Move constructor
2254
+ */
2255
+ XLCellFormats::XLCellFormats(XLCellFormats&& other)
2256
+ : m_cellFormatsNode(std::move(other.m_cellFormatsNode)),
2257
+ m_cellFormats(std::move(other.m_cellFormats)),
2258
+ m_permitXfId(other.m_permitXfId)
2259
+ {}
2260
+
2261
+ /**
2262
+ * @details
2263
+ */
2264
+ XLCellFormats::~XLCellFormats()
2265
+ {
2266
+ m_cellFormats.clear(); // delete vector with all children
2267
+ }
2268
+
2269
+ /**
2270
+ * @details Copy assignment operator
2271
+ */
2272
+ XLCellFormats& XLCellFormats::operator=(const XLCellFormats& other)
2273
+ {
2274
+ if (&other != this) {
2275
+ *m_cellFormatsNode = *other.m_cellFormatsNode;
2276
+ m_cellFormats.clear();
2277
+ m_cellFormats = other.m_cellFormats;
2278
+ m_permitXfId = other.m_permitXfId;
2279
+ }
2280
+ return *this;
2281
+ }
2282
+
2283
+ /**
2284
+ * @details Move assignment operator
2285
+ */
2286
+ XLCellFormats& XLCellFormats::operator=(XLCellFormats&& other) noexcept = default;
2287
+
2288
+ /**
2289
+ * @details Returns the amount of cell format descriptions held by the class
2290
+ */
2291
+ size_t XLCellFormats::count() const { return m_cellFormats.size(); }
2292
+
2293
+ /**
2294
+ * @details fetch XLCellFormat from m_cellFormats by index
2295
+ */
2296
+ XLCellFormat XLCellFormats::cellFormatByIndex(XLStyleIndex index) const
2297
+ {
2298
+ if (index >= m_cellFormats.size()) {
2299
+ using namespace std::literals::string_literals;
2300
+ throw XLException("XLCellFormats::"s + __func__ + ": attempted to access index "s + std::to_string(index)
2301
+ + " with count "s + std::to_string(m_cellFormats.size()));
2302
+ }
2303
+ return m_cellFormats.at(index);
2304
+ }
2305
+
2306
+ /**
2307
+ * @details append a new XLCellFormat to m_cellFormats and m_cellFormatsNode, based on copyFrom
2308
+ */
2309
+ XLStyleIndex XLCellFormats::create(XLCellFormat copyFrom, std::string styleEntriesPrefix)
2310
+ {
2311
+ XLStyleIndex index = count(); // index for the cell format to be created
2312
+ XMLNode newNode{}; // scope declaration
2313
+
2314
+ // ===== Append new node prior to final whitespaces, if any
2315
+ XMLNode lastStyle = m_cellFormatsNode->last_child_of_type(pugi::node_element);
2316
+ if (lastStyle.empty()) newNode = m_cellFormatsNode->prepend_child("xf");
2317
+ else newNode = m_cellFormatsNode->insert_child_after("xf", lastStyle);
2318
+ if (newNode.empty()) {
2319
+ using namespace std::literals::string_literals;
2320
+ throw XLException("XLCellFormats::"s + __func__ + ": failed to append a new xf node"s);
2321
+ }
2322
+ if (styleEntriesPrefix.length() > 0) // if a whitespace prefix is configured
2323
+ m_cellFormatsNode->insert_child_before(pugi::node_pcdata, newNode).set_value(styleEntriesPrefix.c_str()); // prefix the new node with styleEntriesPrefix
2324
+
2325
+ XLCellFormat newCellFormat(newNode, m_permitXfId);
2326
+ if (copyFrom.m_cellFormatNode->empty()) { // if no template is given
2327
+ // ===== Create a cell format with default values
2328
+ // default index 0 for other style elements should protect from exceptions
2329
+ newCellFormat.setNumberFormatId (0);
2330
+ newCellFormat.setFontIndex (0);
2331
+ newCellFormat.setFillIndex (0);
2332
+ newCellFormat.setBorderIndex (0);
2333
+ newCellFormat.setXfId (0);
2334
+ newCellFormat.setApplyNumberFormat(false);
2335
+ newCellFormat.setApplyFont (false);
2336
+ newCellFormat.setApplyFill (false);
2337
+ newCellFormat.setApplyBorder (false);
2338
+ newCellFormat.setApplyAlignment (false);
2339
+ newCellFormat.setApplyProtection (false);
2340
+ newCellFormat.setQuotePrefix (false);
2341
+ newCellFormat.setPivotButton (false);
2342
+ newCellFormat.setLocked (false);
2343
+ newCellFormat.setHidden (false);
2344
+ // Unsupported setter
2345
+ newCellFormat.setExtLst (XLUnsupportedElement {});
2346
+ }
2347
+ else
2348
+ copyXMLNode(newNode, *copyFrom.m_cellFormatNode); // will use copyFrom as template, does nothing if copyFrom is empty
2349
+
2350
+ m_cellFormats.push_back(newCellFormat);
2351
+ appendAndSetAttribute(*m_cellFormatsNode, "count", std::to_string(m_cellFormats.size())); // update array count in XML
2352
+ return index;
2353
+ }
2354
+
2355
+
2356
+ /**
2357
+ * @details Constructor. Initializes an empty XLCellStyle object
2358
+ */
2359
+ XLCellStyle::XLCellStyle() : m_cellStyleNode(std::make_unique<XMLNode>()) {}
2360
+
2361
+ /**
2362
+ * @details Constructor. Initializes the member variables for the new XLCellStyle object.
2363
+ */
2364
+ XLCellStyle::XLCellStyle(const XMLNode& node) : m_cellStyleNode(std::make_unique<XMLNode>(node)) {}
2365
+
2366
+ /**
2367
+ * @details Copy constructor
2368
+ */
2369
+ XLCellStyle::XLCellStyle(const XLCellStyle& other)
2370
+ : m_cellStyleNode(std::make_unique<XMLNode>(*other.m_cellStyleNode))
2371
+ {}
2372
+
2373
+ /**
2374
+ * @details Move constructor
2375
+ */
2376
+ XLCellStyle::XLCellStyle(XLCellStyle&& other) noexcept = default;
2377
+
2378
+ /**
2379
+ * @details
2380
+ */
2381
+ XLCellStyle::~XLCellStyle() = default;
2382
+
2383
+ /**
2384
+ * @details Copy assignment operator
2385
+ */
2386
+ XLCellStyle& XLCellStyle::operator=(const XLCellStyle& other)
2387
+ {
2388
+ if (&other != this) *m_cellStyleNode = *other.m_cellStyleNode;
2389
+ return *this;
2390
+ }
2391
+
2392
+ /**
2393
+ * @details Move assignment operator
2394
+ */
2395
+ XLCellStyle& XLCellStyle::operator=(XLCellStyle&& other) noexcept = default;
2396
+
2397
+ /**
2398
+ * @details Returns the style empty status
2399
+ */
2400
+ bool XLCellStyle::empty() const { return m_cellStyleNode->empty(); }
2401
+
2402
+ /**
2403
+ * @details Getter functions
2404
+ */
2405
+ std::string XLCellStyle::name () const { return m_cellStyleNode->attribute("name" ).value(); }
2406
+ XLStyleIndex XLCellStyle::xfId () const { return m_cellStyleNode->attribute("xfId" ).as_uint(XLInvalidStyleIndex); }
2407
+ uint32_t XLCellStyle::builtinId () const { return m_cellStyleNode->attribute("builtinId" ).as_uint(XLInvalidUInt32); }
2408
+ uint32_t XLCellStyle::outlineStyle () const { return m_cellStyleNode->attribute("iLevel" ).as_uint(XLInvalidUInt32); }
2409
+ bool XLCellStyle::hidden () const { return m_cellStyleNode->attribute("hidden" ).as_bool(); }
2410
+ bool XLCellStyle::customBuiltin() const { return m_cellStyleNode->attribute("customBuiltin").as_bool(); }
2411
+
2412
+ /**
2413
+ * @details Setter functions
2414
+ */
2415
+ bool XLCellStyle::setName (std::string newName) { return appendAndSetAttribute(*m_cellStyleNode, "name", newName).empty() == false; }
2416
+ bool XLCellStyle::setXfId (XLStyleIndex newXfId) { return appendAndSetAttribute(*m_cellStyleNode, "xfId", std::to_string(newXfId)).empty() == false; }
2417
+ bool XLCellStyle::setBuiltinId (uint32_t newBuiltinId) { return appendAndSetAttribute(*m_cellStyleNode, "builtinId", std::to_string(newBuiltinId)).empty() == false; }
2418
+ bool XLCellStyle::setOutlineStyle (uint32_t newOutlineStyle) { return appendAndSetAttribute(*m_cellStyleNode, "iLevel", std::to_string(newOutlineStyle)).empty() == false; }
2419
+ bool XLCellStyle::setHidden (bool set) { return appendAndSetAttribute(*m_cellStyleNode, "hidden", (set ? "true" : "false")).empty() == false; }
2420
+ bool XLCellStyle::setCustomBuiltin(bool set) { return appendAndSetAttribute(*m_cellStyleNode, "customBuiltin", (set ? "true" : "false")).empty() == false; }
2421
+
2422
+ /**
2423
+ * @details Unsupported setter function
2424
+ */
2425
+ bool XLCellStyle::setExtLst(XLUnsupportedElement const& newExtLst) { OpenXLSX::ignore(newExtLst); return false; }
2426
+
2427
+ /**
2428
+ * @details assemble a string summary about the cell style
2429
+ */
2430
+ std::string XLCellStyle::summary() const
2431
+ {
2432
+ using namespace std::literals::string_literals;
2433
+ uint32_t iLevel = outlineStyle();
2434
+ return "name="s + name()
2435
+ + ", xfId="s + std::to_string(xfId())
2436
+ + ", builtinId="s + std::to_string(builtinId())
2437
+ + (iLevel != XLInvalidUInt32 ? ", iLevel="s + std::to_string(outlineStyle()) : ""s)
2438
+ + (hidden() ? ", hidden=true"s : ""s)
2439
+ + (customBuiltin() ? ", customBuiltin=true"s : ""s);
2440
+ }
2441
+
2442
+ // ===== XLCellStyles, parent of XLCellStyle
2443
+
2444
+ /**
2445
+ * @details Constructor. Initializes an empty XLCellStyles object
2446
+ */
2447
+ XLCellStyles::XLCellStyles() : m_cellStylesNode(std::make_unique<XMLNode>()) {}
2448
+
2449
+ /**
2450
+ * @details Constructor. Initializes the member variables for the new XLCellStyles object.
2451
+ */
2452
+ XLCellStyles::XLCellStyles(const XMLNode& cellStyles)
2453
+ : m_cellStylesNode(std::make_unique<XMLNode>(cellStyles))
2454
+ {
2455
+ // initialize XLCellStyles entries and m_cellStyles here
2456
+ XMLNode node = cellStyles.first_child_of_type(pugi::node_element);
2457
+ while (not node.empty()) {
2458
+ std::string nodeName = node.name();
2459
+ if (nodeName == "cellStyle")
2460
+ m_cellStyles.push_back(XLCellStyle(node));
2461
+ else
2462
+ std::cerr << "WARNING: XLCellStyles constructor: unknown subnode " << nodeName << std::endl;
2463
+ node = node.next_sibling_of_type(pugi::node_element);
2464
+ }
2465
+ }
2466
+
2467
+ /**
2468
+ * @details Copy constructor
2469
+ */
2470
+ XLCellStyles::XLCellStyles(const XLCellStyles& other)
2471
+ : m_cellStylesNode(std::make_unique<XMLNode>(*other.m_cellStylesNode)),
2472
+ m_cellStyles(other.m_cellStyles)
2473
+ {}
2474
+
2475
+ /**
2476
+ * @details Move constructor
2477
+ */
2478
+ XLCellStyles::XLCellStyles(XLCellStyles&& other)
2479
+ : m_cellStylesNode(std::move(other.m_cellStylesNode)),
2480
+ m_cellStyles(std::move(other.m_cellStyles))
2481
+ {}
2482
+
2483
+ /**
2484
+ * @details
2485
+ */
2486
+ XLCellStyles::~XLCellStyles()
2487
+ {
2488
+ m_cellStyles.clear(); // delete vector with all children
2489
+ }
2490
+
2491
+ /**
2492
+ * @details Copy assignment operator
2493
+ */
2494
+ XLCellStyles& XLCellStyles::operator=(const XLCellStyles& other)
2495
+ {
2496
+ if (&other != this) {
2497
+ *m_cellStylesNode = *other.m_cellStylesNode;
2498
+ m_cellStyles.clear();
2499
+ m_cellStyles = other.m_cellStyles;
2500
+ }
2501
+ return *this;
2502
+ }
2503
+
2504
+ /**
2505
+ * @details Move assignment operator
2506
+ */
2507
+ XLCellStyles& XLCellStyles::operator=(XLCellStyles&& other) noexcept = default;
2508
+
2509
+ /**
2510
+ * @details Returns the amount of numberFormats held by the class
2511
+ */
2512
+ size_t XLCellStyles::count() const { return m_cellStyles.size(); }
2513
+
2514
+ /**
2515
+ * @details fetch XLCellStyle from m_cellStyles by index
2516
+ */
2517
+ XLCellStyle XLCellStyles::cellStyleByIndex(XLStyleIndex index) const
2518
+ {
2519
+ if (index >= m_cellStyles.size()) {
2520
+ using namespace std::literals::string_literals;
2521
+ throw XLException("XLCellStyles::"s + __func__ + ": attempted to access index "s + std::to_string(index)
2522
+ + " with count "s + std::to_string(m_cellStyles.size()));
2523
+ }
2524
+ return m_cellStyles.at(index);
2525
+ }
2526
+
2527
+ /**
2528
+ * @details append a new XLCellStyle to m_cellStyles and m_cellStyleNode, based on copyFrom
2529
+ */
2530
+ XLStyleIndex XLCellStyles::create(XLCellStyle copyFrom, std::string styleEntriesPrefix)
2531
+ {
2532
+ XLStyleIndex index = count(); // index for the cell style to be created
2533
+ XMLNode newNode{}; // scope declaration
2534
+
2535
+ // ===== Append new node prior to final whitespaces, if any
2536
+ XMLNode lastStyle = m_cellStylesNode->last_child_of_type(pugi::node_element);
2537
+ if (lastStyle.empty()) newNode = m_cellStylesNode->prepend_child("cellStyle");
2538
+ else newNode = m_cellStylesNode->insert_child_after("cellStyle", lastStyle);
2539
+ if (newNode.empty()) {
2540
+ using namespace std::literals::string_literals;
2541
+ throw XLException("XLCellStyles::"s + __func__ + ": failed to append a new cellStyle node"s);
2542
+ }
2543
+ if (styleEntriesPrefix.length() > 0) // if a whitespace prefix is configured
2544
+ m_cellStylesNode->insert_child_before(pugi::node_pcdata, newNode).set_value(styleEntriesPrefix.c_str()); // prefix the new node with styleEntriesPrefix
2545
+
2546
+ XLCellStyle newCellStyle(newNode);
2547
+ if (copyFrom.m_cellStyleNode->empty()) { // if no template is given
2548
+ // ===== Create a cell style with default values
2549
+ // TODO: implement cell style defaults
2550
+ // newCellStyle.setProperty(defaultValue);
2551
+ // ...
2552
+ }
2553
+ else
2554
+ copyXMLNode(newNode, *copyFrom.m_cellStyleNode); // will use copyFrom as template, does nothing if copyFrom is empty
2555
+
2556
+ m_cellStyles.push_back(newCellStyle);
2557
+ appendAndSetAttribute(*m_cellStylesNode, "count", std::to_string(m_cellStyles.size())); // update array count in XML
2558
+ return index;
2559
+ }
2560
+
2561
+
2562
+ /**
2563
+ * @details Constructor. Initializes an empty XLDiffCellFormat object
2564
+ */
2565
+ XLDiffCellFormat::XLDiffCellFormat() : m_diffCellFormatNode(std::make_unique<XMLNode>()) {}
2566
+
2567
+ /**
2568
+ * @details Constructor. Initializes the member variables for the new XLDiffCellFormat object.
2569
+ */
2570
+ XLDiffCellFormat::XLDiffCellFormat(const XMLNode& node) : m_diffCellFormatNode(std::make_unique<XMLNode>(node)) {}
2571
+
2572
+ /**
2573
+ * @details Copy constructor
2574
+ */
2575
+ XLDiffCellFormat::XLDiffCellFormat(const XLDiffCellFormat& other)
2576
+ : m_diffCellFormatNode(std::make_unique<XMLNode>(*other.m_diffCellFormatNode))
2577
+ {}
2578
+
2579
+ /**
2580
+ * @details Move constructor
2581
+ */
2582
+ XLDiffCellFormat::XLDiffCellFormat(XLDiffCellFormat&& other) noexcept = default;
2583
+
2584
+ /**
2585
+ * @details
2586
+ */
2587
+ XLDiffCellFormat::~XLDiffCellFormat() = default;
2588
+
2589
+ /**
2590
+ * @details Copy assignment operator
2591
+ */
2592
+ XLDiffCellFormat& XLDiffCellFormat::operator=(const XLDiffCellFormat& other)
2593
+ {
2594
+ if (&other != this) *m_diffCellFormatNode = *other.m_diffCellFormatNode;
2595
+ return *this;
2596
+ }
2597
+
2598
+ /**
2599
+ * @details Move assignment operator
2600
+ */
2601
+ XLDiffCellFormat& XLDiffCellFormat::operator=(XLDiffCellFormat&& other) noexcept = default;
2602
+
2603
+
2604
+ /**
2605
+ * @details Returns the differential cell format empty status
2606
+ */
2607
+ bool XLDiffCellFormat::empty() const { return m_diffCellFormatNode->empty(); }
2608
+
2609
+ /**
2610
+ * @details Getter functions
2611
+ */
2612
+ XLFont XLDiffCellFormat::font() const
2613
+ {
2614
+ XMLNode fontNode = appendAndGetNode(*m_diffCellFormatNode, "font");
2615
+ if (fontNode.empty()) return XLFont{};
2616
+ return XLFont(fontNode);
2617
+ }
2618
+ XLNumberFormat XLDiffCellFormat::numFmt() const
2619
+ {
2620
+ XMLNode numFmtNode = appendAndGetNode(*m_diffCellFormatNode, "numFmt");
2621
+ if (numFmtNode.empty()) return XLNumberFormat{};
2622
+ return XLNumberFormat(numFmtNode);
2623
+ }
2624
+ XLFill XLDiffCellFormat::fill() const
2625
+ {
2626
+ XMLNode fillNode = appendAndGetNode(*m_diffCellFormatNode, "fill");
2627
+ if (fillNode.empty()) return XLFill{};
2628
+ return XLFill(fillNode);
2629
+ }
2630
+ XLAlignment XLDiffCellFormat::alignment() const
2631
+ {
2632
+ XMLNode alignmentNode = appendAndGetNode(*m_diffCellFormatNode, "alignment");
2633
+ if (alignmentNode.empty()) return XLAlignment{};
2634
+ return XLAlignment(alignmentNode);
2635
+ }
2636
+ XLBorder XLDiffCellFormat::border() const
2637
+ {
2638
+ XMLNode borderNode = appendAndGetNode(*m_diffCellFormatNode, "border");
2639
+ if (borderNode.empty()) return XLBorder{};
2640
+ return XLBorder(borderNode);
2641
+ }
2642
+
2643
+ /**
2644
+ * @details Setter functions
2645
+ */
2646
+ // bool XLDiffCellFormat::setName (std::string newName) { return appendAndSetAttribute(*m_diffCellFormatNode, "name", newName).empty() == false; }
2647
+
2648
+ /**
2649
+ * @details Unsupported setter function
2650
+ */
2651
+ bool XLDiffCellFormat::setExtLst(XLUnsupportedElement const& newExtLst) { OpenXLSX::ignore(newExtLst); return false; }
2652
+
2653
+ /**
2654
+ * @details assemble a string summary about the differential cell format
2655
+ */
2656
+ std::string XLDiffCellFormat::summary() const
2657
+ {
2658
+ using namespace std::literals::string_literals;
2659
+ return ""; // TODO: write this
2660
+ }
2661
+
2662
+ // ===== XLDiffCellFormats, parent of XLDiffCellFormat
2663
+
2664
+ /**
2665
+ * @details Constructor. Initializes an empty XLCellStyles object
2666
+ */
2667
+ XLDiffCellFormats::XLDiffCellFormats() : m_diffCellFormatsNode(std::make_unique<XMLNode>()) {}
2668
+
2669
+ /**
2670
+ * @details Constructor. Initializes the member variables for the new XLCellStyles object.
2671
+ */
2672
+ XLDiffCellFormats::XLDiffCellFormats(const XMLNode& diffCellFormats)
2673
+ : m_diffCellFormatsNode(std::make_unique<XMLNode>(diffCellFormats))
2674
+ {
2675
+ // initialize XLCellStyles entries and m_cellStyles here
2676
+ XMLNode node = m_diffCellFormatsNode->first_child_of_type(pugi::node_element);
2677
+ while (not node.empty()) {
2678
+ std::string nodeName = node.name();
2679
+ if (nodeName == "dxf")
2680
+ m_diffCellFormats.push_back(XLDiffCellFormat(node));
2681
+ else
2682
+ std::cerr << "WARNING: XLDiffCellFormats constructor: unknown subnode " << nodeName << std::endl;
2683
+ node = node.next_sibling_of_type(pugi::node_element);
2684
+ }
2685
+ }
2686
+
2687
+ /**
2688
+ * @details Copy constructor
2689
+ */
2690
+ XLDiffCellFormats::XLDiffCellFormats(const XLDiffCellFormats& other)
2691
+ : m_diffCellFormatsNode(std::make_unique<XMLNode>(*other.m_diffCellFormatsNode)),
2692
+ m_diffCellFormats(other.m_diffCellFormats)
2693
+ {}
2694
+
2695
+ /**
2696
+ * @details Move constructor
2697
+ */
2698
+ XLDiffCellFormats::XLDiffCellFormats(XLDiffCellFormats&& other)
2699
+ : m_diffCellFormatsNode(std::move(other.m_diffCellFormatsNode)),
2700
+ m_diffCellFormats(std::move(other.m_diffCellFormats))
2701
+ {}
2702
+
2703
+ /**
2704
+ * @details
2705
+ */
2706
+ XLDiffCellFormats::~XLDiffCellFormats()
2707
+ {
2708
+ m_diffCellFormats.clear(); // delete vector with all children
2709
+ }
2710
+
2711
+ /**
2712
+ * @details Copy assignment operator
2713
+ */
2714
+ XLDiffCellFormats& XLDiffCellFormats::operator=(const XLDiffCellFormats& other)
2715
+ {
2716
+ if (&other != this) {
2717
+ *m_diffCellFormatsNode = *other.m_diffCellFormatsNode;
2718
+ m_diffCellFormats.clear();
2719
+ m_diffCellFormats = other.m_diffCellFormats;
2720
+ }
2721
+ return *this;
2722
+ }
2723
+
2724
+ /**
2725
+ * @details Move assignment operator
2726
+ */
2727
+ XLDiffCellFormats& XLDiffCellFormats::operator=(XLDiffCellFormats&& other) noexcept = default;
2728
+
2729
+ /**
2730
+ * @details Returns the amount of differential cell formats held by the class
2731
+ */
2732
+ size_t XLDiffCellFormats::count() const { return m_diffCellFormats.size(); }
2733
+
2734
+ /**
2735
+ * @details fetch XLDiffCellFormat from m_diffCellFormats by index
2736
+ */
2737
+ XLDiffCellFormat XLDiffCellFormats::diffCellFormatByIndex(XLStyleIndex index) const
2738
+ {
2739
+ if (index >= m_diffCellFormats.size()) {
2740
+ using namespace std::literals::string_literals;
2741
+ throw XLException("XLDiffCellFormats::"s + __func__ + ": attempted to access index "s + std::to_string(index)
2742
+ + " with count "s + std::to_string(m_diffCellFormats.size()));
2743
+ }
2744
+ return m_diffCellFormats.at(index);
2745
+ }
2746
+
2747
+ /**
2748
+ * @details append a new XLDiffCellFormat to m_diffCellFormats and m_diffCellFormatsNode, based on copyFrom
2749
+ */
2750
+ XLStyleIndex XLDiffCellFormats::create(XLDiffCellFormat copyFrom, std::string styleEntriesPrefix)
2751
+ {
2752
+ XLStyleIndex index = count(); // index for the cell style to be created
2753
+ XMLNode newNode{}; // scope declaration
2754
+
2755
+ // ===== Append new node prior to final whitespaces, if any
2756
+ XMLNode lastDiffCellFormat = m_diffCellFormatsNode->last_child_of_type(pugi::node_element);
2757
+ if (lastDiffCellFormat.empty()) newNode = m_diffCellFormatsNode->prepend_child("dxf");
2758
+ else newNode = m_diffCellFormatsNode->insert_child_after("dxf", lastDiffCellFormat);
2759
+ if (newNode.empty()) {
2760
+ using namespace std::literals::string_literals;
2761
+ throw XLException("XLDiffCellFormats::"s + __func__ + ": failed to append a new dxf node"s);
2762
+ }
2763
+ if (styleEntriesPrefix.length() > 0) // if a whitespace prefix is configured
2764
+ m_diffCellFormatsNode->insert_child_before(pugi::node_pcdata, newNode).set_value(styleEntriesPrefix.c_str()); // prefix the new node with styleEntriesPrefix
2765
+
2766
+ XLDiffCellFormat newDiffCellFormat(newNode);
2767
+ if (copyFrom.m_diffCellFormatNode->empty()) { // if no template is given
2768
+ // no-op: differential cell format entries have NO default values
2769
+ }
2770
+ else
2771
+ copyXMLNode(newNode, *copyFrom.m_diffCellFormatNode); // will use copyFrom as template, does nothing if copyFrom is empty
2772
+
2773
+ m_diffCellFormats.push_back(newDiffCellFormat);
2774
+ appendAndSetAttribute(*m_diffCellFormatsNode, "count", std::to_string(m_diffCellFormats.size())); // update array count in XML
2775
+ return index;
2776
+ }
2777
+
2778
+
2779
+ // ===== XLStyles, master class
2780
+
2781
+ /**
2782
+ * @details Default constructor
2783
+ */
2784
+ XLStyles::XLStyles() {} // TBD if defaulting this constructor again would reintroduce issue #310
2785
+
2786
+ /**
2787
+ * @details Creates an XLStyles object, which will initialize from the given xmlData
2788
+ */
2789
+ XLStyles::XLStyles(XLXmlData* xmlData, bool suppressWarnings, std::string stylesPrefix)
2790
+ : XLXmlFile(xmlData),
2791
+ m_suppressWarnings( suppressWarnings )
2792
+ {
2793
+ XMLDocument & doc = xmlDocument();
2794
+ if (doc.document_element().empty()) // handle a bad (no document element) xl/styles.xml
2795
+ doc.load_string(
2796
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
2797
+ "<styleSheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\">\n"
2798
+ "</styleSheet>",
2799
+ pugi_parse_settings
2800
+ );
2801
+
2802
+ XMLNode node = doc.document_element().first_child_of_type(pugi::node_element);
2803
+ while (not node.empty()) {
2804
+ XLStylesEntryType e = XLStylesEntryTypeFromString (node.name());
2805
+ // std::cout << "node.name() is " << node.name() << ", resulting XLStylesEntryType is " << std::to_string(e) << std::endl;
2806
+ switch (e) {
2807
+ case XLStylesNumberFormats:
2808
+ // std::cout << "found XLStylesNumberFormats, node name is " << node.name() << std::endl;
2809
+ m_numberFormats = std::make_unique<XLNumberFormats>(node);
2810
+ break;
2811
+ case XLStylesFonts:
2812
+ // std::cout << "found XLStylesFonts, node name is " << node.name() << std::endl;
2813
+ m_fonts = std::make_unique<XLFonts>(node);
2814
+ break;
2815
+ case XLStylesFills:
2816
+ // std::cout << "found XLStylesFills, node name is " << node.name() << std::endl;
2817
+ m_fills = std::make_unique<XLFills>(node);
2818
+ break;
2819
+ case XLStylesBorders:
2820
+ // std::cout << "found XLStylesBorders, node name is " << node.name() << std::endl;
2821
+ m_borders = std::make_unique<XLBorders>(node);
2822
+ break;
2823
+ case XLStylesCellStyleFormats:
2824
+ // std::cout << "found XLStylesCellStyleFormats, node name is " << node.name() << std::endl;
2825
+ m_cellStyleFormats = std::make_unique<XLCellFormats>(node);
2826
+ break;
2827
+ case XLStylesCellFormats:
2828
+ // std::cout << "found XLStylesCellFormats, node name is " << node.name() << std::endl;
2829
+ m_cellFormats = std::make_unique<XLCellFormats>(node, XLPermitXfID);
2830
+ break;
2831
+ case XLStylesCellStyles:
2832
+ // std::cout << "found XLStylesCellStyles, node name is " << node.name() << std::endl;
2833
+ m_cellStyles = std::make_unique<XLCellStyles>(node);
2834
+ break;
2835
+ case XLStylesDiffCellFormats:
2836
+ // std::cout << "found XLStylesDiffCellFormats, node name is " << node.name() << std::endl;
2837
+ m_diffCellFormats = std::make_unique<XLDiffCellFormats>(node);
2838
+ break;
2839
+ case XLStylesColors: [[fallthrough]];
2840
+ case XLStylesTableStyles: [[fallthrough]];
2841
+ case XLStylesExtLst:
2842
+ if( !m_suppressWarnings )
2843
+ std::cout << "XLStyles: Ignoring currently unsupported <" << XLStylesEntryTypeToString(e) + "> node" << std::endl;
2844
+ break;
2845
+ case XLStylesInvalid: [[fallthrough]];
2846
+ default:
2847
+ if( !m_suppressWarnings )
2848
+ std::cerr << "WARNING: XLStyles constructor: invalid styles subnode \"" << node.name() << "\"" << std::endl;
2849
+ break;
2850
+ }
2851
+ node = node.next_sibling_of_type(pugi::node_element);
2852
+ }
2853
+
2854
+ // ===== Fallbacks: create root style nodes (sorted insertions using m_nodeOrder)
2855
+ XMLNode docNode = doc.document_element(); // need an rvalue to pass as reference to appendAndGetNode
2856
+ if (!m_diffCellFormats) {
2857
+ node = appendAndGetNode(docNode, XLStylesEntryTypeToString(XLStylesDiffCellFormats).c_str(), m_nodeOrder );
2858
+ wrapNode (doc.document_element(), node, stylesPrefix);
2859
+ m_diffCellFormats = std::make_unique<XLDiffCellFormats>(node);
2860
+ }
2861
+ if (!m_cellStyles) {
2862
+ node = appendAndGetNode(docNode, XLStylesEntryTypeToString(XLStylesCellStyles).c_str(), m_nodeOrder );
2863
+ wrapNode (doc.document_element(), node, stylesPrefix);
2864
+ m_cellStyles = std::make_unique<XLCellStyles>(node);
2865
+ }
2866
+ if (!m_cellFormats) {
2867
+ node = appendAndGetNode(docNode, XLStylesEntryTypeToString(XLStylesCellFormats).c_str(), m_nodeOrder );
2868
+ wrapNode (doc.document_element(), node, stylesPrefix);
2869
+ m_cellFormats = std::make_unique<XLCellFormats>(node, XLPermitXfID);
2870
+ }
2871
+ if (m_cellFormats->count() == 0) { // if the cell formats array is empty
2872
+ // ===== Create a default empty cell format with ID 0 (== XLDefaultCellFormat) because when XLDefaultCellFormat
2873
+ // is assigned to an XLRow, the intention is interpreted as "set the cell back to default formatting",
2874
+ // which does not trigger setting the attribute customFormat="true".
2875
+ // To avoid confusing the user when the first style created does not work for rows, and setting a cell's
2876
+ // format back to XLDefaultCellFormat would cause an actual formatting (if assigned format ID 0), this
2877
+ // initial entry with no properties is created and henceforth ignored
2878
+ m_cellFormats->create();
2879
+ }
2880
+
2881
+ if (!m_cellStyleFormats) {
2882
+ node = appendAndGetNode(docNode, XLStylesEntryTypeToString(XLStylesCellStyleFormats).c_str(), m_nodeOrder );
2883
+ wrapNode (doc.document_element(), node, stylesPrefix);
2884
+ m_cellStyleFormats = std::make_unique<XLCellFormats>(node);
2885
+ }
2886
+ if (!m_borders) {
2887
+ node = appendAndGetNode(docNode, XLStylesEntryTypeToString(XLStylesBorders).c_str(), m_nodeOrder );
2888
+ wrapNode (doc.document_element(), node, stylesPrefix);
2889
+ m_borders = std::make_unique<XLBorders>(node);
2890
+ }
2891
+ if (!m_fills) {
2892
+ node = appendAndGetNode(docNode, XLStylesEntryTypeToString(XLStylesFills).c_str(), m_nodeOrder );
2893
+ wrapNode (doc.document_element(), node, stylesPrefix);
2894
+ m_fills = std::make_unique<XLFills>(node);
2895
+ }
2896
+ if (!m_fonts) {
2897
+ node = appendAndGetNode(docNode, XLStylesEntryTypeToString(XLStylesFonts).c_str(), m_nodeOrder );
2898
+ wrapNode (doc.document_element(), node, stylesPrefix);
2899
+ m_fonts = std::make_unique<XLFonts>(node);
2900
+ }
2901
+ if (!m_numberFormats) {
2902
+ node = appendAndGetNode(docNode, XLStylesEntryTypeToString(XLStylesNumberFormats).c_str(), m_nodeOrder );
2903
+ wrapNode (doc.document_element(), node, stylesPrefix);
2904
+ m_numberFormats = std::make_unique<XLNumberFormats>(node);
2905
+ }
2906
+ }
2907
+
2908
+ XLStyles::~XLStyles()
2909
+ {
2910
+ }
2911
+
2912
+ /**
2913
+ * @details move-construct an XLStyles object
2914
+ */
2915
+ XLStyles::XLStyles(XLStyles&& other) noexcept
2916
+ : XLXmlFile(other),
2917
+ m_suppressWarnings(other.m_suppressWarnings),
2918
+ m_numberFormats (std::move(other.m_numberFormats) ),
2919
+ m_fonts (std::move(other.m_fonts) ),
2920
+ m_fills (std::move(other.m_fills) ),
2921
+ m_borders (std::move(other.m_borders) ),
2922
+ m_cellStyleFormats(std::move(other.m_cellStyleFormats)),
2923
+ m_cellFormats (std::move(other.m_cellFormats) ),
2924
+ m_cellStyles (std::move(other.m_cellStyles) ),
2925
+ m_diffCellFormats (std::move(other.m_diffCellFormats) )
2926
+ {}
2927
+
2928
+ /**
2929
+ * @details copy-construct an XLStyles object
2930
+ */
2931
+ XLStyles::XLStyles(const XLStyles& other)
2932
+ : XLXmlFile(other),
2933
+ m_suppressWarnings(other.m_suppressWarnings),
2934
+ m_numberFormats (std::make_unique<XLNumberFormats >(*other.m_numberFormats) ),
2935
+ m_fonts (std::make_unique<XLFonts >(*other.m_fonts) ),
2936
+ m_fills (std::make_unique<XLFills >(*other.m_fills) ),
2937
+ m_borders (std::make_unique<XLBorders >(*other.m_borders) ),
2938
+ m_cellStyleFormats(std::make_unique<XLCellFormats >(*other.m_cellStyleFormats)),
2939
+ m_cellFormats (std::make_unique<XLCellFormats >(*other.m_cellFormats) ),
2940
+ m_cellStyles (std::make_unique<XLCellStyles >(*other.m_cellStyles) ),
2941
+ m_diffCellFormats (std::make_unique<XLDiffCellFormats>(*other.m_diffCellFormats) )
2942
+ {}
2943
+
2944
+ /**
2945
+ * @details move-assign an XLStyles object
2946
+ */
2947
+ XLStyles& XLStyles::operator=(XLStyles&& other) noexcept
2948
+ {
2949
+ if (&other != this) {
2950
+ XLXmlFile::operator=(std::move(other));
2951
+ m_suppressWarnings = other.m_suppressWarnings;
2952
+ m_numberFormats = std::move(other.m_numberFormats );
2953
+ m_fonts = std::move(other.m_fonts );
2954
+ m_fills = std::move(other.m_fills );
2955
+ m_borders = std::move(other.m_borders );
2956
+ m_cellStyleFormats = std::move(other.m_cellStyleFormats);
2957
+ m_cellFormats = std::move(other.m_cellFormats );
2958
+ m_cellStyles = std::move(other.m_cellStyles );
2959
+ m_diffCellFormats = std::move(other.m_diffCellFormats );
2960
+ }
2961
+ return *this;
2962
+ }
2963
+
2964
+ /**
2965
+ * @details copy-assign an XLStyles object
2966
+ */
2967
+ XLStyles& XLStyles::operator=(const XLStyles& other)
2968
+ {
2969
+ if (&other != this) {
2970
+ XLStyles temp = other; // copy-construct
2971
+ *this = std::move(temp); // move-assign & invalidate temp
2972
+ }
2973
+ return *this;
2974
+ }
2975
+
2976
+ /**
2977
+ * @details return a handle to the underlying number formats
2978
+ */
2979
+ XLNumberFormats& XLStyles::numberFormats() const { return *m_numberFormats; }
2980
+
2981
+ /**
2982
+ * @details return a handle to the underlying fonts
2983
+ */
2984
+ XLFonts& XLStyles::fonts() const { return *m_fonts; }
2985
+
2986
+ /**
2987
+ * @details return a handle to the underlying fills
2988
+ */
2989
+ XLFills& XLStyles::fills() const { return *m_fills; }
2990
+
2991
+ /**
2992
+ * @details return a handle to the underlying borders
2993
+ */
2994
+ XLBorders& XLStyles::borders() const { return *m_borders; }
2995
+
2996
+ /**
2997
+ * @details return a handle to the underlying cell style formats
2998
+ */
2999
+ XLCellFormats& XLStyles::cellStyleFormats() const { return *m_cellStyleFormats; }
3000
+
3001
+ /**
3002
+ * @details return a handle to the underlying cell formats
3003
+ */
3004
+ XLCellFormats& XLStyles::cellFormats() const { return *m_cellFormats; }
3005
+
3006
+ /**
3007
+ * @details return a handle to the underlying cell styles
3008
+ */
3009
+ XLCellStyles& XLStyles::cellStyles() const { return *m_cellStyles; }
3010
+
3011
+ /**
3012
+ * @details return a handle to the underlying differential cell formats
3013
+ */
3014
+ XLDiffCellFormats& XLStyles::diffCellFormats() const { return *m_diffCellFormats; }