diff --git a/include/xlnt/workbook/workbook.hpp b/include/xlnt/workbook/workbook.hpp index 4d6f5405..eab4ade7 100644 --- a/include/xlnt/workbook/workbook.hpp +++ b/include/xlnt/workbook/workbook.hpp @@ -758,6 +758,11 @@ private: /// void register_comments_in_manifest(worksheet ws); + /// + /// Removes calcChain part from manifest if no formulae remain in workbook. + /// + void garbage_collect_formulae(); + /// /// An opaque pointer to a structure that holds all of the data relating to this workbook. /// diff --git a/include/xlnt/worksheet/worksheet.hpp b/include/xlnt/worksheet/worksheet.hpp index 13205352..16fc9dc5 100644 --- a/include/xlnt/worksheet/worksheet.hpp +++ b/include/xlnt/worksheet/worksheet.hpp @@ -742,6 +742,11 @@ private: /// void register_comments_in_manifest(); + /// + /// Removes calcChain part from manifest if no formulae remain in workbook. + /// + void garbage_collect_formulae(); + /// /// /// diff --git a/source/cell/cell.cpp b/source/cell/cell.cpp index f1beb65b..7a60e095 100644 --- a/source/cell/cell.cpp +++ b/source/cell/cell.cpp @@ -508,6 +508,7 @@ std::string cell::formula() const void cell::clear_formula() { d_->formula_.clear(); + worksheet().garbage_collect_formulae(); } void cell::error(const std::string &error) @@ -609,8 +610,8 @@ void cell::clear_value() { d_->value_numeric_ = 0; d_->value_text_.clear(); - d_->formula_.clear(); d_->type_ = cell::type::null; + clear_formula(); } template <> diff --git a/source/detail/custom_value_traits.cpp b/source/detail/custom_value_traits.cpp index bd92dc82..928097c7 100644 --- a/source/detail/custom_value_traits.cpp +++ b/source/detail/custom_value_traits.cpp @@ -37,7 +37,7 @@ std::string to_string(relationship_type t) case relationship_type::thumbnail: return "http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail"; case relationship_type::calculation_chain: - return "http://purl.oclc.org/ooxml/officeDocument/relationships/calcChain"; + return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/calcChain"; case relationship_type::extended_properties: return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties"; case relationship_type::core_properties: diff --git a/source/workbook/tests/test_consume_xlsx.hpp b/source/workbook/tests/test_consume_xlsx.hpp index b6a4ba77..44e0dddf 100644 --- a/source/workbook/tests/test_consume_xlsx.hpp +++ b/source/workbook/tests/test_consume_xlsx.hpp @@ -112,4 +112,16 @@ public: TS_ASSERT(wb.has_custom_property("Client")); TS_ASSERT_EQUALS(wb.custom_property("Client"), "me!"); } + + void test_read_formulae() + { + xlnt::workbook wb; + wb.load("data/22_formulae.xlsx"); + auto ws = wb.active_sheet(); + TS_ASSERT_EQUALS(ws.cell("A1").value(), 6); + TS_ASSERT(ws.cell("A1").has_formula()); + TS_ASSERT_EQUALS(ws.cell("A1").formula(), "A2*A3"); + TS_ASSERT_EQUALS(ws.cell("A2").value(), 2); + TS_ASSERT_EQUALS(ws.cell("A3").value(), 3); + } }; diff --git a/source/workbook/tests/test_produce_xlsx.hpp b/source/workbook/tests/test_produce_xlsx.hpp index e42b1f29..a3bffa32 100644 --- a/source/workbook/tests/test_produce_xlsx.hpp +++ b/source/workbook/tests/test_produce_xlsx.hpp @@ -154,4 +154,15 @@ public: TS_ASSERT(workbook_matches_file(wb, xlnt::path("data/15_basic_comments.xlsx"))); } + + void test_save_after_clear_all_formulae() + { + xlnt::workbook wb; + wb.load("data/22_formulae.xlsx"); + auto ws = wb.active_sheet(); + TS_ASSERT(ws.cell("A1").has_formula()); + TS_ASSERT_EQUALS(ws.cell("A1").formula(), "A2*A3"); + ws.cell("A1").clear_formula(); + wb.save("clear_formulae.xlsx"); + } }; diff --git a/source/workbook/workbook.cpp b/source/workbook/workbook.cpp index 87b9480e..288c5882 100644 --- a/source/workbook/workbook.cpp +++ b/source/workbook/workbook.cpp @@ -1260,4 +1260,38 @@ void workbook::calculation_properties(const class calculation_properties &props) d_->calculation_properties_ = props; } +/// +/// Removes calcChain part from manifest if no formulae remain in workbook. +/// +void workbook::garbage_collect_formulae() +{ + auto any_with_formula = false; + + for (auto ws : *this) + { + for (auto row : ws.iter_cells(true)) + { + for (auto cell : row) + { + if (cell.has_formula()) + { + any_with_formula = true; + } + } + } + } + + if (any_with_formula) return; + + auto wb_rel = manifest().relationship(path("/"), relationship_type::office_document); + + if (manifest().has_relationship(wb_rel.target().path(), relationship_type::calculation_chain)) + { + auto calc_chain_rel = manifest().relationship(wb_rel.target().path(), relationship_type::calculation_chain); + auto calc_chain_part = manifest().canonicalize({wb_rel, calc_chain_rel}); + manifest().unregister_override_type(calc_chain_part); + manifest().unregister_relationship(wb_rel.target(), calc_chain_rel.id()); + } +} + } // namespace xlnt diff --git a/source/worksheet/worksheet.cpp b/source/worksheet/worksheet.cpp index 7e1438ee..9531cf18 100644 --- a/source/worksheet/worksheet.cpp +++ b/source/worksheet/worksheet.cpp @@ -1068,4 +1068,9 @@ double worksheet::row_height(row_t row) const } } +void worksheet::garbage_collect_formulae() +{ + workbook().garbage_collect_formulae(); +} + } // namespace xlnt diff --git a/tests/data/22_formulae.xlsx b/tests/data/22_formulae.xlsx new file mode 100644 index 00000000..e450aec0 Binary files /dev/null and b/tests/data/22_formulae.xlsx differ