2014-05-22 05:48:51 +08:00
|
|
|
#include <algorithm>
|
|
|
|
#include <locale>
|
2014-05-21 22:20:30 +08:00
|
|
|
#include <sstream>
|
|
|
|
|
|
|
|
#include "cell.h"
|
2014-05-30 08:52:14 +08:00
|
|
|
#include "cell_impl.h"
|
2014-05-22 05:48:51 +08:00
|
|
|
#include "cell_reference.h"
|
2014-05-21 22:20:30 +08:00
|
|
|
#include "relationship.h"
|
|
|
|
#include "worksheet.h"
|
|
|
|
|
|
|
|
namespace xlnt {
|
|
|
|
|
2014-05-30 08:52:14 +08:00
|
|
|
cell_impl::cell_impl() : hyperlink_rel("hyperlink"), column(0), row(0), type_(type::null)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
cell_impl::cell_impl(int column_index, int row_index) : hyperlink_rel("hyperlink"), column(column_index), row(row_index), type_(type::null)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2014-05-21 22:20:30 +08:00
|
|
|
const xlnt::color xlnt::color::black(0);
|
|
|
|
const xlnt::color xlnt::color::white(1);
|
|
|
|
|
|
|
|
const std::unordered_map<std::string, int> cell::ErrorCodes =
|
|
|
|
{
|
|
|
|
{"#NULL!", 0},
|
|
|
|
{"#DIV/0!", 1},
|
|
|
|
{"#VALUE!", 2},
|
|
|
|
{"#REF!", 3},
|
|
|
|
{"#NAME?", 4},
|
|
|
|
{"#NUM!", 5},
|
|
|
|
{"#N/A!", 6}
|
|
|
|
};
|
|
|
|
|
2014-05-30 08:52:14 +08:00
|
|
|
cell::cell() : d_(nullptr)
|
2014-05-21 22:20:30 +08:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2014-05-30 08:52:14 +08:00
|
|
|
cell::cell(cell_impl *d) : d_(d)
|
2014-05-21 22:20:30 +08:00
|
|
|
{
|
2014-05-30 08:52:14 +08:00
|
|
|
|
2014-05-21 22:20:30 +08:00
|
|
|
}
|
2014-05-30 08:52:14 +08:00
|
|
|
|
|
|
|
cell::cell(worksheet worksheet, const cell_reference &reference, const std::string &initial_value) : d_(nullptr)
|
2014-05-21 22:20:30 +08:00
|
|
|
{
|
2014-05-30 08:52:14 +08:00
|
|
|
cell self = worksheet.get_cell(reference);
|
|
|
|
d_ = self.d_;
|
2014-05-21 22:20:30 +08:00
|
|
|
|
2014-05-30 08:52:14 +08:00
|
|
|
if(initial_value != "")
|
|
|
|
{
|
|
|
|
*this = initial_value;
|
|
|
|
}
|
2014-05-21 22:20:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
std::string cell::get_value() const
|
|
|
|
{
|
2014-05-30 08:52:14 +08:00
|
|
|
switch(d_->type_)
|
2014-05-21 22:20:30 +08:00
|
|
|
{
|
2014-05-30 08:52:14 +08:00
|
|
|
case cell_impl::type::string:
|
|
|
|
return d_->string_value;
|
|
|
|
case cell_impl::type::numeric:
|
|
|
|
return std::to_string(d_->numeric_value);
|
|
|
|
case cell_impl::type::formula:
|
|
|
|
return d_->formula_value;
|
|
|
|
case cell_impl::type::error:
|
|
|
|
return d_->error_value;
|
|
|
|
case cell_impl::type::null:
|
2014-05-21 22:20:30 +08:00
|
|
|
return "";
|
2014-05-30 08:52:14 +08:00
|
|
|
case cell_impl::type::date:
|
2014-05-21 22:20:30 +08:00
|
|
|
return "00:00:00";
|
2014-05-30 08:52:14 +08:00
|
|
|
case cell_impl::type::boolean:
|
|
|
|
return d_->numeric_value != 0 ? "TRUE" : "FALSE";
|
2014-05-21 22:20:30 +08:00
|
|
|
default:
|
|
|
|
throw std::runtime_error("bad enum");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-22 05:48:51 +08:00
|
|
|
row_t cell::get_row() const
|
2014-05-21 22:20:30 +08:00
|
|
|
{
|
2014-05-30 08:52:14 +08:00
|
|
|
return d_->row + 1;
|
2014-05-21 22:20:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
std::string cell::get_column() const
|
|
|
|
{
|
2014-05-30 08:52:14 +08:00
|
|
|
return cell_reference::column_string_from_index(d_->column + 1);
|
2014-05-21 22:20:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<std::string> split_string(const std::string &string, char delim = ' ')
|
|
|
|
{
|
|
|
|
std::stringstream ss(string);
|
|
|
|
std::string part;
|
|
|
|
std::vector<std::string> parts;
|
|
|
|
while(std::getline(ss, part, delim))
|
|
|
|
{
|
|
|
|
parts.push_back(part);
|
|
|
|
}
|
|
|
|
return parts;
|
|
|
|
}
|
|
|
|
|
|
|
|
cell::type cell::data_type_for_value(const std::string &value)
|
|
|
|
{
|
|
|
|
if(value.empty())
|
|
|
|
{
|
|
|
|
return type::null;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(value[0] == '=')
|
|
|
|
{
|
|
|
|
return type::formula;
|
|
|
|
}
|
|
|
|
else if(value[0] == '0')
|
|
|
|
{
|
|
|
|
if(value.length() > 1)
|
|
|
|
{
|
|
|
|
if(value[1] == '.' || (value.length() > 2 && (value[1] == 'e' || value[1] == 'E')))
|
|
|
|
{
|
|
|
|
auto first_non_number = std::find_if(value.begin() + 2, value.end(),
|
|
|
|
[](char c) { return !std::isdigit(c, std::locale::classic()); });
|
|
|
|
if(first_non_number == value.end())
|
|
|
|
{
|
|
|
|
return type::numeric;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
auto split = split_string(value, ':');
|
|
|
|
if(split.size() == 2 || split.size() == 3)
|
|
|
|
{
|
|
|
|
for(auto part : split)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
std::stoi(part);
|
|
|
|
}
|
|
|
|
catch(std::invalid_argument)
|
|
|
|
{
|
|
|
|
return type::string;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return type::date;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return type::string;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return type::numeric;
|
|
|
|
}
|
|
|
|
else if(value[0] == '#')
|
|
|
|
{
|
|
|
|
return type::error;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
char *p;
|
|
|
|
strtod(value.c_str(), &p);
|
|
|
|
if(*p != 0)
|
|
|
|
{
|
|
|
|
static const std::vector<std::string> possible_booleans = {"TRUE", "true", "FALSE", "false"};
|
|
|
|
if(std::find(possible_booleans.begin(), possible_booleans.end(), value) != possible_booleans.end())
|
|
|
|
{
|
|
|
|
return type::boolean;
|
|
|
|
}
|
|
|
|
return type::string;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return type::numeric;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void cell::set_explicit_value(const std::string &value, type data_type)
|
|
|
|
{
|
2014-05-30 08:52:14 +08:00
|
|
|
d_->type_ = (cell_impl::type)data_type;
|
2014-05-21 22:20:30 +08:00
|
|
|
switch(data_type)
|
|
|
|
{
|
2014-05-30 08:52:14 +08:00
|
|
|
case type::formula: d_->formula_value = value; return;
|
|
|
|
case type::date: d_->date_value.tm_hour = std::stoi(value); return;
|
|
|
|
case type::error: d_->error_value = value; return;
|
|
|
|
case type::boolean: d_->numeric_value = value == "true"; return;
|
2014-05-21 22:20:30 +08:00
|
|
|
case type::null: return;
|
2014-05-30 08:52:14 +08:00
|
|
|
case type::numeric: d_->numeric_value = std::stod(value); return;
|
|
|
|
case type::string: d_->string_value = value; return;
|
2014-05-21 22:20:30 +08:00
|
|
|
default: throw std::runtime_error("bad enum");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void cell::set_hyperlink(const std::string &url)
|
|
|
|
{
|
2014-05-30 08:52:14 +08:00
|
|
|
d_->type_ = cell_impl::type::hyperlink;
|
|
|
|
d_->string_value = url;
|
2014-05-21 22:20:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void cell::set_merged(bool merged)
|
|
|
|
{
|
2014-05-30 08:52:14 +08:00
|
|
|
d_->merged = merged;
|
2014-05-21 22:20:30 +08:00
|
|
|
}
|
|
|
|
|
2014-05-22 05:48:51 +08:00
|
|
|
bool cell::is_merged() const
|
2014-05-21 22:20:30 +08:00
|
|
|
{
|
2014-05-30 08:52:14 +08:00
|
|
|
return d_->merged;
|
2014-05-21 22:20:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool cell::bind_value()
|
|
|
|
{
|
2014-05-30 08:52:14 +08:00
|
|
|
d_->type_ = cell_impl::type::null;
|
2014-05-21 22:20:30 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cell::bind_value(int value)
|
|
|
|
{
|
2014-05-30 08:52:14 +08:00
|
|
|
d_->type_ = cell_impl::type::numeric;
|
|
|
|
d_->numeric_value = value;
|
2014-05-21 22:20:30 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cell::bind_value(double value)
|
|
|
|
{
|
2014-05-30 08:52:14 +08:00
|
|
|
d_->type_ = cell_impl::type::numeric;
|
|
|
|
d_->numeric_value = value;
|
2014-05-21 22:20:30 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cell::bind_value(const std::string &value)
|
|
|
|
{
|
|
|
|
//Given a value, infer type and display options.
|
2014-05-30 08:52:14 +08:00
|
|
|
d_->type_ = (cell_impl::type)data_type_for_value(value);
|
2014-05-21 22:20:30 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cell::bind_value(const char *value)
|
|
|
|
{
|
|
|
|
return bind_value(std::string(value));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cell::bind_value(bool value)
|
|
|
|
{
|
2014-05-30 08:52:14 +08:00
|
|
|
d_->type_ = cell_impl::type::boolean;
|
|
|
|
d_->numeric_value = value ? 1 : 0;
|
2014-05-21 22:20:30 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cell::bind_value(const tm &value)
|
|
|
|
{
|
2014-05-30 08:52:14 +08:00
|
|
|
d_->type_ = cell_impl::type::date;
|
|
|
|
d_->date_value = value;
|
2014-05-21 22:20:30 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cell::is_date() const
|
|
|
|
{
|
2014-05-30 08:52:14 +08:00
|
|
|
return d_->type_ == cell_impl::type::date;
|
2014-05-21 22:20:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
cell_reference cell::get_reference() const
|
|
|
|
{
|
2014-05-30 08:52:14 +08:00
|
|
|
return {d_->column, d_->row};
|
2014-05-21 22:20:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
std::string cell::get_hyperlink_rel_id() const
|
|
|
|
{
|
2014-05-30 08:52:14 +08:00
|
|
|
return d_->hyperlink_rel.get_id();
|
2014-05-21 22:20:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool cell::operator==(std::nullptr_t) const
|
|
|
|
{
|
2014-05-30 08:52:14 +08:00
|
|
|
return d_ == nullptr;
|
2014-05-21 22:20:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool cell::operator==(int comparand) const
|
|
|
|
{
|
2014-05-30 08:52:14 +08:00
|
|
|
return d_->type_ == cell_impl::type::numeric && d_->numeric_value == comparand;
|
2014-05-21 22:20:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool cell::operator==(double comparand) const
|
|
|
|
{
|
2014-05-30 08:52:14 +08:00
|
|
|
return d_->type_ == cell_impl::type::numeric && d_->numeric_value == comparand;
|
2014-05-21 22:20:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool cell::operator==(const std::string &comparand) const
|
|
|
|
{
|
2014-05-30 08:52:14 +08:00
|
|
|
if(d_->type_ == cell_impl::type::hyperlink)
|
2014-05-21 22:20:30 +08:00
|
|
|
{
|
2014-05-30 08:52:14 +08:00
|
|
|
return d_->hyperlink_rel.get_target_uri() == comparand;
|
2014-05-21 22:20:30 +08:00
|
|
|
}
|
2014-05-30 08:52:14 +08:00
|
|
|
if(d_->type_ == cell_impl::type::string)
|
2014-05-21 22:20:30 +08:00
|
|
|
{
|
2014-05-30 08:52:14 +08:00
|
|
|
return d_->string_value == comparand;
|
2014-05-21 22:20:30 +08:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cell::operator==(const char *comparand) const
|
|
|
|
{
|
|
|
|
return *this == std::string(comparand);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cell::operator==(const tm &comparand) const
|
|
|
|
{
|
2014-05-30 08:52:14 +08:00
|
|
|
return d_->type_ == cell_impl::type::date && d_->date_value.tm_hour == comparand.tm_hour;
|
2014-05-21 22:20:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool operator==(int comparand, const xlnt::cell &cell)
|
|
|
|
{
|
|
|
|
return cell == comparand;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator==(const char *comparand, const xlnt::cell &cell)
|
|
|
|
{
|
|
|
|
return cell == comparand;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator==(const std::string &comparand, const xlnt::cell &cell)
|
|
|
|
{
|
|
|
|
return cell == comparand;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator==(const tm &comparand, const xlnt::cell &cell)
|
|
|
|
{
|
|
|
|
return cell == comparand;
|
|
|
|
}
|
|
|
|
|
|
|
|
style &cell::get_style()
|
|
|
|
{
|
2014-05-30 08:52:14 +08:00
|
|
|
if(d_->style_ == nullptr)
|
2014-05-22 05:48:51 +08:00
|
|
|
{
|
2014-05-30 08:52:14 +08:00
|
|
|
d_->style_ = new style();
|
2014-05-22 05:48:51 +08:00
|
|
|
}
|
2014-05-30 08:52:14 +08:00
|
|
|
return *d_->style_;
|
2014-05-21 22:20:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
const style &cell::get_style() const
|
|
|
|
{
|
2014-05-30 08:52:14 +08:00
|
|
|
if(d_->style_ == nullptr)
|
2014-05-22 05:48:51 +08:00
|
|
|
{
|
2014-05-30 08:52:14 +08:00
|
|
|
d_->style_ = new style();
|
2014-05-22 05:48:51 +08:00
|
|
|
}
|
2014-05-30 08:52:14 +08:00
|
|
|
return *d_->style_;
|
2014-05-21 22:20:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
xlnt::cell::type cell::get_data_type() const
|
|
|
|
{
|
2014-05-30 08:52:14 +08:00
|
|
|
return (type)d_->type_;
|
2014-05-21 22:20:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
cell &cell::operator=(const cell &rhs)
|
|
|
|
{
|
2014-05-30 08:52:14 +08:00
|
|
|
d_ = rhs.d_;
|
2014-05-21 22:20:30 +08:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
cell &cell::operator=(int value)
|
|
|
|
{
|
2014-05-30 08:52:14 +08:00
|
|
|
d_->type_ = cell_impl::type::numeric;
|
|
|
|
d_->numeric_value = value;
|
2014-05-21 22:20:30 +08:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
cell &cell::operator=(double value)
|
|
|
|
{
|
2014-05-30 08:52:14 +08:00
|
|
|
d_->type_ = cell_impl::type::numeric;
|
|
|
|
d_->numeric_value = value;
|
2014-05-21 22:20:30 +08:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
cell &cell::operator=(bool value)
|
|
|
|
{
|
2014-05-30 08:52:14 +08:00
|
|
|
d_->type_ = cell_impl::type::boolean;
|
|
|
|
d_->numeric_value = value ? 1 : 0;
|
2014-05-21 22:20:30 +08:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
cell &cell::operator=(const std::string &value)
|
|
|
|
{
|
2014-05-30 08:52:14 +08:00
|
|
|
d_->type_ = (cell_impl::type)data_type_for_value(value);
|
2014-05-21 22:20:30 +08:00
|
|
|
|
2014-05-30 08:52:14 +08:00
|
|
|
switch((type)d_->type_)
|
2014-05-21 22:20:30 +08:00
|
|
|
{
|
|
|
|
case type::date:
|
|
|
|
{
|
2014-05-30 08:52:14 +08:00
|
|
|
d_->date_value = std::tm();
|
2014-05-21 22:20:30 +08:00
|
|
|
auto split = split_string(value, ':');
|
2014-05-30 08:52:14 +08:00
|
|
|
d_->date_value.tm_hour = std::stoi(split[0]);
|
|
|
|
d_->date_value.tm_min = std::stoi(split[1]);
|
2014-05-21 22:20:30 +08:00
|
|
|
if(split.size() > 2)
|
|
|
|
{
|
2014-05-30 08:52:14 +08:00
|
|
|
d_->date_value.tm_sec = std::stoi(split[2]);
|
2014-05-21 22:20:30 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case type::formula:
|
2014-05-30 08:52:14 +08:00
|
|
|
d_->formula_value = value;
|
2014-05-21 22:20:30 +08:00
|
|
|
break;
|
|
|
|
case type::numeric:
|
2014-05-30 08:52:14 +08:00
|
|
|
d_->numeric_value = std::stod(value);
|
2014-05-21 22:20:30 +08:00
|
|
|
break;
|
|
|
|
case type::boolean:
|
2014-05-30 08:52:14 +08:00
|
|
|
d_->numeric_value = value == "TRUE" || value == "true";
|
2014-05-21 22:20:30 +08:00
|
|
|
break;
|
|
|
|
case type::error:
|
2014-05-30 08:52:14 +08:00
|
|
|
d_->error_value = value;
|
2014-05-21 22:20:30 +08:00
|
|
|
break;
|
|
|
|
case type::string:
|
2014-05-30 08:52:14 +08:00
|
|
|
d_->string_value = value;
|
2014-05-21 22:20:30 +08:00
|
|
|
break;
|
|
|
|
case type::null:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
throw std::runtime_error("bad enum");
|
|
|
|
}
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
cell &cell::operator=(const char *value)
|
|
|
|
{
|
|
|
|
return *this = std::string(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
cell &cell::operator=(const tm &value)
|
|
|
|
{
|
2014-05-30 08:52:14 +08:00
|
|
|
d_->type_ = cell_impl::type::date;
|
|
|
|
d_->date_value = value;
|
2014-05-21 22:20:30 +08:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string cell::to_string() const
|
|
|
|
{
|
2014-05-30 08:52:14 +08:00
|
|
|
return "<Cell " + cell_reference(d_->column, d_->row).to_string() + ">";
|
2014-05-21 22:20:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace xlnt
|
|
|
|
|