mirror of
https://github.com/tfussell/xlnt.git
synced 2024-03-22 13:11:17 +08:00
Merge branch 'dev' into phonetics
This commit is contained in:
commit
f54a150589
|
@ -283,6 +283,12 @@ public:
|
||||||
index_t index;
|
index_t index;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class row_or_col_t : int
|
||||||
|
{
|
||||||
|
row,
|
||||||
|
column
|
||||||
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Functor for hashing a column.
|
/// Functor for hashing a column.
|
||||||
/// Allows for use of std::unordered_set<column_t, column_hash> and similar.
|
/// Allows for use of std::unordered_set<column_t, column_hash> and similar.
|
||||||
|
|
|
@ -270,6 +270,26 @@ public:
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void clear_row(row_t row);
|
void clear_row(row_t row);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Insert empty rows before the given row index
|
||||||
|
/// </summary>
|
||||||
|
void insert_rows(row_t row, std::uint32_t amount);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Insert empty columns before the given column index
|
||||||
|
/// </summary>
|
||||||
|
void insert_columns(column_t column, std::uint32_t amount);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Delete rows before the given row index
|
||||||
|
/// </summary>
|
||||||
|
void delete_rows(row_t row, std::uint32_t amount);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Delete columns before the given column index
|
||||||
|
/// </summary>
|
||||||
|
void delete_columns(column_t column, std::uint32_t amount);
|
||||||
|
|
||||||
// properties
|
// properties
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -778,6 +798,12 @@ private:
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void parent(class workbook &wb);
|
void parent(class workbook &wb);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Move cells after index down or right by a given amount. The direction is decided by row_or_col.
|
||||||
|
/// If reverse is true, the cells will be moved up or left, depending on row_or_col.
|
||||||
|
/// </summary>
|
||||||
|
void move_cells(std::uint32_t index, std::uint32_t amount, row_or_col_t row_or_col, bool reverse = false);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The pointer to this sheet's implementation.
|
/// The pointer to this sheet's implementation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -371,7 +371,7 @@ hyperlink cell::hyperlink() const
|
||||||
|
|
||||||
void cell::hyperlink(const std::string &url, const std::string &display)
|
void cell::hyperlink(const std::string &url, const std::string &display)
|
||||||
{
|
{
|
||||||
if (url.empty() || std::find(url.begin(), url.end(), ':') == url.end())
|
if (url.empty())
|
||||||
{
|
{
|
||||||
throw invalid_parameter();
|
throw invalid_parameter();
|
||||||
}
|
}
|
||||||
|
@ -857,6 +857,12 @@ void cell::clear_style()
|
||||||
void cell::style(const class style &new_style)
|
void cell::style(const class style &new_style)
|
||||||
{
|
{
|
||||||
auto new_format = has_format() ? format() : workbook().create_format();
|
auto new_format = has_format() ? format() : workbook().create_format();
|
||||||
|
|
||||||
|
new_format.border(new_style.border());
|
||||||
|
new_format.fill(new_style.fill());
|
||||||
|
new_format.font(new_style.font());
|
||||||
|
new_format.number_format(new_style.number_format());
|
||||||
|
|
||||||
format(new_format.style(new_style));
|
format(new_format.style(new_style));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,11 +52,6 @@ struct stylesheet
|
||||||
impl.parent = this;
|
impl.parent = this;
|
||||||
impl.id = format_impls.size() - 1;
|
impl.id = format_impls.size() - 1;
|
||||||
|
|
||||||
impl.border_id = 0;
|
|
||||||
impl.fill_id = 0;
|
|
||||||
impl.font_id = 0;
|
|
||||||
impl.number_format_id = 0;
|
|
||||||
|
|
||||||
impl.references = default_format ? 1 : 0;
|
impl.references = default_format ? 1 : 0;
|
||||||
|
|
||||||
return xlnt::format(&impl);
|
return xlnt::format(&impl);
|
||||||
|
|
|
@ -1673,13 +1673,13 @@ std::string number_formatter::format_number(const format_code &format, double nu
|
||||||
|
|
||||||
case template_part::template_type::day_abbreviation:
|
case template_part::template_type::day_abbreviation:
|
||||||
{
|
{
|
||||||
result.append(day_names->at(static_cast<std::size_t>(dt.weekday()) - 1).substr(0, 3));
|
result.append(day_names->at(static_cast<std::size_t>(dt.weekday())).substr(0, 3));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case template_part::template_type::day_name:
|
case template_part::template_type::day_name:
|
||||||
{
|
{
|
||||||
result.append(day_names->at(static_cast<std::size_t>(dt.weekday()) - 1));
|
result.append(day_names->at(static_cast<std::size_t>(dt.weekday())));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2349,7 +2349,7 @@ void xlsx_consumer::read_stylesheet()
|
||||||
}
|
}
|
||||||
record.first.border_id = parser().attribute_present("borderId")
|
record.first.border_id = parser().attribute_present("borderId")
|
||||||
? parser().attribute<std::size_t>("borderId")
|
? parser().attribute<std::size_t>("borderId")
|
||||||
: 0;
|
: optional<std::size_t>();
|
||||||
|
|
||||||
if (parser().attribute_present("applyFill"))
|
if (parser().attribute_present("applyFill"))
|
||||||
{
|
{
|
||||||
|
@ -2357,7 +2357,7 @@ void xlsx_consumer::read_stylesheet()
|
||||||
}
|
}
|
||||||
record.first.fill_id = parser().attribute_present("fillId")
|
record.first.fill_id = parser().attribute_present("fillId")
|
||||||
? parser().attribute<std::size_t>("fillId")
|
? parser().attribute<std::size_t>("fillId")
|
||||||
: 0;
|
: optional<std::size_t>();
|
||||||
|
|
||||||
if (parser().attribute_present("applyFont"))
|
if (parser().attribute_present("applyFont"))
|
||||||
{
|
{
|
||||||
|
@ -2365,7 +2365,7 @@ void xlsx_consumer::read_stylesheet()
|
||||||
}
|
}
|
||||||
record.first.font_id = parser().attribute_present("fontId")
|
record.first.font_id = parser().attribute_present("fontId")
|
||||||
? parser().attribute<std::size_t>("fontId")
|
? parser().attribute<std::size_t>("fontId")
|
||||||
: 0;
|
: optional<std::size_t>();
|
||||||
|
|
||||||
if (parser().attribute_present("applyNumberFormat"))
|
if (parser().attribute_present("applyNumberFormat"))
|
||||||
{
|
{
|
||||||
|
@ -2373,7 +2373,7 @@ void xlsx_consumer::read_stylesheet()
|
||||||
}
|
}
|
||||||
record.first.number_format_id = parser().attribute_present("numFmtId")
|
record.first.number_format_id = parser().attribute_present("numFmtId")
|
||||||
? parser().attribute<std::size_t>("numFmtId")
|
? parser().attribute<std::size_t>("numFmtId")
|
||||||
: 0;
|
: optional<std::size_t>();
|
||||||
|
|
||||||
auto apply_alignment_present = parser().attribute_present("applyAlignment");
|
auto apply_alignment_present = parser().attribute_present("applyAlignment");
|
||||||
if (apply_alignment_present)
|
if (apply_alignment_present)
|
||||||
|
|
|
@ -126,18 +126,10 @@ date date::today()
|
||||||
|
|
||||||
int date::weekday() const
|
int date::weekday() const
|
||||||
{
|
{
|
||||||
auto year_temp = (month == 1 || month == 2) ? year - 1 : year;
|
std::tm tm {0, 0, 0, day, month - 1, year - 1900};
|
||||||
auto month_temp = month == 1 ? 13 : month == 2 ? 14 : month;
|
std::time_t time = std::mktime(&tm);
|
||||||
auto day_temp = day + 1;
|
|
||||||
|
|
||||||
auto days = day_temp + static_cast<int>(13 * (month_temp + 1) / 5.0) + (year_temp % 100)
|
return safe_localtime(time).tm_wday;
|
||||||
+ static_cast<int>((year_temp % 100) / 4.0);
|
|
||||||
auto gregorian = days + static_cast<int>(year_temp / 400.0) - 2 * year_temp / 100;
|
|
||||||
auto julian = days + 5 - year_temp / 100;
|
|
||||||
|
|
||||||
int weekday = (year_temp > 1582 ? gregorian : julian) % 7;
|
|
||||||
|
|
||||||
return weekday == 0 ? 7 : weekday;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
||||||
|
|
|
@ -1617,9 +1617,9 @@ struct rel_id_sorter
|
||||||
bool operator()(const xlnt::relationship &lhs, const xlnt::relationship &rhs)
|
bool operator()(const xlnt::relationship &lhs, const xlnt::relationship &rhs)
|
||||||
{
|
{
|
||||||
// format is rTd<decimal number 1..n>
|
// format is rTd<decimal number 1..n>
|
||||||
if (lhs.id().size() < rhs.id().size()) // a number with more digits will be larger
|
if (lhs.id().size() != rhs.id().size()) // a number with more digits will be larger
|
||||||
{
|
{
|
||||||
return true;
|
return lhs.id().size() < rhs.id().size();
|
||||||
}
|
}
|
||||||
return lhs.id() < rhs.id();
|
return lhs.id() < rhs.id();
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,10 @@
|
||||||
#include <xlnt/worksheet/range_iterator.hpp>
|
#include <xlnt/worksheet/range_iterator.hpp>
|
||||||
#include <xlnt/worksheet/range_reference.hpp>
|
#include <xlnt/worksheet/range_reference.hpp>
|
||||||
#include <xlnt/worksheet/worksheet.hpp>
|
#include <xlnt/worksheet/worksheet.hpp>
|
||||||
|
#include <xlnt/worksheet/row_properties.hpp>
|
||||||
|
#include <xlnt/worksheet/column_properties.hpp>
|
||||||
#include <detail/constants.hpp>
|
#include <detail/constants.hpp>
|
||||||
|
#include <detail/default_case.hpp>
|
||||||
#include <detail/implementations/cell_impl.hpp>
|
#include <detail/implementations/cell_impl.hpp>
|
||||||
#include <detail/implementations/workbook_impl.hpp>
|
#include <detail/implementations/workbook_impl.hpp>
|
||||||
#include <detail/implementations/worksheet_impl.hpp>
|
#include <detail/implementations/worksheet_impl.hpp>
|
||||||
|
@ -736,6 +739,182 @@ void worksheet::clear_row(row_t row)
|
||||||
// TODO: garbage collect newly unreferenced resources such as styles?
|
// TODO: garbage collect newly unreferenced resources such as styles?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void worksheet::insert_rows(row_t row, std::uint32_t amount)
|
||||||
|
{
|
||||||
|
move_cells(row, amount, row_or_col_t::row);
|
||||||
|
}
|
||||||
|
|
||||||
|
void worksheet::insert_columns(column_t column, std::uint32_t amount)
|
||||||
|
{
|
||||||
|
move_cells(column.index, amount, row_or_col_t::column);
|
||||||
|
}
|
||||||
|
|
||||||
|
void worksheet::delete_rows(row_t row, std::uint32_t amount)
|
||||||
|
{
|
||||||
|
move_cells(row + amount, amount, row_or_col_t::row, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void worksheet::delete_columns(column_t column, std::uint32_t amount)
|
||||||
|
{
|
||||||
|
move_cells(column.index + amount, amount, row_or_col_t::column, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void worksheet::move_cells(std::uint32_t min_index, std::uint32_t amount, row_or_col_t row_or_col, bool reverse)
|
||||||
|
{
|
||||||
|
if (reverse && amount > min_index)
|
||||||
|
{
|
||||||
|
throw xlnt::invalid_parameter();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((!reverse && row_or_col == row_or_col_t::row && min_index > constants::max_row() - amount) ||
|
||||||
|
(!reverse && row_or_col == row_or_col_t::column && min_index > constants::max_column() - amount))
|
||||||
|
{
|
||||||
|
throw xlnt::exception("Cannot move cells as they would be outside the maximum bounds of the spreadsheet");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<detail::cell_impl> cells_to_move;
|
||||||
|
|
||||||
|
auto cell_iter = d_->cell_map_.cbegin();
|
||||||
|
while (cell_iter != d_->cell_map_.cend())
|
||||||
|
{
|
||||||
|
std::uint32_t current_index;
|
||||||
|
switch (row_or_col)
|
||||||
|
{
|
||||||
|
case row_or_col_t::row:
|
||||||
|
current_index = cell_iter->first.row();
|
||||||
|
break;
|
||||||
|
case row_or_col_t::column:
|
||||||
|
current_index = cell_iter->first.column().index;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw xlnt::unhandled_switch_case();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_index >= min_index) // extract cells to be moved
|
||||||
|
{
|
||||||
|
auto cell = cell_iter->second;
|
||||||
|
if (row_or_col == row_or_col_t::row)
|
||||||
|
{
|
||||||
|
cell.row_ = reverse ? cell.row_ - amount : cell.row_ + amount;
|
||||||
|
}
|
||||||
|
else if (row_or_col == row_or_col_t::column)
|
||||||
|
{
|
||||||
|
cell.column_ = reverse ? cell.column_.index - amount: cell.column_.index + amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
cells_to_move.push_back(cell);
|
||||||
|
cell_iter = d_->cell_map_.erase(cell_iter);
|
||||||
|
}
|
||||||
|
else if (reverse && current_index >= min_index - amount) // delete destination cells
|
||||||
|
{
|
||||||
|
cell_iter = d_->cell_map_.erase(cell_iter);
|
||||||
|
}
|
||||||
|
else // skip other cells
|
||||||
|
{
|
||||||
|
++cell_iter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &cell : cells_to_move)
|
||||||
|
{
|
||||||
|
d_->cell_map_[cell_reference(cell.column_, cell.row_)] = cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (row_or_col == row_or_col_t::row)
|
||||||
|
{
|
||||||
|
std::vector<std::pair<row_t, xlnt::row_properties>> properties_to_move;
|
||||||
|
|
||||||
|
auto row_prop_iter = d_->row_properties_.cbegin();
|
||||||
|
while (row_prop_iter != d_->row_properties_.cend())
|
||||||
|
{
|
||||||
|
auto current_row = row_prop_iter->first;
|
||||||
|
if (current_row >= min_index) // extract properties that need to be moved
|
||||||
|
{
|
||||||
|
auto tmp_row = reverse ? current_row - amount : current_row + amount;
|
||||||
|
properties_to_move.push_back({tmp_row, row_prop_iter->second});
|
||||||
|
row_prop_iter = d_->row_properties_.erase(row_prop_iter);
|
||||||
|
}
|
||||||
|
else if (reverse && current_row >= min_index - amount) // clear properties of destination when in reverse
|
||||||
|
{
|
||||||
|
row_prop_iter = d_->row_properties_.erase(row_prop_iter);
|
||||||
|
}
|
||||||
|
else // skip the rest
|
||||||
|
{
|
||||||
|
++row_prop_iter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &prop : properties_to_move)
|
||||||
|
{
|
||||||
|
add_row_properties(prop.first, prop.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (row_or_col == row_or_col_t::column)
|
||||||
|
{
|
||||||
|
std::vector<std::pair<column_t, xlnt::column_properties>> properties_to_move;
|
||||||
|
|
||||||
|
auto col_prop_iter = d_->column_properties_.cbegin();
|
||||||
|
while (col_prop_iter != d_->column_properties_.cend())
|
||||||
|
{
|
||||||
|
auto current_col = col_prop_iter->first.index;
|
||||||
|
if (current_col >= min_index) // extract properties that need to be moved
|
||||||
|
{
|
||||||
|
auto tmp_column = column_t(reverse ? current_col - amount : current_col + amount);
|
||||||
|
properties_to_move.push_back({tmp_column, col_prop_iter->second});
|
||||||
|
col_prop_iter = d_->column_properties_.erase(col_prop_iter);
|
||||||
|
}
|
||||||
|
else if (reverse && current_col >= min_index - amount) // clear properties of destination when in reverse
|
||||||
|
{
|
||||||
|
col_prop_iter = d_->column_properties_.erase(col_prop_iter);
|
||||||
|
}
|
||||||
|
else // skip the rest
|
||||||
|
{
|
||||||
|
++col_prop_iter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &prop : properties_to_move)
|
||||||
|
{
|
||||||
|
add_column_properties(prop.first, prop.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// adjust merged cells
|
||||||
|
auto shift_reference = [min_index, amount, row_or_col, reverse](cell_reference &ref)
|
||||||
|
{
|
||||||
|
auto index = row_or_col == row_or_col_t::row ?
|
||||||
|
ref.row() :
|
||||||
|
ref.column_index();
|
||||||
|
if (index >= min_index)
|
||||||
|
{
|
||||||
|
auto new_index = reverse ? index - amount : index + amount;
|
||||||
|
if (row_or_col == row_or_col_t::row)
|
||||||
|
{
|
||||||
|
ref.row(new_index);
|
||||||
|
}
|
||||||
|
else if (row_or_col == row_or_col_t::column)
|
||||||
|
{
|
||||||
|
ref.column_index(new_index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto merged_cell = d_->merged_cells_.begin(); merged_cell != d_->merged_cells_.end(); ++merged_cell)
|
||||||
|
{
|
||||||
|
cell_reference new_top_left = merged_cell->top_left();
|
||||||
|
shift_reference(new_top_left);
|
||||||
|
|
||||||
|
cell_reference new_bottom_right = merged_cell->bottom_right();
|
||||||
|
shift_reference(new_bottom_right);
|
||||||
|
|
||||||
|
range_reference new_range {new_top_left, new_bottom_right};
|
||||||
|
if (*merged_cell != new_range)
|
||||||
|
{
|
||||||
|
*merged_cell = new_range;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool worksheet::operator==(const worksheet &other) const
|
bool worksheet::operator==(const worksheet &other) const
|
||||||
{
|
{
|
||||||
return compare(other, true);
|
return compare(other, true);
|
||||||
|
|
|
@ -688,7 +688,6 @@ private:
|
||||||
|
|
||||||
xlnt_assert(!cell.has_hyperlink());
|
xlnt_assert(!cell.has_hyperlink());
|
||||||
xlnt_assert_throws(cell.hyperlink(), xlnt::invalid_attribute);
|
xlnt_assert_throws(cell.hyperlink(), xlnt::invalid_attribute);
|
||||||
xlnt_assert_throws(cell.hyperlink("notaurl"), xlnt::invalid_parameter);
|
|
||||||
xlnt_assert_throws(cell.hyperlink(""), xlnt::invalid_parameter);
|
xlnt_assert_throws(cell.hyperlink(""), xlnt::invalid_parameter);
|
||||||
// link without optional display
|
// link without optional display
|
||||||
const std::string link1("http://example.com");
|
const std::string link1("http://example.com");
|
||||||
|
@ -708,6 +707,13 @@ private:
|
||||||
xlnt_assert_equals(cell.hyperlink().url(), link2);
|
xlnt_assert_equals(cell.hyperlink().url(), link2);
|
||||||
xlnt_assert_equals(cell.hyperlink().relationship().target().to_string(), link2);
|
xlnt_assert_equals(cell.hyperlink().relationship().target().to_string(), link2);
|
||||||
xlnt_assert_equals(cell.hyperlink().display(), display_txt);
|
xlnt_assert_equals(cell.hyperlink().display(), display_txt);
|
||||||
|
// relative (local) url
|
||||||
|
const std::string local("../test_local");
|
||||||
|
cell.hyperlink(local);
|
||||||
|
xlnt_assert(cell.has_hyperlink());
|
||||||
|
xlnt_assert(cell.hyperlink().external());
|
||||||
|
xlnt_assert_equals(cell.hyperlink().url(), local);
|
||||||
|
xlnt_assert_equals(cell.hyperlink().relationship().target().to_string(), local);
|
||||||
// value
|
// value
|
||||||
int cell_test_val = 123;
|
int cell_test_val = 123;
|
||||||
cell.value(cell_test_val);
|
cell.value(cell_test_val);
|
||||||
|
|
Binary file not shown.
|
@ -37,12 +37,12 @@ public:
|
||||||
{
|
{
|
||||||
register_test(test_basic);
|
register_test(test_basic);
|
||||||
register_test(test_simple_format);
|
register_test(test_simple_format);
|
||||||
|
register_test(test_bad_date_format);
|
||||||
register_test(test_simple_date);
|
register_test(test_simple_date);
|
||||||
register_test(test_short_month);
|
register_test(test_short_month);
|
||||||
register_test(test_month_abbreviation);
|
register_test(test_month_abbreviation);
|
||||||
register_test(test_month_name);
|
register_test(test_month_name);
|
||||||
register_test(test_basic);
|
register_test(test_basic);
|
||||||
register_test(test_simple_format);
|
|
||||||
register_test(test_upper_case_date);
|
register_test(test_upper_case_date);
|
||||||
register_test(test_simple_date);
|
register_test(test_simple_date);
|
||||||
register_test(test_short_day);
|
register_test(test_short_day);
|
||||||
|
@ -155,6 +155,46 @@ public:
|
||||||
xlnt_assert_equals(formatted, "zero0");
|
xlnt_assert_equals(formatted, "zero0");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_bad_date_format()
|
||||||
|
{
|
||||||
|
auto date = xlnt::date(2016, 6, 18);
|
||||||
|
auto date_number = date.to_number(xlnt::calendar::windows_1900);
|
||||||
|
|
||||||
|
xlnt::number_format nf;
|
||||||
|
|
||||||
|
nf.format_string("[x]");
|
||||||
|
xlnt_assert_throws(nf.format(date_number, xlnt::calendar::windows_1900),
|
||||||
|
std::runtime_error);
|
||||||
|
|
||||||
|
nf.format_string("mmmmmm");
|
||||||
|
xlnt_assert_throws(nf.format(date_number, xlnt::calendar::windows_1900),
|
||||||
|
std::runtime_error);
|
||||||
|
|
||||||
|
nf.format_string("ddddd");
|
||||||
|
xlnt_assert_throws(nf.format(date_number, xlnt::calendar::windows_1900),
|
||||||
|
std::runtime_error);
|
||||||
|
|
||||||
|
nf.format_string("yyy");
|
||||||
|
xlnt_assert_throws(nf.format(date_number, xlnt::calendar::windows_1900),
|
||||||
|
std::runtime_error);
|
||||||
|
|
||||||
|
nf.format_string("hhh");
|
||||||
|
xlnt_assert_throws(nf.format(date_number, xlnt::calendar::windows_1900),
|
||||||
|
std::runtime_error);
|
||||||
|
|
||||||
|
nf.format_string("sss");
|
||||||
|
xlnt_assert_throws(nf.format(date_number, xlnt::calendar::windows_1900),
|
||||||
|
std::runtime_error);
|
||||||
|
|
||||||
|
nf.format_string("AA");
|
||||||
|
xlnt_assert_throws(nf.format(date_number, xlnt::calendar::windows_1900),
|
||||||
|
std::runtime_error);
|
||||||
|
|
||||||
|
nf.format_string("q");
|
||||||
|
xlnt_assert_throws(nf.format(date_number, xlnt::calendar::windows_1900),
|
||||||
|
std::runtime_error);
|
||||||
|
}
|
||||||
|
|
||||||
void test_upper_case_date()
|
void test_upper_case_date()
|
||||||
{
|
{
|
||||||
auto date = xlnt::date(2016, 6, 18);
|
auto date = xlnt::date(2016, 6, 18);
|
||||||
|
@ -259,7 +299,7 @@ public:
|
||||||
nf.format_string("dddd");
|
nf.format_string("dddd");
|
||||||
auto formatted = nf.format(date_number, xlnt::calendar::windows_1900);
|
auto formatted = nf.format(date_number, xlnt::calendar::windows_1900);
|
||||||
|
|
||||||
xlnt_assert_equals(formatted, "Sunday");
|
xlnt_assert_equals(formatted, "Saturday");
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_day_abbreviation()
|
void test_day_abbreviation()
|
||||||
|
@ -271,7 +311,7 @@ public:
|
||||||
nf.format_string("ddd");
|
nf.format_string("ddd");
|
||||||
auto formatted = nf.format(date_number, xlnt::calendar::windows_1900);
|
auto formatted = nf.format(date_number, xlnt::calendar::windows_1900);
|
||||||
|
|
||||||
xlnt_assert_equals(formatted, "Sun");
|
xlnt_assert_equals(formatted, "Sat");
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_month_letter()
|
void test_month_letter()
|
||||||
|
|
|
@ -40,6 +40,7 @@ public:
|
||||||
register_test(test_early_date);
|
register_test(test_early_date);
|
||||||
register_test(test_mac_calendar);
|
register_test(test_mac_calendar);
|
||||||
register_test(test_operators);
|
register_test(test_operators);
|
||||||
|
register_test(test_weekday);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_from_string()
|
void test_from_string()
|
||||||
|
@ -113,5 +114,12 @@ public:
|
||||||
xlnt_assert_equals(d1, d2);
|
xlnt_assert_equals(d1, d2);
|
||||||
xlnt_assert_differs(d1, d3);
|
xlnt_assert_differs(d1, d3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_weekday()
|
||||||
|
{
|
||||||
|
xlnt_assert_equals(xlnt::date(2000, 1, 1).weekday(), 6);
|
||||||
|
xlnt_assert_equals(xlnt::date(2016, 7, 15).weekday(), 5);
|
||||||
|
xlnt_assert_equals(xlnt::date(2018, 10, 29).weekday(), 1);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
static datetime_test_suite x;
|
static datetime_test_suite x;
|
|
@ -105,6 +105,12 @@ public:
|
||||||
register_test(test_clear_row);
|
register_test(test_clear_row);
|
||||||
register_test(test_set_title);
|
register_test(test_set_title);
|
||||||
register_test(test_phonetics);
|
register_test(test_phonetics);
|
||||||
|
register_test(test_insert_rows);
|
||||||
|
register_test(test_insert_columns);
|
||||||
|
register_test(test_delete_rows);
|
||||||
|
register_test(test_delete_columns);
|
||||||
|
register_test(test_insert_too_many);
|
||||||
|
register_test(test_insert_delete_moves_merges);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_new_worksheet()
|
void test_new_worksheet()
|
||||||
|
@ -1283,5 +1289,285 @@ public:
|
||||||
xlnt_assert_equals(ws2.cell("B1").phonetics_visible(), true);
|
xlnt_assert_equals(ws2.cell("B1").phonetics_visible(), true);
|
||||||
xlnt_assert_equals(ws2.cell("C1").phonetics_visible(), false);
|
xlnt_assert_equals(ws2.cell("C1").phonetics_visible(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_insert_rows()
|
||||||
|
{
|
||||||
|
xlnt::workbook wb;
|
||||||
|
auto ws = wb.active_sheet();
|
||||||
|
|
||||||
|
// set up a 2x2 grid
|
||||||
|
ws.cell("A1").value("A1");
|
||||||
|
ws.cell("A2").value("A2");
|
||||||
|
ws.cell("B1").value("B1");
|
||||||
|
ws.cell("B2").value("B2");
|
||||||
|
|
||||||
|
xlnt::row_properties row_prop;
|
||||||
|
row_prop.height = 1;
|
||||||
|
ws.add_row_properties(1, row_prop);
|
||||||
|
row_prop.height = 2;
|
||||||
|
ws.add_row_properties(2, row_prop);
|
||||||
|
|
||||||
|
xlnt::column_properties col_prop;
|
||||||
|
col_prop.width = 1;
|
||||||
|
ws.add_column_properties(1, col_prop);
|
||||||
|
col_prop.width = 2;
|
||||||
|
ws.add_column_properties(2, col_prop);
|
||||||
|
|
||||||
|
// insert
|
||||||
|
ws.insert_rows(2, 2);
|
||||||
|
|
||||||
|
// first row should be unchanged
|
||||||
|
xlnt_assert(ws.cell("A1").has_value());
|
||||||
|
xlnt_assert(ws.cell("B1").has_value());
|
||||||
|
xlnt_assert_equals(ws.cell("A1").value<std::string>(), "A1");
|
||||||
|
xlnt_assert_equals(ws.cell("B1").value<std::string>(), "B1");
|
||||||
|
xlnt_assert_equals(ws.row_properties(1).height, 1);
|
||||||
|
|
||||||
|
// second and third rows should be empty
|
||||||
|
xlnt_assert(!ws.cell("A2").has_value());
|
||||||
|
xlnt_assert(!ws.cell("B2").has_value());
|
||||||
|
xlnt_assert(!ws.has_row_properties(2));
|
||||||
|
xlnt_assert(!ws.cell("A3").has_value());
|
||||||
|
xlnt_assert(!ws.cell("B3").has_value());
|
||||||
|
xlnt_assert(!ws.has_row_properties(3));
|
||||||
|
|
||||||
|
// fourth row should have the contents and properties of the second
|
||||||
|
xlnt_assert(ws.cell("A4").has_value());
|
||||||
|
xlnt_assert(ws.cell("B4").has_value());
|
||||||
|
xlnt_assert_equals(ws.cell("A4").value<std::string>(), "A2");
|
||||||
|
xlnt_assert_equals(ws.cell("B4").value<std::string>(), "B2");
|
||||||
|
xlnt_assert_equals(ws.row_properties(4).height, 2);
|
||||||
|
|
||||||
|
// column properties should remain unchanged
|
||||||
|
xlnt_assert(ws.has_column_properties(1));
|
||||||
|
xlnt_assert(ws.has_column_properties(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_insert_columns()
|
||||||
|
{
|
||||||
|
xlnt::workbook wb;
|
||||||
|
auto ws = wb.active_sheet();
|
||||||
|
|
||||||
|
// set up a 2x2 grid
|
||||||
|
ws.cell("A1").value("A1");
|
||||||
|
ws.cell("A2").value("A2");
|
||||||
|
ws.cell("B1").value("B1");
|
||||||
|
ws.cell("B2").value("B2");
|
||||||
|
|
||||||
|
xlnt::row_properties row_prop;
|
||||||
|
row_prop.height = 1;
|
||||||
|
ws.add_row_properties(1, row_prop);
|
||||||
|
row_prop.height = 2;
|
||||||
|
ws.add_row_properties(2, row_prop);
|
||||||
|
|
||||||
|
xlnt::column_properties col_prop;
|
||||||
|
col_prop.width = 1;
|
||||||
|
ws.add_column_properties(1, col_prop);
|
||||||
|
col_prop.width = 2;
|
||||||
|
ws.add_column_properties(2, col_prop);
|
||||||
|
|
||||||
|
// insert
|
||||||
|
ws.insert_columns(2, 2);
|
||||||
|
|
||||||
|
// first column should be unchanged
|
||||||
|
xlnt_assert(ws.cell("A1").has_value());
|
||||||
|
xlnt_assert(ws.cell("A2").has_value());
|
||||||
|
xlnt_assert_equals(ws.cell("A1").value<std::string>(), "A1");
|
||||||
|
xlnt_assert_equals(ws.cell("A2").value<std::string>(), "A2");
|
||||||
|
xlnt_assert_equals(ws.column_properties(1).width, 1);
|
||||||
|
|
||||||
|
// second and third columns should be empty
|
||||||
|
xlnt_assert(!ws.cell("B1").has_value());
|
||||||
|
xlnt_assert(!ws.cell("B2").has_value());
|
||||||
|
xlnt_assert(!ws.has_column_properties(2));
|
||||||
|
xlnt_assert(!ws.cell("C1").has_value());
|
||||||
|
xlnt_assert(!ws.cell("C2").has_value());
|
||||||
|
xlnt_assert(!ws.has_column_properties(3));
|
||||||
|
|
||||||
|
// fourth column should have the contents and properties of the second
|
||||||
|
xlnt_assert(ws.cell("D1").has_value());
|
||||||
|
xlnt_assert(ws.cell("D2").has_value());
|
||||||
|
xlnt_assert_equals(ws.cell("D1").value<std::string>(), "B1");
|
||||||
|
xlnt_assert_equals(ws.cell("D2").value<std::string>(), "B2");
|
||||||
|
xlnt_assert_equals(ws.column_properties(4).width, 2);
|
||||||
|
|
||||||
|
// row properties should remain unchanged
|
||||||
|
xlnt_assert_equals(ws.row_properties(1).height, 1);
|
||||||
|
xlnt_assert_equals(ws.row_properties(2).height, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_delete_rows()
|
||||||
|
{
|
||||||
|
xlnt::workbook wb;
|
||||||
|
auto ws = wb.active_sheet();
|
||||||
|
|
||||||
|
// set up a 4x4 grid
|
||||||
|
for (int i = 1; i <= 4; ++i)
|
||||||
|
{
|
||||||
|
for (int j = 1; j <= 4; ++j)
|
||||||
|
{
|
||||||
|
ws.cell(xlnt::cell_reference(i, j)).value(xlnt::cell_reference(i, j).to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
xlnt::row_properties row_prop;
|
||||||
|
row_prop.height = i;
|
||||||
|
ws.add_row_properties(i, row_prop);
|
||||||
|
|
||||||
|
xlnt::column_properties col_prop;
|
||||||
|
col_prop.width = i;
|
||||||
|
ws.add_column_properties(i, col_prop);
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete
|
||||||
|
ws.delete_rows(2, 2);
|
||||||
|
|
||||||
|
// first row should remain unchanged
|
||||||
|
xlnt_assert_equals(ws.cell("A1").value<std::string>(), "A1");
|
||||||
|
xlnt_assert_equals(ws.cell("B1").value<std::string>(), "B1");
|
||||||
|
xlnt_assert_equals(ws.cell("C1").value<std::string>(), "C1");
|
||||||
|
xlnt_assert_equals(ws.cell("D1").value<std::string>(), "D1");
|
||||||
|
xlnt_assert(ws.has_row_properties(1));
|
||||||
|
xlnt_assert_equals(ws.row_properties(1).height, 1);
|
||||||
|
|
||||||
|
// second row should have the contents and properties of the fourth
|
||||||
|
xlnt_assert_equals(ws.cell("A2").value<std::string>(), "A4");
|
||||||
|
xlnt_assert_equals(ws.cell("B2").value<std::string>(), "B4");
|
||||||
|
xlnt_assert_equals(ws.cell("C2").value<std::string>(), "C4");
|
||||||
|
xlnt_assert_equals(ws.cell("D2").value<std::string>(), "D4");
|
||||||
|
xlnt_assert(ws.has_row_properties(2));
|
||||||
|
xlnt_assert_equals(ws.row_properties(2).height, 4);
|
||||||
|
|
||||||
|
// third and fourth rows should be empty
|
||||||
|
auto empty_range = ws.range("A3:D4");
|
||||||
|
for (auto empty_row : empty_range)
|
||||||
|
{
|
||||||
|
for (auto empty_cell : empty_row)
|
||||||
|
{
|
||||||
|
xlnt_assert(!empty_cell.has_value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xlnt_assert(!ws.has_row_properties(3));
|
||||||
|
xlnt_assert(!ws.has_row_properties(4));
|
||||||
|
|
||||||
|
// column properties should remain unchanged
|
||||||
|
for (int i = 1; i <= 4; ++i)
|
||||||
|
{
|
||||||
|
xlnt_assert(ws.has_column_properties(i));
|
||||||
|
xlnt_assert_equals(ws.column_properties(i).width, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_delete_columns()
|
||||||
|
{
|
||||||
|
xlnt::workbook wb;
|
||||||
|
auto ws = wb.active_sheet();
|
||||||
|
|
||||||
|
// set up a 4x4 grid
|
||||||
|
for (int i = 1; i <= 4; ++i)
|
||||||
|
{
|
||||||
|
for (int j = 1; j <= 4; ++j)
|
||||||
|
{
|
||||||
|
ws.cell(xlnt::cell_reference(i, j)).value(xlnt::cell_reference(i, j).to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
xlnt::row_properties row_prop;
|
||||||
|
row_prop.height = i;
|
||||||
|
ws.add_row_properties(i, row_prop);
|
||||||
|
|
||||||
|
xlnt::column_properties col_prop;
|
||||||
|
col_prop.width = i;
|
||||||
|
ws.add_column_properties(i, col_prop);
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete
|
||||||
|
ws.delete_columns(2, 2);
|
||||||
|
|
||||||
|
// first column should remain unchanged
|
||||||
|
xlnt_assert_equals(ws.cell("A1").value<std::string>(), "A1");
|
||||||
|
xlnt_assert_equals(ws.cell("A2").value<std::string>(), "A2");
|
||||||
|
xlnt_assert_equals(ws.cell("A3").value<std::string>(), "A3");
|
||||||
|
xlnt_assert_equals(ws.cell("A4").value<std::string>(), "A4");
|
||||||
|
xlnt_assert(ws.has_column_properties("A"));
|
||||||
|
xlnt_assert_equals(ws.column_properties("A").width.get(), 1);
|
||||||
|
|
||||||
|
// second column should have the contents and properties of the fourth
|
||||||
|
xlnt_assert_equals(ws.cell("B1").value<std::string>(), "D1");
|
||||||
|
xlnt_assert_equals(ws.cell("B2").value<std::string>(), "D2");
|
||||||
|
xlnt_assert_equals(ws.cell("B3").value<std::string>(), "D3");
|
||||||
|
xlnt_assert_equals(ws.cell("B4").value<std::string>(), "D4");
|
||||||
|
xlnt_assert(ws.has_column_properties("B"));
|
||||||
|
xlnt_assert_equals(ws.column_properties("B").width.get(), 4);
|
||||||
|
|
||||||
|
// third and fourth columns should be empty
|
||||||
|
auto empty_range = ws.range("C1:D4");
|
||||||
|
for (auto empty_row : empty_range)
|
||||||
|
{
|
||||||
|
for (auto empty_cell : empty_row)
|
||||||
|
{
|
||||||
|
xlnt_assert(!empty_cell.has_value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xlnt_assert(!ws.has_column_properties("C"));
|
||||||
|
xlnt_assert(!ws.has_column_properties("D"));
|
||||||
|
|
||||||
|
// row properties should remain unchanged
|
||||||
|
for (int i = 1; i <= 4; ++i)
|
||||||
|
{
|
||||||
|
xlnt_assert(ws.has_row_properties(i));
|
||||||
|
xlnt_assert_equals(ws.row_properties(i).height, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_insert_too_many()
|
||||||
|
{
|
||||||
|
xlnt::workbook wb;
|
||||||
|
auto ws = wb.active_sheet();
|
||||||
|
xlnt_assert_throws(ws.insert_rows(10, 4294967290),
|
||||||
|
xlnt::exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_insert_delete_moves_merges()
|
||||||
|
{
|
||||||
|
xlnt::workbook wb;
|
||||||
|
auto ws = wb.active_sheet();
|
||||||
|
ws.merge_cells("A1:A2");
|
||||||
|
ws.merge_cells("B2:B3");
|
||||||
|
ws.merge_cells("C3:C4");
|
||||||
|
ws.merge_cells("A5:B5");
|
||||||
|
ws.merge_cells("B6:C6");
|
||||||
|
ws.merge_cells("C7:D7");
|
||||||
|
|
||||||
|
{
|
||||||
|
ws.insert_rows(3, 3);
|
||||||
|
ws.insert_columns(3, 3);
|
||||||
|
auto merged = ws.merged_ranges();
|
||||||
|
std::vector<xlnt::range_reference> expected =
|
||||||
|
{
|
||||||
|
xlnt::range_reference { "A1:A2" }, // stays
|
||||||
|
xlnt::range_reference { "B2:B6" }, // expands
|
||||||
|
xlnt::range_reference { "F6:F7" }, // shifts
|
||||||
|
xlnt::range_reference { "A8:B8" }, // stays (shifted down)
|
||||||
|
xlnt::range_reference { "B9:F9" }, // expands (shifted down)
|
||||||
|
xlnt::range_reference { "F10:G10" }, // shifts (shifted down)
|
||||||
|
};
|
||||||
|
xlnt_assert_equals(merged, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
ws.delete_rows(4, 2);
|
||||||
|
ws.delete_columns(4, 2);
|
||||||
|
auto merged = ws.merged_ranges();
|
||||||
|
std::vector<xlnt::range_reference> expected =
|
||||||
|
{
|
||||||
|
xlnt::range_reference { "A1:A2" }, // stays
|
||||||
|
xlnt::range_reference { "B2:B4" }, // expands
|
||||||
|
xlnt::range_reference { "D4:D5" }, // shifts
|
||||||
|
xlnt::range_reference { "A6:B6" }, // stays (shifted down)
|
||||||
|
xlnt::range_reference { "B7:D7" }, // expands (shifted down)
|
||||||
|
xlnt::range_reference { "D8:E8" }, // shifts (shifted down)
|
||||||
|
};
|
||||||
|
xlnt_assert_equals(merged, expected);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
static worksheet_test_suite x;
|
static worksheet_test_suite x;
|
Loading…
Reference in New Issue
Block a user