xlnt/source/cell.cpp

490 lines
10 KiB
C++
Raw Normal View History

2014-05-22 05:48:51 +08:00
#include <algorithm>
#include <locale>
2014-05-21 22:20:30 +08:00
#include <sstream>
2014-06-06 04:19:31 +08:00
#include "cell/cell.hpp"
#include "cell/cell_reference.hpp"
#include "common/datetime.hpp"
#include "common/relationship.hpp"
#include "worksheet/worksheet.hpp"
#include "detail/cell_impl.hpp"
2014-06-06 05:42:15 +08:00
#include "common/exceptions.hpp"
2014-05-21 22:20:30 +08:00
namespace xlnt {
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}
};
cell::cell() : d_(nullptr)
2014-05-21 22:20:30 +08:00
{
}
2014-05-31 06:42:25 +08:00
cell::cell(detail::cell_impl *d) : d_(d)
2014-05-21 22:20:30 +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
{
cell self = worksheet.get_cell(reference);
d_ = self.d_;
2014-05-21 22:20:30 +08:00
if(initial_value != "")
{
*this = initial_value;
}
2014-05-21 22:20:30 +08:00
}
std::string cell::get_value() const
{
switch(d_->type_)
2014-05-21 22:20:30 +08:00
{
2014-05-31 06:42:25 +08:00
case type::string:
return d_->string_value;
case type::numeric:
2014-06-10 12:29:49 +08:00
return std::floor(d_->numeric_value) == d_->numeric_value ? std::to_string((int)d_->numeric_value) : std::to_string(d_->numeric_value);
2014-05-31 06:42:25 +08:00
case type::formula:
return d_->string_value;
case type::error:
return d_->string_value;
case type::null:
return "";
case type::boolean:
2014-06-10 12:29:49 +08:00
return d_->numeric_value != 0 ? "1" : "0";
2014-05-31 06:42:25 +08:00
default:
throw std::runtime_error("bad enum");
2014-05-21 22:20:30 +08:00
}
}
2014-05-22 05:48:51 +08:00
row_t cell::get_row() const
2014-05-21 22:20:30 +08:00
{
return d_->row + 1;
2014-05-21 22:20:30 +08:00
}
std::string cell::get_column() const
{
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;
}
}
2014-05-31 06:42:25 +08:00
return type::numeric;
2014-05-21 22:20:30 +08:00
}
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-31 06:42:25 +08:00
d_->type_ = data_type;
2014-05-21 22:20:30 +08:00
switch(data_type)
{
2014-06-06 05:42:15 +08:00
case type::null:
if(value != "")
{
throw data_type_exception();
}
return;
case type::formula:
if(value.length() == 0 || value[0] != '=')
{
throw data_type_exception();
}
d_->string_value = value;
return;
2014-05-31 06:42:25 +08:00
case type::error: d_->string_value = value; return;
case type::boolean: d_->numeric_value = value == "true"; return;
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");
}
}
2014-05-31 06:42:25 +08:00
void cell::set_explicit_value(int value, type data_type)
2014-05-21 22:20:30 +08:00
{
2014-05-31 06:42:25 +08:00
d_->type_ = data_type;
2014-05-21 22:20:30 +08:00
2014-05-31 06:42:25 +08:00
switch(data_type)
{
case type::numeric: d_->numeric_value = value; return;
case type::string: d_->string_value = std::to_string(value); return;
2014-06-06 05:42:15 +08:00
default: throw data_type_exception();
2014-05-31 06:42:25 +08:00
}
2014-05-21 22:20:30 +08:00
}
2014-05-31 06:42:25 +08:00
void cell::set_explicit_value(double value, type data_type)
2014-05-21 22:20:30 +08:00
{
2014-05-31 06:42:25 +08:00
d_->type_ = data_type;
2014-05-21 22:20:30 +08:00
2014-05-31 06:42:25 +08:00
switch(data_type)
{
case type::numeric: d_->numeric_value = value; return;
case type::string: d_->string_value = std::to_string(value); return;
2014-06-06 05:42:15 +08:00
default: throw data_type_exception();
2014-05-31 06:42:25 +08:00
}
2014-05-21 22:20:30 +08:00
}
2014-05-31 06:42:25 +08:00
void cell::set_merged(bool merged)
2014-05-21 22:20:30 +08:00
{
2014-05-31 06:42:25 +08:00
d_->merged = merged;
2014-05-21 22:20:30 +08:00
}
2014-05-31 06:42:25 +08:00
bool cell::is_merged() const
2014-05-21 22:20:30 +08:00
{
2014-05-31 06:42:25 +08:00
return d_->merged;
2014-05-21 22:20:30 +08:00
}
bool cell::is_date() const
{
2014-05-31 06:42:25 +08:00
return d_->is_date_;
2014-05-21 22:20:30 +08:00
}
cell_reference cell::get_reference() const
{
return {d_->column, d_->row};
2014-05-21 22:20:30 +08:00
}
bool cell::operator==(std::nullptr_t) const
{
return d_ == nullptr;
2014-05-21 22:20:30 +08:00
}
bool cell::operator==(int comparand) const
{
2014-05-31 06:42:25 +08:00
return d_->type_ == type::numeric && d_->numeric_value == comparand;
2014-05-21 22:20:30 +08:00
}
bool cell::operator==(double comparand) const
{
2014-05-31 06:42:25 +08:00
return d_->type_ == type::numeric && d_->numeric_value == comparand;
2014-05-21 22:20:30 +08:00
}
bool cell::operator==(const std::string &comparand) const
{
2014-05-31 06:42:25 +08:00
if(d_->type_ == type::string)
2014-05-21 22:20:30 +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);
}
2014-05-31 06:42:25 +08:00
bool cell::operator==(const time &comparand) const
{
return d_->type_ == type::numeric && time(d_->numeric_value).hour == comparand.hour;
}
bool cell::operator==(const date &comparand) const
2014-05-21 22:20:30 +08:00
{
2014-05-31 06:42:25 +08:00
return d_->type_ == type::numeric && date((int)d_->numeric_value, 0, 0).year == comparand.year;
}
bool cell::operator==(const datetime &comparand) const
{
return d_->type_ == type::numeric && datetime((int)d_->numeric_value, 0, 0).year == comparand.year;
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;
}
2014-05-31 06:42:25 +08:00
bool operator==(const time &comparand, const xlnt::cell &cell)
{
return cell == comparand;
}
bool operator==(const date &comparand, const xlnt::cell &cell)
{
return cell == comparand;
}
bool operator==(const datetime &comparand, const xlnt::cell &cell)
2014-05-21 22:20:30 +08:00
{
return cell == comparand;
}
style &cell::get_style()
{
if(d_->style_ == nullptr)
2014-05-22 05:48:51 +08:00
{
d_->style_ = new style();
2014-05-22 05:48:51 +08:00
}
return *d_->style_;
2014-05-21 22:20:30 +08:00
}
const style &cell::get_style() const
{
if(d_->style_ == nullptr)
2014-05-22 05:48:51 +08:00
{
d_->style_ = new style();
2014-05-22 05:48:51 +08:00
}
return *d_->style_;
2014-05-21 22:20:30 +08:00
}
xlnt::cell::type cell::get_data_type() const
{
return (type)d_->type_;
2014-05-21 22:20:30 +08:00
}
cell &cell::operator=(const cell &rhs)
{
d_ = rhs.d_;
2014-05-21 22:20:30 +08:00
return *this;
}
cell &cell::operator=(int value)
{
2014-06-06 05:42:15 +08:00
d_->is_date_ = false;
2014-05-31 06:42:25 +08:00
d_->type_ = type::numeric;
d_->numeric_value = value;
2014-05-21 22:20:30 +08:00
return *this;
}
cell &cell::operator=(double value)
{
2014-06-06 05:42:15 +08:00
d_->is_date_ = false;
2014-05-31 06:42:25 +08:00
d_->type_ = type::numeric;
d_->numeric_value = value;
2014-05-21 22:20:30 +08:00
return *this;
}
2014-06-05 06:42:17 +08:00
cell &cell::operator=(long int value)
{
2014-06-06 05:42:15 +08:00
d_->is_date_ = false;
2014-06-05 06:42:17 +08:00
d_->type_ = type::numeric;
d_->numeric_value = value;
return *this;
}
cell &cell::operator=(long double value)
{
2014-06-06 05:42:15 +08:00
d_->is_date_ = false;
2014-06-05 06:42:17 +08:00
d_->type_ = type::numeric;
d_->numeric_value = value;
return *this;
}
2014-05-21 22:20:30 +08:00
cell &cell::operator=(bool value)
{
2014-06-06 05:42:15 +08:00
d_->is_date_ = false;
2014-05-31 06:42:25 +08:00
d_->type_ = 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-06-06 05:42:15 +08:00
d_->is_date_ = false;
2014-05-31 06:42:25 +08:00
d_->type_ = data_type_for_value(value);
2014-05-21 22:20:30 +08:00
switch((type)d_->type_)
2014-05-21 22:20:30 +08:00
{
case type::formula:
2014-05-31 06:42:25 +08:00
d_->string_value = value;
2014-05-21 22:20:30 +08:00
break;
case type::numeric:
2014-06-06 05:42:15 +08:00
if(value.find(':') != std::string::npos)
{
d_->is_date_ = true;
2014-06-07 23:49:19 +08:00
d_->numeric_value = time(value).to_number();
2014-06-06 05:42:15 +08:00
}
else
{
d_->numeric_value = std::stod(value);
}
2014-05-21 22:20:30 +08:00
break;
case type::boolean:
d_->numeric_value = value == "TRUE" || value == "true";
2014-05-21 22:20:30 +08:00
break;
case type::error:
2014-05-31 06:42:25 +08:00
d_->string_value = value;
2014-05-21 22:20:30 +08:00
break;
case type::string:
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);
}
2014-05-31 06:42:25 +08:00
cell &cell::operator=(const time &value)
{
d_->type_ = type::numeric;
d_->numeric_value = value.hour;
return *this;
}
cell &cell::operator=(const date &value)
2014-05-21 22:20:30 +08:00
{
2014-05-31 06:42:25 +08:00
d_->type_ = type::numeric;
d_->numeric_value = value.year;
2014-06-06 05:42:15 +08:00
d_->is_date_ = true;
2014-05-31 06:42:25 +08:00
return *this;
}
cell &cell::operator=(const datetime &value)
{
d_->type_ = type::numeric;
d_->numeric_value = value.year;
2014-06-06 05:42:15 +08:00
d_->is_date_ = true;
2014-05-21 22:20:30 +08:00
return *this;
}
std::string cell::to_string() const
{
2014-06-06 05:42:15 +08:00
return "<Cell " + worksheet(d_->parent_).get_title() + "." + get_reference().to_string() + ">";
2014-05-21 22:20:30 +08:00
}
2014-05-31 06:42:25 +08:00
std::string cell::get_hyperlink() const
{
return "";
}
2014-05-21 22:20:30 +08:00
2014-06-06 05:42:15 +08:00
void cell::set_hyperlink(const std::string &hyperlink)
2014-05-31 06:42:25 +08:00
{
2014-06-06 05:42:15 +08:00
if(hyperlink.length() == 0 || std::find(hyperlink.begin(), hyperlink.end(), ':') == hyperlink.end())
{
throw data_type_exception();
}
2014-06-07 23:49:19 +08:00
d_->hyperlink_ = hyperlink;
*this = hyperlink;
2014-05-31 06:42:25 +08:00
}
void cell::set_null()
{
d_->type_ = type::null;
}
void cell::set_formula(const std::string &formula)
{
2014-06-06 05:42:15 +08:00
if(formula.length() == 0 || formula[0] != '=')
{
throw data_type_exception();
}
2014-05-31 06:42:25 +08:00
d_->type_ = type::formula;
d_->string_value = formula;
}
void cell::set_error(const std::string &error)
{
2014-06-06 05:42:15 +08:00
if(error.length() == 0 || error[0] != '#')
{
throw data_type_exception();
}
2014-05-31 06:42:25 +08:00
d_->type_ = type::error;
d_->string_value = error;
}
} // namespace xlnt