From 752563de07e7883bf0be74e129d170c65a3ee306 Mon Sep 17 00:00:00 2001 From: akira215 Date: Sat, 24 Dec 2022 11:40:00 -0500 Subject: [PATCH 01/45] creating definedName --- OpenXLSX/CMakeLists.txt | 2 + OpenXLSX/OpenXLSX.hpp | 1 + OpenXLSX/headers/XLDefinedName.hpp | 133 ++++++++++++++++++++++++++ OpenXLSX/headers/XLTable.hpp | 76 +++++++++++++++ OpenXLSX/headers/XLWorkbook.hpp | 11 +++ OpenXLSX/sources/XLCellReference.cpp | 13 ++- OpenXLSX/sources/XLDefinedName.cpp | 135 +++++++++++++++++++++++++++ OpenXLSX/sources/XLTable.cpp | 89 ++++++++++++++++++ OpenXLSX/sources/XLWorkbook.cpp | 39 ++++++++ 9 files changed, 496 insertions(+), 3 deletions(-) create mode 100644 OpenXLSX/headers/XLDefinedName.hpp create mode 100644 OpenXLSX/headers/XLTable.hpp create mode 100644 OpenXLSX/sources/XLDefinedName.cpp create mode 100644 OpenXLSX/sources/XLTable.cpp diff --git a/OpenXLSX/CMakeLists.txt b/OpenXLSX/CMakeLists.txt index 6577cd7b..202d6418 100644 --- a/OpenXLSX/CMakeLists.txt +++ b/OpenXLSX/CMakeLists.txt @@ -99,6 +99,8 @@ set(OPENXLSX_SOURCES ${CMAKE_CURRENT_LIST_DIR}/sources/XLRowData.cpp ${CMAKE_CURRENT_LIST_DIR}/sources/XLSharedStrings.cpp ${CMAKE_CURRENT_LIST_DIR}/sources/XLSheet.cpp + ${CMAKE_CURRENT_LIST_DIR}/sources/XLTable.cpp + ${CMAKE_CURRENT_LIST_DIR}/sources/XLDefinedName.cpp ${CMAKE_CURRENT_LIST_DIR}/sources/XLWorkbook.cpp ${CMAKE_CURRENT_LIST_DIR}/sources/XLXmlData.cpp ${CMAKE_CURRENT_LIST_DIR}/sources/XLXmlFile.cpp diff --git a/OpenXLSX/OpenXLSX.hpp b/OpenXLSX/OpenXLSX.hpp index 77cb1bf7..0a060d6a 100644 --- a/OpenXLSX/OpenXLSX.hpp +++ b/OpenXLSX/OpenXLSX.hpp @@ -52,6 +52,7 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. #include "headers/XLCellValue.hpp" #include "headers/XLColumn.hpp" #include "headers/XLDateTime.hpp" +#include "headers/XLDefinedName.hpp" #include "headers/XLDocument.hpp" #include "headers/XLException.hpp" #include "headers/XLFormula.hpp" diff --git a/OpenXLSX/headers/XLDefinedName.hpp b/OpenXLSX/headers/XLDefinedName.hpp new file mode 100644 index 00000000..13c66460 --- /dev/null +++ b/OpenXLSX/headers/XLDefinedName.hpp @@ -0,0 +1,133 @@ +/* + + ____ ____ ___ ____ ____ ____ ___ + 6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M' + 8P Y8 `MM. d' MM 6M' ` `MM. d' +6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d' +MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d' +MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd +MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM. +MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM. +YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. + 8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM. + YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_ + MM + MM + _MM_ + + Copyright (c) 2018, Kenneth Troldal Balslev + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + - Neither the name of the author nor the + names of any contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ + +#ifndef OPENXLSX_XLDEFINEDNAME_HPP +#define OPENXLSX_XLDEFINEDNAME_HPP + +#pragma warning(push) +#pragma warning(disable : 4251) +#pragma warning(disable : 4275) + +// ===== External Includes ===== // +#include +#include +#include + +// ===== OpenXLSX Includes ===== // +#include "OpenXLSX-Exports.hpp" + +#include "XLCellRange.hpp" +/* +#include "XLCell.hpp" +#include "XLCellReference.hpp" +#include "XLColor.hpp" +#include "XLColumn.hpp" +#include "XLCommandQuery.hpp" +#include "XLDocument.hpp" +#include "XLException.hpp" +#include "XLRow.hpp" +#include "XLXmlFile.hpp" +*/ + +namespace OpenXLSX +{ + /** + * @brief This class derivate from cell range class, + * it just add the method to creating, .... + */ + class OPENXLSX_EXPORT XLDefinedName : public XLCellRange + { + public: + + XLDefinedName(const std::string& name, + const std::string& reference, + uint32_t localSheetId, + const XLCellRange& rng); + /** + * @brief Destructor [default] + * @note This implements the default destructor. + */ + ~XLDefinedName(); + + /** + * @brief The copy constructor + * @param other The defined name object to be copied and assigned. + * @return A reference to the new object. + */ + XLDefinedName(const XLDefinedName& other); + + /** + * @brief The copy assignment operator [default] + * @param other The defined name to be copied and assigned. + * @return A reference to the new object. + * @throws A std::range_error if the source range and destination range are of different size and shape. + * @note This implements the default copy assignment operator. + */ + XLDefinedName& operator=(const XLDefinedName& other); + + /** + * @brief The move assignment operator + * @param other The definedName to be moved and assigned. + * @return A reference to the new object. + * @note This implements the default move assignment operator. + */ + XLDefinedName& operator=(XLDefinedName&& other) noexcept; + + const std::string& name() const; + const std::string& reference() const; + uint32_t localSheetId() const; + + XLCell firstCell() const; + XLCell lastCell() const; + + private: + uint32_t m_localSheetId; + std::string m_name; + std::string m_reference; + }; +} // namespace OpenXLSX + +#pragma warning(pop) +#endif // OPENXLSX_XLDEFINEDNAME_HPP diff --git a/OpenXLSX/headers/XLTable.hpp b/OpenXLSX/headers/XLTable.hpp new file mode 100644 index 00000000..373a8c55 --- /dev/null +++ b/OpenXLSX/headers/XLTable.hpp @@ -0,0 +1,76 @@ +/* + + ____ ____ ___ ____ ____ ____ ___ + 6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M' + 8P Y8 `MM. d' MM 6M' ` `MM. d' +6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d' +MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d' +MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd +MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM. +MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM. +YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. + 8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM. + YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_ + MM + MM + _MM_ + + Copyright (c) 2018, Kenneth Troldal Balslev + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + - Neither the name of the author nor the + names of any contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ + +#ifndef OPENXLSX_XLTABLE_HPP +#define OPENXLSX_XLTABLE_HPP + +#pragma warning(push) +#pragma warning(disable : 4251) +#pragma warning(disable : 4275) + +// ===== External Includes ===== // +#include +#include +#include + +// ===== OpenXLSX Includes ===== // +#include "OpenXLSX-Exports.hpp" +#include "XLCell.hpp" +#include "XLCellReference.hpp" +#include "XLColor.hpp" +#include "XLColumn.hpp" +#include "XLCommandQuery.hpp" +#include "XLDocument.hpp" +#include "XLException.hpp" +#include "XLRow.hpp" +#include "XLXmlFile.hpp" + +namespace OpenXLSX +{ + +} // namespace OpenXLSX + +#pragma warning(pop) +#endif // OPENXLSX_XLTABLE_HPP diff --git a/OpenXLSX/headers/XLWorkbook.hpp b/OpenXLSX/headers/XLWorkbook.hpp index 7150ef50..1c804c33 100644 --- a/OpenXLSX/headers/XLWorkbook.hpp +++ b/OpenXLSX/headers/XLWorkbook.hpp @@ -58,6 +58,7 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. #include "OpenXLSX-Exports.hpp" #include "XLCommandQuery.hpp" #include "XLContentTypes.hpp" +#include "XLDefinedName.hpp" #include "XLException.hpp" #include "XLRelationships.hpp" #include "XLXmlFile.hpp" @@ -151,6 +152,16 @@ namespace OpenXLSX */ XLSheet sheet(const std::string& sheetName); + // ASH + int table(const std::string& tableName); + + /** + * @brief + * @param definedName + * @return A XLDefinedName object which is derived from XLCellRange + */ + XLDefinedName definedName(const std::string& definedName); + /** * @brief * @param sheetName diff --git a/OpenXLSX/sources/XLCellReference.cpp b/OpenXLSX/sources/XLCellReference.cpp index ae889cc9..9cbab0f6 100644 --- a/OpenXLSX/sources/XLCellReference.cpp +++ b/OpenXLSX/sources/XLCellReference.cpp @@ -46,6 +46,7 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. // ===== External Includes ===== // #include #include +#include #ifdef CHARCONV_ENABLED # include #endif @@ -340,15 +341,21 @@ uint16_t XLCellReference::columnAsNumber(const std::string& column) */ XLCoordinates XLCellReference::coordinatesFromAddress(const std::string& address) { + // Escape the $ if any + std::string refAdress = address; + refAdress.erase(std::remove( refAdress.begin(), + refAdress.end(),'$'), + refAdress.end()); + uint64_t letterCount = 0; - for (auto letter : address) { + for (auto letter : refAdress) { if (letter >= 65) // NOLINT ++letterCount; else if (letter <= 57) // NOLINT break; } - auto numberCount = address.size() - letterCount; + auto numberCount = refAdress.size() - letterCount; - return std::make_pair(rowAsNumber(address.substr(letterCount, numberCount)), columnAsNumber(address.substr(0, letterCount))); + return std::make_pair(rowAsNumber(refAdress.substr(letterCount, numberCount)), columnAsNumber(refAdress.substr(0, letterCount))); } \ No newline at end of file diff --git a/OpenXLSX/sources/XLDefinedName.cpp b/OpenXLSX/sources/XLDefinedName.cpp new file mode 100644 index 00000000..bf49e7e3 --- /dev/null +++ b/OpenXLSX/sources/XLDefinedName.cpp @@ -0,0 +1,135 @@ +/* + + ____ ____ ___ ____ ____ ____ ___ + 6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M' + 8P Y8 `MM. d' MM 6M' ` `MM. d' +6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d' +MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d' +MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd +MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM. +MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM. +YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. + 8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM. + YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_ + MM + MM + _MM_ + + Copyright (c) 2018, Kenneth Troldal Balslev + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + - Neither the name of the author nor the + names of any contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ + +// ===== External Includes ===== // +#include +#include +#include +#include +#include +#include +#include + +// ===== OpenXLSX Includes ===== // +/* +#include "XLDocument.hpp" +#include "XLWorkbook.hpp" +*/ +#include "XLDefinedName.hpp" +//#include "XLCell.hpp" + +using namespace OpenXLSX; + + +XLDefinedName::XLDefinedName(const std::string& name, + const std::string& reference, + uint32_t localSheetId, + const XLCellRange& rng): + m_name(name), + m_reference(reference), + m_localSheetId(localSheetId), + XLCellRange(rng) +{ +} + +XLDefinedName::~XLDefinedName() +{} + +XLDefinedName::XLDefinedName(const XLDefinedName& other): + m_name(other.m_name), + m_reference(other.m_reference), + m_localSheetId(other.m_localSheetId), + XLCellRange(other) +{} + + +XLDefinedName& XLDefinedName::operator=(const XLDefinedName& other) +{ + if (&other != this) { + XLCellRange::operator=(other); + m_localSheetId = other.m_localSheetId; + m_name = other.m_name; + m_reference = other.m_reference; + } + + return *this; +} + +XLDefinedName& XLDefinedName::operator=(XLDefinedName&& other) noexcept +{ + if (&other != this) { + XLCellRange::operator=(std::move(other)); + m_localSheetId = other.m_localSheetId; + m_name = std::string(other.m_name); + m_reference = other.m_reference; + } + + return *this; +} + +const std::string& XLDefinedName::name() const +{ + return m_name; +} + +const std::string& XLDefinedName::reference() const +{ + return m_reference; +} + +uint32_t XLDefinedName::localSheetId() const +{ + return m_localSheetId; +} + +XLCell XLDefinedName::firstCell() const +{ + return (*begin()); +} + +XLCell XLDefinedName::lastCell() const +{ + return (*end()); +} diff --git a/OpenXLSX/sources/XLTable.cpp b/OpenXLSX/sources/XLTable.cpp new file mode 100644 index 00000000..ccb4521f --- /dev/null +++ b/OpenXLSX/sources/XLTable.cpp @@ -0,0 +1,89 @@ +/* + + ____ ____ ___ ____ ____ ____ ___ + 6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M' + 8P Y8 `MM. d' MM 6M' ` `MM. d' +6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d' +MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d' +MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd +MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM. +MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM. +YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. + 8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM. + YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_ + MM + MM + _MM_ + + Copyright (c) 2018, Kenneth Troldal Balslev + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + - Neither the name of the author nor the + names of any contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ + +// ===== External Includes ===== // +#include +#include +#include +#include + +// ===== OpenXLSX Includes ===== // +#include "XLDocument.hpp" +#include "XLTable.hpp" +#include "XLWorkbook.hpp" + +using namespace OpenXLSX; + +int XLWorkbook::table(const std::string& tableName) +{ + auto test = xmlDocument().document_element().child("sheets"); + // ===== First determine if the sheet exists. + if (xmlDocument().document_element().child("sheets").find_child_by_attribute("name", tableName.c_str()) == nullptr) + throw XLInputError("Sheet \"" + tableName + "\" does not exist"); + + // ===== Find the sheet data corresponding to the sheet with the requested name + std::string xmlID = + xmlDocument().document_element().child("sheets").find_child_by_attribute("name", tableName.c_str()).attribute("r:id").value(); + + XLQuery pathQuery(XLQueryType::QuerySheetRelsTarget); + pathQuery.setParam("sheetID", xmlID); + auto xmlPath = parentDoc().execQuery(pathQuery).result(); + + // Some spreadsheets use absolute rather than relative paths in relationship items. + if (xmlPath.substr(0,4) == "/xl/") xmlPath = xmlPath.substr(4); + + XLQuery xmlQuery(XLQueryType::QueryXmlData); + xmlQuery.setParam("xmlPath", "xl/" + xmlPath); + return 1; +} + +/* +XLSheet XLWorkbook::sheet(uint16_t index) +{ + if (index < 1 || index > sheetCount()) throw XLInputError("Sheet index is out of bounds"); + return sheet( + std::vector(sheetsNode(xmlDocument()).begin(), sheetsNode(xmlDocument()).end())[index - 1].attribute("name").as_string()); +} +*/ \ No newline at end of file diff --git a/OpenXLSX/sources/XLWorkbook.cpp b/OpenXLSX/sources/XLWorkbook.cpp index e47bc5ad..4439763f 100644 --- a/OpenXLSX/sources/XLWorkbook.cpp +++ b/OpenXLSX/sources/XLWorkbook.cpp @@ -124,6 +124,45 @@ XLWorksheet XLWorkbook::worksheet(const std::string& sheetName) return sheet(sheetName).get(); } +XLDefinedName XLWorkbook::definedName(const std::string& definedName) +{ + auto ElmtNode = xmlDocument().document_element().child("definedNames").find_child_by_attribute("name", definedName.c_str()); + + // ===== First determine if the named range exists. + if (ElmtNode == nullptr) + throw XLInputError("Defined Name \"" + definedName + "\" does not exist"); + + std::string reference = ElmtNode.child_value(); + std::string test = reference.substr(0, 4); + if (reference.substr(0, 4) == "#REF") + throw XLInputError("Defined Name \"" + definedName + "\" is pointing to an invalid reference"); + + // ===== Find the sheet where defineName is declared (but not the reference sheet). Could be empty if global name + // seems to be sheetId - 1. it will be set to 0 if no sheet is specified (global) + uint32_t localSheetId = 0; + std::string strLocalSheetId = ElmtNode.attribute("localSheetId").value(); + if (strLocalSheetId.size() > 0) + localSheetId = static_cast(std::stoul(strLocalSheetId)) + 1; + + // Retrieve the worksheet name and top left - bottom right reference + // TODO deal with non continuous range =Feuil1!$J$10:$K$15;Feuil1!$J$20:$K$24 + // TODO to be moved elsewhere (Utils ?) + std::string::size_type n = reference.find("!"); + const std::string sheetName = reference.substr(0, n); + std::string ref = reference.substr(n+1, reference.size()); + n = ref.find(":"); + std::string topLeft = ref.substr(0, n); + std::string bottomRight; + + if (nworksheet(sheetName).range(XLCellReference(topLeft), XLCellReference(bottomRight))); +} + /** * @details */ From e64a64488d95f3eac9f3214f30e83cab602ec4a9 Mon Sep 17 00:00:00 2001 From: akira215 Date: Sat, 24 Dec 2022 13:33:52 -0500 Subject: [PATCH 02/45] Changing Class name XLNamedRange --- OpenXLSX/CMakeLists.txt | 2 +- OpenXLSX/OpenXLSX.hpp | 2 +- .../{XLDefinedName.hpp => XLNamedRange.hpp} | 40 ++++++++----------- OpenXLSX/headers/XLWorkbook.hpp | 20 ++++++++-- .../{XLDefinedName.cpp => XLNamedRange.cpp} | 22 +++++----- OpenXLSX/sources/XLWorkbook.cpp | 35 +++++++++++++--- 6 files changed, 75 insertions(+), 46 deletions(-) rename OpenXLSX/headers/{XLDefinedName.hpp => XLNamedRange.hpp} (82%) rename OpenXLSX/sources/{XLDefinedName.cpp => XLNamedRange.cpp} (87%) diff --git a/OpenXLSX/CMakeLists.txt b/OpenXLSX/CMakeLists.txt index 202d6418..7eeca780 100644 --- a/OpenXLSX/CMakeLists.txt +++ b/OpenXLSX/CMakeLists.txt @@ -93,6 +93,7 @@ set(OPENXLSX_SOURCES ${CMAKE_CURRENT_LIST_DIR}/sources/XLDateTime.cpp ${CMAKE_CURRENT_LIST_DIR}/sources/XLDocument.cpp ${CMAKE_CURRENT_LIST_DIR}/sources/XLFormula.cpp + ${CMAKE_CURRENT_LIST_DIR}/sources/XLNamedRange.cpp ${CMAKE_CURRENT_LIST_DIR}/sources/XLProperties.cpp ${CMAKE_CURRENT_LIST_DIR}/sources/XLRelationships.cpp ${CMAKE_CURRENT_LIST_DIR}/sources/XLRow.cpp @@ -100,7 +101,6 @@ set(OPENXLSX_SOURCES ${CMAKE_CURRENT_LIST_DIR}/sources/XLSharedStrings.cpp ${CMAKE_CURRENT_LIST_DIR}/sources/XLSheet.cpp ${CMAKE_CURRENT_LIST_DIR}/sources/XLTable.cpp - ${CMAKE_CURRENT_LIST_DIR}/sources/XLDefinedName.cpp ${CMAKE_CURRENT_LIST_DIR}/sources/XLWorkbook.cpp ${CMAKE_CURRENT_LIST_DIR}/sources/XLXmlData.cpp ${CMAKE_CURRENT_LIST_DIR}/sources/XLXmlFile.cpp diff --git a/OpenXLSX/OpenXLSX.hpp b/OpenXLSX/OpenXLSX.hpp index 0a060d6a..8f67f8f8 100644 --- a/OpenXLSX/OpenXLSX.hpp +++ b/OpenXLSX/OpenXLSX.hpp @@ -52,10 +52,10 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. #include "headers/XLCellValue.hpp" #include "headers/XLColumn.hpp" #include "headers/XLDateTime.hpp" -#include "headers/XLDefinedName.hpp" #include "headers/XLDocument.hpp" #include "headers/XLException.hpp" #include "headers/XLFormula.hpp" +#include "headers/XLNamedRange.hpp" #include "headers/XLRow.hpp" #include "headers/XLSheet.hpp" #include "headers/XLWorkbook.hpp" diff --git a/OpenXLSX/headers/XLDefinedName.hpp b/OpenXLSX/headers/XLNamedRange.hpp similarity index 82% rename from OpenXLSX/headers/XLDefinedName.hpp rename to OpenXLSX/headers/XLNamedRange.hpp index 13c66460..8c51b08b 100644 --- a/OpenXLSX/headers/XLDefinedName.hpp +++ b/OpenXLSX/headers/XLNamedRange.hpp @@ -43,33 +43,25 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. */ -#ifndef OPENXLSX_XLDEFINEDNAME_HPP -#define OPENXLSX_XLDEFINEDNAME_HPP +#ifndef OPENXLSX_XLNAMEDRANGE_HPP +#define OPENXLSX_XLNAMEDRANGE_HPP #pragma warning(push) #pragma warning(disable : 4251) #pragma warning(disable : 4275) // ===== External Includes ===== // +#include +/* #include #include #include +*/ // ===== OpenXLSX Includes ===== // #include "OpenXLSX-Exports.hpp" - #include "XLCellRange.hpp" -/* -#include "XLCell.hpp" -#include "XLCellReference.hpp" -#include "XLColor.hpp" -#include "XLColumn.hpp" -#include "XLCommandQuery.hpp" -#include "XLDocument.hpp" -#include "XLException.hpp" -#include "XLRow.hpp" -#include "XLXmlFile.hpp" -*/ + namespace OpenXLSX { @@ -77,11 +69,11 @@ namespace OpenXLSX * @brief This class derivate from cell range class, * it just add the method to creating, .... */ - class OPENXLSX_EXPORT XLDefinedName : public XLCellRange + class OPENXLSX_EXPORT XLNamedRange : public XLCellRange { public: - XLDefinedName(const std::string& name, + XLNamedRange(const std::string& name, const std::string& reference, uint32_t localSheetId, const XLCellRange& rng); @@ -89,31 +81,31 @@ namespace OpenXLSX * @brief Destructor [default] * @note This implements the default destructor. */ - ~XLDefinedName(); + ~XLNamedRange(); /** * @brief The copy constructor - * @param other The defined name object to be copied and assigned. + * @param other The made range object to be copied and assigned. * @return A reference to the new object. */ - XLDefinedName(const XLDefinedName& other); + XLNamedRange(const XLNamedRange& other); /** * @brief The copy assignment operator [default] - * @param other The defined name to be copied and assigned. + * @param other The named range to be copied and assigned. * @return A reference to the new object. * @throws A std::range_error if the source range and destination range are of different size and shape. * @note This implements the default copy assignment operator. */ - XLDefinedName& operator=(const XLDefinedName& other); + XLNamedRange& operator=(const XLNamedRange& other); /** * @brief The move assignment operator - * @param other The definedName to be moved and assigned. + * @param other The named range to be moved and assigned. * @return A reference to the new object. * @note This implements the default move assignment operator. */ - XLDefinedName& operator=(XLDefinedName&& other) noexcept; + XLNamedRange& operator=(XLNamedRange&& other) noexcept; const std::string& name() const; const std::string& reference() const; @@ -130,4 +122,4 @@ namespace OpenXLSX } // namespace OpenXLSX #pragma warning(pop) -#endif // OPENXLSX_XLDEFINEDNAME_HPP +#endif // OPENXLSX_XLNAMEDRANGE_HPP diff --git a/OpenXLSX/headers/XLWorkbook.hpp b/OpenXLSX/headers/XLWorkbook.hpp index 1c804c33..2d5620bc 100644 --- a/OpenXLSX/headers/XLWorkbook.hpp +++ b/OpenXLSX/headers/XLWorkbook.hpp @@ -58,7 +58,6 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. #include "OpenXLSX-Exports.hpp" #include "XLCommandQuery.hpp" #include "XLContentTypes.hpp" -#include "XLDefinedName.hpp" #include "XLException.hpp" #include "XLRelationships.hpp" #include "XLXmlFile.hpp" @@ -73,6 +72,8 @@ namespace OpenXLSX class XLChartsheet; + class XLNamedRange; + /** * @brief The XLSheetType class is an enumeration of the available sheet types, e.g. Worksheet (ordinary * spreadsheets), and Chartsheet (sheets with only a chart). @@ -157,10 +158,10 @@ namespace OpenXLSX /** * @brief - * @param definedName + * @param rangeName * @return A XLDefinedName object which is derived from XLCellRange */ - XLDefinedName definedName(const std::string& definedName); + XLNamedRange namedRange(const std::string& rangeName); /** * @brief @@ -187,10 +188,21 @@ namespace OpenXLSX /** * @brief - * @param sheetName + * @param definedName */ void addWorksheet(const std::string& sheetName); + /** + * @brief + * @param rangeName Name of the range to be created + * @param reference Reference of the cell/range to be named: Sheet1!$I$17:$I$19 + * @param localSheetId Id of the sheet where the name is defined, default is 0 (global) + */ + void addNamedRange(const std::string& rangeName, + const std::string& reference, + uint32_t localSheetId = 0); + + /** * @brief * @param existingName diff --git a/OpenXLSX/sources/XLDefinedName.cpp b/OpenXLSX/sources/XLNamedRange.cpp similarity index 87% rename from OpenXLSX/sources/XLDefinedName.cpp rename to OpenXLSX/sources/XLNamedRange.cpp index bf49e7e3..594eb5cf 100644 --- a/OpenXLSX/sources/XLDefinedName.cpp +++ b/OpenXLSX/sources/XLNamedRange.cpp @@ -57,13 +57,13 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. #include "XLDocument.hpp" #include "XLWorkbook.hpp" */ -#include "XLDefinedName.hpp" +#include "XLNamedRange.hpp" //#include "XLCell.hpp" using namespace OpenXLSX; -XLDefinedName::XLDefinedName(const std::string& name, +XLNamedRange::XLNamedRange(const std::string& name, const std::string& reference, uint32_t localSheetId, const XLCellRange& rng): @@ -74,10 +74,10 @@ XLDefinedName::XLDefinedName(const std::string& name, { } -XLDefinedName::~XLDefinedName() +XLNamedRange::~XLNamedRange() {} -XLDefinedName::XLDefinedName(const XLDefinedName& other): +XLNamedRange::XLNamedRange(const XLNamedRange& other): m_name(other.m_name), m_reference(other.m_reference), m_localSheetId(other.m_localSheetId), @@ -85,7 +85,7 @@ XLDefinedName::XLDefinedName(const XLDefinedName& other): {} -XLDefinedName& XLDefinedName::operator=(const XLDefinedName& other) +XLNamedRange& XLNamedRange::operator=(const XLNamedRange& other) { if (&other != this) { XLCellRange::operator=(other); @@ -97,7 +97,7 @@ XLDefinedName& XLDefinedName::operator=(const XLDefinedName& other) return *this; } -XLDefinedName& XLDefinedName::operator=(XLDefinedName&& other) noexcept +XLNamedRange& XLNamedRange::operator=(XLNamedRange&& other) noexcept { if (&other != this) { XLCellRange::operator=(std::move(other)); @@ -109,27 +109,27 @@ XLDefinedName& XLDefinedName::operator=(XLDefinedName&& other) noexcept return *this; } -const std::string& XLDefinedName::name() const +const std::string& XLNamedRange::name() const { return m_name; } -const std::string& XLDefinedName::reference() const +const std::string& XLNamedRange::reference() const { return m_reference; } -uint32_t XLDefinedName::localSheetId() const +uint32_t XLNamedRange::localSheetId() const { return m_localSheetId; } -XLCell XLDefinedName::firstCell() const +XLCell XLNamedRange::firstCell() const { return (*begin()); } -XLCell XLDefinedName::lastCell() const +XLCell XLNamedRange::lastCell() const { return (*end()); } diff --git a/OpenXLSX/sources/XLWorkbook.cpp b/OpenXLSX/sources/XLWorkbook.cpp index 4439763f..8c12b462 100644 --- a/OpenXLSX/sources/XLWorkbook.cpp +++ b/OpenXLSX/sources/XLWorkbook.cpp @@ -50,6 +50,7 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. #include // ===== OpenXLSX Includes ===== // +#include "XLNamedRange.hpp" #include "XLDocument.hpp" #include "XLSheet.hpp" #include "XLWorkbook.hpp" @@ -124,18 +125,18 @@ XLWorksheet XLWorkbook::worksheet(const std::string& sheetName) return sheet(sheetName).get(); } -XLDefinedName XLWorkbook::definedName(const std::string& definedName) +XLNamedRange XLWorkbook::namedRange(const std::string& rangeName) { - auto ElmtNode = xmlDocument().document_element().child("definedNames").find_child_by_attribute("name", definedName.c_str()); + auto ElmtNode = xmlDocument().document_element().child("definedNames").find_child_by_attribute("name", rangeName.c_str()); // ===== First determine if the named range exists. if (ElmtNode == nullptr) - throw XLInputError("Defined Name \"" + definedName + "\" does not exist"); + throw XLInputError("Defined Name \"" + rangeName + "\" does not exist"); std::string reference = ElmtNode.child_value(); std::string test = reference.substr(0, 4); if (reference.substr(0, 4) == "#REF") - throw XLInputError("Defined Name \"" + definedName + "\" is pointing to an invalid reference"); + throw XLInputError("Defined Name \"" + rangeName + "\" is pointing to an invalid reference"); // ===== Find the sheet where defineName is declared (but not the reference sheet). Could be empty if global name // seems to be sheetId - 1. it will be set to 0 if no sheet is specified (global) @@ -159,7 +160,7 @@ XLDefinedName XLWorkbook::definedName(const std::string& definedName) else // Range with only one cell bottomRight = topLeft; - return XLDefinedName(definedName, reference, localSheetId, + return XLNamedRange(rangeName, reference, localSheetId, this->worksheet(sheetName).range(XLCellReference(topLeft), XLCellReference(bottomRight))); } @@ -248,6 +249,30 @@ void XLWorkbook::addWorksheet(const std::string& sheetName) prepareSheetMetadata(sheetName, internalID); } +void XLWorkbook::addNamedRange(const std::string& rangeName, + const std::string& reference, + uint32_t localSheetId) +{ + auto ElmtNode = xmlDocument().document_element().child("definedNames").find_child_by_attribute("name", rangeName.c_str()); + + // ===== First determine if the named range exists. + if (ElmtNode) + throw XLInputError("Defined Name \"" + rangeName + "\" already exists."); + + //TODO sanitary check the reference (including sheet name exist) + + // ===== Add new child node to the "sheets" node. + auto node = xmlDocument().document_element().child("definedNames").append_child("definedName"); + + // ===== append the required attributes to the newly created sheet node. + + node.append_attribute("name") = rangeName.c_str(); + if (localSheetId) + node.append_attribute("localSheetId") = localSheetId - 1; + + node.text().set(reference.c_str()); +} + /** * @details * @todo If the original sheet's tabSelected attribute is set, ensure it is un-set in the clone. From 725d8dae778e554878de36b89823aa7c9836ada1 Mon Sep 17 00:00:00 2001 From: akira215 Date: Sat, 24 Dec 2022 14:33:55 -0500 Subject: [PATCH 03/45] Adding sanitary check adding named range --- OpenXLSX/headers/XLCellReference.hpp | 4 +++- OpenXLSX/sources/XLCellReference.cpp | 15 +++++++++++--- OpenXLSX/sources/XLWorkbook.cpp | 30 ++++++++++++++++++++++++---- 3 files changed, 41 insertions(+), 8 deletions(-) diff --git a/OpenXLSX/headers/XLCellReference.hpp b/OpenXLSX/headers/XLCellReference.hpp index 98910f61..90cbfa5d 100644 --- a/OpenXLSX/headers/XLCellReference.hpp +++ b/OpenXLSX/headers/XLCellReference.hpp @@ -193,7 +193,7 @@ namespace OpenXLSX * @brief Get the address of the XLCellReference * @return The address, e.g. 'A1' */ - std::string address() const; + std::string address(bool absolute = false) const; /** * @brief Set the address of the XLCellReference @@ -243,6 +243,8 @@ namespace OpenXLSX */ static XLCoordinates coordinatesFromAddress(const std::string& address); + static std::string adressFromCoordinates(uint32_t row, uint16_t column, bool absolute = false); + //---------------------------------------------------------------------------------------------------------------------- // Private Member Variables //---------------------------------------------------------------------------------------------------------------------- diff --git a/OpenXLSX/sources/XLCellReference.cpp b/OpenXLSX/sources/XLCellReference.cpp index 9cbab0f6..ee31831e 100644 --- a/OpenXLSX/sources/XLCellReference.cpp +++ b/OpenXLSX/sources/XLCellReference.cpp @@ -241,9 +241,9 @@ void XLCellReference::setRowAndColumn(uint32_t row, uint16_t column) /** * @details Returns the m_cellAddress property. */ -std::string XLCellReference::address() const +std::string XLCellReference::address(bool absolute) const { - return m_cellAddress; + return adressFromCoordinates(m_row, m_column, absolute); } /** @@ -255,7 +255,7 @@ void XLCellReference::setAddress(const std::string& address) auto coordinates = coordinatesFromAddress(address); m_row = coordinates.first; m_column = coordinates.second; - m_cellAddress = address; + m_cellAddress = adressFromCoordinates(m_row, m_column); } /** @@ -358,4 +358,13 @@ XLCoordinates XLCellReference::coordinatesFromAddress(const std::string& address auto numberCount = refAdress.size() - letterCount; return std::make_pair(rowAsNumber(refAdress.substr(letterCount, numberCount)), columnAsNumber(refAdress.substr(0, letterCount))); +} + +std::string XLCellReference::adressFromCoordinates(uint32_t row, uint16_t column, bool absolute) +{ + std::string separator = std::string(""); + if (absolute) + separator = "$"; + + return separator + columnAsString(column) + separator + rowAsString(row); } \ No newline at end of file diff --git a/OpenXLSX/sources/XLWorkbook.cpp b/OpenXLSX/sources/XLWorkbook.cpp index 8c12b462..6ae4db82 100644 --- a/OpenXLSX/sources/XLWorkbook.cpp +++ b/OpenXLSX/sources/XLWorkbook.cpp @@ -50,8 +50,9 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. #include // ===== OpenXLSX Includes ===== // -#include "XLNamedRange.hpp" +#include "XLCellReference.hpp" #include "XLDocument.hpp" +#include "XLNamedRange.hpp" #include "XLSheet.hpp" #include "XLWorkbook.hpp" @@ -259,18 +260,39 @@ void XLWorkbook::addNamedRange(const std::string& rangeName, if (ElmtNode) throw XLInputError("Defined Name \"" + rangeName + "\" already exists."); - //TODO sanitary check the reference (including sheet name exist) + // Retrieve the worksheet name and top left - bottom right reference and make it safe + // TODO deal with non continuous range =Feuil1!$J$10:$K$15;Feuil1!$J$20:$K$24 + // TODO to be moved elsewhere (Utils ?) + std::string::size_type n = reference.find("!"); + if (n == reference.size()) + throw XLInputError("Invalid reference: \"" + rangeName + "\" no sheet name was found."); + + const std::string sheetName = reference.substr(0, n); + + if (!sheetExists(sheetName)) + throw XLInputError("Sheet with name \"" + sheetName + "\" doesn't exist."); + + std::string ref = reference.substr(n+1, reference.size()); + n = ref.find(":"); + std::string topLeft = ref.substr(0, n); + + // Construct a safe reference that shall be absolute + XLCellReference cellRef(topLeft); + std::string safeReference = sheetName + "!" + cellRef.address(true); + if (n Date: Sat, 24 Dec 2022 14:50:22 -0500 Subject: [PATCH 04/45] adding deleteNamedRange --- OpenXLSX/headers/XLWorkbook.hpp | 10 +++++++++- OpenXLSX/sources/XLWorkbook.cpp | 14 ++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/OpenXLSX/headers/XLWorkbook.hpp b/OpenXLSX/headers/XLWorkbook.hpp index 2d5620bc..b8436f87 100644 --- a/OpenXLSX/headers/XLWorkbook.hpp +++ b/OpenXLSX/headers/XLWorkbook.hpp @@ -192,7 +192,15 @@ namespace OpenXLSX */ void addWorksheet(const std::string& sheetName); - /** + /** + * @brief + * @param rangeName Name of the range to be deleted + * @param localSheetId Id of the sheet where the name is defined, default is 0 (global) + */ + void deleteNamedRange(const std::string& rangeName, + uint32_t localSheetId = 0); + + /** * @brief * @param rangeName Name of the range to be created * @param reference Reference of the cell/range to be named: Sheet1!$I$17:$I$19 diff --git a/OpenXLSX/sources/XLWorkbook.cpp b/OpenXLSX/sources/XLWorkbook.cpp index 6ae4db82..94125f69 100644 --- a/OpenXLSX/sources/XLWorkbook.cpp +++ b/OpenXLSX/sources/XLWorkbook.cpp @@ -250,6 +250,20 @@ void XLWorkbook::addWorksheet(const std::string& sheetName) prepareSheetMetadata(sheetName, internalID); } +void XLWorkbook::deleteNamedRange(const std::string& rangeName, + uint32_t localSheetId) +{ + auto ElmtNode = xmlDocument().document_element().child("definedNames").find_child_by_attribute("name", rangeName.c_str()); + + // ===== First determine if the named range exists. + if (ElmtNode == nullptr) + throw XLInputError("Defined Name \"" + rangeName + "\" does not exist"); + + xmlDocument().document_element().child("definedNames"). + remove_child(xmlDocument().document_element().child("definedNames"). + find_child_by_attribute("name", rangeName.c_str())); + +} void XLWorkbook::addNamedRange(const std::string& rangeName, const std::string& reference, uint32_t localSheetId) From 3a58ce668cee8ed29634e905d6526371589b47c7 Mon Sep 17 00:00:00 2001 From: akira215 Date: Mon, 26 Dec 2022 03:50:15 +0100 Subject: [PATCH 05/45] Work in progress in XLDocument::open --- OpenXLSX/headers/XLContentTypes.hpp | 1 + OpenXLSX/headers/XLSheet.hpp | 3 +++ OpenXLSX/headers/XLXmlData.hpp | 21 ++++++++++++++- OpenXLSX/sources/XLDocument.cpp | 30 ++++++++++++++++++--- OpenXLSX/sources/XLSheet.cpp | 17 ++++++++++++ OpenXLSX/sources/XLWorkbook.cpp | 41 +++++++++++++++++++++++++++++ OpenXLSX/sources/XLXmlData.cpp | 28 +++++++++++++++++++- 7 files changed, 136 insertions(+), 5 deletions(-) diff --git a/OpenXLSX/headers/XLContentTypes.hpp b/OpenXLSX/headers/XLContentTypes.hpp index f1be5e7c..152e8f38 100644 --- a/OpenXLSX/headers/XLContentTypes.hpp +++ b/OpenXLSX/headers/XLContentTypes.hpp @@ -70,6 +70,7 @@ namespace OpenXLSX Workbook, WorkbookMacroEnabled, Worksheet, + WorksheetRelation, Chartsheet, ExternalLink, Theme, diff --git a/OpenXLSX/headers/XLSheet.hpp b/OpenXLSX/headers/XLSheet.hpp index 71c41940..f878aeb2 100644 --- a/OpenXLSX/headers/XLSheet.hpp +++ b/OpenXLSX/headers/XLSheet.hpp @@ -447,6 +447,9 @@ namespace OpenXLSX */ void updateSheetName(const std::string& oldName, const std::string& newName); + //ASH + int listObjects(); + private: /** diff --git a/OpenXLSX/headers/XLXmlData.hpp b/OpenXLSX/headers/XLXmlData.hpp index 8169fbd6..e4f3c48f 100644 --- a/OpenXLSX/headers/XLXmlData.hpp +++ b/OpenXLSX/headers/XLXmlData.hpp @@ -55,6 +55,7 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. #include #include #include +#include // ===== OpenXLSX Includes ===== // #include "OpenXLSX-Exports.hpp" @@ -93,7 +94,8 @@ namespace OpenXLSX XLXmlData(XLDocument* parentDoc, const std::string& xmlPath, const std::string& xmlId = "", - XLContentType xmlType = XLContentType::Unknown); + XLContentType xmlType = XLContentType::Unknown, + XLXmlData* parentNode = nullptr); /** * @brief Default destructor. The XLXmlData does not manage any dynamically allocated resources, so a default @@ -137,6 +139,9 @@ namespace OpenXLSX */ void setRawData(const std::string& data); + void setParentdNode(XLXmlData* parentNode); + void addChildNode(XLXmlData* childNode); + /** * @brief Get the raw data for the underlying XML document. This function will retrieve the raw XML text data * from the underlying XMLDocument object. This will mainly be used when saving data to the .xlsx package @@ -175,6 +180,18 @@ namespace OpenXLSX */ XLContentType getXmlType() const; + /** + * @brief Retrieve the type represented by the XML data. + * @return A XLContentType getValue representing the type. + */ + XLXmlData* getParentNode() const; + + /** + * @brief Retrieve the type represented by the XML data. + * @return A XLContentType getValue representing the type. + */ + std::vector getChildNodes() const; + /** * @brief Access the underlying XMLDocument object. * @return A pointer to the XMLDocument object. @@ -194,6 +211,8 @@ namespace OpenXLSX std::string m_xmlPath {}; /**< The path of the XML data in the .xlsx zip archive. >*/ std::string m_xmlID {}; /**< The relationship ID of the XML data. >*/ XLContentType m_xmlType {}; /**< The type represented by the XML data. >*/ + XLXmlData* m_parentNode {}; /**< A pointer to the parent XLXmlData object. >*/ + std::vector m_childNodes {}; /**< A pointer to the parent XLXmlData object. >*/ mutable std::unique_ptr m_xmlDoc; /**< The underlying XMLDocument object. >*/ }; } // namespace OpenXLSX diff --git a/OpenXLSX/sources/XLDocument.cpp b/OpenXLSX/sources/XLDocument.cpp index 17cea9e5..d59ea006 100644 --- a/OpenXLSX/sources/XLDocument.cpp +++ b/OpenXLSX/sources/XLDocument.cpp @@ -463,17 +463,41 @@ void XLDocument::open(const std::string& fileName) // ===== Add remaining spreadsheet elements to the vector of XLXmlData objects. for (auto& item : m_contentTypes.getContentItems()) { + XLXmlData* pData = nullptr; if (item.path().substr(0, 4) == "/xl/" && !(item.path() == "/xl/workbook.xml")) - m_data.emplace_back(/* parentDoc */ this, + pData = &(m_data.emplace_back(/* parentDoc */ this, /* xmlPath */ item.path().substr(1), /* xmlID */ m_wbkRelationships.relationshipByTarget(item.path().substr(4)).id(), - /* xmlType */ item.type()); - + /* xmlType */ item.type())); else m_data.emplace_back(/* parentDoc */ this, /* xmlPath */ item.path().substr(1), /* xmlID */ m_docRelationships.relationshipByTarget(item.path().substr(1)).id(), /* xmlType */ item.type()); + + // load worksheets/_rels/sheetX.xml.rels if any + std::string sheetRelsPath = item.path(); + std::string::size_type n = sheetRelsPath.find_last_of('/'); + if(ngetXmlDocument()->document_element().children()){ diff --git a/OpenXLSX/sources/XLSheet.cpp b/OpenXLSX/sources/XLSheet.cpp index a654bd04..0d57a007 100644 --- a/OpenXLSX/sources/XLSheet.cpp +++ b/OpenXLSX/sources/XLSheet.cpp @@ -583,6 +583,23 @@ void XLWorksheet::updateSheetName(const std::string& oldName, const std::string& } } +int XLWorksheet::listObjects() +{ + /* + + parentDoc().execCommand(XLCommand(XLCommandType::CloneSheet) + .setParam("sheetID", relationshipID()) + .setParam("cloneName", newName)); + + + XLQuery pathQuery(XLQueryType::QuerySheetRelsTarget); + pathQuery.setParam("sheetID", xmlID); + auto xmlPath = parentDoc().execQuery(pathQuery).result(); + */ + + return 1; +} + /** * @details Constructor */ diff --git a/OpenXLSX/sources/XLWorkbook.cpp b/OpenXLSX/sources/XLWorkbook.cpp index 94125f69..5b0fe476 100644 --- a/OpenXLSX/sources/XLWorkbook.cpp +++ b/OpenXLSX/sources/XLWorkbook.cpp @@ -102,6 +102,22 @@ XLSheet XLWorkbook::sheet(const std::string& sheetName) // Some spreadsheets use absolute rather than relative paths in relationship items. if (xmlPath.substr(0,4) == "/xl/") xmlPath = xmlPath.substr(4); + // Collect depencecies if any + std::string sheetRelsPath = xmlPath; + std::string::size_type n = sheetRelsPath.find_last_of('/'); + if(n()); + } + + XLQuery xmlQuery(XLQueryType::QueryXmlData); xmlQuery.setParam("xmlPath", "xl/" + xmlPath); return XLSheet(parentDoc().execQuery(xmlQuery).result()); @@ -126,6 +142,31 @@ XLWorksheet XLWorkbook::worksheet(const std::string& sheetName) return sheet(sheetName).get(); } +int XLWorkbook::table(const std::string& tableName) +{ + /* + // ===== First determine if the sheet exists. + if (xmlDocument().document_element().child("sheets").find_child_by_attribute("name", sheetName.c_str()) == nullptr) + throw XLInputError("Sheet \"" + sheetName + "\" does not exist"); + + // ===== Find the sheet data corresponding to the sheet with the requested name + std::string xmlID = + xmlDocument().document_element().child("sheets").find_child_by_attribute("name", sheetName.c_str()).attribute("r:id").value(); +*/ + //XLQuery pathQuery(XLQueryType::QuerySheetRelsTarget); + //pathQuery.setParam("sheetID", xmlID); + //auto xmlPath = parentDoc().execQuery(pathQuery).result(); +/* + // Some spreadsheets use absolute rather than relative paths in relationship items. + if (xmlPath.substr(0,4) == "/xl/") xmlPath = xmlPath.substr(4); + + XLQuery xmlQuery(XLQueryType::QueryXmlData); + xmlQuery.setParam("xmlPath", "xl/" + xmlPath); + return XLSheet(parentDoc().execQuery(xmlQuery).result()); + */ + return 1; +} + XLNamedRange XLWorkbook::namedRange(const std::string& rangeName) { auto ElmtNode = xmlDocument().document_element().child("definedNames").find_child_by_attribute("name", rangeName.c_str()); diff --git a/OpenXLSX/sources/XLXmlData.cpp b/OpenXLSX/sources/XLXmlData.cpp index 04bb54f4..00fd26b3 100644 --- a/OpenXLSX/sources/XLXmlData.cpp +++ b/OpenXLSX/sources/XLXmlData.cpp @@ -55,11 +55,17 @@ using namespace OpenXLSX; /** * @details */ -XLXmlData::XLXmlData(OpenXLSX::XLDocument* parentDoc, const std::string& xmlPath, const std::string& xmlId, OpenXLSX::XLContentType xmlType) +XLXmlData::XLXmlData(OpenXLSX::XLDocument* parentDoc, + const std::string& xmlPath, + const std::string& xmlId, + OpenXLSX::XLContentType xmlType, + OpenXLSX::XLXmlData* parentNode) : m_parentDoc(parentDoc), m_xmlPath(xmlPath), m_xmlID(xmlId), m_xmlType(xmlType), + m_parentNode(parentNode), + m_childNodes(), m_xmlDoc(std::make_unique()) { m_xmlDoc->reset(); @@ -78,6 +84,16 @@ void XLXmlData::setRawData(const std::string& data) m_xmlDoc->load_string(data.c_str(), pugi::parse_default | pugi::parse_ws_pcdata); } +void XLXmlData::setParentdNode(XLXmlData* parentNode) +{ + m_parentNode = parentNode; +} + +void XLXmlData::addChildNode(XLXmlData* childNode) +{ + m_childNodes.push_back(childNode); +} + /** * @details */ @@ -128,6 +144,16 @@ XLContentType XLXmlData::getXmlType() const return m_xmlType; } +XLXmlData* XLXmlData::getParentNode() const +{ + return m_parentNode; +} + +std::vector XLXmlData::getChildNodes() const +{ + return m_childNodes; +} + /** * @details */ From b4b1e747d9f4fda4f69280fd2e358a23c4e46b12 Mon Sep 17 00:00:00 2001 From: akira215 Date: Mon, 26 Dec 2022 19:49:59 -0500 Subject: [PATCH 06/45] work in progress XLTable --- Examples/CMakeLists.txt | 6 ++ Examples/Demo9.cpp | 38 ++++++++++++ OpenXLSX/CMakeLists.txt | 1 + OpenXLSX/OpenXLSX.hpp | 1 + OpenXLSX/headers/XLCommandQuery.hpp | 1 + OpenXLSX/headers/XLContentTypes.hpp | 2 +- OpenXLSX/headers/XLRelationships.hpp | 1 + OpenXLSX/headers/XLSheet.hpp | 3 - OpenXLSX/headers/XLTable.hpp | 45 +++++++++----- OpenXLSX/headers/XLTableColumn.hpp | 83 +++++++++++++++++++++++++ OpenXLSX/headers/XLWorkbook.hpp | 5 +- OpenXLSX/sources/XLDocument.cpp | 80 ++++++++++++++++-------- OpenXLSX/sources/XLRelationships.cpp | 2 + OpenXLSX/sources/XLSheet.cpp | 17 ----- OpenXLSX/sources/XLTable.cpp | 92 ++++++++++++++++++++-------- OpenXLSX/sources/XLTableColumn.cpp | 87 ++++++++++++++++++++++++++ OpenXLSX/sources/XLWorkbook.cpp | 46 +++----------- 17 files changed, 383 insertions(+), 127 deletions(-) create mode 100644 Examples/Demo9.cpp create mode 100644 OpenXLSX/headers/XLTableColumn.hpp create mode 100644 OpenXLSX/sources/XLTableColumn.cpp diff --git a/Examples/CMakeLists.txt b/Examples/CMakeLists.txt index 5d63db0f..1776ea9a 100644 --- a/Examples/CMakeLists.txt +++ b/Examples/CMakeLists.txt @@ -67,3 +67,9 @@ target_link_libraries(Demo7 PRIVATE OpenXLSX::OpenXLSX) add_executable(Demo8 Demo8.cpp) target_link_libraries(Demo8 PRIVATE OpenXLSX::OpenXLSX) +#======================================================================================================================= +# Define Demo9 target +#======================================================================================================================= +add_executable(Demo9 Demo9.cpp) +target_link_libraries(Demo9 PRIVATE OpenXLSX::OpenXLSX) + diff --git a/Examples/Demo9.cpp b/Examples/Demo9.cpp new file mode 100644 index 00000000..5bb0aa1e --- /dev/null +++ b/Examples/Demo9.cpp @@ -0,0 +1,38 @@ +#include +// TODO documentation !!!! +using namespace OpenXLSX; + +int main() { + + XLDocument doc; + doc.open("./CTest.xlsx"); + auto wks = doc.workbook().worksheet("Input"); + + + auto rng = wks.range(XLCellReference("A1"), XLCellReference("C20")); + XLNamedRange testrg = doc.workbook().namedRange("defined_in_sheet"); + + testrg = doc.workbook().namedRange("testRange"); + XLCellValue iteration; + for (auto& cell : testrg) + iteration = cell.value(); + + doc.workbook().deleteNamedRange("NewFromCpp"); + + XLCell i = testrg.firstCell(); + XLCellValue itet = i.value(); + i.value() = "Changed By ASH"; + + std::string n = testrg.name(); + + doc.workbook().addNamedRange("NewFromCpp","Input!$F$4f",2); + + + auto testTable = doc.workbook().table("tbl_Hullform"); + + + doc.save(); + doc.close(); + + return 0; +} \ No newline at end of file diff --git a/OpenXLSX/CMakeLists.txt b/OpenXLSX/CMakeLists.txt index 7eeca780..3714e401 100644 --- a/OpenXLSX/CMakeLists.txt +++ b/OpenXLSX/CMakeLists.txt @@ -101,6 +101,7 @@ set(OPENXLSX_SOURCES ${CMAKE_CURRENT_LIST_DIR}/sources/XLSharedStrings.cpp ${CMAKE_CURRENT_LIST_DIR}/sources/XLSheet.cpp ${CMAKE_CURRENT_LIST_DIR}/sources/XLTable.cpp + ${CMAKE_CURRENT_LIST_DIR}/sources/XLTableColumn.cpp ${CMAKE_CURRENT_LIST_DIR}/sources/XLWorkbook.cpp ${CMAKE_CURRENT_LIST_DIR}/sources/XLXmlData.cpp ${CMAKE_CURRENT_LIST_DIR}/sources/XLXmlFile.cpp diff --git a/OpenXLSX/OpenXLSX.hpp b/OpenXLSX/OpenXLSX.hpp index 8f67f8f8..4b924bba 100644 --- a/OpenXLSX/OpenXLSX.hpp +++ b/OpenXLSX/OpenXLSX.hpp @@ -58,6 +58,7 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. #include "headers/XLNamedRange.hpp" #include "headers/XLRow.hpp" #include "headers/XLSheet.hpp" +#include "headers/XLTable.hpp" #include "headers/XLWorkbook.hpp" #include "headers/XLZipArchive.hpp" diff --git a/OpenXLSX/headers/XLCommandQuery.hpp b/OpenXLSX/headers/XLCommandQuery.hpp index 5d503aca..62ae9634 100644 --- a/OpenXLSX/headers/XLCommandQuery.hpp +++ b/OpenXLSX/headers/XLCommandQuery.hpp @@ -142,6 +142,7 @@ namespace OpenXLSX QuerySheetRelsID, QuerySheetRelsTarget, QuerySharedStrings, + QueryTableFromName, QueryXmlData }; diff --git a/OpenXLSX/headers/XLContentTypes.hpp b/OpenXLSX/headers/XLContentTypes.hpp index 152e8f38..a8594cc7 100644 --- a/OpenXLSX/headers/XLContentTypes.hpp +++ b/OpenXLSX/headers/XLContentTypes.hpp @@ -70,7 +70,7 @@ namespace OpenXLSX Workbook, WorkbookMacroEnabled, Worksheet, - WorksheetRelation, + WorksheetRelations, Chartsheet, ExternalLink, Theme, diff --git a/OpenXLSX/headers/XLRelationships.hpp b/OpenXLSX/headers/XLRelationships.hpp index d0d4b8a4..b22c7ffb 100644 --- a/OpenXLSX/headers/XLRelationships.hpp +++ b/OpenXLSX/headers/XLRelationships.hpp @@ -83,6 +83,7 @@ namespace OpenXLSX Theme, Styles, Chart, + Table, ChartStyle, ChartColorStyle, Image, diff --git a/OpenXLSX/headers/XLSheet.hpp b/OpenXLSX/headers/XLSheet.hpp index f878aeb2..e425550b 100644 --- a/OpenXLSX/headers/XLSheet.hpp +++ b/OpenXLSX/headers/XLSheet.hpp @@ -446,9 +446,6 @@ namespace OpenXLSX * @param newName */ void updateSheetName(const std::string& oldName, const std::string& newName); - - //ASH - int listObjects(); private: diff --git a/OpenXLSX/headers/XLTable.hpp b/OpenXLSX/headers/XLTable.hpp index 373a8c55..d7ca6bcb 100644 --- a/OpenXLSX/headers/XLTable.hpp +++ b/OpenXLSX/headers/XLTable.hpp @@ -47,30 +47,45 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. #define OPENXLSX_XLTABLE_HPP #pragma warning(push) -#pragma warning(disable : 4251) -#pragma warning(disable : 4275) +//#pragma warning(disable : 4251) +//#pragma warning(disable : 4275) // ===== External Includes ===== // -#include -#include #include // ===== OpenXLSX Includes ===== // #include "OpenXLSX-Exports.hpp" -#include "XLCell.hpp" -#include "XLCellReference.hpp" -#include "XLColor.hpp" -#include "XLColumn.hpp" -#include "XLCommandQuery.hpp" -#include "XLDocument.hpp" -#include "XLException.hpp" -#include "XLRow.hpp" -#include "XLXmlFile.hpp" - +#include "XLXmlData.hpp" +#include "XLTableColumn.hpp" namespace OpenXLSX { + class OPENXLSX_EXPORT XLTable + { + public: + /** + * @brief The constructor. + * @param xmlData from the table file + */ + explicit XLTable(XLXmlData* xmlData); + + std::string name() const; + std::string ref() const; + uint16_t columnCount() const; + void setName(const std::string& tableName); + + + private: + XLXmlData* m_pXmlData; + uint32_t m_nColumnCount; + std::vector m_columns; + // cell range + // sheet + // filter + // sort state + // tablestyle + }; } // namespace OpenXLSX -#pragma warning(pop) +//#pragma warning(pop) #endif // OPENXLSX_XLTABLE_HPP diff --git a/OpenXLSX/headers/XLTableColumn.hpp b/OpenXLSX/headers/XLTableColumn.hpp new file mode 100644 index 00000000..9bd90b39 --- /dev/null +++ b/OpenXLSX/headers/XLTableColumn.hpp @@ -0,0 +1,83 @@ +/* + + ____ ____ ___ ____ ____ ____ ___ + 6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M' + 8P Y8 `MM. d' MM 6M' ` `MM. d' +6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d' +MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d' +MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd +MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM. +MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM. +YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. + 8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM. + YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_ + MM + MM + _MM_ + + Copyright (c) 2018, Kenneth Troldal Balslev + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + - Neither the name of the author nor the + names of any contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ + +#ifndef OPENXLSX_XLTABLECOLUMN_HPP +#define OPENXLSX_XLTABLECOLUMN_HPP + +#pragma warning(push) +//#pragma warning(disable : 4251) +//#pragma warning(disable : 4275) + +// ===== External Includes ===== // +#include + +// ===== OpenXLSX Includes ===== // +#include "OpenXLSX-Exports.hpp" +#include "XLXmlData.hpp" + +namespace OpenXLSX +{ + class OPENXLSX_EXPORT XLTableColumn + { + public: + /** + * @brief The constructor. + * @param xmlData from the table file + */ + XLTableColumn(XMLNode* dataNode); + + //XLTableColumn(const XLTableColumn&) = delete; + //XLTableColumn& operator=(const XLTableColumn&) = delete; + ~XLTableColumn(); + + std::string name() const; + + private: + XMLNode* m_pDataNode; + }; +} // namespace OpenXLSX + +//#pragma warning(pop) +#endif // OPENXLSX_XLTABLECOLUMN_HPP diff --git a/OpenXLSX/headers/XLWorkbook.hpp b/OpenXLSX/headers/XLWorkbook.hpp index b8436f87..4d40ac03 100644 --- a/OpenXLSX/headers/XLWorkbook.hpp +++ b/OpenXLSX/headers/XLWorkbook.hpp @@ -74,6 +74,8 @@ namespace OpenXLSX class XLNamedRange; + class XLTable; + /** * @brief The XLSheetType class is an enumeration of the available sheet types, e.g. Worksheet (ordinary * spreadsheets), and Chartsheet (sheets with only a chart). @@ -154,7 +156,7 @@ namespace OpenXLSX XLSheet sheet(const std::string& sheetName); // ASH - int table(const std::string& tableName); + XLTable table(const std::string& tableName); /** * @brief @@ -396,7 +398,6 @@ namespace OpenXLSX */ void setSheetActive(const std::string& sheetRID); - }; } // namespace OpenXLSX diff --git a/OpenXLSX/sources/XLDocument.cpp b/OpenXLSX/sources/XLDocument.cpp index d59ea006..0c338216 100644 --- a/OpenXLSX/sources/XLDocument.cpp +++ b/OpenXLSX/sources/XLDocument.cpp @@ -463,41 +463,17 @@ void XLDocument::open(const std::string& fileName) // ===== Add remaining spreadsheet elements to the vector of XLXmlData objects. for (auto& item : m_contentTypes.getContentItems()) { - XLXmlData* pData = nullptr; if (item.path().substr(0, 4) == "/xl/" && !(item.path() == "/xl/workbook.xml")) - pData = &(m_data.emplace_back(/* parentDoc */ this, + m_data.emplace_back(/* parentDoc */ this, /* xmlPath */ item.path().substr(1), /* xmlID */ m_wbkRelationships.relationshipByTarget(item.path().substr(4)).id(), - /* xmlType */ item.type())); + /* xmlType */ item.type()); else m_data.emplace_back(/* parentDoc */ this, /* xmlPath */ item.path().substr(1), /* xmlID */ m_docRelationships.relationshipByTarget(item.path().substr(1)).id(), /* xmlType */ item.type()); - - // load worksheets/_rels/sheetX.xml.rels if any - std::string sheetRelsPath = item.path(); - std::string::size_type n = sheetRelsPath.find_last_of('/'); - if(ngetXmlDocument()->document_element().children()){ @@ -513,6 +489,43 @@ void XLDocument::open(const std::string& fileName) } + // load worksheets/_rels/sheetX.xml.rels if any and connect nodes + for (auto& wsItem : m_data){ + if (wsItem.getXmlType() == XLContentType::Worksheet){ + + std::string sheetRelsPath = wsItem.getXmlPath(); + std::string::size_type n = sheetRelsPath.find_last_of('/'); + if(nsetParentdNode(&wsItem); + auto type = childItem.type(); + } + + } + } + } + } + } + // ===== Open the workbook and document property items // TODO: If property data doesn't exist, consider creating them, instead of ignoring it. @@ -976,7 +989,20 @@ XLQuery XLDocument::execQuery(const XLQuery& query) const case XLQueryType::QuerySharedStrings: return XLQuery(query).setResult(m_sharedStrings); + + case XLQueryType::QueryTableFromName: + { + for (auto& item : m_data){ + if(item.getXmlType() == XLContentType::Table){ + if (item.getXmlDocument()->child("table").attribute("name").value() == query.getParam("tableName")) + return XLQuery(query).setResult(&item); + } + } + throw XLInternalError("Table does not exist in zip archive (" + query.getParam("tableName") + ")"); + return query; // Table not found + } + case XLQueryType::QueryXmlData: { auto result = diff --git a/OpenXLSX/sources/XLRelationships.cpp b/OpenXLSX/sources/XLRelationships.cpp index e03742ae..88e7d27d 100644 --- a/OpenXLSX/sources/XLRelationships.cpp +++ b/OpenXLSX/sources/XLRelationships.cpp @@ -93,6 +93,8 @@ namespace type = XLRelationshipType::Image; else if (typeString == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart") type = XLRelationshipType::Chart; + else if (typeString == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/table") + type = XLRelationshipType::Table; else if (typeString == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/externalLinkPath") type = XLRelationshipType::ExternalLinkPath; else if (typeString == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/printerSettings") diff --git a/OpenXLSX/sources/XLSheet.cpp b/OpenXLSX/sources/XLSheet.cpp index 0d57a007..a654bd04 100644 --- a/OpenXLSX/sources/XLSheet.cpp +++ b/OpenXLSX/sources/XLSheet.cpp @@ -583,23 +583,6 @@ void XLWorksheet::updateSheetName(const std::string& oldName, const std::string& } } -int XLWorksheet::listObjects() -{ - /* - - parentDoc().execCommand(XLCommand(XLCommandType::CloneSheet) - .setParam("sheetID", relationshipID()) - .setParam("cloneName", newName)); - - - XLQuery pathQuery(XLQueryType::QuerySheetRelsTarget); - pathQuery.setParam("sheetID", xmlID); - auto xmlPath = parentDoc().execQuery(pathQuery).result(); - */ - - return 1; -} - /** * @details Constructor */ diff --git a/OpenXLSX/sources/XLTable.cpp b/OpenXLSX/sources/XLTable.cpp index ccb4521f..cbedd4ee 100644 --- a/OpenXLSX/sources/XLTable.cpp +++ b/OpenXLSX/sources/XLTable.cpp @@ -44,46 +44,88 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. */ // ===== External Includes ===== // -#include -#include +#include #include #include // ===== OpenXLSX Includes ===== // -#include "XLDocument.hpp" #include "XLTable.hpp" -#include "XLWorkbook.hpp" + using namespace OpenXLSX; -int XLWorkbook::table(const std::string& tableName) + +XLTable::XLTable(XLXmlData* xmlData) : m_pXmlData(xmlData) { - auto test = xmlDocument().document_element().child("sheets"); - // ===== First determine if the sheet exists. - if (xmlDocument().document_element().child("sheets").find_child_by_attribute("name", tableName.c_str()) == nullptr) - throw XLInputError("Sheet \"" + tableName + "\" does not exist"); + /* + using XMLNode = pugi::xml_node; + using XMLAttribute = pugi::xml_attribute; + using XMLDocument = pugi::xml_document; + */ + - // ===== Find the sheet data corresponding to the sheet with the requested name - std::string xmlID = - xmlDocument().document_element().child("sheets").find_child_by_attribute("name", tableName.c_str()).attribute("r:id").value(); + + - XLQuery pathQuery(XLQueryType::QuerySheetRelsTarget); - pathQuery.setParam("sheetID", xmlID); - auto xmlPath = parentDoc().execQuery(pathQuery).result(); - // Some spreadsheets use absolute rather than relative paths in relationship items. - if (xmlPath.substr(0,4) == "/xl/") xmlPath = xmlPath.substr(4); + // ===== Deal with the columns + XMLNode pTblColumns = m_pXmlData->getXmlDocument()->child("table").child("tableColumns"); + m_nColumnCount = std::stoi(pTblColumns.attribute("count").value()); - XLQuery xmlQuery(XLQueryType::QueryXmlData); - xmlQuery.setParam("xmlPath", "xl/" + xmlPath); - return 1; + for (XMLNode col : pTblColumns.children()){ + std::string test = col.attribute("name").value(); + m_columns.emplace_back(XLTableColumn(&col)); + } + + for (auto item : m_columns){ + std::string test = item.name(); + int i =0; + } + /* + XMLDocument* pTableDoc = xmlData->getXmlDocument(); + m_name = pTableDoc->child("table").attribute("name").value(); + */ +//for (const auto& node : getXmlData("xl/sharedStrings.xml")->getXmlDocument()->document_element().children() + +// + int i = 0; } -/* -XLSheet XLWorkbook::sheet(uint16_t index) +std::string XLTable::name() const +{ + return (m_pXmlData->getXmlDocument()->child("table").attribute("name").value()); +} + +std::string XLTable::ref() const +{ + return (m_pXmlData->getXmlDocument()->child("table").attribute("ref").value()); +} + +uint16_t XLTable::columnCount() const +{ + return (std::stoi(m_pXmlData->getXmlDocument()->child("table") + .child("tableColumns").attribute("count").value())); +} + +void XLTable::setName(const std::string& tableName) +{ + XMLNode tableNode = m_pXmlData->getXmlDocument()->child("table"); + tableNode.attribute("name").set_value(tableName.c_str()); + tableNode.attribute("displayName").set_value(tableName.c_str()); + + // TODO change the formulas in table.xml + // TODO change the formulas in the sheet + + +} + + + +/*XLCellRange XLWorksheet::range(const XLCellReference& topLeft, const XLCellReference& bottomRight) const { - if (index < 1 || index > sheetCount()) throw XLInputError("Sheet index is out of bounds"); - return sheet( - std::vector(sheetsNode(xmlDocument()).begin(), sheetsNode(xmlDocument()).end())[index - 1].attribute("name").as_string()); + return XLCellRange(xmlDocument().first_child().child("sheetData"), + topLeft, + bottomRight, + parentDoc().execQuery(XLQuery(XLQueryType::QuerySharedStrings)).result()); } */ \ No newline at end of file diff --git a/OpenXLSX/sources/XLTableColumn.cpp b/OpenXLSX/sources/XLTableColumn.cpp new file mode 100644 index 00000000..6566b117 --- /dev/null +++ b/OpenXLSX/sources/XLTableColumn.cpp @@ -0,0 +1,87 @@ +/* + + ____ ____ ___ ____ ____ ____ ___ + 6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M' + 8P Y8 `MM. d' MM 6M' ` `MM. d' +6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d' +MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d' +MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd +MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM. +MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM. +YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. + 8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM. + YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_ + MM + MM + _MM_ + + Copyright (c) 2018, Kenneth Troldal Balslev + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + - Neither the name of the author nor the + names of any contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ + +// ===== External Includes ===== // +#include +#include +#include + +// ===== OpenXLSX Includes ===== // +#include "XLTableColumn.hpp" + +using namespace OpenXLSX; + + +XLTableColumn::XLTableColumn(XMLNode* dataNode): + m_pDataNode(dataNode) +{ + /* + m_name = m_dataNode->attribute("name").value(); + m_xr3uid = m_dataNode->attribute("xr3:uid").value(); + m_dataCellStyle = m_dataNode->attribute("dataCellStyle").value(); + m_headerRowCellStyle= m_dataNode->attribute("headerRowCellStyle").value(); + m_totalsRowFunction = m_dataNode->attribute("totalsRowFunction").value(); + m_totalsRowLabel = m_dataNode->attribute("totalsRowLabel").value(); + + m_Id = (m_dataNode->attribute("id")) ? std::stoi(m_dataNode->attribute("id").value()) : (uint32_t) -1; + m_dataDxfId = (m_dataNode->attribute("dataDxfId")) ? std::stoi(m_dataNode->attribute("dataDxfId").value()) : (uint32_t) -1; + m_headerRowDxfId = (m_dataNode->attribute("headerRowDxfId")) ? std::stoi(m_dataNode->attribute("headerRowDxfId").value()) : (uint32_t) -1; + m_totalsRowDxfId = (m_dataNode->attribute("totalsRowDxfId")) ? std::stoi(m_dataNode->attribute("totalsRowDxfId").value()) : (uint32_t) -1; + + if (m_dataNode->child("calculatedColumnFormula")) + m_calculatedColumnFormula = m_dataNode->child("calculatedColumnFormula").child_value(); + if (m_dataNode->child("totalsRowFormula")) + m_totalsRowFormula = m_dataNode->child("totalsRowFormula").child_value(); + */ + +} + +XLTableColumn::~XLTableColumn() = default; + +std::string XLTableColumn::name() const +{ + std::string test = m_pDataNode->attribute("name").value(); + return (m_pDataNode->attribute("name").value()); +} diff --git a/OpenXLSX/sources/XLWorkbook.cpp b/OpenXLSX/sources/XLWorkbook.cpp index 5b0fe476..ccda2d54 100644 --- a/OpenXLSX/sources/XLWorkbook.cpp +++ b/OpenXLSX/sources/XLWorkbook.cpp @@ -54,6 +54,7 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. #include "XLDocument.hpp" #include "XLNamedRange.hpp" #include "XLSheet.hpp" +#include "XLTable.hpp" #include "XLWorkbook.hpp" using namespace OpenXLSX; @@ -102,22 +103,6 @@ XLSheet XLWorkbook::sheet(const std::string& sheetName) // Some spreadsheets use absolute rather than relative paths in relationship items. if (xmlPath.substr(0,4) == "/xl/") xmlPath = xmlPath.substr(4); - // Collect depencecies if any - std::string sheetRelsPath = xmlPath; - std::string::size_type n = sheetRelsPath.find_last_of('/'); - if(n()); - } - - XLQuery xmlQuery(XLQueryType::QueryXmlData); xmlQuery.setParam("xmlPath", "xl/" + xmlPath); return XLSheet(parentDoc().execQuery(xmlQuery).result()); @@ -142,29 +127,16 @@ XLWorksheet XLWorkbook::worksheet(const std::string& sheetName) return sheet(sheetName).get(); } -int XLWorkbook::table(const std::string& tableName) +XLTable XLWorkbook::table(const std::string& tableName) { - /* - // ===== First determine if the sheet exists. - if (xmlDocument().document_element().child("sheets").find_child_by_attribute("name", sheetName.c_str()) == nullptr) - throw XLInputError("Sheet \"" + sheetName + "\" does not exist"); - - // ===== Find the sheet data corresponding to the sheet with the requested name - std::string xmlID = - xmlDocument().document_element().child("sheets").find_child_by_attribute("name", sheetName.c_str()).attribute("r:id").value(); -*/ - //XLQuery pathQuery(XLQueryType::QuerySheetRelsTarget); - //pathQuery.setParam("sheetID", xmlID); - //auto xmlPath = parentDoc().execQuery(pathQuery).result(); -/* - // Some spreadsheets use absolute rather than relative paths in relationship items. - if (xmlPath.substr(0,4) == "/xl/") xmlPath = xmlPath.substr(4); + // Throw an exception if table not exist + XLQuery xmlQuery(XLQueryType::QueryTableFromName); + xmlQuery.setParam("tableName", tableName); + + XLXmlData* tableItem = (parentDoc().execQuery(xmlQuery).result()); + //XLTable test = XLTable(tableItem); - XLQuery xmlQuery(XLQueryType::QueryXmlData); - xmlQuery.setParam("xmlPath", "xl/" + xmlPath); - return XLSheet(parentDoc().execQuery(xmlQuery).result()); - */ - return 1; + return XLTable(tableItem); } XLNamedRange XLWorkbook::namedRange(const std::string& rangeName) From b073a596663ea6af30fa81c3f00d657e56c4c14f Mon Sep 17 00:00:00 2001 From: akira215 Date: Tue, 27 Dec 2022 10:14:41 -0500 Subject: [PATCH 07/45] Working on XLTable --- OpenXLSX/headers/XLTable.hpp | 14 +++++--- OpenXLSX/headers/XLTableColumn.hpp | 8 +++-- OpenXLSX/sources/XLTable.cpp | 58 +++++++++++++++++++----------- OpenXLSX/sources/XLTableColumn.cpp | 14 +++++--- 4 files changed, 63 insertions(+), 31 deletions(-) diff --git a/OpenXLSX/headers/XLTable.hpp b/OpenXLSX/headers/XLTable.hpp index d7ca6bcb..fb7c6ad3 100644 --- a/OpenXLSX/headers/XLTable.hpp +++ b/OpenXLSX/headers/XLTable.hpp @@ -52,13 +52,14 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. // ===== External Includes ===== // #include - +#include // ===== OpenXLSX Includes ===== // #include "OpenXLSX-Exports.hpp" #include "XLXmlData.hpp" #include "XLTableColumn.hpp" namespace OpenXLSX { + class XLSheet; class OPENXLSX_EXPORT XLTable { public: @@ -67,18 +68,23 @@ namespace OpenXLSX * @param xmlData from the table file */ explicit XLTable(XLXmlData* xmlData); + ~XLTable(); std::string name() const; std::string ref() const; + std::vector columnNames() const; + uint16_t columnIndex(const std::string& name) const; + XLSheet getSheet() const; + uint16_t columnCount() const; + void setName(const std::string& tableName); private: - XLXmlData* m_pXmlData; - uint32_t m_nColumnCount; - std::vector m_columns; + XLXmlData* m_pXmlData; + std::vector> m_columns; // cell range // sheet // filter diff --git a/OpenXLSX/headers/XLTableColumn.hpp b/OpenXLSX/headers/XLTableColumn.hpp index 9bd90b39..df0016ec 100644 --- a/OpenXLSX/headers/XLTableColumn.hpp +++ b/OpenXLSX/headers/XLTableColumn.hpp @@ -52,10 +52,11 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. // ===== External Includes ===== // #include +#include // ===== OpenXLSX Includes ===== // #include "OpenXLSX-Exports.hpp" -#include "XLXmlData.hpp" +#include "XLXmlParser.hpp" namespace OpenXLSX { @@ -66,16 +67,17 @@ namespace OpenXLSX * @brief The constructor. * @param xmlData from the table file */ - XLTableColumn(XMLNode* dataNode); + XLTableColumn(const XMLNode& dataNode); //XLTableColumn(const XLTableColumn&) = delete; //XLTableColumn& operator=(const XLTableColumn&) = delete; ~XLTableColumn(); std::string name() const; + void setName(const std::string& name) const; private: - XMLNode* m_pDataNode; + std::unique_ptr m_dataNode; }; } // namespace OpenXLSX diff --git a/OpenXLSX/sources/XLTable.cpp b/OpenXLSX/sources/XLTable.cpp index cbedd4ee..f6662c22 100644 --- a/OpenXLSX/sources/XLTable.cpp +++ b/OpenXLSX/sources/XLTable.cpp @@ -44,14 +44,17 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. */ // ===== External Includes ===== // +#include #include #include #include // ===== OpenXLSX Includes ===== // +#include "XLSheet.hpp" #include "XLTable.hpp" + using namespace OpenXLSX; @@ -62,25 +65,12 @@ XLTable::XLTable(XLXmlData* xmlData) : m_pXmlData(xmlData) using XMLAttribute = pugi::xml_attribute; using XMLDocument = pugi::xml_document; */ - - - - - - // ===== Deal with the columns XMLNode pTblColumns = m_pXmlData->getXmlDocument()->child("table").child("tableColumns"); - m_nColumnCount = std::stoi(pTblColumns.attribute("count").value()); - for (XMLNode col : pTblColumns.children()){ - std::string test = col.attribute("name").value(); - m_columns.emplace_back(XLTableColumn(&col)); - } - - for (auto item : m_columns){ - std::string test = item.name(); - int i =0; - } + for (const XMLNode& col : pTblColumns.children()) + m_columns.emplace_back(std::shared_ptr(new XLTableColumn(col))); + /* XMLDocument* pTableDoc = xmlData->getXmlDocument(); m_name = pTableDoc->child("table").attribute("name").value(); @@ -88,9 +78,11 @@ XLTable::XLTable(XLXmlData* xmlData) : m_pXmlData(xmlData) //for (const auto& node : getXmlData("xl/sharedStrings.xml")->getXmlDocument()->document_element().children() // - int i = 0; } +XLTable::~XLTable() +{} + std::string XLTable::name() const { return (m_pXmlData->getXmlDocument()->child("table").attribute("name").value()); @@ -101,10 +93,30 @@ std::string XLTable::ref() const return (m_pXmlData->getXmlDocument()->child("table").attribute("ref").value()); } -uint16_t XLTable::columnCount() const +uint16_t XLTable::columnIndex(const std::string& name) const { - return (std::stoi(m_pXmlData->getXmlDocument()->child("table") - .child("tableColumns").attribute("count").value())); + auto it = std::find_if(m_columns.begin(), + m_columns.end(), + [&](const auto& val){ return val->name() == name; } ); + + if (it !=m_columns.end()) + return (it - m_columns.begin()); + + return (uint16_t)(-1); +} + +XLSheet XLTable::getSheet() const +{ + return XLSheet(m_pXmlData->getParentNode()); +} + +std::vector XLTable:: columnNames() const +{ + std::vector colNames; + for (auto col : m_columns) + colNames.push_back(col->name()); + + return colNames; } void XLTable::setName(const std::string& tableName) @@ -119,6 +131,12 @@ void XLTable::setName(const std::string& tableName) } +uint16_t XLTable::columnCount() const +{ + return (std::stoi(m_pXmlData->getXmlDocument()->child("table") + .child("tableColumns").attribute("count").value())); +} + /*XLCellRange XLWorksheet::range(const XLCellReference& topLeft, const XLCellReference& bottomRight) const diff --git a/OpenXLSX/sources/XLTableColumn.cpp b/OpenXLSX/sources/XLTableColumn.cpp index 6566b117..eb58df27 100644 --- a/OpenXLSX/sources/XLTableColumn.cpp +++ b/OpenXLSX/sources/XLTableColumn.cpp @@ -54,8 +54,8 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. using namespace OpenXLSX; -XLTableColumn::XLTableColumn(XMLNode* dataNode): - m_pDataNode(dataNode) +XLTableColumn::XLTableColumn(const XMLNode& dataNode): + m_dataNode(std::make_unique(dataNode)) { /* m_name = m_dataNode->attribute("name").value(); @@ -82,6 +82,12 @@ XLTableColumn::~XLTableColumn() = default; std::string XLTableColumn::name() const { - std::string test = m_pDataNode->attribute("name").value(); - return (m_pDataNode->attribute("name").value()); + return (m_dataNode->attribute("name").value()); +} + +void XLTableColumn::setName(const std::string& columnName) const +{ + m_dataNode->attribute("name").set_value(columnName.c_str()); + // TODO change the formulas in table.xml + // TODO change the formulas in the sheet } From 222ab17eecbc567a0a5fcb2027b05e44b764de88 Mon Sep 17 00:00:00 2001 From: akira215 Date: Wed, 28 Dec 2022 10:56:08 -0500 Subject: [PATCH 08/45] XLtable working with iterators --- OpenXLSX/CMakeLists.txt | 1 + OpenXLSX/headers/XLCellRange.hpp | 30 ++++ OpenXLSX/headers/XLCellReference.hpp | 8 + OpenXLSX/headers/XLRow.hpp | 5 +- OpenXLSX/headers/XLSheet.hpp | 6 + OpenXLSX/headers/XLTable.hpp | 15 +- OpenXLSX/headers/XLTableRows.hpp | 248 +++++++++++++++++++++++++ OpenXLSX/sources/XLCellRange.cpp | 61 +++++++ OpenXLSX/sources/XLCellReference.cpp | 20 +++ OpenXLSX/sources/XLSheet.cpp | 7 + OpenXLSX/sources/XLTable.cpp | 95 ++++++++-- OpenXLSX/sources/XLTableRows.cpp | 258 +++++++++++++++++++++++++++ 12 files changed, 732 insertions(+), 22 deletions(-) create mode 100644 OpenXLSX/headers/XLTableRows.hpp create mode 100644 OpenXLSX/sources/XLTableRows.cpp diff --git a/OpenXLSX/CMakeLists.txt b/OpenXLSX/CMakeLists.txt index 3714e401..04a4860f 100644 --- a/OpenXLSX/CMakeLists.txt +++ b/OpenXLSX/CMakeLists.txt @@ -102,6 +102,7 @@ set(OPENXLSX_SOURCES ${CMAKE_CURRENT_LIST_DIR}/sources/XLSheet.cpp ${CMAKE_CURRENT_LIST_DIR}/sources/XLTable.cpp ${CMAKE_CURRENT_LIST_DIR}/sources/XLTableColumn.cpp + ${CMAKE_CURRENT_LIST_DIR}/sources/XLTableRows.cpp ${CMAKE_CURRENT_LIST_DIR}/sources/XLWorkbook.cpp ${CMAKE_CURRENT_LIST_DIR}/sources/XLXmlData.cpp ${CMAKE_CURRENT_LIST_DIR}/sources/XLXmlFile.cpp diff --git a/OpenXLSX/headers/XLCellRange.hpp b/OpenXLSX/headers/XLCellRange.hpp index ccfdb66a..6929ccd1 100644 --- a/OpenXLSX/headers/XLCellRange.hpp +++ b/OpenXLSX/headers/XLCellRange.hpp @@ -52,6 +52,7 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. // ===== External Includes ===== // #include +#include // ===== OpenXLSX Includes ===== // #include "OpenXLSX-Exports.hpp" @@ -124,6 +125,27 @@ namespace OpenXLSX */ XLCellRange& operator=(XLCellRange&& other) noexcept; + /** + * @brief + * @param rhs + * @return + */ + bool operator==(const XLCellRange& rhs) const; + + /** + * @brief + * @param rhs + * @return + */ + bool operator!=(const XLCellRange& rhs) const; + + /** + * @brief + * @param index + * @return + */ + XLCell operator[](uint32_t index) const; + /** * @brief Get the number of rows in the range. * @return The number of rows. @@ -148,11 +170,19 @@ namespace OpenXLSX */ XLCellIterator end() const; + void offset(int row, int col = 0); /** * @brief */ void clear(); + /** + * @brief Static helper function to get top left and bottom right + * @param ref a ref i.e. A1:C20 + * @return A pair of ref + */ + static std::pair topLeftBottomRight(const std::string& ref); + //---------------------------------------------------------------------------------------------------------------------- // Private Member Variables //---------------------------------------------------------------------------------------------------------------------- diff --git a/OpenXLSX/headers/XLCellReference.hpp b/OpenXLSX/headers/XLCellReference.hpp index 90cbfa5d..a7b0f0d9 100644 --- a/OpenXLSX/headers/XLCellReference.hpp +++ b/OpenXLSX/headers/XLCellReference.hpp @@ -158,6 +158,14 @@ namespace OpenXLSX */ XLCellReference operator--(int); // NOLINT + /** + * @brief Offset for a given x, y. Stops at the limit of the worksheet. + * @param rows the relative number of row to offset + * @param columns the relative number of columns to offset + * @return return the offseted object + */ + XLCellReference& offset(int rows, int columns = 0); + /** * @brief Get the row number of the XLCellReference. * @return The row. diff --git a/OpenXLSX/headers/XLRow.hpp b/OpenXLSX/headers/XLRow.hpp index a1647f21..0c4b2ddf 100644 --- a/OpenXLSX/headers/XLRow.hpp +++ b/OpenXLSX/headers/XLRow.hpp @@ -344,6 +344,7 @@ namespace OpenXLSX class OPENXLSX_EXPORT XLRowRange { friend class XLRowIterator; + friend class XLTableRowIterator; //---------------------------------------------------------------------------------------------------------------------- // Public Member Functions @@ -409,10 +410,10 @@ namespace OpenXLSX XLRowIterator end(); //---------------------------------------------------------------------------------------------------------------------- - // Private Member Variables + // Protected Member Variables //---------------------------------------------------------------------------------------------------------------------- - private: + protected: std::unique_ptr m_dataNode; /**< */ uint32_t m_firstRow; /**< The cell reference of the first cell in the range */ uint32_t m_lastRow; /**< The cell reference of the last cell in the range */ diff --git a/OpenXLSX/headers/XLSheet.hpp b/OpenXLSX/headers/XLSheet.hpp index e425550b..eb327bd8 100644 --- a/OpenXLSX/headers/XLSheet.hpp +++ b/OpenXLSX/headers/XLSheet.hpp @@ -386,6 +386,12 @@ namespace OpenXLSX * @return A const XLCellRange object with the requested range. */ XLCellRange range(const XLCellReference& topLeft, const XLCellReference& bottomRight) const; +/** + * @brief Get a range with the given coordinates. + * @param topLeft A Excel type range i.e "A3:C12". + * @return A const XLCellRange object with the requested range. + */ + XLCellRange range(const std::string& range) const; /** * @brief diff --git a/OpenXLSX/headers/XLTable.hpp b/OpenXLSX/headers/XLTable.hpp index fb7c6ad3..a8230f2e 100644 --- a/OpenXLSX/headers/XLTable.hpp +++ b/OpenXLSX/headers/XLTable.hpp @@ -57,6 +57,7 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. #include "OpenXLSX-Exports.hpp" #include "XLXmlData.hpp" #include "XLTableColumn.hpp" +#include "XLTableRows.hpp" namespace OpenXLSX { class XLSheet; @@ -70,12 +71,20 @@ namespace OpenXLSX explicit XLTable(XLXmlData* xmlData); ~XLTable(); - std::string name() const; - std::string ref() const; + const std::string name() const; + const std::string ref() const; std::vector columnNames() const; uint16_t columnIndex(const std::string& name) const; - XLSheet getSheet() const; + XLWorksheet getWorksheet() const; + XLCellRange tableRange() const; + XLTableRows tableRows() const; + XLCellRange dataBodyRange() const; + + + bool isHeaderVisible() const; + bool isTotalVisible() const; + uint16_t columnCount() const; void setName(const std::string& tableName); diff --git a/OpenXLSX/headers/XLTableRows.hpp b/OpenXLSX/headers/XLTableRows.hpp new file mode 100644 index 00000000..ffd0859f --- /dev/null +++ b/OpenXLSX/headers/XLTableRows.hpp @@ -0,0 +1,248 @@ +/* + + ____ ____ ___ ____ ____ ____ ___ + 6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M' + 8P Y8 `MM. d' MM 6M' ` `MM. d' +6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d' +MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d' +MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd +MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM. +MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM. +YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. + 8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM. + YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_ + MM + MM + _MM_ + + Copyright (c) 2018, Kenneth Troldal Balslev + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + - Neither the name of the author nor the + names of any contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ + +#ifndef OPENXLSX_XLTABLEROWS_HPP +#define OPENXLSX_XLTABLEROWS_HPP + +#pragma warning(push) +//#pragma warning(disable : 4251) +//#pragma warning(disable : 4275) + +// ===== External Includes ===== // + +// ===== OpenXLSX Includes ===== // +#include "OpenXLSX-Exports.hpp" +#include "XLCellRange.hpp" +#include "XLRow.hpp" + +namespace OpenXLSX +{ + class XLTableRows; + + /** + * @brief The XLTableRowIterator class is used to iterate througt XLTableRows + */ + class OPENXLSX_EXPORT XLTableRowIterator + { + public: + using iterator_category = std::forward_iterator_tag; + using value_type = XLCellRange; + using pointer = XLCellRange*; + using reference = XLCellRange&; + + /** + * @brief + * @param rowRange + * @param loc + */ + explicit XLTableRowIterator(const XLTableRows& tableRows, + XLIteratorLocation loc); + + /** + * @brief + */ + ~XLTableRowIterator(); + + /** + * @brief + * @param other + */ + XLTableRowIterator(const XLTableRowIterator& other); + + /** + * @brief + * @param other + */ + XLTableRowIterator(XLTableRowIterator&& other) noexcept; + + /** + * @brief + * @param other + * @return + */ + XLTableRowIterator& operator=(const XLTableRowIterator& other); + + /** + * @brief + * @param other + * @return + */ + XLTableRowIterator& operator=(XLTableRowIterator&& other) noexcept; + + /** + * @brief + * @return + */ + XLTableRowIterator& operator++(); + + /** + * @brief + * @return + */ + XLTableRowIterator operator++(int); // NOLINT + + /** + * @brief + * @return + */ + reference operator*(); + + /** + * @brief + * @return + */ + pointer operator->(); + + /** + * @brief + * @param rhs + * @return + */ + bool operator==(const XLTableRowIterator& rhs) const; + + /** + * @brief + * @param rhs + * @return + */ + bool operator!=(const XLTableRowIterator& rhs) const; + + /** + * @brief + * @return + */ + explicit operator bool() const; + + + private: + XLCellRange m_range; /**< The cell range reference of the first cell in the range */ + /**< */ + }; + + //---------------------------------------------------------------------------------------------------------------------- + // Class XLTableRows + //---------------------------------------------------------------------------------------------------------------------- + + /** + * @brief Class XLTableRows derived from XLRowRange. This an iterable object within the databodyrange + */ + class OPENXLSX_EXPORT XLTableRows : public XLRowRange + { + friend class XLTableRowIterator; + + public: + /** + * @brief The constructor. + * @param XMLNode from the table file + */ + XLTableRows(const XMLNode& dataNode, + uint32_t firstRow, + uint32_t lastRow, + uint16_t firstCol, + uint16_t lastCol, + const OpenXLSX::XLSharedStrings& sharedStrings); + /** + * @brief Copy Constructor + * @param other + */ + XLTableRows(const XLTableRows& other); + + /** + * @brief Move Constructor + * @param other + */ + XLTableRows(XLTableRows&& other) noexcept; + + + //XLTableRows(const XLTableColumn&) = delete; + //XLTableRows& operator=(const XLTableColumn&) = delete; + ~XLTableRows(); + + /** + * @brief Copy assignment operator. + * @note The copy assignment operator . + */ + XLTableRows& operator=(const XLTableRows& other); + + /** + * @brief Move assignment operator. + * @note The move assignment operator has been explicitly deleted. + */ + XLTableRows& operator=(XLTableRows&& other) noexcept; + + /** + * @brief Overloading [] operator to access elements in array style + * @return a XLCellRange corresponding to the index row + * @note if the index is out of range, the entire table will be returned + */ + XLCellRange operator[](uint32_t index) const; + + /** + * @brief + * @return + */ + XLTableRowIterator begin(); + + /** + * @brief + * @return + */ + XLTableRowIterator end(); + + /** + * @brief + * @return the number of rows of the table + */ + uint32_t numRows() const; + + + private: + uint16_t m_firstCol; /**< The cell reference of the first cell in the range */ + uint16_t m_lastCol; + }; +} // namespace OpenXLSX + +//#pragma warning(pop) +#endif // OPENXLSX_XLTABLEROWS_HPP diff --git a/OpenXLSX/sources/XLCellRange.cpp b/OpenXLSX/sources/XLCellRange.cpp index 6031cb3a..8dedce89 100644 --- a/OpenXLSX/sources/XLCellRange.cpp +++ b/OpenXLSX/sources/XLCellRange.cpp @@ -52,6 +52,12 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. using namespace OpenXLSX; +namespace OpenXLSX +{ + XMLNode getRowNode(XMLNode sheetDataNode, uint32_t rowNumber); + XMLNode getCellNode(XMLNode rowNode, uint16_t columnNumber); +} + /** * @details From the two XLCellReference objects, the constructor calculates the dimensions of the range. * If the range exceeds the current bounds of the spreadsheet, the spreadsheet is resized to fit. @@ -128,6 +134,39 @@ XLCellRange& XLCellRange::operator=(XLCellRange&& other) noexcept return *this; } +/** + * @details + * @pre + * @post + */ +bool XLCellRange::operator==(const XLCellRange& rhs) const +{ + return ((m_topLeft == rhs.m_topLeft)&&(m_bottomRight == rhs.m_bottomRight)); +} + +/** + * @details + * @pre + * @post + */ +bool XLCellRange::operator!=(const XLCellRange& rhs) const +{ + return !(*this == rhs); +} + +XLCell XLCellRange::operator[](uint32_t index) const +{ + uint16_t nCol = numColumns(); + uint32_t row = m_topLeft.row() + index / nCol; + uint16_t col = m_topLeft.column() + index % nCol; + + if(row > m_bottomRight.row()) + return XLCell(); + + return XLCell(getCellNode(getRowNode(*m_dataNode, row), + col), m_sharedStrings); +} + /** * @details * @pre @@ -168,6 +207,19 @@ XLCellIterator XLCellRange::end() const return XLCellIterator(*this, XLIteratorLocation::End); } +/** + * @details + * @pre + * @post + */ +void XLCellRange::offset(int row, int col) +{ + m_topLeft.offset(row,col); + m_bottomRight.offset(row, col); +} + + + /** * @details * @pre @@ -177,3 +229,12 @@ void XLCellRange::clear() { for(auto& cell: *this) cell.value().clear(); } + +std::pair XLCellRange::topLeftBottomRight(const std::string& ref) +{ + std::string::size_type n = ref.find(':'); + if(n>ref.size()) + throw XLInputError("Invalid reference \"" + ref + "\" for a range"); + + return std::make_pair(ref.substr(0, n),ref.substr(n+1)); +} diff --git a/OpenXLSX/sources/XLCellReference.cpp b/OpenXLSX/sources/XLCellReference.cpp index ee31831e..505853b1 100644 --- a/OpenXLSX/sources/XLCellReference.cpp +++ b/OpenXLSX/sources/XLCellReference.cpp @@ -185,6 +185,26 @@ XLCellReference& XLCellReference::operator=(XLCellReference&& other) noexcept = return oldRef; } + +XLCellReference& XLCellReference::offset(int rows, int columns) +{ + if (m_row + rows > MAX_ROWS) + m_row = MAX_ROWS; + else if (m_row + rows < 1) + m_row = 1; + else + m_row = m_row + rows; + + if (m_column + columns > MAX_COLS) + setColumn(MAX_COLS); + else if (m_column + columns < 1) + setColumn(1); + else + setColumn(m_column + columns); + + return *this; +} + /** * @details Returns the m_row property. */ diff --git a/OpenXLSX/sources/XLSheet.cpp b/OpenXLSX/sources/XLSheet.cpp index a654bd04..4cce7b35 100644 --- a/OpenXLSX/sources/XLSheet.cpp +++ b/OpenXLSX/sources/XLSheet.cpp @@ -46,6 +46,7 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. // ===== External Includes ===== // #include #include +#include // ===== OpenXLSX Includes ===== // #include "XLCellRange.hpp" @@ -391,6 +392,12 @@ XLCellRange XLWorksheet::range(const XLCellReference& topLeft, const XLCellRefer parentDoc().execQuery(XLQuery(XLQueryType::QuerySharedStrings)).result()); } +XLCellRange XLWorksheet::range(const std::string& ref) const +{ + std::pair pair = XLCellRange::topLeftBottomRight(ref); + return range(XLCellReference(pair.first),XLCellReference(pair.second)); +} + /** * @details * @pre diff --git a/OpenXLSX/sources/XLTable.cpp b/OpenXLSX/sources/XLTable.cpp index f6662c22..85acac5f 100644 --- a/OpenXLSX/sources/XLTable.cpp +++ b/OpenXLSX/sources/XLTable.cpp @@ -52,7 +52,8 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. // ===== OpenXLSX Includes ===== // #include "XLSheet.hpp" #include "XLTable.hpp" - +#include "XLCellRange.hpp" +#include "XLCellReference.hpp" using namespace OpenXLSX; @@ -83,16 +84,25 @@ XLTable::XLTable(XLXmlData* xmlData) : m_pXmlData(xmlData) XLTable::~XLTable() {} -std::string XLTable::name() const +const std::string XLTable::name() const { return (m_pXmlData->getXmlDocument()->child("table").attribute("name").value()); } -std::string XLTable::ref() const +const std::string XLTable::ref() const { return (m_pXmlData->getXmlDocument()->child("table").attribute("ref").value()); } +std::vector XLTable:: columnNames() const +{ + std::vector colNames; + for (auto col : m_columns) + colNames.push_back(col->name()); + + return colNames; +} + uint16_t XLTable::columnIndex(const std::string& name) const { auto it = std::find_if(m_columns.begin(), @@ -105,32 +115,72 @@ uint16_t XLTable::columnIndex(const std::string& name) const return (uint16_t)(-1); } -XLSheet XLTable::getSheet() const +XLWorksheet XLTable::getWorksheet() const { - return XLSheet(m_pXmlData->getParentNode()); + return XLWorksheet(m_pXmlData->getParentNode()); } -std::vector XLTable:: columnNames() const +XLCellRange XLTable::tableRange() const { - std::vector colNames; - for (auto col : m_columns) - colNames.push_back(col->name()); - - return colNames; + return getWorksheet().range(ref()); } -void XLTable::setName(const std::string& tableName) +XLTableRows XLTable::tableRows() const { - XMLNode tableNode = m_pXmlData->getXmlDocument()->child("table"); - tableNode.attribute("name").set_value(tableName.c_str()); - tableNode.attribute("displayName").set_value(tableName.c_str()); + std::pair p = XLCellRange::topLeftBottomRight(ref()); + XLCellReference topLeft(p.first); + XLCellReference bottomRight(p.second); + + uint32_t firstRow = topLeft.row(); + uint32_t lastRow = bottomRight.row(); + + uint16_t firstCol = topLeft.column(); + uint16_t lastCol = bottomRight.column(); + + if (isHeaderVisible()) + firstRow +=1; + + if (isTotalVisible()) + lastRow -=1; + + return XLTableRows(m_pXmlData->getParentNode()->getXmlDocument()->first_child().child("sheetData"), + firstRow, lastRow, firstCol, lastCol, + m_pXmlData->getParentDoc()->execQuery(XLQuery(XLQueryType::QuerySharedStrings)).result()); +} - // TODO change the formulas in table.xml - // TODO change the formulas in the sheet +XLCellRange XLTable::dataBodyRange() const +{ + std::pair p = XLCellRange::topLeftBottomRight(ref()); + XLCellReference topLeft(p.first); + XLCellReference bottomRight(p.second); + if (isHeaderVisible()) + topLeft.offset(1); + + if (isTotalVisible()) + bottomRight.offset(-1); + + return getWorksheet().range(topLeft,bottomRight); +} +bool XLTable::isHeaderVisible() const +{ + std::string header = m_pXmlData->getXmlDocument()->child("table").attribute("headerRowCount").value(); + if (header == "0") + return false; + return true; // if missing, visible } +bool XLTable::isTotalVisible() const +{ + std::string header = m_pXmlData->getXmlDocument()->child("table").attribute("totalsRowCount").value(); + if (header == "1") + return true; + return false; // if missing, not visible +} + + + uint16_t XLTable::columnCount() const { return (std::stoi(m_pXmlData->getXmlDocument()->child("table") @@ -138,6 +188,17 @@ uint16_t XLTable::columnCount() const } +void XLTable::setName(const std::string& tableName) +{ + XMLNode tableNode = m_pXmlData->getXmlDocument()->child("table"); + tableNode.attribute("name").set_value(tableName.c_str()); + tableNode.attribute("displayName").set_value(tableName.c_str()); + + // TODO change the formulas in table.xml + // TODO change the formulas in the sheet + + +} /*XLCellRange XLWorksheet::range(const XLCellReference& topLeft, const XLCellReference& bottomRight) const { diff --git a/OpenXLSX/sources/XLTableRows.cpp b/OpenXLSX/sources/XLTableRows.cpp new file mode 100644 index 00000000..e068702a --- /dev/null +++ b/OpenXLSX/sources/XLTableRows.cpp @@ -0,0 +1,258 @@ +/* + + ____ ____ ___ ____ ____ ____ ___ + 6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M' + 8P Y8 `MM. d' MM 6M' ` `MM. d' +6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d' +MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d' +MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd +MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM. +MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM. +YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. + 8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM. + YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_ + MM + MM + _MM_ + + Copyright (c) 2018, Kenneth Troldal Balslev + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + - Neither the name of the author nor the + names of any contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ + +// ===== External Includes ===== // +#include +#include +#include + +// ===== OpenXLSX Includes ===== // +#include "XLTableRows.hpp" + +using namespace OpenXLSX; + + + +// ========== XLTableRowIterator ================================================ // + + + XLTableRowIterator:: XLTableRowIterator(const XLTableRows& tableRows, XLIteratorLocation loc): + m_range (XLCellRange( *tableRows.m_dataNode, + XLCellReference (tableRows.m_firstRow, tableRows.m_firstCol), + XLCellReference (tableRows.m_firstRow, tableRows.m_lastCol), + tableRows.m_sharedStrings)) +{ + if (loc == XLIteratorLocation::End) + m_range = XLCellRange( *tableRows.m_dataNode, + XLCellReference (tableRows.m_lastRow, tableRows.m_firstCol), + XLCellReference (tableRows.m_lastRow, tableRows.m_lastCol), + tableRows.m_sharedStrings); +} + + XLTableRowIterator::~ XLTableRowIterator() = default; + + XLTableRowIterator::XLTableRowIterator(const XLTableRowIterator& other) + : m_range(other.m_range) +{ } + +XLTableRowIterator::XLTableRowIterator(XLTableRowIterator&& other) noexcept = default; + + +XLTableRowIterator& XLTableRowIterator::operator=(const XLTableRowIterator& other) +{ + if (&other != this) { + auto temp = XLTableRowIterator(other); + std::swap(*this, temp); + } + return *this; +} + +XLTableRowIterator& XLTableRowIterator::operator=(XLTableRowIterator&& other) noexcept = default; + + + +XLTableRowIterator& XLTableRowIterator::operator++() +{ + m_range.offset(1); + return *this; +} + +/** + * @details + * @pre + * @post + */ +XLTableRowIterator XLTableRowIterator::operator++(int) // NOLINT +{ + auto oldIter(*this); + ++(*this); + return oldIter; +} + +/** + * @details + * @pre + * @post + */ +XLTableRowIterator::reference XLTableRowIterator::operator*() +{ + return m_range; +} + +/** + * @details + * @pre + * @post + */ +XLTableRowIterator::pointer XLTableRowIterator::operator->() +{ + return &m_range; +} + + +/** + * @details + * @pre + * @post + */ +bool XLTableRowIterator::operator==(const XLTableRowIterator& rhs) const +{ + return m_range == rhs.m_range; +} + +/** + * @details + * @pre + * @post + */ +bool XLTableRowIterator::operator!=(const XLTableRowIterator& rhs) const +{ + return !(*this == rhs); +} + +/** + * @details + * @pre + * @post + */ +XLTableRowIterator::operator bool() const +{ + return false; +} + + +// ========== XLTableRows =================================================== // + +XLTableRows::XLTableRows(const XMLNode& dataNode, + uint32_t firstRow, + uint32_t lastRow, + uint16_t firstCol, + uint16_t lastCol, + const OpenXLSX::XLSharedStrings& sharedStrings): + XLRowRange(dataNode, firstRow, lastRow, sharedStrings), + m_firstCol(firstCol), + m_lastCol(lastCol) +{} + +/** + * @brief Copy Constructor + */ +XLTableRows::XLTableRows(const XLTableRows& other): + XLRowRange(other), + m_firstCol(other.m_firstCol), + m_lastCol(other.m_lastCol) +{} + +/** + * @brief Move Constructor + */ +XLTableRows::XLTableRows(XLTableRows&& other) noexcept = default; + +XLTableRows::~XLTableRows() = default; + +/** + * @brief Copy assignment operator. + */ +XLTableRows& XLTableRows::operator=(const XLTableRows& other) +{ + if (&other != this) { + auto temp = XLTableRows(other); + std::swap(*this, temp); + } + return *this; +} + +/** + * @brief Move assignment operator. + */ +XLTableRows& XLTableRows::operator=(XLTableRows&& other) noexcept = default; + + +XLCellRange XLTableRows::operator[](uint32_t index) const +{ + uint32_t row = m_firstRow + index; + + if (row > m_lastRow) + return XLCellRange(*m_dataNode, + XLCellReference (m_firstRow, m_firstCol), + XLCellReference (m_lastRow, m_lastCol), + m_sharedStrings); + + return XLCellRange(*m_dataNode, + XLCellReference (row, m_firstCol), + XLCellReference (row, m_lastCol), + m_sharedStrings); +} + + +/** + * @details + * @pre + * @post + */ +XLTableRowIterator XLTableRows::begin() +{ + return XLTableRowIterator(*this, XLIteratorLocation::Begin); +} + +/** + * @details + * @pre + * @post + */ +XLTableRowIterator XLTableRows::end() +{ + return XLTableRowIterator(*this, XLIteratorLocation::End); +} + +/** + * @details + * @pre + * @post + */ +uint32_t XLTableRows::numRows() const +{ + return m_firstRow + 1 - m_lastRow; +} \ No newline at end of file From 35b24ce5986b53f7e18d70e85668b8c2831a6f1c Mon Sep 17 00:00:00 2001 From: akira215 Date: Wed, 28 Dec 2022 19:39:07 -0500 Subject: [PATCH 09/45] Working on createTable in XLDocument --- Examples/Demo10.cpp | 51 +++++++++ OpenXLSX/headers/XLCommandQuery.hpp | 2 + OpenXLSX/headers/XLConstants.hpp | 2 + OpenXLSX/headers/XLDocument.hpp | 16 +++ OpenXLSX/headers/XLRelationships.hpp | 1 + OpenXLSX/headers/XLTemplates.hpp | 39 +++++++ OpenXLSX/headers/XLWorkbook.hpp | 9 ++ OpenXLSX/headers/XLXmlData.hpp | 10 +- OpenXLSX/sources/XLDocument.cpp | 163 +++++++++++++++++++++++++-- OpenXLSX/sources/XLWorkbook.cpp | 54 +++++---- OpenXLSX/sources/XLXmlData.cpp | 28 ++++- 11 files changed, 339 insertions(+), 36 deletions(-) create mode 100644 Examples/Demo10.cpp create mode 100644 OpenXLSX/headers/XLTemplates.hpp diff --git a/Examples/Demo10.cpp b/Examples/Demo10.cpp new file mode 100644 index 00000000..4378c5d0 --- /dev/null +++ b/Examples/Demo10.cpp @@ -0,0 +1,51 @@ +#include + +using namespace OpenXLSX; + +int main() { + + XLDocument doc; + doc.open("./testSimple.xlsx"); + auto wks = doc.workbook().worksheet("Matrix"); + + auto matrix = wks.range("C4:G16"); + int myCell = matrix[57].value(); + + + auto testTable = doc.workbook().table("tbl_one"); + + + //testTable.setName("tbl_ash"); + auto testName = testTable.name(); + auto cols = testTable.columnNames(); + + auto ncol = testTable.columnIndex("Col bord"); + auto sht = testTable.getWorksheet(); + auto rang = testTable.dataBodyRange(); + auto rows = testTable.tableRows(); + + int val = 67; + for(auto& row:rows) { + row[0].value() = val; + val +=1; + } +/* + for(auto& cell:rows[9]) { + int i=cell.value(); + } + */ + + auto row5 = rows[5]; + + + std::string shtName = sht.name(); + + //doc.workbook().definedName("nbAngles"); + + //wks.cell("A1").value() = "Hello, OpenXLSX ASHHHH!"; + + doc.save(); + doc.close(); + + return 0; +} \ No newline at end of file diff --git a/OpenXLSX/headers/XLCommandQuery.hpp b/OpenXLSX/headers/XLCommandQuery.hpp index 62ae9634..e03b5ca8 100644 --- a/OpenXLSX/headers/XLCommandQuery.hpp +++ b/OpenXLSX/headers/XLCommandQuery.hpp @@ -75,6 +75,7 @@ namespace OpenXLSX AddSharedStrings, AddWorksheet, AddChartsheet, + AddTable, DeleteSheet, CloneSheet, }; @@ -142,6 +143,7 @@ namespace OpenXLSX QuerySheetRelsID, QuerySheetRelsTarget, QuerySharedStrings, + QuerySheetFromName, QueryTableFromName, QueryXmlData }; diff --git a/OpenXLSX/headers/XLConstants.hpp b/OpenXLSX/headers/XLConstants.hpp index ec314af3..81b52e22 100644 --- a/OpenXLSX/headers/XLConstants.hpp +++ b/OpenXLSX/headers/XLConstants.hpp @@ -5,10 +5,12 @@ #ifndef OPENXLSX_XLCONSTANTS_HPP #define OPENXLSX_XLCONSTANTS_HPP +#define INCREMENT_STRING "1" namespace OpenXLSX { inline const uint16_t MAX_COLS = 16'384; inline const uint32_t MAX_ROWS = 1'048'576; + } // namespace OpenXLSX #endif // OPENXLSX_XLCONSTANTS_HPP diff --git a/OpenXLSX/headers/XLDocument.hpp b/OpenXLSX/headers/XLDocument.hpp index 85744381..9ea9e846 100644 --- a/OpenXLSX/headers/XLDocument.hpp +++ b/OpenXLSX/headers/XLDocument.hpp @@ -292,6 +292,21 @@ namespace OpenXLSX * @return */ bool hasXmlData(const std::string& path) const; + + /** + * @brief Explore the tree to find the sheet element + * @param sheetName to be found + * @return a pointer to XLXmlData or nullptr if sheetName doesn not exist + */ + XLXmlData* getXmlDataBySheetName(const std::string& sheetName) const; + + /** + * @brief + * @param tableName + * @param reference + * @return + */ + void createTable(const std::string& sheetName, const std::string& tableName, const std::string& reference); //---------------------------------------------------------------------------------------------------------------------- // Private Member Variables @@ -310,6 +325,7 @@ namespace OpenXLSX XLContentTypes m_contentTypes {}; /**< A pointer to the content types object*/ XLAppProperties m_appProperties {}; /**< A pointer to the App properties object */ XLProperties m_coreProperties {}; /**< A pointer to the Core properties object*/ + XLXmlData* m_XmlWorkbook {}; XLWorkbook m_workbook {}; /**< A pointer to the workbook object */ IZipArchive m_archive {}; /**< */ }; diff --git a/OpenXLSX/headers/XLRelationships.hpp b/OpenXLSX/headers/XLRelationships.hpp index b22c7ffb..5f5aa6bd 100644 --- a/OpenXLSX/headers/XLRelationships.hpp +++ b/OpenXLSX/headers/XLRelationships.hpp @@ -162,6 +162,7 @@ namespace OpenXLSX */ std::string id() const; + private: // ---------- Private Member Variables ---------- // std::unique_ptr m_relationshipNode; /**< An XMLNode object with the relationship item */ }; diff --git a/OpenXLSX/headers/XLTemplates.hpp b/OpenXLSX/headers/XLTemplates.hpp new file mode 100644 index 00000000..da26eb28 --- /dev/null +++ b/OpenXLSX/headers/XLTemplates.hpp @@ -0,0 +1,39 @@ +// +// Created by Akira215 on 28/12/2022. +// + +#ifndef OPENXLSX_XLTEMPLATES_HPP +#define OPENXLSX_XLTEMPLATES_HPP + +#include + +namespace OpenXLSX +{ + const std::string emptyWorksheetTo { + "\n" + "" + "" + "" + "" + "" + "" + "" + "" + "" + }; + + const std::string emptyTable { + "(\r\n" + "" + "
" + }; + +} // namespace OpenXLSX + +#endif // OPENXLSX_XLTEMPLATES_HPP diff --git a/OpenXLSX/headers/XLWorkbook.hpp b/OpenXLSX/headers/XLWorkbook.hpp index 4d40ac03..e49e1b07 100644 --- a/OpenXLSX/headers/XLWorkbook.hpp +++ b/OpenXLSX/headers/XLWorkbook.hpp @@ -212,6 +212,15 @@ namespace OpenXLSX const std::string& reference, uint32_t localSheetId = 0); + /** + * @brief + * @param wks worksheet which will hold the new table + * @param tableName Name of the range to be created + * @param reference Reference of the cell/range to be named: $I$17:$I$19 + * @param localSheetId Id of the sheet where the name is defined, default is 0 (global) + */ + void addTable(const std::string& sheetName, const std::string& tableName, + const std::string& reference); /** * @brief diff --git a/OpenXLSX/headers/XLXmlData.hpp b/OpenXLSX/headers/XLXmlData.hpp index e4f3c48f..f0749638 100644 --- a/OpenXLSX/headers/XLXmlData.hpp +++ b/OpenXLSX/headers/XLXmlData.hpp @@ -94,6 +94,7 @@ namespace OpenXLSX XLXmlData(XLDocument* parentDoc, const std::string& xmlPath, const std::string& xmlId = "", + const std::string& name = "", XLContentType xmlType = XLContentType::Unknown, XLXmlData* parentNode = nullptr); @@ -139,7 +140,9 @@ namespace OpenXLSX */ void setRawData(const std::string& data); - void setParentdNode(XLXmlData* parentNode); + void setXmlID(const std::string& xmlID); + void setName(const std::string& name); + void setParentNode(XLXmlData* parentNode); void addChildNode(XLXmlData* childNode); /** @@ -174,6 +177,8 @@ namespace OpenXLSX */ std::string getXmlID() const; + const std::string& getName() const; + /** * @brief Retrieve the type represented by the XML data. * @return A XLContentType getValue representing the type. @@ -206,10 +211,11 @@ namespace OpenXLSX private: // ===== PRIVATE MEMBER VARIABLES ===== // - + XLDocument* m_parentDoc {}; /**< A pointer to the parent XLDocument object. >*/ std::string m_xmlPath {}; /**< The path of the XML data in the .xlsx zip archive. >*/ std::string m_xmlID {}; /**< The relationship ID of the XML data. >*/ + std::string m_name{}; XLContentType m_xmlType {}; /**< The type represented by the XML data. >*/ XLXmlData* m_parentNode {}; /**< A pointer to the parent XLXmlData object. >*/ std::vector m_childNodes {}; /**< A pointer to the parent XLXmlData object. >*/ diff --git a/OpenXLSX/sources/XLDocument.cpp b/OpenXLSX/sources/XLDocument.cpp index 0c338216..8b8d11fd 100644 --- a/OpenXLSX/sources/XLDocument.cpp +++ b/OpenXLSX/sources/XLDocument.cpp @@ -50,10 +50,15 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. # include #endif +#include +#include + // ===== OpenXLSX Includes ===== // #include "XLContentTypes.hpp" +#include "XLConstants.hpp" #include "XLDocument.hpp" #include "XLSheet.hpp" +#include "XLTemplates.hpp" using namespace OpenXLSX; @@ -467,13 +472,14 @@ void XLDocument::open(const std::string& fileName) m_data.emplace_back(/* parentDoc */ this, /* xmlPath */ item.path().substr(1), /* xmlID */ m_wbkRelationships.relationshipByTarget(item.path().substr(4)).id(), + /* name */ std::string(), /* xmlType */ item.type()); else m_data.emplace_back(/* parentDoc */ this, /* xmlPath */ item.path().substr(1), /* xmlID */ m_docRelationships.relationshipByTarget(item.path().substr(1)).id(), + /* name */ std::string(), /* xmlType */ item.type()); - } for (const auto& node : getXmlData("xl/sharedStrings.xml")->getXmlDocument()->document_element().children()){ @@ -489,9 +495,22 @@ void XLDocument::open(const std::string& fileName) } - // load worksheets/_rels/sheetX.xml.rels if any and connect nodes + m_XmlWorkbook = getXmlData("xl/workbook.xml"); + m_XmlWorkbook->setName("workbook"); + m_workbook = XLWorkbook(m_XmlWorkbook); + + // load worksheets/_rels/sheet{0}.xml.rels if any and connect nodes for (auto& wsItem : m_data){ if (wsItem.getXmlType() == XLContentType::Worksheet){ + + // Connect worksheets to workbook + m_XmlWorkbook->addChildNode(&wsItem); + wsItem.setParentNode(m_XmlWorkbook); + + // Retrieve sheet name and set it + wsItem.setName(m_XmlWorkbook->getXmlDocument()->document_element().child("sheets") + .find_child_by_attribute("r:id", wsItem.getXmlID().c_str()) + .attribute("name").value()); std::string sheetRelsPath = wsItem.getXmlPath(); std::string::size_type n = sheetRelsPath.find_last_of('/'); @@ -501,23 +520,34 @@ void XLDocument::open(const std::string& fileName) const std::string fileName = sheetRelsPath.substr(n); if (fileName.substr(0, 6) == "/sheet"){ sheetRelsPath = basePath + "/_rels" + fileName + ".rels"; - if (m_archive.hasEntry(sheetRelsPath)){ // there is a xl/worksheets/_rels/sheetX.xml.rels + if (m_archive.hasEntry(sheetRelsPath)){ // there is a xl/worksheets/_rels/sheet{0}.xml.rels + + // Adding the sheet{0}.xml.rels XLXmlData* pRels = &(m_data.emplace_back(/* parentDoc */ this, /* xmlPath */ sheetRelsPath, /* xmlID */ std::string(), + /* name */ std::string(), /* xmlType */ XLContentType::WorksheetRelations, /*parentNode */ &wsItem )); + wsItem.addChildNode(pRels); + auto sheetRels = XLRelationships(pRels); // Loop throught the sheet relations to connect childrens - for (auto& childItem : XLRelationships(getXmlData(sheetRelsPath)).relationships()){ + for (auto& childItem : sheetRels.relationships()){ std::string targetPath = childItem.target(); // Some may be relative path - if (targetPath.substr(0,2) == "..") targetPath = "xl" + targetPath.substr(2); - XLXmlData* pDocChild = getXmlData(targetPath); + if (targetPath.substr(0,2) == "..") + targetPath = "xl" + targetPath.substr(2); + + XLXmlData* pDocChild = getXmlData(targetPath); // Pointer to table elmnt + + pDocChild->setName(pDocChild->getXmlDocument()->child("table") + .attribute("name").value()); wsItem.addChildNode(pDocChild); - pDocChild->setParentdNode(&wsItem); - auto type = childItem.type(); + pDocChild->setParentNode(&wsItem); + pDocChild->setXmlID(sheetRels.relationshipByTarget(childItem.target()).id()); + //auto type = childItem.type(); } } @@ -532,7 +562,7 @@ void XLDocument::open(const std::string& fileName) m_coreProperties = (hasXmlData("docProps/core.xml") ? XLProperties(getXmlData("docProps/core.xml")) : XLProperties()); m_appProperties = (hasXmlData("docProps/app.xml") ? XLAppProperties(getXmlData("docProps/app.xml")) : XLAppProperties()); m_sharedStrings = XLSharedStrings(getXmlData("xl/sharedStrings.xml"), &m_sharedStringCache); - m_workbook = XLWorkbook(getXmlData("xl/workbook.xml")); + } /** @@ -891,12 +921,24 @@ void XLDocument::execCommand(const XLCommand& command) { /* parentDoc */ this, /* xmlPath */ command.getParam("sheetPath").substr(1), /* xmlID */ m_wbkRelationships.relationshipByTarget(command.getParam("sheetPath").substr(4)).id(), + /* xmlID */ command.getParam("sheetName"), /* xmlType */ XLContentType::Worksheet); } break; case XLCommandType::AddChartsheet: // TODO: To be implemented break; + case XLCommandType::AddTable: + { + //TODO worksheet ! + createTable(command.getParam("worksheet"), + command.getParam("tableName"), + command.getParam("reference")); + //get nexta available filename and next available id + // check that the name dont already exist + } + // TODO: To be implemented + break; case XLCommandType::DeleteSheet: { m_appProperties.deleteSheetName(command.getParam("sheetName")); @@ -929,6 +971,7 @@ void XLDocument::execCommand(const XLCommand& command) { /* parentDoc */ this, /* xmlPath */ sheetPath.substr(1), /* xmlID */ m_wbkRelationships.relationshipByTarget(sheetPath.substr(4)).id(), + /* name */ command.getParam("cloneName"), /* xmlType */ XLContentType::Worksheet); } else { @@ -944,6 +987,7 @@ void XLDocument::execCommand(const XLCommand& command) { /* parentDoc */ this, /* xmlPath */ sheetPath.substr(1), /* xmlID */ m_wbkRelationships.relationshipByTarget(sheetPath.substr(4)).id(), + /* name */ command.getParam("cloneName"), /* xmlType */ XLContentType::Chartsheet); } @@ -990,6 +1034,9 @@ XLQuery XLDocument::execQuery(const XLQuery& query) const case XLQueryType::QuerySharedStrings: return XLQuery(query).setResult(m_sharedStrings); + case XLQueryType::QuerySheetFromName: + return XLQuery(query).setResult(getXmlDataBySheetName(query.getParam("sheetName"))); + case XLQueryType::QueryTableFromName: { for (auto& item : m_data){ @@ -1002,7 +1049,6 @@ XLQuery XLDocument::execQuery(const XLQuery& query) const return query; // Table not found } - case XLQueryType::QueryXmlData: { auto result = @@ -1076,3 +1122,100 @@ std::string XLDocument::extractXmlFromArchive(const std::string& path) { return (m_archive.hasEntry(path) ? m_archive.getEntry(path) : ""); } + +XLXmlData* XLDocument::getXmlDataBySheetName(const std::string& sheetName) const +{ + for(auto sheetXmlData : m_XmlWorkbook->getChildNodes()) + if(sheetXmlData->getName() == sheetName) + return sheetXmlData; + + return nullptr; +} + +void XLDocument::createTable(const std::string& sheetName, const std::string& tableName, const std::string& reference) +{ + std::vector fileIndices; + std::vector idIndices; + + std::string basePath; + std::string name = tableName; + // Loop through existing tables to find the available: + // - filename + // - index + // - check name + for (auto& wsItem : m_data) + if (wsItem.getXmlType() == XLContentType::Table){ + std::string path = wsItem.getXmlPath(); + std::string::size_type n = path.find_last_of("/"); + if (basePath.empty()){ + basePath = path.substr(0,n+1); //"xl/tables/" + } + //std::string t = path.substr(n+6,path.size()-n-10); // removing "table and .xml" + fileIndices.push_back(std::stoi(path.substr(n+6,path.size()-n-10))); // removing "table and .xml" + + XMLNode tableNode = wsItem.getXmlDocument()->child("table"); + idIndices.push_back(std::stoi(tableNode.attribute("id").value())); + if (( name == tableNode.attribute("name").value()) || + ( name == tableNode.attribute("displayName").value())) + name += INCREMENT_STRING; + } + // Get the first available indice for file and id (filling missings) + std::sort (fileIndices.begin(), fileIndices.end()); + uint32_t nFile = 1; + for(uint32_t i : fileIndices) + if (i == nFile) + nFile +=1; + + std::sort (idIndices.begin(), idIndices.end()); + uint32_t nId = 1; + for(uint32_t i : idIndices) + if (i == nId) + nId +=1; + + std::string fileName = basePath + "table" + std::to_string(nFile) + ".xml"; + + // add to contentTypes + m_contentTypes.addOverride(fileName, XLContentType::Table); + + XLXmlData* wks = getXmlDataBySheetName(sheetName); + //add to rels + //m_archive.hasEntry(); + + + m_archive.addEntry(fileName, emptyTable); + int i=0; + + + + + + + +} + +/* + std::string emptyWorksheet { + "\n" + "" + "" + "" + "" + "" + "" + "" + "" + "" + }; + m_contentTypes.addOverride(command.getParam("sheetPath"), XLContentType::Worksheet); + m_wbkRelationships.addRelationship(XLRelationshipType::Worksheet, command.getParam("sheetPath").substr(4)); + m_appProperties.appendSheetName(command.getParam("sheetName")); + m_archive.addEntry(command.getParam("sheetPath").substr(1), emptyWorksheet); + m_data.emplace_back( + /* parentDoc this, + /* xmlPath command.getParam("sheetPath").substr(1), + /* xmlID m_wbkRelationships.relationshipByTarget(command.getParam("sheetPath").substr(4)).id(), + /* xmlType XLContentType::Worksheet); +*/ \ No newline at end of file diff --git a/OpenXLSX/sources/XLWorkbook.cpp b/OpenXLSX/sources/XLWorkbook.cpp index ccda2d54..93d3fe5b 100644 --- a/OpenXLSX/sources/XLWorkbook.cpp +++ b/OpenXLSX/sources/XLWorkbook.cpp @@ -88,23 +88,8 @@ XLWorkbook::~XLWorkbook() = default; */ XLSheet XLWorkbook::sheet(const std::string& sheetName) { - // ===== First determine if the sheet exists. - if (xmlDocument().document_element().child("sheets").find_child_by_attribute("name", sheetName.c_str()) == nullptr) - throw XLInputError("Sheet \"" + sheetName + "\" does not exist"); - - // ===== Find the sheet data corresponding to the sheet with the requested name - std::string xmlID = - xmlDocument().document_element().child("sheets").find_child_by_attribute("name", sheetName.c_str()).attribute("r:id").value(); - - XLQuery pathQuery(XLQueryType::QuerySheetRelsTarget); - pathQuery.setParam("sheetID", xmlID); - auto xmlPath = parentDoc().execQuery(pathQuery).result(); - - // Some spreadsheets use absolute rather than relative paths in relationship items. - if (xmlPath.substr(0,4) == "/xl/") xmlPath = xmlPath.substr(4); - - XLQuery xmlQuery(XLQueryType::QueryXmlData); - xmlQuery.setParam("xmlPath", "xl/" + xmlPath); + XLQuery xmlQuery(XLQueryType::QuerySheetFromName); + xmlQuery.setParam("sheetName", sheetName); return XLSheet(parentDoc().execQuery(xmlQuery).result()); } @@ -164,13 +149,13 @@ XLNamedRange XLWorkbook::namedRange(const std::string& rangeName) // TODO to be moved elsewhere (Utils ?) std::string::size_type n = reference.find("!"); const std::string sheetName = reference.substr(0, n); - std::string ref = reference.substr(n+1, reference.size()); + std::string ref = reference.substr(n+1); n = ref.find(":"); std::string topLeft = ref.substr(0, n); std::string bottomRight; if (n()) @@ -84,7 +86,18 @@ void XLXmlData::setRawData(const std::string& data) m_xmlDoc->load_string(data.c_str(), pugi::parse_default | pugi::parse_ws_pcdata); } -void XLXmlData::setParentdNode(XLXmlData* parentNode) +void XLXmlData::setXmlID(const std::string& xmlID) +{ + m_xmlID = xmlID; +} + +void XLXmlData::setName(const std::string& name) +{ + m_name = name; +} + + +void XLXmlData::setParentNode(XLXmlData* parentNode) { m_parentNode = parentNode; } @@ -136,6 +149,11 @@ std::string XLXmlData::getXmlID() const return m_xmlID; } +const std::string& XLXmlData::getName() const +{ + return m_name; +} + /** * @details */ From b226afe277a18ae62d44962b5e57a1d0a5fc1fb0 Mon Sep 17 00:00:00 2001 From: akira215 Date: Thu, 29 Dec 2022 19:53:36 -0500 Subject: [PATCH 10/45] Creating table almost finished check todo --- OpenXLSX/headers/XLDocument.hpp | 22 +- OpenXLSX/headers/XLRelationships.hpp | 8 +- OpenXLSX/headers/XLTemplates.hpp | 385 ++++++++++++++- OpenXLSX/headers/XLWorkbook.hpp | 6 - OpenXLSX/sources/XLDocument.cpp | 713 ++++++++------------------- OpenXLSX/sources/XLRelationships.cpp | 44 +- OpenXLSX/sources/XLWorkbook.cpp | 21 +- OpenXLSX/sources/XLXmlData.cpp | 14 +- 8 files changed, 667 insertions(+), 546 deletions(-) diff --git a/OpenXLSX/headers/XLDocument.hpp b/OpenXLSX/headers/XLDocument.hpp index 9ea9e846..d7b3e8bd 100644 --- a/OpenXLSX/headers/XLDocument.hpp +++ b/OpenXLSX/headers/XLDocument.hpp @@ -277,14 +277,14 @@ namespace OpenXLSX * @param path * @return */ - XLXmlData* getXmlData(const std::string& path); + XLXmlData* getXmlDataByPath(const std::string& path); /** * @brief * @param path * @return */ - const XLXmlData* getXmlData(const std::string& path) const; + const XLXmlData* getXmlDataByPath(const std::string& path) const; /** * @brief @@ -298,7 +298,23 @@ namespace OpenXLSX * @param sheetName to be found * @return a pointer to XLXmlData or nullptr if sheetName doesn not exist */ - XLXmlData* getXmlDataBySheetName(const std::string& sheetName) const; + XLXmlData* getXmlDataByName(const std::string& name) const; + + + /** + * @brief + * @param name + * @return the path to xl/worksheets/_rels/sheet{0}.xml.rels whether it exist or not. + * Return a empty string if sheetName does not exists + */ + std::string getSheetRelsPath(const std::string& sheetName) const; + + /** + * @brief determine the available id disponible for filename + * @param type + * @return Return the available id. + */ + uint16_t availableFileID(XLContentType type); /** * @brief diff --git a/OpenXLSX/headers/XLRelationships.hpp b/OpenXLSX/headers/XLRelationships.hpp index 5f5aa6bd..e66413fc 100644 --- a/OpenXLSX/headers/XLRelationships.hpp +++ b/OpenXLSX/headers/XLRelationships.hpp @@ -271,8 +271,14 @@ namespace OpenXLSX * @return true if the XLRelationshipItem exists; otherwise false. */ bool idExists(const std::string& id) const; + + protected: // ---------- Protected Member Functions ---------- // + /** + * @brief Get the next available id "rId". + * @return return the rId{0} string. + */ + std::string getAvailableRelsId() const; - // ---------- Protected Member Functions ---------- // }; } // namespace OpenXLSX diff --git a/OpenXLSX/headers/XLTemplates.hpp b/OpenXLSX/headers/XLTemplates.hpp index da26eb28..4af1ead3 100644 --- a/OpenXLSX/headers/XLTemplates.hpp +++ b/OpenXLSX/headers/XLTemplates.hpp @@ -9,7 +9,16 @@ namespace OpenXLSX { - const std::string emptyWorksheetTo { + namespace XLTemplate { + const std::string sharedStrings { + "\n" + "\n" + " \n" + " \n" + " \n" + "" + }; + const std::string emptyWorksheet { "\n" "" - "" - }; + " xmlns:xr3=\"http://schemas.microsoft.com/office/spreadsheetml/2016/revision3\"" + " id=\"0\" name=\"Table\" displayName=\"Table\" ref=\"A1:B2\" totalsRowShown=\"0\">" + "" + }; -} // namespace OpenXLSX + const std::string emptySheetRels { + "\r\n" + "" + "" + }; + const std::string tableRels { + "" + }; + const int templateSize = 7714; + const unsigned char templateData[7714] = { + 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00, 0x21, 0x00, 0xb5, 0x55, 0x30, 0x23, 0xf4, 0x00, 0x00, 0x00, + 0x4c, 0x02, 0x00, 0x00, 0x0b, 0x00, 0x08, 0x02, 0x5f, 0x72, 0x65, 0x6c, 0x73, 0x2f, 0x2e, 0x72, 0x65, 0x6c, 0x73, 0x20, 0xa2, 0x04, + 0x02, 0x28, 0xa0, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xac, 0x92, 0x4d, 0x4f, 0xc3, 0x30, 0x0c, 0x86, 0xef, 0x48, 0xfc, + 0x87, 0xc8, 0xf7, 0xd5, 0xdd, 0x90, 0x10, 0x42, 0x4b, 0x77, 0x41, 0x48, 0xbb, 0x21, 0x54, 0x7e, 0x80, 0x49, 0xdc, 0x0f, 0xb5, 0x8d, + 0xa3, 0x24, 0x1b, 0xdd, 0xbf, 0x27, 0x1c, 0x10, 0x54, 0x1a, 0x83, 0x03, 0x47, 0x7f, 0xbd, 0x7e, 0xfc, 0xca, 0xdb, 0xdd, 0x3c, 0x8d, + 0xea, 0xc8, 0x21, 0xf6, 0xe2, 0x34, 0xac, 0x8b, 0x12, 0x14, 0x3b, 0x23, 0xb6, 0x77, 0xad, 0x86, 0x97, 0xfa, 0x71, 0x75, 0x07, 0x2a, + 0x26, 0x72, 0x96, 0x46, 0x71, 0xac, 0xe1, 0xc4, 0x11, 0x76, 0xd5, 0xf5, 0xd5, 0xf6, 0x99, 0x47, 0x4a, 0x79, 0x28, 0x76, 0xbd, 0x8f, + 0x2a, 0xab, 0xb8, 0xa8, 0xa1, 0x4b, 0xc9, 0xdf, 0x23, 0x46, 0xd3, 0xf1, 0x44, 0xb1, 0x10, 0xcf, 0x2e, 0x57, 0x1a, 0x09, 0x13, 0xa5, + 0x1c, 0x86, 0x16, 0x3d, 0x99, 0x81, 0x5a, 0xc6, 0x4d, 0x59, 0xde, 0x62, 0xf8, 0xae, 0x01, 0xd5, 0x42, 0x53, 0xed, 0xad, 0x86, 0xb0, + 0xb7, 0x37, 0xa0, 0xea, 0x93, 0xcf, 0x9b, 0x7f, 0xd7, 0x96, 0xa6, 0xe9, 0x0d, 0x3f, 0x88, 0x39, 0x4c, 0xec, 0xd2, 0x99, 0x15, 0xc8, + 0x73, 0x62, 0x67, 0xd9, 0xae, 0x7c, 0xc8, 0x6c, 0x21, 0xf5, 0xf9, 0x1a, 0x55, 0x53, 0x68, 0x39, 0x69, 0xb0, 0x62, 0x9e, 0x72, 0x3a, + 0x22, 0x79, 0x5f, 0x64, 0x6c, 0xc0, 0xf3, 0x44, 0x9b, 0xbf, 0x13, 0xfd, 0x7c, 0x2d, 0x4e, 0x9c, 0xc8, 0x52, 0x22, 0x34, 0x12, 0xf8, + 0x32, 0xcf, 0x47, 0xc7, 0x25, 0xa0, 0xf5, 0x7f, 0x5a, 0xb4, 0x34, 0xf1, 0xcb, 0x9d, 0x79, 0xc4, 0x37, 0x09, 0xc3, 0xab, 0xc8, 0xf0, + 0xc9, 0x82, 0x8b, 0x1f, 0xa8, 0xde, 0x01, 0x00, 0x00, 0xff, 0xff, 0x03, 0x00, 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x06, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x21, 0x00, 0x47, 0x88, 0xbc, 0xe2, 0x5d, 0x03, 0x00, 0x00, 0x35, 0x08, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x78, + 0x6c, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x62, 0x6f, 0x6f, 0x6b, 0x2e, 0x78, 0x6d, 0x6c, 0xac, 0x55, 0x6d, 0x6f, 0xa3, 0x38, 0x10, 0xfe, + 0x7e, 0xd2, 0xfd, 0x07, 0xc4, 0x77, 0x8a, 0x4d, 0xcc, 0x4b, 0x50, 0xe9, 0x2a, 0x90, 0xa0, 0xab, 0xb4, 0x5d, 0x55, 0x6d, 0xb6, 0xfb, + 0xf1, 0xe4, 0x80, 0x29, 0x56, 0x01, 0x73, 0xc6, 0x34, 0xa9, 0xaa, 0xfd, 0xef, 0x3b, 0x76, 0x42, 0xda, 0x6e, 0x57, 0xa7, 0x5c, 0xf7, + 0xaa, 0xd4, 0xc6, 0x9e, 0xe1, 0xf1, 0x33, 0x33, 0xcf, 0x98, 0xf3, 0x4f, 0xbb, 0xb6, 0xb1, 0x1e, 0x99, 0x1c, 0xb8, 0xe8, 0x12, 0x1b, + 0x9f, 0x21, 0xdb, 0x62, 0x5d, 0x21, 0x4a, 0xde, 0xdd, 0x27, 0xf6, 0xd7, 0x75, 0xee, 0x44, 0xb6, 0x35, 0x28, 0xda, 0x95, 0xb4, 0x11, + 0x1d, 0x4b, 0xec, 0x27, 0x36, 0xd8, 0x9f, 0x2e, 0xfe, 0xfc, 0xe3, 0x7c, 0x2b, 0xe4, 0xc3, 0x46, 0x88, 0x07, 0x0b, 0x00, 0xba, 0x21, + 0xb1, 0x6b, 0xa5, 0xfa, 0xd8, 0x75, 0x87, 0xa2, 0x66, 0x2d, 0x1d, 0xce, 0x44, 0xcf, 0x3a, 0xb0, 0x54, 0x42, 0xb6, 0x54, 0xc1, 0x52, + 0xde, 0xbb, 0x43, 0x2f, 0x19, 0x2d, 0x87, 0x9a, 0x31, 0xd5, 0x36, 0xae, 0x87, 0x50, 0xe0, 0xb6, 0x94, 0x77, 0xf6, 0x1e, 0x21, 0x96, + 0xa7, 0x60, 0x88, 0xaa, 0xe2, 0x05, 0x5b, 0x8a, 0x62, 0x6c, 0x59, 0xa7, 0xf6, 0x20, 0x92, 0x35, 0x54, 0x01, 0xfd, 0xa1, 0xe6, 0xfd, + 0x30, 0xa1, 0xb5, 0xc5, 0x29, 0x70, 0x2d, 0x95, 0x0f, 0x63, 0xef, 0x14, 0xa2, 0xed, 0x01, 0x62, 0xc3, 0x1b, 0xae, 0x9e, 0x0c, 0xa8, + 0x6d, 0xb5, 0x45, 0x7c, 0x79, 0xdf, 0x09, 0x49, 0x37, 0x0d, 0x84, 0xbd, 0xc3, 0xbe, 0xb5, 0x93, 0xf0, 0x0b, 0xe0, 0x1f, 0x23, 0x18, + 0xbc, 0xe9, 0x24, 0x30, 0xbd, 0x3b, 0xaa, 0xe5, 0x85, 0x14, 0x83, 0xa8, 0xd4, 0x19, 0x40, 0xbb, 0x7b, 0xd2, 0xef, 0xe2, 0xc7, 0xc8, + 0xc5, 0xf8, 0x4d, 0x0a, 0x76, 0xef, 0x73, 0x70, 0x1a, 0x12, 0x71, 0x25, 0x7b, 0xe4, 0xba, 0x86, 0x47, 0x56, 0x32, 0xf8, 0x20, 0xab, + 0xe0, 0x88, 0x15, 0xbc, 0x80, 0x61, 0xf4, 0xdb, 0x68, 0x18, 0xa4, 0x65, 0xb4, 0x12, 0x43, 0xf2, 0x3e, 0x88, 0xe6, 0x1f, 0xb9, 0x79, + 0xf6, 0xc5, 0x79, 0xc5, 0x1b, 0x76, 0xb7, 0x97, 0xae, 0x45, 0xfb, 0xfe, 0x0b, 0x6d, 0x75, 0xa5, 0x1a, 0xdb, 0x6a, 0xe8, 0xa0, 0x56, + 0x25, 0x57, 0xac, 0x4c, 0xec, 0x10, 0x96, 0x62, 0xcb, 0xde, 0x6c, 0xc8, 0xb1, 0x4f, 0x47, 0xde, 0x80, 0x15, 0xa3, 0x08, 0x7b, 0xb6, + 0x7b, 0x71, 0x94, 0xf3, 0xb5, 0xb4, 0x4a, 0x56, 0xd1, 0xb1, 0x51, 0x6b, 0x10, 0xf2, 0x04, 0x0f, 0x8e, 0x41, 0x30, 0xf7, 0x7c, 0xed, + 0x09, 0xc2, 0x58, 0x34, 0x8a, 0xc9, 0x8e, 0x2a, 0x96, 0x89, 0x4e, 0x81, 0x0e, 0x0f, 0x71, 0xfd, 0xae, 0xe6, 0x0c, 0x76, 0x56, 0x0b, + 0x50, 0xb8, 0x75, 0xc3, 0xfe, 0x19, 0xb9, 0x64, 0xd0, 0x58, 0xa0, 0x2f, 0x88, 0x15, 0x46, 0x5a, 0xc4, 0x74, 0x33, 0x5c, 0x53, 0x55, + 0x5b, 0xa3, 0x6c, 0x12, 0xdb, 0xfd, 0x3a, 0x40, 0xf0, 0xee, 0x5a, 0x8a, 0x06, 0xba, 0xd3, 0x5d, 0xb2, 0x47, 0xd6, 0x88, 0xde, 0xf4, + 0xc5, 0x86, 0x77, 0x5e, 0xe1, 0xbe, 0x52, 0x28, 0x7d, 0xdf, 0x0e, 0xff, 0x41, 0xa3, 0xb4, 0xd0, 0x81, 0xbb, 0x10, 0xf9, 0x9e, 0xdd, + 0xfe, 0xf9, 0xe7, 0x2c, 0x00, 0x49, 0x19, 0x4f, 0x3a, 0xbc, 0x56, 0xd2, 0x82, 0xe7, 0xcb, 0xe5, 0x67, 0xa8, 0xc5, 0x2d, 0x7d, 0x84, + 0xca, 0x40, 0xfd, 0xcb, 0x43, 0xe3, 0x5e, 0x42, 0xea, 0xa3, 0xbf, 0x9f, 0x17, 0xd9, 0x6c, 0xb6, 0x08, 0xf2, 0xd4, 0xc1, 0x01, 0x9a, + 0x39, 0x5e, 0x40, 0xb0, 0xb3, 0x20, 0x28, 0x77, 0xd2, 0x30, 0x0b, 0x73, 0x2f, 0x45, 0xab, 0x60, 0x1e, 0x7d, 0x87, 0x28, 0x64, 0x10, + 0x17, 0x82, 0x8e, 0xaa, 0x3e, 0x54, 0x5b, 0x63, 0x26, 0x36, 0x21, 0xbf, 0x30, 0x5d, 0xd1, 0xdd, 0x64, 0xc1, 0x28, 0x1e, 0x79, 0xf9, + 0x72, 0xfe, 0x33, 0x3a, 0xfc, 0x39, 0x7a, 0xfe, 0x69, 0x98, 0x6c, 0xdf, 0x75, 0xa4, 0xfa, 0x5e, 0xbb, 0xe3, 0x6c, 0x3b, 0xbc, 0xe8, + 0x42, 0x2f, 0xad, 0xdd, 0x37, 0xde, 0x95, 0x62, 0x9b, 0xd8, 0x5e, 0x18, 0x41, 0x34, 0x4f, 0xd3, 0x12, 0xfb, 0x01, 0x2c, 0xb7, 0xc6, + 0xf8, 0x8d, 0x97, 0xaa, 0x06, 0x8f, 0x08, 0x91, 0xe3, 0xde, 0x5f, 0x8c, 0xdf, 0xd7, 0xc0, 0x18, 0x87, 0x44, 0x6f, 0x82, 0xfe, 0x35, + 0xb3, 0xc4, 0x7e, 0xce, 0x73, 0x32, 0x4f, 0x23, 0xbc, 0x70, 0xb0, 0x17, 0x2e, 0x9c, 0x94, 0x90, 0x0c, 0x12, 0x40, 0x52, 0x27, 0xcf, + 0x51, 0x3e, 0x5b, 0xe5, 0x51, 0x9e, 0xe5, 0x73, 0xc3, 0xc8, 0x7d, 0x45, 0xc9, 0xdc, 0xa0, 0x40, 0xcd, 0xcc, 0x56, 0x67, 0x54, 0x7f, + 0xab, 0x6f, 0x55, 0x0c, 0x57, 0xb5, 0x9e, 0x75, 0x76, 0xe1, 0x59, 0xc6, 0xfa, 0x0c, 0x79, 0x59, 0x62, 0x53, 0xbd, 0xe9, 0xb5, 0x82, + 0x36, 0x05, 0xa8, 0x5c, 0x4f, 0xc6, 0x31, 0xc2, 0xc8, 0x9b, 0x6b, 0x0f, 0xb6, 0x53, 0x9f, 0x07, 0x65, 0x66, 0x10, 0x18, 0x07, 0x7a, + 0x98, 0xa0, 0x45, 0x88, 0xe6, 0xc4, 0x41, 0xab, 0x99, 0xef, 0x90, 0x68, 0xee, 0x39, 0x11, 0x99, 0x79, 0x4e, 0x46, 0x96, 0xde, 0xca, + 0x0f, 0x57, 0xcb, 0x55, 0xea, 0xeb, 0xfa, 0xe8, 0x2f, 0x40, 0xfc, 0x7f, 0xdc, 0x83, 0x46, 0xe7, 0xf1, 0xf4, 0x69, 0xd1, 0x2c, 0x6b, + 0x2a, 0xd5, 0x5a, 0xd2, 0xe2, 0x01, 0x3e, 0x48, 0x37, 0xac, 0x4a, 0xe9, 0x00, 0x4a, 0xda, 0x07, 0x04, 0x7c, 0x5f, 0x93, 0x4d, 0xfd, + 0x28, 0x45, 0x33, 0xa0, 0x48, 0x72, 0x9c, 0x3b, 0x04, 0xcf, 0x91, 0x93, 0xa6, 0x01, 0x71, 0xfc, 0x65, 0x3e, 0xf3, 0x43, 0xbc, 0xcc, + 0x56, 0x7e, 0xfe, 0x42, 0x56, 0x87, 0x5f, 0x7d, 0xf0, 0x16, 0x8a, 0x5c, 0xf3, 0x36, 0xa3, 0x6a, 0x84, 0x0e, 0xd5, 0xcd, 0x69, 0xd6, + 0xb1, 0x1e, 0xf3, 0xc3, 0xee, 0x71, 0xb3, 0xda, 0x6f, 0x1c, 0xea, 0xf4, 0xa6, 0xe9, 0xe2, 0x9b, 0xa5, 0xce, 0xfb, 0xe1, 0xed, 0x7f, + 0x73, 0xbc, 0x85, 0xe8, 0x1b, 0x76, 0xa2, 0x73, 0x7e, 0x77, 0xa2, 0x63, 0xf6, 0xe5, 0x6a, 0x7d, 0x65, 0xb4, 0xf1, 0xcb, 0x00, 0x5c, + 0x93, 0x60, 0x3d, 0x1a, 0x59, 0xb8, 0x53, 0x59, 0x2e, 0x7e, 0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0x00, 0x50, 0x4b, 0x03, 0x04, 0x14, + 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00, 0x21, 0x00, 0xf0, 0x08, 0x58, 0xf4, 0xa5, 0x02, 0x00, 0x00, 0x52, 0x06, 0x00, 0x00, 0x0d, + 0x00, 0x00, 0x00, 0x78, 0x6c, 0x2f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x73, 0x2e, 0x78, 0x6d, 0x6c, 0xa4, 0x55, 0x6d, 0x6b, 0xdb, 0x30, + 0x10, 0xfe, 0x3e, 0xd8, 0x7f, 0x10, 0xfa, 0xee, 0xca, 0x76, 0xe3, 0x2c, 0x09, 0xb6, 0xcb, 0xd2, 0xd4, 0x50, 0xe8, 0xc6, 0xa0, 0x1d, + 0xec, 0xab, 0x62, 0xcb, 0x89, 0xa8, 0x5e, 0x8c, 0x24, 0x67, 0xce, 0xc6, 0xfe, 0xfb, 0x4e, 0x76, 0x5e, 0x1c, 0x3a, 0xb6, 0xd1, 0x7e, + 0x89, 0x4e, 0xe7, 0xd3, 0x73, 0xcf, 0xdd, 0x73, 0x52, 0xd2, 0x9b, 0x4e, 0x0a, 0xb4, 0x63, 0xc6, 0x72, 0xad, 0x32, 0x1c, 0x5d, 0x85, + 0x18, 0x31, 0x55, 0xea, 0x8a, 0xab, 0x4d, 0x86, 0xbf, 0x3e, 0x15, 0xc1, 0x0c, 0x23, 0xeb, 0xa8, 0xaa, 0xa8, 0xd0, 0x8a, 0x65, 0x78, + 0xcf, 0x2c, 0xbe, 0xc9, 0xdf, 0xbf, 0x4b, 0xad, 0xdb, 0x0b, 0xf6, 0xb8, 0x65, 0xcc, 0x21, 0x80, 0x50, 0x36, 0xc3, 0x5b, 0xe7, 0x9a, + 0x05, 0x21, 0xb6, 0xdc, 0x32, 0x49, 0xed, 0x95, 0x6e, 0x98, 0x82, 0x2f, 0xb5, 0x36, 0x92, 0x3a, 0xd8, 0x9a, 0x0d, 0xb1, 0x8d, 0x61, + 0xb4, 0xb2, 0xfe, 0x90, 0x14, 0x24, 0x0e, 0xc3, 0x29, 0x91, 0x94, 0x2b, 0x3c, 0x20, 0x2c, 0x64, 0xf9, 0x3f, 0x20, 0x92, 0x9a, 0xe7, + 0xb6, 0x09, 0x4a, 0x2d, 0x1b, 0xea, 0xf8, 0x9a, 0x0b, 0xee, 0xf6, 0x3d, 0x16, 0x46, 0xb2, 0x5c, 0xdc, 0x6f, 0x94, 0x36, 0x74, 0x2d, + 0x80, 0x6a, 0x17, 0x4d, 0x68, 0x89, 0xba, 0x68, 0x6a, 0x62, 0xd4, 0x99, 0x63, 0x92, 0xde, 0xfb, 0x22, 0x8f, 0xe4, 0xa5, 0xd1, 0x56, + 0xd7, 0xee, 0x0a, 0x70, 0x89, 0xae, 0x6b, 0x5e, 0xb2, 0x97, 0x74, 0xe7, 0x64, 0x4e, 0x68, 0x79, 0x46, 0x02, 0xe4, 0xd7, 0x21, 0x45, + 0x09, 0x09, 0xe3, 0x8b, 0xda, 0x3b, 0xf3, 0x4a, 0xa4, 0x09, 0x31, 0x6c, 0xc7, 0xbd, 0x7c, 0x38, 0x4f, 0x6b, 0xad, 0x9c, 0x45, 0xa5, + 0x6e, 0x95, 0x03, 0x31, 0x81, 0xa8, 0x6f, 0xc1, 0xe2, 0x59, 0xe9, 0xef, 0xaa, 0xf0, 0x9f, 0xbc, 0x73, 0x88, 0xca, 0x53, 0xfb, 0x03, + 0xed, 0xa8, 0x00, 0x4f, 0x8c, 0x49, 0x9e, 0x96, 0x5a, 0x68, 0x83, 0x1c, 0x48, 0x07, 0x9d, 0x8b, 0xbc, 0x47, 0x51, 0xc9, 0x86, 0x88, + 0x5b, 0x2a, 0xf8, 0xda, 0x70, 0xef, 0xac, 0xa9, 0xe4, 0x62, 0x3f, 0xb8, 0xfb, 0x73, 0xbd, 0xda, 0x87, 0x38, 0xc9, 0xa1, 0xf7, 0x3e, + 0x8a, 0x78, 0x1e, 0x87, 0xc5, 0xc2, 0x21, 0x2e, 0xc4, 0x89, 0x55, 0xec, 0x09, 0x80, 0x23, 0x4f, 0x41, 0x3e, 0xc7, 0x8c, 0x2a, 0x60, + 0x83, 0x0e, 0xf6, 0xd3, 0xbe, 0x81, 0xf4, 0x0a, 0x26, 0x6d, 0x80, 0xe9, 0xe3, 0xfe, 0x11, 0xbd, 0x31, 0x74, 0x1f, 0xc5, 0xc9, 0xe8, + 0x00, 0xe9, 0x13, 0xe6, 0xe9, 0x5a, 0x9b, 0x0a, 0x26, 0xfb, 0xdc, 0x8f, 0xa3, 0x2b, 0x4f, 0x05, 0xab, 0x1d, 0x10, 0x35, 0x7c, 0xb3, + 0xf5, 0xab, 0xd3, 0x0d, 0xfc, 0xae, 0xb5, 0x73, 0xa0, 0x7e, 0x9e, 0x56, 0x9c, 0x6e, 0xb4, 0xa2, 0xc2, 0x97, 0x32, 0x80, 0x9c, 0x0c, + 0x28, 0xa7, 0x64, 0x42, 0x3c, 0xfa, 0xe9, 0xff, 0x56, 0x5f, 0x60, 0x77, 0x35, 0x52, 0xad, 0x2c, 0xa4, 0xbb, 0xaf, 0x32, 0x0c, 0xf7, + 0xc8, 0x37, 0xe1, 0x68, 0x42, 0x21, 0x07, 0x73, 0xc0, 0x1b, 0x36, 0x1e, 0x7f, 0x8c, 0x36, 0x60, 0xbf, 0x19, 0x16, 0x75, 0xf5, 0x25, + 0x3e, 0x20, 0x8e, 0x68, 0x5f, 0x90, 0x3e, 0xa5, 0x47, 0x5e, 0xef, 0x0c, 0x7f, 0xf6, 0xd7, 0x55, 0xc0, 0xe4, 0x1c, 0x20, 0xd0, 0xba, + 0xe5, 0xc2, 0x71, 0xf5, 0x07, 0xc2, 0x80, 0x59, 0x75, 0xe7, 0x16, 0x84, 0x5e, 0x01, 0xe7, 0xaf, 0x5e, 0xdf, 0x9c, 0x53, 0x16, 0xe8, + 0x44, 0xc5, 0x6a, 0xda, 0x0a, 0xf7, 0x74, 0xfa, 0x98, 0xe1, 0xb3, 0xfd, 0x89, 0x55, 0xbc, 0x95, 0xf1, 0x29, 0xea, 0x0b, 0xdf, 0x69, + 0xd7, 0x43, 0x64, 0xf8, 0x6c, 0x3f, 0x78, 0xa5, 0xa2, 0xa9, 0xcf, 0xc1, 0x3a, 0xf7, 0x60, 0x61, 0xbc, 0x60, 0x45, 0xad, 0xe1, 0x19, + 0xfe, 0x79, 0xb7, 0xfc, 0x30, 0x5f, 0xdd, 0x15, 0x71, 0x30, 0x0b, 0x97, 0xb3, 0x60, 0x72, 0xcd, 0x92, 0x60, 0x9e, 0x2c, 0x57, 0x41, + 0x32, 0xb9, 0x5d, 0xae, 0x56, 0xc5, 0x3c, 0x8c, 0xc3, 0xdb, 0x5f, 0xa3, 0x07, 0xe0, 0x0d, 0xd7, 0xbf, 0x7f, 0xaf, 0xf2, 0x14, 0x2e, + 0xd6, 0xc2, 0x0a, 0x78, 0x24, 0xcc, 0xa1, 0xd8, 0x43, 0x89, 0x8f, 0x67, 0x5f, 0x86, 0x47, 0x9b, 0x81, 0x7e, 0x3f, 0xa3, 0x40, 0x7b, + 0xcc, 0x7d, 0x1e, 0x4f, 0xc3, 0x8f, 0x49, 0x14, 0x06, 0xc5, 0x75, 0x18, 0x05, 0x93, 0x29, 0x9d, 0x05, 0xb3, 0xe9, 0x75, 0x12, 0x14, + 0x49, 0x14, 0xaf, 0xa6, 0x93, 0xe5, 0x5d, 0x52, 0x24, 0x23, 0xee, 0xc9, 0x2b, 0x9f, 0x89, 0x90, 0x44, 0xd1, 0xf0, 0xe0, 0x78, 0xf2, + 0xc9, 0xc2, 0x71, 0xc9, 0x04, 0x57, 0x47, 0xad, 0x8e, 0x0a, 0x8d, 0xbd, 0x20, 0x12, 0x6c, 0xff, 0x52, 0x04, 0x39, 0x2a, 0x41, 0xce, + 0x7f, 0x06, 0xf9, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0x00, 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x21, 0x00, 0xc1, 0x17, 0x10, 0xbe, 0x4e, 0x07, 0x00, 0x00, 0xc6, 0x20, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x78, 0x6c, 0x2f, + 0x74, 0x68, 0x65, 0x6d, 0x65, 0x2f, 0x74, 0x68, 0x65, 0x6d, 0x65, 0x31, 0x2e, 0x78, 0x6d, 0x6c, 0xec, 0x59, 0xcd, 0x8b, 0x1b, 0x37, + 0x14, 0xbf, 0x17, 0xfa, 0x3f, 0x0c, 0x73, 0x77, 0xfc, 0x35, 0xe3, 0x8f, 0x25, 0xde, 0xe0, 0xcf, 0x6c, 0x93, 0xdd, 0x24, 0x64, 0x9d, + 0x94, 0x1c, 0xb5, 0xb6, 0xec, 0x51, 0x56, 0x33, 0x32, 0x92, 0xbc, 0x1b, 0x13, 0x02, 0x25, 0x39, 0xf5, 0x52, 0x28, 0xa4, 0xa5, 0x97, + 0x42, 0x6f, 0x3d, 0x94, 0xd2, 0x40, 0x03, 0x0d, 0xbd, 0xf4, 0x8f, 0x09, 0x24, 0xb4, 0xe9, 0x1f, 0xd1, 0x27, 0xcd, 0xd8, 0x23, 0xad, + 0xe5, 0x24, 0x9b, 0x6c, 0x4a, 0x5a, 0x76, 0x0d, 0x8b, 0x47, 0xfe, 0xbd, 0xa7, 0xa7, 0xf7, 0x9e, 0x7e, 0x7a, 0xf3, 0x74, 0xf1, 0xd2, + 0xbd, 0x98, 0x7a, 0x47, 0x98, 0x0b, 0xc2, 0x92, 0x96, 0x5f, 0xbe, 0x50, 0xf2, 0x3d, 0x9c, 0x8c, 0xd8, 0x98, 0x24, 0xd3, 0x96, 0x7f, + 0x6b, 0x38, 0x28, 0x34, 0x7c, 0x4f, 0x48, 0x94, 0x8c, 0x11, 0x65, 0x09, 0x6e, 0xf9, 0x0b, 0x2c, 0xfc, 0x4b, 0xdb, 0x9f, 0x7e, 0x72, + 0x11, 0x6d, 0xc9, 0x08, 0xc7, 0xd8, 0x03, 0xf9, 0x44, 0x6c, 0xa1, 0x96, 0x1f, 0x49, 0x39, 0xdb, 0x2a, 0x16, 0xc5, 0x08, 0x86, 0x91, + 0xb8, 0xc0, 0x66, 0x38, 0x81, 0xdf, 0x26, 0x8c, 0xc7, 0x48, 0xc2, 0x23, 0x9f, 0x16, 0xc7, 0x1c, 0x1d, 0x83, 0xde, 0x98, 0x16, 0x2b, + 0xa5, 0x52, 0xad, 0x18, 0x23, 0x92, 0xf8, 0x5e, 0x82, 0x62, 0x50, 0x7b, 0x7d, 0x32, 0x21, 0x23, 0xec, 0x0d, 0x95, 0x4a, 0x7f, 0x7b, + 0xa9, 0xbc, 0x4f, 0xe1, 0x31, 0x91, 0x42, 0x0d, 0x8c, 0x28, 0xdf, 0x57, 0xaa, 0xb1, 0x25, 0xa1, 0xb1, 0xe3, 0xc3, 0xb2, 0x42, 0x88, + 0x85, 0xe8, 0x52, 0xee, 0x1d, 0x21, 0xda, 0xf2, 0x61, 0x9e, 0x31, 0x3b, 0x1e, 0xe2, 0x7b, 0xd2, 0xf7, 0x28, 0x12, 0x12, 0x7e, 0x68, + 0xf9, 0x25, 0xfd, 0xe7, 0x17, 0xb7, 0x2f, 0x16, 0xd1, 0x56, 0x26, 0x44, 0xe5, 0x06, 0x59, 0x43, 0x6e, 0xa0, 0xff, 0x32, 0xb9, 0x4c, + 0x60, 0x7c, 0x58, 0xd1, 0x73, 0xf2, 0xe9, 0xc1, 0x6a, 0xd2, 0x20, 0x08, 0x83, 0x5a, 0x7b, 0xa5, 0x5f, 0x03, 0xa8, 0x5c, 0xc7, 0xf5, + 0xeb, 0xfd, 0x5a, 0xbf, 0xb6, 0xd2, 0xa7, 0x01, 0x68, 0x34, 0x82, 0x95, 0xa6, 0xb6, 0xd8, 0x3a, 0xeb, 0x95, 0x6e, 0x90, 0x61, 0x0d, + 0x50, 0xfa, 0xd5, 0xa1, 0xbb, 0x57, 0xef, 0x55, 0xcb, 0x16, 0xde, 0xd0, 0x5f, 0x5d, 0xb3, 0xb9, 0x1d, 0xaa, 0x8f, 0x85, 0xd7, 0xa0, + 0x54, 0x7f, 0xb0, 0x86, 0x1f, 0x0c, 0xba, 0xe0, 0x45, 0x0b, 0xaf, 0x41, 0x29, 0x3e, 0x5c, 0xc3, 0x87, 0x9d, 0x66, 0xa7, 0x67, 0xeb, + 0xd7, 0xa0, 0x14, 0x5f, 0x5b, 0xc3, 0xd7, 0x4b, 0xed, 0x5e, 0x50, 0xb7, 0xf4, 0x6b, 0x50, 0x44, 0x49, 0x72, 0xb8, 0x86, 0x2e, 0x85, + 0xb5, 0x6a, 0x77, 0xb9, 0xda, 0x15, 0x64, 0xc2, 0xe8, 0x8e, 0x13, 0xde, 0x0c, 0x83, 0x41, 0xbd, 0x92, 0x29, 0xcf, 0x51, 0x90, 0x0d, + 0xab, 0xec, 0x52, 0x53, 0x4c, 0x58, 0x22, 0x37, 0xe5, 0x5a, 0x8c, 0xee, 0x32, 0x3e, 0x00, 0x80, 0x02, 0x52, 0x24, 0x49, 0xe2, 0xc9, + 0xc5, 0x0c, 0x4f, 0xd0, 0x08, 0xb2, 0xb8, 0x8b, 0x28, 0x39, 0xe0, 0xc4, 0xdb, 0x25, 0xd3, 0x08, 0x12, 0x6f, 0x86, 0x12, 0x26, 0x60, + 0xb8, 0x54, 0x29, 0x0d, 0x4a, 0x55, 0xf8, 0xaf, 0x3e, 0x81, 0xfe, 0xa6, 0x23, 0x8a, 0xb6, 0x30, 0x32, 0xa4, 0x95, 0x5d, 0x60, 0x89, + 0x58, 0x1b, 0x52, 0xf6, 0x78, 0x62, 0xc4, 0xc9, 0x4c, 0xb6, 0xfc, 0x2b, 0xa0, 0xd5, 0x37, 0x20, 0x2f, 0x9e, 0x3d, 0x7b, 0xfe, 0xf0, + 0xe9, 0xf3, 0x87, 0xbf, 0x3d, 0x7f, 0xf4, 0xe8, 0xf9, 0xc3, 0x5f, 0xb2, 0xb9, 0xb5, 0x2a, 0x4b, 0x6e, 0x07, 0x25, 0x53, 0x53, 0xee, + 0xd5, 0x8f, 0x5f, 0xff, 0xfd, 0xfd, 0x17, 0xde, 0x5f, 0xbf, 0xfe, 0xf0, 0xea, 0xf1, 0x37, 0xe9, 0xd4, 0x27, 0xf1, 0xc2, 0xc4, 0xbf, + 0xfc, 0xf9, 0xcb, 0x97, 0xbf, 0xff, 0xf1, 0x3a, 0xf5, 0xb0, 0xe2, 0xdc, 0x15, 0x2f, 0xbe, 0x7d, 0xf2, 0xf2, 0xe9, 0x93, 0x17, 0xdf, + 0x7d, 0xf5, 0xe7, 0x4f, 0x8f, 0x1d, 0xda, 0xdb, 0x1c, 0x1d, 0x98, 0xf0, 0x21, 0x89, 0xb1, 0xf0, 0xae, 0xe1, 0x63, 0xef, 0x26, 0x8b, + 0x61, 0x81, 0x0e, 0xfb, 0xf1, 0x01, 0x3f, 0x9d, 0xc4, 0x30, 0x42, 0xc4, 0x92, 0x40, 0x11, 0xe8, 0x76, 0xa8, 0xee, 0xcb, 0xc8, 0x02, + 0x5e, 0x5b, 0x20, 0xea, 0xc2, 0x75, 0xb0, 0xed, 0xc2, 0xdb, 0x1c, 0x58, 0xc6, 0x05, 0xbc, 0x3c, 0xbf, 0x6b, 0xd9, 0xba, 0x1f, 0xf1, + 0xb9, 0x24, 0x8e, 0x99, 0xaf, 0x46, 0xb1, 0x05, 0xdc, 0x63, 0x8c, 0x76, 0x18, 0x77, 0x3a, 0xe0, 0xaa, 0x9a, 0xcb, 0xf0, 0xf0, 0x70, + 0x9e, 0x4c, 0xdd, 0x93, 0xf3, 0xb9, 0x89, 0xbb, 0x89, 0xd0, 0x91, 0x6b, 0xee, 0x2e, 0x4a, 0xac, 0x00, 0xf7, 0xe7, 0x33, 0xa0, 0x57, + 0xe2, 0x52, 0xd9, 0x8d, 0xb0, 0x65, 0xe6, 0x0d, 0x8a, 0x12, 0x89, 0xa6, 0x38, 0xc1, 0xd2, 0x53, 0xbf, 0xb1, 0x43, 0x8c, 0x1d, 0xab, + 0xbb, 0x43, 0x88, 0xe5, 0xd7, 0x3d, 0x32, 0xe2, 0x4c, 0xb0, 0x89, 0xf4, 0xee, 0x10, 0xaf, 0x83, 0x88, 0xd3, 0x25, 0x43, 0x72, 0x60, + 0x25, 0x52, 0x2e, 0xb4, 0x43, 0x62, 0x88, 0xcb, 0xc2, 0x65, 0x20, 0x84, 0xda, 0xf2, 0xcd, 0xde, 0x6d, 0xaf, 0xc3, 0xa8, 0x6b, 0xd5, + 0x3d, 0x7c, 0x64, 0x23, 0x61, 0x5b, 0x20, 0xea, 0x30, 0x7e, 0x88, 0xa9, 0xe5, 0xc6, 0xcb, 0x68, 0x2e, 0x51, 0xec, 0x52, 0x39, 0x44, + 0x31, 0x35, 0x1d, 0xbe, 0x8b, 0x64, 0xe4, 0x32, 0x72, 0x7f, 0xc1, 0x47, 0x26, 0xae, 0x2f, 0x24, 0x44, 0x7a, 0x8a, 0x29, 0xf3, 0xfa, + 0x63, 0x2c, 0x84, 0x4b, 0xe6, 0x3a, 0x87, 0xf5, 0x1a, 0x41, 0xbf, 0x0a, 0x0c, 0xe3, 0x0e, 0xfb, 0x1e, 0x5d, 0xc4, 0x36, 0x92, 0x4b, + 0x72, 0xe8, 0xd2, 0xb9, 0x8b, 0x18, 0x33, 0x91, 0x3d, 0x76, 0xd8, 0x8d, 0x50, 0x3c, 0x73, 0xda, 0x4c, 0x92, 0xc8, 0xc4, 0x7e, 0x26, + 0x0e, 0x21, 0x45, 0x91, 0x77, 0x83, 0x49, 0x17, 0x7c, 0x8f, 0xd9, 0x3b, 0x44, 0x3d, 0x43, 0x1c, 0x50, 0xb2, 0x31, 0xdc, 0xb7, 0x09, + 0xb6, 0xc2, 0xfd, 0x66, 0x22, 0xb8, 0x05, 0xe4, 0x6a, 0x9a, 0x94, 0x27, 0x88, 0xfa, 0x65, 0xce, 0x1d, 0xb1, 0xbc, 0x8c, 0x99, 0xbd, + 0x1f, 0x17, 0x74, 0x82, 0xb0, 0x8b, 0x65, 0xda, 0x3c, 0xb6, 0xd8, 0xb5, 0xcd, 0x89, 0x33, 0x3b, 0x3a, 0xf3, 0xa9, 0x95, 0xda, 0xbb, + 0x18, 0x53, 0x74, 0x8c, 0xc6, 0x18, 0x7b, 0xb7, 0x3e, 0x73, 0x58, 0xd0, 0x61, 0x33, 0xcb, 0xe7, 0xb9, 0xd1, 0x57, 0x22, 0x60, 0x95, + 0x1d, 0xec, 0x4a, 0xac, 0x2b, 0xc8, 0xce, 0x55, 0xf5, 0x9c, 0x60, 0x01, 0x65, 0x92, 0xaa, 0x6b, 0xd6, 0x29, 0x72, 0x97, 0x08, 0x2b, + 0x65, 0xf7, 0xf1, 0x94, 0x6d, 0xb0, 0x67, 0x6f, 0x71, 0x82, 0x78, 0x16, 0x28, 0x89, 0x11, 0xdf, 0xa4, 0xf9, 0x1a, 0x44, 0xdd, 0x4a, + 0x5d, 0x38, 0xe5, 0x9c, 0x54, 0x7a, 0x9d, 0x8e, 0x0e, 0x4d, 0xe0, 0x35, 0x02, 0xe5, 0x1f, 0xe4, 0x8b, 0xd3, 0x29, 0xd7, 0x05, 0xe8, + 0x30, 0x92, 0xbb, 0xbf, 0x49, 0xeb, 0x8d, 0x08, 0x59, 0x67, 0x97, 0x7a, 0x16, 0xee, 0x7c, 0x5d, 0x70, 0x2b, 0x7e, 0x6f, 0xb3, 0xc7, + 0x60, 0x5f, 0xde, 0x3d, 0xed, 0xbe, 0x04, 0x19, 0x7c, 0x6a, 0x19, 0x20, 0xf6, 0xb7, 0xf6, 0xcd, 0x10, 0x51, 0x6b, 0x82, 0x3c, 0x61, + 0x86, 0x08, 0x0a, 0x0c, 0x17, 0xdd, 0x82, 0x88, 0x15, 0xfe, 0x5c, 0x44, 0x9d, 0xab, 0x5a, 0x6c, 0xee, 0x94, 0x9b, 0xd8, 0x9b, 0x36, + 0x0f, 0x03, 0x14, 0x46, 0x56, 0xbd, 0x13, 0x93, 0xe4, 0x8d, 0xc5, 0xcf, 0x89, 0xb2, 0x27, 0xfc, 0x77, 0xca, 0x1e, 0x77, 0x01, 0x73, + 0x06, 0x05, 0x8f, 0x5b, 0xf1, 0xfb, 0x94, 0x3a, 0x9b, 0x28, 0x65, 0xe7, 0x44, 0x81, 0xb3, 0x09, 0xf7, 0x1f, 0x2c, 0x6b, 0x7a, 0x68, + 0x9e, 0xdc, 0xc0, 0x70, 0x92, 0xac, 0x73, 0xd6, 0x79, 0x55, 0x73, 0x5e, 0xd5, 0xf8, 0xff, 0xfb, 0xaa, 0x66, 0xd3, 0x5e, 0x3e, 0xaf, + 0x65, 0xce, 0x6b, 0x99, 0xf3, 0x5a, 0xc6, 0xf5, 0xf6, 0xf5, 0x41, 0x6a, 0x99, 0xbc, 0x7c, 0x81, 0xca, 0x26, 0xef, 0xf2, 0xe8, 0x9e, + 0x4f, 0xbc, 0xb1, 0xe5, 0x33, 0x21, 0x94, 0xee, 0xcb, 0x05, 0xc5, 0xbb, 0x42, 0x77, 0x7d, 0x04, 0xbc, 0xd1, 0x8c, 0x07, 0x30, 0xa8, + 0xdb, 0x51, 0xba, 0x27, 0xb9, 0x6a, 0x01, 0xce, 0x22, 0xf8, 0x9a, 0x35, 0x98, 0x2c, 0xdc, 0x94, 0x23, 0x2d, 0xe3, 0x71, 0x26, 0x3f, + 0x27, 0x32, 0xda, 0x8f, 0xd0, 0x0c, 0x5a, 0x43, 0x65, 0xdd, 0xc0, 0x9c, 0x8a, 0x4c, 0xf5, 0x54, 0x78, 0x33, 0x26, 0xa0, 0x63, 0xa4, + 0x87, 0x75, 0x2b, 0x15, 0x9f, 0xd0, 0xad, 0xfb, 0x4e, 0xf3, 0x78, 0x8f, 0x8d, 0xd3, 0x4e, 0x67, 0xb9, 0xac, 0xba, 0x9a, 0xa9, 0x0b, + 0x05, 0x92, 0xf9, 0x78, 0x29, 0x5c, 0x8d, 0x43, 0x97, 0x4a, 0xa6, 0xe8, 0x5a, 0x3d, 0xef, 0xde, 0xad, 0xd4, 0xeb, 0x7e, 0xe8, 0x54, + 0x77, 0x59, 0x97, 0x06, 0x28, 0xd9, 0xd3, 0x18, 0x61, 0x4c, 0x66, 0x1b, 0x51, 0x75, 0x18, 0x51, 0x5f, 0x0e, 0x42, 0x14, 0x5e, 0x67, + 0x84, 0x5e, 0xd9, 0x99, 0x58, 0xd1, 0x74, 0x58, 0xd1, 0x50, 0xea, 0x97, 0xa1, 0x5a, 0x46, 0x71, 0xe5, 0x0a, 0x30, 0x6d, 0x15, 0x15, + 0x78, 0xe5, 0xf6, 0xe0, 0x45, 0xbd, 0xe5, 0x87, 0x41, 0xda, 0x41, 0x86, 0x66, 0x1c, 0x94, 0xe7, 0x63, 0x15, 0xa7, 0xb4, 0x99, 0xbc, + 0x8c, 0xae, 0x0a, 0xce, 0x99, 0x46, 0x7a, 0x93, 0x33, 0xa9, 0x99, 0x01, 0x50, 0x62, 0x2f, 0x33, 0x20, 0x8f, 0x74, 0x53, 0xd9, 0xba, + 0x71, 0x79, 0x6a, 0x75, 0x69, 0xaa, 0xbd, 0x45, 0xa4, 0x2d, 0x23, 0x8c, 0x74, 0xb3, 0x8d, 0x30, 0xd2, 0x30, 0x82, 0x17, 0xe1, 0x2c, + 0x3b, 0xcd, 0x96, 0xfb, 0x59, 0xc6, 0xba, 0x99, 0x87, 0xd4, 0x32, 0x4f, 0xb9, 0x62, 0xb9, 0x1b, 0x72, 0x33, 0xea, 0x8d, 0x0f, 0x11, + 0x6b, 0x45, 0x22, 0x27, 0xb8, 0x81, 0x26, 0x26, 0x53, 0xd0, 0xc4, 0x3b, 0x6e, 0xf9, 0xb5, 0x6a, 0x08, 0xb7, 0x2a, 0x23, 0x34, 0x6b, + 0xf9, 0x13, 0xe8, 0x18, 0xc3, 0xd7, 0x78, 0x06, 0xb9, 0x23, 0xd4, 0x5b, 0x17, 0xa2, 0x53, 0xb8, 0x76, 0x19, 0x49, 0x9e, 0x6e, 0xf8, + 0x77, 0x61, 0x96, 0x19, 0x17, 0xb2, 0x87, 0x44, 0x94, 0x3a, 0x5c, 0x93, 0x4e, 0xca, 0x06, 0x31, 0x91, 0x98, 0x7b, 0x94, 0xc4, 0x2d, + 0x5f, 0x2d, 0x7f, 0x95, 0x0d, 0x34, 0xd1, 0x1c, 0xa2, 0x6d, 0x2b, 0x57, 0x80, 0x10, 0x3e, 0x5a, 0xe3, 0x9a, 0x40, 0x2b, 0x1f, 0x9b, + 0x71, 0x10, 0x74, 0x3b, 0xc8, 0x78, 0x32, 0xc1, 0x23, 0x69, 0x86, 0xdd, 0x18, 0x51, 0x9e, 0x4e, 0x1f, 0x81, 0xe1, 0x53, 0xae, 0x70, + 0xfe, 0xaa, 0xc5, 0xdf, 0x1d, 0xac, 0x24, 0xd9, 0x1c, 0xc2, 0xbd, 0x1f, 0x8d, 0x8f, 0xbd, 0x03, 0x3a, 0xe7, 0x37, 0x11, 0xa4, 0x58, + 0x58, 0x2f, 0x2b, 0x07, 0x8e, 0x89, 0x80, 0x8b, 0x83, 0x72, 0xea, 0xcd, 0x31, 0x81, 0x9b, 0xb0, 0x15, 0x91, 0xe5, 0xf9, 0x77, 0xe2, + 0x60, 0xca, 0x68, 0xd7, 0xbc, 0x8a, 0xd2, 0x39, 0x94, 0x8e, 0x23, 0x3a, 0x8b, 0x50, 0x76, 0xa2, 0x98, 0x64, 0x9e, 0xc2, 0x35, 0x89, + 0xae, 0xcc, 0xd1, 0x4f, 0x2b, 0x1f, 0x18, 0x4f, 0xd9, 0x9a, 0xc1, 0xa1, 0xeb, 0x2e, 0x3c, 0x98, 0xaa, 0x03, 0xf6, 0xbd, 0x4f, 0xdd, + 0x37, 0x1f, 0xd5, 0xca, 0x73, 0x06, 0x69, 0xe6, 0x67, 0xa6, 0xc5, 0x2a, 0xea, 0xd4, 0x74, 0x93, 0xe9, 0x87, 0x3b, 0xe4, 0x0d, 0xab, + 0xf2, 0x43, 0xd4, 0xb2, 0x2a, 0xa5, 0x6e, 0xfd, 0x4e, 0x2d, 0x72, 0xae, 0x6b, 0x2e, 0xb9, 0x0e, 0x12, 0xd5, 0x79, 0x4a, 0xbc, 0xe1, + 0xd4, 0x7d, 0x8b, 0x03, 0xc1, 0x30, 0x2d, 0x9f, 0xcc, 0x32, 0x4d, 0x59, 0xbc, 0x4e, 0xc3, 0x8a, 0xb3, 0xb3, 0x51, 0xdb, 0xb4, 0x33, + 0x2c, 0x08, 0x0c, 0x4f, 0xd4, 0x36, 0xf8, 0x6d, 0x75, 0x46, 0x38, 0x3d, 0xf1, 0xae, 0x27, 0x3f, 0xc8, 0x9d, 0xcc, 0x5a, 0x75, 0x40, + 0x2c, 0xeb, 0x4a, 0x9d, 0xf8, 0xfa, 0xca, 0xdc, 0xbc, 0xd5, 0x66, 0x07, 0x77, 0x81, 0x3c, 0x7a, 0x70, 0x7f, 0x38, 0xa7, 0x52, 0xe8, + 0x50, 0x42, 0x6f, 0x97, 0x23, 0x28, 0xfa, 0xd2, 0x1b, 0xc8, 0x94, 0x36, 0x60, 0x8b, 0xdc, 0x93, 0x59, 0x8d, 0x08, 0xdf, 0xbc, 0x39, + 0x27, 0x2d, 0xff, 0x7e, 0x29, 0x6c, 0x07, 0xdd, 0x4a, 0xd8, 0x2d, 0x94, 0x1a, 0x61, 0xbf, 0x10, 0x54, 0x83, 0x52, 0xa1, 0x11, 0xb6, + 0xab, 0x85, 0x76, 0x18, 0x56, 0xcb, 0xfd, 0xb0, 0x5c, 0xea, 0x75, 0x2a, 0x0f, 0xe0, 0x60, 0x91, 0x51, 0x5c, 0x0e, 0xd3, 0xeb, 0xfa, + 0x01, 0x5c, 0x61, 0xd0, 0x45, 0x76, 0x69, 0xaf, 0xc7, 0xd7, 0x2e, 0xee, 0xe3, 0xe5, 0x2d, 0xcd, 0x85, 0x11, 0x8b, 0x8b, 0x4c, 0x5f, + 0xcc, 0x17, 0xb5, 0xe1, 0xfa, 0xe2, 0xbe, 0x5c, 0xd9, 0x7c, 0x71, 0xef, 0x11, 0x20, 0x9d, 0xfb, 0xb5, 0xca, 0xa0, 0x59, 0x6d, 0x76, + 0x6a, 0x85, 0x66, 0xb5, 0x3d, 0x28, 0x04, 0xbd, 0x4e, 0xa3, 0xd0, 0xec, 0xd6, 0x3a, 0x85, 0x5e, 0xad, 0x5b, 0xef, 0x0d, 0x7a, 0xdd, + 0xb0, 0xd1, 0x1c, 0x3c, 0xf0, 0xbd, 0x23, 0x0d, 0x0e, 0xda, 0xd5, 0x6e, 0x50, 0xeb, 0x37, 0x0a, 0xb5, 0x72, 0xb7, 0x5b, 0x08, 0x6a, + 0x25, 0x65, 0x7e, 0xa3, 0x59, 0xa8, 0x07, 0x95, 0x4a, 0x3b, 0xa8, 0xb7, 0x1b, 0xfd, 0xa0, 0xfd, 0x20, 0x2b, 0x63, 0x60, 0xe5, 0x29, + 0x7d, 0x64, 0xbe, 0x00, 0xf7, 0x6a, 0xbb, 0xb6, 0xff, 0x01, 0x00, 0x00, 0xff, 0xff, 0x03, 0x00, 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, + 0x06, 0x00, 0x08, 0x00, 0x00, 0x00, 0x21, 0x00, 0xff, 0x6b, 0x0c, 0xe9, 0xcd, 0x01, 0x00, 0x00, 0xb5, 0x03, 0x00, 0x00, 0x18, 0x00, + 0x00, 0x00, 0x78, 0x6c, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x68, 0x65, 0x65, 0x74, 0x73, 0x2f, 0x73, 0x68, 0x65, 0x65, 0x74, 0x31, + 0x2e, 0x78, 0x6d, 0x6c, 0x9c, 0x93, 0x4d, 0x8b, 0xdb, 0x30, 0x10, 0x86, 0xef, 0x85, 0xfe, 0x07, 0xa1, 0xbb, 0x2d, 0xdb, 0xf1, 0x3a, + 0x89, 0x89, 0xb3, 0x6c, 0x36, 0x0d, 0xdd, 0x43, 0xa1, 0xf4, 0xf3, 0x2c, 0xcb, 0x63, 0x5b, 0xc4, 0x92, 0x8c, 0xa4, 0x6c, 0x12, 0x4a, + 0xff, 0x7b, 0xc7, 0x0e, 0xf1, 0x16, 0x72, 0x09, 0x0b, 0x16, 0x68, 0xc6, 0x9a, 0x67, 0x66, 0xa4, 0x77, 0x56, 0x8f, 0x27, 0xd5, 0x91, + 0x57, 0xb0, 0x4e, 0x1a, 0x5d, 0xd0, 0x38, 0x8c, 0x28, 0x01, 0x2d, 0x4c, 0x25, 0x75, 0x53, 0xd0, 0x9f, 0x3f, 0x76, 0xc1, 0x82, 0x12, + 0xe7, 0xb9, 0xae, 0x78, 0x67, 0x34, 0x14, 0xf4, 0x0c, 0x8e, 0x3e, 0xae, 0x3f, 0x7e, 0x58, 0x1d, 0x8d, 0xdd, 0xbb, 0x16, 0xc0, 0x13, + 0x24, 0x68, 0x57, 0xd0, 0xd6, 0xfb, 0x3e, 0x67, 0xcc, 0x89, 0x16, 0x14, 0x77, 0xa1, 0xe9, 0x41, 0xe3, 0x9f, 0xda, 0x58, 0xc5, 0x3d, + 0x9a, 0xb6, 0x61, 0xae, 0xb7, 0xc0, 0xab, 0x31, 0x48, 0x75, 0x2c, 0x89, 0xa2, 0x8c, 0x29, 0x2e, 0x35, 0xbd, 0x10, 0x72, 0x7b, 0x0f, + 0xc3, 0xd4, 0xb5, 0x14, 0xb0, 0x35, 0xe2, 0xa0, 0x40, 0xfb, 0x0b, 0xc4, 0x42, 0xc7, 0x3d, 0xd6, 0xef, 0x5a, 0xd9, 0xbb, 0x2b, 0x4d, + 0x89, 0x7b, 0x70, 0x8a, 0xdb, 0xfd, 0xa1, 0x0f, 0x84, 0x51, 0x3d, 0x22, 0x4a, 0xd9, 0x49, 0x7f, 0x1e, 0xa1, 0x94, 0x28, 0x91, 0xbf, + 0x34, 0xda, 0x58, 0x5e, 0x76, 0xd8, 0xf7, 0x29, 0x4e, 0xb9, 0x20, 0x27, 0x8b, 0x5f, 0x82, 0x6b, 0x76, 0x4d, 0x33, 0xfa, 0x6f, 0x32, + 0x29, 0x29, 0xac, 0x71, 0xa6, 0xf6, 0x21, 0x92, 0xd9, 0xa5, 0xe6, 0xdb, 0xf6, 0x97, 0x6c, 0xc9, 0xb8, 0x98, 0x48, 0xb7, 0xfd, 0xdf, + 0x85, 0x89, 0x53, 0x66, 0xe1, 0x55, 0x0e, 0x0f, 0xf8, 0x86, 0x4a, 0xde, 0x57, 0x52, 0xfc, 0x30, 0xb1, 0x92, 0x37, 0xd8, 0xec, 0x9d, + 0xb0, 0x6c, 0x82, 0x0d, 0xd7, 0x65, 0xf3, 0x83, 0xac, 0x0a, 0xfa, 0x27, 0x4a, 0x97, 0xbb, 0x4d, 0xbc, 0x49, 0x83, 0xe4, 0x29, 0x8b, + 0x83, 0x34, 0x4b, 0x67, 0xc1, 0x62, 0x11, 0x67, 0xc1, 0x62, 0x33, 0xcf, 0x3e, 0x3d, 0xcf, 0xb2, 0xdd, 0x36, 0xdd, 0xfc, 0xa5, 0xeb, + 0x55, 0x25, 0xf1, 0x85, 0x87, 0xae, 0x88, 0x85, 0xba, 0xa0, 0x4f, 0x31, 0x65, 0xeb, 0xd5, 0x28, 0x9e, 0x5f, 0x12, 0x8e, 0xee, 0xbf, + 0x3d, 0xf1, 0xbc, 0xfc, 0x0e, 0x1d, 0x08, 0x0f, 0x98, 0x20, 0xa6, 0x64, 0xd0, 0x66, 0x69, 0xcc, 0x7e, 0x38, 0xf8, 0x82, 0xae, 0x68, + 0x08, 0x65, 0x37, 0xb1, 0xbb, 0x51, 0x9b, 0x5f, 0x2d, 0x29, 0xb9, 0x83, 0x67, 0xd3, 0xfd, 0x96, 0x95, 0x6f, 0x11, 0x80, 0x33, 0x50, + 0x41, 0xcd, 0x0f, 0x9d, 0xff, 0x66, 0x8e, 0x9f, 0x41, 0x36, 0xad, 0x47, 0x6f, 0x86, 0x3d, 0x0c, 0x22, 0xc8, 0xab, 0xf3, 0x16, 0x9c, + 0x40, 0xf5, 0x21, 0x38, 0x4c, 0xa6, 0xaa, 0xb6, 0xdc, 0x73, 0x4c, 0xd3, 0xf3, 0x06, 0xbe, 0x70, 0xdb, 0x48, 0xed, 0x48, 0x07, 0xf5, + 0x78, 0x68, 0x4e, 0x89, 0xbd, 0x50, 0xa2, 0x10, 0xf7, 0xde, 0xf4, 0x43, 0xe8, 0xfc, 0x81, 0x92, 0xd2, 0x78, 0x6f, 0xd4, 0xd5, 0x6a, + 0x71, 0x3c, 0x00, 0x65, 0x10, 0x85, 0x78, 0x61, 0xb5, 0x31, 0xfe, 0x6a, 0x0c, 0xe5, 0x4f, 0x03, 0xb7, 0xfe, 0x07, 0x00, 0x00, 0xff, + 0xff, 0x03, 0x00, 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00, 0x21, 0x00, 0xc2, 0x5e, 0x59, 0x08, 0x90, + 0x01, 0x00, 0x00, 0x1b, 0x03, 0x00, 0x00, 0x10, 0x00, 0x08, 0x01, 0x64, 0x6f, 0x63, 0x50, 0x72, 0x6f, 0x70, 0x73, 0x2f, 0x61, 0x70, + 0x70, 0x2e, 0x78, 0x6d, 0x6c, 0x20, 0xa2, 0x04, 0x01, 0x28, 0xa0, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x92, 0x4d, 0x6f, 0xdb, 0x30, 0x0c, 0x86, 0xef, 0x03, 0xfa, 0x1f, 0x0c, 0xdd, 0x1b, 0x39, 0x6d, + 0x51, 0x0c, 0x81, 0xac, 0x62, 0x48, 0x57, 0xf4, 0xb0, 0x62, 0x01, 0x92, 0x76, 0x67, 0x4e, 0xa6, 0x63, 0xa1, 0xb2, 0x24, 0x88, 0xac, + 0x91, 0xec, 0xd7, 0x4f, 0xb6, 0xd1, 0xd4, 0xd9, 0x76, 0xda, 0x8d, 0x1f, 0x2f, 0x5e, 0x3e, 0xa2, 0xa8, 0xee, 0x0e, 0x9d, 0x2b, 0x7a, + 0x4c, 0x64, 0x83, 0xaf, 0xc4, 0x72, 0x51, 0x8a, 0x02, 0xbd, 0x09, 0xb5, 0xf5, 0xfb, 0x4a, 0x3c, 0xef, 0x1e, 0x2e, 0x3f, 0x8b, 0x82, + 0x18, 0x7c, 0x0d, 0x2e, 0x78, 0xac, 0xc4, 0x11, 0x49, 0xdc, 0xe9, 0x8b, 0x4f, 0x6a, 0x93, 0x42, 0xc4, 0xc4, 0x16, 0xa9, 0xc8, 0x16, + 0x9e, 0x2a, 0xd1, 0x32, 0xc7, 0x95, 0x94, 0x64, 0x5a, 0xec, 0x80, 0x16, 0xb9, 0xed, 0x73, 0xa7, 0x09, 0xa9, 0x03, 0xce, 0x69, 0xda, + 0xcb, 0xd0, 0x34, 0xd6, 0xe0, 0x7d, 0x30, 0x6f, 0x1d, 0x7a, 0x96, 0x57, 0x65, 0x79, 0x2b, 0xf1, 0xc0, 0xe8, 0x6b, 0xac, 0x2f, 0xe3, + 0xc9, 0x50, 0x4c, 0x8e, 0xab, 0x9e, 0xff, 0xd7, 0xb4, 0x0e, 0x66, 0xe0, 0xa3, 0x97, 0xdd, 0x31, 0x66, 0x60, 0xad, 0xbe, 0xc4, 0xe8, + 0xac, 0x01, 0xce, 0xaf, 0xd4, 0x4f, 0xd6, 0xa4, 0x40, 0xa1, 0xe1, 0xe2, 0x09, 0x8c, 0xf5, 0x1c, 0xa8, 0x2d, 0xbe, 0x1e, 0x0c, 0x3a, + 0x25, 0xe7, 0x32, 0x95, 0x39, 0xb7, 0x68, 0xde, 0x92, 0xe5, 0xa3, 0x2e, 0x95, 0x9c, 0xa7, 0x6a, 0x6b, 0xc0, 0xe1, 0x3a, 0x8f, 0xd0, + 0x0d, 0x38, 0x42, 0x25, 0x3f, 0x0a, 0xea, 0x11, 0x61, 0x58, 0xdf, 0x06, 0x6c, 0x22, 0xad, 0x7a, 0x5e, 0xf5, 0x68, 0x38, 0xa4, 0x82, + 0xec, 0xaf, 0xbc, 0xc0, 0x2b, 0x51, 0xfc, 0x04, 0xc2, 0x01, 0xac, 0x12, 0x3d, 0x24, 0x0b, 0x9e, 0x33, 0xe0, 0x20, 0x9b, 0x92, 0x31, + 0x76, 0x91, 0x38, 0xe9, 0x1f, 0x21, 0xbd, 0x52, 0x8b, 0xc8, 0xa4, 0x64, 0x16, 0x4c, 0xc5, 0x31, 0x9c, 0x6b, 0xe7, 0xb1, 0xbd, 0xd1, + 0xcb, 0x51, 0x90, 0x83, 0x73, 0xe1, 0x60, 0x30, 0x81, 0xe4, 0xc6, 0x39, 0xe2, 0xce, 0xb2, 0x43, 0xfa, 0xde, 0x6c, 0x20, 0xf1, 0x3f, + 0x88, 0x97, 0x73, 0xe2, 0x91, 0x61, 0xe2, 0x9d, 0x70, 0xb6, 0x03, 0xdf, 0x34, 0x73, 0xce, 0x37, 0x3e, 0x39, 0x4f, 0xfa, 0xc3, 0x7b, + 0x1d, 0xba, 0x08, 0xfe, 0x98, 0x1b, 0xa7, 0xe8, 0x9b, 0xf5, 0xaf, 0xf4, 0x1c, 0x77, 0xe1, 0x1e, 0x18, 0xdf, 0xd7, 0x79, 0x5e, 0x54, + 0xdb, 0x16, 0x12, 0xd6, 0xf9, 0x07, 0x4e, 0xeb, 0x3e, 0x15, 0xd4, 0x63, 0xde, 0x64, 0x72, 0x83, 0xc9, 0xba, 0x05, 0xbf, 0xc7, 0xfa, + 0x5d, 0xf3, 0x77, 0x63, 0x38, 0x83, 0x97, 0xe9, 0xd6, 0xf5, 0xf2, 0x76, 0x51, 0x5e, 0x97, 0xf9, 0x5f, 0x67, 0x35, 0x25, 0x3f, 0xae, + 0x5a, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0x03, 0x00, 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00, 0x21, + 0x00, 0xbd, 0xde, 0xac, 0xb8, 0x45, 0x01, 0x00, 0x00, 0x6f, 0x02, 0x00, 0x00, 0x11, 0x00, 0x08, 0x01, 0x64, 0x6f, 0x63, 0x50, 0x72, + 0x6f, 0x70, 0x73, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x78, 0x6d, 0x6c, 0x20, 0xa2, 0x04, 0x01, 0x28, 0xa0, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0x92, 0x5f, 0x4b, 0xc3, 0x30, 0x14, 0xc5, 0xdf, 0x05, + 0xbf, 0x43, 0xc9, 0x7b, 0x9b, 0x66, 0x1b, 0x63, 0x96, 0xb6, 0x83, 0x29, 0x7b, 0xd1, 0x81, 0xe0, 0x44, 0xf1, 0x2d, 0x24, 0x77, 0x5b, + 0xb0, 0xf9, 0x43, 0x12, 0xd7, 0xed, 0xdb, 0x9b, 0xb6, 0x5b, 0xad, 0xd4, 0x17, 0x1f, 0x93, 0x73, 0xee, 0x2f, 0xe7, 0x5c, 0x92, 0x2f, + 0x4f, 0xb2, 0x8a, 0x8e, 0x60, 0x9d, 0xd0, 0xaa, 0x40, 0x24, 0x49, 0x51, 0x04, 0x8a, 0x69, 0x2e, 0xd4, 0xbe, 0x40, 0xaf, 0xdb, 0x75, + 0xbc, 0x40, 0x91, 0xf3, 0x54, 0x71, 0x5a, 0x69, 0x05, 0x05, 0x3a, 0x83, 0x43, 0xcb, 0xf2, 0xf6, 0x26, 0x67, 0x26, 0x63, 0xda, 0xc2, + 0xb3, 0xd5, 0x06, 0xac, 0x17, 0xe0, 0xa2, 0x40, 0x52, 0x2e, 0x63, 0xa6, 0x40, 0x07, 0xef, 0x4d, 0x86, 0xb1, 0x63, 0x07, 0x90, 0xd4, + 0x25, 0xc1, 0xa1, 0x82, 0xb8, 0xd3, 0x56, 0x52, 0x1f, 0x8e, 0x76, 0x8f, 0x0d, 0x65, 0x9f, 0x74, 0x0f, 0x78, 0x92, 0xa6, 0x73, 0x2c, + 0xc1, 0x53, 0x4e, 0x3d, 0xc5, 0x0d, 0x30, 0x36, 0x3d, 0x11, 0x5d, 0x90, 0x9c, 0xf5, 0x48, 0xf3, 0x65, 0xab, 0x16, 0xc0, 0x19, 0x86, + 0x0a, 0x24, 0x28, 0xef, 0x30, 0x49, 0x08, 0xfe, 0xf1, 0x7a, 0xb0, 0xd2, 0xfd, 0x39, 0xd0, 0x2a, 0x03, 0xa7, 0x14, 0xfe, 0x6c, 0x42, + 0xa7, 0x4b, 0xdc, 0x21, 0x9b, 0xb3, 0x4e, 0xec, 0xdd, 0x27, 0x27, 0x7a, 0x63, 0x5d, 0xd7, 0x49, 0x3d, 0x6d, 0x63, 0x84, 0xfc, 0x04, + 0xbf, 0x6f, 0x9e, 0x5e, 0xda, 0xaa, 0xb1, 0x50, 0xcd, 0xae, 0x18, 0xa0, 0x32, 0xe7, 0x2c, 0x63, 0x16, 0xa8, 0xd7, 0xb6, 0x7c, 0x04, + 0xa5, 0xc0, 0x1f, 0xa2, 0x15, 0xad, 0x5c, 0x05, 0xc7, 0x1c, 0x0f, 0xb4, 0x66, 0x8f, 0x15, 0x75, 0x7e, 0x13, 0x56, 0xbe, 0x13, 0xc0, + 0x57, 0xe7, 0xb1, 0x7d, 0x6c, 0x09, 0xf4, 0xb6, 0x4c, 0xf7, 0x04, 0xf0, 0x28, 0xc4, 0xcb, 0xba, 0x32, 0x57, 0xe5, 0x6d, 0x7a, 0xff, + 0xb0, 0x5d, 0xa3, 0x72, 0x92, 0x92, 0xbb, 0x38, 0x5d, 0xc4, 0x64, 0xbe, 0x4d, 0xd3, 0x6c, 0x3a, 0xcb, 0xc8, 0xec, 0xa3, 0x49, 0xf0, + 0x6b, 0xbe, 0x89, 0xdb, 0x5d, 0xc8, 0x4b, 0x8e, 0xff, 0x10, 0x27, 0xf3, 0x01, 0xf1, 0x0a, 0x28, 0x73, 0x3c, 0xfa, 0x22, 0xe5, 0x37, + 0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0x00, 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x02, 0x00, 0x08, 0x00, 0x9a, 0xab, 0x0f, 0x4f, 0x5e, + 0xff, 0xec, 0xaa, 0x93, 0x00, 0x00, 0x00, 0xb2, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x78, 0x6c, 0x2f, 0x73, 0x68, 0x61, 0x72, + 0x65, 0x64, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x78, 0x6d, 0x6c, 0x35, 0x8d, 0x41, 0x0a, 0xc2, 0x30, 0x10, 0x45, 0xf7, + 0x82, 0x77, 0x08, 0xb3, 0xd7, 0xa9, 0x2e, 0x44, 0x24, 0x49, 0x17, 0x82, 0x27, 0xd0, 0x03, 0x84, 0x76, 0x6c, 0x03, 0xcd, 0xa4, 0x66, + 0xa6, 0xa2, 0xb7, 0x37, 0x5d, 0xb8, 0xf8, 0xf0, 0x1f, 0x9f, 0xcf, 0xb3, 0xed, 0x27, 0x4d, 0xe6, 0x4d, 0x45, 0x62, 0x66, 0x07, 0x87, + 0x7d, 0x03, 0x86, 0xb8, 0xcb, 0x7d, 0xe4, 0xc1, 0xc1, 0xe3, 0x7e, 0xdb, 0x9d, 0xc1, 0x88, 0x06, 0xee, 0xc3, 0x94, 0x99, 0x1c, 0x7c, + 0x49, 0xa0, 0xf5, 0xdb, 0x8d, 0x15, 0x51, 0x53, 0xbf, 0x2c, 0x0e, 0x46, 0xd5, 0xf9, 0x82, 0x28, 0xdd, 0x48, 0x29, 0xc8, 0x3e, 0xcf, + 0xc4, 0x75, 0x79, 0xe6, 0x92, 0x82, 0x56, 0x2c, 0x03, 0xca, 0x5c, 0x28, 0xf4, 0x32, 0x12, 0x69, 0x9a, 0xf0, 0xd8, 0x34, 0x27, 0x4c, + 0x21, 0x32, 0x98, 0x2e, 0x2f, 0xac, 0xd5, 0x0b, 0x66, 0xe1, 0xf8, 0x5a, 0xe8, 0xfa, 0x67, 0x6f, 0x25, 0x7a, 0xab, 0xde, 0xe2, 0x9a, + 0xb5, 0x63, 0x35, 0x56, 0xf1, 0x0f, 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x02, 0x00, 0x08, 0x00, 0x99, 0x64, 0xef, 0x50, 0xd9, 0x19, + 0xd7, 0x73, 0x3f, 0x01, 0x00, 0x00, 0x7e, 0x04, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x5b, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x5f, 0x54, 0x79, 0x70, 0x65, 0x73, 0x5d, 0x2e, 0x78, 0x6d, 0x6c, 0xad, 0x93, 0xcd, 0x4e, 0xc3, 0x30, 0x10, 0x84, 0xef, 0x3c, 0x45, + 0xe4, 0x2b, 0x4a, 0xdc, 0x72, 0x40, 0x08, 0x35, 0xed, 0x81, 0x9f, 0x23, 0x54, 0xa2, 0x3c, 0x80, 0xb1, 0x37, 0x8d, 0xd5, 0xf8, 0x47, + 0xbb, 0x6e, 0x69, 0xdf, 0x9e, 0x4d, 0x52, 0x21, 0x40, 0x55, 0x03, 0xb4, 0x97, 0x58, 0xf1, 0xce, 0xcc, 0x37, 0x3e, 0xec, 0x64, 0xb6, + 0x75, 0x4d, 0xb6, 0x01, 0x24, 0x1b, 0x7c, 0x29, 0xc6, 0xc5, 0x48, 0x64, 0xe0, 0x75, 0x30, 0xd6, 0x2f, 0x4b, 0xf1, 0xba, 0x78, 0xcc, + 0x6f, 0xc4, 0x6c, 0x3a, 0x59, 0xec, 0x22, 0x50, 0xc6, 0x52, 0x4f, 0xa5, 0xa8, 0x53, 0x8a, 0xb7, 0x52, 0x92, 0xae, 0xc1, 0x29, 0x2a, + 0x42, 0x04, 0xcf, 0x93, 0x2a, 0xa0, 0x53, 0x89, 0x7f, 0x71, 0x29, 0xa3, 0xd2, 0x2b, 0xb5, 0x04, 0x79, 0x35, 0x1a, 0x5d, 0x4b, 0x1d, + 0x7c, 0x02, 0x9f, 0xf2, 0xd4, 0x66, 0x88, 0xe9, 0xe4, 0x1e, 0x2a, 0xb5, 0x6e, 0x52, 0xf6, 0xb0, 0xe5, 0xeb, 0x1e, 0x8b, 0xd0, 0x90, + 0xc8, 0xee, 0x7a, 0x61, 0xcb, 0x2a, 0x85, 0x8a, 0xb1, 0xb1, 0x5a, 0x25, 0x9e, 0xcb, 0x8d, 0x37, 0x3f, 0x28, 0xf9, 0x9e, 0x50, 0xb0, + 0xb3, 0xd3, 0x50, 0x6d, 0x23, 0x5d, 0xb2, 0x40, 0xc8, 0x83, 0x04, 0x9e, 0x1c, 0x01, 0xec, 0x7d, 0xcf, 0x1b, 0x40, 0xb4, 0x06, 0xb2, + 0xb9, 0xc2, 0xf4, 0xa4, 0x1c, 0xab, 0xe4, 0xb6, 0x91, 0xef, 0x01, 0x57, 0x6f, 0x21, 0xac, 0x0a, 0x96, 0xfd, 0xad, 0x65, 0xa8, 0x2a, + 0xab, 0xc1, 0x04, 0xbd, 0x76, 0x6c, 0x29, 0x28, 0x22, 0x28, 0x43, 0x35, 0x40, 0x72, 0x4d, 0xd1, 0x9d, 0x85, 0x53, 0xd6, 0x5f, 0x0e, + 0xf3, 0x3b, 0x31, 0xc9, 0xee, 0x18, 0x9f, 0xb9, 0xc8, 0x67, 0xfe, 0x40, 0x8f, 0x54, 0x83, 0x83, 0xfe, 0x7b, 0x7a, 0x85, 0x2e, 0x66, + 0x00, 0x48, 0x69, 0xd7, 0x00, 0x9d, 0x8c, 0xfa, 0xfe, 0xda, 0x3e, 0x74, 0x88, 0x5c, 0x2b, 0x04, 0xf3, 0x92, 0x90, 0xd7, 0xe0, 0xec, + 0x05, 0xbe, 0x64, 0x1f, 0xed, 0xc1, 0xfe, 0x39, 0x86, 0x48, 0x52, 0x07, 0x84, 0xb6, 0xc4, 0xff, 0x56, 0xa4, 0x75, 0xe7, 0x11, 0x79, + 0x8a, 0xc9, 0xc2, 0xef, 0x88, 0x1c, 0x7d, 0xf2, 0xab, 0xa1, 0xdd, 0x3e, 0x03, 0xe6, 0x00, 0x5b, 0xb6, 0x79, 0x34, 0xbd, 0xf8, 0x00, + 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x02, 0x00, 0x08, 0x00, 0xa7, 0x64, 0xef, 0x50, 0x59, 0xaf, 0xf9, 0x51, 0xdc, 0x00, 0x00, 0x00, + 0xa8, 0x02, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x78, 0x6c, 0x2f, 0x5f, 0x72, 0x65, 0x6c, 0x73, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x62, + 0x6f, 0x6f, 0x6b, 0x2e, 0x78, 0x6d, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x73, 0xad, 0x92, 0xcd, 0x6a, 0xc3, 0x30, 0x10, 0x84, 0xef, 0x7d, + 0x0a, 0xb1, 0xf7, 0x5a, 0x76, 0x5a, 0x4a, 0x29, 0x51, 0x72, 0x29, 0x85, 0x5c, 0xdb, 0xf4, 0x01, 0x84, 0xbc, 0xb6, 0x4c, 0x6c, 0x49, + 0xec, 0x6e, 0x7f, 0xf2, 0xf6, 0x11, 0x0e, 0x24, 0x31, 0x84, 0x90, 0x83, 0x4f, 0x62, 0x46, 0xda, 0x99, 0x4f, 0xb0, 0xcb, 0xf5, 0xff, + 0xd0, 0xab, 0x5f, 0x24, 0xee, 0x62, 0x30, 0x50, 0x15, 0x25, 0x28, 0x0c, 0x2e, 0xd6, 0x5d, 0x68, 0x0d, 0x7c, 0x6f, 0x3f, 0x1e, 0x5f, + 0x61, 0xbd, 0x5a, 0x7e, 0x62, 0x6f, 0x25, 0xbf, 0x60, 0xdf, 0x25, 0x56, 0x79, 0x24, 0xb0, 0x01, 0x2f, 0x92, 0xde, 0xb4, 0x66, 0xe7, + 0x71, 0xb0, 0x5c, 0xc4, 0x84, 0x21, 0xdf, 0x34, 0x91, 0x06, 0x2b, 0x59, 0x52, 0xab, 0x93, 0x75, 0x3b, 0xdb, 0xa2, 0x5e, 0x94, 0xe5, + 0x8b, 0xa6, 0xcb, 0x0c, 0x98, 0x66, 0xaa, 0x4d, 0x6d, 0x80, 0x36, 0xf5, 0x33, 0xa8, 0xed, 0x3e, 0xe1, 0x3d, 0xd9, 0xb1, 0x69, 0x3a, + 0x87, 0xef, 0xd1, 0xfd, 0x0c, 0x18, 0xe4, 0x4a, 0x85, 0x66, 0x6f, 0x09, 0xeb, 0x2f, 0xa1, 0xfc, 0x17, 0xce, 0xc1, 0x96, 0x5a, 0x14, + 0x03, 0x13, 0xbb, 0xc8, 0xa9, 0xa0, 0xaf, 0xc3, 0x3c, 0xcd, 0x0a, 0x23, 0xfb, 0x1e, 0x2f, 0x28, 0x46, 0x7d, 0xb3, 0x7e, 0x31, 0x67, + 0xbd, 0xe4, 0x59, 0x3c, 0xb7, 0x8f, 0xf2, 0x68, 0x56, 0xb7, 0x18, 0xaa, 0x39, 0x19, 0xfe, 0x22, 0xed, 0xd8, 0x23, 0xca, 0x99, 0xe3, + 0x64, 0xb1, 0x1e, 0x8f, 0x13, 0x8c, 0x9e, 0x6c, 0xdc, 0xea, 0xe1, 0x00, 0x50, 0x4b, 0x01, 0x02, 0x2d, 0x00, 0x14, 0x00, 0x06, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x21, 0x00, 0xb5, 0x55, 0x30, 0x23, 0xf4, 0x00, 0x00, 0x00, 0x4c, 0x02, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x72, 0x65, 0x6c, 0x73, 0x2f, 0x2e, 0x72, + 0x65, 0x6c, 0x73, 0x50, 0x4b, 0x01, 0x02, 0x2d, 0x00, 0x14, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00, 0x21, 0x00, 0x47, 0x88, 0xbc, + 0xe2, 0x5d, 0x03, 0x00, 0x00, 0x35, 0x08, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x25, 0x03, 0x00, 0x00, 0x78, 0x6c, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x62, 0x6f, 0x6f, 0x6b, 0x2e, 0x78, 0x6d, 0x6c, 0x50, 0x4b, + 0x01, 0x02, 0x2d, 0x00, 0x14, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00, 0x21, 0x00, 0xf0, 0x08, 0x58, 0xf4, 0xa5, 0x02, 0x00, 0x00, + 0x52, 0x06, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaf, 0x06, 0x00, 0x00, + 0x78, 0x6c, 0x2f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x73, 0x2e, 0x78, 0x6d, 0x6c, 0x50, 0x4b, 0x01, 0x02, 0x2d, 0x00, 0x14, 0x00, 0x06, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x21, 0x00, 0xc1, 0x17, 0x10, 0xbe, 0x4e, 0x07, 0x00, 0x00, 0xc6, 0x20, 0x00, 0x00, 0x13, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x09, 0x00, 0x00, 0x78, 0x6c, 0x2f, 0x74, 0x68, 0x65, 0x6d, + 0x65, 0x2f, 0x74, 0x68, 0x65, 0x6d, 0x65, 0x31, 0x2e, 0x78, 0x6d, 0x6c, 0x50, 0x4b, 0x01, 0x02, 0x2d, 0x00, 0x14, 0x00, 0x06, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x21, 0x00, 0xff, 0x6b, 0x0c, 0xe9, 0xcd, 0x01, 0x00, 0x00, 0xb5, 0x03, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x10, 0x00, 0x00, 0x78, 0x6c, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x73, + 0x68, 0x65, 0x65, 0x74, 0x73, 0x2f, 0x73, 0x68, 0x65, 0x65, 0x74, 0x31, 0x2e, 0x78, 0x6d, 0x6c, 0x50, 0x4b, 0x01, 0x02, 0x2d, 0x00, + 0x14, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00, 0x21, 0x00, 0xc2, 0x5e, 0x59, 0x08, 0x90, 0x01, 0x00, 0x00, 0x1b, 0x03, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x13, 0x00, 0x00, 0x64, 0x6f, 0x63, 0x50, + 0x72, 0x6f, 0x70, 0x73, 0x2f, 0x61, 0x70, 0x70, 0x2e, 0x78, 0x6d, 0x6c, 0x50, 0x4b, 0x01, 0x02, 0x2d, 0x00, 0x14, 0x00, 0x06, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x21, 0x00, 0xbd, 0xde, 0xac, 0xb8, 0x45, 0x01, 0x00, 0x00, 0x6f, 0x02, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc7, 0x15, 0x00, 0x00, 0x64, 0x6f, 0x63, 0x50, 0x72, 0x6f, 0x70, 0x73, + 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x78, 0x6d, 0x6c, 0x50, 0x4b, 0x01, 0x02, 0x14, 0x03, 0x14, 0x00, 0x02, 0x00, 0x08, 0x00, 0x9a, + 0xab, 0x0f, 0x4f, 0x5e, 0xff, 0xec, 0xaa, 0x93, 0x00, 0x00, 0x00, 0xb2, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0xb6, 0x81, 0x43, 0x18, 0x00, 0x00, 0x78, 0x6c, 0x2f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x53, 0x74, + 0x72, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x78, 0x6d, 0x6c, 0x50, 0x4b, 0x01, 0x02, 0x14, 0x03, 0x14, 0x00, 0x02, 0x00, 0x08, 0x00, 0x99, + 0x64, 0xef, 0x50, 0xd9, 0x19, 0xd7, 0x73, 0x3f, 0x01, 0x00, 0x00, 0x7e, 0x04, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0xb6, 0x81, 0x08, 0x19, 0x00, 0x00, 0x5b, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x54, 0x79, + 0x70, 0x65, 0x73, 0x5d, 0x2e, 0x78, 0x6d, 0x6c, 0x50, 0x4b, 0x01, 0x02, 0x14, 0x03, 0x14, 0x00, 0x02, 0x00, 0x08, 0x00, 0xa7, 0x64, + 0xef, 0x50, 0x59, 0xaf, 0xf9, 0x51, 0xdc, 0x00, 0x00, 0x00, 0xa8, 0x02, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0xb6, 0x81, 0x78, 0x1a, 0x00, 0x00, 0x78, 0x6c, 0x2f, 0x5f, 0x72, 0x65, 0x6c, 0x73, 0x2f, 0x77, 0x6f, 0x72, + 0x6b, 0x62, 0x6f, 0x6f, 0x6b, 0x2e, 0x78, 0x6d, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x73, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x0a, 0x00, 0x80, 0x02, 0x00, 0x00, 0x8c, 0x1b, 0x00, 0x00, 0x00, 0x00 + }; + } // namespace XLTemplate +} // namespace OpenXLSX #endif // OPENXLSX_XLTEMPLATES_HPP diff --git a/OpenXLSX/headers/XLWorkbook.hpp b/OpenXLSX/headers/XLWorkbook.hpp index e49e1b07..783ef893 100644 --- a/OpenXLSX/headers/XLWorkbook.hpp +++ b/OpenXLSX/headers/XLWorkbook.hpp @@ -345,12 +345,6 @@ namespace OpenXLSX private: // ---------- Private Member Functions ---------- // - /** - * @brief - * @return - */ - uint16_t createInternalSheetID(); - /** * @brief * @param sheetName diff --git a/OpenXLSX/sources/XLDocument.cpp b/OpenXLSX/sources/XLDocument.cpp index 8b8d11fd..a474e274 100644 --- a/OpenXLSX/sources/XLDocument.cpp +++ b/OpenXLSX/sources/XLDocument.cpp @@ -58,369 +58,11 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. #include "XLConstants.hpp" #include "XLDocument.hpp" #include "XLSheet.hpp" +#include "XLCellRange.hpp" #include "XLTemplates.hpp" using namespace OpenXLSX; -namespace -{ - const int templateSize = 7714; - const unsigned char templateData[7714] = { - 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00, 0x21, 0x00, 0xb5, 0x55, 0x30, 0x23, 0xf4, 0x00, 0x00, 0x00, - 0x4c, 0x02, 0x00, 0x00, 0x0b, 0x00, 0x08, 0x02, 0x5f, 0x72, 0x65, 0x6c, 0x73, 0x2f, 0x2e, 0x72, 0x65, 0x6c, 0x73, 0x20, 0xa2, 0x04, - 0x02, 0x28, 0xa0, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xac, 0x92, 0x4d, 0x4f, 0xc3, 0x30, 0x0c, 0x86, 0xef, 0x48, 0xfc, - 0x87, 0xc8, 0xf7, 0xd5, 0xdd, 0x90, 0x10, 0x42, 0x4b, 0x77, 0x41, 0x48, 0xbb, 0x21, 0x54, 0x7e, 0x80, 0x49, 0xdc, 0x0f, 0xb5, 0x8d, - 0xa3, 0x24, 0x1b, 0xdd, 0xbf, 0x27, 0x1c, 0x10, 0x54, 0x1a, 0x83, 0x03, 0x47, 0x7f, 0xbd, 0x7e, 0xfc, 0xca, 0xdb, 0xdd, 0x3c, 0x8d, - 0xea, 0xc8, 0x21, 0xf6, 0xe2, 0x34, 0xac, 0x8b, 0x12, 0x14, 0x3b, 0x23, 0xb6, 0x77, 0xad, 0x86, 0x97, 0xfa, 0x71, 0x75, 0x07, 0x2a, - 0x26, 0x72, 0x96, 0x46, 0x71, 0xac, 0xe1, 0xc4, 0x11, 0x76, 0xd5, 0xf5, 0xd5, 0xf6, 0x99, 0x47, 0x4a, 0x79, 0x28, 0x76, 0xbd, 0x8f, - 0x2a, 0xab, 0xb8, 0xa8, 0xa1, 0x4b, 0xc9, 0xdf, 0x23, 0x46, 0xd3, 0xf1, 0x44, 0xb1, 0x10, 0xcf, 0x2e, 0x57, 0x1a, 0x09, 0x13, 0xa5, - 0x1c, 0x86, 0x16, 0x3d, 0x99, 0x81, 0x5a, 0xc6, 0x4d, 0x59, 0xde, 0x62, 0xf8, 0xae, 0x01, 0xd5, 0x42, 0x53, 0xed, 0xad, 0x86, 0xb0, - 0xb7, 0x37, 0xa0, 0xea, 0x93, 0xcf, 0x9b, 0x7f, 0xd7, 0x96, 0xa6, 0xe9, 0x0d, 0x3f, 0x88, 0x39, 0x4c, 0xec, 0xd2, 0x99, 0x15, 0xc8, - 0x73, 0x62, 0x67, 0xd9, 0xae, 0x7c, 0xc8, 0x6c, 0x21, 0xf5, 0xf9, 0x1a, 0x55, 0x53, 0x68, 0x39, 0x69, 0xb0, 0x62, 0x9e, 0x72, 0x3a, - 0x22, 0x79, 0x5f, 0x64, 0x6c, 0xc0, 0xf3, 0x44, 0x9b, 0xbf, 0x13, 0xfd, 0x7c, 0x2d, 0x4e, 0x9c, 0xc8, 0x52, 0x22, 0x34, 0x12, 0xf8, - 0x32, 0xcf, 0x47, 0xc7, 0x25, 0xa0, 0xf5, 0x7f, 0x5a, 0xb4, 0x34, 0xf1, 0xcb, 0x9d, 0x79, 0xc4, 0x37, 0x09, 0xc3, 0xab, 0xc8, 0xf0, - 0xc9, 0x82, 0x8b, 0x1f, 0xa8, 0xde, 0x01, 0x00, 0x00, 0xff, 0xff, 0x03, 0x00, 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x06, 0x00, 0x08, - 0x00, 0x00, 0x00, 0x21, 0x00, 0x47, 0x88, 0xbc, 0xe2, 0x5d, 0x03, 0x00, 0x00, 0x35, 0x08, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x78, - 0x6c, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x62, 0x6f, 0x6f, 0x6b, 0x2e, 0x78, 0x6d, 0x6c, 0xac, 0x55, 0x6d, 0x6f, 0xa3, 0x38, 0x10, 0xfe, - 0x7e, 0xd2, 0xfd, 0x07, 0xc4, 0x77, 0x8a, 0x4d, 0xcc, 0x4b, 0x50, 0xe9, 0x2a, 0x90, 0xa0, 0xab, 0xb4, 0x5d, 0x55, 0x6d, 0xb6, 0xfb, - 0xf1, 0xe4, 0x80, 0x29, 0x56, 0x01, 0x73, 0xc6, 0x34, 0xa9, 0xaa, 0xfd, 0xef, 0x3b, 0x76, 0x42, 0xda, 0x6e, 0x57, 0xa7, 0x5c, 0xf7, - 0xaa, 0xd4, 0xc6, 0x9e, 0xe1, 0xf1, 0x33, 0x33, 0xcf, 0x98, 0xf3, 0x4f, 0xbb, 0xb6, 0xb1, 0x1e, 0x99, 0x1c, 0xb8, 0xe8, 0x12, 0x1b, - 0x9f, 0x21, 0xdb, 0x62, 0x5d, 0x21, 0x4a, 0xde, 0xdd, 0x27, 0xf6, 0xd7, 0x75, 0xee, 0x44, 0xb6, 0x35, 0x28, 0xda, 0x95, 0xb4, 0x11, - 0x1d, 0x4b, 0xec, 0x27, 0x36, 0xd8, 0x9f, 0x2e, 0xfe, 0xfc, 0xe3, 0x7c, 0x2b, 0xe4, 0xc3, 0x46, 0x88, 0x07, 0x0b, 0x00, 0xba, 0x21, - 0xb1, 0x6b, 0xa5, 0xfa, 0xd8, 0x75, 0x87, 0xa2, 0x66, 0x2d, 0x1d, 0xce, 0x44, 0xcf, 0x3a, 0xb0, 0x54, 0x42, 0xb6, 0x54, 0xc1, 0x52, - 0xde, 0xbb, 0x43, 0x2f, 0x19, 0x2d, 0x87, 0x9a, 0x31, 0xd5, 0x36, 0xae, 0x87, 0x50, 0xe0, 0xb6, 0x94, 0x77, 0xf6, 0x1e, 0x21, 0x96, - 0xa7, 0x60, 0x88, 0xaa, 0xe2, 0x05, 0x5b, 0x8a, 0x62, 0x6c, 0x59, 0xa7, 0xf6, 0x20, 0x92, 0x35, 0x54, 0x01, 0xfd, 0xa1, 0xe6, 0xfd, - 0x30, 0xa1, 0xb5, 0xc5, 0x29, 0x70, 0x2d, 0x95, 0x0f, 0x63, 0xef, 0x14, 0xa2, 0xed, 0x01, 0x62, 0xc3, 0x1b, 0xae, 0x9e, 0x0c, 0xa8, - 0x6d, 0xb5, 0x45, 0x7c, 0x79, 0xdf, 0x09, 0x49, 0x37, 0x0d, 0x84, 0xbd, 0xc3, 0xbe, 0xb5, 0x93, 0xf0, 0x0b, 0xe0, 0x1f, 0x23, 0x18, - 0xbc, 0xe9, 0x24, 0x30, 0xbd, 0x3b, 0xaa, 0xe5, 0x85, 0x14, 0x83, 0xa8, 0xd4, 0x19, 0x40, 0xbb, 0x7b, 0xd2, 0xef, 0xe2, 0xc7, 0xc8, - 0xc5, 0xf8, 0x4d, 0x0a, 0x76, 0xef, 0x73, 0x70, 0x1a, 0x12, 0x71, 0x25, 0x7b, 0xe4, 0xba, 0x86, 0x47, 0x56, 0x32, 0xf8, 0x20, 0xab, - 0xe0, 0x88, 0x15, 0xbc, 0x80, 0x61, 0xf4, 0xdb, 0x68, 0x18, 0xa4, 0x65, 0xb4, 0x12, 0x43, 0xf2, 0x3e, 0x88, 0xe6, 0x1f, 0xb9, 0x79, - 0xf6, 0xc5, 0x79, 0xc5, 0x1b, 0x76, 0xb7, 0x97, 0xae, 0x45, 0xfb, 0xfe, 0x0b, 0x6d, 0x75, 0xa5, 0x1a, 0xdb, 0x6a, 0xe8, 0xa0, 0x56, - 0x25, 0x57, 0xac, 0x4c, 0xec, 0x10, 0x96, 0x62, 0xcb, 0xde, 0x6c, 0xc8, 0xb1, 0x4f, 0x47, 0xde, 0x80, 0x15, 0xa3, 0x08, 0x7b, 0xb6, - 0x7b, 0x71, 0x94, 0xf3, 0xb5, 0xb4, 0x4a, 0x56, 0xd1, 0xb1, 0x51, 0x6b, 0x10, 0xf2, 0x04, 0x0f, 0x8e, 0x41, 0x30, 0xf7, 0x7c, 0xed, - 0x09, 0xc2, 0x58, 0x34, 0x8a, 0xc9, 0x8e, 0x2a, 0x96, 0x89, 0x4e, 0x81, 0x0e, 0x0f, 0x71, 0xfd, 0xae, 0xe6, 0x0c, 0x76, 0x56, 0x0b, - 0x50, 0xb8, 0x75, 0xc3, 0xfe, 0x19, 0xb9, 0x64, 0xd0, 0x58, 0xa0, 0x2f, 0x88, 0x15, 0x46, 0x5a, 0xc4, 0x74, 0x33, 0x5c, 0x53, 0x55, - 0x5b, 0xa3, 0x6c, 0x12, 0xdb, 0xfd, 0x3a, 0x40, 0xf0, 0xee, 0x5a, 0x8a, 0x06, 0xba, 0xd3, 0x5d, 0xb2, 0x47, 0xd6, 0x88, 0xde, 0xf4, - 0xc5, 0x86, 0x77, 0x5e, 0xe1, 0xbe, 0x52, 0x28, 0x7d, 0xdf, 0x0e, 0xff, 0x41, 0xa3, 0xb4, 0xd0, 0x81, 0xbb, 0x10, 0xf9, 0x9e, 0xdd, - 0xfe, 0xf9, 0xe7, 0x2c, 0x00, 0x49, 0x19, 0x4f, 0x3a, 0xbc, 0x56, 0xd2, 0x82, 0xe7, 0xcb, 0xe5, 0x67, 0xa8, 0xc5, 0x2d, 0x7d, 0x84, - 0xca, 0x40, 0xfd, 0xcb, 0x43, 0xe3, 0x5e, 0x42, 0xea, 0xa3, 0xbf, 0x9f, 0x17, 0xd9, 0x6c, 0xb6, 0x08, 0xf2, 0xd4, 0xc1, 0x01, 0x9a, - 0x39, 0x5e, 0x40, 0xb0, 0xb3, 0x20, 0x28, 0x77, 0xd2, 0x30, 0x0b, 0x73, 0x2f, 0x45, 0xab, 0x60, 0x1e, 0x7d, 0x87, 0x28, 0x64, 0x10, - 0x17, 0x82, 0x8e, 0xaa, 0x3e, 0x54, 0x5b, 0x63, 0x26, 0x36, 0x21, 0xbf, 0x30, 0x5d, 0xd1, 0xdd, 0x64, 0xc1, 0x28, 0x1e, 0x79, 0xf9, - 0x72, 0xfe, 0x33, 0x3a, 0xfc, 0x39, 0x7a, 0xfe, 0x69, 0x98, 0x6c, 0xdf, 0x75, 0xa4, 0xfa, 0x5e, 0xbb, 0xe3, 0x6c, 0x3b, 0xbc, 0xe8, - 0x42, 0x2f, 0xad, 0xdd, 0x37, 0xde, 0x95, 0x62, 0x9b, 0xd8, 0x5e, 0x18, 0x41, 0x34, 0x4f, 0xd3, 0x12, 0xfb, 0x01, 0x2c, 0xb7, 0xc6, - 0xf8, 0x8d, 0x97, 0xaa, 0x06, 0x8f, 0x08, 0x91, 0xe3, 0xde, 0x5f, 0x8c, 0xdf, 0xd7, 0xc0, 0x18, 0x87, 0x44, 0x6f, 0x82, 0xfe, 0x35, - 0xb3, 0xc4, 0x7e, 0xce, 0x73, 0x32, 0x4f, 0x23, 0xbc, 0x70, 0xb0, 0x17, 0x2e, 0x9c, 0x94, 0x90, 0x0c, 0x12, 0x40, 0x52, 0x27, 0xcf, - 0x51, 0x3e, 0x5b, 0xe5, 0x51, 0x9e, 0xe5, 0x73, 0xc3, 0xc8, 0x7d, 0x45, 0xc9, 0xdc, 0xa0, 0x40, 0xcd, 0xcc, 0x56, 0x67, 0x54, 0x7f, - 0xab, 0x6f, 0x55, 0x0c, 0x57, 0xb5, 0x9e, 0x75, 0x76, 0xe1, 0x59, 0xc6, 0xfa, 0x0c, 0x79, 0x59, 0x62, 0x53, 0xbd, 0xe9, 0xb5, 0x82, - 0x36, 0x05, 0xa8, 0x5c, 0x4f, 0xc6, 0x31, 0xc2, 0xc8, 0x9b, 0x6b, 0x0f, 0xb6, 0x53, 0x9f, 0x07, 0x65, 0x66, 0x10, 0x18, 0x07, 0x7a, - 0x98, 0xa0, 0x45, 0x88, 0xe6, 0xc4, 0x41, 0xab, 0x99, 0xef, 0x90, 0x68, 0xee, 0x39, 0x11, 0x99, 0x79, 0x4e, 0x46, 0x96, 0xde, 0xca, - 0x0f, 0x57, 0xcb, 0x55, 0xea, 0xeb, 0xfa, 0xe8, 0x2f, 0x40, 0xfc, 0x7f, 0xdc, 0x83, 0x46, 0xe7, 0xf1, 0xf4, 0x69, 0xd1, 0x2c, 0x6b, - 0x2a, 0xd5, 0x5a, 0xd2, 0xe2, 0x01, 0x3e, 0x48, 0x37, 0xac, 0x4a, 0xe9, 0x00, 0x4a, 0xda, 0x07, 0x04, 0x7c, 0x5f, 0x93, 0x4d, 0xfd, - 0x28, 0x45, 0x33, 0xa0, 0x48, 0x72, 0x9c, 0x3b, 0x04, 0xcf, 0x91, 0x93, 0xa6, 0x01, 0x71, 0xfc, 0x65, 0x3e, 0xf3, 0x43, 0xbc, 0xcc, - 0x56, 0x7e, 0xfe, 0x42, 0x56, 0x87, 0x5f, 0x7d, 0xf0, 0x16, 0x8a, 0x5c, 0xf3, 0x36, 0xa3, 0x6a, 0x84, 0x0e, 0xd5, 0xcd, 0x69, 0xd6, - 0xb1, 0x1e, 0xf3, 0xc3, 0xee, 0x71, 0xb3, 0xda, 0x6f, 0x1c, 0xea, 0xf4, 0xa6, 0xe9, 0xe2, 0x9b, 0xa5, 0xce, 0xfb, 0xe1, 0xed, 0x7f, - 0x73, 0xbc, 0x85, 0xe8, 0x1b, 0x76, 0xa2, 0x73, 0x7e, 0x77, 0xa2, 0x63, 0xf6, 0xe5, 0x6a, 0x7d, 0x65, 0xb4, 0xf1, 0xcb, 0x00, 0x5c, - 0x93, 0x60, 0x3d, 0x1a, 0x59, 0xb8, 0x53, 0x59, 0x2e, 0x7e, 0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0x00, 0x50, 0x4b, 0x03, 0x04, 0x14, - 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00, 0x21, 0x00, 0xf0, 0x08, 0x58, 0xf4, 0xa5, 0x02, 0x00, 0x00, 0x52, 0x06, 0x00, 0x00, 0x0d, - 0x00, 0x00, 0x00, 0x78, 0x6c, 0x2f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x73, 0x2e, 0x78, 0x6d, 0x6c, 0xa4, 0x55, 0x6d, 0x6b, 0xdb, 0x30, - 0x10, 0xfe, 0x3e, 0xd8, 0x7f, 0x10, 0xfa, 0xee, 0xca, 0x76, 0xe3, 0x2c, 0x09, 0xb6, 0xcb, 0xd2, 0xd4, 0x50, 0xe8, 0xc6, 0xa0, 0x1d, - 0xec, 0xab, 0x62, 0xcb, 0x89, 0xa8, 0x5e, 0x8c, 0x24, 0x67, 0xce, 0xc6, 0xfe, 0xfb, 0x4e, 0x76, 0x5e, 0x1c, 0x3a, 0xb6, 0xd1, 0x7e, - 0x89, 0x4e, 0xe7, 0xd3, 0x73, 0xcf, 0xdd, 0x73, 0x52, 0xd2, 0x9b, 0x4e, 0x0a, 0xb4, 0x63, 0xc6, 0x72, 0xad, 0x32, 0x1c, 0x5d, 0x85, - 0x18, 0x31, 0x55, 0xea, 0x8a, 0xab, 0x4d, 0x86, 0xbf, 0x3e, 0x15, 0xc1, 0x0c, 0x23, 0xeb, 0xa8, 0xaa, 0xa8, 0xd0, 0x8a, 0x65, 0x78, - 0xcf, 0x2c, 0xbe, 0xc9, 0xdf, 0xbf, 0x4b, 0xad, 0xdb, 0x0b, 0xf6, 0xb8, 0x65, 0xcc, 0x21, 0x80, 0x50, 0x36, 0xc3, 0x5b, 0xe7, 0x9a, - 0x05, 0x21, 0xb6, 0xdc, 0x32, 0x49, 0xed, 0x95, 0x6e, 0x98, 0x82, 0x2f, 0xb5, 0x36, 0x92, 0x3a, 0xd8, 0x9a, 0x0d, 0xb1, 0x8d, 0x61, - 0xb4, 0xb2, 0xfe, 0x90, 0x14, 0x24, 0x0e, 0xc3, 0x29, 0x91, 0x94, 0x2b, 0x3c, 0x20, 0x2c, 0x64, 0xf9, 0x3f, 0x20, 0x92, 0x9a, 0xe7, - 0xb6, 0x09, 0x4a, 0x2d, 0x1b, 0xea, 0xf8, 0x9a, 0x0b, 0xee, 0xf6, 0x3d, 0x16, 0x46, 0xb2, 0x5c, 0xdc, 0x6f, 0x94, 0x36, 0x74, 0x2d, - 0x80, 0x6a, 0x17, 0x4d, 0x68, 0x89, 0xba, 0x68, 0x6a, 0x62, 0xd4, 0x99, 0x63, 0x92, 0xde, 0xfb, 0x22, 0x8f, 0xe4, 0xa5, 0xd1, 0x56, - 0xd7, 0xee, 0x0a, 0x70, 0x89, 0xae, 0x6b, 0x5e, 0xb2, 0x97, 0x74, 0xe7, 0x64, 0x4e, 0x68, 0x79, 0x46, 0x02, 0xe4, 0xd7, 0x21, 0x45, - 0x09, 0x09, 0xe3, 0x8b, 0xda, 0x3b, 0xf3, 0x4a, 0xa4, 0x09, 0x31, 0x6c, 0xc7, 0xbd, 0x7c, 0x38, 0x4f, 0x6b, 0xad, 0x9c, 0x45, 0xa5, - 0x6e, 0x95, 0x03, 0x31, 0x81, 0xa8, 0x6f, 0xc1, 0xe2, 0x59, 0xe9, 0xef, 0xaa, 0xf0, 0x9f, 0xbc, 0x73, 0x88, 0xca, 0x53, 0xfb, 0x03, - 0xed, 0xa8, 0x00, 0x4f, 0x8c, 0x49, 0x9e, 0x96, 0x5a, 0x68, 0x83, 0x1c, 0x48, 0x07, 0x9d, 0x8b, 0xbc, 0x47, 0x51, 0xc9, 0x86, 0x88, - 0x5b, 0x2a, 0xf8, 0xda, 0x70, 0xef, 0xac, 0xa9, 0xe4, 0x62, 0x3f, 0xb8, 0xfb, 0x73, 0xbd, 0xda, 0x87, 0x38, 0xc9, 0xa1, 0xf7, 0x3e, - 0x8a, 0x78, 0x1e, 0x87, 0xc5, 0xc2, 0x21, 0x2e, 0xc4, 0x89, 0x55, 0xec, 0x09, 0x80, 0x23, 0x4f, 0x41, 0x3e, 0xc7, 0x8c, 0x2a, 0x60, - 0x83, 0x0e, 0xf6, 0xd3, 0xbe, 0x81, 0xf4, 0x0a, 0x26, 0x6d, 0x80, 0xe9, 0xe3, 0xfe, 0x11, 0xbd, 0x31, 0x74, 0x1f, 0xc5, 0xc9, 0xe8, - 0x00, 0xe9, 0x13, 0xe6, 0xe9, 0x5a, 0x9b, 0x0a, 0x26, 0xfb, 0xdc, 0x8f, 0xa3, 0x2b, 0x4f, 0x05, 0xab, 0x1d, 0x10, 0x35, 0x7c, 0xb3, - 0xf5, 0xab, 0xd3, 0x0d, 0xfc, 0xae, 0xb5, 0x73, 0xa0, 0x7e, 0x9e, 0x56, 0x9c, 0x6e, 0xb4, 0xa2, 0xc2, 0x97, 0x32, 0x80, 0x9c, 0x0c, - 0x28, 0xa7, 0x64, 0x42, 0x3c, 0xfa, 0xe9, 0xff, 0x56, 0x5f, 0x60, 0x77, 0x35, 0x52, 0xad, 0x2c, 0xa4, 0xbb, 0xaf, 0x32, 0x0c, 0xf7, - 0xc8, 0x37, 0xe1, 0x68, 0x42, 0x21, 0x07, 0x73, 0xc0, 0x1b, 0x36, 0x1e, 0x7f, 0x8c, 0x36, 0x60, 0xbf, 0x19, 0x16, 0x75, 0xf5, 0x25, - 0x3e, 0x20, 0x8e, 0x68, 0x5f, 0x90, 0x3e, 0xa5, 0x47, 0x5e, 0xef, 0x0c, 0x7f, 0xf6, 0xd7, 0x55, 0xc0, 0xe4, 0x1c, 0x20, 0xd0, 0xba, - 0xe5, 0xc2, 0x71, 0xf5, 0x07, 0xc2, 0x80, 0x59, 0x75, 0xe7, 0x16, 0x84, 0x5e, 0x01, 0xe7, 0xaf, 0x5e, 0xdf, 0x9c, 0x53, 0x16, 0xe8, - 0x44, 0xc5, 0x6a, 0xda, 0x0a, 0xf7, 0x74, 0xfa, 0x98, 0xe1, 0xb3, 0xfd, 0x89, 0x55, 0xbc, 0x95, 0xf1, 0x29, 0xea, 0x0b, 0xdf, 0x69, - 0xd7, 0x43, 0x64, 0xf8, 0x6c, 0x3f, 0x78, 0xa5, 0xa2, 0xa9, 0xcf, 0xc1, 0x3a, 0xf7, 0x60, 0x61, 0xbc, 0x60, 0x45, 0xad, 0xe1, 0x19, - 0xfe, 0x79, 0xb7, 0xfc, 0x30, 0x5f, 0xdd, 0x15, 0x71, 0x30, 0x0b, 0x97, 0xb3, 0x60, 0x72, 0xcd, 0x92, 0x60, 0x9e, 0x2c, 0x57, 0x41, - 0x32, 0xb9, 0x5d, 0xae, 0x56, 0xc5, 0x3c, 0x8c, 0xc3, 0xdb, 0x5f, 0xa3, 0x07, 0xe0, 0x0d, 0xd7, 0xbf, 0x7f, 0xaf, 0xf2, 0x14, 0x2e, - 0xd6, 0xc2, 0x0a, 0x78, 0x24, 0xcc, 0xa1, 0xd8, 0x43, 0x89, 0x8f, 0x67, 0x5f, 0x86, 0x47, 0x9b, 0x81, 0x7e, 0x3f, 0xa3, 0x40, 0x7b, - 0xcc, 0x7d, 0x1e, 0x4f, 0xc3, 0x8f, 0x49, 0x14, 0x06, 0xc5, 0x75, 0x18, 0x05, 0x93, 0x29, 0x9d, 0x05, 0xb3, 0xe9, 0x75, 0x12, 0x14, - 0x49, 0x14, 0xaf, 0xa6, 0x93, 0xe5, 0x5d, 0x52, 0x24, 0x23, 0xee, 0xc9, 0x2b, 0x9f, 0x89, 0x90, 0x44, 0xd1, 0xf0, 0xe0, 0x78, 0xf2, - 0xc9, 0xc2, 0x71, 0xc9, 0x04, 0x57, 0x47, 0xad, 0x8e, 0x0a, 0x8d, 0xbd, 0x20, 0x12, 0x6c, 0xff, 0x52, 0x04, 0x39, 0x2a, 0x41, 0xce, - 0x7f, 0x06, 0xf9, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0x00, 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, - 0x00, 0x21, 0x00, 0xc1, 0x17, 0x10, 0xbe, 0x4e, 0x07, 0x00, 0x00, 0xc6, 0x20, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x78, 0x6c, 0x2f, - 0x74, 0x68, 0x65, 0x6d, 0x65, 0x2f, 0x74, 0x68, 0x65, 0x6d, 0x65, 0x31, 0x2e, 0x78, 0x6d, 0x6c, 0xec, 0x59, 0xcd, 0x8b, 0x1b, 0x37, - 0x14, 0xbf, 0x17, 0xfa, 0x3f, 0x0c, 0x73, 0x77, 0xfc, 0x35, 0xe3, 0x8f, 0x25, 0xde, 0xe0, 0xcf, 0x6c, 0x93, 0xdd, 0x24, 0x64, 0x9d, - 0x94, 0x1c, 0xb5, 0xb6, 0xec, 0x51, 0x56, 0x33, 0x32, 0x92, 0xbc, 0x1b, 0x13, 0x02, 0x25, 0x39, 0xf5, 0x52, 0x28, 0xa4, 0xa5, 0x97, - 0x42, 0x6f, 0x3d, 0x94, 0xd2, 0x40, 0x03, 0x0d, 0xbd, 0xf4, 0x8f, 0x09, 0x24, 0xb4, 0xe9, 0x1f, 0xd1, 0x27, 0xcd, 0xd8, 0x23, 0xad, - 0xe5, 0x24, 0x9b, 0x6c, 0x4a, 0x5a, 0x76, 0x0d, 0x8b, 0x47, 0xfe, 0xbd, 0xa7, 0xa7, 0xf7, 0x9e, 0x7e, 0x7a, 0xf3, 0x74, 0xf1, 0xd2, - 0xbd, 0x98, 0x7a, 0x47, 0x98, 0x0b, 0xc2, 0x92, 0x96, 0x5f, 0xbe, 0x50, 0xf2, 0x3d, 0x9c, 0x8c, 0xd8, 0x98, 0x24, 0xd3, 0x96, 0x7f, - 0x6b, 0x38, 0x28, 0x34, 0x7c, 0x4f, 0x48, 0x94, 0x8c, 0x11, 0x65, 0x09, 0x6e, 0xf9, 0x0b, 0x2c, 0xfc, 0x4b, 0xdb, 0x9f, 0x7e, 0x72, - 0x11, 0x6d, 0xc9, 0x08, 0xc7, 0xd8, 0x03, 0xf9, 0x44, 0x6c, 0xa1, 0x96, 0x1f, 0x49, 0x39, 0xdb, 0x2a, 0x16, 0xc5, 0x08, 0x86, 0x91, - 0xb8, 0xc0, 0x66, 0x38, 0x81, 0xdf, 0x26, 0x8c, 0xc7, 0x48, 0xc2, 0x23, 0x9f, 0x16, 0xc7, 0x1c, 0x1d, 0x83, 0xde, 0x98, 0x16, 0x2b, - 0xa5, 0x52, 0xad, 0x18, 0x23, 0x92, 0xf8, 0x5e, 0x82, 0x62, 0x50, 0x7b, 0x7d, 0x32, 0x21, 0x23, 0xec, 0x0d, 0x95, 0x4a, 0x7f, 0x7b, - 0xa9, 0xbc, 0x4f, 0xe1, 0x31, 0x91, 0x42, 0x0d, 0x8c, 0x28, 0xdf, 0x57, 0xaa, 0xb1, 0x25, 0xa1, 0xb1, 0xe3, 0xc3, 0xb2, 0x42, 0x88, - 0x85, 0xe8, 0x52, 0xee, 0x1d, 0x21, 0xda, 0xf2, 0x61, 0x9e, 0x31, 0x3b, 0x1e, 0xe2, 0x7b, 0xd2, 0xf7, 0x28, 0x12, 0x12, 0x7e, 0x68, - 0xf9, 0x25, 0xfd, 0xe7, 0x17, 0xb7, 0x2f, 0x16, 0xd1, 0x56, 0x26, 0x44, 0xe5, 0x06, 0x59, 0x43, 0x6e, 0xa0, 0xff, 0x32, 0xb9, 0x4c, - 0x60, 0x7c, 0x58, 0xd1, 0x73, 0xf2, 0xe9, 0xc1, 0x6a, 0xd2, 0x20, 0x08, 0x83, 0x5a, 0x7b, 0xa5, 0x5f, 0x03, 0xa8, 0x5c, 0xc7, 0xf5, - 0xeb, 0xfd, 0x5a, 0xbf, 0xb6, 0xd2, 0xa7, 0x01, 0x68, 0x34, 0x82, 0x95, 0xa6, 0xb6, 0xd8, 0x3a, 0xeb, 0x95, 0x6e, 0x90, 0x61, 0x0d, - 0x50, 0xfa, 0xd5, 0xa1, 0xbb, 0x57, 0xef, 0x55, 0xcb, 0x16, 0xde, 0xd0, 0x5f, 0x5d, 0xb3, 0xb9, 0x1d, 0xaa, 0x8f, 0x85, 0xd7, 0xa0, - 0x54, 0x7f, 0xb0, 0x86, 0x1f, 0x0c, 0xba, 0xe0, 0x45, 0x0b, 0xaf, 0x41, 0x29, 0x3e, 0x5c, 0xc3, 0x87, 0x9d, 0x66, 0xa7, 0x67, 0xeb, - 0xd7, 0xa0, 0x14, 0x5f, 0x5b, 0xc3, 0xd7, 0x4b, 0xed, 0x5e, 0x50, 0xb7, 0xf4, 0x6b, 0x50, 0x44, 0x49, 0x72, 0xb8, 0x86, 0x2e, 0x85, - 0xb5, 0x6a, 0x77, 0xb9, 0xda, 0x15, 0x64, 0xc2, 0xe8, 0x8e, 0x13, 0xde, 0x0c, 0x83, 0x41, 0xbd, 0x92, 0x29, 0xcf, 0x51, 0x90, 0x0d, - 0xab, 0xec, 0x52, 0x53, 0x4c, 0x58, 0x22, 0x37, 0xe5, 0x5a, 0x8c, 0xee, 0x32, 0x3e, 0x00, 0x80, 0x02, 0x52, 0x24, 0x49, 0xe2, 0xc9, - 0xc5, 0x0c, 0x4f, 0xd0, 0x08, 0xb2, 0xb8, 0x8b, 0x28, 0x39, 0xe0, 0xc4, 0xdb, 0x25, 0xd3, 0x08, 0x12, 0x6f, 0x86, 0x12, 0x26, 0x60, - 0xb8, 0x54, 0x29, 0x0d, 0x4a, 0x55, 0xf8, 0xaf, 0x3e, 0x81, 0xfe, 0xa6, 0x23, 0x8a, 0xb6, 0x30, 0x32, 0xa4, 0x95, 0x5d, 0x60, 0x89, - 0x58, 0x1b, 0x52, 0xf6, 0x78, 0x62, 0xc4, 0xc9, 0x4c, 0xb6, 0xfc, 0x2b, 0xa0, 0xd5, 0x37, 0x20, 0x2f, 0x9e, 0x3d, 0x7b, 0xfe, 0xf0, - 0xe9, 0xf3, 0x87, 0xbf, 0x3d, 0x7f, 0xf4, 0xe8, 0xf9, 0xc3, 0x5f, 0xb2, 0xb9, 0xb5, 0x2a, 0x4b, 0x6e, 0x07, 0x25, 0x53, 0x53, 0xee, - 0xd5, 0x8f, 0x5f, 0xff, 0xfd, 0xfd, 0x17, 0xde, 0x5f, 0xbf, 0xfe, 0xf0, 0xea, 0xf1, 0x37, 0xe9, 0xd4, 0x27, 0xf1, 0xc2, 0xc4, 0xbf, - 0xfc, 0xf9, 0xcb, 0x97, 0xbf, 0xff, 0xf1, 0x3a, 0xf5, 0xb0, 0xe2, 0xdc, 0x15, 0x2f, 0xbe, 0x7d, 0xf2, 0xf2, 0xe9, 0x93, 0x17, 0xdf, - 0x7d, 0xf5, 0xe7, 0x4f, 0x8f, 0x1d, 0xda, 0xdb, 0x1c, 0x1d, 0x98, 0xf0, 0x21, 0x89, 0xb1, 0xf0, 0xae, 0xe1, 0x63, 0xef, 0x26, 0x8b, - 0x61, 0x81, 0x0e, 0xfb, 0xf1, 0x01, 0x3f, 0x9d, 0xc4, 0x30, 0x42, 0xc4, 0x92, 0x40, 0x11, 0xe8, 0x76, 0xa8, 0xee, 0xcb, 0xc8, 0x02, - 0x5e, 0x5b, 0x20, 0xea, 0xc2, 0x75, 0xb0, 0xed, 0xc2, 0xdb, 0x1c, 0x58, 0xc6, 0x05, 0xbc, 0x3c, 0xbf, 0x6b, 0xd9, 0xba, 0x1f, 0xf1, - 0xb9, 0x24, 0x8e, 0x99, 0xaf, 0x46, 0xb1, 0x05, 0xdc, 0x63, 0x8c, 0x76, 0x18, 0x77, 0x3a, 0xe0, 0xaa, 0x9a, 0xcb, 0xf0, 0xf0, 0x70, - 0x9e, 0x4c, 0xdd, 0x93, 0xf3, 0xb9, 0x89, 0xbb, 0x89, 0xd0, 0x91, 0x6b, 0xee, 0x2e, 0x4a, 0xac, 0x00, 0xf7, 0xe7, 0x33, 0xa0, 0x57, - 0xe2, 0x52, 0xd9, 0x8d, 0xb0, 0x65, 0xe6, 0x0d, 0x8a, 0x12, 0x89, 0xa6, 0x38, 0xc1, 0xd2, 0x53, 0xbf, 0xb1, 0x43, 0x8c, 0x1d, 0xab, - 0xbb, 0x43, 0x88, 0xe5, 0xd7, 0x3d, 0x32, 0xe2, 0x4c, 0xb0, 0x89, 0xf4, 0xee, 0x10, 0xaf, 0x83, 0x88, 0xd3, 0x25, 0x43, 0x72, 0x60, - 0x25, 0x52, 0x2e, 0xb4, 0x43, 0x62, 0x88, 0xcb, 0xc2, 0x65, 0x20, 0x84, 0xda, 0xf2, 0xcd, 0xde, 0x6d, 0xaf, 0xc3, 0xa8, 0x6b, 0xd5, - 0x3d, 0x7c, 0x64, 0x23, 0x61, 0x5b, 0x20, 0xea, 0x30, 0x7e, 0x88, 0xa9, 0xe5, 0xc6, 0xcb, 0x68, 0x2e, 0x51, 0xec, 0x52, 0x39, 0x44, - 0x31, 0x35, 0x1d, 0xbe, 0x8b, 0x64, 0xe4, 0x32, 0x72, 0x7f, 0xc1, 0x47, 0x26, 0xae, 0x2f, 0x24, 0x44, 0x7a, 0x8a, 0x29, 0xf3, 0xfa, - 0x63, 0x2c, 0x84, 0x4b, 0xe6, 0x3a, 0x87, 0xf5, 0x1a, 0x41, 0xbf, 0x0a, 0x0c, 0xe3, 0x0e, 0xfb, 0x1e, 0x5d, 0xc4, 0x36, 0x92, 0x4b, - 0x72, 0xe8, 0xd2, 0xb9, 0x8b, 0x18, 0x33, 0x91, 0x3d, 0x76, 0xd8, 0x8d, 0x50, 0x3c, 0x73, 0xda, 0x4c, 0x92, 0xc8, 0xc4, 0x7e, 0x26, - 0x0e, 0x21, 0x45, 0x91, 0x77, 0x83, 0x49, 0x17, 0x7c, 0x8f, 0xd9, 0x3b, 0x44, 0x3d, 0x43, 0x1c, 0x50, 0xb2, 0x31, 0xdc, 0xb7, 0x09, - 0xb6, 0xc2, 0xfd, 0x66, 0x22, 0xb8, 0x05, 0xe4, 0x6a, 0x9a, 0x94, 0x27, 0x88, 0xfa, 0x65, 0xce, 0x1d, 0xb1, 0xbc, 0x8c, 0x99, 0xbd, - 0x1f, 0x17, 0x74, 0x82, 0xb0, 0x8b, 0x65, 0xda, 0x3c, 0xb6, 0xd8, 0xb5, 0xcd, 0x89, 0x33, 0x3b, 0x3a, 0xf3, 0xa9, 0x95, 0xda, 0xbb, - 0x18, 0x53, 0x74, 0x8c, 0xc6, 0x18, 0x7b, 0xb7, 0x3e, 0x73, 0x58, 0xd0, 0x61, 0x33, 0xcb, 0xe7, 0xb9, 0xd1, 0x57, 0x22, 0x60, 0x95, - 0x1d, 0xec, 0x4a, 0xac, 0x2b, 0xc8, 0xce, 0x55, 0xf5, 0x9c, 0x60, 0x01, 0x65, 0x92, 0xaa, 0x6b, 0xd6, 0x29, 0x72, 0x97, 0x08, 0x2b, - 0x65, 0xf7, 0xf1, 0x94, 0x6d, 0xb0, 0x67, 0x6f, 0x71, 0x82, 0x78, 0x16, 0x28, 0x89, 0x11, 0xdf, 0xa4, 0xf9, 0x1a, 0x44, 0xdd, 0x4a, - 0x5d, 0x38, 0xe5, 0x9c, 0x54, 0x7a, 0x9d, 0x8e, 0x0e, 0x4d, 0xe0, 0x35, 0x02, 0xe5, 0x1f, 0xe4, 0x8b, 0xd3, 0x29, 0xd7, 0x05, 0xe8, - 0x30, 0x92, 0xbb, 0xbf, 0x49, 0xeb, 0x8d, 0x08, 0x59, 0x67, 0x97, 0x7a, 0x16, 0xee, 0x7c, 0x5d, 0x70, 0x2b, 0x7e, 0x6f, 0xb3, 0xc7, - 0x60, 0x5f, 0xde, 0x3d, 0xed, 0xbe, 0x04, 0x19, 0x7c, 0x6a, 0x19, 0x20, 0xf6, 0xb7, 0xf6, 0xcd, 0x10, 0x51, 0x6b, 0x82, 0x3c, 0x61, - 0x86, 0x08, 0x0a, 0x0c, 0x17, 0xdd, 0x82, 0x88, 0x15, 0xfe, 0x5c, 0x44, 0x9d, 0xab, 0x5a, 0x6c, 0xee, 0x94, 0x9b, 0xd8, 0x9b, 0x36, - 0x0f, 0x03, 0x14, 0x46, 0x56, 0xbd, 0x13, 0x93, 0xe4, 0x8d, 0xc5, 0xcf, 0x89, 0xb2, 0x27, 0xfc, 0x77, 0xca, 0x1e, 0x77, 0x01, 0x73, - 0x06, 0x05, 0x8f, 0x5b, 0xf1, 0xfb, 0x94, 0x3a, 0x9b, 0x28, 0x65, 0xe7, 0x44, 0x81, 0xb3, 0x09, 0xf7, 0x1f, 0x2c, 0x6b, 0x7a, 0x68, - 0x9e, 0xdc, 0xc0, 0x70, 0x92, 0xac, 0x73, 0xd6, 0x79, 0x55, 0x73, 0x5e, 0xd5, 0xf8, 0xff, 0xfb, 0xaa, 0x66, 0xd3, 0x5e, 0x3e, 0xaf, - 0x65, 0xce, 0x6b, 0x99, 0xf3, 0x5a, 0xc6, 0xf5, 0xf6, 0xf5, 0x41, 0x6a, 0x99, 0xbc, 0x7c, 0x81, 0xca, 0x26, 0xef, 0xf2, 0xe8, 0x9e, - 0x4f, 0xbc, 0xb1, 0xe5, 0x33, 0x21, 0x94, 0xee, 0xcb, 0x05, 0xc5, 0xbb, 0x42, 0x77, 0x7d, 0x04, 0xbc, 0xd1, 0x8c, 0x07, 0x30, 0xa8, - 0xdb, 0x51, 0xba, 0x27, 0xb9, 0x6a, 0x01, 0xce, 0x22, 0xf8, 0x9a, 0x35, 0x98, 0x2c, 0xdc, 0x94, 0x23, 0x2d, 0xe3, 0x71, 0x26, 0x3f, - 0x27, 0x32, 0xda, 0x8f, 0xd0, 0x0c, 0x5a, 0x43, 0x65, 0xdd, 0xc0, 0x9c, 0x8a, 0x4c, 0xf5, 0x54, 0x78, 0x33, 0x26, 0xa0, 0x63, 0xa4, - 0x87, 0x75, 0x2b, 0x15, 0x9f, 0xd0, 0xad, 0xfb, 0x4e, 0xf3, 0x78, 0x8f, 0x8d, 0xd3, 0x4e, 0x67, 0xb9, 0xac, 0xba, 0x9a, 0xa9, 0x0b, - 0x05, 0x92, 0xf9, 0x78, 0x29, 0x5c, 0x8d, 0x43, 0x97, 0x4a, 0xa6, 0xe8, 0x5a, 0x3d, 0xef, 0xde, 0xad, 0xd4, 0xeb, 0x7e, 0xe8, 0x54, - 0x77, 0x59, 0x97, 0x06, 0x28, 0xd9, 0xd3, 0x18, 0x61, 0x4c, 0x66, 0x1b, 0x51, 0x75, 0x18, 0x51, 0x5f, 0x0e, 0x42, 0x14, 0x5e, 0x67, - 0x84, 0x5e, 0xd9, 0x99, 0x58, 0xd1, 0x74, 0x58, 0xd1, 0x50, 0xea, 0x97, 0xa1, 0x5a, 0x46, 0x71, 0xe5, 0x0a, 0x30, 0x6d, 0x15, 0x15, - 0x78, 0xe5, 0xf6, 0xe0, 0x45, 0xbd, 0xe5, 0x87, 0x41, 0xda, 0x41, 0x86, 0x66, 0x1c, 0x94, 0xe7, 0x63, 0x15, 0xa7, 0xb4, 0x99, 0xbc, - 0x8c, 0xae, 0x0a, 0xce, 0x99, 0x46, 0x7a, 0x93, 0x33, 0xa9, 0x99, 0x01, 0x50, 0x62, 0x2f, 0x33, 0x20, 0x8f, 0x74, 0x53, 0xd9, 0xba, - 0x71, 0x79, 0x6a, 0x75, 0x69, 0xaa, 0xbd, 0x45, 0xa4, 0x2d, 0x23, 0x8c, 0x74, 0xb3, 0x8d, 0x30, 0xd2, 0x30, 0x82, 0x17, 0xe1, 0x2c, - 0x3b, 0xcd, 0x96, 0xfb, 0x59, 0xc6, 0xba, 0x99, 0x87, 0xd4, 0x32, 0x4f, 0xb9, 0x62, 0xb9, 0x1b, 0x72, 0x33, 0xea, 0x8d, 0x0f, 0x11, - 0x6b, 0x45, 0x22, 0x27, 0xb8, 0x81, 0x26, 0x26, 0x53, 0xd0, 0xc4, 0x3b, 0x6e, 0xf9, 0xb5, 0x6a, 0x08, 0xb7, 0x2a, 0x23, 0x34, 0x6b, - 0xf9, 0x13, 0xe8, 0x18, 0xc3, 0xd7, 0x78, 0x06, 0xb9, 0x23, 0xd4, 0x5b, 0x17, 0xa2, 0x53, 0xb8, 0x76, 0x19, 0x49, 0x9e, 0x6e, 0xf8, - 0x77, 0x61, 0x96, 0x19, 0x17, 0xb2, 0x87, 0x44, 0x94, 0x3a, 0x5c, 0x93, 0x4e, 0xca, 0x06, 0x31, 0x91, 0x98, 0x7b, 0x94, 0xc4, 0x2d, - 0x5f, 0x2d, 0x7f, 0x95, 0x0d, 0x34, 0xd1, 0x1c, 0xa2, 0x6d, 0x2b, 0x57, 0x80, 0x10, 0x3e, 0x5a, 0xe3, 0x9a, 0x40, 0x2b, 0x1f, 0x9b, - 0x71, 0x10, 0x74, 0x3b, 0xc8, 0x78, 0x32, 0xc1, 0x23, 0x69, 0x86, 0xdd, 0x18, 0x51, 0x9e, 0x4e, 0x1f, 0x81, 0xe1, 0x53, 0xae, 0x70, - 0xfe, 0xaa, 0xc5, 0xdf, 0x1d, 0xac, 0x24, 0xd9, 0x1c, 0xc2, 0xbd, 0x1f, 0x8d, 0x8f, 0xbd, 0x03, 0x3a, 0xe7, 0x37, 0x11, 0xa4, 0x58, - 0x58, 0x2f, 0x2b, 0x07, 0x8e, 0x89, 0x80, 0x8b, 0x83, 0x72, 0xea, 0xcd, 0x31, 0x81, 0x9b, 0xb0, 0x15, 0x91, 0xe5, 0xf9, 0x77, 0xe2, - 0x60, 0xca, 0x68, 0xd7, 0xbc, 0x8a, 0xd2, 0x39, 0x94, 0x8e, 0x23, 0x3a, 0x8b, 0x50, 0x76, 0xa2, 0x98, 0x64, 0x9e, 0xc2, 0x35, 0x89, - 0xae, 0xcc, 0xd1, 0x4f, 0x2b, 0x1f, 0x18, 0x4f, 0xd9, 0x9a, 0xc1, 0xa1, 0xeb, 0x2e, 0x3c, 0x98, 0xaa, 0x03, 0xf6, 0xbd, 0x4f, 0xdd, - 0x37, 0x1f, 0xd5, 0xca, 0x73, 0x06, 0x69, 0xe6, 0x67, 0xa6, 0xc5, 0x2a, 0xea, 0xd4, 0x74, 0x93, 0xe9, 0x87, 0x3b, 0xe4, 0x0d, 0xab, - 0xf2, 0x43, 0xd4, 0xb2, 0x2a, 0xa5, 0x6e, 0xfd, 0x4e, 0x2d, 0x72, 0xae, 0x6b, 0x2e, 0xb9, 0x0e, 0x12, 0xd5, 0x79, 0x4a, 0xbc, 0xe1, - 0xd4, 0x7d, 0x8b, 0x03, 0xc1, 0x30, 0x2d, 0x9f, 0xcc, 0x32, 0x4d, 0x59, 0xbc, 0x4e, 0xc3, 0x8a, 0xb3, 0xb3, 0x51, 0xdb, 0xb4, 0x33, - 0x2c, 0x08, 0x0c, 0x4f, 0xd4, 0x36, 0xf8, 0x6d, 0x75, 0x46, 0x38, 0x3d, 0xf1, 0xae, 0x27, 0x3f, 0xc8, 0x9d, 0xcc, 0x5a, 0x75, 0x40, - 0x2c, 0xeb, 0x4a, 0x9d, 0xf8, 0xfa, 0xca, 0xdc, 0xbc, 0xd5, 0x66, 0x07, 0x77, 0x81, 0x3c, 0x7a, 0x70, 0x7f, 0x38, 0xa7, 0x52, 0xe8, - 0x50, 0x42, 0x6f, 0x97, 0x23, 0x28, 0xfa, 0xd2, 0x1b, 0xc8, 0x94, 0x36, 0x60, 0x8b, 0xdc, 0x93, 0x59, 0x8d, 0x08, 0xdf, 0xbc, 0x39, - 0x27, 0x2d, 0xff, 0x7e, 0x29, 0x6c, 0x07, 0xdd, 0x4a, 0xd8, 0x2d, 0x94, 0x1a, 0x61, 0xbf, 0x10, 0x54, 0x83, 0x52, 0xa1, 0x11, 0xb6, - 0xab, 0x85, 0x76, 0x18, 0x56, 0xcb, 0xfd, 0xb0, 0x5c, 0xea, 0x75, 0x2a, 0x0f, 0xe0, 0x60, 0x91, 0x51, 0x5c, 0x0e, 0xd3, 0xeb, 0xfa, - 0x01, 0x5c, 0x61, 0xd0, 0x45, 0x76, 0x69, 0xaf, 0xc7, 0xd7, 0x2e, 0xee, 0xe3, 0xe5, 0x2d, 0xcd, 0x85, 0x11, 0x8b, 0x8b, 0x4c, 0x5f, - 0xcc, 0x17, 0xb5, 0xe1, 0xfa, 0xe2, 0xbe, 0x5c, 0xd9, 0x7c, 0x71, 0xef, 0x11, 0x20, 0x9d, 0xfb, 0xb5, 0xca, 0xa0, 0x59, 0x6d, 0x76, - 0x6a, 0x85, 0x66, 0xb5, 0x3d, 0x28, 0x04, 0xbd, 0x4e, 0xa3, 0xd0, 0xec, 0xd6, 0x3a, 0x85, 0x5e, 0xad, 0x5b, 0xef, 0x0d, 0x7a, 0xdd, - 0xb0, 0xd1, 0x1c, 0x3c, 0xf0, 0xbd, 0x23, 0x0d, 0x0e, 0xda, 0xd5, 0x6e, 0x50, 0xeb, 0x37, 0x0a, 0xb5, 0x72, 0xb7, 0x5b, 0x08, 0x6a, - 0x25, 0x65, 0x7e, 0xa3, 0x59, 0xa8, 0x07, 0x95, 0x4a, 0x3b, 0xa8, 0xb7, 0x1b, 0xfd, 0xa0, 0xfd, 0x20, 0x2b, 0x63, 0x60, 0xe5, 0x29, - 0x7d, 0x64, 0xbe, 0x00, 0xf7, 0x6a, 0xbb, 0xb6, 0xff, 0x01, 0x00, 0x00, 0xff, 0xff, 0x03, 0x00, 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, - 0x06, 0x00, 0x08, 0x00, 0x00, 0x00, 0x21, 0x00, 0xff, 0x6b, 0x0c, 0xe9, 0xcd, 0x01, 0x00, 0x00, 0xb5, 0x03, 0x00, 0x00, 0x18, 0x00, - 0x00, 0x00, 0x78, 0x6c, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x68, 0x65, 0x65, 0x74, 0x73, 0x2f, 0x73, 0x68, 0x65, 0x65, 0x74, 0x31, - 0x2e, 0x78, 0x6d, 0x6c, 0x9c, 0x93, 0x4d, 0x8b, 0xdb, 0x30, 0x10, 0x86, 0xef, 0x85, 0xfe, 0x07, 0xa1, 0xbb, 0x2d, 0xdb, 0xf1, 0x3a, - 0x89, 0x89, 0xb3, 0x6c, 0x36, 0x0d, 0xdd, 0x43, 0xa1, 0xf4, 0xf3, 0x2c, 0xcb, 0x63, 0x5b, 0xc4, 0x92, 0x8c, 0xa4, 0x6c, 0x12, 0x4a, - 0xff, 0x7b, 0xc7, 0x0e, 0xf1, 0x16, 0x72, 0x09, 0x0b, 0x16, 0x68, 0xc6, 0x9a, 0x67, 0x66, 0xa4, 0x77, 0x56, 0x8f, 0x27, 0xd5, 0x91, - 0x57, 0xb0, 0x4e, 0x1a, 0x5d, 0xd0, 0x38, 0x8c, 0x28, 0x01, 0x2d, 0x4c, 0x25, 0x75, 0x53, 0xd0, 0x9f, 0x3f, 0x76, 0xc1, 0x82, 0x12, - 0xe7, 0xb9, 0xae, 0x78, 0x67, 0x34, 0x14, 0xf4, 0x0c, 0x8e, 0x3e, 0xae, 0x3f, 0x7e, 0x58, 0x1d, 0x8d, 0xdd, 0xbb, 0x16, 0xc0, 0x13, - 0x24, 0x68, 0x57, 0xd0, 0xd6, 0xfb, 0x3e, 0x67, 0xcc, 0x89, 0x16, 0x14, 0x77, 0xa1, 0xe9, 0x41, 0xe3, 0x9f, 0xda, 0x58, 0xc5, 0x3d, - 0x9a, 0xb6, 0x61, 0xae, 0xb7, 0xc0, 0xab, 0x31, 0x48, 0x75, 0x2c, 0x89, 0xa2, 0x8c, 0x29, 0x2e, 0x35, 0xbd, 0x10, 0x72, 0x7b, 0x0f, - 0xc3, 0xd4, 0xb5, 0x14, 0xb0, 0x35, 0xe2, 0xa0, 0x40, 0xfb, 0x0b, 0xc4, 0x42, 0xc7, 0x3d, 0xd6, 0xef, 0x5a, 0xd9, 0xbb, 0x2b, 0x4d, - 0x89, 0x7b, 0x70, 0x8a, 0xdb, 0xfd, 0xa1, 0x0f, 0x84, 0x51, 0x3d, 0x22, 0x4a, 0xd9, 0x49, 0x7f, 0x1e, 0xa1, 0x94, 0x28, 0x91, 0xbf, - 0x34, 0xda, 0x58, 0x5e, 0x76, 0xd8, 0xf7, 0x29, 0x4e, 0xb9, 0x20, 0x27, 0x8b, 0x5f, 0x82, 0x6b, 0x76, 0x4d, 0x33, 0xfa, 0x6f, 0x32, - 0x29, 0x29, 0xac, 0x71, 0xa6, 0xf6, 0x21, 0x92, 0xd9, 0xa5, 0xe6, 0xdb, 0xf6, 0x97, 0x6c, 0xc9, 0xb8, 0x98, 0x48, 0xb7, 0xfd, 0xdf, - 0x85, 0x89, 0x53, 0x66, 0xe1, 0x55, 0x0e, 0x0f, 0xf8, 0x86, 0x4a, 0xde, 0x57, 0x52, 0xfc, 0x30, 0xb1, 0x92, 0x37, 0xd8, 0xec, 0x9d, - 0xb0, 0x6c, 0x82, 0x0d, 0xd7, 0x65, 0xf3, 0x83, 0xac, 0x0a, 0xfa, 0x27, 0x4a, 0x97, 0xbb, 0x4d, 0xbc, 0x49, 0x83, 0xe4, 0x29, 0x8b, - 0x83, 0x34, 0x4b, 0x67, 0xc1, 0x62, 0x11, 0x67, 0xc1, 0x62, 0x33, 0xcf, 0x3e, 0x3d, 0xcf, 0xb2, 0xdd, 0x36, 0xdd, 0xfc, 0xa5, 0xeb, - 0x55, 0x25, 0xf1, 0x85, 0x87, 0xae, 0x88, 0x85, 0xba, 0xa0, 0x4f, 0x31, 0x65, 0xeb, 0xd5, 0x28, 0x9e, 0x5f, 0x12, 0x8e, 0xee, 0xbf, - 0x3d, 0xf1, 0xbc, 0xfc, 0x0e, 0x1d, 0x08, 0x0f, 0x98, 0x20, 0xa6, 0x64, 0xd0, 0x66, 0x69, 0xcc, 0x7e, 0x38, 0xf8, 0x82, 0xae, 0x68, - 0x08, 0x65, 0x37, 0xb1, 0xbb, 0x51, 0x9b, 0x5f, 0x2d, 0x29, 0xb9, 0x83, 0x67, 0xd3, 0xfd, 0x96, 0x95, 0x6f, 0x11, 0x80, 0x33, 0x50, - 0x41, 0xcd, 0x0f, 0x9d, 0xff, 0x66, 0x8e, 0x9f, 0x41, 0x36, 0xad, 0x47, 0x6f, 0x86, 0x3d, 0x0c, 0x22, 0xc8, 0xab, 0xf3, 0x16, 0x9c, - 0x40, 0xf5, 0x21, 0x38, 0x4c, 0xa6, 0xaa, 0xb6, 0xdc, 0x73, 0x4c, 0xd3, 0xf3, 0x06, 0xbe, 0x70, 0xdb, 0x48, 0xed, 0x48, 0x07, 0xf5, - 0x78, 0x68, 0x4e, 0x89, 0xbd, 0x50, 0xa2, 0x10, 0xf7, 0xde, 0xf4, 0x43, 0xe8, 0xfc, 0x81, 0x92, 0xd2, 0x78, 0x6f, 0xd4, 0xd5, 0x6a, - 0x71, 0x3c, 0x00, 0x65, 0x10, 0x85, 0x78, 0x61, 0xb5, 0x31, 0xfe, 0x6a, 0x0c, 0xe5, 0x4f, 0x03, 0xb7, 0xfe, 0x07, 0x00, 0x00, 0xff, - 0xff, 0x03, 0x00, 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00, 0x21, 0x00, 0xc2, 0x5e, 0x59, 0x08, 0x90, - 0x01, 0x00, 0x00, 0x1b, 0x03, 0x00, 0x00, 0x10, 0x00, 0x08, 0x01, 0x64, 0x6f, 0x63, 0x50, 0x72, 0x6f, 0x70, 0x73, 0x2f, 0x61, 0x70, - 0x70, 0x2e, 0x78, 0x6d, 0x6c, 0x20, 0xa2, 0x04, 0x01, 0x28, 0xa0, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x92, 0x4d, 0x6f, 0xdb, 0x30, 0x0c, 0x86, 0xef, 0x03, 0xfa, 0x1f, 0x0c, 0xdd, 0x1b, 0x39, 0x6d, - 0x51, 0x0c, 0x81, 0xac, 0x62, 0x48, 0x57, 0xf4, 0xb0, 0x62, 0x01, 0x92, 0x76, 0x67, 0x4e, 0xa6, 0x63, 0xa1, 0xb2, 0x24, 0x88, 0xac, - 0x91, 0xec, 0xd7, 0x4f, 0xb6, 0xd1, 0xd4, 0xd9, 0x76, 0xda, 0x8d, 0x1f, 0x2f, 0x5e, 0x3e, 0xa2, 0xa8, 0xee, 0x0e, 0x9d, 0x2b, 0x7a, - 0x4c, 0x64, 0x83, 0xaf, 0xc4, 0x72, 0x51, 0x8a, 0x02, 0xbd, 0x09, 0xb5, 0xf5, 0xfb, 0x4a, 0x3c, 0xef, 0x1e, 0x2e, 0x3f, 0x8b, 0x82, - 0x18, 0x7c, 0x0d, 0x2e, 0x78, 0xac, 0xc4, 0x11, 0x49, 0xdc, 0xe9, 0x8b, 0x4f, 0x6a, 0x93, 0x42, 0xc4, 0xc4, 0x16, 0xa9, 0xc8, 0x16, - 0x9e, 0x2a, 0xd1, 0x32, 0xc7, 0x95, 0x94, 0x64, 0x5a, 0xec, 0x80, 0x16, 0xb9, 0xed, 0x73, 0xa7, 0x09, 0xa9, 0x03, 0xce, 0x69, 0xda, - 0xcb, 0xd0, 0x34, 0xd6, 0xe0, 0x7d, 0x30, 0x6f, 0x1d, 0x7a, 0x96, 0x57, 0x65, 0x79, 0x2b, 0xf1, 0xc0, 0xe8, 0x6b, 0xac, 0x2f, 0xe3, - 0xc9, 0x50, 0x4c, 0x8e, 0xab, 0x9e, 0xff, 0xd7, 0xb4, 0x0e, 0x66, 0xe0, 0xa3, 0x97, 0xdd, 0x31, 0x66, 0x60, 0xad, 0xbe, 0xc4, 0xe8, - 0xac, 0x01, 0xce, 0xaf, 0xd4, 0x4f, 0xd6, 0xa4, 0x40, 0xa1, 0xe1, 0xe2, 0x09, 0x8c, 0xf5, 0x1c, 0xa8, 0x2d, 0xbe, 0x1e, 0x0c, 0x3a, - 0x25, 0xe7, 0x32, 0x95, 0x39, 0xb7, 0x68, 0xde, 0x92, 0xe5, 0xa3, 0x2e, 0x95, 0x9c, 0xa7, 0x6a, 0x6b, 0xc0, 0xe1, 0x3a, 0x8f, 0xd0, - 0x0d, 0x38, 0x42, 0x25, 0x3f, 0x0a, 0xea, 0x11, 0x61, 0x58, 0xdf, 0x06, 0x6c, 0x22, 0xad, 0x7a, 0x5e, 0xf5, 0x68, 0x38, 0xa4, 0x82, - 0xec, 0xaf, 0xbc, 0xc0, 0x2b, 0x51, 0xfc, 0x04, 0xc2, 0x01, 0xac, 0x12, 0x3d, 0x24, 0x0b, 0x9e, 0x33, 0xe0, 0x20, 0x9b, 0x92, 0x31, - 0x76, 0x91, 0x38, 0xe9, 0x1f, 0x21, 0xbd, 0x52, 0x8b, 0xc8, 0xa4, 0x64, 0x16, 0x4c, 0xc5, 0x31, 0x9c, 0x6b, 0xe7, 0xb1, 0xbd, 0xd1, - 0xcb, 0x51, 0x90, 0x83, 0x73, 0xe1, 0x60, 0x30, 0x81, 0xe4, 0xc6, 0x39, 0xe2, 0xce, 0xb2, 0x43, 0xfa, 0xde, 0x6c, 0x20, 0xf1, 0x3f, - 0x88, 0x97, 0x73, 0xe2, 0x91, 0x61, 0xe2, 0x9d, 0x70, 0xb6, 0x03, 0xdf, 0x34, 0x73, 0xce, 0x37, 0x3e, 0x39, 0x4f, 0xfa, 0xc3, 0x7b, - 0x1d, 0xba, 0x08, 0xfe, 0x98, 0x1b, 0xa7, 0xe8, 0x9b, 0xf5, 0xaf, 0xf4, 0x1c, 0x77, 0xe1, 0x1e, 0x18, 0xdf, 0xd7, 0x79, 0x5e, 0x54, - 0xdb, 0x16, 0x12, 0xd6, 0xf9, 0x07, 0x4e, 0xeb, 0x3e, 0x15, 0xd4, 0x63, 0xde, 0x64, 0x72, 0x83, 0xc9, 0xba, 0x05, 0xbf, 0xc7, 0xfa, - 0x5d, 0xf3, 0x77, 0x63, 0x38, 0x83, 0x97, 0xe9, 0xd6, 0xf5, 0xf2, 0x76, 0x51, 0x5e, 0x97, 0xf9, 0x5f, 0x67, 0x35, 0x25, 0x3f, 0xae, - 0x5a, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0x03, 0x00, 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00, 0x21, - 0x00, 0xbd, 0xde, 0xac, 0xb8, 0x45, 0x01, 0x00, 0x00, 0x6f, 0x02, 0x00, 0x00, 0x11, 0x00, 0x08, 0x01, 0x64, 0x6f, 0x63, 0x50, 0x72, - 0x6f, 0x70, 0x73, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x78, 0x6d, 0x6c, 0x20, 0xa2, 0x04, 0x01, 0x28, 0xa0, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0x92, 0x5f, 0x4b, 0xc3, 0x30, 0x14, 0xc5, 0xdf, 0x05, - 0xbf, 0x43, 0xc9, 0x7b, 0x9b, 0x66, 0x1b, 0x63, 0x96, 0xb6, 0x83, 0x29, 0x7b, 0xd1, 0x81, 0xe0, 0x44, 0xf1, 0x2d, 0x24, 0x77, 0x5b, - 0xb0, 0xf9, 0x43, 0x12, 0xd7, 0xed, 0xdb, 0x9b, 0xb6, 0x5b, 0xad, 0xd4, 0x17, 0x1f, 0x93, 0x73, 0xee, 0x2f, 0xe7, 0x5c, 0x92, 0x2f, - 0x4f, 0xb2, 0x8a, 0x8e, 0x60, 0x9d, 0xd0, 0xaa, 0x40, 0x24, 0x49, 0x51, 0x04, 0x8a, 0x69, 0x2e, 0xd4, 0xbe, 0x40, 0xaf, 0xdb, 0x75, - 0xbc, 0x40, 0x91, 0xf3, 0x54, 0x71, 0x5a, 0x69, 0x05, 0x05, 0x3a, 0x83, 0x43, 0xcb, 0xf2, 0xf6, 0x26, 0x67, 0x26, 0x63, 0xda, 0xc2, - 0xb3, 0xd5, 0x06, 0xac, 0x17, 0xe0, 0xa2, 0x40, 0x52, 0x2e, 0x63, 0xa6, 0x40, 0x07, 0xef, 0x4d, 0x86, 0xb1, 0x63, 0x07, 0x90, 0xd4, - 0x25, 0xc1, 0xa1, 0x82, 0xb8, 0xd3, 0x56, 0x52, 0x1f, 0x8e, 0x76, 0x8f, 0x0d, 0x65, 0x9f, 0x74, 0x0f, 0x78, 0x92, 0xa6, 0x73, 0x2c, - 0xc1, 0x53, 0x4e, 0x3d, 0xc5, 0x0d, 0x30, 0x36, 0x3d, 0x11, 0x5d, 0x90, 0x9c, 0xf5, 0x48, 0xf3, 0x65, 0xab, 0x16, 0xc0, 0x19, 0x86, - 0x0a, 0x24, 0x28, 0xef, 0x30, 0x49, 0x08, 0xfe, 0xf1, 0x7a, 0xb0, 0xd2, 0xfd, 0x39, 0xd0, 0x2a, 0x03, 0xa7, 0x14, 0xfe, 0x6c, 0x42, - 0xa7, 0x4b, 0xdc, 0x21, 0x9b, 0xb3, 0x4e, 0xec, 0xdd, 0x27, 0x27, 0x7a, 0x63, 0x5d, 0xd7, 0x49, 0x3d, 0x6d, 0x63, 0x84, 0xfc, 0x04, - 0xbf, 0x6f, 0x9e, 0x5e, 0xda, 0xaa, 0xb1, 0x50, 0xcd, 0xae, 0x18, 0xa0, 0x32, 0xe7, 0x2c, 0x63, 0x16, 0xa8, 0xd7, 0xb6, 0x7c, 0x04, - 0xa5, 0xc0, 0x1f, 0xa2, 0x15, 0xad, 0x5c, 0x05, 0xc7, 0x1c, 0x0f, 0xb4, 0x66, 0x8f, 0x15, 0x75, 0x7e, 0x13, 0x56, 0xbe, 0x13, 0xc0, - 0x57, 0xe7, 0xb1, 0x7d, 0x6c, 0x09, 0xf4, 0xb6, 0x4c, 0xf7, 0x04, 0xf0, 0x28, 0xc4, 0xcb, 0xba, 0x32, 0x57, 0xe5, 0x6d, 0x7a, 0xff, - 0xb0, 0x5d, 0xa3, 0x72, 0x92, 0x92, 0xbb, 0x38, 0x5d, 0xc4, 0x64, 0xbe, 0x4d, 0xd3, 0x6c, 0x3a, 0xcb, 0xc8, 0xec, 0xa3, 0x49, 0xf0, - 0x6b, 0xbe, 0x89, 0xdb, 0x5d, 0xc8, 0x4b, 0x8e, 0xff, 0x10, 0x27, 0xf3, 0x01, 0xf1, 0x0a, 0x28, 0x73, 0x3c, 0xfa, 0x22, 0xe5, 0x37, - 0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0x00, 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x02, 0x00, 0x08, 0x00, 0x9a, 0xab, 0x0f, 0x4f, 0x5e, - 0xff, 0xec, 0xaa, 0x93, 0x00, 0x00, 0x00, 0xb2, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x78, 0x6c, 0x2f, 0x73, 0x68, 0x61, 0x72, - 0x65, 0x64, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x78, 0x6d, 0x6c, 0x35, 0x8d, 0x41, 0x0a, 0xc2, 0x30, 0x10, 0x45, 0xf7, - 0x82, 0x77, 0x08, 0xb3, 0xd7, 0xa9, 0x2e, 0x44, 0x24, 0x49, 0x17, 0x82, 0x27, 0xd0, 0x03, 0x84, 0x76, 0x6c, 0x03, 0xcd, 0xa4, 0x66, - 0xa6, 0xa2, 0xb7, 0x37, 0x5d, 0xb8, 0xf8, 0xf0, 0x1f, 0x9f, 0xcf, 0xb3, 0xed, 0x27, 0x4d, 0xe6, 0x4d, 0x45, 0x62, 0x66, 0x07, 0x87, - 0x7d, 0x03, 0x86, 0xb8, 0xcb, 0x7d, 0xe4, 0xc1, 0xc1, 0xe3, 0x7e, 0xdb, 0x9d, 0xc1, 0x88, 0x06, 0xee, 0xc3, 0x94, 0x99, 0x1c, 0x7c, - 0x49, 0xa0, 0xf5, 0xdb, 0x8d, 0x15, 0x51, 0x53, 0xbf, 0x2c, 0x0e, 0x46, 0xd5, 0xf9, 0x82, 0x28, 0xdd, 0x48, 0x29, 0xc8, 0x3e, 0xcf, - 0xc4, 0x75, 0x79, 0xe6, 0x92, 0x82, 0x56, 0x2c, 0x03, 0xca, 0x5c, 0x28, 0xf4, 0x32, 0x12, 0x69, 0x9a, 0xf0, 0xd8, 0x34, 0x27, 0x4c, - 0x21, 0x32, 0x98, 0x2e, 0x2f, 0xac, 0xd5, 0x0b, 0x66, 0xe1, 0xf8, 0x5a, 0xe8, 0xfa, 0x67, 0x6f, 0x25, 0x7a, 0xab, 0xde, 0xe2, 0x9a, - 0xb5, 0x63, 0x35, 0x56, 0xf1, 0x0f, 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x02, 0x00, 0x08, 0x00, 0x99, 0x64, 0xef, 0x50, 0xd9, 0x19, - 0xd7, 0x73, 0x3f, 0x01, 0x00, 0x00, 0x7e, 0x04, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x5b, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x5f, 0x54, 0x79, 0x70, 0x65, 0x73, 0x5d, 0x2e, 0x78, 0x6d, 0x6c, 0xad, 0x93, 0xcd, 0x4e, 0xc3, 0x30, 0x10, 0x84, 0xef, 0x3c, 0x45, - 0xe4, 0x2b, 0x4a, 0xdc, 0x72, 0x40, 0x08, 0x35, 0xed, 0x81, 0x9f, 0x23, 0x54, 0xa2, 0x3c, 0x80, 0xb1, 0x37, 0x8d, 0xd5, 0xf8, 0x47, - 0xbb, 0x6e, 0x69, 0xdf, 0x9e, 0x4d, 0x52, 0x21, 0x40, 0x55, 0x03, 0xb4, 0x97, 0x58, 0xf1, 0xce, 0xcc, 0x37, 0x3e, 0xec, 0x64, 0xb6, - 0x75, 0x4d, 0xb6, 0x01, 0x24, 0x1b, 0x7c, 0x29, 0xc6, 0xc5, 0x48, 0x64, 0xe0, 0x75, 0x30, 0xd6, 0x2f, 0x4b, 0xf1, 0xba, 0x78, 0xcc, - 0x6f, 0xc4, 0x6c, 0x3a, 0x59, 0xec, 0x22, 0x50, 0xc6, 0x52, 0x4f, 0xa5, 0xa8, 0x53, 0x8a, 0xb7, 0x52, 0x92, 0xae, 0xc1, 0x29, 0x2a, - 0x42, 0x04, 0xcf, 0x93, 0x2a, 0xa0, 0x53, 0x89, 0x7f, 0x71, 0x29, 0xa3, 0xd2, 0x2b, 0xb5, 0x04, 0x79, 0x35, 0x1a, 0x5d, 0x4b, 0x1d, - 0x7c, 0x02, 0x9f, 0xf2, 0xd4, 0x66, 0x88, 0xe9, 0xe4, 0x1e, 0x2a, 0xb5, 0x6e, 0x52, 0xf6, 0xb0, 0xe5, 0xeb, 0x1e, 0x8b, 0xd0, 0x90, - 0xc8, 0xee, 0x7a, 0x61, 0xcb, 0x2a, 0x85, 0x8a, 0xb1, 0xb1, 0x5a, 0x25, 0x9e, 0xcb, 0x8d, 0x37, 0x3f, 0x28, 0xf9, 0x9e, 0x50, 0xb0, - 0xb3, 0xd3, 0x50, 0x6d, 0x23, 0x5d, 0xb2, 0x40, 0xc8, 0x83, 0x04, 0x9e, 0x1c, 0x01, 0xec, 0x7d, 0xcf, 0x1b, 0x40, 0xb4, 0x06, 0xb2, - 0xb9, 0xc2, 0xf4, 0xa4, 0x1c, 0xab, 0xe4, 0xb6, 0x91, 0xef, 0x01, 0x57, 0x6f, 0x21, 0xac, 0x0a, 0x96, 0xfd, 0xad, 0x65, 0xa8, 0x2a, - 0xab, 0xc1, 0x04, 0xbd, 0x76, 0x6c, 0x29, 0x28, 0x22, 0x28, 0x43, 0x35, 0x40, 0x72, 0x4d, 0xd1, 0x9d, 0x85, 0x53, 0xd6, 0x5f, 0x0e, - 0xf3, 0x3b, 0x31, 0xc9, 0xee, 0x18, 0x9f, 0xb9, 0xc8, 0x67, 0xfe, 0x40, 0x8f, 0x54, 0x83, 0x83, 0xfe, 0x7b, 0x7a, 0x85, 0x2e, 0x66, - 0x00, 0x48, 0x69, 0xd7, 0x00, 0x9d, 0x8c, 0xfa, 0xfe, 0xda, 0x3e, 0x74, 0x88, 0x5c, 0x2b, 0x04, 0xf3, 0x92, 0x90, 0xd7, 0xe0, 0xec, - 0x05, 0xbe, 0x64, 0x1f, 0xed, 0xc1, 0xfe, 0x39, 0x86, 0x48, 0x52, 0x07, 0x84, 0xb6, 0xc4, 0xff, 0x56, 0xa4, 0x75, 0xe7, 0x11, 0x79, - 0x8a, 0xc9, 0xc2, 0xef, 0x88, 0x1c, 0x7d, 0xf2, 0xab, 0xa1, 0xdd, 0x3e, 0x03, 0xe6, 0x00, 0x5b, 0xb6, 0x79, 0x34, 0xbd, 0xf8, 0x00, - 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x02, 0x00, 0x08, 0x00, 0xa7, 0x64, 0xef, 0x50, 0x59, 0xaf, 0xf9, 0x51, 0xdc, 0x00, 0x00, 0x00, - 0xa8, 0x02, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x78, 0x6c, 0x2f, 0x5f, 0x72, 0x65, 0x6c, 0x73, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x62, - 0x6f, 0x6f, 0x6b, 0x2e, 0x78, 0x6d, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x73, 0xad, 0x92, 0xcd, 0x6a, 0xc3, 0x30, 0x10, 0x84, 0xef, 0x7d, - 0x0a, 0xb1, 0xf7, 0x5a, 0x76, 0x5a, 0x4a, 0x29, 0x51, 0x72, 0x29, 0x85, 0x5c, 0xdb, 0xf4, 0x01, 0x84, 0xbc, 0xb6, 0x4c, 0x6c, 0x49, - 0xec, 0x6e, 0x7f, 0xf2, 0xf6, 0x11, 0x0e, 0x24, 0x31, 0x84, 0x90, 0x83, 0x4f, 0x62, 0x46, 0xda, 0x99, 0x4f, 0xb0, 0xcb, 0xf5, 0xff, - 0xd0, 0xab, 0x5f, 0x24, 0xee, 0x62, 0x30, 0x50, 0x15, 0x25, 0x28, 0x0c, 0x2e, 0xd6, 0x5d, 0x68, 0x0d, 0x7c, 0x6f, 0x3f, 0x1e, 0x5f, - 0x61, 0xbd, 0x5a, 0x7e, 0x62, 0x6f, 0x25, 0xbf, 0x60, 0xdf, 0x25, 0x56, 0x79, 0x24, 0xb0, 0x01, 0x2f, 0x92, 0xde, 0xb4, 0x66, 0xe7, - 0x71, 0xb0, 0x5c, 0xc4, 0x84, 0x21, 0xdf, 0x34, 0x91, 0x06, 0x2b, 0x59, 0x52, 0xab, 0x93, 0x75, 0x3b, 0xdb, 0xa2, 0x5e, 0x94, 0xe5, - 0x8b, 0xa6, 0xcb, 0x0c, 0x98, 0x66, 0xaa, 0x4d, 0x6d, 0x80, 0x36, 0xf5, 0x33, 0xa8, 0xed, 0x3e, 0xe1, 0x3d, 0xd9, 0xb1, 0x69, 0x3a, - 0x87, 0xef, 0xd1, 0xfd, 0x0c, 0x18, 0xe4, 0x4a, 0x85, 0x66, 0x6f, 0x09, 0xeb, 0x2f, 0xa1, 0xfc, 0x17, 0xce, 0xc1, 0x96, 0x5a, 0x14, - 0x03, 0x13, 0xbb, 0xc8, 0xa9, 0xa0, 0xaf, 0xc3, 0x3c, 0xcd, 0x0a, 0x23, 0xfb, 0x1e, 0x2f, 0x28, 0x46, 0x7d, 0xb3, 0x7e, 0x31, 0x67, - 0xbd, 0xe4, 0x59, 0x3c, 0xb7, 0x8f, 0xf2, 0x68, 0x56, 0xb7, 0x18, 0xaa, 0x39, 0x19, 0xfe, 0x22, 0xed, 0xd8, 0x23, 0xca, 0x99, 0xe3, - 0x64, 0xb1, 0x1e, 0x8f, 0x13, 0x8c, 0x9e, 0x6c, 0xdc, 0xea, 0xe1, 0x00, 0x50, 0x4b, 0x01, 0x02, 0x2d, 0x00, 0x14, 0x00, 0x06, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x21, 0x00, 0xb5, 0x55, 0x30, 0x23, 0xf4, 0x00, 0x00, 0x00, 0x4c, 0x02, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x72, 0x65, 0x6c, 0x73, 0x2f, 0x2e, 0x72, - 0x65, 0x6c, 0x73, 0x50, 0x4b, 0x01, 0x02, 0x2d, 0x00, 0x14, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00, 0x21, 0x00, 0x47, 0x88, 0xbc, - 0xe2, 0x5d, 0x03, 0x00, 0x00, 0x35, 0x08, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x25, 0x03, 0x00, 0x00, 0x78, 0x6c, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x62, 0x6f, 0x6f, 0x6b, 0x2e, 0x78, 0x6d, 0x6c, 0x50, 0x4b, - 0x01, 0x02, 0x2d, 0x00, 0x14, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00, 0x21, 0x00, 0xf0, 0x08, 0x58, 0xf4, 0xa5, 0x02, 0x00, 0x00, - 0x52, 0x06, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaf, 0x06, 0x00, 0x00, - 0x78, 0x6c, 0x2f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x73, 0x2e, 0x78, 0x6d, 0x6c, 0x50, 0x4b, 0x01, 0x02, 0x2d, 0x00, 0x14, 0x00, 0x06, - 0x00, 0x08, 0x00, 0x00, 0x00, 0x21, 0x00, 0xc1, 0x17, 0x10, 0xbe, 0x4e, 0x07, 0x00, 0x00, 0xc6, 0x20, 0x00, 0x00, 0x13, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x09, 0x00, 0x00, 0x78, 0x6c, 0x2f, 0x74, 0x68, 0x65, 0x6d, - 0x65, 0x2f, 0x74, 0x68, 0x65, 0x6d, 0x65, 0x31, 0x2e, 0x78, 0x6d, 0x6c, 0x50, 0x4b, 0x01, 0x02, 0x2d, 0x00, 0x14, 0x00, 0x06, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x21, 0x00, 0xff, 0x6b, 0x0c, 0xe9, 0xcd, 0x01, 0x00, 0x00, 0xb5, 0x03, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x10, 0x00, 0x00, 0x78, 0x6c, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x73, - 0x68, 0x65, 0x65, 0x74, 0x73, 0x2f, 0x73, 0x68, 0x65, 0x65, 0x74, 0x31, 0x2e, 0x78, 0x6d, 0x6c, 0x50, 0x4b, 0x01, 0x02, 0x2d, 0x00, - 0x14, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00, 0x21, 0x00, 0xc2, 0x5e, 0x59, 0x08, 0x90, 0x01, 0x00, 0x00, 0x1b, 0x03, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x13, 0x00, 0x00, 0x64, 0x6f, 0x63, 0x50, - 0x72, 0x6f, 0x70, 0x73, 0x2f, 0x61, 0x70, 0x70, 0x2e, 0x78, 0x6d, 0x6c, 0x50, 0x4b, 0x01, 0x02, 0x2d, 0x00, 0x14, 0x00, 0x06, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x21, 0x00, 0xbd, 0xde, 0xac, 0xb8, 0x45, 0x01, 0x00, 0x00, 0x6f, 0x02, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc7, 0x15, 0x00, 0x00, 0x64, 0x6f, 0x63, 0x50, 0x72, 0x6f, 0x70, 0x73, - 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x78, 0x6d, 0x6c, 0x50, 0x4b, 0x01, 0x02, 0x14, 0x03, 0x14, 0x00, 0x02, 0x00, 0x08, 0x00, 0x9a, - 0xab, 0x0f, 0x4f, 0x5e, 0xff, 0xec, 0xaa, 0x93, 0x00, 0x00, 0x00, 0xb2, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x00, 0x00, 0x00, 0xb6, 0x81, 0x43, 0x18, 0x00, 0x00, 0x78, 0x6c, 0x2f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x53, 0x74, - 0x72, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x78, 0x6d, 0x6c, 0x50, 0x4b, 0x01, 0x02, 0x14, 0x03, 0x14, 0x00, 0x02, 0x00, 0x08, 0x00, 0x99, - 0x64, 0xef, 0x50, 0xd9, 0x19, 0xd7, 0x73, 0x3f, 0x01, 0x00, 0x00, 0x7e, 0x04, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x00, 0x00, 0x00, 0xb6, 0x81, 0x08, 0x19, 0x00, 0x00, 0x5b, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x54, 0x79, - 0x70, 0x65, 0x73, 0x5d, 0x2e, 0x78, 0x6d, 0x6c, 0x50, 0x4b, 0x01, 0x02, 0x14, 0x03, 0x14, 0x00, 0x02, 0x00, 0x08, 0x00, 0xa7, 0x64, - 0xef, 0x50, 0x59, 0xaf, 0xf9, 0x51, 0xdc, 0x00, 0x00, 0x00, 0xa8, 0x02, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0xb6, 0x81, 0x78, 0x1a, 0x00, 0x00, 0x78, 0x6c, 0x2f, 0x5f, 0x72, 0x65, 0x6c, 0x73, 0x2f, 0x77, 0x6f, 0x72, - 0x6b, 0x62, 0x6f, 0x6f, 0x6b, 0x2e, 0x78, 0x6d, 0x6c, 0x2e, 0x72, 0x65, 0x6c, 0x73, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, - 0x0a, 0x00, 0x0a, 0x00, 0x80, 0x02, 0x00, 0x00, 0x8c, 0x1b, 0x00, 0x00, 0x00, 0x00 - }; - -} // namespace - XLDocument::XLDocument(const IZipArchive& zipArchive) : m_archive(zipArchive) {} /** @@ -459,9 +101,9 @@ void XLDocument::open(const std::string& fileName) m_data.emplace_back(this, "_rels/.rels"); m_data.emplace_back(this, "xl/_rels/workbook.xml.rels"); - m_contentTypes = XLContentTypes(getXmlData("[Content_Types].xml")); - m_docRelationships = XLRelationships(getXmlData("_rels/.rels")); - m_wbkRelationships = XLRelationships(getXmlData("xl/_rels/workbook.xml.rels")); + m_contentTypes = XLContentTypes(getXmlDataByPath("[Content_Types].xml")); + m_docRelationships = XLRelationships(getXmlDataByPath("_rels/.rels")); + m_wbkRelationships = XLRelationships(getXmlDataByPath("xl/_rels/workbook.xml.rels")); if (!m_archive.hasEntry("xl/sharedStrings.xml")) execCommand(XLCommand(XLCommandType::AddSharedStrings)); @@ -482,7 +124,7 @@ void XLDocument::open(const std::string& fileName) /* xmlType */ item.type()); } - for (const auto& node : getXmlData("xl/sharedStrings.xml")->getXmlDocument()->document_element().children()){ + for (const auto& node : getXmlDataByPath("xl/sharedStrings.xml")->getXmlDocument()->document_element().children()){ if (std::string(node.first_child().name()) == "r") { std::string result; for (const auto& elem : node.children()) @@ -495,7 +137,7 @@ void XLDocument::open(const std::string& fileName) } - m_XmlWorkbook = getXmlData("xl/workbook.xml"); + m_XmlWorkbook = getXmlDataByPath("xl/workbook.xml"); m_XmlWorkbook->setName("workbook"); m_workbook = XLWorkbook(m_XmlWorkbook); @@ -511,60 +153,52 @@ void XLDocument::open(const std::string& fileName) wsItem.setName(m_XmlWorkbook->getXmlDocument()->document_element().child("sheets") .find_child_by_attribute("r:id", wsItem.getXmlID().c_str()) .attribute("name").value()); - - std::string sheetRelsPath = wsItem.getXmlPath(); - std::string::size_type n = sheetRelsPath.find_last_of('/'); - if(nsetName(pDocChild->getXmlDocument()->child("table") + pDocChild->setName(pDocChild->getXmlDocument()->child("table") .attribute("name").value()); - wsItem.addChildNode(pDocChild); - pDocChild->setParentNode(&wsItem); - pDocChild->setXmlID(sheetRels.relationshipByTarget(childItem.target()).id()); + wsItem.addChildNode(pDocChild); + pDocChild->setParentNode(&wsItem); + pDocChild->setXmlID(sheetRels.relationshipByTarget(childItem.target()).id()); //auto type = childItem.type(); - } - - } } + } - } - } - + + } // if XLContentType::Worksheet + } // for m_data // ===== Open the workbook and document property items // TODO: If property data doesn't exist, consider creating them, instead of ignoring it. - m_coreProperties = (hasXmlData("docProps/core.xml") ? XLProperties(getXmlData("docProps/core.xml")) : XLProperties()); - m_appProperties = (hasXmlData("docProps/app.xml") ? XLAppProperties(getXmlData("docProps/app.xml")) : XLAppProperties()); - m_sharedStrings = XLSharedStrings(getXmlData("xl/sharedStrings.xml"), &m_sharedStringCache); + m_coreProperties = (hasXmlData("docProps/core.xml") ? XLProperties(getXmlDataByPath("docProps/core.xml")) : XLProperties()); + m_appProperties = (hasXmlData("docProps/app.xml") ? XLAppProperties(getXmlDataByPath("docProps/app.xml")) : XLAppProperties()); + m_sharedStrings = XLSharedStrings(getXmlDataByPath("xl/sharedStrings.xml"), &m_sharedStringCache); } + /** * @details Create a new document. This is done by saving the data in XLTemplate.h in binary format. */ @@ -575,7 +209,7 @@ void XLDocument::create(const std::string& fileName) // ===== Stream the binary data for an empty workbook to the output file. // ===== Casting, in particular reinterpret_cast, is discouraged, but in this case it is unfortunately unavoidable. - outfile.write(reinterpret_cast(templateData), templateSize); // NOLINT + outfile.write(reinterpret_cast(XLTemplate::templateData), XLTemplate::templateSize); // NOLINT outfile.close(); open(fileName); @@ -620,7 +254,8 @@ void XLDocument::saveAs(const std::string& fileName) execCommand(XLCommand(XLCommandType::ResetCalcChain)); // ===== Add all xml items to archive and save the archive. - for (auto& item : m_data) m_archive.addEntry(item.getXmlPath(), item.getRawData()); + for (auto& item : m_data) + m_archive.addEntry(item.getXmlPath(), item.getRawData()); m_archive.save(m_filePath); } @@ -883,46 +518,28 @@ void XLDocument::execCommand(const XLCommand& command) { break; case XLCommandType::AddSharedStrings: { - std::string sharedStrings { - "\n" - "\n" - " \n" - " \n" - " \n" - "" - }; m_contentTypes.addOverride("/xl/sharedStrings.xml", XLContentType::SharedStrings); m_wbkRelationships.addRelationship(XLRelationshipType::SharedStrings, "sharedStrings.xml"); - m_archive.addEntry("xl/sharedStrings.xml", sharedStrings); + m_archive.addEntry("xl/sharedStrings.xml", XLTemplate::sharedStrings); } break; case XLCommandType::AddWorksheet: { - std::string emptyWorksheet { - "\n" - "" - "" - "" - "" - "" - "" - "" - "" - "" - }; - m_contentTypes.addOverride(command.getParam("sheetPath"), XLContentType::Worksheet); - m_wbkRelationships.addRelationship(XLRelationshipType::Worksheet, command.getParam("sheetPath").substr(4)); + auto internalID = availableFileID(XLContentType::Worksheet); + std::string sheetPath = "xl/worksheets/sheet" + std::to_string(internalID) + ".xml"; + m_contentTypes.addOverride("/" + sheetPath, XLContentType::Worksheet); + m_wbkRelationships.addRelationship(XLRelationshipType::Worksheet, sheetPath.substr(3)); m_appProperties.appendSheetName(command.getParam("sheetName")); - m_archive.addEntry(command.getParam("sheetPath").substr(1), emptyWorksheet); + m_archive.addEntry(sheetPath, XLTemplate::emptyWorksheet); m_data.emplace_back( /* parentDoc */ this, - /* xmlPath */ command.getParam("sheetPath").substr(1), - /* xmlID */ m_wbkRelationships.relationshipByTarget(command.getParam("sheetPath").substr(4)).id(), + /* xmlPath */ sheetPath, + /* xmlID */ m_wbkRelationships.relationshipByTarget(sheetPath.substr(3)).id(), /* xmlID */ command.getParam("sheetName"), /* xmlType */ XLContentType::Worksheet); + + // TODO move elsewhere ? + m_workbook.prepareSheetMetadata(command.getParam("sheetName"), internalID); } break; case XLCommandType::AddChartsheet: @@ -953,7 +570,7 @@ void XLDocument::execCommand(const XLCommand& command) { break; case XLCommandType::CloneSheet: { - auto internalID = m_workbook.createInternalSheetID(); + auto internalID = availableFileID(XLContentType::Worksheet); auto sheetPath = "/xl/worksheets/sheet" + std::to_string(internalID) + ".xml"; if (m_workbook.sheetExists(command.getParam("cloneName"))) throw XLInternalError("Sheet named \"" + command.getParam("cloneName") + "\" already exists."); @@ -1035,7 +652,7 @@ XLQuery XLDocument::execQuery(const XLQuery& query) const return XLQuery(query).setResult(m_sharedStrings); case XLQueryType::QuerySheetFromName: - return XLQuery(query).setResult(getXmlDataBySheetName(query.getParam("sheetName"))); + return XLQuery(query).setResult(getXmlDataByName(query.getParam("sheetName"))); case XLQueryType::QueryTableFromName: { @@ -1087,7 +704,7 @@ bool XLDocument::isOpen() const { /** * @details */ -XLXmlData* XLDocument::getXmlData(const std::string& path) +XLXmlData* XLDocument::getXmlDataByPath(const std::string& path) { if (!hasXmlData(path)) throw XLInternalError("Path does not exist in zip archive."); return &*std::find_if(m_data.begin(), m_data.end(), [&](const XLXmlData& item) { return item.getXmlPath() == path; }); @@ -1099,7 +716,7 @@ XLXmlData* XLDocument::getXmlData(const std::string& path) /** * @details */ -const XLXmlData* XLDocument::getXmlData(const std::string& path) const +const XLXmlData* XLDocument::getXmlDataByPath(const std::string& path) const { if (!hasXmlData(path)) throw XLInternalError("Path does not exist in zip archive."); return &*std::find_if(m_data.begin(), m_data.end(), [&](const XLXmlData& item) { return item.getXmlPath() == path; }); @@ -1123,19 +740,71 @@ std::string XLDocument::extractXmlFromArchive(const std::string& path) return (m_archive.hasEntry(path) ? m_archive.getEntry(path) : ""); } -XLXmlData* XLDocument::getXmlDataBySheetName(const std::string& sheetName) const +XLXmlData* XLDocument::getXmlDataByName(const std::string& name) const { - for(auto sheetXmlData : m_XmlWorkbook->getChildNodes()) - if(sheetXmlData->getName() == sheetName) - return sheetXmlData; + // for(auto objXmlData : m_XmlWorkbook->getChildNodes()) + for(auto& objXmlData : m_data) + if(objXmlData.getName() == name) + return &objXmlData; return nullptr; } +std::string XLDocument::getSheetRelsPath(const std::string& sheetName) const +{ + XLXmlData* wsItem = getXmlDataByName(sheetName); + if (wsItem == nullptr) // sheetName does not exist + return std::string(); + + std::string sheetPath = wsItem->getXmlPath(); + std::string::size_type n = sheetPath.find_last_of('/'); + + if(n>sheetPath.size()) // path does not contains '/' + return std::string(); + + // Some spreadsheets use absolute rather than relative paths in relationship items. + if (sheetPath.substr(0,4) == "/xl/") + sheetPath = "xl/" + sheetPath.substr(4); + + const std::string basePath = sheetPath.substr(0, n); + const std::string fileName = sheetPath.substr(n); + + if (fileName.substr(0, 6) != "/sheet") // This is not a sheet path + return std::string(); + + return basePath + "/_rels" + fileName + ".rels"; +} + +uint16_t XLDocument::availableFileID(XLContentType type) +{ + std::vector fileIndices; + + for (auto& wsItem : m_data) + if (wsItem.getXmlType() == type){ + std::string path = wsItem.getXmlPath(); + std::string::size_type n = path.find_last_of("/"); + // TODO this works because "sheet", "table" and "chart" have same length + fileIndices.push_back(std::stoi(path.substr(n+6,path.size()-n-10))); // removing "table and .xml" + } + + // Get the first available indice for file and id (filling missings) + std::sort (fileIndices.begin(), fileIndices.end()); + uint32_t nFile = 1; + for(uint32_t i : fileIndices) + if (i == nFile) + nFile +=1; + + return nFile; +} + +/** + * @todo check if the reference overlap an existing table + */ void XLDocument::createTable(const std::string& sheetName, const std::string& tableName, const std::string& reference) { - std::vector fileIndices; - std::vector idIndices; + XLXmlData* wks = getXmlDataByName(sheetName); + + std::vector idIndices;; std::string basePath; std::string name = tableName; @@ -1148,74 +817,126 @@ void XLDocument::createTable(const std::string& sheetName, const std::string& ta std::string path = wsItem.getXmlPath(); std::string::size_type n = path.find_last_of("/"); if (basePath.empty()){ - basePath = path.substr(0,n+1); //"xl/tables/" + basePath = path.substr(0,n+1); //"xl/tables/" only the first time } - //std::string t = path.substr(n+6,path.size()-n-10); // removing "table and .xml" - fileIndices.push_back(std::stoi(path.substr(n+6,path.size()-n-10))); // removing "table and .xml" - + XMLNode tableNode = wsItem.getXmlDocument()->child("table"); idIndices.push_back(std::stoi(tableNode.attribute("id").value())); if (( name == tableNode.attribute("name").value()) || ( name == tableNode.attribute("displayName").value())) name += INCREMENT_STRING; } - // Get the first available indice for file and id (filling missings) - std::sort (fileIndices.begin(), fileIndices.end()); - uint32_t nFile = 1; - for(uint32_t i : fileIndices) - if (i == nFile) - nFile +=1; - + std::sort (idIndices.begin(), idIndices.end()); uint32_t nId = 1; for(uint32_t i : idIndices) if (i == nId) nId +=1; - - std::string fileName = basePath + "table" + std::to_string(nFile) + ".xml"; - - // add to contentTypes - m_contentTypes.addOverride(fileName, XLContentType::Table); - - XLXmlData* wks = getXmlDataBySheetName(sheetName); - //add to rels - //m_archive.hasEntry(); - - m_archive.addEntry(fileName, emptyTable); - int i=0; + std::string fileTable = "table" + + std::to_string(availableFileID(XLContentType::Table)) + + ".xml"; + std::string filePath = basePath + fileTable; + + std::string sheetRelsPath = getSheetRelsPath(sheetName); + if (sheetRelsPath.empty()) // sheetname does not exist or error in the path + return; + if (!m_archive.hasEntry(sheetRelsPath)){ // if the file does not exists xl/worksheets/_rels/sheet{0}.xml.rels + m_archive.addEntry(sheetRelsPath, XLTemplate::emptySheetRels); // add the table{0}.xml file + m_data.emplace_back( + /* parentDoc */ this, + /* xmlPath */ sheetRelsPath, + /* xmlID */ std::string(), + /* name */ std::string(), + /* xmlType */ XLContentType::WorksheetRelations, + /* parentNode*/ wks); + wks->addChildNode(getXmlDataByPath(sheetRelsPath)); + } + // adding Rels + auto sheetRels = XLRelationships(getXmlDataByPath(sheetRelsPath)); + auto relItem = sheetRels.addRelationship(XLRelationshipType::Table, "../tables/" + fileTable); + // adding the file table in content, create it and register it + m_contentTypes.addOverride("/" + filePath, XLContentType::Table); // add to contentTypes + m_archive.addEntry(filePath, XLTemplate::emptyTable); // add the table{0}.xml file + + m_data.emplace_back( + /* parentDoc */ this, + /* xmlPath */ filePath, + /* xmlID */ relItem.id(), + /* name */ name, + /* xmlType */ XLContentType::Table, + /* parentNode*/ wks); + XLXmlData* tableXml = getXmlDataByName(name); + wks->addChildNode(tableXml); + + // add tablePart in sheet{0}.xml + XMLNode tableParts = wks->getXmlDocument()->document_element().child("tableParts"); + if(!tableParts){ + tableParts = wks->getXmlDocument()->child("worksheet").append_child("tableParts"); + tableParts.append_attribute("count").set_value("0"); + } + tableParts.attribute("count") + .set_value(std::to_string(std::stoi( + tableParts.attribute("count").value()) + 1 ).c_str()); + XMLNode newPart = tableParts.append_child("tablePart"); + newPart.append_attribute("r:id").set_value(relItem.id().c_str()); + + // Prepare table{0}.xml + XMLDocument* tableDoc = tableXml->getXmlDocument(); + XMLNode tableNode = tableDoc->child("table"); + + // Get safe ref + auto pair = XLCellRange::topLeftBottomRight(reference); + auto topLeft = XLCellReference(pair.first); + auto bottomRight = XLCellReference(pair.second); + std::string ref = topLeft.address(false) + ":" + bottomRight.address(false); + + + tableNode.attribute("id").set_value(std::to_string(nId).c_str()); + tableNode.attribute("name").set_value(name.c_str()); + tableNode.attribute("displayName").set_value(name.c_str()); + tableNode.attribute("ref").set_value(ref.c_str()); + + // Set up the columns !!! + auto topRight = XLCellReference(topLeft.row(),bottomRight.column()); + auto headerRange = XLCellRange(wks->getXmlDocument()->first_child().child("sheetData"), + topLeft, + topRight, + m_sharedStrings); + + // Setup all the columns name + XMLNode columnsNode = tableNode.child("tableColumns"); + uint16_t colId = 1; + std::vector colNames; + + for(auto& cell : headerRange){ + std::string colName = cell.value(); + if (colName.empty()) + colName = "Column"; + bool notValid = true; + while (notValid){ + if (std::find(colNames.begin(), colNames.end(), colName) != colNames.end()) + colName += INCREMENT_STRING; + else + notValid = false; + } + colNames.push_back(colName); + // Fill shared string + // Fill cell value ! + auto newNode = columnsNode.append_child("tableColumn"); + newNode.append_attribute("id").set_value(std::to_string(colId).c_str()); + newNode.append_attribute("name").set_value(colName.c_str()); + colId +=1; + } + // adding the table columns count ! + columnsNode.attribute("count").set_value(std::to_string(colId-1).c_str()); - + // TODEL + int i=0; + } - -/* - std::string emptyWorksheet { - "\n" - "" - "" - "" - "" - "" - "" - "" - "" - "" - }; - m_contentTypes.addOverride(command.getParam("sheetPath"), XLContentType::Worksheet); - m_wbkRelationships.addRelationship(XLRelationshipType::Worksheet, command.getParam("sheetPath").substr(4)); - m_appProperties.appendSheetName(command.getParam("sheetName")); - m_archive.addEntry(command.getParam("sheetPath").substr(1), emptyWorksheet); - m_data.emplace_back( - /* parentDoc this, - /* xmlPath command.getParam("sheetPath").substr(1), - /* xmlID m_wbkRelationships.relationshipByTarget(command.getParam("sheetPath").substr(4)).id(), - /* xmlType XLContentType::Worksheet); -*/ \ No newline at end of file diff --git a/OpenXLSX/sources/XLRelationships.cpp b/OpenXLSX/sources/XLRelationships.cpp index 88e7d27d..aaba5a9a 100644 --- a/OpenXLSX/sources/XLRelationships.cpp +++ b/OpenXLSX/sources/XLRelationships.cpp @@ -147,6 +147,8 @@ namespace typeString = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"; else if (type == XLRelationshipType::Chart) typeString = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart"; + else if (type == XLRelationshipType::Table) + typeString = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/table"; else if (type == XLRelationshipType::ExternalLinkPath) typeString = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/externalLinkPath"; else if (type == XLRelationshipType::PrinterSettings) @@ -161,19 +163,6 @@ namespace return typeString; } - uint32_t GetNewRelsID(XMLNode relationshipsNode) - { - return static_cast(stoi(std::string(std::max_element(relationshipsNode.children().begin(), - relationshipsNode.children().end(), - [](XMLNode a, XMLNode b) { - return stoi(std::string(a.attribute("Id").value()).substr(3)) < - stoi(std::string(b.attribute("Id").value()).substr(3)); - }) - ->attribute("Id") - .value()) - .substr(3)) + - 1); - } } // namespace XLRelationshipItem::XLRelationshipItem() : m_relationshipNode(std::make_unique()) {} @@ -271,11 +260,9 @@ XLRelationshipItem XLRelationships::addRelationship(XLRelationshipType type, con { std::string typeString = GetStringFromType(type); - std::string id = "rId" + std::to_string(GetNewRelsID(xmlDocument().document_element())); - // Create new node in the .rels file auto node = xmlDocument().document_element().append_child("Relationship"); - node.append_attribute("Id").set_value(id.c_str()); + node.append_attribute("Id").set_value(getAvailableRelsId().c_str()); node.append_attribute("Type").set_value(typeString.c_str()); node.append_attribute("Target").set_value(target.c_str()); @@ -301,3 +288,28 @@ bool XLRelationships::idExists(const std::string& id) const { return xmlDocument().document_element().find_child_by_attribute("Id", id.c_str()) != nullptr; } + +/** + * @details Look for hole in the rId field. First load a vector, + * order it and find the first available id. + */ +std::string XLRelationships::getAvailableRelsId() const +{ + std::vector rIdIndices; + + // Find available rId1 + for (auto pChild : xmlDocument().document_element().children()){ + auto test = pChild.attribute("Id").value(); + if(!std::string(pChild.attribute("Id").value()).empty()) + rIdIndices.push_back(std::stoi(std::string(pChild.attribute("Id").value()).substr(3))); + + } + + std::sort (rIdIndices.begin(), rIdIndices.end()); + uint32_t nrId = 1; + for(uint32_t i : rIdIndices) + if (i == nrId) + nrId +=1; + + return ("rId" + std::to_string(nrId)); +} diff --git a/OpenXLSX/sources/XLWorkbook.cpp b/OpenXLSX/sources/XLWorkbook.cpp index 93d3fe5b..4e3fb7d9 100644 --- a/OpenXLSX/sources/XLWorkbook.cpp +++ b/OpenXLSX/sources/XLWorkbook.cpp @@ -239,13 +239,12 @@ void XLWorkbook::addWorksheet(const std::string& sheetName) throw XLInputError("Sheet named \"" + sheetName + "\" already exists."); // ===== Create new internal (workbook) ID for the sheet - auto internalID = createInternalSheetID(); + //auto internalID = createInternalSheetID(); // ===== Create xml file for new worksheet and add metadata to the workbook file. parentDoc().execCommand(XLCommand(XLCommandType::AddWorksheet) - .setParam("sheetName", sheetName) - .setParam("sheetPath", "/xl/worksheets/sheet" + std::to_string(internalID) + ".xml")); - prepareSheetMetadata(sheetName, internalID); + .setParam("sheetName", sheetName)); + } void XLWorkbook::deleteNamedRange(const std::string& rangeName, @@ -349,20 +348,6 @@ void XLWorkbook::cloneSheet(const std::string& existingName, const std::string& .setParam("cloneName", newName)); } -/** - * @details - */ -uint16_t XLWorkbook::createInternalSheetID() -{ - return static_cast(std::max_element(xmlDocument().document_element().child("sheets").children().begin(), - xmlDocument().document_element().child("sheets").children().end(), - [](const XMLNode& a, const XMLNode& b) { - return a.attribute("sheetId").as_uint() < b.attribute("sheetId").as_uint(); - }) - ->attribute("sheetId") - .as_uint() + - 1); -} /** * @details diff --git a/OpenXLSX/sources/XLXmlData.cpp b/OpenXLSX/sources/XLXmlData.cpp index b62e69ae..be5440d7 100644 --- a/OpenXLSX/sources/XLXmlData.cpp +++ b/OpenXLSX/sources/XLXmlData.cpp @@ -83,6 +83,7 @@ XLXmlData::~XLXmlData() = default; */ void XLXmlData::setRawData(const std::string& data) { + //pugi::parse_ws_pcdata pugi::format_raw m_xmlDoc->load_string(data.c_str(), pugi::parse_default | pugi::parse_ws_pcdata); } @@ -113,10 +114,21 @@ void XLXmlData::addChildNode(XLXmlData* childNode) std::string XLXmlData::getRawData() const { std::ostringstream ostr; - getXmlDocument()->save(ostr, "", pugi::format_raw); + + XMLNode decl = m_xmlDoc->prepend_child(pugi::node_declaration); + decl.append_attribute("version") = "1.0"; + decl.append_attribute("encoding") = "UTF-8"; + decl.append_attribute("standalone") = "yes"; + + getXmlDocument()->save(ostr, "", pugi::format_raw , pugi::encoding_utf8); + + //pugi::parse_ws_pcdata pugi::format_raw + std::string test = ostr.str(); return ostr.str(); } + + /** * @details */ From 1ee6bc7b1ac34a596658631757704b6d8dec22f6 Mon Sep 17 00:00:00 2001 From: akira215 Date: Fri, 30 Dec 2022 17:58:37 +0100 Subject: [PATCH 11/45] Turning XLSharedStrings as singleton to be cleared --- OpenXLSX/headers/XLCell.hpp | 4 +- OpenXLSX/headers/XLCellIterator.hpp | 2 +- OpenXLSX/headers/XLCellRange.hpp | 6 +-- OpenXLSX/headers/XLDocument.hpp | 2 +- OpenXLSX/headers/XLRow.hpp | 10 ++-- OpenXLSX/headers/XLRowData.hpp | 8 +-- OpenXLSX/headers/XLSharedStrings.hpp | 54 ++++++++++++++++---- OpenXLSX/headers/XLTableRows.hpp | 4 +- OpenXLSX/headers/XLTemplates.hpp | 8 +-- OpenXLSX/headers/XLWorkbook.hpp | 4 +- OpenXLSX/sources/XLCell.cpp | 12 ++--- OpenXLSX/sources/XLCellIterator.cpp | 16 +++--- OpenXLSX/sources/XLCellRange.cpp | 19 ++++--- OpenXLSX/sources/XLCellValue.cpp | 10 +++- OpenXLSX/sources/XLDocument.cpp | 33 ++++-------- OpenXLSX/sources/XLRow.cpp | 40 +++++++-------- OpenXLSX/sources/XLRowData.cpp | 29 ++++++----- OpenXLSX/sources/XLSharedStrings.cpp | 76 +++++++++++++++++++++++----- OpenXLSX/sources/XLSheet.cpp | 28 +++++----- OpenXLSX/sources/XLTable.cpp | 4 +- OpenXLSX/sources/XLTableRows.cpp | 22 ++++---- OpenXLSX/sources/XLWorkbook.cpp | 13 +++-- 22 files changed, 243 insertions(+), 161 deletions(-) diff --git a/OpenXLSX/headers/XLCell.hpp b/OpenXLSX/headers/XLCell.hpp index 355e8fd4..f39019f8 100644 --- a/OpenXLSX/headers/XLCell.hpp +++ b/OpenXLSX/headers/XLCell.hpp @@ -89,7 +89,7 @@ namespace OpenXLSX * @param cellNode * @param sharedStrings */ - XLCell(const XMLNode& cellNode, const XLSharedStrings& sharedStrings); + XLCell(const XMLNode& cellNode/*, const XLSharedStrings& sharedStrings*/); /** * @brief Copy constructor @@ -193,7 +193,7 @@ namespace OpenXLSX //---------- Private Member Variables ---------- // std::unique_ptr m_cellNode; /**< A pointer to the root XMLNode for the cell. */ - XLSharedStrings m_sharedStrings; /**< */ + //XLSharedStrings m_sharedStrings; /**< */ XLCellValueProxy m_valueProxy; /**< */ XLFormulaProxy m_formulaProxy; /**< */ }; diff --git a/OpenXLSX/headers/XLCellIterator.hpp b/OpenXLSX/headers/XLCellIterator.hpp index a5fe97c3..43f480e4 100644 --- a/OpenXLSX/headers/XLCellIterator.hpp +++ b/OpenXLSX/headers/XLCellIterator.hpp @@ -157,7 +157,7 @@ namespace OpenXLSX XLCellReference m_topLeft; /**< The cell reference of the first cell in the range */ XLCellReference m_bottomRight; /**< The cell reference of the last cell in the range */ XLCell m_currentCell; /**< */ - XLSharedStrings m_sharedStrings; /**< */ + //XLSharedStrings m_sharedStrings; /**< */ bool m_endReached { false }; /**< */ }; diff --git a/OpenXLSX/headers/XLCellRange.hpp b/OpenXLSX/headers/XLCellRange.hpp index 6929ccd1..215541e3 100644 --- a/OpenXLSX/headers/XLCellRange.hpp +++ b/OpenXLSX/headers/XLCellRange.hpp @@ -85,8 +85,8 @@ namespace OpenXLSX */ explicit XLCellRange(const XMLNode& dataNode, const XLCellReference& topLeft, - const XLCellReference& bottomRight, - const XLSharedStrings& sharedStrings); + const XLCellReference& bottomRight + /*const XLSharedStrings& sharedStrings*/); /** * @brief Copy constructor [default]. @@ -191,7 +191,7 @@ namespace OpenXLSX std::unique_ptr m_dataNode; /**< */ XLCellReference m_topLeft; /**< The cell reference of the first cell in the range */ XLCellReference m_bottomRight; /**< The cell reference of the last cell in the range */ - XLSharedStrings m_sharedStrings; + //XLSharedStrings m_sharedStrings; }; } // namespace OpenXLSX diff --git a/OpenXLSX/headers/XLDocument.hpp b/OpenXLSX/headers/XLDocument.hpp index d7b3e8bd..4e43ef77 100644 --- a/OpenXLSX/headers/XLDocument.hpp +++ b/OpenXLSX/headers/XLDocument.hpp @@ -334,7 +334,7 @@ namespace OpenXLSX mutable std::list m_data {}; /**< */ mutable std::deque m_sharedStringCache {}; /**< */ - mutable XLSharedStrings m_sharedStrings {}; /**< */ + //mutable XLSharedStrings* m_sharedStrings; /**< */ XLRelationships m_docRelationships {}; /**< A pointer to the document relationships object*/ XLRelationships m_wbkRelationships {}; /**< A pointer to the document relationships object*/ diff --git a/OpenXLSX/headers/XLRow.hpp b/OpenXLSX/headers/XLRow.hpp index 0c4b2ddf..e2f28105 100644 --- a/OpenXLSX/headers/XLRow.hpp +++ b/OpenXLSX/headers/XLRow.hpp @@ -86,7 +86,7 @@ namespace OpenXLSX * @param rowNode * @param sharedStrings */ - XLRow(const XMLNode& rowNode, const XLSharedStrings& sharedStrings); + XLRow(const XMLNode& rowNode/*, const XLSharedStrings& sharedStrings*/); /** * @brief Copy Constructor @@ -232,7 +232,7 @@ namespace OpenXLSX //---------- PRIVATE MEMBER VARIABLES ----------// std::unique_ptr m_rowNode; /**< The XMLNode object for the row. */ - XLSharedStrings m_sharedStrings; /**< */ + //XLSharedStrings m_sharedStrings; /**< */ XLRowDataProxy m_rowDataProxy; /**< */ }; @@ -335,7 +335,7 @@ namespace OpenXLSX uint32_t m_firstRow { 1 }; /**< The cell reference of the first cell in the range */ uint32_t m_lastRow { 1 }; /**< The cell reference of the last cell in the range */ XLRow m_currentRow; /**< */ - XLSharedStrings m_sharedStrings; /**< */ + //XLSharedStrings m_sharedStrings; /**< */ }; /** @@ -358,7 +358,7 @@ namespace OpenXLSX * @param last * @param sharedStrings */ - explicit XLRowRange(const XMLNode& dataNode, uint32_t first, uint32_t last, const XLSharedStrings& sharedStrings); + explicit XLRowRange(const XMLNode& dataNode, uint32_t first, uint32_t last/*, const XLSharedStrings& sharedStrings*/); /** * @brief @@ -417,7 +417,7 @@ namespace OpenXLSX std::unique_ptr m_dataNode; /**< */ uint32_t m_firstRow; /**< The cell reference of the first cell in the range */ uint32_t m_lastRow; /**< The cell reference of the last cell in the range */ - XLSharedStrings m_sharedStrings; /**< */ + //XLSharedStrings m_sharedStrings; /**< */ }; } // namespace OpenXLSX diff --git a/OpenXLSX/headers/XLRowData.hpp b/OpenXLSX/headers/XLRowData.hpp index 2ef0f12f..e41e9c1b 100644 --- a/OpenXLSX/headers/XLRowData.hpp +++ b/OpenXLSX/headers/XLRowData.hpp @@ -194,12 +194,12 @@ namespace OpenXLSX * @param lastColumn The index of the last column. * @param sharedStrings A pointer to the shared strings repository. */ - explicit XLRowDataRange(const XMLNode& rowNode, uint16_t firstColumn, uint16_t lastColumn, const XLSharedStrings& sharedStrings); + explicit XLRowDataRange(const XMLNode& rowNode, uint16_t firstColumn, uint16_t lastColumn/*, const XLSharedStrings& sharedStrings*/); std::unique_ptr m_rowNode; /**< */ uint16_t m_firstCol { 1 }; /**< The cell reference of the first cell in the range */ uint16_t m_lastCol { 1 }; /**< The cell reference of the last cell in the range */ - XLSharedStrings m_sharedStrings; /**< */ + //XLSharedStrings m_sharedStrings; /**< */ }; /** @@ -269,7 +269,7 @@ namespace OpenXLSX // ===== If the container value_type is a POD type, use the overloaded operator= on each cell. else { - auto range = XLRowDataRange(*m_rowNode, 1, values.size(), getSharedStrings()); + auto range = XLRowDataRange(*m_rowNode, 1, values.size()/*, getSharedStrings()*/); auto dst = range.begin(); auto src = values.begin(); @@ -368,7 +368,7 @@ namespace OpenXLSX * @brief Helper function for getting a pointer to the shared strings repository. * @return A pointer to an XLSharedStrings object. */ - XLSharedStrings getSharedStrings() const; + //XLSharedStrings getSharedStrings() const; /** * @brief Convenience function for erasing the first 'count' numbers of values in the row. diff --git a/OpenXLSX/headers/XLSharedStrings.hpp b/OpenXLSX/headers/XLSharedStrings.hpp index 94914c56..5a5813a5 100644 --- a/OpenXLSX/headers/XLSharedStrings.hpp +++ b/OpenXLSX/headers/XLSharedStrings.hpp @@ -51,12 +51,20 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. #pragma warning(disable : 4275) #include +#include #include +#include + +//#include // ===== OpenXLSX Includes ===== // #include "OpenXLSX-Exports.hpp" #include "XLXmlFile.hpp" +//#include "XLXmlData.hpp" +//#include "XLDocument.hpp" + + namespace OpenXLSX { /** @@ -74,51 +82,76 @@ namespace OpenXLSX /** * @brief */ - XLSharedStrings() = default; + //XLSharedStrings() = default; /** * @brief * @param xmlData */ - explicit XLSharedStrings(XLXmlData* xmlData, std::deque *stringCache); + //explicit XLSharedStrings(XLXmlData* xmlData, std::deque *stringCache); + //explicit XLSharedStrings(XLXmlData* xmlData); + + ///////////////////// @brief ////////////////////////////////////////////////////// + private: + XLSharedStrings(XLXmlData* xmlData); + + XLSharedStrings(const XLSharedStrings&) = delete; + void operator=(const XLSharedStrings&) = delete; + public: + static XLSharedStrings& instance(std::function *init = nullptr) { + static XLSharedStrings s{(*init)()}; + return s; + } + + static void initialize(XLXmlData* d) { + std::function init = [d]() { return XLSharedStrings(d); }; + instance(&init); + } + + + + + /////////// @brief ////////////////////////////////////////////////////// + + /** * @brief Destructor */ - ~XLSharedStrings(); + //~XLSharedStrings(); /** * @brief * @param other */ - XLSharedStrings(const XLSharedStrings& other) = default; + //XLSharedStrings(const XLSharedStrings& other) = default; /** * @brief * @param other */ - XLSharedStrings(XLSharedStrings&& other) noexcept = default; + //XLSharedStrings(XLSharedStrings&& other) noexcept = default; /** * @brief * @param other * @return */ - XLSharedStrings& operator=(const XLSharedStrings& other) = default; + //XLSharedStrings& operator=(const XLSharedStrings& other) = default; /** * @brief * @param other * @return */ - XLSharedStrings& operator=(XLSharedStrings&& other) noexcept = default; + //XLSharedStrings& operator=(XLSharedStrings&& other) noexcept = default; /** * @brief * @param str * @return */ - int32_t getStringIndex(const std::string& str) const; + uint32_t getStringIndex(const std::string& str) const; /** * @brief @@ -139,7 +172,7 @@ namespace OpenXLSX * @param str The string to append. * @return A long int with the index of the appended string */ - int32_t appendString(const std::string& str); + uint32_t appendString(const std::string& str); /** * @brief Clear the string at the given index. @@ -151,7 +184,8 @@ namespace OpenXLSX void clearString(uint64_t index); private: - std::deque *m_stringCache {}; /** < Each string must have an unchanging memory address; hence the use of std::deque */ + std::vector m_stringShared; /** < Each string must have an unchanging memory address; hence the use of std::deque */ + //std::deque *m_stringCache {}; /** < Each string must have an unchanging memory address; hence the use of std::deque */ }; } // namespace OpenXLSX diff --git a/OpenXLSX/headers/XLTableRows.hpp b/OpenXLSX/headers/XLTableRows.hpp index ffd0859f..ddd7b082 100644 --- a/OpenXLSX/headers/XLTableRows.hpp +++ b/OpenXLSX/headers/XLTableRows.hpp @@ -181,8 +181,8 @@ namespace OpenXLSX uint32_t firstRow, uint32_t lastRow, uint16_t firstCol, - uint16_t lastCol, - const OpenXLSX::XLSharedStrings& sharedStrings); + uint16_t lastCol + /*const OpenXLSX::XLSharedStrings& sharedStrings*/); /** * @brief Copy Constructor * @param other diff --git a/OpenXLSX/headers/XLTemplates.hpp b/OpenXLSX/headers/XLTemplates.hpp index 4af1ead3..c42b7b2a 100644 --- a/OpenXLSX/headers/XLTemplates.hpp +++ b/OpenXLSX/headers/XLTemplates.hpp @@ -12,10 +12,10 @@ namespace OpenXLSX namespace XLTemplate { const std::string sharedStrings { "\n" - "\n" - " \n" - " \n" - " \n" + "" + //" \n" + //" \n" + //" \n" "" }; const std::string emptyWorksheet { diff --git a/OpenXLSX/headers/XLWorkbook.hpp b/OpenXLSX/headers/XLWorkbook.hpp index 783ef893..8efb2c88 100644 --- a/OpenXLSX/headers/XLWorkbook.hpp +++ b/OpenXLSX/headers/XLWorkbook.hpp @@ -325,13 +325,13 @@ namespace OpenXLSX * @brief * @return */ - XLSharedStrings sharedStrings(); + // XLSharedStrings sharedStrings(); /** * @brief * @return */ - bool hasSharedStrings() const; + // bool hasSharedStrings() const; /** * @brief diff --git a/OpenXLSX/sources/XLCell.cpp b/OpenXLSX/sources/XLCell.cpp index dc479650..76a2f079 100644 --- a/OpenXLSX/sources/XLCell.cpp +++ b/OpenXLSX/sources/XLCell.cpp @@ -68,9 +68,9 @@ XLCell::XLCell() * If a cell XMLNode does not exist (i.e., the cell is empty), use the relevant constructor to create an XLCell * from a XLCellReference parameter. */ -XLCell::XLCell(const XMLNode& cellNode, const XLSharedStrings& sharedStrings) +XLCell::XLCell(const XMLNode& cellNode/*, const XLSharedStrings& sharedStrings*/) : m_cellNode(std::make_unique(cellNode)), - m_sharedStrings(sharedStrings), + //m_sharedStrings(sharedStrings), m_valueProxy(XLCellValueProxy(this, m_cellNode.get())), m_formulaProxy(XLFormulaProxy(this, m_cellNode.get())) {} @@ -80,7 +80,7 @@ XLCell::XLCell(const XMLNode& cellNode, const XLSharedStrings& sharedStrings) */ XLCell::XLCell(const XLCell& other) : m_cellNode(other.m_cellNode ? std::make_unique(*other.m_cellNode) : nullptr), - m_sharedStrings(other.m_sharedStrings), + //m_sharedStrings(other.m_sharedStrings), m_valueProxy(XLCellValueProxy(this, m_cellNode.get())), m_formulaProxy(XLFormulaProxy(this, m_cellNode.get())) {} @@ -90,7 +90,7 @@ XLCell::XLCell(const XLCell& other) */ XLCell::XLCell(XLCell&& other) noexcept : m_cellNode(std::move(other.m_cellNode)), - m_sharedStrings(std::move(other.m_sharedStrings)), + //m_sharedStrings(std::move(other.m_sharedStrings)), m_valueProxy(XLCellValueProxy(this, m_cellNode.get())), m_formulaProxy(XLFormulaProxy(this, m_cellNode.get())) {} @@ -120,7 +120,7 @@ XLCell& XLCell::operator=(XLCell&& other) noexcept { if (&other != this) { m_cellNode = std::move(other.m_cellNode); - m_sharedStrings = other.m_sharedStrings; + //m_sharedStrings = other.m_sharedStrings; m_valueProxy = XLCellValueProxy(this, m_cellNode.get()); } @@ -153,7 +153,7 @@ XLCell XLCell::offset(uint16_t rowOffset, uint16_t colOffset) const XLCellReference offsetRef(cellReference().row() + rowOffset, cellReference().column() + colOffset); auto rownode = getRowNode(m_cellNode->parent().parent(), offsetRef.row()); auto cellnode = getCellNode(rownode, offsetRef.column()); - return XLCell{cellnode, m_sharedStrings}; + return XLCell{cellnode/*, m_sharedStrings*/}; } /** diff --git a/OpenXLSX/sources/XLCellIterator.cpp b/OpenXLSX/sources/XLCellIterator.cpp index 9477f571..e11913a4 100644 --- a/OpenXLSX/sources/XLCellIterator.cpp +++ b/OpenXLSX/sources/XLCellIterator.cpp @@ -66,13 +66,13 @@ namespace OpenXLSX XLCellIterator::XLCellIterator(const XLCellRange& cellRange, XLIteratorLocation loc) : m_dataNode(std::make_unique(*cellRange.m_dataNode)), m_topLeft(cellRange.m_topLeft), - m_bottomRight(cellRange.m_bottomRight), - m_sharedStrings(cellRange.m_sharedStrings) + m_bottomRight(cellRange.m_bottomRight) + //m_sharedStrings(cellRange.m_sharedStrings) { if (loc == XLIteratorLocation::End) m_currentCell = XLCell(); else { - m_currentCell = XLCell(getCellNode(getRowNode(*m_dataNode, m_topLeft.row()), m_topLeft.column()), m_sharedStrings); + m_currentCell = XLCell(getCellNode(getRowNode(*m_dataNode, m_topLeft.row()), m_topLeft.column())); } } @@ -88,8 +88,8 @@ XLCellIterator::XLCellIterator(const XLCellIterator& other) : m_dataNode(std::make_unique(*other.m_dataNode)), m_topLeft(other.m_topLeft), m_bottomRight(other.m_bottomRight), - m_currentCell(other.m_currentCell), - m_sharedStrings(other.m_sharedStrings) + m_currentCell(other.m_currentCell) + //m_sharedStrings(other.m_sharedStrings) {} /** @@ -107,7 +107,7 @@ XLCellIterator& XLCellIterator::operator=(const XLCellIterator& other) m_topLeft = other.m_topLeft; m_bottomRight = other.m_bottomRight; m_currentCell = other.m_currentCell; - m_sharedStrings = other.m_sharedStrings; + //m_sharedStrings = other.m_sharedStrings; } return *this; @@ -141,7 +141,7 @@ XLCellIterator& XLCellIterator::operator++() node = m_currentCell.m_cellNode->parent().insert_child_after("c", *m_currentCell.m_cellNode); node.append_attribute("r").set_value(ref.address().c_str()); } - m_currentCell = XLCell(node, m_sharedStrings); + m_currentCell = XLCell(node); } else if (ref.row() > m_currentCell.cellReference().row()) { auto rowNode = m_currentCell.m_cellNode->parent().next_sibling(); @@ -151,7 +151,7 @@ XLCellIterator& XLCellIterator::operator++() // getRowNode(*m_dataNode, ref.row()); } - m_currentCell = XLCell(getCellNode(rowNode, ref.column()), m_sharedStrings); + m_currentCell = XLCell(getCellNode(rowNode, ref.column())); } else throw XLInternalError("An internal error occured"); diff --git a/OpenXLSX/sources/XLCellRange.cpp b/OpenXLSX/sources/XLCellRange.cpp index 8dedce89..dfd70931 100644 --- a/OpenXLSX/sources/XLCellRange.cpp +++ b/OpenXLSX/sources/XLCellRange.cpp @@ -66,12 +66,12 @@ namespace OpenXLSX */ XLCellRange::XLCellRange(const XMLNode& dataNode, const XLCellReference& topLeft, - const XLCellReference& bottomRight, - const XLSharedStrings& sharedStrings) + const XLCellReference& bottomRight + /*const XLSharedStrings& sharedStrings*/) : m_dataNode(std::make_unique(dataNode)), m_topLeft(topLeft), - m_bottomRight(bottomRight), - m_sharedStrings(sharedStrings) + m_bottomRight(bottomRight) + //m_sharedStrings(sharedStrings) {} /** @@ -82,8 +82,8 @@ XLCellRange::XLCellRange(const XMLNode& dataNode, XLCellRange::XLCellRange(const XLCellRange& other) : m_dataNode(std::make_unique(*other.m_dataNode)), m_topLeft(other.m_topLeft), - m_bottomRight(other.m_bottomRight), - m_sharedStrings(other.m_sharedStrings) + m_bottomRight(other.m_bottomRight) + //m_sharedStrings(other.m_sharedStrings) {} /** @@ -111,7 +111,7 @@ XLCellRange& XLCellRange::operator=(const XLCellRange& other) *m_dataNode = *other.m_dataNode; m_topLeft = other.m_topLeft; m_bottomRight = other.m_bottomRight; - m_sharedStrings = other.m_sharedStrings; + //m_sharedStrings = other.m_sharedStrings; } return *this; @@ -128,7 +128,7 @@ XLCellRange& XLCellRange::operator=(XLCellRange&& other) noexcept *m_dataNode = *other.m_dataNode; m_topLeft = other.m_topLeft; m_bottomRight = other.m_bottomRight; - m_sharedStrings = other.m_sharedStrings; + //m_sharedStrings = other.m_sharedStrings; } return *this; @@ -163,8 +163,7 @@ XLCell XLCellRange::operator[](uint32_t index) const if(row > m_bottomRight.row()) return XLCell(); - return XLCell(getCellNode(getRowNode(*m_dataNode, row), - col), m_sharedStrings); + return XLCell(getCellNode(getRowNode(*m_dataNode, row), col)); } /** diff --git a/OpenXLSX/sources/XLCellValue.cpp b/OpenXLSX/sources/XLCellValue.cpp index 27cb64e5..edec2392 100644 --- a/OpenXLSX/sources/XLCellValue.cpp +++ b/OpenXLSX/sources/XLCellValue.cpp @@ -402,9 +402,15 @@ void XLCellValueProxy::setString(const char* stringValue) m_cellNode->attribute("t").set_value("s"); // ===== Get or create the index in the XLSharedStrings object. + uint32_t index; + if (XLSharedStrings::instance().stringExists(stringValue)) + index = XLSharedStrings::instance().getStringIndex(stringValue); + else + index = XLSharedStrings::instance().appendString(stringValue); +/* auto index = (m_cell->m_sharedStrings.stringExists(stringValue) ? m_cell->m_sharedStrings.getStringIndex(stringValue) : m_cell->m_sharedStrings.appendString(stringValue)); - +*/ // ===== Set the text of the value node. m_cellNode->child("v").text().set(index); @@ -443,7 +449,7 @@ XLCellValue XLCellValueProxy::getValue() const case XLValueType::String: if (strcmp(m_cellNode->attribute("t").value(), "s") == 0) - return XLCellValue { m_cell->m_sharedStrings.getString(static_cast(m_cellNode->child("v").text().as_ullong())) }; + return XLCellValue { XLSharedStrings::instance().getString(static_cast(m_cellNode->child("v").text().as_ullong())) }; else if (strcmp(m_cellNode->attribute("t").value(), "str") == 0) return XLCellValue { m_cellNode->child("v").text().get() }; else if (strcmp(m_cellNode->attribute("t").value(), "inlineStr") == 0) diff --git a/OpenXLSX/sources/XLDocument.cpp b/OpenXLSX/sources/XLDocument.cpp index a474e274..bd61485c 100644 --- a/OpenXLSX/sources/XLDocument.cpp +++ b/OpenXLSX/sources/XLDocument.cpp @@ -124,19 +124,6 @@ void XLDocument::open(const std::string& fileName) /* xmlType */ item.type()); } - for (const auto& node : getXmlDataByPath("xl/sharedStrings.xml")->getXmlDocument()->document_element().children()){ - if (std::string(node.first_child().name()) == "r") { - std::string result; - for (const auto& elem : node.children()) - result += elem.child("t").text().get(); - m_sharedStringCache.emplace_back(result); - } - - else - m_sharedStringCache.emplace_back(node.first_child().text().get()); - - } - m_XmlWorkbook = getXmlDataByPath("xl/workbook.xml"); m_XmlWorkbook->setName("workbook"); m_workbook = XLWorkbook(m_XmlWorkbook); @@ -194,8 +181,9 @@ void XLDocument::open(const std::string& fileName) // TODO: If property data doesn't exist, consider creating them, instead of ignoring it. m_coreProperties = (hasXmlData("docProps/core.xml") ? XLProperties(getXmlDataByPath("docProps/core.xml")) : XLProperties()); m_appProperties = (hasXmlData("docProps/app.xml") ? XLAppProperties(getXmlDataByPath("docProps/app.xml")) : XLAppProperties()); - m_sharedStrings = XLSharedStrings(getXmlDataByPath("xl/sharedStrings.xml"), &m_sharedStringCache); - + XLSharedStrings::initialize(getXmlDataByPath("xl/sharedStrings.xml")); + //m_sharedStrings = XLSharedStrings(getXmlDataByPath("xl/sharedStrings.xml")); + //m_sharedStrings = XLSharedStrings(getXmlDataByPath("xl/sharedStrings.xml"), &m_sharedStringCache); } @@ -649,7 +637,8 @@ XLQuery XLDocument::execQuery(const XLQuery& query) const return XLQuery(query).setResult(m_wbkRelationships.relationshipById(query.getParam("sheetID")).target()); case XLQueryType::QuerySharedStrings: - return XLQuery(query).setResult(m_sharedStrings); + //return XLQuery(query).setResult(m_sharedStrings); + return XLQuery(query).setResult(1); case XLQueryType::QuerySheetFromName: return XLQuery(query).setResult(getXmlDataByName(query.getParam("sheetName"))); @@ -806,7 +795,7 @@ void XLDocument::createTable(const std::string& sheetName, const std::string& ta std::vector idIndices;; - std::string basePath; + std::string basePath = "xl/tables/"; std::string name = tableName; // Loop through existing tables to find the available: // - filename @@ -816,9 +805,6 @@ void XLDocument::createTable(const std::string& sheetName, const std::string& ta if (wsItem.getXmlType() == XLContentType::Table){ std::string path = wsItem.getXmlPath(); std::string::size_type n = path.find_last_of("/"); - if (basePath.empty()){ - basePath = path.substr(0,n+1); //"xl/tables/" only the first time - } XMLNode tableNode = wsItem.getXmlDocument()->child("table"); idIndices.push_back(std::stoi(tableNode.attribute("id").value())); @@ -906,8 +892,8 @@ void XLDocument::createTable(const std::string& sheetName, const std::string& ta auto topRight = XLCellReference(topLeft.row(),bottomRight.column()); auto headerRange = XLCellRange(wks->getXmlDocument()->first_child().child("sheetData"), topLeft, - topRight, - m_sharedStrings); + topRight + /*m_sharedStrings*/); // Setup all the columns name XMLNode columnsNode = tableNode.child("tableColumns"); @@ -926,6 +912,7 @@ void XLDocument::createTable(const std::string& sheetName, const std::string& ta notValid = false; } colNames.push_back(colName); + cell.value() = colName; // Fill shared string // Fill cell value ! auto newNode = columnsNode.append_child("tableColumn"); @@ -933,7 +920,7 @@ void XLDocument::createTable(const std::string& sheetName, const std::string& ta newNode.append_attribute("name").set_value(colName.c_str()); colId +=1; } - // adding the table columns count ! + // adding the table columns count columnsNode.attribute("count").set_value(std::to_string(colId-1).c_str()); // TODEL diff --git a/OpenXLSX/sources/XLRow.cpp b/OpenXLSX/sources/XLRow.cpp index 08fa0952..41a3c16d 100644 --- a/OpenXLSX/sources/XLRow.cpp +++ b/OpenXLSX/sources/XLRow.cpp @@ -70,9 +70,9 @@ namespace OpenXLSX * @pre * @post */ - XLRow::XLRow(const XMLNode& rowNode, const XLSharedStrings& sharedStrings) + XLRow::XLRow(const XMLNode& rowNode/*, const XLSharedStrings& sharedStrings*/) : m_rowNode(std::make_unique(rowNode)), - m_sharedStrings(sharedStrings), + //m_sharedStrings(sharedStrings), m_rowDataProxy(this, m_rowNode.get()) {} @@ -83,7 +83,7 @@ namespace OpenXLSX */ XLRow::XLRow(const XLRow& other) : m_rowNode(other.m_rowNode ? std::make_unique(*other.m_rowNode) : nullptr), - m_sharedStrings(other.m_sharedStrings), + //m_sharedStrings(other.m_sharedStrings), m_rowDataProxy(this, m_rowNode.get()) {} @@ -95,7 +95,7 @@ namespace OpenXLSX */ XLRow::XLRow(XLRow&& other) noexcept : m_rowNode(std::move(other.m_rowNode)), - m_sharedStrings(std::move(other.m_sharedStrings)), + //m_sharedStrings(std::move(other.m_sharedStrings)), m_rowDataProxy(this, m_rowNode.get()) {} @@ -130,7 +130,7 @@ namespace OpenXLSX { if (&other != this) { m_rowNode = std::move(other.m_rowNode); - m_sharedStrings = other.m_sharedStrings; + //m_sharedStrings = other.m_sharedStrings; m_rowDataProxy = XLRowDataProxy(this, m_rowNode.get()); } return *this; @@ -264,7 +264,7 @@ namespace OpenXLSX */ XLRowDataRange XLRow::cells() const { - return XLRowDataRange(*m_rowNode, 1, XLCellReference(m_rowNode->last_child().attribute("r").value()).column(), m_sharedStrings); + return XLRowDataRange(*m_rowNode, 1, XLCellReference(m_rowNode->last_child().attribute("r").value()).column()/*, m_sharedStrings*/); } /** @@ -274,7 +274,7 @@ namespace OpenXLSX */ XLRowDataRange XLRow::cells(uint16_t cellCount) const { - return XLRowDataRange(*m_rowNode, 1, cellCount, m_sharedStrings); + return XLRowDataRange(*m_rowNode, 1, cellCount/*, m_sharedStrings*/); } /** @@ -284,7 +284,7 @@ namespace OpenXLSX */ XLRowDataRange XLRow::cells(uint16_t firstCell, uint16_t lastCell) const { - return XLRowDataRange(*m_rowNode, firstCell, lastCell, m_sharedStrings); + return XLRowDataRange(*m_rowNode, firstCell, lastCell/*, m_sharedStrings*/); } bool XLRow::isEqual(const XLRow& lhs, const XLRow& rhs) @@ -314,13 +314,13 @@ namespace OpenXLSX XLRowIterator::XLRowIterator(const XLRowRange& rowRange, XLIteratorLocation loc) : m_dataNode(std::make_unique(*rowRange.m_dataNode)), m_firstRow(rowRange.m_firstRow), - m_lastRow(rowRange.m_lastRow), - m_sharedStrings(rowRange.m_sharedStrings) + m_lastRow(rowRange.m_lastRow) + //m_sharedStrings(rowRange.m_sharedStrings) { if (loc == XLIteratorLocation::End) m_currentRow = XLRow(); else { - m_currentRow = XLRow(getRowNode(*m_dataNode, m_firstRow), m_sharedStrings); + m_currentRow = XLRow(getRowNode(*m_dataNode, m_firstRow)/*, m_sharedStrings*/); } } @@ -340,8 +340,8 @@ namespace OpenXLSX : m_dataNode(std::make_unique(*other.m_dataNode)), m_firstRow(other.m_firstRow), m_lastRow(other.m_lastRow), - m_currentRow(other.m_currentRow), - m_sharedStrings(other.m_sharedStrings) + m_currentRow(other.m_currentRow) + //m_sharedStrings(other.m_sharedStrings) {} /** @@ -389,11 +389,11 @@ namespace OpenXLSX else if (!rowNode || rowNode.attribute("r").as_ullong() != rowNumber) { rowNode = m_dataNode->insert_child_after("row", *m_currentRow.m_rowNode); rowNode.append_attribute("r").set_value(rowNumber); - m_currentRow = XLRow(rowNode, m_sharedStrings); + m_currentRow = XLRow(rowNode/*, m_sharedStrings*/); } else - m_currentRow = XLRow(rowNode, m_sharedStrings); + m_currentRow = XLRow(rowNode/*, m_sharedStrings*/); return *this; } @@ -470,11 +470,11 @@ namespace OpenXLSX * @pre * @post */ - XLRowRange::XLRowRange(const XMLNode& dataNode, uint32_t first, uint32_t last, const OpenXLSX::XLSharedStrings& sharedStrings) + XLRowRange::XLRowRange(const XMLNode& dataNode, uint32_t first, uint32_t last/*, const OpenXLSX::XLSharedStrings& sharedStrings*/) : m_dataNode(std::make_unique(dataNode)), m_firstRow(first), - m_lastRow(last), - m_sharedStrings(sharedStrings) + m_lastRow(last) + //m_sharedStrings(sharedStrings) {} /** @@ -485,8 +485,8 @@ namespace OpenXLSX XLRowRange::XLRowRange(const XLRowRange& other) : m_dataNode(std::make_unique(*other.m_dataNode)), m_firstRow(other.m_firstRow), - m_lastRow(other.m_lastRow), - m_sharedStrings(other.m_sharedStrings) + m_lastRow(other.m_lastRow) + //m_sharedStrings(other.m_sharedStrings) {} /** diff --git a/OpenXLSX/sources/XLRowData.cpp b/OpenXLSX/sources/XLRowData.cpp index c33a9960..4445d91b 100644 --- a/OpenXLSX/sources/XLRowData.cpp +++ b/OpenXLSX/sources/XLRowData.cpp @@ -64,7 +64,7 @@ namespace OpenXLSX XLRowDataIterator::XLRowDataIterator(const XLRowDataRange& rowDataRange, XLIteratorLocation loc) : m_dataRange(std::make_unique(rowDataRange)), m_cellNode(std::make_unique(getCellNode(*m_dataRange->m_rowNode, m_dataRange->m_firstCol))), - m_currentCell(loc == XLIteratorLocation::End ? XLCell() : XLCell(*m_cellNode, m_dataRange->m_sharedStrings)) + m_currentCell(loc == XLIteratorLocation::End ? XLCell() : XLCell(*m_cellNode/*, m_dataRange->m_sharedStrings*/)) {} /** @@ -140,13 +140,13 @@ namespace OpenXLSX XLCellReference( static_cast(m_dataRange->m_rowNode->attribute("r").as_ullong()), static_cast(cellNumber)).address().c_str()); - m_currentCell = XLCell(cellNode, m_dataRange->m_sharedStrings); + m_currentCell = XLCell(cellNode/*, m_dataRange->m_sharedStrings*/); } // ===== Otherwise, the cell node and the column number match. else { assert(XLCellReference(cellNode.attribute("r").value()).column() == cellNumber); - m_currentCell = XLCell(cellNode, m_dataRange->m_sharedStrings); + m_currentCell = XLCell(cellNode/*, m_dataRange->m_sharedStrings*/); } return *this; @@ -219,11 +219,11 @@ namespace OpenXLSX * @pre * @post */ - XLRowDataRange::XLRowDataRange(const XMLNode& rowNode, uint16_t firstColumn, uint16_t lastColumn, const XLSharedStrings& sharedStrings) + XLRowDataRange::XLRowDataRange(const XMLNode& rowNode, uint16_t firstColumn, uint16_t lastColumn/*, const XLSharedStrings& sharedStrings*/) : m_rowNode(std::make_unique(rowNode)), m_firstCol(firstColumn), - m_lastCol(lastColumn), - m_sharedStrings(sharedStrings) + m_lastCol(lastColumn) + //m_sharedStrings(sharedStrings) { if (lastColumn < firstColumn) { m_firstCol = 1; @@ -240,8 +240,8 @@ namespace OpenXLSX XLRowDataRange::XLRowDataRange(const XLRowDataRange& other) : m_rowNode(std::make_unique(*other.m_rowNode)), m_firstCol(other.m_firstCol), - m_lastCol(other.m_lastCol), - m_sharedStrings(other.m_sharedStrings) + m_lastCol(other.m_lastCol) + //m_sharedStrings(other.m_sharedStrings) {} @@ -391,7 +391,7 @@ namespace OpenXLSX curNode = m_rowNode->prepend_child("c"); curNode.append_attribute("r").set_value(XLCellReference(static_cast(m_row->rowNumber()), static_cast(colNo)).address().c_str()); - XLCell(curNode, m_row->m_sharedStrings).value() = *value; + XLCell(curNode/*, m_row->m_sharedStrings*/).value() = *value; --colNo; } @@ -411,7 +411,7 @@ namespace OpenXLSX if (values.size() > MAX_COLS) throw XLOverflowError("Container size exceeds maximum number of columns."); if (values.empty()) return *this; - auto range = XLRowDataRange(*m_rowNode, 1, static_cast(values.size()), getSharedStrings()); + auto range = XLRowDataRange(*m_rowNode, 1, static_cast(values.size())/*, getSharedStrings()*/); auto dst = range.begin(); auto src = values.begin(); @@ -470,7 +470,7 @@ namespace OpenXLSX // ===== If there are one or more cells in the current row, iterate through them and add the value to the container. if (numCells > 0) { for (auto& node : m_rowNode->children()) - result[XLCellReference(node.attribute("r").value()).column() - 1] = XLCell(node, m_row->m_sharedStrings).value(); + result[XLCellReference(node.attribute("r").value()).column() - 1] = XLCell(node/*, m_row->m_sharedStrings*/).value(); } // ===== Return the resulting container. @@ -483,10 +483,13 @@ namespace OpenXLSX * @pre * @post */ + /* XLSharedStrings XLRowDataProxy::getSharedStrings() const { - return m_row->m_sharedStrings; + //return m_row->m_sharedStrings; + return XLSharedStrings::instance(); } + */ /** * @details The deleteCellValues is a convenience function used solely by the templated operator= function. @@ -517,7 +520,7 @@ namespace OpenXLSX { auto curNode = m_rowNode->prepend_child("c"); curNode.append_attribute("r").set_value(XLCellReference(static_cast(m_row->rowNumber()), col).address().c_str()); - XLCell(curNode, m_row->m_sharedStrings).value() = value; + XLCell(curNode/*, m_row->m_sharedStrings*/).value() = value; } /** diff --git a/OpenXLSX/sources/XLSharedStrings.cpp b/OpenXLSX/sources/XLSharedStrings.cpp index c353d4f4..5a26d534 100644 --- a/OpenXLSX/sources/XLSharedStrings.cpp +++ b/OpenXLSX/sources/XLSharedStrings.cpp @@ -57,23 +57,51 @@ using namespace OpenXLSX; * @details Constructs a new XLSharedStrings object. Only one (common) object is allowed per XLDocument instance. * A filepath to the underlying XML file must be provided. */ -XLSharedStrings::XLSharedStrings(XLXmlData* xmlData, std::deque *stringCache) : XLXmlFile(xmlData), m_stringCache(stringCache) +/* +XLSharedStrings::XLSharedStrings(XLXmlData* xmlData, std::deque *stringCache) + : XLXmlFile(xmlData), m_stringCache(stringCache) { } +*/ +XLSharedStrings::XLSharedStrings(XLXmlData* xmlData) + : XLXmlFile(xmlData) +{ -/** - * @details - */ -XLSharedStrings::~XLSharedStrings() = default; + for (const auto& node : m_xmlData->getXmlDocument()->document_element().children()){ + if (std::string(node.first_child().name()) == "r") { + std::string result; + for (const auto& elem : node.children()) + result += elem.child("t").text().get(); + m_stringShared.push_back(result); + + } else { + m_stringShared.push_back(node.first_child().text().get()); + + } + } +} + +/* +XLSharedStrings::~XLSharedStrings() = default; +*/ /** * @details Look up a string index by the string content. If the string does not exist, the returned index is -1. */ -int32_t XLSharedStrings::getStringIndex(const std::string& str) const +uint32_t XLSharedStrings::getStringIndex(const std::string& str) const { + auto it = std::find(m_stringShared.begin(), m_stringShared.end(), str); + if (it != m_stringShared.end()) + return (uint32_t)(it - m_stringShared.begin()); + + // Not found + return (uint32_t)(-1); + + /* auto iter = std::find_if(m_stringCache->begin(), m_stringCache->end(), [&](const std::string& s) { return str == s; }); - return iter == m_stringCache->end() ? -1 : static_cast(std::distance(m_stringCache->begin(), iter)); + return iter == m_stringCache->end() ? -1 : static_cast(std::distance(m_stringCache->begin(), iter)); + */ } /** @@ -81,7 +109,7 @@ int32_t XLSharedStrings::getStringIndex(const std::string& str) const */ bool XLSharedStrings::stringExists(const std::string& str) const { - return getStringIndex(str) >= 0; + return getStringIndex(str) != (uint32_t)(-1); } /** @@ -89,22 +117,37 @@ bool XLSharedStrings::stringExists(const std::string& str) const */ const char* XLSharedStrings::getString(uint32_t index) const { - return (*m_stringCache)[index].c_str(); + try{ + std::string value = m_stringShared.at(index); + return value.c_str(); + } catch (const std::out_of_range&) { + return std::string().c_str(); + } + + //return (*m_stringCache)[index].c_str(); } /** * @details Append a string by creating a new node in the XML file and adding the string to it. The index to the * shared string is returned */ -int32_t XLSharedStrings::appendString(const std::string& str) +uint32_t XLSharedStrings::appendString(const std::string& str) { auto textNode = xmlDocument().document_element().append_child("si").append_child("t"); if (str.front() == ' ' || str.back() == ' ') textNode.append_attribute("xml:space").set_value("preserve"); textNode.text().set(str.c_str()); - m_stringCache->emplace_back(textNode.text().get()); - return static_cast(std::distance(m_stringCache->begin(), m_stringCache->end()) - 1); + m_stringShared.push_back(str); + //m_stringCache->emplace_back(textNode.text().get()); + auto test = m_stringShared.size() - 1; + return m_stringShared.size() - 1; + /* + auto test = static_cast(std::distance(m_stringCache->begin(), m_stringCache->end()) - 1); + auto size = m_stringCache->size(); + + return static_cast(std::distance(m_stringCache->begin(), m_stringCache->end()) - 1); + */ } /** @@ -113,7 +156,14 @@ int32_t XLSharedStrings::appendString(const std::string& str) */ void XLSharedStrings::clearString(uint64_t index) { - (*m_stringCache)[index] = ""; + //(*m_stringCache)[index] = ""; + + try{ + m_stringShared.at(index) = std::string(); + } catch (const std::out_of_range&) { + return; + } + auto iter = xmlDocument().document_element().children().begin(); std::advance(iter, index); iter->text().set(""); diff --git a/OpenXLSX/sources/XLSheet.cpp b/OpenXLSX/sources/XLSheet.cpp index 4cce7b35..95e8c283 100644 --- a/OpenXLSX/sources/XLSheet.cpp +++ b/OpenXLSX/sources/XLSheet.cpp @@ -370,7 +370,7 @@ XLCell XLWorksheet::cell(uint32_t rowNumber, uint16_t columnNumber) const } } - return XLCell{cellNode, parentDoc().execQuery(XLQuery(XLQueryType::QuerySharedStrings)).result()}; + return XLCell{cellNode/*, parentDoc().execQuery(XLQuery(XLQueryType::QuerySharedStrings)).result()*/}; } /** @@ -388,8 +388,8 @@ XLCellRange XLWorksheet::range(const XLCellReference& topLeft, const XLCellRefer { return XLCellRange(xmlDocument().first_child().child("sheetData"), topLeft, - bottomRight, - parentDoc().execQuery(XLQuery(XLQueryType::QuerySharedStrings)).result()); + bottomRight + /*parentDoc().execQuery(XLQuery(XLQueryType::QuerySharedStrings)).result()*/); } XLCellRange XLWorksheet::range(const std::string& ref) const @@ -410,8 +410,8 @@ XLRowRange XLWorksheet::rows() const 1, (sheetDataNode.last_child() ? static_cast(sheetDataNode.last_child().attribute("r").as_ullong()) - : 1), - parentDoc().execQuery(XLQuery(XLQueryType::QuerySharedStrings)).result()); + : 1) + /*parentDoc().execQuery(XLQuery(XLQueryType::QuerySharedStrings)).result()*/); } /** @@ -423,8 +423,8 @@ XLRowRange XLWorksheet::rows(uint32_t rowCount) const { return XLRowRange(xmlDocument().first_child().child("sheetData"), 1, - rowCount, - parentDoc().execQuery(XLQuery(XLQueryType::QuerySharedStrings)).result()); + rowCount + /*parentDoc().execQuery(XLQuery(XLQueryType::QuerySharedStrings)).result()*/); } /** @@ -436,8 +436,8 @@ XLRowRange XLWorksheet::rows(uint32_t firstRow, uint32_t lastRow) const { return XLRowRange(xmlDocument().first_child().child("sheetData"), firstRow, - lastRow, - parentDoc().execQuery(XLQuery(XLQueryType::QuerySharedStrings)).result()); + lastRow + /*parentDoc().execQuery(XLQuery(XLQueryType::QuerySharedStrings)).result()*/); } /** @@ -447,8 +447,8 @@ XLRowRange XLWorksheet::rows(uint32_t firstRow, uint32_t lastRow) const */ XLRow XLWorksheet::row(uint32_t rowNumber) const { - return XLRow{getRowNode(xmlDocument().first_child().child("sheetData"), rowNumber), - parentDoc().execQuery(XLQuery(XLQueryType::QuerySharedStrings)).result()}; + return XLRow{getRowNode(xmlDocument().first_child().child("sheetData"), rowNumber) + /*parentDoc().execQuery(XLQuery(XLQueryType::QuerySharedStrings)).result()*/}; } /** @@ -574,9 +574,9 @@ void XLWorksheet::updateSheetName(const std::string& oldName, const std::string& // ===== Iterate through all defined names for (auto& row : xmlDocument().document_element().child("sheetData")) { for (auto& cell : row.children()) { - if (!XLCell(cell, XLSharedStrings()).hasFormula()) continue; + if (!XLCell(cell/*, XLSharedStrings()*/).hasFormula()) continue; - formula = XLCell(cell, XLSharedStrings()).formula().get(); + formula = XLCell(cell/*, XLSharedStrings()*/).formula().get(); // ===== Skip if formula contains a '[' and ']' (means that the defined refers to external workbook) if (formula.find('[') == std::string::npos && formula.find(']') == std::string::npos) { @@ -584,7 +584,7 @@ void XLWorksheet::updateSheetName(const std::string& oldName, const std::string& while (formula.find(oldNameTemp) != std::string::npos) { // NOLINT formula.replace(formula.find(oldNameTemp), oldNameTemp.length(), newNameTemp); } - XLCell(cell, XLSharedStrings()).formula() = formula; + XLCell(cell/*, XLSharedStrings()*/).formula() = formula; } } } diff --git a/OpenXLSX/sources/XLTable.cpp b/OpenXLSX/sources/XLTable.cpp index 85acac5f..bc5256c2 100644 --- a/OpenXLSX/sources/XLTable.cpp +++ b/OpenXLSX/sources/XLTable.cpp @@ -144,8 +144,8 @@ XLTableRows XLTable::tableRows() const lastRow -=1; return XLTableRows(m_pXmlData->getParentNode()->getXmlDocument()->first_child().child("sheetData"), - firstRow, lastRow, firstCol, lastCol, - m_pXmlData->getParentDoc()->execQuery(XLQuery(XLQueryType::QuerySharedStrings)).result()); + firstRow, lastRow, firstCol, lastCol + /*m_pXmlData->getParentDoc()->execQuery(XLQuery(XLQueryType::QuerySharedStrings)).result()*/); } XLCellRange XLTable::dataBodyRange() const diff --git a/OpenXLSX/sources/XLTableRows.cpp b/OpenXLSX/sources/XLTableRows.cpp index e068702a..7379c28b 100644 --- a/OpenXLSX/sources/XLTableRows.cpp +++ b/OpenXLSX/sources/XLTableRows.cpp @@ -61,14 +61,14 @@ using namespace OpenXLSX; XLTableRowIterator:: XLTableRowIterator(const XLTableRows& tableRows, XLIteratorLocation loc): m_range (XLCellRange( *tableRows.m_dataNode, XLCellReference (tableRows.m_firstRow, tableRows.m_firstCol), - XLCellReference (tableRows.m_firstRow, tableRows.m_lastCol), - tableRows.m_sharedStrings)) + XLCellReference (tableRows.m_firstRow, tableRows.m_lastCol) + /*tableRows.m_sharedStrings*/)) { if (loc == XLIteratorLocation::End) m_range = XLCellRange( *tableRows.m_dataNode, XLCellReference (tableRows.m_lastRow, tableRows.m_firstCol), - XLCellReference (tableRows.m_lastRow, tableRows.m_lastCol), - tableRows.m_sharedStrings); + XLCellReference (tableRows.m_lastRow, tableRows.m_lastCol) + /*tableRows.m_sharedStrings*/); } XLTableRowIterator::~ XLTableRowIterator() = default; @@ -169,9 +169,9 @@ XLTableRows::XLTableRows(const XMLNode& dataNode, uint32_t firstRow, uint32_t lastRow, uint16_t firstCol, - uint16_t lastCol, - const OpenXLSX::XLSharedStrings& sharedStrings): - XLRowRange(dataNode, firstRow, lastRow, sharedStrings), + uint16_t lastCol + /*const OpenXLSX::XLSharedStrings& sharedStrings*/): + XLRowRange(dataNode, firstRow, lastRow/*, sharedStrings*/), m_firstCol(firstCol), m_lastCol(lastCol) {} @@ -217,13 +217,13 @@ XLCellRange XLTableRows::operator[](uint32_t index) const if (row > m_lastRow) return XLCellRange(*m_dataNode, XLCellReference (m_firstRow, m_firstCol), - XLCellReference (m_lastRow, m_lastCol), - m_sharedStrings); + XLCellReference (m_lastRow, m_lastCol) + /*m_sharedStrings*/); return XLCellRange(*m_dataNode, XLCellReference (row, m_firstCol), - XLCellReference (row, m_lastCol), - m_sharedStrings); + XLCellReference (row, m_lastCol) + /*m_sharedStrings*/); } diff --git a/OpenXLSX/sources/XLWorkbook.cpp b/OpenXLSX/sources/XLWorkbook.cpp index 4e3fb7d9..b51e91ec 100644 --- a/OpenXLSX/sources/XLWorkbook.cpp +++ b/OpenXLSX/sources/XLWorkbook.cpp @@ -174,20 +174,23 @@ XLChartsheet XLWorkbook::chartsheet(const std::string& sheetName) /** * @details */ +/* bool XLWorkbook::hasSharedStrings() const { return true;//parentDoc().executeQuery(XLQuerySharedStrings()).sharedStrings() != nullptr; } - +*/ /** * @details */ -XLSharedStrings XLWorkbook::sharedStrings() +/* +XLSharedStrings& XLWorkbook::sharedStrings() { - XLQuery query(XLQueryType::QuerySharedStrings); - return parentDoc().execQuery(query).result(); + //XLQuery query(XLQueryType::QuerySharedStrings); + //return parentDoc().execQuery(query).result(); + return XLSharedStrings::instance(); } - +*/ /** * @details */ From 541858a9c9dd5939e003a261113a839fb3a3fe70 Mon Sep 17 00:00:00 2001 From: akira215 Date: Sat, 31 Dec 2022 00:03:41 +0100 Subject: [PATCH 12/45] Correcting singleton XLSharedString --- OpenXLSX/headers/XLCell.hpp | 9 +++--- OpenXLSX/headers/XLCellIterator.hpp | 4 ++- OpenXLSX/headers/XLCellRange.hpp | 8 ++++-- OpenXLSX/headers/XLCellValue.hpp | 3 ++ OpenXLSX/headers/XLDocument.hpp | 6 ++-- OpenXLSX/headers/XLRow.hpp | 11 +++---- OpenXLSX/headers/XLRowData.hpp | 5 ++-- OpenXLSX/headers/XLSharedStrings.hpp | 43 ++++++---------------------- OpenXLSX/headers/XLSheet.hpp | 7 ++++- OpenXLSX/headers/XLTable.hpp | 11 ++++--- OpenXLSX/headers/XLTableRows.hpp | 4 +-- OpenXLSX/headers/XLWorkbook.hpp | 1 + OpenXLSX/sources/XLCell.cpp | 14 +++++---- OpenXLSX/sources/XLCellIterator.cpp | 17 +++++------ OpenXLSX/sources/XLCellRange.cpp | 19 ++++++------ OpenXLSX/sources/XLCellValue.cpp | 23 +++++++++------ OpenXLSX/sources/XLDocument.cpp | 24 +++++++++------- OpenXLSX/sources/XLRow.cpp | 41 ++++++++++++++------------ OpenXLSX/sources/XLRowData.cpp | 21 +++++++------- OpenXLSX/sources/XLSharedStrings.cpp | 25 +++------------- OpenXLSX/sources/XLSheet.cpp | 27 +++++++++-------- OpenXLSX/sources/XLTable.cpp | 26 +++++++---------- OpenXLSX/sources/XLTableRows.cpp | 22 +++++++------- OpenXLSX/sources/XLWorkbook.cpp | 1 + 24 files changed, 179 insertions(+), 193 deletions(-) diff --git a/OpenXLSX/headers/XLCell.hpp b/OpenXLSX/headers/XLCell.hpp index f39019f8..b1d2acb1 100644 --- a/OpenXLSX/headers/XLCell.hpp +++ b/OpenXLSX/headers/XLCell.hpp @@ -57,13 +57,14 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. #include "XLCellReference.hpp" #include "XLCellValue.hpp" #include "XLFormula.hpp" -#include "XLSharedStrings.hpp" + + // ========== CLASS AND ENUM TYPE DEFINITIONS ========== // namespace OpenXLSX { class XLCellRange; - class XLSharedStrings; + class XLWorksheet; /** * @brief An implementation class encapsulating the properties and behaviours of a spreadsheet cell. @@ -89,7 +90,7 @@ namespace OpenXLSX * @param cellNode * @param sharedStrings */ - XLCell(const XMLNode& cellNode/*, const XLSharedStrings& sharedStrings*/); + XLCell(const XMLNode& cellNode, const XLWorksheet* wks); /** * @brief Copy constructor @@ -193,7 +194,7 @@ namespace OpenXLSX //---------- Private Member Variables ---------- // std::unique_ptr m_cellNode; /**< A pointer to the root XMLNode for the cell. */ - //XLSharedStrings m_sharedStrings; /**< */ + const XLWorksheet* m_worksheet; XLCellValueProxy m_valueProxy; /**< */ XLFormulaProxy m_formulaProxy; /**< */ }; diff --git a/OpenXLSX/headers/XLCellIterator.hpp b/OpenXLSX/headers/XLCellIterator.hpp index 43f480e4..779a4393 100644 --- a/OpenXLSX/headers/XLCellIterator.hpp +++ b/OpenXLSX/headers/XLCellIterator.hpp @@ -60,6 +60,8 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. namespace OpenXLSX { + class XLWorksheet; + class OPENXLSX_EXPORT XLCellIterator { public: @@ -157,7 +159,7 @@ namespace OpenXLSX XLCellReference m_topLeft; /**< The cell reference of the first cell in the range */ XLCellReference m_bottomRight; /**< The cell reference of the last cell in the range */ XLCell m_currentCell; /**< */ - //XLSharedStrings m_sharedStrings; /**< */ + const XLWorksheet* m_worksheet; /**< */ bool m_endReached { false }; /**< */ }; diff --git a/OpenXLSX/headers/XLCellRange.hpp b/OpenXLSX/headers/XLCellRange.hpp index 215541e3..868d65b4 100644 --- a/OpenXLSX/headers/XLCellRange.hpp +++ b/OpenXLSX/headers/XLCellRange.hpp @@ -63,6 +63,8 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. namespace OpenXLSX { + class XLWorksheet; + /** * @brief This class encapsulates the concept of a cell range, i.e. a square area * (or subset) of cells in a spreadsheet. @@ -85,8 +87,8 @@ namespace OpenXLSX */ explicit XLCellRange(const XMLNode& dataNode, const XLCellReference& topLeft, - const XLCellReference& bottomRight - /*const XLSharedStrings& sharedStrings*/); + const XLCellReference& bottomRight, + const XLWorksheet* wks); /** * @brief Copy constructor [default]. @@ -191,7 +193,7 @@ namespace OpenXLSX std::unique_ptr m_dataNode; /**< */ XLCellReference m_topLeft; /**< The cell reference of the first cell in the range */ XLCellReference m_bottomRight; /**< The cell reference of the last cell in the range */ - //XLSharedStrings m_sharedStrings; + const XLWorksheet* m_worksheet; }; } // namespace OpenXLSX diff --git a/OpenXLSX/headers/XLCellValue.hpp b/OpenXLSX/headers/XLCellValue.hpp index ba57f5b5..af321530 100644 --- a/OpenXLSX/headers/XLCellValue.hpp +++ b/OpenXLSX/headers/XLCellValue.hpp @@ -67,6 +67,7 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. namespace OpenXLSX { //---------- Forward Declarations ----------// + class XLSharedStrings; class XLCellValueProxy; class XLCell; @@ -533,6 +534,8 @@ namespace OpenXLSX */ XLCellValue getValue() const; + XLSharedStrings* getSharedString() const; + //---------- Private Member Variables ---------- // XLCell* m_cell; /**< Pointer to the owning XLCell object. */ diff --git a/OpenXLSX/headers/XLDocument.hpp b/OpenXLSX/headers/XLDocument.hpp index 4e43ef77..1d81fa0a 100644 --- a/OpenXLSX/headers/XLDocument.hpp +++ b/OpenXLSX/headers/XLDocument.hpp @@ -55,7 +55,6 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. #include #include #include -#include #include // ===== OpenXLSX Includes ===== // @@ -300,6 +299,7 @@ namespace OpenXLSX */ XLXmlData* getXmlDataByName(const std::string& name) const; + XLSharedStrings& getSharedString() const; /** * @brief @@ -333,8 +333,8 @@ namespace OpenXLSX std::string m_realPath {}; /**< */ mutable std::list m_data {}; /**< */ - mutable std::deque m_sharedStringCache {}; /**< */ - //mutable XLSharedStrings* m_sharedStrings; /**< */ + //mutable std::deque m_sharedStringCache {}; /**< */ + mutable XLSharedStrings m_sharedStrings; /**< */ XLRelationships m_docRelationships {}; /**< A pointer to the document relationships object*/ XLRelationships m_wbkRelationships {}; /**< A pointer to the document relationships object*/ diff --git a/OpenXLSX/headers/XLRow.hpp b/OpenXLSX/headers/XLRow.hpp index e2f28105..aa11748b 100644 --- a/OpenXLSX/headers/XLRow.hpp +++ b/OpenXLSX/headers/XLRow.hpp @@ -58,6 +58,7 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. namespace OpenXLSX { class XLRowRange; + class XLWorksheet; /** * @brief The XLRow class represent a row in an Excel spreadsheet. Using XLRow objects, various row formatting @@ -86,7 +87,7 @@ namespace OpenXLSX * @param rowNode * @param sharedStrings */ - XLRow(const XMLNode& rowNode/*, const XLSharedStrings& sharedStrings*/); + XLRow(const XMLNode& rowNode, const XLWorksheet* wks); /** * @brief Copy Constructor @@ -232,7 +233,7 @@ namespace OpenXLSX //---------- PRIVATE MEMBER VARIABLES ----------// std::unique_ptr m_rowNode; /**< The XMLNode object for the row. */ - //XLSharedStrings m_sharedStrings; /**< */ + const XLWorksheet* m_worksheet; /**< */ XLRowDataProxy m_rowDataProxy; /**< */ }; @@ -335,7 +336,7 @@ namespace OpenXLSX uint32_t m_firstRow { 1 }; /**< The cell reference of the first cell in the range */ uint32_t m_lastRow { 1 }; /**< The cell reference of the last cell in the range */ XLRow m_currentRow; /**< */ - //XLSharedStrings m_sharedStrings; /**< */ + const XLWorksheet* m_worksheet; /**< */ }; /** @@ -358,7 +359,7 @@ namespace OpenXLSX * @param last * @param sharedStrings */ - explicit XLRowRange(const XMLNode& dataNode, uint32_t first, uint32_t last/*, const XLSharedStrings& sharedStrings*/); + explicit XLRowRange(const XMLNode& dataNode, uint32_t first, uint32_t last, const XLWorksheet* wks); /** * @brief @@ -417,7 +418,7 @@ namespace OpenXLSX std::unique_ptr m_dataNode; /**< */ uint32_t m_firstRow; /**< The cell reference of the first cell in the range */ uint32_t m_lastRow; /**< The cell reference of the last cell in the range */ - //XLSharedStrings m_sharedStrings; /**< */ + const XLWorksheet* m_worksheet; /**< */ }; } // namespace OpenXLSX diff --git a/OpenXLSX/headers/XLRowData.hpp b/OpenXLSX/headers/XLRowData.hpp index e41e9c1b..07044973 100644 --- a/OpenXLSX/headers/XLRowData.hpp +++ b/OpenXLSX/headers/XLRowData.hpp @@ -194,12 +194,13 @@ namespace OpenXLSX * @param lastColumn The index of the last column. * @param sharedStrings A pointer to the shared strings repository. */ - explicit XLRowDataRange(const XMLNode& rowNode, uint16_t firstColumn, uint16_t lastColumn/*, const XLSharedStrings& sharedStrings*/); + explicit XLRowDataRange(const XMLNode& rowNode, uint16_t firstColumn, + uint16_t lastColumn, const XLWorksheet* wks); std::unique_ptr m_rowNode; /**< */ uint16_t m_firstCol { 1 }; /**< The cell reference of the first cell in the range */ uint16_t m_lastCol { 1 }; /**< The cell reference of the last cell in the range */ - //XLSharedStrings m_sharedStrings; /**< */ + const XLWorksheet* m_worksheet; /**< */ }; /** diff --git a/OpenXLSX/headers/XLSharedStrings.hpp b/OpenXLSX/headers/XLSharedStrings.hpp index 5a5813a5..c68cefae 100644 --- a/OpenXLSX/headers/XLSharedStrings.hpp +++ b/OpenXLSX/headers/XLSharedStrings.hpp @@ -50,10 +50,10 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. #pragma warning(disable : 4251) #pragma warning(disable : 4275) -#include +//#include #include #include -#include +//#include //#include @@ -82,69 +82,44 @@ namespace OpenXLSX /** * @brief */ - //XLSharedStrings() = default; + XLSharedStrings() = default; /** * @brief * @param xmlData */ - //explicit XLSharedStrings(XLXmlData* xmlData, std::deque *stringCache); - //explicit XLSharedStrings(XLXmlData* xmlData); - - ///////////////////// @brief ////////////////////////////////////////////////////// - private: - XLSharedStrings(XLXmlData* xmlData); - - XLSharedStrings(const XLSharedStrings&) = delete; - void operator=(const XLSharedStrings&) = delete; - public: - static XLSharedStrings& instance(std::function *init = nullptr) { - static XLSharedStrings s{(*init)()}; - return s; - } - - static void initialize(XLXmlData* d) { - std::function init = [d]() { return XLSharedStrings(d); }; - instance(&init); - } - - - - - /////////// @brief ////////////////////////////////////////////////////// - - + explicit XLSharedStrings(XLXmlData* xmlData); /** * @brief Destructor */ - //~XLSharedStrings(); + ~XLSharedStrings(); /** * @brief * @param other */ - //XLSharedStrings(const XLSharedStrings& other) = default; + XLSharedStrings(const XLSharedStrings& other) = default; /** * @brief * @param other */ - //XLSharedStrings(XLSharedStrings&& other) noexcept = default; + XLSharedStrings(XLSharedStrings&& other) noexcept = default; /** * @brief * @param other * @return */ - //XLSharedStrings& operator=(const XLSharedStrings& other) = default; + XLSharedStrings& operator=(const XLSharedStrings& other) = default; /** * @brief * @param other * @return */ - //XLSharedStrings& operator=(XLSharedStrings&& other) noexcept = default; + XLSharedStrings& operator=(XLSharedStrings&& other) noexcept = default; /** * @brief diff --git a/OpenXLSX/headers/XLSheet.hpp b/OpenXLSX/headers/XLSheet.hpp index eb327bd8..61e2079c 100644 --- a/OpenXLSX/headers/XLSheet.hpp +++ b/OpenXLSX/headers/XLSheet.hpp @@ -294,6 +294,7 @@ namespace OpenXLSX .setParam("sheetID", relationshipID()) .setParam("cloneName", newName)); } + }; /** @@ -304,6 +305,7 @@ namespace OpenXLSX friend class XLCell; friend class XLRow; friend class XLWorkbook; + friend class XLCellValueProxy; friend class XLSheetBase; //---------------------------------------------------------------------------------------------------------------------- @@ -350,6 +352,8 @@ namespace OpenXLSX * @note The move assignment operator has been explicitly deleted. */ XLWorksheet& operator=(XLWorksheet&& other) = default; + + //XLSharedStrings& getSharedString() const; /** * @brief @@ -452,7 +456,7 @@ namespace OpenXLSX * @param newName */ void updateSheetName(const std::string& oldName, const std::string& newName); - + private: /** @@ -490,6 +494,7 @@ namespace OpenXLSX * @param selected */ void setActive_impl(); + }; /** diff --git a/OpenXLSX/headers/XLTable.hpp b/OpenXLSX/headers/XLTable.hpp index a8230f2e..1ffd0511 100644 --- a/OpenXLSX/headers/XLTable.hpp +++ b/OpenXLSX/headers/XLTable.hpp @@ -75,10 +75,10 @@ namespace OpenXLSX const std::string ref() const; std::vector columnNames() const; uint16_t columnIndex(const std::string& name) const; - XLWorksheet getWorksheet() const; - XLCellRange tableRange() const; - XLTableRows tableRows() const; - XLCellRange dataBodyRange() const; + XLWorksheet* getWorksheet(); + XLCellRange tableRange(); + XLTableRows tableRows(); + XLCellRange dataBodyRange(); @@ -89,11 +89,10 @@ namespace OpenXLSX void setName(const std::string& tableName); - - private: XLXmlData* m_pXmlData; std::vector> m_columns; + XLWorksheet m_sheet; // cell range // sheet // filter diff --git a/OpenXLSX/headers/XLTableRows.hpp b/OpenXLSX/headers/XLTableRows.hpp index ddd7b082..8ec57d72 100644 --- a/OpenXLSX/headers/XLTableRows.hpp +++ b/OpenXLSX/headers/XLTableRows.hpp @@ -181,8 +181,8 @@ namespace OpenXLSX uint32_t firstRow, uint32_t lastRow, uint16_t firstCol, - uint16_t lastCol - /*const OpenXLSX::XLSharedStrings& sharedStrings*/); + uint16_t lastCol, + const XLWorksheet* wks); /** * @brief Copy Constructor * @param other diff --git a/OpenXLSX/headers/XLWorkbook.hpp b/OpenXLSX/headers/XLWorkbook.hpp index 8efb2c88..9ad4e28d 100644 --- a/OpenXLSX/headers/XLWorkbook.hpp +++ b/OpenXLSX/headers/XLWorkbook.hpp @@ -400,6 +400,7 @@ namespace OpenXLSX * @param state */ void setSheetActive(const std::string& sheetRID); + }; } // namespace OpenXLSX diff --git a/OpenXLSX/sources/XLCell.cpp b/OpenXLSX/sources/XLCell.cpp index 76a2f079..d7509a0f 100644 --- a/OpenXLSX/sources/XLCell.cpp +++ b/OpenXLSX/sources/XLCell.cpp @@ -48,6 +48,7 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. // ===== OpenXLSX Includes ===== // #include "XLCell.hpp" +#include "XLSheet.hpp" #include "XLCellRange.hpp" #include "utilities/XLUtilities.hpp" @@ -58,6 +59,7 @@ using namespace OpenXLSX; */ XLCell::XLCell() : m_cellNode(nullptr), + m_worksheet(nullptr), m_valueProxy(XLCellValueProxy(this, m_cellNode.get())), m_formulaProxy(XLFormulaProxy(this, m_cellNode.get())) {} @@ -68,9 +70,9 @@ XLCell::XLCell() * If a cell XMLNode does not exist (i.e., the cell is empty), use the relevant constructor to create an XLCell * from a XLCellReference parameter. */ -XLCell::XLCell(const XMLNode& cellNode/*, const XLSharedStrings& sharedStrings*/) +XLCell::XLCell(const XMLNode& cellNode, const XLWorksheet* wks) : m_cellNode(std::make_unique(cellNode)), - //m_sharedStrings(sharedStrings), + m_worksheet(wks), m_valueProxy(XLCellValueProxy(this, m_cellNode.get())), m_formulaProxy(XLFormulaProxy(this, m_cellNode.get())) {} @@ -80,7 +82,7 @@ XLCell::XLCell(const XMLNode& cellNode/*, const XLSharedStrings& sharedStrings*/ */ XLCell::XLCell(const XLCell& other) : m_cellNode(other.m_cellNode ? std::make_unique(*other.m_cellNode) : nullptr), - //m_sharedStrings(other.m_sharedStrings), + m_worksheet(other.m_worksheet), m_valueProxy(XLCellValueProxy(this, m_cellNode.get())), m_formulaProxy(XLFormulaProxy(this, m_cellNode.get())) {} @@ -90,7 +92,7 @@ XLCell::XLCell(const XLCell& other) */ XLCell::XLCell(XLCell&& other) noexcept : m_cellNode(std::move(other.m_cellNode)), - //m_sharedStrings(std::move(other.m_sharedStrings)), + m_worksheet(other.m_worksheet), m_valueProxy(XLCellValueProxy(this, m_cellNode.get())), m_formulaProxy(XLFormulaProxy(this, m_cellNode.get())) {} @@ -120,7 +122,7 @@ XLCell& XLCell::operator=(XLCell&& other) noexcept { if (&other != this) { m_cellNode = std::move(other.m_cellNode); - //m_sharedStrings = other.m_sharedStrings; + m_worksheet = other.m_worksheet; m_valueProxy = XLCellValueProxy(this, m_cellNode.get()); } @@ -153,7 +155,7 @@ XLCell XLCell::offset(uint16_t rowOffset, uint16_t colOffset) const XLCellReference offsetRef(cellReference().row() + rowOffset, cellReference().column() + colOffset); auto rownode = getRowNode(m_cellNode->parent().parent(), offsetRef.row()); auto cellnode = getCellNode(rownode, offsetRef.column()); - return XLCell{cellnode/*, m_sharedStrings*/}; + return XLCell{cellnode, m_worksheet}; } /** diff --git a/OpenXLSX/sources/XLCellIterator.cpp b/OpenXLSX/sources/XLCellIterator.cpp index e11913a4..1aa7c725 100644 --- a/OpenXLSX/sources/XLCellIterator.cpp +++ b/OpenXLSX/sources/XLCellIterator.cpp @@ -66,13 +66,14 @@ namespace OpenXLSX XLCellIterator::XLCellIterator(const XLCellRange& cellRange, XLIteratorLocation loc) : m_dataNode(std::make_unique(*cellRange.m_dataNode)), m_topLeft(cellRange.m_topLeft), - m_bottomRight(cellRange.m_bottomRight) - //m_sharedStrings(cellRange.m_sharedStrings) + m_bottomRight(cellRange.m_bottomRight), + m_worksheet(cellRange.m_worksheet) { if (loc == XLIteratorLocation::End) m_currentCell = XLCell(); else { - m_currentCell = XLCell(getCellNode(getRowNode(*m_dataNode, m_topLeft.row()), m_topLeft.column())); + m_currentCell = XLCell(getCellNode(getRowNode(*m_dataNode, m_topLeft.row()), + m_topLeft.column()), m_worksheet); } } @@ -88,8 +89,8 @@ XLCellIterator::XLCellIterator(const XLCellIterator& other) : m_dataNode(std::make_unique(*other.m_dataNode)), m_topLeft(other.m_topLeft), m_bottomRight(other.m_bottomRight), - m_currentCell(other.m_currentCell) - //m_sharedStrings(other.m_sharedStrings) + m_currentCell(other.m_currentCell), + m_worksheet(other.m_worksheet) {} /** @@ -107,7 +108,7 @@ XLCellIterator& XLCellIterator::operator=(const XLCellIterator& other) m_topLeft = other.m_topLeft; m_bottomRight = other.m_bottomRight; m_currentCell = other.m_currentCell; - //m_sharedStrings = other.m_sharedStrings; + m_worksheet = other.m_worksheet; } return *this; @@ -141,7 +142,7 @@ XLCellIterator& XLCellIterator::operator++() node = m_currentCell.m_cellNode->parent().insert_child_after("c", *m_currentCell.m_cellNode); node.append_attribute("r").set_value(ref.address().c_str()); } - m_currentCell = XLCell(node); + m_currentCell = XLCell(node, m_worksheet); } else if (ref.row() > m_currentCell.cellReference().row()) { auto rowNode = m_currentCell.m_cellNode->parent().next_sibling(); @@ -151,7 +152,7 @@ XLCellIterator& XLCellIterator::operator++() // getRowNode(*m_dataNode, ref.row()); } - m_currentCell = XLCell(getCellNode(rowNode, ref.column())); + m_currentCell = XLCell(getCellNode(rowNode, ref.column()), m_worksheet); } else throw XLInternalError("An internal error occured"); diff --git a/OpenXLSX/sources/XLCellRange.cpp b/OpenXLSX/sources/XLCellRange.cpp index dfd70931..4552be28 100644 --- a/OpenXLSX/sources/XLCellRange.cpp +++ b/OpenXLSX/sources/XLCellRange.cpp @@ -49,6 +49,7 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. // ===== OpenXLSX Includes ===== // #include "XLCellRange.hpp" +#include "XLSheet.hpp" using namespace OpenXLSX; @@ -66,12 +67,12 @@ namespace OpenXLSX */ XLCellRange::XLCellRange(const XMLNode& dataNode, const XLCellReference& topLeft, - const XLCellReference& bottomRight - /*const XLSharedStrings& sharedStrings*/) + const XLCellReference& bottomRight, + const XLWorksheet* wks) : m_dataNode(std::make_unique(dataNode)), m_topLeft(topLeft), - m_bottomRight(bottomRight) - //m_sharedStrings(sharedStrings) + m_bottomRight(bottomRight), + m_worksheet(wks) {} /** @@ -82,8 +83,8 @@ XLCellRange::XLCellRange(const XMLNode& dataNode, XLCellRange::XLCellRange(const XLCellRange& other) : m_dataNode(std::make_unique(*other.m_dataNode)), m_topLeft(other.m_topLeft), - m_bottomRight(other.m_bottomRight) - //m_sharedStrings(other.m_sharedStrings) + m_bottomRight(other.m_bottomRight), + m_worksheet(other.m_worksheet) {} /** @@ -111,7 +112,7 @@ XLCellRange& XLCellRange::operator=(const XLCellRange& other) *m_dataNode = *other.m_dataNode; m_topLeft = other.m_topLeft; m_bottomRight = other.m_bottomRight; - //m_sharedStrings = other.m_sharedStrings; + m_worksheet = other.m_worksheet; } return *this; @@ -128,7 +129,7 @@ XLCellRange& XLCellRange::operator=(XLCellRange&& other) noexcept *m_dataNode = *other.m_dataNode; m_topLeft = other.m_topLeft; m_bottomRight = other.m_bottomRight; - //m_sharedStrings = other.m_sharedStrings; + m_worksheet = other.m_worksheet; } return *this; @@ -163,7 +164,7 @@ XLCell XLCellRange::operator[](uint32_t index) const if(row > m_bottomRight.row()) return XLCell(); - return XLCell(getCellNode(getRowNode(*m_dataNode, row), col)); + return XLCell(getCellNode(getRowNode(*m_dataNode, row), col), m_worksheet); } /** diff --git a/OpenXLSX/sources/XLCellValue.cpp b/OpenXLSX/sources/XLCellValue.cpp index edec2392..26f03979 100644 --- a/OpenXLSX/sources/XLCellValue.cpp +++ b/OpenXLSX/sources/XLCellValue.cpp @@ -8,6 +8,8 @@ // ===== OpenXLSX Includes ===== // #include "XLCell.hpp" #include "XLCellValue.hpp" +#include "XLSharedStrings.hpp" +#include "XLSheet.hpp" #include "XLException.hpp" using namespace OpenXLSX; @@ -402,15 +404,14 @@ void XLCellValueProxy::setString(const char* stringValue) m_cellNode->attribute("t").set_value("s"); // ===== Get or create the index in the XLSharedStrings object. + uint32_t index; - if (XLSharedStrings::instance().stringExists(stringValue)) - index = XLSharedStrings::instance().getStringIndex(stringValue); + //if (m_cell->m_worksheet->getSharedString().stringExists(stringValue)) + if (getSharedString()->stringExists(stringValue)) + index = getSharedString()->getStringIndex(stringValue); else - index = XLSharedStrings::instance().appendString(stringValue); -/* - auto index = (m_cell->m_sharedStrings.stringExists(stringValue) ? m_cell->m_sharedStrings.getStringIndex(stringValue) - : m_cell->m_sharedStrings.appendString(stringValue)); -*/ + index = getSharedString()->appendString(stringValue); + // ===== Set the text of the value node. m_cellNode->child("v").text().set(index); @@ -424,7 +425,11 @@ void XLCellValueProxy::setString(const char* stringValue) // m_cellNode->attribute("xml:space").set_value("preserve"); // } } - +XLSharedStrings* XLCellValueProxy::getSharedString() const +{ + XLQuery query(XLQueryType::QuerySharedStrings); + return m_cell->m_worksheet->parentDoc().execQuery(query).template result(); +} /** * @details Get a copy of the XLCellValue object for the cell. This is private helper function for returning an * XLCellValue object corresponding to the cell value. @@ -449,7 +454,7 @@ XLCellValue XLCellValueProxy::getValue() const case XLValueType::String: if (strcmp(m_cellNode->attribute("t").value(), "s") == 0) - return XLCellValue { XLSharedStrings::instance().getString(static_cast(m_cellNode->child("v").text().as_ullong())) }; + return XLCellValue {getSharedString()->getString(static_cast(m_cellNode->child("v").text().as_ullong())) }; else if (strcmp(m_cellNode->attribute("t").value(), "str") == 0) return XLCellValue { m_cellNode->child("v").text().get() }; else if (strcmp(m_cellNode->attribute("t").value(), "inlineStr") == 0) diff --git a/OpenXLSX/sources/XLDocument.cpp b/OpenXLSX/sources/XLDocument.cpp index bd61485c..28d864f9 100644 --- a/OpenXLSX/sources/XLDocument.cpp +++ b/OpenXLSX/sources/XLDocument.cpp @@ -181,9 +181,7 @@ void XLDocument::open(const std::string& fileName) // TODO: If property data doesn't exist, consider creating them, instead of ignoring it. m_coreProperties = (hasXmlData("docProps/core.xml") ? XLProperties(getXmlDataByPath("docProps/core.xml")) : XLProperties()); m_appProperties = (hasXmlData("docProps/app.xml") ? XLAppProperties(getXmlDataByPath("docProps/app.xml")) : XLAppProperties()); - XLSharedStrings::initialize(getXmlDataByPath("xl/sharedStrings.xml")); - //m_sharedStrings = XLSharedStrings(getXmlDataByPath("xl/sharedStrings.xml")); - //m_sharedStrings = XLSharedStrings(getXmlDataByPath("xl/sharedStrings.xml"), &m_sharedStringCache); + m_sharedStrings = XLSharedStrings(getXmlDataByPath("xl/sharedStrings.xml")); } @@ -637,8 +635,8 @@ XLQuery XLDocument::execQuery(const XLQuery& query) const return XLQuery(query).setResult(m_wbkRelationships.relationshipById(query.getParam("sheetID")).target()); case XLQueryType::QuerySharedStrings: - //return XLQuery(query).setResult(m_sharedStrings); - return XLQuery(query).setResult(1); + return XLQuery(query).setResult(&m_sharedStrings); + //return XLQuery(query).setResult(1); case XLQueryType::QuerySheetFromName: return XLQuery(query).setResult(getXmlDataByName(query.getParam("sheetName"))); @@ -739,6 +737,11 @@ XLXmlData* XLDocument::getXmlDataByName(const std::string& name) const return nullptr; } +XLSharedStrings& XLDocument::getSharedString() const +{ + return m_sharedStrings; +} + std::string XLDocument::getSheetRelsPath(const std::string& sheetName) const { XLXmlData* wsItem = getXmlDataByName(sheetName); @@ -792,8 +795,8 @@ uint16_t XLDocument::availableFileID(XLContentType type) void XLDocument::createTable(const std::string& sheetName, const std::string& tableName, const std::string& reference) { XLXmlData* wks = getXmlDataByName(sheetName); - - std::vector idIndices;; + + std::vector idIndices; std::string basePath = "xl/tables/"; std::string name = tableName; @@ -889,11 +892,12 @@ void XLDocument::createTable(const std::string& sheetName, const std::string& ta tableNode.attribute("ref").set_value(ref.c_str()); // Set up the columns !!! + const XLWorksheet* pWks = new XLWorksheet(wks); auto topRight = XLCellReference(topLeft.row(),bottomRight.column()); auto headerRange = XLCellRange(wks->getXmlDocument()->first_child().child("sheetData"), topLeft, - topRight - /*m_sharedStrings*/); + topRight, + pWks); // Setup all the columns name XMLNode columnsNode = tableNode.child("tableColumns"); @@ -924,6 +928,6 @@ void XLDocument::createTable(const std::string& sheetName, const std::string& ta columnsNode.attribute("count").set_value(std::to_string(colId-1).c_str()); // TODEL - int i=0; + delete pWks; } diff --git a/OpenXLSX/sources/XLRow.cpp b/OpenXLSX/sources/XLRow.cpp index 41a3c16d..dc5db4f8 100644 --- a/OpenXLSX/sources/XLRow.cpp +++ b/OpenXLSX/sources/XLRow.cpp @@ -62,6 +62,7 @@ namespace OpenXLSX * @post */ XLRow::XLRow() : m_rowNode(nullptr), + m_worksheet(nullptr), m_rowDataProxy(this, m_rowNode.get()) {} /** @@ -70,9 +71,9 @@ namespace OpenXLSX * @pre * @post */ - XLRow::XLRow(const XMLNode& rowNode/*, const XLSharedStrings& sharedStrings*/) + XLRow::XLRow(const XMLNode& rowNode, const XLWorksheet* wks) : m_rowNode(std::make_unique(rowNode)), - //m_sharedStrings(sharedStrings), + m_worksheet(wks), m_rowDataProxy(this, m_rowNode.get()) {} @@ -83,7 +84,7 @@ namespace OpenXLSX */ XLRow::XLRow(const XLRow& other) : m_rowNode(other.m_rowNode ? std::make_unique(*other.m_rowNode) : nullptr), - //m_sharedStrings(other.m_sharedStrings), + m_worksheet(other.m_worksheet), m_rowDataProxy(this, m_rowNode.get()) {} @@ -95,7 +96,7 @@ namespace OpenXLSX */ XLRow::XLRow(XLRow&& other) noexcept : m_rowNode(std::move(other.m_rowNode)), - //m_sharedStrings(std::move(other.m_sharedStrings)), + m_worksheet(other.m_worksheet), m_rowDataProxy(this, m_rowNode.get()) {} @@ -264,7 +265,8 @@ namespace OpenXLSX */ XLRowDataRange XLRow::cells() const { - return XLRowDataRange(*m_rowNode, 1, XLCellReference(m_rowNode->last_child().attribute("r").value()).column()/*, m_sharedStrings*/); + return XLRowDataRange(*m_rowNode, 1, + XLCellReference(m_rowNode->last_child().attribute("r").value()).column(), m_worksheet); } /** @@ -274,7 +276,7 @@ namespace OpenXLSX */ XLRowDataRange XLRow::cells(uint16_t cellCount) const { - return XLRowDataRange(*m_rowNode, 1, cellCount/*, m_sharedStrings*/); + return XLRowDataRange(*m_rowNode, 1, cellCount, m_worksheet); } /** @@ -284,7 +286,7 @@ namespace OpenXLSX */ XLRowDataRange XLRow::cells(uint16_t firstCell, uint16_t lastCell) const { - return XLRowDataRange(*m_rowNode, firstCell, lastCell/*, m_sharedStrings*/); + return XLRowDataRange(*m_rowNode, firstCell, lastCell, m_worksheet); } bool XLRow::isEqual(const XLRow& lhs, const XLRow& rhs) @@ -314,13 +316,13 @@ namespace OpenXLSX XLRowIterator::XLRowIterator(const XLRowRange& rowRange, XLIteratorLocation loc) : m_dataNode(std::make_unique(*rowRange.m_dataNode)), m_firstRow(rowRange.m_firstRow), - m_lastRow(rowRange.m_lastRow) - //m_sharedStrings(rowRange.m_sharedStrings) + m_lastRow(rowRange.m_lastRow), + m_worksheet(rowRange.m_worksheet) { if (loc == XLIteratorLocation::End) m_currentRow = XLRow(); else { - m_currentRow = XLRow(getRowNode(*m_dataNode, m_firstRow)/*, m_sharedStrings*/); + m_currentRow = XLRow(getRowNode(*m_dataNode, m_firstRow), m_worksheet); } } @@ -340,8 +342,8 @@ namespace OpenXLSX : m_dataNode(std::make_unique(*other.m_dataNode)), m_firstRow(other.m_firstRow), m_lastRow(other.m_lastRow), - m_currentRow(other.m_currentRow) - //m_sharedStrings(other.m_sharedStrings) + m_currentRow(other.m_currentRow), + m_worksheet(other.m_worksheet) {} /** @@ -389,11 +391,11 @@ namespace OpenXLSX else if (!rowNode || rowNode.attribute("r").as_ullong() != rowNumber) { rowNode = m_dataNode->insert_child_after("row", *m_currentRow.m_rowNode); rowNode.append_attribute("r").set_value(rowNumber); - m_currentRow = XLRow(rowNode/*, m_sharedStrings*/); + m_currentRow = XLRow(rowNode, m_worksheet); } else - m_currentRow = XLRow(rowNode/*, m_sharedStrings*/); + m_currentRow = XLRow(rowNode, m_worksheet); return *this; } @@ -470,11 +472,12 @@ namespace OpenXLSX * @pre * @post */ - XLRowRange::XLRowRange(const XMLNode& dataNode, uint32_t first, uint32_t last/*, const OpenXLSX::XLSharedStrings& sharedStrings*/) + XLRowRange::XLRowRange(const XMLNode& dataNode, uint32_t first, + uint32_t last, const XLWorksheet* wks) : m_dataNode(std::make_unique(dataNode)), m_firstRow(first), - m_lastRow(last) - //m_sharedStrings(sharedStrings) + m_lastRow(last), + m_worksheet(wks) {} /** @@ -485,8 +488,8 @@ namespace OpenXLSX XLRowRange::XLRowRange(const XLRowRange& other) : m_dataNode(std::make_unique(*other.m_dataNode)), m_firstRow(other.m_firstRow), - m_lastRow(other.m_lastRow) - //m_sharedStrings(other.m_sharedStrings) + m_lastRow(other.m_lastRow), + m_worksheet(other.m_worksheet) {} /** diff --git a/OpenXLSX/sources/XLRowData.cpp b/OpenXLSX/sources/XLRowData.cpp index 4445d91b..ae260f95 100644 --- a/OpenXLSX/sources/XLRowData.cpp +++ b/OpenXLSX/sources/XLRowData.cpp @@ -64,7 +64,7 @@ namespace OpenXLSX XLRowDataIterator::XLRowDataIterator(const XLRowDataRange& rowDataRange, XLIteratorLocation loc) : m_dataRange(std::make_unique(rowDataRange)), m_cellNode(std::make_unique(getCellNode(*m_dataRange->m_rowNode, m_dataRange->m_firstCol))), - m_currentCell(loc == XLIteratorLocation::End ? XLCell() : XLCell(*m_cellNode/*, m_dataRange->m_sharedStrings*/)) + m_currentCell(loc == XLIteratorLocation::End ? XLCell() : XLCell(*m_cellNode, m_dataRange->m_worksheet)) {} /** @@ -140,13 +140,13 @@ namespace OpenXLSX XLCellReference( static_cast(m_dataRange->m_rowNode->attribute("r").as_ullong()), static_cast(cellNumber)).address().c_str()); - m_currentCell = XLCell(cellNode/*, m_dataRange->m_sharedStrings*/); + m_currentCell = XLCell(cellNode, m_dataRange->m_worksheet); } // ===== Otherwise, the cell node and the column number match. else { assert(XLCellReference(cellNode.attribute("r").value()).column() == cellNumber); - m_currentCell = XLCell(cellNode/*, m_dataRange->m_sharedStrings*/); + m_currentCell = XLCell(cellNode, m_dataRange->m_worksheet); } return *this; @@ -219,11 +219,12 @@ namespace OpenXLSX * @pre * @post */ - XLRowDataRange::XLRowDataRange(const XMLNode& rowNode, uint16_t firstColumn, uint16_t lastColumn/*, const XLSharedStrings& sharedStrings*/) + XLRowDataRange::XLRowDataRange(const XMLNode& rowNode, uint16_t firstColumn, + uint16_t lastColumn, const XLWorksheet* wks) : m_rowNode(std::make_unique(rowNode)), m_firstCol(firstColumn), - m_lastCol(lastColumn) - //m_sharedStrings(sharedStrings) + m_lastCol(lastColumn), + m_worksheet(wks) { if (lastColumn < firstColumn) { m_firstCol = 1; @@ -391,7 +392,7 @@ namespace OpenXLSX curNode = m_rowNode->prepend_child("c"); curNode.append_attribute("r").set_value(XLCellReference(static_cast(m_row->rowNumber()), static_cast(colNo)).address().c_str()); - XLCell(curNode/*, m_row->m_sharedStrings*/).value() = *value; + XLCell(curNode, m_row->m_worksheet).value() = *value; --colNo; } @@ -411,7 +412,7 @@ namespace OpenXLSX if (values.size() > MAX_COLS) throw XLOverflowError("Container size exceeds maximum number of columns."); if (values.empty()) return *this; - auto range = XLRowDataRange(*m_rowNode, 1, static_cast(values.size())/*, getSharedStrings()*/); + auto range = XLRowDataRange(*m_rowNode, 1, static_cast(values.size()),m_row->m_worksheet); auto dst = range.begin(); auto src = values.begin(); @@ -470,7 +471,7 @@ namespace OpenXLSX // ===== If there are one or more cells in the current row, iterate through them and add the value to the container. if (numCells > 0) { for (auto& node : m_rowNode->children()) - result[XLCellReference(node.attribute("r").value()).column() - 1] = XLCell(node/*, m_row->m_sharedStrings*/).value(); + result[XLCellReference(node.attribute("r").value()).column() - 1] = XLCell(node, m_row->m_worksheet).value(); } // ===== Return the resulting container. @@ -520,7 +521,7 @@ namespace OpenXLSX { auto curNode = m_rowNode->prepend_child("c"); curNode.append_attribute("r").set_value(XLCellReference(static_cast(m_row->rowNumber()), col).address().c_str()); - XLCell(curNode/*, m_row->m_sharedStrings*/).value() = value; + XLCell(curNode, m_row->m_worksheet).value() = value; } /** diff --git a/OpenXLSX/sources/XLSharedStrings.cpp b/OpenXLSX/sources/XLSharedStrings.cpp index 5a26d534..a346da87 100644 --- a/OpenXLSX/sources/XLSharedStrings.cpp +++ b/OpenXLSX/sources/XLSharedStrings.cpp @@ -57,12 +57,6 @@ using namespace OpenXLSX; * @details Constructs a new XLSharedStrings object. Only one (common) object is allowed per XLDocument instance. * A filepath to the underlying XML file must be provided. */ -/* -XLSharedStrings::XLSharedStrings(XLXmlData* xmlData, std::deque *stringCache) - : XLXmlFile(xmlData), m_stringCache(stringCache) -{ -} -*/ XLSharedStrings::XLSharedStrings(XLXmlData* xmlData) : XLXmlFile(xmlData) { @@ -82,9 +76,9 @@ XLSharedStrings::XLSharedStrings(XLXmlData* xmlData) } } -/* + XLSharedStrings::~XLSharedStrings() = default; -*/ + /** * @details Look up a string index by the string content. If the string does not exist, the returned index is -1. */ @@ -97,11 +91,6 @@ uint32_t XLSharedStrings::getStringIndex(const std::string& str) const // Not found return (uint32_t)(-1); - /* - auto iter = std::find_if(m_stringCache->begin(), m_stringCache->end(), [&](const std::string& s) { return str == s; }); - - return iter == m_stringCache->end() ? -1 : static_cast(std::distance(m_stringCache->begin(), iter)); - */ } /** @@ -123,8 +112,7 @@ const char* XLSharedStrings::getString(uint32_t index) const } catch (const std::out_of_range&) { return std::string().c_str(); } - - //return (*m_stringCache)[index].c_str(); + } /** @@ -139,15 +127,10 @@ uint32_t XLSharedStrings::appendString(const std::string& str) textNode.text().set(str.c_str()); m_stringShared.push_back(str); - //m_stringCache->emplace_back(textNode.text().get()); + auto test = m_stringShared.size() - 1; return m_stringShared.size() - 1; - /* - auto test = static_cast(std::distance(m_stringCache->begin(), m_stringCache->end()) - 1); - auto size = m_stringCache->size(); - return static_cast(std::distance(m_stringCache->begin(), m_stringCache->end()) - 1); - */ } /** diff --git a/OpenXLSX/sources/XLSheet.cpp b/OpenXLSX/sources/XLSheet.cpp index 95e8c283..dbe6ef3a 100644 --- a/OpenXLSX/sources/XLSheet.cpp +++ b/OpenXLSX/sources/XLSheet.cpp @@ -370,7 +370,7 @@ XLCell XLWorksheet::cell(uint32_t rowNumber, uint16_t columnNumber) const } } - return XLCell{cellNode/*, parentDoc().execQuery(XLQuery(XLQueryType::QuerySharedStrings)).result()*/}; + return XLCell{cellNode, this}; } /** @@ -388,8 +388,8 @@ XLCellRange XLWorksheet::range(const XLCellReference& topLeft, const XLCellRefer { return XLCellRange(xmlDocument().first_child().child("sheetData"), topLeft, - bottomRight - /*parentDoc().execQuery(XLQuery(XLQueryType::QuerySharedStrings)).result()*/); + bottomRight, + this); } XLCellRange XLWorksheet::range(const std::string& ref) const @@ -410,8 +410,8 @@ XLRowRange XLWorksheet::rows() const 1, (sheetDataNode.last_child() ? static_cast(sheetDataNode.last_child().attribute("r").as_ullong()) - : 1) - /*parentDoc().execQuery(XLQuery(XLQueryType::QuerySharedStrings)).result()*/); + : 1), + this); } /** @@ -423,8 +423,8 @@ XLRowRange XLWorksheet::rows(uint32_t rowCount) const { return XLRowRange(xmlDocument().first_child().child("sheetData"), 1, - rowCount - /*parentDoc().execQuery(XLQuery(XLQueryType::QuerySharedStrings)).result()*/); + rowCount, + this); } /** @@ -436,8 +436,8 @@ XLRowRange XLWorksheet::rows(uint32_t firstRow, uint32_t lastRow) const { return XLRowRange(xmlDocument().first_child().child("sheetData"), firstRow, - lastRow - /*parentDoc().execQuery(XLQuery(XLQueryType::QuerySharedStrings)).result()*/); + lastRow, + this); } /** @@ -447,8 +447,7 @@ XLRowRange XLWorksheet::rows(uint32_t firstRow, uint32_t lastRow) const */ XLRow XLWorksheet::row(uint32_t rowNumber) const { - return XLRow{getRowNode(xmlDocument().first_child().child("sheetData"), rowNumber) - /*parentDoc().execQuery(XLQuery(XLQueryType::QuerySharedStrings)).result()*/}; + return XLRow{getRowNode(xmlDocument().first_child().child("sheetData"), rowNumber), this}; } /** @@ -574,9 +573,9 @@ void XLWorksheet::updateSheetName(const std::string& oldName, const std::string& // ===== Iterate through all defined names for (auto& row : xmlDocument().document_element().child("sheetData")) { for (auto& cell : row.children()) { - if (!XLCell(cell/*, XLSharedStrings()*/).hasFormula()) continue; + if (!XLCell(cell, this).hasFormula()) continue; - formula = XLCell(cell/*, XLSharedStrings()*/).formula().get(); + formula = XLCell(cell, this).formula().get(); // ===== Skip if formula contains a '[' and ']' (means that the defined refers to external workbook) if (formula.find('[') == std::string::npos && formula.find(']') == std::string::npos) { @@ -584,7 +583,7 @@ void XLWorksheet::updateSheetName(const std::string& oldName, const std::string& while (formula.find(oldNameTemp) != std::string::npos) { // NOLINT formula.replace(formula.find(oldNameTemp), oldNameTemp.length(), newNameTemp); } - XLCell(cell/*, XLSharedStrings()*/).formula() = formula; + XLCell(cell, this).formula() = formula; } } } diff --git a/OpenXLSX/sources/XLTable.cpp b/OpenXLSX/sources/XLTable.cpp index bc5256c2..4286dec9 100644 --- a/OpenXLSX/sources/XLTable.cpp +++ b/OpenXLSX/sources/XLTable.cpp @@ -59,13 +59,10 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. using namespace OpenXLSX; -XLTable::XLTable(XLXmlData* xmlData) : m_pXmlData(xmlData) +XLTable::XLTable(XLXmlData* xmlData) + : m_pXmlData(xmlData),m_sheet(XLWorksheet(xmlData->getParentNode())) { - /* - using XMLNode = pugi::xml_node; - using XMLAttribute = pugi::xml_attribute; - using XMLDocument = pugi::xml_document; - */ + // ===== Deal with the columns XMLNode pTblColumns = m_pXmlData->getXmlDocument()->child("table").child("tableColumns"); @@ -115,17 +112,17 @@ uint16_t XLTable::columnIndex(const std::string& name) const return (uint16_t)(-1); } -XLWorksheet XLTable::getWorksheet() const +XLWorksheet* XLTable::getWorksheet() { - return XLWorksheet(m_pXmlData->getParentNode()); + return &m_sheet; } -XLCellRange XLTable::tableRange() const +XLCellRange XLTable::tableRange() { - return getWorksheet().range(ref()); + return getWorksheet()->range(ref()); } -XLTableRows XLTable::tableRows() const +XLTableRows XLTable::tableRows() { std::pair p = XLCellRange::topLeftBottomRight(ref()); XLCellReference topLeft(p.first); @@ -144,11 +141,10 @@ XLTableRows XLTable::tableRows() const lastRow -=1; return XLTableRows(m_pXmlData->getParentNode()->getXmlDocument()->first_child().child("sheetData"), - firstRow, lastRow, firstCol, lastCol - /*m_pXmlData->getParentDoc()->execQuery(XLQuery(XLQueryType::QuerySharedStrings)).result()*/); + firstRow, lastRow, firstCol, lastCol, getWorksheet()); } -XLCellRange XLTable::dataBodyRange() const +XLCellRange XLTable::dataBodyRange() { std::pair p = XLCellRange::topLeftBottomRight(ref()); XLCellReference topLeft(p.first); @@ -160,7 +156,7 @@ XLCellRange XLTable::dataBodyRange() const if (isTotalVisible()) bottomRight.offset(-1); - return getWorksheet().range(topLeft,bottomRight); + return getWorksheet()->range(topLeft,bottomRight); } bool XLTable::isHeaderVisible() const diff --git a/OpenXLSX/sources/XLTableRows.cpp b/OpenXLSX/sources/XLTableRows.cpp index 7379c28b..a992fe49 100644 --- a/OpenXLSX/sources/XLTableRows.cpp +++ b/OpenXLSX/sources/XLTableRows.cpp @@ -61,14 +61,14 @@ using namespace OpenXLSX; XLTableRowIterator:: XLTableRowIterator(const XLTableRows& tableRows, XLIteratorLocation loc): m_range (XLCellRange( *tableRows.m_dataNode, XLCellReference (tableRows.m_firstRow, tableRows.m_firstCol), - XLCellReference (tableRows.m_firstRow, tableRows.m_lastCol) - /*tableRows.m_sharedStrings*/)) + XLCellReference (tableRows.m_firstRow, tableRows.m_lastCol), + tableRows.m_worksheet)) { if (loc == XLIteratorLocation::End) m_range = XLCellRange( *tableRows.m_dataNode, XLCellReference (tableRows.m_lastRow, tableRows.m_firstCol), - XLCellReference (tableRows.m_lastRow, tableRows.m_lastCol) - /*tableRows.m_sharedStrings*/); + XLCellReference (tableRows.m_lastRow, tableRows.m_lastCol), + tableRows.m_worksheet); } XLTableRowIterator::~ XLTableRowIterator() = default; @@ -169,9 +169,9 @@ XLTableRows::XLTableRows(const XMLNode& dataNode, uint32_t firstRow, uint32_t lastRow, uint16_t firstCol, - uint16_t lastCol - /*const OpenXLSX::XLSharedStrings& sharedStrings*/): - XLRowRange(dataNode, firstRow, lastRow/*, sharedStrings*/), + uint16_t lastCol, + const XLWorksheet* wks): + XLRowRange(dataNode, firstRow, lastRow, wks), m_firstCol(firstCol), m_lastCol(lastCol) {} @@ -217,13 +217,13 @@ XLCellRange XLTableRows::operator[](uint32_t index) const if (row > m_lastRow) return XLCellRange(*m_dataNode, XLCellReference (m_firstRow, m_firstCol), - XLCellReference (m_lastRow, m_lastCol) - /*m_sharedStrings*/); + XLCellReference (m_lastRow, m_lastCol), + m_worksheet); return XLCellRange(*m_dataNode, XLCellReference (row, m_firstCol), - XLCellReference (row, m_lastCol) - /*m_sharedStrings*/); + XLCellReference (row, m_lastCol), + m_worksheet); } diff --git a/OpenXLSX/sources/XLWorkbook.cpp b/OpenXLSX/sources/XLWorkbook.cpp index b51e91ec..3412dc43 100644 --- a/OpenXLSX/sources/XLWorkbook.cpp +++ b/OpenXLSX/sources/XLWorkbook.cpp @@ -88,6 +88,7 @@ XLWorkbook::~XLWorkbook() = default; */ XLSheet XLWorkbook::sheet(const std::string& sheetName) { + XLQuery xmlQuery(XLQueryType::QuerySheetFromName); xmlQuery.setParam("sheetName", sheetName); return XLSheet(parentDoc().execQuery(xmlQuery).result()); From 7bbaa5e54409650c516339e9e5c65fea285d817b Mon Sep 17 00:00:00 2001 From: akira215 Date: Sat, 31 Dec 2022 01:22:29 +0100 Subject: [PATCH 13/45] Removing bug from addNamedRange --- OpenXLSX/headers/XLDocument.hpp | 2 -- OpenXLSX/headers/XLTemplates.hpp | 4 +-- OpenXLSX/sources/XLCellRange.cpp | 5 ++-- OpenXLSX/sources/XLCellValue.cpp | 1 - OpenXLSX/sources/XLDocument.cpp | 7 ++--- OpenXLSX/sources/XLSharedStrings.cpp | 9 ++++-- OpenXLSX/sources/XLWorkbook.cpp | 44 ++++++++++------------------ 7 files changed, 28 insertions(+), 44 deletions(-) diff --git a/OpenXLSX/headers/XLDocument.hpp b/OpenXLSX/headers/XLDocument.hpp index 1d81fa0a..b77cbce8 100644 --- a/OpenXLSX/headers/XLDocument.hpp +++ b/OpenXLSX/headers/XLDocument.hpp @@ -299,8 +299,6 @@ namespace OpenXLSX */ XLXmlData* getXmlDataByName(const std::string& name) const; - XLSharedStrings& getSharedString() const; - /** * @brief * @param name diff --git a/OpenXLSX/headers/XLTemplates.hpp b/OpenXLSX/headers/XLTemplates.hpp index c42b7b2a..502c3b94 100644 --- a/OpenXLSX/headers/XLTemplates.hpp +++ b/OpenXLSX/headers/XLTemplates.hpp @@ -13,9 +13,6 @@ namespace OpenXLSX const std::string sharedStrings { "\n" "" - //" \n" - //" \n" - //" \n" "" }; const std::string emptyWorksheet { @@ -41,6 +38,7 @@ namespace OpenXLSX " xmlns:xr=\"http://schemas.microsoft.com/office/spreadsheetml/2014/revision\"" " xmlns:xr3=\"http://schemas.microsoft.com/office/spreadsheetml/2016/revision3\"" " id=\"0\" name=\"Table\" displayName=\"Table\" ref=\"A1:B2\" totalsRowShown=\"0\">" + "" "" }; diff --git a/OpenXLSX/sources/XLCellRange.cpp b/OpenXLSX/sources/XLCellRange.cpp index 4552be28..a14b54ee 100644 --- a/OpenXLSX/sources/XLCellRange.cpp +++ b/OpenXLSX/sources/XLCellRange.cpp @@ -233,8 +233,9 @@ void XLCellRange::clear() std::pair XLCellRange::topLeftBottomRight(const std::string& ref) { std::string::size_type n = ref.find(':'); - if(n>ref.size()) - throw XLInputError("Invalid reference \"" + ref + "\" for a range"); + if(n>ref.size()) // there is no : separator + return std::make_pair(ref,ref); + //throw XLInputError("Invalid reference \"" + ref + "\" for a range"); return std::make_pair(ref.substr(0, n),ref.substr(n+1)); } diff --git a/OpenXLSX/sources/XLCellValue.cpp b/OpenXLSX/sources/XLCellValue.cpp index 26f03979..485f5fb7 100644 --- a/OpenXLSX/sources/XLCellValue.cpp +++ b/OpenXLSX/sources/XLCellValue.cpp @@ -406,7 +406,6 @@ void XLCellValueProxy::setString(const char* stringValue) // ===== Get or create the index in the XLSharedStrings object. uint32_t index; - //if (m_cell->m_worksheet->getSharedString().stringExists(stringValue)) if (getSharedString()->stringExists(stringValue)) index = getSharedString()->getStringIndex(stringValue); else diff --git a/OpenXLSX/sources/XLDocument.cpp b/OpenXLSX/sources/XLDocument.cpp index 28d864f9..4a576dcf 100644 --- a/OpenXLSX/sources/XLDocument.cpp +++ b/OpenXLSX/sources/XLDocument.cpp @@ -737,11 +737,6 @@ XLXmlData* XLDocument::getXmlDataByName(const std::string& name) const return nullptr; } -XLSharedStrings& XLDocument::getSharedString() const -{ - return m_sharedStrings; -} - std::string XLDocument::getSheetRelsPath(const std::string& sheetName) const { XLXmlData* wsItem = getXmlDataByName(sheetName); @@ -890,6 +885,8 @@ void XLDocument::createTable(const std::string& sheetName, const std::string& ta tableNode.attribute("name").set_value(name.c_str()); tableNode.attribute("displayName").set_value(name.c_str()); tableNode.attribute("ref").set_value(ref.c_str()); + // set autofilter + tableNode.child("autoFilter").attribute("ref").set_value(ref.c_str()); // Set up the columns !!! const XLWorksheet* pWks = new XLWorksheet(wks); diff --git a/OpenXLSX/sources/XLSharedStrings.cpp b/OpenXLSX/sources/XLSharedStrings.cpp index a346da87..3c6a0776 100644 --- a/OpenXLSX/sources/XLSharedStrings.cpp +++ b/OpenXLSX/sources/XLSharedStrings.cpp @@ -128,7 +128,12 @@ uint32_t XLSharedStrings::appendString(const std::string& str) m_stringShared.push_back(str); - auto test = m_stringShared.size() - 1; + xmlDocument().child("sst").attribute("count") + .set_value(std::to_string(m_stringShared.size()).c_str()); + + // TODO deal with the uniqueCount + xmlDocument().child("sst").attribute("uniqueCount") + .set_value(std::to_string(m_stringShared.size()).c_str()); return m_stringShared.size() - 1; } @@ -147,7 +152,7 @@ void XLSharedStrings::clearString(uint64_t index) return; } - auto iter = xmlDocument().document_element().children().begin(); + auto iter = xmlDocument().document_element().children().begin(); std::advance(iter, index); iter->text().set(""); } diff --git a/OpenXLSX/sources/XLWorkbook.cpp b/OpenXLSX/sources/XLWorkbook.cpp index 3412dc43..e1c167f5 100644 --- a/OpenXLSX/sources/XLWorkbook.cpp +++ b/OpenXLSX/sources/XLWorkbook.cpp @@ -56,6 +56,8 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. #include "XLSheet.hpp" #include "XLTable.hpp" #include "XLWorkbook.hpp" +#include "XLCellRange.hpp" + using namespace OpenXLSX; @@ -151,17 +153,11 @@ XLNamedRange XLWorkbook::namedRange(const std::string& rangeName) std::string::size_type n = reference.find("!"); const std::string sheetName = reference.substr(0, n); std::string ref = reference.substr(n+1); - n = ref.find(":"); - std::string topLeft = ref.substr(0, n); - std::string bottomRight; - if (nworksheet(sheetName).range(XLCellReference(topLeft), XLCellReference(bottomRight))); + this->worksheet(sheetName).range(XLCellReference(pair.first), XLCellReference(pair.second))); } /** @@ -172,15 +168,7 @@ XLChartsheet XLWorkbook::chartsheet(const std::string& sheetName) return sheet(sheetName).get(); } -/** - * @details - */ -/* -bool XLWorkbook::hasSharedStrings() const -{ - return true;//parentDoc().executeQuery(XLQuerySharedStrings()).sharedStrings() != nullptr; -} -*/ + /** * @details */ @@ -292,7 +280,7 @@ void XLWorkbook::addNamedRange(const std::string& rangeName, if (!sheetExists(sheetName)) throw XLInputError("Sheet with name \"" + sheetName + "\" doesn't exist."); - std::string ref = reference.substr(n+1, reference.size()); + std::string ref = reference.substr(n+1); n = ref.find(":"); std::string topLeft = ref.substr(0, n); @@ -300,11 +288,19 @@ void XLWorkbook::addNamedRange(const std::string& rangeName, XLCellReference cellRef(topLeft); std::string safeReference = sheetName + "!" + cellRef.address(true); if (n + auto shtNode = xmlDocument().document_element().child("sheets"); + if(!shtNode) + throw XLInputError("Unable to find tag in \"" + sheetName + "\"."); + + xmlDocument().document_element().insert_child_after("definedNames", shtNode); + } + auto node = xmlDocument().document_element().child("definedNames").append_child("definedName"); // ===== append the required attributes to the newly created sheet node. @@ -322,21 +318,11 @@ void XLWorkbook::addNamedRange(const std::string& rangeName, void XLWorkbook::addTable(const std::string& sheetName, const std::string& tableName, const std::string& reference) { -/* - // ===== If a sheet with the given name already exists, throw an exception. - if (xmlDocument().document_element().child("sheets").find_child_by_attribute("name", sheetName.c_str())) - throw XLInputError("Sheet named \"" + sheetName + "\" already exists."); - - // ===== Create new internal (workbook) ID for the sheet - auto internalID = createInternalSheetID(); -*/ // ===== Create xml file for new worksheet and add metadata to the workbook file. parentDoc().execCommand(XLCommand(XLCommandType::AddTable) .setParam("worksheet", sheetName) .setParam("tableName", tableName) .setParam("reference", reference)); - - //prepareSheetMetadata(sheetName, internalID); } From 7dee4de6b42bf3ee77150b86b81d33cd48aae7ee Mon Sep 17 00:00:00 2001 From: akira215 Date: Sat, 31 Dec 2022 15:43:28 +0100 Subject: [PATCH 14/45] Cleaning up the code --- Examples/CMakeLists.txt | 65 ++++++++++--------- Examples/{Demo1.cpp => Demo01.cpp} | 0 Examples/{Demo1A.cpp => Demo01A.cpp} | 0 Examples/{Demo2.cpp => Demo02.cpp} | 0 Examples/{Demo3.cpp => Demo03.cpp} | 0 Examples/{Demo4.cpp => Demo04.cpp} | 0 Examples/{Demo5.cpp => Demo05.cpp} | 0 Examples/{Demo6.cpp => Demo06.cpp} | 0 Examples/{Demo7.cpp => Demo07.cpp} | 0 Examples/{Demo8.cpp => Demo08.cpp} | 0 Examples/Demo09.cpp | 65 +++++++++++++++++++ Examples/Demo10.cpp | 93 ++++++++++++++++++---------- Examples/Demo9.cpp | 38 ------------ OpenXLSX/OpenXLSX.hpp | 1 + OpenXLSX/headers/XLCellRange.hpp | 7 +++ OpenXLSX/headers/XLCellReference.hpp | 2 +- OpenXLSX/headers/XLCellValue.hpp | 4 ++ OpenXLSX/headers/XLDocument.hpp | 7 +-- OpenXLSX/headers/XLNamedRange.hpp | 33 +++++++--- OpenXLSX/headers/XLRelationships.hpp | 2 +- OpenXLSX/headers/XLRow.hpp | 2 +- OpenXLSX/headers/XLRowData.hpp | 6 -- OpenXLSX/headers/XLSharedStrings.hpp | 6 -- OpenXLSX/headers/XLSheet.hpp | 2 - OpenXLSX/headers/XLTable.hpp | 79 +++++++++++++++++++++-- OpenXLSX/headers/XLTableColumn.hpp | 13 +++- OpenXLSX/headers/XLTableRows.hpp | 5 +- OpenXLSX/headers/XLTemplates.hpp | 2 +- OpenXLSX/headers/XLWorkbook.hpp | 20 +++--- OpenXLSX/sources/XLCellValue.cpp | 2 + OpenXLSX/sources/XLDocument.cpp | 5 +- OpenXLSX/sources/XLNamedRange.cpp | 17 +---- OpenXLSX/sources/XLRowData.cpp | 13 ---- OpenXLSX/sources/XLSharedStrings.cpp | 6 +- OpenXLSX/sources/XLTable.cpp | 38 +++++++----- OpenXLSX/sources/XLTableColumn.cpp | 4 +- OpenXLSX/sources/XLTableRows.cpp | 2 +- OpenXLSX/sources/XLWorkbook.cpp | 26 +++----- 38 files changed, 346 insertions(+), 219 deletions(-) rename Examples/{Demo1.cpp => Demo01.cpp} (100%) rename Examples/{Demo1A.cpp => Demo01A.cpp} (100%) rename Examples/{Demo2.cpp => Demo02.cpp} (100%) rename Examples/{Demo3.cpp => Demo03.cpp} (100%) rename Examples/{Demo4.cpp => Demo04.cpp} (100%) rename Examples/{Demo5.cpp => Demo05.cpp} (100%) rename Examples/{Demo6.cpp => Demo06.cpp} (100%) rename Examples/{Demo7.cpp => Demo07.cpp} (100%) rename Examples/{Demo8.cpp => Demo08.cpp} (100%) create mode 100644 Examples/Demo09.cpp delete mode 100644 Examples/Demo9.cpp diff --git a/Examples/CMakeLists.txt b/Examples/CMakeLists.txt index 1776ea9a..cb56fe01 100644 --- a/Examples/CMakeLists.txt +++ b/Examples/CMakeLists.txt @@ -11,65 +11,70 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") add_subdirectory(external/nowide EXCLUDE_FROM_ALL) #======================================================================================================================= -# Define Demo1 target +# Define Demo01 target #======================================================================================================================= -add_executable(Demo1 Demo1.cpp) -target_link_libraries(Demo1 PRIVATE OpenXLSX::OpenXLSX) +add_executable(Demo01 Demo01.cpp) +target_link_libraries(Demo01 PRIVATE OpenXLSX::OpenXLSX) #======================================================================================================================= -# Define Demo1A target +# Define Demo01A target #======================================================================================================================= if(${OPENXLSX_ENABLE_LIBZIP}) find_package(LIBZIP MODULE REQUIRED) - add_executable(Demo1A Demo1A.cpp) - target_link_libraries(Demo1A PRIVATE OpenXLSX::OpenXLSX libzip::zip) + add_executable(Demo01A Demo01A.cpp) + target_link_libraries(Demo01A PRIVATE OpenXLSX::OpenXLSX libzip::zip) endif() #======================================================================================================================= -# Define Demo2 target +# Define Demo02 target #======================================================================================================================= -add_executable(Demo2 Demo2.cpp) -target_link_libraries(Demo2 PRIVATE OpenXLSX::OpenXLSX) +add_executable(Demo02 Demo02.cpp) +target_link_libraries(Demo02 PRIVATE OpenXLSX::OpenXLSX) #======================================================================================================================= -# Define Demo3 target +# Define Demo03 target #======================================================================================================================= -add_executable(Demo3 Demo3.cpp) -target_link_libraries(Demo3 PRIVATE OpenXLSX::OpenXLSX) +add_executable(Demo03 Demo03.cpp) +target_link_libraries(Demo03 PRIVATE OpenXLSX::OpenXLSX) #======================================================================================================================= -# Define Demo4 target +# Define Demo04 target #======================================================================================================================= -add_executable(Demo4 Demo4.cpp) -target_link_libraries(Demo4 PRIVATE OpenXLSX::OpenXLSX nowide::nowide) +add_executable(Demo04 Demo04.cpp) +target_link_libraries(Demo04 PRIVATE OpenXLSX::OpenXLSX nowide::nowide) #======================================================================================================================= -# Define Demo9 target +# Define Demo09 target #======================================================================================================================= -add_executable(Demo5 Demo5.cpp) -target_link_libraries(Demo5 PRIVATE OpenXLSX::OpenXLSX) +add_executable(Demo05 Demo05.cpp) +target_link_libraries(Demo05 PRIVATE OpenXLSX::OpenXLSX) #======================================================================================================================= -# Define Demo6 target +# Define Demo06 target #======================================================================================================================= -add_executable(Demo6 Demo6.cpp) -target_link_libraries(Demo6 PRIVATE OpenXLSX::OpenXLSX) +add_executable(Demo06 Demo06.cpp) +target_link_libraries(Demo06 PRIVATE OpenXLSX::OpenXLSX) #======================================================================================================================= -# Define Demo7 target +# Define Demo07 target #======================================================================================================================= -add_executable(Demo7 Demo7.cpp) -target_link_libraries(Demo7 PRIVATE OpenXLSX::OpenXLSX) +add_executable(Demo07 Demo07.cpp) +target_link_libraries(Demo07 PRIVATE OpenXLSX::OpenXLSX) #======================================================================================================================= -# Define Demo8 target +# Define Demo08 target #======================================================================================================================= -add_executable(Demo8 Demo8.cpp) -target_link_libraries(Demo8 PRIVATE OpenXLSX::OpenXLSX) +add_executable(Demo08 Demo08.cpp) +target_link_libraries(Demo08 PRIVATE OpenXLSX::OpenXLSX) #======================================================================================================================= -# Define Demo9 target +# Define Demo09 target #======================================================================================================================= -add_executable(Demo9 Demo9.cpp) -target_link_libraries(Demo9 PRIVATE OpenXLSX::OpenXLSX) +add_executable(Demo09 Demo09.cpp) +target_link_libraries(Demo09 PRIVATE OpenXLSX::OpenXLSX) +#======================================================================================================================= +# Define Demo10 target +#======================================================================================================================= +add_executable(Demo10 Demo10.cpp) +target_link_libraries(Demo10 PRIVATE OpenXLSX::OpenXLSX) diff --git a/Examples/Demo1.cpp b/Examples/Demo01.cpp similarity index 100% rename from Examples/Demo1.cpp rename to Examples/Demo01.cpp diff --git a/Examples/Demo1A.cpp b/Examples/Demo01A.cpp similarity index 100% rename from Examples/Demo1A.cpp rename to Examples/Demo01A.cpp diff --git a/Examples/Demo2.cpp b/Examples/Demo02.cpp similarity index 100% rename from Examples/Demo2.cpp rename to Examples/Demo02.cpp diff --git a/Examples/Demo3.cpp b/Examples/Demo03.cpp similarity index 100% rename from Examples/Demo3.cpp rename to Examples/Demo03.cpp diff --git a/Examples/Demo4.cpp b/Examples/Demo04.cpp similarity index 100% rename from Examples/Demo4.cpp rename to Examples/Demo04.cpp diff --git a/Examples/Demo5.cpp b/Examples/Demo05.cpp similarity index 100% rename from Examples/Demo5.cpp rename to Examples/Demo05.cpp diff --git a/Examples/Demo6.cpp b/Examples/Demo06.cpp similarity index 100% rename from Examples/Demo6.cpp rename to Examples/Demo06.cpp diff --git a/Examples/Demo7.cpp b/Examples/Demo07.cpp similarity index 100% rename from Examples/Demo7.cpp rename to Examples/Demo07.cpp diff --git a/Examples/Demo8.cpp b/Examples/Demo08.cpp similarity index 100% rename from Examples/Demo8.cpp rename to Examples/Demo08.cpp diff --git a/Examples/Demo09.cpp b/Examples/Demo09.cpp new file mode 100644 index 00000000..c0707670 --- /dev/null +++ b/Examples/Demo09.cpp @@ -0,0 +1,65 @@ +#include + +using namespace std; +using namespace OpenXLSX; + +int main() { + cout << "********************************************************************************\n"; + cout << "DEMO PROGRAM #09: Named Range\n"; + cout << "********************************************************************************\n"; + + // This example illustrate the use of the named range object. This could be particulary + // usefull when programming without GUI, to set up name in the Excel file, so that + // data could be safetly retrived and written by the code in dedicated location in the Excel file + // Unlike other implementation, named range is accessible within workbook object. Sheet limited + // maed range are as well accessed via the wrokbook. + + // First, create a new document and access the 1st sheet. + cout << "\nGenerating spreadsheet ..." << endl; + XLDocument doc; + doc.create("./Demo09.xlsx"); + auto wks = doc.workbook().sheet(1).get(); + string sheetName = wks.name(); + + // Define a namedrange "New name" + // At this stage the range shall be continuous + // a third argument could be provided the index of the spreasheet where + // the named range will be defined. Absolute marks ($) will be added. + string fullRef = sheetName + "!A5:E10"; + XLNamedRange myRange = doc.workbook().addNamedRange("MyNamedRange",fullRef /*, localSheetId*/); + + // Save the sheet... + cout << "Saving spreadsheet ..." << endl; + doc.save(); + doc.close(); + + // ...and reopen it (just to make sure that it is a valid .xlsx file) + cout << "Re-opening spreadsheet ..." << endl << endl; + doc.open("./Demo09.xlsx"); + wks = doc.workbook().worksheet(sheetName); + + // The NamedRange object is a range, it can be iterated + cout << "Filling the named range object ..." << endl; + XLNamedRange rng = doc.workbook().namedRange("MyNamedRange"); + int i = 0; + for (auto& cell : rng){ + cell.value() = i; + i++; + } + + // It can also be accessed via [] + cout << "Value of the 10th cell of the named range:" << endl; + cout << rng[10].value() << endl; + + // for convenience, in particular in case of mono cell named range, + // a fonction is provided: firstCell() + cout << "first Cell Value: " << rng.firstCell().value()<< endl; + + // Finally named range could be removed + //doc.workbook().deleteNamedRange("MyNamedRange"); + + doc.save(); + doc.close(); + + return 0; +} \ No newline at end of file diff --git a/Examples/Demo10.cpp b/Examples/Demo10.cpp index 4378c5d0..589f5329 100644 --- a/Examples/Demo10.cpp +++ b/Examples/Demo10.cpp @@ -1,48 +1,77 @@ #include +#include + +using namespace std; using namespace OpenXLSX; int main() { - + cout << "********************************************************************************\n"; + cout << "DEMO PROGRAM #10: Tables first part\n"; + cout << "********************************************************************************\n"; + + // This example illustrate the use of the named range object. This could be particulary + // usefull when programming without GUI, to set up name in the Excel file, so that + // data could be safetly retrived and written by the code in dedicated location in the Excel file + // Unlike other implementation, named range is accessible within workbook object. Sheet limited + // maed range are as well accessed via the wrokbook. + + // First, create a new document and access the 1st sheet. + cout << "\nGenerating spreadsheet ..." << endl; XLDocument doc; - doc.open("./testSimple.xlsx"); - auto wks = doc.workbook().worksheet("Matrix"); - - auto matrix = wks.range("C4:G16"); - int myCell = matrix[57].value(); - + doc.create("./Demo10.xlsx"); + auto wks = doc.workbook().sheet(1).get(); + string sheetName = wks.name(); + + // Fill the column header and create the table + // If the table header is not set, default name will be setup + // Also columns name shall be unique, a increment marks is added if required + cout << "Creating table ..." << endl; + wks.cell("B2").value() = "#"; + wks.cell("C2").value() = "One"; + wks.cell("D2").value() = "Col"; + wks.cell("E2").value() = "With"; + wks.cell("F2").value() = "Table"; + + XLTable myTable = doc.workbook().addTable(sheetName,"MyTable","B2:F18"); + + // Save the sheet... + cout << "Saving spreadsheet ..." << endl; + doc.save(); + doc.close(); - auto testTable = doc.workbook().table("tbl_one"); + // ...and reopen it (just to make sure that it is a valid .xlsx file) + cout << "Re-opening spreadsheet ..." << endl << endl; + doc.open("./Demo10.xlsx"); + wks = doc.workbook().worksheet(sheetName); + // We can retrieve the headers name: + XLTable tbl = doc.workbook().table("MyTable"); + vector headers = tbl.columnNames(); - //testTable.setName("tbl_ash"); - auto testName = testTable.name(); - auto cols = testTable.columnNames(); + cout << "Table "<< tbl.name() << " header names:" << endl; + int i = 0; + for(const auto& h : headers){ + cout << i++ << " - " << h << endl; + } - auto ncol = testTable.columnIndex("Col bord"); - auto sht = testTable.getWorksheet(); - auto rang = testTable.dataBodyRange(); - auto rows = testTable.tableRows(); + // We can also access different items + auto ncol = tbl.columnIndex("Col"); // Retrieve the colum index by the name + auto sht = tbl.getWorksheet(); // Retrieve and object worksheet + auto rang = tbl.tableRange(); // whole table range including total & headers + auto bodyRange = tbl.dataBodyRange(); // Only data body table range (excl. total & headers) + auto nRow = tbl.rowsCount(); // Only data body table range (excl. total & headers) + // And iterate throught the table rows + auto nCol = tbl.columnsCount(); // Only data body table range (excl. total & headers) - int val = 67; - for(auto& row:rows) { - row[0].value() = val; - val +=1; - } -/* - for(auto& cell:rows[9]) { - int i=cell.value(); + int j = 0; + for(const auto& row : tbl.tableRows()){ + row[tbl.columnIndex("#")].value() = j; + row[1].value() = "Data" + to_string(j); + row[tbl.columnIndex("Table")].value() = (float)j * 2.0f / 3.0f; + j++; } - */ - - auto row5 = rows[5]; - - - std::string shtName = sht.name(); - - //doc.workbook().definedName("nbAngles"); - //wks.cell("A1").value() = "Hello, OpenXLSX ASHHHH!"; doc.save(); doc.close(); diff --git a/Examples/Demo9.cpp b/Examples/Demo9.cpp deleted file mode 100644 index 5bb0aa1e..00000000 --- a/Examples/Demo9.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include -// TODO documentation !!!! -using namespace OpenXLSX; - -int main() { - - XLDocument doc; - doc.open("./CTest.xlsx"); - auto wks = doc.workbook().worksheet("Input"); - - - auto rng = wks.range(XLCellReference("A1"), XLCellReference("C20")); - XLNamedRange testrg = doc.workbook().namedRange("defined_in_sheet"); - - testrg = doc.workbook().namedRange("testRange"); - XLCellValue iteration; - for (auto& cell : testrg) - iteration = cell.value(); - - doc.workbook().deleteNamedRange("NewFromCpp"); - - XLCell i = testrg.firstCell(); - XLCellValue itet = i.value(); - i.value() = "Changed By ASH"; - - std::string n = testrg.name(); - - doc.workbook().addNamedRange("NewFromCpp","Input!$F$4f",2); - - - auto testTable = doc.workbook().table("tbl_Hullform"); - - - doc.save(); - doc.close(); - - return 0; -} \ No newline at end of file diff --git a/OpenXLSX/OpenXLSX.hpp b/OpenXLSX/OpenXLSX.hpp index 4b924bba..ed68da34 100644 --- a/OpenXLSX/OpenXLSX.hpp +++ b/OpenXLSX/OpenXLSX.hpp @@ -59,6 +59,7 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. #include "headers/XLRow.hpp" #include "headers/XLSheet.hpp" #include "headers/XLTable.hpp" +#include "headers/XLTableRows.hpp" #include "headers/XLWorkbook.hpp" #include "headers/XLZipArchive.hpp" diff --git a/OpenXLSX/headers/XLCellRange.hpp b/OpenXLSX/headers/XLCellRange.hpp index 868d65b4..a4182c63 100644 --- a/OpenXLSX/headers/XLCellRange.hpp +++ b/OpenXLSX/headers/XLCellRange.hpp @@ -172,7 +172,14 @@ namespace OpenXLSX */ XLCellIterator end() const; + /** + * @brief offset the whole range if possible + * @param row integer could be negative + * @param col integer could be negative, default 0 + */ + void offset(int row, int col = 0); + /** * @brief */ diff --git a/OpenXLSX/headers/XLCellReference.hpp b/OpenXLSX/headers/XLCellReference.hpp index a7b0f0d9..285b09f6 100644 --- a/OpenXLSX/headers/XLCellReference.hpp +++ b/OpenXLSX/headers/XLCellReference.hpp @@ -161,7 +161,7 @@ namespace OpenXLSX /** * @brief Offset for a given x, y. Stops at the limit of the worksheet. * @param rows the relative number of row to offset - * @param columns the relative number of columns to offset + * @param columns the relative number of columns to offset default 0. * @return return the offseted object */ XLCellReference& offset(int rows, int columns = 0); diff --git a/OpenXLSX/headers/XLCellValue.hpp b/OpenXLSX/headers/XLCellValue.hpp index af321530..7600442b 100644 --- a/OpenXLSX/headers/XLCellValue.hpp +++ b/OpenXLSX/headers/XLCellValue.hpp @@ -534,6 +534,10 @@ namespace OpenXLSX */ XLCellValue getValue() const; + /** + * @brief Get a pointer to the XLSharedStrings* object of the document. + * @return An XLSharedStrings pointer. + */ XLSharedStrings* getSharedString() const; //---------- Private Member Variables ---------- // diff --git a/OpenXLSX/headers/XLDocument.hpp b/OpenXLSX/headers/XLDocument.hpp index b77cbce8..d4548553 100644 --- a/OpenXLSX/headers/XLDocument.hpp +++ b/OpenXLSX/headers/XLDocument.hpp @@ -315,7 +315,7 @@ namespace OpenXLSX uint16_t availableFileID(XLContentType type); /** - * @brief + * @brief create a new table in the doc * @param tableName * @param reference * @return @@ -330,9 +330,8 @@ namespace OpenXLSX std::string m_filePath {}; /**< The path to the original file*/ std::string m_realPath {}; /**< */ - mutable std::list m_data {}; /**< */ - //mutable std::deque m_sharedStringCache {}; /**< */ - mutable XLSharedStrings m_sharedStrings; /**< */ + mutable std::list m_data {}; /**< */ + mutable XLSharedStrings m_sharedStrings; /**< The sharedstrings object (one for each doc)*/ XLRelationships m_docRelationships {}; /**< A pointer to the document relationships object*/ XLRelationships m_wbkRelationships {}; /**< A pointer to the document relationships object*/ diff --git a/OpenXLSX/headers/XLNamedRange.hpp b/OpenXLSX/headers/XLNamedRange.hpp index 8c51b08b..bf29647c 100644 --- a/OpenXLSX/headers/XLNamedRange.hpp +++ b/OpenXLSX/headers/XLNamedRange.hpp @@ -15,7 +15,7 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. MM _MM_ - Copyright (c) 2018, Kenneth Troldal Balslev + Written by Akira SHIMAHARA All rights reserved. @@ -52,11 +52,6 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. // ===== External Includes ===== // #include -/* -#include -#include -#include -*/ // ===== OpenXLSX Includes ===== // #include "OpenXLSX-Exports.hpp" @@ -72,7 +67,12 @@ namespace OpenXLSX class OPENXLSX_EXPORT XLNamedRange : public XLCellRange { public: - + /** + * @brief Constructor + * @param rangeName Name of the range to be created + * @param reference Reference of the cell/range to be named: Sheet1!$I$17:$I$19 + * @param localSheetId Id of the sheet where the name is defined, default is 0 (global) + */ XLNamedRange(const std::string& name, const std::string& reference, uint32_t localSheetId, @@ -107,12 +107,29 @@ namespace OpenXLSX */ XLNamedRange& operator=(XLNamedRange&& other) noexcept; + /** + * @brief + * @return The name of the named range. + */ const std::string& name() const; + + /** + * @brief + * @return The reference of the range. + */ const std::string& reference() const; + + /** + * @brief + * @return The name of the named range. + */ uint32_t localSheetId() const; + /** + * @brief + * @return The first cell of the range. + */ XLCell firstCell() const; - XLCell lastCell() const; private: uint32_t m_localSheetId; diff --git a/OpenXLSX/headers/XLRelationships.hpp b/OpenXLSX/headers/XLRelationships.hpp index e66413fc..74b30edf 100644 --- a/OpenXLSX/headers/XLRelationships.hpp +++ b/OpenXLSX/headers/XLRelationships.hpp @@ -274,7 +274,7 @@ namespace OpenXLSX protected: // ---------- Protected Member Functions ---------- // /** - * @brief Get the next available id "rId". + * @brief Get the next available id "rId". Find holes in the list * @return return the rId{0} string. */ std::string getAvailableRelsId() const; diff --git a/OpenXLSX/headers/XLRow.hpp b/OpenXLSX/headers/XLRow.hpp index aa11748b..f0104672 100644 --- a/OpenXLSX/headers/XLRow.hpp +++ b/OpenXLSX/headers/XLRow.hpp @@ -336,7 +336,7 @@ namespace OpenXLSX uint32_t m_firstRow { 1 }; /**< The cell reference of the first cell in the range */ uint32_t m_lastRow { 1 }; /**< The cell reference of the last cell in the range */ XLRow m_currentRow; /**< */ - const XLWorksheet* m_worksheet; /**< */ + const XLWorksheet* m_worksheet; /**< */ }; /** diff --git a/OpenXLSX/headers/XLRowData.hpp b/OpenXLSX/headers/XLRowData.hpp index 07044973..1f26cee1 100644 --- a/OpenXLSX/headers/XLRowData.hpp +++ b/OpenXLSX/headers/XLRowData.hpp @@ -365,12 +365,6 @@ namespace OpenXLSX */ std::vector getValues() const; - /** - * @brief Helper function for getting a pointer to the shared strings repository. - * @return A pointer to an XLSharedStrings object. - */ - //XLSharedStrings getSharedStrings() const; - /** * @brief Convenience function for erasing the first 'count' numbers of values in the row. * @param count The number of values to erase. diff --git a/OpenXLSX/headers/XLSharedStrings.hpp b/OpenXLSX/headers/XLSharedStrings.hpp index c68cefae..6d28053d 100644 --- a/OpenXLSX/headers/XLSharedStrings.hpp +++ b/OpenXLSX/headers/XLSharedStrings.hpp @@ -50,20 +50,14 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. #pragma warning(disable : 4251) #pragma warning(disable : 4275) -//#include #include #include -//#include -//#include // ===== OpenXLSX Includes ===== // #include "OpenXLSX-Exports.hpp" #include "XLXmlFile.hpp" -//#include "XLXmlData.hpp" -//#include "XLDocument.hpp" - namespace OpenXLSX { diff --git a/OpenXLSX/headers/XLSheet.hpp b/OpenXLSX/headers/XLSheet.hpp index 61e2079c..6794adc8 100644 --- a/OpenXLSX/headers/XLSheet.hpp +++ b/OpenXLSX/headers/XLSheet.hpp @@ -353,8 +353,6 @@ namespace OpenXLSX */ XLWorksheet& operator=(XLWorksheet&& other) = default; - //XLSharedStrings& getSharedString() const; - /** * @brief * @param ref diff --git a/OpenXLSX/headers/XLTable.hpp b/OpenXLSX/headers/XLTable.hpp index 1ffd0511..60dec840 100644 --- a/OpenXLSX/headers/XLTable.hpp +++ b/OpenXLSX/headers/XLTable.hpp @@ -15,7 +15,7 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. MM _MM_ - Copyright (c) 2018, Kenneth Troldal Balslev + Written by Akira SHIMAHARA All rights reserved. @@ -69,24 +69,93 @@ namespace OpenXLSX * @param xmlData from the table file */ explicit XLTable(XLXmlData* xmlData); + + /** + * @brief The destructor. + */ ~XLTable(); + /** + * @brief + * @return the name of the table + */ const std::string name() const; + + /** + * @brief + * @return the reference cells of the table (without the worksheet) + */ const std::string ref() const; + + /** + * @brief + * @return A vector containing the columns names + */ std::vector columnNames() const; + + /** + * @brief + * @param name the name of the requested column index + * @return The index of the column + */ uint16_t columnIndex(const std::string& name) const; + + /** + * @brief + * @return A pointer to the worksheet object the table belong to + */ XLWorksheet* getWorksheet(); + + /** + * @brief + * @return an XLCellRange object of the whole table + * including header and total row if visibles + */ XLCellRange tableRange(); - XLTableRows tableRows(); + + /** + * @brief + * @return an XLCellRange object of data body range of the table + * exclude header and total row + */ XLCellRange dataBodyRange(); + + /** + * @brief + * @return an XLTableRows iterable object (only data body range) + */ + XLTableRows tableRows(); + /** + * @brief + * @return true if header is visible + */ bool isHeaderVisible() const; - bool isTotalVisible() const; - - uint16_t columnCount() const; + /** + * @brief + * @return true if total row is visible + */ + bool isTotalVisible() const; + + /** + * @brief + * @return number of columns + */ + uint16_t columnsCount() const; + + /** + * @brief + * @return number of data rows, excluding header and total row + */ + uint32_t rowsCount() const; + + /** + * @brief set the name of the table + * @param tableName name of the table + */ void setName(const std::string& tableName); private: diff --git a/OpenXLSX/headers/XLTableColumn.hpp b/OpenXLSX/headers/XLTableColumn.hpp index df0016ec..919beaef 100644 --- a/OpenXLSX/headers/XLTableColumn.hpp +++ b/OpenXLSX/headers/XLTableColumn.hpp @@ -15,7 +15,7 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. MM _MM_ - Copyright (c) 2018, Kenneth Troldal Balslev + Written by Akira SHIMAHARA All rights reserved. @@ -65,7 +65,7 @@ namespace OpenXLSX public: /** * @brief The constructor. - * @param xmlData from the table file + * @param dataNode XMLNode of the column */ XLTableColumn(const XMLNode& dataNode); @@ -73,7 +73,16 @@ namespace OpenXLSX //XLTableColumn& operator=(const XLTableColumn&) = delete; ~XLTableColumn(); + /** + * @brief + * @return the column name + */ std::string name() const; + + /** + * @brief + * @param name set the column name + */ void setName(const std::string& name) const; private: diff --git a/OpenXLSX/headers/XLTableRows.hpp b/OpenXLSX/headers/XLTableRows.hpp index 8ec57d72..36e6c16d 100644 --- a/OpenXLSX/headers/XLTableRows.hpp +++ b/OpenXLSX/headers/XLTableRows.hpp @@ -15,7 +15,7 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. MM _MM_ - Copyright (c) 2018, Kenneth Troldal Balslev + Written by Akira SHIMAHARA All rights reserved. @@ -166,7 +166,8 @@ namespace OpenXLSX //---------------------------------------------------------------------------------------------------------------------- /** - * @brief Class XLTableRows derived from XLRowRange. This an iterable object within the databodyrange + * @brief Class XLTableRows derived from XLRowRange. + * This an iterable object within the databodyrange */ class OPENXLSX_EXPORT XLTableRows : public XLRowRange { diff --git a/OpenXLSX/headers/XLTemplates.hpp b/OpenXLSX/headers/XLTemplates.hpp index 502c3b94..be7a015c 100644 --- a/OpenXLSX/headers/XLTemplates.hpp +++ b/OpenXLSX/headers/XLTemplates.hpp @@ -1,5 +1,5 @@ // -// Created by Akira215 on 28/12/2022. +// Created by Written by Akira SHIMAHARA on 28/12/2022. // #ifndef OPENXLSX_XLTEMPLATES_HPP diff --git a/OpenXLSX/headers/XLWorkbook.hpp b/OpenXLSX/headers/XLWorkbook.hpp index 9ad4e28d..7043a698 100644 --- a/OpenXLSX/headers/XLWorkbook.hpp +++ b/OpenXLSX/headers/XLWorkbook.hpp @@ -155,7 +155,11 @@ namespace OpenXLSX */ XLSheet sheet(const std::string& sheetName); - // ASH + /** + * @brief Get the table with the given name. + * @param tableName The name at which the desired sheet is located. + * @return The table. + */ XLTable table(const std::string& tableName); /** @@ -190,9 +194,10 @@ namespace OpenXLSX /** * @brief - * @param definedName + * @param sheetName + * @return the created worksheet */ - void addWorksheet(const std::string& sheetName); + XLWorksheet addWorksheet(const std::string& sheetName); /** * @brief @@ -207,19 +212,20 @@ namespace OpenXLSX * @param rangeName Name of the range to be created * @param reference Reference of the cell/range to be named: Sheet1!$I$17:$I$19 * @param localSheetId Id of the sheet where the name is defined, default is 0 (global) + * @return the created namedRange */ - void addNamedRange(const std::string& rangeName, + XLNamedRange addNamedRange(const std::string& rangeName, const std::string& reference, uint32_t localSheetId = 0); /** * @brief - * @param wks worksheet which will hold the new table + * @param sheetName worksheet which will hold the new table * @param tableName Name of the range to be created * @param reference Reference of the cell/range to be named: $I$17:$I$19 - * @param localSheetId Id of the sheet where the name is defined, default is 0 (global) + * @return the created table */ - void addTable(const std::string& sheetName, const std::string& tableName, + XLTable addTable(const std::string& sheetName, const std::string& tableName, const std::string& reference); /** diff --git a/OpenXLSX/sources/XLCellValue.cpp b/OpenXLSX/sources/XLCellValue.cpp index 485f5fb7..ac4b3041 100644 --- a/OpenXLSX/sources/XLCellValue.cpp +++ b/OpenXLSX/sources/XLCellValue.cpp @@ -424,11 +424,13 @@ void XLCellValueProxy::setString(const char* stringValue) // m_cellNode->attribute("xml:space").set_value("preserve"); // } } + XLSharedStrings* XLCellValueProxy::getSharedString() const { XLQuery query(XLQueryType::QuerySharedStrings); return m_cell->m_worksheet->parentDoc().execQuery(query).template result(); } + /** * @details Get a copy of the XLCellValue object for the cell. This is private helper function for returning an * XLCellValue object corresponding to the cell value. diff --git a/OpenXLSX/sources/XLDocument.cpp b/OpenXLSX/sources/XLDocument.cpp index 4a576dcf..a4c0aacd 100644 --- a/OpenXLSX/sources/XLDocument.cpp +++ b/OpenXLSX/sources/XLDocument.cpp @@ -888,7 +888,7 @@ void XLDocument::createTable(const std::string& sheetName, const std::string& ta // set autofilter tableNode.child("autoFilter").attribute("ref").set_value(ref.c_str()); - // Set up the columns !!! + // Set up the columns - create a temporary worksheet to access the shared string const XLWorksheet* pWks = new XLWorksheet(wks); auto topRight = XLCellReference(topLeft.row(),bottomRight.column()); auto headerRange = XLCellRange(wks->getXmlDocument()->first_child().child("sheetData"), @@ -914,8 +914,7 @@ void XLDocument::createTable(const std::string& sheetName, const std::string& ta } colNames.push_back(colName); cell.value() = colName; - // Fill shared string - // Fill cell value ! + auto newNode = columnsNode.append_child("tableColumn"); newNode.append_attribute("id").set_value(std::to_string(colId).c_str()); newNode.append_attribute("name").set_value(colName.c_str()); diff --git a/OpenXLSX/sources/XLNamedRange.cpp b/OpenXLSX/sources/XLNamedRange.cpp index 594eb5cf..a85ca3bd 100644 --- a/OpenXLSX/sources/XLNamedRange.cpp +++ b/OpenXLSX/sources/XLNamedRange.cpp @@ -15,7 +15,7 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. MM _MM_ - Copyright (c) 2018, Kenneth Troldal Balslev + Written by Akira SHIMAHARA All rights reserved. @@ -44,21 +44,11 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. */ // ===== External Includes ===== // -#include -#include -#include -#include #include #include -#include // ===== OpenXLSX Includes ===== // -/* -#include "XLDocument.hpp" -#include "XLWorkbook.hpp" -*/ #include "XLNamedRange.hpp" -//#include "XLCell.hpp" using namespace OpenXLSX; @@ -128,8 +118,3 @@ XLCell XLNamedRange::firstCell() const { return (*begin()); } - -XLCell XLNamedRange::lastCell() const -{ - return (*end()); -} diff --git a/OpenXLSX/sources/XLRowData.cpp b/OpenXLSX/sources/XLRowData.cpp index ae260f95..731f5c93 100644 --- a/OpenXLSX/sources/XLRowData.cpp +++ b/OpenXLSX/sources/XLRowData.cpp @@ -478,19 +478,6 @@ namespace OpenXLSX return result; } - /** - * @details The function returns a pointer to an XLSharedStrings object embedded in the m_row member. - * This is required because the XLRow class internals is not visible in the header file. - * @pre - * @post - */ - /* - XLSharedStrings XLRowDataProxy::getSharedStrings() const - { - //return m_row->m_sharedStrings; - return XLSharedStrings::instance(); - } - */ /** * @details The deleteCellValues is a convenience function used solely by the templated operator= function. diff --git a/OpenXLSX/sources/XLSharedStrings.cpp b/OpenXLSX/sources/XLSharedStrings.cpp index 3c6a0776..583f4e20 100644 --- a/OpenXLSX/sources/XLSharedStrings.cpp +++ b/OpenXLSX/sources/XLSharedStrings.cpp @@ -54,8 +54,10 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. using namespace OpenXLSX; /** - * @details Constructs a new XLSharedStrings object. Only one (common) object is allowed per XLDocument instance. - * A filepath to the underlying XML file must be provided. + * @details Constructs a new XLSharedStrings object. + * Only one (common) object is allowed per XLDocument instance. (stored in XLDocument) + * It shall be retrieve via worksheet -> Document query process + * A filepath to the underlying XML file must be provided. */ XLSharedStrings::XLSharedStrings(XLXmlData* xmlData) : XLXmlFile(xmlData) diff --git a/OpenXLSX/sources/XLTable.cpp b/OpenXLSX/sources/XLTable.cpp index 4286dec9..87d8e6d6 100644 --- a/OpenXLSX/sources/XLTable.cpp +++ b/OpenXLSX/sources/XLTable.cpp @@ -15,7 +15,7 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. MM _MM_ - Copyright (c) 2018, Kenneth Troldal Balslev + Written by Akira SHIMAHARA All rights reserved. @@ -69,13 +69,6 @@ XLTable::XLTable(XLXmlData* xmlData) for (const XMLNode& col : pTblColumns.children()) m_columns.emplace_back(std::shared_ptr(new XLTableColumn(col))); - /* - XMLDocument* pTableDoc = xmlData->getXmlDocument(); - m_name = pTableDoc->child("table").attribute("name").value(); - */ -//for (const auto& node : getXmlData("xl/sharedStrings.xml")->getXmlDocument()->document_element().children() - -// } XLTable::~XLTable() @@ -83,6 +76,7 @@ XLTable::~XLTable() const std::string XLTable::name() const { + // Check if displayName is better return (m_pXmlData->getXmlDocument()->child("table").attribute("name").value()); } @@ -177,12 +171,30 @@ bool XLTable::isTotalVisible() const -uint16_t XLTable::columnCount() const +uint16_t XLTable::columnsCount() const { return (std::stoi(m_pXmlData->getXmlDocument()->child("table") .child("tableColumns").attribute("count").value())); } +uint32_t XLTable::rowsCount() const +{ + std::pair p = XLCellRange::topLeftBottomRight(ref()); + XLCellReference topLeft(p.first); + XLCellReference bottomRight(p.second); + + uint32_t firstRow = topLeft.row(); + uint32_t lastRow = bottomRight.row(); + + if (isHeaderVisible()) + firstRow +=1; + + if (isTotalVisible()) + lastRow -=1; + + return (lastRow - firstRow + 1); +} + void XLTable::setName(const std::string& tableName) { @@ -196,11 +208,3 @@ void XLTable::setName(const std::string& tableName) } -/*XLCellRange XLWorksheet::range(const XLCellReference& topLeft, const XLCellReference& bottomRight) const -{ - return XLCellRange(xmlDocument().first_child().child("sheetData"), - topLeft, - bottomRight, - parentDoc().execQuery(XLQuery(XLQueryType::QuerySharedStrings)).result()); -} -*/ \ No newline at end of file diff --git a/OpenXLSX/sources/XLTableColumn.cpp b/OpenXLSX/sources/XLTableColumn.cpp index eb58df27..4b07bd9b 100644 --- a/OpenXLSX/sources/XLTableColumn.cpp +++ b/OpenXLSX/sources/XLTableColumn.cpp @@ -15,7 +15,7 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. MM _MM_ - Copyright (c) 2018, Kenneth Troldal Balslev + Written by Akira SHIMAHARA All rights reserved. @@ -57,7 +57,7 @@ using namespace OpenXLSX; XLTableColumn::XLTableColumn(const XMLNode& dataNode): m_dataNode(std::make_unique(dataNode)) { - /* + /* TODO implement the followings m_name = m_dataNode->attribute("name").value(); m_xr3uid = m_dataNode->attribute("xr3:uid").value(); m_dataCellStyle = m_dataNode->attribute("dataCellStyle").value(); diff --git a/OpenXLSX/sources/XLTableRows.cpp b/OpenXLSX/sources/XLTableRows.cpp index a992fe49..8483401a 100644 --- a/OpenXLSX/sources/XLTableRows.cpp +++ b/OpenXLSX/sources/XLTableRows.cpp @@ -15,7 +15,7 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. MM _MM_ - Copyright (c) 2018, Kenneth Troldal Balslev + Written by Akira SHIMAHARA All rights reserved. diff --git a/OpenXLSX/sources/XLWorkbook.cpp b/OpenXLSX/sources/XLWorkbook.cpp index e1c167f5..f8111ce3 100644 --- a/OpenXLSX/sources/XLWorkbook.cpp +++ b/OpenXLSX/sources/XLWorkbook.cpp @@ -122,7 +122,6 @@ XLTable XLWorkbook::table(const std::string& tableName) xmlQuery.setParam("tableName", tableName); XLXmlData* tableItem = (parentDoc().execQuery(xmlQuery).result()); - //XLTable test = XLTable(tableItem); return XLTable(tableItem); } @@ -169,17 +168,6 @@ XLChartsheet XLWorkbook::chartsheet(const std::string& sheetName) } -/** - * @details - */ -/* -XLSharedStrings& XLWorkbook::sharedStrings() -{ - //XLQuery query(XLQueryType::QuerySharedStrings); - //return parentDoc().execQuery(query).result(); - return XLSharedStrings::instance(); -} -*/ /** * @details */ @@ -224,19 +212,17 @@ void XLWorkbook::deleteSheet(const std::string& sheetName) /** * @details */ -void XLWorkbook::addWorksheet(const std::string& sheetName) +XLWorksheet XLWorkbook::addWorksheet(const std::string& sheetName) { // ===== If a sheet with the given name already exists, throw an exception. if (xmlDocument().document_element().child("sheets").find_child_by_attribute("name", sheetName.c_str())) throw XLInputError("Sheet named \"" + sheetName + "\" already exists."); - // ===== Create new internal (workbook) ID for the sheet - //auto internalID = createInternalSheetID(); - // ===== Create xml file for new worksheet and add metadata to the workbook file. parentDoc().execCommand(XLCommand(XLCommandType::AddWorksheet) .setParam("sheetName", sheetName)); + return worksheet(sheetName); } void XLWorkbook::deleteNamedRange(const std::string& rangeName, @@ -258,7 +244,7 @@ void XLWorkbook::deleteNamedRange(const std::string& rangeName, * @details * @todo check that the name fit excel limitation (no space) XLNamedRange INCREMENT_STRING */ -void XLWorkbook::addNamedRange(const std::string& rangeName, +XLNamedRange XLWorkbook::addNamedRange(const std::string& rangeName, const std::string& reference, uint32_t localSheetId) { @@ -309,13 +295,15 @@ void XLWorkbook::addNamedRange(const std::string& rangeName, node.append_attribute("localSheetId") = localSheetId - 1; node.text().set(safeReference.c_str()); + + return namedRange(rangeName); } /** * @details ref shall be "B1:K12" * @todo check that the name fit excel limitation (no space) */ -void XLWorkbook::addTable(const std::string& sheetName, const std::string& tableName, +XLTable XLWorkbook::addTable(const std::string& sheetName, const std::string& tableName, const std::string& reference) { // ===== Create xml file for new worksheet and add metadata to the workbook file. @@ -323,7 +311,7 @@ void XLWorkbook::addTable(const std::string& sheetName, const std::string& table .setParam("worksheet", sheetName) .setParam("tableName", tableName) .setParam("reference", reference)); - + return table(tableName); } From e635f0fa5ee2788966e74cb510fd18b081f65dbe Mon Sep 17 00:00:00 2001 From: akira215 Date: Sat, 31 Dec 2022 15:45:56 +0100 Subject: [PATCH 15/45] Update readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 11f0ad45..ff05f3ce 100644 --- a/README.md +++ b/README.md @@ -189,6 +189,8 @@ which have been implemented and should be working properly: - Copy worksheets - Cell ranges and iterators - Row ranges and iterators +- Name range +- Basis of table support (work in progress) Features related to formatting, plots and figures have not been implemented, and are not planned to be in the near future. From 962ffe6225c4249a4ba2e9f9152a4f0547c6789c Mon Sep 17 00:00:00 2001 From: akira215 Date: Sat, 31 Dec 2022 15:46:45 +0100 Subject: [PATCH 16/45] Correction on readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ff05f3ce..4c36b003 100644 --- a/README.md +++ b/README.md @@ -189,7 +189,7 @@ which have been implemented and should be working properly: - Copy worksheets - Cell ranges and iterators - Row ranges and iterators -- Name range +- Named range - Basis of table support (work in progress) Features related to formatting, plots and figures have not been From 162d36e62a08094573cb3e29b7c3f80d920caef7 Mon Sep 17 00:00:00 2001 From: akira215 Date: Sat, 31 Dec 2022 18:29:16 +0100 Subject: [PATCH 17/45] Correcting XLTableRowIterator End --- OpenXLSX/CMakeLists.txt | 1 + OpenXLSX/headers/XLAutofilter.hpp | 112 +++++++++++++++++++++++++ OpenXLSX/headers/XLCellRange.hpp | 20 +++++ OpenXLSX/headers/XLCellReference.hpp | 9 +- OpenXLSX/headers/XLTable.hpp | 20 +++++ OpenXLSX/headers/XLTableRows.hpp | 2 + OpenXLSX/sources/XLAutofilter.cpp | 119 +++++++++++++++++++++++++++ OpenXLSX/sources/XLCellRange.cpp | 32 ++++++- OpenXLSX/sources/XLCellReference.cpp | 6 ++ OpenXLSX/sources/XLTable.cpp | 46 ++++++++++- OpenXLSX/sources/XLTableRows.cpp | 14 +++- 11 files changed, 373 insertions(+), 8 deletions(-) create mode 100644 OpenXLSX/headers/XLAutofilter.hpp create mode 100644 OpenXLSX/sources/XLAutofilter.cpp diff --git a/OpenXLSX/CMakeLists.txt b/OpenXLSX/CMakeLists.txt index 04a4860f..12ad4d11 100644 --- a/OpenXLSX/CMakeLists.txt +++ b/OpenXLSX/CMakeLists.txt @@ -82,6 +82,7 @@ endif () # List of project source files #======================================================================================================================= set(OPENXLSX_SOURCES + ${CMAKE_CURRENT_LIST_DIR}/sources/XLAutofilter.cpp ${CMAKE_CURRENT_LIST_DIR}/sources/XLCell.cpp ${CMAKE_CURRENT_LIST_DIR}/sources/XLCellIterator.cpp ${CMAKE_CURRENT_LIST_DIR}/sources/XLCellRange.cpp diff --git a/OpenXLSX/headers/XLAutofilter.hpp b/OpenXLSX/headers/XLAutofilter.hpp new file mode 100644 index 00000000..efbdfd06 --- /dev/null +++ b/OpenXLSX/headers/XLAutofilter.hpp @@ -0,0 +1,112 @@ +/* + + ____ ____ ___ ____ ____ ____ ___ + 6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M' + 8P Y8 `MM. d' MM 6M' ` `MM. d' +6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d' +MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d' +MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd +MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM. +MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM. +YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. + 8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM. + YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_ + MM + MM + _MM_ + + Written by Akira SHIMAHARA + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + - Neither the name of the author nor the + names of any contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ + +#ifndef OPENXLSX_XLAUTOFILTER_HPP +#define OPENXLSX_XLAUTOFILTER_HPP + +#pragma warning(push) +//#pragma warning(disable : 4251) +//#pragma warning(disable : 4275) + +// ===== External Includes ===== // +#include +#include + +// ===== OpenXLSX Includes ===== // +#include "OpenXLSX-Exports.hpp" +#include "XLXmlParser.hpp" + +namespace OpenXLSX +{ + // ========== Forward declaration ============ + class XLXmlData; + + + class OPENXLSX_EXPORT XLAutofilter + { + public: + /** + * @brief The constructor. + * @param dataNode XMLNode of the column + */ + XLAutofilter(const XMLNode& dataNode, XLXmlData* parent); + + //XLTableColumn(const XLTableColumn&) = delete; + //XLTableColumn& operator=(const XLTableColumn&) = delete; + ~XLAutofilter(); + + /** + * @brief + * @return the ref on which the filter apply + */ + std::string ref() const; + + /** + * @brief + * @param name set ref to be applied + */ + void setRef(const std::string& ref) const; + + /** + * @brief + * @param indexCol col index to be hidden (first index is 0) + * @param hide true by default + */ + void hideArrow(uint16_t indexCol, bool hide = true) const; + + /** + * @brief + * @param hide true by default + */ + void hideArrows(bool hide = true) const; + + private: + std::unique_ptr m_dataNode; + XLXmlData* m_parent; + }; +} // namespace OpenXLSX + +//#pragma warning(pop) +#endif // OPENXLSX_XLAUTOFILTER_HPP diff --git a/OpenXLSX/headers/XLCellRange.hpp b/OpenXLSX/headers/XLCellRange.hpp index a4182c63..6e4493fd 100644 --- a/OpenXLSX/headers/XLCellRange.hpp +++ b/OpenXLSX/headers/XLCellRange.hpp @@ -185,6 +185,12 @@ namespace OpenXLSX */ void clear(); + /** + * @brief get the coordinates of the top left and bottom right + * @return A pair of ref + */ + std::pair rangeCoordinates(); + /** * @brief Static helper function to get top left and bottom right * @param ref a ref i.e. A1:C20 @@ -192,6 +198,20 @@ namespace OpenXLSX */ static std::pair topLeftBottomRight(const std::string& ref); + /** + * @brief Static helper function to get the num of row of a range + * @param ref a ref i.e. A1:C20 + * @return the num of columns + */ + static uint16_t columnsCount(const std::string& ref); + + /** + * @brief Static helper function to get the num of row of a range + * @param ref a ref i.e. A1:C20 + * @return the num of columns + */ + static uint32_t rowsCount(const std::string& ref); + //---------------------------------------------------------------------------------------------------------------------- // Private Member Variables //---------------------------------------------------------------------------------------------------------------------- diff --git a/OpenXLSX/headers/XLCellReference.hpp b/OpenXLSX/headers/XLCellReference.hpp index 285b09f6..4f4a0261 100644 --- a/OpenXLSX/headers/XLCellReference.hpp +++ b/OpenXLSX/headers/XLCellReference.hpp @@ -81,6 +81,7 @@ namespace OpenXLSX //---------------------------------------------------------------------------------------------------------------------- public: + /** * @brief Constructor taking a cell address as argument. * @param cellAddress The address of the cell, e.g. 'A1'. @@ -196,6 +197,12 @@ namespace OpenXLSX * @param column The column number. */ void setRowAndColumn(uint32_t row, uint16_t column); + + /** + * @brief . + * @return the coordinates of the cellref. + */ + XLCoordinates coordinates(); /** * @brief Get the address of the XLCellReference @@ -211,7 +218,7 @@ namespace OpenXLSX void setAddress(const std::string& address); //---------------------------------------------------------------------------------------------------------------------- - // Private Member Functions + // Static Helpers Functions //---------------------------------------------------------------------------------------------------------------------- // private: diff --git a/OpenXLSX/headers/XLTable.hpp b/OpenXLSX/headers/XLTable.hpp index 60dec840..eb33ac7e 100644 --- a/OpenXLSX/headers/XLTable.hpp +++ b/OpenXLSX/headers/XLTable.hpp @@ -55,6 +55,7 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. #include // ===== OpenXLSX Includes ===== // #include "OpenXLSX-Exports.hpp" +#include "XLAutofilter.hpp" #include "XLXmlData.hpp" #include "XLTableColumn.hpp" #include "XLTableRows.hpp" @@ -133,6 +134,7 @@ namespace OpenXLSX * @return true if header is visible */ bool isHeaderVisible() const; + /** * @brief @@ -140,6 +142,24 @@ namespace OpenXLSX */ bool isTotalVisible() const; + /** + * @brief + * @param visible + */ + void setHeaderVisible(bool visible = true); + + /** + * @brief + * @param visible + */ + void setTotalVisible(bool visible = true); + + /** + * @brief + * @return the autofilter object + */ + XLAutofilter autofilter(); + /** * @brief * @return number of columns diff --git a/OpenXLSX/headers/XLTableRows.hpp b/OpenXLSX/headers/XLTableRows.hpp index 36e6c16d..4bb40d39 100644 --- a/OpenXLSX/headers/XLTableRows.hpp +++ b/OpenXLSX/headers/XLTableRows.hpp @@ -158,6 +158,8 @@ namespace OpenXLSX private: XLCellRange m_range; /**< The cell range reference of the first cell in the range */ + uint32_t m_firstIterRow; + uint32_t m_lastIterRow; /**< */ }; diff --git a/OpenXLSX/sources/XLAutofilter.cpp b/OpenXLSX/sources/XLAutofilter.cpp new file mode 100644 index 00000000..4bf54084 --- /dev/null +++ b/OpenXLSX/sources/XLAutofilter.cpp @@ -0,0 +1,119 @@ +/* + + ____ ____ ___ ____ ____ ____ ___ + 6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M' + 8P Y8 `MM. d' MM 6M' ` `MM. d' +6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d' +MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d' +MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd +MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM. +MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM. +YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. + 8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM. + YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_ + MM + MM + _MM_ + + Written by Akira SHIMAHARA + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + - Neither the name of the author nor the + names of any contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ + +// ===== External Includes ===== // +#include +#include +#include + +// ===== OpenXLSX Includes ===== // +#include "XLAutofilter.hpp" +#include "XLCellRange.hpp" +#include "XLXmlData.hpp" + + + +using namespace OpenXLSX; + + + XLAutofilter:: XLAutofilter(const XMLNode& dataNode, XLXmlData* parent): + m_dataNode(std::make_unique(dataNode)), + m_parent(parent) +{ +} +// TODO check if Autofilter is valid +XLAutofilter::~XLAutofilter() = default; + +std::string XLAutofilter::ref() const +{ + return std::string(m_dataNode->attribute("ref").value()); +} + + +void XLAutofilter::setRef(const std::string& ref) const +{ + auto node = m_dataNode->attribute("ref"); + if(!node) + node = m_dataNode->append_attribute("ref"); + + node.set_value(ref.c_str()); +} + +void XLAutofilter::hideArrow(uint16_t indexCol, bool hide) const +{ + auto node = m_dataNode->find_child_by_attribute("colId", std::to_string(indexCol).c_str()); + if (!node){ + node = m_dataNode->append_child("filterColumn"); + node.append_attribute("colId") + .set_value(std::to_string(indexCol).c_str()); + } + if(!node.attribute("hiddenButton")) + node.append_attribute("hiddenButton"); + + if(hide) + node.attribute("hiddenButton").set_value("1"); + else + node.attribute("hiddenButton").set_value("0"); +} + +void XLAutofilter::hideArrows(bool hide) const +{ + uint16_t nCol = XLCellRange::columnsCount(ref()); + for (uint16_t i = 0; i < nCol;i++) + hideArrow(i,hide); +} +/* +std::string XLTableColumn::name() const +{ + return (m_dataNode->attribute("name").value()); +} + +void XLTableColumn::setName(const std::string& columnName) const +{ + m_dataNode->attribute("name").set_value(columnName.c_str()); + // TODO change the formulas in table.xml + // TODO change the formulas in the sheet +} +*/ diff --git a/OpenXLSX/sources/XLCellRange.cpp b/OpenXLSX/sources/XLCellRange.cpp index a14b54ee..32b61753 100644 --- a/OpenXLSX/sources/XLCellRange.cpp +++ b/OpenXLSX/sources/XLCellRange.cpp @@ -129,7 +129,7 @@ XLCellRange& XLCellRange::operator=(XLCellRange&& other) noexcept *m_dataNode = *other.m_dataNode; m_topLeft = other.m_topLeft; m_bottomRight = other.m_bottomRight; - m_worksheet = other.m_worksheet; + m_worksheet = other.m_worksheet; } return *this; @@ -230,6 +230,11 @@ void XLCellRange::clear() for(auto& cell: *this) cell.value().clear(); } +std::pair XLCellRange::rangeCoordinates() +{ + return std::make_pair(m_topLeft.coordinates(),m_bottomRight.coordinates()); +} + std::pair XLCellRange::topLeftBottomRight(const std::string& ref) { std::string::size_type n = ref.find(':'); @@ -239,3 +244,28 @@ std::pair XLCellRange::topLeftBottomRight(const std::st return std::make_pair(ref.substr(0, n),ref.substr(n+1)); } + +uint16_t XLCellRange::columnsCount(const std::string& ref) +{ + std::string::size_type n = ref.find(':'); + if(n>ref.size()) // there is no : separator + return 1; + + XLCoordinates topleft = XLCellReference::coordinatesFromAddress(ref.substr(0,n)); + XLCoordinates bottomright = XLCellReference::coordinatesFromAddress(ref.substr(n+1)); + + return bottomright.second - topleft.second + 1; +} + +uint32_t XLCellRange::rowsCount(const std::string& ref) +{ + std::string::size_type n = ref.find(':'); + if(n>ref.size()) // there is no : separator + return 1; + + XLCoordinates topleft = XLCellReference::coordinatesFromAddress(ref.substr(0,n)); + XLCoordinates bottomright = XLCellReference::coordinatesFromAddress(ref.substr(n+1)); + + return bottomright.first - topleft.first + 1; + +} \ No newline at end of file diff --git a/OpenXLSX/sources/XLCellReference.cpp b/OpenXLSX/sources/XLCellReference.cpp index 505853b1..10996fd5 100644 --- a/OpenXLSX/sources/XLCellReference.cpp +++ b/OpenXLSX/sources/XLCellReference.cpp @@ -47,6 +47,7 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. #include #include #include +#include #ifdef CHARCONV_ENABLED # include #endif @@ -258,6 +259,11 @@ void XLCellReference::setRowAndColumn(uint32_t row, uint16_t column) m_cellAddress = columnAsString(m_column) + rowAsString(m_row); } + XLCoordinates XLCellReference::coordinates() + { + return std::make_pair(m_row,m_column); + } + /** * @details Returns the m_cellAddress property. */ diff --git a/OpenXLSX/sources/XLTable.cpp b/OpenXLSX/sources/XLTable.cpp index 87d8e6d6..5012d99e 100644 --- a/OpenXLSX/sources/XLTable.cpp +++ b/OpenXLSX/sources/XLTable.cpp @@ -153,6 +153,8 @@ XLCellRange XLTable::dataBodyRange() return getWorksheet()->range(topLeft,bottomRight); } + + bool XLTable::isHeaderVisible() const { std::string header = m_pXmlData->getXmlDocument()->child("table").attribute("headerRowCount").value(); @@ -163,13 +165,53 @@ bool XLTable::isHeaderVisible() const bool XLTable::isTotalVisible() const { - std::string header = m_pXmlData->getXmlDocument()->child("table").attribute("totalsRowCount").value(); - if (header == "1") + std::string total = m_pXmlData->getXmlDocument()->child("table").attribute("totalsRowCount").value(); + if (total == "1") return true; return false; // if missing, not visible } +void XLTable::setHeaderVisible(bool visible) +{ + if(visible){ // removing the attribute if visible + m_pXmlData->getXmlDocument()->child("table").remove_attribute("headerRowCount"); + } else { + auto node = m_pXmlData->getXmlDocument()->child("table").attribute("headerRowCount"); + if (!node) + node = m_pXmlData->getXmlDocument()->child("table").append_attribute("headerRowCount"); + node.set_value("0"); + // TODO remove autofilter + } +} + + +void XLTable::setTotalVisible(bool visible) +{ + if(visible){ + m_pXmlData->getXmlDocument()->child("table").remove_attribute("totalsRowShown"); + + auto node = m_pXmlData->getXmlDocument()->child("table").attribute("totalsRowCount"); + if (!node) + node = m_pXmlData->getXmlDocument()->child("table").append_attribute("totalsRowCount"); + node.set_value("1"); + } else { // removing the attribute if not visible + m_pXmlData->getXmlDocument()->child("table").remove_attribute("totalsRowCount"); + auto node = m_pXmlData->getXmlDocument()->child("table").attribute("totalsRowShown"); + if (!node) + node = m_pXmlData->getXmlDocument()->child("table").append_attribute("totalsRowShown"); + node.set_value("0"); + + } + +} + +XLAutofilter XLTable::autofilter() +{ + return XLAutofilter(m_pXmlData->getXmlDocument()->child("table").child("autoFilter"),m_pXmlData); +} + + uint16_t XLTable::columnsCount() const { diff --git a/OpenXLSX/sources/XLTableRows.cpp b/OpenXLSX/sources/XLTableRows.cpp index 8483401a..ba812a12 100644 --- a/OpenXLSX/sources/XLTableRows.cpp +++ b/OpenXLSX/sources/XLTableRows.cpp @@ -62,12 +62,14 @@ using namespace OpenXLSX; m_range (XLCellRange( *tableRows.m_dataNode, XLCellReference (tableRows.m_firstRow, tableRows.m_firstCol), XLCellReference (tableRows.m_firstRow, tableRows.m_lastCol), - tableRows.m_worksheet)) + tableRows.m_worksheet)), + m_firstIterRow(tableRows.m_firstRow), + m_lastIterRow(tableRows.m_lastRow) { if (loc == XLIteratorLocation::End) m_range = XLCellRange( *tableRows.m_dataNode, - XLCellReference (tableRows.m_lastRow, tableRows.m_firstCol), - XLCellReference (tableRows.m_lastRow, tableRows.m_lastCol), + XLCellReference (tableRows.m_lastRow+1, tableRows.m_firstCol), + XLCellReference (tableRows.m_lastRow+1, tableRows.m_lastCol), tableRows.m_worksheet); } @@ -95,7 +97,11 @@ XLTableRowIterator& XLTableRowIterator::operator=(XLTableRowIterator&& other) no XLTableRowIterator& XLTableRowIterator::operator++() { - m_range.offset(1); + m_range.offset(1);/* + if(m_range.rangeCoordinates().first.first > m_lastIterRow) + m_range = XLCellRange(); + */ + return *this; } From ea5863f275626188c941a5f55fb2dc8bd76c5a2f Mon Sep 17 00:00:00 2001 From: akira215 Date: Sun, 1 Jan 2023 00:25:28 +0100 Subject: [PATCH 18/45] Adding table total feature --- Examples/Demo10.cpp | 7 + OpenXLSX/headers/XLCellRange.hpp | 11 +- OpenXLSX/headers/XLCellReference.hpp | 6 + OpenXLSX/headers/XLTable.hpp | 339 +++++++++++++++------------ OpenXLSX/headers/XLTableColumn.hpp | 151 +++++++----- OpenXLSX/headers/XLTemplates.hpp | 7 + OpenXLSX/sources/XLCellRange.cpp | 13 +- OpenXLSX/sources/XLCellReference.cpp | 14 +- OpenXLSX/sources/XLRow.cpp | 1 - OpenXLSX/sources/XLTable.cpp | 222 ++++++++++++------ OpenXLSX/sources/XLTableColumn.cpp | 165 ++++++++----- OpenXLSX/sources/XLTableRows.cpp | 5 +- 12 files changed, 591 insertions(+), 350 deletions(-) diff --git a/Examples/Demo10.cpp b/Examples/Demo10.cpp index 589f5329..db2526be 100644 --- a/Examples/Demo10.cpp +++ b/Examples/Demo10.cpp @@ -72,6 +72,13 @@ int main() { j++; } + // Also show the total with selected function + tbl.autofilter().hideArrows(); + //tbl.setHeaderVisible(false); + tbl.setTotalVisible(true); + //tbl.column("Table")->setTotalsRowFunction("sum"); + tbl.column("Table").setTotalsRowFunction("count"); + doc.save(); doc.close(); diff --git a/OpenXLSX/headers/XLCellRange.hpp b/OpenXLSX/headers/XLCellRange.hpp index 6e4493fd..2308e29f 100644 --- a/OpenXLSX/headers/XLCellRange.hpp +++ b/OpenXLSX/headers/XLCellRange.hpp @@ -172,12 +172,19 @@ namespace OpenXLSX */ XLCellIterator end() const; + /** + * @brief offset the whole range if possible + * @param topLeft XLCoordinates of topleft corner + * @param bottomRight XLCoordinates of bottom right corner + */ + void setRangeCoordinates(const XLCellReference& topLeft, + const XLCellReference& bottomRight); + /** * @brief offset the whole range if possible * @param row integer could be negative * @param col integer could be negative, default 0 */ - void offset(int row, int col = 0); /** @@ -189,7 +196,7 @@ namespace OpenXLSX * @brief get the coordinates of the top left and bottom right * @return A pair of ref */ - std::pair rangeCoordinates(); + std::pair rangeCoordinates(); /** * @brief Static helper function to get top left and bottom right diff --git a/OpenXLSX/headers/XLCellReference.hpp b/OpenXLSX/headers/XLCellReference.hpp index 4f4a0261..1cc2b937 100644 --- a/OpenXLSX/headers/XLCellReference.hpp +++ b/OpenXLSX/headers/XLCellReference.hpp @@ -197,6 +197,12 @@ namespace OpenXLSX * @param column The column number. */ void setRowAndColumn(uint32_t row, uint16_t column); + + /** + * @brief Set the address of the XLCellReference + * @param coord coordinates of the cell to be set(std::pair(row, col). + */ + void setCoordinates(const XLCoordinates& coord); /** * @brief . diff --git a/OpenXLSX/headers/XLTable.hpp b/OpenXLSX/headers/XLTable.hpp index eb33ac7e..c0dc0142 100644 --- a/OpenXLSX/headers/XLTable.hpp +++ b/OpenXLSX/headers/XLTable.hpp @@ -15,33 +15,33 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. MM _MM_ - Written by Akira SHIMAHARA - - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - Neither the name of the author nor the - names of any contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - */ + Written by Akira SHIMAHARA + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + - Neither the name of the author nor the + names of any contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ #ifndef OPENXLSX_XLTABLE_HPP #define OPENXLSX_XLTABLE_HPP @@ -59,135 +59,170 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. #include "XLXmlData.hpp" #include "XLTableColumn.hpp" #include "XLTableRows.hpp" +#include "XLSheet.hpp" namespace OpenXLSX { - class XLSheet; - class OPENXLSX_EXPORT XLTable - { - public: - /** - * @brief The constructor. - * @param xmlData from the table file - */ - explicit XLTable(XLXmlData* xmlData); - - /** - * @brief The destructor. - */ - ~XLTable(); - - /** - * @brief - * @return the name of the table - */ - const std::string name() const; - - /** - * @brief - * @return the reference cells of the table (without the worksheet) - */ - const std::string ref() const; - - /** - * @brief - * @return A vector containing the columns names - */ - std::vector columnNames() const; - - /** - * @brief - * @param name the name of the requested column index - * @return The index of the column - */ - uint16_t columnIndex(const std::string& name) const; - - /** - * @brief - * @return A pointer to the worksheet object the table belong to - */ - XLWorksheet* getWorksheet(); - - /** - * @brief - * @return an XLCellRange object of the whole table - * including header and total row if visibles - */ - XLCellRange tableRange(); - - /** - * @brief - * @return an XLCellRange object of data body range of the table - * exclude header and total row - */ - XLCellRange dataBodyRange(); - - - /** - * @brief - * @return an XLTableRows iterable object (only data body range) - */ - XLTableRows tableRows(); - - - /** - * @brief - * @return true if header is visible - */ - bool isHeaderVisible() const; + class OPENXLSX_EXPORT XLTable + { + friend class XLTableColumn; + + public: + /** + * @brief The constructor. + * @param xmlData from the table file + */ + explicit XLTable(XLXmlData* xmlData); + + /** + * @brief The destructor. + */ + ~XLTable(); + + /** + * @brief + * @return the name of the table + */ + const std::string name() const; + + /** + * @brief + * @return the reference cells of the table (without the worksheet) + */ + const std::string ref() const; + + /** + * @brief + * @return A vector containing the columns names + */ + std::vector columnNames() const; + + /** + * @brief + * @param name the name of the requested column index + * @return The index of the column + */ + uint16_t columnIndex(const std::string& name) const; + + /** + * @brief + * @param name the name of the requested column + * @return a pointer to the TableColumn object + */ + XLTableColumn& column(const std::string& name); + + /** + * @brief + * @return A pointer to the worksheet object the table belong to + */ + XLWorksheet* getWorksheet(); + + /** + * @brief + * @return an XLCellRange object of the whole table + * including header and total row if visibles + */ + XLCellRange tableRange(); + + /** + * @brief + * @return a ref to the XLCellRange object of data body range of the table + * exclude header and total row + */ + const XLCellRange& dataBodyRange() const; + + /** + * @brief + * @return a ref to the XLCellRange object of data body range of the table + * exclude header and total row + */ + XLCellRange& dataBodyRange(); - /** - * @brief - * @return true if total row is visible - */ - bool isTotalVisible() const; - - /** - * @brief - * @param visible - */ - void setHeaderVisible(bool visible = true); - - /** - * @brief - * @param visible - */ - void setTotalVisible(bool visible = true); - - /** - * @brief - * @return the autofilter object - */ - XLAutofilter autofilter(); - - /** - * @brief - * @return number of columns - */ - uint16_t columnsCount() const; - - /** - * @brief - * @return number of data rows, excluding header and total row - */ - uint32_t rowsCount() const; - - /** - * @brief set the name of the table - * @param tableName name of the table - */ - void setName(const std::string& tableName); - - private: - XLXmlData* m_pXmlData; - std::vector> m_columns; - XLWorksheet m_sheet; - // cell range - // sheet - // filter - // sort state - // tablestyle - }; + /** + * @brief + * @return an XLTableRows iterable object (only data body range) + */ + XLTableRows tableRows(); + + + /** + * @brief + * @return true if header is visible + */ + bool isHeaderVisible() const; + + + /** + * @brief + * @return true if total row is visible + */ + bool isTotalVisible() const; + + /** + * @brief + * @param visible + */ + void setHeaderVisible(bool visible = true); + + /** + * @brief + * @param visible + */ + void setTotalVisible(bool visible = true); + + /** + * @brief + * @return the autofilter object + */ + XLAutofilter autofilter(); + + /** + * @brief + * @return number of columns + */ + uint16_t columnsCount() const; + + /** + * @brief + * @return number of data rows, excluding header and total row + */ + uint32_t rowsCount() const; + + /** + * @brief set the name of the table + * @param tableName name of the table + */ + void setName(const std::string& tableName); + //---------------------------------------------------------------------------------------------------------------------- + // Protected + //---------------------------------------------------------------------------------------------------------------------- + protected: + /** + * @brief set the formulas in the worksheet for the total row + * the formulas is based on the attribute totalsRowFunction of each col + */ + void setTotalFormulas(); + + /** + * @brief Adjust the ref according to m_dataBodyRange + * and the state of visibility of headers and total + */ + void adjustRef(); + + //---------------------------------------------------------------------------------------------------------------------- + // Private Member Variables + //---------------------------------------------------------------------------------------------------------------------- + private: + XLXmlData* m_pXmlData; + std::vector m_columns; + XLWorksheet m_sheet; + XLCellRange m_dataBodyRange; // without header and total + // cell range + // sheet + // filter + // sort state + // tablestyle + }; } // namespace OpenXLSX //#pragma warning(pop) diff --git a/OpenXLSX/headers/XLTableColumn.hpp b/OpenXLSX/headers/XLTableColumn.hpp index 919beaef..bb3bb490 100644 --- a/OpenXLSX/headers/XLTableColumn.hpp +++ b/OpenXLSX/headers/XLTableColumn.hpp @@ -15,33 +15,33 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. MM _MM_ - Written by Akira SHIMAHARA - - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - Neither the name of the author nor the - names of any contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - */ + Written by Akira SHIMAHARA + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + - Neither the name of the author nor the + names of any contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ #ifndef OPENXLSX_XLTABLECOLUMN_HPP #define OPENXLSX_XLTABLECOLUMN_HPP @@ -60,34 +60,75 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. namespace OpenXLSX { - class OPENXLSX_EXPORT XLTableColumn - { - public: - /** - * @brief The constructor. - * @param dataNode XMLNode of the column - */ - XLTableColumn(const XMLNode& dataNode); - - //XLTableColumn(const XLTableColumn&) = delete; - //XLTableColumn& operator=(const XLTableColumn&) = delete; - ~XLTableColumn(); - - /** - * @brief - * @return the column name - */ - std::string name() const; - - /** - * @brief - * @param name set the column name - */ - void setName(const std::string& name) const; - - private: - std::unique_ptr m_dataNode; - }; + class XLTable; + + class OPENXLSX_EXPORT XLTableColumn + { + public: + /** + * @brief The constructor. + * @param dataNode XMLNode of the column + */ + XLTableColumn(const XMLNode& dataNode, XLTable* table); + + /** + * @brief Copy Constructor + * @note The copy constructor is explicitly deleted + */ + XLTableColumn(const XLTableColumn& other); + + /** + * @brief Move Constructor + * @note The move constructor has been explicitly deleted. + */ + XLTableColumn(XLTableColumn&& other) noexcept; + + //XLTableColumn(const XLTableColumn&) = delete; + //XLTableColumn& operator=(const XLTableColumn&) = delete; + ~XLTableColumn(); + + /** + * @brief Copy assignment operator. + * @note The copy assignment operator is explicitly deleted. + */ + XLTableColumn& operator=(const XLTableColumn& other); + + /** + * @brief Move assignment operator. + * @note The move assignment operator has been explicitly deleted. + */ + XLTableColumn& operator=(XLTableColumn&& other) noexcept; + + + /** + * @brief + * @return the column name + */ + std::string name() const; + + /** + * @brief + * @param name set the column name + */ + void setName(const std::string& name) const; + + /** + * @brief + * @return function + */ + std::string totalsRowFunction() const; + + /** + * @brief + * @param function function to be set. if function is not know, nothing is done + */ + void setTotalsRowFunction(const std::string& function); + + + private: + std::unique_ptr m_dataNode; + XLTable* m_table; + }; } // namespace OpenXLSX //#pragma warning(pop) diff --git a/OpenXLSX/headers/XLTemplates.hpp b/OpenXLSX/headers/XLTemplates.hpp index be7a015c..c926778f 100644 --- a/OpenXLSX/headers/XLTemplates.hpp +++ b/OpenXLSX/headers/XLTemplates.hpp @@ -52,6 +52,13 @@ namespace OpenXLSX "" }; + const std::string totalsRowFunctionList[] = { + "average", "count", "countNums", "custom", "max", "min", "none", "stdDev", "sum", "var" + }; + // Warning : this shall be in the same order than totalsRowFunctionList + const std::string sheetTotalFunctionList[] = { + "101", "103", "102", "custom", "104", "105", "none", "107", "109", "110" + }; const int templateSize = 7714; const unsigned char templateData[7714] = { 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00, 0x21, 0x00, 0xb5, 0x55, 0x30, 0x23, 0xf4, 0x00, 0x00, 0x00, diff --git a/OpenXLSX/sources/XLCellRange.cpp b/OpenXLSX/sources/XLCellRange.cpp index 32b61753..f8e9f101 100644 --- a/OpenXLSX/sources/XLCellRange.cpp +++ b/OpenXLSX/sources/XLCellRange.cpp @@ -218,8 +218,6 @@ void XLCellRange::offset(int row, int col) m_bottomRight.offset(row, col); } - - /** * @details * @pre @@ -230,9 +228,16 @@ void XLCellRange::clear() for(auto& cell: *this) cell.value().clear(); } -std::pair XLCellRange::rangeCoordinates() +void XLCellRange::setRangeCoordinates(const XLCellReference& topLeft, + const XLCellReference& bottomRight) +{ + m_topLeft = topLeft; + m_bottomRight = bottomRight; +} + +std::pair XLCellRange::rangeCoordinates() { - return std::make_pair(m_topLeft.coordinates(),m_bottomRight.coordinates()); + return std::make_pair(m_topLeft,m_bottomRight); } std::pair XLCellRange::topLeftBottomRight(const std::string& ref) diff --git a/OpenXLSX/sources/XLCellReference.cpp b/OpenXLSX/sources/XLCellReference.cpp index 10996fd5..3c31fab5 100644 --- a/OpenXLSX/sources/XLCellReference.cpp +++ b/OpenXLSX/sources/XLCellReference.cpp @@ -259,10 +259,16 @@ void XLCellReference::setRowAndColumn(uint32_t row, uint16_t column) m_cellAddress = columnAsString(m_column) + rowAsString(m_row); } - XLCoordinates XLCellReference::coordinates() - { - return std::make_pair(m_row,m_column); - } +void XLCellReference::setCoordinates(const XLCoordinates& coord) +{ + setRowAndColumn(coord.first,coord.second); +} + + +XLCoordinates XLCellReference::coordinates() +{ + return std::make_pair(m_row,m_column); +} /** * @details Returns the m_cellAddress property. diff --git a/OpenXLSX/sources/XLRow.cpp b/OpenXLSX/sources/XLRow.cpp index dc5db4f8..a38ee096 100644 --- a/OpenXLSX/sources/XLRow.cpp +++ b/OpenXLSX/sources/XLRow.cpp @@ -131,7 +131,6 @@ namespace OpenXLSX { if (&other != this) { m_rowNode = std::move(other.m_rowNode); - //m_sharedStrings = other.m_sharedStrings; m_rowDataProxy = XLRowDataProxy(this, m_rowNode.get()); } return *this; diff --git a/OpenXLSX/sources/XLTable.cpp b/OpenXLSX/sources/XLTable.cpp index 5012d99e..512fafab 100644 --- a/OpenXLSX/sources/XLTable.cpp +++ b/OpenXLSX/sources/XLTable.cpp @@ -15,33 +15,33 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. MM _MM_ - Written by Akira SHIMAHARA - - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - Neither the name of the author nor the - names of any contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - */ + Written by Akira SHIMAHARA + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + - Neither the name of the author nor the + names of any contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ // ===== External Includes ===== // #include @@ -54,20 +54,35 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. #include "XLTable.hpp" #include "XLCellRange.hpp" #include "XLCellReference.hpp" +#include "XLTemplates.hpp" using namespace OpenXLSX; XLTable::XLTable(XLXmlData* xmlData) - : m_pXmlData(xmlData),m_sheet(XLWorksheet(xmlData->getParentNode())) + : m_pXmlData(xmlData), + m_sheet(XLWorksheet(xmlData->getParentNode())), + m_dataBodyRange(getWorksheet()->range()) // Fake range { - - // ===== Deal with the columns - XMLNode pTblColumns = m_pXmlData->getXmlDocument()->child("table").child("tableColumns"); + std::pair p = XLCellRange::topLeftBottomRight(ref()); + XLCellReference topLeft(p.first); + XLCellReference bottomRight(p.second); - for (const XMLNode& col : pTblColumns.children()) - m_columns.emplace_back(std::shared_ptr(new XLTableColumn(col))); + if (isHeaderVisible()) + topLeft.offset(1); + + if (isTotalVisible()) + bottomRight.offset(-1); + + m_dataBodyRange.setRangeCoordinates(topLeft, bottomRight); + + + // ===== Deal with the columns + XMLNode pTblColumns = m_pXmlData->getXmlDocument()->child("table").child("tableColumns"); + + for (const XMLNode& col : pTblColumns.children()) + m_columns.push_back(XLTableColumn(col, this)); } @@ -87,25 +102,44 @@ const std::string XLTable::ref() const std::vector XLTable:: columnNames() const { - std::vector colNames; - for (auto col : m_columns) - colNames.push_back(col->name()); + std::vector colNames; + for (auto& col : m_columns) + colNames.push_back(col.name()); return colNames; } uint16_t XLTable::columnIndex(const std::string& name) const { - auto it = std::find_if(m_columns.begin(), - m_columns.end(), - [&](const auto& val){ return val->name() == name; } ); - - if (it !=m_columns.end()) - return (it - m_columns.begin()); - - return (uint16_t)(-1); + auto it = std::find_if(m_columns.begin(), + m_columns.end(), + [&](const auto& val){ return val.name() == name; } ); + + if (it !=m_columns.end()) + return (it - m_columns.begin()); + + return (uint16_t)(-1); +} +/* +std::shared_ptr XLTable::column(const std::string& name) +{ + uint16_t index = columnIndex(name); + if (index == (uint16_t)(-1)) + return nullptr; // the column does not exist + + return std::shared_ptr(m_columns[index]); +} +*/ +XLTableColumn& XLTable::column(const std::string& name) +{ + uint16_t index = columnIndex(name); + if (index == (uint16_t)(-1)) + index = 0; + + return m_columns[index]; } + XLWorksheet* XLTable::getWorksheet() { return &m_sheet; @@ -118,41 +152,23 @@ XLCellRange XLTable::tableRange() XLTableRows XLTable::tableRows() { - std::pair p = XLCellRange::topLeftBottomRight(ref()); - XLCellReference topLeft(p.first); - XLCellReference bottomRight(p.second); - - uint32_t firstRow = topLeft.row(); - uint32_t lastRow = bottomRight.row(); - - uint16_t firstCol = topLeft.column(); - uint16_t lastCol = bottomRight.column(); - - if (isHeaderVisible()) - firstRow +=1; - - if (isTotalVisible()) - lastRow -=1; - return XLTableRows(m_pXmlData->getParentNode()->getXmlDocument()->first_child().child("sheetData"), - firstRow, lastRow, firstCol, lastCol, getWorksheet()); + m_dataBodyRange.rangeCoordinates().first.row(), + m_dataBodyRange.rangeCoordinates().second.row(), + m_dataBodyRange.rangeCoordinates().first.column(), + m_dataBodyRange.rangeCoordinates().second.column(), + getWorksheet()); } -XLCellRange XLTable::dataBodyRange() +XLCellRange& XLTable::dataBodyRange() { - std::pair p = XLCellRange::topLeftBottomRight(ref()); - XLCellReference topLeft(p.first); - XLCellReference bottomRight(p.second); - - if (isHeaderVisible()) - topLeft.offset(1); - - if (isTotalVisible()) - bottomRight.offset(-1); - - return getWorksheet()->range(topLeft,bottomRight); + return m_dataBodyRange; } +const XLCellRange& XLTable::dataBodyRange() const +{ + return m_dataBodyRange; +} bool XLTable::isHeaderVisible() const @@ -183,6 +199,7 @@ void XLTable::setHeaderVisible(bool visible) node.set_value("0"); // TODO remove autofilter } + adjustRef(); } @@ -195,14 +212,17 @@ void XLTable::setTotalVisible(bool visible) if (!node) node = m_pXmlData->getXmlDocument()->child("table").append_attribute("totalsRowCount"); node.set_value("1"); + + setTotalFormulas(); } else { // removing the attribute if not visible m_pXmlData->getXmlDocument()->child("table").remove_attribute("totalsRowCount"); auto node = m_pXmlData->getXmlDocument()->child("table").attribute("totalsRowShown"); if (!node) node = m_pXmlData->getXmlDocument()->child("table").append_attribute("totalsRowShown"); node.set_value("0"); - } + + adjustRef(); } @@ -212,7 +232,6 @@ XLAutofilter XLTable::autofilter() } - uint16_t XLTable::columnsCount() const { return (std::stoi(m_pXmlData->getXmlDocument()->child("table") @@ -250,3 +269,56 @@ void XLTable::setName(const std::string& tableName) } +void XLTable::setTotalFormulas() +{ + + if (!isTotalVisible()) + return; + + uint32_t totalRow = m_dataBodyRange.rangeCoordinates().second.row() + 1; + uint16_t totalCol = m_dataBodyRange.rangeCoordinates().first.column(); + + for (auto& col: m_columns){ + std::string colFunc = col.totalsRowFunction(); + + // Check if its exist in the list + auto it = std::find(std::begin(XLTemplate::totalsRowFunctionList), + std::end(XLTemplate::totalsRowFunctionList), colFunc); + if( it != std::end(XLTemplate::totalsRowFunctionList)){ + + + // get the equivalent formula in the sheet + std::string sheetFunction = "SUBTOTAL("; + sheetFunction += XLTemplate::sheetTotalFunctionList[ + std::distance(std::begin(XLTemplate::totalsRowFunctionList), it) + ]; + sheetFunction += "," + name() + + "[" + col.name() + "])"; + + m_sheet.cell(totalRow, totalCol).formula() = sheetFunction; + } + totalCol +=1; + } + +} + +void XLTable::adjustRef() +{ + uint32_t firstRow = m_dataBodyRange.rangeCoordinates().first.row(); + uint32_t lastRow = m_dataBodyRange.rangeCoordinates().second.row(); + + uint16_t firstCol = m_dataBodyRange.rangeCoordinates().first.column(); + uint16_t lastCol = m_dataBodyRange.rangeCoordinates().second.column(); + + if(isHeaderVisible()) + firstRow -=1; + + if(isTotalVisible()) + lastRow +=1; + + std::string ref = XLCellReference::adressFromCoordinates(firstRow, firstCol, false); + ref += ":" + XLCellReference::adressFromCoordinates(lastRow, lastCol, false); + + m_pXmlData->getXmlDocument()->child("table") + .attribute("ref").set_value(ref.c_str()); +} \ No newline at end of file diff --git a/OpenXLSX/sources/XLTableColumn.cpp b/OpenXLSX/sources/XLTableColumn.cpp index 4b07bd9b..cf2fe9d8 100644 --- a/OpenXLSX/sources/XLTableColumn.cpp +++ b/OpenXLSX/sources/XLTableColumn.cpp @@ -15,33 +15,33 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. MM _MM_ - Written by Akira SHIMAHARA - - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - Neither the name of the author nor the - names of any contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - */ + Written by Akira SHIMAHARA + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + - Neither the name of the author nor the + names of any contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ // ===== External Includes ===== // #include @@ -50,44 +50,103 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. // ===== OpenXLSX Includes ===== // #include "XLTableColumn.hpp" - +#include "XLTemplates.hpp" +#include "XLTable.hpp" using namespace OpenXLSX; - -XLTableColumn::XLTableColumn(const XMLNode& dataNode): - m_dataNode(std::make_unique(dataNode)) +XLTableColumn::XLTableColumn(const XMLNode& dataNode, XLTable* table): + m_dataNode(std::make_unique(dataNode)), + m_table(table) { - /* TODO implement the followings - m_name = m_dataNode->attribute("name").value(); - m_xr3uid = m_dataNode->attribute("xr3:uid").value(); - m_dataCellStyle = m_dataNode->attribute("dataCellStyle").value(); - m_headerRowCellStyle= m_dataNode->attribute("headerRowCellStyle").value(); - m_totalsRowFunction = m_dataNode->attribute("totalsRowFunction").value(); - m_totalsRowLabel = m_dataNode->attribute("totalsRowLabel").value(); - - m_Id = (m_dataNode->attribute("id")) ? std::stoi(m_dataNode->attribute("id").value()) : (uint32_t) -1; - m_dataDxfId = (m_dataNode->attribute("dataDxfId")) ? std::stoi(m_dataNode->attribute("dataDxfId").value()) : (uint32_t) -1; - m_headerRowDxfId = (m_dataNode->attribute("headerRowDxfId")) ? std::stoi(m_dataNode->attribute("headerRowDxfId").value()) : (uint32_t) -1; - m_totalsRowDxfId = (m_dataNode->attribute("totalsRowDxfId")) ? std::stoi(m_dataNode->attribute("totalsRowDxfId").value()) : (uint32_t) -1; - - if (m_dataNode->child("calculatedColumnFormula")) - m_calculatedColumnFormula = m_dataNode->child("calculatedColumnFormula").child_value(); - if (m_dataNode->child("totalsRowFormula")) - m_totalsRowFormula = m_dataNode->child("totalsRowFormula").child_value(); - */ + /* TODO implement the followings + m_name = m_dataNode->attribute("name").value(); + m_xr3uid = m_dataNode->attribute("xr3:uid").value(); + m_dataCellStyle = m_dataNode->attribute("dataCellStyle").value(); + m_headerRowCellStyle= m_dataNode->attribute("headerRowCellStyle").value(); + m_totalsRowFunction = m_dataNode->attribute("totalsRowFunction").value(); + m_totalsRowLabel = m_dataNode->attribute("totalsRowLabel").value(); + + m_Id = (m_dataNode->attribute("id")) ? std::stoi(m_dataNode->attribute("id").value()) : (uint32_t) -1; + m_dataDxfId = (m_dataNode->attribute("dataDxfId")) ? std::stoi(m_dataNode->attribute("dataDxfId").value()) : (uint32_t) -1; + m_headerRowDxfId = (m_dataNode->attribute("headerRowDxfId")) ? std::stoi(m_dataNode->attribute("headerRowDxfId").value()) : (uint32_t) -1; + m_totalsRowDxfId = (m_dataNode->attribute("totalsRowDxfId")) ? std::stoi(m_dataNode->attribute("totalsRowDxfId").value()) : (uint32_t) -1; + + if (m_dataNode->child("calculatedColumnFormula")) + m_calculatedColumnFormula = m_dataNode->child("calculatedColumnFormula").child_value(); + if (m_dataNode->child("totalsRowFormula")) + m_totalsRowFormula = m_dataNode->child("totalsRowFormula").child_value(); + */ } +XLTableColumn::XLTableColumn(const XLTableColumn& other) + : m_dataNode(other.m_dataNode ? std::make_unique(*other.m_dataNode) : nullptr), + m_table(other.m_table) +{} + +XLTableColumn::XLTableColumn(XLTableColumn&& other) noexcept + : m_dataNode(std::move(other.m_dataNode)), + m_table(other.m_table) +{} + + XLTableColumn::~XLTableColumn() = default; +XLTableColumn& XLTableColumn::operator=(const XLTableColumn& other) +{ + if (&other != this) { + auto temp = XLTableColumn(other); + std::swap(*this, temp); + } + return *this; +} + +XLTableColumn& XLTableColumn::operator=(XLTableColumn&& other) noexcept +{ + if (&other != this) { + m_dataNode = std::move(other.m_dataNode); + m_table = other.m_table; + } + return *this; +} + + std::string XLTableColumn::name() const { - return (m_dataNode->attribute("name").value()); + return (m_dataNode->attribute("name").value()); } void XLTableColumn::setName(const std::string& columnName) const { - m_dataNode->attribute("name").set_value(columnName.c_str()); - // TODO change the formulas in table.xml - // TODO change the formulas in the sheet + m_dataNode->attribute("name").set_value(columnName.c_str()); + // TODO change the formulas in table.xml + // TODO change the formulas in the sheet } + +std::string XLTableColumn::totalsRowFunction() const +{ + return std::string(m_dataNode->attribute("totalsRowFunction").value()); +} + +void XLTableColumn::setTotalsRowFunction(const std::string& function) +{ + // TODO implement + // TODO implement == custom function + + // check if the formula is allowed otherwise quit + auto it = std::find(std::begin(XLTemplate::totalsRowFunctionList), + std::end(XLTemplate::totalsRowFunctionList), function); + if( it == std::end(XLTemplate::totalsRowFunctionList)) + return; + + auto node = m_dataNode->attribute("totalsRowFunction"); + if(!node) + node = m_dataNode->append_attribute("totalsRowFunction"); + + node.set_value(function.c_str()); + + // Update the fonctions in the worksheet + m_table->setTotalFormulas(); + +} + diff --git a/OpenXLSX/sources/XLTableRows.cpp b/OpenXLSX/sources/XLTableRows.cpp index ba812a12..629b9e2e 100644 --- a/OpenXLSX/sources/XLTableRows.cpp +++ b/OpenXLSX/sources/XLTableRows.cpp @@ -97,10 +97,7 @@ XLTableRowIterator& XLTableRowIterator::operator=(XLTableRowIterator&& other) no XLTableRowIterator& XLTableRowIterator::operator++() { - m_range.offset(1);/* - if(m_range.rangeCoordinates().first.first > m_lastIterRow) - m_range = XLCellRange(); - */ + m_range.offset(1); return *this; } From 406ce1d9ce06136b75ac831f2a30a2efcd3959d1 Mon Sep 17 00:00:00 2001 From: akira215 Date: Mon, 2 Jan 2023 17:47:40 +0100 Subject: [PATCH 19/45] Fixing table totla formula clearing --- Examples/Demo10.cpp | 1 + OpenXLSX/headers/XLCellRange.hpp | 59 ++++++++++++++++-------------- OpenXLSX/headers/XLTableColumn.hpp | 7 +++- OpenXLSX/sources/XLCellRange.cpp | 7 ++++ OpenXLSX/sources/XLTable.cpp | 58 +++++++++++++++-------------- OpenXLSX/sources/XLTableColumn.cpp | 19 ++++++++-- 6 files changed, 91 insertions(+), 60 deletions(-) diff --git a/Examples/Demo10.cpp b/Examples/Demo10.cpp index db2526be..3d021845 100644 --- a/Examples/Demo10.cpp +++ b/Examples/Demo10.cpp @@ -78,6 +78,7 @@ int main() { tbl.setTotalVisible(true); //tbl.column("Table")->setTotalsRowFunction("sum"); tbl.column("Table").setTotalsRowFunction("count"); + tbl.column("Table").setTotalsRowFunction(""); doc.save(); diff --git a/OpenXLSX/headers/XLCellRange.hpp b/OpenXLSX/headers/XLCellRange.hpp index 2308e29f..e6d4f737 100644 --- a/OpenXLSX/headers/XLCellRange.hpp +++ b/OpenXLSX/headers/XLCellRange.hpp @@ -15,33 +15,33 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. MM _MM_ - Copyright (c) 2018, Kenneth Troldal Balslev - - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - Neither the name of the author nor the - names of any contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - */ + Copyright (c) 2018, Kenneth Troldal Balslev + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + - Neither the name of the author nor the + names of any contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ #ifndef OPENXLSX_XLCELLRANGE_HPP #define OPENXLSX_XLCELLRANGE_HPP @@ -197,6 +197,11 @@ namespace OpenXLSX * @return A pair of ref */ std::pair rangeCoordinates(); + /** + * @brief get the coordinates of the top left and bottom right + * @return A pair of ref + */ + const std::pair rangeCoordinates() const; /** * @brief Static helper function to get top left and bottom right diff --git a/OpenXLSX/headers/XLTableColumn.hpp b/OpenXLSX/headers/XLTableColumn.hpp index bb3bb490..41d1d938 100644 --- a/OpenXLSX/headers/XLTableColumn.hpp +++ b/OpenXLSX/headers/XLTableColumn.hpp @@ -118,9 +118,14 @@ namespace OpenXLSX */ std::string totalsRowFunction() const; + /** + * @brief clear the total row function of this columns and trigger the sheet update + */ + void clearTotalsRowFunction(); + /** * @brief - * @param function function to be set. if function is not know, nothing is done + * @param function function to be set. use empty string to remove function,or "none"if function is not know, nothing is done */ void setTotalsRowFunction(const std::string& function); diff --git a/OpenXLSX/sources/XLCellRange.cpp b/OpenXLSX/sources/XLCellRange.cpp index f8e9f101..0b01441b 100644 --- a/OpenXLSX/sources/XLCellRange.cpp +++ b/OpenXLSX/sources/XLCellRange.cpp @@ -235,11 +235,18 @@ void XLCellRange::setRangeCoordinates(const XLCellReference& topLeft, m_bottomRight = bottomRight; } + + std::pair XLCellRange::rangeCoordinates() { return std::make_pair(m_topLeft,m_bottomRight); } +const std::pair XLCellRange::rangeCoordinates() const +{ + return std::make_pair(m_topLeft,m_bottomRight); +} + std::pair XLCellRange::topLeftBottomRight(const std::string& ref) { std::string::size_type n = ref.find(':'); diff --git a/OpenXLSX/sources/XLTable.cpp b/OpenXLSX/sources/XLTable.cpp index 512fafab..6a6104cb 100644 --- a/OpenXLSX/sources/XLTable.cpp +++ b/OpenXLSX/sources/XLTable.cpp @@ -240,18 +240,10 @@ uint16_t XLTable::columnsCount() const uint32_t XLTable::rowsCount() const { - std::pair p = XLCellRange::topLeftBottomRight(ref()); - XLCellReference topLeft(p.first); - XLCellReference bottomRight(p.second); + auto p = m_dataBodyRange.rangeCoordinates(); - uint32_t firstRow = topLeft.row(); - uint32_t lastRow = bottomRight.row(); - - if (isHeaderVisible()) - firstRow +=1; - - if (isTotalVisible()) - lastRow -=1; + uint32_t firstRow = p.first.row(); + uint32_t lastRow = p.second.row(); return (lastRow - firstRow + 1); } @@ -271,7 +263,6 @@ void XLTable::setName(const std::string& tableName) void XLTable::setTotalFormulas() { - if (!isTotalVisible()) return; @@ -280,23 +271,34 @@ void XLTable::setTotalFormulas() for (auto& col: m_columns){ std::string colFunc = col.totalsRowFunction(); - - // Check if its exist in the list - auto it = std::find(std::begin(XLTemplate::totalsRowFunctionList), - std::end(XLTemplate::totalsRowFunctionList), colFunc); - if( it != std::end(XLTemplate::totalsRowFunctionList)){ - - - // get the equivalent formula in the sheet - std::string sheetFunction = "SUBTOTAL("; - sheetFunction += XLTemplate::sheetTotalFunctionList[ - std::distance(std::begin(XLTemplate::totalsRowFunctionList), it) - ]; - sheetFunction += "," + name() - + "[" + col.name() + "])"; - - m_sheet.cell(totalRow, totalCol).formula() = sheetFunction; + if (colFunc.empty()){ // if there is nothing, remove formula and values + m_sheet.cell(totalRow, totalCol).formula().clear(); + m_sheet.cell(totalRow, totalCol).value().clear(); } + else + { + // Check if its exist in the list + auto it = std::find(std::begin(XLTemplate::totalsRowFunctionList), + std::end(XLTemplate::totalsRowFunctionList), colFunc); + if( it != std::end(XLTemplate::totalsRowFunctionList)){ + + std::string function = XLTemplate::sheetTotalFunctionList[ + std::distance(std::begin(XLTemplate::totalsRowFunctionList), it) + ]; + if (function != "none") + { + // get the equivalent formula in the sheet + std::string sheetFunction = "SUBTOTAL(" + function + + "," + name() + + "[" + col.name() + "])"; + m_sheet.cell(totalRow, totalCol).formula() = sheetFunction; + } else {// remove the formula if function is none + m_sheet.cell(totalRow, totalCol).formula().clear(); + m_sheet.cell(totalRow, totalCol).value().clear(); + } + + } + } // if col function not empty totalCol +=1; } diff --git a/OpenXLSX/sources/XLTableColumn.cpp b/OpenXLSX/sources/XLTableColumn.cpp index cf2fe9d8..f8564cde 100644 --- a/OpenXLSX/sources/XLTableColumn.cpp +++ b/OpenXLSX/sources/XLTableColumn.cpp @@ -128,10 +128,25 @@ std::string XLTableColumn::totalsRowFunction() const return std::string(m_dataNode->attribute("totalsRowFunction").value()); } +void XLTableColumn::clearTotalsRowFunction() +{ + setTotalsRowFunction(std::string()); +} + void XLTableColumn::setTotalsRowFunction(const std::string& function) { // TODO implement // TODO implement == custom function + auto node = m_dataNode->attribute("totalsRowFunction"); + if(!node) + node = m_dataNode->append_attribute("totalsRowFunction"); + + // If empty string, we remove the formula + if(function.empty()){ + m_dataNode->remove_attribute("totalsRowFunction"); + m_table->setTotalFormulas(); + return; + } // check if the formula is allowed otherwise quit auto it = std::find(std::begin(XLTemplate::totalsRowFunctionList), @@ -139,10 +154,6 @@ void XLTableColumn::setTotalsRowFunction(const std::string& function) if( it == std::end(XLTemplate::totalsRowFunctionList)) return; - auto node = m_dataNode->attribute("totalsRowFunction"); - if(!node) - node = m_dataNode->append_attribute("totalsRowFunction"); - node.set_value(function.c_str()); // Update the fonctions in the worksheet From 151a0451794d3d6672410d7616c8681ba0467f24 Mon Sep 17 00:00:00 2001 From: akira215 Date: Mon, 2 Jan 2023 23:52:08 +0100 Subject: [PATCH 20/45] all functionality of tablestyle checked --- Examples/Demo10.cpp | 16 ++- OpenXLSX/CMakeLists.txt | 1 + OpenXLSX/headers/XLException.hpp | 10 ++ OpenXLSX/headers/XLTable.hpp | 8 ++ OpenXLSX/headers/XLTableStyle.hpp | 181 +++++++++++++++++++++++ OpenXLSX/headers/XLTemplates.hpp | 44 ++++++ OpenXLSX/sources/XLDocument.cpp | 8 +- OpenXLSX/sources/XLTable.cpp | 4 + OpenXLSX/sources/XLTableColumn.cpp | 2 +- OpenXLSX/sources/XLTableStyle.cpp | 223 +++++++++++++++++++++++++++++ 10 files changed, 493 insertions(+), 4 deletions(-) create mode 100644 OpenXLSX/headers/XLTableStyle.hpp create mode 100644 OpenXLSX/sources/XLTableStyle.cpp diff --git a/Examples/Demo10.cpp b/Examples/Demo10.cpp index 3d021845..ca7a881c 100644 --- a/Examples/Demo10.cpp +++ b/Examples/Demo10.cpp @@ -77,9 +77,23 @@ int main() { //tbl.setHeaderVisible(false); tbl.setTotalVisible(true); //tbl.column("Table")->setTotalsRowFunction("sum"); - tbl.column("Table").setTotalsRowFunction("count"); tbl.column("Table").setTotalsRowFunction(""); + tbl.column("Table").setTotalsRowFunction("count"); + + cout << "Table Style : " << tbl.tableStyle().style() << endl; + tbl.tableStyle().setStyle("TableStyleDark7"); + + cout << "Column stripes : " << tbl.tableStyle().columnStripes() << endl; + cout << "row stripes : " << tbl.tableStyle().rowStripes() << endl; + + tbl.tableStyle().showRowStripes(false); + tbl.tableStyle().showColumnStripes(true); + + cout << "1st Column highlighted : " << tbl.tableStyle().firstColumnHighlighted() << endl; + cout << "last Column highlighted : " << tbl.tableStyle().lastColumnHighlighted() << endl; + tbl.tableStyle().showFirstColumnHighlighted(true); + tbl.tableStyle().showLastColumnHighlighted(true); doc.save(); doc.close(); diff --git a/OpenXLSX/CMakeLists.txt b/OpenXLSX/CMakeLists.txt index 12ad4d11..a159fcdd 100644 --- a/OpenXLSX/CMakeLists.txt +++ b/OpenXLSX/CMakeLists.txt @@ -104,6 +104,7 @@ set(OPENXLSX_SOURCES ${CMAKE_CURRENT_LIST_DIR}/sources/XLTable.cpp ${CMAKE_CURRENT_LIST_DIR}/sources/XLTableColumn.cpp ${CMAKE_CURRENT_LIST_DIR}/sources/XLTableRows.cpp + ${CMAKE_CURRENT_LIST_DIR}/sources/XLTableStyle.cpp ${CMAKE_CURRENT_LIST_DIR}/sources/XLWorkbook.cpp ${CMAKE_CURRENT_LIST_DIR}/sources/XLXmlData.cpp ${CMAKE_CURRENT_LIST_DIR}/sources/XLXmlFile.cpp diff --git a/OpenXLSX/headers/XLException.hpp b/OpenXLSX/headers/XLException.hpp index dbcad116..f92a2fba 100644 --- a/OpenXLSX/headers/XLException.hpp +++ b/OpenXLSX/headers/XLException.hpp @@ -52,6 +52,7 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. // ===== External Includes ===== // #include +#include // ===== OpenXLSX Includes ===== // #include "OpenXLSX-Exports.hpp" @@ -148,6 +149,15 @@ namespace OpenXLSX inline explicit XLFormulaError(const std::string& err) : XLException(err) {}; }; + class OPENXLSX_EXPORT XLLogError + { + public: + inline explicit XLLogError(const std::string& err) + { + std::cerr << err << std::endl; + }; + }; + } // namespace OpenXLSX diff --git a/OpenXLSX/headers/XLTable.hpp b/OpenXLSX/headers/XLTable.hpp index c0dc0142..69a8c7d1 100644 --- a/OpenXLSX/headers/XLTable.hpp +++ b/OpenXLSX/headers/XLTable.hpp @@ -59,12 +59,14 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. #include "XLXmlData.hpp" #include "XLTableColumn.hpp" #include "XLTableRows.hpp" +#include "XLTableStyle.hpp" #include "XLSheet.hpp" namespace OpenXLSX { class OPENXLSX_EXPORT XLTable { friend class XLTableColumn; + friend class XLTableStyle; public: /** @@ -176,6 +178,11 @@ namespace OpenXLSX */ XLAutofilter autofilter(); + /** + * @brief return the table style obect + */ + XLTableStyle tableStyle(); + /** * @brief * @return number of columns @@ -193,6 +200,7 @@ namespace OpenXLSX * @param tableName name of the table */ void setName(const std::string& tableName); + //---------------------------------------------------------------------------------------------------------------------- // Protected //---------------------------------------------------------------------------------------------------------------------- diff --git a/OpenXLSX/headers/XLTableStyle.hpp b/OpenXLSX/headers/XLTableStyle.hpp new file mode 100644 index 00000000..f3be0bf0 --- /dev/null +++ b/OpenXLSX/headers/XLTableStyle.hpp @@ -0,0 +1,181 @@ +/* + + ____ ____ ___ ____ ____ ____ ___ + 6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M' + 8P Y8 `MM. d' MM 6M' ` `MM. d' +6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d' +MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d' +MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd +MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM. +MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM. +YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. + 8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM. + YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_ + MM + MM + _MM_ + + Written by Akira SHIMAHARA + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + - Neither the name of the author nor the + names of any contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ + +#ifndef OPENXLSX_XLTABLESTYLE_HPP +#define OPENXLSX_XLTABLESTYLE_HPP + +#pragma warning(push) +//#pragma warning(disable : 4251) +//#pragma warning(disable : 4275) + +// ===== External Includes ===== // +#include +#include + +// ===== OpenXLSX Includes ===== // +#include "OpenXLSX-Exports.hpp" +#include "XLXmlParser.hpp" + +namespace OpenXLSX +{ + class XLTable; + + class OPENXLSX_EXPORT XLTableStyle + { + public: + /** + * @brief The constructor. + * @param dataNode XMLNode of the column + */ + XLTableStyle(const XMLNode& dataNode, XLTable* table); + + /** + * @brief Copy Constructor + * @note The copy constructor is explicitly deleted + */ + XLTableStyle(const XLTableStyle& other); + + /** + * @brief Move Constructor + * @note The move constructor has been explicitly deleted. + */ + XLTableStyle(XLTableStyle&& other) noexcept; + + //XLtableStyle(constXLTableStyle&) = delete; + //XLtableStyle& operator=(constXLTableStyle&) = delete; + ~XLTableStyle(); + + /** + * @brief Copy assignment operator. + * @note The copy assignment operator is explicitly deleted. + */ + XLTableStyle& operator=(const XLTableStyle& other); + + /** + * @brief Move assignment operator. + * @note The move assignment operator has been explicitly deleted. + */ + XLTableStyle& operator=(XLTableStyle&& other) noexcept; + + + /** + * @brief + * @return the style name + */ + const std::string style() const; + + /** + * @brief + * @return true id the colum stripes are shown + */ + bool columnStripes() const; + + /** + * @brief + * @param show true to show the stripes, default is true + */ + void showColumnStripes(bool show = true) const; + + /** + * @brief + * @return true if the colum stripes are shown + */ + bool rowStripes() const; + + /** + * @brief + * @param show true to show the stripes, default is true + */ + void showRowStripes(bool show = true) const; + + /** + * @brief + * @return true fd the first column is highligted + */ + bool firstColumnHighlighted() const; + + /** + * @brief + * @param show true highlight the column, default is true + */ + void showFirstColumnHighlighted(bool show = true) const; + + /** + * @brief + * @return true fd the first column is highligted + */ + bool lastColumnHighlighted() const; + + /** + * @brief + * @param show true highlight the column, default is true + */ + void showLastColumnHighlighted(bool show = true) const; + + /** + * @brief + * @param name the style name. If not availble, do nothing + */ + void setStyle(const std::string& style) const; + + //---------------------------------------------------------------------------------------------------------------------- + // Protected + //---------------------------------------------------------------------------------------------------------------------- + protected: + /** + * @brief return a vector of available table style + * @param style style to be checked if available + */ + bool isTableStyleAvailable(const std::string& style) const; + + + private: + std::unique_ptr m_dataNode; + XLTable* m_table; + }; +} // namespace OpenXLSX + +//#pragma warning(pop) +#endif // OPENXLSX_XLSTYLE_HPP diff --git a/OpenXLSX/headers/XLTemplates.hpp b/OpenXLSX/headers/XLTemplates.hpp index c926778f..cfc5b12e 100644 --- a/OpenXLSX/headers/XLTemplates.hpp +++ b/OpenXLSX/headers/XLTemplates.hpp @@ -15,6 +15,7 @@ namespace OpenXLSX "" "" }; + const std::string emptyWorksheet { "\n" "" "" }; + const std::string tableRels { "" }; + const std::string totalsRowFunctionList[] = { "average", "count", "countNums", "custom", "max", "min", "none", "stdDev", "sum", "var" }; + // Warning : this shall be in the same order than totalsRowFunctionList const std::string sheetTotalFunctionList[] = { "101", "103", "102", "custom", "104", "105", "none", "107", "109", "110" }; + + const std::string defaultTableStyle[] = { + "TableStyleMedium1", "TableStyleMedium2", "TableStyleMedium3", "TableStyleMedium4", "TableStyleMedium5", + "TableStyleMedium6", "TableStyleMedium7", "TableStyleMedium8", "TableStyleMedium9", "TableStyleMedium10", + "TableStyleMedium11", "TableStyleMedium12", "TableStyleMedium13", "TableStyleMedium14", "TableStyleMedium15", + "TableStyleMedium16", "TableStyleMedium17", "TableStyleMedium18", "TableStyleMedium19", "TableStyleMedium20", + "TableStyleMedium21", "TableStyleMedium22", "TableStyleMedium23", "TableStyleMedium24", "TableStyleMedium25", + "TableStyleMedium26", "TableStyleMedium27", "TableStyleMedium28", + "TableStyleLight1", "TableStyleLight2", "TableStyleLight3", "TableStyleLight4", "TableStyleLight5", + "TableStyleLight6", "TableStyleLight7", "TableStyleLight8", "TableStyleLight9", "TableStyleLight10", + "TableStyleLight11", "TableStyleLight12", "TableStyleLight13", "TableStyleLight14", "TableStyleLight15", + "TableStyleLight16", "TableStyleLight17", "TableStyleLight18", "TableStyleLight19", "TableStyleLight20", + "TableStyleLight21", + "TableStyleDark1", "TableStyleDark2", "TableStyleDark3", "TableStyleDark4", "TableStyleDark5", + "TableStyleDark6", "TableStyleDark7", "TableStyleDark8", "TableStyleDark9", "TableStyleDark10", + "TableStyleDark11", + }; + + const std::string defaultPivotStyle[] = { + "PivotStyleMedium1", "PivotStyleMedium2", "PivotStyleMedium3", "PivotStyleMedium4", "PivotStyleMedium5", + "PivotStyleMedium6", "PivotStyleMedium7", "PivotStyleMedium8", "PivotStyleMedium9", "PivotStyleMedium10", + "PivotStyleMedium11", "PivotStyleMedium12", "PivotStyleMedium13", "PivotStyleMedium14", "PivotStyleMedium15", + "PivotStyleMedium16", "PivotStyleMedium17", "PivotStyleMedium18", "PivotStyleMedium19", "PivotStyleMedium20", + "PivotStyleMedium21", "PivotStyleMedium22", "PivotStyleMedium23", "PivotStyleMedium24", "PivotStyleMedium25", + "PivotStyleMedium26", "PivotStyleMedium27", "PivotStyleMedium28", + "PivotStyleLight1", "PivotStyleLight2", "PivotStyleLight3", "PivotStyleLight4", "PivotStyleLight5", + "PivotStyleLight6", "PivotStyleLight7", "PivotStyleLight8", "PivotStyleLight9", "PivotStyleLight10", + "PivotStyleLight11", "PivotStyleLight12", "PivotStyleLight13", "PivotStyleLight14", "PivotStyleLight15", + "PivotStyleLight16", "PivotStyleLight17", "PivotStyleLight18", "PivotStyleLight19", "PivotStyleLight20", + "PivotStyleLight21", "PivotStyleLight22", "PivotStyleLight23", "PivotStyleLight24", "PivotStyleLight25", + "PivotStyleLight26", "PivotStyleLight27", "PivotStyleLight28", + "PivotStyleDark1", "PivotStyleDark2", "PivotStyleDark3", "PivotStyleDark4", "PivotStyleDark5", + "PivotStyleDark6", "PivotStyleDark7", "PivotStyleDark8", "PivotStyleDark9", "PivotStyleDark10", + "PivotStyleDark11", "PivotStyleDark12", "PivotStyleDark13", "PivotStyleDark14", "PivotStyleDark15", + "PivotStyleDark16", "PivotStyleDark17", "PivotStyleDark18", "PivotStyleDark19", "PivotStyleDark20", + "PivotStyleDark21", "PivotStyleDark22", "PivotStyleDark23", "PivotStyleDark24", "PivotStyleDark25", + "PivotStyleDark26", "PivotStyleDark27", "PivotStyleDark28", + }; + const int templateSize = 7714; + const unsigned char templateData[7714] = { 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00, 0x21, 0x00, 0xb5, 0x55, 0x30, 0x23, 0xf4, 0x00, 0x00, 0x00, 0x4c, 0x02, 0x00, 0x00, 0x0b, 0x00, 0x08, 0x02, 0x5f, 0x72, 0x65, 0x6c, 0x73, 0x2f, 0x2e, 0x72, 0x65, 0x6c, 0x73, 0x20, 0xa2, 0x04, diff --git a/OpenXLSX/sources/XLDocument.cpp b/OpenXLSX/sources/XLDocument.cpp index a4c0aacd..a4e69b6d 100644 --- a/OpenXLSX/sources/XLDocument.cpp +++ b/OpenXLSX/sources/XLDocument.cpp @@ -640,7 +640,7 @@ XLQuery XLDocument::execQuery(const XLQuery& query) const case XLQueryType::QuerySheetFromName: return XLQuery(query).setResult(getXmlDataByName(query.getParam("sheetName"))); - + case XLQueryType::QueryTableFromName: { for (auto& item : m_data){ @@ -657,7 +657,11 @@ XLQuery XLDocument::execQuery(const XLQuery& query) const { auto result = std::find_if(m_data.begin(), m_data.end(), [&](const XLXmlData& item) { return item.getXmlPath() == query.getParam("xmlPath"); }); - if (result == m_data.end()) throw XLInternalError("Path does not exist in zip archive (" + query.getParam("xmlPath") + ")"); + if (result == m_data.end()){ + XLLogError("Path does not exist in zip archive (" + query.getParam("xmlPath") + ")"); + //throw XLInternalError("Path does not exist in zip archive (" + query.getParam("xmlPath") + ")"); + return XLQuery(query).setResult(nullptr); + } return XLQuery(query).setResult(&*result); } } diff --git a/OpenXLSX/sources/XLTable.cpp b/OpenXLSX/sources/XLTable.cpp index 6a6104cb..7bf20772 100644 --- a/OpenXLSX/sources/XLTable.cpp +++ b/OpenXLSX/sources/XLTable.cpp @@ -231,6 +231,10 @@ XLAutofilter XLTable::autofilter() return XLAutofilter(m_pXmlData->getXmlDocument()->child("table").child("autoFilter"),m_pXmlData); } +XLTableStyle XLTable::tableStyle() +{ + return XLTableStyle(m_pXmlData->getXmlDocument()->child("table").child("tableStyleInfo"), this); +} uint16_t XLTable::columnsCount() const { diff --git a/OpenXLSX/sources/XLTableColumn.cpp b/OpenXLSX/sources/XLTableColumn.cpp index f8564cde..2bd0bd5b 100644 --- a/OpenXLSX/sources/XLTableColumn.cpp +++ b/OpenXLSX/sources/XLTableColumn.cpp @@ -113,7 +113,7 @@ XLTableColumn& XLTableColumn::operator=(XLTableColumn&& other) noexcept std::string XLTableColumn::name() const { - return (m_dataNode->attribute("name").value()); + return std::string(m_dataNode->attribute("name").value()); } void XLTableColumn::setName(const std::string& columnName) const diff --git a/OpenXLSX/sources/XLTableStyle.cpp b/OpenXLSX/sources/XLTableStyle.cpp new file mode 100644 index 00000000..6ca9cba5 --- /dev/null +++ b/OpenXLSX/sources/XLTableStyle.cpp @@ -0,0 +1,223 @@ +/* + + ____ ____ ___ ____ ____ ____ ___ + 6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M' + 8P Y8 `MM. d' MM 6M' ` `MM. d' +6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d' +MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d' +MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd +MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM. +MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM. +YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. + 8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM. + YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_ + MM + MM + _MM_ + + Written by Akira SHIMAHARA + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + - Neither the name of the author nor the + names of any contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ + +// ===== External Includes ===== // +#include +#include + +// ===== OpenXLSX Includes ===== // +#include "XLTableStyle.hpp" +#include "XLTemplates.hpp" +#include "XLTable.hpp" +#include "XLCommandQuery.hpp" + +using namespace OpenXLSX; + +XLTableStyle::XLTableStyle(const XMLNode& dataNode, XLTable* table): + m_dataNode(std::make_unique(dataNode)), + m_table(table) +{ + /* TODO implement the custom table style (with external xml file if required) + */ + +} + +XLTableStyle::XLTableStyle(const XLTableStyle& other) + : m_dataNode(other.m_dataNode ? std::make_unique(*other.m_dataNode) : nullptr), + m_table(other.m_table) +{} + +XLTableStyle::XLTableStyle(XLTableStyle&& other) noexcept + : m_dataNode(std::move(other.m_dataNode)), + m_table(other.m_table) +{} + + +XLTableStyle::~XLTableStyle() = default; + +XLTableStyle& XLTableStyle::operator=(const XLTableStyle& other) +{ + if (&other != this) { + auto temp = XLTableStyle(other); + std::swap(*this, temp); + } + return *this; +} + +XLTableStyle& XLTableStyle::operator=(XLTableStyle&& other) noexcept +{ + if (&other != this) { + m_dataNode = std::move(other.m_dataNode); + m_table = other.m_table; + } + return *this; +} + +bool XLTableStyle::columnStripes() const +{ + if(std::string(m_dataNode->attribute("showColumnStripes").value()) == "1") + return true; + + return false; +} + +void XLTableStyle::showColumnStripes(bool show) const +{ + auto node = m_dataNode->attribute("showColumnStripes"); + if(!node) + node = m_dataNode->append_attribute("showColumnStripes"); + + if(show) + node.set_value("1"); + else + node.set_value("0"); +} + + +bool XLTableStyle::rowStripes() const +{ + if(std::string(m_dataNode->attribute("showRowStripes").value()) == "1") + return true; + + return false; +} + +void XLTableStyle::showRowStripes(bool show) const +{ + auto node = m_dataNode->attribute("showRowStripes"); + if(!node) + node = m_dataNode->append_attribute("showRowStripes"); + + if(show) + node.set_value("1"); + else + + + node.set_value("0"); +} + +bool XLTableStyle::firstColumnHighlighted() const +{ + if(std::string(m_dataNode->attribute("showFirstColumn").value()) == "1") + return true; + + return false; +} + +void XLTableStyle::showFirstColumnHighlighted(bool show) const +{ + auto node = m_dataNode->attribute("showFirstColumn"); + if(!node) + node = m_dataNode->append_attribute("showFirstColumn"); + + if(show) + node.set_value("1"); + else + + + node.set_value("0"); +} + +bool XLTableStyle::lastColumnHighlighted() const +{ + if(std::string(m_dataNode->attribute("showLastColumn").value()) == "1") + return true; + + return false; +} + +void XLTableStyle::showLastColumnHighlighted(bool show) const +{ + auto node = m_dataNode->attribute("showLastColumn"); + if(!node) + node = m_dataNode->append_attribute("showLastColumn"); + + if(show) + node.set_value("1"); + else + + + node.set_value("0"); +} + + +const std::string XLTableStyle::style() const +{ + return std::string(m_dataNode->attribute("name").value()); +} + +void XLTableStyle::setStyle(const std::string& style) const +{ + if (!isTableStyleAvailable(style)){ + XLLogError("Specified style \"" + style + "\" is not available in this file"); + return; + } + + m_dataNode->attribute("name").set_value(style.c_str()); +} + +bool XLTableStyle::isTableStyleAvailable(const std::string& style) const +{ + // check if the style is in the standard default list + auto it = std::find(std::begin(XLTemplate::defaultTableStyle), + std::end(XLTemplate::defaultTableStyle), style); + if( it != std::end(XLTemplate::defaultTableStyle)) + return true; + + // If not check also in the custom styles in the file + m_table->m_pXmlData->getParentDoc(); + + XLQuery query(XLQueryType::QueryXmlData); + query.setParam("xmlPath", "xl/styles.xml"); + + XLXmlData* p = m_table->m_pXmlData->getParentDoc()->execQuery(query).template result(); + if (p) + for (const auto& node : p->getXmlDocument()->child("styleSheet").child("tableStyles")) + if( style == std::string(node.attribute("name").value())) + return true; + + return false; + +} \ No newline at end of file From cdd49789276be2d8701f1424a59e17a9fefe1ca9 Mon Sep 17 00:00:00 2001 From: akira215 Date: Tue, 3 Jan 2023 06:00:44 +0100 Subject: [PATCH 21/45] working on proxy tableformulas --- Examples/Demo10.cpp | 3 +- OpenXLSX/OpenXLSX.hpp | 1 + OpenXLSX/headers/XLTableColumn.hpp | 132 +++++++++++++++++++- OpenXLSX/sources/XLTable.cpp | 1 + OpenXLSX/sources/XLTableColumn.cpp | 188 ++++++++++++++++++++++++++++- 5 files changed, 318 insertions(+), 7 deletions(-) diff --git a/Examples/Demo10.cpp b/Examples/Demo10.cpp index ca7a881c..4af36bc9 100644 --- a/Examples/Demo10.cpp +++ b/Examples/Demo10.cpp @@ -78,7 +78,8 @@ int main() { tbl.setTotalVisible(true); //tbl.column("Table")->setTotalsRowFunction("sum"); tbl.column("Table").setTotalsRowFunction(""); - tbl.column("Table").setTotalsRowFunction("count"); + //tbl.column("Table").setTotalsRowFunction("count"); + tbl.column("Table").totalsRowFormula() ="sum"; cout << "Table Style : " << tbl.tableStyle().style() << endl; tbl.tableStyle().setStyle("TableStyleDark7"); diff --git a/OpenXLSX/OpenXLSX.hpp b/OpenXLSX/OpenXLSX.hpp index ed68da34..91b15136 100644 --- a/OpenXLSX/OpenXLSX.hpp +++ b/OpenXLSX/OpenXLSX.hpp @@ -60,6 +60,7 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. #include "headers/XLSheet.hpp" #include "headers/XLTable.hpp" #include "headers/XLTableRows.hpp" +#include "headers/XLTableStyle.hpp" #include "headers/XLWorkbook.hpp" #include "headers/XLZipArchive.hpp" diff --git a/OpenXLSX/headers/XLTableColumn.hpp b/OpenXLSX/headers/XLTableColumn.hpp index 41d1d938..8cb77cbb 100644 --- a/OpenXLSX/headers/XLTableColumn.hpp +++ b/OpenXLSX/headers/XLTableColumn.hpp @@ -62,6 +62,126 @@ namespace OpenXLSX { class XLTable; + + /** + * @brief The XLTableColumnFormulaProxy class is used for proxy (or placeholder) objects for XLTableColumnd formulas objects. + * @details The XLTableColumnFormulaProxy class is used for proxy (or placeholder) objects forXLTableColumnd formulas objects. + * The purpose is to enable implicit conversion during assignment operations. XLTableColumnd formulas objects + * can not be constructed manually by the user, only through XLTableColumn objects. + */ + class OPENXLSX_EXPORT XLTableColumnFormulaProxy + { + friend class XLTableColumn; + + public: + //---------- Public Member Functions ----------// + + /** + * @brief Destructor + */ + ~XLTableColumnFormulaProxy(); + + /** + * @brief Copy assignment operator. + * @param other XLCellValueProxy object to be copied. + * @return A reference to the current object. + */ + XLTableColumnFormulaProxy& operator=(const XLTableColumnFormulaProxy& other); + + /** + * @brief Templated assignment operator + * @tparam T The type of numberValue assigned to the object. + * @param value The value. + * @return A reference to the current object. + */ + + XLTableColumnFormulaProxy& operator=(const std::string& formula) + { + setFormula(formula); + return *this; + } + + void set(const std::string& formula) + { + *this = formula; + } + + std::string get() const + { + return getFormula(); + } + + XLTableColumnFormulaProxy& clear(); + + /** + * @brief Set the cell value to a error state. + * @return A reference to the current object. + */ + XLTableColumnFormulaProxy& setError(const std::string & error); + + /** + * @brief Implicitly convert the XLCellValueProxy object to a XLCellValue object. + * @return An XLCellValue object, corresponding to the cell value. + */ + operator std::string(); // NOLINT + + /** + * @brief + * @tparam T + * @return + */ + operator std::string() const + { + return getFormula(); + } + + private: + //---------- Private Member Functions ---------- // + + /** + * @brief Constructor + * @param attr Pointer to the corresponding XML attribute object. + */ + XLTableColumnFormulaProxy(const XMLNode& dataNode, const std::string& attr); + + /** + * @brief Copy constructor + * @param other Object to be copied. + */ + XLTableColumnFormulaProxy(const XLTableColumnFormulaProxy& other); + + /** + * @brief Move constructor + * @param other Object to be moved. + */ + XLTableColumnFormulaProxy(XLTableColumnFormulaProxy&& other) noexcept; + + /** + * @brief Move assignment operator + * @param other Object to be moved + * @return Reference to moved-to pbject. + */ + XLTableColumnFormulaProxy& operator=(XLTableColumnFormulaProxy&& other) noexcept; + + /** + * @brief Set the cell to a string value. + * @param stringValue The value to be set. + */ + void setFormula(const std::string& stringValue); + + /** + * @brief Get a copy of the XLCellValue object for the cell. + * @return An XLCellValue object. + */ + std::string getFormula() const; + + //---------- Private Member Variables ---------- // + + std::shared_ptr m_node; /**< Pointer to corresponding XML attribute */ + std::string m_attribute; + }; // Class + + class OPENXLSX_EXPORT XLTableColumn { public: @@ -117,6 +237,9 @@ namespace OpenXLSX * @return function */ std::string totalsRowFunction() const; + XLTableColumnFormulaProxy& totalsRowFormula(); + + const XLTableColumnFormulaProxy& totalsRowFormula() const; /** * @brief clear the total row function of this columns and trigger the sheet update @@ -131,9 +254,16 @@ namespace OpenXLSX private: - std::unique_ptr m_dataNode; + std::shared_ptr m_dataNode; XLTable* m_table; + XLTableColumnFormulaProxy m_proxyTotal; + XLTableColumnFormulaProxy m_proxyColumn; + }; + + + + } // namespace OpenXLSX //#pragma warning(pop) diff --git a/OpenXLSX/sources/XLTable.cpp b/OpenXLSX/sources/XLTable.cpp index 7bf20772..7caadba2 100644 --- a/OpenXLSX/sources/XLTable.cpp +++ b/OpenXLSX/sources/XLTable.cpp @@ -228,6 +228,7 @@ void XLTable::setTotalVisible(bool visible) XLAutofilter XLTable::autofilter() { + // TODO implement auto filter and adjust header masking accordingly return XLAutofilter(m_pXmlData->getXmlDocument()->child("table").child("autoFilter"),m_pXmlData); } diff --git a/OpenXLSX/sources/XLTableColumn.cpp b/OpenXLSX/sources/XLTableColumn.cpp index 2bd0bd5b..2cf35dff 100644 --- a/OpenXLSX/sources/XLTableColumn.cpp +++ b/OpenXLSX/sources/XLTableColumn.cpp @@ -55,8 +55,10 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. using namespace OpenXLSX; XLTableColumn::XLTableColumn(const XMLNode& dataNode, XLTable* table): - m_dataNode(std::make_unique(dataNode)), - m_table(table) + m_dataNode(std::make_shared(dataNode)), + m_table(table), + m_proxyTotal(XLTableColumnFormulaProxy(dataNode,"totalsRowFunction")), + m_proxyColumn(XLTableColumnFormulaProxy(dataNode,"calculatedColumnFormula")) { /* TODO implement the followings m_name = m_dataNode->attribute("name").value(); @@ -80,13 +82,17 @@ XLTableColumn::XLTableColumn(const XMLNode& dataNode, XLTable* table): } XLTableColumn::XLTableColumn(const XLTableColumn& other) - : m_dataNode(other.m_dataNode ? std::make_unique(*other.m_dataNode) : nullptr), - m_table(other.m_table) + : m_dataNode(other.m_dataNode ? std::make_shared(*other.m_dataNode) : nullptr), + m_table(other.m_table), + m_proxyTotal(XLTableColumnFormulaProxy((*other.m_dataNode),"totalsRowFunction")), + m_proxyColumn(XLTableColumnFormulaProxy((*other.m_dataNode),"calculatedColumnFormula")) {} XLTableColumn::XLTableColumn(XLTableColumn&& other) noexcept : m_dataNode(std::move(other.m_dataNode)), - m_table(other.m_table) + m_table(other.m_table), + m_proxyTotal(std::move(other.m_proxyTotal)), + m_proxyColumn( std::move(other.m_proxyColumn)) {} @@ -133,6 +139,18 @@ void XLTableColumn::clearTotalsRowFunction() setTotalsRowFunction(std::string()); } +XLTableColumnFormulaProxy& XLTableColumn::totalsRowFormula() +{ + auto node = m_dataNode->attribute("totalsRowFunction"); + + if (!node) + node = m_dataNode->append_attribute("totalsRowFunction"); + + return m_proxyTotal; + //return std::string(m_dataNode->attribute("totalsRowFunction").value()); + +} + void XLTableColumn::setTotalsRowFunction(const std::string& function) { // TODO implement @@ -161,3 +179,163 @@ void XLTableColumn::setTotalsRowFunction(const std::string& function) } + +///////////////////////////////////////////////////////////////////////////////////////// +// +// XLTableColumnFormulaProxy +// +///////////////////////////////////////////////////////////////////////////////////////// + + +/** + * @details Constructor + * @pre The attr pointer must not be nullptr and must point to valid objects. + * @post A valid XLCellValueProxy has been created. + */ +XLTableColumnFormulaProxy::XLTableColumnFormulaProxy(const XMLNode& node, const std::string& attr) + : m_node(std::make_shared(node)), m_attribute(attr) +{ + assert(node); // NOLINT +} + +/** + * @details Destructor. Default implementation has been used. + * @pre + * @post + */ +XLTableColumnFormulaProxy::~XLTableColumnFormulaProxy() = default; + +/** + * @details Copy constructor. Default implementation has been used. + * @pre + * @post + */ +XLTableColumnFormulaProxy::XLTableColumnFormulaProxy(const XLTableColumnFormulaProxy& other) + : m_node(other.m_node ? std::make_shared(*other.m_node) : nullptr), + m_attribute(other.m_attribute) +{} + +/** + * @details Move constructor. Default implementation has been used. + * @pre + * @post + */ +XLTableColumnFormulaProxy::XLTableColumnFormulaProxy(XLTableColumnFormulaProxy&& other) noexcept + : m_node(std::move(other.m_node)), + m_attribute(std::move(other.m_attribute)) +{} + +/** + * @details Copy assignment operator. The function is implemented in terms of the templated + * value assignment operators, i.e. it is the XLCellValue that is that is copied, + * not the object itself. + * @pre + * @post + */ +XLTableColumnFormulaProxy& XLTableColumnFormulaProxy::operator=(const XLTableColumnFormulaProxy& other) +{ + if (&other != this) { + *this = other.getFormula(); + } + + return *this; +} + +/** + * @details Move assignment operator. Default implementation has been used. + * @pre + * @post + */ +XLTableColumnFormulaProxy& XLTableColumnFormulaProxy::operator=(XLTableColumnFormulaProxy&& other) noexcept = default; + +/** + * @details Implicitly convert the XLCellValueProxy object to a std::string. + * @pre + * @post + */ +XLTableColumnFormulaProxy::operator std::string() +{ + return getFormula(); +} + +/** + * @details Clear the contents of the cell. This removes all children of the cell node. + * @pre The m_cellNode must not be null, and must point to a valid XML cell node object. + * @post The cell node must be valid, but empty. + */ +XLTableColumnFormulaProxy& XLTableColumnFormulaProxy::clear() +{ + // ===== Check that the m_attribute is valid. + assert(m_node); // NOLINT +/* + // ===== Remove the type attribute + m_cellNode->remove_attribute("t"); + + // ===== Disable space preservation (only relevant for strings). + m_cellNode->remove_attribute(" xml:space"); + + // ===== Remove the value node. + m_cellNode->remove_child("v"); +*/ + return *this; +} +/** + * @details Set the cell value to a error state. This will remove all children and attributes, except + * the type attribute, which is set to "e" + * @pre The m_cellNode must not be null, and must point to a valid XML cell node object. + * @post The cell node must be valid. + */ +XLTableColumnFormulaProxy& XLTableColumnFormulaProxy::setError(const std::string &error) +{ + // ===== Check that the m_cellNode is valid. + assert(m_node); // NOLINT + +/* + // ===== If the cell node doesn't have a type attribute, create it. + if (!m_cellNode->attribute("t")) m_cellNode->append_attribute("t"); + + // ===== Set the type to "e", i.e. error + m_cellNode->attribute("t").set_value("e"); + + // ===== If the cell node doesn't have a value child node, create it. + if (!m_cellNode->child("v")) m_cellNode->append_child("v"); + + // ===== Set the child value to the error + m_cellNode->child("v").text().set(error.c_str()); + + // ===== Disable space preservation (only relevant for strings). + m_cellNode->remove_attribute(" xml:space"); +*/ + return *this; +} + +/** + * @details Set the the formula in the corresponding attribute. + * This is private helper function for setting the attr + * directly in the underlying XML file. + * @pre The m_attribute must not be null, and must point to a valid XMLNode object. + * @post The underlying attribute has been updated correctly, representing a string value. + */ +void XLTableColumnFormulaProxy::setFormula(const std::string& formula) +{ + // ===== Check that the m_cellNode is valid. + assert(m_node); // NOLINT + + m_node->attribute(m_attribute.c_str()).set_value(formula.c_str()); +} + +/** + * @details Get a copy of the XLCellValue object for the cell. This is private helper function for returning an + * XLCellValue object corresponding to the cell value. + * @pre The m_cellNode must not be null, and must point to a valid XMLNode object. + * @post No changes should be made. + */ +std::string XLTableColumnFormulaProxy::getFormula() const +{ + // ===== Check that the m_attribute is valid. + assert(m_node); // NOLINT + + return std::string(m_node->attribute(m_attribute.c_str()).value()); +} + + From 1b5a2f208a10a92488d60f75a5da2bb52772ea77 Mon Sep 17 00:00:00 2001 From: akira215 Date: Tue, 3 Jan 2023 18:28:04 +0100 Subject: [PATCH 22/45] implementation of proxy for tablecolumn formulas --- Examples/Demo10.cpp | 6 +- OpenXLSX/headers/XLTable.hpp | 9 +- OpenXLSX/headers/XLTableColumn.hpp | 48 ++++----- OpenXLSX/sources/XLTable.cpp | 16 ++- OpenXLSX/sources/XLTableColumn.cpp | 156 ++++++++++++----------------- 5 files changed, 110 insertions(+), 125 deletions(-) diff --git a/Examples/Demo10.cpp b/Examples/Demo10.cpp index 4af36bc9..89bf25b8 100644 --- a/Examples/Demo10.cpp +++ b/Examples/Demo10.cpp @@ -77,9 +77,13 @@ int main() { //tbl.setHeaderVisible(false); tbl.setTotalVisible(true); //tbl.column("Table")->setTotalsRowFunction("sum"); - tbl.column("Table").setTotalsRowFunction(""); + //tbl.column("Table").setTotalsRowFunction(""); //tbl.column("Table").setTotalsRowFunction("count"); tbl.column("Table").totalsRowFormula() ="sum"; + std::string totaFormula = tbl.column("Table").totalsRowFormula(); + cout << "total Formula in the table column : " << totaFormula << endl; + + tbl.column("Table").totalsRowFormula() =""; cout << "Table Style : " << tbl.tableStyle().style() << endl; tbl.tableStyle().setStyle("TableStyleDark7"); diff --git a/OpenXLSX/headers/XLTable.hpp b/OpenXLSX/headers/XLTable.hpp index 69a8c7d1..6fa9e548 100644 --- a/OpenXLSX/headers/XLTable.hpp +++ b/OpenXLSX/headers/XLTable.hpp @@ -66,6 +66,7 @@ namespace OpenXLSX class OPENXLSX_EXPORT XLTable { friend class XLTableColumn; + friend class XLTableColumnFormulaProxy; friend class XLTableStyle; public: @@ -205,11 +206,17 @@ namespace OpenXLSX // Protected //---------------------------------------------------------------------------------------------------------------------- protected: + /** + * @brief set the formulas in the worksheet for the total row + * @param attribute of the forumla to be set + */ + void setFormulas(const std::string& attribute) const; + /** * @brief set the formulas in the worksheet for the total row * the formulas is based on the attribute totalsRowFunction of each col */ - void setTotalFormulas(); + void setTotalFormulas() const; /** * @brief Adjust the ref according to m_dataBodyRange diff --git a/OpenXLSX/headers/XLTableColumn.hpp b/OpenXLSX/headers/XLTableColumn.hpp index 8cb77cbb..44431493 100644 --- a/OpenXLSX/headers/XLTableColumn.hpp +++ b/OpenXLSX/headers/XLTableColumn.hpp @@ -91,15 +91,10 @@ namespace OpenXLSX /** * @brief Templated assignment operator * @tparam T The type of numberValue assigned to the object. - * @param value The value. + * @param formula The formula to be set * @return A reference to the current object. - */ - - XLTableColumnFormulaProxy& operator=(const std::string& formula) - { - setFormula(formula); - return *this; - } + */ + XLTableColumnFormulaProxy& operator=(const std::string& formula); void set(const std::string& formula) { @@ -120,17 +115,16 @@ namespace OpenXLSX XLTableColumnFormulaProxy& setError(const std::string & error); /** - * @brief Implicitly convert the XLCellValueProxy object to a XLCellValue object. - * @return An XLCellValue object, corresponding to the cell value. + * @brief Implicitly convert the XLTableColumnFormulaProxy object to a string object. + * @return a string corresponding to the formula. */ operator std::string(); // NOLINT /** - * @brief - * @tparam T - * @return + * @brief Implicitly convert the XLTableColumnFormulaProxy object to a string object. + * @return a string corresponding to the formula. */ - operator std::string() const + operator std::string () const { return getFormula(); } @@ -142,7 +136,8 @@ namespace OpenXLSX * @brief Constructor * @param attr Pointer to the corresponding XML attribute object. */ - XLTableColumnFormulaProxy(const XMLNode& dataNode, const std::string& attr); + XLTableColumnFormulaProxy(const XMLNode& dataNode, + const std::string& attr, const XLTable& table); /** * @brief Copy constructor @@ -178,7 +173,8 @@ namespace OpenXLSX //---------- Private Member Variables ---------- // std::shared_ptr m_node; /**< Pointer to corresponding XML attribute */ - std::string m_attribute; + std::string m_attribute; + const XLTable& m_table; }; // Class @@ -189,7 +185,7 @@ namespace OpenXLSX * @brief The constructor. * @param dataNode XMLNode of the column */ - XLTableColumn(const XMLNode& dataNode, XLTable* table); + XLTableColumn(const XMLNode& dataNode, const XLTable& table); /** * @brief Copy Constructor @@ -233,12 +229,15 @@ namespace OpenXLSX void setName(const std::string& name) const; /** - * @brief - * @return function + * @brief the getter setter function + * @return return a XLTableColumnFormulaProxy ref which could be implicitely convert to string */ - std::string totalsRowFunction() const; XLTableColumnFormulaProxy& totalsRowFormula(); + /** + * @brief the getter setter function + * @return return a XLTableColumnFormulaProxy ref which could be implicitely convert to string + */ const XLTableColumnFormulaProxy& totalsRowFormula() const; /** @@ -246,16 +245,9 @@ namespace OpenXLSX */ void clearTotalsRowFunction(); - /** - * @brief - * @param function function to be set. use empty string to remove function,or "none"if function is not know, nothing is done - */ - void setTotalsRowFunction(const std::string& function); - - private: std::shared_ptr m_dataNode; - XLTable* m_table; + const XLTable& m_table; XLTableColumnFormulaProxy m_proxyTotal; XLTableColumnFormulaProxy m_proxyColumn; diff --git a/OpenXLSX/sources/XLTable.cpp b/OpenXLSX/sources/XLTable.cpp index 7caadba2..9509eef6 100644 --- a/OpenXLSX/sources/XLTable.cpp +++ b/OpenXLSX/sources/XLTable.cpp @@ -82,7 +82,7 @@ XLTable::XLTable(XLXmlData* xmlData) XMLNode pTblColumns = m_pXmlData->getXmlDocument()->child("table").child("tableColumns"); for (const XMLNode& col : pTblColumns.children()) - m_columns.push_back(XLTableColumn(col, this)); + m_columns.push_back(XLTableColumn(col, *this)); } @@ -266,7 +266,17 @@ void XLTable::setName(const std::string& tableName) } -void XLTable::setTotalFormulas() + +void XLTable::setFormulas(const std::string& attribute) const +{ + if (attribute=="totalsRowFunction") + setTotalFormulas(); + else if (attribute=="calculatedColumnFormula") + throw "to be implemented"; + +} + +void XLTable::setTotalFormulas() const { if (!isTotalVisible()) return; @@ -275,7 +285,7 @@ void XLTable::setTotalFormulas() uint16_t totalCol = m_dataBodyRange.rangeCoordinates().first.column(); for (auto& col: m_columns){ - std::string colFunc = col.totalsRowFunction(); + std::string colFunc = col.totalsRowFormula(); if (colFunc.empty()){ // if there is nothing, remove formula and values m_sheet.cell(totalRow, totalCol).formula().clear(); m_sheet.cell(totalRow, totalCol).value().clear(); diff --git a/OpenXLSX/sources/XLTableColumn.cpp b/OpenXLSX/sources/XLTableColumn.cpp index 2cf35dff..954fcd30 100644 --- a/OpenXLSX/sources/XLTableColumn.cpp +++ b/OpenXLSX/sources/XLTableColumn.cpp @@ -54,15 +54,18 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. #include "XLTable.hpp" using namespace OpenXLSX; -XLTableColumn::XLTableColumn(const XMLNode& dataNode, XLTable* table): +XLTableColumn::XLTableColumn(const XMLNode& dataNode, const XLTable& table): m_dataNode(std::make_shared(dataNode)), m_table(table), - m_proxyTotal(XLTableColumnFormulaProxy(dataNode,"totalsRowFunction")), - m_proxyColumn(XLTableColumnFormulaProxy(dataNode,"calculatedColumnFormula")) + m_proxyTotal(XLTableColumnFormulaProxy(dataNode,"totalsRowFunction", table)), + m_proxyColumn(XLTableColumnFormulaProxy(dataNode,"calculatedColumnFormula", table)) { + // TODO implement + // TODO implement == custom function + /* TODO implement the followings - m_name = m_dataNode->attribute("name").value(); - m_xr3uid = m_dataNode->attribute("xr3:uid").value(); + + m_dataCellStyle = m_dataNode->attribute("dataCellStyle").value(); m_headerRowCellStyle= m_dataNode->attribute("headerRowCellStyle").value(); m_totalsRowFunction = m_dataNode->attribute("totalsRowFunction").value(); @@ -84,8 +87,8 @@ XLTableColumn::XLTableColumn(const XMLNode& dataNode, XLTable* table): XLTableColumn::XLTableColumn(const XLTableColumn& other) : m_dataNode(other.m_dataNode ? std::make_shared(*other.m_dataNode) : nullptr), m_table(other.m_table), - m_proxyTotal(XLTableColumnFormulaProxy((*other.m_dataNode),"totalsRowFunction")), - m_proxyColumn(XLTableColumnFormulaProxy((*other.m_dataNode),"calculatedColumnFormula")) + m_proxyTotal(XLTableColumnFormulaProxy((*other.m_dataNode),"totalsRowFunction", other.m_table)), + m_proxyColumn(XLTableColumnFormulaProxy((*other.m_dataNode),"calculatedColumnFormula", other.m_table)) {} XLTableColumn::XLTableColumn(XLTableColumn&& other) noexcept @@ -111,7 +114,6 @@ XLTableColumn& XLTableColumn::operator=(XLTableColumn&& other) noexcept { if (&other != this) { m_dataNode = std::move(other.m_dataNode); - m_table = other.m_table; } return *this; } @@ -129,57 +131,21 @@ void XLTableColumn::setName(const std::string& columnName) const // TODO change the formulas in the sheet } -std::string XLTableColumn::totalsRowFunction() const -{ - return std::string(m_dataNode->attribute("totalsRowFunction").value()); -} - void XLTableColumn::clearTotalsRowFunction() { - setTotalsRowFunction(std::string()); + m_proxyTotal.clear(); } XLTableColumnFormulaProxy& XLTableColumn::totalsRowFormula() { - auto node = m_dataNode->attribute("totalsRowFunction"); - - if (!node) - node = m_dataNode->append_attribute("totalsRowFunction"); - return m_proxyTotal; - //return std::string(m_dataNode->attribute("totalsRowFunction").value()); - } -void XLTableColumn::setTotalsRowFunction(const std::string& function) +const XLTableColumnFormulaProxy& XLTableColumn::totalsRowFormula() const { - // TODO implement - // TODO implement == custom function - auto node = m_dataNode->attribute("totalsRowFunction"); - if(!node) - node = m_dataNode->append_attribute("totalsRowFunction"); - - // If empty string, we remove the formula - if(function.empty()){ - m_dataNode->remove_attribute("totalsRowFunction"); - m_table->setTotalFormulas(); - return; - } - - // check if the formula is allowed otherwise quit - auto it = std::find(std::begin(XLTemplate::totalsRowFunctionList), - std::end(XLTemplate::totalsRowFunctionList), function); - if( it == std::end(XLTemplate::totalsRowFunctionList)) - return; - - node.set_value(function.c_str()); - - // Update the fonctions in the worksheet - m_table->setTotalFormulas(); - + return m_proxyTotal; } - ///////////////////////////////////////////////////////////////////////////////////////// // // XLTableColumnFormulaProxy @@ -192,8 +158,10 @@ void XLTableColumn::setTotalsRowFunction(const std::string& function) * @pre The attr pointer must not be nullptr and must point to valid objects. * @post A valid XLCellValueProxy has been created. */ -XLTableColumnFormulaProxy::XLTableColumnFormulaProxy(const XMLNode& node, const std::string& attr) - : m_node(std::make_shared(node)), m_attribute(attr) +XLTableColumnFormulaProxy::XLTableColumnFormulaProxy(const XMLNode& node, const std::string& attr, const XLTable& table ) + : m_node(std::make_shared(node)), + m_attribute(attr), + m_table(table) { assert(node); // NOLINT } @@ -212,7 +180,8 @@ XLTableColumnFormulaProxy::~XLTableColumnFormulaProxy() = default; */ XLTableColumnFormulaProxy::XLTableColumnFormulaProxy(const XLTableColumnFormulaProxy& other) : m_node(other.m_node ? std::make_shared(*other.m_node) : nullptr), - m_attribute(other.m_attribute) + m_attribute(other.m_attribute), + m_table(other.m_table) {} /** @@ -222,7 +191,8 @@ XLTableColumnFormulaProxy::XLTableColumnFormulaProxy(const XLTableColumnFormulaP */ XLTableColumnFormulaProxy::XLTableColumnFormulaProxy(XLTableColumnFormulaProxy&& other) noexcept : m_node(std::move(other.m_node)), - m_attribute(std::move(other.m_attribute)) + m_attribute(std::move(other.m_attribute)), + m_table(std::move(other.m_table)) {} /** @@ -241,12 +211,28 @@ XLTableColumnFormulaProxy& XLTableColumnFormulaProxy::operator=(const XLTableCol return *this; } +XLTableColumnFormulaProxy& XLTableColumnFormulaProxy::operator=(const std::string& formula) +{ + setFormula(formula); + m_table.setFormulas(m_attribute); + return *this; +} + + /** * @details Move assignment operator. Default implementation has been used. * @pre * @post */ -XLTableColumnFormulaProxy& XLTableColumnFormulaProxy::operator=(XLTableColumnFormulaProxy&& other) noexcept = default; +XLTableColumnFormulaProxy& XLTableColumnFormulaProxy::operator=(XLTableColumnFormulaProxy&& other) noexcept +{ + if (&other != this) { + m_node = std::move(other.m_node); + m_attribute = std::move(other.m_attribute); + } + + return *this; +} /** * @details Implicitly convert the XLCellValueProxy object to a std::string. @@ -267,45 +253,9 @@ XLTableColumnFormulaProxy& XLTableColumnFormulaProxy::clear() { // ===== Check that the m_attribute is valid. assert(m_node); // NOLINT -/* - // ===== Remove the type attribute - m_cellNode->remove_attribute("t"); - - // ===== Disable space preservation (only relevant for strings). - m_cellNode->remove_attribute(" xml:space"); - - // ===== Remove the value node. - m_cellNode->remove_child("v"); -*/ - return *this; -} -/** - * @details Set the cell value to a error state. This will remove all children and attributes, except - * the type attribute, which is set to "e" - * @pre The m_cellNode must not be null, and must point to a valid XML cell node object. - * @post The cell node must be valid. - */ -XLTableColumnFormulaProxy& XLTableColumnFormulaProxy::setError(const std::string &error) -{ - // ===== Check that the m_cellNode is valid. - assert(m_node); // NOLINT - -/* - // ===== If the cell node doesn't have a type attribute, create it. - if (!m_cellNode->attribute("t")) m_cellNode->append_attribute("t"); - - // ===== Set the type to "e", i.e. error - m_cellNode->attribute("t").set_value("e"); - - // ===== If the cell node doesn't have a value child node, create it. - if (!m_cellNode->child("v")) m_cellNode->append_child("v"); - - // ===== Set the child value to the error - m_cellNode->child("v").text().set(error.c_str()); - - // ===== Disable space preservation (only relevant for strings). - m_cellNode->remove_attribute(" xml:space"); -*/ + m_node->remove_attribute(m_attribute.c_str()); + m_table.setTotalFormulas(); + return *this; } @@ -320,8 +270,29 @@ void XLTableColumnFormulaProxy::setFormula(const std::string& formula) { // ===== Check that the m_cellNode is valid. assert(m_node); // NOLINT + auto node = m_node->attribute(m_attribute.c_str()); + if (!node) + node = m_node->append_attribute(m_attribute.c_str()); + + // If empty string, we remove the formula + if(formula.empty()){ + clear(); + return; + } + + if(m_attribute == "totalsRowFunction"){ + // check if the formula is allowed otherwise quit + // TODO check for custom formula + auto it = std::find(std::begin(XLTemplate::totalsRowFunctionList), + std::end(XLTemplate::totalsRowFunctionList), formula); + if( it == std::end(XLTemplate::totalsRowFunctionList)){ + XLLogError("The formula \"" + formula + "\" is not available for total Row function"); + return; + } + } m_node->attribute(m_attribute.c_str()).set_value(formula.c_str()); + } /** @@ -334,7 +305,8 @@ std::string XLTableColumnFormulaProxy::getFormula() const { // ===== Check that the m_attribute is valid. assert(m_node); // NOLINT - + assert(m_node->attribute(m_attribute.c_str())); + return std::string(m_node->attribute(m_attribute.c_str()).value()); } From 0e5bfcb15aa5dc61292d471a666985fa3afd9619 Mon Sep 17 00:00:00 2001 From: akira215 Date: Tue, 3 Jan 2023 23:07:43 +0100 Subject: [PATCH 23/45] finishing table formulas --- Examples/Demo10.cpp | 9 +- OpenXLSX/headers/XLCell.hpp | 2 +- OpenXLSX/headers/XLCellValue.hpp | 4 +- OpenXLSX/headers/XLFormula.hpp | 5 +- OpenXLSX/headers/XLTable.hpp | 7 +- OpenXLSX/headers/XLTableColumn.hpp | 163 ++++++++++++++++++++++++----- OpenXLSX/sources/XLCell.cpp | 22 ++-- OpenXLSX/sources/XLCellValue.cpp | 2 +- OpenXLSX/sources/XLFormula.cpp | 2 +- OpenXLSX/sources/XLTable.cpp | 22 +++- OpenXLSX/sources/XLTableColumn.cpp | 161 ++++++++++++++++++++-------- 11 files changed, 303 insertions(+), 96 deletions(-) diff --git a/Examples/Demo10.cpp b/Examples/Demo10.cpp index 89bf25b8..600aa67b 100644 --- a/Examples/Demo10.cpp +++ b/Examples/Demo10.cpp @@ -75,16 +75,23 @@ int main() { // Also show the total with selected function tbl.autofilter().hideArrows(); //tbl.setHeaderVisible(false); + + // Total formulas tbl.setTotalVisible(true); //tbl.column("Table")->setTotalsRowFunction("sum"); //tbl.column("Table").setTotalsRowFunction(""); //tbl.column("Table").setTotalsRowFunction("count"); tbl.column("Table").totalsRowFormula() ="sum"; - std::string totaFormula = tbl.column("Table").totalsRowFormula(); + string totaFormula = tbl.column("Table").totalsRowFormula(); cout << "total Formula in the table column : " << totaFormula << endl; tbl.column("Table").totalsRowFormula() =""; + // Columns formulas + tbl.column("With").columnFormula() = "MyTable[[#This Row],['#]]*2"; + string columFormula = tbl.column("With").columnFormula(); + cout << "Column Formula : " << columFormula << endl; + cout << "Table Style : " << tbl.tableStyle().style() << endl; tbl.tableStyle().setStyle("TableStyleDark7"); diff --git a/OpenXLSX/headers/XLCell.hpp b/OpenXLSX/headers/XLCell.hpp index b1d2acb1..a6d4ef18 100644 --- a/OpenXLSX/headers/XLCell.hpp +++ b/OpenXLSX/headers/XLCell.hpp @@ -193,7 +193,7 @@ namespace OpenXLSX static bool isEqual(const XLCell& lhs, const XLCell& rhs); //---------- Private Member Variables ---------- // - std::unique_ptr m_cellNode; /**< A pointer to the root XMLNode for the cell. */ + std::shared_ptr m_cellNode; /**< A pointer to the root XMLNode for the cell. */ const XLWorksheet* m_worksheet; XLCellValueProxy m_valueProxy; /**< */ XLFormulaProxy m_formulaProxy; /**< */ diff --git a/OpenXLSX/headers/XLCellValue.hpp b/OpenXLSX/headers/XLCellValue.hpp index 7600442b..38c14518 100644 --- a/OpenXLSX/headers/XLCellValue.hpp +++ b/OpenXLSX/headers/XLCellValue.hpp @@ -483,7 +483,7 @@ namespace OpenXLSX * @param cell Pointer to the parent XLCell object. * @param cellNode Pointer to the corresponding XMLNode object. */ - XLCellValueProxy(XLCell* cell, XMLNode* cellNode); + XLCellValueProxy(XLCell* cell, std::shared_ptr cellNode); /** * @brief Copy constructor @@ -543,7 +543,7 @@ namespace OpenXLSX //---------- Private Member Variables ---------- // XLCell* m_cell; /**< Pointer to the owning XLCell object. */ - XMLNode* m_cellNode; /**< Pointer to corresponding XML cell node. */ + std::shared_ptr m_cellNode; /**< Pointer to corresponding XML cell node. */ }; } // namespace OpenXLSX diff --git a/OpenXLSX/headers/XLFormula.hpp b/OpenXLSX/headers/XLFormula.hpp index 21326fbd..86bfa815 100644 --- a/OpenXLSX/headers/XLFormula.hpp +++ b/OpenXLSX/headers/XLFormula.hpp @@ -55,6 +55,7 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. #include #include #include +#include // ===== OpenXLSX Includes ===== // #include "OpenXLSX-Exports.hpp" @@ -285,7 +286,7 @@ namespace OpenXLSX * @param cell Pointer to the associated cell object. * @param cellNode Pointer to the associated cell node object. */ - XLFormulaProxy(XLCell* cell, XMLNode* cellNode); + XLFormulaProxy(XLCell* cell, std::shared_ptr cellNode); /** * @brief Copy constructor. @@ -321,7 +322,7 @@ namespace OpenXLSX //---------- Private Member Variables ---------- // XLCell* m_cell; /**< Pointer to the owning XLCell object. */ - XMLNode* m_cellNode; /**< Pointer to corresponding XML cell node. */ + std::shared_ptr m_cellNode; /**< Pointer to corresponding XML cell node. */ }; } // namespace OpenXLSX diff --git a/OpenXLSX/headers/XLTable.hpp b/OpenXLSX/headers/XLTable.hpp index 6fa9e548..761e218c 100644 --- a/OpenXLSX/headers/XLTable.hpp +++ b/OpenXLSX/headers/XLTable.hpp @@ -66,6 +66,7 @@ namespace OpenXLSX class OPENXLSX_EXPORT XLTable { friend class XLTableColumn; + friend class XLTableColumnTotalProxy; friend class XLTableColumnFormulaProxy; friend class XLTableStyle; @@ -207,13 +208,13 @@ namespace OpenXLSX //---------------------------------------------------------------------------------------------------------------------- protected: /** - * @brief set the formulas in the worksheet for the total row + * @brief set the formulas in the worksheet for all the columns * @param attribute of the forumla to be set */ - void setFormulas(const std::string& attribute) const; + void setColumnFormulas() const; /** - * @brief set the formulas in the worksheet for the total row + * @brief set the formulas in the worksheet for the all the total row * the formulas is based on the attribute totalsRowFunction of each col */ void setTotalFormulas() const; diff --git a/OpenXLSX/headers/XLTableColumn.hpp b/OpenXLSX/headers/XLTableColumn.hpp index 44431493..6c6e6053 100644 --- a/OpenXLSX/headers/XLTableColumn.hpp +++ b/OpenXLSX/headers/XLTableColumn.hpp @@ -57,6 +57,7 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. // ===== OpenXLSX Includes ===== // #include "OpenXLSX-Exports.hpp" #include "XLXmlParser.hpp" +#include "XLCellRange.hpp" namespace OpenXLSX { @@ -69,7 +70,7 @@ namespace OpenXLSX * The purpose is to enable implicit conversion during assignment operations. XLTableColumnd formulas objects * can not be constructed manually by the user, only through XLTableColumn objects. */ - class OPENXLSX_EXPORT XLTableColumnFormulaProxy + class OPENXLSX_EXPORT XLTableColumnProxy { friend class XLTableColumn; @@ -79,14 +80,14 @@ namespace OpenXLSX /** * @brief Destructor */ - ~XLTableColumnFormulaProxy(); + ~XLTableColumnProxy(); /** * @brief Copy assignment operator. * @param other XLCellValueProxy object to be copied. * @return A reference to the current object. */ - XLTableColumnFormulaProxy& operator=(const XLTableColumnFormulaProxy& other); + XLTableColumnProxy& operator=(const XLTableColumnProxy& other); /** * @brief Templated assignment operator @@ -94,7 +95,7 @@ namespace OpenXLSX * @param formula The formula to be set * @return A reference to the current object. */ - XLTableColumnFormulaProxy& operator=(const std::string& formula); + virtual XLTableColumnProxy& operator=(const std::string& formula) = 0; void set(const std::string& formula) { @@ -106,75 +107,162 @@ namespace OpenXLSX return getFormula(); } - XLTableColumnFormulaProxy& clear(); + //XLTableColumnProxy& clear(); /** * @brief Set the cell value to a error state. * @return A reference to the current object. */ - XLTableColumnFormulaProxy& setError(const std::string & error); + XLTableColumnProxy& setError(const std::string & error); /** - * @brief Implicitly convert the XLTableColumnFormulaProxy object to a string object. + * @brief Implicitly convert the XLTableColumnProxy object to a string object. * @return a string corresponding to the formula. */ - operator std::string(); // NOLINT + operator std::string() { return getFormula(); }; // NOLINT /** - * @brief Implicitly convert the XLTableColumnFormulaProxy object to a string object. + * @brief Implicitly convert the XLTableColumnProxy object to a string object. * @return a string corresponding to the formula. */ - operator std::string () const - { - return getFormula(); - } + operator std::string () const { return getFormula(); }; - private: + protected: //---------- Private Member Functions ---------- // /** * @brief Constructor * @param attr Pointer to the corresponding XML attribute object. */ - XLTableColumnFormulaProxy(const XMLNode& dataNode, + XLTableColumnProxy(const XMLNode& dataNode, const std::string& attr, const XLTable& table); /** * @brief Copy constructor * @param other Object to be copied. */ - XLTableColumnFormulaProxy(const XLTableColumnFormulaProxy& other); + XLTableColumnProxy(const XLTableColumnProxy& other); /** * @brief Move constructor * @param other Object to be moved. */ - XLTableColumnFormulaProxy(XLTableColumnFormulaProxy&& other) noexcept; + XLTableColumnProxy(XLTableColumnProxy&& other) noexcept; /** * @brief Move assignment operator * @param other Object to be moved * @return Reference to moved-to pbject. */ - XLTableColumnFormulaProxy& operator=(XLTableColumnFormulaProxy&& other) noexcept; + XLTableColumnProxy& operator=(XLTableColumnProxy&& other) noexcept; /** * @brief Set the cell to a string value. - * @param stringValue The value to be set. + * @param formula The value to be set. */ - void setFormula(const std::string& stringValue); + virtual void setFormula(const std::string& formula) = 0; /** * @brief Get a copy of the XLCellValue object for the cell. * @return An XLCellValue object. */ - std::string getFormula() const; + virtual std::string getFormula() const = 0; //---------- Private Member Variables ---------- // std::shared_ptr m_node; /**< Pointer to corresponding XML attribute */ std::string m_attribute; const XLTable& m_table; + }; // Class + + class OPENXLSX_EXPORT XLTableColumnTotalProxy : public XLTableColumnProxy + { + friend class XLTableColumn; + + public: + //---------- Public Member Functions ----------// + + /** + * @brief Destructor + */ + ~XLTableColumnTotalProxy()= default; + + /** + * @brief Templated assignment operator + * @param formula The formula to be set + * @return A reference to the current object. + */ + XLTableColumnProxy& operator=(const std::string& formula); + + void clear(); + + private: + //---------- Private Member Functions ---------- // + + /** + * @brief Constructor + * @param attr Pointer to the corresponding XML attribute object. + */ + XLTableColumnTotalProxy(const XMLNode& dataNode, + const std::string& attr, const XLTable& table) + : XLTableColumnProxy(dataNode, attr,table) {}; + + /** + * @brief Set the cell to a string value. + * @param formula The value to be set. + */ + void setFormula(const std::string& formula); + + /** + * @brief Get a copy of the XLCellValue object for the cell. + * @return An XLCellValue object. + */ + std::string getFormula() const; + }; // Class + + class OPENXLSX_EXPORT XLTableColumnFormulaProxy : public XLTableColumnProxy + { + friend class XLTableColumn; + + public: + //---------- Public Member Functions ----------// + + /** + * @brief Destructor + */ + ~XLTableColumnFormulaProxy()= default; + + /** + * @brief Templated assignment operator + * @param formula The formula to be set + * @return A reference to the current object. + */ + XLTableColumnProxy& operator=(const std::string& formula); + + void clear(); + + private: + //---------- Private Member Functions ---------- // + + /** + * @brief Constructor + * @param attr Pointer to the corresponding XML attribute object. + */ + XLTableColumnFormulaProxy(const XMLNode& dataNode, + const std::string& attr, const XLTable& table) + : XLTableColumnProxy(dataNode, attr,table) {}; + + /** + * @brief Set the cell to a string value. + * @param formula The value to be set. + */ + void setFormula(const std::string& formula); + + /** + * @brief Get a copy of the XLCellValue object for the cell. + * @return An XLCellValue object. + */ + std::string getFormula() const; }; // Class @@ -230,25 +318,48 @@ namespace OpenXLSX /** * @brief the getter setter function - * @return return a XLTableColumnFormulaProxy ref which could be implicitely convert to string + * @return return a XLTableColumnProxy ref which could be implicitely convert to string */ - XLTableColumnFormulaProxy& totalsRowFormula(); + XLTableColumnProxy& totalsRowFormula(); + + /** + * @brief the getter setter function + * @return return a XLTableColumnProxy ref which could be implicitely convert to string + */ + const XLTableColumnProxy& totalsRowFormula() const; + + /** + * @brief clear the total row function of this columns and trigger the sheet update + */ + void clearTotalsRowFormula(); + + /** + * @brief the getter setter function + * @return return a XLTableColumnProxy ref which could be implicitely convert to string + */ + XLTableColumnFormulaProxy& columnFormula(); /** * @brief the getter setter function * @return return a XLTableColumnFormulaProxy ref which could be implicitely convert to string */ - const XLTableColumnFormulaProxy& totalsRowFormula() const; + const XLTableColumnFormulaProxy& columnFormula() const; /** * @brief clear the total row function of this columns and trigger the sheet update */ - void clearTotalsRowFunction(); + void clearColumnFormula(); + + /** + * @brief get the body range of the cell + * @return an XLCellReference of the body range of the column + */ + XLCellRange bodyRange() const; private: std::shared_ptr m_dataNode; const XLTable& m_table; - XLTableColumnFormulaProxy m_proxyTotal; + XLTableColumnTotalProxy m_proxyTotal; XLTableColumnFormulaProxy m_proxyColumn; }; diff --git a/OpenXLSX/sources/XLCell.cpp b/OpenXLSX/sources/XLCell.cpp index d7509a0f..41190e60 100644 --- a/OpenXLSX/sources/XLCell.cpp +++ b/OpenXLSX/sources/XLCell.cpp @@ -60,8 +60,8 @@ using namespace OpenXLSX; XLCell::XLCell() : m_cellNode(nullptr), m_worksheet(nullptr), - m_valueProxy(XLCellValueProxy(this, m_cellNode.get())), - m_formulaProxy(XLFormulaProxy(this, m_cellNode.get())) + m_valueProxy(XLCellValueProxy(this, m_cellNode)), + m_formulaProxy(XLFormulaProxy(this, m_cellNode)) {} /** @@ -71,20 +71,20 @@ XLCell::XLCell() * from a XLCellReference parameter. */ XLCell::XLCell(const XMLNode& cellNode, const XLWorksheet* wks) - : m_cellNode(std::make_unique(cellNode)), + : m_cellNode(std::make_shared(cellNode)), m_worksheet(wks), - m_valueProxy(XLCellValueProxy(this, m_cellNode.get())), - m_formulaProxy(XLFormulaProxy(this, m_cellNode.get())) + m_valueProxy(XLCellValueProxy(this, m_cellNode)), + m_formulaProxy(XLFormulaProxy(this, m_cellNode)) {} /** * @details */ XLCell::XLCell(const XLCell& other) - : m_cellNode(other.m_cellNode ? std::make_unique(*other.m_cellNode) : nullptr), + : m_cellNode(other.m_cellNode ? std::make_shared(*other.m_cellNode) : nullptr), m_worksheet(other.m_worksheet), - m_valueProxy(XLCellValueProxy(this, m_cellNode.get())), - m_formulaProxy(XLFormulaProxy(this, m_cellNode.get())) + m_valueProxy(XLCellValueProxy(this, m_cellNode)), + m_formulaProxy(XLFormulaProxy(this, m_cellNode)) {} /** @@ -93,8 +93,8 @@ XLCell::XLCell(const XLCell& other) XLCell::XLCell(XLCell&& other) noexcept : m_cellNode(std::move(other.m_cellNode)), m_worksheet(other.m_worksheet), - m_valueProxy(XLCellValueProxy(this, m_cellNode.get())), - m_formulaProxy(XLFormulaProxy(this, m_cellNode.get())) + m_valueProxy(XLCellValueProxy(this, m_cellNode)), + m_formulaProxy(XLFormulaProxy(this, m_cellNode)) {} /** @@ -123,7 +123,7 @@ XLCell& XLCell::operator=(XLCell&& other) noexcept if (&other != this) { m_cellNode = std::move(other.m_cellNode); m_worksheet = other.m_worksheet; - m_valueProxy = XLCellValueProxy(this, m_cellNode.get()); + m_valueProxy = XLCellValueProxy(this, m_cellNode); } return *this; diff --git a/OpenXLSX/sources/XLCellValue.cpp b/OpenXLSX/sources/XLCellValue.cpp index ac4b3041..21bb2021 100644 --- a/OpenXLSX/sources/XLCellValue.cpp +++ b/OpenXLSX/sources/XLCellValue.cpp @@ -119,7 +119,7 @@ std::string XLCellValue::typeAsString() const * @pre The cell and cellNode pointers must not be nullptr and must point to valid objects. * @post A valid XLCellValueProxy has been created. */ -XLCellValueProxy::XLCellValueProxy(XLCell* cell, XMLNode* cellNode) : m_cell(cell), m_cellNode(cellNode) +XLCellValueProxy::XLCellValueProxy(XLCell* cell, std::shared_ptr cellNode) : m_cell(cell), m_cellNode(cellNode) { assert(cell); // NOLINT // assert(cellNode); // NOLINT diff --git a/OpenXLSX/sources/XLFormula.cpp b/OpenXLSX/sources/XLFormula.cpp index 4bb3454a..c11c8e1e 100644 --- a/OpenXLSX/sources/XLFormula.cpp +++ b/OpenXLSX/sources/XLFormula.cpp @@ -68,7 +68,7 @@ XLFormula::operator std::string() const /** * @details Constructor. Set the m_cell and m_cellNode objects. */ -XLFormulaProxy::XLFormulaProxy(XLCell* cell, XMLNode* cellNode) : m_cell(cell), m_cellNode(cellNode) +XLFormulaProxy::XLFormulaProxy(XLCell* cell, std::shared_ptr cellNode) : m_cell(cell), m_cellNode(cellNode) { assert(cell); // NOLINT } diff --git a/OpenXLSX/sources/XLTable.cpp b/OpenXLSX/sources/XLTable.cpp index 9509eef6..31ebb471 100644 --- a/OpenXLSX/sources/XLTable.cpp +++ b/OpenXLSX/sources/XLTable.cpp @@ -267,12 +267,24 @@ void XLTable::setName(const std::string& tableName) } -void XLTable::setFormulas(const std::string& attribute) const +void XLTable::setColumnFormulas() const { - if (attribute=="totalsRowFunction") - setTotalFormulas(); - else if (attribute=="calculatedColumnFormula") - throw "to be implemented"; + // TO be implemented + uint32_t firstRow = m_dataBodyRange.rangeCoordinates().first.row(); + uint16_t firstCol = m_dataBodyRange.rangeCoordinates().first.column(); + + for (auto& col: m_columns){ + std::string colFormula = col.columnFormula(); + if (colFormula.empty()) // if there is nothing, remove formula keep values + for (auto cell: col.bodyRange()){ + auto test = cell.cellReference(); + cell.formula().clear(); + + } + else + for (auto cell: col.bodyRange()) + cell.formula() = colFormula; + } } diff --git a/OpenXLSX/sources/XLTableColumn.cpp b/OpenXLSX/sources/XLTableColumn.cpp index 954fcd30..60f5b155 100644 --- a/OpenXLSX/sources/XLTableColumn.cpp +++ b/OpenXLSX/sources/XLTableColumn.cpp @@ -57,7 +57,7 @@ using namespace OpenXLSX; XLTableColumn::XLTableColumn(const XMLNode& dataNode, const XLTable& table): m_dataNode(std::make_shared(dataNode)), m_table(table), - m_proxyTotal(XLTableColumnFormulaProxy(dataNode,"totalsRowFunction", table)), + m_proxyTotal(XLTableColumnTotalProxy(dataNode,"totalsRowFunction", table)), m_proxyColumn(XLTableColumnFormulaProxy(dataNode,"calculatedColumnFormula", table)) { // TODO implement @@ -87,7 +87,7 @@ XLTableColumn::XLTableColumn(const XMLNode& dataNode, const XLTable& table): XLTableColumn::XLTableColumn(const XLTableColumn& other) : m_dataNode(other.m_dataNode ? std::make_shared(*other.m_dataNode) : nullptr), m_table(other.m_table), - m_proxyTotal(XLTableColumnFormulaProxy((*other.m_dataNode),"totalsRowFunction", other.m_table)), + m_proxyTotal(XLTableColumnTotalProxy((*other.m_dataNode),"totalsRowFunction", other.m_table)), m_proxyColumn(XLTableColumnFormulaProxy((*other.m_dataNode),"calculatedColumnFormula", other.m_table)) {} @@ -131,24 +131,55 @@ void XLTableColumn::setName(const std::string& columnName) const // TODO change the formulas in the sheet } -void XLTableColumn::clearTotalsRowFunction() +XLTableColumnProxy& XLTableColumn::totalsRowFormula() { - m_proxyTotal.clear(); + return m_proxyTotal; } -XLTableColumnFormulaProxy& XLTableColumn::totalsRowFormula() +const XLTableColumnProxy& XLTableColumn::totalsRowFormula() const { return m_proxyTotal; } -const XLTableColumnFormulaProxy& XLTableColumn::totalsRowFormula() const +void XLTableColumn::clearTotalsRowFormula() { - return m_proxyTotal; + m_proxyTotal.clear(); +} + +XLTableColumnFormulaProxy& XLTableColumn::columnFormula() +{ + return m_proxyColumn; +} + +const XLTableColumnFormulaProxy& XLTableColumn::columnFormula() const +{ + return m_proxyColumn; +} + +void XLTableColumn::clearColumnFormula() +{ + m_proxyColumn.clear(); +} + +XLCellRange XLTableColumn::bodyRange() const +{ + uint16_t colIndex = m_table.columnIndex(name()); + XLCellRange tableRange = m_table.dataBodyRange(); + auto p = tableRange.rangeCoordinates(); + uint16_t firstCol = p.first.column(); + XLCellReference tl = p.first; + XLCellReference br = p.second; + + tl.setColumn(firstCol + colIndex); + br.setColumn(firstCol + colIndex); + + tableRange.setRangeCoordinates(tl, br); + return tableRange; } ///////////////////////////////////////////////////////////////////////////////////////// // -// XLTableColumnFormulaProxy +// XLTableColumnProxy // ///////////////////////////////////////////////////////////////////////////////////////// @@ -158,7 +189,7 @@ const XLTableColumnFormulaProxy& XLTableColumn::totalsRowFormula() const * @pre The attr pointer must not be nullptr and must point to valid objects. * @post A valid XLCellValueProxy has been created. */ -XLTableColumnFormulaProxy::XLTableColumnFormulaProxy(const XMLNode& node, const std::string& attr, const XLTable& table ) +XLTableColumnProxy::XLTableColumnProxy(const XMLNode& node, const std::string& attr, const XLTable& table ) : m_node(std::make_shared(node)), m_attribute(attr), m_table(table) @@ -171,14 +202,14 @@ XLTableColumnFormulaProxy::XLTableColumnFormulaProxy(const XMLNode& node, const * @pre * @post */ -XLTableColumnFormulaProxy::~XLTableColumnFormulaProxy() = default; +XLTableColumnProxy::~XLTableColumnProxy() = default; /** * @details Copy constructor. Default implementation has been used. * @pre * @post */ -XLTableColumnFormulaProxy::XLTableColumnFormulaProxy(const XLTableColumnFormulaProxy& other) +XLTableColumnProxy::XLTableColumnProxy(const XLTableColumnProxy& other) : m_node(other.m_node ? std::make_shared(*other.m_node) : nullptr), m_attribute(other.m_attribute), m_table(other.m_table) @@ -189,7 +220,7 @@ XLTableColumnFormulaProxy::XLTableColumnFormulaProxy(const XLTableColumnFormulaP * @pre * @post */ -XLTableColumnFormulaProxy::XLTableColumnFormulaProxy(XLTableColumnFormulaProxy&& other) noexcept +XLTableColumnProxy::XLTableColumnProxy(XLTableColumnProxy&& other) noexcept : m_node(std::move(other.m_node)), m_attribute(std::move(other.m_attribute)), m_table(std::move(other.m_table)) @@ -202,7 +233,7 @@ XLTableColumnFormulaProxy::XLTableColumnFormulaProxy(XLTableColumnFormulaProxy&& * @pre * @post */ -XLTableColumnFormulaProxy& XLTableColumnFormulaProxy::operator=(const XLTableColumnFormulaProxy& other) +XLTableColumnProxy& XLTableColumnProxy::operator=(const XLTableColumnProxy& other) { if (&other != this) { *this = other.getFormula(); @@ -211,20 +242,13 @@ XLTableColumnFormulaProxy& XLTableColumnFormulaProxy::operator=(const XLTableCol return *this; } -XLTableColumnFormulaProxy& XLTableColumnFormulaProxy::operator=(const std::string& formula) -{ - setFormula(formula); - m_table.setFormulas(m_attribute); - return *this; -} - /** * @details Move assignment operator. Default implementation has been used. * @pre * @post */ -XLTableColumnFormulaProxy& XLTableColumnFormulaProxy::operator=(XLTableColumnFormulaProxy&& other) noexcept +XLTableColumnProxy& XLTableColumnProxy::operator=(XLTableColumnProxy&& other) noexcept { if (&other != this) { m_node = std::move(other.m_node); @@ -234,14 +258,18 @@ XLTableColumnFormulaProxy& XLTableColumnFormulaProxy::operator=(XLTableColumnFor return *this; } -/** - * @details Implicitly convert the XLCellValueProxy object to a std::string. - * @pre - * @post - */ -XLTableColumnFormulaProxy::operator std::string() -{ - return getFormula(); + + +///////////////////////////////////////////////////////////////////////////////////////// +// +// XLTableColumnTotalProxy +// +///////////////////////////////////////////////////////////////////////////////////////// + +XLTableColumnProxy& XLTableColumnTotalProxy::operator=(const std::string& formula) +{ + setFormula(formula); + return *this; } /** @@ -249,14 +277,13 @@ XLTableColumnFormulaProxy::operator std::string() * @pre The m_cellNode must not be null, and must point to a valid XML cell node object. * @post The cell node must be valid, but empty. */ -XLTableColumnFormulaProxy& XLTableColumnFormulaProxy::clear() +void XLTableColumnTotalProxy::clear() { // ===== Check that the m_attribute is valid. assert(m_node); // NOLINT m_node->remove_attribute(m_attribute.c_str()); m_table.setTotalFormulas(); - return *this; } /** @@ -266,7 +293,7 @@ XLTableColumnFormulaProxy& XLTableColumnFormulaProxy::clear() * @pre The m_attribute must not be null, and must point to a valid XMLNode object. * @post The underlying attribute has been updated correctly, representing a string value. */ -void XLTableColumnFormulaProxy::setFormula(const std::string& formula) +void XLTableColumnTotalProxy::setFormula(const std::string& formula) { // ===== Check that the m_cellNode is valid. assert(m_node); // NOLINT @@ -280,19 +307,15 @@ void XLTableColumnFormulaProxy::setFormula(const std::string& formula) return; } - if(m_attribute == "totalsRowFunction"){ - // check if the formula is allowed otherwise quit - // TODO check for custom formula - auto it = std::find(std::begin(XLTemplate::totalsRowFunctionList), + auto it = std::find(std::begin(XLTemplate::totalsRowFunctionList), std::end(XLTemplate::totalsRowFunctionList), formula); - if( it == std::end(XLTemplate::totalsRowFunctionList)){ - XLLogError("The formula \"" + formula + "\" is not available for total Row function"); - return; - } + if( it == std::end(XLTemplate::totalsRowFunctionList)){ + XLLogError("The formula \"" + formula + "\" is not available for total Row function"); + return; } m_node->attribute(m_attribute.c_str()).set_value(formula.c_str()); - + m_table.setTotalFormulas(); } /** @@ -301,13 +324,65 @@ void XLTableColumnFormulaProxy::setFormula(const std::string& formula) * @pre The m_cellNode must not be null, and must point to a valid XMLNode object. * @post No changes should be made. */ -std::string XLTableColumnFormulaProxy::getFormula() const +std::string XLTableColumnTotalProxy::getFormula() const { // ===== Check that the m_attribute is valid. assert(m_node); // NOLINT - assert(m_node->attribute(m_attribute.c_str())); + auto node = m_node->attribute(m_attribute.c_str()); + if (!node) + return std::string(); return std::string(m_node->attribute(m_attribute.c_str()).value()); } +///////////////////////////////////////////////////////////////////////////////////////// +// +// XLTableColumnFormulaProxy +// +///////////////////////////////////////////////////////////////////////////////////////// +XLTableColumnProxy& XLTableColumnFormulaProxy::operator=(const std::string& formula) +{ + setFormula(formula); + return *this; +} + +void XLTableColumnFormulaProxy::clear() +{ + // ===== Check that the m_attribute is valid. + assert(m_node); // NOLINT + m_node->remove_child(m_attribute.c_str()); + m_table.setColumnFormulas(); + +} + +void XLTableColumnFormulaProxy::setFormula(const std::string& formula) +{ + // ===== Check that the m_cellNode is valid. + assert(m_node); // NOLINT + auto node = m_node->child(m_attribute.c_str()); + if (!node) + node = m_node->append_child(m_attribute.c_str()); + + // If empty string, we remove the formula + if(formula.empty()){ + clear(); + return; + } + + m_node->child(m_attribute.c_str()).text().set(formula.c_str()); + m_table.setColumnFormulas(); +} + +std::string XLTableColumnFormulaProxy::getFormula() const +{ + // ===== Check that the m_attribute is valid. + assert(m_node); // NOLINT + auto node = m_node->child(m_attribute.c_str()); + if (!node) + return std::string(); + + return std::string(m_node->child(m_attribute.c_str()).text().get()); + +} +//MyTable[[#This Row],['#]]*2 \ No newline at end of file From 2a1dd03612dd49ff7b472dad1c097859a1e6c8ec Mon Sep 17 00:00:00 2001 From: akira215 Date: Tue, 3 Jan 2023 23:27:55 +0100 Subject: [PATCH 24/45] update the demo10 & add columns table method --- Examples/Demo10.cpp | 17 ++++++++++++++--- OpenXLSX/headers/XLTable.hpp | 6 ++++++ OpenXLSX/sources/XLCell.cpp | 1 + OpenXLSX/sources/XLTable.cpp | 26 ++++++++++---------------- 4 files changed, 31 insertions(+), 19 deletions(-) diff --git a/Examples/Demo10.cpp b/Examples/Demo10.cpp index 600aa67b..110eaa71 100644 --- a/Examples/Demo10.cpp +++ b/Examples/Demo10.cpp @@ -72,26 +72,37 @@ int main() { j++; } + // loop could also be done on colums + for(auto& col : tbl.columns()) + for (auto& cell : col.bodyRange()) + cout << cell.value() << " - "; + + cout << endl; + // Also show the total with selected function tbl.autofilter().hideArrows(); //tbl.setHeaderVisible(false); - // Total formulas + // Total formulas tbl.setTotalVisible(true); - //tbl.column("Table")->setTotalsRowFunction("sum"); //tbl.column("Table").setTotalsRowFunction(""); //tbl.column("Table").setTotalsRowFunction("count"); tbl.column("Table").totalsRowFormula() ="sum"; string totaFormula = tbl.column("Table").totalsRowFormula(); cout << "total Formula in the table column : " << totaFormula << endl; + // To clear, a empty string could be sent, or the method + // clearTotalsRowFormula could be called tbl.column("Table").totalsRowFormula() =""; - // Columns formulas + // Columns formulas could be setup, check and cleared, using either + // empty string or calling clearColumnFormula tbl.column("With").columnFormula() = "MyTable[[#This Row],['#]]*2"; string columFormula = tbl.column("With").columnFormula(); cout << "Column Formula : " << columFormula << endl; + + // Table style basics cout << "Table Style : " << tbl.tableStyle().style() << endl; tbl.tableStyle().setStyle("TableStyleDark7"); diff --git a/OpenXLSX/headers/XLTable.hpp b/OpenXLSX/headers/XLTable.hpp index 761e218c..58f7f5e6 100644 --- a/OpenXLSX/headers/XLTable.hpp +++ b/OpenXLSX/headers/XLTable.hpp @@ -114,6 +114,12 @@ namespace OpenXLSX */ XLTableColumn& column(const std::string& name); + /** + * @brief the column vector to be iterate + * @return a const ref on the vector of columns + */ + const std::vector& columns() const; + /** * @brief * @return A pointer to the worksheet object the table belong to diff --git a/OpenXLSX/sources/XLCell.cpp b/OpenXLSX/sources/XLCell.cpp index 41190e60..5a514892 100644 --- a/OpenXLSX/sources/XLCell.cpp +++ b/OpenXLSX/sources/XLCell.cpp @@ -124,6 +124,7 @@ XLCell& XLCell::operator=(XLCell&& other) noexcept m_cellNode = std::move(other.m_cellNode); m_worksheet = other.m_worksheet; m_valueProxy = XLCellValueProxy(this, m_cellNode); + m_formulaProxy = XLFormulaProxy(this, m_cellNode); } return *this; diff --git a/OpenXLSX/sources/XLTable.cpp b/OpenXLSX/sources/XLTable.cpp index 31ebb471..7175ced5 100644 --- a/OpenXLSX/sources/XLTable.cpp +++ b/OpenXLSX/sources/XLTable.cpp @@ -120,16 +120,8 @@ uint16_t XLTable::columnIndex(const std::string& name) const return (uint16_t)(-1); } -/* -std::shared_ptr XLTable::column(const std::string& name) -{ - uint16_t index = columnIndex(name); - if (index == (uint16_t)(-1)) - return nullptr; // the column does not exist - - return std::shared_ptr(m_columns[index]); -} -*/ + + XLTableColumn& XLTable::column(const std::string& name) { uint16_t index = columnIndex(name); @@ -139,6 +131,11 @@ XLTableColumn& XLTable::column(const std::string& name) return m_columns[index]; } +const std::vector& XLTable::columns() const +{ + return m_columns; +} + XLWorksheet* XLTable::getWorksheet() { @@ -276,13 +273,10 @@ void XLTable::setColumnFormulas() const for (auto& col: m_columns){ std::string colFormula = col.columnFormula(); if (colFormula.empty()) // if there is nothing, remove formula keep values - for (auto cell: col.bodyRange()){ - auto test = cell.cellReference(); - cell.formula().clear(); - - } + for (auto& cell: col.bodyRange()) + cell.formula().clear(); else - for (auto cell: col.bodyRange()) + for (auto& cell: col.bodyRange()) cell.formula() = colFormula; } From 960a18796080115964cda21984645f964674091e Mon Sep 17 00:00:00 2001 From: akira215 Date: Wed, 4 Jan 2023 02:46:21 +0100 Subject: [PATCH 25/45] correcting behavior of table total visible --- Examples/Demo10.cpp | 8 ++- OpenXLSX/headers/XLTable.hpp | 7 +++ OpenXLSX/headers/XLTableColumn.hpp | 63 ++++++++++++++++++++ OpenXLSX/sources/XLTable.cpp | 51 ++++++++++++++--- OpenXLSX/sources/XLTableColumn.cpp | 92 ++++++++++++++++++++++++++++-- 5 files changed, 209 insertions(+), 12 deletions(-) diff --git a/Examples/Demo10.cpp b/Examples/Demo10.cpp index 110eaa71..8f796fa6 100644 --- a/Examples/Demo10.cpp +++ b/Examples/Demo10.cpp @@ -72,7 +72,7 @@ int main() { j++; } - // loop could also be done on colums + // loop could also be done on columns for(auto& col : tbl.columns()) for (auto& cell : col.bodyRange()) cout << cell.value() << " - "; @@ -91,10 +91,16 @@ int main() { string totaFormula = tbl.column("Table").totalsRowFormula(); cout << "total Formula in the table column : " << totaFormula << endl; + tbl.column("#").totalsRowLabel() ="Demo Total"; + string totaLabel = tbl.column("#").totalsRowLabel(); + cout << "total Label in the table column : " << totaLabel << endl; + // To clear, a empty string could be sent, or the method // clearTotalsRowFormula could be called tbl.column("Table").totalsRowFormula() =""; + tbl.setTotalVisible(false); + // Columns formulas could be setup, check and cleared, using either // empty string or calling clearColumnFormula tbl.column("With").columnFormula() = "MyTable[[#This Row],['#]]*2"; diff --git a/OpenXLSX/headers/XLTable.hpp b/OpenXLSX/headers/XLTable.hpp index 58f7f5e6..9e923cfc 100644 --- a/OpenXLSX/headers/XLTable.hpp +++ b/OpenXLSX/headers/XLTable.hpp @@ -68,6 +68,7 @@ namespace OpenXLSX friend class XLTableColumn; friend class XLTableColumnTotalProxy; friend class XLTableColumnFormulaProxy; + friend class XLTableColumnTotalLabelProxy; friend class XLTableStyle; public: @@ -225,6 +226,12 @@ namespace OpenXLSX */ void setTotalFormulas() const; + /** + * @brief set theLabels in the worksheet for the all the total row + * the formulas is based on the attribute totalsRowLabel of each col + */ + void setTotalLabels() const; + /** * @brief Adjust the ref according to m_dataBodyRange * and the state of visibility of headers and total diff --git a/OpenXLSX/headers/XLTableColumn.hpp b/OpenXLSX/headers/XLTableColumn.hpp index 6c6e6053..01f6251d 100644 --- a/OpenXLSX/headers/XLTableColumn.hpp +++ b/OpenXLSX/headers/XLTableColumn.hpp @@ -265,6 +265,51 @@ namespace OpenXLSX std::string getFormula() const; }; // Class + class OPENXLSX_EXPORT XLTableColumnTotalLabelProxy : public XLTableColumnProxy + { + friend class XLTableColumn; + + public: + //---------- Public Member Functions ----------// + + /** + * @brief Destructor + */ + ~XLTableColumnTotalLabelProxy()= default; + + /** + * @brief Templated assignment operator + * @param formula The formula to be set + * @return A reference to the current object. + */ + XLTableColumnProxy& operator=(const std::string& formula); + + void clear(); + + private: + //---------- Private Member Functions ---------- // + + /** + * @brief Constructor + * @param attr Pointer to the corresponding XML attribute object. + */ + XLTableColumnTotalLabelProxy(const XMLNode& dataNode, + const std::string& attr, const XLTable& table) + : XLTableColumnProxy(dataNode, attr,table) {}; + + /** + * @brief Set the cell to a string value. + * @param formula The value to be set. + */ + void setFormula(const std::string& formula); + + /** + * @brief Get a copy of the XLCellValue object for the cell. + * @return An XLCellValue object. + */ + std::string getFormula() const; + }; // Class + class OPENXLSX_EXPORT XLTableColumn { @@ -349,6 +394,23 @@ namespace OpenXLSX * @brief clear the total row function of this columns and trigger the sheet update */ void clearColumnFormula(); + + /** + * @brief the getter setter function + * @return return a XLTableColumnProxy ref which could be implicitely convert to string + */ + XLTableColumnProxy& totalsRowLabel(); + + /** + * @brief the getter setter function + * @return return a XLTableColumnProxy ref which could be implicitely convert to string + */ + const XLTableColumnProxy& totalsRowLabel() const; + + /** + * @brief clear the total row function of this columns and trigger the sheet update + */ + void clearTotalsRowLabel(); /** * @brief get the body range of the cell @@ -361,6 +423,7 @@ namespace OpenXLSX const XLTable& m_table; XLTableColumnTotalProxy m_proxyTotal; XLTableColumnFormulaProxy m_proxyColumn; + XLTableColumnTotalLabelProxy m_proxyLabel; }; diff --git a/OpenXLSX/sources/XLTable.cpp b/OpenXLSX/sources/XLTable.cpp index 7175ced5..352f9cda 100644 --- a/OpenXLSX/sources/XLTable.cpp +++ b/OpenXLSX/sources/XLTable.cpp @@ -197,6 +197,7 @@ void XLTable::setHeaderVisible(bool visible) // TODO remove autofilter } adjustRef(); + } @@ -211,14 +212,18 @@ void XLTable::setTotalVisible(bool visible) node.set_value("1"); setTotalFormulas(); + } else { // removing the attribute if not visible m_pXmlData->getXmlDocument()->child("table").remove_attribute("totalsRowCount"); auto node = m_pXmlData->getXmlDocument()->child("table").attribute("totalsRowShown"); if (!node) node = m_pXmlData->getXmlDocument()->child("table").append_attribute("totalsRowShown"); node.set_value("0"); + //TODO check if required to clear the worksheet when hiding total row } + setTotalFormulas(); + setTotalLabels(); adjustRef(); } @@ -284,17 +289,22 @@ void XLTable::setColumnFormulas() const void XLTable::setTotalFormulas() const { - if (!isTotalVisible()) - return; - uint32_t totalRow = m_dataBodyRange.rangeCoordinates().second.row() + 1; uint16_t totalCol = m_dataBodyRange.rangeCoordinates().first.column(); - + + // Hide everything if the total is hidded + if (!isTotalVisible()){ + for (auto& col: m_columns){ + m_sheet.cell(totalRow, totalCol).formula().clear(); + totalCol += 1; + } + return; + } + for (auto& col: m_columns){ std::string colFunc = col.totalsRowFormula(); if (colFunc.empty()){ // if there is nothing, remove formula and values - m_sheet.cell(totalRow, totalCol).formula().clear(); - m_sheet.cell(totalRow, totalCol).value().clear(); + m_sheet.cell(totalRow, totalCol).formula().clear(); } else { @@ -315,7 +325,6 @@ void XLTable::setTotalFormulas() const m_sheet.cell(totalRow, totalCol).formula() = sheetFunction; } else {// remove the formula if function is none m_sheet.cell(totalRow, totalCol).formula().clear(); - m_sheet.cell(totalRow, totalCol).value().clear(); } } @@ -325,6 +334,34 @@ void XLTable::setTotalFormulas() const } +void XLTable::setTotalLabels() const +{ + uint32_t totalRow = m_dataBodyRange.rangeCoordinates().second.row() + 1; + uint16_t totalCol = m_dataBodyRange.rangeCoordinates().first.column(); + + // Hide everything if the total is hidded + if (!isTotalVisible()){ + for (auto& col: m_columns){ + m_sheet.cell(totalRow, totalCol).value().clear(); + totalCol += 1; + } + return; + } + + for (auto& col: m_columns){ + std::string colLabel = col.totalsRowLabel(); + if (colLabel.empty()){ // if there is nothing, remove values + m_sheet.cell(totalRow, totalCol).value().clear(); + } + else + m_sheet.cell(totalRow, totalCol).value() = colLabel; + + totalCol += 1; + } + +} + + void XLTable::adjustRef() { uint32_t firstRow = m_dataBodyRange.rangeCoordinates().first.row(); diff --git a/OpenXLSX/sources/XLTableColumn.cpp b/OpenXLSX/sources/XLTableColumn.cpp index 60f5b155..a08edb08 100644 --- a/OpenXLSX/sources/XLTableColumn.cpp +++ b/OpenXLSX/sources/XLTableColumn.cpp @@ -58,7 +58,8 @@ XLTableColumn::XLTableColumn(const XMLNode& dataNode, const XLTable& table): m_dataNode(std::make_shared(dataNode)), m_table(table), m_proxyTotal(XLTableColumnTotalProxy(dataNode,"totalsRowFunction", table)), - m_proxyColumn(XLTableColumnFormulaProxy(dataNode,"calculatedColumnFormula", table)) + m_proxyColumn(XLTableColumnFormulaProxy(dataNode,"calculatedColumnFormula", table)), + m_proxyLabel(XLTableColumnTotalLabelProxy(dataNode,"totalsRowLabel", table)) { // TODO implement // TODO implement == custom function @@ -88,14 +89,16 @@ XLTableColumn::XLTableColumn(const XLTableColumn& other) : m_dataNode(other.m_dataNode ? std::make_shared(*other.m_dataNode) : nullptr), m_table(other.m_table), m_proxyTotal(XLTableColumnTotalProxy((*other.m_dataNode),"totalsRowFunction", other.m_table)), - m_proxyColumn(XLTableColumnFormulaProxy((*other.m_dataNode),"calculatedColumnFormula", other.m_table)) + m_proxyColumn(XLTableColumnFormulaProxy((*other.m_dataNode),"calculatedColumnFormula", other.m_table)), + m_proxyLabel(XLTableColumnTotalLabelProxy(*other.m_dataNode,"totalsRowLabel", other.m_table)) {} XLTableColumn::XLTableColumn(XLTableColumn&& other) noexcept : m_dataNode(std::move(other.m_dataNode)), m_table(other.m_table), m_proxyTotal(std::move(other.m_proxyTotal)), - m_proxyColumn( std::move(other.m_proxyColumn)) + m_proxyColumn( std::move(other.m_proxyColumn)), + m_proxyLabel( std::move(other.m_proxyLabel)) {} @@ -161,6 +164,21 @@ void XLTableColumn::clearColumnFormula() m_proxyColumn.clear(); } +XLTableColumnProxy& XLTableColumn::totalsRowLabel() +{ + return m_proxyLabel; +} + +const XLTableColumnProxy& XLTableColumn::totalsRowLabel() const +{ + return m_proxyLabel; +} + +void XLTableColumn::clearTotalsRowLabel() +{ + m_proxyLabel.clear(); +} + XLCellRange XLTableColumn::bodyRange() const { uint16_t colIndex = m_table.columnIndex(name()); @@ -385,4 +403,70 @@ std::string XLTableColumnFormulaProxy::getFormula() const } -//MyTable[[#This Row],['#]]*2 \ No newline at end of file +///////////////////////////////////////////////////////////////////////////////////////// +// +// XLTableColumnTotalLabelProxy +// +///////////////////////////////////////////////////////////////////////////////////////// + +XLTableColumnProxy& XLTableColumnTotalLabelProxy::operator=(const std::string& formula) +{ + setFormula(formula); + return *this; +} + +/** + * @details Clear the contents of the cell. This removes all children of the cell node. + * @pre The m_cellNode must not be null, and must point to a valid XML cell node object. + * @post The cell node must be valid, but empty. + */ +void XLTableColumnTotalLabelProxy::clear() +{ + // ===== Check that the m_attribute is valid. + assert(m_node); // NOLINT + m_node->remove_attribute(m_attribute.c_str()); + m_table.setTotalLabels(); + +} + +/** + * @details Set the the formula in the corresponding attribute. + * This is private helper function for setting the attr + * directly in the underlying XML file. + * @pre The m_attribute must not be null, and must point to a valid XMLNode object. + * @post The underlying attribute has been updated correctly, representing a string value. + */ +void XLTableColumnTotalLabelProxy::setFormula(const std::string& formula) +{ + // ===== Check that the m_cellNode is valid. + assert(m_node); // NOLINT + auto node = m_node->attribute(m_attribute.c_str()); + if (!node) + node = m_node->append_attribute(m_attribute.c_str()); + + // If empty string, we remove the formula + if(formula.empty()){ + clear(); + return; + } + + m_node->attribute(m_attribute.c_str()).set_value(formula.c_str()); + m_table.setTotalLabels(); +} + +/** + * @details Get a copy of the XLCellValue object for the cell. This is private helper function for returning an + * XLCellValue object corresponding to the cell value. + * @pre The m_cellNode must not be null, and must point to a valid XMLNode object. + * @post No changes should be made. + */ +std::string XLTableColumnTotalLabelProxy::getFormula() const +{ + // ===== Check that the m_attribute is valid. + assert(m_node); // NOLINT + auto node = m_node->attribute(m_attribute.c_str()); + if (!node) + return std::string(); + + return std::string(m_node->attribute(m_attribute.c_str()).value()); +} \ No newline at end of file From 0886174129ec42d3a22117363b24351293ada6f0 Mon Sep 17 00:00:00 2001 From: akira215 Date: Thu, 5 Jan 2023 00:26:10 +0100 Subject: [PATCH 26/45] Inserting and appending table column --- Examples/Demo10.cpp | 18 +++- OpenXLSX/headers/XLTable.hpp | 33 ++++++- OpenXLSX/headers/XLTableColumn.hpp | 19 ++++- OpenXLSX/sources/XLTable.cpp | 133 ++++++++++++++++++++++++++--- OpenXLSX/sources/XLTableColumn.cpp | 10 +++ 5 files changed, 195 insertions(+), 18 deletions(-) diff --git a/Examples/Demo10.cpp b/Examples/Demo10.cpp index 8f796fa6..7b05878a 100644 --- a/Examples/Demo10.cpp +++ b/Examples/Demo10.cpp @@ -68,6 +68,8 @@ int main() { for(const auto& row : tbl.tableRows()){ row[tbl.columnIndex("#")].value() = j; row[1].value() = "Data" + to_string(j); + row[2].value() = "Col" + to_string(j); + row[3].value() = 4 * j; row[tbl.columnIndex("Table")].value() = (float)j * 2.0f / 3.0f; j++; } @@ -91,14 +93,13 @@ int main() { string totaFormula = tbl.column("Table").totalsRowFormula(); cout << "total Formula in the table column : " << totaFormula << endl; - tbl.column("#").totalsRowLabel() ="Demo Total"; + tbl.column("#").totalsRowLabel() ="Demo Total"; string totaLabel = tbl.column("#").totalsRowLabel(); cout << "total Label in the table column : " << totaLabel << endl; // To clear, a empty string could be sent, or the method // clearTotalsRowFormula could be called tbl.column("Table").totalsRowFormula() =""; - tbl.setTotalVisible(false); // Columns formulas could be setup, check and cleared, using either @@ -108,6 +109,17 @@ int main() { cout << "Column Formula : " << columFormula << endl; + //Inserting columns + auto& newCol = tbl.insertColumn("newCol",2); + newCol.columnFormula() = "MyTable[[#This Row],['#]]+2"; + cout << "Inserted Column : " << newCol.name() << endl; + + auto& appendCol = tbl.appendColumn("newCol"); // test the auto increment + appendCol.columnFormula() = "MyTable[[#This Row],['#]]+MyTable[[#This Row],[newCol]]"; + cout << "Append Column : " << newCol.name() << endl; + + +/* // Table style basics cout << "Table Style : " << tbl.tableStyle().style() << endl; tbl.tableStyle().setStyle("TableStyleDark7"); @@ -123,7 +135,7 @@ int main() { tbl.tableStyle().showFirstColumnHighlighted(true); tbl.tableStyle().showLastColumnHighlighted(true); - +*/ doc.save(); doc.close(); diff --git a/OpenXLSX/headers/XLTable.hpp b/OpenXLSX/headers/XLTable.hpp index 9e923cfc..5f1c876e 100644 --- a/OpenXLSX/headers/XLTable.hpp +++ b/OpenXLSX/headers/XLTable.hpp @@ -210,13 +210,27 @@ namespace OpenXLSX */ void setName(const std::string& tableName); + /** + * @brief Insert a new column before index position + * @param columnName name of the new column, will be incremented if already exists + * @param index index of insertion + */ + XLTableColumn& insertColumn(const std::string& columnName, uint16_t index = 0); + + /** + * @brief Append a new column at right side of the table + * @param columnName name of the new column, will be incremented if already exists + */ + XLTableColumn& appendColumn(const std::string& columnName); + //---------------------------------------------------------------------------------------------------------------------- // Protected //---------------------------------------------------------------------------------------------------------------------- protected: + /** * @brief set the formulas in the worksheet for all the columns - * @param attribute of the forumla to be set + * formulas are read directly in the table.xml file */ void setColumnFormulas() const; @@ -233,6 +247,23 @@ namespace OpenXLSX void setTotalLabels() const; /** + * @brief set the headers in the worksheet for all the columns + * headers name are read directly in the table.xml file + */ + void setHeaderLabels() const; + + //---------------------------------------------------------------------------------------------------------------------- + // Private Methods + //---------------------------------------------------------------------------------------------------------------------- + private: + + /** + * @brief Load the columns in the vector member variable + * using the table.xml file + */ + void updateColumns(); + + /** * @brief Adjust the ref according to m_dataBodyRange * and the state of visibility of headers and total */ diff --git a/OpenXLSX/headers/XLTableColumn.hpp b/OpenXLSX/headers/XLTableColumn.hpp index 01f6251d..399bf44a 100644 --- a/OpenXLSX/headers/XLTableColumn.hpp +++ b/OpenXLSX/headers/XLTableColumn.hpp @@ -313,6 +313,8 @@ namespace OpenXLSX class OPENXLSX_EXPORT XLTableColumn { + friend class XLTable; + public: /** * @brief The constructor. @@ -350,13 +352,13 @@ namespace OpenXLSX /** - * @brief + * @brief the name of the column (header) * @return the column name */ std::string name() const; /** - * @brief + * @brief set the name of the column (header) * @param name set the column name */ void setName(const std::string& name) const; @@ -417,6 +419,19 @@ namespace OpenXLSX * @return an XLCellReference of the body range of the column */ XLCellRange bodyRange() const; + + protected: + /** + * @brief get the index of the column, from table xml file + * @return the corresponding index + */ + uint16_t index() const; + + /** + * @brief set the index of the column, in the table xml file + * @param index corresponding index + */ + void setIndex(uint16_t index); private: std::shared_ptr m_dataNode; diff --git a/OpenXLSX/sources/XLTable.cpp b/OpenXLSX/sources/XLTable.cpp index 352f9cda..78cdf081 100644 --- a/OpenXLSX/sources/XLTable.cpp +++ b/OpenXLSX/sources/XLTable.cpp @@ -77,12 +77,8 @@ XLTable::XLTable(XLXmlData* xmlData) m_dataBodyRange.setRangeCoordinates(topLeft, bottomRight); - // ===== Deal with the columns - XMLNode pTblColumns = m_pXmlData->getXmlDocument()->child("table").child("tableColumns"); - - for (const XMLNode& col : pTblColumns.children()) - m_columns.push_back(XLTableColumn(col, *this)); + updateColumns(); } @@ -193,11 +189,13 @@ void XLTable::setHeaderVisible(bool visible) auto node = m_pXmlData->getXmlDocument()->child("table").attribute("headerRowCount"); if (!node) node = m_pXmlData->getXmlDocument()->child("table").append_attribute("headerRowCount"); - node.set_value("0"); - // TODO remove autofilter + node.set_value("0"); } - adjustRef(); + // TODO remove autofilter + + setHeaderLabels(); + adjustRef(); } @@ -211,8 +209,6 @@ void XLTable::setTotalVisible(bool visible) node = m_pXmlData->getXmlDocument()->child("table").append_attribute("totalsRowCount"); node.set_value("1"); - setTotalFormulas(); - } else { // removing the attribute if not visible m_pXmlData->getXmlDocument()->child("table").remove_attribute("totalsRowCount"); auto node = m_pXmlData->getXmlDocument()->child("table").attribute("totalsRowShown"); @@ -261,11 +257,97 @@ void XLTable::setName(const std::string& tableName) XMLNode tableNode = m_pXmlData->getXmlDocument()->child("table"); tableNode.attribute("name").set_value(tableName.c_str()); tableNode.attribute("displayName").set_value(tableName.c_str()); - // TODO change the formulas in table.xml // TODO change the formulas in the sheet +} + + XLTableColumn& XLTable::insertColumn(const std::string& columnName, uint16_t index) + { + + // If index is not continuous, the column is appended at the last + if (index > m_columns.size()) + index = m_columns.size(); + + // Increment the name of the column if required + std::string colName = columnName; + bool notValid = true; + while (notValid){ + if (std::find_if(m_columns.begin(), m_columns.end(), + [&colName](const XLTableColumn& i){ return i.name() == colName; }) != m_columns.end()) + colName += INCREMENT_STRING; + else + notValid = false; + } + + // Copy the content of the bodyrange of the column, anr re index tablecolumn in table.xml + for (uint16_t i = m_columns.size() - 1; i >= index; --i) { + auto& tblCol = m_columns[i]; + + // Change the index in table.xml + tblCol.setIndex(i+2); // 1 based index + + // Copy column n in n+1 in the sheet + XLCellRange src = tblCol.bodyRange(); + XLCellRange dest = src; + dest.offset(0,1); + for(uint32_t j = 0; j < src.numRows(); j++){ + dest[j].value() = src[j].value(); + if ( src[j].hasFormula()) + dest[j].formula() = src[j].formula(); + else + dest[j].formula().clear(); + } + } + + // add new entry in table.xml + auto nextNode = m_pXmlData->getXmlDocument()->document_element() + .child("tableColumns").find_child_by_attribute("id",std::to_string(index+2).c_str()); + + XMLNode newNode; + if(nextNode) + newNode = m_pXmlData->getXmlDocument()->document_element() + .child("tableColumns").insert_child_before("tableColumn", nextNode); + else + newNode = m_pXmlData->getXmlDocument()->document_element() + .child("tableColumns").append_child("tableColumn"); + + + newNode.append_attribute("id").set_value(std::to_string(index + 1).c_str()); + newNode.append_attribute("name").set_value(colName.c_str()); + + // Update the range coordinates + auto p = m_dataBodyRange.rangeCoordinates(); + m_dataBodyRange.setRangeCoordinates(p.first, p.second.offset(0,1)); + + + updateColumns(); // Update the member variable + + setHeaderLabels(); // relocate the labels + setTotalLabels(); // relocate the formulas + setTotalLabels(); // reolcate the lables + adjustRef(); // update the ref + + //Clear the content of the new column + for(auto& cell : m_columns[index].bodyRange()) + cell.value().clear(); + + return m_columns[index]; + } + +XLTableColumn& XLTable::appendColumn(const std::string& columnName) +{ + return insertColumn(columnName, m_columns.size()); +} + +void XLTable::updateColumns() +{ + m_columns.clear(); + XMLNode pTblColumns = m_pXmlData->getXmlDocument()->child("table").child("tableColumns"); + + for (const XMLNode& col : pTblColumns.children()) + m_columns.push_back(XLTableColumn(col, *this)); } @@ -281,8 +363,10 @@ void XLTable::setColumnFormulas() const for (auto& cell: col.bodyRange()) cell.formula().clear(); else - for (auto& cell: col.bodyRange()) + for (auto& cell: col.bodyRange()){ cell.formula() = colFormula; + cell.value().clear(); + } } } @@ -361,6 +445,29 @@ void XLTable::setTotalLabels() const } +void XLTable::setHeaderLabels() const +{ + uint32_t headerRow = m_dataBodyRange.rangeCoordinates().first.row() - 1; + uint16_t headerCol = m_dataBodyRange.rangeCoordinates().first.column(); + + // Hide everything if the total is hidded + if (!isHeaderVisible()){ + for (auto& col: m_columns){ + m_sheet.cell(headerRow, headerCol).value().clear(); + headerCol += 1; + } + return; + } + + for (auto& col: m_columns){ + auto test = col.name(); + m_sheet.cell(headerRow, headerCol).value() = col.name(); + + headerCol += 1; + } + +} + void XLTable::adjustRef() { @@ -381,4 +488,6 @@ void XLTable::adjustRef() m_pXmlData->getXmlDocument()->child("table") .attribute("ref").set_value(ref.c_str()); + + // TODO adjust autofilter Move this elsewhere } \ No newline at end of file diff --git a/OpenXLSX/sources/XLTableColumn.cpp b/OpenXLSX/sources/XLTableColumn.cpp index a08edb08..453fd578 100644 --- a/OpenXLSX/sources/XLTableColumn.cpp +++ b/OpenXLSX/sources/XLTableColumn.cpp @@ -195,6 +195,16 @@ XLCellRange XLTableColumn::bodyRange() const return tableRange; } +uint16_t XLTableColumn::index() const +{ + return std::stoi(std::string(m_dataNode->attribute("id").value())); +} + +void XLTableColumn::setIndex(uint16_t index) +{ + m_dataNode->attribute("id").set_value(std::to_string(index).c_str()); +} + ///////////////////////////////////////////////////////////////////////////////////////// // // XLTableColumnProxy From 7b290dc7829e400648be8936be2501abe06a27e2 Mon Sep 17 00:00:00 2001 From: akira215 Date: Fri, 6 Jan 2023 05:59:09 +0100 Subject: [PATCH 27/45] deleting table column Ok --- Examples/Demo10.cpp | 5 +- OpenXLSX/headers/XLFormula.hpp | 29 ++++++++ OpenXLSX/headers/XLTable.hpp | 19 +++++- OpenXLSX/headers/XLTableColumn.hpp | 6 ++ OpenXLSX/sources/XLFormula.cpp | 61 ++++++++++++++++- OpenXLSX/sources/XLTable.cpp | 103 +++++++++++++++++++++++++++-- OpenXLSX/sources/XLTableColumn.cpp | 16 +++++ 7 files changed, 228 insertions(+), 11 deletions(-) diff --git a/Examples/Demo10.cpp b/Examples/Demo10.cpp index 7b05878a..d0a16162 100644 --- a/Examples/Demo10.cpp +++ b/Examples/Demo10.cpp @@ -34,6 +34,7 @@ int main() { wks.cell("F2").value() = "Table"; XLTable myTable = doc.workbook().addTable(sheetName,"MyTable","B2:F18"); + //XLTable myTable = doc.workbook().addTable(sheetName,"MyTable","B2:F4"); // Save the sheet... cout << "Saving spreadsheet ..." << endl; @@ -115,9 +116,11 @@ int main() { cout << "Inserted Column : " << newCol.name() << endl; auto& appendCol = tbl.appendColumn("newCol"); // test the auto increment - appendCol.columnFormula() = "MyTable[[#This Row],['#]]+MyTable[[#This Row],[newCol]]"; + appendCol.columnFormula() = "MyTable[[#This Row],[One]]&\"akira\"&MyTable[[#This Row],[newCol]]"; cout << "Append Column : " << newCol.name() << endl; + // Deleting colum + tbl.deleteColumn("newCol"); /* // Table style basics diff --git a/OpenXLSX/headers/XLFormula.hpp b/OpenXLSX/headers/XLFormula.hpp index 86bfa815..b88664d1 100644 --- a/OpenXLSX/headers/XLFormula.hpp +++ b/OpenXLSX/headers/XLFormula.hpp @@ -109,6 +109,8 @@ namespace OpenXLSX m_formulaString = std::string(formula); else m_formulaString = formula.c_str(); + + checkIfError(); } /** @@ -171,6 +173,7 @@ namespace OpenXLSX void set(T formula) { *this = formula; + checkIfError(); } /** @@ -191,8 +194,23 @@ namespace OpenXLSX */ XLFormula& clear(); + /** + * @brief update the formula considering that the expression + * passed as argument is about to be cancelled + * @param toBeDeleted expression that will be replaced by "#REF!" + * @return Return a reference to the cleared object, which is unchanged if + * it does not contain the param + */ + XLFormula updateDeleting(const std::string& toBeDeleted); + + bool hasError() const; + + private: + void checkIfError(); + private: std::string m_formulaString; /**< A std::string, holding the formula string.*/ + bool m_isError {false}; }; /** @@ -268,6 +286,17 @@ namespace OpenXLSX */ XLFormulaProxy& clear(); + /** + * @brief update the formula considering that the expression + * passed as argument is about to be cancelled + * @param toBeDeleted expression that will be replaced by "#REF!" + * @return Return a reference to the cleared object, which is unchanged if + * it does not contain the param + */ + XLFormula updateDeleting(const std::string& toBeDeleted); + + bool hasError() const; + /** * @brief Conversion operator, for converting the object to a std::string. * @return The formula as a std::string. diff --git a/OpenXLSX/headers/XLTable.hpp b/OpenXLSX/headers/XLTable.hpp index 5f1c876e..10629a34 100644 --- a/OpenXLSX/headers/XLTable.hpp +++ b/OpenXLSX/headers/XLTable.hpp @@ -102,12 +102,19 @@ namespace OpenXLSX std::vector columnNames() const; /** - * @brief + * @brief get column index from name * @param name the name of the requested column index * @return The index of the column */ uint16_t columnIndex(const std::string& name) const; + /** + * @brief get column name from index + * @param index of the requested column + * @return the name of the column + */ + const std::string columnName(uint16_t index) const; + /** * @brief * @param name the name of the requested column @@ -223,6 +230,12 @@ namespace OpenXLSX */ XLTableColumn& appendColumn(const std::string& columnName); + /** + * @brief delete the column + * @param columnName of the column to be deleted + */ + void deleteColumn(const std::string& columnName ); + //---------------------------------------------------------------------------------------------------------------------- // Protected //---------------------------------------------------------------------------------------------------------------------- @@ -259,11 +272,11 @@ namespace OpenXLSX /** * @brief Load the columns in the vector member variable - * using the table.xml file + * using the table.xml file. Update the count in the xml file */ void updateColumns(); - /** + /** * @brief Adjust the ref according to m_dataBodyRange * and the state of visibility of headers and total */ diff --git a/OpenXLSX/headers/XLTableColumn.hpp b/OpenXLSX/headers/XLTableColumn.hpp index 399bf44a..27e39dcb 100644 --- a/OpenXLSX/headers/XLTableColumn.hpp +++ b/OpenXLSX/headers/XLTableColumn.hpp @@ -433,6 +433,12 @@ namespace OpenXLSX */ void setIndex(uint16_t index); + /** + * @brief check if the formula contain the field about to be deleted + * @param toBeDeleted field about to be deleted + * The field is found excluding inside quote. If found the formula is deleted + */ + void formulaUpdateDeleting(const std::string& toBeDeleted); private: std::shared_ptr m_dataNode; const XLTable& m_table; diff --git a/OpenXLSX/sources/XLFormula.cpp b/OpenXLSX/sources/XLFormula.cpp index c11c8e1e..945a8d4e 100644 --- a/OpenXLSX/sources/XLFormula.cpp +++ b/OpenXLSX/sources/XLFormula.cpp @@ -2,12 +2,14 @@ // Created by Kenneth Balslev on 27/08/2021. // +// ===== External Includes ===== // +#include +#include + // ===== OpenXLSX Includes ===== // #include "XLFormula.hpp" #include -#include - using namespace OpenXLSX; /** @@ -54,9 +56,51 @@ std::string XLFormula::get() const XLFormula& XLFormula::clear() { m_formulaString = ""; + m_isError = false; return *this; } +/** + * @details use a regex to replace the variable to be deleted by #REF! + */ +XLFormula XLFormula::updateDeleting(const std::string& toBeDeleted) +{ + + //std::string s = toBeDeleted + R"aka((?=([^"]*"[^"]*")*[^"]*$))aka"; + // Regex that will find all the occurence of toBeDeleted excepted inside quote + // TODO deal with nested quotes + const std::regex re(toBeDeleted + R"&((?=([^"]*"[^"]*")*[^"]*$))&"); + + std::string newFormula = std::regex_replace(m_formulaString, re, "#REF!"); + + if(m_formulaString == newFormula) + m_isError = false; + else + m_isError = true; + + m_formulaString = newFormula; + + return *this; +} + +bool XLFormula::hasError() const +{ + return m_isError; +} + +void XLFormula::checkIfError() +{ + //Check if Formula has error + // TODO deal with nested quotes + const std::regex re(R"&(#REF!(?=([^"]*"[^"]*")*[^"]*$))&"); + + std::smatch m; // unused + + if (std::regex_search(m_formulaString, m, re)) + m_isError = true; + +} + /** * @details */ @@ -143,6 +187,19 @@ XLFormulaProxy& XLFormulaProxy::clear() return *this; } +/** + * @details Set the m_formulaString member to an empty string. + */ +XLFormula XLFormulaProxy::updateDeleting(const std::string& toBeDeleted) +{ + return getFormula().updateDeleting(toBeDeleted); +} + +bool XLFormulaProxy::hasError() const +{ + return getFormula().hasError(); +} + /** * @details Convenience function for setting the formula. This method is called from the templated * string assignment operator. diff --git a/OpenXLSX/sources/XLTable.cpp b/OpenXLSX/sources/XLTable.cpp index 78cdf081..1cd86996 100644 --- a/OpenXLSX/sources/XLTable.cpp +++ b/OpenXLSX/sources/XLTable.cpp @@ -117,6 +117,13 @@ uint16_t XLTable::columnIndex(const std::string& name) const return (uint16_t)(-1); } +const std::string XLTable::columnName(uint16_t index) const +{ + if(index > m_columns.size() - 1) + return std::string(); + + return m_columns.at(index).name(); +} XLTableColumn& XLTable::column(const std::string& name) { @@ -266,8 +273,13 @@ void XLTable::setName(const std::string& tableName) { // If index is not continuous, the column is appended at the last - if (index > m_columns.size()) + if (index > m_columns.size()){ + XLLogError("Index " + std::to_string(index) + + " is out of column range, column will be appeneded considering " + + std::to_string(m_columns.size())); index = m_columns.size(); + } + // Increment the name of the column if required std::string colName = columnName; @@ -312,7 +324,7 @@ void XLTable::setName(const std::string& tableName) newNode = m_pXmlData->getXmlDocument()->document_element() .child("tableColumns").append_child("tableColumn"); - + // Add attributes to the new node newNode.append_attribute("id").set_value(std::to_string(index + 1).c_str()); newNode.append_attribute("name").set_value(colName.c_str()); @@ -320,7 +332,6 @@ void XLTable::setName(const std::string& tableName) auto p = m_dataBodyRange.rangeCoordinates(); m_dataBodyRange.setRangeCoordinates(p.first, p.second.offset(0,1)); - updateColumns(); // Update the member variable setHeaderLabels(); // relocate the labels @@ -330,7 +341,10 @@ void XLTable::setName(const std::string& tableName) //Clear the content of the new column for(auto& cell : m_columns[index].bodyRange()) + { cell.value().clear(); + cell.formula().clear(); + } return m_columns[index]; } @@ -340,14 +354,93 @@ XLTableColumn& XLTable::appendColumn(const std::string& columnName) return insertColumn(columnName, m_columns.size()); } +///////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////// +void XLTable::deleteColumn(const std::string& columnName) +{ + uint16_t index = columnIndex(columnName); + + // If index is not in the line don't do anything + if (index > m_columns.size() - 1){ + XLLogError("Index " + std::to_string(index) + + " is out of column range, no column wil be deleted"); + return; + } + + // Copy the content of the bodyrange of the column, and re index tablecolumn in table.xml + for (uint16_t i = index; i < m_columns.size(); ++i) { + auto& tblCol = m_columns[i]; + + // Change the index in table.xml + tblCol.setIndex(i); // 1 based index + tblCol.formulaUpdateDeleting(columnName); + + if (i != m_columns.size() -1){ + // Copy column n+1 in n in the sheet + XLCellRange dest = tblCol.bodyRange(); + XLCellRange src = dest; + src.offset(0,1); + for(uint32_t j = 0; j < src.numRows(); j++){ + dest[j].value() = src[j].value(); + if ( src[j].hasFormula()) { + dest[j].formula() = src[j].formula().updateDeleting(columnName); + if (dest[j].formula().hasError()){ + dest[j].formula().clear(); // shall be cleared for table formulas + dest[j].value() = "#REF!"; + } + } + else + dest[j].formula().clear(); + } + } // If avoid de copy the column just outside the table + } + + // Delete the entry in table.xml + auto delNode = m_pXmlData->getXmlDocument()->document_element() + .child("tableColumns").find_child_by_attribute("name",columnName.c_str()); + m_pXmlData->getXmlDocument()->document_element() + .child("tableColumns").remove_child(delNode); + + // Update the range coordinates + auto p = m_dataBodyRange.rangeCoordinates(); + m_dataBodyRange.setRangeCoordinates(p.first, p.second.offset(0,-1)); + + updateColumns(); // Update the member variable + + setHeaderLabels(); // relocate the labels + setTotalLabels(); // relocate the formulas + setTotalLabels(); // reolcate the lables + adjustRef(); // update the ref + + //Clear the content of the last column, including header and total if required + XLCellRange lastCol = m_columns[ m_columns.size()-1].bodyRange(); + p = lastCol.rangeCoordinates(); + int t = 0, b = 0; + if (isHeaderVisible()) + t = -1; + if (isTotalVisible()) + b = 1; + lastCol.setRangeCoordinates(p.first.offset(t,1),p.second.offset(b,1)); + for(auto& cell : lastCol) + { + cell.value().clear(); + cell.formula().clear(); + } +} + void XLTable::updateColumns() { m_columns.clear(); - XMLNode pTblColumns = m_pXmlData->getXmlDocument()->child("table").child("tableColumns"); + XMLNode tblColumns = m_pXmlData->getXmlDocument()->child("table").child("tableColumns"); - for (const XMLNode& col : pTblColumns.children()) + for (const XMLNode& col : tblColumns.children()) m_columns.push_back(XLTableColumn(col, *this)); + + if (!tblColumns.attribute("count")) + tblColumns.append_attribute("count"); + + tblColumns.attribute("count").set_value(std::to_string(m_columns.size()).c_str()); } diff --git a/OpenXLSX/sources/XLTableColumn.cpp b/OpenXLSX/sources/XLTableColumn.cpp index 453fd578..324c05cc 100644 --- a/OpenXLSX/sources/XLTableColumn.cpp +++ b/OpenXLSX/sources/XLTableColumn.cpp @@ -47,6 +47,7 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. #include #include #include +#include // ===== OpenXLSX Includes ===== // #include "XLTableColumn.hpp" @@ -205,6 +206,21 @@ void XLTableColumn::setIndex(uint16_t index) m_dataNode->attribute("id").set_value(std::to_string(index).c_str()); } +void XLTableColumn::formulaUpdateDeleting(const std::string& toBeDeleted) +{ + std::string formula = columnFormula(); + + if(formula.empty()) + return; + // Regex that will find all the occurence of toBeDeleted excepted inside quote + // TODO deal with nested quotes + const std::regex re(toBeDeleted + R"&((?=([^"]*"[^"]*")*[^"]*$))&"); + std::smatch m; // unused + + if (std::regex_search(formula, m, re)) + m_dataNode->remove_child("calculatedColumnFormula"); +} + ///////////////////////////////////////////////////////////////////////////////////////// // // XLTableColumnProxy From 566d12ea2636259a465905fb48e0a65a2c124d26 Mon Sep 17 00:00:00 2001 From: akira215 Date: Fri, 6 Jan 2023 18:14:24 +0100 Subject: [PATCH 28/45] Inserting and deleting row in tables --- Examples/Demo10.cpp | 5 ++ OpenXLSX/headers/XLCellRange.hpp | 2 + OpenXLSX/headers/XLTable.hpp | 31 ++++++- OpenXLSX/headers/XLTableRows.hpp | 54 ++++++------ OpenXLSX/sources/XLTable.cpp | 138 +++++++++++++++++++++++++++---- 5 files changed, 186 insertions(+), 44 deletions(-) diff --git a/Examples/Demo10.cpp b/Examples/Demo10.cpp index d0a16162..327c1d87 100644 --- a/Examples/Demo10.cpp +++ b/Examples/Demo10.cpp @@ -122,6 +122,11 @@ int main() { // Deleting colum tbl.deleteColumn("newCol"); + + //Inserting and deleting rows + auto newRow = tbl.insertRow(2); + tbl.deleteRow(3); + /* // Table style basics cout << "Table Style : " << tbl.tableStyle().style() << endl; diff --git a/OpenXLSX/headers/XLCellRange.hpp b/OpenXLSX/headers/XLCellRange.hpp index e6d4f737..d2eb27e0 100644 --- a/OpenXLSX/headers/XLCellRange.hpp +++ b/OpenXLSX/headers/XLCellRange.hpp @@ -184,6 +184,8 @@ namespace OpenXLSX * @brief offset the whole range if possible * @param row integer could be negative * @param col integer could be negative, default 0 + * @note this method does not move any data on the worksheet, + * It will only affect the range considered by the XLCellRange object */ void offset(int row, int col = 0); diff --git a/OpenXLSX/headers/XLTable.hpp b/OpenXLSX/headers/XLTable.hpp index 10629a34..9be6258d 100644 --- a/OpenXLSX/headers/XLTable.hpp +++ b/OpenXLSX/headers/XLTable.hpp @@ -164,14 +164,14 @@ namespace OpenXLSX /** - * @brief + * @brief check if the header row is displayed * @return true if header is visible */ bool isHeaderVisible() const; /** - * @brief + * @brief check if the total row is displayed * @return true if total row is visible */ bool isTotalVisible() const; @@ -221,21 +221,48 @@ namespace OpenXLSX * @brief Insert a new column before index position * @param columnName name of the new column, will be incremented if already exists * @param index index of insertion + * @note the column at the right side of the table are not shifted */ XLTableColumn& insertColumn(const std::string& columnName, uint16_t index = 0); /** * @brief Append a new column at right side of the table * @param columnName name of the new column, will be incremented if already exists + * @note the column at the right side of the table are not shifted */ XLTableColumn& appendColumn(const std::string& columnName); /** * @brief delete the column * @param columnName of the column to be deleted + * @note the column at the right side of the table are not shifted */ void deleteColumn(const std::string& columnName ); + /** + * @brief Insert a new row before index position + * @param index index of insertion + * @note existing cell info may be deleted if there is a column formula + * The data below the table are not shifted down + */ + XLCellRange insertRow(uint16_t index = 0); + + /** + * @brief Append a new row at the bottom side of the table + * @return a XLCellRange of the appened row + * @note existing cell info may be deleted if there is a column formula + * The data below the table are not shifted down + */ + XLCellRange appendRow(); + + /** + * @brief delete a row. Although the Excel behavior, only the row + * is impacted, the row belows are not lifted up + * @param index of the row to be deleted + * @note the data below the table are not shifted + */ + void deleteRow(uint32_t index ); + //---------------------------------------------------------------------------------------------------------------------- // Protected //---------------------------------------------------------------------------------------------------------------------- diff --git a/OpenXLSX/headers/XLTableRows.hpp b/OpenXLSX/headers/XLTableRows.hpp index 4bb40d39..9cbcb26e 100644 --- a/OpenXLSX/headers/XLTableRows.hpp +++ b/OpenXLSX/headers/XLTableRows.hpp @@ -15,33 +15,33 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. MM _MM_ - Written by Akira SHIMAHARA - - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - Neither the name of the author nor the - names of any contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - */ + Written by Akira SHIMAHARA + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + - Neither the name of the author nor the + names of any contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ #ifndef OPENXLSX_XLTABLEROWS_HPP #define OPENXLSX_XLTABLEROWS_HPP diff --git a/OpenXLSX/sources/XLTable.cpp b/OpenXLSX/sources/XLTable.cpp index 1cd86996..839ccd9f 100644 --- a/OpenXLSX/sources/XLTable.cpp +++ b/OpenXLSX/sources/XLTable.cpp @@ -292,7 +292,7 @@ void XLTable::setName(const std::string& tableName) notValid = false; } - // Copy the content of the bodyrange of the column, anr re index tablecolumn in table.xml + // Copy the content of the bodyrange of the column, and re index tablecolumn in table.xml for (uint16_t i = m_columns.size() - 1; i >= index; --i) { auto& tblCol = m_columns[i]; @@ -304,11 +304,13 @@ void XLTable::setName(const std::string& tableName) XLCellRange dest = src; dest.offset(0,1); for(uint32_t j = 0; j < src.numRows(); j++){ - dest[j].value() = src[j].value(); - if ( src[j].hasFormula()) + if ( src[j].hasFormula()){ dest[j].formula() = src[j].formula(); - else - dest[j].formula().clear(); + dest[j].value().clear(); + } else { + dest[j].value() = src[j].value(); + dest[j].formula().clear(); + } } } @@ -335,7 +337,7 @@ void XLTable::setName(const std::string& tableName) updateColumns(); // Update the member variable setHeaderLabels(); // relocate the labels - setTotalLabels(); // relocate the formulas + setTotalFormulas(); // relocate the formulas setTotalLabels(); // reolcate the lables adjustRef(); // update the ref @@ -354,8 +356,6 @@ XLTableColumn& XLTable::appendColumn(const std::string& columnName) return insertColumn(columnName, m_columns.size()); } -///////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////// void XLTable::deleteColumn(const std::string& columnName) { uint16_t index = columnIndex(columnName); @@ -373,24 +373,25 @@ void XLTable::deleteColumn(const std::string& columnName) // Change the index in table.xml tblCol.setIndex(i); // 1 based index - tblCol.formulaUpdateDeleting(columnName); - + tblCol.formulaUpdateDeleting(columnName); + if (i != m_columns.size() -1){ // Copy column n+1 in n in the sheet XLCellRange dest = tblCol.bodyRange(); XLCellRange src = dest; src.offset(0,1); for(uint32_t j = 0; j < src.numRows(); j++){ - dest[j].value() = src[j].value(); if ( src[j].hasFormula()) { dest[j].formula() = src[j].formula().updateDeleting(columnName); if (dest[j].formula().hasError()){ dest[j].formula().clear(); // shall be cleared for table formulas dest[j].value() = "#REF!"; - } - } - else + } else + dest[j].value().clear(); + } else { dest[j].formula().clear(); + dest[j].value() = src[j].value(); + } } } // If avoid de copy the column just outside the table } @@ -408,7 +409,9 @@ void XLTable::deleteColumn(const std::string& columnName) updateColumns(); // Update the member variable setHeaderLabels(); // relocate the labels - setTotalLabels(); // relocate the formulas + setTotalFormulas(); // relocate the formulas + // TODO erase total value if any issue with the formula + setTotalLabels(); // reolcate the lables adjustRef(); // update the ref @@ -428,6 +431,111 @@ void XLTable::deleteColumn(const std::string& columnName) } } + + XLCellRange XLTable::insertRow(uint16_t index) + { + // If index is not continuous, the column is appended at the last + if (index > rowsCount()){ + XLLogError("Index " + std::to_string(index) + + " is out of row range, row will be appeneded considering " + + std::to_string(rowsCount())); + index = rowsCount(); + } + + // Copy the content of the bodyrange of the row, index -1 to force one loop + // in case of appending + XLTableRows rows = tableRows(); + for (uint16_t i = rowsCount() - 1; i >= index - 1; --i) { + + // Copy column n in n+1 in the sheet + XLCellRange src = rows[i]; + XLCellRange dest = src; + dest.offset(1,0); + for(uint32_t j = 0; j < src.numColumns(); j++){ + if ( src[j].hasFormula()){ + dest[j].formula() = src[j].formula(); + dest[j].value().clear(); // shall be cleared for table formulas + } else { + dest[j].value() = src[j].value(); + dest[j].formula().clear(); + } + } + } + + // Update the range coordinates + auto p = m_dataBodyRange.rangeCoordinates(); + m_dataBodyRange.setRangeCoordinates(p.first, p.second.offset(1,0)); + + setHeaderLabels(); // relocate the labels + setTotalFormulas(); // relocate the formulas + setTotalLabels(); // reolcate the lables + adjustRef(); // update the ref + + //Clear the content of the new column + // but keep the column formula if any + rows = tableRows(); + for(auto& cell : rows[index]) + { + cell.value().clear(); + } + + return rows[index]; + } + +XLCellRange XLTable::appendRow() +{ + return insertRow( rowsCount() ); +} + +void XLTable::deleteRow(uint32_t index ) +{ + // If index is not continuous, the column is appended at the last + if (index > rowsCount()){ + XLLogError("Index " + std::to_string(index) + + " is out of row range, no row will be deleted " + + std::to_string(rowsCount())); + return; + } + + // Copy the content of the bodyrange of the row + XLTableRows rows = tableRows(); + for (uint16_t i = index; i < rowsCount() - 2; ++i) { + + // Copy column n+1 in n in the sheet + XLCellRange dest = rows[i]; // 1 based index + XLCellRange src = dest; + src.offset(1,0); + for(uint32_t j = 0; j < src.numRows(); j++){ + if ( src[j].hasFormula()){ + dest[j].formula() = src[j].formula(); + dest[j].value().clear(); // shall be cleared for table formulas + } else { + dest[j].value() = src[j].value(); + dest[j].formula().clear(); + } + } + } + + //Clear the last row as it will be outside the table + for(auto& cell : rows[rowsCount()-1]) + { + cell.value().clear(); + cell.formula().clear(); + } + + + // Update the range coordinates + auto p = m_dataBodyRange.rangeCoordinates(); + m_dataBodyRange.setRangeCoordinates(p.first, p.second.offset(-1,0)); + + setHeaderLabels(); // relocate the labels + setTotalFormulas(); // relocate the formulas + setTotalLabels(); // reolcate the lables + adjustRef(); // update the ref + +} +////////////////////////////////////////////////////////////////////// + void XLTable::updateColumns() { m_columns.clear(); From 4add8001e93cc506a34bdb545deb22cfb91c1984 Mon Sep 17 00:00:00 2001 From: akira215 Date: Fri, 6 Jan 2023 22:32:35 +0100 Subject: [PATCH 29/45] add table autofilter syncro --- Examples/Demo10.cpp | 6 ++++-- OpenXLSX/headers/XLTable.hpp | 17 ++++++++++++++-- OpenXLSX/sources/XLTable.cpp | 39 ++++++++++++++++++++++++++++++++++-- 3 files changed, 56 insertions(+), 6 deletions(-) diff --git a/Examples/Demo10.cpp b/Examples/Demo10.cpp index 327c1d87..2154214f 100644 --- a/Examples/Demo10.cpp +++ b/Examples/Demo10.cpp @@ -122,11 +122,13 @@ int main() { // Deleting colum tbl.deleteColumn("newCol"); - - //Inserting and deleting rows + //Inserting and deleting rows auto newRow = tbl.insertRow(2); tbl.deleteRow(3); + tbl.setHeaderVisible(false); + tbl.setHeaderVisible(true); + /* // Table style basics cout << "Table Style : " << tbl.tableStyle().style() << endl; diff --git a/OpenXLSX/headers/XLTable.hpp b/OpenXLSX/headers/XLTable.hpp index 9be6258d..0df16076 100644 --- a/OpenXLSX/headers/XLTable.hpp +++ b/OpenXLSX/headers/XLTable.hpp @@ -183,17 +183,24 @@ namespace OpenXLSX void setHeaderVisible(bool visible = true); /** - * @brief + * @brief Manage display of the Total Row * @param visible */ void setTotalVisible(bool visible = true); /** - * @brief + * @brief create the autofilter * @return the autofilter object + * @note it will turn on visible the headers if required */ XLAutofilter autofilter(); + /** + * @brief remove the autofilter + * @note it is called automatically when removing headers + */ + void removeAutofilter(); + /** * @brief return the table style obect */ @@ -309,6 +316,12 @@ namespace OpenXLSX */ void adjustRef(); + /** + * @brief create the XML entry for the autofilter and setup its ref + * + */ + void setupAutofilter(); + //---------------------------------------------------------------------------------------------------------------------- // Private Member Variables //---------------------------------------------------------------------------------------------------------------------- diff --git a/OpenXLSX/sources/XLTable.cpp b/OpenXLSX/sources/XLTable.cpp index 839ccd9f..e162fd72 100644 --- a/OpenXLSX/sources/XLTable.cpp +++ b/OpenXLSX/sources/XLTable.cpp @@ -192,11 +192,13 @@ void XLTable::setHeaderVisible(bool visible) { if(visible){ // removing the attribute if visible m_pXmlData->getXmlDocument()->child("table").remove_attribute("headerRowCount"); + setupAutofilter(); } else { auto node = m_pXmlData->getXmlDocument()->child("table").attribute("headerRowCount"); if (!node) node = m_pXmlData->getXmlDocument()->child("table").append_attribute("headerRowCount"); - node.set_value("0"); + node.set_value("0"); + removeAutofilter(); } // TODO remove autofilter @@ -233,8 +235,37 @@ void XLTable::setTotalVisible(bool visible) XLAutofilter XLTable::autofilter() { + // TODO implement auto filter and adjust header masking accordingly - return XLAutofilter(m_pXmlData->getXmlDocument()->child("table").child("autoFilter"),m_pXmlData); + if(isHeaderVisible()) + setupAutofilter(); + else + setHeaderVisible(true); + + return XLAutofilter(m_pXmlData->getXmlDocument()->child("table").child("autoFilter"), + m_pXmlData); +} + +void XLTable::setupAutofilter() +{ + XMLNode node = m_pXmlData->getXmlDocument()->child("table").child("autoFilter"); + if (!node) + node = m_pXmlData->getXmlDocument()->child("table") + .insert_child_before("autoFilter", + m_pXmlData->getXmlDocument()->child("table").first_child()); + + if(!node.attribute("ref")) + node.append_attribute("ref"); + + auto p = m_dataBodyRange.rangeCoordinates(); + + node.attribute("ref").set_value(std::string(p.first.address() + + ":" + p.second.address() ).c_str()); +} + +void XLTable::removeAutofilter() +{ + m_pXmlData->getXmlDocument()->child("table").remove_child("autoFilter"); } XLTableStyle XLTable::tableStyle() @@ -340,6 +371,7 @@ void XLTable::setName(const std::string& tableName) setTotalFormulas(); // relocate the formulas setTotalLabels(); // reolcate the lables adjustRef(); // update the ref + setupAutofilter(); // update the ref //Clear the content of the new column for(auto& cell : m_columns[index].bodyRange()) @@ -414,6 +446,7 @@ void XLTable::deleteColumn(const std::string& columnName) setTotalLabels(); // reolcate the lables adjustRef(); // update the ref + setupAutofilter(); // update the ref //Clear the content of the last column, including header and total if required XLCellRange lastCol = m_columns[ m_columns.size()-1].bodyRange(); @@ -470,6 +503,7 @@ void XLTable::deleteColumn(const std::string& columnName) setTotalFormulas(); // relocate the formulas setTotalLabels(); // reolcate the lables adjustRef(); // update the ref + setupAutofilter(); // update the ref //Clear the content of the new column // but keep the column formula if any @@ -532,6 +566,7 @@ void XLTable::deleteRow(uint32_t index ) setTotalFormulas(); // relocate the formulas setTotalLabels(); // reolcate the lables adjustRef(); // update the ref + setupAutofilter(); // update the ref } ////////////////////////////////////////////////////////////////////// From 5e7ca4e6e3c66230b940ee9216ebec9aeea7583d Mon Sep 17 00:00:00 2001 From: akira215 Date: Sat, 7 Jan 2023 05:49:24 +0100 Subject: [PATCH 30/45] adding helper getAs... in XLCellValue --- OpenXLSX/headers/XLCellValue.hpp | 61 ++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/OpenXLSX/headers/XLCellValue.hpp b/OpenXLSX/headers/XLCellValue.hpp index 38c14518..8560d006 100644 --- a/OpenXLSX/headers/XLCellValue.hpp +++ b/OpenXLSX/headers/XLCellValue.hpp @@ -276,6 +276,52 @@ namespace OpenXLSX return this->get(); } + std::string getAsString() const + { + struct AnyGet { + std::string operator()(bool value) { return value ? "1" : "0"; } + std::string operator()(int64_t value) { return std::to_string(value); } + std::string operator()(double value) { return std::to_string(value); } + std::string operator()(const std::string& value) { return value; } + }; + + return std::visit(AnyGet{}, m_value); + } + + double getAsDouble() const + { + struct AnyGet { + double operator()(bool value) { return value ? 1.0 : 0.0; } + double operator()(int64_t value) { return static_cast(value); } + double operator()(double value) { return value; } + double operator()(const std::string& value) { + double res = 0.0; + try{ res = std::stod(value); + }catch(...) { res = 0.0; } + return res; + } + }; + + return std::visit(AnyGet{}, m_value); + } + + int getAsInteger() const + { + struct AnyGet { + int operator()(bool value) { return value ? 1 : 0; } + int operator()(int64_t value) { return static_cast(value); } + int operator()(double value) { return static_cast(value); } + int operator()(const std::string& value) { + int res = 0; + try{ res = std::stoi(value); + }catch(...) { res = 0; } + return res; + } + }; + + return std::visit(AnyGet{}, m_value); + } + /** * @brief Clears the contents of the XLCellValue object. * @return Returns a reference to the current object. @@ -430,6 +476,21 @@ namespace OpenXLSX return getValue().get(); } + std::string getAsString() const + { + return getValue().getAsString(); + } + + double getAsDouble() const + { + return getValue().getAsDouble(); + } + + int getAsInteger() const + { + return getValue().getAsInteger(); + } + /** * @brief Clear the contents of the cell. * @return A reference to the current object. From d835ea0f1a918e80ba5b14af34d68a09effd5fde Mon Sep 17 00:00:00 2001 From: akira215 Date: Sun, 8 Jan 2023 04:21:12 +0100 Subject: [PATCH 31/45] adding const to getter in workbook --- OpenXLSX/headers/XLWorkbook.hpp | 12 ++++++------ OpenXLSX/sources/XLWorkbook.cpp | 13 ++++++------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/OpenXLSX/headers/XLWorkbook.hpp b/OpenXLSX/headers/XLWorkbook.hpp index 7043a698..9297f05c 100644 --- a/OpenXLSX/headers/XLWorkbook.hpp +++ b/OpenXLSX/headers/XLWorkbook.hpp @@ -146,42 +146,42 @@ namespace OpenXLSX * @return A pointer to an XLAbstractSheet with the sheet at the index. * @note The index must be 1-based (rather than 0-based) as this is the default for Excel spreadsheets. */ - XLSheet sheet(uint16_t index); + XLSheet sheet(uint16_t index) const; /** * @brief Get the sheet (worksheet or chartsheet) with the given name. * @param sheetName The name at which the desired sheet is located. * @return A pointer to an XLAbstractSheet with the sheet at the index. */ - XLSheet sheet(const std::string& sheetName); + XLSheet sheet(const std::string& sheetName) const; /** * @brief Get the table with the given name. * @param tableName The name at which the desired sheet is located. * @return The table. */ - XLTable table(const std::string& tableName); + XLTable table(const std::string& tableName) const; /** * @brief * @param rangeName * @return A XLDefinedName object which is derived from XLCellRange */ - XLNamedRange namedRange(const std::string& rangeName); + XLNamedRange namedRange(const std::string& rangeName) const; /** * @brief * @param sheetName * @return */ - XLWorksheet worksheet(const std::string& sheetName); + XLWorksheet worksheet(const std::string& sheetName) const; /** * @brief * @param sheetName * @return */ - XLChartsheet chartsheet(const std::string& sheetName); + XLChartsheet chartsheet(const std::string& sheetName) const; /** * @brief Delete sheet (worksheet or chartsheet) from the workbook. diff --git a/OpenXLSX/sources/XLWorkbook.cpp b/OpenXLSX/sources/XLWorkbook.cpp index f8111ce3..17d2c6d8 100644 --- a/OpenXLSX/sources/XLWorkbook.cpp +++ b/OpenXLSX/sources/XLWorkbook.cpp @@ -88,9 +88,8 @@ XLWorkbook::~XLWorkbook() = default; /** * @details */ -XLSheet XLWorkbook::sheet(const std::string& sheetName) +XLSheet XLWorkbook::sheet(const std::string& sheetName) const { - XLQuery xmlQuery(XLQueryType::QuerySheetFromName); xmlQuery.setParam("sheetName", sheetName); return XLSheet(parentDoc().execQuery(xmlQuery).result()); @@ -100,7 +99,7 @@ XLSheet XLWorkbook::sheet(const std::string& sheetName) * @details Create a vector with sheet nodes, retrieve the node at the requested index, get sheet name and return the * corresponding sheet object. */ -XLSheet XLWorkbook::sheet(uint16_t index) +XLSheet XLWorkbook::sheet(uint16_t index) const { if (index < 1 || index > sheetCount()) throw XLInputError("Sheet index is out of bounds"); return sheet( @@ -110,12 +109,12 @@ XLSheet XLWorkbook::sheet(uint16_t index) /** * @details */ -XLWorksheet XLWorkbook::worksheet(const std::string& sheetName) +XLWorksheet XLWorkbook::worksheet(const std::string& sheetName) const { return sheet(sheetName).get(); } -XLTable XLWorkbook::table(const std::string& tableName) +XLTable XLWorkbook::table(const std::string& tableName) const { // Throw an exception if table not exist XLQuery xmlQuery(XLQueryType::QueryTableFromName); @@ -126,7 +125,7 @@ XLTable XLWorkbook::table(const std::string& tableName) return XLTable(tableItem); } -XLNamedRange XLWorkbook::namedRange(const std::string& rangeName) +XLNamedRange XLWorkbook::namedRange(const std::string& rangeName) const { auto ElmtNode = xmlDocument().document_element().child("definedNames").find_child_by_attribute("name", rangeName.c_str()); @@ -162,7 +161,7 @@ XLNamedRange XLWorkbook::namedRange(const std::string& rangeName) /** * @details */ -XLChartsheet XLWorkbook::chartsheet(const std::string& sheetName) +XLChartsheet XLWorkbook::chartsheet(const std::string& sheetName) const { return sheet(sheetName).get(); } From 175b24f84f80cf9009e20d1c910c1c2a5f70bcb1 Mon Sep 17 00:00:00 2001 From: akira215 Date: Tue, 17 Jan 2023 08:17:56 -0500 Subject: [PATCH 32/45] Adding table utilities --- Examples/Demo10.cpp | 5 ++ OpenXLSX/headers/XLCommandQuery.hpp | 3 + OpenXLSX/headers/XLDocument.hpp | 62 +++++++++--------- OpenXLSX/headers/XLWorkbook.hpp | 86 +++++++++++++++++-------- OpenXLSX/headers/XLXmlData.hpp | 2 +- OpenXLSX/sources/XLDocument.cpp | 98 ++++++++++++++++++++++++++--- OpenXLSX/sources/XLWorkbook.cpp | 68 +++++++++++++++++++- OpenXLSX/sources/XLXmlData.cpp | 2 +- 8 files changed, 260 insertions(+), 66 deletions(-) diff --git a/Examples/Demo10.cpp b/Examples/Demo10.cpp index 2154214f..e93075b2 100644 --- a/Examples/Demo10.cpp +++ b/Examples/Demo10.cpp @@ -129,6 +129,11 @@ int main() { tbl.setHeaderVisible(false); tbl.setHeaderVisible(true); + + auto test = doc.workbook().tableNames(); + + doc.workbook().deleteTable("MyTable"); + /* // Table style basics cout << "Table Style : " << tbl.tableStyle().style() << endl; diff --git a/OpenXLSX/headers/XLCommandQuery.hpp b/OpenXLSX/headers/XLCommandQuery.hpp index e03b5ca8..3b1727d7 100644 --- a/OpenXLSX/headers/XLCommandQuery.hpp +++ b/OpenXLSX/headers/XLCommandQuery.hpp @@ -77,6 +77,7 @@ namespace OpenXLSX AddChartsheet, AddTable, DeleteSheet, + DeleteTable, CloneSheet, }; @@ -144,6 +145,8 @@ namespace OpenXLSX QuerySheetRelsTarget, QuerySharedStrings, QuerySheetFromName, + QueryTableCount, + QueryTableFromIndex, QueryTableFromName, QueryXmlData }; diff --git a/OpenXLSX/headers/XLDocument.hpp b/OpenXLSX/headers/XLDocument.hpp index d4548553..fe752ccb 100644 --- a/OpenXLSX/headers/XLDocument.hpp +++ b/OpenXLSX/headers/XLDocument.hpp @@ -15,33 +15,33 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. MM _MM_ - Copyright (c) 2018, Kenneth Troldal Balslev - - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - Neither the name of the author nor the - names of any contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - */ + Copyright (c) 2018, Kenneth Troldal Balslev + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + - Neither the name of the author nor the + names of any contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ #ifndef OPENXLSX_XLDOCUMENT_HPP #define OPENXLSX_XLDOCUMENT_HPP @@ -316,12 +316,18 @@ namespace OpenXLSX /** * @brief create a new table in the doc + * @param sheetName * @param tableName * @param reference - * @return */ void createTable(const std::string& sheetName, const std::string& tableName, const std::string& reference); + /** + * @brief delete the corresponding table + * @param tableName the table to be deleted + */ + void deleteTable(const std::string& tableName); + //---------------------------------------------------------------------------------------------------------------------- // Private Member Variables //---------------------------------------------------------------------------------------------------------------------- diff --git a/OpenXLSX/headers/XLWorkbook.hpp b/OpenXLSX/headers/XLWorkbook.hpp index 9297f05c..4bfc82bd 100644 --- a/OpenXLSX/headers/XLWorkbook.hpp +++ b/OpenXLSX/headers/XLWorkbook.hpp @@ -15,33 +15,33 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. MM _MM_ - Copyright (c) 2018, Kenneth Troldal Balslev - - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - Neither the name of the author nor the - names of any contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - */ + Copyright (c) 2018, Kenneth Troldal Balslev + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + - Neither the name of the author nor the + names of any contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ #ifndef OPENXLSX_XLWORKBOOK_HPP #define OPENXLSX_XLWORKBOOK_HPP @@ -162,6 +162,13 @@ namespace OpenXLSX */ XLTable table(const std::string& tableName) const; + /** + * @brief Get the table with the given index. + * @param index The name at which the desired sheet is located. + * @return The table. + */ + XLTable table(uint16_t index) const; + /** * @brief * @param rangeName @@ -228,6 +235,12 @@ namespace OpenXLSX XLTable addTable(const std::string& sheetName, const std::string& tableName, const std::string& reference); + /** + * @brief detele table but without clearing the data + * @param tableName Name of the table to be deleted + */ + void deleteTable(const std::string& tableName); + /** * @brief * @param existingName @@ -281,6 +294,12 @@ namespace OpenXLSX */ unsigned int chartsheetCount() const; + /** + * @brief + * @return + */ + unsigned int tableCount() const; + /** * @brief * @return @@ -299,6 +318,12 @@ namespace OpenXLSX */ std::vector chartsheetNames() const; + /** + * @brief + * @return + */ + std::vector tableNames() const; + /** * @brief * @param sheetName @@ -320,6 +345,13 @@ namespace OpenXLSX */ bool chartsheetExists(const std::string& sheetName) const; + /** + * @brief + * @param tableName + * @return + */ + bool tableExists(const std::string& tableName) const; + /** * @brief * @param oldName diff --git a/OpenXLSX/headers/XLXmlData.hpp b/OpenXLSX/headers/XLXmlData.hpp index f0749638..793d9f9d 100644 --- a/OpenXLSX/headers/XLXmlData.hpp +++ b/OpenXLSX/headers/XLXmlData.hpp @@ -195,7 +195,7 @@ namespace OpenXLSX * @brief Retrieve the type represented by the XML data. * @return A XLContentType getValue representing the type. */ - std::vector getChildNodes() const; + std::vector& getChildNodes(); /** * @brief Access the underlying XMLDocument object. diff --git a/OpenXLSX/sources/XLDocument.cpp b/OpenXLSX/sources/XLDocument.cpp index a4e69b6d..4bcbad73 100644 --- a/OpenXLSX/sources/XLDocument.cpp +++ b/OpenXLSX/sources/XLDocument.cpp @@ -533,14 +533,10 @@ void XLDocument::execCommand(const XLCommand& command) { break; case XLCommandType::AddTable: { - //TODO worksheet ! createTable(command.getParam("worksheet"), command.getParam("tableName"), command.getParam("reference")); - //get nexta available filename and next available id - // check that the name dont already exist } - // TODO: To be implemented break; case XLCommandType::DeleteSheet: { @@ -554,6 +550,12 @@ void XLDocument::execCommand(const XLCommand& command) { })); } break; + case XLCommandType::DeleteTable: + { + deleteTable(command.getParam("tableName")); + } + // TODO: To be implemented + break; case XLCommandType::CloneSheet: { auto internalID = availableFileID(XLContentType::Worksheet); @@ -640,7 +642,31 @@ XLQuery XLDocument::execQuery(const XLQuery& query) const case XLQueryType::QuerySheetFromName: return XLQuery(query).setResult(getXmlDataByName(query.getParam("sheetName"))); - + + case XLQueryType::QueryTableCount: + { + unsigned int results = 0; + + for (auto& item : m_data){ + if(item.getXmlType() == XLContentType::Table) + ++results; + } + + return XLQuery(query).setResult(results); + } + case XLQueryType::QueryTableFromIndex: + { + unsigned int index = 0; + for (auto& item : m_data){ + if(item.getXmlType() == XLContentType::Table){ + if(index == query.getParam("index")) + return XLQuery(query).setResult(&item); + ++index; + } + } + + return query; // Table not found + } case XLQueryType::QueryTableFromName: { for (auto& item : m_data){ @@ -928,6 +954,64 @@ void XLDocument::createTable(const std::string& sheetName, const std::string& ta columnsNode.attribute("count").set_value(std::to_string(colId-1).c_str()); // TODEL - delete pWks; - + delete pWks; } + +void XLDocument::deleteTable(const std::string& tableName) +{ + XLXmlData* pTable = getXmlDataByName(tableName); + if(pTable == nullptr){ + XLLogError("Table \"" + tableName + "\" does not exist, impossible to delete."); + return; // table doesn't exist + } + XLXmlData* pSheet = pTable->getParentNode(); + XLXmlData* pShtRls = getXmlDataByPath(getSheetRelsPath(pSheet->getName())); + std::string rId = pTable->getXmlID(); + + // Delete tablePart in sheet{0}.xml + auto& shtChildren = pSheet->getChildNodes(); + XMLNode tableParts = pSheet->getXmlDocument()->document_element().child("tableParts"); + if(tableParts){ + tableParts.remove_child( + tableParts.find_child_by_attribute("r:id", rId.c_str())); + + uint16_t n = 0; // count children + for (XMLNode child : tableParts.children()) n++; + + if (n>0) + tableParts.attribute("count") + .set_value(std::to_string(n).c_str()); + else + pSheet->getXmlDocument()->document_element().remove_child("tableParts"); + } + + // Delete Relathionship in sheet{0}.xml.rels + XMLNode rels = pShtRls->getXmlDocument()->document_element(); + if(rels){ + rels.remove_child( + rels.find_child_by_attribute("Id", rId.c_str())); + + uint16_t n = 0; // count children + for (XMLNode child : rels.children()) n++; + + if (n == 0){ + // No more relations, we can delete the file + std::string relsPath = pShtRls ->getXmlPath(); + m_archive.deleteEntry(relsPath); + shtChildren.erase(std::find_if(shtChildren.begin(), shtChildren.end(), [&](XLXmlData* item) { + return item->getXmlPath() == relsPath;})); + m_data.erase(std::find_if(m_data.begin(), m_data.end(), [&](const XLXmlData& item) { + return item.getXmlPath() == relsPath;})); + } + } // if rels + + // Delete table{0}.xml file and its reference + std::string tblPath = pTable->getXmlPath(); + m_archive.deleteEntry(tblPath); + m_contentTypes.deleteOverride("/" + tblPath); + shtChildren.erase(std::find_if(shtChildren.begin(), shtChildren.end(), [&](XLXmlData* item) { + return item->getName() == tableName;})); + m_data.erase(std::find_if(m_data.begin(), m_data.end(), [&](const XLXmlData& item) { + return item.getXmlPath() == tblPath;})); + +} \ No newline at end of file diff --git a/OpenXLSX/sources/XLWorkbook.cpp b/OpenXLSX/sources/XLWorkbook.cpp index 17d2c6d8..ee0b5ed5 100644 --- a/OpenXLSX/sources/XLWorkbook.cpp +++ b/OpenXLSX/sources/XLWorkbook.cpp @@ -72,6 +72,7 @@ namespace { return doc.document_element().child("sheets"); } + } // namespace /** @@ -125,6 +126,15 @@ XLTable XLWorkbook::table(const std::string& tableName) const return XLTable(tableItem); } +XLTable XLWorkbook::table(uint16_t index) const +{ + XLQuery query(XLQueryType::QueryTableFromIndex); + query.setParam("index", index); + + return XLTable(parentDoc().execQuery(query).result()); +} + + XLNamedRange XLWorkbook::namedRange(const std::string& rangeName) const { auto ElmtNode = xmlDocument().document_element().child("definedNames").find_child_by_attribute("name", rangeName.c_str()); @@ -195,8 +205,26 @@ void XLWorkbook::deleteSheet(const std::string& sheetName) }); // ===== If this is the last worksheet in the workbook, throw an exception. - if (worksheetCount == 1 && sheetType == XLContentType::Worksheet) - throw XLInputError("Invalid operation. There must be at least one worksheet in the workbook."); + if (worksheetCount == 1 && sheetType == XLContentType::Worksheet){ + //throw XLInputError("Invalid operation. There must be at least one worksheet in the workbook."); + XLLogError("Unable to delete the worksheet \""+ sheetName + "\". There must be at least one worksheet in the workbook."); + return; + } + + // ===== eliminate the tables contained in the worksheet. + if (sheetType == XLContentType::Worksheet){ + XLQuery queryXml(XLQueryType::QuerySheetFromName); + queryXml.setParam("sheetName", sheetName); + XLXmlData* pSheet = parentDoc().execQuery(queryXml).result(); + std::vector tblNames; + for (XLXmlData* item : pSheet->getChildNodes()){ + if (item->getXmlType() == XLContentType::Table) + tblNames.emplace_back(item->getName()); + } + + for (std::string& tblName : tblNames) + deleteTable(tblName); + } // ===== Delete the sheet data as well as the sheet node from Workbook.xml parentDoc().execCommand(XLCommand(XLCommandType::DeleteSheet) @@ -313,6 +341,14 @@ XLTable XLWorkbook::addTable(const std::string& sheetName, const std::string& ta return table(tableName); } +void XLWorkbook::deleteTable(const std::string& tableName) +{ + // ===== Delete the sheet data as well as the sheet node from Workbook.xml + parentDoc().execCommand(XLCommand(XLCommandType::DeleteTable) + .setParam("tableName", tableName)); + +} + /** * @details @@ -542,6 +578,12 @@ unsigned int XLWorkbook::chartsheetCount() const return static_cast(chartsheetNames().size()); } +unsigned int XLWorkbook::tableCount() const +{ + return parentDoc().execQuery(XLQuery(XLQueryType::QueryTableCount)). + result(); +} + /** * @details */ @@ -588,6 +630,22 @@ std::vector XLWorkbook::chartsheetNames() const return results; } + +std::vector XLWorkbook::tableNames() const +{ + std::vector results; + + for (unsigned int i = 0 ; i < tableCount(); ++i){ + XLQuery query(XLQueryType::QueryTableFromIndex); + query.setParam("index", i); + results.emplace_back(parentDoc() + .execQuery(query).result()->getName()); + } + + return results; + +} + /** * @details */ @@ -614,6 +672,12 @@ bool XLWorkbook::chartsheetExists(const std::string& sheetName) const return std::find(chsNames.begin(), chsNames.end(), sheetName) != chsNames.end(); } +bool XLWorkbook::tableExists(const std::string& tableName) const +{ + auto tblNames = tableNames(); + return std::find(tblNames.begin(), tblNames.end(), tableName) != tblNames.end(); +} + /** * @details The UpdateSheetName member function searches throug the usages of the old name and replaces with the * new sheet name. diff --git a/OpenXLSX/sources/XLXmlData.cpp b/OpenXLSX/sources/XLXmlData.cpp index be5440d7..3f07350e 100644 --- a/OpenXLSX/sources/XLXmlData.cpp +++ b/OpenXLSX/sources/XLXmlData.cpp @@ -179,7 +179,7 @@ XLXmlData* XLXmlData::getParentNode() const return m_parentNode; } -std::vector XLXmlData::getChildNodes() const +std::vector& XLXmlData::getChildNodes() { return m_childNodes; } From 989fbf645d4f3dfe389e46f30665437154792a45 Mon Sep 17 00:00:00 2001 From: akira215 Date: Tue, 17 Jan 2023 09:40:36 -0500 Subject: [PATCH 33/45] correcting sheetID --- OpenXLSX/headers/XLDocument.hpp | 8 ++++++++ OpenXLSX/headers/XLWorkbook.hpp | 5 ++++- OpenXLSX/sources/XLDocument.cpp | 22 ++++++++++++++++++++-- OpenXLSX/sources/XLWorkbook.cpp | 6 ++++-- 4 files changed, 36 insertions(+), 5 deletions(-) diff --git a/OpenXLSX/headers/XLDocument.hpp b/OpenXLSX/headers/XLDocument.hpp index fe752ccb..c7d18eef 100644 --- a/OpenXLSX/headers/XLDocument.hpp +++ b/OpenXLSX/headers/XLDocument.hpp @@ -314,6 +314,14 @@ namespace OpenXLSX */ uint16_t availableFileID(XLContentType type); + /** + * @brief determine the available id disponible for Id field + * @param type + * @return Return the available id. + * @note fill the gap if any + */ + uint16_t availableSheetID(); + /** * @brief create a new table in the doc * @param sheetName diff --git a/OpenXLSX/headers/XLWorkbook.hpp b/OpenXLSX/headers/XLWorkbook.hpp index 4bfc82bd..8c30b454 100644 --- a/OpenXLSX/headers/XLWorkbook.hpp +++ b/OpenXLSX/headers/XLWorkbook.hpp @@ -408,8 +408,11 @@ namespace OpenXLSX * @brief * @param sheetName * @param internalID + * @param sheetID */ - void prepareSheetMetadata(const std::string& sheetName, uint16_t internalID); + void prepareSheetMetadata(const std::string& sheetName, + uint16_t internalID, + uint16_t sheetID); /** * @brief diff --git a/OpenXLSX/sources/XLDocument.cpp b/OpenXLSX/sources/XLDocument.cpp index 4bcbad73..2f2beafa 100644 --- a/OpenXLSX/sources/XLDocument.cpp +++ b/OpenXLSX/sources/XLDocument.cpp @@ -512,6 +512,7 @@ void XLDocument::execCommand(const XLCommand& command) { case XLCommandType::AddWorksheet: { auto internalID = availableFileID(XLContentType::Worksheet); + auto sheetID = availableSheetID(); std::string sheetPath = "xl/worksheets/sheet" + std::to_string(internalID) + ".xml"; m_contentTypes.addOverride("/" + sheetPath, XLContentType::Worksheet); m_wbkRelationships.addRelationship(XLRelationshipType::Worksheet, sheetPath.substr(3)); @@ -525,7 +526,7 @@ void XLDocument::execCommand(const XLCommand& command) { /* xmlType */ XLContentType::Worksheet); // TODO move elsewhere ? - m_workbook.prepareSheetMetadata(command.getParam("sheetName"), internalID); + m_workbook.prepareSheetMetadata(command.getParam("sheetName"), internalID, sheetID); } break; case XLCommandType::AddChartsheet: @@ -559,6 +560,7 @@ void XLDocument::execCommand(const XLCommand& command) { case XLCommandType::CloneSheet: { auto internalID = availableFileID(XLContentType::Worksheet); + auto sheetID = availableSheetID(); auto sheetPath = "/xl/worksheets/sheet" + std::to_string(internalID) + ".xml"; if (m_workbook.sheetExists(command.getParam("cloneName"))) throw XLInternalError("Sheet named \"" + command.getParam("cloneName") + "\" already exists."); @@ -596,7 +598,7 @@ void XLDocument::execCommand(const XLCommand& command) { /* xmlType */ XLContentType::Chartsheet); } - m_workbook.prepareSheetMetadata(command.getParam("cloneName"), internalID); + m_workbook.prepareSheetMetadata(command.getParam("cloneName"), internalID, sheetID); } break; } @@ -814,6 +816,22 @@ uint16_t XLDocument::availableFileID(XLContentType type) return nFile; } +uint16_t XLDocument::availableSheetID() +{ + std::vector idIndices; + auto node = m_XmlWorkbook->getXmlDocument()->document_element().child("sheets"); + for (auto& wsItem : node.children()) + idIndices.push_back(std::stoi(wsItem.attribute("sheetId").value())); + + std::sort (idIndices.begin(), idIndices.end()); + uint16_t nId = 1; + for(uint32_t i : idIndices) + if (i == nId) + nId +=1; + + return nId; +} + /** * @todo check if the reference overlap an existing table */ diff --git a/OpenXLSX/sources/XLWorkbook.cpp b/OpenXLSX/sources/XLWorkbook.cpp index ee0b5ed5..13093f36 100644 --- a/OpenXLSX/sources/XLWorkbook.cpp +++ b/OpenXLSX/sources/XLWorkbook.cpp @@ -389,7 +389,9 @@ std::string XLWorkbook::sheetVisibility(const std::string& sheetID) const /** * @details */ -void XLWorkbook::prepareSheetMetadata(const std::string& sheetName, uint16_t internalID) +void XLWorkbook::prepareSheetMetadata(const std::string& sheetName, + uint16_t internalID, + uint16_t sheetID) { // ===== Add new child node to the "sheets" node. auto node = sheetsNode(xmlDocument()).append_child("sheet"); @@ -397,7 +399,7 @@ void XLWorkbook::prepareSheetMetadata(const std::string& sheetName, uint16_t int // ===== append the required attributes to the newly created sheet node. std::string sheetPath = "/xl/worksheets/sheet" + std::to_string(internalID) + ".xml"; node.append_attribute("name") = sheetName.c_str(); - node.append_attribute("sheetId") = std::to_string(internalID).c_str(); + node.append_attribute("sheetId") = std::to_string(sheetID).c_str(); XLQuery query(XLQueryType::QuerySheetRelsID); query.setParam("sheetPath", sheetPath); From 5767b2fb4e6c2df51e0811eebfcf538c292004f0 Mon Sep 17 00:00:00 2001 From: akira215 Date: Tue, 17 Jan 2023 10:15:00 -0500 Subject: [PATCH 34/45] Changing setTabColor Names --- Examples/Demo10.cpp | 7 ++++--- OpenXLSX/headers/XLSheet.hpp | 4 ++-- OpenXLSX/sources/XLSheet.cpp | 10 +++++----- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/Examples/Demo10.cpp b/Examples/Demo10.cpp index e93075b2..4dbaca06 100644 --- a/Examples/Demo10.cpp +++ b/Examples/Demo10.cpp @@ -129,10 +129,7 @@ int main() { tbl.setHeaderVisible(false); tbl.setHeaderVisible(true); - - auto test = doc.workbook().tableNames(); - doc.workbook().deleteTable("MyTable"); /* // Table style basics @@ -151,6 +148,10 @@ int main() { tbl.tableStyle().showFirstColumnHighlighted(true); tbl.tableStyle().showLastColumnHighlighted(true); */ + + auto tablelist = doc.workbook().tableNames(); + doc.workbook().deleteTable("MyTable"); + doc.save(); doc.close(); diff --git a/OpenXLSX/headers/XLSheet.hpp b/OpenXLSX/headers/XLSheet.hpp index 6794adc8..e9363ae6 100644 --- a/OpenXLSX/headers/XLSheet.hpp +++ b/OpenXLSX/headers/XLSheet.hpp @@ -194,7 +194,7 @@ namespace OpenXLSX * @brief * @param color */ - void setColor(const XLColor& color) + void setTabColor(const XLColor& color) { static_cast(*this).setColor_impl(color); } @@ -649,7 +649,7 @@ namespace OpenXLSX * @brief * @param color */ - void setColor(const XLColor& color); + void setTabColor(const XLColor& color); /** * @brief Method for getting the index of the sheet. diff --git a/OpenXLSX/sources/XLSheet.cpp b/OpenXLSX/sources/XLSheet.cpp index dbe6ef3a..ebfc9027 100644 --- a/OpenXLSX/sources/XLSheet.cpp +++ b/OpenXLSX/sources/XLSheet.cpp @@ -66,7 +66,7 @@ namespace OpenXLSX * @param xmlDocument XMLDocument object * @param color Thr color to set */ - void setTabColor(const XMLDocument& xmlDocument, const XLColor& color) { + void setTabColorOnDoc(const XMLDocument& xmlDocument, const XLColor& color) { if (!xmlDocument.document_element().child("sheetPr")) xmlDocument.document_element().prepend_child("sheetPr"); @@ -165,9 +165,9 @@ XLColor XLSheet::color() const * @details This method sets the color of the sheet, by calling the setColor() * member function of the underlying sheet object (XLWorksheet or XLChartsheet). */ -void XLSheet::setColor(const XLColor& color) +void XLSheet::setTabColor(const XLColor& color) { - std::visit([&](auto&& arg) { return arg.setColor(color); }, m_sheet); + std::visit([&](auto&& arg) { return arg.setTabColor(color); }, m_sheet); } /** @@ -283,7 +283,7 @@ XLColor XLWorksheet::getColor_impl() const */ void XLWorksheet::setColor_impl(const XLColor& color) { - setTabColor(xmlDocument(), color); + setTabColorOnDoc(xmlDocument(), color); } /** @@ -612,7 +612,7 @@ XLColor XLChartsheet::getColor_impl() const */ void XLChartsheet::setColor_impl(const XLColor& color) { - setTabColor(xmlDocument(), color); + setTabColorOnDoc(xmlDocument(), color); } /** From 89971b4dfcb09bec0edc3e4db58c2fb50d9c8886 Mon Sep 17 00:00:00 2001 From: akira215 Date: Tue, 17 Jan 2023 10:16:19 -0500 Subject: [PATCH 35/45] updating example --- Examples/Demo03.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Examples/Demo03.cpp b/Examples/Demo03.cpp index c3878a9a..f891ab24 100644 --- a/Examples/Demo03.cpp +++ b/Examples/Demo03.cpp @@ -78,10 +78,10 @@ int main() // The color of each sheet tab can be set using the 'setColor' method for a // sheet, and passing an XLColor object as an argument. - wbk.sheet("Sheet2").setColor(XLColor(0, 0, 0)); - wbk.sheet("Sheet3").setColor(XLColor(255, 0, 0)); - wbk.sheet("Sheet4").setColor(XLColor(0, 255, 0)); - wbk.sheet("Sheet5").setColor(XLColor(0, 0, 255)); + wbk.sheet("Sheet2").setTabColor(XLColor(0, 0, 0)); + wbk.sheet("Sheet3").setTabColor(XLColor(255, 0, 0)); + wbk.sheet("Sheet4").setTabColor(XLColor(0, 255, 0)); + wbk.sheet("Sheet5").setTabColor(XLColor(0, 0, 255)); doc.save(); From 30010efe1f3974685add4aac8b777e7505c44419 Mon Sep 17 00:00:00 2001 From: akira215 Date: Sat, 28 Jan 2023 08:57:38 -0500 Subject: [PATCH 36/45] Fixed this pointer check in XLCell --- OpenXLSX/sources/XLCell.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/OpenXLSX/sources/XLCell.cpp b/OpenXLSX/sources/XLCell.cpp index 5a514892..ffdaf16f 100644 --- a/OpenXLSX/sources/XLCell.cpp +++ b/OpenXLSX/sources/XLCell.cpp @@ -143,7 +143,7 @@ XLCell::operator bool() const */ XLCellReference XLCell::cellReference() const { - if (!*this) throw XLInternalError("XLCell object has not been properly initiated."); + if (!this) throw XLInternalError("XLCell object has not been properly initiated."); return XLCellReference{m_cellNode->attribute("r").value()}; } @@ -152,7 +152,7 @@ XLCellReference XLCell::cellReference() const */ XLCell XLCell::offset(uint16_t rowOffset, uint16_t colOffset) const { - if (!*this) throw XLInternalError("XLCell object has not been properly initiated."); + if (!this) throw XLInternalError("XLCell object has not been properly initiated."); XLCellReference offsetRef(cellReference().row() + rowOffset, cellReference().column() + colOffset); auto rownode = getRowNode(m_cellNode->parent().parent(), offsetRef.row()); auto cellnode = getCellNode(rownode, offsetRef.column()); @@ -164,7 +164,7 @@ XLCell XLCell::offset(uint16_t rowOffset, uint16_t colOffset) const */ bool XLCell::hasFormula() const { - if (!*this) return false; + if (!this) return false; return m_cellNode->child("f") != nullptr; } @@ -173,7 +173,7 @@ bool XLCell::hasFormula() const */ XLFormulaProxy& XLCell::formula() { - if (!*this) throw XLInternalError("XLCell object has not been properly initiated."); + if (!this) throw XLInternalError("XLCell object has not been properly initiated."); return m_formulaProxy; } @@ -182,7 +182,7 @@ XLFormulaProxy& XLCell::formula() */ const XLFormulaProxy& XLCell::formula() const { - if (!*this) throw XLInternalError("XLCell object has not been properly initiated."); + if (!this) throw XLInternalError("XLCell object has not been properly initiated."); return m_formulaProxy; } @@ -192,7 +192,7 @@ const XLFormulaProxy& XLCell::formula() const */ XLCellValueProxy& XLCell::value() { - if (!*this) throw XLInternalError("XLCell object has not been properly initiated."); + if (!this) throw XLInternalError("XLCell object has not been properly initiated."); return m_valueProxy; } @@ -203,7 +203,7 @@ XLCellValueProxy& XLCell::value() */ const XLCellValueProxy& XLCell::value() const { - if (!*this) throw XLInternalError("XLCell object has not been properly initiated."); + if (!this) throw XLInternalError("XLCell object has not been properly initiated."); return m_valueProxy; } From 3fb704f2851c3861e4f05ffd7d717fc853294742 Mon Sep 17 00:00:00 2001 From: akira215 Date: Sat, 28 Jan 2023 09:03:21 -0500 Subject: [PATCH 37/45] Enforce formula node order and properly convert cell type to number --- OpenXLSX/sources/XLFormula.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/OpenXLSX/sources/XLFormula.cpp b/OpenXLSX/sources/XLFormula.cpp index 945a8d4e..06bd1518 100644 --- a/OpenXLSX/sources/XLFormula.cpp +++ b/OpenXLSX/sources/XLFormula.cpp @@ -220,6 +220,15 @@ void XLFormulaProxy::setFormulaString(const char* formulaString) { // ===== Set the text of the value node. m_cellNode->child("f").text().set(formulaString); m_cellNode->child("v").text().set(0); + + // ===== Remove "t" attribute so that the cell shows the number we've just set + m_cellNode->remove_attribute("t"); + + // ===== Remove tag in case previous type was "inlineStr" + m_cellNode->remove_child("is"); + + // ===== Excel fails to load documents where comes after so make sure it is the first child + m_cellNode->prepend_move(m_cellNode->child("f")); } /** From a08ae2617f23dc99a9325025b16e2b2b3607f0be Mon Sep 17 00:00:00 2001 From: akira215 Date: Sat, 28 Jan 2023 09:07:34 -0500 Subject: [PATCH 38/45] Fix changing values of cells of type "inlineStr" --- OpenXLSX/sources/XLCellValue.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/OpenXLSX/sources/XLCellValue.cpp b/OpenXLSX/sources/XLCellValue.cpp index 21bb2021..51cabddf 100644 --- a/OpenXLSX/sources/XLCellValue.cpp +++ b/OpenXLSX/sources/XLCellValue.cpp @@ -199,6 +199,9 @@ XLCellValueProxy& XLCellValueProxy::clear() // ===== Remove the value node. m_cellNode->remove_child("v"); + + // ===== Remove the is node (only relevant in case previous cell type was "inlineStr") + m_cellNode->remove_child("is"); return *this; } /** @@ -228,6 +231,9 @@ XLCellValueProxy& XLCellValueProxy::setError(const std::string &error) // ===== Disable space preservation (only relevant for strings). m_cellNode->remove_attribute(" xml:space"); + // ===== Remove the is node (only relevant in case previous cell type was "inlineStr") + m_cellNode->remove_child("is"); + return *this; } @@ -320,6 +326,9 @@ void XLCellValueProxy::setInteger(int64_t numberValue) // ===== Disable space preservation (only relevant for strings). m_cellNode->child("v").remove_attribute(m_cellNode->child("v").attribute("xml:space")); + + // ===== Remove the is node (only relevant in case previous cell type was "inlineStr") + m_cellNode->remove_child("is"); } /** @@ -348,6 +357,9 @@ void XLCellValueProxy::setBoolean(bool numberValue) // ===== Disable space preservation (only relevant for strings). m_cellNode->child("v").remove_attribute(m_cellNode->child("v").attribute("xml:space")); + + // ===== Remove the is node (only relevant in case previous cell type was "inlineStr") + m_cellNode->remove_child("is"); } /** @@ -375,6 +387,9 @@ void XLCellValueProxy::setFloat(double numberValue) // ===== Disable space preservation (only relevant for strings). m_cellNode->child("v").remove_attribute(m_cellNode->child("v").attribute("xml:space")); + + // ===== Remove the is node (only relevant in case previous cell type was "inlineStr") + m_cellNode->remove_child("is"); } else { setError("#NUM!"); @@ -414,6 +429,9 @@ void XLCellValueProxy::setString(const char* stringValue) // ===== Set the text of the value node. m_cellNode->child("v").text().set(index); + // ===== Remove the is node (only relevant in case previous cell type was "inlineStr") + m_cellNode->remove_child("is"); + // IMPLEMENTATION FOR EMBEDDED STRINGS: // m_cellNode->attribute("t").set_value("str"); // m_cellNode->child("v").text().set(stringValue); From 13688bc93e09d63e020bb56a2d7561bac084b66b Mon Sep 17 00:00:00 2001 From: akira215 Date: Sat, 28 Jan 2023 09:16:57 -0500 Subject: [PATCH 39/45] Fix loading of xlsx files without xl/workbook.xml --- OpenXLSX/sources/XLDocument.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/OpenXLSX/sources/XLDocument.cpp b/OpenXLSX/sources/XLDocument.cpp index 2f2beafa..ba9b4db5 100644 --- a/OpenXLSX/sources/XLDocument.cpp +++ b/OpenXLSX/sources/XLDocument.cpp @@ -107,6 +107,12 @@ void XLDocument::open(const std::string& fileName) if (!m_archive.hasEntry("xl/sharedStrings.xml")) execCommand(XLCommand(XLCommandType::AddSharedStrings)); + + // Add /xl/workbook.xml entry if the file didn't have one + auto items = m_contentTypes.getContentItems(); + if(std::find_if(items.begin(), items.end(), [&](const XLContentItem& item) + { return item.path() == "/xl/workbook.xml"; }) == items.end()) + m_contentTypes.addOverride("/xl/workbook.xml", XLContentType::Workbook); // ===== Add remaining spreadsheet elements to the vector of XLXmlData objects. for (auto& item : m_contentTypes.getContentItems()) { From 7aac01f083701a433cda47fb67c1ac9f9ed9fc3e Mon Sep 17 00:00:00 2001 From: akira215 Date: Sat, 28 Jan 2023 09:21:03 -0500 Subject: [PATCH 40/45] Update XLSheet.cpp with correct type --- OpenXLSX/sources/XLSheet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenXLSX/sources/XLSheet.cpp b/OpenXLSX/sources/XLSheet.cpp index ebfc9027..32dd1baf 100644 --- a/OpenXLSX/sources/XLSheet.cpp +++ b/OpenXLSX/sources/XLSheet.cpp @@ -536,7 +536,7 @@ XLCellReference XLWorksheet::lastCell() const noexcept */ uint16_t XLWorksheet::columnCount() const noexcept { - std::vector counts; + std::vector counts; for (const auto& row : rows()) { counts.emplace_back(row.cellCount()); } From eba7fb2b13c470b462939fd5082f951d167b0839 Mon Sep 17 00:00:00 2001 From: akira215 Date: Sat, 28 Jan 2023 09:35:59 -0500 Subject: [PATCH 41/45] Use a constexpr variable for the template array --- OpenXLSX/headers/XLTemplates.hpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/OpenXLSX/headers/XLTemplates.hpp b/OpenXLSX/headers/XLTemplates.hpp index cfc5b12e..52a2f32b 100644 --- a/OpenXLSX/headers/XLTemplates.hpp +++ b/OpenXLSX/headers/XLTemplates.hpp @@ -6,7 +6,6 @@ #define OPENXLSX_XLTEMPLATES_HPP #include - namespace OpenXLSX { namespace XLTemplate { @@ -102,9 +101,9 @@ namespace OpenXLSX "PivotStyleDark26", "PivotStyleDark27", "PivotStyleDark28", }; - const int templateSize = 7714; + constexpr int templateSize = 7714; - const unsigned char templateData[7714] = { + constexpr unsigned char templateData[7714] = { 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00, 0x21, 0x00, 0xb5, 0x55, 0x30, 0x23, 0xf4, 0x00, 0x00, 0x00, 0x4c, 0x02, 0x00, 0x00, 0x0b, 0x00, 0x08, 0x02, 0x5f, 0x72, 0x65, 0x6c, 0x73, 0x2f, 0x2e, 0x72, 0x65, 0x6c, 0x73, 0x20, 0xa2, 0x04, 0x02, 0x28, 0xa0, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, From a29659390170705c0bf047b20b2a555028cf51bd Mon Sep 17 00:00:00 2001 From: akira215 Date: Sat, 28 Jan 2023 09:38:55 -0500 Subject: [PATCH 42/45] Fix crash when using XLCellProxyValue()::set() with an empty string --- OpenXLSX/sources/XLSharedStrings.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/OpenXLSX/sources/XLSharedStrings.cpp b/OpenXLSX/sources/XLSharedStrings.cpp index 583f4e20..294ccab1 100644 --- a/OpenXLSX/sources/XLSharedStrings.cpp +++ b/OpenXLSX/sources/XLSharedStrings.cpp @@ -124,7 +124,8 @@ const char* XLSharedStrings::getString(uint32_t index) const uint32_t XLSharedStrings::appendString(const std::string& str) { auto textNode = xmlDocument().document_element().append_child("si").append_child("t"); - if (str.front() == ' ' || str.back() == ' ') textNode.append_attribute("xml:space").set_value("preserve"); + if ((!str.empty()) && (str.front() == ' ' || str.back() == ' ')) + textNode.append_attribute("xml:space").set_value("preserve"); textNode.text().set(str.c_str()); From c677a0ab8fbb4ffd53c7c4074c9d9144143535cd Mon Sep 17 00:00:00 2001 From: akira215 Date: Sat, 28 Jan 2023 13:31:14 -0500 Subject: [PATCH 43/45] Working on style --- Examples/CMakeLists.txt | 6 + Examples/Demo11.cpp | 117 +++++++ OpenXLSX/CMakeLists.txt | 1 + OpenXLSX/OpenXLSX.hpp | 1 + OpenXLSX/headers/XLCell.hpp | 15 + OpenXLSX/headers/XLContentTypes.hpp | 84 ++--- OpenXLSX/headers/XLDocument.hpp | 9 + OpenXLSX/headers/XLStyles.hpp | 177 +++++++++++ OpenXLSX/sources/XLCell.cpp | 20 ++ OpenXLSX/sources/XLDocument.cpp | 29 +- OpenXLSX/sources/XLStyles.cpp | 471 ++++++++++++++++++++++++++++ 11 files changed, 878 insertions(+), 52 deletions(-) create mode 100644 Examples/Demo11.cpp create mode 100644 OpenXLSX/headers/XLStyles.hpp create mode 100644 OpenXLSX/sources/XLStyles.cpp diff --git a/Examples/CMakeLists.txt b/Examples/CMakeLists.txt index cb56fe01..4b93a2b2 100644 --- a/Examples/CMakeLists.txt +++ b/Examples/CMakeLists.txt @@ -78,3 +78,9 @@ target_link_libraries(Demo09 PRIVATE OpenXLSX::OpenXLSX) #======================================================================================================================= add_executable(Demo10 Demo10.cpp) target_link_libraries(Demo10 PRIVATE OpenXLSX::OpenXLSX) + +#======================================================================================================================= +# Define Demo11 target +#======================================================================================================================= +add_executable(Demo11 Demo11.cpp) +target_link_libraries(Demo11 PRIVATE OpenXLSX::OpenXLSX) \ No newline at end of file diff --git a/Examples/Demo11.cpp b/Examples/Demo11.cpp new file mode 100644 index 00000000..d7ddcc07 --- /dev/null +++ b/Examples/Demo11.cpp @@ -0,0 +1,117 @@ +#include +#include +#include + +#ifdef WIN32 +#include +#include +#endif + +using namespace std; +using namespace OpenXLSX; + +void printType(XLNumberFormat fmt) +{ +#ifdef WIN32 + SetConsoleOutputCP(CP_UTF8); +#endif + + switch (fmt.type()) { + case XLNumberFormat::XLNumberType::kCurrency: + cout << "\nkCurrency " + fmt.currencySymbol(); + break; + case XLNumberFormat::XLNumberType::kDate: + cout << "\nkDate "; + break; + case XLNumberFormat::XLNumberType::kPercent: + cout << "\nkPercent "; + break; + case XLNumberFormat::XLNumberType::kUnkown: + cout << "\nkUnkown "; + break; + } +} + + +void testNumbers(const XLWorksheet& wks) +{ + // check if the value is a number before using XLNumberFormat + + cout << "\n"; + auto doNumFmt = [&](const XLCell& cell) { + const auto& val = cell.value(); + if (XLValueType::Integer == val.type() || XLValueType::Float == val.type()) { + const auto fmt = cell.style().numberFormat(); + printType(fmt); + cout << " Format string = " << cell.style().formatString(); + } + else + cout << "\nNot a number"; + }; + + doNumFmt(wks.cell("A1")); + doNumFmt(wks.cell("A2")); + doNumFmt(wks.cell("A3")); + doNumFmt(wks.cell("A4")); + doNumFmt(wks.cell("A5")); + doNumFmt(wks.cell("A6")); + doNumFmt(wks.cell("A7")); + doNumFmt(wks.cell("A8")); + doNumFmt(wks.cell("A9")); + cout << "\n"; +} + +void testFonts(const XLWorksheet& wks) +{ + cout << "\n"; + auto doFonstTest = [&](const XLCell& cell) { + const auto& val = cell.value(); + const auto& style = cell.style(); + const auto& font = style.font(); + cout << "value= " << val.get() << ", name= " << font.name() << ", size= " << font.size() + << ", color= " << font.color().hex() << ", isBold " << font.bold() << ", isUnderline " << (font.underline() == 2) + << ", double underline " << (font.underline() == -4119) << ", isStrike " << font.strikethrough() << ", isItalic " + << font.italic() << '\n'; + }; + + doFonstTest(wks.cell("A1")); + doFonstTest(wks.cell("A2")); + doFonstTest(wks.cell("A3")); + doFonstTest(wks.cell("A4")); + doFonstTest(wks.cell("A5")); + doFonstTest(wks.cell("A6")); + cout << "\n"; +} + +int main() +{ + cout << "********************************************************************************\n"; + cout << "DEMO PROGRAM #11: Basic Usage\n"; + cout << "********************************************************************************\n"; +/* + auto& current_path = std::filesystem::current_path(); + auto& parent_path = current_path.parent_path(); + std::filesystem::path foundPath; + + while (parent_path.string().size() > 3) { + if (parent_path.filename().string().compare("OpenXLSX") == 0) foundPath = parent_path; + parent_path = parent_path.parent_path(); + } + foundPath += "\\Tests\\NumberType.xlsx"; + if (!std::filesystem::exists(foundPath)) { + cout << "File not found"; + return 0; + } + */ + std::string testFile = ".\\Tests\\NumberType.xlsx"; + + XLDocument doc; + doc.open(testFile); + + testNumbers(doc.workbook().worksheet("Sheet1")); + testFonts(doc.workbook().worksheet("Sheet2")); + + doc.close(); + + return 0; +} \ No newline at end of file diff --git a/OpenXLSX/CMakeLists.txt b/OpenXLSX/CMakeLists.txt index a159fcdd..6d0a8530 100644 --- a/OpenXLSX/CMakeLists.txt +++ b/OpenXLSX/CMakeLists.txt @@ -101,6 +101,7 @@ set(OPENXLSX_SOURCES ${CMAKE_CURRENT_LIST_DIR}/sources/XLRowData.cpp ${CMAKE_CURRENT_LIST_DIR}/sources/XLSharedStrings.cpp ${CMAKE_CURRENT_LIST_DIR}/sources/XLSheet.cpp + ${CMAKE_CURRENT_LIST_DIR}/sources/XLStyles.cpp ${CMAKE_CURRENT_LIST_DIR}/sources/XLTable.cpp ${CMAKE_CURRENT_LIST_DIR}/sources/XLTableColumn.cpp ${CMAKE_CURRENT_LIST_DIR}/sources/XLTableRows.cpp diff --git a/OpenXLSX/OpenXLSX.hpp b/OpenXLSX/OpenXLSX.hpp index 91b15136..e46d8a01 100644 --- a/OpenXLSX/OpenXLSX.hpp +++ b/OpenXLSX/OpenXLSX.hpp @@ -58,6 +58,7 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. #include "headers/XLNamedRange.hpp" #include "headers/XLRow.hpp" #include "headers/XLSheet.hpp" +#include "headers/XLStyles.hpp" #include "headers/XLTable.hpp" #include "headers/XLTableRows.hpp" #include "headers/XLTableStyle.hpp" diff --git a/OpenXLSX/headers/XLCell.hpp b/OpenXLSX/headers/XLCell.hpp index a6d4ef18..ffc996a5 100644 --- a/OpenXLSX/headers/XLCell.hpp +++ b/OpenXLSX/headers/XLCell.hpp @@ -65,6 +65,8 @@ namespace OpenXLSX { class XLCellRange; class XLWorksheet; + class XLStyles; + class XLStyle; /** * @brief An implementation class encapsulating the properties and behaviours of a spreadsheet cell. @@ -74,6 +76,7 @@ namespace OpenXLSX friend class XLCellIterator; friend class XLCellValueProxy; friend class XLRowDataIterator; + friend class XLStyles; friend bool operator==(const XLCell& lhs, const XLCell& rhs); friend bool operator!=(const XLCell& lhs, const XLCell& rhs); @@ -182,6 +185,18 @@ namespace OpenXLSX * @param newFormula */ + /** + * @brief + * @param + */ + const XLStyles& styles() const; + + /** + * @brief + * @param + */ + const XLStyle style() const; + private: /** diff --git a/OpenXLSX/headers/XLContentTypes.hpp b/OpenXLSX/headers/XLContentTypes.hpp index a8594cc7..619cbc8d 100644 --- a/OpenXLSX/headers/XLContentTypes.hpp +++ b/OpenXLSX/headers/XLContentTypes.hpp @@ -15,33 +15,33 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. MM _MM_ - Copyright (c) 2018, Kenneth Troldal Balslev - - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - Neither the name of the author nor the - names of any contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - */ + Copyright (c) 2018, Kenneth Troldal Balslev + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + - Neither the name of the author nor the + names of any contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ #ifndef OPENXLSX_XLCONTENTTYPES_HPP #define OPENXLSX_XLCONTENTTYPES_HPP @@ -67,29 +67,29 @@ namespace OpenXLSX * @brief */ enum class XLContentType { - Workbook, - WorkbookMacroEnabled, - Worksheet, - WorksheetRelations, - Chartsheet, - ExternalLink, - Theme, - Styles, - SharedStrings, - Drawing, + CalculationChain, Chart, + Chartsheet, ChartStyle, ChartColorStyle, + Comments, ControlProperties, - CalculationChain, - VBAProject, CoreProperties, - ExtendedProperties, CustomProperties, - Comments, + Drawing, + ExtendedProperties, + ExternalLink, + SharedStrings, + Styles, Table, + Theme, + Unknown, + VBAProject, VMLDrawing, - Unknown + Workbook, + WorkbookMacroEnabled, + Worksheet, + WorksheetRelations }; /** diff --git a/OpenXLSX/headers/XLDocument.hpp b/OpenXLSX/headers/XLDocument.hpp index c7d18eef..c1a683ba 100644 --- a/OpenXLSX/headers/XLDocument.hpp +++ b/OpenXLSX/headers/XLDocument.hpp @@ -66,6 +66,7 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. #include "XLProperties.hpp" #include "XLRelationships.hpp" #include "XLSharedStrings.hpp" +#include "XLStyles.hpp" #include "XLWorkbook.hpp" #include "XLXmlData.hpp" #include "XLZipArchive.hpp" @@ -111,6 +112,7 @@ namespace OpenXLSX friend class XLXmlFile; friend class XLWorkbook; friend class XLSheet; + friend class XLStyles; friend class XLXmlData; //---------- Public Member Functions @@ -258,6 +260,12 @@ namespace OpenXLSX */ XLQuery execQuery(const XLQuery& query); + /** + * @brief + * @return + */ + const XLStyles& styles() const; + //---------------------------------------------------------------------------------------------------------------------- // Protected Member Functions @@ -355,6 +363,7 @@ namespace OpenXLSX XLXmlData* m_XmlWorkbook {}; XLWorkbook m_workbook {}; /**< A pointer to the workbook object */ IZipArchive m_archive {}; /**< */ + XLStyles m_styles {}; /**< Styles object >*/ }; } // namespace OpenXLSX diff --git a/OpenXLSX/headers/XLStyles.hpp b/OpenXLSX/headers/XLStyles.hpp new file mode 100644 index 00000000..7824116e --- /dev/null +++ b/OpenXLSX/headers/XLStyles.hpp @@ -0,0 +1,177 @@ +/* + ____ ____ ___ ____ ____ ____ ___ + 6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M' + 8P Y8 `MM. d' MM 6M' ` `MM. d' +6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d' +MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d' +MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd +MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM. +MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM. +YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. + 8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM. + YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_ + MM + MM + _MM_ + Copyright (c) 2018, Kenneth Troldal Balslev + All rights reserved. + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + - Neither the name of the author nor the + names of any contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef OPENXLSX_XLSYLES_HPP +#define OPENXLSX_XLSYLES_HPP + +#pragma warning(push) +#pragma warning(disable : 4251) +#pragma warning(disable : 4275) + +#include +#include + +// ===== OpenXLSX Includes ===== // +#include "OpenXLSX-Exports.hpp" +#include "XLXmlFile.hpp" +#include "XLColor.hpp" +#include "XLXmlParser.hpp" + + +namespace OpenXLSX +{ + class XLStyle; + class XLNumberFormat; + class XLFont; + class XLCell; + + // ================================================================================ + // XLStyles Class + // ================================================================================ + class OPENXLSX_EXPORT XLStyles : public XLXmlFile + { + friend class XLCell; + friend class XLFont; + friend class XLStyle; + friend XLDocument; + + public: + XLStyles() = default; + ~XLStyles(); + XLStyles(XLXmlData* xmlData); + XLStyle style(const XLCell& cell) const; + std::string formatString(int numFmtId) const; + + private: + void init(const XLXmlData* stylesData); + + private: + std::vector m_VecStyle; + }; + + // ================================================================================ + // XLStyle Class + // ================================================================================ + class OPENXLSX_EXPORT XLStyle + { + friend class XLCell; + friend class XLFont; + friend class XLStyles; + + private: + explicit XLStyle(const XLDocument& doc); + + public: + ~XLStyle() = default; + + XLNumberFormat numberFormat() const; + std::string formatString() const; + int numFmtId() const; + XLFont font() const; + + //alignment is in cellXfs, revise to cache the node to lookup + //applyXXX attributes, alignment and stuff we missed. + //lazy cache may be best + + private: + int m_numFmtId = -1; + int m_fontId = -1; + int m_fillId = -1; + int m_borderId = -1; + int m_xfId = -1; + std::reference_wrapper m_doc; + }; + + // ================================================================================ + // Font Class + // ================================================================================ + class OPENXLSX_EXPORT XLFont + { + friend class XLStyle; + + private: + XLFont(const XLStyle& style, const XMLNode& node); + + public: + ~XLFont(); + XLFont(XLFont const&) = delete; + XLFont& operator=(XLFont const&) = delete; + std::string name() const; + double size() const; + XLColor color() const; + int colorIndex() const; + int underline()const; + bool strikethrough() const; + bool bold() const; + bool italic() const; + bool isValid() const; + + private: + std::reference_wrapper m_style; + std::unique_ptr m_node; + }; + + // ================================================================================ + // XLNumberFormat Class + // ================================================================================ + class OPENXLSX_EXPORT XLNumberFormat + { + public: + enum class XLNumberType { kUnkown, kDate, kPercent, kCurrency }; + + public: + explicit XLNumberFormat(const XLStyle& style); + ~XLNumberFormat() = default; + + XLNumberType type(); + std::string currencySymbol() const; + + private: + XLNumberType tryFindType(); + XLNumberType tryBuiltinType(); + + private: + std::reference_wrapper m_style; + std::string m_currencySymbol; + std::string m_fmtLocal; //TODO: get precision etc. + }; +}// namespace OpenXLSX + +#pragma warning(pop) +#endif // OPENXLSX_XLSYLES_HPP \ No newline at end of file diff --git a/OpenXLSX/sources/XLCell.cpp b/OpenXLSX/sources/XLCell.cpp index ffdaf16f..01b2073d 100644 --- a/OpenXLSX/sources/XLCell.cpp +++ b/OpenXLSX/sources/XLCell.cpp @@ -50,6 +50,7 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. #include "XLCell.hpp" #include "XLSheet.hpp" #include "XLCellRange.hpp" +#include "XLStyles.hpp" #include "utilities/XLUtilities.hpp" using namespace OpenXLSX; @@ -216,3 +217,22 @@ bool XLCell::isEqual(const XLCell& lhs, const XLCell& rhs) { return *lhs.m_cellNode == *rhs.m_cellNode; } + +/** + * @details + * @pre + * @post + */ +const OpenXLSX::XLStyles& OpenXLSX::XLCell::styles() const{ + return m_worksheet->parentDoc().styles(); +} + +/** + * @details + * @pre + * @post + */ +const XLStyle XLCell::style() const{ + const OpenXLSX::XLStyles& _styles = styles(); + return _styles.style(*this); +} diff --git a/OpenXLSX/sources/XLDocument.cpp b/OpenXLSX/sources/XLDocument.cpp index ba9b4db5..ce6fc600 100644 --- a/OpenXLSX/sources/XLDocument.cpp +++ b/OpenXLSX/sources/XLDocument.cpp @@ -168,14 +168,16 @@ void XLDocument::open(const std::string& fileName) if (targetPath.substr(0,2) == "..") targetPath = "xl" + targetPath.substr(2); - XLXmlData* pDocChild = getXmlDataByPath(targetPath); // Pointer to table elmnt - - pDocChild->setName(pDocChild->getXmlDocument()->child("table") - .attribute("name").value()); - wsItem.addChildNode(pDocChild); - pDocChild->setParentNode(&wsItem); - pDocChild->setXmlID(sheetRels.relationshipByTarget(childItem.target()).id()); - //auto type = childItem.type(); + if (childItem.type() == XLRelationshipType::Table){ + XLXmlData* pDocChild = getXmlDataByPath(targetPath); // Pointer to table elmnt + + pDocChild->setName(pDocChild->getXmlDocument()->child("table") + .attribute("name").value()); + wsItem.addChildNode(pDocChild); + pDocChild->setParentNode(&wsItem); + pDocChild->setXmlID(sheetRels.relationshipByTarget(childItem.target()).id()); + } // childItem.type() could also be XLRelationshipType::PrinterSettings + } } @@ -188,6 +190,7 @@ void XLDocument::open(const std::string& fileName) m_coreProperties = (hasXmlData("docProps/core.xml") ? XLProperties(getXmlDataByPath("docProps/core.xml")) : XLProperties()); m_appProperties = (hasXmlData("docProps/app.xml") ? XLAppProperties(getXmlDataByPath("docProps/app.xml")) : XLAppProperties()); m_sharedStrings = XLSharedStrings(getXmlDataByPath("xl/sharedStrings.xml")); + m_styles = XLStyles(getXmlDataByPath("xl/styles.xml")); } @@ -726,12 +729,18 @@ bool XLDocument::isOpen() const { return this->operator bool(); } +const OpenXLSX::XLStyles& OpenXLSX::XLDocument::styles() const +{ + return m_styles; +} + + /** * @details */ XLXmlData* XLDocument::getXmlDataByPath(const std::string& path) { - if (!hasXmlData(path)) throw XLInternalError("Path does not exist in zip archive."); + if (!hasXmlData(path)) throw XLInternalError("Path \"" + path + "\" does not exist in zip archive."); return &*std::find_if(m_data.begin(), m_data.end(), [&](const XLXmlData& item) { return item.getXmlPath() == path; }); // auto result = std::find_if(m_data.begin(), m_data.end(), [&](const XLXmlData& item) { return item.getXmlPath() == path; }); // if (result == m_data.end()) throw XLInternalError("Path does not exist in zip archive."); @@ -743,7 +752,7 @@ XLXmlData* XLDocument::getXmlDataByPath(const std::string& path) */ const XLXmlData* XLDocument::getXmlDataByPath(const std::string& path) const { - if (!hasXmlData(path)) throw XLInternalError("Path does not exist in zip archive."); + if (!hasXmlData(path)) throw XLInternalError("Path \"" + path + "\" does not exist in zip archive."); return &*std::find_if(m_data.begin(), m_data.end(), [&](const XLXmlData& item) { return item.getXmlPath() == path; }); // if (result == m_data.end()) throw XLInternalError("Path does not exist in zip archive."); // return &*result; diff --git a/OpenXLSX/sources/XLStyles.cpp b/OpenXLSX/sources/XLStyles.cpp new file mode 100644 index 00000000..e8849922 --- /dev/null +++ b/OpenXLSX/sources/XLStyles.cpp @@ -0,0 +1,471 @@ +/* + ____ ____ ___ ____ ____ ____ ___ + 6MMMMb `MM( )M' `MM' 6MMMMb\`MM( )M' + 8P Y8 `MM. d' MM 6M' ` `MM. d' +6M Mb __ ____ ____ ___ __ `MM. d' MM MM `MM. d' +MM MM `M6MMMMb 6MMMMb `MM 6MMb `MM. d' MM YM. `MM. d' +MM MM MM' `Mb 6M' `Mb MMM9 `Mb `MMd MM YMMMMb `MMd +MM MM MM MM MM MM MM' MM dMM. MM `Mb dMM. +MM MM MM MM MMMMMMMM MM MM d'`MM. MM MM d'`MM. +YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. + 8b d8 MM. ,M9 YM d9 MM MM d' `MM. MM / L ,M9 d' `MM. + YMMMM9 MMYMMM9 YMMMM9 _MM_ _MM_M(_ _)MM_ _MMMMMMM MYMMMM9 _M(_ _)MM_ + MM + MM + _MM_ + Copyright (c) 2018, Kenneth Troldal Balslev + All rights reserved. + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + - Neither the name of the author nor the + names of any contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// ===== External Includes ===== // +#include +#include +#include +#include +#include + + +// ===== OpenXLSX Includes ===== // +#include "XLCell.hpp" +#include "XLDocument.hpp" +#include "XLStyles.hpp" +#include "XLXmlData.hpp" + +using namespace OpenXLSX; + +// ================================================================================ +// Helpers +// ================================================================================ +template +inline void splitA(const std::string& s, char delim, Out result) +{ + std::istringstream iss(s); + std::string item; + while (std::getline(iss, item, delim)) { + *result++ = item; + } +} + +inline void splitA(const std::string& s, char delim, std::vector& elems) +{ + splitA(s, delim, std::back_inserter(elems)); +} + +static pugi::xml_node findFontNode(const XMLDocument& xmlDoc, int fontId) +{ + //xmlDoc.find_child() ? how to use + pugi::xml_node node; + constexpr std::string_view nodeFontsName { "fonts" }; + constexpr std::string_view nodeFontName { "font" }; + for (const auto& nodeItem : xmlDoc.document_element().children()) { + if (nodeFontsName == nodeItem.name()) { + for (auto& xfNode : nodeItem.children()) { + if (nodeFontName == xfNode.name()) { + if (fontId == 0) { + return xfNode; + } + else { + int idx = 0; + while (idx < fontId) { + xfNode = xfNode.next_sibling(); + idx++; + } + return xfNode; + } + } + } + } + } + return node; +} + +// ================================================================================ +// XLStyles Class +// ================================================================================ + +XLStyles::XLStyles(XLXmlData* xmlData) : XLXmlFile(xmlData) +{ + init(xmlData); +} + +XLStyles::~XLStyles() = default; + +XLStyle XLStyles::style(const XLCell& cell) const +{ + XLStyle res(this->parentDoc()); + if (!cell) return res; + if (const auto* val = cell.m_cellNode->attribute("s").value(); val != nullptr) { + if (const size_t pos = std::atoi(val); m_VecStyle.size() > pos) { + res = m_VecStyle.at(pos); + } + } + return res; +} + +std::string XLStyles::formatString(int numFmtId) const +{ + constexpr const auto* snumFmts = "numFmts"; + constexpr const auto* snumFmtId = "numFmtId"; + constexpr const auto* sformatCode = "formatCode"; + + return xmlDocument() + .document_element() + .child(snumFmts) + .find_child_by_attribute(snumFmtId, std::to_string(numFmtId).c_str()) + .attribute(sformatCode) + .value(); +} + +void XLStyles::init(const XLXmlData* stylesData) +{ + // cache cellXfs + if (stylesData) { + constexpr const auto* numFmtId = "numFmtId"; + constexpr const auto* fontId = "fontId"; + constexpr const auto* fillId = "fillId"; + constexpr const auto* borderId = "borderId"; + constexpr const auto* xfId = "xfId"; + + constexpr std::string_view nodeNameCellXfs { "cellXfs" }; + constexpr std::string_view nodeNameXf { "xf" }; + + // TODO: check applyNumberFormat, reserve size from cellXfs count; + for (const auto& node : stylesData->getXmlDocument()->document_element().children()) { + if (nodeNameCellXfs == node.name()) { + for (const auto& xfNode : node.children()) { + if (nodeNameXf == xfNode.name()) { + XLStyle item(this->parentDoc()); + if (const auto* val = xfNode.attribute(numFmtId).value(); val != nullptr) item.m_numFmtId = std::stoi(val); + if (const auto* val = xfNode.attribute(fontId).value(); val != nullptr) item.m_fontId = std::stoi(val); + if (const auto* val = xfNode.attribute(fillId).value(); val != nullptr) item.m_fillId = std::stoi(val); + if (const auto* val = xfNode.attribute(borderId).value(); val != nullptr) item.m_borderId = std::stoi(val); + if (const auto* val = xfNode.attribute(xfId).value(); val != nullptr) item.m_xfId = std::stoi(val); + m_VecStyle.emplace_back(item); + } + } + break; + } + // TODO: Fonts + } + } +} + +// ================================================================================ +// XLStyle Class +// ================================================================================ + +XLStyle::XLStyle(const XLDocument& doc) : m_doc(doc) {} + +XLNumberFormat XLStyle::numberFormat() const +{ + XLNumberFormat fmt(*this); + return fmt; +} + +std::string XLStyle::formatString() const +{ + return m_doc.get().styles().formatString(m_numFmtId); +} + +int XLStyle::numFmtId() const +{ + return m_numFmtId; +} + +XLFont XLStyle::font() const +{ + return XLFont(*this, findFontNode(m_doc.get().styles().xmlDocument(), m_fontId)); +} + +// ================================================================================ +// XLFont Class +// ================================================================================ +// XLQuery? +XLFont::XLFont(const XLStyle& style, const XMLNode& node) : + m_style(style), m_node(new XMLNode(node)) {} + +XLFont::~XLFont() {} + +std::string XLFont::name() const +{ + std::string _name; + if (isValid()) { + _name = m_node->child("name").attribute("val").value(); + } + return _name; +} + +double XLFont::size() const +{ + double result = 0.0; + if (isValid()) { + result = std::stod(m_node->child("sz").attribute("val").value()); + } + return result; +} + +XLColor XLFont::color() const +{ + XLColor clr; + if (isValid()) { + const std::string val = m_node->child("color").attribute("rgb").value(); + if (val.size() != 0) { + clr.set(val); + } + } + return clr; +} + +int XLFont::colorIndex() const +{ + constexpr int xlColorIndexNone = -4142; + if (isValid()) { + const std::string val = m_node->child("color").attribute("theme").value(); + if (val.size() != 0) { + return std::atoi(val.c_str()); + } + } + return xlColorIndexNone; +} + + +int XLFont::underline() const { + //https://docs.microsoft.com/en-us/office/vba/api/excel.xlunderlinestyle + if (isValid()) { + constexpr std::string_view nodeName { "u" }; + constexpr std::string_view attDouble { "double" }; + for (const auto& node : m_node->children()) { + + if (nodeName == node.name()) { + if (auto attribute = node.attribute("val"); !attribute.empty() && attribute.value() == attDouble) { + return -4119; + } + else { + return 2; + } + + } + + } + } + return -4142; +} + +bool XLFont::strikethrough() const { + if (isValid()) { + constexpr std::string_view nodeName { "strike" }; + for (const auto& node : m_node->children()) { + if (nodeName == node.name()) { + return true; + } + } + } + return false; +} + + +bool XLFont::bold() const { + if (isValid()) { + constexpr std::string_view nodeName { "b" }; + for (const auto& node : m_node->children()) { + if (nodeName == node.name()) { + return true; + } + } + } + return false; +} + + +bool XLFont::italic() const{ + if (isValid()) { + constexpr std::string_view nodeName { "i" }; + for (const auto& node : m_node->children()) { + if (nodeName == node.name()) { + return true; + } + } + } + return false; +} + +bool XLFont::isValid() const +{ + constexpr std::string_view nodeFontName { "font" }; + if (m_style.get().m_fontId != -1 && m_node != nullptr && m_node->type() != pugi::xml_node_type::node_null && m_node->name() == nodeFontName){ + return true; + } + return false; +} + +// ================================================================================ +// XLNumberFormat Class +// ================================================================================ +XLNumberFormat::XLNumberFormat(const XLStyle& style) : m_style { style } {} + +XLNumberFormat::XLNumberType XLNumberFormat::type() +{ + return tryFindType(); +} + +std::string XLNumberFormat::currencySymbol() const +{ + return m_currencySymbol; +} + +// TODO: it may be possible to get precision and forrmatting in a single pass. +XLNumberFormat::XLNumberType XLNumberFormat::tryFindType() +{ + const auto _type = tryBuiltinType(); + if (_type != XLNumberType::kUnkown) return _type; + + const std::string fmt = m_style.get().formatString(); + if (fmt.size() == 0) return XLNumberType::kUnkown; + + std::vector bracketTextArray; + std::lconv* lc = std::localeconv(); + std::string bracketText; + bool isInBracket = false; + + auto foundType = XLNumberType::kUnkown; + + if (fmt.find("AM/PM") != std::string::npos) return XLNumberType::kDate; + + for (size_t idx = 0; idx < fmt.size(); idx++) { + if (fmt[idx] == '[') { + isInBracket = true; + } + else if (fmt[idx] == ']') { + isInBracket = false; + bracketTextArray.push_back(bracketText); + bracketText.clear(); + } + else if (isInBracket) { + bracketText += fmt[idx]; + } + else { + const char chr = fmt[idx]; + if (chr == '$') { + m_currencySymbol = chr; + return XLNumberType::kCurrency; + } + else if (std::string lc_curr = lc->currency_symbol; lc_curr.find(chr) != std::string::npos) { + m_currencySymbol = lc->currency_symbol; + return XLNumberType::kCurrency; + } + else if (chr == '%') { + return XLNumberType::kPercent; + } + else if (chr == 'y' || chr == 'M' || chr == 'm' || chr == 'd') { + return XLNumberType::kDate; + } + else if (chr == 'h' || chr == 's' || chr == ':') { + return XLNumberType::kDate; + } + else if (chr == '0' || chr == '#' || chr == '.') { + foundType = XLNumberType::kUnkown; + } + // use lc->int_curr_symbol ? how to get en_US? + //(iCompare(m_slocale, L"ja_jp") || iCompare(m_slocale, L"zh_tw")) && wchr == 'e' || wchr == 'g' || wchr == 'r') + } + } + for (const auto& item : bracketTextArray) { + if (item.find("F800") != std::string::npos) { + return XLNumberType::kDate; + } + else if (item.find("F400") != std::string::npos) { + return XLNumberType::kDate; + } + else { + if (size_t pos = item.find('-'); pos != std::wstring::npos) { + std::vector parts; + splitA(item, '-', parts); + if (parts.size() == 2) { + if (parts[0].size() > 1) { + m_currencySymbol = parts[0].substr(1, parts[0].size() - 1); + m_fmtLocal = parts[1]; + return XLNumberType::kCurrency; + } + } + } + else { + if (item[0] == '$') { + m_currencySymbol = item.substr(1, item.size() - 1); + return XLNumberType::kCurrency; + } + } + } + } + return foundType; +} + +XLNumberFormat::XLNumberType XLNumberFormat::tryBuiltinType() +{ + std::setlocale(LC_MONETARY, ""); + std::lconv* lc = std::localeconv(); + auto n = m_style.get().numFmtId(); + switch (m_style.get().numFmtId()) { + case 0: + case 1: + case 3: + return XLNumberType::kUnkown; + case 2: + case 4: + return XLNumberType::kUnkown; + case 5: + case 6: + case 7: + case 8: + m_currencySymbol = lc->currency_symbol; + return XLNumberType::kCurrency; + case 9: + case 10: + return XLNumberType::kPercent; + case 11: + case 12: + case 13: + return XLNumberType::kUnkown; + case 14: + case 15: + case 16: + case 17: + case 18: + case 19: + case 20: + case 21: + case 22: + return XLNumberType::kDate; + case 37: + case 38: + case 39: + case 40: // accounting + return XLNumberType::kUnkown; + case 45: + case 46: + case 47: + case 48: + return XLNumberType::kDate; + } + return XLNumberType::kUnkown; +} \ No newline at end of file From f6ea8aa24be4fc2bcb86055960174417d4322da9 Mon Sep 17 00:00:00 2001 From: akira215 Date: Sat, 28 Jan 2023 13:42:12 -0500 Subject: [PATCH 44/45] Fix Error in XLDateTime on 30th --- OpenXLSX/sources/XLDateTime.cpp | 2 +- OpenXLSX/sources/XLStyles.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenXLSX/sources/XLDateTime.cpp b/OpenXLSX/sources/XLDateTime.cpp index 86e2df13..3680af4d 100644 --- a/OpenXLSX/sources/XLDateTime.cpp +++ b/OpenXLSX/sources/XLDateTime.cpp @@ -211,7 +211,7 @@ namespace OpenXLSX // ===== Count the number of whole years since 1900. while (true) { auto days = (isLeapYear(result.tm_year + 1900) ? 366 : 365); - if (days > serial) break; + if (days >= static_cast(serial)) break; serial -= days; ++result.tm_year; } diff --git a/OpenXLSX/sources/XLStyles.cpp b/OpenXLSX/sources/XLStyles.cpp index e8849922..87aa4912 100644 --- a/OpenXLSX/sources/XLStyles.cpp +++ b/OpenXLSX/sources/XLStyles.cpp @@ -424,7 +424,7 @@ XLNumberFormat::XLNumberType XLNumberFormat::tryBuiltinType() { std::setlocale(LC_MONETARY, ""); std::lconv* lc = std::localeconv(); - auto n = m_style.get().numFmtId(); + auto n = m_style.get().numFmtId(); // TO DEL switch (m_style.get().numFmtId()) { case 0: case 1: From c12e694bffc2e690a86adbcac7950a25dbb93e90 Mon Sep 17 00:00:00 2001 From: akira215 Date: Thu, 24 Oct 2024 15:23:30 +0200 Subject: [PATCH 45/45] adding include stdint.h --- OpenXLSX/headers/XLCellReference.hpp | 1 + OpenXLSX/headers/XLColor.hpp | 1 + OpenXLSX/sources/XLDateTime.cpp | 6 ++++-- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/OpenXLSX/headers/XLCellReference.hpp b/OpenXLSX/headers/XLCellReference.hpp index 1cc2b937..c7fa073c 100644 --- a/OpenXLSX/headers/XLCellReference.hpp +++ b/OpenXLSX/headers/XLCellReference.hpp @@ -51,6 +51,7 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. #pragma warning(disable : 4275) // ===== External Includes ===== // +#include #include #include diff --git a/OpenXLSX/headers/XLColor.hpp b/OpenXLSX/headers/XLColor.hpp index 3c584381..766e3639 100644 --- a/OpenXLSX/headers/XLColor.hpp +++ b/OpenXLSX/headers/XLColor.hpp @@ -51,6 +51,7 @@ YM M9 MM MM MM MM MM d' `MM. MM MM d' `MM. #pragma warning(disable : 4275) // ===== External Includes ===== // +#include #include // ===== OpenXLSX Includes ===== // diff --git a/OpenXLSX/sources/XLDateTime.cpp b/OpenXLSX/sources/XLDateTime.cpp index 3680af4d..e5de265c 100644 --- a/OpenXLSX/sources/XLDateTime.cpp +++ b/OpenXLSX/sources/XLDateTime.cpp @@ -1,11 +1,13 @@ // // Created by Kenneth Balslev on 28/08/2021. // +#include +#include +#include #include "XLDateTime.hpp" #include "XLException.hpp" -#include -#include + namespace {