fixed some more tests

pull/3/head
Thomas Fussell 2014-05-12 19:59:33 -04:00
parent 99d609ce3a
commit 14cb4e88a4
9 changed files with 774 additions and 140 deletions

View File

@ -3,6 +3,7 @@
#include <iostream>
#include <cxxtest/TestSuite.h>
#include "TemporaryFile.h"
#include "../xlnt.h"
class DumpTestSuite : public CxxTest::TestSuite
@ -10,37 +11,41 @@ class DumpTestSuite : public CxxTest::TestSuite
public:
DumpTestSuite()
{
}
void _get_test_filename()
{
NamedTemporaryFile test_file("w", "xlnt.", ".xlsx", false);
test_file.close();
return test_file.name;
}
_COL_CONVERSION_CACHE = dict((get_column_letter(i), i) for i in range(1, 18279));
//_COL_CONVERSION_CACHE = dict((get_column_letter(i), i) for i in range(1, 18279));
void test_dump_sheet_title()
{
test_filename = _get_test_filename();
wb = Workbook(optimized_write = True);
ws = wb.create_sheet(title = "Test1");
wb.save(test_filename);
wb2 = load_workbook(test_filename, True);
xlnt::workbook wb;
wb.optimized_write(true);
auto ws = wb.create_sheet("Test1");
wb.save(temp_file.GetFilename());
xlnt::workbook wb2;
wb2.load(temp_file.GetFilename());
ws = wb2.get_sheet_by_name("Test1");
TS_ASSERT_EQUALS("Test1", ws.title);
TS_ASSERT_EQUALS("Test1", ws.get_title());
}
void test_dump_sheet()
{
test_filename = _get_test_filename();
wb = Workbook(optimized_write = True);
ws = wb.create_sheet();
letters = [get_column_letter(x + 1) for x in range(20)];
expected_rows = [];
for(auto row : range(20))
auto test_filename = temp_file.GetFilename();
xlnt::workbook wb;
wb.optimized_write(true);
auto ws = wb.create_sheet();
std::vector<std::string> letters;
for(int i = 0; i < 20; i++)
{
letters.push_back(xlnt::cell::get_column_letter(i + 1));
}
std::vector<xlnt::cell> expected_rows;
for(int row = 0; row < 20; row++)
{
expected_rows.append(["%s%d" % (letter, row + 1) for letter in letters]);
for(auto row in range(20))
@ -80,41 +85,43 @@ public:
void test_table_builder()
{
sb = StringTableBuilder();
StringTableBuilder sb;
result = {"a":0, "b" : 1, "c" : 2, "d" : 3};
std::unordered_map<std::string, int> result = {{"a", 0}, {"b", 1}, {"c", 2}, {"d", 3}};
for(auto letter in sorted(result.keys()))
for(auto pair : result)
{
for(int i = 0; i < 5; i++)
{
for x in range(5)
sb.add(pair.first);
auto table = sb.get_table();
try
{
sb.add(letter)
result_items = result.items();
}
table = dict(sb.get_table())
try
{
result_items = result.items()
}
for key, idx in result_items
{
TS_ASSERT_EQUALS(idx, table[key])
}
for key, idx in result_items
{
TS_ASSERT_EQUALS(idx, table[key])
}
}
}
}
void test_open_too_many_files()
{
test_filename = _get_test_filename();
wb = Workbook(optimized_write = True);
auto test_filename = temp_file.GetFilename();
for i in range(200) over 200 worksheets should raise an OSError("too many open files")
xlnt::workbook wb;
wb.optimized_write(true);
for(int i = 0; i < 200; i++) // over 200 worksheets should raise an OSError("too many open files")
{
wb.create_sheet();
wb.save(test_filename);
os.remove(test_filename);
unlink(test_filename.c_str());
}
}
@ -130,29 +137,37 @@ public:
void test_dump_twice()
{
test_filename = _get_test_filename();
auto test_filename = temp_file.GetFilename();
wb = Workbook(optimized_write = True);
ws = wb.create_sheet();
ws.append(["hello"]);
xlnt::workbook wb;
wb.optimized_write(true);
auto ws = wb.create_sheet();
std::vector<std::string> to_append = {"hello"};
ws.append(to_append);
wb.save(test_filename);
os.remove(test_filename);
unlink(test_filename.c_str());
wb.save(test_filename);
}
void test_append_after_save()
{
test_filename = _get_test_filename();
xlnt::workbook wb;
wb.optimized_write(true);
auto ws = wb.create_sheet();
wb = Workbook(optimized_write = True);
ws = wb.create_sheet();
ws.append(["hello"]);
std::vector<std::string> to_append = {"hello"};
ws.append(to_append);
wb.save(test_filename);
os.remove(test_filename);
{
TemporaryFile temp2;
wb.save(temp2.GetFilename());
}
ws.append(["hello"]);
ws.append(to_append);
}
private:
TemporaryFile temp_file;
};

View File

@ -13,17 +13,13 @@ public:
}
void test_1()
{
}
void test_get_dimensions()
{
expected = ["A1:G5", "D1:K30", "D2:D2", "A1:C1"];
auto expected = {"A1:G5", "D1:K30", "D2:D2", "A1:C1"};
wb = _open_wb();
for i, sheetn in enumerate(wb.get_sheet_names())
for(i, sheetn : enumerate(wb.get_sheet_names()))
{
ws = wb.get_sheet_by_name(name = sheetn);
TS_ASSERT_EQUALS(ws._dimensions, expected[i]);
@ -32,68 +28,68 @@ public:
void test_read_fast_integrated()
{
sheet_name = "Sheet1 - Text"
std::string sheet_name = "Sheet1 - Text";
expected = [["This is cell A1 in Sheet 1", None, None, None, None, None, None],
[None, None, None, None, None, None, None],
[None, None, None, None, None, None, None],
[None, None, None, None, None, None, None],
[None, None, None, None, None, None, "This is cell G5"], ]
std::vector<std::vector<char *>> expected = {{"This is cell A1 in Sheet 1", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
{nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
{nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
{nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
{nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, "This is cell G5"}};
wb = load_workbook(filename = workbook_name, use_iterators = True)
ws = wb.get_sheet_by_name(name = sheet_name)
wb = load_workbook(filename = workbook_name, use_iterators = True);
ws = wb.get_sheet_by_name(name = sheet_name);
for row, expected_row in zip(ws.iter_rows(), expected) :
row_values = [x.internal_value for x in row]
TS_ASSERT_EQUALS(row_values, expected_row)
for(row, expected_row : zip(ws.iter_rows(), expected)
{
row_values = [x.internal_value for x in row];
TS_ASSERT_EQUALS(row_values, expected_row);
}
}
void test_get_boundaries_range()
{
TS_ASSERT_EQUALS(get_range_boundaries("C1:C4"), (3, 1, 3, 4))
TS_ASSERT_EQUALS(get_range_boundaries("C1:C4"), (3, 1, 3, 4));
}
void test_get_boundaries_one()
{
TS_ASSERT_EQUALS(get_range_boundaries("C1"), (3, 1, 4, 1))
TS_ASSERT_EQUALS(get_range_boundaries("C1"), (3, 1, 4, 1));
}
void test_read_single_cell_range()
{
wb = load_workbook(filename = workbook_name, use_iterators = True)
ws = wb.get_sheet_by_name(name = sheet_name)
wb = load_workbook(filename = workbook_name, use_iterators = True);
ws = wb.get_sheet_by_name(name = sheet_name);
TS_ASSERT_EQUALS("This is cell A1 in Sheet 1", list(ws.iter_rows("A1"))[0][0].internal_value)
TS_ASSERT_EQUALS("This is cell A1 in Sheet 1", list(ws.iter_rows("A1"))[0][0].internal_value);
}
void test_read_fast_integrated2()
{
sheet_name = "Sheet2 - Numbers"
sheet_name = "Sheet2 - Numbers";
expected = [[x + 1] for x in range(30)]
expected = [[x + 1] for x in range(30)];
query_range = "D1:E30"
query_range = "D1:E30";
wb = load_workbook(filename = workbook_name, use_iterators = True)
ws = wb.get_sheet_by_name(name = sheet_name)
wb = load_workbook(filename = workbook_name, use_iterators = True);
ws = wb.get_sheet_by_name(name = sheet_name);
for row, expected_row in zip(ws.iter_rows(query_range), expected) :
row_values = [x.internal_value for x in row]
TS_ASSERT_EQUALS(row_values, expected_row)
for(row, expected_row : zip(ws.iter_rows(query_range), expected))
{
row_values = [x.internal_value for x in row];
TS_ASSERT_EQUALS(row_values, expected_row);
}
}
void test_read_single_cell_date()
{
sheet_name = "Sheet4 - Dates"
sheet_name = "Sheet4 - Dates";
wb = load_workbook(filename = workbook_name, use_iterators = True)
ws = wb.get_sheet_by_name(name = sheet_name)
wb = load_workbook(filename = workbook_name, use_iterators = True);
ws = wb.get_sheet_by_name(name = sheet_name);
TS_ASSERT_EQUALS(datetime.datetime(1973, 5, 20), list(ws.iter_rows("A1"))[0][0].internal_value)
TS_ASSERT_EQUALS(datetime.datetime(1973, 5, 20, 9, 15, 2), list(ws.iter_rows("C1"))[0][0].internal_value)
TS_ASSERT_EQUALS(datetime.datetime(1973, 5, 20), list(ws.iter_rows("A1"))[0][0].internal_value);
TS_ASSERT_EQUALS(datetime.datetime(1973, 5, 20, 9, 15, 2), list(ws.iter_rows("C1"))[0][0].internal_value);
}
};

View File

@ -15,20 +15,20 @@ public:
void test_write_content_types()
{
wb = Workbook();
xlnt::workbook wb;
wb.create_sheet();
wb.create_sheet();
content = write_content_types(wb);
reference_file = os.path.join(DATADIR, "writer", "expected",
"[Content_Types].xml");
auto content = xlnt::workbook::write_content_types(wb);
std::string reference_file = DATADIR + "/writer/expected/[Content_Types].xml";
assert_equals_file_content(reference_file, content);
}
void test_write_root_rels()
{
wb = Workbook();
content = write_root_rels(wb);
reference_file = os.path.join(DATADIR, "writer", "expected", ".rels");
xlnt::workbook wb;
wb.create_sheet();
auto content = xlnt::workbook::write_root_rels(wb);
std::string reference_file = DATADIR + "/writer/expected/.rels";
assert_equals_file_content(reference_file, content);
}
};

View File

@ -0,0 +1,31 @@
#pragma once
#include <array>
#include <cstdio>
#include <string>
class TemporaryDirectory
{
public:
static std::string CreateTemporaryFilename()
{
std::array<char, L_tmpnam> buffer;
tmpnam(buffer.data());
return std::string(buffer.begin(), buffer.end());
}
TemporaryDirectory() : filename_(CreateTemporaryFilename())
{
}
~TemporaryDirectory()
{
remove(filename_.c_str());
}
std::string GetFilename() const { return filename_; }
private:
const std::string filename_;
};

View File

@ -0,0 +1,31 @@
#pragma once
#include <array>
#include <cstdio>
#include <string>
class TemporaryFile
{
public:
static std::string CreateTemporaryFilename()
{
std::array<char, L_tmpnam> buffer;
tmpnam(buffer.data());
return std::string(buffer.begin(), buffer.end());
}
TemporaryFile() : filename_(CreateTemporaryFilename())
{
}
~TemporaryFile()
{
remove(filename_.c_str());
}
std::string GetFilename() const { return filename_; }
private:
const std::string filename_;
};

View File

@ -34,7 +34,9 @@ public:
void test_set_bad_title()
{
Worksheet(wb, "X" * 50);
std::string title(50, 'X');
xlnt::workbook wb;
wb.create_sheet(title);
}
void test_set_bad_title_character()

View File

@ -4,6 +4,7 @@
#include <cxxtest/TestSuite.h>
#include "../xlnt.h"
#include "TemporaryDirectory.h"
class WriteTestSuite : public CxxTest::TestSuite
{
@ -15,12 +16,11 @@ public:
void test_write_empty_workbook()
{
make_tmpdir();
TemporaryDirectory temp_dir;
wb = Workbook();
dest_filename = os.path.join(TMPDIR, "empty_book.xlsx");
save_workbook(wb, dest_filename);
assert os.path.isfile(dest_filename);
clean_tmpdir();
}
void test_write_virtual_workbook()

View File

@ -6,6 +6,7 @@
#include <sstream>
#include "xlnt.h"
#include "../third-party/pugixml/src/pugixml.hpp"
namespace xlnt {
@ -971,6 +972,8 @@ struct cell_struct
bool bool_value;
};
std::string error_value;
tm date_value;
std::string string_value;
std::string formula_value;
@ -1015,12 +1018,27 @@ cell::cell(cell_struct *root) : root_(root)
cell::type cell::data_type_for_value(const std::string &value)
{
if(value[0] == '=')
{
return type::formula;
}
return type::null;
}
void cell::set_explicit_value(const std::string &value, type data_type)
{
root_->type = data_type;
switch(data_type)
{
case type::formula: root_->formula_value = value; return;
case type::date: root_->date_value.tm_hour = std::stoi(value); return;
case type::error: root_->error_value = value; return;
case type::boolean: root_->bool_value = value == "true"; return;
case type::null: return;
case type::numeric: root_->numeric_value = std::stod(value); return;
case type::string: root_->string_value = value; return;
}
}
bool cell::bind_value()
@ -1620,17 +1638,17 @@ void worksheet::unmerge_cells(int start_row, int start_column, int end_row, int
root_->unmerge_cells(start_row, start_column, end_row, end_column);
}
void worksheet::append(const std::vector<xlnt::cell> &cells)
void worksheet::append(const std::vector<std::string> &cells)
{
root_->append(cells);
}
void worksheet::append(const std::unordered_map<std::string, xlnt::cell> &cells)
void worksheet::append(const std::unordered_map<std::string, std::string> &cells)
{
root_->append(cells);
}
void worksheet::append(const std::unordered_map<int, xlnt::cell> &cells)
void worksheet::append(const std::unordered_map<int, std::string> &cells)
{
root_->append(cells);
}
@ -1676,11 +1694,146 @@ cell worksheet::operator[](const std::string &address)
return cell(address);
}
workbook::workbook() : active_worksheet_(nullptr)
std::string workbook::write_content_types(workbook &wb)
{
std::set<std::string> seen;
pugi::xml_node root;
if(wb.has_vba_archive())
{
root = fromstring(wb.get_vba_archive().read(ARC_CONTENT_TYPES));
for(auto elem : root.findall("{" + CONTYPES_NS + "}Override"))
{
seen.insert(elem.attrib["PartName"]);
}
}
else
{
root = Element("{" + CONTYPES_NS + "}Types");
for(auto content_type : static_content_types_config)
{
if(setting_type == "Override")
{
tag = "{" + CONTYPES_NS + "}Override";
attrib = {"PartName": "/" + name};
}
else
{
tag = "{" + CONTYPES_NS + "}Default";
attrib = {"Extension": name};
}
attrib["ContentType"] = content_type;
SubElement(root, tag, attrib);
}
}
int drawing_id = 1;
int chart_id = 1;
int comments_id = 1;
int sheet_id = 0;
for(auto sheet : wb)
{
std::string name = "/xl/worksheets/sheet" + std::to_string(sheet_id) + ".xml";
if(seen.find(name) == seen.end())
{
SubElement(root, "{" + CONTYPES_NS + "}Override", {{"PartName", name},
{"ContentType", "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"}});
}
if(sheet._charts || sheet._images)
{
name = "/xl/drawings/drawing" + drawing_id + ".xml";
if(seen.find(name) == seen.end())
{
SubElement(root, "{%s}Override" % CONTYPES_NS, {"PartName" : name,
"ContentType" : "application/vnd.openxmlformats-officedocument.drawing+xml"});
}
drawing_id += 1;
for(auto chart : sheet._charts)
{
name = "/xl/charts/chart%d.xml" % chart_id;
if(seen.find(name) == seen.end())
{
SubElement(root, "{%s}Override" % CONTYPES_NS, {"PartName" : name,
"ContentType" : "application/vnd.openxmlformats-officedocument.drawingml.chart+xml"});
}
chart_id += 1;
if(chart._shapes)
{
name = "/xl/drawings/drawing%d.xml" % drawing_id;
if(seen.find(name) == seen.end())
{
SubElement(root, "{%s}Override" % CONTYPES_NS, {"PartName" : name,
"ContentType" : "application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml"});
}
drawing_id += 1;
}
}
}
if(sheet.get_comment_count() > 0)
{
SubElement(root, "{%s}Override" % CONTYPES_NS,
{"PartName": "/xl/comments%d.xml" % comments_id,
"ContentType" : "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml"});
comments_id += 1;
}
}
return get_document_content(root);
}
std::string workbook::write_root_rels(workbook wb)
{
root = Element("{%s}Relationships" % PKG_REL_NS);
relation_tag = "{%s}Relationship" % PKG_REL_NS;
SubElement(root, relation_tag, {"Id": "rId1", "Target" : ARC_WORKBOOK,
"Type" : "%s/officeDocument" % REL_NS});
SubElement(root, relation_tag, {"Id": "rId2", "Target" : ARC_CORE,
"Type" : "%s/metadata/core-properties" % PKG_REL_NS});
SubElement(root, relation_tag, {"Id": "rId3", "Target" : ARC_APP,
"Type" : "%s/extended-properties" % REL_NS});
if(wb.has_vba_archive())
{
// See if there was a customUI relation and reuse its id
arc = fromstring(workbook.vba_archive.read(ARC_ROOT_RELS));
rels = arc.findall(relation_tag);
rId = None;
for(rel in rels)
{
if(rel.get("Target") == ARC_CUSTOM_UI)
{
rId = rel.get("Id");
break;
}
}
if(rId is not None)
{
SubElement(root, relation_tag, {"Id": rId, "Target" : ARC_CUSTOM_UI,
"Type" : "%s" % CUSTOMUI_NS});
}
}
return get_document_content(root);
}
workbook::workbook() : active_sheet_index_(0)
{
auto ws = create_sheet();
ws.set_title("Sheet1");
active_worksheet_ = ws;
}
worksheet workbook::get_sheet_by_name(const std::string &name)
@ -1695,7 +1848,7 @@ worksheet workbook::get_sheet_by_name(const std::string &name)
worksheet workbook::get_active_sheet()
{
return active_worksheet_;
return worksheets_[active_sheet_index_];
}
worksheet workbook::create_sheet()

View File

@ -12,17 +12,21 @@ struct tm;
namespace xlnt {
struct cell_struct;
struct worksheet_struct;
struct package_impl;
class style;
class worksheet;
class worksheet;
class cell;
class relationship;
class workbook;
class comment;
class drawing;
class named_range;
class package;
class relationship;
class style;
class workbook;
class worksheet;
struct cell_struct;
struct drawing_struct;
struct named_range_struct;
struct package_impl;
struct worksheet_struct;
const int MIN_ROW = 0;
const int MIN_COLUMN = 0;
@ -192,6 +196,12 @@ enum class target_mode
Internal
};
enum class encoding_type
{
utf8,
latin1
};
/// <summary>
/// Represents a value type that may or may not have an assigned value.
/// </summary>
@ -798,25 +808,278 @@ struct coordinate
int row;
};
/// <summary>
/// Alignment options for use in styles.
/// </summary>
struct alignment
{
enum class horizontal_alignment
{
general,
left,
right,
center,
center_continuous,
justify
};
enum class vertical_alignment
{
bottom,
top,
center,
justify
};
horizontal_alignment horizontal = horizontal_alignment::general;
vertical_alignment vertical = vertical_alignment::bottom;
int text_rotation = 0;
bool wrap_text = false;
bool shrink_to_fit = false;
int indent = 0;
};
class number_format
{
public:
void set_format_code(const std::string &format_code) { format_code_ = format_code; }
enum class format
{
general,
text,
number,
number00,
number_comma_separated1,
number_comma_separated2,
percentage,
percentage00,
date_yyyymmdd2,
date_yyyymmdd,
date_ddmmyyyy,
date_dmyslash,
date_dmyminus,
date_dmminus,
date_myminus,
date_xlsx14,
date_xlsx15,
date_xlsx16,
date_xlsx17,
date_xlsx22,
date_datetime,
date_time1,
date_time2,
date_time3,
date_time4,
date_time5,
date_time6,
date_time7,
date_time8,
date_timedelta,
date_yyyymmddslash,
currency_usd_simple,
currency_usd,
currency_eur_simple
};
static const std::unordered_map<int, std::string> builtin_formats;
static std::string builtin_format_code(int index);
static bool is_date_format(const std::string &format);
static bool is_builtin(const std::string &format);
format get_format_code() const { return format_code_; }
void set_format_code(format format_code) { format_code_ = format_code; }
private:
std::string format_code_;
format format_code_ = format::general;
int format_index_ = 0;
};
struct color
{
static const color black;
static const color white;
static const color red;
static const color darkred;
static const color blue;
static const color darkblue;
static const color green;
static const color darkgreen;
static const color yellow;
static const color darkyellow;
color(int index)
{
this->index = index;
}
int index;
};
class font
{
enum class underline
{
none,
double_,
double_accounting,
single,
single_accounting
};
std::string name = "Calibri";
int size = 11;
bool bold = false;
bool italic = false;
bool superscript = false;
bool subscript = false;
underline underline = underline::none;
bool strikethrough = false;
color color = color::black;
};
class fill
{
public:
enum class type
{
none,
solid,
gradient_linear,
gradient_path,
pattern_darkdown,
pattern_darkgray,
pattern_darkgrid,
pattern_darkhorizontal,
pattern_darktrellis,
pattern_darkup,
pattern_darkvertical,
pattern_gray0625,
pattern_gray125,
pattern_lightdown,
pattern_lightgray,
pattern_lightgrid,
pattern_lighthorizontal,
pattern_lighttrellis,
pattern_lightup,
pattern_lightvertical,
pattern_mediumgray,
};
type type = type::none;
int rotation = 0;
color start_color = color::white;
color end_color = color::black;
};
class borders
{
struct border
{
enum class style
{
none,
dashdot,
dashdotdot,
dashed,
dotted,
double_,
hair,
medium,
mediumdashdot,
mediumdashdotdot,
mediumdashed,
slantdashdot,
thick,
thin
};
style style = style::none;
color color = color::black;
};
enum class diagonal_direction
{
none,
up,
down,
both
};
border left;
border right;
border top;
border bottom;
border diagonal;
diagonal_direction diagonal_direction = diagonal_direction::none;
border all_borders;
border outline;
border inside;
border vertical;
border horizontal;
};
class protection
{
public:
enum class type
{
inherit,
protected_,
unprotected
};
type locked;
type hidden;
};
class style
{
public:
style(bool static_ = false) : static_(static_) {}
style copy() const;
font get_font() const;
void set_font(font font);
fill get_fill() const;
void set_fill(fill fill);
borders get_borders() const;
void set_borders(borders borders);
alignment get_alignment() const;
void set_alignment(alignment alignment);
number_format &get_number_format() { return number_format_; }
const number_format &get_number_format() const { return number_format_; }
void set_number_format(number_format number_format);
protection get_protection() const;
void set_protection(protection protection);
private:
style(const style &rhs);
bool static_ = false;
font font_;
fill fill_;
borders borders_;
alignment alignment_;
number_format number_format_;
protection protection_;
};
/// <summary>
/// Describes cell associated properties.
/// </summary>
/// <remarks>
/// Properties of interest include style, type, value, and address.
/// The Cell class is required to know its value and type, display options,
/// and any other features of an Excel cell.Utilities for referencing
/// cells using Excel's 'A1' column/row nomenclature are also provided.
/// </remarks>
class cell
{
public:
@ -833,15 +1096,46 @@ public:
static const std::unordered_map<std::string, int> ErrorCodes;
/// <summary>
/// Convert a coordinate string like 'B12' to a tuple ('B', 12)
/// </summary>
static coordinate coordinate_from_string(const std::string &address);
static int column_index_from_string(const std::string &column_string);
static std::string get_column_letter(int column_index);
/// <summary>
/// Convert a coordinate to an absolute coordinate string (B12 -> $B$12)
/// </summary>
static std::string absolute_coordinate(const std::string &absolute_address);
/// <summary>
/// Convert a column letter into a column number (e.g. B -> 2)
/// </summary>
/// <remarks>
/// Excel only supports 1 - 3 letter column names from A->ZZZ, so we
/// restrict our column names to 1 - 3 characters, each in the range A - Z.
/// </remarks>
static int column_index_from_string(const std::string &column_string);
/// <summary>
/// Convert a column number into a column letter (3 -> 'C')
/// </summary>
/// <remarks>
/// Right shift the column col_idx by 26 to find column letters in reverse
/// order.These numbers are 1 - based, and can be converted to ASCII
/// ordinals by adding 64.
/// </remarks>
static std::string get_column_letter(int column_index);
static std::string check_string(const std::string &value);
static std::string check_numeric(const std::string &value);
static std::string check_error(const std::string &value);
cell();
cell(worksheet &ws, const std::string &column, int row);
cell(worksheet &ws, const std::string &column, int row, const std::string &initial_value);
encoding_type get_encoding() const;
std::string to_string() const;
void set_explicit_value(const std::string &value, type data_type);
type data_type_for_value(const std::string &value);
@ -853,32 +1147,59 @@ public:
bool bind_value(bool value);
bool bind_value(const tm &value);
std::string get_hyperlink() const;
void set_hyperlink(const std::string &value);
std::string get_hyperlink_rel_id() const;
void set_number_format(const std::string &format_code);
bool has_style() const;
style &get_style();
const style &get_style() const;
type get_data_type() const;
std::string get_coordinate() const;
std::string get_address() const;
cell get_offset(int row, int column);
bool is_date() const;
std::pair<int, int> get_anchor() const;
comment get_comment() const;
void set_comment(comment comment);
cell &operator=(const cell &rhs);
cell &operator=(bool value);
cell &operator=(int value);
cell &operator=(double value);
cell &operator=(const std::string &value);
cell &operator=(const char *value);
cell &operator=(bool value);
cell &operator=(const tm &value);
bool operator==(std::nullptr_t) const;
bool operator==(bool comparand) const;
bool operator==(int comparand) const;
bool operator==(double comparand) const;
bool operator==(const std::string &comparand) const;
bool operator==(const char *comparand) const;
bool operator==(const tm &comparand) const;
friend bool operator==(std::nullptr_t, const cell &cell);
friend bool operator==(bool comparand, const cell &cell);
friend bool operator==(int comparand, const cell &cell);
friend bool operator==(double comparand, const cell &cell);
friend bool operator==(const std::string &comparand, const cell &cell);
friend bool operator==(const char *comparand, const cell &cell);
friend bool operator==(const tm &comparand, const cell &cell);
std::string to_string() const;
bool is_date() const;
style &get_style();
const style &get_style() const;
type get_data_type() const;
private:
friend struct worksheet_struct;
cell(cell_struct *root);
cell_struct *root_;
};
@ -951,9 +1272,9 @@ public:
void merge_cells(int start_row, int start_column, int end_row, int end_column);
void unmerge_cells(const std::string &range_string);
void unmerge_cells(int start_row, int start_column, int end_row, int end_column);
void append(const std::vector<xlnt::cell> &cells);
void append(const std::unordered_map<std::string, xlnt::cell> &cells);
void append(const std::unordered_map<int, xlnt::cell> &cells);
void append(const std::vector<std::string> &cells);
void append(const std::unordered_map<std::string, std::string> &cells);
void append(const std::unordered_map<int, std::string> &cells);
xlnt::range rows() const;
xlnt::range columns() const;
bool operator==(const worksheet &other) const;
@ -967,26 +1288,111 @@ private:
worksheet_struct *root_;
};
class named_range
{
public:
named_range(const std::string &name);
private:
friend class worksheet;
named_range(named_range_struct *root);
named_range_struct *root_;
};
class drawing
{
public:
drawing();
private:
friend class worksheet;
drawing(drawing_struct *root);
drawing_struct *root_;
};
class workbook
{
public:
static std::string write_content_types(workbook &wb);
static std::string write_root_rels(workbook &wb);
//constructors
workbook();
//prevent copy and assignment
workbook(const workbook &) = delete;
const workbook &operator=(const workbook &) = delete;
worksheet get_sheet_by_name(const std::string &sheet_name);
//named parameters
workbook &optimized_write(bool value);
workbook &encoding(encoding_type value);
workbook &guess_types(bool value);
workbook &data_only(bool value);
void read_workbook_settings(const std::string &xml_source);
//getters
worksheet get_active_sheet();
bool get_optimized_write() const { return optimized_write_; }
encoding_type get_encoding() const { return encoding_; }
bool get_guess_types() const { return guess_types_; }
bool get_data_only() const { return data_only_; }
//create
worksheet create_sheet();
worksheet create_sheet(std::size_t index);
std::vector<std::string> get_sheet_names() const;
worksheet create_sheet(const std::string &title);
worksheet create_sheet(std::size_t index, const std::string &title);
//add
void add_sheet(worksheet worksheet);
void add_sheet(worksheet worksheet, std::size_t index);
//remove
void remove_sheet(worksheet worksheet);
//container operations
worksheet get_sheet_by_name(const std::string &sheet_name);
bool contains(const std::string &key) const;
int get_index(worksheet worksheet);
worksheet operator[](const std::string &name);
std::vector<worksheet>::iterator begin();
std::vector<worksheet>::iterator end();
worksheet operator[](const std::string &name);
std::vector<worksheet>::const_iterator begin() const;
std::vector<worksheet>::const_iterator end() const;
std::vector<worksheet>::const_iterator cbegin() const;
std::vector<worksheet>::const_iterator cend() const;
std::vector<std::string> get_sheet_names() const;
//named ranges
void create_named_range(const std::string &name, worksheet worksheet, const std::string &range_string);
std::vector<named_range> get_named_ranges();
void add_named_range(named_range named_range);
void get_named_range(const std::string &name);
void remove_named_range(named_range named_range);
//serialization
void save(const std::string &filename);
void load(const std::string &filename);
private:
worksheet active_worksheet_;
bool optimized_write_;
bool optimized_read_;
bool guess_types_;
bool data_only_;
int active_sheet_index_;
encoding_type encoding_;
std::vector<worksheet> worksheets_;
std::vector<named_range> named_ranges_;
std::vector<relationship> relationships_;
std::vector<drawing> drawings_;
};
} // namespace xlnt