mirror of
https://github.com/tfussell/xlnt.git
synced 2024-03-22 13:11:17 +08:00
Merge pull request #647 from tfussell/shared-array-formulas
Implement shared and array formulas
This commit is contained in:
commit
1945691bb6
|
@ -115,6 +115,11 @@ public:
|
||||||
/// </summary>
|
/// </summary>
|
||||||
std::string to_string() const;
|
std::string to_string() const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if the given cell reference is within the bounds of this range reference.
|
||||||
|
/// </summary>
|
||||||
|
bool contains(const cell_reference &ref) const;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns true if this range is equivalent to the other range.
|
/// Returns true if this range is equivalent to the other range.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -86,6 +86,7 @@
|
||||||
#include <xlnt/worksheet/range_reference.hpp>
|
#include <xlnt/worksheet/range_reference.hpp>
|
||||||
#include <xlnt/worksheet/row_properties.hpp>
|
#include <xlnt/worksheet/row_properties.hpp>
|
||||||
#include <xlnt/worksheet/selection.hpp>
|
#include <xlnt/worksheet/selection.hpp>
|
||||||
|
#include <xlnt/worksheet/sheet_format_properties.hpp>
|
||||||
#include <xlnt/worksheet/sheet_protection.hpp>
|
#include <xlnt/worksheet/sheet_protection.hpp>
|
||||||
#include <xlnt/worksheet/sheet_view.hpp>
|
#include <xlnt/worksheet/sheet_view.hpp>
|
||||||
#include <xlnt/worksheet/worksheet.hpp>
|
#include <xlnt/worksheet/worksheet.hpp>
|
||||||
|
|
|
@ -165,7 +165,7 @@ xlnt::cell_type type_from_string(const std::string &str)
|
||||||
return xlnt::cell::type::shared_string;
|
return xlnt::cell::type::shared_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
xlnt::detail::Cell parse_cell(xlnt::row_t row_arg, xml::parser *parser)
|
xlnt::detail::Cell parse_cell(xlnt::row_t row_arg, xml::parser *parser, std::unordered_map<std::string, std::string> &array_formulae, std::unordered_map<int, std::string> &shared_formulae)
|
||||||
{
|
{
|
||||||
xlnt::detail::Cell c;
|
xlnt::detail::Cell c;
|
||||||
for (auto &attr : parser->attribute_map())
|
for (auto &attr : parser->attribute_map())
|
||||||
|
@ -202,6 +202,16 @@ xlnt::detail::Cell parse_cell(xlnt::row_t row_arg, xml::parser *parser)
|
||||||
switch (e)
|
switch (e)
|
||||||
{
|
{
|
||||||
case xml::parser::start_element: {
|
case xml::parser::start_element: {
|
||||||
|
if (string_equal(parser->name(), "f") && parser->attribute_present("t"))
|
||||||
|
{
|
||||||
|
// Skip shared formulas with a ref attribute because it indicates that this
|
||||||
|
// is the master cell which will be handled in the xml::parser::characters case.
|
||||||
|
if (parser->attribute("t") == "shared" && !parser->attribute_present("ref"))
|
||||||
|
{
|
||||||
|
auto shared_index = parser->attribute<int>("si");
|
||||||
|
c.formula_string = shared_formulae[shared_index];
|
||||||
|
}
|
||||||
|
}
|
||||||
++level;
|
++level;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -223,6 +233,21 @@ xlnt::detail::Cell parse_cell(xlnt::row_t row_arg, xml::parser *parser)
|
||||||
else if (string_equal(parser->name(), "f"))
|
else if (string_equal(parser->name(), "f"))
|
||||||
{
|
{
|
||||||
c.formula_string += std::move(parser->value());
|
c.formula_string += std::move(parser->value());
|
||||||
|
|
||||||
|
if (parser->attribute_present("t"))
|
||||||
|
{
|
||||||
|
auto formula_ref = parser->attribute("ref");
|
||||||
|
auto formula_type = parser->attribute("t");
|
||||||
|
if (formula_type == "shared")
|
||||||
|
{
|
||||||
|
auto shared_index = parser->attribute<int>("si");
|
||||||
|
shared_formulae[shared_index] = c.formula_string;
|
||||||
|
}
|
||||||
|
else if (formula_type == "array")
|
||||||
|
{
|
||||||
|
array_formulae[formula_ref] = c.formula_string;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (level == 3)
|
else if (level == 3)
|
||||||
|
@ -251,7 +276,7 @@ xlnt::detail::Cell parse_cell(xlnt::row_t row_arg, xml::parser *parser)
|
||||||
}
|
}
|
||||||
|
|
||||||
// <row> inside <sheetData> element
|
// <row> inside <sheetData> element
|
||||||
std::pair<xlnt::row_properties, int> parse_row(xml::parser *parser, xlnt::detail::number_serialiser &converter, std::vector<xlnt::detail::Cell> &parsed_cells)
|
std::pair<xlnt::row_properties, int> parse_row(xml::parser *parser, xlnt::detail::number_serialiser &converter, std::vector<xlnt::detail::Cell> &parsed_cells, std::unordered_map<std::string, std::string> &array_formulae, std::unordered_map<int, std::string> &shared_formulae)
|
||||||
{
|
{
|
||||||
std::pair<xlnt::row_properties, int> props;
|
std::pair<xlnt::row_properties, int> props;
|
||||||
for (auto &attr : parser->attribute_map())
|
for (auto &attr : parser->attribute_map())
|
||||||
|
@ -301,7 +326,7 @@ std::pair<xlnt::row_properties, int> parse_row(xml::parser *parser, xlnt::detail
|
||||||
switch (e)
|
switch (e)
|
||||||
{
|
{
|
||||||
case xml::parser::start_element: {
|
case xml::parser::start_element: {
|
||||||
parsed_cells.push_back(parse_cell(static_cast<xlnt::row_t>(props.second), parser));
|
parsed_cells.push_back(parse_cell(static_cast<xlnt::row_t>(props.second), parser, array_formulae, shared_formulae));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case xml::parser::end_element: {
|
case xml::parser::end_element: {
|
||||||
|
@ -326,7 +351,7 @@ std::pair<xlnt::row_properties, int> parse_row(xml::parser *parser, xlnt::detail
|
||||||
}
|
}
|
||||||
|
|
||||||
// <sheetData> inside <worksheet> element
|
// <sheetData> inside <worksheet> element
|
||||||
Sheet_Data parse_sheet_data(xml::parser *parser, xlnt::detail::number_serialiser &converter)
|
Sheet_Data parse_sheet_data(xml::parser *parser, xlnt::detail::number_serialiser &converter, std::unordered_map<std::string, std::string> &array_formulae, std::unordered_map<int, std::string> &shared_formulae)
|
||||||
{
|
{
|
||||||
Sheet_Data sheet_data;
|
Sheet_Data sheet_data;
|
||||||
int level = 1; // nesting level
|
int level = 1; // nesting level
|
||||||
|
@ -339,7 +364,7 @@ Sheet_Data parse_sheet_data(xml::parser *parser, xlnt::detail::number_serialiser
|
||||||
switch (e)
|
switch (e)
|
||||||
{
|
{
|
||||||
case xml::parser::start_element: {
|
case xml::parser::start_element: {
|
||||||
sheet_data.parsed_rows.push_back(parse_row(parser, converter, sheet_data.parsed_cells));
|
sheet_data.parsed_rows.push_back(parse_row(parser, converter, sheet_data.parsed_cells, array_formulae, shared_formulae));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case xml::parser::end_element: {
|
case xml::parser::end_element: {
|
||||||
|
@ -430,6 +455,9 @@ std::string xlsx_consumer::read_worksheet_begin(const std::string &rel_id)
|
||||||
streaming_cell_.reset(new detail::cell_impl());
|
streaming_cell_.reset(new detail::cell_impl());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
array_formulae_.clear();
|
||||||
|
shared_formulae_.clear();
|
||||||
|
|
||||||
auto title = std::find_if(target_.d_->sheet_title_rel_id_map_.begin(),
|
auto title = std::find_if(target_.d_->sheet_title_rel_id_map_.begin(),
|
||||||
target_.d_->sheet_title_rel_id_map_.end(),
|
target_.d_->sheet_title_rel_id_map_.end(),
|
||||||
[&](const std::pair<std::string, std::string> &p) {
|
[&](const std::pair<std::string, std::string> &p) {
|
||||||
|
@ -742,7 +770,8 @@ void xlsx_consumer::read_worksheet_sheetdata()
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Sheet_Data ws_data = parse_sheet_data(parser_, converter_);
|
|
||||||
|
auto ws_data = parse_sheet_data(parser_, converter_, array_formulae_, shared_formulae_);
|
||||||
// NOTE: parse->construct are seperated here and could easily be threaded
|
// NOTE: parse->construct are seperated here and could easily be threaded
|
||||||
// with a SPSC queue for what is likely to be an easy performance win
|
// with a SPSC queue for what is likely to be an easy performance win
|
||||||
for (auto &row : ws_data.parsed_rows)
|
for (auto &row : ws_data.parsed_rows)
|
||||||
|
@ -803,6 +832,8 @@ void xlsx_consumer::read_worksheet_sheetdata()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stack_.pop_back();
|
stack_.pop_back();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
worksheet xlsx_consumer::read_worksheet_end(const std::string &rel_id)
|
worksheet xlsx_consumer::read_worksheet_end(const std::string &rel_id)
|
||||||
|
@ -1259,6 +1290,17 @@ worksheet xlsx_consumer::read_worksheet_end(const std::string &rel_id)
|
||||||
relationship_type::printer_settings)});
|
relationship_type::printer_settings)});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto array_formula : array_formulae_)
|
||||||
|
{
|
||||||
|
for (auto row : ws.range(array_formula.first))
|
||||||
|
{
|
||||||
|
for (auto cell : row)
|
||||||
|
{
|
||||||
|
cell.formula(array_formula.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ws;
|
return ws;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1356,10 +1398,7 @@ bool xlsx_consumer::has_cell()
|
||||||
|
|
||||||
auto has_value = false;
|
auto has_value = false;
|
||||||
auto value_string = std::string();
|
auto value_string = std::string();
|
||||||
|
auto formula_string = std::string();
|
||||||
auto has_formula = false;
|
|
||||||
auto has_shared_formula = false;
|
|
||||||
auto formula_value_string = std::string();
|
|
||||||
|
|
||||||
while (in_element(qn("spreadsheetml", "c")))
|
while (in_element(qn("spreadsheetml", "c")))
|
||||||
{
|
{
|
||||||
|
@ -1372,17 +1411,56 @@ bool xlsx_consumer::has_cell()
|
||||||
}
|
}
|
||||||
else if (current_element == qn("spreadsheetml", "f")) // CT_CellFormula
|
else if (current_element == qn("spreadsheetml", "f")) // CT_CellFormula
|
||||||
{
|
{
|
||||||
has_formula = true;
|
auto has_shared_formula = false;
|
||||||
|
auto has_array_formula = false;
|
||||||
|
auto is_master_cell = false;
|
||||||
|
auto shared_formula_index = 0;
|
||||||
|
auto formula_range = range_reference();
|
||||||
|
|
||||||
if (parser().attribute_present("t"))
|
if (parser().attribute_present("t"))
|
||||||
{
|
{
|
||||||
has_shared_formula = parser().attribute("t") == "shared";
|
auto formula_type = parser().attribute("t");
|
||||||
|
if (formula_type == "shared")
|
||||||
|
{
|
||||||
|
has_shared_formula = true;
|
||||||
|
shared_formula_index = parser().attribute<int>("si");
|
||||||
|
if (parser().attribute_present("ref"))
|
||||||
|
{
|
||||||
|
is_master_cell = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (formula_type == "array")
|
||||||
|
{
|
||||||
|
has_array_formula = true;
|
||||||
|
formula_range = range_reference(parser().attribute("ref"));
|
||||||
|
is_master_cell = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
skip_attributes({"aca", "ref", "dt2D", "dtr", "del1",
|
skip_attributes({"aca", "dt2D", "dtr", "del1", "del2", "r1",
|
||||||
"del2", "r1", "r2", "ca", "si", "bx"});
|
"r2", "ca", "bx"});
|
||||||
|
|
||||||
formula_value_string = read_text();
|
formula_string = read_text();
|
||||||
|
|
||||||
|
if (is_master_cell)
|
||||||
|
{
|
||||||
|
if (has_shared_formula)
|
||||||
|
{
|
||||||
|
shared_formulae_[shared_formula_index] = formula_string;
|
||||||
|
}
|
||||||
|
else if (has_array_formula)
|
||||||
|
{
|
||||||
|
array_formulae_[formula_range.to_string()] = formula_string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (has_shared_formula)
|
||||||
|
{
|
||||||
|
auto shared_formula = shared_formulae_.find(shared_formula_index);
|
||||||
|
if (shared_formula != shared_formulae_.end())
|
||||||
|
{
|
||||||
|
formula_string = shared_formula->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (current_element == qn("spreadsheetml", "is")) // CT_Rst
|
else if (current_element == qn("spreadsheetml", "is")) // CT_Rst
|
||||||
{
|
{
|
||||||
|
@ -1401,9 +1479,9 @@ bool xlsx_consumer::has_cell()
|
||||||
|
|
||||||
expect_end_element(qn("spreadsheetml", "c"));
|
expect_end_element(qn("spreadsheetml", "c"));
|
||||||
|
|
||||||
if (has_formula && !has_shared_formula)
|
if (!formula_string.empty())
|
||||||
{
|
{
|
||||||
cell.formula(formula_value_string);
|
cell.formula(formula_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_value)
|
if (has_value)
|
||||||
|
|
|
@ -45,6 +45,7 @@ class manifest;
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class optional;
|
class optional;
|
||||||
class path;
|
class path;
|
||||||
|
class range_reference;
|
||||||
class relationship;
|
class relationship;
|
||||||
class streaming_workbook_reader;
|
class streaming_workbook_reader;
|
||||||
class variant;
|
class variant;
|
||||||
|
@ -418,6 +419,9 @@ private:
|
||||||
|
|
||||||
std::unique_ptr<detail::cell_impl> streaming_cell_;
|
std::unique_ptr<detail::cell_impl> streaming_cell_;
|
||||||
|
|
||||||
|
std::unordered_map<int, std::string> shared_formulae_;
|
||||||
|
std::unordered_map<std::string, std::string> array_formulae_;
|
||||||
|
|
||||||
detail::worksheet_impl *current_worksheet_;
|
detail::worksheet_impl *current_worksheet_;
|
||||||
number_serialiser converter_;
|
number_serialiser converter_;
|
||||||
};
|
};
|
||||||
|
|
|
@ -132,12 +132,9 @@ const cell_vector range::vector(std::size_t vector_index) const
|
||||||
return cell_vector(ws_, cursor, ref_, order_, skip_null_, false);
|
return cell_vector(ws_, cursor, ref_, order_, skip_null_, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool range::contains(const cell_reference &ref)
|
bool range::contains(const cell_reference &cell_ref)
|
||||||
{
|
{
|
||||||
return ref_.top_left().column_index() <= ref.column_index()
|
return ref_.contains(cell_ref);
|
||||||
&& ref_.bottom_right().column_index() >= ref.column_index()
|
|
||||||
&& ref_.top_left().row() <= ref.row()
|
|
||||||
&& ref_.bottom_right().row() >= ref.row();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
range range::alignment(const xlnt::alignment &new_alignment)
|
range range::alignment(const xlnt::alignment &new_alignment)
|
||||||
|
|
|
@ -145,6 +145,14 @@ cell_reference range_reference::bottom_right() const
|
||||||
return bottom_right_;
|
return bottom_right_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool range_reference::contains(const cell_reference &ref) const
|
||||||
|
{
|
||||||
|
return top_left_.column_index() <= ref.column_index()
|
||||||
|
&& bottom_right_.column_index() >= ref.column_index()
|
||||||
|
&& top_left_.row() <= ref.row()
|
||||||
|
&& bottom_right_.row() >= ref.row();
|
||||||
|
}
|
||||||
|
|
||||||
bool range_reference::operator==(const std::string &reference_string) const
|
bool range_reference::operator==(const std::string &reference_string) const
|
||||||
{
|
{
|
||||||
return *this == range_reference(reference_string);
|
return *this == range_reference(reference_string);
|
||||||
|
|
BIN
tests/data/18_formulae.xlsx
Normal file
BIN
tests/data/18_formulae.xlsx
Normal file
Binary file not shown.
|
@ -23,31 +23,7 @@
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include <xlnt/cell/cell.hpp>
|
#include <xlnt/xlnt.hpp>
|
||||||
#include <xlnt/cell/comment.hpp>
|
|
||||||
#include <xlnt/cell/hyperlink.hpp>
|
|
||||||
#include <xlnt/styles/border.hpp>
|
|
||||||
#include <xlnt/styles/fill.hpp>
|
|
||||||
#include <xlnt/styles/font.hpp>
|
|
||||||
#include <xlnt/styles/format.hpp>
|
|
||||||
#include <xlnt/styles/number_format.hpp>
|
|
||||||
#include <xlnt/styles/style.hpp>
|
|
||||||
#include <xlnt/utils/date.hpp>
|
|
||||||
#include <xlnt/utils/datetime.hpp>
|
|
||||||
#include <xlnt/utils/time.hpp>
|
|
||||||
#include <xlnt/utils/timedelta.hpp>
|
|
||||||
#include <xlnt/utils/variant.hpp>
|
|
||||||
#include <xlnt/workbook/metadata_property.hpp>
|
|
||||||
#include <xlnt/workbook/streaming_workbook_reader.hpp>
|
|
||||||
#include <xlnt/workbook/streaming_workbook_writer.hpp>
|
|
||||||
#include <xlnt/workbook/workbook.hpp>
|
|
||||||
#include <xlnt/worksheet/column_properties.hpp>
|
|
||||||
#include <xlnt/worksheet/header_footer.hpp>
|
|
||||||
#include <xlnt/worksheet/row_properties.hpp>
|
|
||||||
#include <xlnt/worksheet/sheet_format_properties.hpp>
|
|
||||||
#include <xlnt/worksheet/worksheet.hpp>
|
|
||||||
#include <detail/cryptography/xlsx_crypto_consumer.hpp>
|
|
||||||
#include <detail/serialization/vector_streambuf.hpp>
|
|
||||||
#include <helpers/path_helper.hpp>
|
#include <helpers/path_helper.hpp>
|
||||||
#include <helpers/temporary_file.hpp>
|
#include <helpers/temporary_file.hpp>
|
||||||
#include <helpers/test_suite.hpp>
|
#include <helpers/test_suite.hpp>
|
||||||
|
@ -62,7 +38,7 @@ public:
|
||||||
register_test(test_produce_simple_excel);
|
register_test(test_produce_simple_excel);
|
||||||
register_test(test_save_after_sheet_deletion);
|
register_test(test_save_after_sheet_deletion);
|
||||||
register_test(test_write_comments_hyperlinks_formulae);
|
register_test(test_write_comments_hyperlinks_formulae);
|
||||||
register_test(test_save_after_clear_all_formulae);
|
register_test(test_save_after_clear_formula);
|
||||||
register_test(test_load_non_xlsx);
|
register_test(test_load_non_xlsx);
|
||||||
register_test(test_decrypt_agile);
|
register_test(test_decrypt_agile);
|
||||||
register_test(test_decrypt_libre_office);
|
register_test(test_decrypt_libre_office);
|
||||||
|
@ -304,21 +280,20 @@ public:
|
||||||
xlnt_assert(workbook_matches_file(wb, path));
|
xlnt_assert(workbook_matches_file(wb, path));
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_save_after_clear_all_formulae()
|
void test_save_after_clear_formula()
|
||||||
{
|
{
|
||||||
xlnt::workbook wb;
|
xlnt::workbook wb;
|
||||||
const auto path = path_helper::test_file("10_comments_hyperlinks_formulae.xlsx");
|
const auto path = path_helper::test_file("18_formulae.xlsx");
|
||||||
wb.load(path);
|
wb.load(path);
|
||||||
|
|
||||||
auto ws1 = wb.sheet_by_index(0);
|
auto ws1 = wb.sheet_by_index(0);
|
||||||
xlnt_assert(ws1.cell("C1").has_formula());
|
for (auto row : ws1)
|
||||||
xlnt_assert_equals(ws1.cell("C1").formula(), "CONCATENATE(C2,C3)");
|
{
|
||||||
ws1.cell("C1").clear_formula();
|
for (auto cell : row)
|
||||||
|
{
|
||||||
auto ws2 = wb.sheet_by_index(1);
|
cell.clear_formula();
|
||||||
xlnt_assert(ws2.cell("C1").has_formula());
|
}
|
||||||
xlnt_assert_equals(ws2.cell("C1").formula(), "C2*C3");
|
}
|
||||||
ws2.cell("C1").clear_formula();
|
|
||||||
|
|
||||||
wb.save("clear_formulae.xlsx");
|
wb.save("clear_formulae.xlsx");
|
||||||
}
|
}
|
||||||
|
@ -425,20 +400,41 @@ public:
|
||||||
void test_read_formulae()
|
void test_read_formulae()
|
||||||
{
|
{
|
||||||
xlnt::workbook wb;
|
xlnt::workbook wb;
|
||||||
const auto path = path_helper::test_file("10_comments_hyperlinks_formulae.xlsx");
|
const auto path = path_helper::test_file("18_formulae.xlsx");
|
||||||
wb.load(path);
|
wb.load(path);
|
||||||
|
|
||||||
auto ws1 = wb.sheet_by_index(0);
|
auto ws1 = wb.sheet_by_index(0);
|
||||||
xlnt_assert(ws1.cell("C1").has_formula());
|
|
||||||
xlnt_assert_equals(ws1.cell("C1").formula(), "CONCATENATE(C2,C3)");
|
|
||||||
xlnt_assert_equals(ws1.cell("C2").value<std::string>(), "a");
|
|
||||||
xlnt_assert_equals(ws1.cell("C3").value<std::string>(), "b");
|
|
||||||
|
|
||||||
auto ws2 = wb.sheet_by_index(1);
|
// test has_formula
|
||||||
xlnt_assert(ws2.cell("C1").has_formula());
|
// A1:B3 are plain text cells
|
||||||
xlnt_assert_equals(ws2.cell("C1").formula(), "C2*C3");
|
// C1:G3,I2,F4 have formulae
|
||||||
xlnt_assert_equals(ws2.cell("C2").value<int>(), 2);
|
for (auto row = 1; row < 4; row++)
|
||||||
xlnt_assert_equals(ws2.cell("C3").value<int>(), 3);
|
{
|
||||||
|
for (auto column = 1; column < 8; column++)
|
||||||
|
{
|
||||||
|
if (column < 3)
|
||||||
|
{
|
||||||
|
xlnt_assert(!ws1.cell(column, row).has_formula());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
xlnt_assert(ws1.cell(column, row).has_formula());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
xlnt_assert(ws1.cell("I2").has_formula());
|
||||||
|
xlnt_assert(ws1.cell("F4").has_formula());
|
||||||
|
|
||||||
|
xlnt_assert(!ws1.cell("C9").has_formula()); // empty cell
|
||||||
|
xlnt_assert(!ws1.cell("F5").has_formula()); // text cell
|
||||||
|
|
||||||
|
xlnt_assert_equals(ws1.cell("C1").formula(), "B1^2"); // basic math with reference
|
||||||
|
xlnt_assert_equals(ws1.cell("D1").formula(), "CONCATENATE(A1,B1)"); // concat with ref
|
||||||
|
xlnt_assert_equals(ws1.cell("E1").formula(), "CONCATENATE($C$1,$D$1)"); // concat with absolute ref
|
||||||
|
xlnt_assert_equals(ws1.cell("F1").formula(), "1+1"); // basic math
|
||||||
|
xlnt_assert_equals(ws1.cell("G1").formula(), "PI()"); // constant
|
||||||
|
xlnt_assert_equals(ws1.cell("I2").formula(), "COS(C2)+IMAGINARY(SIN(B2))"); // fancy math
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_read_headers_and_footers()
|
void test_read_headers_and_footers()
|
||||||
|
|
Loading…
Reference in New Issue
Block a user